@ordewell/core 0.10.9 → 0.10.11

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 (40) hide show
  1. package/dist/{IFileSystem-C9W5mRYA.d.mts → IFileSystem-1PqRCjhu.d.mts} +21 -3
  2. package/dist/{IFileSystem-B8qRNC_6.d.ts → IFileSystem-lTRL_G9Z.d.ts} +21 -3
  3. package/dist/{ModeResolver-C1PN5FYG.d.mts → ModeResolver-6TQXVsde.d.mts} +1 -1
  4. package/dist/{ModeResolver-CaPnoU8N.d.ts → ModeResolver-CoJAJD-f.d.ts} +1 -1
  5. package/dist/{Task-hFfRS9rN.d.mts → Task-CfBM0wkV.d.mts} +94 -21
  6. package/dist/{Task-hFfRS9rN.d.ts → Task-CfBM0wkV.d.ts} +94 -21
  7. package/dist/{chunk-H7QX32BH.mjs → chunk-24EL4Z2W.mjs} +2 -2
  8. package/dist/{chunk-O6LQU3W6.mjs → chunk-ESKK5I4F.mjs} +138 -21
  9. package/dist/chunk-ESKK5I4F.mjs.map +1 -0
  10. package/dist/{chunk-LTHKFBKM.mjs → chunk-KWS3VEER.mjs} +3 -3
  11. package/dist/{chunk-EEE2GBLG.mjs → chunk-PFH7WFIB.mjs} +1 -1
  12. package/dist/chunk-PFH7WFIB.mjs.map +1 -0
  13. package/dist/index.d.mts +129 -20
  14. package/dist/index.d.ts +129 -20
  15. package/dist/index.js +556 -92
  16. package/dist/index.js.map +1 -1
  17. package/dist/index.mjs +432 -76
  18. package/dist/index.mjs.map +1 -1
  19. package/dist/parsing.d.mts +2 -2
  20. package/dist/parsing.d.ts +2 -2
  21. package/dist/parsing.js.map +1 -1
  22. package/dist/parsing.mjs +3 -3
  23. package/dist/plan-utils.d.mts +4 -4
  24. package/dist/plan-utils.d.ts +4 -4
  25. package/dist/plan-utils.js +144 -18
  26. package/dist/plan-utils.js.map +1 -1
  27. package/dist/plan-utils.mjs +22 -4
  28. package/dist/{runSettingsText-CGKX3aeV.d.ts → runSettingsText-C5uv2axI.d.ts} +29 -18
  29. package/dist/{runSettingsText-rLoYQlUH.d.mts → runSettingsText-Jb_efnI4.d.mts} +29 -18
  30. package/dist/testing.d.mts +12 -3
  31. package/dist/testing.d.ts +12 -3
  32. package/dist/testing.js +16 -1
  33. package/dist/testing.js.map +1 -1
  34. package/dist/testing.mjs +17 -2
  35. package/dist/testing.mjs.map +1 -1
  36. package/package.json +1 -1
  37. package/dist/chunk-EEE2GBLG.mjs.map +0 -1
  38. package/dist/chunk-O6LQU3W6.mjs.map +0 -1
  39. /package/dist/{chunk-H7QX32BH.mjs.map → chunk-24EL4Z2W.mjs.map} +0 -0
  40. /package/dist/{chunk-LTHKFBKM.mjs.map → chunk-KWS3VEER.mjs.map} +0 -0
@@ -15,7 +15,7 @@ import {
15
15
  stripTrailingCommas,
16
16
  taggedReadOnlyMode,
17
17
  taskWhere
18
- } from "./chunk-H7QX32BH.mjs";
18
+ } from "./chunk-24EL4Z2W.mjs";
19
19
  import {
20
20
  addTaskToPlan,
21
21
  canSetDependencies,
@@ -36,7 +36,7 @@ import {
36
36
  titledTaskRefOf,
37
37
  updateTaskInPlan,
38
38
  walkPlan
39
- } from "./chunk-EEE2GBLG.mjs";
39
+ } from "./chunk-PFH7WFIB.mjs";
40
40
 
