@buildaharness/aielia 0.3.3 → 0.3.5

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 (111) hide show
  1. package/README.md +63 -20
  2. package/dist/PlanGraphPane.d.ts +19 -0
  3. package/dist/_memory-core-generated.d.ts +1764 -0
  4. package/dist/agent-loop.d.ts +31 -8
  5. package/dist/ambiguity-guard-flag.d.ts +12 -0
  6. package/dist/ambiguity-guard.d.ts +20 -0
  7. package/dist/answer-claim.d.ts +13 -1
  8. package/dist/ask-clarification-service.d.ts +12 -1
  9. package/dist/ask-response-format.d.ts +6 -0
  10. package/dist/assistant-session.d.ts +16 -5
  11. package/dist/assistant-source.d.ts +7 -0
  12. package/dist/assistant-types.d.ts +25 -1
  13. package/dist/assistant.d.ts +166 -5
  14. package/dist/benchmark-injected-failure.d.ts +6 -0
  15. package/dist/bin-CjKpxDxl.js +4836 -0
  16. package/dist/bin-CjKpxDxl.js.map +1 -0
  17. package/dist/cli-session.d.ts +26 -1
  18. package/dist/cli.d.ts +20 -2
  19. package/dist/cli.js +1 -1
  20. package/dist/code-plan-templates.d.ts +21 -0
  21. package/dist/config.d.ts +51 -0
  22. package/dist/constraint-check.d.ts +35 -0
  23. package/dist/contradiction-checker.d.ts +7 -0
  24. package/dist/decomposed-answer.d.ts +13 -0
  25. package/dist/decomposition-classifier.d.ts +2 -0
  26. package/dist/doctor-checks.d.ts +3 -0
  27. package/dist/episodic-digest.d.ts +89 -0
  28. package/dist/fact-extraction.d.ts +39 -0
  29. package/dist/file-tools-mcp-server.mjs +138 -12
  30. package/dist/file-tools.d.ts +4 -0
  31. package/dist/first-run.d.ts +3 -2
  32. package/dist/goal-graph-flag.d.ts +44 -0
  33. package/dist/goal-graph-reconcile.d.ts +55 -0
  34. package/dist/goal-graph-service.d.ts +48 -0
  35. package/dist/goal-graph-store.d.ts +485 -0
  36. package/dist/goal-graph-suggest-flag.d.ts +34 -0
  37. package/dist/goal-identity-matcher.d.ts +21 -0
  38. package/dist/goal-thread-identity.d.ts +32 -0
  39. package/dist/goal-thread-scheduler.d.ts +78 -0
  40. package/dist/grounding-check.d.ts +33 -0
  41. package/dist/harness-bridge.d.ts +75 -2
  42. package/dist/harness-token-budget.d.ts +9 -0
  43. package/dist/index.d.ts +30 -1
  44. package/dist/index.js +166 -80
  45. package/dist/index.js.map +1 -1
  46. package/dist/layer-policy-flag.d.ts +13 -0
  47. package/dist/layer-policy-wiring.d.ts +77 -0
  48. package/dist/layer-settings.d.ts +49 -0
  49. package/dist/layer-telemetry.d.ts +2 -0
  50. package/dist/lexical/lexical-mode.d.ts +29 -0
  51. package/dist/live-steering-channel.d.ts +31 -0
  52. package/dist/memory-consolidation.d.ts +80 -0
  53. package/dist/memory-governance.d.ts +30 -0
  54. package/dist/memory-reviewer.d.ts +114 -0
  55. package/dist/memory-service.d.ts +348 -9
  56. package/dist/model-json.d.ts +17 -0
  57. package/dist/next-step-context.d.ts +51 -0
  58. package/dist/next-step-proposer.d.ts +53 -0
  59. package/dist/plan-approval-service.d.ts +1 -1
  60. package/dist/plan-drafting-service.d.ts +1 -1
  61. package/dist/plan-graph-flag.d.ts +20 -0
  62. package/dist/plan-question.d.ts +60 -0
  63. package/dist/plan-service.d.ts +6 -2
  64. package/dist/plan-step-prompt.d.ts +15 -0
  65. package/dist/plan-store.d.ts +7 -1
  66. package/dist/plan-viz/normalize.d.ts +14 -0
  67. package/dist/plan-viz/plan-detail-lines.d.ts +3 -0
  68. package/dist/plan-viz/plan-layout.d.ts +48 -0
  69. package/dist/plan-viz/plan-nav.d.ts +29 -0
  70. package/dist/plan-viz/plan-raster.d.ts +36 -0
  71. package/dist/plan-viz/plan-routes.d.ts +6 -0
  72. package/dist/plan-viz/plan-snapshot.d.ts +73 -0
  73. package/dist/plan-viz/plan-viewport.d.ts +29 -0
  74. package/dist/plan-viz/plan-width.d.ts +15 -0
  75. package/dist/plan-viz/testkit/display-width.d.ts +12 -0
  76. package/dist/plan-viz/testkit/generators.d.ts +61 -0
  77. package/dist/plan-viz/testkit/grid-oracles.d.ts +38 -0
  78. package/dist/plan-viz/testkit/nav-oracles.d.ts +79 -0
  79. package/dist/plan-viz/testkit/types.d.ts +8 -0
  80. package/dist/plan-viz/types.d.ts +34 -0
  81. package/dist/provider-setup-LFsaTkpf.js +16606 -0
  82. package/dist/provider-setup-LFsaTkpf.js.map +1 -0
  83. package/dist/provider-setup.d.ts +51 -0
  84. package/dist/recall-tool.d.ts +43 -0
  85. package/dist/recovery-note.d.ts +22 -0
  86. package/dist/response-service.d.ts +28 -2
  87. package/dist/review-checker.d.ts +10 -4
  88. package/dist/reviewer-revision.d.ts +23 -0
  89. package/dist/risk-classifier.d.ts +7 -0
  90. package/dist/scope-urgency-classifier.d.ts +29 -0
  91. package/dist/scripted-llm-client.d.ts +26 -1
  92. package/dist/semantic-compaction.d.ts +15 -0
  93. package/dist/semantic-hypotheses.d.ts +40 -0
  94. package/dist/source-reliability.d.ts +71 -0
  95. package/dist/supervisor-flag.d.ts +20 -0
  96. package/dist/task-completion-check.d.ts +24 -0
  97. package/dist/tool-control-plane.d.ts +33 -1
  98. package/dist/tool-effect-class.d.ts +9 -0
  99. package/dist/transcript-compaction.d.ts +9 -0
  100. package/dist/{tui-app-CFfOP2DC.js → tui-app-BLR-PRFp.js} +321 -7
  101. package/dist/tui-app-BLR-PRFp.js.map +1 -0
  102. package/dist/tui-app.d.ts +38 -0
  103. package/dist/turn-intent-classifier.d.ts +75 -16
  104. package/dist/turn-interpreter.d.ts +25 -3
  105. package/dist/version.d.ts +1 -1
  106. package/package.json +7 -7
  107. package/dist/bin-Btzhiyzi.js +0 -2108
  108. package/dist/bin-Btzhiyzi.js.map +0 -1
  109. package/dist/cli-session-DnSc6Hhx.js +0 -8343
  110. package/dist/cli-session-DnSc6Hhx.js.map +0 -1
  111. package/dist/tui-app-CFfOP2DC.js.map +0 -1
