@pmate/cli 0.13.0 → 0.13.1

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.
Files changed (2) hide show
  1. package/dist/index.js +492 -471
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12407,10 +12407,10 @@ function resolveHubBaseUrl(value) {
12407
12407
  }
12408
12408
  function readSessionToken() {
12409
12409
  const sessionPath = import_node_path13.default.join(import_node_os4.default.homedir(), ".pmate", "session.json");
12410
- if (!(0, import_node_fs12.existsSync)(sessionPath)) {
12410
+ if (!(0, import_node_fs10.existsSync)(sessionPath)) {
12411
12411
  throw new Error(`Missing session file at ${sessionPath}. Run "pmate login" first.`);
12412
12412
  }
12413
- const raw = (0, import_node_fs12.readFileSync)(sessionPath, "utf8");
12413
+ const raw = (0, import_node_fs10.readFileSync)(sessionPath, "utf8");
12414
12414
  const parsed = JSON.parse(raw);
12415
12415
  const token = parsed.token?.trim();
12416
12416
  if (!token) {
@@ -12427,11 +12427,11 @@ function unwrapAgentResult(value) {
12427
12427
  }
12428
12428
  return value;
12429
12429
  }
12430
- var import_node_fs12, import_node_os4, import_node_path13, import_agent_sdk, DEFAULT_AGENT_API_BASE_URL, DEFAULT_AGENT_HUB_BASE_URL, DEFAULT_NAMESPACE, DEFAULT_FROM, AgentLlmClient;
12430
+ var import_node_fs10, import_node_os4, import_node_path13, import_agent_sdk, DEFAULT_AGENT_API_BASE_URL, DEFAULT_AGENT_HUB_BASE_URL, DEFAULT_NAMESPACE, DEFAULT_FROM, AgentLlmClient;
12431
12431
  var init_AgentLlmClient = __esm({
12432
12432
  "src/llm/AgentLlmClient.ts"() {
12433
12433
  "use strict";
12434
- import_node_fs12 = require("fs");
12434
+ import_node_fs10 = require("fs");
12435
12435
  import_node_os4 = __toESM(require("os"));
12436
12436
  import_node_path13 = __toESM(require("path"));
12437
12437
  import_agent_sdk = __toESM(require_dist4());
@@ -12479,7 +12479,7 @@ __export(index_exports, {
12479
12479
  parseCommandArgs: () => parseCommandArgs
12480
12480
  });
12481
12481
  module.exports = __toCommonJS(index_exports);
12482
- var import_node_fs19 = require("fs");
12482
+ var import_node_fs17 = require("fs");
12483
12483
  var import_node_path21 = __toESM(require("path"));
12484
12484
  var import_chalk3 = __toESM(require("chalk"));
12485
12485
 
@@ -12523,235 +12523,14 @@ var ui = {
12523
12523
  };
12524
12524
 
12525
12525
  // src/commands/ListCommandHandler.ts
12526
- var import_node_fs = require("fs");
12527
- var import_node_path = __toESM(require("path"));
12528
- var import_yaml = __toESM(require("yaml"));
12529
- var ListCommandHandler = class {
12530
- handle(args) {
12531
- const targetDir = this.resolveTargetDir(args.targetPath);
12532
- const config = this.loadConfig(targetDir);
12533
- if (config.apps.length === 0) {
12534
- ui.warn("No apps defined.");
12535
- return;
12536
- }
12537
- for (const app of config.apps) {
12538
- if (app && typeof app.app === "string") {
12539
- if (typeof app.dir !== "string" || !app.dir.trim()) {
12540
- throw new Error(`Invalid .pmate.yaml: missing dir for app ${app.app}`);
12541
- }
12542
- ui.info(`${app.app} -> ${app.dir}`);
12543
- }
12544
- }
12545
- }
12546
- resolveTargetDir(targetPath) {
12547
- return targetPath ? import_node_path.default.resolve(process.cwd(), targetPath) : process.cwd();
12548
- }
12549
- loadConfig(targetDir) {
12550
- const configPath = import_node_path.default.join(targetDir, ".pmate.yaml");
12551
- if (!(0, import_node_fs.existsSync)(configPath)) {
12552
- throw new Error(`No .pmate.yaml found in ${targetDir}`);
12553
- }
12554
- const raw = (0, import_node_fs.readFileSync)(configPath, "utf8");
12555
- const parsed = import_yaml.default.parse(raw);
12556
- if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.apps)) {
12557
- throw new Error("Invalid .pmate.yaml: missing apps array");
12558
- }
12559
- return parsed;
12560
- }
12561
- };
12562
-
12563
- // src/commands/LoginCommandHandler.ts
12564
- var import_node_fs2 = require("fs");
12565
- var import_node_http = require("http");
12566
- var import_node_os = __toESM(require("os"));
12567
12526
  var import_node_path2 = __toESM(require("path"));
12568
- var import_node_child_process = require("child_process");
12569
- var AUTH_UI_BASE_URL = "https://auth.pmate.chat";
12570
- var AUTH_API_BASE_URL = "https://auth-api-v2.pmate.chat";
12571
- var CALLBACK_PATH = "/pmate-login-callback";
12572
- var DEFAULT_APP_ID = "@pmate/cli";
12573
- var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
12574
- function buildHostedLoginUrl(redirectUrl, appId = DEFAULT_APP_ID) {
12575
- const url = new URL(AUTH_UI_BASE_URL);
12576
- url.searchParams.set("redirect", redirectUrl);
12577
- url.searchParams.set("app", appId);
12578
- return url.toString();
12579
- }
12580
- var LoginCommandHandler = class {
12581
- async handle(args) {
12582
- const callback = await this.startCallbackServer();
12583
- const appId = args.app?.trim() || DEFAULT_APP_ID;
12584
- const loginUrl = buildHostedLoginUrl(callback.redirectUrl, appId);
12585
- ui.info("Opening browser for login.", {
12586
- url: loginUrl,
12587
- app: appId
12588
- });
12589
- if (!this.openBrowser(loginUrl)) {
12590
- ui.warn("Unable to open the browser automatically.");
12591
- ui.plain(loginUrl);
12592
- }
12593
- ui.info("Waiting for login redirect...", {
12594
- callback: callback.redirectUrl,
12595
- app: appId
12596
- });
12597
- try {
12598
- const token = await callback.waitForToken;
12599
- const loginResponse = await this.fetchSession(token);
12600
- const sessionPath = this.writeSession(loginResponse);
12601
- ui.success(`Logged in. Session saved to ${sessionPath}`);
12602
- } finally {
12603
- await callback.close();
12604
- }
12605
- }
12606
- async fetchSession(token) {
12607
- const response = await fetch(`${AUTH_API_BASE_URL}/session`, {
12608
- method: "GET",
12609
- headers: {
12610
- Authorization: `Bearer ${token}`
12611
- }
12612
- });
12613
- if (!response.ok) {
12614
- const detail = await response.text();
12615
- throw new Error(
12616
- `Failed to validate session (${response.status}): ${detail || response.statusText}`
12617
- );
12618
- }
12619
- const resp = await response.json();
12620
- return {
12621
- ...resp.data,
12622
- token
12623
- };
12624
- }
12625
- async startCallbackServer() {
12626
- let resolveToken;
12627
- let rejectToken;
12628
- const waitForToken = new Promise((resolve, reject) => {
12629
- resolveToken = resolve;
12630
- rejectToken = reject;
12631
- });
12632
- const server = (0, import_node_http.createServer)((request, response) => {
12633
- this.handleCallbackRequest(request, response, resolveToken, rejectToken);
12634
- });
12635
- await new Promise((resolve, reject) => {
12636
- server.once("error", reject);
12637
- server.listen(0, "127.0.0.1", () => resolve());
12638
- });
12639
- const address = server.address();
12640
- if (!address || typeof address === "string") {
12641
- server.close();
12642
- throw new Error("Failed to start login callback server.");
12643
- }
12644
- const redirectUrl = `http://127.0.0.1:${address.port}${CALLBACK_PATH}`;
12645
- const timeout = setTimeout(() => {
12646
- rejectToken(
12647
- new Error(
12648
- `Timed out waiting for browser login after ${LOGIN_TIMEOUT_MS / 1e3} seconds.`
12649
- )
12650
- );
12651
- }, LOGIN_TIMEOUT_MS);
12652
- const close = async () => {
12653
- clearTimeout(timeout);
12654
- await new Promise((resolve) => {
12655
- server.close(() => resolve());
12656
- });
12657
- };
12658
- return {
12659
- redirectUrl,
12660
- waitForToken,
12661
- close
12662
- };
12663
- }
12664
- handleCallbackRequest(request, response, resolveToken, rejectToken) {
12665
- const url = new URL(request.url || "/", "http://127.0.0.1");
12666
- if (url.pathname !== CALLBACK_PATH) {
12667
- response.statusCode = 404;
12668
- response.end("Not found");
12669
- return;
12670
- }
12671
- const token = url.searchParams.get("sessionId")?.trim();
12672
- if (!token) {
12673
- response.statusCode = 400;
12674
- response.setHeader("Content-Type", "text/html; charset=utf-8");
12675
- response.end(this.renderHtml("Login failed", "Missing sessionId in redirect URL."));
12676
- rejectToken(new Error("Login callback did not include sessionId."));
12677
- return;
12678
- }
12679
- response.statusCode = 200;
12680
- response.setHeader("Content-Type", "text/html; charset=utf-8");
12681
- response.end(
12682
- this.renderHtml(
12683
- "Login complete",
12684
- "You can close this tab and return to the terminal."
12685
- )
12686
- );
12687
- resolveToken(token);
12688
- }
12689
- renderHtml(title, message) {
12690
- return `<!doctype html>
12691
- <html lang="en">
12692
- <head>
12693
- <meta charset="utf-8" />
12694
- <meta name="viewport" content="width=device-width, initial-scale=1" />
12695
- <title>${title}</title>
12696
- <style>
12697
- body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; padding: 32px; color: #111; }
12698
- main { max-width: 560px; margin: 10vh auto; }
12699
- h1 { font-size: 28px; margin-bottom: 12px; }
12700
- p { font-size: 16px; line-height: 1.5; }
12701
- </style>
12702
- </head>
12703
- <body>
12704
- <main>
12705
- <h1>${title}</h1>
12706
- <p>${message}</p>
12707
- </main>
12708
- </body>
12709
- </html>`;
12710
- }
12711
- openBrowser(url) {
12712
- const platform = process.platform;
12713
- const command = platform === "darwin" ? { cmd: "open", args: [url] } : platform === "win32" ? { cmd: "cmd", args: ["/c", "start", "", url] } : { cmd: "xdg-open", args: [url] };
12714
- try {
12715
- const child = (0, import_node_child_process.spawn)(command.cmd, command.args, {
12716
- detached: true,
12717
- stdio: "ignore"
12718
- });
12719
- child.unref();
12720
- return true;
12721
- } catch {
12722
- return false;
12723
- }
12724
- }
12725
- writeSession(session) {
12726
- const sessionDir = import_node_path2.default.join(import_node_os.default.homedir(), ".pmate");
12727
- const sessionPath = import_node_path2.default.join(sessionDir, "session.json");
12728
- (0, import_node_fs2.mkdirSync)(sessionDir, { recursive: true });
12729
- (0, import_node_fs2.writeFileSync)(sessionPath, JSON.stringify(session, null, 2), {
12730
- mode: 384
12731
- });
12732
- try {
12733
- (0, import_node_fs2.chmodSync)(sessionPath, 384);
12734
- } catch {
12735
- }
12736
- return sessionPath;
12737
- }
12738
- };
12739
-
12740
- // src/services/AliyunService.ts
12741
- var import_alidns20150109 = __toESM(require("@alicloud/alidns20150109"));
12742
- var import_cdn20180510 = __toESM(require("@alicloud/cdn20180510"));
12743
- var import_openapi_client = require("@alicloud/openapi-client");
12744
- var import_ali_oss = __toESM(require("ali-oss"));
12745
- var import_node_crypto = require("crypto");
12746
- var import_node_fs4 = require("fs");
12747
- var import_node_path4 = __toESM(require("path"));
12748
12527
 
12749
12528
  // src/config.ts
12750
- var import_node_fs3 = require("fs");
12751
- var import_node_os2 = __toESM(require("os"));
12752
- var import_node_path3 = __toESM(require("path"));
12529
+ var import_node_fs = require("fs");
12530
+ var import_node_os = __toESM(require("os"));
12531
+ var import_node_path = __toESM(require("path"));
12753
12532
  var import_ajv = __toESM(require("ajv"));
12754
- var import_yaml2 = __toESM(require("yaml"));
12533
+ var import_yaml = __toESM(require("yaml"));
12755
12534
  var cachedConfig;
12756
12535
  var CONFIG = new Proxy({}, {
12757
12536
  get(_target, prop) {
@@ -12873,13 +12652,13 @@ function loadPmateConfig() {
12873
12652
  if (cachedConfig !== void 0) {
12874
12653
  return cachedConfig ?? {};
12875
12654
  }
12876
- const pmateDir = import_node_path3.default.join(import_node_os2.default.homedir(), ".pmate");
12877
- const yamlPath = import_node_path3.default.join(pmateDir, "config.yaml");
12655
+ const pmateDir = import_node_path.default.join(import_node_os.default.homedir(), ".pmate");
12656
+ const yamlPath = import_node_path.default.join(pmateDir, "config.yaml");
12878
12657
  let yamlConfig = null;
12879
- if ((0, import_node_fs3.existsSync)(yamlPath)) {
12880
- const raw = (0, import_node_fs3.readFileSync)(yamlPath, "utf8");
12658
+ if ((0, import_node_fs.existsSync)(yamlPath)) {
12659
+ const raw = (0, import_node_fs.readFileSync)(yamlPath, "utf8");
12881
12660
  try {
12882
- const parsed = import_yaml2.default.parse(raw);
12661
+ const parsed = import_yaml.default.parse(raw);
12883
12662
  yamlConfig = validateParsedConfig(parsed, yamlPath);
12884
12663
  } catch (error) {
12885
12664
  const message = error instanceof Error ? error.message : String(error);
@@ -12890,19 +12669,38 @@ function loadPmateConfig() {
12890
12669
  return cachedConfig;
12891
12670
  }
12892
12671
  function loadRepoConfig(cwd) {
12893
- const configPath = findRepoConfigPath(cwd);
12894
- if (!configPath) {
12672
+ const paths = findRepoConfigPaths(cwd, true);
12673
+ if (!paths) {
12895
12674
  return null;
12896
12675
  }
12897
- const raw = (0, import_node_fs3.readFileSync)(configPath, "utf8");
12898
- let parsed;
12899
- try {
12900
- parsed = import_yaml2.default.parse(raw);
12901
- } catch (error) {
12902
- const message = error instanceof Error ? error.message : String(error);
12903
- throw new Error(`Invalid YAML in ${configPath}: ${message}`);
12676
+ const parsed = loadMergedRepoYaml(paths);
12677
+ return normalizeRepoConfig(parsed, paths.configPath);
12678
+ }
12679
+ function loadAppConfig(cwd, options = {}) {
12680
+ const paths = findRepoConfigPaths(cwd, options.searchParents ?? false);
12681
+ if (!paths) {
12682
+ const suffix = options.searchParents ? " or parent directories" : "";
12683
+ throw new Error(`No .pmate.yaml found in ${cwd}${suffix}`);
12684
+ }
12685
+ const parsed = loadMergedRepoYaml(paths);
12686
+ const appConfig = parsed;
12687
+ if (!appConfig || typeof appConfig !== "object" || !Array.isArray(appConfig.apps)) {
12688
+ throw new Error(
12689
+ `Invalid .pmate.yaml: missing apps array (${describeRepoConfigPaths(paths)})`
12690
+ );
12904
12691
  }
12905
- return normalizeRepoConfig(parsed, configPath);
12692
+ return {
12693
+ config: appConfig,
12694
+ rootDir: paths.rootDir,
12695
+ configPath: paths.configPath,
12696
+ localConfigPath: paths.localConfigPath
12697
+ };
12698
+ }
12699
+ function describeLoadedAppConfig({
12700
+ configPath,
12701
+ localConfigPath
12702
+ }) {
12703
+ return localConfigPath ? `${configPath} + ${localConfigPath}` : configPath;
12906
12704
  }
12907
12705
  function validateParsedConfig(value, configPath) {
12908
12706
  if (value === null || value === void 0) {
@@ -12918,101 +12716,384 @@ ${detail}`);
12918
12716
  }
12919
12717
  return value;
12920
12718
  }
12921
- function findRepoConfigPath(cwd) {
12922
- let current = import_node_path3.default.resolve(cwd);
12719
+ function findRepoConfigPaths(cwd, searchParents) {
12720
+ let current = import_node_path.default.resolve(cwd);
12923
12721
  while (true) {
12924
- const candidate = import_node_path3.default.join(current, ".pmate.yaml");
12925
- if ((0, import_node_fs3.existsSync)(candidate)) {
12926
- return candidate;
12722
+ const candidate = import_node_path.default.join(current, ".pmate.yaml");
12723
+ if ((0, import_node_fs.existsSync)(candidate)) {
12724
+ const localCandidate = import_node_path.default.join(current, ".pmate.local.yaml");
12725
+ return {
12726
+ rootDir: current,
12727
+ configPath: candidate,
12728
+ localConfigPath: (0, import_node_fs.existsSync)(localCandidate) ? localCandidate : void 0
12729
+ };
12730
+ }
12731
+ if (!searchParents) {
12732
+ return null;
12927
12733
  }
12928
- const parent = import_node_path3.default.dirname(current);
12734
+ const parent = import_node_path.default.dirname(current);
12929
12735
  if (parent === current) {
12930
12736
  return null;
12931
12737
  }
12932
- current = parent;
12933
- }
12934
- }
12935
- function normalizeRepoConfig(value, configPath) {
12936
- if (!value || typeof value !== "object") {
12937
- return null;
12938
- }
12939
- const config = value;
12940
- const hasRepoKeys = "githubUser" in config || "linear" in config;
12941
- if (!hasRepoKeys) {
12942
- return null;
12738
+ current = parent;
12739
+ }
12740
+ }
12741
+ function loadMergedRepoYaml(paths) {
12742
+ const base = parseYamlFile(paths.configPath);
12743
+ if (!paths.localConfigPath) {
12744
+ return base;
12745
+ }
12746
+ const local = parseYamlFile(paths.localConfigPath);
12747
+ return mergeRepoConfigValues(base, local);
12748
+ }
12749
+ function parseYamlFile(configPath) {
12750
+ const raw = (0, import_node_fs.readFileSync)(configPath, "utf8");
12751
+ try {
12752
+ return import_yaml.default.parse(raw);
12753
+ } catch (error) {
12754
+ const message = error instanceof Error ? error.message : String(error);
12755
+ throw new Error(`Invalid YAML in ${configPath}: ${message}`);
12756
+ }
12757
+ }
12758
+ function describeRepoConfigPaths(paths) {
12759
+ return paths.localConfigPath ? `${paths.configPath} + ${paths.localConfigPath}` : paths.configPath;
12760
+ }
12761
+ function mergeRepoConfigValues(base, local) {
12762
+ if (Array.isArray(base) && Array.isArray(local)) {
12763
+ return [...base, ...local];
12764
+ }
12765
+ if (isPlainObject(base) && isPlainObject(local)) {
12766
+ const merged = { ...base };
12767
+ for (const [key, localValue] of Object.entries(local)) {
12768
+ const baseValue = merged[key];
12769
+ if (key === "apps" && Array.isArray(baseValue) && Array.isArray(localValue)) {
12770
+ merged[key] = mergeApps(baseValue, localValue);
12771
+ continue;
12772
+ }
12773
+ merged[key] = mergeRepoConfigValues(baseValue, localValue);
12774
+ }
12775
+ return merged;
12776
+ }
12777
+ return local === void 0 ? base : local;
12778
+ }
12779
+ function mergeApps(baseApps, localApps) {
12780
+ const merged = [...baseApps];
12781
+ for (const localApp of localApps) {
12782
+ const localName = getAppName(localApp);
12783
+ if (!localName) {
12784
+ merged.push(localApp);
12785
+ continue;
12786
+ }
12787
+ const baseIndex = merged.findIndex((entry) => getAppName(entry) === localName);
12788
+ if (baseIndex === -1) {
12789
+ merged.push(localApp);
12790
+ continue;
12791
+ }
12792
+ merged[baseIndex] = mergeRepoConfigValues(merged[baseIndex], localApp);
12793
+ }
12794
+ return merged;
12795
+ }
12796
+ function getAppName(value) {
12797
+ if (!isPlainObject(value) || typeof value.app !== "string") {
12798
+ return void 0;
12799
+ }
12800
+ const app = value.app.trim();
12801
+ return app || void 0;
12802
+ }
12803
+ function isPlainObject(value) {
12804
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
12805
+ }
12806
+ function normalizeRepoConfig(value, configPath) {
12807
+ if (!value || typeof value !== "object") {
12808
+ return null;
12809
+ }
12810
+ const config = value;
12811
+ const hasRepoKeys = "githubUser" in config || "linear" in config;
12812
+ if (!hasRepoKeys) {
12813
+ return null;
12814
+ }
12815
+ const repoConfig = {};
12816
+ if (config.githubUser !== void 0) {
12817
+ if (typeof config.githubUser !== "string" || !config.githubUser.trim()) {
12818
+ throw new Error(
12819
+ `Invalid repo config in ${configPath}: githubUser must be a non-empty string.`
12820
+ );
12821
+ }
12822
+ repoConfig.githubUser = config.githubUser.trim();
12823
+ }
12824
+ if (config.linear !== void 0) {
12825
+ if (!config.linear || typeof config.linear !== "object") {
12826
+ throw new Error(
12827
+ `Invalid repo config in ${configPath}: linear must be an object.`
12828
+ );
12829
+ }
12830
+ const linear = config.linear;
12831
+ const teamId = getOptionalString(linear.teamId);
12832
+ const teamKey = getOptionalString(linear.teamKey);
12833
+ const rawAccount = linear.account ?? linear.accounts;
12834
+ if (!rawAccount) {
12835
+ throw new Error(
12836
+ `Invalid repo config in ${configPath}: linear account is required.`
12837
+ );
12838
+ }
12839
+ const account = normalizeRepoLinearAccount(rawAccount, configPath);
12840
+ repoConfig.linear = {
12841
+ teamId,
12842
+ teamKey,
12843
+ account
12844
+ };
12845
+ }
12846
+ return repoConfig;
12847
+ }
12848
+ function normalizeRepoLinearAccount(value, configPath) {
12849
+ const account = Array.isArray(value) ? value : [value];
12850
+ if (account.length !== 1) {
12851
+ throw new Error(
12852
+ `Invalid repo config in ${configPath}: linear account must be a single entry.`
12853
+ );
12854
+ }
12855
+ const entry = account[0];
12856
+ if (!entry || typeof entry !== "object") {
12857
+ throw new Error(
12858
+ `Invalid repo config in ${configPath}: linear account must be an object.`
12859
+ );
12860
+ }
12861
+ const raw = entry;
12862
+ const apiKey = getOptionalString(raw.apiKey);
12863
+ if (!apiKey) {
12864
+ throw new Error(
12865
+ `Invalid repo config in ${configPath}: linear account apiKey is required.`
12866
+ );
12867
+ }
12868
+ const title = getOptionalString(raw.title) || "Repo";
12869
+ const teamId = getOptionalString(raw.teamId);
12870
+ const teamKey = getOptionalString(raw.teamKey);
12871
+ return {
12872
+ title,
12873
+ apiKey,
12874
+ teamId,
12875
+ teamKey
12876
+ };
12877
+ }
12878
+ function getOptionalString(value) {
12879
+ if (typeof value !== "string") {
12880
+ return void 0;
12881
+ }
12882
+ const trimmed = value.trim();
12883
+ return trimmed ? trimmed : void 0;
12884
+ }
12885
+
12886
+ // src/commands/ListCommandHandler.ts
12887
+ var ListCommandHandler = class {
12888
+ handle(args) {
12889
+ const targetDir = this.resolveTargetDir(args.targetPath);
12890
+ const config = this.loadConfig(targetDir);
12891
+ if (config.apps.length === 0) {
12892
+ ui.warn("No apps defined.");
12893
+ return;
12894
+ }
12895
+ for (const app of config.apps) {
12896
+ if (app && typeof app.app === "string") {
12897
+ if (typeof app.dir !== "string" || !app.dir.trim()) {
12898
+ throw new Error(`Invalid .pmate.yaml: missing dir for app ${app.app}`);
12899
+ }
12900
+ ui.info(`${app.app} -> ${app.dir}`);
12901
+ }
12902
+ }
12903
+ }
12904
+ resolveTargetDir(targetPath) {
12905
+ return targetPath ? import_node_path2.default.resolve(process.cwd(), targetPath) : process.cwd();
12906
+ }
12907
+ loadConfig(targetDir) {
12908
+ return loadAppConfig(targetDir).config;
12909
+ }
12910
+ };
12911
+
12912
+ // src/commands/LoginCommandHandler.ts
12913
+ var import_node_fs2 = require("fs");
12914
+ var import_node_http = require("http");
12915
+ var import_node_os2 = __toESM(require("os"));
12916
+ var import_node_path3 = __toESM(require("path"));
12917
+ var import_node_child_process = require("child_process");
12918
+ var AUTH_UI_BASE_URL = "https://auth.pmate.chat";
12919
+ var AUTH_API_BASE_URL = "https://auth-api-v2.pmate.chat";
12920
+ var CALLBACK_PATH = "/pmate-login-callback";
12921
+ var DEFAULT_APP_ID = "@pmate/cli";
12922
+ var LOGIN_TIMEOUT_MS = 5 * 60 * 1e3;
12923
+ function buildHostedLoginUrl(redirectUrl, appId = DEFAULT_APP_ID) {
12924
+ const url = new URL(AUTH_UI_BASE_URL);
12925
+ url.searchParams.set("redirect", redirectUrl);
12926
+ url.searchParams.set("app", appId);
12927
+ return url.toString();
12928
+ }
12929
+ var LoginCommandHandler = class {
12930
+ async handle(args) {
12931
+ const callback = await this.startCallbackServer();
12932
+ const appId = args.app?.trim() || DEFAULT_APP_ID;
12933
+ const loginUrl = buildHostedLoginUrl(callback.redirectUrl, appId);
12934
+ ui.info("Opening browser for login.", {
12935
+ url: loginUrl,
12936
+ app: appId
12937
+ });
12938
+ if (!this.openBrowser(loginUrl)) {
12939
+ ui.warn("Unable to open the browser automatically.");
12940
+ ui.plain(loginUrl);
12941
+ }
12942
+ ui.info("Waiting for login redirect...", {
12943
+ callback: callback.redirectUrl,
12944
+ app: appId
12945
+ });
12946
+ try {
12947
+ const token = await callback.waitForToken;
12948
+ const loginResponse = await this.fetchSession(token);
12949
+ const sessionPath = this.writeSession(loginResponse);
12950
+ ui.success(`Logged in. Session saved to ${sessionPath}`);
12951
+ } finally {
12952
+ await callback.close();
12953
+ }
12943
12954
  }
12944
- const repoConfig = {};
12945
- if (config.githubUser !== void 0) {
12946
- if (typeof config.githubUser !== "string" || !config.githubUser.trim()) {
12955
+ async fetchSession(token) {
12956
+ const response = await fetch(`${AUTH_API_BASE_URL}/session`, {
12957
+ method: "GET",
12958
+ headers: {
12959
+ Authorization: `Bearer ${token}`
12960
+ }
12961
+ });
12962
+ if (!response.ok) {
12963
+ const detail = await response.text();
12947
12964
  throw new Error(
12948
- `Invalid repo config in ${configPath}: githubUser must be a non-empty string.`
12965
+ `Failed to validate session (${response.status}): ${detail || response.statusText}`
12949
12966
  );
12950
12967
  }
12951
- repoConfig.githubUser = config.githubUser.trim();
12968
+ const resp = await response.json();
12969
+ return {
12970
+ ...resp.data,
12971
+ token
12972
+ };
12952
12973
  }
12953
- if (config.linear !== void 0) {
12954
- if (!config.linear || typeof config.linear !== "object") {
12955
- throw new Error(
12956
- `Invalid repo config in ${configPath}: linear must be an object.`
12957
- );
12974
+ async startCallbackServer() {
12975
+ let resolveToken;
12976
+ let rejectToken;
12977
+ const waitForToken = new Promise((resolve, reject) => {
12978
+ resolveToken = resolve;
12979
+ rejectToken = reject;
12980
+ });
12981
+ const server = (0, import_node_http.createServer)((request, response) => {
12982
+ this.handleCallbackRequest(request, response, resolveToken, rejectToken);
12983
+ });
12984
+ await new Promise((resolve, reject) => {
12985
+ server.once("error", reject);
12986
+ server.listen(0, "127.0.0.1", () => resolve());
12987
+ });
12988
+ const address = server.address();
12989
+ if (!address || typeof address === "string") {
12990
+ server.close();
12991
+ throw new Error("Failed to start login callback server.");
12958
12992
  }
12959
- const linear = config.linear;
12960
- const teamId = getOptionalString(linear.teamId);
12961
- const teamKey = getOptionalString(linear.teamKey);
12962
- const rawAccount = linear.account ?? linear.accounts;
12963
- if (!rawAccount) {
12964
- throw new Error(
12965
- `Invalid repo config in ${configPath}: linear account is required.`
12993
+ const redirectUrl = `http://127.0.0.1:${address.port}${CALLBACK_PATH}`;
12994
+ const timeout = setTimeout(() => {
12995
+ rejectToken(
12996
+ new Error(
12997
+ `Timed out waiting for browser login after ${LOGIN_TIMEOUT_MS / 1e3} seconds.`
12998
+ )
12966
12999
  );
12967
- }
12968
- const account = normalizeRepoLinearAccount(rawAccount, configPath);
12969
- repoConfig.linear = {
12970
- teamId,
12971
- teamKey,
12972
- account
13000
+ }, LOGIN_TIMEOUT_MS);
13001
+ const close = async () => {
13002
+ clearTimeout(timeout);
13003
+ await new Promise((resolve) => {
13004
+ server.close(() => resolve());
13005
+ });
13006
+ };
13007
+ return {
13008
+ redirectUrl,
13009
+ waitForToken,
13010
+ close
12973
13011
  };
12974
13012
  }
12975
- return repoConfig;
12976
- }
12977
- function normalizeRepoLinearAccount(value, configPath) {
12978
- const account = Array.isArray(value) ? value : [value];
12979
- if (account.length !== 1) {
12980
- throw new Error(
12981
- `Invalid repo config in ${configPath}: linear account must be a single entry.`
13013
+ handleCallbackRequest(request, response, resolveToken, rejectToken) {
13014
+ const url = new URL(request.url || "/", "http://127.0.0.1");
13015
+ if (url.pathname !== CALLBACK_PATH) {
13016
+ response.statusCode = 404;
13017
+ response.end("Not found");
13018
+ return;
13019
+ }
13020
+ const token = url.searchParams.get("sessionId")?.trim();
13021
+ if (!token) {
13022
+ response.statusCode = 400;
13023
+ response.setHeader("Content-Type", "text/html; charset=utf-8");
13024
+ response.end(this.renderHtml("Login failed", "Missing sessionId in redirect URL."));
13025
+ rejectToken(new Error("Login callback did not include sessionId."));
13026
+ return;
13027
+ }
13028
+ response.statusCode = 200;
13029
+ response.setHeader("Content-Type", "text/html; charset=utf-8");
13030
+ response.end(
13031
+ this.renderHtml(
13032
+ "Login complete",
13033
+ "You can close this tab and return to the terminal."
13034
+ )
12982
13035
  );
13036
+ resolveToken(token);
12983
13037
  }
12984
- const entry = account[0];
12985
- if (!entry || typeof entry !== "object") {
12986
- throw new Error(
12987
- `Invalid repo config in ${configPath}: linear account must be an object.`
12988
- );
13038
+ renderHtml(title, message) {
13039
+ return `<!doctype html>
13040
+ <html lang="en">
13041
+ <head>
13042
+ <meta charset="utf-8" />
13043
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
13044
+ <title>${title}</title>
13045
+ <style>
13046
+ body { font-family: -apple-system, BlinkMacSystemFont, sans-serif; padding: 32px; color: #111; }
13047
+ main { max-width: 560px; margin: 10vh auto; }
13048
+ h1 { font-size: 28px; margin-bottom: 12px; }
13049
+ p { font-size: 16px; line-height: 1.5; }
13050
+ </style>
13051
+ </head>
13052
+ <body>
13053
+ <main>
13054
+ <h1>${title}</h1>
13055
+ <p>${message}</p>
13056
+ </main>
13057
+ </body>
13058
+ </html>`;
12989
13059
  }
12990
- const raw = entry;
12991
- const apiKey = getOptionalString(raw.apiKey);
12992
- if (!apiKey) {
12993
- throw new Error(
12994
- `Invalid repo config in ${configPath}: linear account apiKey is required.`
12995
- );
13060
+ openBrowser(url) {
13061
+ const platform = process.platform;
13062
+ const command = platform === "darwin" ? { cmd: "open", args: [url] } : platform === "win32" ? { cmd: "cmd", args: ["/c", "start", "", url] } : { cmd: "xdg-open", args: [url] };
13063
+ try {
13064
+ const child = (0, import_node_child_process.spawn)(command.cmd, command.args, {
13065
+ detached: true,
13066
+ stdio: "ignore"
13067
+ });
13068
+ child.unref();
13069
+ return true;
13070
+ } catch {
13071
+ return false;
13072
+ }
12996
13073
  }
12997
- const title = getOptionalString(raw.title) || "Repo";
12998
- const teamId = getOptionalString(raw.teamId);
12999
- const teamKey = getOptionalString(raw.teamKey);
13000
- return {
13001
- title,
13002
- apiKey,
13003
- teamId,
13004
- teamKey
13005
- };
13006
- }
13007
- function getOptionalString(value) {
13008
- if (typeof value !== "string") {
13009
- return void 0;
13074
+ writeSession(session) {
13075
+ const sessionDir = import_node_path3.default.join(import_node_os2.default.homedir(), ".pmate");
13076
+ const sessionPath = import_node_path3.default.join(sessionDir, "session.json");
13077
+ (0, import_node_fs2.mkdirSync)(sessionDir, { recursive: true });
13078
+ (0, import_node_fs2.writeFileSync)(sessionPath, JSON.stringify(session, null, 2), {
13079
+ mode: 384
13080
+ });
13081
+ try {
13082
+ (0, import_node_fs2.chmodSync)(sessionPath, 384);
13083
+ } catch {
13084
+ }
13085
+ return sessionPath;
13010
13086
  }
13011
- const trimmed = value.trim();
13012
- return trimmed ? trimmed : void 0;
13013
- }
13087
+ };
13014
13088
 
13015
13089
  // src/services/AliyunService.ts
13090
+ var import_alidns20150109 = __toESM(require("@alicloud/alidns20150109"));
13091
+ var import_cdn20180510 = __toESM(require("@alicloud/cdn20180510"));
13092
+ var import_openapi_client = require("@alicloud/openapi-client");
13093
+ var import_ali_oss = __toESM(require("ali-oss"));
13094
+ var import_node_crypto = require("crypto");
13095
+ var import_node_fs3 = require("fs");
13096
+ var import_node_path4 = __toESM(require("path"));
13016
13097
  var AliyunService = class {
13017
13098
  /** Add a DNS record via Aliyun DNS. */
13018
13099
  static async addRecord(input) {
@@ -13155,7 +13236,7 @@ var AliyunService = class {
13155
13236
  const options = contentType ? { headers: { "Content-Type": contentType } } : void 0;
13156
13237
  const existing = existingMap.get(objectKey);
13157
13238
  if (existing && typeof existing.size === "number") {
13158
- const stat = await import_node_fs4.promises.stat(filePath);
13239
+ const stat = await import_node_fs3.promises.stat(filePath);
13159
13240
  if (stat.size === existing.size) {
13160
13241
  const etag = this.normalizeEtag(existing.etag);
13161
13242
  if (etag && !etag.includes("-")) {
@@ -13180,7 +13261,7 @@ var AliyunService = class {
13180
13261
  if (!region) throw new Error("Missing oss.public.region in ~/.pmate/config.yaml.");
13181
13262
  if (!accessKeyId) throw new Error("Missing aliyun.ak in ~/.pmate/config.yaml.");
13182
13263
  if (!accessKeySecret) throw new Error("Missing aliyun.sk in ~/.pmate/config.yaml.");
13183
- if (!(0, import_node_fs4.existsSync)(localFile)) {
13264
+ if (!(0, import_node_fs3.existsSync)(localFile)) {
13184
13265
  throw new Error(`File not found: ${localFile}`);
13185
13266
  }
13186
13267
  const client = new import_ali_oss.default({ region, accessKeyId, accessKeySecret, bucket });
@@ -13455,7 +13536,7 @@ var AliyunService = class {
13455
13536
  }
13456
13537
  /** Recursively collect file paths under a directory. */
13457
13538
  static async collectFiles(dir) {
13458
- const entries = await import_node_fs4.promises.readdir(dir, { withFileTypes: true });
13539
+ const entries = await import_node_fs3.promises.readdir(dir, { withFileTypes: true });
13459
13540
  const files = [];
13460
13541
  for (const entry of entries) {
13461
13542
  const fullPath = import_node_path4.default.join(dir, entry.name);
@@ -13507,7 +13588,7 @@ var AliyunService = class {
13507
13588
  static getFileMd5(filePath) {
13508
13589
  return new Promise((resolve, reject) => {
13509
13590
  const hash = (0, import_node_crypto.createHash)("md5");
13510
- const stream = (0, import_node_fs4.createReadStream)(filePath);
13591
+ const stream = (0, import_node_fs3.createReadStream)(filePath);
13511
13592
  stream.on("data", (chunk) => {
13512
13593
  hash.update(chunk);
13513
13594
  });
@@ -13592,7 +13673,7 @@ var AddDnsCommandHandler = class {
13592
13673
  };
13593
13674
 
13594
13675
  // src/commands/StsCommandHandler.ts
13595
- var import_node_fs5 = require("fs");
13676
+ var import_node_fs4 = require("fs");
13596
13677
  var import_node_os3 = __toESM(require("os"));
13597
13678
  var import_node_path5 = __toESM(require("path"));
13598
13679
  var import_chalk2 = __toESM(require("chalk"));
@@ -13624,10 +13705,10 @@ var StsCommandHandler = class {
13624
13705
  }
13625
13706
  readSession() {
13626
13707
  const sessionPath = import_node_path5.default.join(import_node_os3.default.homedir(), ".pmate", "session.json");
13627
- if (!(0, import_node_fs5.existsSync)(sessionPath)) {
13708
+ if (!(0, import_node_fs4.existsSync)(sessionPath)) {
13628
13709
  throw new Error("Missing session. Run `pmate login` first.");
13629
13710
  }
13630
- const raw = (0, import_node_fs5.readFileSync)(sessionPath, "utf8");
13711
+ const raw = (0, import_node_fs4.readFileSync)(sessionPath, "utf8");
13631
13712
  return JSON.parse(raw);
13632
13713
  }
13633
13714
  };
@@ -13642,10 +13723,9 @@ var BucketCommandHandler = class {
13642
13723
  };
13643
13724
 
13644
13725
  // src/commands/DeployCommandHandler.ts
13645
- var import_node_fs6 = require("fs");
13726
+ var import_node_fs5 = require("fs");
13646
13727
  var import_node_path7 = __toESM(require("path"));
13647
13728
  var import_node_child_process2 = require("child_process");
13648
- var import_yaml3 = __toESM(require("yaml"));
13649
13729
 
13650
13730
  // src/appDir.ts
13651
13731
  var import_node_path6 = __toESM(require("path"));
@@ -13695,11 +13775,12 @@ var DeployCommandHandler = class {
13695
13775
  );
13696
13776
  }
13697
13777
  const cwd = this.resolveCwd(args.deployCwd);
13698
- const config = this.loadConfig(cwd);
13778
+ const loadedConfig = this.loadConfig(cwd);
13779
+ const config = loadedConfig.config;
13699
13780
  const appConfig = config.apps.find((entry) => entry?.app === appName);
13700
13781
  if (!appConfig) {
13701
13782
  throw new Error(
13702
- `No app named ${appName} found in ${import_node_path7.default.join(cwd, ".pmate.yaml")}`
13783
+ `No app named ${appName} found in ${describeLoadedAppConfig(loadedConfig)}`
13703
13784
  );
13704
13785
  }
13705
13786
  if (args.deployAction === "logs") {
@@ -13743,7 +13824,7 @@ var DeployCommandHandler = class {
13743
13824
  async deployVite(appName, cwd, appConfig) {
13744
13825
  const appDir = resolveLocalAppDir(cwd, appName, appConfig.dir);
13745
13826
  const packageJsonPath = import_node_path7.default.join(appDir, "package.json");
13746
- if (!(0, import_node_fs6.existsSync)(packageJsonPath)) {
13827
+ if (!(0, import_node_fs5.existsSync)(packageJsonPath)) {
13747
13828
  throw new Error(`No package.json found at ${packageJsonPath}`);
13748
13829
  }
13749
13830
  const pkg2 = this.loadPackageJson(packageJsonPath);
@@ -13753,7 +13834,7 @@ var DeployCommandHandler = class {
13753
13834
  }
13754
13835
  await this.runCommand("pnpm", ["--filter", pkgName, "build"], cwd);
13755
13836
  const distDir = import_node_path7.default.join(appDir, "dist");
13756
- if (!(0, import_node_fs6.existsSync)(distDir)) {
13837
+ if (!(0, import_node_fs5.existsSync)(distDir)) {
13757
13838
  throw new Error(`No dist directory found at ${distDir}`);
13758
13839
  }
13759
13840
  const bucketName = appConfig.bucket?.trim();
@@ -13767,7 +13848,7 @@ var DeployCommandHandler = class {
13767
13848
  async deployStatic(appName, cwd, appConfig) {
13768
13849
  const appDir = resolveLocalAppDir(cwd, appName, appConfig.dir);
13769
13850
  const srcDir = import_node_path7.default.join(appDir, "src");
13770
- if (!(0, import_node_fs6.existsSync)(srcDir)) {
13851
+ if (!(0, import_node_fs5.existsSync)(srcDir)) {
13771
13852
  throw new Error(`No src directory found at ${srcDir}`);
13772
13853
  }
13773
13854
  const bucketName = appConfig.bucket?.trim();
@@ -13882,7 +13963,7 @@ var DeployCommandHandler = class {
13882
13963
  return target ? import_node_path7.default.resolve(process.cwd(), target) : process.cwd();
13883
13964
  }
13884
13965
  loadPackageJson(packageJsonPath) {
13885
- const raw = (0, import_node_fs6.readFileSync)(packageJsonPath, "utf8");
13966
+ const raw = (0, import_node_fs5.readFileSync)(packageJsonPath, "utf8");
13886
13967
  const parsed = JSON.parse(raw);
13887
13968
  if (!parsed || typeof parsed !== "object") {
13888
13969
  throw new Error(`Invalid package.json at ${packageJsonPath}`);
@@ -13890,16 +13971,7 @@ var DeployCommandHandler = class {
13890
13971
  return parsed;
13891
13972
  }
13892
13973
  loadConfig(cwd) {
13893
- const configPath = import_node_path7.default.join(cwd, ".pmate.yaml");
13894
- if (!(0, import_node_fs6.existsSync)(configPath)) {
13895
- throw new Error(`No .pmate.yaml found in ${cwd}`);
13896
- }
13897
- const raw = (0, import_node_fs6.readFileSync)(configPath, "utf8");
13898
- const parsed = import_yaml3.default.parse(raw);
13899
- if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.apps)) {
13900
- throw new Error("Invalid .pmate.yaml: missing apps array");
13901
- }
13902
- return parsed;
13974
+ return loadAppConfig(cwd);
13903
13975
  }
13904
13976
  runCommand(command, args, cwd) {
13905
13977
  return new Promise((resolve, reject) => {
@@ -13969,11 +14041,10 @@ var DeployCommandHandler = class {
13969
14041
  };
13970
14042
 
13971
14043
  // src/commands/LogCommandHandler.ts
13972
- var import_node_fs7 = require("fs");
14044
+ var import_node_fs6 = require("fs");
13973
14045
  var import_node_child_process3 = require("child_process");
13974
14046
  var import_node_path8 = __toESM(require("path"));
13975
14047
  var import_node_module = require("module");
13976
- var import_yaml4 = __toESM(require("yaml"));
13977
14048
  var LogCommandHandler = class {
13978
14049
  async handle(args) {
13979
14050
  const appName = args.logApp.trim();
@@ -13981,14 +14052,13 @@ var LogCommandHandler = class {
13981
14052
  throw new Error("Missing app name. Usage: log <app-name> [--cwd <dir>].");
13982
14053
  }
13983
14054
  const cwd = this.resolveCwd(args.logCwd);
13984
- const { config, configPath } = this.loadClosestConfig(cwd);
14055
+ const { config, configPath, repoRoot } = this.loadClosestConfig(cwd);
13985
14056
  const appConfig = config.apps.find((entry) => entry?.app === appName);
13986
14057
  if (!appConfig) {
13987
14058
  throw new Error(`No app named ${appName} found in ${configPath}`);
13988
14059
  }
13989
14060
  if (appConfig.type === "node") {
13990
14061
  const server = this.resolveNodeServer(appName, appConfig);
13991
- const repoRoot = import_node_path8.default.dirname(configPath);
13992
14062
  const pm2Name = this.resolvePm2AppName(repoRoot, appName, appConfig);
13993
14063
  await this.runRemotePm2Logs(server, pm2Name);
13994
14064
  return;
@@ -14005,30 +14075,12 @@ var LogCommandHandler = class {
14005
14075
  return target ? import_node_path8.default.resolve(process.cwd(), target) : process.cwd();
14006
14076
  }
14007
14077
  loadClosestConfig(cwd) {
14008
- const configPath = this.findRepoConfigPath(cwd);
14009
- if (!configPath) {
14010
- throw new Error(`No .pmate.yaml found in ${cwd} or parent directories`);
14011
- }
14012
- const raw = (0, import_node_fs7.readFileSync)(configPath, "utf8");
14013
- const parsed = import_yaml4.default.parse(raw);
14014
- if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.apps)) {
14015
- throw new Error(`Invalid .pmate.yaml: missing apps array (${configPath})`);
14016
- }
14017
- return { config: parsed, configPath };
14018
- }
14019
- findRepoConfigPath(cwd) {
14020
- let current = import_node_path8.default.resolve(cwd);
14021
- while (true) {
14022
- const candidate = import_node_path8.default.join(current, ".pmate.yaml");
14023
- if ((0, import_node_fs7.existsSync)(candidate)) {
14024
- return candidate;
14025
- }
14026
- const parent = import_node_path8.default.dirname(current);
14027
- if (parent === current) {
14028
- return null;
14029
- }
14030
- current = parent;
14031
- }
14078
+ const loaded = loadAppConfig(cwd, { searchParents: true });
14079
+ return {
14080
+ config: loaded.config,
14081
+ configPath: describeLoadedAppConfig(loaded),
14082
+ repoRoot: loaded.rootDir
14083
+ };
14032
14084
  }
14033
14085
  resolveNodeServer(appName, appConfig) {
14034
14086
  const server = appConfig.server?.trim();
@@ -14052,11 +14104,11 @@ var LogCommandHandler = class {
14052
14104
  }
14053
14105
  findEcosystemPath(appDir) {
14054
14106
  const cjs = import_node_path8.default.join(appDir, "ecosystem.config.cjs");
14055
- if ((0, import_node_fs7.existsSync)(cjs)) {
14107
+ if ((0, import_node_fs6.existsSync)(cjs)) {
14056
14108
  return cjs;
14057
14109
  }
14058
14110
  const js = import_node_path8.default.join(appDir, "ecosystem.config.js");
14059
- if ((0, import_node_fs7.existsSync)(js)) {
14111
+ if ((0, import_node_fs6.existsSync)(js)) {
14060
14112
  return js;
14061
14113
  }
14062
14114
  return null;
@@ -14157,11 +14209,11 @@ var LogCommandHandler = class {
14157
14209
  };
14158
14210
 
14159
14211
  // src/commands/InitCommandHandler.ts
14160
- var import_node_fs8 = require("fs");
14212
+ var import_node_fs7 = require("fs");
14161
14213
  var import_node_path9 = __toESM(require("path"));
14162
14214
  var import_node_child_process4 = require("child_process");
14163
14215
  var import_promises2 = require("readline/promises");
14164
- var import_yaml5 = __toESM(require("yaml"));
14216
+ var import_yaml2 = __toESM(require("yaml"));
14165
14217
 
14166
14218
  // src/serverAddress.ts
14167
14219
  var import_promises = require("dns/promises");
@@ -14189,14 +14241,14 @@ var InitCommandHandler = class {
14189
14241
  throw new Error("Missing app name. Usage: init <app-name> [--cwd <dir>].");
14190
14242
  }
14191
14243
  const cwd = this.resolveCwd(args.initCwd);
14192
- const config = this.loadConfig(cwd);
14244
+ const { config } = this.loadConfig(cwd);
14193
14245
  let appConfig = config.apps.find((entry) => entry?.app === appName);
14194
14246
  if (!appConfig) {
14195
14247
  appConfig = await this.addAppConfig(config, appName, cwd);
14196
14248
  }
14197
14249
  if (appConfig.type !== "rust") {
14198
14250
  const appDir = resolveLocalAppDir(cwd, appName, appConfig.dir);
14199
- if (!(0, import_node_fs8.existsSync)(appDir)) {
14251
+ if (!(0, import_node_fs7.existsSync)(appDir)) {
14200
14252
  throw new Error(`No app folder found at ${appDir}`);
14201
14253
  }
14202
14254
  }
@@ -14364,10 +14416,10 @@ var InitCommandHandler = class {
14364
14416
  const serverAddress = await resolveServerAddress(server);
14365
14417
  const templateName = serviceType === "ws" ? "nginx.ws.template" : "nginx.rest.template";
14366
14418
  const templatePath = import_node_path9.default.join(__dirname, "..", "templates", templateName);
14367
- if (!(0, import_node_fs8.existsSync)(templatePath)) {
14419
+ if (!(0, import_node_fs7.existsSync)(templatePath)) {
14368
14420
  throw new Error(`Missing nginx template at ${templatePath}`);
14369
14421
  }
14370
- const template = (0, import_node_fs8.readFileSync)(templatePath, "utf8");
14422
+ const template = (0, import_node_fs7.readFileSync)(templatePath, "utf8");
14371
14423
  const host = `${subdomain}.pmate.chat`;
14372
14424
  const rendered = template.replace(/\$\{\{PORT\}\}/g, String(port)).replace(/\$\{\{HOSTS\}\}/g, host).replace(/\$\{\{HOST\}\}/g, host);
14373
14425
  const remotePath = `/etc/nginx/sites-enabled/${subdomain}.conf`;
@@ -14400,15 +14452,15 @@ var InitCommandHandler = class {
14400
14452
  if (options.ensurePackageJson) {
14401
14453
  const appDir = resolveLocalAppDir(cwd, appConfig.app, appConfig.dir);
14402
14454
  ui.info(`Resolved appDir: ${appDir}`);
14403
- if (!(0, import_node_fs8.existsSync)(appDir)) {
14455
+ if (!(0, import_node_fs7.existsSync)(appDir)) {
14404
14456
  throw new Error(`Missing app folder at ${appDir}`);
14405
14457
  }
14406
14458
  const packageJsonPath = import_node_path9.default.join(appDir, "package.json");
14407
14459
  ui.info(`Resolved package.json: ${packageJsonPath}`);
14408
- if (!(0, import_node_fs8.existsSync)(packageJsonPath)) {
14460
+ if (!(0, import_node_fs7.existsSync)(packageJsonPath)) {
14409
14461
  throw new Error(`Missing package.json at ${packageJsonPath}`);
14410
14462
  }
14411
- const pkgStat = (0, import_node_fs8.statSync)(packageJsonPath);
14463
+ const pkgStat = (0, import_node_fs7.statSync)(packageJsonPath);
14412
14464
  ui.info(
14413
14465
  `package.json stat: isFile=${pkgStat.isFile()} isDirectory=${pkgStat.isDirectory()}`
14414
14466
  );
@@ -14474,16 +14526,7 @@ var InitCommandHandler = class {
14474
14526
  return new Promise((resolve) => setTimeout(resolve, ms));
14475
14527
  }
14476
14528
  loadConfig(cwd) {
14477
- const configPath = import_node_path9.default.join(cwd, ".pmate.yaml");
14478
- if (!(0, import_node_fs8.existsSync)(configPath)) {
14479
- throw new Error(`No .pmate.yaml found in ${cwd}`);
14480
- }
14481
- const raw = (0, import_node_fs8.readFileSync)(configPath, "utf8");
14482
- const parsed = import_yaml5.default.parse(raw);
14483
- if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.apps)) {
14484
- throw new Error("Invalid .pmate.yaml: missing apps array");
14485
- }
14486
- return parsed;
14529
+ return loadAppConfig(cwd);
14487
14530
  }
14488
14531
  async addAppConfig(config, appName, cwd) {
14489
14532
  ui.title(`App ${appName} not found in .pmate.yaml.`);
@@ -14601,7 +14644,7 @@ var InitCommandHandler = class {
14601
14644
  }
14602
14645
  }
14603
14646
  loadPackageJson(packageJsonPath) {
14604
- const raw = (0, import_node_fs8.readFileSync)(packageJsonPath, "utf8");
14647
+ const raw = (0, import_node_fs7.readFileSync)(packageJsonPath, "utf8");
14605
14648
  const parsed = JSON.parse(raw);
14606
14649
  if (!parsed || typeof parsed !== "object") {
14607
14650
  throw new Error(`Invalid package.json at ${packageJsonPath}`);
@@ -14610,13 +14653,13 @@ var InitCommandHandler = class {
14610
14653
  }
14611
14654
  writePackageJson(packageJsonPath, data) {
14612
14655
  const serialized = JSON.stringify(data, null, 2);
14613
- (0, import_node_fs8.writeFileSync)(packageJsonPath, `${serialized}
14656
+ (0, import_node_fs7.writeFileSync)(packageJsonPath, `${serialized}
14614
14657
  `, "utf8");
14615
14658
  }
14616
14659
  writeConfig(cwd, config) {
14617
14660
  const configPath = import_node_path9.default.join(cwd, ".pmate.yaml");
14618
- const serialized = import_yaml5.default.stringify(config).trimEnd();
14619
- (0, import_node_fs8.writeFileSync)(configPath, `${serialized}
14661
+ const serialized = import_yaml2.default.stringify(config).trimEnd();
14662
+ (0, import_node_fs7.writeFileSync)(configPath, `${serialized}
14620
14663
  `, "utf8");
14621
14664
  }
14622
14665
  async promptRequired(rl, question) {
@@ -14652,10 +14695,9 @@ var InitCommandHandler = class {
14652
14695
  };
14653
14696
 
14654
14697
  // src/commands/DevCommandHandler.ts
14655
- var import_node_fs9 = require("fs");
14698
+ var import_node_fs8 = require("fs");
14656
14699
  var import_node_path10 = __toESM(require("path"));
14657
14700
  var import_node_child_process5 = require("child_process");
14658
- var import_yaml6 = __toESM(require("yaml"));
14659
14701
  var DevCommandHandler = class {
14660
14702
  async handle(args) {
14661
14703
  const appName = args.devApp.trim();
@@ -14663,16 +14705,17 @@ var DevCommandHandler = class {
14663
14705
  throw new Error("Missing app name. Usage: dev <app-name> [--cwd <dir>].");
14664
14706
  }
14665
14707
  const cwd = this.resolveCwd(args.devCwd);
14666
- const config = this.loadConfig(cwd);
14708
+ const loadedConfig = this.loadConfig(cwd);
14709
+ const config = loadedConfig.config;
14667
14710
  const appConfig = config.apps.find((entry) => entry?.app === appName);
14668
14711
  if (!appConfig) {
14669
14712
  throw new Error(
14670
- `No app named ${appName} found in ${import_node_path10.default.join(cwd, ".pmate.yaml")}`
14713
+ `No app named ${appName} found in ${describeLoadedAppConfig(loadedConfig)}`
14671
14714
  );
14672
14715
  }
14673
14716
  const appDir = resolveLocalAppDir(cwd, appName, appConfig.dir);
14674
14717
  const packageJsonPath = import_node_path10.default.join(appDir, "package.json");
14675
- if (!(0, import_node_fs9.existsSync)(packageJsonPath)) {
14718
+ if (!(0, import_node_fs8.existsSync)(packageJsonPath)) {
14676
14719
  throw new Error(`No package.json found at ${packageJsonPath}`);
14677
14720
  }
14678
14721
  const pkg2 = this.loadPackageJson(packageJsonPath);
@@ -14689,19 +14732,10 @@ var DevCommandHandler = class {
14689
14732
  return target ? import_node_path10.default.resolve(process.cwd(), target) : process.cwd();
14690
14733
  }
14691
14734
  loadConfig(cwd) {
14692
- const configPath = import_node_path10.default.join(cwd, ".pmate.yaml");
14693
- if (!(0, import_node_fs9.existsSync)(configPath)) {
14694
- throw new Error(`No .pmate.yaml found in ${cwd}`);
14695
- }
14696
- const raw = (0, import_node_fs9.readFileSync)(configPath, "utf8");
14697
- const parsed = import_yaml6.default.parse(raw);
14698
- if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.apps)) {
14699
- throw new Error("Invalid .pmate.yaml: missing apps array");
14700
- }
14701
- return parsed;
14735
+ return loadAppConfig(cwd);
14702
14736
  }
14703
14737
  loadPackageJson(packageJsonPath) {
14704
- const raw = (0, import_node_fs9.readFileSync)(packageJsonPath, "utf8");
14738
+ const raw = (0, import_node_fs8.readFileSync)(packageJsonPath, "utf8");
14705
14739
  const parsed = JSON.parse(raw);
14706
14740
  if (!parsed || typeof parsed !== "object") {
14707
14741
  throw new Error(`Invalid package.json at ${packageJsonPath}`);
@@ -14729,7 +14763,7 @@ var DevCommandHandler = class {
14729
14763
  };
14730
14764
 
14731
14765
  // src/commands/OssCommandHandler.ts
14732
- var import_node_fs10 = require("fs");
14766
+ var import_node_fs9 = require("fs");
14733
14767
  var import_node_path11 = __toESM(require("path"));
14734
14768
  var import_promises3 = require("readline/promises");
14735
14769
  var OssCommandHandler = class {
@@ -14765,10 +14799,10 @@ var OssCommandHandler = class {
14765
14799
  }
14766
14800
  }
14767
14801
  assertFile(filePath) {
14768
- if (!(0, import_node_fs10.existsSync)(filePath)) {
14802
+ if (!(0, import_node_fs9.existsSync)(filePath)) {
14769
14803
  throw new Error(`File not found: ${filePath}`);
14770
14804
  }
14771
- const stat = (0, import_node_fs10.statSync)(filePath);
14805
+ const stat = (0, import_node_fs9.statSync)(filePath);
14772
14806
  if (!stat.isFile()) {
14773
14807
  throw new Error(`Not a file: ${filePath}`);
14774
14808
  }
@@ -14804,10 +14838,8 @@ var OssCommandHandler = class {
14804
14838
  };
14805
14839
 
14806
14840
  // src/commands/EnvCommandHandler.ts
14807
- var import_node_fs11 = require("fs");
14808
14841
  var import_node_path12 = __toESM(require("path"));
14809
14842
  var import_node_child_process6 = require("child_process");
14810
- var import_yaml7 = __toESM(require("yaml"));
14811
14843
  var EnvCommandHandler = class {
14812
14844
  async handle(args) {
14813
14845
  const appName = args.envApp.trim();
@@ -14816,14 +14848,12 @@ var EnvCommandHandler = class {
14816
14848
  "Missing app name. Usage: env <app-name> --list|--set KEY --value VALUE|--delete KEY [--cwd <dir>] [--verbose|-v]"
14817
14849
  );
14818
14850
  }
14819
- const config = this.loadConfig(args.envCwd);
14851
+ const loadedConfig = this.loadConfig(args.envCwd);
14852
+ const config = loadedConfig.config;
14820
14853
  const appConfig = config.apps.find((entry) => entry?.app === appName);
14821
14854
  if (!appConfig) {
14822
14855
  throw new Error(
14823
- `No app named ${appName} found in ${import_node_path12.default.join(
14824
- process.cwd(),
14825
- ".pmate.yaml"
14826
- )}`
14856
+ `No app named ${appName} found in ${describeLoadedAppConfig(loadedConfig)}`
14827
14857
  );
14828
14858
  }
14829
14859
  if (appConfig.type !== "node") {
@@ -15091,16 +15121,7 @@ var EnvCommandHandler = class {
15091
15121
  }
15092
15122
  }
15093
15123
  loadConfig(cwd) {
15094
- const configPath = import_node_path12.default.join(cwd, ".pmate.yaml");
15095
- if (!(0, import_node_fs11.existsSync)(configPath)) {
15096
- throw new Error(`No .pmate.yaml found in ${cwd}`);
15097
- }
15098
- const raw = (0, import_node_fs11.readFileSync)(configPath, "utf8");
15099
- const parsed = import_yaml7.default.parse(raw);
15100
- if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.apps)) {
15101
- throw new Error("Invalid .pmate.yaml: missing apps array");
15102
- }
15103
- return parsed;
15124
+ return loadAppConfig(cwd);
15104
15125
  }
15105
15126
  runRemoteCommand(server, command) {
15106
15127
  return new Promise((resolve, reject) => {
@@ -16003,7 +16024,7 @@ function truncate2(value, limit) {
16003
16024
 
16004
16025
  // src/commands/LinearCommandHandler.ts
16005
16026
  var import_node_child_process9 = require("child_process");
16006
- var import_node_fs13 = require("fs");
16027
+ var import_node_fs11 = require("fs");
16007
16028
  var import_node_os5 = __toESM(require("os"));
16008
16029
  var import_node_path15 = __toESM(require("path"));
16009
16030
  var import_promises4 = require("readline/promises");
@@ -16893,11 +16914,11 @@ var LinearCommandHandler = class {
16893
16914
  }
16894
16915
  readCachedLinearSelection(cwd) {
16895
16916
  const selectionPath = this.getLinearSelectionPath();
16896
- if (!(0, import_node_fs13.existsSync)(selectionPath)) {
16917
+ if (!(0, import_node_fs11.existsSync)(selectionPath)) {
16897
16918
  return void 0;
16898
16919
  }
16899
16920
  try {
16900
- const raw = (0, import_node_fs13.readFileSync)(selectionPath, "utf8").trim();
16921
+ const raw = (0, import_node_fs11.readFileSync)(selectionPath, "utf8").trim();
16901
16922
  if (!raw) return void 0;
16902
16923
  const parsed = JSON.parse(raw);
16903
16924
  const value = parsed[cwd];
@@ -16909,11 +16930,11 @@ var LinearCommandHandler = class {
16909
16930
  writeCachedLinearSelection(cwd, title) {
16910
16931
  const selectionPath = this.getLinearSelectionPath();
16911
16932
  const dir = import_node_path15.default.dirname(selectionPath);
16912
- (0, import_node_fs13.mkdirSync)(dir, { recursive: true });
16933
+ (0, import_node_fs11.mkdirSync)(dir, { recursive: true });
16913
16934
  let data = {};
16914
- if ((0, import_node_fs13.existsSync)(selectionPath)) {
16935
+ if ((0, import_node_fs11.existsSync)(selectionPath)) {
16915
16936
  try {
16916
- const raw = (0, import_node_fs13.readFileSync)(selectionPath, "utf8").trim();
16937
+ const raw = (0, import_node_fs11.readFileSync)(selectionPath, "utf8").trim();
16917
16938
  if (raw) {
16918
16939
  data = JSON.parse(raw);
16919
16940
  }
@@ -16922,7 +16943,7 @@ var LinearCommandHandler = class {
16922
16943
  }
16923
16944
  }
16924
16945
  data[cwd] = title;
16925
- (0, import_node_fs13.writeFileSync)(selectionPath, `${JSON.stringify(data, null, 2)}
16946
+ (0, import_node_fs11.writeFileSync)(selectionPath, `${JSON.stringify(data, null, 2)}
16926
16947
  `, "utf8");
16927
16948
  }
16928
16949
  async lookupIssue(client, issueRef) {
@@ -17099,14 +17120,14 @@ var LinearCommandHandler = class {
17099
17120
  if (process.platform !== "darwin") {
17100
17121
  throw new Error("Screenshot capture only supports macOS.");
17101
17122
  }
17102
- const dir = await import_node_fs13.promises.mkdtemp(import_node_path15.default.join(import_node_os5.default.tmpdir(), "pmate-screenshot-"));
17123
+ const dir = await import_node_fs11.promises.mkdtemp(import_node_path15.default.join(import_node_os5.default.tmpdir(), "pmate-screenshot-"));
17103
17124
  const filePath = import_node_path15.default.join(dir, `screenshot-${index}.png`);
17104
17125
  try {
17105
17126
  const code = await this.run("screencapture", ["-i", "-x", filePath], true);
17106
17127
  if (code !== 0) {
17107
17128
  throw new Error("Screenshot capture canceled or failed.");
17108
17129
  }
17109
- const buffer = await import_node_fs13.promises.readFile(filePath);
17130
+ const buffer = await import_node_fs11.promises.readFile(filePath);
17110
17131
  if (buffer.length === 0) {
17111
17132
  throw new Error("Screenshot capture produced an empty file.");
17112
17133
  }
@@ -17118,7 +17139,7 @@ var LinearCommandHandler = class {
17118
17139
  return { buffer, mime, filename: `screenshot-${index}.${extension}` };
17119
17140
  } finally {
17120
17141
  try {
17121
- await import_node_fs13.promises.rm(dir, { recursive: true, force: true });
17142
+ await import_node_fs11.promises.rm(dir, { recursive: true, force: true });
17122
17143
  } catch {
17123
17144
  }
17124
17145
  }
@@ -17262,17 +17283,17 @@ var LinearCommandHandler = class {
17262
17283
  return compact.length > limit ? `${compact.slice(0, limit)}...` : compact;
17263
17284
  }
17264
17285
  async convertToPng(buffer, ext) {
17265
- const dir = await import_node_fs13.promises.mkdtemp(import_node_path15.default.join(import_node_os5.default.tmpdir(), "pmate-"));
17286
+ const dir = await import_node_fs11.promises.mkdtemp(import_node_path15.default.join(import_node_os5.default.tmpdir(), "pmate-"));
17266
17287
  const inputPath = import_node_path15.default.join(dir, `clipboard.${ext}`);
17267
17288
  const outputPath = import_node_path15.default.join(dir, "clipboard.png");
17268
17289
  try {
17269
- await import_node_fs13.promises.writeFile(inputPath, buffer);
17290
+ await import_node_fs11.promises.writeFile(inputPath, buffer);
17270
17291
  const stderr = await this.runCapture(
17271
17292
  "sips",
17272
17293
  ["-s", "format", "png", inputPath, "--out", outputPath],
17273
17294
  true
17274
17295
  );
17275
- const out = await import_node_fs13.promises.readFile(outputPath);
17296
+ const out = await import_node_fs11.promises.readFile(outputPath);
17276
17297
  if (this.detectImageMime(out) !== "image/png") {
17277
17298
  throw new Error(
17278
17299
  stderr?.trim() ? `Failed to convert clipboard ${ext} to PNG: ${stderr.trim()}` : `Failed to convert clipboard ${ext} to PNG.`
@@ -17281,7 +17302,7 @@ var LinearCommandHandler = class {
17281
17302
  return out;
17282
17303
  } finally {
17283
17304
  try {
17284
- await import_node_fs13.promises.rm(dir, { recursive: true, force: true });
17305
+ await import_node_fs11.promises.rm(dir, { recursive: true, force: true });
17285
17306
  } catch {
17286
17307
  }
17287
17308
  }
@@ -17627,7 +17648,7 @@ function sleep(ms) {
17627
17648
  }
17628
17649
 
17629
17650
  // src/commands/NotionCommandHandler.ts
17630
- var import_node_fs14 = require("fs");
17651
+ var import_node_fs12 = require("fs");
17631
17652
  var import_node_path16 = __toESM(require("path"));
17632
17653
 
17633
17654
  // src/services/NotionService.ts
@@ -17968,13 +17989,13 @@ var NotionCommandHandler = class {
17968
17989
  return "";
17969
17990
  }
17970
17991
  const resolved = import_node_path16.default.resolve(process.cwd(), args.filePath);
17971
- return (0, import_node_fs14.readFileSync)(resolved, "utf8");
17992
+ return (0, import_node_fs12.readFileSync)(resolved, "utf8");
17972
17993
  }
17973
17994
  };
17974
17995
 
17975
17996
  // src/commands/QrcodeCommandHandler.ts
17976
17997
  var import_node_child_process10 = require("child_process");
17977
- var import_node_fs15 = require("fs");
17998
+ var import_node_fs13 = require("fs");
17978
17999
  var import_node_os6 = __toESM(require("os"));
17979
18000
  var import_node_path17 = __toESM(require("path"));
17980
18001
  var import_promises5 = require("readline/promises");
@@ -18002,7 +18023,7 @@ var QrcodeCommandHandler = class {
18002
18023
  ui.success("QR code value:", value);
18003
18024
  } finally {
18004
18025
  try {
18005
- await import_node_fs15.promises.rm(dir, { recursive: true, force: true });
18026
+ await import_node_fs13.promises.rm(dir, { recursive: true, force: true });
18006
18027
  } catch {
18007
18028
  }
18008
18029
  }
@@ -18018,13 +18039,13 @@ var QrcodeCommandHandler = class {
18018
18039
  } finally {
18019
18040
  rl.close();
18020
18041
  }
18021
- const dir = await import_node_fs15.promises.mkdtemp(import_node_path17.default.join(import_node_os6.default.tmpdir(), "pmate-qrcode-"));
18042
+ const dir = await import_node_fs13.promises.mkdtemp(import_node_path17.default.join(import_node_os6.default.tmpdir(), "pmate-qrcode-"));
18022
18043
  const filePath = import_node_path17.default.join(dir, "qrcode.png");
18023
18044
  const code = await this.run("screencapture", ["-i", "-x", filePath], true);
18024
18045
  if (code !== 0) {
18025
18046
  throw new Error("Screenshot capture canceled or failed.");
18026
18047
  }
18027
- const buffer = await import_node_fs15.promises.readFile(filePath);
18048
+ const buffer = await import_node_fs13.promises.readFile(filePath);
18028
18049
  if (buffer.length === 0) {
18029
18050
  throw new Error("Screenshot capture produced an empty file.");
18030
18051
  }
@@ -18040,7 +18061,7 @@ var QrcodeCommandHandler = class {
18040
18061
  async decodeQr(filePath) {
18041
18062
  let buffer;
18042
18063
  try {
18043
- buffer = await import_node_fs15.promises.readFile(filePath);
18064
+ buffer = await import_node_fs13.promises.readFile(filePath);
18044
18065
  } catch {
18045
18066
  return null;
18046
18067
  }
@@ -18300,7 +18321,7 @@ function clampNumber(value, min, max, fallback) {
18300
18321
  // src/commands/CollectCommandHandler.ts
18301
18322
  var import_playwright = require("playwright");
18302
18323
  var import_node_crypto3 = require("crypto");
18303
- var import_node_fs16 = require("fs");
18324
+ var import_node_fs14 = require("fs");
18304
18325
  var import_node_os7 = __toESM(require("os"));
18305
18326
  var import_node_path18 = __toESM(require("path"));
18306
18327
  var CollectCommandHandler = class {
@@ -18677,11 +18698,11 @@ async function toDisplayableImagePath(src) {
18677
18698
  return src;
18678
18699
  }
18679
18700
  try {
18680
- const stat = await import_node_fs16.promises.stat(src);
18701
+ const stat = await import_node_fs14.promises.stat(src);
18681
18702
  if (!stat.isFile()) {
18682
18703
  return src;
18683
18704
  }
18684
- const fh = await import_node_fs16.promises.open(src, "r");
18705
+ const fh = await import_node_fs14.promises.open(src, "r");
18685
18706
  try {
18686
18707
  const buf = Buffer.alloc(32);
18687
18708
  const { bytesRead } = await fh.read(buf, 0, 32, 0);
@@ -18696,11 +18717,11 @@ async function toDisplayableImagePath(src) {
18696
18717
  "messages",
18697
18718
  "images"
18698
18719
  );
18699
- await import_node_fs16.promises.mkdir(cacheDir, { recursive: true });
18720
+ await import_node_fs14.promises.mkdir(cacheDir, { recursive: true });
18700
18721
  const base = (0, import_node_crypto3.createHash)("sha1").update(src).digest("hex");
18701
18722
  const displayPath = import_node_path18.default.join(cacheDir, `${base}.${guessedExt}`);
18702
- await import_node_fs16.promises.rm(displayPath, { force: true }).catch(() => void 0);
18703
- await import_node_fs16.promises.copyFile(src, displayPath);
18723
+ await import_node_fs14.promises.rm(displayPath, { force: true }).catch(() => void 0);
18724
+ await import_node_fs14.promises.copyFile(src, displayPath);
18704
18725
  return displayPath;
18705
18726
  } finally {
18706
18727
  await fh.close();
@@ -18756,7 +18777,7 @@ function parseMessageText(raw) {
18756
18777
  }
18757
18778
 
18758
18779
  // src/commands/AgentCommandHandler.ts
18759
- var import_node_fs17 = require("fs");
18780
+ var import_node_fs15 = require("fs");
18760
18781
  var import_node_os8 = __toESM(require("os"));
18761
18782
  var import_node_path19 = __toESM(require("path"));
18762
18783
  var AgentCommandHandler = class {
@@ -18841,10 +18862,10 @@ var AgentCommandHandler = class {
18841
18862
  }
18842
18863
  readToken() {
18843
18864
  const sessionPath = import_node_path19.default.join(import_node_os8.default.homedir(), ".pmate", "session.json");
18844
- if (!(0, import_node_fs17.existsSync)(sessionPath)) {
18865
+ if (!(0, import_node_fs15.existsSync)(sessionPath)) {
18845
18866
  throw new Error(`Missing session file at ${sessionPath}. Run "pmate login" first.`);
18846
18867
  }
18847
- const raw = (0, import_node_fs17.readFileSync)(sessionPath, "utf8");
18868
+ const raw = (0, import_node_fs15.readFileSync)(sessionPath, "utf8");
18848
18869
  const parsed = JSON.parse(raw);
18849
18870
  const token = parsed.token?.trim();
18850
18871
  if (!token) {
@@ -18854,10 +18875,10 @@ var AgentCommandHandler = class {
18854
18875
  }
18855
18876
  readJsonFile(filePath) {
18856
18877
  const absolutePath = import_node_path19.default.resolve(process.cwd(), filePath);
18857
- if (!(0, import_node_fs17.existsSync)(absolutePath)) {
18878
+ if (!(0, import_node_fs15.existsSync)(absolutePath)) {
18858
18879
  throw new Error(`JSON file not found: ${absolutePath}`);
18859
18880
  }
18860
- const raw = (0, import_node_fs17.readFileSync)(absolutePath, "utf8");
18881
+ const raw = (0, import_node_fs15.readFileSync)(absolutePath, "utf8");
18861
18882
  try {
18862
18883
  return JSON.parse(raw);
18863
18884
  } catch (error) {
@@ -18926,7 +18947,7 @@ var AgentCommandHandler = class {
18926
18947
  };
18927
18948
 
18928
18949
  // src/commands/AppCommandHandler.ts
18929
- var import_node_fs18 = require("fs");
18950
+ var import_node_fs16 = require("fs");
18930
18951
  var import_node_os9 = __toESM(require("os"));
18931
18952
  var import_node_path20 = __toESM(require("path"));
18932
18953
  var AppCommandHandler = class {
@@ -18998,10 +19019,10 @@ var AppCommandHandler = class {
18998
19019
  }
18999
19020
  readToken() {
19000
19021
  const sessionPath = import_node_path20.default.join(import_node_os9.default.homedir(), ".pmate", "session.json");
19001
- if (!(0, import_node_fs18.existsSync)(sessionPath)) {
19022
+ if (!(0, import_node_fs16.existsSync)(sessionPath)) {
19002
19023
  throw new Error(`Missing session file at ${sessionPath}. Run "pmate login" first.`);
19003
19024
  }
19004
- const raw = (0, import_node_fs18.readFileSync)(sessionPath, "utf8");
19025
+ const raw = (0, import_node_fs16.readFileSync)(sessionPath, "utf8");
19005
19026
  const parsed = JSON.parse(raw);
19006
19027
  const token = parsed.token?.trim();
19007
19028
  if (!token) {
@@ -19011,10 +19032,10 @@ var AppCommandHandler = class {
19011
19032
  }
19012
19033
  readJsonFile(filePath) {
19013
19034
  const absolutePath = import_node_path20.default.resolve(process.cwd(), filePath);
19014
- if (!(0, import_node_fs18.existsSync)(absolutePath)) {
19035
+ if (!(0, import_node_fs16.existsSync)(absolutePath)) {
19015
19036
  throw new Error(`JSON file not found: ${absolutePath}`);
19016
19037
  }
19017
- const raw = (0, import_node_fs18.readFileSync)(absolutePath, "utf8");
19038
+ const raw = (0, import_node_fs16.readFileSync)(absolutePath, "utf8");
19018
19039
  try {
19019
19040
  return JSON.parse(raw);
19020
19041
  } catch (error) {
@@ -19431,7 +19452,7 @@ function requireValue2(tokens, optionName) {
19431
19452
 
19432
19453
  // src/index.ts
19433
19454
  var pkg = JSON.parse(
19434
- (0, import_node_fs19.readFileSync)(import_node_path21.default.resolve(__dirname, "..", "package.json"), "utf8")
19455
+ (0, import_node_fs17.readFileSync)(import_node_path21.default.resolve(__dirname, "..", "package.json"), "utf8")
19435
19456
  );
19436
19457
  var HELP_TEXT = [
19437
19458
  import_chalk3.default.bold(`pmate v${pkg.version}`),