Skip to content

Add Silicon Signal cookbook project#29

Merged
simantak-dabhade merged 9 commits intotinyfish-io:mainfrom
MANASMATHUR:manas/silicon-signal-clean
Mar 10, 2026
Merged

Add Silicon Signal cookbook project#29
simantak-dabhade merged 9 commits intotinyfish-io:mainfrom
MANASMATHUR:manas/silicon-signal-clean

Conversation

@MANASMATHUR
Copy link
Copy Markdown
Contributor

@MANASMATHUR MANASMATHUR commented Jan 31, 2026

TinyFish - SiliconSignal
SiliconSignal is a high-precision monitoring platform designed to detect logistics risks, lead-time shifts, and lifecycle transitions in real-time. By leveraging the Tinyfish web agent (Mino), it extracts live signals directly from foundry bulletins and primary distributor channels.
Deployment:- https://silicon-signal.vercel.app

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jan 31, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: fc02212f-a703-482b-84c9-269f4a53155e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new silicon-signal Next.js application and related infrastructure: frontend app with landing, dashboard, and UI components; a POST /api/scan server route implementing multi-source browser- and fetch-based part scanning, signal extraction, merging, and risk scoring; types and a lightweight history store with sample history data; build/config files (tsconfig, next.config, ESLint, PostCSS, package.json); global styles and assets. Exports include the scan POST handler, several React components, types, and history-store functions.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API as /api/scan
    participant Cache
    participant History as History Store
    participant Browser as Headless Browser
    participant Dist1 as DigiKey
    participant Dist2 as Mouser
    participant Dist3 as Other Vendors
    participant Risk as Risk Analyzer

    Client->>API: POST /api/scan (part_number, manufacturer)
    API->>API: Validate input
    API->>Cache: Check cache for part
    alt Cache Hit
        Cache-->>API: Cached result
        API-->>Client: Return cached result
    else Cache Miss
        API->>History: Load historical snapshots
        History-->>API: Return history

        API->>Browser: Launch headless browser (fallback: fetch)
        Browser->>Dist1: Navigate & fetch page
        Dist1-->>Browser: Page content / JSON-LD
        Browser->>Browser: Parse DOM & JSON-LD -> extract signals
        Browser->>Dist2: Navigate & fetch page
        Dist2-->>Browser: Page content / JSON-LD
        Browser->>Browser: Parse DOM & JSON-LD -> extract signals
        Browser->>Dist3: Navigate & fetch page
        Dist3-->>Browser: Page content / JSON-LD
        Browser->>Browser: Parse DOM & JSON-LD -> extract signals
        Browser-->>API: Source signals & agent logs

        API->>API: Merge signals across sources
        API->>Risk: Compute consolidated risk & confidence
        Risk->>History: Compare with historical trends
        History-->>Risk: Historical context
        Risk-->>API: Risk analysis

        API->>History: Save new snapshot
        History-->>API: Snapshot stored
        API->>Cache: Store result with TTL
        Cache-->>API: Cached
        API-->>Client: Return ScanResult (signals, risk, evidence, timing)
    end
Loading
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add Silicon Signal cookbook project' directly and clearly summarizes the main change: adding a new project directory (silicon-signal) to the cookbook repository.
Description check ✅ Passed The description is directly related to the changeset, explaining that SiliconSignal is a monitoring platform using Tinyfish/Mino agents, which aligns with the new silicon-signal project files being added.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🤖 Fix all issues with AI agents
In `@README.md`:
- Line 41: Fix the typo in the README table row for the project labeled
"[summer-school-finder]": replace the incorrect text "sch`ool" in the
description string "Discover and compare summer sch`ool programs from
universities around the world" with the correct "school" so the description
reads "Discover and compare summer school programs from universities around the
world".

