@astrasyncai/verification-gateway 3.10.1 → 3.11.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.
- package/dist/adapters/express.js +1 -1
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +1 -1
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/mcp.js +1 -1
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +1 -1
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.js +1 -1
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +1 -1
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.js +1 -1
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +1 -1
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +47 -13
- package/dist/bin/astrasync-codex-hook.js +5107 -0
- package/dist/bin/astrasync-guard.js +176 -18
- package/dist/bin/astrasync.js +184 -18
- package/dist/browser/background.js +26 -3
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +26 -3
- package/dist/browser/background.mjs.map +1 -1
- package/dist/claude-code/claude-code-adapter.js +9 -1
- package/dist/claude-code/claude-code-adapter.js.map +1 -1
- package/dist/claude-code/claude-code-adapter.mjs +9 -1
- package/dist/claude-code/claude-code-adapter.mjs.map +1 -1
- package/dist/codex/index.d.mts +230 -0
- package/dist/codex/index.d.ts +230 -0
- package/dist/codex/index.js +5225 -0
- package/dist/codex/index.js.map +1 -0
- package/dist/codex/index.mjs +5197 -0
- package/dist/codex/index.mjs.map +1 -0
- package/dist/cursor/extension.js +26 -3
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +26 -3
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/gateway/gateway.d.mts +5 -0
- package/dist/gateway/gateway.d.ts +5 -0
- package/dist/gateway/gateway.js +26 -3
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +26 -3
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/local-evaluator/evaluator.js.map +1 -1
- package/dist/local-evaluator/evaluator.mjs.map +1 -1
- package/dist/verify.js +1 -1
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +1 -1
- package/dist/verify.mjs.map +1 -1
- package/package.json +8 -2
|
@@ -4598,7 +4598,7 @@ function getTrustLevel(score) {
|
|
|
4598
4598
|
}
|
|
4599
4599
|
|
|
4600
4600
|
// src/version.ts
|
|
4601
|
-
var SDK_VERSION = "3.
|
|
4601
|
+
var SDK_VERSION = "3.11.0";
|
|
4602
4602
|
|
|
4603
4603
|
// src/well-known.ts
|
|
4604
4604
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -5113,10 +5113,12 @@ function toGatewayConfig(config) {
|
|
|
5113
5113
|
};
|
|
5114
5114
|
}
|
|
5115
5115
|
function toVerificationRequest(context, astraId) {
|
|
5116
|
+
const dotIndex = context.purpose.indexOf(".");
|
|
5117
|
+
const dotted = dotIndex > 0;
|
|
5116
5118
|
return {
|
|
5117
5119
|
credentials: { astraId },
|
|
5118
|
-
purpose: context.purpose,
|
|
5119
|
-
action: context.action,
|
|
5120
|
+
purpose: dotted ? context.purpose.slice(0, dotIndex) : context.purpose,
|
|
5121
|
+
action: dotted ? context.purpose : context.action,
|
|
5120
5122
|
resourceType: context.resourceType,
|
|
5121
5123
|
resource: context.target,
|
|
5122
5124
|
transactionValue: context.transactionValue,
|
|
@@ -5368,6 +5370,20 @@ var TraceLogger = class {
|
|
|
5368
5370
|
decision: redactDeep(decision)
|
|
5369
5371
|
});
|
|
5370
5372
|
}
|
|
5373
|
+
/**
|
|
5374
|
+
* Log a tool call the guard saw but did not govern. One line per skip
|
|
5375
|
+
* keeps coverage holes (unmapped platform tools) visible in the traces
|
|
5376
|
+
* instead of silently indistinguishable from ALLOW.
|
|
5377
|
+
*/
|
|
5378
|
+
logSkipped(toolName, reason) {
|
|
5379
|
+
if (!this.enabled) return;
|
|
5380
|
+
this.write({
|
|
5381
|
+
id: this.generateId(),
|
|
5382
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
5383
|
+
type: "skipped",
|
|
5384
|
+
metadata: { toolName, reason }
|
|
5385
|
+
});
|
|
5386
|
+
}
|
|
5371
5387
|
/**
|
|
5372
5388
|
* Log a mode switch event.
|
|
5373
5389
|
*/
|
|
@@ -5565,6 +5581,13 @@ var AstraSyncGateway = class {
|
|
|
5565
5581
|
getSyncStatus() {
|
|
5566
5582
|
return this.syncQueue?.getStatus() || null;
|
|
5567
5583
|
}
|
|
5584
|
+
/**
|
|
5585
|
+
* Record a tool call the calling adapter saw but did not govern
|
|
5586
|
+
* (unmapped tool, skipTools, MCP with governMcp off). Trace-only.
|
|
5587
|
+
*/
|
|
5588
|
+
logSkippedTool(toolName, reason) {
|
|
5589
|
+
this.traceLogger?.logSkipped(toolName, reason);
|
|
5590
|
+
}
|
|
5568
5591
|
};
|
|
5569
5592
|
|
|
5570
5593
|
// src/git-trigger/git-hooks.ts
|
|
@@ -5693,11 +5716,11 @@ async function evaluateChangedFiles(gateway, files, config = {}) {
|
|
|
5693
5716
|
var import_fs5 = require("fs");
|
|
5694
5717
|
var import_path4 = require("path");
|
|
5695
5718
|
var ASTRASYNC_HOOK_MARKER = "astrasync-claude-hook";
|
|
5696
|
-
var HOOK_MATCHER = "Bash|Write|Edit|MultiEdit|NotebookEdit|Read|Glob|Grep|WebFetch|WebSearch|Task|Agent|mcp__.*";
|
|
5719
|
+
var HOOK_MATCHER = "Bash|PowerShell|Write|Edit|MultiEdit|NotebookEdit|Read|Glob|Grep|WebFetch|WebSearch|Task|Agent|mcp__.*";
|
|
5697
5720
|
var HOOK_TIMEOUT_SECONDS = 10;
|
|
5698
|
-
function isGuardEntry(entry) {
|
|
5721
|
+
function isGuardEntry(entry, marker2) {
|
|
5699
5722
|
return (entry.hooks ?? []).some(
|
|
5700
|
-
(h) => typeof h.command === "string" && h.command.includes(
|
|
5723
|
+
(h) => typeof h.command === "string" && h.command.includes(marker2)
|
|
5701
5724
|
);
|
|
5702
5725
|
}
|
|
5703
5726
|
function readSettings(settingsPath) {
|
|
@@ -5711,24 +5734,26 @@ function writeSettings(settingsPath, settings) {
|
|
|
5711
5734
|
(0, import_fs5.writeFileSync)(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
5712
5735
|
`, "utf-8");
|
|
5713
5736
|
}
|
|
5714
|
-
function buildHookEntry(hookCommand) {
|
|
5737
|
+
function buildHookEntry(hookCommand, matcher = HOOK_MATCHER, extraHookFields = {}) {
|
|
5715
5738
|
return {
|
|
5716
|
-
matcher
|
|
5717
|
-
hooks: [
|
|
5739
|
+
matcher,
|
|
5740
|
+
hooks: [
|
|
5741
|
+
{ type: "command", command: hookCommand, timeout: HOOK_TIMEOUT_SECONDS, ...extraHookFields }
|
|
5742
|
+
]
|
|
5718
5743
|
};
|
|
5719
5744
|
}
|
|
5720
|
-
function installClaudeHooks(settingsPath, hookCommand) {
|
|
5721
|
-
if (!hookCommand.includes(
|
|
5745
|
+
function installClaudeHooks(settingsPath, hookCommand, marker2 = ASTRASYNC_HOOK_MARKER, matcher = HOOK_MATCHER, extraHookFields = {}) {
|
|
5746
|
+
if (!hookCommand.includes(marker2)) {
|
|
5722
5747
|
throw new Error(
|
|
5723
|
-
`Hook command must reference ${
|
|
5748
|
+
`Hook command must reference ${marker2} (got: ${hookCommand}) \u2014 the marker is how install/uninstall identify the guard entry.`
|
|
5724
5749
|
);
|
|
5725
5750
|
}
|
|
5726
5751
|
const settings = readSettings(settingsPath);
|
|
5727
5752
|
settings.hooks = settings.hooks ?? {};
|
|
5728
5753
|
const preToolUse = settings.hooks.PreToolUse = settings.hooks.PreToolUse ?? [];
|
|
5729
|
-
const existing = preToolUse.find(isGuardEntry);
|
|
5754
|
+
const existing = preToolUse.find((entry) => isGuardEntry(entry, marker2));
|
|
5730
5755
|
if (existing) {
|
|
5731
|
-
const fresh = buildHookEntry(hookCommand);
|
|
5756
|
+
const fresh = buildHookEntry(hookCommand, matcher, extraHookFields);
|
|
5732
5757
|
const changed = JSON.stringify(existing) !== JSON.stringify(fresh);
|
|
5733
5758
|
if (changed) {
|
|
5734
5759
|
preToolUse[preToolUse.indexOf(existing)] = fresh;
|
|
@@ -5736,11 +5761,11 @@ function installClaudeHooks(settingsPath, hookCommand) {
|
|
|
5736
5761
|
}
|
|
5737
5762
|
return { installed: false, alreadyPresent: true, updated: changed };
|
|
5738
5763
|
}
|
|
5739
|
-
preToolUse.push(buildHookEntry(hookCommand));
|
|
5764
|
+
preToolUse.push(buildHookEntry(hookCommand, matcher, extraHookFields));
|
|
5740
5765
|
writeSettings(settingsPath, settings);
|
|
5741
5766
|
return { installed: true, alreadyPresent: false, updated: false };
|
|
5742
5767
|
}
|
|
5743
|
-
function uninstallClaudeHooks(settingsPath) {
|
|
5768
|
+
function uninstallClaudeHooks(settingsPath, marker2 = ASTRASYNC_HOOK_MARKER) {
|
|
5744
5769
|
if (!(0, import_fs5.existsSync)(settingsPath)) return false;
|
|
5745
5770
|
let settings;
|
|
5746
5771
|
try {
|
|
@@ -5750,7 +5775,7 @@ function uninstallClaudeHooks(settingsPath) {
|
|
|
5750
5775
|
}
|
|
5751
5776
|
const preToolUse = settings.hooks?.PreToolUse;
|
|
5752
5777
|
if (!preToolUse) return false;
|
|
5753
|
-
const remaining = preToolUse.filter((entry) => !isGuardEntry(entry));
|
|
5778
|
+
const remaining = preToolUse.filter((entry) => !isGuardEntry(entry, marker2));
|
|
5754
5779
|
if (remaining.length === preToolUse.length) return false;
|
|
5755
5780
|
if (remaining.length > 0) {
|
|
5756
5781
|
settings.hooks.PreToolUse = remaining;
|
|
@@ -5764,7 +5789,9 @@ function uninstallClaudeHooks(settingsPath) {
|
|
|
5764
5789
|
var GUARD_SELF_PROTECTION_PATTERNS = [
|
|
5765
5790
|
"**/.claude/settings.json",
|
|
5766
5791
|
"**/.claude/settings.local.json",
|
|
5767
|
-
"**/.astrasync/**"
|
|
5792
|
+
"**/.astrasync/**",
|
|
5793
|
+
"**/.codex/hooks.json",
|
|
5794
|
+
"**/.codex/config.toml"
|
|
5768
5795
|
];
|
|
5769
5796
|
function ensureGuardSelfProtection(policyPath) {
|
|
5770
5797
|
const parsed = parseFile(policyPath);
|
|
@@ -5811,6 +5838,25 @@ function buildDefaultClaudeCodePolicy(name = "claude-code-local-guard") {
|
|
|
5811
5838
|
};
|
|
5812
5839
|
}
|
|
5813
5840
|
|
|
5841
|
+
// src/codex/settings-installer.ts
|
|
5842
|
+
var ASTRASYNC_CODEX_HOOK_MARKER = "astrasync-codex-hook";
|
|
5843
|
+
var CODEX_HOOK_MATCHER = "Bash|apply_patch|Edit|Write|web_search|mcp__.*";
|
|
5844
|
+
var CODEX_STATUS_MESSAGE = "AstraSync Local Guard";
|
|
5845
|
+
function installCodexHooks(hooksPath, hookCommand) {
|
|
5846
|
+
return installClaudeHooks(
|
|
5847
|
+
hooksPath,
|
|
5848
|
+
hookCommand,
|
|
5849
|
+
ASTRASYNC_CODEX_HOOK_MARKER,
|
|
5850
|
+
CODEX_HOOK_MATCHER,
|
|
5851
|
+
{
|
|
5852
|
+
statusMessage: CODEX_STATUS_MESSAGE
|
|
5853
|
+
}
|
|
5854
|
+
);
|
|
5855
|
+
}
|
|
5856
|
+
function uninstallCodexHooks(hooksPath) {
|
|
5857
|
+
return uninstallClaudeHooks(hooksPath, ASTRASYNC_CODEX_HOOK_MARKER);
|
|
5858
|
+
}
|
|
5859
|
+
|
|
5814
5860
|
// src/cli/guard.ts
|
|
5815
5861
|
var DEFAULT_POLICY_PATH = "./local-policy.yaml";
|
|
5816
5862
|
var DEFAULT_CONFIG_DIR = ".astrasync";
|
|
@@ -5976,6 +6022,7 @@ async function cmdStatus() {
|
|
|
5976
6022
|
console.log(' Policy: not found \u2014 run "astrasync guard setup"');
|
|
5977
6023
|
}
|
|
5978
6024
|
printClaudeCodeStatus();
|
|
6025
|
+
printCodexStatus();
|
|
5979
6026
|
console.log("");
|
|
5980
6027
|
}
|
|
5981
6028
|
async function cmdCheck() {
|
|
@@ -6154,6 +6201,108 @@ async function cmdUninstallClaudeCode() {
|
|
|
6154
6201
|
`[AstraSync] Policy and traces left in place at ${astrasyncDir} \u2014 delete manually if unwanted.`
|
|
6155
6202
|
);
|
|
6156
6203
|
}
|
|
6204
|
+
function resolveCodexHookCommand() {
|
|
6205
|
+
const sibling = path.join(__dirname, "astrasync-codex-hook.js");
|
|
6206
|
+
if (fs.existsSync(sibling)) {
|
|
6207
|
+
return `"${process.execPath}" "${sibling}"`;
|
|
6208
|
+
}
|
|
6209
|
+
return "astrasync-codex-hook";
|
|
6210
|
+
}
|
|
6211
|
+
function codexPaths(project) {
|
|
6212
|
+
const root = project ? process.cwd() : os.homedir();
|
|
6213
|
+
return {
|
|
6214
|
+
hooksPath: path.join(root, ".codex", "hooks.json"),
|
|
6215
|
+
astrasyncDir: path.join(root, ".astrasync")
|
|
6216
|
+
};
|
|
6217
|
+
}
|
|
6218
|
+
async function cmdInstallCodex() {
|
|
6219
|
+
const flags = parseClaudeCodeFlags();
|
|
6220
|
+
const { hooksPath, astrasyncDir } = codexPaths(flags.project);
|
|
6221
|
+
const policyPath = flags.policyOverride || path.join(astrasyncDir, "policy.yaml");
|
|
6222
|
+
const guardJsonPath = path.join(astrasyncDir, "guard.json");
|
|
6223
|
+
console.log("\nAstraSync Local Guard for Codex CLI \u2014 install\n");
|
|
6224
|
+
if (fs.existsSync(policyPath)) {
|
|
6225
|
+
console.log(` Policy: using existing ${policyPath} (shared across adapters)`);
|
|
6226
|
+
if (ensureGuardSelfProtection(policyPath)) {
|
|
6227
|
+
console.log(" added guard self-protection patterns to file.write");
|
|
6228
|
+
}
|
|
6229
|
+
} else if (flags.wizard) {
|
|
6230
|
+
const prompt = createPrompt();
|
|
6231
|
+
try {
|
|
6232
|
+
fs.mkdirSync(path.dirname(policyPath), { recursive: true });
|
|
6233
|
+
const wizard = new SetupWizard(prompt);
|
|
6234
|
+
await wizard.runAndSave(policyPath);
|
|
6235
|
+
} finally {
|
|
6236
|
+
prompt.close();
|
|
6237
|
+
}
|
|
6238
|
+
ensureGuardSelfProtection(policyPath);
|
|
6239
|
+
console.log(` Policy: created via wizard at ${policyPath}`);
|
|
6240
|
+
} else {
|
|
6241
|
+
fs.mkdirSync(path.dirname(policyPath), { recursive: true });
|
|
6242
|
+
fs.writeFileSync(policyPath, toYaml(buildDefaultClaudeCodePolicy()), "utf-8");
|
|
6243
|
+
console.log(` Policy: default coding-agent policy written to ${policyPath}`);
|
|
6244
|
+
console.log(" (re-run with --wizard for the interactive setup instead)");
|
|
6245
|
+
}
|
|
6246
|
+
if (!fs.existsSync(guardJsonPath)) {
|
|
6247
|
+
const guardSettings = {
|
|
6248
|
+
posture: flags.active ? "active" : "passive",
|
|
6249
|
+
governMcp: false
|
|
6250
|
+
};
|
|
6251
|
+
fs.writeFileSync(guardJsonPath, `${JSON.stringify(guardSettings, null, 2)}
|
|
6252
|
+
`, "utf-8");
|
|
6253
|
+
console.log(
|
|
6254
|
+
` Guard: ${guardJsonPath} (posture: ${guardSettings.posture}, governMcp: false)`
|
|
6255
|
+
);
|
|
6256
|
+
} else {
|
|
6257
|
+
console.log(` Guard: using existing ${guardJsonPath}`);
|
|
6258
|
+
}
|
|
6259
|
+
const hookCommand = resolveCodexHookCommand();
|
|
6260
|
+
const result = installCodexHooks(hooksPath, hookCommand);
|
|
6261
|
+
if (result.installed) {
|
|
6262
|
+
console.log(` Hook: installed in ${hooksPath}`);
|
|
6263
|
+
} else if (result.updated) {
|
|
6264
|
+
console.log(` Hook: updated in ${hooksPath}`);
|
|
6265
|
+
} else {
|
|
6266
|
+
console.log(` Hook: already present in ${hooksPath}`);
|
|
6267
|
+
}
|
|
6268
|
+
console.log("\n Next steps:");
|
|
6269
|
+
console.log(" 1. Start a NEW Codex session (hooks load at startup; /hooks to inspect).");
|
|
6270
|
+
console.log(` 2. Watch decisions: tail -f ${path.join(astrasyncDir, "traces")}/*.jsonl`);
|
|
6271
|
+
console.log(` 3. When the traces look right, set "posture": "active" in ${guardJsonPath}.`);
|
|
6272
|
+
console.log(" Denies block; approvals fall through to Codex's own prompt \u2014");
|
|
6273
|
+
console.log(" except in dontAsk/bypassPermissions modes, where they deny.");
|
|
6274
|
+
console.log(" 4. Note: Codex fails OPEN if the hook itself times out; the guard");
|
|
6275
|
+
console.log(" fails closed on every failure it can see.\n");
|
|
6276
|
+
}
|
|
6277
|
+
async function cmdUninstallCodex() {
|
|
6278
|
+
const flags = parseClaudeCodeFlags();
|
|
6279
|
+
const { hooksPath, astrasyncDir } = codexPaths(flags.project);
|
|
6280
|
+
const removed = uninstallCodexHooks(hooksPath);
|
|
6281
|
+
if (removed) {
|
|
6282
|
+
console.log(`[AstraSync] Removed Codex hook from ${hooksPath}`);
|
|
6283
|
+
} else {
|
|
6284
|
+
console.log(`[AstraSync] No AstraSync hook found in ${hooksPath}`);
|
|
6285
|
+
}
|
|
6286
|
+
console.log(
|
|
6287
|
+
`[AstraSync] Policy and traces left in place at ${astrasyncDir} \u2014 delete manually if unwanted.`
|
|
6288
|
+
);
|
|
6289
|
+
}
|
|
6290
|
+
function printCodexStatus() {
|
|
6291
|
+
for (const scope of ["user", "project"]) {
|
|
6292
|
+
const { hooksPath, astrasyncDir } = codexPaths(scope === "project");
|
|
6293
|
+
let hookInstalled = false;
|
|
6294
|
+
try {
|
|
6295
|
+
const content = fs.readFileSync(hooksPath, "utf-8");
|
|
6296
|
+
hookInstalled = content.includes(ASTRASYNC_CODEX_HOOK_MARKER);
|
|
6297
|
+
} catch {
|
|
6298
|
+
}
|
|
6299
|
+
if (hookInstalled) {
|
|
6300
|
+
const policyPath = path.join(astrasyncDir, "policy.yaml");
|
|
6301
|
+
const policy = fs.existsSync(policyPath) ? `policy: ${policyPath}` : "policy: missing";
|
|
6302
|
+
console.log(` Codex CLI (${scope}): hook installed, ${policy}`);
|
|
6303
|
+
}
|
|
6304
|
+
}
|
|
6305
|
+
}
|
|
6157
6306
|
function printClaudeCodeStatus() {
|
|
6158
6307
|
for (const scope of ["user", "project"]) {
|
|
6159
6308
|
const { settingsPath, astrasyncDir } = claudeCodePaths(scope === "project");
|
|
@@ -6211,6 +6360,12 @@ async function main() {
|
|
|
6211
6360
|
case "uninstall-claude-code":
|
|
6212
6361
|
await cmdUninstallClaudeCode();
|
|
6213
6362
|
break;
|
|
6363
|
+
case "install-codex":
|
|
6364
|
+
await cmdInstallCodex();
|
|
6365
|
+
break;
|
|
6366
|
+
case "uninstall-codex":
|
|
6367
|
+
await cmdUninstallCodex();
|
|
6368
|
+
break;
|
|
6214
6369
|
default:
|
|
6215
6370
|
console.log("AstraSync Local Guard\n");
|
|
6216
6371
|
console.log("Usage: astrasync guard <command>\n");
|
|
@@ -6228,6 +6383,9 @@ async function main() {
|
|
|
6228
6383
|
console.log(
|
|
6229
6384
|
" uninstall-claude-code Remove the Claude Code hook (--project for project scope)"
|
|
6230
6385
|
);
|
|
6386
|
+
console.log(" install-codex Install the Local Guard hook for OpenAI Codex CLI");
|
|
6387
|
+
console.log(" (same flags; policy shared with Claude Code)");
|
|
6388
|
+
console.log(" uninstall-codex Remove the Codex hook (--project for project scope)");
|
|
6231
6389
|
console.log("");
|
|
6232
6390
|
process.exit(command ? 1 : 0);
|
|
6233
6391
|
}
|
package/dist/bin/astrasync.js
CHANGED
|
@@ -4989,7 +4989,7 @@ var SDK_VERSION;
|
|
|
4989
4989
|
var init_version = __esm({
|
|
4990
4990
|
"src/version.ts"() {
|
|
4991
4991
|
"use strict";
|
|
4992
|
-
SDK_VERSION = "3.
|
|
4992
|
+
SDK_VERSION = "3.11.0";
|
|
4993
4993
|
}
|
|
4994
4994
|
});
|
|
4995
4995
|
|
|
@@ -5959,10 +5959,12 @@ function toGatewayConfig(config) {
|
|
|
5959
5959
|
};
|
|
5960
5960
|
}
|
|
5961
5961
|
function toVerificationRequest(context, astraId) {
|
|
5962
|
+
const dotIndex = context.purpose.indexOf(".");
|
|
5963
|
+
const dotted = dotIndex > 0;
|
|
5962
5964
|
return {
|
|
5963
5965
|
credentials: { astraId },
|
|
5964
|
-
purpose: context.purpose,
|
|
5965
|
-
action: context.action,
|
|
5966
|
+
purpose: dotted ? context.purpose.slice(0, dotIndex) : context.purpose,
|
|
5967
|
+
action: dotted ? context.purpose : context.action,
|
|
5966
5968
|
resourceType: context.resourceType,
|
|
5967
5969
|
resource: context.target,
|
|
5968
5970
|
transactionValue: context.transactionValue,
|
|
@@ -6237,6 +6239,20 @@ var init_trace_logger = __esm({
|
|
|
6237
6239
|
decision: redactDeep(decision)
|
|
6238
6240
|
});
|
|
6239
6241
|
}
|
|
6242
|
+
/**
|
|
6243
|
+
* Log a tool call the guard saw but did not govern. One line per skip
|
|
6244
|
+
* keeps coverage holes (unmapped platform tools) visible in the traces
|
|
6245
|
+
* instead of silently indistinguishable from ALLOW.
|
|
6246
|
+
*/
|
|
6247
|
+
logSkipped(toolName, reason) {
|
|
6248
|
+
if (!this.enabled) return;
|
|
6249
|
+
this.write({
|
|
6250
|
+
id: this.generateId(),
|
|
6251
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
6252
|
+
type: "skipped",
|
|
6253
|
+
metadata: { toolName, reason }
|
|
6254
|
+
});
|
|
6255
|
+
}
|
|
6240
6256
|
/**
|
|
6241
6257
|
* Log a mode switch event.
|
|
6242
6258
|
*/
|
|
@@ -6445,6 +6461,13 @@ var init_gateway = __esm({
|
|
|
6445
6461
|
getSyncStatus() {
|
|
6446
6462
|
return this.syncQueue?.getStatus() || null;
|
|
6447
6463
|
}
|
|
6464
|
+
/**
|
|
6465
|
+
* Record a tool call the calling adapter saw but did not govern
|
|
6466
|
+
* (unmapped tool, skipTools, MCP with governMcp off). Trace-only.
|
|
6467
|
+
*/
|
|
6468
|
+
logSkippedTool(toolName, reason) {
|
|
6469
|
+
this.traceLogger?.logSkipped(toolName, reason);
|
|
6470
|
+
}
|
|
6448
6471
|
};
|
|
6449
6472
|
}
|
|
6450
6473
|
});
|
|
@@ -6579,9 +6602,9 @@ var init_git_hooks = __esm({
|
|
|
6579
6602
|
});
|
|
6580
6603
|
|
|
6581
6604
|
// src/claude-code/settings-installer.ts
|
|
6582
|
-
function isGuardEntry(entry) {
|
|
6605
|
+
function isGuardEntry(entry, marker2) {
|
|
6583
6606
|
return (entry.hooks ?? []).some(
|
|
6584
|
-
(h) => typeof h.command === "string" && h.command.includes(
|
|
6607
|
+
(h) => typeof h.command === "string" && h.command.includes(marker2)
|
|
6585
6608
|
);
|
|
6586
6609
|
}
|
|
6587
6610
|
function readSettings(settingsPath) {
|
|
@@ -6595,24 +6618,26 @@ function writeSettings(settingsPath, settings) {
|
|
|
6595
6618
|
(0, import_fs5.writeFileSync)(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
6596
6619
|
`, "utf-8");
|
|
6597
6620
|
}
|
|
6598
|
-
function buildHookEntry(hookCommand) {
|
|
6621
|
+
function buildHookEntry(hookCommand, matcher = HOOK_MATCHER, extraHookFields = {}) {
|
|
6599
6622
|
return {
|
|
6600
|
-
matcher
|
|
6601
|
-
hooks: [
|
|
6623
|
+
matcher,
|
|
6624
|
+
hooks: [
|
|
6625
|
+
{ type: "command", command: hookCommand, timeout: HOOK_TIMEOUT_SECONDS, ...extraHookFields }
|
|
6626
|
+
]
|
|
6602
6627
|
};
|
|
6603
6628
|
}
|
|
6604
|
-
function installClaudeHooks(settingsPath, hookCommand) {
|
|
6605
|
-
if (!hookCommand.includes(
|
|
6629
|
+
function installClaudeHooks(settingsPath, hookCommand, marker2 = ASTRASYNC_HOOK_MARKER, matcher = HOOK_MATCHER, extraHookFields = {}) {
|
|
6630
|
+
if (!hookCommand.includes(marker2)) {
|
|
6606
6631
|
throw new Error(
|
|
6607
|
-
`Hook command must reference ${
|
|
6632
|
+
`Hook command must reference ${marker2} (got: ${hookCommand}) \u2014 the marker is how install/uninstall identify the guard entry.`
|
|
6608
6633
|
);
|
|
6609
6634
|
}
|
|
6610
6635
|
const settings = readSettings(settingsPath);
|
|
6611
6636
|
settings.hooks = settings.hooks ?? {};
|
|
6612
6637
|
const preToolUse = settings.hooks.PreToolUse = settings.hooks.PreToolUse ?? [];
|
|
6613
|
-
const existing = preToolUse.find(isGuardEntry);
|
|
6638
|
+
const existing = preToolUse.find((entry) => isGuardEntry(entry, marker2));
|
|
6614
6639
|
if (existing) {
|
|
6615
|
-
const fresh = buildHookEntry(hookCommand);
|
|
6640
|
+
const fresh = buildHookEntry(hookCommand, matcher, extraHookFields);
|
|
6616
6641
|
const changed = JSON.stringify(existing) !== JSON.stringify(fresh);
|
|
6617
6642
|
if (changed) {
|
|
6618
6643
|
preToolUse[preToolUse.indexOf(existing)] = fresh;
|
|
@@ -6620,11 +6645,11 @@ function installClaudeHooks(settingsPath, hookCommand) {
|
|
|
6620
6645
|
}
|
|
6621
6646
|
return { installed: false, alreadyPresent: true, updated: changed };
|
|
6622
6647
|
}
|
|
6623
|
-
preToolUse.push(buildHookEntry(hookCommand));
|
|
6648
|
+
preToolUse.push(buildHookEntry(hookCommand, matcher, extraHookFields));
|
|
6624
6649
|
writeSettings(settingsPath, settings);
|
|
6625
6650
|
return { installed: true, alreadyPresent: false, updated: false };
|
|
6626
6651
|
}
|
|
6627
|
-
function uninstallClaudeHooks(settingsPath) {
|
|
6652
|
+
function uninstallClaudeHooks(settingsPath, marker2 = ASTRASYNC_HOOK_MARKER) {
|
|
6628
6653
|
if (!(0, import_fs5.existsSync)(settingsPath)) return false;
|
|
6629
6654
|
let settings;
|
|
6630
6655
|
try {
|
|
@@ -6634,7 +6659,7 @@ function uninstallClaudeHooks(settingsPath) {
|
|
|
6634
6659
|
}
|
|
6635
6660
|
const preToolUse = settings.hooks?.PreToolUse;
|
|
6636
6661
|
if (!preToolUse) return false;
|
|
6637
|
-
const remaining = preToolUse.filter((entry) => !isGuardEntry(entry));
|
|
6662
|
+
const remaining = preToolUse.filter((entry) => !isGuardEntry(entry, marker2));
|
|
6638
6663
|
if (remaining.length === preToolUse.length) return false;
|
|
6639
6664
|
if (remaining.length > 0) {
|
|
6640
6665
|
settings.hooks.PreToolUse = remaining;
|
|
@@ -6698,16 +6723,44 @@ var init_settings_installer = __esm({
|
|
|
6698
6723
|
init_wizard();
|
|
6699
6724
|
init_pdlss_parser();
|
|
6700
6725
|
ASTRASYNC_HOOK_MARKER = "astrasync-claude-hook";
|
|
6701
|
-
HOOK_MATCHER = "Bash|Write|Edit|MultiEdit|NotebookEdit|Read|Glob|Grep|WebFetch|WebSearch|Task|Agent|mcp__.*";
|
|
6726
|
+
HOOK_MATCHER = "Bash|PowerShell|Write|Edit|MultiEdit|NotebookEdit|Read|Glob|Grep|WebFetch|WebSearch|Task|Agent|mcp__.*";
|
|
6702
6727
|
HOOK_TIMEOUT_SECONDS = 10;
|
|
6703
6728
|
GUARD_SELF_PROTECTION_PATTERNS = [
|
|
6704
6729
|
"**/.claude/settings.json",
|
|
6705
6730
|
"**/.claude/settings.local.json",
|
|
6706
|
-
"**/.astrasync/**"
|
|
6731
|
+
"**/.astrasync/**",
|
|
6732
|
+
"**/.codex/hooks.json",
|
|
6733
|
+
"**/.codex/config.toml"
|
|
6707
6734
|
];
|
|
6708
6735
|
}
|
|
6709
6736
|
});
|
|
6710
6737
|
|
|
6738
|
+
// src/codex/settings-installer.ts
|
|
6739
|
+
function installCodexHooks(hooksPath, hookCommand) {
|
|
6740
|
+
return installClaudeHooks(
|
|
6741
|
+
hooksPath,
|
|
6742
|
+
hookCommand,
|
|
6743
|
+
ASTRASYNC_CODEX_HOOK_MARKER,
|
|
6744
|
+
CODEX_HOOK_MATCHER,
|
|
6745
|
+
{
|
|
6746
|
+
statusMessage: CODEX_STATUS_MESSAGE
|
|
6747
|
+
}
|
|
6748
|
+
);
|
|
6749
|
+
}
|
|
6750
|
+
function uninstallCodexHooks(hooksPath) {
|
|
6751
|
+
return uninstallClaudeHooks(hooksPath, ASTRASYNC_CODEX_HOOK_MARKER);
|
|
6752
|
+
}
|
|
6753
|
+
var ASTRASYNC_CODEX_HOOK_MARKER, CODEX_HOOK_MATCHER, CODEX_STATUS_MESSAGE;
|
|
6754
|
+
var init_settings_installer2 = __esm({
|
|
6755
|
+
"src/codex/settings-installer.ts"() {
|
|
6756
|
+
"use strict";
|
|
6757
|
+
init_settings_installer();
|
|
6758
|
+
ASTRASYNC_CODEX_HOOK_MARKER = "astrasync-codex-hook";
|
|
6759
|
+
CODEX_HOOK_MATCHER = "Bash|apply_patch|Edit|Write|web_search|mcp__.*";
|
|
6760
|
+
CODEX_STATUS_MESSAGE = "AstraSync Local Guard";
|
|
6761
|
+
}
|
|
6762
|
+
});
|
|
6763
|
+
|
|
6711
6764
|
// src/cli/guard.ts
|
|
6712
6765
|
var guard_exports = {};
|
|
6713
6766
|
function createPrompt() {
|
|
@@ -6872,6 +6925,7 @@ async function cmdStatus() {
|
|
|
6872
6925
|
console.log(' Policy: not found \u2014 run "astrasync guard setup"');
|
|
6873
6926
|
}
|
|
6874
6927
|
printClaudeCodeStatus();
|
|
6928
|
+
printCodexStatus();
|
|
6875
6929
|
console.log("");
|
|
6876
6930
|
}
|
|
6877
6931
|
async function cmdCheck() {
|
|
@@ -7050,6 +7104,108 @@ async function cmdUninstallClaudeCode() {
|
|
|
7050
7104
|
`[AstraSync] Policy and traces left in place at ${astrasyncDir} \u2014 delete manually if unwanted.`
|
|
7051
7105
|
);
|
|
7052
7106
|
}
|
|
7107
|
+
function resolveCodexHookCommand() {
|
|
7108
|
+
const sibling = path.join(__dirname, "astrasync-codex-hook.js");
|
|
7109
|
+
if (fs.existsSync(sibling)) {
|
|
7110
|
+
return `"${process.execPath}" "${sibling}"`;
|
|
7111
|
+
}
|
|
7112
|
+
return "astrasync-codex-hook";
|
|
7113
|
+
}
|
|
7114
|
+
function codexPaths(project) {
|
|
7115
|
+
const root = project ? process.cwd() : os.homedir();
|
|
7116
|
+
return {
|
|
7117
|
+
hooksPath: path.join(root, ".codex", "hooks.json"),
|
|
7118
|
+
astrasyncDir: path.join(root, ".astrasync")
|
|
7119
|
+
};
|
|
7120
|
+
}
|
|
7121
|
+
async function cmdInstallCodex() {
|
|
7122
|
+
const flags = parseClaudeCodeFlags();
|
|
7123
|
+
const { hooksPath, astrasyncDir } = codexPaths(flags.project);
|
|
7124
|
+
const policyPath = flags.policyOverride || path.join(astrasyncDir, "policy.yaml");
|
|
7125
|
+
const guardJsonPath = path.join(astrasyncDir, "guard.json");
|
|
7126
|
+
console.log("\nAstraSync Local Guard for Codex CLI \u2014 install\n");
|
|
7127
|
+
if (fs.existsSync(policyPath)) {
|
|
7128
|
+
console.log(` Policy: using existing ${policyPath} (shared across adapters)`);
|
|
7129
|
+
if (ensureGuardSelfProtection(policyPath)) {
|
|
7130
|
+
console.log(" added guard self-protection patterns to file.write");
|
|
7131
|
+
}
|
|
7132
|
+
} else if (flags.wizard) {
|
|
7133
|
+
const prompt = createPrompt();
|
|
7134
|
+
try {
|
|
7135
|
+
fs.mkdirSync(path.dirname(policyPath), { recursive: true });
|
|
7136
|
+
const wizard = new SetupWizard(prompt);
|
|
7137
|
+
await wizard.runAndSave(policyPath);
|
|
7138
|
+
} finally {
|
|
7139
|
+
prompt.close();
|
|
7140
|
+
}
|
|
7141
|
+
ensureGuardSelfProtection(policyPath);
|
|
7142
|
+
console.log(` Policy: created via wizard at ${policyPath}`);
|
|
7143
|
+
} else {
|
|
7144
|
+
fs.mkdirSync(path.dirname(policyPath), { recursive: true });
|
|
7145
|
+
fs.writeFileSync(policyPath, toYaml(buildDefaultClaudeCodePolicy()), "utf-8");
|
|
7146
|
+
console.log(` Policy: default coding-agent policy written to ${policyPath}`);
|
|
7147
|
+
console.log(" (re-run with --wizard for the interactive setup instead)");
|
|
7148
|
+
}
|
|
7149
|
+
if (!fs.existsSync(guardJsonPath)) {
|
|
7150
|
+
const guardSettings = {
|
|
7151
|
+
posture: flags.active ? "active" : "passive",
|
|
7152
|
+
governMcp: false
|
|
7153
|
+
};
|
|
7154
|
+
fs.writeFileSync(guardJsonPath, `${JSON.stringify(guardSettings, null, 2)}
|
|
7155
|
+
`, "utf-8");
|
|
7156
|
+
console.log(
|
|
7157
|
+
` Guard: ${guardJsonPath} (posture: ${guardSettings.posture}, governMcp: false)`
|
|
7158
|
+
);
|
|
7159
|
+
} else {
|
|
7160
|
+
console.log(` Guard: using existing ${guardJsonPath}`);
|
|
7161
|
+
}
|
|
7162
|
+
const hookCommand = resolveCodexHookCommand();
|
|
7163
|
+
const result = installCodexHooks(hooksPath, hookCommand);
|
|
7164
|
+
if (result.installed) {
|
|
7165
|
+
console.log(` Hook: installed in ${hooksPath}`);
|
|
7166
|
+
} else if (result.updated) {
|
|
7167
|
+
console.log(` Hook: updated in ${hooksPath}`);
|
|
7168
|
+
} else {
|
|
7169
|
+
console.log(` Hook: already present in ${hooksPath}`);
|
|
7170
|
+
}
|
|
7171
|
+
console.log("\n Next steps:");
|
|
7172
|
+
console.log(" 1. Start a NEW Codex session (hooks load at startup; /hooks to inspect).");
|
|
7173
|
+
console.log(` 2. Watch decisions: tail -f ${path.join(astrasyncDir, "traces")}/*.jsonl`);
|
|
7174
|
+
console.log(` 3. When the traces look right, set "posture": "active" in ${guardJsonPath}.`);
|
|
7175
|
+
console.log(" Denies block; approvals fall through to Codex's own prompt \u2014");
|
|
7176
|
+
console.log(" except in dontAsk/bypassPermissions modes, where they deny.");
|
|
7177
|
+
console.log(" 4. Note: Codex fails OPEN if the hook itself times out; the guard");
|
|
7178
|
+
console.log(" fails closed on every failure it can see.\n");
|
|
7179
|
+
}
|
|
7180
|
+
async function cmdUninstallCodex() {
|
|
7181
|
+
const flags = parseClaudeCodeFlags();
|
|
7182
|
+
const { hooksPath, astrasyncDir } = codexPaths(flags.project);
|
|
7183
|
+
const removed = uninstallCodexHooks(hooksPath);
|
|
7184
|
+
if (removed) {
|
|
7185
|
+
console.log(`[AstraSync] Removed Codex hook from ${hooksPath}`);
|
|
7186
|
+
} else {
|
|
7187
|
+
console.log(`[AstraSync] No AstraSync hook found in ${hooksPath}`);
|
|
7188
|
+
}
|
|
7189
|
+
console.log(
|
|
7190
|
+
`[AstraSync] Policy and traces left in place at ${astrasyncDir} \u2014 delete manually if unwanted.`
|
|
7191
|
+
);
|
|
7192
|
+
}
|
|
7193
|
+
function printCodexStatus() {
|
|
7194
|
+
for (const scope of ["user", "project"]) {
|
|
7195
|
+
const { hooksPath, astrasyncDir } = codexPaths(scope === "project");
|
|
7196
|
+
let hookInstalled = false;
|
|
7197
|
+
try {
|
|
7198
|
+
const content = fs.readFileSync(hooksPath, "utf-8");
|
|
7199
|
+
hookInstalled = content.includes(ASTRASYNC_CODEX_HOOK_MARKER);
|
|
7200
|
+
} catch {
|
|
7201
|
+
}
|
|
7202
|
+
if (hookInstalled) {
|
|
7203
|
+
const policyPath = path.join(astrasyncDir, "policy.yaml");
|
|
7204
|
+
const policy = fs.existsSync(policyPath) ? `policy: ${policyPath}` : "policy: missing";
|
|
7205
|
+
console.log(` Codex CLI (${scope}): hook installed, ${policy}`);
|
|
7206
|
+
}
|
|
7207
|
+
}
|
|
7208
|
+
}
|
|
7053
7209
|
function printClaudeCodeStatus() {
|
|
7054
7210
|
for (const scope of ["user", "project"]) {
|
|
7055
7211
|
const { settingsPath, astrasyncDir } = claudeCodePaths(scope === "project");
|
|
@@ -7107,6 +7263,12 @@ async function main() {
|
|
|
7107
7263
|
case "uninstall-claude-code":
|
|
7108
7264
|
await cmdUninstallClaudeCode();
|
|
7109
7265
|
break;
|
|
7266
|
+
case "install-codex":
|
|
7267
|
+
await cmdInstallCodex();
|
|
7268
|
+
break;
|
|
7269
|
+
case "uninstall-codex":
|
|
7270
|
+
await cmdUninstallCodex();
|
|
7271
|
+
break;
|
|
7110
7272
|
default:
|
|
7111
7273
|
console.log("AstraSync Local Guard\n");
|
|
7112
7274
|
console.log("Usage: astrasync guard <command>\n");
|
|
@@ -7124,6 +7286,9 @@ async function main() {
|
|
|
7124
7286
|
console.log(
|
|
7125
7287
|
" uninstall-claude-code Remove the Claude Code hook (--project for project scope)"
|
|
7126
7288
|
);
|
|
7289
|
+
console.log(" install-codex Install the Local Guard hook for OpenAI Codex CLI");
|
|
7290
|
+
console.log(" (same flags; policy shared with Claude Code)");
|
|
7291
|
+
console.log(" uninstall-codex Remove the Codex hook (--project for project scope)");
|
|
7127
7292
|
console.log("");
|
|
7128
7293
|
process.exit(command ? 1 : 0);
|
|
7129
7294
|
}
|
|
@@ -7143,6 +7308,7 @@ var init_guard = __esm({
|
|
|
7143
7308
|
init_pdlss_parser();
|
|
7144
7309
|
init_git_hooks();
|
|
7145
7310
|
init_settings_installer();
|
|
7311
|
+
init_settings_installer2();
|
|
7146
7312
|
DEFAULT_POLICY_PATH = "./local-policy.yaml";
|
|
7147
7313
|
DEFAULT_CONFIG_DIR = ".astrasync";
|
|
7148
7314
|
main().catch((err) => {
|
|
@@ -3927,7 +3927,7 @@ function getTrustLevel(score) {
|
|
|
3927
3927
|
}
|
|
3928
3928
|
|
|
3929
3929
|
// src/version.ts
|
|
3930
|
-
var SDK_VERSION = "3.
|
|
3930
|
+
var SDK_VERSION = "3.11.0";
|
|
3931
3931
|
|
|
3932
3932
|
// src/well-known.ts
|
|
3933
3933
|
var CACHE_TTL_MS = 60 * 60 * 1e3;
|
|
@@ -4442,10 +4442,12 @@ function toGatewayConfig(config) {
|
|
|
4442
4442
|
};
|
|
4443
4443
|
}
|
|
4444
4444
|
function toVerificationRequest(context, astraId) {
|
|
4445
|
+
const dotIndex = context.purpose.indexOf(".");
|
|
4446
|
+
const dotted = dotIndex > 0;
|
|
4445
4447
|
return {
|
|
4446
4448
|
credentials: { astraId },
|
|
4447
|
-
purpose: context.purpose,
|
|
4448
|
-
action: context.action,
|
|
4449
|
+
purpose: dotted ? context.purpose.slice(0, dotIndex) : context.purpose,
|
|
4450
|
+
action: dotted ? context.purpose : context.action,
|
|
4449
4451
|
resourceType: context.resourceType,
|
|
4450
4452
|
resource: context.target,
|
|
4451
4453
|
transactionValue: context.transactionValue,
|
|
@@ -4697,6 +4699,20 @@ var TraceLogger = class {
|
|
|
4697
4699
|
decision: redactDeep(decision)
|
|
4698
4700
|
});
|
|
4699
4701
|
}
|
|
4702
|
+
/**
|
|
4703
|
+
* Log a tool call the guard saw but did not govern. One line per skip
|
|
4704
|
+
* keeps coverage holes (unmapped platform tools) visible in the traces
|
|
4705
|
+
* instead of silently indistinguishable from ALLOW.
|
|
4706
|
+
*/
|
|
4707
|
+
logSkipped(toolName, reason) {
|
|
4708
|
+
if (!this.enabled) return;
|
|
4709
|
+
this.write({
|
|
4710
|
+
id: this.generateId(),
|
|
4711
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
4712
|
+
type: "skipped",
|
|
4713
|
+
metadata: { toolName, reason }
|
|
4714
|
+
});
|
|
4715
|
+
}
|
|
4700
4716
|
/**
|
|
4701
4717
|
* Log a mode switch event.
|
|
4702
4718
|
*/
|
|
@@ -4894,6 +4910,13 @@ var AstraSyncGateway = class {
|
|
|
4894
4910
|
getSyncStatus() {
|
|
4895
4911
|
return this.syncQueue?.getStatus() || null;
|
|
4896
4912
|
}
|
|
4913
|
+
/**
|
|
4914
|
+
* Record a tool call the calling adapter saw but did not govern
|
|
4915
|
+
* (unmapped tool, skipTools, MCP with governMcp off). Trace-only.
|
|
4916
|
+
*/
|
|
4917
|
+
logSkippedTool(toolName, reason) {
|
|
4918
|
+
this.traceLogger?.logSkipped(toolName, reason);
|
|
4919
|
+
}
|
|
4897
4920
|
};
|
|
4898
4921
|
|
|
4899
4922
|
// src/browser/background.ts
|