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.
Files changed (97) hide show
  1. package/NOTICE +14 -0
  2. package/README.md +88 -0
  3. package/dist/account.js +850 -0
  4. package/dist/agent.js +374 -0
  5. package/dist/argv.js +159 -0
  6. package/dist/bin.js +332 -0
  7. package/dist/bundle.js +133 -0
  8. package/dist/capacity.js +69 -0
  9. package/dist/commands.d.ts +110 -0
  10. package/dist/commands.js +2675 -0
  11. package/dist/connectreq.js +125 -0
  12. package/dist/credfile.js +188 -0
  13. package/dist/credits.js +197 -0
  14. package/dist/devcontainer.d.ts +99 -0
  15. package/dist/devcontainer.js +744 -0
  16. package/dist/device.js +129 -0
  17. package/dist/dirsnap.js +378 -0
  18. package/dist/errfix.js +262 -0
  19. package/dist/generated.d.ts +35 -0
  20. package/dist/generated.js +307 -0
  21. package/dist/github.js +307 -0
  22. package/dist/gitlab.js +210 -0
  23. package/dist/guide.d.ts +19 -0
  24. package/dist/guide.js +366 -0
  25. package/dist/handlers.js +511 -0
  26. package/dist/index.d.ts +14 -0
  27. package/dist/index.js +7 -0
  28. package/dist/init.d.ts +40 -0
  29. package/dist/init.js +352 -0
  30. package/dist/install.d.ts +23 -0
  31. package/dist/install.js +127 -0
  32. package/dist/io.d.ts +37 -0
  33. package/dist/io.js +318 -0
  34. package/dist/live.js +469 -0
  35. package/dist/login.js +1063 -0
  36. package/dist/mcp.js +889 -0
  37. package/dist/money.js +5 -0
  38. package/dist/orgs.js +475 -0
  39. package/dist/pricing.d.ts +52 -0
  40. package/dist/pricing.js +181 -0
  41. package/dist/report.js +132 -0
  42. package/dist/routes.js +135 -0
  43. package/dist/runners-github.js +257 -0
  44. package/dist/runners-gitlab.js +125 -0
  45. package/dist/runners-spec.js +137 -0
  46. package/dist/runners.js +1458 -0
  47. package/dist/sdk/blake3.d.ts +10 -0
  48. package/dist/sdk/blake3.js +111 -0
  49. package/dist/sdk/bundle.d.ts +96 -0
  50. package/dist/sdk/bundle.js +227 -0
  51. package/dist/sdk/ca-guard.js +166 -0
  52. package/dist/sdk/caller.d.ts +73 -0
  53. package/dist/sdk/caller.js +47 -0
  54. package/dist/sdk/client.d.ts +3015 -0
  55. package/dist/sdk/client.js +2583 -0
  56. package/dist/sdk/command-errors.d.ts +41 -0
  57. package/dist/sdk/command-errors.js +36 -0
  58. package/dist/sdk/context.d.ts +119 -0
  59. package/dist/sdk/context.js +588 -0
  60. package/dist/sdk/core.d.ts +285 -0
  61. package/dist/sdk/core.js +266 -0
  62. package/dist/sdk/credstore.d.ts +90 -0
  63. package/dist/sdk/credstore.js +206 -0
  64. package/dist/sdk/dispatcher.js +86 -0
  65. package/dist/sdk/github.d.ts +158 -0
  66. package/dist/sdk/github.js +78 -0
  67. package/dist/sdk/gitlab.d.ts +104 -0
  68. package/dist/sdk/gitlab.js +20 -0
  69. package/dist/sdk/handles.d.ts +82 -0
  70. package/dist/sdk/handles.js +135 -0
  71. package/dist/sdk/hint.js +7 -0
  72. package/dist/sdk/http2.js +1921 -0
  73. package/dist/sdk/index.d.ts +34 -0
  74. package/dist/sdk/index.js +15 -0
  75. package/dist/sdk/keyed.gen.js +7 -0
  76. package/dist/sdk/models.gen.d.ts +6162 -0
  77. package/dist/sdk/models.gen.js +1 -0
  78. package/dist/sdk/proxy.js +249 -0
  79. package/dist/sdk/pty.d.ts +171 -0
  80. package/dist/sdk/pty.js +496 -0
  81. package/dist/sdk/sandbox.d.ts +537 -0
  82. package/dist/sdk/sandbox.js +725 -0
  83. package/dist/sdk/ssh.d.ts +25 -0
  84. package/dist/sdk/ssh.js +114 -0
  85. package/dist/sdk/trace.js +80 -0
  86. package/dist/sdk/transport-worker.js +466 -0
  87. package/dist/sdk/warm.js +40 -0
  88. package/dist/ssh.js +267 -0
  89. package/dist/surface.d.ts +95 -0
  90. package/dist/surface.js +1452 -0
  91. package/dist/templates.js +53 -0
  92. package/dist/term.js +50 -0
  93. package/dist/timing.js +71 -0
  94. package/dist/untar.js +324 -0
  95. package/dist/uploadguard.js +75 -0
  96. package/llms.txt +209 -0
  97. package/package.json +52 -0