In `@silicon-signal/README.md`:
- Line 3: Replace the bare URL on the README's "Live link:" line with a Markdown
link so it uses proper link syntax; for example, change the text that currently
reads "Live link: https://silicon-signal.vercel.app/" to use bracketed link text
and parentheses (e.g., "Live link: [Silicon
Signal](https://silicon-signal.vercel.app/)") so markdownlint MD034 is
satisfied.
- Around line 26-28: The fenced code block containing the environment variable
example (the block with "MINO_API_KEY=your_tinyfish_key") lacks a language tag
and triggers MD040; add the language identifier "dotenv" to the opening fence
(i.e., change the triple-backtick that precedes the MINO_API_KEY line to include
"dotenv") so the snippet is fenced as a dotenv code block.

In `@silicon-signal/src/app/api/scan/route.ts`:
- Around line 551-553: The regex used to validate part_number currently allows a
backslash due to the sequence "\\", which is unintended; update the validation
to disallow backslashes by removing the backslash from the character class and
ensure the hyphen is placed at the end (e.g., use a character class like
[A-Za-z0-9._/+ -] with the hyphen last) in the check that tests part_number so
invalid backslashes are rejected while preserving the intended allowed
characters.
- Around line 6-62: Remove the duplicated interface declarations (RiskAnalysis,
ScanResult, SourceSignal, SignalSummary, ConfidenceInfo) from route.ts and
replace them with a single import of those types from the shared types module;
specifically, delete the interface blocks shown in the diff and add an import
type statement that brings in RiskAnalysis, ScanResult, SourceSignal,
SignalSummary and ConfidenceInfo from the shared types module so the file uses
the canonical definitions instead of duplicating them.

In `@silicon-signal/src/components/Header.tsx`:
- Around line 3-11: The Header component uses client-only APIs (the onClick
handler that sets window.location.href) so either mark the component as a client
component by adding the directive 'use client' at the top of the Header file
(Header component) or make it server-safe by replacing the clickable div (the
element with onClick and the window.location.href usage) with a native anchor
element (<a href="/">) that preserves the same children and styles and removes
the onClick/window reference; update any related imports/props if needed.

In `@silicon-signal/src/components/ScanForm.tsx`:
- Around line 3-25: The handleSubmit function in ScanForm uses the identifier
React.FormEvent but React is not imported (with "jsx":"react-jsx" there is no
default React binding); fix by importing the event type from React and updating
the signature: add an import like "import type { FormEvent } from 'react'" (or
import React as needed) and change handleSubmit's parameter to use FormEvent (or
the imported type) so the TypeScript reference to React.FormEvent is resolved;
ensure this import sits with the other React imports at the top of ScanForm.tsx.

