@kora-platform/cli 0.8.0-rc1 → 0.8.0-rc10

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.
@@ -31,6 +31,12 @@ export const CLI_ALIASES = Object.freeze({
31
31
  process: ["workflow"],
32
32
  project: ["org"],
33
33
  });
34
+ const releaseReadFlag = (description, required = false) => flag("release", description, { acceptsValue: true, ...(required ? { required: true } : {}), valueType: "string" });
35
+ const releaseEnvironmentReadFlag = (description) => flag("environment", description, { acceptsValue: true, valueType: "string" });
36
+ const releaseSnapshotReadFlags = (releaseDescription, environmentDescription) => [
37
+ releaseReadFlag(releaseDescription),
38
+ releaseEnvironmentReadFlag(environmentDescription)
39
+ ];
34
40
  const RAW_CLI_COMMANDS = [
35
41
  command(["help"], "Show human or machine-readable help for a command path.", {
36
42
  labels: ["read", "chat-read", "help"],
@@ -64,13 +70,14 @@ const RAW_CLI_COMMANDS = [
64
70
  command(["auth", "whoami"], "Show the current authenticated user and selected organization.", {
65
71
  labels: ["local", "auth"]
66
72
  }),
67
- command(["auth", "login"], "Start an interactive login flow and select the active organization.", {
73
+ command(["auth", "login"], "Log in and select the active organization. Uses browser device approval with --device or when the terminal is not interactive.", {
68
74
  labels: ["credential", "auth"],
69
75
  flags: [
70
76
  flag("base-url", "Platform base URL for this login.", {
71
77
  acceptsValue: true,
72
78
  valueType: "string"
73
- })
79
+ }),
80
+ flag("device", "Use the browser device-approval flow instead of interactive email/password login.")
74
81
  ]
75
82
  }),
76
83
  command(["auth", "signup"], "Create a local account and start a CLI session.", {
@@ -182,52 +189,37 @@ const RAW_CLI_COMMANDS = [
182
189
  labels: ["read", "activity", "chat-read"],
183
190
  requiresActiveOrg: true
184
191
  }),
185
- command(["workflow", "list"], "List workflows.", {
186
- labels: ["read", "workflow"],
187
- aliases: [["process", "list"]],
188
- flags: [flag("release", "Read workflows from a release.", {
189
- acceptsValue: true,
190
- valueType: "string"
191
- })],
192
+ command(["workflow", "list"], "List live deployed workflows, filter live deployments with --environment, or list workflows from a release with --release.", {
193
+ labels: ["read", "workflow"], aliases: [["process", "list"]],
194
+ examples: ["kora workflow list", "kora workflow list --environment <environment>", "kora workflow list --release <release>"],
195
+ flags: releaseSnapshotReadFlags("Read workflows from an immutable release instead of live deployments.", "Filter live deployed workflows to one environment's live deployment."),
192
196
  requiresActiveOrg: true
193
197
  }),
194
198
  command(["workflow", "get"], "Show workflow detail.", {
195
199
  labels: ["read", "workflow"],
196
200
  aliases: [["process", "get"]],
197
201
  args: [arg("name", "Workflow name.")],
198
- flags: [flag("release", "Read workflow detail from a release.", {
199
- acceptsValue: true,
200
- valueType: "string"
201
- })],
202
+ flags: releaseSnapshotReadFlags("Read workflow detail from a release.", "Read workflow detail from an environment's live deployment release."),
202
203
  requiresActiveOrg: true
203
204
  }),
204
205
  command(["workflow", "version", "get"], "Show one workflow version.", {
205
206
  labels: ["read", "workflow"],
206
207
  aliases: [["process", "version", "get"]],
207
208
  args: [arg("name", "Workflow name."), arg("version", "Workflow version.")],
208
- flags: [flag("release", "Read workflow version from a release.", {
209
- acceptsValue: true,
210
- valueType: "string"
211
- })],
209
+ flags: releaseSnapshotReadFlags("Read workflow version from a release.", "Read workflow version from an environment's live deployment release."),
212
210
  requiresActiveOrg: true
213
211
  }),
214
212
  command(["workflow", "dependencies"], "Show workflow dependency detail.", {
215
213
  labels: ["read", "workflow"],
216
214
  aliases: [["process", "dependencies"]],
217
215
  args: [arg("name", "Workflow name."), arg("version", "Workflow version.")],
218
- flags: [flag("release", "Read workflow dependencies from a release.", {
219
- acceptsValue: true,
220
- valueType: "string"
221
- })],
216
+ flags: releaseSnapshotReadFlags("Read workflow dependencies from a release.", "Read workflow dependencies from an environment's live deployment release."),
222
217
  requiresActiveOrg: true
223
218
  }),
224
219
  command(["workflow", "context"], "Show workflow inspection context.", {
225
220
  labels: ["read", "workflow"],
226
221
  aliases: [["process", "context"]],
227
- flags: [flag("release", "Read workflow context from a release.", {
228
- acceptsValue: true,
229
- valueType: "string"
230
- })],
222
+ flags: releaseSnapshotReadFlags("Read workflow context from a release.", "Read workflow context from an environment's live deployment release."),
231
223
  requiresActiveOrg: true
232
224
  }),
233
225
  command(["workflow", "start"], "Start a workflow.", {
@@ -294,10 +286,7 @@ const RAW_CLI_COMMANDS = [
294
286
  command(["release", "create"], "Create an immutable release artifact from source files; this mutates Platform state and is not a test command.", {
295
287
  labels: ["write", "chat-write", "release"],
296
288
  args: [arg("workspace", "Path to the source folder or zip archive.")],
297
- flags: [flag("label", "Human label for the release.", {
298
- acceptsValue: true,
299
- valueType: "string"
300
- })],
289
+ flags: [],
301
290
  requiresActiveOrg: true
302
291
  }),
303
292
  command(["release", "validate"], "Validate release readiness without deploying.", {
@@ -701,55 +690,72 @@ const RAW_CLI_COMMANDS = [
701
690
  requiresActiveOrg: true
702
691
  }),
703
692
  command(["org-model", "people", "list"], "List modeled people.", {
693
+ flags: releaseSnapshotReadFlags("Read modeled people from a release.", "Read modeled people from an environment's live deployment release."),
704
694
  labels: ["read", "org-model"], requiresActiveOrg: true
705
695
  }),
706
696
  command(["org-model", "people", "get"], "Show one modeled person.", {
707
697
  labels: ["read", "org-model"],
708
698
  args: [arg("name", "Person name.")],
699
+ flags: releaseSnapshotReadFlags("Read modeled person detail from a release.", "Read modeled person detail from an environment's live deployment release."),
709
700
  requiresActiveOrg: true
710
701
  }),
711
702
  command(["org-model", "agents", "list"], "List modeled agents.", {
712
- labels: ["read", "org-model"], requiresActiveOrg: true
703
+ flags: releaseSnapshotReadFlags("Read modeled agents from a release.", "Read modeled agents from an environment's live deployment release."),
704
+ labels: ["read", "org-model"],
705
+ requiresActiveOrg: true
713
706
  }),
714
707
  command(["org-model", "agents", "get"], "Show one modeled agent.", {
715
708
  labels: ["read", "org-model"],
716
709
  args: [arg("name", "Agent name.")],
710
+ flags: releaseSnapshotReadFlags("Read modeled agent detail from a release.", "Read modeled agent detail from an environment's live deployment release."),
717
711
  requiresActiveOrg: true
718
712
  }),
719
713
  command(["org-model", "roles", "list"], "List modeled roles.", {
720
- labels: ["read", "org-model"], requiresActiveOrg: true
714
+ flags: releaseSnapshotReadFlags("Read modeled roles from a release.", "Read modeled roles from an environment's live deployment release."),
715
+ labels: ["read", "org-model"],
716
+ requiresActiveOrg: true
721
717
  }),
722
718
  command(["org-model", "roles", "get"], "Show one modeled role.", {
723
719
  labels: ["read", "org-model"],
724
720
  args: [arg("name", "Role name.")],
721
+ flags: releaseSnapshotReadFlags("Read modeled role detail from a release.", "Read modeled role detail from an environment's live deployment release."),
725
722
  requiresActiveOrg: true
726
723
  }),
727
724
  command(["org-model", "assignments", "list"], "List modeled assignments.", {
728
- labels: ["read", "org-model"], requiresActiveOrg: true
725
+ flags: releaseSnapshotReadFlags("Read modeled assignments from a release.", "Read modeled assignments from an environment's live deployment release."),
726
+ labels: ["read", "org-model"],
727
+ requiresActiveOrg: true
729
728
  }),
730
729
  command(["org-model", "assignments", "get"], "Show one modeled assignment group by role.", {
731
730
  labels: ["read", "org-model"],
732
731
  args: [arg("role-name", "Role name.")],
732
+ flags: releaseSnapshotReadFlags("Read modeled assignment detail from a release.", "Read modeled assignment detail from an environment's live deployment release."),
733
733
  requiresActiveOrg: true
734
734
  }),
735
735
  command(["org-model", "capabilities", "list"], "List capabilities.", {
736
- labels: ["read", "org-model"], requiresActiveOrg: true
736
+ flags: releaseSnapshotReadFlags("Read capabilities from a release.", "Read capabilities from an environment's live deployment release."),
737
+ labels: ["read", "org-model"],
738
+ requiresActiveOrg: true
737
739
  }),
738
740
  command(["org-model", "capabilities", "get"], "Show one capability.", {
739
741
  labels: ["read", "org-model"],
740
742
  args: [arg("name", "Capability name.")],
743
+ flags: releaseSnapshotReadFlags("Read capability detail from a release.", "Read capability detail from an environment's live deployment release."),
741
744
  requiresActiveOrg: true
742
745
  }),
743
746
  command(["org-model", "operations", "list"], "List operations.", {
744
- labels: ["read", "org-model"], requiresActiveOrg: true
747
+ flags: releaseSnapshotReadFlags("Read operations from a release.", "Read operations from an environment's live deployment release."),
748
+ labels: ["read", "org-model"],
749
+ requiresActiveOrg: true
745
750
  }),
746
751
  command(["org-model", "operations", "get"], "Show one operation.", {
747
752
  labels: ["read", "org-model"],
748
753
  args: [arg("name", "Operation name.")],
754
+ flags: releaseSnapshotReadFlags("Read operation detail from a release.", "Read operation detail from an environment's live deployment release."),
749
755
  requiresActiveOrg: true
750
756
  }),
751
757
  command(["access", "members", "list"], "List organization members.", {
752
- labels: ["read", "access"],
758
+ labels: ["read", "chat-read", "access"],
753
759
  flags: [
754
760
  flag("limit", "Maximum number of members to return.", {
755
761
  acceptsValue: true,
@@ -764,7 +770,7 @@ const RAW_CLI_COMMANDS = [
764
770
  requiresActiveOrg: true
765
771
  }),
766
772
  command(["access", "members", "get"], "Show one organization member.", {
767
- labels: ["read", "access"],
773
+ labels: ["read", "chat-read", "access"],
768
774
  args: [arg("user-id", "User id.")],
769
775
  requiresActiveOrg: true
770
776
  }),
@@ -787,7 +793,7 @@ const RAW_CLI_COMMANDS = [
787
793
  requiresActiveOrg: true
788
794
  }),
789
795
  command(["access", "invites", "list"], "List organization invites.", {
790
- labels: ["read", "access"],
796
+ labels: ["read", "chat-read", "access"],
791
797
  flags: [
792
798
  flag("limit", "Maximum number of invites to return.", {
793
799
  acceptsValue: true,
@@ -802,12 +808,12 @@ const RAW_CLI_COMMANDS = [
802
808
  requiresActiveOrg: true
803
809
  }),
804
810
  command(["access", "invites", "get"], "Show one organization invite.", {
805
- labels: ["read", "access"],
811
+ labels: ["read", "chat-read", "access"],
806
812
  args: [arg("invite-id", "Invite id.")],
807
813
  requiresActiveOrg: true
808
814
  }),
809
815
  command(["access", "invites", "create"], "Create an organization invite.", {
810
- labels: ["write", "access"],
816
+ labels: ["write", "chat-write", "access"],
811
817
  flags: [
812
818
  flag("email", "Invitee email address.", {
813
819
  acceptsValue: true,
@@ -870,7 +876,7 @@ const RAW_CLI_COMMANDS = [
870
876
  requiresActiveOrg: true
871
877
  }),
872
878
  command(["extensions", "validate"], "Validate an extension package directory or archive-expanded root.", {
873
- labels: ["read", "extension"],
879
+ labels: ["read", "chat-read", "extension"],
874
880
  args: [arg("path", "Path to an extension package directory.")],
875
881
  flags: [
876
882
  flag("subdir", "Validate a subdirectory from a zip archive.", {
@@ -913,7 +919,7 @@ const RAW_CLI_COMMANDS = [
913
919
  requiresActiveOrg: true
914
920
  }),
915
921
  command(["extensions", "publish"], "Publish a validated extension package revision.", {
916
- labels: ["write", "extension"],
922
+ labels: ["write", "chat-write", "extension"],
917
923
  args: [arg("path", "Path to an extension package directory.")],
918
924
  flags: [
919
925
  flag("subdir", "Publish a subdirectory from a zip archive.", {
@@ -1101,6 +1107,23 @@ const RAW_CLI_COMMANDS = [
1101
1107
  })],
1102
1108
  requiresActiveOrg: true
1103
1109
  }),
1110
+ command(["env", "set"], "Create or update one runtime variable without reading other values.", {
1111
+ labels: ["write", "chat-write", "env"],
1112
+ args: [arg("name", "Variable name.")],
1113
+ flags: [
1114
+ flag("environment", "Target environment.", {
1115
+ acceptsValue: true,
1116
+ required: true,
1117
+ valueType: "string"
1118
+ }),
1119
+ flag("value", "Variable value.", {
1120
+ acceptsValue: true,
1121
+ required: true,
1122
+ valueType: "string"
1123
+ })
1124
+ ],
1125
+ requiresActiveOrg: true
1126
+ }),
1104
1127
  command(["env", "replace"], "Replace the full runtime environment from JSON.", {
1105
1128
  labels: ["destructive", "env"],
1106
1129
  destructive: true,
@@ -1119,16 +1142,6 @@ const RAW_CLI_COMMANDS = [
1119
1142
  ],
1120
1143
  requiresActiveOrg: true
1121
1144
  }),
1122
- command(["env", "import"], "Import runtime variables from a .env file.", {
1123
- labels: ["write", "env"],
1124
- args: [arg("path-to-.env", "Path to a .env file.")],
1125
- flags: [flag("environment", "Target environment.", {
1126
- acceptsValue: true,
1127
- required: true,
1128
- valueType: "string"
1129
- })],
1130
- requiresActiveOrg: true
1131
- }),
1132
1145
  command(["secrets", "list"], "List organization secret names without values.", {
1133
1146
  labels: ["read", "secret"],
1134
1147
  flags: [flag("environment", "Target environment.", {
package/dist/commands.js CHANGED
@@ -3,10 +3,10 @@ import { executeAuthLogin, executeAuthLogout, executeAuthSignup, executeAuthWhoa
3
3
  import { getCliSchema, listCliSchemas } from "./schema-registry.js";
4
4
  import { createPlatformApiClient } from "./api-client.js";
5
5
  import { authProblem, genericProblem, notFoundProblem, usageProblem } from "./cli-errors.js";
6
- import { readOptionalNumberFlag, readOptionalStringFlag, readRequiredStringFlag } from "./command-flags.js";
6
+ import { readOptionalNumberFlag, readOptionalStringFlag, readRequiredStringFlag, readRequiredStringFlagPreservingEmpty } from "./command-flags.js";
7
7
  import { executeArtifactDownload, executeArtifactArchive, executeArtifactInspect, executeArtifactInventory, executeArtifactList, executeArtifactPurge, executeArtifactRead, executeArtifactRestore, executeArtifactUpload } from "./artifact-commands.js";
8
8
  import { executeAudit } from "./audit-commands.js";
9
- import { isZipArchivePath, readArchiveBytes, readImportEntries, readJsonInputSpecifier, readWorkspaceTestEntries, readTextInputSpecifier, parseEnvFile, writeReleaseSourceFiles } from "./files.js";
9
+ import { isZipArchivePath, readArchiveBytes, readImportEntries, readJsonInputSpecifier, readWorkspaceTestEntries, readTextInputSpecifier, writeReleaseSourceFiles } from "./files.js";
10
10
  import { renderDiffSummary, renderKeyValue, renderPrettyJson, renderSuccess, renderTable } from "./format.js";
11
11
  import { buildTaskDetailPresentation } from "./task-detail.js";
12
12
  import { confirmDestructive } from "./interaction.js";
@@ -164,8 +164,8 @@ export async function executeParsedCommand(parsed, context) {
164
164
  return executeExtensions(parsed, context, api, resolveOrgScope);
165
165
  case "env.list":
166
166
  case "env.get":
167
+ case "env.set":
167
168
  case "env.replace":
168
- case "env.import":
169
169
  return executeEnv(parsed, context, api);
170
170
  case "secrets.list":
171
171
  case "secrets.set":
@@ -422,58 +422,98 @@ async function executeActivityOptions(parsed, context, api) {
422
422
  meta: { command: "activity options", orgId: org.id }
423
423
  };
424
424
  }
425
+ function readOptionalReleaseSnapshotSelector(parsed) {
426
+ const releaseId = readOptionalStringFlag(parsed, "release");
427
+ const environment = readCliEnvironmentFlag(parsed);
428
+ if (releaseId && environment) {
429
+ throw usageProblem("Use either --release or --environment, not both.", parsed.definition.id);
430
+ }
431
+ if (releaseId) {
432
+ return { releaseId };
433
+ }
434
+ if (environment) {
435
+ return { environment };
436
+ }
437
+ return undefined;
438
+ }
439
+ function readRequiredReleaseSnapshotSelector(parsed) {
440
+ const selector = readOptionalReleaseSnapshotSelector(parsed);
441
+ if (!selector) {
442
+ throw usageProblem("Provide either --release or --environment.", parsed.definition.id);
443
+ }
444
+ return selector;
445
+ }
446
+ function releaseSnapshotSelectorMeta(selector) {
447
+ if (!selector) {
448
+ return {};
449
+ }
450
+ if (typeof selector.releaseId === "string") {
451
+ return { releaseId: selector.releaseId };
452
+ }
453
+ if (typeof selector.environment === "string") {
454
+ return { environment: selector.environment };
455
+ }
456
+ return {};
457
+ }
425
458
  async function executeWorkflowList(parsed, context, api) {
426
459
  const { org, session } = await resolveOrgScope(parsed, context, api);
427
- const data = await api.listWorkflows(session, org.id, readOptionalStringFlag(parsed, "release"));
460
+ const selector = readOptionalReleaseSnapshotSelector(parsed);
461
+ const data = await api.listWorkflows(session, org.id, selector ?? { live: true });
428
462
  return {
429
463
  data,
430
464
  human: renderTable(data.processes, [
431
465
  { key: "name", label: "Name" },
466
+ { key: "environmentKey", label: "Environment" },
467
+ { key: "liveReleaseId", label: "Live release" },
432
468
  { key: "latestVersion", label: "Latest" },
433
469
  { key: "deployedVersion", label: "Deployed" }
434
470
  ]),
435
471
  kind: "authoring_workflow_list",
436
- meta: { command: "workflow list", orgId: org.id }
472
+ meta: { command: "workflow list", orgId: org.id, ...releaseSnapshotSelectorMeta(selector) }
437
473
  };
438
474
  }
439
475
  async function executeWorkflowGet(parsed, context, api) {
440
476
  const { org, session } = await resolveOrgScope(parsed, context, api);
441
- const data = await api.getWorkflow(session, org.id, readRequiredArg(parsed, "name"), readOptionalStringFlag(parsed, "release"));
477
+ const selector = readRequiredReleaseSnapshotSelector(parsed);
478
+ const data = await api.getWorkflow(session, org.id, readRequiredArg(parsed, "name"), selector);
442
479
  return {
443
480
  data,
444
481
  human: renderPrettyJson(data.process),
445
482
  kind: "authoring_workflow_get",
446
- meta: { command: "workflow get", orgId: org.id }
483
+ meta: { command: "workflow get", orgId: org.id, ...releaseSnapshotSelectorMeta(selector) }
447
484
  };
448
485
  }
449
486
  async function executeWorkflowVersionGet(parsed, context, api) {
450
487
  const { org, session } = await resolveOrgScope(parsed, context, api);
451
- const data = await api.getWorkflowVersion(session, org.id, readRequiredArg(parsed, "name"), readRequiredIntegerArg(parsed, "version"), readOptionalStringFlag(parsed, "release"));
488
+ const selector = readRequiredReleaseSnapshotSelector(parsed);
489
+ const data = await api.getWorkflowVersion(session, org.id, readRequiredArg(parsed, "name"), readRequiredIntegerArg(parsed, "version"), selector);
452
490
  return {
453
491
  data,
454
492
  human: renderPrettyJson(data.process),
455
493
  kind: "authoring_workflow_version_get",
456
- meta: { command: "workflow version get", orgId: org.id }
494
+ meta: { command: "workflow version get", orgId: org.id, ...releaseSnapshotSelectorMeta(selector) }
457
495
  };
458
496
  }
459
497
  async function executeWorkflowDependencies(parsed, context, api) {
460
498
  const { org, session } = await resolveOrgScope(parsed, context, api);
461
- const data = await api.getWorkflowDependencies(session, org.id, readRequiredArg(parsed, "name"), readRequiredIntegerArg(parsed, "version"), readOptionalStringFlag(parsed, "release"));
499
+ const selector = readRequiredReleaseSnapshotSelector(parsed);
500
+ const data = await api.getWorkflowDependencies(session, org.id, readRequiredArg(parsed, "name"), readRequiredIntegerArg(parsed, "version"), selector);
462
501
  return {
463
502
  data,
464
503
  human: renderPrettyJson(data.dependencies),
465
504
  kind: "authoring_workflow_dependencies",
466
- meta: { command: "workflow dependencies", orgId: org.id }
505
+ meta: { command: "workflow dependencies", orgId: org.id, ...releaseSnapshotSelectorMeta(selector) }
467
506
  };
468
507
  }
469
508
  async function executeWorkflowContext(parsed, context, api) {
470
509
  const { org, session } = await resolveOrgScope(parsed, context, api);
471
- const data = await api.getWorkflowContext(session, org.id, readOptionalStringFlag(parsed, "release"));
510
+ const selector = readRequiredReleaseSnapshotSelector(parsed);
511
+ const data = await api.getWorkflowContext(session, org.id, selector);
472
512
  return {
473
513
  data,
474
514
  human: renderPrettyJson(data.context),
475
515
  kind: "authoring_workflow_context",
476
- meta: { command: "workflow context", orgId: org.id }
516
+ meta: { command: "workflow context", orgId: org.id, ...releaseSnapshotSelectorMeta(selector) }
477
517
  };
478
518
  }
479
519
  async function executeWorkflowStart(parsed, context, api) {
@@ -484,7 +524,7 @@ async function executeWorkflowStart(parsed, context, api) {
484
524
  }
485
525
  const inputSpecifier = readOptionalStringFlag(parsed, "input");
486
526
  const inputData = inputSpecifier
487
- ? await readJsonInputSpecifier(inputSpecifier, context.stdin, "workflow start")
527
+ ? await readJsonInputSpecifier(inputSpecifier, context.stdin, "workflow start", { flag: "input" })
488
528
  : undefined;
489
529
  const workflowName = readRequiredArg(parsed, "name");
490
530
  const resolvedEnvironment = resolveCliEnvironment(parsed, session);
@@ -514,7 +554,7 @@ async function executeWorkflowNodeTest(parsed, context, api) {
514
554
  const environment = readOptionalStringFlag(parsed, "environment");
515
555
  const inputSpecifier = readOptionalStringFlag(parsed, "input");
516
556
  const inputData = inputSpecifier
517
- ? await readJsonInputSpecifier(inputSpecifier, context.stdin, "test node")
557
+ ? await readJsonInputSpecifier(inputSpecifier, context.stdin, "test node", { flag: "input" })
518
558
  : undefined;
519
559
  const data = await api.testWorkflowNode(session, org.id, workflowName, nodeId, {
520
560
  ...(environment ? { environment } : {}),
@@ -646,11 +686,8 @@ async function executeReleaseSource(parsed, context, api) {
646
686
  async function executeReleaseCreate(parsed, context, api) {
647
687
  const { org, session } = await resolveOrgScope(parsed, context, api);
648
688
  const workspacePath = readRequiredArg(parsed, "workspace");
649
- const label = readOptionalStringFlag(parsed, "label");
650
689
  if (isZipArchivePath(workspacePath)) {
651
- const data = await api.createReleaseArchive(session, org.id, await readArchiveBytes(workspacePath, "release create"), {
652
- ...(label ? { label } : {})
653
- });
690
+ const data = await api.createReleaseArchive(session, org.id, await readArchiveBytes(workspacePath, "release create"));
654
691
  const summary = summarizeReleaseCreation(data.created.release.id);
655
692
  return {
656
693
  data,
@@ -661,8 +698,7 @@ async function executeReleaseCreate(parsed, context, api) {
661
698
  }
662
699
  const files = await readImportEntries(workspacePath);
663
700
  const data = await api.createRelease(session, org.id, {
664
- files,
665
- ...(label ? { label } : {})
701
+ files
666
702
  });
667
703
  const summary = summarizeReleaseCreation(data.created.release.id);
668
704
  return {
@@ -703,7 +739,7 @@ async function executeEnvironment(parsed, context, api) {
703
739
  const data = await api.getEnvironment(session, org.id, readRequiredArg(parsed, "environment"));
704
740
  return {
705
741
  data,
706
- human: renderPrettyJson(data.environment),
742
+ human: renderPrettyJson(data),
707
743
  kind: "environment_get",
708
744
  meta: { command: "environment get", orgId: org.id }
709
745
  };
@@ -943,7 +979,7 @@ async function executeTaskGet(parsed, context, api) {
943
979
  }
944
980
  async function executeTaskComplete(parsed, context, api) {
945
981
  const { org, session } = await resolveOrgScope(parsed, context, api);
946
- const outputData = await readJsonInputSpecifier(String(parsed.flags.output), context.stdin, "task complete");
982
+ const outputData = await readJsonInputSpecifier(String(parsed.flags.output), context.stdin, "task complete", { flag: "output" });
947
983
  const data = await api.completeTask(session, org.id, readRequiredArg(parsed, "task-id"), {
948
984
  outputData,
949
985
  workflowId: String(parsed.flags.run)
@@ -959,8 +995,9 @@ async function executeOrgModel(parsed, context, api) {
959
995
  const { org, session } = await resolveOrgScope(parsed, context, api);
960
996
  const section = parsed.definition.path[1] ?? "";
961
997
  const verb = parsed.definition.path[2] ?? "";
998
+ const selector = readRequiredReleaseSnapshotSelector(parsed);
962
999
  if (section === "operations") {
963
- const editor = (await api.getOperationsEditor(session, org.id)).editor;
1000
+ const editor = (await api.getOperationsEditor(session, org.id, selector)).editor;
964
1001
  const record = verb === "get"
965
1002
  ? requireFound(editor.operations.find((entry) => entry.name === parsed.args.name), `Operation '${parsed.args.name}' was not found.`, parsed.definition.id)
966
1003
  : undefined;
@@ -973,17 +1010,17 @@ async function executeOrgModel(parsed, context, api) {
973
1010
  { key: "command", label: "Command" }
974
1011
  ]),
975
1012
  kind: `authoring_${sanitizeKind(section)}_${verb}`,
976
- meta: { command: parsed.definition.path.join(" "), orgId: org.id }
1013
+ meta: { command: parsed.definition.path.join(" "), orgId: org.id, ...releaseSnapshotSelectorMeta(selector) }
977
1014
  };
978
1015
  }
979
- const management = (await api.getOrganizationManagementContext(session, org.id)).context;
1016
+ const management = (await api.getOrganizationManagementContext(session, org.id, selector)).context;
980
1017
  if (section === "capabilities" && verb === "get") {
981
- const detail = await api.getCapabilityEditor(session, org.id, readRequiredArg(parsed, "name"));
1018
+ const detail = await api.getCapabilityEditor(session, org.id, readRequiredArg(parsed, "name"), selector);
982
1019
  return {
983
1020
  data: detail,
984
1021
  human: renderPrettyJson(detail.editor),
985
1022
  kind: "authoring_capabilities_get",
986
- meta: { command: parsed.definition.path.join(" "), orgId: org.id }
1023
+ meta: { command: parsed.definition.path.join(" "), orgId: org.id, ...releaseSnapshotSelectorMeta(selector) }
987
1024
  };
988
1025
  }
989
1026
  const selection = selectOrgModelSection(management, section, verb === "get" ? parsed.args[section === "assignments" ? "role-name" : "name"] : undefined);
@@ -991,7 +1028,7 @@ async function executeOrgModel(parsed, context, api) {
991
1028
  data: selection.data,
992
1029
  human: selection.human,
993
1030
  kind: `authoring_${sanitizeKind(section)}_${verb}`,
994
- meta: { command: parsed.definition.path.join(" "), orgId: org.id }
1031
+ meta: { command: parsed.definition.path.join(" "), orgId: org.id, ...releaseSnapshotSelectorMeta(selector) }
995
1032
  };
996
1033
  }
997
1034
  async function executeAccess(parsed, context, api) {
@@ -1188,9 +1225,32 @@ async function executeEnv(parsed, context, api) {
1188
1225
  meta: { command: parsed.definition.path.join(" "), environment, orgId: org.id }
1189
1226
  };
1190
1227
  }
1228
+ case "env.set": {
1229
+ const environment = readRequiredCliEnvironmentFlag(parsed);
1230
+ const name = readRequiredArg(parsed, "name");
1231
+ announceResolvedEnvironment(parsed, context, environment);
1232
+ const data = await api.upsertRuntimeVariable(session, org.id, {
1233
+ environment,
1234
+ name,
1235
+ value: readRequiredStringFlagPreservingEmpty(parsed, "value")
1236
+ });
1237
+ return {
1238
+ data: {
1239
+ variable: {
1240
+ environmentKey: data.variable.environmentKey,
1241
+ name: data.variable.name,
1242
+ status: "defined",
1243
+ updatedAt: data.variable.updatedAt
1244
+ }
1245
+ },
1246
+ human: renderSuccess(`Saved runtime variable '${data.variable.name}' in ${environment}.`),
1247
+ kind: "authoring_env_set",
1248
+ meta: { command: parsed.definition.path.join(" "), environment, orgId: org.id }
1249
+ };
1250
+ }
1191
1251
  case "env.replace": {
1192
1252
  const environment = readRequiredCliEnvironmentFlag(parsed);
1193
- const body = await readJsonInputSpecifier(String(parsed.flags.file), context.stdin, parsed.definition.id);
1253
+ const body = await readJsonInputSpecifier(String(parsed.flags.file), context.stdin, parsed.definition.id, { flag: "file" });
1194
1254
  const rawVariables = body.variables;
1195
1255
  if (!Array.isArray(rawVariables)) {
1196
1256
  throw usageProblem("Environment replace payload must contain a variables array.", parsed.definition.id);
@@ -1224,24 +1284,6 @@ async function executeEnv(parsed, context, api) {
1224
1284
  meta: { command: parsed.definition.path.join(" "), environment, orgId: org.id }
1225
1285
  };
1226
1286
  }
1227
- case "env.import": {
1228
- const environment = readRequiredCliEnvironmentFlag(parsed);
1229
- const filePath = readRequiredArg(parsed, "path-to-.env");
1230
- const content = await readTextInputSpecifier(`@${filePath}`, context.stdin, parsed.definition.id);
1231
- const preview = await parseEnvFile(filePath);
1232
- announceResolvedEnvironment(parsed, context, environment);
1233
- const data = await api.importRuntimeVariables(session, org.id, {
1234
- content,
1235
- environment,
1236
- fileName: filePath
1237
- });
1238
- return {
1239
- data,
1240
- human: renderSuccess(`Imported ${data.importedCount} variables from ${filePath} into ${environment}. Parsed ${preview.length}.`),
1241
- kind: "authoring_env_import",
1242
- meta: { command: parsed.definition.path.join(" "), environment, orgId: org.id }
1243
- };
1244
- }
1245
1287
  default:
1246
1288
  throw genericProblem(`Unhandled env command ${parsed.definition.id}.`, parsed.definition.id);
1247
1289
  }
@@ -0,0 +1,2 @@
1
+ export declare function normalizePublicErrorCode(code: string): string;
2
+ export declare function readPublicErrorCodeFromType(type: string): string;
@@ -0,0 +1,9 @@
1
+ const PUBLIC_ERROR_CODE_PATTERN = /^[a-z][a-z0-9_]*(?:\/[a-z][a-z0-9_]*)?$/u;
2
+ export function normalizePublicErrorCode(code) {
3
+ return PUBLIC_ERROR_CODE_PATTERN.test(code) ? code : "internal/error";
4
+ }
5
+ export function readPublicErrorCodeFromType(type) {
6
+ return type.startsWith("https://errors.kora.dev/")
7
+ ? type.slice("https://errors.kora.dev/".length)
8
+ : "internal/error";
9
+ }
@@ -54,7 +54,7 @@ export async function executeExtensions(parsed, context, api, resolveOrgScope) {
54
54
  ? await api.validateExtensionPackageArchive(session, org.id, await readArchiveBytes(path, parsed.definition.id), {
55
55
  ...(subdir ? { subdir } : {})
56
56
  })
57
- : await api.validateExtensionPackage(session, org.id, { files: await readPackageFileEntries(path) });
57
+ : await api.validateExtensionPackage(session, org.id, { files: await readPackageFileEntries(path, parsed.definition.id) });
58
58
  return {
59
59
  data,
60
60
  exitCode: data.ok ? 0 : 1,
@@ -70,7 +70,7 @@ export async function executeExtensions(parsed, context, api, resolveOrgScope) {
70
70
  ? await api.publishExtensionPackageArchive(session, org.id, await readArchiveBytes(path, parsed.definition.id), {
71
71
  ...(subdir ? { subdir } : {})
72
72
  })
73
- : await api.publishExtensionPackage(session, org.id, { files: await readPackageFileEntries(path) });
73
+ : await api.publishExtensionPackage(session, org.id, { files: await readPackageFileEntries(path, parsed.definition.id) });
74
74
  return {
75
75
  data,
76
76
  human: renderSuccess(`Published extension ${data.package.name} revision ${data.revision.id}.`),
@@ -395,11 +395,11 @@ async function readOptionalPermissions(parsed, context) {
395
395
  if (!specifier) {
396
396
  return undefined;
397
397
  }
398
- return normalizePermissions(await readJsonInputSpecifier(specifier, context.stdin, parsed.definition.id), parsed.definition.id);
398
+ return normalizePermissions(await readJsonInputSpecifier(specifier, context.stdin, parsed.definition.id, { flag: "permissions" }), parsed.definition.id);
399
399
  }
400
400
  async function readRequiredPermissions(parsed, context) {
401
401
  const specifier = readRequiredStringFlag(parsed, "permissions");
402
- return normalizePermissions(await readJsonInputSpecifier(specifier, context.stdin, parsed.definition.id), parsed.definition.id);
402
+ return normalizePermissions(await readJsonInputSpecifier(specifier, context.stdin, parsed.definition.id, { flag: "permissions" }), parsed.definition.id);
403
403
  }
404
404
  function normalizePermissions(input, instance) {
405
405
  const permissions = input.grantedPermissions && isRecord(input.grantedPermissions)
package/dist/files.d.ts CHANGED
@@ -1,5 +1,9 @@
1
+ import { Buffer } from "node:buffer";
1
2
  import type { Readable } from "node:stream";
2
- export declare function readJsonInputSpecifier(specifier: string, stdin: Readable, instance: string): Promise<Record<string, unknown>>;
3
+ interface ReadStructuredInputOptions {
4
+ flag?: string;
5
+ }
6
+ export declare function readJsonInputSpecifier(specifier: string, stdin: Readable, instance: string, options?: ReadStructuredInputOptions): Promise<Record<string, unknown>>;
3
7
  export declare function readTextInputSpecifier(specifier: string, stdin: Readable, instance: string): Promise<string>;
4
8
  export declare function readImportEntries(pathValue: string): Promise<Array<{
5
9
  content: string;
@@ -7,6 +11,12 @@ export declare function readImportEntries(pathValue: string): Promise<Array<{
7
11
  }>>;
8
12
  export declare function isZipArchivePath(pathValue: string): boolean;
9
13
  export declare function readArchiveBytes(pathValue: string, instance: string): Promise<Uint8Array>;
14
+ export declare function readLocalFileBytes(pathValue: string, instance: string, options?: {
15
+ regularFileMessage?: string;
16
+ }): Promise<{
17
+ absolutePath: string;
18
+ bytes: Buffer;
19
+ }>;
10
20
  export declare function readWorkspaceTestEntries(pathValue: string): Promise<Array<{
11
21
  content: string;
12
22
  path: string;
@@ -34,11 +44,8 @@ export declare function writePackageExport(outPath: string, envelope: {
34
44
  }>;
35
45
  metadata: Record<string, unknown>;
36
46
  }): Promise<void>;
37
- export declare function readPackageFileEntries(pathValue: string): Promise<Array<{
47
+ export declare function readPackageFileEntries(pathValue: string, instance: string): Promise<Array<{
38
48
  contentBase64: string;
39
49
  path: string;
40
50
  }>>;
41
- export declare function parseEnvFile(pathValue: string): Promise<Array<{
42
- name: string;
43
- value: string;
44
- }>>;
51
+ export {};