@soleri/core 9.2.0 → 9.3.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.
Files changed (316) hide show
  1. package/data/flows/build.flow.yaml +8 -9
  2. package/data/flows/deliver.flow.yaml +9 -10
  3. package/data/flows/design.flow.yaml +3 -4
  4. package/data/flows/enhance.flow.yaml +5 -6
  5. package/data/flows/explore.flow.yaml +3 -4
  6. package/data/flows/fix.flow.yaml +5 -6
  7. package/data/flows/plan.flow.yaml +4 -5
  8. package/data/flows/review.flow.yaml +3 -4
  9. package/dist/curator/curator.d.ts.map +1 -1
  10. package/dist/curator/curator.js +98 -22
  11. package/dist/curator/curator.js.map +1 -1
  12. package/dist/engine/bin/soleri-engine.js.map +1 -1
  13. package/dist/engine/module-manifest.d.ts +2 -0
  14. package/dist/engine/module-manifest.d.ts.map +1 -1
  15. package/dist/engine/module-manifest.js +136 -1
  16. package/dist/engine/module-manifest.js.map +1 -1
  17. package/dist/engine/register-engine.d.ts.map +1 -1
  18. package/dist/engine/register-engine.js +25 -1
  19. package/dist/engine/register-engine.js.map +1 -1
  20. package/dist/flows/gate-evaluator.js.map +1 -1
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +2 -0
  24. package/dist/index.js.map +1 -1
  25. package/dist/operator/operator-profile.d.ts.map +1 -1
  26. package/dist/operator/operator-profile.js +11 -5
  27. package/dist/operator/operator-profile.js.map +1 -1
  28. package/dist/operator/operator-signals.d.ts.map +1 -1
  29. package/dist/operator/operator-signals.js.map +1 -1
  30. package/dist/planning/evidence-collector.js.map +1 -1
  31. package/dist/planning/gap-passes.d.ts.map +1 -1
  32. package/dist/planning/gap-passes.js +23 -6
  33. package/dist/planning/gap-passes.js.map +1 -1
  34. package/dist/planning/gap-patterns.d.ts.map +1 -1
  35. package/dist/planning/gap-patterns.js +57 -11
  36. package/dist/planning/gap-patterns.js.map +1 -1
  37. package/dist/planning/github-projection.d.ts.map +1 -1
  38. package/dist/planning/github-projection.js +39 -20
  39. package/dist/planning/github-projection.js.map +1 -1
  40. package/dist/planning/impact-analyzer.d.ts.map +1 -1
  41. package/dist/planning/impact-analyzer.js +20 -18
  42. package/dist/planning/impact-analyzer.js.map +1 -1
  43. package/dist/planning/plan-lifecycle.d.ts.map +1 -1
  44. package/dist/planning/plan-lifecycle.js +22 -9
  45. package/dist/planning/plan-lifecycle.js.map +1 -1
  46. package/dist/planning/planner.d.ts.map +1 -1
  47. package/dist/planning/planner.js +60 -17
  48. package/dist/planning/planner.js.map +1 -1
  49. package/dist/planning/rationalization-detector.d.ts.map +1 -1
  50. package/dist/planning/rationalization-detector.js.map +1 -1
  51. package/dist/planning/reconciliation-engine.d.ts.map +1 -1
  52. package/dist/planning/reconciliation-engine.js.map +1 -1
  53. package/dist/planning/task-complexity-assessor.d.ts +42 -0
  54. package/dist/planning/task-complexity-assessor.d.ts.map +1 -0
  55. package/dist/planning/task-complexity-assessor.js +132 -0
  56. package/dist/planning/task-complexity-assessor.js.map +1 -0
  57. package/dist/planning/task-verifier.d.ts.map +1 -1
  58. package/dist/planning/task-verifier.js +14 -6
  59. package/dist/planning/task-verifier.js.map +1 -1
  60. package/dist/runtime/admin-ops.d.ts.map +1 -1
  61. package/dist/runtime/admin-ops.js +18 -0
  62. package/dist/runtime/admin-ops.js.map +1 -1
  63. package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
  64. package/dist/runtime/admin-setup-ops.js +2 -1
  65. package/dist/runtime/admin-setup-ops.js.map +1 -1
  66. package/dist/runtime/branching-ops.d.ts +12 -0
  67. package/dist/runtime/branching-ops.d.ts.map +1 -0
  68. package/dist/runtime/branching-ops.js +100 -0
  69. package/dist/runtime/branching-ops.js.map +1 -0
  70. package/dist/runtime/context-health.d.ts.map +1 -1
  71. package/dist/runtime/context-health.js.map +1 -1
  72. package/dist/runtime/facades/branching-facade.d.ts +7 -0
  73. package/dist/runtime/facades/branching-facade.d.ts.map +1 -0
  74. package/dist/runtime/facades/branching-facade.js +8 -0
  75. package/dist/runtime/facades/branching-facade.js.map +1 -0
  76. package/dist/runtime/facades/chat-service-ops.d.ts.map +1 -1
  77. package/dist/runtime/facades/chat-service-ops.js +3 -1
  78. package/dist/runtime/facades/chat-service-ops.js.map +1 -1
  79. package/dist/runtime/facades/chat-transport-ops.d.ts.map +1 -1
  80. package/dist/runtime/facades/chat-transport-ops.js.map +1 -1
  81. package/dist/runtime/facades/index.d.ts.map +1 -1
  82. package/dist/runtime/facades/index.js +42 -0
  83. package/dist/runtime/facades/index.js.map +1 -1
  84. package/dist/runtime/facades/intake-facade.d.ts +9 -0
  85. package/dist/runtime/facades/intake-facade.d.ts.map +1 -0
  86. package/dist/runtime/facades/intake-facade.js +11 -0
  87. package/dist/runtime/facades/intake-facade.js.map +1 -0
  88. package/dist/runtime/facades/links-facade.d.ts +9 -0
  89. package/dist/runtime/facades/links-facade.d.ts.map +1 -0
  90. package/dist/runtime/facades/links-facade.js +10 -0
  91. package/dist/runtime/facades/links-facade.js.map +1 -0
  92. package/dist/runtime/facades/operator-facade.d.ts.map +1 -1
  93. package/dist/runtime/facades/operator-facade.js.map +1 -1
  94. package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
  95. package/dist/runtime/facades/plan-facade.js +4 -1
  96. package/dist/runtime/facades/plan-facade.js.map +1 -1
  97. package/dist/runtime/facades/tier-facade.d.ts +7 -0
  98. package/dist/runtime/facades/tier-facade.d.ts.map +1 -0
  99. package/dist/runtime/facades/tier-facade.js +8 -0
  100. package/dist/runtime/facades/tier-facade.js.map +1 -0
  101. package/dist/runtime/facades/vault-facade.d.ts +9 -1
  102. package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
  103. package/dist/runtime/facades/vault-facade.js +44 -187
  104. package/dist/runtime/facades/vault-facade.js.map +1 -1
  105. package/dist/runtime/github-integration.d.ts.map +1 -1
  106. package/dist/runtime/github-integration.js +11 -4
  107. package/dist/runtime/github-integration.js.map +1 -1
  108. package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
  109. package/dist/runtime/orchestrate-ops.js +75 -42
  110. package/dist/runtime/orchestrate-ops.js.map +1 -1
  111. package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
  112. package/dist/runtime/planning-extra-ops.js.map +1 -1
  113. package/dist/runtime/runtime.d.ts.map +1 -1
  114. package/dist/runtime/runtime.js +3 -1
  115. package/dist/runtime/runtime.js.map +1 -1
  116. package/dist/runtime/session-briefing.d.ts.map +1 -1
  117. package/dist/runtime/session-briefing.js +5 -1
  118. package/dist/runtime/session-briefing.js.map +1 -1
  119. package/dist/runtime/tier-ops.d.ts +13 -0
  120. package/dist/runtime/tier-ops.d.ts.map +1 -0
  121. package/dist/runtime/tier-ops.js +110 -0
  122. package/dist/runtime/tier-ops.js.map +1 -0
  123. package/dist/skills/sync-skills.d.ts.map +1 -1
  124. package/dist/skills/sync-skills.js +1 -1
  125. package/dist/skills/sync-skills.js.map +1 -1
  126. package/dist/vault/linking.d.ts.map +1 -1
  127. package/dist/vault/linking.js +41 -5
  128. package/dist/vault/linking.js.map +1 -1
  129. package/dist/vault/vault-entries.d.ts.map +1 -1
  130. package/dist/vault/vault-entries.js +68 -26
  131. package/dist/vault/vault-entries.js.map +1 -1
  132. package/dist/vault/vault-maintenance.d.ts.map +1 -1
  133. package/dist/vault/vault-maintenance.js +6 -2
  134. package/dist/vault/vault-maintenance.js.map +1 -1
  135. package/dist/vault/vault-markdown-sync.d.ts.map +1 -1
  136. package/dist/vault/vault-markdown-sync.js.map +1 -1
  137. package/dist/vault/vault-memories.d.ts.map +1 -1
  138. package/dist/vault/vault-memories.js +3 -1
  139. package/dist/vault/vault-memories.js.map +1 -1
  140. package/dist/vault/vault-schema.js +36 -10
  141. package/dist/vault/vault-schema.js.map +1 -1
  142. package/dist/vault/vault.d.ts.map +1 -1
  143. package/dist/vault/vault.js +5 -1
  144. package/dist/vault/vault.js.map +1 -1
  145. package/package.json +7 -7
  146. package/src/agency/agency-manager.test.ts +60 -40
  147. package/src/agency/default-rules.test.ts +17 -9
  148. package/src/capabilities/registry.test.ts +2 -12
  149. package/src/chat/agent-loop.test.ts +33 -43
  150. package/src/chat/mcp-bridge.test.ts +7 -2
  151. package/src/claudemd/inject.test.ts +2 -12
  152. package/src/context/context-engine.test.ts +96 -51
  153. package/src/control/intent-router.test.ts +3 -3
  154. package/src/curator/classifier.test.ts +14 -8
  155. package/src/curator/contradiction-detector.test.ts +30 -5
  156. package/src/curator/curator.ts +278 -56
  157. package/src/curator/duplicate-detector.test.ts +77 -15
  158. package/src/curator/quality-gate.test.ts +71 -31
  159. package/src/curator/tag-manager.test.ts +12 -4
  160. package/src/domain-packs/knowledge-installer.test.ts +2 -10
  161. package/src/domain-packs/token-resolver.test.ts +1 -3
  162. package/src/domain-packs/types.test.ts +16 -2
  163. package/src/enforcement/registry.test.ts +2 -8
  164. package/src/engine/bin/soleri-engine.ts +3 -1
  165. package/src/engine/module-manifest.test.ts +48 -4
  166. package/src/engine/module-manifest.ts +138 -1
  167. package/src/engine/register-engine.test.ts +6 -1
  168. package/src/engine/register-engine.ts +26 -3
  169. package/src/errors/classify.test.ts +6 -2
  170. package/src/errors/retry.test.ts +1 -4
  171. package/src/facades/facade-factory.test.ts +110 -64
  172. package/src/flows/epilogue.test.ts +16 -10
  173. package/src/flows/gate-evaluator.test.ts +12 -6
  174. package/src/flows/gate-evaluator.ts +1 -3
  175. package/src/governance/governance.test.ts +137 -21
  176. package/src/health/health-registry.test.ts +8 -1
  177. package/src/index.ts +8 -0
  178. package/src/intake/content-classifier.test.ts +121 -51
  179. package/src/intake/dedup-gate.test.ts +38 -22
  180. package/src/intake/intake-pipeline.test.ts +5 -3
  181. package/src/intake/text-ingester.test.ts +26 -20
  182. package/src/llm/key-pool.test.ts +1 -3
  183. package/src/llm/llm-client.test.ts +1 -4
  184. package/src/llm/oauth-discovery.test.ts +16 -16
  185. package/src/llm/utils.test.ts +62 -18
  186. package/src/logging/logger.test.ts +4 -1
  187. package/src/loop/loop-manager.test.ts +2 -6
  188. package/src/migrations/migration-runner.edge-cases.test.ts +2 -7
  189. package/src/operator/operator-profile-extended.test.ts +15 -5
  190. package/src/operator/operator-profile.test.ts +26 -8
  191. package/src/operator/operator-profile.ts +38 -22
  192. package/src/operator/operator-signals-extended.test.ts +35 -23
  193. package/src/operator/operator-signals.test.ts +6 -10
  194. package/src/operator/operator-signals.ts +2 -1
  195. package/src/operator/prompts/hook-precompact-operator-dispatch.md +10 -6
  196. package/src/operator/prompts/subagent-soft-signal-extractor.md +5 -0
  197. package/src/operator/prompts/subagent-synthesis-cognition.md +19 -10
  198. package/src/operator/prompts/subagent-synthesis-communication.md +13 -7
  199. package/src/operator/prompts/subagent-synthesis-technical.md +19 -9
  200. package/src/operator/prompts/subagent-synthesis-trust.md +27 -21
  201. package/src/persona/defaults.test.ts +1 -5
  202. package/src/planning/evidence-collector.test.ts +147 -38
  203. package/src/planning/evidence-collector.ts +1 -4
  204. package/src/planning/gap-analysis-alternatives.test.ts +41 -11
  205. package/src/planning/gap-passes.test.ts +215 -33
  206. package/src/planning/gap-passes.ts +115 -46
  207. package/src/planning/gap-patterns.test.ts +87 -13
  208. package/src/planning/gap-patterns.ts +114 -31
  209. package/src/planning/github-projection.test.ts +6 -1
  210. package/src/planning/github-projection.ts +41 -20
  211. package/src/planning/impact-analyzer.test.ts +10 -23
  212. package/src/planning/impact-analyzer.ts +33 -46
  213. package/src/planning/plan-lifecycle.test.ts +103 -36
  214. package/src/planning/plan-lifecycle.ts +49 -18
  215. package/src/planning/planner.test.ts +12 -2
  216. package/src/planning/planner.ts +198 -58
  217. package/src/planning/rationalization-detector.test.ts +5 -20
  218. package/src/planning/rationalization-detector.ts +14 -16
  219. package/src/planning/reconciliation-engine.test.ts +20 -3
  220. package/src/planning/reconciliation-engine.ts +1 -2
  221. package/src/planning/task-complexity-assessor.test.ts +298 -0
  222. package/src/planning/task-complexity-assessor.ts +183 -0
  223. package/src/planning/task-verifier.test.ts +59 -27
  224. package/src/planning/task-verifier.ts +15 -9
  225. package/src/playbooks/playbook-executor.test.ts +1 -3
  226. package/src/plugins/plugin-loader.test.ts +19 -14
  227. package/src/plugins/plugin-registry.test.ts +45 -33
  228. package/src/project/project-registry.test.ts +23 -12
  229. package/src/prompts/template-manager.test.ts +4 -1
  230. package/src/queue/job-queue.test.ts +10 -14
  231. package/src/runtime/admin-extra-ops.test.ts +5 -19
  232. package/src/runtime/admin-ops.test.ts +22 -1
  233. package/src/runtime/admin-ops.ts +19 -0
  234. package/src/runtime/admin-setup-ops.test.ts +3 -4
  235. package/src/runtime/admin-setup-ops.ts +9 -2
  236. package/src/runtime/archive-ops.test.ts +4 -1
  237. package/src/runtime/branching-ops.test.ts +144 -0
  238. package/src/runtime/branching-ops.ts +107 -0
  239. package/src/runtime/capture-ops.test.ts +7 -21
  240. package/src/runtime/chain-ops.test.ts +16 -6
  241. package/src/runtime/claude-md-helpers.test.ts +1 -3
  242. package/src/runtime/context-health.test.ts +1 -3
  243. package/src/runtime/context-health.ts +1 -3
  244. package/src/runtime/curator-extra-ops.test.ts +3 -1
  245. package/src/runtime/domain-ops.test.ts +46 -36
  246. package/src/runtime/facades/admin-facade.test.ts +1 -4
  247. package/src/runtime/facades/archive-facade.test.ts +21 -7
  248. package/src/runtime/facades/brain-facade.test.ts +176 -72
  249. package/src/runtime/facades/branching-facade.test.ts +43 -0
  250. package/src/runtime/facades/branching-facade.ts +11 -0
  251. package/src/runtime/facades/chat-facade.test.ts +81 -28
  252. package/src/runtime/facades/chat-service-ops.test.ts +178 -73
  253. package/src/runtime/facades/chat-service-ops.ts +3 -1
  254. package/src/runtime/facades/chat-session-ops.test.ts +25 -10
  255. package/src/runtime/facades/chat-transport-ops.test.ts +101 -34
  256. package/src/runtime/facades/chat-transport-ops.ts +0 -1
  257. package/src/runtime/facades/context-facade.test.ts +19 -4
  258. package/src/runtime/facades/control-facade.test.ts +3 -3
  259. package/src/runtime/facades/index.ts +42 -0
  260. package/src/runtime/facades/intake-facade.test.ts +215 -0
  261. package/src/runtime/facades/intake-facade.ts +14 -0
  262. package/src/runtime/facades/links-facade.test.ts +203 -0
  263. package/src/runtime/facades/links-facade.ts +13 -0
  264. package/src/runtime/facades/loop-facade.test.ts +22 -5
  265. package/src/runtime/facades/memory-facade.test.ts +19 -5
  266. package/src/runtime/facades/operator-facade.test.ts +17 -4
  267. package/src/runtime/facades/operator-facade.ts +11 -3
  268. package/src/runtime/facades/orchestrate-facade.test.ts +7 -1
  269. package/src/runtime/facades/plan-facade.test.ts +29 -12
  270. package/src/runtime/facades/plan-facade.ts +7 -2
  271. package/src/runtime/facades/tier-facade.test.ts +47 -0
  272. package/src/runtime/facades/tier-facade.ts +11 -0
  273. package/src/runtime/facades/vault-facade.test.ts +174 -242
  274. package/src/runtime/facades/vault-facade.ts +55 -199
  275. package/src/runtime/github-integration.ts +11 -8
  276. package/src/runtime/grading-ops.test.ts +39 -8
  277. package/src/runtime/intake-ops.test.ts +69 -16
  278. package/src/runtime/loop-ops.test.ts +16 -6
  279. package/src/runtime/memory-cross-project-ops.test.ts +25 -14
  280. package/src/runtime/orchestrate-ops.test.ts +204 -0
  281. package/src/runtime/orchestrate-ops.ts +103 -65
  282. package/src/runtime/pack-ops.test.ts +23 -6
  283. package/src/runtime/planning-extra-ops.test.ts +17 -7
  284. package/src/runtime/planning-extra-ops.ts +3 -1
  285. package/src/runtime/playbook-ops.test.ts +26 -3
  286. package/src/runtime/plugin-ops.test.ts +83 -25
  287. package/src/runtime/project-ops.test.ts +26 -6
  288. package/src/runtime/runtime.ts +3 -1
  289. package/src/runtime/session-briefing.test.ts +183 -54
  290. package/src/runtime/session-briefing.ts +8 -2
  291. package/src/runtime/sync-ops.test.ts +3 -12
  292. package/src/runtime/telemetry-ops.test.ts +31 -6
  293. package/src/runtime/tier-ops.test.ts +159 -0
  294. package/src/runtime/tier-ops.ts +119 -0
  295. package/src/runtime/vault-extra-ops.test.ts +32 -8
  296. package/src/runtime/vault-sharing-ops.test.ts +1 -4
  297. package/src/skills/sync-skills.ts +2 -12
  298. package/src/transport/ws-server.test.ts +7 -4
  299. package/src/vault/__tests__/vault-characterization.test.ts +492 -81
  300. package/src/vault/linking.test.ts +50 -17
  301. package/src/vault/linking.ts +48 -7
  302. package/src/vault/obsidian-sync.test.ts +6 -3
  303. package/src/vault/scope-detector.test.ts +1 -3
  304. package/src/vault/vault-branching.test.ts +9 -7
  305. package/src/vault/vault-entries.ts +209 -65
  306. package/src/vault/vault-maintenance.ts +7 -12
  307. package/src/vault/vault-manager.test.ts +10 -10
  308. package/src/vault/vault-markdown-sync.ts +4 -1
  309. package/src/vault/vault-memories.ts +7 -7
  310. package/src/vault/vault-scaling.test.ts +5 -5
  311. package/src/vault/vault-schema.ts +72 -15
  312. package/src/vault/vault.ts +55 -9
  313. package/src/brain/strength-scorer.ts +0 -404
  314. package/src/engine/index.ts +0 -21
  315. package/src/persona/index.ts +0 -9
  316. package/src/vault/vault-interfaces.ts +0 -56
