@pmate/cli 0.25.11 → 0.27.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.js CHANGED
@@ -88,7 +88,7 @@ var init_namespacedRef = __esm({
88
88
 
89
89
  // src/sessionStore.ts
90
90
  function buildSessionStorePath() {
91
- return import_node_path3.default.join(import_node_os2.default.homedir(), ".pmate", "session.json");
91
+ return import_node_path4.default.join(import_node_os3.default.homedir(), ".pmate", "session.json");
92
92
  }
93
93
  function assertValidAppRef(appRef) {
94
94
  return parseNamespacedRef(appRef, { entityLabel: "app ref" }).fullId;
@@ -153,7 +153,7 @@ function loadSessionStore() {
153
153
  }
154
154
  function loadExistingSessionStoreOrEmpty() {
155
155
  const sessionPath = buildSessionStorePath();
156
- if (!(0, import_node_fs2.existsSync)(sessionPath)) {
156
+ if (!(0, import_node_fs3.existsSync)(sessionPath)) {
157
157
  return {
158
158
  version: SESSION_STORE_VERSION,
159
159
  activeAppRef: DEFAULT_APP_ID,
@@ -172,10 +172,10 @@ function loadExistingSessionStoreOrEmpty() {
172
172
  }
173
173
  function loadSessionStoreWithPath() {
174
174
  const sessionPath = buildSessionStorePath();
175
- if (!(0, import_node_fs2.existsSync)(sessionPath)) {
175
+ if (!(0, import_node_fs3.existsSync)(sessionPath)) {
176
176
  throw new Error(`Missing session file at ${sessionPath}. Run "pmate login" first.`);
177
177
  }
178
- const raw = (0, import_node_fs2.readFileSync)(sessionPath, "utf8");
178
+ const raw = (0, import_node_fs3.readFileSync)(sessionPath, "utf8");
179
179
  const parsed = JSON.parse(raw);
180
180
  const store = normalizeStore(parsed);
181
181
  return { sessionPath, store };
@@ -265,12 +265,12 @@ function resolveReadApp(store, options) {
265
265
  }
266
266
  function writeSessionStore(store) {
267
267
  const sessionPath = buildSessionStorePath();
268
- (0, import_node_fs2.mkdirSync)(import_node_path3.default.dirname(sessionPath), { recursive: true });
269
- (0, import_node_fs2.writeFileSync)(sessionPath, JSON.stringify(store, null, 2), {
268
+ (0, import_node_fs3.mkdirSync)(import_node_path4.default.dirname(sessionPath), { recursive: true });
269
+ (0, import_node_fs3.writeFileSync)(sessionPath, JSON.stringify(store, null, 2), {
270
270
  mode: 384
271
271
  });
272
272
  try {
273
- (0, import_node_fs2.chmodSync)(sessionPath, 384);
273
+ (0, import_node_fs3.chmodSync)(sessionPath, 384);
274
274
  } catch {
275
275
  }
276
276
  }
@@ -280,13 +280,13 @@ function buildMissingSessionMessage(sessionPath, app) {
280
280
  }
281
281
  return `Missing session for app ${app} in ${sessionPath}. Run "pmate login --app ${app}" first.`;
282
282
  }
283
- var import_node_fs2, import_node_os2, import_node_path3, DEFAULT_APP_ID, SESSION_STORE_VERSION;
283
+ var import_node_fs3, import_node_os3, import_node_path4, DEFAULT_APP_ID, SESSION_STORE_VERSION;
284
284
  var init_sessionStore = __esm({
285
285
  "src/sessionStore.ts"() {
286
286
  "use strict";
287
- import_node_fs2 = require("fs");
288
- import_node_os2 = __toESM(require("os"));
289
- import_node_path3 = __toESM(require("path"));
287
+ import_node_fs3 = require("fs");
288
+ import_node_os3 = __toESM(require("os"));
289
+ import_node_path4 = __toESM(require("path"));
290
290
  init_namespacedRef();
291
291
  DEFAULT_APP_ID = "pmate:factory";
292
292
  SESSION_STORE_VERSION = 4;
@@ -8950,14 +8950,14 @@ var init_WebsocketClientV2 = __esm({
8950
8950
  if (this.reconnectTimer) return;
8951
8951
  const base = Math.min(1e3 * 2 ** this.reconnectAttempts, this.maxBackoffMs);
8952
8952
  const jitter = Math.floor(Math.random() * 250);
8953
- const delay = base + jitter;
8953
+ const delay2 = base + jitter;
8954
8954
  this.reconnectTimer = globalThis.setTimeout(() => {
8955
8955
  if (this.ws && this.ws.readyState === WebSocket.CONNECTING) return;
8956
8956
  this.reconnectTimer = void 0;
8957
8957
  this.reconnectAttempts++;
8958
8958
  logger3.log("Reconnecting... attempt", this.reconnectAttempts);
8959
8959
  this.init();
8960
- }, delay);
8960
+ }, delay2);
8961
8961
  }
8962
8962
  handleHeartbeatTimeout() {
8963
8963
  this.close(false);
@@ -9570,7 +9570,56 @@ var init_AgentTaskManager = __esm({
9570
9570
  }
9571
9571
  });
9572
9572
 
9573
+ // node_modules/@pmate/agent-sdk/dist/promptMany.js
9574
+ async function mapWithConcurrency(inputs, concurrency, run) {
9575
+ if (!Number.isInteger(concurrency) || concurrency < 1) {
9576
+ throw new Error("concurrency must be a positive integer");
9577
+ }
9578
+ const results = new Array(inputs.length);
9579
+ let nextIndex = 0;
9580
+ const workers = Array.from({ length: Math.min(concurrency, inputs.length) }, async () => {
9581
+ while (nextIndex < inputs.length) {
9582
+ const index = nextIndex;
9583
+ nextIndex += 1;
9584
+ try {
9585
+ results[index] = {
9586
+ ok: true,
9587
+ value: await run(inputs[index], index)
9588
+ };
9589
+ } catch (error) {
9590
+ const candidate = error;
9591
+ results[index] = {
9592
+ ok: false,
9593
+ error: {
9594
+ ...typeof candidate?.code === "string" ? { code: candidate.code } : {},
9595
+ message: typeof candidate?.message === "string" ? candidate.message : String(error)
9596
+ }
9597
+ };
9598
+ }
9599
+ }
9600
+ });
9601
+ await Promise.all(workers);
9602
+ return results;
9603
+ }
9604
+ var init_promptMany = __esm({
9605
+ "node_modules/@pmate/agent-sdk/dist/promptMany.js"() {
9606
+ "use strict";
9607
+ }
9608
+ });
9609
+
9573
9610
  // node_modules/@pmate/agent-sdk/dist/AgentClient.js
9611
+ function isPromptBatchTerminal(status) {
9612
+ return status === "completed" || status === "failed" || status === "expired" || status === "cancelled";
9613
+ }
9614
+ function delay(ms) {
9615
+ return new Promise((resolve) => setTimeout(resolve, ms));
9616
+ }
9617
+ function requireBatchResponse(value) {
9618
+ if (value === null) {
9619
+ throw new Error("LLM batch control returned an empty response");
9620
+ }
9621
+ return value;
9622
+ }
9574
9623
  function createAgentRequestBody(payload) {
9575
9624
  return {
9576
9625
  kind: "request",
@@ -9586,6 +9635,7 @@ var init_AgentClient = __esm({
9586
9635
  init_AgentConnectionPool();
9587
9636
  init_AgentTaskManager();
9588
9637
  init_debug();
9638
+ init_promptMany();
9589
9639
  logger5 = Logger.getDebugger("AgentClient");
9590
9640
  DEFAULT_TIMEOUT_MS = 4e4;
9591
9641
  DEFAULT_STREAM_TIMEOUT_MS = 12e4;
@@ -9636,6 +9686,92 @@ var init_AgentClient = __esm({
9636
9686
  payload: request.payload
9637
9687
  });
9638
9688
  }
9689
+ async promptMany(request) {
9690
+ return mapWithConcurrency(request.requests, request.concurrency ?? 10, (item) => this.prompt(item));
9691
+ }
9692
+ async submitPromptBatch(request) {
9693
+ return requireBatchResponse(await this.runInternal({
9694
+ agentId: request.agentId,
9695
+ payload: {
9696
+ __pmateLlmBatch: {
9697
+ operation: "submit",
9698
+ items: request.items,
9699
+ metadata: request.metadata
9700
+ }
9701
+ }
9702
+ }));
9703
+ }
9704
+ async getPromptBatch(request) {
9705
+ return requireBatchResponse(await this.runInternal({
9706
+ agentId: request.agentId,
9707
+ payload: {
9708
+ __pmateLlmBatch: {
9709
+ operation: "get",
9710
+ batchId: request.batchId
9711
+ }
9712
+ }
9713
+ }));
9714
+ }
9715
+ async getPromptBatchResults(request) {
9716
+ return requireBatchResponse(await this.runInternal({
9717
+ agentId: request.agentId,
9718
+ payload: {
9719
+ __pmateLlmBatch: {
9720
+ operation: "results",
9721
+ batchId: request.batchId
9722
+ }
9723
+ }
9724
+ }));
9725
+ }
9726
+ async waitPromptBatch(request) {
9727
+ const pollIntervalMs = request.pollIntervalMs ?? 1e4;
9728
+ const timeoutMs = request.timeoutMs ?? 24 * 60 * 60 * 1e3;
9729
+ if (!Number.isFinite(pollIntervalMs) || pollIntervalMs < 1) {
9730
+ throw new Error("pollIntervalMs must be a positive number");
9731
+ }
9732
+ if (!Number.isFinite(timeoutMs) || timeoutMs < 1) {
9733
+ throw new Error("timeoutMs must be a positive number");
9734
+ }
9735
+ const deadline = Date.now() + timeoutMs;
9736
+ while (true) {
9737
+ const batch = await this.getPromptBatch(request);
9738
+ if (isPromptBatchTerminal(batch.status)) {
9739
+ return batch;
9740
+ }
9741
+ const remainingMs = deadline - Date.now();
9742
+ if (remainingMs <= 0) {
9743
+ throw new Error(`Timed out waiting for prompt batch "${request.batchId}"; the server-side batch was not cancelled`);
9744
+ }
9745
+ await delay(Math.min(pollIntervalMs, remainingMs));
9746
+ }
9747
+ }
9748
+ async promptBatch(request) {
9749
+ const submitted = await this.submitPromptBatch(request);
9750
+ const completed = await this.waitPromptBatch({
9751
+ agentId: request.agentId,
9752
+ batchId: submitted.id,
9753
+ pollIntervalMs: request.pollIntervalMs,
9754
+ timeoutMs: request.timeoutMs
9755
+ });
9756
+ if (completed.status === "failed" || completed.status === "cancelled") {
9757
+ throw new Error(`Prompt batch "${completed.id}" ended with status "${completed.status}"`);
9758
+ }
9759
+ return this.getPromptBatchResults({
9760
+ agentId: request.agentId,
9761
+ batchId: completed.id
9762
+ });
9763
+ }
9764
+ async cancelPromptBatch(request) {
9765
+ return requireBatchResponse(await this.runInternal({
9766
+ agentId: request.agentId,
9767
+ payload: {
9768
+ __pmateLlmBatch: {
9769
+ operation: "cancel",
9770
+ batchId: request.batchId
9771
+ }
9772
+ }
9773
+ }));
9774
+ }
9639
9775
  async generateImage(request) {
9640
9776
  return this.runInternal({
9641
9777
  agentId: request.agentId,
@@ -10002,6 +10138,7 @@ var init_dist2 = __esm({
10002
10138
  init_AgentTaskManager();
10003
10139
  init_AgentService();
10004
10140
  init_debug();
10141
+ init_promptMany();
10005
10142
  init_src5();
10006
10143
  }
10007
10144
  });
@@ -10034,7 +10171,7 @@ function unwrapAgentResult(agentId, value) {
10034
10171
  return value;
10035
10172
  }
10036
10173
  function resolveMimeType(filePath) {
10037
- const ext = import_node_path10.default.extname(filePath).toLowerCase();
10174
+ const ext = import_node_path12.default.extname(filePath).toLowerCase();
10038
10175
  switch (ext) {
10039
10176
  case ".wav":
10040
10177
  return "audio/wav";
@@ -10054,12 +10191,12 @@ function resolveMimeType(filePath) {
10054
10191
  return "application/octet-stream";
10055
10192
  }
10056
10193
  }
10057
- var import_node_fs6, import_node_path10, DEFAULT_AGENT_API_BASE_URL, DEFAULT_AGENT_HUB_BASE_URL, DEFAULT_NAMESPACE, DEFAULT_AGENT_PROMPT_TIMEOUT_MS, AgentLlmClient;
10194
+ var import_node_fs7, import_node_path12, DEFAULT_AGENT_API_BASE_URL, DEFAULT_AGENT_HUB_BASE_URL, DEFAULT_NAMESPACE, DEFAULT_AGENT_PROMPT_TIMEOUT_MS, AgentLlmClient;
10058
10195
  var init_AgentLlmClient = __esm({
10059
10196
  "src/llm/AgentLlmClient.ts"() {
10060
10197
  "use strict";
10061
- import_node_fs6 = require("fs");
10062
- import_node_path10 = __toESM(require("path"));
10198
+ import_node_fs7 = require("fs");
10199
+ import_node_path12 = __toESM(require("path"));
10063
10200
  init_dist2();
10064
10201
  init_sessionStore();
10065
10202
  DEFAULT_AGENT_API_BASE_URL = "https://agent-api.pmate.chat";
@@ -10126,7 +10263,7 @@ var init_AgentLlmClient = __esm({
10126
10263
  params,
10127
10264
  minChunkSizeBytes: 0
10128
10265
  });
10129
- const file = (0, import_node_fs6.readFileSync)(filePath);
10266
+ const file = (0, import_node_fs7.readFileSync)(filePath);
10130
10267
  input.push(new Blob([file], { type: resolveMimeType(filePath) }));
10131
10268
  input.end();
10132
10269
  return await stream.finish();
@@ -10151,8 +10288,8 @@ __export(index_exports, {
10151
10288
  parseCommandArgs: () => parseCommandArgs
10152
10289
  });
10153
10290
  module.exports = __toCommonJS(index_exports);
10154
- var import_node_fs24 = require("fs");
10155
- var import_node_path28 = __toESM(require("path"));
10291
+ var import_node_fs25 = require("fs");
10292
+ var import_node_path30 = __toESM(require("path"));
10156
10293
  var import_chalk4 = __toESM(require("chalk"));
10157
10294
 
10158
10295
  // src/cli.ts
@@ -10584,8 +10721,67 @@ var ListCommandHandler = class {
10584
10721
 
10585
10722
  // src/commands/LoginCommandHandler.ts
10586
10723
  var import_node_child_process = require("child_process");
10724
+ var import_node_path5 = __toESM(require("path"));
10587
10725
  var import_node_http = require("http");
10588
10726
  var import_promises = require("readline/promises");
10727
+
10728
+ // src/accessKeyFile.ts
10729
+ var import_node_fs2 = require("fs");
10730
+ var import_node_os2 = __toESM(require("os"));
10731
+ var import_node_path3 = __toESM(require("path"));
10732
+ function readAccessKeyFile(filePath, options = {}) {
10733
+ const absolutePath = resolveFilePath(filePath, options.cwd);
10734
+ if (!(0, import_node_fs2.existsSync)(absolutePath)) {
10735
+ throw new Error(`Access key file not found: ${absolutePath}`);
10736
+ }
10737
+ let parsed;
10738
+ try {
10739
+ parsed = JSON.parse((0, import_node_fs2.readFileSync)(absolutePath, "utf8"));
10740
+ } catch (error) {
10741
+ const message = error instanceof Error ? error.message : String(error);
10742
+ throw new Error(`Invalid JSON in ${absolutePath}: ${message}`);
10743
+ }
10744
+ if (!isAccessKeyFile(parsed)) {
10745
+ throw new Error(`Invalid PMate access key file: ${absolutePath}`);
10746
+ }
10747
+ if (options.expectedApp && parsed.app !== options.expectedApp) {
10748
+ throw new Error(
10749
+ `Access key app mismatch. expected=${options.expectedApp}, received=${parsed.app}`
10750
+ );
10751
+ }
10752
+ return parsed;
10753
+ }
10754
+ function scanAccessKeyFiles(app) {
10755
+ const dir = resolveAccessKeyDir(app);
10756
+ if (!(0, import_node_fs2.existsSync)(dir)) {
10757
+ return [];
10758
+ }
10759
+ return (0, import_node_fs2.readdirSync)(dir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".access-key.json")).map((entry) => import_node_path3.default.join(dir, entry.name)).flatMap((filePath) => {
10760
+ try {
10761
+ return [{ filePath, key: readAccessKeyFile(filePath, { expectedApp: app }) }];
10762
+ } catch {
10763
+ return [];
10764
+ }
10765
+ }).sort((a, b) => a.key.name.localeCompare(b.key.name) || a.filePath.localeCompare(b.filePath));
10766
+ }
10767
+ function resolveAccessKeyDir(app) {
10768
+ return import_node_path3.default.join(homeDir(), ".pmate", "access-keys", app);
10769
+ }
10770
+ function resolveFilePath(filePath, cwd = process.cwd()) {
10771
+ return import_node_path3.default.isAbsolute(filePath) ? filePath : import_node_path3.default.resolve(cwd, filePath);
10772
+ }
10773
+ function homeDir() {
10774
+ return process.env.HOME || process.env.USERPROFILE || import_node_os2.default.homedir() || process.cwd();
10775
+ }
10776
+ function isAccessKeyFile(value) {
10777
+ if (!value || typeof value !== "object") {
10778
+ return false;
10779
+ }
10780
+ const candidate = value;
10781
+ return candidate.type === "pmate-access-key" && candidate.version === 1 && typeof candidate.id === "string" && !!candidate.id.trim() && typeof candidate.app === "string" && !!candidate.app.trim() && typeof candidate.name === "string" && !!candidate.name.trim() && typeof candidate.secret === "string" && !!candidate.secret.trim() && typeof candidate.expiresAt === "string" && !!candidate.expiresAt.trim() && typeof candidate.createdAt === "string" && !!candidate.createdAt.trim();
10782
+ }
10783
+
10784
+ // src/commands/LoginCommandHandler.ts
10589
10785
  init_sessionStore();
10590
10786
 
10591
10787
  // src/profileClient.ts
@@ -10632,7 +10828,6 @@ function resolveAuthApiBaseUrl(value) {
10632
10828
 
10633
10829
  // src/commands/LoginCommandHandler.ts
10634
10830
  var AUTH_UI_BASE_URL = "https://auth.pmate.chat";
10635
- var AUTH_API_BASE_URL = DEFAULT_AUTH_API_BASE_URL;
10636
10831
  var CALLBACK_PATH = "/pmate-login-callback";
10637
10832
  var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
10638
10833
  function buildHostedLoginUrl(redirectUrl, appId = DEFAULT_APP_ID) {
@@ -10644,6 +10839,13 @@ function buildHostedLoginUrl(redirectUrl, appId = DEFAULT_APP_ID) {
10644
10839
  }
10645
10840
  var LoginCommandHandler = class {
10646
10841
  async handle(args) {
10842
+ if (args.accessKey || args.accessKeyFile || args.accessKeyScan) {
10843
+ await this.handleAccessKeyLogin(args);
10844
+ return;
10845
+ }
10846
+ await this.handleHostedLogin(args);
10847
+ }
10848
+ async handleHostedLogin(args) {
10647
10849
  const callback = await this.startCallbackServer();
10648
10850
  const appId = assertValidAppRef(args.app?.trim() || DEFAULT_APP_ID);
10649
10851
  const loginUrl = buildHostedLoginUrl(callback.redirectUrl, appId);
@@ -10671,6 +10873,7 @@ var LoginCommandHandler = class {
10671
10873
  const profileId = await this.resolveProfileId({
10672
10874
  appId,
10673
10875
  requestedProfileId: args.profileId,
10876
+ selectProfile: args.selectProfile,
10674
10877
  profiles
10675
10878
  });
10676
10879
  savedSession = saveLoginSession({ ...loginResponse, profileId }, appId);
@@ -10683,8 +10886,28 @@ var LoginCommandHandler = class {
10683
10886
  );
10684
10887
  }
10685
10888
  }
10889
+ async handleAccessKeyLogin(args) {
10890
+ const resolved = await this.resolveAccessKeyInput(args);
10891
+ const appId = assertValidAppRef(resolved.app);
10892
+ const loginResponse = await this.exchangeAccessKeySession(resolved.secret, appId);
10893
+ const profiles = await fetchProfiles({
10894
+ token: loginResponse.token,
10895
+ app: appId,
10896
+ accountId: loginResponse.session.identity.accountId
10897
+ });
10898
+ const profileId = await this.resolveProfileId({
10899
+ appId,
10900
+ requestedProfileId: args.profileId,
10901
+ selectProfile: args.selectProfile,
10902
+ profiles
10903
+ });
10904
+ const savedSession = saveLoginSession({ ...loginResponse, profileId }, appId);
10905
+ ui.success(
10906
+ `Logged in to ${savedSession.app}. Session saved to ${savedSession.sessionPath}`
10907
+ );
10908
+ }
10686
10909
  async exchangeSession(token, appId) {
10687
- const response = await fetch(`${AUTH_API_BASE_URL}/session/exchange`, {
10910
+ const response = await fetch(`${resolveAuthApiBaseUrl()}/session/exchange`, {
10688
10911
  method: "POST",
10689
10912
  headers: {
10690
10913
  "Content-Type": "application/json",
@@ -10705,6 +10928,88 @@ var LoginCommandHandler = class {
10705
10928
  }
10706
10929
  return resp.data;
10707
10930
  }
10931
+ async exchangeAccessKeySession(secret, appId) {
10932
+ const response = await fetch(`${resolveAuthApiBaseUrl()}/access-keys/session`, {
10933
+ method: "POST",
10934
+ headers: {
10935
+ "Content-Type": "application/json",
10936
+ Authorization: `Bearer ${secret}`
10937
+ },
10938
+ body: JSON.stringify({ app: appId })
10939
+ });
10940
+ if (!response.ok) {
10941
+ const detail = await response.text();
10942
+ throw new Error(
10943
+ `Failed to exchange access key session (${response.status}): ${detail || response.statusText}`
10944
+ );
10945
+ }
10946
+ const resp = await response.json();
10947
+ const returnedApp = resp?.data?.session?.identity?.app?.trim();
10948
+ if (!returnedApp || returnedApp !== appId) {
10949
+ throw new Error("Invalid access key session response: app-scoped session mismatch.");
10950
+ }
10951
+ return resp.data;
10952
+ }
10953
+ async resolveAccessKeyInput(args) {
10954
+ if (args.accessKey) {
10955
+ return {
10956
+ app: args.app?.trim() || DEFAULT_APP_ID,
10957
+ secret: args.accessKey.trim()
10958
+ };
10959
+ }
10960
+ if (args.accessKeyFile) {
10961
+ const key = readAccessKeyFile(args.accessKeyFile, {
10962
+ expectedApp: args.app?.trim()
10963
+ });
10964
+ return {
10965
+ app: args.app?.trim() || key.app,
10966
+ secret: key.secret
10967
+ };
10968
+ }
10969
+ const app = assertValidAppRef(args.app?.trim() || DEFAULT_APP_ID);
10970
+ const candidate = await this.selectScannedAccessKey(app);
10971
+ return {
10972
+ app,
10973
+ secret: candidate.key.secret
10974
+ };
10975
+ }
10976
+ async selectScannedAccessKey(app) {
10977
+ const candidates = scanAccessKeyFiles(app);
10978
+ if (candidates.length === 0) {
10979
+ throw new Error(
10980
+ `No access key found for app ${app}. Run "pmate account access-key create --app ${app} ..." or "pmate login --access-key-file <path>".`
10981
+ );
10982
+ }
10983
+ if (candidates.length === 1) {
10984
+ return candidates[0];
10985
+ }
10986
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
10987
+ const files = candidates.map((candidate) => candidate.filePath).join(", ");
10988
+ throw new Error(
10989
+ `Multiple access keys found for app ${app}. Run "pmate login --access-key-file <path>" with one of: ${files}`
10990
+ );
10991
+ }
10992
+ ui.info(`Multiple access keys found for ${app}. Select one:`);
10993
+ candidates.forEach((candidate, index) => {
10994
+ ui.plain(`${index + 1}. ${this.formatAccessKeyLabel(candidate)}`);
10995
+ });
10996
+ const rl = (0, import_promises.createInterface)({
10997
+ input: process.stdin,
10998
+ output: process.stdout
10999
+ });
11000
+ try {
11001
+ while (true) {
11002
+ const answer = (await rl.question("Access key number: ")).trim();
11003
+ const index = Number.parseInt(answer, 10);
11004
+ if (Number.isInteger(index) && index >= 1 && index <= candidates.length) {
11005
+ return candidates[index - 1];
11006
+ }
11007
+ ui.warn(`Enter a number from 1 to ${candidates.length}.`);
11008
+ }
11009
+ } finally {
11010
+ rl.close();
11011
+ }
11012
+ }
10708
11013
  async resolveProfileId(input) {
10709
11014
  const requestedProfileId = input.requestedProfileId?.trim();
10710
11015
  if (requestedProfileId) {
@@ -10717,7 +11022,7 @@ var LoginCommandHandler = class {
10717
11022
  if (input.profiles.length === 0) {
10718
11023
  throw new Error(`No profile found for app ${input.appId}.`);
10719
11024
  }
10720
- if (input.profiles.length === 1) {
11025
+ if (input.profiles.length === 1 || !input.selectProfile) {
10721
11026
  return input.profiles[0].id;
10722
11027
  }
10723
11028
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
@@ -10747,6 +11052,17 @@ var LoginCommandHandler = class {
10747
11052
  rl.close();
10748
11053
  }
10749
11054
  }
11055
+ formatAccessKeyLabel(candidate) {
11056
+ const key = candidate.key;
11057
+ const parts = [
11058
+ key.name?.trim(),
11059
+ key.id?.trim(),
11060
+ key.namespace?.trim(),
11061
+ `expires ${key.expiresAt}`,
11062
+ import_node_path5.default.relative(process.cwd(), candidate.filePath)
11063
+ ].filter(Boolean);
11064
+ return parts.join(" / ");
11065
+ }
10750
11066
  formatProfileLabel(profile) {
10751
11067
  const parts = [
10752
11068
  profile.nickName?.trim(),
@@ -10962,8 +11278,8 @@ var import_openapi_client = require("@alicloud/openapi-client");
10962
11278
  var import_sts20150401 = __toESM(require("@alicloud/sts20150401"));
10963
11279
  var import_ali_oss = __toESM(require("ali-oss"));
10964
11280
  var import_node_crypto = require("crypto");
10965
- var import_node_fs3 = require("fs");
10966
- var import_node_path4 = __toESM(require("path"));
11281
+ var import_node_fs4 = require("fs");
11282
+ var import_node_path6 = __toESM(require("path"));
10967
11283
 
10968
11284
  // src/certs.ts
10969
11285
  var DEFAULT_SSL_CERT_KEY = "pmate-01";
@@ -11256,7 +11572,7 @@ var AliyunService = class {
11256
11572
  ])
11257
11573
  );
11258
11574
  for (const filePath of files) {
11259
- const relativePath = import_node_path4.default.relative(localDir, filePath);
11575
+ const relativePath = import_node_path6.default.relative(localDir, filePath);
11260
11576
  const objectKey = this.toObjectKey(normalizedPrefix, relativePath);
11261
11577
  const contentType = this.getContentType(filePath);
11262
11578
  const cacheControl = this.getStaticAssetCacheControl(relativePath);
@@ -11266,7 +11582,7 @@ var AliyunService = class {
11266
11582
  const options = Object.keys(headers).length > 0 ? { headers } : void 0;
11267
11583
  const existing = existingMap.get(objectKey);
11268
11584
  if (existing && typeof existing.size === "number" && !cacheControl) {
11269
- const stat = await import_node_fs3.promises.stat(filePath);
11585
+ const stat = await import_node_fs4.promises.stat(filePath);
11270
11586
  if (stat.size === existing.size) {
11271
11587
  const etag = this.normalizeEtag(existing.etag);
11272
11588
  if (etag && !etag.includes("-")) {
@@ -11291,7 +11607,7 @@ var AliyunService = class {
11291
11607
  if (!region) throw new Error("Missing oss.public.region in ~/.pmate/config.yaml.");
11292
11608
  if (!accessKeyId) throw new Error("Missing aliyun.ak in ~/.pmate/config.yaml.");
11293
11609
  if (!accessKeySecret) throw new Error("Missing aliyun.sk in ~/.pmate/config.yaml.");
11294
- if (!(0, import_node_fs3.existsSync)(localFile)) {
11610
+ if (!(0, import_node_fs4.existsSync)(localFile)) {
11295
11611
  throw new Error(`File not found: ${localFile}`);
11296
11612
  }
11297
11613
  const client = new import_ali_oss.default({ region, accessKeyId, accessKeySecret, bucket });
@@ -11638,10 +11954,10 @@ var AliyunService = class {
11638
11954
  }
11639
11955
  /** Recursively collect file paths under a directory. */
11640
11956
  static async collectFiles(dir) {
11641
- const entries = await import_node_fs3.promises.readdir(dir, { withFileTypes: true });
11957
+ const entries = await import_node_fs4.promises.readdir(dir, { withFileTypes: true });
11642
11958
  const files = [];
11643
11959
  for (const entry of entries) {
11644
- const fullPath = import_node_path4.default.join(dir, entry.name);
11960
+ const fullPath = import_node_path6.default.join(dir, entry.name);
11645
11961
  if (entry.isDirectory()) {
11646
11962
  files.push(...await this.collectFiles(fullPath));
11647
11963
  } else if (entry.isFile()) {
@@ -11690,7 +12006,7 @@ var AliyunService = class {
11690
12006
  static getFileMd5(filePath) {
11691
12007
  return new Promise((resolve, reject) => {
11692
12008
  const hash = (0, import_node_crypto.createHash)("md5");
11693
- const stream = (0, import_node_fs3.createReadStream)(filePath);
12009
+ const stream = (0, import_node_fs4.createReadStream)(filePath);
11694
12010
  stream.on("data", (chunk) => {
11695
12011
  hash.update(chunk);
11696
12012
  });
@@ -11703,17 +12019,17 @@ var AliyunService = class {
11703
12019
  });
11704
12020
  }
11705
12021
  static toObjectKey(prefix, relativePath) {
11706
- const normalizedPath = relativePath.split(import_node_path4.default.sep).join("/");
12022
+ const normalizedPath = relativePath.split(import_node_path6.default.sep).join("/");
11707
12023
  if (!prefix) {
11708
12024
  return normalizedPath;
11709
12025
  }
11710
12026
  return `${prefix}/${normalizedPath}`;
11711
12027
  }
11712
12028
  static getContentType(filePath) {
11713
- if (import_node_path4.default.basename(filePath).toLowerCase() === "apple-app-site-association") {
12029
+ if (import_node_path6.default.basename(filePath).toLowerCase() === "apple-app-site-association") {
11714
12030
  return "application/json";
11715
12031
  }
11716
- const ext = import_node_path4.default.extname(filePath).toLowerCase();
12032
+ const ext = import_node_path6.default.extname(filePath).toLowerCase();
11717
12033
  switch (ext) {
11718
12034
  case ".html":
11719
12035
  return "text/html";
@@ -11756,7 +12072,7 @@ var AliyunService = class {
11756
12072
  }
11757
12073
  static getStaticAssetCacheControl(filePath) {
11758
12074
  const normalized = filePath.replace(/\\/g, "/");
11759
- const base = import_node_path4.default.posix.basename(normalized).toLowerCase();
12075
+ const base = import_node_path6.default.posix.basename(normalized).toLowerCase();
11760
12076
  if (base === "index.html" || base === "200.html" || base === "404.html" || base === "apple-app-site-association") {
11761
12077
  return "no-cache, no-store, must-revalidate";
11762
12078
  }
@@ -11973,7 +12289,7 @@ var BucketCommandHandler = class {
11973
12289
  };
11974
12290
 
11975
12291
  // src/commands/DeleteCommandHandler.ts
11976
- var import_node_path5 = __toESM(require("path"));
12292
+ var import_node_path7 = __toESM(require("path"));
11977
12293
  var import_node_child_process2 = require("child_process");
11978
12294
 
11979
12295
  // src/serverAddress.ts
@@ -12131,17 +12447,17 @@ var DeleteCommandHandler = class {
12131
12447
  });
12132
12448
  }
12133
12449
  resolveCwd(target) {
12134
- return target ? import_node_path5.default.resolve(process.cwd(), target) : process.cwd();
12450
+ return target ? import_node_path7.default.resolve(process.cwd(), target) : process.cwd();
12135
12451
  }
12136
12452
  };
12137
12453
 
12138
12454
  // src/commands/DevCommandHandler.ts
12139
- var import_node_fs4 = require("fs");
12140
- var import_node_path7 = __toESM(require("path"));
12455
+ var import_node_fs5 = require("fs");
12456
+ var import_node_path9 = __toESM(require("path"));
12141
12457
  var import_node_child_process3 = require("child_process");
12142
12458
 
12143
12459
  // src/appDir.ts
12144
- var import_node_path6 = __toESM(require("path"));
12460
+ var import_node_path8 = __toESM(require("path"));
12145
12461
  function normalizeRelativeDir(input, appName) {
12146
12462
  if (typeof input !== "string") {
12147
12463
  throw new Error(`Missing dir for ${appName} in .pmate.yaml`);
@@ -12154,7 +12470,7 @@ function normalizeRelativeDir(input, appName) {
12154
12470
  if (unixLike.startsWith("/")) {
12155
12471
  throw new Error(`Invalid dir for ${appName} in .pmate.yaml: must be relative`);
12156
12472
  }
12157
- const normalized = import_node_path6.default.posix.normalize(unixLike);
12473
+ const normalized = import_node_path8.default.posix.normalize(unixLike);
12158
12474
  if (normalized.startsWith("../") || normalized === "..") {
12159
12475
  throw new Error(
12160
12476
  `Invalid dir for ${appName} in .pmate.yaml: must stay within repo`
@@ -12164,7 +12480,7 @@ function normalizeRelativeDir(input, appName) {
12164
12480
  }
12165
12481
  function resolveLocalAppDir(repoRoot, appName, dir) {
12166
12482
  const relative = normalizeRelativeDir(dir, appName);
12167
- return import_node_path6.default.resolve(repoRoot, relative);
12483
+ return import_node_path8.default.resolve(repoRoot, relative);
12168
12484
  }
12169
12485
  function resolveRemoteAppDir(appName, dir) {
12170
12486
  return normalizeRelativeDir(dir, appName);
@@ -12187,8 +12503,8 @@ var DevCommandHandler = class {
12187
12503
  );
12188
12504
  }
12189
12505
  const appDir = resolveLocalAppDir(cwd, appName, appConfig.dir);
12190
- const packageJsonPath = import_node_path7.default.join(appDir, "package.json");
12191
- if (!(0, import_node_fs4.existsSync)(packageJsonPath)) {
12506
+ const packageJsonPath = import_node_path9.default.join(appDir, "package.json");
12507
+ if (!(0, import_node_fs5.existsSync)(packageJsonPath)) {
12192
12508
  throw new Error(`No package.json found at ${packageJsonPath}`);
12193
12509
  }
12194
12510
  const pkg2 = this.loadPackageJson(packageJsonPath);
@@ -12202,13 +12518,13 @@ var DevCommandHandler = class {
12202
12518
  await this.runCommand("pnpm", ["--filter", pkgName, "run", "dev"], cwd);
12203
12519
  }
12204
12520
  resolveCwd(target) {
12205
- return target ? import_node_path7.default.resolve(process.cwd(), target) : process.cwd();
12521
+ return target ? import_node_path9.default.resolve(process.cwd(), target) : process.cwd();
12206
12522
  }
12207
12523
  loadConfig(cwd) {
12208
12524
  return loadAppConfig(cwd);
12209
12525
  }
12210
12526
  loadPackageJson(packageJsonPath) {
12211
- const raw = (0, import_node_fs4.readFileSync)(packageJsonPath, "utf8");
12527
+ const raw = (0, import_node_fs5.readFileSync)(packageJsonPath, "utf8");
12212
12528
  const parsed = JSON.parse(raw);
12213
12529
  if (!parsed || typeof parsed !== "object") {
12214
12530
  throw new Error(`Invalid package.json at ${packageJsonPath}`);
@@ -12236,8 +12552,8 @@ var DevCommandHandler = class {
12236
12552
  };
12237
12553
 
12238
12554
  // src/commands/OssCommandHandler.ts
12239
- var import_node_fs5 = require("fs");
12240
- var import_node_path8 = __toESM(require("path"));
12555
+ var import_node_fs6 = require("fs");
12556
+ var import_node_path10 = __toESM(require("path"));
12241
12557
  var OssCommandHandler = class _OssCommandHandler {
12242
12558
  static {
12243
12559
  this.DEFAULT_BUCKET = "parrot-static";
@@ -12254,17 +12570,17 @@ var OssCommandHandler = class _OssCommandHandler {
12254
12570
  }
12255
12571
  return;
12256
12572
  }
12257
- const resolvedFile = import_node_path8.default.resolve(process.cwd(), args.filePath);
12573
+ const resolvedFile = import_node_path10.default.resolve(process.cwd(), args.filePath);
12258
12574
  this.assertFile(resolvedFile);
12259
12575
  const objectKey = this.normalizeObjectKey(args.objectKey);
12260
12576
  const bucket = this.resolveBucket(args.bucket);
12261
12577
  await AliyunService.uploadFile(resolvedFile, bucket, objectKey);
12262
12578
  }
12263
12579
  assertFile(filePath) {
12264
- if (!(0, import_node_fs5.existsSync)(filePath)) {
12580
+ if (!(0, import_node_fs6.existsSync)(filePath)) {
12265
12581
  throw new Error(`File not found: ${filePath}`);
12266
12582
  }
12267
- const stat = (0, import_node_fs5.statSync)(filePath);
12583
+ const stat = (0, import_node_fs6.statSync)(filePath);
12268
12584
  if (!stat.isFile()) {
12269
12585
  throw new Error(`Not a file: ${filePath}`);
12270
12586
  }
@@ -12286,7 +12602,7 @@ var OssCommandHandler = class _OssCommandHandler {
12286
12602
  };
12287
12603
 
12288
12604
  // src/commands/EnvCommandHandler.ts
12289
- var import_node_path9 = __toESM(require("path"));
12605
+ var import_node_path11 = __toESM(require("path"));
12290
12606
  var import_node_child_process4 = require("child_process");
12291
12607
 
12292
12608
  // src/shell.ts
@@ -12370,8 +12686,8 @@ var EnvCommandHandler = class {
12370
12686
  ui.success(`Set ${envKey} in .env.local`, appName);
12371
12687
  }
12372
12688
  async listEnvKeys(server, repoDir, appDir, verbose) {
12373
- const envLocalPath = import_node_path9.default.posix.join(appDir, ".env.local");
12374
- const envPath = import_node_path9.default.posix.join(appDir, ".env");
12689
+ const envLocalPath = import_node_path11.default.posix.join(appDir, ".env.local");
12690
+ const envPath = import_node_path11.default.posix.join(appDir, ".env");
12375
12691
  if (verbose) {
12376
12692
  const repoPath = `$HOME/${repoDir}`;
12377
12693
  ui.info("Env list target", {
@@ -12464,8 +12780,8 @@ var EnvCommandHandler = class {
12464
12780
  }
12465
12781
  }
12466
12782
  async appendEnvLine(server, repoDir, appDir, envKey, envLine, verbose) {
12467
- const envLocalPath = import_node_path9.default.posix.join(appDir, ".env.local");
12468
- const envPath = import_node_path9.default.posix.join(appDir, ".env");
12783
+ const envLocalPath = import_node_path11.default.posix.join(appDir, ".env.local");
12784
+ const envPath = import_node_path11.default.posix.join(appDir, ".env");
12469
12785
  if (verbose) {
12470
12786
  const repoPath = `$HOME/${repoDir}`;
12471
12787
  ui.info("Env add target", {
@@ -12513,8 +12829,8 @@ var EnvCommandHandler = class {
12513
12829
  await this.runRemoteCommand(server, command);
12514
12830
  }
12515
12831
  async deleteEnvKey(server, repoDir, appDir, envKey, verbose) {
12516
- const envLocalPath = import_node_path9.default.posix.join(appDir, ".env.local");
12517
- const envPath = import_node_path9.default.posix.join(appDir, ".env");
12832
+ const envLocalPath = import_node_path11.default.posix.join(appDir, ".env.local");
12833
+ const envPath = import_node_path11.default.posix.join(appDir, ".env");
12518
12834
  if (verbose) {
12519
12835
  const repoPath = `$HOME/${repoDir}`;
12520
12836
  ui.info("Env delete target", {
@@ -13330,7 +13646,7 @@ var CommitCommandHandler = class {
13330
13646
 
13331
13647
  // src/commands/SummaryCommandHandler.ts
13332
13648
  var import_node_child_process6 = require("child_process");
13333
- var import_node_path11 = __toESM(require("path"));
13649
+ var import_node_path13 = __toESM(require("path"));
13334
13650
  var SummaryCommandHandler = class {
13335
13651
  async handle(args) {
13336
13652
  const cwd = this.resolveCwd(args.cwd);
@@ -13515,7 +13831,7 @@ var SummaryCommandHandler = class {
13515
13831
  return this.runCapture("gh", args, allowFailure, await this.getGhEnv(cwd), cwd);
13516
13832
  }
13517
13833
  resolveCwd(value) {
13518
- return value ? import_node_path11.default.resolve(process.cwd(), value) : process.cwd();
13834
+ return value ? import_node_path13.default.resolve(process.cwd(), value) : process.cwd();
13519
13835
  }
13520
13836
  };
13521
13837
  function truncate2(value, limit) {
@@ -13528,9 +13844,9 @@ function truncate2(value, limit) {
13528
13844
 
13529
13845
  // src/commands/LinearCommandHandler.ts
13530
13846
  var import_node_child_process7 = require("child_process");
13531
- var import_node_fs7 = require("fs");
13532
- var import_node_os3 = __toESM(require("os"));
13533
- var import_node_path12 = __toESM(require("path"));
13847
+ var import_node_fs8 = require("fs");
13848
+ var import_node_os4 = __toESM(require("os"));
13849
+ var import_node_path14 = __toESM(require("path"));
13534
13850
  var import_promises3 = require("readline/promises");
13535
13851
  var import_openai = __toESM(require("openai"));
13536
13852
  var import_sdk = require("@linear/sdk");
@@ -14414,15 +14730,15 @@ var LinearCommandHandler = class {
14414
14730
  }
14415
14731
  }
14416
14732
  getLinearSelectionPath() {
14417
- return import_node_path12.default.join(import_node_os3.default.homedir(), ".pmate", "linear-selection.json");
14733
+ return import_node_path14.default.join(import_node_os4.default.homedir(), ".pmate", "linear-selection.json");
14418
14734
  }
14419
14735
  readCachedLinearSelection(cwd) {
14420
14736
  const selectionPath = this.getLinearSelectionPath();
14421
- if (!(0, import_node_fs7.existsSync)(selectionPath)) {
14737
+ if (!(0, import_node_fs8.existsSync)(selectionPath)) {
14422
14738
  return void 0;
14423
14739
  }
14424
14740
  try {
14425
- const raw = (0, import_node_fs7.readFileSync)(selectionPath, "utf8").trim();
14741
+ const raw = (0, import_node_fs8.readFileSync)(selectionPath, "utf8").trim();
14426
14742
  if (!raw) return void 0;
14427
14743
  const parsed = JSON.parse(raw);
14428
14744
  const value = parsed[cwd];
@@ -14433,12 +14749,12 @@ var LinearCommandHandler = class {
14433
14749
  }
14434
14750
  writeCachedLinearSelection(cwd, title) {
14435
14751
  const selectionPath = this.getLinearSelectionPath();
14436
- const dir = import_node_path12.default.dirname(selectionPath);
14437
- (0, import_node_fs7.mkdirSync)(dir, { recursive: true });
14752
+ const dir = import_node_path14.default.dirname(selectionPath);
14753
+ (0, import_node_fs8.mkdirSync)(dir, { recursive: true });
14438
14754
  let data = {};
14439
- if ((0, import_node_fs7.existsSync)(selectionPath)) {
14755
+ if ((0, import_node_fs8.existsSync)(selectionPath)) {
14440
14756
  try {
14441
- const raw = (0, import_node_fs7.readFileSync)(selectionPath, "utf8").trim();
14757
+ const raw = (0, import_node_fs8.readFileSync)(selectionPath, "utf8").trim();
14442
14758
  if (raw) {
14443
14759
  data = JSON.parse(raw);
14444
14760
  }
@@ -14447,7 +14763,7 @@ var LinearCommandHandler = class {
14447
14763
  }
14448
14764
  }
14449
14765
  data[cwd] = title;
14450
- (0, import_node_fs7.writeFileSync)(selectionPath, `${JSON.stringify(data, null, 2)}
14766
+ (0, import_node_fs8.writeFileSync)(selectionPath, `${JSON.stringify(data, null, 2)}
14451
14767
  `, "utf8");
14452
14768
  }
14453
14769
  async lookupIssue(client, issueRef) {
@@ -14624,14 +14940,14 @@ var LinearCommandHandler = class {
14624
14940
  if (process.platform !== "darwin") {
14625
14941
  throw new Error("Screenshot capture only supports macOS.");
14626
14942
  }
14627
- const dir = await import_node_fs7.promises.mkdtemp(import_node_path12.default.join(import_node_os3.default.tmpdir(), "pmate-screenshot-"));
14628
- const filePath = import_node_path12.default.join(dir, `screenshot-${index}.png`);
14943
+ const dir = await import_node_fs8.promises.mkdtemp(import_node_path14.default.join(import_node_os4.default.tmpdir(), "pmate-screenshot-"));
14944
+ const filePath = import_node_path14.default.join(dir, `screenshot-${index}.png`);
14629
14945
  try {
14630
14946
  const code = await this.run("screencapture", ["-i", "-x", filePath], true);
14631
14947
  if (code !== 0) {
14632
14948
  throw new Error("Screenshot capture canceled or failed.");
14633
14949
  }
14634
- const buffer = await import_node_fs7.promises.readFile(filePath);
14950
+ const buffer = await import_node_fs8.promises.readFile(filePath);
14635
14951
  if (buffer.length === 0) {
14636
14952
  throw new Error("Screenshot capture produced an empty file.");
14637
14953
  }
@@ -14643,7 +14959,7 @@ var LinearCommandHandler = class {
14643
14959
  return { buffer, mime, filename: `screenshot-${index}.${extension}` };
14644
14960
  } finally {
14645
14961
  try {
14646
- await import_node_fs7.promises.rm(dir, { recursive: true, force: true });
14962
+ await import_node_fs8.promises.rm(dir, { recursive: true, force: true });
14647
14963
  } catch {
14648
14964
  }
14649
14965
  }
@@ -14787,17 +15103,17 @@ var LinearCommandHandler = class {
14787
15103
  return compact.length > limit ? `${compact.slice(0, limit)}...` : compact;
14788
15104
  }
14789
15105
  async convertToPng(buffer, ext) {
14790
- const dir = await import_node_fs7.promises.mkdtemp(import_node_path12.default.join(import_node_os3.default.tmpdir(), "pmate-"));
14791
- const inputPath = import_node_path12.default.join(dir, `clipboard.${ext}`);
14792
- const outputPath = import_node_path12.default.join(dir, "clipboard.png");
15106
+ const dir = await import_node_fs8.promises.mkdtemp(import_node_path14.default.join(import_node_os4.default.tmpdir(), "pmate-"));
15107
+ const inputPath = import_node_path14.default.join(dir, `clipboard.${ext}`);
15108
+ const outputPath = import_node_path14.default.join(dir, "clipboard.png");
14793
15109
  try {
14794
- await import_node_fs7.promises.writeFile(inputPath, buffer);
15110
+ await import_node_fs8.promises.writeFile(inputPath, buffer);
14795
15111
  const stderr = await this.runCapture(
14796
15112
  "sips",
14797
15113
  ["-s", "format", "png", inputPath, "--out", outputPath],
14798
15114
  true
14799
15115
  );
14800
- const out = await import_node_fs7.promises.readFile(outputPath);
15116
+ const out = await import_node_fs8.promises.readFile(outputPath);
14801
15117
  if (this.detectImageMime(out) !== "image/png") {
14802
15118
  throw new Error(
14803
15119
  stderr?.trim() ? `Failed to convert clipboard ${ext} to PNG: ${stderr.trim()}` : `Failed to convert clipboard ${ext} to PNG.`
@@ -14806,7 +15122,7 @@ var LinearCommandHandler = class {
14806
15122
  return out;
14807
15123
  } finally {
14808
15124
  try {
14809
- await import_node_fs7.promises.rm(dir, { recursive: true, force: true });
15125
+ await import_node_fs8.promises.rm(dir, { recursive: true, force: true });
14810
15126
  } catch {
14811
15127
  }
14812
15128
  }
@@ -15100,7 +15416,7 @@ var LinearCommandHandler = class {
15100
15416
  return this.runCapture("gh", args, allowFailure, await this.getGhEnv(cwd), cwd);
15101
15417
  }
15102
15418
  resolveCwd(value) {
15103
- return value ? import_node_path12.default.resolve(process.cwd(), value) : process.cwd();
15419
+ return value ? import_node_path14.default.resolve(process.cwd(), value) : process.cwd();
15104
15420
  }
15105
15421
  createOpenAiClient() {
15106
15422
  const config = loadPmateConfig();
@@ -15152,8 +15468,8 @@ function sleep2(ms) {
15152
15468
  }
15153
15469
 
15154
15470
  // src/commands/NotionCommandHandler.ts
15155
- var import_node_fs8 = require("fs");
15156
- var import_node_path13 = __toESM(require("path"));
15471
+ var import_node_fs9 = require("fs");
15472
+ var import_node_path15 = __toESM(require("path"));
15157
15473
 
15158
15474
  // src/services/NotionService.ts
15159
15475
  var NotionService = class {
@@ -15392,9 +15708,9 @@ ${indent}\`\`\``;
15392
15708
  static richTextToPlain(richText) {
15393
15709
  return richText.map((item) => item.plain_text ?? item.text?.content ?? "").join("").trim();
15394
15710
  }
15395
- static async requestJson(path29, init) {
15711
+ static async requestJson(path31, init) {
15396
15712
  const token = this.getToken();
15397
- const response = await fetch(`${this.baseUrl}${path29}`, {
15713
+ const response = await fetch(`${this.baseUrl}${path31}`, {
15398
15714
  method: init.method,
15399
15715
  headers: {
15400
15716
  Authorization: `Bearer ${token}`,
@@ -15492,16 +15808,16 @@ var NotionCommandHandler = class {
15492
15808
  if (!args.filePath) {
15493
15809
  return "";
15494
15810
  }
15495
- const resolved = import_node_path13.default.resolve(process.cwd(), args.filePath);
15496
- return (0, import_node_fs8.readFileSync)(resolved, "utf8");
15811
+ const resolved = import_node_path15.default.resolve(process.cwd(), args.filePath);
15812
+ return (0, import_node_fs9.readFileSync)(resolved, "utf8");
15497
15813
  }
15498
15814
  };
15499
15815
 
15500
15816
  // src/commands/QrcodeCommandHandler.ts
15501
15817
  var import_node_child_process8 = require("child_process");
15502
- var import_node_fs9 = require("fs");
15503
- var import_node_os4 = __toESM(require("os"));
15504
- var import_node_path14 = __toESM(require("path"));
15818
+ var import_node_fs10 = require("fs");
15819
+ var import_node_os5 = __toESM(require("os"));
15820
+ var import_node_path16 = __toESM(require("path"));
15505
15821
  var import_promises4 = require("readline/promises");
15506
15822
  var import_jsqr = __toESM(require("jsqr"));
15507
15823
  var import_pngjs = require("pngjs");
@@ -15527,7 +15843,7 @@ var QrcodeCommandHandler = class {
15527
15843
  ui.success("QR code value:", value);
15528
15844
  } finally {
15529
15845
  try {
15530
- await import_node_fs9.promises.rm(dir, { recursive: true, force: true });
15846
+ await import_node_fs10.promises.rm(dir, { recursive: true, force: true });
15531
15847
  } catch {
15532
15848
  }
15533
15849
  }
@@ -15543,13 +15859,13 @@ var QrcodeCommandHandler = class {
15543
15859
  } finally {
15544
15860
  rl.close();
15545
15861
  }
15546
- const dir = await import_node_fs9.promises.mkdtemp(import_node_path14.default.join(import_node_os4.default.tmpdir(), "pmate-qrcode-"));
15547
- const filePath = import_node_path14.default.join(dir, "qrcode.png");
15862
+ const dir = await import_node_fs10.promises.mkdtemp(import_node_path16.default.join(import_node_os5.default.tmpdir(), "pmate-qrcode-"));
15863
+ const filePath = import_node_path16.default.join(dir, "qrcode.png");
15548
15864
  const code = await this.run("screencapture", ["-i", "-x", filePath], true);
15549
15865
  if (code !== 0) {
15550
15866
  throw new Error("Screenshot capture canceled or failed.");
15551
15867
  }
15552
- const buffer = await import_node_fs9.promises.readFile(filePath);
15868
+ const buffer = await import_node_fs10.promises.readFile(filePath);
15553
15869
  if (buffer.length === 0) {
15554
15870
  throw new Error("Screenshot capture produced an empty file.");
15555
15871
  }
@@ -15565,7 +15881,7 @@ var QrcodeCommandHandler = class {
15565
15881
  async decodeQr(filePath) {
15566
15882
  let buffer;
15567
15883
  try {
15568
- buffer = await import_node_fs9.promises.readFile(filePath);
15884
+ buffer = await import_node_fs10.promises.readFile(filePath);
15569
15885
  } catch {
15570
15886
  return null;
15571
15887
  }
@@ -15823,8 +16139,8 @@ function clampNumber(value, min, max, fallback) {
15823
16139
  }
15824
16140
 
15825
16141
  // src/commands/QuizCommandHandler.ts
15826
- var import_node_fs10 = require("fs");
15827
- var import_node_path15 = __toESM(require("path"));
16142
+ var import_node_fs11 = require("fs");
16143
+ var import_node_path17 = __toESM(require("path"));
15828
16144
  init_sessionStore();
15829
16145
 
15830
16146
  // src/services/QuizService.ts
@@ -16369,8 +16685,8 @@ var QuizCommandHandler = class {
16369
16685
  return;
16370
16686
  }
16371
16687
  if (args.action === "update-meta") {
16372
- const resolvedFilePath = import_node_path15.default.resolve(process.cwd(), args.filePath);
16373
- const metadata = JSON.parse((0, import_node_fs10.readFileSync)(resolvedFilePath, "utf8"));
16688
+ const resolvedFilePath = import_node_path17.default.resolve(process.cwd(), args.filePath);
16689
+ const metadata = JSON.parse((0, import_node_fs11.readFileSync)(resolvedFilePath, "utf8"));
16374
16690
  const result = await updateQuizPaperMetadata({
16375
16691
  apiBaseUrl,
16376
16692
  linkBaseUrl,
@@ -16382,8 +16698,8 @@ var QuizCommandHandler = class {
16382
16698
  return;
16383
16699
  }
16384
16700
  if (args.action === "append-step") {
16385
- const resolvedFilePath = import_node_path15.default.resolve(process.cwd(), args.filePath);
16386
- const step = JSON.parse((0, import_node_fs10.readFileSync)(resolvedFilePath, "utf8"));
16701
+ const resolvedFilePath = import_node_path17.default.resolve(process.cwd(), args.filePath);
16702
+ const step = JSON.parse((0, import_node_fs11.readFileSync)(resolvedFilePath, "utf8"));
16387
16703
  const result = await appendQuizPaperStep({
16388
16704
  apiBaseUrl,
16389
16705
  linkBaseUrl,
@@ -16396,8 +16712,8 @@ var QuizCommandHandler = class {
16396
16712
  return;
16397
16713
  }
16398
16714
  if (args.action === "update-step") {
16399
- const resolvedFilePath = import_node_path15.default.resolve(process.cwd(), args.filePath);
16400
- const step = JSON.parse((0, import_node_fs10.readFileSync)(resolvedFilePath, "utf8"));
16715
+ const resolvedFilePath = import_node_path17.default.resolve(process.cwd(), args.filePath);
16716
+ const step = JSON.parse((0, import_node_fs11.readFileSync)(resolvedFilePath, "utf8"));
16401
16717
  step.stepId = args.stepId;
16402
16718
  const result = await updateQuizPaperStep({
16403
16719
  apiBaseUrl,
@@ -16460,8 +16776,8 @@ var QuizCommandHandler = class {
16460
16776
  if (targetIndex < 0) {
16461
16777
  throw new Error(`\u672A\u627E\u5230 stepId=${args.stepId}\uFF0C\u65E0\u6CD5\u66F4\u65B0\u8BE5\u9898\u76EE\u3002`);
16462
16778
  }
16463
- const resolvedFilePath = import_node_path15.default.resolve(process.cwd(), args.filePath);
16464
- const nextStep = JSON.parse((0, import_node_fs10.readFileSync)(resolvedFilePath, "utf8"));
16779
+ const resolvedFilePath = import_node_path17.default.resolve(process.cwd(), args.filePath);
16780
+ const nextStep = JSON.parse((0, import_node_fs11.readFileSync)(resolvedFilePath, "utf8"));
16465
16781
  nextStep.stepId = args.stepId;
16466
16782
  const nextSteps = [...basePaper.steps];
16467
16783
  nextSteps[targetIndex] = nextStep;
@@ -16511,9 +16827,9 @@ var QuizCommandHandler = class {
16511
16827
  };
16512
16828
 
16513
16829
  // src/commands/CollectCommandHandler.ts
16514
- var import_node_fs12 = require("fs");
16515
- var import_node_os6 = __toESM(require("os"));
16516
- var import_node_path17 = __toESM(require("path"));
16830
+ var import_node_fs13 = require("fs");
16831
+ var import_node_os7 = __toESM(require("os"));
16832
+ var import_node_path19 = __toESM(require("path"));
16517
16833
  var import_playwright = require("playwright");
16518
16834
 
16519
16835
  // src/im1BotClient.ts
@@ -16579,13 +16895,13 @@ var Im1BotClient = class {
16579
16895
 
16580
16896
  // src/collectStore.ts
16581
16897
  var import_node_crypto3 = require("crypto");
16582
- var import_node_fs11 = require("fs");
16583
- var import_node_os5 = __toESM(require("os"));
16584
- var import_node_path16 = __toESM(require("path"));
16898
+ var import_node_fs12 = require("fs");
16899
+ var import_node_os6 = __toESM(require("os"));
16900
+ var import_node_path18 = __toESM(require("path"));
16585
16901
  function resolveCollectTarget(input) {
16586
16902
  const endpoint = input.endpoint ?? (input.source === "cc" ? "http://localhost:9223" : "http://localhost:9222");
16587
16903
  const sourceKey = input.source ?? `endpoint-${(0, import_node_crypto3.createHash)("sha1").update(endpoint).digest("hex").slice(0, 8)}`;
16588
- const rootDir = import_node_path16.default.join(import_node_os5.default.homedir(), ".pmate", "collect", sourceKey);
16904
+ const rootDir = import_node_path18.default.join(import_node_os6.default.homedir(), ".pmate", "collect", sourceKey);
16589
16905
  return { sourceKey, endpoint, rootDir };
16590
16906
  }
16591
16907
  function toThreadKey(name) {
@@ -16597,7 +16913,7 @@ function toThreadKey(name) {
16597
16913
  async function readStoredThread(rootDir, threadKey) {
16598
16914
  const filePath = getThreadMetaFilePath(rootDir, threadKey);
16599
16915
  try {
16600
- const raw = await import_node_fs11.promises.readFile(filePath, "utf8");
16916
+ const raw = await import_node_fs12.promises.readFile(filePath, "utf8");
16601
16917
  const parsed = JSON.parse(raw);
16602
16918
  if ("messages" in parsed && Array.isArray(parsed.messages)) {
16603
16919
  return parsed;
@@ -16615,15 +16931,15 @@ async function writeStoredThread(rootDir, thread) {
16615
16931
  const metaPath = getThreadMetaFilePath(rootDir, thread.threadKey);
16616
16932
  const messagePath = getThreadMessagesFilePath(rootDir, thread.threadKey);
16617
16933
  const { messages: messages2, ...meta } = thread;
16618
- await import_node_fs11.promises.mkdir(import_node_path16.default.dirname(metaPath), { recursive: true });
16619
- await import_node_fs11.promises.writeFile(metaPath, JSON.stringify(meta, null, 2) + "\n", "utf8");
16934
+ await import_node_fs12.promises.mkdir(import_node_path18.default.dirname(metaPath), { recursive: true });
16935
+ await import_node_fs12.promises.writeFile(metaPath, JSON.stringify(meta, null, 2) + "\n", "utf8");
16620
16936
  const body = messages2.map((message) => JSON.stringify(message)).join("\n");
16621
- await import_node_fs11.promises.writeFile(messagePath, `${body}${body ? "\n" : ""}`, "utf8");
16937
+ await import_node_fs12.promises.writeFile(messagePath, `${body}${body ? "\n" : ""}`, "utf8");
16622
16938
  }
16623
16939
  async function writeStoredIndex(rootDir, index) {
16624
- await import_node_fs11.promises.mkdir(rootDir, { recursive: true });
16625
- const filePath = import_node_path16.default.join(rootDir, "index.json");
16626
- await import_node_fs11.promises.writeFile(filePath, JSON.stringify(index, null, 2) + "\n", "utf8");
16940
+ await import_node_fs12.promises.mkdir(rootDir, { recursive: true });
16941
+ const filePath = import_node_path18.default.join(rootDir, "index.json");
16942
+ await import_node_fs12.promises.writeFile(filePath, JSON.stringify(index, null, 2) + "\n", "utf8");
16627
16943
  }
16628
16944
  function diffMessages(existing, incoming) {
16629
16945
  const seenMessageIds = new Set(
@@ -16697,7 +17013,7 @@ function joinNormalized(values) {
16697
17013
  async function readStoredMessages(rootDir, threadKey) {
16698
17014
  const filePath = getThreadMessagesFilePath(rootDir, threadKey);
16699
17015
  try {
16700
- const raw = await import_node_fs11.promises.readFile(filePath, "utf8");
17016
+ const raw = await import_node_fs12.promises.readFile(filePath, "utf8");
16701
17017
  return raw.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => normalizeStoredMessage(JSON.parse(line)));
16702
17018
  } catch {
16703
17019
  return [];
@@ -16706,20 +17022,20 @@ async function readStoredMessages(rootDir, threadKey) {
16706
17022
  async function readLegacyStoredThread(rootDir, threadKey) {
16707
17023
  const filePath = getLegacyThreadFilePath(rootDir, threadKey);
16708
17024
  try {
16709
- const raw = await import_node_fs11.promises.readFile(filePath, "utf8");
17025
+ const raw = await import_node_fs12.promises.readFile(filePath, "utf8");
16710
17026
  return JSON.parse(raw);
16711
17027
  } catch {
16712
17028
  return null;
16713
17029
  }
16714
17030
  }
16715
17031
  function getThreadMetaFilePath(rootDir, threadKey) {
16716
- return import_node_path16.default.join(rootDir, "threads", `${threadKey}.json`);
17032
+ return import_node_path18.default.join(rootDir, "threads", `${threadKey}.json`);
16717
17033
  }
16718
17034
  function getThreadMessagesFilePath(rootDir, threadKey) {
16719
- return import_node_path16.default.join(rootDir, "threads", `${threadKey}.jsonl`);
17035
+ return import_node_path18.default.join(rootDir, "threads", `${threadKey}.jsonl`);
16720
17036
  }
16721
17037
  function getLegacyThreadFilePath(rootDir, threadKey) {
16722
- return import_node_path16.default.join(rootDir, "threads", `${threadKey}.json`);
17038
+ return import_node_path18.default.join(rootDir, "threads", `${threadKey}.json`);
16723
17039
  }
16724
17040
  function normalizeStoredMessage(message) {
16725
17041
  return {
@@ -16958,7 +17274,7 @@ var CollectCommandHandler = class {
16958
17274
  }
16959
17275
  async writeSyncReport(rootDir, target, results, failures, syncedAt) {
16960
17276
  const syncId = toSyncId(syncedAt);
16961
- const reportPath = import_node_path17.default.join(rootDir, "syncs", `${syncId}.json`);
17277
+ const reportPath = import_node_path19.default.join(rootDir, "syncs", `${syncId}.json`);
16962
17278
  const threadReports = results.map((result) => ({
16963
17279
  threadKey: result.thread.threadKey,
16964
17280
  threadName: result.thread.threadName,
@@ -16967,8 +17283,8 @@ var CollectCommandHandler = class {
16967
17283
  addedMessages: result.diff.added,
16968
17284
  upgradedMessages: result.diff.upgraded
16969
17285
  })).filter((thread) => thread.addedCount > 0 || thread.upgradedCount > 0);
16970
- await import_node_fs12.promises.mkdir(import_node_path17.default.dirname(reportPath), { recursive: true });
16971
- await import_node_fs12.promises.writeFile(
17286
+ await import_node_fs13.promises.mkdir(import_node_path19.default.dirname(reportPath), { recursive: true });
17287
+ await import_node_fs13.promises.writeFile(
16972
17288
  reportPath,
16973
17289
  JSON.stringify(
16974
17290
  {
@@ -17146,19 +17462,19 @@ async function archiveMessageImage(rootDir, attachmentRoot, threadKey, imagePath
17146
17462
  if (!imagePath || isExternalImageRef(imagePath)) {
17147
17463
  return imagePath;
17148
17464
  }
17149
- const normalized = import_node_path17.default.posix.normalize(imagePath.replace(/\\/g, "/"));
17465
+ const normalized = import_node_path19.default.posix.normalize(imagePath.replace(/\\/g, "/"));
17150
17466
  if (normalized.startsWith("attachments/")) {
17151
- return import_node_path17.default.join(rootDir, ...normalized.split("/"));
17467
+ return import_node_path19.default.join(rootDir, ...normalized.split("/"));
17152
17468
  }
17153
- if (normalized.startsWith("../") || import_node_path17.default.posix.isAbsolute(normalized)) {
17469
+ if (normalized.startsWith("../") || import_node_path19.default.posix.isAbsolute(normalized)) {
17154
17470
  return imagePath;
17155
17471
  }
17156
- const sourcePath = import_node_path17.default.join(attachmentRoot, ...normalized.split("/"));
17157
- const destinationRelativePath = import_node_path17.default.posix.join("attachments", threadKey, normalized);
17158
- const destinationPath = import_node_path17.default.join(rootDir, ...destinationRelativePath.split("/"));
17472
+ const sourcePath = import_node_path19.default.join(attachmentRoot, ...normalized.split("/"));
17473
+ const destinationRelativePath = import_node_path19.default.posix.join("attachments", threadKey, normalized);
17474
+ const destinationPath = import_node_path19.default.join(rootDir, ...destinationRelativePath.split("/"));
17159
17475
  try {
17160
- await import_node_fs12.promises.mkdir(import_node_path17.default.dirname(destinationPath), { recursive: true });
17161
- await import_node_fs12.promises.copyFile(sourcePath, destinationPath);
17476
+ await import_node_fs13.promises.mkdir(import_node_path19.default.dirname(destinationPath), { recursive: true });
17477
+ await import_node_fs13.promises.copyFile(sourcePath, destinationPath);
17162
17478
  return destinationPath;
17163
17479
  } catch {
17164
17480
  return imagePath;
@@ -17168,7 +17484,7 @@ function resolveLocalAttachmentRoot(sourceKey) {
17168
17484
  if (sourceKey !== "cc" && sourceKey !== "yelling") {
17169
17485
  return null;
17170
17486
  }
17171
- return import_node_path17.default.join(import_node_os6.default.homedir(), "Library", "Application Support", sourceKey, "attachments.noindex");
17487
+ return import_node_path19.default.join(import_node_os7.default.homedir(), "Library", "Application Support", sourceKey, "attachments.noindex");
17172
17488
  }
17173
17489
  function isExternalImageRef(imagePath) {
17174
17490
  return /^[a-z][a-z0-9+.-]*:/i.test(imagePath);
@@ -17780,7 +18096,7 @@ function pad2(value) {
17780
18096
  }
17781
18097
 
17782
18098
  // src/commands/ChatRoomCommandHandler.ts
17783
- var import_node_fs13 = require("fs");
18099
+ var import_node_fs14 = require("fs");
17784
18100
  var ChatRoomCommandHandler = class {
17785
18101
  async handle(args) {
17786
18102
  const sdk = await loadChatSdk();
@@ -17830,8 +18146,8 @@ var ChatRoomCommandHandler = class {
17830
18146
  const a = await this.connect(sdk, args.botA, args.app, args.hubUrl, args.authBaseUrl);
17831
18147
  const b = await this.connect(sdk, args.botB, args.app, args.hubUrl, args.authBaseUrl);
17832
18148
  try {
17833
- const botA = sdk.parsePmateBotKeyJson((0, import_node_fs13.readFileSync)(args.botA, "utf8"));
17834
- const botB = sdk.parsePmateBotKeyJson((0, import_node_fs13.readFileSync)(args.botB, "utf8"));
18149
+ const botA = sdk.parsePmateBotKeyJson((0, import_node_fs14.readFileSync)(args.botA, "utf8"));
18150
+ const botB = sdk.parsePmateBotKeyJson((0, import_node_fs14.readFileSync)(args.botB, "utf8"));
17835
18151
  await a.requestFriend({ to: botB.name, message: "smoke friend request" });
17836
18152
  await b.acceptFriend({ to: botA.name, message: "smoke friend accept" });
17837
18153
  await a.sendDm({ to: botB.name, text: "smoke dm from a" });
@@ -17850,7 +18166,7 @@ var ChatRoomCommandHandler = class {
17850
18166
  if (!botPath) {
17851
18167
  throw new Error("Missing required option: --bot");
17852
18168
  }
17853
- const botKey = sdk.parsePmateBotKeyJson((0, import_node_fs13.readFileSync)(botPath, "utf8"));
18169
+ const botKey = sdk.parsePmateBotKeyJson((0, import_node_fs14.readFileSync)(botPath, "utf8"));
17854
18170
  const client = sdk.createChatClient({ appId, botKey, hubUrl, authBaseUrl });
17855
18171
  await client.connect();
17856
18172
  return client;
@@ -17862,8 +18178,8 @@ async function loadChatSdk() {
17862
18178
  }
17863
18179
 
17864
18180
  // src/commands/AgentCommandHandler.ts
17865
- var import_node_fs14 = require("fs");
17866
- var import_node_path18 = __toESM(require("path"));
18181
+ var import_node_fs15 = require("fs");
18182
+ var import_node_path20 = __toESM(require("path"));
17867
18183
  init_AgentLlmClient();
17868
18184
  init_sessionStore();
17869
18185
 
@@ -17896,8 +18212,8 @@ function descriptorPathSegments(descriptor) {
17896
18212
  return ["chains", normalized.chain, "namespaces", normalized.ns, normalized.kind, normalized.name];
17897
18213
  }
17898
18214
  function buildPathUrl(baseUrl, pathSegments, query) {
17899
- const path29 = `/${pathSegments.map((segment) => encodeURIComponent(segment)).join("/")}`;
17900
- const url = new URL(path29, baseUrl);
18215
+ const path31 = `/${pathSegments.map((segment) => encodeURIComponent(segment)).join("/")}`;
18216
+ const url = new URL(path31, baseUrl);
17901
18217
  if (query) {
17902
18218
  for (const [key, value] of Object.entries(query)) {
17903
18219
  url.searchParams.set(key, String(value));
@@ -18354,11 +18670,11 @@ var AgentCommandHandler = class {
18354
18670
  }).token;
18355
18671
  }
18356
18672
  readJsonFile(filePath) {
18357
- const absolutePath = import_node_path18.default.resolve(process.cwd(), filePath);
18358
- if (!(0, import_node_fs14.existsSync)(absolutePath)) {
18673
+ const absolutePath = import_node_path20.default.resolve(process.cwd(), filePath);
18674
+ if (!(0, import_node_fs15.existsSync)(absolutePath)) {
18359
18675
  throw new Error(`JSON file not found: ${absolutePath}`);
18360
18676
  }
18361
- const raw = (0, import_node_fs14.readFileSync)(absolutePath, "utf8");
18677
+ const raw = (0, import_node_fs15.readFileSync)(absolutePath, "utf8");
18362
18678
  try {
18363
18679
  return JSON.parse(raw);
18364
18680
  } catch (error) {
@@ -18369,14 +18685,14 @@ var AgentCommandHandler = class {
18369
18685
  readJsonObjectFile(filePath) {
18370
18686
  const parsed = this.readJsonFile(filePath);
18371
18687
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
18372
- const absolutePath = import_node_path18.default.resolve(process.cwd(), filePath);
18688
+ const absolutePath = import_node_path20.default.resolve(process.cwd(), filePath);
18373
18689
  throw new Error(`Invalid JSON in ${absolutePath}: expected an object`);
18374
18690
  }
18375
18691
  return parsed;
18376
18692
  }
18377
18693
  tryReadJsonObjectFile(filePath) {
18378
18694
  const absolutePath = this.resolveExistingFile(filePath);
18379
- const raw = (0, import_node_fs14.readFileSync)(absolutePath, "utf8");
18695
+ const raw = (0, import_node_fs15.readFileSync)(absolutePath, "utf8");
18380
18696
  try {
18381
18697
  const parsed = JSON.parse(raw);
18382
18698
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
@@ -18388,8 +18704,8 @@ var AgentCommandHandler = class {
18388
18704
  }
18389
18705
  }
18390
18706
  resolveExistingFile(filePath) {
18391
- const absolutePath = import_node_path18.default.resolve(process.cwd(), filePath);
18392
- if (!(0, import_node_fs14.existsSync)(absolutePath)) {
18707
+ const absolutePath = import_node_path20.default.resolve(process.cwd(), filePath);
18708
+ if (!(0, import_node_fs15.existsSync)(absolutePath)) {
18393
18709
  throw new Error(`File not found: ${absolutePath}`);
18394
18710
  }
18395
18711
  return absolutePath;
@@ -18473,8 +18789,8 @@ var AgentCommandHandler = class {
18473
18789
  };
18474
18790
 
18475
18791
  // src/commands/RunnerCommandHandler.ts
18476
- var import_node_fs15 = require("fs");
18477
- var import_node_path19 = __toESM(require("path"));
18792
+ var import_node_fs16 = require("fs");
18793
+ var import_node_path21 = __toESM(require("path"));
18478
18794
  init_sessionStore();
18479
18795
  init_namespacedRef();
18480
18796
  var RunnerCommandHandler = class {
@@ -18569,11 +18885,11 @@ var RunnerCommandHandler = class {
18569
18885
  }).token;
18570
18886
  }
18571
18887
  readJsonFile(filePath) {
18572
- const absolutePath = import_node_path19.default.resolve(process.cwd(), filePath);
18573
- if (!(0, import_node_fs15.existsSync)(absolutePath)) {
18888
+ const absolutePath = import_node_path21.default.resolve(process.cwd(), filePath);
18889
+ if (!(0, import_node_fs16.existsSync)(absolutePath)) {
18574
18890
  throw new Error(`JSON file not found: ${absolutePath}`);
18575
18891
  }
18576
- const raw = (0, import_node_fs15.readFileSync)(absolutePath, "utf8");
18892
+ const raw = (0, import_node_fs16.readFileSync)(absolutePath, "utf8");
18577
18893
  try {
18578
18894
  return JSON.parse(raw);
18579
18895
  } catch (error) {
@@ -18692,8 +19008,8 @@ var NsCommandHandler = class {
18692
19008
  };
18693
19009
 
18694
19010
  // src/commands/StoreCommandHandler.ts
18695
- var import_node_fs16 = require("fs");
18696
- var import_node_path20 = __toESM(require("path"));
19011
+ var import_node_fs17 = require("fs");
19012
+ var import_node_path22 = __toESM(require("path"));
18697
19013
  var StoreCommandHandler = class {
18698
19014
  async handle(args) {
18699
19015
  if (args.scope === "namespace") {
@@ -18835,11 +19151,11 @@ var StoreCommandHandler = class {
18835
19151
  return payload.data ?? [];
18836
19152
  }
18837
19153
  readJsonFile(filePath) {
18838
- const absolutePath = import_node_path20.default.resolve(process.cwd(), filePath);
18839
- if (!(0, import_node_fs16.existsSync)(absolutePath)) {
19154
+ const absolutePath = import_node_path22.default.resolve(process.cwd(), filePath);
19155
+ if (!(0, import_node_fs17.existsSync)(absolutePath)) {
18840
19156
  throw new Error(`JSON file not found: ${absolutePath}`);
18841
19157
  }
18842
- const raw = (0, import_node_fs16.readFileSync)(absolutePath, "utf8");
19158
+ const raw = (0, import_node_fs17.readFileSync)(absolutePath, "utf8");
18843
19159
  try {
18844
19160
  return JSON.parse(raw);
18845
19161
  } catch (error) {
@@ -18891,14 +19207,14 @@ var StoreCommandHandler = class {
18891
19207
  };
18892
19208
 
18893
19209
  // src/commands/AppCommandHandler.ts
18894
- var import_node_fs18 = require("fs");
18895
- var import_node_path22 = __toESM(require("path"));
19210
+ var import_node_fs19 = require("fs");
19211
+ var import_node_path24 = __toESM(require("path"));
18896
19212
  init_sessionStore();
18897
19213
 
18898
19214
  // src/appIcon.ts
18899
- var import_node_fs17 = require("fs");
18900
- var import_node_os7 = __toESM(require("os"));
18901
- var import_node_path21 = __toESM(require("path"));
19215
+ var import_node_fs18 = require("fs");
19216
+ var import_node_os8 = __toESM(require("os"));
19217
+ var import_node_path23 = __toESM(require("path"));
18902
19218
  var import_sharp = __toESM(require("sharp"));
18903
19219
  init_namespacedRef();
18904
19220
  var ANDROID_ICON_SPECS = [
@@ -19003,13 +19319,13 @@ function createAppIconExportPlans(input) {
19003
19319
  if (!input.outDir) {
19004
19320
  throw new Error("App icon preset export requires --out-dir.");
19005
19321
  }
19006
- const outDir = import_node_path21.default.resolve(input.cwd, input.outDir);
19007
- (0, import_node_fs17.mkdirSync)(outDir, { recursive: true });
19322
+ const outDir = import_node_path23.default.resolve(input.cwd, input.outDir);
19323
+ (0, import_node_fs18.mkdirSync)(outDir, { recursive: true });
19008
19324
  return specs.map((spec) => ({
19009
19325
  width: spec.width,
19010
19326
  height: spec.height,
19011
19327
  format: "png",
19012
- outputPath: import_node_path21.default.join(
19328
+ outputPath: import_node_path23.default.join(
19013
19329
  outDir,
19014
19330
  `${namespace}-${objectId}-${spec.name}-${spec.width}x${spec.height}.png`
19015
19331
  )
@@ -19022,8 +19338,8 @@ function createAppIconExportPlans(input) {
19022
19338
  if (!input.output) {
19023
19339
  throw new Error("Single-size app icon export requires --output.");
19024
19340
  }
19025
- const resolvedOutput = import_node_path21.default.resolve(input.cwd, input.output);
19026
- (0, import_node_fs17.mkdirSync)(import_node_path21.default.dirname(resolvedOutput), { recursive: true });
19341
+ const resolvedOutput = import_node_path23.default.resolve(input.cwd, input.output);
19342
+ (0, import_node_fs18.mkdirSync)(import_node_path23.default.dirname(resolvedOutput), { recursive: true });
19027
19343
  return [
19028
19344
  {
19029
19345
  width: input.width,
@@ -19037,7 +19353,7 @@ async function exportAppIcon(icon, plans) {
19037
19353
  const svg = await resolveAppIconSvg(icon);
19038
19354
  for (const plan of plans) {
19039
19355
  const bytes = await renderAppIcon(svg, plan.width, plan.height, plan.format);
19040
- (0, import_node_fs17.writeFileSync)(plan.outputPath, bytes);
19356
+ (0, import_node_fs18.writeFileSync)(plan.outputPath, bytes);
19041
19357
  }
19042
19358
  }
19043
19359
  async function renderAppIconVariant(input) {
@@ -19045,9 +19361,9 @@ async function renderAppIconVariant(input) {
19045
19361
  const bytes = await renderAppIcon(svg, input.width, input.height, input.format);
19046
19362
  let outputPath;
19047
19363
  if (input.output) {
19048
- outputPath = import_node_path21.default.resolve(input.cwd, input.output);
19049
- (0, import_node_fs17.mkdirSync)(import_node_path21.default.dirname(outputPath), { recursive: true });
19050
- (0, import_node_fs17.writeFileSync)(outputPath, bytes);
19364
+ outputPath = import_node_path23.default.resolve(input.cwd, input.output);
19365
+ (0, import_node_fs18.mkdirSync)(import_node_path23.default.dirname(outputPath), { recursive: true });
19366
+ (0, import_node_fs18.writeFileSync)(outputPath, bytes);
19051
19367
  }
19052
19368
  if (input.name) {
19053
19369
  return {
@@ -19068,7 +19384,7 @@ async function renderAppIconVariant(input) {
19068
19384
  };
19069
19385
  }
19070
19386
  async function loadAppIconVariantFile(input) {
19071
- const absolutePath = import_node_path21.default.resolve(input.cwd, input.filePath);
19387
+ const absolutePath = import_node_path23.default.resolve(input.cwd, input.filePath);
19072
19388
  const format = inferVariantFormatFromPath(absolutePath);
19073
19389
  return {
19074
19390
  value: input.name ? await uploadAppIconVariantAsset({
@@ -19077,7 +19393,7 @@ async function loadAppIconVariantFile(input) {
19077
19393
  name: input.name,
19078
19394
  format,
19079
19395
  sourcePath: absolutePath
19080
- }) : createImageDataUrl((0, import_node_fs17.readFileSync)(absolutePath), format),
19396
+ }) : createImageDataUrl((0, import_node_fs18.readFileSync)(absolutePath), format),
19081
19397
  format,
19082
19398
  absolutePath
19083
19399
  };
@@ -19136,7 +19452,7 @@ function shouldAutoGenerateDefaultVariant(icon) {
19136
19452
  return looksLikeSvgMarkup(icon) || looksLikeSvgUrl(icon);
19137
19453
  }
19138
19454
  function inferVariantFormatFromPath(filePath) {
19139
- const ext = import_node_path21.default.extname(filePath).toLowerCase();
19455
+ const ext = import_node_path23.default.extname(filePath).toLowerCase();
19140
19456
  switch (ext) {
19141
19457
  case ".png":
19142
19458
  return "png";
@@ -19207,13 +19523,13 @@ async function uploadAppIconVariantAsset(input) {
19207
19523
  await AliyunService.uploadFile(sourcePath, DEFAULT_APP_ICON_VARIANT_BUCKET, objectKey);
19208
19524
  } finally {
19209
19525
  if (shouldCleanup) {
19210
- (0, import_node_fs17.rmSync)(import_node_path21.default.dirname(sourcePath), { recursive: true, force: true });
19526
+ (0, import_node_fs18.rmSync)(import_node_path23.default.dirname(sourcePath), { recursive: true, force: true });
19211
19527
  }
19212
19528
  }
19213
19529
  return `${DEFAULT_APP_ICON_VARIANT_PUBLIC_BASE_URL}/${objectKey}`;
19214
19530
  }
19215
19531
  function buildAppIconVariantObjectKey(input) {
19216
- return import_node_path21.default.posix.join(
19532
+ return import_node_path23.default.posix.join(
19217
19533
  "apps",
19218
19534
  `${resolveAppIconAssetStem(input.icon, input.appRef)}-${input.name}.${extensionForIconFormat(input.format)}`
19219
19535
  );
@@ -19222,8 +19538,8 @@ function resolveAppIconAssetStem(icon, appRef) {
19222
19538
  if (icon) {
19223
19539
  try {
19224
19540
  const url = new URL(icon);
19225
- const ext = import_node_path21.default.posix.extname(url.pathname);
19226
- const basename = import_node_path21.default.posix.basename(url.pathname, ext);
19541
+ const ext = import_node_path23.default.posix.extname(url.pathname);
19542
+ const basename = import_node_path23.default.posix.basename(url.pathname, ext);
19227
19543
  const normalized = sanitizeAppIconAssetStem(basename);
19228
19544
  if (normalized) {
19229
19545
  return normalized;
@@ -19252,9 +19568,9 @@ function writeTempAppIconVariantFile(objectKey, format, bytes) {
19252
19568
  if (!bytes) {
19253
19569
  throw new Error("App icon variant upload requires bytes or a source file.");
19254
19570
  }
19255
- const tempDir = (0, import_node_fs17.mkdtempSync)(import_node_path21.default.join(import_node_os7.default.tmpdir(), "pmate-app-icon-"));
19256
- const tempPath = import_node_path21.default.join(tempDir, import_node_path21.default.basename(objectKey) || `variant.${extensionForIconFormat(format)}`);
19257
- (0, import_node_fs17.writeFileSync)(tempPath, bytes);
19571
+ const tempDir = (0, import_node_fs18.mkdtempSync)(import_node_path23.default.join(import_node_os8.default.tmpdir(), "pmate-app-icon-"));
19572
+ const tempPath = import_node_path23.default.join(tempDir, import_node_path23.default.basename(objectKey) || `variant.${extensionForIconFormat(format)}`);
19573
+ (0, import_node_fs18.writeFileSync)(tempPath, bytes);
19258
19574
  return tempPath;
19259
19575
  }
19260
19576
 
@@ -19463,10 +19779,10 @@ var AppCommandHandler = class {
19463
19779
  }
19464
19780
  readJsonFile(filePath) {
19465
19781
  const absolutePath = this.resolveFilePath(filePath);
19466
- if (!(0, import_node_fs18.existsSync)(absolutePath)) {
19782
+ if (!(0, import_node_fs19.existsSync)(absolutePath)) {
19467
19783
  throw new Error(`JSON file not found: ${absolutePath}`);
19468
19784
  }
19469
- const raw = (0, import_node_fs18.readFileSync)(absolutePath, "utf8");
19785
+ const raw = (0, import_node_fs19.readFileSync)(absolutePath, "utf8");
19470
19786
  try {
19471
19787
  return JSON.parse(raw);
19472
19788
  } catch (error) {
@@ -19476,10 +19792,10 @@ var AppCommandHandler = class {
19476
19792
  }
19477
19793
  async preparePayload(filePath, appRef) {
19478
19794
  const absolutePath = this.resolveFilePath(filePath);
19479
- return prepareAppPayload(this.readJsonFile(filePath), import_node_path22.default.dirname(absolutePath), { appRef });
19795
+ return prepareAppPayload(this.readJsonFile(filePath), import_node_path24.default.dirname(absolutePath), { appRef });
19480
19796
  }
19481
19797
  resolveFilePath(filePath) {
19482
- return import_node_path22.default.resolve(process.cwd(), filePath);
19798
+ return import_node_path24.default.resolve(process.cwd(), filePath);
19483
19799
  }
19484
19800
  async request(baseUrl, token, method, pathname, body) {
19485
19801
  const response = await fetch(`${baseUrl}${pathname}`, {
@@ -19599,18 +19915,18 @@ function readNamespaceFromPayload(payload) {
19599
19915
  }
19600
19916
 
19601
19917
  // src/commands/ServiceCommandHandler.ts
19602
- var import_node_fs21 = require("fs");
19918
+ var import_node_fs22 = require("fs");
19603
19919
  var import_promises5 = require("fs/promises");
19604
- var import_node_path25 = __toESM(require("path"));
19920
+ var import_node_path27 = __toESM(require("path"));
19605
19921
  var import_node_child_process11 = require("child_process");
19606
19922
  var import_promises6 = require("readline/promises");
19607
19923
 
19608
19924
  // src/services/AndroidApkReleaseService.ts
19609
19925
  var import_node_child_process9 = require("child_process");
19610
19926
  var import_node_crypto4 = require("crypto");
19611
- var import_node_fs19 = require("fs");
19612
- var import_node_os8 = __toESM(require("os"));
19613
- var import_node_path23 = __toESM(require("path"));
19927
+ var import_node_fs20 = require("fs");
19928
+ var import_node_os9 = __toESM(require("os"));
19929
+ var import_node_path25 = __toESM(require("path"));
19614
19930
  var ANDROID_APK_BUCKET = "parrot-static";
19615
19931
  var ANDROID_APK_PUBLIC_BASE_URL = "https://parrot-static.pmate.chat";
19616
19932
  var AndroidApkReleaseService = class {
@@ -19644,7 +19960,7 @@ var AndroidApkReleaseService = class {
19644
19960
  }
19645
19961
  await AliyunService.uploadFile(apkPath, ANDROID_APK_BUCKET, objectKey);
19646
19962
  const sha256 = await sha256File(apkPath);
19647
- const size = (0, import_node_fs19.statSync)(apkPath).size;
19963
+ const size = (0, import_node_fs20.statSync)(apkPath).size;
19648
19964
  const artifact = {
19649
19965
  serviceId: service.id,
19650
19966
  env: options.env,
@@ -19682,7 +19998,7 @@ var AndroidApkReleaseService = class {
19682
19998
  const prefix = `apks/${service.namespace}/${service.name}`;
19683
19999
  const objects = await AliyunService.listObjects(ANDROID_APK_BUCKET, prefix);
19684
20000
  return objects.filter((item) => item.name.endsWith(".apk")).map((item) => {
19685
- const versionName = import_node_path23.default.basename(item.name, ".apk");
20001
+ const versionName = import_node_path25.default.basename(item.name, ".apk");
19686
20002
  return {
19687
20003
  serviceId,
19688
20004
  env: options.env ?? "unknown",
@@ -19705,7 +20021,7 @@ var AndroidApkReleaseService = class {
19705
20021
  }
19706
20022
  }
19707
20023
  resolveRepoRoot(service, cwd) {
19708
- if (cwd) return import_node_path23.default.resolve(process.cwd(), cwd);
20024
+ if (cwd) return import_node_path25.default.resolve(process.cwd(), cwd);
19709
20025
  const repository = this.getRepository(service);
19710
20026
  if (repository) {
19711
20027
  return resolveRepositoryLocalRoot(repository);
@@ -19717,8 +20033,8 @@ var AndroidApkReleaseService = class {
19717
20033
  if (!dir) {
19718
20034
  throw new Error(`Missing dir for android service ${service.id}`);
19719
20035
  }
19720
- const appDir = import_node_path23.default.resolve(repoRoot, dir);
19721
- if (!(0, import_node_fs19.existsSync)(appDir)) {
20036
+ const appDir = import_node_path25.default.resolve(repoRoot, dir);
20037
+ if (!(0, import_node_fs20.existsSync)(appDir)) {
19722
20038
  throw new Error(`Android app dir not found: ${appDir}`);
19723
20039
  }
19724
20040
  return appDir;
@@ -19734,11 +20050,11 @@ var AndroidApkReleaseService = class {
19734
20050
  return void 0;
19735
20051
  }
19736
20052
  async runGradleAssembleAndFindApk(repoRoot, appDir, variant) {
19737
- const gradlew = [import_node_path23.default.join(appDir, "gradlew"), import_node_path23.default.join(repoRoot, "gradlew")].find((candidate) => (0, import_node_fs19.existsSync)(candidate));
20053
+ const gradlew = [import_node_path25.default.join(appDir, "gradlew"), import_node_path25.default.join(repoRoot, "gradlew")].find((candidate) => (0, import_node_fs20.existsSync)(candidate));
19738
20054
  if (!gradlew) {
19739
20055
  throw new Error(`Gradle wrapper not found in ${appDir} or ${repoRoot}`);
19740
20056
  }
19741
- const gradleCwd = import_node_path23.default.dirname(gradlew);
20057
+ const gradleCwd = import_node_path25.default.dirname(gradlew);
19742
20058
  const normalizedVariant = variant.toLowerCase();
19743
20059
  const taskSuffix = `assemble${capitalize(normalizedVariant)}`;
19744
20060
  const tasks = [`:app:${taskSuffix}`, taskSuffix];
@@ -19806,7 +20122,7 @@ function resolveRepositoryLocalRoot(repository) {
19806
20122
  if (!repoName) {
19807
20123
  throw new Error(`Invalid repository: ${repository}`);
19808
20124
  }
19809
- return import_node_path23.default.join(import_node_os8.default.homedir(), "dev", "pmate", repoName);
20125
+ return import_node_path25.default.join(import_node_os9.default.homedir(), "dev", "pmate", repoName);
19810
20126
  }
19811
20127
  function bumpAndroidGradleVersionText(source, bump) {
19812
20128
  const versionNameMatch = source.match(/(^\s*versionName\s+["'])([^"']+)(["']\s*$)/m) ?? source.match(/(^\s*versionName\s*=\s*["'])([^"']+)(["']\s*$)/m);
@@ -19862,42 +20178,42 @@ function parseGradleOutputMetadata(source, apkFileName) {
19862
20178
  }
19863
20179
  function bumpAndroidProjectVersion(appDir, bump) {
19864
20180
  const candidates = [
19865
- import_node_path23.default.join(appDir, "app", "build.gradle.kts"),
19866
- import_node_path23.default.join(appDir, "app", "build.gradle"),
19867
- import_node_path23.default.join(appDir, "build.gradle.kts"),
19868
- import_node_path23.default.join(appDir, "build.gradle")
20181
+ import_node_path25.default.join(appDir, "app", "build.gradle.kts"),
20182
+ import_node_path25.default.join(appDir, "app", "build.gradle"),
20183
+ import_node_path25.default.join(appDir, "build.gradle.kts"),
20184
+ import_node_path25.default.join(appDir, "build.gradle")
19869
20185
  ];
19870
20186
  for (const candidate of candidates) {
19871
- if (!(0, import_node_fs19.existsSync)(candidate)) continue;
19872
- const result = bumpAndroidGradleVersionText((0, import_node_fs19.readFileSync)(candidate, "utf8"), bump);
19873
- (0, import_node_fs19.writeFileSync)(candidate, result.source);
20187
+ if (!(0, import_node_fs20.existsSync)(candidate)) continue;
20188
+ const result = bumpAndroidGradleVersionText((0, import_node_fs20.readFileSync)(candidate, "utf8"), bump);
20189
+ (0, import_node_fs20.writeFileSync)(candidate, result.source);
19874
20190
  return { filePath: candidate, ...result };
19875
20191
  }
19876
20192
  throw new Error(`No Android Gradle version file found under ${appDir}`);
19877
20193
  }
19878
20194
  function findLatestApk(repoRoot, appDir, variant) {
19879
20195
  const dirs = [
19880
- import_node_path23.default.join(appDir, "app", "build", "outputs", "apk", variant),
19881
- import_node_path23.default.join(appDir, "build", "outputs", "apk", variant),
19882
- import_node_path23.default.join(repoRoot, "app", "build", "outputs", "apk", variant)
20196
+ import_node_path25.default.join(appDir, "app", "build", "outputs", "apk", variant),
20197
+ import_node_path25.default.join(appDir, "build", "outputs", "apk", variant),
20198
+ import_node_path25.default.join(repoRoot, "app", "build", "outputs", "apk", variant)
19883
20199
  ];
19884
20200
  const files = dirs.flatMap((dir) => listApks(dir));
19885
20201
  if (files.length === 0) {
19886
20202
  throw new Error(`Cannot find APK output for variant ${variant}`);
19887
20203
  }
19888
- files.sort((a, b) => (0, import_node_fs19.statSync)(b).mtimeMs - (0, import_node_fs19.statSync)(a).mtimeMs);
20204
+ files.sort((a, b) => (0, import_node_fs20.statSync)(b).mtimeMs - (0, import_node_fs20.statSync)(a).mtimeMs);
19889
20205
  return files[0];
19890
20206
  }
19891
20207
  function readGradleOutputMetadata(apkPath) {
19892
- const metadataPath = import_node_path23.default.join(import_node_path23.default.dirname(apkPath), "output-metadata.json");
19893
- if (!(0, import_node_fs19.existsSync)(metadataPath)) {
20208
+ const metadataPath = import_node_path25.default.join(import_node_path25.default.dirname(apkPath), "output-metadata.json");
20209
+ if (!(0, import_node_fs20.existsSync)(metadataPath)) {
19894
20210
  throw new Error(`Gradle output metadata not found: ${metadataPath}`);
19895
20211
  }
19896
- return parseGradleOutputMetadata((0, import_node_fs19.readFileSync)(metadataPath, "utf8"), import_node_path23.default.basename(apkPath));
20212
+ return parseGradleOutputMetadata((0, import_node_fs20.readFileSync)(metadataPath, "utf8"), import_node_path25.default.basename(apkPath));
19897
20213
  }
19898
20214
  function listApks(dir) {
19899
- if (!(0, import_node_fs19.existsSync)(dir)) return [];
19900
- return (0, import_node_fs19.readdirSync)(dir).filter((entry) => entry.endsWith(".apk")).map((entry) => import_node_path23.default.join(dir, entry)).filter((entry) => (0, import_node_fs19.statSync)(entry).isFile());
20215
+ if (!(0, import_node_fs20.existsSync)(dir)) return [];
20216
+ return (0, import_node_fs20.readdirSync)(dir).filter((entry) => entry.endsWith(".apk")).map((entry) => import_node_path25.default.join(dir, entry)).filter((entry) => (0, import_node_fs20.statSync)(entry).isFile());
19901
20217
  }
19902
20218
  function runCommand(command, args, cwd) {
19903
20219
  return new Promise((resolve, reject) => {
@@ -19931,26 +20247,26 @@ async function runAndroidSdkToolCapture(toolName, args) {
19931
20247
  return runCommandCapture(toolPath, args);
19932
20248
  }
19933
20249
  function findAndroidSdkTool(toolName) {
19934
- const sdkRoots = [process.env.ANDROID_HOME, process.env.ANDROID_SDK_ROOT].filter((item) => Boolean(item)).map((item) => import_node_path23.default.resolve(item));
20250
+ const sdkRoots = [process.env.ANDROID_HOME, process.env.ANDROID_SDK_ROOT].filter((item) => Boolean(item)).map((item) => import_node_path25.default.resolve(item));
19935
20251
  for (const sdkRoot of sdkRoots) {
19936
- const candidates = toolName === "aapt" ? listVersionedToolCandidates(import_node_path23.default.join(sdkRoot, "build-tools"), toolName) : [
19937
- import_node_path23.default.join(sdkRoot, "cmdline-tools", "latest", "bin", toolName),
19938
- ...listVersionedToolCandidates(import_node_path23.default.join(sdkRoot, "cmdline-tools"), import_node_path23.default.join("bin", toolName)),
19939
- import_node_path23.default.join(sdkRoot, "tools", "bin", toolName)
20252
+ const candidates = toolName === "aapt" ? listVersionedToolCandidates(import_node_path25.default.join(sdkRoot, "build-tools"), toolName) : [
20253
+ import_node_path25.default.join(sdkRoot, "cmdline-tools", "latest", "bin", toolName),
20254
+ ...listVersionedToolCandidates(import_node_path25.default.join(sdkRoot, "cmdline-tools"), import_node_path25.default.join("bin", toolName)),
20255
+ import_node_path25.default.join(sdkRoot, "tools", "bin", toolName)
19940
20256
  ];
19941
- const match = candidates.find((candidate) => (0, import_node_fs19.existsSync)(candidate));
20257
+ const match = candidates.find((candidate) => (0, import_node_fs20.existsSync)(candidate));
19942
20258
  if (match) return match;
19943
20259
  }
19944
20260
  return void 0;
19945
20261
  }
19946
20262
  function listVersionedToolCandidates(parentDir, relativeToolPath) {
19947
- if (!(0, import_node_fs19.existsSync)(parentDir)) return [];
19948
- return (0, import_node_fs19.readdirSync)(parentDir).map((entry) => import_node_path23.default.join(parentDir, entry)).filter((entry) => (0, import_node_fs19.statSync)(entry).isDirectory()).sort((a, b) => import_node_path23.default.basename(b).localeCompare(import_node_path23.default.basename(a), void 0, { numeric: true })).map((entry) => import_node_path23.default.join(entry, relativeToolPath));
20263
+ if (!(0, import_node_fs20.existsSync)(parentDir)) return [];
20264
+ return (0, import_node_fs20.readdirSync)(parentDir).map((entry) => import_node_path25.default.join(parentDir, entry)).filter((entry) => (0, import_node_fs20.statSync)(entry).isDirectory()).sort((a, b) => import_node_path25.default.basename(b).localeCompare(import_node_path25.default.basename(a), void 0, { numeric: true })).map((entry) => import_node_path25.default.join(entry, relativeToolPath));
19949
20265
  }
19950
20266
  function sha256File(filePath) {
19951
20267
  return new Promise((resolve, reject) => {
19952
20268
  const hash = (0, import_node_crypto4.createHash)("sha256");
19953
- const stream = (0, import_node_fs19.createReadStream)(filePath);
20269
+ const stream = (0, import_node_fs20.createReadStream)(filePath);
19954
20270
  stream.on("data", (chunk) => hash.update(chunk));
19955
20271
  stream.on("error", reject);
19956
20272
  stream.on("end", () => resolve(hash.digest("hex")));
@@ -19967,9 +20283,9 @@ function capitalize(value) {
19967
20283
  }
19968
20284
 
19969
20285
  // src/services/ServiceRuntimeRunner.ts
19970
- var import_node_fs20 = require("fs");
19971
- var import_node_os9 = __toESM(require("os"));
19972
- var import_node_path24 = __toESM(require("path"));
20286
+ var import_node_fs21 = require("fs");
20287
+ var import_node_os10 = __toESM(require("os"));
20288
+ var import_node_path26 = __toESM(require("path"));
19973
20289
  var import_node_child_process10 = require("child_process");
19974
20290
  var import_node_readline = require("readline");
19975
20291
  var import_chalk3 = __toESM(require("chalk"));
@@ -20142,8 +20458,7 @@ var ServiceRegistryClient = class {
20142
20458
  }
20143
20459
  readToken() {
20144
20460
  return readRequiredSession({
20145
- preferredApp: DEFAULT_APP_ID,
20146
- fallbackToActiveApp: true
20461
+ preferredApp: DEFAULT_APP_ID
20147
20462
  }).token;
20148
20463
  }
20149
20464
  async request(method, pathname) {
@@ -20433,14 +20748,14 @@ var ServiceRuntimeRunner = class {
20433
20748
  }
20434
20749
  resolveRepoRoot(service, cwd) {
20435
20750
  if (cwd) {
20436
- return import_node_path24.default.resolve(process.cwd(), cwd);
20751
+ return import_node_path26.default.resolve(process.cwd(), cwd);
20437
20752
  }
20438
20753
  const repository = this.getType(service) === "vite" || this.getType(service) === "static" ? this.getRepoStaticSite(service).repository.trim() : this.getType(service) === "fc" ? this.getFc(service).repository?.trim() : this.getType(service) === "ios" || this.getType(service) === "android" ? void 0 : this.getNetwork(service).repository?.trim();
20439
20754
  if (repository) {
20440
20755
  const repoName = repository.replace(/\/+$/, "").split("/").pop()?.replace(/\.git$/i, "");
20441
20756
  if (repoName) {
20442
- const candidate = import_node_path24.default.join(import_node_os9.default.homedir(), "dev", "pmate", repoName);
20443
- if ((0, import_node_fs20.existsSync)(candidate)) {
20757
+ const candidate = import_node_path26.default.join(import_node_os10.default.homedir(), "dev", "pmate", repoName);
20758
+ if ((0, import_node_fs21.existsSync)(candidate)) {
20444
20759
  return candidate;
20445
20760
  }
20446
20761
  }
@@ -20453,13 +20768,13 @@ var ServiceRuntimeRunner = class {
20453
20768
  if (!dir) {
20454
20769
  throw new Error(`Missing service dir for ${service.id}`);
20455
20770
  }
20456
- return import_node_path24.default.resolve(repoRoot, dir);
20771
+ return import_node_path26.default.resolve(repoRoot, dir);
20457
20772
  }
20458
20773
  async deployVite(service, options) {
20459
20774
  this.assertDeployableStaticSite(service);
20460
20775
  const appDir = this.resolveLocalDir(service, options.cwd);
20461
- const packageJsonPath = import_node_path24.default.join(appDir, "package.json");
20462
- if (!(0, import_node_fs20.existsSync)(packageJsonPath)) {
20776
+ const packageJsonPath = import_node_path26.default.join(appDir, "package.json");
20777
+ if (!(0, import_node_fs21.existsSync)(packageJsonPath)) {
20463
20778
  throw new Error(`No package.json found at ${packageJsonPath}`);
20464
20779
  }
20465
20780
  const pkg2 = this.loadPackageJson(packageJsonPath);
@@ -20474,8 +20789,8 @@ var ServiceRuntimeRunner = class {
20474
20789
  this.resolveRepoRoot(service, options.cwd),
20475
20790
  buildEnv
20476
20791
  );
20477
- const distDir = import_node_path24.default.join(appDir, "dist");
20478
- if (!(0, import_node_fs20.existsSync)(distDir)) {
20792
+ const distDir = import_node_path26.default.join(appDir, "dist");
20793
+ if (!(0, import_node_fs21.existsSync)(distDir)) {
20479
20794
  throw new Error(`No dist directory found at ${distDir}`);
20480
20795
  }
20481
20796
  const site = this.getSite(service);
@@ -20488,8 +20803,8 @@ var ServiceRuntimeRunner = class {
20488
20803
  async deployStatic(service, options) {
20489
20804
  this.assertDeployableStaticSite(service);
20490
20805
  const appDir = this.resolveLocalDir(service, options.cwd);
20491
- const srcDir = import_node_path24.default.join(appDir, "src");
20492
- if (!(0, import_node_fs20.existsSync)(srcDir)) {
20806
+ const srcDir = import_node_path26.default.join(appDir, "src");
20807
+ if (!(0, import_node_fs21.existsSync)(srcDir)) {
20493
20808
  throw new Error(`No src directory found at ${srcDir}`);
20494
20809
  }
20495
20810
  const site = this.getSite(service);
@@ -20523,8 +20838,8 @@ var ServiceRuntimeRunner = class {
20523
20838
  this.validateFcConfig(service, fc);
20524
20839
  const repoRoot = this.resolveRepoRoot(service);
20525
20840
  const appDir = this.resolveLocalDir(service);
20526
- const packageJsonPath = import_node_path24.default.join(appDir, "package.json");
20527
- if (!(0, import_node_fs20.existsSync)(packageJsonPath)) {
20841
+ const packageJsonPath = import_node_path26.default.join(appDir, "package.json");
20842
+ if (!(0, import_node_fs21.existsSync)(packageJsonPath)) {
20528
20843
  throw new Error(`No package.json found at ${packageJsonPath}`);
20529
20844
  }
20530
20845
  const pkg2 = this.loadPackageJson(packageJsonPath);
@@ -20577,15 +20892,15 @@ var ServiceRuntimeRunner = class {
20577
20892
  const repoRoot = this.resolveRepoRoot(service, options.cwd);
20578
20893
  const appDir = this.resolveLocalDir(service, options.cwd);
20579
20894
  await this.ensurePnpmWorkspaceRoot(repoRoot);
20580
- const configPath = import_node_path24.default.join(appDir, fc.configFile ?? "s.yaml");
20581
- if (!(0, import_node_fs20.existsSync)(configPath)) {
20895
+ const configPath = import_node_path26.default.join(appDir, fc.configFile ?? "s.yaml");
20896
+ if (!(0, import_node_fs21.existsSync)(configPath)) {
20582
20897
  throw new Error(`Missing FC config file at ${configPath}`);
20583
20898
  }
20584
- const packageJsonPath = import_node_path24.default.join(appDir, "package.json");
20585
- if (!(0, import_node_fs20.existsSync)(packageJsonPath)) {
20899
+ const packageJsonPath = import_node_path26.default.join(appDir, "package.json");
20900
+ if (!(0, import_node_fs21.existsSync)(packageJsonPath)) {
20586
20901
  throw new Error(`No package.json found at ${packageJsonPath}`);
20587
20902
  }
20588
- const rawConfig = (0, import_node_fs20.readFileSync)(configPath, "utf8");
20903
+ const rawConfig = (0, import_node_fs21.readFileSync)(configPath, "utf8");
20589
20904
  if (!rawConfig.includes(fc.functionName)) {
20590
20905
  throw new Error(`FC config ${configPath} does not mention functionName ${fc.functionName}`);
20591
20906
  }
@@ -20863,7 +21178,7 @@ var ServiceRuntimeRunner = class {
20863
21178
  const serverAddress = await resolveServerAddress(server);
20864
21179
  const templateName = exposeType === "websocket" ? "nginx.ws.template" : "nginx.rest.template";
20865
21180
  const templatePath = this.resolveTemplatePath(templateName);
20866
- const template = (0, import_node_fs20.readFileSync)(templatePath, "utf8");
21181
+ const template = (0, import_node_fs21.readFileSync)(templatePath, "utf8");
20867
21182
  const host = `${subdomain}.${("domain" in network ? network.domain?.trim() : void 0) || "pmate.chat"}`;
20868
21183
  const rendered = template.replace(/\$\{\{PORT\}\}/g, String(port)).replace(/\$\{\{HOSTS\}\}/g, host).replace(/\$\{\{HOST\}\}/g, host);
20869
21184
  const remotePath = `/etc/nginx/sites-enabled/${subdomain}.conf`;
@@ -20895,11 +21210,11 @@ var ServiceRuntimeRunner = class {
20895
21210
  }
20896
21211
  if (config.ensurePackageJson) {
20897
21212
  const appDir = this.resolveLocalDir(service, options.cwd);
20898
- const packageJsonPath = import_node_path24.default.join(appDir, "package.json");
20899
- if (!(0, import_node_fs20.existsSync)(packageJsonPath)) {
21213
+ const packageJsonPath = import_node_path26.default.join(appDir, "package.json");
21214
+ if (!(0, import_node_fs21.existsSync)(packageJsonPath)) {
20900
21215
  throw new Error(`Missing package.json at ${packageJsonPath}`);
20901
21216
  }
20902
- const pkgStat = (0, import_node_fs20.statSync)(packageJsonPath);
21217
+ const pkgStat = (0, import_node_fs21.statSync)(packageJsonPath);
20903
21218
  if (!pkgStat.isFile()) {
20904
21219
  throw new Error(`package.json is not a file at ${packageJsonPath}`);
20905
21220
  }
@@ -21328,9 +21643,9 @@ var ServiceRuntimeRunner = class {
21328
21643
  return tokens;
21329
21644
  }
21330
21645
  readPathValue(source, pathExpr) {
21331
- const path29 = pathExpr.split(".").map((segment) => segment.trim()).filter(Boolean);
21646
+ const path31 = pathExpr.split(".").map((segment) => segment.trim()).filter(Boolean);
21332
21647
  let cursor = source;
21333
- for (const segment of path29) {
21648
+ for (const segment of path31) {
21334
21649
  if (!cursor || typeof cursor !== "object" || Array.isArray(cursor)) {
21335
21650
  return void 0;
21336
21651
  }
@@ -21373,12 +21688,12 @@ var ServiceRuntimeRunner = class {
21373
21688
  }
21374
21689
  resolveTemplatePath(templateName) {
21375
21690
  const candidates = [
21376
- import_node_path24.default.join(__dirname, "..", "templates", templateName),
21377
- import_node_path24.default.join(__dirname, "..", "src", "templates", templateName),
21378
- import_node_path24.default.join(__dirname, "templates", templateName)
21691
+ import_node_path26.default.join(__dirname, "..", "templates", templateName),
21692
+ import_node_path26.default.join(__dirname, "..", "src", "templates", templateName),
21693
+ import_node_path26.default.join(__dirname, "templates", templateName)
21379
21694
  ];
21380
21695
  for (const candidate of candidates) {
21381
- if ((0, import_node_fs20.existsSync)(candidate)) {
21696
+ if ((0, import_node_fs21.existsSync)(candidate)) {
21382
21697
  return candidate;
21383
21698
  }
21384
21699
  }
@@ -21410,7 +21725,7 @@ var ServiceRuntimeRunner = class {
21410
21725
  });
21411
21726
  }
21412
21727
  loadPackageJson(packageJsonPath) {
21413
- const raw = (0, import_node_fs20.readFileSync)(packageJsonPath, "utf8");
21728
+ const raw = (0, import_node_fs21.readFileSync)(packageJsonPath, "utf8");
21414
21729
  const parsed = JSON.parse(raw);
21415
21730
  if (!parsed || typeof parsed !== "object") {
21416
21731
  throw new Error(`Invalid package.json at ${packageJsonPath}`);
@@ -21419,7 +21734,7 @@ var ServiceRuntimeRunner = class {
21419
21734
  }
21420
21735
  writePackageJson(packageJsonPath, data) {
21421
21736
  const serialized = JSON.stringify(data, null, 2);
21422
- (0, import_node_fs20.writeFileSync)(packageJsonPath, `${serialized}
21737
+ (0, import_node_fs21.writeFileSync)(packageJsonPath, `${serialized}
21423
21738
  `, "utf8");
21424
21739
  }
21425
21740
  validateFcConfig(service, fc) {
@@ -21446,8 +21761,8 @@ var ServiceRuntimeRunner = class {
21446
21761
  }
21447
21762
  }
21448
21763
  async ensurePnpmWorkspaceRoot(repoRoot) {
21449
- const workspacePath = import_node_path24.default.join(repoRoot, "pnpm-workspace.yaml");
21450
- if (!(0, import_node_fs20.existsSync)(workspacePath)) {
21764
+ const workspacePath = import_node_path26.default.join(repoRoot, "pnpm-workspace.yaml");
21765
+ if (!(0, import_node_fs21.existsSync)(workspacePath)) {
21451
21766
  throw new Error(`Missing pnpm-workspace.yaml at ${workspacePath}`);
21452
21767
  }
21453
21768
  }
@@ -21521,16 +21836,16 @@ var ServiceRuntimeRunner = class {
21521
21836
  if (!privateKeyPath) {
21522
21837
  throw new Error("Missing ssl.prv in ~/.pmate/config.yaml.");
21523
21838
  }
21524
- if (!(0, import_node_fs20.existsSync)(certificatePath)) {
21839
+ if (!(0, import_node_fs21.existsSync)(certificatePath)) {
21525
21840
  throw new Error(`SSL certificate file not found: ${certificatePath}`);
21526
21841
  }
21527
- if (!(0, import_node_fs20.existsSync)(privateKeyPath)) {
21842
+ if (!(0, import_node_fs21.existsSync)(privateKeyPath)) {
21528
21843
  throw new Error(`SSL private key file not found: ${privateKeyPath}`);
21529
21844
  }
21530
21845
  return {
21531
21846
  certName: host,
21532
- certificate: (0, import_node_fs20.readFileSync)(certificatePath, "utf8"),
21533
- privateKey: (0, import_node_fs20.readFileSync)(privateKeyPath, "utf8")
21847
+ certificate: (0, import_node_fs21.readFileSync)(certificatePath, "utf8"),
21848
+ privateKey: (0, import_node_fs21.readFileSync)(privateKeyPath, "utf8")
21534
21849
  };
21535
21850
  }
21536
21851
  resolveFcProtocol(fc, certConfig) {
@@ -21987,7 +22302,7 @@ var ServiceCommandHandler = class {
21987
22302
  format: "dotenv"
21988
22303
  }
21989
22304
  );
21990
- const outputPath = import_node_path25.default.resolve(process.cwd(), args.output);
22305
+ const outputPath = import_node_path27.default.resolve(process.cwd(), args.output);
21991
22306
  await (0, import_promises5.writeFile)(outputPath, payload.content, "utf8");
21992
22307
  ui.success(`Wrote env file for ${args.appId} to ${outputPath}`);
21993
22308
  this.renderJson({ ...payload, output: outputPath }, args.json);
@@ -22213,11 +22528,11 @@ var ServiceCommandHandler = class {
22213
22528
  return (baseUrl || process.env.PMATE_APPS_API_BASE_URL || "https://apps-api.pmate.chat").replace(/\/+$/, "");
22214
22529
  }
22215
22530
  readJsonFile(filePath) {
22216
- const absolutePath = import_node_path25.default.resolve(process.cwd(), filePath);
22217
- if (!(0, import_node_fs21.existsSync)(absolutePath)) {
22531
+ const absolutePath = import_node_path27.default.resolve(process.cwd(), filePath);
22532
+ if (!(0, import_node_fs22.existsSync)(absolutePath)) {
22218
22533
  throw new Error(`JSON file not found: ${absolutePath}`);
22219
22534
  }
22220
- const raw = (0, import_node_fs21.readFileSync)(absolutePath, "utf8");
22535
+ const raw = (0, import_node_fs22.readFileSync)(absolutePath, "utf8");
22221
22536
  try {
22222
22537
  return JSON.parse(raw);
22223
22538
  } catch (error) {
@@ -22977,8 +23292,7 @@ var RoleCommandHandler = class {
22977
23292
  }
22978
23293
  readToken() {
22979
23294
  return readRequiredSession({
22980
- preferredApp: DEFAULT_APP_ID,
22981
- fallbackToActiveApp: true
23295
+ preferredApp: DEFAULT_APP_ID
22982
23296
  }).token;
22983
23297
  }
22984
23298
  async request(baseUrl, token, method, pathname, body) {
@@ -23026,9 +23340,9 @@ var RoleCommandHandler = class {
23026
23340
  };
23027
23341
 
23028
23342
  // src/commands/AccountCommandHandler.ts
23029
- var import_node_fs22 = require("fs");
23343
+ var import_node_fs23 = require("fs");
23030
23344
  var import_node_crypto5 = require("crypto");
23031
- var import_node_path26 = __toESM(require("path"));
23345
+ var import_node_path28 = __toESM(require("path"));
23032
23346
  init_sessionStore();
23033
23347
  var AccountCommandHandler = class {
23034
23348
  async handle(args) {
@@ -23036,9 +23350,9 @@ var AccountCommandHandler = class {
23036
23350
  case "bot-keygen": {
23037
23351
  const keyFile = this.generateBotKeyFile(args.app, args.name);
23038
23352
  const outPath = args.out ? this.resolveFilePath(args.out) : this.resolveDefaultBotKeyPath(args.app, args.name);
23039
- (0, import_node_fs22.mkdirSync)(import_node_path26.default.dirname(outPath), { recursive: true });
23040
- (0, import_node_fs22.writeFileSync)(outPath, JSON.stringify(keyFile, null, 2), { mode: 384 });
23041
- (0, import_node_fs22.chmodSync)(outPath, 384);
23353
+ (0, import_node_fs23.mkdirSync)(import_node_path28.default.dirname(outPath), { recursive: true });
23354
+ (0, import_node_fs23.writeFileSync)(outPath, JSON.stringify(keyFile, null, 2), { mode: 384 });
23355
+ (0, import_node_fs23.chmodSync)(outPath, 384);
23042
23356
  if (!args.json) {
23043
23357
  ui.success(`Bot key saved to ${outPath}`);
23044
23358
  }
@@ -23404,8 +23718,7 @@ var AccountCommandHandler = class {
23404
23718
  }
23405
23719
  readToken() {
23406
23720
  return readRequiredSession({
23407
- preferredApp: DEFAULT_APP_ID,
23408
- fallbackToActiveApp: true
23721
+ preferredApp: DEFAULT_APP_ID
23409
23722
  }).token;
23410
23723
  }
23411
23724
  buildAccountViewQuery(args) {
@@ -23576,10 +23889,10 @@ var AccountCommandHandler = class {
23576
23889
  throw new Error("Missing visible apps input");
23577
23890
  }
23578
23891
  const absolutePath = this.resolveFilePath(args.filePath);
23579
- if (!(0, import_node_fs22.existsSync)(absolutePath)) {
23892
+ if (!(0, import_node_fs23.existsSync)(absolutePath)) {
23580
23893
  throw new Error(`JSON file not found: ${absolutePath}`);
23581
23894
  }
23582
- const raw = (0, import_node_fs22.readFileSync)(absolutePath, "utf8");
23895
+ const raw = (0, import_node_fs23.readFileSync)(absolutePath, "utf8");
23583
23896
  let parsed;
23584
23897
  try {
23585
23898
  parsed = JSON.parse(raw);
@@ -23593,13 +23906,13 @@ var AccountCommandHandler = class {
23593
23906
  return parsed;
23594
23907
  }
23595
23908
  resolveFilePath(filePath) {
23596
- return import_node_path26.default.resolve(process.cwd(), filePath);
23909
+ return import_node_path28.default.resolve(process.cwd(), filePath);
23597
23910
  }
23598
23911
  resolveDefaultBotKeyPath(app, name) {
23599
- return import_node_path26.default.join(this.homeDir(), ".pmate", "bots", app, `${name}.bot-key.json`);
23912
+ return import_node_path28.default.join(this.homeDir(), ".pmate", "bots", app, `${name}.bot-key.json`);
23600
23913
  }
23601
23914
  resolveDefaultAccessKeyPath(app, name) {
23602
- return import_node_path26.default.join(this.homeDir(), ".pmate", "access-keys", app, `${name}.access-key.json`);
23915
+ return import_node_path28.default.join(this.homeDir(), ".pmate", "access-keys", app, `${name}.access-key.json`);
23603
23916
  }
23604
23917
  homeDir() {
23605
23918
  return process.env.HOME || process.env.USERPROFILE || process.cwd();
@@ -23622,10 +23935,10 @@ var AccountCommandHandler = class {
23622
23935
  throw new Error("Missing bot key file");
23623
23936
  }
23624
23937
  const absolutePath = this.resolveFilePath(filePath);
23625
- if (!(0, import_node_fs22.existsSync)(absolutePath)) {
23938
+ if (!(0, import_node_fs23.existsSync)(absolutePath)) {
23626
23939
  throw new Error(`Bot key file not found: ${absolutePath}`);
23627
23940
  }
23628
- const parsed = JSON.parse((0, import_node_fs22.readFileSync)(absolutePath, "utf8"));
23941
+ const parsed = JSON.parse((0, import_node_fs23.readFileSync)(absolutePath, "utf8"));
23629
23942
  if (parsed.type !== "pmate-bot-key" || parsed.version !== 1 || parsed.algorithm !== "ed25519" || !parsed.publicKey || !parsed.privateKey) {
23630
23943
  throw new Error(`Invalid PMate bot key file: ${absolutePath}`);
23631
23944
  }
@@ -23642,10 +23955,10 @@ var AccountCommandHandler = class {
23642
23955
  throw new Error("Missing access key file");
23643
23956
  }
23644
23957
  const absolutePath = this.resolveFilePath(filePath);
23645
- if (!(0, import_node_fs22.existsSync)(absolutePath)) {
23958
+ if (!(0, import_node_fs23.existsSync)(absolutePath)) {
23646
23959
  throw new Error(`Access key file not found: ${absolutePath}`);
23647
23960
  }
23648
- const parsed = JSON.parse((0, import_node_fs22.readFileSync)(absolutePath, "utf8"));
23961
+ const parsed = JSON.parse((0, import_node_fs23.readFileSync)(absolutePath, "utf8"));
23649
23962
  if (parsed.type !== "pmate-access-key" || parsed.version !== 1 || !parsed.id || !parsed.app || !parsed.secret || !parsed.expiresAt) {
23650
23963
  throw new Error(`Invalid PMate access key file: ${absolutePath}`);
23651
23964
  }
@@ -23667,9 +23980,9 @@ var AccountCommandHandler = class {
23667
23980
  createdAt: result.key.createdAt
23668
23981
  };
23669
23982
  const outPath = out ? this.resolveFilePath(out) : this.resolveDefaultAccessKeyPath(result.key.app, result.key.name);
23670
- (0, import_node_fs22.mkdirSync)(import_node_path26.default.dirname(outPath), { recursive: true });
23671
- (0, import_node_fs22.writeFileSync)(outPath, JSON.stringify(keyFile, null, 2), { mode: 384 });
23672
- (0, import_node_fs22.chmodSync)(outPath, 384);
23983
+ (0, import_node_fs23.mkdirSync)(import_node_path28.default.dirname(outPath), { recursive: true });
23984
+ (0, import_node_fs23.writeFileSync)(outPath, JSON.stringify(keyFile, null, 2), { mode: 384 });
23985
+ (0, import_node_fs23.chmodSync)(outPath, 384);
23673
23986
  }
23674
23987
  renderAccessKeyCreateResult(result, asJson, out) {
23675
23988
  if (asJson) {
@@ -23709,16 +24022,12 @@ var AccountCommandHandler = class {
23709
24022
  }
23710
24023
  }
23711
24024
  async resolveLoginProfileId(login, app, authApiBaseUrl) {
23712
- try {
23713
- return await fetchDefaultProfileId({
23714
- token: login.token,
23715
- app,
23716
- accountId: login.session.identity.accountId,
23717
- authApiBaseUrl
23718
- });
23719
- } catch {
23720
- return login.session.identity.accessKeyId ?? login.session.identity.accountId;
23721
- }
24025
+ return await fetchDefaultProfileId({
24026
+ token: login.token,
24027
+ app,
24028
+ accountId: login.session.identity.accountId,
24029
+ authApiBaseUrl
24030
+ });
23722
24031
  }
23723
24032
  signBotChallenge(challenge, privateKey) {
23724
24033
  const key = (0, import_node_crypto5.createPrivateKey)({
@@ -23760,8 +24069,8 @@ function encodePathSegment2(value) {
23760
24069
  }
23761
24070
 
23762
24071
  // src/commands/OrgCommandHandler.ts
23763
- var import_node_fs23 = require("fs");
23764
- var import_node_path27 = __toESM(require("path"));
24072
+ var import_node_fs24 = require("fs");
24073
+ var import_node_path29 = __toESM(require("path"));
23765
24074
  init_sessionStore();
23766
24075
  var OrgCommandHandler = class {
23767
24076
  async handle(args) {
@@ -23921,8 +24230,7 @@ var OrgCommandHandler = class {
23921
24230
  }
23922
24231
  readToken() {
23923
24232
  return readRequiredSession({
23924
- preferredApp: DEFAULT_APP_ID,
23925
- fallbackToActiveApp: true
24233
+ preferredApp: DEFAULT_APP_ID
23926
24234
  }).token;
23927
24235
  }
23928
24236
  resolveStringArrayInput(values, filePath, itemLabel) {
@@ -23932,11 +24240,11 @@ var OrgCommandHandler = class {
23932
24240
  if (!filePath) {
23933
24241
  throw new Error(`Missing ${itemLabel} input`);
23934
24242
  }
23935
- const absolutePath = import_node_path27.default.resolve(process.cwd(), filePath);
23936
- if (!(0, import_node_fs23.existsSync)(absolutePath)) {
24243
+ const absolutePath = import_node_path29.default.resolve(process.cwd(), filePath);
24244
+ if (!(0, import_node_fs24.existsSync)(absolutePath)) {
23937
24245
  throw new Error(`JSON file not found: ${absolutePath}`);
23938
24246
  }
23939
- const raw = (0, import_node_fs23.readFileSync)(absolutePath, "utf8");
24247
+ const raw = (0, import_node_fs24.readFileSync)(absolutePath, "utf8");
23940
24248
  let parsed;
23941
24249
  try {
23942
24250
  parsed = JSON.parse(raw);
@@ -27332,7 +27640,7 @@ function requireValue12(tokens, option) {
27332
27640
 
27333
27641
  // src/index.ts
27334
27642
  var pkg = JSON.parse(
27335
- (0, import_node_fs24.readFileSync)(import_node_path28.default.resolve(__dirname, "..", "package.json"), "utf8")
27643
+ (0, import_node_fs25.readFileSync)(import_node_path30.default.resolve(__dirname, "..", "package.json"), "utf8")
27336
27644
  );
27337
27645
  var HELP_TEXT = [
27338
27646
  import_chalk4.default.bold(`pmate v${pkg.version}`),
@@ -27348,7 +27656,8 @@ var HELP_TEXT = [
27348
27656
  import_chalk4.default.bold("Commands:"),
27349
27657
  ` ${import_chalk4.default.cyan("list [path]")} List apps from .pmate.yaml in the target folder`,
27350
27658
  ` ${import_chalk4.default.cyan("login")} Log in and store a session in ~/.pmate/session.json`,
27351
- ` ${import_chalk4.default.gray(" [--app <app-id>] [--profile-id <id>]")}`,
27659
+ ` ${import_chalk4.default.gray(" [--app <app-id>] [--profile-id <id>] [--select-profile]")}`,
27660
+ ` ${import_chalk4.default.gray(" [--access-key [secret] | --access-key-file <path>]")}`,
27352
27661
  ` ${import_chalk4.default.cyan("add-dns")} Add a DNS record via Aliyun DNS`,
27353
27662
  ` ${import_chalk4.default.gray(" --type <t> --value <v> --rr <rr> [--ttl <n>] [--domain <name>]")}`,
27354
27663
  ` ${import_chalk4.default.cyan("sts")} Request an OSS STS token from the CI server`,
@@ -27581,6 +27890,10 @@ function parseCommandArgs(args) {
27581
27890
  const rest = args.rest.slice(1);
27582
27891
  let app;
27583
27892
  let profileId;
27893
+ let accessKey;
27894
+ let accessKeyFile;
27895
+ let accessKeyScan = false;
27896
+ let selectProfile = false;
27584
27897
  while (rest.length > 0) {
27585
27898
  const token = rest.shift();
27586
27899
  switch (token) {
@@ -27590,11 +27903,30 @@ function parseCommandArgs(args) {
27590
27903
  case "--profile-id":
27591
27904
  profileId = requireValue13(rest, token);
27592
27905
  break;
27906
+ case "--access-key":
27907
+ if (rest[0] && !rest[0].startsWith("--")) {
27908
+ accessKey = rest.shift();
27909
+ } else {
27910
+ accessKeyScan = true;
27911
+ }
27912
+ break;
27913
+ case "--access-key-file":
27914
+ accessKeyFile = requireValue13(rest, token);
27915
+ break;
27916
+ case "--select-profile":
27917
+ selectProfile = true;
27918
+ break;
27593
27919
  default:
27594
27920
  throw new Error(`Unknown login option: ${token}`);
27595
27921
  }
27596
27922
  }
27597
- return { type: "login" /* Login */, app, profileId };
27923
+ if (accessKey && accessKeyFile) {
27924
+ throw new Error("--access-key and --access-key-file are mutually exclusive");
27925
+ }
27926
+ if (accessKeyScan && accessKeyFile) {
27927
+ throw new Error("--access-key and --access-key-file are mutually exclusive");
27928
+ }
27929
+ return { type: "login" /* Login */, app, profileId, accessKey, accessKeyFile, accessKeyScan, selectProfile };
27598
27930
  }
27599
27931
  if (args.rest[0] === "add-dns") {
27600
27932
  return parseAddDnsArgs(args.rest.slice(1));