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

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,211 @@
1
+ // policy/strategy-capabilities.js
2
+ // Structured capability binding for strategy/policy evaluation.
3
+ //
4
+ // Replaces loose substring matching (e.g. actionLower.includes(allowed)) with
5
+ // structured capability records that bind an action/tool to a precise scope.
6
+ //
7
+ // Capability shapes:
8
+ //
9
+ // { capability: "action.execute", action: "edit" } ← exact action
10
+ // { capability: "action.execute", action: "edit", tool: "edit_file" } ← action+tool
11
+ //
12
+ // { capability: "command.execute",
13
+ // executable: "npm",
14
+ // argsPattern: ["test"] } ← command + argv prefix
15
+ // { capability: "command.execute",
16
+ // executable: "npm",
17
+ // argsPattern: ["run", "lint"] } ← argv-prefix match
18
+ // { capability: "command.execute",
19
+ // executable: /^[a-z0-9_-]+$/i } ← regex on name
20
+ //
21
+ // { capability: "filesystem.write", scope: "src/**" } ← glob scope
22
+ // { capability: "filesystem.write", scope: "src/**", deny: ["**/*.env"] }
23
+ // { capability: "filesystem.read", scope: ["docs/**", "src/**"] }
24
+ //
25
+ // Matching rules:
26
+ // - exact match (string === string) for action / executable / scope-literal
27
+ // - regex (RegExp) when the value is a RegExp
28
+ // - glob (micromatch-style, `*` and `**` supported via small builtin matcher)
29
+ // - argsPattern: array of tokens matched against argv in order; a leading
30
+ // wildcard token "*" consumes any single argv slot.
31
+ //
32
+ // A capability is considered covered if and only if every required field
33
+ // matches the candidate. Missing optional fields on the candidate do not
34
+ // cause a non-match (they only narrow on the capability side).
35
+
36
+ // ---------- glob matcher (small, dependency-free) ----------
37
+
38
+ function globToRegExp(glob) {
39
+ // Escape regex special chars except for * and ? and **.
40
+ let re = "";
41
+ for (let i = 0; i < glob.length; i++) {
42
+ const c = glob[i];
43
+ if (c === "*") {
44
+ if (glob[i + 1] === "*") {
45
+ re += ".*";
46
+ i++;
47
+ if (glob[i + 1] === "/") i++; // consume optional trailing slash
48
+ } else {
49
+ re += "[^/]*";
50
+ }
51
+ } else if (c === "?") {
52
+ re += "[^/]";
53
+ } else if ("\\^$.|+()[]{}".includes(c)) {
54
+ re += "\\" + c;
55
+ } else {
56
+ re += c;
57
+ }
58
+ }
59
+ return new RegExp("^" + re + "$");
60
+ }
61
+
62
+ function matchGlob(value, pattern) {
63
+ if (typeof value !== "string" || typeof pattern !== "string") return false;
64
+ return globToRegExp(pattern).test(value);
65
+ }
66
+
67
+ // ---------- low-level value match ----------
68
+
69
+ function matchValue(actual, expected) {
70
+ if (expected instanceof RegExp) {
71
+ return typeof actual === "string" && expected.test(actual);
72
+ }
73
+ if (typeof expected === "string") {
74
+ if (typeof actual !== "string") return false;
75
+ // exact match only — substring is rejected by design
76
+ return actual === expected;
77
+ }
78
+ if (Array.isArray(expected)) {
79
+ if (!Array.isArray(actual)) return false;
80
+ if (actual.length !== expected.length) return false;
81
+ for (let i = 0; i < expected.length; i++) {
82
+ if (!matchValue(actual[i], expected[i])) return false;
83
+ }
84
+ return true;
85
+ }
86
+ return false;
87
+ }
88
+
89
+ // ---------- argv pattern matching ----------
90
+
91
+ // Pattern is an array of tokens (strings). Supports "*" as a single-segment
92
+ // wildcard that consumes exactly one argv slot. Does NOT do substring or
93
+ // loose matching.
94
+ function matchArgsPattern(argv, pattern) {
95
+ if (!Array.isArray(argv) || !Array.isArray(pattern)) return false;
96
+ if (pattern.length > argv.length) return false;
97
+ for (let i = 0; i < pattern.length; i++) {
98
+ const tok = pattern[i];
99
+ if (tok === "*") continue; // consume one slot, value unchecked
100
+ if (tok instanceof RegExp) {
101
+ if (typeof argv[i] !== "string" || !tok.test(argv[i])) return false;
102
+ continue;
103
+ }
104
+ if (tok !== argv[i]) return false;
105
+ }
106
+ return true;
107
+ }
108
+
109
+ // ---------- capability dispatch ----------
110
+
111
+ function matchActionCapability(cap, candidate) {
112
+ // candidate: { action, tool }
113
+ if (cap.action !== undefined && !matchValue(candidate.action, cap.action)) return false;
114
+ if (cap.tool !== undefined && !matchValue(candidate.tool, cap.tool)) return false;
115
+ return true;
116
+ }
117
+
118
+ function matchCommandCapability(cap, candidate) {
119
+ // candidate: { executable, args }
120
+ if (cap.executable === undefined && cap.argsPattern === undefined) return false;
121
+ if (cap.executable !== undefined) {
122
+ if (!matchValue(candidate.executable, cap.executable)) return false;
123
+ }
124
+ if (cap.argsPattern !== undefined) {
125
+ const argv = Array.isArray(candidate.args) ? candidate.args : [];
126
+ if (!matchArgsPattern(argv, cap.argsPattern)) return false;
127
+ }
128
+ return true;
129
+ }
130
+
131
+ function matchFilesystemCapability(cap, candidate) {
132
+ // candidate: { path, operation: "read" | "write" | "delete" | ... }
133
+ if (cap.scope === undefined) return false;
134
+ const paths = Array.isArray(cap.scope) ? cap.scope : [cap.scope];
135
+ const target = typeof candidate.path === "string" ? candidate.path : "";
136
+ let matched = false;
137
+ for (const pat of paths) {
138
+ if (matchGlob(target, pat)) { matched = true; break; }
139
+ }
140
+ if (!matched) return false;
141
+ if (Array.isArray(cap.deny)) {
142
+ for (const deny of cap.deny) {
143
+ if (matchGlob(target, deny)) return false; // explicit deny wins
144
+ }
145
+ }
146
+ return true;
147
+ }
148
+
149
+ // ---------- public API ----------
150
+
151
+ /**
152
+ * Match a single capability against a candidate descriptor.
153
+ * @param {object} cap capability record
154
+ * @param {object} candidate descriptor of the action being evaluated
155
+ * @returns {boolean}
156
+ */
157
+ export function matchesCapability(cap, candidate) {
158
+ if (!cap || typeof cap !== "object" || !candidate) return false;
159
+ const kind = cap.capability;
160
+ if (kind === "action.execute") return matchActionCapability(cap, candidate);
161
+ if (kind === "command.execute") return matchCommandCapability(cap, candidate);
162
+ if (kind === "filesystem.read" ||
163
+ kind === "filesystem.write" ||
164
+ kind === "filesystem.delete") return matchFilesystemCapability(cap, candidate);
165
+ return false;
166
+ }
167
+
168
+ /**
169
+ * Classify an action against a list of structured capabilities.
170
+ *
171
+ * @param {object} candidate descriptor (action/tool/executable/args/path/...)
172
+ * @param {object} capabilities { allowed: Capability[], prohibited: Capability[] }
173
+ * @returns {{ allowed: boolean, reason: string }}
174
+ *
175
+ * Order of evaluation:
176
+ * 1. Any matching prohibited capability → allowed=false, blocked.
177
+ * 2. Any matching allowed capability → allowed=true, covered.
178
+ * 3. Otherwise → allowed=false, not covered.
179
+ *
180
+ * Loose string substring matching is intentionally NOT supported here.
181
+ */
182
+ export function classifyByCapabilities(candidate, capabilities) {
183
+ if (!capabilities || typeof capabilities !== "object") {
184
+ return { allowed: false, reason: "no-capability-spec" };
185
+ }
186
+ const prohibited = Array.isArray(capabilities.prohibited) ? capabilities.prohibited : [];
187
+ for (const cap of prohibited) {
188
+ if (matchesCapability(cap, candidate)) {
189
+ return { allowed: false, reason: `prohibited-capability:${cap.capability}` };
190
+ }
191
+ }
192
+ const allowed = Array.isArray(capabilities.allowed) ? capabilities.allowed : [];
193
+ for (const cap of allowed) {
194
+ if (matchesCapability(cap, candidate)) {
195
+ return { allowed: true, reason: `allowed-capability:${cap.capability}` };
196
+ }
197
+ }
198
+ return { allowed: false, reason: "no-matching-capability" };
199
+ }
200
+
201
+ /**
202
+ * Convenience: build a normalized candidate from a raw (action, tool, args)
203
+ * triplet the way index.js classifies it today, so call sites don't have to.
204
+ */
205
+ export function buildCandidate({ action, tool, args }) {
206
+ const cmd = String(args?.command || args?.cmd || args?.script || "");
207
+ const argv = cmd.length > 0 ? cmd.split(/\s+/) : [];
208
+ const executable = argv[0] || "";
209
+ const rest = argv.slice(1);
210
+ return { action, tool, executable, args: rest, path: args?.path || args?.filePath };
211
+ }
@@ -0,0 +1,6 @@
1
+ export function createStrategy(name, rules) {
2
+ return { name, rules, status: "PROPOSED", createdAt: Date.now() };
3
+ }
4
+ export function validateStrategy(strategy) {
5
+ return strategy && strategy.name && strategy.rules;
6
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Clasifica la incertidumbre de una tarea.
3
+ * Rule-based, determinista (sin LLM). Prioridad de seguridad: critical > resolvable > non-blocking.
4
+ */
5
+ export function classifyUncertainty(item = "") {
6
+ const text = String(item);
7
+ const CRITICAL = [
8
+ /migra|migrate|migraci[oó]n|refresh.?token|rotar|dele|destructiv|borr|elim|data loss|p[ée]rdida de datos/i,
9
+ /seguridad|security|auth|oauth|token|api.?key|secret|password/i,
10
+ /schema|esquema|api contract|formato de respuesta|response shape|compatibil/i,
11
+ /arquitectura|architecture|scope|alcance|comportamiento|behavior|user.?visible|aceptaci[oó]n/i,
12
+ ];
13
+ const RESOLVABLE = [
14
+ /c[oó]mo se maneja|c[oó]mo funciona|c[oó]mo est[áa]|existe|hay |d[oó]nde est|qu[ée] herramienta|formato de|qu[ée] framework|qu[ée] versi[oó]n|config|tests?|documentaci[oó]n|endpoint existente|api existente/i,
15
+ ];
16
+ if (CRITICAL.some((p) => p.test(text))) return "DECISION_CRITICAL";
17
+ if (RESOLVABLE.some((p) => p.test(text))) return "RESOLVABLE";
18
+ return "NON_BLOCKING";
19
+ }
20
+
21
+ /** Convierte assumed/unknown del pre-flight en uncertainties clasificadas. */
22
+ export function buildUncertainties(assumed = [], unknown = []) {
23
+ const seen = new Set();
24
+ const uncertainties = [];
25
+ const entries = [
26
+ ...(assumed || []).map((a) => ({ kind: "ASSUMED", text: String(a) })),
27
+ ...(unknown || []).map((u) => ({ kind: "UNKNOWN", text: String(u) })),
28
+ ];
29
+ for (const { kind, text } of entries) {
30
+ if (!text || seen.has(text)) continue;
31
+ seen.add(text);
32
+ uncertainties.push({
33
+ id: `U${uncertainties.length + 1}`,
34
+ question: text,
35
+ kind,
36
+ classification: classifyUncertainty(text),
37
+ status: "active",
38
+ });
39
+ }
40
+ return uncertainties;
41
+ }
42
+
43
+ const ASSUMPTION_IMPACT =
44
+ /elim|delet|borr|actualiz|update|schema|esquema|migraci|endpoint|api|arquitectur|estructura|m[oó]dulo|seguridad|auth|token|compatib|breaking|alcance|scope|destructiv|data.?loss|aceptaci[oó]n|criterios/i;
45
+
46
+ /** Clasifica una asunción: DECISION_CRITICAL si toca impacto material. */
47
+ export function classifyAssumption(statement = "") {
48
+ return ASSUMPTION_IMPACT.test(statement) ? "DECISION_CRITICAL" : "NON_BLOCKING";
49
+ }
50
+
51
+ /**
52
+ * Convierte asunciones textuales del análisis en objetos de estado.
53
+ */
54
+ export function buildAssumptions(assumed = []) {
55
+ const seen = new Set();
56
+ const out = [];
57
+ for (const s of assumed || []) {
58
+ if (!s || typeof s !== "string") continue;
59
+ if (seen.has(s)) continue;
60
+ seen.add(s);
61
+ out.push({
62
+ id: `A${out.length + 1}`,
63
+ statement: s,
64
+ classification: classifyAssumption(s),
65
+ status: "active",
66
+ });
67
+ }
68
+ return out;
69
+ }
70
+
71
+ export function escalateAssumptions(state, taskText = "") {
72
+ const contract = state?.contract || {};
73
+ const escalated = [];
74
+ const assumptions = contract.assumptions || [];
75
+ let unknowns = contract.unknowns || [];
76
+ let changed = false;
77
+
78
+ for (const a of assumptions) {
79
+ if (a.status === "active" && a.classification === "NON_BLOCKING") {
80
+ const taskImpact = !!taskText && ASSUMPTION_IMPACT.test(taskText);
81
+ const genericAssumption = /funcionalidad|agregar nueva|nueva funcionalidad|add support|add.*support/i.test(a.statement);
82
+ const cls =
83
+ classifyAssumption(a.statement) === "DECISION_CRITICAL" ||
84
+ (taskImpact && genericAssumption)
85
+ ? "DECISION_CRITICAL"
86
+ : "NON_BLOCKING";
87
+ if (cls === "DECISION_CRITICAL") {
88
+ a.classification = cls;
89
+ a.status = "blocking";
90
+ const existing = unknowns.find((u) => u.status === "blocking" && !u.assumptionId);
91
+ if (existing) {
92
+ existing.assumptionId = a.id;
93
+ } else if (!unknowns.some((u) => u.assumptionId === a.id)) {
94
+ unknowns = [
95
+ ...unknowns,
96
+ {
97
+ id: `U${unknowns.length + 1}`,
98
+ kind: "ASSUMED",
99
+ question: `¿${a.statement}?`,
100
+ status: "blocking",
101
+ assumptionId: a.id,
102
+ },
103
+ ];
104
+ }
105
+ escalated.push(a);
106
+ changed = true;
107
+ }
108
+ }
109
+ }
110
+
111
+ if (changed) {
112
+ contract.assumptions = assumptions;
113
+ contract.unknowns = unknowns;
114
+ state.contract = contract;
115
+ }
116
+ return { escalated, changed };
117
+ }
@@ -0,0 +1,44 @@
1
+ export function createContainer() {
2
+ const registry = new Map(); // name -> { factory, singleton, instance }
3
+
4
+ function register(name, factory, { singleton = true } = {}) {
5
+ if (typeof factory !== 'function') {
6
+ throw new TypeError(`Factory for "${name}" must be a function`);
7
+ }
8
+ registry.set(name, { factory, singleton, instance: undefined });
9
+ }
10
+
11
+ function resolve(name) {
12
+ const entry = registry.get(name);
13
+ if (!entry) {
14
+ throw new Error(`Dependency "${name}" is not registered`);
15
+ }
16
+ if (entry.singleton) {
17
+ if (entry.instance === undefined) {
18
+ entry.instance = entry.factory();
19
+ }
20
+ return entry.instance;
21
+ }
22
+ return entry.factory();
23
+ }
24
+
25
+ function has(name) {
26
+ return registry.has(name);
27
+ }
28
+
29
+ function unregister(name) {
30
+ if (!registry.has(name)) return false;
31
+ registry.delete(name);
32
+ return true;
33
+ }
34
+
35
+ function clear() {
36
+ registry.clear();
37
+ }
38
+
39
+ function list() {
40
+ return Array.from(registry.keys());
41
+ }
42
+
43
+ return { register, resolve, has, unregister, clear, list };
44
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Decision Types — Standardized outcomes for WAM orchestration.
3
+ *
4
+ * Every decision returns a consistent structure:
5
+ * {
6
+ * action: string, // 'CONTINUE', 'BLOCK', 'REPLAN', 'VERIFY'
7
+ * reason: string,
8
+ * stateChange: object | null, // Optional state delta
9
+ * evidenceNeeded: boolean,
10
+ * critical: boolean
11
+ * }
12
+ */
13
+
14
+ export function createDecision(action, reason, { stateChange = null, evidenceNeeded = false, critical = false } = {}) {
15
+ return { action, reason, stateChange, evidenceNeeded, critical };
16
+ }
17
+
18
+ export const ACTIONS = {
19
+ CONTINUE: "CONTINUE",
20
+ BLOCK: "BLOCK",
21
+ REPLAN: "REPLAN",
22
+ VERIFY: "VERIFY",
23
+ DONE: "DONE"
24
+ };
@@ -0,0 +1,160 @@
1
+ // Simple standalone test - doesn't import the full plugin
2
+ // Just tests the core logic functions
3
+
4
+ function assert(condition, message) {
5
+ if (!condition) throw new Error(message || 'Assertion failed');
6
+ }
7
+
8
+ console.log('=== Wait a Minute Simple Test Suite ===\n');
9
+
10
+ let passed = 0;
11
+ let failed = 0;
12
+
13
+ // Test 1: isTrivial detects rename
14
+ console.log('1. isTrivial detects rename');
15
+ try {
16
+ // Mock the isTrivial logic
17
+ const lower = 'rename variable x to y'.toLowerCase();
18
+ const fastPatterns = [
19
+ /^\s*rename\s+/i,
20
+ /^\s*change\s+\w+/i,
21
+ /^\s*what(is|are)\s+/i,
22
+ /^\s*explain\s+/i,
23
+ /^\s*how\s+to\s+/i,
24
+ /^\s*list\s+/i,
25
+ /^\s*show\s+\w+/i,
26
+ /^\s*get\s+\w+/i,
27
+ /^\s*error\s+line/i,
28
+ /^\s*fix\s+this/i,
29
+ ];
30
+ let is trivial = false;
31
+ for (const pattern of fastPatterns) {
32
+ if (pattern.test(lower)) { isTrivial = true; break; }
33
+ }
34
+ assert(isTrivial === true, 'rename should be detected as trivial');
35
+ console.log(' ✓ rename detected as trivial');
36
+ passed++;
37
+ } catch (e) {
38
+ console.log(` ✗ Falló: ${e.message}`);
39
+ failed++;
40
+ }
41
+
42
+ // Test 2: requiresStrict detects migrate
43
+ console.log('2. requiresStrict detects migrate');
44
+ try {
45
+ const lower = 'migra PostgreSQL a la nube'.toLowerCase();
46
+ const strictPatterns = [
47
+ /migra|migrate/i,
48
+ /seguridad|security/i,
49
+ /arquitectura|architecture/i,
50
+ /alto impacto|high impact/i,
51
+ /producción|production/i,
52
+ /destructivo|destructive/i,
53
+ ];
54
+ const result = strictPatterns.some(p => p.test(lower));
55
+ assert(result === true, 'migrate should trigger STRICT');
56
+ console.log(' ✓ migrate detected as STRICT trigger');
57
+ passed++;
58
+ } catch (e) {
59
+ console.log(` ✗ Falló: ${e.message}`);
60
+ failed++;
61
+ }
62
+
63
+ // Test 3: analyze returns structure
64
+ console.log('3. analyze returns structured result');
65
+ try {
66
+ // Minimal test - just check the function exists and has expected shape
67
+ const analyze = async (opts) => {
68
+ const prompt = opts.prompt || '';
69
+ if (!prompt || typeof prompt !== 'string') {
70
+ return { intent: { classification: 'trivial', ambiguity: 'low', confidence: 100 }, project: { detected_stack: 'unknown', architecture: 'unknown', relevant_files: [] }, known: [], inferred: [], assumed: [], unknown: ['No hay prompt para analizar'], skills: { candidates: [], selected: [], rejected: [] }, risk: 'low', complexity: 'trivial', ambiguity: 'low', strategy: 'FAST', ready: true, advice: 'Sin prompt - sin análisis necesario' };
71
+ }
72
+ return { intent: { classification: 'normal', ambiguity: 'medium', confidence: 50 }, project: { detected_stack: 'unknown', architecture: 'unknown', relevant_files: [] }, known: [], inferred: [], assumed: [], unknown: [], skills: { candidates: [], selected: [], rejected: [] }, risk: 'medium', complexity: 'medium', ambiguity: 'medium', strategy: 'NORMAL', ready: false, advice: 'Requiere análisis' };
73
+ };
74
+
75
+ const r = await analyze({ prompt: 'test prompt' });
76
+ assert(r.intent.classification === 'normal', 'Classification should be present');
77
+ assert(r.skills.selected instanceof Array, 'Skills selected should be array');
78
+ assert(r.risk === 'medium', 'Risk should be medium');
79
+ assert(r.strategy === 'NORMAL', 'Strategy should be NORMAL');
80
+ assert(r.ready === false, 'Ready should be false for non-trivial');
81
+ console.log(' ✓ analyze returns structured result');
82
+ passed++;
83
+ } catch (e) {
84
+ console.log(` ✗ Falló: ${e.message}`);
85
+ failed++;
86
+ }
87
+
88
+ // Test 4: isTrivial with various patterns
89
+ console.log('4. isTrivial with various patterns');
90
+ try {
91
+ const testPrompts = [
92
+ { prompt: 'list files', expected: true },
93
+ { prompt: 'show help', expected: true },
94
+ { prompt: 'explain this function', expected: true },
95
+ { prompt: 'change this variable', expected: true },
96
+ { prompt: 'agrega Redis', expected: false }, // ambiguous, not in fast patterns
97
+ { prompt: 'migra base de datos', expected: false }, // not trivial
98
+ ];
99
+
100
+ const fastPatterns = [
101
+ /^\s*rename\s+/i,
102
+ /^\s*change\s+\w+/i,
103
+ /^\s*what(is|are)\s+/i,
104
+ /^\s*explain\s+/i,
105
+ /^\s*how\s+to\s+/i,
106
+ /^\s*list\s+/i,
107
+ /^\s*show\s+\w+/i,
108
+ /^\s*get\s+\w+/i,
109
+ /^\s*error\s+line/i,
110
+ /^\s*fix\s+this/i,
111
+ ];
112
+
113
+ for (const {prompt, expected} of testPrompts) {
114
+ const lower = prompt.toLowerCase();
115
+ let is trivial = false;
116
+ for (const pattern of fastPatterns) {
117
+ if (pattern.test(lower)) { isTrivial = true; break; }
118
+ }
119
+ assert(isTrivial === expected, `${prompt}: expected ${expected}, got ${isTrivial}`);
120
+ }
121
+ console.log(' ✓ isTrivial works with multiple patterns');
122
+ passed++;
123
+ } catch (e) {
124
+ console.log(` ✗ Falló: ${e.message}`);
125
+ failed++;
126
+ }
127
+
128
+ // Test 5: requiresStrict with various patterns
129
+ console.log('5. requiresStrict with various patterns');
130
+ try {
131
+ const strictPatterns = [
132
+ /migra|migrate/i,
133
+ /seguridad|security/i,
134
+ /arquitectura|architecture/i,
135
+ /alto impacto|high impact/i,
136
+ /producción|production/i,
137
+ /destructivo|destructive/i,
138
+ ];
139
+
140
+ const tests = [
141
+ { prompt: 'migra PostgreSQL', expected: true },
142
+ { prompt: 'seguridad del endpoint', expected: true },
143
+ { prompt: 'refactor module', expected: false },
144
+ { prompt: 'agrega cache', expected: false },
145
+ ];
146
+
147
+ for (const {prompt, expected} of tests) {
148
+ const lower = prompt.toLowerCase();
149
+ const result = strictPatterns.some(p => p.test(lower));
150
+ assert(result === expected, `${prompt}: expected ${expected}, got ${result}`);
151
+ }
152
+ console.log(' ✓ requiresStrict works with multiple patterns');
153
+ passed++;
154
+ } catch (e) {
155
+ console.log(` ✗ Falló: ${e.message}`);
156
+ failed++;
157
+ }
158
+
159
+ console.log(`\n=== Results: ${passed} passed, ${failed} failed ===`);
160
+ process.exitCode = failed > 0 ? 1 : 0;
@@ -0,0 +1,52 @@
1
+ export const WAM_EVENTS = {
2
+ CONTEXT_LOADED: "CONTEXT_LOADED",
3
+ CONTEXT_INVALIDATED: "CONTEXT_INVALIDATED",
4
+ CLAIM_CREATED: "CLAIM_CREATED",
5
+ REQUIREMENT_CREATED: "REQUIREMENT_CREATED",
6
+ ACTION_STARTED: "ACTION_STARTED",
7
+ ACTION_COMPLETED: "ACTION_COMPLETED",
8
+ OBSERVATION_CREATED: "OBSERVATION_CREATED",
9
+ EVIDENCE_ADDED: "EVIDENCE_ADDED",
10
+ EVIDENCE_CONFLICT: "EVIDENCE_CONFLICT",
11
+ VERIFICATION_STARTED: "VERIFICATION_STARTED",
12
+ VERIFICATION_COMPLETED: "VERIFICATION_COMPLETED",
13
+ COMPLETION_BLOCKED: "COMPLETION_BLOCKED",
14
+ TASK_COMPLETED: "TASK_COMPLETED",
15
+ };
16
+
17
+ export function createEvent(type, data = {}) {
18
+ return {
19
+ id: `evt-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 7)}`,
20
+ type,
21
+ data,
22
+ timestamp: Date.now(),
23
+ };
24
+ }
25
+
26
+ export function logEvent(type, data, eventLog = []) {
27
+ const event = createEvent(type, data);
28
+ eventLog.push(event);
29
+ return event;
30
+ }
31
+
32
+ export function createDecisionTrace(decision) {
33
+ return {
34
+ id: `trace-${Date.now().toString(36)}`,
35
+ decision,
36
+ chain: [],
37
+ timestamp: Date.now(),
38
+ };
39
+ }
40
+
41
+ export function addToTrace(trace, step) {
42
+ return {
43
+ ...trace,
44
+ chain: [...trace.chain, { ...step, timestamp: Date.now() }],
45
+ };
46
+ }
47
+
48
+ export function formatDecisionTrace(trace) {
49
+ return trace.chain
50
+ .map((step, idx) => `${idx + 1}. [${step.type}] ${step.description}`)
51
+ .join("\n");
52
+ }