@mjasnikovs/pi-task 0.38.22 → 0.38.24

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.
Files changed (42) hide show
  1. package/README.md +2 -2
  2. package/dist/config/reasoning-args.d.ts +12 -1
  3. package/dist/config/reasoning-args.js +5 -2
  4. package/dist/config/reasoning.d.ts +60 -2
  5. package/dist/config/reasoning.js +344 -37
  6. package/dist/config/register.d.ts +76 -32
  7. package/dist/config/register.js +124 -82
  8. package/dist/shared/reasoning-capability.d.ts +2 -5
  9. package/dist/shared/reasoning-capability.js +31 -4
  10. package/dist/task/auto-orchestrator.d.ts +2 -0
  11. package/dist/task/auto-orchestrator.js +28 -41
  12. package/dist/task/child-runner.d.ts +89 -24
  13. package/dist/task/child-runner.js +67 -46
  14. package/dist/task/orchestrator.d.ts +14 -20
  15. package/dist/task/orchestrator.js +12 -9
  16. package/dist/task/phases.d.ts +16 -23
  17. package/dist/task/phases.js +47 -452
  18. package/dist/task/question-dialog.d.ts +56 -0
  19. package/dist/task/question-dialog.js +53 -0
  20. package/dist/task/research-worker.d.ts +180 -0
  21. package/dist/task/research-worker.js +432 -0
  22. package/dist/workers/brave-warning.js +4 -30
  23. package/dist/workers/docs-core.d.ts +8 -4
  24. package/dist/workers/docs-core.js +30 -21
  25. package/dist/workers/docs-lookup.d.ts +72 -0
  26. package/dist/workers/docs-lookup.js +53 -0
  27. package/dist/workers/docs-project.d.ts +9 -0
  28. package/dist/workers/docs-project.js +15 -0
  29. package/dist/workers/pi-worker-core.d.ts +87 -1
  30. package/dist/workers/pi-worker-core.js +3 -7
  31. package/dist/workers/pi-worker-docs.js +27 -31
  32. package/dist/workers/reasoning-warning.d.ts +10 -16
  33. package/dist/workers/reasoning-warning.js +25 -57
  34. package/dist/workers/session-hint.d.ts +37 -0
  35. package/dist/workers/session-hint.js +82 -0
  36. package/dist/workers/worker-failure.d.ts +34 -0
  37. package/dist/workers/worker-failure.js +27 -16
  38. package/dist/workers/worker-kill.d.ts +84 -0
  39. package/dist/workers/worker-kill.js +124 -0
  40. package/package.json +1 -1
  41. package/dist/task/reasoning-groups.d.ts +0 -36
  42. package/dist/task/reasoning-groups.js +0 -36
