@cargo-ai/cli 1.0.105 → 1.0.107

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.
@@ -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;AAGxC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAuB3C,OAAO,EAGL,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,CAsUxB"}
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;AAuB3C,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,CA4UxB"}
@@ -82,13 +82,10 @@ export async function createLocalHarness(input) {
82
82
  }),
83
83
  },
84
84
  id: "cargo-ai-ask",
85
- sandbox: withGetPortEndpoint(createLocalSandbox({ cwd: workspace.sandboxCwd })),
86
85
  sandboxConfig: workspace.workDir === undefined ? {} : { workDir: workspace.workDir },
87
86
  instructions: localHarnessInstructions(input.dir, release),
88
87
  skills: localHarnessSkills(input.dir),
89
88
  model: input.languageModelSlug,
90
- // Nested @ai-sdk/harness ships its own @ai-sdk/provider-utils, so its
91
- // ToolSet does not unify with this package's. Runtime shape is the same.
92
89
  tools: hostTools,
93
90
  permissionMode: "allow-reads",
94
91
  ...(ASK_TIMING_ENABLED === false
@@ -96,14 +93,27 @@ export async function createLocalHarness(input) {
96
93
  : { debug: { enabled: true }, onLog: reportHarnessDiagnostic }),
97
94
  });
98
95
  setupPhase("harness agent constructed");
99
- // Local sandbox cannot broker credentials via request transforms; the
100
- // harness always warns. Keep that off the Ask tree (stderr mid-reply).
101
- const session = await withMutedCredentialBrokerWarning(() => harnessAgent.createSession());
96
+ // Ours rather than the agent's, so ours to stop: the bridge and Claude Code
97
+ // run inside it.
98
+ const sandboxSession = await withGetPortEndpoint(createLocalSandbox({ cwd: workspace.sandboxCwd })).createSession();
99
+ const stopSandbox = () => Promise.resolve(sandboxSession.stop()).catch(() => undefined);
100
+ let session;
101
+ try {
102
+ // Local sandbox cannot broker credentials via request transforms; the
103
+ // harness always warns. Keep that off the Ask tree (stderr mid-reply).
104
+ session = await withMutedCredentialBrokerWarning(() => harnessAgent.createSession({ sandboxSession }));
105
+ }
106
+ catch (error) {
107
+ await stopSandbox();
108
+ throw error;
109
+ }
102
110
  setupPhase("harness session created");
103
111
  // Consumed by the first prompt: this session has never seen the chat, so it
104
112
  // is told the story once rather than on every question.
105
113
  let pendingHistory = input.history;
106
114
  let proxyLastUsedAtMs;
115
+ // Carried from turn to turn: see `LocalTurnAccumulator.reportedCostUsd`.
116
+ let reportedCostUsd = 0;
107
117
  // Approvals the previous turn asked about and never answered — a turn
108
118
  // cancelled at the confirmation prompt leaves one here.
109
119
  const unanswered = [];
@@ -127,17 +137,9 @@ export async function createLocalHarness(input) {
127
137
  // user who walked away from the prompt is "no" — carrying the
128
138
  // question into a turn they did not ask for would be worse.
129
139
  const denials = unanswered.map((approval) => ({
130
- approvalResponse: {
131
- type: "tool-approval-response",
132
- approvalId: approval.approvalId,
133
- approved: false,
134
- },
135
- toolCall: {
136
- type: "tool-call",
137
- toolCallId: approval.toolCallId,
138
- toolName: approval.toolName,
139
- input: approval.input,
140
- },
140
+ type: "tool-approval-response",
141
+ approvalId: approval.approvalId,
142
+ approved: false,
141
143
  }));
142
144
  unanswered.length = 0;
143
145
  // The drain gets its own controller so the timeout can stop it rather
@@ -181,7 +183,7 @@ export async function createLocalHarness(input) {
181
183
  }
182
184
  turnPhase("unfinished previous turn drained");
183
185
  }
184
- const accumulator = createTurnAccumulator();
186
+ const accumulator = createTurnAccumulator(reportedCostUsd);
185
187
  let answer;
186
188
  askUserQuestionAsk.current =
187
189
  options === undefined ? undefined : options.onUserQuestion;
@@ -251,6 +253,7 @@ export async function createLocalHarness(input) {
251
253
  }
