blun-king-cli 9.1.486 → 9.1.489
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/CHANGELOG.md +14 -0
- package/LIESMICH.txt +28 -7
- package/README.md +16 -3
- package/agent-spine-plugin/.claude-plugin/marketplace.json +20 -0
- package/agent-spine-plugin/.claude-plugin/plugin.json +14 -0
- package/agent-spine-plugin/.codex-plugin/plugin.json +34 -0
- package/agent-spine-plugin/.mcp.json +8 -0
- package/agent-spine-plugin/CHANGELOG.md +277 -0
- package/agent-spine-plugin/LICENSE +186 -0
- package/agent-spine-plugin/README.md +342 -0
- package/agent-spine-plugin/assets/agentspine-banner.svg +32 -0
- package/agent-spine-plugin/bin/agentspine-mcp.js +4 -0
- package/agent-spine-plugin/bin/agentspine.js +7 -0
- package/agent-spine-plugin/blun.plugin.json +33 -0
- package/agent-spine-plugin/docs/acceptance.md +61 -0
- package/agent-spine-plugin/docs/architecture.md +183 -0
- package/agent-spine-plugin/docs/attention.md +121 -0
- package/agent-spine-plugin/docs/automatic-continuity.md +79 -0
- package/agent-spine-plugin/docs/channel-runtime.md +92 -0
- package/agent-spine-plugin/docs/coordination.md +138 -0
- package/agent-spine-plugin/docs/feed-transport.md +99 -0
- package/agent-spine-plugin/docs/gateway-runtime.md +109 -0
- package/agent-spine-plugin/docs/harness-reference.md +45 -0
- package/agent-spine-plugin/docs/host-integration.md +129 -0
- package/agent-spine-plugin/docs/https-transport.md +116 -0
- package/agent-spine-plugin/docs/learning.md +98 -0
- package/agent-spine-plugin/docs/object-transport.md +93 -0
- package/agent-spine-plugin/docs/peer-transport.md +88 -0
- package/agent-spine-plugin/docs/preservation-contract.md +53 -0
- package/agent-spine-plugin/docs/quality-gates.md +50 -0
- package/agent-spine-plugin/docs/relationships.md +67 -0
- package/agent-spine-plugin/docs/releasing.md +83 -0
- package/agent-spine-plugin/docs/roadmap.md +307 -0
- package/agent-spine-plugin/docs/selfstarter.md +88 -0
- package/agent-spine-plugin/docs/session-briefing.md +74 -0
- package/agent-spine-plugin/docs/shared-memory.md +259 -0
- package/agent-spine-plugin/docs/source-roots.md +86 -0
- package/agent-spine-plugin/docs/sqlite-transport.md +76 -0
- package/agent-spine-plugin/hooks/hooks.json +95 -0
- package/agent-spine-plugin/hooks/version.json +5 -0
- package/agent-spine-plugin/package.json +69 -0
- package/agent-spine-plugin/scripts/check-hosts.js +193 -0
- package/agent-spine-plugin/scripts/check-install.js +551 -0
- package/agent-spine-plugin/scripts/check-syntax.js +29 -0
- package/agent-spine-plugin/scripts/github-actions.js +11 -0
- package/agent-spine-plugin/scripts/release-check.js +127 -0
- package/agent-spine-plugin/scripts/run-acceptance.js +19 -0
- package/agent-spine-plugin/scripts/run-checks.js +46 -0
- package/agent-spine-plugin/scripts/run-tests-hermetic.js +73 -0
- package/agent-spine-plugin/skill/SKILL.md +76 -0
- package/agent-spine-plugin/skills/agent-spine/SKILL.md +84 -0
- package/agent-spine-plugin/spine-example/1-identity.md +12 -0
- package/agent-spine-plugin/spine-example/2-voice.md +6 -0
- package/agent-spine-plugin/spine-example/3-conduct.md +8 -0
- package/agent-spine-plugin/spine-example/4-history.md +4 -0
- package/agent-spine-plugin/src/cli.js +950 -0
- package/agent-spine-plugin/src/hook.js +646 -0
- package/agent-spine-plugin/src/index.js +84 -0
- package/agent-spine-plugin/src/lib/acceptance.js +294 -0
- package/agent-spine-plugin/src/lib/attention.js +755 -0
- package/agent-spine-plugin/src/lib/audit.js +308 -0
- package/agent-spine-plugin/src/lib/authentication.js +513 -0
- package/agent-spine-plugin/src/lib/briefing.js +305 -0
- package/agent-spine-plugin/src/lib/catalog.js +142 -0
- package/agent-spine-plugin/src/lib/channel-runtime.js +665 -0
- package/agent-spine-plugin/src/lib/context.js +154 -0
- package/agent-spine-plugin/src/lib/continuity.js +333 -0
- package/agent-spine-plugin/src/lib/coordination.js +577 -0
- package/agent-spine-plugin/src/lib/documents.js +199 -0
- package/agent-spine-plugin/src/lib/feed-transport.js +497 -0
- package/agent-spine-plugin/src/lib/filesystem-retry.js +27 -0
- package/agent-spine-plugin/src/lib/gateway-runtime.js +760 -0
- package/agent-spine-plugin/src/lib/graph.js +284 -0
- package/agent-spine-plugin/src/lib/https-transport.js +392 -0
- package/agent-spine-plugin/src/lib/indexed-memory-offline.js +40 -0
- package/agent-spine-plugin/src/lib/indexed-memory.js +281 -0
- package/agent-spine-plugin/src/lib/learning.js +645 -0
- package/agent-spine-plugin/src/lib/object-transport.js +206 -0
- package/agent-spine-plugin/src/lib/paths.js +60 -0
- package/agent-spine-plugin/src/lib/peer-transport.js +283 -0
- package/agent-spine-plugin/src/lib/persona-runtime.js +503 -0
- package/agent-spine-plugin/src/lib/runtime.js +13 -0
- package/agent-spine-plugin/src/lib/selfstarter.js +819 -0
- package/agent-spine-plugin/src/lib/sharing.js +969 -0
- package/agent-spine-plugin/src/lib/source-roots.js +451 -0
- package/agent-spine-plugin/src/lib/sqlite-transport.js +501 -0
- package/agent-spine-plugin/src/lib/telegram-adapter.js +119 -0
- package/agent-spine-plugin/src/lib/voice-runtime.js +39 -0
- package/agent-spine-plugin/src/mcp.js +526 -0
- package/agent-spine-plugin/src/version.js +1 -0
- package/agent-spine-plugin/src/worker.js +178 -0
- package/bin/identity-context-policy.cjs +51 -1
- package/bin/launcher-runtime.js +42 -1
- package/bin/plugin-bootstrap.js +68 -27
- package/bin/repeated-user-message-projection.cjs +6 -0
- package/bin/turn-thinking-policy.cjs +5 -4
- package/bin/turn-tool-performance-policy.cjs +16 -2
- package/blun.mjs +187 -35
- package/package.json +3 -1
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { canonicalPath, isInside } from "./paths.js";
|
|
2
|
+
import { buildCatalog, saveCatalog, verifyCatalog } from "./catalog.js";
|
|
3
|
+
import { loadGraph } from "./graph.js";
|
|
4
|
+
import { attentionFindings, inspectAttention } from "./attention.js";
|
|
5
|
+
import { inspectLearning, learningFindings } from "./learning.js";
|
|
6
|
+
import { coordinationFindings, delegationPolicyFindings, inspectCoordination } from "./coordination.js";
|
|
7
|
+
import { inspectSharing, sharingAuthenticationFindings, sharingFindings } from "./sharing.js";
|
|
8
|
+
import { inspectSignerRegistry, inspectTrust, trustFindings } from "./authentication.js";
|
|
9
|
+
import { resolveContext } from "./context.js";
|
|
10
|
+
import { sessionBriefing } from "./briefing.js";
|
|
11
|
+
import { inspectHttpsFeedState } from "./feed-transport.js";
|
|
12
|
+
import { continuityFindings, inspectContinuity } from "./continuity.js";
|
|
13
|
+
import {
|
|
14
|
+
executionPolicyFindings, inspectSelfstarter, selfstarterFindings
|
|
15
|
+
} from "./selfstarter.js";
|
|
16
|
+
import {
|
|
17
|
+
channelPolicyFindings, channelRuntimeFindings, inspectChannelRuntime
|
|
18
|
+
} from "./channel-runtime.js";
|
|
19
|
+
import { inspectPersonaRuntime, personaRuntimeFindings } from "./persona-runtime.js";
|
|
20
|
+
import { gatewayHealthFindings, gatewayRuntimeFindings, inspectGatewayRuntime } from "./gateway-runtime.js";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
import { checkHosts } from "../../scripts/check-hosts.js";
|
|
23
|
+
import { resolveHostSourceCatalog } from "./source-roots.js";
|
|
24
|
+
|
|
25
|
+
function gate(id, name, ok, detail, severity = "error") {
|
|
26
|
+
return { id, name, ok, severity, detail };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function authorityViolations(graph, attention, learning, continuity, coordination, sharing, trust, registry, feedState) {
|
|
30
|
+
const records = [
|
|
31
|
+
...graph.edges,
|
|
32
|
+
...graph.annotations,
|
|
33
|
+
...graph.entities,
|
|
34
|
+
...graph.entityEdges,
|
|
35
|
+
...graph.history,
|
|
36
|
+
...graph.history.map((entry) => entry.value).filter(Boolean),
|
|
37
|
+
...attention.signals,
|
|
38
|
+
...attention.activities,
|
|
39
|
+
...attention.events,
|
|
40
|
+
...attention.receipts,
|
|
41
|
+
...attention.history,
|
|
42
|
+
...attention.history.map((entry) => entry.value).filter(Boolean),
|
|
43
|
+
...learning.candidates,
|
|
44
|
+
...learning.candidates.flatMap((candidate) => [
|
|
45
|
+
...(candidate.evidence || []), candidate.review, candidate.rollback
|
|
46
|
+
]).filter(Boolean),
|
|
47
|
+
...learning.history,
|
|
48
|
+
...learning.history.map((entry) => entry.value).filter(Boolean),
|
|
49
|
+
...continuity.signals,
|
|
50
|
+
...continuity.history,
|
|
51
|
+
...coordination.tasks,
|
|
52
|
+
...coordination.history,
|
|
53
|
+
...coordination.history.map((entry) => entry.value).filter(Boolean),
|
|
54
|
+
...sharing.records.flatMap((record) => [record, record.event, record.review, record.rollback]).filter(Boolean),
|
|
55
|
+
...sharing.history,
|
|
56
|
+
...sharing.history.flatMap((entry) => [entry.value, entry.value?.event, entry.value?.review, entry.value?.rollback]).filter(Boolean),
|
|
57
|
+
...trust.records.flatMap((record) => [record, record.publicIdentity]).filter(Boolean),
|
|
58
|
+
...trust.history.flatMap((entry) => [entry, entry.value, entry.value?.publicIdentity]).filter(Boolean),
|
|
59
|
+
...registry.signers.flatMap((record) => [record, record.publicIdentity]).filter(Boolean),
|
|
60
|
+
...registry.history.flatMap((entry) => [entry, entry.value]).filter(Boolean),
|
|
61
|
+
...feedState.feeds,
|
|
62
|
+
...feedState.history
|
|
63
|
+
];
|
|
64
|
+
return records.filter((record) => record.authority !== "context-only");
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function forbiddenEntityKeys(graph) {
|
|
68
|
+
const forbidden = /"(?:permissions?|rights?|authorization|credentials?|secrets?|tokens?|api[-_]?keys?)"\s*:/i;
|
|
69
|
+
const historicalEntities = graph.history
|
|
70
|
+
.filter((entry) => entry.kind === "entity")
|
|
71
|
+
.map((entry) => entry.value);
|
|
72
|
+
return [...graph.entities, ...historicalEntities].filter((entity) => forbidden.test(JSON.stringify(entity?.attributes || {})));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function runAudit(root = process.cwd(), { host = null } = {}) {
|
|
76
|
+
let sourceResolution = null;
|
|
77
|
+
let sourceResolutionError = null;
|
|
78
|
+
let resolvedHostSources = null;
|
|
79
|
+
if (["claude", "codex"].includes(host)) {
|
|
80
|
+
try {
|
|
81
|
+
resolvedHostSources = await resolveHostSourceCatalog({ host, cwd: root });
|
|
82
|
+
sourceResolution = resolvedHostSources.diagnostics;
|
|
83
|
+
}
|
|
84
|
+
catch (error) { sourceResolutionError = error.message; }
|
|
85
|
+
}
|
|
86
|
+
let hostIntegration = null;
|
|
87
|
+
let hostIntegrationError = null;
|
|
88
|
+
try {
|
|
89
|
+
hostIntegration = await checkHosts(fileURLToPath(new URL("../..", import.meta.url)));
|
|
90
|
+
} catch (error) {
|
|
91
|
+
hostIntegrationError = error.message;
|
|
92
|
+
}
|
|
93
|
+
const before = resolvedHostSources?.catalog || (sourceResolutionError
|
|
94
|
+
? {
|
|
95
|
+
schema: "agentspine.catalog/v1", generatedAt: new Date().toISOString(), root: await canonicalPath(root),
|
|
96
|
+
preservation: "source-files-are-read-only", documents: [], conflicts: [],
|
|
97
|
+
summary: { total: 0, protected: 0, conflicts: 0, byLayer: {} }
|
|
98
|
+
}
|
|
99
|
+
: await buildCatalog(root));
|
|
100
|
+
const catalog = before;
|
|
101
|
+
const catalogPath = await saveCatalog(catalog);
|
|
102
|
+
const { graph, graphPath } = await loadGraph(before.root, catalog);
|
|
103
|
+
const { attention, attentionPath, error: attentionLoadError } = await inspectAttention(before.root, catalog);
|
|
104
|
+
const { learning, learningPath, error: learningLoadError } = await inspectLearning(before.root, catalog);
|
|
105
|
+
const { continuity, continuityPath, error: continuityLoadError } = await inspectContinuity(before.root, catalog);
|
|
106
|
+
const {
|
|
107
|
+
policy, coordination, policyPath, coordinationPath, errors: coordinationLoadErrors
|
|
108
|
+
} = await inspectCoordination(before.root, catalog);
|
|
109
|
+
const {
|
|
110
|
+
policy: executionPolicy, state: selfstarter, executionPolicyPath, selfstarterPath,
|
|
111
|
+
errors: selfstarterLoadErrors
|
|
112
|
+
} = await inspectSelfstarter(before.root, catalog);
|
|
113
|
+
const {
|
|
114
|
+
policy: channelPolicy, runtime: channelRuntime, channelPolicyPath, channelRuntimePath,
|
|
115
|
+
errors: channelLoadErrors
|
|
116
|
+
} = await inspectChannelRuntime(before.root, catalog);
|
|
117
|
+
const {
|
|
118
|
+
policy: personaPolicy, runtime: personaRuntime, personaPolicyPath, personaRuntimePath,
|
|
119
|
+
errors: personaLoadErrors
|
|
120
|
+
} = await inspectPersonaRuntime(before.root, catalog);
|
|
121
|
+
const {
|
|
122
|
+
policy: gatewayPolicy, runtime: gatewayRuntime, gatewayPolicyPath, gatewayRuntimePath,
|
|
123
|
+
errors: gatewayLoadErrors
|
|
124
|
+
} = await inspectGatewayRuntime(before.root, catalog);
|
|
125
|
+
const { sharing, sharingPath, error: sharingLoadError } = await inspectSharing(before.root, catalog);
|
|
126
|
+
const { trust, trustPath, error: trustLoadError } = await inspectTrust(before.root, catalog);
|
|
127
|
+
const { registry, registryPath, signerDirectory, errors: signerErrors } = await inspectSignerRegistry(before.root, catalog);
|
|
128
|
+
const { state: feedState, statePath: feedStatePath, error: feedStateError } = await inspectHttpsFeedState(before.root);
|
|
129
|
+
const context = await resolveContext({ root: before.root, cwd: before.root, host: "generic", maxBytes: 16384, includeContent: true, catalog });
|
|
130
|
+
let briefing = null;
|
|
131
|
+
let briefingError = null;
|
|
132
|
+
try {
|
|
133
|
+
briefing = await sessionBriefing({
|
|
134
|
+
root: before.root, cwd: before.root, host: host || "generic", maxBytes: 16384,
|
|
135
|
+
includePrivate: false, focusActive: true, includeSourceContent: true,
|
|
136
|
+
catalog: resolvedHostSources?.catalog || null, sourceDiagnostics: sourceResolution
|
|
137
|
+
});
|
|
138
|
+
} catch (error) {
|
|
139
|
+
briefingError = error.message;
|
|
140
|
+
}
|
|
141
|
+
const verification = ["claude", "codex"].includes(host)
|
|
142
|
+
? { ok: !sourceResolutionError, reason: sourceResolutionError ? "host-native-resolution-failed" : "host-native-rescan" }
|
|
143
|
+
: await verifyCatalog(before.root);
|
|
144
|
+
const after = resolvedHostSources
|
|
145
|
+
? (await resolveHostSourceCatalog({ host, cwd: root })).catalog
|
|
146
|
+
: sourceResolutionError ? before : await buildCatalog(before.root);
|
|
147
|
+
const beforeHashes = new Map(before.documents.map((document) => [document.relativePath, document.sha256]));
|
|
148
|
+
const byteStable = after.documents.length === before.documents.length && after.documents.every((document) => beforeHashes.get(document.relativePath) === document.sha256);
|
|
149
|
+
const brokenLinks = catalog.conflicts.filter((conflict) => conflict.type === "broken-link");
|
|
150
|
+
const reviewConflicts = catalog.conflicts.filter((conflict) => conflict.type !== "broken-link");
|
|
151
|
+
const authority = authorityViolations(graph, attention, learning, continuity, coordination, sharing, trust, registry, feedState);
|
|
152
|
+
const forbidden = forbiddenEntityKeys(graph);
|
|
153
|
+
const privacyValues = new Set(["private", "shared", "group"]);
|
|
154
|
+
const privateRecords = [
|
|
155
|
+
...graph.entities,
|
|
156
|
+
...graph.entityEdges,
|
|
157
|
+
...graph.history,
|
|
158
|
+
...graph.history.map((entry) => entry.value).filter((value) => value && "privacy" in value),
|
|
159
|
+
...attention.signals,
|
|
160
|
+
...attention.activities,
|
|
161
|
+
...attention.events,
|
|
162
|
+
...attention.history,
|
|
163
|
+
...attention.history.map((entry) => entry.value).filter((value) => value && "privacy" in value),
|
|
164
|
+
...learning.candidates,
|
|
165
|
+
...learning.history,
|
|
166
|
+
...learning.history.map((entry) => entry.value).filter((value) => value && "privacy" in value),
|
|
167
|
+
...coordination.tasks,
|
|
168
|
+
...coordination.history,
|
|
169
|
+
...coordination.history.map((entry) => entry.value).filter((value) => value && "privacy" in value),
|
|
170
|
+
...sharing.records.map((record) => ({ ...record, privacy: record.event?.privacy })),
|
|
171
|
+
...sharing.history,
|
|
172
|
+
...sharing.history.map((entry) => entry.value).filter(Boolean).map((record) => ({ ...record, privacy: record.event?.privacy }))
|
|
173
|
+
];
|
|
174
|
+
const privacyInvalid = privateRecords.filter((record) => !privacyValues.has(record.privacy));
|
|
175
|
+
const knownGroups = new Set(graph.entities.filter((entity) => entity.kind === "group").map((entity) => entity.id));
|
|
176
|
+
const isKnownGroupMember = (record) => !record.entityId || record.entityId === record.groupId || graph.entityEdges.some((edge) => (
|
|
177
|
+
edge.relation === "member-of" && edge.privacy !== "private" && (
|
|
178
|
+
(edge.from === record.entityId && edge.to === record.groupId)
|
|
179
|
+
|| (edge.to === record.entityId && edge.from === record.groupId)
|
|
180
|
+
)
|
|
181
|
+
));
|
|
182
|
+
const attentionGroupInvalid = [
|
|
183
|
+
...attention.signals,
|
|
184
|
+
...attention.activities,
|
|
185
|
+
...attention.events,
|
|
186
|
+
...attention.history.map((entry) => entry.value).filter(Boolean)
|
|
187
|
+
].filter((record) => record.privacy === "group" && (!knownGroups.has(record.groupId) || !isKnownGroupMember(record)));
|
|
188
|
+
const attentionConfigValid = typeof attention.config.enabled === "boolean"
|
|
189
|
+
&& Number.isFinite(attention.config.minIntervalHours) && attention.config.minIntervalHours >= 1 && attention.config.minIntervalHours <= 720
|
|
190
|
+
&& Number.isFinite(attention.config.entitySilenceDays) && attention.config.entitySilenceDays >= 1 && attention.config.entitySilenceDays <= 3650
|
|
191
|
+
&& Number.isInteger(attention.config.heartbeatStaleMinutes) && attention.config.heartbeatStaleMinutes >= 1 && attention.config.heartbeatStaleMinutes <= 10080
|
|
192
|
+
&& Number.isInteger(attention.config.maxItems) && attention.config.maxItems >= 1 && attention.config.maxItems <= 20
|
|
193
|
+
&& (attention.config.quietHours === null || (
|
|
194
|
+
Number.isInteger(attention.config.quietHours?.start) && attention.config.quietHours.start >= 0 && attention.config.quietHours.start <= 23
|
|
195
|
+
&& Number.isInteger(attention.config.quietHours?.end) && attention.config.quietHours.end >= 0 && attention.config.quietHours.end <= 23
|
|
196
|
+
&& Number.isFinite(attention.config.quietHours?.utcOffsetMinutes)
|
|
197
|
+
&& attention.config.quietHours.utcOffsetMinutes >= -720 && attention.config.quietHours.utcOffsetMinutes <= 840
|
|
198
|
+
));
|
|
199
|
+
const learningIssues = learningFindings(learning, graph);
|
|
200
|
+
const attentionIssues = attentionFindings(attention);
|
|
201
|
+
if (attentionLoadError) attentionIssues.push(`unreadable-state:${attentionLoadError}`);
|
|
202
|
+
if (learningLoadError) learningIssues.push(`unreadable-state:${learningLoadError}`);
|
|
203
|
+
const continuityIssues = continuityFindings(continuity);
|
|
204
|
+
if (continuityLoadError) continuityIssues.push(`unreadable-state:${continuityLoadError}`);
|
|
205
|
+
const policyIssues = delegationPolicyFindings(policy, graph);
|
|
206
|
+
const coordinationIssues = coordinationFindings(coordination, policy, graph);
|
|
207
|
+
for (const error of coordinationLoadErrors) {
|
|
208
|
+
if (error.startsWith("policy:")) policyIssues.push(`unreadable-state:${error}`);
|
|
209
|
+
else coordinationIssues.push(`unreadable-state:${error}`);
|
|
210
|
+
}
|
|
211
|
+
const coordinationAuthorityIssues = coordinationIssues.filter((issue) => /assignment|policy-snapshot/.test(issue));
|
|
212
|
+
const coordinationContextIssues = coordinationIssues.filter((issue) => !coordinationAuthorityIssues.includes(issue));
|
|
213
|
+
const executionPolicyIssues = executionPolicyFindings(executionPolicy, graph, coordination);
|
|
214
|
+
const selfstarterIssues = selfstarterFindings(selfstarter, executionPolicy, graph, coordination);
|
|
215
|
+
for (const error of selfstarterLoadErrors) {
|
|
216
|
+
if (error.startsWith("policy:")) executionPolicyIssues.push(`unreadable-state:${error}`);
|
|
217
|
+
else selfstarterIssues.push(`unreadable-state:${error}`);
|
|
218
|
+
}
|
|
219
|
+
const selfstarterAuthorityIssues = selfstarterIssues.filter((issue) => /grant|policy|task-mismatch/.test(issue));
|
|
220
|
+
const selfstarterStateIssues = selfstarterIssues.filter((issue) => !selfstarterAuthorityIssues.includes(issue));
|
|
221
|
+
const channelPolicyIssues = channelPolicyFindings(channelPolicy, graph);
|
|
222
|
+
const channelRuntimeIssues = channelRuntimeFindings(channelRuntime, channelPolicy, graph)
|
|
223
|
+
.filter((issue) => !channelPolicyIssues.includes(issue));
|
|
224
|
+
for (const error of channelLoadErrors) {
|
|
225
|
+
if (error.startsWith("policy:")) channelPolicyIssues.push(`unreadable-state:${error}`);
|
|
226
|
+
else channelRuntimeIssues.push(`unreadable-state:${error}`);
|
|
227
|
+
}
|
|
228
|
+
const personaIssues = personaRuntimeFindings(personaPolicy, personaRuntime, graph);
|
|
229
|
+
const personaPolicyIssues = personaIssues.filter((issue) => /binding/.test(issue));
|
|
230
|
+
const personaStateIssues = personaIssues.filter((issue) => !personaPolicyIssues.includes(issue));
|
|
231
|
+
for (const error of personaLoadErrors) {
|
|
232
|
+
if (error.startsWith("policy:")) personaPolicyIssues.push(`unreadable-state:${error}`);
|
|
233
|
+
else personaStateIssues.push(`unreadable-state:${error}`);
|
|
234
|
+
}
|
|
235
|
+
const gatewayIssues = [...gatewayRuntimeFindings(gatewayPolicy, gatewayRuntime),
|
|
236
|
+
...gatewayHealthFindings(gatewayPolicy, gatewayRuntime)];
|
|
237
|
+
const gatewayPolicyIssues = gatewayIssues.filter((issue) => /goal/.test(issue));
|
|
238
|
+
const gatewayStateIssues = gatewayIssues.filter((issue) => !gatewayPolicyIssues.includes(issue));
|
|
239
|
+
for (const error of gatewayLoadErrors) {
|
|
240
|
+
if (error.startsWith("policy:")) gatewayPolicyIssues.push(`unreadable-state:${error}`);
|
|
241
|
+
else gatewayStateIssues.push(`unreadable-state:${error}`);
|
|
242
|
+
}
|
|
243
|
+
const sharingIssues = sharingFindings(sharing, graph);
|
|
244
|
+
if (sharingLoadError) sharingIssues.push(`unreadable-state:${sharingLoadError}`);
|
|
245
|
+
const authenticationIssues = [
|
|
246
|
+
...trustFindings(trust),
|
|
247
|
+
...sharingAuthenticationFindings(sharing, trust)
|
|
248
|
+
];
|
|
249
|
+
if (trustLoadError) authenticationIssues.push(`unreadable-trust:${trustLoadError}`);
|
|
250
|
+
authenticationIssues.push(...signerErrors);
|
|
251
|
+
if (feedStateError) authenticationIssues.push(`unreadable-feed-state:${feedStateError}`);
|
|
252
|
+
const sharingAuthorityIssues = sharingIssues.filter((issue) => /authority|unsafe/.test(issue));
|
|
253
|
+
const sharingContextIssues = sharingIssues.filter((issue) => !sharingAuthorityIssues.includes(issue));
|
|
254
|
+
const nativeMapped = catalog.documents.filter((document) => document.hosts.some((host) => host !== "generic"));
|
|
255
|
+
const loadedBytes = context.documents.filter((document) => document.loaded).reduce((sum, document) => sum + document.bytes, 0);
|
|
256
|
+
const briefingBytes = briefing ? Buffer.byteLength(JSON.stringify(briefing)) : null;
|
|
257
|
+
const briefingBudgetValid = briefing !== null && briefingBytes === briefing.budget.usedBytes
|
|
258
|
+
&& briefingBytes <= briefing.budget.maxBytes;
|
|
259
|
+
|
|
260
|
+
const gates = [
|
|
261
|
+
gate(1, "Runtime", Number(process.versions.node.split(".")[0]) >= 20 && hostIntegration?.ok === true, hostIntegrationError
|
|
262
|
+
? `Node ${process.versions.node}; host integration failed closed: ${hostIntegrationError}`
|
|
263
|
+
: `Node ${process.versions.node}; one versioned MCP server and lifecycle hook set per host`),
|
|
264
|
+
gate(2, "Discovery", catalog.schema === "agentspine.catalog/v1"
|
|
265
|
+
&& (!host || (sourceResolution?.status === "loaded" && !sourceResolutionError)), sourceResolutionError
|
|
266
|
+
? `${catalog.documents.length} project documents; host-native source resolution failed closed: ${sourceResolutionError}`
|
|
267
|
+
: sourceResolution ? `${sourceResolution.scopes.user} user, ${sourceResolution.scopes.project} project, and ${sourceResolution.scopes["project-memory"]} memory sources; broad home scan disabled`
|
|
268
|
+
: `${catalog.documents.length} Markdown documents indexed`),
|
|
269
|
+
gate(3, "External state", !isInside(catalog.root, catalogPath) && !isInside(catalog.root, graphPath) && !isInside(catalog.root, attentionPath) && !isInside(catalog.root, learningPath) && !isInside(catalog.root, continuityPath) && !isInside(catalog.root, policyPath) && !isInside(catalog.root, coordinationPath) && !isInside(catalog.root, executionPolicyPath) && !isInside(catalog.root, selfstarterPath) && !isInside(catalog.root, channelPolicyPath) && !isInside(catalog.root, channelRuntimePath) && !isInside(catalog.root, personaPolicyPath) && !isInside(catalog.root, personaRuntimePath) && !isInside(catalog.root, gatewayPolicyPath) && !isInside(catalog.root, gatewayRuntimePath) && !isInside(catalog.root, sharingPath) && !isInside(catalog.root, trustPath) && !isInside(catalog.root, registryPath) && !isInside(catalog.root, signerDirectory) && !isInside(catalog.root, feedStatePath), `State remains outside ${catalog.root}`),
|
|
270
|
+
gate(4, "Native hierarchy", nativeMapped.every((document) => document.hosts.length > 0), `${nativeMapped.length} host-native documents mapped`),
|
|
271
|
+
gate(5, "Link integrity", brokenLinks.length === 0, brokenLinks.length ? `${brokenLinks.length} broken Markdown links` : "All indexed Markdown links resolve"),
|
|
272
|
+
gate(6, "Conflict visibility", Array.isArray(catalog.conflicts), `${reviewConflicts.length} precedence or classification findings exposed`, "warning"),
|
|
273
|
+
gate(7, "Authority boundary", authority.length === 0 && forbidden.length === 0 && policyIssues.length === 0 && coordinationAuthorityIssues.length === 0 && executionPolicyIssues.length === 0 && selfstarterAuthorityIssues.length === 0 && channelPolicyIssues.length === 0 && personaPolicyIssues.length === 0 && gatewayPolicyIssues.length === 0 && sharingAuthorityIssues.length === 0, `${authority.length} context authority violations; ${forbidden.length} forbidden entity records; ${policyIssues.length} delegation policy findings; ${coordinationAuthorityIssues.length} assignment findings; ${executionPolicyIssues.length} execution policy findings; ${selfstarterAuthorityIssues.length} self-starter authority findings; ${channelPolicyIssues.length} channel policy findings; ${personaPolicyIssues.length} persona policy findings; ${gatewayPolicyIssues.length} gateway policy findings; ${sharingAuthorityIssues.length} shared authority findings`),
|
|
274
|
+
gate(8, "Context privacy", privacyInvalid.length === 0 && attentionGroupInvalid.length === 0 && attentionConfigValid && attentionIssues.length === 0 && learningIssues.length === 0 && continuityIssues.length === 0 && coordinationContextIssues.length === 0 && selfstarterStateIssues.length === 0 && channelRuntimeIssues.length === 0 && personaStateIssues.length === 0 && gatewayStateIssues.length === 0 && sharingContextIssues.length === 0 && authenticationIssues.length === 0, `${graph.entities.length} entities, ${graph.entityEdges.length} relationships, ${attention.signals.length} attention cues, ${attention.events.length} lifecycle events, ${learning.candidates.length} learning records, ${continuity.signals.length} continuity signals, ${coordination.tasks.length} coordination items, ${selfstarter.jobs.length} self-starter jobs, ${channelRuntime.events.length} channel events, ${personaRuntime.personas.length} authenticated personas, ${gatewayRuntime.queue.length} gateway queue items, ${gatewayRuntime.outbox.length} delivery records, ${sharing.records.length} shared records, ${trust.records.length} trusted keys, ${registry.signers.length} local signers, and ${feedState.feeds.length} feed receipts checked`),
|
|
275
|
+
gate(9, "Context budget", loadedBytes <= context.budget.maxBytes && briefingBudgetValid, briefingError
|
|
276
|
+
? `${loadedBytes}/${context.budget.maxBytes} source bytes; briefing failed closed: ${briefingError}`
|
|
277
|
+
: `${loadedBytes}/${context.budget.maxBytes} source bytes; ${briefingBytes}/${briefing.budget.maxBytes} briefing bytes`),
|
|
278
|
+
gate(10, "Byte preservation", byteStable && verification.ok, verification.ok ? "Sources remained byte-for-byte unchanged" : "Source drift detected")
|
|
279
|
+
];
|
|
280
|
+
return {
|
|
281
|
+
schema: "agentspine.audit/v1",
|
|
282
|
+
root: catalog.root,
|
|
283
|
+
ok: gates.every((item) => item.ok || item.severity === "warning"),
|
|
284
|
+
passed: gates.filter((item) => item.ok).length,
|
|
285
|
+
total: gates.length,
|
|
286
|
+
gates,
|
|
287
|
+
catalogPath,
|
|
288
|
+
graphPath,
|
|
289
|
+
attentionPath,
|
|
290
|
+
learningPath,
|
|
291
|
+
continuityPath,
|
|
292
|
+
policyPath,
|
|
293
|
+
coordinationPath,
|
|
294
|
+
executionPolicyPath,
|
|
295
|
+
selfstarterPath,
|
|
296
|
+
channelPolicyPath,
|
|
297
|
+
channelRuntimePath,
|
|
298
|
+
personaPolicyPath,
|
|
299
|
+
personaRuntimePath,
|
|
300
|
+
gatewayPolicyPath,
|
|
301
|
+
gatewayRuntimePath,
|
|
302
|
+
sharingPath,
|
|
303
|
+
trustPath,
|
|
304
|
+
registryPath,
|
|
305
|
+
feedStatePath,
|
|
306
|
+
sourceResolution
|
|
307
|
+
};
|
|
308
|
+
}
|