frizz 0.12.13 → 0.13.1
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/frizz.js +872 -369
- package/package.json +13 -13
- package/dist/claude-agent-broker.js +0 -35911
- package/dist/codex-app-server-daemon.js +0 -423
- package/dist/dev-child.js +0 -56194
- package/runtime/board/agent-bindings.mjs +0 -287
- package/runtime/board/agent-liveness.mjs +0 -367
- package/runtime/board/agent-status.mjs +0 -178
- package/runtime/board/config.mjs +0 -993
- package/runtime/board/decisions.mjs +0 -97
- package/runtime/board/index.mjs +0 -704
- package/runtime/board/notify-shared.mjs +0 -90
- package/runtime/board/notify.mjs +0 -81
- package/runtime/board/ownership.mjs +0 -120
- package/runtime/board/rest-detect.mjs +0 -213
- package/runtime/board/thread-excerpt.mjs +0 -162
- package/runtime/board/thread-update.mjs +0 -289
- package/runtime/cc-worker/.claude-plugin/plugin.json +0 -10
- package/runtime/cc-worker/DECISIONS.md +0 -1172
- package/runtime/cc-worker/LICENSE +0 -21
- package/runtime/cc-worker/agents/high.md +0 -7
- package/runtime/cc-worker/agents/low.md +0 -7
- package/runtime/cc-worker/agents/max.md +0 -7
- package/runtime/cc-worker/agents/medium.md +0 -7
- package/runtime/cc-worker/agents/xhigh.md +0 -7
- package/runtime/cc-worker/bin/frizz +0 -17
- package/runtime/cc-worker/bin/frizz-mcp.mjs +0 -1612
- package/runtime/cc-worker/bin/frizz-update +0 -18
- package/runtime/cc-worker/hooks/agent-bind.mjs +0 -40
- package/runtime/cc-worker/hooks/agent-dispatch.mjs +0 -121
- package/runtime/cc-worker/hooks/bash-background.d.mts +0 -6
- package/runtime/cc-worker/hooks/bash-background.mjs +0 -247
- package/runtime/cc-worker/hooks/deny-ask.mjs +0 -39
- package/runtime/cc-worker/hooks/deny-plan.mjs +0 -62
- package/runtime/cc-worker/hooks/hooks.json +0 -102
- package/runtime/cc-worker/hooks/perm-policy.mjs +0 -211
- package/runtime/cc-worker/hooks/scratchpad.mjs +0 -417
- package/runtime/cc-worker/hooks/session-seed.mjs +0 -107
- package/runtime/cc-worker/scripts/frizz/agent-bindings.mjs +0 -9
- package/runtime/cc-worker/scripts/frizz/config.mjs +0 -12
- package/runtime/cc-worker/skills/gh/SKILL.md +0 -141
- package/runtime/cc-worker/skills/gh/scripts/ci-watch.mjs +0 -60
- package/runtime/cc-worker/skills/gh/scripts/github-watch.mjs +0 -130
- package/runtime/cc-worker/skills/gh/scripts/review-watch.mjs +0 -54
- package/web-dist/apple-touch-icon.png +0 -0
- package/web-dist/assets/TerminalPane-Cv0c_SNS.js +0 -7
- package/web-dist/assets/abnfDiagram-VRR7QNED-B-wED8ht.js +0 -1
- package/web-dist/assets/arc-BSyeo0Gb.js +0 -1
- package/web-dist/assets/architecture-TIHT7OUA-nsH-QfGr.js +0 -1
- package/web-dist/assets/architectureDiagram-ZJ3FMSHR-kHm_O2sR.js +0 -36
- package/web-dist/assets/array-BifhSqXX.js +0 -1
- package/web-dist/assets/blockDiagram-677ZJIJ3-CdazUaKU.js +0 -132
- package/web-dist/assets/c4Diagram-LMCZKHZV-rauLKZbJ.js +0 -10
- package/web-dist/assets/channel-fvwjeUt3.js +0 -1
- package/web-dist/assets/chunk-2Q5K7J3B-C1jixKkw.js +0 -1
- package/web-dist/assets/chunk-32BRIVSS-DjOqyEDX.js +0 -1
- package/web-dist/assets/chunk-52WLFC77-f1SThegZ.js +0 -10
- package/web-dist/assets/chunk-5VM5RSS4-ZNzvKenW.js +0 -15
- package/web-dist/assets/chunk-7BUUIJ7U-Bb538aSH.js +0 -1
- package/web-dist/assets/chunk-C7G6YPKG-BfQsesjz.js +0 -1
- package/web-dist/assets/chunk-EX3LRPZG-BIzZW7OQ.js +0 -231
- package/web-dist/assets/chunk-FWX5IMBZ-CATINZFC.js +0 -2
- package/web-dist/assets/chunk-HOUHSVGY-DbMBRCCE.js +0 -1
- package/web-dist/assets/chunk-ICXQ74PX-COcoSWx4.js +0 -2
- package/web-dist/assets/chunk-JWPE2WC7-DVXcaiue.js +0 -1
- package/web-dist/assets/chunk-KEIR6QF5-BfrZ3jm6.js +0 -161
- package/web-dist/assets/chunk-MOJQB5TN-CVnI-o_4.js +0 -88
- package/web-dist/assets/chunk-OGEWGWER-U0vdZqB6.js +0 -1
- package/web-dist/assets/chunk-PUDLZKDR-Bukb7rem.js +0 -156
- package/web-dist/assets/chunk-Q4XR5HBZ-Bl019PHd.js +0 -70
- package/web-dist/assets/chunk-RYQCIY6F-Cu_KplZW.js +0 -1
- package/web-dist/assets/chunk-V7JOEXUC-YJR0vzI6.js +0 -206
- package/web-dist/assets/chunk-VAUOI2AC-CK6NU9kj.js +0 -1
- package/web-dist/assets/chunk-VR4S4FIN-B3LBv3C3.js +0 -1
- package/web-dist/assets/chunk-WYO6CB5R-DjRPyRuS.js +0 -127
- package/web-dist/assets/chunk-XXDRQBXY-DYlTP5J-.js +0 -1
- package/web-dist/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +0 -1
- package/web-dist/assets/chunk-ZGVPDNZ5-BUJCayKP.js +0 -62
- package/web-dist/assets/chunk-ZIRB5QZD-C6fEPe3t.js +0 -32
- package/web-dist/assets/classDiagram-OUVF2IWQ-BRZQ_xnN.js +0 -1
- package/web-dist/assets/classDiagram-v2-EOCWNBFH-BRZQ_xnN.js +0 -1
- package/web-dist/assets/cose-bilkent-JH36ORCC-BUIsLrGc.js +0 -1
- package/web-dist/assets/cynefin-VYW2F7L2-CE3ce51v.js +0 -1
- package/web-dist/assets/cynefinDiagram-TSTJHNR4-DSXSPZQV.js +0 -62
- package/web-dist/assets/cytoscape.esm-B3I8pqwA.js +0 -321
- package/web-dist/assets/dagre-CXRCoUWR.js +0 -1
- package/web-dist/assets/dagre-VKFMJZFB-VwBQdjum.js +0 -4
- package/web-dist/assets/defaultLocale-C8Fc0cco.js +0 -1
- package/web-dist/assets/diagram-FQU43EPY-7Tf5_WDu.js +0 -3
- package/web-dist/assets/diagram-G47NLZAW-mu4aclWA.js +0 -24
- package/web-dist/assets/diagram-NH7WQ7WH-B3kAVNwv.js +0 -24
- package/web-dist/assets/diagram-OA4YK3LP-DAaV-2ou.js +0 -30
- package/web-dist/assets/diagram-WEI45ONY-DijPfgly.js +0 -41
- package/web-dist/assets/dist-DoH_9pyS.js +0 -1
- package/web-dist/assets/ebnfDiagram-CCIWWBDH-B1o42Wp-.js +0 -1
- package/web-dist/assets/erDiagram-Q63AITRT-Dqej9Wi3.js +0 -85
- package/web-dist/assets/eventmodeling-45OFAUF4-B8xeGcXU.js +0 -1
- package/web-dist/assets/flowDiagram-23GEKE2U-Cnyfcz6Z.js +0 -1
- package/web-dist/assets/ganttDiagram-NO4QXBWP-UoyrLPUT.js +0 -292
- package/web-dist/assets/gitGraph-TEB2WS4Q-CwjIwQ3T.js +0 -1
- package/web-dist/assets/gitGraphDiagram-IHSO6WYX-BxU758_g.js +0 -106
- package/web-dist/assets/graphlib-B8gBHxth.js +0 -1
- package/web-dist/assets/index-CT6k_A5y.css +0 -1
- package/web-dist/assets/index-k8HCkyvh.js +0 -319
- package/web-dist/assets/info-DKCQHKI2-CWtSI6aK.js +0 -1
- package/web-dist/assets/infoDiagram-FWYZ7A6U-n5xRfy_d.js +0 -2
- package/web-dist/assets/init-D6jRqBbL.js +0 -1
- package/web-dist/assets/ishikawaDiagram-FXEZZL3T-DU1LTQY-.js +0 -70
- package/web-dist/assets/journeyDiagram-5HDEW3XC-BzZWHoPv.js +0 -139
- package/web-dist/assets/kanban-definition-HUTT4EX6-CeneyR7c.js +0 -89
- package/web-dist/assets/katex-CddkPoXu.js +0 -257
- package/web-dist/assets/line-DTfkLWnw.js +0 -1
- package/web-dist/assets/linear-z2V0wJk9.js +0 -1
- package/web-dist/assets/map-DsCK-0Cs.js +0 -1
- package/web-dist/assets/mermaid-parser.core-CHzoJ5LT.js +0 -7
- package/web-dist/assets/mermaid.core-Cl84DLN2.js +0 -11
- package/web-dist/assets/mindmap-definition-LN4V7U3C-C39sBNqB.js +0 -96
- package/web-dist/assets/ordinal-hYBb2elL.js +0 -1
- package/web-dist/assets/packet-7NZHBO7P-Bj73rlQn.js +0 -1
- package/web-dist/assets/path-BWPyau1x.js +0 -1
- package/web-dist/assets/pegDiagram-2B236MQR-BEEM1vSv.js +0 -1
- package/web-dist/assets/pie-RZYD4A2V-CJ-fEfdy.js +0 -1
- package/web-dist/assets/pieDiagram-ENE6RG2P-Dcqj3oyh.js +0 -39
- package/web-dist/assets/quadrantDiagram-ABIIQ3AL-D5cljQ3D.js +0 -7
- package/web-dist/assets/radar-I7S5WNFK-G8JqqGPf.js +0 -1
- package/web-dist/assets/railroad-3IZDKUUU-CaGNL0iN.js +0 -1
- package/web-dist/assets/railroad-abnf-AHOZXSZD-DWZmdy-r.js +0 -1
- package/web-dist/assets/railroad-ebnf-EBAXGLYW-C-XoPuo_.js +0 -1
- package/web-dist/assets/railroad-peg-LSFZ7HO6-BGpxqg46.js +0 -1
- package/web-dist/assets/railroadDiagram-RFXS5EU6-BZGZXMY4.js +0 -1
- package/web-dist/assets/requirementDiagram-TGXJPOKE-Dj5yn_9e.js +0 -84
- package/web-dist/assets/rolldown-runtime-Bh1tDfsg.js +0 -1
- package/web-dist/assets/rough.esm-CSKSodPl.js +0 -1
- package/web-dist/assets/sankeyDiagram-HTMAVEWB-7iJ_NDNf.js +0 -40
- package/web-dist/assets/sequenceDiagram-DBY2YBRQ-Bl54CknA.js +0 -162
- package/web-dist/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +0 -1
- package/web-dist/assets/src-C4XfhTaE.js +0 -1
- package/web-dist/assets/stateDiagram-2N3HPSRC-DuvjeNgJ.js +0 -1
- package/web-dist/assets/stateDiagram-v2-6OUMAXLB-BR-vrMgH.js +0 -1
- package/web-dist/assets/swimlanes-5IMT3BWC-B7-Jj4Sk.js +0 -2
- package/web-dist/assets/swimlanesDiagram-G3AALYLV-C1HvMf2k.js +0 -8
- package/web-dist/assets/timeline-definition-FHXFAJF6-jsey2pEG.js +0 -120
- package/web-dist/assets/treeView-QDETBFTQ-DhPmOzHr.js +0 -1
- package/web-dist/assets/treemap-6X3UGDF4-Dw2IaXqK.js +0 -1
- package/web-dist/assets/vennDiagram-L72KCM5P-CXKZkBab.js +0 -34
- package/web-dist/assets/wardley-OPB4EBWU-CTCdDwyE.js +0 -1
- package/web-dist/assets/wardleyDiagram-EHGQE667-B1w0xIqB.js +0 -78
- package/web-dist/assets/xychartDiagram-FW5EYKEG-gULk-uIl.js +0 -7
- package/web-dist/favicon-16.png +0 -0
- package/web-dist/favicon-32.png +0 -0
- package/web-dist/favicon.svg +0 -34
- package/web-dist/icon-192.png +0 -0
- package/web-dist/icon-512.png +0 -0
- package/web-dist/icon-maskable-512.png +0 -0
- package/web-dist/index.html +0 -44
- package/web-dist/manifest.webmanifest +0 -16
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
/**
|
|
3
|
-
* frizz — DERIVED agent state. The single shared derivation used by BOTH the Stop-hook
|
|
4
|
-
* liveness helper (`./agent-liveness.mjs`) and the board (`./index.mjs`), so an agent's
|
|
5
|
-
* reported state can never drift between the two.
|
|
6
|
-
*
|
|
7
|
-
* THE PRINCIPLE — compute, don't store (the same rule the board already follows for
|
|
8
|
-
* thread status). The thread↔agent binding (`.frizz/.agent-bindings.jsonl`, written
|
|
9
|
-
* AUTOMATICALLY by the agent-bind hook) records ONLY immutable-at-dispatch facts
|
|
10
|
-
* (`agentId → thread`, plus a label); it carries NO per-agent `status`. (The old
|
|
11
|
-
* hand-maintained `agents:` frontmatter is gone; a lingering one is an ignored no-op.)
|
|
12
|
-
* Every liveness/doneness judgement is DERIVED here from ground truth:
|
|
13
|
-
*
|
|
14
|
-
* - output-file (`tasks/<id>.output`) mtime → how long since the agent last wrote,
|
|
15
|
-
* - the THREAD's own `status:` (done/dismissed = terminal) → whether the orchestrator
|
|
16
|
-
* has deliberately reconciled the thread.
|
|
17
|
-
*
|
|
18
|
-
* There is NO durable per-agent COMPLETION signal: a rest (`.rested-agents.jsonl`) records
|
|
19
|
-
* an `agent_id` but a rest is NOT "done" (an agent rests repeatedly). So "done" is INFERRED
|
|
20
|
-
* (terminal-or-stale output + thread status), never read from a stored per-agent flag. That
|
|
21
|
-
* is exactly why the old hand-maintained `status` field drifted and false-flagged a
|
|
22
|
-
* completed agent as idle; deriving it makes that drift class structurally impossible.
|
|
23
|
-
*
|
|
24
|
-
* Derived states (one per dispatched agent — keyed on the thread's NEWEST agent only):
|
|
25
|
-
* - 'terminal' — nothing to flag, for ANY of: the THREAD is terminal (done/dismissed);
|
|
26
|
-
* the thread is PARKED (non-terminal but not `active`); or the thread is
|
|
27
|
-
* DOWNSTREAM (a PR is landing via the merge cascade, so it is
|
|
28
|
-
* legitimately active while it merges, not because an agent is stuck).
|
|
29
|
-
* - 'dropped' — the conservative, high-confidence "no live agent" signal: an `active`
|
|
30
|
-
* thread whose newest agent's output is stale beyond `droppedMin` AND
|
|
31
|
-
* which has rested at least once (ended a turn) — so it is quiet at a
|
|
32
|
-
* stopping point, not mid-tool-call. Likely finished-but-unreconciled or
|
|
33
|
-
* genuinely dropped. THE one signal that matters.
|
|
34
|
-
* - 'idle' — quiet, but NOT confidently dropped: output between `idleMin` and
|
|
35
|
-
* `droppedMin`, OR stale-but-never-rested (still inside one long tool
|
|
36
|
-
* call — a build/test — so alive). Informational only; say it softly.
|
|
37
|
-
* - 'fresh' — output recent (<=idleMin): actively working, say nothing.
|
|
38
|
-
* - 'unknown' — no readable output file (placeholder id, never-started): can't
|
|
39
|
-
* judge; fail-open (say nothing).
|
|
40
|
-
*
|
|
41
|
-
* WHY a generous `droppedMin` (45m, vs the old 25m). Sub-agents now legitimately arm CI
|
|
42
|
-
* watchers and go quiet for long stretches while CI runs (30–40m), so "no output for 25m" is
|
|
43
|
-
* NORMAL, not stuck — the old threshold cried wolf. 45m gives a watcher room to fire and
|
|
44
|
-
* resume the agent (which refreshes its output) before we ever call it dropped; the bar is
|
|
45
|
-
* deliberately "better to miss a soft case than nag a benign one."
|
|
46
|
-
*/
|
|
47
|
-
|
|
48
|
-
import { readdirSync, statSync } from 'node:fs';
|
|
49
|
-
import { join } from 'node:path';
|
|
50
|
-
|
|
51
|
-
export const DEFAULT_IDLE_MIN = 10;
|
|
52
|
-
export const DEFAULT_DROPPED_MIN = 45;
|
|
53
|
-
// Back-compat alias for the old name; repointed to the new, generous default.
|
|
54
|
-
export const DEFAULT_FROZEN_MIN = DEFAULT_DROPPED_MIN;
|
|
55
|
-
// The WATCHER/AGENT DROP-GUARD threshold (min): a dispatched agent that has RUN this long while
|
|
56
|
-
// still emitting output (looks alive) but has produced NO terminal thread result gets a LOUD
|
|
57
|
-
// "verify directly" flag — the #327 forcing function (a `ci-watch` hung on a nameless ghost check
|
|
58
|
-
// polls forever and looks alive while stranded; "watcher running = fine" then gets trusted). This
|
|
59
|
-
// is DISTINCT from DROPPED_MIN (stale + rested = went quiet): the drop-guard targets the
|
|
60
|
-
// looks-alive-but-maybe-hung band. Measured from the binding `ts` (dispatch time), not output age.
|
|
61
|
-
export const DEFAULT_LONG_RUNTIME_MIN = 35;
|
|
62
|
-
|
|
63
|
-
// Env-resolved thresholds, defined ONCE here so EVERY consumer (the Stop-hook liveness helper
|
|
64
|
-
// AND the board) reads the same knobs and can never disagree. FRIZZ_FROZEN_MIN is honored as the
|
|
65
|
-
// old alias for FRIZZ_DROPPED_MIN.
|
|
66
|
-
export const IDLE_MIN = parseInt(process.env.FRIZZ_IDLE_MIN || '', 10) || DEFAULT_IDLE_MIN;
|
|
67
|
-
export const DROPPED_MIN = parseInt(process.env.FRIZZ_DROPPED_MIN || process.env.FRIZZ_FROZEN_MIN || '', 10) || DEFAULT_DROPPED_MIN;
|
|
68
|
-
export const LONG_RUNTIME_MIN = parseInt(process.env.FRIZZ_LONG_RUNTIME_MIN || '', 10) || DEFAULT_LONG_RUNTIME_MIN;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* GROUND-TRUTH age of an agent's last activity, in minutes — globbed across ALL local
|
|
72
|
-
* Claude task dirs (`<tmp>/claude-<uid>/<project>/<session>/tasks/<id>.output`). Unlike
|
|
73
|
-
* the Stop hook's `deriveTasksDir` (which has the transcript_path and so knows the exact
|
|
74
|
-
* session), the BOARD runs standalone with no session id, so it must search every session
|
|
75
|
-
* for the agent's output symlink. `statSync` follows the symlink → the TARGET transcript's
|
|
76
|
-
* real last-write (the symlink's own mtime is stale). Returns the freshest match's age, or
|
|
77
|
-
* null when no output file exists (placeholder id / never-started / different machine).
|
|
78
|
-
* Fail-open: any error → null.
|
|
79
|
-
* @param {string} agentId
|
|
80
|
-
* @param {number} [now]
|
|
81
|
-
* @returns {number|null} minutes since last activity, or null
|
|
82
|
-
*/
|
|
83
|
-
export function findAgentOutputAge(agentId, now = Date.now()) {
|
|
84
|
-
if (!agentId) return null;
|
|
85
|
-
let best = null; // most-recent mtimeMs found
|
|
86
|
-
try {
|
|
87
|
-
for (const base of ['/tmp', '/private/tmp']) {
|
|
88
|
-
let claudeDirs;
|
|
89
|
-
try {
|
|
90
|
-
claudeDirs = readdirSync(base).filter((d) => d.startsWith('claude-'));
|
|
91
|
-
} catch {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
for (const cd of claudeDirs) {
|
|
95
|
-
const root = join(base, cd);
|
|
96
|
-
let projects;
|
|
97
|
-
try {
|
|
98
|
-
projects = readdirSync(root);
|
|
99
|
-
} catch {
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
for (const proj of projects) {
|
|
103
|
-
let sessions;
|
|
104
|
-
try {
|
|
105
|
-
sessions = readdirSync(join(root, proj));
|
|
106
|
-
} catch {
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
for (const sess of sessions) {
|
|
110
|
-
try {
|
|
111
|
-
const st = statSync(join(root, proj, sess, 'tasks', `${agentId}.output`));
|
|
112
|
-
if (best == null || st.mtimeMs > best) best = st.mtimeMs;
|
|
113
|
-
} catch {
|
|
114
|
-
/* not in this session */
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
} catch {
|
|
121
|
-
/* fail-open */
|
|
122
|
-
}
|
|
123
|
-
return best == null ? null : (now - best) / 60000;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Derive one agent's state PURELY from ground truth. No per-agent stored status is
|
|
128
|
-
* consulted — `ageMin` comes from the output-file mtime and `threadTerminal` from the
|
|
129
|
-
* thread's own `status:` frontmatter.
|
|
130
|
-
*
|
|
131
|
-
* @param {object} a
|
|
132
|
-
* @param {number|null} a.ageMin minutes since the agent's output last changed, or
|
|
133
|
-
* null when there is no readable output file.
|
|
134
|
-
* @param {boolean} a.threadTerminal is the owning thread's status done/dismissed?
|
|
135
|
-
* @param {boolean} [a.threadActive] is the owning thread's status exactly `active`? Only
|
|
136
|
-
* `active` threads are "being worked" by an agent, so
|
|
137
|
-
* only they can have an UNRECONCILED/idle agent. Other
|
|
138
|
-
* non-terminal phases (planning/planned/blocked)
|
|
139
|
-
* with a done/absent agent are EXPECTED, not a drift
|
|
140
|
-
* signal — never flagged. NOTE `planning` is human-or-
|
|
141
|
-
* architect-driven design and may legitimately have NO
|
|
142
|
-
* live agent, so it is deliberately NOT `active` here and
|
|
143
|
-
* never triggers the no-live-agent warning. (Defaults
|
|
144
|
-
* true for backward-compat when a caller doesn't pass it.)
|
|
145
|
-
* @param {boolean} [a.threadDownstream] does the thread have a PR landing via the merge
|
|
146
|
-
* cascade (`.frizz/merge-queue.jsonl`)? Such a thread is
|
|
147
|
-
* legitimately `active` while it merges — the producing
|
|
148
|
-
* agent has finished and reconciled — so it is never a
|
|
149
|
-
* drop. (Defaults false.)
|
|
150
|
-
* @param {boolean} [a.hasRested] has the agent recorded at least one rest (ended a
|
|
151
|
-
* turn)? Stale output + NO rest = still inside one long
|
|
152
|
-
* tool call (a build/test) → ALIVE, never 'dropped'.
|
|
153
|
-
* (Defaults true for back-compat with callers that don't
|
|
154
|
-
* supply it.)
|
|
155
|
-
* @param {number} [a.idleMin] idle threshold (min). Default {@link DEFAULT_IDLE_MIN}.
|
|
156
|
-
* @param {number} [a.droppedMin] dropped/stale threshold (min). Default {@link DEFAULT_DROPPED_MIN}.
|
|
157
|
-
* @param {number} [a.frozenMin] DEPRECATED alias for `droppedMin` (old callers).
|
|
158
|
-
* @returns {'terminal'|'dropped'|'idle'|'fresh'|'unknown'}
|
|
159
|
-
*/
|
|
160
|
-
export function deriveAgentState({ ageMin, threadTerminal, threadActive = true, threadDownstream = false, hasRested = true, idleMin = DEFAULT_IDLE_MIN, droppedMin = DEFAULT_DROPPED_MIN, frozenMin }) {
|
|
161
|
-
if (frozenMin != null) droppedMin = frozenMin; // back-compat: old callers passed frozenMin
|
|
162
|
-
// A reconciled thread is the orchestrator's deliberate "I folded this" signal — the
|
|
163
|
-
// only mutable bit in the whole loop, and it lives on the THREAD, not the agent.
|
|
164
|
-
if (threadTerminal) return 'terminal';
|
|
165
|
-
// A non-`active` non-terminal phase (planning/planned/blocked) is also a
|
|
166
|
-
// deliberate orchestrator state — a stale/done/absent agent on such a thread is EXPECTED
|
|
167
|
-
// (the work finished, the thread awaits a human/dep, or `planning` is human-driven with no
|
|
168
|
-
// agent at all), NOT a drop. Only an `active` thread is "being worked right now" by an
|
|
169
|
-
// agent, so only it can have a drift-signal agent.
|
|
170
|
-
if (!threadActive) return 'terminal';
|
|
171
|
-
// DOWNSTREAM: a PR is landing for this thread via the cascade — it is active for the
|
|
172
|
-
// merge, not a stuck agent. The producing agent has finished + been reconciled; suppress.
|
|
173
|
-
if (threadDownstream) return 'terminal';
|
|
174
|
-
if (ageMin == null) return 'unknown'; // no activity file → can't judge (fail-open)
|
|
175
|
-
if (ageMin > droppedMin) return hasRested ? 'dropped' : 'idle'; // stale + rested = quiet at a stopping point (the signal); stale + never-rested = still in one long tool call → alive
|
|
176
|
-
if (ageMin > idleMin) return 'idle';
|
|
177
|
-
return 'fresh';
|
|
178
|
-
}
|