@praxis.guard/auditor-cli 0.0.44 → 0.0.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/adapters/claude-code/adapter.d.ts +28 -0
- package/dist/adapters/claude-code/adapter.d.ts.map +1 -0
- package/dist/adapters/claude-code/adapter.js +141 -0
- package/dist/adapters/claude-code/adapter.js.map +1 -0
- package/dist/adapters/claude-code/config-detect.d.ts +4 -0
- package/dist/adapters/claude-code/config-detect.d.ts.map +1 -0
- package/dist/adapters/claude-code/config-detect.js +44 -0
- package/dist/adapters/claude-code/config-detect.js.map +1 -0
- package/dist/adapters/claude-code/config-io.d.ts +8 -0
- package/dist/adapters/claude-code/config-io.d.ts.map +1 -0
- package/dist/adapters/claude-code/config-io.js +41 -0
- package/dist/adapters/claude-code/config-io.js.map +1 -0
- package/dist/adapters/claude-code/index.d.ts +3 -0
- package/dist/adapters/claude-code/index.d.ts.map +1 -0
- package/dist/adapters/claude-code/index.js +3 -0
- package/dist/adapters/claude-code/index.js.map +1 -0
- package/dist/adapters/claude-code/paths.d.ts +17 -0
- package/dist/adapters/claude-code/paths.d.ts.map +1 -0
- package/dist/adapters/claude-code/paths.js +32 -0
- package/dist/adapters/claude-code/paths.js.map +1 -0
- package/dist/adapters/claude-code.d.ts +1 -33
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +1 -246
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/codex.d.ts +11 -0
- package/dist/adapters/codex.d.ts.map +1 -0
- package/dist/adapters/codex.js +52 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/registry.d.ts.map +1 -1
- package/dist/adapters/registry.js +2 -0
- package/dist/adapters/registry.js.map +1 -1
- package/dist/adapters/select-targets.js +3 -3
- package/dist/adapters/select-targets.js.map +1 -1
- package/dist/adapters/types.d.ts +9 -2
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/bridge/execution-ticket-consume.d.ts +12 -0
- package/dist/bridge/execution-ticket-consume.d.ts.map +1 -0
- package/dist/bridge/execution-ticket-consume.js +105 -0
- package/dist/bridge/execution-ticket-consume.js.map +1 -0
- package/dist/bridge/execution-ticket-match.d.ts +4 -0
- package/dist/bridge/execution-ticket-match.d.ts.map +1 -0
- package/dist/bridge/execution-ticket-match.js +40 -0
- package/dist/bridge/execution-ticket-match.js.map +1 -0
- package/dist/bridge/execution-ticket-record.d.ts +14 -0
- package/dist/bridge/execution-ticket-record.d.ts.map +1 -0
- package/dist/bridge/execution-ticket-record.js +51 -0
- package/dist/bridge/execution-ticket-record.js.map +1 -0
- package/dist/bridge/execution-ticket.d.ts +2 -23
- package/dist/bridge/execution-ticket.d.ts.map +1 -1
- package/dist/bridge/execution-ticket.js +2 -179
- package/dist/bridge/execution-ticket.js.map +1 -1
- package/dist/cli/dispatch-hook.d.ts +2 -0
- package/dist/cli/dispatch-hook.d.ts.map +1 -0
- package/dist/cli/dispatch-hook.js +29 -0
- package/dist/cli/dispatch-hook.js.map +1 -0
- package/dist/cli/dispatch-setup.d.ts +2 -0
- package/dist/cli/dispatch-setup.d.ts.map +1 -0
- package/dist/cli/dispatch-setup.js +34 -0
- package/dist/cli/dispatch-setup.js.map +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +17 -13
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/help.d.ts +2 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +61 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +6 -96
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/setup-all.d.ts.map +1 -1
- package/dist/cli/setup-all.js +6 -2
- package/dist/cli/setup-all.js.map +1 -1
- package/dist/cli/setup-codex.d.ts +9 -0
- package/dist/cli/setup-codex.d.ts.map +1 -0
- package/dist/cli/setup-codex.js +61 -0
- package/dist/cli/setup-codex.js.map +1 -0
- package/dist/cli/setup-doctor.d.ts.map +1 -1
- package/dist/cli/setup-doctor.js +22 -7
- package/dist/cli/setup-doctor.js.map +1 -1
- package/dist/cli/setup-mcp.d.ts +1 -0
- package/dist/cli/setup-mcp.d.ts.map +1 -1
- package/dist/cli/setup-mcp.js +15 -2
- package/dist/cli/setup-mcp.js.map +1 -1
- package/dist/codex/config.d.ts +23 -0
- package/dist/codex/config.d.ts.map +1 -0
- package/dist/codex/config.js +177 -0
- package/dist/codex/config.js.map +1 -0
- package/dist/codex/evaluate-tool-audit.d.ts +29 -0
- package/dist/codex/evaluate-tool-audit.d.ts.map +1 -0
- package/dist/codex/evaluate-tool-audit.js +58 -0
- package/dist/codex/evaluate-tool-audit.js.map +1 -0
- package/dist/codex/evaluate-tool-bash.d.ts +3 -0
- package/dist/codex/evaluate-tool-bash.d.ts.map +1 -0
- package/dist/codex/evaluate-tool-bash.js +50 -0
- package/dist/codex/evaluate-tool-bash.js.map +1 -0
- package/dist/codex/evaluate-tool-mcp.d.ts +3 -0
- package/dist/codex/evaluate-tool-mcp.d.ts.map +1 -0
- package/dist/codex/evaluate-tool-mcp.js +55 -0
- package/dist/codex/evaluate-tool-mcp.js.map +1 -0
- package/dist/codex/evaluate-tool-types.d.ts +27 -0
- package/dist/codex/evaluate-tool-types.d.ts.map +1 -0
- package/dist/codex/evaluate-tool-types.js +15 -0
- package/dist/codex/evaluate-tool-types.js.map +1 -0
- package/dist/codex/evaluate-tool.d.ts +5 -0
- package/dist/codex/evaluate-tool.d.ts.map +1 -0
- package/dist/codex/evaluate-tool.js +19 -0
- package/dist/codex/evaluate-tool.js.map +1 -0
- package/dist/codex/permission-handoff.d.ts +13 -0
- package/dist/codex/permission-handoff.d.ts.map +1 -0
- package/dist/codex/permission-handoff.js +36 -0
- package/dist/codex/permission-handoff.js.map +1 -0
- package/dist/hooks/run-codex-hooks.d.ts +3 -0
- package/dist/hooks/run-codex-hooks.d.ts.map +1 -0
- package/dist/hooks/run-codex-hooks.js +77 -0
- package/dist/hooks/run-codex-hooks.js.map +1 -0
- package/dist/policy/classify.d.ts +9 -0
- package/dist/policy/classify.d.ts.map +1 -0
- package/dist/policy/classify.js +97 -0
- package/dist/policy/classify.js.map +1 -0
- package/dist/policy/index.d.ts +5 -54
- package/dist/policy/index.d.ts.map +1 -1
- package/dist/policy/index.js +4 -213
- package/dist/policy/index.js.map +1 -1
- package/dist/policy/load.d.ts +8 -0
- package/dist/policy/load.d.ts.map +1 -0
- package/dist/policy/load.js +52 -0
- package/dist/policy/load.js.map +1 -0
- package/dist/policy/paths.d.ts +9 -0
- package/dist/policy/paths.d.ts.map +1 -0
- package/dist/policy/paths.js +42 -0
- package/dist/policy/paths.js.map +1 -0
- package/dist/policy/schema.d.ts +35 -0
- package/dist/policy/schema.d.ts.map +1 -0
- package/dist/policy/schema.js +30 -0
- package/dist/policy/schema.js.map +1 -0
- package/dist/telemetry/agent-host.d.ts +1 -1
- package/dist/telemetry/agent-host.d.ts.map +1 -1
- package/dist/telemetry/agent-host.js +7 -1
- package/dist/telemetry/agent-host.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,247 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
3
|
-
import os from "node:os";
|
|
4
|
-
import path from "node:path";
|
|
5
|
-
const MCP_SERVER_KEY = "praxis-guard";
|
|
6
|
-
const AGENT_HOST = "claude-code";
|
|
7
|
-
const HOOK_COMMAND = "auditor hook claude-code";
|
|
8
|
-
/**
|
|
9
|
-
* Resolve the Claude Code global config file path (~/.claude.json).
|
|
10
|
-
*
|
|
11
|
-
* Set `PRAXIS_CLAUDE_CODE_SETTINGS` to override (used by tests).
|
|
12
|
-
*/
|
|
13
|
-
export function claudeCodeSettingsPath() {
|
|
14
|
-
const override = process.env.PRAXIS_CLAUDE_CODE_SETTINGS?.trim();
|
|
15
|
-
if (override)
|
|
16
|
-
return override;
|
|
17
|
-
return path.join(os.homedir(), ".claude.json");
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Resolve the Claude Code install directory used for detection.
|
|
21
|
-
* When PRAXIS_CLAUDE_CODE_SETTINGS is set (test mode), use its parent dir
|
|
22
|
-
* so detectInstalled() stays hermetic in tests.
|
|
23
|
-
*/
|
|
24
|
-
function claudeCodeInstallDir() {
|
|
25
|
-
const override = process.env.PRAXIS_CLAUDE_CODE_SETTINGS?.trim();
|
|
26
|
-
if (override)
|
|
27
|
-
return path.dirname(override);
|
|
28
|
-
return path.join(os.homedir(), ".claude");
|
|
29
|
-
}
|
|
30
|
-
async function readJson(pathname) {
|
|
31
|
-
try {
|
|
32
|
-
const raw = await readFile(pathname, "utf8");
|
|
33
|
-
const parsed = JSON.parse(raw);
|
|
34
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
35
|
-
throw new Error("JSON root must be an object");
|
|
36
|
-
}
|
|
37
|
-
return parsed;
|
|
38
|
-
}
|
|
39
|
-
catch (e) {
|
|
40
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
41
|
-
if (e.code === "ENOENT")
|
|
42
|
-
return null;
|
|
43
|
-
throw new Error([
|
|
44
|
-
`Invalid JSON at ${pathname}: ${msg}`,
|
|
45
|
-
"Refusing to overwrite existing file.",
|
|
46
|
-
"Fix the JSON manually or back up the file and re-run setup.",
|
|
47
|
-
].join(" "));
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Atomic write: write to a temp file then rename into place.
|
|
52
|
-
* Prevents partial writes from corrupting ~/.claude.json.
|
|
53
|
-
*/
|
|
54
|
-
async function writeJsonAtomic(pathname, data) {
|
|
55
|
-
const dir = path.dirname(pathname);
|
|
56
|
-
await mkdir(dir, { recursive: true });
|
|
57
|
-
const tmp = path.join(dir, `.${path.basename(pathname)}.tmp.${Date.now()}`);
|
|
58
|
-
try {
|
|
59
|
-
await writeFile(tmp, `${JSON.stringify(data, null, 2)}\n`, "utf8");
|
|
60
|
-
await rename(tmp, pathname);
|
|
61
|
-
}
|
|
62
|
-
catch (e) {
|
|
63
|
-
// Best-effort cleanup of the temp file on failure.
|
|
64
|
-
await writeFile(tmp, "", "utf8").catch(() => undefined);
|
|
65
|
-
throw e;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
function hasConfiguredMcpServer(config) {
|
|
69
|
-
if (!config)
|
|
70
|
-
return false;
|
|
71
|
-
const servers = (config.mcpServers ?? {});
|
|
72
|
-
const server = servers[MCP_SERVER_KEY];
|
|
73
|
-
if (!server || typeof server !== "object")
|
|
74
|
-
return false;
|
|
75
|
-
const map = server;
|
|
76
|
-
if (map.command !== "auditor")
|
|
77
|
-
return false;
|
|
78
|
-
if (!Array.isArray(map.args) || map.args.length !== 1 || map.args[0] !== "mcp")
|
|
79
|
-
return false;
|
|
80
|
-
const env = map.env;
|
|
81
|
-
if (!env || typeof env !== "object")
|
|
82
|
-
return false;
|
|
83
|
-
return env.PRAXIS_AGENT_HOST === AGENT_HOST;
|
|
84
|
-
}
|
|
85
|
-
function hasConfiguredPreToolUseHook(config) {
|
|
86
|
-
if (!config)
|
|
87
|
-
return false;
|
|
88
|
-
const hooks = config.hooks;
|
|
89
|
-
if (!hooks || typeof hooks !== "object" || Array.isArray(hooks))
|
|
90
|
-
return false;
|
|
91
|
-
const preToolUse = hooks.PreToolUse;
|
|
92
|
-
if (!Array.isArray(preToolUse))
|
|
93
|
-
return false;
|
|
94
|
-
return preToolUse.some((entry) => {
|
|
95
|
-
if (!entry || typeof entry !== "object")
|
|
96
|
-
return false;
|
|
97
|
-
const e = entry;
|
|
98
|
-
if (e.matcher !== "Bash")
|
|
99
|
-
return false;
|
|
100
|
-
const innerHooks = e.hooks;
|
|
101
|
-
if (!Array.isArray(innerHooks))
|
|
102
|
-
return false;
|
|
103
|
-
return innerHooks.some((h) => {
|
|
104
|
-
if (!h || typeof h !== "object")
|
|
105
|
-
return false;
|
|
106
|
-
return h.command === HOOK_COMMAND;
|
|
107
|
-
});
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* ClaudeCodeAdapter: hook (PreToolUse on Bash) + MCP, both in ~/.claude.json.
|
|
112
|
-
*
|
|
113
|
-
* Unlike ClaudeDesktopAdapter (MCP-only), Claude Code exposes a PreToolUse hook that
|
|
114
|
-
* fires before every Bash tool call, giving Praxis shell governance.
|
|
115
|
-
*
|
|
116
|
-
* IMPORTANT — hook output format:
|
|
117
|
-
* Verify the exact format with a test script before relying on this adapter in production.
|
|
118
|
-
* Run docs/auditor-cli-claude-code-hook-format-test.sh and confirm Claude Code blocks.
|
|
119
|
-
* If the format is wrong, edit HOOK_BLOCK_RESPONSE in run-claude-code-pre-tool-use.ts.
|
|
120
|
-
*
|
|
121
|
-
* Binary path:
|
|
122
|
-
* The hook config uses the bare "auditor" command (consistent with Cursor's adapter),
|
|
123
|
-
* NOT an absolute path. Absolute paths break with mise/nvm node version upgrades.
|
|
124
|
-
* At setup time we warn if auditor is not on PATH, but do not abort.
|
|
125
|
-
*
|
|
126
|
-
* See docs/auditor-cli-multi-agent-adapter-design.md.
|
|
127
|
-
*/
|
|
128
|
-
export class ClaudeCodeAdapter {
|
|
129
|
-
id = "claude-code";
|
|
130
|
-
label = "Claude Code";
|
|
131
|
-
detectInstalled() {
|
|
132
|
-
return existsSync(claudeCodeInstallDir());
|
|
133
|
-
}
|
|
134
|
-
async upsertHook(opts) {
|
|
135
|
-
const dryRun = opts.dryRun ?? false;
|
|
136
|
-
const cfgPath = opts.explicitPath?.trim() || claudeCodeSettingsPath();
|
|
137
|
-
const existing = await readJson(cfgPath);
|
|
138
|
-
const before = JSON.stringify(existing ?? {});
|
|
139
|
-
const config = existing ? JSON.parse(JSON.stringify(existing)) : {};
|
|
140
|
-
if (!config.hooks || typeof config.hooks !== "object" || Array.isArray(config.hooks)) {
|
|
141
|
-
config.hooks = {};
|
|
142
|
-
}
|
|
143
|
-
const hooksMap = config.hooks;
|
|
144
|
-
if (!Array.isArray(hooksMap.PreToolUse)) {
|
|
145
|
-
hooksMap.PreToolUse = [];
|
|
146
|
-
}
|
|
147
|
-
const preToolUse = hooksMap.PreToolUse;
|
|
148
|
-
// Remove any existing Praxis PreToolUse[Bash] entry (idempotent upsert).
|
|
149
|
-
const filtered = preToolUse.filter((entry) => {
|
|
150
|
-
if (!entry || typeof entry !== "object")
|
|
151
|
-
return true;
|
|
152
|
-
const e = entry;
|
|
153
|
-
if (e.matcher !== "Bash")
|
|
154
|
-
return true;
|
|
155
|
-
const innerHooks = e.hooks;
|
|
156
|
-
if (!Array.isArray(innerHooks))
|
|
157
|
-
return true;
|
|
158
|
-
return !innerHooks.some((h) => {
|
|
159
|
-
if (!h || typeof h !== "object")
|
|
160
|
-
return false;
|
|
161
|
-
return h.command === HOOK_COMMAND;
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
filtered.push({
|
|
165
|
-
matcher: "Bash",
|
|
166
|
-
hooks: [{ type: "command", command: HOOK_COMMAND }],
|
|
167
|
-
});
|
|
168
|
-
hooksMap.PreToolUse = filtered;
|
|
169
|
-
const changed = before !== JSON.stringify(config);
|
|
170
|
-
if (changed && !dryRun) {
|
|
171
|
-
await writeJsonAtomic(cfgPath, config);
|
|
172
|
-
}
|
|
173
|
-
return {
|
|
174
|
-
path: cfgPath,
|
|
175
|
-
changed,
|
|
176
|
-
message: changed
|
|
177
|
-
? dryRun
|
|
178
|
-
? "would update Claude Code hook config (PreToolUse)"
|
|
179
|
-
: "updated Claude Code hook config (PreToolUse)"
|
|
180
|
-
: "Claude Code hook config already up to date",
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
async upsertMcp(opts) {
|
|
184
|
-
const dryRun = opts.dryRun ?? false;
|
|
185
|
-
const cfgPath = opts.explicitPath?.trim() || claudeCodeSettingsPath();
|
|
186
|
-
const existing = await readJson(cfgPath);
|
|
187
|
-
const before = JSON.stringify(existing ?? {});
|
|
188
|
-
const config = existing ? JSON.parse(JSON.stringify(existing)) : {};
|
|
189
|
-
if (!config.mcpServers || typeof config.mcpServers !== "object" || Array.isArray(config.mcpServers)) {
|
|
190
|
-
config.mcpServers = {};
|
|
191
|
-
}
|
|
192
|
-
const servers = config.mcpServers;
|
|
193
|
-
const existingEntry = servers[MCP_SERVER_KEY] && typeof servers[MCP_SERVER_KEY] === "object"
|
|
194
|
-
? servers[MCP_SERVER_KEY]
|
|
195
|
-
: {};
|
|
196
|
-
const existingEnv = existingEntry.env && typeof existingEntry.env === "object" && !Array.isArray(existingEntry.env)
|
|
197
|
-
? existingEntry.env
|
|
198
|
-
: {};
|
|
199
|
-
servers[MCP_SERVER_KEY] = {
|
|
200
|
-
...existingEntry,
|
|
201
|
-
command: "auditor",
|
|
202
|
-
args: ["mcp"],
|
|
203
|
-
env: { ...existingEnv, PRAXIS_AGENT_HOST: AGENT_HOST },
|
|
204
|
-
};
|
|
205
|
-
const changed = before !== JSON.stringify(config);
|
|
206
|
-
if (changed && !dryRun) {
|
|
207
|
-
await writeJsonAtomic(cfgPath, config);
|
|
208
|
-
}
|
|
209
|
-
return {
|
|
210
|
-
path: cfgPath,
|
|
211
|
-
changed,
|
|
212
|
-
message: changed
|
|
213
|
-
? dryRun
|
|
214
|
-
? "would update Claude Code MCP config"
|
|
215
|
-
: "updated Claude Code MCP config"
|
|
216
|
-
: "Claude Code MCP config already up to date",
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
async status(opts) {
|
|
220
|
-
const cfgPath = opts?.mcpConfigPath?.trim() || claudeCodeSettingsPath();
|
|
221
|
-
const config = await readJson(cfgPath).catch(() => null);
|
|
222
|
-
const hookConfigured = hasConfiguredPreToolUseHook(config);
|
|
223
|
-
const mcpConfigured = hasConfiguredMcpServer(config);
|
|
224
|
-
// Claude Code has one hook (PreToolUse) covering all tool calls.
|
|
225
|
-
// Report shell=true when PreToolUse is configured; mcp=true mirrors it
|
|
226
|
-
// (no separate MCP hook needed) so adapterReady() passes correctly.
|
|
227
|
-
const hook = {
|
|
228
|
-
global: {
|
|
229
|
-
shell: hookConfigured,
|
|
230
|
-
mcp: hookConfigured,
|
|
231
|
-
path: cfgPath,
|
|
232
|
-
},
|
|
233
|
-
};
|
|
234
|
-
const warnings = [];
|
|
235
|
-
if (hookConfigured && !mcpConfigured) {
|
|
236
|
-
warnings.push("Hook is configured but MCP is not. " +
|
|
237
|
-
"MUTATE approvals require both. Run: auditor setup mcp --for=claude-code");
|
|
238
|
-
}
|
|
239
|
-
return {
|
|
240
|
-
installed: this.detectInstalled(),
|
|
241
|
-
hook,
|
|
242
|
-
mcp: { configured: mcpConfigured, path: cfgPath },
|
|
243
|
-
warnings,
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
}
|
|
1
|
+
export { ClaudeCodeAdapter, claudeCodeSettingsPath } from "./claude-code/index.js";
|
|
247
2
|
//# sourceMappingURL=claude-code.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/adapters/claude-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/adapters/claude-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AgentAdapter, AgentStatus, SetupResult, StatusOpts, UpsertHookOpts, UpsertMcpOpts } from "./types.js";
|
|
2
|
+
export declare class CodexAdapter implements AgentAdapter {
|
|
3
|
+
readonly id: "codex";
|
|
4
|
+
readonly label = "Codex";
|
|
5
|
+
readonly preferredHookScope: "project";
|
|
6
|
+
detectInstalled(): boolean;
|
|
7
|
+
upsertHook(opts: UpsertHookOpts): Promise<SetupResult>;
|
|
8
|
+
upsertMcp(opts: UpsertMcpOpts): Promise<SetupResult>;
|
|
9
|
+
status(opts?: StatusOpts): Promise<AgentStatus>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=codex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,WAAW,EACX,UAAU,EACV,cAAc,EACd,aAAa,EACd,MAAM,YAAY,CAAC;AAMpB,qBAAa,YAAa,YAAW,YAAY;IAC/C,QAAQ,CAAC,EAAE,EAAG,OAAO,CAAU;IAC/B,QAAQ,CAAC,KAAK,WAAW;IACzB,QAAQ,CAAC,kBAAkB,EAAG,SAAS,CAAU;IAEjD,eAAe,IAAI,OAAO;IAI1B,UAAU,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC;IAItD,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC;IAI9C,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC;CAoCtD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { readCodexSetupStatus, upsertCodexConfig, upsertCodexHooks, } from "../codex/config.js";
|
|
5
|
+
function codexHomeDir() {
|
|
6
|
+
return process.env.CODEX_HOME?.trim() || path.join(os.homedir(), ".codex");
|
|
7
|
+
}
|
|
8
|
+
export class CodexAdapter {
|
|
9
|
+
id = "codex";
|
|
10
|
+
label = "Codex";
|
|
11
|
+
preferredHookScope = "project";
|
|
12
|
+
detectInstalled() {
|
|
13
|
+
return existsSync(codexHomeDir());
|
|
14
|
+
}
|
|
15
|
+
upsertHook(opts) {
|
|
16
|
+
return upsertCodexHooks(opts.projectDir || process.cwd(), opts.dryRun);
|
|
17
|
+
}
|
|
18
|
+
upsertMcp(opts) {
|
|
19
|
+
return upsertCodexConfig(opts.projectDir || process.cwd(), opts.dryRun);
|
|
20
|
+
}
|
|
21
|
+
async status(opts) {
|
|
22
|
+
const projectDir = opts?.projectDir || process.cwd();
|
|
23
|
+
const codex = await readCodexSetupStatus(projectDir);
|
|
24
|
+
const warnings = [];
|
|
25
|
+
if (codex.preToolUseConfigured && !codex.permissionRequestConfigured) {
|
|
26
|
+
warnings.push("PreToolUse is configured but PermissionRequest is missing. Run: auditor setup hook --for=codex --project " +
|
|
27
|
+
projectDir);
|
|
28
|
+
}
|
|
29
|
+
if ((codex.preToolUseConfigured || codex.permissionRequestConfigured) && !codex.mcpConfigured) {
|
|
30
|
+
warnings.push("Hooks are configured but MCP is missing. Run: auditor setup mcp --for=codex --project " +
|
|
31
|
+
projectDir);
|
|
32
|
+
}
|
|
33
|
+
if (!codex.agentsGuidancePresent) {
|
|
34
|
+
warnings.push("AGENTS.md is recommended for repo-local Codex guidance.");
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
installed: this.detectInstalled() || existsSync(path.join(projectDir, ".codex")),
|
|
38
|
+
hook: {
|
|
39
|
+
project: {
|
|
40
|
+
shell: codex.preToolUseConfigured,
|
|
41
|
+
mcp: codex.permissionRequestConfigured,
|
|
42
|
+
path: codex.hooksPath,
|
|
43
|
+
shellLabel: "PreToolUse",
|
|
44
|
+
mcpLabel: "PermissionRequest",
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
mcp: { configured: codex.mcpConfigured, path: codex.configPath },
|
|
48
|
+
warnings,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAW5B,SAAS,YAAY;IACnB,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,OAAO,YAAY;IACd,EAAE,GAAG,OAAgB,CAAC;IACtB,KAAK,GAAG,OAAO,CAAC;IAChB,kBAAkB,GAAG,SAAkB,CAAC;IAEjD,eAAe;QACb,OAAO,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,UAAU,CAAC,IAAoB;QAC7B,OAAO,gBAAgB,CAAC,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACzE,CAAC;IAED,SAAS,CAAC,IAAmB;QAC3B,OAAO,iBAAiB,CAAC,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,IAAiB;QAC5B,MAAM,UAAU,GAAG,IAAI,EAAE,UAAU,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACrD,MAAM,KAAK,GAAG,MAAM,oBAAoB,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,IAAI,KAAK,CAAC,oBAAoB,IAAI,CAAC,KAAK,CAAC,2BAA2B,EAAE,CAAC;YACrE,QAAQ,CAAC,IAAI,CACX,2GAA2G;gBACzG,UAAU,CACb,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,oBAAoB,IAAI,KAAK,CAAC,2BAA2B,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;YAC9F,QAAQ,CAAC,IAAI,CACX,wFAAwF;gBACtF,UAAU,CACb,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,qBAAqB,EAAE,CAAC;YACjC,QAAQ,CAAC,IAAI,CAAC,yDAAyD,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YAChF,IAAI,EAAE;gBACJ,OAAO,EAAE;oBACP,KAAK,EAAE,KAAK,CAAC,oBAAoB;oBACjC,GAAG,EAAE,KAAK,CAAC,2BAA2B;oBACtC,IAAI,EAAE,KAAK,CAAC,SAAS;oBACrB,UAAU,EAAE,YAAY;oBACxB,QAAQ,EAAE,mBAAmB;iBAC9B;aACF;YACD,GAAG,EAAE,EAAE,UAAU,EAAE,KAAK,CAAC,aAAa,EAAE,IAAI,EAAE,KAAK,CAAC,UAAU,EAAE;YAChE,QAAQ;SACT,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/adapters/registry.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/adapters/registry.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAExD;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,SAAS,YAAY,EAK/C,CAAC;AAEF,wBAAgB,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,YAAY,CAIpD;AAED,uDAAuD;AACvD,wBAAgB,uBAAuB,IAAI,YAAY,EAAE,CAQxD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ClaudeCodeAdapter } from "./claude-code.js";
|
|
2
2
|
import { ClaudeDesktopAdapter } from "./claude-desktop.js";
|
|
3
|
+
import { CodexAdapter } from "./codex.js";
|
|
3
4
|
import { CursorAdapter } from "./cursor.js";
|
|
4
5
|
/**
|
|
5
6
|
* The set of agent adapters known to the CLI. Adding a new host is one append
|
|
@@ -9,6 +10,7 @@ export const ALL_ADAPTERS = [
|
|
|
9
10
|
new CursorAdapter(),
|
|
10
11
|
new ClaudeDesktopAdapter(),
|
|
11
12
|
new ClaudeCodeAdapter(),
|
|
13
|
+
new CodexAdapter(),
|
|
12
14
|
];
|
|
13
15
|
export function getAdapter(id) {
|
|
14
16
|
const found = ALL_ADAPTERS.find((a) => a.id === id);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/adapters/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAA4B;IACnD,IAAI,aAAa,EAAE;IACnB,IAAI,oBAAoB,EAAE;IAC1B,IAAI,iBAAiB,EAAE;
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/adapters/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAA4B;IACnD,IAAI,aAAa,EAAE;IACnB,IAAI,oBAAoB,EAAE;IAC1B,IAAI,iBAAiB,EAAE;IACvB,IAAI,YAAY,EAAE;CACnB,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,EAAW;IACpC,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACpD,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,EAAE,EAAE,CAAC,CAAC;IACzE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,uBAAuB;IACrC,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAC/B,IAAI,CAAC;YACH,OAAO,CAAC,CAAC,eAAe,EAAE,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ALL_ADAPTERS, getAdapter } from "./registry.js";
|
|
2
|
-
const VALID_IDS = ["cursor", "claude-desktop", "claude-code"];
|
|
2
|
+
const VALID_IDS = ["cursor", "claude-desktop", "claude-code", "codex"];
|
|
3
3
|
/**
|
|
4
4
|
* Parse repeated `--for=<agent>` flags from a setup command's argv tail.
|
|
5
5
|
*
|
|
@@ -15,7 +15,7 @@ export function parseForFlag(args) {
|
|
|
15
15
|
if (arg === "--for") {
|
|
16
16
|
const value = args[i + 1];
|
|
17
17
|
if (!value)
|
|
18
|
-
throw new Error("Missing value for --for (expected: cursor | claude-desktop | claude-code)");
|
|
18
|
+
throw new Error("Missing value for --for (expected: cursor | claude-desktop | claude-code | codex)");
|
|
19
19
|
assertValidAgentId(value);
|
|
20
20
|
forIds.push(value);
|
|
21
21
|
i++;
|
|
@@ -24,7 +24,7 @@ export function parseForFlag(args) {
|
|
|
24
24
|
if (arg.startsWith("--for=")) {
|
|
25
25
|
const value = arg.slice("--for=".length);
|
|
26
26
|
if (!value)
|
|
27
|
-
throw new Error("Missing value for --for= (expected: cursor | claude-desktop | claude-code)");
|
|
27
|
+
throw new Error("Missing value for --for= (expected: cursor | claude-desktop | claude-code | codex)");
|
|
28
28
|
assertValidAgentId(value);
|
|
29
29
|
forIds.push(value);
|
|
30
30
|
continue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select-targets.js","sourceRoot":"","sources":["../../src/adapters/select-targets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGzD,MAAM,SAAS,GAAuB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,aAAa,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"select-targets.js","sourceRoot":"","sources":["../../src/adapters/select-targets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGzD,MAAM,SAAS,GAAuB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;AAE3F;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAc;IACzC,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,IAAI,GAAG,KAAK,OAAO,EAAE,CAAC;YACpB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,mFAAmF,CAAC,CAAC;YACjH,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnB,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,CAAC,KAAK;gBAAE,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC,CAAC;YAClH,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC1B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACnB,SAAS;QACX,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAa;IACvC,IAAI,CAAE,SAA+B,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACtD,MAAM,IAAI,KAAK,CAAC,qBAAqB,KAAK,gBAAgB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpF,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAmB;IACtD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;IAC9C,CAAC;IACD,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QACzC,IAAI,CAAC;YACH,OAAO,CAAC,CAAC,eAAe,EAAE,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC,CAAC;IACH,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;IAC9C,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AAChC,CAAC"}
|
package/dist/adapters/types.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* `upsertHook` and `upsertCloud` are optional — hosts that don't support pre-tool hooks
|
|
7
7
|
* (e.g. Claude Desktop) simply omit them rather than implement no-op stubs.
|
|
8
8
|
*/
|
|
9
|
-
export type AgentId = "cursor" | "claude-desktop" | "claude-code";
|
|
9
|
+
export type AgentId = "cursor" | "claude-desktop" | "claude-code" | "codex";
|
|
10
10
|
export type SetupResult = {
|
|
11
11
|
path: string;
|
|
12
12
|
changed: boolean;
|
|
@@ -29,16 +29,20 @@ export type AgentStatus = {
|
|
|
29
29
|
};
|
|
30
30
|
export type HookStatus = {
|
|
31
31
|
/** Hook config status at the user-global scope (`~/.cursor/hooks.json` for Cursor). */
|
|
32
|
-
global
|
|
32
|
+
global?: {
|
|
33
33
|
shell: boolean;
|
|
34
34
|
mcp: boolean;
|
|
35
35
|
path: string;
|
|
36
|
+
shellLabel?: string;
|
|
37
|
+
mcpLabel?: string;
|
|
36
38
|
};
|
|
37
39
|
/** Hook config status at the project scope, when applicable. */
|
|
38
40
|
project?: {
|
|
39
41
|
shell: boolean;
|
|
40
42
|
mcp: boolean;
|
|
41
43
|
path: string;
|
|
44
|
+
shellLabel?: string;
|
|
45
|
+
mcpLabel?: string;
|
|
42
46
|
};
|
|
43
47
|
};
|
|
44
48
|
export type HookScope = "global" | "project";
|
|
@@ -50,6 +54,7 @@ export type UpsertHookOpts = {
|
|
|
50
54
|
};
|
|
51
55
|
export type UpsertMcpOpts = {
|
|
52
56
|
explicitPath?: string;
|
|
57
|
+
projectDir?: string;
|
|
53
58
|
dryRun?: boolean;
|
|
54
59
|
};
|
|
55
60
|
export type UpsertCloudOpts = {
|
|
@@ -66,6 +71,8 @@ export interface AgentAdapter {
|
|
|
66
71
|
readonly id: AgentId;
|
|
67
72
|
/** Display name for human-readable output. */
|
|
68
73
|
readonly label: string;
|
|
74
|
+
/** Which hook scope this host primarily uses for readiness and doctor output. */
|
|
75
|
+
readonly preferredHookScope?: HookScope;
|
|
69
76
|
/**
|
|
70
77
|
* Cheap filesystem check: does this agent appear to be installed?
|
|
71
78
|
* Drives auto-detect in `setup all` and `doctor`. Must not throw.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,gBAAgB,GAAG,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,gBAAgB,GAAG,aAAa,GAAG,OAAO,CAAC;AAE5E,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,mEAAmE;IACnE,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,GAAG,CAAC,EAAE;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,yEAAyE;IACzE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,uFAAuF;IACvF,MAAM,CAAC,EAAE;QACP,KAAK,EAAE,OAAO,CAAC;QACf,GAAG,EAAE,OAAO,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,gEAAgE;IAChE,OAAO,CAAC,EAAE;QACR,KAAK,EAAE,OAAO,CAAC;QACf,GAAG,EAAE,OAAO,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE7C,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,SAAS,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IAErB,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,iFAAiF;IACjF,QAAQ,CAAC,kBAAkB,CAAC,EAAE,SAAS,CAAC;IAExC;;;OAGG;IACH,eAAe,IAAI,OAAO,CAAC;IAE3B,mEAAmE;IACnE,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAErD,gFAAgF;IAChF,UAAU,CAAC,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAExD,6EAA6E;IAC7E,WAAW,CAAC,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAE1D,kEAAkE;IAClE,MAAM,CAAC,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACjD"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ShellApprovalFingerprintPayload } from "../shell/analyze-command.js";
|
|
2
|
+
export declare const EXECUTION_TICKET_ENV = "PRAXIS_GUARD_EXECUTION_TICKET";
|
|
3
|
+
/**
|
|
4
|
+
* Verify a signed execution ticket locally and consume it once (env var or ticket files).
|
|
5
|
+
*/
|
|
6
|
+
export declare function tryConsumeExecutionTicket(argv: readonly string[], opts?: {
|
|
7
|
+
storageRoot?: string;
|
|
8
|
+
kind?: "shell" | "mcp";
|
|
9
|
+
tool_input_sha256?: string | null;
|
|
10
|
+
approval_fingerprint?: ShellApprovalFingerprintPayload | null;
|
|
11
|
+
}): Promise<boolean>;
|
|
12
|
+
//# sourceMappingURL=execution-ticket-consume.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-ticket-consume.d.ts","sourceRoot":"","sources":["../../src/bridge/execution-ticket-consume.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAInF,eAAO,MAAM,oBAAoB,kCAAkC,CAAC;AAMpE;;GAEG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,IAAI,CAAC,EAAE;IACL,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,oBAAoB,CAAC,EAAE,+BAA+B,GAAG,IAAI,CAAC;CAC/D,GACA,OAAO,CAAC,OAAO,CAAC,CAoElB"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { readdir, readFile, unlink } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getInstallId } from "../cli/install-id.js";
|
|
4
|
+
import { verifyExecutionTicket } from "../approval/grant.js";
|
|
5
|
+
import { resolveShellApprovalHash } from "../approval/argv-fingerprint.js";
|
|
6
|
+
import { guardSubpath } from "./guard-storage-root.js";
|
|
7
|
+
import { argvMatchesApproval, shellApprovalId } from "./execution-ticket-match.js";
|
|
8
|
+
export const EXECUTION_TICKET_ENV = "PRAXIS_GUARD_EXECUTION_TICKET";
|
|
9
|
+
function executionTicketDir(storageRoot) {
|
|
10
|
+
return guardSubpath("tickets", storageRoot);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Verify a signed execution ticket locally and consume it once (env var or ticket files).
|
|
14
|
+
*/
|
|
15
|
+
export async function tryConsumeExecutionTicket(argv, opts) {
|
|
16
|
+
const fromEnv = process.env[EXECUTION_TICKET_ENV]?.trim();
|
|
17
|
+
if (fromEnv && tryConsumeTicketToken(fromEnv, argv, opts)) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
const dir = executionTicketDir(opts?.storageRoot);
|
|
21
|
+
let names = [];
|
|
22
|
+
try {
|
|
23
|
+
names = await readdir(dir);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const now = Date.now();
|
|
29
|
+
const approvalId = shellApprovalId(argv, opts?.approval_fingerprint);
|
|
30
|
+
const candidates = opts?.kind === "mcp"
|
|
31
|
+
? names.filter((n) => n.endsWith(".json"))
|
|
32
|
+
: names.filter((n) => n.startsWith(`${approvalId}_`) && n.endsWith(".json"));
|
|
33
|
+
for (const name of candidates) {
|
|
34
|
+
const file = path.join(dir, name);
|
|
35
|
+
try {
|
|
36
|
+
const raw = await readFile(file, "utf8");
|
|
37
|
+
const row = JSON.parse(raw);
|
|
38
|
+
if (typeof row.exp !== "number" || row.exp < now) {
|
|
39
|
+
await unlink(file).catch(() => { });
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (!argvMatchesApproval(row.argv, argv, opts?.kind ?? row.kind, row.fingerprint, opts?.approval_fingerprint)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const ticket = typeof row.ticket === "string" ? row.ticket : "";
|
|
46
|
+
if (!ticket ||
|
|
47
|
+
!tryConsumeTicketToken(ticket, argv, {
|
|
48
|
+
kind: opts?.kind ?? row.kind,
|
|
49
|
+
tool_input_sha256: opts?.tool_input_sha256,
|
|
50
|
+
approved_argv: row.argv,
|
|
51
|
+
approval_fingerprint: opts?.approval_fingerprint,
|
|
52
|
+
approved_fingerprint: row.fingerprint,
|
|
53
|
+
})) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (row.kind && opts?.kind && row.kind !== opts.kind)
|
|
57
|
+
continue;
|
|
58
|
+
await unlink(file);
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
function tryConsumeTicketToken(ticket, argv, opts) {
|
|
68
|
+
const claims = verifyExecutionTicket(ticket);
|
|
69
|
+
const expectedHash = resolveShellApprovalHash({
|
|
70
|
+
kind: opts?.kind ?? "shell",
|
|
71
|
+
argv,
|
|
72
|
+
approval_fingerprint: opts?.approval_fingerprint,
|
|
73
|
+
});
|
|
74
|
+
if (!claims) {
|
|
75
|
+
return argvMatchesApproval(opts?.approved_argv, argv, opts?.kind, opts?.approved_fingerprint, opts?.approval_fingerprint);
|
|
76
|
+
}
|
|
77
|
+
const approvedArgv = opts?.approved_argv;
|
|
78
|
+
const approvedHash = resolveShellApprovalHash({
|
|
79
|
+
kind: opts?.kind ?? claims.kind ?? "shell",
|
|
80
|
+
argv: approvedArgv ?? argv,
|
|
81
|
+
approval_fingerprint: opts?.approved_fingerprint ?? opts?.approval_fingerprint,
|
|
82
|
+
});
|
|
83
|
+
if (approvedArgv) {
|
|
84
|
+
if (claims.argv_sha256 !== approvedHash)
|
|
85
|
+
return false;
|
|
86
|
+
if (!argvMatchesApproval(approvedArgv, argv, opts?.kind ?? claims.kind, opts?.approved_fingerprint, opts?.approval_fingerprint)) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else if (claims.argv_sha256 !== expectedHash) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
if (claims.install_id !== getInstallId())
|
|
94
|
+
return false;
|
|
95
|
+
if (opts?.kind && claims.kind !== opts.kind)
|
|
96
|
+
return false;
|
|
97
|
+
const expectedToolHash = opts?.tool_input_sha256?.trim() || null;
|
|
98
|
+
const claimToolHash = typeof claims.tool_input_sha256 === "string" ? claims.tool_input_sha256.trim() : null;
|
|
99
|
+
if (claimToolHash && expectedToolHash && claimToolHash !== expectedToolHash)
|
|
100
|
+
return false;
|
|
101
|
+
if (claimToolHash && !expectedToolHash)
|
|
102
|
+
return false;
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=execution-ticket-consume.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-ticket-consume.js","sourceRoot":"","sources":["../../src/bridge/execution-ticket-consume.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ShellApprovalFingerprintPayload } from "../shell/analyze-command.js";
|
|
2
|
+
export declare function shellApprovalId(argv: readonly string[], fingerprint?: ShellApprovalFingerprintPayload | null): string;
|
|
3
|
+
export declare function argvMatchesApproval(approved: readonly string[] | undefined, requested: readonly string[], kind?: "shell" | "mcp", approvedFingerprint?: ShellApprovalFingerprintPayload | null, requestedFingerprint?: ShellApprovalFingerprintPayload | null): boolean;
|
|
4
|
+
//# sourceMappingURL=execution-ticket-match.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-ticket-match.d.ts","sourceRoot":"","sources":["../../src/bridge/execution-ticket-match.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,6BAA6B,CAAC;AAuBnF,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,WAAW,CAAC,EAAE,+BAA+B,GAAG,IAAI,GACnD,MAAM,CAGR;AAED,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EACvC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,IAAI,CAAC,EAAE,OAAO,GAAG,KAAK,EACtB,mBAAmB,CAAC,EAAE,+BAA+B,GAAG,IAAI,EAC5D,oBAAoB,CAAC,EAAE,+BAA+B,GAAG,IAAI,GAC5D,OAAO,CAQT"}
|