前面幾天已經示範過檔案掃描、系統負載採集與 JSONata。今天不再重教這些零件,而是把它們組成 E2E 流程的第一個穩定邊界:採集層只提供事實,並輸出後續層可以依賴的 Task Envelope。
本文同步發布於 GitHub:2026-18th-it-ironman

Windows 現況 → 採集 → 契約清洗 → 決策 → 執行
今天的重點不是「怎麼讀記憶體」或「怎麼列出 Downloads」。這一層真正要解決的是:不同來源如何放進同一筆任務、空資料如何表示,以及下游如何知道資料是否完整。
採集層輸出至少包含以下欄位:
| 欄位 | 責任 | 注意事項 |
|---|---|---|
task_id |
追蹤同一筆任務 | 每次採集都要唯一 |
task_type |
指示 Day25 選擇哪個決策契約 | 不可用模糊字串代替 |
source |
標示資料來源 | 方便日後查 Audit Trail |
input.metrics |
當下環境資訊 | 只描述現況,不直接下處置決定 |
input.files |
檔案事件清單 | 沒有檔案時仍為[] |
input.collected_at |
採集時間 | 使用 ISO 8601 |
採集層不應輸出 AI 的 decision、執行用的 action 或任意 PowerShell 指令。把這些責任留給後續層,才能讓採集流程可重複執行,也不會因為資料剛進來就觸發高風險動作。
本篇 Flow 使用 os、fs 與 path 模組取得記憶體現況與 Downloads 檔案清單,但結果不再散落於臨時變數,而是透過防禦性採集與 JSONata 前置標準化,封裝進固定結構:
// 1. 採集記憶體現況事實 (純客觀數據,不預先下處置結論)
const total = os.totalmem();
const free = os.freemem();
const memPercent = Math.round(((total - free) / total) * 100);
// 2. 掃描 Downloads 並過濾未完成檔案 (.crdownload 等)
const dlDir = path.join(os.homedir(), 'Downloads');
let pendingFiles = [];
if (fs.existsSync(dlDir)) {
pendingFiles = fs.readdirSync(dlDir)
.filter(name => !name.startsWith('.') && !name.endsWith('.crdownload'))
.map(name => {
const fullPath = path.join(dlDir, name);
const stat = fs.statSync(fullPath);
return stat.isFile() ? { filename: name, path: fullPath, size_bytes: stat.size, stable: true } : null;
})
.filter(Boolean).slice(0, 5);
}
接著透過 Change 節點的 JSONata 表達式,消除不必要的環境雜訊,整合成標準 Task Envelope:
{
"task_id": "task_1724389200000_abc123",
"task_type": "CLASSIFY_FILE",
"source": "DAY24_INGESTION",
"input": {
"collected_at": "2026-09-16T08:00:00.000Z",
"download_dir": "C:/Users/example/Downloads",
"metrics": { "mem_percent": 62, "is_heavy": false },
"file_count": 1,
"files": [
{ "filename": "Docker_Installer.exe", "size_bytes": 1048576, "stable": true }
]
}
}
files 仍明確保證為空陣列 [] 而不是 null 或 undefined;同時以 stable: true 排除正在寫入中的暫存檔,確保下游 Day 25 遍歷或讀取屬性時永不拋出 TypeError。input 邊界內,上層的通用任務協議外殼永不破損。stable: false,不交給後續分類。task_id 必須不同,不能共用可變的全域資料。is_heavy,不在採集層呼叫 AI 或執行命令。驗收時要檢查的不只是 Debug 有輸出,而是每一筆訊息都能被 Day25 直接接收,且 files、metrics、時間與來源欄位的型別穩定。
在 Node-RED 點擊「右上角選單」➔「匯入」即可一鍵部署:

今天我們建立了 E2E 系統第一層的關鍵防線:採集層只提供結構穩固的客觀事實,不越權做出業務決策。透過雙軌現場捕獲與 JSONata 標準化清洗,產出下游可 100% 依賴的 Universal Task Envelope。
明天我們將進入 Day 25:AI 決策大腦,只依賴這份標準 Envelope,透過多任務路由表與 JSON Schema 硬約束,精準分流並產生可被信賴的結構化處置建議!