41
41
  // src/models/Usage.ts
42
42
  function partedPromptUsage(parts) {
@@ -55,25 +55,66 @@ function addUsage(totals, record) {
55
55
  }
56
56
  if (record.reportedCost) {
57
57
  const { amount, currency } = record.reportedCost;
58
- next.reportedCost = { ...totals.reportedCost, [currency]: (totals.reportedCost?.[currency] ?? 0) + amount };
58
+ const provenance = record.reportedCost.kind || record.sessionBilling ? {
59
+ kind: record.reportedCost.kind ?? "unknown",
60
+ billing: record.sessionBilling?.type ?? "unknown",
61
+ ...record.reportedCost.basis ? { basis: record.reportedCost.basis } : {}
62
+ } : void 0;
63
+ addCost(next, currency, amount, provenance);
59
64
  }
60
65
  return next;
61
66
  }
67
+ function addCost(totals, currency, amount, provenance) {
68
+ const hadCost = totals.reportedCost?.[currency] !== void 0;
69
+ const previous = totals.costProvenance?.[currency];
70
+ totals.reportedCost = { ...totals.reportedCost, [currency]: (totals.reportedCost?.[currency] ?? 0) + amount };
71
+ if (!previous && !provenance) return;
72
+ const unknown = { kind: "unknown", billing: "unknown" };
73
+ const a = previous ?? unknown;
74
+ const b = provenance ?? unknown;
75
+ const merged = !hadCost ? b : {
76
+ kind: a.kind === "estimate" || b.kind === "estimate" ? "estimate" : a.kind === "billed" && b.kind === "billed" ? "billed" : "unknown",
77
+ billing: a.billing === b.billing ? a.billing : "mixed",
78
+ ...a.basis && a.basis === b.basis ? { basis: a.basis } : {}
79
+ };
80
+ totals.costProvenance = { ...totals.costProvenance, [currency]: merged };
81
+ }
62
82
  function addPlannerUsage(usage, record) {
63
- const next = { ...usage, totals: addUsage(usage.totals, record), byModel: addModelUsage(usage.byModel ?? [], record) };
83
+ if (record.compacted) {
84
+ if (record.subagentId || record.aggregate) return usage;
85
+ const next2 = { ...usage };
86
+ if (record.source !== void 0) next2.source = record.source;
87
+ if (record.model !== void 0) {
88
+ if (record.source !== usage.source || record.model !== usage.model) delete next2.contextWindow;
89
+ next2.model = record.model;
90
+ }
91
+ if (record.contextTokens !== void 0) next2.lastPromptTokens = record.contextTokens;
92
+ else delete next2.lastPromptTokens;
93
+ if (record.contextWindow !== void 0) next2.contextWindow = record.contextWindow > 0 ? record.contextWindow : void 0;
94
+ return next2;
95
+ }
96
+ if (record.sessionBilling && !record.reportedCost && record.inputTokens === void 0 && record.outputTokens === void 0 && record.cachedInputTokens === void 0 && record.contextWindow === void 0) {
97
+ return record.subagentId ? usage : { ...usage, sessionBilling: record.sessionBilling, source: record.source };
98
+ }
99
+ record = { ...record, sessionBilling: record.sessionBilling ?? (usage.source === void 0 || record.source === usage.source ? usage.sessionBilling : void 0) };
100
+ const next = { ...usage, ...!record.subagentId && record.sessionBilling ? { sessionBilling: record.sessionBilling } : {}, totals: addUsage(usage.totals, record), byModel: addModelUsage(usage.byModel ?? [], record) };
64
101
  if (record.subagentId) {
65
102
  next.bySubagent = { ...usage.bySubagent, [record.subagentId]: addUsage(usage.bySubagent?.[record.subagentId] ?? {}, record) };
66
103
  return next;
67
104
  }
68
- if (!record.aggregate) {
69
- if (record.source !== usage.source || record.model !== usage.model) {
70
- delete next.lastPromptTokens;
71
- delete next.contextWindow;
72
- }
73
- next.source = record.source;
74
- next.model = record.model;
105
+ if (record.aggregate) {
106
+ if (record.source !== usage.source && !record.sessionBilling) delete next.sessionBilling;
107
+ return next;
108
+ }
109
+ if (record.source !== usage.source || record.model !== usage.model) {
110
+ delete next.lastPromptTokens;
111
+ delete next.contextWindow;
75
112
  }
76
- if (record.inputTokens !== void 0) next.lastPromptTokens = record.inputTokens;
113
+ if (record.source !== usage.source && !record.sessionBilling) delete next.sessionBilling;
114
+ next.source = record.source;
115
+ next.model = record.model;
116
+ const used = record.contextTokens ?? record.inputTokens;
117
+ if (used !== void 0) next.lastPromptTokens = used;
77
118
  if (record.contextWindow !== void 0) next.contextWindow = record.contextWindow > 0 ? record.contextWindow : void 0;
78
119
  return next;
79
120
  }
@@ -84,6 +125,7 @@ function usageLine(usage) {
84
125
  const contextFill = plannerContextFill(usage);
85
126
  return {
86
127
  totals: usage.totals,
128
+ ...usage.sessionBilling ? { sessionBilling: usage.sessionBilling } : {},
87
129
  ...usage.byModel ? { byModel: usage.byModel } : {},
88
130
  ...usage.model ? { model: usage.model } : {},
89
131
  ...usage.bySubagent ? { bySubagent: usage.bySubagent } : {},
@@ -91,8 +133,8 @@ function usageLine(usage) {
91
133
  };
92
134
  }
93
135
  function plannerContextFill(usage) {
94
- if (usage.lastPromptTokens === void 0 || usage.contextWindow === void 0 || usage.contextWindow <= 0) return void 0;
95
- return { usedTokens: usage.lastPromptTokens, windowTokens: usage.contextWindow };
136
+ if (usage.lastPromptTokens === void 0) return void 0;
137
+ return { usedTokens: usage.lastPromptTokens, ...usage.contextWindow !== void 0 && usage.contextWindow > 0 ? { windowTokens: usage.contextWindow } : {} };
96
138
  }
97
139
  function addModelUsage(models, record) {
98
140
  const index = models.findIndex((m) => m.source === record.source && m.model === record.model);
@@ -104,13 +146,14 @@ function startAttemptUsage(attempt, runner, startedAt) {
104
146
  }
105
147
  function addAttemptUsage(usage, record, now) {
106
148
  const folded = addPlannerUsage(usage, record);
107
- return { ...usage, ...folded, lastPromptTokens: folded.lastPromptTokens, contextWindow: folded.contextWindow, wallTimeMs: Math.max(0, Date.parse(now) - Date.parse(usage.startedAt)) };
149
+ return { ...usage, ...folded, lastPromptTokens: folded.lastPromptTokens, contextWindow: folded.contextWindow, wallTimeMs: Math.max(0, Date.parse(usage.endedAt ?? now) - Date.parse(usage.startedAt)) };
108
150
  }
109
151
  function endAttemptUsage(usage, now, runnerSessionCost, sessionId) {
152
+ const endedAt = usage.endedAt ?? now;
110
153
  return {
111
154
  ...usage,
112
- endedAt: now,
113
- wallTimeMs: Math.max(0, Date.parse(now) - Date.parse(usage.startedAt)),
155
+ endedAt,
156
+ wallTimeMs: Math.max(0, Date.parse(endedAt) - Date.parse(usage.startedAt)),
114
157
  ...sessionId ? { sessionId } : {},
115
158
  ...runnerSessionCost ? { runnerSessionCost } : {}
116
159
  };
@@ -123,8 +166,8 @@ function resumedSessionWindow(attempts, runner, attempt, sessionId) {
123
166
  return last ? { source: last.source, model: last.model, contextWindow: last.contextWindow } : void 0;
124
167
  }
125
168
  function addUsageTotals(totals, addition) {
126
- let next = addUsage(totals, { source: "", inputTokens: addition.inputTokens, outputTokens: addition.outputTokens, cachedInputTokens: addition.cachedInputTokens });
127
- for (const [currency, amount] of Object.entries(addition.reportedCost ?? {})) next = addUsage(next, { source: "", reportedCost: { currency, amount } });
169
+ const next = addUsage(totals, { source: "", inputTokens: addition.inputTokens, outputTokens: addition.outputTokens, cachedInputTokens: addition.cachedInputTokens });
170
+ for (const [currency, amount] of Object.entries(addition.reportedCost ?? {})) addCost(next, currency, amount, addition.costProvenance?.[currency]);
128
171
  return next;
129
172
  }
130
173
  function planUsage(tasks) {
@@ -159,6 +202,71 @@ function taskUsageSummary(task) {
159
202
  ...contextFill ? { contextFill } : {}
160
203
  };
161
204
  }
205
+ function formatTokenCount(n) {
206
+ if (n < 1e3) return String(n);
207
+ if (n < 1e4) return `${(n / 1e3).toFixed(1).replace(/\.0$/, "")}k`;
208
+ if (n < 999500) return `${Math.round(n / 1e3)}k`;
209
+ return `${(n / 1e6).toFixed(1).replace(/\.0$/, "")}M`;
210
+ }
211
+ function formatCost(currency, amount) {
212
+ const value = amount >= 1 ? amount.toFixed(2) : (([whole, frac = ""]) => `${whole}.${frac.padEnd(2, "0")}`)(amount.toFixed(4).replace(/0+$/, "").split("."));
213
+ return currency.toLowerCase() === "usd" ? `$${value}` : `${value} ${currency.toUpperCase()}`;
214
+ }
215
+ function contextMeterText(fill) {
216
+ if (!fill) return null;
217
+ const used = `ctx ${formatTokenCount(fill.usedTokens)}`;
218
+ if (!fill.windowTokens) return used;
219
+ const share = fill.usedTokens / fill.windowTokens * 100;
220
+ return `${used} (${share < 1 ? "<1" : Math.round(share)}%)`;
221
+ }
222
+ function contextMeterTitle(fill) {
223
+ const used = fill.usedTokens.toLocaleString("en-US");
224
+ return fill.windowTokens ? `${used} of ${fill.windowTokens.toLocaleString("en-US")} tokens` : `${used} tokens`;
225
+ }
226
+ function costParts(totals) {
227
+ const rank = (currency) => currency.toLowerCase() === "usd" ? "" : currency.toUpperCase();
228
+ return Object.entries(totals.reportedCost ?? {}).sort(([a], [b]) => rank(a).localeCompare(rank(b))).map(([currency, amount]) => {
229
+ const provenance = totals.costProvenance?.[currency];
230
+ const equivalent = provenance?.billing === "subscription";
231
+ return `${provenance?.kind === "estimate" || equivalent ? "\u2248" : ""}${formatCost(currency, amount)}${equivalent ? " API-equivalent" : ""}`;
232
+ });
233
+ }
234
+ function costText(totals) {
235
+ const parts = costParts(totals);
236
+ return parts.length > 0 ? parts.join(" \xB7 ") : null;
237
+ }
238
+ function usageText(usage) {
239
+ const parts = [contextMeterText(usage.contextFill), costText(usage.totals)].filter((p) => p !== null);
240
+ return parts.length > 0 ? parts.join(" \xB7 ") : null;
241
+ }
242
+ function modelCostTitle(byModel) {
243
+ const lines2 = byModel.flatMap((m) => {
244
+ const cost = costParts(m.totals);
245
+ const descriptions = [...new Set(Object.values(m.totals.costProvenance ?? {}).map((p) => {
246
+ const source = m.source === "claude-code" ? "Claude Code" : m.source === "opencode" ? "OpenCode" : m.source === "openrouter" ? "OpenRouter" : m.source;
247
+ const basis = p.basis === "list" ? " at list price" : p.basis === "managed" ? " at managed price" : "";
248
+ const kind = p.kind === "estimate" ? `${source}'s estimate${basis}` : p.kind === "billed" ? `Amount billed by ${source}` : "Reported cost";
249
+ return `${kind}${p.billing === "subscription" ? "; not billed on a subscription" : ""}`;
250
+ }))];
251
+ return cost.length > 0 ? [`${m.source} / ${m.model ?? "unattributed"}: ${cost.join(" \xB7 ")}${descriptions.length ? ` \u2014 ${descriptions.join("; ")}` : ""}`] : [];
252
+ });
253
+ return lines2.length > 0 ? lines2.join("\n") : void 0;
254
+ }
255
+ function subagentCostTitle(bySubagent) {
256
+ return Object.entries(bySubagent).map(([id, totals]) => `${id}: ${costParts(totals).join(" \xB7 ") || "reported no cost"}`).join("\n");
257
+ }
258
+ function runnersOf(tasks) {
259
+ return tasks.flatMap((task) => [...task.attemptUsage ?? [], ...runnersOf(task.subtasks ?? [])]);
260
+ }
261
+ function tasksTotalText(tasks) {
262
+ const attempts = runnersOf(tasks);
263
+ if (attempts.length === 0) return null;
264
+ const costed = (a) => Object.keys(a.totals.reportedCost ?? {}).length > 0;
265
+ const costless = [...new Set(attempts.filter((a) => a.endedAt !== void 0 && isMeasured(a.totals)).map((a) => a.runner))].filter((runner) => !attempts.some((a) => a.runner === runner && costed(a)));
266
+ const note = costless.length === 0 ? [] : [`${costless.length === 1 ? costless[0] : `${costless.slice(0, -1).join(", ")} and ${costless.at(-1)}`} ${costless.length === 1 ? "reports" : "report"} no cost`];
267
+ const parts = [...costParts(planUsage(tasks).totals), ...note];
268
+ return parts.length > 0 ? `Tasks total: ${parts.join(" \xB7 ")}` : null;
269
+ }
162
270
 
163
271
  // src/services/harness/agentTools.ts
164
272
  var KNOWN_TOOLS = {
@@ -2075,7 +2183,7 @@ function openTurn(view, { turnId, prompt = "", skills = [], wakeUps = [], forced
2075
2183
  wakeUps = wakeUps.slice(adopted.wakeUps);
2076
2184
  if (wakeUps.length === 0) return adopted.prompt || prompt === "" && adopted.wakeUps > 0 ? view : promptLine(view, turnId, prompt, skills, forced);
2077
2185
  const said = prompt === "" || adopted.prompt ? view : promptLine(view, turnId, prompt, skills, forced);
2078
- const at = prompt === "" ? said.blocks.length : findLastIndex(said.blocks, (b) => b.type === "message" && b.role === "user" && b.turnId === turnId);
2186
+ const at = prompt === "" ? said.blocks.length - (said.blocks.at(-1)?.type === "usage" ? 1 : 0) : findLastIndex(said.blocks, (b) => b.type === "message" && b.role === "user" && b.turnId === turnId);
2079
2187
  const updates = wakeUps.map((text2, n) => settledMessage(`b${said.nextId + n}`, "wake_up", text2, turnId));
2080
2188
  return { ...said, blocks: [...said.blocks.slice(0, at), ...updates, ...said.blocks.slice(at)], nextId: said.nextId + updates.length };
2081
2189
  }
@@ -2749,6 +2857,15 @@ export {
2749
2857
  addUsageTotals,
2750
2858
  planUsage,
2751
2859
  taskUsageSummary,
2860
+ formatTokenCount,
2861
+ formatCost,
2862
+ contextMeterText,
2863
+ contextMeterTitle,
2864
+ costText,
2865
+ usageText,
2866
+ modelCostTitle,
2867
+ subagentCostTitle,
2868
+ tasksTotalText,
2752
2869
  sameMessage,
2753
2870
  mapAgentTool,
2754
2871
  normalizeAgentArgs,
@@ -2842,4 +2959,4 @@ export {
2842
2959
  pastGateConfirmation,
2843
2960
  newTaskFields
2844
2961
  };
2845
- //# sourceMappingURL=chunk-O6LQU3W6.mjs.map
2962
+ //# sourceMappingURL=chunk-ESKK5I4F.mjs.map