github-router 0.3.314 → 0.3.315
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/{aic-ledger-Cx_Ubon3.js → aic-ledger-BS47yb_C.js} +66 -6
- package/dist/aic-ledger-BS47yb_C.js.map +1 -0
- package/dist/{attribution-settings-Btc5EZTj.js → attribution-settings-DXmmyuEE.js} +8 -8
- package/dist/{attribution-settings-Btc5EZTj.js.map → attribution-settings-DXmmyuEE.js.map} +1 -1
- package/dist/{auth-O_UG1ABO.js → auth-D8t41c5D.js} +3 -3
- package/dist/{auth-O_UG1ABO.js.map → auth-D8t41c5D.js.map} +1 -1
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/{check-usage-dicJOWML.js → check-usage-BpBKOjGZ.js} +4 -4
- package/dist/{check-usage-dicJOWML.js.map → check-usage-BpBKOjGZ.js.map} +1 -1
- package/dist/{claude-D0vuAqTV.js → claude-Cmmu3-cL.js} +30 -24
- package/dist/claude-Cmmu3-cL.js.map +1 -0
- package/dist/{codex-BNm9D0iJ.js → codex-DqTKKoEx.js} +5 -5
- package/dist/{codex-BNm9D0iJ.js.map → codex-DqTKKoEx.js.map} +1 -1
- package/dist/copilot-discount-IbXR5A28.js +220 -0
- package/dist/copilot-discount-IbXR5A28.js.map +1 -0
- package/dist/{debug-2PgImRnr.js → debug-CA7pg8V9.js} +2 -2
- package/dist/{debug-2PgImRnr.js.map → debug-CA7pg8V9.js.map} +1 -1
- package/dist/engine-b9XaKLp0.js +2 -0
- package/dist/{exec-y8C_MU8A.js → exec-COUT4QsS.js} +2 -2
- package/dist/{exec-y8C_MU8A.js.map → exec-COUT4QsS.js.map} +1 -1
- package/dist/{gate-discovery-CO2njGBB.js → gate-discovery-CPk6Z8yc.js} +6 -6
- package/dist/{gate-discovery-CO2njGBB.js.map → gate-discovery-CPk6Z8yc.js.map} +1 -1
- package/dist/{get-copilot-usage-Cjy8TiFf.js → get-copilot-usage-FSQE8szQ.js} +2 -2
- package/dist/{get-copilot-usage-Cjy8TiFf.js.map → get-copilot-usage-FSQE8szQ.js.map} +1 -1
- package/dist/hooks.mjs +489 -28
- package/dist/hooks.sha256 +1 -1
- package/dist/internal-aic-status-BN0xRLSF.js +432 -0
- package/dist/internal-aic-status-BN0xRLSF.js.map +1 -0
- package/dist/{internal-artifact-open-CxeIfsW_.js → internal-artifact-open-B3stUu74.js} +2 -2
- package/dist/{internal-artifact-open-CxeIfsW_.js.map → internal-artifact-open-B3stUu74.js.map} +1 -1
- package/dist/{internal-fast-dispatch-guard-D8YNlnuQ.js → internal-fast-dispatch-guard-2QjUlhqO.js} +1 -1
- package/dist/{internal-fast-dispatch-guard-19xQEouu.js → internal-fast-dispatch-guard-CAwYj_Yz.js} +2 -2
- package/dist/{internal-fast-dispatch-guard-19xQEouu.js.map → internal-fast-dispatch-guard-CAwYj_Yz.js.map} +1 -1
- package/dist/{internal-first-mate-guard-BuweUgjb.js → internal-first-mate-guard-B0rbLb0L.js} +3 -3
- package/dist/{internal-first-mate-guard-BuweUgjb.js.map → internal-first-mate-guard-B0rbLb0L.js.map} +1 -1
- package/dist/{internal-first-mate-guard-Nf1H0mCK.js → internal-first-mate-guard-VgnHBp0s.js} +1 -1
- package/dist/{internal-max-dispatch-guard-_Pp4LltM.js → internal-max-dispatch-guard-BzKsY9ze.js} +1 -1
- package/dist/{internal-max-dispatch-guard-DZ7KLWxP.js → internal-max-dispatch-guard-l1NGYHtF.js} +2 -2
- package/dist/{internal-max-dispatch-guard-DZ7KLWxP.js.map → internal-max-dispatch-guard-l1NGYHtF.js.map} +1 -1
- package/dist/{internal-plan-review-DLduDz41.js → internal-plan-review-QUvNZmMR.js} +3 -3
- package/dist/{internal-plan-review-DLduDz41.js.map → internal-plan-review-QUvNZmMR.js.map} +1 -1
- package/dist/{internal-prompt-submit-DG94f8E-.js → internal-prompt-submit-fj5ccft_.js} +5 -5
- package/dist/{internal-prompt-submit-DG94f8E-.js.map → internal-prompt-submit-fj5ccft_.js.map} +1 -1
- package/dist/{internal-session-bind-D6Hpl-84.js → internal-session-bind-0Hmak8PR.js} +2 -2
- package/dist/{internal-session-bind-D6Hpl-84.js.map → internal-session-bind-0Hmak8PR.js.map} +1 -1
- package/dist/{internal-stop-hook-D56b6iVj.js → internal-stop-hook-BKiKYeda.js} +6 -6
- package/dist/{internal-stop-hook-D56b6iVj.js.map → internal-stop-hook-BKiKYeda.js.map} +1 -1
- package/dist/{internal-stop-review-DlKzZgFm.js → internal-stop-review-8v2llYDB.js} +2 -2
- package/dist/{internal-stop-review-DlKzZgFm.js.map → internal-stop-review-8v2llYDB.js.map} +1 -1
- package/dist/{internal-worker-guard-D7sfByyo.js → internal-worker-guard-BI4Pl0Ew.js} +2 -2
- package/dist/{internal-worker-guard-D7sfByyo.js.map → internal-worker-guard-BI4Pl0Ew.js.map} +1 -1
- package/dist/{internal-workspace-header-CU5OjLCB.js → internal-workspace-header-kg9FoNXK.js} +2 -2
- package/dist/{internal-workspace-header-CU5OjLCB.js.map → internal-workspace-header-kg9FoNXK.js.map} +1 -1
- package/dist/lifecycle-BpqAyaAj.js +2 -0
- package/dist/lifecycle-CL2WiyeQ.js +2 -0
- package/dist/{lifecycle-CtRA3Y7p.js → lifecycle-Cx1wVrLb.js} +3 -3
- package/dist/{lifecycle-CtRA3Y7p.js.map → lifecycle-Cx1wVrLb.js.map} +1 -1
- package/dist/{lifecycle-BCnarXJV.js → lifecycle-IwotwedG.js} +2 -2
- package/dist/{lifecycle-BCnarXJV.js.map → lifecycle-IwotwedG.js.map} +1 -1
- package/dist/main.js +20 -20
- package/dist/{mcp-workspace-header-B60WSR1Y.js → mcp-workspace-header-BYgWioLH.js} +2 -2
- package/dist/{mcp-workspace-header-B60WSR1Y.js.map → mcp-workspace-header-BYgWioLH.js.map} +1 -1
- package/dist/{models-COuMOfM6.js → models-DgLeb-Dv.js} +3 -3
- package/dist/{models-COuMOfM6.js.map → models-DgLeb-Dv.js.map} +1 -1
- package/dist/{orchestration-DjLA-lxB.js → orchestration-Dc3mO0G3.js} +3 -3
- package/dist/{orchestration-DjLA-lxB.js.map → orchestration-Dc3mO0G3.js.map} +1 -1
- package/dist/paths-BXXCVFvA.js +2 -0
- package/dist/{paths-De1Qh9Q9.js → paths-CMxlQEfQ.js} +3 -3
- package/dist/{paths-De1Qh9Q9.js.map → paths-CMxlQEfQ.js.map} +1 -1
- package/dist/{peer-mcp-personas-0_XU6nm9.js → peer-mcp-personas-CYWJSxPK.js} +11 -11
- package/dist/{peer-mcp-personas-0_XU6nm9.js.map → peer-mcp-personas-CYWJSxPK.js.map} +1 -1
- package/dist/{plan-review-hook-vL6BYmA8.js → plan-review-hook-BIMwWkh6.js} +4 -4
- package/dist/{plan-review-hook-vL6BYmA8.js.map → plan-review-hook-BIMwWkh6.js.map} +1 -1
- package/dist/{prompt-submit-hook-DfqufWC1.js → prompt-submit-hook-BcFpjHXg.js} +3 -3
- package/dist/{prompt-submit-hook-DfqufWC1.js.map → prompt-submit-hook-BcFpjHXg.js.map} +1 -1
- package/dist/{provision-DuCnZJj_.js → provision-AwSjt-vR.js} +5 -5
- package/dist/{provision-DuCnZJj_.js.map → provision-AwSjt-vR.js.map} +1 -1
- package/dist/{self-invocation-B84JCHps.js → self-invocation-cRl4RqfW.js} +2 -2
- package/dist/{self-invocation-B84JCHps.js.map → self-invocation-cRl4RqfW.js.map} +1 -1
- package/dist/{serve-DXFVR6A0.js → serve-BG2O6Slz.js} +13 -13
- package/dist/{serve-DXFVR6A0.js.map → serve-BG2O6Slz.js.map} +1 -1
- package/dist/{server-setup-CP8nGop3.js → server-setup-D7ABbEs1.js} +8 -8
- package/dist/{server-setup-CP8nGop3.js.map → server-setup-D7ABbEs1.js.map} +1 -1
- package/dist/{start-BHEjESCB.js → start-Dpwpnq99.js} +3 -3
- package/dist/{start-BHEjESCB.js.map → start-Dpwpnq99.js.map} +1 -1
- package/dist/{stop-gate-hook-BEU8qQrC.js → stop-gate-hook-BUCxa5Kc.js} +4 -4
- package/dist/{stop-gate-hook-BEU8qQrC.js.map → stop-gate-hook-BUCxa5Kc.js.map} +1 -1
- package/dist/{stop-gate-policy-qzqXfRxE.js → stop-gate-policy--bpyxxXU.js} +3 -3
- package/dist/{stop-gate-policy-qzqXfRxE.js.map → stop-gate-policy--bpyxxXU.js.map} +1 -1
- package/dist/{token-CCg-Ov5q.js → token-ClzS23Y2.js} +2 -2
- package/dist/{token-CCg-Ov5q.js.map → token-ClzS23Y2.js.map} +1 -1
- package/dist/{worker-dispatch-CH-NN5FW.js → worker-dispatch-DMIdrlsF.js} +2 -2
- package/dist/{worker-dispatch-CH-NN5FW.js.map → worker-dispatch-DMIdrlsF.js.map} +1 -1
- package/package.json +1 -1
- package/dist/aic-ledger-Cx_Ubon3.js.map +0 -1
- package/dist/claude-D0vuAqTV.js.map +0 -1
- package/dist/engine-DsVZuCrD.js +0 -2
- package/dist/internal-aic-status-C_swX3_7.js +0 -95
- package/dist/internal-aic-status-C_swX3_7.js.map +0 -1
- package/dist/lifecycle-B0USSJvd.js +0 -2
- package/dist/lifecycle-CQFjaQc0.js +0 -2
- package/dist/paths-DyX6SEnd.js +0 -2
package/dist/hooks.mjs
CHANGED
|
@@ -34642,6 +34642,35 @@ var NANO_AIU_PER_CREDIT;
|
|
|
34642
34642
|
var init_aic_usage = __esmMin((() => {
|
|
34643
34643
|
NANO_AIU_PER_CREDIT = 1e9;
|
|
34644
34644
|
}));
|
|
34645
|
+
//#endregion
|
|
34646
|
+
//#region src/lib/aic-ledger.ts
|
|
34647
|
+
/**
|
|
34648
|
+
* Per-launch AIC (AI Credits) ledger.
|
|
34649
|
+
*
|
|
34650
|
+
* Every route handler records upstream `copilot_usage` here as a side effect
|
|
34651
|
+
* (bytes pass through untouched). The totals feed two consumers:
|
|
34652
|
+
*
|
|
34653
|
+
* 1. `internal-aic-status` — runs as a SEPARATE process on every status-line
|
|
34654
|
+
* tick, so it cannot read in-process memory. Each `record()` therefore
|
|
34655
|
+
* also persists an atomic snapshot file; the ledger path is handed to the
|
|
34656
|
+
* spawned child via `GH_ROUTER_AIC_LEDGER` and baked into the statusLine
|
|
34657
|
+
* command.
|
|
34658
|
+
* 2. The `claude` exit summary — reads the in-process snapshot.
|
|
34659
|
+
*
|
|
34660
|
+
* Keyed per proxy process (one file per PID under `<APP_DIR>/aic-ledger/`),
|
|
34661
|
+
* so concurrent launches never mix. Snapshot writes are best-effort and never
|
|
34662
|
+
* throw into the request path. Stale files (dead PID, >24h) are swept at
|
|
34663
|
+
* startup of the next record and on shutdown.
|
|
34664
|
+
*/
|
|
34665
|
+
function emptyModelTokens() {
|
|
34666
|
+
return {
|
|
34667
|
+
input: 0,
|
|
34668
|
+
cache_read: 0,
|
|
34669
|
+
cache_write: 0,
|
|
34670
|
+
output: 0,
|
|
34671
|
+
other: 0
|
|
34672
|
+
};
|
|
34673
|
+
}
|
|
34645
34674
|
/**
|
|
34646
34675
|
* Read a persisted snapshot file (the status-hook path). Returns undefined
|
|
34647
34676
|
* when missing/unreadable — the hook then prints nothing.
|
|
@@ -34657,12 +34686,41 @@ function readAicSnapshotFile(file) {
|
|
|
34657
34686
|
totalNanoAiu: Math.max(0, Math.floor(record.totalNanoAiu)),
|
|
34658
34687
|
requests: Math.max(0, Math.floor(record.requests)),
|
|
34659
34688
|
perModel: record.perModel && typeof record.perModel === "object" ? record.perModel : {},
|
|
34660
|
-
perTokenType: record.perTokenType && typeof record.perTokenType === "object" ? record.perTokenType : {}
|
|
34689
|
+
perTokenType: record.perTokenType && typeof record.perTokenType === "object" ? record.perTokenType : {},
|
|
34690
|
+
tokensByModel: sanitizeModelTokens(record.tokensByModel)
|
|
34661
34691
|
};
|
|
34662
34692
|
} catch {
|
|
34663
34693
|
return;
|
|
34664
34694
|
}
|
|
34665
34695
|
}
|
|
34696
|
+
/** Best-effort sanitize of persisted per-model token counts; `{}` when absent. */
|
|
34697
|
+
function sanitizeModelTokens(value) {
|
|
34698
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
34699
|
+
const out = {};
|
|
34700
|
+
for (const [model, counts] of Object.entries(value)) {
|
|
34701
|
+
if (!counts || typeof counts !== "object" || Array.isArray(counts)) continue;
|
|
34702
|
+
const entry = counts;
|
|
34703
|
+
const clean = emptyModelTokens();
|
|
34704
|
+
let ok = true;
|
|
34705
|
+
for (const field of [
|
|
34706
|
+
"input",
|
|
34707
|
+
"cache_read",
|
|
34708
|
+
"cache_write",
|
|
34709
|
+
"output",
|
|
34710
|
+
"other"
|
|
34711
|
+
]) {
|
|
34712
|
+
const n = entry[field];
|
|
34713
|
+
if (n === void 0) continue;
|
|
34714
|
+
if (typeof n !== "number" || !Number.isFinite(n) || n < 0) {
|
|
34715
|
+
ok = false;
|
|
34716
|
+
break;
|
|
34717
|
+
}
|
|
34718
|
+
clean[field] = Math.floor(n);
|
|
34719
|
+
}
|
|
34720
|
+
if (ok) out[model] = clean;
|
|
34721
|
+
}
|
|
34722
|
+
return out;
|
|
34723
|
+
}
|
|
34666
34724
|
/** Total credits for a snapshot. */
|
|
34667
34725
|
function aicTotalCredits(snapshot) {
|
|
34668
34726
|
return nanoAiuToCredits(snapshot.totalNanoAiu);
|
|
@@ -34968,7 +35026,7 @@ var internal_stop_hook_exports = /* @__PURE__ */ __exportAll({
|
|
|
34968
35026
|
* no such handle. Hooks always receive piped/redirected stdin, so this never
|
|
34969
35027
|
* blocks (guarded against an interactive TTY, and any error -> "").
|
|
34970
35028
|
*/
|
|
34971
|
-
function readStdin$
|
|
35029
|
+
function readStdin$6() {
|
|
34972
35030
|
try {
|
|
34973
35031
|
if (process.stdin.isTTY) return "";
|
|
34974
35032
|
return readFileSync(0, "utf8");
|
|
@@ -35155,7 +35213,7 @@ var init_internal_stop_hook = __esmMin((() => {
|
|
|
35155
35213
|
description: "Internal: the structural-gate Stop hook. Reads the Claude Code hook payload on stdin, runs the sealed gate, exits 2 (blocks the stop) on a red gate or gate-weakening diff."
|
|
35156
35214
|
},
|
|
35157
35215
|
async run() {
|
|
35158
|
-
const stdin = readStdin$
|
|
35216
|
+
const stdin = readStdin$6();
|
|
35159
35217
|
const reviewEnabled = stopReviewEnabled() && hookMcpRuntimeFromEnv() !== void 0;
|
|
35160
35218
|
let transcriptPath = "";
|
|
35161
35219
|
let userPrompt = "";
|
|
@@ -35323,7 +35381,7 @@ var internal_prompt_submit_exports = /* @__PURE__ */ __exportAll({ internalPromp
|
|
|
35323
35381
|
* no such handle. Hooks always receive piped/redirected stdin, so this never
|
|
35324
35382
|
* blocks (guarded against an interactive TTY, and any error -> "").
|
|
35325
35383
|
*/
|
|
35326
|
-
function readStdin$
|
|
35384
|
+
function readStdin$5() {
|
|
35327
35385
|
try {
|
|
35328
35386
|
if (process.stdin.isTTY) return "";
|
|
35329
35387
|
return readFileSync(0, "utf8");
|
|
@@ -35360,7 +35418,7 @@ var init_internal_prompt_submit = __esmMin((() => {
|
|
|
35360
35418
|
},
|
|
35361
35419
|
async run() {
|
|
35362
35420
|
try {
|
|
35363
|
-
const stdin = readStdin$
|
|
35421
|
+
const stdin = readStdin$5();
|
|
35364
35422
|
const steerEnabled = parseBoolEnv(process.env.GH_ROUTER_DISABLE_PROMPT_STEER) !== true;
|
|
35365
35423
|
const runtime = hookMcpRuntimeFromEnv();
|
|
35366
35424
|
let decision;
|
|
@@ -35655,7 +35713,7 @@ var init_plan_review_hook = __esmMin((() => {
|
|
|
35655
35713
|
//#endregion
|
|
35656
35714
|
//#region src/internal-plan-review.ts
|
|
35657
35715
|
var internal_plan_review_exports = /* @__PURE__ */ __exportAll({ internalPlanReview: () => internalPlanReview });
|
|
35658
|
-
function readStdin$
|
|
35716
|
+
function readStdin$4() {
|
|
35659
35717
|
try {
|
|
35660
35718
|
if (process.stdin.isTTY) return "";
|
|
35661
35719
|
return readFileSync(0, "utf8");
|
|
@@ -35748,7 +35806,7 @@ var init_internal_plan_review = __esmMin((() => {
|
|
|
35748
35806
|
return;
|
|
35749
35807
|
}
|
|
35750
35808
|
const decision = await decidePlanReviewHook({
|
|
35751
|
-
stdin: readStdin$
|
|
35809
|
+
stdin: readStdin$4(),
|
|
35752
35810
|
runtimeAvailable: true,
|
|
35753
35811
|
debounce: filePlanReviewDebounce(stopReviewStateDir()),
|
|
35754
35812
|
fallbackCwd: process.cwd()
|
|
@@ -35771,7 +35829,7 @@ var internal_session_bind_exports = /* @__PURE__ */ __exportAll({
|
|
|
35771
35829
|
* teardown and trips a `uv_async_send` assertion; a synchronous read has no such
|
|
35772
35830
|
* handle. Hooks always receive piped stdin (guarded against a TTY; any error -> "").
|
|
35773
35831
|
*/
|
|
35774
|
-
function readStdin$
|
|
35832
|
+
function readStdin$3() {
|
|
35775
35833
|
try {
|
|
35776
35834
|
if (process.stdin.isTTY) return "";
|
|
35777
35835
|
return readFileSync(0, "utf8");
|
|
@@ -35865,7 +35923,7 @@ var init_internal_session_bind = __esmMin((() => {
|
|
|
35865
35923
|
try {
|
|
35866
35924
|
const out = typeof args.out === "string" ? args.out.trim() : "";
|
|
35867
35925
|
if (!out) return;
|
|
35868
|
-
const record = decodeSessionBind(readStdin$
|
|
35926
|
+
const record = decodeSessionBind(readStdin$3());
|
|
35869
35927
|
if (record) writeSidecar(out, record);
|
|
35870
35928
|
} catch {}
|
|
35871
35929
|
process.exitCode = 0;
|
|
@@ -37678,7 +37736,7 @@ var internal_artifact_open_exports = /* @__PURE__ */ __exportAll({
|
|
|
37678
37736
|
internalArtifactOpen: () => internalArtifactOpen,
|
|
37679
37737
|
parseExitPlanPayload: () => parseExitPlanPayload
|
|
37680
37738
|
});
|
|
37681
|
-
function readStdin$
|
|
37739
|
+
function readStdin$2() {
|
|
37682
37740
|
try {
|
|
37683
37741
|
if (process.stdin.isTTY) return "";
|
|
37684
37742
|
return readFileSync(0, "utf8");
|
|
@@ -37778,7 +37836,7 @@ var init_internal_artifact_open = __esmMin((() => {
|
|
|
37778
37836
|
},
|
|
37779
37837
|
async run() {
|
|
37780
37838
|
try {
|
|
37781
|
-
const raw = readStdin$
|
|
37839
|
+
const raw = readStdin$2();
|
|
37782
37840
|
let payload;
|
|
37783
37841
|
try {
|
|
37784
37842
|
payload = JSON.parse(raw);
|
|
@@ -37997,7 +38055,7 @@ var internal_worker_guard_exports = /* @__PURE__ */ __exportAll({ internalWorker
|
|
|
37997
38055
|
* libuv FS request that races Windows process teardown. Hooks always receive
|
|
37998
38056
|
* piped stdin (guarded against an interactive TTY; any error → "").
|
|
37999
38057
|
*/
|
|
38000
|
-
function readStdin() {
|
|
38058
|
+
function readStdin$1() {
|
|
38001
38059
|
try {
|
|
38002
38060
|
if (process.stdin.isTTY) return "";
|
|
38003
38061
|
return readFileSync(0, "utf8");
|
|
@@ -38028,7 +38086,7 @@ var init_internal_worker_guard = __esmMin((() => {
|
|
|
38028
38086
|
},
|
|
38029
38087
|
run(ctx) {
|
|
38030
38088
|
try {
|
|
38031
|
-
const stdin = readStdin();
|
|
38089
|
+
const stdin = readStdin$1();
|
|
38032
38090
|
const workersKey = String(ctx.args["workers-key"] ?? "").trim();
|
|
38033
38091
|
if (workersKey.length > 0) {
|
|
38034
38092
|
const { output } = decideWorkerGuard({
|
|
@@ -38485,6 +38543,388 @@ var init_internal_max_dispatch_guard = __esmMin((() => {
|
|
|
38485
38543
|
});
|
|
38486
38544
|
}));
|
|
38487
38545
|
//#endregion
|
|
38546
|
+
//#region src/lib/copilot-discount.ts
|
|
38547
|
+
function row(factor, source) {
|
|
38548
|
+
return {
|
|
38549
|
+
factor,
|
|
38550
|
+
source
|
|
38551
|
+
};
|
|
38552
|
+
}
|
|
38553
|
+
/**
|
|
38554
|
+
* Clamp a factor to usable range. Non-finite or negative factors (corrupt
|
|
38555
|
+
* table edit, bad injection) degrade to 1.0 — unfactored but never NaN,
|
|
38556
|
+
* never negative on screen.
|
|
38557
|
+
*/
|
|
38558
|
+
function sanitizeFactor(raw) {
|
|
38559
|
+
return typeof raw === "number" && Number.isFinite(raw) && raw >= 0 ? raw : 1;
|
|
38560
|
+
}
|
|
38561
|
+
/**
|
|
38562
|
+
* Session discounted USD from a ledger snapshot. Total function: never
|
|
38563
|
+
* throws (guards non-finite/negative ledger values defensively — a corrupt
|
|
38564
|
+
* snapshot must degrade the status line, not crash the hook).
|
|
38565
|
+
*/
|
|
38566
|
+
function discountedUsdForSnapshot(snapshot) {
|
|
38567
|
+
return discountedUsdWithFactors(snapshot, DISCOUNT_FACTORS);
|
|
38568
|
+
}
|
|
38569
|
+
/**
|
|
38570
|
+
* Factor-injectable core (exported for unit tests — e.g. proving a
|
|
38571
|
+
* fat-finger factor can never overstate spend). `factors` falls back to
|
|
38572
|
+
* 1.0 per model exactly like the table lookup.
|
|
38573
|
+
*/
|
|
38574
|
+
function discountedUsdWithFactors(snapshot, factors) {
|
|
38575
|
+
const byModel = {};
|
|
38576
|
+
let sum = 0;
|
|
38577
|
+
for (const [model, entry] of Object.entries(snapshot.perModel)) {
|
|
38578
|
+
const nano = typeof entry.nanoAiu === "number" && Number.isFinite(entry.nanoAiu) ? Math.max(0, entry.nanoAiu) : 0;
|
|
38579
|
+
const factor = sanitizeFactor(factors[model]?.factor);
|
|
38580
|
+
const usd = nano / 1e9 * USD_PER_AIC_CREDIT * factor;
|
|
38581
|
+
byModel[model] = usd;
|
|
38582
|
+
sum += usd;
|
|
38583
|
+
}
|
|
38584
|
+
const cap = aicTotalCredits(snapshot) * USD_PER_AIC_CREDIT;
|
|
38585
|
+
if (!(sum > cap * (1 + 1e-9)) || sum <= 0) return {
|
|
38586
|
+
total: sum,
|
|
38587
|
+
byModel,
|
|
38588
|
+
capped: false
|
|
38589
|
+
};
|
|
38590
|
+
const scale = cap / sum;
|
|
38591
|
+
const scaled = {};
|
|
38592
|
+
for (const [model, usd] of Object.entries(byModel)) scaled[model] = usd * scale;
|
|
38593
|
+
return {
|
|
38594
|
+
total: cap,
|
|
38595
|
+
byModel: scaled,
|
|
38596
|
+
capped: true
|
|
38597
|
+
};
|
|
38598
|
+
}
|
|
38599
|
+
var USD_PER_AIC_CREDIT, DISCOUNT_FACTORS;
|
|
38600
|
+
var init_copilot_discount = __esmMin((() => {
|
|
38601
|
+
init_aic_ledger();
|
|
38602
|
+
USD_PER_AIC_CREDIT = .01;
|
|
38603
|
+
DISCOUNT_FACTORS = Object.freeze({
|
|
38604
|
+
"gpt-5.6-sol": row(.28, "0.27-0.29 across 28d/MTD/7d/pre/9-9; write-mix refuted"),
|
|
38605
|
+
"claude-opus-5": row(.62, "0.61-0.64 across windows; 9/7 1.02 excluded as single-day artifact"),
|
|
38606
|
+
"claude-sonnet-5": row(.66, "0.62-0.71 across windows"),
|
|
38607
|
+
"gpt-5.3-codex": row(.6, "0.59-0.62 across windows"),
|
|
38608
|
+
"gpt-5.4": row(.6, "single snapshot 0.598"),
|
|
38609
|
+
"gemini-3.7-flash": row(.29, "September regime; pre-Sep 1.00x — volatile"),
|
|
38610
|
+
"gpt-5.6-luna": row(1, "long-tier portal + writes, no discount"),
|
|
38611
|
+
"grok-4.6": row(1, "portal default, six windows"),
|
|
38612
|
+
"gemini-3.8-flash": row(1, "portal exact, six windows to the dollar")
|
|
38613
|
+
});
|
|
38614
|
+
}));
|
|
38615
|
+
//#endregion
|
|
38616
|
+
//#region src/lib/default-statusline.ts
|
|
38617
|
+
/**
|
|
38618
|
+
* Rich default status line for `github-router claude` sessions.
|
|
38619
|
+
*
|
|
38620
|
+
* Replaces the need for users to maintain their own PowerShell/bash status
|
|
38621
|
+
* script: `internal-aic-status` renders these segments natively from the
|
|
38622
|
+
* Claude Code stdin JSON, then pins the `[AIC x.xx]` ledger fragment ahead
|
|
38623
|
+
* of them. Zero dependencies, cross-platform (Windows 11 is the primary
|
|
38624
|
+
* target — no `powershell`/`bash`/`jq` required), and fast (no shell
|
|
38625
|
+
* startup; one bounded `git rev-parse` at most).
|
|
38626
|
+
*
|
|
38627
|
+
* Segment order (left = highest priority; narrow terminals drop from the
|
|
38628
|
+
* right, `AIC` is never dropped):
|
|
38629
|
+
*
|
|
38630
|
+
* `[AIC] | [ctx bar] % | model | dir (branch) | ~$actual | in/out | dur | +a -r`
|
|
38631
|
+
*
|
|
38632
|
+
* The `$` segment is the DISCOUNTED actual (`~$` = factor-discounted
|
|
38633
|
+
* session total from `copilot-discount.ts`, capped at AIC × $0.01) — NOT
|
|
38634
|
+
* Claude's `cost.total_cost_usd`, which prices at Anthropic list rates and
|
|
38635
|
+
* reads ~10-100x high against Copilot billing (a 28-day sample: 41.1B tokens
|
|
38636
|
+
* for $5,142 ≈ $0.13/1M blended vs $15-75/1M list). Rendering list price
|
|
38637
|
+
* next to the real `[AIC]` billing unit would show two contradictory
|
|
38638
|
+
* numbers, so list price is deliberately not rendered at all.
|
|
38639
|
+
*
|
|
38640
|
+
* Width comes from `COLUMNS` (set by Claude Code for status scripts since
|
|
38641
|
+
* v2.1.153); fallback is 120 when unset/unparseable so a missing `COLUMNS`
|
|
38642
|
+
* never needlessly drops segments.
|
|
38643
|
+
*/
|
|
38644
|
+
function asRecord(value) {
|
|
38645
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
38646
|
+
return value;
|
|
38647
|
+
}
|
|
38648
|
+
function finiteNumber(value) {
|
|
38649
|
+
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
38650
|
+
}
|
|
38651
|
+
function nonEmptyString(value) {
|
|
38652
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
38653
|
+
}
|
|
38654
|
+
/**
|
|
38655
|
+
* Parse Claude Code's status-line stdin JSON into the fields we render.
|
|
38656
|
+
* Total function: malformed JSON or unexpected shapes yield `{}` (every
|
|
38657
|
+
* segment then renders its `--` placeholder or is omitted) — never throws.
|
|
38658
|
+
*/
|
|
38659
|
+
function parseStatusInput(raw) {
|
|
38660
|
+
if (!raw.trim()) return {};
|
|
38661
|
+
let parsed;
|
|
38662
|
+
try {
|
|
38663
|
+
parsed = JSON.parse(raw);
|
|
38664
|
+
} catch {
|
|
38665
|
+
return {};
|
|
38666
|
+
}
|
|
38667
|
+
const root = asRecord(parsed);
|
|
38668
|
+
if (!root) return {};
|
|
38669
|
+
const out = {};
|
|
38670
|
+
const ctx = asRecord(root.context_window);
|
|
38671
|
+
if (ctx) {
|
|
38672
|
+
const pct = finiteNumber(ctx.used_percentage);
|
|
38673
|
+
if (pct !== void 0) out.usedPct = pct;
|
|
38674
|
+
const tIn = finiteNumber(ctx.total_input_tokens);
|
|
38675
|
+
if (tIn !== void 0 && tIn >= 0) out.totalInputTokens = Math.floor(tIn);
|
|
38676
|
+
const tOut = finiteNumber(ctx.total_output_tokens);
|
|
38677
|
+
if (tOut !== void 0 && tOut >= 0) out.totalOutputTokens = Math.floor(tOut);
|
|
38678
|
+
}
|
|
38679
|
+
const cost = asRecord(root.cost);
|
|
38680
|
+
if (cost) {
|
|
38681
|
+
const dur = finiteNumber(cost.total_duration_ms);
|
|
38682
|
+
if (dur !== void 0 && dur >= 0) out.totalDurationMs = dur;
|
|
38683
|
+
const la = finiteNumber(cost.total_lines_added);
|
|
38684
|
+
if (la !== void 0 && la >= 0) out.linesAdded = Math.floor(la);
|
|
38685
|
+
const lr = finiteNumber(cost.total_lines_removed);
|
|
38686
|
+
if (lr !== void 0 && lr >= 0) out.linesRemoved = Math.floor(lr);
|
|
38687
|
+
}
|
|
38688
|
+
const workspace = asRecord(root.workspace);
|
|
38689
|
+
const cwd = (workspace ? nonEmptyString(workspace.current_dir) : void 0) ?? nonEmptyString(root.cwd);
|
|
38690
|
+
if (cwd) out.cwd = cwd;
|
|
38691
|
+
const model = asRecord(root.model);
|
|
38692
|
+
if (model) {
|
|
38693
|
+
const name = nonEmptyString(model.display_name) ?? nonEmptyString(model.id);
|
|
38694
|
+
if (name) out.modelName = name;
|
|
38695
|
+
}
|
|
38696
|
+
return out;
|
|
38697
|
+
}
|
|
38698
|
+
/** Compact token count: `999` → `999`, `15234` → `15.2k`, `2.1M`. */
|
|
38699
|
+
function compactTokens(n) {
|
|
38700
|
+
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
38701
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}k`;
|
|
38702
|
+
return `${n}`;
|
|
38703
|
+
}
|
|
38704
|
+
/** `45000` → `0m45s`, `198000` → `3m18s`, `3720000` → `1h02m`. */
|
|
38705
|
+
function formatDurationMs(ms) {
|
|
38706
|
+
const totalSeconds = Math.floor(ms / 1e3);
|
|
38707
|
+
const hours = Math.floor(totalSeconds / 3600);
|
|
38708
|
+
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
38709
|
+
const seconds = totalSeconds % 60;
|
|
38710
|
+
if (hours >= 1) return `${hours}h${String(minutes).padStart(2, "0")}m`;
|
|
38711
|
+
return `${minutes}m${String(seconds).padStart(2, "0")}s`;
|
|
38712
|
+
}
|
|
38713
|
+
/** Basename of a cwd, tolerant of `/` and `\` separators + trailing slash. */
|
|
38714
|
+
function dirLeaf(cwd) {
|
|
38715
|
+
const trimmed = cwd.replace(/[/\\]+$/, "");
|
|
38716
|
+
const parts = trimmed.split(/[/\\]/);
|
|
38717
|
+
return parts[parts.length - 1] ?? trimmed;
|
|
38718
|
+
}
|
|
38719
|
+
function buildCtxSegment(usedPct) {
|
|
38720
|
+
if (usedPct === void 0 || !Number.isFinite(usedPct)) return {
|
|
38721
|
+
text: `${DIM}[----------] --%${RESET}`,
|
|
38722
|
+
plain: "[----------] --%"
|
|
38723
|
+
};
|
|
38724
|
+
const u = Math.max(0, Math.min(100, Math.round(usedPct)));
|
|
38725
|
+
let filled = Math.round(u / 100 * CTX_BAR_LEN);
|
|
38726
|
+
if (filled > CTX_BAR_LEN) filled = CTX_BAR_LEN;
|
|
38727
|
+
if (filled < 0) filled = 0;
|
|
38728
|
+
const bar = `#`.repeat(filled) + `-`.repeat(CTX_BAR_LEN - filled);
|
|
38729
|
+
return {
|
|
38730
|
+
text: `${u < 50 ? GREEN : u < 75 ? YELLOW : RED}[${bar}] ${u}%${RESET}`,
|
|
38731
|
+
plain: `[${bar}] ${u}%`
|
|
38732
|
+
};
|
|
38733
|
+
}
|
|
38734
|
+
/**
|
|
38735
|
+
* Discounted-actual `$` segment. Callers pass the capped total from
|
|
38736
|
+
* `discountedUsdForSnapshot` — this function only formats. Placeholder
|
|
38737
|
+
* `~$--` until the first priced upstream response lands in the ledger.
|
|
38738
|
+
* Thresholds are tuned for ACTUALS scale (a session runs ~$0.10-2.00) —
|
|
38739
|
+
* not the old list-price scale.
|
|
38740
|
+
*/
|
|
38741
|
+
function buildUsdSegment(actualUsd) {
|
|
38742
|
+
if (actualUsd === void 0 || !Number.isFinite(actualUsd) || actualUsd < 0) return {
|
|
38743
|
+
text: `${DIM}~$--${RESET}`,
|
|
38744
|
+
plain: "~$--"
|
|
38745
|
+
};
|
|
38746
|
+
const c = actualUsd;
|
|
38747
|
+
const color = c < 1 ? GREEN : c < 5 ? YELLOW : c < 20 ? ORANGE : RED;
|
|
38748
|
+
const formatted = c < 10 ? c.toFixed(2) : c.toFixed(1);
|
|
38749
|
+
return {
|
|
38750
|
+
text: `${color}~$${formatted}${RESET}`,
|
|
38751
|
+
plain: `~$${formatted}`
|
|
38752
|
+
};
|
|
38753
|
+
}
|
|
38754
|
+
function buildToksSegment(tIn, tOut) {
|
|
38755
|
+
if (tIn === void 0 || tOut === void 0) return {
|
|
38756
|
+
text: `${DIM}--/--${RESET}`,
|
|
38757
|
+
plain: "--/--"
|
|
38758
|
+
};
|
|
38759
|
+
const cin = compactTokens(tIn);
|
|
38760
|
+
const cout = compactTokens(tOut);
|
|
38761
|
+
return {
|
|
38762
|
+
text: `${CYAN}${cin}${RESET}${DIM}/${RESET}${MAGENTA}${cout}${RESET}`,
|
|
38763
|
+
plain: `${cin}/${cout}`
|
|
38764
|
+
};
|
|
38765
|
+
}
|
|
38766
|
+
function buildDurSegment(durMs) {
|
|
38767
|
+
if (durMs === void 0 || !Number.isFinite(durMs) || durMs < 0) return {
|
|
38768
|
+
text: `${DIM}--${RESET}`,
|
|
38769
|
+
plain: "--"
|
|
38770
|
+
};
|
|
38771
|
+
const formatted = formatDurationMs(durMs);
|
|
38772
|
+
return {
|
|
38773
|
+
text: `${DIM}${formatted}${RESET}`,
|
|
38774
|
+
plain: formatted
|
|
38775
|
+
};
|
|
38776
|
+
}
|
|
38777
|
+
function buildLinesSegment(added, removed) {
|
|
38778
|
+
const a = added ?? 0;
|
|
38779
|
+
const r = removed ?? 0;
|
|
38780
|
+
return {
|
|
38781
|
+
text: `${GREEN}+${a}${RESET} ${RED}-${r}${RESET}`,
|
|
38782
|
+
plain: `+${a} -${r}`
|
|
38783
|
+
};
|
|
38784
|
+
}
|
|
38785
|
+
function buildModelSegment(modelName) {
|
|
38786
|
+
if (!modelName || modelName === "--") return void 0;
|
|
38787
|
+
return {
|
|
38788
|
+
text: `${MAGENTA}${modelName}${RESET}`,
|
|
38789
|
+
plain: modelName
|
|
38790
|
+
};
|
|
38791
|
+
}
|
|
38792
|
+
function buildDirGitSegment(cwd, branch) {
|
|
38793
|
+
const leaf = cwd ? dirLeaf(cwd) : "";
|
|
38794
|
+
const br = branch && branch !== "HEAD" ? branch : "";
|
|
38795
|
+
if (!leaf && !br) return void 0;
|
|
38796
|
+
if (leaf && br) return {
|
|
38797
|
+
text: `${BLUE}${leaf}${RESET} ${CYAN}(${br})${RESET}`,
|
|
38798
|
+
plain: `${leaf} (${br})`
|
|
38799
|
+
};
|
|
38800
|
+
if (leaf) return {
|
|
38801
|
+
text: `${BLUE}${leaf}${RESET}`,
|
|
38802
|
+
plain: leaf
|
|
38803
|
+
};
|
|
38804
|
+
return {
|
|
38805
|
+
text: `${CYAN}${br}${RESET}`,
|
|
38806
|
+
plain: br
|
|
38807
|
+
};
|
|
38808
|
+
}
|
|
38809
|
+
/**
|
|
38810
|
+
* Resolve the current git branch for `cwd`. Bounded (`GIT_TIMEOUT_MS`) and
|
|
38811
|
+
* total: any failure (no git binary, not a repo, detached `HEAD`, timeout,
|
|
38812
|
+
* `%` in a Windows path that cmd.exe cannot safely quote) yields `""`
|
|
38813
|
+
* (caller omits the branch) — never throws.
|
|
38814
|
+
*/
|
|
38815
|
+
function resolveGitBranch(cwd) {
|
|
38816
|
+
try {
|
|
38817
|
+
if (!cwd) return "";
|
|
38818
|
+
const gitPath = resolveExecutable("git");
|
|
38819
|
+
if (!gitPath) return "";
|
|
38820
|
+
const { command, args, shell } = buildExecInvocation([
|
|
38821
|
+
gitPath,
|
|
38822
|
+
"-C",
|
|
38823
|
+
cwd,
|
|
38824
|
+
"rev-parse",
|
|
38825
|
+
"--abbrev-ref",
|
|
38826
|
+
"HEAD"
|
|
38827
|
+
]);
|
|
38828
|
+
const result = spawnSync(command, args, {
|
|
38829
|
+
shell,
|
|
38830
|
+
timeout: GIT_TIMEOUT_MS,
|
|
38831
|
+
encoding: "utf8",
|
|
38832
|
+
stdio: [
|
|
38833
|
+
"ignore",
|
|
38834
|
+
"pipe",
|
|
38835
|
+
"ignore"
|
|
38836
|
+
]
|
|
38837
|
+
});
|
|
38838
|
+
if (result.error) return "";
|
|
38839
|
+
const out = typeof result.stdout === "string" ? result.stdout.trim() : "";
|
|
38840
|
+
if (!out || out === "HEAD") return "";
|
|
38841
|
+
return out.split("\n")[0]?.trim() ?? "";
|
|
38842
|
+
} catch {
|
|
38843
|
+
return "";
|
|
38844
|
+
}
|
|
38845
|
+
}
|
|
38846
|
+
/** Terminal width for the drop-right-to-left assembly. */
|
|
38847
|
+
function terminalWidth(env = process.env) {
|
|
38848
|
+
const raw = env.COLUMNS;
|
|
38849
|
+
if (raw !== void 0) {
|
|
38850
|
+
const n = Number(raw);
|
|
38851
|
+
if (Number.isInteger(n) && n > 0) return n;
|
|
38852
|
+
}
|
|
38853
|
+
return WIDTH_FALLBACK;
|
|
38854
|
+
}
|
|
38855
|
+
/**
|
|
38856
|
+
* Assemble the full status line. `aicFragment` (e.g. `[AIC 12.42]`) is
|
|
38857
|
+
* PINNED — it renders even when nothing else fits. `actualUsd` feeds the
|
|
38858
|
+
* `~$` segment (the capped factor-discounted total from
|
|
38859
|
+
* `discountedUsdForSnapshot`, same snapshot the fragment came from).
|
|
38860
|
+
* Droppable segments in priority order: ctx, model, dir/git, ~$, toks,
|
|
38861
|
+
* dur, lines.
|
|
38862
|
+
*/
|
|
38863
|
+
function assembleStatusLine(aicFragment, input, opts = {}) {
|
|
38864
|
+
const aic = aicFragment.trim();
|
|
38865
|
+
const aicText = aic ? `${AIC_COLOR}${aic}${RESET}` : "";
|
|
38866
|
+
const droppable = [buildCtxSegment(input.usedPct)];
|
|
38867
|
+
const model = buildModelSegment(input.modelName);
|
|
38868
|
+
if (model) droppable.push(model);
|
|
38869
|
+
const dirGit = buildDirGitSegment(input.cwd, opts.branch);
|
|
38870
|
+
if (dirGit) droppable.push(dirGit);
|
|
38871
|
+
droppable.push(buildUsdSegment(opts.actualUsd), buildToksSegment(input.totalInputTokens, input.totalOutputTokens), buildDurSegment(input.totalDurationMs), buildLinesSegment(input.linesAdded, input.linesRemoved));
|
|
38872
|
+
const width = opts.width ?? terminalWidth();
|
|
38873
|
+
const sepLen = 3;
|
|
38874
|
+
let count = droppable.length;
|
|
38875
|
+
while (count > 0) {
|
|
38876
|
+
let total = aic ? aic.length : 0;
|
|
38877
|
+
for (let i = 0; i < count; i++) {
|
|
38878
|
+
if (aic || i > 0) total += sepLen;
|
|
38879
|
+
total += droppable[i].plain.length;
|
|
38880
|
+
}
|
|
38881
|
+
if (total <= width) break;
|
|
38882
|
+
if (count === 1 && !aic) break;
|
|
38883
|
+
count--;
|
|
38884
|
+
}
|
|
38885
|
+
const parts = [];
|
|
38886
|
+
if (aic) parts.push(aicText);
|
|
38887
|
+
for (let i = 0; i < count; i++) parts.push(droppable[i].text);
|
|
38888
|
+
if (parts.length === 0) return "";
|
|
38889
|
+
return parts.join(SEP_TEXT);
|
|
38890
|
+
}
|
|
38891
|
+
/**
|
|
38892
|
+
* Convenience: parse stdin JSON + assemble with branch resolution.
|
|
38893
|
+
* `branchOverride` skips the `git` spawn (used by tests). `actualUsd`
|
|
38894
|
+
* comes from `discountedUsdForSnapshot` on the same ledger snapshot as
|
|
38895
|
+
* `aicFragment` (read by the caller — this module never touches the
|
|
38896
|
+
* ledger file).
|
|
38897
|
+
*/
|
|
38898
|
+
function buildRichStatusLine(stdinRaw, aicFragment, opts = {}) {
|
|
38899
|
+
const input = parseStatusInput(stdinRaw);
|
|
38900
|
+
const branch = opts.branchOverride !== void 0 ? opts.branchOverride : resolveGitBranch(input.cwd);
|
|
38901
|
+
return assembleStatusLine(aicFragment, input, {
|
|
38902
|
+
...opts.width !== void 0 ? { width: opts.width } : {},
|
|
38903
|
+
...branch ? { branch } : {},
|
|
38904
|
+
...opts.actualUsd !== void 0 ? { actualUsd: opts.actualUsd } : {}
|
|
38905
|
+
});
|
|
38906
|
+
}
|
|
38907
|
+
var ESC, RESET, DIM, GREEN, YELLOW, RED, ORANGE, CYAN, MAGENTA, BLUE, AIC_COLOR, CTX_BAR_LEN, GIT_TIMEOUT_MS, WIDTH_FALLBACK, SEP_TEXT;
|
|
38908
|
+
var init_default_statusline = __esmMin((() => {
|
|
38909
|
+
init_copilot_discount();
|
|
38910
|
+
init_exec();
|
|
38911
|
+
ESC = "\x1B";
|
|
38912
|
+
RESET = `${ESC}[0m`;
|
|
38913
|
+
DIM = `${ESC}[90m`;
|
|
38914
|
+
GREEN = `${ESC}[32m`;
|
|
38915
|
+
YELLOW = `${ESC}[33m`;
|
|
38916
|
+
RED = `${ESC}[31m`;
|
|
38917
|
+
ORANGE = `${ESC}[38;5;208m`;
|
|
38918
|
+
CYAN = `${ESC}[36m`;
|
|
38919
|
+
MAGENTA = `${ESC}[35m`;
|
|
38920
|
+
BLUE = `${ESC}[34m`;
|
|
38921
|
+
AIC_COLOR = `${ESC}[1;33m`;
|
|
38922
|
+
CTX_BAR_LEN = 10;
|
|
38923
|
+
GIT_TIMEOUT_MS = 300;
|
|
38924
|
+
WIDTH_FALLBACK = 120;
|
|
38925
|
+
SEP_TEXT = `${DIM} | ${RESET}`;
|
|
38926
|
+
}));
|
|
38927
|
+
//#endregion
|
|
38488
38928
|
//#region src/internal-aic-status.ts
|
|
38489
38929
|
var internal_aic_status_exports = /* @__PURE__ */ __exportAll({
|
|
38490
38930
|
composeAicStatusLine: () => composeAicStatusLine,
|
|
@@ -38492,14 +38932,18 @@ var internal_aic_status_exports = /* @__PURE__ */ __exportAll({
|
|
|
38492
38932
|
runUserStatusLine: () => runUserStatusLine
|
|
38493
38933
|
});
|
|
38494
38934
|
/**
|
|
38495
|
-
* Read stdin synchronously
|
|
38496
|
-
* statusLine command; an unread pipe can SIGPIPE the writer on some
|
|
38935
|
+
* Read stdin synchronously. Claude Code pipes session JSON to the
|
|
38936
|
+
* statusLine command; an unread pipe can SIGPIPE the writer on some
|
|
38937
|
+
* platforms. Returns "" when stdin is a TTY or unreadable — callers render
|
|
38938
|
+
* placeholders/omit segments rather than failing.
|
|
38497
38939
|
*/
|
|
38498
|
-
function
|
|
38940
|
+
function readStdin() {
|
|
38499
38941
|
try {
|
|
38500
|
-
if (process.stdin.isTTY) return;
|
|
38501
|
-
readFileSync(0, "utf8");
|
|
38502
|
-
} catch {
|
|
38942
|
+
if (process.stdin.isTTY) return "";
|
|
38943
|
+
return readFileSync(0, "utf8");
|
|
38944
|
+
} catch {
|
|
38945
|
+
return "";
|
|
38946
|
+
}
|
|
38503
38947
|
}
|
|
38504
38948
|
/**
|
|
38505
38949
|
* Pure core: compose the status line from an AIC fragment and a user line.
|
|
@@ -38536,31 +38980,48 @@ function runUserStatusLine(command, timeoutMs = 5e3) {
|
|
|
38536
38980
|
return "";
|
|
38537
38981
|
}
|
|
38538
38982
|
}
|
|
38539
|
-
function
|
|
38983
|
+
function readAicSnapshot() {
|
|
38540
38984
|
try {
|
|
38541
38985
|
const ledgerPath = process.env.GH_ROUTER_AIC_LEDGER;
|
|
38542
|
-
if (!ledgerPath) return "";
|
|
38986
|
+
if (!ledgerPath) return { fragment: "" };
|
|
38543
38987
|
const snapshot = readAicSnapshotFile(ledgerPath);
|
|
38544
|
-
if (!snapshot) return "";
|
|
38545
|
-
|
|
38988
|
+
if (!snapshot) return { fragment: "" };
|
|
38989
|
+
if (snapshot.requests === 0 || snapshot.totalNanoAiu <= 0) return { fragment: "" };
|
|
38990
|
+
return {
|
|
38991
|
+
fragment: formatAicStatus(snapshot),
|
|
38992
|
+
actualUsd: discountedUsdForSnapshot(snapshot).total
|
|
38993
|
+
};
|
|
38546
38994
|
} catch {
|
|
38547
|
-
return "";
|
|
38995
|
+
return { fragment: "" };
|
|
38548
38996
|
}
|
|
38549
38997
|
}
|
|
38550
38998
|
var internalAicStatus;
|
|
38551
38999
|
var init_internal_aic_status = __esmMin((() => {
|
|
38552
39000
|
init_dist$1();
|
|
38553
39001
|
init_aic_ledger();
|
|
39002
|
+
init_copilot_discount();
|
|
39003
|
+
init_default_statusline();
|
|
38554
39004
|
internalAicStatus = defineCommand({
|
|
38555
39005
|
meta: {
|
|
38556
39006
|
name: "internal-aic-status",
|
|
38557
|
-
description: "Internal: Claude Code statusLine handler printing
|
|
39007
|
+
description: "Internal: Claude Code statusLine handler printing AIC total + rich session line."
|
|
38558
39008
|
},
|
|
38559
39009
|
async run() {
|
|
38560
|
-
|
|
38561
|
-
const aic =
|
|
39010
|
+
const stdinRaw = readStdin();
|
|
39011
|
+
const { fragment: aic, actualUsd } = readAicSnapshot();
|
|
38562
39012
|
const userCommand = process.env.GH_ROUTER_AIC_USER_STATUSLINE ?? "";
|
|
38563
|
-
|
|
39013
|
+
if (userCommand.trim()) {
|
|
39014
|
+
const line = composeAicStatusLine(aic, runUserStatusLine(userCommand));
|
|
39015
|
+
if (line) process.stdout.write(`${line}\n`);
|
|
39016
|
+
process.exitCode = 0;
|
|
39017
|
+
return;
|
|
39018
|
+
}
|
|
39019
|
+
let line;
|
|
39020
|
+
try {
|
|
39021
|
+
line = buildRichStatusLine(stdinRaw, aic, { ...actualUsd !== void 0 ? { actualUsd } : {} });
|
|
39022
|
+
} catch {
|
|
39023
|
+
line = aic.trim();
|
|
39024
|
+
}
|
|
38564
39025
|
if (line) process.stdout.write(`${line}\n`);
|
|
38565
39026
|
process.exitCode = 0;
|
|
38566
39027
|
}
|
package/dist/hooks.sha256
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
a3747ee44a5aac64ec5a952b9efb60112356d31d45f8d04ae939401d0d96a7e5
|