@cargo-ai/cli 1.0.125 → 1.0.127
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/harness/bridgeOutput.d.ts +19 -0
- package/build/commands/ask/harness/bridgeOutput.d.ts.map +1 -0
- package/build/commands/ask/harness/bridgeOutput.js +42 -0
- package/build/commands/ask/harness/create.d.ts.map +1 -1
- package/build/commands/ask/harness/create.js +2 -1
- package/build/commands/ask/harness/index.d.ts +4 -3
- package/build/commands/ask/harness/index.d.ts.map +1 -1
- package/build/commands/ask/harness/index.js +3 -2
- package/build/commands/ask/harness/toolCallReplay.d.ts +31 -0
- package/build/commands/ask/harness/toolCallReplay.d.ts.map +1 -1
- package/build/commands/ask/harness/toolCallReplay.js +89 -8
- package/build/commands/ask/harness/turn.d.ts +17 -0
- package/build/commands/ask/harness/turn.d.ts.map +1 -1
- package/build/commands/ask/harness/turn.js +85 -3
- package/build/commands/ask/harness/usage.d.ts +19 -0
- package/build/commands/ask/harness/usage.d.ts.map +1 -1
- package/build/commands/ask/harness/usage.js +46 -0
- package/build/commands/ask/input/completer.d.ts +1 -1
- package/build/commands/ask/input/completer.d.ts.map +1 -1
- package/build/commands/ask/input/completer.js +2 -0
- package/build/commands/ask/input/prompt.d.ts.map +1 -1
- package/build/commands/ask/input/prompt.js +54 -8
- package/build/commands/ask/input/slash.d.ts +7 -1
- package/build/commands/ask/input/slash.d.ts.map +1 -1
- package/build/commands/ask/input/slash.js +10 -0
- package/build/commands/ask/session/index.d.ts +2 -1
- package/build/commands/ask/session/index.d.ts.map +1 -1
- package/build/commands/ask/session/index.js +2 -1
- package/build/commands/ask/session/markdown.d.ts +20 -0
- package/build/commands/ask/session/markdown.d.ts.map +1 -0
- package/build/commands/ask/session/markdown.js +451 -0
- package/build/commands/ask/session/run.d.ts.map +1 -1
- package/build/commands/ask/session/run.js +194 -12
- package/build/commands/ask/session/tree.d.ts +81 -0
- package/build/commands/ask/session/tree.d.ts.map +1 -1
- package/build/commands/ask/session/tree.js +322 -51
- package/build/commands/runHandler.d.ts +1 -0
- package/build/commands/runHandler.d.ts.map +1 -1
- package/build/commands/runHandler.js +6 -3
- package/build/utils/textWidth.d.ts +25 -0
- package/build/utils/textWidth.d.ts.map +1 -0
- package/build/utils/textWidth.js +147 -0
- package/package.json +3 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@ai-sdk/harness` copies every line the Claude Code bridge writes to its
|
|
3
|
+
* stderr onto ours, as `[harness:claude-code:stderr] …`, with no option to
|
|
4
|
+
* turn it off. In the middle of a session that lands on the spinner row and
|
|
5
|
+
* breaks the tree: an API retry warning is the usual one.
|
|
6
|
+
*
|
|
7
|
+
* So while a session runs, those lines are taken off stderr and handed to
|
|
8
|
+
* `onLine` instead. `CARGO_ASK_TIMING` leaves them alone, since that is when
|
|
9
|
+
* someone wants to read them. Returns the function that puts stderr back.
|
|
10
|
+
*/
|
|
11
|
+
export declare function interceptBridgeOutput(onLine: (line: string) => void): () => void;
|
|
12
|
+
/**
|
|
13
|
+
* A spinner label for Claude Code retrying a failed API call, or undefined
|
|
14
|
+
* for any other bridge line.
|
|
15
|
+
*
|
|
16
|
+
* Exported for tests.
|
|
17
|
+
*/
|
|
18
|
+
export declare function describeBridgeRetry(line: string): string | undefined;
|
|
19
|
+
//# sourceMappingURL=bridgeOutput.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridgeOutput.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/bridgeOutput.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC7B,MAAM,IAAI,CAoBZ;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAQpE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ASK_TIMING_ENABLED } from "./timing.js";
|
|
2
|
+
/**
|
|
3
|
+
* `@ai-sdk/harness` copies every line the Claude Code bridge writes to its
|
|
4
|
+
* stderr onto ours, as `[harness:claude-code:stderr] …`, with no option to
|
|
5
|
+
* turn it off. In the middle of a session that lands on the spinner row and
|
|
6
|
+
* breaks the tree: an API retry warning is the usual one.
|
|
7
|
+
*
|
|
8
|
+
* So while a session runs, those lines are taken off stderr and handed to
|
|
9
|
+
* `onLine` instead. `CARGO_ASK_TIMING` leaves them alone, since that is when
|
|
10
|
+
* someone wants to read them. Returns the function that puts stderr back.
|
|
11
|
+
*/
|
|
12
|
+
export function interceptBridgeOutput(onLine) {
|
|
13
|
+
if (ASK_TIMING_ENABLED === true) {
|
|
14
|
+
return () => undefined;
|
|
15
|
+
}
|
|
16
|
+
const write = process.stderr.write;
|
|
17
|
+
// The harness writes each forwarded line in a single call, prefix first.
|
|
18
|
+
process.stderr.write = ((chunk, ...rest) => {
|
|
19
|
+
if (typeof chunk === "string" && chunk.startsWith(BRIDGE_PREFIX) === true) {
|
|
20
|
+
onLine(chunk.trimEnd());
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return Reflect.apply(write, process.stderr, [chunk, ...rest]);
|
|
24
|
+
});
|
|
25
|
+
return () => {
|
|
26
|
+
process.stderr.write = write;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* A spinner label for Claude Code retrying a failed API call, or undefined
|
|
31
|
+
* for any other bridge line.
|
|
32
|
+
*
|
|
33
|
+
* Exported for tests.
|
|
34
|
+
*/
|
|
35
|
+
export function describeBridgeRetry(line) {
|
|
36
|
+
const match = line.match(/API retry: attempt (\d+)\/(\d+)/);
|
|
37
|
+
if (match === null || match[1] === undefined || match[2] === undefined) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
return `Retrying the API (${match[1]}/${match[2]})`;
|
|
41
|
+
}
|
|
42
|
+
const BRIDGE_PREFIX = "[harness:";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/create.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAwB3C,OAAO,EAEL,KAAK,kBAAkB,EAKxB,MAAM,WAAW,CAAC;AAGnB,MAAM,MAAM,YAAY,GAAG;IACzB,YAAY,EAAE,CACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAC5C,sEAAsE;IACtE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAcF,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,GAAG,EAAE,GAAG,CAAC;IACT;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,uBAAuB,EAAE,OAAO,CAAC;CAClC,GAAG,OAAO,CAAC,YAAY,CAAC,
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/create.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAwB3C,OAAO,EAEL,KAAK,kBAAkB,EAKxB,MAAM,WAAW,CAAC;AAGnB,MAAM,MAAM,YAAY,GAAG;IACzB,YAAY,EAAE,CACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,kBAAkB,KACzB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAC5C,sEAAsE;IACtE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B,CAAC;AAcF,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,GAAG,EAAE,GAAG,CAAC;IACT;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,uBAAuB,EAAE,OAAO,CAAC;CAClC,GAAG,OAAO,CAAC,YAAY,CAAC,CAiVxB"}
|
|
@@ -64,7 +64,8 @@ export async function createLocalHarness(input) {
|
|
|
64
64
|
// createClaudeCode auto-detect AI Gateway from the host process and ignore
|
|
65
65
|
// the Cargo proxy.
|
|
66
66
|
// Wrapped so a batched tool call stays known to the stream that is asked to
|
|
67
|
-
// approve it
|
|
67
|
+
// approve it, and a second approval asked at the same time reaches the next
|
|
68
|
+
// stream instead of one nobody reads (see `toolCallReplay.ts`).
|
|
68
69
|
const claudeCode = withToolCallReplay(createClaudeCode({
|
|
69
70
|
auth: {
|
|
70
71
|
ANTHROPIC_BASE_URL: anthropicBaseUrl,
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
export { isAlwaysDenied, isAutoApproved } from "./approvals.js";
|
|
2
2
|
export { ASK_USER_QUESTION_DENIED_REASON, ASK_USER_QUESTION_MISSING_INPUT_REASON, ASK_USER_QUESTION_TOOL_NAME, buildAskUserQuestionHostTool, denyNativeAskUserQuestion, formatAskUserQuestionAnswers, readAskUserQuestions, summarizeAskUserQuestion, } from "./askUserQuestion.js";
|
|
3
|
+
export { describeBridgeRetry, interceptBridgeOutput } from "./bridgeOutput.js";
|
|
3
4
|
export { createLocalHarness, type LocalHarness } from "./create.js";
|
|
4
5
|
export { localHarnessInstructions, localHarnessSkills, } from "./instructions.js";
|
|
5
6
|
export { resolveWorkspaceLayout } from "./layout.js";
|
|
6
7
|
export { CARGO_MCP_SERVER_NAME } from "./mcp.js";
|
|
7
|
-
export { replayKnownToolCalls, withToolCallReplay, wrapSession, } from "./toolCallReplay.js";
|
|
8
|
-
export { HarnessTurnStalled, HarnessTurnStuck, isBridgeClosedError, type LocalStreamHandlers, type LocalStreamOptions, type LocalToolActivity, type LocalToolApproval, runPromptTurn, settleWithin, type StreamLike, type TurnDriver, } from "./turn.js";
|
|
9
|
-
export { createTurnAccumulator, type LocalTurnAccumulator, type LocalTurnUsage, readClaudeCodeCostUsd, } from "./usage.js";
|
|
8
|
+
export { replayKnownToolCalls, routeSessionEvents, withToolCallReplay, wrapSession, } from "./toolCallReplay.js";
|
|
9
|
+
export { HarnessTurnStalled, HarnessTurnStuck, isBridgeClosedError, type LocalStreamHandlers, type LocalStreamOptions, type LocalToolActivity, type LocalToolApproval, type LocalUsageUpdate, runPromptTurn, settleWithin, type StreamLike, type TurnDriver, } from "./turn.js";
|
|
10
|
+
export { createTurnAccumulator, creditsForStep, type LocalTurnAccumulator, type LocalTurnUsage, readClaudeCodeCostUsd, } from "./usage.js";
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EACL,+BAA+B,EAC/B,sCAAsC,EACtC,2BAA2B,EAC3B,4BAA4B,EAC5B,yBAAyB,EACzB,4BAA4B,EAC5B,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,aAAa,EACb,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EACL,+BAA+B,EAC/B,sCAAsC,EACtC,2BAA2B,EAC3B,4BAA4B,EAC5B,yBAAyB,EACzB,4BAA4B,EAC5B,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EACL,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,aAAa,EACb,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
export { isAlwaysDenied, isAutoApproved } from "./approvals.js";
|
|
2
2
|
export { ASK_USER_QUESTION_DENIED_REASON, ASK_USER_QUESTION_MISSING_INPUT_REASON, ASK_USER_QUESTION_TOOL_NAME, buildAskUserQuestionHostTool, denyNativeAskUserQuestion, formatAskUserQuestionAnswers, readAskUserQuestions, summarizeAskUserQuestion, } from "./askUserQuestion.js";
|
|
3
|
+
export { describeBridgeRetry, interceptBridgeOutput } from "./bridgeOutput.js";
|
|
3
4
|
export { createLocalHarness } from "./create.js";
|
|
4
5
|
export { localHarnessInstructions, localHarnessSkills, } from "./instructions.js";
|
|
5
6
|
export { resolveWorkspaceLayout } from "./layout.js";
|
|
6
7
|
export { CARGO_MCP_SERVER_NAME } from "./mcp.js";
|
|
7
|
-
export { replayKnownToolCalls, withToolCallReplay, wrapSession, } from "./toolCallReplay.js";
|
|
8
|
+
export { replayKnownToolCalls, routeSessionEvents, withToolCallReplay, wrapSession, } from "./toolCallReplay.js";
|
|
8
9
|
export { HarnessTurnStalled, HarnessTurnStuck, isBridgeClosedError, runPromptTurn, settleWithin, } from "./turn.js";
|
|
9
|
-
export { createTurnAccumulator, readClaudeCodeCostUsd, } from "./usage.js";
|
|
10
|
+
export { createTurnAccumulator, creditsForStep, readClaudeCodeCostUsd, } from "./usage.js";
|
|
@@ -15,11 +15,42 @@
|
|
|
15
15
|
* own `emit`, so the session remembers every tool call and replays one into a
|
|
16
16
|
* stream that is about to receive an approval for a call it never saw. Remove
|
|
17
17
|
* this once the agent keeps tool calls for the session.
|
|
18
|
+
*
|
|
19
|
+
* The same batch also loses events outright, which is the stall
|
|
20
|
+
* `HarnessTurnStalled` reports. The agent stops reading a stream at the first
|
|
21
|
+
* approval request in it, but the adapter keeps that stream's listener on the
|
|
22
|
+
* bridge until the turn's `finish`, so whatever the bridge says next goes into
|
|
23
|
+
* a stream nobody reads. When Claude Code asks about two tools at once, the
|
|
24
|
+
* second request lands there: the next stream never hears of it, Claude Code
|
|
25
|
+
* waits for an answer, and the turn waits for output. `routeSessionEvents`
|
|
26
|
+
* holds those events and hands them to the next stream instead.
|
|
18
27
|
*/
|
|
19
28
|
import type { HarnessV1, HarnessV1Session, HarnessV1StreamPart } from "@ai-sdk/harness";
|
|
20
29
|
type Emit = (event: HarnessV1StreamPart) => void;
|
|
21
30
|
/** Exported for tests: one stream's `emit`, fed from a session-wide memory. */
|
|
22
31
|
export declare function replayKnownToolCalls(known: Map<string, HarnessV1StreamPart>, emit: Emit): Emit;
|
|
32
|
+
/**
|
|
33
|
+
* Exported for tests: delivers every bridge event of a session once, to the
|
|
34
|
+
* stream the agent is still reading.
|
|
35
|
+
*
|
|
36
|
+
* Each stream's listener stays on the bridge after the agent is done with it,
|
|
37
|
+
* so one event reaches every listener still attached — the same object each
|
|
38
|
+
* time, which is what lets it be delivered once. It goes to the stream opened
|
|
39
|
+
* last. Once that stream has carried an approval request the agent has
|
|
40
|
+
* stopped reading it, so the rest is also held, in order, and opening the next
|
|
41
|
+
* stream hands it over.
|
|
42
|
+
*
|
|
43
|
+
* Held events are still delivered to the stopped stream, so if the agent ever
|
|
44
|
+
* does read past an approval, it misses nothing; it would see them twice.
|
|
45
|
+
*/
|
|
46
|
+
export declare function routeSessionEvents(): {
|
|
47
|
+
/** The `emit` every stream hands the bridge, current or not. */
|
|
48
|
+
listen: () => Emit;
|
|
49
|
+
/** A new stream is about to be read: send it everything held. */
|
|
50
|
+
open: (emit: Emit, options: {
|
|
51
|
+
freshTurn: boolean;
|
|
52
|
+
}) => void;
|
|
53
|
+
};
|
|
23
54
|
/** Exported for tests. */
|
|
24
55
|
export declare function wrapSession(session: HarnessV1Session): HarnessV1Session;
|
|
25
56
|
/** The harness, with every session it starts keeping its tool calls. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolCallReplay.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/toolCallReplay.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"toolCallReplay.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/toolCallReplay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,gBAAgB,EAChB,mBAAmB,EACpB,MAAM,iBAAiB,CAAC;AAEzB,KAAK,IAAI,GAAG,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;AAEjD,+EAA+E;AAC/E,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,EACvC,IAAI,EAAE,IAAI,GACT,IAAI,CAqBN;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,IAAI;IACpC,gEAAgE;IAChE,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,iEAAiE;IACjE,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CAC7D,CAsDA;AAED,0BAA0B;AAC1B,wBAAgB,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,gBAAgB,CA4CvE;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,CAKhE"}
|
|
@@ -15,6 +15,15 @@
|
|
|
15
15
|
* own `emit`, so the session remembers every tool call and replays one into a
|
|
16
16
|
* stream that is about to receive an approval for a call it never saw. Remove
|
|
17
17
|
* this once the agent keeps tool calls for the session.
|
|
18
|
+
*
|
|
19
|
+
* The same batch also loses events outright, which is the stall
|
|
20
|
+
* `HarnessTurnStalled` reports. The agent stops reading a stream at the first
|
|
21
|
+
* approval request in it, but the adapter keeps that stream's listener on the
|
|
22
|
+
* bridge until the turn's `finish`, so whatever the bridge says next goes into
|
|
23
|
+
* a stream nobody reads. When Claude Code asks about two tools at once, the
|
|
24
|
+
* second request lands there: the next stream never hears of it, Claude Code
|
|
25
|
+
* waits for an answer, and the turn waits for output. `routeSessionEvents`
|
|
26
|
+
* holds those events and hands them to the next stream instead.
|
|
18
27
|
*/
|
|
19
28
|
/** Exported for tests: one stream's `emit`, fed from a session-wide memory. */
|
|
20
29
|
export function replayKnownToolCalls(known, emit) {
|
|
@@ -35,17 +44,89 @@ export function replayKnownToolCalls(known, emit) {
|
|
|
35
44
|
emit(event);
|
|
36
45
|
};
|
|
37
46
|
}
|
|
47
|
+
/**
|
|
48
|
+
* Exported for tests: delivers every bridge event of a session once, to the
|
|
49
|
+
* stream the agent is still reading.
|
|
50
|
+
*
|
|
51
|
+
* Each stream's listener stays on the bridge after the agent is done with it,
|
|
52
|
+
* so one event reaches every listener still attached — the same object each
|
|
53
|
+
* time, which is what lets it be delivered once. It goes to the stream opened
|
|
54
|
+
* last. Once that stream has carried an approval request the agent has
|
|
55
|
+
* stopped reading it, so the rest is also held, in order, and opening the next
|
|
56
|
+
* stream hands it over.
|
|
57
|
+
*
|
|
58
|
+
* Held events are still delivered to the stopped stream, so if the agent ever
|
|
59
|
+
* does read past an approval, it misses nothing; it would see them twice.
|
|
60
|
+
*/
|
|
61
|
+
export function routeSessionEvents() {
|
|
62
|
+
const delivered = new WeakSet();
|
|
63
|
+
const held = [];
|
|
64
|
+
const current = {
|
|
65
|
+
emit: undefined,
|
|
66
|
+
stopped: false,
|
|
67
|
+
};
|
|
68
|
+
const deliver = (event) => {
|
|
69
|
+
if (current.emit === undefined) {
|
|
70
|
+
held.push(event);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (current.stopped === true) {
|
|
74
|
+
held.push(event);
|
|
75
|
+
}
|
|
76
|
+
current.emit(event);
|
|
77
|
+
// The agent ends the stream right here to ask; nothing after this in
|
|
78
|
+
// the same stream is read.
|
|
79
|
+
if (event.type === "tool-approval-request") {
|
|
80
|
+
current.stopped = true;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
listen: () => (event) => {
|
|
85
|
+
if (delivered.has(event) === true) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
delivered.add(event);
|
|
89
|
+
deliver(event);
|
|
90
|
+
},
|
|
91
|
+
open: (emit, options) => {
|
|
92
|
+
current.emit = emit;
|
|
93
|
+
current.stopped = false;
|
|
94
|
+
const backlog = held.splice(0, held.length);
|
|
95
|
+
// A new prompt replaces whatever the bridge was still doing, so what
|
|
96
|
+
// the last turn left behind belongs to nobody.
|
|
97
|
+
if (options.freshTurn === true) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
for (const event of backlog) {
|
|
101
|
+
deliver(event);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
38
106
|
/** Exported for tests. */
|
|
39
107
|
export function wrapSession(session) {
|
|
40
108
|
const known = new Map();
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
109
|
+
const router = routeSessionEvents();
|
|
110
|
+
const doPromptTurn = (options) => {
|
|
111
|
+
router.open(replayKnownToolCalls(known, options.emit), {
|
|
112
|
+
freshTurn: true,
|
|
113
|
+
});
|
|
114
|
+
return session.doPromptTurn({
|
|
115
|
+
...options,
|
|
116
|
+
emit: router.listen(),
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
const doContinueTurn = (options) => {
|
|
120
|
+
// Opened before the adapter wires the stream: its emit already queues,
|
|
121
|
+
// and anything the bridge says in between belongs to this stream too.
|
|
122
|
+
router.open(replayKnownToolCalls(known, options.emit), {
|
|
123
|
+
freshTurn: false,
|
|
124
|
+
});
|
|
125
|
+
return session.doContinueTurn({
|
|
126
|
+
...options,
|
|
127
|
+
emit: router.listen(),
|
|
128
|
+
});
|
|
129
|
+
};
|
|
49
130
|
// A proxy rather than a spread or a prototype: a session may be a class
|
|
50
131
|
// with private state, so every other member is read from it and its methods
|
|
51
132
|
// run bound to it.
|
|
@@ -23,6 +23,8 @@ export type LocalToolActivity = {
|
|
|
23
23
|
toolCallId: string;
|
|
24
24
|
toolName: string;
|
|
25
25
|
isError: boolean;
|
|
26
|
+
/** What the tool returned, or its error, as text. Capped in length. */
|
|
27
|
+
output: string;
|
|
26
28
|
}
|
|
27
29
|
/**
|
|
28
30
|
* Announced, then never run — a tool whose input stopped mid-stream, one
|
|
@@ -36,8 +38,23 @@ export type LocalToolActivity = {
|
|
|
36
38
|
toolCallId: string;
|
|
37
39
|
toolName: string;
|
|
38
40
|
};
|
|
41
|
+
/**
|
|
42
|
+
* Tokens one model call used (`step`) or one stream used in total (`stream`).
|
|
43
|
+
* A step's input is the whole context it was sent, which is how full the
|
|
44
|
+
* window is.
|
|
45
|
+
*/
|
|
46
|
+
export type LocalUsageUpdate = {
|
|
47
|
+
scope: "step" | "stream";
|
|
48
|
+
inputTokens: number;
|
|
49
|
+
/** The part of `inputTokens` served from the prompt cache. */
|
|
50
|
+
cacheReadTokens: number;
|
|
51
|
+
outputTokens: number;
|
|
52
|
+
};
|
|
39
53
|
export type LocalStreamHandlers = {
|
|
40
54
|
onTextDelta?: (delta: string) => void;
|
|
55
|
+
/** Claude Code's summarized thinking, as it streams. */
|
|
56
|
+
onReasoningDelta?: (delta: string) => void;
|
|
57
|
+
onUsage?: (usage: LocalUsageUpdate) => void;
|
|
41
58
|
/**
|
|
42
59
|
* Decide whether the tool may run. Omitted (`--print`, non-interactive)
|
|
43
60
|
* means deny — the turn continues and the model reports what it could not
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/turn.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,IAAI,CAAC;AAa/C,OAAO,EAGL,KAAK,oBAAoB,
|
|
1
|
+
{"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/turn.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DENIED_TOOL_REASON, isAlwaysDenied, isAutoApproved, } from "./approvals.js";
|
|
2
2
|
import { ASK_USER_QUESTION_DENIED_REASON, ASK_USER_QUESTION_TOOL_NAME, formatAskUserQuestionAnswers, summarizeAskUserQuestion, } from "./askUserQuestion.js";
|
|
3
|
-
import { addTurnUsage, createTurnAccumulator, } from "./usage.js";
|
|
3
|
+
import { addTurnUsage, createTurnAccumulator, readUsageTokens, } from "./usage.js";
|
|
4
4
|
/**
|
|
5
5
|
* How many times one turn may suspend for approvals. Each round trip is a
|
|
6
6
|
* decision the user made, so this is only a stop for a harness that keeps
|
|
@@ -464,6 +464,7 @@ async function consumeTurn(input) {
|
|
|
464
464
|
toolCallId,
|
|
465
465
|
toolName: recorded === undefined ? "tool" : recorded.toolName,
|
|
466
466
|
isError,
|
|
467
|
+
output: readToolOutputText(part),
|
|
467
468
|
});
|
|
468
469
|
}
|
|
469
470
|
if (typeof toolCallId === "string" && preliminary === false) {
|
|
@@ -487,9 +488,33 @@ async function consumeTurn(input) {
|
|
|
487
488
|
}
|
|
488
489
|
if (part["type"] === "finish") {
|
|
489
490
|
// One suspended turn is several streams, each ending with its own
|
|
490
|
-
// `finish` — all of them count. Per-step parts
|
|
491
|
-
// tokens are not counted twice.
|
|
491
|
+
// `finish` — all of them count. Per-step parts stay out of the turn's
|
|
492
|
+
// usage so the same tokens are not counted twice.
|
|
492
493
|
addTurnUsage(input.accumulator, part);
|
|
494
|
+
const totals = readUsageTokens(part["totalUsage"]);
|
|
495
|
+
if (totals !== undefined && handlers.onUsage !== undefined) {
|
|
496
|
+
handlers.onUsage({ scope: "stream", ...totals });
|
|
497
|
+
}
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (part["type"] === "finish-step") {
|
|
501
|
+
const step = readUsageTokens(part["usage"]);
|
|
502
|
+
if (step !== undefined && handlers.onUsage !== undefined) {
|
|
503
|
+
handlers.onUsage({ scope: "step", ...step });
|
|
504
|
+
}
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
if (part["type"] === "reasoning-delta") {
|
|
508
|
+
const text = typeof part["text"] === "string"
|
|
509
|
+
? part["text"]
|
|
510
|
+
: typeof part["delta"] === "string"
|
|
511
|
+
? part["delta"]
|
|
512
|
+
: undefined;
|
|
513
|
+
if (text !== undefined &&
|
|
514
|
+
text.length > 0 &&
|
|
515
|
+
handlers.onReasoningDelta !== undefined) {
|
|
516
|
+
handlers.onReasoningDelta(text);
|
|
517
|
+
}
|
|
493
518
|
continue;
|
|
494
519
|
}
|
|
495
520
|
if (part["type"] === "tool-approval-request") {
|
|
@@ -666,3 +691,60 @@ function isToolErrorPart(part) {
|
|
|
666
691
|
part["type"] === "tool-output-error" ||
|
|
667
692
|
part["type"] === "tool-output-denied");
|
|
668
693
|
}
|
|
694
|
+
/** Where a finished tool part may carry its result, most specific first. */
|
|
695
|
+
const TOOL_OUTPUT_FIELDS = ["errorText", "error", "output", "result"];
|
|
696
|
+
/** Enough of a tool's output to preview; the rest is never shown. */
|
|
697
|
+
const TOOL_OUTPUT_MAX_LENGTH = 4_000;
|
|
698
|
+
/**
|
|
699
|
+
* A finished tool's result as text, for the transcript. Built-in tools return
|
|
700
|
+
* a string; MCP tools return content blocks; a failure carries an error.
|
|
701
|
+
*/
|
|
702
|
+
function readToolOutputText(part) {
|
|
703
|
+
if (part["type"] === "tool-output-denied") {
|
|
704
|
+
return "Denied.";
|
|
705
|
+
}
|
|
706
|
+
// The first field with something in it. The UI stream spells the error
|
|
707
|
+
// `errorText`; older AI SDK parts used `result` for `output`. Presence is
|
|
708
|
+
// not enough: an empty `error` must not hide a real `output`.
|
|
709
|
+
const text = TOOL_OUTPUT_FIELDS.map((field) => toolValueText(part[field])).find((candidate) => candidate.trim() !== "");
|
|
710
|
+
if (text === undefined) {
|
|
711
|
+
return "";
|
|
712
|
+
}
|
|
713
|
+
return text.length > TOOL_OUTPUT_MAX_LENGTH
|
|
714
|
+
? `${text.slice(0, TOOL_OUTPUT_MAX_LENGTH)}…`
|
|
715
|
+
: text;
|
|
716
|
+
}
|
|
717
|
+
function toolValueText(value) {
|
|
718
|
+
if (value === undefined || value === null) {
|
|
719
|
+
return "";
|
|
720
|
+
}
|
|
721
|
+
if (typeof value === "string") {
|
|
722
|
+
return value;
|
|
723
|
+
}
|
|
724
|
+
if (value instanceof Error) {
|
|
725
|
+
return value.message;
|
|
726
|
+
}
|
|
727
|
+
if (Array.isArray(value)) {
|
|
728
|
+
return value.map(toolValueText).join("\n");
|
|
729
|
+
}
|
|
730
|
+
if (typeof value === "object") {
|
|
731
|
+
const record = value;
|
|
732
|
+
// `{ type: "text", text }` content blocks, and the AI SDK's
|
|
733
|
+
// `{ type: "text", value }` tool output.
|
|
734
|
+
if (typeof record["text"] === "string") {
|
|
735
|
+
return record["text"];
|
|
736
|
+
}
|
|
737
|
+
if (record["type"] === "text" && typeof record["value"] === "string") {
|
|
738
|
+
return record["value"];
|
|
739
|
+
}
|
|
740
|
+
if (Array.isArray(record["content"])) {
|
|
741
|
+
return toolValueText(record["content"]);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
try {
|
|
745
|
+
return JSON.stringify(value, null, 2);
|
|
746
|
+
}
|
|
747
|
+
catch {
|
|
748
|
+
return "";
|
|
749
|
+
}
|
|
750
|
+
}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credits the proxy bills for one model call, rounded up to the hundredth
|
|
3
|
+
* per call as it does. `inputTokens` is the whole prompt; cache writes are
|
|
4
|
+
* charged as plain input.
|
|
5
|
+
*/
|
|
6
|
+
export declare function creditsForStep(tokens: {
|
|
7
|
+
inputTokens: number;
|
|
8
|
+
cacheReadTokens: number;
|
|
9
|
+
outputTokens: number;
|
|
10
|
+
}): number;
|
|
1
11
|
/**
|
|
2
12
|
* What one turn spent upstream, summed over the streams a suspended turn is
|
|
3
13
|
* made of. `costUsd` is Claude Code's own accounting; the API stores it on
|
|
@@ -41,6 +51,15 @@ export declare function didReachAnthropic(usage: LocalTurnUsage): boolean;
|
|
|
41
51
|
* cost is stored on the ingested message.
|
|
42
52
|
*/
|
|
43
53
|
export declare function addTurnUsage(accumulator: LocalTurnAccumulator, part: Record<string, unknown>): void;
|
|
54
|
+
/**
|
|
55
|
+
* Input and output tokens off an AI SDK usage object, or undefined when the
|
|
56
|
+
* part carries none. Input is the whole prompt, cached or not.
|
|
57
|
+
*/
|
|
58
|
+
export declare function readUsageTokens(value: unknown): {
|
|
59
|
+
inputTokens: number;
|
|
60
|
+
cacheReadTokens: number;
|
|
61
|
+
outputTokens: number;
|
|
62
|
+
} | undefined;
|
|
44
63
|
/**
|
|
45
64
|
* What Claude Code says the turn cost, off the `finish` part.
|
|
46
65
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/usage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/usage.ts"],"names":[],"mappings":"AAeA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,MAAM,CAWT;AAED;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,cAAc,CAAC;IACtB;;;OAGG;IACH,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAgB,qBAAqB,CACnC,mBAAmB,EAAE,MAAM,GAC1B,oBAAoB,CActB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAEhE;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,oBAAoB,EACjC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,IAAI,CAwCN;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,OAAO,GAEZ;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACtE,SAAS,CAkBZ;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,GAAG,SAAS,CA0BpB"}
|
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What one Cargo credit is worth, and what the sandbox proxy charges per
|
|
3
|
+
* million tokens. Mirrors `USD_PER_CREDIT` and
|
|
4
|
+
* `ANTHROPIC_FALLBACK_RATES_USD_PER_MILLION` in the backend's harness usage:
|
|
5
|
+
* the proxy prices each request from these, not from Claude Code's own cost,
|
|
6
|
+
* so the credits shown after a turn have to use them too.
|
|
7
|
+
*/
|
|
8
|
+
const USD_PER_CREDIT = 0.04;
|
|
9
|
+
const PROXY_RATES_USD_PER_MILLION = {
|
|
10
|
+
input: 3,
|
|
11
|
+
output: 15,
|
|
12
|
+
cacheRead: 0.3,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Credits the proxy bills for one model call, rounded up to the hundredth
|
|
16
|
+
* per call as it does. `inputTokens` is the whole prompt; cache writes are
|
|
17
|
+
* charged as plain input.
|
|
18
|
+
*/
|
|
19
|
+
export function creditsForStep(tokens) {
|
|
20
|
+
const usdPerMillion = Math.max(tokens.inputTokens - tokens.cacheReadTokens, 0) *
|
|
21
|
+
PROXY_RATES_USD_PER_MILLION.input +
|
|
22
|
+
tokens.cacheReadTokens * PROXY_RATES_USD_PER_MILLION.cacheRead +
|
|
23
|
+
tokens.outputTokens * PROXY_RATES_USD_PER_MILLION.output;
|
|
24
|
+
const credits = usdPerMillion / 1_000_000 / USD_PER_CREDIT;
|
|
25
|
+
// `toFixed` first, as the backend does, so float noise cannot round an
|
|
26
|
+
// exact hundredth up by one.
|
|
27
|
+
return Math.ceil(Number((credits * 100).toFixed(6))) / 100;
|
|
28
|
+
}
|
|
1
29
|
export function createTurnAccumulator(lastReportedCostUsd) {
|
|
2
30
|
return {
|
|
3
31
|
chunks: [],
|
|
@@ -57,6 +85,24 @@ export function addTurnUsage(accumulator, part) {
|
|
|
57
85
|
usage.reasoningTokens += readCount(details["reasoningTokens"]);
|
|
58
86
|
}
|
|
59
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Input and output tokens off an AI SDK usage object, or undefined when the
|
|
90
|
+
* part carries none. Input is the whole prompt, cached or not.
|
|
91
|
+
*/
|
|
92
|
+
export function readUsageTokens(value) {
|
|
93
|
+
if (typeof value !== "object" || value === null) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
const usage = value;
|
|
97
|
+
const inputDetails = usage["inputTokenDetails"];
|
|
98
|
+
return {
|
|
99
|
+
inputTokens: readCount(usage["inputTokens"]),
|
|
100
|
+
cacheReadTokens: typeof inputDetails === "object" && inputDetails !== null
|
|
101
|
+
? readCount(inputDetails["cacheReadTokens"])
|
|
102
|
+
: 0,
|
|
103
|
+
outputTokens: readCount(usage["outputTokens"]),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
60
106
|
function readCount(value) {
|
|
61
107
|
return typeof value === "number" && Number.isFinite(value) && value > 0
|
|
62
108
|
? value
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Chat slash commands offered on Tab when the line is `/…`. */
|
|
2
|
-
export declare const ASK_SLASH_COMMANDS: readonly ["/help", "/clear", "/new", "/agent", "/cancel", "/exit"];
|
|
2
|
+
export declare const ASK_SLASH_COMMANDS: readonly ["/help", "/clear", "/new", "/agent", "/tools", "/reasoning", "/cancel", "/exit"];
|
|
3
3
|
export type AskCompleter = (line: string) => [string[], string];
|
|
4
4
|
/** What a `/…` token turned out to be. */
|
|
5
5
|
export type SlashTokenKind = "command" | "path" | "unknown";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"completer.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/input/completer.ts"],"names":[],"mappings":"AAYA,gEAAgE;AAChE,eAAO,MAAM,kBAAkB,
|
|
1
|
+
{"version":3,"file":"completer.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/input/completer.ts"],"names":[],"mappings":"AAYA,gEAAgE;AAChE,eAAO,MAAM,kBAAkB,4FASrB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC;AAEhE,0CAA0C;AAC1C,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,CAgBhE;AAED,sDAAsD;AACtD,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAU5D;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CASnE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAYxE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,GAAG,SAAS,CAY1E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,EAAE,MAAM,CAAC,CAwE1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/input/prompt.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/input/prompt.ts"],"names":[],"mappings":";AAkBA;;;;;;GAMG;AACH,qBAAa,cAAe,SAAQ,KAAK;;CAKxC;AASD;;;;;;GAMG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,MAAM,CAAC,cAAc,EAC5B,GAAG,EAAE,MAAM;AACX;;;;GAIG;AACH,WAAW,SAAK,GACf,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA+R7B"}
|