@agent-native/core 0.52.0 → 0.54.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 (267) hide show
  1. package/README.md +41 -95
  2. package/blueprints/action/crud.md +98 -0
  3. package/blueprints/channel/discord.md +74 -0
  4. package/blueprints/provider/stripe.md +87 -0
  5. package/blueprints/sandbox/docker.md +78 -0
  6. package/dist/action.d.ts +64 -1
  7. package/dist/action.d.ts.map +1 -1
  8. package/dist/action.js +73 -2
  9. package/dist/action.js.map +1 -1
  10. package/dist/agent/index.d.ts +1 -0
  11. package/dist/agent/index.d.ts.map +1 -1
  12. package/dist/agent/index.js +1 -0
  13. package/dist/agent/index.js.map +1 -1
  14. package/dist/agent/observational-memory/compactor.d.ts +43 -0
  15. package/dist/agent/observational-memory/compactor.d.ts.map +1 -0
  16. package/dist/agent/observational-memory/compactor.js +50 -0
  17. package/dist/agent/observational-memory/compactor.js.map +1 -0
  18. package/dist/agent/observational-memory/config.d.ts +37 -0
  19. package/dist/agent/observational-memory/config.d.ts.map +1 -0
  20. package/dist/agent/observational-memory/config.js +48 -0
  21. package/dist/agent/observational-memory/config.js.map +1 -0
  22. package/dist/agent/observational-memory/index.d.ts +26 -0
  23. package/dist/agent/observational-memory/index.d.ts.map +1 -0
  24. package/dist/agent/observational-memory/index.js +25 -0
  25. package/dist/agent/observational-memory/index.js.map +1 -0
  26. package/dist/agent/observational-memory/internal-run.d.ts +37 -0
  27. package/dist/agent/observational-memory/internal-run.d.ts.map +1 -0
  28. package/dist/agent/observational-memory/internal-run.js +59 -0
  29. package/dist/agent/observational-memory/internal-run.js.map +1 -0
  30. package/dist/agent/observational-memory/message-text.d.ts +13 -0
  31. package/dist/agent/observational-memory/message-text.d.ts.map +1 -0
  32. package/dist/agent/observational-memory/message-text.js +46 -0
  33. package/dist/agent/observational-memory/message-text.js.map +1 -0
  34. package/dist/agent/observational-memory/migrations.d.ts +13 -0
  35. package/dist/agent/observational-memory/migrations.d.ts.map +1 -0
  36. package/dist/agent/observational-memory/migrations.js +43 -0
  37. package/dist/agent/observational-memory/migrations.js.map +1 -0
  38. package/dist/agent/observational-memory/observer.d.ts +37 -0
  39. package/dist/agent/observational-memory/observer.d.ts.map +1 -0
  40. package/dist/agent/observational-memory/observer.js +82 -0
  41. package/dist/agent/observational-memory/observer.js.map +1 -0
  42. package/dist/agent/observational-memory/plugin.d.ts +16 -0
  43. package/dist/agent/observational-memory/plugin.d.ts.map +1 -0
  44. package/dist/agent/observational-memory/plugin.js +26 -0
  45. package/dist/agent/observational-memory/plugin.js.map +1 -0
  46. package/dist/agent/observational-memory/prompts.d.ts +27 -0
  47. package/dist/agent/observational-memory/prompts.d.ts.map +1 -0
  48. package/dist/agent/observational-memory/prompts.js +42 -0
  49. package/dist/agent/observational-memory/prompts.js.map +1 -0
  50. package/dist/agent/observational-memory/read.d.ts +45 -0
  51. package/dist/agent/observational-memory/read.d.ts.map +1 -0
  52. package/dist/agent/observational-memory/read.js +97 -0
  53. package/dist/agent/observational-memory/read.js.map +1 -0
  54. package/dist/agent/observational-memory/reflector.d.ts +31 -0
  55. package/dist/agent/observational-memory/reflector.d.ts.map +1 -0
  56. package/dist/agent/observational-memory/reflector.js +76 -0
  57. package/dist/agent/observational-memory/reflector.js.map +1 -0
  58. package/dist/agent/observational-memory/schema.d.ts +267 -0
  59. package/dist/agent/observational-memory/schema.d.ts.map +1 -0
  60. package/dist/agent/observational-memory/schema.js +48 -0
  61. package/dist/agent/observational-memory/schema.js.map +1 -0
  62. package/dist/agent/observational-memory/store.d.ts +52 -0
  63. package/dist/agent/observational-memory/store.d.ts.map +1 -0
  64. package/dist/agent/observational-memory/store.js +197 -0
  65. package/dist/agent/observational-memory/store.js.map +1 -0
  66. package/dist/agent/observational-memory/types.d.ts +61 -0
  67. package/dist/agent/observational-memory/types.d.ts.map +1 -0
  68. package/dist/agent/observational-memory/types.js +9 -0
  69. package/dist/agent/observational-memory/types.js.map +1 -0
  70. package/dist/agent/processors.d.ts +146 -0
  71. package/dist/agent/processors.d.ts.map +1 -0
  72. package/dist/agent/processors.js +122 -0
  73. package/dist/agent/processors.js.map +1 -0
  74. package/dist/agent/production-agent.d.ts +25 -0
  75. package/dist/agent/production-agent.d.ts.map +1 -1
  76. package/dist/agent/production-agent.js +341 -1
  77. package/dist/agent/production-agent.js.map +1 -1
  78. package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
  79. package/dist/agent/run-loop-with-resume.js +48 -0
  80. package/dist/agent/run-loop-with-resume.js.map +1 -1
  81. package/dist/agent/run-store.d.ts +17 -0
  82. package/dist/agent/run-store.d.ts.map +1 -1
  83. package/dist/agent/run-store.js +55 -0
  84. package/dist/agent/run-store.js.map +1 -1
  85. package/dist/agent/runtime-context.d.ts +30 -0
  86. package/dist/agent/runtime-context.d.ts.map +1 -1
  87. package/dist/agent/runtime-context.js +54 -1
  88. package/dist/agent/runtime-context.js.map +1 -1
  89. package/dist/agent/tool-call-journal.d.ts +99 -0
  90. package/dist/agent/tool-call-journal.d.ts.map +1 -0
  91. package/dist/agent/tool-call-journal.js +212 -0
  92. package/dist/agent/tool-call-journal.js.map +1 -0
  93. package/dist/agent/types.d.ts +35 -0
  94. package/dist/agent/types.d.ts.map +1 -1
  95. package/dist/agent/types.js.map +1 -1
  96. package/dist/cli/add.d.ts +109 -0
  97. package/dist/cli/add.d.ts.map +1 -0
  98. package/dist/cli/add.js +352 -0
  99. package/dist/cli/add.js.map +1 -0
  100. package/dist/cli/connect.d.ts +2 -2
  101. package/dist/cli/connect.d.ts.map +1 -1
  102. package/dist/cli/connect.js +92 -24
  103. package/dist/cli/connect.js.map +1 -1
  104. package/dist/cli/eval.d.ts +17 -0
  105. package/dist/cli/eval.d.ts.map +1 -0
  106. package/dist/cli/eval.js +121 -0
  107. package/dist/cli/eval.js.map +1 -0
  108. package/dist/cli/index.js +44 -3
  109. package/dist/cli/index.js.map +1 -1
  110. package/dist/cli/mcp.d.ts.map +1 -1
  111. package/dist/cli/mcp.js +11 -5
  112. package/dist/cli/mcp.js.map +1 -1
  113. package/dist/cli/plan-local.d.ts +66 -5
  114. package/dist/cli/plan-local.d.ts.map +1 -1
  115. package/dist/cli/plan-local.js +622 -21
  116. package/dist/cli/plan-local.js.map +1 -1
  117. package/dist/cli/skills.d.ts +2 -2
  118. package/dist/cli/skills.d.ts.map +1 -1
  119. package/dist/cli/skills.js +108 -62
  120. package/dist/cli/skills.js.map +1 -1
  121. package/dist/client/AssistantChat.d.ts.map +1 -1
  122. package/dist/client/AssistantChat.js +118 -92
  123. package/dist/client/AssistantChat.js.map +1 -1
  124. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  125. package/dist/client/agent-chat-adapter.js +16 -0
  126. package/dist/client/agent-chat-adapter.js.map +1 -1
  127. package/dist/client/chat/tool-call-display.d.ts +20 -1
  128. package/dist/client/chat/tool-call-display.d.ts.map +1 -1
  129. package/dist/client/chat/tool-call-display.js +32 -7
  130. package/dist/client/chat/tool-call-display.js.map +1 -1
  131. package/dist/client/sse-event-processor.d.ts +13 -0
  132. package/dist/client/sse-event-processor.d.ts.map +1 -1
  133. package/dist/client/sse-event-processor.js +21 -0
  134. package/dist/client/sse-event-processor.js.map +1 -1
  135. package/dist/coding-tools/run-code.d.ts.map +1 -1
  136. package/dist/coding-tools/run-code.js +18 -2
  137. package/dist/coding-tools/run-code.js.map +1 -1
  138. package/dist/db/client.d.ts +4 -2
  139. package/dist/db/client.d.ts.map +1 -1
  140. package/dist/db/client.js +6 -4
  141. package/dist/db/client.js.map +1 -1
  142. package/dist/deploy/route-discovery.d.ts.map +1 -1
  143. package/dist/deploy/route-discovery.js +1 -0
  144. package/dist/deploy/route-discovery.js.map +1 -1
  145. package/dist/eval/agent-runner.d.ts +63 -0
  146. package/dist/eval/agent-runner.d.ts.map +1 -0
  147. package/dist/eval/agent-runner.js +142 -0
  148. package/dist/eval/agent-runner.js.map +1 -0
  149. package/dist/eval/define-eval.d.ts +29 -0
  150. package/dist/eval/define-eval.d.ts.map +1 -0
  151. package/dist/eval/define-eval.js +43 -0
  152. package/dist/eval/define-eval.js.map +1 -0
  153. package/dist/eval/index.d.ts +18 -0
  154. package/dist/eval/index.d.ts.map +1 -0
  155. package/dist/eval/index.js +17 -0
  156. package/dist/eval/index.js.map +1 -0
  157. package/dist/eval/report.d.ts +8 -0
  158. package/dist/eval/report.d.ts.map +1 -0
  159. package/dist/eval/report.js +44 -0
  160. package/dist/eval/report.js.map +1 -0
  161. package/dist/eval/runner.d.ts +67 -0
  162. package/dist/eval/runner.d.ts.map +1 -0
  163. package/dist/eval/runner.js +256 -0
  164. package/dist/eval/runner.js.map +1 -0
  165. package/dist/eval/scorer.d.ts +83 -0
  166. package/dist/eval/scorer.d.ts.map +1 -0
  167. package/dist/eval/scorer.js +195 -0
  168. package/dist/eval/scorer.js.map +1 -0
  169. package/dist/eval/types.d.ts +162 -0
  170. package/dist/eval/types.d.ts.map +1 -0
  171. package/dist/eval/types.js +20 -0
  172. package/dist/eval/types.js.map +1 -0
  173. package/dist/extensions/fetch-tool.d.ts.map +1 -1
  174. package/dist/extensions/fetch-tool.js +80 -15
  175. package/dist/extensions/fetch-tool.js.map +1 -1
  176. package/dist/extensions/web-content.d.ts +61 -0
  177. package/dist/extensions/web-content.d.ts.map +1 -0
  178. package/dist/extensions/web-content.js +468 -0
  179. package/dist/extensions/web-content.js.map +1 -0
  180. package/dist/extensions/web-search-tool.js +3 -3
  181. package/dist/extensions/web-search-tool.js.map +1 -1
  182. package/dist/mcp/build-server.d.ts.map +1 -1
  183. package/dist/mcp/build-server.js +4 -1
  184. package/dist/mcp/build-server.js.map +1 -1
  185. package/dist/observability/traces.d.ts.map +1 -1
  186. package/dist/observability/traces.js +100 -1
  187. package/dist/observability/traces.js.map +1 -1
  188. package/dist/observability/tracing.d.ts +73 -0
  189. package/dist/observability/tracing.d.ts.map +1 -0
  190. package/dist/observability/tracing.js +126 -0
  191. package/dist/observability/tracing.js.map +1 -0
  192. package/dist/onboarding/default-steps.d.ts.map +1 -1
  193. package/dist/onboarding/default-steps.js +4 -1
  194. package/dist/onboarding/default-steps.js.map +1 -1
  195. package/dist/provider-api/actions/query-staged-dataset.d.ts +1 -1
  196. package/dist/provider-api/corpus-jobs.d.ts +80 -0
  197. package/dist/provider-api/corpus-jobs.d.ts.map +1 -1
  198. package/dist/provider-api/corpus-jobs.js +219 -22
  199. package/dist/provider-api/corpus-jobs.js.map +1 -1
  200. package/dist/provider-api/index.d.ts +24 -32
  201. package/dist/provider-api/index.d.ts.map +1 -1
  202. package/dist/provider-api/index.js +28 -1
  203. package/dist/provider-api/index.js.map +1 -1
  204. package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
  205. package/dist/scripts/agent-engines/list-agent-engines.js +10 -3
  206. package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
  207. package/dist/server/action-discovery.d.ts.map +1 -1
  208. package/dist/server/action-discovery.js +4 -0
  209. package/dist/server/action-discovery.js.map +1 -1
  210. package/dist/server/agent-chat-plugin.d.ts +9 -0
  211. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  212. package/dist/server/agent-chat-plugin.js +119 -111
  213. package/dist/server/agent-chat-plugin.js.map +1 -1
  214. package/dist/server/agent-teams.d.ts +62 -0
  215. package/dist/server/agent-teams.d.ts.map +1 -1
  216. package/dist/server/agent-teams.js +99 -2
  217. package/dist/server/agent-teams.js.map +1 -1
  218. package/dist/server/better-auth-instance.d.ts +7 -0
  219. package/dist/server/better-auth-instance.d.ts.map +1 -1
  220. package/dist/server/better-auth-instance.js +90 -0
  221. package/dist/server/better-auth-instance.js.map +1 -1
  222. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  223. package/dist/server/core-routes-plugin.js +7 -4
  224. package/dist/server/core-routes-plugin.js.map +1 -1
  225. package/dist/server/credential-provider.d.ts.map +1 -1
  226. package/dist/server/credential-provider.js +2 -0
  227. package/dist/server/credential-provider.js.map +1 -1
  228. package/dist/server/deep-link.d.ts +7 -0
  229. package/dist/server/deep-link.d.ts.map +1 -1
  230. package/dist/server/deep-link.js +13 -2
  231. package/dist/server/deep-link.js.map +1 -1
  232. package/dist/server/framework-request-handler.d.ts.map +1 -1
  233. package/dist/server/framework-request-handler.js +33 -1
  234. package/dist/server/framework-request-handler.js.map +1 -1
  235. package/dist/server/index.d.ts +2 -1
  236. package/dist/server/index.d.ts.map +1 -1
  237. package/dist/server/index.js +2 -1
  238. package/dist/server/index.js.map +1 -1
  239. package/dist/templates/default/.agents/skills/actions/SKILL.md +52 -1
  240. package/dist/templates/default/.agents/skills/security/SKILL.md +22 -0
  241. package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +52 -1
  242. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +16 -4
  243. package/dist/templates/workspace-core/.agents/skills/harness-agents/SKILL.md +20 -0
  244. package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +31 -0
  245. package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +22 -0
  246. package/docs/content/actions.md +50 -0
  247. package/docs/content/agent-teams.md +32 -0
  248. package/docs/content/blueprint-installer.md +73 -0
  249. package/docs/content/durable-resume.md +49 -0
  250. package/docs/content/evals.md +141 -0
  251. package/docs/content/external-agents.md +2 -2
  252. package/docs/content/human-approval.md +101 -0
  253. package/docs/content/observability.md +21 -0
  254. package/docs/content/observational-memory.md +63 -0
  255. package/docs/content/plan-plugin.md +5 -0
  256. package/docs/content/pr-visual-recap.md +9 -5
  257. package/docs/content/processors.md +99 -0
  258. package/docs/content/sandbox-adapters.md +134 -0
  259. package/docs/content/template-plan.md +97 -21
  260. package/package.json +10 -1
  261. package/src/templates/default/.agents/skills/actions/SKILL.md +52 -1
  262. package/src/templates/default/.agents/skills/security/SKILL.md +22 -0
  263. package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +52 -1
  264. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +16 -4
  265. package/src/templates/workspace-core/.agents/skills/harness-agents/SKILL.md +20 -0
  266. package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +31 -0
  267. package/src/templates/workspace-core/.agents/skills/security/SKILL.md +22 -0
