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.
- package/LICENSE +21 -0
- package/README.md +318 -2
- package/index.js +1836 -0
- package/package.json +70 -4
- package/skills/codebase-design/SKILL.md +114 -0
- package/skills/design-contract/SKILL.md +27 -0
- package/skills/design-critique/SKILL.md +19 -0
- package/skills/design-system/SKILL.md +17 -0
- package/skills/design-system/references/image-analysis.md +14 -0
- package/skills/design-system/references/tokens.md +32 -0
- package/skills/design-system/references/ui-rules.md +14 -0
- package/skills/diagnosing-bugs/SKILL.md +138 -0
- package/skills/frontend-design/SKILL.md +36 -0
- package/skills/handoff/SKILL.md +16 -0
- package/skills/improve-codebase-architecture/SKILL.md +71 -0
- package/skills/linter-negative/SKILL.md +74 -0
- package/skills/no-slop-ui/SKILL.md +26 -0
- package/skills/prototype/SKILL.md +26 -0
- package/skills/registry.json +44087 -0
- package/skills/tastemaker/SKILL.md +8 -0
- package/skills/tastemaker/references/tastemaker.md +14 -0
- package/skills/tdd/SKILL.md +38 -0
- package/skills/visual-review/SKILL.md +103 -0
- package/skills/visual-review/references/review-gates.md +42 -0
- package/skills/visual-review/references/surface-archetypes.md +37 -0
- package/skills/wizard/SKILL.md +44 -0
- package/skills/writing-for-agents/SKILL.md +81 -0
- package/src/cognition/cognition-store.js +251 -0
- package/src/cognition/cognitive-state.js +126 -0
- package/src/cognition/hypothesis-manager.js +113 -0
- package/src/cognition/observation-engine.js +112 -0
- package/src/cognition/observation-provenance.js +268 -0
- package/src/context/active-context-boundary.js +68 -0
- package/src/context/assembly.js +494 -0
- package/src/context/assessment-rules.js +55 -0
- package/src/context/capsule-staleness.js +267 -0
- package/src/context/capsules.js +2 -0
- package/src/context/compare-array.js +98 -0
- package/src/context/compare-object.js +89 -0
- package/src/context/compare-values.js +42 -0
- package/src/context/context-assembly-contract.js +71 -0
- package/src/context/context-budget-manager.js +232 -0
- package/src/context/context-builder.js +49 -0
- package/src/context/context-cache.js +55 -0
- package/src/context/context-capture.js +243 -0
- package/src/context/context-classification.js +199 -0
- package/src/context/context-compaction.js +179 -0
- package/src/context/context-decision-audit.js +267 -0
- package/src/context/context-demotion.js +173 -0
- package/src/context/context-dictionary.js +106 -0
- package/src/context/context-drift-detection.js +225 -0
- package/src/context/context-evaluation.js +374 -0
- package/src/context/context-event-ingress.js +100 -0
- package/src/context/context-event-normalization.js +224 -0
- package/src/context/context-feedback-loop.js +216 -0
- package/src/context/context-freshness.js +21 -0
- package/src/context/context-graph-builder.js +71 -0
- package/src/context/context-graph.js +451 -0
- package/src/context/context-history-relevance.js +321 -0
- package/src/context/context-interception.js +145 -0
- package/src/context/context-invalidation-events.js +154 -0
- package/src/context/context-lifecycle.js +170 -0
- package/src/context/context-loop-prevention.js +347 -0
- package/src/context/context-manager.js +340 -0
- package/src/context/context-memory-layers.js +265 -0
- package/src/context/context-minimality.js +166 -0
- package/src/context/context-normalization.js +130 -0
- package/src/context/context-optimization-metrics.js +434 -0
- package/src/context/context-output-policy.js +135 -0
- package/src/context/context-pack-authority.js +157 -0
- package/src/context/context-promotion.js +172 -0
- package/src/context/context-query-contract.js +101 -0
- package/src/context/context-ranking.js +164 -0
- package/src/context/context-rate-distortion.js +261 -0
- package/src/context/context-recovery.js +209 -0
- package/src/context/context-retrieval-integration.js +60 -0
- package/src/context/context-retrieval.js +93 -0
- package/src/context/context-router.js +457 -0
- package/src/context/context-routing-evaluation.js +331 -0
- package/src/context/context-routing-observability.js +296 -0
- package/src/context/context-routing-shadow.js +237 -0
- package/src/context/context-scope.js +181 -0
- package/src/context/context-snapshot.js +226 -0
- package/src/context/context-source-registry.js +95 -0
- package/src/context/context-sufficiency-gate.js +120 -0
- package/src/context/context-sufficiency-oracle.js +167 -0
- package/src/context/context-telemetry.js +176 -0
- package/src/context/context.js +633 -0
- package/src/context/dependency-closure.js +246 -0
- package/src/context/page-fault-tracker.js +275 -0
- package/src/context/prompt-engine.js +74 -0
- package/src/context/runtime-context-graph.js +260 -0
- package/src/context/selection.js +2 -0
- package/src/context/session.js +2 -0
- package/src/context/sufficiency-contract.js +300 -0
- package/src/context/tokenizer.js +17 -0
- package/src/context-benchmark-router.mjs +125 -0
- package/src/evidence/evidence-engine.js +161 -0
- package/src/evidence/evidence-factory.js +3 -0
- package/src/evidence/evidence-freshness.js +463 -0
- package/src/evidence/evidence-gap.js +76 -0
- package/src/evidence/evidence-lineage.js +525 -0
- package/src/evidence/evidence.js +136 -0
- package/src/evidence/freshness-validation.js +187 -0
- package/src/evidence/lineage.js +4 -0
- package/src/execution/action-evaluation.js +179 -0
- package/src/execution/circuit-breaker.js +70 -0
- package/src/execution/claim-interception.js +63 -0
- package/src/execution/execution-engine.js +258 -0
- package/src/execution/execution-intent.js +69 -0
- package/src/execution/execution-state.js +89 -0
- package/src/execution/formatting.js +60 -0
- package/src/execution/l1-sanitize.js +16 -0
- package/src/execution/l2-resource-guards.js +19 -0
- package/src/execution/l3-invariant-checker.js +5 -0
- package/src/execution/l4-containment.js +6 -0
- package/src/execution/runtime-guards.js +106 -0
- package/src/execution/strategy-identity.js +162 -0
- package/src/execution/tool-interceptor.js +7 -0
- package/src/execution/tool-result-classifier.js +63 -0
- package/src/integration/canary-deploy.js +143 -0
- package/src/integration/collector.js +59 -0
- package/src/integration/error-recovery.js +6 -0
- package/src/integration/event-bus.js +66 -0
- package/src/integration/health-checker.js +57 -0
- package/src/integration/logger.js +39 -0
- package/src/integration/message-handler.js +611 -0
- package/src/integration/opencode-db.js +153 -0
- package/src/integration/orchestration.js +419 -0
- package/src/integration/part-provenance.js +65 -0
- package/src/integration/rate-limiter.js +55 -0
- package/src/integration/release-gate.js +336 -0
- package/src/integration/rollback-manager.js +164 -0
- package/src/integration/router-adapter.js +269 -0
- package/src/integration/telemetry.js +45 -0
- package/src/integration/update-checker.js +10 -0
- package/src/persistence/event-sourcing.js +75 -0
- package/src/persistence/memory.js +501 -0
- package/src/persistence/migration-runner.js +16 -0
- package/src/persistence/persistence-manager.js +39 -0
- package/src/persistence/transaction-log.js +157 -0
- package/src/policy/action-capabilities.js +116 -0
- package/src/policy/action-policy.js +4 -0
- package/src/policy/assessment-engine.js +104 -0
- package/src/policy/assumption-tracking.js +66 -0
- package/src/policy/budget-enforcer.js +7 -0
- package/src/policy/config-validator.js +102 -0
- package/src/policy/execution-assessment.js +142 -0
- package/src/policy/failure-classification.js +5 -0
- package/src/policy/feature-flags.js +65 -0
- package/src/policy/governance-enforcement.js +118 -0
- package/src/policy/locale.js +15 -0
- package/src/policy/multi-signer.js +151 -0
- package/src/policy/policy-state-machine.js +97 -0
- package/src/policy/ponytail-constraint.js +38 -0
- package/src/policy/project-inspector.js +93 -0
- package/src/policy/query-builder.js +14 -0
- package/src/policy/request-classifier.js +79 -0
- package/src/policy/risk-engine.js +266 -0
- package/src/policy/scope-enforcement.js +140 -0
- package/src/policy/secret-scanner.js +68 -0
- package/src/policy/skill-routing.js +104 -0
- package/src/policy/strategy-capabilities.js +211 -0
- package/src/policy/strategy.js +6 -0
- package/src/policy/uncertainty.js +117 -0
- package/src/shared/container.js +44 -0
- package/src/shared/decision-types.js +24 -0
- package/src/shared/simple-test.js +160 -0
- package/src/shared/wam-events.js +52 -0
- package/src/skills/engine.js +1705 -0
- package/src/skills/skill-registry.js +19 -0
- package/src/skills/skill-routing.js +340 -0
- package/src/state/lifecycle-manager.js +113 -0
- package/src/state/operational-state.js +198 -0
- package/src/state/projections.js +47 -0
- package/src/state/replay-engine.js +5 -0
- package/src/state/requirement-ownership.js +20 -0
- package/src/state/requirement-state.js +152 -0
- package/src/state/run-event-identity.js +172 -0
- package/src/state/state-engine.js +19 -0
- package/src/state/state-machine.js +119 -0
- package/src/state/state-schema.js +318 -0
- package/src/state/state-store.js +335 -0
- package/src/state/state-transition.js +84 -0
- package/src/state/task-dependencies.js +287 -0
- package/src/state/task-execution.js +217 -0
- package/src/state/task-lifecycle.js +59 -0
- package/src/state/task-runs.js +361 -0
- package/src/state/task-state-file.js +86 -0
- package/src/state/task-state.js +41 -0
- package/src/state/task-status.js +54 -0
- package/src/state/task-store.js +48 -0
- package/src/state/wam-state.js +148 -0
- package/src/verification/completion-gate-simple.js +8 -0
- package/src/verification/completion-gate.js +183 -0
- package/src/verification/contract.js +9 -0
- package/src/verification/contradiction-resolution.js +255 -0
- package/src/verification/diagnostic-engine.js +659 -0
- package/src/verification/false-completion-prevention.js +100 -0
- package/src/verification/hook-validator.js +6 -0
- package/src/verification/requirements.js +6 -0
- package/src/verification/verification-context.js +162 -0
- package/src/verification/verification-lifecycle.js +66 -0
- package/src/verification/verification-model.js +89 -0
- package/src/verification/verification-persistence.js +129 -0
- package/src/verification/verification-policy.js +127 -0
- 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,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
|
+
}
|