@agent-native/core 0.48.3 → 0.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/dist/agent/context-xray/actions/context-evict.d.ts +1 -1
  2. package/dist/agent/context-xray/actions/context-pin.d.ts +1 -1
  3. package/dist/agent/context-xray/actions/context-report.d.ts +4 -4
  4. package/dist/agent/context-xray/actions/context-restore.d.ts +1 -1
  5. package/dist/application-state/handlers.d.ts +2 -2
  6. package/dist/application-state/handlers.d.ts.map +1 -1
  7. package/dist/cli/app-skill.d.ts +157 -0
  8. package/dist/cli/app-skill.d.ts.map +1 -0
  9. package/dist/cli/app-skill.js +17 -7
  10. package/dist/cli/app-skill.js.map +1 -1
  11. package/dist/cli/audit-agent-web.d.ts +2 -0
  12. package/dist/cli/audit-agent-web.d.ts.map +1 -0
  13. package/dist/cli/code-agent-connector.d.ts +17 -0
  14. package/dist/cli/code-agent-connector.d.ts.map +1 -0
  15. package/dist/cli/code.d.ts +66 -0
  16. package/dist/cli/code.d.ts.map +1 -0
  17. package/dist/cli/connect.d.ts +168 -0
  18. package/dist/cli/connect.d.ts.map +1 -0
  19. package/dist/cli/connect.js +118 -30
  20. package/dist/cli/connect.js.map +1 -1
  21. package/dist/cli/context-xray-local.d.ts +16 -0
  22. package/dist/cli/context-xray-local.d.ts.map +1 -0
  23. package/dist/cli/create-workspace.d.ts +8 -0
  24. package/dist/cli/create-workspace.d.ts.map +1 -0
  25. package/dist/cli/index.d.ts +3 -0
  26. package/dist/cli/index.d.ts.map +1 -0
  27. package/dist/cli/info.d.ts +2 -0
  28. package/dist/cli/info.d.ts.map +1 -0
  29. package/dist/cli/mcp-config-writers.d.ts +108 -0
  30. package/dist/cli/mcp-config-writers.d.ts.map +1 -0
  31. package/dist/cli/mcp-config-writers.js +143 -0
  32. package/dist/cli/mcp-config-writers.js.map +1 -1
  33. package/dist/cli/mcp.d.ts +16 -0
  34. package/dist/cli/mcp.d.ts.map +1 -0
  35. package/dist/cli/mcp.js +10 -10
  36. package/dist/cli/mcp.js.map +1 -1
  37. package/dist/cli/migrate.d.ts +38 -0
  38. package/dist/cli/migrate.d.ts.map +1 -0
  39. package/dist/cli/plan-local.d.ts +43 -0
  40. package/dist/cli/plan-local.d.ts.map +1 -0
  41. package/dist/cli/plan-publish-store.d.ts +62 -0
  42. package/dist/cli/plan-publish-store.d.ts.map +1 -0
  43. package/dist/cli/pr-visual-recap-workflow.d.ts +11 -0
  44. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -0
  45. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  46. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  47. package/dist/cli/recap.d.ts +453 -0
  48. package/dist/cli/recap.d.ts.map +1 -0
  49. package/dist/cli/recap.js +228 -95
  50. package/dist/cli/recap.js.map +1 -1
  51. package/dist/cli/skills.d.ts +193 -0
  52. package/dist/cli/skills.d.ts.map +1 -0
  53. package/dist/cli/skills.js +518 -177
  54. package/dist/cli/skills.js.map +1 -1
  55. package/dist/cli/telemetry.d.ts +13 -0
  56. package/dist/cli/telemetry.d.ts.map +1 -0
  57. package/dist/cli/telemetry.js +115 -0
  58. package/dist/cli/telemetry.js.map +1 -0
  59. package/dist/cli/workspace-dev.d.ts +96 -0
  60. package/dist/cli/workspace-dev.d.ts.map +1 -0
  61. package/dist/client/AssistantChat.d.ts.map +1 -1
  62. package/dist/client/AssistantChat.js +10 -19
  63. package/dist/client/AssistantChat.js.map +1 -1
  64. package/dist/client/ErrorBoundary.d.ts.map +1 -1
  65. package/dist/client/ErrorBoundary.js +34 -1
  66. package/dist/client/ErrorBoundary.js.map +1 -1
  67. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  68. package/dist/client/blocks/library/AnnotatedCodeBlock.js +15 -7
  69. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  70. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
  71. package/dist/client/blocks/library/DiffBlock.js +17 -10
  72. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  73. package/dist/client/blocks/library/annotation-rail.d.ts +5 -0
  74. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
  75. package/dist/client/blocks/library/annotation-rail.js +6 -0
  76. package/dist/client/blocks/library/annotation-rail.js.map +1 -1
  77. package/dist/client/blocks/types.d.ts +5 -0
  78. package/dist/client/blocks/types.d.ts.map +1 -1
  79. package/dist/client/blocks/types.js.map +1 -1
  80. package/dist/client/index.d.ts +1 -1
  81. package/dist/client/index.d.ts.map +1 -1
  82. package/dist/client/index.js +1 -1
  83. package/dist/client/index.js.map +1 -1
  84. package/dist/client/route-chunk-recovery.d.ts +17 -0
  85. package/dist/client/route-chunk-recovery.d.ts.map +1 -1
  86. package/dist/client/route-chunk-recovery.js +67 -0
  87. package/dist/client/route-chunk-recovery.js.map +1 -1
  88. package/dist/deploy/build.d.ts.map +1 -1
  89. package/dist/deploy/build.js +15 -71
  90. package/dist/deploy/build.js.map +1 -1
  91. package/dist/extensions/schema.d.ts +54 -54
  92. package/dist/extensions/slots/schema.d.ts +13 -13
  93. package/dist/file-upload/actions/upload-image.d.ts +4 -4
  94. package/dist/mcp/actions/create-org-service-token.d.ts +1 -1
  95. package/dist/mcp/actions/list-org-service-tokens.d.ts +7 -7
  96. package/dist/mcp/build-server.d.ts +12 -12
  97. package/dist/mcp/build-server.d.ts.map +1 -1
  98. package/dist/mcp/build-server.js.map +1 -1
  99. package/dist/mcp/connect-route.js +1 -1
  100. package/dist/mcp/connect-route.js.map +1 -1
  101. package/dist/mcp/oauth-route.d.ts +10 -0
  102. package/dist/mcp/oauth-route.d.ts.map +1 -1
  103. package/dist/mcp/oauth-route.js +34 -3
  104. package/dist/mcp/oauth-route.js.map +1 -1
  105. package/dist/mcp/oauth-store.d.ts +15 -1
  106. package/dist/mcp/oauth-store.d.ts.map +1 -1
  107. package/dist/mcp/oauth-store.js +60 -4
  108. package/dist/mcp/oauth-store.js.map +1 -1
  109. package/dist/mcp/oauth-token.d.ts +3 -1
  110. package/dist/mcp/oauth-token.d.ts.map +1 -1
  111. package/dist/mcp/oauth-token.js +78 -6
  112. package/dist/mcp/oauth-token.js.map +1 -1
  113. package/dist/mcp/server.d.ts.map +1 -1
  114. package/dist/mcp/server.js +8 -6
  115. package/dist/mcp/server.js.map +1 -1
  116. package/dist/observability/routes.d.ts +11 -11
  117. package/dist/org/handlers.d.ts +7 -11
  118. package/dist/org/handlers.d.ts.map +1 -1
  119. package/dist/secrets/schema.d.ts +7 -7
  120. package/dist/server/auth.d.ts.map +1 -1
  121. package/dist/server/auth.js +8 -5
  122. package/dist/server/auth.js.map +1 -1
  123. package/dist/server/csrf.d.ts +1 -1
  124. package/dist/server/csrf.d.ts.map +1 -1
  125. package/dist/server/onboarding-html.d.ts.map +1 -1
  126. package/dist/server/onboarding-html.js +12 -11
  127. package/dist/server/onboarding-html.js.map +1 -1
  128. package/dist/server/poll-events.d.ts +1 -1
  129. package/dist/server/security-headers.d.ts +1 -1
  130. package/dist/server/security-headers.d.ts.map +1 -1
  131. package/dist/server/ssr-handler.d.ts.map +1 -1
  132. package/dist/server/ssr-handler.js +42 -130
  133. package/dist/server/ssr-handler.js.map +1 -1
  134. package/dist/sharing/actions/list-resource-shares.d.ts +3 -3
  135. package/dist/sharing/actions/set-resource-visibility.d.ts +2 -2
  136. package/dist/sharing/actions/share-resource.d.ts +4 -4
  137. package/dist/sharing/actions/unshare-resource.d.ts +1 -1
  138. package/dist/sharing/schema.d.ts +12 -12
  139. package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +2 -2
  140. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +6 -6
  141. package/dist/templates/workspace-core/.agents/skills/external-agents/references/mcp-apps-embedding.md +2 -2
  142. package/dist/workspace-files/schema.d.ts +8 -8
  143. package/docs/content/external-agents.md +14 -0
  144. package/docs/content/plan-plugin.md +16 -7
  145. package/package.json +5 -1
  146. package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +2 -2
  147. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +6 -6
  148. package/src/templates/workspace-core/.agents/skills/external-agents/references/mcp-apps-embedding.md +2 -2