package/dist/guide.js ADDED
@@ -0,0 +1,366 @@
1
+ import { CLIENT_ERRORS, CLIENT_ERROR_BY_CODE, ERRORS, ERROR_BY_CODE, TIERS, BUILD_MAX_S, PRICING, } from "./generated.js";
2
+ export const BILLED_TEXT = {
3
+ no: "no: nothing is billed for this",
4
+ yes: "yes: the time used is billed",
5
+ credited: "no: ours, credited back",
6
+ unless_ours: "the time used is billed, unless the cause is shown to be ours: then it is credited back",
7
+ };
8
+ import { DOCS_URL, EXIT_CODES, EXIT_PRECEDENCE_TEXT, GOLDEN_PATH, GROUPS, GUIDE_COMMON_ERRORS, LISTED_COMMANDS, NOT_LIVE_SUMMARY, SCHEMA, VERSION, WAIT_TIMEOUT_DEFAULT, compactNames, } from "./surface.js";
9
+ export const SECTIONS = ["core", "commands", "errors", "cost"];
10
+ export const BUDGETS = {
11
+ core: 1500,
12
+ commands: 4500,
13
+ errors: 2325,
14
+ cost: 600,
15
+ };
16
+ export function lookupError(code) {
17
+ const own = (t) => Object.prototype.hasOwnProperty.call(t, code) ? t[code] : undefined;
18
+ return own(ERROR_BY_CODE) ?? own(CLIENT_ERROR_BY_CODE);
19
+ }
20
+ export const ALL_ERROR_CODES = [...ERRORS, ...CLIENT_ERRORS].map((e) => e.code);
21
+ export const estimateTokens = (s) => Math.ceil(s.length / 4);
22
+ const exitLine = EXIT_CODES.filter((e) => e.code !== 125 && e.code !== 13).map((e) => `${e.code} ${e.name}`).join(" · ");
23
+ const codesOn = (n) => ERRORS.filter((e) => e.exit === n).map((e) => e.code).join(", ");
24
+ const EXIT_NOTE = {
25
+ 7: codesOn(7),
26
+ 10: `${codesOn(10)} only: retry after Retry-After`,
27
+ 12: `some sandboxes ${codesOn(12)}`,
28
+ 13: "agent-guide --check: files would change",
29
+ 125: "exec --sandbox: ours; else the command's code",
30
+ };
31
+ const exitLegend = EXIT_CODES.map((e) => `${e.code} ${e.name}${EXIT_NOTE[e.code] ? ` (${EXIT_NOTE[e.code]})` : ""}`).join(" · ");
32
+ const liveNames = new Set(LISTED_COMMANDS.map((c) => c.name));
33
+ const HOSTED_LIVE = compactNames(LISTED_COMMANDS.filter((c) => !c.notOnHosted).map((c) => c.name));
34
+ const NOT_ON_HOSTED = LISTED_COMMANDS.filter((c) => c.notOnHosted);
35
+ const COUNT_WORDS = ["no", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"];
36
+ const exitOf = (code) => {
37
+ const e = ERROR_BY_CODE[code];
38
+ if (!e)
39
+ throw new Error(`the guide names ${code}, which is not a known error code`);
40
+ return e.exit;
41
+ };
42
+ function renderCore() {
43
+ const common = GUIDE_COMMON_ERRORS.map((code) => {
44
+ const e = ERROR_BY_CODE[code];
45
+ if (!e)
46
+ throw new Error(`GUIDE_COMMON_ERRORS names ${code}, which is not a known error code`);
47
+ return `- \`${e.code}\` (exit ${e.exit}) — ${e.fix}`;
48
+ });
49
+ return [
50
+ `# Promigence — agent guide (promigence@${VERSION})`,
51
+ "",
52
+ "Promigence is an **environment runtime**: verified, reproducible, forkable execution",
53
+ "environments, billed per second (vCPU + memory). The model is one line:",
54
+ "",
55
+ " verify → snapshot → fork(N) → exec → validity report",
56
+ "",
57
+ "- **snapshot** — an image (pinned) + ordered `setup` steps + a `verify` command that, if given, must exit 0.",
58
+ " If verify fails nothing is stored; the build's own time is billed. A branch is not a pin.",
59
+ "- **fork** — a warm copy of that workspace, with its `start` service ready;",
60
+ " N at once, each checked before you get it.",
61
+ "- **validity report** — per sandbox, and this split is the product: **env** failures are ours",
62
+ " (exit 3, replayable; when our side shows the cause, the time since your last snapshot is",
63
+ " credited back, up to 24 h) and **task** failures are yours (exit 4, billed).",
64
+ "",
65
+ "## Golden path",
66
+ "",
67
+ ` ${GOLDEN_PATH}`,
68
+ "",
69
+ "That forks 2 sandboxes of the built-in base, runs the command in each, prints the report and",
70
+ "kills them. Find public snapshots with `promigence examples` (no API key needed).",
71
+ "Build your own: `promigence init` in a repo prints the `snapshot create --image … --wait` to run.",
72
+ "",
73
+ "## Output contract",
74
+ "",
75
+ "Exactly one JSON document on stdout per invocation, whenever `--json` is passed or stdout is",
76
+ "not a TTY; `exec --sandbox` needs `--json` for it:",
77
+ "",
78
+ ` {"schema":"${SCHEMA}","command":…,"ok":…,`,
79
+ ' "error":{"code","message","fix","docs","guide"},"next":[{"cmd","why"}]}',
80
+ "",
81
+ "Progress, prices and diagnostics go to **stderr** — never parse them. `next[].cmd` is",
82
+ "id-based, runnable verbatim (fill any UPPERCASE word); use it, never invent one.",
83
+ "",
84
+ `Exit codes: ${exitLegend}.`,
85
+ `Highest-precedence code wins: ${EXIT_PRECEDENCE_TEXT}.`,
86
+ "",
87
+ `## The ${COUNT_WORDS[common.length] ?? common.length} you will actually hit`,
88
+ "",
89
+ "(`{name}` in a fix is filled from the failure's evidence.)",
90
+ "",
91
+ ...common,
92
+ "",
93
+ "## Limits and stops",
94
+ "",
95
+ `- \`setup_required\` (exit ${exitOf("setup_required")}): answer the account's setup questions in the console first.`,
96
+ `- \`egress_cap_reached\` (exit ${exitOf("egress_cap_reached")}): the month's data out is spent; \`--network none\` still starts; it resets on the 1st (UTC).`,
97
+ "- A paused sandbox is kept 30 days (`pause_expires_at`); resuming keeps it, else it is deleted (`expired`).",
98
+ `- \`stopped_by_support\` (exit ${exitOf("stopped_by_support")}): support stopped it; the message says why.`,
99
+ "",
100
+ "## Do",
101
+ "",
102
+ "- Pass `--cap USD` on every `fork`/`run`: a run over it is refused (exit 5) before anything starts.",
103
+ "- Pass `--json`, and read `ok`, `error.code` and `next` — not the text.",
104
+ `- Use \`--wait\`. **Every wait is bounded to ${WAIT_TIMEOUT_DEFAULT}**: exit 11 means the wait expired and`,
105
+ " **nothing was killed** — run the id-based `next` command to keep waiting.",
106
+ "- Treat exit 3 as ours (re-run or `run replay`) and exit 4 as yours (fix the task).",
107
+ "- Pass the full 40-character commit sha to `snapshot create`.",
108
+ "",
109
+ "## Don't",
110
+ "",
111
+ "- Never put a key or a secret on argv: `auth login` reads `--from-env VAR` or stdin, `secrets",
112
+ " set` also `--from-file P`. Secrets are given at run time, never baked in.",
113
+ "- Don't poll in a loop — `--wait` long-polls server-side and costs one request.",
114
+ ...(liveNames.has("run replay")
115
+ ? ["- Don't re-fork blindly on an env failure: `promigence run replay <run_id>` re-runs it."]
116
+ : [
117
+ "- Don't re-fork on exit 3 without reading the report: an env failure is already retried",
118
+ " once before hand-off, at no charge — so a blind re-fork hides our bug.",
119
+ ]),
120
+ "",
121
+ "## More",
122
+ "",
123
+ "`promigence agent-guide --section commands|errors|cost` · `promigence agent-guide --code <code>`",
124
+ `· \`promigence <command> --help\` · ${DOCS_URL}`,
125
+ "Same surface as MCP tools: `promigence mcp` (stdio; `claude mcp add promigence -- promigence mcp`).",
126
+ "",
127
+ `Live in v${VERSION}: ${HOSTED_LIVE}`,
128
+ ...(NOT_ON_HOSTED.length
129
+ ? [`Not on the hosted service yet: ${compactNames(NOT_ON_HOSTED.map((c) => c.name))} (${[...new Set(NOT_ON_HOSTED.map((c) => c.notOnHosted))].join(", ")}).`]
130
+ : []),
131
+ ...(NOT_LIVE_SUMMARY ? ["Every other command exits 1 `not_released` in the same envelope."] : []),
132
+ "",
133
+ ].join("\n");
134
+ }
135
+ function commandUsage(c) {
136
+ const req = c.flags.filter((f) => f.required).map((f) => `${f.name} ${f.arg ?? ""}`.trim());
137
+ return `promigence ${c.name}${req.length ? " " + req.join(" ") : ""}${c.args ? " " + c.args : ""}`;
138
+ }
139
+ const SAID_ONCE = new Set(["--json", "--no-browser", "--yes"]);
140
+ function optionalFlags(c) {
141
+ const opt = c.flags.filter((f) => !f.required && !f.hidden && !SAID_ONCE.has(f.name)).map((f) => f.name);
142
+ return opt.length ? opt.join(" ") : "";
143
+ }
144
+ function chainEdges() {
145
+ const edges = new Map();
146
+ for (const c of LISTED_COMMANDS) {
147
+ if (c.next.length === 0)
148
+ continue;
149
+ const from = edges.get(c.next[0]);
150
+ if (from)
151
+ from.push(c.name);
152
+ else
153
+ edges.set(c.next[0], [c.name]);
154
+ }
155
+ return [...edges].map(([to, from]) => `- \`${to}\` ← ${from.join(" · ")}`);
156
+ }
157
+ function renderCommands() {
158
+ const out = [
159
+ `# Promigence — every command (promigence@${VERSION})`,
160
+ "",
161
+ "`✓` = live now. Required flags are shown; optional ones are",
162
+ "listed after `+` (every command also takes `--json`; one that signs in, `--no-browser` and",
163
+ "`--yes`). Full detail: `promigence <command> --help`.",
164
+ ];
165
+ for (const g of GROUPS) {
166
+ out.push("", `## ${g}`, "");
167
+ for (const c of LISTED_COMMANDS) {
168
+ if (c.group !== g)
169
+ continue;
170
+ out.push(`- ✓ \`${commandUsage(c)}\` — ${c.summary}`);
171
+ const opt = optionalFlags(c);
172
+ if (opt)
173
+ out.push(` + ${opt}`);
174
+ if (c.note)
175
+ out.push(` ! ${c.note}`);
176
+ }
177
+ }
178
+ out.push("", "## Chaining", "", "Every envelope carries `next`. Each next command, then the commands that name it first:", "", ...chainEdges(), "", `Golden path: \`${GOLDEN_PATH}\``, "");
179
+ return out.join("\n");
180
+ }
181
+ const CATEGORY_NOTE = {
182
+ env: "ours, replayable; a run with a command retries once first. Not billed before hand-over; after it, credited back from your last snapshot (≤ 24 h) when our side shows the cause, else billed as used",
183
+ snapshot: "billed — the snapshot's `verify` did not cover what broke",
184
+ task: "billed — the environment was verified and your command failed",
185
+ grader: "the episode is billed, the grade is not — your work was never judged",
186
+ cap: "the spend cap did its job",
187
+ preempt: "ours — the capacity was given back; credited back from your last snapshot (≤ 24 h), and replayable",
188
+ other: "client / API conditions",
189
+ };
190
+ const CATEGORY_ORDER = ["env", "preempt", "snapshot", "task", "grader", "cap", "other"];
191
+ function renderErrors() {
192
+ const out = [
193
+ `# Promigence — error codes (promigence@${VERSION})`,
194
+ "",
195
+ `Envelope: \`error:{code,message,fix,docs,guide}\`. ${EXIT_PRECEDENCE_TEXT} (highest wins).`,
196
+ "One entry, with its `fix` and HTTP status: `promigence agent-guide --code <code>`.",
197
+ ];
198
+ const seen = new Set(CATEGORY_ORDER);
199
+ const cats = [...CATEGORY_ORDER, ...[...new Set(ERRORS.map((e) => e.category))].filter((c) => !seen.has(c)).sort()];
200
+ for (const cat of cats) {
201
+ const rows = ERRORS.filter((e) => e.category === cat);
202
+ if (!rows.length)
203
+ continue;
204
+ out.push("", `## ${cat}${CATEGORY_NOTE[cat] ? ` — ${CATEGORY_NOTE[cat]}` : ""}`, "");
205
+ for (const e of rows)
206
+ out.push(`- \`${e.code}\` exit ${e.exit} — ${e.message}`);
207
+ }
208
+ out.push("", "## client — made by the SDK or the CLI itself; never sent by the API", "");
209
+ for (const e of CLIENT_ERRORS)
210
+ out.push(`- \`${e.code}\` exit ${e.exit} — ${e.message}`);
211
+ out.push("", "## Exit codes", "", exitLine, "125 passthrough (`exec --sandbox`: Promigence's own failure; the child's code passes through", "otherwise, a command not found exits 127, and the real code travels as `promigence_exit`).", "13 changes_pending (`agent-guide --check`: the files would change; nothing was written).", "", `Fixes for the commonest: ${GUIDE_COMMON_ERRORS.map((c) => `\`${c}\``).join(" ")}`, "— `promigence agent-guide --section errors --code <code>`.", "");
212
+ return out.join("\n");
213
+ }
214
+ function renderCode(code) {
215
+ const e = lookupError(code);
216
+ if (!e) {
217
+ const near = ALL_ERROR_CODES.filter((c) => c.includes(code) || code.includes(c));
218
+ return [
219
+ `# ${code} — not an error code`,
220
+ "",
221
+ near.length ? `Did you mean: ${near.map((c) => `\`${c}\``).join(", ")}?` : "",
222
+ "Every code: `promigence agent-guide --section errors`.",
223
+ "",
224
+ ].filter(Boolean).join("\n");
225
+ }
226
+ const client = CLIENT_ERROR_BY_CODE[e.code] !== undefined;
227
+ return [
228
+ client
229
+ ? `# \`${e.code}\` — ${e.category}, exit ${e.exit}; made by the SDK or the CLI (the API never sends it)`
230
+ : `# \`${e.code}\` — ${e.category}, exit ${e.exit}, HTTP ${e.http}`,
231
+ "",
232
+ `**Message** (\`{name}\` is filled from the failure's evidence): ${e.message}`,
233
+ "",
234
+ `**Fix**: ${e.fix}`,
235
+ "",
236
+ `**Billed**: ${BILLED_TEXT[e.billed] ?? e.billed}`,
237
+ "",
238
+ `**Category**: ${e.category} — ${CATEGORY_NOTE[e.category] ?? ""}`,
239
+ "",
240
+ ].join("\n");
241
+ }
242
+ function renderCost(prices) {
243
+ const perHour = (r) => `$${(r * 3600).toFixed(4)}`;
244
+ const tiers = prices?.tiers ?? TIERS.filter((t) => t.sellable);
245
+ const vcpu = prices?.vcpu_second_usd ?? PRICING.vcpu_second_usd;
246
+ const gib = prices?.gib_second_usd ?? PRICING.gib_second_usd;
247
+ const granularity = prices?.granularity_seconds ?? PRICING.granularity_seconds;
248
+ const buildMax = prices?.build_max_s ?? BUILD_MAX_S;
249
+ const buildHours = buildMax % 3600 === 0 ? `${buildMax / 3600} h` : `${Math.ceil(buildMax / 60)} min`;
250
+ const view = prices?.view;
251
+ const source = prices === undefined
252
+ ? "List prices when this CLI was built. Live, and your plan's: `promigence pricing`."
253
+ : prices.source === "api"
254
+ ? `Live from the API (${view?.as_of ?? "now"}): your organization's prices. \`promigence pricing\` shows the rest.`
255
+ : prices.source === "published"
256
+ ? "Published list prices. Your organization's own: `promigence login`, then `promigence pricing`."
257
+ : `${prices.note ?? "list prices at build time; could not reach the API"} (\`promigence pricing\` asks again).`;
258
+ const limit = view?.limits.max_sandbox_vcpus;
259
+ const out = [
260
+ `# Promigence — what it costs (promigence@${VERSION})`,
261
+ "",
262
+ source,
263
+ "",
264
+ "Billing is **per second**, like the rest of the market: a sandbox bills",
265
+ `$${vcpu} per vCPU-second + $${gib} per GiB-second, from hand-over`,
266
+ `to end, rounded up to ${granularity} s, no minimum. Paused time is not billed.`,
267
+ "",
268
+ "| tier | vCPU | RAM | disk | $/second | $/hour |",
269
+ "|---|---|---|---|---|---|",
270
+ ...tiers.map((t) => `| \`${t.name}\` | ${t.vcpus} | ${t.mem_gib} GiB | ${t.disk_gib} GiB | $${t.per_second_usd} | ${perHour(t.per_second_usd)} |`),
271
+ ...(typeof limit === "number" ? ["", `Your plan runs sandboxes of up to ${limit} vCPU.`] : []),
272
+ "",
273
+ `Building a snapshot bills per second at its tier's rate while it runs, at most ${buildHours} (the most it can`,
274
+ "cost is printed on stderr **before** the build starts; what it cost, when it ends). A build that",
275
+ "fails `verify` or a guard stores nothing and is billed the time it ran; one that fails on our",
276
+ "side is not billed, and reusing an identical build is free.",
277
+ "",
278
+ "`env` failures (`promigence agent-guide --section errors`): one before hand-over is not billed,",
279
+ "e.g. " + ERRORS.filter((e) => e.category === "env").slice(0, 3).map((e) => `\`${e.code}\``).join(", ") + ". After hand-over, a failure our",
280
+ "side shows was ours (a lost host, a memory or disk fault under the tier) is billed to the",
281
+ "failure and the time since your last snapshot of that sandbox is credited back, up to 24 h; one",
282
+ "it cannot show (a sandbox that goes silent on its own) is billed as used. A replay bills as new.",
283
+ "",
284
+ "Controls:",
285
+ "",
286
+ "- `--cap USD` — refused (exit 5) before anything starts if the quote",
287
+ " (count × timeout × rate) exceeds it; a sandbox is paused, its state kept, when its accrued spend reaches its share.",
288
+ "- `--allow-partial` — start what fits; the rest report `not_started` (exit 12).",
289
+ "- `--timeout DUR` — the most one sandbox can cost; finishing early costs less.",
290
+ `- \`promigence run quote\` — the most the run's sandbox time can cost, before you run (data out is not in it); \`promigence me\` — spend to date.`,
291
+ "",
292
+ ];
293
+ return out.filter((l) => l !== undefined).join("\n");
294
+ }
295
+ export const HUMAN_START = "promigence run --count 1 --cap 1 -- python3 -c 'print(6*7)'";
296
+ export function humanHeader() {
297
+ return `For people: this is the guide your coding agent reads, dense on purpose.\nStart here: ${HUMAN_START}\n\n`;
298
+ }
299
+ export function renderGuide(opts = {}) {
300
+ if (opts.code)
301
+ return renderCode(opts.code);
302
+ switch (opts.section ?? "core") {
303
+ case "commands": return renderCommands();
304
+ case "errors": return renderErrors();
305
+ case "cost": return renderCost(opts.prices);
306
+ default: return renderCore();
307
+ }
308
+ }
309
+ export function guideJson(opts = {}) {
310
+ const section = opts.code ? "errors" : (opts.section ?? "core");
311
+ const guide = renderGuide(opts);
312
+ const body = {
313
+ format: "md",
314
+ section,
315
+ tokens: estimateTokens(guide),
316
+ budget: BUDGETS[section] ?? BUDGETS.core,
317
+ guide,
318
+ };
319
+ if (opts.code)
320
+ body["error"] = lookupError(opts.code) ?? null;
321
+ else if (section === "errors") {
322
+ body["errors"] = ERRORS;
323
+ body["client_errors"] = CLIENT_ERRORS;
324
+ }
325
+ else if (section === "cost") {
326
+ body["tiers"] = opts.prices?.tiers ?? TIERS.filter((t) => t.sellable);
327
+ body["prices_source"] = opts.prices?.source ?? "compiled";
328
+ body["prices_note"] = opts.prices === undefined ? "list prices when this CLI was built" : (opts.prices.note ?? null);
329
+ }
330
+ else if (section === "commands") {
331
+ body["commands"] = LISTED_COMMANDS.map((c) => ({
332
+ name: c.name, group: c.group, summary: c.summary, status: c.status,
333
+ usage: commandUsage(c), args: c.args ?? null,
334
+ flags: c.flags.filter((f) => !f.hidden).map((f) => f.name), next: c.next,
335
+ }));
336
+ }
337
+ else {
338
+ body["model"] = "verify → snapshot → fork(N) → exec → validity report";
339
+ body["golden_path"] = GOLDEN_PATH;
340
+ body["exit_codes"] = EXIT_CODES;
341
+ body["common_errors"] = GUIDE_COMMON_ERRORS.map((c) => ERROR_BY_CODE[c]).filter(Boolean);
342
+ }
343
+ return body;
344
+ }
345
+ export function renderLlmsTxt() {
346
+ return [
347
+ `# Promigence — promigence@${VERSION}`,
348
+ "",
349
+ "> Verified, reproducible, forkable execution environments for agents. The CLI is the",
350
+ "> `promigence` command (package `promigence`, which is also the TypeScript SDK).",
351
+ "",
352
+ "## Index",
353
+ "",
354
+ ...LISTED_COMMANDS.map((c) => `- \`promigence ${c.name}\` — ${c.summary}${c.notOnHosted ? ` (not on the hosted service yet)` : ""}`),
355
+ "",
356
+ "- `promigence agent-guide` — this document's first section",
357
+ "- `promigence agent-guide --section commands` — every command with its flags",
358
+ "- `promigence agent-guide --section errors` — every error code and exit code",
359
+ "- `promigence agent-guide --section cost` — tiers and per-second prices",
360
+ `- ${DOCS_URL}`,
361
+ "",
362
+ "---",
363
+ "",
364
+ renderCore(),
365
+ ].join("\n");
366
+ }