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,258 @@
1
+ /**
2
+ * Autonomous execution loop — hypothesis → classify → experiment → observe → replan.
3
+ * Non-destructive: never hard-deletes. Failed approaches are archived/rejected.
4
+ *
5
+ * Decoupled into:
6
+ * - observation-engine.js — raw observation recording
7
+ * - evidence-engine.js — evidence creation + lineage linking
8
+ * - state-machine.js — hypothesis / experiment status transitions
9
+ *
10
+ * This module orchestrates the three engines and remains the entry point
11
+ * for startExperiment / noteFailure / noteSuccess / handleContradiction.
12
+ */
13
+
14
+ import {
15
+ createHypothesis,
16
+ createExperiment,
17
+ completeExperiment,
18
+ failExperiment,
19
+ updateHypothesisStatus,
20
+ hasRepetitiveFailure,
21
+ archiveHypothesis,
22
+ HYPOTHESIS_STATUS,
23
+ } from "../cognition/cognition-store.js";
24
+ import { guardAction } from "./runtime-guards.js";
25
+ import { rejectHypothesis } from "../cognition/cognitive-state.js";
26
+ import { assessObservation, AssessmentResult } from "../policy/assessment-engine.js";
27
+ import { noteContradiction } from "../cognition/hypothesis-manager.js";
28
+ import { getTaskState, persistTaskState } from "../skills/engine.js";
29
+
30
+ // Re-exported as public API surface of the execution entry point.
31
+ export { assessObservation };
32
+
33
+ import {
34
+ recordRawObservation,
35
+ resolveExperimentContext,
36
+ } from "../cognition/observation-engine.js";
37
+ import {
38
+ produceExecutionEvidence,
39
+ linkEvidenceIfBound,
40
+ } from "../evidence/evidence-engine.js";
41
+ import {
42
+ deriveHypothesisStatus,
43
+ shouldReplan,
44
+ shouldNoteContradiction,
45
+ } from "../state/state-machine.js";
46
+
47
+ function describe(tool, args = {}) {
48
+ const { hypothesisId: _h, ...rest } = args;
49
+ return `${tool}:${JSON.stringify(rest)}`;
50
+ }
51
+
52
+ /**
53
+ * Resolve the requirement an execution outcome belongs to. Prefers the
54
+ * explicit id supplied by the runtime bridge; falls back to the task's
55
+ * active requirement (first not done/verified) so a success observation
56
+ * still propagates to the lifecycle state it satisfies.
57
+ */
58
+ function resolveRequirementId(taskRoot, taskId, requirementId) {
59
+ if (requirementId) return requirementId;
60
+ const state = getTaskState(taskId, taskRoot);
61
+ const requirements = Array.isArray(state?.requirements) ? state.requirements : [];
62
+ const active =
63
+ requirements.find((r) => r.status !== "done" && r.status !== "verified") ||
64
+ requirements[0] ||
65
+ null;
66
+ return active?.id || null;
67
+ }
68
+
69
+ /**
70
+ * Propagate a SUPPORTED execution outcome to the requirement lifecycle:
71
+ * mark it verified and attach the producing evidence id. This is the seam
72
+ * where the cognition store (evidence) meets the task state (requirement
73
+ * status); without it a successful tool leaves the completion gate blocked.
74
+ */
75
+ function markRequirementVerified(taskRoot, taskId, requirementId, evidenceId) {
76
+ if (!requirementId) return false;
77
+ const state = getTaskState(taskId, taskRoot);
78
+ if (!state || !Array.isArray(state.requirements)) return false;
79
+ const requirement = state.requirements.find((r) => r.id === requirementId);
80
+ if (!requirement) return false;
81
+ requirement.status = "verified";
82
+ if (evidenceId) {
83
+ if (!Array.isArray(requirement.evidence)) requirement.evidence = [];
84
+ if (!requirement.evidence.includes(evidenceId)) requirement.evidence.push(evidenceId);
85
+ }
86
+ requirement.verifiedAt = requirement.verifiedAt || Date.now();
87
+ persistTaskState(taskId, state, taskRoot);
88
+ return true;
89
+ }
90
+
91
+ /**
92
+ * Pure orchestrator: turn an observation + assessment into the next
93
+ * hypothesis status and the persisted observation record. Delegates
94
+ * persistence to observation-engine and status derivation to state-machine.
95
+ */
96
+ function processObservation(taskRoot, taskId, args) {
97
+ // Resolve experiment context first so the assessment has the right input shape
98
+ // (it needs experiment.expectedObservation to compare against args.actual).
99
+ const experiment = resolveExperimentContext(taskRoot, taskId, args);
100
+ const assessment = assessObservation(experiment ?? { id: null }, {
101
+ actual: args.actual,
102
+ unexpected: args.unexpected,
103
+ provenance: args.provenance,
104
+ experimentId: args.experimentId,
105
+ });
106
+ // Now persist with the *assessment* result, not the raw tool result.
107
+ const { observation } = recordRawObservation(taskRoot, taskId, {
108
+ ...args,
109
+ result: assessment.result,
110
+ });
111
+ const { status, severity } = deriveHypothesisStatus(assessment);
112
+ updateHypothesisStatus(taskRoot, taskId, args.hypothesisId, status);
113
+
114
+ return { assessment, hypothesisStatus: status, severity, observation };
115
+ }
116
+
117
+ export async function startExperiment(taskRoot, taskId, { statement, tool, args = {}, confidence = 0.5, expectedObservation }) {
118
+ const hypothesis = createHypothesis(taskRoot, taskId, { statement, confidence });
119
+ const input = { ...args, hypothesisId: hypothesis.id };
120
+ const guard = await guardAction(tool, input, taskRoot, taskId);
121
+ if (!guard.allowed) {
122
+ archiveHypothesis(taskRoot, taskId, hypothesis.id, guard.reason || "blocked by policy");
123
+ return { ok: false, hypothesis, guard };
124
+ }
125
+
126
+ const actionDescription = describe(tool, args);
127
+ if (hasRepetitiveFailure(taskRoot, taskId, { hypothesisId: hypothesis.id, actionDescription })) {
128
+ archiveHypothesis(taskRoot, taskId, hypothesis.id, "repetitive failure");
129
+ return { ok: false, hypothesis, guard: { allowed: false, reason: "repetitive failure" } };
130
+ }
131
+
132
+ const experiment = createExperiment(taskRoot, taskId, {
133
+ hypothesisId: hypothesis.id,
134
+ tool,
135
+ args,
136
+ actionDescription,
137
+ expectedObservation,
138
+ });
139
+ updateHypothesisStatus(taskRoot, taskId, hypothesis.id, HYPOTHESIS_STATUS.TESTING);
140
+ return { ok: true, hypothesis, experiment, guard };
141
+ }
142
+
143
+ export function noteFailure(taskRoot, taskId, { hypothesisId, experimentId, reason, actual, unexpected, provenance }) {
144
+ if (experimentId) failExperiment(taskRoot, taskId, experimentId, reason);
145
+ const { assessment, hypothesisStatus, severity } = processObservation(taskRoot, taskId, {
146
+ hypothesisId,
147
+ experimentId,
148
+ reason,
149
+ actual,
150
+ unexpected,
151
+ provenance,
152
+ outcome: "failure",
153
+ });
154
+ // Explicit failure: if the assessment didn't already drive the hypothesis to
155
+ // a terminal state (SUPPORTED), archive it so callers observing the cognition
156
+ // store see REJECTED/ARCHIVED instead of stale TESTING. This preserves
157
+ // noteSuccess semantics (no forced archive on success outcomes).
158
+ // Preserve terminal decisions: REJECTED is already the outcome of a
159
+ // high-severity contradiction (state-machine derive). Only soft-archive
160
+ // non-terminal states (e.g. TESTING) so callers never observe stale
161
+ // TESTING. Archiving REJECTED on top of itself erased the distinction
162
+ // between "contradicted" and "retired".
163
+ if (
164
+ hypothesisStatus !== HYPOTHESIS_STATUS.SUPPORTED &&
165
+ hypothesisStatus !== HYPOTHESIS_STATUS.REJECTED
166
+ ) {
167
+ archiveHypothesis(taskRoot, taskId, hypothesisId, reason || "failure");
168
+ }
169
+ return {
170
+ assessment,
171
+ hypothesisStatus,
172
+ severity,
173
+ replan: shouldReplan({ assessment, hypothesisStatus }),
174
+ };
175
+ }
176
+
177
+ export function noteSuccess(taskRoot, taskId, { hypothesisId, experimentId, result, actual, unexpected, provenance, requirementId }) {
178
+ // 0. Mark the experiment as COMPLETED (mirrors noteFailure → failExperiment).
179
+ if (experimentId) completeExperiment(taskRoot, taskId, experimentId, { result });
180
+
181
+ // Bind the outcome to a requirement even when the caller omits it, so the
182
+ // evidence lineage and the task lifecycle stay connected.
183
+ const effectiveRequirementId = resolveRequirementId(taskRoot, taskId, requirementId);
184
+
185
+ // 1. Create evidence first so we can carry its id into the observation facts.
186
+ const { evidence } = produceExecutionEvidence(taskId, taskRoot, {
187
+ requirementId: effectiveRequirementId,
188
+ result,
189
+ hypothesisId,
190
+ });
191
+
192
+ // 2. Persist observation with the evidence id as the primary fact.
193
+ const { assessment, hypothesisStatus, observation } = processObservation(taskRoot, taskId, {
194
+ hypothesisId,
195
+ experimentId,
196
+ result,
197
+ actual,
198
+ unexpected,
199
+ provenance,
200
+ outcome: "success",
201
+ facts: [evidence.id],
202
+ });
203
+
204
+ // 3. Bind evidence to the requirement lineage when both sides are known.
205
+ linkEvidenceIfBound({
206
+ evidenceId: evidence.id,
207
+ requirementId: effectiveRequirementId,
208
+ hypothesisId,
209
+ experimentId,
210
+ observationId: observation?.id,
211
+ taskId,
212
+ taskRoot,
213
+ });
214
+
215
+ // A supported outcome verifies the requirement it satisfies: this closes the
216
+ // seam between cognition evidence and task-state verification.
217
+ if (assessment.result === AssessmentResult.SUPPORTED) {
218
+ markRequirementVerified(taskRoot, taskId, effectiveRequirementId, evidence?.id);
219
+ }
220
+
221
+ if (assessment.result === AssessmentResult.CONTRADICTED) {
222
+ if (shouldNoteContradiction({ assessment, hypothesisStatus })) {
223
+ noteContradiction(taskId, hypothesisId, observation, assessment, taskRoot);
224
+ }
225
+ return {
226
+ assessment,
227
+ hypothesisStatus,
228
+ severity: null,
229
+ replan: shouldReplan({ assessment, hypothesisStatus }),
230
+ };
231
+ }
232
+ return { assessment, hypothesisStatus };
233
+ }
234
+
235
+ export function handleContradiction(taskRoot, taskId, { experiment, observation, assessment }) {
236
+ const { hypothesisId, id: experimentId } = experiment;
237
+ updateHypothesisStatus(taskRoot, taskId, hypothesisId, "contradicted");
238
+ rejectHypothesis(taskRoot, hypothesisId, "contradicted by observation");
239
+ const contradiction = noteContradiction(taskId, hypothesisId, observation, assessment, taskRoot);
240
+ recordRawObservation(taskRoot, taskId, {
241
+ experimentId,
242
+ hypothesisId,
243
+ result: assessment.result,
244
+ facts: [contradiction.detail],
245
+ provenance: { type: "execution-assessment" },
246
+ });
247
+ const newHypothesis = createHypothesis(taskRoot, taskId, {
248
+ statement: `[REPLAN] New hypothesis after contradicting ${hypothesisId}: reassess strategy`,
249
+ confidence: 0.3,
250
+ });
251
+ return {
252
+ status: "CONTRADICTED",
253
+ previousHypothesisId: hypothesisId,
254
+ previousExperimentId: experimentId,
255
+ assessment,
256
+ newHypothesis,
257
+ };
258
+ }
@@ -0,0 +1,69 @@
1
+ export const EXECUTION_INTENT = Object.freeze({
2
+ DIRECT_REQUIREMENT_ACTION: "DIRECT_REQUIREMENT_ACTION",
3
+ SUPPORTING_ACTION: "SUPPORTING_ACTION",
4
+ INVESTIGATION: "INVESTIGATION",
5
+ VALIDATION: "VALIDATION",
6
+ RECOVERY: "RECOVERY",
7
+ UNKNOWN: "UNKNOWN",
8
+ });
9
+
10
+ const INVESTIGATION_TOOLS = new Set(["read", "read_file", "list_directory", "list_files", "get_file", "glob", "grep", "search", "webfetch", "fetch", "task_search", "tool_search"]);
11
+ const RECOVERY_TOOLS = new Set(["revert", "rollback", "restore"]);
12
+ const VALIDATION_TOOLS = new Set(["test", "spec", "vitest", "jest", "pytest", "mocha"]);
13
+ const MODIFICATION_TOOLS = new Set(["write", "edit", "apply_patch", "patch", "todo_write", "todowrite"]);
14
+
15
+ export function classifyExecutionIntent(tool, args = {}, statement = "") {
16
+ const operation = String(tool || "").toLowerCase();
17
+ const stmt = String(statement || "").toLowerCase();
18
+ const cmd = String(args?.command || "").toLowerCase();
19
+ const first = (cmd.split(/\s+/)[0] || "");
20
+
21
+ if (RECOVERY_TOOLS.has(operation)) return EXECUTION_INTENT.RECOVERY;
22
+
23
+ if (VALIDATION_TOOLS.has(operation) || /\b(test|spec|verify|check|assert)\b/.test(operation) || /\btest\b/.test(cmd)) {
24
+ return EXECUTION_INTENT.VALIDATION;
25
+ }
26
+
27
+ if (INVESTIGATION_TOOLS.has(operation)) return EXECUTION_INTENT.INVESTIGATION;
28
+ if (/^(ls|find|cat|grep|search|inspect|inspect_file|view|show)/.test(cmd.split(/\s+/)[0] || "")) return EXECUTION_INTENT.INVESTIGATION;
29
+
30
+ if (MODIFICATION_TOOLS.has(operation)) {
31
+ return EXECUTION_INTENT.SUPPORTING_ACTION;
32
+ }
33
+
34
+ if (/^(npm|pnpm|yarn|brew|apt|pip)\s+(install|add|setup|i)\b/.test(cmd) || /^(install|setup|setup_)/.test(cmd.split(/\s+/)[0] || "")) {
35
+ return EXECUTION_INTENT.SUPPORTING_ACTION;
36
+ }
37
+
38
+ if (/^(npm|pnpm|yarn|node|deno|ruby|python|bash|sh|make|cargo|go|docker|kubectl|npx)/.test(first)) {
39
+ if (/^npx\s+/.test(cmd) || /\binstall\b/.test(cmd) || /\bsetup\b/.test(cmd)) {
40
+ return EXECUTION_INTENT.SUPPORTING_ACTION;
41
+ }
42
+ if (/\btest\b/.test(cmd)) {
43
+ return EXECUTION_INTENT.VALIDATION;
44
+ }
45
+ if (/\b(run|exec|start|build)\b/.test(cmd)) {
46
+ return EXECUTION_INTENT.DIRECT_REQUIREMENT_ACTION;
47
+ }
48
+ return EXECUTION_INTENT.SUPPORTING_ACTION;
49
+ }
50
+
51
+ if (stmt && /\brequirement\b/.test(stmt) && !/(install|setup|test|spec)/.test(cmd)) {
52
+ if (operation && MODIFICATION_TOOLS.has(operation)) {
53
+ return EXECUTION_INTENT.DIRECT_REQUIREMENT_ACTION;
54
+ }
55
+ }
56
+
57
+ return EXECUTION_INTENT.UNKNOWN;
58
+ }
59
+
60
+ export function isDirectRequirementAction(intent) {
61
+ return intent === EXECUTION_INTENT.DIRECT_REQUIREMENT_ACTION;
62
+ }
63
+
64
+ export function isSupportingAction(intent) {
65
+ return intent === EXECUTION_INTENT.SUPPORTING_ACTION ||
66
+ intent === EXECUTION_INTENT.INVESTIGATION ||
67
+ intent === EXECUTION_INTENT.VALIDATION ||
68
+ intent === EXECUTION_INTENT.RECOVERY;
69
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Formal execution state — single source of truth for task lifecycle.
3
+ * Implements spec: formal-execution-state.
4
+ *
5
+ * States:
6
+ * INITIALIZING | INVESTIGATING | EXECUTING | VERIFYING | COMPLETED
7
+ * BLOCKED | WAITING_AUTHORIZATION | FAILED
8
+ *
9
+ * Transition table is strict: only documented transitions are allowed.
10
+ */
11
+
12
+ const VALID_STATES = new Set([
13
+ "INITIALIZING",
14
+ "INVESTIGATING",
15
+ "EXECUTING",
16
+ "VERIFYING",
17
+ "COMPLETED",
18
+ "BLOCKED",
19
+ "WAITING_AUTHORIZATION",
20
+ "FAILED",
21
+ ]);
22
+
23
+ const ALLOWED_TRANSITIONS = {
24
+ INITIALIZING: new Set(["INVESTIGATING", "BLOCKED"]),
25
+ INVESTIGATING: new Set(["EXECUTING", "WAITING_AUTHORIZATION", "BLOCKED"]),
26
+ EXECUTING: new Set(["VERIFYING", "BLOCKED", "FAILED"]),
27
+ VERIFYING: new Set(["COMPLETED", "EXECUTING", "FAILED"]),
28
+ WAITING_AUTHORIZATION: new Set(["EXECUTING", "BLOCKED"]),
29
+ BLOCKED: new Set(["INVESTIGATING", "EXECUTING"]),
30
+ FAILED: new Set(["INVESTIGATING"]),
31
+ COMPLETED: new Set(),
32
+ };
33
+
34
+ const LEGACY_PHASE_TO_STATE = {
35
+ ASKING: "WAITING_AUTHORIZATION",
36
+ PROPOSED: "INVESTIGATING",
37
+ IMPLEMENTING: "EXECUTING",
38
+ VERIFYING: "VERIFYING",
39
+ DONE: "COMPLETED",
40
+ };
41
+
42
+ export function isValidState(s) {
43
+ return typeof s === "string" && VALID_STATES.has(s);
44
+ }
45
+
46
+ export function migrateLegacyPhase(phase) {
47
+ return LEGACY_PHASE_TO_STATE[phase] || "INITIALIZING";
48
+ }
49
+
50
+ export function validateState(s) {
51
+ if (!isValidState(s)) {
52
+ throw new Error(`Invalid execution state: ${JSON.stringify(s)}. Must be one of: ${[...VALID_STATES].join(", ")}`);
53
+ }
54
+ }
55
+
56
+ import { hasOutstandingWork } from "../verification/verification-lifecycle.js";
57
+
58
+ export function transition(from, to, taskState = null) {
59
+ validateState(from);
60
+ validateState(to);
61
+ // Guard: block transition to COMPLETED if there is outstanding work
62
+ if (to === "COMPLETED" && hasOutstandingWork(taskState)) {
63
+ throw new Error("Cannot transition to COMPLETED while there is outstanding work (unverified requirements or pending backlog)");
64
+ }
65
+ const allowed = ALLOWED_TRANSITIONS[from];
66
+ if (!allowed.has(to)) {
67
+ throw new Error(`Invalid transition: ${from} → ${to}. Allowed from ${from}: ${[...allowed].join(", ") || "(none, terminal)"}`);
68
+ }
69
+ return to;
70
+ }
71
+
72
+ export function getStatusReport(taskState, { experiments = [], failures = [], pendingAuth = null, verification = null, completionEvidence = [] } = {}) {
73
+ if (!taskState) return "Sin estado de tarea";
74
+ const lines = [
75
+ `state: ${taskState.state || migrateLegacyPhase(taskState.phase)}`,
76
+ `strategy: ${taskState.approvedStrategy?.strategy || "—"}`,
77
+ `current hypothesis: ${taskState.currentHypothesis || "—"}`,
78
+ `experiments: ${experiments.length}`,
79
+ `failures: ${failures.length}`,
80
+ `pending authorization: ${pendingAuth ? pendingAuth.id || pendingAuth.question || "yes" : "none"}`,
81
+ `verification status: ${verification?.status || "pending"}`,
82
+ `completion evidence: ${completionEvidence.length} item(s)`,
83
+ ];
84
+ // Add each piece of completion evidence with req id and evidence
85
+ for (const item of completionEvidence) {
86
+ lines.push(`${item.req}: ${item.evidence}`);
87
+ }
88
+ return lines.join("\n");
89
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Formatting — funciones puras de formateo y presentación.
3
+ *
4
+ * Contiene:
5
+ * - truncate: utilidad de truncamiento de texto (compartida)
6
+ * - delegationLines: formatea lines de delegación para el inyector
7
+ * - getStatusReport: formatea reporte de estado (re-exportado)
8
+ *
9
+ * Todas son PURAS: toman datos como entrada, retornan strings/arrays.
10
+ * Sin side effects (no persisten, no leen, no escriben).
11
+ */
12
+
13
+ import { getStatusReport } from "./execution-state.js";
14
+
15
+ export { getStatusReport } from "./execution-state.js";
16
+
17
+ // -- Shared utility --------------------------------------------------------
18
+
19
+ /**
20
+ * Trunca texto a máximo `max` caracteres con "..." al final.
21
+ */
22
+ export function truncate(text, max = 80) {
23
+ if (!text || text.length <= max) return text || "";
24
+ return text.slice(0, max - 3) + "...";
25
+ }
26
+
27
+ // -- Delegation lines -------------------------------------------------------
28
+
29
+ const MAX_VISIBLE_REQS = 8;
30
+
31
+ /**
32
+ * Formatea las líneas de delegación visible para el inyector de sistema.
33
+ * Solo se muestra when contract está APPROVED con requisitos pendientes.
34
+ *
35
+ * @param {Object} state - Estado de la tarea
36
+ * @param {Function} [domainHintFn] - Función opcional para clasificar dominio (ej: domainHint de index.js)
37
+ * @returns {string[]} Líneas de delegación
38
+ */
39
+ export function delegationLines(state, domainHintFn = null) {
40
+ const reqs = state?.contract?.requirements || [];
41
+ if (!reqs.length) return [];
42
+ if (state?.contract?.status !== "APPROVED") return [];
43
+
44
+ const pending = reqs.filter((r) => r.status !== "done" && r.status !== "verified");
45
+ if (!pending.length) return [];
46
+
47
+ const lines = [
48
+ "⏳ Delegación: estos requerimientos están aprobados para ejecución paralela:",
49
+ ];
50
+ const visible = pending.slice(0, MAX_VISIBLE_REQS);
51
+ const overflow = pending.length - MAX_VISIBLE_REQS;
52
+ for (const r of visible) {
53
+ const hint = domainHintFn ? domainHintFn(r.title) : "";
54
+ lines.push(` ${r.id} → Task(parallel) "${truncate(r.title, 120)}"${hint ? ` [contexto: ${hint}]` : ""}`);
55
+ }
56
+ if (overflow > 0) {
57
+ lines.push(` ...(+${overflow} requerimientos adicionales consolidados)`);
58
+ }
59
+ return lines;
60
+ }
@@ -0,0 +1,16 @@
1
+ import path from "node:path";
2
+
3
+ export function sanitizeShellArg(arg) {
4
+ // Simple shell escaping
5
+ return "'" + arg.replace(/'/g, "'\\''") + "'";
6
+ }
7
+
8
+ export function sanitizePath(unsafePath) {
9
+ // Resolve and verify base to prevent traversal
10
+ const resolvedPath = path.resolve(unsafePath);
11
+ return resolvedPath;
12
+ }
13
+
14
+ export function stripControlChars(str) {
15
+ return str.replace(/[\x00-\x1F\x7F]/g, "");
16
+ }
@@ -0,0 +1,19 @@
1
+ export class ResourceGuard {
2
+ constructor(options = {}) {
3
+ this.maxDuration = options.maxDuration || 5000;
4
+ }
5
+
6
+ async runWithTimeout(task) {
7
+ const controller = new AbortController();
8
+ const timeout = setTimeout(() => controller.abort(), this.maxDuration);
9
+
10
+ try {
11
+ return await Promise.race([
12
+ task(controller.signal),
13
+ new Promise((_, reject) => controller.signal.addEventListener('abort', () => reject(new Error("AbortError"))))
14
+ ]);
15
+ } finally {
16
+ clearTimeout(timeout);
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,5 @@
1
+ export function checkStateInvariant(state, invariant) {
2
+ if (!invariant(state)) {
3
+ throw new Error("Invariant violation detected");
4
+ }
5
+ }
@@ -0,0 +1,6 @@
1
+ import vm from "node:vm";
2
+
3
+ export function runInSandbox(code, context = {}) {
4
+ const sandbox = vm.createContext({ ...context });
5
+ return vm.runInContext(code, sandbox);
6
+ }
@@ -0,0 +1,106 @@
1
+ import { findRepeatedExperiment, hasRepetitiveFailure } from "../cognition/cognition-store.js";
2
+ import { evaluateAction } from "../policy/risk-engine.js";
3
+ import { getCapability, CAPABILITY_LEVELS } from "../policy/action-capabilities.js";
4
+
5
+ const HARD_DELETE_RE =
6
+ /\b(rmdir|unlink|shred|truncate)\b|\brm\s+(-[a-zA-Z]*f|--force)|\bgit\s+reset\s+--hard\b|\b(DROP|TRUNCATE)\s+(TABLE|DATABASE)\b/i;
7
+
8
+ const HARD_DELETE_TOOLS = new Set(["rm", "rmdir"]);
9
+
10
+ function isHardDelete(tool, args = {}) {
11
+ const t = String(tool || "").toLowerCase();
12
+ if (HARD_DELETE_TOOLS.has(t)) return true;
13
+ const cmd = String(args.command || args.cmd || "");
14
+ return HARD_DELETE_RE.test(cmd);
15
+ }
16
+
17
+ function actionDescription(tool, args = {}) {
18
+ const { hypothesisId: _h, ...rest } = args;
19
+ return `${tool}:${JSON.stringify(rest)}`;
20
+ }
21
+
22
+ /**
23
+ * Autonomy Runtime Guards
24
+ *
25
+ * Intercepta ejecución para evaluar:
26
+ * 1. Riesgo de la acción (Risk Envelope)
27
+ * 2. Stagnation/Repetition (cognition-store)
28
+ * 3. Hard-delete ban (U1: soft-archive only)
29
+ * 4. Scope enforcement
30
+ */
31
+ export async function guardAction(tool, args, taskRoot, taskId) {
32
+ // 0. Fail-closed (C01): herramientas no catalogadas se bloquean aquí,
33
+ // ANTES de cualquier otra evaluación. Esto crea una segunda línea
34
+ // de defensa independiente del risk-engine: aunque la evaluación
35
+ // contextual cambie, una herramienta desconocida nunca llega a
36
+ // ejecutarse.
37
+ const capability = getCapability(tool);
38
+ if (capability === CAPABILITY_LEVELS.UNKNOWN) {
39
+ return {
40
+ allowed: false,
41
+ level: "BLOCKED",
42
+ reason: `fail-closed: herramienta no catalogada (${tool})`,
43
+ };
44
+ }
45
+
46
+ if (isHardDelete(tool, args)) {
47
+ return {
48
+ allowed: false,
49
+ level: "BLOCKED",
50
+ reason: "hard delete forbidden (U1: soft-archive only)",
51
+ };
52
+ }
53
+
54
+ let risk;
55
+ try {
56
+ risk = evaluateAction(tool, args, taskRoot);
57
+ } catch (err) {
58
+ const name = err?.name || err?.constructor?.name;
59
+ if (name === "WamPolicyBlock") {
60
+ return { allowed: false, level: "BLOCKED", reason: err.message };
61
+ }
62
+ throw err;
63
+ }
64
+
65
+ if (risk.level === "BLOCKED") {
66
+ return {
67
+ allowed: false,
68
+ level: "BLOCKED",
69
+ reason: risk.reason || "destructive or irreversible action blocked",
70
+ };
71
+ }
72
+
73
+ const desc = actionDescription(tool, args);
74
+ const probe = {
75
+ hypothesisId: args?.hypothesisId || "unknown",
76
+ actionDescription: desc,
77
+ };
78
+
79
+ if (hasRepetitiveFailure(taskRoot, taskId, probe)) {
80
+ return {
81
+ allowed: false,
82
+ level: risk.level,
83
+ reason: "repetitive failure: same hypothesis+action already failed. Replan with a new hypothesis.",
84
+ };
85
+ }
86
+
87
+ const repeated = findRepeatedExperiment(taskRoot, taskId, probe);
88
+
89
+ if (risk.level === "GUARDED" && !args?.hypothesisId) {
90
+ return {
91
+ allowed: true,
92
+ level: risk.level,
93
+ warning: "GUARDED action without hypothesisId — attach hypothesis before mutating.",
94
+ };
95
+ }
96
+
97
+ if (repeated) {
98
+ return {
99
+ allowed: true,
100
+ level: risk.level,
101
+ warning: `Repetición detectada: ya se intentó ${repeated.status}. Considera replanificar.`,
102
+ };
103
+ }
104
+
105
+ return { allowed: true, level: risk.level };
106
+ }