run402 4.67.2 → 4.68.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 +1 -1
- package/gitvault-surface.json +1 -1
- package/lib/repos.mjs +66 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -70,7 +70,7 @@ run402 repos delete --project prj_xyz --force # refuses without --force while th
|
|
|
70
70
|
|
|
71
71
|
A hosted git remote, encrypted before it leaves the machine — no deploy, no manifest, no app. `origin` is claimed additively — an existing `origin` is never touched, the run402 remote falls back to `run402` instead. Every mutating `repos` verb (`create`, `rename`, `delete`, `snapshot`, `policy`, `mirror`, `gc`, `handoff`, `resume`) is CLI/OpenClaw-only by design — no MCP tool exists or will exist for them (one-shot recovery receipts, immutable generations, irreversible delete, single-use bearer keys). Three READ-ONLY tools do exist — `repos_view`, `repos_list_heads`, `repos_fsck` — teaching only `repos` spellings. See `run402 repos --help` for the full tiered surface (common: `create`/`view`/`list`; occasional: `snapshot`/`mirror`/`recover`/`handoff`/`resume`; lifecycle: `rename`/`delete`; maintenance: `fsck`/`gc`/`access`/`policy`), and the CLI reference's `repos` section for the terminal-loss statement and the progressive backup warning.
|
|
72
72
|
|
|
73
|
-
**Handoff / resume.** `run402 repos handoff [--note-file <path>]` captures the actual working tree (staged/unstaged/untracked, like `git stash push -u`) into the vault and mints a single-use bearer key (`kgh1_…`, printed to stdout exactly once); `run402 repos resume <kgh1_…>` claims it on another machine, clones fresh, and reapplies the exact dirty state with `git stash apply --index`. No shared keystore, no shared allowance — the key is the whole handoff. Sensitive untracked files (`.env`, `*.pem`, SSH/AWS/GPG dirs, …) are excluded from capture by default (`--include-sensitive <glob>` re-admits one). See the reference `run402.com/llms-cli.txt` for the full note-schema and flag reference.
|
|
73
|
+
**Handoff / resume.** `run402 repos handoff [--note-file <path>]` captures the actual working tree (staged/unstaged/untracked, like `git stash push -u`) into the vault and mints a single-use bearer key (`kgh1_…`, printed to stdout exactly once); `run402 repos resume <kgh1_…>` claims it on another machine, clones fresh, and reapplies the exact dirty state with `git stash apply --index`. No shared keystore, no shared allowance — the key is the whole handoff. On a wallet with no active tier, `resume` first folds the same cold-start chain `create` does (allowance → faucet → one x402 prototype payment); `--no-init` opts out, and the claim itself never waits on it. Sensitive untracked files (`.env`, `*.pem`, SSH/AWS/GPG dirs, …) are excluded from capture by default (`--include-sensitive <glob>` re-admits one). See the reference `run402.com/llms-cli.txt` for the full note-schema and flag reference.
|
|
74
74
|
|
|
75
75
|
**Named addressing.** `run402 org slug <slug>` (owner-only, small one-time fee) claims an org's globally-unique, address-form slug, after which `run402::<slug>/<name>` addresses any repo under it — `git push` to a name that doesn't exist yet push-to-creates it. `run402 repos rename <name> [--project <id>]` claims the per-org-unique `<name>` half explicitly (no fee); `repos create` claims one automatically, best-effort, when the org already has a slug. Also CLI/SDK-only — no MCP tool.
|
|
76
76
|
|
package/gitvault-surface.json
CHANGED
package/lib/repos.mjs
CHANGED
|
@@ -26,7 +26,7 @@ import { basename, join } from "node:path";
|
|
|
26
26
|
import { getSdk } from "./sdk.mjs";
|
|
27
27
|
import { reportSdkError, fail } from "./sdk-errors.mjs";
|
|
28
28
|
import { withAutoApprove } from "./operator.mjs";
|
|
29
|
-
import { allowanceAuthHeaders, isCoreApiTarget, resolveProjectId } from "./config.mjs";
|
|
29
|
+
import { allowanceAuthHeaders, isCoreApiTarget, readAllowance, resolveProjectId } from "./config.mjs";
|
|
30
30
|
import { loadLiveControlPlaneSession } from "../core-dist/control-plane-session.js";
|
|
31
31
|
import { resolveOrgId, resolveOwningOrgId } from "./org-context.mjs";
|
|
32
32
|
import { resolveGitvaultTarget } from "./gitvault-target.mjs";
|
|
@@ -74,7 +74,7 @@ Handoff (pass a working tree to another agent):
|
|
|
74
74
|
run402 repos handoff [--project <id>] [--repo <repo_id>] [--ttl <seconds>] [--role <role>]
|
|
75
75
|
[--include-sensitive <glob>]... [--note-file <path>] [--json] [--list] [--revoke <handoff_id>]
|
|
76
76
|
(the Handoff Note is JSON piped on stdin when not using --note-file)
|
|
77
|
-
run402 repos resume <kgh1_…|--key-stdin> [--to <dir>] [--json]
|
|
77
|
+
run402 repos resume <kgh1_…|--key-stdin> [--to <dir>] [--no-init] [--json]
|
|
78
78
|
|
|
79
79
|
Occasional:
|
|
80
80
|
run402 repos snapshot [--project <id>] [--repo <repo_id>] [--message <text>] [--checkpoint] [--dry-run] [--allow-dirty] [--manifest-out <path>]
|
|
@@ -151,9 +151,14 @@ Subcommands:
|
|
|
151
151
|
<glob>\` re-admits a named untracked path the sensitive denylist
|
|
152
152
|
would otherwise exclude (repeatable). \`--list\`/\`--revoke
|
|
153
153
|
<handoff_id>\` read/revoke instead of minting.
|
|
154
|
-
resume Resume a Handoff Key on ANY machine: parses the key
|
|
155
|
-
with
|
|
156
|
-
|
|
154
|
+
resume Resume a Handoff Key on ANY machine: parses the key; on a wallet
|
|
155
|
+
with no active tier first folds the same cold-start chain
|
|
156
|
+
\`create\` does (allowance → faucet → one x402 prototype payment,
|
|
157
|
+
each step announced) so the resumed agent arrives as a paid-up
|
|
158
|
+
run402 wallet of its own — \`--no-init\` opts out, and because the
|
|
159
|
+
claim itself needs no tier a chain failure is reported (never
|
|
160
|
+
blocks the resume); then claims the key with THIS machine's own
|
|
161
|
+
wallet, clones the vault at the base HEAD
|
|
157
162
|
into \`--to <dir>\` (default: the vault's name), applies the
|
|
158
163
|
stash-shaped checkpoint (staged/unstaged/deleted/untracked
|
|
159
164
|
restored distinctly), pins the repo/org/room into the checkout's
|
|
@@ -1668,6 +1673,48 @@ async function handoff(args) {
|
|
|
1668
1673
|
}
|
|
1669
1674
|
}
|
|
1670
1675
|
|
|
1676
|
+
/**
|
|
1677
|
+
* Whether this wallet needs the cold-start chain before a resume: no
|
|
1678
|
+
* allowance file yet (a fresh machine — the viral case), or an allowance
|
|
1679
|
+
* whose org holds no active tier. An unreachable tier status reads as
|
|
1680
|
+
* "no" — the claim needs no tier, and a resume must never wait on a status
|
|
1681
|
+
* read.
|
|
1682
|
+
*/
|
|
1683
|
+
async function resumeNeedsColdStart(sdk) {
|
|
1684
|
+
if (!readAllowance()) return true;
|
|
1685
|
+
try {
|
|
1686
|
+
const status = await sdk.tier.status();
|
|
1687
|
+
return status?.active === false;
|
|
1688
|
+
} catch {
|
|
1689
|
+
return false;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
/**
|
|
1694
|
+
* `resume`'s cold-start fold: the SAME chain `create` runs on
|
|
1695
|
+
* NO_ACTIVE_TIER (`cold-start.mjs`), announced step by step on stderr.
|
|
1696
|
+
* Never throws — a failure is returned as `{ error, next_action }` so the
|
|
1697
|
+
* caller carries it in the result and proceeds with the claim.
|
|
1698
|
+
*/
|
|
1699
|
+
async function foldColdStartForResume(sdk) {
|
|
1700
|
+
if (!(await resumeNeedsColdStart(sdk))) return { performed: false, skipped: "tier_active" };
|
|
1701
|
+
console.error("no active tier — folding the cold-start chain (allowance -> faucet -> prototype tier) before the claim");
|
|
1702
|
+
try {
|
|
1703
|
+
const { foldColdStartChain } = await import("./cold-start.mjs");
|
|
1704
|
+
const chain = await foldColdStartChain((line) => console.error(` ${line}`));
|
|
1705
|
+
return { performed: true, ...chain };
|
|
1706
|
+
} catch (err) {
|
|
1707
|
+
const code = err?.body?.code ?? err?.code ?? null;
|
|
1708
|
+
const message = err?.body?.message ?? err?.message ?? String(err);
|
|
1709
|
+
console.error(`cold-start chain failed (${code ?? "error"}: ${message}) — continuing with the claim; run \`run402 tier set prototype\` afterwards`);
|
|
1710
|
+
return {
|
|
1711
|
+
performed: false,
|
|
1712
|
+
error: { code, message },
|
|
1713
|
+
next_action: { type: "renew_tier", command: "run402 tier set prototype", why: "The resume proceeded without a tier of your own; the perpetual prototype tier is what lets this wallet create and deploy projects." },
|
|
1714
|
+
};
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
|
|
1671
1718
|
/** `kygit.handoff-note.v1` rendered as Markdown — `resume`'s default (non-`--json`) rendering. */
|
|
1672
1719
|
function renderHandoffNoteMarkdown(note) {
|
|
1673
1720
|
if (!note) return null;
|
|
@@ -1708,7 +1755,7 @@ function renderHandoffNoteMarkdown(note) {
|
|
|
1708
1755
|
|
|
1709
1756
|
async function resume(args) {
|
|
1710
1757
|
const a = normalizeArgv(args);
|
|
1711
|
-
assertKnownFlags(a, [...RESUME_VALUE_FLAGS, "--key-stdin", "--json", "-v", "--verbose", "--help", "-h"], RESUME_VALUE_FLAGS);
|
|
1758
|
+
assertKnownFlags(a, [...RESUME_VALUE_FLAGS, "--key-stdin", "--no-init", "--json", "-v", "--verbose", "--help", "-h"], RESUME_VALUE_FLAGS);
|
|
1712
1759
|
const sdk = getSdk();
|
|
1713
1760
|
const keyStdin = a.includes("--key-stdin");
|
|
1714
1761
|
const to = flagValue(a, "--to");
|
|
@@ -1718,10 +1765,22 @@ async function resume(args) {
|
|
|
1718
1765
|
key = (await readStdinText()).trim();
|
|
1719
1766
|
if (!key) fail({ code: "BAD_USAGE", message: "Missing the Handoff Key on stdin.", hint: "Pipe the kgh1_… key, or pass it as a positional argument." });
|
|
1720
1767
|
}
|
|
1768
|
+
// Decided 2026-09-02 (Tal; amends kygit-handoff design D5's "none on
|
|
1769
|
+
// resume"): a resumed agent is a NEW run402 wallet, and the loop is the
|
|
1770
|
+
// point — so on a wallet with no active tier `resume` folds the same
|
|
1771
|
+
// cold-start chain `create` does (allowance → faucet → one x402
|
|
1772
|
+
// prototype payment, announced) BEFORE the claim. The claim itself needs
|
|
1773
|
+
// no tier, so the chain is never allowed to block a resume: a faucet
|
|
1774
|
+
// throttle or payment failure is reported on stderr, carried in the
|
|
1775
|
+
// result as `cold_start.error` with a `renew_tier` next action, and the
|
|
1776
|
+
// claim proceeds (the SDK still creates the bare wallet it needs).
|
|
1777
|
+
// `--no-init` opts out entirely.
|
|
1778
|
+
const coldStart = a.includes("--no-init") ? { performed: false, skipped: "no_init" } : await foldColdStartForResume(sdk);
|
|
1721
1779
|
try {
|
|
1722
1780
|
const result = await sdk.gitvault.resume({ key, ...(to != null ? { to } : {}), onLine: (line) => console.error(line) });
|
|
1781
|
+
if (coldStart.next_action) result.next_actions = [...(result.next_actions ?? []), coldStart.next_action];
|
|
1723
1782
|
if (a.includes("--json")) {
|
|
1724
|
-
printJson(sdk, result);
|
|
1783
|
+
printJson(sdk, { ...result, cold_start: coldStart });
|
|
1725
1784
|
} else {
|
|
1726
1785
|
const rendered = renderHandoffNoteMarkdown(result.note) ?? result.note_raw;
|
|
1727
1786
|
if (rendered) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "run402",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.68.0",
|
|
4
4
|
"description": "CLI for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|