@pmate/cli 0.16.3 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ declare enum Command {
9
9
  Deploy = "deploy",
10
10
  Log = "log",
11
11
  Init = "init",
12
+ Delete = "delete",
12
13
  Dev = "dev",
13
14
  Env = "env",
14
15
  Pr = "pr",
@@ -77,6 +78,11 @@ type InitCommandArgs = {
77
78
  initApp: string;
78
79
  initCwd: string;
79
80
  };
81
+ type DeleteCommandArgs = {
82
+ type: Command.Delete;
83
+ deleteApp: string;
84
+ deleteCwd: string;
85
+ };
80
86
  type DevCommandArgs = {
81
87
  type: Command.Dev;
82
88
  devApp: string;
@@ -463,7 +469,7 @@ type VercelDeploysCommandArgs = {
463
469
  lastWeek: boolean;
464
470
  };
465
471
  type VercelCommandArgs = VercelProjectsCommandArgs | VercelDeploysCommandArgs;
466
- type CommandArgs = NoneCommandArgs | ListCommandArgs | LoginCommandArgs | AddDnsCommandArgs | StsCommandArgs | BucketCommandArgs | DeployCommandArgs | LogCommandArgs | InitCommandArgs | DevCommandArgs | EnvCommandArgs | PrCommandArgs | CommitCommandArgs | SummaryCommandArgs | LinearCommandArgs | NotionCommandArgs | OssCommandArgs | QrcodeCommandArgs | RandomCommandArgs | CollectCommandArgs | AgentCommandArgs | NsCommandArgs | RoleCommandArgs | AccountCommandArgs | StoreCommandArgs | AppCommandArgs | VercelCommandArgs;
472
+ type CommandArgs = NoneCommandArgs | ListCommandArgs | LoginCommandArgs | AddDnsCommandArgs | StsCommandArgs | BucketCommandArgs | DeployCommandArgs | LogCommandArgs | InitCommandArgs | DeleteCommandArgs | DevCommandArgs | EnvCommandArgs | PrCommandArgs | CommitCommandArgs | SummaryCommandArgs | LinearCommandArgs | NotionCommandArgs | OssCommandArgs | QrcodeCommandArgs | RandomCommandArgs | CollectCommandArgs | AgentCommandArgs | NsCommandArgs | RoleCommandArgs | AccountCommandArgs | StoreCommandArgs | AppCommandArgs | VercelCommandArgs;
467
473
 
468
474
  interface ParsedArgs {
469
475
  help: boolean;
package/dist/index.js CHANGED
@@ -12613,7 +12613,7 @@ __export(index_exports, {
12613
12613
  });
12614
12614
  module.exports = __toCommonJS(index_exports);
12615
12615
  var import_node_fs15 = require("fs");
12616
- var import_node_path20 = __toESM(require("path"));
12616
+ var import_node_path21 = __toESM(require("path"));
12617
12617
  var import_chalk3 = __toESM(require("chalk"));
12618
12618
 
12619
12619
  // src/cli.ts
@@ -13292,6 +13292,53 @@ var AliyunService = class {
13292
13292
  );
13293
13293
  return match?.value;
13294
13294
  }
13295
+ /** Delete DNS records matching RR/type and an optional value filter. */
13296
+ static async deleteDomainRecords(input) {
13297
+ const userConfig = loadPmateConfig();
13298
+ const accessKeyId = userConfig.aliyun?.ak?.trim();
13299
+ const accessKeySecret = userConfig.aliyun?.sk?.trim();
13300
+ if (!accessKeyId) throw new Error("Missing aliyun.ak in ~/.pmate/config.yaml.");
13301
+ if (!accessKeySecret) throw new Error("Missing aliyun.sk in ~/.pmate/config.yaml.");
13302
+ const sdkConfig = new import_openapi_client.Config({
13303
+ accessKeyId,
13304
+ accessKeySecret,
13305
+ regionId: userConfig.aliyun?.region?.trim() || "cn-hangzhou"
13306
+ });
13307
+ const client = new import_alidns20150109.default(sdkConfig);
13308
+ const request = new import_alidns20150109.DescribeDomainRecordsRequest({
13309
+ domainName: input.domainName,
13310
+ RRKeyWord: input.rr,
13311
+ type: input.type,
13312
+ searchMode: "ADVANCED",
13313
+ pageSize: 500
13314
+ });
13315
+ const response = await client.describeDomainRecords(request);
13316
+ const records = response.body?.domainRecords?.record ?? [];
13317
+ const normalizedRr = input.rr.toLowerCase();
13318
+ const normalizedType = input.type.toUpperCase();
13319
+ const normalizedValue = input.value?.trim().toLowerCase();
13320
+ const matches = records.filter((record) => {
13321
+ if (record?.RR?.toLowerCase() !== normalizedRr) {
13322
+ return false;
13323
+ }
13324
+ if (record?.type?.toUpperCase() !== normalizedType) {
13325
+ return false;
13326
+ }
13327
+ if (!normalizedValue) {
13328
+ return true;
13329
+ }
13330
+ return record?.value?.trim().toLowerCase() === normalizedValue;
13331
+ });
13332
+ for (const record of matches) {
13333
+ if (!record?.recordId) {
13334
+ continue;
13335
+ }
13336
+ await client.deleteDomainRecord(
13337
+ new import_alidns20150109.DeleteDomainRecordRequest({ recordId: record.recordId })
13338
+ );
13339
+ }
13340
+ return matches.length;
13341
+ }
13295
13342
  /** Create an OSS bucket. */
13296
13343
  static async createBucket(bucketName) {
13297
13344
  const cfg = loadPmateConfig();
@@ -13425,6 +13472,44 @@ var AliyunService = class {
13425
13472
  (name) => typeof name === "string" && name.trim().length > 0
13426
13473
  );
13427
13474
  }
13475
+ /** Delete every object in a bucket and then remove the bucket itself. */
13476
+ static async deleteBucketAndContents(bucketName) {
13477
+ const cfg = loadPmateConfig();
13478
+ const region = cfg.oss?.public?.region?.trim();
13479
+ const accessKeyId = cfg.aliyun?.ak?.trim();
13480
+ const accessKeySecret = cfg.aliyun?.sk?.trim();
13481
+ if (!region) throw new Error("Missing oss.public.region in ~/.pmate/config.yaml.");
13482
+ if (!accessKeyId) throw new Error("Missing aliyun.ak in ~/.pmate/config.yaml.");
13483
+ if (!accessKeySecret) throw new Error("Missing aliyun.sk in ~/.pmate/config.yaml.");
13484
+ const store = new import_ali_oss.default({ region, accessKeyId, accessKeySecret });
13485
+ const exists = await this.bucketExists(store, bucketName);
13486
+ if (!exists) {
13487
+ ui.warn(`Bucket not found: ${bucketName}`);
13488
+ return;
13489
+ }
13490
+ const bucketClient = new import_ali_oss.default({ region, accessKeyId, accessKeySecret, bucket: bucketName });
13491
+ let marker;
13492
+ do {
13493
+ const result = await bucketClient.list(
13494
+ {
13495
+ marker,
13496
+ "max-keys": 1e3
13497
+ },
13498
+ {}
13499
+ );
13500
+ const objectNames = (result.objects ?? []).map((item) => item.name).filter((name) => typeof name === "string" && name.length > 0);
13501
+ if (objectNames.length > 0) {
13502
+ await bucketClient.deleteMulti(objectNames, { quiet: true });
13503
+ ui.success(`Deleted bucket objects from ${bucketName}`, { count: objectNames.length });
13504
+ }
13505
+ marker = result.nextMarker;
13506
+ if (!result.isTruncated) {
13507
+ break;
13508
+ }
13509
+ } while (marker);
13510
+ await store.deleteBucket(bucketName);
13511
+ ui.success(`Deleted bucket: ${bucketName}`);
13512
+ }
13428
13513
  /** Ensure a CDN domain exists for the bucket origin. */
13429
13514
  static async ensureCdnDomain(domainName, bucketName) {
13430
13515
  const client = this.createCdnClient();
@@ -13463,6 +13548,24 @@ var AliyunService = class {
13463
13548
  const match = data.find((item) => item?.domain === domainName) ?? data[0];
13464
13549
  return match?.cname;
13465
13550
  }
13551
+ /** Stop and delete a CDN domain if it exists. */
13552
+ static async deleteCdnDomain(domainName) {
13553
+ const client = this.createCdnClient();
13554
+ const status = await this.getCdnDomainStatus(client, domainName);
13555
+ if (!status || status === "DomainNotExist") {
13556
+ ui.warn(`CDN domain not found: ${domainName}`);
13557
+ return;
13558
+ }
13559
+ try {
13560
+ await client.stopCdnDomain(new import_cdn20180510.StopCdnDomainRequest({ domainName }));
13561
+ } catch (error) {
13562
+ ui.warn(`Failed to stop CDN domain before delete: ${domainName}`, {
13563
+ message: error instanceof Error ? error.message : String(error)
13564
+ });
13565
+ }
13566
+ await client.deleteCdnDomain(new import_cdn20180510.DeleteCdnDomainRequest({ domainName }));
13567
+ ui.success(`Deleted CDN domain: ${domainName}`);
13568
+ }
13466
13569
  /** Enable HTTPS certificate for a CDN domain. */
13467
13570
  static async enableHttpsCertificate(domainName) {
13468
13571
  const client = this.createCdnClient();
@@ -14746,10 +14849,153 @@ var InitCommandHandler = class {
14746
14849
  }
14747
14850
  };
14748
14851
 
14749
- // src/commands/DevCommandHandler.ts
14750
- var import_node_fs6 = require("fs");
14852
+ // src/commands/DeleteCommandHandler.ts
14751
14853
  var import_node_path9 = __toESM(require("path"));
14752
14854
  var import_node_child_process4 = require("child_process");
14855
+ var DeleteCommandHandler = class {
14856
+ async handle(args) {
14857
+ const appName = args.deleteApp.trim();
14858
+ if (!appName) {
14859
+ throw new Error("Missing app name. Usage: delete <app-name> [--cwd <dir>].");
14860
+ }
14861
+ const cwd = this.resolveCwd(args.deleteCwd);
14862
+ const { config, configPath } = loadAppConfig(cwd);
14863
+ const appConfig = config.apps.find((entry) => entry?.app === appName);
14864
+ if (!appConfig) {
14865
+ throw new Error(`App "${appName}" not found in ${configPath}`);
14866
+ }
14867
+ switch (appConfig.type) {
14868
+ case "vite":
14869
+ case "static":
14870
+ await this.deleteStaticApp(config, appConfig);
14871
+ break;
14872
+ case "node":
14873
+ case "rust":
14874
+ case "python":
14875
+ await this.deleteServerApp(appConfig);
14876
+ break;
14877
+ default:
14878
+ throw new Error(`Delete not implemented for app type "${String(appConfig.type)}".`);
14879
+ }
14880
+ ui.success(`Deleted app resources for ${appName}`);
14881
+ }
14882
+ async deleteStaticApp(config, appConfig) {
14883
+ const bucketName = appConfig.bucket?.trim();
14884
+ if (!bucketName) {
14885
+ throw new Error(`Missing bucket for ${appConfig.app} in .pmate.yaml`);
14886
+ }
14887
+ const domainName = config.domain?.trim();
14888
+ if (!domainName) {
14889
+ throw new Error("Missing domain in .pmate.yaml");
14890
+ }
14891
+ const subdomain = appConfig.subdomain?.trim();
14892
+ const dnsRr = subdomain || "@";
14893
+ const cdnDomain = subdomain ? `${subdomain}.${domainName}` : domainName;
14894
+ const cname = await AliyunService.getCdnCname(cdnDomain);
14895
+ if (cname) {
14896
+ const deleted = await AliyunService.deleteDomainRecords({
14897
+ domainName,
14898
+ rr: dnsRr,
14899
+ type: "CNAME",
14900
+ value: cname
14901
+ });
14902
+ this.logDeletedRecords(`Removed CNAME record for ${cdnDomain}`, deleted);
14903
+ } else {
14904
+ ui.warn(`No CDN CNAME found for ${cdnDomain}; skipping DNS value check.`);
14905
+ const deleted = await AliyunService.deleteDomainRecords({
14906
+ domainName,
14907
+ rr: dnsRr,
14908
+ type: "CNAME"
14909
+ });
14910
+ this.logDeletedRecords(`Removed CNAME record for ${cdnDomain}`, deleted);
14911
+ }
14912
+ if (!subdomain) {
14913
+ const deleted = await AliyunService.deleteDomainRecords({
14914
+ domainName,
14915
+ rr: "www",
14916
+ type: "CNAME",
14917
+ value: domainName
14918
+ });
14919
+ this.logDeletedRecords(`Removed CNAME record for www.${domainName}`, deleted);
14920
+ }
14921
+ await AliyunService.deleteCdnDomain(cdnDomain);
14922
+ await AliyunService.deleteBucketAndContents(bucketName);
14923
+ }
14924
+ async deleteServerApp(appConfig) {
14925
+ const subdomain = appConfig.subdomain?.trim();
14926
+ if (!subdomain) {
14927
+ ui.warn(`No subdomain configured for ${appConfig.app}; nothing to tear down on DNS/nginx.`);
14928
+ return;
14929
+ }
14930
+ const server = appConfig.server?.trim();
14931
+ if (!server) {
14932
+ throw new Error(`Missing server for ${appConfig.app} in .pmate.yaml`);
14933
+ }
14934
+ await this.removeRemoteConfig(server, `/etc/nginx/sites-enabled/${subdomain}.conf`);
14935
+ ui.success(`Removed nginx config for ${subdomain} from ${server}`);
14936
+ await this.reloadNginx(server);
14937
+ ui.success(`Reloaded nginx on ${server}`);
14938
+ const serverAddress = await resolveServerAddress(server);
14939
+ const deleted = await AliyunService.deleteDomainRecords({
14940
+ domainName: "pmate.chat",
14941
+ rr: subdomain,
14942
+ type: "A",
14943
+ value: serverAddress
14944
+ });
14945
+ this.logDeletedRecords(`Removed A record for ${subdomain}.pmate.chat`, deleted);
14946
+ }
14947
+ logDeletedRecords(message, deletedCount) {
14948
+ if (deletedCount > 0) {
14949
+ ui.success(message, { deletedCount });
14950
+ return;
14951
+ }
14952
+ ui.warn(`${message} skipped`, { deletedCount });
14953
+ }
14954
+ removeRemoteConfig(server, remotePath) {
14955
+ return new Promise((resolve, reject) => {
14956
+ const target = `pmate@${server}`;
14957
+ const child = (0, import_node_child_process4.spawn)("ssh", [target, "sudo", "rm", "-f", remotePath], {
14958
+ stdio: ["ignore", "inherit", "inherit"]
14959
+ });
14960
+ child.on("error", (error) => {
14961
+ reject(error);
14962
+ });
14963
+ child.on("close", (code) => {
14964
+ if (code === 0) {
14965
+ resolve();
14966
+ return;
14967
+ }
14968
+ reject(new Error(`ssh to ${server} exited with code ${code}`));
14969
+ });
14970
+ });
14971
+ }
14972
+ reloadNginx(server) {
14973
+ return new Promise((resolve, reject) => {
14974
+ const target = `pmate@${server}`;
14975
+ const child = (0, import_node_child_process4.spawn)("ssh", [target, "sudo", "nginx", "-s", "reload"], {
14976
+ stdio: ["ignore", "inherit", "inherit"]
14977
+ });
14978
+ child.on("error", (error) => {
14979
+ reject(error);
14980
+ });
14981
+ child.on("close", (code) => {
14982
+ if (code === 0) {
14983
+ resolve();
14984
+ return;
14985
+ }
14986
+ reject(new Error(`nginx reload on ${server} exited with code ${code}`));
14987
+ });
14988
+ });
14989
+ }
14990
+ resolveCwd(target) {
14991
+ return target ? import_node_path9.default.resolve(process.cwd(), target) : process.cwd();
14992
+ }
14993
+ };
14994
+
14995
+ // src/commands/DevCommandHandler.ts
14996
+ var import_node_fs6 = require("fs");
14997
+ var import_node_path10 = __toESM(require("path"));
14998
+ var import_node_child_process5 = require("child_process");
14753
14999
  var DevCommandHandler = class {
14754
15000
  async handle(args) {
14755
15001
  const appName = args.devApp.trim();
@@ -14766,7 +15012,7 @@ var DevCommandHandler = class {
14766
15012
  );
14767
15013
  }
14768
15014
  const appDir = resolveLocalAppDir(cwd, appName, appConfig.dir);
14769
- const packageJsonPath = import_node_path9.default.join(appDir, "package.json");
15015
+ const packageJsonPath = import_node_path10.default.join(appDir, "package.json");
14770
15016
  if (!(0, import_node_fs6.existsSync)(packageJsonPath)) {
14771
15017
  throw new Error(`No package.json found at ${packageJsonPath}`);
14772
15018
  }
@@ -14781,7 +15027,7 @@ var DevCommandHandler = class {
14781
15027
  await this.runCommand("pnpm", ["--filter", pkgName, "run", "dev"], cwd);
14782
15028
  }
14783
15029
  resolveCwd(target) {
14784
- return target ? import_node_path9.default.resolve(process.cwd(), target) : process.cwd();
15030
+ return target ? import_node_path10.default.resolve(process.cwd(), target) : process.cwd();
14785
15031
  }
14786
15032
  loadConfig(cwd) {
14787
15033
  return loadAppConfig(cwd);
@@ -14796,7 +15042,7 @@ var DevCommandHandler = class {
14796
15042
  }
14797
15043
  runCommand(command, args, cwd) {
14798
15044
  return new Promise((resolve, reject) => {
14799
- const child = (0, import_node_child_process4.spawn)(command, args, {
15045
+ const child = (0, import_node_child_process5.spawn)(command, args, {
14800
15046
  cwd,
14801
15047
  stdio: "inherit"
14802
15048
  });
@@ -14816,7 +15062,7 @@ var DevCommandHandler = class {
14816
15062
 
14817
15063
  // src/commands/OssCommandHandler.ts
14818
15064
  var import_node_fs7 = require("fs");
14819
- var import_node_path10 = __toESM(require("path"));
15065
+ var import_node_path11 = __toESM(require("path"));
14820
15066
  var OssCommandHandler = class _OssCommandHandler {
14821
15067
  static {
14822
15068
  this.DEFAULT_BUCKET = "parrot-static";
@@ -14833,7 +15079,7 @@ var OssCommandHandler = class _OssCommandHandler {
14833
15079
  }
14834
15080
  return;
14835
15081
  }
14836
- const resolvedFile = import_node_path10.default.resolve(process.cwd(), args.filePath);
15082
+ const resolvedFile = import_node_path11.default.resolve(process.cwd(), args.filePath);
14837
15083
  this.assertFile(resolvedFile);
14838
15084
  const objectKey = this.normalizeObjectKey(args.objectKey);
14839
15085
  const bucket = this.resolveBucket(args.bucket);
@@ -14865,8 +15111,8 @@ var OssCommandHandler = class _OssCommandHandler {
14865
15111
  };
14866
15112
 
14867
15113
  // src/commands/EnvCommandHandler.ts
14868
- var import_node_path11 = __toESM(require("path"));
14869
- var import_node_child_process5 = require("child_process");
15114
+ var import_node_path12 = __toESM(require("path"));
15115
+ var import_node_child_process6 = require("child_process");
14870
15116
  var EnvCommandHandler = class {
14871
15117
  async handle(args) {
14872
15118
  const appName = args.envApp.trim();
@@ -14939,8 +15185,8 @@ var EnvCommandHandler = class {
14939
15185
  ui.success(`Set ${envKey} in .env.local`, appName);
14940
15186
  }
14941
15187
  async listEnvKeys(server, repoDir, appDir, verbose) {
14942
- const envLocalPath = import_node_path11.default.posix.join(appDir, ".env.local");
14943
- const envPath = import_node_path11.default.posix.join(appDir, ".env");
15188
+ const envLocalPath = import_node_path12.default.posix.join(appDir, ".env.local");
15189
+ const envPath = import_node_path12.default.posix.join(appDir, ".env");
14944
15190
  if (verbose) {
14945
15191
  const repoPath = `$HOME/${repoDir}`;
14946
15192
  ui.info("Env list target", {
@@ -15033,8 +15279,8 @@ var EnvCommandHandler = class {
15033
15279
  }
15034
15280
  }
15035
15281
  async appendEnvLine(server, repoDir, appDir, envKey, envLine, verbose) {
15036
- const envLocalPath = import_node_path11.default.posix.join(appDir, ".env.local");
15037
- const envPath = import_node_path11.default.posix.join(appDir, ".env");
15282
+ const envLocalPath = import_node_path12.default.posix.join(appDir, ".env.local");
15283
+ const envPath = import_node_path12.default.posix.join(appDir, ".env");
15038
15284
  if (verbose) {
15039
15285
  const repoPath = `$HOME/${repoDir}`;
15040
15286
  ui.info("Env add target", {
@@ -15082,8 +15328,8 @@ var EnvCommandHandler = class {
15082
15328
  await this.runRemoteCommand(server, command);
15083
15329
  }
15084
15330
  async deleteEnvKey(server, repoDir, appDir, envKey, verbose) {
15085
- const envLocalPath = import_node_path11.default.posix.join(appDir, ".env.local");
15086
- const envPath = import_node_path11.default.posix.join(appDir, ".env");
15331
+ const envLocalPath = import_node_path12.default.posix.join(appDir, ".env.local");
15332
+ const envPath = import_node_path12.default.posix.join(appDir, ".env");
15087
15333
  if (verbose) {
15088
15334
  const repoPath = `$HOME/${repoDir}`;
15089
15335
  ui.info("Env delete target", {
@@ -15153,7 +15399,7 @@ var EnvCommandHandler = class {
15153
15399
  runRemoteCommand(server, command) {
15154
15400
  return new Promise((resolve, reject) => {
15155
15401
  const target = `pmate@${server}`;
15156
- const child = (0, import_node_child_process5.spawn)("ssh", buildSshBashArgs(target, command), {
15402
+ const child = (0, import_node_child_process6.spawn)("ssh", buildSshBashArgs(target, command), {
15157
15403
  stdio: "inherit"
15158
15404
  });
15159
15405
  child.on("error", (error) => {
@@ -15171,7 +15417,7 @@ var EnvCommandHandler = class {
15171
15417
  runRemoteCommandCapture(server, command) {
15172
15418
  return new Promise((resolve, reject) => {
15173
15419
  const target = `pmate@${server}`;
15174
- const child = (0, import_node_child_process5.spawn)("ssh", buildSshBashArgs(target, command), {
15420
+ const child = (0, import_node_child_process6.spawn)("ssh", buildSshBashArgs(target, command), {
15175
15421
  stdio: ["ignore", "pipe", "pipe"]
15176
15422
  });
15177
15423
  let output = "";
@@ -15220,7 +15466,7 @@ function formatEnvValue(value) {
15220
15466
  }
15221
15467
 
15222
15468
  // src/commands/PrCommandHandler.ts
15223
- var import_node_child_process6 = require("child_process");
15469
+ var import_node_child_process7 = require("child_process");
15224
15470
  var PrCommandHandler = class {
15225
15471
  constructor(cwd = process.cwd()) {
15226
15472
  this.cwd = cwd;
@@ -15692,7 +15938,7 @@ ${lines}`;
15692
15938
  }
15693
15939
  run(command, args, quietError = false, env, cwd) {
15694
15940
  return new Promise((resolve, reject) => {
15695
- const child = (0, import_node_child_process6.spawn)(command, args, {
15941
+ const child = (0, import_node_child_process7.spawn)(command, args, {
15696
15942
  stdio: quietError ? "ignore" : "inherit",
15697
15943
  env: env ?? process.env,
15698
15944
  cwd: cwd ?? this.cwd
@@ -15711,7 +15957,7 @@ ${lines}`;
15711
15957
  }
15712
15958
  runCapture(command, args, allowFailure = false, env, cwd) {
15713
15959
  return new Promise((resolve, reject) => {
15714
- const child = (0, import_node_child_process6.spawn)(command, args, {
15960
+ const child = (0, import_node_child_process7.spawn)(command, args, {
15715
15961
  stdio: ["ignore", "pipe", "pipe"],
15716
15962
  env: env ?? process.env,
15717
15963
  cwd: cwd ?? this.cwd
@@ -15852,8 +16098,8 @@ var CommitCommandHandler = class {
15852
16098
  };
15853
16099
 
15854
16100
  // src/commands/SummaryCommandHandler.ts
15855
- var import_node_child_process7 = require("child_process");
15856
- var import_node_path12 = __toESM(require("path"));
16101
+ var import_node_child_process8 = require("child_process");
16102
+ var import_node_path13 = __toESM(require("path"));
15857
16103
  var SummaryCommandHandler = class {
15858
16104
  async handle(args) {
15859
16105
  const cwd = this.resolveCwd(args.cwd);
@@ -15961,7 +16207,7 @@ var SummaryCommandHandler = class {
15961
16207
  }
15962
16208
  run(command, args, quietError = false, env, cwd) {
15963
16209
  return new Promise((resolve, reject) => {
15964
- const child = (0, import_node_child_process7.spawn)(command, args, {
16210
+ const child = (0, import_node_child_process8.spawn)(command, args, {
15965
16211
  stdio: quietError ? "ignore" : "inherit",
15966
16212
  env: env ?? process.env,
15967
16213
  cwd
@@ -15980,7 +16226,7 @@ var SummaryCommandHandler = class {
15980
16226
  }
15981
16227
  runCapture(command, args, allowFailure = false, env, cwd) {
15982
16228
  return new Promise((resolve, reject) => {
15983
- const child = (0, import_node_child_process7.spawn)(command, args, {
16229
+ const child = (0, import_node_child_process8.spawn)(command, args, {
15984
16230
  stdio: ["ignore", "pipe", "pipe"],
15985
16231
  env: env ?? process.env,
15986
16232
  cwd
@@ -16038,7 +16284,7 @@ var SummaryCommandHandler = class {
16038
16284
  return this.runCapture("gh", args, allowFailure, await this.getGhEnv(cwd), cwd);
16039
16285
  }
16040
16286
  resolveCwd(value) {
16041
- return value ? import_node_path12.default.resolve(process.cwd(), value) : process.cwd();
16287
+ return value ? import_node_path13.default.resolve(process.cwd(), value) : process.cwd();
16042
16288
  }
16043
16289
  };
16044
16290
  function truncate2(value, limit) {
@@ -16050,10 +16296,10 @@ function truncate2(value, limit) {
16050
16296
  }
16051
16297
 
16052
16298
  // src/commands/LinearCommandHandler.ts
16053
- var import_node_child_process8 = require("child_process");
16299
+ var import_node_child_process9 = require("child_process");
16054
16300
  var import_node_fs8 = require("fs");
16055
16301
  var import_node_os3 = __toESM(require("os"));
16056
- var import_node_path13 = __toESM(require("path"));
16302
+ var import_node_path14 = __toESM(require("path"));
16057
16303
  var import_promises3 = require("readline/promises");
16058
16304
  var import_openai = __toESM(require("openai"));
16059
16305
  var import_sdk = require("@linear/sdk");
@@ -16937,7 +17183,7 @@ var LinearCommandHandler = class {
16937
17183
  }
16938
17184
  }
16939
17185
  getLinearSelectionPath() {
16940
- return import_node_path13.default.join(import_node_os3.default.homedir(), ".pmate", "linear-selection.json");
17186
+ return import_node_path14.default.join(import_node_os3.default.homedir(), ".pmate", "linear-selection.json");
16941
17187
  }
16942
17188
  readCachedLinearSelection(cwd) {
16943
17189
  const selectionPath = this.getLinearSelectionPath();
@@ -16956,7 +17202,7 @@ var LinearCommandHandler = class {
16956
17202
  }
16957
17203
  writeCachedLinearSelection(cwd, title) {
16958
17204
  const selectionPath = this.getLinearSelectionPath();
16959
- const dir = import_node_path13.default.dirname(selectionPath);
17205
+ const dir = import_node_path14.default.dirname(selectionPath);
16960
17206
  (0, import_node_fs8.mkdirSync)(dir, { recursive: true });
16961
17207
  let data = {};
16962
17208
  if ((0, import_node_fs8.existsSync)(selectionPath)) {
@@ -17147,8 +17393,8 @@ var LinearCommandHandler = class {
17147
17393
  if (process.platform !== "darwin") {
17148
17394
  throw new Error("Screenshot capture only supports macOS.");
17149
17395
  }
17150
- const dir = await import_node_fs8.promises.mkdtemp(import_node_path13.default.join(import_node_os3.default.tmpdir(), "pmate-screenshot-"));
17151
- const filePath = import_node_path13.default.join(dir, `screenshot-${index}.png`);
17396
+ const dir = await import_node_fs8.promises.mkdtemp(import_node_path14.default.join(import_node_os3.default.tmpdir(), "pmate-screenshot-"));
17397
+ const filePath = import_node_path14.default.join(dir, `screenshot-${index}.png`);
17152
17398
  try {
17153
17399
  const code = await this.run("screencapture", ["-i", "-x", filePath], true);
17154
17400
  if (code !== 0) {
@@ -17310,9 +17556,9 @@ var LinearCommandHandler = class {
17310
17556
  return compact.length > limit ? `${compact.slice(0, limit)}...` : compact;
17311
17557
  }
17312
17558
  async convertToPng(buffer, ext) {
17313
- const dir = await import_node_fs8.promises.mkdtemp(import_node_path13.default.join(import_node_os3.default.tmpdir(), "pmate-"));
17314
- const inputPath = import_node_path13.default.join(dir, `clipboard.${ext}`);
17315
- const outputPath = import_node_path13.default.join(dir, "clipboard.png");
17559
+ const dir = await import_node_fs8.promises.mkdtemp(import_node_path14.default.join(import_node_os3.default.tmpdir(), "pmate-"));
17560
+ const inputPath = import_node_path14.default.join(dir, `clipboard.${ext}`);
17561
+ const outputPath = import_node_path14.default.join(dir, "clipboard.png");
17316
17562
  try {
17317
17563
  await import_node_fs8.promises.writeFile(inputPath, buffer);
17318
17564
  const stderr = await this.runCapture(
@@ -17336,7 +17582,7 @@ var LinearCommandHandler = class {
17336
17582
  }
17337
17583
  captureClipboard(preferred) {
17338
17584
  return new Promise((resolve, reject) => {
17339
- const child = (0, import_node_child_process8.spawn)("pbpaste", ["-Prefer", preferred], {
17585
+ const child = (0, import_node_child_process9.spawn)("pbpaste", ["-Prefer", preferred], {
17340
17586
  stdio: ["ignore", "pipe", "pipe"]
17341
17587
  });
17342
17588
  const chunks = [];
@@ -17546,7 +17792,7 @@ var LinearCommandHandler = class {
17546
17792
  }
17547
17793
  run(command, args, quietError = false, env, cwd) {
17548
17794
  return new Promise((resolve, reject) => {
17549
- const child = (0, import_node_child_process8.spawn)(command, args, {
17795
+ const child = (0, import_node_child_process9.spawn)(command, args, {
17550
17796
  stdio: quietError ? "ignore" : "inherit",
17551
17797
  env: env ?? process.env,
17552
17798
  cwd
@@ -17565,7 +17811,7 @@ var LinearCommandHandler = class {
17565
17811
  }
17566
17812
  runCapture(command, args, allowFailure = false, env, cwd) {
17567
17813
  return new Promise((resolve, reject) => {
17568
- const child = (0, import_node_child_process8.spawn)(command, args, {
17814
+ const child = (0, import_node_child_process9.spawn)(command, args, {
17569
17815
  stdio: ["ignore", "pipe", "pipe"],
17570
17816
  env: env ?? process.env,
17571
17817
  cwd
@@ -17623,7 +17869,7 @@ var LinearCommandHandler = class {
17623
17869
  return this.runCapture("gh", args, allowFailure, await this.getGhEnv(cwd), cwd);
17624
17870
  }
17625
17871
  resolveCwd(value) {
17626
- return value ? import_node_path13.default.resolve(process.cwd(), value) : process.cwd();
17872
+ return value ? import_node_path14.default.resolve(process.cwd(), value) : process.cwd();
17627
17873
  }
17628
17874
  createOpenAiClient() {
17629
17875
  const config = loadPmateConfig();
@@ -17676,7 +17922,7 @@ function sleep2(ms) {
17676
17922
 
17677
17923
  // src/commands/NotionCommandHandler.ts
17678
17924
  var import_node_fs9 = require("fs");
17679
- var import_node_path14 = __toESM(require("path"));
17925
+ var import_node_path15 = __toESM(require("path"));
17680
17926
 
17681
17927
  // src/services/NotionService.ts
17682
17928
  var NotionService = class {
@@ -17915,9 +18161,9 @@ ${indent}\`\`\``;
17915
18161
  static richTextToPlain(richText) {
17916
18162
  return richText.map((item) => item.plain_text ?? item.text?.content ?? "").join("").trim();
17917
18163
  }
17918
- static async requestJson(path21, init) {
18164
+ static async requestJson(path22, init) {
17919
18165
  const token = this.getToken();
17920
- const response = await fetch(`${this.baseUrl}${path21}`, {
18166
+ const response = await fetch(`${this.baseUrl}${path22}`, {
17921
18167
  method: init.method,
17922
18168
  headers: {
17923
18169
  Authorization: `Bearer ${token}`,
@@ -18015,16 +18261,16 @@ var NotionCommandHandler = class {
18015
18261
  if (!args.filePath) {
18016
18262
  return "";
18017
18263
  }
18018
- const resolved = import_node_path14.default.resolve(process.cwd(), args.filePath);
18264
+ const resolved = import_node_path15.default.resolve(process.cwd(), args.filePath);
18019
18265
  return (0, import_node_fs9.readFileSync)(resolved, "utf8");
18020
18266
  }
18021
18267
  };
18022
18268
 
18023
18269
  // src/commands/QrcodeCommandHandler.ts
18024
- var import_node_child_process9 = require("child_process");
18270
+ var import_node_child_process10 = require("child_process");
18025
18271
  var import_node_fs10 = require("fs");
18026
18272
  var import_node_os4 = __toESM(require("os"));
18027
- var import_node_path15 = __toESM(require("path"));
18273
+ var import_node_path16 = __toESM(require("path"));
18028
18274
  var import_promises4 = require("readline/promises");
18029
18275
  var import_jsqr = __toESM(require("jsqr"));
18030
18276
  var import_pngjs = require("pngjs");
@@ -18066,8 +18312,8 @@ var QrcodeCommandHandler = class {
18066
18312
  } finally {
18067
18313
  rl.close();
18068
18314
  }
18069
- const dir = await import_node_fs10.promises.mkdtemp(import_node_path15.default.join(import_node_os4.default.tmpdir(), "pmate-qrcode-"));
18070
- const filePath = import_node_path15.default.join(dir, "qrcode.png");
18315
+ const dir = await import_node_fs10.promises.mkdtemp(import_node_path16.default.join(import_node_os4.default.tmpdir(), "pmate-qrcode-"));
18316
+ const filePath = import_node_path16.default.join(dir, "qrcode.png");
18071
18317
  const code = await this.run("screencapture", ["-i", "-x", filePath], true);
18072
18318
  if (code !== 0) {
18073
18319
  throw new Error("Screenshot capture canceled or failed.");
@@ -18129,7 +18375,7 @@ var QrcodeCommandHandler = class {
18129
18375
  }
18130
18376
  run(command, args, quietError = false, env, cwd) {
18131
18377
  return new Promise((resolve, reject) => {
18132
- const child = (0, import_node_child_process9.spawn)(command, args, {
18378
+ const child = (0, import_node_child_process10.spawn)(command, args, {
18133
18379
  stdio: quietError ? "ignore" : "inherit",
18134
18380
  env: env ?? process.env,
18135
18381
  cwd
@@ -18350,7 +18596,7 @@ var import_playwright = require("playwright");
18350
18596
  var import_node_crypto3 = require("crypto");
18351
18597
  var import_node_fs11 = require("fs");
18352
18598
  var import_node_os5 = __toESM(require("os"));
18353
- var import_node_path16 = __toESM(require("path"));
18599
+ var import_node_path17 = __toESM(require("path"));
18354
18600
  var CollectCommandHandler = class {
18355
18601
  async handle(args) {
18356
18602
  let browser = null;
@@ -18717,10 +18963,10 @@ function computeMessageHash(threadName, message) {
18717
18963
  return (0, import_node_crypto3.createHash)("sha1").update(base).digest("hex").slice(0, 16);
18718
18964
  }
18719
18965
  async function toDisplayableImagePath(src) {
18720
- if (!import_node_path16.default.isAbsolute(src)) {
18966
+ if (!import_node_path17.default.isAbsolute(src)) {
18721
18967
  return src;
18722
18968
  }
18723
- const ext = import_node_path16.default.extname(src);
18969
+ const ext = import_node_path17.default.extname(src);
18724
18970
  if (ext) {
18725
18971
  return src;
18726
18972
  }
@@ -18738,7 +18984,7 @@ async function toDisplayableImagePath(src) {
18738
18984
  if (!guessedExt) {
18739
18985
  return src;
18740
18986
  }
18741
- const cacheDir = import_node_path16.default.join(
18987
+ const cacheDir = import_node_path17.default.join(
18742
18988
  import_node_os5.default.homedir(),
18743
18989
  ".pmate",
18744
18990
  "messages",
@@ -18746,7 +18992,7 @@ async function toDisplayableImagePath(src) {
18746
18992
  );
18747
18993
  await import_node_fs11.promises.mkdir(cacheDir, { recursive: true });
18748
18994
  const base = (0, import_node_crypto3.createHash)("sha1").update(src).digest("hex");
18749
- const displayPath = import_node_path16.default.join(cacheDir, `${base}.${guessedExt}`);
18995
+ const displayPath = import_node_path17.default.join(cacheDir, `${base}.${guessedExt}`);
18750
18996
  await import_node_fs11.promises.rm(displayPath, { force: true }).catch(() => void 0);
18751
18997
  await import_node_fs11.promises.copyFile(src, displayPath);
18752
18998
  return displayPath;
@@ -18805,7 +19051,7 @@ function parseMessageText(raw) {
18805
19051
 
18806
19052
  // src/commands/AgentCommandHandler.ts
18807
19053
  var import_node_fs12 = require("fs");
18808
- var import_node_path17 = __toESM(require("path"));
19054
+ var import_node_path18 = __toESM(require("path"));
18809
19055
  init_sessionStore();
18810
19056
 
18811
19057
  // src/storeClient.ts
@@ -18837,8 +19083,8 @@ function descriptorPathSegments(descriptor) {
18837
19083
  return ["chains", normalized.chain, "namespaces", normalized.ns, normalized.kind, normalized.name];
18838
19084
  }
18839
19085
  function buildPathUrl(baseUrl, pathSegments, query) {
18840
- const path21 = `/${pathSegments.map((segment) => encodeURIComponent(segment)).join("/")}`;
18841
- const url = new URL(path21, baseUrl);
19086
+ const path22 = `/${pathSegments.map((segment) => encodeURIComponent(segment)).join("/")}`;
19087
+ const url = new URL(path22, baseUrl);
18842
19088
  if (query) {
18843
19089
  for (const [key, value] of Object.entries(query)) {
18844
19090
  url.searchParams.set(key, String(value));
@@ -19214,7 +19460,7 @@ var AgentCommandHandler = class {
19214
19460
  }).token;
19215
19461
  }
19216
19462
  readJsonFile(filePath) {
19217
- const absolutePath = import_node_path17.default.resolve(process.cwd(), filePath);
19463
+ const absolutePath = import_node_path18.default.resolve(process.cwd(), filePath);
19218
19464
  if (!(0, import_node_fs12.existsSync)(absolutePath)) {
19219
19465
  throw new Error(`JSON file not found: ${absolutePath}`);
19220
19466
  }
@@ -19353,7 +19599,7 @@ var NsCommandHandler = class {
19353
19599
 
19354
19600
  // src/commands/StoreCommandHandler.ts
19355
19601
  var import_node_fs13 = require("fs");
19356
- var import_node_path18 = __toESM(require("path"));
19602
+ var import_node_path19 = __toESM(require("path"));
19357
19603
  var StoreCommandHandler = class {
19358
19604
  async handle(args) {
19359
19605
  if (args.scope === "namespace") {
@@ -19495,7 +19741,7 @@ var StoreCommandHandler = class {
19495
19741
  return payload.data ?? [];
19496
19742
  }
19497
19743
  readJsonFile(filePath) {
19498
- const absolutePath = import_node_path18.default.resolve(process.cwd(), filePath);
19744
+ const absolutePath = import_node_path19.default.resolve(process.cwd(), filePath);
19499
19745
  if (!(0, import_node_fs13.existsSync)(absolutePath)) {
19500
19746
  throw new Error(`JSON file not found: ${absolutePath}`);
19501
19747
  }
@@ -19552,7 +19798,7 @@ var StoreCommandHandler = class {
19552
19798
 
19553
19799
  // src/commands/AppCommandHandler.ts
19554
19800
  var import_node_fs14 = require("fs");
19555
- var import_node_path19 = __toESM(require("path"));
19801
+ var import_node_path20 = __toESM(require("path"));
19556
19802
  init_sessionStore();
19557
19803
  var AppCommandHandler = class {
19558
19804
  async handle(args) {
@@ -19628,7 +19874,7 @@ var AppCommandHandler = class {
19628
19874
  }).token;
19629
19875
  }
19630
19876
  readJsonFile(filePath) {
19631
- const absolutePath = import_node_path19.default.resolve(process.cwd(), filePath);
19877
+ const absolutePath = import_node_path20.default.resolve(process.cwd(), filePath);
19632
19878
  if (!(0, import_node_fs14.existsSync)(absolutePath)) {
19633
19879
  throw new Error(`JSON file not found: ${absolutePath}`);
19634
19880
  }
@@ -19706,9 +19952,9 @@ function readNamespaceFromPayload(payload) {
19706
19952
  }
19707
19953
 
19708
19954
  // src/commands/VercelCommandHandler.ts
19709
- var import_node_child_process10 = require("child_process");
19955
+ var import_node_child_process11 = require("child_process");
19710
19956
  var import_node_util = require("util");
19711
- var execFileAsync = (0, import_node_util.promisify)(import_node_child_process10.execFile);
19957
+ var execFileAsync = (0, import_node_util.promisify)(import_node_child_process11.execFile);
19712
19958
  function parseDeploymentTimestamp(deployment) {
19713
19959
  const candidates = [deployment.createdAt, deployment.readyAt, deployment.ready];
19714
19960
  for (const value of candidates) {
@@ -20028,6 +20274,13 @@ var AccountCommandHandler = class {
20028
20274
  for (const item of items) {
20029
20275
  ui.info(item.account.id, {
20030
20276
  mobile: item.account.mobile,
20277
+ profiles: item.profiles.map((profile) => ({
20278
+ id: profile.id,
20279
+ app: profile.app,
20280
+ nickName: profile.nickName,
20281
+ userName: profile.userName,
20282
+ role: profile.role
20283
+ })),
20031
20284
  nickNames: item.nickNames,
20032
20285
  roles: item.roles.map((role) => `${role.namespace}/${role.role}`)
20033
20286
  });
@@ -20686,6 +20939,8 @@ function parseAccountArgs(tokens) {
20686
20939
  while (rest.length > 0) {
20687
20940
  const token = rest.shift();
20688
20941
  switch (token) {
20942
+ case void 0:
20943
+ break;
20689
20944
  case "--account":
20690
20945
  account2 = requireValue6(rest, token);
20691
20946
  break;
@@ -20703,6 +20958,10 @@ function parseAccountArgs(tokens) {
20703
20958
  json2 = true;
20704
20959
  break;
20705
20960
  default:
20961
+ if (!token.startsWith("-") && !account2 && !mobile && !nickName) {
20962
+ account2 = token;
20963
+ break;
20964
+ }
20706
20965
  throw new Error(`Unknown account view option: ${token}`);
20707
20966
  }
20708
20967
  }
@@ -20799,7 +21058,7 @@ function requireValue6(tokens, optionName) {
20799
21058
 
20800
21059
  // src/index.ts
20801
21060
  var pkg = JSON.parse(
20802
- (0, import_node_fs15.readFileSync)(import_node_path20.default.resolve(__dirname, "..", "package.json"), "utf8")
21061
+ (0, import_node_fs15.readFileSync)(import_node_path21.default.resolve(__dirname, "..", "package.json"), "utf8")
20803
21062
  );
20804
21063
  var HELP_TEXT = [
20805
21064
  import_chalk3.default.bold(`pmate v${pkg.version}`),
@@ -20827,6 +21086,8 @@ var HELP_TEXT = [
20827
21086
  ` ${import_chalk3.default.gray(" <app-name> [--ns <namespace>] [--search <keyword>] [--page <n>] [--history] [--cwd <dir>]")}`,
20828
21087
  ` ${import_chalk3.default.cyan("init")} Initialize an app bucket + CDN`,
20829
21088
  ` ${import_chalk3.default.gray(" <app-name> [--cwd <dir>]")}`,
21089
+ ` ${import_chalk3.default.cyan("delete")} Tear down app resources created by init`,
21090
+ ` ${import_chalk3.default.gray(" [app] <app-name> [--cwd <dir>]")}`,
20830
21091
  ` ${import_chalk3.default.cyan("dev")} Run the dev script for app dir from .pmate.yaml`,
20831
21092
  ` ${import_chalk3.default.gray(" <app-name> [--cwd <dir>]")}`,
20832
21093
  ` ${import_chalk3.default.cyan("env")} Manage app env vars on the server`,
@@ -20998,6 +21259,9 @@ function parseCommandArgs(args) {
20998
21259
  if (args.rest[0] === "init") {
20999
21260
  return parseInitArgs(args.rest.slice(1));
21000
21261
  }
21262
+ if (args.rest[0] === "delete") {
21263
+ return parseDeleteArgs(args.rest.slice(1));
21264
+ }
21001
21265
  if (args.rest[0] === "dev") {
21002
21266
  return parseDevArgs(args.rest.slice(1));
21003
21267
  }
@@ -21313,6 +21577,30 @@ function parseDevArgs(tokens) {
21313
21577
  }
21314
21578
  return { type: "dev" /* Dev */, ...options };
21315
21579
  }
21580
+ function parseDeleteArgs(tokens) {
21581
+ const rest = [...tokens];
21582
+ const head = rest.shift();
21583
+ const deleteApp = head === "app" ? rest.shift() : head;
21584
+ if (!deleteApp) {
21585
+ throw new Error("Missing app name for delete command");
21586
+ }
21587
+ let deleteCwd = process.cwd();
21588
+ while (rest.length > 0) {
21589
+ const token = rest.shift();
21590
+ switch (token) {
21591
+ case "--cwd":
21592
+ deleteCwd = requireValue7(rest, token);
21593
+ break;
21594
+ default:
21595
+ throw new Error(`Unknown delete option: ${token}`);
21596
+ }
21597
+ }
21598
+ return {
21599
+ type: "delete" /* Delete */,
21600
+ deleteApp,
21601
+ deleteCwd
21602
+ };
21603
+ }
21316
21604
  function parseOssArgs(tokens) {
21317
21605
  const rest = [...tokens];
21318
21606
  const action = rest.shift();
@@ -22409,6 +22697,11 @@ async function main() {
22409
22697
  await handler.handle(commandArgs);
22410
22698
  return;
22411
22699
  }
22700
+ case "delete" /* Delete */: {
22701
+ const handler = new DeleteCommandHandler();
22702
+ await handler.handle(commandArgs);
22703
+ return;
22704
+ }
22412
22705
  case "dev" /* Dev */: {
22413
22706
  const handler = new DevCommandHandler();
22414
22707
  await handler.handle(commandArgs);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pmate/cli",
3
- "version": "0.16.3",
3
+ "version": "0.17.0",
4
4
  "description": "CLI utilities for the pMate project",
5
5
  "license": "MIT",
6
6
  "bin": {