blun-king-cli 9.1.563 → 9.1.565
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/agent-spine-plugin/.claude-plugin/marketplace.json +20 -20
- package/agent-spine-plugin/.claude-plugin/plugin.json +14 -14
- package/agent-spine-plugin/.codex-plugin/plugin.json +34 -34
- package/agent-spine-plugin/.mcp.json +8 -8
- package/agent-spine-plugin/CONTRIBUTING.md +52 -0
- package/agent-spine-plugin/LICENSE +186 -186
- package/agent-spine-plugin/README.md +394 -0
- package/agent-spine-plugin/SECURITY.md +47 -0
- package/agent-spine-plugin/assets/agentspine-banner.svg +32 -32
- package/agent-spine-plugin/bin/agentspine-mcp.js +4 -4
- package/agent-spine-plugin/bin/agentspine.js +7 -7
- package/agent-spine-plugin/blun.plugin.json +33 -33
- package/agent-spine-plugin/hooks/codex.json +47 -47
- package/agent-spine-plugin/hooks/hooks.json +106 -106
- package/agent-spine-plugin/hooks/version.json +5 -5
- package/agent-spine-plugin/package.json +69 -69
- package/agent-spine-plugin/scripts/check-hosts.js +199 -199
- package/agent-spine-plugin/skill/SKILL.md +76 -76
- package/agent-spine-plugin/skills/agent-spine/SKILL.md +85 -85
- package/agent-spine-plugin/src/cli.js +1488 -1442
- package/agent-spine-plugin/src/hook.js +886 -812
- package/agent-spine-plugin/src/index.js +93 -93
- package/agent-spine-plugin/src/lib/acceptance.js +333 -333
- package/agent-spine-plugin/src/lib/attention.js +755 -755
- package/agent-spine-plugin/src/lib/audit.js +351 -342
- package/agent-spine-plugin/src/lib/authentication.js +515 -515
- package/agent-spine-plugin/src/lib/briefing.js +317 -317
- package/agent-spine-plugin/src/lib/catalog.js +167 -167
- package/agent-spine-plugin/src/lib/channel-runtime.js +665 -665
- package/agent-spine-plugin/src/lib/context.js +154 -154
- package/agent-spine-plugin/src/lib/continuity.js +338 -338
- package/agent-spine-plugin/src/lib/coordination.js +577 -577
- package/agent-spine-plugin/src/lib/documents.js +217 -217
- package/agent-spine-plugin/src/lib/feed-transport.js +499 -499
- package/agent-spine-plugin/src/lib/filesystem-retry.js +32 -32
- package/agent-spine-plugin/src/lib/gateway-runtime.js +1119 -760
- package/agent-spine-plugin/src/lib/graph.js +337 -337
- package/agent-spine-plugin/src/lib/hook-audit.js +29 -0
- package/agent-spine-plugin/src/lib/https-transport.js +392 -392
- package/agent-spine-plugin/src/lib/indexed-memory-offline.js +40 -40
- package/agent-spine-plugin/src/lib/indexed-memory.js +281 -281
- package/agent-spine-plugin/src/lib/learning.js +6923 -6466
- package/agent-spine-plugin/src/lib/object-transport.js +206 -206
- package/agent-spine-plugin/src/lib/owned-file-lock.js +143 -143
- package/agent-spine-plugin/src/lib/paths.js +109 -109
- package/agent-spine-plugin/src/lib/peer-transport.js +283 -283
- package/agent-spine-plugin/src/lib/persona-runtime.js +581 -581
- package/agent-spine-plugin/src/lib/preflight.js +702 -702
- package/agent-spine-plugin/src/lib/runtime.js +13 -13
- package/agent-spine-plugin/src/lib/selfstarter.js +892 -819
- package/agent-spine-plugin/src/lib/sharing.js +969 -969
- package/agent-spine-plugin/src/lib/source-roots.js +529 -482
- package/agent-spine-plugin/src/lib/sqlite-transport.js +501 -501
- package/agent-spine-plugin/src/lib/telegram-adapter.js +119 -119
- package/agent-spine-plugin/src/lib/voice-runtime.js +39 -39
- package/agent-spine-plugin/src/mcp.js +597 -572
- package/agent-spine-plugin/src/version.js +1 -1
- package/agent-spine-plugin/src/worker.js +202 -195
- package/bin/active-steer-priority-policy.cjs +24 -0
- package/bin/launcher-runtime.js +8 -1
- package/bin/mnemo-tool-agent-policy.cjs +22 -0
- package/bin/thinking-activity-status-policy.cjs +132 -0
- package/bin/thinking-only-guard.cjs +75 -0
- package/bin/tool-call-loop-policy.cjs +53 -0
- package/bin/turn-thinking-policy.cjs +25 -1
- package/blun.mjs +554 -64
- package/package.json +4 -1
- package/standard-skills/translate-native/LICENSE +21 -21
- package/standard-skills/translate-native/references/evaluation-protocol.md +95 -95
- package/standard-skills/translate-native/references/native-orthography.md +79 -79
- package/standard-skills/translate-native/references/native-translation-standard.md +94 -94
- package/standard-skills/translate-native/references/structured-content.md +72 -72
- package/standard-skills/translate-native/references/translationese-review.md +77 -77
- package/standard-skills/translate-native/scripts/blun_language_guard.py +697 -697
- package/standard-skills/translate-native/scripts/check_diacritics.py +353 -353
- package/standard-skills/translate-native/scripts/guard_service_client.py +264 -264
- package/standard-skills/translate-native/scripts/language_gateway.py +62 -62
- package/standard-skills/translate-native/scripts/language_quality.py +377 -377
- package/standard-skills/translate-native/scripts/pre_output_guard.py +64 -64
- package/standard-skills/translate-native/scripts/translation_guard.py +916 -916
- package/standard-tools/language-guard/blun_language_guard.py +697 -697
- package/standard-tools/language-guard/check_diacritics.py +353 -353
- package/standard-tools/language-guard/guard_service_client.py +264 -264
- package/standard-tools/language-guard/language_quality.py +377 -377
- package/standard-tools/language-guard/translation_guard.py +916 -916
|
@@ -1,167 +1,167 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { open, readFile, stat, unlink, writeFile } from "node:fs/promises";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { setTimeout as delay } from "node:timers/promises";
|
|
5
|
-
import { canonicalPath, comparablePath, isInside, projectStateDir, stateRoot } from "./paths.js";
|
|
6
|
-
import { discoverDocuments } from "./documents.js";
|
|
7
|
-
import { isFileLockContention, replaceFileWithRetry } from "./filesystem-retry.js";
|
|
8
|
-
|
|
9
|
-
export const CATALOG_SCHEMA = "agentspine.catalog/v1";
|
|
10
|
-
|
|
11
|
-
export function catalogScanPolicy(root, env = process.env) {
|
|
12
|
-
return {
|
|
13
|
-
stateRoot: isInside(comparablePath(root), comparablePath(stateRoot(env))) ? "excluded" : "outside",
|
|
14
|
-
authority: "scanner-boundary-only"
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function catalogForStateRoot(catalog, root) {
|
|
19
|
-
if (!catalog || catalog.schema !== CATALOG_SCHEMA || typeof root !== "string" || !root) {
|
|
20
|
-
throw new Error("a resolved catalog and state root are required");
|
|
21
|
-
}
|
|
22
|
-
if (catalog.root === root) return catalog;
|
|
23
|
-
return {
|
|
24
|
-
schema: CATALOG_SCHEMA,
|
|
25
|
-
generatedAt: catalog.generatedAt,
|
|
26
|
-
root,
|
|
27
|
-
scanPolicy: catalogScanPolicy(root),
|
|
28
|
-
preservation: "source-files-are-read-only",
|
|
29
|
-
documents: [],
|
|
30
|
-
conflicts: [],
|
|
31
|
-
summary: { total: 0, protected: 0, conflicts: 0, byLayer: {} }
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function catalogConflicts(documents) {
|
|
36
|
-
const byPath = new Map(documents.map((document) => [document.relativePath, document]));
|
|
37
|
-
const conflicts = [];
|
|
38
|
-
for (const document of documents) {
|
|
39
|
-
for (const target of document.links) {
|
|
40
|
-
if (!byPath.has(target)) {
|
|
41
|
-
conflicts.push({ type: "broken-link", source: document.relativePath, target });
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
const byDirectory = new Map();
|
|
46
|
-
for (const document of documents) {
|
|
47
|
-
const directory = document.relativePath.includes("/")
|
|
48
|
-
? document.relativePath.slice(0, document.relativePath.lastIndexOf("/"))
|
|
49
|
-
: ".";
|
|
50
|
-
const key = `${directory}\0${document.layer}\0${document.hosts.join(",")}`;
|
|
51
|
-
if (!byDirectory.has(key)) byDirectory.set(key, []);
|
|
52
|
-
byDirectory.get(key).push(document);
|
|
53
|
-
}
|
|
54
|
-
for (const entries of byDirectory.values()) {
|
|
55
|
-
if (entries.length < 2 || !["constitution", "soul", "memory-index"].includes(entries[0].layer)) continue;
|
|
56
|
-
const names = entries.map((entry) => entry.relativePath).sort();
|
|
57
|
-
const knownOverride = names.some((name) => /(?:AGENTS\.override|CLAUDE\.local)\.md$/.test(name));
|
|
58
|
-
conflicts.push({
|
|
59
|
-
type: knownOverride ? "native-precedence" : "multiple-candidates",
|
|
60
|
-
layer: entries[0].layer,
|
|
61
|
-
documents: names,
|
|
62
|
-
resolution: knownOverride ? "host-native-order" : "agent-review-required"
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
return conflicts.sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b)));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function buildCatalog(inputRoot = process.cwd(), { env = process.env } = {}) {
|
|
69
|
-
const root = await canonicalPath(inputRoot);
|
|
70
|
-
const documents = await discoverDocuments(root, { excludeRoots: [stateRoot(env)] });
|
|
71
|
-
const conflicts = catalogConflicts(documents);
|
|
72
|
-
const byLayer = Object.fromEntries(
|
|
73
|
-
[...new Set(documents.map((document) => document.layer))]
|
|
74
|
-
.sort()
|
|
75
|
-
.map((layer) => [layer, documents.filter((document) => document.layer === layer).length])
|
|
76
|
-
);
|
|
77
|
-
return {
|
|
78
|
-
schema: CATALOG_SCHEMA,
|
|
79
|
-
generatedAt: new Date().toISOString(),
|
|
80
|
-
root,
|
|
81
|
-
scanPolicy: catalogScanPolicy(root, env),
|
|
82
|
-
preservation: "source-files-are-read-only",
|
|
83
|
-
documents,
|
|
84
|
-
conflicts,
|
|
85
|
-
summary: {
|
|
86
|
-
total: documents.length,
|
|
87
|
-
protected: documents.filter((document) => document.protected).length,
|
|
88
|
-
conflicts: conflicts.length,
|
|
89
|
-
byLayer
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export async function saveCatalog(catalog) {
|
|
95
|
-
const directory = await projectStateDir(catalog.root);
|
|
96
|
-
const target = join(directory, "catalog.json");
|
|
97
|
-
const lockPath = `${target}.lock`;
|
|
98
|
-
let handle;
|
|
99
|
-
for (let attempt = 0; attempt < 40; attempt += 1) {
|
|
100
|
-
try {
|
|
101
|
-
handle = await open(lockPath, "wx", 0o600);
|
|
102
|
-
break;
|
|
103
|
-
} catch (error) {
|
|
104
|
-
if (!isFileLockContention(error)) throw error;
|
|
105
|
-
try {
|
|
106
|
-
const metadata = await stat(lockPath);
|
|
107
|
-
if (Date.now() - metadata.mtimeMs > 15000) await unlink(lockPath);
|
|
108
|
-
} catch (lockError) {
|
|
109
|
-
if (lockError.code !== "ENOENT") throw lockError;
|
|
110
|
-
}
|
|
111
|
-
await delay(25);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
if (!handle) throw new Error("catalog state is busy; retry later");
|
|
115
|
-
const temporary = `${target}.${process.pid}.${randomUUID()}.tmp`;
|
|
116
|
-
try {
|
|
117
|
-
await writeFile(temporary, `${JSON.stringify(catalog, null, 2)}\n`, { mode: 0o600 });
|
|
118
|
-
await replaceFileWithRetry(temporary, target);
|
|
119
|
-
return target;
|
|
120
|
-
} finally {
|
|
121
|
-
await handle.close();
|
|
122
|
-
await unlink(temporary).catch((error) => { if (error.code !== "ENOENT") throw error; });
|
|
123
|
-
await unlink(lockPath).catch((error) => { if (error.code !== "ENOENT") throw error; });
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export async function scanAndSave(root) {
|
|
128
|
-
const catalog = await buildCatalog(root);
|
|
129
|
-
const catalogPath = await saveCatalog(catalog);
|
|
130
|
-
return { catalog, catalogPath };
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export async function loadCatalog(inputRoot = process.cwd()) {
|
|
134
|
-
const root = await canonicalPath(inputRoot);
|
|
135
|
-
const directory = await projectStateDir(root);
|
|
136
|
-
const path = join(directory, "catalog.json");
|
|
137
|
-
const content = await readFile(path, "utf8");
|
|
138
|
-
return { catalog: JSON.parse(content), catalogPath: path };
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
export async function verifyCatalog(inputRoot = process.cwd()) {
|
|
142
|
-
let previous;
|
|
143
|
-
try {
|
|
144
|
-
previous = await loadCatalog(inputRoot);
|
|
145
|
-
} catch (error) {
|
|
146
|
-
if (error.code === "ENOENT") {
|
|
147
|
-
return { ok: false, reason: "no-catalog", added: [], removed: [], changed: [] };
|
|
148
|
-
}
|
|
149
|
-
throw error;
|
|
150
|
-
}
|
|
151
|
-
const current = await buildCatalog(previous.catalog.root);
|
|
152
|
-
const before = new Map(previous.catalog.documents.map((doc) => [doc.relativePath, doc]));
|
|
153
|
-
const after = new Map(current.documents.map((doc) => [doc.relativePath, doc]));
|
|
154
|
-
const removed = [...before.keys()].filter((path) => !after.has(path)).sort();
|
|
155
|
-
const added = [...after.keys()].filter((path) => !before.has(path)).sort();
|
|
156
|
-
const changed = [...after.keys()]
|
|
157
|
-
.filter((path) => before.has(path) && before.get(path).sha256 !== after.get(path).sha256)
|
|
158
|
-
.sort();
|
|
159
|
-
return {
|
|
160
|
-
ok: removed.length === 0 && added.length === 0 && changed.length === 0,
|
|
161
|
-
reason: "compared",
|
|
162
|
-
added,
|
|
163
|
-
removed,
|
|
164
|
-
changed,
|
|
165
|
-
catalogPath: previous.catalogPath
|
|
166
|
-
};
|
|
167
|
-
}
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { open, readFile, stat, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
5
|
+
import { canonicalPath, comparablePath, isInside, projectStateDir, stateRoot } from "./paths.js";
|
|
6
|
+
import { discoverDocuments } from "./documents.js";
|
|
7
|
+
import { isFileLockContention, replaceFileWithRetry } from "./filesystem-retry.js";
|
|
8
|
+
|
|
9
|
+
export const CATALOG_SCHEMA = "agentspine.catalog/v1";
|
|
10
|
+
|
|
11
|
+
export function catalogScanPolicy(root, env = process.env) {
|
|
12
|
+
return {
|
|
13
|
+
stateRoot: isInside(comparablePath(root), comparablePath(stateRoot(env))) ? "excluded" : "outside",
|
|
14
|
+
authority: "scanner-boundary-only"
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function catalogForStateRoot(catalog, root) {
|
|
19
|
+
if (!catalog || catalog.schema !== CATALOG_SCHEMA || typeof root !== "string" || !root) {
|
|
20
|
+
throw new Error("a resolved catalog and state root are required");
|
|
21
|
+
}
|
|
22
|
+
if (catalog.root === root) return catalog;
|
|
23
|
+
return {
|
|
24
|
+
schema: CATALOG_SCHEMA,
|
|
25
|
+
generatedAt: catalog.generatedAt,
|
|
26
|
+
root,
|
|
27
|
+
scanPolicy: catalogScanPolicy(root),
|
|
28
|
+
preservation: "source-files-are-read-only",
|
|
29
|
+
documents: [],
|
|
30
|
+
conflicts: [],
|
|
31
|
+
summary: { total: 0, protected: 0, conflicts: 0, byLayer: {} }
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function catalogConflicts(documents) {
|
|
36
|
+
const byPath = new Map(documents.map((document) => [document.relativePath, document]));
|
|
37
|
+
const conflicts = [];
|
|
38
|
+
for (const document of documents) {
|
|
39
|
+
for (const target of document.links) {
|
|
40
|
+
if (!byPath.has(target)) {
|
|
41
|
+
conflicts.push({ type: "broken-link", source: document.relativePath, target });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const byDirectory = new Map();
|
|
46
|
+
for (const document of documents) {
|
|
47
|
+
const directory = document.relativePath.includes("/")
|
|
48
|
+
? document.relativePath.slice(0, document.relativePath.lastIndexOf("/"))
|
|
49
|
+
: ".";
|
|
50
|
+
const key = `${directory}\0${document.layer}\0${document.hosts.join(",")}`;
|
|
51
|
+
if (!byDirectory.has(key)) byDirectory.set(key, []);
|
|
52
|
+
byDirectory.get(key).push(document);
|
|
53
|
+
}
|
|
54
|
+
for (const entries of byDirectory.values()) {
|
|
55
|
+
if (entries.length < 2 || !["constitution", "soul", "memory-index"].includes(entries[0].layer)) continue;
|
|
56
|
+
const names = entries.map((entry) => entry.relativePath).sort();
|
|
57
|
+
const knownOverride = names.some((name) => /(?:AGENTS\.override|CLAUDE\.local)\.md$/.test(name));
|
|
58
|
+
conflicts.push({
|
|
59
|
+
type: knownOverride ? "native-precedence" : "multiple-candidates",
|
|
60
|
+
layer: entries[0].layer,
|
|
61
|
+
documents: names,
|
|
62
|
+
resolution: knownOverride ? "host-native-order" : "agent-review-required"
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return conflicts.sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b)));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export async function buildCatalog(inputRoot = process.cwd(), { env = process.env } = {}) {
|
|
69
|
+
const root = await canonicalPath(inputRoot);
|
|
70
|
+
const documents = await discoverDocuments(root, { excludeRoots: [stateRoot(env)] });
|
|
71
|
+
const conflicts = catalogConflicts(documents);
|
|
72
|
+
const byLayer = Object.fromEntries(
|
|
73
|
+
[...new Set(documents.map((document) => document.layer))]
|
|
74
|
+
.sort()
|
|
75
|
+
.map((layer) => [layer, documents.filter((document) => document.layer === layer).length])
|
|
76
|
+
);
|
|
77
|
+
return {
|
|
78
|
+
schema: CATALOG_SCHEMA,
|
|
79
|
+
generatedAt: new Date().toISOString(),
|
|
80
|
+
root,
|
|
81
|
+
scanPolicy: catalogScanPolicy(root, env),
|
|
82
|
+
preservation: "source-files-are-read-only",
|
|
83
|
+
documents,
|
|
84
|
+
conflicts,
|
|
85
|
+
summary: {
|
|
86
|
+
total: documents.length,
|
|
87
|
+
protected: documents.filter((document) => document.protected).length,
|
|
88
|
+
conflicts: conflicts.length,
|
|
89
|
+
byLayer
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function saveCatalog(catalog) {
|
|
95
|
+
const directory = await projectStateDir(catalog.root);
|
|
96
|
+
const target = join(directory, "catalog.json");
|
|
97
|
+
const lockPath = `${target}.lock`;
|
|
98
|
+
let handle;
|
|
99
|
+
for (let attempt = 0; attempt < 40; attempt += 1) {
|
|
100
|
+
try {
|
|
101
|
+
handle = await open(lockPath, "wx", 0o600);
|
|
102
|
+
break;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (!isFileLockContention(error)) throw error;
|
|
105
|
+
try {
|
|
106
|
+
const metadata = await stat(lockPath);
|
|
107
|
+
if (Date.now() - metadata.mtimeMs > 15000) await unlink(lockPath);
|
|
108
|
+
} catch (lockError) {
|
|
109
|
+
if (lockError.code !== "ENOENT") throw lockError;
|
|
110
|
+
}
|
|
111
|
+
await delay(25);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (!handle) throw new Error("catalog state is busy; retry later");
|
|
115
|
+
const temporary = `${target}.${process.pid}.${randomUUID()}.tmp`;
|
|
116
|
+
try {
|
|
117
|
+
await writeFile(temporary, `${JSON.stringify(catalog, null, 2)}\n`, { mode: 0o600 });
|
|
118
|
+
await replaceFileWithRetry(temporary, target);
|
|
119
|
+
return target;
|
|
120
|
+
} finally {
|
|
121
|
+
await handle.close();
|
|
122
|
+
await unlink(temporary).catch((error) => { if (error.code !== "ENOENT") throw error; });
|
|
123
|
+
await unlink(lockPath).catch((error) => { if (error.code !== "ENOENT") throw error; });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export async function scanAndSave(root) {
|
|
128
|
+
const catalog = await buildCatalog(root);
|
|
129
|
+
const catalogPath = await saveCatalog(catalog);
|
|
130
|
+
return { catalog, catalogPath };
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export async function loadCatalog(inputRoot = process.cwd()) {
|
|
134
|
+
const root = await canonicalPath(inputRoot);
|
|
135
|
+
const directory = await projectStateDir(root);
|
|
136
|
+
const path = join(directory, "catalog.json");
|
|
137
|
+
const content = await readFile(path, "utf8");
|
|
138
|
+
return { catalog: JSON.parse(content), catalogPath: path };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export async function verifyCatalog(inputRoot = process.cwd()) {
|
|
142
|
+
let previous;
|
|
143
|
+
try {
|
|
144
|
+
previous = await loadCatalog(inputRoot);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
if (error.code === "ENOENT") {
|
|
147
|
+
return { ok: false, reason: "no-catalog", added: [], removed: [], changed: [] };
|
|
148
|
+
}
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
const current = await buildCatalog(previous.catalog.root);
|
|
152
|
+
const before = new Map(previous.catalog.documents.map((doc) => [doc.relativePath, doc]));
|
|
153
|
+
const after = new Map(current.documents.map((doc) => [doc.relativePath, doc]));
|
|
154
|
+
const removed = [...before.keys()].filter((path) => !after.has(path)).sort();
|
|
155
|
+
const added = [...after.keys()].filter((path) => !before.has(path)).sort();
|
|
156
|
+
const changed = [...after.keys()]
|
|
157
|
+
.filter((path) => before.has(path) && before.get(path).sha256 !== after.get(path).sha256)
|
|
158
|
+
.sort();
|
|
159
|
+
return {
|
|
160
|
+
ok: removed.length === 0 && added.length === 0 && changed.length === 0,
|
|
161
|
+
reason: "compared",
|
|
162
|
+
added,
|
|
163
|
+
removed,
|
|
164
|
+
changed,
|
|
165
|
+
catalogPath: previous.catalogPath
|
|
166
|
+
};
|
|
167
|
+
}
|