@cargo-ai/cli 1.0.94 → 1.0.96

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.
Files changed (123) hide show
  1. package/build/commands/ai/chat.d.ts.map +1 -1
  2. package/build/commands/ai/chat.js +2 -1
  3. package/build/commands/ai/message.d.ts.map +1 -1
  4. package/build/commands/ai/message.js +2 -1
  5. package/build/commands/ai/release.d.ts.map +1 -1
  6. package/build/commands/ai/release.js +7 -6
  7. package/build/commands/ask/harness/approvals.d.ts +7 -0
  8. package/build/commands/ask/harness/approvals.d.ts.map +1 -0
  9. package/build/commands/ask/harness/approvals.js +81 -0
  10. package/build/commands/ask/harness/artifacts.d.ts.map +1 -0
  11. package/build/commands/ask/harness/askUserQuestion.d.ts +69 -0
  12. package/build/commands/ask/harness/askUserQuestion.d.ts.map +1 -0
  13. package/build/commands/ask/harness/askUserQuestion.js +218 -0
  14. package/build/commands/ask/harness/claudeConfig.d.ts.map +1 -0
  15. package/build/commands/ask/{claudeConfig.js → harness/claudeConfig.js} +28 -13
  16. package/build/commands/ask/harness/create.d.ts +59 -0
  17. package/build/commands/ask/harness/create.d.ts.map +1 -0
  18. package/build/commands/ask/harness/create.js +314 -0
  19. package/build/commands/ask/harness/index.d.ts +9 -0
  20. package/build/commands/ask/harness/index.d.ts.map +1 -0
  21. package/build/commands/ask/harness/index.js +8 -0
  22. package/build/commands/ask/harness/ingest.d.ts +25 -0
  23. package/build/commands/ask/harness/ingest.d.ts.map +1 -0
  24. package/build/commands/ask/harness/ingest.js +35 -0
  25. package/build/commands/ask/harness/instructions.d.ts +13 -0
  26. package/build/commands/ask/harness/instructions.d.ts.map +1 -0
  27. package/build/commands/ask/harness/instructions.js +43 -0
  28. package/build/commands/ask/harness/layout.d.ts +23 -0
  29. package/build/commands/ask/harness/layout.d.ts.map +1 -0
  30. package/build/commands/ask/harness/layout.js +32 -0
  31. package/build/commands/ask/harness/mcp.d.ts +25 -0
  32. package/build/commands/ask/harness/mcp.d.ts.map +1 -0
  33. package/build/commands/ask/harness/mcp.js +72 -0
  34. package/build/commands/ask/harness/pnpmShim.d.ts.map +1 -0
  35. package/build/commands/ask/harness/release.d.ts +18 -0
  36. package/build/commands/ask/harness/release.d.ts.map +1 -0
  37. package/build/commands/ask/harness/release.js +117 -0
  38. package/build/commands/ask/harness/sandbox.d.ts +9 -0
  39. package/build/commands/ask/harness/sandbox.d.ts.map +1 -0
  40. package/build/commands/ask/harness/sandbox.js +27 -0
  41. package/build/commands/ask/harness/timing.d.ts +16 -0
  42. package/build/commands/ask/harness/timing.d.ts.map +1 -0
  43. package/build/commands/ask/harness/timing.js +72 -0
  44. package/build/commands/ask/harness/turn.d.ts +152 -0
  45. package/build/commands/ask/harness/turn.d.ts.map +1 -0
  46. package/build/commands/ask/harness/turn.js +676 -0
  47. package/build/commands/ask/harness/usage.d.ts +50 -0
  48. package/build/commands/ask/harness/usage.d.ts.map +1 -0
  49. package/build/commands/ask/harness/usage.js +87 -0
  50. package/build/commands/ask/index.d.ts +9 -0
  51. package/build/commands/ask/index.d.ts.map +1 -1
  52. package/build/commands/ask/index.js +7 -7
  53. package/build/commands/ask/input/completer.d.ts.map +1 -0
  54. package/build/commands/ask/input/index.d.ts +5 -0
  55. package/build/commands/ask/input/index.d.ts.map +1 -0
  56. package/build/commands/ask/input/index.js +4 -0
  57. package/build/commands/ask/input/prompt.d.ts.map +1 -0
  58. package/build/commands/ask/{prompt.js → input/prompt.js} +1 -1
  59. package/build/commands/ask/input/slash.d.ts.map +1 -0
  60. package/build/commands/ask/{slash.js → input/slash.js} +1 -1
  61. package/build/commands/ask/input/typeAhead.d.ts.map +1 -0
  62. package/build/commands/ask/{history.d.ts → persist/history.d.ts} +1 -1
  63. package/build/commands/ask/persist/history.d.ts.map +1 -0
  64. package/build/commands/ask/persist/index.d.ts +4 -0
  65. package/build/commands/ask/persist/index.d.ts.map +1 -0
  66. package/build/commands/ask/persist/index.js +3 -0
  67. package/build/commands/ask/persist/persist.d.ts.map +1 -0
  68. package/build/commands/ask/persist/state.d.ts.map +1 -0
  69. package/build/commands/ask/session/claim.d.ts +56 -0
  70. package/build/commands/ask/session/claim.d.ts.map +1 -0
  71. package/build/commands/ask/session/claim.js +76 -0
  72. package/build/commands/ask/session/index.d.ts +5 -0
  73. package/build/commands/ask/session/index.d.ts.map +1 -0
  74. package/build/commands/ask/session/index.js +4 -0
  75. package/build/commands/ask/session/run.d.ts +36 -0
  76. package/build/commands/ask/session/run.d.ts.map +1 -0
  77. package/build/commands/ask/session/run.js +846 -0
  78. package/build/commands/ask/session/thinking.d.ts.map +1 -0
  79. package/build/commands/ask/session/tree.d.ts +99 -0
  80. package/build/commands/ask/session/tree.d.ts.map +1 -0
  81. package/build/commands/ask/session/tree.js +356 -0
  82. package/package.json +6 -5
  83. package/build/commands/ask/artifacts.d.ts.map +0 -1
  84. package/build/commands/ask/binding.d.ts +0 -13
  85. package/build/commands/ask/binding.d.ts.map +0 -1
  86. package/build/commands/ask/binding.js +0 -19
  87. package/build/commands/ask/claudeConfig.d.ts.map +0 -1
  88. package/build/commands/ask/completer.d.ts.map +0 -1
  89. package/build/commands/ask/history.d.ts.map +0 -1
  90. package/build/commands/ask/localHarness.d.ts +0 -278
  91. package/build/commands/ask/localHarness.d.ts.map +0 -1
  92. package/build/commands/ask/localHarness.js +0 -1300
  93. package/build/commands/ask/messageStream.d.ts +0 -33
  94. package/build/commands/ask/messageStream.d.ts.map +0 -1
  95. package/build/commands/ask/messageStream.js +0 -114
  96. package/build/commands/ask/persist.d.ts.map +0 -1
  97. package/build/commands/ask/pnpmShim.d.ts.map +0 -1
  98. package/build/commands/ask/prompt.d.ts.map +0 -1
  99. package/build/commands/ask/session.d.ts +0 -101
  100. package/build/commands/ask/session.d.ts.map +0 -1
  101. package/build/commands/ask/session.js +0 -1328
  102. package/build/commands/ask/slash.d.ts.map +0 -1
  103. package/build/commands/ask/state.d.ts.map +0 -1
  104. package/build/commands/ask/thinking.d.ts.map +0 -1
  105. package/build/commands/ask/typeAhead.d.ts.map +0 -1
  106. /package/build/commands/ask/{artifacts.d.ts → harness/artifacts.d.ts} +0 -0
  107. /package/build/commands/ask/{artifacts.js → harness/artifacts.js} +0 -0
  108. /package/build/commands/ask/{claudeConfig.d.ts → harness/claudeConfig.d.ts} +0 -0
  109. /package/build/commands/ask/{pnpmShim.d.ts → harness/pnpmShim.d.ts} +0 -0
  110. /package/build/commands/ask/{pnpmShim.js → harness/pnpmShim.js} +0 -0
  111. /package/build/commands/ask/{completer.d.ts → input/completer.d.ts} +0 -0
  112. /package/build/commands/ask/{completer.js → input/completer.js} +0 -0
  113. /package/build/commands/ask/{prompt.d.ts → input/prompt.d.ts} +0 -0
  114. /package/build/commands/ask/{slash.d.ts → input/slash.d.ts} +0 -0
  115. /package/build/commands/ask/{typeAhead.d.ts → input/typeAhead.d.ts} +0 -0
  116. /package/build/commands/ask/{typeAhead.js → input/typeAhead.js} +0 -0
  117. /package/build/commands/ask/{history.js → persist/history.js} +0 -0
  118. /package/build/commands/ask/{persist.d.ts → persist/persist.d.ts} +0 -0
  119. /package/build/commands/ask/{persist.js → persist/persist.js} +0 -0
  120. /package/build/commands/ask/{state.d.ts → persist/state.d.ts} +0 -0
  121. /package/build/commands/ask/{state.js → persist/state.js} +0 -0
  122. /package/build/commands/ask/{thinking.d.ts → session/thinking.d.ts} +0 -0
  123. /package/build/commands/ask/{thinking.js → session/thinking.js} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinking.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/session/thinking.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,EAAE,SAAS,MAAM,EAyB/C,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAc1D"}
