@use-aistack/cli 0.9.0 → 0.10.0
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 +443 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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.
|
|
7
|
+
var CLI_VERSION = true ? "0.10.0" : "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
|
|
3485
|
-
return {
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
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",
|
|
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
|
|
3512
|
-
|
|
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
|
|
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 =
|
|
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(
|
|
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(
|
|
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(`${
|
|
3848
|
-
const lastDay = Date.parse(`${
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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)
|
|
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";
|
|
@@ -7006,11 +7325,11 @@ function payloadBlock(payload, width, ownWindow, stats) {
|
|
|
7006
7325
|
}
|
|
7007
7326
|
var MODEL_ROLLUP = 0.01;
|
|
7008
7327
|
var PHASE_ORDER = ["scout", "build", "verify", "handoff", "unknown"];
|
|
7009
|
-
function workflowBlock(
|
|
7328
|
+
function workflowBlock(workflowDays, utcOffsetMinutes, host) {
|
|
7010
7329
|
const out = [];
|
|
7011
|
-
const folded = foldWorkflowDays(
|
|
7012
|
-
aggregateVersion:
|
|
7013
|
-
utcOffsetMinutes
|
|
7330
|
+
const folded = foldWorkflowDays(workflowDays, {
|
|
7331
|
+
aggregateVersion: WORKFLOW_AGGREGATES_V2,
|
|
7332
|
+
utcOffsetMinutes
|
|
7014
7333
|
});
|
|
7015
7334
|
const harnesses = folded?.harnesses ?? [];
|
|
7016
7335
|
const withPlaybook = harnesses.filter((h) => h.phase);
|
|
@@ -7019,12 +7338,12 @@ function workflowBlock(workflow, host) {
|
|
|
7019
7338
|
...new Set(withPlaybook.map((h) => h.phase?.ruleVersion ?? ""))
|
|
7020
7339
|
].filter(Boolean);
|
|
7021
7340
|
out.push(
|
|
7022
|
-
`workflow ${harnesses.length} harness${harnesses.length === 1 ? "" : "es"} \xB7 ${sessions} sessions \xB7 ${
|
|
7341
|
+
`workflow ${harnesses.length} harness${harnesses.length === 1 ? "" : "es"} \xB7 ${sessions} sessions \xB7 ${WORKFLOW_AGGREGATES_V2}`
|
|
7023
7342
|
);
|
|
7024
7343
|
const first = folded?.dates[0];
|
|
7025
7344
|
const last = folded?.dates.at(-1);
|
|
7026
7345
|
out.push(
|
|
7027
|
-
`
|
|
7346
|
+
` ${workflowDays.length} day${workflowDays.length === 1 ? "" : "s"}${first && last ? ` \xB7 ${first} to ${last}` : ""}`
|
|
7028
7347
|
);
|
|
7029
7348
|
const seconds = PHASE_ORDER.map(
|
|
7030
7349
|
(phase) => withPlaybook.reduce((a, h) => a + (h.phase?.phaseSec[phase] ?? 0), 0)
|
|
@@ -7043,6 +7362,24 @@ function workflowBlock(workflow, host) {
|
|
|
7043
7362
|
out.push(` (Publish workflow is on for ${host})`);
|
|
7044
7363
|
return out;
|
|
7045
7364
|
}
|
|
7365
|
+
function daysLine(measuredDays, selection) {
|
|
7366
|
+
const n = measuredDays.days.length;
|
|
7367
|
+
const head = `${n} day${n === 1 ? "" : "s"} to publish`;
|
|
7368
|
+
const unchanged = selection?.unchanged ?? 0;
|
|
7369
|
+
return unchanged > 0 ? `${head}, ${unchanged} unchanged` : head;
|
|
7370
|
+
}
|
|
7371
|
+
function daysBlock(measuredDays, selection) {
|
|
7372
|
+
const out = [`days ${daysLine(measuredDays, selection)}`];
|
|
7373
|
+
const first = measuredDays.days[0]?.date;
|
|
7374
|
+
const last = measuredDays.days.at(-1)?.date;
|
|
7375
|
+
const usageDays = measuredDays.days.filter((d) => d.usage).length;
|
|
7376
|
+
if (first && last) {
|
|
7377
|
+
out.push(
|
|
7378
|
+
` ${first} to ${last} \xB7 ${usageDays} with usage \xB7 ${measuredDays.aggregateVersion}`
|
|
7379
|
+
);
|
|
7380
|
+
}
|
|
7381
|
+
return out;
|
|
7382
|
+
}
|
|
7046
7383
|
function buildGateSummary(ctx) {
|
|
7047
7384
|
const { body, keptPrivate, config, source, baseUrl } = ctx;
|
|
7048
7385
|
const { payloads } = body;
|
|
@@ -7073,10 +7410,23 @@ function buildGateSummary(ctx) {
|
|
|
7073
7410
|
out.push(...payloadBlock(payload, width, windows.size > 1, stats));
|
|
7074
7411
|
}
|
|
7075
7412
|
if (out[out.length - 1] === "") out.pop();
|
|
7413
|
+
if (body.measuredDays) {
|
|
7414
|
+
out.push("");
|
|
7415
|
+
out.push(...daysBlock(body.measuredDays, ctx.days));
|
|
7416
|
+
}
|
|
7076
7417
|
out.push("");
|
|
7077
|
-
|
|
7078
|
-
|
|
7418
|
+
const workflowDays = (body.measuredDays?.days ?? []).flatMap(
|
|
7419
|
+
(d) => d.workflow ? [d.workflow] : []
|
|
7079
7420
|
);
|
|
7421
|
+
if (!config.publishWorkflow || !body.measuredDays) {
|
|
7422
|
+
out.push("workflow not published");
|
|
7423
|
+
} else if (workflowDays.length === 0) {
|
|
7424
|
+
out.push("workflow on, no changed day to publish");
|
|
7425
|
+
} else {
|
|
7426
|
+
out.push(
|
|
7427
|
+
...workflowBlock(workflowDays, body.measuredDays.utcOffsetMinutes, host)
|
|
7428
|
+
);
|
|
7429
|
+
}
|
|
7080
7430
|
const n = payloads.reduce((a, p8) => a + withheldCount(p8), 0);
|
|
7081
7431
|
if (n > 0) {
|
|
7082
7432
|
out.push("");
|
|
@@ -7118,6 +7468,7 @@ function buildGateSummary(ctx) {
|
|
|
7118
7468
|
}
|
|
7119
7469
|
|
|
7120
7470
|
// src/sync/stage.ts
|
|
7471
|
+
var utcDate2 = (ms) => new Date(ms).toISOString().slice(0, 10);
|
|
7121
7472
|
function stageId(bodyJson) {
|
|
7122
7473
|
return createHash2("sha256").update(bodyJson).digest("hex").slice(0, 12);
|
|
7123
7474
|
}
|
|
@@ -7128,20 +7479,33 @@ async function stageSync(deps) {
|
|
|
7128
7479
|
const adapters = deps.adaptersImpl ?? detectedAdapters;
|
|
7129
7480
|
const windowDays = deps.windowDays ?? DEFAULT_WINDOW_DAYS;
|
|
7130
7481
|
const projectWorkspaceId = deps.getProjectWorkspaceIdImpl ?? getProjectWorkspaceId;
|
|
7482
|
+
const fetchManifest = deps.fetchManifestImpl ?? fetchDayManifest;
|
|
7131
7483
|
const { config, source } = await loadConfig({
|
|
7132
7484
|
baseUrl: deps.baseUrl,
|
|
7133
7485
|
...token ? { token } : {}
|
|
7134
7486
|
});
|
|
7487
|
+
let manifest = null;
|
|
7488
|
+
if (token) {
|
|
7489
|
+
try {
|
|
7490
|
+
manifest = await fetchManifest(deps.baseUrl, token);
|
|
7491
|
+
} catch {
|
|
7492
|
+
manifest = null;
|
|
7493
|
+
}
|
|
7494
|
+
}
|
|
7495
|
+
const retentionDays = Math.max(
|
|
7496
|
+
1,
|
|
7497
|
+
Math.min(manifest?.retentionDays ?? MAX_DAY_WINDOW, MAX_DAY_WINDOW)
|
|
7498
|
+
);
|
|
7135
7499
|
const built = [];
|
|
7136
7500
|
const scanStats = {};
|
|
7137
7501
|
const workflowScans = [];
|
|
7502
|
+
const usageScans = [];
|
|
7138
7503
|
const sinceMs = windowStartMs(now, windowDays);
|
|
7139
|
-
|
|
7140
|
-
|
|
7141
|
-
|
|
7142
|
-
});
|
|
7504
|
+
const daysSinceMs = windowStartMs(now, retentionDays);
|
|
7505
|
+
const active = await adapters(sinceMs);
|
|
7506
|
+
for (const adapter of active) {
|
|
7507
|
+
const { aggregate, stats } = await adapter.scan({ sinceMs });
|
|
7143
7508
|
scanStats[adapter.name] = stats;
|
|
7144
|
-
workflowScans.push({ aggregate: workflow2, local: workflowLocal });
|
|
7145
7509
|
built.push(
|
|
7146
7510
|
buildPayload({
|
|
7147
7511
|
aggregate,
|
|
@@ -7155,19 +7519,51 @@ async function stageSync(deps) {
|
|
|
7155
7519
|
})
|
|
7156
7520
|
);
|
|
7157
7521
|
}
|
|
7522
|
+
for (const adapter of active) {
|
|
7523
|
+
const { aggregate, workflow: workflow2, workflowLocal } = await adapter.scan({
|
|
7524
|
+
sinceMs: daysSinceMs
|
|
7525
|
+
});
|
|
7526
|
+
workflowScans.push({ aggregate: workflow2, local: workflowLocal });
|
|
7527
|
+
usageScans.push(
|
|
7528
|
+
buildUsageDays({
|
|
7529
|
+
harness: adapter.name,
|
|
7530
|
+
aggregate,
|
|
7531
|
+
publishCost: config.publishCost,
|
|
7532
|
+
projectWorkspaceId
|
|
7533
|
+
})
|
|
7534
|
+
);
|
|
7535
|
+
}
|
|
7158
7536
|
const settings = (deps.getSettingsImpl ?? getSettings)();
|
|
7159
7537
|
const workflow = workflowScans.length > 0 && config.publishWorkflow ? extractLocalWorkflow({
|
|
7160
7538
|
harnesses: workflowScans,
|
|
7161
|
-
fromMs:
|
|
7539
|
+
fromMs: daysSinceMs,
|
|
7162
7540
|
toMs: now,
|
|
7163
7541
|
...deps.gitRunnerImpl ? { run: deps.gitRunnerImpl } : {}
|
|
7164
7542
|
}) : void 0;
|
|
7543
|
+
const localDays = applyDayConsent(
|
|
7544
|
+
buildMeasuredDays({
|
|
7545
|
+
usage: mergeUsageDays(usageScans),
|
|
7546
|
+
...workflow ? { workflow: workflow.days } : {},
|
|
7547
|
+
from: utcDate2(daysSinceMs),
|
|
7548
|
+
to: utcDate2(now)
|
|
7549
|
+
}),
|
|
7550
|
+
config
|
|
7551
|
+
);
|
|
7552
|
+
const days = selectDaysToPublish({
|
|
7553
|
+
local: localDays,
|
|
7554
|
+
manifest,
|
|
7555
|
+
todayUtc: utcDate2(now)
|
|
7556
|
+
});
|
|
7165
7557
|
const body = buildSyncBody(
|
|
7166
7558
|
built,
|
|
7167
7559
|
config,
|
|
7168
7560
|
settings.autoSync,
|
|
7169
7561
|
deps.trigger,
|
|
7170
|
-
|
|
7562
|
+
active.length > 0 ? {
|
|
7563
|
+
aggregateVersion: MEASURED_DAYS_V1,
|
|
7564
|
+
utcOffsetMinutes: workflow?.utcOffsetMinutes ?? machineUtcOffsetMinutes(),
|
|
7565
|
+
days: days.send
|
|
7566
|
+
} : void 0,
|
|
7171
7567
|
CLI_VERSION
|
|
7172
7568
|
);
|
|
7173
7569
|
const bodyJson = JSON.stringify(body);
|
|
@@ -7179,6 +7575,7 @@ async function stageSync(deps) {
|
|
|
7179
7575
|
source,
|
|
7180
7576
|
baseUrl: deps.baseUrl,
|
|
7181
7577
|
scanStats,
|
|
7578
|
+
days,
|
|
7182
7579
|
// The real terminal, so the inventory rows break where this window ends
|
|
7183
7580
|
// (#217). A pipe reports nothing and the preview falls back to 80.
|
|
7184
7581
|
width: process.stdout.columns
|
|
@@ -7201,7 +7598,8 @@ async function stageSync(deps) {
|
|
|
7201
7598
|
config,
|
|
7202
7599
|
token,
|
|
7203
7600
|
stagedAt: now,
|
|
7204
|
-
blockedReason
|
|
7601
|
+
blockedReason,
|
|
7602
|
+
days
|
|
7205
7603
|
};
|
|
7206
7604
|
}
|
|
7207
7605
|
|