promigence 0.1.0-beta.12
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/NOTICE +14 -0
- package/README.md +88 -0
- package/dist/account.js +850 -0
- package/dist/agent.js +374 -0
- package/dist/argv.js +159 -0
- package/dist/bin.js +332 -0
- package/dist/bundle.js +133 -0
- package/dist/capacity.js +69 -0
- package/dist/commands.d.ts +110 -0
- package/dist/commands.js +2675 -0
- package/dist/connectreq.js +125 -0
- package/dist/credfile.js +188 -0
- package/dist/credits.js +197 -0
- package/dist/devcontainer.d.ts +99 -0
- package/dist/devcontainer.js +744 -0
- package/dist/device.js +129 -0
- package/dist/dirsnap.js +378 -0
- package/dist/errfix.js +262 -0
- package/dist/generated.d.ts +35 -0
- package/dist/generated.js +307 -0
- package/dist/github.js +307 -0
- package/dist/gitlab.js +210 -0
- package/dist/guide.d.ts +19 -0
- package/dist/guide.js +366 -0
- package/dist/handlers.js +511 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +7 -0
- package/dist/init.d.ts +40 -0
- package/dist/init.js +352 -0
- package/dist/install.d.ts +23 -0
- package/dist/install.js +127 -0
- package/dist/io.d.ts +37 -0
- package/dist/io.js +318 -0
- package/dist/live.js +469 -0
- package/dist/login.js +1063 -0
- package/dist/mcp.js +889 -0
- package/dist/money.js +5 -0
- package/dist/orgs.js +475 -0
- package/dist/pricing.d.ts +52 -0
- package/dist/pricing.js +181 -0
- package/dist/report.js +132 -0
- package/dist/routes.js +135 -0
- package/dist/runners-github.js +257 -0
- package/dist/runners-gitlab.js +125 -0
- package/dist/runners-spec.js +137 -0
- package/dist/runners.js +1458 -0
- package/dist/sdk/blake3.d.ts +10 -0
- package/dist/sdk/blake3.js +111 -0
- package/dist/sdk/bundle.d.ts +96 -0
- package/dist/sdk/bundle.js +227 -0
- package/dist/sdk/ca-guard.js +166 -0
- package/dist/sdk/caller.d.ts +73 -0
- package/dist/sdk/caller.js +47 -0
- package/dist/sdk/client.d.ts +3015 -0
- package/dist/sdk/client.js +2583 -0
- package/dist/sdk/command-errors.d.ts +41 -0
- package/dist/sdk/command-errors.js +36 -0
- package/dist/sdk/context.d.ts +119 -0
- package/dist/sdk/context.js +588 -0
- package/dist/sdk/core.d.ts +285 -0
- package/dist/sdk/core.js +266 -0
- package/dist/sdk/credstore.d.ts +90 -0
- package/dist/sdk/credstore.js +206 -0
- package/dist/sdk/dispatcher.js +86 -0
- package/dist/sdk/github.d.ts +158 -0
- package/dist/sdk/github.js +78 -0
- package/dist/sdk/gitlab.d.ts +104 -0
- package/dist/sdk/gitlab.js +20 -0
- package/dist/sdk/handles.d.ts +82 -0
- package/dist/sdk/handles.js +135 -0
- package/dist/sdk/hint.js +7 -0
- package/dist/sdk/http2.js +1921 -0
- package/dist/sdk/index.d.ts +34 -0
- package/dist/sdk/index.js +15 -0
- package/dist/sdk/keyed.gen.js +7 -0
- package/dist/sdk/models.gen.d.ts +6162 -0
- package/dist/sdk/models.gen.js +1 -0
- package/dist/sdk/proxy.js +249 -0
- package/dist/sdk/pty.d.ts +171 -0
- package/dist/sdk/pty.js +496 -0
- package/dist/sdk/sandbox.d.ts +537 -0
- package/dist/sdk/sandbox.js +725 -0
- package/dist/sdk/ssh.d.ts +25 -0
- package/dist/sdk/ssh.js +114 -0
- package/dist/sdk/trace.js +80 -0
- package/dist/sdk/transport-worker.js +466 -0
- package/dist/sdk/warm.js +40 -0
- package/dist/ssh.js +267 -0
- package/dist/surface.d.ts +95 -0
- package/dist/surface.js +1452 -0
- package/dist/templates.js +53 -0
- package/dist/term.js +50 -0
- package/dist/timing.js +71 -0
- package/dist/untar.js +324 -0
- package/dist/uploadguard.js +75 -0
- package/llms.txt +209 -0
- package/package.json +52 -0
package/dist/sdk/warm.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { isIP } from "node:net";
|
|
2
|
+
import { DEFAULT_API_URL } from "./core.js";
|
|
3
|
+
import { PromigenceClient, isKeyedCreate, newIdempotencyKey, serverAppMs } from "./client.js";
|
|
4
|
+
import { warmTransport } from "./http2.js";
|
|
5
|
+
import { Sandbox } from "./sandbox.js";
|
|
6
|
+
import { untraced } from "./trace.js";
|
|
7
|
+
function quietly(f) {
|
|
8
|
+
try {
|
|
9
|
+
const r = f();
|
|
10
|
+
if (r instanceof Promise)
|
|
11
|
+
r.catch(() => { });
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export function warmUp() {
|
|
17
|
+
try {
|
|
18
|
+
untraced(() => {
|
|
19
|
+
quietly(() => newIdempotencyKey());
|
|
20
|
+
quietly(() => isKeyedCreate("POST", "/runs?wait_ms=1"));
|
|
21
|
+
quietly(() => serverAppMs("app;dur=1.00"));
|
|
22
|
+
quietly(() => warmTransport());
|
|
23
|
+
quietly(() => { isIP("a.b"); isIP("a.b"); });
|
|
24
|
+
let client;
|
|
25
|
+
quietly(() => { client = new PromigenceClient({ apiKey: "warm", apiUrl: DEFAULT_API_URL }); });
|
|
26
|
+
if (client === undefined)
|
|
27
|
+
return;
|
|
28
|
+
const c = client;
|
|
29
|
+
quietly(() => c.request(undefined));
|
|
30
|
+
quietly(() => c.runs.start(undefined));
|
|
31
|
+
quietly(() => c.sandboxes.exec("sbx_0", undefined));
|
|
32
|
+
quietly(() => Sandbox.create({ client: c, tier: "small" }));
|
|
33
|
+
quietly(() => Sandbox.forkHandlesWith("", undefined, {}));
|
|
34
|
+
const make = Sandbox;
|
|
35
|
+
quietly(() => new make({ sandboxId: "sbx_0", runId: "run_0", snapshot: "", client: c }).commands.run("", null));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
}
|
|
40
|
+
}
|
package/dist/ssh.js
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
2
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { isIP } from "node:net";
|
|
4
|
+
import { delimiter, join, resolve } from "node:path";
|
|
5
|
+
import { PromigenceClient, PromigenceError, configDir } from "./sdk/index.js";
|
|
6
|
+
import { bool, client, clientOpts, nexts, positional, str } from "./commands.js";
|
|
7
|
+
import { emit, exitWith, okEnvelope, recordNotice, usageError, write } from "./io.js";
|
|
8
|
+
import { sh, shellArg } from "./term.js";
|
|
9
|
+
const SANDBOX_ID = /^[A-Za-z0-9][A-Za-z0-9_-]{0,127}$/;
|
|
10
|
+
const SSH_USER = /^[a-z_][a-z0-9_-]{0,31}$/;
|
|
11
|
+
const HOST_LABEL = /^[A-Za-z0-9_](?:[A-Za-z0-9_-]{0,61}[A-Za-z0-9_])?$/;
|
|
12
|
+
export function validSshHost(host) {
|
|
13
|
+
if (isIP(host) !== 0)
|
|
14
|
+
return true;
|
|
15
|
+
if (host.length === 0 || host.length > 253)
|
|
16
|
+
return false;
|
|
17
|
+
return host.split(".").every((label) => HOST_LABEL.test(label));
|
|
18
|
+
}
|
|
19
|
+
export const validSshUser = (user) => SSH_USER.test(user);
|
|
20
|
+
export function sshSandboxId(sid) {
|
|
21
|
+
if (!SANDBOX_ID.test(sid)) {
|
|
22
|
+
throw usageError(`'${sid}' is not a sandbox id`, "Pass the id as the API shows it, e.g. promigence sandbox ssh sbx_01 (see promigence sandbox list).");
|
|
23
|
+
}
|
|
24
|
+
return sid;
|
|
25
|
+
}
|
|
26
|
+
function badAccess(what) {
|
|
27
|
+
return new PromigenceError({
|
|
28
|
+
code: "internal",
|
|
29
|
+
message: `the API's ssh access answer has ${what}; nothing was written or run`,
|
|
30
|
+
fix: "Not your fault. Check PROMIGENCE_API_URL points at the Promigence API; if it does, report it with promigence --version.",
|
|
31
|
+
exitCode: 1,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export function checkSshAccess(access) {
|
|
35
|
+
if (typeof access.host !== "string" || !validSshHost(access.host))
|
|
36
|
+
throw badAccess("a host that is not a hostname or an address");
|
|
37
|
+
if (typeof access.user !== "string" || !validSshUser(access.user))
|
|
38
|
+
throw badAccess("a login name outside [a-z_][a-z0-9_-]");
|
|
39
|
+
for (const [name, v] of [["host key", access.host_key], ["access credential", access.token]]) {
|
|
40
|
+
if (typeof v !== "string" || v.trim() === "" || /[\r\n\0]/.test(v))
|
|
41
|
+
throw badAccess(`a ${name} that is empty or spans lines`);
|
|
42
|
+
}
|
|
43
|
+
return access;
|
|
44
|
+
}
|
|
45
|
+
export const sshDir = (sandboxId) => join(configDir(), "ssh", sandboxId);
|
|
46
|
+
const paths = (sandboxId) => {
|
|
47
|
+
const dir = sshDir(sandboxId);
|
|
48
|
+
return {
|
|
49
|
+
dir,
|
|
50
|
+
keyPath: join(dir, "id_ed25519"),
|
|
51
|
+
knownHosts: join(dir, "known_hosts"),
|
|
52
|
+
tokenPath: join(dir, "token"),
|
|
53
|
+
apiUrlPath: join(dir, "api_url"),
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
function ensureKey(p) {
|
|
57
|
+
mkdirSync(p.dir, { recursive: true, mode: 0o700 });
|
|
58
|
+
chmodSync(p.dir, 0o700);
|
|
59
|
+
if (!existsSync(`${p.keyPath}.pub`)) {
|
|
60
|
+
rmSync(p.keyPath, { force: true });
|
|
61
|
+
const r = spawnSync("ssh-keygen", ["-q", "-t", "ed25519", "-N", "", "-C", "promigence", "-f", p.keyPath], { stdio: ["ignore", "ignore", "pipe"] });
|
|
62
|
+
if (r.status !== 0) {
|
|
63
|
+
throw usageError(`ssh-keygen failed: ${String(r.stderr ?? "").trim() || "not found"}`, "Install OpenSSH (`ssh-keygen` must be on PATH), or pass --key PATH to use a key you already have.");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return readFileSync(`${p.keyPath}.pub`, "utf8").trim();
|
|
67
|
+
}
|
|
68
|
+
async function open(ctx, sandboxId) {
|
|
69
|
+
const local = paths(sandboxId);
|
|
70
|
+
const keyFlag = str(ctx, "--key");
|
|
71
|
+
let publicKey;
|
|
72
|
+
if (keyFlag) {
|
|
73
|
+
const pub = keyFlag.endsWith(".pub") ? keyFlag : `${keyFlag}.pub`;
|
|
74
|
+
if (!existsSync(pub)) {
|
|
75
|
+
throw usageError(`no public key at ${pub}`, "Pass --key PATH pointing at an ssh-ed25519 private key; its .pub must be beside it.");
|
|
76
|
+
}
|
|
77
|
+
publicKey = readFileSync(pub, "utf8").trim();
|
|
78
|
+
local.keyPath = resolve(pub.replace(/\.pub$/, ""));
|
|
79
|
+
mkdirSync(local.dir, { recursive: true, mode: 0o700 });
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
publicKey = ensureKey(local);
|
|
83
|
+
}
|
|
84
|
+
const ttl = str(ctx, "--ttl");
|
|
85
|
+
const idle = str(ctx, "--idle");
|
|
86
|
+
const num = (v, flag) => {
|
|
87
|
+
if (v === undefined)
|
|
88
|
+
return undefined;
|
|
89
|
+
const n = Number(v);
|
|
90
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
91
|
+
throw usageError(`${flag} must be a number of seconds`, `e.g. ${flag} 900.`);
|
|
92
|
+
return Math.floor(n);
|
|
93
|
+
};
|
|
94
|
+
const c = client(ctx);
|
|
95
|
+
const access = checkSshAccess(await c.sandboxes.ssh.open(sandboxId, {
|
|
96
|
+
publicKey,
|
|
97
|
+
...(num(ttl, "--ttl") === undefined ? {} : { ttlS: num(ttl, "--ttl") }),
|
|
98
|
+
...(num(idle, "--idle") === undefined ? {} : { idleTimeoutS: num(idle, "--idle") }),
|
|
99
|
+
}));
|
|
100
|
+
writeFileSync(local.knownHosts, `${access.host} ${access.host_key}\n`, { mode: 0o600 });
|
|
101
|
+
writeFileSync(local.tokenPath, `${access.token}\n`, { mode: 0o600 });
|
|
102
|
+
chmodSync(local.tokenPath, 0o600);
|
|
103
|
+
writeFileSync(local.apiUrlPath, `${c.apiUrl}\n`, { mode: 0o600 });
|
|
104
|
+
return { access, local };
|
|
105
|
+
}
|
|
106
|
+
export const winArg = (value) => /^[A-Za-z0-9_.:\\/@,=-]+$/.test(value) ? value : `"${value.replace(/"/g, '\\"')}"`;
|
|
107
|
+
const configPath = (path, platform) => platform === "win32" || /\s/.test(path) ? `"${path}"` : path;
|
|
108
|
+
export const proxyCommand = (self, sandboxId, platform = process.platform) => `${self} sandbox ssh ${platform === "win32" ? winArg(sandboxId) : shellArg(sandboxId)} --proxy`;
|
|
109
|
+
function sshArgs(sid, local, self, platform = process.platform) {
|
|
110
|
+
return [
|
|
111
|
+
"-i",
|
|
112
|
+
local.keyPath,
|
|
113
|
+
"-o",
|
|
114
|
+
"IdentitiesOnly=yes",
|
|
115
|
+
"-o",
|
|
116
|
+
`UserKnownHostsFile=${configPath(local.knownHosts, platform)}`,
|
|
117
|
+
"-o",
|
|
118
|
+
"StrictHostKeyChecking=yes",
|
|
119
|
+
"-o",
|
|
120
|
+
`ProxyCommand=${proxyCommand(self, sid, platform)}`,
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
export function selfCommand(platform = process.platform, argv1 = process.argv[1] ?? "", execPath = process.execPath) {
|
|
124
|
+
if (platform === "win32")
|
|
125
|
+
return `"${execPath}" "${argv1}"`;
|
|
126
|
+
if (/promigence$/.test(argv1) && !argv1.endsWith(".js") && onPathIsThis(argv1))
|
|
127
|
+
return "promigence";
|
|
128
|
+
return `${shellArg(execPath)} ${shellArg(argv1)}`;
|
|
129
|
+
}
|
|
130
|
+
function onPathIsThis(self) {
|
|
131
|
+
try {
|
|
132
|
+
const mine = realpathSync(self);
|
|
133
|
+
for (const dir of (process.env["PATH"] ?? "").split(delimiter)) {
|
|
134
|
+
if (!dir)
|
|
135
|
+
continue;
|
|
136
|
+
const cand = join(dir, "promigence");
|
|
137
|
+
if (existsSync(cand))
|
|
138
|
+
return realpathSync(cand) === mine;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
export const configBlock = (sid, access, local, self, platform = process.platform) => [
|
|
146
|
+
`Host ${access.host}`,
|
|
147
|
+
` User ${access.user}`,
|
|
148
|
+
` IdentityFile ${configPath(local.keyPath, platform)}`,
|
|
149
|
+
` IdentitiesOnly yes`,
|
|
150
|
+
` UserKnownHostsFile ${configPath(local.knownHosts, platform)}`,
|
|
151
|
+
` StrictHostKeyChecking yes`,
|
|
152
|
+
` ProxyCommand ${proxyCommand(self, sid, platform)}`,
|
|
153
|
+
"",
|
|
154
|
+
].join("\n");
|
|
155
|
+
export const sshConfigHint = (sid, platform = process.platform) => platform === "win32"
|
|
156
|
+
? `New-Item -ItemType Directory -Force $HOME\\.ssh | Out-Null; ${sh `promigence sandbox ssh ${sid} --config`} | Out-File -Append -Encoding ascii $HOME\\.ssh\\config`
|
|
157
|
+
: `mkdir -p -m 700 ~/.ssh && ${sh `promigence sandbox ssh ${sid} --config`} >> ~/.ssh/config && chmod 600 ~/.ssh/config`;
|
|
158
|
+
async function proxy(ctx, sandboxId) {
|
|
159
|
+
const local = paths(sandboxId);
|
|
160
|
+
let token;
|
|
161
|
+
if (existsSync(local.tokenPath))
|
|
162
|
+
token = readFileSync(local.tokenPath, "utf8").trim();
|
|
163
|
+
const issuedBy = token && existsSync(local.apiUrlPath) ? readFileSync(local.apiUrlPath, "utf8").trim() : "";
|
|
164
|
+
const c = issuedBy
|
|
165
|
+
? new PromigenceClient({ ...clientOpts(ctx), apiUrl: issuedBy, onNotice: recordNotice })
|
|
166
|
+
: client(ctx);
|
|
167
|
+
const tunnel = await c.sandboxes.ssh.connect(sandboxId, {
|
|
168
|
+
...(token ? { token } : {}),
|
|
169
|
+
onData: (d) => {
|
|
170
|
+
process.stdout.write(d);
|
|
171
|
+
},
|
|
172
|
+
onClose: () => {
|
|
173
|
+
},
|
|
174
|
+
});
|
|
175
|
+
process.stdin.on("data", (d) => tunnel.write(new Uint8Array(d)));
|
|
176
|
+
process.stdin.on("end", () => tunnel.close());
|
|
177
|
+
process.stdin.resume();
|
|
178
|
+
await tunnel.done;
|
|
179
|
+
return 0;
|
|
180
|
+
}
|
|
181
|
+
export async function proxyRefusal(ctx, sid, e) {
|
|
182
|
+
if (!(e instanceof PromigenceError) || e.code !== "auth" || !existsSync(paths(sid).tokenPath))
|
|
183
|
+
return e;
|
|
184
|
+
const state = await client(ctx).sandboxes.get(sid).then((s) => s.state).catch(() => undefined);
|
|
185
|
+
const again = sh `promigence sandbox ssh ${sid}`;
|
|
186
|
+
const [message, fix] = state === "ended"
|
|
187
|
+
? [`sandbox ${sid} has ended`, "Start a new sandbox (promigence fork --count 1 --cap 1) and connect to that one."]
|
|
188
|
+
: state === undefined
|
|
189
|
+
? [`this ssh access to ${sid} was revoked or has expired, or the sandbox has ended`, `Run \`${again}\` again for new access (\`${sh `promigence sandbox info ${sid}`}\` shows whether it is still running).`]
|
|
190
|
+
: [`this ssh access to ${sid} was revoked or has expired`, `Run \`${again}\` again for new access.`];
|
|
191
|
+
return new PromigenceError({
|
|
192
|
+
code: e.code, message, fix, exitCode: e.cliExit,
|
|
193
|
+
...(e.status === undefined ? {} : { status: e.status }),
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
async function listAccess(ctx, sid) {
|
|
197
|
+
const r = await client(ctx).sandboxes.ssh.list(sid);
|
|
198
|
+
const next = r.keys.length
|
|
199
|
+
? nexts([sh `promigence sandbox ssh ${sid} --revoke KEY_ID`, "end one key's access early: put its key_id from this list in place of KEY_ID"])
|
|
200
|
+
: nexts([sh `promigence sandbox ssh ${sid}`, "new access"]);
|
|
201
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...r }, next), [
|
|
202
|
+
`ssh access to ${sid}: ${r.keys.length} key(s)`,
|
|
203
|
+
...r.keys.map((k) => ` ${k.key_id} ${k.fingerprint} expires ${k.expires_at}${k.token_active ? "" : " (access credential ended)"}`),
|
|
204
|
+
], 0, ctx.pointer);
|
|
205
|
+
}
|
|
206
|
+
async function revokeAccess(ctx, sid, keyId) {
|
|
207
|
+
const r = await client(ctx).sandboxes.ssh.revoke(sid, keyId);
|
|
208
|
+
const next = nexts([sh `promigence sandbox ssh ${sid} --list`, "the access that is left"]);
|
|
209
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...r }, next), [
|
|
210
|
+
r.revoked ? `revoked ${r.key_id} on ${sid}` : `${r.key_id} on ${sid} had no access left to revoke`,
|
|
211
|
+
], 0, ctx.pointer);
|
|
212
|
+
}
|
|
213
|
+
export const sandboxSsh = async (ctx) => {
|
|
214
|
+
const sid = sshSandboxId(positional(ctx, "a sandbox id", "promigence sandbox ssh sbx_01"));
|
|
215
|
+
if (bool(ctx, "--proxy")) {
|
|
216
|
+
let code;
|
|
217
|
+
try {
|
|
218
|
+
code = await proxy(ctx, sid);
|
|
219
|
+
}
|
|
220
|
+
catch (e) {
|
|
221
|
+
throw await proxyRefusal(ctx, sid, e);
|
|
222
|
+
}
|
|
223
|
+
return exitWith(code);
|
|
224
|
+
}
|
|
225
|
+
if (bool(ctx, "--list"))
|
|
226
|
+
return listAccess(ctx, sid);
|
|
227
|
+
const revoke = str(ctx, "--revoke");
|
|
228
|
+
if (revoke !== undefined)
|
|
229
|
+
return revokeAccess(ctx, sid, revoke);
|
|
230
|
+
const { access, local } = await open(ctx, sid);
|
|
231
|
+
const self = selfCommand();
|
|
232
|
+
const next = nexts([sshConfigHint(sid), "attach an IDE, scp or rsync"], [sh `promigence sandbox ssh ${sid} --revoke ${access.key_id}`, "end this access early"]);
|
|
233
|
+
if (bool(ctx, "--config")) {
|
|
234
|
+
const block = configBlock(sid, access, local, self);
|
|
235
|
+
if (ctx.explicitMode !== "json") {
|
|
236
|
+
await write(process.stdout, block);
|
|
237
|
+
await write(process.stderr, ` next: ${next[0].cmd}\n then: ssh ${access.host}\n`);
|
|
238
|
+
return exitWith(0);
|
|
239
|
+
}
|
|
240
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...access, ssh_config: block }, next), block.split("\n"), 0, ctx.pointer);
|
|
241
|
+
}
|
|
242
|
+
const sshLine = ["ssh", ...sshArgs(sid, local, self), `${access.user}@${access.host}`].map(process.platform === "win32" ? winArg : shellArg).join(" ");
|
|
243
|
+
const details = [
|
|
244
|
+
` host key ${access.host_key_fingerprint}`,
|
|
245
|
+
` key ${access.fingerprint} (${access.key_id})`,
|
|
246
|
+
` expires ${access.expires_at}, idle timeout ${access.idle_timeout_s}s`,
|
|
247
|
+
];
|
|
248
|
+
if (bool(ctx, "--print") && ctx.explicitMode !== "json") {
|
|
249
|
+
await write(process.stdout, `${sshLine}\n`);
|
|
250
|
+
await write(process.stderr, `${details.join("\n")}\n`);
|
|
251
|
+
return exitWith(0);
|
|
252
|
+
}
|
|
253
|
+
const runRemote = ctx.cmdTail.length > 0 && ctx.explicitMode !== "json";
|
|
254
|
+
if (bool(ctx, "--print") || (ctx.mode === "json" && !runRemote)) {
|
|
255
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, { ...access }, next), [sshLine, ...details], 0, ctx.pointer);
|
|
256
|
+
}
|
|
257
|
+
const args = [...sshArgs(sid, local, self), `${access.user}@${access.host}`, ...ctx.cmdTail];
|
|
258
|
+
const child = spawn("ssh", args, { stdio: "inherit" });
|
|
259
|
+
const code = await new Promise((resolve) => {
|
|
260
|
+
child.on("error", () => resolve(125));
|
|
261
|
+
child.on("exit", (c, sig) => resolve(c ?? (sig ? 128 : 125)));
|
|
262
|
+
});
|
|
263
|
+
return exitWith(code);
|
|
264
|
+
};
|
|
265
|
+
export const SSH_HANDLERS = {
|
|
266
|
+
"sandbox ssh": sandboxSsh,
|
|
267
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { VERSION, DOCS_URL } from "./sdk/index.js";
|
|
2
|
+
export { VERSION, DOCS_URL };
|
|
3
|
+
export declare const SCHEMA: "promigence.cli/v1";
|
|
4
|
+
export declare const GUIDE_POINTER = "AI agents: run 'promigence agent-guide' (~1.4k tokens) before using this tool.";
|
|
5
|
+
export declare const DESCRIPTION = "Promigence \u2014 verified, reproducible, forkable execution environments for agents.";
|
|
6
|
+
export declare const GOLDEN_PATH = "promigence run --snapshot promigence/base --count 2 --cap 1 --json -- python3 -c 'print(6*7)'";
|
|
7
|
+
export declare const WAIT_TIMEOUT_DEFAULT = "100s";
|
|
8
|
+
export declare const REQUEST_TIMEOUT_DEFAULT = "30s";
|
|
9
|
+
export declare const LIVE_COMMANDS: readonly ["login", "signup", "logout", "auth login", "keys list", "keys create", "keys revoke", "org list", "org create", "org switch", "org members", "org invite", "org invites", "org uninvite", "org resend", "org role", "org remove", "org leave", "org join", "org audit", "org rename", "org delete", "project list", "project create", "project rename", "project delete", "project cap", "project move", "me", "billing card", "doctor", "ping", "init", "examples", "templates", "templates show", "agent-guide", "mcp", "snapshot create", "snapshot status", "snapshot list", "snapshot inspect", "snapshot verify", "snapshot export", "fork", "exec", "exec output", "exec ps", "exec kill", "files put", "files get", "files ls", "run", "run quote", "run report", "run status", "run cancel", "run kill", "run replay", "run open", "run captures", "sandbox kill", "sandbox shell", "sandbox ssh", "sandbox network", "port expose", "port list", "port revoke", "secrets set", "bench burst", "status", "billing usage", "billing portal", "snapshot delete", "snapshot builds", "snapshot alias", "run list", "sandbox list", "sandbox info", "sandbox pause", "sandbox resume", "sandbox extend", "sandbox probe", "files rm", "secrets list", "secrets delete", "image resolve", "sandbox snapshot", "files search", "files mkdir", "files mv", "files cp", "files chmod", "exec stdin", "sandbox autopause", "agent start", "referrals", "referrals apply", "credits", "credits claim", "runners github", "runners gitlab", "pricing", "github connect", "github status", "github disconnect", "github untrack", "repos", "gitlab connect", "gitlab status", "gitlab disconnect", "gitlab untrack", "billing history"];
|
|
10
|
+
export declare const GUIDE_COMMON_ERRORS: readonly ["auth", "credit_unclaimed", "not_found", "not_verified", "cap_exceeded", "timeout", "nonzero_exit"];
|
|
11
|
+
export type Group = "Setup" | "Snapshots" | "Runs" | "Sandboxes" | "Ops";
|
|
12
|
+
export type CommandStatus = "planned" | "released";
|
|
13
|
+
export interface Flag {
|
|
14
|
+
name: string;
|
|
15
|
+
arg?: string;
|
|
16
|
+
summary: string;
|
|
17
|
+
repeatable?: boolean;
|
|
18
|
+
required?: boolean;
|
|
19
|
+
hidden?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface Command {
|
|
22
|
+
name: string;
|
|
23
|
+
group: Group;
|
|
24
|
+
summary: string;
|
|
25
|
+
args?: string;
|
|
26
|
+
flags: Flag[];
|
|
27
|
+
status: CommandStatus;
|
|
28
|
+
next: string[];
|
|
29
|
+
helpRow?: {
|
|
30
|
+
key: string;
|
|
31
|
+
summary: string;
|
|
32
|
+
via?: string;
|
|
33
|
+
};
|
|
34
|
+
noGuidePointer?: boolean;
|
|
35
|
+
notOnHosted?: string;
|
|
36
|
+
passthroughExit?: number;
|
|
37
|
+
autoIdempotencyKey?: boolean;
|
|
38
|
+
signIn?: string;
|
|
39
|
+
note?: string;
|
|
40
|
+
ownExtraWords?: true;
|
|
41
|
+
}
|
|
42
|
+
export declare const TIER_NOTE = "a sandbox has its snapshot's size (base: small); another size: snapshot create --image REF --tier T";
|
|
43
|
+
export declare const BACKGROUND_NOTE = "background commands started with `exec --background` are ended; anything else you started keeps running when the sandbox resumes";
|
|
44
|
+
export declare const COMMANDS: readonly Command[];
|
|
45
|
+
export declare function compactNames(names: readonly string[]): string;
|
|
46
|
+
export declare const LISTED_COMMANDS: readonly Command[];
|
|
47
|
+
export declare const LIVE_SUMMARY: string;
|
|
48
|
+
export declare const NOT_LIVE_SUMMARY = "";
|
|
49
|
+
export declare const STATUS_LINE: string;
|
|
50
|
+
export declare const GROUPS: readonly Group[];
|
|
51
|
+
export declare const GLOBAL_FLAGS: readonly Flag[];
|
|
52
|
+
export declare function knownFlags(cmd: Command): Set<string>;
|
|
53
|
+
export declare function unknownFlags(cmd: Command, typed: Iterable<string>): string[];
|
|
54
|
+
export declare function nearestFlag(typo: string, cmd: Command): string | undefined;
|
|
55
|
+
export interface ExitCode {
|
|
56
|
+
code: number;
|
|
57
|
+
name: string;
|
|
58
|
+
summary: string;
|
|
59
|
+
}
|
|
60
|
+
export declare const EXIT_CODES: readonly ExitCode[];
|
|
61
|
+
export declare const EXIT_PRECEDENCE: readonly number[];
|
|
62
|
+
export declare const EXIT_PRECEDENCE_TEXT = "2 > 5 > 6 > 7/8/9/10 > 11 > 3 > 12 > 4 > 1 > 0";
|
|
63
|
+
export declare const OUTPUT_MODE_PRECEDENCE: readonly ["--json | --text", "PROMIGENCE_OUTPUT=json|text", "stdout TTY → text, else json"];
|
|
64
|
+
export interface NextHint {
|
|
65
|
+
cmd: string;
|
|
66
|
+
why: string;
|
|
67
|
+
}
|
|
68
|
+
export interface EnvelopeError {
|
|
69
|
+
code: string;
|
|
70
|
+
message: string;
|
|
71
|
+
fix: string;
|
|
72
|
+
docs: string;
|
|
73
|
+
guide: string;
|
|
74
|
+
request_id?: string;
|
|
75
|
+
category?: string;
|
|
76
|
+
retryable?: boolean;
|
|
77
|
+
exit?: number;
|
|
78
|
+
}
|
|
79
|
+
export interface Envelope {
|
|
80
|
+
schema: typeof SCHEMA;
|
|
81
|
+
command: string;
|
|
82
|
+
ok: boolean;
|
|
83
|
+
error?: EnvelopeError;
|
|
84
|
+
next: NextHint[];
|
|
85
|
+
idempotent_replay?: boolean;
|
|
86
|
+
hint?: string;
|
|
87
|
+
promigence_exit?: number;
|
|
88
|
+
[extra: string]: unknown;
|
|
89
|
+
}
|
|
90
|
+
export declare function findCommand(words: readonly string[]): Command | undefined;
|
|
91
|
+
export declare function renderHelp(): string;
|
|
92
|
+
export declare function signInLine(c: Pick<Command, "signIn">): string | undefined;
|
|
93
|
+
export declare function renderCommandHelp(c: Command): string;
|
|
94
|
+
export declare function notReleasedEnvelope(c: Command): Envelope;
|
|
95
|
+
export declare function notReleasedLines(c: Command, env: Envelope): string[];
|