codiedev 0.10.0-beta.5 → 0.10.0-beta.7

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 (44) hide show
  1. package/README.md +4 -4
  2. package/dist/captureSignals.js +2 -0
  3. package/dist/cli.js +38 -50
  4. package/dist/codexHookTrust.js +67 -4
  5. package/dist/codie.js +23 -74
  6. package/dist/codieLauncher.js +18 -22
  7. package/dist/commands/agentTemplates.generated.js +136 -0
  8. package/dist/commands/agents.js +1068 -0
  9. package/dist/commands/agentsSdk.generated.js +7 -0
  10. package/dist/commands/doctor.js +12 -38
  11. package/dist/commands/evals.js +187 -0
  12. package/dist/commands/pack.js +1 -1
  13. package/dist/commands/traces.js +79 -15
  14. package/dist/commands/tracesLabel.js +348 -0
  15. package/dist/connect.js +11 -52
  16. package/dist/copilotHooks.js +0 -4
  17. package/dist/cursorHooks.js +0 -15
  18. package/dist/harnessDirs.js +4 -0
  19. package/dist/hook.js +33 -197
  20. package/dist/limitEventReporter.js +1 -1
  21. package/dist/managedPi.js +240 -0
  22. package/dist/mcp.js +0 -307
  23. package/dist/packs/harnesses.js +40 -3
  24. package/dist/packs/install.js +2 -1
  25. package/dist/piHooks.js +216 -0
  26. package/dist/piRuntime.js +120 -0
  27. package/dist/selfUpdate.js +47 -2
  28. package/dist/utils.js +232 -115
  29. package/package.json +5 -7
  30. package/dist/codieStartup.js +0 -27
  31. package/dist/commands/promote.js +0 -53
  32. package/dist/commands/react.js +0 -38
  33. package/dist/commands/reverseTicket.js +0 -444
  34. package/dist/commands/security.js +0 -156
  35. package/dist/prUrl.js +0 -28
  36. package/dist/security.js +0 -417
  37. package/dist/securityDeepScan.js +0 -235
  38. package/dist/securityDoctor.js +0 -61
  39. package/dist/securityFeature.js +0 -6
  40. package/dist/securityInstall.js +0 -232
  41. package/dist/securityInventory.js +0 -566
  42. package/dist/securityPilot.js +0 -59
  43. package/dist/securityPolicy.js +0 -181
  44. package/dist/securitySession.js +0 -72