@@ -0,0 +1,82 @@
1
+ /**
2
+ * A one-line startup hint in the TUI, and the whole widget lifetime around it.
3
+ *
4
+ * WHY IT IS ONE MODULE. Two hints exist (brave-warning, reasoning-warning) and
5
+ * both had written the same ritual out: the `session_start` subscription, the
6
+ * TUI gate, the `setWidget` in a try/catch, the `onTerminalInput` that clears on
7
+ * the first keystroke, the unsubscribe, and the swallow for a stale ctx — down
8
+ * to a byte-identical comment. Two adapters is a real seam, so the ritual lives
9
+ * here once and each hint supplies only its `compose`.
10
+ *
11
+ * The REFINE half is why this is not just deduplication. A hint may learn
12
+ * something after it has painted (the reasoning hint probes the model's server),
13
+ * and the rule that a refinement must never repaint a widget the user already
14
+ * dismissed lived in one closure variable in one of the two files. It is now a
15
+ * property of this module, asserted once.
16
+ */
17
+ /**
18
+ * Register one startup hint.
19
+ *
20
+ * `compose` is the seam: it runs at `session_start` inside the TUI gate and
21
+ * returns the hint, or null to say nothing at all. Everything it returns is
22
+ * text; nothing about widgets, keystrokes or teardown reaches it.
23
+ */
24
+ export function registerSessionHint(pi, key, compose) {
25
+ pi.on('session_start', (_event, ctx) => {
26
+ // Terminal-only hint: needs an interactive TUI to render and to catch the
27
+ // keystroke that dismisses it.
28
+ if (ctx.mode !== 'tui')
29
+ return;
30
+ const hint = compose(ctx);
31
+ if (hint === null)
32
+ return;
33
+ let unsubscribe = null;
34
+ let cleared = false;
35
+ let painted = false;
36
+ const clear = () => {
37
+ cleared = true;
38
+ try {
39
+ ctx.ui.setWidget(key, undefined);
40
+ }
41
+ catch {
42
+ /* stale ctx after a session switch — nothing to clear */
43
+ }
44
+ unsubscribe?.();
45
+ unsubscribe = null;
46
+ };
47
+ const render = (text) => {
48
+ try {
49
+ ctx.ui.setWidget(key, [ctx.ui.theme.fg('warning', text)]);
50
+ return true;
51
+ }
52
+ catch {
53
+ return false;
54
+ }
55
+ };
56
+ // Handled BEFORE the paint can bail. `compose` builds this promise
57
+ // eagerly — the reasoning hint kicks its probe off inside it — so a
58
+ // rejection with the handler attached later is an unhandled rejection on
59
+ // exactly the path the try/catch around `setWidget` exists for: a stale
60
+ // ctx after a session switch. `refine`'s contract says a rejection leaves
61
+ // the first line standing, and that has to hold when there is no first
62
+ // line either.
63
+ if (hint.refine !== undefined) {
64
+ void hint.refine
65
+ .then(text => {
66
+ if (cleared || !painted || text === null)
67
+ return;
68
+ render(text);
69
+ })
70
+ .catch(() => { });
71
+ }
72
+ painted = render(hint.text);
73
+ if (!painted)
74
+ return;
75
+ // Disappear on any interaction — the first raw keystroke clears it.
76
+ // Returning undefined leaves the input untouched (we only observe it).
77
+ unsubscribe = ctx.ui.onTerminalInput(() => {
78
+ clear();
79
+ return undefined;
80
+ });
81
+ });
82
+ }
@@ -26,6 +26,7 @@
26
26
  * caused the bug impossible rather than merely fixed.
27
27
  */
28
28
  import type { LoopHit } from '../task/loop-detector.js';
29
+ import type { WorkerKillId } from './worker-kill.js';
29
30
  /**
30
31
  * The subset of a finished child result this classification reads.
31
32
  *
@@ -83,6 +84,39 @@ export type WorkerFailure = {
83
84
  };
84
85
  /** The `kind` of every row, for exhaustiveness checks in consumers. */
85
86
  export type WorkerFailureKind = WorkerFailure['kind'];
