@mtreeai/msapling-cli 2.3.6-beta.42 → 2.3.6-beta.44

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 +785 -2150
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1,10 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from 'module'; const require = createRequire(import.meta.url);
3
- var __create = Object.create;
4
3
  var __defProp = Object.defineProperty;
5
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
7
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
10
8
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
@@ -15,9 +13,6 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
15
13
  var __esm = (fn, res) => function __init() {
16
14
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
17
15
  };
18
- var __commonJS = (cb, mod) => function __require2() {
19
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
20
- };
21
16
  var __export = (target, all) => {
22
17
  for (var name in all)
23
18
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -30,22 +25,14 @@ var __copyProps = (to, from, except, desc) => {
30
25
  }
31
26
  return to;
32
27
  };
33
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
34
- // If the importer is in node compatibility mode or this is not an ESM
35
- // file that has been converted to a CommonJS file using a Babel-
36
- // compatible transform (i.e. "__esModule" has not been set), then set
37
- // "default" to the CommonJS "module.exports" for node compatibility.
38
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
39
- mod
40
- ));
41
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
42
29
 
43
- // ../../node_modules/.bun/tsup@8.5.1+2af0484081a85c02/node_modules/tsup/assets/esm_shims.js
30
+ // ../../node_modules/tsup/assets/esm_shims.js
44
31
  import path from "path";
45
32
  import { fileURLToPath } from "url";
46
33
  var getFilename, getDirname, __dirname;
