@voybio/ace-swarm 0.2.0 → 0.2.2
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/README.md +15 -15
- package/assets/agent-state/EVIDENCE_LOG.md +1 -1
- package/assets/agent-state/STATUS.md +2 -2
- package/dist/ace-autonomy.js +38 -1
- package/dist/ace-context.js +8 -0
- package/dist/ace-server-instructions.js +55 -19
- package/dist/ace-state-resolver.d.ts +18 -0
- package/dist/ace-state-resolver.js +106 -0
- package/dist/cli.js +67 -0
- package/dist/handoff-registry.js +11 -7
- package/dist/helpers.js +74 -8
- package/dist/job-scheduler.js +94 -44
- package/dist/run-ledger.js +3 -4
- package/dist/server.d.ts +1 -1
- package/dist/server.js +1 -1
- package/dist/shared.d.ts +1 -1
- package/dist/status-events.js +12 -14
- package/dist/store/bootstrap-store.js +20 -9
- package/dist/store/materializers/context-snapshot-materializer.d.ts +10 -0
- package/dist/store/materializers/context-snapshot-materializer.js +51 -0
- package/dist/store/materializers/host-file-materializer.d.ts +6 -0
- package/dist/store/materializers/host-file-materializer.js +13 -0
- package/dist/store/materializers/projection-manager.d.ts +14 -0
- package/dist/store/materializers/projection-manager.js +73 -0
- package/dist/store/materializers/scheduler-projection-materializer.d.ts +16 -0
- package/dist/store/materializers/scheduler-projection-materializer.js +48 -0
- package/dist/store/repositories/context-snapshot-repository.d.ts +46 -0
- package/dist/store/repositories/context-snapshot-repository.js +105 -0
- package/dist/store/repositories/local-model-runtime-repository.d.ts +98 -0
- package/dist/store/repositories/local-model-runtime-repository.js +165 -0
- package/dist/store/repositories/scheduler-repository.d.ts +21 -39
- package/dist/store/repositories/scheduler-repository.js +123 -93
- package/dist/store/repositories/todo-repository.d.ts +4 -0
- package/dist/store/repositories/todo-repository.js +50 -0
- package/dist/store/state-reader.d.ts +8 -1
- package/dist/store/state-reader.js +12 -1
- package/dist/store/store-artifacts.js +31 -5
- package/dist/store/store-authority-audit.d.ts +30 -0
- package/dist/store/store-authority-audit.js +448 -0
- package/dist/store/types.d.ts +2 -0
- package/dist/store/types.js +1 -0
- package/dist/todo-state.js +179 -11
- package/dist/tools-files.js +2 -1
- package/dist/tools-framework.js +60 -0
- package/dist/tools-memory.js +69 -34
- package/dist/tools-todo.js +1 -1
- package/dist/tui/agent-worker.d.ts +1 -1
- package/dist/tui/agent-worker.js +5 -3
- package/dist/tui/chat.d.ts +19 -0
- package/dist/tui/chat.js +275 -9
- package/dist/tui/commands.d.ts +2 -0
- package/dist/tui/commands.js +62 -0
- package/dist/tui/dashboard.d.ts +5 -0
- package/dist/tui/dashboard.js +38 -2
- package/dist/tui/index.d.ts +5 -0
- package/dist/tui/index.js +146 -2
- package/dist/tui/input.js +5 -0
- package/dist/tui/layout.d.ts +24 -0
- package/dist/tui/layout.js +76 -2
- package/dist/tui/local-model-contract.d.ts +50 -0
- package/dist/tui/local-model-contract.js +272 -0
- package/dist/vericify-bridge.js +3 -4
- package/dist/vericify-context.js +18 -6
- package/package.json +1 -1
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
+
import { dirname, relative, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import * as ts from "typescript";
|
|
5
|
+
import { ACE_ROOT_REL, ACE_SCRIPTS_ROOT_REL, ACE_TASKS_ROOT_REL, mapAceWorkspaceRelativePath, safeWrite, } from "../helpers.js";
|
|
6
|
+
import { OPERATIONAL_ARTIFACT_REL_PATHS, operationalArtifactKey } from "./store-artifacts.js";
|
|
7
|
+
export const STORE_AUTHORITY_AUDIT_REPORT_REL_PATH = "agent-state/STORE_AUTHORITY_AUDIT.md";
|
|
8
|
+
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
9
|
+
const SRC_ROOT = resolve(PACKAGE_ROOT, "src");
|
|
10
|
+
const TARGET_CALLS = new Set(["safeWrite", "safeWriteWorkspaceFile", "safeWriteReport"]);
|
|
11
|
+
const SKIPPED_INTERNAL_FUNCTIONS = new Set(["safeWriteWorkspaceFile", "safeWriteReport"]);
|
|
12
|
+
const TASK_KEY_TO_FILE = {
|
|
13
|
+
todo: "todo.md",
|
|
14
|
+
role_tasks: "role_tasks.md",
|
|
15
|
+
cli_work_split: "cli_work_split.md",
|
|
16
|
+
lessons: "lessons.md",
|
|
17
|
+
readme: "README.md",
|
|
18
|
+
handoff_template: "SWARM_HANDOFF.template.json",
|
|
19
|
+
handoff_example: "SWARM_HANDOFF.example.json",
|
|
20
|
+
handoff_example_vos_ui: "SWARM_HANDOFF.example_vos_to_ui.json",
|
|
21
|
+
handoff_example_ui_coders: "SWARM_HANDOFF.example_ui_to_coders.json",
|
|
22
|
+
};
|
|
23
|
+
const STATIC_AGENT_STATE = new Set([
|
|
24
|
+
"ACE_WORKFLOW.md",
|
|
25
|
+
"ARTIFACT_MANIFEST.json",
|
|
26
|
+
"AST_GREP_COMMANDS.md",
|
|
27
|
+
"AST_GREP_INDEX.json",
|
|
28
|
+
"AST_GREP_INDEX.md",
|
|
29
|
+
"DECISIONS.md",
|
|
30
|
+
"EVIDENCE_LOG.md",
|
|
31
|
+
"HANDOFF.json",
|
|
32
|
+
"INTERFACE_REGISTRY.md",
|
|
33
|
+
"PROVENANCE_LOG.md",
|
|
34
|
+
"QUALITY_GATES.md",
|
|
35
|
+
"RISKS.md",
|
|
36
|
+
"SCOPE.md",
|
|
37
|
+
"SKILL_CATALOG.md",
|
|
38
|
+
"STATUS.md",
|
|
39
|
+
"STATUS_EVENTS.ndjson",
|
|
40
|
+
"TASK.md",
|
|
41
|
+
"TEAL_CONFIG.md",
|
|
42
|
+
"MODULES/registry.json",
|
|
43
|
+
"handoff-registry.json",
|
|
44
|
+
"index-fingerprints.json",
|
|
45
|
+
"index.json",
|
|
46
|
+
"run-ledger.json",
|
|
47
|
+
"runtime-executor-sessions.json",
|
|
48
|
+
"runtime-tool-specs.json",
|
|
49
|
+
"runtime-workspaces.json",
|
|
50
|
+
"todo-state.json",
|
|
51
|
+
"tracker-snapshot.json",
|
|
52
|
+
"vericify/ace-bridge.json",
|
|
53
|
+
"vericify/process-posts.json",
|
|
54
|
+
]);
|
|
55
|
+
function isKnowledgeReportArtifact(canonicalPath) {
|
|
56
|
+
const fileName = canonicalPath.split("/").pop() ?? canonicalPath;
|
|
57
|
+
return /(?:REPORT|AUDIT|TRIAGE|PLAN)\.md$/i.test(fileName);
|
|
58
|
+
}
|
|
59
|
+
function normalizeAuditPath(path) {
|
|
60
|
+
return path.replace(/\\/g, "/").replace(/^(?:\.\/)+/, "").replace(/\/+/g, "/");
|
|
61
|
+
}
|
|
62
|
+
function isFunctionLike(node) {
|
|
63
|
+
return (ts.isFunctionDeclaration(node) ||
|
|
64
|
+
ts.isMethodDeclaration(node) ||
|
|
65
|
+
ts.isFunctionExpression(node) ||
|
|
66
|
+
ts.isArrowFunction(node) ||
|
|
67
|
+
ts.isConstructorDeclaration(node));
|
|
68
|
+
}
|
|
69
|
+
function functionName(node) {
|
|
70
|
+
if (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isMethodDeclaration(node)) {
|
|
71
|
+
return node.name?.getText();
|
|
72
|
+
}
|
|
73
|
+
if (ts.isArrowFunction(node) || ts.isConstructorDeclaration(node))
|
|
74
|
+
return undefined;
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
function callName(node) {
|
|
78
|
+
const expr = node.expression;
|
|
79
|
+
if (ts.isIdentifier(expr))
|
|
80
|
+
return expr.text;
|
|
81
|
+
if (ts.isPropertyAccessExpression(expr))
|
|
82
|
+
return expr.name.text;
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
function collectResolvableConstants(root, sourceFile, inherited) {
|
|
86
|
+
const constants = new Map(inherited);
|
|
87
|
+
const pending = [];
|
|
88
|
+
const visit = (node) => {
|
|
89
|
+
if (node !== root && isFunctionLike(node))
|
|
90
|
+
return;
|
|
91
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) {
|
|
92
|
+
pending.push({ name: node.name.text, initializer: node.initializer });
|
|
93
|
+
}
|
|
94
|
+
if (node.kind === ts.SyntaxKind.Parameter) {
|
|
95
|
+
const parameter = node;
|
|
96
|
+
if (ts.isIdentifier(parameter.name) && parameter.initializer) {
|
|
97
|
+
pending.push({ name: parameter.name.text, initializer: parameter.initializer });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
ts.forEachChild(node, visit);
|
|
101
|
+
};
|
|
102
|
+
ts.forEachChild(root, visit);
|
|
103
|
+
let changed = true;
|
|
104
|
+
let safety = 0;
|
|
105
|
+
while (changed && safety < pending.length + 2) {
|
|
106
|
+
changed = false;
|
|
107
|
+
safety += 1;
|
|
108
|
+
for (const entry of pending) {
|
|
109
|
+
if (constants.has(entry.name))
|
|
110
|
+
continue;
|
|
111
|
+
const resolved = resolveExpression(entry.initializer, sourceFile, constants);
|
|
112
|
+
if (resolved) {
|
|
113
|
+
constants.set(entry.name, resolved);
|
|
114
|
+
changed = true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return constants;
|
|
119
|
+
}
|
|
120
|
+
function resolvePathExpression(expr, sourceFile, constants) {
|
|
121
|
+
if (ts.isStringLiteralLike(expr))
|
|
122
|
+
return normalizeAuditPath(expr.text);
|
|
123
|
+
if (ts.isNoSubstitutionTemplateLiteral(expr))
|
|
124
|
+
return normalizeAuditPath(expr.text);
|
|
125
|
+
if (ts.isParenthesizedExpression(expr))
|
|
126
|
+
return resolveExpression(expr.expression, sourceFile, constants);
|
|
127
|
+
if (ts.isAsExpression(expr) || ts.isTypeAssertionExpression(expr)) {
|
|
128
|
+
return resolveExpression(expr.expression, sourceFile, constants);
|
|
129
|
+
}
|
|
130
|
+
if (ts.isIdentifier(expr)) {
|
|
131
|
+
return constants.get(expr.text);
|
|
132
|
+
}
|
|
133
|
+
if (ts.isTemplateExpression(expr)) {
|
|
134
|
+
let value = expr.head.text;
|
|
135
|
+
for (const span of expr.templateSpans) {
|
|
136
|
+
const segment = resolveExpression(span.expression, sourceFile, constants);
|
|
137
|
+
if (typeof segment !== "string")
|
|
138
|
+
return undefined;
|
|
139
|
+
value += `${segment}${span.literal.text}`;
|
|
140
|
+
}
|
|
141
|
+
return normalizeAuditPath(value);
|
|
142
|
+
}
|
|
143
|
+
if (ts.isCallExpression(expr)) {
|
|
144
|
+
const name = callName(expr);
|
|
145
|
+
const args = expr.arguments.map((arg) => resolveExpression(arg, sourceFile, constants));
|
|
146
|
+
if (name === "resolveWritableTaskPath") {
|
|
147
|
+
const key = args[0];
|
|
148
|
+
if (typeof key !== "string")
|
|
149
|
+
return undefined;
|
|
150
|
+
const file = TASK_KEY_TO_FILE[key];
|
|
151
|
+
if (!file)
|
|
152
|
+
return undefined;
|
|
153
|
+
return mapAceWorkspaceRelativePath(`${ACE_TASKS_ROOT_REL}/${file}`);
|
|
154
|
+
}
|
|
155
|
+
if (name === "wsPath" || name === "acePath") {
|
|
156
|
+
const segments = expr.arguments.map((arg) => resolvePathLikeSegment(arg, sourceFile, constants));
|
|
157
|
+
if (segments.length === 0)
|
|
158
|
+
return undefined;
|
|
159
|
+
return mapAceWorkspaceRelativePath(segments.join("/"));
|
|
160
|
+
}
|
|
161
|
+
if (name === "join" || name === "resolve") {
|
|
162
|
+
const segments = expr.arguments.map((arg) => resolvePathLikeSegment(arg, sourceFile, constants));
|
|
163
|
+
if (segments.length === 0)
|
|
164
|
+
return undefined;
|
|
165
|
+
return normalizeAuditPath(segments.join("/"));
|
|
166
|
+
}
|
|
167
|
+
if (args.length === 1 && typeof args[0] === "string")
|
|
168
|
+
return normalizeAuditPath(args[0]);
|
|
169
|
+
}
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
function resolvePathLikeSegment(expr, sourceFile, constants) {
|
|
173
|
+
const resolved = resolveExpression(expr, sourceFile, constants);
|
|
174
|
+
if (typeof resolved === "string" && resolved.length > 0) {
|
|
175
|
+
return resolved;
|
|
176
|
+
}
|
|
177
|
+
return "*";
|
|
178
|
+
}
|
|
179
|
+
function resolveExpression(expr, sourceFile, constants) {
|
|
180
|
+
if (ts.isStringLiteralLike(expr) || ts.isNoSubstitutionTemplateLiteral(expr)) {
|
|
181
|
+
return normalizeAuditPath(expr.text);
|
|
182
|
+
}
|
|
183
|
+
if (ts.isTemplateExpression(expr) || ts.isParenthesizedExpression(expr) || ts.isAsExpression(expr) || ts.isTypeAssertionExpression(expr)) {
|
|
184
|
+
return resolvePathExpression(expr, sourceFile, constants);
|
|
185
|
+
}
|
|
186
|
+
if (ts.isIdentifier(expr)) {
|
|
187
|
+
return constants.get(expr.text);
|
|
188
|
+
}
|
|
189
|
+
if (ts.isCallExpression(expr)) {
|
|
190
|
+
return resolvePathExpression(expr, sourceFile, constants);
|
|
191
|
+
}
|
|
192
|
+
return undefined;
|
|
193
|
+
}
|
|
194
|
+
function collectSourceFiles(root) {
|
|
195
|
+
const files = [];
|
|
196
|
+
const walk = (dir) => {
|
|
197
|
+
if (!existsSync(dir))
|
|
198
|
+
return;
|
|
199
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
200
|
+
if (entry.name === "dist" || entry.name === "node_modules" || entry.name.startsWith(".")) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
const abs = resolve(dir, entry.name);
|
|
204
|
+
if (entry.isDirectory()) {
|
|
205
|
+
walk(abs);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (!entry.isFile() || !entry.name.endsWith(".ts"))
|
|
209
|
+
continue;
|
|
210
|
+
files.push(abs);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
walk(root);
|
|
214
|
+
return files.sort((left, right) => left.localeCompare(right));
|
|
215
|
+
}
|
|
216
|
+
function maybeMapAbsoluteRuntimeFile(path) {
|
|
217
|
+
const normalized = normalizeAuditPath(path);
|
|
218
|
+
if (!normalized)
|
|
219
|
+
return undefined;
|
|
220
|
+
return mapAceWorkspaceRelativePath(normalized);
|
|
221
|
+
}
|
|
222
|
+
function deriveFallbackKeys(canonicalPath) {
|
|
223
|
+
const keys = new Set();
|
|
224
|
+
const canonical = maybeMapAbsoluteRuntimeFile(canonicalPath);
|
|
225
|
+
if (!canonical)
|
|
226
|
+
return [];
|
|
227
|
+
if (canonical.startsWith(`${ACE_ROOT_REL}/agent-state/`)) {
|
|
228
|
+
const rel = canonical.slice(`${ACE_ROOT_REL}/agent-state/`.length);
|
|
229
|
+
if (rel.startsWith("context-snapshots/")) {
|
|
230
|
+
const snapshotRel = rel.slice("context-snapshots/".length);
|
|
231
|
+
if (snapshotRel.length > 0) {
|
|
232
|
+
keys.add(`state/memory/context_snapshots/${snapshotRel}`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const operationalKey = `agent-state/${rel}`;
|
|
236
|
+
if (OPERATIONAL_ARTIFACT_REL_PATHS.has(operationalKey)) {
|
|
237
|
+
keys.add(operationalArtifactKey(operationalKey));
|
|
238
|
+
}
|
|
239
|
+
if (STATIC_AGENT_STATE.has(rel)) {
|
|
240
|
+
keys.add(`knowledge/agent-state/${rel}`);
|
|
241
|
+
}
|
|
242
|
+
if (rel.startsWith("MODULES/gates/")) {
|
|
243
|
+
keys.add(`knowledge/gates/${rel.slice("MODULES/gates/".length)}`);
|
|
244
|
+
}
|
|
245
|
+
if (rel.startsWith("MODULES/roles/")) {
|
|
246
|
+
keys.add(`knowledge/roles/${rel.slice("MODULES/roles/".length)}`);
|
|
247
|
+
}
|
|
248
|
+
if (rel.startsWith("MODULES/schemas/")) {
|
|
249
|
+
keys.add(`knowledge/schemas/${rel.slice("MODULES/schemas/".length)}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
if (canonical.startsWith(`${ACE_TASKS_ROOT_REL}/`)) {
|
|
253
|
+
keys.add(`knowledge/tasks/${canonical.slice(`${ACE_TASKS_ROOT_REL}/`.length)}`);
|
|
254
|
+
}
|
|
255
|
+
if (canonical.startsWith(`${ACE_SCRIPTS_ROOT_REL}/`)) {
|
|
256
|
+
keys.add(`knowledge/scripts/${canonical.slice(`${ACE_SCRIPTS_ROOT_REL}/`.length)}`);
|
|
257
|
+
}
|
|
258
|
+
return [...keys];
|
|
259
|
+
}
|
|
260
|
+
function classifyTarget(targetPath) {
|
|
261
|
+
if (!targetPath) {
|
|
262
|
+
return {
|
|
263
|
+
classification: "canonical knowledge artifact",
|
|
264
|
+
fallbackKeys: [],
|
|
265
|
+
canonicalTarget: undefined,
|
|
266
|
+
note: "dynamic target could not be resolved statically",
|
|
267
|
+
bypassesAcepack: false,
|
|
268
|
+
regenerableFromStore: false,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
const canonicalTarget = maybeMapAbsoluteRuntimeFile(targetPath);
|
|
272
|
+
const fallbackKeys = deriveFallbackKeys(targetPath);
|
|
273
|
+
const targetFile = canonicalTarget?.split("/").pop() ?? "";
|
|
274
|
+
const isKanbanProjection = canonicalTarget?.startsWith(`${ACE_ROOT_REL}/agent-state/kanban.`) === true;
|
|
275
|
+
const runtimeNamespace = canonicalTarget?.startsWith(`${ACE_ROOT_REL}/agent-state/`) ||
|
|
276
|
+
canonicalTarget?.startsWith(`${ACE_TASKS_ROOT_REL}/`);
|
|
277
|
+
if (canonicalTarget && isKnowledgeReportArtifact(canonicalTarget)) {
|
|
278
|
+
return {
|
|
279
|
+
classification: "canonical knowledge artifact",
|
|
280
|
+
fallbackKeys,
|
|
281
|
+
canonicalTarget,
|
|
282
|
+
note: "report artifact is intentionally file-backed",
|
|
283
|
+
bypassesAcepack: false,
|
|
284
|
+
regenerableFromStore: false,
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
if (isKanbanProjection || targetFile === "kanban.html" || targetFile === "kanban.json") {
|
|
288
|
+
return {
|
|
289
|
+
classification: "projection only",
|
|
290
|
+
fallbackKeys,
|
|
291
|
+
canonicalTarget,
|
|
292
|
+
note: "Kanban snapshot is a derived projection and can be regenerated from store state",
|
|
293
|
+
bypassesAcepack: false,
|
|
294
|
+
regenerableFromStore: true,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
if (runtimeNamespace) {
|
|
298
|
+
return {
|
|
299
|
+
classification: fallbackKeys.length > 0 ? "projection only" : "canonical runtime state",
|
|
300
|
+
fallbackKeys,
|
|
301
|
+
canonicalTarget,
|
|
302
|
+
note: fallbackKeys.length > 0
|
|
303
|
+
? "runtime surface is store-backed and projected for compatibility"
|
|
304
|
+
: "runtime surface has no store fallback key",
|
|
305
|
+
bypassesAcepack: fallbackKeys.length === 0,
|
|
306
|
+
regenerableFromStore: fallbackKeys.length > 0,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
classification: "canonical knowledge artifact",
|
|
311
|
+
fallbackKeys,
|
|
312
|
+
canonicalTarget,
|
|
313
|
+
note: fallbackKeys.length > 0
|
|
314
|
+
? "knowledge surface also has a store fallback key"
|
|
315
|
+
: "knowledge artifact is file-backed by design",
|
|
316
|
+
bypassesAcepack: false,
|
|
317
|
+
regenerableFromStore: fallbackKeys.length > 0,
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
function formatLocation(sourceFile, node) {
|
|
321
|
+
const pos = sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile));
|
|
322
|
+
return { line: pos.line + 1, column: pos.character + 1 };
|
|
323
|
+
}
|
|
324
|
+
function scanSourceFile(sourcePath) {
|
|
325
|
+
const raw = readFileSync(sourcePath, "utf-8");
|
|
326
|
+
const sourceFile = ts.createSourceFile(sourcePath, raw, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
327
|
+
const sites = [];
|
|
328
|
+
const scanNode = (node, inheritedConstants, currentFunction) => {
|
|
329
|
+
if (node !== sourceFile && isFunctionLike(node)) {
|
|
330
|
+
const name = functionName(node) ?? currentFunction;
|
|
331
|
+
const constants = collectResolvableConstants(node, sourceFile, inheritedConstants);
|
|
332
|
+
if (node.body) {
|
|
333
|
+
ts.forEachChild(node.body, (child) => scanNode(child, constants, name));
|
|
334
|
+
}
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
if (ts.isCallExpression(node)) {
|
|
338
|
+
const name = callName(node);
|
|
339
|
+
if (name && TARGET_CALLS.has(name)) {
|
|
340
|
+
if (currentFunction && SKIPPED_INTERNAL_FUNCTIONS.has(currentFunction) && name === "safeWrite") {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const firstArg = node.arguments[0];
|
|
344
|
+
const targetPath = firstArg ? resolveExpression(firstArg, sourceFile, inheritedConstants) : undefined;
|
|
345
|
+
const resolved = classifyTarget(targetPath);
|
|
346
|
+
const location = formatLocation(sourceFile, node);
|
|
347
|
+
sites.push({
|
|
348
|
+
call: name,
|
|
349
|
+
classification: resolved.classification,
|
|
350
|
+
file: normalizeAuditPath(relative(PACKAGE_ROOT, sourcePath)),
|
|
351
|
+
line: location.line,
|
|
352
|
+
column: location.column,
|
|
353
|
+
target_expression: firstArg ? firstArg.getText(sourceFile) : "",
|
|
354
|
+
target_path: resolved.canonicalTarget,
|
|
355
|
+
fallback_keys: resolved.fallbackKeys,
|
|
356
|
+
bypasses_acepack: resolved.bypassesAcepack,
|
|
357
|
+
regenerable_from_store: resolved.regenerableFromStore,
|
|
358
|
+
note: resolved.note,
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
ts.forEachChild(node, (child) => scanNode(child, inheritedConstants, currentFunction));
|
|
363
|
+
};
|
|
364
|
+
const fileConstants = collectResolvableConstants(sourceFile, sourceFile, new Map());
|
|
365
|
+
ts.forEachChild(sourceFile, (child) => scanNode(child, fileConstants));
|
|
366
|
+
return sites;
|
|
367
|
+
}
|
|
368
|
+
function groupByClassification(sites) {
|
|
369
|
+
return {
|
|
370
|
+
"canonical knowledge artifact": sites.filter((site) => site.classification === "canonical knowledge artifact"),
|
|
371
|
+
"canonical runtime state": sites.filter((site) => site.classification === "canonical runtime state"),
|
|
372
|
+
"projection only": sites.filter((site) => site.classification === "projection only"),
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
export function auditStoreAuthority() {
|
|
376
|
+
const safeWriteSites = collectSourceFiles(SRC_ROOT).flatMap((sourcePath) => scanSourceFile(sourcePath));
|
|
377
|
+
const classifications = groupByClassification(safeWriteSites);
|
|
378
|
+
const runtimeFilesWithoutStoreFallbackKeys = safeWriteSites.filter((site) => site.bypasses_acepack);
|
|
379
|
+
const nonRegenerableProjections = safeWriteSites.filter((site) => site.classification === "projection only" && !site.regenerable_from_store);
|
|
380
|
+
const report_path = STORE_AUTHORITY_AUDIT_REPORT_REL_PATH;
|
|
381
|
+
return {
|
|
382
|
+
bypassing_sites: runtimeFilesWithoutStoreFallbackKeys,
|
|
383
|
+
classifications,
|
|
384
|
+
generated_at: new Date().toISOString(),
|
|
385
|
+
non_regenerable_projections: nonRegenerableProjections,
|
|
386
|
+
report_path,
|
|
387
|
+
runtime_files_without_store_fallback_keys: runtimeFilesWithoutStoreFallbackKeys,
|
|
388
|
+
safe_write_sites: safeWriteSites.sort((left, right) => {
|
|
389
|
+
const byFile = left.file.localeCompare(right.file);
|
|
390
|
+
if (byFile !== 0)
|
|
391
|
+
return byFile;
|
|
392
|
+
if (left.line !== right.line)
|
|
393
|
+
return left.line - right.line;
|
|
394
|
+
return left.column - right.column;
|
|
395
|
+
}),
|
|
396
|
+
source_root: SRC_ROOT,
|
|
397
|
+
total_safe_write_sites: safeWriteSites.length,
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function renderSites(label, sites) {
|
|
401
|
+
const lines = [`## ${label}`];
|
|
402
|
+
if (sites.length === 0) {
|
|
403
|
+
lines.push("- none");
|
|
404
|
+
return lines;
|
|
405
|
+
}
|
|
406
|
+
for (const site of sites) {
|
|
407
|
+
lines.push(`- \`${site.file}:${site.line}:${site.column}\` \`${site.call}\` -> \`${site.target_expression || "<dynamic>"}\``);
|
|
408
|
+
lines.push(` - target: ${site.target_path ? `\`${site.target_path}\`` : "unresolved"}`);
|
|
409
|
+
lines.push(` - fallback keys: ${site.fallback_keys.length > 0 ? site.fallback_keys.map((key) => `\`${key}\``).join(", ") : "none"}`);
|
|
410
|
+
lines.push(` - classification: \`${site.classification}\``);
|
|
411
|
+
lines.push(` - note: ${site.note}`);
|
|
412
|
+
}
|
|
413
|
+
return lines;
|
|
414
|
+
}
|
|
415
|
+
export function renderStoreAuthorityAuditReport(result) {
|
|
416
|
+
const lines = [
|
|
417
|
+
"# STORE_AUTHORITY_AUDIT",
|
|
418
|
+
"",
|
|
419
|
+
`Generated: ${result.generated_at}`,
|
|
420
|
+
`Source root: ${result.source_root}`,
|
|
421
|
+
`Total safeWrite users: ${result.total_safe_write_sites}`,
|
|
422
|
+
"",
|
|
423
|
+
"## Summary",
|
|
424
|
+
`- bypassing ACEPACK: ${result.bypassing_sites.length}`,
|
|
425
|
+
`- runtime files without store fallback keys: ${result.runtime_files_without_store_fallback_keys.length}`,
|
|
426
|
+
`- non-regenerable projections: ${result.non_regenerable_projections.length}`,
|
|
427
|
+
`- canonical knowledge artifacts: ${result.classifications["canonical knowledge artifact"].length}`,
|
|
428
|
+
`- canonical runtime state writers: ${result.classifications["canonical runtime state"].length}`,
|
|
429
|
+
`- projection-only writers: ${result.classifications["projection only"].length}`,
|
|
430
|
+
"",
|
|
431
|
+
...renderSites("Writers Bypassing ACEPACK", result.bypassing_sites),
|
|
432
|
+
"",
|
|
433
|
+
...renderSites("Runtime Files Without Store Fallback Keys", result.runtime_files_without_store_fallback_keys),
|
|
434
|
+
"",
|
|
435
|
+
...renderSites("Projections That Cannot Be Regenerated From Store State", result.non_regenerable_projections),
|
|
436
|
+
"",
|
|
437
|
+
...renderSites("Canonical Knowledge Artifacts", result.classifications["canonical knowledge artifact"]),
|
|
438
|
+
"",
|
|
439
|
+
...renderSites("Canonical Runtime State Writers", result.classifications["canonical runtime state"]),
|
|
440
|
+
"",
|
|
441
|
+
...renderSites("Projection Only Writers", result.classifications["projection only"]),
|
|
442
|
+
];
|
|
443
|
+
return lines.join("\n");
|
|
444
|
+
}
|
|
445
|
+
export function writeStoreAuthorityAuditReport(result, targetPath = STORE_AUTHORITY_AUDIT_REPORT_REL_PATH) {
|
|
446
|
+
return safeWrite(targetPath, renderStoreAuthorityAuditReport(result));
|
|
447
|
+
}
|
|
448
|
+
//# sourceMappingURL=store-authority-audit.js.map
|
package/dist/store/types.d.ts
CHANGED
|
@@ -25,6 +25,7 @@ export declare const EntityKind: {
|
|
|
25
25
|
readonly DomainDocument: 17;
|
|
26
26
|
readonly HookContext: 18;
|
|
27
27
|
readonly CatalogEntry: 19;
|
|
28
|
+
readonly ContextSnapshot: 20;
|
|
28
29
|
};
|
|
29
30
|
export type EntityKindCode = (typeof EntityKind)[keyof typeof EntityKind];
|
|
30
31
|
export interface UnifiedEntry {
|
|
@@ -99,6 +100,7 @@ export interface StateReader {
|
|
|
99
100
|
sessions(): Promise<unknown[]>;
|
|
100
101
|
statusEvents(): Promise<unknown[]>;
|
|
101
102
|
providerDiscovery(): Promise<unknown[]>;
|
|
103
|
+
runtimeStatuses(): Promise<unknown[]>;
|
|
102
104
|
vericifyPosts(): Promise<unknown[]>;
|
|
103
105
|
domainDocs(domain: string): Promise<unknown[]>;
|
|
104
106
|
}
|
package/dist/store/types.js
CHANGED