@use-aistack/cli 0.9.0 → 0.10.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.
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  import { Command } from "commander";
5
5
 
6
6
  // src/version.ts
7
- var CLI_VERSION = true ? "0.9.0" : "0.0.0-dev";
7
+ var CLI_VERSION = true ? "0.10.1" : "0.0.0-dev";
8
8
 
9
9
  // src/api.ts
10
10
  var BASE_URL = process.env.AISTACK_URL || "https://aistack.to";
@@ -122,6 +122,29 @@ async function syncPublish(token, bodyJson) {
122
122
  }
123
123
  return res.json();
124
124
  }
125
+ async function fetchDayManifest(baseUrl, token) {
126
+ const res = await fetch(`${baseUrl}/api/cli/sync-manifest`, {
127
+ headers: { "Content-Type": "application/json", ...authHeaders(token) }
128
+ });
129
+ if (res.status === 404) return null;
130
+ if (res.status === 401)
131
+ throw new Error(
132
+ "Authentication expired. Run `npx @use-aistack/cli login` again."
133
+ );
134
+ if (res.status === 403 || res.status === 429)
135
+ throw failure("Manifest fetch failed", res);
136
+ if (!res.ok) {
137
+ throw new Error(await formatHttpError(res, "Manifest fetch failed"));
138
+ }
139
+ const body = await res.json();
140
+ const retentionDays = typeof body.retentionDays === "number" && body.retentionDays > 0 ? body.retentionDays : 400;
141
+ const aggregateVersion = typeof body.aggregateVersion === "string" ? body.aggregateVersion : "";
142
+ const days = Array.isArray(body.days) ? body.days.flatMap((d) => {
143
+ const row = d;
144
+ return typeof row?.date === "string" && typeof row?.fingerprint === "string" ? [{ date: row.date, fingerprint: row.fingerprint }] : [];
145
+ }) : [];
146
+ return { retentionDays, aggregateVersion, days };
147
+ }
125
148
  async function setAutoSync(token, flag) {
126
149
  const res = await request("/api/cli/auto-sync", {
127
150
  method: "POST",
@@ -1592,6 +1615,64 @@ var asName = (v) => {
1592
1615
  const s = asStr(v);
1593
1616
  return s === null ? null : cleanName(s);
1594
1617
  };
1618
+ var utcDateOf = (ms) => new Date(ms).toISOString().slice(0, 10);
1619
+ function usageDayAcc(agg, tsMs) {
1620
+ const date = utcDateOf(tsMs);
1621
+ let day = agg.usageDays.get(date);
1622
+ if (!day) {
1623
+ day = {
1624
+ models: /* @__PURE__ */ new Map(),
1625
+ subagentTokens: 0,
1626
+ syntheticTokens: 0,
1627
+ projectDirs: /* @__PURE__ */ new Set()
1628
+ };
1629
+ agg.usageDays.set(date, day);
1630
+ }
1631
+ return day;
1632
+ }
1633
+ function noteUsageResponse(agg, response, sign = 1) {
1634
+ if (response.tsMs === null) return;
1635
+ const day = usageDayAcc(agg, response.tsMs);
1636
+ let m = day.models.get(response.modelKey);
1637
+ if (!m) {
1638
+ m = {
1639
+ counts: {
1640
+ input: 0,
1641
+ output: 0,
1642
+ cacheWrite5m: 0,
1643
+ cacheWrite1h: 0,
1644
+ cacheWriteUnsplit: 0,
1645
+ cacheRead: 0
1646
+ },
1647
+ costUSD: 0,
1648
+ unpricedTokens: 0
1649
+ };
1650
+ day.models.set(response.modelKey, m);
1651
+ }
1652
+ const c = response.counts;
1653
+ m.counts.input += sign * c.input;
1654
+ m.counts.output += sign * c.output;
1655
+ m.counts.cacheWrite5m += sign * c.cacheWrite5m;
1656
+ m.counts.cacheWrite1h += sign * c.cacheWrite1h;
1657
+ m.counts.cacheWriteUnsplit += sign * c.cacheWriteUnsplit;
1658
+ m.counts.cacheRead += sign * c.cacheRead;
1659
+ if (response.costUSD === null) m.unpricedTokens += sign * countsTotal(c);
1660
+ else m.costUSD += sign * response.costUSD;
1661
+ if (response.sidechain) day.subagentTokens += sign * countsTotal(c);
1662
+ }
1663
+ function noteSyntheticTokens(agg, tsMs, tokens) {
1664
+ if (tsMs === null) return;
1665
+ usageDayAcc(agg, tsMs).syntheticTokens += tokens;
1666
+ }
1667
+ function noteSessionStart(agg, sessionId, tsMs) {
1668
+ if (tsMs === null) return;
1669
+ const held = agg.sessionStarts.get(sessionId);
1670
+ if (held === void 0 || tsMs < held) agg.sessionStarts.set(sessionId, tsMs);
1671
+ }
1672
+ function noteProjectDay(agg, directory, tsMs) {
1673
+ if (tsMs === null) return;
1674
+ usageDayAcc(agg, tsMs).projectDirs.add(directory);
1675
+ }
1595
1676
  function createAggregate() {
1596
1677
  return {
1597
1678
  files: 0,
@@ -1631,7 +1712,9 @@ function createAggregate() {
1631
1712
  textBlocks: 0,
1632
1713
  webSearchRequests: 0,
1633
1714
  webFetchRequests: 0,
1634
- seen: /* @__PURE__ */ new Map()
1715
+ seen: /* @__PURE__ */ new Map(),
1716
+ usageDays: /* @__PURE__ */ new Map(),
1717
+ sessionStarts: /* @__PURE__ */ new Map()
1635
1718
  };
1636
1719
  }
1637
1720
  var bump = (m, k, n = 1) => m.set(k, (m.get(k) ?? 0) + n);
@@ -1649,7 +1732,16 @@ function emptyUsage() {
1649
1732
  };
1650
1733
  }
1651
1734
  var countsTotal = (t) => t.input + t.output + t.cacheWrite5m + t.cacheWrite1h + t.cacheWriteUnsplit + t.cacheRead;
1652
- function addModelUsage(agg, modelKey, counts, costUSD, messages = 1) {
1735
+ function addModelUsage(agg, modelKey, counts, costUSD, messages = 1, at) {
1736
+ if (at) {
1737
+ noteUsageResponse(agg, {
1738
+ tsMs: at.tsMs,
1739
+ modelKey,
1740
+ counts,
1741
+ costUSD,
1742
+ ...at.sidechain ? { sidechain: true } : {}
1743
+ });
1744
+ }
1653
1745
  let m = agg.byModel.get(modelKey);
1654
1746
  if (!m) {
1655
1747
  m = emptyUsage();
@@ -2423,6 +2515,12 @@ function foldWorkflowDays(days, options) {
2423
2515
  git: foldGitDays(days.map((day) => day.git)),
2424
2516
  ...parallelProjectDays.length === 0 ? {} : { parallelProjects: Math.max(...parallelProjectDays) },
2425
2517
  parallelProjectDays,
2518
+ gitDays: [...days].sort((a, b) => a.date.localeCompare(b.date)).map((day) => ({
2519
+ date: day.date,
2520
+ additions: day.git.additions,
2521
+ removals: day.git.removals,
2522
+ commits: day.git.commits
2523
+ })),
2426
2524
  webSearchDays
2427
2525
  };
2428
2526
  }
@@ -3181,6 +3279,38 @@ function deriveSessionPhases(events, ruleSet = PHASE_RULES_V1, harness) {
3181
3279
  };
3182
3280
  }
3183
3281
 
3282
+ // ../workflow-rules/src/usage.ts
3283
+ var MEASURED_DAYS_V1 = "measured-days/v1";
3284
+ function canonicalJson(value) {
3285
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
3286
+ if (value && typeof value === "object") {
3287
+ const entries = Object.entries(value).filter(([, v]) => v !== void 0).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
3288
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`).join(",")}}`;
3289
+ }
3290
+ return JSON.stringify(value) ?? "null";
3291
+ }
3292
+ function fnv1a64(text) {
3293
+ const prime = 0x100000001b3n;
3294
+ const mask = 0xffffffffffffffffn;
3295
+ let hash = 0xcbf29ce484222325n;
3296
+ const bytes = new TextEncoder().encode(text);
3297
+ for (const byte of bytes) {
3298
+ hash ^= BigInt(byte);
3299
+ hash = hash * prime & mask;
3300
+ }
3301
+ return hash.toString(16).padStart(16, "0");
3302
+ }
3303
+ function dayFingerprint(day) {
3304
+ return fnv1a64(
3305
+ canonicalJson({
3306
+ version: MEASURED_DAYS_V1,
3307
+ date: day.date,
3308
+ usage: day.usage,
3309
+ workflow: day.workflow
3310
+ })
3311
+ );
3312
+ }
3313
+
3184
3314
  // ../workflow-rules/src/workflowRows.ts
3185
3315
  function metricRowId(metricId) {
3186
3316
  return `metric:${metricId}`;
@@ -3481,12 +3611,23 @@ function buildPayload(input) {
3481
3611
  }
3482
3612
  };
3483
3613
  }
3484
- function toPayloadWorkflow(extraction) {
3485
- return {
3486
- aggregateVersion: extraction.aggregateVersion,
3487
- utcOffsetMinutes: extraction.utcOffsetMinutes,
3488
- days: extraction.days
3489
- };
3614
+ function applyDayConsent(days, syncConfig) {
3615
+ return days.map((day) => {
3616
+ const { workflow, usage, ...rest } = day;
3617
+ const out = { ...rest };
3618
+ if (usage) {
3619
+ out.usage = syncConfig.publishCost ? usage : {
3620
+ harnesses: usage.harnesses.map((h) => ({
3621
+ ...h,
3622
+ models: h.models.map(
3623
+ ({ usd: _usd, pricingTable: _table, ...model }) => model
3624
+ )
3625
+ }))
3626
+ };
3627
+ }
3628
+ if (workflow && syncConfig.publishWorkflow) out.workflow = workflow;
3629
+ return out;
3630
+ });
3490
3631
  }
3491
3632
  function mergeKeptPrivate(halves) {
3492
3633
  const out = {};
@@ -3505,11 +3646,18 @@ function mergeKeptPrivate(halves) {
3505
3646
  }
3506
3647
  return out;
3507
3648
  }
3508
- function buildSyncBody(built, syncConfig, autoSync, trigger = "manual", workflow, cliVersion) {
3649
+ function buildSyncBody(built, syncConfig, autoSync, trigger = "manual", measuredDays, cliVersion) {
3509
3650
  const payloads = built.map((b) => b.payload);
3510
3651
  const base = autoSync ? { payloads, autoSync, trigger } : { payloads, trigger };
3511
- const withWorkflow = workflow && syncConfig.publishWorkflow ? { ...base, workflow: toPayloadWorkflow(workflow) } : base;
3512
- const withVersion = cliVersion ? { ...withWorkflow, cliVersion } : withWorkflow;
3652
+ const withDays = measuredDays ? {
3653
+ ...base,
3654
+ measuredDays: {
3655
+ aggregateVersion: MEASURED_DAYS_V1,
3656
+ utcOffsetMinutes: measuredDays.utcOffsetMinutes,
3657
+ days: applyDayConsent(measuredDays.days, syncConfig)
3658
+ }
3659
+ } : base;
3660
+ const withVersion = cliVersion ? { ...withDays, cliVersion } : withDays;
3513
3661
  if (!syncConfig.reviewKeptPrivate) return withVersion;
3514
3662
  return {
3515
3663
  ...withVersion,
@@ -3533,7 +3681,7 @@ var finiteNonnegative = (value) => value !== void 0 && Number.isFinite(value) &&
3533
3681
  var bump2 = (map, key, amount = 1) => {
3534
3682
  map.set(key, (map.get(key) ?? 0) + amount);
3535
3683
  };
3536
- var utcDateOf = (ms) => new Date(ms).toISOString().slice(0, 10);
3684
+ var utcDateOf2 = (ms) => new Date(ms).toISOString().slice(0, 10);
3537
3685
  var PHASE_RANK = {
3538
3686
  verify: 4,
3539
3687
  handoff: 3,
@@ -3658,7 +3806,7 @@ function createHarnessWorkflowReducer(harness, localSources = createWorkflowLoca
3658
3806
  state.parentSession ??= observation.parentSession;
3659
3807
  state.sidechain ||= observation.sidechain === true;
3660
3808
  const at = new Date(observation.tsMs);
3661
- const date = utcDateOf(observation.tsMs);
3809
+ const date = utcDateOf2(observation.tsMs);
3662
3810
  if (observation.projectWorkspace) {
3663
3811
  state.projectWorkspaces.add(observation.projectWorkspace);
3664
3812
  localSources.projectWorkspaces.add(observation.projectWorkspace);
@@ -3711,7 +3859,7 @@ function createHarnessWorkflowReducer(harness, localSources = createWorkflowLoca
3711
3859
  let phaseSessionCount = 0;
3712
3860
  for (const state of sessions.values()) {
3713
3861
  if (state.firstTs === void 0) continue;
3714
- const day = dayOf(utcDateOf(state.firstTs));
3862
+ const day = dayOf(utcDateOf2(state.firstTs));
3715
3863
  const events = reduceEventBatches(state.events, harness);
3716
3864
  const responses = [...state.responses.values()];
3717
3865
  day.sessions++;
@@ -3821,7 +3969,7 @@ function createHarnessWorkflowReducer(harness, localSources = createWorkflowLoca
3821
3969
  const parent = sessions.get(parentKey);
3822
3970
  const anchor = parent?.firstTs ?? Math.min(...children.map((child) => child.firstTs ?? Infinity));
3823
3971
  if (!Number.isFinite(anchor)) continue;
3824
- const day = dayOf(utcDateOf(anchor));
3972
+ const day = dayOf(utcDateOf2(anchor));
3825
3973
  day.hasDelegation = true;
3826
3974
  day.delegation.mostSubagents = Math.max(
3827
3975
  day.delegation.mostSubagents,
@@ -3844,10 +3992,10 @@ function createHarnessWorkflowReducer(harness, localSources = createWorkflowLoca
3844
3992
  localSources.activeProjectDays.clear();
3845
3993
  for (const state of sessions.values()) {
3846
3994
  if (state.firstTs === void 0 || state.lastTs === void 0) continue;
3847
- let day = Date.parse(`${utcDateOf(state.firstTs)}T00:00:00Z`);
3848
- const lastDay = Date.parse(`${utcDateOf(state.lastTs)}T00:00:00Z`);
3995
+ let day = Date.parse(`${utcDateOf2(state.firstTs)}T00:00:00Z`);
3996
+ const lastDay = Date.parse(`${utcDateOf2(state.lastTs)}T00:00:00Z`);
3849
3997
  while (day <= lastDay) {
3850
- const date = utcDateOf(day);
3998
+ const date = utcDateOf2(day);
3851
3999
  const projects = localSources.activeProjectDays.get(date) ?? /* @__PURE__ */ new Set();
3852
4000
  for (const project of state.projectWorkspaces) projects.add(project);
3853
4001
  if (projects.size > 0)
@@ -3961,7 +4109,8 @@ function ingestRecord(agg, raw, ctx) {
3961
4109
  const rec = asObj(raw);
3962
4110
  if (!rec) return;
3963
4111
  agg.records++;
3964
- agg.projectDirs.add(projectWorkspaceDirectory(rec) ?? ctx.projectDir);
4112
+ const projectDir = projectWorkspaceDirectory(rec) ?? ctx.projectDir;
4113
+ agg.projectDirs.add(projectDir);
3965
4114
  const version = asStr(rec.version);
3966
4115
  if (version) agg.ccVersions.add(cleanName(version));
3967
4116
  const sessionId = asStr(rec.sessionId);
@@ -3977,6 +4126,8 @@ function ingestRecord(agg, raw, ctx) {
3977
4126
  agg.lastTs = agg.lastTs === null ? ts : Math.max(agg.lastTs, ts);
3978
4127
  }
3979
4128
  }
4129
+ if (sessionId) noteSessionStart(agg, sessionId, tsMs);
4130
+ noteProjectDay(agg, projectDir, tsMs);
3980
4131
  const type = asStr(rec.type);
3981
4132
  if (type === "assistant") {
3982
4133
  ingestClaudeWorkflow(agg, rec, ctx, tsMs);
@@ -4088,7 +4239,9 @@ function ingestAssistant(agg, rec, tsMs) {
4088
4239
  const model = asName(msg.model) ?? "(unknown)";
4089
4240
  if (model.startsWith("<")) {
4090
4241
  agg.syntheticRecords++;
4091
- agg.syntheticTokens += countsTotal(readCounts(usage));
4242
+ const synthetic = countsTotal(readCounts(usage));
4243
+ agg.syntheticTokens += synthetic;
4244
+ noteSyntheticTokens(agg, tsMs, synthetic);
4092
4245
  return;
4093
4246
  }
4094
4247
  if (tsMs === null) agg.untimestampedResponses++;
@@ -4188,6 +4341,7 @@ function buildContribution(usage, model, sidechain, tsMs) {
4188
4341
  entries,
4189
4342
  total: entries.reduce((a, e) => a + countsTotal(e.counts), 0),
4190
4343
  sidechain,
4344
+ tsMs,
4191
4345
  webSearch: serverTools ? asNum(serverTools.web_search_requests) : 0,
4192
4346
  webFetch: serverTools ? asNum(serverTools.web_fetch_requests) : 0,
4193
4347
  mirroredIterationTypes: [...mirrored],
@@ -4211,6 +4365,11 @@ function applyContribution(agg, c, sign) {
4211
4365
  m.cacheRead += sign * counts.cacheRead;
4212
4366
  if (costUSD === null) m.unpricedTokens += sign * countsTotal(counts);
4213
4367
  else m.costUSD += sign * costUSD;
4368
+ noteUsageResponse(
4369
+ agg,
4370
+ { tsMs: c.tsMs, modelKey, counts, costUSD, sidechain: c.sidechain },
4371
+ sign
4372
+ );
4214
4373
  });
4215
4374
  if (c.sidechain) agg.sidechainTokens += sign * c.total;
4216
4375
  else agg.mainTokens += sign * c.total;
@@ -4477,12 +4636,14 @@ function ingestLine(agg, raw, state, sinceMs) {
4477
4636
  agg.firstTs = agg.firstTs === null ? tsMs : Math.min(agg.firstTs, tsMs);
4478
4637
  agg.lastTs = agg.lastTs === null ? tsMs : Math.max(agg.lastTs, tsMs);
4479
4638
  }
4480
- noteActivity(agg, state);
4639
+ noteActivity(agg, state, tsMs);
4640
+ noteProjectDay(agg, state.cwd ?? "(unknown)", tsMs);
4481
4641
  if (type === "event_msg" && payload) ingestEvent(agg, payload, state, tsMs);
4482
4642
  else if (type === "response_item" && payload)
4483
4643
  ingestItem(agg, payload, state, tsMs);
4484
4644
  }
4485
- function noteActivity(agg, state) {
4645
+ function noteActivity(agg, state, tsMs) {
4646
+ if (state.sessionId) noteSessionStart(agg, state.sessionId, tsMs);
4486
4647
  if (state.counted) return;
4487
4648
  state.counted = true;
4488
4649
  if (state.sessionId) agg.sessions.add(state.sessionId);
@@ -4513,7 +4674,9 @@ function ingestEvent(agg, payload, state, tsMs) {
4513
4674
  agg,
4514
4675
  modelKey,
4515
4676
  counts,
4516
- apiEquivalentCost(modelKey, counts, tsMs)
4677
+ apiEquivalentCost(modelKey, counts, tsMs),
4678
+ 1,
4679
+ { tsMs }
4517
4680
  );
4518
4681
  agg.mainTokens += total;
4519
4682
  if (tsMs !== null && state.sessionId) {
@@ -4916,10 +5079,14 @@ function ingestMessageRow(agg, state, row) {
4916
5079
  const session = sessionId ? state.sessions.get(sessionId) : void 0;
4917
5080
  if (sessionId) {
4918
5081
  agg.sessions.add(sessionId);
5082
+ noteSessionStart(agg, sessionId, tsMs);
4919
5083
  if (session?.version) agg.ccVersions.add(cleanName(session.version));
4920
5084
  }
4921
5085
  const cwd = asStr(row.cwd);
4922
- if (cwd) agg.projectDirs.add(cwd);
5086
+ if (cwd) {
5087
+ agg.projectDirs.add(cwd);
5088
+ noteProjectDay(agg, cwd, tsMs);
5089
+ }
4923
5090
  if (asStr(row.role) !== "assistant") return;
4924
5091
  agg.assistantRecords++;
4925
5092
  agg.distinctResponses++;
@@ -4942,7 +5109,9 @@ function ingestMessageRow(agg, state, row) {
4942
5109
  agg,
4943
5110
  modelKey,
4944
5111
  counts,
4945
- apiEquivalentCost(modelKey, counts, tsMs)
5112
+ apiEquivalentCost(modelKey, counts, tsMs),
5113
+ 1,
5114
+ { tsMs, sidechain: Boolean(session?.parentId) }
4946
5115
  );
4947
5116
  if (sessionId && tsMs !== null) {
4948
5117
  const completed = asNum(row.completedTsMs);
@@ -5418,7 +5587,8 @@ function ingestEntry(agg, raw, state, fold, sinceMs) {
5418
5587
  agg.firstTs = agg.firstTs === null ? tsMs : Math.min(agg.firstTs, tsMs);
5419
5588
  agg.lastTs = agg.lastTs === null ? tsMs : Math.max(agg.lastTs, tsMs);
5420
5589
  }
5421
- noteActivity2(agg, state);
5590
+ noteActivity2(agg, state, tsMs);
5591
+ noteProjectDay(agg, state.cwd ?? "(unknown)", tsMs);
5422
5592
  if (role === "assistant" && message) {
5423
5593
  agg.assistantRecords++;
5424
5594
  const served = asStr(message.responseModel);
@@ -5465,7 +5635,8 @@ function ingestEntry(agg, raw, state, fold, sinceMs) {
5465
5635
  countUsage(agg, fold, rec, 0, rec.usage, state.modelKey, tsMs);
5466
5636
  }
5467
5637
  }
5468
- function noteActivity2(agg, state) {
5638
+ function noteActivity2(agg, state, tsMs) {
5639
+ if (state.sessionId) noteSessionStart(agg, state.sessionId, tsMs);
5469
5640
  if (state.counted) return;
5470
5641
  state.counted = true;
5471
5642
  if (state.sessionId) agg.sessions.add(state.sessionId);
@@ -5494,7 +5665,9 @@ function countUsage(agg, fold, rec, msgTsMs, usageRaw, modelKey, tsMs, priceable
5494
5665
  agg,
5495
5666
  key,
5496
5667
  counts,
5497
- priceable ? apiEquivalentCost(key, counts, tsMs) : null
5668
+ priceable ? apiEquivalentCost(key, counts, tsMs) : null,
5669
+ 1,
5670
+ { tsMs }
5498
5671
  );
5499
5672
  agg.mainTokens += total;
5500
5673
  return "counted";
@@ -6445,6 +6618,152 @@ import { dirname as dirname7, join as join10 } from "path";
6445
6618
  // src/sync/stage.ts
6446
6619
  import { createHash as createHash2 } from "crypto";
6447
6620
 
6621
+ // src/usage/days.ts
6622
+ var round6 = (n) => Math.round(n * 1e6) / 1e6;
6623
+ function buildUsageDays(input) {
6624
+ const { aggregate: agg, harness, publishCost, projectWorkspaceId } = input;
6625
+ const sessionsByDay = /* @__PURE__ */ new Map();
6626
+ for (const startMs of agg.sessionStarts.values()) {
6627
+ const date = utcDateOf(startMs);
6628
+ sessionsByDay.set(date, (sessionsByDay.get(date) ?? 0) + 1);
6629
+ }
6630
+ const dates = [
6631
+ .../* @__PURE__ */ new Set([...agg.usageDays.keys(), ...sessionsByDay.keys()])
6632
+ ].sort();
6633
+ const out = /* @__PURE__ */ new Map();
6634
+ for (const date of dates) {
6635
+ const acc = agg.usageDays.get(date);
6636
+ const groups = /* @__PURE__ */ new Map();
6637
+ let unpriced = 0;
6638
+ for (const [modelKey, m] of acc?.models ?? []) {
6639
+ const id = sanitizeModelId(baseModelId(modelKey));
6640
+ let g = groups.get(id);
6641
+ if (!g) {
6642
+ g = {
6643
+ tokens: {
6644
+ input: 0,
6645
+ output: 0,
6646
+ cacheWrite: 0,
6647
+ cacheRead: 0,
6648
+ cacheWriteTtl: { fiveMinute: 0, oneHour: 0, unsplit: 0 }
6649
+ },
6650
+ costUSD: 0,
6651
+ unpricedTokens: 0,
6652
+ table: null
6653
+ };
6654
+ groups.set(id, g);
6655
+ }
6656
+ g.table ??= pricingTableFor(modelKey);
6657
+ g.tokens.input += m.counts.input;
6658
+ g.tokens.output += m.counts.output;
6659
+ g.tokens.cacheRead += m.counts.cacheRead;
6660
+ g.tokens.cacheWrite += m.counts.cacheWrite5m + m.counts.cacheWrite1h + m.counts.cacheWriteUnsplit;
6661
+ g.tokens.cacheWriteTtl.fiveMinute += m.counts.cacheWrite5m;
6662
+ g.tokens.cacheWriteTtl.oneHour += m.counts.cacheWrite1h;
6663
+ g.tokens.cacheWriteTtl.unsplit += m.counts.cacheWriteUnsplit;
6664
+ g.costUSD += m.costUSD;
6665
+ g.unpricedTokens += m.unpricedTokens;
6666
+ unpriced += m.unpricedTokens;
6667
+ }
6668
+ const models = [...groups.entries()].map(([model, g]) => {
6669
+ const { cacheWriteTtl, ...plain } = g.tokens;
6670
+ const tokens = g.tokens.cacheWrite > 0 ? { ...plain, cacheWriteTtl } : plain;
6671
+ const row = { model, tokens };
6672
+ if (publishCost && g.unpricedTokens === 0 && g.table !== null && countsTotalOf(tokens) > 0) {
6673
+ row.usd = round6(g.costUSD);
6674
+ row.pricingTable = g.table;
6675
+ }
6676
+ return row;
6677
+ }).filter((row) => countsTotalOf(row.tokens) > 0).sort(
6678
+ (a, b) => countsTotalOf(b.tokens) - countsTotalOf(a.tokens) || a.model.localeCompare(b.model)
6679
+ );
6680
+ out.set(date, {
6681
+ harness,
6682
+ sessions: sessionsByDay.get(date) ?? 0,
6683
+ projectKeys: [
6684
+ ...new Set([...acc?.projectDirs ?? []].map(projectWorkspaceId))
6685
+ ].sort(),
6686
+ models,
6687
+ subagentTokens: acc?.subagentTokens ?? 0,
6688
+ excludedTokens: { unpriced, synthetic: acc?.syntheticTokens ?? 0 }
6689
+ });
6690
+ }
6691
+ return out;
6692
+ }
6693
+ var countsTotalOf = (t) => t.input + t.output + t.cacheWrite + t.cacheRead;
6694
+ function mergeUsageDays(perHarness) {
6695
+ const out = /* @__PURE__ */ new Map();
6696
+ const dates = [
6697
+ ...new Set(perHarness.flatMap((days) => [...days.keys()]))
6698
+ ].sort();
6699
+ for (const date of dates) {
6700
+ const harnesses = [];
6701
+ for (const days of perHarness) {
6702
+ const day = days.get(date);
6703
+ if (day) harnesses.push(day);
6704
+ }
6705
+ out.set(date, { harnesses });
6706
+ }
6707
+ return out;
6708
+ }
6709
+ function buildMeasuredDays(input) {
6710
+ const workflowByDate = /* @__PURE__ */ new Map();
6711
+ for (const day of input.workflow ?? []) workflowByDate.set(day.date, day);
6712
+ const dates = [.../* @__PURE__ */ new Set([...input.usage.keys(), ...workflowByDate.keys()])].filter(
6713
+ (d) => /^\d{4}-\d{2}-\d{2}$/.test(d) && d >= input.from && d <= input.to
6714
+ ).sort();
6715
+ return dates.map((date) => {
6716
+ const usage = input.usage.get(date);
6717
+ const workflow = workflowByDate.get(date);
6718
+ return {
6719
+ date,
6720
+ ...usage ? { usage } : {},
6721
+ ...workflow ? { workflow } : {}
6722
+ };
6723
+ });
6724
+ }
6725
+
6726
+ // src/usage/diff.ts
6727
+ var MAX_DAY_WINDOW = 400;
6728
+ var DAY_MS = 864e5;
6729
+ function retentionFloor(todayUtc, days) {
6730
+ const span = Math.max(1, Math.min(days, MAX_DAY_WINDOW));
6731
+ const todayMs = Date.parse(`${todayUtc}T00:00:00.000Z`);
6732
+ return new Date(todayMs - (span - 1) * DAY_MS).toISOString().slice(0, 10);
6733
+ }
6734
+ function selectDaysToPublish(input) {
6735
+ const { local, manifest, todayUtc } = input;
6736
+ const retention = manifest?.retentionDays ?? MAX_DAY_WINDOW;
6737
+ const floor = retentionFloor(todayUtc, retention);
6738
+ const comparable = manifest !== null && manifest.aggregateVersion === MEASURED_DAYS_V1;
6739
+ const held = /* @__PURE__ */ new Map();
6740
+ if (comparable) {
6741
+ for (const day of manifest.days) held.set(day.date, day.fingerprint);
6742
+ }
6743
+ const send = [];
6744
+ const skipped = [];
6745
+ for (const day of [...local].sort((a, b) => a.date.localeCompare(b.date))) {
6746
+ if (day.date < floor) {
6747
+ skipped.push({ date: day.date, reason: "expired" });
6748
+ continue;
6749
+ }
6750
+ if (comparable && day.date !== todayUtc) {
6751
+ const fingerprint = held.get(day.date);
6752
+ if (fingerprint !== void 0 && fingerprint === dayFingerprint(day)) {
6753
+ skipped.push({ date: day.date, reason: "unchanged" });
6754
+ continue;
6755
+ }
6756
+ }
6757
+ send.push(day);
6758
+ }
6759
+ return {
6760
+ send,
6761
+ unchanged: skipped.filter((s) => s.reason === "unchanged").length,
6762
+ skipped,
6763
+ mode: comparable ? "diff" : "full"
6764
+ };
6765
+ }
6766
+
6448
6767
  // src/workflow/git.ts
6449
6768
  import { execFileSync as execFileSync2 } from "child_process";
6450
6769
  import path6 from "path";
@@ -6935,10 +7254,18 @@ function payloadBlock(payload, width, ownWindow, stats) {
6935
7254
  `${days} active day${days === 1 ? "" : "s"}`,
6936
7255
  `${fmtTokens(payload.activity.totalTokens)} tokens`
6937
7256
  ];
6938
- out.push(...wrapRow("", " ", `- ${label} \xB7 ${totals.join(" \xB7 ")}`, width));
6939
- if (payload.activity.totalTokens === 0) return out;
7257
+ out.push(`${label.toUpperCase()} ${payload.activity.sessions}`);
7258
+ if (payload.activity.totalTokens === 0) {
7259
+ out.push(`usage ${totals.slice(1).join(" \xB7 ")}`);
7260
+ return out;
7261
+ }
6940
7262
  out.push(
6941
- usd === null ? "cost not published" : `cost ${fmtUSD(usd)} at API prices`
7263
+ ...wrapRow(
7264
+ "usage ",
7265
+ " ".repeat(LABEL_WIDTH),
7266
+ `${totals.slice(1).join(" \xB7 ")} \xB7 ${usd === null ? "cost not published" : `${fmtUSD(usd)} at API prices`}`,
7267
+ width
7268
+ )
6942
7269
  );
6943
7270
  if (ownWindow) {
6944
7271
  out.push(
@@ -6954,24 +7281,29 @@ function payloadBlock(payload, width, ownWindow, stats) {
6954
7281
  if (stats) {
6955
7282
  out.push(...scanNoteLines(stats, harnessLabel2(payload.harness.name)));
6956
7283
  }
6957
- const indent = " ".repeat(LABEL_WIDTH);
6958
7284
  const shown = payload.models.filter((m) => m.tokenShare >= MODEL_ROLLUP);
6959
7285
  const rolled = payload.models.filter((m) => m.tokenShare < MODEL_ROLLUP);
6960
- const modelWidth = Math.max(0, ...shown.map((m) => m.id.length), 8);
6961
- const row = (i, name, share, dollars) => `${i === 0 ? "models".padEnd(LABEL_WIDTH) : indent}${name.padEnd(modelWidth)} ${fmtPct(share).padStart(5)}${dollars}`;
6962
- shown.forEach((m, i) => {
6963
- const dollars = usd !== null && m.apiEquivalentUSD !== void 0 ? ` ${fmtUSD(m.apiEquivalentUSD)}` : "";
6964
- out.push(row(i, m.id, m.tokenShare, dollars));
6965
- });
7286
+ const entry = (name, share, dollars) => `${name} ${fmtPct(share)}${usd !== null && dollars !== void 0 ? ` ${fmtUSD(dollars)}` : ""}`;
7287
+ const entries = shown.map(
7288
+ (m) => entry(m.id, m.tokenShare, m.apiEquivalentUSD)
7289
+ );
6966
7290
  if (rolled.length > 0) {
6967
7291
  const priced = rolled.every((m) => m.apiEquivalentUSD !== void 0);
6968
- const sum = rolled.reduce((a, m) => a + (m.apiEquivalentUSD ?? 0), 0);
6969
- out.push(
6970
- row(
6971
- shown.length,
7292
+ entries.push(
7293
+ entry(
6972
7294
  `+${rolled.length} more`,
6973
7295
  rolled.reduce((a, m) => a + m.tokenShare, 0),
6974
- usd !== null && priced ? ` ${fmtUSD(sum)}` : ""
7296
+ priced ? rolled.reduce((a, m) => a + (m.apiEquivalentUSD ?? 0), 0) : void 0
7297
+ )
7298
+ );
7299
+ }
7300
+ if (entries.length > 0) {
7301
+ out.push(
7302
+ ...wrapRow(
7303
+ "models ",
7304
+ " ".repeat(LABEL_WIDTH),
7305
+ entries.join(" \xB7 "),
7306
+ width
6975
7307
  )
6976
7308
  );
6977
7309
  }
@@ -7004,13 +7336,14 @@ function payloadBlock(payload, width, ownWindow, stats) {
7004
7336
  }
7005
7337
  return out;
7006
7338
  }
7339
+ var DIVIDER = "\u2500".repeat(40);
7007
7340
  var MODEL_ROLLUP = 0.01;
7008
7341
  var PHASE_ORDER = ["scout", "build", "verify", "handoff", "unknown"];
7009
- function workflowBlock(workflow, host) {
7342
+ function workflowBlock(workflowDays, utcOffsetMinutes, host) {
7010
7343
  const out = [];
7011
- const folded = foldWorkflowDays(workflow.days, {
7012
- aggregateVersion: workflow.aggregateVersion,
7013
- utcOffsetMinutes: workflow.utcOffsetMinutes
7344
+ const folded = foldWorkflowDays(workflowDays, {
7345
+ aggregateVersion: WORKFLOW_AGGREGATES_V2,
7346
+ utcOffsetMinutes
7014
7347
  });
7015
7348
  const harnesses = folded?.harnesses ?? [];
7016
7349
  const withPlaybook = harnesses.filter((h) => h.phase);
@@ -7019,12 +7352,12 @@ function workflowBlock(workflow, host) {
7019
7352
  ...new Set(withPlaybook.map((h) => h.phase?.ruleVersion ?? ""))
7020
7353
  ].filter(Boolean);
7021
7354
  out.push(
7022
- `workflow ${harnesses.length} harness${harnesses.length === 1 ? "" : "es"} \xB7 ${sessions} sessions \xB7 ${workflow.aggregateVersion}`
7355
+ `workflow ${harnesses.length} harness${harnesses.length === 1 ? "" : "es"} \xB7 ${sessions} sessions \xB7 ${WORKFLOW_AGGREGATES_V2}`
7023
7356
  );
7024
7357
  const first = folded?.dates[0];
7025
7358
  const last = folded?.dates.at(-1);
7026
7359
  out.push(
7027
- `days ${workflow.days.length} day${workflow.days.length === 1 ? "" : "s"}${first && last ? ` \xB7 ${first} to ${last}` : ""}`
7360
+ ` ${workflowDays.length} day${workflowDays.length === 1 ? "" : "s"}${first && last ? ` \xB7 ${first} to ${last}` : ""}`
7028
7361
  );
7029
7362
  const seconds = PHASE_ORDER.map(
7030
7363
  (phase) => withPlaybook.reduce((a, h) => a + (h.phase?.phaseSec[phase] ?? 0), 0)
@@ -7043,13 +7376,29 @@ function workflowBlock(workflow, host) {
7043
7376
  out.push(` (Publish workflow is on for ${host})`);
7044
7377
  return out;
7045
7378
  }
7379
+ function daysLine(measuredDays, selection) {
7380
+ const n = measuredDays.days.length;
7381
+ const head = `${n} day${n === 1 ? "" : "s"} to publish`;
7382
+ const unchanged = selection?.unchanged ?? 0;
7383
+ return unchanged > 0 ? `${head}, ${unchanged} unchanged` : head;
7384
+ }
7385
+ function daysBlock(measuredDays, selection) {
7386
+ const out = [`days ${daysLine(measuredDays, selection)}`];
7387
+ const first = measuredDays.days[0]?.date;
7388
+ const last = measuredDays.days.at(-1)?.date;
7389
+ const usageDays = measuredDays.days.filter((d) => d.usage).length;
7390
+ if (first && last) {
7391
+ out.push(
7392
+ ` ${first} to ${last} \xB7 ${usageDays} with usage \xB7 ${measuredDays.aggregateVersion}`
7393
+ );
7394
+ }
7395
+ return out;
7396
+ }
7046
7397
  function buildGateSummary(ctx) {
7047
7398
  const { body, keptPrivate, config, source, baseUrl } = ctx;
7048
7399
  const { payloads } = body;
7049
7400
  const host = baseUrl.replace(/^https?:\/\//, "");
7050
7401
  const out = [];
7051
- out.push("from your machine \xB7 sync preview");
7052
- out.push("");
7053
7402
  if (config.stack === null) {
7054
7403
  out.push("to (no linked stack; publish is unavailable)");
7055
7404
  } else {
@@ -7058,49 +7407,59 @@ function buildGateSummary(ctx) {
7058
7407
  );
7059
7408
  }
7060
7409
  out.push(
7061
- `searched ${HARNESS_ADAPTERS.map((a) => harnessLabel2(a.name).toLowerCase()).join(", ")}${body.cliVersion ? ` \xB7 aistack ${body.cliVersion}` : ""}`
7410
+ `searched ${HARNESS_ADAPTERS.map((a) => harnessLabel2(a.name).toLowerCase()).join(", ")}`
7062
7411
  );
7063
7412
  const windows = new Set(
7064
7413
  payloads.map(
7065
7414
  (p8) => `${p8.window.days} days \xB7 ${p8.window.from} \u2192 ${p8.window.to}`
7066
7415
  )
7067
7416
  );
7068
- if (windows.size === 1) out.push(`window ${[...windows][0]}`);
7417
+ if (windows.size === 1) {
7418
+ out.push(
7419
+ `window ${[...windows][0]}${body.cliVersion ? ` \xB7 aistack ${body.cliVersion}` : ""}`
7420
+ );
7421
+ }
7069
7422
  const width = wrapWidth(ctx.width);
7070
7423
  for (const payload of payloads) {
7071
7424
  const stats = ctx.scanStats?.[payload.harness.name];
7072
- out.push("");
7425
+ out.push("", DIVIDER, "");
7073
7426
  out.push(...payloadBlock(payload, width, windows.size > 1, stats));
7074
7427
  }
7075
- if (out[out.length - 1] === "") out.pop();
7076
- out.push("");
7077
- out.push(
7078
- body.workflow ? workflowBlock(body.workflow, host).join("\n") : "workflow not published"
7428
+ out.push("", DIVIDER, "", "ALSO PUBLISHING");
7429
+ if (body.measuredDays) {
7430
+ out.push(...daysBlock(body.measuredDays, ctx.days));
7431
+ }
7432
+ const workflowDays = (body.measuredDays?.days ?? []).flatMap(
7433
+ (d) => d.workflow ? [d.workflow] : []
7079
7434
  );
7435
+ if (!config.publishWorkflow || !body.measuredDays) {
7436
+ out.push("workflow not published");
7437
+ } else if (workflowDays.length === 0) {
7438
+ out.push("workflow on, no changed day to publish");
7439
+ } else {
7440
+ out.push(
7441
+ ...workflowBlock(workflowDays, body.measuredDays.utcOffsetMinutes, host)
7442
+ );
7443
+ }
7080
7444
  const n = payloads.reduce((a, p8) => a + withheldCount(p8), 0);
7081
7445
  if (n > 0) {
7082
- out.push("");
7083
- out.push(`kept private: ${n} name${n === 1 ? "" : "s"}`);
7084
7446
  const rows = keptPrivateRows(keptPrivate);
7085
7447
  const shown = rows.slice(0, KEPT_PRIVATE_ROWS_SHOWN);
7086
- const width2 = Math.max(...shown.map((r) => r.label.length));
7087
- for (const row of shown) {
7088
- out.push(` ${row.label.padEnd(width2)} ${row.names}`);
7089
- }
7090
- if (rows.length > shown.length) {
7091
- out.push(` ...${rows.length - shown.length} more`);
7092
- }
7448
+ const examples = shown.map((r) => r.names > 1 ? `${r.label} \xD7${r.names}` : r.label).join(", ");
7449
+ const more = rows.length > shown.length ? `, ...${rows.length - shown.length} more` : "";
7450
+ out.push(`private ${n} name${n === 1 ? "" : "s"} \xB7 ${examples}${more}`);
7093
7451
  if (body.keptPrivate !== void 0 && config.stack !== null) {
7094
- out.push(` publish them at ${host}/stacks/${config.stack.slug}/changes`);
7095
7452
  out.push(
7096
- " (they go up for you to review - turn off: Review kept-private names, on your stack)"
7453
+ ` they go up for you to review at ${host}/stacks/${config.stack.slug}/changes`
7454
+ );
7455
+ out.push(
7456
+ " (turn off: Review kept-private names, on your stack)"
7097
7457
  );
7098
7458
  } else {
7099
- out.push(" they stay on this machine");
7459
+ out.push(" they stay on this machine");
7100
7460
  }
7101
7461
  }
7102
7462
  if (body.autoSync !== void 0) {
7103
- out.push("");
7104
7463
  out.push(
7105
7464
  `auto-sync ${body.autoSync.enabled ? `on, about every ${body.autoSync.frequencyHours}h` : "off"}`
7106
7465
  );
@@ -7118,6 +7477,7 @@ function buildGateSummary(ctx) {
7118
7477
  }
7119
7478
 
7120
7479
  // src/sync/stage.ts
7480
+ var utcDate2 = (ms) => new Date(ms).toISOString().slice(0, 10);
7121
7481
  function stageId(bodyJson) {
7122
7482
  return createHash2("sha256").update(bodyJson).digest("hex").slice(0, 12);
7123
7483
  }
@@ -7128,20 +7488,33 @@ async function stageSync(deps) {
7128
7488
  const adapters = deps.adaptersImpl ?? detectedAdapters;
7129
7489
  const windowDays = deps.windowDays ?? DEFAULT_WINDOW_DAYS;
7130
7490
  const projectWorkspaceId = deps.getProjectWorkspaceIdImpl ?? getProjectWorkspaceId;
7491
+ const fetchManifest = deps.fetchManifestImpl ?? fetchDayManifest;
7131
7492
  const { config, source } = await loadConfig({
7132
7493
  baseUrl: deps.baseUrl,
7133
7494
  ...token ? { token } : {}
7134
7495
  });
7496
+ let manifest = null;
7497
+ if (token) {
7498
+ try {
7499
+ manifest = await fetchManifest(deps.baseUrl, token);
7500
+ } catch {
7501
+ manifest = null;
7502
+ }
7503
+ }
7504
+ const retentionDays = Math.max(
7505
+ 1,
7506
+ Math.min(manifest?.retentionDays ?? MAX_DAY_WINDOW, MAX_DAY_WINDOW)
7507
+ );
7135
7508
  const built = [];
7136
7509
  const scanStats = {};
7137
7510
  const workflowScans = [];
7511
+ const usageScans = [];
7138
7512
  const sinceMs = windowStartMs(now, windowDays);
7139
- for (const adapter of await adapters(sinceMs)) {
7140
- const { aggregate, stats, workflow: workflow2, workflowLocal } = await adapter.scan({
7141
- sinceMs
7142
- });
7513
+ const daysSinceMs = windowStartMs(now, retentionDays);
7514
+ const active = await adapters(sinceMs);
7515
+ for (const adapter of active) {
7516
+ const { aggregate, stats } = await adapter.scan({ sinceMs });
7143
7517
  scanStats[adapter.name] = stats;
7144
- workflowScans.push({ aggregate: workflow2, local: workflowLocal });
7145
7518
  built.push(
7146
7519
  buildPayload({
7147
7520
  aggregate,
@@ -7155,19 +7528,51 @@ async function stageSync(deps) {
7155
7528
  })
7156
7529
  );
7157
7530
  }
7531
+ for (const adapter of active) {
7532
+ const { aggregate, workflow: workflow2, workflowLocal } = await adapter.scan({
7533
+ sinceMs: daysSinceMs
7534
+ });
7535
+ workflowScans.push({ aggregate: workflow2, local: workflowLocal });
7536
+ usageScans.push(
7537
+ buildUsageDays({
7538
+ harness: adapter.name,
7539
+ aggregate,
7540
+ publishCost: config.publishCost,
7541
+ projectWorkspaceId
7542
+ })
7543
+ );
7544
+ }
7158
7545
  const settings = (deps.getSettingsImpl ?? getSettings)();
7159
7546
  const workflow = workflowScans.length > 0 && config.publishWorkflow ? extractLocalWorkflow({
7160
7547
  harnesses: workflowScans,
7161
- fromMs: sinceMs,
7548
+ fromMs: daysSinceMs,
7162
7549
  toMs: now,
7163
7550
  ...deps.gitRunnerImpl ? { run: deps.gitRunnerImpl } : {}
7164
7551
  }) : void 0;
7552
+ const localDays = applyDayConsent(
7553
+ buildMeasuredDays({
7554
+ usage: mergeUsageDays(usageScans),
7555
+ ...workflow ? { workflow: workflow.days } : {},
7556
+ from: utcDate2(daysSinceMs),
7557
+ to: utcDate2(now)
7558
+ }),
7559
+ config
7560
+ );
7561
+ const days = selectDaysToPublish({
7562
+ local: localDays,
7563
+ manifest,
7564
+ todayUtc: utcDate2(now)
7565
+ });
7165
7566
  const body = buildSyncBody(
7166
7567
  built,
7167
7568
  config,
7168
7569
  settings.autoSync,
7169
7570
  deps.trigger,
7170
- workflow,
7571
+ active.length > 0 ? {
7572
+ aggregateVersion: MEASURED_DAYS_V1,
7573
+ utcOffsetMinutes: workflow?.utcOffsetMinutes ?? machineUtcOffsetMinutes(),
7574
+ days: days.send
7575
+ } : void 0,
7171
7576
  CLI_VERSION
7172
7577
  );
7173
7578
  const bodyJson = JSON.stringify(body);
@@ -7179,6 +7584,7 @@ async function stageSync(deps) {
7179
7584
  source,
7180
7585
  baseUrl: deps.baseUrl,
7181
7586
  scanStats,
7587
+ days,
7182
7588
  // The real terminal, so the inventory rows break where this window ends
7183
7589
  // (#217). A pipe reports nothing and the preview falls back to 80.
7184
7590
  width: process.stdout.columns
@@ -7201,7 +7607,8 @@ async function stageSync(deps) {
7201
7607
  config,
7202
7608
  token,
7203
7609
  stagedAt: now,
7204
- blockedReason
7610
+ blockedReason,
7611
+ days
7205
7612
  };
7206
7613
  }
7207
7614
 
@@ -7385,7 +7792,7 @@ async function syncCommand(options = {}) {
7385
7792
  return;
7386
7793
  }
7387
7794
  s.stop("Scan complete");
7388
- p7.log.message(staged.summary.split("\n").join("\n"));
7795
+ p7.log.message(staged.summary.split("\n").map(styleSummaryLine).join("\n"));
7389
7796
  if (staged.blockedReason !== null) {
7390
7797
  outroError(staged.blockedReason);
7391
7798
  process.exitCode = 1;
@@ -7432,6 +7839,21 @@ async function syncCommand(options = {}) {
7432
7839
  process.exitCode = 1;
7433
7840
  }
7434
7841
  }
7842
+ function styleSummaryLine(line) {
7843
+ if (line.startsWith("\u2500")) return dim(line);
7844
+ const section2 = /^([A-Z][A-Z0-9 .-]+?)( \d+)?$/.exec(line);
7845
+ if (section2) return `${bold(section2[1] ?? "")}${dim(section2[2] ?? "")}`;
7846
+ const labelled = /^([a-z-]+)( +)(.*)$/.exec(line);
7847
+ if (labelled) {
7848
+ const [, label = "", gap = "", rest = ""] = labelled;
7849
+ const body = label === "skipped" ? yellow(rest) : rest.replace(/≈\$[\d,]+/g, (m) => lime(m));
7850
+ return `${dim(label)}${gap}${body}`;
7851
+ }
7852
+ const sub = /^( {2}[a-z]+ +)(.*)$/.exec(line);
7853
+ if (sub) return `${lime(sub[1] ?? "")}${dim(sub[2] ?? "")}`;
7854
+ if (/^ {10}\S/.test(line)) return dim(line);
7855
+ return line;
7856
+ }
7435
7857
 
7436
7858
  // src/sync/server.ts
7437
7859
  var SERVER_NAME = "aistack";