@honua/mcp-server 0.1.2-beta.0 → 0.1.8-beta.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.
Files changed (117) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +232 -9
  3. package/dist/src/certification/admin-parity.d.ts +96 -0
  4. package/dist/src/certification/admin-parity.d.ts.map +1 -0
  5. package/dist/src/certification/admin-parity.js +235 -0
  6. package/dist/src/certification/census-fixture-client.d.ts.map +1 -1
  7. package/dist/src/certification/census-fixture-client.js +5 -0
  8. package/dist/src/certification/certifier.d.ts +1 -1
  9. package/dist/src/certification/certifier.d.ts.map +1 -1
  10. package/dist/src/certification/certifier.js +28 -20
  11. package/dist/src/certification/cli.js +1 -1
  12. package/dist/src/certification/cql2.d.ts +24 -0
  13. package/dist/src/certification/cql2.d.ts.map +1 -0
  14. package/dist/src/certification/cql2.js +354 -0
  15. package/dist/src/certification/fixtures.d.ts +8 -0
  16. package/dist/src/certification/fixtures.d.ts.map +1 -1
  17. package/dist/src/certification/fixtures.js +26 -10
  18. package/dist/src/certification/ogc-data.d.ts +30 -0
  19. package/dist/src/certification/ogc-data.d.ts.map +1 -0
  20. package/dist/src/certification/ogc-data.js +726 -0
  21. package/dist/src/certification/ogc-fixture-client.d.ts +4 -0
  22. package/dist/src/certification/ogc-fixture-client.d.ts.map +1 -0
  23. package/dist/src/certification/ogc-fixture-client.js +190 -0
  24. package/dist/src/certification/target.d.ts +10 -1
  25. package/dist/src/certification/target.d.ts.map +1 -1
  26. package/dist/src/certification/target.js +63 -28
  27. package/dist/src/credential-endpoint.d.ts +3 -0
  28. package/dist/src/credential-endpoint.d.ts.map +1 -0
  29. package/dist/src/credential-endpoint.js +24 -0
  30. package/dist/src/eval/cli.js +6 -3
  31. package/dist/src/eval/corpus.d.ts +7 -0
  32. package/dist/src/eval/corpus.d.ts.map +1 -1
  33. package/dist/src/eval/corpus.js +12 -0
  34. package/dist/src/eval/ogc-corpus.d.ts +3 -0
  35. package/dist/src/eval/ogc-corpus.d.ts.map +1 -0
  36. package/dist/src/eval/ogc-corpus.js +437 -0
  37. package/dist/src/eval/runner.d.ts +6 -0
  38. package/dist/src/eval/runner.d.ts.map +1 -1
  39. package/dist/src/eval/runner.js +21 -7
  40. package/dist/src/helpers.d.ts +8 -13
  41. package/dist/src/helpers.d.ts.map +1 -1
  42. package/dist/src/helpers.js +7 -35
  43. package/dist/src/index.d.ts +36 -8
  44. package/dist/src/index.d.ts.map +1 -1
  45. package/dist/src/index.js +55 -18
  46. package/dist/src/neutral/errors.d.ts +73 -0
  47. package/dist/src/neutral/errors.d.ts.map +1 -0
  48. package/dist/src/neutral/errors.js +112 -0
  49. package/dist/src/neutral/filter.d.ts +108 -0
  50. package/dist/src/neutral/filter.d.ts.map +1 -0
  51. package/dist/src/neutral/filter.js +271 -0
  52. package/dist/src/neutral/query.d.ts +101 -0
  53. package/dist/src/neutral/query.d.ts.map +1 -0
  54. package/dist/src/neutral/query.js +180 -0
  55. package/dist/src/neutral/result.d.ts +33 -0
  56. package/dist/src/neutral/result.d.ts.map +1 -0
  57. package/dist/src/neutral/result.js +38 -0
  58. package/dist/src/neutral/source-ref.d.ts +126 -0
  59. package/dist/src/neutral/source-ref.d.ts.map +1 -0
  60. package/dist/src/neutral/source-ref.js +267 -0
  61. package/dist/src/nl-map-control.d.ts.map +1 -1
  62. package/dist/src/proxy.d.ts.map +1 -1
  63. package/dist/src/proxy.js +29 -14
  64. package/dist/src/release/zero-to-map-checkpoint.d.ts +34 -0
  65. package/dist/src/release/zero-to-map-checkpoint.d.ts.map +1 -0
  66. package/dist/src/release/zero-to-map-checkpoint.js +369 -0
  67. package/dist/src/release/zero-to-map-cli.d.ts +51 -0
  68. package/dist/src/release/zero-to-map-cli.d.ts.map +1 -0
  69. package/dist/src/release/zero-to-map-cli.js +880 -0
  70. package/dist/src/release/zero-to-map-provision.d.ts +37 -0
  71. package/dist/src/release/zero-to-map-provision.d.ts.map +1 -0
  72. package/dist/src/release/zero-to-map-provision.js +177 -0
  73. package/dist/src/release/zero-to-map.d.ts +296 -0
  74. package/dist/src/release/zero-to-map.d.ts.map +1 -0
  75. package/dist/src/release/zero-to-map.js +1069 -0
  76. package/dist/src/tools/admin-install-local.d.ts +30 -0
  77. package/dist/src/tools/admin-install-local.d.ts.map +1 -0
  78. package/dist/src/tools/admin-install-local.js +22 -0
  79. package/dist/src/tools/control-plane-command.d.ts +99 -0
  80. package/dist/src/tools/control-plane-command.d.ts.map +1 -0
  81. package/dist/src/tools/control-plane-command.js +180 -0
  82. package/dist/src/tools/count-features.d.ts +85 -11
  83. package/dist/src/tools/count-features.d.ts.map +1 -1
  84. package/dist/src/tools/count-features.js +49 -31
  85. package/dist/src/tools/describe-layer.d.ts +30 -6
  86. package/dist/src/tools/describe-layer.d.ts.map +1 -1
  87. package/dist/src/tools/describe-layer.js +99 -8
  88. package/dist/src/tools/docs-search.d.ts +100 -0
  89. package/dist/src/tools/docs-search.d.ts.map +1 -0
  90. package/dist/src/tools/docs-search.js +381 -0
  91. package/dist/src/tools/get-extent.d.ts +69 -11
  92. package/dist/src/tools/get-extent.d.ts.map +1 -1
  93. package/dist/src/tools/get-extent.js +28 -46
  94. package/dist/src/tools/list-services.d.ts +7 -0
  95. package/dist/src/tools/list-services.d.ts.map +1 -1
  96. package/dist/src/tools/list-services.js +8 -1
  97. package/dist/src/tools/list-sources.d.ts +44 -0
  98. package/dist/src/tools/list-sources.d.ts.map +1 -0
  99. package/dist/src/tools/list-sources.js +138 -0
  100. package/dist/src/tools/query-features.d.ts +99 -19
  101. package/dist/src/tools/query-features.d.ts.map +1 -1
  102. package/dist/src/tools/query-features.js +38 -45
  103. package/dist/src/tools/statistics.d.ts +80 -12
  104. package/dist/src/tools/statistics.d.ts.map +1 -1
  105. package/dist/src/tools/statistics.js +56 -23
  106. package/package.json +37 -8
  107. package/release/zero-to-map/README.md +174 -0
  108. package/release/zero-to-map/configs/claude-code.mcp.json +11 -0
  109. package/release/zero-to-map/configs/claude-desktop.json +11 -0
  110. package/release/zero-to-map/configs/cursor.json +11 -0
  111. package/release/zero-to-map/contracts/aws-ecs-provision-binding.schema.json +59 -0
  112. package/release/zero-to-map/contracts/checkpoint.schema.json +152 -0
  113. package/release/zero-to-map/contracts/console-receipt.schema.json +150 -0
  114. package/release/zero-to-map/contracts/esri-gp-mcp.v1.json +73 -0
  115. package/release/zero-to-map/fixtures/parcels.geojson +33 -0
  116. package/release/zero-to-map/fixtures/zoning.geojson +24 -0
  117. package/release/zero-to-map/journey.v1.json +1248 -0