@@ -8,55 +8,58 @@ import os from "node:os";
8
8
  import path from "node:path";
9
9
  import { spawn } from "node:child_process";
10
10
  import { createHash } from "node:crypto";
11
+ import { fileURLToPath } from "node:url";
12
+ import { createCliTelemetry } from "./telemetry.js";
11
13
  import { buildAppSkillPack, ensureAppSkill, loadAppSkillManifest, normalizeAppSkillManifest, } from "./app-skill.js";
12
14
  import { readConnectClientPreferences, resolveClients, runConnect, writeConnectClientPreferences, } from "./connect.js";
13
15
  import { CONTEXT_XRAY_SKILL_MD, installLocalContextXray, } from "./context-xray-local.js";
14
16
  import { CLIENTS } from "./mcp-config-writers.js";
15
17
  import { PR_VISUAL_RECAP_SETUP, writePrVisualRecapWorkflow } from "./recap.js";
16
- const HELP = `agent-native skills
18
+ const HELP = `npx @agent-native/core@latest skills
17
19
 
18
20
  Usage:
19
- agent-native skills list
20
- agent-native skills status [assets|design-exploration|visual-plan|visual-recap|context-xray] [--client codex|claude-code|all] [--scope user|project] [--json]
21
- agent-native skills update [assets|design-exploration|visual-plan|visual-recap|context-xray] [--client codex|claude-code|all] [--scope user|project] [--dry-run] [--json]
22
- agent-native skills add assets|design-exploration|visual-plan|visual-recap|context-xray [--client codex|claude-code|claude-code-cli|cowork|all] [--scope user|project] [--mcp-url <url>] [--no-connect] [--with-github-action] [--yes] [--dry-run] [--json]
23
- agent-native skills add <manifest-or-app-dir|skill-repo> [--skill <name>] [--client ...] [--yes]
21
+ npx @agent-native/core@latest skills list
22
+ npx @agent-native/core@latest skills status [assets|design-exploration|visual-plan|visual-recap|context-xray] [--client codex|claude-code|all] [--scope user|project] [--json]
23
+ npx @agent-native/core@latest skills update [assets|design-exploration|visual-plan|visual-recap|context-xray] [--client codex|claude-code|all] [--scope user|project] [--dry-run] [--json]
24
+ npx @agent-native/core@latest skills add assets|design-exploration|visual-plan|visual-recap|context-xray [--client codex|claude-code|claude-code-cli|cowork|all] [--scope user|project] [--mcp-url <url>] [--no-connect] [--with-github-action] [--yes] [--dry-run] [--json]
25
+ npx @agent-native/core@latest skills add <manifest-or-app-dir|skill-repo> [--skill <name>] [--client ...] [--yes]
24
26
 
25
27
  Examples:
26
- agent-native skills add assets
27
- agent-native skills add design-exploration
28
- agent-native skills add visual-plan
29
- agent-native skills add visual-plan --with-github-action
30
- agent-native skills status visual-plan
31
- agent-native skills update visual-plan
32
- agent-native skills add visual-plan --no-connect
33
- agent-native skills add context-xray --client all
34
- agent-native skills add assets --client claude-code
35
- agent-native skills add assets --mcp-url https://my-app.ngrok-free.dev
36
- agent-native skills add ./dist/assets-skill --client codex
37
- agent-native skills add BuilderIO/skills --client codex --scope project
38
- agent-native skills add BuilderIO/skills --with-github-action
28
+ npx @agent-native/core@latest skills add assets
29
+ npx @agent-native/core@latest skills add design-exploration
30
+ npx @agent-native/core@latest skills add visual-plan
31
+ npx @agent-native/core@latest skills add visual-recap
32
+ npx @agent-native/core@latest skills add visual-recap --with-github-action
33
+ npx @agent-native/core@latest skills status visual-plan
34
+ npx @agent-native/core@latest skills update visual-plan
35
+ npx @agent-native/core@latest skills add visual-plan --no-connect
36
+ npx @agent-native/core@latest skills add context-xray --client all
37
+ npx @agent-native/core@latest skills add assets --client claude-code
38
+ npx @agent-native/core@latest skills add assets --mcp-url https://my-app.ngrok-free.dev
39
+ npx @agent-native/core@latest skills add ./dist/assets-skill --client codex
40
+ npx @agent-native/core@latest skills add BuilderIO/skills --client codex --scope project
41
+ npx @agent-native/core@latest skills add BuilderIO/skills --with-github-action
39
42
 
40
43
  The add command installs the SKILL.md instructions, registers the app-backed
41
44
  MCP connector, and then authenticates it in one step so you do not hit an OAuth
42
- wall on the first tool call. Authentication reuses "agent-native connect":
45
+ wall on the first tool call. Authentication reuses "npx @agent-native/core@latest connect":
43
46
  OAuth-capable clients (Claude Code) get a URL-only entry and a /mcp authenticate
44
47
  prompt, while Codex / Cowork run the browser device-code flow. In a
45
48
  non-interactive shell or CI the auth step is skipped and the exact
46
- "agent-native connect <url>" command is printed instead.
49
+ "npx @agent-native/core@latest connect <url>" command is printed instead.
47
50
 
48
51
  Running "npx @agent-native/skills add ..." directly installs instructions only;
49
52
  use this Agent Native CLI path when you want MCP setup and auth too. Pass --no-connect to
50
53
  register the connector without authenticating (leave auth to the host or run
51
- "agent-native connect" later). Pass --mcp-url to register that connector against
54
+ "npx @agent-native/core@latest connect" later). Pass --mcp-url to register that connector against
52
55
  a custom origin (an ngrok tunnel, a local dev server, or a self-hosted
53
56
  deployment) instead of the built-in hosted default — a bare origin gets the
54
57
  standard /_agent-native/mcp path appended. Use app-skill pack for marketplace
55
58
  bundles and custom adapter output.
56
59
 
57
- When installing visual-plan interactively, the CLI offers to add the optional PR
60
+ When installing visual-recap interactively, the CLI offers to add the optional PR
58
61
  Visual Recap GitHub Action. Pass --with-github-action to write it directly, then
59
- run "agent-native recap setup" / "agent-native recap doctor" to configure and
62
+ run "npx @agent-native/core@latest recap setup" / "npx @agent-native/core@latest recap doctor" to configure and
60
63
  verify GitHub Actions.
61
64
 
62
65
  The status/update commands inspect copied Agent Native skill folders and refresh
@@ -120,7 +123,7 @@ of using a generic image generator.
120
123
 