@@ -0,0 +1,99 @@
1
+ import { type Spinner } from "../../runHandler.js";
2
+ import type { LocalToolApproval } from "../harness/turn.js";
3
+ /**
4
+ * Greedy wrap on spaces. A word longer than the width keeps its own line
5
+ * rather than being cut mid-token.
6
+ *
7
+ * Exported for tests.
8
+ */
9
+ export declare function wrapLine(text: string, width: number): string[];
10
+ export declare function showStep(label: string, body: string): void;
11
+ /**
12
+ * Slash help / notes — finished step like the palette:
13
+ * ◇ /help
14
+ * │ …
15
+ */
16
+ export declare function showCard(body: string): void;
17
+ /**
18
+ * Finished user turn — message on the diamond, like the palette's
19
+ * `◇ ask hey --continue`. No "You" label.
20
+ */
21
+ export declare function showUserTurn(body: string): void;
22
+ export type LiveAssistantTurn = {
23
+ buffer: string;
24
+ paintedLines: number;
25
+ /**
26
+ * The question being typed while this reply streams, drawn under it.
27
+ *
28
+ * It cannot live on the spinner: the first text delta stops the spinner and
29
+ * opens this block, and raw mode means the terminal is not echoing. Without
30
+ * it here, the one moment type-ahead is most obviously in use — typing over
31
+ * a reply as it arrives — is the one moment nothing appears on screen.
32
+ */
33
+ footer: string;
34
+ };
35
+ /** Rail gap, then an empty marker line ready for deltas. */
36
+ export declare function beginAssistantTurn(): LiveAssistantTurn;
37
+ export declare function appendAssistantDelta(live: LiveAssistantTurn, delta: string): void;
38
+ /** Show, change or remove the question being typed over this reply. */
39
+ export declare function setAssistantFooter(live: LiveAssistantTurn, footer: string): void;
40
+ /** Trailing rail gap before the next user turn / ◆ prompt. */
41
+ export declare function endAssistantTurn(live: LiveAssistantTurn): void;
42
+ /**
43
+ * Finished assistant turn — same tree as a user step, with `■` instead of `◇`.
44
+ */
45
+ export declare function showAssistantTurn(body: string): void;
46
+ export declare function describeToolActivity(toolName: string, summary: string): string;
47
+ /**
48
+ * A tool that has finished, left in the transcript.
49
+ *
50
+ * The spinner shows what is running, but it is one line that is overwritten
51
+ * and then cleared, so once a turn is over there is no record of what it did —
52
+ * only the prose describing it. A turn that read four files and ran two
53
+ * commands should say so afterwards, the way the approval prompt does for the
54
+ * tools it happened to ask about.
55
+ *
56
+ * Written through the spinner's `log` when one is up, which wipes the spinner
57
+ * line, leaves this behind, and lets the next frame redraw underneath.
58
+ */
59
+ export declare function showToolRun(input: {
60
+ spinner: Spinner | undefined;
61
+ toolName: string;
62
+ summary: string;
63
+ isError: boolean;
64
+ }): void;
65
+ /**
66
+ * A path inside the session directory reads better relative to it; anything
67
+ * outside stays absolute so it is obvious the turn left the project.
68
+ *
69
+ * Exported for tests.
70
+ */
71
+ export declare function displayPath(path: string, dir: string): string;
72
+ /**
73
+ * Closing step for a turn that edited the working copy, so a reply that says
74
+ * "done" is backed by the list of files it touched.
75
+ */
76
+ export declare function showTouchedFiles(paths: ReadonlySet<string>, dir: string): void;
77
+ /**
78
+ * Side notes from a turn — a chat-history save that failed, say. They are not
79
+ * part of the reply, so they land after it rather than inside it.
80
+ */
81
+ export declare function showNotices(notices: string[]): void;
82
+ /**
83
+ * Local Claude Code runs against the user's own working copy, so anything
84
+ * beyond a read is confirmed before it happens:
85
+ *
86
+ * ◆ Run Bash: npm test?
87
+ * │ ● Yes …
88
+ */
89
+ export declare function askToolApproval(approval: LocalToolApproval): Promise<"yes" | "always" | "no">;
90
+ /**
91
+ * Claude Code's question picker, in this session's tree. Each question is one
92
+ * `selectOne` — the same prompt as a tool approval, so the rail stays intact.
93
+ *
94
+ * Multi-select is flattened to one pick: this terminal can only answer one
95
+ * row at a time, and a comma-joined bag of labels is worse than the one the
96
+ * user actually chose.
97
+ */
98
+ export declare function askUserQuestions(toolInput: unknown): Promise<Record<string, string> | undefined>;
99
+ //# sourceMappingURL=tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tree.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/session/tree.ts"],"names":[],"mappings":"AAIA,OAAO,EAAuB,KAAK,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAKxE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AA6B5D;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAe9D;AA0DD,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,CAE/C;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AA+DF,4DAA4D;AAC5D,wBAAgB,kBAAkB,IAAI,iBAAiB,CAItD;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,iBAAiB,EACvB,KAAK,EAAE,MAAM,GACZ,IAAI,CAeN;AAkBD,uEAAuE;AACvE,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,iBAAiB,EACvB,MAAM,EAAE,MAAM,GACb,IAAI,CAON;AAED,8DAA8D;AAC9D,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAK9D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAIpD;AAiBD,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,MAAM,CAYR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE;IACjC,OAAO,EAAE,OAAO,GAAG,SAAS,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG,IAAI,CAYP;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAQ7D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,EAC1B,GAAG,EAAE,MAAM,GACV,IAAI,CAWN;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,CAQnD;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,CAAC,KAAK,GAAG,QAAQ,GAAG,IAAI,CAAC,CAkBlC;AAID;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,OAAO,GACjB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CA6B7C"}
@@ -0,0 +1,356 @@
1
+ import { isAbsolute, relative } from "node:path";
2
+ import { selectOne } from "@cargo-ai/cdk/cli";
3
+ import { clipToWidth, colors } from "../../runHandler.js";
4
+ import { ASK_USER_QUESTION_TOOL_NAME, readAskUserQuestions, } from "../harness/askUserQuestion.js";
5
+ /**
6
+ * What an assistant turn is marked with, alongside `◇` for a step and `│` for
7
+ * the rail.
8
+ *
9
+ * A text glyph rather than an emoji, so it takes the same `marker + two
10
+ * spaces` as every other row and the whole tree stays on one left edge. An
11
+ * emoji is two columns wide and needs its own spacing rule to line up, which
12
+ * is one more thing to get wrong every time a line is drawn.
13
+ */
14
+ const ASSISTANT_MARKER = "■";
15
+ /** Completed tool call, so the transcript keeps what was actually run. */
16
+ const TOOL_MARKER = "⏺";
17
+ /**
18
+ * Body width under `◇ ` / `│ ` / `◆ `. Soft wrap without this drops the
19
+ * rail mid-line and the tree looks broken.
20
+ */
21
+ function treeBodyWidth() {
22
+ const columns = process.stderr.columns === undefined ? 80 : process.stderr.columns;
23
+ // Marker + two spaces (`◇ `, `│ `, `◆ `), and one column of margin: a
24
+ // line filling the last cell makes some terminals wrap on their own, and the
25
+ // `\n` after it then lands a row further down than the tree expects.
26
+ return Math.max(24, columns - 4);
27
+ }
28
+ /**
29
+ * Greedy wrap on spaces. A word longer than the width keeps its own line
30
+ * rather than being cut mid-token.
31
+ *
32
+ * Exported for tests.
33
+ */
34
+ export function wrapLine(text, width) {
35
+ const lines = [];
36
+ for (const word of text.split(/\s+/).filter((part) => part.length > 0)) {
37
+ const current = lines[lines.length - 1];
38
+ if (current === undefined || `${current} ${word}`.length > width) {
39
+ lines.push(word);
40
+ continue;
41
+ }
42
+ lines[lines.length - 1] = `${current} ${word}`;
43
+ }
44
+ return lines;
45
+ }
46
+ /** One line under the current ◆/◇, with the │ rail (same indent as clack). */
47
+ function writeRail(body) {
48
+ process.stderr.write(`${colors.dim("│")} ${body}\n`);
49
+ }
50
+ /** Word-wrap onto the │ rail so the terminal never soft-wraps mid-line. */
51
+ function writeRailWrapped(body) {
52
+ // Keep the rail on blank paragraphs so the tree does not break mid-reply.
53
+ if (body === "") {
54
+ writeRail("");
55
+ return;
56
+ }
57
+ const lines = wrapLine(body, treeBodyWidth());
58
+ if (lines.length === 0) {
59
+ writeRail("");
60
+ return;
61
+ }
62
+ for (const line of lines) {
63
+ writeRail(line);
64
+ }
65
+ }
66
+ /**
67
+ * Light cleanup so model markdown does not fight the tree. Keeps the words;
68
+ * drops heading marks, bold markers, and horizontal rules.
69
+ */
70
+ function forTerminal(text) {
71
+ return text
72
+ .replace(/^#{1,6}\s+/gm, "")
73
+ .replace(/\*\*([^*]+)\*\*/g, "$1")
74
+ .replace(/^---+$/gm, "");
75
+ }
76
+ /**
77
+ * A `◇` step: the first line beside the marker, the rest continuing on the
78
+ * rail under it.
79
+ *
80
+ * Wrapped here rather than left to the terminal. A label long enough to reach
81
+ * the edge — a stall notice, an API error — soft-wraps mid-word and starts its
82
+ * next line at column zero, outside the tree, which is how a one-sentence
83
+ * notice ends up looking like the output is corrupted.
84
+ */
85
+ function writeDiamondBlock(body) {
86
+ const lines = body === "" ? [""] : wrapLine(body, treeBodyWidth());
87
+ const first = lines[0] === undefined ? "" : lines[0];
88
+ process.stderr.write(`${colors.dim("◇")} ${first}\n`);
89
+ for (const line of lines.slice(1)) {
90
+ writeRail(line);
91
+ }
92
+ }
93
+ export function showStep(label, body) {
94
+ writeDiamondBlock(label);
95
+ for (const paragraph of body.split("\n")) {
96
+ writeRailWrapped(paragraph);
97
+ }
98
+ }
99
+ /**
100
+ * Slash help / notes — finished step like the palette:
101
+ * ◇ /help
102
+ * │ …
103
+ */
104
+ export function showCard(body) {
105
+ const paragraphs = body.split("\n");
106
+ const title = paragraphs[0] === undefined ? "" : paragraphs[0];
107
+ const rest = paragraphs.slice(1).join("\n");
108
+ showStep(title, rest);
109
+ }
110
+ /**
111
+ * Finished user turn — message on the diamond, like the palette's
112
+ * `◇ ask hey --continue`. No "You" label.
113
+ */
114
+ export function showUserTurn(body) {
115
+ writeDiamondBlock(body);
116
+ }
117
+ /**
118
+ * Display lines for an assistant body. First line is the brick header body;
119
+ * later lines sit on the │ rail. Blank paragraphs keep an empty rail.
120
+ */
121
+ function assistantDisplayLines(body) {
122
+ const paragraphs = forTerminal(body).split("\n");
123
+ const lines = [];
124
+ for (let index = 0; index < paragraphs.length; index += 1) {
125
+ const paragraph = paragraphs[index];
126
+ if (paragraph === undefined) {
127
+ continue;
128
+ }
129
+ if (paragraph === "") {
130
+ lines.push("");
131
+ continue;
132
+ }
133
+ const wrapped = wrapLine(paragraph, treeBodyWidth());
134
+ if (wrapped.length === 0) {
135
+ lines.push("");
136
+ continue;
137
+ }
138
+ for (const line of wrapped) {
139
+ lines.push(line);
140
+ }
141
+ }
142
+ if (lines.length === 0) {
143
+ return [""];
144
+ }
145
+ return lines;
146
+ }
147
+ function writeAssistantLines(lines) {
148
+ const first = lines[0] === undefined ? "" : lines[0];
149
+ process.stderr.write(`${ASSISTANT_MARKER} ${first}\n`);
150
+ for (let index = 1; index < lines.length; index += 1) {
151
+ const line = lines[index];
152
+ if (line !== undefined) {
153
+ writeRail(line);
154
+ }
155
+ }
156
+ }
157
+ function clearPaintedLines(count) {
158
+ if (count <= 0 || process.stderr.isTTY !== true) {
159
+ return;
160
+ }
161
+ process.stderr.write(`\x1B[${String(count)}A\r\x1B[J`);
162
+ }
163
+ /** Rail gap, then an empty marker line ready for deltas. */
164
+ export function beginAssistantTurn() {
165
+ writeRail("");
166
+ process.stderr.write(`${ASSISTANT_MARKER} \n`);
167
+ return { buffer: "", paintedLines: 1, footer: "" };
168
+ }
169
+ export function appendAssistantDelta(live, delta) {
170
+ // A tool between two pieces of narration inserts a paragraph break, so that
171
+ // "Let me look." and what it found do not run together. When the tool also
172
+ // closed the block on screen, that break arrives as the first thing in the
173
+ // *next* block — and renders as an empty rail line under the marker before a
174
+ // word has been said. Kept in the stored answer, where the paragraphs still
175
+ // belong; dropped here, where the block itself is already the separation.
176
+ const text = live.buffer === "" ? delta.replace(/^\n+/, "") : delta;
177
+ if (text === "") {
178
+ return;
179
+ }
180
+ live.buffer += text;
181
+ repaintAssistantTurn(live);
182
+ }
183
+ /** Draw the block again from its buffer, with the typed line under it. */
184
+ function repaintAssistantTurn(live) {
185
+ const lines = assistantDisplayLines(live.buffer);
186
+ clearPaintedLines(live.paintedLines);
187
+ writeAssistantLines(lines);
188
+ live.paintedLines = lines.length;
189
+ if (live.footer !== "") {
190
+ // Clipped for the same reason the spinner's is: it has to occupy exactly
191
+ // one row, or the next repaint clears from the wrong line.
192
+ process.stderr.write(`${colors.dim(clipToWidth(live.footer))}\n`);
193
+ live.paintedLines += 1;
194
+ }
195
+ }
196
+ /** Show, change or remove the question being typed over this reply. */
197
+ export function setAssistantFooter(live, footer) {
198
+ if (live.footer === footer) {
199
+ return;
200
+ }
201
+ live.footer = footer;
202
+ repaintAssistantTurn(live);
203
+ }
204
+ /** Trailing rail gap before the next user turn / ◆ prompt. */
205
+ export function endAssistantTurn(live) {
206
+ // The typed line belongs to whatever draws next — the spinner, or the block
207
+ // after this one. Left here it would be printed twice.
208
+ setAssistantFooter(live, "");
209
+ writeRail("");
210
+ }
211
+ /**
212
+ * Finished assistant turn — same tree as a user step, with `■` instead of `◇`.
213
+ */
214
+ export function showAssistantTurn(body) {
215
+ const live = beginAssistantTurn();
216
+ appendAssistantDelta(live, body);
217
+ endAssistantTurn(live);
218
+ }
219
+ /** Common tool names arrive lowercase (`bash`); natives keep their case. */
220
+ function toolLabel(toolName) {
221
+ if (toolName === ASK_USER_QUESTION_TOOL_NAME) {
222
+ return "Ask user";
223
+ }
224
+ if (toolName.length === 0) {
225
+ return "tool";
226
+ }
227
+ return `${toolName.slice(0, 1).toUpperCase()}${toolName.slice(1)}`;
228
+ }
229
+ const ACTIVITY_MAX_LENGTH = 72;
230
+ export function describeToolActivity(toolName, summary) {
231
+ const label = toolLabel(toolName);
232
+ if (summary === "") {
233
+ return label;
234
+ }
235
+ const line = `${label}: ${summary}`;
236
+ return line.length > ACTIVITY_MAX_LENGTH
237
+ ? `${line.slice(0, ACTIVITY_MAX_LENGTH - 1)}…`
238
+ : line;
239
+ }
240
+ /**
241
+ * A tool that has finished, left in the transcript.
242
+ *
243
+ * The spinner shows what is running, but it is one line that is overwritten
244
+ * and then cleared, so once a turn is over there is no record of what it did —
245
+ * only the prose describing it. A turn that read four files and ran two
246
+ * commands should say so afterwards, the way the approval prompt does for the
247
+ * tools it happened to ask about.
248
+ *
249
+ * Written through the spinner's `log` when one is up, which wipes the spinner
250
+ * line, leaves this behind, and lets the next frame redraw underneath.
251
+ */
252
+ export function showToolRun(input) {
253
+ const marker = input.isError === true ? colors.red("✗") : colors.dim(TOOL_MARKER);
254
+ const label = describeToolActivity(input.toolName, input.summary);
255
+ const line = `${marker} ${colors.dim(label)}`;
256
+ if (input.spinner !== undefined) {
257
+ input.spinner.log(line);
258
+ return;
259
+ }
260
+ process.stderr.write(`${line}\n`);
261
+ }
262
+ /**
263
+ * A path inside the session directory reads better relative to it; anything
264
+ * outside stays absolute so it is obvious the turn left the project.
265
+ *
266
+ * Exported for tests.
267
+ */
268
+ export function displayPath(path, dir) {
269
+ const relativePath = relative(dir, path);
270
+ return relativePath === "" ||
271
+ relativePath.startsWith("..") === true ||
272
+ isAbsolute(relativePath) === true
273
+ ? path
274
+ : relativePath;
275
+ }
276
+ /**
277
+ * Closing step for a turn that edited the working copy, so a reply that says
278
+ * "done" is backed by the list of files it touched.
279
+ */
280
+ export function showTouchedFiles(paths, dir) {
281
+ if (paths.size === 0) {
282
+ return;
283
+ }
284
+ const listed = [...paths].map((path) => displayPath(path, dir)).sort();
285
+ showStep(`${String(listed.length)} file${listed.length === 1 ? "" : "s"} changed`, listed.join("\n"));
286
+ }
287
+ /**
288
+ * Side notes from a turn — a chat-history save that failed, say. They are not
289
+ * part of the reply, so they land after it rather than inside it.
290
+ */
291
+ export function showNotices(notices) {
292
+ while (notices.length > 0) {
293
+ const notice = notices.shift();
294
+ if (notice !== undefined) {
295
+ showCard(notice);
296
+ }
297
+ }
298
+ }
299
+ /**
300
+ * Local Claude Code runs against the user's own working copy, so anything
301
+ * beyond a read is confirmed before it happens:
302
+ *
303
+ * ◆ Run Bash: npm test?
304
+ * │ ● Yes …
305
+ */
306
+ export async function askToolApproval(approval) {
307
+ const decision = await selectOne({
308
+ message: approval.summary === ""
309
+ ? `Run ${approval.toolName}?`
310
+ : `Run ${approval.toolName}: ${approval.summary}?`,
311
+ recommended: "yes",
312
+ // Escape here means "not that tool", not "leave the chat" — the turn
313
+ // continues and the model reports what it could not do.
314
+ cancelValue: "no",
315
+ choices: [
316
+ { value: "yes", label: "Yes", hint: "just this once" },
317
+ { value: "always", label: "Yes to everything", hint: "for this chat" },
318
+ { value: "no", label: "No", hint: "tell the model to skip it" },
319
+ ],
320
+ });
321
+ return decision === "always" ? "always" : decision === "no" ? "no" : "yes";
322
+ }
323
+ const SKIP_QUESTION = "__skip__";
324
+ /**
325
+ * Claude Code's question picker, in this session's tree. Each question is one
326
+ * `selectOne` — the same prompt as a tool approval, so the rail stays intact.
327
+ *
328
+ * Multi-select is flattened to one pick: this terminal can only answer one
329
+ * row at a time, and a comma-joined bag of labels is worse than the one the
330
+ * user actually chose.
331
+ */
332
+ export async function askUserQuestions(toolInput) {
333
+ const questions = readAskUserQuestions(toolInput);
334
+ if (questions === undefined) {
335
+ return undefined;
336
+ }
337
+ const answers = {};
338
+ for (const question of questions) {
339
+ const header = question.header === undefined ? "" : `${question.header}: `;
340
+ const first = question.options[0];
341
+ const chosen = await selectOne({
342
+ message: `${header}${question.question}`,
343
+ recommended: first === undefined ? undefined : first.label,
344
+ cancelValue: SKIP_QUESTION,
345
+ choices: question.options.map((option) => ({
346
+ value: option.label,
347
+ label: option.label,
348
+ hint: option.description,
349
+ })),
350
+ });
351
+ if (chosen !== SKIP_QUESTION) {
352
+ answers[question.question] = chosen;
353
+ }
354
+ }
355
+ return Object.keys(answers).length === 0 ? undefined : answers;
356
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cargo-ai/cli",
3
- "version": "1.0.94",
3
+ "version": "1.0.96",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://getcargo.ai",
@@ -67,10 +67,10 @@
67
67
  "dependencies": {
68
68
  "@ai-sdk/harness": "^1.0.95",
69
69
  "@ai-sdk/harness-claude-code": "^1.0.99",
70
- "@cargo-ai/api": "^1.0.81",
70
+ "@cargo-ai/api": "^1.0.83",
71
71
  "@cargo-ai/app-sdk": "^1.0.10",
72
- "@cargo-ai/cdk": "^1.0.80",
73
- "@cargo-ai/types": "^1.0.78",
72
+ "@cargo-ai/cdk": "^1.0.81",
73
+ "@cargo-ai/types": "^1.0.79",
74
74
  "@cargo-ai/utils": "^1.0.30",
75
75
  "@cargo-ai/worker-sdk": "^1.0.17",
76
76
  "@modelcontextprotocol/sdk": "1.29.0",
@@ -78,7 +78,8 @@
78
78
  "ai-sdk-sandbox-local": "^0.1.2",
79
79
  "commander": "^12.1.0",
80
80
  "tsx": "^4.19.2",
81
- "undici": "^7.29.0"
81
+ "undici": "^7.29.0",
82
+ "uuid": "^14.0.0"
82
83
  },
83
84
  "devDependencies": {
84
85
  "@cargo-ai/eslint-config": "*",
@@ -1 +0,0 @@
1
- {"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../../src/commands/ask/artifacts.ts"],"names":[],"mappings":"AAwBA,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI,CAGzE"}
@@ -1,13 +0,0 @@
1
- type RepositoryLike = {
2
- connectorUuid?: string;
3
- repository?: string;
4
- } | null | undefined;
5
- /**
6
- * A usable GitHub workspace: connector + owner/name. Matches
7
- * parseHarnessBinding's required fields, without decrypting env.
8
- *
9
- * Exported for tests.
10
- */
11
- export declare function isBoundRepository(repository: RepositoryLike): boolean;
12
- export {};
13
- //# sourceMappingURL=binding.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../../src/commands/ask/binding.ts"],"names":[],"mappings":"AAAA,KAAK,cAAc,GACf;IACE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GACD,IAAI,GACJ,SAAS,CAAC;AAEd;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,cAAc,GAAG,OAAO,CAgBrE"}
@@ -1,19 +0,0 @@
1
- /**
2
- * A usable GitHub workspace: connector + owner/name. Matches
3
- * parseHarnessBinding's required fields, without decrypting env.
4
- *
5
- * Exported for tests.
6
- */
7
- export function isBoundRepository(repository) {
8
- if (repository === undefined || repository === null) {
9
- return false;
10
- }
11
- if (repository.connectorUuid === undefined) {
12
- return false;
13
- }
14
- if (repository.repository === undefined) {
15
- return false;
16
- }
17
- const slashIndex = repository.repository.indexOf("/");
18
- return slashIndex > 0 && slashIndex < repository.repository.length - 1;
19
- }
@@ -1 +0,0 @@
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 +0,0 @@
1
- {"version":3,"file":"completer.d.ts","sourceRoot":"","sources":["../../../src/commands/ask/completer.ts"],"names":[],"mappings":"AAYA,gEAAgE;AAChE,eAAO,MAAM,kBAAkB,oEAOrB,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 +0,0 @@
1
- {"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../../../src/commands/ask/history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AA0BxC;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE;IACnD,GAAG,EAAE,GAAG,CAAC;IACT,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAU9B;AAED,KAAK,cAAc,GAAG;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,SAAS,cAAc,EAAE,GAClC,MAAM,GAAG,SAAS,CA6CpB"}