blun-king-cli 9.1.510 → 9.1.511
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 +6 -0
- package/LIESMICH.txt +12 -1
- package/README.md +12 -1
- package/agent-spine-plugin/.claude-plugin/marketplace.json +1 -1
- package/agent-spine-plugin/.claude-plugin/plugin.json +1 -1
- package/agent-spine-plugin/.codex-plugin/plugin.json +2 -1
- package/agent-spine-plugin/CHANGELOG.md +70 -8
- package/agent-spine-plugin/README.md +1 -1
- package/agent-spine-plugin/blun.plugin.json +33 -33
- package/agent-spine-plugin/docs/acceptance.md +2 -2
- package/agent-spine-plugin/docs/gateway-runtime.md +8 -1
- package/agent-spine-plugin/docs/host-integration.md +34 -34
- package/agent-spine-plugin/docs/preflight-recall.md +69 -0
- package/agent-spine-plugin/docs/relationships.md +6 -0
- package/agent-spine-plugin/hooks/codex.json +47 -0
- package/agent-spine-plugin/hooks/hooks.json +11 -0
- package/agent-spine-plugin/hooks/version.json +2 -2
- package/agent-spine-plugin/package.json +4 -4
- package/agent-spine-plugin/scripts/check-hosts.js +53 -51
- package/agent-spine-plugin/scripts/check-install.js +53 -35
- package/agent-spine-plugin/scripts/release-check.js +11 -10
- package/agent-spine-plugin/skills/agent-spine/SKILL.md +1 -1
- package/agent-spine-plugin/src/cli.js +46 -1
- package/agent-spine-plugin/src/hook.js +168 -90
- package/agent-spine-plugin/src/index.js +6 -0
- package/agent-spine-plugin/src/lib/acceptance.js +40 -0
- package/agent-spine-plugin/src/lib/audit.js +9 -2
- package/agent-spine-plugin/src/lib/graph.js +22 -4
- package/agent-spine-plugin/src/lib/persona-runtime.js +103 -31
- package/agent-spine-plugin/src/lib/preflight.js +678 -0
- package/agent-spine-plugin/src/lib/source-roots.js +32 -32
- package/agent-spine-plugin/src/version.js +1 -1
- package/agent-spine-plugin/src/worker.js +20 -3
- package/package.json +1 -1
|
@@ -9,12 +9,12 @@ import { purgeIndexedMemoryCache, resolveIndexedMemory } from "./indexed-memory.
|
|
|
9
9
|
|
|
10
10
|
export const SOURCE_REGISTRY_SCHEMA = "agentspine.source-roots/v1";
|
|
11
11
|
const MAX_REGISTRY_BYTES = 1024 * 1024;
|
|
12
|
-
const MAX_SOURCES = 256;
|
|
13
|
-
const MAX_RULE_FILES = 128;
|
|
14
|
-
const MAX_PROJECT_FILES = 240;
|
|
15
|
-
const MAX_TOTAL_SOURCE_BYTES = 8 * 1024 * 1024;
|
|
16
|
-
const MAX_DIRECTORY_ENTRIES = 4096;
|
|
17
|
-
const MAX_PROJECT_DIRECTORY_ENTRIES = 8192;
|
|
12
|
+
const MAX_SOURCES = 256;
|
|
13
|
+
const MAX_RULE_FILES = 128;
|
|
14
|
+
const MAX_PROJECT_FILES = 240;
|
|
15
|
+
const MAX_TOTAL_SOURCE_BYTES = 8 * 1024 * 1024;
|
|
16
|
+
const MAX_DIRECTORY_ENTRIES = 4096;
|
|
17
|
+
const MAX_PROJECT_DIRECTORY_ENTRIES = 8192;
|
|
18
18
|
const SOURCE_RESOLUTION_MS = 2000;
|
|
19
19
|
const SAFE_NAME = /^[A-Za-z0-9._-]{1,128}$/;
|
|
20
20
|
const SKIP_EXTRA_DIRS = new Set([".git", ".hg", ".svn", ".claude", ".codex", "node_modules", "vendor", "dist", "build", "coverage"]);
|
|
@@ -160,7 +160,7 @@ async function findRoot(cwd, markers) {
|
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
async function containsProjectMarker(directory) {
|
|
163
|
+
async function containsProjectMarker(directory) {
|
|
164
164
|
try {
|
|
165
165
|
await lstat(join(directory, ".git"));
|
|
166
166
|
return true;
|
|
@@ -168,37 +168,37 @@ async function containsProjectMarker(directory) {
|
|
|
168
168
|
if (error.code === "ENOENT") return false;
|
|
169
169
|
throw error;
|
|
170
170
|
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
async function containsEmbeddedHostProfile(directory) {
|
|
174
|
-
return Boolean(
|
|
175
|
-
await existingDirectory(join(directory, ".runtime-private"))
|
|
176
|
-
&& await existingRegular(join(directory, "config.toml"))
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
async function boundedMarkdownTree(directory, prefix, host, scope, precedenceStart, deadline, {
|
|
181
|
-
projectBoundary = false,
|
|
182
|
-
maxFiles = MAX_RULE_FILES,
|
|
183
|
-
maxDirectoryEntries = MAX_DIRECTORY_ENTRIES
|
|
184
|
-
} = {}) {
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function containsEmbeddedHostProfile(directory) {
|
|
174
|
+
return Boolean(
|
|
175
|
+
await existingDirectory(join(directory, ".runtime-private"))
|
|
176
|
+
&& await existingRegular(join(directory, "config.toml"))
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function boundedMarkdownTree(directory, prefix, host, scope, precedenceStart, deadline, {
|
|
181
|
+
projectBoundary = false,
|
|
182
|
+
maxFiles = MAX_RULE_FILES,
|
|
183
|
+
maxDirectoryEntries = MAX_DIRECTORY_ENTRIES
|
|
184
|
+
} = {}) {
|
|
185
185
|
const root = await existingDirectory(directory);
|
|
186
186
|
if (!root) return [];
|
|
187
187
|
const output = [];
|
|
188
188
|
let visitedEntries = 0;
|
|
189
189
|
async function walk(current) {
|
|
190
190
|
if (Date.now() > deadline) throw new Error(`host-native source resolution exceeded ${SOURCE_RESOLUTION_MS} ms`);
|
|
191
|
-
if (projectBoundary && current !== root
|
|
192
|
-
&& (await containsProjectMarker(current) || await containsEmbeddedHostProfile(current))) return;
|
|
191
|
+
if (projectBoundary && current !== root
|
|
192
|
+
&& (await containsProjectMarker(current) || await containsEmbeddedHostProfile(current))) return;
|
|
193
193
|
const entries = [];
|
|
194
194
|
for await (const entry of await opendir(current)) {
|
|
195
195
|
visitedEntries += 1;
|
|
196
|
-
if (visitedEntries > maxDirectoryEntries) throw new Error(`host-native source tree exceeds ${maxDirectoryEntries} entries`);
|
|
196
|
+
if (visitedEntries > maxDirectoryEntries) throw new Error(`host-native source tree exceeds ${maxDirectoryEntries} entries`);
|
|
197
197
|
entries.push(entry);
|
|
198
198
|
}
|
|
199
199
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
200
200
|
for (const entry of entries) {
|
|
201
|
-
if (output.length >= maxFiles) throw new Error(`host-native rule tree exceeds ${maxFiles} files`);
|
|
201
|
+
if (output.length >= maxFiles) throw new Error(`host-native rule tree exceeds ${maxFiles} files`);
|
|
202
202
|
if (entry.isSymbolicLink()) continue;
|
|
203
203
|
const path = join(current, entry.name);
|
|
204
204
|
if (entry.isDirectory() && !entry.name.startsWith(".") && !SKIP_EXTRA_DIRS.has(entry.name)) await walk(path);
|
|
@@ -388,11 +388,11 @@ export async function resolveHostSourceCatalog({ host, cwd = process.cwd(), inpu
|
|
|
388
388
|
const { registry } = await readRegistry(env);
|
|
389
389
|
let hostHome;
|
|
390
390
|
let projectRoot;
|
|
391
|
-
let sources;
|
|
392
|
-
let hostDetails = {};
|
|
393
|
-
if (host === "codex") {
|
|
394
|
-
const codexHome = env.CODEX_HOME || env.BLUN_HOME || join(homedir(), ".codex");
|
|
395
|
-
hostHome = await existingDirectory(resolve(codexHome)) || resolve(codexHome);
|
|
391
|
+
let sources;
|
|
392
|
+
let hostDetails = {};
|
|
393
|
+
if (host === "codex") {
|
|
394
|
+
const codexHome = env.CODEX_HOME || env.BLUN_HOME || join(homedir(), ".codex");
|
|
395
|
+
hostHome = await existingDirectory(resolve(codexHome)) || resolve(codexHome);
|
|
396
396
|
const config = await codexConfig(hostHome);
|
|
397
397
|
projectRoot = env.AGENTSPINE_ROOT ? await canonicalPath(env.AGENTSPINE_ROOT) : await findRoot(canonicalCwd, config.rootMarkers);
|
|
398
398
|
sources = await codexSources({ cwd: canonicalCwd, projectRoot, codexHome: hostHome, config });
|
|
@@ -407,8 +407,8 @@ export async function resolveHostSourceCatalog({ host, cwd = process.cwd(), inpu
|
|
|
407
407
|
memoryDiagnostics: result.memoryDiagnostics };
|
|
408
408
|
}
|
|
409
409
|
if (projectRoot !== homedir() && projectRoot !== dirname(hostHome)) {
|
|
410
|
-
sources.push(...await boundedMarkdownTree(projectRoot, "agentspine:project", host, "project", 3000, deadline,
|
|
411
|
-
{ projectBoundary: true, maxFiles: MAX_PROJECT_FILES, maxDirectoryEntries: MAX_PROJECT_DIRECTORY_ENTRIES }));
|
|
410
|
+
sources.push(...await boundedMarkdownTree(projectRoot, "agentspine:project", host, "project", 3000, deadline,
|
|
411
|
+
{ projectBoundary: true, maxFiles: MAX_PROJECT_FILES, maxDirectoryEntries: MAX_PROJECT_DIRECTORY_ENTRIES }));
|
|
412
412
|
}
|
|
413
413
|
const nativeNames = new Set(host === "codex"
|
|
414
414
|
? ["AGENTS.override.md", "AGENTS.md", ...(hostDetails.fallbackNames || [])]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = "0.
|
|
1
|
+
export const VERSION = "0.10.1";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn } from "node:child_process";
|
|
3
3
|
import { watch } from "node:fs";
|
|
4
|
-
import { realpath } from "node:fs/promises";
|
|
5
|
-
import { isAbsolute, resolve } from "node:path";
|
|
4
|
+
import { lstat, realpath } from "node:fs/promises";
|
|
5
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
6
6
|
import { claimGatewayWork, completeGatewayRun, deliverPrepared, failGatewayRun, loadGatewayRuntime, reconcileGateway, updateGatewayHealth } from "./lib/gateway-runtime.js";
|
|
7
7
|
import { createTelegramAdapter } from "./lib/telegram-adapter.js";
|
|
8
8
|
import { acknowledgeChannelDelivery, loadChannelRuntime } from "./lib/channel-runtime.js";
|
|
@@ -12,11 +12,25 @@ import { isMainModule } from "./lib/runtime.js";
|
|
|
12
12
|
const MAX_FRAME = 64 * 1024;
|
|
13
13
|
const WAKE_FILES = new Set(["attention.json", "channel-runtime.json", "gateway-policy.json", "persona-policy.json", "persona-runtime.json"]);
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
async function wakeSnapshot(directory) {
|
|
16
|
+
return Promise.all([...WAKE_FILES].sort().map(async (name) => {
|
|
17
|
+
try {
|
|
18
|
+
const metadata = await lstat(join(directory, name), { bigint: true });
|
|
19
|
+
return `${name}:${metadata.dev}:${metadata.ino}:${metadata.size}:${metadata.mtimeNs}`;
|
|
20
|
+
} catch (error) {
|
|
21
|
+
if (error.code === "ENOENT") return `${name}:missing`;
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
})).then((entries) => entries.join("\n"));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function waitForGatewayWake(root, delayMs, { watchFactory = watch, realpathFactory = realpath, onReady = null } = {}) {
|
|
16
28
|
const delay = Math.max(250, Math.min(60000, Number(delayMs) || 60000));
|
|
17
29
|
const { directory } = await loadGatewayRuntime(root);
|
|
18
30
|
let watchPath;
|
|
19
31
|
try { watchPath = await realpathFactory(directory); } catch { return "watch-unavailable"; }
|
|
32
|
+
let before;
|
|
33
|
+
try { before = await wakeSnapshot(watchPath); } catch { return "watch-unavailable"; }
|
|
20
34
|
return new Promise((resolvePromise) => {
|
|
21
35
|
let settled = false; let watcher;
|
|
22
36
|
const finish = (reason) => {
|
|
@@ -32,6 +46,9 @@ export async function waitForGatewayWake(root, delayMs, { watchFactory = watch,
|
|
|
32
46
|
if (name === null || WAKE_FILES.has(name)) finish("event");
|
|
33
47
|
});
|
|
34
48
|
watcher.on?.("error", () => finish("watch-error"));
|
|
49
|
+
Promise.resolve().then(() => onReady?.(watchPath)).then(() => wakeSnapshot(watchPath)).then((after) => {
|
|
50
|
+
if (after !== before) finish("event");
|
|
51
|
+
}).catch(() => finish("watch-error"));
|
|
35
52
|
} catch { finish("watch-unavailable"); }
|
|
36
53
|
});
|
|
37
54
|
}
|