@prism-d1/cli 1.2.0 → 1.3.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 (127) hide show
  1. package/dist/assets/github-workflows/prism-eval-gate-kiro.yml +2 -2
  2. package/dist/assets/infra/bin/app.ts +61 -37
  3. package/dist/assets/infra/lib/constructs/security-agent-construct.ts +35 -30
  4. package/dist/assets/infra/lib/metrics-pipeline-stack.ts +2 -110
  5. package/dist/assets/infra/lib/security-agent-resources.ts +136 -0
  6. package/dist/assets/infra/lib/security-agent-stack.ts +69 -0
  7. package/dist/assets/pentest-cdk/bin/app.ts +12 -0
  8. package/dist/assets/pentest-cdk/cdk.json +7 -0
  9. package/dist/assets/pentest-cdk/lib/pentest-target-stack.ts +206 -0
  10. package/dist/assets/pentest-cdk/package.json +18 -0
  11. package/dist/assets/pentest-cdk/tsconfig.json +12 -0
  12. package/dist/src/codewatch/results.d.ts +124 -4
  13. package/dist/src/codewatch/results.d.ts.map +1 -1
  14. package/dist/src/codewatch/results.js +8 -2
  15. package/dist/src/codewatch/results.js.map +1 -1
  16. package/dist/src/commands/_top/version.d.ts +62 -0
  17. package/dist/src/commands/_top/version.d.ts.map +1 -0
  18. package/dist/src/commands/_top/version.js +175 -0
  19. package/dist/src/commands/_top/version.js.map +1 -0
  20. package/dist/src/commands/bootstrapper/setup-otel-sync.d.ts +12 -6
  21. package/dist/src/commands/bootstrapper/setup-otel-sync.d.ts.map +1 -1
  22. package/dist/src/commands/bootstrapper/setup-otel-sync.js +18 -409
  23. package/dist/src/commands/bootstrapper/setup-otel-sync.js.map +1 -1
  24. package/dist/src/commands/enable/codeburn.d.ts +59 -0
  25. package/dist/src/commands/enable/codeburn.d.ts.map +1 -0
  26. package/dist/src/commands/enable/codeburn.js +531 -0
  27. package/dist/src/commands/enable/codeburn.js.map +1 -0
  28. package/dist/src/commands/enable/security.d.ts +41 -0
  29. package/dist/src/commands/enable/security.d.ts.map +1 -0
  30. package/dist/src/commands/enable/security.js +130 -0
  31. package/dist/src/commands/enable/security.js.map +1 -0
  32. package/dist/src/commands/export/otel.d.ts +31 -0
  33. package/dist/src/commands/export/otel.d.ts.map +1 -0
  34. package/dist/src/commands/export/otel.js +52 -0
  35. package/dist/src/commands/export/otel.js.map +1 -0
  36. package/dist/src/commands/security/code-review.d.ts +22 -0
  37. package/dist/src/commands/security/code-review.d.ts.map +1 -0
  38. package/dist/src/commands/security/code-review.js +43 -0
  39. package/dist/src/commands/security/code-review.js.map +1 -0
  40. package/dist/src/commands/security/findings.d.ts +15 -0
  41. package/dist/src/commands/security/findings.d.ts.map +1 -0
  42. package/dist/src/commands/security/findings.js +31 -0
  43. package/dist/src/commands/security/findings.js.map +1 -0
  44. package/dist/src/commands/security/pentest.d.ts +18 -0
  45. package/dist/src/commands/security/pentest.d.ts.map +1 -0
  46. package/dist/src/commands/security/pentest.js +32 -0
  47. package/dist/src/commands/security/pentest.js.map +1 -0
  48. package/dist/src/commands/security/threat-model.d.ts +16 -0
  49. package/dist/src/commands/security/threat-model.d.ts.map +1 -0
  50. package/dist/src/commands/security/threat-model.js +24 -0
  51. package/dist/src/commands/security/threat-model.js.map +1 -0
  52. package/dist/src/commands/security/threats.d.ts +12 -0
  53. package/dist/src/commands/security/threats.d.ts.map +1 -0
  54. package/dist/src/commands/security/threats.js +23 -0
  55. package/dist/src/commands/security/threats.js.map +1 -0
  56. package/dist/src/commands/securityagent/setup.d.ts +19 -5
  57. package/dist/src/commands/securityagent/setup.d.ts.map +1 -1
  58. package/dist/src/commands/securityagent/setup.js +25 -189
  59. package/dist/src/commands/securityagent/setup.js.map +1 -1
  60. package/dist/src/dashboard/codewatch.d.ts.map +1 -1
  61. package/dist/src/dashboard/codewatch.js +2 -1
  62. package/dist/src/dashboard/codewatch.js.map +1 -1
  63. package/dist/src/dashboard/page.d.ts.map +1 -1
  64. package/dist/src/dashboard/page.js +159 -4
  65. package/dist/src/dashboard/page.js.map +1 -1
  66. package/dist/src/dashboard/payload.d.ts +8 -5
  67. package/dist/src/dashboard/payload.d.ts.map +1 -1
  68. package/dist/src/dashboard/payload.js +5 -2
  69. package/dist/src/dashboard/payload.js.map +1 -1
  70. package/dist/src/dashboard/security.d.ts +130 -0
  71. package/dist/src/dashboard/security.d.ts.map +1 -0
  72. package/dist/src/dashboard/security.js +144 -0
  73. package/dist/src/dashboard/security.js.map +1 -0
  74. package/dist/src/dashboard/setup.d.ts +15 -0
  75. package/dist/src/dashboard/setup.d.ts.map +1 -1
  76. package/dist/src/dashboard/setup.js +20 -3
  77. package/dist/src/dashboard/setup.js.map +1 -1
  78. package/dist/src/dashboard/usage.js +1 -1
  79. package/dist/src/dashboard/usage.js.map +1 -1
  80. package/dist/src/index.d.ts.map +1 -1
  81. package/dist/src/index.js +9 -2
  82. package/dist/src/index.js.map +1 -1
  83. package/dist/src/security/cfn-diff.d.ts +57 -0
  84. package/dist/src/security/cfn-diff.d.ts.map +1 -0
  85. package/dist/src/security/cfn-diff.js +112 -0
  86. package/dist/src/security/cfn-diff.js.map +1 -0
  87. package/dist/src/security/errors.d.ts +45 -0
  88. package/dist/src/security/errors.d.ts.map +1 -0
  89. package/dist/src/security/errors.js +116 -0
  90. package/dist/src/security/errors.js.map +1 -0
  91. package/dist/src/security/marker.d.ts +46 -0
  92. package/dist/src/security/marker.d.ts.map +1 -0
  93. package/dist/src/security/marker.js +120 -0
  94. package/dist/src/security/marker.js.map +1 -0
  95. package/dist/src/security/pentest-dockerfile.d.ts +8 -0
  96. package/dist/src/security/pentest-dockerfile.d.ts.map +1 -0
  97. package/dist/src/security/pentest-dockerfile.js +163 -0
  98. package/dist/src/security/pentest-dockerfile.js.map +1 -0
  99. package/dist/src/security/pentest.d.ts +233 -0
  100. package/dist/src/security/pentest.d.ts.map +1 -0
  101. package/dist/src/security/pentest.js +1057 -0
  102. package/dist/src/security/pentest.js.map +1 -0
  103. package/dist/src/security/repo.d.ts +25 -0
  104. package/dist/src/security/repo.d.ts.map +1 -0
  105. package/dist/src/security/repo.js +38 -0
  106. package/dist/src/security/repo.js.map +1 -0
  107. package/dist/src/security/review.d.ts +202 -0
  108. package/dist/src/security/review.d.ts.map +1 -0
  109. package/dist/src/security/review.js +706 -0
  110. package/dist/src/security/review.js.map +1 -0
  111. package/dist/src/security/setup.d.ts +193 -0
  112. package/dist/src/security/setup.d.ts.map +1 -0
  113. package/dist/src/security/setup.js +728 -0
  114. package/dist/src/security/setup.js.map +1 -0
  115. package/dist/src/security/threat-model.d.ts +133 -0
  116. package/dist/src/security/threat-model.d.ts.map +1 -0
  117. package/dist/src/security/threat-model.js +653 -0
  118. package/dist/src/security/threat-model.js.map +1 -0
  119. package/dist/src/utils/exec.d.ts +6 -0
  120. package/dist/src/utils/exec.d.ts.map +1 -1
  121. package/dist/src/utils/exec.js +12 -1
  122. package/dist/src/utils/exec.js.map +1 -1
  123. package/dist/src/utils/otel-sync-schedule.d.ts +19 -0
  124. package/dist/src/utils/otel-sync-schedule.d.ts.map +1 -1
  125. package/dist/src/utils/otel-sync-schedule.js +24 -2
  126. package/dist/src/utils/otel-sync-schedule.js.map +1 -1
  127. package/package.json +3 -3
