@mduan/paseo-cli 0.11.0-fork.1 → 0.11.0-fork.3

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 (68) hide show
  1. package/node_modules/@getpaseo/client/package.json +3 -3
  2. package/node_modules/@getpaseo/highlight/package.json +1 -1
  3. package/node_modules/@getpaseo/plugin/package.json +3 -3
  4. package/node_modules/@getpaseo/protocol/dist/agent-types.d.ts +3 -0
  5. package/node_modules/@getpaseo/protocol/dist/generated/validation/ws-outbound.aot.js +337 -1
  6. package/node_modules/@getpaseo/protocol/dist/messages.js +4 -0
  7. package/node_modules/@getpaseo/protocol/package.json +1 -1
  8. package/node_modules/@getpaseo/relay/package.json +1 -1
  9. package/node_modules/@getpaseo/server/dist/server/builtin-plugins/package.json +1 -1
  10. package/node_modules/@getpaseo/server/dist/server/server/agent/agent-manager.d.ts +2 -2
  11. package/node_modules/@getpaseo/server/dist/server/server/agent/agent-manager.js +5 -0
  12. package/node_modules/@getpaseo/server/dist/server/server/agent/agent-projections.js +4 -0
  13. package/node_modules/@getpaseo/server/dist/server/server/agent/agent-sdk-types.d.ts +8 -1
  14. package/node_modules/@getpaseo/server/dist/server/server/agent/agent-storage.d.ts +2 -0
  15. package/node_modules/@getpaseo/server/dist/server/server/agent/agent-storage.js +2 -0
  16. package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/cost.d.ts +17 -0
  17. package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/cost.js +25 -0
  18. package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/subtitle-format.d.ts +8 -0
  19. package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/subtitle-format.js +22 -0
  20. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/appended-lines-reader.d.ts +20 -0
  21. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/appended-lines-reader.js +59 -0
  22. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/agent.js +147 -4
  23. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/live-source.d.ts +6 -0
  24. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/live-source.js +33 -0
  25. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/presentation.d.ts +4 -0
  26. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/presentation.js +6 -8
  27. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/replay-source.d.ts +13 -0
  28. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/replay-source.js +44 -22
  29. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/transcript-cost.d.ts +18 -0
  30. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/transcript-cost.js +50 -0
  31. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/pricing.d.ts +15 -1
  32. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/pricing.js +32 -1
  33. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/rollout-cost.d.ts +4 -8
  34. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/rollout-cost.js +11 -51
  35. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex-app-server-agent.d.ts +7 -1
  36. package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex-app-server-agent.js +119 -17
  37. package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/snapshot.d.ts +14 -0
  38. package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/snapshot.js +91 -4
  39. package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/store.d.ts +3 -3
  40. package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/store.js +24 -18
  41. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-930503b4f858c84de293b25a88bddcd5.js → desktop-attachment-bridge-6eaa3854bb0e0bf2260c50ed5acac196.js} +1 -1
  42. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6eaa3854bb0e0bf2260c50ed5acac196.js.br +4 -0
  43. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6eaa3854bb0e0bf2260c50ed5acac196.js.gz +0 -0
  44. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-46b63a296048f752e9cace2869e65020.js → desktop-attachment-store-f093e6af17b9293a6d18bd73214b3172.js} +1 -1
  45. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-46b63a296048f752e9cace2869e65020.js.br → desktop-attachment-store-f093e6af17b9293a6d18bd73214b3172.js.br} +0 -0
  46. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-f093e6af17b9293a6d18bd73214b3172.js.gz +0 -0
  47. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{index-9489c4e1587c4252f0bd3b6e4b1abab3.js → index-ac557a7bf2f9db15fc71b6d2cbb3fcf7.js} +748 -747
  48. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-ac557a7bf2f9db15fc71b6d2cbb3fcf7.js.br +0 -0
  49. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-ac557a7bf2f9db15fc71b6d2cbb3fcf7.js.gz +0 -0
  50. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-4443393854050b1919467b89f1cbafc4.js → indexeddb-attachment-store-c1b8c035b248805cc62bb0f7b8e50acc.js} +1 -1
  51. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-4443393854050b1919467b89f1cbafc4.js.br → indexeddb-attachment-store-c1b8c035b248805cc62bb0f7b8e50acc.js.br} +0 -0
  52. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c1b8c035b248805cc62bb0f7b8e50acc.js.gz +0 -0
  53. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-d5f9e56b2ce163fcb45fa34b52e2c3d1.js → native-file-attachment-store-c3b75054cb85e7c8b21aedadaf7d54f3.js} +3 -3
  54. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-c3b75054cb85e7c8b21aedadaf7d54f3.js.br +0 -0
  55. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-c3b75054cb85e7c8b21aedadaf7d54f3.js.gz +0 -0
  56. package/node_modules/@getpaseo/server/dist/server/web-ui/index.html +1 -1
  57. package/node_modules/@getpaseo/server/dist/server/web-ui/index.html.br +0 -0
  58. package/node_modules/@getpaseo/server/dist/server/web-ui/index.html.gz +0 -0
  59. package/node_modules/@getpaseo/server/package.json +6 -6
  60. package/package.json +7 -7
  61. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-930503b4f858c84de293b25a88bddcd5.js.br +0 -0
  62. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-930503b4f858c84de293b25a88bddcd5.js.gz +0 -0
  63. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-46b63a296048f752e9cace2869e65020.js.gz +0 -0
  64. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-9489c4e1587c4252f0bd3b6e4b1abab3.js.br +0 -0
  65. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-9489c4e1587c4252f0bd3b6e4b1abab3.js.gz +0 -0
  66. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-4443393854050b1919467b89f1cbafc4.js.gz +0 -0
  67. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-d5f9e56b2ce163fcb45fa34b52e2c3d1.js.br +0 -0
  68. package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-d5f9e56b2ce163fcb45fa34b52e2c3d1.js.gz +0 -0
