@acprompt/join 0.1.8 → 0.1.10

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 (45) hide show
  1. package/README.md +10 -2
  2. package/dist/auth/paths.d.ts.map +1 -1
  3. package/dist/auth/paths.js +6 -1
  4. package/dist/auth/paths.js.map +1 -1
  5. package/dist/commands/install.d.ts +33 -0
  6. package/dist/commands/install.d.ts.map +1 -1
  7. package/dist/commands/install.js +43 -9
  8. package/dist/commands/install.js.map +1 -1
  9. package/dist/detect/claude-code.d.ts +11 -0
  10. package/dist/detect/claude-code.d.ts.map +1 -1
  11. package/dist/detect/claude-code.js +24 -9
  12. package/dist/detect/claude-code.js.map +1 -1
  13. package/dist/detect/ide-apps.d.ts +26 -0
  14. package/dist/detect/ide-apps.d.ts.map +1 -0
  15. package/dist/detect/ide-apps.js +193 -0
  16. package/dist/detect/ide-apps.js.map +1 -0
  17. package/dist/detect/index.d.ts.map +1 -1
  18. package/dist/detect/index.js +6 -0
  19. package/dist/detect/index.js.map +1 -1
  20. package/dist/detect/which.d.ts +10 -0
  21. package/dist/detect/which.d.ts.map +1 -0
  22. package/dist/detect/which.js +55 -0
  23. package/dist/detect/which.js.map +1 -0
  24. package/dist/index.js +25 -2
  25. package/dist/index.js.map +1 -1
  26. package/dist/install/claude-code.d.ts +16 -0
  27. package/dist/install/claude-code.d.ts.map +1 -1
  28. package/dist/install/claude-code.js +21 -2
  29. package/dist/install/claude-code.js.map +1 -1
  30. package/dist/install/ide-apps.d.ts +8 -0
  31. package/dist/install/ide-apps.d.ts.map +1 -0
  32. package/dist/install/ide-apps.js +116 -0
  33. package/dist/install/ide-apps.js.map +1 -0
  34. package/dist/install/index.d.ts +10 -0
  35. package/dist/install/index.d.ts.map +1 -1
  36. package/dist/install/index.js +20 -0
  37. package/dist/install/index.js.map +1 -1
  38. package/dist/install/letta.d.ts.map +1 -1
  39. package/dist/install/letta.js +3 -1
  40. package/dist/install/letta.js.map +1 -1
  41. package/dist/util/atomic-write.d.ts +8 -0
  42. package/dist/util/atomic-write.d.ts.map +1 -0
  43. package/dist/util/atomic-write.js +58 -0
  44. package/dist/util/atomic-write.js.map +1 -0
  45. package/package.json +1 -1
