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/handlers.js
ADDED
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
import { existsSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { BUNDLE_EXT, DEFAULT_SNAPSHOT, PromigenceError, VERSION as SDK_VERSION, configDir, credentialsPath, platformOf, readCredentialsWithStore, renderBundle, verifyBundle, } from "./sdk/index.js";
|
|
4
|
+
import { storeLabel } from "./sdk/credstore.js";
|
|
5
|
+
import { bool, client, list, nexts, positional, required, str, } from "./commands.js";
|
|
6
|
+
import { emit, exitWith, forkSummary, markGuideSeen, ms, okEnvelope, parseCount, parseDuration, parseUsd, pickExit, usageError, write, } from "./io.js";
|
|
7
|
+
import { ALL_ERROR_CODES, BUDGETS, estimateTokens, guideJson, humanHeader, lookupError, renderGuide } from "./guide.js";
|
|
8
|
+
import { livePricing, quickClient } from "./pricing.js";
|
|
9
|
+
import { install, installLines } from "./install.js";
|
|
10
|
+
import { backgroundOutput } from "./live.js";
|
|
11
|
+
import { detect, gitFacts, imageCreateCommand, renderConfig, stripRemoteCredentials } from "./init.js";
|
|
12
|
+
import { TIERS } from "./generated.js";
|
|
13
|
+
import { GOLDEN_PATH, SCHEMA, VERSION } from "./surface.js";
|
|
14
|
+
import { jsonLine, sh } from "./term.js";
|
|
15
|
+
import { fmtMs, median, where } from "./timing.js";
|
|
16
|
+
const SECTION_NAMES = new Set(["core", "commands", "errors", "cost"]);
|
|
17
|
+
const agentGuide = async (ctx) => {
|
|
18
|
+
const format = str(ctx, "--format") ?? (ctx.explicitMode === "json" ? "json" : "md");
|
|
19
|
+
if (format !== "md" && format !== "json") {
|
|
20
|
+
throw usageError(`--format: '${format}' is not a format`, "Pass --format md (default) or --format json.");
|
|
21
|
+
}
|
|
22
|
+
const json = format === "json";
|
|
23
|
+
if (bool(ctx, "--create") && !bool(ctx, "--install") && !bool(ctx, "--check")) {
|
|
24
|
+
throw usageError("--create needs --install", "Pass --install --create to write AGENTS.md (and the skill and rule files) here.");
|
|
25
|
+
}
|
|
26
|
+
if (bool(ctx, "--install") || bool(ctx, "--check")) {
|
|
27
|
+
const checking = bool(ctx, "--check");
|
|
28
|
+
const res = install(process.cwd(), { write: !checking, create: bool(ctx, "--create") });
|
|
29
|
+
markGuideSeen();
|
|
30
|
+
const skipped = res.artifacts.find((a) => a.action === "skipped");
|
|
31
|
+
const next = nexts(...(skipped
|
|
32
|
+
? [["promigence agent-guide --install --create", "create AGENTS.md and write the fence into it"]]
|
|
33
|
+
: []), ["promigence agent-guide", "the guide itself (~1.4k tokens)"], ["promigence examples", "what you can fork with no build (the built-in base)"]);
|
|
34
|
+
const env = okEnvelope(ctx.cmd.name, {
|
|
35
|
+
mode: checking ? "check" : "install",
|
|
36
|
+
dir: res.dir,
|
|
37
|
+
changed: res.changed,
|
|
38
|
+
...(res.memoryFile ? { memory_file: res.memoryFile } : {}),
|
|
39
|
+
artifacts: res.artifacts,
|
|
40
|
+
}, next);
|
|
41
|
+
return emit(ctx.mode, env, installLines(res, checking), checking && res.changed ? 13 : 0, false);
|
|
42
|
+
}
|
|
43
|
+
const code = str(ctx, "--code");
|
|
44
|
+
const sectionFlag = str(ctx, "--section");
|
|
45
|
+
if (sectionFlag !== undefined && !SECTION_NAMES.has(sectionFlag)) {
|
|
46
|
+
throw usageError(`--section: '${sectionFlag}' is not a section`, "Pass --section commands | errors | cost (omit it for the core guide).");
|
|
47
|
+
}
|
|
48
|
+
const section = (sectionFlag ?? "core");
|
|
49
|
+
if (code !== undefined && lookupError(code) === undefined) {
|
|
50
|
+
const near = ALL_ERROR_CODES.filter((k) => k.includes(code) || code.includes(k)).slice(0, 3);
|
|
51
|
+
throw usageError(`--code: '${code}' is not an error code`, `${near.length ? `Did you mean ${near.join(", ")}? ` : ""}List them: promigence agent-guide --section errors.`);
|
|
52
|
+
}
|
|
53
|
+
const prices = section === "cost" && code === undefined ? await livePricing(quickClient(ctx)) : undefined;
|
|
54
|
+
const opts = { section, ...(code === undefined ? {} : { code }), ...(prices === undefined ? {} : { prices }) };
|
|
55
|
+
const guide = renderGuide(opts);
|
|
56
|
+
markGuideSeen();
|
|
57
|
+
if (json) {
|
|
58
|
+
const body = guideJson(opts);
|
|
59
|
+
const env = {
|
|
60
|
+
schema: SCHEMA, command: ctx.cmd.name, ok: true, ...body,
|
|
61
|
+
next: [
|
|
62
|
+
{ cmd: "promigence examples", why: "what you can fork with no build (the built-in base)" },
|
|
63
|
+
{ cmd: GOLDEN_PATH, why: "the golden path, end to end" },
|
|
64
|
+
],
|
|
65
|
+
};
|
|
66
|
+
await write(process.stdout, jsonLine(process.stdout, env));
|
|
67
|
+
return exitWith(0);
|
|
68
|
+
}
|
|
69
|
+
if (section === "core" && code === undefined && process.stdout.isTTY)
|
|
70
|
+
await write(process.stdout, humanHeader());
|
|
71
|
+
await write(process.stdout, guide);
|
|
72
|
+
const budget = BUDGETS[section] ?? BUDGETS.core;
|
|
73
|
+
const used = estimateTokens(guide);
|
|
74
|
+
if (used > budget)
|
|
75
|
+
await write(process.stderr, `warning: ${section} guide is ~${used} tokens, over its ${budget} budget\n`);
|
|
76
|
+
return exitWith(0);
|
|
77
|
+
};
|
|
78
|
+
const TIERS_SELLABLE = TIERS.filter((t) => t.sellable)
|
|
79
|
+
.sort((a, b) => a.vcpus - b.vcpus || a.mem_gib - b.mem_gib)
|
|
80
|
+
.map((t) => t.name);
|
|
81
|
+
const init = async (ctx) => {
|
|
82
|
+
const dir = process.cwd();
|
|
83
|
+
const path = join(dir, "promigence.toml");
|
|
84
|
+
const printOnly = bool(ctx, "--print");
|
|
85
|
+
if (existsSync(path) && !bool(ctx, "--force") && !printOnly) {
|
|
86
|
+
throw usageError(`promigence.toml already exists in ${dir}`, "Pass --force to overwrite it, or --print to see what init would write without touching it.");
|
|
87
|
+
}
|
|
88
|
+
const found = detect(dir);
|
|
89
|
+
const git = gitFacts(dir);
|
|
90
|
+
const notes = [];
|
|
91
|
+
const repoGiven = str(ctx, "--repo");
|
|
92
|
+
const repo = repoGiven === undefined ? git.repo : stripRemoteCredentials(repoGiven);
|
|
93
|
+
const credsRemoved = repoGiven === undefined ? Boolean(git.credentialsRemoved) : repo !== repoGiven;
|
|
94
|
+
if (credsRemoved) {
|
|
95
|
+
notes.push("WARNING: credentials removed from the git remote URL: promigence.toml is committed with your code, and " +
|
|
96
|
+
"credentials in repository URLs are not accepted. For private code, see the line on code the builder cannot clone.");
|
|
97
|
+
}
|
|
98
|
+
if (!repo) {
|
|
99
|
+
throw usageError("no git remote `origin` in this directory, and no --repo", "Pass --repo https://github.com/org/app — the builder clones it, so it must be a public repository it can reach.");
|
|
100
|
+
}
|
|
101
|
+
const commit = str(ctx, "--commit") ?? git.commit;
|
|
102
|
+
if (!commit) {
|
|
103
|
+
throw usageError("cannot read HEAD in this directory, and no --commit", "Run this inside a git checkout, or pass --commit <40-char sha> (a branch is not a pin).");
|
|
104
|
+
}
|
|
105
|
+
if (!/^[0-9a-f]{40}$/i.test(commit)) {
|
|
106
|
+
throw usageError(`--commit ${commit} is not a 40-character sha`, "A branch or short sha is not a pin: pass the full sha (git rev-parse HEAD).");
|
|
107
|
+
}
|
|
108
|
+
const setupFlags = list(ctx, "--setup");
|
|
109
|
+
const setup = setupFlags.length ? setupFlags : found.setup;
|
|
110
|
+
const verify = str(ctx, "--verify") ?? found.verify;
|
|
111
|
+
const tier = str(ctx, "--tier") ?? "medium";
|
|
112
|
+
if (!TIERS_SELLABLE.includes(tier)) {
|
|
113
|
+
throw usageError(`--tier: '${tier}' is not a tier`, `Pass --tier ${TIERS_SELLABLE.join(" | ")} (see 'promigence agent-guide --section cost').`);
|
|
114
|
+
}
|
|
115
|
+
if (!verify) {
|
|
116
|
+
throw usageError(`no verify command could be inferred (${found.why})`, "Pass --verify 'the command that must exit 0' — a snapshot with nothing to verify is not verified.");
|
|
117
|
+
}
|
|
118
|
+
notes.push(`ecosystem: ${found.ecosystem}${found.lockfile ? ` (${found.lockfile})` : ""}`);
|
|
119
|
+
notes.push(`verify: ${setupFlags.length || str(ctx, "--verify") ? "given on the command line" : found.why}`);
|
|
120
|
+
if (git.dirty)
|
|
121
|
+
notes.push("WARNING: the working tree is dirty — the snapshot is built from the commit, not your edits.");
|
|
122
|
+
if (str(ctx, "--commit") === undefined && git.onRemote === false) {
|
|
123
|
+
notes.push(git.noRemoteRefs
|
|
124
|
+
? `WARNING: HEAD ${commit.slice(0, 7)} has not been pushed (this checkout has no remote branches), so the builder ` +
|
|
125
|
+
"cannot fetch it: push it first (git push), or pass --commit with a sha that is on the remote."
|
|
126
|
+
: `WARNING: HEAD ${commit.slice(0, 7)} is on no remote branch, so the builder cannot fetch it: push it first (git push), ` +
|
|
127
|
+
"or pass --commit with a sha that is on the remote.");
|
|
128
|
+
}
|
|
129
|
+
if (git.branch && git.branch !== "HEAD")
|
|
130
|
+
notes.push(`pinned from branch ${git.branch}; re-run promigence init after every commit you want to fork`);
|
|
131
|
+
const uncloneable = credsRemoved || (str(ctx, "--commit") === undefined && git.onRemote === false);
|
|
132
|
+
const otherWays = "Code the builder cannot clone (private, or not pushed): `promigence snapshot create --dir . --alias NAME " +
|
|
133
|
+
"--setup … --verify … --wait` uploads this checkout instead (built on promigence/base), or `promigence github connect` " +
|
|
134
|
+
"and then `promigence snapshot create --repo owner/name`.";
|
|
135
|
+
if (uncloneable)
|
|
136
|
+
notes.push(otherWays);
|
|
137
|
+
const cfg = {
|
|
138
|
+
repo, commit: commit.toLowerCase(), setup, verify, tier,
|
|
139
|
+
toolchain: found.toolchain,
|
|
140
|
+
...(found.lockfile ? { lockfile: found.lockfile } : {}),
|
|
141
|
+
};
|
|
142
|
+
const createCmd = imageCreateCommand(cfg, found.ecosystem);
|
|
143
|
+
const toml = renderConfig(cfg, notes, createCmd);
|
|
144
|
+
if (!printOnly)
|
|
145
|
+
writeFileSync(path, toml);
|
|
146
|
+
const next = nexts([createCmd, "build and verify the snapshot this file describes"], ["promigence examples", "or fork the built-in base first, with no build at all"]);
|
|
147
|
+
const env = okEnvelope(ctx.cmd.name, {
|
|
148
|
+
path: printOnly ? null : path,
|
|
149
|
+
written: !printOnly,
|
|
150
|
+
ecosystem: found.ecosystem,
|
|
151
|
+
...(found.lockfile ? { lockfile: found.lockfile } : {}),
|
|
152
|
+
repo, commit: cfg.commit, setup, verify, tier,
|
|
153
|
+
toolchain: found.toolchain,
|
|
154
|
+
...(git.branch ? { branch: git.branch } : {}),
|
|
155
|
+
...(git.dirty === undefined ? {} : { dirty: git.dirty }),
|
|
156
|
+
inference: found.why,
|
|
157
|
+
...(credsRemoved ? { credentials_removed: true } : {}),
|
|
158
|
+
config: toml,
|
|
159
|
+
}, next);
|
|
160
|
+
const lines = [
|
|
161
|
+
`promigence init: ${printOnly ? "(--print, nothing written)" : path}`,
|
|
162
|
+
` ecosystem ${found.ecosystem}${found.lockfile ? ` from ${found.lockfile}` : ""} — ${found.why}`,
|
|
163
|
+
` repo ${repo}`,
|
|
164
|
+
...(credsRemoved ? [" WARNING: credentials removed from the git remote URL (promigence.toml is committed with your code)"] : []),
|
|
165
|
+
` commit ${cfg.commit}${git.dirty ? " (working tree is dirty; the build uses the commit)" : ""}`,
|
|
166
|
+
...setup.map((s, i) => ` setup[${i}] ${s}`),
|
|
167
|
+
` verify ${verify}`,
|
|
168
|
+
` tier ${tier}${str(ctx, "--tier") === undefined ? " (init's default; every fork of this snapshot runs at this size: --tier small is the smaller one)" : ""}`,
|
|
169
|
+
...(printOnly ? ["", ...toml.split("\n")] : []),
|
|
170
|
+
` next: ${createCmd}`,
|
|
171
|
+
...(uncloneable ? [` or: ${otherWays}`] : []),
|
|
172
|
+
];
|
|
173
|
+
return emit(ctx.mode, env, lines, 0, ctx.pointer);
|
|
174
|
+
};
|
|
175
|
+
const FALLBACK_EXAMPLES = [
|
|
176
|
+
{
|
|
177
|
+
snapshot_id: DEFAULT_SNAPSHOT,
|
|
178
|
+
visibility: "public",
|
|
179
|
+
tier: "small",
|
|
180
|
+
verify: { cmd: "python3 -c 'print(6*7)'" },
|
|
181
|
+
},
|
|
182
|
+
];
|
|
183
|
+
const examples = async (ctx) => {
|
|
184
|
+
const limit = parseCount(str(ctx, "--limit") ?? "20", "--limit");
|
|
185
|
+
const c = client(ctx);
|
|
186
|
+
let snapshots;
|
|
187
|
+
let fallback = false;
|
|
188
|
+
let failed = false;
|
|
189
|
+
let reason;
|
|
190
|
+
try {
|
|
191
|
+
snapshots = await c.snapshots.public(limit);
|
|
192
|
+
if (snapshots.length === 0) {
|
|
193
|
+
snapshots = [...FALLBACK_EXAMPLES];
|
|
194
|
+
fallback = true;
|
|
195
|
+
reason = "the API lists no public snapshots yet; promigence/base is built in and not listed by the API";
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
snapshots = [...FALLBACK_EXAMPLES];
|
|
200
|
+
fallback = true;
|
|
201
|
+
failed = true;
|
|
202
|
+
reason = err instanceof PromigenceError ? `${err.code}: ${err.message}` : String(err);
|
|
203
|
+
}
|
|
204
|
+
const bundles = [];
|
|
205
|
+
if (bool(ctx, "--bundle")) {
|
|
206
|
+
if (fallback) {
|
|
207
|
+
throw usageError(`--bundle writes one file per public snapshot, and there are none to write (${reason}); the built-in promigence/base has no bundle`, "Bundle an environment of your own instead: `promigence snapshot export <id> --out env.promigence`.");
|
|
208
|
+
}
|
|
209
|
+
for (const s of snapshots) {
|
|
210
|
+
const id = s.snapshot_id;
|
|
211
|
+
const { bundle, served_by } = await c.snapshots.bundle(id);
|
|
212
|
+
const form = verifyBundle(bundle);
|
|
213
|
+
const text = renderBundle(bundle);
|
|
214
|
+
const file = `${bundle.alias ?? bundle.snap_id}${BUNDLE_EXT}`;
|
|
215
|
+
writeFileSync(resolve(file), text);
|
|
216
|
+
bundles.push({
|
|
217
|
+
path: resolve(file), bytes: text.length, form, served_by,
|
|
218
|
+
snapshot_id: bundle.snap_id, manifest_hash: bundle.manifest_hash,
|
|
219
|
+
platform: platformOf(bundle) ?? null,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const first = fallback ? undefined : snapshots[0];
|
|
224
|
+
const golden = first
|
|
225
|
+
? sh `promigence run --snapshot ${first.alias ? (first.commit ? `${first.alias}@${first.commit.slice(0, 7)}` : first.alias) : first.snapshot_id} --count 2 --cap 1 --json -- sh -c ${first.verify?.cmd ?? "true"}`
|
|
226
|
+
: GOLDEN_PATH;
|
|
227
|
+
const next = nexts([golden, "fork it twice, run its verify command in each, print the validity report"], ["promigence agent-guide", "the model, the output contract and the exit codes"]);
|
|
228
|
+
const env = {
|
|
229
|
+
...okEnvelope(ctx.cmd.name, {
|
|
230
|
+
snapshots,
|
|
231
|
+
count: snapshots.length,
|
|
232
|
+
source: fallback ? "fallback" : "api",
|
|
233
|
+
default_snapshot: DEFAULT_SNAPSHOT,
|
|
234
|
+
...(reason ? { fallback_reason: reason } : {}),
|
|
235
|
+
...(bundles.length ? { bundles } : {}),
|
|
236
|
+
authenticated: false,
|
|
237
|
+
}, next),
|
|
238
|
+
};
|
|
239
|
+
const lines = [
|
|
240
|
+
fallback ? "public snapshots: the built-in base" : `public snapshots: ${snapshots.length}`,
|
|
241
|
+
...(failed ? [` the API did not serve the list: ${reason}`] : []),
|
|
242
|
+
...(fallback && !failed ? [" promigence/base is built in and not listed by the API; it has no manifest or bundle"] : []),
|
|
243
|
+
...(fallback ? [] : [` ${DEFAULT_SNAPSHOT} built in: the default when no --snapshot is given (not in the list below)`]),
|
|
244
|
+
...snapshots.map((s) => ` ${s.alias ?? s.snapshot_id}${s.commit ? `@${s.commit.slice(0, 7)}` : ""} tier ${s.tier ?? "?"} verify ${JSON.stringify(s.verify?.cmd ?? "?")} ${s.repo ?? ""}`),
|
|
245
|
+
...bundles.map((b) => ` wrote ${b["path"]} — ${b["bytes"].toLocaleString("en-US")} B, ${b["form"]} form (${b["served_by"]}-composed)`),
|
|
246
|
+
` next: ${golden}`,
|
|
247
|
+
];
|
|
248
|
+
return emit(ctx.mode, env, lines, 0, ctx.pointer);
|
|
249
|
+
};
|
|
250
|
+
const ok = (name, measured) => ({ name, measured, result: "ok" });
|
|
251
|
+
const warn = (name, measured, fix) => ({ name, measured, result: "warn", fix });
|
|
252
|
+
const fail = (name, measured, fix, exit) => ({ name, measured, result: "fail", fix, exit });
|
|
253
|
+
function keySource(ctx) {
|
|
254
|
+
if (ctx.apiKey)
|
|
255
|
+
return { source: "--api-key (visible in `ps`; prefer PROMIGENCE_API_KEY)", present: true };
|
|
256
|
+
if (process.env["PROMIGENCE_API_KEY"])
|
|
257
|
+
return { source: "PROMIGENCE_API_KEY", present: true };
|
|
258
|
+
const { creds, store } = readCredentialsWithStore();
|
|
259
|
+
if (creds.api_key) {
|
|
260
|
+
return { source: store === "file" || store === undefined ? credentialsPath() : `${storeLabel(store)} (item ${credentialsPath()})`, present: true };
|
|
261
|
+
}
|
|
262
|
+
return { source: "none", present: false };
|
|
263
|
+
}
|
|
264
|
+
async function clientChecks(ctx) {
|
|
265
|
+
const checks = [];
|
|
266
|
+
const major = Number(process.versions.node.split(".")[0]);
|
|
267
|
+
checks.push(major >= 20
|
|
268
|
+
? ok("node", `v${process.versions.node} (>= 20)`)
|
|
269
|
+
: fail("node", `v${process.versions.node}`, "promigence needs Node >= 20 (package.json engines). Upgrade Node, then rerun.", 1));
|
|
270
|
+
checks.push(ok("promigence", `${VERSION} (sdk ${SDK_VERSION})`));
|
|
271
|
+
const cfg = configDir();
|
|
272
|
+
checks.push(ok("config_dir", `${cfg}${existsSync(cfg) ? "" : " (not created yet)"}`));
|
|
273
|
+
const key = keySource(ctx);
|
|
274
|
+
if (!key.present) {
|
|
275
|
+
checks.push(fail("auth_key", "no key in --api-key, PROMIGENCE_API_KEY, the OS keychain or the credentials file", "No key yet: `promigence login` signs you up or in and stores one. A key you already have: `promigence auth login --from-env VAR`.", 7));
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
checks.push(ok("auth_key", `from ${key.source}`));
|
|
279
|
+
const path = credentialsPath();
|
|
280
|
+
if (existsSync(path)) {
|
|
281
|
+
const mode = statSync(path).mode & 0o777;
|
|
282
|
+
checks.push(mode === 0o600
|
|
283
|
+
? ok("credentials_mode", `0${mode.toString(8)} on ${path}`)
|
|
284
|
+
: warn("credentials_mode", `0${mode.toString(8)} on ${path}`, `Tighten it: chmod 600 ${path} (it holds your API key).`));
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return checks;
|
|
288
|
+
}
|
|
289
|
+
async function apiChecks(ctx, checks) {
|
|
290
|
+
const c = client(ctx);
|
|
291
|
+
checks.push(ok("api_url", c.apiUrl));
|
|
292
|
+
let health;
|
|
293
|
+
const t0 = Date.now();
|
|
294
|
+
try {
|
|
295
|
+
health = await c.health({ timeoutMs: 10_000 });
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
const e = err;
|
|
299
|
+
checks.push(fail("api_reachable", `${e.code ?? "error"}: ${e.message ?? String(err)}`, e.fix ?? "Check PROMIGENCE_API_URL and connectivity; the API is at https://api.promigence.ai/v1.", e.cliExit ?? 9));
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const ms = Date.now() - t0;
|
|
303
|
+
checks.push(ok("api_reachable", `GET /health in ${ms} ms`));
|
|
304
|
+
if (health.serving === false) {
|
|
305
|
+
checks.push(warn("capacity_ready", "the service cannot start new sandboxes right now", "New sandboxes queue until capacity is ready; nothing is billed while they wait. `promigence status` shows each service."));
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
checks.push(ok("capacity_ready", health.serving === true ? "new sandboxes can start now" : "the API did not say; `promigence status` shows each service"));
|
|
309
|
+
}
|
|
310
|
+
const server = health.version;
|
|
311
|
+
checks.push(ok("version_skew", server
|
|
312
|
+
? `client ${VERSION} · api ${server} (numbered separately)`
|
|
313
|
+
: `client ${VERSION} · the API did not report a version`));
|
|
314
|
+
if (!keySource(ctx).present)
|
|
315
|
+
return;
|
|
316
|
+
try {
|
|
317
|
+
const me = await c.me();
|
|
318
|
+
const cap = typeof me.default_spend_cap === "number" && me.default_spend_cap > 0 ? ` · default spend cap $${me.default_spend_cap}` : "";
|
|
319
|
+
checks.push(ok("auth_accepted", `org ${me.org_id ?? "?"}${me.key?.key_id ? ` key ${me.key.key_id}` : ""}${cap}`));
|
|
320
|
+
}
|
|
321
|
+
catch (err) {
|
|
322
|
+
const e = err;
|
|
323
|
+
checks.push(fail("auth_accepted", `${e.code}: ${e.message}`, e.fix, e.cliExit ?? 7));
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
const ping = async (ctx) => {
|
|
327
|
+
const n = Number(process.env["PROMIGENCE_PING_COUNT"] ?? "5");
|
|
328
|
+
if (!Number.isInteger(n) || n < 1 || n > 50)
|
|
329
|
+
throw usageError("PROMIGENCE_PING_COUNT takes 1 to 50", "Unset it for the default of five.");
|
|
330
|
+
const c = client(ctx);
|
|
331
|
+
const rounds = [];
|
|
332
|
+
let location;
|
|
333
|
+
for (let i = 0; i < n; i++) {
|
|
334
|
+
const h = await c.health({ timeoutMs: 10_000 });
|
|
335
|
+
if (typeof h.location === "string" && h.location)
|
|
336
|
+
location = h.location;
|
|
337
|
+
const tm = c.lastTiming;
|
|
338
|
+
if (tm)
|
|
339
|
+
rounds.push({ totalMs: tm.totalMs, ourMs: tm.ourMs });
|
|
340
|
+
}
|
|
341
|
+
const totals = rounds.map((r) => r.totalMs);
|
|
342
|
+
const ours = rounds.map((r) => r.ourMs).filter((x) => x !== null);
|
|
343
|
+
const nets = rounds.filter((r) => r.ourMs !== null).map((r) => Math.max(0, r.totalMs - r.ourMs));
|
|
344
|
+
const rt = median(totals);
|
|
345
|
+
const our = median(ours);
|
|
346
|
+
const net = median(nets);
|
|
347
|
+
const r1 = (x) => (x === undefined ? null : Math.round(x * 10) / 10);
|
|
348
|
+
const fields = {
|
|
349
|
+
location: location ?? null,
|
|
350
|
+
round_trips: n,
|
|
351
|
+
round_trip_ms: { median: r1(rt), min: r1(Math.min(...totals)), max: r1(Math.max(...totals)) },
|
|
352
|
+
our_side_ms: r1(our),
|
|
353
|
+
network_ms: r1(net),
|
|
354
|
+
};
|
|
355
|
+
const lines = [
|
|
356
|
+
`promigence ping: ${where(location)}`,
|
|
357
|
+
` round trip ${rt === undefined ? "—" : fmtMs(rt)} (median of ${n}; ${fmtMs(Math.min(...totals))} to ${fmtMs(Math.max(...totals))})`,
|
|
358
|
+
` our side ${our === undefined ? "— (not said by this service)" : fmtMs(our)}`,
|
|
359
|
+
` your network ${net === undefined ? "—" : fmtMs(net)}`,
|
|
360
|
+
...(net !== undefined && net >= 150
|
|
361
|
+
? [" Times marked 'on our side' are the platform's own; the rest is the distance to our servers."]
|
|
362
|
+
: []),
|
|
363
|
+
];
|
|
364
|
+
return emit(ctx.mode, okEnvelope(ctx.cmd.name, fields, nexts(["promigence doctor", "check the client, your key and the API"])), lines, 0, ctx.pointer);
|
|
365
|
+
};
|
|
366
|
+
const doctor = async (ctx) => {
|
|
367
|
+
const checks = await clientChecks(ctx);
|
|
368
|
+
await apiChecks(ctx, checks);
|
|
369
|
+
const failed = checks.filter((c) => c.result === "fail");
|
|
370
|
+
const warned = checks.filter((c) => c.result === "warn");
|
|
371
|
+
const exit = pickExit(failed.map((c) => c.exit ?? 1));
|
|
372
|
+
const next = failed.length
|
|
373
|
+
? nexts([failed[0].fix?.match(/`([^`]+)`/)?.[1] ?? "promigence agent-guide --section errors", `fix the first failure: ${failed[0].name}`])
|
|
374
|
+
: nexts(["promigence examples", "what you can fork with no build (the built-in base)"]);
|
|
375
|
+
const env = {
|
|
376
|
+
...okEnvelope(ctx.cmd.name, {
|
|
377
|
+
checks,
|
|
378
|
+
ok: failed.length === 0,
|
|
379
|
+
failures: failed.length,
|
|
380
|
+
warnings: warned.length,
|
|
381
|
+
exit,
|
|
382
|
+
}, next),
|
|
383
|
+
ok: failed.length === 0,
|
|
384
|
+
};
|
|
385
|
+
const lines = [
|
|
386
|
+
`promigence doctor: ${checks.length} checks · ${failed.length} failed · ${warned.length} warned`,
|
|
387
|
+
...checks.map((c) => ` ${(c.result === "ok" ? "ok " : c.result === "warn" ? "warn" : "FAIL")} ${c.name.padEnd(18)} ${c.measured}`),
|
|
388
|
+
...failed.flatMap((c) => [` fix (${c.name}): ${c.fix}`]),
|
|
389
|
+
...warned.flatMap((c) => [` note (${c.name}): ${c.fix}`]),
|
|
390
|
+
];
|
|
391
|
+
return emit(ctx.mode, env, lines, exit, ctx.pointer);
|
|
392
|
+
};
|
|
393
|
+
export function parseRange(value) {
|
|
394
|
+
const v = value.trim();
|
|
395
|
+
const m = /^(\d+)-(\d*)$/.exec(v);
|
|
396
|
+
if (!m) {
|
|
397
|
+
throw usageError(`--range: '${value}' is not a byte range`, v.startsWith("-")
|
|
398
|
+
? "There is no suffix form: pass --range A-B or A- (0-based, B inclusive). For the tail, read `total_bytes` from the envelope and ask for `<total_bytes-N>-`."
|
|
399
|
+
: "Pass --range A-B or A- (0-based, B inclusive), e.g. --range 0-65535.");
|
|
400
|
+
}
|
|
401
|
+
const out = { from: Number(m[1]) };
|
|
402
|
+
if (m[2] !== "")
|
|
403
|
+
out.to = Number(m[2]);
|
|
404
|
+
if (out.to !== undefined && out.to < out.from) {
|
|
405
|
+
throw usageError(`--range: '${value}' ends before it starts`, "Pass --range A-B with B >= A.");
|
|
406
|
+
}
|
|
407
|
+
return out;
|
|
408
|
+
}
|
|
409
|
+
const execOutput = async (ctx) => {
|
|
410
|
+
const execId = positional(ctx, "an exec id", "promigence exec output exec_ab12 --sandbox sbx_cd34");
|
|
411
|
+
if (execId.startsWith("x_"))
|
|
412
|
+
return backgroundOutput(ctx, execId);
|
|
413
|
+
if (bool(ctx, "--follow")) {
|
|
414
|
+
throw usageError("--follow is for a background exec (x_…)", "A foreground exec has already finished; drop --follow.");
|
|
415
|
+
}
|
|
416
|
+
const range = str(ctx, "--range");
|
|
417
|
+
const res = await client(ctx).sandboxes.output(execId, {
|
|
418
|
+
...(str(ctx, "--sandbox") === undefined ? {} : { sandboxId: str(ctx, "--sandbox") }),
|
|
419
|
+
...(str(ctx, "--run") === undefined ? {} : { runId: str(ctx, "--run") }),
|
|
420
|
+
...(range === undefined ? {} : { range: parseRange(range) }),
|
|
421
|
+
});
|
|
422
|
+
if (ctx.mode === "text") {
|
|
423
|
+
await write(process.stdout, bool(ctx, "--stderr") ? res.stderr : res.stdout);
|
|
424
|
+
return exitWith(0);
|
|
425
|
+
}
|
|
426
|
+
const next = nexts(...(res.run_id ? [[sh `promigence run report ${res.run_id} --json`, "the validity report this exec belongs to"]] : []), ...(res.sandbox_id && res.terminal !== true ? [[sh `promigence sandbox kill ${res.sandbox_id}`, "end the sandbox when you are done"]] : []));
|
|
427
|
+
const env = okEnvelope(ctx.cmd.name, {
|
|
428
|
+
exec_id: res.exec_id,
|
|
429
|
+
...(res.sandbox_id ? { sandbox_id: res.sandbox_id } : {}),
|
|
430
|
+
...(res.run_id ? { run_id: res.run_id } : {}),
|
|
431
|
+
...(res.argv ? { argv: res.argv } : {}),
|
|
432
|
+
exit_code: res.exit_code,
|
|
433
|
+
stdout: res.stdout,
|
|
434
|
+
stderr: res.stderr,
|
|
435
|
+
truncated: res.truncated ?? false,
|
|
436
|
+
bytes: res.bytes,
|
|
437
|
+
total_bytes: res.total_bytes,
|
|
438
|
+
...(res.range ? { range: res.range } : {}),
|
|
439
|
+
}, next);
|
|
440
|
+
return emit(ctx.mode, env, [], 0, false);
|
|
441
|
+
};
|
|
442
|
+
const benchBurst = async (ctx) => {
|
|
443
|
+
const snapshot = required(ctx, "--snapshot", "Pass --snapshot snap_<id> | <alias>[@commit7], or promigence/base (the built-in base).");
|
|
444
|
+
const count = parseCount(required(ctx, "--count", "Pass --count N — how many sandboxes to start at once. The published burst table uses 100."), "--count");
|
|
445
|
+
const timeoutMs = parseDuration(str(ctx, "--timeout") ?? "120s", "--timeout");
|
|
446
|
+
const capStr = str(ctx, "--cap") ?? process.env["PROMIGENCE_SPEND_CAP"];
|
|
447
|
+
if (capStr === undefined) {
|
|
448
|
+
throw usageError("bench burst needs a spend cap", `Pass --cap USD (or set PROMIGENCE_SPEND_CAP). Price it first: \`${sh `promigence run quote --snapshot ${snapshot} --count ${count}`}\`.`);
|
|
449
|
+
}
|
|
450
|
+
const spendCap = parseUsd(capStr, "--cap");
|
|
451
|
+
const keep = bool(ctx, "--keep");
|
|
452
|
+
const c = client(ctx);
|
|
453
|
+
const t0 = Date.now();
|
|
454
|
+
const started = await c.runs.start({ snapshot, count, spendCap, timeoutMs });
|
|
455
|
+
const runId = started.run_id;
|
|
456
|
+
ctx.startedRunId = runId;
|
|
457
|
+
let waited;
|
|
458
|
+
let wallMs;
|
|
459
|
+
let report;
|
|
460
|
+
let killed = false;
|
|
461
|
+
try {
|
|
462
|
+
waited = await c.runs.waitReady(runId, { waitTimeoutMs: timeoutMs + 10_000 });
|
|
463
|
+
wallMs = Date.now() - t0;
|
|
464
|
+
report = await c.runs.report(runId).catch(() => undefined);
|
|
465
|
+
}
|
|
466
|
+
finally {
|
|
467
|
+
if (!keep)
|
|
468
|
+
killed = await c.runs.kill(runId).then(() => true, () => false);
|
|
469
|
+
}
|
|
470
|
+
const up = waited.sandboxes.filter((s) => s.state === "ready" || s.state === "running").length;
|
|
471
|
+
const successPct = Math.round((up / count) * 1000) / 10;
|
|
472
|
+
const fork = report ? forkSummary(report.fork) : {};
|
|
473
|
+
const next = nexts([sh `promigence run report ${runId} --json`, "the validity report behind these numbers"], ...(killed ? [] : [[sh `promigence run kill ${runId}`, keep ? "end the burst (--keep left it running and billing)" : "the kill did not complete: end the burst"]]));
|
|
474
|
+
const env = {
|
|
475
|
+
...okEnvelope(ctx.cmd.name, {
|
|
476
|
+
run_id: runId,
|
|
477
|
+
requested: { snapshot, count, timeout_ms: timeoutMs, spend_cap: spendCap },
|
|
478
|
+
up,
|
|
479
|
+
success_pct: successPct,
|
|
480
|
+
wall_ms: wallMs,
|
|
481
|
+
waited_ms: waited.waitedMs,
|
|
482
|
+
timed_out: waited.timedOut,
|
|
483
|
+
fork,
|
|
484
|
+
...(report?.totals ? { totals: report.totals } : {}),
|
|
485
|
+
sandboxes: waited.sandboxes,
|
|
486
|
+
killed,
|
|
487
|
+
}, next),
|
|
488
|
+
ok: up === count,
|
|
489
|
+
};
|
|
490
|
+
const pct = (k) => {
|
|
491
|
+
const v = fork[k];
|
|
492
|
+
return v ? `${k} p50 ${ms(v.p50 ?? 0)} · p95 ${ms(v.p95 ?? 0)}${v.p99 === undefined ? "" : ` · p99 ${ms(v.p99)}`}` : "";
|
|
493
|
+
};
|
|
494
|
+
const lines = [
|
|
495
|
+
`burst ${runId}: ${up}/${count} up (${successPct}%) in ${ms(wallMs)}`,
|
|
496
|
+
...["e2e_ms", "fork_ms", "ready_ms", "queued_ms"].map(pct).filter(Boolean).map((l) => ` ${l}`),
|
|
497
|
+
...(waited.timedOut ? [` timed out after ${ms(timeoutMs + 10_000)}: ${count - up} never came up`] : []),
|
|
498
|
+
killed ? " sandboxes killed" : keep ? " --keep: sandboxes left running, billed until killed or --timeout" : " the kill did not complete: run the kill below",
|
|
499
|
+
` next: ${next.map((n) => n.cmd).join(" · ")}`,
|
|
500
|
+
];
|
|
501
|
+
return emit(ctx.mode, env, lines, up === count ? 0 : 3, ctx.pointer);
|
|
502
|
+
};
|
|
503
|
+
export const EXTRA_HANDLERS = {
|
|
504
|
+
"bench burst": benchBurst,
|
|
505
|
+
"agent-guide": agentGuide,
|
|
506
|
+
init,
|
|
507
|
+
examples,
|
|
508
|
+
doctor,
|
|
509
|
+
ping,
|
|
510
|
+
"exec output": execOutput,
|
|
511
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export * from "./sdk/index.js";
|
|
2
|
+
export { SCHEMA, GUIDE_POINTER, GOLDEN_PATH, COMMANDS, LISTED_COMMANDS, GROUPS, GLOBAL_FLAGS, EXIT_CODES, LIVE_COMMANDS, LIVE_SUMMARY, NOT_LIVE_SUMMARY, STATUS_LINE, DESCRIPTION, compactNames, EXIT_PRECEDENCE, EXIT_PRECEDENCE_TEXT, OUTPUT_MODE_PRECEDENCE, WAIT_TIMEOUT_DEFAULT, REQUEST_TIMEOUT_DEFAULT, GUIDE_COMMON_ERRORS, findCommand, knownFlags, nearestFlag, unknownFlags, renderHelp, renderCommandHelp, signInLine, notReleasedEnvelope, notReleasedLines, } from "./surface.js";
|
|
3
|
+
export { ALL_ERROR_CODES, BILLED_TEXT, BUDGETS, SECTIONS, estimateTokens, guideJson, lookupError, renderGuide, renderLlmsTxt,
|
|
4
|
+
renderGuide as renderAgentGuide, } from "./guide.js";
|
|
5
|
+
export type { Section } from "./guide.js";
|
|
6
|
+
export { CLIENT_ERRORS, CLIENT_ERROR_BY_CODE, ERRORS, ERROR_BY_CODE, TIERS, BUILD_MAX_S, PRICING } from "./generated.js";
|
|
7
|
+
export type { ErrorEntry, TierEntry } from "./generated.js";
|
|
8
|
+
export { FENCE_BEGIN, FENCE_END, FENCE_MAX_LINES, fenceBody, install, spliceFence } from "./install.js";
|
|
9
|
+
export type { Artifact, InstallResult } from "./install.js";
|
|
10
|
+
export { detect, gitFacts, normalizeRemote, readConfig, renderConfig, stripRemoteCredentials } from "./init.js";
|
|
11
|
+
export type { Config, Detection, Ecosystem, GitFacts, ReadConfig } from "./init.js";
|
|
12
|
+
export { DEVCONTAINER_NAMES, DEVCONTAINER_SPEC, DevcontainerError, detectOne, discover, load, parseJsonc, planJson, planLines, planSetup, resolveGiven, shellQuote, snapshotEnv, snapshotUsers, substituteString, translate, workspaceRootFor, wrapCommand, } from "./devcontainer.js";
|
|
13
|
+
export type { LoadedDevcontainer, Plan, PlanSource, LifecycleStep, IgnoredProperty } from "./devcontainer.js";
|
|
14
|
+
export type { Command, Flag, Group, CommandStatus, ExitCode, Envelope, EnvelopeError, NextHint } from "./surface.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from "./sdk/index.js";
|
|
2
|
+
export { SCHEMA, GUIDE_POINTER, GOLDEN_PATH, COMMANDS, LISTED_COMMANDS, GROUPS, GLOBAL_FLAGS, EXIT_CODES, LIVE_COMMANDS, LIVE_SUMMARY, NOT_LIVE_SUMMARY, STATUS_LINE, DESCRIPTION, compactNames, EXIT_PRECEDENCE, EXIT_PRECEDENCE_TEXT, OUTPUT_MODE_PRECEDENCE, WAIT_TIMEOUT_DEFAULT, REQUEST_TIMEOUT_DEFAULT, GUIDE_COMMON_ERRORS, findCommand, knownFlags, nearestFlag, unknownFlags, renderHelp, renderCommandHelp, signInLine, notReleasedEnvelope, notReleasedLines, } from "./surface.js";
|
|
3
|
+
export { ALL_ERROR_CODES, BILLED_TEXT, BUDGETS, SECTIONS, estimateTokens, guideJson, lookupError, renderGuide, renderLlmsTxt, renderGuide as renderAgentGuide, } from "./guide.js";
|
|
4
|
+
export { CLIENT_ERRORS, CLIENT_ERROR_BY_CODE, ERRORS, ERROR_BY_CODE, TIERS, BUILD_MAX_S, PRICING } from "./generated.js";
|
|
5
|
+
export { FENCE_BEGIN, FENCE_END, FENCE_MAX_LINES, fenceBody, install, spliceFence } from "./install.js";
|
|
6
|
+
export { detect, gitFacts, normalizeRemote, readConfig, renderConfig, stripRemoteCredentials } from "./init.js";
|
|
7
|
+
export { DEVCONTAINER_NAMES, DEVCONTAINER_SPEC, DevcontainerError, detectOne, discover, load, parseJsonc, planJson, planLines, planSetup, resolveGiven, shellQuote, snapshotEnv, snapshotUsers, substituteString, translate, workspaceRootFor, wrapCommand, } from "./devcontainer.js";
|
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type Ecosystem = "bun" | "pnpm" | "yarn" | "npm" | "uv" | "poetry" | "pipenv" | "pip" | "pyproject" | "cargo" | "go" | "bundler" | "composer" | "unknown";
|
|
2
|
+
export interface Detection {
|
|
3
|
+
ecosystem: Ecosystem;
|
|
4
|
+
lockfile?: string;
|
|
5
|
+
setup: string[];
|
|
6
|
+
verify: string;
|
|
7
|
+
toolchain: string[];
|
|
8
|
+
why: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function detect(dir: string): Detection;
|
|
11
|
+
export declare function stripRemoteCredentials(url: string): string;
|
|
12
|
+
export declare function normalizeRemote(url: string): string;
|
|
13
|
+
export interface GitFacts {
|
|
14
|
+
repo?: string;
|
|
15
|
+
commit?: string;
|
|
16
|
+
branch?: string;
|
|
17
|
+
dirty?: boolean;
|
|
18
|
+
credentialsRemoved?: boolean;
|
|
19
|
+
onRemote?: boolean;
|
|
20
|
+
noRemoteRefs?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function gitFacts(dir: string): GitFacts;
|
|
23
|
+
export declare const INIT_IMAGES: Partial<Record<string, string>>;
|
|
24
|
+
export declare function ecosystemOfCommands(commands: readonly string[]): string | undefined;
|
|
25
|
+
export declare function imageCreateCommand(c: Pick<Config, "repo" | "commit" | "setup" | "verify"> & {
|
|
26
|
+
tier?: string | undefined;
|
|
27
|
+
}, ecosystem: string): string;
|
|
28
|
+
export interface Config {
|
|
29
|
+
repo: string;
|
|
30
|
+
commit: string;
|
|
31
|
+
setup: string[];
|
|
32
|
+
verify: string;
|
|
33
|
+
tier: string;
|
|
34
|
+
toolchain: string[];
|
|
35
|
+
lockfile?: string;
|
|
36
|
+
alias?: string;
|
|
37
|
+
}
|
|
38
|
+
export type ReadConfig = Partial<Pick<Config, "repo" | "commit" | "tier" | "alias" | "verify" | "setup">>;
|
|
39
|
+
export declare function readConfig(text: string): ReadConfig;
|
|
40
|
+
export declare function renderConfig(c: Config, notes?: readonly string[], build?: string): string;
|