@pmate/cli 0.21.5 → 0.21.7

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/index.d.ts CHANGED
@@ -693,6 +693,72 @@ type ServiceCommandArgs = {
693
693
  history: boolean;
694
694
  search?: string;
695
695
  follow: boolean;
696
+ } | {
697
+ type: Command.Service;
698
+ action: "env-list";
699
+ appId: string;
700
+ scope?: string;
701
+ includeSecretMeta: boolean;
702
+ includeSecretValue: boolean;
703
+ baseUrl?: string;
704
+ json: boolean;
705
+ } | {
706
+ type: Command.Service;
707
+ action: "env-get";
708
+ appId: string;
709
+ key: string;
710
+ scope: string;
711
+ includeSecretValue: boolean;
712
+ baseUrl?: string;
713
+ json: boolean;
714
+ } | {
715
+ type: Command.Service;
716
+ action: "env-set";
717
+ appId: string;
718
+ key: string;
719
+ value?: string;
720
+ scope: string;
721
+ secret: boolean;
722
+ prompt: boolean;
723
+ baseUrl?: string;
724
+ json: boolean;
725
+ } | {
726
+ type: Command.Service;
727
+ action: "env-unset";
728
+ appId: string;
729
+ key: string;
730
+ scope: string;
731
+ baseUrl?: string;
732
+ json: boolean;
733
+ } | {
734
+ type: Command.Service;
735
+ action: "env-resolve";
736
+ appId: string;
737
+ stage: "dev" | "preview" | "prod";
738
+ branch?: string;
739
+ includeSecretValue: boolean;
740
+ baseUrl?: string;
741
+ json: boolean;
742
+ } | {
743
+ type: Command.Service;
744
+ action: "env-pull";
745
+ appId: string;
746
+ stage: "dev" | "preview" | "prod";
747
+ branch?: string;
748
+ output: string;
749
+ baseUrl?: string;
750
+ json: boolean;
751
+ } | {
752
+ type: Command.Service;
753
+ action: "env-copy-from";
754
+ targetAppId: string;
755
+ sourceAppId: string;
756
+ scope?: string;
757
+ includeSecret: boolean;
758
+ overwrite: boolean;
759
+ onlyKeys?: string[];
760
+ baseUrl?: string;
761
+ json: boolean;
696
762
  };
697
763
  type VercelProjectsCommandArgs = {
698
764
  type: Command.Vercel;
package/dist/index.js CHANGED
@@ -11660,7 +11660,7 @@ var PrepareDevCommandHandler = class {
11660
11660
  this.renderOpen(result2, args.json);
11661
11661
  return result2;
11662
11662
  }
11663
- const result = await this.closeEnvironment(args.repo, args.envIndex, envRoot);
11663
+ const result = await this.closeEnvironment(args.repo, args.envIndex, envRoot, baseRoot);
11664
11664
  this.renderClose(result, args.json);
11665
11665
  return result;
11666
11666
  }
@@ -11732,9 +11732,10 @@ var PrepareDevCommandHandler = class {
11732
11732
  }
11733
11733
  throw new Error(`No available dev environment found for ${repo} under ${envRoot}`);
11734
11734
  }
