ccsidekick 1.6.1 → 1.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ccsidekick-render.js +425 -103
- package/dist/ccsidekick.js +476 -132
- package/package.json +3 -3
package/dist/ccsidekick.js
CHANGED
|
@@ -48,7 +48,7 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
48
48
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
49
49
|
|
|
50
50
|
// src/domain/constants.ts
|
|
51
|
-
var COST_TTL_MS =
|
|
51
|
+
var COST_TTL_MS = 5000, REFRESH_INTERVAL_SEC = 1, USAGE_TTL_MS = 300000, CREDS_TTL_MS = 3600000, BALANCE_FRESHNESS_MS = 300000, FX_TTL_MS = 604800000, MIN_RIGHT_WIDTH = 53, FIGURE_COLS = 25, FIGURE_ROWS = 9, GAP = 2, SESSION_TTL_DAYS = 30, HOT_MS = 15000, MOOD_WINDOW_MS = 300000, IDLE_ROTATE_MS = 900000, MOOD_FAIL_N = 3, EGG_EVERY_N = 12, COMEBACK_GAP_DAYS = 3, STREAK_MILESTONES, SESSION_MILESTONES, STREAK_GRACE_DAYS = 1, RECENT_WINDOW_DAYS = 30, ANALYTICS_TTL_MS = 1500, CHAR_LINE_MAX = 66, HELPFUL_SHOW_MS = 300000, HELPFUL_COOLDOWN_MS = 600000, BURN_WINDOW_MS = 18000000, COMPACT_URGENT_PCT = 90, QUOTA_HIGH_PCT = 80, QUOTA_PACE_MIN_PCT = 20, QUOTA_PROJECT_MIN_PCT = 50, PAY_AS_YOU_GO_CAUTION_PCT = 60, PAY_AS_YOU_GO_NEAR_PCT = 80, BALANCE_LOW = 25, SHIMMER_PERIOD_MS = 24000, THEME_CHROMA_MIN = 40, THEME_MAXCH_MIN = 95, SIGNAL_HUE_RANGES, COMPACT_SOON_PCT = 60, COMPACTION_THRASH_N = 3, CACHE_RATIO_FLOOR = 0.5, CACHE_WARMUP_TURNS = 20, BIG_DIFF_LINES = 1000, UNTRACKED_N = 20, STASH_N = 5, STALE_BRANCH_N = 20, TODO_STALLED_MIN = 30, TIER_THRESHOLDS, DAILY_WINDOW_DAYS = 60, PRICING_TIER_THRESHOLD = 200000;
|
|
52
52
|
var init_constants = __esm(() => {
|
|
53
53
|
STREAK_MILESTONES = [3, 7, 30, 100];
|
|
54
54
|
SESSION_MILESTONES = [10, 50, 100, 250, 500];
|
|
@@ -57,10 +57,11 @@ var init_constants = __esm(() => {
|
|
|
57
57
|
caution: { min: 20, max: 55 },
|
|
58
58
|
critical: { wrapMax: 15, wrapMin: 345 }
|
|
59
59
|
};
|
|
60
|
+
TIER_THRESHOLDS = [3, 15, 50, 100];
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
// src/domain/enums.ts
|
|
63
|
-
var MOODS, PRESSURE_MOODS, TIERS, STACKS, EVENT_CATEGORIES, REACTION_CATEGORIES, isStack = (s) => STACKS.includes(s), isEventCategory = (s) => EVENT_CATEGORIES.includes(s);
|
|
64
|
+
var MOODS, PRESSURE_MOODS, TIERS, STACKS, EVENT_CATEGORIES, REACTION_CATEGORIES, MIN_SEVERITIES, CHARACTER_MODES, BANDINGS, isStack = (s) => STACKS.includes(s), isEventCategory = (s) => EVENT_CATEGORIES.includes(s);
|
|
64
65
|
var init_enums = __esm(() => {
|
|
65
66
|
MOODS = ["idle", "busy", "happy", "struggling", "recovery"];
|
|
66
67
|
PRESSURE_MOODS = ["compact_hint", "block_limit", "weekly_limit"];
|
|
@@ -147,6 +148,9 @@ var init_enums = __esm(() => {
|
|
|
147
148
|
"db_migrate",
|
|
148
149
|
"dangerous"
|
|
149
150
|
];
|
|
151
|
+
MIN_SEVERITIES = ["low", "medium", "high", "critical"];
|
|
152
|
+
CHARACTER_MODES = ["fixed", "random"];
|
|
153
|
+
BANDINGS = ["solid", "cycle"];
|
|
150
154
|
});
|
|
151
155
|
|
|
152
156
|
// src/domain/ids.ts
|
|
@@ -2012,7 +2016,7 @@ function hot(i, category) {
|
|
|
2012
2016
|
function cut(s, max = 24) {
|
|
2013
2017
|
return s.length <= max ? s : `${s.slice(0, Math.max(0, max - 1))}…`;
|
|
2014
2018
|
}
|
|
2015
|
-
var
|
|
2019
|
+
var EFFORT_LOW_LEVEL = "low", PROD_CONTEXT_PATTERN, SECRET_PATTERNS, SECRET_SAFE, SECRET_RE, SAFE_RE, detached = (g) => g !== null && g.branch === undefined, dirty = (g) => g !== null && g.staged + g.unstaged > 0, onDefault = (g) => g !== null && g.branch !== undefined && g.defaultBranch !== undefined && g.branch === g.defaultBranch, ahead = (g) => g?.ahead ?? 0, behind = (g) => g?.behind ?? 0, bare = (left) => (left ?? "").replace(/ left$/, ""), branchName = (g) => cut(g?.branch ?? ""), HELPFUL_CATALOG;
|
|
2016
2020
|
var init_catalog = __esm(() => {
|
|
2017
2021
|
init_domain();
|
|
2018
2022
|
init_format();
|
|
@@ -2162,7 +2166,7 @@ var init_catalog = __esm(() => {
|
|
|
2162
2166
|
category: "quota",
|
|
2163
2167
|
momentary: false,
|
|
2164
2168
|
template: "5h limit at {pct}%, {reset} to reset. Save heavy asks for after.",
|
|
2165
|
-
test: (i) => i.quota.block !== undefined && i.quota.block.usedPct > QUOTA_HIGH_PCT,
|
|
2169
|
+
test: (i) => i.quota.block !== undefined && i.quota.block.usedPct > QUOTA_HIGH_PCT && i.quota.block.overPace === true,
|
|
2166
2170
|
render: (i) => `5h limit at ${pct(i.quota.block?.usedPct ?? 0)}, ${bare(i.quota.block?.resetIn)} to reset. Save heavy asks for after.`
|
|
2167
2171
|
},
|
|
2168
2172
|
{
|
|
@@ -2171,7 +2175,7 @@ var init_catalog = __esm(() => {
|
|
|
2171
2175
|
category: "quota",
|
|
2172
2176
|
momentary: false,
|
|
2173
2177
|
template: "Weekly quota {pct}% spent, {reset} to go. Ration the big requests.",
|
|
2174
|
-
test: (i) => i.quota.weekly !== undefined && i.quota.weekly.usedPct > QUOTA_HIGH_PCT,
|
|
2178
|
+
test: (i) => i.quota.weekly !== undefined && i.quota.weekly.usedPct > QUOTA_HIGH_PCT && i.quota.weekly.overPace === true,
|
|
2175
2179
|
render: (i) => `Weekly quota ${pct(i.quota.weekly?.usedPct ?? 0)} spent, ${bare(i.quota.weekly?.resetIn)} to go. Ration the big requests.`
|
|
2176
2180
|
},
|
|
2177
2181
|
{
|
|
@@ -2180,7 +2184,7 @@ var init_catalog = __esm(() => {
|
|
|
2180
2184
|
category: "quota",
|
|
2181
2185
|
momentary: false,
|
|
2182
2186
|
template: "This burn rate empties the 5h block before reset, cutting you off mid-task.",
|
|
2183
|
-
test: (i) => i.quota.block !== undefined && i.quota.block.
|
|
2187
|
+
test: (i) => i.quota.block !== undefined && i.quota.block.usedPct > QUOTA_PROJECT_MIN_PCT && i.quota.block.overPace === true,
|
|
2184
2188
|
render: () => "This burn rate empties the 5h block before reset, cutting you off mid-task."
|
|
2185
2189
|
},
|
|
2186
2190
|
{
|
|
@@ -2189,7 +2193,7 @@ var init_catalog = __esm(() => {
|
|
|
2189
2193
|
category: "quota",
|
|
2190
2194
|
momentary: false,
|
|
2191
2195
|
template: "At this pace the weekly quota runs dry before reset, locking you out for days.",
|
|
2192
|
-
test: (i) => i.quota.weekly !== undefined && i.quota.weekly.
|
|
2196
|
+
test: (i) => i.quota.weekly !== undefined && i.quota.weekly.usedPct > QUOTA_PROJECT_MIN_PCT && i.quota.weekly.overPace === true,
|
|
2193
2197
|
render: () => "At this pace the weekly quota runs dry before reset, locking you out for days."
|
|
2194
2198
|
},
|
|
2195
2199
|
{
|
|
@@ -2810,9 +2814,9 @@ function modelKeyOf(modelId, aliases = NO_ALIASES) {
|
|
|
2810
2814
|
return resolveKey(modelId, aliases) ?? modelId;
|
|
2811
2815
|
}
|
|
2812
2816
|
function tiered(tokens, base, above) {
|
|
2813
|
-
if (tokens <=
|
|
2817
|
+
if (tokens <= PRICING_TIER_THRESHOLD || above === undefined)
|
|
2814
2818
|
return tokens * base;
|
|
2815
|
-
return
|
|
2819
|
+
return PRICING_TIER_THRESHOLD * base + (tokens - PRICING_TIER_THRESHOLD) * above;
|
|
2816
2820
|
}
|
|
2817
2821
|
function priceMessage(usage, modelId, aliases = NO_ALIASES, atMs) {
|
|
2818
2822
|
const row = resolvePrice(modelId, aliases, atMs);
|
|
@@ -2829,9 +2833,10 @@ function priceMessage(usage, modelId, aliases = NO_ALIASES, atMs) {
|
|
|
2829
2833
|
const speedMult = usage.speed === "fast" ? row.fast_mult : 1;
|
|
2830
2834
|
return cost * speedMult;
|
|
2831
2835
|
}
|
|
2832
|
-
var PER_MILLION = 1e6,
|
|
2836
|
+
var PER_MILLION = 1e6, RAW, TABLE, NO_ALIASES, isAlnum = (c) => c !== "" && /[a-z0-9]/i.test(c);
|
|
2833
2837
|
var init_pricing2 = __esm(() => {
|
|
2834
2838
|
init_pricing();
|
|
2839
|
+
init_domain();
|
|
2835
2840
|
RAW = pricing_default;
|
|
2836
2841
|
TABLE = (() => {
|
|
2837
2842
|
const byKey = new Map;
|
|
@@ -2914,6 +2919,7 @@ function joinRecords(attribution, cache, tz) {
|
|
|
2914
2919
|
for (const [session, g] of groupBySession(cache)) {
|
|
2915
2920
|
const attr = attribution[session];
|
|
2916
2921
|
out.push({
|
|
2922
|
+
session,
|
|
2917
2923
|
character: attr?.character ?? "unknown",
|
|
2918
2924
|
project: attr?.project ?? g.projectRaw,
|
|
2919
2925
|
start: g.start,
|
|
@@ -2949,7 +2955,7 @@ function currentStreak(activeDays, today) {
|
|
|
2949
2955
|
}
|
|
2950
2956
|
return streak2;
|
|
2951
2957
|
}
|
|
2952
|
-
function deriveFamiliarity(attribution, character, cache, project, clock) {
|
|
2958
|
+
function deriveFamiliarity(attribution, character, cache, project, clock, currentSession = "") {
|
|
2953
2959
|
const tz = clock.timezone();
|
|
2954
2960
|
const records = joinRecords(attribution, cache, tz);
|
|
2955
2961
|
const seenProject = records.some((r) => r.project === String(project));
|
|
@@ -2961,10 +2967,12 @@ function deriveFamiliarity(attribution, character, cache, project, clock) {
|
|
|
2961
2967
|
let lastEnd = Number.NEGATIVE_INFINITY;
|
|
2962
2968
|
let workingSinceMs = Number.POSITIVE_INFINITY;
|
|
2963
2969
|
for (const r of mine) {
|
|
2964
|
-
if (r.end > lastEnd)
|
|
2965
|
-
lastEnd = r.end;
|
|
2966
2970
|
if (r.start < workingSinceMs)
|
|
2967
2971
|
workingSinceMs = r.start;
|
|
2972
|
+
if (r.session === currentSession)
|
|
2973
|
+
continue;
|
|
2974
|
+
if (r.end > lastEnd)
|
|
2975
|
+
lastEnd = r.end;
|
|
2968
2976
|
}
|
|
2969
2977
|
const daysSinceLastSession = Number.isFinite(lastEnd) ? Math.floor((clock.now() - lastEnd) / MS_PER_DAY) : Number.POSITIVE_INFINITY;
|
|
2970
2978
|
return {
|
|
@@ -3003,12 +3011,20 @@ function hourOfDay(ms, tz) {
|
|
|
3003
3011
|
}
|
|
3004
3012
|
function joinFull(attribution, cache, tz, normalizeProject) {
|
|
3005
3013
|
const tokenPriced = cache.aggregate.tokenPriced;
|
|
3014
|
+
const groups = [...groupBySession(cache)];
|
|
3015
|
+
const rootToName = new Map;
|
|
3016
|
+
for (const [session, g] of groups) {
|
|
3017
|
+
const attr = attribution[session];
|
|
3018
|
+
if (attr !== undefined)
|
|
3019
|
+
rootToName.set(normalizeProject(g.projectRaw), attr.project);
|
|
3020
|
+
}
|
|
3006
3021
|
const out = [];
|
|
3007
|
-
for (const [session, g] of
|
|
3022
|
+
for (const [session, g] of groups) {
|
|
3008
3023
|
const attr = attribution[session];
|
|
3024
|
+
const root = normalizeProject(g.projectRaw);
|
|
3009
3025
|
out.push({
|
|
3010
3026
|
session,
|
|
3011
|
-
project:
|
|
3027
|
+
project: attr?.project ?? rootToName.get(root) ?? root,
|
|
3012
3028
|
character: attr?.character ?? "unknown",
|
|
3013
3029
|
start: g.start,
|
|
3014
3030
|
end: g.end,
|
|
@@ -3267,11 +3283,10 @@ function buildModels(byModel) {
|
|
|
3267
3283
|
share: totalCost > 0 ? v.cost / totalCost : 0
|
|
3268
3284
|
})).sort((a, b) => b.costUsd - a.costUsd);
|
|
3269
3285
|
}
|
|
3270
|
-
var MS_PER_DAY = 86400000
|
|
3286
|
+
var MS_PER_DAY = 86400000;
|
|
3271
3287
|
var init_analytics = __esm(() => {
|
|
3272
3288
|
init_domain();
|
|
3273
3289
|
init_pricing2();
|
|
3274
|
-
TIER_THRESHOLDS = [3, 15, 50, 100];
|
|
3275
3290
|
});
|
|
3276
3291
|
|
|
3277
3292
|
// src/derived/signals.ts
|
|
@@ -3283,9 +3298,9 @@ function contextBand(pct2) {
|
|
|
3283
3298
|
return "critical";
|
|
3284
3299
|
}
|
|
3285
3300
|
function quotaBand(usedPct, resetsAtMs, windowMs, nowMs) {
|
|
3286
|
-
if (usedPct >=
|
|
3301
|
+
if (usedPct >= QUOTA_HIGH_PCT)
|
|
3287
3302
|
return "critical";
|
|
3288
|
-
if (resetsAtMs === undefined)
|
|
3303
|
+
if (resetsAtMs === undefined || usedPct < QUOTA_PACE_MIN_PCT)
|
|
3289
3304
|
return contextBand(usedPct);
|
|
3290
3305
|
const usedFraction = usedPct / 100;
|
|
3291
3306
|
const elapsedFraction = Math.max((nowMs - (resetsAtMs - windowMs)) / windowMs, 0.01);
|
|
@@ -3296,7 +3311,16 @@ function quotaBand(usedPct, resetsAtMs, windowMs, nowMs) {
|
|
|
3296
3311
|
return "caution";
|
|
3297
3312
|
return "critical";
|
|
3298
3313
|
}
|
|
3299
|
-
|
|
3314
|
+
function overQuotaPace(usedPct, resetsAtMs, windowMs, nowMs) {
|
|
3315
|
+
if (resetsAtMs === undefined)
|
|
3316
|
+
return false;
|
|
3317
|
+
const usedFraction = usedPct / 100;
|
|
3318
|
+
const elapsedFraction = Math.max((nowMs - (resetsAtMs - windowMs)) / windowMs, 0.01);
|
|
3319
|
+
return usedFraction / elapsedFraction > 1.5;
|
|
3320
|
+
}
|
|
3321
|
+
var init_signals = __esm(() => {
|
|
3322
|
+
init_domain();
|
|
3323
|
+
});
|
|
3300
3324
|
|
|
3301
3325
|
// src/derived/context.ts
|
|
3302
3326
|
function deriveContext(payload, scan) {
|
|
@@ -3320,6 +3344,7 @@ function deriveContext(payload, scan) {
|
|
|
3320
3344
|
}
|
|
3321
3345
|
var init_context = __esm(() => {
|
|
3322
3346
|
init_domain();
|
|
3347
|
+
init_signals();
|
|
3323
3348
|
});
|
|
3324
3349
|
|
|
3325
3350
|
// src/derived/cost.ts
|
|
@@ -3604,12 +3629,13 @@ function buildWindow(payloadQuota, oauthQuota, windowMs, clock) {
|
|
|
3604
3629
|
return;
|
|
3605
3630
|
}
|
|
3606
3631
|
const band2 = quotaBand(usedPct, resetsAtMs, windowMs, clock.now());
|
|
3632
|
+
const overPace = overQuotaPace(usedPct, resetsAtMs, windowMs, clock.now());
|
|
3607
3633
|
if (resetsAtMs === undefined)
|
|
3608
|
-
return { usedPct, band: band2 };
|
|
3634
|
+
return { usedPct, band: band2, overPace };
|
|
3609
3635
|
const left = resetsAtMs - clock.now();
|
|
3610
3636
|
if (left <= 0)
|
|
3611
|
-
return { usedPct, band: band2 };
|
|
3612
|
-
return { usedPct, band: band2, resetIn: fmtLeft(left) };
|
|
3637
|
+
return { usedPct, band: band2, overPace };
|
|
3638
|
+
return { usedPct, band: band2, overPace, resetIn: fmtLeft(left) };
|
|
3613
3639
|
}
|
|
3614
3640
|
function buildPayg(usage) {
|
|
3615
3641
|
const extra = usage?.extra_usage;
|
|
@@ -3649,6 +3675,7 @@ var FIVE_HOUR_MS, SEVEN_DAY_MS;
|
|
|
3649
3675
|
var init_quota = __esm(() => {
|
|
3650
3676
|
init_domain();
|
|
3651
3677
|
init_format();
|
|
3678
|
+
init_signals();
|
|
3652
3679
|
FIVE_HOUR_MS = 5 * 60 * 60 * 1000;
|
|
3653
3680
|
SEVEN_DAY_MS = 7 * 24 * 60 * 60 * 1000;
|
|
3654
3681
|
});
|
|
@@ -4006,7 +4033,7 @@ function readJson(path, fallback) {
|
|
|
4006
4033
|
var init_readJson = () => {};
|
|
4007
4034
|
|
|
4008
4035
|
// src/sources/storage/withLock.ts
|
|
4009
|
-
import { closeSync, mkdirSync as mkdirSync2, openSync, statSync, unlinkSync } from "node:fs";
|
|
4036
|
+
import { closeSync, mkdirSync as mkdirSync2, openSync, renameSync as renameSync2, statSync, unlinkSync } from "node:fs";
|
|
4010
4037
|
import { dirname as dirname2 } from "node:path";
|
|
4011
4038
|
function withLock(lockPath, fn, readOnly) {
|
|
4012
4039
|
let fd;
|
|
@@ -4020,8 +4047,12 @@ function withLock(lockPath, fn, readOnly) {
|
|
|
4020
4047
|
} catch {
|
|
4021
4048
|
try {
|
|
4022
4049
|
if (Date.now() - statSync(lockPath).mtimeMs > STALE_MS) {
|
|
4023
|
-
|
|
4050
|
+
const aside = `${lockPath}.stale`;
|
|
4051
|
+
renameSync2(lockPath, aside);
|
|
4024
4052
|
fd = openSync(lockPath, "wx");
|
|
4053
|
+
try {
|
|
4054
|
+
unlinkSync(aside);
|
|
4055
|
+
} catch {}
|
|
4025
4056
|
}
|
|
4026
4057
|
} catch {}
|
|
4027
4058
|
}
|
|
@@ -4109,6 +4140,10 @@ function upsertAttribution(root, sessionId, rec) {
|
|
|
4109
4140
|
const path = storePath(root);
|
|
4110
4141
|
withLock(`${path}.lock`, () => {
|
|
4111
4142
|
const store = coerceStore(readJson(path, undefined));
|
|
4143
|
+
const existing = store[sessionId];
|
|
4144
|
+
if (existing !== undefined && existing.project === rec.project && existing.character === rec.character) {
|
|
4145
|
+
return;
|
|
4146
|
+
}
|
|
4112
4147
|
store[sessionId] = rec.updatedMs !== undefined ? { project: rec.project, character: rec.character, updatedMs: rec.updatedMs } : { project: rec.project, character: rec.character };
|
|
4113
4148
|
atomicWrite(path, JSON.stringify(store));
|
|
4114
4149
|
}, () => {});
|
|
@@ -4119,9 +4154,17 @@ var init_analyticsStore = __esm(() => {
|
|
|
4119
4154
|
});
|
|
4120
4155
|
|
|
4121
4156
|
// src/sources/balance.ts
|
|
4157
|
+
import { statSync as statSync3 } from "node:fs";
|
|
4122
4158
|
function readBalance(path, clock) {
|
|
4123
4159
|
if (path === "")
|
|
4124
4160
|
return null;
|
|
4161
|
+
try {
|
|
4162
|
+
const st = statSync3(path);
|
|
4163
|
+
if (!st.isFile() || st.size > BALANCE_MAX_BYTES)
|
|
4164
|
+
return null;
|
|
4165
|
+
} catch {
|
|
4166
|
+
return null;
|
|
4167
|
+
}
|
|
4125
4168
|
const raw = readJson(path, undefined);
|
|
4126
4169
|
if (typeof raw !== "object" || raw === null)
|
|
4127
4170
|
return null;
|
|
@@ -4139,9 +4182,11 @@ function readBalance(path, clock) {
|
|
|
4139
4182
|
return null;
|
|
4140
4183
|
return { amount, currency, ts };
|
|
4141
4184
|
}
|
|
4185
|
+
var BALANCE_MAX_BYTES;
|
|
4142
4186
|
var init_balance = __esm(() => {
|
|
4143
4187
|
init_domain();
|
|
4144
4188
|
init_storage();
|
|
4189
|
+
BALANCE_MAX_BYTES = 64 * 1024;
|
|
4145
4190
|
});
|
|
4146
4191
|
|
|
4147
4192
|
// src/sources/clock.ts
|
|
@@ -5400,10 +5445,10 @@ function loadConfig(globalToml = "", projectToml = "") {
|
|
|
5400
5445
|
const statusline = section(g, p, "statusline");
|
|
5401
5446
|
const d = DEFAULT_CONFIG;
|
|
5402
5447
|
return {
|
|
5403
|
-
schema_version: numv(p["schema_version"]
|
|
5448
|
+
schema_version: numv(p["schema_version"], numv(g["schema_version"], d.schema_version)),
|
|
5404
5449
|
character: {
|
|
5405
5450
|
enabled: bool(character["enabled"], d.character.enabled),
|
|
5406
|
-
mode: oneOf(character["mode"],
|
|
5451
|
+
mode: oneOf(character["mode"], CHARACTER_MODES, d.character.mode),
|
|
5407
5452
|
name: str(character["name"], d.character.name),
|
|
5408
5453
|
roster: stringArray(character["roster"], d.character.roster)
|
|
5409
5454
|
},
|
|
@@ -5412,7 +5457,7 @@ function loadConfig(globalToml = "", projectToml = "") {
|
|
|
5412
5457
|
...typeof theme["statusline"] === "string" ? { statusline: theme["statusline"] } : {},
|
|
5413
5458
|
...typeof theme["logo"] === "string" ? { logo: theme["logo"] } : {},
|
|
5414
5459
|
...typeof theme["comment"] === "string" ? { comment: theme["comment"] } : {},
|
|
5415
|
-
banding: oneOf(theme["banding"],
|
|
5460
|
+
banding: oneOf(theme["banding"], BANDINGS, d.theme.banding),
|
|
5416
5461
|
mood_shift: bool(theme["mood_shift"], d.theme.mood_shift),
|
|
5417
5462
|
icons: mergeIcons({
|
|
5418
5463
|
...obj(obj(g["theme"])["icons"]),
|
|
@@ -5422,7 +5467,7 @@ function loadConfig(globalToml = "", projectToml = "") {
|
|
|
5422
5467
|
comments: {
|
|
5423
5468
|
character: bool(comments["character"], d.comments.character),
|
|
5424
5469
|
helpful: bool(comments["helpful"], d.comments.helpful),
|
|
5425
|
-
min_severity: oneOf(comments["min_severity"],
|
|
5470
|
+
min_severity: oneOf(comments["min_severity"], MIN_SEVERITIES, d.comments.min_severity)
|
|
5426
5471
|
},
|
|
5427
5472
|
network: {
|
|
5428
5473
|
fx_refresh: bool(network["fx_refresh"], d.network.fx_refresh),
|
|
@@ -5445,6 +5490,7 @@ var DEFAULT_WIDGETS, DEFAULT_CONFIG, obj = (v) => v !== null && typeof v === "ob
|
|
|
5445
5490
|
});
|
|
5446
5491
|
var init_config = __esm(() => {
|
|
5447
5492
|
init_dist();
|
|
5493
|
+
init_domain();
|
|
5448
5494
|
init_locale();
|
|
5449
5495
|
DEFAULT_WIDGETS = {
|
|
5450
5496
|
dir: true,
|
|
@@ -5598,7 +5644,19 @@ function coerceEntry(v) {
|
|
|
5598
5644
|
}
|
|
5599
5645
|
const projectPath = typeof v["projectPath"] === "string" ? v["projectPath"] : String(record.project);
|
|
5600
5646
|
const models = Array.isArray(v["models"]) ? v["models"].filter((x) => typeof x === "string") : [];
|
|
5601
|
-
|
|
5647
|
+
const byteOffset = asNumber(v["byteOffset"]);
|
|
5648
|
+
const headHash = typeof v["headHash"] === "string" ? v["headHash"] : undefined;
|
|
5649
|
+
return {
|
|
5650
|
+
mtime,
|
|
5651
|
+
size,
|
|
5652
|
+
total,
|
|
5653
|
+
lines,
|
|
5654
|
+
models,
|
|
5655
|
+
projectPath,
|
|
5656
|
+
record,
|
|
5657
|
+
...byteOffset !== undefined ? { byteOffset } : {},
|
|
5658
|
+
...headHash !== undefined ? { headHash } : {}
|
|
5659
|
+
};
|
|
5602
5660
|
}
|
|
5603
5661
|
function coerceByModel(v) {
|
|
5604
5662
|
if (!isObject(v))
|
|
@@ -5855,13 +5913,9 @@ var init_oauthUsage = __esm(() => {
|
|
|
5855
5913
|
// src/sources/creds.ts
|
|
5856
5914
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
5857
5915
|
import { readFileSync as readFileSync4 } from "node:fs";
|
|
5858
|
-
import { homedir as homedir3 } from "node:os";
|
|
5859
5916
|
import { join as join5 } from "node:path";
|
|
5860
|
-
function configBase2() {
|
|
5861
|
-
return process.env["CLAUDE_CONFIG_DIR"] ?? join5(homedir3(), ".claude");
|
|
5862
|
-
}
|
|
5863
5917
|
function readBlob(run, base) {
|
|
5864
|
-
for (const service of [keychainService(base),
|
|
5918
|
+
for (const service of [keychainService(base), KEYCHAIN_SERVICE]) {
|
|
5865
5919
|
const keychain = run("security", ["find-generic-password", "-s", service, "-w"]);
|
|
5866
5920
|
if (keychain.trim() !== "")
|
|
5867
5921
|
return keychain;
|
|
@@ -5871,7 +5925,7 @@ function readBlob(run, base) {
|
|
|
5871
5925
|
if (file.trim() !== "")
|
|
5872
5926
|
return file;
|
|
5873
5927
|
} catch {}
|
|
5874
|
-
const secretTool = run("secret-tool", ["lookup", "service",
|
|
5928
|
+
const secretTool = run("secret-tool", ["lookup", "service", KEYCHAIN_SERVICE]);
|
|
5875
5929
|
if (secretTool.trim() !== "")
|
|
5876
5930
|
return secretTool;
|
|
5877
5931
|
return "";
|
|
@@ -5900,7 +5954,7 @@ function readOrgTier(base) {
|
|
|
5900
5954
|
}
|
|
5901
5955
|
function readCreds(run = defaultRunner) {
|
|
5902
5956
|
try {
|
|
5903
|
-
const base =
|
|
5957
|
+
const base = configBase();
|
|
5904
5958
|
const blob = readBlob(run, base);
|
|
5905
5959
|
if (blob.trim() !== "") {
|
|
5906
5960
|
const tier = parseSubscription(blob);
|
|
@@ -5914,7 +5968,39 @@ function readCreds(run = defaultRunner) {
|
|
|
5914
5968
|
return null;
|
|
5915
5969
|
}
|
|
5916
5970
|
}
|
|
5917
|
-
|
|
5971
|
+
function credsCachePath(root) {
|
|
5972
|
+
return join5(cacheDir(root), CREDS_CACHE_FILE);
|
|
5973
|
+
}
|
|
5974
|
+
function coerceCachedCreds(raw) {
|
|
5975
|
+
if (!isObject3(raw) || typeof raw["at"] !== "number")
|
|
5976
|
+
return null;
|
|
5977
|
+
const at = raw["at"];
|
|
5978
|
+
const info = raw["info"];
|
|
5979
|
+
if (info === null)
|
|
5980
|
+
return { info: null, at };
|
|
5981
|
+
if (isObject3(info) && typeof info["present"] === "boolean") {
|
|
5982
|
+
const sub = info["subscriptionType"];
|
|
5983
|
+
return {
|
|
5984
|
+
at,
|
|
5985
|
+
info: typeof sub === "string" && SUBSCRIPTIONS.has(sub) ? { present: info["present"], subscriptionType: sub } : { present: info["present"] }
|
|
5986
|
+
};
|
|
5987
|
+
}
|
|
5988
|
+
return null;
|
|
5989
|
+
}
|
|
5990
|
+
function readCredsCached(root) {
|
|
5991
|
+
return coerceCachedCreds(readJson(credsCachePath(root), undefined))?.info ?? null;
|
|
5992
|
+
}
|
|
5993
|
+
function refreshCreds(root, clock, run = defaultRunner) {
|
|
5994
|
+
const cached = coerceCachedCreds(readJson(credsCachePath(root), undefined));
|
|
5995
|
+
const now = clock.now();
|
|
5996
|
+
if (cached !== null && now - cached.at <= CREDS_TTL_MS)
|
|
5997
|
+
return;
|
|
5998
|
+
const info = readCreds(run);
|
|
5999
|
+
try {
|
|
6000
|
+
atomicWrite(credsCachePath(root), JSON.stringify({ info, at: now }));
|
|
6001
|
+
} catch {}
|
|
6002
|
+
}
|
|
6003
|
+
var SUBSCRIPTIONS, isObject3 = (v) => typeof v === "object" && v !== null, defaultRunner = (cmd, args) => {
|
|
5918
6004
|
try {
|
|
5919
6005
|
const r = spawnSync2(cmd, args, {
|
|
5920
6006
|
encoding: "utf8",
|
|
@@ -5927,9 +6013,11 @@ var KEYCHAIN_SERVICE2 = "Claude Code-credentials", SUBSCRIPTIONS, isObject3 = (v
|
|
|
5927
6013
|
} catch {
|
|
5928
6014
|
return "";
|
|
5929
6015
|
}
|
|
5930
|
-
};
|
|
6016
|
+
}, CREDS_CACHE_FILE = "creds.json";
|
|
5931
6017
|
var init_creds = __esm(() => {
|
|
6018
|
+
init_domain();
|
|
5932
6019
|
init_oauthUsage();
|
|
6020
|
+
init_storage();
|
|
5933
6021
|
SUBSCRIPTIONS = new Set(["pro", "max", "team", "enterprise"]);
|
|
5934
6022
|
});
|
|
5935
6023
|
|
|
@@ -6408,12 +6496,14 @@ function readSubmoduleRollup(run, workTreeRoot) {
|
|
|
6408
6496
|
return rollup;
|
|
6409
6497
|
}
|
|
6410
6498
|
function readGit(cwd, run = defaultRunner2(cwd)) {
|
|
6411
|
-
|
|
6499
|
+
const probe = run(["rev-parse", "--is-inside-work-tree", "--git-dir", "--show-toplevel"]).split(`
|
|
6500
|
+
`);
|
|
6501
|
+
if ((probe[0] ?? "").trim() !== "true")
|
|
6412
6502
|
return null;
|
|
6413
6503
|
const status = parseStatus(run(["status", "--porcelain=v2", "--branch", "--show-stash"]));
|
|
6414
|
-
const gitDirRaw =
|
|
6504
|
+
const gitDirRaw = (probe[1] ?? "").trim();
|
|
6415
6505
|
const gitDir = gitDirRaw === "" ? "" : resolve(cwd, gitDirRaw);
|
|
6416
|
-
const workTreeRoot =
|
|
6506
|
+
const workTreeRoot = (probe[2] ?? "").trim();
|
|
6417
6507
|
const tag = run(["describe", "--tags", "--exact-match"]).trim() || undefined;
|
|
6418
6508
|
const originRepo = normalizeOriginRepo(run(["remote", "get-url", "origin"]));
|
|
6419
6509
|
const defaultBranch = resolveDefaultBranch(run);
|
|
@@ -6474,7 +6564,7 @@ var init_git = __esm(() => {
|
|
|
6474
6564
|
|
|
6475
6565
|
// src/sources/helpfulEnv.ts
|
|
6476
6566
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
6477
|
-
import { homedir as
|
|
6567
|
+
import { homedir as homedir3 } from "node:os";
|
|
6478
6568
|
import { delimiter, join as join9 } from "node:path";
|
|
6479
6569
|
function kubeconfigPath() {
|
|
6480
6570
|
const env = process.env["KUBECONFIG"];
|
|
@@ -6483,7 +6573,7 @@ function kubeconfigPath() {
|
|
|
6483
6573
|
if (first !== undefined)
|
|
6484
6574
|
return first;
|
|
6485
6575
|
}
|
|
6486
|
-
return join9(
|
|
6576
|
+
return join9(homedir3(), ".kube", "config");
|
|
6487
6577
|
}
|
|
6488
6578
|
function readKubeContext() {
|
|
6489
6579
|
try {
|
|
@@ -6799,7 +6889,7 @@ var init_state = __esm(() => {
|
|
|
6799
6889
|
});
|
|
6800
6890
|
|
|
6801
6891
|
// src/sources/transcript.ts
|
|
6802
|
-
import { readFileSync as readFileSync8, readdirSync as readdirSync2, statSync as
|
|
6892
|
+
import { closeSync as closeSync2, openSync as openSync2, readFileSync as readFileSync8, readSync, readdirSync as readdirSync2, statSync as statSync4 } from "node:fs";
|
|
6803
6893
|
import { basename as basename2, dirname as dirname5, join as join12 } from "node:path";
|
|
6804
6894
|
function parseTs(s) {
|
|
6805
6895
|
if (s === undefined)
|
|
@@ -7021,7 +7111,7 @@ function reconstructTodos(lines) {
|
|
|
7021
7111
|
}
|
|
7022
7112
|
function statSafe(p) {
|
|
7023
7113
|
try {
|
|
7024
|
-
const s =
|
|
7114
|
+
const s = statSync4(p);
|
|
7025
7115
|
return { mtimeMs: s.mtimeMs, size: s.size };
|
|
7026
7116
|
} catch {
|
|
7027
7117
|
return null;
|
|
@@ -7034,6 +7124,61 @@ function readSafe(p) {
|
|
|
7034
7124
|
return "";
|
|
7035
7125
|
}
|
|
7036
7126
|
}
|
|
7127
|
+
function readBufSafe(p) {
|
|
7128
|
+
try {
|
|
7129
|
+
return readFileSync8(p);
|
|
7130
|
+
} catch {
|
|
7131
|
+
return null;
|
|
7132
|
+
}
|
|
7133
|
+
}
|
|
7134
|
+
function readRange(p, start, end) {
|
|
7135
|
+
if (end <= start)
|
|
7136
|
+
return Buffer.alloc(0);
|
|
7137
|
+
let fd;
|
|
7138
|
+
try {
|
|
7139
|
+
fd = openSync2(p, "r");
|
|
7140
|
+
const len = end - start;
|
|
7141
|
+
const buf = Buffer.allocUnsafe(len);
|
|
7142
|
+
let off = 0;
|
|
7143
|
+
while (off < len) {
|
|
7144
|
+
const n = readSync(fd, buf, off, len - off, start + off);
|
|
7145
|
+
if (n === 0)
|
|
7146
|
+
break;
|
|
7147
|
+
off += n;
|
|
7148
|
+
}
|
|
7149
|
+
return off === len ? buf : null;
|
|
7150
|
+
} catch {
|
|
7151
|
+
return null;
|
|
7152
|
+
} finally {
|
|
7153
|
+
if (fd !== undefined)
|
|
7154
|
+
closeSync2(fd);
|
|
7155
|
+
}
|
|
7156
|
+
}
|
|
7157
|
+
function headHashOf(head) {
|
|
7158
|
+
let h = 2166136261;
|
|
7159
|
+
for (const b of head) {
|
|
7160
|
+
h ^= b;
|
|
7161
|
+
h = Math.imul(h, 16777619);
|
|
7162
|
+
}
|
|
7163
|
+
return (h >>> 0).toString(16);
|
|
7164
|
+
}
|
|
7165
|
+
function makeInternModel(models) {
|
|
7166
|
+
const index = new Map;
|
|
7167
|
+
models.forEach((m, i) => index.set(m, i));
|
|
7168
|
+
return (model) => {
|
|
7169
|
+
let i = index.get(model);
|
|
7170
|
+
if (i === undefined) {
|
|
7171
|
+
i = models.length;
|
|
7172
|
+
models.push(model);
|
|
7173
|
+
index.set(model, i);
|
|
7174
|
+
}
|
|
7175
|
+
return i;
|
|
7176
|
+
};
|
|
7177
|
+
}
|
|
7178
|
+
function lastLineEnd(buf) {
|
|
7179
|
+
const i = buf.lastIndexOf(10);
|
|
7180
|
+
return i < 0 ? 0 : i + 1;
|
|
7181
|
+
}
|
|
7037
7182
|
function emptyScan(mtime, size) {
|
|
7038
7183
|
return { tokens: EMPTY_TOKENS, messages: 0, compactions: 0, todos: [], burn: [], mtime, size };
|
|
7039
7184
|
}
|
|
@@ -7113,7 +7258,7 @@ function repoRootForCwd(cwd) {
|
|
|
7113
7258
|
let result = cwd;
|
|
7114
7259
|
while (dir !== "" && dir !== dirname5(dir)) {
|
|
7115
7260
|
try {
|
|
7116
|
-
if (
|
|
7261
|
+
if (statSync4(join12(dir, ".git")).isDirectory()) {
|
|
7117
7262
|
result = dir;
|
|
7118
7263
|
break;
|
|
7119
7264
|
}
|
|
@@ -7134,7 +7279,7 @@ function* walkTree(dir, encodedDir) {
|
|
|
7134
7279
|
const full = join12(dir, name);
|
|
7135
7280
|
let st;
|
|
7136
7281
|
try {
|
|
7137
|
-
st =
|
|
7282
|
+
st = statSync4(full);
|
|
7138
7283
|
} catch {
|
|
7139
7284
|
continue;
|
|
7140
7285
|
}
|
|
@@ -7173,22 +7318,16 @@ function scanBounds(lines) {
|
|
|
7173
7318
|
return { sessionId, start, end };
|
|
7174
7319
|
}
|
|
7175
7320
|
function priceFile(path, encodedDir, st, price, resolveProject) {
|
|
7176
|
-
const
|
|
7321
|
+
const buf = readBufSafe(path) ?? Buffer.alloc(0);
|
|
7322
|
+
const byteOffset = lastLineEnd(buf);
|
|
7323
|
+
const headHash = headHashOf(buf.subarray(0, headLen(byteOffset)));
|
|
7324
|
+
const lines = parseAll(buf.subarray(0, byteOffset).toString("utf8"));
|
|
7177
7325
|
const { sessionId, start, end } = scanBounds(lines);
|
|
7178
7326
|
const priced = collapseStreaming(lines);
|
|
7179
7327
|
const gate = makeDedupGate();
|
|
7180
7328
|
const costLines = [];
|
|
7181
7329
|
const models = [];
|
|
7182
|
-
const
|
|
7183
|
-
const internModel = (model) => {
|
|
7184
|
-
let i = modelIndex.get(model);
|
|
7185
|
-
if (i === undefined) {
|
|
7186
|
-
i = models.length;
|
|
7187
|
-
models.push(model);
|
|
7188
|
-
modelIndex.set(model, i);
|
|
7189
|
-
}
|
|
7190
|
-
return i;
|
|
7191
|
-
};
|
|
7330
|
+
const internModel = makeInternModel(models);
|
|
7192
7331
|
let total = 0;
|
|
7193
7332
|
let input = 0;
|
|
7194
7333
|
let output = 0;
|
|
@@ -7233,6 +7372,8 @@ function priceFile(path, encodedDir, st, price, resolveProject) {
|
|
|
7233
7372
|
return {
|
|
7234
7373
|
mtime: st.mtimeMs,
|
|
7235
7374
|
size: st.size,
|
|
7375
|
+
byteOffset,
|
|
7376
|
+
headHash,
|
|
7236
7377
|
total,
|
|
7237
7378
|
lines: costLines,
|
|
7238
7379
|
models,
|
|
@@ -7240,6 +7381,138 @@ function priceFile(path, encodedDir, st, price, resolveProject) {
|
|
|
7240
7381
|
record
|
|
7241
7382
|
};
|
|
7242
7383
|
}
|
|
7384
|
+
function resumeCostFile(cached, path, st, price) {
|
|
7385
|
+
const tail = readAppendedTail(cached, path, st);
|
|
7386
|
+
if (tail === null)
|
|
7387
|
+
return null;
|
|
7388
|
+
if (tail === "partial")
|
|
7389
|
+
return { ...cached, mtime: st.mtimeMs, size: st.size };
|
|
7390
|
+
const models = [...cached.models];
|
|
7391
|
+
const keyIndex = new Map;
|
|
7392
|
+
cached.lines.forEach((l, i) => {
|
|
7393
|
+
if (l.id !== undefined && l.reqId !== undefined)
|
|
7394
|
+
keyIndex.set(`${l.id}|${l.reqId}`, i);
|
|
7395
|
+
});
|
|
7396
|
+
const gate = makeDedupGate();
|
|
7397
|
+
const acc = {
|
|
7398
|
+
lines: [...cached.lines],
|
|
7399
|
+
models,
|
|
7400
|
+
counted: cached.lines.map((l) => gate(l.id, l.reqId, l.sidechain)),
|
|
7401
|
+
keyIndex,
|
|
7402
|
+
gate,
|
|
7403
|
+
internModel: makeInternModel(models),
|
|
7404
|
+
input: cached.record.tokens.input,
|
|
7405
|
+
output: cached.record.tokens.output,
|
|
7406
|
+
cacheRead: cached.record.tokens.cache_read,
|
|
7407
|
+
cacheCreation: cached.record.tokens.cache_creation,
|
|
7408
|
+
total: cached.total,
|
|
7409
|
+
messages: cached.record.messages,
|
|
7410
|
+
start: cached.record.start,
|
|
7411
|
+
end: cached.record.end
|
|
7412
|
+
};
|
|
7413
|
+
for (const l of collapseStreaming(tail.appended))
|
|
7414
|
+
foldAppendedLine(acc, l, price);
|
|
7415
|
+
return {
|
|
7416
|
+
mtime: st.mtimeMs,
|
|
7417
|
+
size: st.size,
|
|
7418
|
+
byteOffset: tail.newByteOffset,
|
|
7419
|
+
headHash: tail.newHeadHash,
|
|
7420
|
+
total: acc.total,
|
|
7421
|
+
lines: acc.lines,
|
|
7422
|
+
models: acc.models,
|
|
7423
|
+
projectPath: cached.projectPath,
|
|
7424
|
+
record: {
|
|
7425
|
+
...cached.record,
|
|
7426
|
+
start: acc.start,
|
|
7427
|
+
end: acc.end,
|
|
7428
|
+
tokens: {
|
|
7429
|
+
input: acc.input,
|
|
7430
|
+
output: acc.output,
|
|
7431
|
+
cache_read: acc.cacheRead,
|
|
7432
|
+
cache_creation: acc.cacheCreation
|
|
7433
|
+
},
|
|
7434
|
+
messages: acc.messages
|
|
7435
|
+
}
|
|
7436
|
+
};
|
|
7437
|
+
}
|
|
7438
|
+
function costLineOf(internModel, l, cost, totalTok) {
|
|
7439
|
+
return {
|
|
7440
|
+
...l.id !== undefined ? { id: l.id } : {},
|
|
7441
|
+
...l.requestId !== undefined ? { reqId: l.requestId } : {},
|
|
7442
|
+
sidechain: l.isSidechain,
|
|
7443
|
+
ts: l.tsMs ?? 0,
|
|
7444
|
+
cost,
|
|
7445
|
+
...l.model !== undefined ? { m: internModel(l.model) } : {},
|
|
7446
|
+
tok: totalTok
|
|
7447
|
+
};
|
|
7448
|
+
}
|
|
7449
|
+
function readAppendedTail(cached, path, st) {
|
|
7450
|
+
const offset = cached.byteOffset;
|
|
7451
|
+
if (offset === undefined || offset === 0 || st.size < offset)
|
|
7452
|
+
return null;
|
|
7453
|
+
const head = readRange(path, 0, headLen(offset));
|
|
7454
|
+
if (head === null || headHashOf(head) !== cached.headHash)
|
|
7455
|
+
return null;
|
|
7456
|
+
const tailBuf = readRange(path, offset, st.size);
|
|
7457
|
+
if (tailBuf === null)
|
|
7458
|
+
return null;
|
|
7459
|
+
const added = lastLineEnd(tailBuf);
|
|
7460
|
+
if (added === 0)
|
|
7461
|
+
return "partial";
|
|
7462
|
+
const newByteOffset = offset + added;
|
|
7463
|
+
const newHead = headLen(newByteOffset) === head.length ? head : readRange(path, 0, headLen(newByteOffset));
|
|
7464
|
+
if (newHead === null)
|
|
7465
|
+
return null;
|
|
7466
|
+
return {
|
|
7467
|
+
appended: parseAll(tailBuf.subarray(0, added).toString("utf8")),
|
|
7468
|
+
newByteOffset,
|
|
7469
|
+
newHeadHash: headHashOf(newHead)
|
|
7470
|
+
};
|
|
7471
|
+
}
|
|
7472
|
+
function widenBounds(acc, tsMs) {
|
|
7473
|
+
if (tsMs === undefined)
|
|
7474
|
+
return;
|
|
7475
|
+
if (tsMs > acc.end)
|
|
7476
|
+
acc.end = tsMs;
|
|
7477
|
+
if (acc.start === 0 || tsMs < acc.start)
|
|
7478
|
+
acc.start = tsMs;
|
|
7479
|
+
}
|
|
7480
|
+
function foldAppendedLine(acc, l, price) {
|
|
7481
|
+
widenBounds(acc, l.tsMs);
|
|
7482
|
+
const usage = l.usage;
|
|
7483
|
+
if (usage === undefined)
|
|
7484
|
+
return;
|
|
7485
|
+
const t = tokenize(usage);
|
|
7486
|
+
const totalTok = t.input + t.output + t.cache_read + t.c5m + t.c1h;
|
|
7487
|
+
const key = l.id !== undefined && l.requestId !== undefined ? `${l.id}|${l.requestId}` : null;
|
|
7488
|
+
const existing = key !== null ? acc.keyIndex.get(key) : undefined;
|
|
7489
|
+
const old = existing !== undefined ? acc.lines[existing] : undefined;
|
|
7490
|
+
if (existing !== undefined && old !== undefined) {
|
|
7491
|
+
if (totalTok <= (old.tok ?? 0))
|
|
7492
|
+
return;
|
|
7493
|
+
const cost2 = price(usage, l.model ?? "", l.tsMs);
|
|
7494
|
+
if (acc.counted[existing] === true) {
|
|
7495
|
+
acc.output += totalTok - (old.tok ?? 0);
|
|
7496
|
+
acc.total += cost2 - old.cost;
|
|
7497
|
+
}
|
|
7498
|
+
acc.lines[existing] = costLineOf(acc.internModel, l, cost2, totalTok);
|
|
7499
|
+
return;
|
|
7500
|
+
}
|
|
7501
|
+
const cost = price(usage, l.model ?? "", l.tsMs);
|
|
7502
|
+
const isCounted = acc.gate(l.id, l.requestId, l.isSidechain);
|
|
7503
|
+
if (key !== null)
|
|
7504
|
+
acc.keyIndex.set(key, acc.lines.length);
|
|
7505
|
+
acc.lines.push(costLineOf(acc.internModel, l, cost, totalTok));
|
|
7506
|
+
acc.counted.push(isCounted);
|
|
7507
|
+
if (isCounted) {
|
|
7508
|
+
acc.input += t.input;
|
|
7509
|
+
acc.output += t.output;
|
|
7510
|
+
acc.cacheRead += t.cache_read;
|
|
7511
|
+
acc.cacheCreation += t.c5m + t.c1h;
|
|
7512
|
+
acc.total += cost;
|
|
7513
|
+
acc.messages += 1;
|
|
7514
|
+
}
|
|
7515
|
+
}
|
|
7243
7516
|
function buildAggregate(files, chat) {
|
|
7244
7517
|
const sessionProject = {};
|
|
7245
7518
|
const all = [];
|
|
@@ -7274,16 +7547,26 @@ function scanCostTree(root, cache, clock, price, resolveProject) {
|
|
|
7274
7547
|
return cache;
|
|
7275
7548
|
const chat = cache.aggregate.chat;
|
|
7276
7549
|
const files = {};
|
|
7550
|
+
let changed = false;
|
|
7277
7551
|
for (const { path, encodedDir } of walkJsonl(root)) {
|
|
7278
7552
|
const st = statSafe(path);
|
|
7279
7553
|
if (!st)
|
|
7280
7554
|
continue;
|
|
7281
7555
|
const cached = cache.files[path];
|
|
7282
|
-
|
|
7556
|
+
if (cached && cached.mtime === st.mtimeMs && cached.size === st.size) {
|
|
7557
|
+
files[path] = cached;
|
|
7558
|
+
} else {
|
|
7559
|
+
const resumed = cached ? resumeCostFile(cached, path, st, price) : null;
|
|
7560
|
+
files[path] = resumed ?? priceFile(path, encodedDir, st, price, resolveProject);
|
|
7561
|
+
changed = true;
|
|
7562
|
+
}
|
|
7283
7563
|
}
|
|
7564
|
+
const sameFileSet = Object.keys(files).length === Object.keys(cache.files).length;
|
|
7565
|
+
if (!changed && sameFileSet)
|
|
7566
|
+
return { files, aggregate: cache.aggregate, lastScanTs: now };
|
|
7284
7567
|
return { files, aggregate: buildAggregate(files, chat), lastScanTs: now };
|
|
7285
7568
|
}
|
|
7286
|
-
var asObj = (v) => v !== null && typeof v === "object" ? v : undefined, asStr = (v) => typeof v === "string" ? v : undefined, asNum = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0, asArr = (v) => Array.isArray(v) ? v : [], EMPTY_TOKENS, repoRootCache;
|
|
7569
|
+
var asObj = (v) => v !== null && typeof v === "object" ? v : undefined, asStr = (v) => typeof v === "string" ? v : undefined, asNum = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0, asArr = (v) => Array.isArray(v) ? v : [], HEAD_HASH_BYTES = 4096, headLen = (byteOffset) => Math.min(HEAD_HASH_BYTES, byteOffset), EMPTY_TOKENS, repoRootCache;
|
|
7287
7570
|
var init_transcript = __esm(() => {
|
|
7288
7571
|
init_domain();
|
|
7289
7572
|
EMPTY_TOKENS = {
|
|
@@ -7317,15 +7600,31 @@ var init_sources = __esm(() => {
|
|
|
7317
7600
|
});
|
|
7318
7601
|
|
|
7319
7602
|
// src/cli/gc.ts
|
|
7320
|
-
import {
|
|
7603
|
+
import {
|
|
7604
|
+
existsSync as existsSync2,
|
|
7605
|
+
mkdirSync as mkdirSync4,
|
|
7606
|
+
readFileSync as readFileSync9,
|
|
7607
|
+
readdirSync as readdirSync3,
|
|
7608
|
+
rmSync,
|
|
7609
|
+
statSync as statSync5,
|
|
7610
|
+
writeFileSync as writeFileSync3
|
|
7611
|
+
} from "node:fs";
|
|
7321
7612
|
import { join as join13 } from "node:path";
|
|
7613
|
+
function readGcStamp(path) {
|
|
7614
|
+
try {
|
|
7615
|
+
const n = Number(readFileSync9(path, "utf8"));
|
|
7616
|
+
return Number.isFinite(n) ? n : undefined;
|
|
7617
|
+
} catch {
|
|
7618
|
+
return;
|
|
7619
|
+
}
|
|
7620
|
+
}
|
|
7322
7621
|
function newestMtime(dir) {
|
|
7323
7622
|
let newest = 0;
|
|
7324
7623
|
try {
|
|
7325
|
-
newest =
|
|
7624
|
+
newest = statSync5(dir).mtimeMs;
|
|
7326
7625
|
for (const name of readdirSync3(dir)) {
|
|
7327
7626
|
try {
|
|
7328
|
-
const m =
|
|
7627
|
+
const m = statSync5(join13(dir, name)).mtimeMs;
|
|
7329
7628
|
if (m > newest)
|
|
7330
7629
|
newest = m;
|
|
7331
7630
|
} catch {}
|
|
@@ -7345,7 +7644,7 @@ function pruneSessions(root, now) {
|
|
|
7345
7644
|
for (const name of names) {
|
|
7346
7645
|
const dir = join13(sessions, name);
|
|
7347
7646
|
try {
|
|
7348
|
-
if (!
|
|
7647
|
+
if (!statSync5(dir).isDirectory())
|
|
7349
7648
|
continue;
|
|
7350
7649
|
} catch {
|
|
7351
7650
|
continue;
|
|
@@ -7358,36 +7657,62 @@ function pruneSessions(root, now) {
|
|
|
7358
7657
|
function pruneCostCache(root) {
|
|
7359
7658
|
const cache = readCostCache(root);
|
|
7360
7659
|
const kept = {};
|
|
7660
|
+
const liveSessions = new Set;
|
|
7361
7661
|
let dropped = false;
|
|
7362
7662
|
for (const [path, entry] of Object.entries(cache.files)) {
|
|
7363
|
-
if (existsSync2(path))
|
|
7663
|
+
if (existsSync2(path)) {
|
|
7364
7664
|
kept[path] = entry;
|
|
7365
|
-
|
|
7665
|
+
liveSessions.add(String(entry.record.session));
|
|
7666
|
+
} else {
|
|
7366
7667
|
dropped = true;
|
|
7668
|
+
}
|
|
7669
|
+
}
|
|
7670
|
+
const chatKept = {};
|
|
7671
|
+
let chatDropped = false;
|
|
7672
|
+
for (const [session, cost] of Object.entries(cache.aggregate.chat)) {
|
|
7673
|
+
if (liveSessions.has(session))
|
|
7674
|
+
chatKept[session] = cost;
|
|
7675
|
+
else
|
|
7676
|
+
chatDropped = true;
|
|
7677
|
+
}
|
|
7678
|
+
if (dropped || chatDropped) {
|
|
7679
|
+
writeCostCache(root, {
|
|
7680
|
+
...cache,
|
|
7681
|
+
files: kept,
|
|
7682
|
+
aggregate: { ...cache.aggregate, chat: chatKept }
|
|
7683
|
+
});
|
|
7367
7684
|
}
|
|
7368
|
-
if (dropped)
|
|
7369
|
-
writeCostCache(root, { ...cache, files: kept });
|
|
7370
7685
|
}
|
|
7371
7686
|
function runGc(root, clock) {
|
|
7687
|
+
const now = clock.now();
|
|
7688
|
+
const stampPath = join13(root, "cache", ".gc-stamp");
|
|
7689
|
+
const last = readGcStamp(stampPath);
|
|
7690
|
+
if (last !== undefined && now - last < GC_MIN_INTERVAL_MS)
|
|
7691
|
+
return;
|
|
7372
7692
|
try {
|
|
7373
|
-
pruneSessions(root,
|
|
7693
|
+
pruneSessions(root, now);
|
|
7374
7694
|
} catch {}
|
|
7375
7695
|
try {
|
|
7376
7696
|
pruneCostCache(root);
|
|
7377
7697
|
} catch {}
|
|
7698
|
+
try {
|
|
7699
|
+
mkdirSync4(join13(root, "cache"), { recursive: true });
|
|
7700
|
+
writeFileSync3(stampPath, String(now));
|
|
7701
|
+
} catch {}
|
|
7378
7702
|
}
|
|
7379
|
-
var DAY_MS = 86400000;
|
|
7703
|
+
var DAY_MS = 86400000, GC_MIN_INTERVAL_MS;
|
|
7380
7704
|
var init_gc = __esm(() => {
|
|
7381
7705
|
init_domain();
|
|
7382
7706
|
init_sources();
|
|
7707
|
+
GC_MIN_INTERVAL_MS = 6 * 60 * 60 * 1000;
|
|
7383
7708
|
});
|
|
7384
7709
|
|
|
7385
7710
|
// src/cli/render.ts
|
|
7386
|
-
import { readFileSync as
|
|
7711
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
7387
7712
|
import { dirname as dirname6, join as join14 } from "node:path";
|
|
7388
7713
|
function readTextSafe(path) {
|
|
7389
7714
|
try {
|
|
7390
|
-
return
|
|
7715
|
+
return readFileSync10(path, "utf8");
|
|
7391
7716
|
} catch {
|
|
7392
7717
|
return "";
|
|
7393
7718
|
}
|
|
@@ -7422,18 +7747,28 @@ function applyThemeIcons(fields, theme, config) {
|
|
|
7422
7747
|
});
|
|
7423
7748
|
}
|
|
7424
7749
|
function readGated(overrides, envInputs, config, root, dir, markers, clock) {
|
|
7425
|
-
const creds = overrides?.creds !== undefined ? overrides.creds : envInputs.hasApiKey || config.network.usage_fetch ?
|
|
7750
|
+
const creds = overrides?.creds !== undefined ? overrides.creds : envInputs.hasApiKey || config.network.usage_fetch ? readCredsCached(root) : null;
|
|
7426
7751
|
const usage = overrides?.usage !== undefined ? overrides.usage : config.network.usage_fetch ? readUsageCached(root) : null;
|
|
7427
7752
|
const balance = overrides?.balance !== undefined ? overrides.balance : config.network.balance_path !== "" ? readBalance(config.network.balance_path, clock) : null;
|
|
7428
7753
|
const helpfulEnv = needsHelpfulEnv(markers) ? readHelpfulEnv(dir) : EMPTY_HELPFUL_ENV;
|
|
7429
7754
|
return { creds, usage, balance, helpfulEnv };
|
|
7430
7755
|
}
|
|
7431
|
-
function
|
|
7432
|
-
const loaded = loadPack(name);
|
|
7756
|
+
function packThemeOf(loaded) {
|
|
7433
7757
|
if (!loaded.ok || loaded.pack.theme === undefined)
|
|
7434
7758
|
return null;
|
|
7435
7759
|
return { displayName: loaded.pack.displayName, ...loaded.pack.theme };
|
|
7436
7760
|
}
|
|
7761
|
+
function makePackThemeLookup(persona, loaded, load = loadPack) {
|
|
7762
|
+
const memo = new Map;
|
|
7763
|
+
return (name) => {
|
|
7764
|
+
const cached = memo.get(name);
|
|
7765
|
+
if (cached !== undefined || memo.has(name))
|
|
7766
|
+
return cached ?? null;
|
|
7767
|
+
const theme = packThemeOf(name === persona ? loaded : load(name));
|
|
7768
|
+
memo.set(name, theme);
|
|
7769
|
+
return theme;
|
|
7770
|
+
};
|
|
7771
|
+
}
|
|
7437
7772
|
function runRender(stdin, env, term, clock, overrides) {
|
|
7438
7773
|
try {
|
|
7439
7774
|
return build(stdin, env, term, clock, overrides);
|
|
@@ -7495,8 +7830,8 @@ function build(stdin, env, term, clock, overrides) {
|
|
|
7495
7830
|
const stacks = deriveStacks(markers, events);
|
|
7496
7831
|
const fresh = freshestEvent(events);
|
|
7497
7832
|
const stack = pickStack(stacks, fresh?.stack);
|
|
7498
|
-
const familiarity = deriveFamiliarity(attribution, persona, scannedCache, project, clock);
|
|
7499
|
-
const theme = resolveTheme(config,
|
|
7833
|
+
const familiarity = deriveFamiliarity(attribution, persona, scannedCache, project, clock, String(session));
|
|
7834
|
+
const theme = resolveTheme(config, makePackThemeLookup(persona, loaded), persona);
|
|
7500
7835
|
const composeInputs = {
|
|
7501
7836
|
provider,
|
|
7502
7837
|
model,
|
|
@@ -7597,6 +7932,10 @@ function build(stdin, env, term, clock, overrides) {
|
|
|
7597
7932
|
}
|
|
7598
7933
|
swallow(() => {
|
|
7599
7934
|
const payloadChat = payload.cost?.total_cost_usd;
|
|
7935
|
+
const rescanned = scannedCache !== costCache;
|
|
7936
|
+
const chatChanged = !isDefault && payloadChat !== undefined && scannedCache.aggregate.chat[String(session)] !== payloadChat;
|
|
7937
|
+
if (!rescanned && !chatChanged)
|
|
7938
|
+
return;
|
|
7600
7939
|
const toWrite = !isDefault && payloadChat !== undefined ? {
|
|
7601
7940
|
...scannedCache,
|
|
7602
7941
|
aggregate: {
|
|
@@ -7620,6 +7959,10 @@ function build(stdin, env, term, clock, overrides) {
|
|
|
7620
7959
|
swallow(() => {
|
|
7621
7960
|
readUsage(root, clock, { enabled: config.network.usage_fetch });
|
|
7622
7961
|
});
|
|
7962
|
+
swallow(() => {
|
|
7963
|
+
if (envInputs.hasApiKey || config.network.usage_fetch)
|
|
7964
|
+
refreshCreds(root, clock);
|
|
7965
|
+
});
|
|
7623
7966
|
swallow(() => {
|
|
7624
7967
|
runGc(root, clock);
|
|
7625
7968
|
});
|
|
@@ -7646,7 +7989,7 @@ var init_render2 = __esm(() => {
|
|
|
7646
7989
|
});
|
|
7647
7990
|
|
|
7648
7991
|
// src/cli/settings.ts
|
|
7649
|
-
import { existsSync as existsSync3, readFileSync as
|
|
7992
|
+
import { existsSync as existsSync3, readFileSync as readFileSync11, readdirSync as readdirSync4, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
7650
7993
|
import { basename as basename3, dirname as dirname7, join as join15 } from "node:path";
|
|
7651
7994
|
function asRecord(v) {
|
|
7652
7995
|
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : {};
|
|
@@ -7677,16 +8020,16 @@ function pruneBackups(settingsPath) {
|
|
|
7677
8020
|
}
|
|
7678
8021
|
function safeWriteJson(path, text, restoreText) {
|
|
7679
8022
|
const tmp = `${path}.tmp.${String(process.pid)}.${Math.random().toString(36).slice(2)}`;
|
|
7680
|
-
|
|
7681
|
-
|
|
8023
|
+
writeFileSync4(tmp, text);
|
|
8024
|
+
renameSync3(tmp, path);
|
|
7682
8025
|
let ok = false;
|
|
7683
8026
|
try {
|
|
7684
|
-
ok = parseJsonObject(
|
|
8027
|
+
ok = parseJsonObject(readFileSync11(path, "utf8")) !== null;
|
|
7685
8028
|
} catch {
|
|
7686
8029
|
ok = false;
|
|
7687
8030
|
}
|
|
7688
8031
|
if (!ok) {
|
|
7689
|
-
|
|
8032
|
+
writeFileSync4(path, restoreText);
|
|
7690
8033
|
throw new Error(`ccsidekick: settings write failed verification at ${path}; restored prior content`);
|
|
7691
8034
|
}
|
|
7692
8035
|
}
|
|
@@ -7696,7 +8039,7 @@ function installSettings(opts) {
|
|
|
7696
8039
|
let base = {};
|
|
7697
8040
|
let originalText = "";
|
|
7698
8041
|
if (exists) {
|
|
7699
|
-
originalText =
|
|
8042
|
+
originalText = readFileSync11(settingsPath, "utf8");
|
|
7700
8043
|
const parsed = parseJsonObject(originalText);
|
|
7701
8044
|
if (parsed === null) {
|
|
7702
8045
|
throw new Error(`ccsidekick: refusing to modify unparseable settings at ${settingsPath}`);
|
|
@@ -7721,7 +8064,7 @@ function installSettings(opts) {
|
|
|
7721
8064
|
spinnerVerbs: { mode: "replace", verbs: [...spinnerVerbs] }
|
|
7722
8065
|
};
|
|
7723
8066
|
if (exists) {
|
|
7724
|
-
|
|
8067
|
+
writeFileSync4(`${settingsPath}.ccsidekick-bak.${String(Date.now())}`, originalText);
|
|
7725
8068
|
pruneBackups(settingsPath);
|
|
7726
8069
|
}
|
|
7727
8070
|
safeWriteJson(settingsPath, `${JSON.stringify(merged, null, 2)}
|
|
@@ -7735,11 +8078,11 @@ var init_settings = __esm(() => {
|
|
|
7735
8078
|
init_dist();
|
|
7736
8079
|
init_domain();
|
|
7737
8080
|
init_sources();
|
|
7738
|
-
HOOK_EVENTS = ["PostToolUse", "PostToolUseFailure"
|
|
8081
|
+
HOOK_EVENTS = ["PostToolUse", "PostToolUseFailure"];
|
|
7739
8082
|
});
|
|
7740
8083
|
|
|
7741
8084
|
// src/cli/setup.ts
|
|
7742
|
-
import { readFileSync as
|
|
8085
|
+
import { readFileSync as readFileSync12 } from "node:fs";
|
|
7743
8086
|
import { join as join16 } from "node:path";
|
|
7744
8087
|
function themeNames() {
|
|
7745
8088
|
return [CHARACTER_THEME, ...Object.keys(THEMES), ...PACKS];
|
|
@@ -7891,14 +8234,14 @@ function setupHelp() {
|
|
|
7891
8234
|
"",
|
|
7892
8235
|
"Flags (only the ones you pass are applied):",
|
|
7893
8236
|
` --character <name> ${PACKS.join(", ")}`,
|
|
7894
|
-
` --mode <mode> ${
|
|
8237
|
+
` --mode <mode> ${CHARACTER_MODES.join(", ")}`,
|
|
7895
8238
|
" --roster <a,b,c> characters for random mode (from --character's list)",
|
|
7896
8239
|
` --theme <name> ${themeNames().join(", ")}`,
|
|
7897
8240
|
" --currency <code> e.g. USD, EUR, INR",
|
|
7898
8241
|
" --budget <usd> monthly budget, a number >= 0",
|
|
7899
8242
|
" --comments <on|off> the character's own comment line",
|
|
7900
8243
|
" --helpful <on|off> the helpful-tip line",
|
|
7901
|
-
` --min-severity <sev> ${
|
|
8244
|
+
` --min-severity <sev> ${MIN_SEVERITIES.join(", ")}`,
|
|
7902
8245
|
" --widgets <a,b,c> statusline widgets to enable (others are turned off)",
|
|
7903
8246
|
" --usage-fetch <on|off> account-usage lookup to Anthropic (needed by the pay_as_you_go widget; no tokens)",
|
|
7904
8247
|
" --global | --local save target (default: global)",
|
|
@@ -7911,12 +8254,12 @@ function setupHelp() {
|
|
|
7911
8254
|
}
|
|
7912
8255
|
function defaultReadConfig(path) {
|
|
7913
8256
|
try {
|
|
7914
|
-
return
|
|
8257
|
+
return readFileSync12(path, "utf8");
|
|
7915
8258
|
} catch {
|
|
7916
8259
|
return null;
|
|
7917
8260
|
}
|
|
7918
8261
|
}
|
|
7919
|
-
var WIDGET_IDS,
|
|
8262
|
+
var WIDGET_IDS, VALUE_FLAGS, BOOL_FLAGS, splitList = (raw) => raw.split(",").map((s) => s.trim()).filter((s) => s !== ""), invalid = (flag, value, valid) => `ccsidekick: invalid --${flag} "${value}". Valid: ${valid.join(", ")}`, parseOnOff = (flag, value, errors) => {
|
|
7920
8263
|
if (value === "on")
|
|
7921
8264
|
return true;
|
|
7922
8265
|
if (value === "off")
|
|
@@ -7926,12 +8269,11 @@ var WIDGET_IDS, MODES, SEVERITIES, VALUE_FLAGS, BOOL_FLAGS, splitList = (raw) =>
|
|
|
7926
8269
|
}, memberOf = (value, valid) => valid.includes(value), VALIDATORS;
|
|
7927
8270
|
var init_setup = __esm(() => {
|
|
7928
8271
|
init_data();
|
|
8272
|
+
init_domain();
|
|
7929
8273
|
init_packs();
|
|
7930
8274
|
init_render();
|
|
7931
8275
|
init_sources();
|
|
7932
8276
|
WIDGET_IDS = Object.keys(DEFAULT_CONFIG.statusline.widgets);
|
|
7933
|
-
MODES = ["fixed", "random"];
|
|
7934
|
-
SEVERITIES = ["low", "medium", "high", "critical"];
|
|
7935
8277
|
VALUE_FLAGS = new Set([
|
|
7936
8278
|
"character",
|
|
7937
8279
|
"mode",
|
|
@@ -7952,7 +8294,7 @@ var init_setup = __esm(() => {
|
|
|
7952
8294
|
enumInto(v, PACKS, "character", e, (x) => f.character = x);
|
|
7953
8295
|
},
|
|
7954
8296
|
mode: (v, f, e) => {
|
|
7955
|
-
enumInto(v,
|
|
8297
|
+
enumInto(v, CHARACTER_MODES, "mode", e, (x) => f.mode = x);
|
|
7956
8298
|
},
|
|
7957
8299
|
roster: (v, f, e) => {
|
|
7958
8300
|
listInto(v, PACKS, "roster", e, (x) => f.roster = x);
|
|
@@ -7985,7 +8327,7 @@ var init_setup = __esm(() => {
|
|
|
7985
8327
|
f.helpful = b;
|
|
7986
8328
|
},
|
|
7987
8329
|
"min-severity": (v, f, e) => {
|
|
7988
|
-
enumInto(v,
|
|
8330
|
+
enumInto(v, MIN_SEVERITIES, "min-severity", e, (x) => f.minSeverity = x);
|
|
7989
8331
|
},
|
|
7990
8332
|
widgets: (v, f, e) => {
|
|
7991
8333
|
listInto(v, WIDGET_IDS, "widgets", e, (x) => f.widgets = x);
|
|
@@ -7999,7 +8341,7 @@ var init_setup = __esm(() => {
|
|
|
7999
8341
|
});
|
|
8000
8342
|
|
|
8001
8343
|
// src/cli/uninstall.ts
|
|
8002
|
-
import { existsSync as existsSync4, readFileSync as
|
|
8344
|
+
import { existsSync as existsSync4, readFileSync as readFileSync13, readdirSync as readdirSync5 } from "node:fs";
|
|
8003
8345
|
import { basename as basename4, dirname as dirname8, join as join17 } from "node:path";
|
|
8004
8346
|
function asRecord2(v) {
|
|
8005
8347
|
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : {};
|
|
@@ -8046,7 +8388,7 @@ function restoreNewestBackup(settingsPath) {
|
|
|
8046
8388
|
}
|
|
8047
8389
|
if (newest === undefined)
|
|
8048
8390
|
return null;
|
|
8049
|
-
atomicWrite(settingsPath,
|
|
8391
|
+
atomicWrite(settingsPath, readFileSync13(join17(dir, newest.name), "utf8"));
|
|
8050
8392
|
return newest.name;
|
|
8051
8393
|
}
|
|
8052
8394
|
function runRestore(settingsPath, emit) {
|
|
@@ -8100,7 +8442,7 @@ function runUninstall(opts) {
|
|
|
8100
8442
|
return;
|
|
8101
8443
|
}
|
|
8102
8444
|
if (existsSync4(settingsPath)) {
|
|
8103
|
-
const parsed = parseJsonObject2(
|
|
8445
|
+
const parsed = parseJsonObject2(readFileSync13(settingsPath, "utf8"));
|
|
8104
8446
|
if (parsed === null) {
|
|
8105
8447
|
throw new Error(`ccsidekick: refusing to modify unparseable settings at ${settingsPath}`);
|
|
8106
8448
|
}
|
|
@@ -8182,7 +8524,7 @@ var init_metrics = __esm(() => {
|
|
|
8182
8524
|
var ACCENT = "#ffd700", FRAME = "gray", DANGER = "red";
|
|
8183
8525
|
|
|
8184
8526
|
// src/tui/save.ts
|
|
8185
|
-
import { mkdirSync as
|
|
8527
|
+
import { mkdirSync as mkdirSync5 } from "node:fs";
|
|
8186
8528
|
import { join as join19 } from "node:path";
|
|
8187
8529
|
function defaultResolveVerbs(name) {
|
|
8188
8530
|
const loaded = loadPack(name);
|
|
@@ -8219,7 +8561,7 @@ function save(config, scope, dir, renderBin, opts = {}) {
|
|
|
8219
8561
|
writeConfigToml(join19(cwd, ".ccsidekick"), normalized);
|
|
8220
8562
|
if (opts.wireLocalSettings === true) {
|
|
8221
8563
|
const claudeDir = join19(cwd, ".claude");
|
|
8222
|
-
|
|
8564
|
+
mkdirSync5(claudeDir, { recursive: true });
|
|
8223
8565
|
installSettings({
|
|
8224
8566
|
settingsPath: join19(claudeDir, "settings.json"),
|
|
8225
8567
|
renderBin,
|
|
@@ -10917,14 +11259,14 @@ var init_PreviewPanel = __esm(() => {
|
|
|
10917
11259
|
|
|
10918
11260
|
// src/tui/preview/fixture.ts
|
|
10919
11261
|
import { execFileSync } from "node:child_process";
|
|
10920
|
-
import { existsSync as existsSync6, mkdirSync as
|
|
11262
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync6, mkdtempSync, realpathSync, writeFileSync as writeFileSync5 } from "node:fs";
|
|
10921
11263
|
import { tmpdir } from "node:os";
|
|
10922
11264
|
import { join as join20 } from "node:path";
|
|
10923
11265
|
function seedTranscriptFixture(workdir, root) {
|
|
10924
11266
|
const dir = root !== undefined ? join20(root, "projects", workdir.replace(/[/.]/g, "-")) : workdir;
|
|
10925
11267
|
const path = join20(dir, "preview-transcript.jsonl");
|
|
10926
11268
|
try {
|
|
10927
|
-
|
|
11269
|
+
mkdirSync6(dir, { recursive: true });
|
|
10928
11270
|
if (!existsSync6(path)) {
|
|
10929
11271
|
const lines = [
|
|
10930
11272
|
JSON.stringify({ type: "system", subtype: "compact_boundary" }),
|
|
@@ -10948,7 +11290,7 @@ function seedTranscriptFixture(workdir, root) {
|
|
|
10948
11290
|
}
|
|
10949
11291
|
})
|
|
10950
11292
|
];
|
|
10951
|
-
|
|
11293
|
+
writeFileSync5(path, `${lines.join(`
|
|
10952
11294
|
`)}
|
|
10953
11295
|
`);
|
|
10954
11296
|
}
|
|
@@ -10992,7 +11334,7 @@ function gitEnv() {
|
|
|
10992
11334
|
}
|
|
10993
11335
|
function setupGitFixture(workdir) {
|
|
10994
11336
|
try {
|
|
10995
|
-
|
|
11337
|
+
mkdirSync6(workdir, { recursive: true });
|
|
10996
11338
|
if (existsSync6(join20(workdir, ".git")))
|
|
10997
11339
|
return;
|
|
10998
11340
|
const env2 = gitEnv();
|
|
@@ -11003,20 +11345,20 @@ function setupGitFixture(workdir) {
|
|
|
11003
11345
|
git("config", "user.email", "wayne@example.com");
|
|
11004
11346
|
git("config", "user.name", "Bruce Wayne");
|
|
11005
11347
|
git("remote", "add", "origin", "https://github.com/wayne/ccsidekick.git");
|
|
11006
|
-
|
|
11348
|
+
writeFileSync5(join20(workdir, "README.md"), `# ccsidekick
|
|
11007
11349
|
|
|
11008
11350
|
original line
|
|
11009
11351
|
keep me
|
|
11010
11352
|
`);
|
|
11011
11353
|
git("add", "README.md");
|
|
11012
11354
|
git("commit", "-q", "-m", "initial commit");
|
|
11013
|
-
|
|
11355
|
+
writeFileSync5(join20(workdir, "README.md"), `# ccsidekick
|
|
11014
11356
|
|
|
11015
11357
|
edited line
|
|
11016
11358
|
keep me
|
|
11017
11359
|
new line
|
|
11018
11360
|
`);
|
|
11019
|
-
|
|
11361
|
+
writeFileSync5(join20(workdir, "src.ts"), `export const answer = 42;
|
|
11020
11362
|
`);
|
|
11021
11363
|
git("add", "src.ts");
|
|
11022
11364
|
} catch {}
|
|
@@ -11041,11 +11383,11 @@ function seedCostFixture(root, workdir) {
|
|
|
11041
11383
|
const projectsRoot = join20(root, "projects");
|
|
11042
11384
|
const currentProjectDir = join20(projectsRoot, workdir.replace(/[/.]/g, "-"));
|
|
11043
11385
|
const otherProjectDir = join20(projectsRoot, "-other-project");
|
|
11044
|
-
|
|
11045
|
-
|
|
11046
|
-
|
|
11386
|
+
mkdirSync6(currentProjectDir, { recursive: true });
|
|
11387
|
+
mkdirSync6(otherProjectDir, { recursive: true });
|
|
11388
|
+
writeFileSync5(join20(currentProjectDir, "sess-a.jsonl"), `${transcriptLine("sess-a-1", "claude-opus-4-8", 1e5, 20000)}
|
|
11047
11389
|
`);
|
|
11048
|
-
|
|
11390
|
+
writeFileSync5(join20(otherProjectDir, "sess-b.jsonl"), `${transcriptLine("sess-b-1", "claude-opus-4-8", 200000, 50000)}
|
|
11049
11391
|
`);
|
|
11050
11392
|
}
|
|
11051
11393
|
function scratchRoot(scratchDir) {
|
|
@@ -11056,7 +11398,7 @@ function scratchRoot(scratchDir) {
|
|
|
11056
11398
|
}
|
|
11057
11399
|
function previewEnv(root, extra) {
|
|
11058
11400
|
const homeBase = join20(root, "home");
|
|
11059
|
-
|
|
11401
|
+
mkdirSync6(homeBase, { recursive: true });
|
|
11060
11402
|
let home = homeBase;
|
|
11061
11403
|
try {
|
|
11062
11404
|
home = realpathSync(homeBase);
|
|
@@ -11265,8 +11607,8 @@ function checkedTargets(targets, checked) {
|
|
|
11265
11607
|
}
|
|
11266
11608
|
|
|
11267
11609
|
// src/tui/sections/configdir.tsx
|
|
11268
|
-
import { existsSync as existsSync7, mkdirSync as
|
|
11269
|
-
import { homedir as
|
|
11610
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync7 } from "node:fs";
|
|
11611
|
+
import { homedir as homedir4 } from "node:os";
|
|
11270
11612
|
import { Box as Box22, Text as Text27, useApp, useInput as useInput7 } from "ink";
|
|
11271
11613
|
import { useState as useState6 } from "react";
|
|
11272
11614
|
import { jsxDEV as jsxDEV14 } from "react/jsx-dev-runtime";
|
|
@@ -11310,7 +11652,7 @@ function handleCustomKey(input, key, d) {
|
|
|
11310
11652
|
function handleConfirmKey(key, d) {
|
|
11311
11653
|
if (key.return && d.pending !== null) {
|
|
11312
11654
|
try {
|
|
11313
|
-
|
|
11655
|
+
mkdirSync7(d.pending, { recursive: true });
|
|
11314
11656
|
d.addDir(d.pending);
|
|
11315
11657
|
} catch {
|
|
11316
11658
|
d.setError(`Could not create ${d.pending}`);
|
|
@@ -11377,7 +11719,7 @@ function ConfigDirPicker({
|
|
|
11377
11719
|
onQuit
|
|
11378
11720
|
}) {
|
|
11379
11721
|
const { exit } = useApp();
|
|
11380
|
-
const home =
|
|
11722
|
+
const home = homedir4();
|
|
11381
11723
|
const [cursor4, setCursor] = useState6(0);
|
|
11382
11724
|
const [mode, setMode] = useState6("list");
|
|
11383
11725
|
const [text, setText] = useState6("");
|
|
@@ -11640,7 +11982,10 @@ function commentsFields(d) {
|
|
|
11640
11982
|
value: d.comments.min_severity,
|
|
11641
11983
|
next: (c) => ({
|
|
11642
11984
|
...c,
|
|
11643
|
-
comments: {
|
|
11985
|
+
comments: {
|
|
11986
|
+
...c.comments,
|
|
11987
|
+
min_severity: step(MIN_SEVERITIES, c.comments.min_severity, 1)
|
|
11988
|
+
}
|
|
11644
11989
|
})
|
|
11645
11990
|
};
|
|
11646
11991
|
return d.comments.helpful ? [characterComments, helpfulComments, minSeverity] : [characterComments, helpfulComments];
|
|
@@ -11688,16 +12033,15 @@ function sectionFields(section2, d) {
|
|
|
11688
12033
|
return [];
|
|
11689
12034
|
}
|
|
11690
12035
|
}
|
|
11691
|
-
var onOff = (b) => b ? "on" : "off", WIDGET_IDS2,
|
|
12036
|
+
var onOff = (b) => b ? "on" : "off", WIDGET_IDS2, step = (arr, cur, dir) => {
|
|
11692
12037
|
const n = arr.length;
|
|
11693
12038
|
const i = arr.indexOf(cur);
|
|
11694
12039
|
return arr[((i + dir) % n + n) % n] ?? cur;
|
|
11695
12040
|
};
|
|
11696
12041
|
var init_forms = __esm(() => {
|
|
12042
|
+
init_domain();
|
|
11697
12043
|
init_sources();
|
|
11698
12044
|
WIDGET_IDS2 = Object.keys(DEFAULT_CONFIG.statusline.widgets);
|
|
11699
|
-
SEVERITIES2 = ["low", "medium", "high", "critical"];
|
|
11700
|
-
BANDINGS = ["solid", "cycle"];
|
|
11701
12045
|
});
|
|
11702
12046
|
|
|
11703
12047
|
// src/tui/sections/FormSection.tsx
|
|
@@ -12838,7 +13182,7 @@ var init_inputRoute = __esm(() => {
|
|
|
12838
13182
|
});
|
|
12839
13183
|
|
|
12840
13184
|
// src/tui/shell/saveTarget.ts
|
|
12841
|
-
import { existsSync as existsSync8, readFileSync as
|
|
13185
|
+
import { existsSync as existsSync8, readFileSync as readFileSync14 } from "node:fs";
|
|
12842
13186
|
import { join as join22 } from "node:path";
|
|
12843
13187
|
function chipFor(targets) {
|
|
12844
13188
|
if (targets.every((t) => t.scope === "global"))
|
|
@@ -12851,7 +13195,7 @@ function alreadyWired(settingsPath) {
|
|
|
12851
13195
|
if (!existsSync8(settingsPath))
|
|
12852
13196
|
return false;
|
|
12853
13197
|
try {
|
|
12854
|
-
const parsed = JSON.parse(
|
|
13198
|
+
const parsed = JSON.parse(readFileSync14(settingsPath, "utf8"));
|
|
12855
13199
|
return isOurStatusLine(parsed.statusLine);
|
|
12856
13200
|
} catch {
|
|
12857
13201
|
return false;
|
|
@@ -13105,7 +13449,7 @@ var init_useMouseWheel = __esm(() => {
|
|
|
13105
13449
|
});
|
|
13106
13450
|
|
|
13107
13451
|
// src/tui/shell/Dashboard.tsx
|
|
13108
|
-
import { readFileSync as
|
|
13452
|
+
import { readFileSync as readFileSync15 } from "node:fs";
|
|
13109
13453
|
import { join as join23 } from "node:path";
|
|
13110
13454
|
import { Box as Box30, Text as Text35, useApp as useApp2, useInput as useInput8 } from "ink";
|
|
13111
13455
|
import { useCallback as useCallback6, useMemo as useMemo9, useState as useState8 } from "react";
|
|
@@ -13904,7 +14248,7 @@ var seed = (configDir2, initial) => {
|
|
|
13904
14248
|
if (initial)
|
|
13905
14249
|
return initial;
|
|
13906
14250
|
try {
|
|
13907
|
-
return loadConfig(
|
|
14251
|
+
return loadConfig(readFileSync15(join23(configDir2, "ccsidekick", "config.toml"), "utf8"));
|
|
13908
14252
|
} catch {
|
|
13909
14253
|
return loadConfig("");
|
|
13910
14254
|
}
|
|
@@ -14547,8 +14891,8 @@ var init_Wizard = __esm(() => {
|
|
|
14547
14891
|
});
|
|
14548
14892
|
|
|
14549
14893
|
// src/tui/shell/App.tsx
|
|
14550
|
-
import { existsSync as existsSync9, readFileSync as
|
|
14551
|
-
import { homedir as
|
|
14894
|
+
import { existsSync as existsSync9, readFileSync as readFileSync16 } from "node:fs";
|
|
14895
|
+
import { homedir as homedir5 } from "node:os";
|
|
14552
14896
|
import { join as join24 } from "node:path";
|
|
14553
14897
|
import { useInput as useInput10 } from "ink";
|
|
14554
14898
|
import { useMemo as useMemo10, useState as useState10 } from "react";
|
|
@@ -14562,7 +14906,7 @@ function welcomeTheme(suggestedDir) {
|
|
|
14562
14906
|
if (suggestedDir === undefined || suggestedDir === "")
|
|
14563
14907
|
return THEMES.houston;
|
|
14564
14908
|
try {
|
|
14565
|
-
const text =
|
|
14909
|
+
const text = readFileSync16(join24(suggestedDir, "ccsidekick", "config.toml"), "utf8");
|
|
14566
14910
|
return pickTheme(loadConfig(text).theme.name);
|
|
14567
14911
|
} catch {
|
|
14568
14912
|
return THEMES.houston;
|
|
@@ -14611,7 +14955,7 @@ function App(props) {
|
|
|
14611
14955
|
const rows = props.rows ?? live.rows;
|
|
14612
14956
|
const atFloor = breakpointFor(columns, rows) === "floor";
|
|
14613
14957
|
useInput10(() => {});
|
|
14614
|
-
const home = props.homeDir ??
|
|
14958
|
+
const home = props.homeDir ?? homedir5();
|
|
14615
14959
|
const cwd = props.cwd ?? process.cwd();
|
|
14616
14960
|
const suggested = props.suggestedDir ?? env2["CLAUDE_CONFIG_DIR"];
|
|
14617
14961
|
const wordmarkHues = useMemo10(() => welcomeTheme(suggested).hues, [suggested]);
|
|
@@ -14722,12 +15066,12 @@ var init_shell = __esm(() => {
|
|
|
14722
15066
|
init_cli();
|
|
14723
15067
|
init_domain();
|
|
14724
15068
|
init_tui();
|
|
14725
|
-
import { homedir as
|
|
15069
|
+
import { homedir as homedir6 } from "node:os";
|
|
14726
15070
|
import { join as join25 } from "node:path";
|
|
14727
15071
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
14728
15072
|
var sub = process.argv[2];
|
|
14729
15073
|
function claudeDir() {
|
|
14730
|
-
return process.env["CLAUDE_CONFIG_DIR"] ?? join25(
|
|
15074
|
+
return process.env["CLAUDE_CONFIG_DIR"] ?? join25(homedir6(), ".claude");
|
|
14731
15075
|
}
|
|
14732
15076
|
function printHelp() {
|
|
14733
15077
|
process.stdout.write([
|
|
@@ -14772,7 +15116,7 @@ async function launchTui() {
|
|
|
14772
15116
|
const renderBin = fileURLToPath2(new URL("ccsidekick-render.js", import.meta.url));
|
|
14773
15117
|
const suggested = process.env["CLAUDE_CONFIG_DIR"];
|
|
14774
15118
|
const instance = render(createElement(App2, {
|
|
14775
|
-
homeDir:
|
|
15119
|
+
homeDir: homedir6(),
|
|
14776
15120
|
renderBin,
|
|
14777
15121
|
...suggested !== undefined ? { suggestedDir: suggested } : {}
|
|
14778
15122
|
}));
|
|
@@ -14805,7 +15149,7 @@ async function main() {
|
|
|
14805
15149
|
renderBin,
|
|
14806
15150
|
readConfig: defaultReadConfig,
|
|
14807
15151
|
cwd: process.cwd(),
|
|
14808
|
-
homeDir:
|
|
15152
|
+
homeDir: homedir6(),
|
|
14809
15153
|
env: process.env,
|
|
14810
15154
|
out: (s) => process.stdout.write(s),
|
|
14811
15155
|
err: (s) => process.stderr.write(s)
|