@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.
- package/README.md +10 -2
- package/dist/auth/paths.d.ts.map +1 -1
- package/dist/auth/paths.js +6 -1
- package/dist/auth/paths.js.map +1 -1
- package/dist/commands/install.d.ts +33 -0
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +43 -9
- package/dist/commands/install.js.map +1 -1
- package/dist/detect/claude-code.d.ts +11 -0
- package/dist/detect/claude-code.d.ts.map +1 -1
- package/dist/detect/claude-code.js +24 -9
- package/dist/detect/claude-code.js.map +1 -1
- package/dist/detect/ide-apps.d.ts +26 -0
- package/dist/detect/ide-apps.d.ts.map +1 -0
- package/dist/detect/ide-apps.js +193 -0
- package/dist/detect/ide-apps.js.map +1 -0
- package/dist/detect/index.d.ts.map +1 -1
- package/dist/detect/index.js +6 -0
- package/dist/detect/index.js.map +1 -1
- package/dist/detect/which.d.ts +10 -0
- package/dist/detect/which.d.ts.map +1 -0
- package/dist/detect/which.js +55 -0
- package/dist/detect/which.js.map +1 -0
- package/dist/index.js +25 -2
- package/dist/index.js.map +1 -1
- package/dist/install/claude-code.d.ts +16 -0
- package/dist/install/claude-code.d.ts.map +1 -1
- package/dist/install/claude-code.js +21 -2
- package/dist/install/claude-code.js.map +1 -1
- package/dist/install/ide-apps.d.ts +8 -0
- package/dist/install/ide-apps.d.ts.map +1 -0
- package/dist/install/ide-apps.js +116 -0
- package/dist/install/ide-apps.js.map +1 -0
- package/dist/install/index.d.ts +10 -0
- package/dist/install/index.d.ts.map +1 -1
- package/dist/install/index.js +20 -0
- package/dist/install/index.js.map +1 -1
- package/dist/install/letta.d.ts.map +1 -1
- package/dist/install/letta.js +3 -1
- package/dist/install/letta.js.map +1 -1
- package/dist/util/atomic-write.d.ts +8 -0
- package/dist/util/atomic-write.d.ts.map +1 -0
- package/dist/util/atomic-write.js +58 -0
- package/dist/util/atomic-write.js.map +1 -0
- 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
|
|
package/dist/auth/paths.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/auth/paths.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/auth/paths.js
CHANGED
|
@@ -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
|
-
|
|
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);
|
package/dist/auth/paths.js.map
CHANGED
|
@@ -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;
|
|
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":"
|
|
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"}
|
package/dist/commands/install.js
CHANGED
|
@@ -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
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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 =
|
|
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":"AAAA,wDAAwD;AACxD,EAAE;AACF,QAAQ;AACR,yCAAyC;AACzC,0DAA0D;AAC1D,2CAA2C;AAC3C,qEAAqE;AACrE,6DAA6D;AAC7D,qBAAqB;AAErB,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EACL,aAAa,EACb,cAAc,GAEf,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;
|
|
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;
|
|
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.
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
|
|
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":"AAAA,iDAAiD;AACjD,EAAE;AACF,yDAAyD;AACzD,mDAAmD;AACnD,6DAA6D;AAC7D,iFAAiF;AACjF,6DAA6D;AAC7D,6EAA6E;AAC7E,0EAA0E;AAC1E,2EAA2E;AAC3E,uDAAuD;AACvD,EAAE;AACF,wEAAwE;AACxE,2EAA2E;AAC3E,6EAA6E;AAE7E,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAOtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,MAAM,UAAU,uBAAuB,CAAC,GAAqB;IAC3D,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAC7E,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,4BAA4B,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,IAAI,CACd,GAAG,CAAC,IAAI,EACR,SAAS,EACT,qBAAqB,EACrB,QAAQ,EACR,4BAA4B,CAC7B,CAAC;IACJ,CAAC;IACD,0BAA0B;IAC1B,MAAM,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC5E,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,EAAE,4BAA4B,CAAC,CAAC;AACtE,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,CAAS;IACjC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,GAAqB;IAClD,oEAAoE;IACpE,2EAA2E;IAC3E,EAAE;IACF,sEAAsE;IACtE,qEAAqE;IACrE,
|
|
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":"AAAA,iDAAiD;AACjD,EAAE;AACF,4EAA4E;AAC5E,6EAA6E;AAC7E,uEAAuE;AACvE,EAAE;AACF,6EAA6E;AAC7E,4EAA4E;AAC5E,6EAA6E;AAC7E,yEAAyE;AACzE,uBAAuB;AACvB,EAAE;AACF,4EAA4E;AAC5E,iEAAiE;AACjE,8EAA8E;AAC9E,8DAA8D;AAC9D,2EAA2E;AAC3E,qDAAqD;AAErD,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAM7B,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAkBlD,KAAK,UAAU,UAAU,CAAC,CAAS;IACjC,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,KAAK,UAAU,SAAS,CAAC,CAAS;IAChC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3B,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,0EAA0E;AAC1E,8EAA8E;AAE9E,MAAM,UAAU,gBAAgB,CAAC,GAAqB;IACpD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAqB;IACvD,4EAA4E;IAC5E,2EAA2E;IAC3E,iEAAiE;IACjE,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,GAAqB;IACtD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAqB;IAChD,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;AAC/C,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,SAAS,kBAAkB,CAAC,IAAgB;IAC1C,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,KAAK,EAAE,IAAI,CAAC,KAAK;QAEjB,KAAK,CAAC,MAAM,CAAC,GAAqB;YAChC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YACxC,MAAM,aAAa,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YAErD,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAa,EAAE,CAAC;gBAE9B,IAAI,UAAU,IAAI,CAAC,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;oBACjD,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,gBAAgB,UAAU,EAAE,CAAC,CAAC;gBAC3D,CAAC;gBAED,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;oBACpC,IAAI,MAAM,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;wBACzB,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,aAAa,GAAG,EAAE,CAAC,CAAC;oBACjD,CAAC;gBACH,CAAC;gBAED,MAAM,GAAG,GAAG,MAAM,oBAAoB,CAAC,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;gBAC3D,IAAI,GAAG,EAAE,CAAC;oBACR,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,GAAG,EAAE,CAAC,CAAC;gBAC9D,CAAC;gBAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC1B,OAAO;wBACL,OAAO,EAAE,IAAI,CAAC,EAAE;wBAChB,KAAK,EAAE,IAAI,CAAC,KAAK;wBACjB,QAAQ,EAAE,KAAK;wBACf,MAAM,EAAE,IAAI,CAAC,aAAa;wBAC1B,aAAa;qBACd,CAAC;gBACJ,CAAC;gBAED,OAAO;oBACL,OAAO,EAAE,IAAI,CAAC,EAAE;oBAChB,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,QAAQ,EAAE,IAAI;oBACd,QAAQ;oBACR,aAAa;iBACd,CAAC;YACJ,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,sEAAsE;gBACtE,wDAAwD;gBACxD,OAAO;oBACL,OAAO,EAAE,IAAI,CAAC,EAAE;oBAChB,KAAK,EAAE,IAAI,CAAC,KAAK;oBACjB,QAAQ,EAAE,KAAK;oBACf,MAAM,EAAG,CAAW,CAAC,OAAO;oBAC5B,aAAa;iBACd,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,MAAM,CAAC,MAAM,cAAc,GAAG,kBAAkB,CAAC;IAC/C,EAAE,EAAE,QAAQ;IACZ,KAAK,EAAE,QAAQ;IACf,UAAU,EAAE,gBAAgB;IAC5B,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAClD,QAAQ,EAAE,CAAC,QAAQ,CAAC;IACpB,aAAa,EAAE,mDAAmD;CACnE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,kBAAkB,CAAC;IAClD,EAAE,EAAE,WAAW;IACf,KAAK,EAAE,WAAW;IAClB,UAAU,EAAE,mBAAmB;IAC/B,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACrD,2EAA2E;IAC3E,QAAQ,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC;IACpC,aAAa,EAAE,gEAAgE;CAChF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;IACjD,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IACjB,UAAU,EAAE,kBAAkB;IAC9B,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC/D,QAAQ,EAAE,CAAC,UAAU,CAAC;IACtB,aAAa,EAAE,+DAA+D;CAC/E,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;IACjD,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,UAAU;IACjB,UAAU,EAAE,kBAAkB;IAC9B,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACpD,QAAQ,EAAE,CAAC,UAAU,CAAC;IACtB,aAAa,EAAE,uDAAuD;CACvE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,kBAAkB,CAAC;IACjD,EAAE,EAAE,UAAU;IACd,KAAK,EAAE,cAAc;IACrB,UAAU,EAAE,kBAAkB;IAC9B,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACpD,QAAQ,EAAE,CAAC,UAAU,CAAC;IACtB,aAAa,EAAE,sDAAsD;CACtE,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,kBAAkB,CAAC;IAC5C,EAAE,EAAE,KAAK;IACT,KAAK,EAAE,KAAK;IACZ,wEAAwE;IACxE,0EAA0E;IAC1E,oEAAoE;IACpE,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI;IACtB,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IACrC,QAAQ,EAAE,CAAC,KAAK,CAAC;IACjB,aAAa,EAAE,oDAAoD;CACpE,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA+B;IAC3D,cAAc;IACd,iBAAiB;IACjB,gBAAgB;IAChB,WAAW;IACX,gBAAgB;IAChB,gBAAgB;CACjB,CAAC"}
|
|
@@ -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;
|
|
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"}
|
package/dist/detect/index.js
CHANGED
|
@@ -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() {
|
package/dist/detect/index.js.map
CHANGED
|
@@ -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":";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,CAAC,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.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;
|
|
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
|
-
|
|
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
|
-
|
|
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":"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,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAGvC;IACC,OAAO;QACL,OAAO,EAAE,KAAK;QACd,IAAI,EAAE;YACJ,IAAI;YACJ,
|
|
1
|
+
{"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/install/claude-code.ts"],"names":[],"mappings":"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"}
|
|
@@ -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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"}
|
package/dist/install/index.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/install/index.js
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/install/letta.js
CHANGED
|
@@ -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
|
-
|
|
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,
|
|
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"}
|