airgate 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/airgate.mjs +70 -26
- package/package.json +1 -1
package/dist/airgate.mjs
CHANGED
|
@@ -130,6 +130,12 @@ var init_pack = __esm({
|
|
|
130
130
|
});
|
|
131
131
|
|
|
132
132
|
// ../sandbox/src/types.ts
|
|
133
|
+
var AIRLOCK_MODES = ["ask", "branches", "off"];
|
|
134
|
+
var AIRLOCK_MODE_INFO = {
|
|
135
|
+
ask: { name: "ask", line: "everything waits for you: pushes, pull requests, email, deploys, outside calls" },
|
|
136
|
+
branches: { name: "work branches go through", line: "pushes to work branches go through on their own; main, force pushes, pull requests, email and deploys still wait" },
|
|
137
|
+
off: { name: "off", line: "everything goes through on its own. it's all still recorded in the airlock, but nothing waits for you" }
|
|
138
|
+
};
|
|
133
139
|
var SIZES = {
|
|
134
140
|
small: { cpu: 8, memoryGb: 4, diskGb: 100 },
|
|
135
141
|
standard: { cpu: 8, memoryGb: 8, diskGb: 100 },
|
|
@@ -2914,12 +2920,12 @@ function typeIn(src, options) {
|
|
|
2914
2920
|
};
|
|
2915
2921
|
});
|
|
2916
2922
|
}
|
|
2917
|
-
function level(t, period2,
|
|
2923
|
+
function level(t, period2, mode2) {
|
|
2918
2924
|
const u = mod(t, period2) / period2;
|
|
2919
2925
|
const ease2 = (k) => smoothstep(0, 1, k);
|
|
2920
|
-
if (
|
|
2926
|
+
if (mode2 === "in")
|
|
2921
2927
|
return u < 0.4 ? ease2(u / 0.4) : 1;
|
|
2922
|
-
if (
|
|
2928
|
+
if (mode2 === "out")
|
|
2923
2929
|
return u < 0.6 ? 1 : 1 - ease2((u - 0.6) / 0.4);
|
|
2924
2930
|
return u < 0.3 ? ease2(u / 0.3) : u < 0.6 ? 1 : u < 0.9 ? 1 - ease2((u - 0.6) / 0.3) : 0;
|
|
2925
2931
|
}
|
|
@@ -2929,7 +2935,7 @@ var MODE_WHAT = { in: "in", out: "out", inout: "in and out" };
|
|
|
2929
2935
|
function dissolve(src, options) {
|
|
2930
2936
|
const o = optionsOf2(options, "dissolve", ["period", "mode", "blob", "edge", "seed"]);
|
|
2931
2937
|
const period2 = num(o.period, "dissolve.period", 6, "seconds");
|
|
2932
|
-
const
|
|
2938
|
+
const mode2 = choice(o.mode, "dissolve.mode", MODES, "inout");
|
|
2933
2939
|
const scale2 = 1 / num(o.blob, "dissolve.blob", 7, "atLeast1");
|
|
2934
2940
|
const auto = o.edge === void 0;
|
|
2935
2941
|
const edge = o.edge === "" ? "" : chars2(o.edge, "dissolve.edge", ".:", 1);
|
|
@@ -2947,10 +2953,10 @@ function dissolve(src, options) {
|
|
|
2947
2953
|
return {
|
|
2948
2954
|
moves: true,
|
|
2949
2955
|
period: period2,
|
|
2950
|
-
still: HELD[
|
|
2951
|
-
what: `dissolving ${MODE_WHAT[
|
|
2956
|
+
still: HELD[mode2] * period2,
|
|
2957
|
+
what: `dissolving ${MODE_WHAT[mode2]}`,
|
|
2952
2958
|
setup: () => (t, s2, g) => {
|
|
2953
|
-
const k = level(t, period2,
|
|
2959
|
+
const k = level(t, period2, mode2);
|
|
2954
2960
|
if (k >= 1)
|
|
2955
2961
|
return copy(s2, g);
|
|
2956
2962
|
const front = k * (1 + band);
|
|
@@ -2971,7 +2977,7 @@ function dissolve(src, options) {
|
|
|
2971
2977
|
function fade2(src, options) {
|
|
2972
2978
|
const o = optionsOf2(options, "fade", ["period", "mode", "ramp"]);
|
|
2973
2979
|
const period2 = num(o.period, "fade.period", 6, "seconds");
|
|
2974
|
-
const
|
|
2980
|
+
const mode2 = choice(o.mode, "fade.mode", MODES, "inout");
|
|
2975
2981
|
const auto = o.ramp === void 0 || o.ramp === "auto";
|
|
2976
2982
|
const chars3 = ramp(auto ? "standard" : o.ramp);
|
|
2977
2983
|
if (chars3[0] !== " ")
|
|
@@ -2982,8 +2988,8 @@ function fade2(src, options) {
|
|
|
2982
2988
|
return build2("fade", src, o, () => ({
|
|
2983
2989
|
moves: true,
|
|
2984
2990
|
period: period2,
|
|
2985
|
-
still: HELD[
|
|
2986
|
-
what: `fading ${MODE_WHAT[
|
|
2991
|
+
still: HELD[mode2] * period2,
|
|
2992
|
+
what: `fading ${MODE_WHAT[mode2]}`,
|
|
2987
2993
|
setup: () => {
|
|
2988
2994
|
const steps = /* @__PURE__ */ new Map();
|
|
2989
2995
|
const stepsOf = (c) => {
|
|
@@ -2996,7 +3002,7 @@ function fade2(src, options) {
|
|
|
2996
3002
|
return v;
|
|
2997
3003
|
};
|
|
2998
3004
|
return (t, s2, g) => {
|
|
2999
|
-
const k = level(t, period2,
|
|
3005
|
+
const k = level(t, period2, mode2);
|
|
3000
3006
|
if (k >= 1)
|
|
3001
3007
|
return copy(s2, g);
|
|
3002
3008
|
for (let y = 0, i = 0; y < g.rows; y++)
|
|
@@ -7070,7 +7076,7 @@ function approvalRows(ctx, items, names) {
|
|
|
7070
7076
|
ctx.ui.c(a.state === "pending" ? "warn" : a.state === "denied" || a.state === "failed" ? "bad" : "ok", a.state),
|
|
7071
7077
|
a.kind,
|
|
7072
7078
|
names.get(a.podId) ?? (a.requestedBy ? `${a.requestedBy}'s pod` : a.podId),
|
|
7073
|
-
a.summary + (a.requestedBy ? ctx.ui.c("dim", ` \xB7 from ${a.requestedBy}`) : "") + (a.needsApprover && a.state === "pending" && !a.requestedBy ? ctx.ui.c("warn", " \xB7 waits for an approver") : ""),
|
|
7079
|
+
a.summary + (a.auto ? ctx.ui.c("dim", ` \xB7 went through on its own (${a.auto})`) : "") + (a.requestedBy ? ctx.ui.c("dim", ` \xB7 from ${a.requestedBy}`) : "") + (a.needsApprover && a.state === "pending" && !a.requestedBy ? ctx.ui.c("warn", " \xB7 waits for an approver") : ""),
|
|
7074
7080
|
ago(a.createdAt),
|
|
7075
7081
|
ctx.ui.c("dim", a.id)
|
|
7076
7082
|
]);
|
|
@@ -7083,12 +7089,21 @@ var airlock = {
|
|
|
7083
7089
|
name: "airlock",
|
|
7084
7090
|
aliases: ["approvals"],
|
|
7085
7091
|
group: "airlock \xB7 mask",
|
|
7086
|
-
usage: "[--watch]",
|
|
7087
|
-
summary: "what your pods want to send out: pending first, then recent",
|
|
7088
|
-
example: "airgate airlock
|
|
7089
|
-
notes: [
|
|
7090
|
-
|
|
7092
|
+
usage: "[--watch] | mode [ask|branches|off|account] [--pod p]",
|
|
7093
|
+
summary: "what your pods want to send out: pending first, then recent \xB7 how strict it is",
|
|
7094
|
+
example: "airgate airlock mode branches",
|
|
7095
|
+
notes: [
|
|
7096
|
+
"--watch follows the live stream and prints each new request as it arrives; ctrl-c to stop.",
|
|
7097
|
+
"mode: how much waits for you, like Claude Code's permission modes. ask (the default): everything waits. branches: pushes to work branches go through on their own; main, force pushes, pull requests, email and deploys still wait. off: everything goes through, still recorded.",
|
|
7098
|
+
"mode with --pod sets one pod's own mode (account: back to the account's). a team's approver rules always win."
|
|
7099
|
+
],
|
|
7100
|
+
flags: {
|
|
7101
|
+
watch: { type: "boolean", short: "w", help: "follow new requests" },
|
|
7102
|
+
pod: { type: "string", value: "pod", help: "with mode: this pod only" }
|
|
7103
|
+
},
|
|
7091
7104
|
async run(ctx) {
|
|
7105
|
+
if (ctx.args.positionals[0] === "mode") return mode(ctx);
|
|
7106
|
+
if (ctx.args.positionals.length) throw new UsageError("airgate airlock [--watch] | airgate airlock mode [ask|branches|off]");
|
|
7092
7107
|
if (bool(ctx.args, "watch")) return watch(ctx);
|
|
7093
7108
|
const [items, names] = await Promise.all([ctx.api.approvals(), podNames(ctx)]);
|
|
7094
7109
|
const pending = items.filter((a) => a.state === "pending").sort((a, b2) => a.createdAt - b2.createdAt);
|
|
@@ -7107,6 +7122,30 @@ var airlock = {
|
|
|
7107
7122
|
}
|
|
7108
7123
|
}
|
|
7109
7124
|
};
|
|
7125
|
+
async function mode(ctx) {
|
|
7126
|
+
const want = ctx.args.positionals[1];
|
|
7127
|
+
const podRef = str(ctx.args, "pod");
|
|
7128
|
+
if (want && !AIRLOCK_MODES.includes(want) && !(podRef && want === "account")) {
|
|
7129
|
+
throw new UsageError(`${AIRLOCK_MODES.join(", ")}${podRef ? " or account" : ""}`, "airgate airlock mode branches");
|
|
7130
|
+
}
|
|
7131
|
+
const account = (await ctx.api.me()).user.airlockMode ?? "ask";
|
|
7132
|
+
const say = (who, m2, own) => {
|
|
7133
|
+
ctx.ui.out(`${who}: ${m2 === "off" ? ctx.ui.c("warn", AIRLOCK_MODE_INFO[m2].name) : AIRLOCK_MODE_INFO[m2].name}${own ? "" : ctx.ui.c("dim", " (the account's)")}`);
|
|
7134
|
+
ctx.ui.out(ctx.ui.c("dim", ` ${AIRLOCK_MODE_INFO[m2].line}`));
|
|
7135
|
+
if (m2 === "off") ctx.ui.err(ctx.ui.ce("warn", " nothing waits: an agent's push to main, a pull request or an email goes out on its own"));
|
|
7136
|
+
};
|
|
7137
|
+
if (podRef) {
|
|
7138
|
+
let pod = await resolvePod(ctx, podRef);
|
|
7139
|
+
if (want) pod = await ctx.api.updatePod(pod.id, { airlock: want === "account" ? null : want });
|
|
7140
|
+
const m2 = pod.spec.airlock ?? account;
|
|
7141
|
+
if (ctx.json) return ctx.ui.json({ pod: pod.spec.name, mode: m2, own: Boolean(pod.spec.airlock) });
|
|
7142
|
+
return say(pod.spec.name, m2, Boolean(pod.spec.airlock));
|
|
7143
|
+
}
|
|
7144
|
+
const m = want ? (await ctx.api.updateMe({ airlockMode: want })).user.airlockMode ?? want : account;
|
|
7145
|
+
if (ctx.json) return ctx.ui.json({ mode: m });
|
|
7146
|
+
say("airlock", m, true);
|
|
7147
|
+
if (!want) ctx.ui.out(ctx.ui.c("dim", ` change it: airgate airlock mode ${AIRLOCK_MODES.join("|")} \xB7 one pod: --pod <p>`));
|
|
7148
|
+
}
|
|
7110
7149
|
async function watch(ctx) {
|
|
7111
7150
|
const seen = /* @__PURE__ */ new Set();
|
|
7112
7151
|
let first = true;
|
|
@@ -7562,7 +7601,7 @@ import { rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
|
7562
7601
|
import { resolve as resolve4 } from "node:path";
|
|
7563
7602
|
|
|
7564
7603
|
// src/version.ts
|
|
7565
|
-
var VERSION = "0.2.
|
|
7604
|
+
var VERSION = "0.2.4";
|
|
7566
7605
|
|
|
7567
7606
|
// src/commands/team.ts
|
|
7568
7607
|
async function checkSimilar(ctx, task2) {
|
|
@@ -8136,6 +8175,7 @@ var launch = {
|
|
|
8136
8175
|
env: { type: "string", value: "file", help: "a .env file: its keys become this pod's secrets before it boots" },
|
|
8137
8176
|
"public-repo": { type: "boolean", help: "the repo is public: don't check it against your GitHub App" },
|
|
8138
8177
|
mask: { type: "boolean", default: true, help: "mask model traffic (--no-mask to turn off)" },
|
|
8178
|
+
airlock: { type: "string", value: "mode", choices: AIRLOCK_MODES, help: "this pod's airlock: ask | branches | off (default: your account's, see airgate airlock mode)" },
|
|
8139
8179
|
undo: { type: "boolean", default: true, help: "checkpoint after every agent step (--no-undo to turn off)" },
|
|
8140
8180
|
network: { type: "string", value: "policy", choices: NETWORK_NAMES, default: "allowlist", help: "allowlist | open | off" },
|
|
8141
8181
|
allow: { type: "list", value: "host", help: "extra hosts for the allowlist (repeatable, or comma-separated)" },
|
|
@@ -8255,6 +8295,8 @@ function specFromFlags(ctx, defaults = {}) {
|
|
|
8255
8295
|
if (jobs2.length) spec.jobs = jobs2;
|
|
8256
8296
|
if (builtin) spec.builtinModel = true;
|
|
8257
8297
|
if (builtin && model) spec.model = model;
|
|
8298
|
+
const airlockMode = str(a, "airlock");
|
|
8299
|
+
if (airlockMode) spec.airlock = airlockMode;
|
|
8258
8300
|
return spec;
|
|
8259
8301
|
}
|
|
8260
8302
|
var info = {
|
|
@@ -8278,6 +8320,7 @@ var info = {
|
|
|
8278
8320
|
["network", s2.network + (s2.network === "allowlist" && s2.allow?.length ? ` \xB7 ${s2.allow.join(", ")}` : "")],
|
|
8279
8321
|
["mask", s2.masking ? `on${s2.maskTerms?.length ? ` \xB7 ${s2.maskTerms.length} terms` : ""}` : ctx.ui.c("warn", "off")],
|
|
8280
8322
|
["undo", s2.autoCheckpoint ? "auto checkpoints" : "manual only"],
|
|
8323
|
+
["airlock", s2.airlock ? s2.airlock === "off" ? ctx.ui.c("warn", AIRLOCK_MODE_INFO.off.name) : AIRLOCK_MODE_INFO[s2.airlock].name : "as the account"],
|
|
8281
8324
|
["auto-stop", s2.autoStopMinutes === 0 ? "keep awake (never sleeps: every hour counts, ~720 a month)" : `sleeps after ${s2.autoStopMinutes ?? 10} min idle`]
|
|
8282
8325
|
];
|
|
8283
8326
|
if (s2.repo) rows2.push(["repo", s2.repo]);
|
|
@@ -10675,17 +10718,18 @@ var TOOLS = [
|
|
|
10675
10718
|
},
|
|
10676
10719
|
{
|
|
10677
10720
|
name: "pod_settings",
|
|
10678
|
-
description: "Change a pod's network after launch (open | allowlist | off, extra allowlist hosts)
|
|
10679
|
-
inputSchema: obj({ pod: POD, network: s("open | allowlist | off", { enum: ["open", "allowlist", "off"] }), allow: { type: "array", items: { type: "string" }, description: "extra allowlist hosts (replaces the list)" }, aiOff: b("true switches the pod's AI off; false back on") }, ["pod"]),
|
|
10721
|
+
description: "Change a pod's network after launch (open | allowlist | off, extra allowlist hosts), switch its AI off/on (aiOff: no model calls at all), or set its airlock (ask | branches | off | account). Applies immediately. Only when the user asked for it; never loosen the airlock on your own.",
|
|
10722
|
+
inputSchema: obj({ pod: POD, network: s("open | allowlist | off", { enum: ["open", "allowlist", "off"] }), allow: { type: "array", items: { type: "string" }, description: "extra allowlist hosts (replaces the list)" }, aiOff: b("true switches the pod's AI off; false back on"), airlock: s("ask (everything waits) | branches (pushes to work branches go through) | off (nothing waits) | account (the account's mode)", { enum: ["ask", "branches", "off", "account"] }) }, ["pod"]),
|
|
10680
10723
|
async call(ctx, a) {
|
|
10681
10724
|
const p = await resolvePod(ctx, need(a, "pod"));
|
|
10682
10725
|
const patch = {};
|
|
10683
10726
|
if (typeof a.network === "string") patch.network = a.network;
|
|
10684
10727
|
if (Array.isArray(a.allow)) patch.allow = a.allow.map(String);
|
|
10685
10728
|
if (typeof a.aiOff === "boolean") patch.aiOff = a.aiOff;
|
|
10686
|
-
if (
|
|
10729
|
+
if (typeof a.airlock === "string") patch.airlock = a.airlock === "account" ? null : a.airlock;
|
|
10730
|
+
if (!Object.keys(patch).length) throw new UsageError("nothing to change: network, allow, aiOff or airlock");
|
|
10687
10731
|
const pod = await ctx.api.updatePod(p.id, patch);
|
|
10688
|
-
return { name: pod.spec.name, network: pod.spec.network, allow: pod.spec.allow ?? [], aiOff: Boolean(pod.spec.aiOff) };
|
|
10732
|
+
return { name: pod.spec.name, network: pod.spec.network, allow: pod.spec.allow ?? [], aiOff: Boolean(pod.spec.aiOff), airlock: pod.spec.airlock ?? "account" };
|
|
10689
10733
|
}
|
|
10690
10734
|
},
|
|
10691
10735
|
{
|
|
@@ -12890,16 +12934,16 @@ var network = {
|
|
|
12890
12934
|
remove: { type: "string", value: "host", help: "remove hosts (comma separated)" }
|
|
12891
12935
|
},
|
|
12892
12936
|
async run(ctx) {
|
|
12893
|
-
const [ref,
|
|
12937
|
+
const [ref, mode2] = ctx.args.positionals;
|
|
12894
12938
|
if (!ref) throw new UsageError("airgate network <pod> [open|allowlist|off]");
|
|
12895
|
-
if (
|
|
12939
|
+
if (mode2 && !["open", "allowlist", "off"].includes(mode2)) throw new UsageError("open, allowlist or off");
|
|
12896
12940
|
const pod = await resolvePod(ctx, ref);
|
|
12897
12941
|
const list2 = (v) => (v ?? "").split(",").map((h) => h.trim().toLowerCase()).filter(Boolean);
|
|
12898
12942
|
let allow = pod.spec.allow ?? [];
|
|
12899
12943
|
if (str(ctx.args, "allow") !== void 0) allow = list2(str(ctx.args, "allow"));
|
|
12900
12944
|
allow = [.../* @__PURE__ */ new Set([...allow, ...list2(str(ctx.args, "add"))])].filter((h) => !list2(str(ctx.args, "remove")).includes(h));
|
|
12901
|
-
const changed =
|
|
12902
|
-
const p = changed ? await ctx.api.updatePod(pod.id, { ...
|
|
12945
|
+
const changed = mode2 || ["allow", "add", "remove"].some((k) => str(ctx.args, k) !== void 0);
|
|
12946
|
+
const p = changed ? await ctx.api.updatePod(pod.id, { ...mode2 ? { network: mode2 } : {}, allow }) : pod;
|
|
12903
12947
|
if (ctx.json) return ctx.ui.json({ network: p.spec.network, allow: p.spec.allow ?? [], aiOff: Boolean(p.spec.aiOff) });
|
|
12904
12948
|
ctx.ui.out(`${p.spec.name}: ${p.spec.network}${p.spec.network === "allowlist" && (p.spec.allow ?? []).length ? ` + ${(p.spec.allow ?? []).join(", ")}` : ""}${p.spec.aiOff ? ctx.ui.c("warn", " \xB7 AI off") : ""}${changed ? ctx.ui.c("dim", " (applied now)") : ""}`);
|
|
12905
12949
|
}
|