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,228 +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 bundlePath = process.env.BLUN_BUNDLE_UNDER_TEST
10
- ? path.resolve(process.env.BLUN_BUNDLE_UNDER_TEST)
11
- : path.resolve(__dirname, '..', 'blun.mjs');
12
- const bundle = fs.readFileSync(bundlePath, 'utf8');
13
-
14
- function assert(condition, message) {
15
- if (!condition) throw new Error(message);
16
- }
17
-
18
- const renderer = bundle.match(
19
- /function renderSessionStartHookResult\(results\) \{[\s\S]*?\n\}/,
20
- );
21
- const allowRenderer = bundle.match(
22
- /function renderAllowHookResult\(event, results\) \{[\s\S]*?\n\}/,
23
- );
24
- const wrapperRenderer = bundle.match(
25
- /function renderHookResult\(event, message\) \{[\s\S]*?\n\}/,
26
- );
27
- const messageSelector = bundle.match(
28
- /function userPromptHookMessage\(result\) \{[\s\S]*?\n\}/,
29
- );
30
- const stringPredicate = bundle.match(
31
- /function isNonEmptyString\$1\(value\) \{[\s\S]*?\n\}/,
32
- );
33
- const trigger = bundle.match(
34
- /async triggerSessionStart\(source\) \{[\s\S]*?\n\t\t\}/,
35
- );
36
- const scheduler = bundle.match(
37
- /scheduleSessionStart\(source\) \{[\s\S]*?\n\t\t\}/,
38
- );
39
- const createMain = bundle.match(
40
- /async createMain\(\) \{[\s\S]*?\n\t\t\}/,
41
- );
42
- const resume = bundle.match(
43
- /async resume\(\) \{[\s\S]*?\n\t\t\}/,
44
- );
45
-
46
- assert(renderer, 'SESSION_START_HOOK_CONTEXT_REGRESSION: SessionStart renderer is missing');
47
- assert(allowRenderer, 'SESSION_START_HOOK_CONTEXT_REGRESSION: shared allow renderer is missing');
48
- assert(wrapperRenderer, 'SESSION_START_HOOK_CONTEXT_REGRESSION: hook wrapper renderer is missing');
49
- assert(messageSelector, 'SESSION_START_HOOK_CONTEXT_REGRESSION: hook message selector is missing');
50
- assert(stringPredicate, 'SESSION_START_HOOK_CONTEXT_REGRESSION: hook string predicate is missing');
51
- assert(trigger, 'SESSION_START_HOOK_CONTEXT_REGRESSION: SessionStart trigger is missing');
52
- assert(scheduler, 'SESSION_START_HOOK_CONTEXT_REGRESSION: non-blocking SessionStart scheduler is missing');
53
- assert(createMain, 'SESSION_START_HOOK_CONTEXT_REGRESSION: createMain is missing');
54
- assert(resume, 'SESSION_START_HOOK_CONTEXT_REGRESSION: resume is missing');
55
- assert(
56
- /renderAllowHookResult\("SessionStart", results\)/.test(renderer[0]),
57
- 'SESSION_START_HOOK_CONTEXT_REGRESSION: SessionStart output is not rendered',
58
- );
59
- assert(
60
- /const results = await this\.hookEngine\.trigger\("SessionStart"/.test(trigger[0]),
61
- 'SESSION_START_HOOK_CONTEXT_REGRESSION: SessionStart results are still discarded',
62
- );
63
- assert(
64
- /renderSessionStartHookResult\(results\)/.test(trigger[0]),
65
- 'SESSION_START_HOOK_CONTEXT_REGRESSION: SessionStart result does not reach the context path',
66
- );
67
- assert(
68
- /appendSystemReminder\([\s\S]*variant: "session_start_hook"/.test(trigger[0]),
69
- 'SESSION_START_HOOK_CONTEXT_REGRESSION: SessionStart result is not persisted as a scoped reminder',
70
- );
71
- assert(
72
- /await mainAgent\.records\.flush\(\)/.test(trigger[0]),
73
- 'SESSION_START_HOOK_CONTEXT_REGRESSION: completed SessionStart reminder is not flushed',
74
- );
75
- assert(
76
- /this\.scheduleSessionStart\("startup"\)/.test(createMain[0])
77
- && !/await this\.triggerSessionStart\("startup"\)/.test(createMain[0]),
78
- 'SESSION_START_HOOK_CONTEXT_REGRESSION: fresh-session input is still blocked by SessionStart',
79
- );
80
- assert(
81
- /this\.scheduleSessionStart\("resume"\)/.test(resume[0])
82
- && !/await this\.triggerSessionStart\("resume"\)/.test(resume[0]),
83
- 'SESSION_START_HOOK_CONTEXT_REGRESSION: resumed-session input is still blocked by SessionStart',
84
- );
85
- assert(
86
- /void this\.triggerSessionStart\(source\)\.catch\(/.test(scheduler[0]),
87
- 'SESSION_START_HOOK_CONTEXT_REGRESSION: SessionStart is not detached from interactive startup',
88
- );
89
-
90
- const packageRoot = path.resolve(__dirname, '..');
91
- const agentSpineRoot = path.join(packageRoot, 'agent-spine-plugin');
92
- const agentSpineManifest = JSON.parse(
93
- fs.readFileSync(path.join(agentSpineRoot, 'blun.plugin.json'), 'utf8'),
94
- );
95
- const agentSpineCodexHooks = JSON.parse(
96
- fs.readFileSync(path.join(agentSpineRoot, 'hooks', 'codex.json'), 'utf8'),
97
- );
98
- const blunSessionStart = agentSpineManifest.hooks.find(
99
- (hook) => hook.event === 'SessionStart',
100
- );
101
- const codexSessionStart = agentSpineCodexHooks.hooks.SessionStart?.[0]?.hooks?.[0];
102
-
103
- assert(
104
- blunSessionStart?.timeout >= 180,
105
- 'SESSION_START_HOOK_CONTEXT_REGRESSION: BLUN AgentSpine SessionStart timeout must cover the measured 123.6 s cold scan',
106
- );
107
- assert(
108
- codexSessionStart?.timeout >= 180,
109
- 'SESSION_START_HOOK_CONTEXT_REGRESSION: Codex AgentSpine SessionStart timeout must match the BLUN runtime budget',
110
- );
111
-
112
- const probeRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'blun-session-start-hook-'));
113
- try {
114
- fs.mkdirSync(path.join(probeRoot, '.git'));
115
- fs.writeFileSync(
116
- path.join(probeRoot, 'AGENTS.md'),
117
- '# SessionStart probe\n\nLoad this project instruction automatically.\n',
118
- );
119
- const stateRoot = path.join(probeRoot, '.agentspine-state');
120
- const hookRun = spawnSync(process.execPath, [path.join(agentSpineRoot, 'src', 'hook.js')], {
121
- cwd: agentSpineRoot,
122
- input: JSON.stringify({
123
- hook_event_name: 'SessionStart',
124
- session_id: 'session-start-regression',
125
- cwd: probeRoot,
126
- source: 'resume',
127
- }),
128
- encoding: 'utf8',
129
- timeout: 30_000,
130
- env: {
131
- ...process.env,
132
- BLUN_HOME: probeRoot,
133
- BLUN_PLUGIN_ROOT: agentSpineRoot,
134
- AGENTSPINE_STATE_DIR: stateRoot,
135
- },
136
- });
137
- assert(
138
- hookRun.error === undefined && hookRun.status === 0,
139
- `SESSION_START_HOOK_CONTEXT_REGRESSION: real AgentSpine hook failed: ${hookRun.error?.message || hookRun.stderr}`,
140
- );
141
- const hookOutput = JSON.parse(hookRun.stdout.trim());
142
- assert(
143
- hookOutput.hookSpecificOutput?.hookEventName === 'SessionStart'
144
- && hookOutput.hookSpecificOutput?.message?.includes('AgentSpine'),
145
- `SESSION_START_HOOK_CONTEXT_REGRESSION: real AgentSpine process output is not injectable: ${hookRun.stdout.trim()}`,
146
- );
147
- } finally {
148
- fs.rmSync(probeRoot, { recursive: true, force: true });
149
- }
150
-
151
- const triggerFunction = trigger[0].replace(
152
- /^async triggerSessionStart/,
153
- 'async function triggerSessionStart',
154
- );
155
- const schedulerFunction = scheduler[0].replace(
156
- /^scheduleSessionStart/,
157
- 'function scheduleSessionStart',
158
- );
159
- const runTrigger = Function(
160
- `${wrapperRenderer[0]}\n${messageSelector[0]}\n${stringPredicate[0]}\n${allowRenderer[0]}\n${renderer[0]}\n${triggerFunction}\nreturn triggerSessionStart;`,
161
- )();
162
- const scheduleTrigger = Function(
163
- `${schedulerFunction}\nreturn scheduleSessionStart;`,
164
- )();
165
-
166
- (async () => {
167
- const reminders = [];
168
- let flushes = 0;
169
- const fakeSession = {
170
- hookEngine: {
171
- async trigger(event, args) {
172
- assert(event === 'SessionStart', 'runtime probe called the wrong hook event');
173
- assert(args.matcherValue === 'resume', 'runtime probe lost the reload matcher');
174
- return [{ action: 'allow', message: 'AgentSpine ready: 152 sources indexed.' }];
175
- },
176
- },
177
- requireMainAgent() {
178
- return {
179
- context: {
180
- appendSystemReminder(text, origin) {
181
- reminders.push({ text, origin });
182
- },
183
- },
184
- records: {
185
- async flush() {
186
- flushes += 1;
187
- },
188
- },
189
- };
190
- },
191
- };
192
-
193
- await runTrigger.call(fakeSession, 'resume');
194
- assert(reminders.length === 1, 'runtime probe did not append exactly one reminder');
195
- assert(flushes === 1, 'runtime probe did not flush exactly once');
196
- assert(
197
- reminders[0].text.includes('<hook_result hook_event="SessionStart">')
198
- && reminders[0].text.includes('AgentSpine ready: 152 sources indexed.'),
199
- 'runtime probe lost the AgentSpine SessionStart message',
200
- );
201
- assert(
202
- reminders[0].origin?.kind === 'injection'
203
- && reminders[0].origin?.variant === 'session_start_hook',
204
- 'runtime probe used the wrong reminder origin',
205
- );
206
-
207
- let detachedCompleted = false;
208
- const detachedStartedAt = Date.now();
209
- scheduleTrigger.call({
210
- async triggerSessionStart(source) {
211
- assert(source === 'startup', 'detached runtime probe lost the startup source');
212
- await new Promise((resolve) => setTimeout(resolve, 75));
213
- detachedCompleted = true;
214
- },
215
- log: { warn() {} },
216
- }, 'startup');
217
- assert(
218
- Date.now() - detachedStartedAt < 50 && detachedCompleted === false,
219
- 'SessionStart scheduler still waits for the hook before returning',
220
- );
221
- await new Promise((resolve) => setTimeout(resolve, 100));
222
- assert(detachedCompleted, 'detached SessionStart hook did not finish in the background');
223
-
224
- process.stdout.write('session-start-hook-context-regression PASS\n');
225
- })().catch((error) => {
226
- process.stderr.write(`${error.stack || error.message}\n`);
227
- process.exitCode = 1;
228
- });
@@ -1,81 +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
- const { spawn } = require('node:child_process');
8
-
9
- const packageRoot = path.resolve(__dirname, '..');
10
- const bundlePath = process.argv[2] === undefined
11
- ? path.join(packageRoot, 'blun.mjs')
12
- : path.resolve(process.argv[2]);
13
- const bundle = fs.readFileSync(bundlePath, 'utf8');
14
- const source = /function buildLocalSpawnOptions\(isWindows, cwd, env\) \{[\s\S]*?\n\}/.exec(bundle)?.[0];
15
-
16
- assert(source, 'SHELL_TERMINAL_ISOLATION: buildLocalSpawnOptions is missing');
17
-
18
- const context = {};
19
- vm.runInNewContext(`${source}; globalThis.buildLocalSpawnOptions = buildLocalSpawnOptions;`, context);
20
- const buildLocalSpawnOptions = context.buildLocalSpawnOptions;
21
- const cwd = packageRoot;
22
- const env = { ...process.env, BLUN_SHELL_ISOLATION_PROBE: '1' };
23
-
24
- for (const isWindows of [false, true]) {
25
- const options = buildLocalSpawnOptions(isWindows, cwd, env);
26
- assert.deepEqual(Array.from(options.stdio), ['pipe', 'pipe', 'pipe']);
27
- assert.equal(options.detached, true,
28
- `local shell must start in a separate process group when isWindows=${String(isWindows)}`);
29
- assert.equal(options.windowsHide, true);
30
- assert.equal(options.cwd, cwd);
31
- assert.equal(options.env, env);
32
- }
33
-
34
- async function runCapturedProcessProbe() {
35
- const options = buildLocalSpawnOptions(process.platform === 'win32', cwd, env);
36
- const child = spawn(process.execPath, [
37
- '-e',
38
- [
39
- "process.stdin.setEncoding('utf8')",
40
- "process.stdin.on('data', () => { process.exitCode = 90 })",
41
- "process.stdin.on('end', () => {",
42
- " process.stdout.write('stdout-ok')",
43
- " process.stderr.write('stderr-ok')",
44
- '})',
45
- ].join(';'),
46
- ], options);
47
-
48
- let stdout = '';
49
- let stderr = '';
50
- child.stdout.setEncoding('utf8');
51
- child.stderr.setEncoding('utf8');
52
- child.stdout.on('data', (chunk) => { stdout += chunk; });
53
- child.stderr.on('data', (chunk) => { stderr += chunk; });
54
- child.stdin.end();
55
-
56
- const exit = await new Promise((resolve, reject) => {
57
- const timer = setTimeout(() => {
58
- child.kill();
59
- reject(new Error('captured child did not observe stdin EOF'));
60
- }, 10_000);
61
- child.once('error', (error) => {
62
- clearTimeout(timer);
63
- reject(error);
64
- });
65
- child.once('close', (code, signal) => {
66
- clearTimeout(timer);
67
- resolve({ code, signal });
68
- });
69
- });
70
-
71
- assert.deepEqual(exit, { code: 0, signal: null });
72
- assert.equal(stdout, 'stdout-ok');
73
- assert.equal(stderr, 'stderr-ok');
74
- }
75
-
76
- runCapturedProcessProbe().then(() => {
77
- process.stdout.write('shell-terminal-isolation-regression PASS\n');
78
- }).catch((error) => {
79
- console.error(error);
80
- process.exitCode = 1;
81
- });
@@ -1,89 +0,0 @@
1
- const assert = require('node:assert/strict');
2
- const fs = require('node:fs');
3
- const path = require('node:path');
4
-
5
- const packageRoot = path.resolve(__dirname, '..');
6
- const bundle = fs.readFileSync(path.join(packageRoot, 'blun.mjs'), 'utf8');
7
- const match = /editor\.onEscape = \(autocompleteCancelled = false\) => \{([\s\S]*?)\n\t\t\};\n\t\teditor\.onShiftTab =/.exec(bundle);
8
- assert(match, 'SLASH_ESCAPE_REGRESSION: editor.onEscape handler is missing');
9
-
10
- const runEscape = Function('host', 'editor', 'autocompleteCancelled', match[1]);
11
- const ctrlSMatch = /editor\.onCtrlS = \(\) => \{([\s\S]*?)\n\t\t\};\n\t\teditor\.onCtrlB =/.exec(bundle);
12
- assert(ctrlSMatch, 'SLASH_ESCAPE_REGRESSION: editor.onCtrlS handler is missing');
13
- const runCtrlS = Function('host', 'editor', ctrlSMatch[1]);
14
-
15
- function probe(initialText, autocompleteCancelled) {
16
- let text = initialText;
17
- const editor = {
18
- inputMode: 'prompt',
19
- getText: () => text,
20
- setText: (value) => { text = value; },
21
- };
22
- const host = {
23
- cancelInFlight: undefined,
24
- queueSteerInFlight: undefined,
25
- state: {
26
- activeDialog: null,
27
- appState: {
28
- isCompacting: false,
29
- streamingPhase: 'idle',
30
- },
31
- },
32
- streamingUI: { hasActiveTurn: () => false },
33
- btwPanelController: { closeOrCancel: () => false },
34
- };
35
- const controller = {
36
- pendingExit: null,
37
- pendingUndoEsc: null,
38
- clearPendingExit() {},
39
- clearPendingUndoEsc() {},
40
- armPendingUndoEsc() {},
41
- };
42
-
43
- runEscape.call(controller, host, editor, autocompleteCancelled);
44
- return text;
45
- }
46
-
47
- assert.equal(
48
- probe('/reload', true),
49
- '',
50
- 'SLASH_ESCAPE_REGRESSION: Escape must cancel the open slash-command draft together with its menu',
51
- );
52
- assert.equal(
53
- probe('ordinary draft', true),
54
- 'ordinary draft',
55
- 'SLASH_ESCAPE_REGRESSION: cancelling ordinary autocomplete must preserve the draft',
56
- );
57
-
58
- let flushed = null;
59
- const idleHost = {
60
- streamingUI: { hasActiveTurn: () => false },
61
- state: {
62
- appState: { streamingPhase: 'idle' },
63
- ui: { requestRender() {} },
64
- },
65
- flushQueuedMessages: (draft, mode) => { flushed = { draft, mode }; },
66
- updateQueueDisplay() {},
67
- };
68
- const slashEditor = {
69
- inputMode: 'prompt',
70
- getText: () => '/reload',
71
- };
72
- runCtrlS(idleHost, slashEditor);
73
- assert.deepEqual(
74
- flushed,
75
- { draft: '/reload', mode: 'prompt' },
76
- 'SLASH_ESCAPE_REGRESSION: Ctrl+S must hand an idle slash draft to the existing queue drain',
77
- );
78
- flushed = null;
79
- runCtrlS(idleHost, {
80
- inputMode: 'prompt',
81
- getText: () => 'ordinary draft',
82
- });
83
- assert.equal(
84
- flushed,
85
- null,
86
- 'SLASH_ESCAPE_REGRESSION: the existing idle behavior for ordinary drafts must stay unchanged',
87
- );
88
-
89
- console.log('slash-escape-regression PASS (Escape + Ctrl+S)');
@@ -1,24 +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 = process.env.BLUN_PACKAGE_UNDER_TEST
9
- ? path.resolve(process.env.BLUN_PACKAGE_UNDER_TEST)
10
- : path.resolve(__dirname, '..');
11
- const bundle = fs.readFileSync(path.join(packageRoot, 'blun.mjs'), 'utf8');
12
-
13
- for (const needle of [
14
- '.option("--swarm", "Start in swarm mode.", false)',
15
- 'swarm: raw["swarm"] === true,',
16
- 'thinking: startup.effort,',
17
- 'if (startup.effort !== void 0) await session.setThinking(startup.effort);',
18
- 'if (startup.swarm && !(await session.getStatus()).swarmMode) await session.setSwarmMode(true, "effort");',
19
- 'if (startup.swarm) this.setAppState({ swarmMode: true, swarmModeEntry: "effort" });',
20
- ]) {
21
- assert.ok(bundle.includes(needle), `startup swarm command wiring missing: ${needle}`);
22
- }
23
-
24
- process.stdout.write('startup-swarm-command-regression PASS\n');