252
254
  finally {
253
255
  askUserQuestionAsk.current = undefined;
256
+ reportedCostUsd = accumulator.reportedCostUsd;
254
257
  }
255
258
  if (didReachAnthropic(accumulator.usage) === true) {
256
259
  proxyLastUsedAtMs = Date.now();
@@ -292,6 +295,7 @@ export async function createLocalHarness(input) {
292
295
  // this call exists to prevent, but a teardown already stuck is no more
293
296
  // likely to finish while the user waits on it.
294
297
  await settleWithin(session.destroy().catch(() => undefined), SESSION_DESTROY_TIMEOUT_MS);
298
+ await settleWithin(stopSandbox(), SESSION_DESTROY_TIMEOUT_MS);
295
299
  },
296
300
  };
297
301
  }
@@ -1,13 +1,11 @@
1
1
  import type { Ai, Orchestration } from "@cargo-ai/api";
2
+ import { jsonSchema } from "ai";
2
3
  import type { Api } from "../../../api.js";
3
4
  /** Mount prefix so agent MCP tools can be auto-approved without widening user MCP. */
4
5
  export declare const CARGO_AGENT_MCP_NAME_PREFIX = "cargoagent_";
5
6
  type HostTool = {
6
7
  description?: string;
7
- inputSchema: {
8
- type: "object";
9
- additionalProperties: true;
10
- };
8
+ inputSchema: ReturnType<typeof jsonSchema>;
11
9
  execute: (data: unknown) => Promise<unknown>;
12
10
  };
13
11
  export declare function buildReleaseInstructionAppendix(release: Ai.Release): string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/release.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEvD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAE3C,sFAAsF;AACtF,eAAO,MAAM,2BAA2B,gBAAgB,CAAC;AAEzD,KAAK,QAAQ,GAAG;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,oBAAoB,EAAE,IAAI,CAAC;KAC5B,CAAC;IACF,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C,CAAC;AAEF,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,EAAE,CAAC,OAAO,GAClB,MAAM,GAAG,SAAS,CAwCpB;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,EAAE,CAAC,SAAS,EAAE,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiBzB;AAED,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,GACnB,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CA4B1B;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,EAAE,CAAC,MAAM,GAChB,aAAa,CAAC,GAAG,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAgClD"}
1
+ {"version":3,"file":"release.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/release.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAEhC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAE3C,sFAAsF;AACtF,eAAO,MAAM,2BAA2B,gBAAgB,CAAC;AAEzD,KAAK,QAAQ,GAAG;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;IAC3C,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;CAC9C,CAAC;AAEF,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,EAAE,CAAC,OAAO,GAClB,MAAM,GAAG,SAAS,CAwCpB;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,EAAE,CAAC,SAAS,EAAE,GACzB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiBzB;AAED,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,EAAE,CAAC,MAAM,EAAE,GACnB,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CA4B1B;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,EAAE,CAAC,MAAM,GAChB,aAAa,CAAC,GAAG,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAgClD"}
@@ -1,3 +1,4 @@
1
+ import { jsonSchema } from "ai";
1
2
  /** Mount prefix so agent MCP tools can be auto-approved without widening user MCP. */
2
3
  export const CARGO_AGENT_MCP_NAME_PREFIX = "cargoagent_";