@@ -253,8 +253,10 @@ const AgentUsageSchema = z.object({
253
253
  inputTokens: z.number().optional(),
254
254
  cachedInputTokens: z.number().optional(),
255
255
  outputTokens: z.number().optional(),
256
+ subagentCostUsd: z.number().optional(),
256
257
  totalCostUsd: z.number().optional(),
257
258
  totalCostUnavailable: z.boolean().optional(),
259
+ totalCostEstimated: z.boolean().optional(),
258
260
  contextWindowMaxTokens: z.number().optional(),
259
261
  contextWindowUsedTokens: z.number().optional(),
260
262
  });
@@ -1570,6 +1572,8 @@ export const AgentTurnDiffsListRequestMessageSchema = z.object({
1570
1572
  export const AgentTurnDiffTargetSchema = z.discriminatedUnion("kind", [
1571
1573
  z.object({ kind: z.literal("turn"), turnId: z.string() }),
1572
1574
  z.object({ kind: z.literal("last_turn") }),
1575
+ // COMPAT(turnDiffSession): added in v0.11.0-beta.3, remove after 2027-01-04. The daemon no longer
1576
+ // serves Chat Session diffs; older clients still send this target.
1573
1577
  z.object({ kind: z.literal("session") }),
1574
1578
  ]);
1575
1579
  export const AgentTurnDiffsGetDiffRequestMessageSchema = z.object({
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getpaseo/protocol",
3
- "version": "0.11.0-fork.1",
3
+ "version": "0.11.0-fork.3",
4
4
  "description": "Paseo shared protocol schemas and wire types",
5
5
  "files": [
6
6
  "dist",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getpaseo/relay",
3
- "version": "0.11.0-fork.1",
3
+ "version": "0.11.0-fork.3",
4
4
  "description": "Paseo relay for bridging daemon and client connections",
5
5
  "files": [
6
6
  "dist",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getpaseo/builtin-plugins",
3
- "version": "0.11.0-fork.1",
3
+ "version": "0.11.0-fork.3",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
@@ -12,7 +12,7 @@ import { type ForegroundTurnWaiter } from "./agent-run-state.js";
12
12
  import { type RewindMode } from "./rewind/rewind.js";
13
13
  import type { PaseoToolCatalogFactory } from "./tools/types.js";
14
14
  import { type ProviderSubagentDescriptor, type ProviderSubagentStoreEvent } from "./provider-subagents/store.js";
15
- import type { WorkingTreeSnapshot } from "./turn-diffs/snapshot.js";
15
+ import type { TurnStartSnapshot } from "./turn-diffs/snapshot.js";
16
16
  import type { TurnDiffStore } from "./turn-diffs/store.js";
17
17
  export declare class AgentManagerShuttingDownError extends Error {
18
18
  constructor();
@@ -160,7 +160,7 @@ export type AttentionState = {
160
160
  };
161
161
  interface PendingTurnDiff {
162
162
  turnId: string;
163
- start: WorkingTreeSnapshot;
163
+ start: TurnStartSnapshot;
164
164
  clientMessageId?: string;
165
165
  }
166
166
  interface ManagedAgentBase {
@@ -229,6 +229,9 @@ function buildExplicitTimelineSeedForRegister(now, options) {
229
229
  function totalCostOf(usage) {
230
230
  return usage?.totalCostUsd;
231
231
  }
232
+ function subagentCostOf(usage) {
233
+ return usage?.subagentCostUsd;
234
+ }
232
235
  function buildImportedTimelineRows(entries) {
233
236
  const rows = [];
234
237
  for (const entry of entries) {
@@ -780,6 +783,7 @@ export class AgentManager {
780
783
  workspaceId: options?.workspaceId ?? null,
781
784
  });
782
785
  launchContext.priorTotalCostUsd = totalCostOf(record?.lastUsage);
786
+ launchContext.priorSubagentCostUsd = subagentCostOf(record?.lastUsage);
783
787
  const providerLaunchConfig = this.resolveProviderLaunchConfig(launchConfig, launchContext);
784
788
  const session = await client.resumeSession(handle, providerLaunchConfig, launchContext, currentResumeOptions);
785
789
  await this.requireExternalMcpSupport(session, storedConfig);
@@ -931,6 +935,7 @@ export class AgentManager {
931
935
  const previousPaseoToolPolicy = this.paseoToolPolicies.get(agentId);
932
936
  const launchContext = await this.buildLaunchContext(agentId, client, storedConfig.cwd, paseoToolPolicy, undefined, { reason: "refresh", purpose: "interactive", workspaceId: existing.workspaceId });
933
937
  launchContext.priorTotalCostUsd = totalCostOf(preservedLastUsage);
938
+ launchContext.priorSubagentCostUsd = subagentCostOf(preservedLastUsage);
934
939
  const providerLaunchConfig = this.resolveProviderLaunchConfig(launchConfig, launchContext);
935
940
  if (Object.keys(storedConfig.mcpServers ?? {}).length > 0 &&
936
941
  existing.session.capabilities.supportsMcpServers !== true) {
@@ -371,6 +371,7 @@ function sanitizeUsage(value) {
371
371
  "inputTokens",
372
372
  "cachedInputTokens",
373
373
  "outputTokens",
374
+ "subagentCostUsd",
374
375
  "totalCostUsd",
375
376
  "contextWindowMaxTokens",
376
377
  "contextWindowUsedTokens",
@@ -383,6 +384,9 @@ function sanitizeUsage(value) {
383
384
  if (typeof sanitized.totalCostUnavailable === "boolean") {
384
385
  result.totalCostUnavailable = sanitized.totalCostUnavailable;
385
386
  }
387
+ if (typeof sanitized.totalCostEstimated === "boolean") {
388
+ result.totalCostEstimated = sanitized.totalCostEstimated;
389
+ }
386
390
  return Object.keys(result).length ? result : undefined;
387
391
  }
388
392
  function sanitizeRuntimeInfo(runtimeInfo) {
@@ -173,13 +173,18 @@ export interface AgentUsage {
173
173
  inputTokens?: number;
174
174
  cachedInputTokens?: number;
175
175
  outputTokens?: number;
176
+ /** Cost attributed to provider-native descendants. Paseo-managed agents are excluded. */
177
+ subagentCostUsd?: number;
178
+ /** Total cost for this provider session, including provider-native descendants. */
176
179
  totalCostUsd?: number;
177
180
  /** The provider can estimate cost, but its price list could not be loaded. */
178
181
  totalCostUnavailable?: boolean;
182
+ /** Paseo priced the provider's token counts itself; the provider reports no cost. */
183
+ totalCostEstimated?: boolean;
179
184
  contextWindowMaxTokens?: number;
180
185
  contextWindowUsedTokens?: number;
181
186
  }
182
- export type AgentUsageNumericField = Exclude<keyof AgentUsage, "totalCostUnavailable">;
187
+ export type AgentUsageNumericField = Exclude<keyof AgentUsage, "totalCostUnavailable" | "totalCostEstimated">;
183
188
  export declare const TOOL_CALL_ICON_NAMES: readonly ["wrench", "square_terminal", "eye", "pencil", "search", "bot", "sparkles", "brain", "mic_vocal"];
184
189
  export type ToolCallIconName = (typeof TOOL_CALL_ICON_NAMES)[number];
185
190
  export type ToolCallDetail = {
@@ -548,6 +553,8 @@ export interface AgentLaunchContext {
548
553
  * total restarts with their process add it, so a resume or reload keeps the session total.
549
554
  */
550
555
  priorTotalCostUsd?: number;
556
+ /** Provider-native descendant cost reported before this session object existed. */
557
+ priorSubagentCostUsd?: number;
551
558
  }
552
559
  export interface AgentCreateSessionOptions {
553
560
  /**
@@ -86,8 +86,10 @@ declare const STORED_AGENT_SCHEMA: z.ZodObject<{
86
86
  inputTokens: z.ZodOptional<z.ZodNumber>;
87
87
  cachedInputTokens: z.ZodOptional<z.ZodNumber>;
88
88
  outputTokens: z.ZodOptional<z.ZodNumber>;
89
+ subagentCostUsd: z.ZodOptional<z.ZodNumber>;
89
90
  totalCostUsd: z.ZodOptional<z.ZodNumber>;
90
91
  totalCostUnavailable: z.ZodOptional<z.ZodBoolean>;
92
+ totalCostEstimated: z.ZodOptional<z.ZodBoolean>;
91
93
  contextWindowMaxTokens: z.ZodOptional<z.ZodNumber>;
92
94
  contextWindowUsedTokens: z.ZodOptional<z.ZodNumber>;
93
95
  }, z.core.$strip>>;
@@ -37,8 +37,10 @@ const STORED_USAGE_SCHEMA = z.object({
37
37
  inputTokens: z.number().optional(),
38
38
  cachedInputTokens: z.number().optional(),
39
39
  outputTokens: z.number().optional(),
40
+ subagentCostUsd: z.number().optional(),
40
41
  totalCostUsd: z.number().optional(),
41
42
  totalCostUnavailable: z.boolean().optional(),
43
+ totalCostEstimated: z.boolean().optional(),
42
44
  contextWindowMaxTokens: z.number().optional(),
43
45
  contextWindowUsedTokens: z.number().optional(),
44
46
  });
@@ -0,0 +1,17 @@
1
+ export interface ProviderSubagentCostNode {
2
+ id: string;
3
+ parentSubagentId: string | null;
4
+ ownCostUsd: number;
5
+ }
6
+ export interface ProviderSubagentCost {
7
+ ownCostUsd: number;
8
+ subagentCostUsd: number;
9
+ totalCostUsd: number;
10
+ }
11
+ export interface ProviderSubagentCostRollup {
12
+ byId: Map<string, ProviderSubagentCost>;
13
+ totalCostUsd: number;
14
+ }
15
+ /** Roll each direct cost into every native ancestor. Missing parents remain attributed to root. */
16
+ export declare function rollupProviderSubagentCosts(nodes: readonly ProviderSubagentCostNode[]): ProviderSubagentCostRollup;
17
+ //# sourceMappingURL=cost.d.ts.map
@@ -0,0 +1,25 @@
1
+ /** Roll each direct cost into every native ancestor. Missing parents remain attributed to root. */
2
+ export function rollupProviderSubagentCosts(nodes) {
3
+ const nodesById = new Map(nodes.map((node) => [node.id, node]));
4
+ const byId = new Map(nodes.map((node) => [
5
+ node.id,
6
+ { ownCostUsd: node.ownCostUsd, subagentCostUsd: 0, totalCostUsd: node.ownCostUsd },
7
+ ]));
8
+ let totalCostUsd = 0;
9
+ for (const node of nodes) {
10
+ totalCostUsd += node.ownCostUsd;
11
+ const visited = new Set([node.id]);
12
+ let parentId = node.parentSubagentId;
13
+ while (parentId && !visited.has(parentId)) {
14
+ visited.add(parentId);
15
+ const parentCost = byId.get(parentId);
16
+ if (!parentCost)
17
+ break;
18
+ parentCost.subagentCostUsd += node.ownCostUsd;
19
+ parentCost.totalCostUsd += node.ownCostUsd;
20
+ parentId = nodesById.get(parentId)?.parentSubagentId ?? null;
21
+ }
22
+ }
23
+ return { byId, totalCostUsd };
24
+ }
25
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1,8 @@
1
+ /** Subtitle parts that every provider formats the same way. */
2
+ export declare function formatSubagentTokens(totalTokens: number | undefined): string | undefined;
3
+ /** Subagent rows show the estimated cost of the subagent and all its native descendants. */
4
+ export declare function formatSubagentCosts({ ownCostUsd, subagentCostUsd, }: {
5
+ ownCostUsd: number | undefined;
6
+ subagentCostUsd: number | undefined;
7
+ }): string[];
8
+ //# sourceMappingURL=subtitle-format.d.ts.map
@@ -0,0 +1,22 @@
1
+ /** Subtitle parts that every provider formats the same way. */
2
+ export function formatSubagentTokens(totalTokens) {
3
+ if (typeof totalTokens !== "number" || totalTokens <= 0)
4
+ return undefined;
5
+ if (totalTokens < 1000)
6
+ return `${Math.round(totalTokens)} tokens`;
7
+ return `${Math.round(totalTokens / 100) / 10}k tokens`;
8
+ }
9
+ function formatSubagentCost(costUsd) {
10
+ if (typeof costUsd !== "number" || !Number.isFinite(costUsd) || costUsd < 0)
11
+ return undefined;
12
+ const amount = costUsd < 0.01 && costUsd > 0 ? costUsd.toFixed(4) : costUsd.toFixed(2);
13
+ return `$${amount}`;
14
+ }
15
+ /** Subagent rows show the estimated cost of the subagent and all its native descendants. */
16
+ export function formatSubagentCosts({ ownCostUsd, subagentCostUsd, }) {
17
+ if (typeof ownCostUsd !== "number")
18
+ return [];
19
+ const total = formatSubagentCost(ownCostUsd + Math.max(0, subagentCostUsd ?? 0));
20
+ return total ? [`~${total}`] : [];
21
+ }
22
+ //# sourceMappingURL=subtitle-format.js.map
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Reads a file that a provider keeps appending to, one complete line at a time.
3
+ * Each read parses only the bytes appended since the previous read, and reads run one at a time so
4
+ * a line is never handed out twice.
5
+ */
6
+ export declare class AppendedLinesReader {
7
+ private readonly filePath;
8
+ private offset;
9
+ private readonly decoder;
10
+ private pendingLine;
11
+ private queue;
12
+ constructor(filePath: string);
13
+ /** Passes each line completed since the previous read to `onLine`. */
14
+ read(onLine: (line: string) => void): Promise<void>;
15
+ private readAppended;
16
+ }
17
+ export declare function parseRecordLine(line: string): Record<string, unknown> | undefined;
18
+ export declare function toRecord(value: unknown): Record<string, unknown> | undefined;
19
+ export declare function readCount(value: unknown): number;
20
+ //# sourceMappingURL=appended-lines-reader.d.ts.map
@@ -0,0 +1,59 @@
1
+ import fs from "node:fs/promises";
2
+ import { StringDecoder } from "node:string_decoder";
3
+ /**
4
+ * Reads a file that a provider keeps appending to, one complete line at a time.
5
+ * Each read parses only the bytes appended since the previous read, and reads run one at a time so
6
+ * a line is never handed out twice.
7
+ */
8
+ export class AppendedLinesReader {
9
+ constructor(filePath) {
10
+ this.filePath = filePath;
11
+ this.offset = 0;
12
+ this.decoder = new StringDecoder("utf8");
13
+ this.pendingLine = "";
14
+ this.queue = Promise.resolve();
15
+ }
16
+ /** Passes each line completed since the previous read to `onLine`. */
17
+ read(onLine) {
18
+ const result = this.queue.then(() => this.readAppended(onLine));
19
+ this.queue = result.catch(() => undefined);
20
+ return result;
21
+ }
22
+ async readAppended(onLine) {
23
+ const handle = await fs.open(this.filePath, "r");
24
+ try {
25
+ const { size } = await handle.stat();
26
+ if (size <= this.offset)
27
+ return;
28
+ const buffer = Buffer.alloc(size - this.offset);
29
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, this.offset);
30
+ this.offset += bytesRead;
31
+ const lines = (this.pendingLine + this.decoder.write(buffer.subarray(0, bytesRead))).split("\n");
32
+ this.pendingLine = lines.pop() ?? "";
33
+ for (const line of lines) {
34
+ onLine(line);
35
+ }
36
+ }
37
+ finally {
38
+ await handle.close();
39
+ }
40
+ }
41
+ }
42
+ export function parseRecordLine(line) {
43
+ try {
44
+ return toRecord(JSON.parse(line));
45
+ }
46
+ catch {
47
+ // A torn or foreign line only drops that line from an estimate.
48
+ return undefined;
49
+ }
50
+ }
51
+ export function toRecord(value) {
52
+ return typeof value === "object" && value !== null && !Array.isArray(value)
53
+ ? value
54
+ : undefined;
55
+ }
56
+ export function readCount(value) {
57
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
58
+ }
59
+ //# sourceMappingURL=appended-lines-reader.js.map
@@ -11,10 +11,12 @@ import { parsePartialJsonObject } from "./partial-json.js";
11
11
  import { ClaudeSidechainTracker } from "./sidechain-tracker.js";
12
12
  import { ClaudeTaskState } from "./task-state.js";
13
13
  import { ClaudeTaskProtocolSource, } from "./subagents/live-source.js";
14
- import { observeReplaySubagents, parseClaudeSubagentMeta, } from "./subagents/replay-source.js";
14
+ import { observeReplaySubagentCosts, observeReplaySubagents, parseClaudeSubagentMeta, } from "./subagents/replay-source.js";
15
15
  import { foldSubagentObservations } from "./subagents/observation.js";
16
16
  import { observeReplayWorkflows, parseClaudeWorkflowRun, } from "./subagents/workflow-replay-source.js";
17
17
  import { readClaudeWorkflowResultFile } from "./subagents/workflow-output.js";
18
+ import { ClaudeTranscriptCost } from "./subagents/transcript-cost.js";
19
+ import { getSharedCodexPriceList } from "../codex/pricing.js";
18
20
  import { buildClaudeFeatures, claudeModelSupportsFastMode } from "./feature-definitions.js";
19
21
  import { buildBinaryDiagnosticRows, buildCommandResolutionDiagnosticRows, formatProviderDiagnostic, formatProviderDiagnosticError, } from "../diagnostic-utils.js";
20
22
  import { appendOrReplaceGrowingAssistantMessage, runProviderTurn } from "../provider-runner.js";
@@ -1075,6 +1077,7 @@ export class ClaudeAgentClient {
1075
1077
  agentId: launchContext?.agentId,
1076
1078
  launchEnv: launchContext?.env,
1077
1079
  priorTotalCostUsd: launchContext?.priorTotalCostUsd,
1080
+ priorSubagentCostUsd: launchContext?.priorSubagentCostUsd,
1078
1081
  persistSession: options?.persistSession,
1079
1082
  logger: this.logger,
1080
1083
  queryFactory: this.queryFactory,
@@ -1101,6 +1104,7 @@ export class ClaudeAgentClient {
1101
1104
  agentId: launchContext?.agentId,
1102
1105
  launchEnv: launchContext?.env,
1103
1106
  priorTotalCostUsd: launchContext?.priorTotalCostUsd,
1107
+ priorSubagentCostUsd: launchContext?.priorSubagentCostUsd,
1104
1108
  logger: this.logger,
1105
1109
  queryFactory: this.queryFactory,
1106
1110
  resolveBinary: this.resolveBinary,
@@ -1534,6 +1538,9 @@ class ClaudeAgentSession {
1534
1538
  getToolInput: (toolUseId) => this.toolUseCache.get(toolUseId)?.input ?? null,
1535
1539
  readWorkflowResult: readClaudeWorkflowResultFile,
1536
1540
  });
1541
+ /** Task id -> cost reader over that subagent's transcript. */
1542
+ this.subagentCosts = new Map();
1543
+ this.replaySubagentTaskIds = new Set();
1537
1544
  this.sidechainTracker = new ClaudeSidechainTracker({
1538
1545
  getToolInput: (toolUseId) => this.toolUseCache.get(toolUseId)?.input ?? null,
1539
1546
  // Releases that predate the task protocol announce nothing, so the tracker keeps deriving
@@ -1545,6 +1552,7 @@ class ClaudeAgentSession {
1545
1552
  this.persistedHistory = [];
1546
1553
  this.persistedProviderSubagentEvents = [];
1547
1554
  this.historyPending = false;
1555
+ this.replaySubagentCostTargets = [];
1548
1556
  this.turnState = "idle";
1549
1557
  this.nextTurnOrdinal = 1;
1550
1558
  this.cancelCurrentTurn = null;
@@ -1652,6 +1660,7 @@ class ClaudeAgentSession {
1652
1660
  assertClaudeThinkingOptionSupported(config.model, config.thinkingOptionId);
1653
1661
  this.launchEnv = options.launchEnv;
1654
1662
  this.costBeforeQueryUsd = options.priorTotalCostUsd ?? 0;
1663
+ this.subagentCostUsd = options.priorSubagentCostUsd ?? 0;
1655
1664
  this.agentId = options.agentId;
1656
1665
  this.defaults = options.defaults;
1657
1666
  this.runtimeSettings = options.runtimeSettings;
@@ -1874,8 +1883,10 @@ class ClaudeAgentSession {
1874
1883
  }
1875
1884
  const history = this.persistedHistory;
1876
1885
  const providerSubagentEvents = this.persistedProviderSubagentEvents;
1886
+ const costTargets = this.replaySubagentCostTargets;
1877
1887
  this.persistedHistory = [];
1878
1888
  this.persistedProviderSubagentEvents = [];
1889
+ this.replaySubagentCostTargets = [];
1879
1890
  this.historyPending = false;
1880
1891
  for (const entry of history) {
1881
1892
  yield {
@@ -1886,6 +1897,28 @@ class ClaudeAgentSession {
1886
1897
  };
1887
1898
  }
1888
1899
  yield* providerSubagentEvents;
1900
+ yield* await this.replaySubagentCostEvents(costTargets);
1901
+ }
1902
+ /** Replay has no task frames to trigger pricing, so restored subagents are priced here. */
1903
+ async replaySubagentCostEvents(targets) {
1904
+ if (targets.length === 0)
1905
+ return [];
1906
+ try {
1907
+ const prices = await getSharedCodexPriceList(this.logger).get();
1908
+ if (!prices)
1909
+ return [];
1910
+ const costUsdByTaskId = new Map();
1911
+ for (const target of targets) {
1912
+ const costUsd = await this.subagentTranscriptCost(target.taskId)?.read(prices);
1913
+ if (costUsd !== undefined)
1914
+ costUsdByTaskId.set(target.taskId, costUsd);
1915
+ }
1916
+ return foldSubagentObservations(observeReplaySubagentCosts(targets, costUsdByTaskId)).map((event) => ({ type: "provider_subagent", provider: "claude", event }));
1917
+ }
1918
+ catch (error) {
1919
+ this.logger.warn({ err: error }, "Failed to estimate restored Claude subagent costs");
1920
+ return [];
1921
+ }
1889
1922
  }
1890
1923
  async getAvailableModes() {
1891
1924
  return this.availableModes;
@@ -2130,6 +2163,8 @@ class ClaudeAgentSession {
2130
2163
  this.turnState = "idle";
2131
2164
  this.sidechainTracker.clear();
2132
2165
  this.taskProtocolSource.reset();
2166
+ this.subagentCosts.clear();
2167
+ this.replaySubagentTaskIds.clear();
2133
2168
  this.input?.end();
2134
2169
  this.query?.close?.();
2135
2170
  await this.awaitWithTimeout(this.query?.interrupt?.(), "close query interrupt");
@@ -2383,6 +2418,7 @@ class ClaudeAgentSession {
2383
2418
  this.persistedHistory = [];
2384
2419
  this.persistedProviderSubagentEvents = [];
2385
2420
  this.historyPending = false;
2421
+ this.replaySubagentCostTargets = [];
2386
2422
  this.userMessageIds = [];
2387
2423
  this.emittedUserMessageIds.clear();
2388
2424
  this.rewindTurnAnchors.length = 0;
@@ -2413,6 +2449,7 @@ class ClaudeAgentSession {
2413
2449
  this.persistedHistory = [];
2414
2450
  this.persistedProviderSubagentEvents = [];
2415
2451
  this.historyPending = false;
2452
+ this.replaySubagentCostTargets = [];
2416
2453
  this.userMessageIds = [];
2417
2454
  this.emittedUserMessageIds.clear();
2418
2455
  this.rewindTurnAnchors.length = 0;
@@ -3258,6 +3295,7 @@ class ClaudeAgentSession {
3258
3295
  this.persistedHistory = [];
3259
3296
  this.persistedProviderSubagentEvents = [];
3260
3297
  this.historyPending = false;
3298
+ this.replaySubagentCostTargets = [];
3261
3299
  this.cachedRuntimeInfo = null;
3262
3300
  this.queryRestartNeeded = false;
3263
3301
  this.autonomousTurn = null;
@@ -3325,6 +3363,7 @@ class ClaudeAgentSession {
3325
3363
  for (const event of foldSubagentObservations(subagentObservations)) {
3326
3364
  events.push({ type: "provider_subagent", provider: "claude", event });
3327
3365
  }
3366
+ this.refreshSubagentCost(message);
3328
3367
  for (const observation of subagentObservations) {
3329
3368
  if (observation.kind !== "declared")
3330
3369
  continue;
@@ -3812,7 +3851,13 @@ class ClaudeAgentSession {
3812
3851
  }
3813
3852
  // A crash or startup-error result can carry a zeroed total; keep the running one.
3814
3853
  this.queryCostUsd = Math.max(this.queryCostUsd, usage.totalCostUsd);
3815
- return { ...usage, totalCostUsd: this.costBeforeQueryUsd + this.queryCostUsd };
3854
+ const totalCostUsd = this.costBeforeQueryUsd + this.queryCostUsd;
3855
+ const subagentCostUsd = Math.min(this.subagentCostUsd, totalCostUsd);
3856
+ return {
3857
+ ...usage,
3858
+ totalCostUsd,
3859
+ ...(subagentCostUsd > 0 ? { subagentCostUsd } : {}),
3860
+ };
3816
3861
  }
3817
3862
  enqueueTimeline(item) {
3818
3863
  this.pushEvent({ type: "timeline", item, provider: "claude" });
@@ -3851,6 +3896,95 @@ class ClaudeAgentSession {
3851
3896
  pushEvent(event) {
3852
3897
  this.notifySubscribers(event);
3853
3898
  }
3899
+ /**
3900
+ * Claude reports only a token count per subagent, so each usage report re-prices the
3901
+ * subagent's transcript from the point the previous report reached.
3902
+ */
3903
+ refreshSubagentCost(message) {
3904
+ if (message.type !== "system")
3905
+ return;
3906
+ if (message.subtype !== "task_progress" && message.subtype !== "task_notification")
3907
+ return;
3908
+ const taskId = message.task_id;
3909
+ if (typeof taskId !== "string" || !this.taskProtocolSource.isDeclaredTask(taskId))
3910
+ return;
3911
+ void this.readSubagentCost(taskId);
3912
+ }
3913
+ async readSubagentCost(taskId) {
3914
+ try {
3915
+ const transcript = this.subagentTranscriptCost(taskId);
3916
+ if (!transcript)
3917
+ return;
3918
+ const prices = await getSharedCodexPriceList(this.logger).get();
3919
+ if (!prices)
3920
+ return;
3921
+ const costUsd = await transcript.read(prices);
3922
+ if (costUsd === undefined)
3923
+ return;
3924
+ for (const event of foldSubagentObservations(this.taskProtocolSource.observeCost(taskId, costUsd))) {
3925
+ this.notifySubscribers({ type: "provider_subagent", provider: "claude", event });
3926
+ }
3927
+ await this.refreshSubagentCostTotal(prices);
3928
+ }
3929
+ catch (error) {
3930
+ this.logger.debug({ err: error, taskId }, "Failed to estimate Claude subagent cost");
3931
+ }
3932
+ }
3933
+ async refreshSubagentCostTotal(prices) {
3934
+ const historyPath = this.claudeSessionId ? this.resolveHistoryPath(this.claudeSessionId) : null;
3935
+ if (!historyPath)
3936
+ return;
3937
+ const directory = claudeSubagentsDirectory(historyPath);
3938
+ let entries;
3939
+ try {
3940
+ entries = await promises.readdir(directory);
3941
+ }
3942
+ catch (error) {
3943
+ if (error.code === "ENOENT")
3944
+ return;
3945
+ throw error;
3946
+ }
3947
+ const admittedTaskIds = new Set([
3948
+ ...this.replaySubagentTaskIds,
3949
+ ...this.taskProtocolSource.costTaskIds,
3950
+ ]);
3951
+ const costs = await Promise.all(entries
3952
+ .filter((entry) => entry.startsWith("agent-") && entry.endsWith(".jsonl"))
3953
+ .map(async (entry) => {
3954
+ const taskId = entry.slice("agent-".length, -".jsonl".length);
3955
+ if (!admittedTaskIds.has(taskId))
3956
+ return undefined;
3957
+ return this.subagentTranscriptCost(taskId)?.read(prices);
3958
+ }));
3959
+ let subagentCostUsd = 0;
3960
+ for (const cost of costs)
3961
+ subagentCostUsd += cost ?? 0;
3962
+ this.subagentCostUsd = subagentCostUsd;
3963
+ const totalCostUsd = this.costBeforeQueryUsd + this.queryCostUsd;
3964
+ if (totalCostUsd <= 0 || this.subagentCostUsd <= 0)
3965
+ return;
3966
+ this.notifySubscribers({
3967
+ type: "usage_updated",
3968
+ provider: "claude",
3969
+ usage: { subagentCostUsd: Math.min(this.subagentCostUsd, totalCostUsd) },
3970
+ });
3971
+ }
3972
+ subagentTranscriptCost(taskId) {
3973
+ const existing = this.subagentCosts.get(taskId);
3974
+ if (existing)
3975
+ return existing;
3976
+ const historyPath = this.claudeSessionId ? this.resolveHistoryPath(this.claudeSessionId) : null;
3977
+ if (!historyPath)
3978
+ return undefined;
3979
+ // Claude Code names a subagent's transcript after the same id the task protocol calls task_id.
3980
+ const transcriptPath = path.join(claudeSubagentsDirectory(historyPath), `agent-${taskId}.jsonl`);
3981
+ // Workflows and transcript-less tasks never get one; don't fetch prices for them.
3982
+ if (!fs.existsSync(transcriptPath))
3983
+ return undefined;
3984
+ const transcript = new ClaudeTranscriptCost(transcriptPath);
3985
+ this.subagentCosts.set(taskId, transcript);
3986
+ return transcript;
3987
+ }
3854
3988
  /**
3855
3989
  * Effort is reachable only through hooks.
3856
3990
  *
@@ -3968,6 +4102,9 @@ class ClaudeAgentSession {
3968
4102
  parent: readClaudeReplayParentFacts(parentEntries),
3969
4103
  convertEntry: (entry) => this.convertHistoryEntry(entry),
3970
4104
  });
4105
+ for (const taskId of subagentReplay.taskIds)
4106
+ this.replaySubagentTaskIds.add(taskId);
4107
+ this.replaySubagentCostTargets = subagentReplay.costTargets;
3971
4108
  const observations = [
3972
4109
  ...subagentReplay.observations,
3973
4110
  ...observeReplayWorkflows({
@@ -4698,9 +4835,15 @@ function readClaudeReplayParentFacts(parentEntries) {
4698
4835
  };
4699
4836
  }
4700
4837
  const CLAUDE_SUBAGENT_META_FILE = /^agent-(.+)\.meta\.json$/;
4838
+ function claudeSessionDirectory(historyPath) {
4839
+ return path.join(path.dirname(historyPath), path.basename(historyPath, ".jsonl"));
4840
+ }
4841
+ function claudeSubagentsDirectory(historyPath) {
4842
+ return path.join(claudeSessionDirectory(historyPath), "subagents");
4843
+ }
4701
4844
  function readClaudeSidechainHistory(historyPath) {
4702
- const sessionDirectory = path.join(path.dirname(historyPath), path.basename(historyPath, ".jsonl"));
4703
- const sidechainDirectory = path.join(sessionDirectory, "subagents");
4845
+ const sessionDirectory = claudeSessionDirectory(historyPath);
4846
+ const sidechainDirectory = claudeSubagentsDirectory(historyPath);
4704
4847
  const history = {
4705
4848
  contents: [],
4706
4849
  workflowContents: [],
@@ -55,6 +55,8 @@ export declare class ClaudeTaskProtocolSource {
55
55
  private readonly lastStatusById;
56
56
  /** Claude facts stay inside the provider boundary; clients receive one compact subtitle. */
57
57
  private readonly presentationById;
58
+ private readonly parentSubagentIdById;
59
+ private readonly directCostUsdById;
58
60
  private readonly lastSubtitleById;
59
61
  private sawTaskStarted;
60
62
  private sawAnyTask;
@@ -77,6 +79,7 @@ export declare class ClaudeTaskProtocolSource {
77
79
  * this source has yet to hear about.
78
80
  */
79
81
  get announcesTasks(): boolean;
82
+ get costTaskIds(): ReadonlySet<string>;
80
83
  /**
81
84
  * Whether this source declared the given subagent. Callers route frames through this before
82
85
  * attributing anything to an id: a frame for a task that was never declared belongs to work
@@ -126,6 +129,9 @@ export declare class ClaudeTaskProtocolSource {
126
129
  */
127
130
  private observeTaskProgress;
128
131
  private observeUsage;
132
+ /** Cost estimated from the subagent's transcript, which the session reads as usage grows. */
133
+ observeCost(taskId: string, costUsd: number): SubagentObservation[];
134
+ private costRollup;
129
135
  /**
130
136
  * Effort as reported by a hook firing inside a subagent.
131
137
  *