121
124
  - Hosted default: connect \`https://assets.agent-native.com/_agent-native/mcp\`.
122
125
  Do not put shared secrets in skill files.
123
- - For CLI/code-editor clients, keep any \`agent-native connect\` command
126
+ - For CLI/code-editor clients, keep any \`npx @agent-native/core@latest connect\` command
124
127
  running until browser authorization finishes. Stopping it early can leave the
125
128
  browser approved but the local MCP config unwritten. Restart or reload the
126
129
  agent client after installing or connecting if Assets tools do not appear in
@@ -130,9 +133,12 @@ of using a generic image generator.
130
133
  - Do not call image/video providers directly from another app. Assets owns
131
134
  generation, picker UI, search/list/export, and asset context.
132
135
  - If an Assets tool call returns \`Session terminated\`, \`needs auth\`, or
133
- another connector/session error, do not keep retrying the tool. Tell the user
134
- to reconnect or authenticate the Assets MCP connector, then continue after it
135
- is available.
136
+ another connector/session error, do not keep retrying the tool. Stop and give
137
+ the user the reconnect step: in Claude Code run \`/mcp\` and choose
138
+ Authenticate/Reconnect for the Assets connector; from any terminal run
139
+ \`npx @agent-native/core@latest reconnect https://assets.agent-native.com\` — this
140
+ re-authenticates WITHOUT reinstalling. Never reinstall from scratch just to fix
141
+ auth. Continue once the connector is available.
136
142
  - Do not hand-roll MCP HTTP requests with curl from the agent session. Use the
137
143
  host-exposed Assets tools after restart/reload, or use the returned
138
144
  browser/deep-link fallback.
@@ -192,7 +198,7 @@ iteration, or a human-in-the-loop choice among design directions.
192
198
 
193
199
  - Hosted default: connect \`https://design.agent-native.com/_agent-native/mcp\`.
194
200
  Do not put shared secrets in skill files.
195
- - For CLI/code-editor clients, keep any \`agent-native connect\` command
201
+ - For CLI/code-editor clients, keep any \`npx @agent-native/core@latest connect\` command
196
202
  running until browser authorization finishes. Stopping it early can leave the
197
203
  browser approved but the local MCP config unwritten. Restart or reload the
198
204
  agent client after installing or connecting if Design tools do not appear in
@@ -202,9 +208,12 @@ iteration, or a human-in-the-loop choice among design directions.
202
208
  - Keep the loop visual: surface the inline MCP App or the returned "Open
203
209
  design" link instead of pasting large HTML blobs into chat.
204
210
  - If a Design tool call returns \`Session terminated\`, \`needs auth\`, or
205
- another connector/session error, do not keep retrying the tool. Tell the user
206
- to reconnect or authenticate the Design MCP connector, then continue after it
207
- is available.
211
+ another connector/session error, do not keep retrying the tool. Stop and give
212
+ the user the reconnect step: in Claude Code run \`/mcp\` and choose
213
+ Authenticate/Reconnect for the Design connector; from any terminal run
214
+ \`npx @agent-native/core@latest reconnect https://design.agent-native.com\` — this
215
+ re-authenticates WITHOUT reinstalling. Never reinstall from scratch just to fix
216
+ auth. Continue once the connector is available.
208
217
  - Do not hand-roll MCP HTTP requests with curl from the agent session. Use the
209
218
  host-exposed Design tools after restart/reload, or use the returned
210
219
  browser/deep-link fallback.
@@ -250,10 +259,13 @@ your repo as MDX. This local mode is a separate advanced path, not the default
250
259
  hosted flow.
251
260
 
252
261
  If a Plans tool returns \`needs auth\`, \`Unauthorized\`, or \`Session terminated\`,
253
- do not keep retrying the tool. Authenticate the connector with
254
- \`npx @agent-native/core@latest connect https://plan.agent-native.com\` (OAuth-capable hosts can
255
- instead re-run /mcp and choose Authenticate), then continue once the connector
256
- is available.
262
+ do not keep retrying the tool. Stop and give the user the reconnect step: in
263
+ Claude Code run \`/mcp\` and choose Authenticate/Reconnect for the plan
264
+ connector; from any terminal run
265
+ \`npx @agent-native/core@latest reconnect https://plan.agent-native.com\` — this
266
+ re-authenticates WITHOUT reinstalling and finds the entry by URL regardless of
267
+ connector name. Never reinstall from scratch just to fix auth. Continue once
268
+ the connector is available.
257
269
 
258
270
  Hosted default: connect \`https://plan.agent-native.com/_agent-native/mcp\`. Do
259
271
  not put shared secrets in skill files.`;
@@ -915,11 +927,12 @@ plan over as inline chat content — no Markdown prose, ASCII sketch, table, or
915
927
  fenced wireframe. If the connector's tools are missing, do NOT fall back to
916
928
  inline output: the usual cause is a connector that did not finish connecting
917
929
  this session (it registers zero tools), not auth. Stop and give the user the
918
- exact restore step — reconnect via \`/mcp\` (or restart the session); only if
919
- genuinely unauthenticated, run
920
- \`npx @agent-native/core@latest connect https://plan.agent-native.com\`. Publish once the tool is
921
- reachable. Local-files privacy mode (after Tool Guidance) is the only
922
- exception.
930
+ exact restore step — in Claude Code run \`/mcp\` and choose
931
+ Authenticate/Reconnect (or restart the session); if genuinely unauthenticated,
932
+ run \`npx @agent-native/core@latest reconnect https://plan.agent-native.com\` this
933
+ re-authenticates WITHOUT reinstalling. Never reinstall from scratch just to fix
934
+ auth. Publish once the tool is reachable. Local-files privacy mode (after Tool
935
+ Guidance) is the only exception.
923
936
 
924
937
  ## Core Workflow
925
938
 
@@ -1223,10 +1236,13 @@ because it is named \`agent-native-plans\` instead of \`plan\`. The usual cause
1223
1236
  connector that did not finish connecting this session (it registers zero tools),
1224
1237
  NOT necessarily an auth problem — so do not assume the user must authenticate.
1225
1238
  Stop and tell the user how to restore it: reconnect the Plan MCP connector (in
1226
- Claude Code, run \`/mcp\` and reconnect, or restart the session); only if it is
1227
- genuinely unauthenticated, run \`npx @agent-native/core@latest connect <plan-app-url>\` or
1228
- re-authenticate via \`/mcp\`. Then publish once the tool is reachable. Falling
1229
- back to inline content is a defect, not a degraded mode.
1239
+ Claude Code, run \`/mcp\` and choose Authenticate/Reconnect, or restart the
1240
+ session); if it is genuinely unauthenticated, run
1241
+ \`npx @agent-native/core@latest reconnect https://plan.agent-native.com\` this
1242
+ re-authenticates WITHOUT reinstalling and finds the entry by URL regardless of
1243
+ connector name. Never reinstall from scratch just to fix auth. Then publish once
1244
+ the tool is reachable. Falling back to inline content is a defect, not a
1245
+ degraded mode.
1230
1246
 
1231
1247
  ## When To Use
1232
1248
 
@@ -1947,6 +1963,21 @@ function builtInExtraFiles(entry) {
1947
1963
  function builtInSkillNames(entry) {
1948
1964
  return [entry.skillName, ...Object.keys(builtInExtraSkills(entry))];
1949
1965
  }
1966
+ /**
1967
+ * When a target names a single skill that lives inside a multi-skill bundle
1968
+ * (the plan bundle ships both `visual-plan` and `visual-recap`), restrict the
1969
+ * install to just that skill. The bundle aliases (`visual-plans`, `plannotate`,
1970
+ * …) return undefined so they install every skill in the bundle.
1971
+ */
1972
+ function builtInOnlySkillNames(target) {
1973
+ const normalized = target.trim().toLowerCase();
1974
+ if (normalized === "visual-plan")
1975
+ return ["visual-plan"];
1976
+ if (normalized === "visual-recap" || normalized === "visual-recaps") {
1977
+ return ["visual-recap"];
1978
+ }
1979
+ return undefined;
1980
+ }
1950
1981
  function stableSkillHash(files) {
1951
1982
  const hash = createHash("sha256");
1952
1983
  for (const rel of Object.keys(files).sort()) {
@@ -2009,10 +2040,49 @@ function writeSkillFolder(dir, bundle, installedAt = new Date().toISOString()) {
2009
2040
  contentHash: bundle.contentHash,
2010
2041
  mcpUrl: bundle.mcpUrl,
2011
2042
  installedAt,
2012
- updateCommand: `agent-native skills update ${bundle.skillName}`,
2043
+ updateCommand: `npx @agent-native/core@latest skills update ${bundle.skillName}`,
2013
2044
  };
2014
2045
  fs.writeFileSync(path.join(dir, AGENT_NATIVE_SKILL_METADATA_FILE), `${JSON.stringify(metadata, null, 2)}\n`, "utf-8");
2015
2046
  }
2047
+ /**
2048
+ * The skills directory a built-in skill's instructions are copied into for a
2049
+ * given agent + scope. Mirrors the layout the skills installer uses so
2050
+ * `skills status` / `skills update` find the folders again.
2051
+ */
2052
+ function builtInSkillsRootForAgent(agent, scope, baseDir) {
2053
+ const home = homeDir() ?? baseDir;
2054
+ if (scope === "project") {
2055
+ return agent === "codex"
2056
+ ? path.join(baseDir, ".agents", "skills")
2057
+ : path.join(baseDir, ".claude", "skills");
2058
+ }
2059
+ if (agent === "codex") {
2060
+ return process.env.CODEX_HOME
2061
+ ? path.join(process.env.CODEX_HOME, "skills")
2062
+ : path.join(home, ".codex", "skills");
2063
+ }
2064
+ return path.join(home, ".claude", "skills");
2065
+ }
2066
+ /**
2067
+ * Write a built-in skill's instruction folders straight into each client's
2068
+ * skills directory. Built-in skills ship their SKILL.md inside this package, so
2069
+ * there is no need to shell out to the separate @agent-native/skills installer
2070
+ * (which would have to be published to npm first). Returns the written folders.
2071
+ */
2072
+ function installBuiltInInstructions(input) {
2073
+ const bundles = Object.values(skillFilesForBuiltIn(input.appSkillId)).filter((bundle) => !input.onlySkillNames || input.onlySkillNames.includes(bundle.skillName));
2074
+ const written = [];
2075
+ for (const agent of input.skillsAgents) {
2076
+ const root = builtInSkillsRootForAgent(agent, input.scope, input.baseDir);
2077
+ for (const bundle of bundles) {
2078
+ const dir = path.join(root, bundle.skillName);
2079
+ if (!input.dryRun)
2080
+ writeSkillFolder(dir, bundle);
2081
+ written.push(dir);
2082
+ }
2083
+ }
2084
+ return written;
2085
+ }
2016
2086
  function listSkillFolderFiles(dir) {
2017
2087
  const out = {};
2018
2088
  const walk = (current, prefix = "") => {
@@ -2097,7 +2167,7 @@ function targetIdsForStatus(parsed) {
2097
2167
  }
2098
2168
  const known = normalizeKnownSkillTarget(parsed.target);
2099
2169
  if (!known) {
2100
- throw new Error(`Unknown built-in skill: ${parsed.target}. Run "agent-native skills list".`);
2170
+ throw new Error(`Unknown built-in skill: ${parsed.target}. Run "npx @agent-native/core@latest skills list".`);
2101
2171
  }
2102
2172
  if (isLocalOnlyBuiltInSkill(BUILT_IN_APP_SKILLS[known])) {
2103
2173
  throw new Error(`${BUILT_IN_APP_SKILLS[known].manifest.displayName} is installed as a local command and cannot be refreshed with skills update yet.`);
@@ -2200,12 +2270,25 @@ function clientPromptOptions() {
2200
2270
  hint: CLIENT_HINTS[client],
2201
2271
  }));
2202
2272
  }
2273
+ // For now the interactive installer offers only the two plan skills, each as
2274
+ // an independently selectable entry (uncheck one to install just the other).
2275
+ // The other built-in skills stay installable via `agent-native skills add
2276
+ // <name>` but are hidden from the default checklist. The values are the real
2277
+ // slash-command names so users see exactly what they are installing.
2278
+ const PLAN_SKILL_PROMPT_OPTIONS = [
2279
+ {
2280
+ value: "visual-plan",
2281
+ label: "visual-plan",
2282
+ hint: "Reviewable coding-agent plan: diagrams, annotated code, file trees, open questions.",
2283
+ },
2284
+ {
2285
+ value: "visual-recap",
2286
+ label: "visual-recap",
2287
+ hint: "Turn a PR, commit, branch, or git diff into a high-altitude visual recap.",
2288
+ },
2289
+ ];
2203
2290
  function skillPromptOptions() {
2204
- return Object.values(BUILT_IN_APP_SKILLS).map((entry) => ({
2205
- value: entry.skillName,
2206
- label: entry.manifest.displayName,
2207
- hint: entry.manifest.description,
2208
- }));
2291
+ return PLAN_SKILL_PROMPT_OPTIONS;
2209
2292
  }