11735
- async closeEnvironment(repo, envIndex, envRoot) {
11735
+ async closeEnvironment(repo, envIndex, envRoot, baseRoot) {
11736
11736
  const envPath = import_node_path10.default.join(envRoot, `${repo}-${envIndex}`);
11737
11737
  const lockPath = import_node_path10.default.join(envPath, LOCK_FILE_NAME);
11738
+ const baseRepoPath = import_node_path10.default.join(baseRoot, repo);
11738
11739
  if (!await this.pathExists(envPath) || !await this.pathExists(import_node_path10.default.join(envPath, ".git"))) {
11739
11740
  throw new Error(`Dev environment not found: ${envPath}`);
11740
11741
  }
@@ -11744,6 +11745,7 @@ var PrepareDevCommandHandler = class {
11744
11745
  `Cannot close ${repo}-${envIndex}: local changes detected. Commit or clean the worktree first.`
11745
11746
  );
11746
11747
  }
11748
+ const baseRepoSync = await this.syncBaseRepo(baseRepoPath);
11747
11749
  const removedLock = await this.removeLock(lockPath);
11748
11750
  return {
11749
11751
  action: "close",
@@ -11751,7 +11753,9 @@ var PrepareDevCommandHandler = class {
11751
11753
  envIndex,
11752
11754
  envPath,
11753
11755
  lockPath,
11754
- removedLock
11756
+ removedLock,
11757
+ baseRepoPath,
11758
+ baseRepoSync
11755
11759
  };
11756
11760
  }
11757
11761
  resolveRoot(input, fallbackSegments) {
@@ -11766,6 +11770,33 @@ var PrepareDevCommandHandler = class {
11766
11770
  throw new Error(`Expected ${cwd} to be on main, got ${branch || "(detached)"}`);
11767
11771
  }
11768
11772
  }
11773
+ async syncBaseRepo(baseRepoPath) {
11774
+ if (!await this.pathExists(baseRepoPath) || !await this.pathExists(import_node_path10.default.join(baseRepoPath, ".git"))) {
11775
+ throw new Error(`Cannot close dev environment: base repo not found: ${baseRepoPath}`);
11776
+ }
11777
+ const origin = await this.safeGitOutput(baseRepoPath, ["remote", "get-url", "origin"]);
11778
+ if (!origin || this.isLocalOrigin(origin)) {
11779
+ throw new Error(
11780
+ `Cannot close dev environment: base repo has invalid origin: ${baseRepoPath}`
11781
+ );
11782
+ }
11783
+ const branch = await this.safeGitOutput(baseRepoPath, ["branch", "--show-current"]);
11784
+ if (branch !== "main") {
11785
+ throw new Error(
11786
+ `Cannot close dev environment: base repo must be on main before sync, got ${branch || "(detached)"}.`
11787
+ );
11788
+ }
11789
+ if (await this.hasUncommittedChanges(baseRepoPath)) {
11790
+ throw new Error(
11791
+ `Cannot close dev environment: base repo has local changes: ${baseRepoPath}`
11792
+ );
11793
+ }
11794
+ await this.runGit(["pull", "--ff-only"], baseRepoPath);
11795
+ return {
11796
+ attempted: true,
11797
+ updated: true
11798
+ };
11799
+ }
11769
11800
  async hasUncommittedChanges(cwd) {
11770
11801
  const status = await this.getGitOutput(cwd, ["status", "--porcelain"]);
11771
11802
  if (!status) {
@@ -11851,7 +11882,9 @@ var PrepareDevCommandHandler = class {
11851
11882
  }
11852
11883
  ui.success(`Closed ${result.repo}-${result.envIndex}`, {
11853
11884
  path: result.envPath,
11854
- lockRemoved: result.removedLock
11885
+ lockRemoved: result.removedLock,
11886
+ baseRepo: result.baseRepoPath,
11887
+ baseRepoSynced: result.baseRepoSync.updated
11855
11888
  });
11856
11889
  }
11857
11890
  };
@@ -15002,15 +15035,18 @@ var INTRO_MIN_LENGTHS = Object.freeze({
15002
15035
  var FIELD_RULES = Object.freeze({
15003
15036
  teachingArticle: Object.freeze({
15004
15037
  label: "teachingArticle\uFF08\u6559\u5B66\u77ED\u6587\uFF09",
15038
+ legacyLabel: "knowledgeSummary\uFF08\u77E5\u8BC6\u8BB2\u89E3\uFF09",
15005
15039
  defaultHint: "\u77E5\u8BC6\u8BB2\u89E3\u81F3\u5C11\u8981\u5148\u628A\u9898\u76EE\u524D\u63D0\u8BF4\u6E05\u695A\uFF0C\u518D\u8BA9\u7528\u6237\u53BB\u9009\u7B54\u6848\u3002",
15006
15040
  introHint: "\u5F00\u573A\u9898\u81F3\u5C11\u8981\u8BB2\u6E05\u5B83\u662F\u4EC0\u4E48\u3001\u89E3\u51B3\u4EC0\u4E48\u95EE\u9898\uFF0C\u4EE5\u53CA\u8BFB\u8005\u63A5\u4E0B\u6765\u8BE5\u5E26\u7740\u4EC0\u4E48\u7406\u89E3\u8DEF\u5F84\u7EE7\u7EED\u5F80\u4E0B\u770B\u3002"
15007
15041
  }),
15008
15042
  teachingTip: Object.freeze({
15009
15043
  label: "teachingTip\uFF08\u8865\u5145\u8BF4\u660E\uFF09",
15044
+ legacyLabel: "knowledgeNote\uFF08\u8865\u5145\u8BF4\u660E\uFF09",
15010
15045
  introHint: "\u5F00\u573A\u9898\u8981\u8865\u5145\u4E3A\u4EC0\u4E48\u5BB9\u6613\u8BEF\u89E3\uFF0C\u6216\u8005\u7B2C\u4E00\u6B21\u8BFB\u8FD9\u5757\u5185\u5BB9\u65F6\u5E94\u8BE5\u5148\u770B\u54EA\u91CC\u3002"
15011
15046
  }),
15012
15047
  explanation: Object.freeze({
15013
15048
  label: "explanation\uFF08\u89E3\u6790\uFF09",
15049
+ legacyLabel: "explanation\uFF08\u89E3\u6790\uFF09",
15014
15050
  defaultHint: "\u89E3\u6790\u81F3\u5C11\u8981\u6309 3W+1H \u8BB2\u6E05 What\u3001Why\u3001Where\u3001How\uFF0C\u5E76\u8986\u76D6\u6B63\u786E\u539F\u56E0\u548C\u4E00\u4E2A\u5E38\u89C1\u8BEF\u533A\u3002",
15015
15051
  introHint: "\u89E3\u6790\u81F3\u5C11\u8981\u6309 3W+1H \u8BB2\u6E05 What\u3001Why\u3001Where\u3001How\uFF0C\u5E76\u8865\u4E0A\u6B63\u786E\u539F\u56E0\u3001\u4E00\u4E2A\u5E38\u89C1\u8BEF\u533A\uFF0C\u4EE5\u53CA\u5B83\u548C\u5F53\u524D\u4E0A\u4E0B\u6587\u7684\u5177\u4F53\u5173\u7CFB\u3002"
15016
15052
  })
@@ -15025,14 +15061,47 @@ function formatStepLabel(step, index) {
15025
15061
  const stepId = String(step?.stepId || `step-${index + 1}`);
15026
15062
  return `\u7B2C ${index + 1} \u9898\uFF08${stepId}\uFF09`;
15027
15063
  }
15064
+ function getFieldValue(step, field) {
15065
+ if (field === "teachingArticle") {
15066
+ return step.teachingArticle ?? step.knowledgeSummary;
15067
+ }
15068
+ if (field === "teachingTip") {
15069
+ return step.teachingTip ?? step.knowledgeNote;
15070
+ }
15071
+ return step[field];
15072
+ }
15073
+ function getFieldLabel(step, field) {
15074
+ const fieldRule = FIELD_RULES[field];
15075
+ if (field === "teachingArticle" && step.teachingArticle == null && step.knowledgeSummary != null) {
15076
+ return fieldRule.legacyLabel ?? "teachingArticle\uFF08\u6559\u5B66\u77ED\u6587\uFF09";
15077
+ }
15078
+ if (field === "teachingTip" && step.teachingTip == null && step.knowledgeNote != null) {
15079
+ return fieldRule.legacyLabel ?? "teachingTip\uFF08\u8865\u5145\u8BF4\u660E\uFF09";
15080
+ }
15081
+ return fieldRule.label;
15082
+ }
15083
+ function normalizeQuizStep(rawStep) {
15084
+ return {
15085
+ ...rawStep,
15086
+ conceptTitle: rawStep.conceptTitle ?? rawStep.knowledgeTitle,
15087
+ teachingArticle: rawStep.teachingArticle ?? rawStep.knowledgeSummary,
15088
+ teachingTip: rawStep.teachingTip ?? rawStep.knowledgeNote
15089
+ };
15090
+ }
15091
+ function normalizeQuizPaperPayloadDocument(payload) {
15092
+ const rawSteps = Array.isArray(payload.steps) ? payload.steps : [];
15093
+ return {
15094
+ ...payload,
15095
+ steps: rawSteps.map((step) => normalizeQuizStep(step ?? {}))
15096
+ };
15097
+ }
15028
15098
  function assertMinLength(step, index, field, minLength, hint) {
15029
- const currentLength = countMeaningfulChars(step?.[field]);
15099
+ const currentLength = countMeaningfulChars(getFieldValue(step, field));
15030
15100
  if (currentLength >= minLength) {
15031
15101
  return;
15032
15102
  }
15033
- const fieldRule = FIELD_RULES[field];
15034
15103
  throw new Error(
15035
- `${formatStepLabel(step, index)}\u7684${fieldRule.label}\u592A\u77ED\uFF0C\u81F3\u5C11\u9700\u8981${minLength}\u4E2A\u975E\u7A7A\u767D\u5B57\u7B26\uFF0C\u5F53\u524D\u53EA\u6709${currentLength}\u4E2A\u3002${hint}`
15104
+ `${formatStepLabel(step, index)}\u7684${getFieldLabel(step, field)}\u592A\u77ED\uFF0C\u81F3\u5C11\u9700\u8981${minLength}\u4E2A\u975E\u7A7A\u767D\u5B57\u7B26\uFF0C\u5F53\u524D\u53EA\u6709${currentLength}\u4E2A\u3002${hint}`
15036
15105
  );
15037
15106
  }
15038
15107
  function validateQuizPaperPayload(payload) {
@@ -15114,8 +15183,10 @@ async function publishQuizPaper({
15114
15183
  }) {
15115
15184
  const trimmedApiBaseUrl = apiBaseUrl.replace(/\/+$/, "");
15116
15185
  const trimmedLinkBaseUrl = linkBaseUrl.replace(/\/+$/, "");
15117
- const { steps = [], ...metadata } = payload ?? {};
15118
- validateQuizPaperPayload(payload);
15186
+ const rawPayload = payload ?? {};
15187
+ const normalizedPayload = normalizeQuizPaperPayloadDocument(rawPayload);
15188
+ const { steps = [], ...metadata } = normalizedPayload;
15189
+ validateQuizPaperPayload(rawPayload);
15119
15190
  await requestJson(
15120
15191
  fetchImpl,
15121
15192
  `${trimmedApiBaseUrl}/api/quiz/papers`,
@@ -15292,6 +15363,7 @@ async function appendQuizPaperStep({
15292
15363
  const trimmedApiBaseUrl = apiBaseUrl.replace(/\/+$/, "");
15293
15364
  const trimmedLinkBaseUrl = linkBaseUrl.replace(/\/+$/, "");
15294
15365
  const previewLink = `${trimmedLinkBaseUrl}/?paper=${encodeURIComponent(paperId)}`;
15366
+ const normalizedStep = normalizeQuizStep(step);
15295
15367
  const data = await requestJson(
15296
15368
  fetchImpl,
15297
15369
  `${trimmedApiBaseUrl}/api/quiz/papers/${encodeURIComponent(paperId)}/steps`,
@@ -15301,7 +15373,7 @@ async function appendQuizPaperStep({
15301
15373
  Authorization: `Bearer ${token}`,
15302
15374
  "Content-Type": "application/json"
15303
15375
  },
15304
- body: JSON.stringify(step)
15376
+ body: JSON.stringify(normalizedStep)
15305
15377
  },
15306
15378
  `\u8FFD\u52A0\u9898\u76EE\uFF08${String(step?.stepId ?? "unknown-step")}\uFF09`
15307
15379
  );
@@ -15324,6 +15396,7 @@ async function updateQuizPaperStep({
15324
15396
  const trimmedApiBaseUrl = apiBaseUrl.replace(/\/+$/, "");
15325
15397
  const trimmedLinkBaseUrl = linkBaseUrl.replace(/\/+$/, "");
15326
15398
  const previewLink = `${trimmedLinkBaseUrl}/?paper=${encodeURIComponent(paperId)}`;
15399
+ const normalizedStep = normalizeQuizStep(step);
15327
15400
  const data = await requestJson(
15328
15401
  fetchImpl,
15329
15402
  `${trimmedApiBaseUrl}/api/quiz/papers/${encodeURIComponent(paperId)}/steps/${encodeURIComponent(stepId)}`,
@@ -15333,7 +15406,7 @@ async function updateQuizPaperStep({
15333
15406
  Authorization: `Bearer ${token}`,
15334
15407
  "Content-Type": "application/json"
15335
15408
  },
15336
- body: JSON.stringify(step)
15409
+ body: JSON.stringify(normalizedStep)
15337
15410
  },
15338
15411
  `\u66F4\u65B0\u9898\u76EE\uFF08${stepId}\uFF09`
15339
15412
  );
@@ -17303,7 +17376,9 @@ function readNamespaceFromPayload(payload) {
17303
17376
 
17304
17377
  // src/commands/ServiceCommandHandler.ts
17305
17378
  var import_node_fs18 = require("fs");
17379
+ var import_promises5 = require("fs/promises");
17306
17380
  var import_node_path23 = __toESM(require("path"));
17381
+ var import_promises6 = require("readline/promises");
17307
17382
 
17308
17383
  // src/services/ServiceRuntimeRunner.ts
17309
17384
  var import_node_fs17 = require("fs");
@@ -18398,6 +18473,107 @@ var ServiceCommandHandler = class {
18398
18473
  });
18399
18474
  return;
18400
18475
  }
18476
+ case "env-list": {
18477
+ const payload = await this.request(
18478
+ baseUrl,
18479
+ "GET",
18480
+ this.buildEnvPath(args.appId, {
18481
+ scope: args.scope,
18482
+ includeSecretMeta: args.includeSecretMeta,
18483
+ includeSecretValue: args.includeSecretValue
18484
+ })
18485
+ );
18486
+ this.renderJson(payload, true);
18487
+ return;
18488
+ }
18489
+ case "env-get": {
18490
+ const payload = await this.request(
18491
+ baseUrl,
18492
+ "GET",
18493
+ `${this.buildEnvBasePath(args.appId)}/${encodeURIComponent(args.key)}?${new URLSearchParams({
18494
+ scope: args.scope,
18495
+ ...args.includeSecretValue ? { includeSecretValue: "true" } : {}
18496
+ }).toString()}`
18497
+ );
18498
+ this.renderJson(payload, true);
18499
+ return;
18500
+ }
18501
+ case "env-set": {
18502
+ const value = await this.resolveEnvValue(args);
18503
+ const payload = await this.request(
18504
+ baseUrl,
18505
+ "PUT",
18506
+ `${this.buildEnvBasePath(args.appId)}/${encodeURIComponent(args.key)}`,
18507
+ {
18508
+ value,
18509
+ scope: args.scope,
18510
+ kind: args.secret ? "secret" : "plain"
18511
+ }
18512
+ );
18513
+ ui.success(`Updated env ${args.key} for ${args.appId}`);
18514
+ this.renderJson(payload, args.json);
18515
+ return;
18516
+ }
18517
+ case "env-unset": {
18518
+ const payload = await this.request(
18519
+ baseUrl,
18520
+ "DELETE",
18521
+ `${this.buildEnvBasePath(args.appId)}/${encodeURIComponent(args.key)}?${new URLSearchParams({
18522
+ scope: args.scope
18523
+ }).toString()}`
18524
+ );
18525
+ ui.success(`Deleted env ${payload.key} (${payload.scope}) from ${args.appId}`);
18526
+ this.renderJson(payload, args.json);
18527
+ return;
18528
+ }
18529
+ case "env-resolve": {
18530
+ const payload = await this.request(
18531
+ baseUrl,
18532
+ "POST",
18533
+ `${this.buildEnvBasePath(args.appId)}/resolve`,
18534
+ {
18535
+ stage: args.stage,
18536
+ ...args.branch ? { branch: args.branch } : {},
18537
+ ...args.includeSecretValue ? { includeSecretValue: true } : {}
18538
+ }
18539
+ );
18540
+ this.renderJson(payload, true);
18541
+ return;
18542
+ }
18543
+ case "env-pull": {
18544
+ const payload = await this.request(
18545
+ baseUrl,
18546
+ "POST",
18547
+ `${this.buildEnvBasePath(args.appId)}/pull`,
18548
+ {
18549
+ stage: args.stage,
18550
+ ...args.branch ? { branch: args.branch } : {},
18551
+ format: "dotenv"
18552
+ }
18553
+ );
18554
+ const outputPath = import_node_path23.default.resolve(process.cwd(), args.output);
18555
+ await (0, import_promises5.writeFile)(outputPath, payload.content, "utf8");
18556
+ ui.success(`Wrote env file for ${args.appId} to ${outputPath}`);
18557
+ this.renderJson({ ...payload, output: outputPath }, args.json);
18558
+ return;
18559
+ }
18560
+ case "env-copy-from": {
18561
+ const payload = await this.request(
18562
+ baseUrl,
18563
+ "POST",
18564
+ `${this.buildEnvBasePath(args.targetAppId)}/copy-from`,
18565
+ {
18566
+ sourceAppId: args.sourceAppId,
18567
+ ...args.scope ? { scope: args.scope } : {},
18568
+ ...args.includeSecret ? { includeSecret: true } : {},
18569
+ ...args.overwrite ? { overwrite: true } : {},
18570
+ ...args.onlyKeys?.length ? { onlyKeys: args.onlyKeys } : {}
18571
+ }
18572
+ );
18573
+ ui.success(`Copied env items from ${args.sourceAppId} to ${args.targetAppId}`);
18574
+ this.renderJson(payload, args.json);
18575
+ return;
18576
+ }
18401
18577
  }
18402
18578
  }
18403
18579
  resolveBaseUrl(baseUrl) {
@@ -18437,6 +18613,44 @@ var ServiceCommandHandler = class {
18437
18613
  }
18438
18614
  return payload.data;
18439
18615
  }
18616
+ buildEnvBasePath(appId) {
18617
+ return `/apps/by-id/${encodeURIComponent(appId)}/env`;
18618
+ }
18619
+ buildEnvPath(appId, query) {
18620
+ const params = new URLSearchParams();
18621
+ if (query.scope) {
18622
+ params.set("scope", query.scope);
18623
+ }
18624
+ if (query.includeSecretMeta) {
18625
+ params.set("includeSecretMeta", "true");
18626
+ }
18627
+ if (query.includeSecretValue) {
18628
+ params.set("includeSecretValue", "true");
18629
+ }
18630
+ const qs = params.toString();
18631
+ return `${this.buildEnvBasePath(appId)}${qs ? `?${qs}` : ""}`;
18632
+ }
18633
+ async resolveEnvValue(args) {
18634
+ if (args.value !== void 0) {
18635
+ return args.value;
18636
+ }
18637
+ if (!args.prompt && !args.secret) {
18638
+ throw new Error("Missing env value. Pass a value or use --prompt.");
18639
+ }
18640
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
18641
+ throw new Error("Prompt input requires an interactive terminal.");
18642
+ }
18643
+ const rl = (0, import_promises6.createInterface)({
18644
+ input: process.stdin,
18645
+ output: process.stdout
18646
+ });
18647
+ try {
18648
+ const prompt = args.secret ? `Enter secret value for ${args.key}: ` : `Enter value for ${args.key}: `;
18649
+ return await rl.question(prompt);
18650
+ } finally {
18651
+ rl.close();
18652
+ }
18653
+ }
18440
18654
  async requireNamespace(payload, baseUrl) {
18441
18655
  if (!payload || typeof payload !== "object") {
18442
18656
  throw new Error("Service payload must be a JSON object.");
@@ -19883,6 +20097,10 @@ init_namespacedRef();
19883
20097
  function parseServiceArgs(tokens) {
19884
20098
  const rest = [...tokens];
19885
20099
  const rawAction = rest.shift();
20100
+ if (rawAction && looksLikeNamespacedRef(rawAction) && rest[0] === "env") {
20101
+ rest.shift();
20102
+ return parseServiceEnvArgs(rawAction, rest);
20103
+ }
19886
20104
  const action = rawAction === "view" ? "view" : rawAction;
19887
20105
  if (!action) {
19888
20106
  throw new Error("Missing service action. Use: service list|get|view|create|update|rename|delete");
@@ -20159,6 +20377,245 @@ function parseBareRenameId3(value, entityName) {
20159
20377
  }
20160
20378
  return normalized;
20161
20379
  }
20380
+ function looksLikeNamespacedRef(value) {
20381
+ return value.includes(":") && !value.startsWith("-");
20382
+ }
20383
+ function parseServiceEnvArgs(appId, tokens) {
20384
+ const rest = [...tokens];
20385
+ const action = rest.shift();
20386
+ if (!action) {
20387
+ throw new Error("Usage: service <ns:app> env list|get|set|unset|resolve|pull|copy-from");
20388
+ }
20389
+ let baseUrl;
20390
+ let json = false;
20391
+ if (action === "list") {
20392
+ let scope;
20393
+ let includeSecretMeta = false;
20394
+ let includeSecretValue = false;
20395
+ while (rest.length > 0) {
20396
+ const token = rest.shift();
20397
+ switch (token) {
20398
+ case "--scope":
20399
+ scope = requireValue6(rest, token);
20400
+ break;
20401
+ case "--include-secret-meta":
20402
+ includeSecretMeta = true;
20403
+ break;
20404
+ case "--include-secret-value":
20405
+ includeSecretValue = true;
20406
+ break;
20407
+ case "--base-url":
20408
+ baseUrl = requireValue6(rest, token);
20409
+ break;
20410
+ case "--json":
20411
+ json = true;
20412
+ break;
20413
+ default:
20414
+ throw new Error(`Unknown service env list option: ${token}`);
20415
+ }
20416
+ }
20417
+ return { type: "service" /* Service */, action: "env-list", appId, scope, includeSecretMeta, includeSecretValue, baseUrl, json };
20418
+ }
20419
+ if (action === "get") {
20420
+ const key = rest.shift();
20421
+ if (!key || key.startsWith("-")) {
20422
+ throw new Error("Usage: service <ns:app> env get <key> --scope <scope> [--include-secret-value]");
20423
+ }
20424
+ let scope;
20425
+ let includeSecretValue = false;
20426
+ while (rest.length > 0) {
20427
+ const token = rest.shift();
20428
+ switch (token) {
20429
+ case "--scope":
20430
+ scope = requireValue6(rest, token);
20431
+ break;
20432
+ case "--include-secret-value":
20433
+ includeSecretValue = true;
20434
+ break;
20435
+ case "--base-url":
20436
+ baseUrl = requireValue6(rest, token);
20437
+ break;
20438
+ case "--json":
20439
+ json = true;
20440
+ break;
20441
+ default:
20442
+ throw new Error(`Unknown service env get option: ${token}`);
20443
+ }
20444
+ }
20445
+ if (!scope) {
20446
+ throw new Error("Usage: service <ns:app> env get <key> --scope <scope> [--include-secret-value]");
20447
+ }
20448
+ return { type: "service" /* Service */, action: "env-get", appId, key, scope, includeSecretValue, baseUrl, json };
20449
+ }
20450
+ if (action === "set") {
20451
+ const key = rest.shift();
20452
+ if (!key || key.startsWith("-")) {
20453
+ throw new Error("Usage: service <ns:app> env set <key> [value] --scope <scope> [--secret] [--prompt]");
20454
+ }
20455
+ let value;
20456
+ if (rest[0] && !rest[0].startsWith("-")) {
20457
+ value = rest.shift();
20458
+ }
20459
+ let scope;
20460
+ let secret = false;
20461
+ let prompt = false;
20462
+ while (rest.length > 0) {
20463
+ const token = rest.shift();
20464
+ switch (token) {
20465
+ case "--scope":
20466
+ scope = requireValue6(rest, token);
20467
+ break;
20468
+ case "--secret":
20469
+ secret = true;
20470
+ break;
20471
+ case "--prompt":
20472
+ prompt = true;
20473
+ break;
20474
+ case "--base-url":
20475
+ baseUrl = requireValue6(rest, token);
20476
+ break;
20477
+ case "--json":
20478
+ json = true;
20479
+ break;
20480
+ default:
20481
+ throw new Error(`Unknown service env set option: ${token}`);
20482
+ }
20483
+ }
20484
+ if (!scope) {
20485
+ throw new Error("Usage: service <ns:app> env set <key> [value] --scope <scope> [--secret] [--prompt]");
20486
+ }
20487
+ if (!value && !secret && !prompt) {
20488
+ throw new Error("Missing env value. Pass a value or use --prompt.");
20489
+ }
20490
+ return { type: "service" /* Service */, action: "env-set", appId, key, value, scope, secret, prompt, baseUrl, json };
20491
+ }
20492
+ if (action === "unset") {
20493
+ const key = rest.shift();
20494
+ if (!key || key.startsWith("-")) {
20495
+ throw new Error("Usage: service <ns:app> env unset <key> --scope <scope>");
20496
+ }
20497
+ let scope;
20498
+ while (rest.length > 0) {
20499
+ const token = rest.shift();
20500
+ switch (token) {
20501
+ case "--scope":
20502
+ scope = requireValue6(rest, token);
20503
+ break;
20504
+ case "--base-url":
20505
+ baseUrl = requireValue6(rest, token);
20506
+ break;
20507
+ case "--json":
20508
+ json = true;
20509
+ break;
20510
+ default:
20511
+ throw new Error(`Unknown service env unset option: ${token}`);
20512
+ }
20513
+ }
20514
+ if (!scope) {
20515
+ throw new Error("Usage: service <ns:app> env unset <key> --scope <scope>");
20516
+ }
20517
+ return { type: "service" /* Service */, action: "env-unset", appId, key, scope, baseUrl, json };
20518
+ }
20519
+ if (action === "resolve") {
20520
+ let stage;
20521
+ let branch;
20522
+ let includeSecretValue = false;
20523
+ while (rest.length > 0) {
20524
+ const token = rest.shift();
20525
+ switch (token) {
20526
+ case "--stage":
20527
+ stage = requireValue6(rest, token);
20528
+ break;
20529
+ case "--branch":
20530
+ branch = requireValue6(rest, token);
20531
+ break;
20532
+ case "--include-secret-value":
20533
+ includeSecretValue = true;
20534
+ break;
20535
+ case "--base-url":
20536
+ baseUrl = requireValue6(rest, token);
20537
+ break;
20538
+ case "--json":
20539
+ json = true;
20540
+ break;
20541
+ default:
20542
+ throw new Error(`Unknown service env resolve option: ${token}`);
20543
+ }
20544
+ }
20545
+ if (!stage) {
20546
+ throw new Error("Usage: service <ns:app> env resolve --stage <dev|preview|prod> [--branch <name>]");
20547
+ }
20548
+ return { type: "service" /* Service */, action: "env-resolve", appId, stage, branch, includeSecretValue, baseUrl, json };
20549
+ }
20550
+ if (action === "pull") {
20551
+ let stage;
20552
+ let branch;
20553
+ let output = ".env.local";
20554
+ while (rest.length > 0) {
20555
+ const token = rest.shift();
20556
+ switch (token) {
20557
+ case "--stage":
20558
+ stage = requireValue6(rest, token);
20559
+ break;
20560
+ case "--branch":
20561
+ branch = requireValue6(rest, token);
20562
+ break;
20563
+ case "--output":
20564
+ output = requireValue6(rest, token);
20565
+ break;
20566
+ case "--base-url":
20567
+ baseUrl = requireValue6(rest, token);
20568
+ break;
20569
+ case "--json":
20570
+ json = true;
20571
+ break;
20572
+ default:
20573
+ throw new Error(`Unknown service env pull option: ${token}`);
20574
+ }
20575
+ }
20576
+ if (!stage) {
20577
+ throw new Error("Usage: service <ns:app> env pull --stage <dev|preview|prod> [--branch <name>] [--output <path>]");
20578
+ }
20579
+ return { type: "service" /* Service */, action: "env-pull", appId, stage, branch, output, baseUrl, json };
20580
+ }
20581
+ if (action === "copy-from") {
20582
+ const sourceAppId = rest.shift();
20583
+ if (!sourceAppId || sourceAppId.startsWith("-")) {
20584
+ throw new Error("Usage: service <ns:app> env copy-from <source-ns:app> [--scope <scope>] [--include-secret] [--overwrite]");
20585
+ }
20586
+ let scope;
20587
+ let includeSecret = false;
20588
+ let overwrite = false;
20589
+ let onlyKeys;
20590
+ while (rest.length > 0) {
20591
+ const token = rest.shift();
20592
+ switch (token) {
20593
+ case "--scope":
20594
+ scope = requireValue6(rest, token);
20595
+ break;
20596
+ case "--include-secret":
20597
+ includeSecret = true;
20598
+ break;
20599
+ case "--overwrite":
20600
+ overwrite = true;
20601
+ break;
20602
+ case "--only":
20603
+ onlyKeys = requireValue6(rest, token).split(",").map((item) => item.trim()).filter(Boolean);
20604
+ break;
20605
+ case "--base-url":
20606
+ baseUrl = requireValue6(rest, token);
20607
+ break;
20608
+ case "--json":
20609
+ json = true;
20610
+ break;
20611
+ default:
20612
+ throw new Error(`Unknown service env copy-from option: ${token}`);
20613
+ }
20614
+ }
20615
+ return { type: "service" /* Service */, action: "env-copy-from", targetAppId: appId, sourceAppId, scope, includeSecret, overwrite, onlyKeys, baseUrl, json };
20616
+ }
20617
+ throw new Error(`Unknown service env action: ${action}`);
20618
+ }
20162
20619
 
20163
20620
  // src/roleCommandParser.ts
20164
20621
  function parseRoleArgs(tokens) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pmate/cli",
3
- "version": "0.21.5",
3
+ "version": "0.21.7",
4
4
  "description": "CLI utilities for the pMate project",
5
5
  "license": "MIT",
6
6
  "bin": {