@@ -11,19 +11,40 @@ export * from './reconciliation-engine.js';
11
11
  export * from './task-verifier.js';
12
12
  export * from './planner-types.js';
13
13
  import type {
14
- TaskStatus, PlanTask, Plan, PlanStore, PlanCheck, PlannerOptions,
14
+ TaskStatus,
15
+ PlanTask,
16
+ Plan,
17
+ PlanStore,
18
+ PlanCheck,
19
+ PlannerOptions,
15
20
  } from './planner-types.js';
16
21
  import {
17
- applyTransition, scoreToGrade, gradeToMinScore, PlanGradeRejectionError,
18
- hasCircularDependencies, applyIteration, applySplitTasks, calculateScore,
19
- applyTaskStatusUpdate, createPlanObject,
22
+ applyTransition,
23
+ scoreToGrade,
24
+ gradeToMinScore,
25
+ PlanGradeRejectionError,
26
+ hasCircularDependencies,
27
+ applyIteration,
28
+ applySplitTasks,
29
+ calculateScore,
30
+ applyTaskStatusUpdate,
31
+ createPlanObject,
20
32
  } from './plan-lifecycle.js';
21
33
  import type { PlanStatus, PlanGrade, IterateChanges } from './plan-lifecycle.js';
22
- import { buildReconciliationReport, buildAutoReconcileInput, computeExecutionSummary } from './reconciliation-engine.js';
34
+ import {
35
+ buildReconciliationReport,
36
+ buildAutoReconcileInput,
37
+ computeExecutionSummary,
38
+ } from './reconciliation-engine.js';
23
39
  import type { ReconcileInput } from './reconciliation-engine.js';
