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,260 @@
1
+ /**
2
+ * Runtime Context Graph — canonical assembler for all runtime state layers.
3
+ *
4
+ * Unifies taskState, runState, evidenceLineage, cognitionState, decisions,
5
+ * constraints, artifacts, observations, hypotheses, and experiments into a
6
+ * single ContextGraph. Replaces the shallow buildGraphFromTaskState() that
7
+ * only saw (task, requirements, evidence) with a layer-aware builder that
8
+ * creates nodes/edges for every state slice present in the runtime.
9
+ *
10
+ * Pattern follows context-graph-builder.js but expands coverage to:
11
+ * - task, requirements
12
+ * - evidence (lineage)
13
+ * - decisions, constraints
14
+ * - artifacts
15
+ * - observations
16
+ * - hypotheses, experiments (only when supplied)
17
+ *
18
+ * Edges are added only when both endpoints exist.
19
+ */
20
+
21
+ import { ContextGraph } from "./context-graph.js";
22
+ import { buildContextGraph } from "./context-graph-builder.js";
23
+
24
+ /**
25
+ * @typedef {Object} BuildRuntimeContextGraphInput
26
+ * @property {Object} [taskState]
27
+ * @property {Object} [runState]
28
+ * @property {Array} [evidenceLineage]
29
+ * @property {Object} [cognitionState]
30
+ * @property {Array} [decisions]
31
+ * @property {Array} [constraints]
32
+ * @property {Array} [artifacts]
33
+ * @property {Array} [observations]
34
+ * @property {Array} [hypotheses]
35
+ * @property {Array} [experiments]
36
+ */
37
+
38
+ /**
39
+ * Build a canonical ContextGraph from all runtime state layers.
40
+ *
41
+ * @param {BuildRuntimeContextGraphInput} input
42
+ * @returns {ContextGraph}
43
+ */
44
+ export function buildRuntimeContextGraph(input = {}) {
45
+ const {
46
+ taskState = {},
47
+ runState = {},
48
+ evidenceLineage = [],
49
+ cognitionState = {},
50
+ decisions = [],
51
+ constraints = [],
52
+ artifacts = [],
53
+ observations = [],
54
+ hypotheses = [],
55
+ experiments = [],
56
+ } = input;
57
+
58
+ // Canonical primary source: delegate base graph (task + requirements +
59
+ // evidence) to context-graph-builder.js so node/edge schema and IDs
60
+ // stay canonical. The remaining state layers (cognition, decisions,
61
+ // constraints, artifacts, observations, hypotheses, experiments) are
62
+ // added below on top of the canonical base.
63
+ const g = buildContextGraph(taskState, runState, evidenceLineage);
64
+ const taskId = taskState?.taskId || null;
65
+
66
+ // -- Requirement shadow output nodes (router compatibility) --
67
+ // The canonical requirement node + the task→requirement edge are
68
+ // already produced by buildContextGraph() above. We only need the
69
+ // shadow "output" node per requirement so Context Router's Phase 3
70
+ // collection can resolve output-type ids.
71
+ const requirementIds = new Set();
72
+ for (const req of taskState?.requirements || []) {
73
+ if (!req?.id) continue;
74
+ requirementIds.add(req.id);
75
+ const outputId = `${req.id}::output`;
76
+ g.addNode({
77
+ id: outputId,
78
+ type: "output",
79
+ content: req.title || req.description || "",
80
+ metadata: {
81
+ provenance: "user_decided",
82
+ shadowOf: req.id,
83
+ },
84
+ });
85
+ if (taskId) {
86
+ g.addEdge({ from: taskId, to: outputId, type: "related_to" });
87
+ }
88
+ }
89
+
90
+ // -- Evidence lineage (evidence supports requirement when linked) --
91
+ for (const ev of evidenceLineage || []) {
92
+ if (!ev?.id) continue;
93
+ g.addNode({
94
+ id: ev.id,
95
+ type: "evidence",
96
+ content: ev.content || ev.summary || "",
97
+ verified: ev.status === "valid" || ev.verified === true,
98
+ metadata: {
99
+ provenance: "run_execution",
100
+ source: ev.source || null,
101
+ capturedAt: ev.capturedAt || null,
102
+ },
103
+ });
104
+ if (ev.requirementId && requirementIds.has(ev.requirementId)) {
105
+ g.addEdge({ from: ev.id, to: ev.requirementId, type: "supports" });
106
+ } else if (taskId) {
107
+ g.addEdge({ from: ev.id, to: taskId, type: "supports" });
108
+ }
109
+ }
110
+
111
+ // -- Decisions (decision influences requirement/task) --
112
+ for (const dec of decisions || []) {
113
+ if (!dec?.id) continue;
114
+ g.addNode({
115
+ id: dec.id,
116
+ type: "decision",
117
+ content: dec.summary || dec.description || dec.content || "",
118
+ metadata: {
119
+ provenance: dec.provenance || "user_decided",
120
+ madeAt: dec.madeAt || null,
121
+ status: dec.status || "accepted",
122
+ },
123
+ });
124
+ if (dec.requirementId && requirementIds.has(dec.requirementId)) {
125
+ g.addEdge({ from: dec.id, to: dec.requirementId, type: "supports" });
126
+ } else if (taskId) {
127
+ g.addEdge({ from: dec.id, to: taskId, type: "supports" });
128
+ }
129
+ }
130
+
131
+ // -- Constraints (constraint constrains task/requirement) --
132
+ for (const c of constraints || []) {
133
+ if (!c?.id) continue;
134
+ g.addNode({
135
+ id: c.id,
136
+ type: "constraint",
137
+ content: c.description || c.content || c.summary || "",
138
+ metadata: {
139
+ provenance: c.provenance || "user_decided",
140
+ severity: c.severity || "normal",
141
+ relation: "constraint",
142
+ },
143
+ });
144
+ const target = c.requirementId || taskId;
145
+ if (target) {
146
+ g.addEdge({ from: target, to: c.id, type: "related_to" });
147
+ }
148
+ }
149
+
150
+ // -- Artifacts (task produces artifact) --
151
+ for (const a of artifacts || []) {
152
+ if (!a?.id) continue;
153
+ g.addNode({
154
+ id: a.id,
155
+ type: "artifact",
156
+ content: a.content || a.path || a.summary || "",
157
+ metadata: {
158
+ provenance: a.provenance || "run_execution",
159
+ path: a.path || null,
160
+ kind: a.kind || "generic",
161
+ },
162
+ });
163
+ // taskId is the canonical producer; fall back to requirement only
164
+ // when no task is in scope.
165
+ const producer = taskId || a.taskId || a.requirementId;
166
+ if (producer) {
167
+ g.addEdge({ from: producer, to: a.id, type: "produces" });
168
+ }
169
+ if (a.requirementId && requirementIds.has(a.requirementId)) {
170
+ g.addEdge({ from: a.id, to: a.requirementId, type: "supports" });
171
+ }
172
+ }
173
+
174
+ // -- Observations (observation relates to task) --
175
+ for (const o of observations || []) {
176
+ if (!o?.id) continue;
177
+ g.addNode({
178
+ id: o.id,
179
+ type: "observation",
180
+ content: o.content || o.summary || "",
181
+ metadata: {
182
+ provenance: o.provenance || "run_execution",
183
+ observedAt: o.observedAt || null,
184
+ },
185
+ });
186
+ const target = o.requirementId || o.taskId || taskId;
187
+ if (target) {
188
+ g.addEdge({ from: o.id, to: target, type: "related_to" });
189
+ }
190
+ }
191
+
192
+ // -- Hypotheses (only when present) --
193
+ for (const h of hypotheses || []) {
194
+ if (!h?.id) continue;
195
+ g.addNode({
196
+ id: h.id,
197
+ type: "claim",
198
+ content: h.statement || h.content || "",
199
+ metadata: {
200
+ provenance: h.provenance || "user_decided",
201
+ confidence: h.confidence ?? null,
202
+ kind: "hypothesis",
203
+ },
204
+ });
205
+ const target = h.requirementId || h.taskId || taskId;
206
+ if (target) {
207
+ g.addEdge({ from: h.id, to: target, type: "related_to" });
208
+ }
209
+ }
210
+
211
+ // -- Experiments (only when present) --
212
+ for (const x of experiments || []) {
213
+ if (!x?.id) continue;
214
+ g.addNode({
215
+ id: x.id,
216
+ type: "action",
217
+ content: x.description || x.content || "",
218
+ metadata: {
219
+ provenance: x.provenance || "run_execution",
220
+ status: x.status || "planned",
221
+ kind: "experiment",
222
+ },
223
+ });
224
+ if (x.hypothesisId && g.hasNode(x.hypothesisId)) {
225
+ g.addEdge({ from: x.id, to: x.hypothesisId, type: "supports" });
226
+ }
227
+ const target = x.requirementId || taskId;
228
+ if (target) {
229
+ g.addEdge({ from: x.id, to: target, type: "produces" });
230
+ }
231
+ }
232
+
233
+ // -- Cognition summary node (single node when cognitionState present) --
234
+ if (cognitionState && Object.keys(cognitionState).length > 0) {
235
+ const cogId = cognitionState.id || `cognition:${taskId || "global"}`;
236
+ if (!g.hasNode(cogId)) {
237
+ g.addNode({
238
+ id: cogId,
239
+ type: "observation",
240
+ content:
241
+ cognitionState.summary ||
242
+ cognitionState.objective ||
243
+ "Active cognition state",
244
+ metadata: {
245
+ provenance: "run_execution",
246
+ kind: "cognition",
247
+ load: cognitionState.load ?? null,
248
+ focus: cognitionState.focus || null,
249
+ },
250
+ });
251
+ if (taskId) {
252
+ g.addEdge({ from: cogId, to: taskId, type: "related_to" });
253
+ }
254
+ }
255
+ }
256
+
257
+ return g;
258
+ }
259
+
260
+ export default { buildRuntimeContextGraph };
@@ -0,0 +1,2 @@
1
+ import { selectContext, retrieveContext } from "./context.js";
2
+ export { selectContext, retrieveContext };
@@ -0,0 +1,2 @@
1
+ import { getSessionId } from "./context.js";
2
+ export { getSessionId };
@@ -0,0 +1,300 @@
1
+ /**
2
+ * Context Sufficiency Contract — task-derived conditions for safe execution.
3
+ *
4
+ * Replaces lexical keyword matching with structured conditions that
5
+ * must be satisfied before autonomous execution is permitted.
6
+ *
7
+ * States: SATISFIED | MISSING | BLOCKED | UNKNOWN
8
+ */
9
+
10
+ /**
11
+ * @typedef {"SATISFIED" | "MISSING" | "BLOCKED" | "UNKNOWN"} ConditionStatus
12
+ */
13
+
14
+ /**
15
+ * @typedef {Object} SufficiencyCondition
16
+ * @property {string} id
17
+ * @property {string} type - Type of required knowledge
18
+ * @property {string} description
19
+ * @property {ConditionStatus} status
20
+ * @property {string} source - What satisfied or blocked this condition
21
+ * @property {"MANDATORY" | "CONDITIONAL"} severity
22
+ */
23
+
24
+ /**
25
+ * @typedef {Object} SufficiencyContract
26
+ * @property {string} taskId
27
+ * @property {SufficiencyCondition[]} conditions
28
+ * @property {boolean} sufficient - True only when all MANDATORY conditions are SATISFIED
29
+ * @property {string[]} missing - List of missing MANDATORY condition descriptions
30
+ */
31
+
32
+ /** Condition types derived from task analysis */
33
+ const CONDITION_TYPES = {
34
+ PROJECT_KNOWLEDGE: "project-knowledge",
35
+ DECISION: "decision",
36
+ CONSTRAINT: "constraint",
37
+ DEPENDENCY: "dependency",
38
+ VERIFICATION: "verification",
39
+ UNKNOWN_RESOLUTION: "unknown-resolution",
40
+ };
41
+
42
+ /**
43
+ * Patterns that indicate required context domains.
44
+ * Each pattern maps to one or more condition types.
45
+ */
46
+ const DOMAIN_PATTERNS = [
47
+ {
48
+ domain: "auth",
49
+ patterns: /\b(auth|oauth|jwt|token|login|credential|password|session)\b/i,
50
+ conditions: [
51
+ { type: CONDITION_TYPES.DECISION, description: "Auth mechanism decision (OAuth, JWT, etc.)" },
52
+ { type: CONDITION_TYPES.PROJECT_KNOWLEDGE, description: "Existing auth implementation" },
53
+ ],
54
+ },
55
+ {
56
+ domain: "migration",
57
+ patterns: /\b(migrat|schema.*change|database.*change|column.*add|table.*rename)\b/i,
58
+ conditions: [
59
+ { type: CONDITION_TYPES.DECISION, description: "Migration strategy (forward, backward-compatible)" },
60
+ { type: CONDITION_TYPES.CONSTRAINT, description: "Data integrity constraints" },
61
+ { type: CONDITION_TYPES.DEPENDENCY, description: "Migration tool version" },
62
+ ],
63
+ },
64
+ {
65
+ domain: "security",
66
+ patterns: /\b(security|vulnerability|cve|encrypt|hash|sanitiz|xss|csrf|injection)\b/i,
67
+ conditions: [
68
+ { type: CONDITION_TYPES.DECISION, description: "Security approach decision" },
69
+ { type: CONDITION_TYPES.CONSTRAINT, description: "Security constraints and compliance requirements" },
70
+ ],
71
+ },
72
+ {
73
+ domain: "testing",
74
+ patterns: /\b(test|spec|coverage|e2e|unit|integration)\b/i,
75
+ conditions: [
76
+ { type: CONDITION_TYPES.PROJECT_KNOWLEDGE, description: "Test framework and patterns" },
77
+ { type: CONDITION_TYPES.VERIFICATION, description: "Verification criteria" },
78
+ ],
79
+ },
80
+ {
81
+ domain: "architecture",
82
+ patterns: /\b(architect|refactor|restructur|monolith|microservice|modul)\b/i,
83
+ conditions: [
84
+ { type: CONDITION_TYPES.DECISION, description: "Architecture decision" },
85
+ { type: CONDITION_TYPES.CONSTRAINT, description: "Architectural constraints" },
86
+ { type: CONDITION_TYPES.PROJECT_KNOWLEDGE, description: "Current architecture state" },
87
+ ],
88
+ },
89
+ {
90
+ domain: "performance",
91
+ patterns: /\b(performance|optim|cache|redis|latency|throughput|bottleneck)\b/i,
92
+ conditions: [
93
+ { type: CONDITION_TYPES.DECISION, description: "Performance optimization strategy" },
94
+ { type: CONDITION_TYPES.PROJECT_KNOWLEDGE, description: "Current performance baseline" },
95
+ ],
96
+ },
97
+ {
98
+ domain: "scraping",
99
+ patterns: /\b(scrap|crawl|puppeteer|playwright|selenium|parser)\b/i,
100
+ conditions: [
101
+ { type: CONDITION_TYPES.PROJECT_KNOWLEDGE, description: "Scraping framework and patterns" },
102
+ { type: CONDITION_TYPES.DEPENDENCY, description: "Browser automation dependency" },
103
+ ],
104
+ },
105
+ ];
106
+
107
+ /**
108
+ * Concrete terms per domain. When a domain's condition is unsatisfied, the
109
+ * matched terms are surfaced verbatim in `missing` so the caller can name the
110
+ * exact missing concept (e.g. "cache") instead of only a prose description.
111
+ */
112
+ const DOMAIN_TERMS = {
113
+ auth: ["auth", "oauth", "jwt", "token", "login", "credential", "password", "session"],
114
+ migration: ["migration", "schema", "column", "table"],
115
+ security: ["security", "vulnerability", "encrypt", "hash", "sanitize", "xss", "csrf", "injection"],
116
+ testing: ["test", "coverage", "e2e", "unit", "integration"],
117
+ architecture: ["architecture", "refactor", "structure", "monolith", "microservice", "module"],
118
+ performance: ["performance", "optimization", "cache", "redis", "latency", "throughput", "bottleneck"],
119
+ scraping: ["scraping", "crawl", "puppeteer", "playwright", "selenium", "parser"],
120
+ };
121
+
122
+ /**
123
+ * Collect the MANDATORY missing descriptions plus the matched domain terms.
124
+ * Descriptions stay first so existing consumers keep working; the terms are
125
+ * appended so a caller can test for a concrete missing concept.
126
+ *
127
+ * @param {SufficiencyCondition[]} conditions
128
+ * @returns {string[]}
129
+ */
130
+ function collectMissing(conditions) {
131
+ const out = [];
132
+ const seen = new Set();
133
+ for (const c of conditions) {
134
+ if (c.status !== "MISSING" && c.status !== "BLOCKED") continue;
135
+ if (c.severity !== "MANDATORY") continue;
136
+ if (!seen.has(c.description)) {
137
+ out.push(c.description);
138
+ seen.add(c.description);
139
+ }
140
+ for (const term of c.terms || []) {
141
+ if (!seen.has(term)) {
142
+ out.push(term);
143
+ seen.add(term);
144
+ }
145
+ }
146
+ }
147
+ return out;
148
+ }
149
+
150
+ /**
151
+ * Generate a sufficiency contract from a task description.
152
+ *
153
+ * @param {string} taskDescription
154
+ * @param {string} taskId
155
+ * @returns {SufficiencyContract}
156
+ */
157
+ export function generateContract(taskDescription, taskId) {
158
+ const conditions = [];
159
+ const seen = new Set();
160
+
161
+ for (const domain of DOMAIN_PATTERNS) {
162
+ if (domain.patterns.test(taskDescription)) {
163
+ const terms = (DOMAIN_TERMS[domain.domain] || []).filter((t) =>
164
+ new RegExp(`\\b${t}`, "i").test(taskDescription)
165
+ );
166
+ for (const cond of domain.conditions) {
167
+ const key = `${cond.type}:${cond.description}`;
168
+ if (!seen.has(key)) {
169
+ seen.add(key);
170
+ conditions.push({
171
+ id: `SC-${conditions.length + 1}`,
172
+ type: cond.type,
173
+ description: cond.description,
174
+ domain: domain.domain,
175
+ terms,
176
+ status: "MISSING",
177
+ source: "",
178
+ severity: "MANDATORY",
179
+ });
180
+ }
181
+ }
182
+ }
183
+ }
184
+
185
+ // Always require project knowledge as a baseline
186
+ const projectKnowledgeKey = `${CONDITION_TYPES.PROJECT_KNOWLEDGE}:Project structure and dependencies`;
187
+ if (!seen.has(projectKnowledgeKey)) {
188
+ seen.add(projectKnowledgeKey);
189
+ conditions.push({
190
+ id: `SC-${conditions.length + 1}`,
191
+ type: CONDITION_TYPES.PROJECT_KNOWLEDGE,
192
+ description: "Project structure and dependencies",
193
+ status: "MISSING",
194
+ source: "",
195
+ severity: "MANDATORY",
196
+ });
197
+ }
198
+
199
+ const missing = collectMissing(conditions);
200
+
201
+ return {
202
+ taskId,
203
+ conditions,
204
+ sufficient: missing.length === 0,
205
+ missing,
206
+ };
207
+ }
208
+
209
+ /**
210
+ * Evaluate a sufficiency contract against available context capsules.
211
+ *
212
+ * @param {SufficiencyContract} contract
213
+ * @param {Array} capsules - Selected context capsules
214
+ * @returns {SufficiencyContract} Updated contract with statuses
215
+ */
216
+ export function evaluateContract(contract, capsules) {
217
+ const capsuleText = capsules
218
+ .map((c) => `${c.purpose || ""} ${c.scope || ""} ${c.content || ""}`)
219
+ .join(" ")
220
+ .toLowerCase();
221
+
222
+ for (const condition of contract.conditions) {
223
+ // Check if any capsule covers this condition
224
+ const covered = capsules.some((c) => {
225
+ const text = `${c.purpose || ""} ${c.scope || ""} ${c.content || ""}`.toLowerCase();
226
+ return conditionMatchesText(condition, text);
227
+ });
228
+
229
+ if (covered) {
230
+ condition.status = "SATISFIED";
231
+ condition.source = "capsule";
232
+ }
233
+ }
234
+
235
+ // Recalculate sufficiency
236
+ contract.missing = collectMissing(contract.conditions);
237
+ contract.sufficient = contract.missing.length === 0;
238
+
239
+ return contract;
240
+ }
241
+
242
+ /**
243
+ * Check if a condition is covered by text content.
244
+ */
245
+ function conditionMatchesText(condition, text) {
246
+ // Type-specific matching
247
+ switch (condition.type) {
248
+ case CONDITION_TYPES.PROJECT_KNOWLEDGE:
249
+ return /\b(project|package\.json|dependenc|structure|architect)\b/i.test(text);
250
+ case CONDITION_TYPES.DECISION:
251
+ return /\b(decision|decid|chose|selected|approach|strategy)\b/i.test(text);
252
+ case CONDITION_TYPES.CONSTRAINT:
253
+ return /\b(constraint|requirement|must|shall|mandatory|compliance)\b/i.test(text);
254
+ case CONDITION_TYPES.DEPENDENCY:
255
+ return /\b(dependency|version|package|library|framework)\b/i.test(text);
256
+ case CONDITION_TYPES.VERIFICATION:
257
+ return /\b(verification|verify|test|pass|evidence|criteria)\b/i.test(text);
258
+ case CONDITION_TYPES.UNKNOWN_RESOLUTION:
259
+ return /\b(answer|resolved|clarified|confirmed)\b/i.test(text);
260
+ default:
261
+ return false;
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Merge a sufficiency contract with assumptions from the analysis.
267
+ * Assumptions with DECISION_CRITICAL classification become MANDATORY conditions.
268
+ *
269
+ * @param {SufficiencyContract} contract
270
+ * @param {Array} assumptions - From analysis.assumptions
271
+ * @returns {SufficiencyContract}
272
+ */
273
+ export function mergeAssumptions(contract, assumptions) {
274
+ for (const assumption of assumptions || []) {
275
+ if (assumption.classification === "DECISION_CRITICAL" && assumption.status === "active") {
276
+ const key = `${CONDITION_TYPES.UNKNOWN_RESOLUTION}:${assumption.statement}`;
277
+ const exists = contract.conditions.some(
278
+ (c) => c.type === CONDITION_TYPES.UNKNOWN_RESOLUTION && c.description === assumption.statement
279
+ );
280
+ if (!exists) {
281
+ contract.conditions.push({
282
+ id: `SC-${contract.conditions.length + 1}`,
283
+ type: CONDITION_TYPES.UNKNOWN_RESOLUTION,
284
+ description: assumption.statement,
285
+ status: "BLOCKED",
286
+ source: `assumption ${assumption.id}`,
287
+ severity: "MANDATORY",
288
+ });
289
+ }
290
+ }
291
+ }
292
+
293
+ // Recalculate
294
+ contract.missing = collectMissing(contract.conditions);
295
+ contract.sufficient = contract.missing.length === 0;
296
+
297
+ return contract;
298
+ }
299
+
300
+ export { CONDITION_TYPES };
@@ -0,0 +1,17 @@
1
+ export function countTokens(text) {
2
+ if (text == null || text === '') return 0;
3
+ const str = String(text);
4
+ // Approximation: GPT-2 BPE rule of thumb.
5
+ // Common regex from OpenAI's gpt-3.5-turbo tokenizer approximations
6
+ // and tiktoken's "cl100k_base" approximated regex pattern.
7
+ const re = /'s|'t|'re|'ve|'m|'ll|'d| ?[A-Za-z]+| ?[0-9]+| ?[^\sA-Za-z0-9]+|\s+(?!\S)/g;
8
+ const matches = str.match(re);
9
+ if (!matches) return 0;
10
+ // Each matched piece is roughly 1 token for short ASCII; multi-byte chars add overhead.
11
+ let tokens = matches.length;
12
+ // Account for multi-byte characters (emojis, accented, CJK) — roughly 2 tokens each.
13
+ const multibyteCount = (str.match(/[^\x00-\x7F]/g) || []).length;
14
+ // Multi-byte chars are already counted once in matches; roughly double-count them.
15
+ tokens += multibyteCount;
16
+ return tokens;
17
+ }