@prism-d1/cli 1.1.2 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/dist/assets/github-workflows/prism-agent-eval.yml +2 -1
  2. package/dist/assets/github-workflows/prism-eval-gate-kiro.yml +11 -1
  3. package/dist/assets/gitlab-workflows/prism-eval-gate.yml +8 -0
  4. package/dist/assets/infra/lib/constructs/otel-collector-construct.ts +96 -0
  5. package/dist/assets/infra/lib/dashboard-stack.ts +27 -0
  6. package/dist/assets/infra/lib/lambda/otel-receiver.ts +278 -8
  7. package/dist/assets/infra/lib/lambda/pricing/litellm-snapshot.json +3769 -0
  8. package/dist/assets/infra/lib/lambda/pricing/price-source.ts +56 -0
  9. package/dist/assets/infra/lib/lambda/pricing/price-table.ts +240 -0
  10. package/dist/assets/infra/lib/lambda/pricing/prices-key.ts +6 -0
  11. package/dist/assets/infra/lib/lambda/pricing/reprice.ts +108 -0
  12. package/dist/assets/infra/lib/lambda/pricing-refresh.ts +352 -0
  13. package/dist/assets/infra/lib/lambda/velocity-widget.ts +124 -1
  14. package/dist/assets/infra/package.json +4 -1
  15. package/dist/assets/metric-hooks/prepare-commit-msg +3 -1
  16. package/dist/src/codewatch/config.d.ts +17 -0
  17. package/dist/src/codewatch/config.d.ts.map +1 -0
  18. package/dist/src/codewatch/config.js +40 -0
  19. package/dist/src/codewatch/config.js.map +1 -0
  20. package/dist/src/codewatch/gitleaks.d.ts +49 -0
  21. package/dist/src/codewatch/gitleaks.d.ts.map +1 -0
  22. package/dist/src/codewatch/gitleaks.js +160 -0
  23. package/dist/src/codewatch/gitleaks.js.map +1 -0
  24. package/dist/src/codewatch/globalHooks.d.ts +52 -0
  25. package/dist/src/codewatch/globalHooks.d.ts.map +1 -0
  26. package/dist/src/codewatch/globalHooks.js +235 -0
  27. package/dist/src/codewatch/globalHooks.js.map +1 -0
  28. package/dist/src/codewatch/hooks.d.ts +38 -0
  29. package/dist/src/codewatch/hooks.d.ts.map +1 -0
  30. package/dist/src/codewatch/hooks.js +176 -0
  31. package/dist/src/codewatch/hooks.js.map +1 -0
  32. package/dist/src/codewatch/prepush.d.ts +37 -0
  33. package/dist/src/codewatch/prepush.d.ts.map +1 -0
  34. package/dist/src/codewatch/prepush.js +231 -0
  35. package/dist/src/codewatch/prepush.js.map +1 -0
  36. package/dist/src/codewatch/results.d.ts +90 -0
  37. package/dist/src/codewatch/results.d.ts.map +1 -0
  38. package/dist/src/codewatch/results.js +121 -0
  39. package/dist/src/codewatch/results.js.map +1 -0
  40. package/dist/src/codewatch/reviewers/claude.d.ts +9 -0
  41. package/dist/src/codewatch/reviewers/claude.d.ts.map +1 -0
  42. package/dist/src/codewatch/reviewers/claude.js +48 -0
  43. package/dist/src/codewatch/reviewers/claude.js.map +1 -0
  44. package/dist/src/codewatch/reviewers/index.d.ts +39 -0
  45. package/dist/src/codewatch/reviewers/index.d.ts.map +1 -0
  46. package/dist/src/codewatch/reviewers/index.js +97 -0
  47. package/dist/src/codewatch/reviewers/index.js.map +1 -0
  48. package/dist/src/codewatch/reviewers/kiro.d.ts +14 -0
  49. package/dist/src/codewatch/reviewers/kiro.d.ts.map +1 -0
  50. package/dist/src/codewatch/reviewers/kiro.js +32 -0
  51. package/dist/src/codewatch/reviewers/kiro.js.map +1 -0
  52. package/dist/src/codewatch/reviewers/types.d.ts +56 -0
  53. package/dist/src/codewatch/reviewers/types.d.ts.map +1 -0
  54. package/dist/src/codewatch/reviewers/types.js +91 -0
  55. package/dist/src/codewatch/reviewers/types.js.map +1 -0
  56. package/dist/src/codewatch/rules.d.ts +12 -0
  57. package/dist/src/codewatch/rules.d.ts.map +1 -0
  58. package/dist/src/codewatch/rules.js +27 -0
  59. package/dist/src/codewatch/rules.js.map +1 -0
  60. package/dist/src/commands/_top/dashboard.d.ts +17 -0
  61. package/dist/src/commands/_top/dashboard.d.ts.map +1 -0
  62. package/dist/src/commands/_top/dashboard.js +76 -0
  63. package/dist/src/commands/_top/dashboard.js.map +1 -0
  64. package/dist/src/commands/bedrock-protection/scan-account.d.ts.map +1 -1
  65. package/dist/src/commands/bedrock-protection/scan-account.js +2 -1
  66. package/dist/src/commands/bedrock-protection/scan-account.js.map +1 -1
  67. package/dist/src/commands/bedrock-protection/scan-org.d.ts.map +1 -1
  68. package/dist/src/commands/bedrock-protection/scan-org.js +16 -4
  69. package/dist/src/commands/bedrock-protection/scan-org.js.map +1 -1
  70. package/dist/src/commands/bootstrapper/install-eval-harness.d.ts.map +1 -1
  71. package/dist/src/commands/bootstrapper/install-eval-harness.js +15 -48
  72. package/dist/src/commands/bootstrapper/install-eval-harness.js.map +1 -1
  73. package/dist/src/commands/bootstrapper/install-git-hooks.d.ts +13 -0
  74. package/dist/src/commands/bootstrapper/install-git-hooks.d.ts.map +1 -1
  75. package/dist/src/commands/bootstrapper/install-git-hooks.js +28 -147
  76. package/dist/src/commands/bootstrapper/install-git-hooks.js.map +1 -1
  77. package/dist/src/commands/bootstrapper/setup-otel-sync.d.ts.map +1 -1
  78. package/dist/src/commands/bootstrapper/setup-otel-sync.js +5 -39
  79. package/dist/src/commands/bootstrapper/setup-otel-sync.js.map +1 -1
  80. package/dist/src/commands/codewatch/pre-commit.d.ts +7 -0
  81. package/dist/src/commands/codewatch/pre-commit.d.ts.map +1 -0
  82. package/dist/src/commands/codewatch/pre-commit.js +30 -0
  83. package/dist/src/commands/codewatch/pre-commit.js.map +1 -0
  84. package/dist/src/commands/codewatch/pre-push.d.ts +16 -0
  85. package/dist/src/commands/codewatch/pre-push.d.ts.map +1 -0
  86. package/dist/src/commands/codewatch/pre-push.js +32 -0
  87. package/dist/src/commands/codewatch/pre-push.js.map +1 -0
  88. package/dist/src/commands/codewatch/report.d.ts +22 -0
  89. package/dist/src/commands/codewatch/report.d.ts.map +1 -0
  90. package/dist/src/commands/codewatch/report.js +64 -0
  91. package/dist/src/commands/codewatch/report.js.map +1 -0
  92. package/dist/src/commands/enable/codewatch.d.ts +15 -0
  93. package/dist/src/commands/enable/codewatch.d.ts.map +1 -0
  94. package/dist/src/commands/enable/codewatch.js +186 -0
  95. package/dist/src/commands/enable/codewatch.js.map +1 -0
  96. package/dist/src/commands/git/claude-session-context.d.ts.map +1 -1
  97. package/dist/src/commands/git/claude-session-context.js +2 -1
  98. package/dist/src/commands/git/claude-session-context.js.map +1 -1
  99. package/dist/src/commands/git/commit-trailers.js +1 -1
  100. package/dist/src/commands/git/commit-trailers.js.map +1 -1
  101. package/dist/src/commands/workshop/verify-setup.d.ts.map +1 -1
  102. package/dist/src/commands/workshop/verify-setup.js +5 -3
  103. package/dist/src/commands/workshop/verify-setup.js.map +1 -1
  104. package/dist/src/dashboard/codewatch.d.ts +106 -0
  105. package/dist/src/dashboard/codewatch.d.ts.map +1 -0
  106. package/dist/src/dashboard/codewatch.js +119 -0
  107. package/dist/src/dashboard/codewatch.js.map +1 -0
  108. package/dist/src/dashboard/commits.d.ts +96 -0
  109. package/dist/src/dashboard/commits.d.ts.map +1 -0
  110. package/dist/src/dashboard/commits.js +207 -0
  111. package/dist/src/dashboard/commits.js.map +1 -0
  112. package/dist/src/dashboard/page.d.ts +10 -0
  113. package/dist/src/dashboard/page.d.ts.map +1 -0
  114. package/dist/src/dashboard/page.js +315 -0
  115. package/dist/src/dashboard/page.js.map +1 -0
  116. package/dist/src/dashboard/payload.d.ts +111 -0
  117. package/dist/src/dashboard/payload.d.ts.map +1 -0
  118. package/dist/src/dashboard/payload.js +93 -0
  119. package/dist/src/dashboard/payload.js.map +1 -0
  120. package/dist/src/dashboard/report.d.ts +99 -0
  121. package/dist/src/dashboard/report.d.ts.map +1 -0
  122. package/dist/src/dashboard/report.js +300 -0
  123. package/dist/src/dashboard/report.js.map +1 -0
  124. package/dist/src/dashboard/repos.d.ts +58 -0
  125. package/dist/src/dashboard/repos.d.ts.map +1 -0
  126. package/dist/src/dashboard/repos.js +111 -0
  127. package/dist/src/dashboard/repos.js.map +1 -0
  128. package/dist/src/dashboard/server.d.ts +52 -0
  129. package/dist/src/dashboard/server.d.ts.map +1 -0
  130. package/dist/src/dashboard/server.js +163 -0
  131. package/dist/src/dashboard/server.js.map +1 -0
  132. package/dist/src/dashboard/setup.d.ts +52 -0
  133. package/dist/src/dashboard/setup.d.ts.map +1 -0
  134. package/dist/src/dashboard/setup.js +129 -0
  135. package/dist/src/dashboard/setup.js.map +1 -0
  136. package/dist/src/dashboard/usage.d.ts +43 -0
  137. package/dist/src/dashboard/usage.d.ts.map +1 -0
  138. package/dist/src/dashboard/usage.js +88 -0
  139. package/dist/src/dashboard/usage.js.map +1 -0
  140. package/dist/src/index.d.ts +1 -0
  141. package/dist/src/index.d.ts.map +1 -1
  142. package/dist/src/index.js +40 -1
  143. package/dist/src/index.js.map +1 -1
  144. package/dist/src/utils/audit-bedrock.d.ts +1 -0
  145. package/dist/src/utils/audit-bedrock.d.ts.map +1 -1
  146. package/dist/src/utils/audit-bedrock.js +133 -0
  147. package/dist/src/utils/audit-bedrock.js.map +1 -1
  148. package/dist/src/utils/audit-org.d.ts +1 -0
  149. package/dist/src/utils/audit-org.d.ts.map +1 -1
  150. package/dist/src/utils/audit-org.js +155 -0
  151. package/dist/src/utils/audit-org.js.map +1 -1
  152. package/dist/src/utils/otel-sync-schedule.d.ts +22 -0
  153. package/dist/src/utils/otel-sync-schedule.d.ts.map +1 -0
  154. package/dist/src/utils/otel-sync-schedule.js +68 -0
  155. package/dist/src/utils/otel-sync-schedule.js.map +1 -0
  156. package/dist/src/utils/tool-check.d.ts +14 -0
  157. package/dist/src/utils/tool-check.d.ts.map +1 -0
  158. package/dist/src/utils/tool-check.js +42 -0
  159. package/dist/src/utils/tool-check.js.map +1 -0
  160. package/package.json +3 -2
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Loopback-only HTTP server for `prism-cli dashboard`.
3
+ *
4
+ * Access control, all enforced on every request:
5
+ * - bound to 127.0.0.1 only (the host is a constant, not an option);
6
+ * - a per-run 256-bit random token, accepted once from `/?token=` and
7
+ * exchanged for an HttpOnly, SameSite=Strict cookie, then required as that
8
+ * cookie on every request (compared in constant time);
9
+ * - the Host header must be 127.0.0.1:<port> or localhost:<port>, which
10
+ * defeats DNS rebinding (a rebound name arrives with its own Host);
11
+ * - GET only, read-only routes, no CORS headers, strict CSP.
12
+ *
13
+ * Why a minted token and not a platform auth mechanism: the server is
14
+ * reachable only from this machine, the audience is the developer running it,
15
+ * and the CLI ships as public sample code, so it uses the loopback-plus-token
16
+ * pattern native to local developer tools (Jupyter, VS Code server) rather
17
+ * than any hosted identity provider. It must never be bound beyond loopback.
18
+ */
19
+ import { createServer } from 'node:http';
20
+ import { randomBytes, timingSafeEqual } from 'node:crypto';
21
+ import { renderPage } from './page.js';
22
+ import { renderReportHtml, renderReportMarkdown } from './report.js';
23
+ export const BIND_HOST = '127.0.0.1';
24
+ export function newToken() {
25
+ return randomBytes(32).toString('base64url');
26
+ }
27
+ export function cookieName(port) {
28
+ // Cookies are scoped by host, not port: two dashboards on different ports
29
+ // would otherwise overwrite each other's cookie.
30
+ return `prism_dash_${port}`;
31
+ }
32
+ function safeEqual(a, b) {
33
+ const x = Buffer.from(a);
34
+ const y = Buffer.from(b);
35
+ return x.length === y.length && timingSafeEqual(x, y);
36
+ }
37
+ function readCookie(req, name) {
38
+ const raw = req.headers.cookie;
39
+ if (!raw)
40
+ return null;
41
+ for (const part of raw.split(';')) {
42
+ const i = part.indexOf('=');
43
+ if (i > 0 && part.slice(0, i).trim() === name)
44
+ return part.slice(i + 1).trim();
45
+ }
46
+ return null;
47
+ }
48
+ function baseHeaders(nonce) {
49
+ const csp = nonce
50
+ ? `default-src 'none'; script-src 'nonce-${nonce}'; style-src 'nonce-${nonce}'; connect-src 'self'; img-src 'self' data:; base-uri 'none'; form-action 'none'; frame-ancestors 'none'`
51
+ : "default-src 'none'; frame-ancestors 'none'";
52
+ return {
53
+ 'Content-Security-Policy': csp,
54
+ 'X-Content-Type-Options': 'nosniff',
55
+ 'X-Frame-Options': 'DENY',
56
+ 'Referrer-Policy': 'no-referrer',
57
+ 'Cache-Control': 'no-store',
58
+ 'Cross-Origin-Resource-Policy': 'same-origin',
59
+ };
60
+ }
61
+ function send(res, status, type, body, extra = {}, nonce) {
62
+ res.writeHead(status, { ...baseHeaders(nonce), 'Content-Type': type, ...extra });
63
+ res.end(body);
64
+ }
65
+ /** /report/<id> or /report/<id>.md; anything else (slashes, dots, %-escapes) does not match. */
66
+ const REPORT_ROUTE = /^\/report\/([A-Za-z0-9_-]{1,120})(\.md)?$/;
67
+ export function createHandler(opts) {
68
+ return async (req, res) => {
69
+ try {
70
+ const port = opts.getPort();
71
+ const host = String(req.headers.host || '').toLowerCase();
72
+ if (host !== `${BIND_HOST}:${port}` && host !== `localhost:${port}`) {
73
+ return send(res, 403, 'text/plain; charset=utf-8', 'Forbidden: unexpected Host header\n');
74
+ }
75
+ if (req.method !== 'GET') {
76
+ return send(res, 405, 'text/plain; charset=utf-8', 'Method Not Allowed\n', { Allow: 'GET' });
77
+ }
78
+ const url = new URL(req.url || '/', `http://${BIND_HOST}:${port}`);
79
+ const name = cookieName(port);
80
+ const cookie = readCookie(req, name);
81
+ const cookieOk = cookie !== null && safeEqual(cookie, opts.token);
82
+ // First load: exchange the URL token for the cookie, then drop it from the URL.
83
+ const qToken = url.searchParams.get('token');
84
+ if (url.pathname === '/' && qToken !== null) {
85
+ if (!safeEqual(qToken, opts.token))
86
+ return send(res, 401, 'text/plain; charset=utf-8', 'Unauthorized\n');
87
+ return send(res, 303, 'text/plain; charset=utf-8', 'See Other\n', {
88
+ Location: '/',
89
+ 'Set-Cookie': `${name}=${opts.token}; HttpOnly; SameSite=Strict; Path=/`,
90
+ });
91
+ }
92
+ if (!cookieOk) {
93
+ return send(res, 401, 'text/plain; charset=utf-8', 'Unauthorized: open the URL printed by prism-cli dashboard\n');
94
+ }
95
+ if (url.pathname === '/') {
96
+ const nonce = randomBytes(16).toString('base64');
97
+ return send(res, 200, 'text/html; charset=utf-8', renderPage(nonce), {}, nonce);
98
+ }
99
+ if (url.pathname === '/api/data') {
100
+ const payload = await opts.getPayload();
101
+ return send(res, 200, 'application/json; charset=utf-8', JSON.stringify(payload));
102
+ }
103
+ const m = REPORT_ROUTE.exec(url.pathname);
104
+ if (m && opts.getReport) {
105
+ const report = await opts.getReport(m[1]);
106
+ if (!report)
107
+ return send(res, 404, 'text/plain; charset=utf-8', 'Report not found\n');
108
+ if (m[2]) {
109
+ return send(res, 200, 'text/markdown; charset=utf-8', renderReportMarkdown(report), {
110
+ 'Content-Disposition': `attachment; filename="codewatch-report-${m[1]}.md"`,
111
+ });
112
+ }
113
+ const nonce = randomBytes(16).toString('base64');
114
+ return send(res, 200, 'text/html; charset=utf-8', renderReportHtml(report, { nonce, links: { back: '/', markdown: `/report/${m[1]}.md` } }), {}, nonce);
115
+ }
116
+ return send(res, 404, 'text/plain; charset=utf-8', 'Not Found\n');
117
+ }
118
+ catch (e) {
119
+ if (!res.headersSent)
120
+ send(res, 500, 'text/plain; charset=utf-8', 'Internal Server Error\n');
121
+ else
122
+ res.end();
123
+ process.stderr.write(`prism dashboard: request failed: ${e?.message || e}\n`);
124
+ }
125
+ };
126
+ }
127
+ /** Starts the server on 127.0.0.1. `port` 0 (default) picks a free port. */
128
+ export function startServer(opts) {
129
+ const token = opts.token || newToken();
130
+ let port = 0;
131
+ const server = createServer(createHandler({ token, getPort: () => port, getPayload: opts.getPayload, getReport: opts.getReport }));
132
+ return new Promise((resolve, reject) => {
133
+ server.once('error', reject);
134
+ server.listen(opts.port ?? 0, BIND_HOST, () => {
135
+ const addr = server.address();
136
+ if (!addr || typeof addr === 'string' || addr.address !== BIND_HOST) {
137
+ server.close();
138
+ return reject(new Error(`refusing to serve: bound to ${JSON.stringify(addr)}, expected ${BIND_HOST}`));
139
+ }
140
+ port = addr.port;
141
+ resolve({
142
+ server, port, token,
143
+ url: `http://${BIND_HOST}:${port}/?token=${token}`,
144
+ close: () => new Promise((r) => server.close(() => r())),
145
+ });
146
+ });
147
+ });
148
+ }
149
+ /** Memoises the payload for `ttlMs` and shares one in-flight build between requests. */
150
+ export function cachedPayload(build, ttlMs = 30_000) {
151
+ let at = 0;
152
+ let pending = null;
153
+ let value;
154
+ return () => {
155
+ if (value !== undefined && Date.now() - at < ttlMs)
156
+ return Promise.resolve(value);
157
+ if (!pending) {
158
+ pending = build().then((v) => { value = v; at = Date.now(); return v; }).finally(() => { pending = null; });
159
+ }
160
+ return pending;
161
+ };
162
+ }
163
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/dashboard/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import { gitleaksInstallHint } from '../codewatch/gitleaks.js';
2
+ import { type GlobalStatus } from '../codewatch/globalHooks.js';
3
+ export type CheckStatus = 'ok' | 'warn' | 'missing';
4
+ export interface CheckItem {
5
+ id: string;
6
+ label: string;
7
+ status: CheckStatus;
8
+ detail: string;
9
+ /** One-line fix; empty when status is ok. */
10
+ fix: string;
11
+ }
12
+ export interface MachineDeps {
13
+ pathEnv?: string;
14
+ home?: string;
15
+ env?: NodeJS.ProcessEnv;
16
+ scheduleExists?: () => boolean;
17
+ schedulerName?: () => string;
18
+ /** Global codewatch hooks state; computed once by the payload builder. */
19
+ global?: GlobalStatus;
20
+ }
21
+ export declare const GLOBAL_INSTALL_CMD = "prism-cli enable codewatch --global";
22
+ export declare const GLOBAL_FORCE_CMD = "prism-cli enable codewatch --global --force";
23
+ /** The machine row for the global hooks (~/.prism/hooks via git config --global core.hooksPath). */
24
+ export declare function globalHooksCheck(g: GlobalStatus): CheckItem;
25
+ export { gitleaksInstallHint };
26
+ /** Checks that do not depend on a repository. */
27
+ export declare function machineChecks(deps?: MachineDeps): CheckItem[];
28
+ export interface CodewatchSetup {
29
+ /**
30
+ * ok: codewatch runs here (per-repo hooks, or the global hooks).
31
+ * warn: the global hooks are installed but this repo's own core.hooksPath bypasses them.
32
+ * opted-out: git config prism.codewatch false.
33
+ * missing: anything else (including hooks from before the rename).
34
+ */
35
+ status: 'ok' | 'warn' | 'missing' | 'opted-out';
36
+ /** Covered by the global hooks rather than per-repo hooks. */
37
+ global: boolean;
38
+ /** Reviewer the pre-push review would use here, or null when none is available. */
39
+ reviewer: string | null;
40
+ /** Where that choice came from: git-config, prism-config, detected, fallback or none. */
41
+ reviewerSource: string;
42
+ detail: string;
43
+ /** Empty when ok. */
44
+ fix: string;
45
+ }
46
+ export declare function enableCodewatchFix(repo: string): string;
47
+ /** The only per-repo check: does codewatch run here (per repo or globally), and which reviewer would run. */
48
+ export declare function codewatchSetup(repo: string, deps?: {
49
+ pathEnv?: string;
50
+ global?: GlobalStatus;
51
+ }): CodewatchSetup;
52
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../../src/dashboard/setup.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAA6E,KAAK,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAK3I,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;AACpD,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,WAAW,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC;IAC/B,aAAa,CAAC,EAAE,MAAM,MAAM,CAAC;IAC7B,0EAA0E;IAC1E,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,eAAO,MAAM,kBAAkB,wCAAwC,CAAC;AACxE,eAAO,MAAM,gBAAgB,gDAAgD,CAAC;AAE9E,oGAAoG;AACpG,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,YAAY,GAAG,SAAS,CAY3D;AAGD,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAM/B,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,IAAI,GAAE,WAAgB,GAAG,SAAS,EAAE,CAwCjE;AAWD,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,MAAM,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC;IAChD,8DAA8D;IAC9D,MAAM,EAAE,OAAO,CAAC;IAChB,mFAAmF;IACnF,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,yFAAyF;IACzF,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAOD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEvD;AAOD,6GAA6G;AAC7G,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,YAAY,CAAA;CAAO,GAAG,cAAc,CA+BnH"}
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Setup checklist. Local evidence only: no AWS, GitHub or GitLab calls, and no
3
+ * credential file is opened (only its existence is checked).
4
+ */
5
+ import { spawnSync } from 'node:child_process';
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import { homedir } from 'node:os';
8
+ import { join, resolve } from 'node:path';
9
+ import { checkTool } from '../utils/tool-check.js';
10
+ import { lastSync, scheduleExists, schedulerName } from '../utils/otel-sync-schedule.js';
11
+ import { HOOK_MARKER, MANAGED_HOOKS } from '../codewatch/hooks.js';
12
+ import { gitleaksInstallHint } from '../codewatch/gitleaks.js';
13
+ import { globalHooksDir, globalStatus, isOptedOut, OPT_OUT_KEY, repoLocalHooksPath } from '../codewatch/globalHooks.js';
14
+ import { realpathSync } from 'node:fs';
15
+ import { readEvalConfig, REVIEWER_GIT_CONFIG_KEY } from '../codewatch/config.js';
16
+ import { detectReviewers, resolveReviewer } from '../codewatch/reviewers/index.js';
17
+ export const GLOBAL_INSTALL_CMD = 'prism-cli enable codewatch --global';
18
+ export const GLOBAL_FORCE_CMD = 'prism-cli enable codewatch --global --force';
19
+ /** The machine row for the global hooks (~/.prism/hooks via git config --global core.hooksPath). */
20
+ export function globalHooksCheck(g) {
21
+ const label = 'Codewatch global hooks';
22
+ switch (g.state) {
23
+ case 'installed':
24
+ return item('codewatch-global', label, 'ok', 'core.hooksPath -> ~/.prism/hooks; every repo is covered');
25
+ case 'elsewhere':
26
+ return item('codewatch-global', label, 'warn', `global core.hooksPath points to ${g.hooksPath}`, `${GLOBAL_FORCE_CMD} (its hooks still run)`);
27
+ case 'incomplete':
28
+ return item('codewatch-global', label, 'warn', 'core.hooksPath points to ~/.prism/hooks but its hooks are missing', GLOBAL_INSTALL_CMD);
29
+ default:
30
+ return item('codewatch-global', label, 'missing', 'not installed (optional: covers every repo at once)', GLOBAL_INSTALL_CMD);
31
+ }
32
+ }
33
+ // Shared with enable codewatch and the pre-commit warning so the three cannot drift.
34
+ export { gitleaksInstallHint };
35
+ const item = (id, label, status, detail, fix = '') => ({ id, label, status, detail, fix: status === 'ok' ? '' : fix });
36
+ const AWS_ENV_VARS = ['AWS_PROFILE', 'AWS_ACCESS_KEY_ID', 'AWS_WEB_IDENTITY_TOKEN_FILE', 'AWS_CONTAINER_CREDENTIALS_FULL_URI', 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI'];
37
+ /** Checks that do not depend on a repository. */
38
+ export function machineChecks(deps = {}) {
39
+ const env = deps.env || process.env;
40
+ const home = deps.home || homedir();
41
+ const out = [];
42
+ const cb = checkTool('codeburn', { pathEnv: deps.pathEnv });
43
+ out.push(item('codeburn', 'codeburn installed', cb.installed ? 'ok' : 'missing', cb.installed ? (cb.version || 'version unknown') : 'not on PATH', 'npm install -g codeburn'));
44
+ const hasSchedule = (deps.scheduleExists || scheduleExists)();
45
+ const sched = (deps.schedulerName || schedulerName)();
46
+ const last = lastSync(home);
47
+ if (hasSchedule) {
48
+ out.push(item('codeburn-sync', 'Scheduled codeburn sync push', last ? 'ok' : 'warn', last ? `${sched} entry installed; last sync log write ${last.at}` : `${sched} entry installed; no sync log yet in ~/.prism/logs`, 'Wait for the next run, or check ~/.prism/logs/otel-sync.log'));
49
+ }
50
+ else {
51
+ out.push(item('codeburn-sync', 'Scheduled codeburn sync push', 'missing', `no ${sched} entry${last ? `; last sync log write ${last.at}` : ''}`, 'prism-cli bootstrapper setup-otel-sync'));
52
+ }
53
+ const gl = checkTool('gitleaks', { pathEnv: deps.pathEnv, versionArgs: ['version'] });
54
+ // warn, not missing: commits are still allowed, just not secret-scanned (decided).
55
+ out.push(item('gitleaks', 'gitleaks available', gl.installed ? 'ok' : 'warn', gl.installed ? (gl.version || 'version unknown') : 'not on PATH; secret scanning is off and commits are not scanned', gitleaksInstallHint()));
56
+ // Presence only. STS is never called and no credential or config file is read.
57
+ const envVar = AWS_ENV_VARS.find((k) => env[k]);
58
+ const configFile = env.AWS_CONFIG_FILE || join(home, '.aws', 'config');
59
+ const credsFile = env.AWS_SHARED_CREDENTIALS_FILE || join(home, '.aws', 'credentials');
60
+ const files = [configFile, credsFile].filter((f) => existsSync(f));
61
+ const awsOk = Boolean(envVar) || files.length > 0;
62
+ out.push(item('aws-credentials', 'AWS credentials configured', awsOk ? 'ok' : 'missing', envVar ? `${envVar} is set${envVar === 'AWS_PROFILE' ? ` (${env.AWS_PROFILE})` : ''} (not validated)`
63
+ : files.length ? `AWS config present (${files.length === 2 ? 'config and credentials files' : 'one file'}; not validated)`
64
+ : 'no AWS env var or ~/.aws config found', "aws configure (or aws sso login); then validate with 'aws sts get-caller-identity'"));
65
+ out.push(globalHooksCheck(deps.global || globalStatus(home)));
66
+ return out;
67
+ }
68
+ function git(repo, args) {
69
+ const r = spawnSync('git', ['-C', repo, ...args], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
70
+ return r.status === 0 ? r.stdout.trim() : null;
71
+ }
72
+ function readText(p) {
73
+ try {
74
+ return readFileSync(p, 'utf8');
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ }
80
+ /** Shell-quotes a path for the copy-paste fix line. */
81
+ function shellPath(p) {
82
+ return /^[A-Za-z0-9_./~+-]+$/.test(p) ? p : `'${p.replace(/'/g, `'\\''`)}'`;
83
+ }
84
+ export function enableCodewatchFix(repo) {
85
+ return `cd ${shellPath(repo)} && prism-cli enable codewatch`;
86
+ }
87
+ function samePath(a, b) {
88
+ const n = (p) => { try {
89
+ return realpathSync(p);
90
+ }
91
+ catch {
92
+ return resolve(p);
93
+ } };
94
+ return n(a) === n(b);
95
+ }
96
+ /** The only per-repo check: does codewatch run here (per repo or globally), and which reviewer would run. */
97
+ export function codewatchSetup(repo, deps = {}) {
98
+ const g = deps.global || globalStatus();
99
+ const hooksDir = git(repo, ['rev-parse', '--path-format=absolute', '--git-path', 'hooks']) || resolve(repo, '.git/hooks');
100
+ const viaGlobal = g.state === 'installed' && samePath(hooksDir, globalHooksDir());
101
+ const state = MANAGED_HOOKS.map((h) => {
102
+ const t = readText(resolve(hooksDir, h));
103
+ return { h, ours: !!t && t.includes(HOOK_MARKER), old: !!t && !t.includes(HOOK_MARKER) && t.includes('# prism-cli enable security') };
104
+ });
105
+ const choice = resolveReviewer({
106
+ gitConfigValue: git(repo, ['config', '--get', REVIEWER_GIT_CONFIG_KEY]),
107
+ prismConfigValue: readEvalConfig(repo).reviewer,
108
+ available: detectReviewers(deps.pathEnv),
109
+ });
110
+ const reviewer = choice.id;
111
+ const base = { reviewer, reviewerSource: choice.source, global: viaGlobal };
112
+ if (isOptedOut(repo)) {
113
+ return { ...base, status: 'opted-out', fix: '', detail: `opted out (git config ${OPT_OUT_KEY} false)` };
114
+ }
115
+ if (state.every((x) => x.ours)) {
116
+ const where = viaGlobal ? 'covered by the global hooks (global)' : 'pre-commit and pre-push installed';
117
+ return { ...base, status: 'ok', fix: '', detail: reviewer ? where : `${where}; no reviewer on PATH (install kiro-cli or Claude Code)` };
118
+ }
119
+ const local = repoLocalHooksPath(repo);
120
+ if (local && g.state === 'installed') {
121
+ return { ...base, status: 'warn', fix: enableCodewatchFix(repo),
122
+ detail: `this repo's core.hooksPath (${local}) bypasses the global hooks; install codewatch into it` };
123
+ }
124
+ const have = state.filter((x) => x.ours).map((x) => x.h);
125
+ const detail = state.some((x) => x.old) ? 'hooks from before the codewatch rename'
126
+ : have.length ? `only ${have.join(', ')} installed` : 'not installed';
127
+ return { ...base, status: 'missing', detail, fix: enableCodewatchFix(repo) };
128
+ }
129
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../src/dashboard/setup.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACzF,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,kBAAkB,EAAqB,MAAM,6BAA6B,CAAC;AAC3I,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAsBnF,MAAM,CAAC,MAAM,kBAAkB,GAAG,qCAAqC,CAAC;AACxE,MAAM,CAAC,MAAM,gBAAgB,GAAG,6CAA6C,CAAC;AAE9E,oGAAoG;AACpG,MAAM,UAAU,gBAAgB,CAAC,CAAe;IAC9C,MAAM,KAAK,GAAG,wBAAwB,CAAC;IACvC,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC;QAChB,KAAK,WAAW;YACd,OAAO,IAAI,CAAC,kBAAkB,EAAE,KAAK,EAAE,IAAI,EAAE,yDAAyD,CAAC,CAAC;QAC1G,KAAK,WAAW;YACd,OAAO,IAAI,CAAC,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,mCAAmC,CAAC,CAAC,SAAS,EAAE,EAAE,GAAG,gBAAgB,wBAAwB,CAAC,CAAC;QAChJ,KAAK,YAAY;YACf,OAAO,IAAI,CAAC,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,mEAAmE,EAAE,kBAAkB,CAAC,CAAC;QAC1I;YACE,OAAO,IAAI,CAAC,kBAAkB,EAAE,KAAK,EAAE,SAAS,EAAE,qDAAqD,EAAE,kBAAkB,CAAC,CAAC;IACjI,CAAC;AACH,CAAC;AAED,qFAAqF;AACrF,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAE/B,MAAM,IAAI,GAAG,CAAC,EAAU,EAAE,KAAa,EAAE,MAAmB,EAAE,MAAc,EAAE,GAAG,GAAG,EAAE,EAAa,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;AAEvK,MAAM,YAAY,GAAG,CAAC,aAAa,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,oCAAoC,EAAE,wCAAwC,CAAC,CAAC;AAEzK,iDAAiD;AACjD,MAAM,UAAU,aAAa,CAAC,OAAoB,EAAE;IAClD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,EAAE,CAAC;IACpC,MAAM,GAAG,GAAgB,EAAE,CAAC;IAE5B,MAAM,EAAE,GAAG,SAAS,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAC5D,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,oBAAoB,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAC7E,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,yBAAyB,CAAC,CAAC,CAAC;IAEhG,MAAM,WAAW,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,cAAc,CAAC,EAAE,CAAC;IAC9D,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,EAAE,CAAC;IACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,WAAW,EAAE,CAAC;QAChB,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,8BAA8B,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EACjF,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,yCAAyC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,oDAAoD,EAChI,6DAA6D,CAAC,CAAC,CAAC;IACpE,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,8BAA8B,EAAE,SAAS,EACtE,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,yBAAyB,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,wCAAwC,CAAC,CAAC,CAAC;IACrH,CAAC;IAED,MAAM,EAAE,GAAG,SAAS,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IACtF,mFAAmF;IACnF,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,oBAAoB,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,EAC1E,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC,iEAAiE,EACpH,mBAAmB,EAAE,CAAC,CAAC,CAAC;IAE1B,+EAA+E;IAC/E,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAChD,MAAM,UAAU,GAAG,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,GAAG,CAAC,2BAA2B,IAAI,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;IACvF,MAAM,KAAK,GAAG,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAClD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE,4BAA4B,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EACrF,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,UAAU,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC,CAAC,EAAE,kBAAkB;QACnG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,uBAAuB,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,8BAA8B,CAAC,CAAC,CAAC,UAAU,kBAAkB;YACxH,CAAC,CAAC,uCAAuC,EAC7C,oFAAoF,CAAC,CAAC,CAAC;IACzF,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,GAAG,CAAC,IAAY,EAAE,IAAc;IACvC,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7G,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS;IACzB,IAAI,CAAC;QAAC,OAAO,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;AAChE,CAAC;AAqBD,uDAAuD;AACvD,SAAS,SAAS,CAAC,CAAS;IAC1B,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,OAAO,MAAM,SAAS,CAAC,IAAI,CAAC,gCAAgC,CAAC;AAC/D,CAAC;AAED,SAAS,QAAQ,CAAC,CAAS,EAAE,CAAS;IACpC,MAAM,CAAC,GAAG,CAAC,CAAS,EAAE,EAAE,GAAG,IAAI,CAAC;QAAC,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IAAC,CAAC,CAAC,CAAC,CAAC;IAC1F,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,OAAoD,EAAE;IACjG,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,IAAI,YAAY,EAAE,CAAC;IACxC,MAAM,QAAQ,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,wBAAwB,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC1H,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,KAAK,WAAW,IAAI,QAAQ,CAAC,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC;IAClF,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACpC,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;QACzC,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,6BAA6B,CAAC,EAAE,CAAC;IACxI,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,eAAe,CAAC;QAC7B,cAAc,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,uBAAuB,CAAC,CAAC;QACvE,gBAAgB,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC,QAAQ;QAC/C,SAAS,EAAE,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC;KACzC,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IAC5E,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,yBAAyB,WAAW,SAAS,EAAE,CAAC;IAC1G,CAAC;IACD,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,sCAAsC,CAAC,CAAC,CAAC,mCAAmC,CAAC;QACvG,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,yDAAyD,EAAE,CAAC;IAC1I,CAAC;IACD,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,KAAK,IAAI,CAAC,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;QACrC,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,kBAAkB,CAAC,IAAI,CAAC;YAC7D,MAAM,EAAE,+BAA+B,KAAK,wDAAwD,EAAE,CAAC;IAC3G,CAAC;IACD,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,wCAAwC;QAChF,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,eAAe,CAAC;IACxE,OAAO,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;AAC/E,CAAC"}
@@ -0,0 +1,43 @@
1
+ export declare const TOP_N = 5;
2
+ export interface Totals {
3
+ cost: number;
4
+ calls: number;
5
+ sessions: number;
6
+ }
7
+ export interface UsagePanel {
8
+ status: 'ok' | 'not-installed' | 'no-data' | 'error';
9
+ message: string | null;
10
+ currency: string;
11
+ today: Totals | null;
12
+ month: (Totals & {
13
+ from: string;
14
+ to: string;
15
+ }) | null;
16
+ topModels: {
17
+ name: string;
18
+ cost: number;
19
+ calls: number;
20
+ }[];
21
+ /** `name` is the folder name; `path` is codeburn's full project path, for a tooltip. */
22
+ topProjects: {
23
+ name: string;
24
+ path: string;
25
+ cost: number;
26
+ sessions: number;
27
+ }[];
28
+ generated: string | null;
29
+ /** Shown as a note, never a link: codeburn web is a CLI command. */
30
+ fullView: string;
31
+ }
32
+ /** Runs `codeburn export -f json` with extra args and returns the parsed JSON. Injected in tests. */
33
+ export type CodeburnExport = (args: string[]) => Promise<any>;
34
+ export declare function realCodeburnExport(binary: string): CodeburnExport;
35
+ /** Local calendar date, YYYY-MM-DD. */
36
+ export declare function localDate(d: Date): string;
37
+ export declare function emptyUsage(status: UsagePanel['status'], message: string): UsagePanel;
38
+ export declare function collectUsage(opts?: {
39
+ now?: Date;
40
+ exporter?: CodeburnExport;
41
+ pathEnv?: string;
42
+ }): Promise<UsagePanel>;
43
+ //# sourceMappingURL=usage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../../src/dashboard/usage.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,KAAK,IAAI,CAAC;AAGvB,MAAM,WAAW,MAAM;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE;AACzE,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,IAAI,GAAG,eAAe,GAAG,SAAS,GAAG,OAAO,CAAC;IACrD,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,CAAC,MAAM,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC;IACtD,SAAS,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3D,wFAAwF;IACxF,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,qGAAqG;AACrG,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;AAE9D,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAWjE;AAQD,uCAAuC;AACvC,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAGzC;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,MAAM,GAAG,UAAU,CAEpF;AAED,wBAAsB,YAAY,CAAC,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,OAAO,CAAC,UAAU,CAAC,CA4C9H"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Usage panel data, from `codeburn export -f json` (schema codeburn.export.v2,
3
+ * checked against codeburn 0.9.24).
4
+ *
5
+ * Two exports: the default one for "Today", and a `--from <1st of month>
6
+ * --to <today>` one for this calendar month and its top models and projects.
7
+ * codeburn's own charts are not rebuilt; the panel points at `codeburn web`.
8
+ */
9
+ import { execFile } from 'node:child_process';
10
+ import { mkdtempSync, readFileSync, rmSync } from 'node:fs';
11
+ import { tmpdir } from 'node:os';
12
+ import { basename, join } from 'node:path';
13
+ import { promisify } from 'node:util';
14
+ import { findOnPath } from '../utils/tool-check.js';
15
+ const execFileP = promisify(execFile);
16
+ export const TOP_N = 5;
17
+ const EXPORT_TIMEOUT_MS = 60_000;
18
+ export function realCodeburnExport(binary) {
19
+ return async (args) => {
20
+ const dir = mkdtempSync(join(tmpdir(), 'prism-dash-cb-'));
21
+ try {
22
+ const out = join(dir, 'export.json');
23
+ await execFileP(binary, ['export', '-f', 'json', '-o', out, ...args], { timeout: EXPORT_TIMEOUT_MS, maxBuffer: 16 * 1024 * 1024 });
24
+ return JSON.parse(readFileSync(out, 'utf8'));
25
+ }
26
+ finally {
27
+ rmSync(dir, { recursive: true, force: true });
28
+ }
29
+ };
30
+ }
31
+ const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : 0);
32
+ function totalsFrom(row) {
33
+ return { cost: num(row?.['Cost (USD)']), calls: num(row?.['API Calls']), sessions: num(row?.['Sessions']) };
34
+ }
35
+ /** Local calendar date, YYYY-MM-DD. */
36
+ export function localDate(d) {
37
+ const p = (n) => String(n).padStart(2, '0');
38
+ return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}`;
39
+ }
40
+ export function emptyUsage(status, message) {
41
+ return { status, message, currency: 'USD', today: null, month: null, topModels: [], topProjects: [], generated: null, fullView: 'codeburn web' };
42
+ }
43
+ export async function collectUsage(opts = {}) {
44
+ let exporter = opts.exporter;
45
+ if (!exporter) {
46
+ const bin = findOnPath('codeburn', opts.pathEnv);
47
+ if (!bin)
48
+ return emptyUsage('not-installed', 'codeburn is not installed. Install it with: npm install -g codeburn');
49
+ exporter = realCodeburnExport(bin);
50
+ }
51
+ const now = opts.now || new Date();
52
+ const to = localDate(now);
53
+ const from = `${to.slice(0, 8)}01`;
54
+ let base, month;
55
+ try {
56
+ [base, month] = await Promise.all([exporter([]), exporter(['--from', from, '--to', to])]);
57
+ }
58
+ catch (e) {
59
+ return emptyUsage('error', `codeburn export failed: ${String(e?.message || e).split('\n')[0].slice(0, 200)}`);
60
+ }
61
+ if (!String(base?.schema || '').startsWith('codeburn.export.')) {
62
+ return emptyUsage('error', `unrecognised codeburn export schema: ${String(base?.schema).slice(0, 40)}`);
63
+ }
64
+ const todayRow = (Array.isArray(base.summary) ? base.summary : []).find((r) => r?.Period === 'Today');
65
+ const monthRow = Array.isArray(month?.summary) ? month.summary[0] : null;
66
+ const monthModels = Array.isArray(month?.periods?.[0]?.models) ? month.periods[0].models : [];
67
+ const monthProjects = Array.isArray(month?.projects) ? month.projects : [];
68
+ const panel = {
69
+ status: 'ok',
70
+ message: null,
71
+ currency: String(base?.currency?.code || 'USD'),
72
+ today: todayRow ? totalsFrom(todayRow) : { cost: 0, calls: 0, sessions: 0 },
73
+ month: monthRow ? { ...totalsFrom(monthRow), from, to } : { cost: 0, calls: 0, sessions: 0, from, to },
74
+ topModels: monthModels
75
+ .map((m) => ({ name: String(m?.Model || 'unknown'), cost: num(m?.['Cost (USD)']), calls: num(m?.['API Calls']) }))
76
+ .sort((a, b) => b.cost - a.cost).slice(0, TOP_N),
77
+ topProjects: monthProjects
78
+ .map((p) => { const path = String(p?.Project || 'unknown'); return { name: basename(path.replace(/[\\/]+$/, '')) || path, path, cost: num(p?.['Cost (USD)']), sessions: num(p?.Sessions) }; })
79
+ .sort((a, b) => b.cost - a.cost).slice(0, TOP_N),
80
+ generated: typeof base?.generated === 'string' ? base.generated : null,
81
+ fullView: 'codeburn web',
82
+ };
83
+ if (panel.today.calls === 0 && panel.month.calls === 0) {
84
+ return { ...panel, status: 'no-data', message: 'codeburn found no usage this month.' };
85
+ }
86
+ return panel;
87
+ }
88
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/dashboard/usage.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Structure:
5
5
  * commands/
6
+ * _top/<name>.js → becomes `prism-cli <name>` (top-level command)
6
7
  * <category>/ → becomes `prism-cli <category>`
7
8
  * <command>.js → becomes `prism-cli <category> <command>`
8
9
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AA0DA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,GAAG,iBAMlD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AA8FA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,GAAG,iBAOlD"}
package/dist/src/index.js CHANGED
@@ -3,6 +3,8 @@ import { resolve, dirname, basename } from 'node:path';
3
3
  import { fileURLToPath, pathToFileURL } from 'node:url';
4
4
  const __dirname = dirname(fileURLToPath(import.meta.url));
5
5
  const commandsDir = resolve(__dirname, 'commands');
6
+ /** Files here register as top-level commands (`prism-cli <name>`), not as a group. */
7
+ const TOP_LEVEL_DIR = '_top';
6
8
  function attach(program, category, command, def) {
7
9
  // Reuse an existing category command if it was already created
8
10
  let categoryCmd = program.commands.find((c) => c.name() === category);
@@ -15,6 +17,33 @@ function attach(program, category, command, def) {
15
17
  }
16
18
  sub.action((opts) => def.action(opts));
17
19
  }
20
+ function attachTop(program, name, def) {
21
+ if (program.commands.find((c) => c.name() === name))
22
+ return;
23
+ const cmd = program.command(name).description(def.description || name);
24
+ if (def.options) {
25
+ for (const opt of def.options)
26
+ cmd.option(opt.flags, opt.description, opt.default);
27
+ }
28
+ cmd.action((opts) => def.action(opts));
29
+ }
30
+ function findModule(dir, name) {
31
+ for (const candidate of [`${name}.js`, `${name}.ts`]) {
32
+ const p = resolve(dir, candidate);
33
+ if (existsSync(p))
34
+ return p;
35
+ }
36
+ return '';
37
+ }
38
+ /** Fast path for a top-level command (`prism-cli dashboard --json`). */
39
+ async function registerTop(program, name) {
40
+ const file = findModule(resolve(commandsDir, TOP_LEVEL_DIR), name);
41
+ if (!file)
42
+ return false;
43
+ const mod = await import(pathToFileURL(file).href);
44
+ attachTop(program, name, mod.default || mod);
45
+ return true;
46
+ }
18
47
  /**
19
48
  * Fast path: import and register ONLY the `<category> <command>` module being
20
49
  * invoked. Returns false if the module can't be found (so we can fall back).
@@ -41,8 +70,15 @@ async function registerOne(program, category, command) {
41
70
  /** Full registration — imports every command module. Used for --help and unmatched invocations. */
42
71
  async function registerAll(program) {
43
72
  const categories = readdirSync(commandsDir).filter((entry) => {
44
- return statSync(resolve(commandsDir, entry)).isDirectory();
73
+ return entry !== TOP_LEVEL_DIR && statSync(resolve(commandsDir, entry)).isDirectory();
45
74
  });
75
+ const topDir = resolve(commandsDir, TOP_LEVEL_DIR);
76
+ if (existsSync(topDir)) {
77
+ for (const file of readdirSync(topDir).filter((f) => f.endsWith('.js') && !f.endsWith('.d.ts'))) {
78
+ const mod = await import(pathToFileURL(resolve(topDir, file)).href);
79
+ attachTop(program, basename(file, '.js'), mod.default || mod);
80
+ }
81
+ }
46
82
  for (const category of categories) {
47
83
  const categoryDir = resolve(commandsDir, category);
48
84
  const files = readdirSync(categoryDir).filter((f) => f.endsWith('.js') && !f.endsWith('.d.ts'));
@@ -59,6 +95,7 @@ async function registerAll(program) {
59
95
  *
60
96
  * Structure:
61
97
  * commands/
98
+ * _top/<name>.js → becomes `prism-cli <name>` (top-level command)
62
99
  * <category>/ → becomes `prism-cli <category>`
63
100
  * <command>.js → becomes `prism-cli <category> <command>`
64
101
  *
@@ -73,6 +110,8 @@ async function registerAll(program) {
73
110
  */
74
111
  export async function registerCommands(program) {
75
112
  const [category, command] = process.argv.slice(2);
113
+ if (category && !category.startsWith('-') && (await registerTop(program, category)))
114
+ return;
76
115
  if (category && command && !category.startsWith('-') && !command.startsWith('-')) {
77
116
  if (await registerOne(program, category, command))
78
117
  return;