87
+ /**
88
+ * The ordered ladder. FIRST MATCH WINS — row order IS the precedence, and it is
89
+ * the only statement of it in the codebase.
90
+ *
91
+ * The order, and why:
92
+ *
93
+ * 1. `stalled` — no output AND the model endpoint did not answer a probe. The
94
+ * most specific diagnosis there is, and the one most easily lost: the kill
95
+ * aborts, so anything checked after `aborted` never sees it.
96
+ * 2. `command-timeout` — a watchdog kill naming the tool call that hung. Also
97
+ * aborts. Before the wall-clock timeout because it is the narrower cause
98
+ * (the two cannot be confused: a watchdog kill leaves the worker's own
99
+ * timeout flag false).
100
+ * 3. `stream-stall` — a watchdog kill for a model stream that went silent while
101
+ * no tool was running. Sits next to `command-timeout` because it is the same
102
+ * class of event: a watchdog, not the model, ended the attempt.
103
+ * 4. `worker-timeout` — the wall-clock backstop.
104
+ * 5. `loop` — killed for repeating one tool call past threshold. After the
105
+ * timeouts, matching the enforce ladder this replaces; in practice the two
106
+ * cannot both fire, since a loop kill stops the attempt before its own timer
107
+ * can expire.
108
+ * 6. `leaked-tool-call` — the model wrote a call as prose instead of invoking
109
+ * it. Only ever set on an otherwise clean run.
110
+ * 7. `aborted` — no specific cause survived, so this really is a cancel.
111
+ * 8. `exit` — a plain non-zero exit with no kill behind it: a crash.
112
+ */
113
+ export declare const FAILURE_RULES: ReadonlyArray<{
114
+ /** The roster id this row matches. `worker-kill.test.ts` checks the sequence
115
+ * against `FAILURE_ORDER`, so a reordering or an omission is a test failure
116
+ * rather than a silently different precedence. */
117
+ id: WorkerKillId;
118
+ match: (r: WorkerFailureInput) => WorkerFailure | null;
119
+ }>;
86
120
  /**
87
121
  * Classify a finished child. Returns `undefined` when nothing killed it —
88
122
  * which is not the same as "it answered": the text may still be empty, and that
@@ -25,6 +25,8 @@
25
25
  * in every consumer that has not handled it — which is what makes the drift that
26
26
  * caused the bug impossible rather than merely fixed.
27
27
  */
28
+ const _kindsAreKills = true;
29
+ void _kindsAreKills;
28
30
  /**
29
31
  * The ordered ladder. FIRST MATCH WINS — row order IS the precedence, and it is
30
32
  * the only statement of it in the codebase.
@@ -51,21 +53,30 @@
51
53
  * 7. `aborted` — no specific cause survived, so this really is a cancel.
52
54
  * 8. `exit` — a plain non-zero exit with no kill behind it: a crash.
53
55
  */
