@agent-native/skills 0.2.11 → 0.2.13
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 +5 -4
- package/dist/connect.d.ts +5 -6
- package/dist/connect.d.ts.map +1 -1
- package/dist/connect.js +52 -12
- package/dist/connect.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +125 -27
- package/dist/index.js.map +1 -1
- package/dist/mcp-config-writers.d.ts +32 -21
- package/dist/mcp-config-writers.d.ts.map +1 -1
- package/dist/mcp-config-writers.js +166 -23
- package/dist/mcp-config-writers.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -10,10 +10,11 @@ npx @agent-native/skills@latest add --skill visual-plan --mode local-files
|
|
|
10
10
|
```
|
|
11
11
|
|
|
12
12
|
Use `--skill <name>` one or more times to select specific skills, or omit it in
|
|
13
|
-
an interactive terminal to choose from a prompt.
|
|
14
|
-
|
|
15
|
-
`--client
|
|
16
|
-
|
|
13
|
+
an interactive terminal to choose from a prompt. The prompt puts `visual-plan`
|
|
14
|
+
and `visual-recap` first and preselects only those by default. Use
|
|
15
|
+
`--client codex`, `--client claude-code`, or `--client all` to choose install
|
|
16
|
+
targets; omitted `--client` defaults to all supported clients. For
|
|
17
|
+
`visual-plan` and `visual-recap`, use `--mode hosted`, `--mode local-files`, or
|
|
17
18
|
`--mode self-hosted --mcp-url <url>` to choose hosted sharing, all-local text
|
|
18
19
|
files, or your own Plan app. Add `--update-instructions` to append an idempotent
|
|
19
20
|
managed block to `AGENTS.md` and/or `CLAUDE.md` for instruction-style skills.
|
package/dist/connect.d.ts
CHANGED
|
@@ -9,14 +9,13 @@
|
|
|
9
9
|
* SAME device-code/OAuth protocol as core.
|
|
10
10
|
*
|
|
11
11
|
* Two client families, exactly as in core:
|
|
12
|
-
* - OAuth-capable (
|
|
13
|
-
* entry (no bearer headers). The user authenticates
|
|
14
|
-
* remote MCP OAuth
|
|
12
|
+
* - OAuth-capable (Claude Code, Cursor, OpenCode, GitHub Copilot / VS Code):
|
|
13
|
+
* get a URL-only HTTP MCP entry (no bearer headers). The user authenticates
|
|
14
|
+
* in-host via standard remote MCP OAuth.
|
|
15
15
|
* - Device-code (codex, cowork): run the browser device-code flow against the
|
|
16
16
|
* descriptor's hosted URL, then write the entry WITH the minted bearer token
|
|
17
|
-
* + headers. Non-interactive (or no TTY) skips
|
|
18
|
-
*
|
|
19
|
-
* fallback command.
|
|
17
|
+
* + headers. Non-interactive (or no TTY) skips writing device-code configs,
|
|
18
|
+
* surfacing the exact `agent-native connect <url>` fallback command.
|
|
20
19
|
*
|
|
21
20
|
* Server contract (identical paths + JSON field names to core):
|
|
22
21
|
* POST <hostedUrl>/_agent-native/mcp/connect/device/start (no auth)
|
package/dist/connect.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,EAAE,QAAQ,EAA2B,MAAM,yBAAyB,CAAC;AA6B5E;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,aAAa,CAAC;IAC1B,OAAO,EAAE,QAAQ,EAAE,CAAC;IACpB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,IAAI,CAAC,EAAE;QACL,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;QACzB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACvC,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE;QAAE,MAAM,EAAE,QAAQ,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC9C,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AA0CD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAEhE;AAiXD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,iBAAiB,CAAC,CAyH5B"}
|
package/dist/connect.js
CHANGED
|
@@ -9,14 +9,13 @@
|
|
|
9
9
|
* SAME device-code/OAuth protocol as core.
|
|
10
10
|
*
|
|
11
11
|
* Two client families, exactly as in core:
|
|
12
|
-
* - OAuth-capable (
|
|
13
|
-
* entry (no bearer headers). The user authenticates
|
|
14
|
-
* remote MCP OAuth
|
|
12
|
+
* - OAuth-capable (Claude Code, Cursor, OpenCode, GitHub Copilot / VS Code):
|
|
13
|
+
* get a URL-only HTTP MCP entry (no bearer headers). The user authenticates
|
|
14
|
+
* in-host via standard remote MCP OAuth.
|
|
15
15
|
* - Device-code (codex, cowork): run the browser device-code flow against the
|
|
16
16
|
* descriptor's hosted URL, then write the entry WITH the minted bearer token
|
|
17
|
-
* + headers. Non-interactive (or no TTY) skips
|
|
18
|
-
*
|
|
19
|
-
* fallback command.
|
|
17
|
+
* + headers. Non-interactive (or no TTY) skips writing device-code configs,
|
|
18
|
+
* surfacing the exact `agent-native connect <url>` fallback command.
|
|
20
19
|
*
|
|
21
20
|
* Server contract (identical paths + JSON field names to core):
|
|
22
21
|
* POST <hostedUrl>/_agent-native/mcp/connect/device/start (no auth)
|
|
@@ -40,7 +39,19 @@ const MCP_PATH = "/_agent-native/mcp";
|
|
|
40
39
|
const REMOTE_MCP_OAUTH_CLIENTS = new Set([
|
|
41
40
|
"claude-code",
|
|
42
41
|
"claude-code-cli",
|
|
42
|
+
"cursor",
|
|
43
|
+
"opencode",
|
|
44
|
+
"github-copilot",
|
|
43
45
|
]);
|
|
46
|
+
const CLIENT_LABELS = {
|
|
47
|
+
"claude-code": "Claude Code",
|
|
48
|
+
"claude-code-cli": "Claude Code CLI",
|
|
49
|
+
codex: "Codex",
|
|
50
|
+
cowork: "Claude Cowork",
|
|
51
|
+
cursor: "Cursor",
|
|
52
|
+
opencode: "OpenCode",
|
|
53
|
+
"github-copilot": "GitHub Copilot / VS Code",
|
|
54
|
+
};
|
|
44
55
|
// ---------------------------------------------------------------------------
|
|
45
56
|
// Helpers
|
|
46
57
|
// ---------------------------------------------------------------------------
|
|
@@ -153,6 +164,22 @@ function manualConnectGuidance(baseUrl, clients, scope) {
|
|
|
153
164
|
return (`To authenticate ${describeClients(clients)}, run: ` +
|
|
154
165
|
fallbackConnectCommand(baseUrl, clients, scope));
|
|
155
166
|
}
|
|
167
|
+
function oauthNextStepsForClients(clients, serverName) {
|
|
168
|
+
const lines = [];
|
|
169
|
+
if (clients.includes("claude-code") || clients.includes("claude-code-cli")) {
|
|
170
|
+
lines.push("Claude Code: restart Claude Code, run /mcp, and choose Authenticate.");
|
|
171
|
+
}
|
|
172
|
+
if (clients.includes("cursor")) {
|
|
173
|
+
lines.push("Cursor: restart or reload Cursor, then authenticate the MCP server from Cursor MCP settings if prompted.");
|
|
174
|
+
}
|
|
175
|
+
if (clients.includes("opencode")) {
|
|
176
|
+
lines.push(`OpenCode: run opencode mcp auth ${serverName ?? "<server-name>"} or authenticate on first use.`);
|
|
177
|
+
}
|
|
178
|
+
if (clients.includes("github-copilot")) {
|
|
179
|
+
lines.push("GitHub Copilot / VS Code: reload VS Code, open the MCP config, and use the Auth action above the server if prompted.");
|
|
180
|
+
}
|
|
181
|
+
return lines;
|
|
182
|
+
}
|
|
156
183
|
/** Write a token+headers entry for every config key, collecting files. */
|
|
157
184
|
function writeAuthedEntries(clients, keys, mcpUrl, token, headers, scope, baseDir, written, errors) {
|
|
158
185
|
for (const client of clients) {
|
|
@@ -215,11 +242,18 @@ async function runDeviceFlow(baseUrl, appSlug, clientArg, log, timeoutMs, deps =
|
|
|
215
242
|
try {
|
|
216
243
|
const { status, json } = await postJson(fetchImpl, `${baseUrl}${DEVICE_POLL_PATH}`, { device_code: start.device_code });
|
|
217
244
|
if (status < 200 || status >= 300) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
245
|
+
if (isTerminalPollBody(json)) {
|
|
246
|
+
poll = json;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
log(` Connect polling failed (HTTP ${status}): ` +
|
|
250
|
+
responseMessage(json, "server returned an error."));
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
poll = (json ?? { status: "pending" });
|
|
221
256
|
}
|
|
222
|
-
poll = (json ?? { status: "pending" });
|
|
223
257
|
}
|
|
224
258
|
catch {
|
|
225
259
|
// Transient network error — keep polling until the deadline.
|
|
@@ -267,6 +301,12 @@ async function runDeviceFlow(baseUrl, appSlug, clientArg, log, timeoutMs, deps =
|
|
|
267
301
|
}
|
|
268
302
|
return null;
|
|
269
303
|
}
|
|
304
|
+
function isTerminalPollBody(json) {
|
|
305
|
+
return (json?.status === "not_found" ||
|
|
306
|
+
json?.status === "error" ||
|
|
307
|
+
json?.status === "expired" ||
|
|
308
|
+
json?.status === "consumed");
|
|
309
|
+
}
|
|
270
310
|
// ---------------------------------------------------------------------------
|
|
271
311
|
// Public entry point
|
|
272
312
|
// ---------------------------------------------------------------------------
|
|
@@ -308,7 +348,7 @@ export async function registerMcpServer(opts) {
|
|
|
308
348
|
// OAuth clients always get URL-only entries (in-host OAuth, no local bearer).
|
|
309
349
|
if (oauthClients.length > 0) {
|
|
310
350
|
writeUrlOnlyEntries(oauthClients, keys, mcpUrl, scope, baseDir, written, errors);
|
|
311
|
-
guidance.push(`${describeClients(oauthClients)}: wrote URL-only MCP config (no bearer headers).`,
|
|
351
|
+
guidance.push(`${describeClients(oauthClients)}: wrote URL-only MCP config (no bearer headers).`, ...oauthNextStepsForClients(oauthClients, descriptor.serverName));
|
|
312
352
|
}
|
|
313
353
|
// Device-code clients.
|
|
314
354
|
if (deviceClients.length > 0) {
|
|
@@ -348,7 +388,7 @@ export async function registerMcpServer(opts) {
|
|
|
348
388
|
return { written, authenticated, guidance: [...guidance, ...errors] };
|
|
349
389
|
}
|
|
350
390
|
function describeClients(clients) {
|
|
351
|
-
return clients.join(", ");
|
|
391
|
+
return clients.map((client) => CLIENT_LABELS[client]).join(", ");
|
|
352
392
|
}
|
|
353
393
|
/** Derive the `app` slug the device-start endpoint expects. */
|
|
354
394
|
function appSlugFor(descriptor, baseUrl) {
|
package/dist/connect.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAY,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAE5E,MAAM,iBAAiB,GAAG,yCAAyC,CAAC;AACpE,MAAM,gBAAgB,GAAG,wCAAwC,CAAC;AAClE,MAAM,QAAQ,GAAG,oBAAoB,CAAC;AAEtC,8EAA8E;AAC9E,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAW;IACjD,aAAa;IACb,iBAAiB;CAClB,CAAC,CAAC;AA+EH,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,UAAU,sBAAsB,CAAC,MAAgB;IACrD,OAAO,wBAAwB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC9C,CAAC;AAED,MAAM,8BAA8B,GAAG,MAAM,CAAC;AAE9C,SAAS,SAAS,CAAC,EAAU;IAC3B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,gEAAgE;AAChE,SAAS,kBAAkB,CAAC,GAAW;IACrC,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,UAAyB;IAC9C,IAAI,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QAClD,OAAO,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;IAClC,CAAC;IACD,IAAI,UAAU,CAAC,SAAS,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QACxD,MAAM,IAAI,GAAG,kBAAkB,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,OAAO,GAAG,IAAI,GAAG,QAAQ,EAAE,CAAC;IAC9B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,0EAA0E;AAC1E,SAAS,cAAc,CAAC,UAAyB;IAC/C,IAAI,UAAU,CAAC,SAAS,IAAI,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,CAAC;QACxD,OAAO,kBAAkB,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,8DAA8D;IAC9D,IAAI,UAAU,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QAClD,MAAM,OAAO,GAAG,kBAAkB,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC/B,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,kFAAkF;AAClF,SAAS,UAAU,CAAC,UAAyB;IAC3C,MAAM,IAAI,GAAa,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;IAC/C,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;QAC7C,IAAI,KAAK,IAAI,KAAK,KAAK,UAAU,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACtE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,eAAe,CAAC,IAAS,EAAE,QAAgB;IAClD,MAAM,OAAO,GACX,OAAO,IAAI,EAAE,OAAO,KAAK,QAAQ;QAC/B,CAAC,CAAC,IAAI,CAAC,OAAO;QACd,CAAC,CAAC,OAAO,IAAI,EAAE,KAAK,KAAK,QAAQ;YAC/B,CAAC,CAAC,IAAI,CAAC,KAAK;YACZ,CAAC,CAAC,EAAE,CAAC;IACX,OAAO,OAAO,CAAC,IAAI,EAAE,IAAI,QAAQ,CAAC;AACpC,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,SAAuB,EACvB,GAAW,EACX,IAAa;IAEb,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE;YACpC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,EAAE,CAAC;YAChC,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;QACH,IAAI,IAAI,GAAQ,IAAI,CAAC;QACrB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,GAAG,IAAI,CAAC;QACd,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC;IAC3C,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,OAAmB;IAC9C,OAAO,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,sBAAsB,CAC7B,OAAe,EACf,OAAmB,EACnB,KAAa;IAEb,OAAO,yCAAyC,OAAO,aAAa,mBAAmB,CACrF,OAAO,CACR,YAAY,KAAK,EAAE,CAAC;AACvB,CAAC;AAED,iFAAiF;AACjF,SAAS,mBAAmB,CAC1B,OAAmB,EACnB,IAAc,EACd,MAAc,EACd,KAAa,EACb,OAAe,EACf,OAA6C,EAC7C,MAAgB;IAEhB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,uBAAuB,CAClC,MAAM,EACN,GAAG,EACH,MAAM,EACN,SAAS,EACT,OAAO,EACP,KAAK,EACL,SAAS,CACV,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACjC,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,CACT,mBAAmB,GAAG,QAAQ,MAAM,KAAK,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAC/D,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,qBAAqB,CAC5B,OAAe,EACf,OAAmB,EACnB,KAAa;IAEb,OAAO,CACL,mBAAmB,eAAe,CAAC,OAAO,CAAC,SAAS;QACpD,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAChD,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,SAAS,kBAAkB,CACzB,OAAmB,EACnB,IAAc,EACd,MAAc,EACd,KAAyB,EACzB,OAA2C,EAC3C,KAAa,EACb,OAAe,EACf,OAA6C,EAC7C,MAAgB;IAEhB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,uBAAuB,CAClC,MAAM,EACN,GAAG,EACH,MAAM,EACN,KAAK,EACL,OAAO,EACP,KAAK,EACL,OAAO,CACR,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;YACjC,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAClB,MAAM,CAAC,IAAI,CACT,mBAAmB,GAAG,QAAQ,MAAM,KAAK,GAAG,EAAE,OAAO,IAAI,GAAG,EAAE,CAC/D,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,kEAAkE;AAClE,8EAA8E;AAE9E;;;;;GAKG;AACH,KAAK,UAAU,aAAa,CAC1B,OAAe,EACf,OAAe,EACf,SAAiB,EACjB,GAAwB,EACxB,SAA6B,EAC7B,OAAmC,EAAE;IAErC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;IACtC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;IAE3C,IAAI,KAA0B,CAAC;IAC/B,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ,CACrC,SAAS,EACT,GAAG,OAAO,GAAG,iBAAiB,EAAE,EAChC,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,CACpC,CAAC;QACF,IAAI,MAAM,GAAG,GAAG,IAAI,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC;YACxD,GAAG,CACD,yCAAyC,OAAO,UAAU,MAAM,KAAK;gBACnE,mEAAmE;gBACnE,mBAAmB,CACtB,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,GAAG,IAA2B,CAAC;IACtC,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,GAAG,CACD,qBAAqB,OAAO,KAAK,GAAG,EAAE,OAAO,IAAI,GAAG,KAAK;YACvD,iCAAiC,CACpC,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,CAAC;IACtE,MAAM,gBAAgB,GAAG,SAAS,GAAG,IAAI,CAAC;IAC1C,MAAM,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAClC,CAAC,EACD,SAAS,IAAI,8BAA8B,CAC5C,CAAC;IACF,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;IAC/D,MAAM,aAAa,GAAG,MAAM,GAAG,gBAAgB,CAAC;IAChD,MAAM,QAAQ,GAAG,GAAG,EAAE,GAAG,MAAM,CAAC;IAEhC,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,GAAG,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAC;IAClC,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,GAAG,CAAC,iBAAiB,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC;IACxC,GAAG,CAAC,iBAAiB,KAAK,CAAC,yBAAyB,EAAE,CAAC,CAAC;IACxD,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,GAAG,CAAC,qCAAqC,CAAC,CAAC;IAE3C,OAAO,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QACxB,IAAI,IAAwB,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,QAAQ,CACrC,SAAS,EACT,GAAG,OAAO,GAAG,gBAAgB,EAAE,EAC/B,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CACnC,CAAC;YACF,IAAI,MAAM,GAAG,GAAG,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;gBAClC,GAAG,CACD,kCAAkC,MAAM,KAAK;oBAC3C,eAAe,CAAC,IAAI,EAAE,2BAA2B,CAAC,CACrD,CAAC;gBACF,OAAO,IAAI,CAAC;YACd,CAAC;YACD,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,CAAuB,CAAC;QAC/D,CAAC;QAAC,MAAM,CAAC;YACP,6DAA6D;YAC7D,IAAI,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;QAC/B,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,GAAG,OAAO,GAAG,QAAQ,EAAE,CAAC;YACtD,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,OAAO,CAAC;YAC9C,MAAM,OAAO,GACX,IAAI,CAAC,cAAc;gBACnB,OAAO,IAAI,CAAC,cAAc,KAAK,QAAQ;gBACvC,IAAI,CAAC,cAAc,CAAC,OAAO;gBAC3B,OAAO,IAAI,CAAC,cAAc,CAAC,OAAO,KAAK,QAAQ;gBAC7C,CAAC,CAAE,IAAI,CAAC,cAAc,CAAC,OAAkC;gBACzD,CAAC,CAAC,SAAS,CAAC;YAChB,GAAG,CAAC,aAAa,CAAC,CAAC;YACnB,OAAO,EAAE,KAAK,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;QACpE,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC9B,GAAG,CAAC,uDAAuD,CAAC,CAAC;YAC7D,GAAG,CAAC,mCAAmC,CAAC,CAAC;YACzC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC/B,GAAG,CAAC,8DAA8D,CAAC,CAAC;YACpE,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,IAAI,IAAI,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAC3D,GAAG,CACD,6BAA6B,eAAe,CAC1C,IAAI,EACJ,IAAI,CAAC,MAAM,KAAK,WAAW;gBACzB,CAAC,CAAC,4BAA4B;gBAC9B,CAAC,CAAC,2BAA2B,CAChC,EAAE,CACJ,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,WAAW,GAAG,QAAQ,GAAG,GAAG,EAAE,CAAC;QACrC,IAAI,WAAW,IAAI,CAAC;YAAE,MAAM;QAC5B,MAAM,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;IACtD,CAAC;IAED,IAAI,aAAa,EAAE,CAAC;QAClB,GAAG,CACD,2BAA2B,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,+BAA+B,CACpF,CAAC;QACF,GAAG,CAAC,sDAAsD,CAAC,CAAC;IAC9D,CAAC;SAAM,CAAC;QACN,GAAG,CAAC,mEAAmE,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAwB;IAExB,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IACzD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC;IAE7B,MAAM,OAAO,GAAyC,EAAE,CAAC;IACzD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,MAAM,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;IACzC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO;YACL,OAAO;YACP,aAAa;YACb,QAAQ,EAAE;gBACR,oBAAoB,UAAU,CAAC,UAAU,qCAAqC;aAC/E;SACF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,IAAI,QAAQ,CAAC;IAEjD,0EAA0E;IAC1E,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,mBAAmB,CACjB,IAAI,CAAC,OAAO,EACZ,IAAI,EACJ,MAAM,EACN,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,CACP,CAAC;QACF,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;IACxE,CAAC;IAED,uEAAuE;IACvE,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7E,8EAA8E;IAC9E,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,mBAAmB,CACjB,YAAY,EACZ,IAAI,EACJ,MAAM,EACN,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,CACP,CAAC;QACF,QAAQ,CAAC,IAAI,CACX,GAAG,eAAe,CAAC,YAAY,CAAC,kDAAkD,EAClF,+DAA+D,CAChE,CAAC;IACJ,CAAC;IAED,uBAAuB;IACvB,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;QAE3C,6EAA6E;QAC7E,2EAA2E;QAC3E,uEAAuE;QACvE,4EAA4E;QAC5E,4EAA4E;QAC5E,sEAAsE;QACtE,MAAM,UAAU,GAAG,WAAW,IAAI,CAAC,CAAC,OAAO,CAAC;QAE5C,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,IAAI,OAAO,EAAE,CAAC;gBACZ,QAAQ,CAAC,IAAI,CACX,GAAG,eAAe,CAAC,aAAa,CAAC,gEAAgE,EACjG,qBAAqB,CAAC,OAAO,EAAE,aAAa,EAAE,KAAK,CAAC,CACrD,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,CACX,GAAG,eAAe,CAAC,aAAa,CAAC,8EAA8E,CAChH,CAAC;YACJ,CAAC;QACH,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,UAAU,CAAC,UAAU,EAAE,OAAQ,CAAC,CAAC;YACjD,MAAM,SAAS,GAAG,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;YACxE,MAAM,KAAK,GAAG,MAAM,aAAa,CAC/B,OAAQ,EACR,OAAO,EACP,SAAS,EACT,GAAG,EACH,IAAI,CAAC,mBAAmB,EACxB,IAAI,CACL,CAAC;YAEF,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBACzB,wEAAwE;gBACxE,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC;gBAC3C,kBAAkB,CAChB,aAAa,EACb,IAAI,EACJ,WAAW,EACX,KAAK,CAAC,KAAK,EACX,KAAK,CAAC,OAAO,EACb,KAAK,EACL,OAAO,EACP,OAAO,EACP,MAAM,CACP,CAAC;gBACF,aAAa,GAAG,IAAI,CAAC;YACvB,CAAC;iBAAM,CAAC;gBACN,wEAAwE;gBACxE,uEAAuE;gBACvE,QAAQ,CAAC,IAAI,CACX,GAAG,eAAe,CAAC,aAAa,CAAC,4EAA4E,EAC7G,qBAAqB,CAAC,OAAQ,EAAE,aAAa,EAAE,KAAK,CAAC,CACtD,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC;AACxE,CAAC;AAED,SAAS,eAAe,CAAC,OAAmB;IAC1C,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,+DAA+D;AAC/D,SAAS,UAAU,CAAC,UAAyB,EAAE,OAAe;IAC5D,uEAAuE;IACvE,MAAM,IAAI,GAAG,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IACjE,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;QACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACjC,OAAO,KAAK,IAAI,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;IAClD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC","sourcesContent":["/**\n * MCP-server registration + authentication for `@agent-native/skills`.\n *\n * This is a dependency-free port of the MCP-config-writing + device-code/OAuth\n * flow that lives in `@agent-native/core`'s `cli/connect.ts`. The skills package\n * ships standalone (no `@agent-native/core` dependency), so this module\n * re-implements just the registration surface against the shared on-disk\n * writers in `./mcp-config-writers.js`. It writes the SAME config and speaks the\n * SAME device-code/OAuth protocol as core.\n *\n * Two client families, exactly as in core:\n * - OAuth-capable (claude-code, claude-code-cli): get a URL-only HTTP MCP\n * entry (no bearer headers). The user authenticates in-host via standard\n * remote MCP OAuth: restart Claude Code, run /mcp, choose Authenticate.\n * - Device-code (codex, cowork): run the browser device-code flow against the\n * descriptor's hosted URL, then write the entry WITH the minted bearer token\n * + headers. Non-interactive (or no TTY) skips the flow and writes a\n * URL-only entry, surfacing the exact `agent-native connect <url> --token`\n * fallback command.\n *\n * Server contract (identical paths + JSON field names to core):\n * POST <hostedUrl>/_agent-native/mcp/connect/device/start (no auth)\n * body { client?, app? }\n * → { device_code, user_code, verification_uri,\n * verification_uri_complete, interval, expires_in }\n * POST <hostedUrl>/_agent-native/mcp/connect/device/poll (no auth)\n * body { device_code }\n * → { status: \"pending\" }\n * | { status: \"approved\", token, mcpUrl, serverName, mcpServerEntry }\n * | { status: \"expired\" } | { status: \"consumed\" }\n * | { status: \"error\" | \"not_found\", message? }\n *\n * Node-only. Node built-ins + global fetch only; no npm deps.\n */\n\nimport { ClientId, writeHttpEntryForClient } from \"./mcp-config-writers.js\";\n\nconst DEVICE_START_PATH = \"/_agent-native/mcp/connect/device/start\";\nconst DEVICE_POLL_PATH = \"/_agent-native/mcp/connect/device/poll\";\nconst MCP_PATH = \"/_agent-native/mcp\";\n\n/** OAuth-capable clients (in-host remote MCP OAuth, never a local bearer). */\nconst REMOTE_MCP_OAUTH_CLIENTS = new Set<ClientId>([\n \"claude-code\",\n \"claude-code-cli\",\n]);\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Describes one MCP server to register. `serverName` is the canonical config\n * key; `aliases` are additional config keys that point at the same MCP URL\n * (e.g. `plan` + `agent-native-plans`). `hostedUrl` is the deployed app origin\n * the device-code flow authenticates against; `mcpUrl` is the resolved MCP\n * endpoint written into the config (defaults to `<hostedUrl>/_agent-native/mcp`\n * when only `hostedUrl` is supplied).\n */\nexport interface McpDescriptor {\n serverName: string;\n mcpUrl: string;\n aliases?: string[];\n authMode?: \"oauth\" | \"device\" | \"none\";\n hostedUrl?: string;\n}\n\nexport interface RegisterMcpOptions {\n descriptor: McpDescriptor;\n clients: ClientId[];\n scope: \"user\" | \"project\";\n baseDir: string;\n interactive: boolean;\n log?: (m: string) => void;\n deviceFlowTimeoutMs?: number;\n deps?: {\n fetchImpl?: typeof fetch;\n now?: () => number;\n sleep?: (ms: number) => Promise<void>;\n };\n}\n\nexport interface RegisterMcpResult {\n written: { client: ClientId; file: string }[];\n authenticated: boolean;\n guidance: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Device-code protocol shapes (field names match core EXACTLY).\n// ---------------------------------------------------------------------------\n\ninterface DeviceStartResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n interval?: number;\n expires_in?: number;\n}\n\ninterface DevicePollResponse {\n status:\n | \"pending\"\n | \"approved\"\n | \"expired\"\n | \"consumed\"\n | \"error\"\n | \"not_found\";\n token?: string;\n mcpUrl?: string;\n serverName?: string;\n mcpServerEntry?: Record<string, unknown>;\n message?: string;\n error?: string;\n}\n\ninterface DeviceGrant {\n token?: string;\n mcpUrl: string;\n serverName: string;\n headers?: Record<string, string>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nexport function supportsRemoteMcpOAuth(client: ClientId): boolean {\n return REMOTE_MCP_OAUTH_CLIENTS.has(client);\n}\n\nconst DEFAULT_DEVICE_FLOW_TIMEOUT_MS = 90_000;\n\nfunction realSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Trailing-slash-stripped origin+path for a hosted app URL. */\nfunction stripTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Resolve the MCP endpoint URL for a descriptor. Prefers an explicit `mcpUrl`,\n * otherwise derives `<hostedUrl>/_agent-native/mcp` (mirrors core's\n * `mcpUrlForBaseUrl`). Returns `undefined` when neither is usable.\n */\nfunction resolveMcpUrl(descriptor: McpDescriptor): string | undefined {\n if (descriptor.mcpUrl && descriptor.mcpUrl.trim()) {\n return descriptor.mcpUrl.trim();\n }\n if (descriptor.hostedUrl && descriptor.hostedUrl.trim()) {\n const base = stripTrailingSlash(descriptor.hostedUrl.trim());\n return `${base}${MCP_PATH}`;\n }\n return undefined;\n}\n\n/** Base (origin) URL of the deployed app the device flow runs against. */\nfunction resolveBaseUrl(descriptor: McpDescriptor): string | undefined {\n if (descriptor.hostedUrl && descriptor.hostedUrl.trim()) {\n return stripTrailingSlash(descriptor.hostedUrl.trim());\n }\n // Fall back to stripping the MCP path off an explicit mcpUrl.\n if (descriptor.mcpUrl && descriptor.mcpUrl.trim()) {\n const trimmed = stripTrailingSlash(descriptor.mcpUrl.trim());\n if (trimmed.endsWith(MCP_PATH)) {\n return trimmed.slice(0, -MCP_PATH.length);\n }\n }\n return undefined;\n}\n\n/** All config keys to register: the canonical name plus any aliases (deduped). */\nfunction configKeys(descriptor: McpDescriptor): string[] {\n const keys: string[] = [descriptor.serverName];\n for (const alias of descriptor.aliases ?? []) {\n if (alias && alias !== descriptor.serverName && !keys.includes(alias)) {\n keys.push(alias);\n }\n }\n return keys;\n}\n\nfunction responseMessage(json: any, fallback: string): string {\n const message =\n typeof json?.message === \"string\"\n ? json.message\n : typeof json?.error === \"string\"\n ? json.error\n : \"\";\n return message.trim() || fallback;\n}\n\nasync function postJson(\n fetchImpl: typeof fetch,\n url: string,\n body: unknown,\n): Promise<{ status: number; json: any }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 30_000);\n try {\n const response = await fetchImpl(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body ?? {}),\n signal: controller.signal,\n });\n let json: any = null;\n try {\n json = await response.json();\n } catch {\n json = null;\n }\n return { status: response.status, json };\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * The exact no-browser fallback command core prints. Surfaced as guidance when\n * a device-code client is asked to register non-interactively.\n */\nfunction clientArgForClients(clients: ClientId[]): string {\n return clients.length === 1 ? clients[0] : clients.join(\",\");\n}\n\nfunction fallbackConnectCommand(\n baseUrl: string,\n clients: ClientId[],\n scope: string,\n): string {\n return `npx @agent-native/core@latest connect ${baseUrl} --client ${clientArgForClients(\n clients,\n )} --scope ${scope}`;\n}\n\n/** Write a URL-only entry (no bearer) for every config key, collecting files. */\nfunction writeUrlOnlyEntries(\n clients: ClientId[],\n keys: string[],\n mcpUrl: string,\n scope: string,\n baseDir: string,\n written: { client: ClientId; file: string }[],\n errors: string[],\n): void {\n for (const client of clients) {\n for (const key of keys) {\n try {\n const file = writeHttpEntryForClient(\n client,\n key,\n mcpUrl,\n undefined,\n baseDir,\n scope,\n undefined,\n );\n written.push({ client, file });\n } catch (err: any) {\n errors.push(\n `Could not write ${key} for ${client}: ${err?.message ?? err}`,\n );\n }\n }\n }\n}\n\nfunction manualConnectGuidance(\n baseUrl: string,\n clients: ClientId[],\n scope: string,\n): string {\n return (\n `To authenticate ${describeClients(clients)}, run: ` +\n fallbackConnectCommand(baseUrl, clients, scope)\n );\n}\n\n/** Write a token+headers entry for every config key, collecting files. */\nfunction writeAuthedEntries(\n clients: ClientId[],\n keys: string[],\n mcpUrl: string,\n token: string | undefined,\n headers: Record<string, string> | undefined,\n scope: string,\n baseDir: string,\n written: { client: ClientId; file: string }[],\n errors: string[],\n): void {\n for (const client of clients) {\n for (const key of keys) {\n try {\n const file = writeHttpEntryForClient(\n client,\n key,\n mcpUrl,\n token,\n baseDir,\n scope,\n headers,\n );\n written.push({ client, file });\n } catch (err: any) {\n errors.push(\n `Could not write ${key} for ${client}: ${err?.message ?? err}`,\n );\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Device-code flow (dependency-free port of core's runDeviceFlow)\n// ---------------------------------------------------------------------------\n\n/**\n * Run the device-code flow against `baseUrl` and return the approved grant, or\n * `null` (after logging a clear message) on expiry/consumed/error/timeout. Same\n * state machine and field handling as core; the spinner/browser-open are\n * dropped since this runs inside a non-interactive installer context.\n */\nasync function runDeviceFlow(\n baseUrl: string,\n appSlug: string,\n clientArg: string,\n log: (m: string) => void,\n timeoutMs: number | undefined,\n deps: RegisterMcpOptions[\"deps\"] = {},\n): Promise<DeviceGrant | null> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const sleep = deps.sleep ?? realSleep;\n const now = deps.now ?? (() => Date.now());\n\n let start: DeviceStartResponse;\n try {\n const { status, json } = await postJson(\n fetchImpl,\n `${baseUrl}${DEVICE_START_PATH}`,\n { client: clientArg, app: appSlug },\n );\n if (status < 200 || status >= 300 || !json?.device_code) {\n log(\n ` Could not start the connect flow on ${baseUrl} (HTTP ${status}). ` +\n `Is this an agent-native app, and is it deployed with the connect ` +\n `endpoint enabled?`,\n );\n return null;\n }\n start = json as DeviceStartResponse;\n } catch (err: any) {\n log(\n ` Could not reach ${baseUrl} (${err?.message ?? err}). ` +\n `Check the URL and your network.`,\n );\n return null;\n }\n\n const interval = Math.max(1, Number(start.interval) || 5);\n const expiresIn = Math.max(interval, Number(start.expires_in) || 600);\n const serverDeadlineMs = expiresIn * 1000;\n const installerDeadlineMs = Math.max(\n 0,\n timeoutMs ?? DEFAULT_DEVICE_FLOW_TIMEOUT_MS,\n );\n const waitMs = Math.min(serverDeadlineMs, installerDeadlineMs);\n const waitWasCapped = waitMs < serverDeadlineMs;\n const deadline = now() + waitMs;\n\n log(\"\");\n log(` Connecting to ${baseUrl}`);\n log(\"\");\n log(` Your code: ${start.user_code}`);\n log(` Open: ${start.verification_uri_complete}`);\n log(\"\");\n log(\" Approve in the browser to finish.\");\n\n while (now() < deadline) {\n let poll: DevicePollResponse;\n try {\n const { status, json } = await postJson(\n fetchImpl,\n `${baseUrl}${DEVICE_POLL_PATH}`,\n { device_code: start.device_code },\n );\n if (status < 200 || status >= 300) {\n log(\n ` Connect polling failed (HTTP ${status}): ` +\n responseMessage(json, \"server returned an error.\"),\n );\n return null;\n }\n poll = (json ?? { status: \"pending\" }) as DevicePollResponse;\n } catch {\n // Transient network error — keep polling until the deadline.\n poll = { status: \"pending\" };\n }\n\n if (poll.status === \"approved\") {\n const token = poll.token ?? \"\";\n const mcpUrl = poll.mcpUrl ?? `${baseUrl}${MCP_PATH}`;\n const serverName = poll.serverName ?? appSlug;\n const headers =\n poll.mcpServerEntry &&\n typeof poll.mcpServerEntry === \"object\" &&\n poll.mcpServerEntry.headers &&\n typeof poll.mcpServerEntry.headers === \"object\"\n ? (poll.mcpServerEntry.headers as Record<string, string>)\n : undefined;\n log(\" Approved.\");\n return { token: token || undefined, mcpUrl, serverName, headers };\n }\n if (poll.status === \"expired\") {\n log(\" The connect request expired before it was approved.\");\n log(\" Run the command again to retry.\");\n return null;\n }\n if (poll.status === \"consumed\") {\n log(\" This connect code was already used. Run the command again.\");\n return null;\n }\n if (poll.status === \"error\" || poll.status === \"not_found\") {\n log(\n ` Connect polling failed: ${responseMessage(\n poll,\n poll.status === \"not_found\"\n ? \"device code was not found.\"\n : \"server returned an error.\",\n )}`,\n );\n return null;\n }\n\n const remainingMs = deadline - now();\n if (remainingMs <= 0) break;\n await sleep(Math.min(interval * 1000, remainingMs));\n }\n\n if (waitWasCapped) {\n log(\n ` Stopped waiting after ${Math.round(waitMs / 1000)}s so installation can finish.`,\n );\n log(\" You can authenticate later with the command below.\");\n } else {\n log(\" Timed out waiting for approval. Run the command again to retry.\");\n }\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Public entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Register an MCP server (plus aliases) into the requested client configs,\n * authenticating device-code clients via the browser flow when interactive.\n *\n * Idempotent: re-running replaces the same named entries. Never throws on a\n * single client/key failing — failures are collected into `guidance`.\n */\nexport async function registerMcpServer(\n opts: RegisterMcpOptions,\n): Promise<RegisterMcpResult> {\n const { descriptor, scope, baseDir, interactive } = opts;\n const log = opts.log ?? (() => {});\n const deps = opts.deps ?? {};\n\n const written: { client: ClientId; file: string }[] = [];\n const guidance: string[] = [];\n const errors: string[] = [];\n let authenticated = false;\n\n const keys = configKeys(descriptor);\n const mcpUrl = resolveMcpUrl(descriptor);\n if (!mcpUrl) {\n return {\n written,\n authenticated,\n guidance: [\n `Cannot register \"${descriptor.serverName}\": no mcpUrl or hostedUrl supplied.`,\n ],\n };\n }\n\n const authMode = descriptor.authMode ?? \"device\";\n\n // authMode \"none\" (e.g. context-xray): URL-only for ALL clients, no auth.\n if (authMode === \"none\") {\n writeUrlOnlyEntries(\n opts.clients,\n keys,\n mcpUrl,\n scope,\n baseDir,\n written,\n errors,\n );\n return { written, authenticated, guidance: [...guidance, ...errors] };\n }\n\n // Split into OAuth-capable and device-code clients, exactly like core.\n const oauthClients = opts.clients.filter((c) => supportsRemoteMcpOAuth(c));\n const deviceClients = opts.clients.filter((c) => !supportsRemoteMcpOAuth(c));\n\n // OAuth clients always get URL-only entries (in-host OAuth, no local bearer).\n if (oauthClients.length > 0) {\n writeUrlOnlyEntries(\n oauthClients,\n keys,\n mcpUrl,\n scope,\n baseDir,\n written,\n errors,\n );\n guidance.push(\n `${describeClients(oauthClients)}: wrote URL-only MCP config (no bearer headers).`,\n \"Next: restart Claude Code, run /mcp, and choose Authenticate.\",\n );\n }\n\n // Device-code clients.\n if (deviceClients.length > 0) {\n const baseUrl = resolveBaseUrl(descriptor);\n\n // We only reach here for authMode \"oauth\"/\"device\" (authMode \"none\" returned\n // earlier). Run the flow only when interactive AND we have a hosted URL to\n // authenticate against. Device-code clients such as Codex cannot use a\n // URL-only hosted entry: writing one would overwrite a working bearer token\n // and leave new sessions unauthenticated. If auth cannot complete, keep the\n // existing config untouched and surface the explicit connect command.\n const canRunFlow = interactive && !!baseUrl;\n\n if (!canRunFlow) {\n if (baseUrl) {\n guidance.push(\n `${describeClients(deviceClients)}: skipped MCP config because this client needs a bearer token.`,\n manualConnectGuidance(baseUrl, deviceClients, scope),\n );\n } else {\n guidance.push(\n `${describeClients(deviceClients)}: skipped MCP config because no hosted URL was available for authentication.`,\n );\n }\n } else {\n const appSlug = appSlugFor(descriptor, baseUrl!);\n const clientArg = deviceClients.length === 1 ? deviceClients[0] : \"all\";\n const grant = await runDeviceFlow(\n baseUrl!,\n appSlug,\n clientArg,\n log,\n opts.deviceFlowTimeoutMs,\n deps,\n );\n\n if (grant && grant.token) {\n // Write authed entries; honour the server's resolved mcpUrl when given.\n const resolvedUrl = grant.mcpUrl || mcpUrl;\n writeAuthedEntries(\n deviceClients,\n keys,\n resolvedUrl,\n grant.token,\n grant.headers,\n scope,\n baseDir,\n written,\n errors,\n );\n authenticated = true;\n } else {\n // Flow failed (or approved with no token). Do not downgrade device-code\n // clients to a URL-only hosted entry; keep any existing bearer config.\n guidance.push(\n `${describeClients(deviceClients)}: authentication did not complete; existing MCP config was left unchanged.`,\n manualConnectGuidance(baseUrl!, deviceClients, scope),\n );\n }\n }\n }\n\n return { written, authenticated, guidance: [...guidance, ...errors] };\n}\n\nfunction describeClients(clients: ClientId[]): string {\n return clients.join(\", \");\n}\n\n/** Derive the `app` slug the device-start endpoint expects. */\nfunction appSlugFor(descriptor: McpDescriptor, baseUrl: string): string {\n // Prefer the descriptor's server name without the agent-native prefix.\n const name = descriptor.serverName.replace(/^agent-native-/, \"\");\n if (name) return name;\n try {\n const host = new URL(baseUrl).hostname;\n const first = host.split(\".\")[0];\n return first && first !== \"www\" ? first : \"app\";\n } catch {\n return \"app\";\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../src/connect.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MCP-server registration + authentication for `@agent-native/skills`.\n *\n * This is a dependency-free port of the MCP-config-writing + device-code/OAuth\n * flow that lives in `@agent-native/core`'s `cli/connect.ts`. The skills package\n * ships standalone (no `@agent-native/core` dependency), so this module\n * re-implements just the registration surface against the shared on-disk\n * writers in `./mcp-config-writers.js`. It writes the SAME config and speaks the\n * SAME device-code/OAuth protocol as core.\n *\n * Two client families, exactly as in core:\n * - OAuth-capable (Claude Code, Cursor, OpenCode, GitHub Copilot / VS Code):\n * get a URL-only HTTP MCP entry (no bearer headers). The user authenticates\n * in-host via standard remote MCP OAuth.\n * - Device-code (codex, cowork): run the browser device-code flow against the\n * descriptor's hosted URL, then write the entry WITH the minted bearer token\n * + headers. Non-interactive (or no TTY) skips writing device-code configs,\n * surfacing the exact `agent-native connect <url>` fallback command.\n *\n * Server contract (identical paths + JSON field names to core):\n * POST <hostedUrl>/_agent-native/mcp/connect/device/start (no auth)\n * body { client?, app? }\n * → { device_code, user_code, verification_uri,\n * verification_uri_complete, interval, expires_in }\n * POST <hostedUrl>/_agent-native/mcp/connect/device/poll (no auth)\n * body { device_code }\n * → { status: \"pending\" }\n * | { status: \"approved\", token, mcpUrl, serverName, mcpServerEntry }\n * | { status: \"expired\" } | { status: \"consumed\" }\n * | { status: \"error\" | \"not_found\", message? }\n *\n * Node-only. Node built-ins + global fetch only; no npm deps.\n */\n\nimport { ClientId, writeHttpEntryForClient } from \"./mcp-config-writers.js\";\n\nconst DEVICE_START_PATH = \"/_agent-native/mcp/connect/device/start\";\nconst DEVICE_POLL_PATH = \"/_agent-native/mcp/connect/device/poll\";\nconst MCP_PATH = \"/_agent-native/mcp\";\n\n/** OAuth-capable clients (in-host remote MCP OAuth, never a local bearer). */\nconst REMOTE_MCP_OAUTH_CLIENTS = new Set<ClientId>([\n \"claude-code\",\n \"claude-code-cli\",\n \"cursor\",\n \"opencode\",\n \"github-copilot\",\n]);\n\nconst CLIENT_LABELS: Record<ClientId, string> = {\n \"claude-code\": \"Claude Code\",\n \"claude-code-cli\": \"Claude Code CLI\",\n codex: \"Codex\",\n cowork: \"Claude Cowork\",\n cursor: \"Cursor\",\n opencode: \"OpenCode\",\n \"github-copilot\": \"GitHub Copilot / VS Code\",\n};\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Describes one MCP server to register. `serverName` is the canonical config\n * key; `aliases` are additional config keys that point at the same MCP URL\n * (e.g. `plan` + `agent-native-plans`). `hostedUrl` is the deployed app origin\n * the device-code flow authenticates against; `mcpUrl` is the resolved MCP\n * endpoint written into the config (defaults to `<hostedUrl>/_agent-native/mcp`\n * when only `hostedUrl` is supplied).\n */\nexport interface McpDescriptor {\n serverName: string;\n mcpUrl: string;\n aliases?: string[];\n authMode?: \"oauth\" | \"device\" | \"none\";\n hostedUrl?: string;\n}\n\nexport interface RegisterMcpOptions {\n descriptor: McpDescriptor;\n clients: ClientId[];\n scope: \"user\" | \"project\";\n baseDir: string;\n interactive: boolean;\n log?: (m: string) => void;\n deviceFlowTimeoutMs?: number;\n deps?: {\n fetchImpl?: typeof fetch;\n now?: () => number;\n sleep?: (ms: number) => Promise<void>;\n };\n}\n\nexport interface RegisterMcpResult {\n written: { client: ClientId; file: string }[];\n authenticated: boolean;\n guidance: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Device-code protocol shapes (field names match core EXACTLY).\n// ---------------------------------------------------------------------------\n\ninterface DeviceStartResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n interval?: number;\n expires_in?: number;\n}\n\ninterface DevicePollResponse {\n status:\n | \"pending\"\n | \"approved\"\n | \"expired\"\n | \"consumed\"\n | \"error\"\n | \"not_found\";\n token?: string;\n mcpUrl?: string;\n serverName?: string;\n mcpServerEntry?: Record<string, unknown>;\n message?: string;\n error?: string;\n}\n\ninterface DeviceGrant {\n token?: string;\n mcpUrl: string;\n serverName: string;\n headers?: Record<string, string>;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nexport function supportsRemoteMcpOAuth(client: ClientId): boolean {\n return REMOTE_MCP_OAUTH_CLIENTS.has(client);\n}\n\nconst DEFAULT_DEVICE_FLOW_TIMEOUT_MS = 90_000;\n\nfunction realSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** Trailing-slash-stripped origin+path for a hosted app URL. */\nfunction stripTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Resolve the MCP endpoint URL for a descriptor. Prefers an explicit `mcpUrl`,\n * otherwise derives `<hostedUrl>/_agent-native/mcp` (mirrors core's\n * `mcpUrlForBaseUrl`). Returns `undefined` when neither is usable.\n */\nfunction resolveMcpUrl(descriptor: McpDescriptor): string | undefined {\n if (descriptor.mcpUrl && descriptor.mcpUrl.trim()) {\n return descriptor.mcpUrl.trim();\n }\n if (descriptor.hostedUrl && descriptor.hostedUrl.trim()) {\n const base = stripTrailingSlash(descriptor.hostedUrl.trim());\n return `${base}${MCP_PATH}`;\n }\n return undefined;\n}\n\n/** Base (origin) URL of the deployed app the device flow runs against. */\nfunction resolveBaseUrl(descriptor: McpDescriptor): string | undefined {\n if (descriptor.hostedUrl && descriptor.hostedUrl.trim()) {\n return stripTrailingSlash(descriptor.hostedUrl.trim());\n }\n // Fall back to stripping the MCP path off an explicit mcpUrl.\n if (descriptor.mcpUrl && descriptor.mcpUrl.trim()) {\n const trimmed = stripTrailingSlash(descriptor.mcpUrl.trim());\n if (trimmed.endsWith(MCP_PATH)) {\n return trimmed.slice(0, -MCP_PATH.length);\n }\n }\n return undefined;\n}\n\n/** All config keys to register: the canonical name plus any aliases (deduped). */\nfunction configKeys(descriptor: McpDescriptor): string[] {\n const keys: string[] = [descriptor.serverName];\n for (const alias of descriptor.aliases ?? []) {\n if (alias && alias !== descriptor.serverName && !keys.includes(alias)) {\n keys.push(alias);\n }\n }\n return keys;\n}\n\nfunction responseMessage(json: any, fallback: string): string {\n const message =\n typeof json?.message === \"string\"\n ? json.message\n : typeof json?.error === \"string\"\n ? json.error\n : \"\";\n return message.trim() || fallback;\n}\n\nasync function postJson(\n fetchImpl: typeof fetch,\n url: string,\n body: unknown,\n): Promise<{ status: number; json: any }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 30_000);\n try {\n const response = await fetchImpl(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body ?? {}),\n signal: controller.signal,\n });\n let json: any = null;\n try {\n json = await response.json();\n } catch {\n json = null;\n }\n return { status: response.status, json };\n } finally {\n clearTimeout(timeout);\n }\n}\n\n/**\n * The exact no-browser fallback command core prints. Surfaced as guidance when\n * a device-code client is asked to register non-interactively.\n */\nfunction clientArgForClients(clients: ClientId[]): string {\n return clients.length === 1 ? clients[0] : clients.join(\",\");\n}\n\nfunction fallbackConnectCommand(\n baseUrl: string,\n clients: ClientId[],\n scope: string,\n): string {\n return `npx @agent-native/core@latest connect ${baseUrl} --client ${clientArgForClients(\n clients,\n )} --scope ${scope}`;\n}\n\n/** Write a URL-only entry (no bearer) for every config key, collecting files. */\nfunction writeUrlOnlyEntries(\n clients: ClientId[],\n keys: string[],\n mcpUrl: string,\n scope: string,\n baseDir: string,\n written: { client: ClientId; file: string }[],\n errors: string[],\n): void {\n for (const client of clients) {\n for (const key of keys) {\n try {\n const file = writeHttpEntryForClient(\n client,\n key,\n mcpUrl,\n undefined,\n baseDir,\n scope,\n undefined,\n );\n written.push({ client, file });\n } catch (err: any) {\n errors.push(\n `Could not write ${key} for ${client}: ${err?.message ?? err}`,\n );\n }\n }\n }\n}\n\nfunction manualConnectGuidance(\n baseUrl: string,\n clients: ClientId[],\n scope: string,\n): string {\n return (\n `To authenticate ${describeClients(clients)}, run: ` +\n fallbackConnectCommand(baseUrl, clients, scope)\n );\n}\n\nfunction oauthNextStepsForClients(\n clients: ClientId[],\n serverName?: string,\n): string[] {\n const lines: string[] = [];\n if (clients.includes(\"claude-code\") || clients.includes(\"claude-code-cli\")) {\n lines.push(\n \"Claude Code: restart Claude Code, run /mcp, and choose Authenticate.\",\n );\n }\n if (clients.includes(\"cursor\")) {\n lines.push(\n \"Cursor: restart or reload Cursor, then authenticate the MCP server from Cursor MCP settings if prompted.\",\n );\n }\n if (clients.includes(\"opencode\")) {\n lines.push(\n `OpenCode: run opencode mcp auth ${serverName ?? \"<server-name>\"} or authenticate on first use.`,\n );\n }\n if (clients.includes(\"github-copilot\")) {\n lines.push(\n \"GitHub Copilot / VS Code: reload VS Code, open the MCP config, and use the Auth action above the server if prompted.\",\n );\n }\n return lines;\n}\n\n/** Write a token+headers entry for every config key, collecting files. */\nfunction writeAuthedEntries(\n clients: ClientId[],\n keys: string[],\n mcpUrl: string,\n token: string | undefined,\n headers: Record<string, string> | undefined,\n scope: string,\n baseDir: string,\n written: { client: ClientId; file: string }[],\n errors: string[],\n): void {\n for (const client of clients) {\n for (const key of keys) {\n try {\n const file = writeHttpEntryForClient(\n client,\n key,\n mcpUrl,\n token,\n baseDir,\n scope,\n headers,\n );\n written.push({ client, file });\n } catch (err: any) {\n errors.push(\n `Could not write ${key} for ${client}: ${err?.message ?? err}`,\n );\n }\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Device-code flow (dependency-free port of core's runDeviceFlow)\n// ---------------------------------------------------------------------------\n\n/**\n * Run the device-code flow against `baseUrl` and return the approved grant, or\n * `null` (after logging a clear message) on expiry/consumed/error/timeout. Same\n * state machine and field handling as core; the spinner/browser-open are\n * dropped since this runs inside a non-interactive installer context.\n */\nasync function runDeviceFlow(\n baseUrl: string,\n appSlug: string,\n clientArg: string,\n log: (m: string) => void,\n timeoutMs: number | undefined,\n deps: RegisterMcpOptions[\"deps\"] = {},\n): Promise<DeviceGrant | null> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const sleep = deps.sleep ?? realSleep;\n const now = deps.now ?? (() => Date.now());\n\n let start: DeviceStartResponse;\n try {\n const { status, json } = await postJson(\n fetchImpl,\n `${baseUrl}${DEVICE_START_PATH}`,\n { client: clientArg, app: appSlug },\n );\n if (status < 200 || status >= 300 || !json?.device_code) {\n log(\n ` Could not start the connect flow on ${baseUrl} (HTTP ${status}). ` +\n `Is this an agent-native app, and is it deployed with the connect ` +\n `endpoint enabled?`,\n );\n return null;\n }\n start = json as DeviceStartResponse;\n } catch (err: any) {\n log(\n ` Could not reach ${baseUrl} (${err?.message ?? err}). ` +\n `Check the URL and your network.`,\n );\n return null;\n }\n\n const interval = Math.max(1, Number(start.interval) || 5);\n const expiresIn = Math.max(interval, Number(start.expires_in) || 600);\n const serverDeadlineMs = expiresIn * 1000;\n const installerDeadlineMs = Math.max(\n 0,\n timeoutMs ?? DEFAULT_DEVICE_FLOW_TIMEOUT_MS,\n );\n const waitMs = Math.min(serverDeadlineMs, installerDeadlineMs);\n const waitWasCapped = waitMs < serverDeadlineMs;\n const deadline = now() + waitMs;\n\n log(\"\");\n log(` Connecting to ${baseUrl}`);\n log(\"\");\n log(` Your code: ${start.user_code}`);\n log(` Open: ${start.verification_uri_complete}`);\n log(\"\");\n log(\" Approve in the browser to finish.\");\n\n while (now() < deadline) {\n let poll: DevicePollResponse;\n try {\n const { status, json } = await postJson(\n fetchImpl,\n `${baseUrl}${DEVICE_POLL_PATH}`,\n { device_code: start.device_code },\n );\n if (status < 200 || status >= 300) {\n if (isTerminalPollBody(json)) {\n poll = json as DevicePollResponse;\n } else {\n log(\n ` Connect polling failed (HTTP ${status}): ` +\n responseMessage(json, \"server returned an error.\"),\n );\n return null;\n }\n } else {\n poll = (json ?? { status: \"pending\" }) as DevicePollResponse;\n }\n } catch {\n // Transient network error — keep polling until the deadline.\n poll = { status: \"pending\" };\n }\n\n if (poll.status === \"approved\") {\n const token = poll.token ?? \"\";\n const mcpUrl = poll.mcpUrl ?? `${baseUrl}${MCP_PATH}`;\n const serverName = poll.serverName ?? appSlug;\n const headers =\n poll.mcpServerEntry &&\n typeof poll.mcpServerEntry === \"object\" &&\n poll.mcpServerEntry.headers &&\n typeof poll.mcpServerEntry.headers === \"object\"\n ? (poll.mcpServerEntry.headers as Record<string, string>)\n : undefined;\n log(\" Approved.\");\n return { token: token || undefined, mcpUrl, serverName, headers };\n }\n if (poll.status === \"expired\") {\n log(\" The connect request expired before it was approved.\");\n log(\" Run the command again to retry.\");\n return null;\n }\n if (poll.status === \"consumed\") {\n log(\" This connect code was already used. Run the command again.\");\n return null;\n }\n if (poll.status === \"error\" || poll.status === \"not_found\") {\n log(\n ` Connect polling failed: ${responseMessage(\n poll,\n poll.status === \"not_found\"\n ? \"device code was not found.\"\n : \"server returned an error.\",\n )}`,\n );\n return null;\n }\n\n const remainingMs = deadline - now();\n if (remainingMs <= 0) break;\n await sleep(Math.min(interval * 1000, remainingMs));\n }\n\n if (waitWasCapped) {\n log(\n ` Stopped waiting after ${Math.round(waitMs / 1000)}s so installation can finish.`,\n );\n log(\" You can authenticate later with the command below.\");\n } else {\n log(\" Timed out waiting for approval. Run the command again to retry.\");\n }\n return null;\n}\n\nfunction isTerminalPollBody(json: any): boolean {\n return (\n json?.status === \"not_found\" ||\n json?.status === \"error\" ||\n json?.status === \"expired\" ||\n json?.status === \"consumed\"\n );\n}\n\n// ---------------------------------------------------------------------------\n// Public entry point\n// ---------------------------------------------------------------------------\n\n/**\n * Register an MCP server (plus aliases) into the requested client configs,\n * authenticating device-code clients via the browser flow when interactive.\n *\n * Idempotent: re-running replaces the same named entries. Never throws on a\n * single client/key failing — failures are collected into `guidance`.\n */\nexport async function registerMcpServer(\n opts: RegisterMcpOptions,\n): Promise<RegisterMcpResult> {\n const { descriptor, scope, baseDir, interactive } = opts;\n const log = opts.log ?? (() => {});\n const deps = opts.deps ?? {};\n\n const written: { client: ClientId; file: string }[] = [];\n const guidance: string[] = [];\n const errors: string[] = [];\n let authenticated = false;\n\n const keys = configKeys(descriptor);\n const mcpUrl = resolveMcpUrl(descriptor);\n if (!mcpUrl) {\n return {\n written,\n authenticated,\n guidance: [\n `Cannot register \"${descriptor.serverName}\": no mcpUrl or hostedUrl supplied.`,\n ],\n };\n }\n\n const authMode = descriptor.authMode ?? \"device\";\n\n // authMode \"none\" (e.g. context-xray): URL-only for ALL clients, no auth.\n if (authMode === \"none\") {\n writeUrlOnlyEntries(\n opts.clients,\n keys,\n mcpUrl,\n scope,\n baseDir,\n written,\n errors,\n );\n return { written, authenticated, guidance: [...guidance, ...errors] };\n }\n\n // Split into OAuth-capable and device-code clients, exactly like core.\n const oauthClients = opts.clients.filter((c) => supportsRemoteMcpOAuth(c));\n const deviceClients = opts.clients.filter((c) => !supportsRemoteMcpOAuth(c));\n\n // OAuth clients always get URL-only entries (in-host OAuth, no local bearer).\n if (oauthClients.length > 0) {\n writeUrlOnlyEntries(\n oauthClients,\n keys,\n mcpUrl,\n scope,\n baseDir,\n written,\n errors,\n );\n guidance.push(\n `${describeClients(oauthClients)}: wrote URL-only MCP config (no bearer headers).`,\n ...oauthNextStepsForClients(oauthClients, descriptor.serverName),\n );\n }\n\n // Device-code clients.\n if (deviceClients.length > 0) {\n const baseUrl = resolveBaseUrl(descriptor);\n\n // We only reach here for authMode \"oauth\"/\"device\" (authMode \"none\" returned\n // earlier). Run the flow only when interactive AND we have a hosted URL to\n // authenticate against. Device-code clients such as Codex cannot use a\n // URL-only hosted entry: writing one would overwrite a working bearer token\n // and leave new sessions unauthenticated. If auth cannot complete, keep the\n // existing config untouched and surface the explicit connect command.\n const canRunFlow = interactive && !!baseUrl;\n\n if (!canRunFlow) {\n if (baseUrl) {\n guidance.push(\n `${describeClients(deviceClients)}: skipped MCP config because this client needs a bearer token.`,\n manualConnectGuidance(baseUrl, deviceClients, scope),\n );\n } else {\n guidance.push(\n `${describeClients(deviceClients)}: skipped MCP config because no hosted URL was available for authentication.`,\n );\n }\n } else {\n const appSlug = appSlugFor(descriptor, baseUrl!);\n const clientArg = deviceClients.length === 1 ? deviceClients[0] : \"all\";\n const grant = await runDeviceFlow(\n baseUrl!,\n appSlug,\n clientArg,\n log,\n opts.deviceFlowTimeoutMs,\n deps,\n );\n\n if (grant && grant.token) {\n // Write authed entries; honour the server's resolved mcpUrl when given.\n const resolvedUrl = grant.mcpUrl || mcpUrl;\n writeAuthedEntries(\n deviceClients,\n keys,\n resolvedUrl,\n grant.token,\n grant.headers,\n scope,\n baseDir,\n written,\n errors,\n );\n authenticated = true;\n } else {\n // Flow failed (or approved with no token). Do not downgrade device-code\n // clients to a URL-only hosted entry; keep any existing bearer config.\n guidance.push(\n `${describeClients(deviceClients)}: authentication did not complete; existing MCP config was left unchanged.`,\n manualConnectGuidance(baseUrl!, deviceClients, scope),\n );\n }\n }\n }\n\n return { written, authenticated, guidance: [...guidance, ...errors] };\n}\n\nfunction describeClients(clients: ClientId[]): string {\n return clients.map((client) => CLIENT_LABELS[client]).join(\", \");\n}\n\n/** Derive the `app` slug the device-start endpoint expects. */\nfunction appSlugFor(descriptor: McpDescriptor, baseUrl: string): string {\n // Prefer the descriptor's server name without the agent-native prefix.\n const name = descriptor.serverName.replace(/^agent-native-/, \"\");\n if (name) return name;\n try {\n const host = new URL(baseUrl).hostname;\n const first = host.split(\".\")[0];\n return first && first !== \"www\" ? first : \"app\";\n } catch {\n return \"app\";\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CliTelemetry } from "./telemetry.js";
|
|
2
|
-
export type SkillClient = "codex" | "claude-code";
|
|
2
|
+
export type SkillClient = "codex" | "claude-code" | "cowork" | "pi" | "cursor" | "opencode" | "github-copilot";
|
|
3
3
|
export type SkillScope = "project" | "user";
|
|
4
4
|
export type PlanMode = "hosted" | "local-files" | "self-hosted";
|
|
5
5
|
export interface SkillEntry {
|
|
@@ -82,6 +82,7 @@ interface ParsedArgs {
|
|
|
82
82
|
mcp: boolean;
|
|
83
83
|
planMode?: PlanMode;
|
|
84
84
|
mcpUrl?: string;
|
|
85
|
+
quiet: boolean;
|
|
85
86
|
}
|
|
86
87
|
interface PromptOption<T extends string> {
|
|
87
88
|
value: T;
|
|
@@ -101,6 +102,8 @@ export interface ScopePromptContext {
|
|
|
101
102
|
}
|
|
102
103
|
export interface GithubActionPromptContext {
|
|
103
104
|
workflowPath: string;
|
|
105
|
+
setupCommand: string;
|
|
106
|
+
docsUrl: string;
|
|
104
107
|
}
|
|
105
108
|
export interface PlanModePromptContext {
|
|
106
109
|
initialMode: PlanMode;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAsB,KAAK,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEvE,MAAM,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|