blun-king-cli 9.1.536 → 9.1.561

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.
Files changed (129) hide show
  1. package/LIESMICH.txt +13 -869
  2. package/README.md +41 -833
  3. package/bin/assistant-message-offload-policy.cjs +3 -1
  4. package/bin/compaction-transaction-policy.cjs +122 -0
  5. package/bin/context-performance-policy.cjs +2 -5
  6. package/bin/context-pressure-policy.cjs +20 -0
  7. package/bin/cron-run-output.cjs +45 -0
  8. package/bin/cron-run-store.cjs +145 -0
  9. package/bin/default-model-output-budget-policy.cjs +28 -0
  10. package/bin/durable-task-resume-policy.cjs +130 -0
  11. package/bin/durable-task-resume-runtime.cjs +117 -0
  12. package/bin/durable-task-resume-store.cjs +88 -0
  13. package/bin/editable-tool-approval-policy.cjs +540 -0
  14. package/bin/editable-tool-approval-runtime.cjs +99 -0
  15. package/bin/file-observation-policy.cjs +133 -0
  16. package/bin/html-to-research-markdown.cjs +146 -0
  17. package/bin/launcher-runtime.js +0 -1
  18. package/bin/micro-compaction-policy.cjs +64 -0
  19. package/bin/mnemo-connect-heartbeat.cjs +1 -3
  20. package/bin/programmatic-tool-runtime.mjs +330 -4
  21. package/bin/read-continuation-policy.cjs +36 -5
  22. package/bin/retry-checkpoint-policy.cjs +13 -0
  23. package/bin/scoped-cron-run-policy.cjs +358 -0
  24. package/bin/session-checkpoint-policy.cjs +25 -0
  25. package/bin/startup-preferences.cjs +4 -3
  26. package/bin/structured-agent-swarm-output.cjs +325 -0
  27. package/bin/subagent-context-fork-policy.cjs +155 -0
  28. package/bin/subagent-skill-policy.cjs +204 -0
  29. package/bin/telegram-approval-relay.cjs +2 -1
  30. package/bin/tool-file-persistence.cjs +141 -0
  31. package/bin/tool-result-offload-policy.cjs +25 -33
  32. package/bin/turn-thinking-policy.cjs +2 -26
  33. package/bin/update-notice.js +30 -18
  34. package/bin/user-message-offload-policy.cjs +3 -1
  35. package/blun.mjs +1564 -640
  36. package/codebase-index/README.md +12 -0
  37. package/codebase-index/codebase_index.py +129 -18
  38. package/package.json +23 -58
  39. package/telegram-plugin/bin/telegram-mnemo-capture.cjs +1 -3
  40. package/telegram-plugin/bin/telegram-typing-keepalive.cjs +89 -0
  41. package/telegram-plugin/dist/bridge.mjs +8 -1
  42. package/CHANGELOG.md +0 -321
  43. package/agent-spine-plugin/CHANGELOG.md +0 -406
  44. package/agent-spine-plugin/CONTRIBUTING.md +0 -52
  45. package/agent-spine-plugin/README.md +0 -344
  46. package/agent-spine-plugin/SECURITY.md +0 -47
  47. package/agent-spine-plugin/docs/acceptance.md +0 -61
  48. package/agent-spine-plugin/docs/architecture.md +0 -183
  49. package/agent-spine-plugin/docs/attention.md +0 -121
  50. package/agent-spine-plugin/docs/automatic-continuity.md +0 -79
  51. package/agent-spine-plugin/docs/channel-runtime.md +0 -92
  52. package/agent-spine-plugin/docs/coordination.md +0 -138
  53. package/agent-spine-plugin/docs/feed-transport.md +0 -99
  54. package/agent-spine-plugin/docs/gateway-runtime.md +0 -116
  55. package/agent-spine-plugin/docs/harness-reference.md +0 -45
  56. package/agent-spine-plugin/docs/host-integration.md +0 -129
  57. package/agent-spine-plugin/docs/https-transport.md +0 -116
  58. package/agent-spine-plugin/docs/learning.md +0 -133
  59. package/agent-spine-plugin/docs/object-transport.md +0 -93
  60. package/agent-spine-plugin/docs/peer-transport.md +0 -88
  61. package/agent-spine-plugin/docs/preflight-recall.md +0 -69
  62. package/agent-spine-plugin/docs/preservation-contract.md +0 -53
  63. package/agent-spine-plugin/docs/quality-gates.md +0 -50
  64. package/agent-spine-plugin/docs/relationships.md +0 -73
  65. package/agent-spine-plugin/docs/releasing.md +0 -83
  66. package/agent-spine-plugin/docs/roadmap.md +0 -307
  67. package/agent-spine-plugin/docs/selfstarter.md +0 -88
  68. package/agent-spine-plugin/docs/session-briefing.md +0 -74
  69. package/agent-spine-plugin/docs/shared-memory.md +0 -259
  70. package/agent-spine-plugin/docs/source-roots.md +0 -86
  71. package/agent-spine-plugin/docs/sqlite-transport.md +0 -76
  72. package/agent-spine-plugin/scripts/check-hosts.js +0 -195
  73. package/agent-spine-plugin/scripts/check-install.js +0 -569
  74. package/agent-spine-plugin/scripts/check-syntax.js +0 -29
  75. package/agent-spine-plugin/scripts/github-actions.js +0 -11
  76. package/agent-spine-plugin/scripts/release-check.js +0 -128
  77. package/agent-spine-plugin/scripts/run-acceptance.js +0 -19
  78. package/agent-spine-plugin/scripts/run-checks.js +0 -46
  79. package/agent-spine-plugin/scripts/run-tests-hermetic.js +0 -73
  80. package/agent-spine-plugin/spine-example/1-identity.md +0 -12
  81. package/agent-spine-plugin/spine-example/2-voice.md +0 -6
  82. package/agent-spine-plugin/spine-example/3-conduct.md +0 -8
  83. package/agent-spine-plugin/spine-example/4-history.md +0 -4
  84. package/bin/empty-response-retry-policy.cjs +0 -29
  85. package/bin/fredrik-glm-provider.cjs +0 -256
  86. package/bin/package-regression-policy.cjs +0 -77
  87. package/fredrik-glm-profile.toml.example +0 -26
  88. package/release-planned-removals.json +0 -15
  89. package/scripts/check-active-profile-plugin-startup.js +0 -36
  90. package/scripts/check-active-work-steer-regression.js +0 -46
  91. package/scripts/check-approval-observability-regression.js +0 -111
  92. package/scripts/check-approval-queue-shortcuts-regression.js +0 -65
  93. package/scripts/check-bundled-agent-spine-regression.js +0 -48
  94. package/scripts/check-codebase-search-packaging-regression.js +0 -92
  95. package/scripts/check-copy-command-regression.js +0 -74
  96. package/scripts/check-current-turn-read-pin-mutation-regression.js +0 -72
  97. package/scripts/check-current-turn-read-pin-regression.js +0 -94
  98. package/scripts/check-deepseek-native-max-regression.js +0 -49
  99. package/scripts/check-empty-response-effort-downgrade-regression.js +0 -48
  100. package/scripts/check-fredrik-glm-mutation-regression.js +0 -18
  101. package/scripts/check-fredrik-glm-regression.js +0 -169
  102. package/scripts/check-historical-tool-result-preview-regression.js +0 -77
  103. package/scripts/check-history-pressure-offload-regression.js +0 -77
  104. package/scripts/check-mcp-startup-wait-budget.js +0 -48
  105. package/scripts/check-package-regression.js +0 -38
  106. package/scripts/check-plugin-startup-regression.js +0 -53
  107. package/scripts/check-programmatic-context-isolation-regression.js +0 -193
  108. package/scripts/check-programmatic-tool-regression.js +0 -294
  109. package/scripts/check-queue-controls-regression.js +0 -189
  110. package/scripts/check-release-metadata.js +0 -103
  111. package/scripts/check-reload-agent-spine-regression.js +0 -76
  112. package/scripts/check-resume-replay-regression.js +0 -102
  113. package/scripts/check-session-cancel-regression.js +0 -43
  114. package/scripts/check-session-picker-resume-metrics-regression.js +0 -97
  115. package/scripts/check-session-start-hook-context-regression.js +0 -228
  116. package/scripts/check-shell-terminal-isolation-regression.js +0 -81
  117. package/scripts/check-slash-escape-regression.js +0 -89
  118. package/scripts/check-startup-swarm-command-regression.js +0 -24
  119. package/scripts/check-structured-subagent-output-regression.js +0 -331
  120. package/scripts/check-telegram-bridge-watchdog.js +0 -60
  121. package/scripts/check-telegram-direct-work-resume-regression.js +0 -53
  122. package/scripts/check-telegram-loop-exactly-once-regression.js +0 -71
  123. package/scripts/check-todo-loop-regression.js +0 -78
  124. package/scripts/check-todo-progress-regression.js +0 -416
  125. package/scripts/check-todo-recovery-catalog-regression.js +0 -50
  126. package/scripts/check-tool-schema-capacity-regression.js +0 -40
  127. package/scripts/programmatic-tool-runtime.test.mjs +0 -365
  128. package/scripts/structured-subagent-output.test.cjs +0 -170
  129. /package/{scripts → bin}/fix-node-pty-perms.js +0 -0
