thinkwork-cli 0.12.3 → 0.12.5

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/cli.js CHANGED
@@ -201,7 +201,7 @@ async function ensureWorkspace(cwd, stage) {
201
201
  }
202
202
  }
203
203
  function runTerraformRaw(cwd, args) {
204
- return new Promise((resolve6, reject) => {
204
+ return new Promise((resolve7, reject) => {
205
205
  const proc = spawn("terraform", args, {
206
206
  cwd,
207
207
  stdio: ["pipe", "pipe", "pipe"]
@@ -211,13 +211,13 @@ function runTerraformRaw(cwd, args) {
211
211
  proc.stdout.on("data", (d) => stdout += d);
212
212
  proc.stderr.on("data", (d) => stderr += d);
213
213
  proc.on("close", (code) => {
214
- if (code === 0) resolve6(stdout);
214
+ if (code === 0) resolve7(stdout);
215
215
  else reject(new Error(`terraform ${args.join(" ")} failed (exit ${code}): ${stderr}`));
216
216
  });
217
217
  });
218
218
  }
219
219
  function runTerraform(cwd, args) {
220
- return new Promise((resolve6) => {
220
+ return new Promise((resolve7) => {
221
221
  console.log(`
222
222
  \u2192 terraform ${args.join(" ")}
223
223
  `);
@@ -225,7 +225,7 @@ function runTerraform(cwd, args) {
225
225
  cwd,
226
226
  stdio: "inherit"
227
227
  });
228
- proc.on("close", (code) => resolve6(code ?? 1));
228
+ proc.on("close", (code) => resolve7(code ?? 1));
229
229
  });
230
230
  }
231
231
  async function ensureInit(cwd) {
@@ -469,10 +469,10 @@ async function confirm(message) {
469
469
  input: process.stdin,
470
470
  output: process.stdout
471
471
  });
472
- return new Promise((resolve6) => {
472
+ return new Promise((resolve7) => {
473
473
  rl.question(`${message} [y/N] `, (answer) => {
474
474
  rl.close();
475
- resolve6(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
475
+ resolve7(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
476
476
  });
477
477
  });
478
478
  }
@@ -553,7 +553,7 @@ async function runPostDeployProbe(stage) {
553
553
  );
554
554
  return;
555
555
  }
556
- await new Promise((resolve6) => {
556
+ await new Promise((resolve7) => {
557
557
  const proc = spawn2("bash", [scriptPath, "--stage", stage], {
558
558
  stdio: "inherit",
559
559
  env: process.env
@@ -564,11 +564,11 @@ async function runPostDeployProbe(stage) {
564
564
  `post-deploy probe exited ${code} \u2014 deploy not rolled back`
565
565
  );
566
566
  }
567
- resolve6();
567
+ resolve7();
568
568
  });
569
569
  proc.on("error", (err) => {
570
570
  printWarning(`post-deploy probe spawn failed: ${err.message}`);
571
- resolve6();
571
+ resolve7();
572
572
  });
573
573
  });
574
574
  }
@@ -1025,7 +1025,7 @@ function registerConfigCommand(program2) {
1025
1025
  import { spawn as spawn3 } from "child_process";
1026
1026
  import { resolve } from "path";
1027
1027
  function getTerraformOutput(cwd, key) {
1028
- return new Promise((resolve6, reject) => {
1028
+ return new Promise((resolve7, reject) => {
1029
1029
  const proc = spawn3("terraform", ["output", "-raw", key], {
1030
1030
  cwd,
1031
1031
  stdio: ["pipe", "pipe", "pipe"]
@@ -1033,17 +1033,17 @@ function getTerraformOutput(cwd, key) {
1033
1033
  let stdout = "";
1034
1034
  proc.stdout.on("data", (d) => stdout += d);
1035
1035
  proc.on("close", (code) => {
1036
- if (code === 0) resolve6(stdout.trim());
1036
+ if (code === 0) resolve7(stdout.trim());
1037
1037
  else reject(new Error(`terraform output ${key} failed (exit ${code})`));
1038
1038
  });
1039
1039
  });
1040
1040
  }
1041
1041
  function runScript(scriptPath, args) {
1042
- return new Promise((resolve6) => {
1042
+ return new Promise((resolve7) => {
1043
1043
  const proc = spawn3("bash", [scriptPath, ...args], {
1044
1044
  stdio: "inherit"
1045
1045
  });
1046
- proc.on("close", (code) => resolve6(code ?? 1));
1046
+ proc.on("close", (code) => resolve7(code ?? 1));
1047
1047
  });
1048
1048
  }
1049
1049
  function registerBootstrapCommand(program2) {
@@ -1418,7 +1418,7 @@ function buildAuthorizeUrl(cognito, redirectUri, state) {
1418
1418
  return `${cognito.domainUrl}/oauth2/authorize?${params.toString()}`;
1419
1419
  }
1420
1420
  function waitForCallbackCode(opts) {
1421
- return new Promise((resolve6, reject) => {
1421
+ return new Promise((resolve7, reject) => {
1422
1422
  const server = createServer((req, res) => handleRequest(req, res));
1423
1423
  let finished = false;
1424
1424
  const finish = (err, code) => {
@@ -1429,7 +1429,7 @@ function waitForCallbackCode(opts) {
1429
1429
  closer.closeAllConnections?.();
1430
1430
  server.close(() => {
1431
1431
  if (err) reject(err);
1432
- else resolve6(code);
1432
+ else resolve7(code);
1433
1433
  });
1434
1434
  };
1435
1435
  const timer = setTimeout(() => {
@@ -1620,10 +1620,10 @@ function escapeHtml(s) {
1620
1620
  // src/commands/login.ts
1621
1621
  function ask(prompt) {
1622
1622
  const rl = createInterface2({ input: process.stdin, output: process.stdout });
1623
- return new Promise((resolve6) => {
1623
+ return new Promise((resolve7) => {
1624
1624
  rl.question(prompt, (answer) => {
1625
1625
  rl.close();
1626
- resolve6(answer.trim());
1626
+ resolve7(answer.trim());
1627
1627
  });
1628
1628
  });
1629
1629
  }
@@ -2184,10 +2184,10 @@ var __dirname = dirname3(fileURLToPath2(import.meta.url));
2184
2184
  function ask2(prompt, defaultVal = "") {
2185
2185
  const rl = createInterface3({ input: process.stdin, output: process.stdout });
2186
2186
  const suffix = defaultVal ? chalk8.dim(` [${defaultVal}]`) : "";
2187
- return new Promise((resolve6) => {
2187
+ return new Promise((resolve7) => {
2188
2188
  rl.question(` ${prompt}${suffix}: `, (answer) => {
2189
2189
  rl.close();
2190
- resolve6(answer.trim() || defaultVal);
2190
+ resolve7(answer.trim() || defaultVal);
2191
2191
  });
2192
2192
  });
2193
2193
  }
@@ -3923,7 +3923,7 @@ function registerUpdateCommand(program2) {
3923
3923
  import { spawn as spawn5 } from "child_process";
3924
3924
  import { input as input2, select as select7 } from "@inquirer/prompts";
3925
3925
  function getTerraformOutput2(cwd, key) {
3926
- return new Promise((resolve6, reject) => {
3926
+ return new Promise((resolve7, reject) => {
3927
3927
  const proc = spawn5("terraform", ["output", "-raw", key], {
3928
3928
  cwd,
3929
3929
  stdio: ["pipe", "pipe", "pipe"]
@@ -3933,7 +3933,7 @@ function getTerraformOutput2(cwd, key) {
3933
3933
  proc.stdout.on("data", (d) => stdout += d);
3934
3934
  proc.stderr.on("data", (d) => stderr += d);
3935
3935
  proc.on("close", (code) => {
3936
- if (code === 0) resolve6(stdout.trim());
3936
+ if (code === 0) resolve7(stdout.trim());
3937
3937
  else
3938
3938
  reject(
3939
3939
  new Error(
@@ -3944,7 +3944,7 @@ function getTerraformOutput2(cwd, key) {
3944
3944
  });
3945
3945
  }
3946
3946
  function runAwsCognitoReset(userPoolId, username, region) {
3947
- return new Promise((resolve6) => {
3947
+ return new Promise((resolve7) => {
3948
3948
  const args = [
3949
3949
  "cognito-idp",
3950
3950
  "admin-reset-user-password",
@@ -3961,7 +3961,7 @@ function runAwsCognitoReset(userPoolId, username, region) {
3961
3961
  let stderr = "";
3962
3962
  proc.stdout.on("data", (d) => stdout += d);
3963
3963
  proc.stderr.on("data", (d) => stderr += d);
3964
- proc.on("close", (code) => resolve6({ code: code ?? 1, stdout, stderr }));
3964
+ proc.on("close", (code) => resolve7({ code: code ?? 1, stdout, stderr }));
3965
3965
  });
3966
3966
  }
3967
3967
  function requireTty2(label) {
@@ -4701,6 +4701,7 @@ var CliCreateWebhookDocument = { "kind": "Document", "definitions": [{ "kind": "
4701
4701
  var CliUpdateWebhookDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "CliUpdateWebhook" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "ID" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "input" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "UpdateWebhookInput" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "updateWebhook" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "input" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "input" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "targetType" } }, { "kind": "Field", "name": { "kind": "Name", "value": "enabled" } }, { "kind": "Field", "name": { "kind": "Name", "value": "rateLimit" } }] } }] } }] };
4702
4702
  var CliDeleteWebhookDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "CliDeleteWebhook" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "ID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "deleteWebhook" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }] }] } }] };
4703
4703
  var CliRegenerateWebhookTokenDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "CliRegenerateWebhookToken" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "ID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "regenerateWebhookToken" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "id" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "id" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "token" } }] } }] } }] };
4704
+ var CliWebhookDeliveriesDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "CliWebhookDeliveries" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "webhookId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "ID" } } } }, { "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "webhookDeliveries" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "webhookId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "webhookId" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "limit" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "limit" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "providerName" } }, { "kind": "Field", "name": { "kind": "Name", "value": "providerEventId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "normalizedKind" } }, { "kind": "Field", "name": { "kind": "Name", "value": "receivedAt" } }, { "kind": "Field", "name": { "kind": "Name", "value": "signatureStatus" } }, { "kind": "Field", "name": { "kind": "Name", "value": "resolutionStatus" } }, { "kind": "Field", "name": { "kind": "Name", "value": "statusCode" } }, { "kind": "Field", "name": { "kind": "Name", "value": "durationMs" } }, { "kind": "Field", "name": { "kind": "Name", "value": "threadId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "threadCreated" } }, { "kind": "Field", "name": { "kind": "Name", "value": "retryCount" } }, { "kind": "Field", "name": { "kind": "Name", "value": "isReplay" } }, { "kind": "Field", "name": { "kind": "Name", "value": "errorMessage" } }] } }] } }] };
4704
4705
  var CliWebhookTenantBySlugDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "CliWebhookTenantBySlug" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "tenantBySlug" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "slug" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }] } }] } }] };
4705
4706
  var CliWikiTenantBySlugDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "CliWikiTenantBySlug" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "String" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "tenantBySlug" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "slug" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "slug" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }] } }] } }] };
4706
4707
  var CliAllTenantAgentsForWikiDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "CliAllTenantAgentsForWiki" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "tenantId" } }, "type": { "kind": "NonNullType", "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "ID" } } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "allTenantAgents" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "tenantId" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "tenantId" } } }, { "kind": "Argument", "name": { "kind": "Name", "value": "includeSystem" }, "value": { "kind": "BooleanValue", "value": false } }, { "kind": "Argument", "name": { "kind": "Name", "value": "includeSubAgents" }, "value": { "kind": "BooleanValue", "value": false } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "id" } }, { "kind": "Field", "name": { "kind": "Name", "value": "name" } }, { "kind": "Field", "name": { "kind": "Name", "value": "slug" } }, { "kind": "Field", "name": { "kind": "Name", "value": "type" } }, { "kind": "Field", "name": { "kind": "Name", "value": "status" } }] } }] } }] };
@@ -4877,6 +4878,7 @@ var documents = {
4877
4878
  "\n mutation CliUpdateWebhook($id: ID!, $input: UpdateWebhookInput!) {\n updateWebhook(id: $id, input: $input) {\n id\n name\n targetType\n enabled\n rateLimit\n }\n }\n": CliUpdateWebhookDocument,
4878
4879
  "\n mutation CliDeleteWebhook($id: ID!) {\n deleteWebhook(id: $id)\n }\n": CliDeleteWebhookDocument,
4879
4880
  "\n mutation CliRegenerateWebhookToken($id: ID!) {\n regenerateWebhookToken(id: $id) {\n id\n token\n }\n }\n": CliRegenerateWebhookTokenDocument,
4881
+ "\n query CliWebhookDeliveries($webhookId: ID!, $limit: Int) {\n webhookDeliveries(webhookId: $webhookId, limit: $limit) {\n id\n providerName\n providerEventId\n normalizedKind\n receivedAt\n signatureStatus\n resolutionStatus\n statusCode\n durationMs\n threadId\n threadCreated\n retryCount\n isReplay\n errorMessage\n }\n }\n": CliWebhookDeliveriesDocument,
4880
4882
  "\n query CliWebhookTenantBySlug($slug: String!) {\n tenantBySlug(slug: $slug) {\n id\n }\n }\n": CliWebhookTenantBySlugDocument,
4881
4883
  "\n query CliWikiTenantBySlug($slug: String!) {\n tenantBySlug(slug: $slug) {\n id\n slug\n name\n }\n }\n": CliWikiTenantBySlugDocument,
4882
4884
  "\n query CliAllTenantAgentsForWiki($tenantId: ID!) {\n allTenantAgents(tenantId: $tenantId, includeSystem: false, includeSubAgents: false) {\n id\n name\n slug\n type\n status\n }\n }\n": CliAllTenantAgentsForWikiDocument,
@@ -10619,6 +10621,26 @@ var RegenerateWebhookTokenDoc = graphql(`
10619
10621
  }
10620
10622
  }
10621
10623
  `);
10624
+ var WebhookDeliveriesDoc = graphql(`
10625
+ query CliWebhookDeliveries($webhookId: ID!, $limit: Int) {
10626
+ webhookDeliveries(webhookId: $webhookId, limit: $limit) {
10627
+ id
10628
+ providerName
10629
+ providerEventId
10630
+ normalizedKind
10631
+ receivedAt
10632
+ signatureStatus
10633
+ resolutionStatus
10634
+ statusCode
10635
+ durationMs
10636
+ threadId
10637
+ threadCreated
10638
+ retryCount
10639
+ isReplay
10640
+ errorMessage
10641
+ }
10642
+ }
10643
+ `);
10622
10644
  var WebhookTenantBySlugDoc = graphql(`
10623
10645
  query CliWebhookTenantBySlug($slug: String!) {
10624
10646
  tenantBySlug(slug: $slug) {
@@ -10852,6 +10874,50 @@ async function runWebhookRotate(id, opts) {
10852
10874
  console.log(" New token (SAVE THIS):");
10853
10875
  console.log(` ${wh.token}`);
10854
10876
  }
10877
+ async function runWebhookDeliveries(id, opts) {
10878
+ const ctx = await resolveWebhookContext(opts);
10879
+ const limit = Math.min(
10880
+ Math.max(Number.parseInt(opts.limit ?? "25", 10) || 25, 1),
10881
+ 500
10882
+ );
10883
+ const data = await gqlQuery(ctx.client, WebhookDeliveriesDoc, {
10884
+ webhookId: id,
10885
+ limit
10886
+ });
10887
+ const rows = data.webhookDeliveries;
10888
+ if (isJsonMode()) {
10889
+ printJson({ items: rows });
10890
+ return;
10891
+ }
10892
+ if (rows.length === 0) {
10893
+ logStderr(`No deliveries recorded for webhook ${id}.`);
10894
+ return;
10895
+ }
10896
+ printTable(
10897
+ rows.map((r) => ({
10898
+ received: r.receivedAt ?? "",
10899
+ provider: r.providerName ?? "\u2014",
10900
+ event: r.normalizedKind ?? r.providerEventId ?? "\u2014",
10901
+ sig: r.signatureStatus,
10902
+ resolution: r.resolutionStatus,
10903
+ status: r.statusCode != null ? String(r.statusCode) : "\u2014",
10904
+ durMs: r.durationMs != null ? String(r.durationMs) : "\u2014",
10905
+ retry: r.retryCount != null ? String(r.retryCount) : "\u2014",
10906
+ thread: r.threadId ?? "\u2014"
10907
+ })),
10908
+ [
10909
+ { key: "received", header: "Received" },
10910
+ { key: "provider", header: "Provider" },
10911
+ { key: "event", header: "Event" },
10912
+ { key: "sig", header: "Sig" },
10913
+ { key: "resolution", header: "Resolution" },
10914
+ { key: "status", header: "Status" },
10915
+ { key: "durMs", header: "Dur(ms)" },
10916
+ { key: "retry", header: "Retry" },
10917
+ { key: "thread", header: "Thread" }
10918
+ ]
10919
+ );
10920
+ }
10855
10921
  function notYetImplementedAtApi2(verb) {
10856
10922
  printError(
10857
10923
  `\`webhook ${verb}\` is not yet implemented at the GraphQL API.
@@ -10874,7 +10940,9 @@ Examples:
10874
10940
  wh.command("delete <id>").description("Delete a webhook (its URL stops working immediately).").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("-y, --yes", "Skip confirmation").action(runWebhookDelete);
10875
10941
  wh.command("test <id>").description("Send a synthetic payload to the webhook. (API surface pending.)").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--payload <json>").action(() => notYetImplementedAtApi2("test"));
10876
10942
  wh.command("rotate <id>").description("Generate a new token for an existing webhook.").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("-y, --yes", "Skip confirmation").action(runWebhookRotate);
10877
- wh.command("deliveries <id>").description("Show recent delivery attempts. (API surface pending.)").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--limit <n>", "Max rows", "25").action(() => notYetImplementedAtApi2("deliveries"));
10943
+ wh.command("deliveries <id>").description(
10944
+ "Show recent delivery attempts for a webhook (newest first). Default 25, max 500."
10945
+ ).option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("--limit <n>", "Max rows (1-500)", "25").action(runWebhookDeliveries);
10878
10946
  }
10879
10947
 
10880
10948
  // src/lib/plugin-zip.ts
@@ -13267,10 +13335,15 @@ async function runEvalSeed(opts) {
13267
13335
  categories: opts.category && opts.category.length > 0 ? opts.category : null
13268
13336
  });
13269
13337
  if (isJsonMode()) {
13270
- printJson({ inserted: data.seedEvalTestCases });
13338
+ printJson({
13339
+ source: "built-in-yaml-seed",
13340
+ inserted: data.seedEvalTestCases
13341
+ });
13271
13342
  return;
13272
13343
  }
13273
- printSuccess(`Seeded ${data.seedEvalTestCases} new test case(s). (Duplicates were skipped.)`);
13344
+ printSuccess(
13345
+ `Seeded ${data.seedEvalTestCases} new test case(s). (Duplicates were skipped.)`
13346
+ );
13274
13347
  }
13275
13348
 
13276
13349
  // src/commands/eval/test-case/list.ts
@@ -15336,12 +15409,541 @@ function printBootstrapSummary(result) {
15336
15409
  }
15337
15410
  }
15338
15411
 
15412
+ // src/commands/enterprise/overlay.ts
15413
+ import { resolve as resolve6 } from "path";
15414
+
15415
+ // src/commands/enterprise/overlay-schema.ts
15416
+ import { existsSync as existsSync11, readdirSync as readdirSync3, readFileSync as readFileSync9, statSync as statSync3 } from "fs";
15417
+ import { join as join9, relative as relative3, sep as sep2 } from "path";
15418
+ function loadEnterpriseOverlayDefinition(repoRoot) {
15419
+ const path2 = join9(repoRoot, "customer", "deployment.json");
15420
+ if (!existsSync11(path2)) {
15421
+ throw new Error(`Missing customer overlay definition: ${path2}`);
15422
+ }
15423
+ const parsed = JSON.parse(readFileSync9(path2, "utf8"));
15424
+ if (parsed.schemaVersion !== 1) {
15425
+ throw new Error(
15426
+ `Unsupported customer/deployment.json schemaVersion ${parsed.schemaVersion}`
15427
+ );
15428
+ }
15429
+ if (!isNonEmptyString(parsed.customerSlug)) {
15430
+ throw new Error("customer/deployment.json requires customerSlug");
15431
+ }
15432
+ if (!isRecord(parsed.stages)) {
15433
+ throw new Error("customer/deployment.json requires stages");
15434
+ }
15435
+ return {
15436
+ schemaVersion: 1,
15437
+ customerSlug: parsed.customerSlug,
15438
+ stages: Object.fromEntries(
15439
+ Object.entries(parsed.stages).map(([stage, value]) => [
15440
+ stage,
15441
+ normalizeStage(stage, value)
15442
+ ])
15443
+ )
15444
+ };
15445
+ }
15446
+ function stageOverlay(definition, stage) {
15447
+ const config = definition.stages[stage];
15448
+ if (!config) {
15449
+ throw new Error(`customer/deployment.json does not define stage ${stage}`);
15450
+ }
15451
+ return config;
15452
+ }
15453
+ function readCustomerEvalPack(repoRoot, packName) {
15454
+ assertPackName(packName, "eval");
15455
+ const path2 = join9(repoRoot, "customer", "evals", `${packName}.json`);
15456
+ if (!existsSync11(path2)) {
15457
+ throw new Error(`Eval pack "${packName}" is missing: ${path2}`);
15458
+ }
15459
+ const parsed = JSON.parse(readFileSync9(path2, "utf8"));
15460
+ if (!Array.isArray(parsed)) {
15461
+ throw new Error(`Eval pack "${packName}" must be a JSON array`);
15462
+ }
15463
+ return parsed.map(
15464
+ (value, index) => normalizeEvalSeed(value, `customer/evals/${packName}.json[${index}]`)
15465
+ );
15466
+ }
15467
+ function readJsonSeedPack(repoRoot, packName) {
15468
+ assertPackName(packName, "seed");
15469
+ const path2 = join9(repoRoot, "customer", "seeds", `${packName}.json`);
15470
+ if (!existsSync11(path2)) {
15471
+ throw new Error(`Seed pack "${packName}" is missing: ${path2}`);
15472
+ }
15473
+ return JSON.parse(readFileSync9(path2, "utf8"));
15474
+ }
15475
+ function collectOverlayFiles(repoRoot, family, packName) {
15476
+ assertPackName(packName, family);
15477
+ const root = join9(repoRoot, "customer", family, packName);
15478
+ if (!existsSync11(root) || !statSync3(root).isDirectory()) {
15479
+ throw new Error(`Overlay pack "${family}/${packName}" is missing: ${root}`);
15480
+ }
15481
+ const files = [];
15482
+ walkFiles(root, (path2) => {
15483
+ const relativePath = relative3(root, path2).split(sep2).join("/");
15484
+ if (relativePath === ".DS_Store" || relativePath.endsWith("/.DS_Store")) {
15485
+ return;
15486
+ }
15487
+ files.push({
15488
+ relativePath,
15489
+ content: readFileSync9(path2, "utf8")
15490
+ });
15491
+ });
15492
+ if (family === "skills" && !files.some((file) => file.relativePath === "SKILL.md")) {
15493
+ throw new Error(`Skill pack "${packName}" must include SKILL.md`);
15494
+ }
15495
+ if (files.length === 0) {
15496
+ throw new Error(`Overlay pack "${family}/${packName}" contains no files`);
15497
+ }
15498
+ return files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
15499
+ }
15500
+ function normalizeStage(stage, value) {
15501
+ if (!isRecord(value)) {
15502
+ throw new Error(`Stage ${stage} must be an object`);
15503
+ }
15504
+ if (!isNonEmptyString(value.tenantSlug)) {
15505
+ throw new Error(`Stage ${stage} requires tenantSlug`);
15506
+ }
15507
+ const branding = value.branding;
15508
+ if (branding !== null && branding !== void 0 && !isRecord(branding)) {
15509
+ throw new Error(`Stage ${stage} branding must be an object or null`);
15510
+ }
15511
+ return {
15512
+ tenantSlug: value.tenantSlug,
15513
+ evalPacks: normalizePackArray(value.evalPacks, `${stage}.evalPacks`),
15514
+ seedPacks: normalizePackArray(value.seedPacks, `${stage}.seedPacks`),
15515
+ skillPacks: normalizePackArray(value.skillPacks, `${stage}.skillPacks`),
15516
+ workspaceDefaultPacks: normalizePackArray(
15517
+ value.workspaceDefaultPacks,
15518
+ `${stage}.workspaceDefaultPacks`
15519
+ ),
15520
+ branding: branding ?? null,
15521
+ defaultAgentTemplateSlug: isNonEmptyString(value.defaultAgentTemplateSlug) ? value.defaultAgentTemplateSlug : "default"
15522
+ };
15523
+ }
15524
+ function normalizeEvalSeed(value, label) {
15525
+ if (!isRecord(value)) throw new Error(`${label} must be an object`);
15526
+ if (!isNonEmptyString(value.name))
15527
+ throw new Error(`${label}.name is required`);
15528
+ if (!isNonEmptyString(value.category))
15529
+ throw new Error(`${label}.category is required`);
15530
+ if (!isNonEmptyString(value.query))
15531
+ throw new Error(`${label}.query is required`);
15532
+ const assertions = value.assertions;
15533
+ if (!Array.isArray(assertions)) {
15534
+ throw new Error(`${label}.assertions must be an array`);
15535
+ }
15536
+ return {
15537
+ name: value.name,
15538
+ category: value.category,
15539
+ query: value.query,
15540
+ systemPrompt: typeof value.systemPrompt === "string" ? value.systemPrompt : null,
15541
+ agentTemplateId: typeof value.agentTemplateId === "string" ? value.agentTemplateId : null,
15542
+ assertions: assertions.map(
15543
+ (assertion, index) => normalizeAssertion(assertion, `${label}.assertions[${index}]`)
15544
+ ),
15545
+ agentcoreEvaluatorIds: normalizeOptionalStringArray(
15546
+ value.agentcoreEvaluatorIds,
15547
+ `${label}.agentcoreEvaluatorIds`
15548
+ ),
15549
+ tags: normalizeOptionalStringArray(value.tags, `${label}.tags`),
15550
+ enabled: typeof value.enabled === "boolean" ? value.enabled : true
15551
+ };
15552
+ }
15553
+ function normalizeAssertion(value, label) {
15554
+ if (!isRecord(value)) throw new Error(`${label} must be an object`);
15555
+ if (!isNonEmptyString(value.type))
15556
+ throw new Error(`${label}.type is required`);
15557
+ return {
15558
+ type: value.type,
15559
+ value: typeof value.value === "string" || value.value === null ? value.value : void 0,
15560
+ path: typeof value.path === "string" || value.path === null ? value.path : void 0
15561
+ };
15562
+ }
15563
+ function normalizePackArray(value, label) {
15564
+ const items = normalizeStringArray(value, label);
15565
+ for (const item of items) assertPackName(item, label);
15566
+ return items;
15567
+ }
15568
+ function normalizeStringArray(value, label) {
15569
+ if (value === void 0) return [];
15570
+ if (!Array.isArray(value)) throw new Error(`${label} must be an array`);
15571
+ return value.map((item, index) => {
15572
+ if (!isNonEmptyString(item)) {
15573
+ throw new Error(`${label}[${index}] must be a non-empty string`);
15574
+ }
15575
+ return item;
15576
+ });
15577
+ }
15578
+ function normalizeOptionalStringArray(value, label) {
15579
+ if (value === void 0 || value === null) return [];
15580
+ return normalizeStringArray(value, label);
15581
+ }
15582
+ function assertPackName(value, label) {
15583
+ if (!/^[a-z0-9][a-z0-9_.-]*$/.test(value)) {
15584
+ throw new Error(
15585
+ `${label} pack "${value}" must use lowercase letters, numbers, dot, underscore, or hyphen`
15586
+ );
15587
+ }
15588
+ }
15589
+ function walkFiles(root, visit) {
15590
+ for (const entry of readdirSync3(root, { withFileTypes: true })) {
15591
+ const path2 = join9(root, entry.name);
15592
+ if (entry.isDirectory()) {
15593
+ walkFiles(path2, visit);
15594
+ } else if (entry.isFile()) {
15595
+ visit(path2);
15596
+ }
15597
+ }
15598
+ }
15599
+ function isRecord(value) {
15600
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15601
+ }
15602
+ function isNonEmptyString(value) {
15603
+ return typeof value === "string" && value.trim().length > 0;
15604
+ }
15605
+
15606
+ // src/commands/enterprise/overlay-apply.ts
15607
+ function buildEnterpriseOverlayPlan(options) {
15608
+ const definition = loadEnterpriseOverlayDefinition(options.repoRoot);
15609
+ const stage = stageOverlay(definition, options.stage);
15610
+ return {
15611
+ repoRoot: options.repoRoot,
15612
+ stage: options.stage,
15613
+ tenantSlug: stage.tenantSlug,
15614
+ targetTemplateSlug: stage.defaultAgentTemplateSlug,
15615
+ operations: [
15616
+ ...evalOperations(options.repoRoot, stage),
15617
+ ...workspaceFileOperations(options.repoRoot, stage),
15618
+ ...seedOperations(options.repoRoot, stage),
15619
+ ...stage.branding ? [{ kind: "branding", branding: stage.branding }] : []
15620
+ ]
15621
+ };
15622
+ }
15623
+ async function applyEnterpriseOverlay(plan, client) {
15624
+ const result = {
15625
+ stage: plan.stage,
15626
+ tenantSlug: plan.tenantSlug,
15627
+ evals: { inserted: 0, updated: 0, skipped: 0, packs: [] },
15628
+ workspaceFiles: { written: 0, packs: [] },
15629
+ seeds: { validated: 0, packs: [] },
15630
+ branding: "not-configured"
15631
+ };
15632
+ const existing = await client.listEvalTestCases();
15633
+ const existingByOverlayKey = new Map(
15634
+ existing.flatMap(
15635
+ (testCase) => (testCase.tags ?? []).filter((tag) => tag.startsWith("customer-overlay:key:")).map((tag) => [tag, testCase])
15636
+ )
15637
+ );
15638
+ for (const operation of plan.operations) {
15639
+ if (operation.kind === "eval-pack") {
15640
+ const packResult = {
15641
+ pack: operation.pack,
15642
+ inserted: 0,
15643
+ updated: 0,
15644
+ skipped: 0
15645
+ };
15646
+ for (const testCase of operation.testCases) {
15647
+ const input20 = withOverlayTags(
15648
+ operation.pack,
15649
+ testCase,
15650
+ client.targetAgentTemplateId
15651
+ );
15652
+ const existingCase = existingByOverlayKey.get(
15653
+ overlayKeyTag(operation.pack, testCase)
15654
+ );
15655
+ if (existingCase) {
15656
+ if (sameEval(existingCase, input20)) {
15657
+ result.evals.skipped++;
15658
+ packResult.skipped++;
15659
+ } else {
15660
+ await client.updateEvalTestCase(existingCase.id, input20);
15661
+ result.evals.updated++;
15662
+ packResult.updated++;
15663
+ }
15664
+ } else {
15665
+ await client.createEvalTestCase(input20);
15666
+ result.evals.inserted++;
15667
+ packResult.inserted++;
15668
+ }
15669
+ }
15670
+ result.evals.packs.push(packResult);
15671
+ continue;
15672
+ }
15673
+ if (operation.kind === "workspace-file-pack") {
15674
+ for (const file of operation.files) {
15675
+ await client.putWorkspaceFile({
15676
+ templateSlug: operation.targetTemplateSlug,
15677
+ path: workspaceTargetPath(
15678
+ operation.family,
15679
+ operation.pack,
15680
+ file.relativePath
15681
+ ),
15682
+ content: file.content
15683
+ });
15684
+ result.workspaceFiles.written++;
15685
+ }
15686
+ result.workspaceFiles.packs.push({
15687
+ family: operation.family,
15688
+ pack: operation.pack,
15689
+ written: operation.files.length
15690
+ });
15691
+ continue;
15692
+ }
15693
+ if (operation.kind === "seed-pack") {
15694
+ result.seeds.validated++;
15695
+ result.seeds.packs.push(operation.pack);
15696
+ continue;
15697
+ }
15698
+ if (operation.kind === "branding") {
15699
+ result.branding = "recorded";
15700
+ }
15701
+ }
15702
+ return result;
15703
+ }
15704
+ function evalOperations(repoRoot, stage) {
15705
+ return stage.evalPacks.map((pack) => ({
15706
+ kind: "eval-pack",
15707
+ pack,
15708
+ testCases: readCustomerEvalPack(repoRoot, pack)
15709
+ }));
15710
+ }
15711
+ function workspaceFileOperations(repoRoot, stage) {
15712
+ return [
15713
+ ...stage.skillPacks.map((pack) => ({
15714
+ kind: "workspace-file-pack",
15715
+ family: "skills",
15716
+ pack,
15717
+ targetTemplateSlug: stage.defaultAgentTemplateSlug,
15718
+ files: collectOverlayFiles(repoRoot, "skills", pack)
15719
+ })),
15720
+ ...stage.workspaceDefaultPacks.map((pack) => ({
15721
+ kind: "workspace-file-pack",
15722
+ family: "workspace-defaults",
15723
+ pack,
15724
+ targetTemplateSlug: stage.defaultAgentTemplateSlug,
15725
+ files: collectOverlayFiles(repoRoot, "workspace-defaults", pack)
15726
+ }))
15727
+ ];
15728
+ }
15729
+ function seedOperations(repoRoot, stage) {
15730
+ return stage.seedPacks.map((pack) => ({
15731
+ kind: "seed-pack",
15732
+ pack,
15733
+ payload: readJsonSeedPack(repoRoot, pack)
15734
+ }));
15735
+ }
15736
+ function workspaceTargetPath(family, pack, relativePath) {
15737
+ if (family === "skills") return `skills/${pack}/${relativePath}`;
15738
+ return relativePath;
15739
+ }
15740
+ function withOverlayTags(pack, testCase, defaultAgentTemplateId) {
15741
+ return {
15742
+ ...testCase,
15743
+ agentTemplateId: testCase.agentTemplateId ?? defaultAgentTemplateId,
15744
+ tags: Array.from(
15745
+ /* @__PURE__ */ new Set([
15746
+ ...testCase.tags ?? [],
15747
+ "source:customer-overlay",
15748
+ `customer-overlay:pack:${pack}`,
15749
+ overlayKeyTag(pack, testCase)
15750
+ ])
15751
+ )
15752
+ };
15753
+ }
15754
+ function overlayKeyTag(pack, testCase) {
15755
+ return `customer-overlay:key:${pack}/${slugify(testCase.name)}`;
15756
+ }
15757
+ function sameEval(existing, next) {
15758
+ return existing.name === next.name && existing.category === next.category && existing.query === next.query && (existing.systemPrompt ?? null) === (next.systemPrompt ?? null) && JSON.stringify(existing.assertions ?? []) === JSON.stringify(next.assertions ?? []) && JSON.stringify(existing.agentcoreEvaluatorIds ?? []) === JSON.stringify(next.agentcoreEvaluatorIds ?? []) && JSON.stringify(existing.tags ?? []) === JSON.stringify(next.tags ?? []) && (existing.enabled ?? true) === (next.enabled ?? true);
15759
+ }
15760
+ function slugify(value) {
15761
+ return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
15762
+ }
15763
+
15764
+ // src/commands/enterprise/overlay.ts
15765
+ function registerEnterpriseOverlayCommand(program2) {
15766
+ const overlay = program2.command("overlay").description(
15767
+ "Validate and apply customer overlay packs from a deployment repo."
15768
+ );
15769
+ overlay.command("plan").argument("[repoRoot]", "Deployment repository root", ".").description(
15770
+ "Validate customer/deployment.json and print the overlay plan."
15771
+ ).option("-s, --stage <name>", "Deployment stage").option("-r, --region <region>", "AWS region", "us-east-1").action(
15772
+ (repoRoot, opts) => runEnterpriseOverlayPlan(repoRoot, opts)
15773
+ );
15774
+ overlay.command("apply").argument("[repoRoot]", "Deployment repository root", ".").description("Apply customer overlay packs to the deployed stage.").option("-s, --stage <name>", "Deployment stage").option("-t, --tenant <slug>", "Tenant slug").option("-r, --region <region>", "AWS region", "us-east-1").option("--dry-run", "Validate and print the apply plan without mutation").action(
15775
+ (repoRoot, opts) => runEnterpriseOverlayApply(repoRoot, opts)
15776
+ );
15777
+ }
15778
+ async function runEnterpriseOverlayPlan(repoRoot, opts) {
15779
+ const plan = buildEnterpriseOverlayPlan({
15780
+ repoRoot: resolve6(repoRoot),
15781
+ stage: resolveOverlayStage(opts)
15782
+ });
15783
+ printJson(publicPlan(plan));
15784
+ }
15785
+ async function runEnterpriseOverlayApply(repoRoot, opts) {
15786
+ const stage = resolveOverlayStage(opts);
15787
+ const plan = buildEnterpriseOverlayPlan({
15788
+ repoRoot: resolve6(repoRoot),
15789
+ stage
15790
+ });
15791
+ if (opts.dryRun) {
15792
+ printJson({ dryRun: true, plan: publicPlan(plan) });
15793
+ return;
15794
+ }
15795
+ const client = await createOverlayApiClient(plan, opts);
15796
+ const result = await applyEnterpriseOverlay(plan, client);
15797
+ if (isJsonMode()) {
15798
+ printJson(result);
15799
+ return;
15800
+ }
15801
+ printSuccess(
15802
+ `Applied overlay for ${plan.tenantSlug}: ${result.evals.inserted} eval(s) inserted, ${result.evals.updated} updated, ${result.workspaceFiles.written} workspace file(s) written.`
15803
+ );
15804
+ }
15805
+ async function createOverlayApiClient(plan, opts) {
15806
+ const region = opts.region ?? "us-east-1";
15807
+ const ctx = await resolveEvalContext({
15808
+ stage: plan.stage,
15809
+ region,
15810
+ tenant: opts.tenant ?? plan.tenantSlug
15811
+ });
15812
+ const templateId = await resolveTemplateId(
15813
+ ctx.client,
15814
+ ctx.tenantId,
15815
+ plan.targetTemplateSlug
15816
+ );
15817
+ const auth = await resolveAuth({ stage: plan.stage, region });
15818
+ const apiUrl = getApiEndpoint(plan.stage, region);
15819
+ if (!apiUrl) {
15820
+ printError(
15821
+ `Cannot discover API endpoint for stage "${plan.stage}" in ${region}.`
15822
+ );
15823
+ process.exit(1);
15824
+ }
15825
+ return {
15826
+ targetAgentTemplateId: templateId,
15827
+ async listEvalTestCases() {
15828
+ const data = await gqlQuery(ctx.client, EvalTestCasesDoc, {
15829
+ tenantId: ctx.tenantId,
15830
+ category: null,
15831
+ search: null
15832
+ });
15833
+ return data.evalTestCases;
15834
+ },
15835
+ async createEvalTestCase(input20) {
15836
+ await gqlMutate(ctx.client, CreateEvalTestCaseDoc, {
15837
+ tenantId: ctx.tenantId,
15838
+ input: evalInput(input20)
15839
+ });
15840
+ },
15841
+ async updateEvalTestCase(id, input20) {
15842
+ await gqlMutate(ctx.client, UpdateEvalTestCaseDoc, {
15843
+ id,
15844
+ input: evalInput(input20)
15845
+ });
15846
+ },
15847
+ async putWorkspaceFile(input20) {
15848
+ const response = await fetch(
15849
+ `${apiUrl.replace(/\/+$/, "")}/api/workspaces/files`,
15850
+ {
15851
+ method: "POST",
15852
+ headers: {
15853
+ "content-type": "application/json",
15854
+ ...auth.headers,
15855
+ "x-tenant-id": ctx.tenantId
15856
+ },
15857
+ body: JSON.stringify({
15858
+ action: "put",
15859
+ templateId,
15860
+ path: input20.path,
15861
+ content: input20.content
15862
+ })
15863
+ }
15864
+ );
15865
+ if (!response.ok) {
15866
+ const text = await response.text();
15867
+ throw new Error(
15868
+ `PUT ${input20.path} failed: ${response.status} ${text || response.statusText}`
15869
+ );
15870
+ }
15871
+ }
15872
+ };
15873
+ }
15874
+ async function resolveTemplateId(client, tenantId, templateSlug) {
15875
+ const data = await gqlQuery(client, AgentTemplatesForEvalDoc, { tenantId });
15876
+ const template = data.agentTemplates.find(
15877
+ (item) => item.slug === templateSlug
15878
+ );
15879
+ if (!template) {
15880
+ throw new Error(
15881
+ `Agent template "${templateSlug}" not found for tenant ${tenantId}`
15882
+ );
15883
+ }
15884
+ return template.id;
15885
+ }
15886
+ function evalInput(input20) {
15887
+ return {
15888
+ name: input20.name,
15889
+ category: input20.category,
15890
+ query: input20.query,
15891
+ systemPrompt: input20.systemPrompt ?? null,
15892
+ agentTemplateId: input20.agentTemplateId ?? null,
15893
+ assertions: input20.assertions,
15894
+ agentcoreEvaluatorIds: input20.agentcoreEvaluatorIds ?? [],
15895
+ tags: input20.tags ?? [],
15896
+ enabled: input20.enabled ?? true
15897
+ };
15898
+ }
15899
+ function publicPlan(plan) {
15900
+ return {
15901
+ stage: plan.stage,
15902
+ tenantSlug: plan.tenantSlug,
15903
+ targetTemplateSlug: plan.targetTemplateSlug,
15904
+ operations: plan.operations.map((operation) => {
15905
+ if (operation.kind === "eval-pack") {
15906
+ return {
15907
+ kind: operation.kind,
15908
+ pack: operation.pack,
15909
+ testCases: operation.testCases.length
15910
+ };
15911
+ }
15912
+ if (operation.kind === "workspace-file-pack") {
15913
+ return {
15914
+ kind: operation.kind,
15915
+ family: operation.family,
15916
+ pack: operation.pack,
15917
+ targetTemplateSlug: operation.targetTemplateSlug,
15918
+ files: operation.files.length
15919
+ };
15920
+ }
15921
+ if (operation.kind === "seed-pack") {
15922
+ return {
15923
+ kind: operation.kind,
15924
+ pack: operation.pack,
15925
+ status: "validated"
15926
+ };
15927
+ }
15928
+ return { kind: operation.kind, status: "recorded" };
15929
+ })
15930
+ };
15931
+ }
15932
+ function resolveOverlayStage(opts) {
15933
+ const stage = opts.stage ?? process.env.STAGE;
15934
+ if (!stage) {
15935
+ throw new Error("Deployment stage is required. Pass --stage or set STAGE.");
15936
+ }
15937
+ return stage;
15938
+ }
15939
+
15339
15940
  // src/commands/enterprise.ts
15340
15941
  function registerEnterpriseCommand(program2) {
15341
15942
  const enterprise = program2.command("enterprise").description(
15342
15943
  "Bootstrap and operate customer-owned ThinkWork enterprise deployment repositories."
15343
15944
  );
15344
15945
  registerEnterpriseBootstrapCommand(enterprise);
15946
+ registerEnterpriseOverlayCommand(enterprise);
15345
15947
  }
15346
15948
 
15347
15949
  // src/cli.ts