@@ -0,0 +1,352 @@
1
+ /**
2
+ * `agent-native add <kind> [name|url]` — the **blueprint installer**.
3
+ *
4
+ * Borrowed from Flue's `flue add`: instead of being a dumb scaffolder that
5
+ * writes files for you, this command emits a curated Markdown *integration
6
+ * blueprint* to stdout. You pipe that blueprint into your own coding agent,
7
+ * which applies the changes against the live repo:
8
+ *
9
+ * agent-native add provider stripe | claude
10
+ * agent-native add channel discord | codex
11
+ *
12
+ * This fits the agent-applies-changes, filesystem-first house style: the
13
+ * framework supplies the recipe (the canonical files to touch, the rules to
14
+ * honor, the verification step), and the coding agent does the editing with
15
+ * full repo context.
16
+ *
17
+ * A bare name resolves a curated blueprint from `blueprints/<kind>/<name>.md`.
18
+ * A URL instead of a name emits a GENERIC "research-and-integrate" blueprint
19
+ * for that kind with the URL embedded as the research starting point (mirrors
20
+ * Flue: a URL is a research seed, not a known recipe).
21
+ *
22
+ * Blueprint `.md` files ship in the published package via the `blueprints`
23
+ * entry in `package.json` `files`, so they live at
24
+ * `node_modules/@agent-native/core/blueprints/**` at runtime. Resolution works
25
+ * both from source (tsx: `src/cli` → `../../blueprints`) and from the compiled
26
+ * package (`dist/cli` → `../../blueprints`), with an upward-walk fallback.
27
+ */
28
+ import fs from "node:fs";
29
+ import path from "node:path";
30
+ import { fileURLToPath } from "node:url";
31
+ /**
32
+ * Locate the directory that holds the blueprint `.md` recipes.
33
+ *
34
+ * Both `src/cli` (tsx/source) and `dist/cli` (published) sit two levels under
35
+ * the package root, where `blueprints/` lives, so `../../blueprints` from this
36
+ * module's directory is the primary path. We additionally walk upward looking
37
+ * for a `blueprints` directory as a resilience fallback (e.g. unusual bundler
38
+ * layouts). An explicit override is honored for tests.
39
+ */
40
+ export function resolveBlueprintsRoot(overrideRoot) {
41
+ if (overrideRoot)
42
+ return overrideRoot;
43
+ const here = path.dirname(fileURLToPath(import.meta.url));
44
+ const primary = path.resolve(here, "../../blueprints");
45
+ if (isDir(primary))
46
+ return primary;
47
+ // Fallback: walk up from this module looking for a sibling `blueprints` dir.
48
+ let dir = here;
49
+ for (let i = 0; i < 8; i += 1) {
50
+ const candidate = path.join(dir, "blueprints");
51
+ if (isDir(candidate))
52
+ return candidate;
53
+ const parent = path.dirname(dir);
54
+ if (parent === dir)
55
+ break;
56
+ dir = parent;
57
+ }
58
+ // Return the primary path even if missing so error messages are concrete.
59
+ return primary;
60
+ }
61
+ function isDir(p) {
62
+ try {
63
+ return fs.statSync(p).isDirectory();
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ }
69
+ /** True for an argument that should be treated as a research URL, not a name. */
70
+ export function looksLikeUrl(value) {
71
+ return /^https?:\/\//i.test(value.trim());
72
+ }
73
+ /** List the blueprint kinds (subdirectories) available, sorted. */
74
+ export function listKinds(root) {
75
+ if (!isDir(root))
76
+ return [];
77
+ return fs
78
+ .readdirSync(root, { withFileTypes: true })
79
+ .filter((e) => e.isDirectory())
80
+ .map((e) => e.name)
81
+ .sort();
82
+ }
83
+ /** List the blueprint names available under a kind, sorted (no `.md`). */
84
+ export function listBlueprintNames(root, kind) {
85
+ const dir = path.join(root, kind);
86
+ if (!isDir(dir))
87
+ return [];
88
+ return fs
89
+ .readdirSync(dir, { withFileTypes: true })
90
+ .filter((e) => e.isFile() && e.name.endsWith(".md"))
91
+ .map((e) => e.name.slice(0, -".md".length))
92
+ .sort();
93
+ }
94
+ /** A flat catalog of every kind and its blueprint names. */
95
+ export function listCatalog(root) {
96
+ return listKinds(root).map((kind) => ({
97
+ kind,
98
+ names: listBlueprintNames(root, kind),
99
+ }));
100
+ }
101
+ /** Render the `--list` / no-args catalog text. */
102
+ export function formatCatalog(root) {
103
+ const catalog = listCatalog(root);
104
+ const lines = [];
105
+ lines.push("Available blueprints:");
106
+ lines.push("");
107
+ if (catalog.length === 0) {
108
+ lines.push(" (none found)");
109
+ }
110
+ else {
111
+ for (const { kind, names } of catalog) {
112
+ const shown = names.length > 0 ? names.join(", ") : "(generic — pass a URL)";
113
+ lines.push(` ${kind.padEnd(10)} ${shown}`);
114
+ }
115
+ }
116
+ lines.push("");
117
+ lines.push("Usage:");
118
+ lines.push(" agent-native add <kind> <name> Print a curated blueprint");
119
+ lines.push(" agent-native add <kind> <https://docs…> Research-and-integrate from a URL");
120
+ lines.push(" agent-native add --list Show this list");
121
+ lines.push("");
122
+ lines.push("Pipe a blueprint into your coding agent to apply it:");
123
+ lines.push(" agent-native add provider stripe | claude");
124
+ lines.push(" agent-native add channel discord | codex");
125
+ return lines.join("\n");
126
+ }
127
+ /**
128
+ * Build the generic "research-and-integrate" blueprint emitted when the user
129
+ * passes a URL instead of a known blueprint name. Mirrors Flue: a URL is a
130
+ * research seed. We keep this self-contained — the coding agent reading it has
131
+ * no other context.
132
+ */
133
+ export function buildGenericUrlBlueprint(kind, url) {
134
+ const kindGuidance = GENERIC_KIND_GUIDANCE[kind] ?? GENERIC_DEFAULT_GUIDANCE;
135
+ return `# Blueprint: integrate a new ${kind} from a URL
136
+
137
+ You are a coding agent working inside an **agent-native** app (a repo built on
138
+ \`@agent-native/core\`). Apply this blueprint as real source changes on the
139
+ current branch. Do not just describe the work — research, implement, then verify.
140
+
141
+ ## Research seed
142
+
143
+ Start from this URL and follow it for the API/protocol/contract you need:
144
+
145
+ ${url}
146
+
147
+ Fetch it (and the pages it links to) to learn the real endpoints, auth model,
148
+ payload shapes, and any signature/verification requirements. Do not guess from
149
+ training data — the docs are the source of truth, and package/API versions
150
+ drift. Confirm the current version before writing code.
151
+
152
+ ## What you're adding
153
+
154
+ A new **${kind}** integration. ${kindGuidance}
155
+
156
+ ## How agent-native wants it built
157
+
158
+ - **Actions are the single source of truth.** Add app operations in \`actions/\`
159
+ with \`defineAction\` (Zod schema). The agent calls them as tools; the frontend
160
+ calls the same action through \`useActionQuery\` / \`useActionMutation\`. Do NOT
161
+ add \`/api/*\` or Nitro pass-through routes that just wrap an action.
162
+ - **Prefer the provider-api substrate for external HTTP.** For ad-hoc reads
163
+ against a third-party API, register the provider with
164
+ \`@agent-native/core/provider-api\` and expose the
165
+ \`provider-api-catalog\` / \`provider-api-docs\` / \`provider-api-request\` trio
166
+ instead of one rigid action per endpoint. First-class actions are shortcuts,
167
+ not capability limits.
168
+ - **Read the relevant skill before editing** — \`actions\`,
169
+ \`integration-webhooks\`, \`secrets\`, \`onboarding\`, \`sharing\`, \`security\` —
170
+ for the area you're touching.
171
+ - **Never hardcode secrets.** Read API keys / tokens / signing secrets from the
172
+ secret store (\`readAppSecret\`, the provider credential adapter, OAuth token
173
+ helpers) at call time. Use obviously-fake placeholders in any example
174
+ (e.g. \`sk_test_PLACEHOLDER_xxx\`), never a real credential.
175
+ - **Scope ownable data.** Tables with \`ownableColumns()\` require
176
+ \`accessFilter\` / \`resolveAccess\` / \`assertAccess\`; fail closed.
177
+ - **Changeset.** If you edit a publishable package's source
178
+ (\`packages/core\`, \`packages/dispatch\`, \`packages/scheduling\`,
179
+ \`packages/pinpoint\`), add a \`.changeset/*.md\`.
180
+
181
+ ## Verify
182
+
183
+ 1. \`agent-native typecheck\` (or \`tsc --noEmit\`) passes.
184
+ 2. Add a focused \`*.spec.ts\` for the new surface and run it.
185
+ 3. Exercise the real workflow end to end: invoke the new action from the agent
186
+ chat (and the UI if applicable), and confirm the external call round-trips
187
+ with credentials injected and secrets redacted.
188
+ `;
189
+ }
190
+ const GENERIC_DEFAULT_GUIDANCE = "Identify whether it is best modeled as an action, a provider-api integration, " +
191
+ "an inbound channel adapter, or a sandbox backend, and follow that area's skill.";
192
+ const GENERIC_KIND_GUIDANCE = {
193
+ provider: "Wire it into the provider-api substrate (`@agent-native/core/provider-api`): " +
194
+ "register the base URL, auth style, credential key, and docs URLs, then expose " +
195
+ "the `provider-api-catalog` / `provider-api-docs` / `provider-api-request` trio " +
196
+ "so any endpoint is reachable without one action per endpoint.",
197
+ channel: "Implement a `PlatformAdapter` (see " +
198
+ "`packages/core/src/integrations/types.ts` and the adapters under " +
199
+ "`packages/core/src/integrations/adapters/`) and register it in " +
200
+ "`getDefaultAdapters()` in `packages/core/src/integrations/plugin.ts`. " +
201
+ "Enqueue to SQL and return 200 fast; run the agent loop in the separate " +
202
+ "`_process-task` execution. Read the `integration-webhooks` skill.",
203
+ sandbox: "Implement the `SandboxAdapter` seam in " +
204
+ "`packages/core/src/coding-tools/sandbox/` (mirror " +
205
+ "`local-child-process-adapter.ts`) and select it via `AGENT_NATIVE_SANDBOX` " +
206
+ "or `registerSandboxAdapter()`. The adapter only runs the already-prepared, " +
207
+ "non-secret module source — it never sees app secrets.",
208
+ action: "Add a single multi-surface `defineAction` in `actions/` with a Zod schema. " +
209
+ "Keep the surface small and orthogonal (one CRUD-style `update` over N " +
210
+ "per-field actions). Read the `actions` skill.",
211
+ };
212
+ /**
213
+ * Resolve a blueprint for a `kind` + optional `name`/`url`.
214
+ *
215
+ * - A known name → the curated `blueprints/<kind>/<name>.md`.
216
+ * - A URL → the generic research-and-integrate blueprint for the kind.
217
+ * - Unknown name → throws `AddResolutionError` listing what's available.
218
+ */
219
+ export function resolveBlueprint(opts) {
220
+ const { kind, nameOrUrl, root } = opts;
221
+ const kinds = listKinds(root);
222
+ if (!kinds.includes(kind)) {
223
+ throw new AddResolutionError(`Unknown blueprint kind: ${kind}\n\n${formatCatalog(root)}`);
224
+ }
225
+ // A URL seed → generic blueprint for the kind.
226
+ if (nameOrUrl && looksLikeUrl(nameOrUrl)) {
227
+ return {
228
+ markdown: buildGenericUrlBlueprint(kind, nameOrUrl.trim()),
229
+ source: {
230
+ kind: "generic-url",
231
+ blueprintKind: kind,
232
+ url: nameOrUrl.trim(),
233
+ },
234
+ };
235
+ }
236
+ const names = listBlueprintNames(root, kind);
237
+ // No name given: if exactly one curated blueprint exists, use it; otherwise
238
+ // ask the user to pick one (or pass a URL for the generic path).
239
+ if (!nameOrUrl) {
240
+ if (names.length === 1) {
241
+ return loadCurated(root, kind, names[0]);
242
+ }
243
+ throw new AddResolutionError(`Specify a ${kind} blueprint name or a URL.\n` +
244
+ ` Available ${kind} blueprints: ${names.length ? names.join(", ") : "(none — pass a URL)"}\n` +
245
+ ` Or research from a URL: agent-native add ${kind} https://…`);
246
+ }
247
+ if (!names.includes(nameOrUrl)) {
248
+ throw new AddResolutionError(`Unknown ${kind} blueprint: ${nameOrUrl}\n` +
249
+ ` Available ${kind} blueprints: ${names.length ? names.join(", ") : "(none)"}\n` +
250
+ ` Or research from a URL: agent-native add ${kind} https://…`);
251
+ }
252
+ return loadCurated(root, kind, nameOrUrl);
253
+ }
254
+ function loadCurated(root, kind, name) {
255
+ const filePath = path.join(root, kind, `${name}.md`);
256
+ const markdown = fs.readFileSync(filePath, "utf-8");
257
+ return {
258
+ markdown,
259
+ source: { kind: "curated", blueprintKind: kind, name, path: filePath },
260
+ };
261
+ }
262
+ /** Thrown for an unknown kind/name; the CLI prints the message and exits 1. */
263
+ export class AddResolutionError extends Error {
264
+ constructor(message) {
265
+ super(message);
266
+ this.name = "AddResolutionError";
267
+ }
268
+ }
269
+ export function parseAddArgs(argv) {
270
+ const out = {
271
+ list: false,
272
+ help: false,
273
+ print: false,
274
+ positionals: [],
275
+ };
276
+ for (const arg of argv) {
277
+ if (arg === "--")
278
+ continue;
279
+ if (arg === "--list" || arg === "-l")
280
+ out.list = true;
281
+ else if (arg === "--help" || arg === "-h")
282
+ out.help = true;
283
+ else if (arg === "--print" || arg === "-p")
284
+ out.print = true;
285
+ else if (arg.startsWith("-")) {
286
+ // Ignore unknown flags rather than misparse them as a name.
287
+ continue;
288
+ }
289
+ else
290
+ out.positionals.push(arg);
291
+ }
292
+ return out;
293
+ }
294
+ const HELP = `agent-native add — emit an integration blueprint for your coding agent.
295
+
296
+ Instead of scaffolding files, \`add\` prints a curated Markdown recipe to stdout.
297
+ Pipe it into a coding agent (Claude Code, Codex, …) and it applies the changes
298
+ against your live repo, the agent-native way.
299
+
300
+ Usage:
301
+ agent-native add <kind> <name> Print a curated blueprint
302
+ agent-native add <kind> <https://docs…> Research-and-integrate from a URL
303
+ agent-native add --list List available kinds and blueprints
304
+
305
+ Examples:
306
+ agent-native add provider stripe | claude
307
+ agent-native add channel discord | codex
308
+ agent-native add sandbox docker
309
+ agent-native add action crud
310
+ agent-native add provider https://docs.example.com/api | claude
311
+
312
+ Options:
313
+ -l, --list List available blueprint kinds and names
314
+ -p, --print Print the blueprint to stdout (the default; explicit no-op)
315
+ -h, --help Show this help`;
316
+ /**
317
+ * CLI entry point. Returns the process exit code so the dispatcher / tests can
318
+ * assert on it. Writes the blueprint Markdown to stdout and diagnostics to
319
+ * stderr so `... | claude` only receives the blueprint.
320
+ */
321
+ export function runAdd(argv, io = {}) {
322
+ const out = io.out ?? ((s) => process.stdout.write(s));
323
+ const err = io.err ?? ((s) => process.stderr.write(s));
324
+ const root = resolveBlueprintsRoot(io.root);
325
+ const parsed = parseAddArgs(argv);
326
+ if (parsed.help) {
327
+ out(HELP + "\n");
328
+ return 0;
329
+ }
330
+ // `--list` or no positionals → show the catalog (to stdout; this is the
331
+ // requested output, not an error).
332
+ if (parsed.list || parsed.positionals.length === 0) {
333
+ out(formatCatalog(root) + "\n");
334
+ return 0;
335
+ }
336
+ const [kind, nameOrUrl] = parsed.positionals;
337
+ try {
338
+ const resolved = resolveBlueprint({ kind, nameOrUrl, root });
339
+ out(resolved.markdown.endsWith("\n")
340
+ ? resolved.markdown
341
+ : resolved.markdown + "\n");
342
+ return 0;
343
+ }
344
+ catch (e) {
345
+ if (e instanceof AddResolutionError) {
346
+ err(e.message + "\n");
347
+ return 1;
348
+ }
349
+ throw e;
350
+ }
351
+ }
352
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/cli/add.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `agent-native add <kind> [name|url]` — the **blueprint installer**.\n *\n * Borrowed from Flue's `flue add`: instead of being a dumb scaffolder that\n * writes files for you, this command emits a curated Markdown *integration\n * blueprint* to stdout. You pipe that blueprint into your own coding agent,\n * which applies the changes against the live repo:\n *\n * agent-native add provider stripe | claude\n * agent-native add channel discord | codex\n *\n * This fits the agent-applies-changes, filesystem-first house style: the\n * framework supplies the recipe (the canonical files to touch, the rules to\n * honor, the verification step), and the coding agent does the editing with\n * full repo context.\n *\n * A bare name resolves a curated blueprint from `blueprints/<kind>/<name>.md`.\n * A URL instead of a name emits a GENERIC \"research-and-integrate\" blueprint\n * for that kind with the URL embedded as the research starting point (mirrors\n * Flue: a URL is a research seed, not a known recipe).\n *\n * Blueprint `.md` files ship in the published package via the `blueprints`\n * entry in `package.json` `files`, so they live at\n * `node_modules/@agent-native/core/blueprints/**` at runtime. Resolution works\n * both from source (tsx: `src/cli` → `../../blueprints`) and from the compiled\n * package (`dist/cli` → `../../blueprints`), with an upward-walk fallback.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\n/** A coarse classification of what `add` resolved for a given invocation. */\nexport type AddBlueprintSource =\n | { kind: \"curated\"; blueprintKind: string; name: string; path: string }\n | { kind: \"generic-url\"; blueprintKind: string; url: string };\n\nexport interface ResolvedBlueprint {\n /** The Markdown to print to stdout (piped into a coding agent). */\n markdown: string;\n source: AddBlueprintSource;\n}\n\n/**\n * Locate the directory that holds the blueprint `.md` recipes.\n *\n * Both `src/cli` (tsx/source) and `dist/cli` (published) sit two levels under\n * the package root, where `blueprints/` lives, so `../../blueprints` from this\n * module's directory is the primary path. We additionally walk upward looking\n * for a `blueprints` directory as a resilience fallback (e.g. unusual bundler\n * layouts). An explicit override is honored for tests.\n */\nexport function resolveBlueprintsRoot(overrideRoot?: string): string {\n if (overrideRoot) return overrideRoot;\n\n const here = path.dirname(fileURLToPath(import.meta.url));\n const primary = path.resolve(here, \"../../blueprints\");\n if (isDir(primary)) return primary;\n\n // Fallback: walk up from this module looking for a sibling `blueprints` dir.\n let dir = here;\n for (let i = 0; i < 8; i += 1) {\n const candidate = path.join(dir, \"blueprints\");\n if (isDir(candidate)) return candidate;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n // Return the primary path even if missing so error messages are concrete.\n return primary;\n}\n\nfunction isDir(p: string): boolean {\n try {\n return fs.statSync(p).isDirectory();\n } catch {\n return false;\n }\n}\n\n/** True for an argument that should be treated as a research URL, not a name. */\nexport function looksLikeUrl(value: string): boolean {\n return /^https?:\\/\\//i.test(value.trim());\n}\n\n/** List the blueprint kinds (subdirectories) available, sorted. */\nexport function listKinds(root: string): string[] {\n if (!isDir(root)) return [];\n return fs\n .readdirSync(root, { withFileTypes: true })\n .filter((e) => e.isDirectory())\n .map((e) => e.name)\n .sort();\n}\n\n/** List the blueprint names available under a kind, sorted (no `.md`). */\nexport function listBlueprintNames(root: string, kind: string): string[] {\n const dir = path.join(root, kind);\n if (!isDir(dir)) return [];\n return fs\n .readdirSync(dir, { withFileTypes: true })\n .filter((e) => e.isFile() && e.name.endsWith(\".md\"))\n .map((e) => e.name.slice(0, -\".md\".length))\n .sort();\n}\n\n/** A flat catalog of every kind and its blueprint names. */\nexport function listCatalog(root: string): Array<{\n kind: string;\n names: string[];\n}> {\n return listKinds(root).map((kind) => ({\n kind,\n names: listBlueprintNames(root, kind),\n }));\n}\n\n/** Render the `--list` / no-args catalog text. */\nexport function formatCatalog(root: string): string {\n const catalog = listCatalog(root);\n const lines: string[] = [];\n lines.push(\"Available blueprints:\");\n lines.push(\"\");\n if (catalog.length === 0) {\n lines.push(\" (none found)\");\n } else {\n for (const { kind, names } of catalog) {\n const shown =\n names.length > 0 ? names.join(\", \") : \"(generic — pass a URL)\";\n lines.push(` ${kind.padEnd(10)} ${shown}`);\n }\n }\n lines.push(\"\");\n lines.push(\"Usage:\");\n lines.push(\n \" agent-native add <kind> <name> Print a curated blueprint\",\n );\n lines.push(\n \" agent-native add <kind> <https://docs…> Research-and-integrate from a URL\",\n );\n lines.push(\" agent-native add --list Show this list\");\n lines.push(\"\");\n lines.push(\"Pipe a blueprint into your coding agent to apply it:\");\n lines.push(\" agent-native add provider stripe | claude\");\n lines.push(\" agent-native add channel discord | codex\");\n return lines.join(\"\\n\");\n}\n\n/**\n * Build the generic \"research-and-integrate\" blueprint emitted when the user\n * passes a URL instead of a known blueprint name. Mirrors Flue: a URL is a\n * research seed. We keep this self-contained — the coding agent reading it has\n * no other context.\n */\nexport function buildGenericUrlBlueprint(kind: string, url: string): string {\n const kindGuidance = GENERIC_KIND_GUIDANCE[kind] ?? GENERIC_DEFAULT_GUIDANCE;\n return `# Blueprint: integrate a new ${kind} from a URL\n\nYou are a coding agent working inside an **agent-native** app (a repo built on\n\\`@agent-native/core\\`). Apply this blueprint as real source changes on the\ncurrent branch. Do not just describe the work — research, implement, then verify.\n\n## Research seed\n\nStart from this URL and follow it for the API/protocol/contract you need:\n\n ${url}\n\nFetch it (and the pages it links to) to learn the real endpoints, auth model,\npayload shapes, and any signature/verification requirements. Do not guess from\ntraining data — the docs are the source of truth, and package/API versions\ndrift. Confirm the current version before writing code.\n\n## What you're adding\n\nA new **${kind}** integration. ${kindGuidance}\n\n## How agent-native wants it built\n\n- **Actions are the single source of truth.** Add app operations in \\`actions/\\`\n with \\`defineAction\\` (Zod schema). The agent calls them as tools; the frontend\n calls the same action through \\`useActionQuery\\` / \\`useActionMutation\\`. Do NOT\n add \\`/api/*\\` or Nitro pass-through routes that just wrap an action.\n- **Prefer the provider-api substrate for external HTTP.** For ad-hoc reads\n against a third-party API, register the provider with\n \\`@agent-native/core/provider-api\\` and expose the\n \\`provider-api-catalog\\` / \\`provider-api-docs\\` / \\`provider-api-request\\` trio\n instead of one rigid action per endpoint. First-class actions are shortcuts,\n not capability limits.\n- **Read the relevant skill before editing** — \\`actions\\`,\n \\`integration-webhooks\\`, \\`secrets\\`, \\`onboarding\\`, \\`sharing\\`, \\`security\\` —\n for the area you're touching.\n- **Never hardcode secrets.** Read API keys / tokens / signing secrets from the\n secret store (\\`readAppSecret\\`, the provider credential adapter, OAuth token\n helpers) at call time. Use obviously-fake placeholders in any example\n (e.g. \\`sk_test_PLACEHOLDER_xxx\\`), never a real credential.\n- **Scope ownable data.** Tables with \\`ownableColumns()\\` require\n \\`accessFilter\\` / \\`resolveAccess\\` / \\`assertAccess\\`; fail closed.\n- **Changeset.** If you edit a publishable package's source\n (\\`packages/core\\`, \\`packages/dispatch\\`, \\`packages/scheduling\\`,\n \\`packages/pinpoint\\`), add a \\`.changeset/*.md\\`.\n\n## Verify\n\n1. \\`agent-native typecheck\\` (or \\`tsc --noEmit\\`) passes.\n2. Add a focused \\`*.spec.ts\\` for the new surface and run it.\n3. Exercise the real workflow end to end: invoke the new action from the agent\n chat (and the UI if applicable), and confirm the external call round-trips\n with credentials injected and secrets redacted.\n`;\n}\n\nconst GENERIC_DEFAULT_GUIDANCE =\n \"Identify whether it is best modeled as an action, a provider-api integration, \" +\n \"an inbound channel adapter, or a sandbox backend, and follow that area's skill.\";\n\nconst GENERIC_KIND_GUIDANCE: Record<string, string> = {\n provider:\n \"Wire it into the provider-api substrate (`@agent-native/core/provider-api`): \" +\n \"register the base URL, auth style, credential key, and docs URLs, then expose \" +\n \"the `provider-api-catalog` / `provider-api-docs` / `provider-api-request` trio \" +\n \"so any endpoint is reachable without one action per endpoint.\",\n channel:\n \"Implement a `PlatformAdapter` (see \" +\n \"`packages/core/src/integrations/types.ts` and the adapters under \" +\n \"`packages/core/src/integrations/adapters/`) and register it in \" +\n \"`getDefaultAdapters()` in `packages/core/src/integrations/plugin.ts`. \" +\n \"Enqueue to SQL and return 200 fast; run the agent loop in the separate \" +\n \"`_process-task` execution. Read the `integration-webhooks` skill.\",\n sandbox:\n \"Implement the `SandboxAdapter` seam in \" +\n \"`packages/core/src/coding-tools/sandbox/` (mirror \" +\n \"`local-child-process-adapter.ts`) and select it via `AGENT_NATIVE_SANDBOX` \" +\n \"or `registerSandboxAdapter()`. The adapter only runs the already-prepared, \" +\n \"non-secret module source — it never sees app secrets.\",\n action:\n \"Add a single multi-surface `defineAction` in `actions/` with a Zod schema. \" +\n \"Keep the surface small and orthogonal (one CRUD-style `update` over N \" +\n \"per-field actions). Read the `actions` skill.\",\n};\n\n/**\n * Resolve a blueprint for a `kind` + optional `name`/`url`.\n *\n * - A known name → the curated `blueprints/<kind>/<name>.md`.\n * - A URL → the generic research-and-integrate blueprint for the kind.\n * - Unknown name → throws `AddResolutionError` listing what's available.\n */\nexport function resolveBlueprint(opts: {\n kind: string;\n nameOrUrl?: string;\n root: string;\n}): ResolvedBlueprint {\n const { kind, nameOrUrl, root } = opts;\n const kinds = listKinds(root);\n\n if (!kinds.includes(kind)) {\n throw new AddResolutionError(\n `Unknown blueprint kind: ${kind}\\n\\n${formatCatalog(root)}`,\n );\n }\n\n // A URL seed → generic blueprint for the kind.\n if (nameOrUrl && looksLikeUrl(nameOrUrl)) {\n return {\n markdown: buildGenericUrlBlueprint(kind, nameOrUrl.trim()),\n source: {\n kind: \"generic-url\",\n blueprintKind: kind,\n url: nameOrUrl.trim(),\n },\n };\n }\n\n const names = listBlueprintNames(root, kind);\n\n // No name given: if exactly one curated blueprint exists, use it; otherwise\n // ask the user to pick one (or pass a URL for the generic path).\n if (!nameOrUrl) {\n if (names.length === 1) {\n return loadCurated(root, kind, names[0]);\n }\n throw new AddResolutionError(\n `Specify a ${kind} blueprint name or a URL.\\n` +\n ` Available ${kind} blueprints: ${\n names.length ? names.join(\", \") : \"(none — pass a URL)\"\n }\\n` +\n ` Or research from a URL: agent-native add ${kind} https://…`,\n );\n }\n\n if (!names.includes(nameOrUrl)) {\n throw new AddResolutionError(\n `Unknown ${kind} blueprint: ${nameOrUrl}\\n` +\n ` Available ${kind} blueprints: ${\n names.length ? names.join(\", \") : \"(none)\"\n }\\n` +\n ` Or research from a URL: agent-native add ${kind} https://…`,\n );\n }\n\n return loadCurated(root, kind, nameOrUrl);\n}\n\nfunction loadCurated(\n root: string,\n kind: string,\n name: string,\n): ResolvedBlueprint {\n const filePath = path.join(root, kind, `${name}.md`);\n const markdown = fs.readFileSync(filePath, \"utf-8\");\n return {\n markdown,\n source: { kind: \"curated\", blueprintKind: kind, name, path: filePath },\n };\n}\n\n/** Thrown for an unknown kind/name; the CLI prints the message and exits 1. */\nexport class AddResolutionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AddResolutionError\";\n }\n}\n\ninterface ParsedAddArgs {\n list: boolean;\n help: boolean;\n /** Accepted as an explicit no-op alias for the default print behavior. */\n print: boolean;\n positionals: string[];\n}\n\nexport function parseAddArgs(argv: string[]): ParsedAddArgs {\n const out: ParsedAddArgs = {\n list: false,\n help: false,\n print: false,\n positionals: [],\n };\n for (const arg of argv) {\n if (arg === \"--\") continue;\n if (arg === \"--list\" || arg === \"-l\") out.list = true;\n else if (arg === \"--help\" || arg === \"-h\") out.help = true;\n else if (arg === \"--print\" || arg === \"-p\") out.print = true;\n else if (arg.startsWith(\"-\")) {\n // Ignore unknown flags rather than misparse them as a name.\n continue;\n } else out.positionals.push(arg);\n }\n return out;\n}\n\nconst HELP = `agent-native add — emit an integration blueprint for your coding agent.\n\nInstead of scaffolding files, \\`add\\` prints a curated Markdown recipe to stdout.\nPipe it into a coding agent (Claude Code, Codex, …) and it applies the changes\nagainst your live repo, the agent-native way.\n\nUsage:\n agent-native add <kind> <name> Print a curated blueprint\n agent-native add <kind> <https://docs…> Research-and-integrate from a URL\n agent-native add --list List available kinds and blueprints\n\nExamples:\n agent-native add provider stripe | claude\n agent-native add channel discord | codex\n agent-native add sandbox docker\n agent-native add action crud\n agent-native add provider https://docs.example.com/api | claude\n\nOptions:\n -l, --list List available blueprint kinds and names\n -p, --print Print the blueprint to stdout (the default; explicit no-op)\n -h, --help Show this help`;\n\n/**\n * CLI entry point. Returns the process exit code so the dispatcher / tests can\n * assert on it. Writes the blueprint Markdown to stdout and diagnostics to\n * stderr so `... | claude` only receives the blueprint.\n */\nexport function runAdd(\n argv: string[],\n io: {\n out?: (s: string) => void;\n err?: (s: string) => void;\n root?: string;\n } = {},\n): number {\n const out = io.out ?? ((s: string) => process.stdout.write(s));\n const err = io.err ?? ((s: string) => process.stderr.write(s));\n const root = resolveBlueprintsRoot(io.root);\n\n const parsed = parseAddArgs(argv);\n\n if (parsed.help) {\n out(HELP + \"\\n\");\n return 0;\n }\n\n // `--list` or no positionals → show the catalog (to stdout; this is the\n // requested output, not an error).\n if (parsed.list || parsed.positionals.length === 0) {\n out(formatCatalog(root) + \"\\n\");\n return 0;\n }\n\n const [kind, nameOrUrl] = parsed.positionals;\n\n try {\n const resolved = resolveBlueprint({ kind, nameOrUrl, root });\n out(\n resolved.markdown.endsWith(\"\\n\")\n ? resolved.markdown\n : resolved.markdown + \"\\n\",\n );\n return 0;\n } catch (e) {\n if (e instanceof AddResolutionError) {\n err(e.message + \"\\n\");\n return 1;\n }\n throw e;\n }\n}\n"]}
@@ -5,7 +5,7 @@
5
5
  * browser device-code flow: open the verification URL, approve in the browser,
6
6
  * and the minted HTTP MCP server entry is written idempotently.
7
7
  *
8
- * agent-native connect <url> [--client all|claude-code|claude-code-cli|
8
+ * agent-native connect <url> [--client all|claude-code|
9
9
  * codex|cowork|cursor|opencode|github-copilot]
10
10
  * [--scope user|project]
11
11
  * [--name <serverName>]
@@ -35,7 +35,7 @@ export interface ParsedConnectArgs {
35
35
  mode?: "dev" | "prod" | "reauth" | "reconnect";
36
36
  /** Positional URL (the deployed app origin). Undefined for `--all`. */
37
37
  url?: string;
38
- /** all | claude-code | claude-code-cli | codex | cowork | cursor | opencode | github-copilot (default "all"). */
38
+ /** all | claude-code | codex | cowork | cursor | opencode | github-copilot (default "all"). claude-code-cli is accepted as a legacy alias for claude-code. */
39
39
  client: string;
40
40
  /** True when the user passed --client explicitly, so we skip the picker. */
41
41
  clientExplicit: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/cli/connect.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/cli/connect.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,7 @@
5
5
  * browser device-code flow: open the verification URL, approve in the browser,
6
6
  * and the minted HTTP MCP server entry is written idempotently.
7
7
  *
8
- * agent-native connect <url> [--client all|claude-code|claude-code-cli|
8
+ * agent-native connect <url> [--client all|claude-code|
9
9
  * codex|cowork|cursor|opencode|github-copilot]
10
10
  * [--scope user|project]
11
11
  * [--name <serverName>]
@@ -185,11 +185,15 @@ export function normalizeUrl(raw) {
185
185
  const base = `${parsed.origin}${parsed.pathname}`.replace(/\/+$/, "");
186
186
  return base;
187
187
  }
188
+ // Clients offered in the interactive picker and expanded by "all". Excludes
189
+ // the `claude-code-cli` alias so users only ever see a single "Claude Code"
190
+ // option (it still works if passed explicitly via --client).
191
+ const SELECTABLE_CLIENTS = CLIENTS.filter((c) => c !== "claude-code-cli");
188
192
  /** Resolve the requested clients list. "all" → every supported client. */
189
193
  export function resolveClients(client) {
190
194
  const c = normalizeClientAlias(client ?? "all");
191
195
  if (c === "all" || c === "")
192
- return [...CLIENTS];
196
+ return [...SELECTABLE_CLIENTS];
193
197
  if (c.includes(",")) {
194
198
  const clients = normalizeClientIds(c.split(",").map((part) => part.trim()));
195
199
  if (clients.length > 0)
@@ -201,7 +205,12 @@ export function resolveClients(client) {
201
205
  }
202
206
  function normalizeClientAlias(value) {
203
207
  const id = value.trim().toLowerCase();
204
- if (id === "claude" || id === "claude-code-desktop")
208
+ // The Claude Code CLI and desktop share ~/.claude.json, so they are one
209
+ // client. `claude-code-cli` stays accepted for back-compat but collapses to
210
+ // the single "Claude Code" option everywhere it surfaces.
211
+ if (id === "claude" ||
212
+ id === "claude-code-desktop" ||
213
+ id === "claude-code-cli")
205
214
  return "claude-code";
206
215
  if (id === "copilot" || id === "vscode" || id === "vs-code") {
207
216
  return "github-copilot";
@@ -252,7 +261,7 @@ export function writeConnectClientPreferences(clients, file = connectPreferences
252
261
  }, null, 2) + "\n", "utf-8");
253
262
  }
254
263
  function clientPromptOptions() {
255
- return CLIENTS.map((client) => ({
264
+ return SELECTABLE_CLIENTS.map((client) => ({
256
265
  value: client,
257
266
  label: CLIENT_LABELS[client],
258
267
  hint: CLIENT_HINTS[client],
@@ -591,26 +600,43 @@ export async function runDeviceFlow(baseUrl, appSlug, clientArg, deps = {}, opti
591
600
  const sleep = deps.sleep ?? realSleep;
592
601
  const open = deps.openBrowser ?? openInBrowser;
593
602
  const now = deps.now ?? (() => Date.now());
594
- let start;
595
- try {
596
- const { status, json } = await postJson(fetchImpl, `${baseUrl}${DEVICE_START_PATH}`, {
597
- client: clientArg,
598
- app: appSlug,
599
- ...(options.fullCatalog ? { fullCatalog: true } : {}),
600
- });
601
- if (status < 200 || status >= 300 || !json?.device_code) {
603
+ let start = null;
604
+ // A cold/propagating Plan instance can briefly 404/5xx before its connect
605
+ // route is registered (async plugin init). Retry a few times so a recoverable
606
+ // blip doesn't kill the connect before polling even begins.
607
+ const START_ATTEMPTS = 4;
608
+ for (let attempt = 0; attempt < START_ATTEMPTS; attempt++) {
609
+ try {
610
+ const { status, json } = await postJson(fetchImpl, `${baseUrl}${DEVICE_START_PATH}`, {
611
+ client: clientArg,
612
+ app: appSlug,
613
+ ...(options.fullCatalog ? { fullCatalog: true } : {}),
614
+ });
615
+ if (status >= 200 && status < 300 && json?.device_code) {
616
+ start = json;
617
+ break;
618
+ }
619
+ if ((status === 404 || status >= 500) && attempt < START_ATTEMPTS - 1) {
620
+ await sleep(1000 * (attempt + 1));
621
+ continue;
622
+ }
602
623
  logErr(` Could not start the connect flow on ${baseUrl} ` +
603
624
  `(HTTP ${status}). Is this an agent-native app, and is it ` +
604
625
  `deployed with the connect endpoint enabled?`);
605
626
  return null;
606
627
  }
607
- start = json;
628
+ catch (err) {
629
+ if (attempt < START_ATTEMPTS - 1) {
630
+ await sleep(1000 * (attempt + 1));
631
+ continue;
632
+ }
633
+ logErr(` Could not reach ${baseUrl} (${err?.message ?? err}). ` +
634
+ `Check the URL and your network.`);
635
+ return null;
636
+ }
608
637
  }
609
- catch (err) {
610
- logErr(` Could not reach ${baseUrl} (${err?.message ?? err}). ` +
611
- `Check the URL and your network.`);
638
+ if (!start)
612
639
  return null;
613
- }
614
640
  const interval = Math.max(1, Number(start.interval) || 5);
615
641
  const expiresIn = Math.max(interval, Number(start.expires_in) || 600);
616
642
  const deadline = now() + expiresIn * 1000;
@@ -623,23 +649,59 @@ export async function runDeviceFlow(baseUrl, appSlug, clientArg, deps = {}, opti
623
649
  logOut(" Approve in the browser to finish. Opening it now…");
624
650
  open(start.verification_uri_complete);
625
651
  let spin = 0;
652
+ let transientStreak = 0;
653
+ // Ride out brief cold-instance blips, but don't poll a persistently-dead
654
+ // endpoint forever: give up after this many consecutive transient (404/5xx
655
+ // or network-error) polls. Reset as soon as one poll responds normally.
656
+ const MAX_TRANSIENT_POLLS = 20;
626
657
  const isTTY = !!process.stdout.isTTY;
627
658
  while (now() < deadline) {
628
659
  let poll;
660
+ let transient = false;
629
661
  try {
630
662
  const { status, json } = await postJson(fetchImpl, `${baseUrl}${DEVICE_POLL_PATH}`, { device_code: start.device_code });
631
663
  if (status < 200 || status >= 300) {
664
+ if (isTerminalPollBody(json)) {
665
+ poll = json;
666
+ }
667
+ else if (status === 404 || status >= 500) {
668
+ // Transient: a cold/propagating Plan instance can briefly serve a
669
+ // bare 404 (the MCP route isn't registered until async plugin init
670
+ // settles) or a 5xx before it's healthy. The next poll usually lands
671
+ // on a warm instance, so keep polling until the deadline instead of
672
+ // hard-failing the whole connect on a recoverable blip. (This is the
673
+ // recurring "Cannot find any route matching [POST] .../mcp" case.)
674
+ poll = { status: "pending" };
675
+ transient = true;
676
+ }
677
+ else {
678
+ if (isTTY)
679
+ process.stdout.write("\r\x1b[K");
680
+ logErr(` Connect polling failed (HTTP ${status}): ` +
681
+ responseMessage(json, "server returned an error."));
682
+ return null;
683
+ }
684
+ }
685
+ else {
686
+ poll = (json ?? { status: "pending" });
687
+ }
688
+ }
689
+ catch {
690
+ // Transient network error — keep polling.
691
+ poll = { status: "pending" };
692
+ transient = true;
693
+ }
694
+ if (transient) {
695
+ if (++transientStreak > MAX_TRANSIENT_POLLS) {
632
696
  if (isTTY)
633
697
  process.stdout.write("\r\x1b[K");
634
- logErr(` Connect polling failed (HTTP ${status}): ` +
635
- responseMessage(json, "server returned an error."));
698
+ logErr(" Connect endpoint is not responding (repeated 404/5xx). It may be " +
699
+ "mid-deploy wait a minute and run the command again.");
636
700
  return null;
637
701
  }
638
- poll = (json ?? { status: "pending" });
639
702
  }
640
- catch {
641
- // Transient network error — keep polling until the deadline.
642
- poll = { status: "pending" };
703
+ else {
704
+ transientStreak = 0;
643
705
  }
644
706
  if (poll.status === "approved") {
645
707
  if (isTTY)
@@ -687,6 +749,12 @@ export async function runDeviceFlow(baseUrl, appSlug, clientArg, deps = {}, opti
687
749
  logErr(" Timed out waiting for approval. Run the command again to retry.");
688
750
  return null;
689
751
  }
752
+ function isTerminalPollBody(json) {
753
+ return (json?.status === "not_found" ||
754
+ json?.status === "error" ||
755
+ json?.status === "expired" ||
756
+ json?.status === "consumed");
757
+ }
690
758
  // ---------------------------------------------------------------------------
691
759
  // Writing config(s)
692
760
  // ---------------------------------------------------------------------------
@@ -1849,7 +1917,7 @@ Developer:
1849
1917
  npx @agent-native/core@latest connect prod [--apps mail,calendar] [--client <c>]
1850
1918
  Restore production MCP entries saved before the dev switch.
1851
1919
 
1852
- Clients: all (default), claude-code, claude-code-cli, codex, cowork, cursor, opencode, github-copilot
1920
+ Clients: all (default), claude-code, codex, cowork, cursor, opencode, github-copilot
1853
1921
  Scope: user (default, ~/.claude.json) or project (.mcp.json)`;
1854
1922
  /**
1855
1923
  * `agent-native connect` entry point. `deps` is injectable for tests; the