@askalf/dario 5.5.25 → 5.5.27
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/dist/cc-template.d.ts +2 -62
- package/dist/cc-template.js +7 -73
- package/dist/live-fingerprint.d.ts +73 -7
- package/dist/live-fingerprint.js +138 -2
- package/package.json +1 -1
package/dist/cc-template.d.ts
CHANGED
|
@@ -7,74 +7,14 @@
|
|
|
7
7
|
* live cache self-heals when Anthropic ships a new CC version — no user
|
|
8
8
|
* action required. See src/live-fingerprint.ts for the capture pipeline.
|
|
9
9
|
*/
|
|
10
|
-
import { TemplateData } from './live-fingerprint.js';
|
|
10
|
+
import { TemplateData, PLATFORM_ONLY_TOOLS, INTERACTIVE_ONLY_TOOLS, CONFIG_SCOPED_TOOLS } from './live-fingerprint.js';
|
|
11
|
+
export { PLATFORM_ONLY_TOOLS, INTERACTIVE_ONLY_TOOLS, CONFIG_SCOPED_TOOLS };
|
|
11
12
|
/** The loaded template itself — source, version, capture age, all fields. Startup banners and drift checks read this directly. */
|
|
12
13
|
export declare const CC_TEMPLATE: TemplateData;
|
|
13
|
-
/**
|
|
14
|
-
* Tools CC only ships on a specific platform. The bundled template is a
|
|
15
|
-
* union capture (any platform the maintainer baked from), so we filter it
|
|
16
|
-
* down to the running platform at module load. Real CC on the client side
|
|
17
|
-
* only advertises the tools available to its host — forwarding a larger
|
|
18
|
-
* set through dario would both leak a fingerprint (Anthropic sees tools
|
|
19
|
-
* the client would never actually call) and risk tool_use round-trips
|
|
20
|
-
* coming back for a tool the client has no handler for.
|
|
21
|
-
*
|
|
22
|
-
* PowerShell shipped in CC v2.1.116 on Windows; POSIX CC installs do not
|
|
23
|
-
* advertise it. As of CC v2.1.162 the Glob/Grep tools are the same shape:
|
|
24
|
-
* Windows CC advertises them, POSIX CC drops them and steers the agent to
|
|
25
|
-
* shell `find`/`grep` instead (which PowerShell has no native equivalent
|
|
26
|
-
* for). Registering them here filters them to win32 clients AND keeps a
|
|
27
|
-
* POSIX auto-bake from dropping them out of the union — the v4.8.28
|
|
28
|
-
* regression, where a Linux runner re-baked the bundle down to 28 tools.
|
|
29
|
-
* Add new platform-scoped tools here as CC adds them.
|
|
30
|
-
*/
|
|
31
|
-
export declare const PLATFORM_ONLY_TOOLS: Record<string, Set<string>>;
|
|
32
14
|
/** Keep tool `t` unless its name is listed under a platform other than the current one. */
|
|
33
15
|
export declare function filterToolsForPlatform<T extends {
|
|
34
16
|
name: string;
|
|
35
17
|
}>(tools: T[], platform: string): T[];
|
|
36
|
-
/**
|
|
37
|
-
* Tools CC only advertises in an INTERACTIVE session. The bake captures CC
|
|
38
|
-
* headlessly (`claude --print -p hi`, see live-fingerprint.ts), and CC v2.1.187
|
|
39
|
-
* dropped these plan-mode / clarification tools in `--print` mode — so a fresh
|
|
40
|
-
* headless capture no longer carries them even though every real interactive CC
|
|
41
|
-
* client still advertises them. Like PLATFORM_ONLY_TOOLS, the bundled template
|
|
42
|
-
* must stay a SUPERSET: register them here so a headless auto-rebake preserves
|
|
43
|
-
* them from the previous bundle instead of dropping them. Dropping them broke
|
|
44
|
-
* buildCCRequest's advertise-respects-client contract (the v4.8.93 regression):
|
|
45
|
-
* dario advertises only the intersection of the client's declared tools and this
|
|
46
|
-
* template, so a missing AskUserQuestion meant dario could not advertise it even
|
|
47
|
-
* when a full CC client declared it. Unlike PLATFORM_ONLY_TOOLS these are NOT
|
|
48
|
-
* platform-filtered — they stay in CC_TOOL_DEFINITIONS on every host so a client
|
|
49
|
-
* that declares them is always honored. Add new interactive-only tools here as
|
|
50
|
-
* CC adds them.
|
|
51
|
-
*/
|
|
52
|
-
export declare const INTERACTIVE_ONLY_TOOLS: Set<string>;
|
|
53
|
-
/**
|
|
54
|
-
* Tools CC advertises only under some runtime configurations. Unlike
|
|
55
|
-
* INTERACTIVE_ONLY_TOOLS (absent because the bake captures headlessly), these
|
|
56
|
-
* come and go with CC's REMOTE config for the same capture mode: the 2026-08-11
|
|
57
|
-
* bake on CC v2.1.232 captured all four headlessly, and the 2026-08-15 bake on
|
|
58
|
-
* v2.1.233 captured none of them — while TaskOutput/TaskStop, the rest of the
|
|
59
|
-
* task subsystem, stayed put. That is the v4.2.1 drift class (same binary,
|
|
60
|
-
* different wire shape via remote configuration), and it is not a signal that
|
|
61
|
-
* CC retired the tools.
|
|
62
|
-
*
|
|
63
|
-
* The bundle must stay a SUPERSET, so the bake preserves these from the previous
|
|
64
|
-
* bundle exactly as it does the platform- and interactive-only sets. The cost of
|
|
65
|
-
* the two directions is asymmetric, which is what settles it: a stale entry is
|
|
66
|
-
* INERT, because buildCCRequest advertises only the intersection of the bundle
|
|
67
|
-
* with what the client declared — no client declares it, nothing is advertised.
|
|
68
|
-
* Dropping one is NOT inert: CC_NATIVE_NAMES_UNION is derived from this bundle,
|
|
69
|
-
* so a client that does declare TaskCreate stops identity-mapping, falls into
|
|
70
|
-
* the unmapped round-robin, and is renamed onto a fallback slot with junk args
|
|
71
|
-
* (the v4.8.93 regression, caught here by issue-29-tool-translation.mjs).
|
|
72
|
-
*
|
|
73
|
-
* Add new config-scoped tools here as CC's remote config churns. Removing a name
|
|
74
|
-
* is a deliberate act: it means CC genuinely retired the tool, and it should be
|
|
75
|
-
* paired with the capture evidence that says so.
|
|
76
|
-
*/
|
|
77
|
-
export declare const CONFIG_SCOPED_TOOLS: Set<string>;
|
|
78
18
|
/** CC's exact tool definitions for the current platform — filtered from the bundled union. */
|
|
79
19
|
export declare const CC_TOOL_DEFINITIONS: {
|
|
80
20
|
name: string;
|
package/dist/cc-template.js
CHANGED
|
@@ -7,32 +7,17 @@
|
|
|
7
7
|
* live cache self-heals when Anthropic ships a new CC version — no user
|
|
8
8
|
* action required. See src/live-fingerprint.ts for the capture pipeline.
|
|
9
9
|
*/
|
|
10
|
-
import { loadTemplate, promptVariantsOf, VARIANT_FAMILIES } from './live-fingerprint.js';
|
|
10
|
+
import { loadTemplate, promptVariantsOf, VARIANT_FAMILIES, PLATFORM_ONLY_TOOLS, INTERACTIVE_ONLY_TOOLS, CONFIG_SCOPED_TOOLS, } from './live-fingerprint.js';
|
|
11
|
+
// Re-exported so existing importers (scripts/capture-and-bake.mjs, the template
|
|
12
|
+
// invariant tests) keep their import site. The definitions live in
|
|
13
|
+
// live-fingerprint.ts because loadTemplate must apply the same superset rule to
|
|
14
|
+
// a live capture that the bake applies to the bundle, and cc-template.ts is
|
|
15
|
+
// downstream of that load (#1035).
|
|
16
|
+
export { PLATFORM_ONLY_TOOLS, INTERACTIVE_ONLY_TOOLS, CONFIG_SCOPED_TOOLS };
|
|
11
17
|
// Load template at module init — prefer live cache, fall back to bundled.
|
|
12
18
|
const TEMPLATE = loadTemplate({ silent: true });
|
|
13
19
|
/** The loaded template itself — source, version, capture age, all fields. Startup banners and drift checks read this directly. */
|
|
14
20
|
export const CC_TEMPLATE = TEMPLATE;
|
|
15
|
-
/**
|
|
16
|
-
* Tools CC only ships on a specific platform. The bundled template is a
|
|
17
|
-
* union capture (any platform the maintainer baked from), so we filter it
|
|
18
|
-
* down to the running platform at module load. Real CC on the client side
|
|
19
|
-
* only advertises the tools available to its host — forwarding a larger
|
|
20
|
-
* set through dario would both leak a fingerprint (Anthropic sees tools
|
|
21
|
-
* the client would never actually call) and risk tool_use round-trips
|
|
22
|
-
* coming back for a tool the client has no handler for.
|
|
23
|
-
*
|
|
24
|
-
* PowerShell shipped in CC v2.1.116 on Windows; POSIX CC installs do not
|
|
25
|
-
* advertise it. As of CC v2.1.162 the Glob/Grep tools are the same shape:
|
|
26
|
-
* Windows CC advertises them, POSIX CC drops them and steers the agent to
|
|
27
|
-
* shell `find`/`grep` instead (which PowerShell has no native equivalent
|
|
28
|
-
* for). Registering them here filters them to win32 clients AND keeps a
|
|
29
|
-
* POSIX auto-bake from dropping them out of the union — the v4.8.28
|
|
30
|
-
* regression, where a Linux runner re-baked the bundle down to 28 tools.
|
|
31
|
-
* Add new platform-scoped tools here as CC adds them.
|
|
32
|
-
*/
|
|
33
|
-
export const PLATFORM_ONLY_TOOLS = {
|
|
34
|
-
win32: new Set(['PowerShell', 'Glob', 'Grep']),
|
|
35
|
-
};
|
|
36
21
|
/** Keep tool `t` unless its name is listed under a platform other than the current one. */
|
|
37
22
|
export function filterToolsForPlatform(tools, platform) {
|
|
38
23
|
return tools.filter((tool) => {
|
|
@@ -43,57 +28,6 @@ export function filterToolsForPlatform(tools, platform) {
|
|
|
43
28
|
return true;
|
|
44
29
|
});
|
|
45
30
|
}
|
|
46
|
-
/**
|
|
47
|
-
* Tools CC only advertises in an INTERACTIVE session. The bake captures CC
|
|
48
|
-
* headlessly (`claude --print -p hi`, see live-fingerprint.ts), and CC v2.1.187
|
|
49
|
-
* dropped these plan-mode / clarification tools in `--print` mode — so a fresh
|
|
50
|
-
* headless capture no longer carries them even though every real interactive CC
|
|
51
|
-
* client still advertises them. Like PLATFORM_ONLY_TOOLS, the bundled template
|
|
52
|
-
* must stay a SUPERSET: register them here so a headless auto-rebake preserves
|
|
53
|
-
* them from the previous bundle instead of dropping them. Dropping them broke
|
|
54
|
-
* buildCCRequest's advertise-respects-client contract (the v4.8.93 regression):
|
|
55
|
-
* dario advertises only the intersection of the client's declared tools and this
|
|
56
|
-
* template, so a missing AskUserQuestion meant dario could not advertise it even
|
|
57
|
-
* when a full CC client declared it. Unlike PLATFORM_ONLY_TOOLS these are NOT
|
|
58
|
-
* platform-filtered — they stay in CC_TOOL_DEFINITIONS on every host so a client
|
|
59
|
-
* that declares them is always honored. Add new interactive-only tools here as
|
|
60
|
-
* CC adds them.
|
|
61
|
-
*/
|
|
62
|
-
export const INTERACTIVE_ONLY_TOOLS = new Set([
|
|
63
|
-
'AskUserQuestion',
|
|
64
|
-
'EnterPlanMode',
|
|
65
|
-
'ExitPlanMode',
|
|
66
|
-
]);
|
|
67
|
-
/**
|
|
68
|
-
* Tools CC advertises only under some runtime configurations. Unlike
|
|
69
|
-
* INTERACTIVE_ONLY_TOOLS (absent because the bake captures headlessly), these
|
|
70
|
-
* come and go with CC's REMOTE config for the same capture mode: the 2026-08-11
|
|
71
|
-
* bake on CC v2.1.232 captured all four headlessly, and the 2026-08-15 bake on
|
|
72
|
-
* v2.1.233 captured none of them — while TaskOutput/TaskStop, the rest of the
|
|
73
|
-
* task subsystem, stayed put. That is the v4.2.1 drift class (same binary,
|
|
74
|
-
* different wire shape via remote configuration), and it is not a signal that
|
|
75
|
-
* CC retired the tools.
|
|
76
|
-
*
|
|
77
|
-
* The bundle must stay a SUPERSET, so the bake preserves these from the previous
|
|
78
|
-
* bundle exactly as it does the platform- and interactive-only sets. The cost of
|
|
79
|
-
* the two directions is asymmetric, which is what settles it: a stale entry is
|
|
80
|
-
* INERT, because buildCCRequest advertises only the intersection of the bundle
|
|
81
|
-
* with what the client declared — no client declares it, nothing is advertised.
|
|
82
|
-
* Dropping one is NOT inert: CC_NATIVE_NAMES_UNION is derived from this bundle,
|
|
83
|
-
* so a client that does declare TaskCreate stops identity-mapping, falls into
|
|
84
|
-
* the unmapped round-robin, and is renamed onto a fallback slot with junk args
|
|
85
|
-
* (the v4.8.93 regression, caught here by issue-29-tool-translation.mjs).
|
|
86
|
-
*
|
|
87
|
-
* Add new config-scoped tools here as CC's remote config churns. Removing a name
|
|
88
|
-
* is a deliberate act: it means CC genuinely retired the tool, and it should be
|
|
89
|
-
* paired with the capture evidence that says so.
|
|
90
|
-
*/
|
|
91
|
-
export const CONFIG_SCOPED_TOOLS = new Set([
|
|
92
|
-
'TaskCreate',
|
|
93
|
-
'TaskGet',
|
|
94
|
-
'TaskList',
|
|
95
|
-
'TaskUpdate',
|
|
96
|
-
]);
|
|
97
31
|
/** CC's exact tool definitions for the current platform — filtered from the bundled union. */
|
|
98
32
|
export const CC_TOOL_DEFINITIONS = filterToolsForPlatform(TEMPLATE.tools, process.platform);
|
|
99
33
|
/** The UNFILTERED bundled union — every tool the bake knows across platforms
|
|
@@ -234,16 +234,82 @@ export declare function promptVariantsOf(t: TemplateData): Record<string, string
|
|
|
234
234
|
* Variants the live template already has win, so a future per-model live
|
|
235
235
|
* capture supersedes the bake without another change here.
|
|
236
236
|
*/
|
|
237
|
-
export declare function withBundledVariants(live: TemplateData): TemplateData;
|
|
238
237
|
/**
|
|
239
|
-
*
|
|
240
|
-
*
|
|
238
|
+
* Tools CC only ships on a specific platform. A capture sees only the host it
|
|
239
|
+
* ran on, so both the bundle and any live capture must be re-unioned against
|
|
240
|
+
* the other platforms' names before use. Filtered back down to the running
|
|
241
|
+
* platform at request time by filterToolsForPlatform().
|
|
242
|
+
*
|
|
243
|
+
* PowerShell shipped in CC v2.1.116 on Windows; POSIX CC installs do not
|
|
244
|
+
* advertise it. As of CC v2.1.162 Glob/Grep are the same shape: Windows CC
|
|
245
|
+
* advertises them, POSIX CC drops them and steers the agent to shell
|
|
246
|
+
* `find`/`grep` instead. Registering them here filters them to win32 clients
|
|
247
|
+
* AND keeps a POSIX capture from dropping them out of the union — the v4.8.28
|
|
248
|
+
* regression, where a Linux runner re-baked the bundle down to 28 tools.
|
|
249
|
+
* Add new platform-scoped tools here as CC adds them.
|
|
250
|
+
*/
|
|
251
|
+
export declare const PLATFORM_ONLY_TOOLS: Record<string, Set<string>>;
|
|
252
|
+
/**
|
|
253
|
+
* Tools CC only advertises in an INTERACTIVE session. Captures spawn CC
|
|
254
|
+
* headlessly (`claude --print -p hi`), and CC v2.1.187 dropped these plan-mode /
|
|
255
|
+
* clarification tools in `--print` mode — so a fresh headless capture no longer
|
|
256
|
+
* carries them even though every real interactive CC client still advertises
|
|
257
|
+
* them. Unlike PLATFORM_ONLY_TOOLS these are NOT platform-filtered: they stay in
|
|
258
|
+
* the tool set on every host so a client that declares them is always honored.
|
|
259
|
+
* Add new interactive-only tools here as CC adds them.
|
|
260
|
+
*/
|
|
261
|
+
export declare const INTERACTIVE_ONLY_TOOLS: Set<string>;
|
|
262
|
+
/**
|
|
263
|
+
* Tools CC advertises only under some runtime configurations. Unlike
|
|
264
|
+
* INTERACTIVE_ONLY_TOOLS (absent because the capture is headless), these come
|
|
265
|
+
* and go with CC's REMOTE config for the same capture mode: the 2026-08-11 bake
|
|
266
|
+
* on CC v2.1.232 captured all four headlessly, and the 2026-08-15 bake on
|
|
267
|
+
* v2.1.233 captured none of them — while TaskOutput/TaskStop, the rest of the
|
|
268
|
+
* task subsystem, stayed put. That is the v4.2.1 drift class (same binary,
|
|
269
|
+
* different wire shape via remote configuration), not a signal that CC retired
|
|
270
|
+
* the tools.
|
|
271
|
+
*
|
|
272
|
+
* Removing a name here is a deliberate act: it means CC genuinely retired the
|
|
273
|
+
* tool, and it should be paired with the capture evidence that says so.
|
|
274
|
+
*/
|
|
275
|
+
export declare const CONFIG_SCOPED_TOOLS: Set<string>;
|
|
276
|
+
/** Why a given tool was preserved — used for logging at bake time. */
|
|
277
|
+
export type PreservedToolReason = 'platform' | 'interactive' | 'config-scoped';
|
|
278
|
+
/**
|
|
279
|
+
* Decide whether `name` must be preserved into a capture taken on `platform`,
|
|
280
|
+
* and say why. The single definition of the superset rule.
|
|
281
|
+
*
|
|
282
|
+
* The cost of the two directions is asymmetric, which is what settles it. A
|
|
283
|
+
* stale entry is INERT: buildCCRequest advertises the intersection of the tool
|
|
284
|
+
* set with what the CLIENT declared, so an entry no client declares is never
|
|
285
|
+
* sent. Dropping one is NOT inert — CC_NATIVE_NAMES_UNION is derived from the
|
|
286
|
+
* loaded template, so a client that does declare the tool stops identity-
|
|
287
|
+
* mapping, falls into the unmapped round-robin, and has its history tool_use
|
|
288
|
+
* blocks renamed onto a fallback slot with junk arguments (the v4.8.93
|
|
289
|
+
* regression).
|
|
290
|
+
*/
|
|
291
|
+
export declare function preservedToolReason(name: string, platform: string): PreservedToolReason | null;
|
|
292
|
+
/**
|
|
293
|
+
* Re-union `capture.tools` with any tool `fallback` carries that the capture is
|
|
294
|
+
* required to keep (see preservedToolReason). Returns the merged tool array,
|
|
295
|
+
* CC's alphabetical wire order restored, plus what was preserved and why.
|
|
241
296
|
*
|
|
242
|
-
* This is
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
*
|
|
297
|
+
* This is the rule the bake has always applied to the previous bundle. It must
|
|
298
|
+
* apply to a LIVE capture too: `loadTemplate` prefers a fresh live cache, the
|
|
299
|
+
* cache refreshes on a 24h TTL, and the capture is headless — so without this,
|
|
300
|
+
* every dario install with CC present degrades its own tool set within a day
|
|
301
|
+
* of running, and CI never sees it because CI has no live cache (#1035).
|
|
246
302
|
*/
|
|
303
|
+
export declare function mergePreservedTools<T extends {
|
|
304
|
+
name: string;
|
|
305
|
+
}>(captureTools: T[], fallbackTools: T[], platform: string): {
|
|
306
|
+
tools: T[];
|
|
307
|
+
preserved: Array<{
|
|
308
|
+
name: string;
|
|
309
|
+
reason: PreservedToolReason;
|
|
310
|
+
}>;
|
|
311
|
+
};
|
|
312
|
+
export declare function withBundledVariants(live: TemplateData): TemplateData;
|
|
247
313
|
export declare function loadTemplate(_options?: {
|
|
248
314
|
silent?: boolean;
|
|
249
315
|
}): TemplateData;
|
package/dist/live-fingerprint.js
CHANGED
|
@@ -167,6 +167,114 @@ export function promptVariantsOf(t) {
|
|
|
167
167
|
* Variants the live template already has win, so a future per-model live
|
|
168
168
|
* capture supersedes the bake without another change here.
|
|
169
169
|
*/
|
|
170
|
+
/**
|
|
171
|
+
* Tools CC only ships on a specific platform. A capture sees only the host it
|
|
172
|
+
* ran on, so both the bundle and any live capture must be re-unioned against
|
|
173
|
+
* the other platforms' names before use. Filtered back down to the running
|
|
174
|
+
* platform at request time by filterToolsForPlatform().
|
|
175
|
+
*
|
|
176
|
+
* PowerShell shipped in CC v2.1.116 on Windows; POSIX CC installs do not
|
|
177
|
+
* advertise it. As of CC v2.1.162 Glob/Grep are the same shape: Windows CC
|
|
178
|
+
* advertises them, POSIX CC drops them and steers the agent to shell
|
|
179
|
+
* `find`/`grep` instead. Registering them here filters them to win32 clients
|
|
180
|
+
* AND keeps a POSIX capture from dropping them out of the union — the v4.8.28
|
|
181
|
+
* regression, where a Linux runner re-baked the bundle down to 28 tools.
|
|
182
|
+
* Add new platform-scoped tools here as CC adds them.
|
|
183
|
+
*/
|
|
184
|
+
export const PLATFORM_ONLY_TOOLS = {
|
|
185
|
+
win32: new Set(['PowerShell', 'Glob', 'Grep']),
|
|
186
|
+
};
|
|
187
|
+
/**
|
|
188
|
+
* Tools CC only advertises in an INTERACTIVE session. Captures spawn CC
|
|
189
|
+
* headlessly (`claude --print -p hi`), and CC v2.1.187 dropped these plan-mode /
|
|
190
|
+
* clarification tools in `--print` mode — so a fresh headless capture no longer
|
|
191
|
+
* carries them even though every real interactive CC client still advertises
|
|
192
|
+
* them. Unlike PLATFORM_ONLY_TOOLS these are NOT platform-filtered: they stay in
|
|
193
|
+
* the tool set on every host so a client that declares them is always honored.
|
|
194
|
+
* Add new interactive-only tools here as CC adds them.
|
|
195
|
+
*/
|
|
196
|
+
export const INTERACTIVE_ONLY_TOOLS = new Set([
|
|
197
|
+
'AskUserQuestion',
|
|
198
|
+
'EnterPlanMode',
|
|
199
|
+
'ExitPlanMode',
|
|
200
|
+
]);
|
|
201
|
+
/**
|
|
202
|
+
* Tools CC advertises only under some runtime configurations. Unlike
|
|
203
|
+
* INTERACTIVE_ONLY_TOOLS (absent because the capture is headless), these come
|
|
204
|
+
* and go with CC's REMOTE config for the same capture mode: the 2026-08-11 bake
|
|
205
|
+
* on CC v2.1.232 captured all four headlessly, and the 2026-08-15 bake on
|
|
206
|
+
* v2.1.233 captured none of them — while TaskOutput/TaskStop, the rest of the
|
|
207
|
+
* task subsystem, stayed put. That is the v4.2.1 drift class (same binary,
|
|
208
|
+
* different wire shape via remote configuration), not a signal that CC retired
|
|
209
|
+
* the tools.
|
|
210
|
+
*
|
|
211
|
+
* Removing a name here is a deliberate act: it means CC genuinely retired the
|
|
212
|
+
* tool, and it should be paired with the capture evidence that says so.
|
|
213
|
+
*/
|
|
214
|
+
export const CONFIG_SCOPED_TOOLS = new Set([
|
|
215
|
+
'TaskCreate',
|
|
216
|
+
'TaskGet',
|
|
217
|
+
'TaskList',
|
|
218
|
+
'TaskUpdate',
|
|
219
|
+
]);
|
|
220
|
+
/**
|
|
221
|
+
* Decide whether `name` must be preserved into a capture taken on `platform`,
|
|
222
|
+
* and say why. The single definition of the superset rule.
|
|
223
|
+
*
|
|
224
|
+
* The cost of the two directions is asymmetric, which is what settles it. A
|
|
225
|
+
* stale entry is INERT: buildCCRequest advertises the intersection of the tool
|
|
226
|
+
* set with what the CLIENT declared, so an entry no client declares is never
|
|
227
|
+
* sent. Dropping one is NOT inert — CC_NATIVE_NAMES_UNION is derived from the
|
|
228
|
+
* loaded template, so a client that does declare the tool stops identity-
|
|
229
|
+
* mapping, falls into the unmapped round-robin, and has its history tool_use
|
|
230
|
+
* blocks renamed onto a fallback slot with junk arguments (the v4.8.93
|
|
231
|
+
* regression).
|
|
232
|
+
*/
|
|
233
|
+
export function preservedToolReason(name, platform) {
|
|
234
|
+
for (const [plat, names] of Object.entries(PLATFORM_ONLY_TOOLS)) {
|
|
235
|
+
if (names.has(name) && plat !== platform)
|
|
236
|
+
return 'platform';
|
|
237
|
+
}
|
|
238
|
+
if (INTERACTIVE_ONLY_TOOLS.has(name))
|
|
239
|
+
return 'interactive';
|
|
240
|
+
if (CONFIG_SCOPED_TOOLS.has(name))
|
|
241
|
+
return 'config-scoped';
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Re-union `capture.tools` with any tool `fallback` carries that the capture is
|
|
246
|
+
* required to keep (see preservedToolReason). Returns the merged tool array,
|
|
247
|
+
* CC's alphabetical wire order restored, plus what was preserved and why.
|
|
248
|
+
*
|
|
249
|
+
* This is the rule the bake has always applied to the previous bundle. It must
|
|
250
|
+
* apply to a LIVE capture too: `loadTemplate` prefers a fresh live cache, the
|
|
251
|
+
* cache refreshes on a 24h TTL, and the capture is headless — so without this,
|
|
252
|
+
* every dario install with CC present degrades its own tool set within a day
|
|
253
|
+
* of running, and CI never sees it because CI has no live cache (#1035).
|
|
254
|
+
*/
|
|
255
|
+
export function mergePreservedTools(captureTools, fallbackTools, platform) {
|
|
256
|
+
const have = new Set(captureTools.map((t) => t.name));
|
|
257
|
+
const preserved = [];
|
|
258
|
+
const additions = [];
|
|
259
|
+
for (const tool of fallbackTools) {
|
|
260
|
+
if (have.has(tool.name))
|
|
261
|
+
continue;
|
|
262
|
+
const reason = preservedToolReason(tool.name, platform);
|
|
263
|
+
if (!reason)
|
|
264
|
+
continue;
|
|
265
|
+
additions.push(tool);
|
|
266
|
+
preserved.push({ name: tool.name, reason });
|
|
267
|
+
have.add(tool.name);
|
|
268
|
+
}
|
|
269
|
+
if (additions.length === 0)
|
|
270
|
+
return { tools: captureTools, preserved };
|
|
271
|
+
// CC sends tools alphabetically by name — sort after merge so preserved tools
|
|
272
|
+
// insert at their natural position rather than appending at the end.
|
|
273
|
+
return {
|
|
274
|
+
tools: [...captureTools, ...additions].sort((a, b) => a.name.localeCompare(b.name)),
|
|
275
|
+
preserved,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
170
278
|
export function withBundledVariants(live) {
|
|
171
279
|
let bundled;
|
|
172
280
|
try {
|
|
@@ -217,12 +325,40 @@ const LIVE_TTL_MS = 24 * 60 * 60 * 1000; // re-extract once a day
|
|
|
217
325
|
* background via refreshLiveFingerprintAsync(); its results are written
|
|
218
326
|
* to the cache file and picked up on the next dario startup.
|
|
219
327
|
*/
|
|
328
|
+
/**
|
|
329
|
+
* Bring a live capture up to the superset the rest of the codebase assumes:
|
|
330
|
+
* merge back any preserved tool the bundle has and the capture lacks, then
|
|
331
|
+
* re-derive `tool_names`.
|
|
332
|
+
*
|
|
333
|
+
* `tool_names === tools.map(t => t.name)` is the contract everywhere —
|
|
334
|
+
* scrubTemplate() sets it from `tools`, and so does the capture path. The bake
|
|
335
|
+
* learned the hard way that a merge which mutates `tools` without re-deriving
|
|
336
|
+
* the list ships an artifact whose two tool lists disagree; do not repeat it
|
|
337
|
+
* here (#1035).
|
|
338
|
+
*/
|
|
339
|
+
function withPreservedTools(live, options) {
|
|
340
|
+
let bundled;
|
|
341
|
+
try {
|
|
342
|
+
bundled = loadBundledTemplate({ silent: true });
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
return live; // bundle unreadable — the capture is still better than throwing
|
|
346
|
+
}
|
|
347
|
+
const { tools, preserved } = mergePreservedTools(live.tools, bundled.tools, process.platform);
|
|
348
|
+
if (preserved.length === 0)
|
|
349
|
+
return live;
|
|
350
|
+
if (!options?.silent) {
|
|
351
|
+
const byReason = preserved.map((p) => `${p.name} (${p.reason})`).join(', ');
|
|
352
|
+
console.log(`[dario] live template: restored ${preserved.length} tool${preserved.length === 1 ? '' : 's'} the capture omitted: ${byReason}`);
|
|
353
|
+
}
|
|
354
|
+
return { ...live, tools, tool_names: tools.map((t) => t.name) };
|
|
355
|
+
}
|
|
220
356
|
export function loadTemplate(_options) {
|
|
221
357
|
const cached = readLiveCache();
|
|
222
358
|
if (cached) {
|
|
223
359
|
const age = Date.now() - new Date(cached._captured).getTime();
|
|
224
360
|
if (age < LIVE_TTL_MS) {
|
|
225
|
-
return withBundledVariants(cached);
|
|
361
|
+
return withPreservedTools(withBundledVariants(cached), _options);
|
|
226
362
|
}
|
|
227
363
|
// Stale cache: prefer whichever of the live cache and the bundled
|
|
228
364
|
// snapshot was captured more recently — do NOT blindly keep the cache.
|
|
@@ -236,7 +372,7 @@ export function loadTemplate(_options) {
|
|
|
236
372
|
const bundled = loadBundledTemplate(_options);
|
|
237
373
|
const cachedAt = new Date(cached._captured).getTime();
|
|
238
374
|
const bundledAt = new Date(bundled._captured).getTime();
|
|
239
|
-
return Number.isFinite(bundledAt) && bundledAt > cachedAt ? bundled : withBundledVariants(cached);
|
|
375
|
+
return Number.isFinite(bundledAt) && bundledAt > cachedAt ? bundled : withPreservedTools(withBundledVariants(cached), _options);
|
|
240
376
|
}
|
|
241
377
|
return loadBundledTemplate(_options);
|
|
242
378
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askalf/dario",
|
|
3
|
-
"version": "5.5.
|
|
3
|
+
"version": "5.5.27",
|
|
4
4
|
"description": "Use your Claude Pro/Max subscription in any tool — Cursor, Cline, Aider, the Agent SDK, your scripts — at subscription pricing, not per-token API bills. One local Anthropic + OpenAI-compatible endpoint.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|