@acprompt/join 0.1.8 → 0.1.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/auth/paths.ts"],"names":[],"mappings":"AAMA,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAWjD;AAED,yEAAyE;AACzE,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAWvF"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/auth/paths.ts"],"names":[],"mappings":"AAOA,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAWjD;AAED,yEAAyE;AACzE,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAevF"}
@@ -2,6 +2,7 @@
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { promises as fs } from "node:fs";
5
+ import { writeFileAtomic } from "../util/atomic-write.js";
5
6
  export function acpromptDir() {
6
7
  return path.join(os.homedir(), ".acprompt");
7
8
  }
@@ -34,7 +35,11 @@ export async function ensureDir() {
34
35
  export async function writeSecureJson(filePath, payload) {
35
36
  await ensureDir();
36
37
  const body = JSON.stringify(payload, null, 2);
37
- await fs.writeFile(filePath, body, { encoding: "utf8", mode: 0o600 });
38
+ // R33 — atomic (temp file + rename). A torn write here leaves a truncated
39
+ // config.json, which reads as "not logged in" and silently discards the
40
+ // stored agent identity. Mode is applied to the temp file, so the secret is
41
+ // never world-readable even for an instant.
42
+ await writeFileAtomic(filePath, body, { mode: 0o600 });
38
43
  if (process.platform !== "win32") {
39
44
  try {
40
45
  await fs.chmod(filePath, 0o600);
@@ -1 +1 @@
1
- {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/auth/paths.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAEhD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,eAAe,CAAC,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;IAC1B,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,gEAAgE;QAClE,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAgB;IACtE,MAAM,SAAS,EAAE,CAAC;IAClB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9C,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/auth/paths.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAEhD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,aAAa,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,eAAe,CAAC,CAAC;AACnD,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS;IAC7B,MAAM,GAAG,GAAG,WAAW,EAAE,CAAC;IAC1B,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,gEAAgE;QAClE,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB,EAAE,OAAgB;IACtE,MAAM,SAAS,EAAE,CAAC;IAClB,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9C,0EAA0E;IAC1E,wEAAwE;IACxE,4EAA4E;IAC5E,4CAA4C;IAC5C,MAAM,eAAe,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACvD,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -1,4 +1,15 @@
1
1
  import type { DetectionContext, HarnessDetector } from "./types.js";
2
2
  export declare function claudeDesktopConfigPath(ctx: DetectionContext): string;
3
+ /**
4
+ * The command we probe for the Claude Code CLI on every platform.
5
+ *
6
+ * R33 — Windows used to probe `claude.cmd` specifically. That only matches the
7
+ * npm-installed shim; the NATIVE Windows installer ships `claude.exe` (no .cmd),
8
+ * so the probe failed for a correctly installed CLI and `acprompt-join` told a
9
+ * native-install user "Claude Code CLI not on PATH". Probing the bare `claude`
10
+ * through the shell (see below) lets cmd.exe resolve either `claude.cmd` or
11
+ * `claude.exe` via PATHEXT. Exported so the regression is pinned by a test.
12
+ */
13
+ export declare function claudeCliProbe(_platform: NodeJS.Platform): string;
3
14
  export declare const claudeCodeDetector: HarnessDetector;
4
15
  //# sourceMappingURL=claude-code.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/detect/claude-code.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EACV,gBAAgB,EAEhB,eAAe,EAChB,MAAM,YAAY,CAAC;AAIpB,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAiBrE;AAoCD,eAAO,MAAM,kBAAkB,EAAE,eAkChC,CAAC"}
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/detect/claude-code.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EACV,gBAAgB,EAEhB,eAAe,EAChB,MAAM,YAAY,CAAC;AAIpB,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAiBrE;AAWD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,GAAG,MAAM,CAEjE;AA6BD,eAAO,MAAM,kBAAkB,EAAE,eAkChC,CAAC"}
@@ -39,22 +39,37 @@ async function fileExists(p) {
39
39
  return false;
40
40
  }
41
41
  }
42
+ /**
43
+ * The command we probe for the Claude Code CLI on every platform.
44
+ *
45
+ * R33 — Windows used to probe `claude.cmd` specifically. That only matches the
46
+ * npm-installed shim; the NATIVE Windows installer ships `claude.exe` (no .cmd),
47
+ * so the probe failed for a correctly installed CLI and `acprompt-join` told a
48
+ * native-install user "Claude Code CLI not on PATH". Probing the bare `claude`
49
+ * through the shell (see below) lets cmd.exe resolve either `claude.cmd` or
50
+ * `claude.exe` via PATHEXT. Exported so the regression is pinned by a test.
51
+ */
52
+ export function claudeCliProbe(_platform) {
53
+ return "claude";
54
+ }
42
55
  async function claudeCliOnPath(ctx) {
43
56
  // `claude --version` is the cheapest way to confirm the CLI exists.
44
57
  // Swallow every error — if it's not installed, the CLI simply isn't there.
45
58
  //
46
59
  // Windows-specific: on Node 24 (CVE-2024-27980 hardening), spawning a
47
60
  // `.cmd` file without `shell: true` is rejected unconditionally with
48
- // EINVAL. The old code would catch that and report "no CLI" — a
49
- // false-negative on every Windows-Node-24 install that actually HAS
50
- // Claude Code CLI. We pass `shell: true` on win32 to stay compatible
51
- // across Node 20/22/24. Safe against the F7-class cmd.exe argv-
52
- // splitting trap because the only arg is the literal `--version`,
53
- // containing no whitespace or shell metacharacters.
54
- const probe = ctx.platform === "win32" ? "claude.cmd" : "claude";
61
+ // EINVAL. We pass `shell: true` on win32 to stay compatible across Node
62
+ // 20/22/24. Safe against the F7-class cmd.exe argv-splitting trap because
63
+ // the only arg is the literal `--version`, containing no whitespace or
64
+ // shell metacharacters.
65
+ //
66
+ // R33 — `env: ctx.env` is deliberate, not cosmetic: without it the probe
67
+ // used the PROCESS environment regardless of the context, so a caller (or a
68
+ // test) that supplied a controlled PATH still hit the developer's real PATH.
69
+ const probe = claudeCliProbe(ctx.platform);
55
70
  const opts = ctx.platform === "win32"
56
- ? { timeout: 3000, shell: true }
57
- : { timeout: 3000 };
71
+ ? { timeout: 3000, shell: true, env: ctx.env, windowsHide: true }
72
+ : { timeout: 3000, env: ctx.env };
58
73
  try {
59
74
  await execFileAsync(probe, ["--version"], opts);
60
75
  return true;
@@ -1 +1 @@
1
- {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/detect/claude-code.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/detect/claude-code.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,20 @@
1
1
  import { type HarnessInstaller } from "./shared.js";
2
+ /**
3
+ * Pinned mcp-remote version.
4
+ *
5
+ * R33 — `npx -y mcp-remote` resolved to "whatever is latest at install time",
6
+ * so an upstream release could silently change behavior months after we wrote
7
+ * the config (the shape below depends on a specific documented-in-code behavior:
8
+ * `${VAR}` expansion of header values). Pinned so the config a user gets is
9
+ * reproducible; bump deliberately, then re-run scripts/probe-mcp-remote.mjs
10
+ * against the real endpoint before shipping.
11
+ *
12
+ * Verified 2026-10-31 (R33): 0.15.2 still expands `${VAR}` in header values —
13
+ * dist substituteEnvVars() is applied to every parsed header before the
14
+ * transport is built. If a bump ever removes that, every Claude Desktop config
15
+ * we wrote starts 401ing with a literal "${ACP_MCP_AUTH}" header.
16
+ */
17
+ export declare const MCP_REMOTE_SPEC = "mcp-remote@0.15.2";
2
18
  /**
3
19
  * Build the Claude-Desktop-compatible MCP server entry for ACPrompt. See
4
20
  * the file-top comment for why this shape (and not `{type:"http",...}`)
@@ -1 +1 @@
1
- {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/install/claude-code.ts"],"names":[],"mappings":"AA8CA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGvE;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAc1B;AAuBD,eAAO,MAAM,mBAAmB,EAAE,gBA4CjC,CAAC"}
1
+ {"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../src/install/claude-code.ts"],"names":[],"mappings":"AA8CA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIvE;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,sBAAsB,CAAC;AAEnD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAc1B;AAyBD,eAAO,MAAM,mBAAmB,EAAE,gBA4CjC,CAAC"}
@@ -44,7 +44,24 @@ import pc from "picocolors";
44
44
  import { promises as fs } from "node:fs";
45
45
  import path from "node:path";
46
46
  import { readMergeableJson } from "./shared.js";
47
+ import { writeJsonAtomic } from "../util/atomic-write.js";
47
48
  import { claudeDesktopConfigPath } from "../detect/claude-code.js";
49
+ /**
50
+ * Pinned mcp-remote version.
51
+ *
52
+ * R33 — `npx -y mcp-remote` resolved to "whatever is latest at install time",
53
+ * so an upstream release could silently change behavior months after we wrote
54
+ * the config (the shape below depends on a specific documented-in-code behavior:
55
+ * `${VAR}` expansion of header values). Pinned so the config a user gets is
56
+ * reproducible; bump deliberately, then re-run scripts/probe-mcp-remote.mjs
57
+ * against the real endpoint before shipping.
58
+ *
59
+ * Verified 2026-10-31 (R33): 0.15.2 still expands `${VAR}` in header values —
60
+ * dist substituteEnvVars() is applied to every parsed header before the
61
+ * transport is built. If a bump ever removes that, every Claude Desktop config
62
+ * we wrote starts 401ing with a literal "${ACP_MCP_AUTH}" header.
63
+ */
64
+ export const MCP_REMOTE_SPEC = "mcp-remote@0.15.2";
48
65
  /**
49
66
  * Build the Claude-Desktop-compatible MCP server entry for ACPrompt. See
50
67
  * the file-top comment for why this shape (and not `{type:"http",...}`)
@@ -56,7 +73,7 @@ export function buildClaudeDesktopEntry(opts) {
56
73
  command: "npx",
57
74
  args: [
58
75
  "-y",
59
- "mcp-remote",
76
+ MCP_REMOTE_SPEC,
60
77
  opts.mcpUrl,
61
78
  "--header",
62
79
  "Authorization:${ACP_MCP_AUTH}",
@@ -81,7 +98,9 @@ async function mergeConfig(configPath, entry) {
81
98
  const servers = (current.mcpServers ?? {});
82
99
  servers["acprompt"] = entry;
83
100
  current.mcpServers = servers;
84
- await fs.writeFile(configPath, JSON.stringify(current, null, 2), "utf8");
101
+ // R33 — atomic: a torn write here destroys every other MCP server the
102
+ // user had configured. See src/util/atomic-write.ts.
103
+ await writeJsonAtomic(configPath, current);
85
104
  }
86
105
  export const claudeCodeInstaller = async (ic) => {
87
106
  const wrote = [];
@@ -1 +1 @@
1
- {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/install/claude-code.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/install/claude-code.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"letta.d.ts","sourceRoot":"","sources":["../../src/install/letta.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGvE,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED,eAAO,MAAM,cAAc,EAAE,gBAmB5B,CAAC"}
1
+ {"version":3,"file":"letta.d.ts","sourceRoot":"","sources":["../../src/install/letta.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAIvE,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAmBf;AAED,eAAO,MAAM,cAAc,EAAE,gBAmB5B,CAAC"}
@@ -18,6 +18,7 @@ import pc from "picocolors";
18
18
  import { promises as fs } from "node:fs";
19
19
  import path from "node:path";
20
20
  import { readMergeableJson } from "./shared.js";
21
+ import { writeJsonAtomic } from "../util/atomic-write.js";
21
22
  import { lettaMcpConfigPath } from "../detect/letta.js";
22
23
  export async function writeLettaMcpConfig(configPath, mcpUrl, token) {
23
24
  // See comment in claude-code.ts::mergeConfig — readMergeableJson is the
@@ -36,7 +37,8 @@ export async function writeLettaMcpConfig(configPath, mcpUrl, token) {
36
37
  headers: { Authorization: `Bearer ${token}` },
37
38
  };
38
39
  current.mcpServers = servers;
39
- await fs.writeFile(configPath, JSON.stringify(current, null, 2), "utf8");
40
+ // R33 — atomic write; see src/util/atomic-write.ts.
41
+ await writeJsonAtomic(configPath, current);
40
42
  }
41
43
  export const lettaInstaller = async (ic) => {
42
44
  const configPath = ic.detection.configTargets?.[0] ??
@@ -1 +1 @@
1
- {"version":3,"file":"letta.js","sourceRoot":"","sources":["../../src/install/letta.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,EAAE;AACF,sEAAsE;AACtE,uEAAuE;AACvE,mEAAmE;AACnE,yCAAyC;AACzC,EAAE;AACF,MAAM;AACN,sBAAsB;AACtB,sBAAsB;AACtB,0CAA0C;AAC1C,qDAAqD;AACrD,2DAA2D;AAC3D,UAAU;AACV,QAAQ;AACR,MAAM;AAEN,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAyB,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,UAAkB,EAClB,MAAc,EACd,KAAa;IAEb,wEAAwE;IACxE,mEAAmE;IACnE,sEAAsE;IACtE,6CAA6C;IAC7C,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,QAAQ,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAA4B,CAAC;IACtE,OAAO,CAAC,UAAU,CAAC,GAAG;QACpB,SAAS,EAAE,iBAAiB;QAC5B,GAAG,EAAE,MAAM;QACX,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;KAC9C,CAAC;IACF,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC;IAC7B,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAqB,KAAK,EAAE,EAAE,EAAE,EAAE;IAC3D,MAAM,UAAU,GACd,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAC/B,kBAAkB,CAAC;YACjB,GAAG,EAAE,EAAE,CAAC,IAAI;YACZ,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;IAEL,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;QACf,MAAM,mBAAmB,CAAC,UAAU,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,sCAAsC,UAAU,GAAG,CAAC,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CACT,EAAE,CAAC,GAAG,CAAC,gEAAgE,CAAC,CACzE,CAAC;IAEF,OAAO,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC9C,CAAC,CAAC"}
1
+ {"version":3,"file":"letta.js","sourceRoot":"","sources":["../../src/install/letta.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,EAAE;AACF,sEAAsE;AACtE,uEAAuE;AACvE,mEAAmE;AACnE,yCAAyC;AACzC,EAAE;AACF,MAAM;AACN,sBAAsB;AACtB,sBAAsB;AACtB,0CAA0C;AAC1C,qDAAqD;AACrD,2DAA2D;AAC3D,UAAU;AACV,QAAQ;AACR,MAAM;AAEN,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAyB,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,UAAkB,EAClB,MAAc,EACd,KAAa;IAEb,wEAAwE;IACxE,mEAAmE;IACnE,sEAAsE;IACtE,6CAA6C;IAC7C,MAAM,QAAQ,GAAG,MAAM,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,QAAQ,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,UAAU,IAAI,EAAE,CAA4B,CAAC;IACtE,OAAO,CAAC,UAAU,CAAC,GAAG;QACpB,SAAS,EAAE,iBAAiB;QAC5B,GAAG,EAAE,MAAM;QACX,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE;KAC9C,CAAC;IACF,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC;IAC7B,oDAAoD;IACpD,MAAM,eAAe,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAqB,KAAK,EAAE,EAAE,EAAE,EAAE;IAC3D,MAAM,UAAU,GACd,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAC/B,kBAAkB,CAAC;YACjB,GAAG,EAAE,EAAE,CAAC,IAAI;YACZ,IAAI,EAAE,EAAE,CAAC,IAAI;YACb,QAAQ,EAAE,EAAE,CAAC,QAAQ;YACrB,GAAG,EAAE,OAAO,CAAC,GAAG;SACjB,CAAC,CAAC;IAEL,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;QACf,MAAM,mBAAmB,CAAC,UAAU,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IAC7D,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,sCAAsC,UAAU,GAAG,CAAC,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CACT,EAAE,CAAC,GAAG,CAAC,gEAAgE,CAAC,CACzE,CAAC;IAEF,OAAO,EAAE,KAAK,EAAE,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AAC9C,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface AtomicWriteOptions {
2
+ /** File mode for the temp file (e.g. 0o600 for secrets). */
3
+ mode?: number;
4
+ }
5
+ export declare function writeFileAtomic(targetPath: string, data: string, opts?: AtomicWriteOptions): Promise<void>;
6
+ /** JSON convenience wrapper: pretty-print then write atomically. */
7
+ export declare function writeJsonAtomic(targetPath: string, value: unknown, opts?: AtomicWriteOptions): Promise<void>;
8
+ //# sourceMappingURL=atomic-write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.d.ts","sourceRoot":"","sources":["../../src/util/atomic-write.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,kBAAkB;IACjC,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAyCf;AAED,oEAAoE;AACpE,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,OAAO,EACd,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAEf"}
@@ -0,0 +1,58 @@
1
+ // Atomic file write — serialize to a sibling temp file, fsync, rename over
2
+ // the target.
3
+ //
4
+ // Why this exists: several installers merge our entry into a config file the
5
+ // user already owns (Claude Desktop's claude_desktop_config.json, Letta's mcp
6
+ // config, ~/.acprompt/config.json). A plain `fs.writeFile` truncates the target
7
+ // first and then streams the new bytes in, so a crash, a full disk, a killed
8
+ // process, or a Windows antivirus/OneDrive lock in the middle of that window
9
+ // leaves a HALF-WRITTEN file. For a merged config that means the user's other
10
+ // MCP servers are gone; for the token store it means auth silently breaks.
11
+ //
12
+ // rename(2) within one directory is atomic, so the target is always either the
13
+ // complete old file or the complete new one.
14
+ import { promises as fs } from "node:fs";
15
+ import path from "node:path";
16
+ import { randomBytes } from "node:crypto";
17
+ export async function writeFileAtomic(targetPath, data, opts = {}) {
18
+ const dir = path.dirname(targetPath);
19
+ const tmpPath = path.join(dir, `.${path.basename(targetPath)}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`);
20
+ let handle;
21
+ try {
22
+ handle = await fs.open(tmpPath, "w", opts.mode ?? 0o644);
23
+ await handle.writeFile(data, "utf8");
24
+ // Flush to disk before the rename, otherwise a power loss can leave the
25
+ // renamed (empty) file behind on some filesystems.
26
+ await handle.sync();
27
+ }
28
+ finally {
29
+ await handle?.close();
30
+ }
31
+ // Windows: rename over an existing file fails with EPERM/EBUSY while another
32
+ // process (editor, antivirus, sync client) holds a handle. Retry briefly —
33
+ // these are almost always short-lived — then fail loudly with the real cause.
34
+ const attempts = process.platform === "win32" ? 5 : 1;
35
+ let lastErr;
36
+ for (let i = 0; i < attempts; i++) {
37
+ try {
38
+ await fs.rename(tmpPath, targetPath);
39
+ return;
40
+ }
41
+ catch (err) {
42
+ lastErr = err;
43
+ const code = err.code;
44
+ if (code !== "EPERM" && code !== "EBUSY" && code !== "EACCES")
45
+ break;
46
+ await new Promise((r) => setTimeout(r, 60 * (i + 1)));
47
+ }
48
+ }
49
+ // Never leave the temp fragment behind on failure.
50
+ await fs.rm(tmpPath, { force: true }).catch(() => undefined);
51
+ throw new Error(`Could not write ${targetPath} atomically: ${lastErr?.message ?? "unknown error"}. ` +
52
+ `The existing file was left untouched. Close any program holding it open and retry.`);
53
+ }
54
+ /** JSON convenience wrapper: pretty-print then write atomically. */
55
+ export async function writeJsonAtomic(targetPath, value, opts = {}) {
56
+ await writeFileAtomic(targetPath, JSON.stringify(value, null, 2), opts);
57
+ }
58
+ //# sourceMappingURL=atomic-write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atomic-write.js","sourceRoot":"","sources":["../../src/util/atomic-write.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,cAAc;AACd,EAAE;AACF,6EAA6E;AAC7E,8EAA8E;AAC9E,gFAAgF;AAChF,6EAA6E;AAC7E,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,EAAE;AACF,+EAA+E;AAC/E,6CAA6C;AAE7C,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO1C,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAkB,EAClB,IAAY,EACZ,OAA2B,EAAE;IAE7B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CACvB,GAAG,EACH,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,OAAO,CAAC,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CACrF,CAAC;IAEF,IAAI,MAAuD,CAAC;IAC5D,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC;QACzD,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACrC,wEAAwE;QACxE,mDAAmD;QACnD,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,EAAE,KAAK,EAAE,CAAC;IACxB,CAAC;IAED,6EAA6E;IAC7E,2EAA2E;IAC3E,8EAA8E;IAC9E,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,IAAI,OAAgB,CAAC;IACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,GAAG,GAAG,CAAC;YACd,MAAM,IAAI,GAAI,GAA6B,CAAC,IAAI,CAAC;YACjD,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,QAAQ;gBAAE,MAAM;YACrE,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,CAAC;IACH,CAAC;IAED,mDAAmD;IACnD,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAC7D,MAAM,IAAI,KAAK,CACb,mBAAmB,UAAU,gBAAiB,OAAiB,EAAE,OAAO,IAAI,eAAe,IAAI;QAC7F,oFAAoF,CACvF,CAAC;AACJ,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAkB,EAClB,KAAc,EACd,OAA2B,EAAE;IAE7B,MAAM,eAAe,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;AAC1E,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acprompt/join",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Smart installer for ACPrompt — one-shot MCP config for any agent harness.",
5
5
  "keywords": [
6
6
  "acprompt",