taskchef 8.1.0 → 8.1.1

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,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "8.1.0",
3
+ "version": "8.1.1",
4
4
  "description": "Dispatch work from a data-only workspace to visible Codex project tasks.",
5
5
  "author": {
6
6
  "name": "Favo Yang",
package/README.md CHANGED
@@ -368,8 +368,8 @@ figures are labeled API-equivalent estimates; provenance identifies the online
368
368
  pricing request or offline fallback mode, and zero-priced unknown models show
369
369
  cost unavailable rather than a misleading `$0.00`. Per-turn cost is also
370
370
  unavailable when its cumulative boundaries used different ccusage versions or
371
- pricing modes. ccusage 20.0.20 may omit GPT-5.6 cache-write charges, so TaskChef
372
- labels that analyzer limitation instead of presenting the estimate as complete.
371
+ pricing modes. TaskChef displays the cumulative estimate supplied by ccusage
372
+ without applying a separate model-family or cache-write coverage policy.
373
373
  The same detail view reports lifecycle wall-clock elapsed time independently of
374
374
  ccusage. Each terminal turn shows **Elapsed** from `startedAt` to
375
375
  `result.updatedAt`; **Total reported work** sums only valid terminal-turn
package/docs/spec.md CHANGED
@@ -172,10 +172,12 @@ store a cumulative usage boundary, and MUST NOT receive a token or cost delta.
172
172
  A later executor turn MUST use the nearest preceding reliable executor
173
173
  boundary, skipping any intervening dashboard-manual turns.
174
174
 
175
- The mode-0600 `.taskchef-usage.json` cache stores only normalized cumulative
175
+ The mode-0600 `.taskchef-usage.json` schema 2 cache stores only normalized cumulative
176
176
  token boundaries, per-turn deltas, model names, estimated cost, source version,
177
177
  and freshness. It is independent of task-log schema versions so legacy logs remain
178
- readable. Writes MUST use the workspace lock and atomic replacement. Symlinked
178
+ readable. Schema 1 usage caches MUST migrate in memory by discarding their
179
+ TaskChef-specific cost-coverage classification while preserving valid ccusage
180
+ cumulative estimates. Writes MUST use the workspace lock and atomic replacement. Symlinked
179
181
  or unsupported cache files MUST be rejected. Writes MUST compact the derived
180
182
  cache to recent task projections, recent per-turn results, and the latest
181
183
  cumulative boundary. An oversized legacy cache MUST be treated as rebuildable
@@ -214,10 +216,11 @@ The online mode records TaskChef's request, not a claim about ccusage's internal
214
216
  cache. Dollar values MUST be labeled API-equivalent estimates. Positive token
215
217
  usage with a zero or missing analyzer cost MUST display cost unavailable, not
216
218
  `$0.00`. A per-turn dollar delta MUST be unavailable when its adjacent
217
- cumulative boundaries use different analyzer versions, requested pricing modes,
218
- or declared cost coverage. For GPT-5.6 with ccusage 20.0.20, provenance MUST
219
- disclose unverified cache-write coverage and TaskChef MUST NOT claim that the
220
- estimate includes those charges.
219
+ cumulative boundaries use different analyzer versions or requested pricing
220
+ modes. When ccusage supplies a valid cumulative estimate, TaskChef MUST display
221
+ it without applying its own model-family or cache-write coverage policy. A model
222
+ family change between otherwise compatible boundaries MUST NOT prevent TaskChef
223
+ from deriving the per-turn estimate.
221
224
  The dashboard Settings response MUST report the provider version returned by
222
225
  the executable resolved for runtime use, not merely copy the dependency pin.
223
226
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskchef",
3
- "version": "8.1.0",
3
+ "version": "8.1.1",
4
4
  "description": "A non-blocking interactive dispatcher for visible Codex tasks.",
5
5
  "license": "MIT",
6
6
  "author": "Favo Yang",
@@ -482,9 +482,6 @@ export function usagePresentation(usage, { wholeTask = false } = {}) {
482
482
  : "";
483
483
  const freshness = usage.sourceUpdatedAt ?? usage.sampledAt;
484
484
  provenance.textContent = `Source: ccusage${version}${pricingMode}${freshness ? ` · updated ${formatRelativeTime(freshness)}` : ""}. Dollar cost is an API-equivalent estimate${wholeTask ? " for the task" : " for this turn"}.`;
485
- if (usage.provenance?.costCoverage === "cache_writes_unverified") {
486
- provenance.textContent += " ccusage may omit GPT-5.6 cache-write charges.";
487
- }
488
485
  container.append(provenance);
489
486
  return container;
490
487
  }
package/src/usage.js CHANGED
@@ -19,6 +19,7 @@ const PINNED_CCUSAGE_VERSION = taskchefPackage.optionalDependencies?.ccusage;
19
19
  const CCUSAGE_RESOLVER = fileURLToPath(new URL("./resolve-ccusage.js", import.meta.url));
20
20
  let npxResolvedCcusageInvocation = null;
21
21
  const USAGE_FILE_NAME = ".taskchef-usage.json";
22
+ const USAGE_SCHEMA_VERSION = 2;
22
23
  const UUID_PATTERN = /[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/gi;
23
24
  const TOKEN_FIELDS = [
24
25
  "inputTokens",
@@ -92,10 +93,6 @@ function normalizeProvenance(value, name, { includeSessionCount = false } = {})
92
93
  pricingMode: value.pricingMode === "online" || value.pricingMode === "offline"
93
94
  ? value.pricingMode
94
95
  : null,
95
- costCoverage: value.costCoverage === "cache_writes_unverified"
96
- || value.costCoverage === "ccusage_reported"
97
- ? value.costCoverage
98
- : null,
99
96
  ...(includeSessionCount ? {
100
97
  sessionCount: nonNegativeNumber(value.sessionCount, `${name}.provenance.sessionCount`),
101
98
  } : {}),
@@ -127,10 +124,6 @@ function normalizeStoredSnapshot(value, name) {
127
124
  }
128
125
  snapshot.models = models;
129
126
  snapshot.provenance = normalizeProvenance(value.provenance, name, { includeSessionCount: true });
130
- if (snapshot.provenance.pricingMode === null || snapshot.provenance.costCoverage === null) {
131
- snapshot.estimatedCostUsd = null;
132
- snapshot.costStatus = "unavailable";
133
- }
134
127
  snapshot.sampledAt = timestampOrNull(value.sampledAt, `${name}.sampledAt`);
135
128
  snapshot.sourceUpdatedAt = timestampOrNull(value.sourceUpdatedAt, `${name}.sourceUpdatedAt`);
136
129
  return snapshot;
@@ -150,7 +143,7 @@ function normalizeStoredTurn(value, name) {
150
143
  ? null
151
144
  : nonNegativeNumber(value.estimatedCostUsd, `${name}.estimatedCostUsd`);
152
145
  const provenance = normalizeProvenance(value.provenance, name);
153
- if (provenance.pricingMode === null || provenance.costCoverage === null) {
146
+ if (provenance.pricingMode === null) {
154
147
  normalized.estimatedCostUsd = null;
155
148
  }
156
149
  return {
@@ -271,9 +264,6 @@ export function aggregateCcusageSessions(payload, threadId, {
271
264
  provider: "ccusage",
272
265
  version,
273
266
  pricingMode,
274
- costCoverage: Object.keys(models).some((model) => /^gpt-5\.6(?:-|$)/i.test(model))
275
- ? "cache_writes_unverified"
276
- : "ccusage_reported",
277
267
  sessionCount: sessions.length,
278
268
  },
279
269
  sampledAt,
@@ -627,21 +617,23 @@ export async function readUsageStore(workspace) {
627
617
  if (error.code === "ENOENT") return null;
628
618
  throw error;
629
619
  });
630
- if (details === null) return { schemaVersion: 1, tasks: {} };
620
+ if (details === null) return { schemaVersion: USAGE_SCHEMA_VERSION, tasks: {} };
631
621
  if (details.isSymbolicLink() || !details.isFile()) {
632
622
  throw new Error("TaskChef usage cache must be a regular file");
633
623
  }
634
624
  if (details.size > MAX_USAGE_FILE_BYTES) {
635
- return { schemaVersion: 1, tasks: {} };
625
+ return { schemaVersion: USAGE_SCHEMA_VERSION, tasks: {} };
636
626
  }
637
627
  const value = JSON.parse(await readFile(filePath, "utf8"));
638
- if (value?.schemaVersion !== 1 || !value.tasks || typeof value.tasks !== "object") {
628
+ if (![1, USAGE_SCHEMA_VERSION].includes(value?.schemaVersion)
629
+ || !value.tasks
630
+ || typeof value.tasks !== "object") {
639
631
  throw new Error("TaskChef usage cache has an unsupported schema");
640
632
  }
641
633
  const tasks = Object.entries(value.tasks);
642
- if (tasks.length > 2_000) return { schemaVersion: 1, tasks: {} };
634
+ if (tasks.length > 2_000) return { schemaVersion: USAGE_SCHEMA_VERSION, tasks: {} };
643
635
  return {
644
- schemaVersion: 1,
636
+ schemaVersion: USAGE_SCHEMA_VERSION,
645
637
  tasks: Object.fromEntries(tasks.map(([taskId, record]) => [
646
638
  taskId,
647
639
  normalizeStoredRecord(record, `usage task ${taskId}`),
@@ -672,7 +664,7 @@ export function compactUsageStore(store) {
672
664
  tasks[taskId] = compacted;
673
665
  approximateBytes += entryBytes;
674
666
  }
675
- return { schemaVersion: 1, tasks };
667
+ return { schemaVersion: USAGE_SCHEMA_VERSION, tasks };
676
668
  }
677
669
 
678
670
  export async function writeUsageStore(workspace, store) {
@@ -704,7 +696,7 @@ export function usageDelta(current, previous = null) {
704
696
  if (!Number.isFinite(value) || value < 0) return null;
705
697
  delta[field] = value;
706
698
  }
707
- const samePricingSource = previous === null || ["version", "pricingMode", "costCoverage"]
699
+ const samePricingSource = previous === null || ["version", "pricingMode"]
708
700
  .every((field) => current.provenance?.[field] === previous.provenance?.[field]);
709
701
  let estimatedCostUsd = !samePricingSource
710
702
  || current.estimatedCostUsd === null