@manifest-network/manifest-agent-core 0.9.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 +39 -0
- package/dist/close-lease.d.ts +33 -0
- package/dist/close-lease.d.ts.map +1 -0
- package/dist/close-lease.js +138 -0
- package/dist/close-lease.js.map +1 -0
- package/dist/deploy-app.d.ts +24 -0
- package/dist/deploy-app.d.ts.map +1 -0
- package/dist/deploy-app.js +446 -0
- package/dist/deploy-app.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +7 -0
- package/dist/internals/classify-deploy-error.d.ts +41 -0
- package/dist/internals/classify-deploy-error.d.ts.map +1 -0
- package/dist/internals/classify-deploy-error.js +79 -0
- package/dist/internals/classify-deploy-error.js.map +1 -0
- package/dist/internals/classify-deploy-response.d.ts +56 -0
- package/dist/internals/classify-deploy-response.d.ts.map +1 -0
- package/dist/internals/classify-deploy-response.js +33 -0
- package/dist/internals/classify-deploy-response.js.map +1 -0
- package/dist/internals/connection.d.ts +76 -0
- package/dist/internals/connection.d.ts.map +1 -0
- package/dist/internals/connection.js +94 -0
- package/dist/internals/connection.js.map +1 -0
- package/dist/internals/evaluate-readiness.d.ts +55 -0
- package/dist/internals/evaluate-readiness.d.ts.map +1 -0
- package/dist/internals/evaluate-readiness.js +131 -0
- package/dist/internals/evaluate-readiness.js.map +1 -0
- package/dist/internals/find-sku-uuid.d.ts +40 -0
- package/dist/internals/find-sku-uuid.d.ts.map +1 -0
- package/dist/internals/find-sku-uuid.js +20 -0
- package/dist/internals/find-sku-uuid.js.map +1 -0
- package/dist/internals/format-success.d.ts +35 -0
- package/dist/internals/format-success.d.ts.map +1 -0
- package/dist/internals/format-success.js +80 -0
- package/dist/internals/format-success.js.map +1 -0
- package/dist/internals/guarded-fetch.d.ts +138 -0
- package/dist/internals/guarded-fetch.d.ts.map +1 -0
- package/dist/internals/guarded-fetch.js +242 -0
- package/dist/internals/guarded-fetch.js.map +1 -0
- package/dist/internals/humanize-denom.d.ts +45 -0
- package/dist/internals/humanize-denom.d.ts.map +1 -0
- package/dist/internals/humanize-denom.js +105 -0
- package/dist/internals/humanize-denom.js.map +1 -0
- package/dist/internals/inspect-image.d.ts +31 -0
- package/dist/internals/inspect-image.d.ts.map +1 -0
- package/dist/internals/inspect-image.js +345 -0
- package/dist/internals/inspect-image.js.map +1 -0
- package/dist/internals/lease-items.d.ts +46 -0
- package/dist/internals/lease-items.d.ts.map +1 -0
- package/dist/internals/lease-items.js +58 -0
- package/dist/internals/lease-items.js.map +1 -0
- package/dist/internals/lease-state.d.ts +32 -0
- package/dist/internals/lease-state.d.ts.map +1 -0
- package/dist/internals/lease-state.js +80 -0
- package/dist/internals/lease-state.js.map +1 -0
- package/dist/internals/render-deployment-plan.d.ts +22 -0
- package/dist/internals/render-deployment-plan.d.ts.map +1 -0
- package/dist/internals/render-deployment-plan.js +135 -0
- package/dist/internals/render-deployment-plan.js.map +1 -0
- package/dist/internals/render-intent-recap.d.ts +43 -0
- package/dist/internals/render-intent-recap.d.ts.map +1 -0
- package/dist/internals/render-intent-recap.js +136 -0
- package/dist/internals/render-intent-recap.js.map +1 -0
- package/dist/internals/render-partial-success-prompt.d.ts +26 -0
- package/dist/internals/render-partial-success-prompt.d.ts.map +1 -0
- package/dist/internals/render-partial-success-prompt.js +53 -0
- package/dist/internals/render-partial-success-prompt.js.map +1 -0
- package/dist/internals/save-manifest.d.ts +105 -0
- package/dist/internals/save-manifest.d.ts.map +1 -0
- package/dist/internals/save-manifest.js +122 -0
- package/dist/internals/save-manifest.js.map +1 -0
- package/dist/internals/secret-denylist.d.ts +42 -0
- package/dist/internals/secret-denylist.d.ts.map +1 -0
- package/dist/internals/secret-denylist.js +59 -0
- package/dist/internals/secret-denylist.js.map +1 -0
- package/dist/internals/spec-normalize.d.ts +84 -0
- package/dist/internals/spec-normalize.d.ts.map +1 -0
- package/dist/internals/spec-normalize.js +169 -0
- package/dist/internals/spec-normalize.js.map +1 -0
- package/dist/internals/verify-domain-state.d.ts +20 -0
- package/dist/internals/verify-domain-state.d.ts.map +1 -0
- package/dist/internals/verify-domain-state.js +63 -0
- package/dist/internals/verify-domain-state.js.map +1 -0
- package/dist/internals/verify-recover.d.ts +120 -0
- package/dist/internals/verify-recover.d.ts.map +1 -0
- package/dist/internals/verify-recover.js +91 -0
- package/dist/internals/verify-recover.js.map +1 -0
- package/dist/manage-domain.d.ts +36 -0
- package/dist/manage-domain.d.ts.map +1 -0
- package/dist/manage-domain.js +230 -0
- package/dist/manage-domain.js.map +1 -0
- package/dist/troubleshoot.d.ts +23 -0
- package/dist/troubleshoot.d.ts.map +1 -0
- package/dist/troubleshoot.js +124 -0
- package/dist/troubleshoot.js.map +1 -0
- package/dist/types.d.ts +294 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +0 -0
- package/package.json +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# @manifest-network/manifest-agent-core
|
|
2
|
+
|
|
3
|
+
TypeScript orchestration surface for Manifest agent flows. This package owns the deploy / manage-domain / troubleshoot / close-lease orchestration that host surfaces consume in lockstep — a bug fix in the core's recovery branch fixes every host surface simultaneously.
|
|
4
|
+
|
|
5
|
+
> **Status.** All four orchestration functions have real implementations as of ENG-129 (PRs 1–4). The package remains `private: true` pending a publish decision; do not depend on it from external repos yet.
|
|
6
|
+
|
|
7
|
+
See [ENG-127](https://linear.app/liftedinit/issue/ENG-127) for the broader initiative and [ENG-128](https://linear.app/liftedinit/issue/ENG-128) for the bootstrap PR.
|
|
8
|
+
|
|
9
|
+
## Layering
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
manifest-mcp-mono — protocol-level tools (RPC over MCP)
|
|
13
|
+
manifest-agent-core — orchestration, verification, recovery, plans, journal (this package)
|
|
14
|
+
host surface(s) — chat / conversational / autonomous front-ends
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The core sits above MCP; host surfaces sit above the core. Callbacks are where surfaces differ — a chat surface emits chat output and `AskUserQuestion`; a conversational surface updates its UI; an autonomous daemon auto-picks recovery branches per policy.
|
|
18
|
+
|
|
19
|
+
## Public surface
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import {
|
|
23
|
+
closeLease,
|
|
24
|
+
deployApp,
|
|
25
|
+
manageDomain,
|
|
26
|
+
troubleshootDeployment,
|
|
27
|
+
} from '@manifest-network/manifest-agent-core';
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Each function takes a typed args object plus a callbacks object with `onConfirm` / `onProgress` / `onComplete` / `onFailure` hooks. `deployApp` takes a `DeploySpec`; the other three take action-discriminated `*Args` types (e.g. `ManageDomainArgs` is `{ action: 'set' | 'clear' | 'lookup', ... }`). Only `deployApp` accepts `onPlan` and uses an enriched `onFailure` — `(failure: FailureEnvelope, options: RecoveryOption[]) => Promise<RecoveryChoice>` — to drive partial-success recovery: retry the set-domain step, salvage the lease without the custom domain, cancel a pending lease, or close an active one. See `RecoveryOptionId` in `src/types.ts` for the exact literal IDs (`retry_set_domain`, `salvage_without_domain`, `cancel_lease`, `close_lease`). The other three use the simpler `(failure: { reason: string }) => Promise<void>`. See `src/types.ts` for the frozen shapes.
|
|
31
|
+
|
|
32
|
+
## Where each function lives
|
|
33
|
+
|
|
34
|
+
| Function | Home |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| `deployApp` | `src/deploy-app.ts` |
|
|
37
|
+
| `manageDomain` | `src/manage-domain.ts` |
|
|
38
|
+
| `troubleshootDeployment` | `src/troubleshoot.ts` |
|
|
39
|
+
| `closeLease` | `src/close-lease.ts` |
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { CloseLeaseArgs, CloseLeaseCallbacks, CloseLeaseOptions, CloseLeaseResult } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/close-lease.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Close a lease and verify it reached a terminal on-chain state.
|
|
6
|
+
*
|
|
7
|
+
* @throws `ManifestMCPError(INVALID_CONFIG)` for args validation or when
|
|
8
|
+
* `onConfirm` returns `'no'`.
|
|
9
|
+
* @throws `ManifestMCPError` (typically `TX_FAILED`) propagated as-is
|
|
10
|
+
* from the `stopApp()` broadcast step. Broadcast errors do NOT invoke
|
|
11
|
+
* `onFailure` — that callback is reserved for post-broadcast
|
|
12
|
+
* verification failures. `stopApp` already raises a structured
|
|
13
|
+
* `ManifestMCPError` from the core package; wrapping it again at this
|
|
14
|
+
* layer would be redundant. Callers wanting to react to broadcast
|
|
15
|
+
* errors should catch them at the call site.
|
|
16
|
+
* @throws `ManifestMCPError(TX_FAILED)` when post-broadcast verification
|
|
17
|
+
* reaches one of two failure modes (both with `onFailure({ reason })`
|
|
18
|
+
* invoked first):
|
|
19
|
+
* - the lease is still non-terminal (`pending_drift` branch — state
|
|
20
|
+
* decoded as PENDING / ACTIVE / similar non-terminal); or
|
|
21
|
+
* - the chain returns `{ lease: null }` post-close, so the lease is
|
|
22
|
+
* not visible on-chain (`unclassified` branch).
|
|
23
|
+
* @throws `ManifestMCPError(QUERY_FAILED)` when the post-broadcast verify
|
|
24
|
+
* chain query (`billing.v1.lease`) raises a non-NotFound error
|
|
25
|
+
* (RPC / transport / decoding failure). Wrapped inside the verifier
|
|
26
|
+
* closure so the failure flows through `onFailure({ reason })` before
|
|
27
|
+
* the throw. Structured `ManifestMCPError`s raised by the chain client
|
|
28
|
+
* are re-thrown as-is (with `onFailure` invoked first).
|
|
29
|
+
*/
|
|
30
|
+
declare function closeLease(args: CloseLeaseArgs, callbacks: CloseLeaseCallbacks, opts: CloseLeaseOptions): Promise<CloseLeaseResult>;
|
|
31
|
+
//#endregion
|
|
32
|
+
export { closeLease };
|
|
33
|
+
//# sourceMappingURL=close-lease.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"close-lease.d.ts","names":[],"sources":["../src/close-lease.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA+EsB,UAAA,CACpB,IAAA,EAAM,cAAA,EACN,SAAA,EAAW,mBAAA,EACX,IAAA,EAAM,iBAAA,GACL,OAAA,CAAQ,gBAAA"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { decode, isTerminal } from "./internals/lease-state.js";
|
|
2
|
+
import { verifyAndRecover } from "./internals/verify-recover.js";
|
|
3
|
+
import { ManifestMCPError, ManifestMCPErrorCode, stopApp } from "@manifest-network/manifest-mcp-core";
|
|
4
|
+
//#region src/close-lease.ts
|
|
5
|
+
/**
|
|
6
|
+
* Public entry point: orchestrate closing an existing lease via the
|
|
7
|
+
* `close-lease` billing tx.
|
|
8
|
+
*
|
|
9
|
+
* Composition (mirrors `deploy-app.ts` / `manage-domain.ts`):
|
|
10
|
+
*
|
|
11
|
+
* 1. Validate args.
|
|
12
|
+
* 2. Render a confirmation block + optionally consult `onConfirm`.
|
|
13
|
+
* 3. Broadcast `stopApp` (which submits `MsgCloseLease`).
|
|
14
|
+
* 4. Verify the post-broadcast on-chain state via `verifyAndRecover`
|
|
15
|
+
* driving a direct `billing.v1.lease({ leaseUuid })` query +
|
|
16
|
+
* `lease-state.decode` + `isTerminal`. Terminal states (CLOSED /
|
|
17
|
+
* REJECTED / EXPIRED / INSUFFICIENT_FUNDS) count as success;
|
|
18
|
+
* PENDING / ACTIVE map to the `pending_drift` branch; a chain
|
|
19
|
+
* response with no lease (`{ lease: null }`) maps to the catch-all
|
|
20
|
+
* `unclassified` branch.
|
|
21
|
+
* 5. On verify-failure, invoke the simple-form `onFailure({ reason })`
|
|
22
|
+
* then throw `ManifestMCPError(TX_FAILED)`. On success, emit
|
|
23
|
+
* `onComplete` with the typed `CloseLeaseResult`.
|
|
24
|
+
*/
|
|
25
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
26
|
+
/**
|
|
27
|
+
* Close a lease and verify it reached a terminal on-chain state.
|
|
28
|
+
*
|
|
29
|
+
* @throws `ManifestMCPError(INVALID_CONFIG)` for args validation or when
|
|
30
|
+
* `onConfirm` returns `'no'`.
|
|
31
|
+
* @throws `ManifestMCPError` (typically `TX_FAILED`) propagated as-is
|
|
32
|
+
* from the `stopApp()` broadcast step. Broadcast errors do NOT invoke
|
|
33
|
+
* `onFailure` — that callback is reserved for post-broadcast
|
|
34
|
+
* verification failures. `stopApp` already raises a structured
|
|
35
|
+
* `ManifestMCPError` from the core package; wrapping it again at this
|
|
36
|
+
* layer would be redundant. Callers wanting to react to broadcast
|
|
37
|
+
* errors should catch them at the call site.
|
|
38
|
+
* @throws `ManifestMCPError(TX_FAILED)` when post-broadcast verification
|
|
39
|
+
* reaches one of two failure modes (both with `onFailure({ reason })`
|
|
40
|
+
* invoked first):
|
|
41
|
+
* - the lease is still non-terminal (`pending_drift` branch — state
|
|
42
|
+
* decoded as PENDING / ACTIVE / similar non-terminal); or
|
|
43
|
+
* - the chain returns `{ lease: null }` post-close, so the lease is
|
|
44
|
+
* not visible on-chain (`unclassified` branch).
|
|
45
|
+
* @throws `ManifestMCPError(QUERY_FAILED)` when the post-broadcast verify
|
|
46
|
+
* chain query (`billing.v1.lease`) raises a non-NotFound error
|
|
47
|
+
* (RPC / transport / decoding failure). Wrapped inside the verifier
|
|
48
|
+
* closure so the failure flows through `onFailure({ reason })` before
|
|
49
|
+
* the throw. Structured `ManifestMCPError`s raised by the chain client
|
|
50
|
+
* are re-thrown as-is (with `onFailure` invoked first).
|
|
51
|
+
*/
|
|
52
|
+
async function closeLease(args, callbacks, opts) {
|
|
53
|
+
validateArgs(args);
|
|
54
|
+
const block = renderConfirmationBlock(args);
|
|
55
|
+
if (callbacks.onConfirm) {
|
|
56
|
+
if (await callbacks.onConfirm(block) !== "yes") throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, "User declined to proceed with close-lease.");
|
|
57
|
+
}
|
|
58
|
+
callbacks.onProgress?.({ kind: "user_confirmed" });
|
|
59
|
+
await stopApp(opts.clientManager, args.leaseUuid);
|
|
60
|
+
const verifyResult = await verifyAndRecover({
|
|
61
|
+
verifier: async () => {
|
|
62
|
+
let result;
|
|
63
|
+
try {
|
|
64
|
+
result = await (await opts.clientManager.getQueryClient()).liftedinit.billing.v1.lease({ leaseUuid: args.leaseUuid });
|
|
65
|
+
} catch (err) {
|
|
66
|
+
const reason = `Failed to query lease ${args.leaseUuid} during close-verify: ${err instanceof Error ? err.message : String(err)}`;
|
|
67
|
+
if (callbacks.onFailure) await callbacks.onFailure({ reason });
|
|
68
|
+
if (err instanceof ManifestMCPError) throw err;
|
|
69
|
+
throw new ManifestMCPError(ManifestMCPErrorCode.QUERY_FAILED, reason);
|
|
70
|
+
}
|
|
71
|
+
const lease = result?.lease;
|
|
72
|
+
if (lease === null || lease === void 0) return {
|
|
73
|
+
outcome: "not_found",
|
|
74
|
+
diagnostic: { reason: `lease ${args.leaseUuid} not visible on chain after close` }
|
|
75
|
+
};
|
|
76
|
+
const rawState = lease.state;
|
|
77
|
+
const stateName = decode(typeof rawState === "number" || typeof rawState === "string" ? rawState : void 0);
|
|
78
|
+
if (stateName === void 0) return {
|
|
79
|
+
outcome: "pending",
|
|
80
|
+
diagnostic: { reason: `lease ${args.leaseUuid} state could not be decoded (raw=${String(rawState)})` }
|
|
81
|
+
};
|
|
82
|
+
return {
|
|
83
|
+
outcome: isTerminal(stateName) ? "terminal" : "pending",
|
|
84
|
+
diagnostic: { stateName }
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
successValues: ["terminal"],
|
|
88
|
+
branches: {
|
|
89
|
+
pending: {
|
|
90
|
+
branchId: "pending_drift",
|
|
91
|
+
journalActionTags: ["close-lease-verify-pending"],
|
|
92
|
+
buildFailureEnvelope: (d) => ({
|
|
93
|
+
outcome: "failed",
|
|
94
|
+
reason: d.reason ?? `close_lease tx accepted but state is still ${d.stateName ?? "unknown"}.`
|
|
95
|
+
}),
|
|
96
|
+
buildRecoveryOptions: () => []
|
|
97
|
+
},
|
|
98
|
+
not_found: {
|
|
99
|
+
branchId: "unclassified",
|
|
100
|
+
journalActionTags: ["close-lease-verify-not-found"],
|
|
101
|
+
buildFailureEnvelope: (d) => ({
|
|
102
|
+
outcome: "failed",
|
|
103
|
+
reason: d.reason ?? `Lease ${args.leaseUuid} not visible on chain after close.`
|
|
104
|
+
}),
|
|
105
|
+
buildRecoveryOptions: () => []
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}, void 0);
|
|
109
|
+
if (verifyResult.result !== "success") {
|
|
110
|
+
const reason = verifyResult.failure?.reason ?? "close-lease verification failed.";
|
|
111
|
+
if (callbacks.onFailure) await callbacks.onFailure({ reason });
|
|
112
|
+
throw new ManifestMCPError(ManifestMCPErrorCode.TX_FAILED, reason);
|
|
113
|
+
}
|
|
114
|
+
if (!verifyResult.diagnostic.stateName) throw new ManifestMCPError(ManifestMCPErrorCode.TX_FAILED, `close-lease verifier invariant violated: success outcome reached without diagnostic.stateName for lease ${args.leaseUuid}`);
|
|
115
|
+
const finalState = verifyResult.diagnostic.stateName;
|
|
116
|
+
const result = {
|
|
117
|
+
leaseUuid: args.leaseUuid,
|
|
118
|
+
finalState
|
|
119
|
+
};
|
|
120
|
+
callbacks.onComplete?.(result);
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
function validateArgs(args) {
|
|
124
|
+
if (typeof args.leaseUuid !== "string" || !args.leaseUuid.match(UUID_RE)) throw new ManifestMCPError(ManifestMCPErrorCode.INVALID_CONFIG, `closeLease: leaseUuid must be a UUID; got "${args.leaseUuid}".`);
|
|
125
|
+
}
|
|
126
|
+
function renderConfirmationBlock(args) {
|
|
127
|
+
return { text: [
|
|
128
|
+
`Close lease ${args.leaseUuid}.`,
|
|
129
|
+
" Image: (image not recorded)",
|
|
130
|
+
" This is permanent — the lease cannot be reopened.",
|
|
131
|
+
"",
|
|
132
|
+
"Proceed?"
|
|
133
|
+
].join("\n") };
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { closeLease };
|
|
137
|
+
|
|
138
|
+
//# sourceMappingURL=close-lease.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"close-lease.js","names":["decodeLeaseState"],"sources":["../src/close-lease.ts"],"sourcesContent":["/**\n * Public entry point: orchestrate closing an existing lease via the\n * `close-lease` billing tx.\n *\n * Composition (mirrors `deploy-app.ts` / `manage-domain.ts`):\n *\n * 1. Validate args.\n * 2. Render a confirmation block + optionally consult `onConfirm`.\n * 3. Broadcast `stopApp` (which submits `MsgCloseLease`).\n * 4. Verify the post-broadcast on-chain state via `verifyAndRecover`\n * driving a direct `billing.v1.lease({ leaseUuid })` query +\n * `lease-state.decode` + `isTerminal`. Terminal states (CLOSED /\n * REJECTED / EXPIRED / INSUFFICIENT_FUNDS) count as success;\n * PENDING / ACTIVE map to the `pending_drift` branch; a chain\n * response with no lease (`{ lease: null }`) maps to the catch-all\n * `unclassified` branch.\n * 5. On verify-failure, invoke the simple-form `onFailure({ reason })`\n * then throw `ManifestMCPError(TX_FAILED)`. On success, emit\n * `onComplete` with the typed `CloseLeaseResult`.\n */\n\nimport {\n ManifestMCPError,\n ManifestMCPErrorCode,\n stopApp,\n} from '@manifest-network/manifest-mcp-core';\nimport {\n decode as decodeLeaseState,\n isTerminal,\n} from './internals/lease-state.js';\nimport {\n type VerificationSpec,\n verifyAndRecover,\n} from './internals/verify-recover.js';\nimport type {\n CloseLeaseArgs,\n CloseLeaseCallbacks,\n CloseLeaseOptions,\n CloseLeaseResult,\n DeploymentPlanBlock,\n LeaseStateName,\n} from './types.js';\n\nconst UUID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\ntype CloseOutcome = 'terminal' | 'pending' | 'not_found';\n\ninterface CloseDiag {\n stateName?: LeaseStateName;\n reason?: string;\n}\n\n/**\n * Close a lease and verify it reached a terminal on-chain state.\n *\n * @throws `ManifestMCPError(INVALID_CONFIG)` for args validation or when\n * `onConfirm` returns `'no'`.\n * @throws `ManifestMCPError` (typically `TX_FAILED`) propagated as-is\n * from the `stopApp()` broadcast step. Broadcast errors do NOT invoke\n * `onFailure` — that callback is reserved for post-broadcast\n * verification failures. `stopApp` already raises a structured\n * `ManifestMCPError` from the core package; wrapping it again at this\n * layer would be redundant. Callers wanting to react to broadcast\n * errors should catch them at the call site.\n * @throws `ManifestMCPError(TX_FAILED)` when post-broadcast verification\n * reaches one of two failure modes (both with `onFailure({ reason })`\n * invoked first):\n * - the lease is still non-terminal (`pending_drift` branch — state\n * decoded as PENDING / ACTIVE / similar non-terminal); or\n * - the chain returns `{ lease: null }` post-close, so the lease is\n * not visible on-chain (`unclassified` branch).\n * @throws `ManifestMCPError(QUERY_FAILED)` when the post-broadcast verify\n * chain query (`billing.v1.lease`) raises a non-NotFound error\n * (RPC / transport / decoding failure). Wrapped inside the verifier\n * closure so the failure flows through `onFailure({ reason })` before\n * the throw. Structured `ManifestMCPError`s raised by the chain client\n * are re-thrown as-is (with `onFailure` invoked first).\n */\nexport async function closeLease(\n args: CloseLeaseArgs,\n callbacks: CloseLeaseCallbacks,\n opts: CloseLeaseOptions,\n): Promise<CloseLeaseResult> {\n validateArgs(args);\n\n const block = renderConfirmationBlock(args);\n if (callbacks.onConfirm) {\n const yesNo = await callbacks.onConfirm(block);\n if (yesNo !== 'yes') {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n 'User declined to proceed with close-lease.',\n );\n }\n }\n callbacks.onProgress?.({ kind: 'user_confirmed' });\n\n await stopApp(opts.clientManager, args.leaseUuid);\n\n // Direct single-lease query (Copilot review PR #60, comment 3275999624):\n // the previous `leasesByTenant` + page-1-only pagination would\n // false-`not_found` for tenants with >100 leases. `billing.v1.lease`\n // is the same query shape `troubleshoot.ts` already uses; it's\n // tenant-agnostic and bounded to a single lease.\n const spec: VerificationSpec<unknown, CloseOutcome, CloseDiag> = {\n verifier: async () => {\n // Wrap the chain call in try/catch (Copilot review PR #60,\n // comment 3276419264): if `billing.v1.lease` rejects (RPC down,\n // transport, structured `ManifestMCPError`), the error would\n // otherwise propagate OUT of `verifyAndRecover` and bypass the\n // post-verify `onFailure({ reason })` callback below. Mirror\n // the disambiguation pattern from `lookupDomain` (commit aaa5cc5)\n // and `troubleshootDeployment` (commit f1a4737): invoke\n // `onFailure` first, then re-throw `ManifestMCPError` as-is or\n // wrap plain errors as `QUERY_FAILED`.\n let result: unknown;\n try {\n const queryClient = await opts.clientManager.getQueryClient();\n result = await queryClient.liftedinit.billing.v1.lease({\n leaseUuid: args.leaseUuid,\n });\n } catch (err) {\n const reason = `Failed to query lease ${args.leaseUuid} during close-verify: ${\n err instanceof Error ? err.message : String(err)\n }`;\n if (callbacks.onFailure) {\n await callbacks.onFailure({ reason });\n }\n if (err instanceof ManifestMCPError) {\n throw err;\n }\n throw new ManifestMCPError(ManifestMCPErrorCode.QUERY_FAILED, reason);\n }\n const lease = (result as { lease?: unknown })?.lease;\n if (lease === null || lease === undefined) {\n return {\n outcome: 'not_found' as const,\n diagnostic: {\n reason: `lease ${args.leaseUuid} not visible on chain after close`,\n },\n };\n }\n const rawState = (lease as { state?: unknown }).state;\n const stateName = decodeLeaseState(\n typeof rawState === 'number' || typeof rawState === 'string'\n ? rawState\n : undefined,\n );\n if (stateName === undefined) {\n return {\n outcome: 'pending' as const,\n diagnostic: {\n reason: `lease ${args.leaseUuid} state could not be decoded (raw=${String(rawState)})`,\n },\n };\n }\n return {\n outcome: (isTerminal(stateName) ? 'terminal' : 'pending') as\n | 'terminal'\n | 'pending',\n diagnostic: { stateName },\n };\n },\n successValues: ['terminal'],\n branches: {\n pending: {\n branchId: 'pending_drift',\n journalActionTags: ['close-lease-verify-pending'],\n buildFailureEnvelope: (d) => ({\n outcome: 'failed',\n reason:\n d.reason ??\n `close_lease tx accepted but state is still ${d.stateName ?? 'unknown'}.`,\n }),\n buildRecoveryOptions: () => [],\n },\n not_found: {\n branchId: 'unclassified',\n journalActionTags: ['close-lease-verify-not-found'],\n buildFailureEnvelope: (d) => ({\n outcome: 'failed',\n reason:\n d.reason ??\n `Lease ${args.leaseUuid} not visible on chain after close.`,\n }),\n buildRecoveryOptions: () => [],\n },\n },\n };\n\n const verifyResult = await verifyAndRecover(spec, undefined);\n\n if (verifyResult.result !== 'success') {\n const reason =\n verifyResult.failure?.reason ?? 'close-lease verification failed.';\n if (callbacks.onFailure) {\n await callbacks.onFailure({ reason });\n }\n throw new ManifestMCPError(ManifestMCPErrorCode.TX_FAILED, reason);\n }\n\n // Invariant: when `verifyAndRecover` returns success, the matched\n // outcome was `'terminal'`, and the verifier's `terminal` branch\n // ALWAYS sets `diagnostic.stateName` (see the spec above). A missing\n // `stateName` on the success path means the verifier invariant is\n // broken — likely a future refactor regression. The previous\n // implementation fell back to `'LEASE_STATE_CLOSED'` silently, which\n // would lie to the caller (Copilot review PR #60, comment 3276719603).\n // Fail loudly with a typed error instead. `TX_FAILED` is the closest\n // available code in `ManifestMCPErrorCode` (no `INTERNAL_ERROR`\n // variant); the message names the invariant explicitly.\n if (!verifyResult.diagnostic.stateName) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.TX_FAILED,\n `close-lease verifier invariant violated: success outcome reached without diagnostic.stateName for lease ${args.leaseUuid}`,\n );\n }\n const finalState: LeaseStateName = verifyResult.diagnostic.stateName;\n const result: CloseLeaseResult = {\n leaseUuid: args.leaseUuid,\n finalState,\n };\n callbacks.onComplete?.(result);\n return result;\n}\n\n// --- Helpers --------------------------------------------------------\n\nfunction validateArgs(args: CloseLeaseArgs): void {\n if (typeof args.leaseUuid !== 'string' || !args.leaseUuid.match(UUID_RE)) {\n throw new ManifestMCPError(\n ManifestMCPErrorCode.INVALID_CONFIG,\n `closeLease: leaseUuid must be a UUID; got \"${args.leaseUuid}\".`,\n );\n }\n}\n\nfunction renderConfirmationBlock(args: CloseLeaseArgs): DeploymentPlanBlock {\n // Image is not tracked in `CloseLeaseArgs` and `stopApp` doesn't return it;\n // surface the gap explicitly so reviewers/users see the missing context\n // rather than silently omitting an image field they'd expect.\n const text = [\n `Close lease ${args.leaseUuid}.`,\n ' Image: (image not recorded)',\n ' This is permanent — the lease cannot be reopened.',\n '',\n 'Proceed?',\n ].join('\\n');\n return { text };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA2CA,MAAM,UACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmCF,eAAsB,WACpB,MACA,WACA,MAC2B;AAC3B,cAAa,KAAK;CAElB,MAAM,QAAQ,wBAAwB,KAAK;AAC3C,KAAI,UAAU;MACE,MAAM,UAAU,UAAU,MAAM,KAChC,MACZ,OAAM,IAAI,iBACR,qBAAqB,gBACrB,6CACD;;AAGL,WAAU,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAM,QAAQ,KAAK,eAAe,KAAK,UAAU;CA6FjD,MAAM,eAAe,MAAM,iBAtFsC;EAC/D,UAAU,YAAY;GAUpB,IAAI;AACJ,OAAI;AAEF,aAAS,OADW,MAAM,KAAK,cAAc,gBAAgB,EAClC,WAAW,QAAQ,GAAG,MAAM,EACrD,WAAW,KAAK,WACjB,CAAC;YACK,KAAK;IACZ,MAAM,SAAS,yBAAyB,KAAK,UAAU,wBACrD,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAElD,QAAI,UAAU,UACZ,OAAM,UAAU,UAAU,EAAE,QAAQ,CAAC;AAEvC,QAAI,eAAe,iBACjB,OAAM;AAER,UAAM,IAAI,iBAAiB,qBAAqB,cAAc,OAAO;;GAEvE,MAAM,QAAS,QAAgC;AAC/C,OAAI,UAAU,QAAQ,UAAU,KAAA,EAC9B,QAAO;IACL,SAAS;IACT,YAAY,EACV,QAAQ,SAAS,KAAK,UAAU,oCACjC;IACF;GAEH,MAAM,WAAY,MAA8B;GAChD,MAAM,YAAYA,OAChB,OAAO,aAAa,YAAY,OAAO,aAAa,WAChD,WACA,KAAA,EACL;AACD,OAAI,cAAc,KAAA,EAChB,QAAO;IACL,SAAS;IACT,YAAY,EACV,QAAQ,SAAS,KAAK,UAAU,mCAAmC,OAAO,SAAS,CAAC,IACrF;IACF;AAEH,UAAO;IACL,SAAU,WAAW,UAAU,GAAG,aAAa;IAG/C,YAAY,EAAE,WAAW;IAC1B;;EAEH,eAAe,CAAC,WAAW;EAC3B,UAAU;GACR,SAAS;IACP,UAAU;IACV,mBAAmB,CAAC,6BAA6B;IACjD,uBAAuB,OAAO;KAC5B,SAAS;KACT,QACE,EAAE,UACF,8CAA8C,EAAE,aAAa,UAAU;KAC1E;IACD,4BAA4B,EAAE;IAC/B;GACD,WAAW;IACT,UAAU;IACV,mBAAmB,CAAC,+BAA+B;IACnD,uBAAuB,OAAO;KAC5B,SAAS;KACT,QACE,EAAE,UACF,SAAS,KAAK,UAAU;KAC3B;IACD,4BAA4B,EAAE;IAC/B;GACF;EACF,EAEiD,KAAA,EAAU;AAE5D,KAAI,aAAa,WAAW,WAAW;EACrC,MAAM,SACJ,aAAa,SAAS,UAAU;AAClC,MAAI,UAAU,UACZ,OAAM,UAAU,UAAU,EAAE,QAAQ,CAAC;AAEvC,QAAM,IAAI,iBAAiB,qBAAqB,WAAW,OAAO;;AAapE,KAAI,CAAC,aAAa,WAAW,UAC3B,OAAM,IAAI,iBACR,qBAAqB,WACrB,2GAA2G,KAAK,YACjH;CAEH,MAAM,aAA6B,aAAa,WAAW;CAC3D,MAAM,SAA2B;EAC/B,WAAW,KAAK;EAChB;EACD;AACD,WAAU,aAAa,OAAO;AAC9B,QAAO;;AAKT,SAAS,aAAa,MAA4B;AAChD,KAAI,OAAO,KAAK,cAAc,YAAY,CAAC,KAAK,UAAU,MAAM,QAAQ,CACtE,OAAM,IAAI,iBACR,qBAAqB,gBACrB,8CAA8C,KAAK,UAAU,IAC9D;;AAIL,SAAS,wBAAwB,MAA2C;AAW1E,QAAO,EAAE,MAPI;EACX,eAAe,KAAK,UAAU;EAC9B;EACA;EACA;EACA;EACD,CAAC,KAAK,KAAK,EACG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { DeployAppCallbacks, DeployAppOptions, DeployResult, DeploySpec } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/deploy-app.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Orchestrate a deployment. See module-level docstring for the architect-
|
|
6
|
+
* locked composition + E-hybrid runtime-context contract.
|
|
7
|
+
*
|
|
8
|
+
* @throws `ManifestMCPError(INVALID_CONFIG)` for spec / wallet validation.
|
|
9
|
+
* @throws `ManifestMCPError(INVALID_CONFIG)` when `onConfirm` returns
|
|
10
|
+
* `'no'` or `onPlan` returns `'cancel'`.
|
|
11
|
+
*
|
|
12
|
+
* Errors from fred's broadcast or core's recovery primitives surface as
|
|
13
|
+
* typed `ManifestMCPError`s. Partial-success failures with applicable
|
|
14
|
+
* recovery options route through `onFailure(envelope, options)` — the
|
|
15
|
+
* callback's return value drives recovery dispatch via the inline
|
|
16
|
+
* closures in `dispatchRecovery`. Non-partial or inform-only failures
|
|
17
|
+
* (no recovery choices to present, per `handleBroadcastFailure`'s F3
|
|
18
|
+
* branch) throw directly as `ManifestMCPError(TX_FAILED)` without
|
|
19
|
+
* invoking `onFailure`.
|
|
20
|
+
*/
|
|
21
|
+
declare function deployApp(spec: DeploySpec, callbacks: DeployAppCallbacks, opts: DeployAppOptions): Promise<DeployResult>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { deployApp };
|
|
24
|
+
//# sourceMappingURL=deploy-app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deploy-app.d.ts","names":[],"sources":["../src/deploy-app.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;iBAoHsB,SAAA,CACpB,IAAA,EAAM,UAAA,EACN,SAAA,EAAW,kBAAA,EACX,IAAA,EAAM,gBAAA,GACL,OAAA,CAAQ,YAAA"}
|