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,26 +0,0 @@
1
- # Add only to Fredrik's active profile config.toml. Keep King as the default.
2
-
3
- [providers."fredrik:zai"]
4
- type = "openai_compatible"
5
- base_url = "https://api.z.ai/api/coding/paas/v4"
6
- api_key_file = "secrets/zai-api-key.txt"
7
-
8
- [models."fredrik/glm-5.3-flash"]
9
- provider = "fredrik:zai"
10
- model = "glm-5.3-flash"
11
- display_name = "GLM 5.3 Flash"
12
- max_context_size = 1000000
13
- max_output_size = 128000
14
- capabilities = ["tool_use", "always_thinking"]
15
- support_efforts = ["low", "high", "max"]
16
- default_effort = "max"
17
-
18
- [models."fredrik/glm-5.3"]
19
- provider = "fredrik:zai"
20
- model = "glm-5.3"
21
- display_name = "GLM 5.3"
22
- max_context_size = 1000000
23
- max_output_size = 128000
24
- capabilities = ["tool_use", "always_thinking"]
25
- support_efforts = ["low", "high", "max"]
26
- default_effort = "max"
@@ -1,15 +0,0 @@
1
- {
2
- "version": "9.1.393",
3
- "removals": [
4
- {
5
- "path": "package/bin/running-update.cjs",
6
- "reason": "Background updater removed by owner decision; the visible manual startup picker remains.",
7
- "decisionRef": "Telegram DM 5597, 5603, 5610, 5614 and 5619, 2026-08-28"
8
- },
9
- {
10
- "path": "package/bin/running-update-preference.cjs",
11
- "reason": "Background updater preference removed with the background updater; manual startup choices remain.",
12
- "decisionRef": "Telegram DM 5597, 5603, 5610, 5614 and 5619, 2026-08-28"
13
- }
14
- ]
15
- }
@@ -1,36 +0,0 @@
1
- 'use strict';
2
-
3
- const assert = require('node:assert/strict');
4
- const fs = require('node:fs');
5
- const os = require('node:os');
6
- const path = require('node:path');
7
-
8
- const { installAgentSpineForExistingProfiles } = require('../bin/launcher-runtime');
9
-
10
- const packageRoot = path.resolve(__dirname, '..');
11
- const temporaryRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'blun-active-profile-plugin-'));
12
- const sharedHome = path.join(temporaryRoot, '.blun');
13
- const currentProfile = path.join(sharedHome, 'profile', 'current');
14
- const dormantProfile = path.join(sharedHome, 'profile', 'dormant');
15
-
16
- try {
17
- fs.mkdirSync(currentProfile, { recursive: true });
18
- fs.mkdirSync(dormantProfile, { recursive: true });
19
-
20
- installAgentSpineForExistingProfiles(packageRoot, sharedHome, currentProfile);
21
-
22
- assert.equal(
23
- fs.existsSync(path.join(currentProfile, 'plugins', 'installed.json')),
24
- true,
25
- 'the active profile must receive the managed AgentSpine plugin',
26
- );
27
- assert.equal(
28
- fs.existsSync(path.join(dormantProfile, 'plugins', 'installed.json')),
29
- false,
30
- 'startup must not rescan or mutate dormant profiles',
31
- );
32
-
33
- process.stdout.write('active profile plugin startup regression: PASS\n');
34
- } finally {
35
- fs.rmSync(temporaryRoot, { recursive: true, force: true });
36
- }
@@ -1,46 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('node:fs');
5
- const path = require('node:path');
6
-
7
- const packageRoot = process.env.BLUN_PACKAGE_UNDER_TEST
8
- ? path.resolve(process.env.BLUN_PACKAGE_UNDER_TEST)
9
- : path.resolve(__dirname, '..');
10
- const policy = require(path.join(packageRoot, 'bin', 'turn-thinking-policy.cjs'));
11
- const bundle = fs.readFileSync(path.join(packageRoot, 'blun.mjs'), 'utf8');
12
-
13
- function assert(condition, message) {
14
- if (!condition) throw new Error(`ACTIVE_WORK_STEER_REGRESSION: ${message}`);
15
- }
16
-
17
- assert(
18
- policy.selectThinkingEffortForTurn('Wo stehst du?', 'user') === 'low',
19
- 'an idle standalone status question must retain the fast conversation path',
20
- );
21
-
22
- for (const text of [
23
- 'Wo stehst du?',
24
- 'Kurzes Update',
25
- 'Danke, gute Arbeit',
26
- ]) {
27
- assert(
28
- policy.selectThinkingEffortForBufferedSteer(text, 'user') === undefined,
29
- `buffered active-work steer must preserve the running turn: ${text}`,
30
- );
31
- }
32
-
33
- assert(
34
- bundle.includes('if (steerEfforts.some((effort) => effort === void 0)) return;'),
35
- 'active-work steers no longer fall through to the running turn configuration',
36
- );
37
- assert(
38
- bundle.includes('additionalMessages: steers.messages,'),
39
- 'preserved active-work steers are not appended to the next model request',
40
- );
41
- assert(
42
- bundle.includes('this.turn.commitPendingSteers(steers);'),
43
- 'preserved active-work steers are not committed after request assembly',
44
- );
45
-
46
- process.stdout.write('active-work-steer-regression PASS\n');
@@ -1,111 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const assert = require('node:assert/strict');
5
- const fs = require('node:fs');
6
- const path = require('node:path');
7
-
8
- const packageRoot = path.resolve(__dirname, '..');
9
- const bundlePath = process.env.BLUN_BUNDLE_UNDER_TEST
10
- ? path.resolve(process.env.BLUN_BUNDLE_UNDER_TEST)
11
- : path.join(packageRoot, 'blun.mjs');
12
- const relayPath = process.env.BLUN_APPROVAL_RELAY_UNDER_TEST
13
- ? path.resolve(process.env.BLUN_APPROVAL_RELAY_UNDER_TEST)
14
- : path.join(packageRoot, 'bin', 'telegram-approval-relay.cjs');
15
- const pluginRelayPath = process.env.BLUN_PLUGIN_APPROVAL_RELAY_UNDER_TEST
16
- ? path.resolve(process.env.BLUN_PLUGIN_APPROVAL_RELAY_UNDER_TEST)
17
- : path.join(packageRoot, 'telegram-plugin', 'bin', 'telegram-approval-relay.cjs');
18
-
19
- const bundle = fs.readFileSync(bundlePath, 'utf8');
20
- const requestToolApproval = bundle.match(
21
- /async requestToolApproval\(context, result, policyName\) \{[\s\S]*?\n\t\t\}/,
22
- );
23
- assert(requestToolApproval, 'APPROVAL_OBSERVABILITY_REGRESSION: requestToolApproval is missing');
24
- assert.match(
25
- requestToolApproval[0],
26
- /this\.agent\.records\.logRecord\(\{[\s\S]*?type: "permission\.approval_requested"[\s\S]*?toolCallId: id[\s\S]*?toolName: name/,
27
- 'APPROVAL_OBSERVABILITY_REGRESSION: opening an approval is invisible in the wire',
28
- );
29
- assert(
30
- requestToolApproval[0].indexOf('type: "permission.approval_requested"')
31
- < requestToolApproval[0].indexOf('await this.agent.rpc.requestApproval'),
32
- 'APPROVAL_OBSERVABILITY_REGRESSION: approval wire event is emitted too late',
33
- );
34
-
35
- const ApprovalProbe = Function(`return class ApprovalProbe {${requestToolApproval[0]}};`)();
36
- const wireRecords = [];
37
- const probe = new ApprovalProbe();
38
- probe.agent = {
39
- records: { logRecord(record) { wireRecords.push(record); } },
40
- rpc: { async requestApproval() { return { decision: 'approved' }; } },
41
- hooks: { fireAndForgetTrigger() {} },
42
- telemetry: { track() {} },
43
- };
44
- probe.recordApprovalResult = () => {};
45
- probe.permissionPolicyResolutionToPrepare = () => undefined;
46
- probe.formatApprovalRejectionMessage = () => '';
47
-
48
- const approvalRun = probe.requestToolApproval({
49
- signal: new AbortController().signal,
50
- turnId: 7,
51
- toolCall: { id: 'tool-7', name: 'Bash' },
52
- execution: {
53
- description: 'Run command',
54
- display: { kind: 'command', command: 'echo ok' },
55
- },
56
- args: { command: 'echo ok' },
57
- }, {}, 'manual-approval');
58
- assert.equal(wireRecords.length, 1, 'approval request must be written before awaiting a response');
59
- assert.deepEqual(
60
- wireRecords[0],
61
- {
62
- type: 'permission.approval_requested',
63
- turnId: 7,
64
- toolCallId: 'tool-7',
65
- toolName: 'Bash',
66
- action: 'Run command',
67
- display: { kind: 'command', command: 'echo ok' },
68
- policyName: 'manual-approval',
69
- },
70
- 'approval wire record lost identifying fields',
71
- );
72
-
73
- function checkRelay(modulePath, label) {
74
- delete require.cache[require.resolve(modulePath)];
75
- const { resolveTelegramApprovalTarget } = require(modulePath);
76
- assert.equal(
77
- resolveTelegramApprovalTarget(['1605241602', '-1003927574737']),
78
- '1605241602',
79
- `${label}: one authorized private chat must be selected even when groups are also allowed`,
80
- );
81
- assert.equal(
82
- resolveTelegramApprovalTarget(['0', '-1003927574737']),
83
- null,
84
- `${label}: zero is not a positive private Telegram chat ID`,
85
- );
86
- assert.equal(
87
- resolveTelegramApprovalTarget(['1605241602', '8711923962', '-1003927574737']),
88
- null,
89
- `${label}: multiple authorized private chats must remain fail-closed`,
90
- );
91
- assert.equal(
92
- resolveTelegramApprovalTarget(['1605241602', '8711923962'], '8711923962'),
93
- '8711923962',
94
- `${label}: an explicitly configured authorized chat must win`,
95
- );
96
- assert.equal(
97
- resolveTelegramApprovalTarget(['1605241602'], '-1003927574737'),
98
- null,
99
- `${label}: an unauthorized configured chat must be rejected`,
100
- );
101
- }
102
-
103
- checkRelay(relayPath, 'package relay');
104
- checkRelay(pluginRelayPath, 'plugin relay');
105
-
106
- approvalRun.then(() => {
107
- process.stdout.write('approval-observability-regression PASS\n');
108
- }).catch((error) => {
109
- process.stderr.write(`${error.stack || error.message}\n`);
110
- process.exitCode = 1;
111
- });
@@ -1,65 +0,0 @@
1
- const assert = require('node:assert/strict');
2
- const fs = require('node:fs');
3
- const path = require('node:path');
4
-
5
- const bundlePath = process.env.BLUN_BUNDLE_UNDER_TEST
6
- || path.join(__dirname, '..', 'blun.mjs');
7
- const bundle = fs.readFileSync(bundlePath, 'utf8');
8
-
9
- function between(start, end, from = 0) {
10
- const startIndex = bundle.indexOf(start, from);
11
- assert.notEqual(startIndex, -1, `missing bundle marker: ${start}`);
12
- const endIndex = bundle.indexOf(end, startIndex + start.length);
13
- assert.notEqual(endIndex, -1, `missing bundle marker: ${end}`);
14
- return bundle.slice(startIndex, endIndex);
15
- }
16
-
17
- const panelStart = bundle.indexOf('var ApprovalPanelComponent = class extends Container {');
18
- assert.notEqual(panelStart, -1, 'ApprovalPanelComponent must exist');
19
- const handleSource = between('\n\thandleInput(data) {', '\n\trender(width) {', panelStart).trim();
20
-
21
- const Key = {
22
- escape: 'escape',
23
- ctrl(key) { return `ctrl+${key}`; },
24
- };
25
- const matchesKey = (data, expected) => {
26
- if (expected === 'escape') return data === '\x1b';
27
- if (expected === 'ctrl+s') return data === '\x13';
28
- return data === expected;
29
- };
30
- const handleInput = Function(
31
- 'matchesKey',
32
- 'Key',
33
- `"use strict"; return ({${handleSource}}).handleInput;`,
34
- )(matchesKey, Key);
35
-
36
- let responses = 0;
37
- let flushed = 0;
38
- let released = 0;
39
- const panel = {
40
- choiceCount() { return 0; },
41
- onResponse(response) {
42
- responses += 1;
43
- assert.equal(response.response, 'rejected');
44
- },
45
- onCtrlS() { flushed += 1; },
46
- onEscape() { released += 1; return true; },
47
- };
48
-
49
- handleInput.call(panel, '\x13');
50
- assert.equal(flushed, 1, 'Ctrl+S must reach the global queue flush while approval is open');
51
- assert.equal(responses, 0);
52
-
53
- handleInput.call(panel, '\x1b');
54
- assert.equal(released, 1, 'Escape must first release one queued message while approval is open');
55
- assert.equal(responses, 0, 'a released queued message must not reject the approval');
56
-
57
- panel.onEscape = () => false;
58
- handleInput.call(panel, '\x1b');
59
- assert.equal(responses, 1, 'Escape must reject the approval when no queued message waits');
60
-
61
- const showApprovalPanel = between('\n\tshowApprovalPanel(payload) {', '\n\thideApprovalPanel() {');
62
- assert.match(showApprovalPanel, /this\.flushQueuedMessages\(this\.state\.editor\.getText\(\)\.trim\(\), this\.state\.editor\.inputMode\)/);
63
- assert.match(showApprovalPanel, /return this\.releaseNextQueuedMessage\(\)/);
64
-
65
- console.log('approval queue shortcuts regression: PASS');
@@ -1,48 +0,0 @@
1
- const assert = require('node:assert/strict');
2
- const { execFileSync } = require('node:child_process');
3
- const fs = require('node:fs');
4
- const path = require('node:path');
5
-
6
- const expectedVersion = '0.11.4';
7
- const pluginRoot = process.env.BLUN_AGENT_SPINE_ROOT_UNDER_TEST
8
- ? path.resolve(process.env.BLUN_AGENT_SPINE_ROOT_UNDER_TEST)
9
- : path.resolve(__dirname, '..', 'agent-spine-plugin');
10
-
11
- function readJson(relativePath) {
12
- return JSON.parse(fs.readFileSync(path.join(pluginRoot, relativePath), 'utf8'));
13
- }
14
-
15
- for (const relativePath of [
16
- 'package.json',
17
- 'hooks/version.json',
18
- '.claude-plugin/plugin.json',
19
- '.codex-plugin/plugin.json',
20
- 'blun.plugin.json',
21
- ]) {
22
- assert.equal(
23
- readJson(relativePath).version,
24
- expectedVersion,
25
- `BUNDLED_AGENT_SPINE_REGRESSION: ${relativePath} must declare ${expectedVersion}`,
26
- );
27
- }
28
-
29
- const runtimeVersion = execFileSync(
30
- process.execPath,
31
- [path.join(pluginRoot, 'bin', 'agentspine.js'), '--version'],
32
- { encoding: 'utf8' },
33
- ).trim();
34
- assert.equal(
35
- runtimeVersion,
36
- expectedVersion,
37
- 'BUNDLED_AGENT_SPINE_REGRESSION: packaged runtime version is stale',
38
- );
39
-
40
- for (const relativePath of ['CONTRIBUTING.md', 'SECURITY.md']) {
41
- assert.equal(
42
- fs.existsSync(path.join(pluginRoot, relativePath)),
43
- true,
44
- `BUNDLED_AGENT_SPINE_REGRESSION: README link target ${relativePath} is missing`,
45
- );
46
- }
47
-
48
- console.log(`bundled-agent-spine-regression PASS (${expectedVersion})`);
@@ -1,92 +0,0 @@
1
- 'use strict';
2
-
3
- const assert = require('node:assert/strict');
4
- const { spawnSync } = require('node:child_process');
5
- const { mkdtempSync, readFileSync, rmSync, writeFileSync } = require('node:fs');
6
- const { tmpdir } = require('node:os');
7
- const { join } = require('node:path');
8
- const { pathToFileURL } = require('node:url');
9
-
10
- const root = join(__dirname, '..');
11
- const bundlePath = join(root, 'blun.mjs');
12
- const scriptPath = join(root, 'codebase-index', 'codebase_index.py');
13
- const readmePath = join(root, 'codebase-index', 'README.md');
14
- const runtimePath = join(root, 'bin', 'codebase-search-runtime.cjs');
15
-
16
- function readUtf8(path) {
17
- return readFileSync(path, 'utf8');
18
- }
19
-
20
- function pythonCommand() {
21
- for (const command of ['python', 'python3']) {
22
- const result = spawnSync(command, ['--version'], { encoding: 'utf8', windowsHide: true });
23
- if (result.status === 0) return command;
24
- }
25
- throw new Error('CODEBASE_SEARCH_PYTHON_MISSING');
26
- }
27
-
28
- function assertPackageContract() {
29
- const packageJson = JSON.parse(readUtf8(join(root, 'package.json')));
30
- assert.ok(packageJson.files.includes('codebase-index/'), 'package files must include codebase-index/');
31
- assert.ok(packageJson.scripts.prepack.includes('check-codebase-search-packaging-regression.js'), 'prepack must run the packaging gate');
32
-
33
- const source = readUtf8(bundlePath);
34
- assert.match(source, /resolveCodebaseIndexScript\(import\.meta\.url, process\.env\["CODEBASE_INDEX_SCRIPT"\]\)/u);
35
- assert.match(source, /\.\/bin\/codebase-search-runtime\.cjs/u);
36
- const start = source.indexOf('function resolveScriptPath()');
37
- const end = source.indexOf('\nvar resolveCodebaseIndexScript', start);
38
- assert.ok(start >= 0 && end > start, 'CodebaseSearch resolver region missing');
39
- assert.doesNotMatch(source.slice(start, end), /\.\.\/\.\.\/\.\.\/\.\.\/\.\.\/codebase-index/u, 'source-tree traversal must not survive packaging');
40
- }
41
-
42
- function assertResolverContract() {
43
- const { resolveCodebaseIndexScript } = require(runtimePath);
44
- const bundleUrl = pathToFileURL(bundlePath).href;
45
- assert.equal(resolveCodebaseIndexScript(bundleUrl), scriptPath, 'default resolution must select the packaged script');
46
-
47
- const temp = mkdtempSync(join(tmpdir(), 'blun-codebase-search-'));
48
- try {
49
- const override = join(temp, 'override.py');
50
- writeFileSync(override, 'print("override")\n', 'utf8');
51
- assert.equal(resolveCodebaseIndexScript(bundleUrl, override), override, 'existing absolute override must win');
52
- assert.equal(resolveCodebaseIndexScript(bundleUrl, join(temp, 'missing.py')), '', 'missing override must fail closed');
53
- assert.equal(resolveCodebaseIndexScript(bundleUrl, 'relative.py'), '', 'relative override must fail closed');
54
- assert.equal(resolveCodebaseIndexScript('', override), '', 'missing module URL must fail closed');
55
- } finally {
56
- rmSync(temp, { recursive: true, force: true });
57
- }
58
- }
59
-
60
- function assertPythonSource() {
61
- const source = readUtf8(scriptPath);
62
- assert.match(source, /def cmd_build\(repo: str\)/u);
63
- assert.match(source, /def cmd_update\(repo: str\)/u);
64
- assert.match(source, /def cmd_query\(repo: str, question: str, top: int\)/u);
65
- assert.match(source, /HINWEIS: semantischer Index/u);
66
- assert.match(readUtf8(readmePath), /fastembed/u);
67
-
68
- const cache = mkdtempSync(join(tmpdir(), 'blun-codebase-pycache-'));
69
- try {
70
- const result = spawnSync(pythonCommand(), ['-m', 'py_compile', scriptPath], {
71
- encoding: 'utf8',
72
- env: { ...process.env, PYTHONPYCACHEPREFIX: cache },
73
- windowsHide: true,
74
- });
75
- assert.equal(result.status, 0, `codebase_index.py syntax failed: ${result.stderr || result.stdout}`);
76
- } finally {
77
- rmSync(cache, { recursive: true, force: true });
78
- }
79
- }
80
-
81
- function assertMutationCoverage() {
82
- const runtime = readUtf8(runtimePath);
83
- assert.match(runtime, /existsSync\(packaged\) \? packaged : ''/u, 'packaged path existence gate missing');
84
- assert.match(runtime, /!isAbsolute\(envPath\) \|\| !existsSync\(envPath\)/u, 'override boundary missing');
85
- assert.doesNotMatch(runtime, /process\.cwd/u, 'resolver must not search arbitrary working directories');
86
- }
87
-
88
- assertPackageContract();
89
- assertResolverContract();
90
- assertPythonSource();
91
- assertMutationCoverage();
92
- process.stdout.write('codebase-search-packaging PASS\n');
@@ -1,74 +0,0 @@
1
- 'use strict';
2
-
3
- const assert = require('node:assert/strict');
4
- const fs = require('node:fs');
5
- const path = require('node:path');
6
- const vm = require('node:vm');
7
-
8
- const rootArg = process.argv.find((value) => value.startsWith('--root='));
9
- const packageRoot = rootArg ? path.resolve(rootArg.slice('--root='.length)) : path.resolve(__dirname, '..');
10
- const bundle = fs.readFileSync(path.join(packageRoot, 'blun.mjs'), 'utf8');
11
-
12
- function extractFunction(name) {
13
- const start = bundle.indexOf(`function ${name}(`);
14
- assert.notEqual(start, -1, `${name} must exist`);
15
- const open = bundle.indexOf('{', start);
16
- let depth = 0;
17
- for (let index = open; index < bundle.length; index += 1) {
18
- if (bundle[index] === '{') depth += 1;
19
- if (bundle[index] === '}') depth -= 1;
20
- if (depth === 0) return bundle.slice(start, index + 1);
21
- }
22
- assert.fail(`${name} must have a complete function body`);
23
- }
24
-
25
- assert.match(
26
- bundle,
27
- /name:\s*"copy"[\s\S]{0,180}descriptionKey:\s*"command\.copy\.description"[\s\S]{0,180}availability:\s*"always"/,
28
- '/copy must be registered and available while a turn is running',
29
- );
30
- assert.match(bundle, /case "copy":\s*await handleCopyCommand\(host\);\s*return;/, '/copy must dispatch to its handler');
31
- assert.match(bundle, /await copyTextToClipboard\(text\);/, '/copy must use the existing cross-platform clipboard helper');
32
-
33
- const selectorSource = extractFunction('findLatestAssistantResponse');
34
- const findLatestAssistantResponse = vm.runInNewContext(`(${selectorSource})`);
35
- assert.equal(
36
- findLatestAssistantResponse([
37
- { kind: 'assistant', content: ' previous answer ' },
38
- { kind: 'user', content: 'question' },
39
- { kind: 'assistant', content: ' ' },
40
- ]),
41
- ' previous answer ',
42
- 'the selector must ignore user and empty assistant entries while preserving response bytes',
43
- );
44
- assert.equal(findLatestAssistantResponse([{ kind: 'user', content: 'question' }]), undefined);
45
-
46
- const requiredUiStrings = [
47
- 'Copy the latest assistant response to the clipboard.',
48
- 'Copied the latest response to the clipboard.',
49
- 'There is no response to copy yet.',
50
- 'Could not copy the latest response: {error}',
51
- 'Neueste Assistentenantwort in die Zwischenablage übernehmen.',
52
- 'Die neueste Antwort wurde in die Zwischenablage übernommen.',
53
- 'Es ist noch keine Antwort zum Kopieren verfügbar.',
54
- 'Die neueste Antwort konnte nicht kopiert werden: {error}',
55
- 'Copiar la respuesta más reciente del asistente al portapapeles.',
56
- 'La respuesta más reciente se copió al portapapeles.',
57
- 'Todavía no hay ninguna respuesta que copiar.',
58
- 'No se pudo copiar la respuesta más reciente: {error}',
59
- 'Copier la réponse la plus récente de l’assistant dans le presse-papiers.',
60
- 'La réponse la plus récente a été copiée dans le presse-papiers.',
61
- 'Aucune réponse à copier pour le moment.',
62
- 'Impossible de copier la réponse la plus récente : {error}',
63
- 'Kopiera assistentens senaste svar till urklipp.',
64
- 'Det senaste svaret kopierades till urklipp.',
65
- 'Det finns inget svar att kopiera ännu.',
66
- 'Det gick inte att kopiera det senaste svaret: {error}',
67
- 'Zkopírovat nejnovější odpověď asistenta do schránky.',
68
- 'Nejnovější odpověď byla zkopírována do schránky.',
69
- 'Zatím není k dispozici žádná odpověď ke zkopírování.',
70
- 'Nejnovější odpověď se nepodařilo zkopírovat: {error}',
71
- ];
72
- for (const text of requiredUiStrings) assert.ok(bundle.includes(text), `missing released UI text: ${text}`);
73
-
74
- process.stdout.write('Copy command regression gate: PASS\n');
@@ -1,72 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('node:fs');
5
- const os = require('node:os');
6
- const path = require('node:path');
7
- const { spawnSync } = require('node:child_process');
8
-
9
- const packageRoot = path.resolve(__dirname, '..');
10
- const gatePath = path.join(packageRoot, 'scripts', 'check-current-turn-read-pin-regression.js');
11
- const sourcePolicy = fs.readFileSync(
12
- path.join(packageRoot, 'bin', 'tool-result-offload-policy.cjs'),
13
- 'utf8',
14
- );
15
- const sourceBundle = fs.readFileSync(path.join(packageRoot, 'blun.mjs'), 'utf8');
16
-
17
- const mutations = [
18
- {
19
- name: 'policy helper removed',
20
- policy: sourcePolicy.replace(
21
- 'function currentTurnReadToolResultIds(messages) {',
22
- 'function removedCurrentTurnReadToolResultIds(messages) {',
23
- ),
24
- bundle: sourceBundle,
25
- },
26
- {
27
- name: 'injections accepted as user turns',
28
- policy: sourcePolicy.replace(
29
- "message?.role === 'user' && message.origin?.kind === 'user'",
30
- "message?.role === 'user'",
31
- ),
32
- bundle: sourceBundle,
33
- },
34
- {
35
- name: 'Read pin filter removed',
36
- policy: sourcePolicy,
37
- bundle: sourceBundle.replace(
38
- ' && !pinnedReadIds.has(message.toolCallId)',
39
- '',
40
- ),
41
- },
42
- {
43
- name: 'current user instruction no longer skipped',
44
- policy: sourcePolicy,
45
- bundle: sourceBundle.replace(
46
- 'if (historyIndex === currentTurnStart) continue;',
47
- 'if (false && historyIndex === currentTurnStart) continue;',
48
- ),
49
- },
50
- ];
51
-
52
- for (const mutation of mutations) {
53
- if (mutation.policy === sourcePolicy && mutation.bundle === sourceBundle) {
54
- throw new Error(`mutation marker missing: ${mutation.name}`);
55
- }
56
- const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'blun-read-pin-mutation-'));
57
- try {
58
- fs.mkdirSync(path.join(tempRoot, 'bin'), { recursive: true });
59
- fs.writeFileSync(path.join(tempRoot, 'bin', 'tool-result-offload-policy.cjs'), mutation.policy);
60
- fs.writeFileSync(path.join(tempRoot, 'blun.mjs'), mutation.bundle);
61
- const result = spawnSync(process.execPath, [gatePath], {
62
- cwd: packageRoot,
63
- encoding: 'utf8',
64
- env: { ...process.env, BLUN_PACKAGE_UNDER_TEST: tempRoot },
65
- });
66
- if (result.status === 0) throw new Error(`gate accepted mutation: ${mutation.name}`);
67
- } finally {
68
- fs.rmSync(tempRoot, { recursive: true, force: true });
69
- }
70
- }
71
-
72
- process.stdout.write(`current-turn-read-pin-mutation-regression PASS (${mutations.length} mutations rejected)\n`);