@@ -0,0 +1,175 @@
1
+ /**
2
+ * `prism-cli version`: this CLI's version, whether npm has a newer one, and
3
+ * any other prism-cli on PATH that shadows this one or differs from it (an old
4
+ * /usr/bin/prism-cli under a system Node is the usual case).
5
+ *
6
+ * The npm check never fails the command: a timeout, no network or no npm is
7
+ * reported as "not checked". `--offline` skips it. `prism-cli --version` stays
8
+ * the bare version string from commander.
9
+ */
10
+ import { spawnSync } from 'node:child_process';
11
+ import { existsSync, readFileSync, realpathSync, statSync } from 'node:fs';
12
+ import { delimiter, dirname, join, resolve } from 'node:path';
13
+ import { fileURLToPath } from 'node:url';
14
+ export const PACKAGE_NAME = '@prism-d1/cli';
15
+ const BIN_NAME = 'prism-cli';
16
+ /** Short: this runs on every `version` call and must not stall a terminal. */
17
+ const NPM_TIMEOUT_MS = 5000;
18
+ /** Walks up from `start` to the package.json of @prism-d1/cli, at most 6 levels. */
19
+ export function findPackageDir(start) {
20
+ let dir = start;
21
+ for (let i = 0; i < 6; i++) {
22
+ const pkg = join(dir, 'package.json');
23
+ if (existsSync(pkg)) {
24
+ try {
25
+ if (JSON.parse(readFileSync(pkg, 'utf8')).name === PACKAGE_NAME)
26
+ return dir;
27
+ }
28
+ catch { /* not ours */ }
29
+ }
30
+ const parent = dirname(dir);
31
+ if (parent === dir)
32
+ break;
33
+ dir = parent;
34
+ }
35
+ return null;
36
+ }
37
+ function packageVersion(dir) {
38
+ if (!dir)
39
+ return null;
40
+ try {
41
+ return String(JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')).version);
42
+ }
43
+ catch {
44
+ return null;
45
+ }
46
+ }
47
+ /** -1, 0 or 1, comparing dotted numeric versions; pre-release tags are ignored. */
48
+ export function compareVersions(a, b) {
49
+ const pa = a.split(/[.-]/).slice(0, 3).map((n) => parseInt(n, 10) || 0);
50
+ const pb = b.split(/[.-]/).slice(0, 3).map((n) => parseInt(n, 10) || 0);
51
+ for (let i = 0; i < 3; i++)
52
+ if (pa[i] !== pb[i])
53
+ return pa[i] > pb[i] ? 1 : -1;
54
+ return 0;
55
+ }
56
+ /**
57
+ * Every prism-cli on PATH, in PATH order, deduplicated by real path (e.g.
58
+ * /bin -> /usr/bin).
59
+ *
60
+ * shortcut: on Windows, npm's .cmd shims do not resolve to their package, so
61
+ * other installs there show version unknown; parse the shim if that matters.
62
+ */
63
+ export function installsOnPath(pathEnv, ownPackageDir) {
64
+ const seen = new Set();
65
+ const out = [];
66
+ const exts = process.platform === 'win32' ? ['.cmd', ''] : [''];
67
+ const own = realOrSelf(ownPackageDir);
68
+ for (const dir of pathEnv.split(delimiter)) {
69
+ if (!dir)
70
+ continue;
71
+ for (const ext of exts) {
72
+ const p = join(dir, BIN_NAME + ext);
73
+ try {
74
+ if (!statSync(p).isFile())
75
+ continue;
76
+ }
77
+ catch {
78
+ continue;
79
+ }
80
+ const real = realOrSelf(p);
81
+ if (seen.has(real))
82
+ continue;
83
+ seen.add(real);
84
+ const pkgDir = findPackageDir(dirname(real));
85
+ out.push({ path: p, realpath: real, version: packageVersion(pkgDir), isThis: !!pkgDir && realOrSelf(pkgDir) === own });
86
+ }
87
+ }
88
+ return out;
89
+ }
90
+ function realOrSelf(p) {
91
+ try {
92
+ return realpathSync(p);
93
+ }
94
+ catch {
95
+ return resolve(p);
96
+ }
97
+ }
98
+ export function buildReport(opts, d) {
99
+ const version = packageVersion(d.ownPackageDir) ?? 'unknown';
100
+ const warnings = [];
101
+ const onPath = installsOnPath(d.pathEnv, d.ownPackageDir);
102
+ const first = onPath[0];
103
+ if (!first) {
104
+ warnings.push(`${BIN_NAME} is not on PATH; this copy runs only by its full path.`);
105
+ }
106
+ else if (!first.isThis) {
107
+ warnings.push(`"${BIN_NAME}" on PATH runs ${first.path} (${first.version ?? 'version unknown'}), not this CLI (${version}, ${d.ownPackageDir}).`);
108
+ }
109
+ const others = onPath.filter((i, n) => !i.isThis && n > 0 && i.version !== version);
110
+ for (const o of others) {
111
+ warnings.push(`Another ${BIN_NAME} on PATH: ${o.path} (${o.version ?? 'version unknown'}), shadowed by ${first.path}. A different Node or shell may run it; remove it with that Node's "npm uninstall -g ${PACKAGE_NAME}".`);
112
+ }
113
+ let latest = null;
114
+ let latestNote = null;
115
+ if (opts.offline) {
116
+ latestNote = 'offline';
117
+ }
118
+ else {
119
+ const r = d.npmLatest();
120
+ latest = r.version;
121
+ if (!latest)
122
+ latestNote = r.error || 'npm returned no version';
123
+ }
124
+ const updateAvailable = latest && version !== 'unknown' ? compareVersions(latest, version) > 0 : null;
125
+ return { schema: 'prism.version.v1', version, node: process.version, latest, updateAvailable, latestNote, onPath, warnings };
126
+ }
127
+ function realNpmLatest() {
128
+ const o = { encoding: 'utf8', timeout: NPM_TIMEOUT_MS, stdio: ['ignore', 'pipe', 'pipe'] };
129
+ // Windows resolves npm.cmd only through a shell. The command is a constant
130
+ // with no user input, so the shell parses nothing it was given.
131
+ const r = process.platform === 'win32'
132
+ ? spawnSync(`npm view ${PACKAGE_NAME} version`, { ...o, shell: true })
133
+ : spawnSync('npm', ['view', PACKAGE_NAME, 'version'], o);
134
+ if (r.error)
135
+ return { version: null, error: r.error.code === 'ETIMEDOUT' ? `npm did not answer within ${NPM_TIMEOUT_MS / 1000}s` : r.error.message };
136
+ if (r.status !== 0)
137
+ return { version: null, error: (r.stderr || '').trim().split('\n')[0] || `npm exited ${r.status}` };
138
+ const v = (r.stdout || '').trim();
139
+ return /^\d+\.\d+\.\d+/.test(v) ? { version: v } : { version: null, error: 'unexpected npm output' };
140
+ }
141
+ export function defaultDeps() {
142
+ return {
143
+ ownPackageDir: findPackageDir(dirname(fileURLToPath(import.meta.url))) ?? process.cwd(),
144
+ pathEnv: process.env.PATH || '',
145
+ npmLatest: realNpmLatest,
146
+ };
147
+ }
148
+ export function printReport(r, log = console.log) {
149
+ log(`${BIN_NAME} ${r.version} (Node ${r.node})`);
150
+ if (r.updateAvailable)
151
+ log(`Update available: ${r.latest}. Run: npm install -g ${PACKAGE_NAME}`);
152
+ else if (r.latest)
153
+ log(`Up to date (latest on npm: ${r.latest}).`);
154
+ else if (r.latestNote === 'offline')
155
+ log('Update check skipped (--offline).');
156
+ else
157
+ log(`Update check: not checked (${r.latestNote}).`);
158
+ for (const w of r.warnings)
159
+ log(`⚠ ${w}`);
160
+ }
161
+ export default {
162
+ description: 'Print the CLI version, check npm for a newer release, and warn about other prism-cli copies on PATH',
163
+ options: [
164
+ { flags: '--json', description: 'Print the report as JSON' },
165
+ { flags: '--offline', description: 'Skip the npm check' },
166
+ ],
167
+ async action(opts) {
168
+ const report = buildReport(opts, defaultDeps());
169
+ if (opts.json)
170
+ console.log(JSON.stringify(report, null, 2));
171
+ else
172
+ printReport(report);
173
+ },
174
+ };
175
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../../src/commands/_top/version.ts"],"names":[],"mappings":"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"}
@@ -1,15 +1,21 @@
1
+ import { type CodeburnHooks, type CodeburnOptions } from '../enable/codeburn.js';
2
+ /**
3
+ * DEPRECATED alias for `prism-cli enable codeburn`.
4
+ *
5
+ * `enable codeburn` is this command under its new name: the same flags, sync
6
+ * setup and schedule, plus a codeburn install when it is missing (after a
7
+ * confirmation), --dry-run, and re-runs that report what is already done. The
8
+ * command is kept so existing scripts and docs keep working.
9
+ */
10
+ export declare const DEPRECATION: string[];
1
11
  declare const _default: {
2
12
  description: string;
3
13
  options: {
4
14
  flags: string;
5
15
  description: string;
6
16
  }[];
7
- action(opts: {
8
- url?: string;
9
- interval?: string;
10
- status?: boolean;
11
- remove?: boolean;
12
- }): Promise<void>;
17
+ /** Errors are handled once, in runEnableCodeburn, for this alias too. `hooks` is for tests. */
18
+ action(opts: CodeburnOptions, hooks?: CodeburnHooks): Promise<void>;
13
19
  };
14
20
  export default _default;
15
21
  //# sourceMappingURL=setup-otel-sync.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setup-otel-sync.d.ts","sourceRoot":"","sources":["../../../../src/commands/bootstrapper/setup-otel-sync.ts"],"names":[],"mappings":";;;;;;iBAySqB;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE;;AAR5F,wBAqJE"}
1
+ {"version":3,"file":"setup-otel-sync.d.ts","sourceRoot":"","sources":["../../../../src/commands/bootstrapper/setup-otel-sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuC,KAAK,aAAa,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEtH;;;;;;;GAOG;AACH,eAAO,MAAM,WAAW,UAGvB,CAAC;;;;;;;IAKA,+FAA+F;iBAC5E,eAAe,UAAU,aAAa;;AAJ3D,wBASE"}
@@ -1,416 +1,25 @@
1
- import { createInterface } from 'node:readline';
2
- import { platform, homedir } from 'node:os';
3
- import { existsSync, mkdirSync, writeFileSync, readFileSync, unlinkSync } from 'node:fs';
4
- import { join } from 'node:path';
5
- import { run, runInteractive } from '../../utils/exec.js';
6
- import { withPrivateTemp } from '../../utils/tempfile.js';
7
- import { CRON_MARKER, PLIST_LABEL, SCHTASK_NAME, otelLogDir, codeburnSyncConfigPath, linuxCrontabAvailable, darwinPlistPath, scheduleExists, schedulerName, } from '../../utils/otel-sync-schedule.js';
8
- function prompt(question, defaultValue) {
9
- const rl = createInterface({ input: process.stdin, output: process.stdout });
10
- const suffix = defaultValue ? ` [${defaultValue}]` : '';
11
- return new Promise((resolve) => {
12
- rl.question(`${question}${suffix}: `, (answer) => {
13
- rl.close();
14
- resolve(answer.trim() || defaultValue || '');
15
- });
16
- });
17
- }
18
- // ---- Constants ----
19
- // Marker, label and task name are shared with the dashboard's setup check.
20
- const LOG_DIR = otelLogDir();
21
- /** Window the recurring sync pushes on every run. */
22
- const SYNC_SINCE = '7d';
23
- // ---- Scheduler helpers per OS ----
24
- function getCodeburnPath() {
25
- const result = platform() === 'win32'
26
- ? run('where', ['codeburn'])
27
- : run('which', ['codeburn']);
28
- return result.ok ? result.stdout.split('\n')[0].trim() : null;
29
- }
1
+ import { CODEBURN_OPTIONS, runEnableCodeburn } from '../enable/codeburn.js';
30
2
  /**
31
- * The argv of the recurring sync, shared by every platform.
3
+ * DEPRECATED alias for `prism-cli enable codeburn`.
32
4
  *
33
- * This is the single source of truth on purpose. It previously existed only as
34
- * a Linux helper, and the Windows branch open-coded its own command string
35
- * that omitted --attribution. That silently reduced Windows machines to usage
36
- * telemetry with no commit attribution, so those developers counted toward the
37
- * Attribution Coverage denominator (CI sees their commits) while contributing
38
- * nothing to the numerator -- indistinguishable on the dashboard from someone
39
- * who never onboarded. Any new platform branch must call this.
5
+ * `enable codeburn` is this command under its new name: the same flags, sync
6
+ * setup and schedule, plus a codeburn install when it is missing (after a
7
+ * confirmation), --dry-run, and re-runs that report what is already done. The
8
+ * command is kept so existing scripts and docs keep working.
40
9
  */
41
- function syncArgs(since) {
42
- return ['sync', 'push', '--since', since, '--attribution'];
43
- }
44
- // ---- Linux: user crontab ----
45
- /**
46
- * Single-quotes a value for the crontab line.
47
- *
48
- * A crontab entry is interpreted by /bin/sh, so unlike our argv call sites
49
- * this one genuinely does need quoting -- the shell is the scheduler's, not
50
- * ours, and we cannot pass it argv. Wrapping in single quotes and encoding any
51
- * embedded single quote as '\'' is the only form with no escape sequences to
52
- * get wrong. Paths under a home directory containing a space would otherwise
53
- * split into two arguments.
54
- */
55
- function shQuote(value) {
56
- return `'${value.replace(/'/g, `'\\''`)}'`;
57
- }
58
- function linuxInstallSchedule(codeburnPath, intervalHours) {
59
- if (!linuxCrontabAvailable()) {
60
- console.warn('\n⚠️ crontab not found — skipping automatic schedule installation.');
61
- console.warn(' Run "codeburn sync push --since 7d" manually, or install cronie:');
62
- console.warn(' sudo yum install cronie -y # then re-run this command\n');
63
- return false;
64
- }
65
- const existing = run('crontab', ['-l']);
66
- const lines = existing.ok ? existing.stdout.split('\n').filter(l => !l.includes(CRON_MARKER)) : [];
67
- const logFile = join(LOG_DIR, 'otel-sync.log');
68
- const cronExpr = `0 */${intervalHours} * * *`;
69
- const command = [shQuote(codeburnPath), ...syncArgs(SYNC_SINCE)].join(' ');
70
- lines.push(`${CRON_MARKER}`);
71
- lines.push(`${cronExpr} ${command} >> ${shQuote(logFile)} 2>&1`);
72
- const result = withPrivateTemp('crontab', lines.join('\n') + '\n', f => run('crontab', [f]));
73
- if (!result.ok)
74
- throw new Error(`Failed to install crontab: ${result.stderr}`);
75
- return true;
76
- }
77
- function linuxRemoveSchedule() {
78
- if (!linuxCrontabAvailable())
79
- return;
80
- const existing = run('crontab', ['-l']);
81
- if (!existing.ok)
82
- return;
83
- const lines = existing.stdout.split('\n').filter(l => !l.includes(CRON_MARKER) && !l.includes('codeburn sync push'));
84
- withPrivateTemp('crontab', lines.join('\n') + '\n', f => run('crontab', [f]));
85
- }
86
- // ---- macOS: LaunchAgent ----
87
- /**
88
- * Escapes a value for use inside a plist <string> element.
89
- *
90
- * The plist is generated XML, so a path containing `&` or `<` -- both legal in
91
- * macOS filenames -- would otherwise produce a malformed document that
92
- * launchctl refuses to load, reported only as a generic load failure.
93
- */
94
- function xmlEscape(value) {
95
- return value
96
- .replace(/&/g, '&amp;')
97
- .replace(/</g, '&lt;')
98
- .replace(/>/g, '&gt;');
99
- }
100
- function darwinInstallSchedule(codeburnPath, intervalHours) {
101
- const logFile = join(LOG_DIR, 'otel-sync.log');
102
- const argElements = [codeburnPath, ...syncArgs(SYNC_SINCE)]
103
- .map(a => ` <string>${xmlEscape(a)}</string>`)
104
- .join('\n');
105
- const plist = `<?xml version="1.0" encoding="UTF-8"?>
106
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
107
- <plist version="1.0">
108
- <dict>
109
- <key>Label</key>
110
- <string>${PLIST_LABEL}</string>
111
- <key>ProgramArguments</key>
112
- <array>
113
- ${argElements}
114
- </array>
115
- <key>StartInterval</key>
116
- <integer>${intervalHours * 3600}</integer>
117
- <key>StandardOutPath</key>
118
- <string>${xmlEscape(logFile)}</string>
119
- <key>StandardErrorPath</key>
120
- <string>${xmlEscape(logFile)}</string>
121
- <key>RunAtLoad</key>
122
- <true/>
123
- </dict>
124
- </plist>`;
125
- const plistPath = darwinPlistPath();
126
- mkdirSync(join(homedir(), 'Library', 'LaunchAgents'), { recursive: true });
127
- writeFileSync(plistPath, plist);
128
- // Unload first so a reinstall replaces rather than conflicts. A missing
129
- // agent makes this fail, which is expected and ignored -- run() captures
130
- // stderr rather than leaking it, so no shell redirect is needed.
131
- run('launchctl', ['unload', plistPath]);
132
- const result = run('launchctl', ['load', plistPath]);
133
- if (!result.ok)
134
- throw new Error(`Failed to load LaunchAgent: ${result.stderr}`);
135
- }
136
- function darwinRemoveSchedule() {
137
- const plistPath = darwinPlistPath();
138
- if (existsSync(plistPath)) {
139
- run('launchctl', ['unload', plistPath]);
140
- unlinkSync(plistPath);
141
- }
142
- }
143
- // ---- Windows: schtasks ----
144
- /** Path of the generated batch wrapper the scheduled task invokes. */
145
- function windowsWrapperPath() {
146
- return join(homedir(), '.prism', 'otel-sync.cmd');
147
- }
148
- /**
149
- * Installs the Windows scheduled task via a generated .cmd wrapper.
150
- *
151
- * The previous version nested the whole command inside schtasks' /tr argument:
152
- *
153
- * /tr "cmd /c <codeburnPath> sync push ... >> "<logFile>" 2>&1"
154
- *
155
- * and tried to make that legal with cmd.replace(/"/g, '\\"'). That is three
156
- * quoting layers deep -- our shell, schtasks' own /tr parser, then cmd.exe --
157
- * and the replacement handled exactly one metacharacter of one of them. It did
158
- * not escape backslashes, which is not a corner case on Windows: every path
159
- * here is backslash-separated, so a trailing separator turns the closing \"
160
- * into an escaped quote and unbalances the argument. cmd.exe also does not
161
- * treat \" the way that replacement assumes, so the escaping was aimed at the
162
- * wrong grammar to begin with.
163
- *
164
- * Writing the command to a file removes every one of those layers. The task
165
- * runs one fixed argument -- the wrapper path -- and the redirection lives in
166
- * a batch file where it needs no escaping at all. This also sidesteps the
167
- * documented 261-character limit on /tr, which the inlined form could exceed
168
- * with a long install path.
169
- */
170
- function windowsInstallSchedule(codeburnPath, intervalHours) {
171
- const logFile = join(LOG_DIR, 'otel-sync.log');
172
- const args = syncArgs(SYNC_SINCE).join(' ');
173
- const wrapper = [
174
- '@echo off',
175
- 'REM Generated by prism-cli bootstrapper setup-otel-sync. Do not edit.',
176
- `"${codeburnPath}" ${args} >> "${logFile}" 2>&1`,
177
- '',
178
- ].join('\r\n');
179
- mkdirSync(join(homedir(), '.prism'), { recursive: true });
180
- writeFileSync(windowsWrapperPath(), wrapper);
181
- const result = run('schtasks', [
182
- '/create',
183
- '/tn', SCHTASK_NAME,
184
- '/sc', 'hourly',
185
- '/mo', String(intervalHours),
186
- '/tr', windowsWrapperPath(),
187
- '/f',
188
- ]);
189
- if (!result.ok)
190
- throw new Error(`Failed to create scheduled task: ${result.stderr}`);
191
- }
192
- function windowsRemoveSchedule() {
193
- run('schtasks', ['/delete', '/tn', SCHTASK_NAME, '/f']);
194
- const wrapper = windowsWrapperPath();
195
- if (existsSync(wrapper))
196
- unlinkSync(wrapper);
197
- }
198
- // ---- Unified scheduler interface ----
199
- function installSchedule(codeburnPath, intervalHours) {
200
- mkdirSync(LOG_DIR, { recursive: true });
201
- switch (platform()) {
202
- case 'darwin':
203
- darwinInstallSchedule(codeburnPath, intervalHours);
204
- return true;
205
- case 'win32':
206
- windowsInstallSchedule(codeburnPath, intervalHours);
207
- return true;
208
- default: return linuxInstallSchedule(codeburnPath, intervalHours);
209
- }
210
- }
211
- function removeSchedule() {
212
- switch (platform()) {
213
- case 'darwin': return darwinRemoveSchedule();
214
- case 'win32': return windowsRemoveSchedule();
215
- default: return linuxRemoveSchedule();
216
- }
217
- }
218
- // ---- Status ----
219
- function showStatus(codeburnPath) {
220
- console.log('\n📊 OTEL Sync Status\n');
221
- // Codeburn installed?
222
- if (codeburnPath) {
223
- console.log(` ✓ codeburn found: ${codeburnPath}`);
224
- const ver = run(codeburnPath, ['--version']);
225
- if (ver.ok)
226
- console.log(` version: ${ver.stdout}`);
227
- }
228
- else {
229
- console.log(' ✗ codeburn not found in PATH');
230
- }
231
- // Sync configured?
232
- const configPath = codeburnSyncConfigPath();
233
- if (existsSync(configPath)) {
234
- try {
235
- const cfg = JSON.parse(readFileSync(configPath, 'utf8'));
236
- console.log(` ✓ sync configured: ${cfg.baseUrl || cfg.endpoint || cfg.url || '(configured)'}`);
237
- }
238
- catch {
239
- console.log(` ✓ sync config exists: ${configPath}`);
240
- }
241
- }
242
- else {
243
- console.log(' ✗ sync not configured (run setup first)');
244
- }
245
- // Schedule exists?
246
- if (scheduleExists()) {
247
- console.log(` ✓ ${schedulerName()} schedule active`);
248
- }
249
- else {
250
- console.log(` ✗ no ${schedulerName()} schedule found`);
251
- }
252
- // Last log?
253
- const logFile = join(LOG_DIR, 'otel-sync.log');
254
- if (existsSync(logFile)) {
255
- // Read in process rather than shelling out to tail, which does not exist
256
- // on Windows -- the platform this command explicitly supports. The old
257
- // `tail -5` silently produced no output there, making a working schedule
258
- // look like it had never run.
259
- const tail = readFileSync(logFile, 'utf8').split('\n').filter(Boolean).slice(-5);
260
- if (tail.length) {
261
- console.log(` Last sync output (${logFile}):`);
262
- for (const line of tail) {
263
- console.log(` ${line}`);
264
- }
265
- }
266
- }
267
- console.log('');
268
- }
269
- // ---- Main ----
10
+ export const DEPRECATION = [
11
+ '⚠ "prism-cli bootstrapper setup-otel-sync" is deprecated; use "prism-cli enable codeburn".',
12
+ ' It takes the same flags, and also installs codeburn when missing (asks first; --yes skips the prompt).',
13
+ ];
270
14
  export default {
271
- description: 'Set up automated codeburn OTEL sync (pushes AI usage telemetry every 12h)',
272
- options: [
273
- { flags: '--url <url>', description: 'OTEL collector URL (from CDK deploy output OtelCollectorUrl)' },
274
- { flags: '--interval <hours>', description: 'Sync interval in hours (default: 12)' },
275
- { flags: '--status', description: 'Show current sync schedule status' },
276
- { flags: '--remove', description: 'Remove the sync schedule' },
277
- ],
278
- async action(opts) {
279
- const codeburnPath = getCodeburnPath();
280
- // --status
281
- if (opts.status) {
282
- showStatus(codeburnPath);
283
- return;
284
- }
285
- // --remove
286
- if (opts.remove) {
287
- if (scheduleExists()) {
288
- removeSchedule();
289
- console.log(`\n ✓ ${schedulerName()} schedule removed.\n`);
290
- }
291
- else {
292
- console.log(`\n No ${schedulerName()} schedule found — nothing to remove.\n`);
293
- }
294
- return;
295
- }
296
- // ---- Setup flow ----
297
- console.log('\n🔄 OTEL Sync Setup\n');
298
- console.log('This will configure automated codeburn telemetry sync to your PRISM');
299
- console.log('OTEL collector. Runs every 12 hours to keep dashboards fresh.\n');
300
- // 1. Check codeburn version
301
- if (!codeburnPath) {
302
- console.error('Error: codeburn not found. Install with: npm install -g codeburn');
303
- process.exit(1);
304
- }
305
- const verResult = run(codeburnPath, ['--version']);
306
- if (verResult.ok) {
307
- const ver = verResult.stdout.replace(/[^0-9.]/g, '');
308
- const parts = ver.split('.').map(Number);
309
- if (parts[0] === 0 && parts[1] < 9 || (parts[1] === 9 && parts[2] < 16)) {
310
- console.error(`Error: codeburn >= 0.9.16 required (found ${ver}). Run: npm update -g codeburn`);
311
- process.exit(1);
312
- }
313
- console.log(` ✓ codeburn ${ver}`);
314
- }
315
- // 2. Get the OTEL collector URL
316
- const otelUrl = opts.url || await prompt('OTEL collector URL (from CDK deploy output OtelCollectorUrl)');
317
- if (!otelUrl) {
318
- console.error('Error: OTEL collector URL is required.');
319
- process.exit(1);
320
- }
321
- // Reject anything that is not a real http(s) URL before it is persisted
322
- // into codeburn's sync config, where a malformed value surfaces later as an
323
- // opaque push failure from the scheduled job rather than here.
324
- try {
325
- const parsed = new URL(otelUrl);
326
- if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {
327
- throw new Error('unsupported protocol');
328
- }
329
- }
330
- catch {
331
- console.error(`Error: "${otelUrl}" is not a valid http(s) URL.`);
332
- console.error(' Expected the OtelCollectorUrl value from the CDK stack outputs.');
333
- process.exit(1);
334
- }
335
- // 3. Check if codeburn sync is already configured for this URL
336
- const configPath = codeburnSyncConfigPath();
337
- let needsSetup = true;
338
- if (existsSync(configPath)) {
339
- try {
340
- const cfg = JSON.parse(readFileSync(configPath, 'utf8'));
341
- const existingUrl = cfg.baseUrl || cfg.endpoint || cfg.url || '';
342
- if (existingUrl === otelUrl || existingUrl.startsWith(otelUrl)) {
343
- console.log(` ✓ codeburn sync already configured for this endpoint.`);
344
- needsSetup = false;
345
- }
346
- else {
347
- console.log(` ⚠ codeburn sync configured for different endpoint: ${existingUrl}`);
348
- const override = await prompt('Reconfigure for the new URL? (y/N)', 'N');
349
- if (override.toLowerCase() !== 'y') {
350
- console.log(' Keeping existing configuration.');
351
- needsSetup = false;
352
- }
353
- }
354
- }
355
- catch {
356
- // Corrupt config — re-setup
357
- }
358
- }
359
- // 4. Run codeburn sync setup (opens browser for OIDC)
360
- if (needsSetup) {
361
- console.log('\n Running: codeburn sync setup ' + otelUrl);
362
- console.log(' (This will open a browser for OIDC authentication)\n');
363
- // argv, not a command string: otelUrl comes straight from prompt() and
364
- // previously reached execSync as shell source.
365
- if (runInteractive(codeburnPath, ['sync', 'setup', otelUrl])) {
366
- console.log('\n ✓ codeburn sync configured.');
367
- }
368
- else {
369
- console.error(`\n ✗ codeburn sync setup failed. Ensure Cognito user exists and try again.`);
370
- process.exit(1);
371
- }
372
- }
373
- // 5. Initial backfill push (30d — server drops >14d from CloudWatch, keeps in DDB/S3)
374
- console.log('\n Pushing initial backfill (last 30 days of telemetry)...');
375
- const backfill = run(codeburnPath, syncArgs('30d'));
376
- if (backfill.ok) {
377
- console.log(' ✓ Backfill push complete.');
378
- if (backfill.stdout)
379
- console.log(` ${backfill.stdout.split('\n').slice(-1)[0]}`);
380
- }
381
- else {
382
- console.log(` ⚠ Backfill push failed (non-fatal): ${backfill.stderr.split('\n')[0]}`);
383
- console.log(' The schedule will retry. Check ~/.prism/logs/otel-sync.log');
384
- }
385
- // 6. Install OS schedule
386
- const intervalHours = opts.interval ? parseInt(opts.interval, 10) : 12;
387
- if (isNaN(intervalHours) || intervalHours < 1) {
388
- console.error('Error: --interval must be a positive integer (hours).');
389
- process.exit(1);
390
- }
391
- if (scheduleExists()) {
392
- console.log(`\n ✓ ${schedulerName()} schedule already exists — updating.`);
393
- removeSchedule();
394
- }
395
- const scheduled = installSchedule(codeburnPath, intervalHours);
396
- if (scheduled) {
397
- console.log(` ✓ ${schedulerName()} schedule installed (every ${intervalHours}h).`);
398
- }
399
- // Summary
400
- console.log('\n════════════════════════════════════════════════');
401
- console.log(' ✅ OTEL sync setup complete!');
402
- console.log('════════════════════════════════════════════════');
403
- console.log(`\n Endpoint: ${otelUrl}`);
404
- if (scheduled) {
405
- console.log(` Schedule: every ${intervalHours}h via ${schedulerName()}`);
406
- }
407
- else {
408
- console.log(` Schedule: ⚠️ not installed (run manually: codeburn sync push --since 7d)`);
409
- }
410
- console.log(` Backfill: last 30d pushed (dashboard shows last 14d)`);
411
- console.log(` Logs: ${join(LOG_DIR, 'otel-sync.log')}`);
412
- console.log(`\n Run \`prism-cli bootstrapper setup-otel-sync --status\` to check health.`);
413
- console.log(` Run \`prism-cli bootstrapper setup-otel-sync --remove\` to uninstall.\n`);
15
+ description: '[deprecated] Alias for "prism-cli enable codeburn"',
16
+ options: CODEBURN_OPTIONS,
17
+ /** Errors are handled once, in runEnableCodeburn, for this alias too. `hooks` is for tests. */
18
+ async action(opts, hooks) {
19
+ for (const l of DEPRECATION)
20
+ console.warn(l);
21
+ console.warn('');
22
+ await runEnableCodeburn(opts, hooks);
414
23
  },
415
24
  };
416
25
  //# sourceMappingURL=setup-otel-sync.js.map