3
4
  export function buildReleaseInstructionAppendix(release) {
@@ -46,10 +47,10 @@ export function buildReleaseHostTools(api, actions) {
46
47
  for (const action of actions) {
47
48
  tools[action.slug] = {
48
49
  description: action.description,
49
- inputSchema: {
50
+ inputSchema: jsonSchema({
50
51
  type: "object",
51
52
  additionalProperties: true,
52
- },
53
+ }),
53
54
  execute: async (data) => {
54
55
  try {
55
56
  return await api.orchestration.action.execute({
@@ -1,3 +1,4 @@
1
+ import type { ToolApprovalResponse } from "ai";
1
2
  import { type LocalTurnAccumulator } from "./usage.js";
2
3
  /**
3
4
  * A built-in tool Claude Code wants to run that `permissionMode` does not
@@ -70,24 +71,10 @@ export type StreamLike = {
70
71
  fullStream: AsyncIterable<unknown>;
71
72
  text: PromiseLike<string>;
72
73
  };
73
- export type ApprovalContinuation = {
74
- approvalResponse: {
75
- type: "tool-approval-response";
76
- approvalId: string;
77
- approved: boolean;
78
- reason?: string;
79
- };
80
- toolCall: {
81
- type: "tool-call";
82
- toolCallId: string;
83
- toolName: string;
84
- input: unknown;
85
- };
86
- };
87
74
  /** The two harness calls a turn needs. Split out so tests can fake them. */
88
75
  export type TurnDriver = {
89
76
  start: () => Promise<StreamLike>;
90
- continueWithApprovals: (continuations: readonly ApprovalContinuation[]) => Promise<StreamLike>;
77
+ continueWithApprovals: (continuations: readonly ToolApprovalResponse[]) => Promise<StreamLike>;
91
78
  };
92
79
  /**
93
80
  * Run one turn to completion, answering approval requests along the way.
@@ -1 +1 @@
1
- {"version":3,"file":"turn.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/turn.ts"],"names":[],"mappings":"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"}
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,EAC1B,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,8EAA8E;AAC9E,MAAM,MAAM,iBAAiB,GACzB;IACE,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,GACD;IACE,IAAI,EAAE,KAAK,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;CAClB;AACH;;;;;;GAMG;GACD;IACE,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEN,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/D;;;;;OAKG;IACH,cAAc,CAAC,EAAE,CACf,KAAK,EAAE,OAAO,KACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC;IACjD,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACnD,qEAAqE;IACrE,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,GAAG;IACrD,sEAAsE;IACtE,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,EAAE,aAAa,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CAC3B,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,UAAU,GAAG;IACvB,KAAK,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IACjC,qBAAqB,EAAE,CACrB,aAAa,EAAE,SAAS,oBAAoB,EAAE,KAC3C,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1B,CAAC;AA8DF;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE;IACzC,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,mBAAmB,GAAG,SAAS,CAAC;IAC1C,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC;;;;OAIG;IACH,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACjC,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyIlB;AAgGD;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,KAAK;;CAO1C;AAED;;;;;GAKG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,SAAS,EAAE,MAAM,EAAE,gBAAgB,UAAQ;CAUxD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAK3D;AAsDD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,MAAM,iBAe3E"}
@@ -59,7 +59,7 @@ export async function runPromptTurn(input) {
59
59
  const handlers = input.handlers === undefined ? {} : input.handlers;
60
60
  const onApproval = handlers.onApproval;
61
61
  const accumulator = input.accumulator === undefined
62
- ? createTurnAccumulator()
62
+ ? createTurnAccumulator(0)
63
63
  : input.accumulator;
64
64
  const stallTimeoutMs = input.stallTimeoutMs === undefined
65
65
  ? TURN_STALL_TIMEOUT_MS
@@ -81,7 +81,7 @@ export async function runPromptTurn(input) {
81
81
  handlers,
82
82
  assistantChunks,
83
83
  toolCalls,
84
- usage: accumulator.usage,
84
+ accumulator,
85
85
  turnState,
86
86
  stallTimeoutMs,
87
87
  toolStallTimeoutMs,
@@ -132,24 +132,16 @@ export async function runPromptTurn(input) {
132
132
  }
133
133
  }
134
134
  continuations.push({
135
- approvalResponse: {
136
- type: "tool-approval-response",
137
- approvalId: approval.approvalId,
138
- approved,
139
- // Told why, so it does something else rather than asking again
140
- // until the approval-round cap ends the turn.
141
- reason: question !== undefined
142
- ? question.reason
143
- : denied === true
144
- ? DENIED_TOOL_REASON
145
- : undefined,
146
- },
147
- toolCall: {
148
- type: "tool-call",
149
- toolCallId: approval.toolCallId,
150
- toolName: approval.toolName,
151
- input: approval.input,
152
- },
135
+ type: "tool-approval-response",
136
+ approvalId: approval.approvalId,
137
+ approved,
138
+ // Told why, so it does something else rather than asking again
139
+ // until the approval-round cap ends the turn.
140
+ reason: question !== undefined
141
+ ? question.reason
142
+ : denied === true
143
+ ? DENIED_TOOL_REASON
144
+ : undefined,
153
145
  });
154
146
  }
155
147
  retractAbandonedCalls(turnState.announced, handlers.onActivity);
@@ -495,9 +487,9 @@ async function consumeTurn(input) {
495
487
  }
496
488
  if (part["type"] === "finish") {
497
489
  // One suspended turn is several streams, each ending with its own
498
- // `finish` and its own totals — sum them. Per-step parts are ignored
499
- // so the same tokens are not counted twice.
500
- addTurnUsage(input.usage, part);
490
+ // `finish` — all of them count. Per-step parts are ignored so the same
491
+ // tokens are not counted twice.
492
+ addTurnUsage(input.accumulator, part);
501
493
  continue;
502
494
  }
503
495
  if (part["type"] === "tool-approval-request") {
@@ -21,9 +21,13 @@ export type LocalTurnUsage = {
21
21
  export type LocalTurnAccumulator = {
22
22
  chunks: string[];
23
23
  usage: LocalTurnUsage;
24
+ /**
25
+ * Claude Code's last running cost for the session. It counts every turn so
26
+ * far, so a turn starts from the previous turn's and bills what it added.
27
+ */
28
+ reportedCostUsd: number;
24
29
  };
25
- /** Exported for tests. */
26
- export declare function createTurnAccumulator(): LocalTurnAccumulator;
30
+ export declare function createTurnAccumulator(lastReportedCostUsd: number): LocalTurnAccumulator;
27
31
  /**
28
32
  * Whether the turn got as far as Anthropic. `costUsd` and `totalTokens` are
29
33
  * reported independently by the harness, so either alone means it did.
@@ -31,10 +35,12 @@ export declare function createTurnAccumulator(): LocalTurnAccumulator;
31
35
  export declare function didReachAnthropic(usage: LocalTurnUsage): boolean;
32
36
  /**
33
37
  * Add one stream's `finish` totals to the turn. `totalUsage` is the AI SDK
34
- * shape; `costUsd` is what Claude Code reports for the same stream under
35
- * `harnessMetadata`, and is stored on the ingested message.
38
+ * shape and counts that stream alone. `costUsd`, under `harnessMetadata`, is a
39
+ * running total, so the turn takes what it added since the last report; a
40
+ * total below that belongs to a new session, and counts in full. The turn's
41
+ * cost is stored on the ingested message.
36
42
  */
37
- export declare function addTurnUsage(usage: LocalTurnUsage, part: Record<string, unknown>): void;
43
+ export declare function addTurnUsage(accumulator: LocalTurnAccumulator, part: Record<string, unknown>): void;
38
44
  /**
39
45
  * What Claude Code says the turn cost, off the `finish` part.
40
46
  *
@@ -1 +1 @@
1
- {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/usage.ts"],"names":[],"mappings":"AAAA;;;;;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;CACvB,CAAC;AAEF,0BAA0B;AAC1B,wBAAgB,qBAAqB,IAAI,oBAAoB,CAa5D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAEhE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,cAAc,EACrB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,IAAI,CAmCN;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,GAAG,SAAS,CA0BpB"}
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../../src/commands/ask/harness/usage.ts"],"names":[],"mappings":"AAAA;;;;;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;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,MAAM,GAAG,SAAS,CA0BpB"}
@@ -1,7 +1,7 @@
1
- /** Exported for tests. */
2
- export function createTurnAccumulator() {
1
+ export function createTurnAccumulator(lastReportedCostUsd) {
3
2
  return {
4
3
  chunks: [],
4
+ reportedCostUsd: lastReportedCostUsd,
5
5
  usage: {
6
6
  costUsd: 0,
7
7
  totalTokens: 0,
@@ -22,13 +22,20 @@ export function didReachAnthropic(usage) {
22
22
  }
23
23
  /**
24
24
  * Add one stream's `finish` totals to the turn. `totalUsage` is the AI SDK
25
- * shape; `costUsd` is what Claude Code reports for the same stream under
26
- * `harnessMetadata`, and is stored on the ingested message.
25
+ * shape and counts that stream alone. `costUsd`, under `harnessMetadata`, is a
26
+ * running total, so the turn takes what it added since the last report; a
27
+ * total below that belongs to a new session, and counts in full. The turn's
28
+ * cost is stored on the ingested message.
27
29
  */
28
- export function addTurnUsage(usage, part) {
30
+ export function addTurnUsage(accumulator, part) {
31
+ const usage = accumulator.usage;
29
32
  const costUsd = readClaudeCodeCostUsd(part);
30
33
  if (costUsd !== undefined) {
31
- usage.costUsd += costUsd;
34
+ usage.costUsd +=
35
+ costUsd >= accumulator.reportedCostUsd
36
+ ? costUsd - accumulator.reportedCostUsd
37
+ : costUsd;
38
+ accumulator.reportedCostUsd = costUsd;
32
39
  }
33
40
  const totalUsage = part["totalUsage"];
34
41
  if (typeof totalUsage !== "object" || totalUsage === null) {
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/commands/hosting/worker.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAQxC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CA6ON"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/commands/hosting/worker.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAQxC,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,OAAO,EACf,MAAM,EAAE,MAAM,GAAG,GAChB,IAAI,CAoPN"}
@@ -56,12 +56,14 @@ export function registerWorkerCommands(parent, getApi) {
56
56
  .option("--name <name>", "New display name")
57
57
  .option("--folder-uuid <uuid>", "New folder UUID (pass 'null' to move to the workspace root)")
58
58
  .option("--triggers <json>", "Full replacement list of cron triggers (pass '[]' to remove all)")
59
+ .option("--run-as-user-uuid <uuid>", "Service user the worker runs as (pass 'null' to clear). Cargo then binds a temporary CARGO_API_TOKEN for that user.")
59
60
  .action(async (opts) => {
60
61
  const api = getApi();
61
62
  const result = await handleApiCall(() => api.hosting.worker.update({
62
63
  uuid: opts.uuid,
63
64
  name: opts.name,
64
65
  folderUuid: opts.folderUuid === "null" ? null : opts.folderUuid,
66
+ runAsUserUuid: opts.runAsUserUuid === "null" ? null : opts.runAsUserUuid,
65
67
  triggers: opts.triggers !== undefined
66
68
  ? parseJson(opts.triggers, "--triggers")
67
69
  : undefined,
@@ -1 +1 @@
1
- {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../src/commands/workspaceManagement/user.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAGxC,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI,CAwM7E"}
1
+ {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../src/commands/workspaceManagement/user.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAGxC,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,IAAI,CAsM7E"}
@@ -30,15 +30,16 @@ Examples:
30
30
  user
31
31
  .command("create")
32
32
  .description("Invite a user to the workspace")
33
- .requiredOption("--user-email <email>", "User email address (string, required)")
33
+ .requiredOption("--email <email>", "User email address (string, required)")
34
34
  .requiredOption("--role-slug <slug>", "Role slug to assign (string, required)")
35
35
  .addHelpText("after", `
36
36
  Example:
37
- $ cargo-ai workspaceManagement user create --user-email alice@example.com --role-slug admin`)
37
+ $ cargo-ai workspaceManagement user create --email alice@example.com --role-slug admin`)
38
38
  .action(async (opts) => {
39
39
  const api = getApi();
40
40
  const result = await handleApiCall(() => api.workspaceManagement.user.create({
41
- userEmail: opts.userEmail,
41
+ kind: "person",
42
+ email: opts.email,
42
43
  roleSlug: opts.roleSlug,
43
44
  }));
44
45
  outputJson(result);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cargo-ai/cli",
3
- "version": "1.0.105",
3
+ "version": "1.0.107",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "homepage": "https://getcargo.ai",
@@ -65,16 +65,16 @@
65
65
  "format:check": "prettier --check ."
66
66
  },
67
67
  "dependencies": {
68
- "@ai-sdk/harness": "^1.0.95",
69
- "@ai-sdk/harness-claude-code": "^1.0.99",
70
- "@cargo-ai/api": "^1.0.87",
68
+ "@ai-sdk/harness": "^1.0.144",
69
+ "@ai-sdk/harness-claude-code": "^1.0.148",
70
+ "@cargo-ai/api": "^1.0.89",
71
71
  "@cargo-ai/app-sdk": "^1.0.11",
72
- "@cargo-ai/cdk": "^1.0.99",
73
- "@cargo-ai/types": "^1.0.90",
72
+ "@cargo-ai/cdk": "^1.0.102",
73
+ "@cargo-ai/types": "^1.0.92",
74
74
  "@cargo-ai/utils": "^1.0.32",
75
75
  "@cargo-ai/worker-sdk": "^1.0.20",
76
- "@modelcontextprotocol/sdk": "1.31.0",
77
- "ai": "^7.0.84",
76
+ "@modelcontextprotocol/sdk": "^1.31.0",
77
+ "ai": "^7.0.133",
78
78
  "ai-sdk-sandbox-local": "^0.1.2",
79
79
  "commander": "^12.1.0",
80
80
  "tsx": "^4.19.2",