blun-king-cli 9.1.536 → 9.1.550

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 (117) 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/context-performance-policy.cjs +2 -5
  5. package/bin/context-pressure-policy.cjs +20 -0
  6. package/bin/cron-run-output.cjs +45 -0
  7. package/bin/cron-run-store.cjs +145 -0
  8. package/bin/durable-task-resume-policy.cjs +130 -0
  9. package/bin/durable-task-resume-runtime.cjs +117 -0
  10. package/bin/durable-task-resume-store.cjs +88 -0
  11. package/bin/editable-tool-approval-policy.cjs +540 -0
  12. package/bin/editable-tool-approval-runtime.cjs +99 -0
  13. package/bin/html-to-research-markdown.cjs +146 -0
  14. package/bin/programmatic-tool-runtime.mjs +330 -4
  15. package/bin/read-continuation-policy.cjs +36 -5
  16. package/bin/scoped-cron-run-policy.cjs +358 -0
  17. package/bin/startup-preferences.cjs +3 -3
  18. package/bin/structured-agent-swarm-output.cjs +325 -0
  19. package/bin/subagent-context-fork-policy.cjs +155 -0
  20. package/bin/subagent-skill-policy.cjs +204 -0
  21. package/bin/telegram-approval-relay.cjs +2 -1
  22. package/bin/tool-result-offload-policy.cjs +14 -1
  23. package/bin/update-notice.js +14 -18
  24. package/bin/user-message-offload-policy.cjs +3 -1
  25. package/blun.mjs +1089 -477
  26. package/codebase-index/README.md +12 -0
  27. package/codebase-index/codebase_index.py +129 -18
  28. package/package.json +23 -58
  29. package/telegram-plugin/bin/telegram-typing-keepalive.cjs +89 -0
  30. package/telegram-plugin/dist/bridge.mjs +8 -1
  31. package/CHANGELOG.md +0 -321
  32. package/agent-spine-plugin/CHANGELOG.md +0 -406
  33. package/agent-spine-plugin/CONTRIBUTING.md +0 -52
  34. package/agent-spine-plugin/README.md +0 -344
  35. package/agent-spine-plugin/SECURITY.md +0 -47
  36. package/agent-spine-plugin/docs/acceptance.md +0 -61
  37. package/agent-spine-plugin/docs/architecture.md +0 -183
  38. package/agent-spine-plugin/docs/attention.md +0 -121
  39. package/agent-spine-plugin/docs/automatic-continuity.md +0 -79
  40. package/agent-spine-plugin/docs/channel-runtime.md +0 -92
  41. package/agent-spine-plugin/docs/coordination.md +0 -138
  42. package/agent-spine-plugin/docs/feed-transport.md +0 -99
  43. package/agent-spine-plugin/docs/gateway-runtime.md +0 -116
  44. package/agent-spine-plugin/docs/harness-reference.md +0 -45
  45. package/agent-spine-plugin/docs/host-integration.md +0 -129
  46. package/agent-spine-plugin/docs/https-transport.md +0 -116
  47. package/agent-spine-plugin/docs/learning.md +0 -133
  48. package/agent-spine-plugin/docs/object-transport.md +0 -93
  49. package/agent-spine-plugin/docs/peer-transport.md +0 -88
  50. package/agent-spine-plugin/docs/preflight-recall.md +0 -69
  51. package/agent-spine-plugin/docs/preservation-contract.md +0 -53
  52. package/agent-spine-plugin/docs/quality-gates.md +0 -50
  53. package/agent-spine-plugin/docs/relationships.md +0 -73
  54. package/agent-spine-plugin/docs/releasing.md +0 -83
  55. package/agent-spine-plugin/docs/roadmap.md +0 -307
  56. package/agent-spine-plugin/docs/selfstarter.md +0 -88
  57. package/agent-spine-plugin/docs/session-briefing.md +0 -74
  58. package/agent-spine-plugin/docs/shared-memory.md +0 -259
  59. package/agent-spine-plugin/docs/source-roots.md +0 -86
  60. package/agent-spine-plugin/docs/sqlite-transport.md +0 -76
  61. package/agent-spine-plugin/scripts/check-hosts.js +0 -195
  62. package/agent-spine-plugin/scripts/check-install.js +0 -569
  63. package/agent-spine-plugin/scripts/check-syntax.js +0 -29
  64. package/agent-spine-plugin/scripts/github-actions.js +0 -11
  65. package/agent-spine-plugin/scripts/release-check.js +0 -128
  66. package/agent-spine-plugin/scripts/run-acceptance.js +0 -19
  67. package/agent-spine-plugin/scripts/run-checks.js +0 -46
  68. package/agent-spine-plugin/scripts/run-tests-hermetic.js +0 -73
  69. package/agent-spine-plugin/spine-example/1-identity.md +0 -12
  70. package/agent-spine-plugin/spine-example/2-voice.md +0 -6
  71. package/agent-spine-plugin/spine-example/3-conduct.md +0 -8
  72. package/agent-spine-plugin/spine-example/4-history.md +0 -4
  73. package/bin/fredrik-glm-provider.cjs +0 -256
  74. package/bin/package-regression-policy.cjs +0 -77
  75. package/fredrik-glm-profile.toml.example +0 -26
  76. package/release-planned-removals.json +0 -15
  77. package/scripts/check-active-profile-plugin-startup.js +0 -36
  78. package/scripts/check-active-work-steer-regression.js +0 -46
  79. package/scripts/check-approval-observability-regression.js +0 -111
  80. package/scripts/check-approval-queue-shortcuts-regression.js +0 -65
  81. package/scripts/check-bundled-agent-spine-regression.js +0 -48
  82. package/scripts/check-codebase-search-packaging-regression.js +0 -92
  83. package/scripts/check-copy-command-regression.js +0 -74
  84. package/scripts/check-current-turn-read-pin-mutation-regression.js +0 -72
  85. package/scripts/check-current-turn-read-pin-regression.js +0 -94
  86. package/scripts/check-deepseek-native-max-regression.js +0 -49
  87. package/scripts/check-empty-response-effort-downgrade-regression.js +0 -48
  88. package/scripts/check-fredrik-glm-mutation-regression.js +0 -18
  89. package/scripts/check-fredrik-glm-regression.js +0 -169
  90. package/scripts/check-historical-tool-result-preview-regression.js +0 -77
  91. package/scripts/check-history-pressure-offload-regression.js +0 -77
  92. package/scripts/check-mcp-startup-wait-budget.js +0 -48
  93. package/scripts/check-package-regression.js +0 -38
  94. package/scripts/check-plugin-startup-regression.js +0 -53
  95. package/scripts/check-programmatic-context-isolation-regression.js +0 -193
  96. package/scripts/check-programmatic-tool-regression.js +0 -294
  97. package/scripts/check-queue-controls-regression.js +0 -189
  98. package/scripts/check-release-metadata.js +0 -103
  99. package/scripts/check-reload-agent-spine-regression.js +0 -76
  100. package/scripts/check-resume-replay-regression.js +0 -102
  101. package/scripts/check-session-cancel-regression.js +0 -43
  102. package/scripts/check-session-picker-resume-metrics-regression.js +0 -97
  103. package/scripts/check-session-start-hook-context-regression.js +0 -228
  104. package/scripts/check-shell-terminal-isolation-regression.js +0 -81
  105. package/scripts/check-slash-escape-regression.js +0 -89
  106. package/scripts/check-startup-swarm-command-regression.js +0 -24
  107. package/scripts/check-structured-subagent-output-regression.js +0 -331
  108. package/scripts/check-telegram-bridge-watchdog.js +0 -60
  109. package/scripts/check-telegram-direct-work-resume-regression.js +0 -53
  110. package/scripts/check-telegram-loop-exactly-once-regression.js +0 -71
  111. package/scripts/check-todo-loop-regression.js +0 -78
  112. package/scripts/check-todo-progress-regression.js +0 -416
  113. package/scripts/check-todo-recovery-catalog-regression.js +0 -50
  114. package/scripts/check-tool-schema-capacity-regression.js +0 -40
  115. package/scripts/programmatic-tool-runtime.test.mjs +0 -365
  116. package/scripts/structured-subagent-output.test.cjs +0 -170
  117. /package/{scripts → bin}/fix-node-pty-perms.js +0 -0
