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.
- package/LIESMICH.txt +13 -869
- package/README.md +41 -833
- package/bin/assistant-message-offload-policy.cjs +3 -1
- package/bin/compaction-transaction-policy.cjs +122 -0
- package/bin/context-performance-policy.cjs +2 -5
- package/bin/context-pressure-policy.cjs +20 -0
- package/bin/cron-run-output.cjs +45 -0
- package/bin/cron-run-store.cjs +145 -0
- package/bin/default-model-output-budget-policy.cjs +28 -0
- package/bin/durable-task-resume-policy.cjs +130 -0
- package/bin/durable-task-resume-runtime.cjs +117 -0
- package/bin/durable-task-resume-store.cjs +88 -0
- package/bin/editable-tool-approval-policy.cjs +540 -0
- package/bin/editable-tool-approval-runtime.cjs +99 -0
- package/bin/file-observation-policy.cjs +133 -0
- package/bin/html-to-research-markdown.cjs +146 -0
- package/bin/launcher-runtime.js +0 -1
- package/bin/micro-compaction-policy.cjs +64 -0
- package/bin/mnemo-connect-heartbeat.cjs +1 -3
- package/bin/programmatic-tool-runtime.mjs +330 -4
- package/bin/read-continuation-policy.cjs +36 -5
- package/bin/retry-checkpoint-policy.cjs +13 -0
- package/bin/scoped-cron-run-policy.cjs +358 -0
- package/bin/session-checkpoint-policy.cjs +25 -0
- package/bin/startup-preferences.cjs +4 -3
- package/bin/structured-agent-swarm-output.cjs +325 -0
- package/bin/subagent-context-fork-policy.cjs +155 -0
- package/bin/subagent-skill-policy.cjs +204 -0
- package/bin/telegram-approval-relay.cjs +2 -1
- package/bin/tool-file-persistence.cjs +141 -0
- package/bin/tool-result-offload-policy.cjs +25 -33
- package/bin/turn-thinking-policy.cjs +2 -26
- package/bin/update-notice.js +30 -18
- package/bin/user-message-offload-policy.cjs +3 -1
- package/blun.mjs +1564 -640
- package/codebase-index/README.md +12 -0
- package/codebase-index/codebase_index.py +129 -18
- package/package.json +23 -58
- package/telegram-plugin/bin/telegram-mnemo-capture.cjs +1 -3
- package/telegram-plugin/bin/telegram-typing-keepalive.cjs +89 -0
- package/telegram-plugin/dist/bridge.mjs +8 -1
- package/CHANGELOG.md +0 -321
- package/agent-spine-plugin/CHANGELOG.md +0 -406
- package/agent-spine-plugin/CONTRIBUTING.md +0 -52
- package/agent-spine-plugin/README.md +0 -344
- package/agent-spine-plugin/SECURITY.md +0 -47
- package/agent-spine-plugin/docs/acceptance.md +0 -61
- package/agent-spine-plugin/docs/architecture.md +0 -183
- package/agent-spine-plugin/docs/attention.md +0 -121
- package/agent-spine-plugin/docs/automatic-continuity.md +0 -79
- package/agent-spine-plugin/docs/channel-runtime.md +0 -92
- package/agent-spine-plugin/docs/coordination.md +0 -138
- package/agent-spine-plugin/docs/feed-transport.md +0 -99
- package/agent-spine-plugin/docs/gateway-runtime.md +0 -116
- package/agent-spine-plugin/docs/harness-reference.md +0 -45
- package/agent-spine-plugin/docs/host-integration.md +0 -129
- package/agent-spine-plugin/docs/https-transport.md +0 -116
- package/agent-spine-plugin/docs/learning.md +0 -133
- package/agent-spine-plugin/docs/object-transport.md +0 -93
- package/agent-spine-plugin/docs/peer-transport.md +0 -88
- package/agent-spine-plugin/docs/preflight-recall.md +0 -69
- package/agent-spine-plugin/docs/preservation-contract.md +0 -53
- package/agent-spine-plugin/docs/quality-gates.md +0 -50
- package/agent-spine-plugin/docs/relationships.md +0 -73
- package/agent-spine-plugin/docs/releasing.md +0 -83
- package/agent-spine-plugin/docs/roadmap.md +0 -307
- package/agent-spine-plugin/docs/selfstarter.md +0 -88
- package/agent-spine-plugin/docs/session-briefing.md +0 -74
- package/agent-spine-plugin/docs/shared-memory.md +0 -259
- package/agent-spine-plugin/docs/source-roots.md +0 -86
- package/agent-spine-plugin/docs/sqlite-transport.md +0 -76
- package/agent-spine-plugin/scripts/check-hosts.js +0 -195
- package/agent-spine-plugin/scripts/check-install.js +0 -569
- package/agent-spine-plugin/scripts/check-syntax.js +0 -29
- package/agent-spine-plugin/scripts/github-actions.js +0 -11
- package/agent-spine-plugin/scripts/release-check.js +0 -128
- package/agent-spine-plugin/scripts/run-acceptance.js +0 -19
- package/agent-spine-plugin/scripts/run-checks.js +0 -46
- package/agent-spine-plugin/scripts/run-tests-hermetic.js +0 -73
- package/agent-spine-plugin/spine-example/1-identity.md +0 -12
- package/agent-spine-plugin/spine-example/2-voice.md +0 -6
- package/agent-spine-plugin/spine-example/3-conduct.md +0 -8
- package/agent-spine-plugin/spine-example/4-history.md +0 -4
- package/bin/empty-response-retry-policy.cjs +0 -29
- package/bin/fredrik-glm-provider.cjs +0 -256
- package/bin/package-regression-policy.cjs +0 -77
- package/fredrik-glm-profile.toml.example +0 -26
- package/release-planned-removals.json +0 -15
- package/scripts/check-active-profile-plugin-startup.js +0 -36
- package/scripts/check-active-work-steer-regression.js +0 -46
- package/scripts/check-approval-observability-regression.js +0 -111
- package/scripts/check-approval-queue-shortcuts-regression.js +0 -65
- package/scripts/check-bundled-agent-spine-regression.js +0 -48
- package/scripts/check-codebase-search-packaging-regression.js +0 -92
- package/scripts/check-copy-command-regression.js +0 -74
- package/scripts/check-current-turn-read-pin-mutation-regression.js +0 -72
- package/scripts/check-current-turn-read-pin-regression.js +0 -94
- package/scripts/check-deepseek-native-max-regression.js +0 -49
- package/scripts/check-empty-response-effort-downgrade-regression.js +0 -48
- package/scripts/check-fredrik-glm-mutation-regression.js +0 -18
- package/scripts/check-fredrik-glm-regression.js +0 -169
- package/scripts/check-historical-tool-result-preview-regression.js +0 -77
- package/scripts/check-history-pressure-offload-regression.js +0 -77
- package/scripts/check-mcp-startup-wait-budget.js +0 -48
- package/scripts/check-package-regression.js +0 -38
- package/scripts/check-plugin-startup-regression.js +0 -53
- package/scripts/check-programmatic-context-isolation-regression.js +0 -193
- package/scripts/check-programmatic-tool-regression.js +0 -294
- package/scripts/check-queue-controls-regression.js +0 -189
- package/scripts/check-release-metadata.js +0 -103
- package/scripts/check-reload-agent-spine-regression.js +0 -76
- package/scripts/check-resume-replay-regression.js +0 -102
- package/scripts/check-session-cancel-regression.js +0 -43
- package/scripts/check-session-picker-resume-metrics-regression.js +0 -97
- package/scripts/check-session-start-hook-context-regression.js +0 -228
- package/scripts/check-shell-terminal-isolation-regression.js +0 -81
- package/scripts/check-slash-escape-regression.js +0 -89
- package/scripts/check-startup-swarm-command-regression.js +0 -24
- package/scripts/check-structured-subagent-output-regression.js +0 -331
- package/scripts/check-telegram-bridge-watchdog.js +0 -60
- package/scripts/check-telegram-direct-work-resume-regression.js +0 -53
- package/scripts/check-telegram-loop-exactly-once-regression.js +0 -71
- package/scripts/check-todo-loop-regression.js +0 -78
- package/scripts/check-todo-progress-regression.js +0 -416
- package/scripts/check-todo-recovery-catalog-regression.js +0 -50
- package/scripts/check-tool-schema-capacity-regression.js +0 -40
- package/scripts/programmatic-tool-runtime.test.mjs +0 -365
- package/scripts/structured-subagent-output.test.cjs +0 -170
- /package/{scripts → bin}/fix-node-pty-perms.js +0 -0
|
@@ -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
|
-
});
|