agentix-cli 0.52.1 → 0.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{App-X6FGYBLX.js → App-VRTLAPRF.js} +2 -2
- package/dist/{ChatApp-XMUOXQ2M.js → ChatApp-YENWPZT4.js} +2 -2
- package/dist/{agent-KKVMU3VB.js → agent-HVUGHYBF.js} +2 -2
- package/dist/{board-dashboard-KETIFTBD.js → board-dashboard-3XJVYDB3.js} +729 -191
- package/dist/board-dashboard-3XJVYDB3.js.map +1 -0
- package/dist/chunk-2D3RYIDU.js +3 -0
- package/dist/chunk-2D3RYIDU.js.map +1 -0
- package/dist/{chunk-H7R3F2CO.js → chunk-2TJYZF4E.js} +2 -2
- package/dist/chunk-33QV5O6P.js +7 -0
- package/dist/chunk-33QV5O6P.js.map +1 -0
- package/dist/{chunk-MHBUAU2B.js → chunk-37EABIOJ.js} +2 -2
- package/dist/chunk-3RCFUIYR.js +29 -0
- package/dist/chunk-3RCFUIYR.js.map +1 -0
- package/dist/{chunk-B5UA3X6E.js → chunk-3W2KMI5O.js} +2 -2
- package/dist/{chunk-3IUU4YFI.js → chunk-4FFWNPFX.js} +5 -5
- package/dist/chunk-4FFWNPFX.js.map +1 -0
- package/dist/{chunk-7BQQWI4T.js → chunk-4HNHHKJF.js} +2 -2
- package/dist/chunk-6JHA3ZE6.js +1111 -0
- package/dist/chunk-6JHA3ZE6.js.map +1 -0
- package/dist/{chunk-76NNONUJ.js → chunk-BKDUCPZ3.js} +2 -2
- package/dist/{chunk-64UYAWAK.js → chunk-BMSPRUEJ.js} +33 -33
- package/dist/chunk-BMSPRUEJ.js.map +1 -0
- package/dist/{chunk-NKSCUCVZ.js → chunk-ENRJ2QEH.js} +2 -2
- package/dist/{chunk-AWRRBNWQ.js → chunk-HQMISQ7L.js} +2 -2
- package/dist/{chunk-E57WKMRR.js → chunk-KLDGJSR5.js} +2 -2
- package/dist/{ntfy-ZY2NPGBA.js → chunk-KZKDVIOE.js} +3 -3
- package/dist/chunk-KZKDVIOE.js.map +1 -0
- package/dist/{chunk-7NF45XCM.js → chunk-M67AN4J7.js} +2 -2
- package/dist/{chunk-WKTFP3SK.js → chunk-NO2HOK4B.js} +2 -2
- package/dist/chunk-QD6IICK7.js +2 -0
- package/dist/chunk-QD6IICK7.js.map +1 -0
- package/dist/{chunk-QDPLR3SB.js → chunk-QX4R5WY7.js} +2 -2
- package/dist/{chunk-QZ4M2KAC.js → chunk-QYHABRLM.js} +2 -2
- package/dist/{chunk-AKAM4BNC.js → chunk-TLFJVLVQ.js} +166 -160
- package/dist/chunk-TLFJVLVQ.js.map +1 -0
- package/dist/{chunk-YS3Z2Z64.js → chunk-UYMK3XNB.js} +44 -45
- package/dist/chunk-UYMK3XNB.js.map +1 -0
- package/dist/{chunk-7M7VJMGP.js → chunk-WLRHL2P7.js} +2 -2
- package/dist/chunk-WWMFNLKD.js +10 -0
- package/dist/chunk-WWMFNLKD.js.map +1 -0
- package/dist/{chunk-YPPTPBBV.js → chunk-XWU7O3S5.js} +2 -2
- package/dist/{chunk-XOUIZBAQ.js → chunk-ZOJUHPD5.js} +2 -2
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/client-N4XQEAVL.js +2 -0
- package/dist/{compaction-NWPBPWY2.js → compaction-H5U32UU6.js} +2 -2
- package/dist/{config-FGCJVXYX.js → config-KHKIY6LI.js} +2 -2
- package/dist/config-mutator-ZZKFQ7HJ.js +2 -0
- package/dist/doctor-QICAXIQB.js +2 -0
- package/dist/index.d.ts +130 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/memory-extract-F76BE6KA.js +2 -0
- package/dist/ntfy-52EXHVMD.js +2 -0
- package/dist/program-ZWNGK3RB.js +2 -0
- package/dist/{promote-NBFF7ZIW.js → promote-H6ZHJXTY.js} +2 -2
- package/dist/push-HEDA6P3B.js +2 -0
- package/dist/push-HEDA6P3B.js.map +1 -0
- package/dist/push-keys-2DTD7YNQ.js +2 -0
- package/dist/push-store-LXTYULUF.js +2 -0
- package/dist/query-FTE4FLYK.js +2 -0
- package/dist/registry-HDOFVNRK.js +2 -0
- package/dist/{request-planner-ZEXFARZE.js → request-planner-ABD4WIGM.js} +2 -2
- package/dist/{review-candidates-F2HNH2TZ.js → review-candidates-B6574GOJ.js} +2 -2
- package/dist/{routing-XSRZ7V23.js → routing-BGKZOHOA.js} +2 -2
- package/dist/schedule-tool-UDHXTKWV.js +2 -0
- package/dist/scheduler-NQM3HVUY.js +2 -0
- package/dist/scheduler-NQM3HVUY.js.map +1 -0
- package/dist/{seat-IPDLEUI5.js → seat-VGST5AQB.js} +2 -2
- package/dist/seat-VGST5AQB.js.map +1 -0
- package/dist/{select-BYOX63CR.js → select-Y7SBUCGJ.js} +2 -2
- package/dist/set-enabled-ARKMDLXN.js +2 -0
- package/dist/set-enabled-ARKMDLXN.js.map +1 -0
- package/dist/{tool-WW4YCMSP.js → tool-5EVYUN2G.js} +2 -2
- package/dist/wiki-GREI2TSP.js +2 -0
- package/dist/wiki-GREI2TSP.js.map +1 -0
- package/package.json +3 -1
- package/dist/board-dashboard-KETIFTBD.js.map +0 -1
- package/dist/chunk-3IUU4YFI.js.map +0 -1
- package/dist/chunk-64UYAWAK.js.map +0 -1
- package/dist/chunk-6BXKZY76.js +0 -7
- package/dist/chunk-6BXKZY76.js.map +0 -1
- package/dist/chunk-7PK32QT5.js +0 -1107
- package/dist/chunk-7PK32QT5.js.map +0 -1
- package/dist/chunk-AKAM4BNC.js.map +0 -1
- package/dist/chunk-HRBKSZ34.js +0 -2
- package/dist/chunk-HRBKSZ34.js.map +0 -1
- package/dist/chunk-WCNKTV6G.js +0 -28
- package/dist/chunk-WCNKTV6G.js.map +0 -1
- package/dist/chunk-YS3Z2Z64.js.map +0 -1
- package/dist/client-AVQSLPIZ.js +0 -2
- package/dist/config-mutator-5JSG3CHW.js +0 -2
- package/dist/doctor-VITHTLEC.js +0 -2
- package/dist/memory-extract-MGGXIZTE.js +0 -2
- package/dist/ntfy-ZY2NPGBA.js.map +0 -1
- package/dist/program-MNFDOQGQ.js +0 -2
- package/dist/query-XCXR57IV.js +0 -2
- package/dist/registry-5ZP3ZNSH.js +0 -2
- package/dist/schedule-tool-AKCVLCWK.js +0 -2
- package/dist/scheduler-BEGZJWJU.js +0 -2
- package/dist/wiki-IVJJQUKB.js +0 -2
- /package/dist/{App-X6FGYBLX.js.map → App-VRTLAPRF.js.map} +0 -0
- /package/dist/{ChatApp-XMUOXQ2M.js.map → ChatApp-YENWPZT4.js.map} +0 -0
- /package/dist/{agent-KKVMU3VB.js.map → agent-HVUGHYBF.js.map} +0 -0
- /package/dist/{chunk-H7R3F2CO.js.map → chunk-2TJYZF4E.js.map} +0 -0
- /package/dist/{chunk-MHBUAU2B.js.map → chunk-37EABIOJ.js.map} +0 -0
- /package/dist/{chunk-B5UA3X6E.js.map → chunk-3W2KMI5O.js.map} +0 -0
- /package/dist/{chunk-7BQQWI4T.js.map → chunk-4HNHHKJF.js.map} +0 -0
- /package/dist/{chunk-76NNONUJ.js.map → chunk-BKDUCPZ3.js.map} +0 -0
- /package/dist/{chunk-NKSCUCVZ.js.map → chunk-ENRJ2QEH.js.map} +0 -0
- /package/dist/{chunk-AWRRBNWQ.js.map → chunk-HQMISQ7L.js.map} +0 -0
- /package/dist/{chunk-E57WKMRR.js.map → chunk-KLDGJSR5.js.map} +0 -0
- /package/dist/{chunk-7NF45XCM.js.map → chunk-M67AN4J7.js.map} +0 -0
- /package/dist/{chunk-WKTFP3SK.js.map → chunk-NO2HOK4B.js.map} +0 -0
- /package/dist/{chunk-QDPLR3SB.js.map → chunk-QX4R5WY7.js.map} +0 -0
- /package/dist/{chunk-QZ4M2KAC.js.map → chunk-QYHABRLM.js.map} +0 -0
- /package/dist/{chunk-7M7VJMGP.js.map → chunk-WLRHL2P7.js.map} +0 -0
- /package/dist/{chunk-YPPTPBBV.js.map → chunk-XWU7O3S5.js.map} +0 -0
- /package/dist/{chunk-XOUIZBAQ.js.map → chunk-ZOJUHPD5.js.map} +0 -0
- /package/dist/{client-AVQSLPIZ.js.map → client-N4XQEAVL.js.map} +0 -0
- /package/dist/{compaction-NWPBPWY2.js.map → compaction-H5U32UU6.js.map} +0 -0
- /package/dist/{config-FGCJVXYX.js.map → config-KHKIY6LI.js.map} +0 -0
- /package/dist/{config-mutator-5JSG3CHW.js.map → config-mutator-ZZKFQ7HJ.js.map} +0 -0
- /package/dist/{doctor-VITHTLEC.js.map → doctor-QICAXIQB.js.map} +0 -0
- /package/dist/{memory-extract-MGGXIZTE.js.map → memory-extract-F76BE6KA.js.map} +0 -0
- /package/dist/{program-MNFDOQGQ.js.map → ntfy-52EXHVMD.js.map} +0 -0
- /package/dist/{promote-NBFF7ZIW.js.map → program-ZWNGK3RB.js.map} +0 -0
- /package/dist/{query-XCXR57IV.js.map → promote-H6ZHJXTY.js.map} +0 -0
- /package/dist/{registry-5ZP3ZNSH.js.map → push-keys-2DTD7YNQ.js.map} +0 -0
- /package/dist/{routing-XSRZ7V23.js.map → push-store-LXTYULUF.js.map} +0 -0
- /package/dist/{schedule-tool-AKCVLCWK.js.map → query-FTE4FLYK.js.map} +0 -0
- /package/dist/{scheduler-BEGZJWJU.js.map → registry-HDOFVNRK.js.map} +0 -0
- /package/dist/{request-planner-ZEXFARZE.js.map → request-planner-ABD4WIGM.js.map} +0 -0
- /package/dist/{review-candidates-F2HNH2TZ.js.map → review-candidates-B6574GOJ.js.map} +0 -0
- /package/dist/{seat-IPDLEUI5.js.map → routing-BGKZOHOA.js.map} +0 -0
- /package/dist/{wiki-IVJJQUKB.js.map → schedule-tool-UDHXTKWV.js.map} +0 -0
- /package/dist/{select-BYOX63CR.js.map → select-Y7SBUCGJ.js.map} +0 -0
- /package/dist/{tool-WW4YCMSP.js.map → tool-5EVYUN2G.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/daemon/workflow-health.ts","../src/daemon/routines.ts","../src/daemon/mesh-auth.ts","../src/daemon/browser-origin.ts","../src/business/work-pool.ts","../src/business/backlog-store.ts","../src/business/backlog-sync.ts","../src/business/clients.ts","../src/approvals/cards.ts","../src/approvals/inbox.ts","../src/approvals/state.ts","../src/daemon/file-ops.ts","../src/computer-use/capture-settings.ts"],"sourcesContent":["// --- Is the automation still running? -------------------------------------\n//\n// A workflow that stops firing produces nothing: no error, no run, no page\n// entry. On this fleet 16 workflows produced 759 runs and then went quiet for\n// three days without anyone noticing, which is the failure this module exists\n// to make visible. Health is therefore about ABSENCE first and failure second.\n//\n// Cost note: RunStore.get() replays a whole run file. Polling that for every\n// run on every dashboard refresh is not affordable, so we read each file's\n// first line (the snapshot, which carries workflowId) and last line (the\n// terminal status), and cache per file keyed on mtime. Runs are append-only,\n// so after the first scan almost nothing is re-read.\n\nimport { existsSync, readdirSync, readFileSync, statSync } from \"fs\"\nimport { resolve } from \"path\"\n\nexport interface RunSummary { workflowId: string; status: string; at: number }\n\n/** Absence first: a workflow that used to fire and no longer does is the\n * headline, because nothing else in the product will ever mention it. */\nexport type WorkflowState = \"never\" | \"failing\" | \"dormant\" | \"active\" | \"quiet\"\n\nexport interface WorkflowHealth {\n id: string\n name: string\n state: WorkflowState\n /** Last run of any status, ms since epoch. Null when it has never run. */\n lastRunAt: number | null\n recent: number\n prior: number\n failed: number\n /** Runs parked at a checkpoint. These are waiting on a human, not broken. */\n paused: number\n}\n\nexport function workflowHealth(\n workflows: Array<{ id: string; name?: string }>,\n runs: RunSummary[],\n now = Date.now(),\n windowDays = 7,\n): WorkflowHealth[] {\n // One day in ms, inlined: workflowHealth is stringified and shipped to the\n // workflows page, where a module-scope constant would be unbound.\n const span = windowDays * 86_400_000\n const byId = new Map<string, RunSummary[]>()\n for (const r of runs) {\n const list = byId.get(r.workflowId)\n if (list) list.push(r)\n else byId.set(r.workflowId, [r])\n }\n return workflows.map(w => {\n const mine = byId.get(w.id) ?? []\n const recent = mine.filter(r => now - r.at <= span)\n const prior = mine.filter(r => now - r.at > span && now - r.at <= span * 2)\n const failed = recent.filter(r => r.status === \"failed\").length\n const paused = mine.filter(r => r.status === \"paused\").length\n const lastRunAt = mine.length ? Math.max(...mine.map(r => r.at)) : null\n // Order matters: a workflow that has stopped firing is reported as dormant\n // even when its last few runs failed — the silence is the bigger signal.\n const state: WorkflowState =\n !mine.length ? \"never\"\n : prior.length > 0 && recent.length === 0 ? \"dormant\"\n : recent.length > 0 && failed * 2 >= recent.length ? \"failing\"\n : recent.length > 0 ? \"active\"\n : \"quiet\"\n return { id: w.id, name: w.name || w.id, state, lastRunAt, recent: recent.length, prior: prior.length, failed, paused }\n }).sort((a, b) => {\n // Inlined rather than a module constant: workflowHealth is stringified\n // and shipped to the workflows page, where module scope does not travel.\n // A hoisted RANK only failed with two or more workflows, because Array\n // .sort never calls the comparator on a single-element list.\n const rank: Record<string, number> = { dormant: 0, failing: 1, active: 2, quiet: 3, never: 4 }\n return rank[a.state] - rank[b.state] || (b.lastRunAt ?? 0) - (a.lastRunAt ?? 0)\n })\n}\n\n\nconst cache = new Map<string, { mtime: number; summary: RunSummary | null }>()\n\n/** Read workflowId + terminal status per run, re-reading only changed files. */\nexport function scanRuns(runsDir: string, limit = 1000): RunSummary[] {\n if (!existsSync(runsDir)) return []\n const files = readdirSync(runsDir)\n .filter(f => f.endsWith(\".jsonl\"))\n .map(f => { const p = resolve(runsDir, f); return { path: p, mtime: statSync(p).mtimeMs } })\n .sort((a, b) => b.mtime - a.mtime)\n .slice(0, limit)\n const live = new Set(files.map(f => f.path))\n for (const key of cache.keys()) if (!live.has(key)) cache.delete(key)\n const out: RunSummary[] = []\n for (const { path, mtime } of files) {\n const hit = cache.get(path)\n if (hit && hit.mtime === mtime) { if (hit.summary) out.push(hit.summary); continue }\n const summary = readSummary(path, mtime)\n cache.set(path, { mtime, summary })\n if (summary) out.push(summary)\n }\n return out\n}\n\nfunction readSummary(path: string, mtime: number): RunSummary | null {\n try {\n const lines = readFileSync(path, \"utf-8\").split(\"\\n\").filter(Boolean)\n if (!lines.length) return null\n const head = JSON.parse(lines[0]) as { run?: { workflowId?: string; status?: string } }\n const workflowId = head.run?.workflowId\n if (!workflowId) return null\n // The last line is either a status-bearing exec entry or another snapshot;\n // fall back to the snapshot's own status when it carries neither.\n let status = head.run?.status ?? \"unknown\"\n for (let i = lines.length - 1; i >= 0; i--) {\n const tail = JSON.parse(lines[i]) as { status?: string; run?: { status?: string } }\n const s = tail.status ?? tail.run?.status\n if (s) { status = s; break }\n }\n return { workflowId, status, at: mtime }\n } catch { return null }\n}\n","// --- Routines: everything that runs on its own, in one list -----------------\n//\n// Automation lives in two places: time-based `crons.*` jobs and workflows\n// whose trigger node is `trigger.cron` or `trigger.hook`. This module is a\n// read model over both — no new schema — merged into one bounded row shape\n// with a staleness verdict, so obsolete or failing automation surfaces on\n// the mesh overview instead of going unnoticed.\n//\n// Pure: callers pass the job list, the persisted cron attempts (the source\n// of truth; scheduler counters reset on reload), the workflow definitions\n// and the workflow run summaries. Nothing here reads prompts or responses,\n// and every string that leaves it is length-capped.\n//\n// Routine ids are stable and namespaced by source — `cron:<jobId>` and\n// `workflow:<workflowId>` — so later per-routine actions can address a row\n// without knowing which subsystem owns it.\n\nimport type { CronRunHistoryItem } from \"@/crons/run-history\"\nimport { getNextCronDate } from \"@/crons/scheduler\"\nimport { workflowHealth, type RunSummary } from \"./workflow-health\"\n\nexport type RoutineKind = \"schedule\" | \"event\"\nexport type RoutineSource = \"cron\" | \"workflow\"\nexport type RoutineOutcome = \"success\" | \"failed\" | \"timeout\" | \"canceled\" | \"running\" | \"paused\" | \"unknown\"\nexport type RoutineFlagReason = \"failing\" | \"overdue\" | \"dormant\" | \"never-ran\" | \"disabled-long\"\nexport type RoutineAttention = \"critical\" | \"warning\" | \"info\"\n\nexport interface RoutineFlag { reason: RoutineFlagReason; detail: string }\n\nexport interface Routine {\n id: string\n source: RoutineSource\n kind: RoutineKind\n name: string\n trigger: {\n /** Cron expression for schedules. */\n schedule?: string\n timezone?: string\n /** `on:*` event for event routines. */\n event?: string\n /** Compact `key=value` renderings of the trigger filters. */\n filters?: string[]\n }\n agent: string | null\n enabled: boolean\n /** Cron: enabled/disabled. Workflow: active/disabled/quarantined. */\n state: string\n nextRunAt: string | null\n lastRun: { at: string; status: RoutineOutcome; summary?: string } | null\n lastSuccessAt: string | null\n /** Terminal failures in a row, newest first, over the sampled runs. */\n consecutiveFailures: number\n /** Runs inspected to reach the verdict (bounded, not a lifetime total). */\n sampledRuns: number\n flags: RoutineFlag[]\n attention: RoutineAttention | null\n}\n\nexport interface RoutineCronJob {\n id: string\n enabled: boolean\n schedule: string\n timezone?: string\n agent: string\n nextRun?: Date | string\n}\n\nexport interface RoutineWorkflow {\n id: string\n title?: string\n state?: string\n ownerAgent?: string\n project?: string\n updated?: string\n created?: string\n nodes: Array<{ id: string; type: string; config?: Record<string, unknown> }>\n}\n\nexport interface RoutineThresholds {\n /** Consecutive failures that flag a routine as failing. */\n failStreak: number\n /** Days a routine may sit disabled before it reads as obsolete. */\n disabledDays: number\n /** Scheduled fires that may pass without an attempt before it is overdue. */\n missedFires: number\n /** Slack added to the overdue deadline for slow starts and restarts. */\n graceMs: number\n}\n\nexport const DEFAULT_ROUTINE_THRESHOLDS: RoutineThresholds = {\n failStreak: 3,\n disabledDays: 30,\n missedFires: 2,\n graceMs: 15 * 60_000,\n}\n\n/** Hard caps: the list is served on an unauthenticated GET and polled. */\nexport const ROUTINE_LIMITS = { routines: 200, summary: 160, filters: 6, filterValue: 60, text: 120 }\n\nexport type NextFire = (expression: string, after: Date, timezone: string) => Date | null\n\nconst defaultNextFire: NextFire = (expression, after, timezone) => {\n try { return getNextCronDate(expression, after, timezone) } catch { return null }\n}\n\nexport interface BuildRoutinesInput {\n crons: RoutineCronJob[]\n /** Newest-first persisted attempts per cron job id. */\n cronRuns: Map<string, CronRunHistoryItem[]>\n workflows: RoutineWorkflow[]\n workflowRuns: RunSummary[]\n now?: number\n thresholds?: Partial<RoutineThresholds>\n nextFire?: NextFire\n}\n\nconst DAY = 86_400_000\n\nexport function buildRoutines(input: BuildRoutinesInput): Routine[] {\n const now = input.now ?? Date.now()\n const t = { ...DEFAULT_ROUTINE_THRESHOLDS, ...input.thresholds }\n const nextFire = input.nextFire ?? defaultNextFire\n const out: Routine[] = []\n\n for (const job of input.crons) {\n const runs = input.cronRuns.get(job.id) ?? []\n const timezone = job.timezone || \"UTC\"\n const outcomes = runs.map((r) => ({ at: Date.parse(r.startedAt), status: r.status as RoutineOutcome }))\n const latest = runs[0]\n const routine: Routine = {\n id: `cron:${job.id}`,\n source: \"cron\",\n kind: \"schedule\",\n name: cap(job.id, ROUTINE_LIMITS.text),\n trigger: { schedule: cap(job.schedule, ROUTINE_LIMITS.text), timezone },\n agent: job.agent || null,\n enabled: job.enabled,\n state: job.enabled ? \"enabled\" : \"disabled\",\n nextRunAt: job.enabled ? isoOrNull(job.nextRun) ?? isoOrNull(nextFire(job.schedule, new Date(now), timezone)) : null,\n lastRun: latest\n ? { at: latest.startedAt, status: latest.status, summary: capOpt(latest.status === \"success\" ? undefined : latest.errorSummary, ROUTINE_LIMITS.summary) }\n : null,\n lastSuccessAt: runs.find((r) => r.status === \"success\")?.startedAt ?? null,\n consecutiveFailures: failStreak(outcomes),\n sampledRuns: runs.length,\n flags: [],\n attention: null,\n }\n routine.flags = scheduleFlags(routine, outcomes, job.schedule, timezone, null, now, t, nextFire)\n out.push(finish(routine))\n }\n\n const health = new Map(workflowHealth(\n input.workflows.map((w) => ({ id: w.id, name: w.title })), input.workflowRuns, now,\n ).map((h) => [h.id, h] as const))\n const runsByWorkflow = new Map<string, RunSummary[]>()\n for (const r of input.workflowRuns) {\n const list = runsByWorkflow.get(r.workflowId)\n if (list) list.push(r)\n else runsByWorkflow.set(r.workflowId, [r])\n }\n\n for (const wf of input.workflows) {\n const trigger = wf.nodes.find((n) => n.type.startsWith(\"trigger.\"))\n if (!trigger || (trigger.type !== \"trigger.cron\" && trigger.type !== \"trigger.hook\")) continue\n const cfg = (trigger.config ?? {}) as Record<string, unknown>\n const state = wf.state || \"active\"\n const enabled = state === \"active\"\n const runs = (runsByWorkflow.get(wf.id) ?? []).slice().sort((a, b) => b.at - a.at)\n const outcomes = runs.map((r) => ({ at: r.at, status: workflowOutcome(r.status) }))\n const latest = outcomes[0]\n const isCron = trigger.type === \"trigger.cron\"\n const spec = typeof cfg.spec === \"string\" ? cfg.spec : \"\"\n const timezone = typeof cfg.timezone === \"string\" ? cfg.timezone : \"UTC\"\n const routine: Routine = {\n id: `workflow:${wf.id}`,\n source: \"workflow\",\n kind: isCron ? \"schedule\" : \"event\",\n name: cap(wf.title || wf.id, ROUTINE_LIMITS.text),\n trigger: isCron\n ? { schedule: cap(spec, ROUTINE_LIMITS.text), timezone }\n : { event: cap(typeof cfg.event === \"string\" ? cfg.event : \"\", ROUTINE_LIMITS.text), filters: describeFilters(cfg.filter, wf) },\n agent: workflowAgent(wf),\n enabled,\n state,\n nextRunAt: isCron && enabled && spec ? isoOrNull(nextFire(spec, new Date(now), timezone)) : null,\n lastRun: latest ? { at: new Date(latest.at).toISOString(), status: latest.status } : null,\n lastSuccessAt: (() => { const s = outcomes.find((o) => o.status === \"success\"); return s ? new Date(s.at).toISOString() : null })(),\n consecutiveFailures: failStreak(outcomes),\n sampledRuns: runs.length,\n flags: [],\n attention: null,\n }\n const changedAt = Date.parse(wf.updated || wf.created || \"\")\n routine.flags = isCron\n ? scheduleFlags(routine, outcomes, spec, timezone, Number.isFinite(changedAt) ? changedAt : null, now, t, nextFire)\n : eventFlags(routine, health.get(wf.id)?.state === \"dormant\", Number.isFinite(changedAt) ? changedAt : null, now, t)\n out.push(finish(routine))\n }\n\n return out.sort(compareRoutines).slice(0, ROUTINE_LIMITS.routines)\n}\n\n/** Terminal failures in a row from the newest run. In-flight and parked\n * runs are skipped; a success or cancel ends the streak. */\nexport function failStreak(outcomes: Array<{ status: RoutineOutcome }>): number {\n let n = 0\n for (const o of outcomes) {\n if (o.status === \"running\" || o.status === \"paused\" || o.status === \"unknown\") continue\n if (o.status === \"failed\" || o.status === \"timeout\") n++\n else break\n }\n return n\n}\n\nfunction scheduleFlags(\n r: Routine,\n outcomes: Array<{ at: number; status: RoutineOutcome }>,\n spec: string,\n timezone: string,\n changedAt: number | null,\n now: number,\n t: RoutineThresholds,\n nextFire: NextFire,\n): RoutineFlag[] {\n const flags: RoutineFlag[] = []\n const lastAt = outcomes.length ? outcomes[0].at : null\n if (!r.enabled) {\n const disabled = disabledFlag(lastAt, changedAt, now, t)\n if (disabled) flags.push(disabled)\n return flags\n }\n if (r.consecutiveFailures >= t.failStreak) {\n flags.push({ reason: \"failing\", detail: `${r.consecutiveFailures} failed attempts in a row` })\n }\n if (lastAt === null) {\n flags.push({ reason: \"never-ran\", detail: \"No persisted attempt\" })\n return flags\n }\n // Walk the schedule forward from the last attempt: if `missedFires`\n // expected fires have already passed (plus grace), the job has gone quiet.\n let cursor = new Date(lastAt)\n let deadline: Date | null = null\n for (let i = 0; i < t.missedFires; i++) {\n deadline = nextFire(spec, cursor, timezone)\n if (!deadline) break\n cursor = deadline\n }\n if (deadline && now > deadline.getTime() + t.graceMs) {\n flags.push({ reason: \"overdue\", detail: `No attempt since ${new Date(lastAt).toISOString()}; ${t.missedFires} scheduled fires missed` })\n }\n return flags\n}\n\nfunction eventFlags(\n r: Routine,\n dormant: boolean,\n changedAt: number | null,\n now: number,\n t: RoutineThresholds,\n): RoutineFlag[] {\n const flags: RoutineFlag[] = []\n const lastAt = r.lastRun ? Date.parse(r.lastRun.at) : null\n if (!r.enabled) {\n const disabled = disabledFlag(lastAt, changedAt, now, t)\n if (disabled) flags.push(disabled)\n return flags\n }\n if (r.consecutiveFailures >= t.failStreak) {\n flags.push({ reason: \"failing\", detail: `${r.consecutiveFailures} failed runs in a row` })\n }\n if (lastAt === null) flags.push({ reason: \"never-ran\", detail: \"No run recorded for this trigger\" })\n else if (dormant) flags.push({ reason: \"dormant\", detail: \"Fired in the prior week, silent in the last one\" })\n return flags\n}\n\nfunction disabledFlag(lastAt: number | null, changedAt: number | null, now: number, t: RoutineThresholds): RoutineFlag | null {\n // Crons carry no \"disabled since\" timestamp, so the last attempt (or the\n // workflow's last edit) is the best available proxy for how long it sat.\n const since = Math.max(lastAt ?? 0, changedAt ?? 0)\n if (since && now - since < t.disabledDays * DAY) return null\n return {\n reason: \"disabled-long\",\n detail: since ? `Disabled; no activity for ${Math.floor((now - since) / DAY)} days` : \"Disabled and never ran\",\n }\n}\n\nfunction finish(r: Routine): Routine {\n const reasons = new Set(r.flags.map((f) => f.reason))\n r.attention = reasons.has(\"failing\") ? \"critical\"\n : reasons.has(\"overdue\") || reasons.has(\"dormant\") || reasons.has(\"never-ran\") ? \"warning\"\n : reasons.has(\"disabled-long\") ? \"info\"\n : null\n return r\n}\n\nconst ATTENTION_RANK: Record<string, number> = { critical: 0, warning: 1, info: 2 }\n\nfunction compareRoutines(a: Routine, b: Routine): number {\n const ra = a.attention ? ATTENTION_RANK[a.attention] : 3\n const rb = b.attention ? ATTENTION_RANK[b.attention] : 3\n return ra - rb || Number(b.enabled) - Number(a.enabled) || a.name.localeCompare(b.name)\n}\n\n/** Map a workflow run's last recorded status onto the routine vocabulary.\n * The tail line may be a node execution entry (`ok`), not a run status. */\nexport function workflowOutcome(status: string): RoutineOutcome {\n switch (status) {\n case \"completed\": case \"ok\": return \"success\"\n case \"failed\": return \"failed\"\n case \"timeout\": return \"timeout\"\n case \"canceled\": return \"canceled\"\n case \"running\": return \"running\"\n case \"paused\": return \"paused\"\n default: return \"unknown\"\n }\n}\n\nfunction workflowAgent(wf: RoutineWorkflow): string | null {\n if (wf.ownerAgent) return cap(wf.ownerAgent, ROUTINE_LIMITS.text)\n const node = wf.nodes.find((n) => n.type === \"agent\" && typeof n.config?.agentId === \"string\" && n.config.agentId)\n return node ? cap(String(node.config!.agentId), ROUTINE_LIMITS.text) : null\n}\n\n/** `filter.action = [\"open\",\"reopen\"]` → `action=open,reopen`. The workflow's\n * project scope is a filter too: it silently drops other projects' events. */\nexport function describeFilters(filter: unknown, wf?: { project?: string }): string[] {\n const out: string[] = []\n const project = wf?.project\n if (project) out.push(cap(`project=${project}`, ROUTINE_LIMITS.filterValue))\n if (filter && typeof filter === \"object\" && !Array.isArray(filter)) {\n for (const [key, value] of Object.entries(filter as Record<string, unknown>)) {\n const values = Array.isArray(value) ? value.map(String) : value == null ? [] : [String(value)]\n if (!values.length) continue\n out.push(cap(`${key}=${values.join(\",\")}`, ROUTINE_LIMITS.filterValue))\n }\n }\n return out.slice(0, ROUTINE_LIMITS.filters)\n}\n\nfunction isoOrNull(v: Date | string | null | undefined): string | null {\n if (!v) return null\n const d = v instanceof Date ? v : new Date(v)\n return Number.isFinite(d.getTime()) ? d.toISOString() : null\n}\n\nfunction cap(value: string, limit: number): string {\n return value.length <= limit ? value : value.slice(0, limit - 3) + \"...\"\n}\n\nfunction capOpt(value: string | undefined, limit: number): string | undefined {\n return value === undefined ? undefined : cap(value, limit)\n}\n","// --- Inbound auth decision for the daemon's mesh surface ---\n//\n// Pure decision logic, kept out of the daemon class so it can be unit\n// tested. The daemon wraps this with logging and the 401 response.\n//\n// Model: mesh peers have always sent `Authorization: Bearer <token>`\n// (a2a/mesh.ts sendTask), so verifying it server-side is compatible with\n// existing paired meshes. Loopback callers (CLI, same-host dashboard,\n// local tools) are exempt. Installs with no token configured anywhere\n// pass with a warning — that grace path is scheduled for removal.\n\nexport interface MeshAuthRequest {\n /** req.socket.remoteAddress */\n remoteAddress: string\n /** Raw Authorization header value (\"\" when absent). */\n authorizationHeader: string\n /** All tokens this node accepts: MESH_TOKEN, peer tokens, dashboard.token. */\n acceptedTokens: ReadonlySet<string>\n /** AGENTX_MESH_AUTH=off escape hatch. */\n enforcementDisabled?: boolean\n /** A browser says the request comes from another origin's page (see\n * browser-origin.ts). Such a page is not the operator, even though the\n * browser that sends it sits on loopback. */\n foreignBrowser?: boolean\n}\n\nexport type MeshAuthDecision =\n | { allowed: true; reason: \"disabled\" | \"loopback\" | \"token\" | \"no-tokens-configured\" }\n | { allowed: false; reason: \"missing-or-invalid-token\" | \"foreign-browser-origin\" }\n\nconst LOOPBACK = new Set([\"127.0.0.1\", \"::1\", \"::ffff:127.0.0.1\"])\n\n/** Routes gated for every method, reads included. Agent memory is\n * injected into every future session of its agent, so an off-box write\n * is a persistent prompt injection and an off-box read can leak what an\n * agent noted down. Agents reach it with `curl localhost` from their own\n * Bash, which the loopback exemption keeps working. */\nexport function isMeshGatedPath(path: string): boolean {\n return path === \"/api/memory\" || path.startsWith(\"/api/memory/\") ||\n // Approvals list held memory facts and draft wiki articles, and a card\n // written from off-box would ask the operator in an agent's name.\n path === \"/approvals\" || path.startsWith(\"/approvals/\") ||\n // Recent events name agents, chats and errors across the node.\n path === \"/events/recent\"\n}\n\n/** Control POSTs that act as this daemon: reload its config, stop or\n * steer a running task, kill an agent process, or send a message on one\n * of its channels. The CLI, TUI and same-host dashboard reach them over\n * loopback; an off-box caller needs a mesh token. */\nexport function isControlPost(path: string): boolean {\n return path === \"/reload\" || path === \"/api/processes/kill\" ||\n path === \"/send\" || path === \"/send/agent\" || path === \"/send/contact\" ||\n /^\\/api\\/tasks\\/[^/]+\\/(cancel|followup)$/.test(path)\n}\n\n/** True when the socket peer is on this host. Used by loopback-only\n * endpoints (e.g. the guard hook) that must never be reachable off-box. */\nexport function isLoopback(remoteAddress: string): boolean {\n return LOOPBACK.has(remoteAddress)\n}\n\nexport function decideMeshAuth(req: MeshAuthRequest): MeshAuthDecision {\n // Checked before every exemption: loopback, the no-token grace path and\n // the off switch all exist for the operator's own tools, not for pages.\n if (req.foreignBrowser) return { allowed: false, reason: \"foreign-browser-origin\" }\n if (req.enforcementDisabled) return { allowed: true, reason: \"disabled\" }\n if (LOOPBACK.has(req.remoteAddress)) return { allowed: true, reason: \"loopback\" }\n if (req.acceptedTokens.size === 0) return { allowed: true, reason: \"no-tokens-configured\" }\n\n const header = req.authorizationHeader || \"\"\n const token = header.startsWith(\"Bearer \") ? header.slice(7).trim() : \"\"\n if (token && req.acceptedTokens.has(token)) return { allowed: true, reason: \"token\" }\n\n return { allowed: false, reason: \"missing-or-invalid-token\" }\n}\n\n/** Config shape this module needs. Structural so callers can pass a full\n * DaemonConfig without this module importing it. */\nexport interface MeshTokenSources {\n mesh?: { peers?: Array<{ token?: string }> }\n dashboard?: { token?: string }\n}\n\n/**\n * Every token accepted on a mesh WRITE path.\n *\n * MESH_TOKEN and per-peer tokens only. `dashboard.token` is deliberately\n * NOT included: it is the most widely handled secret in the config — it\n * sits in dashboard settings and travels alongside peer entries — and\n * accepting it here made it sufficient to POST /task, /channel/send, and\n * the peer-identity forwards that make the daemon act as its own GitLab\n * and GitHub bot.\n *\n * A dashboard on the same host reaches the daemon over loopback, which\n * decideMeshAuth exempts before tokens are consulted. A dashboard on a\n * different host needs a real mesh credential instead.\n */\nexport function collectAcceptedMeshTokens(\n config: MeshTokenSources,\n env: Record<string, string | undefined> = process.env,\n): Set<string> {\n const accepted = new Set<string>()\n if (env.MESH_TOKEN) accepted.add(env.MESH_TOKEN)\n for (const p of config.mesh?.peers || []) if (p.token) accepted.add(p.token)\n return accepted\n}\n\n/**\n * Bearer token the dashboard sends to `target` (a normalized node URL).\n *\n * The primary daemon gets dashboard.token and a configured\n * dashboard.daemons[] entry gets its own token. Without one (a peer the\n * dashboard only learned about through /mesh, or a primary with no\n * dashboard.token) it falls back to MESH_TOKEN, the credential every node\n * in the mesh accepts.\n */\nexport function dashboardTokenForNode(\n dashboard: { daemonUrl: string; token?: string; daemons: Array<{ url: string; token?: string }> },\n target: string,\n env: Record<string, string | undefined> = process.env,\n): string | undefined {\n const norm = (u: string) => u.replace(/\\/+$/, \"\")\n const configured = target === norm(dashboard.daemonUrl)\n ? dashboard.token\n : dashboard.daemons.find((d) => norm(d.url) === target)?.token\n return configured || env.MESH_TOKEN || undefined\n}\n","import type { IncomingHttpHeaders } from \"http\"\n\n// --- Browser-origin guard for the daemon and dashboard HTTP servers ---\n//\n// Both servers trust loopback callers, and a browser on the same machine is\n// a loopback caller. So any web page open in that browser could make it call\n// these servers: send an agent a task, write agent memory, post to a channel.\n// Neither server has a cross-origin browser client (dashboard pages call the\n// dashboard; daemon pages call the daemon; everything else is curl, the CLI,\n// native apps or server-to-server, none of which send Origin), so a request\n// the browser marks as coming from another origin is not trusted.\n//\n// Pure functions, unit tested; the servers add the 403 and the logging.\n\nexport type BrowserOrigin =\n /** No browser origin marker: curl, CLI, native apps, servers. */\n | \"none\"\n /** A page served by this same server. */\n | \"same-origin\"\n /** A page from any other origin, including another port on this host. */\n | \"foreign\"\n\nfunction first(v: string | string[] | undefined): string {\n return (Array.isArray(v) ? v[0] : v)?.trim() ?? \"\"\n}\n\nfunction originHost(origin: string): string | null {\n try {\n return new URL(origin).host.toLowerCase()\n } catch {\n // Opaque origins (\"null\": sandboxed iframes, file://) never match.\n return null\n }\n}\n\n/** Extra trusted origins, for a dashboard served through a reverse proxy\n * under another host name. Comma-separated full origins. */\nexport function allowedOriginsFromEnv(env: NodeJS.ProcessEnv = process.env): Set<string> {\n return new Set(\n (env.AGENTX_ALLOWED_ORIGINS || \"\")\n .split(\",\")\n .map((s) => s.trim().replace(/\\/+$/, \"\").toLowerCase())\n .filter(Boolean),\n )\n}\n\nexport function classifyBrowserRequest(\n headers: IncomingHttpHeaders,\n extraAllowed: ReadonlySet<string> = allowedOriginsFromEnv(),\n): BrowserOrigin {\n const origin = first(headers.origin)\n if (origin) {\n if (extraAllowed.has(origin.replace(/\\/+$/, \"\").toLowerCase())) return \"same-origin\"\n const from = originHost(origin)\n const hosts = [first(headers.host), first(headers[\"x-forwarded-host\"])]\n .filter(Boolean)\n .map((h) => h.toLowerCase())\n return from && hosts.includes(from) ? \"same-origin\" : \"foreign\"\n }\n // Browsers omit Origin on plain GET navigations and image loads, but\n // modern ones still say where the request came from. localhost on\n // another port is \"same-site\", and it is still someone else's page.\n const site = first(headers[\"sec-fetch-site\"]).toLowerCase()\n if (site === \"cross-site\" || site === \"same-site\") return \"foreign\"\n return \"none\"\n}\n\n/** Methods that change state, plus the CORS preflight that precedes a\n * cross-origin write. A foreign page gets none of these. */\nexport function isStateChangingOrPreflight(method: string | undefined): boolean {\n const m = (method || \"GET\").toUpperCase()\n return m !== \"GET\" && m !== \"HEAD\"\n}\n","import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from \"fs\"\nimport { resolve, join } from \"path\"\nimport type { BusinessConfig, BusinessWorkSource } from \"./config\"\nimport type { DaemonConfig } from \"@/daemon/config\"\nimport { BacklogStore } from \"./backlog-store\"\nimport { syncBacklogItemToSource, resolveAssigneesForSource, type BacklogPatch } from \"./backlog-sync\"\n\n// --- Work pool: pluggable source of tasks for the business layer ---\n\nexport interface WorkItem {\n id: string // stable id for claim/report (e.g. \"backlog:line-12\", \"gitlab:proj:issue:42\")\n title: string\n description?: string\n assignee?: string // agentId\n estimatedSeconds?: number\n url?: string\n priority?: number // lower = higher priority\n /** Board stage / kanban column id. Was a closed enum back when boards\n * had a fixed schema; widened to `string` because per-project boards\n * can declare arbitrary column ids. The well-known names below remain\n * the standard set most boards use. */\n stage?: string // typically: \"triage\" | \"todo\" | \"doing\" | \"onhold\" | \"review\" | \"done\"\n /** Raw labels from the source (GitLab). Empty array if source doesn't support labels. */\n labels?: string[]\n /** Label name+color when the source returns colored labels (GitLab with_labels_details). */\n labelDetails?: Array<{ name: string; color: string; text_color?: string }>\n /** ISO timestamp of last update on the source. */\n updatedAt?: string\n /** Open/closed state from the source. */\n state?: \"opened\" | \"closed\"\n /** Optional milestone title (GitLab: issue.milestone.title). */\n milestone?: string\n /** GitLab assignees (0..n). `assignee` above is the agentId alias for assignees[0]. */\n assignees?: Array<{ username: string; name?: string; avatarUrl?: string }>\n}\n\n/** Member of a source (GitLab project members) — used for assignee pickers. */\nexport interface WorkMember {\n username: string\n name?: string\n avatarUrl?: string\n}\n\n/** Milestone on a source — used for milestone pickers. */\nexport interface WorkMilestone {\n id: number | string\n title: string\n state?: \"active\" | \"closed\"\n dueDate?: string\n}\n\n/** Full issue detail — a superset of WorkItem for the detail view. */\nexport interface WorkDetail extends WorkItem {\n /** Raw body, may be markdown. */\n descriptionHtml?: string\n /** ISO timestamp of creation. */\n createdAt?: string\n /** Author (issue reporter). */\n author?: { username: string; name?: string; avatarUrl?: string }\n /** Full labels list (all of them). */\n allLabels?: string[]\n}\n\nexport interface WorkReport {\n status: \"in-progress\" | \"done\" | \"blocked\"\n note?: string\n timeSeconds?: number\n blocker?: string\n}\n\n/** What a WorkSource can do beyond the minimal listOpen/claim/report triple. */\nexport interface WorkSourceCapabilities {\n /** Enumerate items beyond assignee filter — required for a board view. */\n listAll: boolean\n /** Create new items (e.g. POST GitLab issue). */\n create: boolean\n /** Arbitrary column transitions (label add/remove pair). */\n transition: boolean\n /** Surfaces labels[] on returned items. */\n labels: boolean\n /** Server-side text search. */\n search: boolean\n}\n\nexport interface WorkCreateInput {\n title: string\n description?: string\n /** agentId */\n assignee?: string\n /** Raw GitLab usernames — bypass agentId resolution for UI-driven creates. */\n assigneeUsernames?: string[]\n labels?: string[]\n /** Milestone title (resolved to id). */\n milestoneTitle?: string\n /** For sources that span multiple projects (gitlab): \"group/project\". */\n projectHint?: string\n}\n\nexport interface ListAllOpts {\n sinceDays?: number\n labels?: string[]\n /** Exclude items carrying any of these labels (client-side filter). */\n notLabels?: string[]\n /** Exclude items whose labels carry this scoped prefix (e.g. \"Status\"). */\n withoutScopedPrefix?: string\n search?: string\n assignee?: string\n /** GitLab issue state. Defaults to \"opened\" (boards hide closed issues). */\n state?: \"opened\" | \"closed\" | \"all\"\n /** Milestone filter (GitLab \"milestone\" query param). */\n milestone?: string\n}\n\nexport interface WorkSource {\n type: string\n capabilities: WorkSourceCapabilities\n listOpen(agentId: string): Promise<WorkItem[]>\n claim(agentId: string, itemId: string): Promise<void>\n report(itemId: string, update: WorkReport): Promise<void>\n /** Optional — gated by capabilities.listAll. */\n listAll?(opts: ListAllOpts): Promise<WorkItem[]>\n /** Optional — gated by capabilities.create. */\n create?(input: WorkCreateInput): Promise<WorkItem>\n /**\n * Optional — gated by capabilities.transition. Add `toLabel` and remove\n * `fromLabel` (if provided) from the item. Used by the kanban board on drag.\n */\n transition?(itemId: string, toLabel: string, fromLabel?: string): Promise<void>\n}\n\n// ---------- BacklogWorkSource: GFM checklist file ----------\n// Format in .agentx/backlog.md (or configured path):\n//\n// - [ ] @alice Implement login form [time: 2h]\n// - [x] @alice Write unit tests (done)\n// - [ ] @bob Design pricing page [time: 1h30m]\n//\n// Line number is the stable id.\n\nconst CHECK_RE = /^(\\s*)-\\s*\\[( |x|X)\\]\\s*(.*)$/\nconst MENTION_RE = /@([a-z0-9_-]+)/i\nconst TIME_RE = /\\[time:\\s*([0-9hm\\s]+)\\]/i\n\nfunction parseDuration(s: string): number {\n // \"2h30m\" -> 9000 s. \"1h\" -> 3600. \"45m\" -> 2700.\n const hMatch = s.match(/(\\d+)\\s*h/i)\n const mMatch = s.match(/(\\d+)\\s*m/i)\n return (hMatch ? parseInt(hMatch[1], 10) * 3600 : 0) + (mMatch ? parseInt(mMatch[1], 10) * 60 : 0)\n}\n\nexport class BacklogWorkSource implements WorkSource {\n type = \"backlog\"\n capabilities: WorkSourceCapabilities = {\n listAll: true, create: false, transition: false, labels: true, search: false,\n }\n private store: BacklogStore\n\n constructor(\n private path: string,\n private daemon?: DaemonConfig,\n private log: (...args: unknown[]) => void = () => {},\n ) {\n this.store = new BacklogStore(this.path)\n }\n\n /** Expose the store so the CLI and sync-back can share state. */\n getStore(): BacklogStore {\n return this.store\n }\n\n private readMd(): string[] {\n const full = resolve(process.cwd(), this.path)\n if (!existsSync(full)) return []\n return readFileSync(full, \"utf-8\").split(\"\\n\")\n }\n\n private writeMd(lines: string[]): void {\n const full = resolve(process.cwd(), this.path)\n writeFileSync(full, lines.join(\"\\n\"))\n }\n\n async listOpen(agentId: string): Promise<WorkItem[]> {\n if (this.store.exists()) {\n const items = this.store.list().filter((it) =>\n it.status !== \"done\" &&\n (!it.assignee || it.assignee.toLowerCase() === agentId.toLowerCase()),\n )\n return items.map((it) => this.toWorkItem(it))\n }\n // Legacy markdown-checklist fallback (unchanged behavior).\n const lines = this.readMd()\n const items: WorkItem[] = []\n for (let i = 0; i < lines.length; i++) {\n const m = lines[i].match(CHECK_RE)\n if (!m) continue\n const checked = m[2].toLowerCase() === \"x\"\n if (checked) continue\n const body = m[3]\n const mention = body.match(MENTION_RE)\n if (mention && mention[1].toLowerCase() !== agentId.toLowerCase()) continue\n const timeMatch = body.match(TIME_RE)\n const title = body.replace(MENTION_RE, \"\").replace(TIME_RE, \"\").trim()\n items.push({\n id: `backlog:${i}`,\n title: title || `Task at line ${i + 1}`,\n assignee: mention ? mention[1] : undefined,\n estimatedSeconds: timeMatch ? parseDuration(timeMatch[1]) : undefined,\n priority: i,\n })\n }\n return items\n }\n\n async listAll(_opts: ListAllOpts = {}): Promise<WorkItem[]> {\n if (!this.store.exists()) return []\n return this.store.list().map((it) => this.toWorkItem(it))\n }\n\n async claim(agentId: string, itemId: string): Promise<void> {\n if (!this.store.exists()) return\n const item = this.store.findById(itemId)\n if (!item) return\n const updated = this.store.update(itemId, {\n assignee: item.assignee || agentId,\n status: \"doing\",\n })\n if (updated.source && this.daemon) {\n const usernames = resolveAssigneesForSource([updated.assignee || agentId], updated.source, this.daemon)\n void syncBacklogItemToSource(updated, {\n assigneeUsernames: usernames,\n addLabels: [\"Doing\"],\n removeLabels: [\"To Do\"],\n }, this.daemon, this.log).catch((e) =>\n this.log(`[backlog-sync] claim failed for ${itemId}: ${e?.message ?? e}`),\n )\n }\n }\n\n async report(itemId: string, update: WorkReport): Promise<void> {\n // Structured store path.\n if (this.store.exists() && this.store.findById(itemId)) {\n const patch: Partial<import(\"./backlog-store\").BacklogItem> = {}\n if (update.status === \"done\") patch.status = \"done\"\n else if (update.status === \"blocked\") {\n patch.status = \"blocked\"\n patch.blocker = update.blocker || update.note || undefined\n } else if (update.status === \"in-progress\") patch.status = \"doing\"\n if (update.timeSeconds) patch.estimatedSeconds = update.timeSeconds\n const item = this.store.update(itemId, patch)\n\n if (item.source && this.daemon) {\n const sourcePatch: BacklogPatch = {}\n if (update.status === \"done\") {\n sourcePatch.addLabels = [\"Done\"]\n sourcePatch.removeLabels = [\"Doing\"]\n } else if (update.status === \"blocked\") {\n sourcePatch.addLabels = [\"Blocked\"]\n }\n if (update.note) sourcePatch.note = update.note\n if (Object.keys(sourcePatch).length) {\n void syncBacklogItemToSource(item, sourcePatch, this.daemon, this.log).catch((e) =>\n this.log(`[backlog-sync] report failed for ${itemId}: ${e?.message ?? e}`),\n )\n }\n }\n return\n }\n\n // Legacy markdown path (line-number ids).\n if (!itemId.startsWith(\"backlog:\")) throw new Error(`not a backlog id: ${itemId}`)\n const lineNo = parseInt(itemId.slice(\"backlog:\".length), 10)\n const lines = this.readMd()\n const line = lines[lineNo]\n if (!line) throw new Error(`backlog line ${lineNo} missing`)\n const m = line.match(CHECK_RE)\n if (!m) throw new Error(`backlog line ${lineNo} not a checkbox`)\n\n if (update.status === \"done\") {\n lines[lineNo] = line.replace(/- \\[ \\]/, \"- [x]\")\n const note = update.timeSeconds\n ? ` <!-- done by agent, ${Math.round(update.timeSeconds / 60)}m -->`\n : \" <!-- done by agent -->\"\n lines.splice(lineNo + 1, 0, note)\n } else if (update.status === \"blocked\") {\n lines.splice(lineNo + 1, 0, ` <!-- BLOCKED: ${update.blocker || update.note || \"?\"} -->`)\n } else if (update.note) {\n lines.splice(lineNo + 1, 0, ` <!-- ${update.note.replace(/-->/g, \"— >\")} -->`)\n }\n this.writeMd(lines)\n }\n\n private toWorkItem(it: import(\"./backlog-store\").BacklogItem): WorkItem {\n const stage = ({ todo: \"todo\", doing: \"doing\", blocked: \"onhold\", done: \"done\" } as const)[it.status]\n return {\n id: it.id,\n title: it.title,\n description: it.description,\n assignee: it.assignee,\n estimatedSeconds: it.estimatedSeconds,\n priority: it.priority,\n labels: it.labels,\n stage,\n milestone: it.milestone,\n url: it.source?.url,\n updatedAt: it.updatedAt,\n state: it.status === \"done\" ? \"closed\" : \"opened\",\n }\n }\n}\n\n// ---------- WikiWorkSource: scan markdown files for @mention checkboxes ----------\n\nexport class WikiWorkSource implements WorkSource {\n type = \"wiki\"\n capabilities: WorkSourceCapabilities = {\n listAll: false, create: false, transition: false, labels: false, search: false,\n }\n constructor(private root: string, private glob: string) {}\n\n private walk(dir: string, out: string[]): void {\n if (!existsSync(dir)) return\n for (const entry of readdirSync(dir)) {\n const full = join(dir, entry)\n const st = statSync(full)\n if (st.isDirectory()) {\n this.walk(full, out)\n } else if (entry.endsWith(\".md\")) {\n out.push(full)\n }\n }\n }\n\n async listOpen(agentId: string): Promise<WorkItem[]> {\n const files: string[] = []\n this.walk(resolve(process.cwd(), this.root), files)\n const items: WorkItem[] = []\n for (const file of files) {\n const lines = readFileSync(file, \"utf-8\").split(\"\\n\")\n for (let i = 0; i < lines.length; i++) {\n const m = lines[i].match(CHECK_RE)\n if (!m || m[2].toLowerCase() === \"x\") continue\n const mention = m[3].match(MENTION_RE)\n if (!mention || mention[1].toLowerCase() !== agentId.toLowerCase()) continue\n items.push({\n id: `wiki:${file}:${i}`,\n title: m[3].replace(MENTION_RE, \"\").trim(),\n assignee: mention[1],\n priority: i,\n })\n }\n }\n return items\n }\n\n async claim(): Promise<void> { /* no-op */ }\n\n async report(itemId: string, update: WorkReport): Promise<void> {\n // wiki:<file>:<line>\n const parts = itemId.split(\":\")\n const lineNo = parseInt(parts[parts.length - 1], 10)\n const file = parts.slice(1, -1).join(\":\")\n if (!existsSync(file)) return\n const lines = readFileSync(file, \"utf-8\").split(\"\\n\")\n if (update.status === \"done\" && lines[lineNo]) {\n lines[lineNo] = lines[lineNo].replace(/- \\[ \\]/, \"- [x]\")\n writeFileSync(file, lines.join(\"\\n\"))\n }\n }\n}\n\n// ---------- GitLabWorkSource: assignee-filtered issues via GitLab API ----------\n\nexport class GitLabWorkSource implements WorkSource {\n type = \"gitlab\"\n capabilities: WorkSourceCapabilities = {\n listAll: true, create: true, transition: true, labels: true, search: true,\n }\n\n constructor(\n private host: string,\n private token: string,\n private projects: string[],\n /** Map from agentId -> GitLab username(s) */\n private agentUsernames: Record<string, string[]>,\n private log: (...args: unknown[]) => void,\n ) {}\n\n /** Reverse lookup: GitLab username -> agentId. Used when resolving board items\n * back to an agent (for the reconciler and card display). */\n private usernameToAgent(username: string): string | undefined {\n for (const [agentId, names] of Object.entries(this.agentUsernames)) {\n if (names.some((n) => n.toLowerCase() === username.toLowerCase())) return agentId\n }\n return undefined\n }\n\n private mapIssue(issue: any, project: string): WorkItem {\n const ns = issue.references?.full?.split(\"#\")[0] || project\n // `labels` may be a string[] or, with with_labels_details=true, an object[].\n let labels: string[] = []\n let labelDetails: Array<{ name: string; color: string; text_color?: string }> | undefined\n if (Array.isArray(issue.labels)) {\n if (issue.labels.length && typeof issue.labels[0] === \"object\") {\n labelDetails = issue.labels.map((l: any) => ({\n name: l.name, color: l.color, text_color: l.text_color,\n }))\n labels = labelDetails!.map((l) => l.name)\n } else {\n labels = issue.labels\n }\n }\n const rawAssignees: any[] = Array.isArray(issue.assignees) && issue.assignees.length\n ? issue.assignees\n : (issue.assignee ? [issue.assignee] : [])\n const assignees = rawAssignees.map((a) => ({\n username: a.username, name: a.name, avatarUrl: a.avatar_url,\n }))\n const firstUsername = assignees[0]?.username\n return {\n id: `gitlab:${ns}:issue:${issue.iid}`,\n title: issue.title,\n description: issue.description || undefined,\n // Prefer configured agentId mapping; fall back to the raw GitLab username\n // so cards still render an assignee even without agentMappings configured.\n assignee: firstUsername ? (this.usernameToAgent(firstUsername) || firstUsername) : undefined,\n assignees,\n url: issue.web_url,\n priority: issue.weight ?? 99,\n estimatedSeconds: issue.time_stats?.time_estimate || undefined,\n labels,\n labelDetails,\n updatedAt: issue.updated_at,\n state: issue.state === \"closed\" ? \"closed\" : \"opened\",\n milestone: issue.milestone?.title || undefined,\n }\n }\n\n private async api(path: string, init: RequestInit = {}): Promise<any> {\n const res = await fetch(`${this.host}/api/v4${path}`, {\n ...init,\n headers: {\n \"PRIVATE-TOKEN\": this.token,\n \"Content-Type\": \"application/json\",\n ...(init.headers || {}),\n },\n })\n if (!res.ok) throw new Error(`GitLab ${res.status}: ${await res.text().catch(() => \"\")}`)\n return res.json()\n }\n\n async listOpen(agentId: string): Promise<WorkItem[]> {\n const usernames = this.agentUsernames[agentId] || []\n if (!usernames.length) return []\n\n const items: WorkItem[] = []\n const projectList = this.projects.length\n ? this.projects\n : [\"__ALL__\"] // falls back to a global issues query\n\n for (const username of usernames) {\n for (const project of projectList) {\n try {\n const q = `assignee_username=${encodeURIComponent(username)}&state=opened&scope=all&per_page=20`\n const path = project === \"__ALL__\"\n ? `/issues?${q}`\n : `/projects/${encodeURIComponent(project)}/issues?${q}`\n const issues = await this.api(path)\n for (const issue of issues) {\n const item = this.mapIssue(issue, project)\n // Force assignee to the agent we queried for (listOpen is per-agent).\n item.assignee = agentId\n items.push(item)\n }\n } catch (e: any) {\n this.log(`[business] GitLab listOpen failed for ${username} on ${project}: ${e.message}`)\n }\n }\n }\n return items\n }\n\n async claim(agentId: string, itemId: string): Promise<void> {\n // itemId: \"gitlab:<project>:issue:<iid>\"\n const { project, iid, type } = this.parseId(itemId)\n // Transition labels: add \"Doing\", remove \"To Do\"\n const path = `/projects/${encodeURIComponent(project)}/${type === \"issue\" ? \"issues\" : \"merge_requests\"}/${iid}?add_labels=Doing&remove_labels=To Do`\n try {\n await this.api(path, { method: \"PUT\" })\n } catch (e: any) {\n this.log(`[business] claim label update failed: ${e.message}`)\n }\n }\n\n async report(itemId: string, update: WorkReport): Promise<void> {\n const { project, iid, type } = this.parseId(itemId)\n const seg = type === \"issue\" ? \"issues\" : \"merge_requests\"\n\n // Time tracking\n if (update.timeSeconds && update.timeSeconds > 0) {\n const mins = Math.max(1, Math.round(update.timeSeconds / 60))\n const dur = mins >= 60 ? `${Math.floor(mins / 60)}h${mins % 60 ? ` ${mins % 60}m` : \"\"}` : `${mins}m`\n try {\n await this.api(\n `/projects/${encodeURIComponent(project)}/${seg}/${iid}/add_spent_time?duration=${encodeURIComponent(dur)}`,\n { method: \"POST\" },\n )\n } catch (e: any) {\n this.log(`[business] add_spent_time failed: ${e.message}`)\n }\n }\n\n // Status → labels\n if (update.status === \"done\") {\n try {\n await this.api(\n `/projects/${encodeURIComponent(project)}/${seg}/${iid}?add_labels=Done&remove_labels=Doing`,\n { method: \"PUT\" },\n )\n } catch (e: any) {\n this.log(`[business] done label update failed: ${e.message}`)\n }\n } else if (update.status === \"blocked\") {\n try {\n await this.api(\n `/projects/${encodeURIComponent(project)}/${seg}/${iid}?add_labels=Blocked`,\n { method: \"PUT\" },\n )\n } catch (e: any) {\n this.log(`[business] blocked label update failed: ${e.message}`)\n }\n }\n\n // Note/comment\n if (update.note) {\n try {\n await this.api(\n `/projects/${encodeURIComponent(project)}/${seg}/${iid}/notes`,\n { method: \"POST\", body: JSON.stringify({ body: update.note }) },\n )\n } catch (e: any) {\n this.log(`[business] report note failed: ${e.message}`)\n }\n }\n }\n\n async listAll(opts: ListAllOpts = {}): Promise<WorkItem[]> {\n const sinceDays = opts.sinceDays ?? 30\n const updatedAfter = new Date(Date.now() - sinceDays * 24 * 3600_000).toISOString()\n\n const params = new URLSearchParams()\n const state = opts.state ?? \"opened\"\n params.set(\"state\", state)\n // `updated_after` makes sense for the Closed column (bounded window) and for\n // keeping the open list recent; for \"opened\" we pass it too but GitLab treats\n // the window loosely (any issue updated since counts, regardless of open-age).\n params.set(\"updated_after\", updatedAfter)\n params.set(\"scope\", \"all\")\n params.set(\"per_page\", \"100\")\n params.set(\"with_labels_details\", \"true\")\n params.set(\"order_by\", \"updated_at\")\n params.set(\"sort\", \"desc\")\n if (opts.labels?.length) params.set(\"labels\", opts.labels.join(\",\"))\n if (opts.milestone) params.set(\"milestone\", opts.milestone)\n if (opts.search) params.set(\"search\", opts.search)\n\n const projectList = this.projects.length ? this.projects : [\"__ALL__\"]\n const items: WorkItem[] = []\n for (const project of projectList) {\n try {\n const path = project === \"__ALL__\"\n ? `/issues?${params.toString()}`\n : `/projects/${encodeURIComponent(project)}/issues?${params.toString()}`\n const issues = await this.api(path)\n for (const issue of issues) items.push(this.mapIssue(issue, project))\n } catch (e: any) {\n this.log(`[business] GitLab listAll failed on ${project}: ${e.message}`)\n }\n }\n\n // Client-side negative-label filter (GitLab API supports `not[labels]` only\n // via the `not[]` nested query form, which isn't convenient via URLSearchParams).\n let result = items\n if (opts.notLabels?.length) {\n const deny = new Set(opts.notLabels)\n result = result.filter((i) => !(i.labels || []).some((l) => deny.has(l)))\n }\n if (opts.withoutScopedPrefix) {\n const prefix = opts.withoutScopedPrefix + \"::\"\n result = result.filter((i) => !(i.labels || []).some((l) => l.startsWith(prefix)))\n }\n return result\n }\n\n /** Close or reopen an issue via state_event. */\n async setState(itemId: string, to: \"close\" | \"reopen\"): Promise<void> {\n const { project, iid, type } = this.parseId(itemId)\n const seg = type === \"issue\" ? \"issues\" : \"merge_requests\"\n await this.api(\n `/projects/${encodeURIComponent(project)}/${seg}/${iid}?state_event=${to}`,\n { method: \"PUT\" },\n )\n }\n\n /** Fetch a single issue's full detail. */\n async getItem(itemId: string): Promise<WorkDetail | null> {\n const { project, iid } = this.parseId(itemId)\n try {\n const issue = await this.api(\n `/projects/${encodeURIComponent(project)}/issues/${iid}?with_labels_details=true`,\n )\n const base = this.mapIssue(issue, project)\n return {\n ...base,\n descriptionHtml: issue.description_html || undefined,\n createdAt: issue.created_at,\n author: issue.author ? {\n username: issue.author.username, name: issue.author.name, avatarUrl: issue.author.avatar_url,\n } : undefined,\n allLabels: Array.isArray(issue.labels)\n ? (typeof issue.labels[0] === \"object\" ? issue.labels.map((l: any) => l.name) : issue.labels)\n : [],\n }\n } catch (e: any) {\n this.log(`[board] GitLab getItem failed for ${itemId}: ${e.message}`)\n return null\n }\n }\n\n /** Update fields on an issue. Accepts string usernames for assignees. */\n async updateItem(\n itemId: string,\n patch: {\n title?: string\n description?: string\n labels?: string[]\n addLabels?: string[]\n removeLabels?: string[]\n assigneeUsernames?: string[]\n milestoneTitle?: string | null\n },\n ): Promise<WorkItem> {\n const { project, iid } = this.parseId(itemId)\n\n // Resolve assignee usernames → user ids (parallel).\n let assigneeIds: number[] | undefined\n if (patch.assigneeUsernames) {\n const results = await Promise.all(patch.assigneeUsernames.map(async (u) => {\n try {\n const users = await this.api(`/users?username=${encodeURIComponent(u)}`)\n return Array.isArray(users) && users[0]?.id ? users[0].id : null\n } catch { return null }\n }))\n assigneeIds = results.filter((x): x is number => typeof x === \"number\")\n }\n\n // Resolve milestone title → id (null clears the milestone).\n let milestoneId: number | 0 | undefined\n if (patch.milestoneTitle !== undefined) {\n if (patch.milestoneTitle === null || patch.milestoneTitle === \"\") {\n milestoneId = 0\n } else {\n try {\n const ms = await this.api(\n `/projects/${encodeURIComponent(project)}/milestones?title=${encodeURIComponent(patch.milestoneTitle)}`,\n )\n if (Array.isArray(ms) && ms[0]?.id) milestoneId = ms[0].id\n } catch (e: any) {\n this.log(`[board] milestone lookup failed for \"${patch.milestoneTitle}\": ${e.message}`)\n }\n }\n }\n\n const body: Record<string, unknown> = {}\n if (patch.title !== undefined) body.title = patch.title\n if (patch.description !== undefined) body.description = patch.description\n if (patch.labels !== undefined) body.labels = patch.labels.join(\",\")\n if (patch.addLabels?.length) body.add_labels = patch.addLabels.join(\",\")\n if (patch.removeLabels?.length) body.remove_labels = patch.removeLabels.join(\",\")\n if (assigneeIds !== undefined) body.assignee_ids = assigneeIds\n if (milestoneId !== undefined) body.milestone_id = milestoneId\n\n const issue = await this.api(`/projects/${encodeURIComponent(project)}/issues/${iid}`, {\n method: \"PUT\",\n body: JSON.stringify(body),\n })\n return this.mapIssue(issue, project)\n }\n\n /** List project members (direct + inherited). Deduped by username across projects. */\n async listMembers(): Promise<WorkMember[]> {\n const byUsername = new Map<string, WorkMember>()\n for (const project of this.projects) {\n try {\n const members = await this.api(\n `/projects/${encodeURIComponent(project)}/members/all?per_page=100`,\n )\n for (const m of members) {\n if (m.username && !byUsername.has(m.username)) {\n byUsername.set(m.username, {\n username: m.username, name: m.name, avatarUrl: m.avatar_url,\n })\n }\n }\n } catch (e: any) {\n this.log(`[board] listMembers failed for ${project}: ${e.message}`)\n }\n }\n return [...byUsername.values()].sort((a, b) => a.username.localeCompare(b.username))\n }\n\n /** List milestones (active first, then closed). Deduped by title across projects. */\n async listMilestones(): Promise<WorkMilestone[]> {\n const byTitle = new Map<string, WorkMilestone>()\n for (const project of this.projects) {\n try {\n const ms = await this.api(\n `/projects/${encodeURIComponent(project)}/milestones?per_page=100`,\n )\n for (const m of ms) {\n if (m.title && !byTitle.has(m.title)) {\n byTitle.set(m.title, {\n id: m.id, title: m.title, state: m.state, dueDate: m.due_date,\n })\n }\n }\n } catch (e: any) {\n this.log(`[board] listMilestones failed for ${project}: ${e.message}`)\n }\n }\n const all = [...byTitle.values()]\n all.sort((a, b) => {\n if (a.state !== b.state) return a.state === \"active\" ? -1 : 1\n return a.title.localeCompare(b.title)\n })\n return all\n }\n\n async create(input: WorkCreateInput): Promise<WorkItem> {\n const project = input.projectHint || this.projects[0]\n if (!project) throw new Error(\"GitLabWorkSource.create requires projectHint or configured projects\")\n\n // Resolve assignee usernames → user ids. Prefer explicit `assigneeUsernames`,\n // fall back to agentId → configured mapping for legacy callers.\n let assignee_ids: number[] | undefined\n const usernames = input.assigneeUsernames?.length\n ? input.assigneeUsernames\n : (input.assignee ? (this.agentUsernames[input.assignee] || []).slice(0, 1) : [])\n if (usernames.length) {\n const results = await Promise.all(usernames.map(async (u) => {\n try {\n const users = await this.api(`/users?username=${encodeURIComponent(u)}`)\n return Array.isArray(users) && users[0]?.id ? users[0].id : null\n } catch (e: any) {\n this.log(`[board] user lookup failed for ${u}: ${e.message}`)\n return null\n }\n }))\n assignee_ids = results.filter((x): x is number => typeof x === \"number\")\n }\n\n // Resolve milestone title → id.\n let milestone_id: number | undefined\n if (input.milestoneTitle) {\n try {\n const ms = await this.api(\n `/projects/${encodeURIComponent(project)}/milestones?title=${encodeURIComponent(input.milestoneTitle)}`,\n )\n if (Array.isArray(ms) && ms[0]?.id) milestone_id = ms[0].id\n } catch (e: any) {\n this.log(`[board] milestone lookup failed for \"${input.milestoneTitle}\": ${e.message}`)\n }\n }\n\n const body: Record<string, unknown> = {\n title: input.title,\n description: input.description,\n labels: (input.labels || []).join(\",\"),\n }\n if (assignee_ids?.length) body.assignee_ids = assignee_ids\n if (milestone_id !== undefined) body.milestone_id = milestone_id\n\n const issue = await this.api(`/projects/${encodeURIComponent(project)}/issues`, {\n method: \"POST\",\n body: JSON.stringify(body),\n })\n return this.mapIssue(issue, project)\n }\n\n async transition(itemId: string, toLabel: string, fromLabel?: string): Promise<void> {\n // Legacy single add/remove — boards use transitionMany.\n await this.transitionMany(itemId, toLabel ? [toLabel] : [], fromLabel ? [fromLabel] : [])\n }\n\n /** Multi-label transition; used by board drag-drop (scoped labels produce pairs). */\n async transitionMany(itemId: string, add: string[], remove: string[]): Promise<void> {\n const { project, iid, type } = this.parseId(itemId)\n const seg = type === \"issue\" ? \"issues\" : \"merge_requests\"\n const params = new URLSearchParams()\n if (add.length) params.set(\"add_labels\", add.join(\",\"))\n if (remove.length) params.set(\"remove_labels\", remove.join(\",\"))\n if (!params.toString()) return\n await this.api(\n `/projects/${encodeURIComponent(project)}/${seg}/${iid}?${params.toString()}`,\n { method: \"PUT\" },\n )\n }\n\n private parseId(itemId: string): { project: string; type: \"issue\" | \"mr\"; iid: string } {\n // \"gitlab:<project>:issue:<iid>\" (project may contain a slash → it's joined)\n const body = itemId.replace(/^gitlab:/, \"\")\n const parts = body.split(\":\")\n const iid = parts.pop() as string\n const type = parts.pop() === \"mr\" ? \"mr\" : \"issue\"\n const project = parts.join(\":\")\n return { project, type, iid }\n }\n}\n\n// ---------- Factory ----------\n\nexport function createWorkSource(\n business: BusinessConfig,\n daemon: DaemonConfig,\n log: (...args: unknown[]) => void,\n): WorkSource {\n const ws: BusinessWorkSource = business.workSource\n switch (ws.type) {\n case \"backlog\":\n return new BacklogWorkSource(ws.path, daemon, log)\n\n case \"wiki\":\n return new WikiWorkSource(ws.path, ws.glob)\n\n case \"gitlab\": {\n const gl = daemon.channels.gitlab\n if (!gl?.token) {\n throw new Error(\"business.workSource.type=gitlab requires channels.gitlab.token\")\n }\n const agentUsernames: Record<string, string[]> = {}\n for (const mapping of gl.agentMappings) {\n if (mapping.gitlabUsernames.length) {\n agentUsernames[mapping.agentId] = mapping.gitlabUsernames\n }\n }\n const projects = ws.projects.length\n ? ws.projects\n : gl.routes.map((r) => r.project)\n return new GitLabWorkSource(gl.host, gl.token, projects, agentUsernames, log)\n }\n }\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\"\nimport { dirname, resolve } from \"path\"\nimport { randomUUID } from \"crypto\"\nimport { z } from \"zod\"\n\n// --- Structured backlog store (Plan B + import) ---\n//\n// Replaces the legacy `.agentx/backlog.md` GFM checklist as the canonical\n// store when `.agentx/backlog.json` is present. The markdown view is\n// regenerated on every save so humans still get a readable diff.\n//\n// Why structured: importing issues from gitlab/github needs a stable\n// linkage back to the source (project + iid + url) so mutations\n// (assignee, labels, status, milestone) can be pushed upstream by the\n// sync-back layer. Encoding that in markdown comments is brittle.\n\nconst sourceSchema = z.object({\n type: z.enum([\"gitlab\", \"github\"]),\n host: z.string().optional(),\n project: z.string(),\n iid: z.number().int().positive(),\n url: z.string(),\n})\n\nconst itemSchema = z.object({\n id: z.string(),\n title: z.string(),\n description: z.string().optional(),\n assignee: z.string().optional(),\n labels: z.array(z.string()).default([]),\n milestone: z.string().optional(),\n status: z.enum([\"todo\", \"doing\", \"blocked\", \"done\"]).default(\"todo\"),\n priority: z.number().int().optional(),\n estimatedSeconds: z.number().int().optional(),\n source: sourceSchema.optional(),\n importedAt: z.string().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n blocker: z.string().optional(),\n doneNote: z.string().optional(),\n})\n\nconst fileSchema = z.object({\n version: z.literal(1),\n items: z.array(itemSchema).default([]),\n})\n\nexport type BacklogSource = z.infer<typeof sourceSchema>\nexport type BacklogItem = z.infer<typeof itemSchema>\nexport type BacklogFile = z.infer<typeof fileSchema>\n\nexport class BacklogStore {\n constructor(private path: string) {}\n\n /** Absolute path of the JSON store. */\n jsonPath(): string {\n return resolve(process.cwd(), this.path).replace(/\\.md$/i, \".json\")\n }\n\n /** Absolute path of the markdown view (alongside the JSON store). */\n mdPath(): string {\n return resolve(process.cwd(), this.path).replace(/\\.json$/i, \".md\")\n }\n\n exists(): boolean {\n return existsSync(this.jsonPath())\n }\n\n load(): BacklogFile {\n const p = this.jsonPath()\n if (!existsSync(p)) return { version: 1, items: [] }\n const raw = readFileSync(p, \"utf-8\")\n try {\n return fileSchema.parse(JSON.parse(raw))\n } catch (e: any) {\n throw new Error(`Backlog file invalid (${p}): ${e.message}`)\n }\n }\n\n save(file: BacklogFile): void {\n const jsonP = this.jsonPath()\n mkdirSync(dirname(jsonP), { recursive: true })\n writeFileSync(jsonP, JSON.stringify(file, null, 2) + \"\\n\")\n writeFileSync(this.mdPath(), this.toMarkdown(file))\n }\n\n list(): BacklogItem[] {\n return this.load().items\n }\n\n findById(id: string): BacklogItem | undefined {\n return this.list().find((i) => i.id === id)\n }\n\n /** Add an item; rejects duplicates by id. Returns the saved item. */\n add(input: Omit<BacklogItem, \"createdAt\" | \"updatedAt\"> & { createdAt?: string }): BacklogItem {\n const file = this.load()\n if (file.items.some((i) => i.id === input.id)) {\n throw new Error(`backlog item ${input.id} already exists`)\n }\n const now = new Date().toISOString()\n const item: BacklogItem = {\n ...input,\n labels: input.labels ?? [],\n status: input.status ?? \"todo\",\n createdAt: input.createdAt ?? now,\n updatedAt: now,\n }\n file.items.push(item)\n this.save(file)\n return item\n }\n\n /** Add many; skips items whose id already exists, returns the inserted set. */\n addMany(inputs: Array<Omit<BacklogItem, \"createdAt\" | \"updatedAt\"> & { createdAt?: string }>): BacklogItem[] {\n const file = this.load()\n const existing = new Set(file.items.map((i) => i.id))\n const now = new Date().toISOString()\n const added: BacklogItem[] = []\n for (const input of inputs) {\n if (existing.has(input.id)) continue\n const item: BacklogItem = {\n ...input,\n labels: input.labels ?? [],\n status: input.status ?? \"todo\",\n createdAt: input.createdAt ?? now,\n updatedAt: now,\n }\n file.items.push(item)\n added.push(item)\n existing.add(item.id)\n }\n if (added.length) this.save(file)\n return added\n }\n\n update(id: string, patch: Partial<BacklogItem>): BacklogItem {\n const file = this.load()\n const idx = file.items.findIndex((i) => i.id === id)\n if (idx < 0) throw new Error(`backlog item ${id} not found`)\n const updated: BacklogItem = {\n ...file.items[idx],\n ...patch,\n id: file.items[idx].id,\n createdAt: file.items[idx].createdAt,\n updatedAt: new Date().toISOString(),\n }\n file.items[idx] = updated\n this.save(file)\n return updated\n }\n\n remove(id: string): boolean {\n const file = this.load()\n const before = file.items.length\n file.items = file.items.filter((i) => i.id !== id)\n if (file.items.length === before) return false\n this.save(file)\n return true\n }\n\n /** Render a human-readable markdown view (generated, not authoritative). */\n toMarkdown(file: BacklogFile): string {\n const lines: string[] = [\n \"# Backlog\",\n \"\",\n \"_Generated from `backlog.json`. Do not edit by hand — use `agentx backlog` commands._\",\n \"\",\n ]\n const buckets: Record<BacklogItem[\"status\"], BacklogItem[]> = {\n doing: [], blocked: [], todo: [], done: [],\n }\n for (const item of file.items) buckets[item.status].push(item)\n const sections: Array<[BacklogItem[\"status\"], string]> = [\n [\"doing\", \"Doing\"], [\"blocked\", \"Blocked\"], [\"todo\", \"To Do\"], [\"done\", \"Done\"],\n ]\n for (const [key, label] of sections) {\n if (!buckets[key].length) continue\n lines.push(`## ${label}`, \"\")\n for (const it of buckets[key]) {\n const check = key === \"done\" ? \"x\" : \" \"\n const mention = it.assignee ? `@${it.assignee} ` : \"\"\n const time = it.estimatedSeconds\n ? ` [time: ${Math.round(it.estimatedSeconds / 60)}m]`\n : \"\"\n const src = it.source ? ` (${it.source.type}: ${it.source.project}#${it.source.iid})` : \"\"\n lines.push(`- [${check}] ${mention}${it.title}${time}${src}`)\n if (it.source?.url) lines.push(` - <${it.source.url}>`)\n if (it.labels.length) lines.push(` - labels: ${it.labels.join(\", \")}`)\n if (it.milestone) lines.push(` - milestone: ${it.milestone}`)\n if (it.blocker) lines.push(` - BLOCKED: ${it.blocker}`)\n }\n lines.push(\"\")\n }\n return lines.join(\"\\n\")\n }\n}\n\n/** Generate a stable BacklogItem.id for a fresh manual item. */\nexport function manualBacklogId(): string {\n return `manual:${randomUUID()}`\n}\n\n/** Build the canonical id for an imported source issue. */\nexport function sourceBacklogId(source: BacklogSource): string {\n return `${source.type}:${source.project}:${source.iid}`\n}\n","import type { BacklogItem, BacklogSource } from \"./backlog-store\"\nimport type { DaemonConfig } from \"@/daemon/config\"\n\n// --- Sync-back layer: backlog item mutations → upstream issue ---\n//\n// When a backlog item carries a `source` ref (gitlab or github), changes\n// applied via the backlog work-source need to flow back to the original\n// issue: assignees, labels, title, description, milestone, open/close.\n// Otherwise the imported view drifts from upstream and humans browsing\n// the source see stale state.\n//\n// This module is intentionally stateless — callers pass the patch they\n// just applied to the local item; we forward the same shape to the\n// matching upstream API.\n\nexport interface BacklogPatch {\n title?: string\n description?: string\n /** Replace labels wholesale. Use addLabels/removeLabels for incremental. */\n labels?: string[]\n addLabels?: string[]\n removeLabels?: string[]\n /** Username on the source (NOT agentId — caller resolves the mapping). */\n assigneeUsernames?: string[]\n /** Title of the milestone, or empty string to clear. */\n milestoneTitle?: string | null\n /** Open/close transition. */\n state?: \"open\" | \"closed\"\n /** Optional comment to post on the upstream issue. */\n note?: string\n}\n\nexport interface SyncBackResult {\n ok: boolean\n url?: string\n error?: string\n /** Each upstream call we attempted, in order. */\n attempts: Array<{ kind: string; ok: boolean; status?: number; error?: string }>\n}\n\n/** Resolve agentIds in a patch to upstream usernames using the daemon mappings. */\nexport function resolveAssigneesForSource(\n agentIds: string[],\n source: BacklogSource,\n daemon: DaemonConfig,\n): string[] {\n const out: string[] = []\n if (source.type === \"gitlab\") {\n const mappings = daemon.channels.gitlab?.agentMappings ?? []\n for (const agentId of agentIds) {\n const m = mappings.find((x) => x.agentId === agentId)\n if (m?.gitlabUsernames?.length) out.push(m.gitlabUsernames[0])\n else out.push(agentId)\n }\n } else if (source.type === \"github\") {\n const mappings = daemon.channels.github?.agentMappings ?? []\n for (const agentId of agentIds) {\n const m = mappings.find((x) => x.agentId === agentId)\n if (m?.githubUsernames?.length) out.push(m.githubUsernames[0])\n else out.push(agentId)\n }\n }\n return out\n}\n\n/** Push a backlog patch to the upstream source referenced by the item. */\nexport async function syncBacklogItemToSource(\n item: BacklogItem,\n patch: BacklogPatch,\n daemon: DaemonConfig,\n log: (...args: unknown[]) => void = () => {},\n): Promise<SyncBackResult> {\n if (!item.source) return { ok: true, attempts: [] }\n if (item.source.type === \"gitlab\") return syncToGitLab(item.source, patch, daemon, log)\n if (item.source.type === \"github\") return syncToGitHub(item.source, patch, daemon, log)\n return { ok: false, error: `unknown source.type ${(item.source as any).type}`, attempts: [] }\n}\n\n// ---------- GitLab ----------\n\nasync function syncToGitLab(\n source: BacklogSource,\n patch: BacklogPatch,\n daemon: DaemonConfig,\n log: (...args: unknown[]) => void,\n): Promise<SyncBackResult> {\n const gl = daemon.channels.gitlab\n const token = gl?.token\n const host = gl?.host || (source.host ? `https://${source.host}` : undefined)\n if (!token || !host) {\n return { ok: false, error: \"gitlab token/host not configured\", attempts: [] }\n }\n const attempts: SyncBackResult[\"attempts\"] = []\n\n const api = async (path: string, init: RequestInit = {}): Promise<Response> => {\n return fetch(`${host}/api/v4${path}`, {\n ...init,\n headers: {\n \"PRIVATE-TOKEN\": token,\n \"Content-Type\": \"application/json\",\n ...(init.headers || {}),\n },\n })\n }\n\n const projectEnc = encodeURIComponent(source.project)\n\n // Resolve assignee usernames → ids (parallel) — only when we need them.\n let assigneeIds: number[] | undefined\n if (patch.assigneeUsernames !== undefined) {\n const ids = await Promise.all(patch.assigneeUsernames.map(async (u) => {\n try {\n const res = await fetch(`${host}/api/v4/users?username=${encodeURIComponent(u)}`, {\n headers: { \"PRIVATE-TOKEN\": token },\n })\n if (!res.ok) return null\n const arr: any = await res.json()\n return Array.isArray(arr) && arr[0]?.id ? arr[0].id : null\n } catch { return null }\n }))\n assigneeIds = ids.filter((x): x is number => typeof x === \"number\")\n }\n\n // Resolve milestone title → id.\n let milestoneId: number | 0 | undefined\n if (patch.milestoneTitle !== undefined) {\n if (patch.milestoneTitle === null || patch.milestoneTitle === \"\") {\n milestoneId = 0\n } else {\n try {\n const res = await api(`/projects/${projectEnc}/milestones?title=${encodeURIComponent(patch.milestoneTitle)}`)\n if (res.ok) {\n const arr: any = await res.json()\n if (Array.isArray(arr) && arr[0]?.id) milestoneId = arr[0].id\n }\n } catch (e: any) {\n log(`[backlog-sync] milestone lookup failed: ${e.message}`)\n }\n }\n }\n\n // Build the PUT body.\n const body: Record<string, unknown> = {}\n if (patch.title !== undefined) body.title = patch.title\n if (patch.description !== undefined) body.description = patch.description\n if (patch.labels !== undefined) body.labels = patch.labels.join(\",\")\n if (patch.addLabels?.length) body.add_labels = patch.addLabels.join(\",\")\n if (patch.removeLabels?.length) body.remove_labels = patch.removeLabels.join(\",\")\n if (assigneeIds !== undefined) body.assignee_ids = assigneeIds\n if (milestoneId !== undefined) body.milestone_id = milestoneId\n if (patch.state) body.state_event = patch.state === \"closed\" ? \"close\" : \"reopen\"\n\n if (Object.keys(body).length) {\n try {\n const res = await api(`/projects/${projectEnc}/issues/${source.iid}`, {\n method: \"PUT\",\n body: JSON.stringify(body),\n })\n attempts.push({ kind: \"PUT issue\", ok: res.ok, status: res.status })\n if (!res.ok) {\n const text = await res.text().catch(() => \"\")\n return { ok: false, attempts, error: `PUT issue ${res.status}: ${text.slice(0, 200)}`, url: source.url }\n }\n } catch (e: any) {\n attempts.push({ kind: \"PUT issue\", ok: false, error: e.message })\n return { ok: false, attempts, error: e.message, url: source.url }\n }\n }\n\n if (patch.note) {\n try {\n const res = await api(`/projects/${projectEnc}/issues/${source.iid}/notes`, {\n method: \"POST\",\n body: JSON.stringify({ body: patch.note }),\n })\n attempts.push({ kind: \"POST note\", ok: res.ok, status: res.status })\n } catch (e: any) {\n attempts.push({ kind: \"POST note\", ok: false, error: e.message })\n }\n }\n\n return { ok: attempts.every((a) => a.ok), attempts, url: source.url }\n}\n\n// ---------- GitHub ----------\n\nasync function syncToGitHub(\n source: BacklogSource,\n patch: BacklogPatch,\n daemon: DaemonConfig,\n log: (...args: unknown[]) => void,\n): Promise<SyncBackResult> {\n const gh = daemon.channels.github\n const token = gh?.token\n if (!token) {\n return { ok: false, error: \"github token not configured\", attempts: [] }\n }\n const attempts: SyncBackResult[\"attempts\"] = []\n\n const api = async (path: string, init: RequestInit = {}): Promise<Response> => {\n return fetch(`https://api.github.com${path}`, {\n ...init,\n headers: {\n \"Authorization\": `Bearer ${token}`,\n \"Accept\": \"application/vnd.github+json\",\n \"X-GitHub-Api-Version\": \"2022-11-28\",\n ...(init.headers || {}),\n },\n })\n }\n\n const repo = source.project // GitHub IDs use \"owner/repo\" verbatim in the URL path.\n\n // Resolve milestone title → number.\n let milestoneNumber: number | null | undefined\n if (patch.milestoneTitle !== undefined) {\n if (patch.milestoneTitle === null || patch.milestoneTitle === \"\") {\n milestoneNumber = null\n } else {\n try {\n const res = await api(`/repos/${repo}/milestones?state=all&per_page=100`)\n if (res.ok) {\n const arr: any = await res.json()\n const found = Array.isArray(arr) ? arr.find((m: any) => m.title === patch.milestoneTitle) : null\n if (found?.number) milestoneNumber = found.number\n }\n } catch (e: any) {\n log(`[backlog-sync] github milestone lookup failed: ${e.message}`)\n }\n }\n }\n\n // GitHub doesn't support add/remove labels in the issue PATCH the way\n // GitLab does — labels is a wholesale set. If only addLabels/removeLabels\n // were provided we read+merge.\n let nextLabels: string[] | undefined\n if (patch.labels !== undefined) {\n nextLabels = patch.labels\n } else if (patch.addLabels?.length || patch.removeLabels?.length) {\n try {\n const res = await api(`/repos/${repo}/issues/${source.iid}`)\n if (res.ok) {\n const issue: any = await res.json()\n const current: string[] = Array.isArray(issue.labels)\n ? issue.labels.map((l: any) => (typeof l === \"string\" ? l : l.name))\n : []\n const adds = new Set([...current, ...(patch.addLabels ?? [])])\n for (const r of patch.removeLabels ?? []) adds.delete(r)\n nextLabels = [...adds]\n }\n } catch (e: any) {\n log(`[backlog-sync] github label fetch failed: ${e.message}`)\n }\n }\n\n const body: Record<string, unknown> = {}\n if (patch.title !== undefined) body.title = patch.title\n if (patch.description !== undefined) body.body = patch.description\n if (nextLabels !== undefined) body.labels = nextLabels\n if (patch.assigneeUsernames !== undefined) body.assignees = patch.assigneeUsernames\n if (milestoneNumber !== undefined) body.milestone = milestoneNumber\n if (patch.state) body.state = patch.state\n\n if (Object.keys(body).length) {\n try {\n const res = await api(`/repos/${repo}/issues/${source.iid}`, {\n method: \"PATCH\",\n body: JSON.stringify(body),\n })\n attempts.push({ kind: \"PATCH issue\", ok: res.ok, status: res.status })\n if (!res.ok) {\n const text = await res.text().catch(() => \"\")\n return { ok: false, attempts, error: `PATCH issue ${res.status}: ${text.slice(0, 200)}`, url: source.url }\n }\n } catch (e: any) {\n attempts.push({ kind: \"PATCH issue\", ok: false, error: e.message })\n return { ok: false, attempts, error: e.message, url: source.url }\n }\n }\n\n if (patch.note) {\n try {\n const res = await api(`/repos/${repo}/issues/${source.iid}/comments`, {\n method: \"POST\",\n body: JSON.stringify({ body: patch.note }),\n })\n attempts.push({ kind: \"POST comment\", ok: res.ok, status: res.status })\n } catch (e: any) {\n attempts.push({ kind: \"POST comment\", ok: false, error: e.message })\n }\n }\n\n return { ok: attempts.every((a) => a.ok), attempts, url: source.url }\n}\n","// --- Who is the work for? -------------------------------------------------\n//\n// The principal behind a piece of work is a CLIENT. That concept already\n// existed, spread across `business.projects[].client`, `business.contactMap[]`\n// and the `orgChart` reportsTo chain, resolved privately inside the activity\n// graph panel. This module is the single implementation both that panel and\n// the session monitor call, plus the policy layer the monitor needs.\n//\n// Clients are DERIVED, never declared: one appears the moment a project or a\n// contact mentions it. `business.clients` only carries overrides — a display\n// name, whether it is a paying client or your own house, how fast a delay\n// costs you, and what agents may do for it without asking. A client with no\n// entry there still resolves; it just gets defaults.\n\nexport interface ContactRule {\n channel?: string\n chatId?: string\n username?: string\n senderId?: string\n client: string\n project?: string\n displayName?: string\n}\nexport interface ProjectRule { id: string; pm?: string; client?: string }\nexport interface ClientPolicy {\n name?: string\n kind?: \"client\" | \"internal\" | \"own\"\n respondWithin?: string\n standing?: string[]\n}\nexport interface BusinessShape {\n projects?: ProjectRule[]\n contactMap?: ContactRule[]\n orgChart?: Record<string, { reportsTo?: string }>\n clients?: Record<string, ClientPolicy>\n}\nexport interface ResolvedClient {\n id: string\n name: string\n kind: \"client\" | \"internal\" | \"own\"\n /** Minutes before a wait starts costing; undefined = no external clock. */\n respondWithinMinutes?: number\n standing: string[]\n /** True when nothing in config mentions this client — derived only. */\n declared: boolean\n}\n\nexport const UNMAPPED = \"unmapped\"\n\n/** Explicit `business.projects[].client` wins; otherwise the leading segment\n * of the id. Works for \"owner/repo\" on any forge and for bare internal ids. */\nexport function clientFromProject(project: string | null | undefined, projects: ProjectRule[] = []): string {\n if (!project) return UNMAPPED\n const hit = projects.find(p => p.id === project)\n if (hit?.client) return hit.client\n const slash = project.indexOf(\"/\")\n return slash > 0 ? project.slice(0, slash) : project\n}\n\n/** agent id -> client, from project PMs then transitively down reportsTo.\n * A mesh dispatch carries no project, so without this it is unattributable. */\nexport function agentClients(business: BusinessShape): Map<string, string> {\n const out = new Map<string, string>()\n const projects = business.projects ?? []\n const orgChart = business.orgChart ?? {}\n for (const p of projects) {\n if (p.pm) if (!out.has(p.pm)) out.set(p.pm, clientFromProject(p.id, projects))\n }\n const climb = (agentId: string, seen = new Set<string>()): string | undefined => {\n if (out.has(agentId)) return out.get(agentId)\n if (seen.has(agentId)) return undefined\n seen.add(agentId)\n const up = orgChart[agentId]?.reportsTo\n if (!up) return undefined\n const c = climb(up, seen)\n if (c) out.set(agentId, c)\n return c\n }\n for (const agentId of Object.keys(orgChart)) climb(agentId)\n return out\n}\n\n/** chatId > username > senderId > channel-default. First match wins. */\nexport function matchContact(\n channel: string | undefined,\n who: { chatId?: string; username?: string; senderId?: string },\n contactMap: ContactRule[] = [],\n): ContactRule | undefined {\n if (!contactMap.length) return undefined\n const pool = contactMap.filter(m => !m.channel || m.channel === channel)\n return pool.find(m => m.chatId && who.chatId && m.chatId === who.chatId)\n ?? pool.find(m => m.username && who.username && m.username === who.username)\n ?? pool.find(m => m.senderId && who.senderId && m.senderId === who.senderId)\n ?? pool.find(m => m.channel && !m.chatId && !m.username && !m.senderId)\n}\n\nexport interface WorkRef { agentId?: string; channel?: string; project?: string; chatId?: string; username?: string }\n\n/** The one entry point. Conversation rules beat project shape, which beats\n * the agent's place in the org, because a rule someone wrote by hand is\n * always more deliberate than a heuristic. */\nexport function resolveClient(ref: WorkRef, business: BusinessShape): string {\n const contact = matchContact(ref.channel, { chatId: ref.chatId, username: ref.username }, business.contactMap)\n if (contact) return contact.client\n if (ref.project) return clientFromProject(ref.project, business.projects)\n if (ref.agentId) {\n const byAgent = agentClients(business).get(ref.agentId)\n if (byAgent) return byAgent\n }\n return UNMAPPED\n}\n\n/** A monitor session id is \"<agent>:<channel>:<target...>\". Forge targets\n * carry the project, chat targets carry the chat id. */\nexport function parseWorkRef(sessionId: string, agentId?: string): WorkRef {\n const parts = String(sessionId || \"\").split(\":\")\n if (parts.length < 3) return { agentId }\n const [agent, channel, ...rest] = parts\n const target = rest.join(\":\")\n const ref: WorkRef = { agentId: agentId || agent, channel }\n if (channel === \"gitlab\" || channel === \"github\") {\n // \"owner/repo:issue:94\" and \"owner/repo:pipeline:10897\" -> \"owner/repo\"\n ref.project = target.split(\":\")[0]\n } else if (channel === \"cron\" || channel === \"api\") {\n // Nothing addressable: fall through to the agent's own client.\n } else {\n ref.chatId = target.split(\"@\")[0]\n }\n return ref\n}\n\nconst KIND_DEFAULT = (id: string): \"client\" | \"internal\" | \"own\" => (id === UNMAPPED ? \"internal\" : \"client\")\n\nexport function clientPolicy(id: string, business: BusinessShape): ResolvedClient {\n const p = business.clients?.[id]\n return {\n id,\n name: p?.name || id,\n kind: p?.kind ?? KIND_DEFAULT(id),\n respondWithinMinutes: parseDuration(p?.respondWithin),\n standing: p?.standing ?? [],\n declared: Boolean(p),\n }\n}\n\n/** Every client the config can produce: from projects, contacts and overrides. */\nexport function listClients(business: BusinessShape): ResolvedClient[] {\n const ids = new Set<string>()\n for (const p of business.projects ?? []) ids.add(clientFromProject(p.id, business.projects))\n for (const c of business.contactMap ?? []) ids.add(c.client)\n for (const id of Object.keys(business.clients ?? {})) ids.add(id)\n return [...ids].sort().map(id => clientPolicy(id, business))\n}\n\n/** \"4h\", \"90m\", \"2d\" -> minutes. Anything else is treated as no clock, so a\n * typo can never silently become an aggressive deadline. */\nexport function parseDuration(v: string | undefined): number | undefined {\n const m = /^(\\d+)\\s*([mhd])$/.exec(String(v ?? \"\").trim())\n if (!m) return undefined\n const n = Number(m[1])\n return m[2] === \"m\" ? n : m[2] === \"h\" ? n * 60 : n * 1440\n}\n\n/** Whether an agent may act unattended for this client. Deny by default, and\n * never for a paying client regardless of what is listed — an outward-facing\n * mistake on someone else's repo is not ours to make on a timer. */\nexport function mayProceedUnattended(client: ResolvedClient, capability: string): boolean {\n if (client.kind === \"client\") return false\n return client.standing.includes(\"*\") || client.standing.includes(capability)\n}\n","import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, writeFileSync } from \"fs\"\nimport { resolve } from \"path\"\n\n// --- Decision cards: what an agent asks the operator ---\n//\n// An agent that needs a yes/no from the operator writes a card instead of\n// asking in chat. A card says what it is, the question, what the agent\n// recommends, and what happens if nobody answers by `expires`. Nothing\n// waits forever: past `expires` the daemon applies `if_silent` (sweep.ts).\n//\n// Storage: one JSON file per card under `.agentx/approvals/`, written\n// atomically, like wiki proposals. The CLI, the dashboard and the daemon\n// are separate processes and all read the same files.\n//\n// Field names match the API (`if_silent`, `raised_by`), so a stored card is\n// exactly what `POST /approvals` accepted.\n\nexport type IfSilent = \"discard\" | \"keep\" | \"pause\" | \"approve\"\nexport const IF_SILENT_VALUES: readonly IfSilent[] = [\"discard\", \"keep\", \"pause\", \"approve\"]\n\nexport type CardStatus = \"pending\" | \"decided\" | \"expired\"\nexport type Verdict = \"yes\" | \"no\"\n\n/** Where the agent was asked, so the verdict can be taken back there. */\nexport interface ReplyTarget {\n channel: string\n chatId: string\n accountId?: string\n}\n\nexport interface DecisionCard {\n id: string\n title: string\n ask: string\n recommend: string\n if_silent: IfSilent\n /** ISO time the default applies. Always set. */\n expires: string\n /** Link to the draft, PR or issue. */\n source?: string\n raised_by: string\n created_at: string\n reply?: ReplyTarget\n status: CardStatus\n /** The operator's answer (status \"decided\"). */\n verdict?: Verdict\n /** What applied on expiry (status \"expired\"). */\n outcome?: IfSilent\n decided_by?: string\n decided_at?: string\n note?: string\n /** Set once the raising agent has been told the result. */\n agent_notified_at?: string\n}\n\nexport const CARD_LIMITS = {\n title: 120,\n ask: 300,\n recommend: 300,\n source: 500,\n note: 500,\n /** Pending cards one agent may have open at a time. */\n pendingPerAgent: 25,\n} as const\n\nexport interface CardSettings {\n defaultExpiryDays: number\n maxExpiryDays: number\n}\n\nexport const DEFAULT_CARD_SETTINGS: CardSettings = { defaultExpiryDays: 3, maxExpiryDays: 30 }\n\nexport function approvalsDir(root: string): string {\n return resolve(root, \".agentx\", \"approvals\")\n}\n\nconst CARD_ID_RE = /^[a-z0-9][a-z0-9-]{0,80}$/\n\nexport function isValidCardId(id: string): boolean {\n return CARD_ID_RE.test(id)\n}\n\nfunction fileFor(root: string, id: string): string {\n if (!isValidCardId(id)) throw new Error(`invalid card id: ${id}`)\n return resolve(approvalsDir(root), `${id}.json`)\n}\n\nexport function newCardId(now: number, title: string): string {\n const day = new Date(now).toISOString().slice(0, 10)\n const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, \"-\").replace(/^-+|-+$/g, \"\").slice(0, 40)\n return `${day}-${slug || \"card\"}-${Math.random().toString(36).slice(2, 6)}`\n}\n\nexport function saveCard(root: string, card: DecisionCard): void {\n mkdirSync(approvalsDir(root), { recursive: true })\n const path = fileFor(root, card.id)\n const tmp = `${path}.${process.pid}.tmp`\n writeFileSync(tmp, JSON.stringify(card, null, 2) + \"\\n\")\n renameSync(tmp, path)\n}\n\nexport function readCard(root: string, id: string): DecisionCard | null {\n if (!isValidCardId(id)) return null\n try {\n return JSON.parse(readFileSync(fileFor(root, id), \"utf-8\")) as DecisionCard\n } catch {\n return null\n }\n}\n\n/** Cards, oldest first; only `status` ones when given. */\nexport function listCards(root: string, status?: CardStatus): DecisionCard[] {\n const dir = approvalsDir(root)\n if (!existsSync(dir)) return []\n const out: DecisionCard[] = []\n for (const f of readdirSync(dir).filter((f) => f.endsWith(\".json\") && !f.startsWith(\"_\")).sort()) {\n const c = readCard(root, f.slice(0, -5))\n if (c && (!status || c.status === status)) out.push(c)\n }\n return out\n}\n\nfunction oneLine(v: unknown): string {\n return typeof v === \"string\" ? v.replace(/\\s+/g, \" \").trim() : \"\"\n}\n\n/**\n * `expires` as given by an agent: an ISO date or time, or a relative\n * \"12h\" / \"3d\". Unset: the default. Always capped at maxExpiryDays, so a\n * card can't be parked for a year.\n */\nexport function resolveExpiry(input: unknown, now: number, settings: CardSettings): { ok: true; at: string } | { ok: false; error: string } {\n const max = now + settings.maxExpiryDays * 86_400_000\n let at: number\n const raw = oneLine(input)\n if (!raw) {\n at = now + settings.defaultExpiryDays * 86_400_000\n } else {\n const rel = /^(\\d+)\\s*([hd])$/i.exec(raw)\n if (rel) {\n at = now + Number(rel[1]) * (rel[2].toLowerCase() === \"d\" ? 86_400_000 : 3_600_000)\n } else {\n at = Date.parse(raw)\n if (Number.isNaN(at)) return { ok: false, error: `expires must be an ISO date or time, or like \"12h\" / \"3d\" (got \"${raw}\")` }\n }\n }\n if (at <= now) return { ok: false, error: \"expires must be in the future\" }\n return { ok: true, at: new Date(Math.min(at, max)).toISOString() }\n}\n\nexport interface CardInput {\n title?: unknown\n ask?: unknown\n recommend?: unknown\n if_silent?: unknown\n expires?: unknown\n source?: unknown\n raised_by?: unknown\n reply?: unknown\n}\n\n/** Validate what an agent sent and build a pending card. Never saves. */\nexport function buildCard(\n input: CardInput,\n opts: { now?: number; settings?: CardSettings } = {},\n): { ok: true; card: DecisionCard } | { ok: false; error: string } {\n const now = opts.now ?? Date.now()\n const settings = opts.settings ?? DEFAULT_CARD_SETTINGS\n const title = oneLine(input.title)\n const ask = oneLine(input.ask)\n const recommend = oneLine(input.recommend)\n const raisedBy = oneLine(input.raised_by)\n if (!title) return { ok: false, error: \"title is required\" }\n if (!ask) return { ok: false, error: \"ask is required: the yes/no question\" }\n if (!recommend) return { ok: false, error: \"recommend is required: your advice and why, in one line\" }\n if (!raisedBy) return { ok: false, error: \"raised_by is required: the agent id\" }\n if (title.length > CARD_LIMITS.title) return { ok: false, error: `title is longer than ${CARD_LIMITS.title} characters` }\n if (ask.length > CARD_LIMITS.ask) return { ok: false, error: `ask is longer than ${CARD_LIMITS.ask} characters` }\n if (recommend.length > CARD_LIMITS.recommend) return { ok: false, error: `recommend is longer than ${CARD_LIMITS.recommend} characters` }\n const ifSilent = oneLine(input.if_silent).toLowerCase()\n if (!IF_SILENT_VALUES.includes(ifSilent as IfSilent)) {\n return { ok: false, error: `if_silent must be one of ${IF_SILENT_VALUES.join(\", \")}` }\n }\n const expiry = resolveExpiry(input.expires, now, settings)\n if (!expiry.ok) return expiry\n const source = oneLine(input.source)\n if (source.length > CARD_LIMITS.source) return { ok: false, error: `source is longer than ${CARD_LIMITS.source} characters` }\n if (source && /^[a-z][a-z0-9+.-]*:/i.test(source) && !/^https?:\\/\\//i.test(source)) {\n return { ok: false, error: \"source must be an http(s) link or a plain reference\" }\n }\n let reply: ReplyTarget | undefined\n const r = input.reply as Record<string, unknown> | undefined\n if (r && typeof r === \"object\" && oneLine(r.channel) && oneLine(r.chatId)) {\n reply = { channel: oneLine(r.channel), chatId: oneLine(r.chatId), ...(oneLine(r.accountId) ? { accountId: oneLine(r.accountId) } : {}) }\n }\n return {\n ok: true,\n card: {\n id: newCardId(now, title),\n title,\n ask,\n recommend,\n if_silent: ifSilent as IfSilent,\n expires: expiry.at,\n ...(source ? { source } : {}),\n raised_by: raisedBy,\n created_at: new Date(now).toISOString(),\n ...(reply ? { reply } : {}),\n status: \"pending\",\n },\n }\n}\n\n/** Validate, enforce the per-agent cap, and save. */\nexport function createCard(\n root: string,\n input: CardInput,\n opts: { now?: number; settings?: CardSettings } = {},\n): { ok: true; card: DecisionCard } | { ok: false; error: string } {\n const built = buildCard(input, opts)\n if (!built.ok) return built\n const open = listCards(root, \"pending\").filter((c) => c.raised_by === built.card.raised_by).length\n if (open >= CARD_LIMITS.pendingPerAgent) {\n return { ok: false, error: `${built.card.raised_by} already has ${open} cards waiting; wait for decisions before raising more` }\n }\n saveCard(root, built.card)\n return built\n}\n\n/** Record the operator's answer. Refuses anything no longer pending. */\nexport function decideCard(\n root: string,\n id: string,\n verdict: Verdict,\n opts: { by?: string; note?: string; now?: number } = {},\n): { ok: true; card: DecisionCard } | { ok: false; error: string } {\n const card = readCard(root, id)\n if (!card) return { ok: false, error: `no card \"${id}\"` }\n if (card.status !== \"pending\") return { ok: false, error: `card \"${id}\" is already ${card.status}` }\n const note = oneLine(opts.note).slice(0, CARD_LIMITS.note)\n const decided: DecisionCard = {\n ...card,\n status: \"decided\",\n verdict,\n decided_by: opts.by ?? \"operator\",\n decided_at: new Date(opts.now ?? Date.now()).toISOString(),\n ...(note ? { note } : {}),\n }\n saveCard(root, decided)\n return { ok: true, card: decided }\n}\n\n/** Apply `if_silent` to every pending card past its expiry. */\nexport function expireCards(root: string, now: number = Date.now()): DecisionCard[] {\n const out: DecisionCard[] = []\n for (const card of listCards(root, \"pending\")) {\n if (Date.parse(card.expires) > now) continue\n const expired: DecisionCard = {\n ...card,\n status: \"expired\",\n outcome: card.if_silent,\n decided_by: \"expiry\",\n decided_at: new Date(now).toISOString(),\n }\n saveCard(root, expired)\n out.push(expired)\n }\n return out\n}\n\n/** Decided or expired cards whose agent hasn't been told yet. */\nexport function cardsAwaitingAgentNotice(root: string): DecisionCard[] {\n return listCards(root).filter((c) => c.status !== \"pending\" && !c.agent_notified_at)\n}\n\nexport function markAgentNotified(root: string, id: string, now: number = Date.now()): void {\n const card = readCard(root, id)\n if (!card || card.agent_notified_at) return\n saveCard(root, { ...card, agent_notified_at: new Date(now).toISOString() })\n}\n\n/** What the raising agent is told. Plain text, one short message. */\nexport function verdictMessage(card: DecisionCard): string {\n const result = card.status === \"decided\"\n ? (card.verdict === \"yes\" ? \"The operator said YES.\" : \"The operator said NO.\")\n : `Nobody answered before it expired, so the default applied: ${card.outcome ?? card.if_silent}.`\n const lines = [\n `[Approval result] Your decision card \"${card.title}\" (${card.id}) is closed.`,\n `Question: ${card.ask}`,\n result,\n ]\n if (card.note) lines.push(`Operator note: ${card.note}`)\n if (card.source) lines.push(`Source: ${card.source}`)\n if (card.reply) lines.push(`You raised it from ${card.reply.channel} chat ${card.reply.chatId}; reply there if the requester should know.`)\n lines.push(\"Act on this result now. Do not raise the same card again.\")\n return lines.join(\"\\n\")\n}\n","import { existsSync, readdirSync, readFileSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { MemoryStore } from \"@/agents/memory-store\"\nimport { approveSchedule, formatFireTime, humanizeCron, nextFireTime, rejectSchedule } from \"@/crons/schedule-ops\"\nimport { listProposals, readProposal, type PromotionProposal } from \"@/wiki/proposals\"\nimport { approveProposal, rejectProposal } from \"@/wiki/promote\"\nimport { decideCard, listCards, readCard, type DecisionCard, type IfSilent } from \"./cards\"\nimport { readInboxState, snooze } from \"./state\"\n\n// --- The Approvals inbox: one list over every pending decision ---\n//\n// A read model, not a store. Each source keeps its own records and its own\n// approve/reject; the inbox lists them in one shape and hands a verdict to\n// the source's existing function:\n//\n// card decision cards agents raise (cards.ts)\n// schedule schedules an agent asked to create or delete (crons/schedule-ops)\n// memory facts from outside sources held before agents may use them\n// wiki lessons proposed for the shared wiki (wiki/proposals, wiki/promote)\n//\n// Only operator surfaces call decide(): the `agentx approvals` CLI and the\n// dashboard's /api/admin/approvals. The daemon's agent-facing API and the\n// MCP tool can create cards and read, never decide.\n\nexport type ApprovalKind = \"card\" | \"schedule\" | \"memory\" | \"wiki\"\nexport const APPROVAL_KINDS: readonly ApprovalKind[] = [\"card\", \"schedule\", \"memory\", \"wiki\"]\n\nexport type InboxAction = \"yes\" | \"no\" | \"later\"\n\n/** One pending decision, in bounded summary form. */\nexport interface InboxItem {\n /** `<kind>:<ref>`: what the CLI and the dashboard pass back. */\n key: string\n kind: ApprovalKind\n title: string\n /** The yes/no question. */\n ask: string\n /** What yes and no do, in words. */\n yes: string\n no: string\n recommend?: string\n if_silent?: IfSilent\n expires?: string\n source?: string\n raised_by: string\n created_at: string\n /** A short excerpt of what is being decided. */\n detail?: string\n /** The source's own command for the full record. */\n more?: string\n snoozed_until?: string\n}\n\nexport interface InboxContext {\n /** Directory holding agentx.json and .agentx/. */\n root: string\n configPath?: string\n wikiDir?: string\n /** Hot-reload the daemon after a schedule decision. Default true. */\n reload?: boolean\n now?: number\n}\n\nexport const DETAIL_MAX = 280\n\nfunction clip(s: string, n = DETAIL_MAX): string {\n const flat = s.replace(/\\s+/g, \" \").trim()\n return flat.length > n ? `${flat.slice(0, n - 1)}…` : flat\n}\n\nfunction configPathFor(ctx: InboxContext): string {\n if (ctx.configPath) return resolve(ctx.configPath)\n const candidates = [resolve(ctx.root, \"agentx.json\"), resolve(ctx.root, \".agentx\", \"config.json\")]\n return candidates.find((c) => existsSync(c)) ?? candidates[0]\n}\n\nfunction wikiDirFor(ctx: InboxContext): string {\n return ctx.wikiDir ? resolve(ctx.wikiDir) : resolve(ctx.root, \".agentx\", \"wiki\")\n}\n\n// ── Sources ──────────────────────────────────────────────────────────\n\nfunction cardItems(ctx: InboxContext): InboxItem[] {\n return listCards(ctx.root, \"pending\").map(cardItem)\n}\n\nfunction cardItem(c: DecisionCard): InboxItem {\n return {\n key: `card:${c.id}`,\n kind: \"card\",\n title: c.title,\n ask: c.ask,\n yes: `tell ${c.raised_by} yes`,\n no: `tell ${c.raised_by} no`,\n recommend: c.recommend,\n if_silent: c.if_silent,\n expires: c.expires,\n ...(c.source ? { source: c.source } : {}),\n raised_by: c.raised_by,\n created_at: c.created_at,\n }\n}\n\nfunction scheduleItems(ctx: InboxContext): InboxItem[] {\n const path = configPathFor(ctx)\n if (!existsSync(path)) return []\n let cfg: any\n try { cfg = JSON.parse(readFileSync(path, \"utf-8\")) } catch { return [] }\n const now = new Date(ctx.now ?? Date.now())\n const out: InboxItem[] = []\n for (const [id, job] of Object.entries<any>(cfg?.crons ?? {})) {\n const approval = job?.approval\n if (!approval || (approval.action !== \"create\" && approval.action !== \"delete\")) continue\n const tz = job.timezone || \"UTC\"\n const human = job.schedule ? humanizeCron(job.schedule) : \"\"\n const when = job.schedule ? `${human.charAt(0).toLowerCase()}${human.slice(1)} (${job.schedule})` : \"no schedule\"\n const what = String(job.prompt ?? job.command ?? \"\")\n const creating = approval.action === \"create\"\n out.push({\n key: `schedule:${id}`,\n kind: \"schedule\",\n title: creating ? `New schedule \"${id}\" for ${job.agent ?? \"an agent\"}` : `Delete schedule \"${id}\"`,\n ask: creating ? `Let ${job.agent ?? \"the agent\"} run this ${when}?` : `Remove the schedule \"${id}\" (${when})?`,\n yes: creating ? \"enable it\" : \"remove it\",\n no: creating ? \"drop the request\" : \"keep the schedule\",\n raised_by: String(approval.requestedBy ?? \"unknown\"),\n created_at: String(approval.requestedAt ?? \"\"),\n detail: clip(`${what}${creating && job.schedule ? ` · first run ${formatFireTime(nextFireTime(job.schedule, tz, now), tz)}` : \"\"}`),\n more: \"agentx schedule list\",\n })\n }\n return out\n}\n\nfunction memoryAgents(root: string): string[] {\n const dir = resolve(root, \".agentx\", \"memory\")\n if (!existsSync(dir)) return []\n return readdirSync(dir).filter((f) => f.endsWith(\".jsonl\")).map((f) => f.slice(0, -6)).sort()\n}\n\nfunction memoryItems(ctx: InboxContext): InboxItem[] {\n const agents = memoryAgents(ctx.root)\n if (agents.length === 0) return []\n const store = new MemoryStore(ctx.root)\n const out: InboxItem[] = []\n for (const agent of agents) {\n for (const f of store.held(agent)) {\n out.push({\n key: `memory:${agent}/${f.id}`,\n kind: \"memory\",\n title: `Fact ${agent} learned from ${f.source.channel}`,\n ask: `Let ${agent} use this fact in its prompts?`,\n yes: \"use it\",\n no: \"keep it out for good\",\n raised_by: agent,\n created_at: f.createdAt,\n detail: clip(f.content),\n more: `agentx memory facts held --agent ${agent}`,\n })\n }\n }\n return out\n}\n\n/** One line on what backs a wiki proposal. A lesson drawn from a\n * recurring failure says so, with the failure, before the article text:\n * the reviewer is judging a fix for something that keeps breaking. */\nexport function proposalBacking(e: PromotionProposal[\"evidence\"]): string {\n const failures = e.sources.filter((s) => s.failure)\n if (failures.length) {\n return failures.map((s) =>\n `Recurring failure: ${s.agentId}'s ${s.failure!.tool} fails with \"${s.failure!.errorClass}\" in ${s.occurrences ?? 1} sessions (${s.failure!.runs} runs).`,\n ).join(\" \")\n }\n return `${e.sources.length} source(s)${e.occurrences > 1 ? `, seen in ${e.occurrences} sessions` : \"\"}.`\n}\n\nfunction wikiItems(ctx: InboxContext): InboxItem[] {\n return listProposals(wikiDirFor(ctx), \"pending\").map((p) => {\n const e = p.evidence\n return {\n key: `wiki:${p.id}`,\n kind: \"wiki\" as const,\n title: p.article.title,\n ask: p.replaces ? `Update \"${p.article.path}\" in the shared wiki?` : `Add \"${p.article.path}\" to the shared wiki?`,\n yes: \"write the article\",\n no: \"decline it\",\n raised_by: e.agents.join(\", \") || \"wiki promote\",\n created_at: p.createdAt,\n detail: clip(`${proposalBacking(e)} ${p.article.content}`),\n more: `agentx wiki proposals show ${p.id}`,\n }\n })\n}\n\nconst SOURCES: Record<ApprovalKind, (ctx: InboxContext) => InboxItem[]> = {\n card: cardItems,\n schedule: scheduleItems,\n memory: memoryItems,\n wiki: wikiItems,\n}\n\n// ── Read model ───────────────────────────────────────────────────────\n\nexport interface InboxListing {\n items: InboxItem[]\n /** Hidden because the operator said \"later\". */\n snoozed: number\n /** Sources that couldn't be read, so an empty list isn't mistaken for \"nothing waiting\". */\n errors: Array<{ kind: ApprovalKind; error: string }>\n}\n\n/** Soonest expiry first; then oldest first. */\nexport function byUrgency(a: InboxItem, b: InboxItem): number {\n const ea = a.expires ? Date.parse(a.expires) : Infinity\n const eb = b.expires ? Date.parse(b.expires) : Infinity\n if (ea !== eb) return ea - eb\n return (Date.parse(a.created_at) || 0) - (Date.parse(b.created_at) || 0)\n}\n\nexport function listInbox(ctx: InboxContext, opts: { includeSnoozed?: boolean; kinds?: ApprovalKind[] } = {}): InboxListing {\n const now = ctx.now ?? Date.now()\n const { snoozed } = readInboxState(ctx.root)\n const items: InboxItem[] = []\n const errors: InboxListing[\"errors\"] = []\n let hidden = 0\n for (const kind of opts.kinds ?? APPROVAL_KINDS) {\n let found: InboxItem[]\n try { found = SOURCES[kind](ctx) } catch (e: any) {\n errors.push({ kind, error: String(e?.message ?? e).slice(0, 200) })\n continue\n }\n for (const item of found) {\n const until = snoozed[item.key]\n if (until && Date.parse(until) > now) {\n if (!opts.includeSnoozed) { hidden++; continue }\n item.snoozed_until = until\n }\n items.push(item)\n }\n }\n items.sort(byUrgency)\n return { items, snoozed: hidden, errors }\n}\n\n// ── Decide ───────────────────────────────────────────────────────────\n\nexport interface DecideOptions {\n /** Wiki: approve even if the article changed since the proposal. */\n force?: boolean\n /** Kept with the decision where the source records one. */\n note?: string\n /** \"later\": how long to put it off. */\n laterHours?: number\n by?: string\n}\n\nexport type DecideResult = { ok: true; message: string } | { ok: false; error: string }\n\nexport function parseKey(key: string): { kind: ApprovalKind; ref: string } | null {\n const i = key.indexOf(\":\")\n if (i <= 0) return null\n const kind = key.slice(0, i) as ApprovalKind\n const ref = key.slice(i + 1)\n if (!APPROVAL_KINDS.includes(kind) || !ref) return null\n return { kind, ref }\n}\n\n/** True while the item is still waiting in its source. */\nfunction stillPending(ctx: InboxContext, kind: ApprovalKind, ref: string): boolean {\n switch (kind) {\n case \"card\": return readCard(ctx.root, ref)?.status === \"pending\"\n case \"wiki\": return readProposal(wikiDirFor(ctx), ref)?.status === \"pending\"\n default: return SOURCES[kind](ctx).some((i) => i.key === `${kind}:${ref}`)\n }\n}\n\n/**\n * Apply the operator's answer through the source's own approve/reject.\n * Operator surfaces only: never expose this to agents.\n */\nexport async function decide(ctx: InboxContext, key: string, action: InboxAction, opts: DecideOptions = {}): Promise<DecideResult> {\n const parsed = parseKey(key)\n if (!parsed) return { ok: false, error: `unknown item \"${key}\": use a key from \\`agentx approvals list\\`` }\n const { kind, ref } = parsed\n const now = ctx.now ?? Date.now()\n const by = opts.by ?? \"operator\"\n\n if (action === \"later\") {\n if (!stillPending(ctx, kind, ref)) return { ok: false, error: `nothing waiting for \"${key}\"` }\n const hours = opts.laterHours && opts.laterHours > 0 ? opts.laterHours : 24\n const until = new Date(now + hours * 3_600_000)\n snooze(ctx.root, key, until, now)\n return { ok: true, message: `${key} put off until ${until.toISOString()}` }\n }\n\n const yes = action === \"yes\"\n switch (kind) {\n case \"card\": {\n const r = decideCard(ctx.root, ref, yes ? \"yes\" : \"no\", { by, note: opts.note, now })\n return r.ok ? { ok: true, message: `${key}: ${r.card.raised_by} will be told ${yes ? \"yes\" : \"no\"}` } : r\n }\n case \"schedule\": {\n const r = await (yes ? approveSchedule : rejectSchedule)(ref, { configPath: configPathFor(ctx), reload: ctx.reload })\n return r.success ? { ok: true, message: r.message } : { ok: false, error: r.message }\n }\n case \"memory\": {\n const slash = ref.indexOf(\"/\")\n if (slash <= 0) return { ok: false, error: `memory keys look like memory:<agent>/<fact-id>` }\n const agent = ref.slice(0, slash)\n const id = ref.slice(slash + 1)\n if (!memoryAgents(ctx.root).includes(agent)) return { ok: false, error: `no memory for agent \"${agent}\"` }\n const store = new MemoryStore(ctx.root)\n if (!store.held(agent).some((f) => f.id === id)) return { ok: false, error: `fact \"${id}\" isn't waiting for review` }\n store.review(agent, id, yes ? \"approved\" : \"rejected\", by)\n return { ok: true, message: `${key} ${yes ? \"approved: the agent may use it\" : \"rejected: it stays out of prompts\"}` }\n }\n case \"wiki\": {\n const dir = wikiDirFor(ctx)\n const r = yes\n ? approveProposal(dir, ref, { by, force: opts.force, now })\n : rejectProposal(dir, ref, { by, reason: opts.note, now })\n if (!r.ok) return r\n return { ok: true, message: yes ? `${r.proposal.article.path} written to the shared wiki` : `${key} rejected` }\n }\n }\n}\n","import { mkdirSync, readFileSync, renameSync, writeFileSync } from \"fs\"\nimport { resolve } from \"path\"\nimport { approvalsDir } from \"./cards\"\n\n// --- Inbox view state: \"later\" and the digest date ---\n//\n// Not a decision store. Every decision stays with its source (the card\n// file, the schedule in agentx.json, the memory fact, the wiki proposal).\n// This file only remembers which inbox items the operator put off until\n// when, and the last day a digest went out.\n\nexport interface InboxState {\n /** Inbox key → ISO time it comes back. */\n snoozed: Record<string, string>\n /** Local date (YYYY-MM-DD) of the last digest sent. */\n lastDigest?: string\n}\n\nfunction stateFile(root: string): string {\n return resolve(approvalsDir(root), \"_state.json\")\n}\n\nexport function readInboxState(root: string): InboxState {\n try {\n const raw = JSON.parse(readFileSync(stateFile(root), \"utf-8\"))\n return {\n snoozed: raw && typeof raw.snoozed === \"object\" && raw.snoozed ? raw.snoozed : {},\n ...(typeof raw?.lastDigest === \"string\" ? { lastDigest: raw.lastDigest } : {}),\n }\n } catch {\n return { snoozed: {} }\n }\n}\n\nexport function writeInboxState(root: string, state: InboxState): void {\n mkdirSync(approvalsDir(root), { recursive: true })\n const path = stateFile(root)\n const tmp = `${path}.${process.pid}.tmp`\n writeFileSync(tmp, JSON.stringify(state, null, 2) + \"\\n\")\n renameSync(tmp, path)\n}\n\n/** Put an item off until `until`. Drops snoozes that have run out. */\nexport function snooze(root: string, key: string, until: Date, now: number = Date.now()): void {\n const state = readInboxState(root)\n const snoozed: Record<string, string> = {}\n for (const [k, v] of Object.entries(state.snoozed)) if (Date.parse(v) > now) snoozed[k] = v\n snoozed[key] = until.toISOString()\n writeInboxState(root, { ...state, snoozed })\n}\n\nexport function recordDigest(root: string, localDate: string): void {\n writeInboxState(root, { ...readInboxState(root), lastDigest: localDate })\n}\n","import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, rmSync, statSync } from \"fs\"\nimport { resolve, relative, dirname, join, extname, basename } from \"path\"\n\n// --- Scoped file operations for the admin panel ---\n//\n// Lets the dashboard read/write identity files (CLAUDE.md / SOUL.md /\n// IDENTITY.md) and skill files (.claude/skills/<slug>/SKILL.md) WITHIN an\n// agent's workspace without ever touching the rest of the filesystem.\n// Every public function resolves the requested path against the agent's\n// workspace and refuses anything that would escape via .. symlinks, etc.\n\nconst MAX_FILE_BYTES = 200 * 1024 // 200 KB — plenty for CLAUDE.md / skills.\nconst ALLOWED_EXTENSIONS = new Set([\".md\", \".markdown\", \".txt\"])\n/** Extensions the skill-tree viewer is allowed to read/write. Broader than\n * identity editing — skills include shell scripts, lockfiles, configs. Kept\n * as an allow-list so a malicious prompt can't touch an arbitrary binary. */\nconst SKILL_EDITABLE_EXTENSIONS = new Set([\n \".md\", \".markdown\", \".txt\", \".json\", \".jsonc\", \".yaml\", \".yml\", \".toml\",\n \".sh\", \".bash\", \".zsh\", \".py\", \".js\", \".mjs\", \".ts\", \".tsx\", \".jsx\",\n \".css\", \".html\", \".lock\", \".cfg\", \".ini\", \".env\", \".gitignore\",\n])\n/** Depth limit when walking a skill dir tree — defensive against loops. */\nconst SKILL_TREE_MAX_DEPTH = 6\nconst IDENTITY_FILENAMES = new Set([\n \"CLAUDE.md\", \"SOUL.md\", \"IDENTITY.md\", \"PERSONA.md\", \"AGENT.md\", \"BOOTSTRAP.md\",\n])\n\nexport interface FileOverview {\n identity: Array<{\n path: string // relative to workspace, e.g. \"CLAUDE.md\"\n title: string\n size: number\n exists: boolean // canonical files can be listed as templates even if missing\n }>\n skills: Array<{\n slug: string // dir name under .claude/skills/\n title: string // first # heading in SKILL.md or fallback to slug\n size: number\n path: string // relative to workspace, e.g. \".claude/skills/foo/SKILL.md\"\n }>\n workspace: string // absolute, for display only\n}\n\n/**\n * Resolve a user-supplied path to an absolute path strictly within `workspace`.\n * Throws if the result would escape. Returns the normalised absolute path.\n */\nfunction resolveInWorkspace(workspace: string, relPath: string): string {\n if (!workspace) throw new Error(\"Agent workspace is not configured.\")\n const wsAbs = resolve(workspace)\n if (!existsSync(wsAbs)) {\n // Create the workspace lazily — a fresh agent scaffolded via the wizard\n // may have an empty directory created but not yet with file structure.\n mkdirSync(wsAbs, { recursive: true })\n }\n // Reject absolute-path attempts outright.\n if (!relPath || relPath.startsWith(\"/\") || relPath.match(/^[a-zA-Z]:/)) {\n throw new Error(`Path must be relative to the workspace: ${relPath}`)\n }\n const target = resolve(wsAbs, relPath)\n const rel = relative(wsAbs, target)\n // rel === \"\" means target IS the workspace dir — fine for list ops.\n // rel starts with \"..\" iff target is outside the workspace.\n if (rel.startsWith(\"..\")) {\n throw new Error(`Path escapes the workspace: ${relPath}`)\n }\n return target\n}\n\nfunction assertEditable(absPath: string): void {\n const ext = extname(absPath).toLowerCase()\n if (!ALLOWED_EXTENSIONS.has(ext)) {\n throw new Error(`Only text files (.md, .markdown, .txt) can be edited from the admin panel (got ${ext}).`)\n }\n}\n\nfunction extractTitle(markdown: string, fallback: string): string {\n const line = markdown.split(/\\r?\\n/).find((l) => l.trim().startsWith(\"#\"))\n if (!line) return fallback\n return line.replace(/^#+\\s*/, \"\").trim().slice(0, 120) || fallback\n}\n\n/**\n * List the identity files + skills for an agent. Identity \"canonical\" names\n * that don't exist are still reported (exists: false) so the UI can offer to\n * create them with a sensible default.\n */\nexport function listAgentFiles(workspace: string): FileOverview {\n const wsAbs = resolveInWorkspace(workspace, \".\")\n const identity: FileOverview[\"identity\"] = []\n const seen = new Set<string>()\n\n // Every .md in the workspace root is identity material; canonical names\n // sort first.\n let rootEntries: string[] = []\n try { rootEntries = readdirSync(wsAbs) } catch { /* empty */ }\n for (const name of IDENTITY_FILENAMES) {\n const abs = join(wsAbs, name)\n if (existsSync(abs) && statSync(abs).isFile()) {\n const size = statSync(abs).size\n const content = size > 0 && size < MAX_FILE_BYTES ? safeRead(abs) : \"\"\n identity.push({ path: name, title: extractTitle(content, name), size, exists: true })\n seen.add(name)\n } else {\n identity.push({ path: name, title: name, size: 0, exists: false })\n seen.add(name)\n }\n }\n for (const name of rootEntries) {\n if (seen.has(name)) continue\n const abs = join(wsAbs, name)\n try {\n const st = statSync(abs)\n if (!st.isFile()) continue\n if (!ALLOWED_EXTENSIONS.has(extname(name).toLowerCase())) continue\n const content = st.size > 0 && st.size < MAX_FILE_BYTES ? safeRead(abs) : \"\"\n identity.push({ path: name, title: extractTitle(content, name), size: st.size, exists: true })\n } catch { /* skip unreadable */ }\n }\n\n // Skills live under .claude/skills/<slug>/SKILL.md\n const skills: FileOverview[\"skills\"] = []\n const skillsRoot = join(wsAbs, \".claude\", \"skills\")\n if (existsSync(skillsRoot)) {\n try {\n for (const slug of readdirSync(skillsRoot)) {\n const dir = join(skillsRoot, slug)\n let st\n try { st = statSync(dir) } catch { continue }\n if (!st.isDirectory()) continue\n const file = join(dir, \"SKILL.md\")\n if (!existsSync(file)) continue\n const stf = statSync(file)\n const content = stf.size < MAX_FILE_BYTES ? safeRead(file) : \"\"\n skills.push({\n slug,\n title: extractTitle(content, slug),\n size: stf.size,\n path: `.claude/skills/${slug}/SKILL.md`,\n })\n }\n } catch { /* */ }\n }\n skills.sort((a, b) => a.slug.localeCompare(b.slug))\n\n return { identity, skills, workspace: wsAbs }\n}\n\nfunction safeRead(abs: string): string {\n try { return readFileSync(abs, \"utf-8\") } catch { return \"\" }\n}\n\n/**\n * Read a single file within the workspace. Throws if the path is outside the\n * workspace, has a disallowed extension, or doesn't exist.\n */\nexport function readAgentFile(workspace: string, relPath: string): { path: string; content: string } {\n const abs = resolveInWorkspace(workspace, relPath)\n assertEditable(abs)\n if (!existsSync(abs)) return { path: relPath, content: \"\" }\n if (statSync(abs).size > MAX_FILE_BYTES) {\n throw new Error(`File is too large to edit in the admin panel (> ${MAX_FILE_BYTES / 1024} KB).`)\n }\n return { path: relPath, content: readFileSync(abs, \"utf-8\") }\n}\n\n/**\n * Write a file. Creates parent dirs as needed. Rejects extensions / size\n * outside the allow-list the same way readAgentFile does.\n */\nexport function writeAgentFile(workspace: string, relPath: string, content: string): { path: string; bytes: number } {\n const abs = resolveInWorkspace(workspace, relPath)\n assertEditable(abs)\n const buf = Buffer.from(content, \"utf-8\")\n if (buf.length > MAX_FILE_BYTES) {\n throw new Error(`File too large (${buf.length} > ${MAX_FILE_BYTES} bytes).`)\n }\n mkdirSync(dirname(abs), { recursive: true })\n writeFileSync(abs, buf)\n return { path: relPath, bytes: buf.length }\n}\n\n/**\n * Create a new skill scaffold at .claude/skills/<slug>/SKILL.md.\n */\nexport function createAgentSkill(\n workspace: string,\n slug: string,\n opts: { title?: string; content?: string } = {},\n): { slug: string; path: string } {\n if (!/^[a-z0-9][a-z0-9_-]*$/.test(slug)) {\n throw new Error(\"Skill slug must be lowercase (letters, digits, -, _) and start with a letter or digit.\")\n }\n const relPath = `.claude/skills/${slug}/SKILL.md`\n const abs = resolveInWorkspace(workspace, relPath)\n if (existsSync(abs)) throw new Error(`Skill \"${slug}\" already exists.`)\n mkdirSync(dirname(abs), { recursive: true })\n const body = opts.content?.trim()\n ? opts.content\n : defaultSkillTemplate(slug, opts.title)\n writeFileSync(abs, body)\n return { slug, path: relPath }\n}\n\n/**\n * Remove a skill directory (.claude/skills/<slug>). Scoped to the workspace\n * so we can never touch anything else.\n */\nexport function deleteAgentSkill(workspace: string, slug: string): { slug: string } {\n if (!/^[a-z0-9][a-z0-9_-]*$/.test(slug)) throw new Error(`Invalid skill slug: ${slug}`)\n const abs = resolveInWorkspace(workspace, `.claude/skills/${slug}`)\n if (!existsSync(abs)) throw new Error(`Skill \"${slug}\" not found.`)\n const st = statSync(abs)\n if (!st.isDirectory()) throw new Error(`Skill path is not a directory: ${slug}`)\n rmSync(abs, { recursive: true, force: true })\n return { slug }\n}\n\n// --- Skill directory tree + per-file I/O ---\n//\n// A skill is `.claude/skills/<slug>/` — usually SKILL.md plus scripts,\n// lockfiles, configs. The admin UI lets the operator browse the directory\n// tree, edit any text file, and dispatch \"install deps\" through the agent.\n\nexport interface SkillTreeEntry {\n /** Path relative to the skill dir root. Directories end with \"/\". */\n path: string\n kind: \"file\" | \"dir\"\n size: number\n editable: boolean // false for binaries or disallowed extensions\n}\n\nexport interface SkillDepsHint {\n /** Which install command the operator should run (or have an agent run). */\n manager: \"npm\" | \"pnpm\" | \"yarn\" | \"pip\" | \"bundle\" | null\n /** Filename that triggered the detection, relative to skill dir. */\n file: string | null\n /** The exact command we'd recommend. */\n command: string | null\n}\n\n/** List every file in `.claude/skills/<slug>/`, recursively. Scoped so the\n * caller can't escape the skill dir via symlinks or \"..\" segments. */\nexport function listSkillTree(workspace: string, slug: string): SkillTreeEntry[] {\n if (!/^[a-z0-9][a-z0-9_-]*$/.test(slug)) throw new Error(`Invalid skill slug: ${slug}`)\n const skillRoot = resolveInWorkspace(workspace, `.claude/skills/${slug}`)\n if (!existsSync(skillRoot)) throw new Error(`Skill \"${slug}\" not found.`)\n const out: SkillTreeEntry[] = []\n walk(skillRoot, \"\", 0, out)\n out.sort((a, b) => {\n // dirs first, then alphabetical\n if (a.kind !== b.kind) return a.kind === \"dir\" ? -1 : 1\n return a.path.localeCompare(b.path)\n })\n return out\n\n function walk(absDir: string, relDir: string, depth: number, acc: SkillTreeEntry[]): void {\n if (depth > SKILL_TREE_MAX_DEPTH) return\n let entries: string[] = []\n try { entries = readdirSync(absDir) } catch { return }\n for (const name of entries) {\n if (name === \"node_modules\" || name === \".git\") continue\n const abs = join(absDir, name)\n const rel = relDir ? `${relDir}/${name}` : name\n let st\n try { st = statSync(abs) } catch { continue }\n if (st.isDirectory()) {\n acc.push({ path: `${rel}/`, kind: \"dir\", size: 0, editable: false })\n walk(abs, rel, depth + 1, acc)\n } else if (st.isFile()) {\n const ext = extname(name).toLowerCase()\n // name-only allowlist for dotfiles like .env / .gitignore (no extension)\n const allowedByName = SKILL_EDITABLE_EXTENSIONS.has(ext) ||\n SKILL_EDITABLE_EXTENSIONS.has(name.toLowerCase())\n acc.push({\n path: rel,\n kind: \"file\",\n size: st.size,\n editable: allowedByName && st.size < MAX_FILE_BYTES,\n })\n }\n }\n }\n}\n\n/** Read any file in a skill dir. Respects the skill-editable allowlist. */\nexport function readSkillFile(workspace: string, slug: string, relPath: string): { path: string; content: string } {\n if (!/^[a-z0-9][a-z0-9_-]*$/.test(slug)) throw new Error(`Invalid skill slug: ${slug}`)\n if (!relPath || relPath.includes(\"..\")) throw new Error(`Invalid file path: ${relPath}`)\n const abs = resolveInWorkspace(workspace, `.claude/skills/${slug}/${relPath}`)\n if (!existsSync(abs) || !statSync(abs).isFile()) {\n throw new Error(`File not found: ${relPath}`)\n }\n const ext = extname(abs).toLowerCase()\n const name = basename(abs).toLowerCase()\n if (!SKILL_EDITABLE_EXTENSIONS.has(ext) && !SKILL_EDITABLE_EXTENSIONS.has(name)) {\n throw new Error(`File type not editable: ${relPath}`)\n }\n if (statSync(abs).size > MAX_FILE_BYTES) {\n throw new Error(`File too large to edit (> ${MAX_FILE_BYTES / 1024} KB): ${relPath}`)\n }\n return { path: relPath, content: readFileSync(abs, \"utf-8\") }\n}\n\n/** Write any allowed file inside a skill dir. Creates parents. */\nexport function writeSkillFile(\n workspace: string,\n slug: string,\n relPath: string,\n content: string,\n): { path: string; bytes: number } {\n if (!/^[a-z0-9][a-z0-9_-]*$/.test(slug)) throw new Error(`Invalid skill slug: ${slug}`)\n if (!relPath || relPath.includes(\"..\")) throw new Error(`Invalid file path: ${relPath}`)\n const abs = resolveInWorkspace(workspace, `.claude/skills/${slug}/${relPath}`)\n const ext = extname(abs).toLowerCase()\n const name = basename(abs).toLowerCase()\n if (!SKILL_EDITABLE_EXTENSIONS.has(ext) && !SKILL_EDITABLE_EXTENSIONS.has(name)) {\n throw new Error(`File type not editable: ${relPath}`)\n }\n const buf = Buffer.from(content, \"utf-8\")\n if (buf.length > MAX_FILE_BYTES) {\n throw new Error(`File too large (${buf.length} > ${MAX_FILE_BYTES} bytes).`)\n }\n mkdirSync(dirname(abs), { recursive: true })\n writeFileSync(abs, buf)\n return { path: relPath, bytes: buf.length }\n}\n\n/** Detect which dependency manager a skill needs based on the files present. */\nexport function detectSkillDeps(workspace: string, slug: string): SkillDepsHint {\n if (!/^[a-z0-9][a-z0-9_-]*$/.test(slug)) throw new Error(`Invalid skill slug: ${slug}`)\n const skillRoot = resolveInWorkspace(workspace, `.claude/skills/${slug}`)\n if (!existsSync(skillRoot)) throw new Error(`Skill \"${slug}\" not found.`)\n const check = (name: string): boolean => existsSync(join(skillRoot, name))\n if (check(\"pnpm-lock.yaml\")) return { manager: \"pnpm\", file: \"pnpm-lock.yaml\", command: \"pnpm install\" }\n if (check(\"yarn.lock\")) return { manager: \"yarn\", file: \"yarn.lock\", command: \"yarn install\" }\n if (check(\"package.json\")) return { manager: \"npm\", file: \"package.json\", command: \"npm install\" }\n if (check(\"requirements.txt\")) return { manager: \"pip\", file: \"requirements.txt\", command: \"pip install -r requirements.txt\" }\n if (check(\"Gemfile\")) return { manager: \"bundle\", file: \"Gemfile\", command: \"bundle install\" }\n return { manager: null, file: null, command: null }\n}\n\nfunction defaultSkillTemplate(slug: string, title?: string): string {\n const displayTitle = title?.trim() || slug\n return `# ${displayTitle}\n\nDescribe what this skill does and when the agent should use it. Keep it under ~5 lines — the agent reads this to decide whether to invoke the skill.\n\n## When to use\n- Trigger condition 1\n- Trigger condition 2\n\n## How to use\nDocument the arguments, commands, or files the skill expects. Example:\n\n\\`\\`\\`bash\n# Example invocation\nclaude-code ${basename(slug)} --arg value\n\\`\\`\\`\n`\n}\n","import { loadDaemonConfig, type DaemonConfig } from \"@/daemon/config\"\n\n// The `screen` block of agentx.json and the one write rule for it, shared\n// by `agentx screen config` and the dashboard so both refuse the same\n// values.\n\nexport type ScreenSettings = DaemonConfig[\"screen\"]\ntype Rect = ScreenSettings[\"regions\"][string]\n\nexport const DEFAULT_SCREEN: ScreenSettings = {\n maxPixels: 1_200_000,\n timeoutMs: 5_000,\n intervalMs: 100,\n changeThreshold: 0.015,\n stableMs: 400,\n regions: {},\n buffer: { enabled: false, seconds: 10, fps: 2, region: \"screen\", maxPixels: 300_000 },\n}\n\n/** Fill gaps in a partial `screen` block with the defaults. */\nexport function screenSettings(cfg: Partial<ScreenSettings> | undefined): ScreenSettings {\n return {\n ...DEFAULT_SCREEN,\n ...(cfg ?? {}),\n regions: { ...(cfg?.regions ?? {}) },\n buffer: { ...DEFAULT_SCREEN.buffer, ...(cfg?.buffer ?? {}) },\n }\n}\n\n/** The `screen` block from agentx.json. A missing or invalid file means\n * the defaults: a capture should never fail over a settings file. */\nexport function readScreenSettings(configPath?: string): ScreenSettings {\n try { return screenSettings(loadDaemonConfig(configPath).screen) } catch { return screenSettings(undefined) }\n}\n\nconst REGION_NAME =/^[a-z][\\w-]*$/\n\n/** Regions the helper knows without configuration; `screen.regions` adds\n * more and may override these. */\nexport const BUILT_IN_REGIONS = [\"window\", \"screen\", \"menubar\", \"notifications\"]\n\nfunction num(v: unknown, what: string, ok: (n: number) => boolean, rule: string): number {\n const n = Number(v)\n if (v === \"\" || v === null || !Number.isFinite(n) || !ok(n)) throw new Error(`${what} must be ${rule}`)\n return n\n}\nconst positiveInt = (v: unknown, what: string) => num(v, what, (n) => Number.isInteger(n) && n > 0, \"a whole number above 0\")\n\n/** \"x,y,w,h\" or {x, y, width, height} → a rect, or an error. */\nexport function parseRect(v: unknown): Rect {\n const r = typeof v === \"string\" ? v.split(\",\").map(Number) : [(v as any)?.x, (v as any)?.y, (v as any)?.width, (v as any)?.height].map(Number)\n if (r.length !== 4 || !r.every(Number.isFinite) || r[2] <= 0 || r[3] <= 0) throw new Error(\"a region is x,y,width,height in screen points, with width and height above 0\")\n return { x: r[0], y: r[1], width: r[2], height: r[3] }\n}\n\n/**\n * Apply a change to a stored `screen` block. Returns the new block;\n * throws on a value that would not load. `regions` entries set to null\n * are removed.\n */\nexport function patchScreen(current: Partial<ScreenSettings> | undefined, patch: Record<string, any>): Partial<ScreenSettings> {\n const next: Record<string, any> = { ...(current ?? {}) }\n if (\"maxPixels\" in patch) next.maxPixels = positiveInt(patch.maxPixels, \"maxPixels\")\n if (\"timeoutMs\" in patch) next.timeoutMs = positiveInt(patch.timeoutMs, \"timeoutMs\")\n if (\"intervalMs\" in patch) next.intervalMs = positiveInt(patch.intervalMs, \"intervalMs\")\n if (\"stableMs\" in patch) next.stableMs = num(patch.stableMs, \"stableMs\", (n) => Number.isInteger(n) && n >= 0, \"a whole number, 0 or more\")\n if (\"changeThreshold\" in patch) next.changeThreshold = num(patch.changeThreshold, \"changeThreshold\", (n) => n >= 0 && n <= 1, \"between 0 and 1\")\n if (patch.regions && typeof patch.regions === \"object\") {\n const regions = { ...(next.regions ?? {}) }\n for (const [name, rect] of Object.entries(patch.regions)) {\n if (!REGION_NAME.test(name)) throw new Error(`region name \"${name}\" must be lowercase letters, digits, - or _`)\n if (rect === null) delete regions[name]\n else regions[name] = parseRect(rect)\n }\n next.regions = regions\n }\n if (patch.buffer && typeof patch.buffer === \"object\") {\n const b = patch.buffer\n const buffer = { ...(next.buffer ?? {}) }\n if (\"enabled\" in b) buffer.enabled = Boolean(b.enabled)\n if (\"seconds\" in b) buffer.seconds = num(b.seconds, \"buffer.seconds\", (n) => n > 0 && n <= 120, \"above 0 and at most 120\")\n if (\"fps\" in b) buffer.fps = num(b.fps, \"buffer.fps\", (n) => n > 0 && n <= 10, \"above 0 and at most 10\")\n if (\"maxPixels\" in b) buffer.maxPixels = positiveInt(b.maxPixels, \"buffer.maxPixels\")\n if (\"region\" in b) buffer.region = String(b.region).trim()\n next.buffer = buffer\n }\n const watched = next.buffer?.region\n if (watched !== undefined && !BUILT_IN_REGIONS.includes(watched) && !next.regions?.[watched]) {\n try { parseRect(watched) } catch {\n throw new Error(`buffer.region \"${watched}\" is not a region — use ${[...BUILT_IN_REGIONS, ...Object.keys(next.regions ?? {})].join(\", \")}, or x,y,w,h`)\n }\n }\n return next\n}\n"],"mappings":"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","names":["existsSync","readdirSync","readFileSync","statSync","resolve","workflowHealth","workflows","runs","now","windowDays","span","byId","r","list","w","mine","recent","prior","failed","paused","lastRunAt","state","b","rank","cache","scanRuns","runsDir","limit","files","f","p","a","live","key","out","path","mtime","hit","summary","readSummary","lines","head","workflowId","status","i","tail","s","DEFAULT_ROUTINE_THRESHOLDS","ROUTINE_LIMITS","defaultNextFire","expression","after","timezone","getNextCronDate","DAY","buildRoutines","input","now","nextFire","out","job","runs","outcomes","r","latest","routine","cap","isoOrNull","capOpt","failStreak","scheduleFlags","finish","health","workflowHealth","w","h","runsByWorkflow","list","wf","trigger","n","cfg","state","enabled","a","b","workflowOutcome","isCron","spec","describeFilters","workflowAgent","s","o","changedAt","eventFlags","compareRoutines","t","flags","lastAt","disabled","disabledFlag","cursor","deadline","i","dormant","since","reasons","f","ATTENTION_RANK","ra","rb","status","node","filter","project","key","value","values","v","d","limit","LOOPBACK","isMeshGatedPath","path","isControlPost","isLoopback","remoteAddress","decideMeshAuth","req","header","token","collectAcceptedMeshTokens","config","env","accepted","p","dashboardTokenForNode","dashboard","target","norm","u","d","first","v","originHost","origin","allowedOriginsFromEnv","env","s","classifyBrowserRequest","headers","extraAllowed","from","hosts","h","site","isStateChangingOrPreflight","method","m","readFileSync","writeFileSync","existsSync","readdirSync","statSync","resolve","join","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","resolve","z","sourceSchema","itemSchema","fileSchema","BacklogStore","path","resolve","existsSync","p","raw","readFileSync","e","file","jsonP","mkdirSync","dirname","writeFileSync","id","i","input","now","item","inputs","existing","added","patch","idx","updated","before","lines","buckets","sections","key","label","it","check","mention","time","src","sourceBacklogId","source","resolveAssigneesForSource","agentIds","source","daemon","out","mappings","agentId","m","x","syncBacklogItemToSource","item","patch","log","syncToGitLab","syncToGitHub","gl","token","host","attempts","api","path","init","projectEnc","assigneeIds","u","res","arr","milestoneId","e","body","text","a","repo","milestoneNumber","found","nextLabels","issue","current","l","adds","r","CHECK_RE","MENTION_RE","TIME_RE","parseDuration","s","hMatch","mMatch","BacklogWorkSource","path","daemon","log","BacklogStore","full","resolve","existsSync","readFileSync","lines","writeFileSync","agentId","it","items","i","m","body","mention","timeMatch","title","_opts","itemId","item","updated","usernames","resolveAssigneesForSource","syncBacklogItemToSource","e","update","patch","sourcePatch","lineNo","line","note","stage","WikiWorkSource","root","glob","dir","out","entry","readdirSync","join","statSync","files","file","parts","GitLabWorkSource","host","token","projects","agentUsernames","username","names","n","issue","project","ns","labels","labelDetails","l","assignees","a","firstUsername","init","res","projectList","q","issues","iid","type","seg","mins","dur","opts","sinceDays","updatedAfter","params","state","result","deny","prefix","to","assigneeIds","users","x","milestoneId","ms","byUsername","members","b","byTitle","all","input","assignee_ids","u","milestone_id","toLabel","fromLabel","add","remove","createWorkSource","business","ws","gl","mapping","r","UNMAPPED","clientFromProject","project","projects","hit","p","slash","agentClients","business","out","orgChart","climb","agentId","seen","up","c","matchContact","channel","who","contactMap","pool","m","resolveClient","ref","contact","byAgent","parseWorkRef","sessionId","parts","agent","rest","target","KIND_DEFAULT","id","clientPolicy","parseDuration","listClients","ids","v","n","existsSync","mkdirSync","readdirSync","readFileSync","renameSync","writeFileSync","resolve","IF_SILENT_VALUES","CARD_LIMITS","DEFAULT_CARD_SETTINGS","approvalsDir","root","CARD_ID_RE","isValidCardId","id","fileFor","newCardId","now","title","day","slug","saveCard","card","path","tmp","readCard","listCards","status","dir","out","f","c","oneLine","v","resolveExpiry","input","settings","max","at","raw","rel","buildCard","opts","ask","recommend","raisedBy","ifSilent","expiry","source","reply","r","createCard","built","open","decideCard","verdict","note","decided","expireCards","expired","cardsAwaitingAgentNotice","markAgentNotified","verdictMessage","result","lines","existsSync","readdirSync","readFileSync","resolve","mkdirSync","readFileSync","renameSync","writeFileSync","resolve","stateFile","root","resolve","approvalsDir","readInboxState","raw","readFileSync","writeInboxState","state","mkdirSync","path","tmp","writeFileSync","renameSync","snooze","key","until","now","snoozed","k","v","recordDigest","localDate","APPROVAL_KINDS","DETAIL_MAX","clip","s","n","flat","configPathFor","ctx","resolve","candidates","c","existsSync","wikiDirFor","cardItems","listCards","cardItem","scheduleItems","path","cfg","readFileSync","now","out","id","job","approval","tz","human","humanizeCron","when","what","creating","formatFireTime","nextFireTime","memoryAgents","root","dir","readdirSync","f","memoryItems","agents","store","MemoryStore","agent","proposalBacking","e","failures","wikiItems","listProposals","p","SOURCES","byUrgency","a","b","ea","eb","listInbox","opts","snoozed","readInboxState","items","errors","hidden","kind","found","item","until","parseKey","key","i","ref","stillPending","readCard","readProposal","decide","action","parsed","by","hours","snooze","yes","r","decideCard","approveSchedule","rejectSchedule","slash","approveProposal","rejectProposal","existsSync","readFileSync","writeFileSync","mkdirSync","readdirSync","rmSync","statSync","resolve","relative","dirname","join","extname","basename","MAX_FILE_BYTES","ALLOWED_EXTENSIONS","SKILL_EDITABLE_EXTENSIONS","SKILL_TREE_MAX_DEPTH","IDENTITY_FILENAMES","resolveInWorkspace","workspace","relPath","wsAbs","target","assertEditable","absPath","ext","extractTitle","markdown","fallback","line","l","listAgentFiles","identity","seen","rootEntries","name","abs","size","content","safeRead","st","skills","skillsRoot","slug","dir","file","stf","a","b","readAgentFile","writeAgentFile","buf","createAgentSkill","opts","body","defaultSkillTemplate","deleteAgentSkill","listSkillTree","skillRoot","out","walk","absDir","relDir","depth","acc","entries","rel","allowedByName","readSkillFile","writeSkillFile","detectSkillDeps","check","title","init_config","DEFAULT_SCREEN","screenSettings","cfg","readScreenSettings","configPath","loadDaemonConfig","REGION_NAME","BUILT_IN_REGIONS","num","v","what","ok","rule","n","positiveInt","parseRect","r","patchScreen","current","patch","next","regions","name","rect","b","buffer","watched"]}
|