@cargo-ai/cli 1.0.86 → 1.0.88
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/build/commands/ask/claudeConfig.d.ts +2 -0
- package/build/commands/ask/claudeConfig.d.ts.map +1 -1
- package/build/commands/ask/claudeConfig.js +67 -1
- package/build/commands/ask/index.js +1 -1
- package/build/commands/ask/localHarness.d.ts +53 -0
- package/build/commands/ask/localHarness.d.ts.map +1 -1
- package/build/commands/ask/localHarness.js +281 -55
- package/build/commands/ask/prompt.d.ts +7 -1
- package/build/commands/ask/prompt.d.ts.map +1 -1
- package/build/commands/ask/prompt.js +9 -3
- package/build/commands/ask/session.d.ts +8 -1
- package/build/commands/ask/session.d.ts.map +1 -1
- package/build/commands/ask/session.js +426 -63
- package/build/commands/ask/thinking.d.ts +21 -0
- package/build/commands/ask/thinking.d.ts.map +1 -0
- package/build/commands/ask/thinking.js +57 -0
- package/build/commands/ask/typeAhead.d.ts +67 -0
- package/build/commands/ask/typeAhead.d.ts.map +1 -0
- package/build/commands/ask/typeAhead.js +169 -0
- package/build/commands/runHandler.d.ts +7 -0
- package/build/commands/runHandler.d.ts.map +1 -1
- package/build/commands/runHandler.js +39 -4
- package/package.json +6 -4
|
@@ -18,6 +18,8 @@
|
|
|
18
18
|
*
|
|
19
19
|
* Set `CLAUDE_CONFIG_DIR` to share a config with the `claude` CLI instead —
|
|
20
20
|
* that reinstates the user's hooks and MCP servers, and their startup cost.
|
|
21
|
+
* Nothing is written into a directory named that way: it is the user's, and
|
|
22
|
+
* the settings file in it is theirs to own.
|
|
21
23
|
*/
|
|
22
24
|
export declare function askClaudeConfigDir(): string;
|
|
23
25
|
//# sourceMappingURL=claudeConfig.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claudeConfig.d.ts","sourceRoot":"","sources":["../../../src/commands/ask/claudeConfig.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"claudeConfig.d.ts","sourceRoot":"","sources":["../../../src/commands/ask/claudeConfig.ts"],"names":[],"mappings":"AA2BA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAa3C"}
|
|
@@ -1,6 +1,27 @@
|
|
|
1
|
-
import { mkdirSync } from "node:fs";
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { getConfigDir } from "@cargo-ai/cdk/cli";
|
|
4
|
+
/**
|
|
5
|
+
* Tools that spawn a subagent, refused at source.
|
|
6
|
+
*
|
|
7
|
+
* Approving one is a different kind of decision from approving a Bash: the
|
|
8
|
+
* subagent runs its own tools, and whether those come back here for individual
|
|
9
|
+
* approval is not something we control. A prompt that cannot describe what it
|
|
10
|
+
* is granting is worse than not offering the capability.
|
|
11
|
+
*
|
|
12
|
+
* It has to be refused *here*, in Claude Code's own settings, because the
|
|
13
|
+
* approval prompt never sees it. The harness bridge only writes `ask` rules
|
|
14
|
+
* for the tools in its own `NATIVE_TOOL_KINDS` map, and the subagent tools are
|
|
15
|
+
* not in it — so `permissionMode: "allow-reads"` leaves them ungated, Claude
|
|
16
|
+
* Code never asks the bridge, and `isAlwaysDenied` is never consulted. A deny
|
|
17
|
+
* rule withholds the tool instead: Claude Code reports it as "disabled for
|
|
18
|
+
* this session, in subagents as well as here" and the model does the work
|
|
19
|
+
* itself.
|
|
20
|
+
*
|
|
21
|
+
* Both spellings, because the tool has been called each of them across Claude
|
|
22
|
+
* Code versions and a rule for a tool that does not exist costs nothing.
|
|
23
|
+
*/
|
|
24
|
+
const SUBAGENT_TOOL_NAMES = ["Agent", "Task"];
|
|
4
25
|
/**
|
|
5
26
|
* The Claude Agent SDK loads every filesystem settings source it can find when
|
|
6
27
|
* `settingSources` is omitted, and the harness bridge omits it. A local turn
|
|
@@ -21,6 +42,8 @@ import { getConfigDir } from "@cargo-ai/cdk/cli";
|
|
|
21
42
|
*
|
|
22
43
|
* Set `CLAUDE_CONFIG_DIR` to share a config with the `claude` CLI instead —
|
|
23
44
|
* that reinstates the user's hooks and MCP servers, and their startup cost.
|
|
45
|
+
* Nothing is written into a directory named that way: it is the user's, and
|
|
46
|
+
* the settings file in it is theirs to own.
|
|
24
47
|
*/
|
|
25
48
|
export function askClaudeConfigDir() {
|
|
26
49
|
const configured = process.env["CLAUDE_CONFIG_DIR"];
|
|
@@ -29,5 +52,48 @@ export function askClaudeConfigDir() {
|
|
|
29
52
|
}
|
|
30
53
|
const dir = join(getConfigDir(), "ask-claude-config");
|
|
31
54
|
mkdirSync(dir, { recursive: true });
|
|
55
|
+
denySubagentTools(dir);
|
|
32
56
|
return dir;
|
|
33
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Add the subagent deny rules to the settings file in Ask's own config
|
|
60
|
+
* directory, keeping whatever else is in there.
|
|
61
|
+
*
|
|
62
|
+
* Merged rather than written whole, because Claude Code keeps its own state
|
|
63
|
+
* under this directory.
|
|
64
|
+
*
|
|
65
|
+
* A failure here is reported rather than swallowed. There is no second line of
|
|
66
|
+
* defence to fall back on: the approval-time refusal in `isAlwaysDenied` is
|
|
67
|
+
* never reached, which is the whole reason this exists — so a settings file
|
|
68
|
+
* that could not be written means subagents run unattended, and the user is
|
|
69
|
+
* the only one who can tell whether that matters. Reported, not thrown: it
|
|
70
|
+
* must not fail the question they just asked.
|
|
71
|
+
*/
|
|
72
|
+
function denySubagentTools(dir) {
|
|
73
|
+
const path = join(dir, "settings.json");
|
|
74
|
+
try {
|
|
75
|
+
const existing = existsSync(path)
|
|
76
|
+
? JSON.parse(readFileSync(path, "utf-8"))
|
|
77
|
+
: {};
|
|
78
|
+
const settings = typeof existing === "object" && existing !== null
|
|
79
|
+
? existing
|
|
80
|
+
: {};
|
|
81
|
+
const permissionsValue = settings["permissions"];
|
|
82
|
+
const permissions = typeof permissionsValue === "object" && permissionsValue !== null
|
|
83
|
+
? permissionsValue
|
|
84
|
+
: {};
|
|
85
|
+
const denyValue = permissions["deny"];
|
|
86
|
+
const deny = Array.isArray(denyValue) ? denyValue : [];
|
|
87
|
+
const missing = SUBAGENT_TOOL_NAMES.filter((name) => deny.includes(name) === false);
|
|
88
|
+
if (missing.length === 0) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
writeFileSync(path, `${JSON.stringify({
|
|
92
|
+
...settings,
|
|
93
|
+
permissions: { ...permissions, deny: [...deny, ...missing] },
|
|
94
|
+
}, null, 2)}\n`);
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
process.stderr.write(`Could not write ${path}, so subagent tools are not withheld from this session: ${error instanceof Error ? error.message : "unknown error"}\n`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -30,7 +30,7 @@ turns use POST /v1/ai/messages/stream, like the webapp chat).
|
|
|
30
30
|
|
|
31
31
|
Ask continues the palette tree and streams the reply as it arrives:
|
|
32
32
|
◇ your message
|
|
33
|
-
|
|
33
|
+
■ reply
|
|
34
34
|
◆ to type the next line (slash and path suggestions as you type)
|
|
35
35
|
Empty Enter or /exit returns to the menu. Ctrl-C cancels the turn in flight
|
|
36
36
|
and comes back to the prompt. Slash commands (/help, /clear, /new, /agent,
|
|
@@ -25,12 +25,26 @@ export type LocalToolApproval = {
|
|
|
25
25
|
/** A tool starting or finishing, so the caller can show what is happening. */
|
|
26
26
|
export type LocalToolActivity = {
|
|
27
27
|
kind: "start";
|
|
28
|
+
toolCallId: string;
|
|
28
29
|
toolName: string;
|
|
29
30
|
summary: string;
|
|
30
31
|
} | {
|
|
31
32
|
kind: "end";
|
|
33
|
+
toolCallId: string;
|
|
32
34
|
toolName: string;
|
|
33
35
|
isError: boolean;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Announced, then never run — a tool whose input stopped mid-stream, one
|
|
39
|
+
* that was refused, or a sibling whose approval request the harness lost.
|
|
40
|
+
* None of them report a result, so `end` never comes: a caller tracking
|
|
41
|
+
* what is live has to be told, or it shows that tool for the rest of the
|
|
42
|
+
* turn. `retractAbandonedCalls` decides which calls qualify and when.
|
|
43
|
+
*/
|
|
44
|
+
| {
|
|
45
|
+
kind: "dropped";
|
|
46
|
+
toolCallId: string;
|
|
47
|
+
toolName: string;
|
|
34
48
|
};
|
|
35
49
|
export type LocalStreamHandlers = {
|
|
36
50
|
onTextDelta?: (delta: string) => void;
|
|
@@ -49,6 +63,12 @@ export type LocalStreamHandlers = {
|
|
|
49
63
|
export type LocalStreamOptions = LocalStreamHandlers & {
|
|
50
64
|
/** Aborts the turn; the harness interrupts Claude Code gracefully. */
|
|
51
65
|
abortSignal?: AbortSignal;
|
|
66
|
+
/**
|
|
67
|
+
* Fired when the stall watchdog gives up, before the turn is rejected.
|
|
68
|
+
* Should abort `abortSignal` so Claude Code stops rather than being torn
|
|
69
|
+
* down out from under a still-open bridge.
|
|
70
|
+
*/
|
|
71
|
+
onStall?: () => void;
|
|
52
72
|
};
|
|
53
73
|
/**
|
|
54
74
|
* What one turn spent upstream, summed over the streams a suspended turn is
|
|
@@ -197,6 +217,13 @@ export declare function runPromptTurn(input: {
|
|
|
197
217
|
unanswered?: LocalToolApproval[];
|
|
198
218
|
/** Overridden by tests; `Infinity` waits forever. */
|
|
199
219
|
stallTimeoutMs?: number;
|
|
220
|
+
/** The same, for the stream while a tool is executing. */
|
|
221
|
+
toolStallTimeoutMs?: number;
|
|
222
|
+
/**
|
|
223
|
+
* Called when the stall watchdog fires, before the turn is rejected — abort
|
|
224
|
+
* the harness stream so Claude Code does not keep running after we give up.
|
|
225
|
+
*/
|
|
226
|
+
onStall?: () => void;
|
|
200
227
|
}): Promise<string>;
|
|
201
228
|
/**
|
|
202
229
|
* The previous turn could not be wound down, so this session cannot take
|
|
@@ -209,6 +236,20 @@ export declare function runPromptTurn(input: {
|
|
|
209
236
|
export declare class HarnessTurnStuck extends Error {
|
|
210
237
|
constructor();
|
|
211
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* The turn produced nothing for `TURN_STALL_TIMEOUT_MS` while no tool was in
|
|
241
|
+
* flight. Common causes: a step that asked to run several confirmable tools at
|
|
242
|
+
* once (the harness only surfaces one approval), or the Claude Code bridge
|
|
243
|
+
* going silent. Recoverable — replace the session and ask again.
|
|
244
|
+
*/
|
|
245
|
+
export declare class HarnessTurnStalled extends Error {
|
|
246
|
+
constructor(timeoutMs: number, whileToolRunning?: boolean);
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* The Claude Code bridge dropped mid-turn. Same recovery as a stall: the
|
|
250
|
+
* process behind the session is gone, so the next question needs a new one.
|
|
251
|
+
*/
|
|
252
|
+
export declare function isBridgeClosedError(error: unknown): boolean;
|
|
212
253
|
/**
|
|
213
254
|
* Wait for `work`, but give up after `timeoutMs` rather than blocking a
|
|
214
255
|
* teardown forever. Resolves either way; the caller has already decided that
|
|
@@ -221,5 +262,17 @@ export declare function settleWithin(work: Promise<unknown>, timeoutMs: number):
|
|
|
221
262
|
export declare function isAutoApproved(toolName: string): boolean;
|
|
222
263
|
/** Exported for tests. */
|
|
223
264
|
export declare function isAlwaysDenied(toolName: string): boolean;
|
|
265
|
+
/**
|
|
266
|
+
* What Claude Code says the turn cost, off the `finish` part.
|
|
267
|
+
*
|
|
268
|
+
* Two keys, because the value is renamed on its way here: the bridge emits
|
|
269
|
+
* `harnessMetadata`, and `HarnessAgent` republishes the same object as
|
|
270
|
+
* `providerMetadata` on the parts this code actually reads. Looking only for
|
|
271
|
+
* the bridge's name found nothing, so every local turn was ingested at a cost
|
|
272
|
+
* of zero and priced into no credits at all.
|
|
273
|
+
*
|
|
274
|
+
* Exported for tests.
|
|
275
|
+
*/
|
|
276
|
+
export declare function readClaudeCodeCostUsd(part: Record<string, unknown>): number | undefined;
|
|
224
277
|
export {};
|
|
225
278
|
//# sourceMappingURL=localHarness.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localHarness.d.ts","sourceRoot":"","sources":["../../../src/commands/ask/localHarness.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"localHarness.d.ts","sourceRoot":"","sources":["../../../src/commands/ask/localHarness.ts"],"names":[],"mappings":"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"}
|