aicodeman 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +27 -0
- package/dist/cli.js.map +1 -1
- package/dist/config/dependency-registry.d.ts +42 -0
- package/dist/config/dependency-registry.d.ts.map +1 -0
- package/dist/config/dependency-registry.js +104 -0
- package/dist/config/dependency-registry.js.map +1 -0
- package/dist/document-conversion-limiter.d.ts +27 -0
- package/dist/document-conversion-limiter.d.ts.map +1 -0
- package/dist/document-conversion-limiter.js +64 -0
- package/dist/document-conversion-limiter.js.map +1 -0
- package/dist/document-preview-cache.d.ts +15 -0
- package/dist/document-preview-cache.d.ts.map +1 -0
- package/dist/document-preview-cache.js +261 -0
- package/dist/document-preview-cache.js.map +1 -0
- package/dist/document-thumbnailer.d.ts +9 -0
- package/dist/document-thumbnailer.d.ts.map +1 -0
- package/dist/document-thumbnailer.js +70 -0
- package/dist/document-thumbnailer.js.map +1 -0
- package/dist/hooks-config.d.ts +34 -0
- package/dist/hooks-config.d.ts.map +1 -1
- package/dist/hooks-config.js +203 -73
- package/dist/hooks-config.js.map +1 -1
- package/dist/image-watcher.d.ts.map +1 -1
- package/dist/image-watcher.js +2 -6
- package/dist/image-watcher.js.map +1 -1
- package/dist/session-attachment-history.d.ts +19 -0
- package/dist/session-attachment-history.d.ts.map +1 -0
- package/dist/session-attachment-history.js +63 -0
- package/dist/session-attachment-history.js.map +1 -0
- package/dist/session.d.ts +10 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +27 -0
- package/dist/session.js.map +1 -1
- package/dist/types/session.d.ts +35 -0
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js.map +1 -1
- package/dist/usage-telemetry.d.ts +102 -0
- package/dist/usage-telemetry.d.ts.map +1 -0
- package/dist/usage-telemetry.js +130 -0
- package/dist/usage-telemetry.js.map +1 -0
- package/dist/utils/dependency-checker.d.ts +42 -0
- package/dist/utils/dependency-checker.d.ts.map +1 -0
- package/dist/utils/dependency-checker.js +167 -0
- package/dist/utils/dependency-checker.js.map +1 -0
- package/dist/utils/dependency-report.d.ts +26 -0
- package/dist/utils/dependency-report.d.ts.map +1 -0
- package/dist/utils/dependency-report.js +68 -0
- package/dist/utils/dependency-report.js.map +1 -0
- package/dist/web/middleware/auth.d.ts +4 -8
- package/dist/web/middleware/auth.d.ts.map +1 -1
- package/dist/web/middleware/auth.js +18 -25
- package/dist/web/middleware/auth.js.map +1 -1
- package/dist/web/plan-usage-latest.d.ts +15 -0
- package/dist/web/plan-usage-latest.d.ts.map +1 -0
- package/dist/web/plan-usage-latest.js +20 -0
- package/dist/web/plan-usage-latest.js.map +1 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/app.92f49a9d.js +37 -0
- package/dist/web/public/app.92f49a9d.js.br +0 -0
- package/dist/web/public/app.92f49a9d.js.gz +0 -0
- package/dist/web/public/{constants.aa510a4d.js → constants.59faac65.js} +16 -0
- package/dist/web/public/constants.59faac65.js.br +0 -0
- package/dist/web/public/constants.59faac65.js.gz +0 -0
- package/dist/web/public/image-input.0ea86695.js.gz +0 -0
- package/dist/web/public/index.html +40 -27
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.b8686b5e.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.bc753cc7.js.gz +0 -0
- package/dist/web/public/{mobile-handlers.763a7439.js → mobile-handlers.db3dc3c8.js} +3 -0
- package/dist/web/public/mobile-handlers.db3dc3c8.js.br +0 -0
- package/dist/web/public/mobile-handlers.db3dc3c8.js.gz +0 -0
- package/dist/web/public/mobile.06b38d3a.css +1 -0
- package/dist/web/public/mobile.06b38d3a.css.br +0 -0
- package/dist/web/public/mobile.06b38d3a.css.gz +0 -0
- package/dist/web/public/notification-manager.9c984ac2.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/{panels-ui.ba0b0f1a.js → panels-ui.2f467969.js} +141 -87
- package/dist/web/public/panels-ui.2f467969.js.br +0 -0
- package/dist/web/public/panels-ui.2f467969.js.gz +0 -0
- package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
- package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
- package/dist/web/public/respawn-ui.2d249da9.js.gz +0 -0
- package/dist/web/public/sanitize-html.bc7078d6.js +1 -0
- package/dist/web/public/sanitize-html.bc7078d6.js.br +0 -0
- package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
- package/dist/web/public/session-ui.1463b824.js +36 -0
- package/dist/web/public/session-ui.1463b824.js.br +0 -0
- package/dist/web/public/session-ui.1463b824.js.gz +0 -0
- package/dist/web/public/settings-ui.44b99ce0.js +55 -0
- package/dist/web/public/settings-ui.44b99ce0.js.br +0 -0
- package/dist/web/public/settings-ui.44b99ce0.js.gz +0 -0
- package/dist/web/public/styles.8e1ea0c6.css +1 -0
- package/dist/web/public/styles.8e1ea0c6.css.br +0 -0
- package/dist/web/public/styles.8e1ea0c6.css.gz +0 -0
- package/dist/web/public/subagent-windows.a366a4ad.js.gz +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/terminal-ui.a7e046da.js +3 -0
- package/dist/web/public/terminal-ui.a7e046da.js.br +0 -0
- package/dist/web/public/terminal-ui.a7e046da.js.gz +0 -0
- package/dist/web/public/upload.html.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js +3 -0
- package/dist/web/public/vendor/dompurify.min.js.br +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.085e9e73.js.gz +0 -0
- package/dist/web/routes/file-routes.d.ts +2 -2
- package/dist/web/routes/file-routes.d.ts.map +1 -1
- package/dist/web/routes/file-routes.js +298 -1
- package/dist/web/routes/file-routes.js.map +1 -1
- package/dist/web/routes/index.d.ts +1 -0
- package/dist/web/routes/index.d.ts.map +1 -1
- package/dist/web/routes/index.js +1 -0
- package/dist/web/routes/index.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +27 -1
- package/dist/web/routes/session-routes.js.map +1 -1
- package/dist/web/routes/status-telemetry-routes.d.ts +17 -0
- package/dist/web/routes/status-telemetry-routes.d.ts.map +1 -0
- package/dist/web/routes/status-telemetry-routes.js +57 -0
- package/dist/web/routes/status-telemetry-routes.js.map +1 -0
- package/dist/web/routes/system-routes.d.ts.map +1 -1
- package/dist/web/routes/system-routes.js +21 -1
- package/dist/web/routes/system-routes.js.map +1 -1
- package/dist/web/schemas.d.ts +30 -1
- package/dist/web/schemas.d.ts.map +1 -1
- package/dist/web/schemas.js +52 -0
- package/dist/web/schemas.js.map +1 -1
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +51 -5
- package/dist/web/server.js.map +1 -1
- package/dist/web/sse-events.d.ts +3 -0
- package/dist/web/sse-events.d.ts.map +1 -1
- package/dist/web/sse-events.js +3 -0
- package/dist/web/sse-events.js.map +1 -1
- package/package.json +1 -1
- package/dist/web/public/app.95e6e231.js +0 -35
- package/dist/web/public/app.95e6e231.js.br +0 -0
- package/dist/web/public/app.95e6e231.js.gz +0 -0
- package/dist/web/public/constants.aa510a4d.js.br +0 -0
- package/dist/web/public/constants.aa510a4d.js.gz +0 -0
- package/dist/web/public/mobile-handlers.763a7439.js.br +0 -0
- package/dist/web/public/mobile-handlers.763a7439.js.gz +0 -0
- package/dist/web/public/mobile.c7513aed.css +0 -1
- package/dist/web/public/mobile.c7513aed.css.br +0 -0
- package/dist/web/public/mobile.c7513aed.css.gz +0 -0
- package/dist/web/public/panels-ui.ba0b0f1a.js.br +0 -0
- package/dist/web/public/panels-ui.ba0b0f1a.js.gz +0 -0
- package/dist/web/public/session-ui.34f25fdf.js +0 -36
- package/dist/web/public/session-ui.34f25fdf.js.br +0 -0
- package/dist/web/public/session-ui.34f25fdf.js.gz +0 -0
- package/dist/web/public/settings-ui.bf79c4c0.js +0 -55
- package/dist/web/public/settings-ui.bf79c4c0.js.br +0 -0
- package/dist/web/public/settings-ui.bf79c4c0.js.gz +0 -0
- package/dist/web/public/styles.f3cc9833.css +0 -1
- package/dist/web/public/styles.f3cc9833.css.br +0 -0
- package/dist/web/public/styles.f3cc9833.css.gz +0 -0
- package/dist/web/public/terminal-ui.5bf97f7e.js +0 -3
- package/dist/web/public/terminal-ui.5bf97f7e.js.br +0 -0
- package/dist/web/public/terminal-ui.5bf97f7e.js.gz +0 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Pure parsing + formatting of Claude Code statusline telemetry.
|
|
3
|
+
*
|
|
4
|
+
* Claude Code (v2.1.80+) pipes a JSON blob to a configured `statusLine.command`
|
|
5
|
+
* on each render. On Pro/Max subscriptions that blob carries a `rate_limits`
|
|
6
|
+
* object with the 5-hour rolling and 7-day weekly plan windows. The
|
|
7
|
+
* Codeman-managed statusLine exporter (see `hooks-config.generateStatusLineCommand`)
|
|
8
|
+
* POSTs that blob to `/api/status-telemetry`; these helpers normalize the subset
|
|
9
|
+
* Codeman displays and format the compact in-terminal footer string.
|
|
10
|
+
*
|
|
11
|
+
* Confirmed schema (empirically captured, CC 2.1.177, Claude Max — see
|
|
12
|
+
* `docs/usage-limits-display-plan.md`):
|
|
13
|
+
* rate_limits.{five_hour,seven_day}.{used_percentage: number 0-100,
|
|
14
|
+
* resets_at: number EPOCH-SECONDS}
|
|
15
|
+
* Only those two windows exist (no Opus-weekly field). `rate_limits` is absent
|
|
16
|
+
* before the first API response and for non-subscriber auth — both yield null.
|
|
17
|
+
*
|
|
18
|
+
* All functions are pure for testability. See `test/usage-telemetry.test.ts`.
|
|
19
|
+
*
|
|
20
|
+
* @module usage-telemetry
|
|
21
|
+
*/
|
|
22
|
+
function clampPct(n) {
|
|
23
|
+
if (!Number.isFinite(n))
|
|
24
|
+
return 0;
|
|
25
|
+
return Math.max(0, Math.min(100, n));
|
|
26
|
+
}
|
|
27
|
+
function parseWindow(w) {
|
|
28
|
+
if (!w || typeof w.used_percentage !== 'number' || typeof w.resets_at !== 'number')
|
|
29
|
+
return undefined;
|
|
30
|
+
if (!Number.isFinite(w.resets_at) || w.resets_at <= 0)
|
|
31
|
+
return undefined;
|
|
32
|
+
return { usedPercentage: clampPct(w.used_percentage), resetAt: Math.round(w.resets_at * 1000) };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Normalize a raw statusline payload to the telemetry Codeman displays. Returns
|
|
36
|
+
* null when there is no plan-limit data to show (pre-first-response or a
|
|
37
|
+
* non-subscriber account) so the caller can skip broadcasting.
|
|
38
|
+
*/
|
|
39
|
+
export function parseStatusTelemetry(data) {
|
|
40
|
+
if (!data)
|
|
41
|
+
return null;
|
|
42
|
+
const fiveHour = parseWindow(data.rate_limits?.five_hour);
|
|
43
|
+
const sevenDay = parseWindow(data.rate_limits?.seven_day);
|
|
44
|
+
if (!fiveHour && !sevenDay)
|
|
45
|
+
return null;
|
|
46
|
+
const t = {};
|
|
47
|
+
if (fiveHour)
|
|
48
|
+
t.fiveHour = fiveHour;
|
|
49
|
+
if (sevenDay)
|
|
50
|
+
t.sevenDay = sevenDay;
|
|
51
|
+
if (typeof data.context_window?.used_percentage === 'number') {
|
|
52
|
+
t.contextUsedPercentage = clampPct(data.context_window.used_percentage);
|
|
53
|
+
}
|
|
54
|
+
if (typeof data.cost?.total_cost_usd === 'number' && Number.isFinite(data.cost.total_cost_usd)) {
|
|
55
|
+
t.costUsd = data.cost.total_cost_usd;
|
|
56
|
+
}
|
|
57
|
+
if (typeof data.model?.display_name === 'string' && data.model.display_name) {
|
|
58
|
+
t.modelDisplayName = data.model.display_name.slice(0, 60);
|
|
59
|
+
}
|
|
60
|
+
return t;
|
|
61
|
+
}
|
|
62
|
+
/** Group a non-negative integer with thousands separators: 562411 → "562,411". */
|
|
63
|
+
function withCommas(n) {
|
|
64
|
+
return Math.max(0, Math.round(n))
|
|
65
|
+
.toString()
|
|
66
|
+
.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
67
|
+
}
|
|
68
|
+
/** Extract current-session status (footer) from the raw payload. */
|
|
69
|
+
export function parseSessionStatus(data) {
|
|
70
|
+
if (!data)
|
|
71
|
+
return null;
|
|
72
|
+
const s = {};
|
|
73
|
+
if (typeof data.model?.display_name === 'string' && data.model.display_name) {
|
|
74
|
+
s.modelDisplayName = data.model.display_name.slice(0, 60);
|
|
75
|
+
}
|
|
76
|
+
const cw = data.context_window;
|
|
77
|
+
if (typeof cw?.total_input_tokens === 'number' && Number.isFinite(cw.total_input_tokens)) {
|
|
78
|
+
s.inputTokens = Math.max(0, cw.total_input_tokens);
|
|
79
|
+
}
|
|
80
|
+
if (typeof cw?.total_output_tokens === 'number' && Number.isFinite(cw.total_output_tokens)) {
|
|
81
|
+
s.outputTokens = Math.max(0, cw.total_output_tokens);
|
|
82
|
+
}
|
|
83
|
+
if (typeof cw?.used_percentage === 'number') {
|
|
84
|
+
s.contextUsedPercentage = clampPct(cw.used_percentage);
|
|
85
|
+
}
|
|
86
|
+
return Object.keys(s).length ? s : null;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Format the in-terminal statusline footer: the CURRENT SESSION's status —
|
|
90
|
+
* `Opus 4.8 (1M context) in:562,411 out:1,188 ctx:56%` — NOT the plan limits,
|
|
91
|
+
* which live in the Codeman header chip. Claude requires a statusLine command to
|
|
92
|
+
* emit the rate_limits JSON at all, so this is what that command prints back.
|
|
93
|
+
*/
|
|
94
|
+
export function formatSessionStatusText(s) {
|
|
95
|
+
if (!s)
|
|
96
|
+
return 'codeman';
|
|
97
|
+
const groups = [];
|
|
98
|
+
if (s.modelDisplayName)
|
|
99
|
+
groups.push(s.modelDisplayName);
|
|
100
|
+
const tok = [];
|
|
101
|
+
if (s.inputTokens != null)
|
|
102
|
+
tok.push(`in:${withCommas(s.inputTokens)}`);
|
|
103
|
+
if (s.outputTokens != null)
|
|
104
|
+
tok.push(`out:${withCommas(s.outputTokens)}`);
|
|
105
|
+
if (tok.length)
|
|
106
|
+
groups.push(tok.join(' '));
|
|
107
|
+
if (s.contextUsedPercentage != null)
|
|
108
|
+
groups.push(`ctx:${Math.round(clampPct(s.contextUsedPercentage))}%`);
|
|
109
|
+
return groups.length ? groups.join(' ') : 'codeman';
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Stable signature for change-detection — the statusline fires on every
|
|
113
|
+
* assistant message, so the route only rebroadcasts when this value changes.
|
|
114
|
+
*
|
|
115
|
+
* Keys on EXACTLY the values the header chip displays: the two windows' ROUNDED
|
|
116
|
+
* percentages (the chip renders `Math.round`) + their reset times. Deliberately
|
|
117
|
+
* excludes contextUsedPercentage / costUsd / modelDisplayName — none are shown
|
|
118
|
+
* in the chip, and contextUsedPercentage in particular drifts on every assistant
|
|
119
|
+
* message, which would defeat the dedup and fan out a redundant SSE broadcast +
|
|
120
|
+
* localStorage write + identical chip re-render each time.
|
|
121
|
+
*/
|
|
122
|
+
export function telemetrySignature(t) {
|
|
123
|
+
return JSON.stringify([
|
|
124
|
+
t.fiveHour ? Math.round(t.fiveHour.usedPercentage) : null,
|
|
125
|
+
t.fiveHour?.resetAt ?? null,
|
|
126
|
+
t.sevenDay ? Math.round(t.sevenDay.usedPercentage) : null,
|
|
127
|
+
t.sevenDay?.resetAt ?? null,
|
|
128
|
+
]);
|
|
129
|
+
}
|
|
130
|
+
//# sourceMappingURL=usage-telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-telemetry.js","sourceRoot":"","sources":["../src/usage-telemetry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAiCH,SAAS,QAAQ,CAAC,CAAS;IACzB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,SAAS,WAAW,CAAC,CAAoD;IACvE,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,eAAe,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACrG,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC;QAAE,OAAO,SAAS,CAAC;IACxE,OAAO,EAAE,cAAc,EAAE,QAAQ,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC,EAAE,CAAC;AAClG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAsC;IACzE,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;IAC1D,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAExC,MAAM,CAAC,GAAoB,EAAE,CAAC;IAC9B,IAAI,QAAQ;QAAE,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACpC,IAAI,QAAQ;QAAE,CAAC,CAAC,QAAQ,GAAG,QAAQ,CAAC;IACpC,IAAI,OAAO,IAAI,CAAC,cAAc,EAAE,eAAe,KAAK,QAAQ,EAAE,CAAC;QAC7D,CAAC,CAAC,qBAAqB,GAAG,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,OAAO,IAAI,CAAC,IAAI,EAAE,cAAc,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QAC/F,CAAC,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;IACvC,CAAC;IACD,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,YAAY,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QAC5E,CAAC,CAAC,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAcD,kFAAkF;AAClF,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SAC9B,QAAQ,EAAE;SACV,OAAO,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAC;AAC3C,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,kBAAkB,CAAC,IAAsC;IACvE,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,CAAC,GAAkB,EAAE,CAAC;IAC5B,IAAI,OAAO,IAAI,CAAC,KAAK,EAAE,YAAY,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QAC5E,CAAC,CAAC,gBAAgB,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC;IAC/B,IAAI,OAAO,EAAE,EAAE,kBAAkB,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC;QACzF,CAAC,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,kBAAkB,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,OAAO,EAAE,EAAE,mBAAmB,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC3F,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,OAAO,EAAE,EAAE,eAAe,KAAK,QAAQ,EAAE,CAAC;QAC5C,CAAC,CAAC,qBAAqB,GAAG,QAAQ,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,CAAuB;IAC7D,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,CAAC,CAAC,gBAAgB;QAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;IACxD,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,IAAI,CAAC,CAAC,WAAW,IAAI,IAAI;QAAE,GAAG,CAAC,IAAI,CAAC,MAAM,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACvE,IAAI,CAAC,CAAC,YAAY,IAAI,IAAI;QAAE,GAAG,CAAC,IAAI,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAC1E,IAAI,GAAG,CAAC,MAAM;QAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3C,IAAI,CAAC,CAAC,qBAAqB,IAAI,IAAI;QAAE,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,GAAG,CAAC,CAAC;IAC1G,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACvD,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,CAAkB;IACnD,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI;QACzD,CAAC,CAAC,QAAQ,EAAE,OAAO,IAAI,IAAI;QAC3B,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI;QACzD,CAAC,CAAC,QAAQ,EAAE,OAAO,IAAI,IAAI;KAC5B,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Probe engine for `codeman doctor`. Resolves each registry tool
|
|
3
|
+
* against an injectable ProbeHost (real impl uses child_process/fs; tests inject
|
|
4
|
+
* fakes) and returns structured results. Pure given the host — no global I/O.
|
|
5
|
+
*
|
|
6
|
+
* @module utils/dependency-checker
|
|
7
|
+
*/
|
|
8
|
+
import type { ProbeEnvironment, ToolCategory, ToolDependency } from '../config/dependency-registry.js';
|
|
9
|
+
export interface EnvDetectionInputs {
|
|
10
|
+
platform: NodeJS.Platform;
|
|
11
|
+
procVersion: string;
|
|
12
|
+
hasWindowsInterop: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function detectEnvironment(inputs: EnvDetectionInputs): ProbeEnvironment;
|
|
15
|
+
export declare function extractVersion(text: string, re?: RegExp): string | undefined;
|
|
16
|
+
/** Returns -1 if a < b, 0 if equal, 1 if a > b (numeric, component-wise). */
|
|
17
|
+
export declare function compareVersions(a: string, b: string): number;
|
|
18
|
+
export type ToolStatus = 'ok' | 'missing' | 'outdated' | 'skipped' | 'error';
|
|
19
|
+
export interface ToolResult {
|
|
20
|
+
id: string;
|
|
21
|
+
label: string;
|
|
22
|
+
category: ToolCategory;
|
|
23
|
+
required: boolean;
|
|
24
|
+
usedBy: string[];
|
|
25
|
+
status: ToolStatus;
|
|
26
|
+
version?: string;
|
|
27
|
+
path?: string;
|
|
28
|
+
installHint?: string;
|
|
29
|
+
reason?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface ProbeHost {
|
|
32
|
+
environment: ProbeEnvironment;
|
|
33
|
+
which(bin: string): string | null;
|
|
34
|
+
fileExists(path: string): boolean;
|
|
35
|
+
runVersion(bin: string, args: string[]): string | null;
|
|
36
|
+
windowsProgramRoots(): string[];
|
|
37
|
+
windowsFileVersion(winPath: string): string | null;
|
|
38
|
+
}
|
|
39
|
+
export declare function checkTool(tool: ToolDependency, host: ProbeHost): ToolResult;
|
|
40
|
+
export declare function checkAll(registry: ToolDependency[], host: ProbeHost): ToolResult[];
|
|
41
|
+
export declare function createRealHost(): ProbeHost;
|
|
42
|
+
//# sourceMappingURL=dependency-checker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-checker.d.ts","sourceRoot":"","sources":["../../src/utils/dependency-checker.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AAEvG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,OAAO,CAAC;CAC5B;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,gBAAgB,CAK9E;AAID,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG5E;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAS5D;AAED,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,CAAC;AAE7E,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,SAAS;IACxB,WAAW,EAAE,gBAAgB,CAAC;IAC9B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAClC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CAAC;IACvD,mBAAmB,IAAI,MAAM,EAAE,CAAC;IAChC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACpD;AAeD,wBAAgB,SAAS,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,GAAG,UAAU,CAyC3E;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,EAAE,IAAI,EAAE,SAAS,GAAG,UAAU,EAAE,CAElF;AAqED,wBAAgB,cAAc,IAAI,SAAS,CAc1C"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Probe engine for `codeman doctor`. Resolves each registry tool
|
|
3
|
+
* against an injectable ProbeHost (real impl uses child_process/fs; tests inject
|
|
4
|
+
* fakes) and returns structured results. Pure given the host — no global I/O.
|
|
5
|
+
*
|
|
6
|
+
* @module utils/dependency-checker
|
|
7
|
+
*/
|
|
8
|
+
import { execFileSync } from 'node:child_process';
|
|
9
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
10
|
+
import { EXEC_TIMEOUT_MS } from '../config/exec-timeout.js';
|
|
11
|
+
export function detectEnvironment(inputs) {
|
|
12
|
+
if (inputs.platform === 'win32')
|
|
13
|
+
return 'win32';
|
|
14
|
+
if (inputs.platform === 'darwin')
|
|
15
|
+
return 'darwin';
|
|
16
|
+
const isWsl = /microsoft|wsl/i.test(inputs.procVersion) && inputs.hasWindowsInterop;
|
|
17
|
+
return isWsl ? 'wsl' : 'linux';
|
|
18
|
+
}
|
|
19
|
+
const DEFAULT_VERSION_RE = /(\d+\.\d+(?:\.\d+)?)/;
|
|
20
|
+
export function extractVersion(text, re) {
|
|
21
|
+
const m = (re ?? DEFAULT_VERSION_RE).exec(text);
|
|
22
|
+
return m ? m[1] : undefined;
|
|
23
|
+
}
|
|
24
|
+
/** Returns -1 if a < b, 0 if equal, 1 if a > b (numeric, component-wise). */
|
|
25
|
+
export function compareVersions(a, b) {
|
|
26
|
+
const pa = a.split('.').map((n) => parseInt(n, 10) || 0);
|
|
27
|
+
const pb = b.split('.').map((n) => parseInt(n, 10) || 0);
|
|
28
|
+
const len = Math.max(pa.length, pb.length);
|
|
29
|
+
for (let i = 0; i < len; i++) {
|
|
30
|
+
const d = (pa[i] || 0) - (pb[i] || 0);
|
|
31
|
+
if (d !== 0)
|
|
32
|
+
return d < 0 ? -1 : 1;
|
|
33
|
+
}
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
function finalize(base, tool, path, version) {
|
|
37
|
+
if (tool.minVersion) {
|
|
38
|
+
if (!version)
|
|
39
|
+
return { ...base, status: 'error', path, reason: 'version required but could not be parsed' };
|
|
40
|
+
if (compareVersions(version, tool.minVersion) < 0)
|
|
41
|
+
return { ...base, status: 'outdated', path, version };
|
|
42
|
+
}
|
|
43
|
+
return { ...base, status: 'ok', path, version };
|
|
44
|
+
}
|
|
45
|
+
export function checkTool(tool, host) {
|
|
46
|
+
const base = {
|
|
47
|
+
id: tool.id,
|
|
48
|
+
label: tool.label,
|
|
49
|
+
category: tool.category,
|
|
50
|
+
required: tool.required,
|
|
51
|
+
usedBy: tool.usedBy ?? [],
|
|
52
|
+
};
|
|
53
|
+
const installHint = tool.installHint?.[host.environment];
|
|
54
|
+
const spec = tool.resolvers.find((r) => r.match.includes(host.environment));
|
|
55
|
+
if (!spec)
|
|
56
|
+
return { ...base, status: 'skipped', reason: `not applicable on ${host.environment}` };
|
|
57
|
+
if (spec.resolver.kind === 'path') {
|
|
58
|
+
const { bins, versionArg, versionRegex } = spec.resolver;
|
|
59
|
+
for (const bin of bins) {
|
|
60
|
+
const resolved = host.which(bin);
|
|
61
|
+
if (resolved) {
|
|
62
|
+
const out = host.runVersion(bin, [versionArg ?? '--version']);
|
|
63
|
+
const version = out ? extractVersion(out, versionRegex) : undefined;
|
|
64
|
+
return finalize(base, tool, resolved, version);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return { ...base, status: 'missing', installHint };
|
|
68
|
+
}
|
|
69
|
+
// windows-side
|
|
70
|
+
const { appDirs, exes } = spec.resolver;
|
|
71
|
+
for (const root of host.windowsProgramRoots()) {
|
|
72
|
+
for (const dir of appDirs) {
|
|
73
|
+
for (const exe of exes) {
|
|
74
|
+
const winPath = `${root}/${dir}/${exe}`;
|
|
75
|
+
if (host.fileExists(winPath)) {
|
|
76
|
+
const raw = host.windowsFileVersion(winPath);
|
|
77
|
+
const version = raw ? extractVersion(raw) : undefined;
|
|
78
|
+
return finalize(base, tool, winPath, version);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { ...base, status: 'missing', installHint };
|
|
84
|
+
}
|
|
85
|
+
export function checkAll(registry, host) {
|
|
86
|
+
return registry.map((tool) => checkTool(tool, host));
|
|
87
|
+
}
|
|
88
|
+
function safeWhich(bin) {
|
|
89
|
+
try {
|
|
90
|
+
const out = execFileSync(process.platform === 'win32' ? 'where' : 'which', [bin], {
|
|
91
|
+
encoding: 'utf-8',
|
|
92
|
+
timeout: EXEC_TIMEOUT_MS,
|
|
93
|
+
}).trim();
|
|
94
|
+
const first = out.split(/\r?\n/)[0]?.trim();
|
|
95
|
+
return first && existsSync(first) ? first : null;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
function safeRunVersion(bin, args) {
|
|
102
|
+
try {
|
|
103
|
+
return execFileSync(bin, args, {
|
|
104
|
+
encoding: 'utf-8',
|
|
105
|
+
timeout: EXEC_TIMEOUT_MS,
|
|
106
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
// Some tools (e.g. ffmpeg) exit non-zero on -version but still print to stdout
|
|
111
|
+
const stdout = err?.stdout;
|
|
112
|
+
return stdout ? stdout.toString() : null;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function readProcVersion() {
|
|
116
|
+
try {
|
|
117
|
+
return readFileSync('/proc/version', 'utf-8');
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return '';
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function listWindowsProgramRoots() {
|
|
124
|
+
const roots = [];
|
|
125
|
+
try {
|
|
126
|
+
for (const entry of readdirSync('/mnt')) {
|
|
127
|
+
for (const pf of ['Program Files', 'Program Files (x86)']) {
|
|
128
|
+
const root = `/mnt/${entry}/${pf}`;
|
|
129
|
+
if (existsSync(root))
|
|
130
|
+
roots.push(root);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
// /mnt absent (not WSL) -> no roots
|
|
136
|
+
}
|
|
137
|
+
return roots;
|
|
138
|
+
}
|
|
139
|
+
function readWindowsFileVersion(winPath) {
|
|
140
|
+
try {
|
|
141
|
+
const windowsPath = execFileSync('wslpath', ['-w', winPath], {
|
|
142
|
+
encoding: 'utf-8',
|
|
143
|
+
timeout: EXEC_TIMEOUT_MS,
|
|
144
|
+
}).trim();
|
|
145
|
+
const out = execFileSync('powershell.exe', ['-NoProfile', '-Command', `(Get-Item '${windowsPath.replace(/'/g, "''")}').VersionInfo.ProductVersion`], { encoding: 'utf-8', timeout: EXEC_TIMEOUT_MS }).trim();
|
|
146
|
+
return out || null;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export function createRealHost() {
|
|
153
|
+
const environment = detectEnvironment({
|
|
154
|
+
platform: process.platform,
|
|
155
|
+
procVersion: readProcVersion(),
|
|
156
|
+
hasWindowsInterop: safeWhich('cmd.exe') !== null || safeWhich('powershell.exe') !== null,
|
|
157
|
+
});
|
|
158
|
+
return {
|
|
159
|
+
environment,
|
|
160
|
+
which: safeWhich,
|
|
161
|
+
fileExists: existsSync,
|
|
162
|
+
runVersion: safeRunVersion,
|
|
163
|
+
windowsProgramRoots: listWindowsProgramRoots,
|
|
164
|
+
windowsFileVersion: readWindowsFileVersion,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=dependency-checker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-checker.js","sourceRoot":"","sources":["../../src/utils/dependency-checker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Renders ToolResult[] from the dependency checker into a
|
|
3
|
+
* human-readable grouped table or JSON, and computes the process exit code.
|
|
4
|
+
* Plain text only (no color) so output is stable and snapshot-friendly; the
|
|
5
|
+
* CLI layer may colorize.
|
|
6
|
+
*
|
|
7
|
+
* @module utils/dependency-report
|
|
8
|
+
*/
|
|
9
|
+
import type { ProbeEnvironment } from '../config/dependency-registry.js';
|
|
10
|
+
import type { ToolResult } from './dependency-checker.js';
|
|
11
|
+
export declare function computeExitCode(results: ToolResult[]): number;
|
|
12
|
+
export declare function renderTable(results: ToolResult[], environment: ProbeEnvironment): string;
|
|
13
|
+
export interface DependencyReportJson {
|
|
14
|
+
platform: {
|
|
15
|
+
environment: ProbeEnvironment;
|
|
16
|
+
};
|
|
17
|
+
summary: {
|
|
18
|
+
ok: number;
|
|
19
|
+
requiredMissing: number;
|
|
20
|
+
optionalMissing: number;
|
|
21
|
+
exitCode: number;
|
|
22
|
+
};
|
|
23
|
+
tools: ToolResult[];
|
|
24
|
+
}
|
|
25
|
+
export declare function renderJson(results: ToolResult[], environment: ProbeEnvironment): DependencyReportJson;
|
|
26
|
+
//# sourceMappingURL=dependency-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-report.d.ts","sourceRoot":"","sources":["../../src/utils/dependency-report.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAgB,MAAM,kCAAkC,CAAC;AACvF,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,yBAAyB,CAAC;AAkBtE,wBAAgB,eAAe,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,CAK7D;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,WAAW,EAAE,gBAAgB,GAAG,MAAM,CAmBxF;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE;QAAE,WAAW,EAAE,gBAAgB,CAAA;KAAE,CAAC;IAC5C,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5F,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,UAAU,EAAE,EAAE,WAAW,EAAE,gBAAgB,GAAG,oBAAoB,CAYrG"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Renders ToolResult[] from the dependency checker into a
|
|
3
|
+
* human-readable grouped table or JSON, and computes the process exit code.
|
|
4
|
+
* Plain text only (no color) so output is stable and snapshot-friendly; the
|
|
5
|
+
* CLI layer may colorize.
|
|
6
|
+
*
|
|
7
|
+
* @module utils/dependency-report
|
|
8
|
+
*/
|
|
9
|
+
const CATEGORY_ORDER = ['core', 'office', 'other'];
|
|
10
|
+
function glyph(r) {
|
|
11
|
+
if (r.status === 'ok')
|
|
12
|
+
return '✓';
|
|
13
|
+
if (r.status === 'skipped')
|
|
14
|
+
return '○';
|
|
15
|
+
return r.required ? '✗' : '○';
|
|
16
|
+
}
|
|
17
|
+
function statusText(r) {
|
|
18
|
+
if (r.status === 'ok')
|
|
19
|
+
return r.version ?? 'installed';
|
|
20
|
+
if (r.status === 'outdated')
|
|
21
|
+
return `${r.version ?? '?'} (below minimum)`;
|
|
22
|
+
if (r.status === 'skipped')
|
|
23
|
+
return 'n/a';
|
|
24
|
+
if (r.status === 'error')
|
|
25
|
+
return 'version error';
|
|
26
|
+
return 'not found';
|
|
27
|
+
}
|
|
28
|
+
export function computeExitCode(results) {
|
|
29
|
+
const failed = results.some((r) => r.required && (r.status === 'missing' || r.status === 'outdated' || r.status === 'error'));
|
|
30
|
+
return failed ? 1 : 0;
|
|
31
|
+
}
|
|
32
|
+
export function renderTable(results, environment) {
|
|
33
|
+
const lines = [`Codeman dependency check — ${environment}`, ''];
|
|
34
|
+
for (const category of CATEGORY_ORDER) {
|
|
35
|
+
const rows = results.filter((r) => r.category === category);
|
|
36
|
+
if (rows.length === 0)
|
|
37
|
+
continue;
|
|
38
|
+
lines.push(category.toUpperCase());
|
|
39
|
+
for (const r of rows) {
|
|
40
|
+
const detail = r.path ? ` ${r.path}` : '';
|
|
41
|
+
lines.push(` ${glyph(r)} ${r.label.padEnd(14)} ${statusText(r).padEnd(22)}${detail}`);
|
|
42
|
+
if (r.usedBy.length)
|
|
43
|
+
lines.push(` used by: ${r.usedBy.join(', ')}`);
|
|
44
|
+
if (r.installHint)
|
|
45
|
+
lines.push(` install: ${r.installHint}`);
|
|
46
|
+
}
|
|
47
|
+
lines.push('');
|
|
48
|
+
}
|
|
49
|
+
const ok = results.filter((r) => r.status === 'ok').length;
|
|
50
|
+
const requiredMissing = results.filter((r) => r.required && r.status !== 'ok' && r.status !== 'skipped').length;
|
|
51
|
+
const optionalMissing = results.filter((r) => !r.required && r.status === 'missing').length;
|
|
52
|
+
lines.push(`Summary: ${ok} ok · ${requiredMissing} required missing · ${optionalMissing} optional missing`);
|
|
53
|
+
return lines.join('\n');
|
|
54
|
+
}
|
|
55
|
+
export function renderJson(results, environment) {
|
|
56
|
+
const byStatus = (s) => results.filter((r) => r.status === s).length;
|
|
57
|
+
return {
|
|
58
|
+
platform: { environment },
|
|
59
|
+
summary: {
|
|
60
|
+
ok: byStatus('ok'),
|
|
61
|
+
requiredMissing: results.filter((r) => r.required && r.status !== 'ok' && r.status !== 'skipped').length,
|
|
62
|
+
optionalMissing: results.filter((r) => !r.required && r.status === 'missing').length,
|
|
63
|
+
exitCode: computeExitCode(results),
|
|
64
|
+
},
|
|
65
|
+
tools: results,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=dependency-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dependency-report.js","sourceRoot":"","sources":["../../src/utils/dependency-report.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,16 +23,12 @@ interface AuthState {
|
|
|
23
23
|
* Register HTTP Basic Auth middleware with session cookies and rate limiting.
|
|
24
24
|
* Only active when CODEMAN_PASSWORD is set.
|
|
25
25
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
* the bypass additionally requires the shared hook secret (COD-54). When no
|
|
30
|
-
* tunnel is running (loopback-only, the normal case) the plain localhost bypass
|
|
31
|
-
* is kept so already-deployed (pre-secret) hooks + the loop channel keep working.
|
|
32
|
-
* Optional; defaults to "no tunnel" (unchanged behavior) when omitted.
|
|
26
|
+
* The `/api/hook-event` + `/api/status-telemetry` localhost bypass requires the
|
|
27
|
+
* shared hook secret unconditionally (COD-91) — see the onRequest hook below.
|
|
28
|
+
*
|
|
33
29
|
* @returns AuthState for lifecycle management (dispose on server stop)
|
|
34
30
|
*/
|
|
35
|
-
export declare function registerAuthMiddleware(app: FastifyInstance, https: boolean
|
|
31
|
+
export declare function registerAuthMiddleware(app: FastifyInstance, https: boolean): AuthState;
|
|
36
32
|
/**
|
|
37
33
|
* Register the anti-DNS-rebinding Host allowlist + cross-site (CSRF) Origin guard.
|
|
38
34
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/web/middleware/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,SAAS,CAAC;AAE7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAgD,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAU1G,eAAO,MAAM,gBAAgB,oBAAoB,CAAC;AAElD,8EAA8E;AAC9E,UAAU,SAAS;IACjB,YAAY,EAAE,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,IAAI,CAAC;IACnE,YAAY,EAAE,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACxD,cAAc,EAAE,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAC1D,kBAAkB,EAAE,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;CAC/D;AAED
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/web/middleware/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAgB,MAAM,SAAS,CAAC;AAE7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAgD,KAAK,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAU1G,eAAO,MAAM,gBAAgB,oBAAoB,CAAC;AAElD,8EAA8E;AAC9E,UAAU,SAAS;IACjB,YAAY,EAAE,kBAAkB,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAAG,IAAI,CAAC;IACnE,YAAY,EAAE,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACxD,cAAc,EAAE,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IAC1D,kBAAkB,EAAE,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;CAC/D;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,SAAS,CAoKtF;AAKD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,UAAU,GAAG,IAAI,CAazF;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAqDlF"}
|
|
@@ -18,16 +18,12 @@ export const AUTH_COOKIE_NAME = 'codeman_session';
|
|
|
18
18
|
* Register HTTP Basic Auth middleware with session cookies and rate limiting.
|
|
19
19
|
* Only active when CODEMAN_PASSWORD is set.
|
|
20
20
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* the bypass additionally requires the shared hook secret (COD-54). When no
|
|
25
|
-
* tunnel is running (loopback-only, the normal case) the plain localhost bypass
|
|
26
|
-
* is kept so already-deployed (pre-secret) hooks + the loop channel keep working.
|
|
27
|
-
* Optional; defaults to "no tunnel" (unchanged behavior) when omitted.
|
|
21
|
+
* The `/api/hook-event` + `/api/status-telemetry` localhost bypass requires the
|
|
22
|
+
* shared hook secret unconditionally (COD-91) — see the onRequest hook below.
|
|
23
|
+
*
|
|
28
24
|
* @returns AuthState for lifecycle management (dispose on server stop)
|
|
29
25
|
*/
|
|
30
|
-
export function registerAuthMiddleware(app, https
|
|
26
|
+
export function registerAuthMiddleware(app, https) {
|
|
31
27
|
const state = {
|
|
32
28
|
authSessions: null,
|
|
33
29
|
authFailures: null,
|
|
@@ -73,36 +69,33 @@ export function registerAuthMiddleware(app, https, getTunnelRunning = () => fals
|
|
|
73
69
|
reply.code(429).send('Too Many Requests — try again later');
|
|
74
70
|
}
|
|
75
71
|
app.addHook('onRequest', (req, reply, done) => {
|
|
76
|
-
// Hook events come from local Claude Code
|
|
77
|
-
// Basic-Auth credentials available. Validated downstream by
|
|
72
|
+
// Hook events + statusline telemetry come from local Claude Code (curl from
|
|
73
|
+
// localhost) — no Basic-Auth credentials available. Validated downstream by
|
|
74
|
+
// HookEventSchema / StatusTelemetrySchema. Same loopback+hook-secret gate.
|
|
78
75
|
//
|
|
79
76
|
// COD-54: the bare localhost bypass is unsafe while a tunnel is running, because
|
|
80
77
|
// `cloudflared --url http://127.0.0.1:port` proxies internet traffic INTO the
|
|
81
78
|
// loopback origin, so a tunneled request arrives with req.ip === 127.0.0.1 and
|
|
82
|
-
// would pass.
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
|
|
79
|
+
// would pass. COD-91: require the shared hook secret on the loopback bypass
|
|
80
|
+
// UNCONDITIONALLY (not just while the managed tunnel is up). Codeman can't detect
|
|
81
|
+
// a user's own loopback reverse proxy (their own `cloudflared --url`, `tailscale
|
|
82
|
+
// serve`, nginx → 127.0.0.1), so tunnel-gating left that path with the unsafe plain
|
|
83
|
+
// bypass. Managed-session hooks always present the secret (X-Codeman-Hook-Secret,
|
|
84
|
+
// from $CODEMAN_HOOK_SECRET_FILE — generated for every instance), so requiring it
|
|
85
|
+
// always closes the gap without breaking the legitimate hook channel.
|
|
86
|
+
if ((req.url === '/api/hook-event' || req.url === '/api/status-telemetry') && req.method === 'POST') {
|
|
89
87
|
const ip = req.ip;
|
|
90
88
|
const isLoopback = ip === '127.0.0.1' || ip === '::1' || ip === '::ffff:127.0.0.1';
|
|
91
89
|
if (isLoopback) {
|
|
92
|
-
|
|
93
|
-
// Loopback-only: unchanged behavior.
|
|
94
|
-
done();
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
// Tunnel up: require the shared secret (constant-time compare).
|
|
90
|
+
// Always require the shared secret (constant-time compare).
|
|
98
91
|
const presented = Buffer.from(req.headers[HOOK_SECRET_HEADER.toLowerCase()]?.toString() ?? '');
|
|
99
92
|
const expected = Buffer.from(getHookSecret());
|
|
100
93
|
if (presented.length === expected.length && timingSafeEqual(presented, expected)) {
|
|
101
94
|
done();
|
|
102
95
|
return;
|
|
103
96
|
}
|
|
104
|
-
// Wrong/absent secret
|
|
105
|
-
//
|
|
97
|
+
// Wrong/absent secret — rate-limit per IP in the DEDICATED hook bucket
|
|
98
|
+
// (never authFailures, which would lock out the login path).
|
|
106
99
|
const hookIp = req.ip;
|
|
107
100
|
const hookFailures = hookSecretFailures.get(hookIp) ?? 0;
|
|
108
101
|
if (hookFailures >= AUTH_FAILURE_MAX) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/web/middleware/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,OAAO,EAAE,oBAAoB,EAAE,sBAAsB,EAAmB,MAAM,2BAA2B,CAAC;AAC1G,OAAO,EACL,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEhF,2BAA2B;AAC3B,MAAM,CAAC,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAUlD
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/web/middleware/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Process-wide last-known plan-usage telemetry (account-global).
|
|
3
|
+
*
|
|
4
|
+
* The status-telemetry route writes the latest broadcast value here; the SSE
|
|
5
|
+
* init snapshot (`getLightState`) replays it so the header "Plan Usage Limits"
|
|
6
|
+
* chip shows immediately on a fresh page load / SSE reconnect — before any new
|
|
7
|
+
* statusline render arrives, and without relying on per-browser localStorage.
|
|
8
|
+
*
|
|
9
|
+
* Null until the first telemetry of the process; cleared naturally on restart.
|
|
10
|
+
*
|
|
11
|
+
* @module plan-usage-latest
|
|
12
|
+
*/
|
|
13
|
+
export declare function setLatestPlanUsage(value: Record<string, unknown>): void;
|
|
14
|
+
export declare function getLatestPlanUsage(): Record<string, unknown> | null;
|
|
15
|
+
//# sourceMappingURL=plan-usage-latest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-usage-latest.d.ts","sourceRoot":"","sources":["../../src/web/plan-usage-latest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEvE;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEnE"}
|