2210
2293
  function prVisualRecapWorkflowPath(baseDir) {
2211
2294
  return path.join(baseDir, ".github", "workflows", "pr-visual-recap.yml");
@@ -2214,7 +2297,7 @@ function prVisualRecapWorkflowDisplayPath() {
2214
2297
  return path.join(".github", "workflows", "pr-visual-recap.yml");
2215
2298
  }
2216
2299
  function prVisualRecapInstallCommand() {
2217
- return "npx @agent-native/core@latest skills add visual-plan --with-github-action";
2300
+ return "npx @agent-native/core@latest skills add visual-recap --with-github-action";
2218
2301
  }
2219
2302
  function prVisualRecapSetupCommand() {
2220
2303
  return "npx @agent-native/core@latest recap setup";
@@ -2222,8 +2305,11 @@ function prVisualRecapSetupCommand() {
2222
2305
  async function promptForGithubAction(context) {
2223
2306
  const clack = await import("@clack/prompts");
2224
2307
  const result = await clack.confirm({
2225
- message: "Optional: add automatic PR Visual Recaps?\n" +
2226
- ` This writes ${context.workflowPath}; ${context.setupCommand} can finish GitHub secrets.`,
2308
+ message: "Optional: add automatic PR Visual Recaps? (GitHub Action)\n" +
2309
+ " Posts a human-friendly recap on every pull request — a high-altitude\n" +
2310
+ " overview of what the PR does, with annotated code, diagrams, and\n" +
2311
+ " before/after notes instead of a raw diff.\n" +
2312
+ ` Writes ${context.workflowPath}; ${context.setupCommand} finishes the GitHub secrets.`,
2227
2313
  initialValue: false,
2228
2314
  });
2229
2315
  if (clack.isCancel(result)) {
@@ -2258,6 +2344,30 @@ async function promptForClients(context) {
2258
2344
  }
2259
2345
  return normalizeClientIds(result);
2260
2346
  }
2347
+ async function promptForScope(context) {
2348
+ const clack = await import("@clack/prompts");
2349
+ const result = await clack.select({
2350
+ message: "Where do you want to install these skills?",
2351
+ options: [
2352
+ {
2353
+ value: "project",
2354
+ label: "Project",
2355
+ hint: "This repo only (.agents / .claude in the current directory) — committed with your project",
2356
+ },
2357
+ {
2358
+ value: "user",
2359
+ label: "User",
2360
+ hint: "Your home directory (~/.codex, ~/.claude) — available across all projects",
2361
+ },
2362
+ ],
2363
+ initialValue: context.initialScope,
2364
+ });
2365
+ if (clack.isCancel(result)) {
2366
+ clack.cancel("Cancelled.");
2367
+ return null;
2368
+ }
2369
+ return result === "project" ? "project" : "user";
2370
+ }
2261
2371
  async function promptForSkills(context) {
2262
2372
  const clack = await import("@clack/prompts");
2263
2373
  const result = await clack.multiselect({
@@ -2300,12 +2410,29 @@ async function resolveSkillTargets(parsed, options) {
2300
2410
  return [parsed.target ?? "assets"];
2301
2411
  }
2302
2412
  const prompt = options.promptSkills ?? promptForSkills;
2413
+ const promptOptions = skillPromptOptions();
2414
+ // The interactive multiselect skill picker is about to be shown (no --skill /
2415
+ // target passed and we are interactive) — record the funnel "prompted" step.
2416
+ options.telemetry?.track("skills_cli skills prompted", {
2417
+ availableCount: promptOptions.length,
2418
+ available: promptOptions.map((option) => option.value).join(","),
2419
+ });
2303
2420
  const selected = await prompt({
2304
- initialTargets: ["assets"],
2305
- options: skillPromptOptions(),
2421
+ initialTargets: ["visual-plan", "visual-recap"],
2422
+ options: promptOptions,
2306
2423
  });
2307
2424
  if (!selected || selected.length === 0)
2308
2425
  return null;
2426
+ // Both plan skills share one MCP connector, so when both are selected install
2427
+ // them through the bundle target — that registers/authenticates the connector
2428
+ // once instead of twice.
2429
+ const planSubskills = ["visual-plan", "visual-recap"];
2430
+ if (planSubskills.every((skill) => selected.includes(skill))) {
2431
+ return [
2432
+ "visual-plans",
2433
+ ...selected.filter((s) => !planSubskills.includes(s)),
2434
+ ];
2435
+ }
2309
2436
  return selected;
2310
2437
  }
2311
2438
  export function parseSkillsArgs(argv) {
@@ -2406,11 +2533,11 @@ export function parseSkillsArgs(argv) {
2406
2533
  }
2407
2534
  return out;
2408
2535
  }
2409
- function loadSkillTarget(target) {
2536
+ function loadSkillTarget(target, onlySkillNames) {
2410
2537
  const knownTarget = normalizeKnownSkillTarget(target);
2411
2538
  if (knownTarget) {
2412
2539
  const builtIn = BUILT_IN_APP_SKILLS[knownTarget];
2413
- const skillNames = builtInSkillNames(builtIn);
2540
+ const skillNames = builtInSkillNames(builtIn).filter((name) => !onlySkillNames || onlySkillNames.includes(name));
2414
2541
  return {
2415
2542
  id: builtIn.manifest.id,
2416
2543
  displayName: builtIn.manifest.displayName,
@@ -2423,6 +2550,9 @@ function loadSkillTarget(target) {
2423
2550
  materializeInstructions(outDir) {
2424
2551
  const bundles = skillFilesForBuiltIn(knownTarget);
2425
2552
  for (const bundle of Object.values(bundles)) {
2553
+ if (onlySkillNames && !onlySkillNames.includes(bundle.skillName)) {
2554
+ continue;
2555
+ }
2426
2556
  writeSkillFolder(path.join(outDir, "skills", bundle.skillName), bundle);
2427
2557
  }
2428
2558
  return outDir;
@@ -2505,6 +2635,7 @@ function preserveMcpUrlAppPathOverride(target, input) {
2505
2635
  function dryRunInstallCommand(parsed, target) {
2506
2636
  const clients = parsed.clients ?? resolveClients(parsed.client);
2507
2637
  const args = [
2638
+ "@agent-native/core@latest",
2508
2639
  "skills",
2509
2640
  "add",
2510
2641
  target,
@@ -2529,7 +2660,7 @@ function dryRunInstallCommand(parsed, target) {
2529
2660
  args.push("--no-update-instructions");
2530
2661
  if (parsed.yes || isKnownSkill(target))
2531
2662
  args.push("--yes");
2532
- return commandString("agent-native", args);
2663
+ return commandString("npx", args);
2533
2664
  }
2534
2665
  async function runCommand(cmd, args, options = {}) {
2535
2666
  return new Promise((resolve, reject) => {
@@ -2679,6 +2810,12 @@ async function addPlainSkillRepo(parsed, options) {
2679
2810
  if (code !== 0)
2680
2811
  throw new Error(`npx @agent-native/skills add exited with ${code}.`);
2681
2812
  }
2813
+ options.telemetry?.track("skills_cli install completed", {
2814
+ skills: target,
2815
+ clients: clients.join(","),
2816
+ scope: parsed.scope,
2817
+ dryRun: Boolean(parsed.dryRun),
2818
+ });
2682
2819
  return {
2683
2820
  id: target,
2684
2821
  displayName: target,
@@ -2708,6 +2845,7 @@ function canRunInteractiveConnect(options) {
2708
2845
  /** Build the `npx @agent-native/core@latest connect <url> --client … --scope …` command. */
2709
2846
  function connectCommandFor(hostedUrl, clients, scope) {
2710
2847
  const args = [
2848
+ "@agent-native/core@latest",
2711
2849
  "connect",
2712
2850
  hostedUrl,
2713
2851
  "--client",
@@ -2715,7 +2853,7 @@ function connectCommandFor(hostedUrl, clients, scope) {
2715
2853
  "--scope",
2716
2854
  scope,
2717
2855
  ];
2718
- return commandString("agent-native", args);
2856
+ return commandString("npx", args);
2719
2857
  }
2720
2858
  /**
2721
2859
  * Authenticate the freshly-registered hosted MCP connector so the user does not
@@ -2740,6 +2878,7 @@ async function connectAfterEnsure(installTarget, clients, parsed, options) {
2740
2878
  return { connected: false, connectCommand };
2741
2879
  }
2742
2880
  options.log?.(`Authenticating ${installTarget.displayName}…`);
2881
+ options.telemetry?.track("skills_cli connect started");
2743
2882
  try {
2744
2883
  await (options.runConnect ?? runConnect)([
2745
2884
  hostedUrl,
@@ -2748,10 +2887,14 @@ async function connectAfterEnsure(installTarget, clients, parsed, options) {
2748
2887
  "--scope",
2749
2888
  parsed.scope,
2750
2889
  ]);
2890
+ options.telemetry?.track("skills_cli connect completed");
2751
2891
  return { connected: true, connectCommand: "" };
2752
2892
  }
2753
2893
  catch (err) {
2754
2894
  // Non-fatal: the MCP connector is registered. Surface the manual command.
2895
+ options.telemetry?.track("skills_cli connect failed", {
2896
+ error: err?.message ?? String(err),
2897
+ });
2755
2898
  options.log?.(`Could not finish authentication automatically (${err?.message ?? err}). ` +
2756
2899
  `Run it later with: ${connectCommand}`);
2757
2900
  return { connected: false, connectCommand };
@@ -2760,11 +2903,19 @@ async function connectAfterEnsure(installTarget, clients, parsed, options) {
2760
2903
  export async function addAgentNativeSkill(parsed, options = {}) {
2761
2904
  const target = parsed.target ?? "assets";
2762
2905
  const knownTarget = normalizeKnownSkillTarget(target);
2906
+ // For multi-skill bundles (the plan bundle), a single-skill target installs
2907
+ // only that skill. `installsRecap` controls the PR Visual Recap github-action
2908
+ // offer, which is only relevant when the recap skill is part of the install.
2909
+ const onlySkillNames = knownTarget
2910
+ ? builtInOnlySkillNames(target)
2911
+ : undefined;
2912
+ const installsRecap = knownTarget === "visual-plans" &&
2913
+ (!onlySkillNames || onlySkillNames.includes("visual-recap"));
2763
2914
  if (!knownTarget && isPlainSkillRepoTarget(target)) {
2764
2915
  return addPlainSkillRepo({ ...parsed, target }, options);
2765
2916
  }
2766
2917
  if (!knownTarget && !fs.existsSync(path.resolve(target))) {
2767
- throw new Error(`Unknown skill or manifest path: ${target}. Run "agent-native skills list".`);
2918
+ throw new Error(`Unknown skill or manifest path: ${target}. Run "npx @agent-native/core@latest skills list".`);
2768
2919
  }
2769
2920
  const knownBuiltIn = knownTarget ? BUILT_IN_APP_SKILLS[knownTarget] : null;
2770
2921
  if (isLocalOnlyBuiltInSkill(knownBuiltIn)) {
@@ -2780,6 +2931,12 @@ export async function addAgentNativeSkill(parsed, options = {}) {
2780
2931
  const githubActionPath = parsed.withGithubAction && knownTarget === "visual-plans"
2781
2932
  ? prVisualRecapWorkflowDisplayPath()
2782
2933
  : undefined;
2934
+ options.telemetry?.track("skills_cli install completed", {
2935
+ skills: knownBuiltIn.skillName,
2936
+ clients: clients.join(","),
2937
+ scope: parsed.scope,
2938
+ dryRun: true,
2939
+ });
2783
2940
  return {
2784
2941
  id: knownBuiltIn.manifest.id,
2785
2942
  displayName: knownBuiltIn.manifest.displayName,
@@ -2798,6 +2955,12 @@ export async function addAgentNativeSkill(parsed, options = {}) {
2798
2955
  clients,
2799
2956
  scope: parsed.scope,
2800
2957
  });
2958
+ options.telemetry?.track("skills_cli install completed", {
2959
+ skills: knownBuiltIn.skillName,
2960
+ clients: clients.join(","),
2961
+ scope: parsed.scope,
2962
+ dryRun: false,
2963
+ });
2801
2964
  return {
2802
2965
  id: knownBuiltIn.manifest.id,
2803
2966
  displayName: knownBuiltIn.manifest.displayName,
@@ -2813,7 +2976,7 @@ export async function addAgentNativeSkill(parsed, options = {}) {
2813
2976
  commands: localInstall.commands,
2814
2977
  };
2815
2978
  }
2816
- let installTarget = loadSkillTarget(target);
2979
+ let installTarget = loadSkillTarget(target, onlySkillNames);
2817
2980
  if (parsed.mcpUrl) {
2818
2981
  installTarget = withMcpUrlOverride(installTarget, parsed.mcpUrl);
2819
2982
  }
@@ -2822,12 +2985,18 @@ export async function addAgentNativeSkill(parsed, options = {}) {
2822
2985
  const skillsAgents = skillsAgentsForClients(clients);
2823
2986
  if (parsed.dryRun) {
2824
2987
  try {
2825
- const githubActionPath = parsed.withGithubAction && knownTarget === "visual-plans"
2988
+ const githubActionPath = parsed.withGithubAction && installsRecap
2826
2989
  ? prVisualRecapWorkflowDisplayPath()
2827
2990
  : undefined;
2828
- const githubActionSuggestedCommand = knownTarget === "visual-plans" && !parsed.withGithubAction
2991
+ const githubActionSuggestedCommand = installsRecap && !parsed.withGithubAction
2829
2992
  ? prVisualRecapInstallCommand()
2830
2993
  : undefined;
2994
+ options.telemetry?.track("skills_cli install completed", {
2995
+ skills: installTarget.skillNames.join(","),
2996
+ clients: clients.join(","),
2997
+ scope: parsed.scope,
2998
+ dryRun: true,
2999
+ });
2831
3000
  return {
2832
3001
  id: installTarget.id,
2833
3002
  displayName: installTarget.displayName,
@@ -2848,6 +3017,7 @@ export async function addAgentNativeSkill(parsed, options = {}) {
2848
3017
  const commands = [];
2849
3018
  const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "an-skills-add-"));
2850
3019
  let instructionSource;
3020
+ let instructionsWritten;
2851
3021
  let connected = false;
2852
3022
  let connectCommand;
2853
3023
  try {
@@ -2857,7 +3027,26 @@ export async function addAgentNativeSkill(parsed, options = {}) {
2857
3027
  throw new Error("Skill instructions can only be installed for Codex or Claude Code clients. Use an MCP-capable client or omit --instructions-only.");
2858
3028
  }
2859
3029
  }
3030
+ else if (knownTarget) {
3031
+ // Built-in skills ship their instructions inside this package, so copy
3032
+ // the skill folders straight into each client's skills directory. This
3033
+ // avoids shelling out to the separate @agent-native/skills installer
3034
+ // (which would need to be published to npm to run via npx).
3035
+ instructionsWritten = installBuiltInInstructions({
3036
+ appSkillId: knownTarget,
3037
+ onlySkillNames,
3038
+ skillsAgents,
3039
+ scope: parsed.scope,
3040
+ baseDir: options.baseDir ?? process.cwd(),
3041
+ dryRun: parsed.dryRun,
3042
+ });
3043
+ instructionSource = instructionsWritten[0];
3044
+ commands.push(...instructionsWritten.map((dir) => `write ${dir}`));
3045
+ }
2860
3046
  else {
3047
+ // External app-skill manifests / plain skill repos still go through the
3048
+ // standalone installer, which knows how to pack adapters and fetch
3049
+ // remote skill collections.
2861
3050
  instructionSource = installTarget.materializeInstructions(tmpRoot);
2862
3051
  const args = [
2863
3052
  "--yes",
@@ -2880,6 +3069,14 @@ export async function addAgentNativeSkill(parsed, options = {}) {
2880
3069
  }
2881
3070
  }
2882
3071
  }
3072
+ // Skill instructions are now on disk (built-in folders copied or external
3073
+ // pack materialized) — record the install before MCP registration/connect.
3074
+ options.telemetry?.track("skills_cli install completed", {
3075
+ skills: installTarget.skillNames.join(","),
3076
+ clients: clients.join(","),
3077
+ scope: parsed.scope,
3078
+ dryRun: Boolean(parsed.dryRun),
3079
+ });
2883
3080
  if (parsed.mcp) {
2884
3081
  commands.push(`npx @agent-native/core@latest app-skill ensure --manifest ${installTarget.loaded.file} --client ${parsed.client} --scope ${parsed.scope} --yes`);
2885
3082
  if (!parsed.dryRun) {
@@ -2891,6 +3088,9 @@ export async function addAgentNativeSkill(parsed, options = {}) {
2891
3088
  confirm: true,
2892
3089
  log: options.log,
2893
3090
  });
3091
+ options.telemetry?.track("skills_cli mcp registered", {
3092
+ skills: installTarget.skillNames.join(","),
3093
+ });
2894
3094
  // One-step install + authenticate: after registering a hosted MCP
2895
3095
  // connector, kick off the existing connect/device-code flow so the user
2896
3096
  // does not hit an OAuth wall on the first tool call. `--no-connect`
@@ -2911,24 +3111,32 @@ export async function addAgentNativeSkill(parsed, options = {}) {
2911
3111
  let githubActionPath;
2912
3112
  let githubActionExisted;
2913
3113
  let githubActionSuggestedCommand;
2914
- if (knownTarget === "visual-plans" &&
3114
+ if (installsRecap &&
2915
3115
  !withGithubAction &&
2916
3116
  !fs.existsSync(prVisualRecapWorkflowPath(baseDir))) {
2917
- if (shouldPrompt(parsed, options)) {
3117
+ // Normally the recap decision is made up front in `runSkills` (so it's
3118
+ // resolved here). Only prompt inline when a direct caller invoked
3119
+ // addAgentNativeSkill without going through that up-front step.
3120
+ if (!parsed.githubActionResolved && shouldPrompt(parsed, options)) {
2918
3121
  const prompt = options.promptGithubAction ?? promptForGithubAction;
2919
- withGithubAction =
2920
- (await prompt({
2921
- workflowPath: prVisualRecapWorkflowDisplayPath(),
2922
- setupCommand: prVisualRecapSetupCommand(),
2923
- })) === true;
3122
+ const choice = await prompt({
3123
+ workflowPath: prVisualRecapWorkflowDisplayPath(),
3124
+ setupCommand: prVisualRecapSetupCommand(),
3125
+ });
3126
+ if (choice === null) {
3127
+ options.telemetry?.track("skills_cli cancelled", {
3128
+ step: "github-action",
3129
+ });
3130
+ }
3131
+ withGithubAction = choice === true;
2924
3132
  }
2925
3133
  if (!withGithubAction) {
2926
3134
  githubActionSuggestedCommand = prVisualRecapInstallCommand();
2927
3135
  }
2928
3136
  }
2929
3137
  if (withGithubAction) {
2930
- if (knownTarget !== "visual-plans") {
2931
- options.log?.("--with-github-action only applies to the visual-plan skill; skipping the workflow.");
3138
+ if (!installsRecap) {
3139
+ options.log?.("--with-github-action only applies to the visual-recap skill; skipping the workflow.");
2932
3140
  }
2933
3141
  else {
2934
3142
  const writeResult = writePrVisualRecapWorkflow(baseDir, {
@@ -2941,6 +3149,7 @@ export async function addAgentNativeSkill(parsed, options = {}) {
2941
3149
  githubActionExisted =
2942
3150
  writeResult.status === "written" ? writeResult.existed : false;
2943
3151
  commands.push(`write ${writeResult.path}`);
3152
+ options.telemetry?.track("skills_cli github action added");
2944
3153
  }
2945
3154
  }
2946
3155
  return {
@@ -2953,6 +3162,7 @@ export async function addAgentNativeSkill(parsed, options = {}) {
2953
3162
  mcpClients: clients,
2954
3163
  dryRun: parsed.dryRun,
2955
3164
  commands,
3165
+ written: instructionsWritten,
2956
3166
  connected,
2957
3167
  connectCommand,
2958
3168
  githubActionPath,
@@ -3019,7 +3229,7 @@ function runSkillsStatusOrUpdate(parsed, options, update) {
3019
3229
  }
3020
3230
  if (before.length === 0) {
3021
3231
  const target = parsed.target ? ` for ${parsed.target}` : "";
3022
- process.stdout.write(`No installed Agent Native skill copies found${target}.\nRun "agent-native skills add ${parsed.target ?? "visual-plan"}" to install one.\n`);
3232
+ process.stdout.write(`No installed Agent Native skill copies found${target}.\nRun "npx @agent-native/core@latest skills add ${parsed.target ?? "visual-plan"}" to install one.\n`);
3023
3233
  return;
3024
3234
  }
3025
3235
  if (update) {
@@ -3037,6 +3247,21 @@ function runSkillsStatusOrUpdate(parsed, options, update) {
3037
3247
  const rows = (update && parsed.dryRun ? before : after).map(formatSkillState);
3038
3248
  process.stdout.write(`${rows.join("\n")}\n`);
3039
3249
  }
3250
+ /**
3251
+ * Resolve the CLI version the same way `index.ts` does — read it from the
3252
+ * package.json two levels up from the compiled module (dist/cli/skills.js →
3253
+ * ../../package.json). Best-effort: falls back to "unknown".
3254
+ */
3255
+ function readCliVersion() {
3256
+ try {
3257
+ const here = path.dirname(fileURLToPath(import.meta.url));
3258
+ const pkg = JSON.parse(fs.readFileSync(path.resolve(here, "../../package.json"), "utf8"));
3259
+ return typeof pkg.version === "string" ? pkg.version : "unknown";
3260
+ }
3261
+ catch {
3262
+ return "unknown";
3263
+ }
3264
+ }
3040
3265
  export async function runSkills(argv, options = {}) {
3041
3266
  const parsed = parseSkillsArgs(argv);
3042
3267
  const log = parsed.printJson
@@ -3046,115 +3271,231 @@ export async function runSkills(argv, options = {}) {
3046
3271
  process.stdout.write(`${HELP}\n`);
3047
3272
  return;
3048
3273
  }
3049
- if (parsed.command === "list") {
3050
- const skills = listSkills();
3274
+ // `@agent-native/skills` now delegates its interactive install to this
3275
+ // function. For plain skill repos we still shell out to
3276
+ // `npx @agent-native/skills add …`; this env guard tells that child process
3277
+ // to run its OWN headless installer instead of bouncing back into core,
3278
+ // which would otherwise be an infinite skills → core → skills loop.
3279
+ process.env.AGENT_NATIVE_SKILLS_DIRECT = "1";
3280
+ // Best-effort install-funnel telemetry. Created once per run and flushed in a
3281
+ // finally so events send on success, error, and cancellation — the CLI is
3282
+ // short-lived, so flushing before exit is essential or the events never send.
3283
+ const startedAt = Date.now();
3284
+ const telemetry = options.telemetry ??
3285
+ createCliTelemetry({
3286
+ cli: "core",
3287
+ cliVersion: readCliVersion(),
3288
+ command: parsed.command,
3289
+ interactive: shouldPrompt(parsed, options),
3290
+ });
3291
+ const optionsWithTelemetry = { ...options, telemetry };
3292
+ try {
3293
+ telemetry.track("skills_cli started");
3294
+ if (parsed.command === "list") {
3295
+ const skills = listSkills();
3296
+ telemetry.track("skills_cli skills listed", {
3297
+ availableCount: skills.length,
3298
+ available: skills.map((skill) => skill.id).join(","),
3299
+ });
3300
+ if (parsed.printJson) {
3301
+ process.stdout.write(`${JSON.stringify(skills, null, 2)}\n`);
3302
+ return;
3303
+ }
3304
+ for (const skill of skills) {
3305
+ const description = skill.description.replace(/[.?!]?$/, ".");
3306
+ const aliases = skill.aliases.length
3307
+ ? ` Aliases: ${skill.aliases.join(", ")}.`
3308
+ : "";
3309
+ const target = skill.local ? "local command" : skill.mcpUrl;
3310
+ process.stdout.write(`${skill.id.padEnd(12)} ${description}${aliases} (${target})\n`);
3311
+ }
3312
+ return;
3313
+ }
3314
+ if (parsed.command === "status" || parsed.command === "update") {
3315
+ runSkillsStatusOrUpdate(parsed, options, parsed.command === "update");
3316
+ return;
3317
+ }
3318
+ const targets = await resolveSkillTargets(parsed, optionsWithTelemetry);
3319
+ if (!targets) {
3320
+ telemetry.track("skills_cli cancelled", { step: "skills" });
3321
+ return;
3322
+ }
3323
+ const preselected = Boolean(parsed.target);
3324
+ telemetry.track("skills_cli skills selected", {
3325
+ selected: targets.join(","),
3326
+ selectedCount: targets.length,
3327
+ // Best-effort "took everything offered" signal: compare against the
3328
+ // interactive picker's option count (the plan sub-skills collapse into a
3329
+ // single bundle target, so this is approximate, like the standalone CLI).
3330
+ selectedAll: targets.length === skillPromptOptions().length,
3331
+ preselected,
3332
+ });
3333
+ const clients = await resolveSkillsClients(parsed, optionsWithTelemetry);
3334
+ if (!clients) {
3335
+ telemetry.track("skills_cli cancelled", { step: "clients" });
3336
+ return;
3337
+ }
3338
+ telemetry.track("skills_cli clients selected", {
3339
+ clients: clients.join(","),
3340
+ clientCount: clients.length,
3341
+ });
3342
+ // Ask where to install (project vs user) unless an explicit --scope was
3343
+ // passed or we are running non-interactively.
3344
+ if (!parsed.scopeExplicit && shouldPrompt(parsed, options)) {
3345
+ const promptScope = options.promptScope ?? promptForScope;
3346
+ const scope = await promptScope({ initialScope: "project" });
3347
+ if (!scope) {
3348
+ telemetry.track("skills_cli cancelled", { step: "scope" });
3349
+ return;
3350
+ }
3351
+ parsed.scope = scope;
3352
+ }
3353
+ telemetry.track("skills_cli scope selected", { scope: parsed.scope });
3354
+ // Decide the optional PR Visual Recap GitHub Action UP FRONT — before any
3355
+ // install or MCP registration — so every prompt is answered before we touch
3356
+ // disk. The choice is threaded into each install via `withGithubAction` +
3357
+ // `githubActionResolved` (so addAgentNativeSkill doesn't re-prompt mid-flow).
3358
+ const recapBaseDir = options.baseDir ?? process.cwd();
3359
+ const anyRecapTarget = targets.some((target) => {
3360
+ if (normalizeKnownSkillTarget(target) !== "visual-plans")
3361
+ return false;
3362
+ const only = builtInOnlySkillNames(target);
3363
+ return !only || only.includes("visual-recap");
3364
+ });
3365
+ if (anyRecapTarget &&
3366
+ !parsed.withGithubAction &&
3367
+ !fs.existsSync(prVisualRecapWorkflowPath(recapBaseDir)) &&
3368
+ shouldPrompt(parsed, options)) {
3369
+ const prompt = options.promptGithubAction ?? promptForGithubAction;
3370
+ const choice = await prompt({
3371
+ workflowPath: prVisualRecapWorkflowDisplayPath(),
3372
+ setupCommand: prVisualRecapSetupCommand(),
3373
+ });
3374
+ if (choice === null) {
3375
+ telemetry.track("skills_cli cancelled", { step: "github-action" });
3376
+ }
3377
+ parsed.withGithubAction = choice === true;
3378
+ parsed.githubActionResolved = true;
3379
+ }
3380
+ const results = [];
3381
+ for (const target of targets) {
3382
+ results.push(await addAgentNativeSkill({
3383
+ ...parsed,
3384
+ target,
3385
+ client: clientArgForClients(clients),
3386
+ clients,
3387
+ }, {
3388
+ ...optionsWithTelemetry,
3389
+ log,
3390
+ }));
3391
+ }
3392
+ // The add flow succeeded for every target — record the funnel completion
3393
+ // before printing output (output below cannot fail the install).
3394
+ const completedSkills = [
3395
+ ...new Set(results.flatMap((result) => result.skillNames)),
3396
+ ];
3397
+ const completedClients = [
3398
+ ...new Set(results.flatMap((result) => result.mcpClients)),
3399
+ ];
3400
+ telemetry.track("skills_cli completed", {
3401
+ skills: completedSkills.join(","),
3402
+ clients: completedClients.join(","),
3403
+ scope: parsed.scope,
3404
+ durationMs: Date.now() - startedAt,
3405
+ });
3051
3406
  if (parsed.printJson) {
3052
- process.stdout.write(`${JSON.stringify(skills, null, 2)}\n`);
3407
+ process.stdout.write(`${JSON.stringify(results.length === 1 ? results[0] : results, null, 2)}\n`);
3408
+ return;
3409
+ }
3410
+ if (parsed.dryRun) {
3411
+ process.stdout.write(`${results.flatMap((result) => result.commands).join("\n")}\n`);
3053
3412
  return;
3054
3413
  }
3055
- for (const skill of skills) {
3056
- const description = skill.description.replace(/[.?!]?$/, ".");
3057
- const aliases = skill.aliases.length
3058
- ? ` Aliases: ${skill.aliases.join(", ")}.`
3414
+ const installedNames = results
3415
+ .map((result) => result.displayName)
3416
+ .join(", ");
3417
+ const skillsAgents = [
3418
+ ...new Set(results.flatMap((result) => result.skillsAgents)),
3419
+ ];
3420
+ const mcpClients = [
3421
+ ...new Set(results.flatMap((result) => result.mcpClients)),
3422
+ ];
3423
+ const mcpUrls = [
3424
+ ...new Set(results.map((result) => result.mcpUrl).filter(Boolean)),
3425
+ ];
3426
+ const localCommands = [
3427
+ ...new Set(results
3428
+ .filter((result) => result.local)
3429
+ .flatMap((result) => result.commands)),
3430
+ ];
3431
+ const authConnected = results.some((result) => result.connected);
3432
+ const pendingConnectCommands = [
3433
+ ...new Set(results
3434
+ .map((result) => result.connectCommand)
3435
+ .filter((command) => Boolean(command))),
3436
+ ];
3437
+ const authLine = authConnected
3438
+ ? "Authentication: completed."
3439
+ : pendingConnectCommands.length
3440
+ ? `Authentication: pending — run ${pendingConnectCommands.join(" && ")}`
3059
3441
  : "";
3060
- const target = skill.local ? "local command" : skill.mcpUrl;
3061
- process.stdout.write(`${skill.id.padEnd(12)} ${description}${aliases} (${target})\n`);
3442
+ const githubActions = [
3443
+ ...new Set(results
3444
+ .map((result) => result.githubActionPath)
3445
+ .filter((p) => Boolean(p))),
3446
+ ];
3447
+ const githubActionLine = githubActions.length
3448
+ ? `PR Visual Recap workflow: wrote ${githubActions.join(", ")}.\nNext: run ${prVisualRecapSetupCommand()} to configure GitHub secrets/variables, or set them manually:\n ${PR_VISUAL_RECAP_SETUP.join("\n ")}`
3449
+ : "";
3450
+ const githubActionSuggestions = [
3451
+ ...new Set(results
3452
+ .map((result) => result.githubActionSuggestedCommand)
3453
+ .filter((command) => Boolean(command))),
3454
+ ];
3455
+ const githubActionSuggestionLine = githubActionSuggestions.length
3456
+ ? `Optional PR Visual Recap workflow: run ${githubActionSuggestions.join(" && ")} to add automatic recap comments on pull requests.`
3457
+ : "";
3458
+ const clack = await import("@clack/prompts");
3459
+ const summary = [
3460
+ skillsAgents.length
3461
+ ? `Skill instructions ${skillsAgents.join(", ")}`
3462
+ : "Skill instructions skipped",
3463
+ mcpClients.length
3464
+ ? `MCP config ${mcpClients.join(", ")}`
3465
+ : "MCP config not required",
3466
+ mcpUrls.length ? `MCP URL ${mcpUrls.join(", ")}` : "",
3467
+ authConnected
3468
+ ? "Authentication completed"
3469
+ : pendingConnectCommands.length
3470
+ ? `Authentication pending — run ${pendingConnectCommands.join(" && ")}`
3471
+ : "",
3472
+ localCommands.length
3473
+ ? `Local command ${localCommands.join(", ")}`
3474
+ : "",
3475
+ ].filter(Boolean);
3476
+ clack.note(summary.join("\n"), `Installed ${installedNames} skill${results.length === 1 ? "" : "s"}`);
3477
+ // GitHub Action follow-ups — kept as exact, copy-pasteable command lines.
3478
+ for (const line of [githubActionLine, githubActionSuggestionLine].filter(Boolean)) {
3479
+ process.stdout.write(`${line}\n`);
3062
3480
  }
3063
- return;
3064
- }
3065
- if (parsed.command === "status" || parsed.command === "update") {
3066
- runSkillsStatusOrUpdate(parsed, options, parsed.command === "update");
3067
- return;
3068
- }
3069
- const targets = await resolveSkillTargets(parsed, options);
3070
- if (!targets)
3071
- return;
3072
- const clients = await resolveSkillsClients(parsed, options);
3073
- if (!clients)
3074
- return;
3075
- const results = [];
3076
- for (const target of targets) {
3077
- results.push(await addAgentNativeSkill({
3078
- ...parsed,
3079
- target,
3080
- client: clientArgForClients(clients),
3081
- clients,
3082
- }, {
3083
- ...options,
3084
- log,
3085
- }));
3481
+ const slashCommands = completedSkills.map((name) => `/${name}`).join(" ");
3482
+ const clientHint = parsed.clientExplicit
3483
+ ? ""
3484
+ : "\n Add another client later with --client <client> (e.g. --client claude-code).";
3485
+ clack.outro(`✅ All set! Start using ${slashCommands || "your new skills"} in your agent client.` +
3486
+ `\n You may need to reload the client for the skill + MCP server to appear.` +
3487
+ clientHint);
3086
3488
  }
3087
- if (parsed.printJson) {
3088
- process.stdout.write(`${JSON.stringify(results.length === 1 ? results[0] : results, null, 2)}\n`);
3089
- return;
3489
+ catch (error) {
3490
+ telemetry.track("skills_cli failed", {
3491
+ command: parsed.command,
3492
+ error: error instanceof Error ? error.message : String(error),
3493
+ durationMs: Date.now() - startedAt,
3494
+ });
3495
+ throw error;
3090
3496
  }
3091
- if (parsed.dryRun) {
3092
- process.stdout.write(`${results.flatMap((result) => result.commands).join("\n")}\n`);
3093
- return;
3497
+ finally {
3498
+ await telemetry.flush();
3094
3499
  }
3095
- const installedNames = results.map((result) => result.displayName).join(", ");
3096
- const skillsAgents = [
3097
- ...new Set(results.flatMap((result) => result.skillsAgents)),
3098
- ];
3099
- const mcpClients = [
3100
- ...new Set(results.flatMap((result) => result.mcpClients)),
3101
- ];
3102
- const mcpUrls = [
3103
- ...new Set(results.map((result) => result.mcpUrl).filter(Boolean)),
3104
- ];
3105
- const localCommands = [
3106
- ...new Set(results
3107
- .filter((result) => result.local)
3108
- .flatMap((result) => result.commands)),
3109
- ];
3110
- const authConnected = results.some((result) => result.connected);
3111
- const pendingConnectCommands = [
3112
- ...new Set(results
3113
- .map((result) => result.connectCommand)
3114
- .filter((command) => Boolean(command))),
3115
- ];
3116
- const authLine = authConnected
3117
- ? "Authentication: completed."
3118
- : pendingConnectCommands.length
3119
- ? `Authentication: pending — run ${pendingConnectCommands.join(" && ")}`
3120
- : "";
3121
- const githubActions = [
3122
- ...new Set(results
3123
- .map((result) => result.githubActionPath)
3124
- .filter((p) => Boolean(p))),
3125
- ];
3126
- const githubActionLine = githubActions.length
3127
- ? `PR Visual Recap workflow: wrote ${githubActions.join(", ")}.\nNext: run ${prVisualRecapSetupCommand()} to configure GitHub secrets/variables, or set them manually:\n ${PR_VISUAL_RECAP_SETUP.join("\n ")}`
3128
- : "";
3129
- const githubActionSuggestions = [
3130
- ...new Set(results
3131
- .map((result) => result.githubActionSuggestedCommand)
3132
- .filter((command) => Boolean(command))),
3133
- ];
3134
- const githubActionSuggestionLine = githubActionSuggestions.length
3135
- ? `Optional PR Visual Recap workflow: run ${githubActionSuggestions.join(" && ")} to add automatic recap comments on pull requests.`
3136
- : "";
3137
- process.stdout.write([
3138
- `Installed ${installedNames} skill${results.length === 1 ? "" : "s"}.`,
3139
- skillsAgents.length
3140
- ? `Skill instructions: ${skillsAgents.join(", ")}.`
3141
- : "Skill instructions: skipped.",
3142
- mcpClients.length
3143
- ? `MCP config: ${mcpClients.join(", ")}.`
3144
- : "MCP config: not required.",
3145
- mcpUrls.length
3146
- ? `MCP URL${mcpUrls.length === 1 ? "" : "s"}: ${mcpUrls.join(", ")}.`
3147
- : "",
3148
- authLine,
3149
- githubActionLine,
3150
- githubActionSuggestionLine,
3151
- localCommands.length ? `Local command: ${localCommands.join(", ")}.` : "",
3152
- "Restart or reload selected agent clients if the skill is not visible yet.",
3153
- parsed.clientExplicit
3154
- ? ""
3155
- : `To add another client later, rerun with --client <client> (for example: --client claude-code).`,
3156
- ]
3157
- .filter(Boolean)
3158
- .join("\n") + "\n");
3159
3500
  }
3160
3501
  //# sourceMappingURL=skills.js.map