@@ -0,0 +1,369 @@
1
+ import { createHash } from "node:crypto";
2
+ import { ZERO_TO_MAP_CATALOG_RECEIPT_SCHEMA, ZERO_TO_MAP_CONSOLE_RECEIPT_REQUEST_SCHEMA, } from "./zero-to-map.js";
3
+ export const ZERO_TO_MAP_CHECKPOINT_SCHEMA = "honua.zero-to-map.checkpoint/v1";
4
+ export const ZERO_TO_MAP_CHECKPOINT_MAX_AGE_MS = 24 * 60 * 60 * 1_000;
5
+ export function createZeroToMapCheckpoint(bindings, snapshot, createdAt = new Date().toISOString()) {
6
+ assertTargetBinding(bindings);
7
+ const payload = {
8
+ schemaVersion: ZERO_TO_MAP_CHECKPOINT_SCHEMA,
9
+ state: "paused",
10
+ createdAt,
11
+ ...bindings,
12
+ resume: {
13
+ startedAt: snapshot.startedAt,
14
+ capturedVariables: snapshot.capturedVariables,
15
+ completedStages: snapshot.completedStages,
16
+ resumeAt: snapshot.resumeAt,
17
+ // Carried across the Console boundary because no post-checkpoint stage
18
+ // can re-derive it; the resumed run's final receipt would otherwise
19
+ // overwrite the pre-pause receipt with one that has no catalog evidence.
20
+ ...(snapshot.catalog ? { catalog: snapshot.catalog } : {}),
21
+ },
22
+ consoleReceiptRequest: snapshot.consoleReceiptRequest,
23
+ };
24
+ assertSecretFree(payload);
25
+ return seal(payload);
26
+ }
27
+ export function consumeZeroToMapCheckpoint(checkpoint, finalReceiptSha256, consumedAt = new Date().toISOString()) {
28
+ if (checkpoint.state !== "paused")
29
+ throw new Error("checkpoint has already been consumed");
30
+ const { integrity: _integrity, ...prior } = checkpoint;
31
+ return seal({ ...prior, state: "consumed", consumedAt, finalReceiptSha256 });
32
+ }
33
+ export function parseZeroToMapCheckpoint(value) {
34
+ const checkpoint = object(value, "checkpoint");
35
+ exactKeys(checkpoint, [
36
+ "schemaVersion",
37
+ "state",
38
+ "createdAt",
39
+ "journeyId",
40
+ "releaseContract",
41
+ "target",
42
+ "planSha256",
43
+ "sourceRevision",
44
+ "mcpEndpointSha256",
45
+ "candidateId",
46
+ "releaseId",
47
+ "provisionReceiptSha256",
48
+ "resume",
49
+ "consoleReceiptRequest",
50
+ "consumedAt",
51
+ "finalReceiptSha256",
52
+ "integrity",
53
+ ], "checkpoint");
54
+ if (checkpoint.schemaVersion !== ZERO_TO_MAP_CHECKPOINT_SCHEMA) {
55
+ throw new Error(`checkpoint.schemaVersion must be ${ZERO_TO_MAP_CHECKPOINT_SCHEMA}`);
56
+ }
57
+ if (checkpoint.state !== "paused" && checkpoint.state !== "consumed") {
58
+ throw new Error("checkpoint.state must be paused or consumed");
59
+ }
60
+ const createdAt = timestamp(checkpoint.createdAt, "checkpoint.createdAt");
61
+ const bindings = {
62
+ journeyId: text(checkpoint.journeyId, "checkpoint.journeyId"),
63
+ releaseContract: text(checkpoint.releaseContract, "checkpoint.releaseContract"),
64
+ target: target(checkpoint.target),
65
+ planSha256: sha256(checkpoint.planSha256, "checkpoint.planSha256"),
66
+ sourceRevision: revision(checkpoint.sourceRevision, "checkpoint.sourceRevision"),
67
+ mcpEndpointSha256: sha256(checkpoint.mcpEndpointSha256, "checkpoint.mcpEndpointSha256"),
68
+ candidateId: text(checkpoint.candidateId, "checkpoint.candidateId"),
69
+ releaseId: text(checkpoint.releaseId, "checkpoint.releaseId"),
70
+ ...(checkpoint.provisionReceiptSha256 === undefined
71
+ ? {}
72
+ : {
73
+ provisionReceiptSha256: sha256(checkpoint.provisionReceiptSha256, "checkpoint.provisionReceiptSha256"),
74
+ }),
75
+ };
76
+ assertTargetBinding(bindings);
77
+ const resume = parseResume(checkpoint.resume);
78
+ const consoleReceiptRequest = parseReceiptRequest(checkpoint.consoleReceiptRequest);
79
+ const integrity = object(checkpoint.integrity, "checkpoint.integrity");
80
+ exactKeys(integrity, ["algorithm", "digest"], "checkpoint.integrity");
81
+ if (integrity.algorithm !== "sha256")
82
+ throw new Error("checkpoint.integrity.algorithm must be sha256");
83
+ const digest = sha256(integrity.digest, "checkpoint.integrity.digest");
84
+ const state = checkpoint.state;
85
+ const consumedAt = checkpoint.consumedAt;
86
+ const finalReceiptSha256 = checkpoint.finalReceiptSha256;
87
+ if (state === "paused" && (consumedAt !== undefined || finalReceiptSha256 !== undefined)) {
88
+ throw new Error("paused checkpoint cannot carry consumed receipt fields");
89
+ }
90
+ if (state === "consumed" && (consumedAt === undefined || finalReceiptSha256 === undefined)) {
91
+ throw new Error("consumed checkpoint must carry consumedAt and finalReceiptSha256");
92
+ }
93
+ const payload = {
94
+ schemaVersion: ZERO_TO_MAP_CHECKPOINT_SCHEMA,
95
+ state,
96
+ createdAt,
97
+ ...bindings,
98
+ resume,
99
+ consoleReceiptRequest,
100
+ ...(state === "consumed"
101
+ ? {
102
+ consumedAt: timestamp(consumedAt, "checkpoint.consumedAt"),
103
+ finalReceiptSha256: sha256(finalReceiptSha256, "checkpoint.finalReceiptSha256"),
104
+ }
105
+ : {}),
106
+ };
107
+ assertSecretFree(payload);
108
+ const expected = digestPayload(payload);
109
+ if (digest !== expected)
110
+ throw new Error("checkpoint integrity digest does not match its canonical payload");
111
+ return { ...payload, integrity: { algorithm: "sha256", digest } };
112
+ }
113
+ export function assertZeroToMapCheckpointFresh(checkpoint, now = new Date()) {
114
+ const age = now.getTime() - Date.parse(checkpoint.createdAt);
115
+ if (age < 0 || age > ZERO_TO_MAP_CHECKPOINT_MAX_AGE_MS) {
116
+ throw new Error("checkpoint is stale or has a future creation time");
117
+ }
118
+ }
119
+ export function assertZeroToMapCheckpointDigest(checkpoint, expectedDigest) {
120
+ if (!/^[0-9a-f]{64}$/.test(expectedDigest) || checkpoint.integrity.digest !== expectedDigest) {
121
+ throw new Error("externally carried checkpoint digest does not match");
122
+ }
123
+ }
124
+ export function assertZeroToMapCheckpointBindings(checkpoint, expected) {
125
+ for (const key of Object.keys(expected)) {
126
+ if (checkpoint[key] !== expected[key])
127
+ throw new Error(`checkpoint binding mismatch: ${key}`);
128
+ }
129
+ }
130
+ function assertTargetBinding(bindings) {
131
+ if (bindings.target === "aws-ecs" && bindings.provisionReceiptSha256 === undefined) {
132
+ throw new Error("AWS ECS checkpoint must bind provisionReceiptSha256");
133
+ }
134
+ if (bindings.target === "local-docker" && bindings.provisionReceiptSha256 !== undefined) {
135
+ throw new Error("local Docker checkpoint cannot bind an AWS provision receipt");
136
+ }
137
+ }
138
+ function seal(payload) {
139
+ return { ...payload, integrity: { algorithm: "sha256", digest: digestPayload(payload) } };
140
+ }
141
+ function digestPayload(payload) {
142
+ return createHash("sha256").update(canonicalJson(payload)).digest("hex");
143
+ }
144
+ /** Checkpoints are an allowlisted release handoff, never a credential transport. */
145
+ function assertSecretFree(value, path = "checkpoint") {
146
+ if (Array.isArray(value)) {
147
+ value.forEach((item, index) => assertSecretFree(item, `${path}[${index}]`));
148
+ return;
149
+ }
150
+ if (!value || typeof value !== "object")
151
+ return;
152
+ for (const [key, item] of Object.entries(value)) {
153
+ if (/(?:password|authorization|api[-_]?key|access[-_]?key|secret(?:[-_]?key)?|bearer|token|material)/i.test(key)) {
154
+ throw new Error(`checkpoint contains a forbidden credential field at ${path}.${key}`);
155
+ }
156
+ assertSecretFree(item, `${path}.${key}`);
157
+ }
158
+ }
159
+ function canonicalJson(value) {
160
+ if (value === null)
161
+ return "null";
162
+ if (Array.isArray(value))
163
+ return `[${value.map(canonicalJson).join(",")}]`;
164
+ if (typeof value === "object") {
165
+ const candidate = value;
166
+ return `{${Object.keys(candidate)
167
+ .filter((key) => candidate[key] !== undefined)
168
+ .sort()
169
+ .map((key) => `${JSON.stringify(key)}:${canonicalJson(candidate[key])}`)
170
+ .join(",")}}`;
171
+ }
172
+ const encoded = JSON.stringify(value);
173
+ if (encoded === undefined)
174
+ throw new Error("checkpoint contains a non-JSON value");
175
+ return encoded;
176
+ }
177
+ function parseResume(value) {
178
+ const resume = object(value, "checkpoint.resume");
179
+ exactKeys(resume, ["startedAt", "capturedVariables", "completedStages", "resumeAt", "catalog"], "checkpoint.resume");
180
+ const capturedVariables = object(resume.capturedVariables, "checkpoint.resume.capturedVariables");
181
+ if (!Array.isArray(resume.completedStages))
182
+ throw new Error("checkpoint.resume.completedStages must be an array");
183
+ return {
184
+ startedAt: timestamp(resume.startedAt, "checkpoint.resume.startedAt"),
185
+ capturedVariables,
186
+ completedStages: resume.completedStages.map(parseStageReceipt),
187
+ resumeAt: parseResumePoint(resume.resumeAt),
188
+ ...(resume.catalog === undefined ? {} : { catalog: parseCatalogReceipt(resume.catalog) }),
189
+ };
190
+ }
191
+ /**
192
+ * Catalog preflight evidence restored from the checkpoint. Validated as
193
+ * strictly as the rest of the payload: it is re-emitted onto the final release
194
+ * receipt, so a malformed or padded catalog block must not survive the parse.
195
+ */
196
+ function parseCatalogReceipt(value) {
197
+ const path = "checkpoint.resume.catalog";
198
+ const catalog = object(value, path);
199
+ exactKeys(catalog, [
200
+ "schemaVersion",
201
+ "activeProfiles",
202
+ "expectedTotalTools",
203
+ "advertisedTotalTools",
204
+ "baseStaticTools",
205
+ "baseAdminTools",
206
+ "auditedExclusions",
207
+ "profiles",
208
+ "catalogSha256",
209
+ "adminRosterSha256",
210
+ "staticRosterSha256",
211
+ "exclusionRosterSha256",
212
+ ], path);
213
+ if (catalog.schemaVersion !== ZERO_TO_MAP_CATALOG_RECEIPT_SCHEMA) {
214
+ throw new Error(`${path}.schemaVersion must be ${ZERO_TO_MAP_CATALOG_RECEIPT_SCHEMA}`);
215
+ }
216
+ if (!Array.isArray(catalog.profiles))
217
+ throw new Error(`${path}.profiles must be an array`);
218
+ return {
219
+ schemaVersion: ZERO_TO_MAP_CATALOG_RECEIPT_SCHEMA,
220
+ activeProfiles: stringList(catalog.activeProfiles, `${path}.activeProfiles`),
221
+ expectedTotalTools: count(catalog.expectedTotalTools, `${path}.expectedTotalTools`),
222
+ advertisedTotalTools: count(catalog.advertisedTotalTools, `${path}.advertisedTotalTools`),
223
+ baseStaticTools: count(catalog.baseStaticTools, `${path}.baseStaticTools`),
224
+ baseAdminTools: count(catalog.baseAdminTools, `${path}.baseAdminTools`),
225
+ auditedExclusions: count(catalog.auditedExclusions, `${path}.auditedExclusions`),
226
+ profiles: catalog.profiles.map((profile, index) => parseProfileReceipt(profile, `${path}.profiles[${index}]`)),
227
+ catalogSha256: sha256(catalog.catalogSha256, `${path}.catalogSha256`),
228
+ adminRosterSha256: sha256(catalog.adminRosterSha256, `${path}.adminRosterSha256`),
229
+ staticRosterSha256: sha256(catalog.staticRosterSha256, `${path}.staticRosterSha256`),
230
+ exclusionRosterSha256: sha256(catalog.exclusionRosterSha256, `${path}.exclusionRosterSha256`),
231
+ };
232
+ }
233
+ function parseProfileReceipt(value, path) {
234
+ const profile = object(value, path);
235
+ exactKeys(profile, ["id", "expectedMembers", "advertisedMembers", "confirmedMembers", "nameResolvedMembers", "rosterSha256"], path);
236
+ return {
237
+ id: text(profile.id, `${path}.id`),
238
+ expectedMembers: count(profile.expectedMembers, `${path}.expectedMembers`),
239
+ advertisedMembers: count(profile.advertisedMembers, `${path}.advertisedMembers`),
240
+ confirmedMembers: stringList(profile.confirmedMembers, `${path}.confirmedMembers`),
241
+ nameResolvedMembers: stringList(profile.nameResolvedMembers, `${path}.nameResolvedMembers`),
242
+ rosterSha256: sha256(profile.rosterSha256, `${path}.rosterSha256`),
243
+ };
244
+ }
245
+ function parseResumePoint(value) {
246
+ const point = object(value, "checkpoint.resume.resumeAt");
247
+ exactKeys(point, ["stageId", "actionId"], "checkpoint.resume.resumeAt");
248
+ return {
249
+ stageId: text(point.stageId, "checkpoint.resume.resumeAt.stageId"),
250
+ actionId: text(point.actionId, "checkpoint.resume.resumeAt.actionId"),
251
+ };
252
+ }
253
+ function parseReceiptRequest(value) {
254
+ const request = object(value, "checkpoint.consoleReceiptRequest");
255
+ exactKeys(request, ["schemaVersion", "actionId", "receiptSchema", "matches", "requiredPointers", "equalPointers"], "checkpoint.consoleReceiptRequest");
256
+ if (request.schemaVersion !== ZERO_TO_MAP_CONSOLE_RECEIPT_REQUEST_SCHEMA) {
257
+ throw new Error(`checkpoint.consoleReceiptRequest.schemaVersion must be ${ZERO_TO_MAP_CONSOLE_RECEIPT_REQUEST_SCHEMA}`);
258
+ }
259
+ const matches = object(request.matches, "checkpoint.consoleReceiptRequest.matches");
260
+ const requiredPointers = stringList(request.requiredPointers, "checkpoint.consoleReceiptRequest.requiredPointers");
261
+ if (!Array.isArray(request.equalPointers)) {
262
+ throw new Error("checkpoint.consoleReceiptRequest.equalPointers must be an array");
263
+ }
264
+ const equalPointers = request.equalPointers.map((value, index) => {
265
+ if (!Array.isArray(value) || value.length !== 2 || value.some((item) => typeof item !== "string" || !item)) {
266
+ throw new Error(`checkpoint.consoleReceiptRequest.equalPointers[${index}] must be a pointer pair`);
267
+ }
268
+ return [value[0], value[1]];
269
+ });
270
+ return {
271
+ schemaVersion: ZERO_TO_MAP_CONSOLE_RECEIPT_REQUEST_SCHEMA,
272
+ actionId: text(request.actionId, "checkpoint.consoleReceiptRequest.actionId"),
273
+ receiptSchema: text(request.receiptSchema, "checkpoint.consoleReceiptRequest.receiptSchema"),
274
+ matches,
275
+ requiredPointers,
276
+ equalPointers,
277
+ };
278
+ }
279
+ function parseStageReceipt(value, index) {
280
+ const path = `checkpoint.resume.completedStages[${index}]`;
281
+ const stage = object(value, path);
282
+ exactKeys(stage, ["number", "id", "title", "status", "actions"], path);
283
+ if (!Number.isInteger(stage.number) || stage.number < 1)
284
+ throw new Error(`${path}.number must be positive`);
285
+ if (!Array.isArray(stage.actions))
286
+ throw new Error(`${path}.actions must be an array`);
287
+ return {
288
+ number: stage.number,
289
+ id: text(stage.id, `${path}.id`),
290
+ title: text(stage.title, `${path}.title`),
291
+ status: actionStatus(stage.status, `${path}.status`),
292
+ actions: stage.actions.map((action, actionIndex) => parseActionReceipt(action, `${path}.actions[${actionIndex}]`)),
293
+ };
294
+ }
295
+ function parseActionReceipt(value, path) {
296
+ const action = object(value, path);
297
+ exactKeys(action, ["id", "kind", "status", "startedAt", "finishedAt", "code", "message", "evidence", "captures"], path);
298
+ const kind = action.kind;
299
+ if (!["cli", "mcp", "mcp-resource", "gpserver", "receipt", "http"].includes(String(kind))) {
300
+ throw new Error(`${path}.kind is invalid`);
301
+ }
302
+ return {
303
+ id: text(action.id, `${path}.id`),
304
+ kind: kind,
305
+ status: actionStatus(action.status, `${path}.status`),
306
+ startedAt: timestamp(action.startedAt, `${path}.startedAt`),
307
+ finishedAt: timestamp(action.finishedAt, `${path}.finishedAt`),
308
+ ...(action.code === undefined ? {} : { code: text(action.code, `${path}.code`) }),
309
+ ...(action.message === undefined ? {} : { message: text(action.message, `${path}.message`) }),
310
+ ...(action.evidence === undefined ? {} : { evidence: object(action.evidence, `${path}.evidence`) }),
311
+ ...(action.captures === undefined ? {} : { captures: object(action.captures, `${path}.captures`) }),
312
+ };
313
+ }
314
+ function actionStatus(value, path) {
315
+ if (value !== "passed" && value !== "blocked" && value !== "failed" && value !== "skipped") {
316
+ throw new Error(`${path} is invalid`);
317
+ }
318
+ return value;
319
+ }
320
+ function object(value, path) {
321
+ if (!value || typeof value !== "object" || Array.isArray(value))
322
+ throw new Error(`${path} must be an object`);
323
+ return value;
324
+ }
325
+ function exactKeys(value, allowed, path) {
326
+ const extras = Object.keys(value).filter((key) => !allowed.includes(key));
327
+ if (extras.length > 0)
328
+ throw new Error(`${path} has unknown fields: ${extras.join(", ")}`);
329
+ }
330
+ function text(value, path) {
331
+ if (typeof value !== "string" || !value)
332
+ throw new Error(`${path} must be a non-empty string`);
333
+ return value;
334
+ }
335
+ function timestamp(value, path) {
336
+ const result = text(value, path);
337
+ if (!Number.isFinite(Date.parse(result)))
338
+ throw new Error(`${path} must be an ISO timestamp`);
339
+ return result;
340
+ }
341
+ function sha256(value, path) {
342
+ const result = text(value, path);
343
+ if (!/^[0-9a-f]{64}$/.test(result))
344
+ throw new Error(`${path} must be a lowercase SHA-256 digest`);
345
+ return result;
346
+ }
347
+ function revision(value, path) {
348
+ const result = text(value, path);
349
+ if (!/^[0-9a-f]{40}$/.test(result))
350
+ throw new Error(`${path} must be a full lowercase git SHA`);
351
+ return result;
352
+ }
353
+ function target(value) {
354
+ if (value !== "local-docker" && value !== "aws-ecs") {
355
+ throw new Error("checkpoint.target must be local-docker or aws-ecs");
356
+ }
357
+ return value;
358
+ }
359
+ function count(value, path) {
360
+ if (!Number.isInteger(value) || value < 0)
361
+ throw new Error(`${path} must be a non-negative integer`);
362
+ return value;
363
+ }
364
+ function stringList(value, path) {
365
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || !item)) {
366
+ throw new Error(`${path} must be an array of non-empty strings`);
367
+ }
368
+ return value;
369
+ }
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ import { type AwsEcsProvisionBinding } from "./zero-to-map-provision.js";
3
+ import { type JourneyExecutionResult, type JourneyMcpResourceAction } from "./zero-to-map.js";
4
+ type JourneyTarget = "local-docker" | "aws-ecs";
5
+ export interface CliOptions {
6
+ readonly execute: boolean;
7
+ readonly confirmed: boolean;
8
+ readonly planPath: string;
9
+ readonly outputPath: string;
10
+ readonly honuaCommand: string;
11
+ readonly target: JourneyTarget;
12
+ readonly mcpUrl?: string;
13
+ readonly checkpointPath?: string;
14
+ readonly checkpointDigest?: string;
15
+ readonly provisionReceiptPath?: string;
16
+ readonly consoleReceiptPath?: string;
17
+ readonly provisionBinding?: AwsEcsProvisionBinding;
18
+ readonly provisionReceiptSha256?: string;
19
+ readonly sourceRevision?: string;
20
+ readonly variables: Readonly<Record<string, unknown>>;
21
+ readonly receiptPaths: Readonly<Record<string, string>>;
22
+ }
23
+ export declare function runZeroToMapCli(argv?: readonly string[], env?: NodeJS.ProcessEnv): Promise<number>;
24
+ export declare function parseZeroToMapCliArgs(argv: readonly string[], env: NodeJS.ProcessEnv): CliOptions;
25
+ /** Resolve the live mutating CLI without permitting Windows' cwd-first executable search. */
26
+ export declare function resolveLiveExecutable(command: string, env: NodeJS.ProcessEnv, excludedDirectory: string): Promise<string>;
27
+ /** Atomically transfer one paused checkpoint to a single resume owner. */
28
+ export declare function claimZeroToMapCheckpoint(path: string, digest: string): Promise<string>;
29
+ export declare function parseInstallAccessCredential(stdout: string): {
30
+ readonly id: string;
31
+ readonly name: string;
32
+ readonly status: "active";
33
+ readonly requestedGrants: readonly string[];
34
+ readonly effectiveGrants: readonly string[];
35
+ readonly canAuthenticate: true;
36
+ readonly referenceType: "private-env-file";
37
+ readonly referenceDigestSha256: string;
38
+ readonly provisioned: boolean;
39
+ };
40
+ /** Poll one MCP job resource to its declared successful terminal state. */
41
+ export declare function readJourneyMcpResource(action: JourneyMcpResourceAction, read: (uri: string) => Promise<unknown>): Promise<JourneyExecutionResult>;
42
+ export declare function requireCompletedPublishedOperation(tool: string, value: unknown): {
43
+ operationId: string;
44
+ status: string;
45
+ handleId?: string;
46
+ approvalLane?: string;
47
+ jobId?: string;
48
+ metadataRevision?: number;
49
+ } | undefined;
50
+ export {};
51
+ //# sourceMappingURL=zero-to-map-cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zero-to-map-cli.d.ts","sourceRoot":"","sources":["../../../src/release/zero-to-map-cli.ts"],"names":[],"mappings":";AAwBA,OAAO,EACL,KAAK,sBAAsB,EAI5B,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAGL,KAAK,sBAAsB,EAE3B,KAAK,wBAAwB,EAG9B,MAAM,kBAAkB,CAAC;AAE1B,KAAK,aAAa,GAAG,cAAc,GAAG,SAAS,CAAC;AAEhD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,sBAAsB,CAAC;IACnD,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IACzC,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACtD,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACzD;AA8PD,wBAAsB,eAAe,CACnC,IAAI,GAAE,SAAS,MAAM,EAA0B,EAC/C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,MAAM,CAAC,CAyDjB;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,UAAU,CAwGjG;AAuCD,6FAA6F;AAC7F,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,iBAAiB,EAAE,MAAM,GACxB,OAAO,CAAC,MAAM,CAAC,CAkBjB;AAsED,0EAA0E;AAC1E,wBAAsB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwB5F;AA+DD,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,MAAM,GAAG;IAC5D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,eAAe,EAAE,IAAI,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,kBAAkB,CAAC;IAC3C,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B,CAuFA;AA8CD,2EAA2E;AAC3E,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,wBAAwB,EAChC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GACtC,OAAO,CAAC,sBAAsB,CAAC,CAsBjC;AA8BD,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GAEZ;IACE,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,GACD,SAAS,CAcZ"}