@@ -1,235 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.mergeDeepScanFindings = mergeDeepScanFindings;
37
- exports.runDeepSecurityScan = runDeepSecurityScan;
38
- const child_process_1 = require("child_process");
39
- const fs = __importStar(require("fs"));
40
- const os = __importStar(require("os"));
41
- const path = __importStar(require("path"));
42
- function mergeDeepScanFindings(report, deep) {
43
- const byComponent = new Map();
44
- for (const finding of deep.findings) {
45
- if (!finding.componentKey)
46
- continue;
47
- const current = byComponent.get(finding.componentKey) ?? [];
48
- current.push(finding);
49
- byComponent.set(finding.componentKey, current);
50
- }
51
- return {
52
- ...report,
53
- components: report.components.map((component) => {
54
- const external = byComponent.get(component.componentKey) ?? [];
55
- const findings = [
56
- ...component.findings,
57
- ...external.map((finding) => ({
58
- code: `oss:${finding.scanner}:${finding.ruleId ?? "finding"}`.slice(0, 240),
59
- severity: finding.severity,
60
- detail: finding.title,
61
- })),
62
- ];
63
- return {
64
- ...component,
65
- findings: [...new Map(findings.map((finding) => [`${finding.code}:${finding.detail}`, finding])).values()].slice(0, 100),
66
- };
67
- }),
68
- };
69
- }
70
- function defaultRunner(command, args, timeoutMs) {
71
- return (0, child_process_1.spawnSync)(command, args, { encoding: "utf8", timeout: timeoutMs, maxBuffer: 8 * 1024 * 1024 });
72
- }
73
- function actualPath(source, homeDir, workspace) {
74
- if (source === ".")
75
- return workspace;
76
- if (source.startsWith("~/"))
77
- return path.join(homeDir, source.slice(2));
78
- if (source.startsWith("[external:"))
79
- return null;
80
- return path.join(workspace, source);
81
- }
82
- function severity(value) {
83
- const normalized = String(value ?? "medium").toLowerCase();
84
- if (normalized === "critical" || normalized === "high" || normalized === "low")
85
- return normalized;
86
- return "medium";
87
- }
88
- function collectFindingObjects(value, scanner, componentKey) {
89
- const findings = [];
90
- const visit = (child, depth) => {
91
- if (depth > 8 || findings.length >= 500 || child === null || child === undefined)
92
- return;
93
- if (Array.isArray(child)) {
94
- for (const item of child.slice(0, 1_000))
95
- visit(item, depth + 1);
96
- return;
97
- }
98
- if (typeof child !== "object")
99
- return;
100
- const row = child;
101
- const ruleId = row.rule_id ?? row.ruleId ?? row.id ?? row.code;
102
- const title = row.title ?? row.rule_name ?? row.ruleName ?? row.name ??
103
- (ruleId !== undefined ? `Scanner finding ${String(ruleId)}` : undefined);
104
- const severityValue = row.severity ?? row.level ?? row.risk;
105
- const looksLikeFinding = typeof title === "string" && (severityValue !== undefined || ruleId !== undefined || row.match !== undefined || row.finding !== undefined);
106
- if (looksLikeFinding) {
107
- findings.push({
108
- scanner,
109
- ...(componentKey ? { componentKey } : {}),
110
- severity: severity(severityValue),
111
- ...(ruleId !== undefined ? { ruleId: String(ruleId).slice(0, 160) } : {}),
112
- title: String(title).replace(/\s+/g, " ").slice(0, 500),
113
- });
114
- }
115
- for (const nested of Object.values(row))
116
- visit(nested, depth + 1);
117
- };
118
- visit(value, 0);
119
- return [...new Map(findings.map((finding) => [
120
- `${finding.scanner}:${finding.componentKey}:${finding.ruleId}:${finding.title}`,
121
- finding,
122
- ])).values()];
123
- }
124
- function runJsonScanner(args) {
125
- const result = args.runner(args.command, args.commandArgs, args.timeoutMs);
126
- if (result.error && result.error.code === "ENOENT") {
127
- return { scanner: args.scanner, status: "unavailable", detail: `${args.command} is not installed`, findings: [] };
128
- }
129
- const stdout = String(result.stdout ?? "").trim();
130
- const stderr = String(result.stderr ?? "").trim();
131
- let parsed = null;
132
- if (stdout) {
133
- try {
134
- parsed = JSON.parse(stdout);
135
- }
136
- catch {
137
- const start = stdout.indexOf("{");
138
- const end = stdout.lastIndexOf("}");
139
- if (start >= 0 && end > start) {
140
- try {
141
- parsed = JSON.parse(stdout.slice(start, end + 1));
142
- }
143
- catch { }
144
- }
145
- }
146
- }
147
- const findings = collectFindingObjects(parsed, args.scanner, args.componentKey);
148
- if (result.status === 0 || findings.length > 0) {
149
- return {
150
- scanner: args.scanner,
151
- status: findings.length > 0 ? "findings" : "passed",
152
- detail: findings.length > 0 ? `${findings.length} finding(s)` : "scan completed with no findings",
153
- findings,
154
- };
155
- }
156
- return {
157
- scanner: args.scanner,
158
- status: "error",
159
- detail: (stderr || `scanner exited ${result.status ?? "without a status"}`).replace(/\s+/g, " ").slice(0, 500),
160
- findings: [],
161
- };
162
- }
163
- function pathsFor(report, kind, homeDir, workspace) {
164
- return report.components
165
- .filter((component) => component.kind === kind)
166
- .map((component) => ({ component, filePath: actualPath(component.source, homeDir, workspace) }))
167
- .filter((item) => Boolean(item.filePath && fs.existsSync(item.filePath)));
168
- }
169
- function runDeepSecurityScan(report, options = {}) {
170
- const homeDir = path.resolve(options.homeDir ?? os.homedir());
171
- const workspace = path.resolve(options.workspace ?? process.cwd());
172
- const timeoutMs = options.timeoutMs ?? 120_000;
173
- const runner = options.runner ?? defaultRunner;
174
- const runs = [];
175
- const skillPaths = pathsFor(report, "skill", homeDir, workspace);
176
- for (const { component, filePath } of skillPaths) {
177
- const cisco = runJsonScanner({
178
- scanner: "cisco-skill-scanner", command: "skill-scanner",
179
- commandArgs: ["scan", filePath, "--format", "json"], componentKey: component.componentKey,
180
- timeoutMs, runner,
181
- });
182
- if (cisco.status !== "unavailable")
183
- runs.push(cisco);
184
- else
185
- runs.push(runJsonScanner({
186
- scanner: "agent-threat-rules", command: "atr",
187
- commandArgs: ["scan", filePath, "--json", "--severity", "high", "--no-report"],
188
- componentKey: component.componentKey, timeoutMs, runner,
189
- }));
190
- }
191
- if (skillPaths.length === 0) {
192
- runs.push({ scanner: "skill", status: "skipped", detail: "no skills discovered", findings: [] });
193
- }
194
- runs.push(runJsonScanner({
195
- scanner: "osv-scanner", command: "osv-scanner",
196
- commandArgs: ["scan", "source", "-r", "--format", "json", workspace], timeoutMs, runner,
197
- }));
198
- if (options.connectMcp) {
199
- const configPaths = [...new Set(pathsFor(report, "mcp-server", homeDir, workspace).map((item) => item.filePath))];
200
- for (const configPath of configPaths) {
201
- runs.push(runJsonScanner({
202
- scanner: "cisco-mcp-scanner", command: "mcp-scanner",
203
- commandArgs: ["--config-path", configPath, "--analyzers", "yara", "--format", "raw"],
204
- timeoutMs, runner,
205
- }));
206
- }
207
- if (configPaths.length === 0)
208
- runs.push({ scanner: "cisco-mcp-scanner", status: "skipped", detail: "no MCP configurations discovered", findings: [] });
209
- }
210
- else {
211
- runs.push({ scanner: "cisco-mcp-scanner", status: "skipped", detail: "live MCP startup disabled; pass --connect-mcp to opt in", findings: [] });
212
- }
213
- if (options.supplyChain) {
214
- for (const { component } of pathsFor(report, "extension", homeDir, workspace)) {
215
- runs.push(runJsonScanner({
216
- scanner: "guarddog", command: "guarddog",
217
- commandArgs: [
218
- "extension", "scan", component.name,
219
- ...(component.version ? ["--version", component.version] : []),
220
- "--output-format=json",
221
- ],
222
- componentKey: component.componentKey, timeoutMs, runner,
223
- }));
224
- }
225
- }
226
- else {
227
- runs.push({ scanner: "guarddog", status: "skipped", detail: "registry downloads disabled; pass --supply-chain to opt in", findings: [] });
228
- }
229
- return {
230
- schemaVersion: 1,
231
- generatedAt: new Date((options.now ?? Date.now)()).toISOString(),
232
- runs,
233
- findings: runs.flatMap((run) => run.findings),
234
- };
235
- }
@@ -1,61 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.collectSecurityDoctorReport = collectSecurityDoctorReport;
4
- exports.securityDoctorChecks = securityDoctorChecks;
5
- const securityInstall_1 = require("./securityInstall");
6
- const securityPilot_1 = require("./securityPilot");
7
- const securityPolicy_1 = require("./securityPolicy");
8
- function collectSecurityDoctorReport(companyId) {
9
- const manifest = (0, securityInstall_1.readSecurityInstallManifest)();
10
- const integrity = (0, securityInstall_1.verifySecurityInstallManifest)(manifest);
11
- const installations = (0, securityInstall_1.inspectSecurityInstallation)();
12
- const pilot = (0, securityPilot_1.runSyntheticSecurityPilot)();
13
- const policy = (0, securityPolicy_1.inspectEndpointSecurityPolicy)(undefined, undefined, companyId);
14
- const ok = integrity.ok &&
15
- policy.verification.ok &&
16
- pilot.ok &&
17
- !installations.some((result) => result.status === "fail");
18
- return {
19
- schemaVersion: 1,
20
- ok,
21
- integrity,
22
- manifest,
23
- installations,
24
- policyExists: policy.exists,
25
- policySignature: policy.verification,
26
- policySelfTest: { ok: pilot.ok, cases: pilot.cases.length },
27
- };
28
- }
29
- function securityDoctorChecks(report) {
30
- const checks = [
31
- {
32
- name: "Agent Security hook integrity",
33
- status: report.integrity.ok ? "pass" : "fail",
34
- detail: report.integrity.detail,
35
- },
36
- ...report.installations.map((installation) => ({
37
- name: `Agent Security ${installation.surface}`,
38
- status: installation.status === "pass"
39
- ? "pass"
40
- : installation.status === "not-installed"
41
- ? "warn"
42
- : "fail",
43
- detail: installation.detail,
44
- })),
45
- {
46
- name: "Agent Security policy",
47
- status: !report.policyExists
48
- ? "warn"
49
- : report.policySignature.ok
50
- ? "pass"
51
- : "fail",
52
- detail: report.policySignature.detail,
53
- },
54
- {
55
- name: "Agent Security policy self-test",
56
- status: report.policySelfTest.ok ? "pass" : "fail",
57
- detail: `${report.policySelfTest.cases} deterministic cases`,
58
- },
59
- ];
60
- return checks;
61
- }
@@ -1,6 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isAgentSecurityEnabled = isAgentSecurityEnabled;
4
- function isAgentSecurityEnabled(config) {
5
- return config?.agentSecurityEnabled === true;
6
- }
@@ -1,232 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.createSecurityInstallSnapshot = createSecurityInstallSnapshot;
37
- exports.writeSecurityInstallManifest = writeSecurityInstallManifest;
38
- exports.readSecurityInstallManifest = readSecurityInstallManifest;
39
- exports.verifySecurityInstallManifest = verifySecurityInstallManifest;
40
- exports.restoreSecurityInstallSnapshot = restoreSecurityInstallSnapshot;
41
- exports.inspectSecurityInstallation = inspectSecurityInstallation;
42
- const crypto = __importStar(require("crypto"));
43
- const fs = __importStar(require("fs"));
44
- const os = __importStar(require("os"));
45
- const path = __importStar(require("path"));
46
- const configDir_1 = require("./configDir");
47
- const detection_1 = require("./detection");
48
- const codexHookTrust_1 = require("./codexHookTrust");
49
- const version_1 = require("./version");
50
- const copilotInstallation_1 = require("./copilotInstallation");
51
- const harnessDirs_1 = require("./harnessDirs");
52
- const MANIFEST_FILE = "security-install.json";
53
- function sha256File(filePath) {
54
- return crypto.createHash("sha256").update(fs.readFileSync(filePath)).digest("hex");
55
- }
56
- function safeSnapshotName(index, filePath) {
57
- const digest = crypto.createHash("sha256").update(filePath).digest("hex").slice(0, 12);
58
- return `${String(index + 1).padStart(2, "0")}-${digest}-${path.basename(filePath)}`;
59
- }
60
- function createSecurityInstallSnapshot(configPaths, stateDir = (0, configDir_1.codiedevStateDir)(), now = Date.now) {
61
- const timestamp = now();
62
- const id = `${timestamp}-${process.pid}`;
63
- const snapshotDir = path.join(stateDir, "security-rollbacks", id);
64
- fs.mkdirSync(snapshotDir, { recursive: true, mode: 0o700 });
65
- const files = [];
66
- for (const [index, originalPath] of [...new Set(configPaths)].entries()) {
67
- if (!fs.existsSync(originalPath) || !fs.statSync(originalPath).isFile())
68
- continue;
69
- const snapshotPath = path.join(snapshotDir, safeSnapshotName(index, originalPath));
70
- fs.copyFileSync(originalPath, snapshotPath);
71
- fs.chmodSync(snapshotPath, 0o600);
72
- files.push({ originalPath, snapshotPath });
73
- }
74
- return { id, createdAt: new Date(timestamp).toISOString(), files };
75
- }
76
- function writeSecurityInstallManifest(options) {
77
- const stateDir = options.stateDir ?? (0, configDir_1.codiedevStateDir)();
78
- const now = options.now ?? Date.now;
79
- if (!fs.existsSync(options.hookScriptPath)) {
80
- throw new Error(`security hook script not found: ${options.hookScriptPath}`);
81
- }
82
- const manifest = {
83
- schemaVersion: 1,
84
- cliVersion: version_1.CLI_VERSION,
85
- installedAt: new Date(now()).toISOString(),
86
- hookScriptPath: path.resolve(options.hookScriptPath),
87
- hookScriptSha256: sha256File(options.hookScriptPath),
88
- targets: options.targets,
89
- rollbackSnapshotId: options.snapshot.id,
90
- rollbackFiles: options.snapshot.files,
91
- };
92
- fs.mkdirSync(stateDir, { recursive: true, mode: 0o700 });
93
- const manifestPath = path.join(stateDir, MANIFEST_FILE);
94
- fs.writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, { mode: 0o600 });
95
- fs.chmodSync(manifestPath, 0o600);
96
- return manifest;
97
- }
98
- function readSecurityInstallManifest(stateDir = (0, configDir_1.codiedevStateDir)()) {
99
- try {
100
- const value = JSON.parse(fs.readFileSync(path.join(stateDir, MANIFEST_FILE), "utf8"));
101
- return value?.schemaVersion === 1 ? value : null;
102
- }
103
- catch {
104
- return null;
105
- }
106
- }
107
- function verifySecurityInstallManifest(manifest) {
108
- if (!manifest)
109
- return { ok: false, detail: "security install manifest is missing" };
110
- if (!fs.existsSync(manifest.hookScriptPath)) {
111
- return { ok: false, detail: "recorded security hook script is missing" };
112
- }
113
- if (sha256File(manifest.hookScriptPath) !== manifest.hookScriptSha256) {
114
- return {
115
- ok: false,
116
- detail: "installed hook does not match the recorded SHA-256 integrity digest",
117
- };
118
- }
119
- return {
120
- ok: true,
121
- detail: `v${manifest.cliVersion}; rollback snapshot ${manifest.rollbackSnapshotId} available`,
122
- };
123
- }
124
- function restoreSecurityInstallSnapshot(manifest) {
125
- if (!manifest)
126
- throw new Error("security install manifest is missing");
127
- let restored = 0;
128
- for (const file of manifest.rollbackFiles) {
129
- const snapshotPath = path.resolve(file.snapshotPath);
130
- const snapshotDir = path.dirname(snapshotPath);
131
- if (path.basename(snapshotDir) !== manifest.rollbackSnapshotId ||
132
- path.basename(path.dirname(snapshotDir)) !== "security-rollbacks") {
133
- throw new Error(`rollback file does not match rollback snapshot ${manifest.rollbackSnapshotId}`);
134
- }
135
- if (!fs.existsSync(snapshotPath) || !fs.statSync(snapshotPath).isFile()) {
136
- throw new Error(`rollback file is missing: ${snapshotPath}`);
137
- }
138
- const originalPath = path.resolve(file.originalPath);
139
- fs.mkdirSync(path.dirname(originalPath), { recursive: true, mode: 0o700 });
140
- const temporaryPath = `${originalPath}.codiedev-rollback-${process.pid}`;
141
- fs.copyFileSync(snapshotPath, temporaryPath);
142
- fs.chmodSync(temporaryPath, 0o600);
143
- fs.renameSync(temporaryPath, originalPath);
144
- restored += 1;
145
- }
146
- return { restored, snapshotId: manifest.rollbackSnapshotId };
147
- }
148
- function hookCommands(parsed, eventName, allowFlat) {
149
- const entries = parsed?.hooks?.[eventName];
150
- if (!Array.isArray(entries))
151
- return [];
152
- const commands = [];
153
- for (const entry of entries) {
154
- const flatCommand = entry.command;
155
- if (allowFlat && typeof flatCommand === "string" && (0, detection_1.isCodiedevHookCommand)(flatCommand)) {
156
- commands.push(flatCommand);
157
- }
158
- const nested = entry?.hooks;
159
- if (!Array.isArray(nested))
160
- continue;
161
- for (const hook of nested) {
162
- if (typeof hook.command === "string" && (0, detection_1.isCodiedevHookCommand)(hook.command)) {
163
- commands.push(hook.command);
164
- }
165
- }
166
- }
167
- return commands;
168
- }
169
- function inspectJsonSurface(surface, filePath, codexConfigPath) {
170
- if (!fs.existsSync(filePath)) {
171
- return { surface, status: "not-installed", detail: `${filePath} not found` };
172
- }
173
- try {
174
- const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
175
- const expected = surface === "cursor"
176
- ? [
177
- ["beforeSubmitPrompt", "security-prompt-cursor"],
178
- ["preToolUse", "security-pre-cursor"],
179
- ["postToolUse", "security-post-cursor"],
180
- ["postToolUseFailure", "security-failure-cursor"],
181
- ]
182
- : [
183
- ["UserPromptSubmit", surface === "codex" ? "discover-codex" : "discover"],
184
- ["PreToolUse", surface === "codex" ? "security-pre-codex" : "security-pre"],
185
- ["PostToolUse", surface === "codex" ? "security-post-codex" : "security-post"],
186
- ...(surface === "claude-code"
187
- ? [["PostToolUseFailure", "security-failure"]]
188
- : []),
189
- ];
190
- const missing = expected
191
- .filter(([eventName, subcommand]) => !hookCommands(parsed, eventName, surface === "cursor").some((command) => command.trim().endsWith(subcommand)))
192
- .map(([eventName]) => eventName);
193
- if (missing.length > 0) {
194
- return { surface, status: "fail", detail: `missing security hooks: ${missing.join(", ")}` };
195
- }
196
- if (surface === "codex") {
197
- const trust = (0, codexHookTrust_1.inspectCodexHookTrust)(codexConfigPath ?? path.join(path.dirname(filePath), "config.toml"), filePath, parsed, ["discover-codex", "security-pre-codex", "security-post-codex"]);
198
- if (!trust.ok) {
199
- return { surface, status: "fail", detail: `Codex hook trust missing or stale (${trust.trusted}/${trust.total} trusted)` };
200
- }
201
- }
202
- return { surface, status: "pass", detail: "prompt guard and tool telemetry hooks installed and active" };
203
- }
204
- catch (error) {
205
- return { surface, status: "fail", detail: `invalid hook configuration: ${error.message}` };
206
- }
207
- }
208
- function inspectSecurityInstallation(paths = {}) {
209
- const home = os.homedir();
210
- const claude = paths.claudeSettingsPath ?? path.join((0, harnessDirs_1.claudeConfigDir)(), "settings.json");
211
- const codex = paths.codexHooksPath ?? path.join((0, harnessDirs_1.codexHome)(), "hooks.json");
212
- const cursor = paths.cursorHooksPath ?? path.join(home, ".cursor", "hooks.json");
213
- const codie = paths.codiePluginPath ?? path.join((0, harnessDirs_1.openCodeConfigDir)(), "plugins", "codiedev.js");
214
- const results = [
215
- inspectJsonSurface("claude-code", claude),
216
- inspectJsonSurface("codex", codex, paths.codexConfigPath),
217
- inspectJsonSurface("cursor", cursor),
218
- { surface: "copilot", ...(0, copilotInstallation_1.inspectCopilotHooks)(paths.copilotHooksPath, true) },
219
- ];
220
- if (!fs.existsSync(codie)) {
221
- results.push({ surface: "codie-harness", status: "not-installed", detail: `${codie} not found` });
222
- }
223
- else {
224
- const source = fs.readFileSync(codie, "utf8");
225
- const markers = ["security-pre-codie", "security-post-codie", "chat.message", "tool.execute.before", "tool.execute.after"];
226
- const missing = markers.filter((marker) => !source.includes(marker));
227
- results.push(missing.length === 0
228
- ? { surface: "codie-harness", status: "pass", detail: "prompt guard and tool telemetry adapter installed" }
229
- : { surface: "codie-harness", status: "fail", detail: `adapter missing: ${missing.join(", ")}` });
230
- }
231
- return results;
232
- }