@@ -0,0 +1,485 @@
1
+ import { z } from 'zod';
2
+ import { MemoryAdapter } from '@buildaharness/runtime';
3
+ import { PlanFsPersistence, PlanRecord } from './plan-store.js';
4
+ export declare const GoalThreadStatusSchema: z.ZodEnum<["READY", "ACTIVE", "BLOCKED", "PAUSED", "DONE", "ABANDONED"]>;
5
+ export type GoalThreadStatus = z.infer<typeof GoalThreadStatusSchema>;
6
+ /**
7
+ * R3's two reasons for multiple root nodes, handled oppositely: `alternative` roots are competing
8
+ * guesses at one intent (resolving one abandons the others), `concurrent` roots are genuinely
9
+ * separate goals that coexist. Absent for a thread with no siblings needing disambiguation.
10
+ */
11
+ export declare const SiblingRelationSchema: z.ZodEnum<["alternative", "concurrent"]>;
12
+ export type SiblingRelation = z.infer<typeof SiblingRelationSchema>;
13
+ declare const GoalTaskRecordSchema: z.ZodObject<{
14
+ id: z.ZodString;
15
+ description: z.ZodString;
16
+ depends_on: z.ZodArray<z.ZodString, "many">;
17
+ status: z.ZodEnum<["PENDING", "RUNNING", "COMPLETE", "FAILED", "BLOCKED", "HUMAN_REQUIRED"]>;
18
+ riskLevel: z.ZodOptional<z.ZodEnum<["LOW", "MEDIUM", "HIGH"]>>;
19
+ cancelled: z.ZodOptional<z.ZodBoolean>;
20
+ }, "strip", z.ZodTypeAny, {
21
+ id: string;
22
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
23
+ description: string;
24
+ depends_on: string[];
25
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
26
+ cancelled?: boolean | undefined;
27
+ }, {
28
+ id: string;
29
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
30
+ description: string;
31
+ depends_on: string[];
32
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
33
+ cancelled?: boolean | undefined;
34
+ }>;
35
+ export type GoalTaskRecord = z.infer<typeof GoalTaskRecordSchema>;
36
+ /**
37
+ * A persisted next-step suggestion (R7) — what next-step-proposer.ts's `proposeNextSteps()` yields
38
+ * for a thread that just reached DONE, minus `goalThreadId` (it lives on the thread that owns it).
39
+ * Advisory only: a suggestion is never a task on the thread and is never executed; the user acts on
40
+ * it, if at all, by simply asking. `promotion` records the confidence policy that admitted it
41
+ * (`auto` = high confidence, `pending_confirm` = medium); `session_only` (low confidence)
42
+ * suggestions are never persisted, so they don't appear here.
43
+ */
44
+ export declare const ThreadSuggestionSchema: z.ZodObject<{
45
+ id: z.ZodString;
46
+ description: z.ZodString;
47
+ rationale: z.ZodString;
48
+ confidence: z.ZodEnum<["high", "medium", "low"]>;
49
+ promotion: z.ZodEnum<["auto", "pending_confirm", "session_only"]>;
50
+ createdAt: z.ZodString;
51
+ }, "strip", z.ZodTypeAny, {
52
+ rationale: string;
53
+ id: string;
54
+ confidence: "high" | "medium" | "low";
55
+ description: string;
56
+ createdAt: string;
57
+ promotion: "auto" | "pending_confirm" | "session_only";
58
+ }, {
59
+ rationale: string;
60
+ id: string;
61
+ confidence: "high" | "medium" | "low";
62
+ description: string;
63
+ createdAt: string;
64
+ promotion: "auto" | "pending_confirm" | "session_only";
65
+ }>;
66
+ export type ThreadSuggestion = z.infer<typeof ThreadSuggestionSchema>;
67
+ /**
68
+ * One node in the persisted goal DAG (R2). Absorbs PlanRecord's exact shape (Q1) — templateName
69
+ * through updatedAt below are unchanged in meaning from PlanRecord — plus the fields that make a
70
+ * thread schedulable: a stable `id` (PlanRecord had none, being a singleton), a scheduler-facing
71
+ * `status` distinct from `mode` (which is about this thread's own Tier-2 drafting/approval
72
+ * lifecycle, not whether the Scheduler may currently give it focus — see INV-40), and R3's sibling
73
+ * relation for when this thread is one of several roots.
74
+ */
75
+ export declare const GoalThreadSchema: z.ZodObject<{
76
+ id: z.ZodString;
77
+ status: z.ZodEnum<["READY", "ACTIVE", "BLOCKED", "PAUSED", "DONE", "ABANDONED"]>;
78
+ relationToSiblings: z.ZodOptional<z.ZodEnum<["alternative", "concurrent"]>>;
79
+ /** Sibling GoalThread ids this one is grouped with as competing/concurrent roots (R3). */
80
+ siblingIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
81
+ /** templateName..updatedAt: absorbed from PlanRecord unchanged (Q1). */
82
+ templateName: z.ZodNullable<z.ZodString>;
83
+ successCriteria: z.ZodString;
84
+ rationale: z.ZodString;
85
+ tasks: z.ZodArray<z.ZodObject<{
86
+ id: z.ZodString;
87
+ description: z.ZodString;
88
+ depends_on: z.ZodArray<z.ZodString, "many">;
89
+ status: z.ZodEnum<["PENDING", "RUNNING", "COMPLETE", "FAILED", "BLOCKED", "HUMAN_REQUIRED"]>;
90
+ riskLevel: z.ZodOptional<z.ZodEnum<["LOW", "MEDIUM", "HIGH"]>>;
91
+ cancelled: z.ZodOptional<z.ZodBoolean>;
92
+ }, "strip", z.ZodTypeAny, {
93
+ id: string;
94
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
95
+ description: string;
96
+ depends_on: string[];
97
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
98
+ cancelled?: boolean | undefined;
99
+ }, {
100
+ id: string;
101
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
102
+ description: string;
103
+ depends_on: string[];
104
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
105
+ cancelled?: boolean | undefined;
106
+ }>, "many">;
107
+ mode: z.ZodEnum<["drafting", "awaiting_approval", "active", "done", "abandoned"]>;
108
+ reviewNotes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
109
+ verifiedAt: z.ZodOptional<z.ZodString>;
110
+ executingOnPlan: z.ZodBoolean;
111
+ /** Advisory next steps proposed when this thread reached DONE — see ThreadSuggestionSchema. */
112
+ suggestions: z.ZodOptional<z.ZodArray<z.ZodObject<{
113
+ id: z.ZodString;
114
+ description: z.ZodString;
115
+ rationale: z.ZodString;
116
+ confidence: z.ZodEnum<["high", "medium", "low"]>;
117
+ promotion: z.ZodEnum<["auto", "pending_confirm", "session_only"]>;
118
+ createdAt: z.ZodString;
119
+ }, "strip", z.ZodTypeAny, {
120
+ rationale: string;
121
+ id: string;
122
+ confidence: "high" | "medium" | "low";
123
+ description: string;
124
+ createdAt: string;
125
+ promotion: "auto" | "pending_confirm" | "session_only";
126
+ }, {
127
+ rationale: string;
128
+ id: string;
129
+ confidence: "high" | "medium" | "low";
130
+ description: string;
131
+ createdAt: string;
132
+ promotion: "auto" | "pending_confirm" | "session_only";
133
+ }>, "many">>;
134
+ trustApprovedSteps: z.ZodOptional<z.ZodBoolean>;
135
+ planApprovalId: z.ZodOptional<z.ZodString>;
136
+ createdAt: z.ZodString;
137
+ updatedAt: z.ZodString;
138
+ }, "strip", z.ZodTypeAny, {
139
+ rationale: string;
140
+ id: string;
141
+ status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
142
+ tasks: {
143
+ id: string;
144
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
145
+ description: string;
146
+ depends_on: string[];
147
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
148
+ cancelled?: boolean | undefined;
149
+ }[];
150
+ successCriteria: string;
151
+ mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
152
+ createdAt: string;
153
+ templateName: string | null;
154
+ executingOnPlan: boolean;
155
+ updatedAt: string;
156
+ relationToSiblings?: "alternative" | "concurrent" | undefined;
157
+ siblingIds?: string[] | undefined;
158
+ reviewNotes?: string[] | undefined;
159
+ verifiedAt?: string | undefined;
160
+ suggestions?: {
161
+ rationale: string;
162
+ id: string;
163
+ confidence: "high" | "medium" | "low";
164
+ description: string;
165
+ createdAt: string;
166
+ promotion: "auto" | "pending_confirm" | "session_only";
167
+ }[] | undefined;
168
+ trustApprovedSteps?: boolean | undefined;
169
+ planApprovalId?: string | undefined;
170
+ }, {
171
+ rationale: string;
172
+ id: string;
173
+ status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
174
+ tasks: {
175
+ id: string;
176
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
177
+ description: string;
178
+ depends_on: string[];
179
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
180
+ cancelled?: boolean | undefined;
181
+ }[];
182
+ successCriteria: string;
183
+ mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
184
+ createdAt: string;
185
+ templateName: string | null;
186
+ executingOnPlan: boolean;
187
+ updatedAt: string;
188
+ relationToSiblings?: "alternative" | "concurrent" | undefined;
189
+ siblingIds?: string[] | undefined;
190
+ reviewNotes?: string[] | undefined;
191
+ verifiedAt?: string | undefined;
192
+ suggestions?: {
193
+ rationale: string;
194
+ id: string;
195
+ confidence: "high" | "medium" | "low";
196
+ description: string;
197
+ createdAt: string;
198
+ promotion: "auto" | "pending_confirm" | "session_only";
199
+ }[] | undefined;
200
+ trustApprovedSteps?: boolean | undefined;
201
+ planApprovalId?: string | undefined;
202
+ }>;
203
+ export type GoalThread = z.infer<typeof GoalThreadSchema>;
204
+ /**
205
+ * The persisted DAG itself (R2): `threads` is the full set of goal threads known this session,
206
+ * `activeThreadId` is the O(1) current-focus pointer every downstream mechanism (classifier,
207
+ * Scheduler, next-step proposer, Tier-2 scoping) needs answerable without a graph traversal —
208
+ * see the "current-focus / task→goal linkage primitive" gap this plan's design brief calls out.
209
+ * INV-38/39 (at most one ACTIVE thread, Scheduler is the sole writer of this pointer) are enforced
210
+ * starting Phase 5, not here — this phase only defines the shape.
211
+ */
212
+ export declare const GoalGraphRecordSchema: z.ZodObject<{
213
+ threads: z.ZodArray<z.ZodObject<{
214
+ id: z.ZodString;
215
+ status: z.ZodEnum<["READY", "ACTIVE", "BLOCKED", "PAUSED", "DONE", "ABANDONED"]>;
216
+ relationToSiblings: z.ZodOptional<z.ZodEnum<["alternative", "concurrent"]>>;
217
+ /** Sibling GoalThread ids this one is grouped with as competing/concurrent roots (R3). */
218
+ siblingIds: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
219
+ /** templateName..updatedAt: absorbed from PlanRecord unchanged (Q1). */
220
+ templateName: z.ZodNullable<z.ZodString>;
221
+ successCriteria: z.ZodString;
222
+ rationale: z.ZodString;
223
+ tasks: z.ZodArray<z.ZodObject<{
224
+ id: z.ZodString;
225
+ description: z.ZodString;
226
+ depends_on: z.ZodArray<z.ZodString, "many">;
227
+ status: z.ZodEnum<["PENDING", "RUNNING", "COMPLETE", "FAILED", "BLOCKED", "HUMAN_REQUIRED"]>;
228
+ riskLevel: z.ZodOptional<z.ZodEnum<["LOW", "MEDIUM", "HIGH"]>>;
229
+ cancelled: z.ZodOptional<z.ZodBoolean>;
230
+ }, "strip", z.ZodTypeAny, {
231
+ id: string;
232
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
233
+ description: string;
234
+ depends_on: string[];
235
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
236
+ cancelled?: boolean | undefined;
237
+ }, {
238
+ id: string;
239
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
240
+ description: string;
241
+ depends_on: string[];
242
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
243
+ cancelled?: boolean | undefined;
244
+ }>, "many">;
245
+ mode: z.ZodEnum<["drafting", "awaiting_approval", "active", "done", "abandoned"]>;
246
+ reviewNotes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
247
+ verifiedAt: z.ZodOptional<z.ZodString>;
248
+ executingOnPlan: z.ZodBoolean;
249
+ /** Advisory next steps proposed when this thread reached DONE — see ThreadSuggestionSchema. */
250
+ suggestions: z.ZodOptional<z.ZodArray<z.ZodObject<{
251
+ id: z.ZodString;
252
+ description: z.ZodString;
253
+ rationale: z.ZodString;
254
+ confidence: z.ZodEnum<["high", "medium", "low"]>;
255
+ promotion: z.ZodEnum<["auto", "pending_confirm", "session_only"]>;
256
+ createdAt: z.ZodString;
257
+ }, "strip", z.ZodTypeAny, {
258
+ rationale: string;
259
+ id: string;
260
+ confidence: "high" | "medium" | "low";
261
+ description: string;
262
+ createdAt: string;
263
+ promotion: "auto" | "pending_confirm" | "session_only";
264
+ }, {
265
+ rationale: string;
266
+ id: string;
267
+ confidence: "high" | "medium" | "low";
268
+ description: string;
269
+ createdAt: string;
270
+ promotion: "auto" | "pending_confirm" | "session_only";
271
+ }>, "many">>;
272
+ trustApprovedSteps: z.ZodOptional<z.ZodBoolean>;
273
+ planApprovalId: z.ZodOptional<z.ZodString>;
274
+ createdAt: z.ZodString;
275
+ updatedAt: z.ZodString;
276
+ }, "strip", z.ZodTypeAny, {
277
+ rationale: string;
278
+ id: string;
279
+ status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
280
+ tasks: {
281
+ id: string;
282
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
283
+ description: string;
284
+ depends_on: string[];
285
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
286
+ cancelled?: boolean | undefined;
287
+ }[];
288
+ successCriteria: string;
289
+ mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
290
+ createdAt: string;
291
+ templateName: string | null;
292
+ executingOnPlan: boolean;
293
+ updatedAt: string;
294
+ relationToSiblings?: "alternative" | "concurrent" | undefined;
295
+ siblingIds?: string[] | undefined;
296
+ reviewNotes?: string[] | undefined;
297
+ verifiedAt?: string | undefined;
298
+ suggestions?: {
299
+ rationale: string;
300
+ id: string;
301
+ confidence: "high" | "medium" | "low";
302
+ description: string;
303
+ createdAt: string;
304
+ promotion: "auto" | "pending_confirm" | "session_only";
305
+ }[] | undefined;
306
+ trustApprovedSteps?: boolean | undefined;
307
+ planApprovalId?: string | undefined;
308
+ }, {
309
+ rationale: string;
310
+ id: string;
311
+ status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
312
+ tasks: {
313
+ id: string;
314
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
315
+ description: string;
316
+ depends_on: string[];
317
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
318
+ cancelled?: boolean | undefined;
319
+ }[];
320
+ successCriteria: string;
321
+ mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
322
+ createdAt: string;
323
+ templateName: string | null;
324
+ executingOnPlan: boolean;
325
+ updatedAt: string;
326
+ relationToSiblings?: "alternative" | "concurrent" | undefined;
327
+ siblingIds?: string[] | undefined;
328
+ reviewNotes?: string[] | undefined;
329
+ verifiedAt?: string | undefined;
330
+ suggestions?: {
331
+ rationale: string;
332
+ id: string;
333
+ confidence: "high" | "medium" | "low";
334
+ description: string;
335
+ createdAt: string;
336
+ promotion: "auto" | "pending_confirm" | "session_only";
337
+ }[] | undefined;
338
+ trustApprovedSteps?: boolean | undefined;
339
+ planApprovalId?: string | undefined;
340
+ }>, "many">;
341
+ activeThreadId: z.ZodNullable<z.ZodString>;
342
+ createdAt: z.ZodString;
343
+ updatedAt: z.ZodString;
344
+ }, "strip", z.ZodTypeAny, {
345
+ createdAt: string;
346
+ updatedAt: string;
347
+ threads: {
348
+ rationale: string;
349
+ id: string;
350
+ status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
351
+ tasks: {
352
+ id: string;
353
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
354
+ description: string;
355
+ depends_on: string[];
356
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
357
+ cancelled?: boolean | undefined;
358
+ }[];
359
+ successCriteria: string;
360
+ mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
361
+ createdAt: string;
362
+ templateName: string | null;
363
+ executingOnPlan: boolean;
364
+ updatedAt: string;
365
+ relationToSiblings?: "alternative" | "concurrent" | undefined;
366
+ siblingIds?: string[] | undefined;
367
+ reviewNotes?: string[] | undefined;
368
+ verifiedAt?: string | undefined;
369
+ suggestions?: {
370
+ rationale: string;
371
+ id: string;
372
+ confidence: "high" | "medium" | "low";
373
+ description: string;
374
+ createdAt: string;
375
+ promotion: "auto" | "pending_confirm" | "session_only";
376
+ }[] | undefined;
377
+ trustApprovedSteps?: boolean | undefined;
378
+ planApprovalId?: string | undefined;
379
+ }[];
380
+ activeThreadId: string | null;
381
+ }, {
382
+ createdAt: string;
383
+ updatedAt: string;
384
+ threads: {
385
+ rationale: string;
386
+ id: string;
387
+ status: "BLOCKED" | "READY" | "ACTIVE" | "PAUSED" | "DONE" | "ABANDONED";
388
+ tasks: {
389
+ id: string;
390
+ status: "BLOCKED" | "HUMAN_REQUIRED" | "PENDING" | "RUNNING" | "COMPLETE" | "FAILED";
391
+ description: string;
392
+ depends_on: string[];
393
+ riskLevel?: "HIGH" | "MEDIUM" | "LOW" | undefined;
394
+ cancelled?: boolean | undefined;
395
+ }[];
396
+ successCriteria: string;
397
+ mode: "active" | "done" | "drafting" | "awaiting_approval" | "abandoned";
398
+ createdAt: string;
399
+ templateName: string | null;
400
+ executingOnPlan: boolean;
401
+ updatedAt: string;
402
+ relationToSiblings?: "alternative" | "concurrent" | undefined;
403
+ siblingIds?: string[] | undefined;
404
+ reviewNotes?: string[] | undefined;
405
+ verifiedAt?: string | undefined;
406
+ suggestions?: {
407
+ rationale: string;
408
+ id: string;
409
+ confidence: "high" | "medium" | "low";
410
+ description: string;
411
+ createdAt: string;
412
+ promotion: "auto" | "pending_confirm" | "session_only";
413
+ }[] | undefined;
414
+ trustApprovedSteps?: boolean | undefined;
415
+ planApprovalId?: string | undefined;
416
+ }[];
417
+ activeThreadId: string | null;
418
+ }>;
419
+ export type GoalGraphRecord = z.infer<typeof GoalGraphRecordSchema>;
420
+ /** Same `{backend, workspaceRoot}` pair as PlanFsPersistence — a goal graph and its session's plan file live in the same workspace. */
421
+ export type GoalGraphFsPersistence = PlanFsPersistence;
422
+ /**
423
+ * Wraps an existing `PlanRecord` into the single `GoalThread` it becomes under Q1's "absorb, don't
424
+ * duplicate" resolution — nothing in `plan`'s own fields is dropped.
425
+ */
426
+ export declare function createGoalThreadFromPlanRecord(plan: PlanRecord, id?: string): GoalThread;
427
+ /** A fresh, empty goal graph — no threads, nothing active. */
428
+ export declare function createEmptyGoalGraphRecord(): GoalGraphRecord;
429
+ /** Wraps a single pre-existing `PlanRecord` into a one-thread `GoalGraphRecord` — the migration path's output shape. */
430
+ export declare function createGoalGraphRecordFromPlanRecord(plan: PlanRecord): GoalGraphRecord;
431
+ /**
432
+ * R2's O(1) locatability primitive, live as of Phase 4: the currently-focused thread, found by a
433
+ * direct field lookup (`activeThreadId`), never a graph traversal. Defensive about a transient
434
+ * inconsistency Phase 4 can produce (see goal-graph-reconcile.ts): a NEW_GOAL/CANCEL_CURRENT
435
+ * steering message can pause/abandon the thread `activeThreadId` still points at, ahead of Phase
436
+ * 5's Scheduler ever reassigning that pointer (INV-39 — only the Scheduler writes it) — so this
437
+ * only returns a thread whose own `status` is still genuinely `ACTIVE`, not just pointed-at.
438
+ */
439
+ export declare function getActiveThread(record: GoalGraphRecord): GoalThread | null;
440
+ /** R2's task→goal parent-link query — every task belonging to `goalId`, a direct field filter, never a traversal. */
441
+ export declare function tasksForGoal(record: GoalGraphRecord, goalId: string): GoalTaskRecord[];
442
+ /**
443
+ * Every thread the Scheduler could hand focus to right now (Phase 5): READY, and not mid-Tier-2
444
+ * drafting or awaiting approval (INV-40). A drafting thread's `status` is READY (see
445
+ * createGoalThreadFromPlanRecord / mintConcurrentReadyThread), so the exclusion has to look at
446
+ * `mode`, not just `status` — until 2026-09-23 this filtered on status alone, which quietly made
447
+ * INV-40 false: a thread minted by a NEW_GOAL steering message (mode 'drafting') was eligible for
448
+ * focus. The identity matcher (goal-thread-identity.ts) is what adopts such a thread, by matching
449
+ * a real turn to it and promoting its mode to 'active'.
450
+ */
451
+ export declare function readyThreads(record: GoalGraphRecord): GoalThread[];
452
+ /**
453
+ * R4's NEW_GOAL branch (both IMMEDIATE and DEFERRED collapse to this in Phase 4 — see
454
+ * check-caller-updates.ts's cancel_current sibling doc comment and the plan's resolved
455
+ * "ACTIVE-pointer write authority" decision: Tier-1 never writes `activeThreadId` itself, it only
456
+ * pauses the old thread and mints the new one READY; Phase 5's Scheduler decides what becomes
457
+ * ACTIVE next). `pauseThreadId`, when given and currently ACTIVE, transitions to PAUSED and is
458
+ * linked to the new thread as a `concurrent` sibling (R3) — never `alternative`, since a NEW_GOAL
459
+ * is a genuinely separate objective, not a competing guess at the same one.
460
+ */
461
+ export declare function mintConcurrentReadyThread(record: GoalGraphRecord, description: string, pauseThreadId?: string | null): GoalGraphRecord;
462
+ /** R4's CANCEL_CURRENT branch — marks a thread ABANDONED. Kept for audit trail, never removed from `threads`. */
463
+ export declare function abandonThread(record: GoalGraphRecord, threadId: string): GoalGraphRecord;
464
+ export declare function saveGoalGraphRecord(memory: MemoryAdapter, sessionId: string, record: GoalGraphRecord, fsPersistence?: GoalGraphFsPersistence): Promise<void>;
465
+ /**
466
+ * Loads `sessionId`'s goal graph, migrating a pre-existing `PlanRecord` in place the first time
467
+ * this is called for a session that predates this mechanism (P5-equivalent non-destructive
468
+ * discipline — same as `migrateFact`/`migratePlanRecord`: the old record's data is never silently
469
+ * dropped, just re-shaped and persisted once under the new key). Every call after that first one
470
+ * finds the migrated `GoalGraphRecord` directly and never re-touches the legacy `PlanRecord`.
471
+ *
472
+ * When `fsPersistence` is configured and its goal-graph JSON file exists, that file wins over the
473
+ * Dexie/State-tier record, mirroring `loadPlanRecord`'s own fs-file-wins-then-reconcile behavior
474
+ * (INV-33's discipline, applied here too: the result is written back into `memory` so the two
475
+ * never stay silently split).
476
+ */
477
+ export declare function loadGoalGraphRecord(memory: MemoryAdapter, sessionId: string, fsPersistence?: GoalGraphFsPersistence): Promise<GoalGraphRecord | null>;
478
+ /**
479
+ * Appends advisory `suggestions` to `threadId`, skipping any whose description (case-insensitive,
480
+ * trimmed) the thread already carries — proposing again for the same DONE thread must not stack
481
+ * duplicates. `session_only` suggestions are dropped here (low confidence is advisory for the turn
482
+ * that produced it, never persisted). A `threadId` not present in `record.threads` is a no-op.
483
+ */
484
+ export declare function addThreadSuggestions(record: GoalGraphRecord, threadId: string, suggestions: ThreadSuggestion[]): GoalGraphRecord;
485
+ export {};
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Pure logic backing the hierarchical-goal-tree mechanism's Tier 1.5 gate — the next-step
3
+ * proposer (Phase 6, `next-step-proposer.ts`) — see
4
+ * plans/hierarchical_goal_tree_and_steering_plan.html. Split out into its own file/flag rather
5
+ * than folded into `goal-graph-flag.ts`, matching this codebase's one-flag-per-file convention
6
+ * (`one-loop-flag.ts`/`ask-mode-flag.ts`/`plan-mode-flag.ts`/`goal-graph-flag.ts`) and the plan's
7
+ * own "Rollout discipline" resolution (2026-09-22): gated independently of `goalGraphMode` since a
8
+ * regression in the next-step proposer shouldn't block Tier 0/1 (the steering channel, classifier,
9
+ * persistent `GoalGraphRecord`).
10
+ *
11
+ * As of Phase 8, threaded through `AssistantConfig` exactly like `goal-graph-flag.ts`:
12
+ * `goalGraphSuggestMode` is a real config field with `/config set` support, a
13
+ * `VITE_ASSISTANT_GOAL_GRAPH_SUGGEST` build-time line in chat-ui's browser-config.ts, and
14
+ * flag-chain resolution tests (cli-config.test.ts, browser-config.test.ts) — resolved via
15
+ * `normalizeGoalGraphSuggestMode` below, mirroring `normalizeGoalGraphMode` exactly. No production
16
+ * call site reads `config.goalGraphSuggestMode` yet (`next-step-proposer.ts`'s
17
+ * `proposeNextSteps()` still takes its `suggestMode` argument directly from whichever caller wires
18
+ * it in, and no caller does that yet — see that file's own notes), so this remains inert beyond
19
+ * the config seam itself.
20
+ *
21
+ * Default OFF ('disabled'): `next-step-proposer.ts`'s `proposeNextSteps()` returns `[]` without
22
+ * making any LLM call, so a flag-off session sees zero behavior change (INV-43).
23
+ */
24
+ export type GoalGraphSuggestMode = 'enabled' | 'disabled';
25
+ export declare const DEFAULT_GOAL_GRAPH_SUGGEST_MODE: GoalGraphSuggestMode;
26
+ /** See isGoalGraphEnabled (goal-graph-flag.ts) — same undefined-means-package-default rule. */
27
+ export declare function isGoalGraphSuggestEnabled(mode: GoalGraphSuggestMode | undefined): boolean;
28
+ /**
29
+ * Same signature/typo-tolerance-with-a-warning convention as `normalizeGoalGraphMode`: an unset or
30
+ * empty value falls back to the default silently, an unrecognized non-empty value falls back with
31
+ * a startup warning naming `varName`.
32
+ */
33
+ export declare function normalizeGoalGraphSuggestMode(raw: string | undefined, varName?: string): GoalGraphSuggestMode;
34
+ export declare function resolveGoalGraphSuggestMode(env: NodeJS.ProcessEnv): GoalGraphSuggestMode;
@@ -0,0 +1,21 @@
1
+ import { ILLMClient, TokenUsage } from '@buildaharness/runtime';
2
+ export interface GoalCandidate {
3
+ id: string;
4
+ /** A short description of the goal's intent — e.g. a GoalThread's successCriteria/rationale — used as the identity anchor for matching, not its full task list. */
5
+ description: string;
6
+ }
7
+ export interface GoalIdentityMatchResult {
8
+ /** The existing candidate this message's intent matches, or null when nothing matches — including on ambiguity, see `ambiguous`. Always one of `candidates`' ids, never a dangling/unrecognized one. */
9
+ matchedGoalId: string | null;
10
+ /** True when more than one candidate plausibly matches and the model couldn't confidently pick a single one. matchedGoalId is always null in this case — never guess a specific attachment, same fail-safe direction as no-match at all. */
11
+ ambiguous: boolean;
12
+ }
13
+ /**
14
+ * One bounded LLM call per incoming steering message, only when there's at least one existing
15
+ * goal thread to match against. Falls back to "no match, treat as new" — the same fail-safe
16
+ * direction as an unrecognized/dangling id or genuine ambiguity — on any parse failure or LLM
17
+ * error, matching this codebase's other LLM-backed classifiers (classifyTurnIntent,
18
+ * checkForContradictions): a missed match costs nothing worse than spinning up an extra
19
+ * `concurrent` goal root, never a wrong attachment to the wrong thread.
20
+ */
21
+ export declare function matchGoalIdentity(message: string, candidates: GoalCandidate[], llmClient: ILLMClient, model?: string, onUsage?: (usage: TokenUsage) => void): Promise<GoalIdentityMatchResult>;
@@ -0,0 +1,32 @@
1
+ import { ILLMClient, MemoryAdapter, TokenUsage } from '@buildaharness/runtime';
2
+ import { GoalGraphFsPersistence } from './goal-graph-store.js';
3
+ /**
4
+ * Cross-turn goal identity, wired into the turn (plans/hierarchical_goal_tree_and_steering_plan.html
5
+ * Phase 2's matcher, unused until now): decides which goal thread a full turn belongs to, so a
6
+ * message that continues an earlier goal gets that goal's thread back in focus (with its paused
7
+ * evidence intact) and a message about something new starts its own thread. This is what makes
8
+ * the graph fill in for ordinary conversation; before it, threads only came from a session plan or
9
+ * a NEW_GOAL steering message.
10
+ *
11
+ * - candidates: every thread that is not finished (READY / ACTIVE / PAUSED / BLOCKED — including a
12
+ * placeholder a NEW_GOAL steering message minted, which is how that deferred ask finds its
13
+ * thread again when it runs as its own turn). DONE and ABANDONED goals are not reopened.
14
+ * - matched → `focusThread` (the Scheduler's single write path, INV-39); a BLOCKED match keeps
15
+ * its status but is still the thread this turn's evidence lands on.
16
+ * - no match or ambiguous → `startThread`. Ambiguity is never guessed into an attachment
17
+ * (same fail-safe as the matcher: a missed match costs an extra thread, a wrong one costs work
18
+ * landing on the wrong goal).
19
+ * - no candidates → `startThread` with no LLM call at all.
20
+ *
21
+ * Best-effort by construction: any failure (memory, matcher) resolves to "no thread" for this turn,
22
+ * exactly as if the goal graph were off. Returns the thread id this turn's evidence should land on.
23
+ */
24
+ export declare function resolveTurnGoalThread(params: {
25
+ userMessage: string;
26
+ sessionId: string;
27
+ memory: MemoryAdapter;
28
+ llmClient: ILLMClient;
29
+ model?: string;
30
+ onUsage?: (usage: TokenUsage) => void;
31
+ fsPersistence?: GoalGraphFsPersistence;
32
+ }): Promise<string | undefined>;
@@ -0,0 +1,78 @@
1
+ import { GoalGraphRecord, GoalThread } from './goal-graph-store.js';
2
+ /**
3
+ * Phase 5 of plans/hierarchical_goal_tree_and_steering_plan.html — the Scheduler: the sole writer
4
+ * of `GoalGraphRecord.activeThreadId` (INV-39), enforcing single-focus v1 (INV-38 — at most one
5
+ * `ACTIVE` thread at a time) and READY-only selection that excludes anything mid-Tier-2-drafting
6
+ * (INV-40, via `readyThreads()`'s own `status`+`mode` filter).
7
+ *
8
+ * Per the plan's resolved "ACTIVE-pointer write authority" decision, IMMEDIATE and DEFERRED
9
+ * steering both call this *same* selection function with the *same* exclusion rules — the only
10
+ * difference is *when* a caller invokes it: `goal-graph-reconcile.ts`'s NEW_GOAL branch calls it
11
+ * synchronously, this same iteration, for IMMEDIATE; DEFERRED leaves it for the next natural pass
12
+ * (today, `assistant.ts`'s own per-turn call at turn-dispatch, gated on `options.steeringChannel`
13
+ * being present — the natural turn-scoped analog of "off a control_state BLOCKED trigger", since
14
+ * TaskGraph loading/swapping is itself a turn-scoped operation, not a mid-iteration one).
15
+ */
16
+ export interface SchedulerSelectionResult {
17
+ record: GoalGraphRecord;
18
+ activeThreadId: string | null;
19
+ switched: boolean;
20
+ }
21
+ /**
22
+ * The Scheduler's one selection pass. If a thread is already genuinely `ACTIVE`
23
+ * (`getActiveThread` — defensively re-checks `status`, not just the pointer), it keeps focus:
24
+ * v1 is cooperative, not preemptive by default (Q6) — a still-workable ACTIVE thread is never
25
+ * bumped just because other READY threads exist. Only when there is *no* valid ACTIVE thread
26
+ * (null pointer, or the pointed-at thread's own status has moved on — PAUSED/BLOCKED/DONE/
27
+ * ABANDONED, e.g. after a NEW_GOAL/CANCEL_CURRENT steering event paused or abandoned it) does it
28
+ * pick the next eligible candidate, FIFO by `createdAt`. No eligible candidate leaves the pointer
29
+ * exactly as it was — never invents a switch out of thin air.
30
+ */
31
+ export declare function selectActiveThread(record: GoalGraphRecord): SchedulerSelectionResult;
32
+ /**
33
+ * IMMEDIATE steering's synchronous hook (see the header comment): forces `threadId` to become
34
+ * `ACTIVE` right now if — and only if — it's actually eligible (`READY`, not mid-drafting) per the
35
+ * exact same rules `selectActiveThread` itself enforces. An ineligible or unknown `threadId` (e.g.
36
+ * the just-minted thread is still `mode: 'drafting'`, per `mintConcurrentReadyThread` — real,
37
+ * common case: Tier-2 hasn't decomposed it into runnable tasks yet) falls back to the ordinary
38
+ * `selectActiveThread` pass rather than force-activating something not actually runnable —
39
+ * "same selection function, same exclusion rules either way" holds even for the forced path.
40
+ */
41
+ export declare function forceActivateThread(record: GoalGraphRecord, threadId: string): SchedulerSelectionResult;
42
+ /**
43
+ * Gives `threadId` focus for the turn that is about to run on it — the identity matcher's "this
44
+ * message continues that goal" outcome. Unlike `forceActivateThread` (which only ever activates a
45
+ * thread the Scheduler already considers eligible), this is the deliberate, user-driven switch:
46
+ * the message itself is the evidence, so a READY, PAUSED or still-drafting thread is promoted
47
+ * (a drafting thread — e.g. one a NEW_GOAL steering message minted — becomes `mode: 'active'`,
48
+ * because a real turn is now executing it) and whatever else was ACTIVE is paused with its
49
+ * evidence intact (INV-42). Still the Scheduler's single write path to the ACTIVE pointer (INV-39).
50
+ * A BLOCKED, DONE, ABANDONED or already-ACTIVE thread is left exactly as it is (`switched: false`):
51
+ * blocked work isn't silently unblocked by a mention, and finished work isn't reopened.
52
+ */
53
+ export declare function focusThread(record: GoalGraphRecord, threadId: string): SchedulerSelectionResult;
54
+ /**
55
+ * Starts a brand-new goal thread that takes focus immediately — the identity matcher's "this is a
56
+ * new goal" outcome (no existing thread matches, or it was ambiguous). The description is the
57
+ * message itself, kept to one short line. Any thread that was ACTIVE is paused and linked as a
58
+ * `concurrent` sibling (R3), never discarded (INV-42). `tasks` starts empty and is adopted from the
59
+ * harness's task graph once the turn runs (see syncThreadFromTaskGraph).
60
+ */
61
+ export declare function startThread(record: GoalGraphRecord, description: string): SchedulerSelectionResult;
62
+ /**
63
+ * INV-42 (Q3's resolution — "PAUSED preserves partial state/evidence — never silently discarded
64
+ * on preemption"): the per-thread analog of `plan-store.ts`'s `updatePlanFromRun`, mapping the
65
+ * harness's resulting task statuses back onto `threadId`'s own `tasks` list. Deliberately looked
66
+ * up **by id**, not via `getActiveThread` — the whole point is this still works for a thread the
67
+ * Scheduler has since moved to `PAUSED` (an in-flight tool call that was already running when a
68
+ * steering message preempted its thread runs to completion per Q3's "let it finish" default, and
69
+ * its result must still land on the now-PAUSED thread, not be silently dropped). A `threadId` not
70
+ * present in `record.threads` is a no-op — defensive, never throws on a stale id.
71
+ */
72
+ export declare function syncThreadFromTaskGraph(record: GoalGraphRecord, threadId: string, taskGraphTasks: {
73
+ id: string;
74
+ status: GoalThread['tasks'][number]['status'];
75
+ description?: string;
76
+ depends_on?: string[];
77
+ risk_level?: 'LOW' | 'MEDIUM' | 'HIGH';
78
+ }[]): GoalGraphRecord;