@@ -1,128 +0,0 @@
1
- #!/usr/bin/env node
2
- import { spawnSync } from "node:child_process";
3
- import { readFile } from "node:fs/promises";
4
- import { resolve } from "node:path";
5
- import { fileURLToPath } from "node:url";
6
-
7
- const SEMVER_RE = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
8
- const REQUIRED_PACKAGE_FILES = [
9
- "blun.plugin.json", ".claude-plugin/plugin.json", ".codex-plugin/plugin.json", ".mcp.json",
10
- "CHANGELOG.md", "LICENSE", "README.md", "bin/agentspine.js", "bin/agentspine-mcp.js",
11
- "docs/acceptance.md", "docs/source-roots.md", "docs/preflight-recall.md", "docs/preservation-contract.md", "scripts/run-acceptance.js",
12
- "skills/agent-spine/SKILL.md", "src/index.js", "src/mcp.js", "src/worker.js",
13
- "hooks/hooks.json", "hooks/codex.json", "hooks/version.json"
14
- ];
15
- const FORBIDDEN_PACKAGE_PATHS = [
16
- /(?:^|\/)\.env(?:\.|$)/i,
17
- /(?:^|\/)\.git(?:$|\/)/i,
18
- /(?:^|\/)\.agentspine(?:$|\/)/i,
19
- /(?:^|\/)(?:AGENTS|CLAUDE|SOUL|MEMORY)\.md$/i,
20
- /(?:^|\/)(?:test|\.github)(?:$|\/)/,
21
- /\.(?:key|pem|p12|pfx)$/i,
22
- /(?:^|\/)state\.json$/i,
23
- /(?:^|\/)(?:catalog|graph|attention|learning|coordination|sharing|sharing-trust|delegation-policy)\.json$/
24
- ];
25
-
26
- function parse(argv) {
27
- const options = { root: process.cwd(), tag: null, allowDirty: false, skipPack: false, json: false };
28
- for (let index = 0; index < argv.length; index += 1) {
29
- const token = argv[index];
30
- if (token === "--root") options.root = argv[++index];
31
- else if (token === "--tag") options.tag = argv[++index];
32
- else if (token === "--allow-dirty") options.allowDirty = true;
33
- else if (token === "--skip-pack") options.skipPack = true;
34
- else if (token === "--json") options.json = true;
35
- else throw new Error(`unknown release-check argument: ${token}`);
36
- }
37
- options.root = resolve(options.root);
38
- return options;
39
- }
40
-
41
- async function json(root, path) {
42
- return JSON.parse(await readFile(resolve(root, path), "utf8"));
43
- }
44
-
45
- function command(root, args) {
46
- const npmCli = process.env.npm_execpath;
47
- const executable = npmCli ? process.execPath : (process.platform === "win32" ? "npm.cmd" : "npm");
48
- const commandArgs = npmCli ? [npmCli, ...args] : args;
49
- return spawnSync(executable, commandArgs, { cwd: root, encoding: "utf8" });
50
- }
51
-
52
- function git(root, args) {
53
- return spawnSync("git", args, { cwd: root, encoding: "utf8" });
54
- }
55
-
56
- function assert(condition, message) {
57
- if (!condition) throw new Error(message);
58
- }
59
-
60
- function validatePackageReport(report, version) {
61
- assert(Array.isArray(report) && report.length === 1, "npm pack report must describe exactly one package");
62
- const item = report[0];
63
- assert(item.version === version, "npm pack version does not match package.json");
64
- assert(typeof item.filename === "string" && item.filename.endsWith(`-${version}.tgz`), "npm pack filename is not versioned correctly");
65
- assert(typeof item.integrity === "string" && item.integrity.startsWith("sha512-"), "npm pack did not report SHA-512 integrity");
66
- assert(Number.isInteger(item.entryCount) && item.entryCount > 0 && item.entryCount <= 500, "npm package file count is outside the release limit");
67
- assert(Number.isInteger(item.unpackedSize) && item.unpackedSize > 0 && item.unpackedSize <= 2 * 1024 * 1024, "npm package exceeds the 2 MiB unpacked release limit");
68
- const paths = (item.files || []).map((file) => file.path);
69
- assert(paths.length === new Set(paths).size, "npm package contains duplicate paths");
70
- for (const path of REQUIRED_PACKAGE_FILES) assert(paths.includes(path), `npm package is missing required file: ${path}`);
71
- for (const path of paths) {
72
- assert(path && !path.startsWith("/") && !path.split("/").includes(".."), `npm package contains an unsafe path: ${path}`);
73
- assert(!FORBIDDEN_PACKAGE_PATHS.some((pattern) => pattern.test(path)), `npm package contains forbidden state or source material: ${path}`);
74
- }
75
- return { filename: item.filename, integrity: item.integrity, files: paths.length, unpackedSize: item.unpackedSize };
76
- }
77
-
78
- export async function releaseCheck(options) {
79
- const [pkg, lock, blun, claude, codex, marketplace, hookVersion, changelog] = await Promise.all([
80
- json(options.root, "package.json"), json(options.root, "package-lock.json"),
81
- json(options.root, "blun.plugin.json"),
82
- json(options.root, ".claude-plugin/plugin.json"), json(options.root, ".codex-plugin/plugin.json"),
83
- json(options.root, ".claude-plugin/marketplace.json"), json(options.root, "hooks/version.json"),
84
- readFile(resolve(options.root, "CHANGELOG.md"), "utf8")
85
- ]);
86
- assert(SEMVER_RE.test(pkg.version || ""), "package version is not valid SemVer");
87
- const versions = [lock.version, lock.packages?.[""]?.version, blun.version, claude.version, codex.version, marketplace.plugins?.[0]?.version, hookVersion.version];
88
- assert(versions.every((version) => version === pkg.version), "release version differs across package and host manifests");
89
- assert(pkg.name === lock.name && pkg.name === lock.packages?.[""]?.name, "package name differs from package-lock.json");
90
- assert(pkg.repository?.url === "git+https://github.com/Maykbiletti/AgentSpine.git", "package repository must identify the public source repository exactly");
91
- if (options.tag) {
92
- assert(options.tag === `v${pkg.version}`, `release tag must be v${pkg.version}`);
93
- const escaped = pkg.version.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
94
- assert(new RegExp(`^## \\[${escaped}\\] - \\d{4}-\\d{2}-\\d{2}$`, "m").test(changelog), `CHANGELOG.md needs a dated ${pkg.version} section`);
95
- }
96
- if (!options.allowDirty) {
97
- const status = git(options.root, ["status", "--porcelain"]);
98
- assert(status.status === 0, status.stderr || "git status failed");
99
- assert(status.stdout.trim() === "", "release worktree must be clean");
100
- }
101
- let packageReport = null;
102
- if (!options.skipPack) {
103
- const packed = command(options.root, ["pack", "--dry-run", "--ignore-scripts", "--json"]);
104
- assert(packed.status === 0, packed.stderr || "npm pack --dry-run failed");
105
- packageReport = validatePackageReport(JSON.parse(packed.stdout), pkg.version);
106
- }
107
- return {
108
- ok: true,
109
- version: pkg.version,
110
- tag: options.tag,
111
- cleanRequired: !options.allowDirty,
112
- package: packageReport,
113
- authority: "release-metadata-only"
114
- };
115
- }
116
-
117
- async function main() {
118
- const options = parse(process.argv.slice(2));
119
- const result = await releaseCheck(options);
120
- process.stdout.write(`${JSON.stringify(result, null, options.json ? 2 : 0)}\n`);
121
- }
122
-
123
- if (process.argv[1] && resolve(process.argv[1]) === resolve(fileURLToPath(import.meta.url))) {
124
- main().catch((error) => {
125
- process.stderr.write(`AgentSpine release check failed: ${error.message}\n`);
126
- process.exitCode = 1;
127
- });
128
- }
@@ -1,19 +0,0 @@
1
- #!/usr/bin/env node
2
- import { resolve } from "node:path";
3
- import { fileURLToPath } from "node:url";
4
- import { renderAcceptanceReport, runVisibleAcceptance } from "../src/lib/acceptance.js";
5
-
6
- export async function main(argv = process.argv.slice(2)) {
7
- const unknown = argv.filter((item) => item !== "--json");
8
- if (unknown.length) throw new Error(`unknown acceptance argument: ${unknown[0]}`);
9
- const report = await runVisibleAcceptance();
10
- process.stdout.write(argv.includes("--json") ? `${JSON.stringify(report, null, 2)}\n` : renderAcceptanceReport(report));
11
- return report;
12
- }
13
-
14
- if (process.argv[1] && resolve(process.argv[1]) === resolve(fileURLToPath(import.meta.url))) {
15
- main().catch((error) => {
16
- process.stderr.write(`AgentSpine acceptance failed: ${error.message}\n`);
17
- process.exitCode = 1;
18
- });
19
- }
@@ -1,46 +0,0 @@
1
- #!/usr/bin/env node
2
- import { spawn } from "node:child_process";
3
- import { resolve } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { githubErrorCommand } from "./github-actions.js";
6
-
7
- const CHECKS = [
8
- { title: "Syntax check", script: "lint" },
9
- { title: "Hermetic test suite", script: "test" },
10
- { title: "Host manifest check", script: "host:check" },
11
- { title: "Installed bundle check", script: "host:install-check" },
12
- { title: "Runtime smoke test", script: "smoke" },
13
- { title: "Self audit", script: "audit:self" }
14
- ];
15
-
16
- function runNpmScript(script) {
17
- const npmExecPath = process.env.npm_execpath;
18
- const executable = npmExecPath ? process.execPath : (process.platform === "win32" ? "npm.cmd" : "npm");
19
- const args = npmExecPath ? [npmExecPath, "run", script] : ["run", script];
20
- return new Promise((resolve, reject) => {
21
- const child = spawn(executable, args, { stdio: "inherit", shell: false, windowsHide: true });
22
- child.once("error", reject);
23
- child.once("close", (code) => resolve(code ?? 1));
24
- });
25
- }
26
-
27
- export async function runChecks({
28
- checks = CHECKS, runCommand = runNpmScript, githubActions = process.env.GITHUB_ACTIONS === "true", output = process.stderr
29
- } = {}) {
30
- for (const check of checks) {
31
- let code;
32
- try { code = await runCommand(check.script); }
33
- catch (error) {
34
- if (githubActions) output.write(githubErrorCommand(check.title, error.message) + "\n");
35
- else output.write(`${check.title} failed: ${error.message}\n`);
36
- return 1;
37
- }
38
- if (code !== 0) {
39
- if (githubActions) output.write(githubErrorCommand(check.title, `npm run ${check.script} exited with code ${code}`) + "\n");
40
- return code;
41
- }
42
- }
43
- return 0;
44
- }
45
-
46
- if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) process.exitCode = await runChecks();
@@ -1,73 +0,0 @@
1
- #!/usr/bin/env node
2
- import { spawn } from "node:child_process";
3
- import { cpus, tmpdir } from "node:os";
4
- import { mkdir, mkdtemp, readdir, rm, writeFile } from "node:fs/promises";
5
- import { join, resolve } from "node:path";
6
- import { fileURLToPath } from "node:url";
7
- import { githubErrorCommand } from "./github-actions.js";
8
-
9
- const root = resolve(fileURLToPath(new URL("..", import.meta.url)));
10
- const base = await mkdtemp(join(tmpdir(), "agentspine-hermetic-tests-"));
11
- const testFiles = (await readdir(join(root, "test"))).filter((name) => name.endsWith(".test.js")).sort();
12
- const concurrency = Math.max(1, Math.min(4, cpus().length));
13
-
14
- async function profileEnvironment(mode, index) {
15
- const profile = join(base, mode, String(index));
16
- const home = join(profile, "home"); const claude = join(profile, "claude"); const codex = join(profile, "codex");
17
- const state = join(profile, "state"); const xdgState = join(profile, "xdg-state"); const temporary = join(profile, "tmp");
18
- for (const directory of [home, claude, codex, state, xdgState, temporary]) await mkdir(directory, { recursive: true });
19
- if (mode === "populated") {
20
- await writeFile(join(claude, "CLAUDE.md"), "# Hermetic populated Claude profile\n\nSynthetic global source.\n");
21
- await writeFile(join(codex, "AGENTS.md"), "# Hermetic populated Codex profile\n\nSynthetic global source.\n");
22
- }
23
- const inherited = Object.fromEntries(Object.entries(process.env).filter(([key]) =>
24
- !/^(?:AGENTSPINE_|CLAUDE_|CODEX_|HOME$|USERPROFILE$|XDG_STATE_HOME$|TMPDIR$|TMP$|TEMP$|NODE_OPTIONS$|NODE_PATH$)/.test(key)));
25
- return { ...inherited, HOME: home, USERPROFILE: home, CLAUDE_CONFIG_DIR: claude, CODEX_HOME: codex,
26
- AGENTSPINE_STATE_DIR: state, XDG_STATE_HOME: xdgState, TMPDIR: temporary, TMP: temporary, TEMP: temporary,
27
- AGENTSPINE_HERMETIC_ROOT: profile, AGENTSPINE_TEST_PROFILE: mode };
28
- }
29
-
30
- async function runOne(file, mode, index) {
31
- const env = await profileEnvironment(mode, index);
32
- return new Promise((resolvePromise) => {
33
- const child = spawn(process.execPath, ["--test", join(root, "test", file)], { cwd: root, env, shell: false,
34
- stdio: ["ignore", "pipe", "pipe"], windowsHide: true });
35
- let stdout = ""; let stderr = "";
36
- child.stdout.on("data", (chunk) => { stdout += chunk; }); child.stderr.on("data", (chunk) => { stderr += chunk; });
37
- child.on("close", (code) => resolvePromise({ file, mode, code, stdout, stderr }));
38
- child.on("error", (error) => resolvePromise({ file, mode, code: 1, stdout, stderr: error.message }));
39
- });
40
- }
41
-
42
- async function runMode(mode) {
43
- const queue = testFiles.map((file, index) => ({ file, index })); const results = [];
44
- async function worker() { while (queue.length) { const item = queue.shift(); results.push(await runOne(item.file, mode, item.index)); } }
45
- await Promise.all(Array.from({ length: concurrency }, () => worker()));
46
- for (const result of results.sort((a, b) => a.file.localeCompare(b.file))) {
47
- if (result.code !== 0) {
48
- if (process.env.GITHUB_ACTIONS === "true") {
49
- process.stderr.write(githubErrorCommand(`${mode}: ${result.file}`, result.stdout + result.stderr) + "\n");
50
- }
51
- process.stderr.write("\n[" + mode + "] " + result.file + " failed\n" + result.stdout + result.stderr);
52
- }
53
- }
54
- return results;
55
- }
56
-
57
- let failed = false; let runnerError = null;
58
- try {
59
- for (const mode of ["empty", "populated"]) {
60
- const results = await runMode(mode); const failures = results.filter((item) => item.code !== 0);
61
- process.stdout.write("Hermetic " + mode + " profile: " + (results.length - failures.length) + "/" + results.length + " test files passed\n");
62
- if (failures.length) failed = true;
63
- }
64
- } catch (error) { runnerError = error; }
65
- try { await rm(base, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }); }
66
- catch (error) { runnerError = runnerError ? new AggregateError([runnerError, error], "Hermetic test run and cleanup failed") : error; }
67
- if (runnerError) {
68
- if (process.env.GITHUB_ACTIONS === "true") {
69
- process.stderr.write(githubErrorCommand("Hermetic test runner", runnerError.stack || runnerError.message) + "\n");
70
- }
71
- throw runnerError;
72
- }
73
- if (failed) process.exitCode = 1;
@@ -1,12 +0,0 @@
1
- # Layer 1 — Identity
2
-
3
- I am <AgentName>, the <role> of <Owner>. <Owner> is my owner; their word is
4
- final.
5
-
6
- My purpose: <one sentence — what this agent exists to do>.
7
-
8
- Principles that no later layer may override:
9
-
10
- - I am honest before I am impressive. "Not verified yet" beats a wrong "done".
11
- - I claim only what a real result has shown me.
12
- - What my owner teaches me about myself becomes part of me (layer 4).
@@ -1,6 +0,0 @@
1
- # Layer 2 — Voice
2
-
3
- - Language: <language the owner prefers>.
4
- - Tone: warm, direct, like a colleague — not a manual, not a servant.
5
- - Length: short by default; detail only on request.
6
- - Never: invented certainty, filler praise, jargon the owner did not use.
@@ -1,8 +0,0 @@
1
- # Layer 3 — Conduct
2
-
3
- - Measure before acting; re-measure before reporting.
4
- - A claim carries its evidence: the command, the number, the file.
5
- - Errors are reported at once, with what I did and what I will do.
6
- - Escalate to the owner only for decisions that are truly theirs;
7
- everything reversible I do myself.
8
- - Tasks, credentials and permissions do not live in this spine.
@@ -1,4 +0,0 @@
1
- # Layer 4 — Grown history (append-only)
2
-
3
- ## 2026-08-27
4
- Spine created.
@@ -1,29 +0,0 @@
1
- 'use strict';
2
-
3
- const EMPTY_LENGTH_EFFORT_DOWNGRADE = Object.freeze({
4
- max: 'high',
5
- xhigh: 'high',
6
- high: 'low',
7
- medium: 'low',
8
- low: 'off',
9
- minimal: 'off',
10
- });
11
-
12
- function nextThinkingEffortForExhaustedEmpty(input = {}) {
13
- const budget = Number(input.maxCompletionTokens);
14
- const completion = Number(input.completionTokens);
15
- if (
16
- input.emptyResponseKind !== 'length'
17
- || !Number.isFinite(budget)
18
- || budget <= 0
19
- || !Number.isFinite(completion)
20
- || completion < budget
21
- ) return undefined;
22
-
23
- return EMPTY_LENGTH_EFFORT_DOWNGRADE[String(input.thinkingEffort || '').toLowerCase()];
24
- }
25
-
26
- module.exports = {
27
- EMPTY_LENGTH_EFFORT_DOWNGRADE,
28
- nextThinkingEffortForExhaustedEmpty,
29
- };
@@ -1,256 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('node:fs');
4
- const path = require('node:path');
5
- const { spawnSync } = require('node:child_process');
6
-
7
- const PROVIDER_ID = 'fredrik:zai';
8
- const PROVIDER_TYPE = 'openai_compatible';
9
- const BASE_URL = 'https://api.z.ai/api/coding/paas/v4';
10
- const MODEL_ALIASES = Object.freeze({
11
- 'fredrik/glm-5.3-flash': Object.freeze({
12
- model: 'glm-5.3-flash',
13
- displayName: 'GLM 5.3 Flash',
14
- }),
15
- 'fredrik/glm-5.3': Object.freeze({
16
- model: 'glm-5.3',
17
- displayName: 'GLM 5.3',
18
- }),
19
- });
20
- const MODEL_EFFORTS = Object.freeze(['low', 'high', 'max']);
21
- const MAX_SECRET_BYTES = 4096;
22
-
23
- function nonEmpty(value) {
24
- if (typeof value !== 'string') return undefined;
25
- const trimmed = value.trim();
26
- return trimmed.length === 0 ? undefined : trimmed;
27
- }
28
-
29
- function normalizeBaseUrl(value) {
30
- const raw = nonEmpty(value);
31
- if (raw === undefined) throw new Error('Fredrik GLM base_url is required.');
32
- let parsed;
33
- try {
34
- parsed = new URL(raw);
35
- } catch {
36
- throw new Error('Fredrik GLM base_url is invalid.');
37
- }
38
- if (
39
- parsed.protocol !== 'https:' ||
40
- parsed.username !== '' ||
41
- parsed.password !== '' ||
42
- parsed.search !== '' ||
43
- parsed.hash !== '' ||
44
- parsed.hostname.toLowerCase() !== 'api.z.ai'
45
- ) {
46
- throw new Error('Fredrik GLM base_url must use the approved api.z.ai Coding endpoint.');
47
- }
48
- const normalized = `${parsed.origin}${parsed.pathname.replace(/\/+$/, '')}`;
49
- if (normalized !== BASE_URL) {
50
- throw new Error('Fredrik GLM base_url must use the approved api.z.ai Coding endpoint.');
51
- }
52
- return BASE_URL;
53
- }
54
-
55
- function resolveProfileRoot(env = process.env) {
56
- const configured = nonEmpty(env.BLUN_HOME);
57
- if (configured !== undefined) return path.resolve(configured);
58
- const profile = nonEmpty(env.BLUN_PROFILE) ?? 'default';
59
- return path.resolve(require('node:os').homedir(), '.blun', 'profile', profile);
60
- }
61
-
62
- function isContained(root, candidate) {
63
- const relative = path.relative(root, candidate);
64
- return relative !== '' && !relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative);
65
- }
66
-
67
- function rejectUnsafeRelativePath(value) {
68
- const relative = nonEmpty(value);
69
- if (relative === undefined) throw new Error('Fredrik GLM api_key_file is required.');
70
- if (path.isAbsolute(relative)) throw new Error('Fredrik GLM api_key_file must be profile-relative.');
71
- if (relative.includes('\0')) throw new Error('Fredrik GLM api_key_file contains a NUL byte.');
72
- if (relative.split(/[\\/]/u).some((part) => part === '..' || part.includes(':'))) {
73
- throw new Error('Fredrik GLM api_key_file escapes the profile or uses an alternate data stream.');
74
- }
75
- return relative;
76
- }
77
-
78
- function assertNoSymlinkPath(root, candidate) {
79
- const relative = path.relative(root, candidate);
80
- let cursor = root;
81
- for (const segment of relative.split(path.sep)) {
82
- cursor = path.join(cursor, segment);
83
- const info = fs.lstatSync(cursor);
84
- if (info.isSymbolicLink()) throw new Error('Fredrik GLM api_key_file must not use links or reparse points.');
85
- }
86
- }
87
-
88
- function assertWindowsAcl(filePath) {
89
- if (process.platform !== 'win32') return;
90
- const script = [
91
- '$target = $env:BLUN_SECRET_ACL_PATH',
92
- '$unsafe = @("S-1-1-0", "S-1-5-11", "S-1-5-32-545")',
93
- '$writeMask = [System.Security.AccessControl.FileSystemRights]::Write -bor [System.Security.AccessControl.FileSystemRights]::Modify -bor [System.Security.AccessControl.FileSystemRights]::FullControl -bor [System.Security.AccessControl.FileSystemRights]::CreateFiles -bor [System.Security.AccessControl.FileSystemRights]::AppendData -bor [System.Security.AccessControl.FileSystemRights]::WriteData',
94
- 'foreach ($rule in (Get-Acl -LiteralPath $target).Access) {',
95
- ' if ($rule.AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow) { continue }',
96
- ' $sid = $rule.IdentityReference.Translate([System.Security.Principal.SecurityIdentifier]).Value',
97
- ' if ($unsafe -contains $sid -and (($rule.FileSystemRights -band $writeMask) -ne 0)) { exit 23 }',
98
- '}',
99
- 'exit 0',
100
- ].join('; ');
101
- const result = spawnSync('powershell.exe', ['-NoLogo', '-NoProfile', '-NonInteractive', '-Command', script], {
102
- encoding: 'utf8',
103
- windowsHide: true,
104
- timeout: 5000,
105
- env: { ...process.env, BLUN_SECRET_ACL_PATH: filePath },
106
- });
107
- if (result.status === 23) throw new Error('Fredrik GLM api_key_file ACL is too permissive.');
108
- if (result.status !== 0) throw new Error('Fredrik GLM api_key_file ACL could not be verified.');
109
- }
110
-
111
- function readApiKeyFile(provider, env = process.env) {
112
- if (provider?.type !== PROVIDER_TYPE) throw new Error('Fredrik GLM provider type is invalid.');
113
- if (provider.apiKey !== undefined || provider.env !== undefined || provider.oauth !== undefined || provider.customHeaders !== undefined) {
114
- throw new Error('Fredrik GLM accepts only api_key_file authentication.');
115
- }
116
- normalizeBaseUrl(provider.baseUrl);
117
- const profileRoot = resolveProfileRoot(env);
118
- const relative = rejectUnsafeRelativePath(provider.apiKeyFile);
119
- if (relative.replaceAll('\\', '/') !== 'secrets/zai-api-key.txt') {
120
- throw new Error('Fredrik GLM api_key_file must use the approved profile-relative path.');
121
- }
122
- const candidate = path.resolve(profileRoot, relative);
123
- if (!isContained(profileRoot, candidate)) throw new Error('Fredrik GLM api_key_file escapes the profile root.');
124
- let rootReal;
125
- let candidateReal;
126
- try {
127
- rootReal = fs.realpathSync(profileRoot);
128
- assertNoSymlinkPath(profileRoot, candidate);
129
- candidateReal = fs.realpathSync(candidate);
130
- } catch (error) {
131
- if (error instanceof Error && /links or reparse points/u.test(error.message)) throw error;
132
- throw new Error('Fredrik GLM api_key_file could not be resolved safely.');
133
- }
134
- if (!isContained(rootReal, candidateReal)) throw new Error('Fredrik GLM api_key_file escapes the resolved profile root.');
135
- let info;
136
- try {
137
- info = fs.statSync(candidateReal);
138
- } catch {
139
- throw new Error('Fredrik GLM api_key_file could not be inspected safely.');
140
- }
141
- if (!info.isFile()) throw new Error('Fredrik GLM api_key_file must be a regular file.');
142
- if (info.size < 1 || info.size > MAX_SECRET_BYTES) throw new Error('Fredrik GLM api_key_file has an invalid size.');
143
- assertWindowsAcl(candidateReal);
144
- let raw;
145
- try {
146
- raw = fs.readFileSync(candidateReal);
147
- } catch {
148
- throw new Error('Fredrik GLM api_key_file could not be read safely.');
149
- }
150
- if (raw[0] === 0xef && raw[1] === 0xbb && raw[2] === 0xbf) throw new Error('Fredrik GLM api_key_file must not contain a BOM.');
151
- if (raw.includes(0)) throw new Error('Fredrik GLM api_key_file must not contain NUL bytes.');
152
- const text = raw.toString('utf8');
153
- if (Buffer.from(text, 'utf8').compare(raw) !== 0) throw new Error('Fredrik GLM api_key_file must be valid UTF-8.');
154
- const lines = text.replace(/\r?\n$/u, '').split(/\r?\n/u);
155
- if (lines.length !== 1 || lines[0].trim().length === 0 || lines[0] !== lines[0].trim()) {
156
- throw new Error('Fredrik GLM api_key_file must contain exactly one non-empty line.');
157
- }
158
- return lines[0];
159
- }
160
-
161
- function isConfiguredAlias(alias, entry) {
162
- const expected = MODEL_ALIASES[alias];
163
- const capabilities = Array.isArray(entry?.capabilities) ? entry.capabilities : [];
164
- const efforts = Array.isArray(entry?.supportEfforts) ? entry.supportEfforts : [];
165
- return (
166
- expected !== undefined &&
167
- entry?.provider === PROVIDER_ID &&
168
- entry.model === expected.model &&
169
- entry.displayName === expected.displayName &&
170
- entry.defaultEffort === 'max' &&
171
- efforts.length === MODEL_EFFORTS.length &&
172
- efforts.every((effort, index) => effort === MODEL_EFFORTS[index]) &&
173
- capabilities.includes('always_thinking') &&
174
- capabilities.includes('tool_use')
175
- );
176
- }
177
-
178
- function configuredModels(models) {
179
- const out = {};
180
- for (const alias of Object.keys(MODEL_ALIASES)) {
181
- const entry = models?.[alias];
182
- if (isConfiguredAlias(alias, entry)) out[alias] = entry;
183
- }
184
- return out;
185
- }
186
-
187
- function configuredProvider(providers) {
188
- const provider = providers?.[PROVIDER_ID];
189
- if (provider?.type !== PROVIDER_TYPE) return undefined;
190
- if (
191
- provider.apiKey !== undefined ||
192
- provider.env !== undefined ||
193
- provider.oauth !== undefined ||
194
- provider.customHeaders !== undefined ||
195
- provider.apiKeyFile !== 'secrets/zai-api-key.txt'
196
- ) return undefined;
197
- try {
198
- normalizeBaseUrl(provider.baseUrl);
199
- } catch {
200
- return undefined;
201
- }
202
- return provider;
203
- }
204
-
205
- function isAllowedRuntimeAlias(alias, models) {
206
- return alias === 'blun/king' || isConfiguredAlias(alias, models?.[alias]);
207
- }
208
-
209
- function normalizeEffort(effort) {
210
- if (!MODEL_EFFORTS.includes(effort)) throw new Error('GLM 5.3 supports only low, high, or max reasoning effort.');
211
- return effort;
212
- }
213
-
214
- function requestControls(effort) {
215
- return Object.freeze({
216
- thinking: Object.freeze({ type: 'enabled' }),
217
- reasoning_effort: normalizeEffort(effort),
218
- });
219
- }
220
-
221
- function safeDiagnostic(alias, models, providers, credentialPresent = false) {
222
- const entry = models?.[alias];
223
- if (!isConfiguredAlias(alias, entry)) throw new Error('Unknown Fredrik GLM alias.');
224
- const provider = configuredProvider(providers);
225
- if (provider === undefined) throw new Error('Fredrik GLM provider is not configured safely.');
226
- return Object.freeze({
227
- alias,
228
- alias_source: 'profile-config',
229
- provider: PROVIDER_ID,
230
- provider_type: PROVIDER_TYPE,
231
- model: entry.model,
232
- base_host: 'api.z.ai',
233
- credential_source: 'profile-file',
234
- credential_present: credentialPresent === true,
235
- credential_fingerprint: null,
236
- wire_format: 'openai-chat-completions',
237
- health: 'untested',
238
- });
239
- }
240
-
241
- module.exports = Object.freeze({
242
- PROVIDER_ID,
243
- PROVIDER_TYPE,
244
- BASE_URL,
245
- MODEL_ALIASES,
246
- MODEL_EFFORTS,
247
- normalizeBaseUrl,
248
- readApiKeyFile,
249
- configuredModels,
250
- configuredProvider,
251
- isAllowedRuntimeAlias,
252
- isConfiguredAlias,
253
- normalizeEffort,
254
- requestControls,
255
- safeDiagnostic,
256
- });
@@ -1,77 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('node:fs');
4
- const zlib = require('node:zlib');
5
-
6
- function tarText(buffer, start, length) {
7
- return buffer.subarray(start, start + length).toString('utf8').replace(/\0.*$/s, '').trim();
8
- }
9
-
10
- function listTarGzPaths(tarballPath) {
11
- const archive = zlib.gunzipSync(fs.readFileSync(tarballPath));
12
- const paths = [];
13
- let offset = 0;
14
- while (offset + 512 <= archive.length) {
15
- const header = archive.subarray(offset, offset + 512);
16
- if (header.every((byte) => byte === 0)) break;
17
- const name = tarText(header, 0, 100);
18
- const prefix = tarText(header, 345, 155);
19
- const sizeText = tarText(header, 124, 12);
20
- const size = sizeText ? Number.parseInt(sizeText, 8) : 0;
21
- if (!Number.isFinite(size)) throw new Error(`Ungueltige TAR-Groesse bei ${name || '[ohne Namen]'}`);
22
- const fullName = [prefix, name].filter(Boolean).join('/').replaceAll('\\', '/');
23
- if (fullName) paths.push(fullName);
24
- offset += 512 + Math.ceil(size / 512) * 512;
25
- }
26
- return paths;
27
- }
28
-
29
- function isStablePackagePath(filePath) {
30
- const normalized = String(filePath || '').replaceAll('\\', '/');
31
- if (!normalized || normalized.endsWith('/')) return false;
32
- if (normalized.startsWith('package/dist-web/assets/')) return false;
33
- if (normalized.startsWith('package/dist-web/vis/')) return false;
34
- return normalized.startsWith('package/');
35
- }
36
-
37
- function validatePlannedRemovals(document) {
38
- const removals = Array.isArray(document?.removals) ? document.removals : [];
39
- for (const removal of removals) {
40
- if (!isStablePackagePath(removal?.path)) throw new Error(`Ungueltiger Entfernungspfad: ${removal?.path || '[leer]'}`);
41
- if (!String(removal?.reason || '').trim()) throw new Error(`Entfernungsgrund fehlt: ${removal.path}`);
42
- if (!String(removal?.decisionRef || '').trim()) throw new Error(`Entscheidungsreferenz fehlt: ${removal.path}`);
43
- }
44
- return new Set(removals.map((removal) => removal.path.replaceAll('\\', '/')));
45
- }
46
-
47
- function findUnexpectedRemovals(previousPaths, currentPaths, plannedDocument = { removals: [] }) {
48
- const current = new Set(currentPaths.map((entry) => String(entry).replaceAll('\\', '/')));
49
- const planned = validatePlannedRemovals(plannedDocument);
50
- return [...new Set(previousPaths
51
- .map((entry) => String(entry).replaceAll('\\', '/'))
52
- .filter(isStablePackagePath)
53
- .filter((entry) => !current.has(entry) && !planned.has(entry)))]
54
- .sort();
55
- }
56
-
57
- function comparePackagePaths(previousPaths, currentPaths, plannedDocument = { removals: [] }) {
58
- const previousStablePaths = [...new Set(previousPaths
59
- .map((entry) => String(entry).replaceAll('\\', '/'))
60
- .filter(isStablePackagePath))];
61
- const currentStablePaths = [...new Set(currentPaths
62
- .map((entry) => String(entry).replaceAll('\\', '/'))
63
- .filter(isStablePackagePath))];
64
- return {
65
- checkedStablePaths: previousStablePaths.length,
66
- currentStablePaths: currentStablePaths.length,
67
- unexpectedRemovals: findUnexpectedRemovals(previousStablePaths, currentStablePaths, plannedDocument),
68
- };
69
- }
70
-
71
- module.exports = {
72
- comparePackagePaths,
73
- findUnexpectedRemovals,
74
- isStablePackagePath,
75
- listTarGzPaths,
76
- validatePlannedRemovals,
77
- };