54
- const FAILURE_RULES = [
55
- r => (r.stalled === true ? { kind: 'stalled' } : null),
56
- r => r.commandTimedOut ?
57
- {
58
- kind: 'command-timeout',
59
- toolName: r.commandTimedOut.toolName,
60
- timeoutMs: r.commandTimedOut.timeoutMs
61
- }
62
- : null,
63
- r => (r.streamStalled ? { kind: 'stream-stall', idleMs: r.streamStalled.idleMs } : null),
64
- r => (r.timedOut === true ? { kind: 'worker-timeout' } : null),
65
- r => (r.loopHit ? { kind: 'loop', hit: r.loopHit } : null),
66
- r => (r.leakedToolCall ? { kind: 'leaked-tool-call', text: String(r.leakedToolCall) } : null),
67
- r => (r.aborted ? { kind: 'aborted' } : null),
68
- r => (r.exitCode !== 0 ? { kind: 'exit', code: r.exitCode } : null)
56
+ export const FAILURE_RULES = [
57
+ { id: 'stalled', match: r => (r.stalled === true ? { kind: 'stalled' } : null) },
58
+ {
59
+ id: 'command-timeout',
60
+ match: r => r.commandTimedOut ?
61
+ {
62
+ kind: 'command-timeout',
63
+ toolName: r.commandTimedOut.toolName,
64
+ timeoutMs: r.commandTimedOut.timeoutMs
65
+ }
66
+ : null
67
+ },
68
+ {
69
+ id: 'stream-stall',
70
+ match: r => r.streamStalled ? { kind: 'stream-stall', idleMs: r.streamStalled.idleMs } : null
71
+ },
72
+ { id: 'worker-timeout', match: r => (r.timedOut === true ? { kind: 'worker-timeout' } : null) },
73
+ { id: 'loop', match: r => (r.loopHit ? { kind: 'loop', hit: r.loopHit } : null) },
74
+ {
75
+ id: 'leaked-tool-call',
76
+ match: r => r.leakedToolCall ? { kind: 'leaked-tool-call', text: String(r.leakedToolCall) } : null
77
+ },
78
+ { id: 'aborted', match: r => (r.aborted ? { kind: 'aborted' } : null) },
79
+ { id: 'exit', match: r => (r.exitCode !== 0 ? { kind: 'exit', code: r.exitCode } : null) }
69
80
  ];
70
81
  /**
71
82
  * Classify a finished child. Returns `undefined` when nothing killed it —
@@ -74,7 +85,7 @@ const FAILURE_RULES = [
74
85
  */
75
86
  export function classifyWorkerFailure(r) {
76
87
  for (const rule of FAILURE_RULES) {
77
- const hit = rule(r);
88
+ const hit = rule.match(r);
78
89
  if (hit)
79
90
  return hit;
80
91
  }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * The ROSTER of ways a worker child can die, and what each one implies.
3
+ *
4
+ * WHY IT EXISTS. One kill cause was named in six unlinked places: a
5
+ * `RunWorkerInput` guard option, a `RunWorkerResult` field, the
6
+ * `WorkerRestartReason` union, a `RESTART_RULES` row, the `CARRY_FORWARD_REASONS`
7
+ * set, and a `FAILURE_RULES` row. Adding one meant six coordinated edits, and
8
+ * only two of them failed to compile if you skipped one. That is not
9
+ * hypothetical: `worker-failure.ts`'s own header records the bug it cost —
10
+ * *"`streamStalled` was added to the result and to `finalAttemptFailed`, but the
11
+ * enforce ladder never grew an arm for it, so an enforcement child killed for a
12
+ * hung model stream fell all the way through to `if (aborted) return
13
+ * USER_CANCELLED`"*. That fix closed the READER side. This closes the author
14
+ * side.
15
+ *
16
+ * WHAT IS AND IS NOT UNIFIED. The roster is one table. The two ORDERINGS stay
17
+ * two, because they genuinely disagree and each says so in its own prose: the
18
+ * restart ladder puts `loop` first (its hint is the most specific thing to tell a
19
+ * re-spawn), and the failure ladder puts `stalled` first (the diagnosis most
20
+ * easily lost behind the `aborted` every kill path sets). Folding two
21
+ * precedences into one row type would need an escape hatch per row — the same
22
+ * objection that got a `WriteGuard` row table rejected. What the orderings gain
23
+ * here is that neither can name a cause with no row, nor silently omit one.
24
+ *
25
+ * Not every cause appears in both ladders, and that asymmetry is real:
26
+ * `connection-error` is restartable but is reported as a `modelError`, never as a
27
+ * kill; `stalled`, `aborted` and `exit` end an attempt outright and no hint would
28
+ * help.
29
+ */
30
+ /** Every way a worker attempt can end other than by answering. */
31
+ export type WorkerKillId = 'stalled' | 'command-timeout' | 'stream-stall' | 'worker-timeout' | 'connection-error' | 'loop' | 'leaked-tool-call' | 'aborted' | 'exit';
32
+ export interface WorkerKill {
33
+ id: WorkerKillId;
34
+ /**
35
+ * The `RunWorkerResult` field that reports this cause on the FINAL attempt,
36
+ * or null when the cause never reaches the result under its own name
37
+ * (`connection-error` arrives as `modelError`; `aborted` and `exit` are the
38
+ * generic fields every kill path also sets).
39
+ *
40
+ * A string rather than `keyof RunWorkerResult` so this module stays free of
41
+ * pi-worker-core's import graph; `worker-kill.test.ts` checks it against the
42
+ * real interface.
43
+ */
44
+ resultField: string | null;
45
+ /**
46
+ * Is a killed attempt's partial output worth carrying into the next one?
47
+ *
48
+ * A clock kill, a hung tool, an idle stream and a dropped socket all discard
49
+ * work the model genuinely did. A loop kill and a leaked tool call do not —
50
+ * the first is by definition the same call repeated, the second is malformed
51
+ * protocol text, and replaying either would feed the failure back to itself.
52
+ */
53
+ carryForward: boolean;
54
+ /** Does the restart ladder have a rule for this cause? */
55
+ restartable: boolean;
56
+ /** Does this cause reach a consumer as a `WorkerFailure`? */
57
+ reported: boolean;
58
+ }
59
+ export declare const WORKER_KILLS: readonly WorkerKill[];
60
+ /** Look one cause up. `undefined` only for an id with no row, which the suite forbids. */
61
+ export declare function workerKill(id: WorkerKillId): WorkerKill | undefined;
62
+ /**
63
+ * The restart ladder's precedence, as ids. `RESTART_RULES` must be exactly this,
64
+ * in this order.
65
+ *
66
+ * `loop` leads: its hint names the offending call, which is the most useful thing
67
+ * to tell a re-spawn. The two watchdogs come before the wall clock because each
68
+ * is the narrower diagnosis, and they cannot be confused with it — a watchdog
69
+ * kill leaves the worker's own timeout flag false.
70
+ */
71
+ export declare const RESTART_ORDER: readonly ["loop", "command-timeout", "stream-stall", "worker-timeout", "connection-error", "leaked-tool-call"];
72
+ /**
73
+ * The failure ladder's precedence, as ids. `FAILURE_RULES` must be exactly this,
74
+ * in this order.
75
+ *
76
+ * DIFFERENT from `RESTART_ORDER`, deliberately. Every kill path also sets
77
+ * `aborted` and a non-zero exit, so the specific causes must all be matched
78
+ * before the two generic ones or a dead backend is reported as "you cancelled".
79
+ * `stalled` leads because it is both the most specific diagnosis and the one most
80
+ * easily lost.
81
+ */
82
+ export declare const FAILURE_ORDER: readonly ["stalled", "command-timeout", "stream-stall", "worker-timeout", "loop", "leaked-tool-call", "aborted", "exit"];
83
+ /** The causes whose partial output is worth keeping. Derived, never hand-kept. */
84
+ export declare const CARRY_FORWARD_IDS: ReadonlySet<WorkerKillId>;
@@ -0,0 +1,124 @@
1
+ /**
2
+ * The ROSTER of ways a worker child can die, and what each one implies.
3
+ *
4
+ * WHY IT EXISTS. One kill cause was named in six unlinked places: a
5
+ * `RunWorkerInput` guard option, a `RunWorkerResult` field, the
6
+ * `WorkerRestartReason` union, a `RESTART_RULES` row, the `CARRY_FORWARD_REASONS`
7
+ * set, and a `FAILURE_RULES` row. Adding one meant six coordinated edits, and
8
+ * only two of them failed to compile if you skipped one. That is not
9
+ * hypothetical: `worker-failure.ts`'s own header records the bug it cost —
10
+ * *"`streamStalled` was added to the result and to `finalAttemptFailed`, but the
11
+ * enforce ladder never grew an arm for it, so an enforcement child killed for a
12
+ * hung model stream fell all the way through to `if (aborted) return
13
+ * USER_CANCELLED`"*. That fix closed the READER side. This closes the author
14
+ * side.
15
+ *
16
+ * WHAT IS AND IS NOT UNIFIED. The roster is one table. The two ORDERINGS stay
17
+ * two, because they genuinely disagree and each says so in its own prose: the
18
+ * restart ladder puts `loop` first (its hint is the most specific thing to tell a
19
+ * re-spawn), and the failure ladder puts `stalled` first (the diagnosis most
20
+ * easily lost behind the `aborted` every kill path sets). Folding two
21
+ * precedences into one row type would need an escape hatch per row — the same
22
+ * objection that got a `WriteGuard` row table rejected. What the orderings gain
23
+ * here is that neither can name a cause with no row, nor silently omit one.
24
+ *
25
+ * Not every cause appears in both ladders, and that asymmetry is real:
26
+ * `connection-error` is restartable but is reported as a `modelError`, never as a
27
+ * kill; `stalled`, `aborted` and `exit` end an attempt outright and no hint would
28
+ * help.
29
+ */
30
+ export const WORKER_KILLS = [
31
+ {
32
+ id: 'stalled',
33
+ resultField: 'stalled',
34
+ carryForward: false,
35
+ restartable: false,
36
+ reported: true
37
+ },
38
+ {
39
+ id: 'command-timeout',
40
+ resultField: 'commandTimedOut',
41
+ carryForward: true,
42
+ restartable: true,
43
+ reported: true
44
+ },
45
+ {
46
+ id: 'stream-stall',
47
+ resultField: 'streamStalled',
48
+ carryForward: true,
49
+ restartable: true,
50
+ reported: true
51
+ },
52
+ {
53
+ id: 'worker-timeout',
54
+ resultField: 'timedOut',
55
+ carryForward: true,
56
+ restartable: true,
57
+ reported: true
58
+ },
59
+ {
60
+ id: 'connection-error',
61
+ resultField: null,
62
+ carryForward: true,
63
+ restartable: true,
64
+ reported: false
65
+ },
66
+ { id: 'loop', resultField: 'loopHit', carryForward: false, restartable: true, reported: true },
67
+ {
68
+ id: 'leaked-tool-call',
69
+ resultField: 'leakedToolCall',
70
+ carryForward: false,
71
+ restartable: true,
72
+ reported: true
73
+ },
74
+ { id: 'aborted', resultField: null, carryForward: false, restartable: false, reported: true },
75
+ { id: 'exit', resultField: null, carryForward: false, restartable: false, reported: true }
76
+ ];
77
+ /** Look one cause up. `undefined` only for an id with no row, which the suite forbids. */
78
+ export function workerKill(id) {
79
+ return WORKER_KILLS.find(k => k.id === id);
80
+ }
81
+ /**
82
+ * The restart ladder's precedence, as ids. `RESTART_RULES` must be exactly this,
83
+ * in this order.
84
+ *
85
+ * `loop` leads: its hint names the offending call, which is the most useful thing
86
+ * to tell a re-spawn. The two watchdogs come before the wall clock because each
87
+ * is the narrower diagnosis, and they cannot be confused with it — a watchdog
88
+ * kill leaves the worker's own timeout flag false.
89
+ */
90
+ export const RESTART_ORDER = [
91
+ 'loop',
92
+ 'command-timeout',
93
+ 'stream-stall',
94
+ 'worker-timeout',
95
+ 'connection-error',
96
+ 'leaked-tool-call'
97
+ // `as const satisfies`, not an annotation: `WorkerRestartReason` is
98
+ // `(typeof RESTART_ORDER)[number]`, and a `readonly WorkerKillId[]`
99
+ // annotation collapses that to the whole `WorkerKillId` union — which would
100
+ // let `noteRestart('aborted')` compile for a cause the restart ladder has no
101
+ // rule for. `satisfies` keeps the membership check without the widening.
102
+ ];
103
+ /**
104
+ * The failure ladder's precedence, as ids. `FAILURE_RULES` must be exactly this,
105
+ * in this order.
106
+ *
107
+ * DIFFERENT from `RESTART_ORDER`, deliberately. Every kill path also sets
108
+ * `aborted` and a non-zero exit, so the specific causes must all be matched
109
+ * before the two generic ones or a dead backend is reported as "you cancelled".
110
+ * `stalled` leads because it is both the most specific diagnosis and the one most
111
+ * easily lost.
112
+ */
113
+ export const FAILURE_ORDER = [
114
+ 'stalled',
115
+ 'command-timeout',
116
+ 'stream-stall',
117
+ 'worker-timeout',
118
+ 'loop',
119
+ 'leaked-tool-call',
120
+ 'aborted',
121
+ 'exit'
122
+ ];
123
+ /** The causes whose partial output is worth keeping. Derived, never hand-kept. */
124
+ export const CARRY_FORWARD_IDS = new Set(WORKER_KILLS.filter(k => k.carryForward).map(k => k.id));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mjasnikovs/pi-task",
3
- "version": "0.38.22",
3
+ "version": "0.38.24",
4
4
  "description": "Deterministic task planning and spec-orchestration for local models — crash-safe /task pipelines with verify/enforce gates, a real-time remote web view, and web/docs/fetch/worker subagent tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,36 +0,0 @@
1
- /**
2
- * Child NAME → reasoning group, for every child that goes through
3
- * `runPhaseChild` / `runPlanningChild`.
4
- *
5
- * WHY KEYED ON THE NAME
6
- * ---------------------
7
- * The name is the only identifier in scope at all three spawn paths (phases,
8
- * /task-auto planning, /task-plan), it is what the loader and the debug trail
9
- * already print, and it is the one thing a reader can check against the phase
10
- * list without following the call graph. Threading a group parameter through
11
- * `PhaseDeps` / `AutoDeps` instead would touch both orchestrators' dep bags to
12
- * express something the call site already says out loud.
13
- *
14
- * AN UNMAPPED NAME IS A BUILD FAILURE, not a silent `inherit`.
15
- * `reasoning-groups.test.ts` scans every literal child name in src/ and fails if
16
- * it is missing here. A defaulting lookup would let a phase added next year opt
17
- * itself out of a measured setting without anyone deciding to — which is exactly
18
- * how `/no_think` ended up applied to eight prompts and read by none of them.
19
- *
20
- * The gate, research and extraction groups are NOT here: those children reach the
21
- * model through `runWorker` / `focusedChildArgs`, where the group is a property
22
- * of the call site rather than of a name, and is passed directly.
23
- */
24
- import type { ReasoningGroup } from '../config/reasoning.js';
25
- export declare const REASONING_GROUP_BY_CHILD: Readonly<Record<string, ReasoningGroup>>;
26
- /**
27
- * The group a named child belongs to.
28
- *
29
- * Returns `undefined` for a name the table does not know, and the CALLER decides
30
- * what that means. `runPhaseChild` treats it as `inherit` — a child that reaches
31
- * the model with today's argv is always safe — while the test treats it as a
32
- * failure. That split is deliberate: the guard belongs at build time, where
33
- * someone can fix it, not at run time, where it would abort a user's task over a
34
- * missing table row.
35
- */
36
- export declare function reasoningGroupForChild(name: string): ReasoningGroup | undefined;
@@ -1,36 +0,0 @@
1
- export const REASONING_GROUP_BY_CHILD = {
2
- // ── phase: task/phases.ts + task/title-label.ts ──────────────────────────
3
- refine: 'phase',
4
- 'verify-tooling': 'phase',
5
- 'grill-auto': 'phase',
6
- 'grill-gen': 'phase',
7
- compose: 'phase',
8
- critique: 'phase',
9
- 'critique-triage': 'phase',
10
- 'compress-label': 'phase',
11
- // ── planning: task/auto-orchestrator.ts ──────────────────────────────────
12
- 'clarify-triage': 'planning',
13
- 'auto-clarify': 'planning',
14
- 'auto-decompose': 'planning',
15
- 'requirement-extract': 'planning',
16
- 'decompose-coverage': 'planning',
17
- 'coverage-map': 'planning',
18
- 'contract-extract': 'planning',
19
- 'launch-extract': 'planning',
20
- // ── plan: task/plan-orchestrator.ts ──────────────────────────────────────
21
- 'plan-question': 'plan',
22
- 'plan-answer': 'plan'
23
- };
24
- /**
25
- * The group a named child belongs to.
26
- *
27
- * Returns `undefined` for a name the table does not know, and the CALLER decides
28
- * what that means. `runPhaseChild` treats it as `inherit` — a child that reaches
29
- * the model with today's argv is always safe — while the test treats it as a
30
- * failure. That split is deliberate: the guard belongs at build time, where
31
- * someone can fix it, not at run time, where it would abort a user's task over a
32
- * missing table row.
33
- */
34
- export function reasoningGroupForChild(name) {
35
- return REASONING_GROUP_BY_CHILD[name];
36
- }