@@ -1,71 +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.resolve(process.env.BLUN_BUNDLE_UNDER_TEST)
7
- : path.join(__dirname, '..', 'blun.mjs');
8
- const bundle = fs.readFileSync(bundlePath, 'utf8');
9
- const match = /async function handleLoopCommand\(host, args\) \{([\s\S]*?)\n\}\nfunction hasRunnableSession/.exec(bundle);
10
- assert(match, 'TELEGRAM_LOOP_EXACTLY_ONCE: handleLoopCommand is missing');
11
-
12
- const handleLoopCommand = Function(
13
- 'parseLoopCommand',
14
- 'hasRunnableSession',
15
- 'llmNotSetMessage',
16
- 'isStreaming',
17
- `return async function handleLoopCommand(host, args) {${match[1]}\n};`,
18
- )(
19
- () => ({ kind: 'create', interval: '*/5 * * * *', prompt: 'work once' }),
20
- () => true,
21
- () => 'missing model',
22
- (host) => host.streaming,
23
- );
24
-
25
- function createHost({ telegram = false, streaming = true } = {}) {
26
- const calls = { send: [], enqueue: [] };
27
- const session = {
28
- async createLoop({ interval, prompt }) {
29
- return { interval, prompt, status: 'active' };
30
- },
31
- };
32
- const host = {
33
- streaming,
34
- session,
35
- telegramRemoteCommandContext: telegram ? { item: { telegramCommandName: 'loop' } } : undefined,
36
- state: { appState: { isCompacting: false, model: 'blun/king' } },
37
- requireSession() { return session; },
38
- setAppState() {},
39
- track() {},
40
- showStatus() {},
41
- showError(message) { throw new Error(message); },
42
- sendNormalUserInput(text) { calls.send.push(text); },
43
- enqueueNormalUserInput(text) { calls.enqueue.push(text); },
44
- };
45
- return { host, calls };
46
- }
47
-
48
- (async () => {
49
- const telegram = createHost({ telegram: true, streaming: true });
50
- await handleLoopCommand(telegram.host, '5 min work once');
51
- assert.deepEqual(telegram.calls.send, ['work once']);
52
- assert.deepEqual(
53
- telegram.calls.enqueue,
54
- [],
55
- 'TELEGRAM_LOOP_EXACTLY_ONCE: Telegram loop payload must not survive in the normal queue',
56
- );
57
-
58
- const local = createHost({ telegram: false, streaming: true });
59
- await handleLoopCommand(local.host, '5 min work once');
60
- assert.deepEqual(local.calls.send, []);
61
- assert.deepEqual(
62
- local.calls.enqueue,
63
- ['work once'],
64
- 'TELEGRAM_LOOP_EXACTLY_ONCE: local busy-loop behavior must stay queued',
65
- );
66
-
67
- console.log('telegram-loop-exactly-once-regression PASS');
68
- })().catch((error) => {
69
- console.error(error);
70
- process.exitCode = 1;
71
- });
@@ -1,78 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const fs = require('node:fs');
5
- const path = require('node:path');
6
- const { enforceSingleTodoWritePerStep } = require('../bin/todo-list-turn-policy.cjs');
7
-
8
- const bundlePath = process.env.BLUN_BUNDLE_UNDER_TEST
9
- ? path.resolve(process.env.BLUN_BUNDLE_UNDER_TEST)
10
- : path.resolve(__dirname, '..', 'blun.mjs');
11
- const bundle = fs.readFileSync(bundlePath, 'utf8');
12
-
13
- function assert(condition, message) {
14
- if (!condition) throw new Error(message);
15
- }
16
-
17
- assert(
18
- !bundle.includes('TodoList is unchanged after extended work'),
19
- 'TODO_LOOP_REGRESSION: unchanged truthful TodoList refreshes must remain accepted',
20
- );
21
- assert(
22
- !/isIdle:\s*\(task\)\s*=>[\s\S]{0,240}owner\s*!==\s*["']session-loop["']/.test(bundle),
23
- 'TODO_LOOP_REGRESSION: unfinished TodoList work must not suppress an idle session loop',
24
- );
25
- assert(
26
- /isIdle:\s*\(\)\s*=>\s*!agent\.turn\.hasActiveTurn/.test(bundle),
27
- 'TODO_LOOP_REGRESSION: expected idle-only session loop scheduler wiring is missing',
28
- );
29
- assert(
30
- /todos\.filter\(\(todo\)\s*=>\s*todo\.status\s*!==\s*["']done["']\)/.test(bundle),
31
- 'TODO_LIFECYCLE_REGRESSION: completed items must be pruned from the stored visible list',
32
- );
33
- assert(
34
- /const PENDING_TEXT\s*=\s*["']#aeb8c6["']/.test(bundle)
35
- && !/const PENDING_TEXT\s*=\s*["']#2a3550["']/.test(bundle),
36
- 'TODO_UI_REGRESSION: pending markers must remain visible on ANSI16 terminals',
37
- );
38
- assert(
39
- /activeGoal\s*===\s*null\s*&&\s*!startsTrackedList/.test(bundle)
40
- && /The first TodoList must contain at least one item, exactly one in_progress item/.test(bundle),
41
- 'TODO_INITIAL_STATE_REGRESSION: a new non-goal TodoList must not accept an all-pending list',
42
- );
43
- assert(
44
- /enforceSingleTodoWritePerStep\(ctx\)/.test(bundle),
45
- 'TODO_PARALLEL_REGRESSION: per-step TodoList write guard is not wired',
46
- );
47
-
48
- const calls = [
49
- { id: 'todo-first', name: 'TodoList' },
50
- { id: 'todo-second', name: 'TodoList' },
51
- ];
52
- assert(
53
- enforceSingleTodoWritePerStep({
54
- toolCall: calls[0],
55
- toolCalls: calls,
56
- args: { todos: [{ title: 'first', status: 'in_progress' }] },
57
- }) === undefined,
58
- 'TODO_PARALLEL_REGRESSION: first TodoList write must remain executable',
59
- );
60
- const duplicateWrite = enforceSingleTodoWritePerStep({
61
- toolCall: calls[1],
62
- toolCalls: calls,
63
- args: { todos: [{ title: 'second', status: 'in_progress' }] },
64
- });
65
- assert(
66
- duplicateWrite?.block === true,
67
- 'TODO_PARALLEL_REGRESSION: later TodoList writes in the same step must be blocked',
68
- );
69
- assert(
70
- enforceSingleTodoWritePerStep({
71
- toolCall: { id: 'todo-read', name: 'TodoList' },
72
- toolCalls: calls,
73
- args: {},
74
- }) === undefined,
75
- 'TODO_PARALLEL_REGRESSION: read-only TodoList queries must not be blocked',
76
- );
77
-
78
- process.stdout.write('todo-loop-regression PASS\n');
@@ -1,416 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const assert = require('node:assert/strict');
5
- const { spawnSync } = require('node:child_process');
6
- const fs = require('node:fs');
7
- const os = require('node:os');
8
- const path = require('node:path');
9
-
10
- const packageRoot = path.resolve(__dirname, '..');
11
- const bundlePath = process.env.BLUN_TODO_PROGRESS_BUNDLE_UNDER_TEST
12
- ? path.resolve(process.env.BLUN_TODO_PROGRESS_BUNDLE_UNDER_TEST)
13
- : path.join(packageRoot, 'blun.mjs');
14
- const bundle = fs.readFileSync(bundlePath, 'utf8');
15
-
16
- const policyPath = process.env.BLUN_TODO_PROGRESS_POLICY_UNDER_TEST
17
- ? path.resolve(process.env.BLUN_TODO_PROGRESS_POLICY_UNDER_TEST)
18
- : path.join(packageRoot, 'bin', 'todo-list-turn-policy.cjs');
19
-
20
- const {
21
- MAX_TODO_ITEMS,
22
- assessTodoListBounds,
23
- assessTodoMaintenanceUpdate,
24
- canonicalStoredTodos,
25
- } = require(policyPath);
26
- const { normalizeTodoProgressState } = require(path.join(
27
- packageRoot,
28
- 'bin',
29
- 'agent-resume-snapshot.cjs',
30
- ));
31
-
32
- function todos(count, status = 'pending') {
33
- return Array.from({ length: count }, (_, index) => ({
34
- title: `Task ${String(index + 1)}`,
35
- status: index === 0 && status === 'pending' ? 'in_progress' : status,
36
- }));
37
- }
38
-
39
- function between(startNeedle, endNeedle) {
40
- const start = bundle.indexOf(startNeedle);
41
- assert.notEqual(start, -1, `TODO_PROGRESS: missing bundle start ${startNeedle}`);
42
- const end = bundle.indexOf(endNeedle, start + startNeedle.length);
43
- assert.notEqual(end, -1, `TODO_PROGRESS: missing bundle end ${endNeedle}`);
44
- return bundle.slice(start, end);
45
- }
46
-
47
- function extractFunction(name) {
48
- const start = bundle.indexOf(`function ${name}(`);
49
- assert.notEqual(start, -1, `TODO_PROGRESS: missing function ${name}`);
50
- const open = bundle.indexOf('{', start);
51
- let depth = 0;
52
- for (let index = open; index < bundle.length; index += 1) {
53
- if (bundle[index] === '{') depth += 1;
54
- if (bundle[index] === '}') depth -= 1;
55
- if (depth === 0) return bundle.slice(start, index + 1);
56
- }
57
- assert.fail(`TODO_PROGRESS: incomplete function ${name}`);
58
- }
59
-
60
- function assertBundleContract() {
61
- assert.match(
62
- bundle,
63
- /\(\{ assessTodoListBounds, assessTodoMaintenanceUpdate, enforceSingleTodoWritePerStep, todoRefreshWorkCallLimit \} = createRequire\(import\.meta\.url\)\("\.\/bin\/todo-list-turn-policy\.cjs"\)\);/u,
64
- 'TODO_PROGRESS: bundle must import every progress-policy helper',
65
- );
66
- const prepare = between('prepareToolExecution: async (ctx) => {', 'authorizeToolExecution: async (ctx) => {');
67
- const boundsIndex = prepare.indexOf('enforceTodoListBounds(this.agent, ctx)');
68
- const goalIndex = prepare.indexOf('enforceGoalTodoPolicy(this.agent, ctx)');
69
- assert.ok(boundsIndex >= 0 && goalIndex > boundsIndex, 'TODO_PROGRESS: bounds must run before goal/idea exceptions');
70
-
71
- const evidence = between('function recordGoalTodoEvidence(', 'function goalTodoMaintenanceMode(');
72
- assert.doesNotMatch(
73
- evidence,
74
- /name === "TodoList"[\s\S]*recentEvidence = \[\]/u,
75
- 'TODO_PROGRESS: a successful unchanged refresh must not erase its evidence in finalize',
76
- );
77
- assert.match(evidence, /progress\.evidenceRevision = \(Number\(progress\.evidenceRevision\) \|\| 0\) \+ 1/u);
78
-
79
- const mode = between('function goalTodoMaintenanceMode(', 'function goalTodoMaintenanceTools(');
80
- assert.match(mode, /todoRefreshWorkCallLimit\(progress\.unchangedRefreshStreak\)/u);
81
-
82
- const enforcement = between('function enforceGoalTodoPolicy(', 'function ideaOutboundChannel(');
83
- assert.match(enforcement, /assessTodoMaintenanceUpdate\(\{/u);
84
- assert.match(enforcement, /code: "todo-maintenance-stalled"/u);
85
- assert.match(enforcement, /if \(!maintenanceUpdate\.preserveRecentEvidence\) progress\.recentEvidence = \[\]/u);
86
- assert.match(enforcement, /todoRefreshWorkCallLimit\(progress\.unchangedRefreshStreak\)/u);
87
- assert.doesNotMatch(bundle, /const GOAL_TODO_REFRESH_WORK_CALL_LIMIT = 8/u);
88
- assert.doesNotMatch(bundle, /TodoList is unchanged after extended work/u);
89
- assert.match(bundle, /If no boundary is proven, preserve the list unchanged; never invent progress\./u);
90
-
91
- const resumeSource = fs.readFileSync(
92
- path.join(packageRoot, 'bin', 'agent-resume-snapshot.cjs'),
93
- 'utf8',
94
- );
95
- assert.match(resumeSource, /todoProgress: normalizeTodoProgressState\(agent\.goalTodoPolicyState\) \?\? null/u);
96
- assert.match(resumeSource, /agent\.goalTodoPolicyState = normalizeTodoProgressState\(snapshot\.todoProgress\)/u);
97
- }
98
-
99
- function exerciseBundledPolicy() {
100
- const ideaTodos = (agent) => agent.tools.store.todo ?? [];
101
- const goalTodoProgressState = Function(
102
- `"use strict"; return (${extractFunction('goalTodoProgressState')});`,
103
- )();
104
- const enforceTodoListBounds = Function(
105
- 'assessTodoListBounds',
106
- 'ideaTodos',
107
- `"use strict"; return (${extractFunction('enforceTodoListBounds')});`,
108
- )(assessTodoListBounds, ideaTodos);
109
- const enforceGoalTodoPolicy = Function(
110
- 'isIdeaGoal',
111
- 'TELEGRAM_DELIVERY_TOOL_RE',
112
- 'ideaTodos',
113
- 'goalTodoProgressState',
114
- 'validInitialIdeaPlan',
115
- 'IDEA_TERMINAL_TODO_STATUSES',
116
- 'assessTodoMaintenanceUpdate',
117
- 'todoRefreshWorkCallLimit',
118
- `"use strict"; return (${extractFunction('enforceGoalTodoPolicy')});`,
119
- )(
120
- () => false,
121
- /^mcp__[^\s]*telegram[^\s]*__(?:reply|edit_message)$/iu,
122
- ideaTodos,
123
- goalTodoProgressState,
124
- () => true,
125
- Object.freeze(['done', 'blocked', 'waiting_approval', 'aborted']),
126
- assessTodoMaintenanceUpdate,
127
- require(policyPath).todoRefreshWorkCallLimit,
128
- );
129
- const goalTodoMaintenanceMode = Function(
130
- 'isIdeaGoal',
131
- 'ideaTodos',
132
- 'goalTodoProgressState',
133
- 'todoRefreshWorkCallLimit',
134
- `"use strict"; return (${extractFunction('goalTodoMaintenanceMode')});`,
135
- )(
136
- () => false,
137
- ideaTodos,
138
- goalTodoProgressState,
139
- require(policyPath).todoRefreshWorkCallLimit,
140
- );
141
-
142
- const emitted = [];
143
- const agent = {
144
- tools: { store: { todo: current.map((todo) => ({ ...todo })) } },
145
- goal: { getActiveGoal: () => ({ objective: 'exercise policy' }) },
146
- goalTodoPolicyState: {
147
- workCallsSinceRefresh: 8,
148
- refreshRequired: true,
149
- unchangedRefreshStreak: 2,
150
- recentEvidence: ['Bash succeeded: candidate.js'],
151
- evidenceRevision: 4,
152
- lastMaintenanceEvidenceRevision: 3,
153
- },
154
- emitEvent(event) { emitted.push(event); },
155
- };
156
- const unchangedContext = {
157
- toolCall: { id: 'todo-1', name: 'TodoList' },
158
- toolCalls: [{ id: 'todo-1', name: 'TodoList' }],
159
- args: { todos: current.map((todo) => ({ ...todo })) },
160
- };
161
- assert.equal(enforceTodoListBounds(agent, unchangedContext), undefined);
162
- assert.equal(enforceGoalTodoPolicy(agent, unchangedContext), undefined);
163
- assert.equal(agent.goalTodoPolicyState.unchangedRefreshStreak, 3);
164
- assert.deepEqual(agent.goalTodoPolicyState.recentEvidence, ['Bash succeeded: candidate.js']);
165
- assert.equal(agent.goalTodoPolicyState.workCallsSinceRefresh, 0);
166
- assert.equal(agent.goalTodoPolicyState.refreshRequired, false);
167
- assert.equal(emitted.length, 1);
168
- assert.equal(emitted[0].code, 'todo-maintenance-stalled');
169
- assert.equal(emitted[0].blocked, false);
170
-
171
- agent.goalTodoPolicyState.workCallsSinceRefresh = 63;
172
- assert.equal(goalTodoMaintenanceMode(agent), null, '64-call backoff must leave work available');
173
- agent.goalTodoPolicyState.workCallsSinceRefresh = 64;
174
- assert.equal(goalTodoMaintenanceMode(agent), 'refresh');
175
-
176
- agent.goalTodoPolicyState.recentEvidence = ['Write succeeded: candidate.js'];
177
- agent.goalTodoPolicyState.evidenceRevision = 5;
178
- const changedContext = {
179
- ...unchangedContext,
180
- toolCall: { id: 'todo-2', name: 'TodoList' },
181
- toolCalls: [{ id: 'todo-2', name: 'TodoList' }],
182
- args: {
183
- todos: [
184
- { title: 'Measure source', status: 'done' },
185
- { title: 'Write candidate', status: 'in_progress' },
186
- ],
187
- },
188
- };
189
- assert.equal(enforceGoalTodoPolicy(agent, changedContext), undefined);
190
- assert.equal(agent.goalTodoPolicyState.unchangedRefreshStreak, 0);
191
- assert.deepEqual(agent.goalTodoPolicyState.recentEvidence, []);
192
-
193
- const oversizedAgent = {
194
- tools: { store: { todo: [] } },
195
- };
196
- const oversized = enforceTodoListBounds(oversizedAgent, {
197
- toolCall: { name: 'TodoList' },
198
- args: { todos: todos(33) },
199
- });
200
- assert.equal(oversized.block, true);
201
- assert.match(oversized.reason, /at most 32 visible items/u);
202
- }
203
-
204
- assert.equal(MAX_TODO_ITEMS, 32, 'TODO_PROGRESS: visible list cap must be 32');
205
-
206
- const current = [
207
- { title: 'Measure source', status: 'in_progress' },
208
- { title: 'Write candidate', status: 'pending' },
209
- ];
210
-
211
- const unchangedOne = assessTodoMaintenanceUpdate({
212
- currentTodos: current,
213
- nextTodos: current,
214
- unchangedRefreshStreak: 0,
215
- recentEvidenceCount: 8,
216
- });
217
- assert.deepEqual(unchangedOne, {
218
- changed: false,
219
- unchangedRefreshStreak: 1,
220
- refreshWorkCallLimit: 16,
221
- preserveRecentEvidence: true,
222
- requireConcreteProgress: false,
223
- emitStalledWarning: false,
224
- });
225
-
226
- const unchangedTwo = assessTodoMaintenanceUpdate({
227
- currentTodos: current,
228
- nextTodos: current,
229
- unchangedRefreshStreak: unchangedOne.unchangedRefreshStreak,
230
- recentEvidenceCount: 8,
231
- });
232
- assert.equal(unchangedTwo.changed, false);
233
- assert.equal(unchangedTwo.unchangedRefreshStreak, 2);
234
- assert.equal(unchangedTwo.refreshWorkCallLimit, 32);
235
- assert.equal(unchangedTwo.preserveRecentEvidence, true);
236
- assert.equal(unchangedTwo.requireConcreteProgress, true);
237
- assert.equal(unchangedTwo.emitStalledWarning, false);
238
-
239
- const unchangedThree = assessTodoMaintenanceUpdate({
240
- currentTodos: current,
241
- nextTodos: current,
242
- unchangedRefreshStreak: unchangedTwo.unchangedRefreshStreak,
243
- recentEvidenceCount: 8,
244
- });
245
- assert.equal(unchangedThree.unchangedRefreshStreak, 3);
246
- assert.equal(unchangedThree.refreshWorkCallLimit, 64);
247
- assert.equal(unchangedThree.requireConcreteProgress, true);
248
- assert.equal(unchangedThree.emitStalledWarning, true);
249
-
250
- const unchangedWithoutEvidence = assessTodoMaintenanceUpdate({
251
- currentTodos: current,
252
- nextTodos: current,
253
- unchangedRefreshStreak: 2,
254
- recentEvidenceCount: 0,
255
- });
256
- assert.equal(unchangedWithoutEvidence.unchangedRefreshStreak, 2);
257
- assert.equal(unchangedWithoutEvidence.preserveRecentEvidence, true);
258
- assert.equal(unchangedWithoutEvidence.emitStalledWarning, false);
259
-
260
- const changed = assessTodoMaintenanceUpdate({
261
- currentTodos: current,
262
- nextTodos: [
263
- { title: 'Measure source', status: 'done' },
264
- { title: 'Write candidate', status: 'in_progress' },
265
- ],
266
- unchangedRefreshStreak: 3,
267
- recentEvidenceCount: 8,
268
- });
269
- assert.deepEqual(changed, {
270
- changed: true,
271
- unchangedRefreshStreak: 0,
272
- refreshWorkCallLimit: 8,
273
- preserveRecentEvidence: false,
274
- requireConcreteProgress: false,
275
- emitStalledWarning: false,
276
- });
277
- assert.deepEqual(canonicalStoredTodos([
278
- { title: 'Measure source', status: 'done' },
279
- { title: 'Write candidate', status: 'in_progress' },
280
- ]), [{ title: 'Write candidate', status: 'in_progress' }]);
281
-
282
- assert.equal(assessTodoListBounds({ currentTodos: [], nextTodos: todos(32) }), undefined);
283
- assert.match(
284
- assessTodoListBounds({ currentTodos: [], nextTodos: todos(33) }).reason,
285
- /at most 32 visible items/,
286
- );
287
-
288
- const legacy = todos(47);
289
- assert.equal(
290
- assessTodoListBounds({ currentTodos: legacy, nextTodos: legacy }),
291
- undefined,
292
- 'TODO_PROGRESS: unchanged legacy lists must not deadlock',
293
- );
294
- assert.match(
295
- assessTodoListBounds({ currentTodos: legacy, nextTodos: legacy.slice(0, 46) }).reason,
296
- /may remove an unresolved legacy item only by submitting it as done/,
297
- );
298
- const legacyWithDone = legacy.map((todo, index) => index === 46
299
- ? { ...todo, status: 'done' }
300
- : todo);
301
- assert.equal(
302
- assessTodoListBounds({ currentTodos: legacy, nextTodos: legacyWithDone }),
303
- undefined,
304
- 'TODO_PROGRESS: explicit done pruning must shrink an oversized legacy list',
305
- );
306
- const legacyShrunkAndRenamed = legacyWithDone.map((todo, index) => index === 0
307
- ? { ...todo, title: 'Replacement task' }
308
- : todo);
309
- assert.match(
310
- assessTodoListBounds({ currentTodos: legacy, nextTodos: legacyShrunkAndRenamed }).reason,
311
- /Do not add, omit, or rename items/,
312
- 'TODO_PROGRESS: crossing the cap must not bypass legacy identity checks',
313
- );
314
-
315
- assertBundleContract();
316
- exerciseBundledPolicy();
317
-
318
- assert.deepEqual(normalizeTodoProgressState({
319
- workCallsSinceRefresh: 64,
320
- refreshRequired: true,
321
- unchangedRefreshStreak: 3,
322
- recentEvidence: Array.from({ length: 10 }, (_, index) => `evidence-${String(index)}`),
323
- evidenceRevision: 12,
324
- lastMaintenanceEvidenceRevision: 11,
325
- allVisibleWorkCompleted: false,
326
- }), {
327
- workCallsSinceRefresh: 64,
328
- refreshRequired: true,
329
- unchangedRefreshStreak: 3,
330
- recentEvidence: Array.from({ length: 8 }, (_, index) => `evidence-${String(index + 2)}`),
331
- evidenceRevision: 12,
332
- lastMaintenanceEvidenceRevision: 11,
333
- allVisibleWorkCompleted: false,
334
- });
335
- assert.equal(normalizeTodoProgressState(undefined), undefined);
336
-
337
- if (process.env.BLUN_TODO_PROGRESS_SKIP_MUTATIONS !== '1') {
338
- const originalPolicy = fs.readFileSync(policyPath, 'utf8');
339
- const policyMutations = [
340
- ['cap', 'const MAX_TODO_ITEMS = 32;', 'const MAX_TODO_ITEMS = 33;'],
341
- ['unchanged-progress', ')\n !== semanticTodoFingerprint(input?.nextTodos);', ')\n === semanticTodoFingerprint(input?.nextTodos);'],
342
- ['concrete-progress', 'requireConcreteProgress: unchangedRefreshStreak >= 2,', 'requireConcreteProgress: unchangedRefreshStreak >= 99,'],
343
- ['stalled-warning', 'unchangedRefreshStreak === TODO_STALLED_WARNING_STREAK,', 'unchangedRefreshStreak === 99,'],
344
- ];
345
- const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'blun-todo-progress-mutations-'));
346
- try {
347
- for (const [name, needle, replacement] of policyMutations) {
348
- assert.ok(originalPolicy.includes(needle), `TODO_PROGRESS: mutation anchor missing: ${name}`);
349
- const mutatedPath = path.join(tempRoot, `${name}.cjs`);
350
- fs.writeFileSync(mutatedPath, originalPolicy.replace(needle, replacement), 'utf8');
351
- const result = spawnSync(process.execPath, [__filename], {
352
- encoding: 'utf8',
353
- env: {
354
- ...process.env,
355
- BLUN_TODO_PROGRESS_POLICY_UNDER_TEST: mutatedPath,
356
- BLUN_TODO_PROGRESS_SKIP_MUTATIONS: '1',
357
- },
358
- windowsHide: true,
359
- });
360
- assert.notEqual(
361
- result.status,
362
- 0,
363
- `TODO_PROGRESS: ${name} mutation survived the regression gate`,
364
- );
365
- }
366
-
367
- const bundleMutations = [
368
- [
369
- 'bounds-wiring',
370
- '\t\t\t\t\t\t\t\tconst todoBoundsPolicy = enforceTodoListBounds(this.agent, ctx);\n\t\t\t\t\t\t\t\tif (todoBoundsPolicy !== void 0) return todoBoundsPolicy;\n',
371
- '',
372
- __filename,
373
- ],
374
- [
375
- 'done-pruning',
376
- 'todos.filter((todo) => todo.status !== "done")',
377
- 'todos.filter((todo) => todo.status !== "never_done")',
378
- path.join(__dirname, 'check-todo-loop-regression.js'),
379
- ],
380
- [
381
- 'recovery-catalog',
382
- '\t"Bash"\n]);',
383
- '\t"WebSearch"\n]);',
384
- path.join(__dirname, 'check-todo-recovery-catalog-regression.js'),
385
- ],
386
- ];
387
- for (const [name, needle, replacement, gatePath] of bundleMutations) {
388
- assert.ok(bundle.includes(needle), `TODO_PROGRESS: bundle mutation anchor missing: ${name}`);
389
- const mutatedPath = path.join(tempRoot, `${name}.mjs`);
390
- fs.writeFileSync(mutatedPath, bundle.replace(needle, replacement), 'utf8');
391
- const gateIsSelf = gatePath === __filename;
392
- const result = spawnSync(process.execPath, [gatePath], {
393
- encoding: 'utf8',
394
- env: {
395
- ...process.env,
396
- ...(gateIsSelf
397
- ? {
398
- BLUN_TODO_PROGRESS_BUNDLE_UNDER_TEST: mutatedPath,
399
- BLUN_TODO_PROGRESS_SKIP_MUTATIONS: '1',
400
- }
401
- : { BLUN_BUNDLE_UNDER_TEST: mutatedPath }),
402
- },
403
- windowsHide: true,
404
- });
405
- assert.notEqual(
406
- result.status,
407
- 0,
408
- `TODO_PROGRESS: ${name} bundle mutation survived its regression gate`,
409
- );
410
- }
411
- } finally {
412
- fs.rmSync(tempRoot, { recursive: true, force: true });
413
- }
414
- }
415
-
416
- process.stdout.write('todo-progress-regression PASS (bundle + 7 mutations)\n');
@@ -1,50 +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 bundlePath = process.env.BLUN_BUNDLE_UNDER_TEST
8
- ? path.resolve(process.env.BLUN_BUNDLE_UNDER_TEST)
9
- : path.resolve(__dirname, '..', 'blun.mjs');
10
- const bundle = fs.readFileSync(bundlePath, 'utf8');
11
-
12
- function assert(condition, message) {
13
- if (!condition) throw new Error(message);
14
- }
15
-
16
- const namesMatch = bundle.match(
17
- /const TODO_MAINTENANCE_RECOVERY_TOOL_NAMES = new Set\(\[([\s\S]*?)\]\);/,
18
- );
19
- const functionMatch = bundle.match(
20
- /function goalTodoMaintenanceTools\(eligibleTools, selectedTools\) \{[\s\S]*?\n\}/,
21
- );
22
-
23
- assert(
24
- !/proactive TodoList maintenance step[\s\S]{0,900}tools:\s*\[todoTool\]/.test(bundle),
25
- 'TODO_RECOVERY_CATALOG_REGRESSION: proactive maintenance still switches to TodoList-only',
26
- );
27
- assert(namesMatch, 'TODO_RECOVERY_CATALOG_REGRESSION: recovery tool names are missing');
28
- assert(functionMatch, 'TODO_RECOVERY_CATALOG_REGRESSION: recovery catalogue selector is missing');
29
- assert(
30
- /proactive TodoList maintenance step[\s\S]{0,1100}tools:\s*todoMaintenanceTools/.test(bundle),
31
- 'TODO_RECOVERY_CATALOG_REGRESSION: proactive maintenance is not wired to the recovery catalogue',
32
- );
33
-
34
- const selectMaintenanceTools = Function(
35
- `const TODO_MAINTENANCE_RECOVERY_TOOL_NAMES = new Set([${namesMatch[1]}]); return (${functionMatch[0]});`,
36
- )();
37
- const tools = ['TodoList', 'Read', 'Write', 'Edit', 'Bash', 'WebSearch'].map((name) => ({ name }));
38
- const selected = [tools[5], tools[1]];
39
- const actual = selectMaintenanceTools(tools, selected).map((tool) => tool.name);
40
-
41
- assert(
42
- actual.join(',') === 'WebSearch,Read,TodoList,Write,Edit,Bash',
43
- `TODO_RECOVERY_CATALOG_REGRESSION: unexpected catalogue ${actual.join(',')}`,
44
- );
45
- assert(
46
- new Set(actual).size === actual.length,
47
- 'TODO_RECOVERY_CATALOG_REGRESSION: recovery catalogue contains duplicates',
48
- );
49
-
50
- process.stdout.write('todo-recovery-catalog-regression PASS\n');
@@ -1,40 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const assert = require('node:assert/strict');
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-tool-performance-policy.cjs'));
11
-
12
- assert.equal(policy.TOOL_SCHEMA_BUDGET_RATIO, 0.35);
13
- assert.equal(policy.TOOL_SCHEMA_MAX_TOKENS, 64_000);
14
- assert.equal(policy.MAX_PERSISTENT_DEFERRED_TOOLS, 12);
15
- assert.equal(policy.MAX_AUTO_RANKED_TOOLS, 6);
16
- assert.equal(policy.toolSchemaBudgetTokens(1_048_576), 64_000);
17
- assert.equal(policy.toolSchemaBudgetTokens(100_000), 35_000);
18
-
19
- const tools = Array.from({ length: 20 }, (_, index) => ({
20
- name: `DeferredTool${String(index + 1)}`,
21
- description: `Deferred tool ${String(index + 1)}`,
22
- parameters: { type: 'object', properties: {} },
23
- }));
24
- const selected = [];
25
- const loaded = new Set();
26
- const loader = policy.createDeferredToolLoader(selected, tools, loaded);
27
-
28
- (async () => {
29
- for (let index = 0; index < tools.length; index += 1) {
30
- const execution = loader.resolveExecution({ query: `select:${tools[index].name}` });
31
- const result = await execution.execute();
32
- assert.equal(result.isError, false);
33
- }
34
- assert.equal(loaded.size, 12, 'the twelve most recently loaded schemas must persist');
35
- assert.deepEqual([...loaded], tools.slice(-12).map((tool) => tool.name));
36
- process.stdout.write('tool-schema-capacity-regression PASS\n');
37
- })().catch((error) => {
38
- console.error(error);
39
- process.exitCode = 1;
40
- });