24
40
  import {
25
- createEvidence, verifyTaskLogic, verifyPlanLogic, verifyDeliverablesLogic,
26
- createDeliverable, buildSpecReviewPrompt, buildQualityReviewPrompt,
41
+ createEvidence,
42
+ verifyTaskLogic,
43
+ verifyPlanLogic,
44
+ verifyDeliverablesLogic,
45
+ createDeliverable,
46
+ buildSpecReviewPrompt,
47
+ buildQualityReviewPrompt,
27
48
  } from './task-verifier.js';
28
49
 
29
50
  export class Planner {
@@ -51,7 +72,9 @@ export class Planner {
51
72
  const store = JSON.parse(data) as PlanStore;
52
73
  for (const plan of store.plans) plan.checks = plan.checks ?? [];
53
74
  return store;
54
- } catch { return { version: '1.0', plans: [] }; }
75
+ } catch {
76
+ return { version: '1.0', plans: [] };
77
+ }
55
78
  }
56
79
 
57
80
  private save(): void {
@@ -88,7 +111,9 @@ export class Planner {
88
111
  return this.store.plans.find((p) => p.id === planId) ?? null;
89
112
  }
90
113
 
91
- list(): Plan[] { return [...this.store.plans]; }
114
+ list(): Plan[] {
115
+ return [...this.store.plans];
116
+ }
92
117
 
93
118
  remove(planId: string): boolean {
94
119
  const idx = this.store.plans.findIndex((p) => p.id === planId);
@@ -109,7 +134,12 @@ export class Planner {
109
134
  const plan = this.requirePlan(planId);
110
135
  const check = plan.latestCheck;
111
136
  if (check && check.score < gradeToMinScore(this.minGradeForApproval)) {
112
- throw new PlanGradeRejectionError(check.grade, check.score, this.minGradeForApproval, check.gaps);
137
+ throw new PlanGradeRejectionError(
138
+ check.grade,
139
+ check.score,
140
+ this.minGradeForApproval,
141
+ check.gaps,
142
+ );
113
143
  }
114
144
  this.transition(plan, 'approved');
115
145
  this.save();
@@ -140,7 +170,9 @@ export class Planner {
140
170
  updateTask(planId: string, taskId: string, status: TaskStatus): Plan {
141
171
  const plan = this.requirePlan(planId);
142
172
  if (plan.status !== 'executing' && plan.status !== 'validating')
143
- throw new Error(`Cannot update tasks on plan in '${plan.status}' status — must be 'executing' or 'validating'`);
173
+ throw new Error(
174
+ `Cannot update tasks on plan in '${plan.status}' status — must be 'executing' or 'validating'`,
175
+ );
144
176
  applyTaskStatusUpdate(this.requireTask(plan, taskId), status);
145
177
  plan.updatedAt = Date.now();
146
178
  this.save();
@@ -149,8 +181,14 @@ export class Planner {
149
181
 
150
182
  reconcile(planId: string, report: ReconcileInput): Plan {
151
183
  const plan = this.requirePlan(planId);
152
- if (plan.status !== 'executing' && plan.status !== 'validating' && plan.status !== 'reconciling')
153
- throw new Error(`Cannot reconcile plan in '${plan.status}' status — must be 'executing', 'validating', or 'reconciling'`);
184
+ if (
185
+ plan.status !== 'executing' &&
186
+ plan.status !== 'validating' &&
187
+ plan.status !== 'reconciling'
188
+ )
189
+ throw new Error(
190
+ `Cannot reconcile plan in '${plan.status}' status — must be 'executing', 'validating', or 'reconciling'`,
191
+ );
154
192
  plan.reconciliation = buildReconciliationReport(planId, report);
155
193
  plan.executionSummary = computeExecutionSummary(plan.tasks);
156
194
  if (plan.status === 'executing' || plan.status === 'validating') plan.status = 'reconciling';
@@ -173,7 +211,9 @@ export class Planner {
173
211
  autoReconcile(planId: string): Plan | null {
174
212
  const plan = this.requirePlan(planId);
175
213
  if (plan.status !== 'executing' && plan.status !== 'validating')
176
- throw new Error(`Cannot auto-reconcile plan in '${plan.status}' status — must be 'executing' or 'validating'`);
214
+ throw new Error(
215
+ `Cannot auto-reconcile plan in '${plan.status}' status — must be 'executing' or 'validating'`,
216
+ );
177
217
  const result = buildAutoReconcileInput(plan.tasks);
178
218
  if (!result.canAutoReconcile || !result.input) return null;
179
219
  return this.reconcile(planId, result.input);
@@ -184,51 +224,81 @@ export class Planner {
184
224
  }
185
225
 
186
226
  getActive(): Plan[] {
187
- return this.store.plans.filter((p) =>
188
- p.status === 'brainstorming' || p.status === 'draft' || p.status === 'approved' ||
189
- p.status === 'executing' || p.status === 'validating' || p.status === 'reconciling');
227
+ return this.store.plans.filter(
228
+ (p) =>
229
+ p.status === 'brainstorming' ||
230
+ p.status === 'draft' ||
231
+ p.status === 'approved' ||
232
+ p.status === 'executing' ||
233
+ p.status === 'validating' ||
234
+ p.status === 'reconciling',
235
+ );
190
236
  }
191
237
 
192
238
  iterate(planId: string, changes: IterateChanges): Plan {
193
239
  const plan = this.requirePlan(planId);
194
240
  if (plan.status !== 'draft' && plan.status !== 'brainstorming')
195
- throw new Error(`Cannot iterate plan in '${plan.status}' status — must be 'draft' or 'brainstorming'`);
241
+ throw new Error(
242
+ `Cannot iterate plan in '${plan.status}' status — must be 'draft' or 'brainstorming'`,
243
+ );
196
244
  applyIteration(plan, changes);
197
245
  this.save();
198
246
  return plan;
199
247
  }
200
248
 
201
- splitTasks(planId: string, tasks: Array<{
202
- title: string; description: string; dependsOn?: string[]; acceptanceCriteria?: string[];
203
- }>): Plan {
249
+ splitTasks(
250
+ planId: string,
251
+ tasks: Array<{
252
+ title: string;
253
+ description: string;
254
+ dependsOn?: string[];
255
+ acceptanceCriteria?: string[];
256
+ }>,
257
+ ): Plan {
204
258
  const plan = this.requirePlan(planId);
205
259
  if (plan.status !== 'brainstorming' && plan.status !== 'draft' && plan.status !== 'approved')
206
- throw new Error(`Cannot split tasks on plan in '${plan.status}' status — must be 'brainstorming', 'draft', or 'approved'`);
260
+ throw new Error(
261
+ `Cannot split tasks on plan in '${plan.status}' status — must be 'brainstorming', 'draft', or 'approved'`,
262
+ );
207
263
  applySplitTasks(plan, tasks);
208
264
  this.save();
209
265
  return plan;
210
266
  }
211
267
 
212
- addReview(planId: string, review: {
213
- taskId?: string; reviewer: string;
214
- outcome: 'approved' | 'rejected' | 'needs_changes'; comments: string;
215
- }): Plan {
268
+ addReview(
269
+ planId: string,
270
+ review: {
271
+ taskId?: string;
272
+ reviewer: string;
273
+ outcome: 'approved' | 'rejected' | 'needs_changes';
274
+ comments: string;
275
+ },
276
+ ): Plan {
216
277
  const plan = this.requirePlan(planId);
217
278
  if (review.taskId) this.requireTask(plan, review.taskId);
218
279
  if (!plan.reviews) plan.reviews = [];
219
280
  plan.reviews.push({
220
- planId, taskId: review.taskId, reviewer: review.reviewer,
221
- outcome: review.outcome, comments: review.comments, reviewedAt: Date.now(),
281
+ planId,
282
+ taskId: review.taskId,
283
+ reviewer: review.reviewer,
284
+ outcome: review.outcome,
285
+ comments: review.comments,
286
+ reviewedAt: Date.now(),
222
287
  });
223
288
  plan.updatedAt = Date.now();
224
289
  this.save();
225
290
  return plan;
226
291
  }
227
292
 
228
- setGitHubProjection(planId: string, projection: {
229
- repo: string; milestone?: number;
230
- issues: Array<{ taskId: string; issueNumber: number }>; projectedAt: number;
231
- }): Plan {
293
+ setGitHubProjection(
294
+ planId: string,
295
+ projection: {
296
+ repo: string;
297
+ milestone?: number;
298
+ issues: Array<{ taskId: string; issueNumber: number }>;
299
+ projectedAt: number;
300
+ },
301
+ ): Plan {
232
302
  const plan = this.requirePlan(planId);
233
303
  plan.githubProjection = projection;
234
304
  plan.updatedAt = Date.now();
@@ -236,8 +306,13 @@ export class Planner {
236
306
  return plan;
237
307
  }
238
308
 
239
- getDispatch(planId: string, taskId: string): {
240
- task: PlanTask; unmetDependencies: PlanTask[]; ready: boolean;
309
+ getDispatch(
310
+ planId: string,
311
+ taskId: string,
312
+ ): {
313
+ task: PlanTask;
314
+ unmetDependencies: PlanTask[];
315
+ ready: boolean;
241
316
  deliverableStatus?: { count: number; staleCount: number };
242
317
  } {
243
318
  const plan = this.requirePlan(planId);
@@ -248,14 +323,21 @@ export class Planner {
248
323
  if (dep && dep.status !== 'completed') unmetDeps.push(dep);
249
324
  }
250
325
  return {
251
- task, unmetDependencies: unmetDeps, ready: unmetDeps.length === 0,
326
+ task,
327
+ unmetDependencies: unmetDeps,
328
+ ready: unmetDeps.length === 0,
252
329
  ...(task.deliverables?.length && {
253
- deliverableStatus: { count: task.deliverables.length, staleCount: task.deliverables.filter((d) => d.stale).length },
330
+ deliverableStatus: {
331
+ count: task.deliverables.length,
332
+ staleCount: task.deliverables.filter((d) => d.stale).length,
333
+ },
254
334
  }),
255
335
  };
256
336
  }
257
337
 
258
- submitDeliverable(planId: string, taskId: string,
338
+ submitDeliverable(
339
+ planId: string,
340
+ taskId: string,
259
341
  deliverable: { type: 'file' | 'vault_entry' | 'url'; path: string; hash?: string },
260
342
  ): PlanTask {
261
343
  const plan = this.requirePlan(planId);
@@ -268,9 +350,15 @@ export class Planner {
268
350
  return task;
269
351
  }
270
352
 
271
- verifyDeliverables(planId: string, taskId: string,
353
+ verifyDeliverables(
354
+ planId: string,
355
+ taskId: string,
272
356
  vault?: { get(id: string): unknown | null },
273
- ): { verified: boolean; deliverables: import('./planner-types.js').TaskDeliverable[]; staleCount: number } {
357
+ ): {
358
+ verified: boolean;
359
+ deliverables: import('./planner-types.js').TaskDeliverable[];
360
+ staleCount: number;
361
+ } {
274
362
  const plan = this.requirePlan(planId);
275
363
  const task = this.requireTask(plan, taskId);
276
364
  const result = verifyDeliverablesLogic(task.deliverables ?? [], vault);
@@ -280,8 +368,14 @@ export class Planner {
280
368
  return result;
281
369
  }
282
370
 
283
- submitEvidence(planId: string, taskId: string,
284
- evidence: { criterion: string; content: string; type: import('./planner-types.js').TaskEvidence['type'] },
371
+ submitEvidence(
372
+ planId: string,
373
+ taskId: string,
374
+ evidence: {
375
+ criterion: string;
376
+ content: string;
377
+ type: import('./planner-types.js').TaskEvidence['type'];
378
+ },
285
379
  ): PlanTask {
286
380
  const plan = this.requirePlan(planId);
287
381
  const task = this.requireTask(plan, taskId);
@@ -292,8 +386,13 @@ export class Planner {
292
386
  return task;
293
387
  }
294
388
 
295
- verifyTask(planId: string, taskId: string): {
296
- verified: boolean; task: PlanTask; missingCriteria: string[];
389
+ verifyTask(
390
+ planId: string,
391
+ taskId: string,
392
+ ): {
393
+ verified: boolean;
394
+ task: PlanTask;
395
+ missingCriteria: string[];
297
396
  reviewStatus: 'approved' | 'rejected' | 'needs_changes' | 'no_reviews';
298
397
  } {
299
398
  const plan = this.requirePlan(planId);
@@ -312,35 +411,65 @@ export class Planner {
312
411
  return verifyPlanLogic(planId, this.requirePlan(planId).tasks);
313
412
  }
314
413
 
315
- generateReviewSpec(planId: string, taskId: string): { prompt: string; task: PlanTask; plan: Plan } {
414
+ generateReviewSpec(
415
+ planId: string,
416
+ taskId: string,
417
+ ): { prompt: string; task: PlanTask; plan: Plan } {
316
418
  const plan = this.requirePlan(planId);
317
419
  const task = this.requireTask(plan, taskId);
318
420
  return { prompt: buildSpecReviewPrompt(task, plan.objective), task, plan };
319
421
  }
320
422
 
321
- generateReviewQuality(planId: string, taskId: string): { prompt: string; task: PlanTask; plan: Plan } {
423
+ generateReviewQuality(
424
+ planId: string,
425
+ taskId: string,
426
+ ): { prompt: string; task: PlanTask; plan: Plan } {
322
427
  const plan = this.requirePlan(planId);
323
428
  const task = this.requireTask(plan, taskId);
324
429
  return { prompt: buildQualityReviewPrompt(task), task, plan };
325
430
  }
326
431
 
327
432
  archive(olderThanDays?: number): Plan[] {
328
- const cutoff = olderThanDays !== undefined
329
- ? Date.now() - olderThanDays * 24 * 60 * 60 * 1000 : Date.now() + 1;
330
- const toArchive = this.store.plans.filter((p) => p.status === 'completed' && p.updatedAt < cutoff);
331
- for (const plan of toArchive) { plan.status = 'archived'; plan.updatedAt = Date.now(); }
433
+ const cutoff =
434
+ olderThanDays !== undefined
435
+ ? Date.now() - olderThanDays * 24 * 60 * 60 * 1000
436
+ : Date.now() + 1;
437
+ const toArchive = this.store.plans.filter(
438
+ (p) => p.status === 'completed' && p.updatedAt < cutoff,
439
+ );
440
+ for (const plan of toArchive) {
441
+ plan.status = 'archived';
442
+ plan.updatedAt = Date.now();
443
+ }
332
444
  if (toArchive.length > 0) this.save();
333
445
  return toArchive;
334
446
  }
335
447
 
336
448
  stats(): {
337
- total: number; byStatus: Record<PlanStatus, number>;
338
- avgTasksPerPlan: number; totalTasks: number; tasksByStatus: Record<TaskStatus, number>;
449
+ total: number;
450
+ byStatus: Record<PlanStatus, number>;
451
+ avgTasksPerPlan: number;
452
+ totalTasks: number;
453
+ tasksByStatus: Record<TaskStatus, number>;
339
454
  } {
340
455
  const plans = this.store.plans;
341
- const byStatus = { brainstorming: 0, draft: 0, approved: 0, executing: 0,
342
- validating: 0, reconciling: 0, completed: 0, archived: 0 } as Record<PlanStatus, number>;
343
- const tasksByStatus = { pending: 0, in_progress: 0, completed: 0, skipped: 0, failed: 0 } as Record<TaskStatus, number>;
456
+ const byStatus = {
457
+ brainstorming: 0,
458
+ draft: 0,
459
+ approved: 0,
460
+ executing: 0,
461
+ validating: 0,
462
+ reconciling: 0,
463
+ completed: 0,
464
+ archived: 0,
465
+ } as Record<PlanStatus, number>;
466
+ const tasksByStatus = {
467
+ pending: 0,
468
+ in_progress: 0,
469
+ completed: 0,
470
+ skipped: 0,
471
+ failed: 0,
472
+ } as Record<TaskStatus, number>;
344
473
  let totalTasks = 0;
345
474
  for (const p of plans) {
346
475
  byStatus[p.status]++;
@@ -348,7 +477,10 @@ export class Planner {
348
477
  for (const t of p.tasks) tasksByStatus[t.status]++;
349
478
  }
350
479
  return {
351
- total: plans.length, byStatus, totalTasks, tasksByStatus,
480
+ total: plans.length,
481
+ byStatus,
482
+ totalTasks,
483
+ tasksByStatus,
352
484
  avgTasksPerPlan: plans.length > 0 ? Math.round((totalTasks / plans.length) * 100) / 100 : 0,
353
485
  };
354
486
  }
@@ -358,17 +490,25 @@ export class Planner {
358
490
  const gaps = runGapAnalysis(plan, this.gapOptions);
359
491
  if (hasCircularDependencies(plan.tasks)) {
360
492
  gaps.push({
361
- id: `gap_${Date.now()}_circ`, severity: 'critical', category: 'structure',
493
+ id: `gap_${Date.now()}_circ`,
494
+ severity: 'critical',
495
+ category: 'structure',
362
496
  description: 'Circular dependencies detected among tasks.',
363
497
  recommendation: 'Remove circular dependency chains so tasks can be executed in order.',
364
- location: 'tasks', _trigger: 'circular_dependencies',
498
+ location: 'tasks',
499
+ _trigger: 'circular_dependencies',
365
500
  });
366
501
  }
367
502
  const iteration = plan.checks.length + 1;
368
503
  const score = calculateScore(gaps, iteration);
369
504
  const check: PlanCheck = {
370
505
  checkId: `chk-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
371
- planId, grade: scoreToGrade(score), score, gaps, iteration, checkedAt: Date.now(),
506
+ planId,
507
+ grade: scoreToGrade(score),
508
+ score,
509
+ gaps,
510
+ iteration,
511
+ checkedAt: Date.now(),
372
512
  };
373
513
  plan.checks.push(check);
374
514
  plan.latestCheck = check;
@@ -31,10 +31,7 @@ describe('detectRationalizations', () => {
31
31
  });
32
32
 
33
33
  it('detects "follow-up PR" pattern', () => {
34
- const report = detectRationalizations(
35
- CRITERIA,
36
- 'Test coverage bump deferred to follow-up PR.',
37
- );
34
+ const report = detectRationalizations(CRITERIA, 'Test coverage bump deferred to follow-up PR.');
38
35
  expect(report.detected).toBe(true);
39
36
  expect(report.items[0].pattern).toBe('follow-up-ticket');
40
37
  });
@@ -98,19 +95,13 @@ describe('detectRationalizations', () => {
98
95
  // ─── Case-insensitive matching ──────────────────────────────
99
96
 
100
97
  it('matches case-insensitively (uppercase)', () => {
101
- const report = detectRationalizations(
102
- CRITERIA,
103
- 'This is OUT OF SCOPE for the current work.',
104
- );
98
+ const report = detectRationalizations(CRITERIA, 'This is OUT OF SCOPE for the current work.');
105
99
  expect(report.detected).toBe(true);
106
100
  expect(report.items[0].pattern).toBe('out-of-scope');
107
101
  });
108
102
 
109
103
  it('matches case-insensitively (mixed case)', () => {
110
- const report = detectRationalizations(
111
- CRITERIA,
112
- 'That is a Pre-Existing Issue we inherited.',
113
- );
104
+ const report = detectRationalizations(CRITERIA, 'That is a Pre-Existing Issue we inherited.');
114
105
  expect(report.detected).toBe(true);
115
106
  expect(report.items[0].pattern).toBe('pre-existing-issue');
116
107
  });
@@ -118,10 +109,7 @@ describe('detectRationalizations', () => {
118
109
  // ─── Empty/skip cases ──────────────────────────────────────
119
110
 
120
111
  it('skips detection when acceptance criteria are empty', () => {
121
- const report = detectRationalizations(
122
- [],
123
- 'This is out of scope and a pre-existing issue.',
124
- );
112
+ const report = detectRationalizations([], 'This is out of scope and a pre-existing issue.');
125
113
  expect(report.detected).toBe(false);
126
114
  expect(report.items).toHaveLength(0);
127
115
  });
@@ -158,10 +146,7 @@ describe('detectRationalizations', () => {
158
146
  // ─── Suggestion is always present ──────────────────────────
159
147
 
160
148
  it('provides actionable suggestions for each item', () => {
161
- const report = detectRationalizations(
162
- CRITERIA,
163
- 'This is out of scope and over-engineering.',
164
- );
149
+ const report = detectRationalizations(CRITERIA, 'This is out of scope and over-engineering.');
165
150
  expect(report.detected).toBe(true);
166
151
  for (const item of report.items) {
167
152
  expect(item.suggestion).toBeTruthy();
@@ -37,32 +37,38 @@ const PATTERNS: RationalizationPattern[] = [
37
37
  {
38
38
  name: 'out-of-scope',
39
39
  regex: /out\s+of\s+scope/i,
40
- suggestion: 'If it was in the acceptance criteria, it is in scope. Remove from criteria or complete it.',
40
+ suggestion:
41
+ 'If it was in the acceptance criteria, it is in scope. Remove from criteria or complete it.',
41
42
  },
42
43
  {
43
44
  name: 'follow-up-ticket',
44
45
  regex: /follow[- ]?up\s+(ticket|issue|pr|task)/i,
45
- suggestion: 'Deferring to a follow-up means the criterion is unmet. Complete it now or revise the plan.',
46
+ suggestion:
47
+ 'Deferring to a follow-up means the criterion is unmet. Complete it now or revise the plan.',
46
48
  },
47
49
  {
48
50
  name: 'pre-existing-issue',
49
51
  regex: /pre[- ]?existing\s+(issue|bug|problem)/i,
50
- suggestion: 'Pre-existing or not, the criterion expects it resolved. Fix it or remove the criterion.',
52
+ suggestion:
53
+ 'Pre-existing or not, the criterion expects it resolved. Fix it or remove the criterion.',
51
54
  },
52
55
  {
53
56
  name: 'over-engineering',
54
57
  regex: /over[- ]?engineering/i,
55
- suggestion: 'Meeting acceptance criteria is not over-engineering. Implement what was agreed upon.',
58
+ suggestion:
59
+ 'Meeting acceptance criteria is not over-engineering. Implement what was agreed upon.',
56
60
  },
57
61
  {
58
62
  name: 'separate-pr',
59
63
  regex: /separate\s+(pr|task|ticket|issue)/i,
60
- suggestion: 'Splitting into a separate PR defers the work. Complete the criterion or update the plan.',
64
+ suggestion:
65
+ 'Splitting into a separate PR defers the work. Complete the criterion or update the plan.',
61
66
  },
62
67
  {
63
68
  name: 'too-complex',
64
69
  regex: /too\s+complex\s+for\s+this\s+(task|pr|ticket|issue|scope)/i,
65
- suggestion: 'Complexity was known at planning time. Revisit the plan or complete the criterion.',
70
+ suggestion:
71
+ 'Complexity was known at planning time. Revisit the plan or complete the criterion.',
66
72
  },
67
73
  ];
68
74
 
@@ -91,11 +97,7 @@ export function detectRationalizations(
91
97
  if (!match) continue;
92
98
 
93
99
  // Find which criterion is being rationalized (nearest mention)
94
- const criterion = findRelatedCriterion(
95
- acceptanceCriteria,
96
- completionClaim,
97
- match.index,
98
- );
100
+ const criterion = findRelatedCriterion(acceptanceCriteria, completionClaim, match.index);
99
101
 
100
102
  items.push({
101
103
  criterion,
@@ -114,11 +116,7 @@ export function detectRationalizations(
114
116
  * Find the acceptance criterion most related to the rationalization phrase
115
117
  * by checking which criterion text appears closest to the match position.
116
118
  */
117
- function findRelatedCriterion(
118
- criteria: string[],
119
- claim: string,
120
- matchIndex: number,
121
- ): string {
119
+ function findRelatedCriterion(criteria: string[], claim: string, matchIndex: number): string {
122
120
  const claimLower = claim.toLowerCase();
123
121
  let bestCriterion = criteria[0];
124
122
  let bestDistance = Infinity;
@@ -36,7 +36,10 @@ describe('reconciliation-engine', () => {
36
36
  });
37
37
  it('floors at 0', () => {
38
38
  const items: DriftItem[] = Array.from({ length: 10 }, () => ({
39
- type: 'skipped' as const, description: 'x', impact: 'high' as const, rationale: 'r',
39
+ type: 'skipped' as const,
40
+ description: 'x',
41
+ impact: 'high' as const,
42
+ rationale: 'r',
40
43
  }));
41
44
  expect(calculateDriftScore(items)).toBe(0);
42
45
  });
@@ -63,8 +66,22 @@ describe('reconciliation-engine', () => {
63
66
  });
64
67
  it('computes average duration from tasks with metrics', () => {
65
68
  const tasks: PlanTask[] = [
66
- { id: 't1', title: '', description: '', status: 'completed', updatedAt: 0, metrics: { durationMs: 100 } },
67
- { id: 't2', title: '', description: '', status: 'completed', updatedAt: 0, metrics: { durationMs: 200 } },
69
+ {
70
+ id: 't1',
71
+ title: '',
72
+ description: '',
73
+ status: 'completed',
74
+ updatedAt: 0,
75
+ metrics: { durationMs: 100 },
76
+ },
77
+ {
78
+ id: 't2',
79
+ title: '',
80
+ description: '',
81
+ status: 'completed',
82
+ updatedAt: 0,
83
+ metrics: { durationMs: 200 },
84
+ },
68
85
  { id: 't3', title: '', description: '', status: 'completed', updatedAt: 0 }, // no metrics
69
86
  ];
70
87
  const summary = computeExecutionSummary(tasks);
@@ -65,8 +65,7 @@ export function computeExecutionSummary(tasks: ReadonlyArray<PlanTask>): Executi
65
65
  tasksCompleted,
66
66
  tasksSkipped,
67
67
  tasksFailed,
68
- avgTaskDurationMs:
69
- tasksWithDuration > 0 ? Math.round(totalDurationMs / tasksWithDuration) : 0,
68
+ avgTaskDurationMs: tasksWithDuration > 0 ? Math.round(totalDurationMs / tasksWithDuration) : 0,
70
69
  };
71
70
  }
72
71