package/README.md CHANGED
@@ -10,7 +10,7 @@ Smart installer for [ACPrompt](https://www.acprompt.com) — one command to wire
10
10
  npx @acprompt/join
11
11
  ```
12
12
 
13
- 1. Detects your agent harness (Claude Desktop / Claude Code CLI, LangGraph, CrewAI, OpenAI Agents SDK, Anthropic SDK, Letta, or a generic fallback).
13
+ 1. Detects your agent harness (Claude Desktop / Claude Code CLI, Cursor, WorkBuddy, Windsurf, Continue.dev, OpenClaw, Zed, LangGraph, CrewAI, OpenAI Agents SDK, Anthropic SDK, Letta, or a generic fallback).
14
14
  2. Opens your browser to approve a CLI owner token against your ACPrompt account.
15
15
  3. Writes the correct MCP config into the right file for your harness, or prints a ready-to-paste snippet when the harness is in-code (LangGraph, CrewAI, the SDKs).
16
16
  4. Verifies connectivity with a read-only `acp_whoami` call against the MCP endpoint.
@@ -41,8 +41,16 @@ npx @acprompt/join whoami # show stored owner + identity public key
41
41
  | OpenAI Agents SDK | yes | in-code (`new Agent({ mcpServers })`) | prints snippet (py+js) |
42
42
  | Anthropic SDK | yes | in-code (`mcp_servers` param on `messages.create`) | prints snippet (py+js) |
43
43
  | Letta | yes | `~/.letta/mcp_config.json` | auto-writes |
44
+ | Cursor | yes | `~/.cursor/mcp.json` | prints snippet (no `type` field) |
45
+ | WorkBuddy | yes | `~/.workbuddy/mcp.json` (**not** `.mcp.json`) | prints snippet (`type: http`) |
46
+ | Windsurf | yes | `~/.codeium/windsurf/mcp_config.json` | prints snippet |
47
+ | Continue.dev | yes | `~/.continue/config.json` | prints snippet |
48
+ | OpenClaw | yes | `~/.openclaw/openclaw.json` under `mcp.servers` | prints CLI command + snippet |
49
+ | Zed | yes | settings UI only (no config file) | prints the JSON to paste into the UI |
44
50
  | Generic fallback | yes | whatever your harness expects | prints raw endpoint + header |
45
51
 
52
+ If several harnesses are installed and the auto-pick is not the one you want, force it: `npx @acprompt/join --harness workbuddy` (or set `ACPROMPT_HARNESS`). Until v0.1.10 the six desktop apps above were not detected at all, even though `install.sh` already advertised them.
53
+
46
54
  Auto-write targets are merge-safe: existing siblings in the config file are preserved, Windows UTF-8-BOM inputs are handled, and an unparseable existing file aborts the write rather than clobbering it.
47
55
 
48
56
  ## Config & secrets
@@ -50,7 +58,7 @@ Auto-write targets are merge-safe: existing siblings in the config file are pres
50
58
  - Owner token: `~/.acprompt/config.json` (chmod 600 on unix, user-profile ACL on Windows).
51
59
  - Identity keypair: `~/.acprompt/identity.json` (same permissions).
52
60
  - For `claude-code` / `letta`, the Bearer token is written into the harness's config file in plaintext — that's how those harnesses consume it. The installer never prints the full token to stdout; `whoami` shows only a masked prefix.
53
- - Snippet installers (LangGraph / CrewAI / SDKs) do print the full token as part of the copy-paste snippet — unavoidable, since there's no config file to write into.
61
+ - Snippet installers (LangGraph / CrewAI / SDKs / Cursor / WorkBuddy / Windsurf / Continue / OpenClaw / Zed) do print the full token as part of the copy-paste snippet — unavoidable, since there's no config file to write into. The six desktop apps above deliberately do **not** auto-write: we know which JSON entry each one accepts, but not how to merge into every shape of their file safely, and a printed snippet cannot corrupt an existing config.
54
62
 
55
63
  ## Development
56
64
 
@@ -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,7 +1,40 @@
1
+ import { type DetectionResult } from "../detect/index.js";
1
2
  export interface InstallOptions {
2
3
  /** Skip all confirm prompts, accepting defaults. Required for non-TTY. */
3
4
  yes?: boolean;
5
+ /**
6
+ * Force a specific harness id instead of taking the first detection.
7
+ *
8
+ * Needed because detection is home-scoped for desktop apps: a developer with
9
+ * Claude Code, Cursor and WorkBuddy all installed would otherwise always be
10
+ * routed to whichever sits first in ALL_DETECTORS. `ACPROMPT_HARNESS` is
11
+ * honoured too, mirroring `install.sh`.
12
+ */
13
+ harness?: string;
4
14
  }
15
+ /** Harness ids are compared loosely: `claude_code` == `claude-code`. */
16
+ export declare function normalizeHarnessId(raw: string): string;
17
+ export interface HarnessPick {
18
+ picked?: DetectionResult;
19
+ /** True when the caller forced a harness that detection had no evidence for. */
20
+ forced?: boolean;
21
+ error?: string;
22
+ }
23
+ /**
24
+ * Decide which detection `install` acts on.
25
+ *
26
+ * Default behaviour is unchanged since v0.1.7: first detected entry wins,
27
+ * which is why the IDE-app detectors were appended after the existing ones.
28
+ *
29
+ * With an explicit override we trust the human over the filesystem. Forcing a
30
+ * harness that showed no evidence is allowed (the user may have a non-standard
31
+ * install path) but reported as `forced` so the caller can warn. An id that
32
+ * isn't in the registry is a hard error — silently falling back to `generic`
33
+ * there would look like the override worked when it didn't.
34
+ *
35
+ * Exported for testing: `runInstall` needs network + a token, this doesn't.
36
+ */
37
+ export declare function pickDetection(detections: readonly DetectionResult[], override?: string): HarnessPick;
5
38
  /**
6
39
  * Resolve a yes/no from the user.
7
40
  * - If `yes` is set, accept the default without prompting.
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,OAAO,EACrB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,OAAO,CAAC,CASlB;AAED,wBAAsB,UAAU,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4GzE"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAYA,OAAO,EAGL,KAAK,eAAe,EACrB,MAAM,oBAAoB,CAAC;AAO5B,MAAM,WAAW,cAAc;IAC7B,0EAA0E;IAC1E,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,gFAAgF;IAChF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,QAAQ,CAAC,EAAE,MAAM,GAChB,WAAW,CAgBb;AAED;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,OAAO,EACrB,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,OAAO,CAAC,CASlB;AAED,wBAAsB,UAAU,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkHzE"}
@@ -13,8 +13,41 @@ import { ALL_DETECTORS, currentContext, } from "../detect/index.js";
13
13
  import { runBrowserAuth } from "../auth/browser-flow.js";
14
14
  import { getToken, maskToken } from "../auth/token-store.js";
15
15
  import { loadOrCreateIdentity } from "../identity/keypair.js";
16
- import { getInstaller, DEFAULT_MCP_URL } from "../install/index.js";
16
+ import { getInstaller, DEFAULT_MCP_URL, FILE_WRITER_HARNESSES } from "../install/index.js";
17
17
  import { runVerify } from "./verify.js";
18
+ /** Harness ids are compared loosely: `claude_code` == `claude-code`. */
19
+ export function normalizeHarnessId(raw) {
20
+ return raw.trim().toLowerCase().replace(/_/g, "-");
21
+ }
22
+ /**
23
+ * Decide which detection `install` acts on.
24
+ *
25
+ * Default behaviour is unchanged since v0.1.7: first detected entry wins,
26
+ * which is why the IDE-app detectors were appended after the existing ones.
27
+ *
28
+ * With an explicit override we trust the human over the filesystem. Forcing a
29
+ * harness that showed no evidence is allowed (the user may have a non-standard
30
+ * install path) but reported as `forced` so the caller can warn. An id that
31
+ * isn't in the registry is a hard error — silently falling back to `generic`
32
+ * there would look like the override worked when it didn't.
33
+ *
34
+ * Exported for testing: `runInstall` needs network + a token, this doesn't.
35
+ */
36
+ export function pickDetection(detections, override) {
37
+ const known = detections.map((d) => d.harness).join(", ");
38
+ if (override && override.trim().length > 0) {
39
+ const want = normalizeHarnessId(override);
40
+ const hit = detections.find((d) => normalizeHarnessId(d.harness) === want);
41
+ if (!hit) {
42
+ return { error: `Unknown harness "${override}". Known ids: ${known}.` };
43
+ }
44
+ return { picked: hit, forced: !hit.detected };
45
+ }
46
+ const first = detections.find((d) => d.detected);
47
+ return first
48
+ ? { picked: first, forced: false }
49
+ : { error: "No harness detected." };
50
+ }
18
51
  /**
19
52
  * Resolve a yes/no from the user.
20
53
  * - If `yes` is set, accept the default without prompting.
@@ -39,13 +72,14 @@ export async function runInstall(opts = {}) {
39
72
  console.log("");
40
73
  const ctx = currentContext();
41
74
  const detections = await Promise.all(ALL_DETECTORS.map((d) => d.detect(ctx)));
42
- const best = detections.find((d) => d.detected);
43
- if (!best) {
44
- // Can't happen in practice: the generic detector always matches. We
45
- // still guard against it for defensive programming — a detector
46
- // throwing mid-Promise.all would otherwise leave us with nothing.
47
- console.log(pc.yellow("No harness detected."));
48
- return;
75
+ const override = opts.harness ?? process.env.ACPROMPT_HARNESS;
76
+ const pick = pickDetection(detections, override);
77
+ if (!pick.picked) {
78
+ throw new Error(pick.error ?? "No harness detected.");
79
+ }
80
+ const best = pick.picked;
81
+ if (pick.forced) {
82
+ console.log(pc.yellow(`--harness ${best.harness}: forced despite no detection evidence (${best.reason ?? "no reason recorded"}).`));
49
83
  }
50
84
  console.log(pc.green(`Detected: ${best.label}`));
51
85
  (best.evidence ?? []).forEach((e) => console.log(pc.dim(` ${e}`)));
@@ -86,7 +120,7 @@ export async function runInstall(opts = {}) {
86
120
  // Confirmation gates — writes always ask; snippets don't (printing is
87
121
  // read-only from the user's perspective).
88
122
  const installer = getInstaller(best.harness);
89
- const isFileWriter = best.harness === "claude-code" || best.harness === "letta";
123
+ const isFileWriter = FILE_WRITER_HARNESSES.has(best.harness);
90
124
  if (isFileWriter) {
91
125
  const target = best.configTargets?.[0] ?? "its default config path";
92
126
  const ok = await askYesNo(`Write ACPrompt MCP server entry into ${target}?`, true, opts);
@@ -1 +1 @@
1
- {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"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"}
@@ -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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"}
@@ -0,0 +1,26 @@
1
+ import type { DetectionContext, HarnessDetector } from "./types.js";
2
+ export declare function cursorConfigPath(ctx: DetectionContext): string;
3
+ export declare function workbuddyConfigPath(ctx: DetectionContext): string;
4
+ export declare function windsurfConfigPath(ctx: DetectionContext): string;
5
+ export declare function openclawConfigPath(ctx: DetectionContext): string;
6
+ export declare function continueConfigPath(ctx: DetectionContext): string;
7
+ export declare function zedConfigDir(ctx: DetectionContext): string;
8
+ export declare const cursorDetector: HarnessDetector;
9
+ export declare const workbuddyDetector: HarnessDetector;
10
+ export declare const windsurfDetector: HarnessDetector;
11
+ export declare const openclawDetector: HarnessDetector;
12
+ export declare const continueDetector: HarnessDetector;
13
+ export declare const zedDetector: HarnessDetector;
14
+ /**
15
+ * Every detector added in v0.1.10, in the order they are appended to
16
+ * `ALL_DETECTORS` (after the SDK harnesses, before `generic`).
17
+ *
18
+ * Ordering rationale: these are HOME-scoped signals ("the app is installed"),
19
+ * which is weaker evidence of intent than a repo dependency or a CLI the user
20
+ * just invoked. `install` picks the first detected harness, so putting them
21
+ * last keeps every pre-v0.1.10 selection decision byte-for-byte identical.
22
+ * Users who have several harnesses and want a specific one pass
23
+ * `--harness <id>`.
24
+ */
25
+ export declare const IDE_APP_DETECTORS: readonly HarnessDetector[];
26
+ //# sourceMappingURL=ide-apps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ide-apps.d.ts","sourceRoot":"","sources":["../../src/detect/ide-apps.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EACV,gBAAgB,EAEhB,eAAe,EAChB,MAAM,YAAY,CAAC;AAyCpB,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAE9D;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAKjE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAEhE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAEhE;AAED,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAEhE;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,gBAAgB,GAAG,MAAM,CAE1D;AAqED,eAAO,MAAM,cAAc,iBAOzB,CAAC;AAEH,eAAO,MAAM,iBAAiB,iBAQ5B,CAAC;AAEH,eAAO,MAAM,gBAAgB,iBAO3B,CAAC;AAEH,eAAO,MAAM,gBAAgB,iBAO3B,CAAC;AAEH,eAAO,MAAM,gBAAgB,iBAO3B,CAAC;AAEH,eAAO,MAAM,WAAW,iBAUtB,CAAC;AAEH;;;;;;;;;;GAUG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,eAAe,EAOvD,CAAC"}
@@ -0,0 +1,193 @@
1
+ // Desktop-IDE / desktop-agent harness detectors.
2
+ //
3
+ // These six harnesses all keep their MCP config in a per-user file (or, for
4
+ // Zed, only in its settings UI), so detection is "does that file / directory
5
+ // exist, or is the CLI on PATH". No process is spawned — see which.ts.
6
+ //
7
+ // Authoritative source for every path below: `acp/src/lib/harness-quirks.ts`
8
+ // (`HARNESS_CONFIG_TABLE`) and `acp/public/install.sh` (`case "$HARNESS"`),
9
+ // both of which were verified against real installs. Do not "improve" a path
10
+ // from memory — a wrong path means we tell the user to edit a file their
11
+ // harness never reads.
12
+ //
13
+ // Why these were missing until v0.1.10: the npm installer only ever carried
14
+ // detectors for claude-code + the Python/JS SDK harnesses, while
15
+ // `install.sh` already advertised `cursor, windsurf, zed, openclaw, continue,
16
+ // workbuddy` as auto-detectable. Users of those harnesses ran
17
+ // `npx @acprompt/join`, were told "No specific harness matched", and got a
18
+ // generic snippet instead of their real config path.
19
+ import { promises as fs } from "node:fs";
20
+ import path from "node:path";
21
+ import { findExecutableOnPath } from "./which.js";
22
+ async function fileExists(p) {
23
+ try {
24
+ const s = await fs.stat(p);
25
+ return s.isFile();
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ }
31
+ async function dirExists(p) {
32
+ try {
33
+ const s = await fs.stat(p);
34
+ return s.isDirectory();
35
+ }
36
+ catch {
37
+ return false;
38
+ }
39
+ }
40
+ // ---------------------------------------------------------------------------
41
+ // Paths. Exported so tests (and future installers) pin the exact strings.
42
+ // ---------------------------------------------------------------------------
43
+ export function cursorConfigPath(ctx) {
44
+ return path.join(ctx.home, ".cursor", "mcp.json");
45
+ }
46
+ export function workbuddyConfigPath(ctx) {
47
+ // NO leading dot on mcp.json. `~/.workbuddy/.mcp.json` is auto-generated by
48
+ // WorkBuddy as an internal connector-proxy descriptor; user config written
49
+ // there is overwritten on the next restart. Verified 2026-05-04.
50
+ return path.join(ctx.home, ".workbuddy", "mcp.json");
51
+ }
52
+ export function windsurfConfigPath(ctx) {
53
+ return path.join(ctx.home, ".codeium", "windsurf", "mcp_config.json");
54
+ }
55
+ export function openclawConfigPath(ctx) {
56
+ return path.join(ctx.home, ".openclaw", "openclaw.json");
57
+ }
58
+ export function continueConfigPath(ctx) {
59
+ return path.join(ctx.home, ".continue", "config.json");
60
+ }
61
+ export function zedConfigDir(ctx) {
62
+ return path.join(ctx.home, ".config", "zed");
63
+ }
64
+ // ---------------------------------------------------------------------------
65
+ // Factory
66
+ // ---------------------------------------------------------------------------
67
+ function makeIdeAppDetector(spec) {
68
+ return {
69
+ id: spec.id,
70
+ label: spec.label,
71
+ async detect(ctx) {
72
+ const configPath = spec.configPath(ctx);
73
+ const configTargets = configPath ? [configPath] : [];
74
+ try {
75
+ const evidence = [];
76
+ if (configPath && (await fileExists(configPath))) {
77
+ evidence.push(`${spec.label} MCP config: ${configPath}`);
78
+ }
79
+ for (const dir of spec.appDirs(ctx)) {
80
+ if (await dirExists(dir)) {
81
+ evidence.push(`${spec.label} app dir: ${dir}`);
82
+ }
83
+ }
84
+ const bin = await findExecutableOnPath(ctx, spec.binNames);
85
+ if (bin) {
86
+ evidence.push(`${spec.binNames.join("|")} on PATH: ${bin}`);
87
+ }
88
+ if (evidence.length === 0) {
89
+ return {
90
+ harness: spec.id,
91
+ label: spec.label,
92
+ detected: false,
93
+ reason: spec.missingReason,
94
+ configTargets,
95
+ };
96
+ }
97
+ return {
98
+ harness: spec.id,
99
+ label: spec.label,
100
+ detected: true,
101
+ evidence,
102
+ configTargets,
103
+ };
104
+ }
105
+ catch (e) {
106
+ // Detectors must never throw — a single failure would be swallowed by
107
+ // Promise.all's caller and could hide the whole report.
108
+ return {
109
+ harness: spec.id,
110
+ label: spec.label,
111
+ detected: false,
112
+ reason: e.message,
113
+ configTargets,
114
+ };
115
+ }
116
+ },
117
+ };
118
+ }
119
+ // ---------------------------------------------------------------------------
120
+ // The six detectors
121
+ // ---------------------------------------------------------------------------
122
+ export const cursorDetector = makeIdeAppDetector({
123
+ id: "cursor",
124
+ label: "Cursor",
125
+ configPath: cursorConfigPath,
126
+ appDirs: (ctx) => [path.join(ctx.home, ".cursor")],
127
+ binNames: ["cursor"],
128
+ missingReason: "No ~/.cursor/ directory and `cursor` not on PATH.",
129
+ });
130
+ export const workbuddyDetector = makeIdeAppDetector({
131
+ id: "workbuddy",
132
+ label: "WorkBuddy",
133
+ configPath: workbuddyConfigPath,
134
+ appDirs: (ctx) => [path.join(ctx.home, ".workbuddy")],
135
+ // `codebuddy` is the upstream product name the same installer ships under.
136
+ binNames: ["workbuddy", "codebuddy"],
137
+ missingReason: "No ~/.workbuddy/ directory and no workbuddy/codebuddy on PATH.",
138
+ });
139
+ export const windsurfDetector = makeIdeAppDetector({
140
+ id: "windsurf",
141
+ label: "Windsurf",
142
+ configPath: windsurfConfigPath,
143
+ appDirs: (ctx) => [path.join(ctx.home, ".codeium", "windsurf")],
144
+ binNames: ["windsurf"],
145
+ missingReason: "No ~/.codeium/windsurf/ directory and `windsurf` not on PATH.",
146
+ });
147
+ export const openclawDetector = makeIdeAppDetector({
148
+ id: "openclaw",
149
+ label: "OpenClaw",
150
+ configPath: openclawConfigPath,
151
+ appDirs: (ctx) => [path.join(ctx.home, ".openclaw")],
152
+ binNames: ["openclaw"],
153
+ missingReason: "No ~/.openclaw/ directory and `openclaw` not on PATH.",
154
+ });
155
+ export const continueDetector = makeIdeAppDetector({
156
+ id: "continue",
157
+ label: "Continue.dev",
158
+ configPath: continueConfigPath,
159
+ appDirs: (ctx) => [path.join(ctx.home, ".continue")],
160
+ binNames: ["continue"],
161
+ missingReason: "No ~/.continue/ directory and no `continue` on PATH.",
162
+ });
163
+ export const zedDetector = makeIdeAppDetector({
164
+ id: "zed",
165
+ label: "Zed",
166
+ // Zed's MCP servers are configured in its settings UI only; there is no
167
+ // file we can point the user at. Empty configTargets is intentional — the
168
+ // installer prints the JSON to paste into the UI instead of a path.
169
+ configPath: () => null,
170
+ appDirs: (ctx) => [zedConfigDir(ctx)],
171
+ binNames: ["zed"],
172
+ missingReason: "No ~/.config/zed/ directory and `zed` not on PATH.",
173
+ });
174
+ /**
175
+ * Every detector added in v0.1.10, in the order they are appended to
176
+ * `ALL_DETECTORS` (after the SDK harnesses, before `generic`).
177
+ *
178
+ * Ordering rationale: these are HOME-scoped signals ("the app is installed"),
179
+ * which is weaker evidence of intent than a repo dependency or a CLI the user
180
+ * just invoked. `install` picks the first detected harness, so putting them
181
+ * last keeps every pre-v0.1.10 selection decision byte-for-byte identical.
182
+ * Users who have several harnesses and want a specific one pass
183
+ * `--harness <id>`.
184
+ */
185
+ export const IDE_APP_DETECTORS = [
186
+ cursorDetector,
187
+ workbuddyDetector,
188
+ windsurfDetector,
189
+ zedDetector,
190
+ openclawDetector,
191
+ continueDetector,
192
+ ];
193
+ //# sourceMappingURL=ide-apps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ide-apps.js","sourceRoot":"","sources":["../../src/detect/ide-apps.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detect/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AASpE,eAAO,MAAM,aAAa,EAAE,SAAS,eAAe,EAQnD,CAAC;AAEF,wBAAgB,cAAc,IAAI,gBAAgB,CAOjD;AAED,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/detect/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAcpE,eAAO,MAAM,aAAa,EAAE,SAAS,eAAe,EASnD,CAAC;AAEF,wBAAgB,cAAc,IAAI,gBAAgB,CAOjD;AAED,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
@@ -6,7 +6,12 @@ import { crewaiDetector } from "./crewai.js";
6
6
  import { openaiAgentsDetector } from "./openai-agents.js";
7
7
  import { anthropicSdkDetector } from "./anthropic-sdk.js";
8
8
  import { lettaDetector } from "./letta.js";
9
+ import { IDE_APP_DETECTORS } from "./ide-apps.js";
9
10
  import { genericDetector } from "./generic.js";
11
+ // Order matters twice over:
12
+ // 1. More specific (cwd-scoped) evidence first, `generic` last.
13
+ // 2. `install` picks the FIRST detected entry, so appending to the end
14
+ // preserves every pre-v0.1.10 selection when several harnesses match.
10
15
  export const ALL_DETECTORS = [
11
16
  claudeCodeDetector,
12
17
  langgraphDetector,
@@ -14,6 +19,7 @@ export const ALL_DETECTORS = [
14
19
  openaiAgentsDetector,
15
20
  anthropicSdkDetector,
16
21
  lettaDetector,
22
+ ...IDE_APP_DETECTORS,
17
23
  genericDetector,
18
24
  ];
19
25
  export function currentContext() {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/detect/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAEzE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,CAAC,MAAM,aAAa,GAA+B;IACvD,kBAAkB;IAClB,iBAAiB;IACjB,cAAc;IACd,oBAAoB;IACpB,oBAAoB;IACpB,aAAa;IACb,eAAe;CAChB,CAAC;AAEF,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,IAAI,EAAE,EAAE,CAAC,OAAO,EAAE;QAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/detect/index.ts"],"names":[],"mappings":"AAAA,yEAAyE;AAEzE,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAE/C,4BAA4B;AAC5B,kEAAkE;AAClE,yEAAyE;AACzE,2EAA2E;AAC3E,MAAM,CAAC,MAAM,aAAa,GAA+B;IACvD,kBAAkB;IAClB,iBAAiB;IACjB,cAAc;IACd,oBAAoB;IACpB,oBAAoB;IACpB,aAAa;IACb,GAAG,iBAAiB;IACpB,eAAe;CAChB,CAAC;AAEF,MAAM,UAAU,cAAc;IAC5B,OAAO;QACL,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,IAAI,EAAE,EAAE,CAAC,OAAO,EAAE;QAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,GAAG,EAAE,OAAO,CAAC,GAAG;KACjB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { DetectionContext } from "./types.js";
2
+ /**
3
+ * Resolve `names` against `ctx.env.PATH`. Returns the absolute path of the
4
+ * first hit, or null. Pure filesystem access — nothing is executed.
5
+ *
6
+ * `ctx.env` (not `process.env`) is read deliberately so tests can supply a
7
+ * controlled PATH; same reasoning as the R33 fix in claude-code.ts.
8
+ */
9
+ export declare function findExecutableOnPath(ctx: DetectionContext, names: readonly string[]): Promise<string | null>;
10
+ //# sourceMappingURL=which.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"which.d.ts","sourceRoot":"","sources":["../../src/detect/which.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAenD;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,GAAG,EAAE,gBAAgB,EACrB,KAAK,EAAE,SAAS,MAAM,EAAE,GACvB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBxB"}
@@ -0,0 +1,55 @@
1
+ // PATH lookup that never executes the binary it finds.
2
+ //
3
+ // Why not `execFile(name, ["--version"])` like the Claude Code detector does?
4
+ // Because desktop-app CLIs are not all safe to invoke: `cursor`, `windsurf`
5
+ // and `zed` will happily launch the full GUI (or block on a socket waiting
6
+ // for a running instance). A detector runs on every `install` invocation, so
7
+ // "probing" must be a read, not a process spawn.
8
+ //
9
+ // We therefore resolve the name against PATH with fs only. On Windows we try
10
+ // the usual executable suffixes because `where cursor` would have matched
11
+ // `cursor.cmd` / `cursor.exe` regardless of how npm or the native installer
12
+ // shipped it (the R33 bug: probing only `claude.cmd` missed native installs).
13
+ import { promises as fs } from "node:fs";
14
+ import path from "node:path";
15
+ /** Extensions Windows will resolve for a bare command name. */
16
+ const WIN_SUFFIXES = ["", ".exe", ".cmd", ".bat", ".ps1", ".com"];
17
+ const POSIX_SUFFIXES = [""];
18
+ async function isFile(p) {
19
+ try {
20
+ const s = await fs.stat(p);
21
+ return s.isFile();
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ }
27
+ /**
28
+ * Resolve `names` against `ctx.env.PATH`. Returns the absolute path of the
29
+ * first hit, or null. Pure filesystem access — nothing is executed.
30
+ *
31
+ * `ctx.env` (not `process.env`) is read deliberately so tests can supply a
32
+ * controlled PATH; same reasoning as the R33 fix in claude-code.ts.
33
+ */
34
+ export async function findExecutableOnPath(ctx, names) {
35
+ const rawPath = ctx.env.PATH ?? ctx.env.Path ?? "";
36
+ if (!rawPath)
37
+ return null;
38
+ const suffixes = ctx.platform === "win32" ? WIN_SUFFIXES : POSIX_SUFFIXES;
39
+ // `path.delimiter` follows the HOST, not ctx.platform. Reading a Windows
40
+ // PATH as ";" separators on a POSIX host (or vice versa) silently yields one
41
+ // giant bogus entry, so pick the separator from ctx explicitly.
42
+ const separator = ctx.platform === "win32" ? ";" : ":";
43
+ const dirs = rawPath.split(separator).filter((d) => d.length > 0);
44
+ for (const name of names) {
45
+ for (const dir of dirs) {
46
+ for (const suffix of suffixes) {
47
+ const candidate = path.join(dir, name + suffix);
48
+ if (await isFile(candidate))
49
+ return candidate;
50
+ }
51
+ }
52
+ }
53
+ return null;
54
+ }
55
+ //# sourceMappingURL=which.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"which.js","sourceRoot":"","sources":["../../src/detect/which.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,EAAE;AACF,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAC3E,6EAA6E;AAC7E,iDAAiD;AACjD,EAAE;AACF,6EAA6E;AAC7E,0EAA0E;AAC1E,4EAA4E;AAC5E,8EAA8E;AAE9E,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,+DAA+D;AAC/D,MAAM,YAAY,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;AAC3E,MAAM,cAAc,GAAG,CAAC,EAAE,CAAU,CAAC;AAErC,KAAK,UAAU,MAAM,CAAC,CAAS;IAC7B,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3B,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,GAAqB,EACrB,KAAwB;IAExB,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;IACnD,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC;IAC1E,yEAAyE;IACzE,6EAA6E;IAC7E,gEAAgE;IAChE,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACvD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAElE,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,KAAK,MAAM,MAAM,IAAI,QAAQ,EAAE,CAAC;gBAC9B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC;gBAChD,IAAI,MAAM,MAAM,CAAC,SAAS,CAAC;oBAAE,OAAO,SAAS,CAAC;YAChD,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
package/dist/index.js CHANGED
@@ -21,8 +21,9 @@ program
21
21
  .command("install")
22
22
  .description("Interactive: detect harness, mint token, write config, verify.")
23
23
  .option("-y, --yes", "Accept all confirm prompts; required for non-TTY environments (CI, piped shells, background tasks).")
24
+ .option("--harness <id>", "Force a harness id (cursor, workbuddy, windsurf, zed, openclaw, continue, letta, claude-code, ...) instead of taking the first detection. Also settable via ACPROMPT_HARNESS.")
24
25
  .action(async (options) => {
25
- await runInstall({ yes: Boolean(options.yes) });
26
+ await runInstall({ yes: Boolean(options.yes), harness: options.harness });
26
27
  });
27
28
  program
28
29
  .command("detect")
@@ -46,12 +47,34 @@ program
46
47
  // `npx @acprompt/join -y` / `--yes` as a shorthand for `install --yes`,
47
48
  // since that's the documented escape hatch for non-TTY invocations.
48
49
  const subcommands = new Set(["install", "detect", "verify", "whoami", "help", "--help", "-h", "--version", "-V"]);
50
+ /**
51
+ * Hand-parse `--harness <id>` / `--harness=<id>` out of the bare-invocation
52
+ * argv. Commander isn't in play on that path (we never call program.parse),
53
+ * and the flag has to keep working for `npx @acprompt/join --harness cursor`
54
+ * because that is how a user with several harnesses targets a specific one.
55
+ */
56
+ function bareHarnessFlag(argv) {
57
+ for (let i = 0; i < argv.length; i++) {
58
+ const arg = argv[i] ?? "";
59
+ if (arg === "--harness") {
60
+ const next = argv[i + 1];
61
+ if (next && !next.startsWith("-"))
62
+ return next;
63
+ return undefined;
64
+ }
65
+ if (arg.startsWith("--harness=")) {
66
+ const value = arg.slice("--harness=".length);
67
+ return value.length > 0 ? value : undefined;
68
+ }
69
+ }
70
+ return undefined;
71
+ }
49
72
  const firstArg = process.argv[2];
50
73
  const isBareInvocation = process.argv.length <= 2 || !subcommands.has(firstArg ?? "");
51
74
  if (isBareInvocation) {
52
75
  const rest = process.argv.slice(2);
53
76
  const yes = rest.includes("-y") || rest.includes("--yes");
54
- runInstall({ yes }).catch((err) => {
77
+ runInstall({ yes, harness: bareHarnessFlag(rest) }).catch((err) => {
55
78
  console.error(err.message);
56
79
  process.exit(1);
57
80
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,8BAA8B;AAC9B,EAAE;AACF,gBAAgB;AAChB,mEAAmE;AACnE,gDAAgD;AAChD,yDAAyD;AACzD,yDAAyD;AAEzD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,eAAe,CAAC;KACrB,WAAW,CAAC,0FAA0F,CAAC;KACvG,OAAO,CAAC,WAAW,CAAC,CAAC;AAExB,OAAO;KACJ,OAAO,CAAC,SAAS,CAAC;KAClB,WAAW,CAAC,gEAAgE,CAAC;KAC7E,MAAM,CAAC,WAAW,EAAE,qGAAqG,CAAC;KAC1H,MAAM,CACL,gBAAgB,EAChB,+KAA+K,CAChL;KACA,MAAM,CAAC,KAAK,EAAE,OAA4C,EAAE,EAAE;IAC7D,MAAM,UAAU,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;AAC5E,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,6DAA6D,CAAC;KAC1E,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,SAAS,EAAE,CAAC;AACpB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,uDAAuD,CAAC;KACpE,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,SAAS,EAAE,CAAC;AACpB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,oDAAoD,CAAC;KACjE,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,SAAS,EAAE,CAAC;AACpB,CAAC,CAAC,CAAC;AAEL,qEAAqE;AACrE,wEAAwE;AACxE,oEAAoE;AACpE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;AAElH;;;;;GAKG;AACH,SAAS,eAAe,CAAC,IAAuB;IAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1B,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACzB,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC/C,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;YAC7C,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9C,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjC,MAAM,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;AACtF,IAAI,gBAAgB,EAAE,CAAC;IACrB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC1D,UAAU,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;QACvE,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,CAAC;IACN,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;QACpD,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -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":"AAAA,0CAA0C;AAC1C,EAAE;AACF,2BAA2B;AAC3B,8DAA8D;AAC9D,oEAAoE;AACpE,uEAAuE;AACvE,yEAAyE;AACzE,EAAE;AACF,wEAAwE;AACxE,sEAAsE;AACtE,EAAE;AACF,+EAA+E;AAC/E,yDAAyD;AACzD,+EAA+E;AAC/E,gFAAgF;AAChF,4EAA4E;AAC5E,yEAAyE;AACzE,2EAA2E;AAC3E,EAAE;AACF,2EAA2E;AAC3E,kEAAkE;AAClE,mEAAmE;AACnE,qEAAqE;AACrE,0EAA0E;AAC1E,yDAAyD;AACzD,sEAAsE;AACtE,EAAE;AACF,qEAAqE;AACrE,oEAAoE;AACpE,0EAA0E;AAC1E,uDAAuD;AACvD,wEAAwE;AACxE,uEAAuE;AACvE,wEAAwE;AACxE,uDAAuD;AACvD,EAAE;AACF,oBAAoB;AACpB,yEAAyE;AACzE,sEAAsE;AACtE,sEAAsE;AACtE,uEAAuE;AACvE,sCAAsC;AAEtC,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,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,mBAAmB,CAAC;AAEnD;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAGvC;IACC,OAAO;QACL,OAAO,EAAE,KAAK;QACd,IAAI,EAAE;YACJ,IAAI;YACJ,eAAe;YACf,IAAI,CAAC,MAAM;YACX,UAAU;YACV,+BAA+B;SAChC;QACD,GAAG,EAAE;YACH,YAAY,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE;SACrC;KACF,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,UAAkB,EAClB,KAA8B;IAE9B,sEAAsE;IACtE,qEAAqE;IACrE,uEAAuE;IACvE,oEAAoE;IACpE,sEAAsE;IACtE,wDAAwD;IACxD,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,KAAK,CAAC;IAC5B,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC;IAC7B,sEAAsE;IACtE,qDAAqD;IACrD,MAAM,eAAe,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAqB,KAAK,EAAE,EAAE,EAAE,EAAE;IAChE,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,MAAM,UAAU,GACd,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QAC/B,uBAAuB,CAAC;YACtB,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,MAAM,KAAK,GAAG,uBAAuB,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;IAE9E,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC;QACf,MAAM,WAAW,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACvC,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACvB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,sCAAsC,UAAU,GAAG,CAAC,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CACT,EAAE,CAAC,GAAG,CACJ,sFAAsF,CACvF,CACF,CAAC;IACF,OAAO,CAAC,GAAG,CACT,EAAE,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAC3D,CAAC;IAEF,MAAM,MAAM,GAAG,CAAC,EAAE,CAAC,SAAS,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CACtD,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAC9B,CAAC;IACF,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC,CAAC;QAC1E,OAAO,CAAC,GAAG,CACT,EAAE,CAAC,GAAG,CACJ,6BAA6B,EAAE,CAAC,MAAM,sDAAsD,CAC7F,CACF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACvC,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAC5B,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { HarnessInstaller } from "./shared.js";
2
+ export declare const cursorInstaller: HarnessInstaller;
3
+ export declare const workbuddyInstaller: HarnessInstaller;
4
+ export declare const windsurfInstaller: HarnessInstaller;
5
+ export declare const continueInstaller: HarnessInstaller;
6
+ export declare const openclawInstaller: HarnessInstaller;
7
+ export declare const zedInstaller: HarnessInstaller;
8
+ //# sourceMappingURL=ide-apps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ide-apps.d.ts","sourceRoot":"","sources":["../../src/install/ide-apps.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAkCpD,eAAO,MAAM,eAAe,EAAE,gBAU7B,CAAC;AAEF,eAAO,MAAM,kBAAkB,EAAE,gBAmBhC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,gBAQ/B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,gBAU/B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,gBAmB/B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,gBAa1B,CAAC"}
@@ -0,0 +1,116 @@
1
+ // Installers for the six desktop-IDE / desktop-agent harnesses.
2
+ //
3
+ // Every one of these harnesses takes a remote (Streamable HTTP) MCP server as
4
+ // a JSON entry, but they disagree on the details, and getting it wrong is a
5
+ // silent "tools never appear" for the user:
6
+ //
7
+ // - Cursor : `mcpServers.<name>` with NO `type` field. Adding one is
8
+ // tolerated today but is not what Cursor documents.
9
+ // - Windsurf : `mcpServers.<name>` in ~/.codeium/windsurf/mcp_config.json.
10
+ // - WorkBuddy : `mcpServers.<name>` WITH `"type": "http"`, in
11
+ // ~/.workbuddy/mcp.json (no leading dot — see detector).
12
+ // - Continue : `mcpServers.<name>` in ~/.continue/config.json.
13
+ // - OpenClaw : `mcp.servers.<name>` (nested one level deeper), or
14
+ // `openclaw mcp set` which does it for you.
15
+ // - Zed : no config file at all — the JSON goes into the settings UI.
16
+ //
17
+ // All six are PRINT-ONLY. Nothing here writes to disk. That is deliberate:
18
+ // the schemas above were verified for "what entry does this harness accept",
19
+ // not for "what else lives in that file and how do we merge into it". The
20
+ // only two file-writers in this package (claude-code, letta) each had to go
21
+ // through readMergeableJson for the Round-3 data-loss fix; a printer cannot
22
+ // destroy a user's existing config no matter how wrong the snippet's shape is,
23
+ // and a wrong snippet is an error the user can see and report.
24
+ //
25
+ // Source of truth for each shape: `acp/public/install.sh` (case "$HARNESS"),
26
+ // which was validated against real users. Keep the two in sync.
27
+ import pc from "picocolors";
28
+ const DOCS_URL = "https://www.acprompt.com/api/discover";
29
+ function entry(mcpUrl, token) {
30
+ return {
31
+ url: mcpUrl,
32
+ headers: { Authorization: `Bearer ${token}` },
33
+ };
34
+ }
35
+ function pretty(value) {
36
+ return JSON.stringify(value, null, 2);
37
+ }
38
+ /** Render `{ mcpServers: { acprompt: <entry> } }`. */
39
+ function mcpServersBlock(mcpUrl, token, extra = {}) {
40
+ return pretty({
41
+ mcpServers: { acprompt: { ...extra, ...entry(mcpUrl, token) } },
42
+ });
43
+ }
44
+ function footer(restart) {
45
+ console.log("");
46
+ console.log(pc.bold("Then:"));
47
+ console.log(` ${restart}`);
48
+ console.log("");
49
+ console.log(pc.dim(`Docs: ${DOCS_URL}`));
50
+ }
51
+ export const cursorInstaller = async (ic) => {
52
+ console.log(pc.bold("Cursor — edit ~/.cursor/mcp.json"));
53
+ console.log("");
54
+ console.log(pc.dim("Add this to the file's `mcpServers` object (create the file if absent):"));
55
+ console.log("");
56
+ console.log(mcpServersBlock(ic.mcpUrl, ic.token));
57
+ footer("Quit Cursor completely (Cmd+Q / File → Exit) and reopen it.");
58
+ return { wrote: [], printed: ["cursor-snippet"] };
59
+ };
60
+ export const workbuddyInstaller = async (ic) => {
61
+ console.log(pc.bold("WorkBuddy — edit ~/.workbuddy/mcp.json"));
62
+ console.log("");
63
+ console.log(pc.yellow("Use mcp.json, NOT .mcp.json. The dot-file is auto-generated by WorkBuddy"));
64
+ console.log(pc.yellow("as an internal connector-proxy descriptor and gets overwritten."));
65
+ console.log("");
66
+ console.log(pc.dim("Merge this into the `mcpServers` object:"));
67
+ console.log("");
68
+ console.log(mcpServersBlock(ic.mcpUrl, ic.token, { type: "http" }));
69
+ footer("Fully close WorkBuddy — close the window AND quit from the tray icon — then reopen. MCP servers only load at startup.");
70
+ return { wrote: [], printed: ["workbuddy-snippet"] };
71
+ };
72
+ export const windsurfInstaller = async (ic) => {
73
+ console.log(pc.bold("Windsurf — edit ~/.codeium/windsurf/mcp_config.json"));
74
+ console.log("");
75
+ console.log(pc.dim("Merge this into the `mcpServers` object:"));
76
+ console.log("");
77
+ console.log(mcpServersBlock(ic.mcpUrl, ic.token));
78
+ footer("Restart Windsurf.");
79
+ return { wrote: [], printed: ["windsurf-snippet"] };
80
+ };
81
+ export const continueInstaller = async (ic) => {
82
+ console.log(pc.bold("Continue.dev — edit ~/.continue/config.json"));
83
+ console.log("");
84
+ console.log(pc.dim("Merge this into the `mcpServers` object:"));
85
+ console.log("");
86
+ console.log(mcpServersBlock(ic.mcpUrl, ic.token));
87
+ footer("Reload the Continue extension (Cmd+Shift+P → Continue: Reload).");
88
+ return { wrote: [], printed: ["continue-snippet"] };
89
+ };
90
+ export const openclawInstaller = async (ic) => {
91
+ console.log(pc.bold("OpenClaw — prefer the CLI, fall back to the file"));
92
+ console.log("");
93
+ console.log(pc.dim("Run this (it writes the config for you):"));
94
+ console.log("");
95
+ console.log(` openclaw mcp set acprompt --url ${ic.mcpUrl} --header "Authorization: Bearer ${ic.token}"`);
96
+ console.log("");
97
+ console.log(pc.dim("If that fails, edit ~/.openclaw/openclaw.json — note the nesting"));
98
+ console.log(pc.dim("is `mcp.servers`, one level deeper than the others:"));
99
+ console.log("");
100
+ console.log(pretty({ mcp: { servers: { acprompt: entry(ic.mcpUrl, ic.token) } } }));
101
+ footer("Restart the OpenClaw gateway.");
102
+ return { wrote: [], printed: ["openclaw-snippet"] };
103
+ };
104
+ export const zedInstaller = async (ic) => {
105
+ console.log(pc.bold("Zed — configure in the settings UI"));
106
+ console.log("");
107
+ console.log("Zed has no MCP config file. Open:");
108
+ console.log(" Zed → Settings → Assistant → MCP Servers → Add Server");
109
+ console.log("");
110
+ console.log(pc.dim("and enter:"));
111
+ console.log("");
112
+ console.log(pretty({ name: "acprompt", ...entry(ic.mcpUrl, ic.token) }));
113
+ footer("Reload Zed (Cmd+R / Ctrl+R) or quit and reopen.");
114
+ return { wrote: [], printed: ["zed-snippet"] };
115
+ };
116
+ //# sourceMappingURL=ide-apps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ide-apps.js","sourceRoot":"","sources":["../../src/install/ide-apps.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,14 @@
1
1
  import type { HarnessInstaller } from "./shared.js";
2
+ /**
3
+ * Harnesses whose installer writes into an existing user config file, and
4
+ * therefore needs an explicit confirmation prompt before it runs.
5
+ *
6
+ * This used to be an inline `=== "claude-code" || === "letta"` check inside
7
+ * install.ts, which silently stopped being true the moment a new writer was
8
+ * added. Keeping the list next to the registry makes the coupling visible.
9
+ * Every id in here MUST route its merge through `readMergeableJson`.
10
+ */
11
+ export declare const FILE_WRITER_HARNESSES: ReadonlySet<string>;
2
12
  export declare function getInstaller(harnessId: string): HarnessInstaller;
3
13
  export type { HarnessInstaller, InstallerContext, InstallerResult } from "./shared.js";
4
14
  export { DEFAULT_MCP_URL, inferLanguage } from "./shared.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/install/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAmBpD,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAEhE;AAED,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/install/index.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAiCpD;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,MAAM,CAGpD,CAAC;AAEH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,gBAAgB,CAEhE;AAED,YAAY,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -9,6 +9,7 @@ import { crewaiInstaller } from "./crewai.js";
9
9
  import { openaiAgentsInstaller } from "./openai-agents.js";
10
10
  import { anthropicSdkInstaller } from "./anthropic-sdk.js";
11
11
  import { lettaInstaller } from "./letta.js";
12
+ import { cursorInstaller, workbuddyInstaller, windsurfInstaller, continueInstaller, openclawInstaller, zedInstaller, } from "./ide-apps.js";
12
13
  import { genericInstaller } from "./generic.js";
13
14
  const REGISTRY = {
14
15
  "claude-code": claudeCodeInstaller,
@@ -17,8 +18,27 @@ const REGISTRY = {
17
18
  "openai-agents": openaiAgentsInstaller,
18
19
  "anthropic-sdk": anthropicSdkInstaller,
19
20
  letta: lettaInstaller,
21
+ cursor: cursorInstaller,
22
+ workbuddy: workbuddyInstaller,
23
+ windsurf: windsurfInstaller,
24
+ continue: continueInstaller,
25
+ openclaw: openclawInstaller,
26
+ zed: zedInstaller,
20
27
  generic: genericInstaller,
21
28
  };
29
+ /**
30
+ * Harnesses whose installer writes into an existing user config file, and
31
+ * therefore needs an explicit confirmation prompt before it runs.
32
+ *
33
+ * This used to be an inline `=== "claude-code" || === "letta"` check inside
34
+ * install.ts, which silently stopped being true the moment a new writer was
35
+ * added. Keeping the list next to the registry makes the coupling visible.
36
+ * Every id in here MUST route its merge through `readMergeableJson`.
37
+ */
38
+ export const FILE_WRITER_HARNESSES = new Set([
39
+ "claude-code",
40
+ "letta",
41
+ ]);
22
42
  export function getInstaller(harnessId) {
23
43
  return REGISTRY[harnessId] ?? genericInstaller;
24
44
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/install/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,EAAE;AACF,0EAA0E;AAC1E,yEAAyE;AACzE,6CAA6C;AAG7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,QAAQ,GAAqC;IACjD,aAAa,EAAE,mBAAmB;IAClC,SAAS,EAAE,kBAAkB;IAC7B,MAAM,EAAE,eAAe;IACvB,eAAe,EAAE,qBAAqB;IACtC,eAAe,EAAE,qBAAqB;IACtC,KAAK,EAAE,cAAc;IACrB,OAAO,EAAE,gBAAgB;CAC1B,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,OAAO,QAAQ,CAAC,SAAS,CAAC,IAAI,gBAAgB,CAAC;AACjD,CAAC;AAGD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/install/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,EAAE;AACF,0EAA0E;AAC1E,yEAAyE;AACzE,6CAA6C;AAG7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,QAAQ,GAAqC;IACjD,aAAa,EAAE,mBAAmB;IAClC,SAAS,EAAE,kBAAkB;IAC7B,MAAM,EAAE,eAAe;IACvB,eAAe,EAAE,qBAAqB;IACtC,eAAe,EAAE,qBAAqB;IACtC,KAAK,EAAE,cAAc;IACrB,MAAM,EAAE,eAAe;IACvB,SAAS,EAAE,kBAAkB;IAC7B,QAAQ,EAAE,iBAAiB;IAC3B,QAAQ,EAAE,iBAAiB;IAC3B,QAAQ,EAAE,iBAAiB;IAC3B,GAAG,EAAE,YAAY;IACjB,OAAO,EAAE,gBAAgB;CAC1B,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAwB,IAAI,GAAG,CAAC;IAChE,aAAa;IACb,OAAO;CACR,CAAC,CAAC;AAEH,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,OAAO,QAAQ,CAAC,SAAS,CAAC,IAAI,gBAAgB,CAAC;AACjD,CAAC;AAGD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC"}
@@ -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.10",
4
4
  "description": "Smart installer for ACPrompt — one-shot MCP config for any agent harness.",
5
5
  "keywords": [
6
6
  "acprompt",