In `@silicon-signal/src/components/SignalOverview.tsx`:
- Around line 13-18: In the SignalOverview component JSX there is an invalid
nesting: a <div> placed inside the inline <span> that renders the live status;
replace that inner <div> with a <span> (preserving the clsx class string "w-1.5
h-1.5 rounded-full" and conditional classes "bg-accent"/"bg-border") so the
status indicator is valid inline HTML; update the JSX where the outer span uses
clsx(...) and the nested element created for the dot indicator to be a span
instead of div.

In `@silicon-signal/src/components/SiliconWafer.tsx`:
- Around line 1-2: This file is missing the Next.js client boundary directive
required for framer-motion; add the literal string 'use client' as the very
first line in SiliconWafer.tsx (before any imports) so the component and its use
of motion from 'framer-motion' run as a client component; ensure the directive
appears above the import of motion and any other imports in the file.

In `@silicon-signal/src/lib/store.ts`:
- Around line 27-79: saveSnapshot performs a read-modify-write (via attemptSave
and currentHistoryFile) without any locking, which can cause lost updates under
concurrent writes; fix by making writes atomic: when writing inside attemptSave,
write the JSON to a temporary file (e.g., same dir + unique suffix) and then
atomically rename/replace the target file (fs.renameSync) to avoid
partial/overwritten data, and optionally add a short retry/backoff or simple
lock-file mechanism around attemptSave to reduce race windows; if you choose not
to implement concurrency control, add a clear comment/docstring on saveSnapshot
explaining the race condition limitation and recommending atomic rename or
external locking for production.
🧹 Nitpick comments (10)
silicon-signal/src/components/HistoricalTrend.tsx (1)

6-12: Clamp history scores before plotting to avoid out-of-range rendering.

If a score is outside 0–100, the path can render off-canvas. Clamping keeps the chart stable without changing data semantics elsewhere.

♻️ Suggested change
-    const points = history.length > 1 ? history.map((h, i) => {
-        const x = (i / (history.length - 1)) * 240 + 20;
-        const y = 90 - (h.score / 100) * 80;
-        return { x, y };
-    }) : [];
+    const clampScore = (score: number) => Math.min(100, Math.max(0, score));
+    const points = history.length > 1 ? history.map((h, i) => {
+        const x = (i / (history.length - 1)) * 240 + 20;
+        const y = 90 - (clampScore(h.score) / 100) * 80;
+        return { x, y };
+    }) : [];
silicon-signal/src/components/ScanResultCard.tsx (2)

4-4: Unused import: Calendar

The Calendar icon is imported but never used in the component.

🧹 Remove unused import
-import { ExternalLink, AlertTriangle, Calendar, CheckCircle, Activity, DollarSign, Globe } from 'lucide-react';
+import { ExternalLink, AlertTriangle, CheckCircle, Activity, DollarSign, Globe } from 'lucide-react';

23-23: Set explicit value for aria-hidden

The aria-hidden attribute should have an explicit boolean or string value for clarity.

🧹 Suggested fix
-            <div className="absolute -top-20 -right-20 w-64 h-64 bg-cyan-500/10 rounded-full blur-3xl group-hover:bg-cyan-500/20 transition-all duration-1000" aria-hidden />
+            <div className="absolute -top-20 -right-20 w-64 h-64 bg-cyan-500/10 rounded-full blur-3xl group-hover:bg-cyan-500/20 transition-all duration-1000" aria-hidden="true" />
silicon-signal/src/components/PlatformView.tsx (1)

34-37: Consider checking response status before parsing JSON

The current flow parses JSON before checking res.ok. If the server returns a non-JSON error (e.g., 502 Bad Gateway with HTML), res.json() will throw, and the error message will be a parse error rather than the actual HTTP error.

🛡️ Suggested improvement for robustness
-            const data = await res.json();
-            if (!res.ok) {
-                throw new Error(data?.error || 'Scan failed');
-            }
-            setResult(data);
+            if (!res.ok) {
+                const data = await res.json().catch(() => ({}));
+                throw new Error(data?.error || `Scan failed (${res.status})`);
+            }
+            const data = await res.json();
+            setResult(data);
silicon-signal/src/lib/store.ts (1)

81-94: Fallback behavior may skip valid data in other files

getHistory stops at the first successfully parsed file, even if that file doesn't contain the requested partNumber. If the part's history exists only in a later file (e.g., data/history.json), it won't be found.

This is likely acceptable for the demo's use case but worth noting.

silicon-signal/src/types.ts (1)

1-5: Consider using a union type for level

Using a union type for level would provide better type safety and autocompletion:

🧹 Suggested improvement
+export type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH';
+
 export interface RiskAnalysis {
     score: number;
-    level: string;
+    level: RiskLevel;
     reasoning: string;
 }
silicon-signal/src/app/api/scan/route.ts (4)

616-627: Multiple @ts-ignore comments for Chromium types

The type mismatches between puppeteer-core and @sparticuz/chromium are common. Consider using type assertions with as unknown as X for slightly safer typing, or adding a brief comment explaining why these ignores are necessary.


786-799: Browser cleanup could use finally block

The browser cleanup is split between the happy path (line 786) and error handling (lines 792-798). Using a finally block would ensure cleanup happens regardless of which path is taken.

🧹 Consider wrapping browser operations in try-finally
let browser: Browser | undefined;
try {
    browser = await launchBrowser();
    // ... browser operations
} finally {
    if (browser) {
        try {
            await browser.close();
        } catch {
            // ignore close errors
        }
    }
}

1076-1089: Cache eviction removes oldest by insertion, not by TTL

The eviction logic removes entries in insertion order, not by expiration time. This means a recently used entry that was inserted early could be evicted before an expired entry inserted later. For a demo this is fine, but worth noting if caching is enabled in production.


534-1111: POST handler is quite long (~580 lines)

The handler orchestrates many concerns: validation, browser management, data fetching, signal parsing, risk calculation, caching, and history. For a cookbook demo this is acceptable, but consider extracting logical sections into helper functions for maintainability:

  • launchBrowser() - browser initialization logic
  • fetchSignalsWithBrowser() - browser-based data collection
  • computeRiskAnalysis() - risk scoring logic
  • buildScanResult() - result assembly

Comment thread README.md Outdated
Comment thread silicon-signal/README.md Outdated
Comment thread silicon-signal/README.md
Comment thread silicon-signal/src/app/api/scan/route.ts
Comment thread silicon-signal/src/app/api/scan/route.ts
Comment thread silicon-signal/src/components/Header.tsx Outdated
Comment thread silicon-signal/src/components/ScanForm.tsx Outdated
Comment thread silicon-signal/src/components/SignalOverview.tsx
Comment thread silicon-signal/src/components/SiliconWafer.tsx
Comment thread silicon-signal/src/lib/store.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@silicon-signal/src/components/SignalOverview.tsx`:
- Around line 5-9: The "Data Confidence" metric in the metrics array is
hardcoded to 95; update the Data Confidence value to use the actual scan result
confidence (use result.confidence?.score or result?.confidence?.score ??
<fallback>) instead of 95, e.g. replace the numeric literal in the Data
Confidence entry inside the metrics constant so it reads the ScanResult
confidence score and preserves existing status/color logic.
🧹 Nitpick comments (2)
silicon-signal/src/app/api/scan/route.ts (2)

554-571: Consider adding type declarations or explicit typing for chromium integration.

Multiple @ts-ignore comments suppress TypeScript errors for the @sparticuz/chromium integration. While this is a common workaround, it reduces type safety. Consider:

  1. Adding a local type declaration file for the chromium module
  2. Using explicit type assertions with comments explaining the expected types
  3. Checking if newer versions of @sparticuz/chromium have improved type definitions
♻️ Example type declaration approach

Create silicon-signal/src/types/chromium.d.ts:

declare module '@sparticuz/chromium' {
    const chromium: {
        executablePath(): Promise<string>;
        args: string[];
        defaultViewport: { width: number; height: number };
        headless: boolean | 'new';
    };
    export default chromium;
}

621-665: Consider logging suppressed errors to agent logs for observability.

Multiple empty catch blocks silently swallow errors during DOM extraction and page navigation. While graceful degradation is appropriate here, logging these failures to agentLogs would aid debugging without affecting control flow.

♻️ Example improvement for one catch block
                         } catch {
-                            // optional
+                            agentLogs.push(`${logPrefix} DOM extraction from search page skipped.`);
                         }

Comment thread silicon-signal/src/components/SignalOverview.tsx
Copy link
Copy Markdown
Contributor

@simantak-dabhade simantak-dabhade left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @MANASMATHUR — thanks for the submission! The concept is great and the signal extraction logic is really well thought out. However there's a core issue we need to address before this can be merged:


🔴 Not using TinyFish API

The project uses Puppeteer for all web scraping, not the TinyFish API. The MINO_API_KEY env var is checked at src/app/api/scan/route.ts:532 but only to log a status message — it's never actually used in any API call.

The actual scraping flow is:

  • puppeteer.launch() → navigate to DuckDuckGo → scrape distributor pages directly

For a cookbook recipe, we need the project to demonstrate actual TinyFish API usage — calling https://agent.tinyfish.ai/v1/automation/run-sse with a URL and goal, consuming the SSE response, etc.

The good news is your scraping targets (DigiKey, Mouser, Newark, Arrow, Farnell) are exactly the kind of dynamic sites TinyFish handles well, and replacing Puppeteer with TinyFish calls would actually simplify the code significantly — no need for @sparticuz/chromium, no browser launch logic, no DOM evaluation functions.

Here's roughly what the TinyFish integration would look like for each distributor:

const response = await fetch('https://agent.tinyfish.ai/v1/automation/run-sse', {
  method: 'POST',
  headers: {
    'X-API-Key': process.env.TINYFISH_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    url: `https://www.digikey.com/en/products/result?keywords=${encodeURIComponent(partNumber)}`,
    goal: `Find the product listing for ${partNumber}. Extract: price, availability/stock status, lead time, lifecycle status. Return as JSON.`,
  }),
});

