@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
package/dist/bin/astrasync.js
CHANGED
|
@@ -36,7 +36,7 @@ var SDK_VERSION;
|
|
|
36
36
|
var init_version = __esm({
|
|
37
37
|
"src/version.ts"() {
|
|
38
38
|
"use strict";
|
|
39
|
-
SDK_VERSION = "5.18.
|
|
39
|
+
SDK_VERSION = "5.18.1";
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
42
|
|
|
@@ -3474,115 +3474,115 @@ function validatePolicy(policy) {
|
|
|
3474
3474
|
}
|
|
3475
3475
|
return { valid: errors.length === 0, errors };
|
|
3476
3476
|
}
|
|
3477
|
-
function validatePurpose(purpose,
|
|
3477
|
+
function validatePurpose(purpose, path3) {
|
|
3478
3478
|
const errors = [];
|
|
3479
3479
|
if (!purpose || typeof purpose !== "object") {
|
|
3480
|
-
return [{ path:
|
|
3480
|
+
return [{ path: path3, message: "purpose must be an object" }];
|
|
3481
3481
|
}
|
|
3482
3482
|
const p = purpose;
|
|
3483
3483
|
if (typeof p.id !== "string" || !p.id) {
|
|
3484
|
-
errors.push({ path: `${
|
|
3484
|
+
errors.push({ path: `${path3}.id`, message: "id is required and must be a non-empty string" });
|
|
3485
3485
|
}
|
|
3486
3486
|
if (typeof p.allowed !== "boolean") {
|
|
3487
|
-
errors.push({ path: `${
|
|
3487
|
+
errors.push({ path: `${path3}.allowed`, message: "allowed is required and must be a boolean" });
|
|
3488
3488
|
}
|
|
3489
3489
|
if (p.targets !== void 0 && !isStringArray(p.targets)) {
|
|
3490
|
-
errors.push({ path: `${
|
|
3490
|
+
errors.push({ path: `${path3}.targets`, message: "targets must be an array of strings" });
|
|
3491
3491
|
}
|
|
3492
3492
|
if (p.blockedPatterns !== void 0 && !isStringArray(p.blockedPatterns)) {
|
|
3493
3493
|
errors.push({
|
|
3494
|
-
path: `${
|
|
3494
|
+
path: `${path3}.blockedPatterns`,
|
|
3495
3495
|
message: "blockedPatterns must be an array of strings"
|
|
3496
3496
|
});
|
|
3497
3497
|
}
|
|
3498
3498
|
if (p.requiresApproval !== void 0 && typeof p.requiresApproval !== "boolean") {
|
|
3499
3499
|
errors.push({
|
|
3500
|
-
path: `${
|
|
3500
|
+
path: `${path3}.requiresApproval`,
|
|
3501
3501
|
message: "requiresApproval must be a boolean"
|
|
3502
3502
|
});
|
|
3503
3503
|
}
|
|
3504
3504
|
return errors;
|
|
3505
3505
|
}
|
|
3506
|
-
function validateScope(scope,
|
|
3506
|
+
function validateScope(scope, path3) {
|
|
3507
3507
|
const errors = [];
|
|
3508
3508
|
if (typeof scope !== "object" || scope === null) {
|
|
3509
|
-
return [{ path:
|
|
3509
|
+
return [{ path: path3, message: "scope must be an object" }];
|
|
3510
3510
|
}
|
|
3511
3511
|
const s = scope;
|
|
3512
3512
|
for (const field of ["allowedDomains", "blockedDomains", "blockedResources"]) {
|
|
3513
3513
|
if (s[field] !== void 0 && !isStringArray(s[field])) {
|
|
3514
|
-
errors.push({ path: `${
|
|
3514
|
+
errors.push({ path: `${path3}.${field}`, message: `${field} must be an array of strings` });
|
|
3515
3515
|
}
|
|
3516
3516
|
}
|
|
3517
3517
|
return errors;
|
|
3518
3518
|
}
|
|
3519
|
-
function validateLimits(limits,
|
|
3519
|
+
function validateLimits(limits, path3) {
|
|
3520
3520
|
const errors = [];
|
|
3521
3521
|
if (typeof limits !== "object" || limits === null) {
|
|
3522
|
-
return [{ path:
|
|
3522
|
+
return [{ path: path3, message: "limits must be an object" }];
|
|
3523
3523
|
}
|
|
3524
3524
|
const l = limits;
|
|
3525
3525
|
if (l.autonomousThreshold !== void 0 && typeof l.autonomousThreshold !== "number") {
|
|
3526
3526
|
errors.push({
|
|
3527
|
-
path: `${
|
|
3527
|
+
path: `${path3}.autonomousThreshold`,
|
|
3528
3528
|
message: "autonomousThreshold must be a number"
|
|
3529
3529
|
});
|
|
3530
3530
|
}
|
|
3531
3531
|
if (l.maxTransactionAmount !== void 0 && typeof l.maxTransactionAmount !== "number") {
|
|
3532
3532
|
errors.push({
|
|
3533
|
-
path: `${
|
|
3533
|
+
path: `${path3}.maxTransactionAmount`,
|
|
3534
3534
|
message: "maxTransactionAmount must be a number"
|
|
3535
3535
|
});
|
|
3536
3536
|
}
|
|
3537
3537
|
if (typeof l.autonomousThreshold === "number" && typeof l.maxTransactionAmount === "number" && l.autonomousThreshold > l.maxTransactionAmount) {
|
|
3538
3538
|
errors.push({
|
|
3539
|
-
path: `${
|
|
3539
|
+
path: `${path3}.autonomousThreshold`,
|
|
3540
3540
|
message: "autonomousThreshold (Autonomous Limit) must be <= maxTransactionAmount (Hard Limit)"
|
|
3541
3541
|
});
|
|
3542
3542
|
}
|
|
3543
3543
|
if (l.maxRequestsPerHour !== void 0 && typeof l.maxRequestsPerHour !== "number") {
|
|
3544
3544
|
errors.push({
|
|
3545
|
-
path: `${
|
|
3545
|
+
path: `${path3}.maxRequestsPerHour`,
|
|
3546
3546
|
message: "maxRequestsPerHour must be a number"
|
|
3547
3547
|
});
|
|
3548
3548
|
}
|
|
3549
3549
|
if (l.currency !== void 0 && typeof l.currency !== "string") {
|
|
3550
|
-
errors.push({ path: `${
|
|
3550
|
+
errors.push({ path: `${path3}.currency`, message: "currency must be a string" });
|
|
3551
3551
|
}
|
|
3552
3552
|
return errors;
|
|
3553
3553
|
}
|
|
3554
|
-
function validateRiskThresholds(thresholds,
|
|
3554
|
+
function validateRiskThresholds(thresholds, path3) {
|
|
3555
3555
|
const errors = [];
|
|
3556
3556
|
if (typeof thresholds !== "object" || thresholds === null) {
|
|
3557
|
-
return [{ path:
|
|
3557
|
+
return [{ path: path3, message: "riskThresholds must be an object" }];
|
|
3558
3558
|
}
|
|
3559
3559
|
const t = thresholds;
|
|
3560
3560
|
for (const range of ["autoAllow", "requireApproval", "autoBlock"]) {
|
|
3561
3561
|
if (!t[range] || typeof t[range] !== "object") {
|
|
3562
3562
|
errors.push({
|
|
3563
|
-
path: `${
|
|
3563
|
+
path: `${path3}.${range}`,
|
|
3564
3564
|
message: `${range} is required and must be an object with min and max`
|
|
3565
3565
|
});
|
|
3566
3566
|
continue;
|
|
3567
3567
|
}
|
|
3568
3568
|
const r = t[range];
|
|
3569
3569
|
if (typeof r.min !== "number" || typeof r.max !== "number") {
|
|
3570
|
-
errors.push({ path: `${
|
|
3570
|
+
errors.push({ path: `${path3}.${range}`, message: `${range} must have numeric min and max` });
|
|
3571
3571
|
} else if (r.min > r.max) {
|
|
3572
|
-
errors.push({ path: `${
|
|
3572
|
+
errors.push({ path: `${path3}.${range}`, message: `${range}.min must be <= ${range}.max` });
|
|
3573
3573
|
}
|
|
3574
3574
|
}
|
|
3575
3575
|
if (isValidThresholdShape(t)) {
|
|
3576
3576
|
const thresholdObj = t;
|
|
3577
3577
|
if (thresholdObj.autoAllow.max + 1 !== thresholdObj.requireApproval.min) {
|
|
3578
3578
|
errors.push({
|
|
3579
|
-
path: `${
|
|
3579
|
+
path: `${path3}`,
|
|
3580
3580
|
message: `Gap between autoAllow.max (${thresholdObj.autoAllow.max}) and requireApproval.min (${thresholdObj.requireApproval.min}). Ranges must be contiguous.`
|
|
3581
3581
|
});
|
|
3582
3582
|
}
|
|
3583
3583
|
if (thresholdObj.requireApproval.max + 1 !== thresholdObj.autoBlock.min) {
|
|
3584
3584
|
errors.push({
|
|
3585
|
-
path: `${
|
|
3585
|
+
path: `${path3}`,
|
|
3586
3586
|
message: `Gap between requireApproval.max (${thresholdObj.requireApproval.max}) and autoBlock.min (${thresholdObj.autoBlock.min}). Ranges must be contiguous.`
|
|
3587
3587
|
});
|
|
3588
3588
|
}
|
|
@@ -3962,8 +3962,8 @@ ${category.label}
|
|
|
3962
3962
|
async runAndSave(outputPath) {
|
|
3963
3963
|
const policy = await this.run();
|
|
3964
3964
|
const yaml2 = toYaml(policy);
|
|
3965
|
-
const
|
|
3966
|
-
|
|
3965
|
+
const fs3 = await import("fs");
|
|
3966
|
+
fs3.writeFileSync(outputPath, yaml2, "utf-8");
|
|
3967
3967
|
this.print(`
|
|
3968
3968
|
Policy saved to ${outputPath}`);
|
|
3969
3969
|
this.print(" AstraSync Local Guard is now protecting your agent.\n");
|
|
@@ -7825,29 +7825,29 @@ function loadEnrolment(paths) {
|
|
|
7825
7825
|
[paths.machineDevice, "machine"],
|
|
7826
7826
|
[paths.userDevice, "user"]
|
|
7827
7827
|
];
|
|
7828
|
-
for (const [
|
|
7829
|
-
if (!(0, import_fs6.existsSync)(
|
|
7828
|
+
for (const [path3, scope] of candidates) {
|
|
7829
|
+
if (!(0, import_fs6.existsSync)(path3)) continue;
|
|
7830
7830
|
try {
|
|
7831
|
-
const parsed = JSON.parse((0, import_fs6.readFileSync)(
|
|
7831
|
+
const parsed = JSON.parse((0, import_fs6.readFileSync)(path3, "utf-8"));
|
|
7832
7832
|
if (isEnrolment(parsed)) return { enrolment: parsed, scope };
|
|
7833
7833
|
} catch {
|
|
7834
7834
|
}
|
|
7835
|
-
return { corrupt: true, path:
|
|
7835
|
+
return { corrupt: true, path: path3 };
|
|
7836
7836
|
}
|
|
7837
7837
|
return null;
|
|
7838
7838
|
}
|
|
7839
|
-
function writeFileMode(
|
|
7840
|
-
(0, import_fs6.mkdirSync)((0, import_path5.dirname)(
|
|
7841
|
-
(0, import_fs6.writeFileSync)(
|
|
7839
|
+
function writeFileMode(path3, content, mode) {
|
|
7840
|
+
(0, import_fs6.mkdirSync)((0, import_path5.dirname)(path3), { recursive: true, mode: 448 });
|
|
7841
|
+
(0, import_fs6.writeFileSync)(path3, content, { encoding: "utf-8", mode });
|
|
7842
7842
|
try {
|
|
7843
|
-
(0, import_fs6.chmodSync)(
|
|
7843
|
+
(0, import_fs6.chmodSync)(path3, mode);
|
|
7844
7844
|
} catch {
|
|
7845
7845
|
}
|
|
7846
7846
|
}
|
|
7847
7847
|
function saveEnrolment(paths, enrolment, scope) {
|
|
7848
|
-
const
|
|
7849
|
-
writeFileMode(
|
|
7850
|
-
return
|
|
7848
|
+
const path3 = scope === "machine" ? paths.machineDevice : paths.userDevice;
|
|
7849
|
+
writeFileMode(path3, JSON.stringify(enrolment, null, 2), scope === "machine" ? 420 : 384);
|
|
7850
|
+
return path3;
|
|
7851
7851
|
}
|
|
7852
7852
|
function readCachedPolicies(paths) {
|
|
7853
7853
|
const out = [];
|
|
@@ -8175,12 +8175,12 @@ function formatFleetStatus(status) {
|
|
|
8175
8175
|
if (status.lastError) lines.push(` Last sync error: ${status.lastError}`);
|
|
8176
8176
|
return lines;
|
|
8177
8177
|
}
|
|
8178
|
-
function managedHookCommand(target,
|
|
8178
|
+
function managedHookCommand(target, os3) {
|
|
8179
8179
|
const bin = target === "claude" ? "astrasync-claude-hook" : "astrasync-codex-hook";
|
|
8180
|
-
if (
|
|
8180
|
+
if (os3 === "win32") return `"C:\\Program Files\\nodejs\\${bin}.cmd"`;
|
|
8181
8181
|
return `/usr/local/bin/${bin}`;
|
|
8182
8182
|
}
|
|
8183
|
-
function buildClaudeManagedSettings(
|
|
8183
|
+
function buildClaudeManagedSettings(os3) {
|
|
8184
8184
|
return {
|
|
8185
8185
|
allowManagedHooksOnly: true,
|
|
8186
8186
|
env: { ASTRASYNC_FLEET_REQUIRED: "1" },
|
|
@@ -8188,7 +8188,7 @@ function buildClaudeManagedSettings(os2) {
|
|
|
8188
8188
|
PreToolUse: [
|
|
8189
8189
|
{
|
|
8190
8190
|
matcher: HOOK_MATCHER,
|
|
8191
|
-
hooks: [{ type: "command", command: managedHookCommand("claude",
|
|
8191
|
+
hooks: [{ type: "command", command: managedHookCommand("claude", os3), timeout: 10 }]
|
|
8192
8192
|
}
|
|
8193
8193
|
]
|
|
8194
8194
|
},
|
|
@@ -8198,11 +8198,11 @@ function buildClaudeManagedSettings(os2) {
|
|
|
8198
8198
|
function tomlString(value) {
|
|
8199
8199
|
return JSON.stringify(value);
|
|
8200
8200
|
}
|
|
8201
|
-
function buildCodexRequirementsToml(
|
|
8202
|
-
const command =
|
|
8201
|
+
function buildCodexRequirementsToml(os3) {
|
|
8202
|
+
const command = os3 === "win32" ? `set ASTRASYNC_FLEET_REQUIRED=1&& ${managedHookCommand("codex", os3)}` : `ASTRASYNC_FLEET_REQUIRED=1 ${managedHookCommand("codex", os3)}`;
|
|
8203
8203
|
return [
|
|
8204
8204
|
"# AstraSync Local Guard \u2014 managed hook (generated by `astrasync guard managed-settings --codex`)",
|
|
8205
|
-
`# Install at: ${MANAGED_SETTINGS_LOCATIONS.codex[
|
|
8205
|
+
`# Install at: ${MANAGED_SETTINGS_LOCATIONS.codex[os3]}`,
|
|
8206
8206
|
"allow_managed_hooks_only = true",
|
|
8207
8207
|
"",
|
|
8208
8208
|
"[features]",
|
|
@@ -8222,14 +8222,14 @@ function buildCodexRequirementsToml(os2) {
|
|
|
8222
8222
|
function buildManagedSettingsFiles(targets) {
|
|
8223
8223
|
const out = [];
|
|
8224
8224
|
for (const target of targets) {
|
|
8225
|
-
for (const
|
|
8226
|
-
const content = target === "claude" ? `${JSON.stringify(buildClaudeManagedSettings(
|
|
8227
|
-
` : buildCodexRequirementsToml(
|
|
8225
|
+
for (const os3 of ["darwin", "linux", "win32"]) {
|
|
8226
|
+
const content = target === "claude" ? `${JSON.stringify(buildClaudeManagedSettings(os3), null, 2)}
|
|
8227
|
+
` : buildCodexRequirementsToml(os3);
|
|
8228
8228
|
out.push({
|
|
8229
8229
|
target,
|
|
8230
|
-
os:
|
|
8231
|
-
installPath: MANAGED_SETTINGS_LOCATIONS[target][
|
|
8232
|
-
fileName: `${target}-${
|
|
8230
|
+
os: os3,
|
|
8231
|
+
installPath: MANAGED_SETTINGS_LOCATIONS[target][os3],
|
|
8232
|
+
fileName: `${target}-${os3}-${target === "claude" ? "managed-settings.json" : "requirements.toml"}`,
|
|
8233
8233
|
content
|
|
8234
8234
|
});
|
|
8235
8235
|
}
|
|
@@ -8435,7 +8435,8 @@ function createLocalCert(hosts, days = 30) {
|
|
|
8435
8435
|
${b64}
|
|
8436
8436
|
-----END CERTIFICATE-----
|
|
8437
8437
|
`,
|
|
8438
|
-
key: privateKey.export({ type: "pkcs8", format: "pem" }).toString()
|
|
8438
|
+
key: privateKey.export({ type: "pkcs8", format: "pem" }).toString(),
|
|
8439
|
+
spkiSha256: import_node_crypto5.default.createHash("sha256").update(spki).digest("base64")
|
|
8439
8440
|
};
|
|
8440
8441
|
}
|
|
8441
8442
|
var import_node_crypto5, tlv, seq2, set2, ctx, ECDSA_SHA256;
|
|
@@ -8451,16 +8452,204 @@ var init_local_cert = __esm({
|
|
|
8451
8452
|
}
|
|
8452
8453
|
});
|
|
8453
8454
|
|
|
8455
|
+
// src/fleet/open-browser.ts
|
|
8456
|
+
function isWsl(env = process.env, platform2 = process.platform, readVersion = () => import_node_fs.default.readFileSync("/proc/version", "utf8")) {
|
|
8457
|
+
if (platform2 !== "linux") return false;
|
|
8458
|
+
if (env.WSL_DISTRO_NAME) return true;
|
|
8459
|
+
try {
|
|
8460
|
+
return /microsoft/i.test(readVersion());
|
|
8461
|
+
} catch {
|
|
8462
|
+
return false;
|
|
8463
|
+
}
|
|
8464
|
+
}
|
|
8465
|
+
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)) {
|
|
8466
|
+
let candidates;
|
|
8467
|
+
if (platform2 === "darwin") {
|
|
8468
|
+
candidates = MAC_PATHS;
|
|
8469
|
+
} else if (platform2 === "win32") {
|
|
8470
|
+
const bases = [
|
|
8471
|
+
env.ProgramFiles,
|
|
8472
|
+
env["ProgramFiles(x86)"],
|
|
8473
|
+
env.LOCALAPPDATA ?? env.LocalAppData
|
|
8474
|
+
].filter((b) => !!b);
|
|
8475
|
+
candidates = [
|
|
8476
|
+
...bases.map((b) => import_node_path.default.win32.join(b, "Google", "Chrome", "Application", "chrome.exe")),
|
|
8477
|
+
...bases.map((b) => import_node_path.default.win32.join(b, "Microsoft", "Edge", "Application", "msedge.exe"))
|
|
8478
|
+
];
|
|
8479
|
+
} else {
|
|
8480
|
+
const dirs = (env.PATH ?? "").split(":").filter(Boolean);
|
|
8481
|
+
candidates = LINUX_NAMES.flatMap((n) => dirs.map((d) => import_node_path.default.posix.join(d, n)));
|
|
8482
|
+
const cache2 = env.PLAYWRIGHT_BROWSERS_PATH ?? (env.HOME ? `${env.HOME}/.cache/ms-playwright` : "");
|
|
8483
|
+
if (cache2) {
|
|
8484
|
+
let builds = [];
|
|
8485
|
+
try {
|
|
8486
|
+
builds = listDir(cache2).filter((d) => /^chromium-\d+$/.test(d));
|
|
8487
|
+
} catch {
|
|
8488
|
+
}
|
|
8489
|
+
builds.sort((a, b) => Number(b.split("-")[1]) - Number(a.split("-")[1]));
|
|
8490
|
+
for (const b of builds)
|
|
8491
|
+
candidates.push(
|
|
8492
|
+
import_node_path.default.posix.join(cache2, b, "chrome-linux64", "chrome"),
|
|
8493
|
+
import_node_path.default.posix.join(cache2, b, "chrome-linux", "chrome")
|
|
8494
|
+
);
|
|
8495
|
+
}
|
|
8496
|
+
if (wsl) candidates = [...candidates, ...WSL_WINDOWS_PATHS];
|
|
8497
|
+
}
|
|
8498
|
+
return candidates.find((c) => exists(c)) ?? null;
|
|
8499
|
+
}
|
|
8500
|
+
function isWindowsExeFromWsl(browserPath) {
|
|
8501
|
+
return /^\/mnt\/[a-z]\//i.test(browserPath) && /\.exe$/i.test(browserPath);
|
|
8502
|
+
}
|
|
8503
|
+
function browserName(browserPath) {
|
|
8504
|
+
const b = browserPath.toLowerCase();
|
|
8505
|
+
if (b.includes("edge")) return "Edge";
|
|
8506
|
+
if (b.includes("chromium")) return "Chromium";
|
|
8507
|
+
return "Chrome";
|
|
8508
|
+
}
|
|
8509
|
+
function profileDirFor(proxyPort) {
|
|
8510
|
+
return import_node_path.default.join(import_node_os.default.tmpdir(), `astrasync-agent-browser-${proxyPort}`);
|
|
8511
|
+
}
|
|
8512
|
+
function windowsProfileDir(profileDir) {
|
|
8513
|
+
if (/^\/mnt\/[a-z]\//i.test(profileDir)) {
|
|
8514
|
+
try {
|
|
8515
|
+
return (0, import_node_child_process.execFileSync)("wslpath", ["-w", profileDir], { encoding: "utf8" }).trim();
|
|
8516
|
+
} catch {
|
|
8517
|
+
}
|
|
8518
|
+
}
|
|
8519
|
+
return `C:\\Temp\\${import_node_path.default.basename(profileDir)}`;
|
|
8520
|
+
}
|
|
8521
|
+
function certFlag(certSpki) {
|
|
8522
|
+
return `--ignore-certificate-errors-spki-list=${certSpki}`;
|
|
8523
|
+
}
|
|
8524
|
+
function launchBrowser(browserPath, proxyPort, url, certSpki, profileDir = profileDirFor(proxyPort), onError) {
|
|
8525
|
+
const dir = isWindowsExeFromWsl(browserPath) ? windowsProfileDir(profileDir) : profileDir;
|
|
8526
|
+
const child = (0, import_node_child_process.spawn)(
|
|
8527
|
+
browserPath,
|
|
8528
|
+
[
|
|
8529
|
+
`--proxy-server=http://127.0.0.1:${proxyPort}`,
|
|
8530
|
+
certFlag(certSpki),
|
|
8531
|
+
`--user-data-dir=${dir}`,
|
|
8532
|
+
"--no-first-run",
|
|
8533
|
+
"--new-window",
|
|
8534
|
+
url
|
|
8535
|
+
],
|
|
8536
|
+
{ detached: true, stdio: "ignore" }
|
|
8537
|
+
);
|
|
8538
|
+
child.on("error", (err) => onError?.(err));
|
|
8539
|
+
child.unref();
|
|
8540
|
+
return child;
|
|
8541
|
+
}
|
|
8542
|
+
function browserCommand(platform2, port, url, certSpki, wsl = false) {
|
|
8543
|
+
const proxy = `--proxy-server="http://127.0.0.1:${port}" ${certFlag(certSpki)}`;
|
|
8544
|
+
if (platform2 === "win32" || wsl) {
|
|
8545
|
+
return `& "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" ${proxy} --user-data-dir="$env:TEMP\\astrasync-agent-${port}" '${url}'`;
|
|
8546
|
+
}
|
|
8547
|
+
const exe = platform2 === "darwin" ? '"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"' : "google-chrome";
|
|
8548
|
+
return `${exe} ${proxy} --user-data-dir="\${TMPDIR:-/tmp}/astrasync-agent-${port}" '${url}'`;
|
|
8549
|
+
}
|
|
8550
|
+
function browserCommandLines(platform2, port, url, certSpki, wsl = isWsl(process.env, platform2)) {
|
|
8551
|
+
if (wsl) {
|
|
8552
|
+
return [
|
|
8553
|
+
" In PowerShell (Windows):",
|
|
8554
|
+
` ${browserCommand("win32", port, url, certSpki)}`,
|
|
8555
|
+
" Or inside WSL (with Chromium installed):",
|
|
8556
|
+
` ${browserCommand("linux", port, url, certSpki)}`,
|
|
8557
|
+
` ${CERT_FLAG_NOTE}`
|
|
8558
|
+
];
|
|
8559
|
+
}
|
|
8560
|
+
return [` ${browserCommand(platform2, port, url, certSpki)}`, ` ${CERT_FLAG_NOTE}`];
|
|
8561
|
+
}
|
|
8562
|
+
function openThroughProxy(opts) {
|
|
8563
|
+
const log = opts.log ?? ((l) => console.log(l));
|
|
8564
|
+
const platform2 = opts.platform ?? process.platform;
|
|
8565
|
+
const env = opts.env ?? process.env;
|
|
8566
|
+
const wsl = opts.wsl ?? isWsl(env, platform2);
|
|
8567
|
+
const found = opts.find ? opts.find() : findChromium(env, platform2, void 0, wsl);
|
|
8568
|
+
if (!found) {
|
|
8569
|
+
log("No Chrome/Edge/Chromium found. Start one through the proxy with:");
|
|
8570
|
+
for (const l of browserCommandLines(platform2, opts.port, opts.url, opts.certSpki, wsl)) log(l);
|
|
8571
|
+
return false;
|
|
8572
|
+
}
|
|
8573
|
+
(opts.launch ?? launchBrowser)(
|
|
8574
|
+
found,
|
|
8575
|
+
opts.port,
|
|
8576
|
+
opts.url,
|
|
8577
|
+
opts.certSpki,
|
|
8578
|
+
profileDirFor(opts.port),
|
|
8579
|
+
(err) => log(`Couldn't start ${browserName(found)}: ${err.message}`)
|
|
8580
|
+
);
|
|
8581
|
+
log(`Opened ${browserName(found)} through the proxy.`);
|
|
8582
|
+
log(CERT_FLAG_NOTE);
|
|
8583
|
+
if (wsl && isWindowsExeFromWsl(found)) {
|
|
8584
|
+
log(
|
|
8585
|
+
"If the Windows browser can't reach the proxy, install Chromium inside WSL (e.g. npx playwright install chromium)."
|
|
8586
|
+
);
|
|
8587
|
+
}
|
|
8588
|
+
return true;
|
|
8589
|
+
}
|
|
8590
|
+
var import_node_child_process, import_node_fs, import_node_os, import_node_path, MAC_PATHS, LINUX_NAMES, WSL_WINDOWS_PATHS, CERT_FLAG_NOTE;
|
|
8591
|
+
var init_open_browser = __esm({
|
|
8592
|
+
"src/fleet/open-browser.ts"() {
|
|
8593
|
+
"use strict";
|
|
8594
|
+
import_node_child_process = require("child_process");
|
|
8595
|
+
import_node_fs = __toESM(require("fs"));
|
|
8596
|
+
import_node_os = __toESM(require("os"));
|
|
8597
|
+
import_node_path = __toESM(require("path"));
|
|
8598
|
+
MAC_PATHS = [
|
|
8599
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
8600
|
+
"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge",
|
|
8601
|
+
"/Applications/Chromium.app/Contents/MacOS/Chromium"
|
|
8602
|
+
];
|
|
8603
|
+
LINUX_NAMES = [
|
|
8604
|
+
"google-chrome",
|
|
8605
|
+
"google-chrome-stable",
|
|
8606
|
+
"chromium",
|
|
8607
|
+
"chromium-browser",
|
|
8608
|
+
"microsoft-edge"
|
|
8609
|
+
];
|
|
8610
|
+
WSL_WINDOWS_PATHS = [
|
|
8611
|
+
"/mnt/c/Program Files/Google/Chrome/Application/chrome.exe",
|
|
8612
|
+
"/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
|
|
8613
|
+
"/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe",
|
|
8614
|
+
"/mnt/c/Program Files/Microsoft/Edge/Application/msedge.exe"
|
|
8615
|
+
];
|
|
8616
|
+
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.";
|
|
8617
|
+
}
|
|
8618
|
+
});
|
|
8619
|
+
|
|
8454
8620
|
// src/fleet/browse-proxy.ts
|
|
8455
8621
|
function cleanHeaders(h) {
|
|
8456
8622
|
const out = {};
|
|
8457
8623
|
for (const [k, v] of Object.entries(h)) if (!HOP_BY_HOP.has(k) && v !== void 0) out[k] = v;
|
|
8458
8624
|
return out;
|
|
8459
8625
|
}
|
|
8626
|
+
function helpPage(port, certSpki) {
|
|
8627
|
+
const proxy = `http://127.0.0.1:${port}`;
|
|
8628
|
+
return `<!doctype html>
|
|
8629
|
+
<html lang="en"><head><meta charset="utf-8"><title>AstraSync device proxy</title>
|
|
8630
|
+
<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>
|
|
8631
|
+
</head><body>
|
|
8632
|
+
<h1>AstraSync device proxy</h1>
|
|
8633
|
+
<p>This is AstraSync's Local Guard device proxy. It only works as a browser proxy — it isn't a page to open.</p>
|
|
8634
|
+
<h2>Open the sign-in link</h2>
|
|
8635
|
+
<ul>
|
|
8636
|
+
<li>Run <code>astrasync guard browse --open</code> — it opens a browser that goes through this proxy.</li>
|
|
8637
|
+
<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>
|
|
8638
|
+
</ul>
|
|
8639
|
+
<p>Chrome shows a warning bar about that flag. That is expected — it trusts only this proxy's certificate — so close the bar.</p>
|
|
8640
|
+
<p>Keep <code>astrasync guard browse</code> running while you use the session.</p>
|
|
8641
|
+
</body></html>
|
|
8642
|
+
`;
|
|
8643
|
+
}
|
|
8460
8644
|
async function startBrowseProxy(opts) {
|
|
8461
8645
|
const hosts = new Set(opts.hosts.map((h) => h.toLowerCase()));
|
|
8462
8646
|
const deviceHeader = `Device ${opts.deviceCredential}`;
|
|
8463
|
-
const { cert, key } = createLocalCert([...hosts]);
|
|
8647
|
+
const { cert, key, spkiSha256 } = createLocalCert([...hosts]);
|
|
8648
|
+
const sockets = /* @__PURE__ */ new Set();
|
|
8649
|
+
const track = (s) => {
|
|
8650
|
+
sockets.add(s);
|
|
8651
|
+
s.once("close", () => sockets.delete(s));
|
|
8652
|
+
};
|
|
8464
8653
|
function forward(req, res, target) {
|
|
8465
8654
|
const headers = cleanHeaders(req.headers);
|
|
8466
8655
|
headers["x-astra-device"] = deviceHeader;
|
|
@@ -8512,6 +8701,7 @@ async function startBrowseProxy(opts) {
|
|
|
8512
8701
|
},
|
|
8513
8702
|
onConnect
|
|
8514
8703
|
) : import_node_net.default.connect(target.port, target.host, onConnect);
|
|
8704
|
+
track(upstream);
|
|
8515
8705
|
upstream.on("error", () => socket.destroy());
|
|
8516
8706
|
socket.on("error", () => upstream.destroy());
|
|
8517
8707
|
}
|
|
@@ -8543,6 +8733,16 @@ async function startBrowseProxy(opts) {
|
|
|
8543
8733
|
});
|
|
8544
8734
|
});
|
|
8545
8735
|
const server = import_node_http.default.createServer((req, res) => {
|
|
8736
|
+
if ((req.url ?? "").startsWith("/")) {
|
|
8737
|
+
if (req.url === "/favicon.ico") {
|
|
8738
|
+
res.writeHead(404).end();
|
|
8739
|
+
return;
|
|
8740
|
+
}
|
|
8741
|
+
const listening = server.address()?.port ?? 0;
|
|
8742
|
+
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
8743
|
+
res.end(helpPage(listening, spkiSha256));
|
|
8744
|
+
return;
|
|
8745
|
+
}
|
|
8546
8746
|
let url;
|
|
8547
8747
|
try {
|
|
8548
8748
|
url = new URL(req.url ?? "");
|
|
@@ -8635,18 +8835,22 @@ async function startBrowseProxy(opts) {
|
|
|
8635
8835
|
upstream.pipe(socket);
|
|
8636
8836
|
socket.pipe(upstream);
|
|
8637
8837
|
});
|
|
8838
|
+
track(upstream);
|
|
8638
8839
|
upstream.on("error", () => socket.destroy());
|
|
8639
8840
|
socket.on("error", () => upstream.destroy());
|
|
8640
8841
|
});
|
|
8842
|
+
server.on("connection", track);
|
|
8641
8843
|
await new Promise((resolve) => server.listen(opts.port ?? 0, "127.0.0.1", resolve));
|
|
8642
8844
|
const port = server.address().port;
|
|
8643
8845
|
return {
|
|
8644
8846
|
port,
|
|
8847
|
+
certSpki: spkiSha256,
|
|
8645
8848
|
close: () => new Promise((resolve) => {
|
|
8646
8849
|
inner.close();
|
|
8647
8850
|
plainInner.close();
|
|
8648
8851
|
server.close(() => resolve());
|
|
8649
8852
|
server.closeAllConnections?.();
|
|
8853
|
+
for (const s of sockets) s.destroy();
|
|
8650
8854
|
})
|
|
8651
8855
|
};
|
|
8652
8856
|
}
|
|
@@ -8659,6 +8863,7 @@ var init_browse_proxy = __esm({
|
|
|
8659
8863
|
import_node_net = __toESM(require("net"));
|
|
8660
8864
|
import_node_tls = __toESM(require("tls"));
|
|
8661
8865
|
init_local_cert();
|
|
8866
|
+
init_open_browser();
|
|
8662
8867
|
HOP_BY_HOP = /* @__PURE__ */ new Set([
|
|
8663
8868
|
"connection",
|
|
8664
8869
|
"proxy-connection",
|
|
@@ -8754,6 +8959,18 @@ async function runBrowse(paths, opts) {
|
|
|
8754
8959
|
log(
|
|
8755
8960
|
`Device proxy: http://127.0.0.1:${proxy.port} (adds this machine's credential for ${hosts.join(", ")})`
|
|
8756
8961
|
);
|
|
8962
|
+
if (!opts.open) {
|
|
8963
|
+
log("Open it in a browser through the proxy:");
|
|
8964
|
+
for (const l of browserCommandLines(
|
|
8965
|
+
opts.platform ?? process.platform,
|
|
8966
|
+
proxy.port,
|
|
8967
|
+
openUrl,
|
|
8968
|
+
proxy.certSpki,
|
|
8969
|
+
opts.wsl
|
|
8970
|
+
))
|
|
8971
|
+
log(l);
|
|
8972
|
+
log(" (or re-run with --open)");
|
|
8973
|
+
}
|
|
8757
8974
|
log("Playwright:");
|
|
8758
8975
|
log(
|
|
8759
8976
|
` chromium.launch({ proxy: { server: 'http://127.0.0.1:${proxy.port}' } }) + newContext({ ignoreHTTPSErrors: true })`
|
|
@@ -8770,6 +8987,7 @@ var init_browse = __esm({
|
|
|
8770
8987
|
"use strict";
|
|
8771
8988
|
init_enrolment_store();
|
|
8772
8989
|
init_browse_proxy();
|
|
8990
|
+
init_open_browser();
|
|
8773
8991
|
}
|
|
8774
8992
|
});
|
|
8775
8993
|
|
|
@@ -8799,7 +9017,7 @@ async function cmdSetup() {
|
|
|
8799
9017
|
}
|
|
8800
9018
|
async function cmdUpgrade() {
|
|
8801
9019
|
const policyPath = process.argv[4] || DEFAULT_POLICY_PATH;
|
|
8802
|
-
if (!
|
|
9020
|
+
if (!fs2.existsSync(policyPath)) {
|
|
8803
9021
|
console.error(`No policy file found at ${policyPath}`);
|
|
8804
9022
|
console.error('Run "astrasync guard setup" first to create a policy.');
|
|
8805
9023
|
process.exit(1);
|
|
@@ -8827,13 +9045,13 @@ async function cmdUpgrade() {
|
|
|
8827
9045
|
prompt: (message) => prompt.question(message),
|
|
8828
9046
|
print: (message) => console.log(message),
|
|
8829
9047
|
writeConfig: async (filePath, content) => {
|
|
8830
|
-
const dir =
|
|
8831
|
-
if (!
|
|
8832
|
-
|
|
9048
|
+
const dir = path2.dirname(filePath);
|
|
9049
|
+
if (!fs2.existsSync(dir)) fs2.mkdirSync(dir, { recursive: true });
|
|
9050
|
+
fs2.writeFileSync(filePath, content, "utf-8");
|
|
8833
9051
|
},
|
|
8834
9052
|
readConfig: async (filePath) => {
|
|
8835
9053
|
try {
|
|
8836
|
-
return
|
|
9054
|
+
return fs2.readFileSync(filePath, "utf-8");
|
|
8837
9055
|
} catch {
|
|
8838
9056
|
return null;
|
|
8839
9057
|
}
|
|
@@ -8854,13 +9072,13 @@ async function cmdStart() {
|
|
|
8854
9072
|
let gatewayConfig;
|
|
8855
9073
|
const upgraded = await isUpgraded(DEFAULT_CONFIG_DIR, async (p) => {
|
|
8856
9074
|
try {
|
|
8857
|
-
return
|
|
9075
|
+
return fs2.readFileSync(p, "utf-8");
|
|
8858
9076
|
} catch {
|
|
8859
9077
|
return null;
|
|
8860
9078
|
}
|
|
8861
9079
|
});
|
|
8862
9080
|
if (upgraded) {
|
|
8863
|
-
const config = JSON.parse(
|
|
9081
|
+
const config = JSON.parse(fs2.readFileSync(`${DEFAULT_CONFIG_DIR}/config`, "utf-8"));
|
|
8864
9082
|
gatewayConfig = {
|
|
8865
9083
|
mode: config.mode,
|
|
8866
9084
|
apiBaseUrl: config.platformUrl ? `${config.platformUrl}/api/v1` : void 0,
|
|
@@ -8868,7 +9086,7 @@ async function cmdStart() {
|
|
|
8868
9086
|
};
|
|
8869
9087
|
console.log(`[AstraSync] Starting in ${config.mode} mode (agent: ${config.agentId})`);
|
|
8870
9088
|
} else {
|
|
8871
|
-
if (!
|
|
9089
|
+
if (!fs2.existsSync(policyPath)) {
|
|
8872
9090
|
console.error(`No policy file found at ${policyPath}`);
|
|
8873
9091
|
console.error('Run "astrasync guard setup" first.');
|
|
8874
9092
|
process.exit(1);
|
|
@@ -8905,7 +9123,7 @@ async function cmdStatus() {
|
|
|
8905
9123
|
const policyPath = process.argv[4] || DEFAULT_POLICY_PATH;
|
|
8906
9124
|
const upgraded = await isUpgraded(DEFAULT_CONFIG_DIR, async (p) => {
|
|
8907
9125
|
try {
|
|
8908
|
-
return
|
|
9126
|
+
return fs2.readFileSync(p, "utf-8");
|
|
8909
9127
|
} catch {
|
|
8910
9128
|
return null;
|
|
8911
9129
|
}
|
|
@@ -8915,7 +9133,7 @@ async function cmdStatus() {
|
|
|
8915
9133
|
console.log(` ${line}`);
|
|
8916
9134
|
}
|
|
8917
9135
|
if (upgraded) {
|
|
8918
|
-
const config = JSON.parse(
|
|
9136
|
+
const config = JSON.parse(fs2.readFileSync(`${DEFAULT_CONFIG_DIR}/config`, "utf-8"));
|
|
8919
9137
|
console.log(` Mode: ${config.mode}`);
|
|
8920
9138
|
console.log(` Agent: ${config.agentId}`);
|
|
8921
9139
|
console.log(` Platform: ${config.platformUrl}`);
|
|
@@ -8923,7 +9141,7 @@ async function cmdStatus() {
|
|
|
8923
9141
|
} else {
|
|
8924
9142
|
console.log(" Mode: local (free tier)");
|
|
8925
9143
|
}
|
|
8926
|
-
if (
|
|
9144
|
+
if (fs2.existsSync(policyPath)) {
|
|
8927
9145
|
const parsed = parseFile(policyPath);
|
|
8928
9146
|
if (parsed.validation.valid && parsed.policy) {
|
|
8929
9147
|
const p = parsed.policy;
|
|
@@ -8948,7 +9166,7 @@ async function cmdCheck() {
|
|
|
8948
9166
|
(a) => !a.startsWith("--") && a !== "guard" && a !== "check" && a !== process.argv[0] && a !== process.argv[1]
|
|
8949
9167
|
) || DEFAULT_POLICY_PATH;
|
|
8950
9168
|
const trigger = process.argv.find((a) => a.startsWith("--trigger="))?.split("=")[1] || "pre-push";
|
|
8951
|
-
if (!
|
|
9169
|
+
if (!fs2.existsSync(policyPath)) {
|
|
8952
9170
|
console.log("[AstraSync] No policy file \u2014 skipping check");
|
|
8953
9171
|
process.exit(0);
|
|
8954
9172
|
}
|
|
@@ -8960,9 +9178,9 @@ async function cmdCheck() {
|
|
|
8960
9178
|
}
|
|
8961
9179
|
let enforcement = "warn";
|
|
8962
9180
|
const configPath = `${DEFAULT_CONFIG_DIR}/config`;
|
|
8963
|
-
if (
|
|
9181
|
+
if (fs2.existsSync(configPath)) {
|
|
8964
9182
|
try {
|
|
8965
|
-
const config = JSON.parse(
|
|
9183
|
+
const config = JSON.parse(fs2.readFileSync(configPath, "utf-8"));
|
|
8966
9184
|
enforcement = config.gitTriggerEnforcement || "warn";
|
|
8967
9185
|
} catch {
|
|
8968
9186
|
}
|
|
@@ -9025,8 +9243,8 @@ async function cmdUninstallHooks() {
|
|
|
9025
9243
|
}
|
|
9026
9244
|
}
|
|
9027
9245
|
function resolveClaudeHookCommand() {
|
|
9028
|
-
const sibling =
|
|
9029
|
-
if (
|
|
9246
|
+
const sibling = path2.join(__dirname, "astrasync-claude-hook.js");
|
|
9247
|
+
if (fs2.existsSync(sibling)) {
|
|
9030
9248
|
return `"${process.execPath}" "${sibling}"`;
|
|
9031
9249
|
}
|
|
9032
9250
|
return "astrasync-claude-hook";
|
|
@@ -9042,19 +9260,19 @@ function parseClaudeCodeFlags() {
|
|
|
9042
9260
|
};
|
|
9043
9261
|
}
|
|
9044
9262
|
function claudeCodePaths(project) {
|
|
9045
|
-
const root = project ? process.cwd() :
|
|
9263
|
+
const root = project ? process.cwd() : os2.homedir();
|
|
9046
9264
|
return {
|
|
9047
|
-
settingsPath:
|
|
9048
|
-
astrasyncDir:
|
|
9265
|
+
settingsPath: path2.join(root, ".claude", "settings.json"),
|
|
9266
|
+
astrasyncDir: path2.join(root, ".astrasync")
|
|
9049
9267
|
};
|
|
9050
9268
|
}
|
|
9051
9269
|
async function cmdInstallClaudeCode() {
|
|
9052
9270
|
const flags = parseClaudeCodeFlags();
|
|
9053
9271
|
const { settingsPath, astrasyncDir } = claudeCodePaths(flags.project);
|
|
9054
|
-
const policyPath = flags.policyOverride ||
|
|
9055
|
-
const guardJsonPath =
|
|
9272
|
+
const policyPath = flags.policyOverride || path2.join(astrasyncDir, "policy.yaml");
|
|
9273
|
+
const guardJsonPath = path2.join(astrasyncDir, "guard.json");
|
|
9056
9274
|
console.log("\nAstraSync Local Guard for Claude Code \u2014 install\n");
|
|
9057
|
-
if (
|
|
9275
|
+
if (fs2.existsSync(policyPath)) {
|
|
9058
9276
|
console.log(` Policy: using existing ${policyPath}`);
|
|
9059
9277
|
if (ensureGuardSelfProtection(policyPath)) {
|
|
9060
9278
|
console.log(" added guard self-protection patterns to file.write");
|
|
@@ -9062,7 +9280,7 @@ async function cmdInstallClaudeCode() {
|
|
|
9062
9280
|
} else if (flags.wizard) {
|
|
9063
9281
|
const prompt = createPrompt();
|
|
9064
9282
|
try {
|
|
9065
|
-
|
|
9283
|
+
fs2.mkdirSync(path2.dirname(policyPath), { recursive: true });
|
|
9066
9284
|
const wizard = new SetupWizard(prompt);
|
|
9067
9285
|
await wizard.runAndSave(policyPath);
|
|
9068
9286
|
} finally {
|
|
@@ -9071,17 +9289,17 @@ async function cmdInstallClaudeCode() {
|
|
|
9071
9289
|
ensureGuardSelfProtection(policyPath);
|
|
9072
9290
|
console.log(` Policy: created via wizard at ${policyPath}`);
|
|
9073
9291
|
} else {
|
|
9074
|
-
|
|
9075
|
-
|
|
9292
|
+
fs2.mkdirSync(path2.dirname(policyPath), { recursive: true });
|
|
9293
|
+
fs2.writeFileSync(policyPath, toYaml(buildDefaultClaudeCodePolicy()), "utf-8");
|
|
9076
9294
|
console.log(` Policy: default coding-agent policy written to ${policyPath}`);
|
|
9077
9295
|
console.log(" (re-run with --wizard for the interactive setup instead)");
|
|
9078
9296
|
}
|
|
9079
|
-
if (!
|
|
9297
|
+
if (!fs2.existsSync(guardJsonPath)) {
|
|
9080
9298
|
const guardSettings = {
|
|
9081
9299
|
posture: flags.active ? "active" : "passive",
|
|
9082
9300
|
governMcp: false
|
|
9083
9301
|
};
|
|
9084
|
-
|
|
9302
|
+
fs2.writeFileSync(guardJsonPath, `${JSON.stringify(guardSettings, null, 2)}
|
|
9085
9303
|
`, "utf-8");
|
|
9086
9304
|
console.log(
|
|
9087
9305
|
` Guard: ${guardJsonPath} (posture: ${guardSettings.posture}, governMcp: false)`
|
|
@@ -9111,7 +9329,7 @@ async function cmdInstallClaudeCode() {
|
|
|
9111
9329
|
}
|
|
9112
9330
|
console.log("\n Next steps:");
|
|
9113
9331
|
console.log(" 1. Start a NEW Claude Code session (settings load at startup).");
|
|
9114
|
-
console.log(` 2. Watch decisions: tail -f ${
|
|
9332
|
+
console.log(` 2. Watch decisions: tail -f ${path2.join(astrasyncDir, "traces")}/*.jsonl`);
|
|
9115
9333
|
console.log(` 3. When the traces look right, set "posture": "active" in ${guardJsonPath}`);
|
|
9116
9334
|
console.log(" to enforce (denies block, approvals use Claude Code's own prompt).");
|
|
9117
9335
|
console.log(' 4. To govern MCP tools too, set "governMcp": true and add');
|
|
@@ -9141,26 +9359,26 @@ async function cmdUninstallClaudeCode() {
|
|
|
9141
9359
|
);
|
|
9142
9360
|
}
|
|
9143
9361
|
function resolveCodexHookCommand() {
|
|
9144
|
-
const sibling =
|
|
9145
|
-
if (
|
|
9362
|
+
const sibling = path2.join(__dirname, "astrasync-codex-hook.js");
|
|
9363
|
+
if (fs2.existsSync(sibling)) {
|
|
9146
9364
|
return `"${process.execPath}" "${sibling}"`;
|
|
9147
9365
|
}
|
|
9148
9366
|
return "astrasync-codex-hook";
|
|
9149
9367
|
}
|
|
9150
9368
|
function codexPaths(project) {
|
|
9151
|
-
const root = project ? process.cwd() :
|
|
9369
|
+
const root = project ? process.cwd() : os2.homedir();
|
|
9152
9370
|
return {
|
|
9153
|
-
hooksPath:
|
|
9154
|
-
astrasyncDir:
|
|
9371
|
+
hooksPath: path2.join(root, ".codex", "hooks.json"),
|
|
9372
|
+
astrasyncDir: path2.join(root, ".astrasync")
|
|
9155
9373
|
};
|
|
9156
9374
|
}
|
|
9157
9375
|
async function cmdInstallCodex() {
|
|
9158
9376
|
const flags = parseClaudeCodeFlags();
|
|
9159
9377
|
const { hooksPath, astrasyncDir } = codexPaths(flags.project);
|
|
9160
|
-
const policyPath = flags.policyOverride ||
|
|
9161
|
-
const guardJsonPath =
|
|
9378
|
+
const policyPath = flags.policyOverride || path2.join(astrasyncDir, "policy.yaml");
|
|
9379
|
+
const guardJsonPath = path2.join(astrasyncDir, "guard.json");
|
|
9162
9380
|
console.log("\nAstraSync Local Guard for Codex CLI \u2014 install\n");
|
|
9163
|
-
if (
|
|
9381
|
+
if (fs2.existsSync(policyPath)) {
|
|
9164
9382
|
console.log(` Policy: using existing ${policyPath} (shared across adapters)`);
|
|
9165
9383
|
if (ensureGuardSelfProtection(policyPath)) {
|
|
9166
9384
|
console.log(" added guard self-protection patterns to file.write");
|
|
@@ -9168,7 +9386,7 @@ async function cmdInstallCodex() {
|
|
|
9168
9386
|
} else if (flags.wizard) {
|
|
9169
9387
|
const prompt = createPrompt();
|
|
9170
9388
|
try {
|
|
9171
|
-
|
|
9389
|
+
fs2.mkdirSync(path2.dirname(policyPath), { recursive: true });
|
|
9172
9390
|
const wizard = new SetupWizard(prompt);
|
|
9173
9391
|
await wizard.runAndSave(policyPath);
|
|
9174
9392
|
} finally {
|
|
@@ -9177,17 +9395,17 @@ async function cmdInstallCodex() {
|
|
|
9177
9395
|
ensureGuardSelfProtection(policyPath);
|
|
9178
9396
|
console.log(` Policy: created via wizard at ${policyPath}`);
|
|
9179
9397
|
} else {
|
|
9180
|
-
|
|
9181
|
-
|
|
9398
|
+
fs2.mkdirSync(path2.dirname(policyPath), { recursive: true });
|
|
9399
|
+
fs2.writeFileSync(policyPath, toYaml(buildDefaultClaudeCodePolicy()), "utf-8");
|
|
9182
9400
|
console.log(` Policy: default coding-agent policy written to ${policyPath}`);
|
|
9183
9401
|
console.log(" (re-run with --wizard for the interactive setup instead)");
|
|
9184
9402
|
}
|
|
9185
|
-
if (!
|
|
9403
|
+
if (!fs2.existsSync(guardJsonPath)) {
|
|
9186
9404
|
const guardSettings = {
|
|
9187
9405
|
posture: flags.active ? "active" : "passive",
|
|
9188
9406
|
governMcp: false
|
|
9189
9407
|
};
|
|
9190
|
-
|
|
9408
|
+
fs2.writeFileSync(guardJsonPath, `${JSON.stringify(guardSettings, null, 2)}
|
|
9191
9409
|
`, "utf-8");
|
|
9192
9410
|
console.log(
|
|
9193
9411
|
` Guard: ${guardJsonPath} (posture: ${guardSettings.posture}, governMcp: false)`
|
|
@@ -9206,7 +9424,7 @@ async function cmdInstallCodex() {
|
|
|
9206
9424
|
}
|
|
9207
9425
|
console.log("\n Next steps:");
|
|
9208
9426
|
console.log(" 1. Start a NEW Codex session (hooks load at startup; /hooks to inspect).");
|
|
9209
|
-
console.log(` 2. Watch decisions: tail -f ${
|
|
9427
|
+
console.log(` 2. Watch decisions: tail -f ${path2.join(astrasyncDir, "traces")}/*.jsonl`);
|
|
9210
9428
|
console.log(` 3. When the traces look right, set "posture": "active" in ${guardJsonPath}.`);
|
|
9211
9429
|
console.log(" Denies block; approvals fall through to Codex's own prompt \u2014");
|
|
9212
9430
|
console.log(" except in dontAsk/bypassPermissions modes, where they deny.");
|
|
@@ -9231,13 +9449,13 @@ function printCodexStatus() {
|
|
|
9231
9449
|
const { hooksPath, astrasyncDir } = codexPaths(scope === "project");
|
|
9232
9450
|
let hookInstalled = false;
|
|
9233
9451
|
try {
|
|
9234
|
-
const content =
|
|
9452
|
+
const content = fs2.readFileSync(hooksPath, "utf-8");
|
|
9235
9453
|
hookInstalled = content.includes(ASTRASYNC_CODEX_HOOK_MARKER);
|
|
9236
9454
|
} catch {
|
|
9237
9455
|
}
|
|
9238
9456
|
if (hookInstalled) {
|
|
9239
|
-
const policyPath =
|
|
9240
|
-
const policy =
|
|
9457
|
+
const policyPath = path2.join(astrasyncDir, "policy.yaml");
|
|
9458
|
+
const policy = fs2.existsSync(policyPath) ? `policy: ${policyPath}` : "policy: missing";
|
|
9241
9459
|
console.log(` Codex CLI (${scope}): hook installed, ${policy}`);
|
|
9242
9460
|
}
|
|
9243
9461
|
}
|
|
@@ -9247,24 +9465,24 @@ function printClaudeCodeStatus() {
|
|
|
9247
9465
|
const { settingsPath, astrasyncDir } = claudeCodePaths(scope === "project");
|
|
9248
9466
|
let hookInstalled = false;
|
|
9249
9467
|
try {
|
|
9250
|
-
const content =
|
|
9468
|
+
const content = fs2.readFileSync(settingsPath, "utf-8");
|
|
9251
9469
|
hookInstalled = content.includes(ASTRASYNC_HOOK_MARKER);
|
|
9252
9470
|
} catch {
|
|
9253
9471
|
}
|
|
9254
|
-
const policyPath =
|
|
9255
|
-
const guardJsonPath =
|
|
9472
|
+
const policyPath = path2.join(astrasyncDir, "policy.yaml");
|
|
9473
|
+
const guardJsonPath = path2.join(astrasyncDir, "guard.json");
|
|
9256
9474
|
let posture = "";
|
|
9257
|
-
if (
|
|
9475
|
+
if (fs2.existsSync(guardJsonPath)) {
|
|
9258
9476
|
try {
|
|
9259
|
-
const settings = JSON.parse(
|
|
9477
|
+
const settings = JSON.parse(fs2.readFileSync(guardJsonPath, "utf-8"));
|
|
9260
9478
|
posture = settings.posture ? `, posture: ${settings.posture}` : "";
|
|
9261
9479
|
} catch {
|
|
9262
9480
|
posture = ", guard.json unreadable";
|
|
9263
9481
|
}
|
|
9264
9482
|
}
|
|
9265
|
-
if (hookInstalled ||
|
|
9483
|
+
if (hookInstalled || fs2.existsSync(policyPath)) {
|
|
9266
9484
|
const hook = hookInstalled ? "hook installed" : "hook NOT installed";
|
|
9267
|
-
const policy =
|
|
9485
|
+
const policy = fs2.existsSync(policyPath) ? `policy: ${policyPath}` : "policy: missing";
|
|
9268
9486
|
console.log(` Claude Code (${scope}): ${hook}, ${policy}${posture}`);
|
|
9269
9487
|
}
|
|
9270
9488
|
}
|
|
@@ -9310,14 +9528,21 @@ async function cmdFleetStatus() {
|
|
|
9310
9528
|
async function cmdBrowse() {
|
|
9311
9529
|
try {
|
|
9312
9530
|
const port = flagValue("--port");
|
|
9313
|
-
const
|
|
9531
|
+
const open = process.argv.includes("--open");
|
|
9532
|
+
const { proxy, openUrl } = await runBrowse(fleetPaths(), {
|
|
9314
9533
|
checkpoint: flagValue("--checkpoint") ?? "",
|
|
9315
9534
|
slug: flagValue("--slug") ?? "",
|
|
9316
9535
|
upstream: flagValue("--upstream"),
|
|
9317
9536
|
port: port ? Number(port) : void 0,
|
|
9318
|
-
extraHosts: flagValue("--host") ? [flagValue("--host")] : []
|
|
9537
|
+
extraHosts: flagValue("--host") ? [flagValue("--host")] : [],
|
|
9538
|
+
open
|
|
9319
9539
|
});
|
|
9540
|
+
if (open) openThroughProxy({ port: proxy.port, url: openUrl, certSpki: proxy.certSpki });
|
|
9541
|
+
let stopping = false;
|
|
9320
9542
|
const stop = async () => {
|
|
9543
|
+
if (stopping) process.exit(0);
|
|
9544
|
+
stopping = true;
|
|
9545
|
+
setTimeout(() => process.exit(0), 2e3).unref();
|
|
9321
9546
|
await proxy.close();
|
|
9322
9547
|
process.exit(0);
|
|
9323
9548
|
};
|
|
@@ -9352,7 +9577,7 @@ async function cmdGitRoute() {
|
|
|
9352
9577
|
}
|
|
9353
9578
|
async function cmdGitCredential() {
|
|
9354
9579
|
const action = process.argv[process.argv.indexOf("git-credential") + 1] ?? "";
|
|
9355
|
-
const input =
|
|
9580
|
+
const input = fs2.readFileSync(0, "utf-8");
|
|
9356
9581
|
process.stdout.write(runGitCredential(action, input));
|
|
9357
9582
|
}
|
|
9358
9583
|
async function cmdManagedSettings() {
|
|
@@ -9456,8 +9681,9 @@ async function main() {
|
|
|
9456
9681
|
" browse Sign an agent in to your dashboard from this machine and"
|
|
9457
9682
|
);
|
|
9458
9683
|
console.log(
|
|
9459
|
-
" run its device proxy (--checkpoint <url> --slug <agent
|
|
9684
|
+
" run its device proxy (--checkpoint <url> --slug <agent>;"
|
|
9460
9685
|
);
|
|
9686
|
+
console.log(" --open to start a browser through the proxy)");
|
|
9461
9687
|
console.log(" enroll <token> Enrol this machine in your organisation fleet");
|
|
9462
9688
|
console.log(" (--api-base-url <url>, --system for machine scope)");
|
|
9463
9689
|
console.log(" fleet-status Show fleet enrolment, signed policy and heartbeat");
|
|
@@ -9471,13 +9697,13 @@ async function main() {
|
|
|
9471
9697
|
process.exit(command ? 1 : 0);
|
|
9472
9698
|
}
|
|
9473
9699
|
}
|
|
9474
|
-
var
|
|
9700
|
+
var fs2, os2, path2, readline, DEFAULT_POLICY_PATH, DEFAULT_CONFIG_DIR;
|
|
9475
9701
|
var init_guard = __esm({
|
|
9476
9702
|
"src/cli/guard.ts"() {
|
|
9477
9703
|
"use strict";
|
|
9478
|
-
|
|
9479
|
-
|
|
9480
|
-
|
|
9704
|
+
fs2 = __toESM(require("fs"));
|
|
9705
|
+
os2 = __toESM(require("os"));
|
|
9706
|
+
path2 = __toESM(require("path"));
|
|
9481
9707
|
readline = __toESM(require("readline"));
|
|
9482
9708
|
init_wizard();
|
|
9483
9709
|
init_upgrade();
|
|
@@ -9491,6 +9717,7 @@ var init_guard = __esm({
|
|
|
9491
9717
|
init_enrolment_store();
|
|
9492
9718
|
init_git_route();
|
|
9493
9719
|
init_browse();
|
|
9720
|
+
init_open_browser();
|
|
9494
9721
|
DEFAULT_POLICY_PATH = "./local-policy.yaml";
|
|
9495
9722
|
DEFAULT_CONFIG_DIR = ".astrasync";
|
|
9496
9723
|
main().catch((err) => {
|
|
@@ -9527,6 +9754,7 @@ COMMANDS:
|
|
|
9527
9754
|
(--api-base-url <url>, --system for machine scope)
|
|
9528
9755
|
guard fleet-status Fleet enrolment, signed policy and heartbeat state
|
|
9529
9756
|
guard browse Sign an agent in to your dashboard via this machine's device proxy
|
|
9757
|
+
(--checkpoint <url> --slug <agent>; --open starts a browser through it)
|
|
9530
9758
|
guard managed-settings MDM templates for Claude Code / Codex (--claude, --codex, --out <dir>)
|
|
9531
9759
|
|
|
9532
9760
|
REGISTER OPTIONS:
|