opencode-wait-a-minute 0.0.0-stage → 1.1.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Router Adapter — transforms router output to assembly format.
|
|
3
|
+
*
|
|
4
|
+
* Bridges Context Router (graph-based) to Context Assembly (N3 packing).
|
|
5
|
+
* Router decides WHAT; Adapter formats for Assembly; Assembly decides HOW.
|
|
6
|
+
*
|
|
7
|
+
* Flow:
|
|
8
|
+
* Task State → Context Graph → Router → Adapter → Assembly → N3
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { resolveContext, ADMISSION } from "../context/context-router.js";
|
|
12
|
+
import { buildContextGraph } from "../context/context-graph-builder.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {Object} RouterAdapterOptions
|
|
16
|
+
* @property {string} taskId
|
|
17
|
+
* @property {number} budget
|
|
18
|
+
* @property {string} root
|
|
19
|
+
* @property {Object} graph - Context Graph instance
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {Object} AdapterResult
|
|
24
|
+
* @property {Array} capsules - Capsules in assembly format
|
|
25
|
+
* @property {string} sufficiency - "ok" | "insufficient"
|
|
26
|
+
* @property {string[]} missing
|
|
27
|
+
* @property {Object} contract
|
|
28
|
+
* @property {Object} routerResult - Raw router output
|
|
29
|
+
* @property {string} source - "router" | "fallback"
|
|
30
|
+
* @property {string} status - "READY" | "EMPTY" | "INSUFFICIENT" | "CONFLICTED" | "ERROR"
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Transform a graph node to capsule format for assembly.
|
|
35
|
+
*
|
|
36
|
+
* @param {Object} node
|
|
37
|
+
* @returns {Object} Capsule-like object
|
|
38
|
+
*/
|
|
39
|
+
function nodeToCapsule(node) {
|
|
40
|
+
return {
|
|
41
|
+
context_id: node.id,
|
|
42
|
+
level: node.type === "task" ? "N2" : node.type === "output" ? "N3" : "N3",
|
|
43
|
+
provenance: node.metadata?.provenance || "inferred",
|
|
44
|
+
purpose: node.metadata?.purpose || `${node.type}: ${node.id}`,
|
|
45
|
+
scope: node.type || "unknown",
|
|
46
|
+
content: node.content || "",
|
|
47
|
+
tokenEstimate: Math.ceil((node.content || "").length / 4) + 20,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Adapt router result to assembly-compatible format.
|
|
53
|
+
*
|
|
54
|
+
* @param {Object} routerResult - Output from resolveContext()
|
|
55
|
+
* @param {Object} options
|
|
56
|
+
* @returns {AdapterResult}
|
|
57
|
+
*/
|
|
58
|
+
export function adaptRouterResult(routerResult, options = {}) {
|
|
59
|
+
const { budget = 4000 } = options;
|
|
60
|
+
|
|
61
|
+
if (!routerResult) {
|
|
62
|
+
return {
|
|
63
|
+
capsules: [],
|
|
64
|
+
sufficiency: "insufficient",
|
|
65
|
+
missing: ["router returned null"],
|
|
66
|
+
contract: { conditions: [] },
|
|
67
|
+
routerResult: null,
|
|
68
|
+
source: "fallback",
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Transform nodes to capsules
|
|
73
|
+
const capsules = routerResult.nodes.map(nodeToCapsule);
|
|
74
|
+
|
|
75
|
+
// Build contract from missing/omitted
|
|
76
|
+
const conditions = [];
|
|
77
|
+
for (const gap of routerResult.missing || []) {
|
|
78
|
+
conditions.push({
|
|
79
|
+
id: `SC-${conditions.length + 1}`,
|
|
80
|
+
type: "dependency",
|
|
81
|
+
description: gap.description || `Missing: ${gap.requiredBy}`,
|
|
82
|
+
status: "MISSING",
|
|
83
|
+
severity: "MANDATORY",
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
for (const omitted of routerResult.omitted || []) {
|
|
88
|
+
conditions.push({
|
|
89
|
+
id: `SC-${conditions.length + 1}`,
|
|
90
|
+
type: "admission",
|
|
91
|
+
description: `Omitted: ${omitted.id} (${omitted.reason})`,
|
|
92
|
+
status: omitted.admission === ADMISSION.MANDATORY ? "MISSING" : "OPTIONAL",
|
|
93
|
+
severity: omitted.admission,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const missing = conditions
|
|
98
|
+
.filter((c) => c.status === "MISSING" && c.severity === "MANDATORY")
|
|
99
|
+
.map((c) => c.description);
|
|
100
|
+
|
|
101
|
+
const sufficiency = routerResult.sufficient ? "ok" : "insufficient";
|
|
102
|
+
|
|
103
|
+
// Map router results to status
|
|
104
|
+
let status = "READY";
|
|
105
|
+
if (!routerResult) status = "ERROR";
|
|
106
|
+
else if (!routerResult.nodes.length) status = "EMPTY";
|
|
107
|
+
else if (!routerResult.sufficient) status = "INSUFFICIENT";
|
|
108
|
+
else if (routerResult.budgetOverflow) status = "INSUFFICIENT";
|
|
109
|
+
else if ((routerResult.omitted || []).some((o) => o.admission === ADMISSION.MANDATORY)) status = "INSUFFICIENT";
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
capsules,
|
|
113
|
+
sufficiency,
|
|
114
|
+
missing,
|
|
115
|
+
contract: { conditions },
|
|
116
|
+
routerResult,
|
|
117
|
+
source: "router",
|
|
118
|
+
status
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Execute router and adapt result for assembly.
|
|
124
|
+
* This is the main integration point.
|
|
125
|
+
*
|
|
126
|
+
* Canonical path: Context Router is the sole authority for N3 selection.
|
|
127
|
+
* Silent fallbacks are forbidden; the only opt-in legacy selector is
|
|
128
|
+
* gated by env WAM_CONTEXT_SELECTOR=legacy OR options.useLegacySelector=true.
|
|
129
|
+
*
|
|
130
|
+
* @param {Object} graph - Context Graph (canonical ContextGraph instance)
|
|
131
|
+
* @param {RouterAdapterOptions} options
|
|
132
|
+
* @returns {AdapterResult}
|
|
133
|
+
*/
|
|
134
|
+
export function routeAndAdapt(graph, options) {
|
|
135
|
+
const { taskId, budget = 4000, useLegacySelector = false } = options;
|
|
136
|
+
const legacySelectorAllowed =
|
|
137
|
+
process.env.WAM_CONTEXT_SELECTOR === "legacy" || useLegacySelector === true;
|
|
138
|
+
|
|
139
|
+
if (!graph || !taskId) {
|
|
140
|
+
return {
|
|
141
|
+
capsules: [],
|
|
142
|
+
sufficiency: "insufficient",
|
|
143
|
+
missing: ["no graph or taskId"],
|
|
144
|
+
contract: { conditions: [] },
|
|
145
|
+
routerResult: null,
|
|
146
|
+
source: "fallback",
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
const routerResult = resolveContext(graph, { taskId, maxTokens: budget });
|
|
152
|
+
const adapted = adaptRouterResult(routerResult, { budget });
|
|
153
|
+
// C02: mark source as legacy only when caller explicitly opted in
|
|
154
|
+
// AND router returned empty/insufficient — never silent.
|
|
155
|
+
// Equivalent to the previous `adapted.capsules.length === 0` check, but
|
|
156
|
+
// evaluated before N2 injection so the opt-in path is unchanged.
|
|
157
|
+
const routerSelectedNothing = !routerResult.nodes || routerResult.nodes.length === 0;
|
|
158
|
+
if (legacySelectorAllowed && routerSelectedNothing) {
|
|
159
|
+
return { ...adapted, source: "legacy-allowed" };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// N2 obligation: the current task node is always assembled. The router
|
|
163
|
+
// selects supporting context (N3) only and never emits the task node
|
|
164
|
+
// itself, so the adapter injects it here (nodeToCapsule maps task -> N2).
|
|
165
|
+
const taskNode = typeof graph.getNode === "function" ? graph.getNode(taskId) : null;
|
|
166
|
+
if (taskNode && !adapted.capsules.some((c) => c.context_id === taskNode.id)) {
|
|
167
|
+
adapted.capsules = [nodeToCapsule(taskNode), ...adapted.capsules];
|
|
168
|
+
}
|
|
169
|
+
return adapted;
|
|
170
|
+
} catch (error) {
|
|
171
|
+
// Surface error: do NOT swap in legacy selector unless explicitly allowed.
|
|
172
|
+
if (!legacySelectorAllowed) {
|
|
173
|
+
return {
|
|
174
|
+
capsules: [],
|
|
175
|
+
sufficiency: "insufficient",
|
|
176
|
+
missing: [`router error: ${error.message}`],
|
|
177
|
+
contract: { conditions: [] },
|
|
178
|
+
routerResult: null,
|
|
179
|
+
source: "router-error",
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
capsules: [],
|
|
184
|
+
sufficiency: "insufficient",
|
|
185
|
+
missing: [`router error: ${error.message}`],
|
|
186
|
+
contract: { conditions: [] },
|
|
187
|
+
routerResult: null,
|
|
188
|
+
source: "fallback",
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Build a minimal context graph from task state.
|
|
195
|
+
* Used when no pre-existing graph is available.
|
|
196
|
+
*
|
|
197
|
+
* @deprecated Callers should use buildRuntimeContextGraph() instead so all
|
|
198
|
+
* runtime layers (evidence, decisions, constraints, artifacts, observations,
|
|
199
|
+
* cognition, hypotheses, experiments) are represented. This helper is kept
|
|
200
|
+
* only for the legacy selector opt-in path (WAM_CONTEXT_SELECTOR=legacy).
|
|
201
|
+
*
|
|
202
|
+
* @param {Object} taskState
|
|
203
|
+
* @param {string} root
|
|
204
|
+
* @returns {Object} Minimal graph-like structure
|
|
205
|
+
*/
|
|
206
|
+
export function buildGraphFromTaskState(taskState, root) {
|
|
207
|
+
const nodes = [];
|
|
208
|
+
const edges = [];
|
|
209
|
+
|
|
210
|
+
// Add task node
|
|
211
|
+
if (taskState?.taskId) {
|
|
212
|
+
nodes.push({
|
|
213
|
+
id: taskState.taskId,
|
|
214
|
+
type: "task",
|
|
215
|
+
content: taskState.lastAction || taskState.contract?.objective || "",
|
|
216
|
+
metadata: {
|
|
217
|
+
purpose: "Current task",
|
|
218
|
+
provenance: "user_decided",
|
|
219
|
+
},
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Add requirement nodes
|
|
224
|
+
for (const req of taskState?.requirements || []) {
|
|
225
|
+
nodes.push({
|
|
226
|
+
id: req.id,
|
|
227
|
+
type: "output",
|
|
228
|
+
content: req.title || req.description || "",
|
|
229
|
+
metadata: {
|
|
230
|
+
purpose: `Requirement: ${req.title}`,
|
|
231
|
+
provenance: "user_decided",
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
edges.push({
|
|
235
|
+
from: taskState.taskId,
|
|
236
|
+
to: req.id,
|
|
237
|
+
type: "depends_on",
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Build graph interface
|
|
242
|
+
const nodeMap = new Map(nodes.map((n) => [n.id, n]));
|
|
243
|
+
return {
|
|
244
|
+
getNode: (id) => nodeMap.get(id) || null,
|
|
245
|
+
getEdgesFrom: (id) => edges.filter((e) => e.from === id),
|
|
246
|
+
getEdgesTo: (id) => edges.filter((e) => e.to === id),
|
|
247
|
+
getEdgesFromByType: (id, type) => edges.filter((e) => e.from === id && e.type === type),
|
|
248
|
+
getEdgesToByType: (id, type) => edges.filter((e) => e.to === id && e.type === type),
|
|
249
|
+
getUpstream: (id, depth) => {
|
|
250
|
+
const result = [];
|
|
251
|
+
const visited = new Set();
|
|
252
|
+
const queue = [id];
|
|
253
|
+
while (queue.length > 0 && result.length < 100) {
|
|
254
|
+
const nodeId = queue.shift();
|
|
255
|
+
if (visited.has(nodeId)) continue;
|
|
256
|
+
visited.add(nodeId);
|
|
257
|
+
const node = nodeMap.get(nodeId);
|
|
258
|
+
if (node) result.push(node);
|
|
259
|
+
for (const edge of edges.filter((e) => e.to === nodeId)) {
|
|
260
|
+
if (!visited.has(edge.from)) queue.push(edge.from);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return result;
|
|
264
|
+
},
|
|
265
|
+
getContradicting: () => [],
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export { ADMISSION };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export function createTelemetry({ sink, onError, clock = () => Date.now() } = {}) {
|
|
2
|
+
const buffer = [];
|
|
3
|
+
|
|
4
|
+
function emit(event, data) {
|
|
5
|
+
if (typeof event !== 'string' || event.length === 0) {
|
|
6
|
+
if (onError) onError(new Error('Telemetry event name must be a non-empty string'));
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
buffer.push({ event, data, timestamp: clock() });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function flush() {
|
|
13
|
+
if (!sink || buffer.length === 0) {
|
|
14
|
+
const out = buffer.splice(0, buffer.length);
|
|
15
|
+
return { sent: out.length, dropped: 0 };
|
|
16
|
+
}
|
|
17
|
+
const drain = buffer.splice(0, buffer.length);
|
|
18
|
+
let sent = 0;
|
|
19
|
+
let dropped = 0;
|
|
20
|
+
try {
|
|
21
|
+
const result = await sink(drain);
|
|
22
|
+
sent = drain.length;
|
|
23
|
+
if (typeof result === 'number') sent = Math.min(sent, Math.max(0, result));
|
|
24
|
+
dropped = drain.length - sent;
|
|
25
|
+
} catch (err) {
|
|
26
|
+
dropped = drain.length;
|
|
27
|
+
if (onError) onError(err);
|
|
28
|
+
}
|
|
29
|
+
return { sent, dropped };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function size() {
|
|
33
|
+
return buffer.length;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function clear() {
|
|
37
|
+
buffer.length = 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function peek() {
|
|
41
|
+
return [...buffer];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return { emit, flush, size, clear, peek };
|
|
45
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export async function checkUpdates(currentVersion, registryUrl) {
|
|
2
|
+
// Simulate network check
|
|
3
|
+
if (registryUrl === 'https://error.com') throw new Error('Registry unreachable');
|
|
4
|
+
|
|
5
|
+
const latest = '1.1.0';
|
|
6
|
+
return {
|
|
7
|
+
latest,
|
|
8
|
+
needsUpdate: currentVersion !== latest
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Event Sourcing — append-only event store with reduce.
|
|
3
|
+
*
|
|
4
|
+
* Stores immutable events keyed by stream. Reduces them into a derived
|
|
5
|
+
* state via a user-provided reducer. Production hardening (M5-51).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {Object} StoredEvent
|
|
10
|
+
* @property {number} seq
|
|
11
|
+
* @property {string} streamId
|
|
12
|
+
* @property {string} type
|
|
13
|
+
* @property {*} payload
|
|
14
|
+
* @property {number} timestamp
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {Object} EventStore
|
|
19
|
+
* @property {(streamId: string, type: string, payload?: unknown) => StoredEvent} append
|
|
20
|
+
* @property {(streamId: string) => StoredEvent[]} query
|
|
21
|
+
* @property {(streamId: string, reducer: Function, initial: unknown) => unknown} reduce
|
|
22
|
+
* @property {() => number} totalEvents
|
|
23
|
+
* @property {() => string[]} streams
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Create an event store.
|
|
28
|
+
* @returns {EventStore}
|
|
29
|
+
*/
|
|
30
|
+
export function createEventStore() {
|
|
31
|
+
/** @type {Map<string, StoredEvent[]>} */
|
|
32
|
+
const byStream = new Map();
|
|
33
|
+
let seq = 0;
|
|
34
|
+
|
|
35
|
+
function append(streamId, type, payload) {
|
|
36
|
+
if (!streamId || typeof streamId !== "string") throw new TypeError("streamId required");
|
|
37
|
+
if (!type || typeof type !== "string") throw new TypeError("type required");
|
|
38
|
+
const event = {
|
|
39
|
+
seq: ++seq,
|
|
40
|
+
streamId,
|
|
41
|
+
type,
|
|
42
|
+
payload,
|
|
43
|
+
timestamp: Date.now(),
|
|
44
|
+
};
|
|
45
|
+
let list = byStream.get(streamId);
|
|
46
|
+
if (!list) {
|
|
47
|
+
list = [];
|
|
48
|
+
byStream.set(streamId, list);
|
|
49
|
+
}
|
|
50
|
+
list.push(event);
|
|
51
|
+
return event;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function query(streamId) {
|
|
55
|
+
const list = byStream.get(streamId);
|
|
56
|
+
return list ? [...list] : [];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function reduce(streamId, reducer, initial) {
|
|
60
|
+
const list = byStream.get(streamId) ?? [];
|
|
61
|
+
return list.reduce((state, ev) => reducer(state, ev), initial);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function totalEvents() {
|
|
65
|
+
let n = 0;
|
|
66
|
+
for (const list of byStream.values()) n += list.length;
|
|
67
|
+
return n;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function streams() {
|
|
71
|
+
return [...byStream.keys()];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return { append, query, reduce, totalEvents, streams };
|
|
75
|
+
}
|