@run402/sdk 4.126.0 → 4.126.2
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/dist/kernel.d.ts +9 -0
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +13 -4
- package/dist/kernel.js.map +1 -1
- package/dist/namespaces/events.d.ts +3 -1
- package/dist/namespaces/events.d.ts.map +1 -1
- package/dist/namespaces/events.js +4 -2
- package/dist/namespaces/events.js.map +1 -1
- package/dist/namespaces/projects.d.ts +5 -1
- package/dist/namespaces/projects.d.ts.map +1 -1
- package/dist/namespaces/projects.js +116 -24
- package/dist/namespaces/projects.js.map +1 -1
- package/dist/namespaces/push.d.ts +3 -1
- package/dist/namespaces/push.d.ts.map +1 -1
- package/dist/namespaces/push.js +5 -1
- package/dist/namespaces/push.js.map +1 -1
- package/dist/namespaces/rooms.d.ts.map +1 -1
- package/dist/namespaces/rooms.js +106 -124
- package/dist/namespaces/rooms.js.map +1 -1
- package/dist/namespaces/snapshots.d.ts +6 -0
- package/dist/namespaces/snapshots.d.ts.map +1 -1
- package/dist/namespaces/snapshots.js +9 -0
- package/dist/namespaces/snapshots.js.map +1 -1
- package/dist/node/actions-node.d.ts.map +1 -1
- package/dist/node/actions-node.js +159 -56
- package/dist/node/actions-node.js.map +1 -1
- package/dist/node/status.d.ts +2 -1
- package/dist/node/status.d.ts.map +1 -1
- package/dist/node/status.js +1 -1
- package/dist/node/status.js.map +1 -1
- package/dist/node/workflow-output.d.ts.map +1 -1
- package/dist/node/workflow-output.js +27 -3
- package/dist/node/workflow-output.js.map +1 -1
- package/dist/project-id.d.ts +31 -0
- package/dist/project-id.d.ts.map +1 -0
- package/dist/project-id.js +53 -0
- package/dist/project-id.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions-node.d.ts","sourceRoot":"","sources":["../../src/node/actions-node.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAIV,kBAAkB,EAClB,sBAAsB,EACtB,aAAa,EAGb,kCAAkC,EAClC,wBAAwB,EACxB,mBAAmB,EACnB,cAAc,EAGf,MAAM,eAAe,CAAC;AAEvB,OAAO,EAaL,KAAK,qBAAqB,EAG3B,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAU1C,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,KAAK,EAAY,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAUrE,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAEhE,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAwKD;;;GAGG;AAEH,qBAAa,WAAY,YAAW,aAAa;;IAE7C,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFvB,YACmB,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,kBAAuB,EAC5C;IAEE,GAAG,CACP,KAAK,EAAE,kCAAkC,EACzC,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC,CAAC;IAC1C,GAAG,CACP,KAAK,EAAE,wBAAwB,EAC/B,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC;IACxC,GAAG,CACP,KAAK,EAAE,mBAAmB,EAC1B,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC,CAAC;IA2CzC,EAAE,CACN,KAAK,GAAE,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAM,EAC7C,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC,CAG7C;
|
|
1
|
+
{"version":3,"file":"actions-node.d.ts","sourceRoot":"","sources":["../../src/node/actions-node.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAIV,kBAAkB,EAClB,sBAAsB,EACtB,aAAa,EAGb,kCAAkC,EAClC,wBAAwB,EACxB,mBAAmB,EACnB,cAAc,EAGf,MAAM,eAAe,CAAC;AAEvB,OAAO,EAaL,KAAK,qBAAqB,EAG3B,MAAM,cAAc,CAAC;AAGtB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAU1C,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,iCAAiC,CAAC;AACvF,OAAO,KAAK,EAAY,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAUrE,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAEhE,MAAM,WAAW,kBAAkB;IACjC,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAwKD;;;GAGG;AAEH,qBAAa,WAAY,YAAW,aAAa;;IAE7C,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFvB,YACmB,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,kBAAuB,EAC5C;IAEE,GAAG,CACP,KAAK,EAAE,kCAAkC,EACzC,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,eAAe,CAAC,CAAC,CAAC;IAC1C,GAAG,CACP,KAAK,EAAE,wBAAwB,EAC/B,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC,CAAC;IACxC,GAAG,CACP,KAAK,EAAE,mBAAmB,EAC1B,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC,CAAC;IA2CzC,EAAE,CACN,KAAK,GAAE,IAAI,CAAC,mBAAmB,EAAE,MAAM,CAAM,EAC7C,IAAI,CAAC,EAAE,sBAAsB,GAC5B,OAAO,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC,CAG7C;CAozEF;AA4bD;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAU3F;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAUzG;AA0iBD,mGAAmG;AACnG,wBAAsB,uBAAuB,CAAC,KAAK,EAAE;IACnD,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACtH,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,oBAAoB,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC/F,GAAG,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,UAAU,GAAG,gBAAgB,GAAG,UAAU,GAAG,QAAQ,GAAG,YAAY,CAAA;CAAE,CAAC,CAmBpJ"}
|
|
@@ -128,7 +128,7 @@ export class NodeActions {
|
|
|
128
128
|
}
|
|
129
129
|
const tier = input.tier ?? DEFAULT_BOOTSTRAP_TIER;
|
|
130
130
|
if (run.autoPrerequisites) {
|
|
131
|
-
await this.#ensureCloudTier(run, tier);
|
|
131
|
+
await this.#ensureCloudTier(run, tier, { explicitTier: input.tier !== undefined });
|
|
132
132
|
}
|
|
133
133
|
const idempotencyKey = input.idempotencyKey ?? run.rootIdempotencyKey;
|
|
134
134
|
const step = run.addStep({
|
|
@@ -280,7 +280,7 @@ export class NodeActions {
|
|
|
280
280
|
});
|
|
281
281
|
}
|
|
282
282
|
else if (this.#targetKind() !== "core") {
|
|
283
|
-
await this.#ensureCloudTier(run, input.tier ?? DEFAULT_BOOTSTRAP_TIER);
|
|
283
|
+
await this.#ensureCloudTier(run, input.tier ?? DEFAULT_BOOTSTRAP_TIER, { explicitTier: input.tier !== undefined });
|
|
284
284
|
}
|
|
285
285
|
else {
|
|
286
286
|
run.skipStep({
|
|
@@ -1122,7 +1122,7 @@ export class NodeActions {
|
|
|
1122
1122
|
app_result: blocked,
|
|
1123
1123
|
});
|
|
1124
1124
|
}
|
|
1125
|
-
await this.#ensureCloudTier(run, input.tier ?? DEFAULT_BOOTSTRAP_TIER);
|
|
1125
|
+
await this.#ensureCloudTier(run, input.tier ?? DEFAULT_BOOTSTRAP_TIER, { explicitTier: input.tier !== undefined });
|
|
1126
1126
|
const resolved = await this.#resolveProject(input, manifest, workspaceDir, run);
|
|
1127
1127
|
await this.#recordAppInstallState({
|
|
1128
1128
|
projectId: resolved.projectId,
|
|
@@ -1720,8 +1720,15 @@ export class NodeActions {
|
|
|
1720
1720
|
propagationWaitMs,
|
|
1721
1721
|
};
|
|
1722
1722
|
}
|
|
1723
|
+
/**
|
|
1724
|
+
* Ensure a local wallet exists and, with `fund`, that it holds testnet USDC.
|
|
1725
|
+
* Returns `funded` when this call dripped the faucet, and `planned` when a
|
|
1726
|
+
* dry run planned a wallet that does not exist yet (so nothing about its
|
|
1727
|
+
* organization can be read).
|
|
1728
|
+
*/
|
|
1723
1729
|
async #ensureWallet(run, opts = { fund: false }) {
|
|
1724
1730
|
const status = await this.sdk.wallets.status();
|
|
1731
|
+
let balanceUnknown = false;
|
|
1725
1732
|
if (status.configured) {
|
|
1726
1733
|
run.skipStep({
|
|
1727
1734
|
action: "wallets.create",
|
|
@@ -1731,8 +1738,19 @@ export class NodeActions {
|
|
|
1731
1738
|
details: { address: status.address, path: status.path ?? null },
|
|
1732
1739
|
});
|
|
1733
1740
|
if (!opts.fund)
|
|
1734
|
-
return false;
|
|
1735
|
-
|
|
1741
|
+
return { funded: false, planned: false };
|
|
1742
|
+
let balance;
|
|
1743
|
+
try {
|
|
1744
|
+
balance = await prototypeBalance(status.address);
|
|
1745
|
+
}
|
|
1746
|
+
catch (err) {
|
|
1747
|
+
// A dry run only describes; an unreadable balance plans the faucet
|
|
1748
|
+
// instead of failing the plan. Execution still refuses to guess.
|
|
1749
|
+
if (!run.dryRun)
|
|
1750
|
+
throw err;
|
|
1751
|
+
balance = 0n;
|
|
1752
|
+
balanceUnknown = true;
|
|
1753
|
+
}
|
|
1736
1754
|
if (balance > 0n) {
|
|
1737
1755
|
run.skipStep({
|
|
1738
1756
|
action: "wallets.faucet",
|
|
@@ -1741,7 +1759,7 @@ export class NodeActions {
|
|
|
1741
1759
|
auto: true,
|
|
1742
1760
|
details: { address: status.address, balance_usd_micros: balance.toString() },
|
|
1743
1761
|
});
|
|
1744
|
-
return false;
|
|
1762
|
+
return { funded: false, planned: false };
|
|
1745
1763
|
}
|
|
1746
1764
|
}
|
|
1747
1765
|
else {
|
|
@@ -1754,7 +1772,7 @@ export class NodeActions {
|
|
|
1754
1772
|
await run.approve(createStep, ["wallets.create"], "Create a local wallet.");
|
|
1755
1773
|
if (run.dryRun) {
|
|
1756
1774
|
run.setState(createStep, "planned");
|
|
1757
|
-
return false;
|
|
1775
|
+
return { funded: false, planned: true };
|
|
1758
1776
|
}
|
|
1759
1777
|
run.setState(createStep, "running");
|
|
1760
1778
|
const created = await this.sdk.wallets.create();
|
|
@@ -1763,7 +1781,7 @@ export class NodeActions {
|
|
|
1763
1781
|
path: created.path ?? null,
|
|
1764
1782
|
});
|
|
1765
1783
|
if (!opts.fund)
|
|
1766
|
-
return false;
|
|
1784
|
+
return { funded: false, planned: false };
|
|
1767
1785
|
}
|
|
1768
1786
|
const faucetKey = run.childKey("wallets.faucet");
|
|
1769
1787
|
const faucetStep = run.addStep({
|
|
@@ -1771,12 +1789,16 @@ export class NodeActions {
|
|
|
1771
1789
|
description: "Request testnet faucet funds for wallet",
|
|
1772
1790
|
mutation: true,
|
|
1773
1791
|
auto: true,
|
|
1774
|
-
details: {
|
|
1792
|
+
details: {
|
|
1793
|
+
idempotency_key: faucetKey ?? null,
|
|
1794
|
+
...(opts.reason ? { reason: opts.reason } : {}),
|
|
1795
|
+
...(balanceUnknown ? { balance: "unknown" } : {}),
|
|
1796
|
+
},
|
|
1775
1797
|
});
|
|
1776
1798
|
await run.approve(faucetStep, ["wallets.faucet"], "Request testnet USDC for the local wallet.");
|
|
1777
1799
|
if (run.dryRun) {
|
|
1778
1800
|
run.setState(faucetStep, "planned");
|
|
1779
|
-
return false;
|
|
1801
|
+
return { funded: false, planned: false };
|
|
1780
1802
|
}
|
|
1781
1803
|
run.setState(faucetStep, "running");
|
|
1782
1804
|
const faucet = await this.sdk.wallets.faucet(faucetKey ? { idempotencyKey: faucetKey } : {});
|
|
@@ -1785,75 +1807,134 @@ export class NodeActions {
|
|
|
1785
1807
|
amount: faucet.amount,
|
|
1786
1808
|
network: faucet.network,
|
|
1787
1809
|
});
|
|
1788
|
-
return true;
|
|
1810
|
+
return { funded: true, planned: false };
|
|
1789
1811
|
}
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
reason: "dry_run",
|
|
1810
|
-
},
|
|
1812
|
+
/**
|
|
1813
|
+
* Bootstrap readiness: make sure the caller's organization holds a tier at
|
|
1814
|
+
* least `desiredTier`. A dry run resolves this against the real organization
|
|
1815
|
+
* exactly as execution does (one read of `GET /tiers/v1/status`), so a plan
|
|
1816
|
+
* never lists a purchase that execution would skip. Bootstrap never buys a
|
|
1817
|
+
* tier lower than the organization's current one unless the caller named
|
|
1818
|
+
* that tier explicitly (`explicitTier`).
|
|
1819
|
+
*/
|
|
1820
|
+
async #ensureCloudTier(run, desiredTier, opts = {}) {
|
|
1821
|
+
const wallet = await this.#ensureWallet(run, { fund: false });
|
|
1822
|
+
const idempotencyKey = run.childKey("tier.set");
|
|
1823
|
+
if (wallet.planned) {
|
|
1824
|
+
// Dry run, no local wallet yet: a new wallet has no organization and no
|
|
1825
|
+
// tier, so bootstrap would fund it and start the tier.
|
|
1826
|
+
const reason = "new wallet has no tier";
|
|
1827
|
+
await this.#planFaucet(run, reason);
|
|
1828
|
+
await this.#planTierPurchase(run, desiredTier, {
|
|
1829
|
+
description: `Start the ${desiredTier} tier`,
|
|
1830
|
+
details: { tier: desiredTier, current_tier: null, active: false, reason, idempotency_key: idempotencyKey ?? null },
|
|
1811
1831
|
});
|
|
1812
|
-
await run.approve(step, ["tier.set"], `Set the ${desiredTier} tier if no active tier exists.`);
|
|
1813
|
-
run.setState(step, "planned");
|
|
1814
1832
|
return;
|
|
1815
1833
|
}
|
|
1816
|
-
let status;
|
|
1834
|
+
let status = null;
|
|
1835
|
+
let statusError = null;
|
|
1817
1836
|
try {
|
|
1818
1837
|
status = await this.sdk.tier.status();
|
|
1819
1838
|
}
|
|
1820
|
-
catch {
|
|
1821
|
-
|
|
1839
|
+
catch (err) {
|
|
1840
|
+
statusError = err;
|
|
1841
|
+
}
|
|
1842
|
+
if (!status) {
|
|
1843
|
+
const error = statusError instanceof Error ? statusError.message : String(statusError);
|
|
1844
|
+
if (run.dryRun) {
|
|
1845
|
+
const reason = "tier status unavailable";
|
|
1846
|
+
await this.#planFaucet(run, reason);
|
|
1847
|
+
await this.#planTierPurchase(run, desiredTier, {
|
|
1848
|
+
description: `Set the ${desiredTier} tier if the organization has no tier at least ${desiredTier} (current tier unknown)`,
|
|
1849
|
+
details: { tier: desiredTier, current_tier: "unknown", reason, error, idempotency_key: idempotencyKey ?? null },
|
|
1850
|
+
});
|
|
1851
|
+
return;
|
|
1852
|
+
}
|
|
1853
|
+
// Paying blind could replace a higher tier the organization already holds.
|
|
1854
|
+
throw run.error(`Could not read the organization's tier (GET /tiers/v1/status failed: ${error}). Bootstrap does not buy a tier without knowing the current one.`, "RUN402_TIER_STATUS_UNAVAILABLE", {
|
|
1855
|
+
desired_tier: desiredTier,
|
|
1856
|
+
error,
|
|
1857
|
+
next_actions: [{
|
|
1858
|
+
type: "check_usage",
|
|
1859
|
+
command: "run402 tier status",
|
|
1860
|
+
argv: ["run402", "tier", "status"],
|
|
1861
|
+
why: "Confirm the organization's current tier, then retry.",
|
|
1862
|
+
}],
|
|
1863
|
+
});
|
|
1822
1864
|
}
|
|
1823
|
-
const current = normalizeTier(status
|
|
1824
|
-
|
|
1865
|
+
const current = normalizeTier(status.tier);
|
|
1866
|
+
const facts = {
|
|
1867
|
+
current_tier: current ?? status.tier ?? null,
|
|
1868
|
+
desired_tier: desiredTier,
|
|
1869
|
+
active: status.active,
|
|
1870
|
+
lease_perpetual: status.lease_perpetual ?? null,
|
|
1871
|
+
lease_expires_at: status.lease_expires_at ?? null,
|
|
1872
|
+
};
|
|
1873
|
+
if (status.active && current && TIER_RANK[current] >= TIER_RANK[desiredTier]) {
|
|
1874
|
+
const reason = `org has active ${current} tier`;
|
|
1825
1875
|
run.skipStep({
|
|
1826
|
-
action:
|
|
1827
|
-
description:
|
|
1876
|
+
action: "wallets.faucet",
|
|
1877
|
+
description: `Faucet not needed: ${reason}`,
|
|
1828
1878
|
mutation: false,
|
|
1829
1879
|
auto: true,
|
|
1830
|
-
details: {
|
|
1880
|
+
details: { reason },
|
|
1831
1881
|
});
|
|
1832
|
-
return;
|
|
1833
|
-
}
|
|
1834
|
-
if (status?.active && current && TIER_RANK[current] > TIER_RANK[desiredTier]) {
|
|
1835
1882
|
run.skipStep({
|
|
1836
1883
|
action: Run402Action.TierSet,
|
|
1837
|
-
description:
|
|
1884
|
+
description: current === desiredTier
|
|
1885
|
+
? `Active ${current} tier already in place`
|
|
1886
|
+
: `Active ${current} tier already satisfies the ${desiredTier} requirement`,
|
|
1838
1887
|
mutation: false,
|
|
1839
1888
|
auto: true,
|
|
1840
|
-
details: {
|
|
1889
|
+
details: { reason, ...facts },
|
|
1841
1890
|
});
|
|
1842
1891
|
return;
|
|
1843
1892
|
}
|
|
1844
|
-
|
|
1845
|
-
|
|
1893
|
+
if (current && TIER_RANK[current] > TIER_RANK[desiredTier] && !opts.explicitTier) {
|
|
1894
|
+
// The organization's higher tier has lapsed. Buying the default lower
|
|
1895
|
+
// tier would replace it; that takes an explicit choice.
|
|
1896
|
+
const retryVerb = run.input.type === Run402Action.ProjectsProvision
|
|
1897
|
+
? ["run402", "projects", "provision"]
|
|
1898
|
+
: ["run402", "up"];
|
|
1899
|
+
throw run.error(`The organization's ${current} tier is not active. Bootstrap will not replace it with the lower default ${desiredTier} tier. Renew ${current}, or pass the tier explicitly to accept ${desiredTier}.`, "RUN402_TIER_DOWNGRADE_REFUSED", {
|
|
1900
|
+
...facts,
|
|
1901
|
+
next_actions: [
|
|
1902
|
+
{
|
|
1903
|
+
type: "renew_tier",
|
|
1904
|
+
command: `run402 tier set ${current}`,
|
|
1905
|
+
argv: ["run402", "tier", "set", current],
|
|
1906
|
+
why: `Renew the organization's ${current} tier, then retry.`,
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
type: "retry",
|
|
1910
|
+
command: `${retryVerb.join(" ")} --tier ${desiredTier}`,
|
|
1911
|
+
argv: [...retryVerb, "--tier", desiredTier],
|
|
1912
|
+
why: `Accept the lower ${desiredTier} tier explicitly.`,
|
|
1913
|
+
},
|
|
1914
|
+
],
|
|
1915
|
+
});
|
|
1916
|
+
}
|
|
1917
|
+
const description = !current
|
|
1918
|
+
? `Start the ${desiredTier} tier`
|
|
1919
|
+
: current === desiredTier
|
|
1920
|
+
? `Renew the ${desiredTier} tier (current lease is not active)`
|
|
1921
|
+
: TIER_RANK[current] < TIER_RANK[desiredTier]
|
|
1922
|
+
? `Upgrade tier from ${current} to ${desiredTier}`
|
|
1923
|
+
: `Set the ${desiredTier} tier as requested (current ${current} tier is not active)`;
|
|
1924
|
+
const reason = !current ? "org has no tier" : status.active ? `org has active ${current} tier` : `org's ${current} tier is not active`;
|
|
1925
|
+
const details = { tier: desiredTier, ...facts, reason, idempotency_key: idempotencyKey ?? null };
|
|
1926
|
+
if (run.dryRun) {
|
|
1927
|
+
await this.#ensureWallet(run, { fund: true, reason: "tier payment may be needed" });
|
|
1928
|
+
await this.#planTierPurchase(run, desiredTier, { description, details });
|
|
1929
|
+
return;
|
|
1930
|
+
}
|
|
1931
|
+
const { funded: justFunded } = await this.#ensureWallet(run, { fund: true });
|
|
1846
1932
|
const step = run.addStep({
|
|
1847
1933
|
action: Run402Action.TierSet,
|
|
1848
|
-
description
|
|
1934
|
+
description,
|
|
1849
1935
|
mutation: true,
|
|
1850
1936
|
auto: true,
|
|
1851
|
-
details
|
|
1852
|
-
tier: desiredTier,
|
|
1853
|
-
current_tier: current ?? null,
|
|
1854
|
-
active: status?.active ?? null,
|
|
1855
|
-
idempotency_key: idempotencyKey ?? null,
|
|
1856
|
-
},
|
|
1937
|
+
details,
|
|
1857
1938
|
});
|
|
1858
1939
|
await run.approve(step, ["tier.set"], `Set the ${desiredTier} tier (start, renew, or upgrade).`);
|
|
1859
1940
|
run.setState(step, "running");
|
|
@@ -1861,6 +1942,28 @@ export class NodeActions {
|
|
|
1861
1942
|
const result = await (justFunded ? afterFaucet(pay) : pay());
|
|
1862
1943
|
run.setState(step, "succeeded", { tier: result.tier, action: result.action });
|
|
1863
1944
|
}
|
|
1945
|
+
async #planFaucet(run, reason) {
|
|
1946
|
+
const step = run.addStep({
|
|
1947
|
+
action: "wallets.faucet",
|
|
1948
|
+
description: "Request testnet faucet funds if tier payment is needed",
|
|
1949
|
+
mutation: true,
|
|
1950
|
+
auto: true,
|
|
1951
|
+
details: { reason },
|
|
1952
|
+
});
|
|
1953
|
+
await run.approve(step, ["wallets.faucet"], "Request testnet USDC if tier bootstrap needs payment.");
|
|
1954
|
+
run.setState(step, "planned");
|
|
1955
|
+
}
|
|
1956
|
+
async #planTierPurchase(run, desiredTier, plan) {
|
|
1957
|
+
const step = run.addStep({
|
|
1958
|
+
action: Run402Action.TierSet,
|
|
1959
|
+
description: plan.description,
|
|
1960
|
+
mutation: true,
|
|
1961
|
+
auto: true,
|
|
1962
|
+
details: plan.details,
|
|
1963
|
+
});
|
|
1964
|
+
await run.approve(step, ["tier.set"], `Set the ${desiredTier} tier (start, renew, or upgrade).`);
|
|
1965
|
+
run.setState(step, "planned");
|
|
1966
|
+
}
|
|
1864
1967
|
async #resolveProject(input, manifest, workspaceDir, run) {
|
|
1865
1968
|
const linkPath = join(workspaceDir, ".run402", "project.json");
|
|
1866
1969
|
const link = await readWorkspaceProjectLink(linkPath);
|