@astrasyncai/verification-gateway 5.18.0 → 5.18.1
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/CHANGELOG.md +29 -0
- 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/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +1 -1
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +1 -1
- package/dist/bin/astrasync-codex-hook.js +1 -1
- package/dist/bin/astrasync-guard.js +330 -112
- package/dist/bin/astrasync.js +341 -113
- package/dist/browser/background.js +1 -1
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +1 -1
- package/dist/browser/background.mjs.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/cli/index.mjs.map +1 -1
- package/dist/codex/index.js +1 -1
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +1 -1
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +1 -1
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +1 -1
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.js +1 -1
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs +1 -1
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.js +1 -1
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +1 -1
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.js +1 -1
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +1 -1
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- 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/registration/index.d.mts +1 -1
- package/dist/registration/index.d.ts +1 -1
- package/dist/registration/index.js +1 -1
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +1 -1
- package/dist/registration/index.mjs.map +1 -1
- package/dist/transport/index.js +1 -1
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +1 -1
- package/dist/transport/index.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 +1 -1
|
@@ -24,9 +24,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/cli/guard.ts
|
|
27
|
-
var
|
|
28
|
-
var
|
|
29
|
-
var
|
|
27
|
+
var fs2 = __toESM(require("fs"));
|
|
28
|
+
var os2 = __toESM(require("os"));
|
|
29
|
+
var path2 = __toESM(require("path"));
|
|
30
30
|
var readline = __toESM(require("readline"));
|
|
31
31
|
|
|
32
32
|
// ../../node_modules/js-yaml/dist/js-yaml.mjs
|
|
@@ -3129,115 +3129,115 @@ function validatePolicy(policy) {
|
|
|
3129
3129
|
}
|
|
3130
3130
|
return { valid: errors.length === 0, errors };
|
|
3131
3131
|
}
|
|
3132
|
-
function validatePurpose(purpose,
|
|
3132
|
+
function validatePurpose(purpose, path3) {
|
|
3133
3133
|
const errors = [];
|
|
3134
3134
|
if (!purpose || typeof purpose !== "object") {
|
|
3135
|
-
return [{ path:
|
|
3135
|
+
return [{ path: path3, message: "purpose must be an object" }];
|
|
3136
3136
|
}
|
|
3137
3137
|
const p = purpose;
|
|
3138
3138
|
if (typeof p.id !== "string" || !p.id) {
|
|
3139
|
-
errors.push({ path: `${
|
|
3139
|
+
errors.push({ path: `${path3}.id`, message: "id is required and must be a non-empty string" });
|
|
3140
3140
|
}
|
|
3141
3141
|
if (typeof p.allowed !== "boolean") {
|
|
3142
|
-
errors.push({ path: `${
|
|
3142
|
+
errors.push({ path: `${path3}.allowed`, message: "allowed is required and must be a boolean" });
|
|
3143
3143
|
}
|
|
3144
3144
|
if (p.targets !== void 0 && !isStringArray(p.targets)) {
|
|
3145
|
-
errors.push({ path: `${
|
|
3145
|
+
errors.push({ path: `${path3}.targets`, message: "targets must be an array of strings" });
|
|
3146
3146
|
}
|
|
3147
3147
|
if (p.blockedPatterns !== void 0 && !isStringArray(p.blockedPatterns)) {
|
|
3148
3148
|
errors.push({
|
|
3149
|
-
path: `${
|
|
3149
|
+
path: `${path3}.blockedPatterns`,
|
|
3150
3150
|
message: "blockedPatterns must be an array of strings"
|
|
3151
3151
|
});
|
|
3152
3152
|
}
|
|
3153
3153
|
if (p.requiresApproval !== void 0 && typeof p.requiresApproval !== "boolean") {
|
|
3154
3154
|
errors.push({
|
|
3155
|
-
path: `${
|
|
3155
|
+
path: `${path3}.requiresApproval`,
|
|
3156
3156
|
message: "requiresApproval must be a boolean"
|
|
3157
3157
|
});
|
|
3158
3158
|
}
|
|
3159
3159
|
return errors;
|
|
3160
3160
|
}
|
|
3161
|
-
function validateScope(scope,
|
|
3161
|
+
function validateScope(scope, path3) {
|
|
3162
3162
|
const errors = [];
|
|
3163
3163
|
if (typeof scope !== "object" || scope === null) {
|
|
3164
|
-
return [{ path:
|
|
3164
|
+
return [{ path: path3, message: "scope must be an object" }];
|
|
3165
3165
|
}
|
|
3166
3166
|
const s = scope;
|
|
3167
3167
|
for (const field of ["allowedDomains", "blockedDomains", "blockedResources"]) {
|
|
3168
3168
|
if (s[field] !== void 0 && !isStringArray(s[field])) {
|
|
3169
|
-
errors.push({ path: `${
|
|
3169
|
+
errors.push({ path: `${path3}.${field}`, message: `${field} must be an array of strings` });
|
|
3170
3170
|
}
|
|
3171
3171
|
}
|
|
3172
3172
|
return errors;
|
|
3173
3173
|
}
|
|
3174
|
-
function validateLimits(limits,
|
|
3174
|
+
function validateLimits(limits, path3) {
|
|
3175
3175
|
const errors = [];
|
|
3176
3176
|
if (typeof limits !== "object" || limits === null) {
|
|
3177
|
-
return [{ path:
|
|
3177
|
+
return [{ path: path3, message: "limits must be an object" }];
|
|
3178
3178
|
}
|
|
3179
3179
|
const l = limits;
|
|
3180
3180
|
if (l.autonomousThreshold !== void 0 && typeof l.autonomousThreshold !== "number") {
|
|
3181
3181
|
errors.push({
|
|
3182
|
-
path: `${
|
|
3182
|
+
path: `${path3}.autonomousThreshold`,
|
|
3183
3183
|
message: "autonomousThreshold must be a number"
|
|
3184
3184
|
});
|
|
3185
3185
|
}
|
|
3186
3186
|
if (l.maxTransactionAmount !== void 0 && typeof l.maxTransactionAmount !== "number") {
|
|
3187
3187
|
errors.push({
|
|
3188
|
-
path: `${
|
|
3188
|
+
path: `${path3}.maxTransactionAmount`,
|
|
3189
3189
|
message: "maxTransactionAmount must be a number"
|
|
3190
3190
|
});
|
|
3191
3191
|
}
|
|
3192
3192
|
if (typeof l.autonomousThreshold === "number" && typeof l.maxTransactionAmount === "number" && l.autonomousThreshold > l.maxTransactionAmount) {
|
|
3193
3193
|
errors.push({
|
|
3194
|
-
path: `${
|
|
3194
|
+
path: `${path3}.autonomousThreshold`,
|
|
3195
3195
|
message: "autonomousThreshold (Autonomous Limit) must be <= maxTransactionAmount (Hard Limit)"
|
|
3196
3196
|
});
|
|
3197
3197
|
}
|
|
3198
3198
|
if (l.maxRequestsPerHour !== void 0 && typeof l.maxRequestsPerHour !== "number") {
|
|
3199
3199
|
errors.push({
|
|
3200
|
-
path: `${
|
|
3200
|
+
path: `${path3}.maxRequestsPerHour`,
|
|
3201
3201
|
message: "maxRequestsPerHour must be a number"
|
|
3202
3202
|
});
|
|
3203
3203
|
}
|
|
3204
3204
|
if (l.currency !== void 0 && typeof l.currency !== "string") {
|
|
3205
|
-
errors.push({ path: `${
|
|
3205
|
+
errors.push({ path: `${path3}.currency`, message: "currency must be a string" });
|
|
3206
3206
|
}
|
|
3207
3207
|
return errors;
|
|
3208
3208
|
}
|
|
3209
|
-
function validateRiskThresholds(thresholds,
|
|
3209
|
+
function validateRiskThresholds(thresholds, path3) {
|
|
3210
3210
|
const errors = [];
|
|
3211
3211
|
if (typeof thresholds !== "object" || thresholds === null) {
|
|
3212
|
-
return [{ path:
|
|
3212
|
+
return [{ path: path3, message: "riskThresholds must be an object" }];
|
|
3213
3213
|
}
|
|
3214
3214
|
const t = thresholds;
|
|
3215
3215
|
for (const range of ["autoAllow", "requireApproval", "autoBlock"]) {
|
|
3216
3216
|
if (!t[range] || typeof t[range] !== "object") {
|
|
3217
3217
|
errors.push({
|
|
3218
|
-
path: `${
|
|
3218
|
+
path: `${path3}.${range}`,
|
|
3219
3219
|
message: `${range} is required and must be an object with min and max`
|
|
3220
3220
|
});
|
|
3221
3221
|
continue;
|
|
3222
3222
|
}
|
|
3223
3223
|
const r = t[range];
|
|
3224
3224
|
if (typeof r.min !== "number" || typeof r.max !== "number") {
|
|
3225
|
-
errors.push({ path: `${
|
|
3225
|
+
errors.push({ path: `${path3}.${range}`, message: `${range} must have numeric min and max` });
|
|
3226
3226
|
} else if (r.min > r.max) {
|
|
3227
|
-
errors.push({ path: `${
|
|
3227
|
+
errors.push({ path: `${path3}.${range}`, message: `${range}.min must be <= ${range}.max` });
|
|
3228
3228
|
}
|
|
3229
3229
|
}
|
|
3230
3230
|
if (isValidThresholdShape(t)) {
|
|
3231
3231
|
const thresholdObj = t;
|
|
3232
3232
|
if (thresholdObj.autoAllow.max + 1 !== thresholdObj.requireApproval.min) {
|
|
3233
3233
|
errors.push({
|
|
3234
|
-
path: `${
|
|
3234
|
+
path: `${path3}`,
|
|
3235
3235
|
message: `Gap between autoAllow.max (${thresholdObj.autoAllow.max}) and requireApproval.min (${thresholdObj.requireApproval.min}). Ranges must be contiguous.`
|
|
3236
3236
|
});
|
|
3237
3237
|
}
|
|
3238
3238
|
if (thresholdObj.requireApproval.max + 1 !== thresholdObj.autoBlock.min) {
|
|
3239
3239
|
errors.push({
|
|
3240
|
-
path: `${
|
|
3240
|
+
path: `${path3}`,
|
|
3241
3241
|
message: `Gap between requireApproval.max (${thresholdObj.requireApproval.max}) and autoBlock.min (${thresholdObj.autoBlock.min}). Ranges must be contiguous.`
|
|
3242
3242
|
});
|
|
3243
3243
|
}
|
|
@@ -3597,8 +3597,8 @@ ${category.label}
|
|
|
3597
3597
|
async runAndSave(outputPath) {
|
|
3598
3598
|
const policy = await this.run();
|
|
3599
3599
|
const yaml2 = toYaml(policy);
|
|
3600
|
-
const
|
|
3601
|
-
|
|
3600
|
+
const fs3 = await import("fs");
|
|
3601
|
+
fs3.writeFileSync(outputPath, yaml2, "utf-8");
|
|
3602
3602
|
this.print(`
|
|
3603
3603
|
Policy saved to ${outputPath}`);
|
|
3604
3604
|
this.print(" AstraSync Local Guard is now protecting your agent.\n");
|
|
@@ -3713,7 +3713,7 @@ Policy saved to ${outputPath}`);
|
|
|
3713
3713
|
};
|
|
3714
3714
|
|
|
3715
3715
|
// src/version.ts
|
|
3716
|
-
var SDK_VERSION = "5.18.
|
|
3716
|
+
var SDK_VERSION = "5.18.1";
|
|
3717
3717
|
|
|
3718
3718
|
// src/http.ts
|
|
3719
3719
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -6574,29 +6574,29 @@ function loadEnrolment(paths) {
|
|
|
6574
6574
|
[paths.machineDevice, "machine"],
|
|
6575
6575
|
[paths.userDevice, "user"]
|
|
6576
6576
|
];
|
|
6577
|
-
for (const [
|
|
6578
|
-
if (!(0, import_fs6.existsSync)(
|
|
6577
|
+
for (const [path3, scope] of candidates) {
|
|
6578
|
+
if (!(0, import_fs6.existsSync)(path3)) continue;
|
|
6579
6579
|
try {
|
|
6580
|
-
const parsed = JSON.parse((0, import_fs6.readFileSync)(
|
|
6580
|
+
const parsed = JSON.parse((0, import_fs6.readFileSync)(path3, "utf-8"));
|
|
6581
6581
|
if (isEnrolment(parsed)) return { enrolment: parsed, scope };
|
|
6582
6582
|
} catch {
|
|
6583
6583
|
}
|
|
6584
|
-
return { corrupt: true, path:
|
|
6584
|
+
return { corrupt: true, path: path3 };
|
|
6585
6585
|
}
|
|
6586
6586
|
return null;
|
|
6587
6587
|
}
|
|
6588
|
-
function writeFileMode(
|
|
6589
|
-
(0, import_fs6.mkdirSync)((0, import_path5.dirname)(
|
|
6590
|
-
(0, import_fs6.writeFileSync)(
|
|
6588
|
+
function writeFileMode(path3, content, mode) {
|
|
6589
|
+
(0, import_fs6.mkdirSync)((0, import_path5.dirname)(path3), { recursive: true, mode: 448 });
|
|
6590
|
+
(0, import_fs6.writeFileSync)(path3, content, { encoding: "utf-8", mode });
|
|
6591
6591
|
try {
|
|
6592
|
-
(0, import_fs6.chmodSync)(
|
|
6592
|
+
(0, import_fs6.chmodSync)(path3, mode);
|
|
6593
6593
|
} catch {
|
|
6594
6594
|
}
|
|
6595
6595
|
}
|
|
6596
6596
|
function saveEnrolment(paths, enrolment, scope) {
|
|
6597
|
-
const
|
|
6598
|
-
writeFileMode(
|
|
6599
|
-
return
|
|
6597
|
+
const path3 = scope === "machine" ? paths.machineDevice : paths.userDevice;
|
|
6598
|
+
writeFileMode(path3, JSON.stringify(enrolment, null, 2), scope === "machine" ? 420 : 384);
|
|
6599
|
+
return path3;
|
|
6600
6600
|
}
|
|
6601
6601
|
function readCachedPolicies(paths) {
|
|
6602
6602
|
const out = [];
|
|
@@ -6918,12 +6918,12 @@ var MANAGED_SETTINGS_LOCATIONS = {
|
|
|
6918
6918
|
win32: "%ProgramData%\\OpenAI\\Codex\\requirements.toml"
|
|
6919
6919
|
}
|
|
6920
6920
|
};
|
|
6921
|
-
function managedHookCommand(target,
|
|
6921
|
+
function managedHookCommand(target, os3) {
|
|
6922
6922
|
const bin = target === "claude" ? "astrasync-claude-hook" : "astrasync-codex-hook";
|
|
6923
|
-
if (
|
|
6923
|
+
if (os3 === "win32") return `"C:\\Program Files\\nodejs\\${bin}.cmd"`;
|
|
6924
6924
|
return `/usr/local/bin/${bin}`;
|
|
6925
6925
|
}
|
|
6926
|
-
function buildClaudeManagedSettings(
|
|
6926
|
+
function buildClaudeManagedSettings(os3) {
|
|
6927
6927
|
return {
|
|
6928
6928
|
allowManagedHooksOnly: true,
|
|
6929
6929
|
env: { ASTRASYNC_FLEET_REQUIRED: "1" },
|
|
@@ -6931,7 +6931,7 @@ function buildClaudeManagedSettings(os2) {
|
|
|
6931
6931
|
PreToolUse: [
|
|
6932
6932
|
{
|
|
6933
6933
|
matcher: HOOK_MATCHER,
|
|
6934
|
-
hooks: [{ type: "command", command: managedHookCommand("claude",
|
|
6934
|
+
hooks: [{ type: "command", command: managedHookCommand("claude", os3), timeout: 10 }]
|
|
6935
6935
|
}
|
|
6936
6936
|
]
|
|
6937
6937
|
},
|
|
@@ -6941,11 +6941,11 @@ function buildClaudeManagedSettings(os2) {
|
|
|
6941
6941
|
function tomlString(value) {
|
|
6942
6942
|
return JSON.stringify(value);
|
|
6943
6943
|
}
|
|
6944
|
-
function buildCodexRequirementsToml(
|
|
6945
|
-
const command =
|
|
6944
|
+
function buildCodexRequirementsToml(os3) {
|
|
6945
|
+
const command = os3 === "win32" ? `set ASTRASYNC_FLEET_REQUIRED=1&& ${managedHookCommand("codex", os3)}` : `ASTRASYNC_FLEET_REQUIRED=1 ${managedHookCommand("codex", os3)}`;
|
|
6946
6946
|
return [
|
|
6947
6947
|
"# AstraSync Local Guard \u2014 managed hook (generated by `astrasync guard managed-settings --codex`)",
|
|
6948
|
-
`# Install at: ${MANAGED_SETTINGS_LOCATIONS.codex[
|
|
6948
|
+
`# Install at: ${MANAGED_SETTINGS_LOCATIONS.codex[os3]}`,
|
|
6949
6949
|
"allow_managed_hooks_only = true",
|
|
6950
6950
|
"",
|
|
6951
6951
|
"[features]",
|
|
@@ -6965,14 +6965,14 @@ function buildCodexRequirementsToml(os2) {
|
|
|
6965
6965
|
function buildManagedSettingsFiles(targets) {
|
|
6966
6966
|
const out = [];
|
|
6967
6967
|
for (const target of targets) {
|
|
6968
|
-
for (const
|
|
6969
|
-
const content = target === "claude" ? `${JSON.stringify(buildClaudeManagedSettings(
|
|
6970
|
-
` : buildCodexRequirementsToml(
|
|
6968
|
+
for (const os3 of ["darwin", "linux", "win32"]) {
|
|
6969
|
+
const content = target === "claude" ? `${JSON.stringify(buildClaudeManagedSettings(os3), null, 2)}
|
|
6970
|
+
` : buildCodexRequirementsToml(os3);
|
|
6971
6971
|
out.push({
|
|
6972
6972
|
target,
|
|
6973
|
-
os:
|
|
6974
|
-
installPath: MANAGED_SETTINGS_LOCATIONS[target][
|
|
6975
|
-
fileName: `${target}-${
|
|
6973
|
+
os: os3,
|
|
6974
|
+
installPath: MANAGED_SETTINGS_LOCATIONS[target][os3],
|
|
6975
|
+
fileName: `${target}-${os3}-${target === "claude" ? "managed-settings.json" : "requirements.toml"}`,
|
|
6976
6976
|
content
|
|
6977
6977
|
});
|
|
6978
6978
|
}
|
|
@@ -7151,10 +7151,170 @@ function createLocalCert(hosts, days = 30) {
|
|
|
7151
7151
|
${b64}
|
|
7152
7152
|
-----END CERTIFICATE-----
|
|
7153
7153
|
`,
|
|
7154
|
-
key: privateKey.export({ type: "pkcs8", format: "pem" }).toString()
|
|
7154
|
+
key: privateKey.export({ type: "pkcs8", format: "pem" }).toString(),
|
|
7155
|
+
spkiSha256: import_node_crypto5.default.createHash("sha256").update(spki).digest("base64")
|
|
7155
7156
|
};
|
|
7156
7157
|
}
|
|
7157
7158
|
|
|
7159
|
+
// src/fleet/open-browser.ts
|
|
7160
|
+
var import_node_child_process = require("child_process");
|
|
7161
|
+
var import_node_fs = __toESM(require("fs"));
|
|
7162
|
+
var import_node_os = __toESM(require("os"));
|
|
7163
|
+
var import_node_path = __toESM(require("path"));
|
|
7164
|
+
function isWsl(env = process.env, platform2 = process.platform, readVersion = () => import_node_fs.default.readFileSync("/proc/version", "utf8")) {
|
|
7165
|
+
if (platform2 !== "linux") return false;
|
|
7166
|
+
if (env.WSL_DISTRO_NAME) return true;
|
|
7167
|
+
try {
|
|
7168
|
+
return /microsoft/i.test(readVersion());
|
|
7169
|
+
} catch {
|
|
7170
|
+
return false;
|
|
7171
|
+
}
|
|
7172
|
+
}
|
|
7173
|
+
var MAC_PATHS = [
|
|
7174
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
7175
|
+
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
7176
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium"
|
|
7177
|
+
];
|
|
7178
|
+
var LINUX_NAMES = [
|
|
7179
|
+
"google-chrome",
|
|
7180
|
+
"google-chrome-stable",
|
|
7181
|
+
"chromium",
|
|
7182
|
+
"chromium-browser",
|
|
7183
|
+
"microsoft-edge"
|
|
7184
|
+
];
|
|
7185
|
+
var WSL_WINDOWS_PATHS = [
|
|
7186
|
+
"/mnt/c/Program Files/Google/Chrome/Application/chrome.exe",
|
|
7187
|
+
"/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
|
7188
|
+
"/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe",
|
|
7189
|
+
"/mnt/c/Program Files/Microsoft/Edge/Application/msedge.exe"
|
|
7190
|
+
];
|
|
7191
|
+
function findChromium(env = process.env, platform2 = process.platform, exists = (p) => import_node_fs.default.existsSync(p), wsl = isWsl(env, platform2), listDir = (dir) => import_node_fs.default.readdirSync(dir)) {
|
|
7192
|
+
let candidates;
|
|
7193
|
+
if (platform2 === "darwin") {
|
|
7194
|
+
candidates = MAC_PATHS;
|
|
7195
|
+
} else if (platform2 === "win32") {
|
|
7196
|
+
const bases = [
|
|
7197
|
+
env.ProgramFiles,
|
|
7198
|
+
env["ProgramFiles(x86)"],
|
|
7199
|
+
env.LOCALAPPDATA ?? env.LocalAppData
|
|
7200
|
+
].filter((b) => !!b);
|
|
7201
|
+
candidates = [
|
|
7202
|
+
...bases.map((b) => import_node_path.default.win32.join(b, "Google", "Chrome", "Application", "chrome.exe")),
|
|
7203
|
+
...bases.map((b) => import_node_path.default.win32.join(b, "Microsoft", "Edge", "Application", "msedge.exe"))
|
|
7204
|
+
];
|
|
7205
|
+
} else {
|
|
7206
|
+
const dirs = (env.PATH ?? "").split(":").filter(Boolean);
|
|
7207
|
+
candidates = LINUX_NAMES.flatMap((n) => dirs.map((d) => import_node_path.default.posix.join(d, n)));
|
|
7208
|
+
const cache2 = env.PLAYWRIGHT_BROWSERS_PATH ?? (env.HOME ? `${env.HOME}/.cache/ms-playwright` : "");
|
|
7209
|
+
if (cache2) {
|
|
7210
|
+
let builds = [];
|
|
7211
|
+
try {
|
|
7212
|
+
builds = listDir(cache2).filter((d) => /^chromium-\d+$/.test(d));
|
|
7213
|
+
} catch {
|
|
7214
|
+
}
|
|
7215
|
+
builds.sort((a, b) => Number(b.split("-")[1]) - Number(a.split("-")[1]));
|
|
7216
|
+
for (const b of builds)
|
|
7217
|
+
candidates.push(
|
|
7218
|
+
import_node_path.default.posix.join(cache2, b, "chrome-linux64", "chrome"),
|
|
7219
|
+
import_node_path.default.posix.join(cache2, b, "chrome-linux", "chrome")
|
|
7220
|
+
);
|
|
7221
|
+
}
|
|
7222
|
+
if (wsl) candidates = [...candidates, ...WSL_WINDOWS_PATHS];
|
|
7223
|
+
}
|
|
7224
|
+
return candidates.find((c) => exists(c)) ?? null;
|
|
7225
|
+
}
|
|
7226
|
+
function isWindowsExeFromWsl(browserPath) {
|
|
7227
|
+
return /^\/mnt\/[a-z]\//i.test(browserPath) && /\.exe$/i.test(browserPath);
|
|
7228
|
+
}
|
|
7229
|
+
function browserName(browserPath) {
|
|
7230
|
+
const b = browserPath.toLowerCase();
|
|
7231
|
+
if (b.includes("edge")) return "Edge";
|
|
7232
|
+
if (b.includes("chromium")) return "Chromium";
|
|
7233
|
+
return "Chrome";
|
|
7234
|
+
}
|
|
7235
|
+
function profileDirFor(proxyPort) {
|
|
7236
|
+
return import_node_path.default.join(import_node_os.default.tmpdir(), `astrasync-agent-browser-${proxyPort}`);
|
|
7237
|
+
}
|
|
7238
|
+
function windowsProfileDir(profileDir) {
|
|
7239
|
+
if (/^\/mnt\/[a-z]\//i.test(profileDir)) {
|
|
7240
|
+
try {
|
|
7241
|
+
return (0, import_node_child_process.execFileSync)("wslpath", ["-w", profileDir], { encoding: "utf8" }).trim();
|
|
7242
|
+
} catch {
|
|
7243
|
+
}
|
|
7244
|
+
}
|
|
7245
|
+
return `C:\\Temp\\${import_node_path.default.basename(profileDir)}`;
|
|
7246
|
+
}
|
|
7247
|
+
function certFlag(certSpki) {
|
|
7248
|
+
return `--ignore-certificate-errors-spki-list=${certSpki}`;
|
|
7249
|
+
}
|
|
7250
|
+
var CERT_FLAG_NOTE = "Chrome shows a warning bar about the --ignore-certificate-errors-spki-list flag. That is expected (it trusts only this proxy's certificate); close the bar.";
|
|
7251
|
+
function launchBrowser(browserPath, proxyPort, url, certSpki, profileDir = profileDirFor(proxyPort), onError) {
|
|
7252
|
+
const dir = isWindowsExeFromWsl(browserPath) ? windowsProfileDir(profileDir) : profileDir;
|
|
7253
|
+
const child = (0, import_node_child_process.spawn)(
|
|
7254
|
+
browserPath,
|
|
7255
|
+
[
|
|
7256
|
+
`--proxy-server=http://127.0.0.1:${proxyPort}`,
|
|
7257
|
+
certFlag(certSpki),
|
|
7258
|
+
`--user-data-dir=${dir}`,
|
|
7259
|
+
"--no-first-run",
|
|
7260
|
+
"--new-window",
|
|
7261
|
+
url
|
|
7262
|
+
],
|
|
7263
|
+
{ detached: true, stdio: "ignore" }
|
|
7264
|
+
);
|
|
7265
|
+
child.on("error", (err) => onError?.(err));
|
|
7266
|
+
child.unref();
|
|
7267
|
+
return child;
|
|
7268
|
+
}
|
|
7269
|
+
function browserCommand(platform2, port, url, certSpki, wsl = false) {
|
|
7270
|
+
const proxy = `--proxy-server="http://127.0.0.1:${port}" ${certFlag(certSpki)}`;
|
|
7271
|
+
if (platform2 === "win32" || wsl) {
|
|
7272
|
+
return `& "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" ${proxy} --user-data-dir="$env:TEMP\\astrasync-agent-${port}" '${url}'`;
|
|
7273
|
+
}
|
|
7274
|
+
const exe = platform2 === "darwin" ? '"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"' : "google-chrome";
|
|
7275
|
+
return `${exe} ${proxy} --user-data-dir="\${TMPDIR:-/tmp}/astrasync-agent-${port}" '${url}'`;
|
|
7276
|
+
}
|
|
7277
|
+
function browserCommandLines(platform2, port, url, certSpki, wsl = isWsl(process.env, platform2)) {
|
|
7278
|
+
if (wsl) {
|
|
7279
|
+
return [
|
|
7280
|
+
" In PowerShell (Windows):",
|
|
7281
|
+
` ${browserCommand("win32", port, url, certSpki)}`,
|
|
7282
|
+
" Or inside WSL (with Chromium installed):",
|
|
7283
|
+
` ${browserCommand("linux", port, url, certSpki)}`,
|
|
7284
|
+
` ${CERT_FLAG_NOTE}`
|
|
7285
|
+
];
|
|
7286
|
+
}
|
|
7287
|
+
return [` ${browserCommand(platform2, port, url, certSpki)}`, ` ${CERT_FLAG_NOTE}`];
|
|
7288
|
+
}
|
|
7289
|
+
function openThroughProxy(opts) {
|
|
7290
|
+
const log = opts.log ?? ((l) => console.log(l));
|
|
7291
|
+
const platform2 = opts.platform ?? process.platform;
|
|
7292
|
+
const env = opts.env ?? process.env;
|
|
7293
|
+
const wsl = opts.wsl ?? isWsl(env, platform2);
|
|
7294
|
+
const found = opts.find ? opts.find() : findChromium(env, platform2, void 0, wsl);
|
|
7295
|
+
if (!found) {
|
|
7296
|
+
log("No Chrome/Edge/Chromium found. Start one through the proxy with:");
|
|
7297
|
+
for (const l of browserCommandLines(platform2, opts.port, opts.url, opts.certSpki, wsl)) log(l);
|
|
7298
|
+
return false;
|
|
7299
|
+
}
|
|
7300
|
+
(opts.launch ?? launchBrowser)(
|
|
7301
|
+
found,
|
|
7302
|
+
opts.port,
|
|
7303
|
+
opts.url,
|
|
7304
|
+
opts.certSpki,
|
|
7305
|
+
profileDirFor(opts.port),
|
|
7306
|
+
(err) => log(`Couldn't start ${browserName(found)}: ${err.message}`)
|
|
7307
|
+
);
|
|
7308
|
+
log(`Opened ${browserName(found)} through the proxy.`);
|
|
7309
|
+
log(CERT_FLAG_NOTE);
|
|
7310
|
+
if (wsl && isWindowsExeFromWsl(found)) {
|
|
7311
|
+
log(
|
|
7312
|
+
"If the Windows browser can't reach the proxy, install Chromium inside WSL (e.g. npx playwright install chromium)."
|
|
7313
|
+
);
|
|
7314
|
+
}
|
|
7315
|
+
return true;
|
|
7316
|
+
}
|
|
7317
|
+
|
|
7158
7318
|
// src/fleet/browse-proxy.ts
|
|
7159
7319
|
var HOP_BY_HOP = /* @__PURE__ */ new Set([
|
|
7160
7320
|
"connection",
|
|
@@ -7171,10 +7331,33 @@ function cleanHeaders(h) {
|
|
|
7171
7331
|
for (const [k, v] of Object.entries(h)) if (!HOP_BY_HOP.has(k) && v !== void 0) out[k] = v;
|
|
7172
7332
|
return out;
|
|
7173
7333
|
}
|
|
7334
|
+
function helpPage(port, certSpki) {
|
|
7335
|
+
const proxy = `http://127.0.0.1:${port}`;
|
|
7336
|
+
return `<!doctype html>
|
|
7337
|
+
<html lang="en"><head><meta charset="utf-8"><title>AstraSync device proxy</title>
|
|
7338
|
+
<style>body{font:16px/1.5 system-ui,sans-serif;max-width:40rem;margin:2rem auto;padding:0 1rem}code{background:#f2f2f2;padding:0 .25rem}</style>
|
|
7339
|
+
</head><body>
|
|
7340
|
+
<h1>AstraSync device proxy</h1>
|
|
7341
|
+
<p>This is AstraSync's Local Guard device proxy. It only works as a browser proxy — it isn't a page to open.</p>
|
|
7342
|
+
<h2>Open the sign-in link</h2>
|
|
7343
|
+
<ul>
|
|
7344
|
+
<li>Run <code>astrasync guard browse --open</code> — it opens a browser that goes through this proxy.</li>
|
|
7345
|
+
<li>Or start Chrome, Edge or Chromium with <code>--proxy-server=${proxy} ${certFlag(certSpki)}</code> and a separate profile (<code>--user-data-dir=<an empty folder></code>), then open the sign-in link in it.</li>
|
|
7346
|
+
</ul>
|
|
7347
|
+
<p>Chrome shows a warning bar about that flag. That is expected — it trusts only this proxy's certificate — so close the bar.</p>
|
|
7348
|
+
<p>Keep <code>astrasync guard browse</code> running while you use the session.</p>
|
|
7349
|
+
</body></html>
|
|
7350
|
+
`;
|
|
7351
|
+
}
|
|
7174
7352
|
async function startBrowseProxy(opts) {
|
|
7175
7353
|
const hosts = new Set(opts.hosts.map((h) => h.toLowerCase()));
|
|
7176
7354
|
const deviceHeader = `Device ${opts.deviceCredential}`;
|
|
7177
|
-
const { cert, key } = createLocalCert([...hosts]);
|
|
7355
|
+
const { cert, key, spkiSha256 } = createLocalCert([...hosts]);
|
|
7356
|
+
const sockets = /* @__PURE__ */ new Set();
|
|
7357
|
+
const track = (s) => {
|
|
7358
|
+
sockets.add(s);
|
|
7359
|
+
s.once("close", () => sockets.delete(s));
|
|
7360
|
+
};
|
|
7178
7361
|
function forward(req, res, target) {
|
|
7179
7362
|
const headers = cleanHeaders(req.headers);
|
|
7180
7363
|
headers["x-astra-device"] = deviceHeader;
|
|
@@ -7226,6 +7409,7 @@ async function startBrowseProxy(opts) {
|
|
|
7226
7409
|
},
|
|
7227
7410
|
onConnect
|
|
7228
7411
|
) : import_node_net.default.connect(target.port, target.host, onConnect);
|
|
7412
|
+
track(upstream);
|
|
7229
7413
|
upstream.on("error", () => socket.destroy());
|
|
7230
7414
|
socket.on("error", () => upstream.destroy());
|
|
7231
7415
|
}
|
|
@@ -7257,6 +7441,16 @@ async function startBrowseProxy(opts) {
|
|
|
7257
7441
|
});
|
|
7258
7442
|
});
|
|
7259
7443
|
const server = import_node_http.default.createServer((req, res) => {
|
|
7444
|
+
if ((req.url ?? "").startsWith("/")) {
|
|
7445
|
+
if (req.url === "/favicon.ico") {
|
|
7446
|
+
res.writeHead(404).end();
|
|
7447
|
+
return;
|
|
7448
|
+
}
|
|
7449
|
+
const listening = server.address()?.port ?? 0;
|
|
7450
|
+
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
7451
|
+
res.end(helpPage(listening, spkiSha256));
|
|
7452
|
+
return;
|
|
7453
|
+
}
|
|
7260
7454
|
let url;
|
|
7261
7455
|
try {
|
|
7262
7456
|
url = new URL(req.url ?? "");
|
|
@@ -7349,18 +7543,22 @@ async function startBrowseProxy(opts) {
|
|
|
7349
7543
|
upstream.pipe(socket);
|
|
7350
7544
|
socket.pipe(upstream);
|
|
7351
7545
|
});
|
|
7546
|
+
track(upstream);
|
|
7352
7547
|
upstream.on("error", () => socket.destroy());
|
|
7353
7548
|
socket.on("error", () => upstream.destroy());
|
|
7354
7549
|
});
|
|
7550
|
+
server.on("connection", track);
|
|
7355
7551
|
await new Promise((resolve) => server.listen(opts.port ?? 0, "127.0.0.1", resolve));
|
|
7356
7552
|
const port = server.address().port;
|
|
7357
7553
|
return {
|
|
7358
7554
|
port,
|
|
7555
|
+
certSpki: spkiSha256,
|
|
7359
7556
|
close: () => new Promise((resolve) => {
|
|
7360
7557
|
inner.close();
|
|
7361
7558
|
plainInner.close();
|
|
7362
7559
|
server.close(() => resolve());
|
|
7363
7560
|
server.closeAllConnections?.();
|
|
7561
|
+
for (const s of sockets) s.destroy();
|
|
7364
7562
|
})
|
|
7365
7563
|
};
|
|
7366
7564
|
}
|
|
@@ -7447,6 +7645,18 @@ async function runBrowse(paths, opts) {
|
|
|
7447
7645
|
log(
|
|
7448
7646
|
`Device proxy: http://127.0.0.1:${proxy.port} (adds this machine's credential for ${hosts.join(", ")})`
|
|
7449
7647
|
);
|
|
7648
|
+
if (!opts.open) {
|
|
7649
|
+
log("Open it in a browser through the proxy:");
|
|
7650
|
+
for (const l of browserCommandLines(
|
|
7651
|
+
opts.platform ?? process.platform,
|
|
7652
|
+
proxy.port,
|
|
7653
|
+
openUrl,
|
|
7654
|
+
proxy.certSpki,
|
|
7655
|
+
opts.wsl
|
|
7656
|
+
))
|
|
7657
|
+
log(l);
|
|
7658
|
+
log(" (or re-run with --open)");
|
|
7659
|
+
}
|
|
7450
7660
|
log("Playwright:");
|
|
7451
7661
|
log(
|
|
7452
7662
|
` chromium.launch({ proxy: { server: 'http://127.0.0.1:${proxy.port}' } }) + newContext({ ignoreHTTPSErrors: true })`
|
|
@@ -7486,7 +7696,7 @@ async function cmdSetup() {
|
|
|
7486
7696
|
}
|
|
7487
7697
|
async function cmdUpgrade() {
|
|
7488
7698
|
const policyPath = process.argv[4] || DEFAULT_POLICY_PATH;
|
|
7489
|
-
if (!
|
|
7699
|
+
if (!fs2.existsSync(policyPath)) {
|
|
7490
7700
|
console.error(`No policy file found at ${policyPath}`);
|
|
7491
7701
|
console.error('Run "astrasync guard setup" first to create a policy.');
|
|
7492
7702
|
process.exit(1);
|
|
@@ -7514,13 +7724,13 @@ async function cmdUpgrade() {
|
|
|
7514
7724
|
prompt: (message) => prompt.question(message),
|
|
7515
7725
|
print: (message) => console.log(message),
|
|
7516
7726
|
writeConfig: async (filePath, content) => {
|
|
7517
|
-
const dir =
|
|
7518
|
-
if (!
|
|
7519
|
-
|
|
7727
|
+
const dir = path2.dirname(filePath);
|
|
7728
|
+
if (!fs2.existsSync(dir)) fs2.mkdirSync(dir, { recursive: true });
|
|
7729
|
+
fs2.writeFileSync(filePath, content, "utf-8");
|
|
7520
7730
|
},
|
|
7521
7731
|
readConfig: async (filePath) => {
|
|
7522
7732
|
try {
|
|
7523
|
-
return
|
|
7733
|
+
return fs2.readFileSync(filePath, "utf-8");
|
|
7524
7734
|
} catch {
|
|
7525
7735
|
return null;
|
|
7526
7736
|
}
|
|
@@ -7541,13 +7751,13 @@ async function cmdStart() {
|
|
|
7541
7751
|
let gatewayConfig;
|
|
7542
7752
|
const upgraded = await isUpgraded(DEFAULT_CONFIG_DIR, async (p) => {
|
|
7543
7753
|
try {
|
|
7544
|
-
return
|
|
7754
|
+
return fs2.readFileSync(p, "utf-8");
|
|
7545
7755
|
} catch {
|
|
7546
7756
|
return null;
|
|
7547
7757
|
}
|
|
7548
7758
|
});
|
|
7549
7759
|
if (upgraded) {
|
|
7550
|
-
const config = JSON.parse(
|
|
7760
|
+
const config = JSON.parse(fs2.readFileSync(`${DEFAULT_CONFIG_DIR}/config`, "utf-8"));
|
|
7551
7761
|
gatewayConfig = {
|
|
7552
7762
|
mode: config.mode,
|
|
7553
7763
|
apiBaseUrl: config.platformUrl ? `${config.platformUrl}/api/v1` : void 0,
|
|
@@ -7555,7 +7765,7 @@ async function cmdStart() {
|
|
|
7555
7765
|
};
|
|
7556
7766
|
console.log(`[AstraSync] Starting in ${config.mode} mode (agent: ${config.agentId})`);
|
|
7557
7767
|
} else {
|
|
7558
|
-
if (!
|
|
7768
|
+
if (!fs2.existsSync(policyPath)) {
|
|
7559
7769
|
console.error(`No policy file found at ${policyPath}`);
|
|
7560
7770
|
console.error('Run "astrasync guard setup" first.');
|
|
7561
7771
|
process.exit(1);
|
|
@@ -7592,7 +7802,7 @@ async function cmdStatus() {
|
|
|
7592
7802
|
const policyPath = process.argv[4] || DEFAULT_POLICY_PATH;
|
|
7593
7803
|
const upgraded = await isUpgraded(DEFAULT_CONFIG_DIR, async (p) => {
|
|
7594
7804
|
try {
|
|
7595
|
-
return
|
|
7805
|
+
return fs2.readFileSync(p, "utf-8");
|
|
7596
7806
|
} catch {
|
|
7597
7807
|
return null;
|
|
7598
7808
|
}
|
|
@@ -7602,7 +7812,7 @@ async function cmdStatus() {
|
|
|
7602
7812
|
console.log(` ${line}`);
|
|
7603
7813
|
}
|
|
7604
7814
|
if (upgraded) {
|
|
7605
|
-
const config = JSON.parse(
|
|
7815
|
+
const config = JSON.parse(fs2.readFileSync(`${DEFAULT_CONFIG_DIR}/config`, "utf-8"));
|
|
7606
7816
|
console.log(` Mode: ${config.mode}`);
|
|
7607
7817
|
console.log(` Agent: ${config.agentId}`);
|
|
7608
7818
|
console.log(` Platform: ${config.platformUrl}`);
|
|
@@ -7610,7 +7820,7 @@ async function cmdStatus() {
|
|
|
7610
7820
|
} else {
|
|
7611
7821
|
console.log(" Mode: local (free tier)");
|
|
7612
7822
|
}
|
|
7613
|
-
if (
|
|
7823
|
+
if (fs2.existsSync(policyPath)) {
|
|
7614
7824
|
const parsed = parseFile(policyPath);
|
|
7615
7825
|
if (parsed.validation.valid && parsed.policy) {
|
|
7616
7826
|
const p = parsed.policy;
|
|
@@ -7635,7 +7845,7 @@ async function cmdCheck() {
|
|
|
7635
7845
|
(a) => !a.startsWith("--") && a !== "guard" && a !== "check" && a !== process.argv[0] && a !== process.argv[1]
|
|
7636
7846
|
) || DEFAULT_POLICY_PATH;
|
|
7637
7847
|
const trigger = process.argv.find((a) => a.startsWith("--trigger="))?.split("=")[1] || "pre-push";
|
|
7638
|
-
if (!
|
|
7848
|
+
if (!fs2.existsSync(policyPath)) {
|
|
7639
7849
|
console.log("[AstraSync] No policy file \u2014 skipping check");
|
|
7640
7850
|
process.exit(0);
|
|
7641
7851
|
}
|
|
@@ -7647,9 +7857,9 @@ async function cmdCheck() {
|
|
|
7647
7857
|
}
|
|
7648
7858
|
let enforcement = "warn";
|
|
7649
7859
|
const configPath = `${DEFAULT_CONFIG_DIR}/config`;
|
|
7650
|
-
if (
|
|
7860
|
+
if (fs2.existsSync(configPath)) {
|
|
7651
7861
|
try {
|
|
7652
|
-
const config = JSON.parse(
|
|
7862
|
+
const config = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
|
|
7653
7863
|
enforcement = config.gitTriggerEnforcement || "warn";
|
|
7654
7864
|
} catch {
|
|
7655
7865
|
}
|
|
@@ -7712,8 +7922,8 @@ async function cmdUninstallHooks() {
|
|
|
7712
7922
|
}
|
|
7713
7923
|
}
|
|
7714
7924
|
function resolveClaudeHookCommand() {
|
|
7715
|
-
const sibling =
|
|
7716
|
-
if (
|
|
7925
|
+
const sibling = path2.join(__dirname, "astrasync-claude-hook.js");
|
|
7926
|
+
if (fs2.existsSync(sibling)) {
|
|
7717
7927
|
return `"${process.execPath}" "${sibling}"`;
|
|
7718
7928
|
}
|
|
7719
7929
|
return "astrasync-claude-hook";
|
|
@@ -7729,19 +7939,19 @@ function parseClaudeCodeFlags() {
|
|
|
7729
7939
|
};
|
|
7730
7940
|
}
|
|
7731
7941
|
function claudeCodePaths(project) {
|
|
7732
|
-
const root = project ? process.cwd() :
|
|
7942
|
+
const root = project ? process.cwd() : os2.homedir();
|
|
7733
7943
|
return {
|
|
7734
|
-
settingsPath:
|
|
7735
|
-
astrasyncDir:
|
|
7944
|
+
settingsPath: path2.join(root, ".claude", "settings.json"),
|
|
7945
|
+
astrasyncDir: path2.join(root, ".astrasync")
|
|
7736
7946
|
};
|
|
7737
7947
|
}
|
|
7738
7948
|
async function cmdInstallClaudeCode() {
|
|
7739
7949
|
const flags = parseClaudeCodeFlags();
|
|
7740
7950
|
const { settingsPath, astrasyncDir } = claudeCodePaths(flags.project);
|
|
7741
|
-
const policyPath = flags.policyOverride ||
|
|
7742
|
-
const guardJsonPath =
|
|
7951
|
+
const policyPath = flags.policyOverride || path2.join(astrasyncDir, "policy.yaml");
|
|
7952
|
+
const guardJsonPath = path2.join(astrasyncDir, "guard.json");
|
|
7743
7953
|
console.log("\nAstraSync Local Guard for Claude Code \u2014 install\n");
|
|
7744
|
-
if (
|
|
7954
|
+
if (fs2.existsSync(policyPath)) {
|
|
7745
7955
|
console.log(` Policy: using existing ${policyPath}`);
|
|
7746
7956
|
if (ensureGuardSelfProtection(policyPath)) {
|
|
7747
7957
|
console.log(" added guard self-protection patterns to file.write");
|
|
@@ -7749,7 +7959,7 @@ async function cmdInstallClaudeCode() {
|
|
|
7749
7959
|
} else if (flags.wizard) {
|
|
7750
7960
|
const prompt = createPrompt();
|
|
7751
7961
|
try {
|
|
7752
|
-
|
|
7962
|
+
fs2.mkdirSync(path2.dirname(policyPath), { recursive: true });
|
|
7753
7963
|
const wizard = new SetupWizard(prompt);
|
|
7754
7964
|
await wizard.runAndSave(policyPath);
|
|
7755
7965
|
} finally {
|
|
@@ -7758,17 +7968,17 @@ async function cmdInstallClaudeCode() {
|
|
|
7758
7968
|
ensureGuardSelfProtection(policyPath);
|
|
7759
7969
|
console.log(` Policy: created via wizard at ${policyPath}`);
|
|
7760
7970
|
} else {
|
|
7761
|
-
|
|
7762
|
-
|
|
7971
|
+
fs2.mkdirSync(path2.dirname(policyPath), { recursive: true });
|
|
7972
|
+
fs2.writeFileSync(policyPath, toYaml(buildDefaultClaudeCodePolicy()), "utf-8");
|
|
7763
7973
|
console.log(` Policy: default coding-agent policy written to ${policyPath}`);
|
|
7764
7974
|
console.log(" (re-run with --wizard for the interactive setup instead)");
|
|
7765
7975
|
}
|
|
7766
|
-
if (!
|
|
7976
|
+
if (!fs2.existsSync(guardJsonPath)) {
|
|
7767
7977
|
const guardSettings = {
|
|
7768
7978
|
posture: flags.active ? "active" : "passive",
|
|
7769
7979
|
governMcp: false
|
|
7770
7980
|
};
|
|
7771
|
-
|
|
7981
|
+
fs2.writeFileSync(guardJsonPath, `${JSON.stringify(guardSettings, null, 2)}
|
|
7772
7982
|
`, "utf-8");
|
|
7773
7983
|
console.log(
|
|
7774
7984
|
` Guard: ${guardJsonPath} (posture: ${guardSettings.posture}, governMcp: false)`
|
|
@@ -7798,7 +8008,7 @@ async function cmdInstallClaudeCode() {
|
|
|
7798
8008
|
}
|
|
7799
8009
|
console.log("\n Next steps:");
|
|
7800
8010
|
console.log(" 1. Start a NEW Claude Code session (settings load at startup).");
|
|
7801
|
-
console.log(` 2. Watch decisions: tail -f ${
|
|
8011
|
+
console.log(` 2. Watch decisions: tail -f ${path2.join(astrasyncDir, "traces")}/*.jsonl`);
|
|
7802
8012
|
console.log(` 3. When the traces look right, set "posture": "active" in ${guardJsonPath}`);
|
|
7803
8013
|
console.log(" to enforce (denies block, approvals use Claude Code's own prompt).");
|
|
7804
8014
|
console.log(' 4. To govern MCP tools too, set "governMcp": true and add');
|
|
@@ -7828,26 +8038,26 @@ async function cmdUninstallClaudeCode() {
|
|
|
7828
8038
|
);
|
|
7829
8039
|
}
|
|
7830
8040
|
function resolveCodexHookCommand() {
|
|
7831
|
-
const sibling =
|
|
7832
|
-
if (
|
|
8041
|
+
const sibling = path2.join(__dirname, "astrasync-codex-hook.js");
|
|
8042
|
+
if (fs2.existsSync(sibling)) {
|
|
7833
8043
|
return `"${process.execPath}" "${sibling}"`;
|
|
7834
8044
|
}
|
|
7835
8045
|
return "astrasync-codex-hook";
|
|
7836
8046
|
}
|
|
7837
8047
|
function codexPaths(project) {
|
|
7838
|
-
const root = project ? process.cwd() :
|
|
8048
|
+
const root = project ? process.cwd() : os2.homedir();
|
|
7839
8049
|
return {
|
|
7840
|
-
hooksPath:
|
|
7841
|
-
astrasyncDir:
|
|
8050
|
+
hooksPath: path2.join(root, ".codex", "hooks.json"),
|
|
8051
|
+
astrasyncDir: path2.join(root, ".astrasync")
|
|
7842
8052
|
};
|
|
7843
8053
|
}
|
|
7844
8054
|
async function cmdInstallCodex() {
|
|
7845
8055
|
const flags = parseClaudeCodeFlags();
|
|
7846
8056
|
const { hooksPath, astrasyncDir } = codexPaths(flags.project);
|
|
7847
|
-
const policyPath = flags.policyOverride ||
|
|
7848
|
-
const guardJsonPath =
|
|
8057
|
+
const policyPath = flags.policyOverride || path2.join(astrasyncDir, "policy.yaml");
|
|
8058
|
+
const guardJsonPath = path2.join(astrasyncDir, "guard.json");
|
|
7849
8059
|
console.log("\nAstraSync Local Guard for Codex CLI \u2014 install\n");
|
|
7850
|
-
if (
|
|
8060
|
+
if (fs2.existsSync(policyPath)) {
|
|
7851
8061
|
console.log(` Policy: using existing ${policyPath} (shared across adapters)`);
|
|
7852
8062
|
if (ensureGuardSelfProtection(policyPath)) {
|
|
7853
8063
|
console.log(" added guard self-protection patterns to file.write");
|
|
@@ -7855,7 +8065,7 @@ async function cmdInstallCodex() {
|
|
|
7855
8065
|
} else if (flags.wizard) {
|
|
7856
8066
|
const prompt = createPrompt();
|
|
7857
8067
|
try {
|
|
7858
|
-
|
|
8068
|
+
fs2.mkdirSync(path2.dirname(policyPath), { recursive: true });
|
|
7859
8069
|
const wizard = new SetupWizard(prompt);
|
|
7860
8070
|
await wizard.runAndSave(policyPath);
|
|
7861
8071
|
} finally {
|
|
@@ -7864,17 +8074,17 @@ async function cmdInstallCodex() {
|
|
|
7864
8074
|
ensureGuardSelfProtection(policyPath);
|
|
7865
8075
|
console.log(` Policy: created via wizard at ${policyPath}`);
|
|
7866
8076
|
} else {
|
|
7867
|
-
|
|
7868
|
-
|
|
8077
|
+
fs2.mkdirSync(path2.dirname(policyPath), { recursive: true });
|
|
8078
|
+
fs2.writeFileSync(policyPath, toYaml(buildDefaultClaudeCodePolicy()), "utf-8");
|
|
7869
8079
|
console.log(` Policy: default coding-agent policy written to ${policyPath}`);
|
|
7870
8080
|
console.log(" (re-run with --wizard for the interactive setup instead)");
|
|
7871
8081
|
}
|
|
7872
|
-
if (!
|
|
8082
|
+
if (!fs2.existsSync(guardJsonPath)) {
|
|
7873
8083
|
const guardSettings = {
|
|
7874
8084
|
posture: flags.active ? "active" : "passive",
|
|
7875
8085
|
governMcp: false
|
|
7876
8086
|
};
|
|
7877
|
-
|
|
8087
|
+
fs2.writeFileSync(guardJsonPath, `${JSON.stringify(guardSettings, null, 2)}
|
|
7878
8088
|
`, "utf-8");
|
|
7879
8089
|
console.log(
|
|
7880
8090
|
` Guard: ${guardJsonPath} (posture: ${guardSettings.posture}, governMcp: false)`
|
|
@@ -7893,7 +8103,7 @@ async function cmdInstallCodex() {
|
|
|
7893
8103
|
}
|
|
7894
8104
|
console.log("\n Next steps:");
|
|
7895
8105
|
console.log(" 1. Start a NEW Codex session (hooks load at startup; /hooks to inspect).");
|
|
7896
|
-
console.log(` 2. Watch decisions: tail -f ${
|
|
8106
|
+
console.log(` 2. Watch decisions: tail -f ${path2.join(astrasyncDir, "traces")}/*.jsonl`);
|
|
7897
8107
|
console.log(` 3. When the traces look right, set "posture": "active" in ${guardJsonPath}.`);
|
|
7898
8108
|
console.log(" Denies block; approvals fall through to Codex's own prompt \u2014");
|
|
7899
8109
|
console.log(" except in dontAsk/bypassPermissions modes, where they deny.");
|
|
@@ -7918,13 +8128,13 @@ function printCodexStatus() {
|
|
|
7918
8128
|
const { hooksPath, astrasyncDir } = codexPaths(scope === "project");
|
|
7919
8129
|
let hookInstalled = false;
|
|
7920
8130
|
try {
|
|
7921
|
-
const content =
|
|
8131
|
+
const content = fs2.readFileSync(hooksPath, "utf-8");
|
|
7922
8132
|
hookInstalled = content.includes(ASTRASYNC_CODEX_HOOK_MARKER);
|
|
7923
8133
|
} catch {
|
|
7924
8134
|
}
|
|
7925
8135
|
if (hookInstalled) {
|
|
7926
|
-
const policyPath =
|
|
7927
|
-
const policy =
|
|
8136
|
+
const policyPath = path2.join(astrasyncDir, "policy.yaml");
|
|
8137
|
+
const policy = fs2.existsSync(policyPath) ? `policy: ${policyPath}` : "policy: missing";
|
|
7928
8138
|
console.log(` Codex CLI (${scope}): hook installed, ${policy}`);
|
|
7929
8139
|
}
|
|
7930
8140
|
}
|
|
@@ -7934,24 +8144,24 @@ function printClaudeCodeStatus() {
|
|
|
7934
8144
|
const { settingsPath, astrasyncDir } = claudeCodePaths(scope === "project");
|
|
7935
8145
|
let hookInstalled = false;
|
|
7936
8146
|
try {
|
|
7937
|
-
const content =
|
|
8147
|
+
const content = fs2.readFileSync(settingsPath, "utf-8");
|
|
7938
8148
|
hookInstalled = content.includes(ASTRASYNC_HOOK_MARKER);
|
|
7939
8149
|
} catch {
|
|
7940
8150
|
}
|
|
7941
|
-
const policyPath =
|
|
7942
|
-
const guardJsonPath =
|
|
8151
|
+
const policyPath = path2.join(astrasyncDir, "policy.yaml");
|
|
8152
|
+
const guardJsonPath = path2.join(astrasyncDir, "guard.json");
|
|
7943
8153
|
let posture = "";
|
|
7944
|
-
if (
|
|
8154
|
+
if (fs2.existsSync(guardJsonPath)) {
|
|
7945
8155
|
try {
|
|
7946
|
-
const settings = JSON.parse(
|
|
8156
|
+
const settings = JSON.parse(fs2.readFileSync(guardJsonPath, "utf-8"));
|
|
7947
8157
|
posture = settings.posture ? `, posture: ${settings.posture}` : "";
|
|
7948
8158
|
} catch {
|
|
7949
8159
|
posture = ", guard.json unreadable";
|
|
7950
8160
|
}
|
|
7951
8161
|
}
|
|
7952
|
-
if (hookInstalled ||
|
|
8162
|
+
if (hookInstalled || fs2.existsSync(policyPath)) {
|
|
7953
8163
|
const hook = hookInstalled ? "hook installed" : "hook NOT installed";
|
|
7954
|
-
const policy =
|
|
8164
|
+
const policy = fs2.existsSync(policyPath) ? `policy: ${policyPath}` : "policy: missing";
|
|
7955
8165
|
console.log(` Claude Code (${scope}): ${hook}, ${policy}${posture}`);
|
|
7956
8166
|
}
|
|
7957
8167
|
}
|
|
@@ -7997,14 +8207,21 @@ async function cmdFleetStatus() {
|
|
|
7997
8207
|
async function cmdBrowse() {
|
|
7998
8208
|
try {
|
|
7999
8209
|
const port = flagValue("--port");
|
|
8000
|
-
const
|
|
8210
|
+
const open = process.argv.includes("--open");
|
|
8211
|
+
const { proxy, openUrl } = await runBrowse(fleetPaths(), {
|
|
8001
8212
|
checkpoint: flagValue("--checkpoint") ?? "",
|
|
8002
8213
|
slug: flagValue("--slug") ?? "",
|
|
8003
8214
|
upstream: flagValue("--upstream"),
|
|
8004
8215
|
port: port ? Number(port) : void 0,
|
|
8005
|
-
extraHosts: flagValue("--host") ? [flagValue("--host")] : []
|
|
8216
|
+
extraHosts: flagValue("--host") ? [flagValue("--host")] : [],
|
|
8217
|
+
open
|
|
8006
8218
|
});
|
|
8219
|
+
if (open) openThroughProxy({ port: proxy.port, url: openUrl, certSpki: proxy.certSpki });
|
|
8220
|
+
let stopping = false;
|
|
8007
8221
|
const stop = async () => {
|
|
8222
|
+
if (stopping) process.exit(0);
|
|
8223
|
+
stopping = true;
|
|
8224
|
+
setTimeout(() => process.exit(0), 2e3).unref();
|
|
8008
8225
|
await proxy.close();
|
|
8009
8226
|
process.exit(0);
|
|
8010
8227
|
};
|
|
@@ -8039,7 +8256,7 @@ async function cmdGitRoute() {
|
|
|
8039
8256
|
}
|
|
8040
8257
|
async function cmdGitCredential() {
|
|
8041
8258
|
const action = process.argv[process.argv.indexOf("git-credential") + 1] ?? "";
|
|
8042
|
-
const input =
|
|
8259
|
+
const input = fs2.readFileSync(0, "utf-8");
|
|
8043
8260
|
process.stdout.write(runGitCredential(action, input));
|
|
8044
8261
|
}
|
|
8045
8262
|
async function cmdManagedSettings() {
|
|
@@ -8143,8 +8360,9 @@ async function main() {
|
|
|
8143
8360
|
" browse Sign an agent in to your dashboard from this machine and"
|
|
8144
8361
|
);
|
|
8145
8362
|
console.log(
|
|
8146
|
-
" run its device proxy (--checkpoint <url> --slug <agent
|
|
8363
|
+
" run its device proxy (--checkpoint <url> --slug <agent>;"
|
|
8147
8364
|
);
|
|
8365
|
+
console.log(" --open to start a browser through the proxy)");
|
|
8148
8366
|
console.log(" enroll <token> Enrol this machine in your organisation fleet");
|
|
8149
8367
|
console.log(" (--api-base-url <url>, --system for machine scope)");
|
|
8150
8368
|
console.log(" fleet-status Show fleet enrolment, signed policy and heartbeat");
|