You could launch these in parallel across all distributors and consume the SSE streams.


🟡 Other Items

  • Mino → TinyFish: rename all references (env var should be TINYFISH_API_KEY, update README, types comments, architecture diagram)
  • Root README.md modification: Please remove the change to the root README.md — we add recipes to the table ourselves
  • No .env.example: Add one with TINYFISH_API_KEY= placeholder

Happy to help if you have questions about the TinyFish API integration. The core signal extraction and risk analysis logic you've built is solid — it just needs to be powered by TinyFish instead of Puppeteer.

Copy link
Copy Markdown
Contributor

@simantak-dabhade simantak-dabhade left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requesting changes: project uses Puppeteer instead of TinyFish API. See review comments for details.

@MANASMATHUR
Copy link
Copy Markdown
Contributor Author

Hi @simantak-dabhade , I've made the changes in the repository . Please check

MANASMATHUR and others added 2 commits March 6, 2026 09:16
… add .env.example

- Remove puppeteer, puppeteer-core, @sparticuz/chromium from package.json (no longer used)
- Fix remaining Mino references in types.ts comment and SystemArchitecture.tsx SVG
- Add .env.example with TINYFISH_API_KEY placeholder
- Fix .gitignore to allow .env.example
Copy link
Copy Markdown
Contributor

@simantak-dabhade simantak-dabhade left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work on the rewrite — Puppeteer fully replaced with TinyFish run-sse, parallel scraping across distributors, proper SSE stream parsing. Pushed final cleanup: removed dead Puppeteer deps from package.json, fixed last 2 Mino references, added .env.example. LGTM.

@simantak-dabhade simantak-dabhade merged commit 9713aac into tinyfish-io:main Mar 10, 2026
3 checks passed
KrishnaAgarwal7531 pushed a commit to KrishnaAgarwal7531/TinyFish-cookbook that referenced this pull request Mar 31, 2026
**TinyFish - SiliconSignal** 
SiliconSignal is a high-precision monitoring platform designed to detect
logistics risks, lead-time shifts, and lifecycle transitions in
real-time. By leveraging the Tinyfish web agent (Mino), it extracts live
signals directly from foundry bulletins and primary distributor
channels.
Deployment:- https://silicon-signal.vercel.app

---------

Co-authored-by: Pranav Janakiraman <104693003+pranavjana@users.noreply.github.com>
Co-authored-by: Simantak Dabhade <simantak@mac.local>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants