opencode-wait-a-minute 0.0.0-stage → 1.1.0-rc.10

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 (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +318 -2
  3. package/index.js +1836 -0
  4. package/package.json +70 -4
  5. package/skills/codebase-design/SKILL.md +114 -0
  6. package/skills/design-contract/SKILL.md +27 -0
  7. package/skills/design-critique/SKILL.md +19 -0
  8. package/skills/design-system/SKILL.md +17 -0
  9. package/skills/design-system/references/image-analysis.md +14 -0
  10. package/skills/design-system/references/tokens.md +32 -0
  11. package/skills/design-system/references/ui-rules.md +14 -0
  12. package/skills/diagnosing-bugs/SKILL.md +138 -0
  13. package/skills/frontend-design/SKILL.md +36 -0
  14. package/skills/handoff/SKILL.md +16 -0
  15. package/skills/improve-codebase-architecture/SKILL.md +71 -0
  16. package/skills/linter-negative/SKILL.md +74 -0
  17. package/skills/no-slop-ui/SKILL.md +26 -0
  18. package/skills/prototype/SKILL.md +26 -0
  19. package/skills/registry.json +44087 -0
  20. package/skills/tastemaker/SKILL.md +8 -0
  21. package/skills/tastemaker/references/tastemaker.md +14 -0
  22. package/skills/tdd/SKILL.md +38 -0
  23. package/skills/visual-review/SKILL.md +103 -0
  24. package/skills/visual-review/references/review-gates.md +42 -0
  25. package/skills/visual-review/references/surface-archetypes.md +37 -0
  26. package/skills/wizard/SKILL.md +44 -0
  27. package/skills/writing-for-agents/SKILL.md +81 -0
  28. package/src/cognition/cognition-store.js +251 -0
  29. package/src/cognition/cognitive-state.js +126 -0
  30. package/src/cognition/hypothesis-manager.js +113 -0
  31. package/src/cognition/observation-engine.js +112 -0
  32. package/src/cognition/observation-provenance.js +268 -0
  33. package/src/context/active-context-boundary.js +68 -0
  34. package/src/context/assembly.js +494 -0
  35. package/src/context/assessment-rules.js +55 -0
  36. package/src/context/capsule-staleness.js +267 -0
  37. package/src/context/capsules.js +2 -0
  38. package/src/context/compare-array.js +98 -0
  39. package/src/context/compare-object.js +89 -0
  40. package/src/context/compare-values.js +42 -0
  41. package/src/context/context-assembly-contract.js +71 -0
  42. package/src/context/context-budget-manager.js +232 -0
  43. package/src/context/context-builder.js +49 -0
  44. package/src/context/context-cache.js +55 -0
  45. package/src/context/context-capture.js +243 -0
  46. package/src/context/context-classification.js +199 -0
  47. package/src/context/context-compaction.js +179 -0
  48. package/src/context/context-decision-audit.js +267 -0
  49. package/src/context/context-demotion.js +173 -0
  50. package/src/context/context-dictionary.js +106 -0
  51. package/src/context/context-drift-detection.js +225 -0
  52. package/src/context/context-evaluation.js +374 -0
  53. package/src/context/context-event-ingress.js +100 -0
  54. package/src/context/context-event-normalization.js +224 -0
  55. package/src/context/context-feedback-loop.js +216 -0
  56. package/src/context/context-freshness.js +21 -0
  57. package/src/context/context-graph-builder.js +71 -0
  58. package/src/context/context-graph.js +451 -0
  59. package/src/context/context-history-relevance.js +321 -0
  60. package/src/context/context-interception.js +145 -0
  61. package/src/context/context-invalidation-events.js +154 -0
  62. package/src/context/context-lifecycle.js +170 -0
  63. package/src/context/context-loop-prevention.js +347 -0
  64. package/src/context/context-manager.js +340 -0
  65. package/src/context/context-memory-layers.js +265 -0
  66. package/src/context/context-minimality.js +166 -0
  67. package/src/context/context-normalization.js +130 -0
  68. package/src/context/context-optimization-metrics.js +434 -0
  69. package/src/context/context-output-policy.js +135 -0
  70. package/src/context/context-pack-authority.js +157 -0
  71. package/src/context/context-promotion.js +172 -0
  72. package/src/context/context-query-contract.js +101 -0
  73. package/src/context/context-ranking.js +164 -0
  74. package/src/context/context-rate-distortion.js +261 -0
  75. package/src/context/context-recovery.js +209 -0
  76. package/src/context/context-retrieval-integration.js +60 -0
  77. package/src/context/context-retrieval.js +93 -0
  78. package/src/context/context-router.js +457 -0
  79. package/src/context/context-routing-evaluation.js +331 -0
  80. package/src/context/context-routing-observability.js +296 -0
  81. package/src/context/context-routing-shadow.js +237 -0
  82. package/src/context/context-scope.js +181 -0
  83. package/src/context/context-snapshot.js +226 -0
  84. package/src/context/context-source-registry.js +95 -0
  85. package/src/context/context-sufficiency-gate.js +120 -0
  86. package/src/context/context-sufficiency-oracle.js +167 -0
  87. package/src/context/context-telemetry.js +176 -0
  88. package/src/context/context.js +633 -0
  89. package/src/context/dependency-closure.js +246 -0
  90. package/src/context/page-fault-tracker.js +275 -0
  91. package/src/context/prompt-engine.js +74 -0
  92. package/src/context/runtime-context-graph.js +260 -0
  93. package/src/context/selection.js +2 -0
  94. package/src/context/session.js +2 -0
  95. package/src/context/sufficiency-contract.js +300 -0
  96. package/src/context/tokenizer.js +17 -0
  97. package/src/context-benchmark-router.mjs +125 -0
  98. package/src/evidence/evidence-engine.js +161 -0
  99. package/src/evidence/evidence-factory.js +3 -0
  100. package/src/evidence/evidence-freshness.js +463 -0
  101. package/src/evidence/evidence-gap.js +76 -0
  102. package/src/evidence/evidence-lineage.js +525 -0
  103. package/src/evidence/evidence.js +136 -0
  104. package/src/evidence/freshness-validation.js +187 -0
  105. package/src/evidence/lineage.js +4 -0
  106. package/src/execution/action-evaluation.js +179 -0
  107. package/src/execution/circuit-breaker.js +70 -0
  108. package/src/execution/claim-interception.js +63 -0
  109. package/src/execution/execution-engine.js +258 -0
  110. package/src/execution/execution-intent.js +69 -0
  111. package/src/execution/execution-state.js +89 -0
  112. package/src/execution/formatting.js +60 -0
  113. package/src/execution/l1-sanitize.js +16 -0
  114. package/src/execution/l2-resource-guards.js +19 -0
  115. package/src/execution/l3-invariant-checker.js +5 -0
  116. package/src/execution/l4-containment.js +6 -0
  117. package/src/execution/runtime-guards.js +106 -0
  118. package/src/execution/strategy-identity.js +162 -0
  119. package/src/execution/tool-interceptor.js +7 -0
  120. package/src/execution/tool-result-classifier.js +63 -0
  121. package/src/integration/canary-deploy.js +143 -0
  122. package/src/integration/collector.js +59 -0
  123. package/src/integration/error-recovery.js +6 -0
  124. package/src/integration/event-bus.js +66 -0
  125. package/src/integration/health-checker.js +57 -0
  126. package/src/integration/logger.js +39 -0
  127. package/src/integration/message-handler.js +611 -0
  128. package/src/integration/opencode-db.js +153 -0
  129. package/src/integration/orchestration.js +419 -0
  130. package/src/integration/part-provenance.js +65 -0
  131. package/src/integration/rate-limiter.js +55 -0
  132. package/src/integration/release-gate.js +336 -0
  133. package/src/integration/rollback-manager.js +164 -0
  134. package/src/integration/router-adapter.js +269 -0
  135. package/src/integration/telemetry.js +45 -0
  136. package/src/integration/update-checker.js +10 -0
  137. package/src/persistence/event-sourcing.js +75 -0
  138. package/src/persistence/memory.js +501 -0
  139. package/src/persistence/migration-runner.js +16 -0
  140. package/src/persistence/persistence-manager.js +39 -0
  141. package/src/persistence/transaction-log.js +157 -0
  142. package/src/policy/action-capabilities.js +116 -0
  143. package/src/policy/action-policy.js +4 -0
  144. package/src/policy/assessment-engine.js +104 -0
  145. package/src/policy/assumption-tracking.js +66 -0
  146. package/src/policy/budget-enforcer.js +7 -0
  147. package/src/policy/config-validator.js +102 -0
  148. package/src/policy/execution-assessment.js +142 -0
  149. package/src/policy/failure-classification.js +5 -0
  150. package/src/policy/feature-flags.js +65 -0
  151. package/src/policy/governance-enforcement.js +118 -0
  152. package/src/policy/locale.js +15 -0
  153. package/src/policy/multi-signer.js +151 -0
  154. package/src/policy/policy-state-machine.js +97 -0
  155. package/src/policy/ponytail-constraint.js +38 -0
  156. package/src/policy/project-inspector.js +93 -0
  157. package/src/policy/query-builder.js +14 -0
  158. package/src/policy/request-classifier.js +79 -0
  159. package/src/policy/risk-engine.js +266 -0
  160. package/src/policy/scope-enforcement.js +140 -0
  161. package/src/policy/secret-scanner.js +68 -0
  162. package/src/policy/skill-routing.js +104 -0
  163. package/src/policy/strategy-capabilities.js +211 -0
  164. package/src/policy/strategy.js +6 -0
  165. package/src/policy/uncertainty.js +117 -0
  166. package/src/shared/container.js +44 -0
  167. package/src/shared/decision-types.js +24 -0
  168. package/src/shared/simple-test.js +160 -0
  169. package/src/shared/wam-events.js +52 -0
  170. package/src/skills/engine.js +1705 -0
  171. package/src/skills/skill-registry.js +19 -0
  172. package/src/skills/skill-routing.js +340 -0
  173. package/src/state/lifecycle-manager.js +113 -0
  174. package/src/state/operational-state.js +198 -0
  175. package/src/state/projections.js +47 -0
  176. package/src/state/replay-engine.js +5 -0
  177. package/src/state/requirement-ownership.js +20 -0
  178. package/src/state/requirement-state.js +152 -0
  179. package/src/state/run-event-identity.js +172 -0
  180. package/src/state/state-engine.js +19 -0
  181. package/src/state/state-machine.js +119 -0
  182. package/src/state/state-schema.js +318 -0
  183. package/src/state/state-store.js +335 -0
  184. package/src/state/state-transition.js +84 -0
  185. package/src/state/task-dependencies.js +287 -0
  186. package/src/state/task-execution.js +217 -0
  187. package/src/state/task-lifecycle.js +59 -0
  188. package/src/state/task-runs.js +361 -0
  189. package/src/state/task-state-file.js +86 -0
  190. package/src/state/task-state.js +41 -0
  191. package/src/state/task-status.js +54 -0
  192. package/src/state/task-store.js +48 -0
  193. package/src/state/wam-state.js +148 -0
  194. package/src/verification/completion-gate-simple.js +8 -0
  195. package/src/verification/completion-gate.js +183 -0
  196. package/src/verification/contract.js +9 -0
  197. package/src/verification/contradiction-resolution.js +255 -0
  198. package/src/verification/diagnostic-engine.js +659 -0
  199. package/src/verification/false-completion-prevention.js +100 -0
  200. package/src/verification/hook-validator.js +6 -0
  201. package/src/verification/requirements.js +6 -0
  202. package/src/verification/verification-context.js +162 -0
  203. package/src/verification/verification-lifecycle.js +66 -0
  204. package/src/verification/verification-model.js +89 -0
  205. package/src/verification/verification-persistence.js +129 -0
  206. package/src/verification/verification-policy.js +127 -0
  207. package/src/verification/verification.js +415 -0
@@ -0,0 +1,84 @@
1
+ /**
2
+ * State Transition — Unified transition layer for all WAM lifecycles.
3
+ *
4
+ * Guarantees: All state transitions follow (OldState + Event) → NewState pattern.
5
+ * No scattered state mutation across modules.
6
+ */
7
+
8
+ import { PHASE_TRANSITIONS } from "../integration/orchestration.js";
9
+
10
+ /**
11
+ * Transition Task state based on event
12
+ */
13
+ export function transitionTask(state, event) {
14
+ const { type, payload } = event;
15
+
16
+ switch (type) {
17
+ case "REQUIREMENT_VERIFIED":
18
+ return {
19
+ ...state,
20
+ requirements: state.requirements.map(r =>
21
+ r.id === payload.requirementId ? { ...r, status: "verified" } : r
22
+ ),
23
+ updatedAt: Date.now()
24
+ };
25
+
26
+ case "PHASE_CHANGE":
27
+ const allowed = PHASE_TRANSITIONS[state.phase] || [];
28
+ if (!allowed.includes(payload.phase)) {
29
+ throw new Error(`Invalid phase transition: ${state.phase} → ${payload.phase}`);
30
+ }
31
+ return { ...state, phase: payload.phase, updatedAt: Date.now() };
32
+
33
+ case "CONTRACT_APPROVED":
34
+ return { ...state, contract: { ...state.contract, status: "APPROVED" }, updatedAt: Date.now() };
35
+
36
+ case "NEXT_ACTION":
37
+ return { ...state, nextAction: payload.action, updatedAt: Date.now() };
38
+
39
+ default:
40
+ return state;
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Transition Verification state
46
+ */
47
+ export function transitionVerification(state, event) {
48
+ const { type, payload } = event;
49
+
50
+ switch (type) {
51
+ case "VERIFY_START":
52
+ return { ...state, verificationStatus: "VERIFYING", updatedAt: Date.now() };
53
+ case "VERIFY_PASS":
54
+ return { ...state, verificationStatus: "VERIFIED", updatedAt: Date.now() };
55
+ case "VERIFY_FAIL":
56
+ return { ...state, verificationStatus: "FAILED", updatedAt: Date.now() };
57
+ case "INVALIDATE":
58
+ return { ...state, verificationStatus: "INVALIDATED", updatedAt: Date.now() };
59
+ default:
60
+ return state;
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Transition Cognition (Hypothesis) state
66
+ */
67
+ export function transitionHypothesis(state, event) {
68
+ const { type, payload } = event;
69
+
70
+ switch (type) {
71
+ case "HYPOTHESIS_PROPOSED":
72
+ return { ...state, hypotheses: [...(state.hypotheses || []), payload.hypothesis] };
73
+ case "HYPOTHESIS_SUPPORTED":
74
+ return { ...state, hypotheses: state.hypotheses.map(h =>
75
+ h.id === payload.hypothesisId ? { ...h, status: "SUPPORTED" } : h
76
+ )};
77
+ case "HYPOTHESIS_REJECTED":
78
+ return { ...state, hypotheses: state.hypotheses.map(h =>
79
+ h.id === payload.hypothesisId ? { ...h, status: "REJECTED" } : h
80
+ )};
81
+ default:
82
+ return state;
83
+ }
84
+ }
@@ -0,0 +1,287 @@
1
+ /**
2
+ * WAM Task Dependencies
3
+ *
4
+ * Typed dependencies between tasks. Each dependency connects an output
5
+ * from one task's execution to a requirement of another task.
6
+ *
7
+ * The dependency model extends the existing WAM task model using ContextGraph
8
+ * as the underlying structure.
9
+ */
10
+
11
+ import { ContextGraph } from "../context/context-graph.js";
12
+ import { getTaskState, persistTaskState } from "../skills/engine.js";
13
+
14
+ // -- Types --
15
+
16
+ /**
17
+ * @typedef {"requires_completion"|"requires_output"|"requires_evidence"|"requires_decision"|"depends_on_artifact"|"blocked_by"|"invalidated_by"} DependencyType
18
+ * @typedef {"decision"|"artifact"|"evidence"|"constraint"|"observation"|"verification"} OutputType
19
+ */
20
+
21
+ /**
22
+ * @typedef {Object} TaskDependency
23
+ * @property {string} from - Task or node that has the dependency
24
+ * @property {string} to - Task or node that is depended upon
25
+ * @property {DependencyType} type
26
+ * @property {boolean} required
27
+ * @property {number} createdAt
28
+ */
29
+
30
+ /**
31
+ * @typedef {Object} TaskOutput
32
+ * @property {string} id
33
+ * @property {string} taskId
34
+ * @property {string} executionId
35
+ * @property {OutputType} type
36
+ * @property {string} content
37
+ * @property {boolean} verified
38
+ * @property {number} createdAt
39
+ */
40
+
41
+ // -- Persistent Graph Store --
42
+
43
+ const GRAPH_FILE = "context-graph.json";
44
+
45
+ function loadGraph(root) {
46
+ const graph = new ContextGraph();
47
+ const stateDir = path.join(root || process.cwd(), ".wam");
48
+ const graphFile = path.join(stateDir, GRAPH_FILE);
49
+
50
+ try {
51
+ const raw = fs.readFileSync(graphFile, "utf-8");
52
+ const data = JSON.parse(raw);
53
+ for (const node of data.nodes || []) graph.addNode(node);
54
+ for (const edge of data.edges || []) {
55
+ try { graph.addEdge(edge); } catch { /* skip invalid */ }
56
+ }
57
+ } catch { /* fresh graph */ }
58
+
59
+ return graph;
60
+ }
61
+
62
+ function saveGraph(graph, root) {
63
+ const stateDir = path.join(root || process.cwd(), ".wam");
64
+ if (!fs.existsSync(stateDir)) fs.mkdirSync(stateDir, { recursive: true });
65
+
66
+ const nodes = graph.getNodes().map((n) => ({
67
+ id: n.id, type: n.type, content: n.content,
68
+ taskId: n.taskId, verified: n.verified,
69
+ metadata: n.metadata, createdAt: n.createdAt, updatedAt: n.updatedAt,
70
+ }));
71
+
72
+ const edges = [];
73
+ const seen = new Set();
74
+ for (const node of graph.getNodes()) {
75
+ for (const edge of graph.getEdgesFrom(node.id)) {
76
+ const key = `${edge.from}|${edge.to}|${edge.type}`;
77
+ if (!seen.has(key)) {
78
+ seen.add(key);
79
+ edges.push({ from: edge.from, to: edge.to, type: edge.type, weight: edge.weight });
80
+ }
81
+ }
82
+ }
83
+
84
+ fs.writeFileSync(
85
+ path.join(stateDir, GRAPH_FILE),
86
+ JSON.stringify({ nodes, edges }, null, 2)
87
+ );
88
+ }
89
+
90
+ // Need to import these
91
+ import fs from "node:fs";
92
+ import path from "node:path";
93
+
94
+ // -- Output Management --
95
+
96
+ /**
97
+ * Register an output produced by a task execution.
98
+ */
99
+ export function registerOutput(taskId, executionId, outputType, content, verified, root) {
100
+ const graph = loadGraph(root);
101
+ const outputId = `output-${taskId}-${executionId}-${Date.now()}`;
102
+
103
+ const node = {
104
+ id: outputId,
105
+ type: "output",
106
+ content,
107
+ taskId,
108
+ verified: verified || false,
109
+ metadata: { executionId, outputType },
110
+ createdAt: Date.now(),
111
+ updatedAt: Date.now(),
112
+ };
113
+
114
+ graph.addNode(node);
115
+
116
+ // Link output to its producing task (use raw taskId as node id)
117
+ if (!graph.getNode(taskId)) {
118
+ graph.addNode({
119
+ id: taskId,
120
+ type: "task",
121
+ content: content.slice(0, 200),
122
+ taskId,
123
+ verified: false,
124
+ createdAt: Date.now(),
125
+ updatedAt: Date.now(),
126
+ });
127
+ }
128
+
129
+ graph.addEdge({ from: taskId, to: outputId, type: "produces" });
130
+ saveGraph(graph, root);
131
+
132
+ return outputId;
133
+ }
134
+
135
+ // -- Dependency Management --
136
+
137
+ /**
138
+ * Add a dependency between two tasks/nodes.
139
+ */
140
+ export function addDependency(fromId, toId, type, required, root) {
141
+ const graph = loadGraph(root);
142
+
143
+ // Ensure nodes exist
144
+ if (!graph.getNode(fromId)) {
145
+ graph.addNode({
146
+ id: fromId, type: "task", content: fromId,
147
+ verified: false, createdAt: Date.now(), updatedAt: Date.now(),
148
+ });
149
+ }
150
+ if (!graph.getNode(toId)) {
151
+ graph.addNode({
152
+ id: toId, type: "task", content: toId,
153
+ verified: false, createdAt: Date.now(), updatedAt: Date.now(),
154
+ });
155
+ }
156
+
157
+ const edge = graph.addEdge({ from: fromId, to: toId, type, weight: 1.0 });
158
+ saveGraph(graph, root);
159
+
160
+ return { from: fromId, to: toId, type, required: required !== false, createdAt: Date.now() };
161
+ }
162
+
163
+ /**
164
+ * Get all dependencies of a node.
165
+ */
166
+ export function getDependencies(nodeId, root) {
167
+ const graph = loadGraph(root);
168
+ return graph.getDependencies(nodeId);
169
+ }
170
+
171
+ /**
172
+ * Get all nodes that depend on this node.
173
+ */
174
+ export function getDependents(nodeId, root) {
175
+ const graph = loadGraph(root);
176
+ return graph.getDownstream(nodeId);
177
+ }
178
+
179
+ /**
180
+ * Traverse upstream through the dependency graph.
181
+ */
182
+ export function getUpstream(nodeId, root, maxDepth) {
183
+ const graph = loadGraph(root);
184
+ return graph.getUpstream(nodeId, maxDepth);
185
+ }
186
+
187
+ // -- Missing Dependency Detection --
188
+
189
+ /**
190
+ * Detect missing dependencies for a node.
191
+ * Returns gaps where required outputs are not yet produced.
192
+ */
193
+ export function detectMissingDependencies(nodeId, root) {
194
+ const graph = loadGraph(root);
195
+ const deps = graph.getDependencies(nodeId);
196
+
197
+ const missing = [];
198
+ for (const dep of deps) {
199
+ const edges = graph.getEdgesFrom(nodeId);
200
+ const depEdge = edges.find((e) => e.to === dep.id);
201
+ if (depEdge && ["requires_output", "requires_completion", "requires_evidence",
202
+ "requires_decision", "depends_on_artifact"].includes(depEdge.type)) {
203
+ if (!dep.verified && dep.type === "output") {
204
+ const outputNode = graph.getNode(dep.id);
205
+ if (!outputNode) {
206
+ missing.push({ requiredBy: nodeId, type: "dependency", description: `Output ${dep.id} not found` });
207
+ }
208
+ }
209
+ }
210
+ }
211
+
212
+ return missing;
213
+ }
214
+
215
+ // -- Invalidation --
216
+
217
+ /**
218
+ * Invalidate an output node and all downstream nodes.
219
+ */
220
+ export function invalidateOutput(outputId, reason, root) {
221
+ const graph = loadGraph(root);
222
+
223
+ const node = graph.getNode(outputId);
224
+ if (!node) throw new Error(`Output ${outputId} not found`);
225
+
226
+ graph.updateNode(outputId, {
227
+ verified: false,
228
+ metadata: { ...node.metadata, invalidated: true, invalidationReason: reason },
229
+ });
230
+
231
+ const downstream = graph.getDownstream(outputId);
232
+
233
+ for (const d of downstream) {
234
+ try {
235
+ graph.addEdge({ from: outputId, to: d.id, type: "invalidates" });
236
+ } catch { /* already exists */ }
237
+ }
238
+
239
+ saveGraph(graph, root);
240
+ return { invalidated: outputId, affected: downstream.map((d) => d.id) };
241
+ }
242
+
243
+ /**
244
+ * Check if a node has any invalidated dependencies.
245
+ */
246
+ export function getInvalidatedDependencies(nodeId, root) {
247
+ const graph = loadGraph(root);
248
+ const deps = graph.getDependencies(nodeId);
249
+
250
+ return deps.filter((dep) => {
251
+ const meta = dep.metadata;
252
+ return meta && meta.invalidated;
253
+ });
254
+ }
255
+
256
+ // -- Context Gap --
257
+
258
+ /**
259
+ * Detect context gaps: nodes that cannot proceed due to missing dependencies.
260
+ */
261
+ export function detectContextGaps(nodeId, root) {
262
+ const graph = loadGraph(root);
263
+ const missing = detectMissingDependencies(nodeId, root);
264
+ const invalidated = getInvalidatedDependencies(nodeId, root);
265
+
266
+ const gaps = [];
267
+
268
+ for (const m of missing) {
269
+ gaps.push({
270
+ type: "missing_dependency",
271
+ severity: "blocking",
272
+ description: m.description,
273
+ requiredBy: m.requiredBy,
274
+ });
275
+ }
276
+
277
+ for (const inv of invalidated) {
278
+ gaps.push({
279
+ type: "invalidated_dependency",
280
+ severity: "warning",
281
+ description: `Dependency ${inv.id} was invalidated`,
282
+ requiredBy: nodeId,
283
+ });
284
+ }
285
+
286
+ return gaps;
287
+ }
@@ -0,0 +1,217 @@
1
+ /**
2
+ * WAM Task Execution History — DEPRECATED compatibility layer.
3
+ *
4
+ * DEPRECATED: Use task-runs.js directly. This module is a thin wrapper
5
+ * that delegates to task-runs.js for backward compatibility.
6
+ *
7
+ * Canonical model: task-runs.js (separate run files in .wam/tasks/<taskId>/runs/)
8
+ * Legacy model: state.yaml executions[] array (deprecated, will be migrated)
9
+ *
10
+ * Migration: On first access, executions[] from state.yaml are migrated
11
+ * to runs/ directory and the legacy field is removed.
12
+ */
13
+
14
+ import fs from "node:fs";
15
+ import path from "node:path";
16
+ import { getTaskState, persistTaskState } from "../skills/engine.js";
17
+ import {
18
+ startRun,
19
+ closeRun,
20
+ addObservation as addRunObservation,
21
+ addDecision as addRunDecision,
22
+ addEvidence as addRunEvidence,
23
+ getRuns,
24
+ getRunsNormalized,
25
+ getRun,
26
+ getLastRun,
27
+ getLastRunSummary,
28
+ getUnresolvedRequirements as getUnresolvedReqs,
29
+ getPreviousFailures as getPrevFailures,
30
+ getPreviousDecisions as getPrevDecisions,
31
+ getResumeContext as getResumeCtx,
32
+ needsNewRun,
33
+ } from "./task-runs.js";
34
+
35
+ // -- Migration --
36
+
37
+ /**
38
+ * Migrate legacy executions[] from state.yaml to runs/ directory.
39
+ * This is idempotent — safe to call multiple times.
40
+ */
41
+ export function migrateLegacyExecutions(taskId, root) {
42
+ const state = getTaskState(taskId, root);
43
+ if (!state?.executions || state.executions.length === 0) return 0;
44
+
45
+ const existingRuns = getRuns(taskId, root);
46
+ const existingRunIds = new Set(existingRuns.map((r) => r.id));
47
+
48
+ let migrated = 0;
49
+
50
+ for (const exec of state.executions) {
51
+ // Skip if already migrated (by ID convention or content match)
52
+ if (existingRunIds.has(exec.id)) continue;
53
+
54
+ // Convert execution to run format
55
+ const run = {
56
+ id: exec.id,
57
+ taskId: exec.taskId || taskId,
58
+ startedAt: exec.startedAt,
59
+ completedAt: exec.completedAt,
60
+ status: exec.status || "active",
61
+ phase: "IMPLEMENTING",
62
+ observations: (exec.observations || []).map((text, i) => ({
63
+ id: `obs-${i + 1}`,
64
+ text: typeof text === "string" ? text : text.text || String(text),
65
+ timestamp: exec.startedAt || Date.now(),
66
+ })),
67
+ decisions: (exec.decisions || []).map((text, i) => ({
68
+ id: `dec-${i + 1}`,
69
+ text: typeof text === "string" ? text : text.text || String(text),
70
+ timestamp: exec.startedAt || Date.now(),
71
+ })),
72
+ evidence: (exec.evidence || []).map((text, i) => ({
73
+ id: `ev-${i + 1}`,
74
+ text: typeof text === "string" ? text : text.text || String(text),
75
+ timestamp: exec.startedAt || Date.now(),
76
+ })),
77
+ actions: [],
78
+ outcome: exec.outcome || null,
79
+ };
80
+
81
+ // Write to runs directory
82
+ const runsDir = path.join(root || process.cwd(), ".wam", "tasks", taskId, "runs");
83
+ if (!fs.existsSync(runsDir)) {
84
+ fs.mkdirSync(runsDir, { recursive: true });
85
+ }
86
+ fs.writeFileSync(path.join(runsDir, `${run.id}.json`), JSON.stringify(run, null, 2));
87
+
88
+ migrated++;
89
+ }
90
+
91
+ // Remove legacy executions[] from state
92
+ delete state.executions;
93
+ persistTaskState(taskId, state, root);
94
+
95
+ return migrated;
96
+ }
97
+
98
+ /**
99
+ * Check if a task has legacy executions that need migration.
100
+ */
101
+ export function hasLegacyExecutions(taskId, root) {
102
+ const state = getTaskState(taskId, root);
103
+ return state?.executions && state.executions.length > 0;
104
+ }
105
+
106
+ // -- Delegated API (backward compatible) --
107
+
108
+ /**
109
+ * Create a new execution for an existing task.
110
+ * Delegates to startRun().
111
+ */
112
+ export function createExecution(taskId, root) {
113
+ return startRun(taskId, root);
114
+ }
115
+
116
+ /**
117
+ * Close an execution with a status and optional outcome.
118
+ * Delegates to closeRun().
119
+ */
120
+ export function closeExecution(taskId, execId, status, outcome, root) {
121
+ return closeRun(taskId, execId, status, outcome, root);
122
+ }
123
+
124
+ function readExecFromRuns(taskId, execId, root) {
125
+ // Lazy: read from runs/ directory via task-runs.js
126
+ return getRun(taskId, execId, root);
127
+ }
128
+
129
+ /**
130
+ * Add an observation to an execution.
131
+ * Delegates to addObservation() in task-runs.js.
132
+ */
133
+ export function addObservation(taskId, execId, text, root) {
134
+ return addRunObservation(taskId, execId, text, root);
135
+ }
136
+
137
+ /**
138
+ * Add a decision to an execution.
139
+ * Delegates to addDecision() in task-runs.js.
140
+ */
141
+ export function addDecision(taskId, execId, text, root) {
142
+ return addRunDecision(taskId, execId, text, root);
143
+ }
144
+
145
+ /**
146
+ * Add evidence to an execution.
147
+ * Delegates to addEvidence() in task-runs.js.
148
+ */
149
+ export function addEvidence(taskId, execId, text, root) {
150
+ return addRunEvidence(taskId, execId, text, root);
151
+ }
152
+
153
+ // -- Query (delegated) --
154
+
155
+ /**
156
+ * Get all executions for a task.
157
+ * Delegates to getRuns().
158
+ */
159
+ export function getExecutions(taskId, root) {
160
+ return getRunsNormalized(taskId, root);
161
+ }
162
+
163
+ /**
164
+ * Get the last (most recent) execution for a task.
165
+ * Delegates to getLastRun().
166
+ */
167
+ export function getLastExecution(taskId, root) {
168
+ return getLastRun(taskId, root);
169
+ }
170
+
171
+ /**
172
+ * Get the last known state of a task from its most recent execution.
173
+ * Delegates to getLastRunSummary().
174
+ */
175
+ export function getLastExecutionSummary(taskId, root) {
176
+ return getLastRunSummary(taskId, root);
177
+ }
178
+
179
+ /**
180
+ * Get unresolved requirements from task state.
181
+ * Delegates to getUnresolvedRequirements() in task-runs.js.
182
+ */
183
+ export function getUnresolvedRequirements(taskId, root) {
184
+ return getUnresolvedReqs(taskId, root);
185
+ }
186
+
187
+ /**
188
+ * Get relevant previous failures.
189
+ * Delegates to getPreviousFailures() in task-runs.js.
190
+ */
191
+ export function getPreviousFailures(taskId, root) {
192
+ return getPrevFailures(taskId, root);
193
+ }
194
+
195
+ /**
196
+ * Get relevant previous decisions from execution history.
197
+ * Delegates to getPreviousDecisions() in task-runs.js.
198
+ */
199
+ export function getPreviousDecisions(taskId, root, limit = 5) {
200
+ return getPrevDecisions(taskId, root, limit);
201
+ }
202
+
203
+ /**
204
+ * Resume context: aggregate what's needed to continue work.
205
+ * Delegates to getResumeContext() in task-runs.js.
206
+ */
207
+ export function getResumeContext(taskId, root) {
208
+ return getResumeCtx(taskId, root);
209
+ }
210
+
211
+ /**
212
+ * Check if task needs a new execution (no active one).
213
+ * Delegates to needsNewRun().
214
+ */
215
+ export function needsNewExecution(taskId, root) {
216
+ return needsNewRun(taskId, root);
217
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Task Lifecycle — Task state transitions (Create, Resume, Switch, Pause, Complete, Block).
3
+ */
4
+
5
+ import { createState, normalizeState, validateState } from "./task-state.js";
6
+ import { loadTask, saveTask, taskExists, deleteTask } from "./task-store.js";
7
+
8
+ const TERMINAL_PHASES = new Set(["DONE"]);
9
+
10
+ export function create(taskId, root) {
11
+ if (taskExists(taskId, root)) {
12
+ throw new Error(`Task ${taskId} already exists`);
13
+ }
14
+ const state = createState(taskId);
15
+ saveTask(taskId, state, root);
16
+ return state;
17
+ }
18
+
19
+ export function resume(taskId, root) {
20
+ const state = loadTask(taskId, root);
21
+ if (!state) {
22
+ throw new Error(`Task ${taskId} not found`);
23
+ }
24
+ return normalizeState(state);
25
+ }
26
+
27
+ export function switchTo(taskId, newPhase, root) {
28
+ const state = loadTask(taskId, root);
29
+ if (!state) throw new Error(`Task ${taskId} not found`);
30
+
31
+ if (TERMINAL_PHASES.has(state.phase) && newPhase !== state.phase) {
32
+ throw new Error(`cannot transition from terminal phase ${state.phase}`);
33
+ }
34
+
35
+ state.phase = newPhase;
36
+ state.updatedAt = Date.now();
37
+ saveTask(taskId, state, root);
38
+ return state;
39
+ }
40
+
41
+ export function pause(taskId, root) {
42
+ return switchTo(taskId, "WAITING", root);
43
+ }
44
+
45
+ export function complete(taskId, root) {
46
+ return switchTo(taskId, "DONE", root);
47
+ }
48
+
49
+ export function block(taskId, reason, root) {
50
+ const state = loadTask(taskId, root);
51
+ if (!state) throw new Error(`Task ${taskId} not found`);
52
+
53
+ state.blocked = reason;
54
+ state.updatedAt = Date.now();
55
+ saveTask(taskId, state, root);
56
+ return state;
57
+ }
58
+
59
+ export { createState, normalizeState, validateState };