@toon-protocol/rig 4.5.0 → 4.6.0
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/README.md +13 -5
- package/dist/{chunk-S2BMLXAD.js → chunk-DCGV6ALH.js} +429 -14
- package/dist/chunk-DCGV6ALH.js.map +1 -0
- package/dist/{chunk-HMED76GU.js → chunk-JBFBD7HV.js} +99 -55
- package/dist/chunk-JBFBD7HV.js.map +1 -0
- package/dist/{chunk-UZZ2JKEC.js → chunk-X232W4TG.js} +491 -185
- package/dist/chunk-X232W4TG.js.map +1 -0
- package/dist/{ci-serve-PYEHIBN7.js → ci-serve-AYFZOY4O.js} +8 -19
- package/dist/ci-serve-AYFZOY4O.js.map +1 -0
- package/dist/cli/rig.js +4 -3
- package/dist/cli/rig.js.map +1 -1
- package/dist/index.d.ts +362 -20
- package/dist/index.js +494 -3
- package/dist/index.js.map +1 -1
- package/dist/{publisher-Cf6tKnZ3.d.ts → publisher-DgbfziOm.d.ts} +152 -26
- package/dist/standalone/index.d.ts +1 -1
- package/dist/{standalone-mode-W3ZEKC6M.js → standalone-mode-UQSP4677.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-HMED76GU.js.map +0 -1
- package/dist/chunk-S2BMLXAD.js.map +0 -1
- package/dist/chunk-UZZ2JKEC.js.map +0 -1
- package/dist/ci-serve-PYEHIBN7.js.map +0 -1
- /package/dist/{standalone-mode-W3ZEKC6M.js.map → standalone-mode-UQSP4677.js.map} +0 -0
package/dist/cli/rig.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/rig.ts","../../src/cli/output.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `rig` — the git-native TOON CLI shipped by `@toon-protocol/rig` (epic\n * #222; standalone-only since #248; git passthrough since #250).\n *\n * rig-owned subcommands (see ./dispatch.ts):\n * init one-shot repo setup (identity + toon.* git config)\n * remote relays as git remotes (#249): add/remove/list\n * push estimate → confirm → execute (#229)\n * issue | comment | pr single NIP-34 event publishes (#231), incl.\n * `pr status` (moved from `rig status` in #250)\n * channel payment channels (#262/#263): list, open,\n * close, settle\n * fund | balance client money lifecycle (#263): devnet faucet\n * drip; wallet + channel balances\n *\n * Everything else is `git <argv...>` verbatim: `rig status` runs git status.\n *\n * STRICT `--json` STDOUT (#265): when a rig-owned command runs with `--json`,\n * stdout carries exactly one JSON document — the process-level stdout guard\n * reroutes every other write (including dependencies' `console.log`) to\n * stderr, the io layer sends human lines to stderr, and the post-dispatch\n * backstop emits an error envelope for paths that bailed before emitting.\n * The git passthrough is exempt: it inherits stdio verbatim (./output.ts).\n * The enforcement matrix in ./strict-json.test.ts mirrors this composition.\n */\n\nimport { createInterface } from 'node:readline/promises';\nimport { dispatch } from './dispatch.js';\nimport {\n calmBootstrapNoise,\n isJsonInvocation,\n makeCliIo,\n redirectStdoutToStderr,\n type RigIo,\n} from './output.js';\n\n/** Real terminal I/O: stdout/stderr sinks + readline y/N confirm. */\nfunction makeIo(jsonMode: boolean): RigIo {\n // Reframe the embedded client's expected announce-402 stderr noise (#280)\n // — installed for every mode, before any command code can run.\n calmBootstrapNoise();\n // In --json mode, patch process.stdout FIRST — before any command (or its\n // dynamically imported dependencies) can write — and keep the only real\n // stdout writer for the machine document.\n const guard = jsonMode ? redirectStdoutToStderr() : undefined;\n return makeCliIo({\n jsonMode,\n writeStdout: guard\n ? guard.write\n : (text) => {\n process.stdout.write(text);\n },\n writeStderr: (text) => {\n process.stderr.write(text);\n },\n isInteractive: Boolean(process.stdin.isTTY && process.stdout.isTTY),\n confirm: async (question) => {\n const rl = createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n try {\n const answer = (await rl.question(question)).trim().toLowerCase();\n return answer === 'y' || answer === 'yes';\n } finally {\n rl.close();\n }\n },\n });\n}\n\n/**\n * Exit as soon as stdio is flushed (#279). By the time dispatch resolves,\n * every command has finished its work and awaited its teardown — but the\n * embedded `@toon-protocol/client` can leave a keep-alive socket behind\n * that holds the Node event loop open for ~30 more seconds. That lingering\n * handle — not discovery or negotiation — was the bulk of the uniform\n * \"~32s per paid command\" tax the #279 study measured. Nothing rig can\n * reach unrefs it, so the one-shot CLI does what one-shot CLIs do: flush\n * and exit.\n */\nfunction exitWhenFlushed(code: number): void {\n process.exitCode = code;\n let pending = 2;\n const done = (): void => {\n pending -= 1;\n if (pending === 0) process.exit(code);\n };\n process.stdout.write('', done);\n process.stderr.write('', done);\n}\n\nconst argv = process.argv.slice(2);\nconst io = makeIo(isJsonInvocation(argv));\n\ndispatch(argv, {\n io,\n env: process.env,\n cwd: process.cwd(),\n}).then(\n (code) => {\n io.ensureSingleJsonDoc(code);\n exitWhenFlushed(code);\n },\n (err: unknown) => {\n process.stderr.write(\n `rig: unexpected error: ${err instanceof Error ? (err.stack ?? err.message) : String(err)}\\n`\n );\n io.ensureSingleJsonDoc(1);\n exitWhenFlushed(1);\n }\n);\n","/**\n * The rig CLI output layer (#265): the strict `--json` stdout guarantee.\n *\n * CONTRACT — when `--json` is set on a rig-owned command, stdout carries\n * EXACTLY ONE parseable JSON document and nothing else. Agents consume this\n * stream (`rig … --json | jq`), so any stray banner, progress line, warning,\n * deprecation nudge, or third-party `console.log` on stdout breaks pipelines\n * (the #260 addendum: `[Bootstrap] …` logs from the embedded client's core\n * polluted `rig push --json`). Everything human-facing goes to stderr.\n *\n * Three layers enforce the contract (composed in ./rig.ts; the enforcement\n * matrix in ./strict-json.test.ts mirrors that composition):\n *\n * 1. {@link makeCliIo} — the ONLY output surface commands use. In JSON mode\n * `out()` (human lines) reroutes to stderr and `emitJson()` is the sole\n * writer that reaches the real stdout.\n * 2. {@link redirectStdoutToStderr} — a process-level guard for code the io\n * seam cannot reach: dependencies that `console.log` directly (the\n * embedded `@toon-protocol/client`'s core bootstrap does). Installed\n * before any command code runs, it reroutes EVERY `process.stdout.write`\n * to stderr; only the writer it returns (wired into `emitJson`) still\n * reaches the real stdout.\n * 3. {@link RigIo.ensureSingleJsonDoc} — the backstop for paths that bail\n * out before emitting an envelope (usage errors, pre-payment refusals):\n * after dispatch it emits one error envelope built from the collected\n * stderr lines, so stdout is never empty in JSON mode.\n *\n * GIT PASSTHROUGH IS EXEMPT: `--json` is a per-subcommand flag on rig-owned\n * verbs, not a global rig flag. Any verb rig does not own goes to system git\n * with the EXACT argv tail and inherited stdio — `rig status --json` runs\n * `git status --json` (git rejects it), and flags BEFORE the subcommand\n * (`rig --json status`) are not rig's either: the whole argv passes through\n * to git verbatim. {@link isJsonInvocation} implements exactly that boundary.\n */\n\n// ---------------------------------------------------------------------------\n// The io seam\n// ---------------------------------------------------------------------------\n\n/** Terminal I/O seam — every rig-owned command writes ONLY through this. */\nexport interface CliIo {\n /**\n * One HUMAN-facing line: stdout normally, stderr when `--json` is active\n * (chatter must never pollute the machine stream).\n */\n out(line: string): void;\n /** One human-facing line to stderr (warnings, nudges, errors). */\n err(line: string): void;\n /**\n * THE machine-readable JSON document of a `--json` run — serialized here\n * (2-space indent) and written to the REAL stdout. Must be a command's\n * single stdout emission; call it at most once per invocation.\n */\n emitJson(payload: unknown): void;\n /** True when stdin+stdout are TTYs (interactive confirm possible). */\n isInteractive: boolean;\n /** Ask a y/N question; resolves true on explicit yes. */\n confirm(question: string): Promise<boolean>;\n}\n\n/** {@link CliIo} plus the JSON-mode bookkeeping the entrypoint needs. */\nexport interface RigIo extends CliIo {\n /** True when this invocation runs in `--json` mode. */\n readonly jsonMode: boolean;\n /** True once `emitJson` has written the machine document. */\n readonly emittedJson: boolean;\n /**\n * The #265 backstop: called once after dispatch (see ./rig.ts). In JSON\n * mode, when NO machine document was emitted (usage error, pre-payment\n * refusal, unexpected crash), emits one error envelope carrying the\n * human-facing lines the run wrote to stderr — so `--json` stdout always\n * parses. No-op outside JSON mode or after a real emission.\n */\n ensureSingleJsonDoc(exitCode: number): void;\n}\n\n/** Sinks + terminal facts {@link makeCliIo} builds a {@link RigIo} from. */\nexport interface CliIoOptions {\n /** Whether this invocation is a rig-owned command with `--json`. */\n jsonMode: boolean;\n /**\n * Write to the REAL stdout (in JSON mode: the pre-guard writer returned by\n * {@link redirectStdoutToStderr}). Receives full text including newlines.\n */\n writeStdout(text: string): void;\n /** Write to stderr. Receives full text including newlines. */\n writeStderr(text: string): void;\n isInteractive: boolean;\n confirm(question: string): Promise<boolean>;\n}\n\n/**\n * Build the {@link RigIo} for one invocation. Centralizes the #265 routing:\n * human lines → stderr in JSON mode, and `emitJson` as the only stdout path.\n */\nexport function makeCliIo(options: CliIoOptions): RigIo {\n const { jsonMode, writeStdout, writeStderr } = options;\n let emittedJson = false;\n /** Human lines collected in JSON mode — the backstop envelope's detail. */\n const humanLines: string[] = [];\n\n const toStderr = (line: string): void => {\n if (jsonMode) humanLines.push(line);\n writeStderr(`${line}\\n`);\n };\n\n return {\n jsonMode,\n get emittedJson() {\n return emittedJson;\n },\n out: (line) => {\n if (jsonMode) {\n toStderr(line);\n } else {\n writeStdout(`${line}\\n`);\n }\n },\n err: toStderr,\n emitJson: (payload) => {\n emittedJson = true;\n writeStdout(`${JSON.stringify(payload, null, 2)}\\n`);\n },\n isInteractive: options.isInteractive,\n confirm: options.confirm,\n ensureSingleJsonDoc(exitCode: number): void {\n if (!jsonMode || emittedJson) return;\n const detail =\n humanLines.join('\\n') ||\n (exitCode === 0\n ? 'the command produced no machine output'\n : 'the command failed before emitting machine output — see stderr');\n this.emitJson(\n exitCode === 0\n ? { error: null, exitCode, detail }\n : { error: 'error', exitCode, detail }\n );\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// JSON-mode detection (and the git-passthrough exemption)\n// ---------------------------------------------------------------------------\n\n/**\n * The verbs rig owns — everything else is `git <argv…>` verbatim. Must match\n * the ./dispatch.ts switch (dispatch.test.ts pins both directions).\n */\nexport const RIG_OWNED_VERBS: ReadonlySet<string> = new Set([\n 'init',\n 'identity',\n 'remote',\n 'clone',\n 'fetch',\n 'push',\n 'site',\n 'issue',\n 'comment',\n 'pr',\n 'maintainers',\n 'payout',\n 'channel',\n 'channels',\n 'fund',\n 'balance',\n 'chain',\n 'entry',\n 'name',\n 'ci',\n]);\n\n/**\n * True when this argv is a rig-owned command run with `--json` — the strict\n * stdout contract applies. Deliberately NOT true for:\n *\n * - non-owned verbs (`rig status --json` IS `git status --json`: inherited\n * stdio, git's own semantics, rig adds nothing);\n * - flags before the subcommand (`rig --json status`): rig has no global\n * flags besides help/--version, so the argv passes to git verbatim;\n * - `--json` after a bare `--` (parseArgs treats those tokens as\n * positionals, so rig's flag parsers never see it as a flag either).\n *\n * Mirrors a plain token scan rather than each command's full parseArgs\n * config: the one divergence is `--json` consumed as a STRING option's value\n * (e.g. `rig push --relay --json`) — a pathological invocation that ends up\n * with chatter on stderr and a backstop envelope on stdout, which still\n * honors the parse guarantee.\n */\nexport function isJsonInvocation(argv: string[]): boolean {\n const [verb, ...rest] = argv;\n if (verb === undefined || !RIG_OWNED_VERBS.has(verb)) return false;\n for (const arg of rest) {\n if (arg === '--') return false;\n if (arg === '--json') return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Process-level stdout guard (third-party console.log defense)\n// ---------------------------------------------------------------------------\n\n/** Handle on an installed stdout guard. */\nexport interface StdoutGuard {\n /** Write to the REAL stdout (bypasses the redirection). */\n write(text: string): void;\n /** Undo the patch (tests; the one-shot CLI process never needs it). */\n restore(): void;\n}\n\n/**\n * Reroute every `process.stdout.write` — including `console.log` from\n * dependencies rig cannot re-route at the io seam, like the embedded\n * client's `[Bootstrap] …` logs (#260) — to stderr. Returns the ONLY writer\n * that still reaches the real stdout; ./rig.ts wires it into\n * {@link makeCliIo}'s `writeStdout` so `emitJson` output is the single\n * survivor on the machine stream.\n *\n * @param realWrite Override the saved real-stdout writer (tests capture it);\n * defaults to the unpatched `process.stdout.write`.\n */\n// ---------------------------------------------------------------------------\n// Process-level stderr calmer (third-party bootstrap noise defense, #280)\n// ---------------------------------------------------------------------------\n\n/** Handle on an installed stderr calmer. */\nexport interface StderrCalmer {\n /** Undo the patch (tests; the one-shot CLI process never needs it). */\n restore(): void;\n}\n\n/** The embedded client's core self-announce failure log line. */\nconst ANNOUNCE_FAILED_RE = /\\[Bootstrap\\] Announce failed/;\n/** … specifically the EXPECTED pre-payment 402 refusal (x402 challenge). */\nconst ANNOUNCE_402_RE = /402|payment required/i;\n\n/**\n * The calm reframe of the announce-402: what happened, why it is expected,\n * and that the command is unaffected — instead of a full x402 challenge JSON\n * dump. Exported so tests pin the exact line.\n */\nexport const ANNOUNCE_402_INFO =\n 'rig: skipped the optional identity self-announce — the payment peer ' +\n 'charges for announces and this identity has not paid for one (expected ' +\n 'on a fresh or unfunded identity); harmless, the command continues.\\n';\n\n/**\n * Reframe the embedded client's scary-but-harmless bootstrap announce noise\n * (#280). The core's bootstrap tries a PAID self-announce and `console.warn`s\n * the refusal — `[Bootstrap] Announce failed …: … (402 Payment Required):\n * {…x402…}` — straight to stderr, which rig's io seam cannot reach. A\n * first-run user reads that as their (succeeding!) push having failed.\n *\n * This process-level guard patches `process.stderr.write`:\n *\n * - an announce-402 line becomes {@link ANNOUNCE_402_INFO} once per\n * process (repeats are dropped — one calm line, not one per peer);\n * - announce failures that are NOT the expected 402 (network errors, peer\n * misconfig) pass through untouched — those ARE signal;\n * - everything else passes through untouched.\n *\n * Installed unconditionally in ./rig.ts before dispatch. Composes with\n * {@link redirectStdoutToStderr}: that guard forwards to `process.stderr.write`\n * via a dynamic property lookup, so rerouted stdout noise is calmed too.\n */\nexport function calmBootstrapNoise(): StderrCalmer {\n const original = process.stderr.write;\n let reframed = false;\n const patched = ((\n chunk: Uint8Array | string,\n encodingOrCb?: BufferEncoding | ((err?: Error | null) => void),\n cb?: (err?: Error | null) => void\n ): boolean => {\n let text = chunk;\n if (typeof chunk === 'string' && ANNOUNCE_FAILED_RE.test(chunk)) {\n if (ANNOUNCE_402_RE.test(chunk)) {\n text = reframed ? '' : ANNOUNCE_402_INFO;\n reframed = true;\n }\n }\n if (typeof encodingOrCb === 'function') {\n // `original` is `typeof process.stderr.write`, an overloaded function\n // type; `.call()` on it only resolves against the LAST overload\n // (chunk, encoding, cb), so the 2-arg (chunk, cb) call needs an\n // explicit narrow to the matching overload signature.\n const writeWithCallback = original as (\n chunk: Uint8Array | string,\n cb?: (err?: Error | null) => void\n ) => boolean;\n return writeWithCallback.call(process.stderr, text, encodingOrCb);\n }\n return original.call(process.stderr, text, encodingOrCb, cb);\n }) as typeof process.stderr.write;\n process.stderr.write = patched;\n return {\n restore: () => {\n if (process.stderr.write === patched) process.stderr.write = original;\n },\n };\n}\n\nexport function redirectStdoutToStderr(\n realWrite?: (text: string) => void\n): StdoutGuard {\n const original = process.stdout.write;\n const real = realWrite ?? original.bind(process.stdout);\n const patched = ((\n chunk: Uint8Array | string,\n encodingOrCb?: BufferEncoding | ((err?: Error | null) => void),\n cb?: (err?: Error | null) => void\n ): boolean =>\n typeof encodingOrCb === 'function'\n ? process.stderr.write(chunk, encodingOrCb)\n : process.stderr.write(\n chunk,\n encodingOrCb,\n cb\n )) as typeof process.stdout.write;\n process.stdout.write = patched;\n return {\n write: (text) => {\n real(text);\n },\n restore: () => {\n if (process.stdout.write === patched) process.stdout.write = original;\n },\n };\n}\n"],"mappings":"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","names":["argv"]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/rig.ts","../../src/cli/output.ts"],"sourcesContent":["#!/usr/bin/env node\n/**\n * `rig` — the git-native TOON CLI shipped by `@toon-protocol/rig` (epic\n * #222; standalone-only since #248; git passthrough since #250).\n *\n * rig-owned subcommands (see ./dispatch.ts):\n * init one-shot repo setup (identity + toon.* git config)\n * remote relays as git remotes (#249): add/remove/list\n * push estimate → confirm → execute (#229)\n * issue | comment | pr single NIP-34 event publishes (#231), incl.\n * `pr status` (moved from `rig status` in #250)\n * channel payment channels (#262/#263): list, open,\n * close, settle\n * fund | balance client money lifecycle (#263): devnet faucet\n * drip; wallet + channel balances\n *\n * Everything else is `git <argv...>` verbatim: `rig status` runs git status.\n *\n * STRICT `--json` STDOUT (#265): when a rig-owned command runs with `--json`,\n * stdout carries exactly one JSON document — the process-level stdout guard\n * reroutes every other write (including dependencies' `console.log`) to\n * stderr, the io layer sends human lines to stderr, and the post-dispatch\n * backstop emits an error envelope for paths that bailed before emitting.\n * The git passthrough is exempt: it inherits stdio verbatim (./output.ts).\n * The enforcement matrix in ./strict-json.test.ts mirrors this composition.\n */\n\nimport { createInterface } from 'node:readline/promises';\nimport { dispatch } from './dispatch.js';\nimport {\n calmBootstrapNoise,\n isJsonInvocation,\n makeCliIo,\n redirectStdoutToStderr,\n type RigIo,\n} from './output.js';\n\n/** Real terminal I/O: stdout/stderr sinks + readline y/N confirm. */\nfunction makeIo(jsonMode: boolean): RigIo {\n // Reframe the embedded client's expected announce-402 stderr noise (#280)\n // — installed for every mode, before any command code can run.\n calmBootstrapNoise();\n // In --json mode, patch process.stdout FIRST — before any command (or its\n // dynamically imported dependencies) can write — and keep the only real\n // stdout writer for the machine document.\n const guard = jsonMode ? redirectStdoutToStderr() : undefined;\n return makeCliIo({\n jsonMode,\n writeStdout: guard\n ? guard.write\n : (text) => {\n process.stdout.write(text);\n },\n writeStderr: (text) => {\n process.stderr.write(text);\n },\n isInteractive: Boolean(process.stdin.isTTY && process.stdout.isTTY),\n confirm: async (question) => {\n const rl = createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n try {\n const answer = (await rl.question(question)).trim().toLowerCase();\n return answer === 'y' || answer === 'yes';\n } finally {\n rl.close();\n }\n },\n });\n}\n\n/**\n * Exit as soon as stdio is flushed (#279). By the time dispatch resolves,\n * every command has finished its work and awaited its teardown — but the\n * embedded `@toon-protocol/client` can leave a keep-alive socket behind\n * that holds the Node event loop open for ~30 more seconds. That lingering\n * handle — not discovery or negotiation — was the bulk of the uniform\n * \"~32s per paid command\" tax the #279 study measured. Nothing rig can\n * reach unrefs it, so the one-shot CLI does what one-shot CLIs do: flush\n * and exit.\n */\nfunction exitWhenFlushed(code: number): void {\n process.exitCode = code;\n let pending = 2;\n const done = (): void => {\n pending -= 1;\n if (pending === 0) process.exit(code);\n };\n process.stdout.write('', done);\n process.stderr.write('', done);\n}\n\nconst argv = process.argv.slice(2);\nconst io = makeIo(isJsonInvocation(argv));\n\ndispatch(argv, {\n io,\n env: process.env,\n cwd: process.cwd(),\n}).then(\n (code) => {\n io.ensureSingleJsonDoc(code);\n exitWhenFlushed(code);\n },\n (err: unknown) => {\n process.stderr.write(\n `rig: unexpected error: ${err instanceof Error ? (err.stack ?? err.message) : String(err)}\\n`\n );\n io.ensureSingleJsonDoc(1);\n exitWhenFlushed(1);\n }\n);\n","/**\n * The rig CLI output layer (#265): the strict `--json` stdout guarantee.\n *\n * CONTRACT — when `--json` is set on a rig-owned command, stdout carries\n * EXACTLY ONE parseable JSON document and nothing else. Agents consume this\n * stream (`rig … --json | jq`), so any stray banner, progress line, warning,\n * deprecation nudge, or third-party `console.log` on stdout breaks pipelines\n * (the #260 addendum: `[Bootstrap] …` logs from the embedded client's core\n * polluted `rig push --json`). Everything human-facing goes to stderr.\n *\n * Three layers enforce the contract (composed in ./rig.ts; the enforcement\n * matrix in ./strict-json.test.ts mirrors that composition):\n *\n * 1. {@link makeCliIo} — the ONLY output surface commands use. In JSON mode\n * `out()` (human lines) reroutes to stderr and `emitJson()` is the sole\n * writer that reaches the real stdout.\n * 2. {@link redirectStdoutToStderr} — a process-level guard for code the io\n * seam cannot reach: dependencies that `console.log` directly (the\n * embedded `@toon-protocol/client`'s core bootstrap does). Installed\n * before any command code runs, it reroutes EVERY `process.stdout.write`\n * to stderr; only the writer it returns (wired into `emitJson`) still\n * reaches the real stdout.\n * 3. {@link RigIo.ensureSingleJsonDoc} — the backstop for paths that bail\n * out before emitting an envelope (usage errors, pre-payment refusals):\n * after dispatch it emits one error envelope built from the collected\n * stderr lines, so stdout is never empty in JSON mode.\n *\n * GIT PASSTHROUGH IS EXEMPT: `--json` is a per-subcommand flag on rig-owned\n * verbs, not a global rig flag. Any verb rig does not own goes to system git\n * with the EXACT argv tail and inherited stdio — `rig status --json` runs\n * `git status --json` (git rejects it), and flags BEFORE the subcommand\n * (`rig --json status`) are not rig's either: the whole argv passes through\n * to git verbatim. {@link isJsonInvocation} implements exactly that boundary.\n */\n\n// ---------------------------------------------------------------------------\n// The io seam\n// ---------------------------------------------------------------------------\n\n/** Terminal I/O seam — every rig-owned command writes ONLY through this. */\nexport interface CliIo {\n /**\n * One HUMAN-facing line: stdout normally, stderr when `--json` is active\n * (chatter must never pollute the machine stream).\n */\n out(line: string): void;\n /** One human-facing line to stderr (warnings, nudges, errors). */\n err(line: string): void;\n /**\n * THE machine-readable JSON document of a `--json` run — serialized here\n * (2-space indent) and written to the REAL stdout. Must be a command's\n * single stdout emission; call it at most once per invocation.\n */\n emitJson(payload: unknown): void;\n /** True when stdin+stdout are TTYs (interactive confirm possible). */\n isInteractive: boolean;\n /** Ask a y/N question; resolves true on explicit yes. */\n confirm(question: string): Promise<boolean>;\n}\n\n/** {@link CliIo} plus the JSON-mode bookkeeping the entrypoint needs. */\nexport interface RigIo extends CliIo {\n /** True when this invocation runs in `--json` mode. */\n readonly jsonMode: boolean;\n /** True once `emitJson` has written the machine document. */\n readonly emittedJson: boolean;\n /**\n * The #265 backstop: called once after dispatch (see ./rig.ts). In JSON\n * mode, when NO machine document was emitted (usage error, pre-payment\n * refusal, unexpected crash), emits one error envelope carrying the\n * human-facing lines the run wrote to stderr — so `--json` stdout always\n * parses. No-op outside JSON mode or after a real emission.\n */\n ensureSingleJsonDoc(exitCode: number): void;\n}\n\n/** Sinks + terminal facts {@link makeCliIo} builds a {@link RigIo} from. */\nexport interface CliIoOptions {\n /** Whether this invocation is a rig-owned command with `--json`. */\n jsonMode: boolean;\n /**\n * Write to the REAL stdout (in JSON mode: the pre-guard writer returned by\n * {@link redirectStdoutToStderr}). Receives full text including newlines.\n */\n writeStdout(text: string): void;\n /** Write to stderr. Receives full text including newlines. */\n writeStderr(text: string): void;\n isInteractive: boolean;\n confirm(question: string): Promise<boolean>;\n}\n\n/**\n * Build the {@link RigIo} for one invocation. Centralizes the #265 routing:\n * human lines → stderr in JSON mode, and `emitJson` as the only stdout path.\n */\nexport function makeCliIo(options: CliIoOptions): RigIo {\n const { jsonMode, writeStdout, writeStderr } = options;\n let emittedJson = false;\n /** Human lines collected in JSON mode — the backstop envelope's detail. */\n const humanLines: string[] = [];\n\n const toStderr = (line: string): void => {\n if (jsonMode) humanLines.push(line);\n writeStderr(`${line}\\n`);\n };\n\n return {\n jsonMode,\n get emittedJson() {\n return emittedJson;\n },\n out: (line) => {\n if (jsonMode) {\n toStderr(line);\n } else {\n writeStdout(`${line}\\n`);\n }\n },\n err: toStderr,\n emitJson: (payload) => {\n emittedJson = true;\n writeStdout(`${JSON.stringify(payload, null, 2)}\\n`);\n },\n isInteractive: options.isInteractive,\n confirm: options.confirm,\n ensureSingleJsonDoc(exitCode: number): void {\n if (!jsonMode || emittedJson) return;\n const detail =\n humanLines.join('\\n') ||\n (exitCode === 0\n ? 'the command produced no machine output'\n : 'the command failed before emitting machine output — see stderr');\n this.emitJson(\n exitCode === 0\n ? { error: null, exitCode, detail }\n : { error: 'error', exitCode, detail }\n );\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// JSON-mode detection (and the git-passthrough exemption)\n// ---------------------------------------------------------------------------\n\n/**\n * The verbs rig owns — everything else is `git <argv…>` verbatim. Must match\n * the ./dispatch.ts switch (dispatch.test.ts pins both directions).\n */\nexport const RIG_OWNED_VERBS: ReadonlySet<string> = new Set([\n 'init',\n 'identity',\n 'remote',\n 'clone',\n 'fetch',\n 'push',\n 'site',\n 'issue',\n 'comment',\n 'pr',\n 'maintainers',\n 'payout',\n 'refresh',\n 'channel',\n 'channels',\n 'fund',\n 'balance',\n 'chain',\n 'entry',\n 'name',\n 'ci',\n]);\n\n/**\n * True when this argv is a rig-owned command run with `--json` — the strict\n * stdout contract applies. Deliberately NOT true for:\n *\n * - non-owned verbs (`rig status --json` IS `git status --json`: inherited\n * stdio, git's own semantics, rig adds nothing);\n * - flags before the subcommand (`rig --json status`): rig has no global\n * flags besides help/--version, so the argv passes to git verbatim;\n * - `--json` after a bare `--` (parseArgs treats those tokens as\n * positionals, so rig's flag parsers never see it as a flag either).\n *\n * Mirrors a plain token scan rather than each command's full parseArgs\n * config: the one divergence is `--json` consumed as a STRING option's value\n * (e.g. `rig push --relay --json`) — a pathological invocation that ends up\n * with chatter on stderr and a backstop envelope on stdout, which still\n * honors the parse guarantee.\n */\nexport function isJsonInvocation(argv: string[]): boolean {\n const [verb, ...rest] = argv;\n if (verb === undefined || !RIG_OWNED_VERBS.has(verb)) return false;\n for (const arg of rest) {\n if (arg === '--') return false;\n if (arg === '--json') return true;\n }\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Process-level stdout guard (third-party console.log defense)\n// ---------------------------------------------------------------------------\n\n/** Handle on an installed stdout guard. */\nexport interface StdoutGuard {\n /** Write to the REAL stdout (bypasses the redirection). */\n write(text: string): void;\n /** Undo the patch (tests; the one-shot CLI process never needs it). */\n restore(): void;\n}\n\n/**\n * Reroute every `process.stdout.write` — including `console.log` from\n * dependencies rig cannot re-route at the io seam, like the embedded\n * client's `[Bootstrap] …` logs (#260) — to stderr. Returns the ONLY writer\n * that still reaches the real stdout; ./rig.ts wires it into\n * {@link makeCliIo}'s `writeStdout` so `emitJson` output is the single\n * survivor on the machine stream.\n *\n * @param realWrite Override the saved real-stdout writer (tests capture it);\n * defaults to the unpatched `process.stdout.write`.\n */\n// ---------------------------------------------------------------------------\n// Process-level stderr calmer (third-party bootstrap noise defense, #280)\n// ---------------------------------------------------------------------------\n\n/** Handle on an installed stderr calmer. */\nexport interface StderrCalmer {\n /** Undo the patch (tests; the one-shot CLI process never needs it). */\n restore(): void;\n}\n\n/** The embedded client's core self-announce failure log line. */\nconst ANNOUNCE_FAILED_RE = /\\[Bootstrap\\] Announce failed/;\n/** … specifically the EXPECTED pre-payment 402 refusal (x402 challenge). */\nconst ANNOUNCE_402_RE = /402|payment required/i;\n\n/**\n * The calm reframe of the announce-402: what happened, why it is expected,\n * and that the command is unaffected — instead of a full x402 challenge JSON\n * dump. Exported so tests pin the exact line.\n */\nexport const ANNOUNCE_402_INFO =\n 'rig: skipped the optional identity self-announce — the payment peer ' +\n 'charges for announces and this identity has not paid for one (expected ' +\n 'on a fresh or unfunded identity); harmless, the command continues.\\n';\n\n/**\n * Reframe the embedded client's scary-but-harmless bootstrap announce noise\n * (#280). The core's bootstrap tries a PAID self-announce and `console.warn`s\n * the refusal — `[Bootstrap] Announce failed …: … (402 Payment Required):\n * {…x402…}` — straight to stderr, which rig's io seam cannot reach. A\n * first-run user reads that as their (succeeding!) push having failed.\n *\n * This process-level guard patches `process.stderr.write`:\n *\n * - an announce-402 line becomes {@link ANNOUNCE_402_INFO} once per\n * process (repeats are dropped — one calm line, not one per peer);\n * - announce failures that are NOT the expected 402 (network errors, peer\n * misconfig) pass through untouched — those ARE signal;\n * - everything else passes through untouched.\n *\n * Installed unconditionally in ./rig.ts before dispatch. Composes with\n * {@link redirectStdoutToStderr}: that guard forwards to `process.stderr.write`\n * via a dynamic property lookup, so rerouted stdout noise is calmed too.\n */\nexport function calmBootstrapNoise(): StderrCalmer {\n const original = process.stderr.write;\n let reframed = false;\n const patched = ((\n chunk: Uint8Array | string,\n encodingOrCb?: BufferEncoding | ((err?: Error | null) => void),\n cb?: (err?: Error | null) => void\n ): boolean => {\n let text = chunk;\n if (typeof chunk === 'string' && ANNOUNCE_FAILED_RE.test(chunk)) {\n if (ANNOUNCE_402_RE.test(chunk)) {\n text = reframed ? '' : ANNOUNCE_402_INFO;\n reframed = true;\n }\n }\n if (typeof encodingOrCb === 'function') {\n // `original` is `typeof process.stderr.write`, an overloaded function\n // type; `.call()` on it only resolves against the LAST overload\n // (chunk, encoding, cb), so the 2-arg (chunk, cb) call needs an\n // explicit narrow to the matching overload signature.\n const writeWithCallback = original as (\n chunk: Uint8Array | string,\n cb?: (err?: Error | null) => void\n ) => boolean;\n return writeWithCallback.call(process.stderr, text, encodingOrCb);\n }\n return original.call(process.stderr, text, encodingOrCb, cb);\n }) as typeof process.stderr.write;\n process.stderr.write = patched;\n return {\n restore: () => {\n if (process.stderr.write === patched) process.stderr.write = original;\n },\n };\n}\n\nexport function redirectStdoutToStderr(\n realWrite?: (text: string) => void\n): StdoutGuard {\n const original = process.stdout.write;\n const real = realWrite ?? original.bind(process.stdout);\n const patched = ((\n chunk: Uint8Array | string,\n encodingOrCb?: BufferEncoding | ((err?: Error | null) => void),\n cb?: (err?: Error | null) => void\n ): boolean =>\n typeof encodingOrCb === 'function'\n ? process.stderr.write(chunk, encodingOrCb)\n : process.stderr.write(\n chunk,\n encodingOrCb,\n cb\n )) as typeof process.stdout.write;\n process.stdout.write = patched;\n return {\n write: (text) => {\n real(text);\n },\n restore: () => {\n if (process.stdout.write === patched) process.stdout.write = original;\n },\n };\n}\n"],"mappings":"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","names":["argv"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,104 @@
|
|
|
1
|
-
import { d as
|
|
2
|
-
export { C as COMMENT_KIND, f as GitObject, G as GitObjectUpload, M as MAINTAINERS_TAG,
|
|
1
|
+
import { d as PayoutPointer, b as UnsignedEvent, e as GitObjectType, P as Publisher, F as FeeRates, c as PublishReceipt } from './publisher-DgbfziOm.js';
|
|
2
|
+
export { C as COMMENT_KIND, f as CommentParent, g as CommentRoot, h as GitObject, G as GitObjectUpload, L as LEGACY_COMMENT_KIND, M as MAINTAINERS_TAG, i as MAX_ARWEAVE_TAGS_PER_EVENT, j as MAX_OBJECT_SIZE, k as PAYOUT_TAG, l as PayoutChain, R as REPOSITORY_STATE_KIND, m as StatusKind, U as UploadReceipt, n as authorizedStatusAuthors, o as buildComment, p as buildIssue, q as buildPatch, r as buildRepoRefs, s as buildStatus, t as commentBelongsToThread, u as createGitBlob, v as createGitCommit, w as createGitTag, x as createGitTree, y as hashGitObject, z as isValidEvmPayoutAddress, A as parseMaintainers, D as parsePayout } from './publisher-DgbfziOm.js';
|
|
3
3
|
import '@toon-protocol/core/nip34';
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* The kind:30617 repository announcement — build and amend (#154).
|
|
7
|
+
*
|
|
8
|
+
* A kind:30617 is NIP-33 replaceable: publishing a new one REPLACES the old
|
|
9
|
+
* one wholesale, so a republish that rebuilds the event from the handful of
|
|
10
|
+
* fields rig models destroys every tag rig does not model — another client's
|
|
11
|
+
* maintainer role tags (`M`/`m`/`o`), `clone`, `blossoms`, `t`, `alt`, or any
|
|
12
|
+
* tag invented after this file was written.
|
|
13
|
+
*
|
|
14
|
+
* This module owns the whole "next announcement" question so no caller has to
|
|
15
|
+
* think about it: give it the current announcement (or `null` for a repo's
|
|
16
|
+
* first) plus the fields you are editing, and it returns the next unsigned
|
|
17
|
+
* event. The known-tag set is explicit and small; **carrying a tag over
|
|
18
|
+
* verbatim is the default**, and unknown tags keep their original relative
|
|
19
|
+
* order. Same pattern as ngit's `is_known_tag_name` + `extra_tags`
|
|
20
|
+
* (`ngit:src/lib/repo_ref.rs`).
|
|
21
|
+
*
|
|
22
|
+
* Every kind:30617 rig publishes — first push, `rig maintainers`,
|
|
23
|
+
* `rig payout` — is built here.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** NIP-34 tag naming the relays a repo's events are published to. */
|
|
27
|
+
declare const RELAYS_TAG = "relays";
|
|
28
|
+
/** NIP-34 tag naming a web URL where the repo can be browsed. */
|
|
29
|
+
declare const WEB_TAG = "web";
|
|
30
|
+
/**
|
|
31
|
+
* The marker that makes an `["r", "<sha>", "euc"]` tag the repo's *earliest
|
|
32
|
+
* unique commit* — its fork-identity root — rather than any other `r` tag.
|
|
33
|
+
*/
|
|
34
|
+
declare const EARLIEST_UNIQUE_COMMIT_MARKER = "euc";
|
|
35
|
+
/** The current announcement, as read off the relay. */
|
|
36
|
+
interface ExistingAnnouncement {
|
|
37
|
+
tags: string[][];
|
|
38
|
+
/** kind:30617 content is conventionally empty, but it is preserved. */
|
|
39
|
+
content?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The fields an amendment can change. **Omit a field to leave it exactly as
|
|
43
|
+
* the current announcement has it** — that, not deletion, is the default.
|
|
44
|
+
* Pass a value to rewrite it, and `null`/`[]` to remove it.
|
|
45
|
+
*/
|
|
46
|
+
interface AnnouncementEdits {
|
|
47
|
+
/** The `d` tag. Always written — an announcement is nothing without it. */
|
|
48
|
+
repoId: string;
|
|
49
|
+
name?: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
/**
|
|
52
|
+
* Declared maintainer pubkeys (hex). Emitted as ONE multi-valued
|
|
53
|
+
* `["maintainers", …]` tag; duplicates and non-64-hex values are dropped,
|
|
54
|
+
* and an empty result emits no tag. The owner is an implicit maintainer.
|
|
55
|
+
*/
|
|
56
|
+
maintainers?: readonly string[];
|
|
57
|
+
/** The `["payout", "<chain>", "<address>"]` pointer (rig#92). */
|
|
58
|
+
payout?: PayoutPointer | null;
|
|
59
|
+
/** Relay URLs, as ONE multi-valued `["relays", …]` tag. */
|
|
60
|
+
relays?: readonly string[] | null;
|
|
61
|
+
/** Web viewer URLs, as ONE multi-valued `["web", …]` tag. */
|
|
62
|
+
web?: readonly string[] | null;
|
|
63
|
+
/**
|
|
64
|
+
* The repo's earliest unique commit, emitted as `["r", "<sha>", "euc"]`.
|
|
65
|
+
* Omit to keep whatever the announcement already declares: a repo's fork
|
|
66
|
+
* identity must never change under its owner.
|
|
67
|
+
*/
|
|
68
|
+
earliestUniqueCommit?: string | null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The next kind:30617 for a repo: `current` with `edits` applied, and
|
|
72
|
+
* everything else — known-but-unedited tags AND tags rig has never heard of —
|
|
73
|
+
* carried over verbatim in place.
|
|
74
|
+
*
|
|
75
|
+
* An edited slot is rewritten where the current announcement first mentions
|
|
76
|
+
* it, so a republish moves nothing; repeated tags for one slot collapse into
|
|
77
|
+
* the single edited value. Slots the current announcement lacks are appended
|
|
78
|
+
* in {@link SLOTS} order. `d` always leads.
|
|
79
|
+
*
|
|
80
|
+
* @param current - The announcement being amended, or `null` for a repo's first.
|
|
81
|
+
* @param edits - The fields to change; omitted fields are left as they are.
|
|
82
|
+
*/
|
|
83
|
+
declare function amendRepoAnnouncement(current: ExistingAnnouncement | null, edits: AnnouncementEdits): UnsignedEvent;
|
|
84
|
+
/**
|
|
85
|
+
* Build a repo's FIRST kind:30617 announcement — {@link amendRepoAnnouncement}
|
|
86
|
+
* with nothing to amend.
|
|
87
|
+
*
|
|
88
|
+
* @param repoId - Repository identifier (d tag)
|
|
89
|
+
* @param name - Human-readable repository name
|
|
90
|
+
* @param description - Repository description
|
|
91
|
+
* @param maintainers - Optional declared maintainer pubkeys (hex). Emitted as
|
|
92
|
+
* a single `["maintainers", …]` tag when non-empty; duplicate and non-64-hex
|
|
93
|
+
* values are dropped. The owner (the signer) is an implicit maintainer and
|
|
94
|
+
* need not be listed — if passed it is emitted, which is harmless since the
|
|
95
|
+
* owner is authorized regardless. See {@link MAINTAINERS_TAG}.
|
|
96
|
+
* @param payout - Optional declared payout pointer (rig#92). Emitted as a
|
|
97
|
+
* single `["payout", "evm", <address>]` tag when given; omit (or pass
|
|
98
|
+
* `null`) to leave the repo with no payout pointer. See {@link PAYOUT_TAG}.
|
|
99
|
+
*/
|
|
100
|
+
declare function buildRepoAnnouncement(repoId: string, name: string, description: string, maintainers?: string[], payout?: PayoutPointer | null): UnsignedEvent;
|
|
101
|
+
|
|
5
102
|
/**
|
|
6
103
|
* GitRepoReader — read a local repository via `execFile` git plumbing.
|
|
7
104
|
*
|
|
@@ -133,6 +230,47 @@ declare class GitRepoReader {
|
|
|
133
230
|
* trees) — used by push planning to report actionable oversize errors.
|
|
134
231
|
*/
|
|
135
232
|
objectsBetweenWithPaths(want: string[], have: string[]): Promise<ObjectWithPath[]>;
|
|
233
|
+
/**
|
|
234
|
+
* Run git and hand each stdout line to `visit` as it arrives, never holding
|
|
235
|
+
* the whole output in memory. Returning `false` from `visit` ends the walk:
|
|
236
|
+
* the child is killed and the promise resolves with what was seen.
|
|
237
|
+
*
|
|
238
|
+
* Every other git call here buffers into one `execFile` string, which is
|
|
239
|
+
* fine for bounded output. These object walks are not bounded — they grow
|
|
240
|
+
* with the size of the repository — so on a repo big enough to need the
|
|
241
|
+
* object-map cap they would be the thing that breaks (#162).
|
|
242
|
+
*/
|
|
243
|
+
private streamLines;
|
|
244
|
+
/**
|
|
245
|
+
* Every object SHA in the local object database, in no particular order
|
|
246
|
+
* (`git cat-file --batch-all-objects --batch-check`, no bodies read).
|
|
247
|
+
*
|
|
248
|
+
* This is the honest answer to "what does this repository already have",
|
|
249
|
+
* which `rig fetch` needs to compute its delta. It deliberately does NOT
|
|
250
|
+
* consult the remote's kind:30618 `arweave` map: that map is capped (#162)
|
|
251
|
+
* and is a hint cache, never an index of local presence.
|
|
252
|
+
*
|
|
253
|
+
* Streamed, so the listing never has to fit in one buffer.
|
|
254
|
+
*/
|
|
255
|
+
listAllObjectShas(): Promise<string[]>;
|
|
256
|
+
/**
|
|
257
|
+
* SHAs of every object reachable from `tips`, newest first: commits in
|
|
258
|
+
* reverse-chronological order, each commit immediately followed by the
|
|
259
|
+
* trees and blobs it is the first to reference
|
|
260
|
+
* (`git rev-list --objects --in-commit-order`).
|
|
261
|
+
*
|
|
262
|
+
* Used to rank the kind:30618 object map when it exceeds
|
|
263
|
+
* `MAX_ARWEAVE_TAGS_PER_EVENT` (#162): the entries most likely to be wanted
|
|
264
|
+
* by the next clone or fetch are the ones nearest the tips. Tips that do
|
|
265
|
+
* not resolve locally (a remote ref we never fetched) are dropped rather
|
|
266
|
+
* than failing the walk.
|
|
267
|
+
*
|
|
268
|
+
* `limit` stops the walk once that many SHAs have been seen — the ranking
|
|
269
|
+
* caller never needs more than the cap, and a full walk of a repository big
|
|
270
|
+
* enough to hit the cap is exactly the work worth not doing. The walk is
|
|
271
|
+
* streamed, so neither its output nor this array is ever bigger than that.
|
|
272
|
+
*/
|
|
273
|
+
reachableObjectsNewestFirst(tips: string[], limit?: number): Promise<string[]>;
|
|
136
274
|
/**
|
|
137
275
|
* List every blob (file) reachable from a ref's root tree, recursively,
|
|
138
276
|
* with the path it is served at (#368: the ar.io site manifest join key).
|
|
@@ -180,6 +318,19 @@ declare class GitRepoReader {
|
|
|
180
318
|
* pairs for exactly the commits a format-patch series carries.
|
|
181
319
|
*/
|
|
182
320
|
commitParents(shas: string[]): Promise<Map<string, string[]>>;
|
|
321
|
+
/**
|
|
322
|
+
* SHAs of the repo's ROOT commits — the parentless commits a history starts
|
|
323
|
+
* from — via `git rev-list --max-parents=0`.
|
|
324
|
+
*
|
|
325
|
+
* The repo's *earliest unique commit* (NIP-34's `euc` fork-identity tag) is
|
|
326
|
+
* chosen from these; the choosing rule lives in `repo-announcement.ts`.
|
|
327
|
+
*
|
|
328
|
+
* @param rev - Consider only roots reachable from this revision. Omit for
|
|
329
|
+
* every root in the repository (`--all`).
|
|
330
|
+
* @returns The roots in `rev-list` order, or `[]` when the revision does not
|
|
331
|
+
* resolve — an unborn `HEAD` in a repo with no commits is not an error.
|
|
332
|
+
*/
|
|
333
|
+
rootCommits(rev?: string): Promise<string[]>;
|
|
183
334
|
/**
|
|
184
335
|
* Resolve a ref/revision to a full SHA via `git rev-parse --verify`.
|
|
185
336
|
* Throws {@link GitError} when the name doesn't resolve.
|
|
@@ -192,8 +343,9 @@ declare class GitRepoReader {
|
|
|
192
343
|
* `rig push` (epic #222, ticket #225).
|
|
193
344
|
*
|
|
194
345
|
* Queries relay(s) over NIP-01 WebSocket for the repository's NIP-34 state:
|
|
195
|
-
* - kind:30618 (repository state):
|
|
196
|
-
*
|
|
346
|
+
* - kind:30618 (repository state): ref tags → ref map (both the NIP-34
|
|
347
|
+
* shape and rig's legacy `r` shape — see `./nip34-refs.ts`), `HEAD`
|
|
348
|
+
* symref, `arweave` tags → git SHA → Arweave txId hints.
|
|
197
349
|
* - kind:30617 (repository announcement): presence = the repo exists on
|
|
198
350
|
* TOON (first-push detection) + name/description/relays metadata.
|
|
199
351
|
*
|
|
@@ -231,6 +383,12 @@ interface NostrFilter {
|
|
|
231
383
|
'#a'?: string[];
|
|
232
384
|
/** Event-reference tag filter (#278 tracker: statuses + comments). */
|
|
233
385
|
'#e'?: string[];
|
|
386
|
+
/**
|
|
387
|
+
* NIP-22 UPPERCASE root-scope reference — distinct from `#e` and matched
|
|
388
|
+
* case-sensitively (#159: kind:1111 comments hang off their thread root's
|
|
389
|
+
* `E` tag, while `e` names the immediate parent).
|
|
390
|
+
*/
|
|
391
|
+
'#E'?: string[];
|
|
234
392
|
/** Commit tag filter (#125 CI: results/progress/jobs for one commit). */
|
|
235
393
|
'#c'?: string[];
|
|
236
394
|
/** Addressee tag filter (#125 CI: a coordinator's inbox — 9843/9844/9840/29846). */
|
|
@@ -281,7 +439,12 @@ interface RemoteState {
|
|
|
281
439
|
refs: Map<string, string>;
|
|
282
440
|
/** HEAD symref target (e.g. `refs/heads/main`), or null if unset. */
|
|
283
441
|
headSymref: string | null;
|
|
284
|
-
/**
|
|
442
|
+
/**
|
|
443
|
+
* Git SHA → Arweave txId hints from the latest kind:30618 `arweave` tags,
|
|
444
|
+
* capped at `MAX_ARWEAVE_TAGS_PER_EVENT` (#162). A HINT MAP, not an index:
|
|
445
|
+
* a SHA missing from it is resolved via {@link RemoteState.resolveMissing},
|
|
446
|
+
* never assumed absent from Arweave.
|
|
447
|
+
*/
|
|
285
448
|
shaToTxId: Map<string, string>;
|
|
286
449
|
/** The latest kind:30618 event, or null if the repo has no state yet. */
|
|
287
450
|
refsEvent: NostrEvent | null;
|
|
@@ -594,6 +757,14 @@ declare function ownerToHex(owner: string): string;
|
|
|
594
757
|
* `r` tags are the full new ref state. On a first push it publishes the
|
|
595
758
|
* kind:30617 announcement before the refs event.
|
|
596
759
|
*
|
|
760
|
+
* That merge is bounded at `MAX_ARWEAVE_TAGS_PER_EVENT` (#162): an unbounded
|
|
761
|
+
* map eventually produces an event relays reject. Over the cap, entries are
|
|
762
|
+
* kept in priority order (this push's objects, then objects reachable from
|
|
763
|
+
* the new tips newest-first); under it, the published map is byte-identical
|
|
764
|
+
* to what earlier releases published. A dropped entry is a cache miss, never
|
|
765
|
+
* a lost object — it is still on Arweave under its `Git-SHA` / `Repo` tags
|
|
766
|
+
* and still resolves through the GraphQL resolver.
|
|
767
|
+
*
|
|
597
768
|
* Resume safety: uploads are content-addressed (Git-SHA-tagged), so re-running
|
|
598
769
|
* `executePush` after a crash is safe — it consults the merged
|
|
599
770
|
* remote + planned sha→txId map before paying for any upload, and a re-plan
|
|
@@ -731,10 +902,18 @@ interface PushPlan {
|
|
|
731
902
|
knownShaToTxId: Map<string, string>;
|
|
732
903
|
/** True when no kind:30617 exists yet — executePush announces first. */
|
|
733
904
|
announceNeeded: boolean;
|
|
734
|
-
/**
|
|
905
|
+
/**
|
|
906
|
+
* Announcement metadata used when {@link announceNeeded}. `web` and
|
|
907
|
+
* `earliestUniqueCommit` are the NIP-34 conformance tags (#158); the
|
|
908
|
+
* `relays` tag comes from the relay list `executePush` publishes to.
|
|
909
|
+
*/
|
|
735
910
|
announcement: {
|
|
736
911
|
name: string;
|
|
737
912
|
description: string;
|
|
913
|
+
/** The repo's rig-web viewer URL (`repoWebUrl`), when one is known. */
|
|
914
|
+
web?: string;
|
|
915
|
+
/** The repo's `["r", "<sha>", "euc"]` fork identity, from local git. */
|
|
916
|
+
earliestUniqueCommit?: string;
|
|
738
917
|
};
|
|
739
918
|
estimate: PushFeeEstimate;
|
|
740
919
|
}
|
|
@@ -753,10 +932,15 @@ interface PlanPushOptions {
|
|
|
753
932
|
refs?: string[];
|
|
754
933
|
/** Allow non-fast-forward updates (default false → hard error). */
|
|
755
934
|
force?: boolean;
|
|
756
|
-
/**
|
|
935
|
+
/**
|
|
936
|
+
* Repo metadata for the first-push announcement. `web` is the repo's
|
|
937
|
+
* rig-web viewer URL (`repoWebUrl` — the CLI supplies it once a relay is
|
|
938
|
+
* resolved); the `euc` is computed here from `repoReader`.
|
|
939
|
+
*/
|
|
757
940
|
announcement?: {
|
|
758
941
|
name?: string;
|
|
759
942
|
description?: string;
|
|
943
|
+
web?: string;
|
|
760
944
|
};
|
|
761
945
|
/**
|
|
762
946
|
* Async resolver for SHAs the remote's `arweave` tags don't cover —
|
|
@@ -790,8 +974,11 @@ interface PushResult {
|
|
|
790
974
|
/** kind:30618 (cumulative refs + arweave map) receipt. */
|
|
791
975
|
refsReceipt: PublishReceipt;
|
|
792
976
|
/**
|
|
793
|
-
* The
|
|
794
|
-
* resolver finds + this push's uploads
|
|
977
|
+
* The sha→txId map actually published in the refs event: remote hints +
|
|
978
|
+
* resolver finds + this push's uploads, bounded to
|
|
979
|
+
* `MAX_ARWEAVE_TAGS_PER_EVENT` in priority order (#162). Entries dropped by
|
|
980
|
+
* the cap are still on Arweave and still resolve through the GraphQL
|
|
981
|
+
* `Git-SHA` resolver.
|
|
795
982
|
*/
|
|
796
983
|
arweaveMap: Map<string, string>;
|
|
797
984
|
/** Total fees actually paid (uploads + events), smallest asset unit. */
|
|
@@ -865,10 +1052,15 @@ interface GitEstimateRequest {
|
|
|
865
1052
|
* (forward-compat); defaults to the daemon's config-seeded relay.
|
|
866
1053
|
*/
|
|
867
1054
|
relayUrls?: string[];
|
|
868
|
-
/**
|
|
1055
|
+
/**
|
|
1056
|
+
* Repo metadata for the first-push kind:30617 announcement. `web` is the
|
|
1057
|
+
* repo's rig-web viewer URL for the NIP-34 `web` tag (#158); a daemon that
|
|
1058
|
+
* predates it simply ignores the field.
|
|
1059
|
+
*/
|
|
869
1060
|
announcement?: {
|
|
870
1061
|
name?: string;
|
|
871
1062
|
description?: string;
|
|
1063
|
+
web?: string;
|
|
872
1064
|
};
|
|
873
1065
|
}
|
|
874
1066
|
/** Pre-push fee table (all fees in base/micro units, decimal strings). */
|
|
@@ -903,9 +1095,16 @@ interface GitEstimateResponse {
|
|
|
903
1095
|
knownShaToTxId: Record<string, string>;
|
|
904
1096
|
/** True when no kind:30617 exists yet — the push announces first. */
|
|
905
1097
|
announceNeeded: boolean;
|
|
1098
|
+
/**
|
|
1099
|
+
* What the first announcement will carry. `web` and `earliestUniqueCommit`
|
|
1100
|
+
* are the NIP-34 conformance tags (#158) and are absent when the planner
|
|
1101
|
+
* could not derive them (no relay resolved, or a repo with no commits).
|
|
1102
|
+
*/
|
|
906
1103
|
announcement: {
|
|
907
1104
|
name: string;
|
|
908
1105
|
description: string;
|
|
1106
|
+
web?: string;
|
|
1107
|
+
earliestUniqueCommit?: string;
|
|
909
1108
|
};
|
|
910
1109
|
estimate: GitFeeEstimate;
|
|
911
1110
|
}
|
|
@@ -964,20 +1163,32 @@ interface GitIssueRequest {
|
|
|
964
1163
|
/** Labels (`t` tags). */
|
|
965
1164
|
labels?: string[];
|
|
966
1165
|
}
|
|
967
|
-
/**
|
|
1166
|
+
/**
|
|
1167
|
+
* `POST /git/comment` — publish a NIP-22 kind:1111 comment on an issue or
|
|
1168
|
+
* patch. PAID.
|
|
1169
|
+
*
|
|
1170
|
+
* The root is the issue/patch being discussed, NEVER the repository: it
|
|
1171
|
+
* becomes the comment's uppercase `E`/`K`/`P` scope. `parentComment` makes
|
|
1172
|
+
* the comment a nested reply (lowercase `e`/`k`/`p`, `k` = 1111); omitted,
|
|
1173
|
+
* the parent is the root itself. Legacy kind:1622 is never published (#159).
|
|
1174
|
+
*/
|
|
968
1175
|
interface GitCommentRequest {
|
|
969
1176
|
repoAddr: GitRepoAddr;
|
|
970
|
-
/** Event id of the issue or patch
|
|
1177
|
+
/** Event id of the issue or patch the thread hangs off (uppercase `E`). */
|
|
971
1178
|
rootEventId: string;
|
|
1179
|
+
/** Kind of that root event, e.g. 1621 or 1617 (uppercase `K`). */
|
|
1180
|
+
rootKind: number;
|
|
1181
|
+
/** Pubkey of the root event's author (uppercase `P`). */
|
|
1182
|
+
rootAuthorPubkey: string;
|
|
972
1183
|
/** Comment body (Markdown content). */
|
|
973
1184
|
body: string;
|
|
974
|
-
/**
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1185
|
+
/** The kind:1111 comment being replied to — omit for a top-level comment. */
|
|
1186
|
+
parentComment?: {
|
|
1187
|
+
/** Event id of that comment (lowercase `e`). */
|
|
1188
|
+
eventId: string;
|
|
1189
|
+
/** Pubkey of its author (lowercase `p`). */
|
|
1190
|
+
authorPubkey: string;
|
|
1191
|
+
};
|
|
981
1192
|
}
|
|
982
1193
|
/**
|
|
983
1194
|
* `POST /git/patch` — publish a kind:1617 patch. Supply EXACTLY ONE of
|
|
@@ -2177,4 +2388,135 @@ declare function assembleCiStatus(opts: AssembleStatusOptions): {
|
|
|
2177
2388
|
reason?: string;
|
|
2178
2389
|
};
|
|
2179
2390
|
|
|
2180
|
-
|
|
2391
|
+
/**
|
|
2392
|
+
* Real wire capture from wss://relay.ngit.dev (2026-09-17T16:00:01Z).
|
|
2393
|
+
*
|
|
2394
|
+
* A kind:30617 repository announcement for ngit's `wyrd` repo. It carries a
|
|
2395
|
+
* `clone` tag and the unmerged role tags from nips PR #2324 (`M` — lead
|
|
2396
|
+
* maintainer, `m` — maintainer), alongside the conformant `relays`, `web`
|
|
2397
|
+
* and `["r", <sha>, "euc"]` earliest-unique-commit tags described in
|
|
2398
|
+
* rig#153's Implementation Decisions. Committed byte-for-byte as received —
|
|
2399
|
+
* no edited tags, no re-serialization — so its id and signature verify (see
|
|
2400
|
+
* `ngit-fixtures.test.ts`).
|
|
2401
|
+
*
|
|
2402
|
+
* No live event combining `M`, `m` AND `o` together with `clone` was found
|
|
2403
|
+
* on relay.ngit.dev at capture time (a relay-wide scan of 597 kind:30617
|
|
2404
|
+
* events found exactly one `o`-tagged announcement, and it carried no `M`).
|
|
2405
|
+
* This fixture is the richest real combination available: `M` + `m` + `clone`.
|
|
2406
|
+
*
|
|
2407
|
+
* Captured with `scripts/capture-ngit-fixtures.mjs` (repo root); see that
|
|
2408
|
+
* file for the exact filter and how to re-run the capture.
|
|
2409
|
+
*/
|
|
2410
|
+
|
|
2411
|
+
declare const NGIT_ANNOUNCEMENT_WYRD_RELAY = "wss://relay.ngit.dev";
|
|
2412
|
+
declare const NGIT_ANNOUNCEMENT_WYRD_CAPTURED_AT = "2026-09-17T16:00:01Z";
|
|
2413
|
+
declare const NGIT_ANNOUNCEMENT_WYRD_EVENT_ID = "5df470edc9067955e707def26b57dbf3c61920ede9c6792ab592d435729192b0";
|
|
2414
|
+
/** kind:30617 announcement for `wyrd`, as served by relay.ngit.dev. */
|
|
2415
|
+
declare const NGIT_ANNOUNCEMENT_WYRD: NostrEvent;
|
|
2416
|
+
|
|
2417
|
+
/**
|
|
2418
|
+
* Real wire capture from wss://relay.ngit.dev (2026-09-17T16:00:01Z).
|
|
2419
|
+
*
|
|
2420
|
+
* The kind:30618 repository state event for ngit's own `ngit` repo
|
|
2421
|
+
* (author a008def15796fba9a0d6fab04e8fd57089285d9fd505da5a83fe8aad57a3564d,
|
|
2422
|
+
* npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr — the
|
|
2423
|
+
* canonical repo ngit's cli/git plugin ships from). It carries `HEAD` and
|
|
2424
|
+
* NIP-34 ref-shape tags for `refs/heads/*` and `refs/tags/*`, INCLUDING
|
|
2425
|
+
* peeled `^{}` entries for annotated tags (e.g. `refs/tags/v3.0.0^{}`) —
|
|
2426
|
+
* exactly the shape rig#153's dual-read work must parse without treating
|
|
2427
|
+
* peeled entries as ordinary refs. Committed byte-for-byte as received — no
|
|
2428
|
+
* edited tags, no re-serialization, tag order preserved — so its id and
|
|
2429
|
+
* signature verify (see `ngit-fixtures.test.ts`).
|
|
2430
|
+
*
|
|
2431
|
+
* Captured with `scripts/capture-ngit-fixtures.mjs` (repo root); see that
|
|
2432
|
+
* file for the exact filter and how to re-run the capture.
|
|
2433
|
+
*/
|
|
2434
|
+
|
|
2435
|
+
declare const NGIT_STATE_NGIT_RELAY = "wss://relay.ngit.dev";
|
|
2436
|
+
declare const NGIT_STATE_NGIT_CAPTURED_AT = "2026-09-17T16:00:01Z";
|
|
2437
|
+
declare const NGIT_STATE_NGIT_EVENT_ID = "17fdde63cbc0289e933e6ed232e354cce6713d89e10a793f6d6f9d8ad274ee14";
|
|
2438
|
+
/** kind:30618 repository state for ngit's own `ngit` repo. */
|
|
2439
|
+
declare const NGIT_STATE_NGIT: NostrEvent;
|
|
2440
|
+
|
|
2441
|
+
/**
|
|
2442
|
+
* Real wire capture from wss://relay.ngit.dev (2026-09-17T16:00:01Z).
|
|
2443
|
+
*
|
|
2444
|
+
* A kind:1621 issue on the `HydrusUI` repo (author
|
|
2445
|
+
* 43d7f07d10b9e662745e10b2fc201a74dc178a308c31409350d06b04477816e1) and its
|
|
2446
|
+
* full kind:1111 NIP-22 comment thread: five comments, including one
|
|
2447
|
+
* NESTED reply. Four of the five comments (`e`/`k`/`p`) point straight at
|
|
2448
|
+
* the root issue; `NGIT_COMMENT_THREAD_NESTED_REPLY` instead points its
|
|
2449
|
+
* lowercase `e`/`k`/`p` at another comment
|
|
2450
|
+
* (`NGIT_COMMENT_THREAD_NESTED_REPLY_PARENT_ID`), while its uppercase
|
|
2451
|
+
* `E`/`K`/`P` still name the root issue — the shape rig#153's comment
|
|
2452
|
+
* builder and readers must produce and accept. Committed byte-for-byte as
|
|
2453
|
+
* received — no edited tags, no re-serialization, tag order preserved — so
|
|
2454
|
+
* every event's id and signature verify (see `ngit-fixtures.test.ts`).
|
|
2455
|
+
*
|
|
2456
|
+
* Captured with `scripts/capture-ngit-fixtures.mjs` (repo root); see that
|
|
2457
|
+
* file for the exact filter and how to re-run the capture.
|
|
2458
|
+
*/
|
|
2459
|
+
|
|
2460
|
+
declare const NGIT_COMMENT_THREAD_RELAY = "wss://relay.ngit.dev";
|
|
2461
|
+
declare const NGIT_COMMENT_THREAD_CAPTURED_AT = "2026-09-17T16:00:01Z";
|
|
2462
|
+
declare const NGIT_COMMENT_THREAD_ROOT_EVENT_ID = "3bb49002757fe697f328a2825fdd00f48a8c376238db65b18906d52864692e2a";
|
|
2463
|
+
declare const NGIT_COMMENT_THREAD_COMMENT_EVENT_IDS: string[];
|
|
2464
|
+
/** The one comment in the thread whose parent is another comment, not the root issue. */
|
|
2465
|
+
declare const NGIT_COMMENT_THREAD_NESTED_REPLY_ID = "952c1fe0a2e88c3c716b56aa2f695349a77220a211779de30e97b115ba94e084";
|
|
2466
|
+
declare const NGIT_COMMENT_THREAD_NESTED_REPLY_PARENT_ID = "6f815f058c6f627eab6f5324f06cda29163e0232f410abf8eff22de250e188c1";
|
|
2467
|
+
/** kind:1621 issue "Bug: Thumbnail Healing / Transfer" on HydrusUI. */
|
|
2468
|
+
declare const NGIT_COMMENT_THREAD_ROOT: NostrEvent;
|
|
2469
|
+
/** All five kind:1111 comments on the thread, oldest first. */
|
|
2470
|
+
declare const NGIT_COMMENT_THREAD_COMMENTS: NostrEvent[];
|
|
2471
|
+
|
|
2472
|
+
/**
|
|
2473
|
+
* Real wire capture from wss://relay.ngit.dev (2026-09-17T16:00:01Z).
|
|
2474
|
+
*
|
|
2475
|
+
* A kind:1631 ("applied"/merged) status event on ngit's own `ngit` repo, in
|
|
2476
|
+
* NIP-10 marker form: `["e", <target-id>, "", "root"]` plus the repo's `a`
|
|
2477
|
+
* coordinate tag — exactly the shape rig#153's status builder must produce
|
|
2478
|
+
* and its readers must resolve, instead of today's bare `["e", <id>]`. Its
|
|
2479
|
+
* target, {@link NGIT_STATUS_NGIT_TARGET}, is the kind:1618 pull request the
|
|
2480
|
+
* status applies to (a `branch-name` tag rides along on it, relevant to a
|
|
2481
|
+
* neighbouring rig#153 ticket). Committed byte-for-byte as received — no
|
|
2482
|
+
* edited tags, no re-serialization, tag order preserved — so both events'
|
|
2483
|
+
* ids and signatures verify (see `ngit-fixtures.test.ts`).
|
|
2484
|
+
*
|
|
2485
|
+
* Captured with `scripts/capture-ngit-fixtures.mjs` (repo root); see that
|
|
2486
|
+
* file for the exact filter and how to re-run the capture.
|
|
2487
|
+
*/
|
|
2488
|
+
|
|
2489
|
+
declare const NGIT_STATUS_NGIT_RELAY = "wss://relay.ngit.dev";
|
|
2490
|
+
declare const NGIT_STATUS_NGIT_CAPTURED_AT = "2026-09-17T16:00:01Z";
|
|
2491
|
+
declare const NGIT_STATUS_NGIT_EVENT_ID = "7fa92c2970493b77974848db0c225e0c37fb6694eabed67387224a4711093b2f";
|
|
2492
|
+
declare const NGIT_STATUS_NGIT_TARGET_EVENT_ID = "fabe42e7c41d4e43e3dcc78db20c3859a7696eb6bc655aed852741e074951c48";
|
|
2493
|
+
/** kind:1631 status ("applied") in NIP-10 marker form, targeting the PR below. */
|
|
2494
|
+
declare const NGIT_STATUS_NGIT: NostrEvent;
|
|
2495
|
+
/** kind:1618 pull request that {@link NGIT_STATUS_NGIT} targets. */
|
|
2496
|
+
declare const NGIT_STATUS_NGIT_TARGET: NostrEvent;
|
|
2497
|
+
|
|
2498
|
+
/**
|
|
2499
|
+
* Real NIP-34 wire fixtures captured from `wss://relay.ngit.dev` (rig#155,
|
|
2500
|
+
* spec rig#153). Conformance is tested against what the incumbent (ngit)
|
|
2501
|
+
* actually publishes, not against our reading of the NIP.
|
|
2502
|
+
*
|
|
2503
|
+
* Every event here is committed exactly as the relay sent it — no edited
|
|
2504
|
+
* tags, no re-serialization — so `ngit-fixtures.test.ts` can verify each
|
|
2505
|
+
* one's id and signature. `@toon-protocol/rig` imports these fixtures from
|
|
2506
|
+
* this module and re-exports them from its package index.
|
|
2507
|
+
* `@toon-protocol/rig-web` tests use a self-contained COPY of this same
|
|
2508
|
+
* captured data instead of importing this package directly
|
|
2509
|
+
* (`packages/rig-web/src/web/__fixtures__/ngit-wire.ts`) — rig-web's
|
|
2510
|
+
* typecheck gate runs before `@toon-protocol/rig` is built, so an import
|
|
2511
|
+
* resolved through its built `dist/` would fail there even though it can
|
|
2512
|
+
* look fine locally with a stale `dist/`. See that file's header for the
|
|
2513
|
+
* full rationale.
|
|
2514
|
+
*
|
|
2515
|
+
* Re-capture with `scripts/capture-ngit-fixtures.mjs` (repo root); update
|
|
2516
|
+
* BOTH this package's fixtures and rig-web's copy from the same capture.
|
|
2517
|
+
*/
|
|
2518
|
+
|
|
2519
|
+
/** Every captured event, flattened — for the id/signature verification test. */
|
|
2520
|
+
declare const ALL_NGIT_FIXTURE_EVENTS: NostrEvent[];
|
|
2521
|
+
|
|
2522
|
+
export { ALL_NGIT_FIXTURE_EVENTS, type AnnouncementEdits, type BuildIncrementOfferOptions, type BuildNarrationOptions, type BuildResultEventOptions, CI_ADVERTISEMENT_KIND, CI_JOB_RESULT_KIND, CI_MANUAL_TRIGGER_KIND, CI_MAX_ADVERTISEMENT_TTL, CI_MAX_PROGRESS_TTL, CI_RUNNER_FAMILY, CI_SECRET_UPDATE_KIND, CI_SERVICE_REQUEST_KIND, CI_SERVICE_STOP_KIND, CI_SOFTWARE, CI_TRUST_ORDER, CI_WORKFLOW_PROGRESS_KIND, CI_WORKFLOW_RESULT_KIND, type CiAdmissionPolicy, type CiAdvertisement, type CiAdvertisementInput, type CiArtifact, type CiBillingPolicy, type CiConclusion, type CiExecutionPolicy, type CiJobQuote, type CiJobResult, type CiJobResultInput, type CiManualTrigger, type CiPrContext, type CiProgressStatus, type CiProvenance, type CiSecretUpdate, type CiSecretUpdateArgs, type CiStatusJob, type CiStatusReport, type CiStatusRun, type CiStatusSummary, type CiTriggerContext, type CiTriggerReason, type CiTrustLevel, type CiWorkflowProgress, type CiWorkflowProgressInput, type CiWorkflowRef, type CiWorkflowResult, type CiWorkflowResultInput, type ClosureResult, type CollectRepoObjectsOptions, type CollectRepoObjectsResult, DEFAULT_CONCURRENCY, type DeriveTrustLevelArgs, type DiscoveredWorkflow, type DownloadOptions, type DownloadResult, EARLIEST_UNIQUE_COMMIT_MARKER, type EncryptedArtifact, type EncryptedArtifactRef, type ExecuteFactoryJobOptions, type ExecutePushOptions, type ExistingAnnouncement, FACTORY_JOB_FEEDBACK_KIND, FACTORY_JOB_REQUEST_KIND, FACTORY_JOB_RESULT_KIND, type FactoryJobExecution, type FactoryJobHooks, type FactoryJobOutcome, type FactoryJobRequest, type FactoryJobWork, type FactoryMilestone, type FactoryTicket, FakeRunner, type FakeRunnerScript, FeeRates, type FetchLike, type FetchRemoteStateOptions, type FetchedObject, type GateCheck, type GateResult, type GatewayFetchOptions, type GitCommentRequest, GitError, type GitErrorEnvelope, type GitEstimateRequest, type GitEstimateResponse, type GitEventResponse, type GitFeeEstimate, type GitIssueRequest, GitObjectType, type GitPatchRequest, type GitPlannedObject, type GitPublishReceipt, type GitPushRequest, type GitPushResponse, type GitRef, type GitRefUpdate, type GitRepoAddr, GitRepoReader, type GitStatusRequest, type GitStatusValue, type GitUploadStep, type IncrementSpec, type JobDeliveryPort, MAX_SECRET_CIPHERTEXT_BYTES, MAX_SECRET_NAMES, MAX_SECRET_PLAINTEXT_BYTES, MAX_SECRET_VALUE_BYTES, type MissingObject, NGIT_ANNOUNCEMENT_WYRD, NGIT_ANNOUNCEMENT_WYRD_CAPTURED_AT, NGIT_ANNOUNCEMENT_WYRD_EVENT_ID, NGIT_ANNOUNCEMENT_WYRD_RELAY, NGIT_COMMENT_THREAD_CAPTURED_AT, NGIT_COMMENT_THREAD_COMMENTS, NGIT_COMMENT_THREAD_COMMENT_EVENT_IDS, NGIT_COMMENT_THREAD_NESTED_REPLY_ID, NGIT_COMMENT_THREAD_NESTED_REPLY_PARENT_ID, NGIT_COMMENT_THREAD_RELAY, NGIT_COMMENT_THREAD_ROOT, NGIT_COMMENT_THREAD_ROOT_EVENT_ID, NGIT_STATE_NGIT, NGIT_STATE_NGIT_CAPTURED_AT, NGIT_STATE_NGIT_EVENT_ID, NGIT_STATE_NGIT_RELAY, NGIT_STATUS_NGIT, NGIT_STATUS_NGIT_CAPTURED_AT, NGIT_STATUS_NGIT_EVENT_ID, NGIT_STATUS_NGIT_RELAY, NGIT_STATUS_NGIT_TARGET, NGIT_STATUS_NGIT_TARGET_EVENT_ID, NonFastForwardError, type NostrEvent, type NostrFilter, ObjectIntegrityError, type ObjectStat, type ObjectWithPath, ObjectWriteMismatchError, type OfferedIncrement, type OversizeObject, OversizeObjectsError, PayoutPointer, type PlanPushOptions, type PlannedObject, PublishReceipt, Publisher, type PushFeeEstimate, type PushPlan, type PushResult, RELAYS_TAG, RESERVED_SECRET_NAMES, type ReadGitObject, type ReadObjectsResult, type RefFilters, type RefUpdate, type RefUpdateKind, type RejectedRefUpdate, type RelayEvent, type RemoteState, type RepoAddress, type RepoRefs, type Runner, type RunnerArtifact, type RunnerJobResult, type RunnerRequest, type RunnerRunResult, SECRET_NAME_RE, type SecretInventory, type SecretInventoryEntry, type SecretUpdatePlaintext, type SelectServiceRequestsOptions, type SelectedServiceRequests, type ServiceControl, type StatObjectsResult, UnsignedEvent, type UploadStepResult, WEB_TAG, WORKFLOW_DIRS, type WebSocketFactory, type WebSocketLike, type WorkflowJob, type WorkflowTriggers, amendRepoAnnouncement, applySecretUpdate, assembleCiStatus, assertSecretUpdateShape, buildCiAdvertisement, buildCiJobResult, buildCiManualTrigger, buildCiSecretUpdate, buildCiServiceRequest, buildCiServiceStop, buildCiWorkflowProgress, buildCiWorkflowResult, buildIncrementOfferEvent, buildNarrationEvent, buildQuoteEvent, buildRepoAnnouncement, buildResultEvent, collectRepoObjects, commonTriggerTags, controlOrder, decryptSecretUpdate, defaultFakeRunResult, deriveTrustLevel, discoverWorkflows, downloadGitObjects, effectiveSecrets, encryptSecretUpdate, executeFactoryJob, executePush, fetchRemoteState, fetchTxBytes, gatePassed, generateSecretsKey, hexToNpub, isCiConclusion, isCiTrustLevel, isSafeRefname, matchesPullRequest, matchesPush, missingObjectsMessage, npubToHex, ownerToHex, parseCiAdvertisement, parseCiJobResult, parseCiManualTrigger, parseCiSecretUpdate, parseCiServiceControl, parseCiTriggerContext, parseCiWorkflowProgress, parseCiWorkflowResult, parseFactoryJobRequest, parseRepoAddress, parseWorkflow, planFactoryJob, planPush, queryRelay, refMatchesPatterns, referencedShas, repoAddress, selectServiceRequests, serializeEventReceipt, serializeFeeEstimate, serializePushPlan, serializePushResult, setHeadSymref, sha256Hex, trustAtLeast, updateRef, validateSecretUpdate, verifyObjectBody, walkClosure, writeGitObject, writeGitObjects };
|