@cargo-ai/cli 1.0.133 → 1.0.134
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/session/index.d.ts +1 -1
- package/build/commands/ask/session/index.d.ts.map +1 -1
- package/build/commands/ask/session/index.js +1 -1
- package/build/commands/ask/session/run.d.ts.map +1 -1
- package/build/commands/ask/session/run.js +7 -3
- package/build/commands/ask/session/tree.d.ts +30 -0
- package/build/commands/ask/session/tree.d.ts.map +1 -1
- package/build/commands/ask/session/tree.js +91 -17
- package/package.json +1 -1
|
@@ -2,5 +2,5 @@ export { type ChatTurnClaim, claimChatTurn, proxyTokenDeadlineMs, } from "./clai
|
|
|
2
2
|
export { renderMarkdown } from "./markdown.js";
|
|
3
3
|
export { type AskSessionOptions, doesChatExist, runAskPrint, runAskSession, } from "./run.js";
|
|
4
4
|
export { ASK_THINKING_WORDS, pickThinkingWord } from "./thinking.js";
|
|
5
|
-
export { displayPath, showTurnStats, wrapLine } from "./tree.js";
|
|
5
|
+
export { approvalMessage, displayPath, foldUserTurn, showTurnStats, wrapLine, } from "./tree.js";
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,aAAa,EACb,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,KAAK,iBAAiB,EACtB,aAAa,EACb,WAAW,EACX,aAAa,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/session/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,aAAa,EAClB,aAAa,EACb,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EACL,KAAK,iBAAiB,EACtB,aAAa,EACb,WAAW,EACX,aAAa,GACd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACrE,OAAO,EACL,eAAe,EACf,WAAW,EACX,YAAY,EACZ,aAAa,EACb,QAAQ,GACT,MAAM,WAAW,CAAC"}
|
|
@@ -2,4 +2,4 @@ export { claimChatTurn, proxyTokenDeadlineMs, } from "./claim.js";
|
|
|
2
2
|
export { renderMarkdown } from "./markdown.js";
|
|
3
3
|
export { doesChatExist, runAskPrint, runAskSession, } from "./run.js";
|
|
4
4
|
export { ASK_THINKING_WORDS, pickThinkingWord } from "./thinking.js";
|
|
5
|
-
export { displayPath, showTurnStats, wrapLine } from "./tree.js";
|
|
5
|
+
export { approvalMessage, displayPath, foldUserTurn, showTurnStats, wrapLine, } from "./tree.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/session/run.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/session/run.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAmE3C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,EAAE,GAAG,CAAC;IACT,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAwHF;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,OAAO,CAAC,CAqBlB;AAyND;;;;;;GAMG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,SAAS,GAAG,MAAM,CAAC,CAg0B7B;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE;IACvC,GAAG,EAAE,GAAG,CAAC;IACT,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;CACb,GAAG,OAAO,CAAC,IAAI,CAAC,CAqGhB"}
|
|
@@ -13,7 +13,7 @@ import { saveAskState } from "../persist/persist.js";
|
|
|
13
13
|
import { ASK_STATE_VERSION } from "../persist/state.js";
|
|
14
14
|
import { claimChatTurn, proxyTokenDeadlineMs, releaseChatTurn, reportApiFailure, } from "./claim.js";
|
|
15
15
|
import { pickThinkingWord } from "./thinking.js";
|
|
16
|
-
import { appendAssistantDelta, appendReasoningDelta, askToolApproval, askUserQuestions, beginAssistantTurn, beginReasoning, describeToolActivity, endAssistantTurn, endReasoning, REASONING_DISPLAYS, setAssistantFooter, setReasoningFooter, showAssistantTurn, showCard, showNotices, showToolGroup, showToolRun, showTouchedFiles, showTurnStats, showUserTurn, TOOL_DISPLAYS, } from "./tree.js";
|
|
16
|
+
import { appendAssistantDelta, appendReasoningDelta, askToolApproval, askUserQuestions, beginAssistantTurn, beginReasoning, describeToolActivity, endAssistantTurn, endReasoning, isCountOnlyTool, REASONING_DISPLAYS, setAssistantFooter, setReasoningFooter, showAssistantTurn, showCard, showNotices, showToolGroup, showToolRun, showTouchedFiles, showTurnStats, showUserTurn, TOOL_DISPLAYS, } from "./tree.js";
|
|
17
17
|
function requireInteractive() {
|
|
18
18
|
if (isInteractive() === false || process.stdout.isTTY !== true) {
|
|
19
19
|
failWith("Ask needs a terminal. Re-run with --print for one JSON turn.", {
|
|
@@ -557,7 +557,9 @@ export async function runAskSession(options) {
|
|
|
557
557
|
};
|
|
558
558
|
const flushToolRun = () => {
|
|
559
559
|
const [only] = toolRun.summaries;
|
|
560
|
-
if (toolRun.summaries.length === 1 &&
|
|
560
|
+
if (toolRun.summaries.length === 1 &&
|
|
561
|
+
only !== undefined &&
|
|
562
|
+
isCountOnlyTool(toolRun.toolName) === false) {
|
|
561
563
|
showToolRun({
|
|
562
564
|
spinner,
|
|
563
565
|
toolName: toolRun.toolName,
|
|
@@ -567,7 +569,9 @@ export async function runAskSession(options) {
|
|
|
567
569
|
display: "collapsed",
|
|
568
570
|
});
|
|
569
571
|
}
|
|
570
|
-
else if (toolRun.summaries.length >
|
|
572
|
+
else if (toolRun.summaries.length > 0) {
|
|
573
|
+
// Two or more of a tool, or one read, which is counted rather than
|
|
574
|
+
// named: `Read 1 file`.
|
|
571
575
|
showToolGroup({
|
|
572
576
|
spinner,
|
|
573
577
|
toolName: toolRun.toolName,
|
|
@@ -19,6 +19,26 @@ export declare function showCard(body: string): void;
|
|
|
19
19
|
* `◇ ask hey --continue`. No "You" label.
|
|
20
20
|
*/
|
|
21
21
|
export declare function showUserTurn(body: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* A message of more than a few lines, folded to its start and its length:
|
|
24
|
+
*
|
|
25
|
+
* ◇ /cargo-project Set up the `tam-building` cookbook with… [81 lines]
|
|
26
|
+
*
|
|
27
|
+
* The person already knows what they sent, and a message that long was
|
|
28
|
+
* pasted or handed over (the brief `cargo-ai project init` passes when it
|
|
29
|
+
* opens this chat) rather than typed. Printed whole, a brief fills the screen
|
|
30
|
+
* above the reply it asked for, with its lists run together into one block by
|
|
31
|
+
* the wrap. Claude Code folds a paste the same way.
|
|
32
|
+
*
|
|
33
|
+
* Counted in the message's own lines, not in rows: a long paragraph typed in
|
|
34
|
+
* one go is one line, and it is shown whole.
|
|
35
|
+
*
|
|
36
|
+
* Exported for tests.
|
|
37
|
+
*/
|
|
38
|
+
export declare function foldUserTurn(body: string, width: number): {
|
|
39
|
+
text: string;
|
|
40
|
+
suffix: string;
|
|
41
|
+
} | undefined;
|
|
22
42
|
export type LiveAssistantTurn = {
|
|
23
43
|
buffer: string;
|
|
24
44
|
/**
|
|
@@ -143,6 +163,7 @@ export declare function showToolGroup(input: {
|
|
|
143
163
|
toolName: string;
|
|
144
164
|
summaries: readonly string[];
|
|
145
165
|
}): void;
|
|
166
|
+
export declare function isCountOnlyTool(toolName: string): boolean;
|
|
146
167
|
/**
|
|
147
168
|
* A path inside the session directory reads better relative to it; anything
|
|
148
169
|
* outside stays absolute so it is obvious the turn left the project.
|
|
@@ -168,6 +189,15 @@ export declare function showNotices(notices: string[]): void;
|
|
|
168
189
|
* │ ● Yes …
|
|
169
190
|
*/
|
|
170
191
|
export declare function askToolApproval(approval: LocalToolApproval): Promise<"yes" | "always" | "no">;
|
|
192
|
+
/**
|
|
193
|
+
* The approval's question on one row. clack wraps a long message itself, at
|
|
194
|
+
* the terminal edge and with its own indent, so a long command came out over
|
|
195
|
+
* three ragged rows; the command is clipped here instead, and the line under
|
|
196
|
+
* the finished call (`⏺ Bash: …`) says the same thing again once it has run.
|
|
197
|
+
*
|
|
198
|
+
* Exported for tests.
|
|
199
|
+
*/
|
|
200
|
+
export declare function approvalMessage(approval: Pick<LocalToolApproval, "toolName" | "summary">, width: number): string;
|
|
171
201
|
/**
|
|
172
202
|
* Claude Code's question picker, in this session's tree. Each question is one
|
|
173
203
|
* `selectOne` — the same prompt as a tool approval, so the rail stays intact.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/session/tree.ts"],"names":[],"mappings":"AAKA,OAAO,EAAuB,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAKxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AA8B5D;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAe9D;AA+CD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAM1D;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAK3C;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/session/tree.ts"],"names":[],"mappings":"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"}
|
|
@@ -104,7 +104,40 @@ export function showCard(body) {
|
|
|
104
104
|
* `◇ ask hey --continue`. No "You" label.
|
|
105
105
|
*/
|
|
106
106
|
export function showUserTurn(body) {
|
|
107
|
-
|
|
107
|
+
const folded = foldUserTurn(body, treeBodyWidth());
|
|
108
|
+
if (folded === undefined) {
|
|
109
|
+
writeDiamondBlock(body);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
process.stderr.write(`${colors.dim("◇")} ${folded.text}${colors.dim(folded.suffix)}\n`);
|
|
113
|
+
}
|
|
114
|
+
/** Lines a sent message may have before it is folded to one row. */
|
|
115
|
+
const USER_TURN_MAX_LINES = 4;
|
|
116
|
+
/**
|
|
117
|
+
* A message of more than a few lines, folded to its start and its length:
|
|
118
|
+
*
|
|
119
|
+
* ◇ /cargo-project Set up the `tam-building` cookbook with… [81 lines]
|
|
120
|
+
*
|
|
121
|
+
* The person already knows what they sent, and a message that long was
|
|
122
|
+
* pasted or handed over (the brief `cargo-ai project init` passes when it
|
|
123
|
+
* opens this chat) rather than typed. Printed whole, a brief fills the screen
|
|
124
|
+
* above the reply it asked for, with its lists run together into one block by
|
|
125
|
+
* the wrap. Claude Code folds a paste the same way.
|
|
126
|
+
*
|
|
127
|
+
* Counted in the message's own lines, not in rows: a long paragraph typed in
|
|
128
|
+
* one go is one line, and it is shown whole.
|
|
129
|
+
*
|
|
130
|
+
* Exported for tests.
|
|
131
|
+
*/
|
|
132
|
+
export function foldUserTurn(body, width) {
|
|
133
|
+
const count = body.trim().split("\n").length;
|
|
134
|
+
if (count <= USER_TURN_MAX_LINES) {
|
|
135
|
+
return undefined;
|
|
136
|
+
}
|
|
137
|
+
const lines = body.split("\n").filter((line) => line.trim() !== "");
|
|
138
|
+
const suffix = ` [${String(count)} lines]`;
|
|
139
|
+
const text = clipToCells(lines.map((line) => line.trim()).join(" "), Math.max(8, width - textWidth(suffix)));
|
|
140
|
+
return { text, suffix };
|
|
108
141
|
}
|
|
109
142
|
/**
|
|
110
143
|
* Where the finished part of a reply ends: just past its last blank line, as
|
|
@@ -484,11 +517,13 @@ export function showToolGroup(input) {
|
|
|
484
517
|
const verb = TOOL_GROUP_VERBS.find((entry) => entry.toolName === input.toolName.toLowerCase());
|
|
485
518
|
const head = verb === undefined
|
|
486
519
|
? `${toolLabel(input.toolName)} ×${String(count)}`
|
|
487
|
-
: `${verb.label} ${String(count)} ${verb.noun}`;
|
|
520
|
+
: `${verb.label} ${String(count)} ${count === 1 ? verb.one : verb.noun}`;
|
|
488
521
|
// Paths shown by file name: the directory is usually the same for all.
|
|
489
|
-
const items = input.
|
|
490
|
-
|
|
491
|
-
|
|
522
|
+
const items = isCountOnlyTool(input.toolName)
|
|
523
|
+
? []
|
|
524
|
+
: input.summaries
|
|
525
|
+
.filter((summary) => summary !== "")
|
|
526
|
+
.map((summary) => isAbsolute(summary) === true ? basename(summary) : summary);
|
|
492
527
|
const label = clipToCells(items.length === 0 ? head : `${head}: ${items.join(", ")}`, treeBodyWidth());
|
|
493
528
|
const line = `${colors.dim(TOOL_MARKER)} ${colors.dim(label)}`;
|
|
494
529
|
if (input.spinner !== undefined) {
|
|
@@ -499,16 +534,32 @@ export function showToolGroup(input) {
|
|
|
499
534
|
}
|
|
500
535
|
/** How a run of one built-in tool is counted. Names arrive lowercase. */
|
|
501
536
|
const TOOL_GROUP_VERBS = [
|
|
502
|
-
{ toolName: "read", label: "Read", noun: "files" },
|
|
503
|
-
{ toolName: "edit", label: "Edited", noun: "files" },
|
|
504
|
-
{ toolName: "multiedit", label: "Edited", noun: "files" },
|
|
505
|
-
{ toolName: "write", label: "Wrote", noun: "files" },
|
|
506
|
-
{ toolName: "bash", label: "Ran", noun: "commands" },
|
|
507
|
-
{ toolName: "grep", label: "Ran", noun: "searches" },
|
|
508
|
-
{ toolName: "glob", label: "Listed", noun: "patterns" },
|
|
509
|
-
{ toolName: "webfetch", label: "Fetched", noun: "pages" },
|
|
510
|
-
{
|
|
537
|
+
{ toolName: "read", label: "Read", one: "file", noun: "files" },
|
|
538
|
+
{ toolName: "edit", label: "Edited", one: "file", noun: "files" },
|
|
539
|
+
{ toolName: "multiedit", label: "Edited", one: "file", noun: "files" },
|
|
540
|
+
{ toolName: "write", label: "Wrote", one: "file", noun: "files" },
|
|
541
|
+
{ toolName: "bash", label: "Ran", one: "command", noun: "commands" },
|
|
542
|
+
{ toolName: "grep", label: "Ran", one: "search", noun: "searches" },
|
|
543
|
+
{ toolName: "glob", label: "Listed", one: "pattern", noun: "patterns" },
|
|
544
|
+
{ toolName: "webfetch", label: "Fetched", one: "page", noun: "pages" },
|
|
545
|
+
{
|
|
546
|
+
toolName: "websearch",
|
|
547
|
+
label: "Ran",
|
|
548
|
+
one: "web search",
|
|
549
|
+
noun: "web searches",
|
|
550
|
+
},
|
|
511
551
|
];
|
|
552
|
+
/**
|
|
553
|
+
* Tools whose calls are counted under `collapsed`, never named: `Read 2
|
|
554
|
+
* files`. What an agent read on its way to an answer is how it got there, not
|
|
555
|
+
* what it did, and a row of paths says less than the reply under it. The
|
|
556
|
+
* names are one `/tools full` away. Edits and writes keep theirs, because
|
|
557
|
+
* they changed something.
|
|
558
|
+
*/
|
|
559
|
+
const COUNT_ONLY_TOOLS = new Set(["read"]);
|
|
560
|
+
export function isCountOnlyTool(toolName) {
|
|
561
|
+
return COUNT_ONLY_TOOLS.has(toolName.toLowerCase());
|
|
562
|
+
}
|
|
512
563
|
/**
|
|
513
564
|
* The start of a tool's result, clipped to the rail. A failure always gets
|
|
514
565
|
* its first line, so a ✗ says why without switching the display.
|
|
@@ -576,9 +627,7 @@ export function showNotices(notices) {
|
|
|
576
627
|
*/
|
|
577
628
|
export async function askToolApproval(approval) {
|
|
578
629
|
const decision = await selectOne({
|
|
579
|
-
message: approval
|
|
580
|
-
? `Run ${approval.toolName}?`
|
|
581
|
-
: `Run ${approval.toolName}: ${approval.summary}?`,
|
|
630
|
+
message: approvalMessage(approval, treeBodyWidth()),
|
|
582
631
|
recommended: "yes",
|
|
583
632
|
// Escape here means "not that tool", not "leave the chat" — the turn
|
|
584
633
|
// continues and the model reports what it could not do.
|
|
@@ -589,8 +638,32 @@ export async function askToolApproval(approval) {
|
|
|
589
638
|
{ value: "no", label: "No", hint: "tell the model to skip it" },
|
|
590
639
|
],
|
|
591
640
|
});
|
|
641
|
+
closePicker();
|
|
592
642
|
return decision === "always" ? "always" : decision === "no" ? "no" : "yes";
|
|
593
643
|
}
|
|
644
|
+
/**
|
|
645
|
+
* The approval's question on one row. clack wraps a long message itself, at
|
|
646
|
+
* the terminal edge and with its own indent, so a long command came out over
|
|
647
|
+
* three ragged rows; the command is clipped here instead, and the line under
|
|
648
|
+
* the finished call (`⏺ Bash: …`) says the same thing again once it has run.
|
|
649
|
+
*
|
|
650
|
+
* Exported for tests.
|
|
651
|
+
*/
|
|
652
|
+
export function approvalMessage(approval, width) {
|
|
653
|
+
if (approval.summary === "") {
|
|
654
|
+
return `Run ${approval.toolName}?`;
|
|
655
|
+
}
|
|
656
|
+
return `${clipToCells(`Run ${approval.toolName}: ${approval.summary}`, width - 1)}?`;
|
|
657
|
+
}
|
|
658
|
+
/**
|
|
659
|
+
* The rail row a finished picker leaves under its answer. clack opens each of
|
|
660
|
+
* its prompts with one, so a second question gets it for free; the tool line
|
|
661
|
+
* or the reply that comes next does not, and printed straight under the dim
|
|
662
|
+
* answer it reads as part of it.
|
|
663
|
+
*/
|
|
664
|
+
function closePicker() {
|
|
665
|
+
writeRail("");
|
|
666
|
+
}
|
|
594
667
|
const SKIP_QUESTION = "__skip__";
|
|
595
668
|
/**
|
|
596
669
|
* Claude Code's question picker, in this session's tree. Each question is one
|
|
@@ -623,5 +696,6 @@ export async function askUserQuestions(toolInput) {
|
|
|
623
696
|
answers[question.question] = chosen;
|
|
624
697
|
}
|
|
625
698
|
}
|
|
699
|
+
closePicker();
|
|
626
700
|
return Object.keys(answers).length === 0 ? undefined : answers;
|
|
627
701
|
}
|