47
34
  var init_esm_shims = __esm({
48
- "../../node_modules/.bun/tsup@8.5.1+2af0484081a85c02/node_modules/tsup/assets/esm_shims.js"() {
35
+ "../../node_modules/tsup/assets/esm_shims.js"() {
49
36
  "use strict";
50
37
  getFilename = () => fileURLToPath(import.meta.url);
51
38
  getDirname = () => path.dirname(getFilename());
@@ -304,17 +291,61 @@ import {
304
291
  renameSync,
305
292
  writeFileSync
306
293
  } from "fs";
294
+ import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
295
+ function configureJournalCrypto(provider) {
296
+ _journalKeyProvider = provider;
297
+ }
298
+ function resetJournalCrypto() {
299
+ _journalKeyProvider = null;
300
+ }
301
+ function requireKey() {
302
+ const key = _journalKeyProvider ? _journalKeyProvider() : null;
303
+ if (!key || key.length !== 32) throw new JournalEncryptionUnavailableError();
304
+ return key;
305
+ }
306
+ function encryptContent(plaintext) {
307
+ const key = requireKey();
308
+ const iv = randomBytes(12);
309
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
310
+ const ct = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
311
+ const tag = cipher.getAuthTag();
312
+ return ENC_PREFIX + Buffer.concat([iv, tag, ct]).toString("base64");
313
+ }
314
+ function isEncrypted(value) {
315
+ return typeof value === "string" && value.startsWith(ENC_PREFIX);
316
+ }
317
+ function decryptContent(stored) {
318
+ if (!isEncrypted(stored)) return stored;
319
+ const key = requireKey();
320
+ const buf = Buffer.from(stored.slice(ENC_PREFIX.length), "base64");
321
+ const iv = buf.subarray(0, 12);
322
+ const tag = buf.subarray(12, 28);
323
+ const ct = buf.subarray(28);
324
+ const decipher = createDecipheriv("aes-256-gcm", key, iv);
325
+ decipher.setAuthTag(tag);
326
+ return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
327
+ }
307
328
  function getJournal() {
308
329
  if (!journalInstance) {
309
330
  journalInstance = new Journal();
310
331
  }
311
332
  return journalInstance;
312
333
  }
313
- var DatabaseConnection, Journal, journalInstance;
334
+ var ENC_PREFIX, _journalKeyProvider, JournalEncryptionUnavailableError, DatabaseConnection, Journal, journalInstance;
314
335
  var init_journal = __esm({
315
336
  "../api-client/src/journal.ts"() {
316
337
  "use strict";
317
338
  init_esm_shims();
339
+ ENC_PREFIX = "enc:v1:";
340
+ _journalKeyProvider = null;
341
+ JournalEncryptionUnavailableError = class extends Error {
342
+ constructor() {
343
+ super(
344
+ "Cannot write offline journal entry: no encryption key is available. The journal refuses to persist chat content in plaintext. Ensure the OS keychain is reachable (so the journal key can be stored) and retry."
345
+ );
346
+ this.name = "JournalEncryptionUnavailableError";
347
+ }
348
+ };
318
349
  try {
319
350
  const sqlite = __require("sqlite");
320
351
  DatabaseConnection = sqlite;
@@ -328,7 +359,7 @@ var init_journal = __esm({
328
359
  db = null;
329
360
  jsonlEntries = [];
330
361
  constructor() {
331
- const home = homedir2();
362
+ const home = process.env.HOME || process.env.USERPROFILE || homedir2();
332
363
  const msaplingDir = join2(home, ".msapling");
333
364
  this.dbPath = join2(msaplingDir, "journal.sqlite");
334
365
  this.jsonlPath = join2(msaplingDir, "journal.jsonl");
@@ -385,11 +416,14 @@ var init_journal = __esm({
385
416
  for (const line of content.split("\n")) {
386
417
  const trimmed = line.trim();
387
418
  if (!trimmed) continue;
419
+ let parsed;
388
420
  try {
389
- this.jsonlEntries.push(JSON.parse(trimmed));
421
+ parsed = JSON.parse(trimmed);
390
422
  } catch {
391
423
  malformed++;
424
+ continue;
392
425
  }
426
+ this.jsonlEntries.push(parsed);
393
427
  }
394
428
  if (malformed > 0) {
395
429
  console.warn(`[Journal] Skipped ${malformed} malformed JSONL line(s)`);
@@ -399,10 +433,21 @@ var init_journal = __esm({
399
433
  }
400
434
  }
401
435
  async journalAppend(entry) {
436
+ let encryptedContent;
437
+ try {
438
+ encryptedContent = encryptContent(entry.content);
439
+ } catch (e) {
440
+ if (e instanceof JournalEncryptionUnavailableError) {
441
+ console.warn("[Journal] Skipping append: encryption key unavailable (refusing to write plaintext).");
442
+ return;
443
+ }
444
+ throw e;
445
+ }
402
446
  if (this.useJsonl) {
403
- this.jsonlEntries.push(entry);
447
+ const onDisk = { ...entry, content: encryptedContent };
448
+ this.jsonlEntries.push(onDisk);
404
449
  try {
405
- appendFileSync(this.jsonlPath, JSON.stringify(entry) + "\n", "utf8");
450
+ appendFileSync(this.jsonlPath, JSON.stringify(onDisk) + "\n", "utf8");
406
451
  } catch (e) {
407
452
  console.warn("[Journal] Failed to append JSONL entry", e);
408
453
  }
@@ -417,7 +462,7 @@ var init_journal = __esm({
417
462
  entry.chat_id,
418
463
  entry.project_id || null,
419
464
  entry.role,
420
- entry.content,
465
+ encryptedContent,
421
466
  entry.ts,
422
467
  entry.model || null,
423
468
  entry.token_count || null,
@@ -429,8 +474,15 @@ var init_journal = __esm({
429
474
  }
430
475
  }
431
476
  async journalListPending() {
477
+ const decryptEntry = (e) => {
478
+ try {
479
+ return { ...e, content: decryptContent(e.content) };
480
+ } catch {
481
+ return { ...e, content: "[encrypted \u2014 key unavailable]" };
482
+ }
483
+ };
432
484
  if (this.useJsonl) {
433
- return this.jsonlEntries.filter((e) => !e.synced_at);
485
+ return this.jsonlEntries.filter((e) => !e.synced_at).map(decryptEntry);
434
486
  }
435
487
  if (!this.db) return [];
436
488
  try {
@@ -441,7 +493,7 @@ var init_journal = __esm({
441
493
  ORDER BY ts ASC
442
494
  `);
443
495
  const rows = stmt.all();
444
- return rows.map((r) => ({
496
+ return rows.map((r) => decryptEntry({
445
497
  id: r.id,
446
498
  chat_id: r.chat_id,
447
499
  project_id: r.project_id,
@@ -521,18 +573,18 @@ var init_journal = __esm({
521
573
  });
522
574
 
523
575
  // ../api-client/src/oauth.ts
524
- import { randomBytes, createHash } from "crypto";
576
+ import { randomBytes as randomBytes2, createHash } from "crypto";
525
577
  function base64url(buf) {
526
578
  return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
527
579
  }
528
580
  function generateState() {
529
- return base64url(randomBytes(32));
581
+ return base64url(randomBytes2(32));
530
582
  }
531
583
  function generateNonce() {
532
- return base64url(randomBytes(24));
584
+ return base64url(randomBytes2(24));
533
585
  }
534
586
  function generatePKCE() {
535
- const verifier = base64url(randomBytes(32));
587
+ const verifier = base64url(randomBytes2(32));
536
588
  const challenge = base64url(createHash("sha256").update(verifier).digest());
537
589
  return { verifier, challenge, method: "S256" };
538
590
  }
@@ -720,19 +772,24 @@ var init_refreshFamily = __esm({
720
772
  var src_exports = {};
721
773
  __export(src_exports, {
722
774
  Journal: () => Journal,
775
+ JournalEncryptionUnavailableError: () => JournalEncryptionUnavailableError,
723
776
  LocalLlmClient: () => LocalLlmClient,
724
777
  MSaplingClient: () => MSaplingClient,
725
778
  MSaplingError: () => MSaplingError,
726
779
  OllamaClient: () => OllamaClient,
727
780
  RefreshTokenFamilyStore: () => RefreshTokenFamilyStore,
781
+ configureJournalCrypto: () => configureJournalCrypto,
728
782
  decodeJwtClaims: () => decodeJwtClaims,
783
+ decryptContent: () => decryptContent,
729
784
  detectLocalLlm: () => detectLocalLlm,
785
+ encryptContent: () => encryptContent,
730
786
  generateNonce: () => generateNonce,
731
787
  generatePKCE: () => generatePKCE,
732
788
  generateState: () => generateState,
733
789
  getJournal: () => getJournal,
734
790
  newTransaction: () => newTransaction,
735
791
  probeDialect: () => probeDialect,
792
+ resetJournalCrypto: () => resetJournalCrypto,
736
793
  timingSafeEquals: () => timingSafeEquals,
737
794
  validateJwtClaims: () => validateJwtClaims
738
795
  });
@@ -803,10 +860,14 @@ var init_src = __esm({
803
860
  * controller.abort();
804
861
  */
805
862
  _clientSignal;
863
+ // CLI-STREAM-IDLE-TIMEOUT-01: per-chunk idle deadline for streamChat's
864
+ // reader loop (see ClientOptions.streamIdleTimeoutMs). Defaults to 60s.
865
+ _streamIdleTimeoutMs;
806
866
  constructor(options = {}) {
807
867
  this.apiUrl = (options.apiUrl || "https://api.msapling.com").replace(/\/$/, "");
808
868
  this.token = options.token || null;
809
869
  this._clientSignal = options.signal;
870
+ this._streamIdleTimeoutMs = options.streamIdleTimeoutMs ?? 6e4;
810
871
  }
811
872
  setToken(token) {
812
873
  this.token = token;
@@ -871,6 +932,9 @@ var init_src = __esm({
871
932
  if (!headers.has("Content-Type")) {
872
933
  headers.set("Content-Type", "application/json");
873
934
  }
935
+ if (!headers.has("X-Client-Type")) {
936
+ headers.set("X-Client-Type", "cli");
937
+ }
874
938
  if (this.cookies.size > 0) {
875
939
  headers.set("Cookie", this.serializeCookies());
876
940
  }
@@ -923,6 +987,12 @@ var init_src = __esm({
923
987
  }
924
988
  }
925
989
  return response.json();
990
+ } catch (e) {
991
+ if (e instanceof MSaplingError) throw e;
992
+ if (e?.name === "AbortError") {
993
+ throw new MSaplingError("Request timed out after 30s.", 408, "timeout");
994
+ }
995
+ throw e;
926
996
  } finally {
927
997
  clearTimeout(timeout);
928
998
  }
@@ -1598,10 +1668,25 @@ var init_src = __esm({
1598
1668
  else this._clientSignal.addEventListener("abort", externalAbortHandler);
1599
1669
  }
1600
1670
  const timeout = setTimeout(() => controller.abort(), 3e4);
1671
+ let idleTimer;
1672
+ let idleAborted = false;
1673
+ const idleMs = this._streamIdleTimeoutMs;
1674
+ const armIdleTimer = () => {
1675
+ if (!idleMs || idleMs <= 0) return;
1676
+ if (idleTimer) clearTimeout(idleTimer);
1677
+ idleTimer = setTimeout(() => {
1678
+ idleAborted = true;
1679
+ controller.abort();
1680
+ }, idleMs);
1681
+ };
1601
1682
  try {
1602
1683
  const headers = {
1603
1684
  "Authorization": `Bearer ${this.token}`,
1604
- "Content-Type": "application/json"
1685
+ "Content-Type": "application/json",
1686
+ // CLI-CLIENT-TYPE-HEADER-01: identify the chat-stream surface as "cli"
1687
+ // so the backend's active-stream registry / 423 lock-owner message
1688
+ // attributes the slot correctly instead of defaulting to "web".
1689
+ "X-Client-Type": "cli"
1605
1690
  };
1606
1691
  if (this.cookies.size > 0) {
1607
1692
  headers["Cookie"] = this.serializeCookies();
@@ -1639,21 +1724,29 @@ var init_src = __esm({
1639
1724
  if (!response.body) throw new Error("No response body");
1640
1725
  const reader = response.body.getReader();
1641
1726
  const decoder = new TextDecoder();
1727
+ armIdleTimer();
1642
1728
  let pending = "";
1643
1729
  const yieldLine = function* (raw) {
1644
1730
  const line = raw.replace(/\r$/, "").trim();
1645
1731
  if (!line) return;
1732
+ let parsed;
1646
1733
  try {
1647
- yield JSON.parse(line);
1734
+ parsed = JSON.parse(line);
1648
1735
  } catch {
1649
1736
  if (line.startsWith("{")) {
1650
1737
  console.warn(`[Stream] Dropped malformed JSON: ${line}`);
1651
1738
  }
1739
+ return;
1740
+ }
1741
+ if (parsed && typeof parsed === "object" && typeof parsed.error === "string" && parsed.error) {
1742
+ throw new MSaplingError(parsed.error, void 0, "stream_error");
1652
1743
  }
1744
+ yield parsed;
1653
1745
  };
1654
1746
  while (true) {
1655
1747
  const { done, value } = await reader.read();
1656
1748
  if (done) break;
1749
+ armIdleTimer();
1657
1750
  pending += decoder.decode(value, { stream: true });
1658
1751
  let nlIdx;
1659
1752
  while ((nlIdx = pending.indexOf("\n")) !== -1) {
@@ -1669,12 +1762,20 @@ var init_src = __esm({
1669
1762
  }
1670
1763
  } catch (e) {
1671
1764
  if (e.name === "AbortError") {
1765
+ if (idleAborted) {
1766
+ throw new MSaplingError(
1767
+ `Stream stalled \u2014 no data for ${Math.round(idleMs / 1e3)}s.`,
1768
+ 408,
1769
+ "stream_idle_timeout"
1770
+ );
1771
+ }
1672
1772
  if (externalSignal?.aborted || this._clientSignal?.aborted) throw e;
1673
1773
  throw new MSaplingError("Request timed out after 30s.", 408, "timeout");
1674
1774
  }
1675
1775
  throw e;
1676
1776
  } finally {
1677
1777
  clearTimeout(timeout);
1778
+ if (idleTimer) clearTimeout(idleTimer);
1678
1779
  if (externalSignal) {
1679
1780
  externalSignal.removeEventListener("abort", externalAbortHandler);
1680
1781
  }
@@ -1899,7 +2000,7 @@ import { resolve as resolve2, normalize as normalize2, relative as relative2, is
1899
2000
  import { writeFile, readFile as readFile3, mkdir } from "fs/promises";
1900
2001
  import { existsSync as existsSync3 } from "fs";
1901
2002
  import { homedir as homedir3 } from "os";
1902
- import { randomBytes as randomBytes2 } from "crypto";
2003
+ import { randomBytes as randomBytes3 } from "crypto";
1903
2004
  var MAX_CONTENT_BYTES, WriteFileTool;
1904
2005
  var init_WriteFileTool = __esm({
1905
2006
  "../core/src/tools/WriteFileTool.ts"() {
@@ -1976,7 +2077,7 @@ var init_WriteFileTool = __esm({
1976
2077
  const existingContent = await readFile3(resolvedTarget, "utf8");
1977
2078
  const filename = resolvedTarget.split(/[\\/]/).pop() ?? "file";
1978
2079
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
1979
- const suffix = randomBytes2(4).toString("hex");
2080
+ const suffix = randomBytes3(4).toString("hex");
1980
2081
  const backupPath = join4(homedir3(), ".msapling", "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
1981
2082
  await mkdir(join4(homedir3(), ".msapling", "backups"), { recursive: true });
1982
2083
  await writeFile(backupPath, existingContent, "utf8");
@@ -2004,236 +2105,17 @@ Previous content backed up to: ${backedUpTo}`;
2004
2105
  }
2005
2106
  });
2006
2107
 
2007
- // ../../node_modules/.bun/shell-quote@1.8.3/node_modules/shell-quote/quote.js
2008
- var require_quote = __commonJS({
2009
- "../../node_modules/.bun/shell-quote@1.8.3/node_modules/shell-quote/quote.js"(exports, module) {
2010
- "use strict";
2011
- init_esm_shims();
2012
- module.exports = function quote(xs) {
2013
- return xs.map(function(s) {
2014
- if (s === "") {
2015
- return "''";
2016
- }
2017
- if (s && typeof s === "object") {
2018
- return s.op.replace(/(.)/g, "\\$1");
2019
- }
2020
- if (/["\s\\]/.test(s) && !/'/.test(s)) {
2021
- return "'" + s.replace(/(['])/g, "\\$1") + "'";
2022
- }
2023
- if (/["'\s]/.test(s)) {
2024
- return '"' + s.replace(/(["\\$`!])/g, "\\$1") + '"';
2025
- }
2026
- return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g, "$1\\$2");
2027
- }).join(" ");
2028
- };
2029
- }
2030
- });
2031
-
2032
- // ../../node_modules/.bun/shell-quote@1.8.3/node_modules/shell-quote/parse.js
2033
- var require_parse = __commonJS({
2034
- "../../node_modules/.bun/shell-quote@1.8.3/node_modules/shell-quote/parse.js"(exports, module) {
2035
- "use strict";
2036
- init_esm_shims();
2037
- var CONTROL = "(?:" + [
2038
- "\\|\\|",
2039
- "\\&\\&",
2040
- ";;",
2041
- "\\|\\&",
2042
- "\\<\\(",
2043
- "\\<\\<\\<",
2044
- ">>",
2045
- ">\\&",
2046
- "<\\&",
2047
- "[&;()|<>]"
2048
- ].join("|") + ")";
2049
- var controlRE = new RegExp("^" + CONTROL + "$");
2050
- var META = "|&;()<> \\t";
2051
- var SINGLE_QUOTE = '"((\\\\"|[^"])*?)"';
2052
- var DOUBLE_QUOTE = "'((\\\\'|[^'])*?)'";
2053
- var hash = /^#$/;
2054
- var SQ = "'";
2055
- var DQ = '"';
2056
- var DS = "$";
2057
- var TOKEN = "";
2058
- var mult = 4294967296;
2059
- for (i = 0; i < 4; i++) {
2060
- TOKEN += (mult * Math.random()).toString(16);
2061
- }
2062
- var i;
2063
- var startsWithToken = new RegExp("^" + TOKEN);
2064
- function matchAll(s, r) {
2065
- var origIndex = r.lastIndex;
2066
- var matches2 = [];
2067
- var matchObj;
2068
- while (matchObj = r.exec(s)) {
2069
- matches2.push(matchObj);
2070
- if (r.lastIndex === matchObj.index) {
2071
- r.lastIndex += 1;
2072
- }
2073
- }
2074
- r.lastIndex = origIndex;
2075
- return matches2;
2076
- }
2077
- function getVar(env, pre, key) {
2078
- var r = typeof env === "function" ? env(key) : env[key];
2079
- if (typeof r === "undefined" && key != "") {
2080
- r = "";
2081
- } else if (typeof r === "undefined") {
2082
- r = "$";
2083
- }
2084
- if (typeof r === "object") {
2085
- return pre + TOKEN + JSON.stringify(r) + TOKEN;
2086
- }
2087
- return pre + r;
2088
- }
2089
- function parseInternal(string, env, opts) {
2090
- if (!opts) {
2091
- opts = {};
2092
- }
2093
- var BS = opts.escape || "\\";
2094
- var BAREWORD = "(\\" + BS + `['"` + META + `]|[^\\s'"` + META + "])+";
2095
- var chunker = new RegExp([
2096
- "(" + CONTROL + ")",
2097
- // control chars
2098
- "(" + BAREWORD + "|" + SINGLE_QUOTE + "|" + DOUBLE_QUOTE + ")+"
2099
- ].join("|"), "g");
2100
- var matches2 = matchAll(string, chunker);
2101
- if (matches2.length === 0) {
2102
- return [];
2103
- }
2104
- if (!env) {
2105
- env = {};
2106
- }
2107
- var commented = false;
2108
- return matches2.map(function(match) {
2109
- var s = match[0];
2110
- if (!s || commented) {
2111
- return void 0;
2112
- }
2113
- if (controlRE.test(s)) {
2114
- return { op: s };
2115
- }
2116
- var quote = false;
2117
- var esc = false;
2118
- var out = "";
2119
- var isGlob = false;
2120
- var i2;
2121
- function parseEnvVar() {
2122
- i2 += 1;
2123
- var varend;
2124
- var varname;
2125
- var char = s.charAt(i2);
2126
- if (char === "{") {
2127
- i2 += 1;
2128
- if (s.charAt(i2) === "}") {
2129
- throw new Error("Bad substitution: " + s.slice(i2 - 2, i2 + 1));
2130
- }
2131
- varend = s.indexOf("}", i2);
2132
- if (varend < 0) {
2133
- throw new Error("Bad substitution: " + s.slice(i2));
2134
- }
2135
- varname = s.slice(i2, varend);
2136
- i2 = varend;
2137
- } else if (/[*@#?$!_-]/.test(char)) {
2138
- varname = char;
2139
- i2 += 1;
2140
- } else {
2141
- var slicedFromI = s.slice(i2);
2142
- varend = slicedFromI.match(/[^\w\d_]/);
2143
- if (!varend) {
2144
- varname = slicedFromI;
2145
- i2 = s.length;
2146
- } else {
2147
- varname = slicedFromI.slice(0, varend.index);
2148
- i2 += varend.index - 1;
2149
- }
2150
- }
2151
- return getVar(env, "", varname);
2152
- }
2153
- for (i2 = 0; i2 < s.length; i2++) {
2154
- var c = s.charAt(i2);
2155
- isGlob = isGlob || !quote && (c === "*" || c === "?");
2156
- if (esc) {
2157
- out += c;
2158
- esc = false;
2159
- } else if (quote) {
2160
- if (c === quote) {
2161
- quote = false;
2162
- } else if (quote == SQ) {
2163
- out += c;
2164
- } else {
2165
- if (c === BS) {
2166
- i2 += 1;
2167
- c = s.charAt(i2);
2168
- if (c === DQ || c === BS || c === DS) {
2169
- out += c;
2170
- } else {
2171
- out += BS + c;
2172
- }
2173
- } else if (c === DS) {
2174
- out += parseEnvVar();
2175
- } else {
2176
- out += c;
2177
- }
2178
- }
2179
- } else if (c === DQ || c === SQ) {
2180
- quote = c;
2181
- } else if (controlRE.test(c)) {
2182
- return { op: s };
2183
- } else if (hash.test(c)) {
2184
- commented = true;
2185
- var commentObj = { comment: string.slice(match.index + i2 + 1) };
2186
- if (out.length) {
2187
- return [out, commentObj];
2188
- }
2189
- return [commentObj];
2190
- } else if (c === BS) {
2191
- esc = true;
2192
- } else if (c === DS) {
2193
- out += parseEnvVar();
2194
- } else {
2195
- out += c;
2196
- }
2197
- }
2198
- if (isGlob) {
2199
- return { op: "glob", pattern: out };
2200
- }
2201
- return out;
2202
- }).reduce(function(prev, arg) {
2203
- return typeof arg === "undefined" ? prev : prev.concat(arg);
2204
- }, []);
2205
- }
2206
- module.exports = function parse(s, env, opts) {
2207
- var mapped = parseInternal(s, env, opts);
2208
- if (typeof env !== "function") {
2209
- return mapped;
2210
- }
2211
- return mapped.reduce(function(acc, s2) {
2212
- if (typeof s2 === "object") {
2213
- return acc.concat(s2);
2214
- }
2215
- var xs = s2.split(RegExp("(" + TOKEN + ".*?" + TOKEN + ")", "g"));
2216
- if (xs.length === 1) {
2217
- return acc.concat(xs[0]);
2218
- }
2219
- return acc.concat(xs.filter(Boolean).map(function(x) {
2220
- if (startsWithToken.test(x)) {
2221
- return JSON.parse(x.split(TOKEN)[1]);
2222
- }
2223
- return x;
2224
- }));
2225
- }, []);
2226
- };
2227
- }
2228
- });
2229
-
2230
- // ../../node_modules/.bun/shell-quote@1.8.3/node_modules/shell-quote/index.js
2231
- var require_shell_quote = __commonJS({
2232
- "../../node_modules/.bun/shell-quote@1.8.3/node_modules/shell-quote/index.js"(exports) {
2108
+ // ../core/src/shellQuote.ts
2109
+ import { createRequire as nodeCreateRequire } from "module";
2110
+ var requireShellQuote, impl, parse, quote;
2111
+ var init_shellQuote = __esm({
2112
+ "../core/src/shellQuote.ts"() {
2233
2113
  "use strict";
2234
2114
  init_esm_shims();
2235
- exports.quote = require_quote();
2236
- exports.parse = require_parse();
2115
+ requireShellQuote = nodeCreateRequire(import.meta.url);
2116
+ impl = requireShellQuote("shell-quote/index.js");
2117
+ parse = impl.parse;
2118
+ quote = impl.quote;
2237
2119
  }
2238
2120
  });
2239
2121
 
@@ -2241,13 +2123,13 @@ var require_shell_quote = __commonJS({
2241
2123
  import { spawn } from "child_process";
2242
2124
  import { resolve as resolve3, relative as relative3, isAbsolute as isAbsolute3 } from "path";
2243
2125
  import { realpath } from "fs/promises";
2244
- var import_shell_quote, RunCommandTool;
2126
+ var RunCommandTool;
2245
2127
  var init_RunCommandTool = __esm({
2246
2128
  "../core/src/tools/RunCommandTool.ts"() {
2247
2129
  "use strict";
2248
2130
  init_esm_shims();
2249
2131
  init_BaseTool();
2250
- import_shell_quote = __toESM(require_shell_quote(), 1);
2132
+ init_shellQuote();
2251
2133
  RunCommandTool = class _RunCommandTool extends BaseTool {
2252
2134
  name = "run_command";
2253
2135
  description = "Execute a shell command and return its output.";
@@ -2290,7 +2172,7 @@ var init_RunCommandTool = __esm({
2290
2172
  isError: true
2291
2173
  };
2292
2174
  }
2293
- const parsed = (0, import_shell_quote.parse)(args2.command);
2175
+ const parsed = parse(args2.command);
2294
2176
  const argv = parsed.filter((tok) => typeof tok === "string").map(String);
2295
2177
  if (argv.length === 0) {
2296
2178
  return {
@@ -2301,7 +2183,8 @@ var init_RunCommandTool = __esm({
2301
2183
  let cwd = projectRoot;
2302
2184
  if (args2.cwd && typeof args2.cwd === "string" && args2.cwd.trim()) {
2303
2185
  const rawCwd = args2.cwd.trim();
2304
- if (isAbsolute3(rawCwd)) {
2186
+ const isWindowsStyleAbsolute = /^[a-zA-Z]:[\\/]/.test(rawCwd) || rawCwd.startsWith("\\");
2187
+ if (isAbsolute3(rawCwd) || isWindowsStyleAbsolute) {
2305
2188
  return {
2306
2189
  content: `Error: invalid cwd "${args2.cwd}" \u2014 must be a relative path within the project root.`,
2307
2190
  isError: true
@@ -3340,7 +3223,7 @@ import { resolve as resolve6, normalize as normalize5, relative as relative6, is
3340
3223
  import { readFile as readFile5, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
3341
3224
  import { existsSync as existsSync6 } from "fs";
3342
3225
  import { homedir as homedir4 } from "os";
3343
- import { randomBytes as randomBytes3 } from "crypto";
3226
+ import { randomBytes as randomBytes4 } from "crypto";
3344
3227
  var PatchFileTool;
3345
3228
  var init_PatchFileTool = __esm({
3346
3229
  "../core/src/tools/PatchFileTool.ts"() {
@@ -3448,7 +3331,7 @@ File preview (first 200 chars): ${JSON.stringify(preview)}`,
3448
3331
  try {
3449
3332
  const filename = resolvedTarget.split(/[\\/]/).pop() ?? "file";
3450
3333
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
3451
- const suffix = randomBytes3(4).toString("hex");
3334
+ const suffix = randomBytes4(4).toString("hex");
3452
3335
  const backupPath = join8(homedir4(), ".msapling", "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
3453
3336
  await mkdir2(join8(homedir4(), ".msapling", "backups"), { recursive: true });
3454
3337
  await writeFile2(backupPath, originalContent, "utf8");
@@ -4028,7 +3911,7 @@ Command: ${command}`,
4028
3911
  proc = spawn5(shellArgv[0], shellArgv.slice(1), {
4029
3912
  cwd,
4030
3913
  stdio: ["pipe", "pipe", "pipe"],
4031
- shell: true
3914
+ shell: false
4032
3915
  });
4033
3916
  } catch (e) {
4034
3917
  return {
@@ -4309,7 +4192,7 @@ import { resolve as resolve9, normalize as normalize8, relative as relative9, is
4309
4192
  import { readFile as readFile7, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
4310
4193
  import { existsSync as existsSync8 } from "fs";
4311
4194
  import { homedir as homedir5 } from "os";
4312
- import { randomBytes as randomBytes4 } from "crypto";
4195
+ import { randomBytes as randomBytes5 } from "crypto";
4313
4196
  function normaliseSource(source) {
4314
4197
  if (source === "") return [];
4315
4198
  const lines = source.split("\n");
@@ -4487,7 +4370,7 @@ var init_NotebookEditTool = __esm({
4487
4370
  try {
4488
4371
  const filename = absPath.split(/[\\/]/).pop() ?? "notebook.ipynb";
4489
4372
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4490
- const suffix = randomBytes4(4).toString("hex");
4373
+ const suffix = randomBytes5(4).toString("hex");
4491
4374
  const backupPath = join10(
4492
4375
  homedir5(),
4493
4376
  ".msapling",
@@ -4568,7 +4451,7 @@ import { resolve as resolve10, normalize as normalize9, relative as relative10,
4568
4451
  import { readFile as readFile8, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
4569
4452
  import { existsSync as existsSync9 } from "fs";
4570
4453
  import { homedir as homedir6 } from "os";
4571
- import { randomBytes as randomBytes5 } from "crypto";
4454
+ import { randomBytes as randomBytes6 } from "crypto";
4572
4455
  var MAX_EDITS, MultiEditFileTool;
4573
4456
  var init_MultiEditFileTool = __esm({
4574
4457
  "../core/src/tools/MultiEditFileTool.ts"() {
@@ -4730,7 +4613,7 @@ No changes were written (atomic: all-or-nothing).`,
4730
4613
  try {
4731
4614
  const filename = resolvedTarget.split(/[\\/]/).pop() ?? "file";
4732
4615
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4733
- const suffix = randomBytes5(4).toString("hex");
4616
+ const suffix = randomBytes6(4).toString("hex");
4734
4617
  const backupPath = join11(
4735
4618
  homedir6(),
4736
4619
  ".msapling",
@@ -4768,7 +4651,7 @@ Pre-edit content backed up to: ${backedUpTo}`;
4768
4651
  import { resolve as resolve11, normalize as normalize10, relative as relative11, isAbsolute as isAbsolute11, dirname as dirname2 } from "path";
4769
4652
  import { rename, mkdir as mkdir5, copyFile, rm, stat as stat2, readdir as readdir2 } from "fs/promises";
4770
4653
  import { existsSync as existsSync10, statSync as statSync3 } from "fs";
4771
- import { randomBytes as randomBytes6 } from "crypto";
4654
+ import { randomBytes as randomBytes7 } from "crypto";
4772
4655
  function containedPath(p, root) {
4773
4656
  const abs = isAbsolute11(p) ? normalize10(p) : resolve11(root, p.trim());
4774
4657
  const rel = relative11(root, abs);
@@ -4797,7 +4680,7 @@ async function backupFile(absPath) {
4797
4680
  const { join: join39 } = await import("path");
4798
4681
  const filename = absPath.split(/[\\/]/).pop() ?? "file";
4799
4682
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
4800
- const suffix = randomBytes6(4).toString("hex");
4683
+ const suffix = randomBytes7(4).toString("hex");
4801
4684
  const backupPath = join39(
4802
4685
  homedir22(),
4803
4686
  ".msapling",
@@ -4958,7 +4841,7 @@ Overwritten destination backed up to: ${backedUpTo}`;
4958
4841
  // ../core/src/tools/DeleteFileTool.ts
4959
4842
  import { resolve as resolve12, normalize as normalize11, relative as relative12, isAbsolute as isAbsolute12, join as join13 } from "path";
4960
4843
  import { rm as rm2, stat as stat3 } from "fs/promises";
4961
- import { randomBytes as randomBytes7 } from "crypto";
4844
+ import { randomBytes as randomBytes8 } from "crypto";
4962
4845
  var DeleteFileTool;
4963
4846
  var init_DeleteFileTool = __esm({
4964
4847
  "../core/src/tools/DeleteFileTool.ts"() {
@@ -5036,7 +4919,7 @@ var init_DeleteFileTool = __esm({
5036
4919
  const existingContent = await readFile30(abs, "utf8");
5037
4920
  const filename = abs.split(/[\\/]/).pop() ?? "file";
5038
4921
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
5039
- const suffix = randomBytes7(4).toString("hex");
4922
+ const suffix = randomBytes8(4).toString("hex");
5040
4923
  const backupPath = join13(homedir22(), ".msapling", "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
5041
4924
  await mkdir10(join13(homedir22(), ".msapling", "backups"), { recursive: true });
5042
4925
  await writeFile19(backupPath, existingContent, "utf8");
@@ -5125,15 +5008,20 @@ import { resolve as resolve13, normalize as normalize12, relative as relative13,
5125
5008
  import { realpathSync } from "fs";
5126
5009
  import { realpath as realpath2 } from "fs/promises";
5127
5010
  import { createHash as createHash3 } from "crypto";
5128
- var import_shell_quote2, Sandbox;
5011
+ var Sandbox;
5129
5012
  var init_Sandbox = __esm({
5130
5013
  "../core/src/Sandbox.ts"() {
5131
5014
  "use strict";
5132
5015
  init_esm_shims();
5133
- import_shell_quote2 = __toESM(require_shell_quote(), 1);
5016
+ init_shellQuote();
5134
5017
  Sandbox = class _Sandbox {
5135
5018
  projectRoot;
5136
5019
  permissions = { trustedCommands: [], trustedPaths: [] };
5020
+ // CLI-TEST-MOCK-LEAK-01: injectable realpath resolver. Production uses the
5021
+ // real fs.realpathSync; tests pass a stub here instead of `mock.module('fs')`,
5022
+ // which under Bun pins the top-level `import { realpathSync }` binding for the
5023
+ // ENTIRE process and silently breaks Sandbox in every later test file.
5024
+ realpathSyncFn;
5137
5025
  static SAFE_BINARIES = /* @__PURE__ */ new Set([
5138
5026
  "git",
5139
5027
  "ls",
@@ -5174,8 +5062,9 @@ var init_Sandbox = __esm({
5174
5062
  "reg",
5175
5063
  "sc"
5176
5064
  ]);
5177
- constructor(projectRoot) {
5065
+ constructor(projectRoot, opts) {
5178
5066
  this.projectRoot = resolve13(projectRoot);
5067
+ this.realpathSyncFn = opts?.realpathSync ?? realpathSync;
5179
5068
  }
5180
5069
  setPermissions(state) {
5181
5070
  this.permissions = state;
@@ -5192,7 +5081,7 @@ var init_Sandbox = __esm({
5192
5081
  const normalizedTarget = isAbsolute13(targetPath) ? normalize12(targetPath) : resolve13(this.projectRoot, targetPath);
5193
5082
  let resolvedTarget = normalizedTarget;
5194
5083
  try {
5195
- resolvedTarget = realpathSync(normalizedTarget);
5084
+ resolvedTarget = this.realpathSyncFn(normalizedTarget);
5196
5085
  } catch {
5197
5086
  resolvedTarget = normalizedTarget;
5198
5087
  }
@@ -5253,7 +5142,7 @@ var init_Sandbox = __esm({
5253
5142
  if (this.permissions.trustedCommands.includes(hash)) {
5254
5143
  return { status: "trusted", hash };
5255
5144
  }
5256
- const parsed = (0, import_shell_quote2.parse)(commandLine);
5145
+ const parsed = parse(commandLine);
5257
5146
  const tokens = parsed.filter((t) => typeof t === "string");
5258
5147
  const normalize13 = (raw) => {
5259
5148
  let b = raw.toLowerCase();
@@ -5349,10 +5238,10 @@ var init_Sandbox = __esm({
5349
5238
  * to a minimal platform default so subprocess spawn never sees an empty PATH.
5350
5239
  */
5351
5240
  static curatePath(rawPath) {
5352
- const sep3 = process.platform === "win32" ? ";" : ":";
5353
- const entries = (rawPath ?? "").split(sep3);
5241
+ const sep4 = process.platform === "win32" ? ";" : ":";
5242
+ const entries = (rawPath ?? "").split(sep4);
5354
5243
  const kept = entries.filter((e) => _Sandbox.isSafePathEntry(e));
5355
- if (kept.length > 0) return kept.join(sep3);
5244
+ if (kept.length > 0) return kept.join(sep4);
5356
5245
  return process.platform === "win32" ? "C:\\Windows\\System32;C:\\Windows" : "/usr/local/bin:/usr/bin:/bin";
5357
5246
  }
5358
5247
  getRestrictedEnv(pathOverride) {
@@ -5371,6 +5260,19 @@ var init_Sandbox = __esm({
5371
5260
 
5372
5261
  // ../core/src/Voice.ts
5373
5262
  import { spawn as spawn6 } from "child_process";
5263
+ function buildTtsInvocation(text, rate) {
5264
+ const psCommand = `
5265
+ Add-Type -AssemblyName System.Speech;
5266
+ $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer;
5267
+ $synth.Rate = ${Math.trunc(rate)};
5268
+ $synth.Speak($env:MSAPLING_TTS_TEXT);
5269
+ `;
5270
+ return {
5271
+ command: "powershell",
5272
+ args: ["-NoProfile", "-Command", psCommand],
5273
+ env: { ...process.env, MSAPLING_TTS_TEXT: text }
5274
+ };
5275
+ }
5374
5276
  var VoiceService;
5375
5277
  var init_Voice = __esm({
5376
5278
  "../core/src/Voice.ts"() {
@@ -5387,27 +5289,19 @@ var init_Voice = __esm({
5387
5289
  */
5388
5290
  async speak(text, identity = "natural") {
5389
5291
  if (!this.enabled) return;
5390
- let pitch = 0;
5391
5292
  let rate = 0;
5392
5293
  if (identity === "robotic") {
5393
- pitch = -5;
5394
5294
  rate = 2;
5395
5295
  }
5396
5296
  if (identity === "urgent") {
5397
- pitch = 5;
5398
5297
  rate = 5;
5399
5298
  }
5400
- const psCommand = `
5401
- Add-Type -AssemblyName System.Speech;
5402
- $synth = New-Object System.Speech.Synthesis.SpeechSynthesizer;
5403
- $synth.Rate = ${rate};
5404
- $synth.Speak("${text}");
5405
- `;
5299
+ const { command, args: args2, env } = buildTtsInvocation(text, rate);
5406
5300
  try {
5407
5301
  if (process.platform === "win32") {
5408
5302
  await new Promise((resolve20, reject) => {
5409
5303
  try {
5410
- const proc = spawn6("powershell", ["-Command", psCommand]);
5304
+ const proc = spawn6(command, args2, { env });
5411
5305
  proc.on("exit", () => resolve20());
5412
5306
  proc.on("error", reject);
5413
5307
  } catch (e) {
@@ -6103,15 +5997,15 @@ ${blocker.stderr || "(empty)"}`,
6103
5997
  }
6104
5998
  }
6105
5999
  if (args2.path) {
6106
- const check = await this.sandbox.isPathSafeAsync(args2.path);
6107
- if (!check.safe) {
6000
+ const check2 = await this.sandbox.isPathSafeAsync(args2.path);
6001
+ if (!check2.safe) {
6108
6002
  await this.voice.speak(`Security block detected`, "urgent");
6109
6003
  const staleKey = `${toolName}:${(args2.path || "").trim()}`;
6110
6004
  if (this.trustStore?.has(staleKey)) {
6111
6005
  this.trustStore.delete(staleKey).catch(() => {
6112
6006
  });
6113
6007
  }
6114
- return { content: `Security Block: ${check.reason}`, isError: true };
6008
+ return { content: `Security Block: ${check2.reason}`, isError: true };
6115
6009
  }
6116
6010
  }
6117
6011
  if (toolName === "run_command" || toolName === "bash_command") {
@@ -6890,1623 +6784,40 @@ var init_Mutex = __esm({
6890
6784
  acquire() {
6891
6785
  let release3;
6892
6786
  const next = new Promise((resolve20) => {
6893
- release3 = resolve20;
6894
- });
6895
- const entry = this._queue.then(() => release3);
6896
- this._queue = this._queue.then(() => next);
6897
- return entry;
6898
- }
6899
- /**
6900
- * Convenience wrapper: acquire the lock, run `fn`, then automatically
6901
- * release. Returns whatever `fn` returns.
6902
- */
6903
- async run(fn) {
6904
- const release3 = await this.acquire();
6905
- try {
6906
- return await fn();
6907
- } finally {
6908
- release3();
6909
- }
6910
- }
6911
- };
6912
- }
6913
- });
6914
-
6915
- // ../../node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/polyfills.js
6916
- var require_polyfills = __commonJS({
6917
- "../../node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/polyfills.js"(exports, module) {
6918
- "use strict";
6919
- init_esm_shims();
6920
- var constants = __require("constants");
6921
- var origCwd = process.cwd;
6922
- var cwd = null;
6923
- var platform5 = process.env.GRACEFUL_FS_PLATFORM || process.platform;
6924
- process.cwd = function() {
6925
- if (!cwd)
6926
- cwd = origCwd.call(process);
6927
- return cwd;
6928
- };
6929
- try {
6930
- process.cwd();
6931
- } catch (er) {
6932
- }
6933
- if (typeof process.chdir === "function") {
6934
- chdir = process.chdir;
6935
- process.chdir = function(d) {
6936
- cwd = null;
6937
- chdir.call(process, d);
6938
- };
6939
- if (Object.setPrototypeOf) Object.setPrototypeOf(process.chdir, chdir);
6940
- }
6941
- var chdir;
6942
- module.exports = patch;
6943
- function patch(fs3) {
6944
- if (constants.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
6945
- patchLchmod(fs3);
6946
- }
6947
- if (!fs3.lutimes) {
6948
- patchLutimes(fs3);
6949
- }
6950
- fs3.chown = chownFix(fs3.chown);
6951
- fs3.fchown = chownFix(fs3.fchown);
6952
- fs3.lchown = chownFix(fs3.lchown);
6953
- fs3.chmod = chmodFix(fs3.chmod);
6954
- fs3.fchmod = chmodFix(fs3.fchmod);
6955
- fs3.lchmod = chmodFix(fs3.lchmod);
6956
- fs3.chownSync = chownFixSync(fs3.chownSync);
6957
- fs3.fchownSync = chownFixSync(fs3.fchownSync);
6958
- fs3.lchownSync = chownFixSync(fs3.lchownSync);
6959
- fs3.chmodSync = chmodFixSync(fs3.chmodSync);
6960
- fs3.fchmodSync = chmodFixSync(fs3.fchmodSync);
6961
- fs3.lchmodSync = chmodFixSync(fs3.lchmodSync);
6962
- fs3.stat = statFix(fs3.stat);
6963
- fs3.fstat = statFix(fs3.fstat);
6964
- fs3.lstat = statFix(fs3.lstat);
6965
- fs3.statSync = statFixSync(fs3.statSync);
6966
- fs3.fstatSync = statFixSync(fs3.fstatSync);
6967
- fs3.lstatSync = statFixSync(fs3.lstatSync);
6968
- if (fs3.chmod && !fs3.lchmod) {
6969
- fs3.lchmod = function(path2, mode, cb) {
6970
- if (cb) process.nextTick(cb);
6971
- };
6972
- fs3.lchmodSync = function() {
6973
- };
6974
- }
6975
- if (fs3.chown && !fs3.lchown) {
6976
- fs3.lchown = function(path2, uid, gid, cb) {
6977
- if (cb) process.nextTick(cb);
6978
- };
6979
- fs3.lchownSync = function() {
6980
- };
6981
- }
6982
- if (platform5 === "win32") {
6983
- fs3.rename = typeof fs3.rename !== "function" ? fs3.rename : (function(fs$rename) {
6984
- function rename4(from, to, cb) {
6985
- var start = Date.now();
6986
- var backoff = 0;
6987
- fs$rename(from, to, function CB(er) {
6988
- if (er && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY") && Date.now() - start < 6e4) {
6989
- setTimeout(function() {
6990
- fs3.stat(to, function(stater, st) {
6991
- if (stater && stater.code === "ENOENT")
6992
- fs$rename(from, to, CB);
6993
- else
6994
- cb(er);
6995
- });
6996
- }, backoff);
6997
- if (backoff < 100)
6998
- backoff += 10;
6999
- return;
7000
- }
7001
- if (cb) cb(er);
7002
- });
7003
- }
7004
- if (Object.setPrototypeOf) Object.setPrototypeOf(rename4, fs$rename);
7005
- return rename4;
7006
- })(fs3.rename);
7007
- }
7008
- fs3.read = typeof fs3.read !== "function" ? fs3.read : (function(fs$read) {
7009
- function read(fd, buffer, offset, length, position, callback_) {
7010
- var callback;
7011
- if (callback_ && typeof callback_ === "function") {
7012
- var eagCounter = 0;
7013
- callback = function(er, _, __) {
7014
- if (er && er.code === "EAGAIN" && eagCounter < 10) {
7015
- eagCounter++;
7016
- return fs$read.call(fs3, fd, buffer, offset, length, position, callback);
7017
- }
7018
- callback_.apply(this, arguments);
7019
- };
7020
- }
7021
- return fs$read.call(fs3, fd, buffer, offset, length, position, callback);
7022
- }
7023
- if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read);
7024
- return read;
7025
- })(fs3.read);
7026
- fs3.readSync = typeof fs3.readSync !== "function" ? fs3.readSync : /* @__PURE__ */ (function(fs$readSync) {
7027
- return function(fd, buffer, offset, length, position) {
7028
- var eagCounter = 0;
7029
- while (true) {
7030
- try {
7031
- return fs$readSync.call(fs3, fd, buffer, offset, length, position);
7032
- } catch (er) {
7033
- if (er.code === "EAGAIN" && eagCounter < 10) {
7034
- eagCounter++;
7035
- continue;
7036
- }
7037
- throw er;
7038
- }
7039
- }
7040
- };
7041
- })(fs3.readSync);
7042
- function patchLchmod(fs4) {
7043
- fs4.lchmod = function(path2, mode, callback) {
7044
- fs4.open(
7045
- path2,
7046
- constants.O_WRONLY | constants.O_SYMLINK,
7047
- mode,
7048
- function(err, fd) {
7049
- if (err) {
7050
- if (callback) callback(err);
7051
- return;
7052
- }
7053
- fs4.fchmod(fd, mode, function(err2) {
7054
- fs4.close(fd, function(err22) {
7055
- if (callback) callback(err2 || err22);
7056
- });
7057
- });
7058
- }
7059
- );
7060
- };
7061
- fs4.lchmodSync = function(path2, mode) {
7062
- var fd = fs4.openSync(path2, constants.O_WRONLY | constants.O_SYMLINK, mode);
7063
- var threw = true;
7064
- var ret;
7065
- try {
7066
- ret = fs4.fchmodSync(fd, mode);
7067
- threw = false;
7068
- } finally {
7069
- if (threw) {
7070
- try {
7071
- fs4.closeSync(fd);
7072
- } catch (er) {
7073
- }
7074
- } else {
7075
- fs4.closeSync(fd);
7076
- }
7077
- }
7078
- return ret;
7079
- };
7080
- }
7081
- function patchLutimes(fs4) {
7082
- if (constants.hasOwnProperty("O_SYMLINK") && fs4.futimes) {
7083
- fs4.lutimes = function(path2, at, mt, cb) {
7084
- fs4.open(path2, constants.O_SYMLINK, function(er, fd) {
7085
- if (er) {
7086
- if (cb) cb(er);
7087
- return;
7088
- }
7089
- fs4.futimes(fd, at, mt, function(er2) {
7090
- fs4.close(fd, function(er22) {
7091
- if (cb) cb(er2 || er22);
7092
- });
7093
- });
7094
- });
7095
- };
7096
- fs4.lutimesSync = function(path2, at, mt) {
7097
- var fd = fs4.openSync(path2, constants.O_SYMLINK);
7098
- var ret;
7099
- var threw = true;
7100
- try {
7101
- ret = fs4.futimesSync(fd, at, mt);
7102
- threw = false;
7103
- } finally {
7104
- if (threw) {
7105
- try {
7106
- fs4.closeSync(fd);
7107
- } catch (er) {
7108
- }
7109
- } else {
7110
- fs4.closeSync(fd);
7111
- }
7112
- }
7113
- return ret;
7114
- };
7115
- } else if (fs4.futimes) {
7116
- fs4.lutimes = function(_a, _b, _c, cb) {
7117
- if (cb) process.nextTick(cb);
7118
- };
7119
- fs4.lutimesSync = function() {
7120
- };
7121
- }
7122
- }
7123
- function chmodFix(orig) {
7124
- if (!orig) return orig;
7125
- return function(target, mode, cb) {
7126
- return orig.call(fs3, target, mode, function(er) {
7127
- if (chownErOk(er)) er = null;
7128
- if (cb) cb.apply(this, arguments);
7129
- });
7130
- };
7131
- }
7132
- function chmodFixSync(orig) {
7133
- if (!orig) return orig;
7134
- return function(target, mode) {
7135
- try {
7136
- return orig.call(fs3, target, mode);
7137
- } catch (er) {
7138
- if (!chownErOk(er)) throw er;
7139
- }
7140
- };
7141
- }
7142
- function chownFix(orig) {
7143
- if (!orig) return orig;
7144
- return function(target, uid, gid, cb) {
7145
- return orig.call(fs3, target, uid, gid, function(er) {
7146
- if (chownErOk(er)) er = null;
7147
- if (cb) cb.apply(this, arguments);
7148
- });
7149
- };
7150
- }
7151
- function chownFixSync(orig) {
7152
- if (!orig) return orig;
7153
- return function(target, uid, gid) {
7154
- try {
7155
- return orig.call(fs3, target, uid, gid);
7156
- } catch (er) {
7157
- if (!chownErOk(er)) throw er;
7158
- }
7159
- };
7160
- }
7161
- function statFix(orig) {
7162
- if (!orig) return orig;
7163
- return function(target, options, cb) {
7164
- if (typeof options === "function") {
7165
- cb = options;
7166
- options = null;
7167
- }
7168
- function callback(er, stats) {
7169
- if (stats) {
7170
- if (stats.uid < 0) stats.uid += 4294967296;
7171
- if (stats.gid < 0) stats.gid += 4294967296;
7172
- }
7173
- if (cb) cb.apply(this, arguments);
7174
- }
7175
- return options ? orig.call(fs3, target, options, callback) : orig.call(fs3, target, callback);
7176
- };
7177
- }
7178
- function statFixSync(orig) {
7179
- if (!orig) return orig;
7180
- return function(target, options) {
7181
- var stats = options ? orig.call(fs3, target, options) : orig.call(fs3, target);
7182
- if (stats) {
7183
- if (stats.uid < 0) stats.uid += 4294967296;
7184
- if (stats.gid < 0) stats.gid += 4294967296;
7185
- }
7186
- return stats;
7187
- };
7188
- }
7189
- function chownErOk(er) {
7190
- if (!er)
7191
- return true;
7192
- if (er.code === "ENOSYS")
7193
- return true;
7194
- var nonroot = !process.getuid || process.getuid() !== 0;
7195
- if (nonroot) {
7196
- if (er.code === "EINVAL" || er.code === "EPERM")
7197
- return true;
7198
- }
7199
- return false;
7200
- }
7201
- }
7202
- }
7203
- });
7204
-
7205
- // ../../node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/legacy-streams.js
7206
- var require_legacy_streams = __commonJS({
7207
- "../../node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/legacy-streams.js"(exports, module) {
7208
- "use strict";
7209
- init_esm_shims();
7210
- var Stream = __require("stream").Stream;
7211
- module.exports = legacy;
7212
- function legacy(fs3) {
7213
- return {
7214
- ReadStream,
7215
- WriteStream
7216
- };
7217
- function ReadStream(path2, options) {
7218
- if (!(this instanceof ReadStream)) return new ReadStream(path2, options);
7219
- Stream.call(this);
7220
- var self = this;
7221
- this.path = path2;
7222
- this.fd = null;
7223
- this.readable = true;
7224
- this.paused = false;
7225
- this.flags = "r";
7226
- this.mode = 438;
7227
- this.bufferSize = 64 * 1024;
7228
- options = options || {};
7229
- var keys = Object.keys(options);
7230
- for (var index = 0, length = keys.length; index < length; index++) {
7231
- var key = keys[index];
7232
- this[key] = options[key];
7233
- }
7234
- if (this.encoding) this.setEncoding(this.encoding);
7235
- if (this.start !== void 0) {
7236
- if ("number" !== typeof this.start) {
7237
- throw TypeError("start must be a Number");
7238
- }
7239
- if (this.end === void 0) {
7240
- this.end = Infinity;
7241
- } else if ("number" !== typeof this.end) {
7242
- throw TypeError("end must be a Number");
7243
- }
7244
- if (this.start > this.end) {
7245
- throw new Error("start must be <= end");
7246
- }
7247
- this.pos = this.start;
7248
- }
7249
- if (this.fd !== null) {
7250
- process.nextTick(function() {
7251
- self._read();
7252
- });
7253
- return;
7254
- }
7255
- fs3.open(this.path, this.flags, this.mode, function(err, fd) {
7256
- if (err) {
7257
- self.emit("error", err);
7258
- self.readable = false;
7259
- return;
7260
- }
7261
- self.fd = fd;
7262
- self.emit("open", fd);
7263
- self._read();
7264
- });
7265
- }
7266
- function WriteStream(path2, options) {
7267
- if (!(this instanceof WriteStream)) return new WriteStream(path2, options);
7268
- Stream.call(this);
7269
- this.path = path2;
7270
- this.fd = null;
7271
- this.writable = true;
7272
- this.flags = "w";
7273
- this.encoding = "binary";
7274
- this.mode = 438;
7275
- this.bytesWritten = 0;
7276
- options = options || {};
7277
- var keys = Object.keys(options);
7278
- for (var index = 0, length = keys.length; index < length; index++) {
7279
- var key = keys[index];
7280
- this[key] = options[key];
7281
- }
7282
- if (this.start !== void 0) {
7283
- if ("number" !== typeof this.start) {
7284
- throw TypeError("start must be a Number");
7285
- }
7286
- if (this.start < 0) {
7287
- throw new Error("start must be >= zero");
7288
- }
7289
- this.pos = this.start;
7290
- }
7291
- this.busy = false;
7292
- this._queue = [];
7293
- if (this.fd === null) {
7294
- this._open = fs3.open;
7295
- this._queue.push([this._open, this.path, this.flags, this.mode, void 0]);
7296
- this.flush();
7297
- }
7298
- }
7299
- }
7300
- }
7301
- });
7302
-
7303
- // ../../node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/clone.js
7304
- var require_clone = __commonJS({
7305
- "../../node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/clone.js"(exports, module) {
7306
- "use strict";
7307
- init_esm_shims();
7308
- module.exports = clone;
7309
- var getPrototypeOf = Object.getPrototypeOf || function(obj) {
7310
- return obj.__proto__;
7311
- };
7312
- function clone(obj) {
7313
- if (obj === null || typeof obj !== "object")
7314
- return obj;
7315
- if (obj instanceof Object)
7316
- var copy = { __proto__: getPrototypeOf(obj) };
7317
- else
7318
- var copy = /* @__PURE__ */ Object.create(null);
7319
- Object.getOwnPropertyNames(obj).forEach(function(key) {
7320
- Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key));
7321
- });
7322
- return copy;
7323
- }
7324
- }
7325
- });
7326
-
7327
- // ../../node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/graceful-fs.js
7328
- var require_graceful_fs = __commonJS({
7329
- "../../node_modules/.bun/graceful-fs@4.2.11/node_modules/graceful-fs/graceful-fs.js"(exports, module) {
7330
- "use strict";
7331
- init_esm_shims();
7332
- var fs3 = __require("fs");
7333
- var polyfills = require_polyfills();
7334
- var legacy = require_legacy_streams();
7335
- var clone = require_clone();
7336
- var util = __require("util");
7337
- var gracefulQueue;
7338
- var previousSymbol;
7339
- if (typeof Symbol === "function" && typeof Symbol.for === "function") {
7340
- gracefulQueue = /* @__PURE__ */ Symbol.for("graceful-fs.queue");
7341
- previousSymbol = /* @__PURE__ */ Symbol.for("graceful-fs.previous");
7342
- } else {
7343
- gracefulQueue = "___graceful-fs.queue";
7344
- previousSymbol = "___graceful-fs.previous";
7345
- }
7346
- function noop() {
7347
- }
7348
- function publishQueue(context, queue2) {
7349
- Object.defineProperty(context, gracefulQueue, {
7350
- get: function() {
7351
- return queue2;
7352
- }
7353
- });
7354
- }
7355
- var debug = noop;
7356
- if (util.debuglog)
7357
- debug = util.debuglog("gfs4");
7358
- else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || ""))
7359
- debug = function() {
7360
- var m = util.format.apply(util, arguments);
7361
- m = "GFS4: " + m.split(/\n/).join("\nGFS4: ");
7362
- console.error(m);
7363
- };
7364
- if (!fs3[gracefulQueue]) {
7365
- queue = global[gracefulQueue] || [];
7366
- publishQueue(fs3, queue);
7367
- fs3.close = (function(fs$close) {
7368
- function close(fd, cb) {
7369
- return fs$close.call(fs3, fd, function(err) {
7370
- if (!err) {
7371
- resetQueue();
7372
- }
7373
- if (typeof cb === "function")
7374
- cb.apply(this, arguments);
7375
- });
7376
- }
7377
- Object.defineProperty(close, previousSymbol, {
7378
- value: fs$close
7379
- });
7380
- return close;
7381
- })(fs3.close);
7382
- fs3.closeSync = (function(fs$closeSync) {
7383
- function closeSync(fd) {
7384
- fs$closeSync.apply(fs3, arguments);
7385
- resetQueue();
7386
- }
7387
- Object.defineProperty(closeSync, previousSymbol, {
7388
- value: fs$closeSync
7389
- });
7390
- return closeSync;
7391
- })(fs3.closeSync);
7392
- if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
7393
- process.on("exit", function() {
7394
- debug(fs3[gracefulQueue]);
7395
- __require("assert").equal(fs3[gracefulQueue].length, 0);
7396
- });
7397
- }
7398
- }
7399
- var queue;
7400
- if (!global[gracefulQueue]) {
7401
- publishQueue(global, fs3[gracefulQueue]);
7402
- }
7403
- module.exports = patch(clone(fs3));
7404
- if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs3.__patched) {
7405
- module.exports = patch(fs3);
7406
- fs3.__patched = true;
7407
- }
7408
- function patch(fs4) {
7409
- polyfills(fs4);
7410
- fs4.gracefulify = patch;
7411
- fs4.createReadStream = createReadStream;
7412
- fs4.createWriteStream = createWriteStream;
7413
- var fs$readFile = fs4.readFile;
7414
- fs4.readFile = readFile30;
7415
- function readFile30(path2, options, cb) {
7416
- if (typeof options === "function")
7417
- cb = options, options = null;
7418
- return go$readFile(path2, options, cb);
7419
- function go$readFile(path3, options2, cb2, startTime) {
7420
- return fs$readFile(path3, options2, function(err) {
7421
- if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
7422
- enqueue([go$readFile, [path3, options2, cb2], err, startTime || Date.now(), Date.now()]);
7423
- else {
7424
- if (typeof cb2 === "function")
7425
- cb2.apply(this, arguments);
7426
- }
7427
- });
7428
- }
7429
- }
7430
- var fs$writeFile = fs4.writeFile;
7431
- fs4.writeFile = writeFile19;
7432
- function writeFile19(path2, data, options, cb) {
7433
- if (typeof options === "function")
7434
- cb = options, options = null;
7435
- return go$writeFile(path2, data, options, cb);
7436
- function go$writeFile(path3, data2, options2, cb2, startTime) {
7437
- return fs$writeFile(path3, data2, options2, function(err) {
7438
- if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
7439
- enqueue([go$writeFile, [path3, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
7440
- else {
7441
- if (typeof cb2 === "function")
7442
- cb2.apply(this, arguments);
7443
- }
7444
- });
7445
- }
7446
- }
7447
- var fs$appendFile = fs4.appendFile;
7448
- if (fs$appendFile)
7449
- fs4.appendFile = appendFile2;
7450
- function appendFile2(path2, data, options, cb) {
7451
- if (typeof options === "function")
7452
- cb = options, options = null;
7453
- return go$appendFile(path2, data, options, cb);
7454
- function go$appendFile(path3, data2, options2, cb2, startTime) {
7455
- return fs$appendFile(path3, data2, options2, function(err) {
7456
- if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
7457
- enqueue([go$appendFile, [path3, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
7458
- else {
7459
- if (typeof cb2 === "function")
7460
- cb2.apply(this, arguments);
7461
- }
7462
- });
7463
- }
7464
- }
7465
- var fs$copyFile = fs4.copyFile;
7466
- if (fs$copyFile)
7467
- fs4.copyFile = copyFile2;
7468
- function copyFile2(src, dest, flags, cb) {
7469
- if (typeof flags === "function") {
7470
- cb = flags;
7471
- flags = 0;
7472
- }
7473
- return go$copyFile(src, dest, flags, cb);
7474
- function go$copyFile(src2, dest2, flags2, cb2, startTime) {
7475
- return fs$copyFile(src2, dest2, flags2, function(err) {
7476
- if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
7477
- enqueue([go$copyFile, [src2, dest2, flags2, cb2], err, startTime || Date.now(), Date.now()]);
7478
- else {
7479
- if (typeof cb2 === "function")
7480
- cb2.apply(this, arguments);
7481
- }
7482
- });
7483
- }
7484
- }
7485
- var fs$readdir = fs4.readdir;
7486
- fs4.readdir = readdir5;
7487
- var noReaddirOptionVersions = /^v[0-5]\./;
7488
- function readdir5(path2, options, cb) {
7489
- if (typeof options === "function")
7490
- cb = options, options = null;
7491
- var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path3, options2, cb2, startTime) {
7492
- return fs$readdir(path3, fs$readdirCallback(
7493
- path3,
7494
- options2,
7495
- cb2,
7496
- startTime
7497
- ));
7498
- } : function go$readdir2(path3, options2, cb2, startTime) {
7499
- return fs$readdir(path3, options2, fs$readdirCallback(
7500
- path3,
7501
- options2,
7502
- cb2,
7503
- startTime
7504
- ));
7505
- };
7506
- return go$readdir(path2, options, cb);
7507
- function fs$readdirCallback(path3, options2, cb2, startTime) {
7508
- return function(err, files) {
7509
- if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
7510
- enqueue([
7511
- go$readdir,
7512
- [path3, options2, cb2],
7513
- err,
7514
- startTime || Date.now(),
7515
- Date.now()
7516
- ]);
7517
- else {
7518
- if (files && files.sort)
7519
- files.sort();
7520
- if (typeof cb2 === "function")
7521
- cb2.call(this, err, files);
7522
- }
7523
- };
7524
- }
7525
- }
7526
- if (process.version.substr(0, 4) === "v0.8") {
7527
- var legStreams = legacy(fs4);
7528
- ReadStream = legStreams.ReadStream;
7529
- WriteStream = legStreams.WriteStream;
7530
- }
7531
- var fs$ReadStream = fs4.ReadStream;
7532
- if (fs$ReadStream) {
7533
- ReadStream.prototype = Object.create(fs$ReadStream.prototype);
7534
- ReadStream.prototype.open = ReadStream$open;
7535
- }
7536
- var fs$WriteStream = fs4.WriteStream;
7537
- if (fs$WriteStream) {
7538
- WriteStream.prototype = Object.create(fs$WriteStream.prototype);
7539
- WriteStream.prototype.open = WriteStream$open;
7540
- }
7541
- Object.defineProperty(fs4, "ReadStream", {
7542
- get: function() {
7543
- return ReadStream;
7544
- },
7545
- set: function(val) {
7546
- ReadStream = val;
7547
- },
7548
- enumerable: true,
7549
- configurable: true
7550
- });
7551
- Object.defineProperty(fs4, "WriteStream", {
7552
- get: function() {
7553
- return WriteStream;
7554
- },
7555
- set: function(val) {
7556
- WriteStream = val;
7557
- },
7558
- enumerable: true,
7559
- configurable: true
7560
- });
7561
- var FileReadStream = ReadStream;
7562
- Object.defineProperty(fs4, "FileReadStream", {
7563
- get: function() {
7564
- return FileReadStream;
7565
- },
7566
- set: function(val) {
7567
- FileReadStream = val;
7568
- },
7569
- enumerable: true,
7570
- configurable: true
7571
- });
7572
- var FileWriteStream = WriteStream;
7573
- Object.defineProperty(fs4, "FileWriteStream", {
7574
- get: function() {
7575
- return FileWriteStream;
7576
- },
7577
- set: function(val) {
7578
- FileWriteStream = val;
7579
- },
7580
- enumerable: true,
7581
- configurable: true
7582
- });
7583
- function ReadStream(path2, options) {
7584
- if (this instanceof ReadStream)
7585
- return fs$ReadStream.apply(this, arguments), this;
7586
- else
7587
- return ReadStream.apply(Object.create(ReadStream.prototype), arguments);
7588
- }
7589
- function ReadStream$open() {
7590
- var that = this;
7591
- open(that.path, that.flags, that.mode, function(err, fd) {
7592
- if (err) {
7593
- if (that.autoClose)
7594
- that.destroy();
7595
- that.emit("error", err);
7596
- } else {
7597
- that.fd = fd;
7598
- that.emit("open", fd);
7599
- that.read();
7600
- }
7601
- });
7602
- }
7603
- function WriteStream(path2, options) {
7604
- if (this instanceof WriteStream)
7605
- return fs$WriteStream.apply(this, arguments), this;
7606
- else
7607
- return WriteStream.apply(Object.create(WriteStream.prototype), arguments);
7608
- }
7609
- function WriteStream$open() {
7610
- var that = this;
7611
- open(that.path, that.flags, that.mode, function(err, fd) {
7612
- if (err) {
7613
- that.destroy();
7614
- that.emit("error", err);
7615
- } else {
7616
- that.fd = fd;
7617
- that.emit("open", fd);
7618
- }
7619
- });
7620
- }
7621
- function createReadStream(path2, options) {
7622
- return new fs4.ReadStream(path2, options);
7623
- }
7624
- function createWriteStream(path2, options) {
7625
- return new fs4.WriteStream(path2, options);
7626
- }
7627
- var fs$open = fs4.open;
7628
- fs4.open = open;
7629
- function open(path2, flags, mode, cb) {
7630
- if (typeof mode === "function")
7631
- cb = mode, mode = null;
7632
- return go$open(path2, flags, mode, cb);
7633
- function go$open(path3, flags2, mode2, cb2, startTime) {
7634
- return fs$open(path3, flags2, mode2, function(err, fd) {
7635
- if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
7636
- enqueue([go$open, [path3, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
7637
- else {
7638
- if (typeof cb2 === "function")
7639
- cb2.apply(this, arguments);
7640
- }
7641
- });
7642
- }
7643
- }
7644
- return fs4;
7645
- }
7646
- function enqueue(elem) {
7647
- debug("ENQUEUE", elem[0].name, elem[1]);
7648
- fs3[gracefulQueue].push(elem);
7649
- retry();
7650
- }
7651
- var retryTimer;
7652
- function resetQueue() {
7653
- var now = Date.now();
7654
- for (var i = 0; i < fs3[gracefulQueue].length; ++i) {
7655
- if (fs3[gracefulQueue][i].length > 2) {
7656
- fs3[gracefulQueue][i][3] = now;
7657
- fs3[gracefulQueue][i][4] = now;
7658
- }
7659
- }
7660
- retry();
7661
- }
7662
- function retry() {
7663
- clearTimeout(retryTimer);
7664
- retryTimer = void 0;
7665
- if (fs3[gracefulQueue].length === 0)
7666
- return;
7667
- var elem = fs3[gracefulQueue].shift();
7668
- var fn = elem[0];
7669
- var args2 = elem[1];
7670
- var err = elem[2];
7671
- var startTime = elem[3];
7672
- var lastTime = elem[4];
7673
- if (startTime === void 0) {
7674
- debug("RETRY", fn.name, args2);
7675
- fn.apply(null, args2);
7676
- } else if (Date.now() - startTime >= 6e4) {
7677
- debug("TIMEOUT", fn.name, args2);
7678
- var cb = args2.pop();
7679
- if (typeof cb === "function")
7680
- cb.call(null, err);
7681
- } else {
7682
- var sinceAttempt = Date.now() - lastTime;
7683
- var sinceStart = Math.max(lastTime - startTime, 1);
7684
- var desiredDelay = Math.min(sinceStart * 1.2, 100);
7685
- if (sinceAttempt >= desiredDelay) {
7686
- debug("RETRY", fn.name, args2);
7687
- fn.apply(null, args2.concat([startTime]));
7688
- } else {
7689
- fs3[gracefulQueue].push(elem);
7690
- }
7691
- }
7692
- if (retryTimer === void 0) {
7693
- retryTimer = setTimeout(retry, 0);
7694
- }
7695
- }
7696
- }
7697
- });
7698
-
7699
- // ../../node_modules/.bun/retry@0.12.0/node_modules/retry/lib/retry_operation.js
7700
- var require_retry_operation = __commonJS({
7701
- "../../node_modules/.bun/retry@0.12.0/node_modules/retry/lib/retry_operation.js"(exports, module) {
7702
- "use strict";
7703
- init_esm_shims();
7704
- function RetryOperation(timeouts, options) {
7705
- if (typeof options === "boolean") {
7706
- options = { forever: options };
7707
- }
7708
- this._originalTimeouts = JSON.parse(JSON.stringify(timeouts));
7709
- this._timeouts = timeouts;
7710
- this._options = options || {};
7711
- this._maxRetryTime = options && options.maxRetryTime || Infinity;
7712
- this._fn = null;
7713
- this._errors = [];
7714
- this._attempts = 1;
7715
- this._operationTimeout = null;
7716
- this._operationTimeoutCb = null;
7717
- this._timeout = null;
7718
- this._operationStart = null;
7719
- if (this._options.forever) {
7720
- this._cachedTimeouts = this._timeouts.slice(0);
7721
- }
7722
- }
7723
- module.exports = RetryOperation;
7724
- RetryOperation.prototype.reset = function() {
7725
- this._attempts = 1;
7726
- this._timeouts = this._originalTimeouts;
7727
- };
7728
- RetryOperation.prototype.stop = function() {
7729
- if (this._timeout) {
7730
- clearTimeout(this._timeout);
7731
- }
7732
- this._timeouts = [];
7733
- this._cachedTimeouts = null;
7734
- };
7735
- RetryOperation.prototype.retry = function(err) {
7736
- if (this._timeout) {
7737
- clearTimeout(this._timeout);
7738
- }
7739
- if (!err) {
7740
- return false;
7741
- }
7742
- var currentTime = (/* @__PURE__ */ new Date()).getTime();
7743
- if (err && currentTime - this._operationStart >= this._maxRetryTime) {
7744
- this._errors.unshift(new Error("RetryOperation timeout occurred"));
7745
- return false;
7746
- }
7747
- this._errors.push(err);
7748
- var timeout = this._timeouts.shift();
7749
- if (timeout === void 0) {
7750
- if (this._cachedTimeouts) {
7751
- this._errors.splice(this._errors.length - 1, this._errors.length);
7752
- this._timeouts = this._cachedTimeouts.slice(0);
7753
- timeout = this._timeouts.shift();
7754
- } else {
7755
- return false;
7756
- }
7757
- }
7758
- var self = this;
7759
- var timer = setTimeout(function() {
7760
- self._attempts++;
7761
- if (self._operationTimeoutCb) {
7762
- self._timeout = setTimeout(function() {
7763
- self._operationTimeoutCb(self._attempts);
7764
- }, self._operationTimeout);
7765
- if (self._options.unref) {
7766
- self._timeout.unref();
7767
- }
7768
- }
7769
- self._fn(self._attempts);
7770
- }, timeout);
7771
- if (this._options.unref) {
7772
- timer.unref();
7773
- }
7774
- return true;
7775
- };
7776
- RetryOperation.prototype.attempt = function(fn, timeoutOps) {
7777
- this._fn = fn;
7778
- if (timeoutOps) {
7779
- if (timeoutOps.timeout) {
7780
- this._operationTimeout = timeoutOps.timeout;
7781
- }
7782
- if (timeoutOps.cb) {
7783
- this._operationTimeoutCb = timeoutOps.cb;
7784
- }
7785
- }
7786
- var self = this;
7787
- if (this._operationTimeoutCb) {
7788
- this._timeout = setTimeout(function() {
7789
- self._operationTimeoutCb();
7790
- }, self._operationTimeout);
7791
- }
7792
- this._operationStart = (/* @__PURE__ */ new Date()).getTime();
7793
- this._fn(this._attempts);
7794
- };
7795
- RetryOperation.prototype.try = function(fn) {
7796
- console.log("Using RetryOperation.try() is deprecated");
7797
- this.attempt(fn);
7798
- };
7799
- RetryOperation.prototype.start = function(fn) {
7800
- console.log("Using RetryOperation.start() is deprecated");
7801
- this.attempt(fn);
7802
- };
7803
- RetryOperation.prototype.start = RetryOperation.prototype.try;
7804
- RetryOperation.prototype.errors = function() {
7805
- return this._errors;
7806
- };
7807
- RetryOperation.prototype.attempts = function() {
7808
- return this._attempts;
7809
- };
7810
- RetryOperation.prototype.mainError = function() {
7811
- if (this._errors.length === 0) {
7812
- return null;
7813
- }
7814
- var counts = {};
7815
- var mainError = null;
7816
- var mainErrorCount = 0;
7817
- for (var i = 0; i < this._errors.length; i++) {
7818
- var error = this._errors[i];
7819
- var message = error.message;
7820
- var count = (counts[message] || 0) + 1;
7821
- counts[message] = count;
7822
- if (count >= mainErrorCount) {
7823
- mainError = error;
7824
- mainErrorCount = count;
7825
- }
7826
- }
7827
- return mainError;
7828
- };
7829
- }
7830
- });
7831
-
7832
- // ../../node_modules/.bun/retry@0.12.0/node_modules/retry/lib/retry.js
7833
- var require_retry = __commonJS({
7834
- "../../node_modules/.bun/retry@0.12.0/node_modules/retry/lib/retry.js"(exports) {
7835
- "use strict";
7836
- init_esm_shims();
7837
- var RetryOperation = require_retry_operation();
7838
- exports.operation = function(options) {
7839
- var timeouts = exports.timeouts(options);
7840
- return new RetryOperation(timeouts, {
7841
- forever: options && options.forever,
7842
- unref: options && options.unref,
7843
- maxRetryTime: options && options.maxRetryTime
7844
- });
7845
- };
7846
- exports.timeouts = function(options) {
7847
- if (options instanceof Array) {
7848
- return [].concat(options);
7849
- }
7850
- var opts = {
7851
- retries: 10,
7852
- factor: 2,
7853
- minTimeout: 1 * 1e3,
7854
- maxTimeout: Infinity,
7855
- randomize: false
7856
- };
7857
- for (var key in options) {
7858
- opts[key] = options[key];
7859
- }
7860
- if (opts.minTimeout > opts.maxTimeout) {
7861
- throw new Error("minTimeout is greater than maxTimeout");
7862
- }
7863
- var timeouts = [];
7864
- for (var i = 0; i < opts.retries; i++) {
7865
- timeouts.push(this.createTimeout(i, opts));
7866
- }
7867
- if (options && options.forever && !timeouts.length) {
7868
- timeouts.push(this.createTimeout(i, opts));
7869
- }
7870
- timeouts.sort(function(a, b) {
7871
- return a - b;
7872
- });
7873
- return timeouts;
7874
- };
7875
- exports.createTimeout = function(attempt, opts) {
7876
- var random = opts.randomize ? Math.random() + 1 : 1;
7877
- var timeout = Math.round(random * opts.minTimeout * Math.pow(opts.factor, attempt));
7878
- timeout = Math.min(timeout, opts.maxTimeout);
7879
- return timeout;
7880
- };
7881
- exports.wrap = function(obj, options, methods) {
7882
- if (options instanceof Array) {
7883
- methods = options;
7884
- options = null;
7885
- }
7886
- if (!methods) {
7887
- methods = [];
7888
- for (var key in obj) {
7889
- if (typeof obj[key] === "function") {
7890
- methods.push(key);
7891
- }
7892
- }
7893
- }
7894
- for (var i = 0; i < methods.length; i++) {
7895
- var method = methods[i];
7896
- var original = obj[method];
7897
- obj[method] = function retryWrapper(original2) {
7898
- var op = exports.operation(options);
7899
- var args2 = Array.prototype.slice.call(arguments, 1);
7900
- var callback = args2.pop();
7901
- args2.push(function(err) {
7902
- if (op.retry(err)) {
7903
- return;
7904
- }
7905
- if (err) {
7906
- arguments[0] = op.mainError();
7907
- }
7908
- callback.apply(this, arguments);
7909
- });
7910
- op.attempt(function() {
7911
- original2.apply(obj, args2);
7912
- });
7913
- }.bind(obj, original);
7914
- obj[method].options = options;
7915
- }
7916
- };
7917
- }
7918
- });
7919
-
7920
- // ../../node_modules/.bun/retry@0.12.0/node_modules/retry/index.js
7921
- var require_retry2 = __commonJS({
7922
- "../../node_modules/.bun/retry@0.12.0/node_modules/retry/index.js"(exports, module) {
7923
- "use strict";
7924
- init_esm_shims();
7925
- module.exports = require_retry();
7926
- }
7927
- });
7928
-
7929
- // ../../node_modules/.bun/signal-exit@3.0.7/node_modules/signal-exit/signals.js
7930
- var require_signals = __commonJS({
7931
- "../../node_modules/.bun/signal-exit@3.0.7/node_modules/signal-exit/signals.js"(exports, module) {
7932
- "use strict";
7933
- init_esm_shims();
7934
- module.exports = [
7935
- "SIGABRT",
7936
- "SIGALRM",
7937
- "SIGHUP",
7938
- "SIGINT",
7939
- "SIGTERM"
7940
- ];
7941
- if (process.platform !== "win32") {
7942
- module.exports.push(
7943
- "SIGVTALRM",
7944
- "SIGXCPU",
7945
- "SIGXFSZ",
7946
- "SIGUSR2",
7947
- "SIGTRAP",
7948
- "SIGSYS",
7949
- "SIGQUIT",
7950
- "SIGIOT"
7951
- // should detect profiler and enable/disable accordingly.
7952
- // see #21
7953
- // 'SIGPROF'
7954
- );
7955
- }
7956
- if (process.platform === "linux") {
7957
- module.exports.push(
7958
- "SIGIO",
7959
- "SIGPOLL",
7960
- "SIGPWR",
7961
- "SIGSTKFLT",
7962
- "SIGUNUSED"
7963
- );
7964
- }
7965
- }
7966
- });
7967
-
7968
- // ../../node_modules/.bun/signal-exit@3.0.7/node_modules/signal-exit/index.js
7969
- var require_signal_exit = __commonJS({
7970
- "../../node_modules/.bun/signal-exit@3.0.7/node_modules/signal-exit/index.js"(exports, module) {
7971
- "use strict";
7972
- init_esm_shims();
7973
- var process2 = global.process;
7974
- var processOk = function(process3) {
7975
- return process3 && typeof process3 === "object" && typeof process3.removeListener === "function" && typeof process3.emit === "function" && typeof process3.reallyExit === "function" && typeof process3.listeners === "function" && typeof process3.kill === "function" && typeof process3.pid === "number" && typeof process3.on === "function";
7976
- };
7977
- if (!processOk(process2)) {
7978
- module.exports = function() {
7979
- return function() {
7980
- };
7981
- };
7982
- } else {
7983
- assert = __require("assert");
7984
- signals = require_signals();
7985
- isWin2 = /^win/i.test(process2.platform);
7986
- EE = __require("events");
7987
- if (typeof EE !== "function") {
7988
- EE = EE.EventEmitter;
7989
- }
7990
- if (process2.__signal_exit_emitter__) {
7991
- emitter = process2.__signal_exit_emitter__;
7992
- } else {
7993
- emitter = process2.__signal_exit_emitter__ = new EE();
7994
- emitter.count = 0;
7995
- emitter.emitted = {};
7996
- }
7997
- if (!emitter.infinite) {
7998
- emitter.setMaxListeners(Infinity);
7999
- emitter.infinite = true;
8000
- }
8001
- module.exports = function(cb, opts) {
8002
- if (!processOk(global.process)) {
8003
- return function() {
8004
- };
8005
- }
8006
- assert.equal(typeof cb, "function", "a callback must be provided for exit handler");
8007
- if (loaded === false) {
8008
- load();
8009
- }
8010
- var ev = "exit";
8011
- if (opts && opts.alwaysLast) {
8012
- ev = "afterexit";
8013
- }
8014
- var remove = function() {
8015
- emitter.removeListener(ev, cb);
8016
- if (emitter.listeners("exit").length === 0 && emitter.listeners("afterexit").length === 0) {
8017
- unload();
8018
- }
8019
- };
8020
- emitter.on(ev, cb);
8021
- return remove;
8022
- };
8023
- unload = function unload2() {
8024
- if (!loaded || !processOk(global.process)) {
8025
- return;
8026
- }
8027
- loaded = false;
8028
- signals.forEach(function(sig) {
8029
- try {
8030
- process2.removeListener(sig, sigListeners[sig]);
8031
- } catch (er) {
8032
- }
8033
- });
8034
- process2.emit = originalProcessEmit;
8035
- process2.reallyExit = originalProcessReallyExit;
8036
- emitter.count -= 1;
8037
- };
8038
- module.exports.unload = unload;
8039
- emit = function emit2(event, code, signal) {
8040
- if (emitter.emitted[event]) {
8041
- return;
8042
- }
8043
- emitter.emitted[event] = true;
8044
- emitter.emit(event, code, signal);
8045
- };
8046
- sigListeners = {};
8047
- signals.forEach(function(sig) {
8048
- sigListeners[sig] = function listener() {
8049
- if (!processOk(global.process)) {
8050
- return;
8051
- }
8052
- var listeners = process2.listeners(sig);
8053
- if (listeners.length === emitter.count) {
8054
- unload();
8055
- emit("exit", null, sig);
8056
- emit("afterexit", null, sig);
8057
- if (isWin2 && sig === "SIGHUP") {
8058
- sig = "SIGINT";
8059
- }
8060
- process2.kill(process2.pid, sig);
8061
- }
8062
- };
8063
- });
8064
- module.exports.signals = function() {
8065
- return signals;
8066
- };
8067
- loaded = false;
8068
- load = function load2() {
8069
- if (loaded || !processOk(global.process)) {
8070
- return;
8071
- }
8072
- loaded = true;
8073
- emitter.count += 1;
8074
- signals = signals.filter(function(sig) {
8075
- try {
8076
- process2.on(sig, sigListeners[sig]);
8077
- return true;
8078
- } catch (er) {
8079
- return false;
8080
- }
8081
- });
8082
- process2.emit = processEmit;
8083
- process2.reallyExit = processReallyExit;
8084
- };
8085
- module.exports.load = load;
8086
- originalProcessReallyExit = process2.reallyExit;
8087
- processReallyExit = function processReallyExit2(code) {
8088
- if (!processOk(global.process)) {
8089
- return;
8090
- }
8091
- process2.exitCode = code || /* istanbul ignore next */
8092
- 0;
8093
- emit("exit", process2.exitCode, null);
8094
- emit("afterexit", process2.exitCode, null);
8095
- originalProcessReallyExit.call(process2, process2.exitCode);
8096
- };
8097
- originalProcessEmit = process2.emit;
8098
- processEmit = function processEmit2(ev, arg) {
8099
- if (ev === "exit" && processOk(global.process)) {
8100
- if (arg !== void 0) {
8101
- process2.exitCode = arg;
8102
- }
8103
- var ret = originalProcessEmit.apply(this, arguments);
8104
- emit("exit", process2.exitCode, null);
8105
- emit("afterexit", process2.exitCode, null);
8106
- return ret;
8107
- } else {
8108
- return originalProcessEmit.apply(this, arguments);
8109
- }
8110
- };
8111
- }
8112
- var assert;
8113
- var signals;
8114
- var isWin2;
8115
- var EE;
8116
- var emitter;
8117
- var unload;
8118
- var emit;
8119
- var sigListeners;
8120
- var loaded;
8121
- var load;
8122
- var originalProcessReallyExit;
8123
- var processReallyExit;
8124
- var originalProcessEmit;
8125
- var processEmit;
8126
- }
8127
- });
8128
-
8129
- // ../../node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/mtime-precision.js
8130
- var require_mtime_precision = __commonJS({
8131
- "../../node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/mtime-precision.js"(exports, module) {
8132
- "use strict";
8133
- init_esm_shims();
8134
- var cacheSymbol = /* @__PURE__ */ Symbol();
8135
- function probe(file, fs3, callback) {
8136
- const cachedPrecision = fs3[cacheSymbol];
8137
- if (cachedPrecision) {
8138
- return fs3.stat(file, (err, stat5) => {
8139
- if (err) {
8140
- return callback(err);
8141
- }
8142
- callback(null, stat5.mtime, cachedPrecision);
8143
- });
8144
- }
8145
- const mtime = new Date(Math.ceil(Date.now() / 1e3) * 1e3 + 5);
8146
- fs3.utimes(file, mtime, mtime, (err) => {
8147
- if (err) {
8148
- return callback(err);
8149
- }
8150
- fs3.stat(file, (err2, stat5) => {
8151
- if (err2) {
8152
- return callback(err2);
8153
- }
8154
- const precision = stat5.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
8155
- Object.defineProperty(fs3, cacheSymbol, { value: precision });
8156
- callback(null, stat5.mtime, precision);
8157
- });
8158
- });
8159
- }
8160
- function getMtime(precision) {
8161
- let now = Date.now();
8162
- if (precision === "s") {
8163
- now = Math.ceil(now / 1e3) * 1e3;
8164
- }
8165
- return new Date(now);
8166
- }
8167
- module.exports.probe = probe;
8168
- module.exports.getMtime = getMtime;
8169
- }
8170
- });
8171
-
8172
- // ../../node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/lockfile.js
8173
- var require_lockfile = __commonJS({
8174
- "../../node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/lockfile.js"(exports, module) {
8175
- "use strict";
8176
- init_esm_shims();
8177
- var path2 = __require("path");
8178
- var fs3 = require_graceful_fs();
8179
- var retry = require_retry2();
8180
- var onExit = require_signal_exit();
8181
- var mtimePrecision = require_mtime_precision();
8182
- var locks = {};
8183
- function getLockFile(file, options) {
8184
- return options.lockfilePath || `${file}.lock`;
8185
- }
8186
- function resolveCanonicalPath(file, options, callback) {
8187
- if (!options.realpath) {
8188
- return callback(null, path2.resolve(file));
8189
- }
8190
- options.fs.realpath(file, callback);
8191
- }
8192
- function acquireLock(file, options, callback) {
8193
- const lockfilePath = getLockFile(file, options);
8194
- options.fs.mkdir(lockfilePath, (err) => {
8195
- if (!err) {
8196
- return mtimePrecision.probe(lockfilePath, options.fs, (err2, mtime, mtimePrecision2) => {
8197
- if (err2) {
8198
- options.fs.rmdir(lockfilePath, () => {
8199
- });
8200
- return callback(err2);
8201
- }
8202
- callback(null, mtime, mtimePrecision2);
8203
- });
8204
- }
8205
- if (err.code !== "EEXIST") {
8206
- return callback(err);
8207
- }
8208
- if (options.stale <= 0) {
8209
- return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
8210
- }
8211
- options.fs.stat(lockfilePath, (err2, stat5) => {
8212
- if (err2) {
8213
- if (err2.code === "ENOENT") {
8214
- return acquireLock(file, { ...options, stale: 0 }, callback);
8215
- }
8216
- return callback(err2);
8217
- }
8218
- if (!isLockStale(stat5, options)) {
8219
- return callback(Object.assign(new Error("Lock file is already being held"), { code: "ELOCKED", file }));
8220
- }
8221
- removeLock(file, options, (err3) => {
8222
- if (err3) {
8223
- return callback(err3);
8224
- }
8225
- acquireLock(file, { ...options, stale: 0 }, callback);
8226
- });
8227
- });
8228
- });
8229
- }
8230
- function isLockStale(stat5, options) {
8231
- return stat5.mtime.getTime() < Date.now() - options.stale;
8232
- }
8233
- function removeLock(file, options, callback) {
8234
- options.fs.rmdir(getLockFile(file, options), (err) => {
8235
- if (err && err.code !== "ENOENT") {
8236
- return callback(err);
8237
- }
8238
- callback();
8239
- });
8240
- }
8241
- function updateLock(file, options) {
8242
- const lock5 = locks[file];
8243
- if (lock5.updateTimeout) {
8244
- return;
8245
- }
8246
- lock5.updateDelay = lock5.updateDelay || options.update;
8247
- lock5.updateTimeout = setTimeout(() => {
8248
- lock5.updateTimeout = null;
8249
- options.fs.stat(lock5.lockfilePath, (err, stat5) => {
8250
- const isOverThreshold = lock5.lastUpdate + options.stale < Date.now();
8251
- if (err) {
8252
- if (err.code === "ENOENT" || isOverThreshold) {
8253
- return setLockAsCompromised(file, lock5, Object.assign(err, { code: "ECOMPROMISED" }));
8254
- }
8255
- lock5.updateDelay = 1e3;
8256
- return updateLock(file, options);
8257
- }
8258
- const isMtimeOurs = lock5.mtime.getTime() === stat5.mtime.getTime();
8259
- if (!isMtimeOurs) {
8260
- return setLockAsCompromised(
8261
- file,
8262
- lock5,
8263
- Object.assign(
8264
- new Error("Unable to update lock within the stale threshold"),
8265
- { code: "ECOMPROMISED" }
8266
- )
8267
- );
8268
- }
8269
- const mtime = mtimePrecision.getMtime(lock5.mtimePrecision);
8270
- options.fs.utimes(lock5.lockfilePath, mtime, mtime, (err2) => {
8271
- const isOverThreshold2 = lock5.lastUpdate + options.stale < Date.now();
8272
- if (lock5.released) {
8273
- return;
8274
- }
8275
- if (err2) {
8276
- if (err2.code === "ENOENT" || isOverThreshold2) {
8277
- return setLockAsCompromised(file, lock5, Object.assign(err2, { code: "ECOMPROMISED" }));
8278
- }
8279
- lock5.updateDelay = 1e3;
8280
- return updateLock(file, options);
8281
- }
8282
- lock5.mtime = mtime;
8283
- lock5.lastUpdate = Date.now();
8284
- lock5.updateDelay = null;
8285
- updateLock(file, options);
8286
- });
8287
- });
8288
- }, lock5.updateDelay);
8289
- if (lock5.updateTimeout.unref) {
8290
- lock5.updateTimeout.unref();
8291
- }
8292
- }
8293
- function setLockAsCompromised(file, lock5, err) {
8294
- lock5.released = true;
8295
- if (lock5.updateTimeout) {
8296
- clearTimeout(lock5.updateTimeout);
8297
- }
8298
- if (locks[file] === lock5) {
8299
- delete locks[file];
8300
- }
8301
- lock5.options.onCompromised(err);
8302
- }
8303
- function lock4(file, options, callback) {
8304
- options = {
8305
- stale: 1e4,
8306
- update: null,
8307
- realpath: true,
8308
- retries: 0,
8309
- fs: fs3,
8310
- onCompromised: (err) => {
8311
- throw err;
8312
- },
8313
- ...options
8314
- };
8315
- options.retries = options.retries || 0;
8316
- options.retries = typeof options.retries === "number" ? { retries: options.retries } : options.retries;
8317
- options.stale = Math.max(options.stale || 0, 2e3);
8318
- options.update = options.update == null ? options.stale / 2 : options.update || 0;
8319
- options.update = Math.max(Math.min(options.update, options.stale / 2), 1e3);
8320
- resolveCanonicalPath(file, options, (err, file2) => {
8321
- if (err) {
8322
- return callback(err);
8323
- }
8324
- const operation = retry.operation(options.retries);
8325
- operation.attempt(() => {
8326
- acquireLock(file2, options, (err2, mtime, mtimePrecision2) => {
8327
- if (operation.retry(err2)) {
8328
- return;
8329
- }
8330
- if (err2) {
8331
- return callback(operation.mainError());
8332
- }
8333
- const lock5 = locks[file2] = {
8334
- lockfilePath: getLockFile(file2, options),
8335
- mtime,
8336
- mtimePrecision: mtimePrecision2,
8337
- options,
8338
- lastUpdate: Date.now()
8339
- };
8340
- updateLock(file2, options);
8341
- callback(null, (releasedCallback) => {
8342
- if (lock5.released) {
8343
- return releasedCallback && releasedCallback(Object.assign(new Error("Lock is already released"), { code: "ERELEASED" }));
8344
- }
8345
- unlock4(file2, { ...options, realpath: false }, releasedCallback);
8346
- });
8347
- });
8348
- });
8349
- });
8350
- }
8351
- function unlock4(file, options, callback) {
8352
- options = {
8353
- fs: fs3,
8354
- realpath: true,
8355
- ...options
8356
- };
8357
- resolveCanonicalPath(file, options, (err, file2) => {
8358
- if (err) {
8359
- return callback(err);
8360
- }
8361
- const lock5 = locks[file2];
8362
- if (!lock5) {
8363
- return callback(Object.assign(new Error("Lock is not acquired/owned by you"), { code: "ENOTACQUIRED" }));
8364
- }
8365
- lock5.updateTimeout && clearTimeout(lock5.updateTimeout);
8366
- lock5.released = true;
8367
- delete locks[file2];
8368
- removeLock(file2, options, callback);
8369
- });
8370
- }
8371
- function check(file, options, callback) {
8372
- options = {
8373
- stale: 1e4,
8374
- realpath: true,
8375
- fs: fs3,
8376
- ...options
8377
- };
8378
- options.stale = Math.max(options.stale || 0, 2e3);
8379
- resolveCanonicalPath(file, options, (err, file2) => {
8380
- if (err) {
8381
- return callback(err);
8382
- }
8383
- options.fs.stat(getLockFile(file2, options), (err2, stat5) => {
8384
- if (err2) {
8385
- return err2.code === "ENOENT" ? callback(null, false) : callback(err2);
8386
- }
8387
- return callback(null, !isLockStale(stat5, options));
8388
- });
8389
- });
8390
- }
8391
- function getLocks() {
8392
- return locks;
8393
- }
8394
- onExit(() => {
8395
- for (const file in locks) {
8396
- const options = locks[file].options;
8397
- try {
8398
- options.fs.rmdirSync(getLockFile(file, options));
8399
- } catch (e) {
8400
- }
8401
- }
8402
- });
8403
- module.exports.lock = lock4;
8404
- module.exports.unlock = unlock4;
8405
- module.exports.check = check;
8406
- module.exports.getLocks = getLocks;
8407
- }
8408
- });
8409
-
8410
- // ../../node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/adapter.js
8411
- var require_adapter = __commonJS({
8412
- "../../node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/lib/adapter.js"(exports, module) {
8413
- "use strict";
8414
- init_esm_shims();
8415
- var fs3 = require_graceful_fs();
8416
- function createSyncFs(fs4) {
8417
- const methods = ["mkdir", "realpath", "stat", "rmdir", "utimes"];
8418
- const newFs = { ...fs4 };
8419
- methods.forEach((method) => {
8420
- newFs[method] = (...args2) => {
8421
- const callback = args2.pop();
8422
- let ret;
8423
- try {
8424
- ret = fs4[`${method}Sync`](...args2);
8425
- } catch (err) {
8426
- return callback(err);
8427
- }
8428
- callback(null, ret);
8429
- };
8430
- });
8431
- return newFs;
8432
- }
8433
- function toPromise(method) {
8434
- return (...args2) => new Promise((resolve20, reject) => {
8435
- args2.push((err, result) => {
8436
- if (err) {
8437
- reject(err);
8438
- } else {
8439
- resolve20(result);
8440
- }
8441
- });
8442
- method(...args2);
8443
- });
8444
- }
8445
- function toSync(method) {
8446
- return (...args2) => {
8447
- let err;
8448
- let result;
8449
- args2.push((_err, _result) => {
8450
- err = _err;
8451
- result = _result;
6787
+ release3 = resolve20;
8452
6788
  });
8453
- method(...args2);
8454
- if (err) {
8455
- throw err;
6789
+ const entry = this._queue.then(() => release3);
6790
+ this._queue = this._queue.then(() => next);
6791
+ return entry;
6792
+ }
6793
+ /**
6794
+ * Convenience wrapper: acquire the lock, run `fn`, then automatically
6795
+ * release. Returns whatever `fn` returns.
6796
+ */
6797
+ async run(fn) {
6798
+ const release3 = await this.acquire();
6799
+ try {
6800
+ return await fn();
6801
+ } finally {
6802
+ release3();
8456
6803
  }
8457
- return result;
8458
- };
8459
- }
8460
- function toSyncOptions(options) {
8461
- options = { ...options };
8462
- options.fs = createSyncFs(options.fs || fs3);
8463
- if (typeof options.retries === "number" && options.retries > 0 || options.retries && typeof options.retries.retries === "number" && options.retries.retries > 0) {
8464
- throw Object.assign(new Error("Cannot use retries with the sync api"), { code: "ESYNC" });
8465
6804
  }
8466
- return options;
8467
- }
8468
- module.exports = {
8469
- toPromise,
8470
- toSync,
8471
- toSyncOptions
8472
6805
  };
8473
6806
  }
8474
6807
  });
8475
6808
 
8476
- // ../../node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/index.js
8477
- var require_proper_lockfile = __commonJS({
8478
- "../../node_modules/.bun/proper-lockfile@4.1.2/node_modules/proper-lockfile/index.js"(exports, module) {
6809
+ // ../core/src/lockfile.ts
6810
+ import { createRequire as nodeCreateRequire2 } from "module";
6811
+ var requireLockfile, impl2, lock, unlock, check;
6812
+ var init_lockfile = __esm({
6813
+ "../core/src/lockfile.ts"() {
8479
6814
  "use strict";
8480
6815
  init_esm_shims();
8481
- var lockfile4 = require_lockfile();
8482
- var { toPromise, toSync, toSyncOptions } = require_adapter();
8483
- async function lock4(file, options) {
8484
- const release3 = await toPromise(lockfile4.lock)(file, options);
8485
- return toPromise(release3);
8486
- }
8487
- function lockSync(file, options) {
8488
- const release3 = toSync(lockfile4.lock)(file, toSyncOptions(options));
8489
- return toSync(release3);
8490
- }
8491
- function unlock4(file, options) {
8492
- return toPromise(lockfile4.unlock)(file, options);
8493
- }
8494
- function unlockSync(file, options) {
8495
- return toSync(lockfile4.unlock)(file, toSyncOptions(options));
8496
- }
8497
- function check(file, options) {
8498
- return toPromise(lockfile4.check)(file, options);
8499
- }
8500
- function checkSync(file, options) {
8501
- return toSync(lockfile4.check)(file, toSyncOptions(options));
8502
- }
8503
- module.exports = lock4;
8504
- module.exports.lock = lock4;
8505
- module.exports.unlock = unlock4;
8506
- module.exports.lockSync = lockSync;
8507
- module.exports.unlockSync = unlockSync;
8508
- module.exports.check = check;
8509
- module.exports.checkSync = checkSync;
6816
+ requireLockfile = nodeCreateRequire2(import.meta.url);
6817
+ impl2 = requireLockfile("proper-lockfile/index.js");
6818
+ lock = impl2.lock;
6819
+ unlock = impl2.unlock;
6820
+ check = impl2.check;
8510
6821
  }
8511
6822
  });
8512
6823
 
@@ -8515,14 +6826,14 @@ import { join as join16, dirname as dirname4 } from "path";
8515
6826
  import { homedir as homedir9, platform as platform3 } from "os";
8516
6827
  import { existsSync as existsSync12, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
8517
6828
  import { readFile as readFile12, writeFile as writeFile5, rename as rename2, chmod } from "fs/promises";
8518
- import { randomBytes as randomBytes8 } from "crypto";
8519
- var lockfile, USER_SETTINGS_PATH, TrustStore;
6829
+ import { randomBytes as randomBytes9 } from "crypto";
6830
+ var USER_SETTINGS_PATH, TrustStore;
8520
6831
  var init_TrustStore = __esm({
8521
6832
  "../core/src/TrustStore.ts"() {
8522
6833
  "use strict";
8523
6834
  init_esm_shims();
8524
6835
  init_Mutex();
8525
- lockfile = __toESM(require_proper_lockfile(), 1);
6836
+ init_lockfile();
8526
6837
  USER_SETTINGS_PATH = join16(homedir9(), ".msapling", "settings.json");
8527
6838
  TrustStore = class {
8528
6839
  /** Current in-memory set of trusted `tool:command` keys. */
@@ -8563,7 +6874,7 @@ var init_TrustStore = __esm({
8563
6874
  const dir = dirname4(this.settingsPath);
8564
6875
  if (!existsSync12(dir)) mkdirSync2(dir, { recursive: true });
8565
6876
  const pid = process.pid;
8566
- const rand = randomBytes8(4).toString("hex");
6877
+ const rand = randomBytes9(4).toString("hex");
8567
6878
  const tmpPath = `${this.settingsPath}.tmp.${pid}.${rand}`;
8568
6879
  await writeFile5(tmpPath, JSON.stringify(settings, null, 2), "utf8");
8569
6880
  await rename2(tmpPath, this.settingsPath);
@@ -8615,7 +6926,7 @@ var init_TrustStore = __esm({
8615
6926
  }
8616
6927
  let release3 = null;
8617
6928
  try {
8618
- release3 = await lockfile.lock(this.settingsPath, { retries: 5, retryWait: 50 });
6929
+ release3 = await lock(this.settingsPath, { retries: 5, retryWait: 50 });
8619
6930
  this.trusted.add(key);
8620
6931
  const settings = await this.readSettings();
8621
6932
  const existing = Array.isArray(settings.trustedCommands) ? settings.trustedCommands : [];
@@ -8626,7 +6937,7 @@ var init_TrustStore = __esm({
8626
6937
  } finally {
8627
6938
  if (release3) {
8628
6939
  try {
8629
- await lockfile.unlock(this.settingsPath, { skipStale: true });
6940
+ await unlock(this.settingsPath, { skipStale: true });
8630
6941
  } catch {
8631
6942
  }
8632
6943
  }
@@ -8649,7 +6960,7 @@ var init_TrustStore = __esm({
8649
6960
  }
8650
6961
  let release3 = null;
8651
6962
  try {
8652
- release3 = await lockfile.lock(this.settingsPath, { retries: 5, retryWait: 50 });
6963
+ release3 = await lock(this.settingsPath, { retries: 5, retryWait: 50 });
8653
6964
  this.trusted.delete(key);
8654
6965
  const settings = await this.readSettings();
8655
6966
  if (Array.isArray(settings.trustedCommands)) {
@@ -8661,7 +6972,7 @@ var init_TrustStore = __esm({
8661
6972
  } finally {
8662
6973
  if (release3) {
8663
6974
  try {
8664
- await lockfile.unlock(this.settingsPath, { skipStale: true });
6975
+ await unlock(this.settingsPath, { skipStale: true });
8665
6976
  } catch {
8666
6977
  }
8667
6978
  }
@@ -8688,7 +6999,7 @@ import { createHash as createHash4 } from "crypto";
8688
6999
  async function getKeytar() {
8689
7000
  if (_keytar !== "pending") return _keytar;
8690
7001
  try {
8691
- const mod = await import("keytar");
7002
+ const mod = await import("@napi-rs/keyring/keytar.js");
8692
7003
  _keytar = mod && typeof mod.setPassword === "function" ? mod : mod?.default ?? mod;
8693
7004
  } catch {
8694
7005
  _keytar = null;
@@ -8699,33 +7010,43 @@ async function saveToken(baseDir, token) {
8699
7010
  const filePath = join17(baseDir, "vault", "token");
8700
7011
  try {
8701
7012
  const kt = await getKeytar();
8702
- if (!kt) throw new Error("keytar not loadable");
7013
+ if (!kt) throw new Error("keyring not loadable");
8703
7014
  await kt.setPassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT, token);
8704
- try {
8705
- if (existsSync13(filePath)) unlinkSync(filePath);
8706
- } catch {
8707
- }
8708
7015
  } catch (e) {
8709
- console.debug(`Keychain unavailable (${e instanceof Error ? e.message : String(e)}), falling back to file storage`);
8710
- await writeFile6(filePath, token, "utf8");
8711
- if (process.platform !== "win32") {
8712
- chmodSync(filePath, 384);
8713
- }
7016
+ throw new KeychainUnavailableError(e instanceof Error ? e.message : String(e));
7017
+ }
7018
+ try {
7019
+ if (existsSync13(filePath)) unlinkSync(filePath);
7020
+ } catch {
8714
7021
  }
8715
7022
  }
8716
7023
  async function loadToken(baseDir) {
8717
7024
  const filePath = join17(baseDir, "vault", "token");
7025
+ let kt = null;
8718
7026
  try {
8719
- const kt = await getKeytar();
8720
- if (!kt) throw new Error("keytar not loadable");
7027
+ kt = await getKeytar();
7028
+ if (!kt) throw new Error("keyring not loadable");
8721
7029
  const keychainToken = await kt.getPassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT);
8722
7030
  if (keychainToken) return keychainToken;
8723
7031
  } catch (e) {
8724
- console.debug(`Keychain unavailable (${e instanceof Error ? e.message : String(e)}), falling back to file storage`);
7032
+ kt = null;
7033
+ console.debug(`Keychain unavailable (${e instanceof Error ? e.message : String(e)})`);
8725
7034
  }
8726
7035
  if (existsSync13(filePath)) {
8727
- const text = await readFile13(filePath, "utf8");
8728
- return text.trim();
7036
+ const legacyToken = (await readFile13(filePath, "utf8")).trim();
7037
+ if (!legacyToken) return null;
7038
+ if (kt) {
7039
+ try {
7040
+ await kt.setPassword(KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT, legacyToken);
7041
+ unlinkSync(filePath);
7042
+ console.warn("[vault] Migrated legacy plaintext token into the OS keychain and deleted the plaintext file.");
7043
+ } catch (e) {
7044
+ console.warn(`[vault] WARNING: using legacy plaintext token file (keychain migration failed: ${e instanceof Error ? e.message : String(e)}). Re-run /login once the keychain is available to store the token securely.`);
7045
+ }
7046
+ } else {
7047
+ console.warn("[vault] WARNING: using legacy plaintext token file because the OS keychain is unavailable. This token is stored insecurely; new logins require a working keychain.");
7048
+ }
7049
+ return legacyToken;
8729
7050
  }
8730
7051
  return null;
8731
7052
  }
@@ -8746,6 +7067,29 @@ async function clearToken(baseDir) {
8746
7067
  console.warn(`Failed to delete token file: ${e}`);
8747
7068
  }
8748
7069
  }
7070
+ async function getOrCreateJournalKey() {
7071
+ let kt = null;
7072
+ try {
7073
+ kt = await getKeytar();
7074
+ if (!kt) return null;
7075
+ } catch {
7076
+ return null;
7077
+ }
7078
+ try {
7079
+ const existing = await kt.getPassword(KEYCHAIN_SERVICE, KEYCHAIN_JOURNAL_ACCOUNT);
7080
+ if (existing) {
7081
+ const buf = Buffer.from(existing, "base64");
7082
+ if (buf.length === 32) return buf;
7083
+ }
7084
+ const { randomBytes: randomBytes15 } = await import("crypto");
7085
+ const key = randomBytes15(32);
7086
+ await kt.setPassword(KEYCHAIN_SERVICE, KEYCHAIN_JOURNAL_ACCOUNT, key.toString("base64"));
7087
+ return key;
7088
+ } catch (e) {
7089
+ console.debug(`Journal key unavailable (${e instanceof Error ? e.message : String(e)})`);
7090
+ return null;
7091
+ }
7092
+ }
8749
7093
  async function writeVaultRef(baseDir, label, value) {
8750
7094
  const hash = createHash4("sha256").update(value, "utf8").digest("hex");
8751
7095
  const objectPath = join17(baseDir, "vault", "objects", hash);
@@ -8767,7 +7111,7 @@ async function readVaultRef(baseDir, label) {
8767
7111
  if (!existsSync13(objectPath)) return null;
8768
7112
  return readFile13(objectPath, "utf8");
8769
7113
  }
8770
- var _keytar, KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT;
7114
+ var _keytar, KEYCHAIN_SERVICE, KEYCHAIN_ACCOUNT, KeychainUnavailableError, KEYCHAIN_JOURNAL_ACCOUNT;
8771
7115
  var init_vault = __esm({
8772
7116
  "../core/src/Storage/vault.ts"() {
8773
7117
  "use strict";
@@ -8775,6 +7119,15 @@ var init_vault = __esm({
8775
7119
  _keytar = "pending";
8776
7120
  KEYCHAIN_SERVICE = "msapling-cli";
8777
7121
  KEYCHAIN_ACCOUNT = "auth_token";
7122
+ KeychainUnavailableError = class extends Error {
7123
+ constructor(cause) {
7124
+ super(
7125
+ `Cannot save auth token: the OS keychain is unavailable (${cause}). Refusing to write the token to plain disk. Remediation: enable your platform keychain (Windows: Credential Manager/DPAPI, macOS: Keychain, Linux: libsecret/gnome-keyring) and retry login.`
7126
+ );
7127
+ this.name = "KeychainUnavailableError";
7128
+ }
7129
+ };
7130
+ KEYCHAIN_JOURNAL_ACCOUNT = "journal_enc_key";
8778
7131
  }
8779
7132
  });
8780
7133
 
@@ -8834,10 +7187,10 @@ var init_recipes = __esm({
8834
7187
  });
8835
7188
 
8836
7189
  // ../core/src/Storage/history.ts
8837
- import { join as join19 } from "path";
7190
+ import { join as join19, basename } from "path";
8838
7191
  import { existsSync as existsSync15, renameSync as renameSync4, writeFileSync as writeFileSync3 } from "fs";
8839
7192
  import { writeFile as writeFile8, readFile as readFile15, appendFile } from "fs/promises";
8840
- import { createHash as createHash6, randomBytes as randomBytes9 } from "crypto";
7193
+ import { createHash as createHash6, randomBytes as randomBytes10 } from "crypto";
8841
7194
  function hashLine(line) {
8842
7195
  return createHash6("sha256").update(line, "utf8").digest("hex");
8843
7196
  }
@@ -8849,7 +7202,7 @@ async function appendHistoryEntry(baseDir, historyMutex, content) {
8849
7202
  if (!existsSync15(path2)) {
8850
7203
  await writeFile8(path2, "", "utf8");
8851
7204
  }
8852
- release3 = await lockfile2.lock(path2, { retries: 5, retryWait: 50 });
7205
+ release3 = await lock(path2, { retries: 5, retryWait: 50 });
8853
7206
  let prevHash = null;
8854
7207
  let seq = 1;
8855
7208
  if (existsSync15(path2)) {
@@ -8877,7 +7230,7 @@ async function appendHistoryEntry(baseDir, historyMutex, content) {
8877
7230
  } finally {
8878
7231
  if (release3) {
8879
7232
  try {
8880
- await lockfile2.unlock(path2, { skipStale: true });
7233
+ await unlock(path2, { skipStale: true });
8881
7234
  } catch {
8882
7235
  }
8883
7236
  }
@@ -8922,7 +7275,7 @@ async function saveHistory(baseDir, historyMutex, history) {
8922
7275
  let release3;
8923
7276
  try {
8924
7277
  if (!existsSync15(path2)) writeFileSync3(path2, "[]", "utf8");
8925
- release3 = await lockfile2.lock(path2, { realpath: false, retries: 5, retryWait: 50 });
7278
+ release3 = await lock(path2, { realpath: false, retries: 5, retryWait: 50 });
8926
7279
  await historyMutex.run(async () => {
8927
7280
  const tmpPath = `${path2}.tmp`;
8928
7281
  const content = JSON.stringify(history, null, 2);
@@ -8943,7 +7296,7 @@ async function saveHistory(baseDir, historyMutex, history) {
8943
7296
  } finally {
8944
7297
  if (release3) {
8945
7298
  try {
8946
- await lockfile2.unlock(path2, { skipStale: true });
7299
+ await unlock(path2, { skipStale: true });
8947
7300
  } catch (e) {
8948
7301
  console.warn(`Failed to unlock history file: ${e}`);
8949
7302
  }
@@ -8955,16 +7308,16 @@ async function loadHistory(baseDir, historyMutex) {
8955
7308
  if (!existsSync15(path2)) return [];
8956
7309
  let release3;
8957
7310
  try {
8958
- release3 = await lockfile2.lock(path2, { realpath: false, retries: 5, retryWait: 50 });
7311
+ release3 = await lock(path2, { realpath: false, retries: 5, retryWait: 50 });
8959
7312
  return historyMutex.run(async () => {
8960
7313
  if (existsSync15(path2)) {
8961
7314
  const text = await readFile15(path2, "utf8");
8962
7315
  try {
8963
7316
  return JSON.parse(text);
8964
7317
  } catch (parseErr) {
8965
- const filename = path2.split("/").pop() || "shell_history.json";
7318
+ const filename = basename(path2) || "shell_history.json";
8966
7319
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
8967
- const suffix = randomBytes9(4).toString("hex");
7320
+ const suffix = randomBytes10(4).toString("hex");
8968
7321
  const corruptBackupPath = join19(
8969
7322
  baseDir,
8970
7323
  "history",
@@ -8984,19 +7337,18 @@ async function loadHistory(baseDir, historyMutex) {
8984
7337
  } finally {
8985
7338
  if (release3) {
8986
7339
  try {
8987
- await lockfile2.unlock(path2, { skipStale: true });
7340
+ await unlock(path2, { skipStale: true });
8988
7341
  } catch (e) {
8989
7342
  console.warn(`Failed to unlock history file: ${e}`);
8990
7343
  }
8991
7344
  }
8992
7345
  }
8993
7346
  }
8994
- var lockfile2;
8995
7347
  var init_history = __esm({
8996
7348
  "../core/src/Storage/history.ts"() {
8997
7349
  "use strict";
8998
7350
  init_esm_shims();
8999
- lockfile2 = __toESM(require_proper_lockfile(), 1);
7351
+ init_lockfile();
9000
7352
  }
9001
7353
  });
9002
7354
 
@@ -9004,13 +7356,13 @@ var init_history = __esm({
9004
7356
  import { join as join20 } from "path";
9005
7357
  import { existsSync as existsSync16, renameSync as renameSync5, writeFileSync as writeFileSync4 } from "fs";
9006
7358
  import { writeFile as writeFile9, readFile as readFile16 } from "fs/promises";
9007
- import { randomBytes as randomBytes10 } from "crypto";
7359
+ import { randomBytes as randomBytes11 } from "crypto";
9008
7360
  async function savePermissions(baseDir, permissionsMutex, permissions) {
9009
7361
  const path2 = join20(baseDir, "vault", "permissions.json");
9010
7362
  let release3;
9011
7363
  try {
9012
7364
  if (!existsSync16(path2)) writeFileSync4(path2, "{}", "utf8");
9013
- release3 = await lockfile3.lock(path2, { realpath: false, retries: 5, retryWait: 50 });
7365
+ release3 = await lock(path2, { realpath: false, retries: 5, retryWait: 50 });
9014
7366
  await permissionsMutex.run(async () => {
9015
7367
  const tmpPath = `${path2}.tmp`;
9016
7368
  const content = JSON.stringify(permissions, null, 2);
@@ -9031,7 +7383,7 @@ async function savePermissions(baseDir, permissionsMutex, permissions) {
9031
7383
  } finally {
9032
7384
  if (release3) {
9033
7385
  try {
9034
- await lockfile3.unlock(path2, { skipStale: true });
7386
+ await unlock(path2, { skipStale: true });
9035
7387
  } catch (e) {
9036
7388
  console.warn(`Failed to unlock permissions file: ${e}`);
9037
7389
  }
@@ -9043,7 +7395,7 @@ async function loadPermissions(baseDir, permissionsMutex) {
9043
7395
  if (!existsSync16(path2)) return { trustedCommands: [], trustedPaths: [] };
9044
7396
  let release3;
9045
7397
  try {
9046
- release3 = await lockfile3.lock(path2, { realpath: false, retries: 5, retryWait: 50 });
7398
+ release3 = await lock(path2, { realpath: false, retries: 5, retryWait: 50 });
9047
7399
  return permissionsMutex.run(async () => {
9048
7400
  if (existsSync16(path2)) {
9049
7401
  const text = await readFile16(path2, "utf8");
@@ -9052,7 +7404,7 @@ async function loadPermissions(baseDir, permissionsMutex) {
9052
7404
  } catch (parseErr) {
9053
7405
  const filename = path2.split("/").pop() || "permissions.json";
9054
7406
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
9055
- const suffix = randomBytes10(4).toString("hex");
7407
+ const suffix = randomBytes11(4).toString("hex");
9056
7408
  const corruptBackupPath = join20(
9057
7409
  baseDir,
9058
7410
  "vault",
@@ -9072,19 +7424,18 @@ async function loadPermissions(baseDir, permissionsMutex) {
9072
7424
  } finally {
9073
7425
  if (release3) {
9074
7426
  try {
9075
- await lockfile3.unlock(path2, { skipStale: true });
7427
+ await unlock(path2, { skipStale: true });
9076
7428
  } catch (e) {
9077
7429
  console.warn(`Failed to unlock permissions file: ${e}`);
9078
7430
  }
9079
7431
  }
9080
7432
  }
9081
7433
  }
9082
- var lockfile3;
9083
7434
  var init_permissions = __esm({
9084
7435
  "../core/src/Storage/permissions.ts"() {
9085
7436
  "use strict";
9086
7437
  init_esm_shims();
9087
- lockfile3 = __toESM(require_proper_lockfile(), 1);
7438
+ init_lockfile();
9088
7439
  }
9089
7440
  });
9090
7441
 
@@ -9093,7 +7444,7 @@ import { join as join21 } from "path";
9093
7444
  import { homedir as homedir10 } from "os";
9094
7445
  import { chmodSync as chmodSync2 } from "fs";
9095
7446
  import { mkdir as mkdir6, writeFile as writeFile10 } from "fs/promises";
9096
- import { randomBytes as randomBytes11 } from "crypto";
7447
+ import { randomBytes as randomBytes12 } from "crypto";
9097
7448
  var StorageManager;
9098
7449
  var init_Storage = __esm({
9099
7450
  "../core/src/Storage.ts"() {
@@ -9101,6 +7452,8 @@ var init_Storage = __esm({
9101
7452
  init_esm_shims();
9102
7453
  init_Mutex();
9103
7454
  init_vault();
7455
+ init_vault();
7456
+ init_vault();
9104
7457
  init_recipes();
9105
7458
  init_history();
9106
7459
  init_permissions();
@@ -9212,7 +7565,7 @@ var init_Storage = __esm({
9212
7565
  await this._ready;
9213
7566
  const filename = filePath.split("/").pop() || "file";
9214
7567
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
9215
- const suffix = randomBytes11(4).toString("hex");
7568
+ const suffix = randomBytes12(4).toString("hex");
9216
7569
  const backupPath = join21(this.baseDir, "backups", `${filename}.backup-${stamp}-${suffix}.bak`);
9217
7570
  await writeFile10(backupPath, content, "utf8");
9218
7571
  if (process.platform !== "win32") {
@@ -9224,23 +7577,48 @@ var init_Storage = __esm({
9224
7577
  }
9225
7578
  });
9226
7579
 
7580
+ // ../core/src/journalCrypto.ts
7581
+ async function initJournalEncryption() {
7582
+ if (_initialized) return true;
7583
+ const key = await getOrCreateJournalKey();
7584
+ configureJournalCrypto(() => key);
7585
+ _initialized = true;
7586
+ return key !== null;
7587
+ }
7588
+ var _initialized;
7589
+ var init_journalCrypto = __esm({
7590
+ "../core/src/journalCrypto.ts"() {
7591
+ "use strict";
7592
+ init_esm_shims();
7593
+ init_src();
7594
+ init_vault();
7595
+ _initialized = false;
7596
+ }
7597
+ });
7598
+
9227
7599
  // ../core/src/Settings.ts
9228
7600
  import { homedir as homedir11 } from "os";
9229
7601
  import { join as join22 } from "path";
9230
7602
  import { existsSync as existsSync17 } from "fs";
9231
7603
  import * as fs from "fs";
9232
7604
  import { readFile as readFile17 } from "fs/promises";
9233
- import { randomBytes as randomBytes12 } from "crypto";
7605
+ import { randomBytes as randomBytes13 } from "crypto";
7606
+ function backupStaleFile(p) {
7607
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
7608
+ const suffix = randomBytes13(4).toString("hex");
7609
+ fs.renameSync(p, `${p}.broken-${stamp}-${suffix}`);
7610
+ }
9234
7611
  function ensureConfigDir(p) {
7612
+ if (fs.existsSync(p) && !fs.statSync(p).isDirectory()) {
7613
+ backupStaleFile(p);
7614
+ }
9235
7615
  try {
9236
7616
  fs.mkdirSync(p, { recursive: true, mode: 448 });
9237
7617
  } catch (e) {
9238
7618
  if (e.code === "EEXIST" || e.code === "ENOTDIR") {
9239
7619
  const stat5 = fs.statSync(p);
9240
7620
  if (!stat5.isDirectory()) {
9241
- const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
9242
- const suffix = randomBytes12(4).toString("hex");
9243
- fs.renameSync(p, `${p}.broken-${stamp}-${suffix}`);
7621
+ backupStaleFile(p);
9244
7622
  fs.mkdirSync(p, { recursive: true, mode: 448 });
9245
7623
  }
9246
7624
  } else {
@@ -9305,7 +7683,8 @@ function mergeSettings(base, override) {
9305
7683
  }
9306
7684
  async function loadSettings(cwd = process.cwd(), env = process.env, warn) {
9307
7685
  const sources = [];
9308
- const userPath = join22(homedir11() || ".", ".msapling", "settings.json");
7686
+ const home = env.HOME || env.USERPROFILE || process.env.HOME || process.env.USERPROFILE || homedir11() || ".";
7687
+ const userPath = join22(home, ".msapling", "settings.json");
9309
7688
  const projectPath = join22(cwd, ".msapling", "settings.json");
9310
7689
  const [user, project] = await Promise.all([readJson(userPath), readJson(projectPath)]);
9311
7690
  if (user) sources.push(userPath);
@@ -9664,6 +8043,7 @@ __export(src_exports2, {
9664
8043
  GlobFilesTool: () => GlobFilesTool,
9665
8044
  GrepSearchTool: () => GrepSearchTool,
9666
8045
  HookRunner: () => HookRunner,
8046
+ KeychainUnavailableError: () => KeychainUnavailableError,
9667
8047
  ListDirectoryTool: () => ListDirectoryTool,
9668
8048
  MCPClient: () => MCPClient,
9669
8049
  MCPClientError: () => MCPClientError,
@@ -9688,6 +8068,8 @@ __export(src_exports2, {
9688
8068
  formatCell: () => formatCell,
9689
8069
  formatNotebookHeader: () => formatNotebookHeader,
9690
8070
  formatTodos: () => formatTodos,
8071
+ getOrCreateJournalKey: () => getOrCreateJournalKey,
8072
+ initJournalEncryption: () => initJournalEncryption,
9691
8073
  loadProjectConfig: () => loadProjectConfig,
9692
8074
  loadSettings: () => loadSettings,
9693
8075
  takeSnapshot: () => takeSnapshot
@@ -9702,6 +8084,8 @@ var init_src3 = __esm({
9702
8084
  init_TrustStore();
9703
8085
  init_ContextBudget();
9704
8086
  init_Storage();
8087
+ init_Storage();
8088
+ init_journalCrypto();
9705
8089
  init_Mutex();
9706
8090
  init_ProjectConfig();
9707
8091
  init_Settings();
@@ -9747,22 +8131,29 @@ async function promptPassword(prompt4) {
9747
8131
  const wasRaw = stdin.isRaw ?? false;
9748
8132
  setRawModeGuarded(stdin, true);
9749
8133
  let password = "";
8134
+ let settled = false;
8135
+ const settle = (value) => {
8136
+ if (settled) return;
8137
+ settled = true;
8138
+ setRawModeGuarded(stdin, wasRaw);
8139
+ stdin.removeListener("data", onData);
8140
+ stdout.write("\n");
8141
+ resolve20(value);
8142
+ };
9750
8143
  const onData = (chunk) => {
9751
- const char = chunk.toString();
9752
- if (char === "\n" || char === "\r") {
9753
- setRawModeGuarded(stdin, wasRaw);
9754
- stdin.removeListener("data", onData);
9755
- stdout.write("\n");
9756
- resolve20(password);
9757
- } else if (char === "") {
9758
- setRawModeGuarded(stdin, wasRaw);
9759
- stdin.removeListener("data", onData);
9760
- stdout.write("\n");
9761
- resolve20("");
9762
- } else if (char === "\x7F" || char === "\b") {
9763
- password = password.slice(0, -1);
9764
- } else if (char >= " " && char <= "~") {
9765
- password += char;
8144
+ try {
8145
+ const char = chunk.toString();
8146
+ if (char === "\n" || char === "\r") {
8147
+ settle(password);
8148
+ } else if (char === "") {
8149
+ settle("");
8150
+ } else if (char === "\x7F" || char === "\b") {
8151
+ password = password.slice(0, -1);
8152
+ } else if (char >= " " && char <= "~") {
8153
+ password += char;
8154
+ }
8155
+ } catch {
8156
+ settle("");
9766
8157
  }
9767
8158
  };
9768
8159
  stdin.on("data", onData);
@@ -9971,10 +8362,11 @@ var init_login = __esm({
9971
8362
  async function getKeytar2() {
9972
8363
  if (_keytar2 !== "pending") return _keytar2;
9973
8364
  try {
9974
- _keytar2 = await import("keytar");
8365
+ const mod = await import("@napi-rs/keyring/keytar.js");
8366
+ _keytar2 = mod && typeof mod.setPassword === "function" ? mod : mod?.default ?? mod;
9975
8367
  return _keytar2;
9976
8368
  } catch (e) {
9977
- console.warn(`[secureStore] keytar unavailable, falling back to file token: ${e instanceof Error ? e.message : String(e)}`);
8369
+ console.warn(`[secureStore] keyring unavailable, falling back to file token: ${e instanceof Error ? e.message : String(e)}`);
9978
8370
  _keytar2 = null;
9979
8371
  return null;
9980
8372
  }
@@ -10219,7 +8611,7 @@ var init_unlock = __esm({
10219
8611
  // src/commands/doctor.ts
10220
8612
  import { homedir as homedir12 } from "os";
10221
8613
  import { join as join23 } from "path";
10222
- import { existsSync as existsSync18 } from "fs";
8614
+ import { existsSync as existsSync19 } from "fs";
10223
8615
  import { readFile as readFile18 } from "fs/promises";
10224
8616
  async function checkApiHealth(client) {
10225
8617
  try {
@@ -10247,7 +8639,7 @@ async function checkAuthStatus(client) {
10247
8639
  async function checkSettingsFile() {
10248
8640
  const settingsPath = join23(homedir12(), ".msapling", "settings.json");
10249
8641
  try {
10250
- if (!existsSync18(settingsPath)) {
8642
+ if (!existsSync19(settingsPath)) {
10251
8643
  return { ok: false, message: `Not found: ${settingsPath}` };
10252
8644
  }
10253
8645
  const text = await readFile18(settingsPath, "utf8");
@@ -10815,6 +9207,43 @@ var init_ollama = __esm({
10815
9207
  });
10816
9208
 
10817
9209
  // src/commands/keys.ts
9210
+ function setRawModeGuarded2(stdin, mode) {
9211
+ try {
9212
+ if (typeof stdin.setRawMode === "function") {
9213
+ stdin.setRawMode(mode);
9214
+ }
9215
+ } catch {
9216
+ }
9217
+ }
9218
+ async function promptSecret(prompt4) {
9219
+ return new Promise((resolve20) => {
9220
+ const stdin = process.stdin;
9221
+ const stdout = process.stdout;
9222
+ stdout.write(prompt4);
9223
+ const wasRaw = stdin.isRaw ?? false;
9224
+ setRawModeGuarded2(stdin, true);
9225
+ let secret = "";
9226
+ const onData = (chunk) => {
9227
+ const char = chunk.toString();
9228
+ if (char === "\n" || char === "\r") {
9229
+ setRawModeGuarded2(stdin, wasRaw);
9230
+ stdin.removeListener("data", onData);
9231
+ stdout.write("\n");
9232
+ resolve20(secret);
9233
+ } else if (char === "") {
9234
+ setRawModeGuarded2(stdin, wasRaw);
9235
+ stdin.removeListener("data", onData);
9236
+ stdout.write("\n");
9237
+ resolve20("");
9238
+ } else if (char === "\x7F" || char === "\b") {
9239
+ secret = secret.slice(0, -1);
9240
+ } else if (char >= " " && char <= "~") {
9241
+ secret += char;
9242
+ }
9243
+ };
9244
+ stdin.on("data", onData);
9245
+ });
9246
+ }
10818
9247
  var keysCommand;
10819
9248
  var init_keys = __esm({
10820
9249
  "src/commands/keys.ts"() {
@@ -10848,12 +9277,42 @@ var init_keys = __esm({
10848
9277
  }
10849
9278
  if (sub === "add" || sub === "save") {
10850
9279
  const provider = rest[0];
10851
- const key = rest.slice(1).join(" ").trim();
10852
- if (!provider || !key) {
10853
- context.addMessage("system", "Usage: /keys add <provider> <key> (e.g. /keys add openai sk-...)");
9280
+ const inlineKey = rest.slice(1).join(" ").trim();
9281
+ if (!provider) {
9282
+ context.addMessage("system", "Usage: /keys add <provider> (e.g. /keys add openai) \u2014 you will be prompted for the key");
9283
+ return;
9284
+ }
9285
+ if (inlineKey) {
9286
+ context.addMessage(
9287
+ "error",
9288
+ "Refusing to accept an API key on the command line \u2014 it would be saved in your REPL/shell history."
9289
+ );
9290
+ context.addMessage("system", `Re-run without the key: /keys add ${provider}`);
9291
+ context.addMessage("system", "You will be prompted for the key with hidden input. Then rotate the key you just typed, since it is now in history.");
9292
+ return;
9293
+ }
9294
+ if (process.stdin.listenerCount("data") > 0) {
9295
+ context.addMessage(
9296
+ "error",
9297
+ "Cannot prompt for the key inside the REPL \u2014 Ink owns stdin and would echo the key into chat."
9298
+ );
9299
+ context.addMessage("system", `Run it outside the REPL instead: msapling --exec "/keys add ${provider}"`);
9300
+ return;
9301
+ }
9302
+ let key = "";
9303
+ try {
9304
+ key = await promptSecret(`Enter API key for ${provider} (hidden): `);
9305
+ } catch (err) {
9306
+ context.addMessage("error", `Key prompt failed: ${err}`);
9307
+ return;
9308
+ }
9309
+ key = key.trim();
9310
+ if (!key) {
9311
+ context.addMessage("system", "Cancelled \u2014 no key entered.");
10854
9312
  return;
10855
9313
  }
10856
9314
  const res = await context.client.saveProviderKey(provider, key);
9315
+ key = "";
10857
9316
  context.addMessage("system", `Saved key for ${provider}: ${res.message ?? res.status}`);
10858
9317
  return;
10859
9318
  }
@@ -10935,14 +9394,28 @@ var init_memories = __esm({
10935
9394
 
10936
9395
  // src/commands/mdrive.ts
10937
9396
  import { readFile as readFile19, writeFile as writeFile11 } from "fs/promises";
10938
- import { existsSync as existsSync19 } from "fs";
10939
- import { basename, resolve as resolve14 } from "path";
9397
+ import { existsSync as existsSync20 } from "fs";
9398
+ import { basename as basename2, resolve as resolve14, relative as relative14, isAbsolute as isAbsolute14, sep as sep3 } from "path";
10940
9399
  function formatBytes(b) {
10941
9400
  if (!b) return "0";
10942
9401
  if (b < 1024) return `${b}`;
10943
9402
  if (b < 1024 * 1024) return `${(b / 1024).toFixed(1)}K`;
10944
9403
  return `${(b / 1024 / 1024).toFixed(1)}M`;
10945
9404
  }
9405
+ function containLocalPath(targetPath, root = process.cwd()) {
9406
+ const resolvedRoot = resolve14(root);
9407
+ const resolved = isAbsolute14(targetPath) ? resolve14(targetPath) : resolve14(resolvedRoot, targetPath);
9408
+ const rel = relative14(resolvedRoot, resolved);
9409
+ if (rel === ".." || rel.startsWith(`..${sep3}`) || rel.startsWith("../") || isAbsolute14(rel)) {
9410
+ return null;
9411
+ }
9412
+ return resolved;
9413
+ }
9414
+ function isRemotePathSafe(remotePath) {
9415
+ if (!remotePath || remotePath.includes("\0")) return false;
9416
+ const segments = remotePath.replace(/\\/g, "/").split("/");
9417
+ return !segments.some((seg) => seg === "..");
9418
+ }
10946
9419
  var mdriveCommand;
10947
9420
  var init_mdrive = __esm({
10948
9421
  "src/commands/mdrive.ts"() {
@@ -10969,6 +9442,10 @@ var init_mdrive = __esm({
10969
9442
  try {
10970
9443
  if (sub === "ls" || sub === "list") {
10971
9444
  const path2 = rest[0] || ".";
9445
+ if (!isRemotePathSafe(path2)) {
9446
+ context.addMessage("error", `Rejected unsafe MDrive path (path traversal): ${path2}`);
9447
+ return;
9448
+ }
10972
9449
  const res = await context.client.mdriveList(path2);
10973
9450
  const entries = res.entries ?? res.files ?? res.items ?? [];
10974
9451
  context.addMessage("system", `MDrive: ${path2} (${entries.length} entries)`);
@@ -10986,19 +9463,31 @@ var init_mdrive = __esm({
10986
9463
  context.addMessage("system", "Usage: /mdrive cat <path>");
10987
9464
  return;
10988
9465
  }
9466
+ if (!isRemotePathSafe(p)) {
9467
+ context.addMessage("error", `Rejected unsafe MDrive path (path traversal): ${p}`);
9468
+ return;
9469
+ }
10989
9470
  const res = await context.client.mdriveRead(p);
10990
9471
  context.addMessage("system", res.content ?? res.body ?? "(no content)");
10991
9472
  return;
10992
9473
  }
10993
9474
  if (sub === "put" || sub === "upload" || sub === "write") {
10994
9475
  const local = rest[0];
10995
- const remote = rest[1] || (local ? basename(local) : "");
9476
+ const remote = rest[1] || (local ? basename2(local) : "");
10996
9477
  if (!local || !remote) {
10997
9478
  context.addMessage("system", "Usage: /mdrive put <local> [<remote>]");
10998
9479
  return;
10999
9480
  }
11000
- const absLocal = resolve14(local);
11001
- if (!existsSync19(absLocal)) {
9481
+ if (!isRemotePathSafe(remote)) {
9482
+ context.addMessage("error", `Rejected unsafe MDrive path (path traversal): ${remote}`);
9483
+ return;
9484
+ }
9485
+ const absLocal = containLocalPath(local);
9486
+ if (!absLocal) {
9487
+ context.addMessage("error", `Refusing to read local file outside the working directory: ${local}`);
9488
+ return;
9489
+ }
9490
+ if (!existsSync20(absLocal)) {
11002
9491
  context.addMessage("error", `Local file not found: ${absLocal}`);
11003
9492
  return;
11004
9493
  }
@@ -11014,11 +9503,23 @@ var init_mdrive = __esm({
11014
9503
  context.addMessage("system", "Usage: /mdrive get <remote> [<local>]");
11015
9504
  return;
11016
9505
  }
9506
+ if (!isRemotePathSafe(remote)) {
9507
+ context.addMessage("error", `Rejected unsafe MDrive path (path traversal): ${remote}`);
9508
+ return;
9509
+ }
9510
+ let absLocal = null;
9511
+ if (local) {
9512
+ absLocal = containLocalPath(local);
9513
+ if (!absLocal) {
9514
+ context.addMessage("error", `Refusing to write local file outside the working directory: ${local}`);
9515
+ return;
9516
+ }
9517
+ }
11017
9518
  const res = await context.client.mdriveRead(remote);
11018
9519
  const content = res.content ?? res.body ?? "";
11019
- if (local) {
11020
- await writeFile11(resolve14(local), content, "utf8");
11021
- context.addMessage("system", `Wrote ${resolve14(local)} (${formatBytes(content.length)})`);
9520
+ if (absLocal) {
9521
+ await writeFile11(absLocal, content, "utf8");
9522
+ context.addMessage("system", `Wrote ${absLocal} (${formatBytes(content.length)})`);
11022
9523
  } else {
11023
9524
  context.addMessage("system", content);
11024
9525
  }
@@ -11030,6 +9531,10 @@ var init_mdrive = __esm({
11030
9531
  context.addMessage("system", "Usage: /mdrive rm <path>");
11031
9532
  return;
11032
9533
  }
9534
+ if (!isRemotePathSafe(p)) {
9535
+ context.addMessage("error", `Rejected unsafe MDrive path (path traversal): ${p}`);
9536
+ return;
9537
+ }
11033
9538
  await context.client.mdriveDelete(p);
11034
9539
  context.addMessage("system", `Deleted mdrive:${p}`);
11035
9540
  return;
@@ -11041,6 +9546,10 @@ var init_mdrive = __esm({
11041
9546
  context.addMessage("system", "Usage: /mdrive mv <path> <new-name>");
11042
9547
  return;
11043
9548
  }
9549
+ if (!isRemotePathSafe(p) || !isRemotePathSafe(newName)) {
9550
+ context.addMessage("error", `Rejected unsafe MDrive path (path traversal): ${!isRemotePathSafe(p) ? p : newName}`);
9551
+ return;
9552
+ }
11044
9553
  await context.client.mdriveRename(p, newName);
11045
9554
  context.addMessage("system", `Renamed mdrive:${p} \u2192 ${newName}`);
11046
9555
  return;
@@ -11051,6 +9560,10 @@ var init_mdrive = __esm({
11051
9560
  context.addMessage("system", "Usage: /mdrive mkdir <path>");
11052
9561
  return;
11053
9562
  }
9563
+ if (!isRemotePathSafe(p)) {
9564
+ context.addMessage("error", `Rejected unsafe MDrive path (path traversal): ${p}`);
9565
+ return;
9566
+ }
11054
9567
  await context.client.mdriveMkdir(p);
11055
9568
  context.addMessage("system", `Created mdrive:${p}/`);
11056
9569
  return;
@@ -11061,7 +9574,7 @@ var init_mdrive = __esm({
11061
9574
  if (msg.includes("Invalid or revoked API key") || msg.includes("401")) {
11062
9575
  context.addMessage(
11063
9576
  "error",
11064
- 'MDrive requires a paid account + MDrive API key. Generate one at https://msapling.com/settings \u2192 API Keys \u2192 "Create MDrive Key", then run /keys add mdrive <key>.'
9577
+ 'MDrive requires a paid account + MDrive API key. Generate one at https://msapling.com/settings \u2192 API Keys \u2192 "Create MDrive Key", then run /keys add mdrive (you will be prompted for the key).'
11065
9578
  );
11066
9579
  } else {
11067
9580
  context.addMessage("error", `MDrive: ${msg}`);
@@ -11097,12 +9610,12 @@ var init_clear = __esm({
11097
9610
  // src/commands/mode.ts
11098
9611
  import { homedir as homedir13 } from "os";
11099
9612
  import { join as join24 } from "path";
11100
- import { existsSync as existsSync20 } from "fs";
9613
+ import { existsSync as existsSync21 } from "fs";
11101
9614
  import { readFile as readFile20, writeFile as writeFile12, mkdir as mkdir7 } from "fs/promises";
11102
9615
  async function persistApprovalMode(mode, ttlMs) {
11103
9616
  try {
11104
9617
  let existing = {};
11105
- if (existsSync20(SETTINGS_PATH)) {
9618
+ if (existsSync21(SETTINGS_PATH)) {
11106
9619
  const text = await readFile20(SETTINGS_PATH, "utf8");
11107
9620
  if (text.trim()) {
11108
9621
  existing = JSON.parse(text);
@@ -11115,7 +9628,7 @@ async function persistApprovalMode(mode, ttlMs) {
11115
9628
  };
11116
9629
  existing.approvalMode = entry;
11117
9630
  const settingsDir = join24(homedir13(), ".msapling");
11118
- if (!existsSync20(settingsDir)) {
9631
+ if (!existsSync21(settingsDir)) {
11119
9632
  await mkdir7(settingsDir, { recursive: true });
11120
9633
  }
11121
9634
  await writeFile12(SETTINGS_PATH, JSON.stringify(existing, null, 2), "utf8");
@@ -11550,7 +10063,7 @@ var init_compact = __esm({
11550
10063
 
11551
10064
  // src/commands/init.ts
11552
10065
  import { join as join25 } from "path";
11553
- import { existsSync as existsSync21 } from "fs";
10066
+ import { existsSync as existsSync22 } from "fs";
11554
10067
  import { writeFile as writeFile13 } from "fs/promises";
11555
10068
  var initCommand;
11556
10069
  var init_init = __esm({
@@ -11565,7 +10078,7 @@ var init_init = __esm({
11565
10078
  try {
11566
10079
  const cwd = process.cwd();
11567
10080
  const path2 = join25(cwd, "MSAPLING.md");
11568
- if (existsSync21(path2)) {
10081
+ if (existsSync22(path2)) {
11569
10082
  context.addMessage("error", "MSAPLING.md already exists in current directory.");
11570
10083
  return;
11571
10084
  }
@@ -11591,7 +10104,7 @@ var init_init = __esm({
11591
10104
  });
11592
10105
 
11593
10106
  // src/commands/review.ts
11594
- import { existsSync as existsSync22 } from "fs";
10107
+ import { existsSync as existsSync23 } from "fs";
11595
10108
  import { readFile as readFile21 } from "fs/promises";
11596
10109
  var reviewCommand;
11597
10110
  var init_review = __esm({
@@ -11611,7 +10124,7 @@ var init_review = __esm({
11611
10124
  }
11612
10125
  let content = "";
11613
10126
  try {
11614
- if (existsSync22(target)) {
10127
+ if (existsSync23(target)) {
11615
10128
  content = await readFile21(target, "utf8");
11616
10129
  } else {
11617
10130
  content = `Review target: ${target}`;
@@ -11705,7 +10218,7 @@ var init_swarm = __esm({
11705
10218
 
11706
10219
  // src/commands/recipe.ts
11707
10220
  import { parse as parseYaml } from "yaml";
11708
- import { existsSync as existsSync23 } from "fs";
10221
+ import { existsSync as existsSync24 } from "fs";
11709
10222
  import { readFile as readFile22 } from "fs/promises";
11710
10223
  import { join as join26 } from "path";
11711
10224
  function findRecipe(name, cwd) {
@@ -11713,7 +10226,7 @@ function findRecipe(name, cwd) {
11713
10226
  for (const suffix of NAME_SUFFIXES) {
11714
10227
  for (const ext of FILE_EXTS) {
11715
10228
  const p = join26(cwd, dir, `${name}${suffix}${ext}`);
11716
- if (existsSync23(p)) return p;
10229
+ if (existsSync24(p)) return p;
11717
10230
  }
11718
10231
  }
11719
10232
  }
@@ -11826,13 +10339,13 @@ ${rendered}` : rendered;
11826
10339
  });
11827
10340
 
11828
10341
  // src/commands/skill.ts
11829
- import { existsSync as existsSync24, readdirSync as readdirSync2, statSync as statSync5 } from "fs";
10342
+ import { existsSync as existsSync25, readdirSync as readdirSync2, statSync as statSync5 } from "fs";
11830
10343
  import { readFile as readFile23 } from "fs/promises";
11831
10344
  import { join as join27, resolve as resolve15 } from "path";
11832
10345
  function findSkillsRoot(cwd) {
11833
10346
  for (const candidate of SKILLS_DIRS) {
11834
10347
  const full = resolve15(cwd, candidate);
11835
- if (existsSync24(full) && statSync5(full).isDirectory()) return full;
10348
+ if (existsSync25(full) && statSync5(full).isDirectory()) return full;
11836
10349
  }
11837
10350
  return null;
11838
10351
  }
@@ -11968,7 +10481,7 @@ function parseArgs(args2) {
11968
10481
  }
11969
10482
  function formatTable(results) {
11970
10483
  const header = `${"Model".padEnd(40)} ${"TTFT(ms)".padStart(9)} ${"TPS".padStart(7)} ${"Tokens".padStart(8)} ${"Cost($)".padStart(9)}`;
11971
- const sep3 = "-".repeat(header.length);
10484
+ const sep4 = "-".repeat(header.length);
11972
10485
  const rows = results.map((r) => {
11973
10486
  const model = r.model.slice(0, 39).padEnd(40);
11974
10487
  const ttft = r.ttft_ms != null ? r.ttft_ms.toFixed(0).padStart(9) : " - ";
@@ -11978,7 +10491,7 @@ function formatTable(results) {
11978
10491
  const err = r.error ? ` \u26A0 ${r.error}` : "";
11979
10492
  return `${model} ${ttft} ${tps} ${tok} ${cost}${err}`;
11980
10493
  });
11981
- return [sep3, header, sep3, ...rows, sep3].join("\n");
10494
+ return [sep4, header, sep4, ...rows, sep4].join("\n");
11982
10495
  }
11983
10496
  var DEFAULT_PROMPTS, benchmarkCommand;
11984
10497
  var init_benchmark = __esm({
@@ -12322,13 +10835,13 @@ var init_theme = __esm({
12322
10835
  // src/commands/theme.ts
12323
10836
  import { join as join29 } from "path";
12324
10837
  import { homedir as homedir15 } from "os";
12325
- import { existsSync as existsSync25 } from "fs";
10838
+ import { existsSync as existsSync26 } from "fs";
12326
10839
  import { readFile as readFile24, writeFile as writeFile14 } from "fs/promises";
12327
10840
  async function persistTheme(storage, themeName) {
12328
10841
  const settingsPath = join29(homedir15(), ".msapling", "settings.json");
12329
10842
  let existing = {};
12330
10843
  try {
12331
- if (existsSync25(settingsPath)) {
10844
+ if (existsSync26(settingsPath)) {
12332
10845
  const text = await readFile24(settingsPath, "utf8");
12333
10846
  if (text.trim()) existing = JSON.parse(text);
12334
10847
  }
@@ -12407,8 +10920,8 @@ var init_version = __esm({
12407
10920
  description: "Show version information for CLI and core packages",
12408
10921
  category: "debug",
12409
10922
  handler: async (_args, context) => {
12410
- const cliVersion = true ? "2.3.6-beta.42" : "(dev)";
12411
- const coreVersion = true ? "2.3.2" : "(dev)";
10923
+ const cliVersion = true ? "2.3.6-beta.44" : "(dev)";
10924
+ const coreVersion = true ? "2.3.6-beta.43" : "(dev)";
12412
10925
  const runtime = process.version;
12413
10926
  context.addMessage("system", "MSapling Version Info");
12414
10927
  context.addMessage("system", "\u2500".repeat(40));
@@ -12416,7 +10929,7 @@ var init_version = __esm({
12416
10929
  context.addMessage("system", row2("Core (@msapling/core)", coreVersion));
12417
10930
  context.addMessage("system", row2("Runtime (Node/Bun)", runtime));
12418
10931
  try {
12419
- const ts = "2026-06-02T16:20:01.508Z";
10932
+ const ts = "2026-06-20T07:08:23.320Z";
12420
10933
  if (ts && ts !== "__BUILD_TIMESTAMP__") {
12421
10934
  context.addMessage("system", row2("Build Timestamp", ts));
12422
10935
  }
@@ -12430,13 +10943,13 @@ var init_version = __esm({
12430
10943
 
12431
10944
  // src/commands/feedback.ts
12432
10945
  import { join as join30 } from "path";
12433
- import { existsSync as existsSync26 } from "fs";
10946
+ import { existsSync as existsSync27 } from "fs";
12434
10947
  import { readFile as readFile25 } from "fs/promises";
12435
10948
  async function readCliVersion() {
12436
10949
  try {
12437
10950
  const baseDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
12438
10951
  const pkgPath = join30(baseDir, "..", "..", "package.json");
12439
- if (!existsSync26(pkgPath)) return "unknown";
10952
+ if (!existsSync27(pkgPath)) return "unknown";
12440
10953
  const text = await readFile25(pkgPath, "utf8");
12441
10954
  const json = JSON.parse(text);
12442
10955
  return json.version ?? "unknown";
@@ -12740,14 +11253,14 @@ var init_plan = __esm({
12740
11253
  // src/commands/note.ts
12741
11254
  import { homedir as homedir17 } from "os";
12742
11255
  import { join as join32 } from "path";
12743
- import { existsSync as existsSync27 } from "fs";
11256
+ import { existsSync as existsSync28 } from "fs";
12744
11257
  import { readFile as readFile26, writeFile as writeFile16 } from "fs/promises";
12745
11258
  function getNotesFilePath() {
12746
11259
  return join32(homedir17(), ".msapling", "notes.json");
12747
11260
  }
12748
11261
  async function readNotes(filePath = getNotesFilePath()) {
12749
11262
  try {
12750
- if (!existsSync27(filePath)) return [];
11263
+ if (!existsSync28(filePath)) return [];
12751
11264
  const raw = await readFile26(filePath, "utf8");
12752
11265
  const parsed = JSON.parse(raw);
12753
11266
  if (!Array.isArray(parsed)) return [];
@@ -12904,10 +11417,13 @@ var init_todo = __esm({
12904
11417
 
12905
11418
  // src/commands/outputStyle.ts
12906
11419
  import { homedir as homedir18 } from "os";
12907
- import { join as join33, basename as basename2, extname as extname3 } from "path";
12908
- import { existsSync as existsSync28, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync5 } from "fs";
11420
+ import { join as join33, basename as basename3, extname as extname3 } from "path";
11421
+ import { existsSync as existsSync29, mkdirSync as mkdirSync5, readdirSync as readdirSync3, readFileSync as readFileSync2, writeFileSync as writeFileSync5 } from "fs";
11422
+ function resolveHome() {
11423
+ return process.env.HOME || process.env.USERPROFILE || homedir18();
11424
+ }
12909
11425
  function stylesDir() {
12910
- return join33(homedir18(), ".msapling", "output-styles");
11426
+ return join33(resolveHome(), ".msapling", "output-styles");
12911
11427
  }
12912
11428
  function activeFile() {
12913
11429
  return join33(stylesDir(), ".active");
@@ -12931,7 +11447,7 @@ function parseStyleFile(text) {
12931
11447
  }
12932
11448
  function listUserStyles() {
12933
11449
  const dir = stylesDir();
12934
- if (!existsSync28(dir)) return [];
11450
+ if (!existsSync29(dir)) return [];
12935
11451
  const out = [];
12936
11452
  for (const entry of readdirSync3(dir)) {
12937
11453
  if (extname3(entry).toLowerCase() !== ".md") continue;
@@ -12940,7 +11456,7 @@ function listUserStyles() {
12940
11456
  const text = readFileSync2(full, "utf8");
12941
11457
  const { description, body } = parseStyleFile(text);
12942
11458
  out.push({
12943
- name: basename2(entry, ".md"),
11459
+ name: basename3(entry, ".md"),
12944
11460
  description,
12945
11461
  body,
12946
11462
  source: "user",
@@ -12963,7 +11479,7 @@ function findStyle(name) {
12963
11479
  function getActiveStyleName() {
12964
11480
  try {
12965
11481
  const f = activeFile();
12966
- if (!existsSync28(f)) return "default";
11482
+ if (!existsSync29(f)) return "default";
12967
11483
  return readFileSync2(f, "utf8").trim() || "default";
12968
11484
  } catch {
12969
11485
  return "default";
@@ -12971,7 +11487,7 @@ function getActiveStyleName() {
12971
11487
  }
12972
11488
  function setActiveStyleName(name) {
12973
11489
  const dir = stylesDir();
12974
- if (!existsSync28(dir)) mkdirSync5(dir, { recursive: true });
11490
+ if (!existsSync29(dir)) mkdirSync5(dir, { recursive: true });
12975
11491
  writeFileSync5(activeFile(), `${name}
12976
11492
  `, "utf8");
12977
11493
  }
@@ -12984,7 +11500,7 @@ function createUserStyle(name, description, body) {
12984
11500
  throw new Error(`Invalid style name "${name}" \u2014 use letters, digits, _ and - only.`);
12985
11501
  }
12986
11502
  const dir = stylesDir();
12987
- if (!existsSync28(dir)) mkdirSync5(dir, { recursive: true });
11503
+ if (!existsSync29(dir)) mkdirSync5(dir, { recursive: true });
12988
11504
  const target = join33(dir, `${name}.md`);
12989
11505
  const frontmatter = `---
12990
11506
  description: ${description.replace(/\n/g, " ")}
@@ -14351,7 +12867,7 @@ var exec_exports = {};
14351
12867
  __export(exec_exports, {
14352
12868
  runExec: () => runExec
14353
12869
  });
14354
- import { existsSync as existsSync31 } from "fs";
12870
+ import { existsSync as existsSync32 } from "fs";
14355
12871
  import { readFile as readFile29 } from "fs/promises";
14356
12872
  import { homedir as homedir20 } from "os";
14357
12873
  import { join as join35 } from "path";
@@ -14359,7 +12875,7 @@ async function loadPersistedSettings() {
14359
12875
  const out = { mode: "default", theme: null };
14360
12876
  try {
14361
12877
  const p = join35(homedir20(), ".msapling", "settings.json");
14362
- if (!existsSync31(p)) return out;
12878
+ if (!existsSync32(p)) return out;
14363
12879
  const raw = JSON.parse(await readFile29(p, "utf8"));
14364
12880
  const parsed = parseApprovalMode(raw, Date.now());
14365
12881
  if (parsed.kind === "ok") out.mode = parsed.mode;
@@ -14725,8 +13241,7 @@ async function runSub(argv) {
14725
13241
  console.log(formatSubSummary(balance));
14726
13242
  console.log("");
14727
13243
  } catch (e) {
14728
- console.error(`Error fetching subscription status: ${e.message}`);
14729
- process.exit(1);
13244
+ throw new Error(`Error fetching subscription status: ${e.message}`, { cause: e });
14730
13245
  }
14731
13246
  }
14732
13247
  async function runSubUpgrade(flags) {
@@ -14779,8 +13294,7 @@ Payment confirmed. Your plan has been upgraded to ${formatTier(product)}.`);
14779
13294
  Checkout ${result.state}. No charges were made.`);
14780
13295
  }
14781
13296
  } catch (e) {
14782
- console.error(`Checkout error: ${e.message}`);
14783
- process.exit(1);
13297
+ throw new Error(`Checkout error: ${e.message}`, { cause: e });
14784
13298
  }
14785
13299
  }
14786
13300
  async function runSubManage() {
@@ -14818,8 +13332,7 @@ Current plan: ${formatTier(balance.tier)}`);
14818
13332
  await postSubscriptionCancel();
14819
13333
  console.log("\nSubscription cancelled. You retain access until the end of your billing period.");
14820
13334
  } catch (e) {
14821
- console.error(`Cancel failed: ${e.message}`);
14822
- process.exit(1);
13335
+ throw new Error(`Cancel failed: ${e.message}`, { cause: e });
14823
13336
  }
14824
13337
  }
14825
13338
  var init_sub = __esm({
@@ -14885,8 +13398,7 @@ Payment confirmed. New balance: ${formatCredits(balance.fuel_credits)} (${format
14885
13398
  Checkout ${result.state}. No charges were made.`);
14886
13399
  }
14887
13400
  } catch (e) {
14888
- console.error(`Checkout error: ${e.message}`);
14889
- process.exit(1);
13401
+ throw new Error(`Checkout error: ${e.message}`, { cause: e });
14890
13402
  }
14891
13403
  }
14892
13404
  async function runTopupAuto() {
@@ -14894,8 +13406,7 @@ async function runTopupAuto() {
14894
13406
  try {
14895
13407
  balance = await fetchBalance();
14896
13408
  } catch (e) {
14897
- console.error(`Error fetching settings: ${e.message}`);
14898
- process.exit(1);
13409
+ throw new Error(`Error fetching settings: ${e.message}`, { cause: e });
14899
13410
  }
14900
13411
  const at = balance.auto_topup;
14901
13412
  console.log("\n--- Auto-Topup Settings ---");
@@ -14920,8 +13431,7 @@ async function runTopupAuto() {
14920
13431
  const amount = parseFloat(amountStr);
14921
13432
  const cap = parseFloat(capStr);
14922
13433
  if (isNaN(threshold) || isNaN(amount) || isNaN(cap)) {
14923
- console.error("Invalid values \u2014 no changes made.");
14924
- process.exit(1);
13434
+ throw new Error("Invalid values \u2014 no changes made.");
14925
13435
  }
14926
13436
  try {
14927
13437
  await patchAutoTopup({
@@ -14932,8 +13442,7 @@ async function runTopupAuto() {
14932
13442
  });
14933
13443
  console.log("Auto-topup settings updated.");
14934
13444
  } catch (e) {
14935
- console.error(`Update failed: ${e.message}`);
14936
- process.exit(1);
13445
+ throw new Error(`Update failed: ${e.message}`, { cause: e });
14937
13446
  }
14938
13447
  }
14939
13448
  var init_topup = __esm({
@@ -14954,8 +13463,7 @@ __export(redeem_exports, {
14954
13463
  async function runRedeem(argv) {
14955
13464
  const code = (argv[0] ?? "").trim().toUpperCase();
14956
13465
  if (!code) {
14957
- console.error("Usage: msapling gift redeem <code> (e.g. MSAPL-GIFT-ABCD-EFGH)");
14958
- process.exit(1);
13466
+ throw new Error("Usage: msapling gift redeem <code> (e.g. MSAPL-GIFT-ABCD-EFGH)");
14959
13467
  }
14960
13468
  try {
14961
13469
  const result = await postGiftRedeem(code);
@@ -14965,8 +13473,7 @@ async function runRedeem(argv) {
14965
13473
  console.log(`Could not apply gift: ${result.message}`);
14966
13474
  }
14967
13475
  } catch (e) {
14968
- console.error(`Redeem failed: ${e.message}`);
14969
- process.exit(1);
13476
+ throw new Error(`Redeem failed: ${e.message}`, { cause: e });
14970
13477
  }
14971
13478
  }
14972
13479
  var init_redeem = __esm({
@@ -14987,20 +13494,18 @@ async function runGift(argv) {
14987
13494
  if (subCmd === "sub") return runGiftSub(argv.slice(1));
14988
13495
  if (subCmd === "credits") return runGiftCredits(argv.slice(1));
14989
13496
  if (subCmd === "redeem") return runRedeem(argv.slice(1));
14990
- console.error("Usage: msapling gift sub <user> | credits <user> <5|10> | redeem <code>");
14991
- process.exit(1);
13497
+ throw new Error("Usage: msapling gift sub <user> | credits <user> <5|10> | redeem <code>");
14992
13498
  }
14993
13499
  async function _resolveRecipient(username) {
14994
13500
  const clean = username.replace(/^@/, "");
14995
13501
  try {
14996
13502
  const user = await fetchUserLookup(clean);
14997
13503
  if (user === null) {
14998
- console.error(`User @${clean} not found.`);
14999
- process.exit(1);
13504
+ throw new Error(`User @${clean} not found.`);
15000
13505
  }
15001
13506
  } catch (e) {
15002
- console.error(`User lookup failed: ${e.message}`);
15003
- process.exit(1);
13507
+ if (e.message?.startsWith("User @")) throw e;
13508
+ throw new Error(`User lookup failed: ${e.message}`, { cause: e });
15004
13509
  }
15005
13510
  return clean;
15006
13511
  }
@@ -15013,14 +13518,12 @@ async function _giftMethodMenu() {
15013
13518
  rl.close();
15014
13519
  if (choice === "1") return "direct";
15015
13520
  if (choice === "2") return "code";
15016
- console.error("Invalid choice.");
15017
- process.exit(1);
13521
+ throw new Error("Invalid choice.");
15018
13522
  }
15019
13523
  async function runGiftSub(argv) {
15020
13524
  const usernameRaw = argv[0] ?? "";
15021
13525
  if (!usernameRaw) {
15022
- console.error("Usage: msapling gift sub <username|@username>");
15023
- process.exit(1);
13526
+ throw new Error("Usage: msapling gift sub <username|@username>");
15024
13527
  }
15025
13528
  const recipient = await _resolveRecipient(usernameRaw);
15026
13529
  console.log(`
@@ -15058,21 +13561,18 @@ Payment confirmed. Gift code will be emailed to you shortly.`);
15058
13561
  Checkout ${result.state}. No charges were made.`);
15059
13562
  }
15060
13563
  } catch (e) {
15061
- console.error(`Gift checkout error: ${e.message}`);
15062
- process.exit(1);
13564
+ throw new Error(`Gift checkout error: ${e.message}`, { cause: e });
15063
13565
  }
15064
13566
  }
15065
13567
  async function runGiftCredits(argv) {
15066
13568
  const usernameRaw = argv[0] ?? "";
15067
13569
  const countStr = argv[1] ?? "";
15068
13570
  if (!usernameRaw || !countStr) {
15069
- console.error("Usage: msapling gift credits <username|@username> <5|10>");
15070
- process.exit(1);
13571
+ throw new Error("Usage: msapling gift credits <username|@username> <5|10>");
15071
13572
  }
15072
13573
  const count = parseInt(countStr, 10);
15073
13574
  if (count !== 5 && count !== 10) {
15074
- console.error("Credit amount must be 5 or 10.");
15075
- process.exit(1);
13575
+ throw new Error("Credit amount must be 5 or 10.");
15076
13576
  }
15077
13577
  const recipient = await _resolveRecipient(usernameRaw);
15078
13578
  const product = `gift_fuel_${count}`;
@@ -15112,8 +13612,7 @@ Payment confirmed. Gift code will be emailed to you shortly.`);
15112
13612
  Checkout ${result.state}. No charges were made.`);
15113
13613
  }
15114
13614
  } catch (e) {
15115
- console.error(`Gift checkout error: ${e.message}`);
15116
- process.exit(1);
13615
+ throw new Error(`Gift checkout error: ${e.message}`, { cause: e });
15117
13616
  }
15118
13617
  }
15119
13618
  var init_gift = __esm({
@@ -15142,8 +13641,7 @@ async function dispatchBillingCommand(cmd, argv) {
15142
13641
  return runGift(argv);
15143
13642
  default: {
15144
13643
  const _exhaustive = cmd;
15145
- console.error(`Unknown billing command: ${_exhaustive}`);
15146
- process.exit(1);
13644
+ throw new Error(`Unknown billing command: ${_exhaustive}`);
15147
13645
  }
15148
13646
  }
15149
13647
  }
@@ -15237,7 +13735,7 @@ __export(doctor_exports, {
15237
13735
  });
15238
13736
  import { homedir as homedir21, platform as platform4, tmpdir } from "os";
15239
13737
  import { join as join36 } from "path";
15240
- import { existsSync as existsSync32, statSync as statSync6 } from "fs";
13738
+ import { existsSync as existsSync33, statSync as statSync6 } from "fs";
15241
13739
  import { readdir as readdir3, mkdir as mkdir9, rm as rm3 } from "fs/promises";
15242
13740
  import { exec } from "child_process";
15243
13741
  import { promisify } from "util";
@@ -15261,7 +13759,7 @@ async function checkNodeVersion() {
15261
13759
  }
15262
13760
  async function checkConfigDir() {
15263
13761
  const configDir = join36(homedir21(), ".msapling");
15264
- if (!existsSync32(configDir)) {
13762
+ if (!existsSync33(configDir)) {
15265
13763
  return {
15266
13764
  name: "Config directory",
15267
13765
  status: "WARN",
@@ -15298,28 +13796,29 @@ async function checkConfigDir() {
15298
13796
  }
15299
13797
  async function checkKeytar() {
15300
13798
  try {
15301
- const keytar = await import("keytar");
15302
- if (keytar && typeof keytar.getPassword === "function") {
13799
+ const mod = await import("@napi-rs/keyring/keytar.js");
13800
+ const keyring = mod && typeof mod.getPassword === "function" ? mod : mod?.default ?? mod;
13801
+ if (keyring && typeof keyring.getPassword === "function") {
15303
13802
  return {
15304
- name: "Keytar native binary",
13803
+ name: "Keyring native binary",
15305
13804
  status: "PASS",
15306
- message: "Keytar loadable and functional"
13805
+ message: "@napi-rs/keyring loadable and functional"
15307
13806
  };
15308
13807
  }
15309
13808
  } catch (e) {
15310
13809
  const msg = e instanceof Error ? e.message : String(e);
15311
13810
  return {
15312
- name: "Keytar native binary",
13811
+ name: "Keyring native binary",
15313
13812
  status: "WARN",
15314
- message: `Keytar unavailable: ${msg}`,
15315
- remediation: `Token will be stored in plaintext. Run 'npm rebuild keytar' or 'bun install --force' to rebuild native bindings.`
13813
+ message: `@napi-rs/keyring unavailable: ${msg}`,
13814
+ remediation: `Token will be stored in plaintext. Run 'bun install' or 'npm install' to restore the @napi-rs/keyring prebuilt binary.`
15316
13815
  };
15317
13816
  }
15318
13817
  return {
15319
- name: "Keytar native binary",
13818
+ name: "Keyring native binary",
15320
13819
  status: "WARN",
15321
- message: "Keytar check inconclusive",
15322
- remediation: `Run 'npm rebuild keytar' or 'bun install --force' to rebuild native bindings.`
13820
+ message: "Keyring check inconclusive",
13821
+ remediation: `Run 'bun install' or 'npm install' to restore the @napi-rs/keyring prebuilt binary.`
15323
13822
  };
15324
13823
  }
15325
13824
  async function checkPathConflicts() {
@@ -15329,7 +13828,7 @@ async function checkPathConflicts() {
15329
13828
  const timedOutDirs = [];
15330
13829
  const DIR_TIMEOUT_MS = 1500;
15331
13830
  for (const dir of paths) {
15332
- if (!dir || !existsSync32(dir)) continue;
13831
+ if (!dir || !existsSync33(dir)) continue;
15333
13832
  try {
15334
13833
  const files = await Promise.race([
15335
13834
  readdir3(dir),
@@ -15422,7 +13921,8 @@ async function checkNetworkReach() {
15422
13921
  }
15423
13922
  async function checkTokenValidity() {
15424
13923
  try {
15425
- const keytar = await import("keytar");
13924
+ const mod = await import("@napi-rs/keyring/keytar.js");
13925
+ const keytar = mod && typeof mod.getPassword === "function" ? mod : mod?.default ?? mod;
15426
13926
  const KEYCHAIN_SERVICE3 = "msapling-cli";
15427
13927
  const KEYCHAIN_ACCOUNT3 = "auth_token";
15428
13928
  const token = await keytar.getPassword(KEYCHAIN_SERVICE3, KEYCHAIN_ACCOUNT3);
@@ -15517,11 +14017,11 @@ async function checkOsSpecific() {
15517
14017
  }
15518
14018
  if (platform4() === "linux") {
15519
14019
  try {
15520
- await import("keytar");
14020
+ await import("@napi-rs/keyring/keytar.js");
15521
14021
  return {
15522
14022
  name: "OS-specific (Linux)",
15523
14023
  status: "PASS",
15524
- message: "libsecret/keytar dependencies available"
14024
+ message: "libsecret/@napi-rs/keyring dependencies available"
15525
14025
  };
15526
14026
  } catch (e) {
15527
14027
  return {
@@ -15579,8 +14079,8 @@ async function runDoctor(debug = false) {
15579
14079
  checks.push(await checkTokenValidity());
15580
14080
  checks.push(await checkOsSpecific());
15581
14081
  const maxLabelWidth = Math.max(...checks.map((c) => c.name.length));
15582
- for (const check of checks) {
15583
- output.push(formatCheckResult(check, maxLabelWidth));
14082
+ for (const check2 of checks) {
14083
+ output.push(formatCheckResult(check2, maxLabelWidth));
15584
14084
  }
15585
14085
  output.push("");
15586
14086
  output.push("\u2500".repeat(60));
@@ -16004,10 +14504,10 @@ var init_local_tools = __esm({
16004
14504
  }
16005
14505
  });
16006
14506
 
16007
- // ../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/diff/base.js
14507
+ // ../../node_modules/diff/libesm/diff/base.js
16008
14508
  var Diff;
16009
14509
  var init_base = __esm({
16010
- "../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/diff/base.js"() {
14510
+ "../../node_modules/diff/libesm/diff/base.js"() {
16011
14511
  "use strict";
16012
14512
  init_esm_shims();
16013
14513
  Diff = class {
@@ -16213,7 +14713,7 @@ var init_base = __esm({
16213
14713
  }
16214
14714
  });
16215
14715
 
16216
- // ../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/util/string.js
14716
+ // ../../node_modules/diff/libesm/util/string.js
16217
14717
  function hasOnlyWinLineEndings(string) {
16218
14718
  return string.includes("\r\n") && !string.startsWith("\n") && !string.match(/[^\r]\n/);
16219
14719
  }
@@ -16221,13 +14721,13 @@ function hasOnlyUnixLineEndings(string) {
16221
14721
  return !string.includes("\r\n") && string.includes("\n");
16222
14722
  }
16223
14723
  var init_string = __esm({
16224
- "../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/util/string.js"() {
14724
+ "../../node_modules/diff/libesm/util/string.js"() {
16225
14725
  "use strict";
16226
14726
  init_esm_shims();
16227
14727
  }
16228
14728
  });
16229
14729
 
16230
- // ../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/diff/line.js
14730
+ // ../../node_modules/diff/libesm/diff/line.js
16231
14731
  function diffLines(oldStr, newStr, options) {
16232
14732
  return lineDiff.diff(oldStr, newStr, options);
16233
14733
  }
@@ -16251,7 +14751,7 @@ function tokenize(value, options) {
16251
14751
  }
16252
14752
  var LineDiff, lineDiff;
16253
14753
  var init_line = __esm({
16254
- "../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/diff/line.js"() {
14754
+ "../../node_modules/diff/libesm/diff/line.js"() {
16255
14755
  "use strict";
16256
14756
  init_esm_shims();
16257
14757
  init_base();
@@ -16283,7 +14783,7 @@ var init_line = __esm({
16283
14783
  }
16284
14784
  });
16285
14785
 
16286
- // ../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/patch/line-endings.js
14786
+ // ../../node_modules/diff/libesm/patch/line-endings.js
16287
14787
  function unixToWin(patch) {
16288
14788
  if (Array.isArray(patch)) {
16289
14789
  return patch.map((p) => unixToWin(p));
@@ -16315,13 +14815,13 @@ function isWin(patch) {
16315
14815
  })));
16316
14816
  }
16317
14817
  var init_line_endings = __esm({
16318
- "../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/patch/line-endings.js"() {
14818
+ "../../node_modules/diff/libesm/patch/line-endings.js"() {
16319
14819
  "use strict";
16320
14820
  init_esm_shims();
16321
14821
  }
16322
14822
  });
16323
14823
 
16324
- // ../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/patch/parse.js
14824
+ // ../../node_modules/diff/libesm/patch/parse.js
16325
14825
  function parsePatch(uniDiff) {
16326
14826
  const diffstr = uniDiff.split(/\n/), list2 = [];
16327
14827
  let i = 0;
@@ -16657,13 +15157,13 @@ function parsePatch(uniDiff) {
16657
15157
  return list2;
16658
15158
  }
16659
15159
  var init_parse = __esm({
16660
- "../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/patch/parse.js"() {
15160
+ "../../node_modules/diff/libesm/patch/parse.js"() {
16661
15161
  "use strict";
16662
15162
  init_esm_shims();
16663
15163
  }
16664
15164
  });
16665
15165
 
16666
- // ../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/util/distance-iterator.js
15166
+ // ../../node_modules/diff/libesm/util/distance-iterator.js
16667
15167
  function distance_iterator_default(start, minLine, maxLine) {
16668
15168
  let wantForward = true, backwardExhausted = false, forwardExhausted = false, localOffset = 1;
16669
15169
  return function iterator() {
@@ -16692,13 +15192,13 @@ function distance_iterator_default(start, minLine, maxLine) {
16692
15192
  };
16693
15193
  }
16694
15194
  var init_distance_iterator = __esm({
16695
- "../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/util/distance-iterator.js"() {
15195
+ "../../node_modules/diff/libesm/util/distance-iterator.js"() {
16696
15196
  "use strict";
16697
15197
  init_esm_shims();
16698
15198
  }
16699
15199
  });
16700
15200
 
16701
- // ../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/patch/apply.js
15201
+ // ../../node_modules/diff/libesm/patch/apply.js
16702
15202
  function applyPatch(source, patch, options = {}) {
16703
15203
  let patches;
16704
15204
  if (typeof patch === "string") {
@@ -16847,7 +15347,7 @@ function applyStructuredPatch(source, patch, options = {}) {
16847
15347
  return resultLines.join("\n");
16848
15348
  }
16849
15349
  var init_apply = __esm({
16850
- "../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/patch/apply.js"() {
15350
+ "../../node_modules/diff/libesm/patch/apply.js"() {
16851
15351
  "use strict";
16852
15352
  init_esm_shims();
16853
15353
  init_string();
@@ -16857,7 +15357,7 @@ var init_apply = __esm({
16857
15357
  }
16858
15358
  });
16859
15359
 
16860
- // ../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/patch/create.js
15360
+ // ../../node_modules/diff/libesm/patch/create.js
16861
15361
  function needsQuoting(s) {
16862
15362
  for (let i = 0; i < s.length; i++) {
16863
15363
  if (s[i] < " " || s[i] > "~" || s[i] === '"' || s[i] === "\\") {
@@ -17115,7 +15615,7 @@ function splitLines(text) {
17115
15615
  }
17116
15616
  var INCLUDE_HEADERS;
17117
15617
  var init_create = __esm({
17118
- "../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/patch/create.js"() {
15618
+ "../../node_modules/diff/libesm/patch/create.js"() {
17119
15619
  "use strict";
17120
15620
  init_esm_shims();
17121
15621
  init_line();
@@ -17127,9 +15627,9 @@ var init_create = __esm({
17127
15627
  }
17128
15628
  });
17129
15629
 
17130
- // ../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/index.js
15630
+ // ../../node_modules/diff/libesm/index.js
17131
15631
  var init_libesm = __esm({
17132
- "../../node_modules/.bun/diff@9.0.0/node_modules/diff/libesm/index.js"() {
15632
+ "../../node_modules/diff/libesm/index.js"() {
17133
15633
  "use strict";
17134
15634
  init_esm_shims();
17135
15635
  init_apply();
@@ -17139,7 +15639,7 @@ var init_libesm = __esm({
17139
15639
 
17140
15640
  // ../core/src/mcp/catalog.ts
17141
15641
  import { readdirSync as readdirSync4, readFileSync as readFileSync3, statSync as statSync7 } from "fs";
17142
- import { join as join37, relative as relative14 } from "path";
15642
+ import { join as join37, relative as relative15 } from "path";
17143
15643
  function buildFileTree(root, maxFiles) {
17144
15644
  const SKIP_DIRS2 = /* @__PURE__ */ new Set(["node_modules", ".git", "build", "dist", ".venv", "venv", ".next", "__pycache__", ".dart_tool", ".bun", "target"]);
17145
15645
  const SOURCE_EXT = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".py", ".go", ".rs", ".java", ".kt", ".swift", ".dart", ".rb", ".cs", ".cpp", ".c", ".h", ".md", ".json", ".yaml", ".yml", ".toml", ".sh", ".sql"]);
@@ -17185,7 +15685,7 @@ function readFilesAsContext(root, files, maxKB) {
17185
15685
  continue;
17186
15686
  }
17187
15687
  if (body.length > cap) body = body.slice(0, cap) + "\n[...truncated]";
17188
- const rel = relative14(root, f).replace(/\\/g, "/");
15688
+ const rel = relative15(root, f).replace(/\\/g, "/");
17189
15689
  parts.push(`### ${rel}
17190
15690
 
17191
15691
  \`\`\`
@@ -17595,8 +16095,38 @@ var server_exports = {};
17595
16095
  __export(server_exports, {
17596
16096
  MCPServer: () => MCPServer,
17597
16097
  runStdio: () => runStdio,
17598
- runStdioWithRegistry: () => runStdioWithRegistry
16098
+ runStdioWithRegistry: () => runStdioWithRegistry,
16099
+ safeStdoutWrite: () => safeStdoutWrite
17599
16100
  });
16101
+ function safeStdoutWrite(frame) {
16102
+ if (stdoutBroken) return false;
16103
+ try {
16104
+ process.stdout.write(frame);
16105
+ return true;
16106
+ } catch (e) {
16107
+ if (e?.code === "EPIPE") {
16108
+ stdoutBroken = true;
16109
+ process.stderr.write("[mcp-server] stdout pipe closed (EPIPE); shutting down.\n");
16110
+ setImmediate(() => process.exit(0));
16111
+ return false;
16112
+ }
16113
+ process.stderr.write(`[mcp-server] stdout write error: ${e?.message ?? e}
16114
+ `);
16115
+ return false;
16116
+ }
16117
+ }
16118
+ function installStdoutErrorHandler() {
16119
+ process.stdout.on("error", (e) => {
16120
+ if (e?.code === "EPIPE") {
16121
+ stdoutBroken = true;
16122
+ process.stderr.write("[mcp-server] stdout pipe closed (EPIPE, async); shutting down.\n");
16123
+ process.exit(0);
16124
+ } else {
16125
+ process.stderr.write(`[mcp-server] stdout error: ${e?.message ?? e}
16126
+ `);
16127
+ }
16128
+ });
16129
+ }
17600
16130
  function installDrainHandlers(server) {
17601
16131
  const abort = new AbortController();
17602
16132
  let drainStarted = false;
@@ -17607,10 +16137,7 @@ function installDrainHandlers(server) {
17607
16137
  `);
17608
16138
  server.drain().then((forcedResponses) => {
17609
16139
  for (const resp of forcedResponses) {
17610
- try {
17611
- process.stdout.write(JSON.stringify(resp) + "\n");
17612
- } catch {
17613
- }
16140
+ safeStdoutWrite(JSON.stringify(resp) + "\n");
17614
16141
  }
17615
16142
  process.stderr.write("[mcp-server] drain complete, exiting\n");
17616
16143
  abort.abort();
@@ -17635,7 +16162,7 @@ async function readStdinLoop(server, abort) {
17635
16162
  try {
17636
16163
  const req = JSON.parse(line);
17637
16164
  const resp = await server.handle(req);
17638
- if (resp) process.stdout.write(JSON.stringify(resp) + "\n");
16165
+ if (resp) safeStdoutWrite(JSON.stringify(resp) + "\n");
17639
16166
  } catch (e) {
17640
16167
  process.stderr.write(`[mcp-server] frame error: ${e?.message}
17641
16168
  `);
@@ -17645,15 +16172,17 @@ async function readStdinLoop(server, abort) {
17645
16172
  }
17646
16173
  async function runStdio(client) {
17647
16174
  const server = new MCPServer(client);
16175
+ installStdoutErrorHandler();
17648
16176
  const abort = installDrainHandlers(server);
17649
16177
  await readStdinLoop(server, abort);
17650
16178
  }
17651
16179
  async function runStdioWithRegistry(client, registryClient) {
17652
16180
  const server = new MCPServer(client, registryClient || client);
16181
+ installStdoutErrorHandler();
17653
16182
  const abort = installDrainHandlers(server);
17654
16183
  await readStdinLoop(server, abort);
17655
16184
  }
17656
- var MCPServer;
16185
+ var MCPServer, stdoutBroken;
17657
16186
  var init_server = __esm({
17658
16187
  "../core/src/mcp/server.ts"() {
17659
16188
  "use strict";
@@ -17903,6 +16432,7 @@ var init_server = __esm({
17903
16432
  return asResult2(JSON.stringify(result, null, 2));
17904
16433
  }
17905
16434
  };
16435
+ stdoutBroken = false;
17906
16436
  if (typeof Bun !== "undefined" && import.meta.main) {
17907
16437
  const apiUrl = process.env.MSAPLING_API_URL;
17908
16438
  const token = process.env.MSAPLING_TOKEN;
@@ -17922,7 +16452,7 @@ import { render } from "ink";
17922
16452
 
17923
16453
  // src/App.tsx
17924
16454
  init_esm_shims();
17925
- import { useState as useState3, useEffect as useEffect3, useCallback, useRef } from "react";
16455
+ import { useState as useState4, useEffect as useEffect4, useCallback as useCallback2, useRef } from "react";
17926
16456
  import { Box as Box7, Text as Text8, useApp, useStdout } from "ink";
17927
16457
 
17928
16458
  // src/components/Header.tsx
@@ -17932,7 +16462,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
17932
16462
  var Header = () => /* @__PURE__ */ jsxs(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [
17933
16463
  /* @__PURE__ */ jsxs(Text, { bold: true, color: "cyan", children: [
17934
16464
  "\u25CF MSapling CLI v",
17935
- "2.3.6-beta.42"
16465
+ "2.3.6-beta.44"
17936
16466
  ] }),
17937
16467
  /* @__PURE__ */ jsx(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx(Text, { color: "gray", children: "Platinum Tier Architecture" }) })
17938
16468
  ] });
@@ -18328,6 +16858,7 @@ function createIdleAwarePoll(pollingIntervalRef, lastActivityRef, client, setUse
18328
16858
  const liveUser = await client.getLiveUsage();
18329
16859
  setUser(liveUser);
18330
16860
  } catch (e) {
16861
+ console.debug(`[polling] live usage refresh failed: ${e instanceof Error ? e.message : String(e)}`);
18331
16862
  }
18332
16863
  }, POLL_INTERVAL_MS2);
18333
16864
  }
@@ -18342,13 +16873,13 @@ import { spawn as spawn9 } from "child_process";
18342
16873
  init_esm_shims();
18343
16874
  import { homedir as homedir19 } from "os";
18344
16875
  import { join as join34, dirname as dirname5 } from "path";
18345
- import { existsSync as existsSync29, mkdirSync as mkdirSync6 } from "fs";
16876
+ import { existsSync as existsSync30, mkdirSync as mkdirSync6 } from "fs";
18346
16877
  import { readFile as readFile27, writeFile as writeFile17, rename as rename3 } from "fs/promises";
18347
- import { randomBytes as randomBytes13 } from "crypto";
16878
+ import { randomBytes as randomBytes14 } from "crypto";
18348
16879
  var STATE_PATH = join34(homedir19(), ".msapling", "state.json");
18349
16880
  async function loadPersistentState(statePath = STATE_PATH) {
18350
16881
  try {
18351
- if (!existsSync29(statePath)) return { version: 1 };
16882
+ if (!existsSync30(statePath)) return { version: 1 };
18352
16883
  const text = await readFile27(statePath, "utf8");
18353
16884
  const parsed = JSON.parse(text);
18354
16885
  if (parsed.version !== 1) return { version: 1 };
@@ -18364,7 +16895,7 @@ async function loadPersistentState(statePath = STATE_PATH) {
18364
16895
  async function savePersistentState(state, statePath = STATE_PATH) {
18365
16896
  try {
18366
16897
  const dir = dirname5(statePath);
18367
- if (!existsSync29(dir)) mkdirSync6(dir, { recursive: true });
16898
+ if (!existsSync30(dir)) mkdirSync6(dir, { recursive: true });
18368
16899
  const existing = await loadPersistentState(statePath);
18369
16900
  const merged = {
18370
16901
  version: 1,
@@ -18372,7 +16903,7 @@ async function savePersistentState(state, statePath = STATE_PATH) {
18372
16903
  lastChatId: state.lastChatId ?? existing.lastChatId
18373
16904
  };
18374
16905
  const pid = process.pid;
18375
- const rand = randomBytes13(4).toString("hex");
16906
+ const rand = randomBytes14(4).toString("hex");
18376
16907
  const tmp = `${statePath}.tmp.${pid}.${rand}`;
18377
16908
  await writeFile17(tmp, JSON.stringify(merged, null, 2), "utf8");
18378
16909
  await rename3(tmp, statePath);
@@ -18491,7 +17022,19 @@ ${prompt4}` : prompt4;
18491
17022
  let chatId = ctx.activeChatId;
18492
17023
  if (!chatId) {
18493
17024
  const overview = await ctx.client.me();
18494
- chatId = overview.active_locks[0]?.chat_id || "default-chat";
17025
+ chatId = overview.active_locks[0]?.chat_id;
17026
+ if (!chatId) {
17027
+ const currentProj = ctx.getProjectId() || "Default Project";
17028
+ const project = overview.projects.find((p) => p.id === currentProj) ?? overview.projects[0];
17029
+ const result = await ctx.client.createChat({
17030
+ projectName: project?.name || "Default Project",
17031
+ title: cmd.slice(0, 30) + (cmd.length > 30 ? "..." : ""),
17032
+ model: ctx.activeModel
17033
+ });
17034
+ chatId = result.chat_id;
17035
+ ctx.setActiveChatId(chatId);
17036
+ ctx.addMessage("system", `Created new chat automatically: ${result.title}`);
17037
+ }
18495
17038
  }
18496
17039
  let finalCmd = cmd;
18497
17040
  const fileMentions = finalCmd.match(/@(\S+)/g);
@@ -18499,9 +17042,9 @@ ${prompt4}` : prompt4;
18499
17042
  for (const mention of fileMentions) {
18500
17043
  const filePath = mention.slice(1);
18501
17044
  try {
18502
- const { existsSync: existsSync33 } = await import("fs");
17045
+ const { existsSync: existsSync34 } = await import("fs");
18503
17046
  const { readFile: readFile30 } = await import("fs/promises");
18504
- if (existsSync33(filePath)) {
17047
+ if (existsSync34(filePath)) {
18505
17048
  const content = await readFile30(filePath, "utf8");
18506
17049
  const MAX_LEN = 32768;
18507
17050
  const truncated = content.length > MAX_LEN ? content.slice(0, MAX_LEN) + "\n...[TRUNCATED]" : content;
@@ -18532,6 +17075,8 @@ ${finalCmd}`;
18532
17075
  } catch (e) {
18533
17076
  if (e.message.includes("423")) {
18534
17077
  ctx.addMessage("error", "Error: Chat is locked. Use /unlock to hijack.");
17078
+ } else if (e?.status === 401 || e.message.includes("401") || /unauthor/i.test(e.message)) {
17079
+ ctx.addMessage("error", "Session expired - run /login");
18535
17080
  } else {
18536
17081
  ctx.addMessage("error", `Error: ${e.message}`);
18537
17082
  }
@@ -18558,10 +17103,22 @@ ${finalCmd}`;
18558
17103
  // src/state/initSession.ts
18559
17104
  init_esm_shims();
18560
17105
  init_src3();
17106
+ init_src();
18561
17107
  init_parseApprovalMode();
18562
17108
  import { readFile as readFile28 } from "fs/promises";
18563
- import { existsSync as existsSync30 } from "fs";
17109
+ import { existsSync as existsSync31 } from "fs";
18564
17110
  async function initSession(ctx) {
17111
+ try {
17112
+ const journalEncrypted = await initJournalEncryption();
17113
+ if (!journalEncrypted) {
17114
+ ctx.addMessage(
17115
+ "system",
17116
+ "\u26A0 Offline journal encryption unavailable (OS keychain unreachable). Offline messages will NOT be persisted to disk to avoid storing chat content in plaintext."
17117
+ );
17118
+ }
17119
+ } catch (e) {
17120
+ ctx.addMessage("system", `\u26A0 Journal encryption init failed: ${e?.message ?? e}`);
17121
+ }
18565
17122
  try {
18566
17123
  const { settings } = await loadSettings(
18567
17124
  process.cwd(),
@@ -18577,7 +17134,7 @@ async function initSession(ctx) {
18577
17134
  const { homedir: homedir22 } = await import("os");
18578
17135
  const { join: join39 } = await import("path");
18579
17136
  const userSettingsPath = join39(homedir22(), ".msapling", "settings.json");
18580
- if (existsSync30(userSettingsPath)) {
17137
+ if (existsSync31(userSettingsPath)) {
18581
17138
  const userText = await readFile28(userSettingsPath, "utf8");
18582
17139
  let parsed;
18583
17140
  try {
@@ -18647,8 +17204,19 @@ async function initSession(ctx) {
18647
17204
  }
18648
17205
  const token = await ctx.storage.loadToken();
18649
17206
  if (token) {
18650
- ctx.client.setToken(token);
18651
- await ctx.refreshOverview();
17207
+ const claims = decodeJwtClaims(token);
17208
+ const expired = claims && typeof claims.exp === "number" && claims.exp * 1e3 <= Date.now();
17209
+ if (expired) {
17210
+ try {
17211
+ await ctx.storage.clearToken();
17212
+ } catch {
17213
+ }
17214
+ ctx.client.setToken("");
17215
+ ctx.setStatus("Session expired - run /login");
17216
+ } else {
17217
+ ctx.client.setToken(token);
17218
+ await ctx.refreshOverview();
17219
+ }
18652
17220
  } else {
18653
17221
  ctx.setStatus("Login required: /login <token>");
18654
17222
  }
@@ -18664,30 +17232,60 @@ async function initSession(ctx) {
18664
17232
  }
18665
17233
  }
18666
17234
 
17235
+ // src/hooks/useTerminalResize.ts
17236
+ init_esm_shims();
17237
+ import { useState as useState3, useEffect as useEffect3, useCallback } from "react";
17238
+ function getCurrentDimensions() {
17239
+ return {
17240
+ columns: process.stdout.columns ?? 80,
17241
+ rows: process.stdout.rows ?? 24
17242
+ };
17243
+ }
17244
+ function useTerminalResize() {
17245
+ const [dimensions, setDimensions] = useState3(
17246
+ getCurrentDimensions
17247
+ );
17248
+ const handleResize = useCallback(() => {
17249
+ setDimensions(getCurrentDimensions());
17250
+ }, []);
17251
+ useEffect3(() => {
17252
+ process.stdout.on("resize", handleResize);
17253
+ const onSigwinch = () => handleResize();
17254
+ process.on("SIGWINCH", onSigwinch);
17255
+ handleResize();
17256
+ return () => {
17257
+ process.stdout.off("resize", handleResize);
17258
+ process.off("SIGWINCH", onSigwinch);
17259
+ };
17260
+ }, [handleResize]);
17261
+ return dimensions;
17262
+ }
17263
+
18667
17264
  // src/App.tsx
18668
17265
  import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
18669
17266
  var App = ({ compact: compact2 = false }) => {
18670
- const [user, setUser] = useState3(null);
18671
- const [input, setInput] = useState3("");
18672
- const [history, setHistory] = useState3([]);
18673
- const [isRunning, setIsRunning] = useState3(false);
18674
- const [status2, setStatus] = useState3("Initializing...");
18675
- const [activeChatId, setActiveChatId] = useState3(null);
18676
- const [activeProjectId, setActiveProjectId] = useState3(null);
18677
- const [mode, setModeState] = useState3("default");
18678
- const [activeModel, setActiveModel] = useState3("google/gemini-2.0-flash-001");
18679
- const [lastCost, setLastCost] = useState3(0);
18680
- const [sessionCost, setSessionCost] = useState3(0);
18681
- const [pendingApproval, setPendingApproval] = useState3(null);
18682
- const [swarmWorkers, setSwarmWorkers] = useState3(null);
18683
- const [activePlan, setActivePlan] = useState3(null);
18684
- const [contextBudgetSnap, setContextBudgetSnap] = useState3(null);
18685
- const [shellEscapeEnabled, setShellEscapeEnabled] = useState3(true);
17267
+ const [user, setUser] = useState4(null);
17268
+ const [input, setInput] = useState4("");
17269
+ const [history, setHistory] = useState4([]);
17270
+ const [isRunning, setIsRunning] = useState4(false);
17271
+ const [status2, setStatus] = useState4("Initializing...");
17272
+ const [activeChatId, setActiveChatId] = useState4(null);
17273
+ const [activeProjectId, setActiveProjectId] = useState4(null);
17274
+ const [mode, setModeState] = useState4("default");
17275
+ const [activeModel, setActiveModel] = useState4("google/gemini-2.0-flash-001");
17276
+ const [lastCost, setLastCost] = useState4(0);
17277
+ const [sessionCost, setSessionCost] = useState4(0);
17278
+ const [pendingApproval, setPendingApproval] = useState4(null);
17279
+ const [swarmWorkers, setSwarmWorkers] = useState4(null);
17280
+ const [activePlan, setActivePlan] = useState4(null);
17281
+ const [contextBudgetSnap, setContextBudgetSnap] = useState4(null);
17282
+ const [shellEscapeEnabled, setShellEscapeEnabled] = useState4(true);
18686
17283
  const { exit } = useApp();
18687
17284
  const { stdout: termStdout } = useStdout();
17285
+ const { columns: termResizeCols, rows: termResizeRows } = useTerminalResize();
18688
17286
  const storage = useRef(new StorageManager()).current;
18689
17287
  const client = useRef(new MSaplingClient()).current;
18690
- const requestApproval = useCallback((request) => {
17288
+ const requestApproval = useCallback2((request) => {
18691
17289
  return new Promise((resolve20) => {
18692
17290
  setPendingApproval({ request, resolve: resolve20 });
18693
17291
  });
@@ -18696,38 +17294,47 @@ var App = ({ compact: compact2 = false }) => {
18696
17294
  const trustStore = useRef(new TrustStore()).current;
18697
17295
  const lastActivityRef = useRef(Date.now());
18698
17296
  const pollingIntervalRef = useRef(null);
18699
- useEffect3(() => {
17297
+ useEffect4(() => {
18700
17298
  agent.setApprovalCallback(requestApproval);
18701
17299
  }, [agent, requestApproval]);
18702
- const resolveApproval = useCallback((decision) => {
17300
+ const resolveApproval = useCallback2((decision) => {
18703
17301
  setPendingApproval((current) => {
18704
17302
  current?.resolve(decision);
18705
17303
  return null;
18706
17304
  });
18707
17305
  }, []);
18708
- const addMessage = useCallback((role, content) => {
17306
+ const addMessage = useCallback2((role, content) => {
18709
17307
  setHistory((prev) => [...prev, { role, content }]);
18710
17308
  }, []);
18711
- const clearHistory = useCallback(() => {
17309
+ const clearHistory = useCallback2(() => {
18712
17310
  setHistory([]);
18713
17311
  }, []);
18714
- const setMode = useCallback((m) => {
17312
+ const setMode = useCallback2((m) => {
18715
17313
  setModeState(m);
18716
17314
  agent.setMode(m);
18717
17315
  }, [agent]);
18718
- const getMode = useCallback(() => mode, [mode]);
18719
- const setModel = useCallback((m) => {
17316
+ const getMode = useCallback2(() => mode, [mode]);
17317
+ const setModel = useCallback2((m) => {
18720
17318
  setActiveModel(m);
18721
17319
  }, []);
18722
- const getModel = useCallback(() => activeModel, [activeModel]);
18723
- const setProjectId = useCallback((id) => {
17320
+ const getModel = useCallback2(() => activeModel, [activeModel]);
17321
+ const setProjectId = useCallback2((id) => {
18724
17322
  setActiveProjectId(id);
18725
17323
  agent.setProjectId(id);
18726
17324
  }, [agent]);
18727
- const getProjectId = useCallback(() => activeProjectId, [activeProjectId]);
18728
- const getPlan = useCallback(() => activePlan, [activePlan]);
18729
- const setPlan = useCallback((steps) => setActivePlan(steps), []);
18730
- const refreshOverview = useCallback(async () => {
17325
+ const getProjectId = useCallback2(() => activeProjectId, [activeProjectId]);
17326
+ const getPlan = useCallback2(() => activePlan, [activePlan]);
17327
+ const setPlan = useCallback2((steps) => setActivePlan(steps), []);
17328
+ const handle401 = useCallback2(async () => {
17329
+ setUser(null);
17330
+ try {
17331
+ await storage.clearToken();
17332
+ } catch {
17333
+ }
17334
+ client.setToken("");
17335
+ setStatus("Session expired - run /login");
17336
+ }, [client, storage]);
17337
+ const refreshOverview = useCallback2(async () => {
18731
17338
  try {
18732
17339
  const overview = await client.me();
18733
17340
  setUser(overview.user);
@@ -18743,10 +17350,14 @@ var App = ({ compact: compact2 = false }) => {
18743
17350
  setStatus("No active chat. Use /chat <id> or send a message.");
18744
17351
  }
18745
17352
  } catch (e) {
17353
+ if (e?.status === 401) {
17354
+ await handle401();
17355
+ return;
17356
+ }
18746
17357
  setStatus(`Auth required: ${e.message}`);
18747
17358
  }
18748
- }, [client, activeChatId, activeProjectId, setProjectId]);
18749
- useEffect3(() => {
17359
+ }, [client, activeChatId, activeProjectId, setProjectId, handle401]);
17360
+ useEffect4(() => {
18750
17361
  initSession({
18751
17362
  agent,
18752
17363
  client,
@@ -18763,7 +17374,7 @@ var App = ({ compact: compact2 = false }) => {
18763
17374
  setActiveChatId
18764
17375
  });
18765
17376
  }, []);
18766
- useEffect3(() => {
17377
+ useEffect4(() => {
18767
17378
  if (!user) return;
18768
17379
  createIdleAwarePoll(pollingIntervalRef, lastActivityRef, client, setUser);
18769
17380
  return () => {
@@ -18818,8 +17429,8 @@ var App = ({ compact: compact2 = false }) => {
18818
17429
  updateAssistantMessage,
18819
17430
  shellEscapeEnabled
18820
17431
  });
18821
- const termHeight = termStdout?.rows ?? 24;
18822
- const termColumns = termStdout?.columns ?? 80;
17432
+ const termHeight = termResizeRows ?? termStdout?.rows ?? 24;
17433
+ const termColumns = termResizeCols ?? termStdout?.columns ?? 80;
18823
17434
  const visibleLines = Math.max(termHeight - 10, 5);
18824
17435
  return /* @__PURE__ */ jsxs7(Box7, { flexDirection: "column", padding: 1, children: [
18825
17436
  /* @__PURE__ */ jsx8(Header, {}),
@@ -19008,6 +17619,30 @@ function handleCliArgs(args2) {
19008
17619
  // src/index.tsx
19009
17620
  import { jsx as jsx9 } from "react/jsx-runtime";
19010
17621
  var index_default = App;
17622
+ function restoreTerminalMode() {
17623
+ try {
17624
+ const stdin = process.stdin;
17625
+ if (stdin?.isTTY && typeof stdin.setRawMode === "function") {
17626
+ stdin.setRawMode(false);
17627
+ }
17628
+ if (process.stdout.isTTY) process.stdout.write("\x1B[?25h");
17629
+ } catch {
17630
+ }
17631
+ }
17632
+ var crashHandled = false;
17633
+ function handleFatal(label, err) {
17634
+ if (crashHandled) return;
17635
+ crashHandled = true;
17636
+ restoreTerminalMode();
17637
+ const msg = err instanceof Error ? err.message : String(err);
17638
+ console.error(`
17639
+ msapling: fatal ${label}: ${msg}`);
17640
+ process.exit(1);
17641
+ }
17642
+ if (!process.env.NODE_ENV?.includes("test")) {
17643
+ process.on("uncaughtException", (err) => handleFatal("uncaught exception", err));
17644
+ process.on("unhandledRejection", (reason) => handleFatal("unhandled rejection", reason));
17645
+ }
19011
17646
  var args = process.argv.slice(2);
19012
17647
  var compact = args.includes("--compact");
19013
17648
  var shouldRenderRepl = handleCliArgs(args);