@synap-core/cli 1.8.0 → 1.10.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 (332) hide show
  1. package/dist/commands/agent-chat.d.ts +47 -0
  2. package/dist/commands/agent-chat.js +250 -0
  3. package/dist/commands/agent-chat.js.map +1 -0
  4. package/dist/commands/agent-run.js +3 -4
  5. package/dist/commands/agent-run.js.map +1 -1
  6. package/dist/commands/agents.js +85 -46
  7. package/dist/commands/agents.js.map +1 -1
  8. package/dist/commands/automation.js +2 -1
  9. package/dist/commands/automation.js.map +1 -1
  10. package/dist/commands/bridge-setup.d.ts +66 -0
  11. package/dist/commands/bridge-setup.js +1112 -0
  12. package/dist/commands/bridge-setup.js.map +1 -0
  13. package/dist/commands/cap-connections.d.ts +28 -0
  14. package/dist/commands/cap-connections.js +224 -0
  15. package/dist/commands/cap-connections.js.map +1 -0
  16. package/dist/commands/capability.d.ts +89 -0
  17. package/dist/commands/capability.js +1523 -0
  18. package/dist/commands/capability.js.map +1 -0
  19. package/dist/commands/centrality.d.ts +20 -0
  20. package/dist/commands/centrality.js +94 -0
  21. package/dist/commands/centrality.js.map +1 -0
  22. package/dist/commands/connect.d.ts +2 -0
  23. package/dist/commands/connect.js +16 -35
  24. package/dist/commands/connect.js.map +1 -1
  25. package/dist/commands/context.js +4 -6
  26. package/dist/commands/context.js.map +1 -1
  27. package/dist/commands/data-extra.d.ts +1 -0
  28. package/dist/commands/data-extra.js +34 -10
  29. package/dist/commands/data-extra.js.map +1 -1
  30. package/dist/commands/data.d.ts +4 -4
  31. package/dist/commands/data.js +241 -184
  32. package/dist/commands/data.js.map +1 -1
  33. package/dist/commands/diagnose.d.ts +20 -0
  34. package/dist/commands/diagnose.js +143 -0
  35. package/dist/commands/diagnose.js.map +1 -0
  36. package/dist/commands/digest.d.ts +17 -0
  37. package/dist/commands/digest.js +121 -0
  38. package/dist/commands/digest.js.map +1 -0
  39. package/dist/commands/discover.d.ts +2 -0
  40. package/dist/commands/discover.js +25 -8
  41. package/dist/commands/discover.js.map +1 -1
  42. package/dist/commands/events.js +2 -1
  43. package/dist/commands/events.js.map +1 -1
  44. package/dist/commands/explain.d.ts +1 -1
  45. package/dist/commands/explain.js +18 -15
  46. package/dist/commands/explain.js.map +1 -1
  47. package/dist/commands/facet.d.ts +29 -0
  48. package/dist/commands/facet.js +113 -0
  49. package/dist/commands/facet.js.map +1 -0
  50. package/dist/commands/graph.js +2 -1
  51. package/dist/commands/graph.js.map +1 -1
  52. package/dist/commands/import.d.ts +38 -0
  53. package/dist/commands/import.js +440 -0
  54. package/dist/commands/import.js.map +1 -0
  55. package/dist/commands/init.js +35 -16
  56. package/dist/commands/init.js.map +1 -1
  57. package/dist/commands/keys.js +3 -4
  58. package/dist/commands/keys.js.map +1 -1
  59. package/dist/commands/knowledge.d.ts +2 -0
  60. package/dist/commands/knowledge.js +61 -9
  61. package/dist/commands/knowledge.js.map +1 -1
  62. package/dist/commands/launch.d.ts +50 -0
  63. package/dist/commands/launch.js +790 -0
  64. package/dist/commands/launch.js.map +1 -0
  65. package/dist/commands/lens.d.ts +45 -0
  66. package/dist/commands/lens.js +386 -0
  67. package/dist/commands/lens.js.map +1 -0
  68. package/dist/commands/market.d.ts +209 -0
  69. package/dist/commands/market.js +1368 -0
  70. package/dist/commands/market.js.map +1 -0
  71. package/dist/commands/mcp.d.ts +42 -0
  72. package/dist/commands/mcp.js +184 -0
  73. package/dist/commands/mcp.js.map +1 -0
  74. package/dist/commands/observe.js +14 -11
  75. package/dist/commands/observe.js.map +1 -1
  76. package/dist/commands/open.d.ts +21 -4
  77. package/dist/commands/open.js +45 -4
  78. package/dist/commands/open.js.map +1 -1
  79. package/dist/commands/pod.d.ts +100 -0
  80. package/dist/commands/pod.js +359 -0
  81. package/dist/commands/pod.js.map +1 -0
  82. package/dist/commands/pods.d.ts +1 -0
  83. package/dist/commands/pods.js +77 -15
  84. package/dist/commands/pods.js.map +1 -1
  85. package/dist/commands/proposals-actions.js +40 -3
  86. package/dist/commands/proposals-actions.js.map +1 -1
  87. package/dist/commands/purge.d.ts +23 -0
  88. package/dist/commands/purge.js +148 -0
  89. package/dist/commands/purge.js.map +1 -0
  90. package/dist/commands/raycast.d.ts +15 -0
  91. package/dist/commands/raycast.js +153 -0
  92. package/dist/commands/raycast.js.map +1 -0
  93. package/dist/commands/sessions.js +45 -21
  94. package/dist/commands/sessions.js.map +1 -1
  95. package/dist/commands/skill-manage.d.ts +21 -0
  96. package/dist/commands/skill-manage.js +195 -0
  97. package/dist/commands/skill-manage.js.map +1 -0
  98. package/dist/commands/skills-commands.js +2 -1
  99. package/dist/commands/skills-commands.js.map +1 -1
  100. package/dist/commands/skills.js +4 -3
  101. package/dist/commands/skills.js.map +1 -1
  102. package/dist/commands/status.d.ts +3 -1
  103. package/dist/commands/status.js +166 -14
  104. package/dist/commands/status.js.map +1 -1
  105. package/dist/commands/statusline.d.ts +24 -0
  106. package/dist/commands/statusline.js +450 -0
  107. package/dist/commands/statusline.js.map +1 -0
  108. package/dist/commands/subscribe.js +2 -2
  109. package/dist/commands/subscribe.js.map +1 -1
  110. package/dist/commands/tools.d.ts +30 -0
  111. package/dist/commands/tools.js +315 -0
  112. package/dist/commands/tools.js.map +1 -0
  113. package/dist/commands/versions.d.ts +27 -0
  114. package/dist/commands/versions.js +277 -0
  115. package/dist/commands/versions.js.map +1 -0
  116. package/dist/commands/view.js +3 -2
  117. package/dist/commands/view.js.map +1 -1
  118. package/dist/commands/whoami.d.ts +21 -0
  119. package/dist/commands/whoami.js +129 -0
  120. package/dist/commands/whoami.js.map +1 -0
  121. package/dist/index.js +776 -60
  122. package/dist/index.js.map +1 -1
  123. package/dist/lib/approval-poll.d.ts +42 -0
  124. package/dist/lib/approval-poll.js +52 -0
  125. package/dist/lib/approval-poll.js.map +1 -0
  126. package/dist/lib/auth.d.ts +29 -6
  127. package/dist/lib/auth.js +105 -94
  128. package/dist/lib/auth.js.map +1 -1
  129. package/dist/lib/bundle-version.d.ts +11 -0
  130. package/dist/lib/bundle-version.js +33 -0
  131. package/dist/lib/bundle-version.js.map +1 -0
  132. package/dist/lib/capture-lane.d.ts +30 -12
  133. package/dist/lib/capture-lane.js +71 -14
  134. package/dist/lib/capture-lane.js.map +1 -1
  135. package/dist/lib/cp-packages.d.ts +121 -0
  136. package/dist/lib/cp-packages.js +218 -0
  137. package/dist/lib/cp-packages.js.map +1 -0
  138. package/dist/lib/describe-lens.d.ts +46 -0
  139. package/dist/lib/describe-lens.js +33 -0
  140. package/dist/lib/describe-lens.js.map +1 -0
  141. package/dist/lib/hub-client.d.ts +78 -1
  142. package/dist/lib/hub-client.js +474 -22
  143. package/dist/lib/hub-client.js.map +1 -1
  144. package/dist/lib/installed.d.ts +51 -0
  145. package/dist/lib/installed.js +70 -0
  146. package/dist/lib/installed.js.map +1 -0
  147. package/dist/lib/next-steps.d.ts +61 -0
  148. package/dist/lib/next-steps.js +146 -0
  149. package/dist/lib/next-steps.js.map +1 -0
  150. package/dist/lib/pod.d.ts +91 -19
  151. package/dist/lib/pod.js +222 -56
  152. package/dist/lib/pod.js.map +1 -1
  153. package/dist/lib/project-ref.d.ts +95 -0
  154. package/dist/lib/project-ref.js +144 -0
  155. package/dist/lib/project-ref.js.map +1 -0
  156. package/dist/lib/project.d.ts +35 -0
  157. package/dist/lib/project.js +39 -0
  158. package/dist/lib/project.js.map +1 -0
  159. package/dist/lib/session-lens.d.ts +33 -0
  160. package/dist/lib/session-lens.js +76 -0
  161. package/dist/lib/session-lens.js.map +1 -0
  162. package/dist/lib/skill-import.d.ts +40 -0
  163. package/dist/lib/skill-import.js +203 -0
  164. package/dist/lib/skill-import.js.map +1 -0
  165. package/dist/lib/skills-installer.d.ts +17 -6
  166. package/dist/lib/skills-installer.js +133 -19
  167. package/dist/lib/skills-installer.js.map +1 -1
  168. package/dist/lib/suite.d.ts +28 -0
  169. package/dist/lib/suite.js +29 -0
  170. package/dist/lib/suite.js.map +1 -0
  171. package/dist/lib/superwhisper-import.d.ts +40 -0
  172. package/dist/lib/superwhisper-import.js +389 -0
  173. package/dist/lib/superwhisper-import.js.map +1 -0
  174. package/dist/lib/targets.d.ts +49 -1
  175. package/dist/lib/targets.js +420 -288
  176. package/dist/lib/targets.js.map +1 -1
  177. package/dist/lib/unwrapList.d.ts +1 -0
  178. package/dist/lib/unwrapList.js +20 -0
  179. package/dist/lib/unwrapList.js.map +1 -0
  180. package/dist/utils/logger.d.ts +2 -0
  181. package/dist/utils/logger.js +10 -2
  182. package/dist/utils/logger.js.map +1 -1
  183. package/package.json +9 -4
  184. package/skills/agent-os/SKILL.md +212 -0
  185. package/skills/manifest.json +5 -0
  186. package/skills/onboard/SKILL.md +186 -0
  187. package/skills/synap/SKILL.md +1182 -37
  188. package/skills/synap/_order.txt +37 -0
  189. package/skills/synap/_skill.yaml +24 -0
  190. package/skills/synap/authentication.md +10 -0
  191. package/skills/synap/automations.md +264 -0
  192. package/skills/synap/capabilities.md +107 -0
  193. package/skills/synap/capture.md +10 -0
  194. package/skills/synap/cli-operations.md +107 -0
  195. package/skills/synap/common-mistakes.md +12 -0
  196. package/skills/synap/creative-loop.md +43 -0
  197. package/skills/synap/crm.md +117 -0
  198. package/skills/synap/diagnostics.md +35 -0
  199. package/skills/synap/digesting-a-channel.md +38 -0
  200. package/skills/synap/document-embeds.md +123 -0
  201. package/skills/synap/escalation-ladder.md +71 -0
  202. package/skills/synap/focus-sessions.md +47 -0
  203. package/skills/synap/governance-rules.md +64 -0
  204. package/skills/synap/governance.md +6 -6
  205. package/skills/synap/graph-gardening.md +21 -0
  206. package/skills/synap/inline-patterns.md +38 -0
  207. package/skills/synap/lenses.md +38 -0
  208. package/skills/synap/linking-principle.md +39 -0
  209. package/skills/synap/linking.md +1 -0
  210. package/skills/synap/mental-model.md +45 -0
  211. package/skills/synap/more.md +7 -0
  212. package/skills/synap/multi-entity-capture.md +10 -0
  213. package/skills/synap/next-action.md +37 -0
  214. package/skills/synap/north-star.md +17 -0
  215. package/skills/synap/operating-mode-rules.md +45 -0
  216. package/skills/synap/operating-mode.md +9 -0
  217. package/skills/synap/quick-reference.md +67 -0
  218. package/skills/synap/reading.md +43 -0
  219. package/skills/synap/recap.md +21 -0
  220. package/skills/synap/reflexes.md +46 -0
  221. package/skills/synap/response-style.md +21 -0
  222. package/skills/synap/scope.md +13 -0
  223. package/skills/synap/showing.md +17 -0
  224. package/skills/synap/user-model.md +25 -0
  225. package/skills/synap/viewframe-cells.md +290 -0
  226. package/skills/synap/work-flow.md +113 -0
  227. package/skills/synap/worked-examples.md +53 -0
  228. package/skills/synap/workspace-design.md +45 -0
  229. package/skills/synap/workspace-edges.md +49 -0
  230. package/skills/synap/writes.md +156 -0
  231. package/skills/synap-schema/SKILL.md +97 -6
  232. package/skills/synap-schema/_order.txt +13 -0
  233. package/skills/synap-schema/_skill.yaml +22 -0
  234. package/skills/synap-schema/before-you-touch.md +14 -0
  235. package/skills/synap-schema/common-mistakes.md +9 -0
  236. package/skills/synap-schema/creating-profiles.md +17 -0
  237. package/skills/synap-schema/discover-profiles.md +24 -0
  238. package/skills/synap-schema/entity-scope.md +8 -0
  239. package/skills/synap-schema/extend-vs-create.md +31 -0
  240. package/skills/synap-schema/more.md +6 -0
  241. package/skills/synap-schema/overlay-properties.md +22 -0
  242. package/skills/synap-schema/profiles.md +3 -0
  243. package/skills/synap-schema/property-defs.md +29 -0
  244. package/skills/synap-schema/read-before-write.md +50 -0
  245. package/skills/synap-schema/relations.md +18 -0
  246. package/skills/synap-schema/worked-example.md +30 -0
  247. package/skills/synap-ui/SKILL.md +26 -2
  248. package/skills/synap-ui/_order.txt +13 -0
  249. package/skills/synap-ui/_skill.yaml +23 -0
  250. package/skills/synap-ui/ai-companion.md +27 -0
  251. package/skills/synap-ui/arranging-bento.md +8 -0
  252. package/skills/synap-ui/before-you-build.md +20 -0
  253. package/skills/synap-ui/bento-layouts.md +35 -0
  254. package/skills/synap-ui/common-mistakes.md +10 -0
  255. package/skills/synap-ui/creating-views.md +26 -0
  256. package/skills/synap-ui/four-builds.md +24 -0
  257. package/skills/synap-ui/more.md +7 -0
  258. package/skills/synap-ui/proposing-vs-extending.md +11 -0
  259. package/skills/synap-ui/view-list.md +24 -0
  260. package/skills/synap-ui/views.md +3 -0
  261. package/skills/synap-ui/worked-example.md +18 -0
  262. package/skills/synap-ui/workspaces.md +47 -0
  263. package/templates/automations/bookmark-enrichment.automation.json +44 -0
  264. package/templates/automations/mail-feed.automation.json +86 -0
  265. package/templates/automations/url-bookmark-capture.automation.json +70 -0
  266. package/templates/skills/README.md +21 -0
  267. package/templates/skills/authoring-automations/SKILL.md +95 -0
  268. package/templates/skills/authoring-automations/reference/node-matrix.md +49 -0
  269. package/templates/skills/authoring-capabilities/SKILL.md +93 -0
  270. package/templates/skills/authoring-capabilities/reference/template-anatomy.md +70 -0
  271. package/templates/skills/authoring-playbooks/SKILL.md +102 -0
  272. package/templates/skills/authoring-playbooks/reference/stages-contract.md +35 -0
  273. package/templates/skills/authoring-playbooks/reference/worked-example.md +64 -0
  274. package/templates/skills/bookmark-enrichment/SKILL.md +40 -0
  275. package/templates/skills/coordinating-agents/SKILL.md +32 -0
  276. package/templates/skills/coordinating-branches/SKILL.md +27 -0
  277. package/templates/skills/mapping-the-server/SKILL.md +54 -0
  278. package/templates/skills/reading-client-progress/SKILL.md +65 -0
  279. package/templates/skills/routing-to-channels/SKILL.md +54 -0
  280. package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-CHEATSHEET.md +133 -0
  281. package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-ONBOARDING-GUIDE.md +761 -0
  282. package/templates/skills/stellar-scf-grants-advisor/CLIENT-FAQ.md +181 -0
  283. package/templates/skills/stellar-scf-grants-advisor/PARTNER-HANDOVER.md +130 -0
  284. package/templates/skills/stellar-scf-grants-advisor/SKILL.md +102 -0
  285. package/templates/skills/stellar-scf-grants-advisor/examples/README.md +43 -0
  286. package/templates/skills/stellar-scf-grants-advisor/examples/chat-summary-templates.md +158 -0
  287. package/templates/skills/stellar-scf-grants-advisor/examples/corpus-comparable-rows.md +136 -0
  288. package/templates/skills/stellar-scf-grants-advisor/examples/q10-team-rewrites.md +109 -0
  289. package/templates/skills/stellar-scf-grants-advisor/examples/q2-description-rewrites.md +88 -0
  290. package/templates/skills/stellar-scf-grants-advisor/examples/q6-integration-rewrites.md +107 -0
  291. package/templates/skills/stellar-scf-grants-advisor/examples/tranche-structures.md +176 -0
  292. package/templates/skills/stellar-scf-grants-advisor/reference/01-methodology.md +96 -0
  293. package/templates/skills/stellar-scf-grants-advisor/reference/02-scoring-framework.md +199 -0
  294. package/templates/skills/stellar-scf-grants-advisor/reference/03-rejection-patterns.md +241 -0
  295. package/templates/skills/stellar-scf-grants-advisor/reference/04-winner-patterns.md +120 -0
  296. package/templates/skills/stellar-scf-grants-advisor/reference/05-comeback-patterns.md +92 -0
  297. package/templates/skills/stellar-scf-grants-advisor/reference/06-budget-benchmarks.md +125 -0
  298. package/templates/skills/stellar-scf-grants-advisor/reference/07-integration-list.md +147 -0
  299. package/templates/skills/stellar-scf-grants-advisor/reference/08-abstract-fields.md +258 -0
  300. package/templates/skills/stellar-scf-grants-advisor/reference/09-build-fields.md +259 -0
  301. package/templates/skills/stellar-scf-grants-advisor/reference/10-corpus-winners.md +135 -0
  302. package/templates/skills/stellar-scf-grants-advisor/reference/11-corpus-rejects.md +267 -0
  303. package/templates/skills/stellar-scf-grants-advisor/reference/12-client-communication.md +131 -0
  304. package/templates/skills/stellar-scf-grants-advisor/reference/13-excel-output-spec.md +199 -0
  305. package/templates/skills/stellar-scf-grants-advisor/reference/14-worked-examples.md +160 -0
  306. package/templates/skills/stellar-scf-grants-advisor/templates/abstract-review-builder.py +253 -0
  307. package/templates/skills/stellar-scf-grants-advisor/templates/build-review-builder.py +213 -0
  308. package/dist/commands/connectors.d.ts +0 -31
  309. package/dist/commands/connectors.js +0 -276
  310. package/dist/commands/connectors.js.map +0 -1
  311. package/dist/commands/finish.d.ts +0 -25
  312. package/dist/commands/finish.js +0 -274
  313. package/dist/commands/finish.js.map +0 -1
  314. package/dist/commands/openclaw.d.ts +0 -40
  315. package/dist/commands/openclaw.js +0 -1148
  316. package/dist/commands/openclaw.js.map +0 -1
  317. package/dist/commands/security-audit.d.ts +0 -12
  318. package/dist/commands/security-audit.js +0 -100
  319. package/dist/commands/security-audit.js.map +0 -1
  320. package/dist/lib/hardening.d.ts +0 -18
  321. package/dist/lib/hardening.js +0 -214
  322. package/dist/lib/hardening.js.map +0 -1
  323. package/node_modules/@synap/hub-rest-client/dist/index.cjs +0 -881
  324. package/node_modules/@synap/hub-rest-client/dist/index.d.cts +0 -907
  325. package/node_modules/@synap/hub-rest-client/dist/index.d.ts +0 -907
  326. package/node_modules/@synap/hub-rest-client/dist/index.js +0 -851
  327. package/node_modules/@synap/hub-rest-client/package.json +0 -45
  328. package/node_modules/@synap/hub-rest-client/src/client.ts +0 -1143
  329. package/node_modules/@synap/hub-rest-client/src/errors.ts +0 -30
  330. package/node_modules/@synap/hub-rest-client/src/index.ts +0 -111
  331. package/node_modules/@synap/hub-rest-client/src/setup.ts +0 -77
  332. package/node_modules/@synap/hub-rest-client/src/types.ts +0 -639
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ import { Command } from "commander";
16
16
  import { readFileSync } from "fs";
17
17
  import { fileURLToPath } from "url";
18
18
  import { dirname, join } from "path";
19
+ import { bootstrapPodOverride } from "./lib/pod.js";
19
20
  const __filename = fileURLToPath(import.meta.url);
20
21
  const __dirname = dirname(__filename);
21
22
  let version = "0.1.0";
@@ -31,7 +32,11 @@ program
31
32
  .name("synap")
32
33
  .description("Synap CLI — connect AI agents to your data pod")
33
34
  .version(version)
34
- .showSuggestionAfterError(true);
35
+ .showSuggestionAfterError(true)
36
+ // Global, position-independent: target a saved pod profile for THIS command
37
+ // only (see `synap pods`). Consumed pre-parse by bootstrapPodOverride so it
38
+ // works in any position and overrides the default/env pod for one invocation.
39
+ .option("--pod <name>", "Run this command against a saved pod profile (overrides the default pod for this invocation only)");
35
40
  program
36
41
  .command("init")
37
42
  .description("Full setup: connect to a Synap pod and install the skill")
@@ -42,6 +47,41 @@ program
42
47
  const { init } = await import("./commands/init.js");
43
48
  await init(opts);
44
49
  });
50
+ // ── launch — nothing → a working company (project + domain workspaces) ────────
51
+ // Not a template browser: `--list` shows what's launchable (local, no pod),
52
+ // bare `synap launch` runs the guided one-per-company setup.
53
+ program
54
+ .command("launch")
55
+ .description("Stand up a NEW company/OS on a pod — creates a project + its core workspaces (interactive)")
56
+ .option("--list", "List what can be launched (local templates, no pod needed) and exit")
57
+ .option("--search <query>", "Filter --list by name/description/slug")
58
+ .option("--type <type>", "Filter --list by package type (workspace|capability|skill|workflow|view|cell)")
59
+ .option("--json", "Output as JSON")
60
+ .option("--pod-url <url>", "Pod URL override")
61
+ .option("--api-key <key>", "API key override")
62
+ .action(async (opts) => {
63
+ const { launch } = await import("./commands/launch.js");
64
+ await launch(opts);
65
+ });
66
+ // Hidden: one-shot Discord↔Synap bridge provisioning (dogfood/dev convenience).
67
+ program
68
+ .command("bridge-setup", { hidden: true })
69
+ .description("(hidden) One-shot Discord↔Synap bridge provisioning")
70
+ .option("--client-id <id>", "Discord application (client) id — prints the invite URL")
71
+ .option("--bot-token <token>", "Discord bot token — provisioned into the pod vault")
72
+ .option("--guild-id <id>", "Discord server (guild) id — written to the bridge .env")
73
+ .option("--bridge-dir <path>", "Path to the telegram-discord-bridge repo")
74
+ .option("--workspace-id <uuid>", "Target workspace (default: pod profile's)")
75
+ .option("--proactive-channel <id>", "Discord channel id for the agent's proactive posts")
76
+ .option("--enable-react", "Turn on ✅-react capture")
77
+ .option("--pod <name>", "Pod profile to connect the bridge to (default: prompt)")
78
+ .option("--governance <mode>", "Agent governance preset: safe | normal | crazy (default: prompt)")
79
+ .option("--pod-url <url>", "Synap pod URL (override)")
80
+ .option("--api-key <key>", "Hub Protocol API key (override)")
81
+ .action(async (opts) => {
82
+ const { bridgeSetup } = await import("./commands/bridge-setup.js");
83
+ await bridgeSetup(opts);
84
+ });
45
85
  program
46
86
  .command("connect")
47
87
  .description("Connect an AI surface (Claude Code, Claude Desktop, Cursor, Raycast) to a Synap pod")
@@ -51,6 +91,8 @@ program
51
91
  .option("--name <name>", "Pod profile name to save credentials under (default: 'default')")
52
92
  .option("--list", "List supported targets and exit")
53
93
  .option("--manual-key", "Skip the browser approval flow and paste a key (or provisioning token)")
94
+ .option("--pin-workspace <id>", "Pin the connection to one workspace (default: pod-wide lens)")
95
+ .option("--pin-project <id>", "Pin the connection to one project (composable with --pin-workspace)")
54
96
  .action(async (opts) => {
55
97
  const { connect } = await import("./commands/connect.js");
56
98
  await connect(opts);
@@ -77,9 +119,10 @@ pods
77
119
  .command("use <name>")
78
120
  .description("Switch active pod and propagate credentials to all agent surfaces")
79
121
  .option("--surface <surface>", "Only switch this surface (raycast, claude-code, claude-desktop, cursor)")
122
+ .option("--json", "Output as JSON (incl. nextSteps for agents; full-switch only)")
80
123
  .action(async (name, opts) => {
81
124
  const { podsUse } = await import("./commands/pods.js");
82
- await podsUse(name, { surface: opts.surface });
125
+ await podsUse(name, { surface: opts.surface, json: opts.json });
83
126
  });
84
127
  pods
85
128
  .command("remove <name>")
@@ -99,9 +142,34 @@ pods
99
142
  program
100
143
  .command("status")
101
144
  .description("Show Synap pod health and API status")
102
- .action(async () => {
145
+ .option("--json", "Dump raw status (incl. release/migration detail) as JSON")
146
+ .action(async (opts) => {
103
147
  const { status } = await import("./commands/status.js");
104
- await status();
148
+ await status({ json: opts.json });
149
+ });
150
+ program
151
+ .command("versions")
152
+ .description("Show LOCAL vs NPM vs CONTROL-PLANE vs POD version drift for workspace-templates, api-types, and capabilities")
153
+ .option("--json", "Output structured {artifacts:[...]} JSON")
154
+ .action(async (opts) => {
155
+ const { versions } = await import("./commands/versions.js");
156
+ await versions({ json: opts.json });
157
+ });
158
+ program
159
+ .command("whoami")
160
+ .description("Show the winning API key's identity/scopes/workspace and flag env-vs-surface key divergence")
161
+ .action(async () => {
162
+ const { whoami } = await import("./commands/whoami.js");
163
+ await whoami();
164
+ });
165
+ // Hidden: compact ANSI line for the Claude Code statusLine (reads stdin JSON).
166
+ program
167
+ .command("statusline", { hidden: true })
168
+ .description("(internal) Compact ANSI status line for Claude Code")
169
+ .option("--refresh", "Refresh the pod cache (run detached in the background)")
170
+ .action(async (opts) => {
171
+ const { statusline } = await import("./commands/statusline.js");
172
+ await statusline({ refresh: opts.refresh });
105
173
  });
106
174
  program
107
175
  .command("update")
@@ -174,9 +242,46 @@ program
174
242
  const { connections } = await import("./commands/connections.js");
175
243
  await connections();
176
244
  });
245
+ // ─── mcp ────────────────────────────────────────────────────────────────────
246
+ // The MCP front door: point any AI client at the pod's /mcp server.
247
+ const mcp = program
248
+ .command("mcp")
249
+ .description("Connect any AI client to your pod's MCP server (the ambient tool layer)");
250
+ mcp
251
+ .command("url")
252
+ .description("Print a ready-to-paste MCP connection (URL + key + snippets) for UI clients like ChatGPT")
253
+ .option("--client <name>", "Name the dedicated agent key after the target client")
254
+ .option("--workspace <id>", "Scope to a specific workspace (omit for pod-wide)")
255
+ .option("--project <id>", "Focus the agent on a project (narrows every tool call; orthogonal to --workspace)")
256
+ .option("--json", "Output as JSON")
257
+ .option("--pod-url <url>", "Pod URL override")
258
+ .option("--api-key <key>", "API key override")
259
+ .action(async (opts) => {
260
+ const { mcpUrl } = await import("./commands/mcp.js");
261
+ await mcpUrl(opts);
262
+ });
263
+ mcp
264
+ .command("verify")
265
+ .description("Health-check: is the pod's /mcp endpoint reachable and the key valid?")
266
+ .option("--workspace <id>", "Scope to a specific workspace")
267
+ .option("--json", "Output as JSON")
268
+ .option("--pod-url <url>", "Pod URL override")
269
+ .option("--api-key <key>", "API key override")
270
+ .action(async (opts) => {
271
+ const { mcpVerify } = await import("./commands/mcp.js");
272
+ await mcpVerify(opts);
273
+ });
274
+ mcp
275
+ .command("connect [client]")
276
+ .description("Write the MCP config for a file-configurable client (Claude Code, Cursor, Desktop, …) — alias of `synap connect`")
277
+ .option("--name <name>", "Pod profile to connect")
278
+ .action(async (client, opts) => {
279
+ const { connect } = await import("./commands/connect.js");
280
+ await connect({ target: client, name: opts.name });
281
+ });
177
282
  program
178
283
  .command("login")
179
- .description("Connect to a Synap pod (self-hosted or managed)")
284
+ .description("Connect your Synap account (private templates) + your pods")
180
285
  .option("--reconnect [name]", "Re-authenticate a saved pod without re-entering its URL")
181
286
  .action(async (opts) => {
182
287
  const chalk = (await import("chalk")).default;
@@ -200,23 +305,44 @@ program
200
305
  // Already have pods — show status and offer reconnect if any are unreachable
201
306
  const { checkPodHealth } = await import("./lib/pod.js");
202
307
  const ora = (await import("ora")).default;
203
- const spinner = ora("Checking pod health...").start();
308
+ const spinner = ora("Checking pods + credentials...").start();
204
309
  const checks = await Promise.all(profiles.map(async (p) => {
205
310
  const h = await checkPodHealth(p.config.podUrl).catch(() => ({ healthy: false }));
206
- return { ...p, healthy: h.healthy };
311
+ // A pod can be HEALTHY (public /health) while the saved key is REVOKED.
312
+ // Validate the actual credential too — otherwise a dead key looks "ok"
313
+ // and the user gets cryptic 401s downstream (the connect trap).
314
+ let keyValid = false;
315
+ if (h.healthy && p.config.hubApiKey) {
316
+ try {
317
+ const res = await fetch(`${p.config.podUrl.replace(/\/$/, "")}/api/hub/auth/status`, {
318
+ headers: { Authorization: `Bearer ${p.config.hubApiKey}` },
319
+ signal: AbortSignal.timeout(6000),
320
+ });
321
+ keyValid = res.ok;
322
+ }
323
+ catch {
324
+ keyValid = false;
325
+ }
326
+ }
327
+ return { ...p, healthy: h.healthy, keyValid };
207
328
  }));
208
329
  spinner.stop();
209
330
  console.log("\n Configured pods:\n");
210
331
  for (const p of checks) {
211
332
  const active = p.active ? chalk.green(" ● ") : " ";
212
- const status = p.healthy ? chalk.green("ok") : chalk.red("unreachable");
333
+ const status = !p.healthy
334
+ ? chalk.red("unreachable")
335
+ : p.keyValid
336
+ ? chalk.green("ok")
337
+ : chalk.yellow("key expired");
213
338
  console.log(` ${active}${chalk.bold(p.name.padEnd(14))} ${status} ${chalk.dim(p.config.podUrl)}`);
214
339
  }
215
340
  console.log();
216
- const unreachable = checks.filter((p) => !p.healthy);
217
- if (unreachable.length > 0) {
218
- console.log(chalk.yellow(` ${unreachable.length} pod(s) unreachable. To refresh credentials:`));
219
- for (const p of unreachable) {
341
+ // Anything that won't authenticate — unreachable OR a revoked/expired key.
342
+ const needsReconnect = checks.filter((p) => !p.healthy || !p.keyValid);
343
+ if (needsReconnect.length > 0) {
344
+ console.log(chalk.yellow(` ${needsReconnect.length} pod(s) need re-authentication. Refresh credentials:`));
345
+ for (const p of needsReconnect) {
220
346
  console.log(chalk.dim(` synap login --reconnect ${p.name}`));
221
347
  }
222
348
  console.log();
@@ -226,22 +352,87 @@ program
226
352
  const active = checks.find((p) => p.active);
227
353
  if (active)
228
354
  console.log(chalk.dim(` Active: ${active.name} (${active.config.podUrl})`));
229
- console.log();
230
- console.log(chalk.dim(" synap pods use <name> — switch active pod"));
231
- console.log(chalk.dim(" synap pods add — connect another pod"));
232
355
  }
356
+ // ── Synap ACCOUNT (control plane) — a FIRST-CLASS half of "login" ──────
357
+ // Pods authenticate DATA access; the ACCOUNT authenticates the control plane
358
+ // (private templates like The Arch, hosted pods, marketplace publishing).
359
+ // They are different credentials, and pods alone never unlock private
360
+ // templates — so this gets its own headed section, not a footnote. `synap
361
+ // launch`'s "private templates after 'synap login'" hint lands HERE.
362
+ const { isLoggedIn: cpLoggedIn, login: cpLogin } = await import("./lib/auth.js");
363
+ console.log("\n Synap account:\n");
364
+ const account = await cpLoggedIn();
365
+ let accountEmail;
366
+ if (account.valid) {
367
+ accountEmail = account.email;
368
+ console.log(` ${chalk.green("●")} ${chalk.bold(account.email ?? "logged in")} ${chalk.dim("— private templates available")}`);
369
+ }
370
+ else {
371
+ console.log(` ${chalk.yellow("○")} ${chalk.bold("not logged in")} ${chalk.dim("— your private templates (e.g. The Arch) are hidden until you log in")}`);
372
+ const prompts = (await import("prompts")).default;
373
+ const { doLogin } = await prompts({
374
+ type: "confirm",
375
+ name: "doLogin",
376
+ message: "Log in to your Synap account now?",
377
+ initial: true,
378
+ });
379
+ if (doLogin) {
380
+ const creds = await cpLogin();
381
+ if (creds?.email) {
382
+ accountEmail = creds.email;
383
+ console.log(chalk.green(` ✓ Logged in as ${creds.email} — private templates unlocked.`));
384
+ }
385
+ }
386
+ else {
387
+ console.log(chalk.dim(" Later: synap login · or synap login --token <token> (synap.live/account/tokens)"));
388
+ }
389
+ }
390
+ const { renderNextSteps, FLOW } = await import("./lib/next-steps.js");
391
+ renderNextSteps(FLOW.afterLogin(accountEmail));
233
392
  });
234
393
  // ─── orient ───────────────────────────────────────────────────────────────────
235
394
  program
236
395
  .command("orient")
237
- .description("Show pod orientation: who you are, workspaces, profiles, and entity counts")
396
+ .description("Show a lightweight lens map: who you are, your projects (companies/initiatives), and workspaces (operational domains)")
238
397
  .option("--json", "Output as JSON")
398
+ .option("--details", "Include per-workspace profiles + entity counts (heavier)")
239
399
  .option("--pod-url <url>", "Pod URL override")
240
400
  .option("--api-key <key>", "API key override")
241
401
  .action(async (opts) => {
242
402
  const { orient } = await import("./commands/data.js");
243
403
  await orient(opts);
244
404
  });
405
+ // ─── digest ─────────────────────────────────────────────────────────────────
406
+ // A quick read of what's already in a workspace or project (counts + key
407
+ // entities + summary). Default = the active workspace lens.
408
+ program
409
+ .command("digest")
410
+ .description("Summarize what's in a workspace or project (counts + key entities)")
411
+ .option("--workspace <id|name>", "Workspace to digest (defaults to active workspace lens)")
412
+ .option("--project <id|name>", "Project to digest (cross-cutting lens)")
413
+ .option("--json", "Output raw JSON")
414
+ .option("--pod-url <url>", "Pod URL override")
415
+ .option("--api-key <key>", "API key override")
416
+ .action(async (opts) => {
417
+ const { digest } = await import("./commands/digest.js");
418
+ await digest(opts);
419
+ });
420
+ // ─── diagnose ────────────────────────────────────────────────────────────────
421
+ // See what an AI did across flows: the unified run feed, or one run's activity
422
+ // timeline (for a capture: WHY a facet/entity dropped, with a fixHint).
423
+ program
424
+ .command("diagnose [runId]")
425
+ .description("See what an AI did — the run feed, or one run's activity (why it did what it did)")
426
+ .option("--flow <automation|playbook|capture|session>", "Restrict the feed, or the run's flow (default capture for a runId)")
427
+ .option("--flow-id <id>", "Restrict the feed to one flow's runs (automationId / playbookId)")
428
+ .option("--limit <n>", "Max runs in the feed")
429
+ .option("--json", "Output raw JSON")
430
+ .option("--pod-url <url>", "Pod URL override")
431
+ .option("--api-key <key>", "API key override")
432
+ .action(async (runId, opts) => {
433
+ const { diagnose } = await import("./commands/diagnose.js");
434
+ await diagnose(runId, opts);
435
+ });
245
436
  // ─── use ──────────────────────────────────────────────────────────────────────
246
437
  program
247
438
  .command("use <workspace>")
@@ -253,20 +444,70 @@ program
253
444
  const { useWorkspace } = await import("./commands/data.js");
254
445
  await useWorkspace(workspace, opts);
255
446
  });
256
- // ─── note ─────────────────────────────────────────────────────────────────────
257
- // Quick `note` entity. The one canonical READ verb is `ask`; the one canonical
258
- // structured-WRITE verb is `capture`. (search / recall / remember removed — they
259
- // were redundant doors `ask`/`capture`/`note` already cover.)
260
- program
261
- .command("note <text>")
262
- .description("Quick freeform note → note entity (for structured learnings use `synap capture`)")
263
- .option("--context <entity-id>", "Link this note to an entity")
447
+ // ─── project / lens (per-Claude-session scoping) ──────────────────────────────
448
+ const project = program
449
+ .command("project")
450
+ .description("Manage + focus the cross-cutting project lens (a company/initiative): list, new, use, clear");
451
+ project
452
+ .command("list", { isDefault: true })
453
+ .description("List projects on the active pod, with the pinned one marked (bare `synap project` runs this)")
454
+ .option("--json", "Output as JSON (incl. nextSteps for agents)")
455
+ .option("--pod-url <url>", "Pod URL override")
456
+ .option("--api-key <key>", "API key override")
457
+ .action(async (opts) => {
458
+ const { projectList } = await import("./commands/lens.js");
459
+ await projectList(opts);
460
+ });
461
+ project
462
+ .command("new <name>")
463
+ .description("Create a project (a company/initiative) on the active pod, then guide you to pin + add to it")
464
+ .option("--description <text>", "Optional one-line description")
465
+ .option("--json", "Output as JSON (incl. nextSteps for agents)")
466
+ .option("--pod-url <url>", "Pod URL override")
467
+ .option("--api-key <key>", "API key override")
468
+ .action(async (name, opts) => {
469
+ const { projectNew } = await import("./commands/lens.js");
470
+ await projectNew(name, opts);
471
+ });
472
+ project
473
+ .command("use <ref>")
474
+ .description("Pin the active project (durable, like `synap use <workspace>`). Ref = uuid, slug, or <pod>/<slug> — cross-pod refs switch the active pod too")
475
+ .option("--session", "Ephemeral: scope only this Claude Code session, don't persist (cross-pod refs refused)")
264
476
  .option("--json", "Output as JSON")
265
477
  .option("--pod-url <url>", "Pod URL override")
266
478
  .option("--api-key <key>", "API key override")
267
- .action(async (text, opts) => {
268
- const { noteData } = await import("./commands/data.js");
269
- await noteData(text, opts);
479
+ .action(async (ref, opts) => {
480
+ const { useProject } = await import("./commands/lens.js");
481
+ await useProject(ref, opts);
482
+ });
483
+ project
484
+ .command("clear")
485
+ .description("Clear the active project focus (durable by default)")
486
+ .option("--session", "Ephemeral: clear only this Claude Code session's project")
487
+ .option("--json", "Output as JSON")
488
+ .action(async (opts) => {
489
+ const { clearProject } = await import("./commands/lens.js");
490
+ await clearProject(opts);
491
+ });
492
+ project
493
+ .command("purge <target>")
494
+ .description("HARD teardown: delete a project + its pod-wide-exclusive entities (owner-only, irreversible)")
495
+ .option("--confirm <name>", "Confirm non-interactively by passing the exact project name")
496
+ .option("--yes", "Skip the interactive name prompt (uses the resolved name)")
497
+ .option("--json", "Output raw JSON")
498
+ .option("--pod-url <url>", "Pod URL override")
499
+ .option("--api-key <key>", "API key override")
500
+ .action(async (target, opts) => {
501
+ const { projectPurge } = await import("./commands/purge.js");
502
+ await projectPurge(target, opts);
503
+ });
504
+ program
505
+ .command("lens")
506
+ .description("Show this Claude session's lens (workspace + project + focus session)")
507
+ .option("--json", "Output as JSON")
508
+ .action(async (opts) => {
509
+ const { showLens } = await import("./commands/lens.js");
510
+ await showLens(opts);
270
511
  });
271
512
  // ─── ask (unified knowledge access) ─────────────────────────────────────────────
272
513
  // The ONE read verb. Routes to the right substrate(s) — semantic (entities),
@@ -277,6 +518,8 @@ program
277
518
  .option("--workspace <id>", "Scope to a specific workspace (omit for pod-wide)")
278
519
  .option("--limit <n>", "Max results per substrate", "10")
279
520
  .option("--json", "Output as JSON")
521
+ .option("--session", "Scope retrieval to the active session context")
522
+ .option("--compare", "A/B diagnostic: show baseline vs Horizon rankers side-by-side (read-only, does not change the answer)")
280
523
  .option("--pod-url <url>", "Pod URL override")
281
524
  .option("--api-key <key>", "API key override")
282
525
  .action(async (query, opts) => {
@@ -294,6 +537,7 @@ program
294
537
  .option("--why <text>", "Reasoning or context")
295
538
  .option("--evidence <text>", "Supporting file path, URL, or code snippet")
296
539
  .option("--tags <csv>", "Comma-separated tags e.g. repo:synap-backend,layer:migrations")
540
+ .option("--session", "Link captured knowledge to the active session")
297
541
  .option("--global", "GLOBAL lane: pod-wide cross-cutting runbook (→ knowledge_keys), visible in every workspace")
298
542
  .option("--key <ns:slug>", "Stable key for a --global runbook (derived from --type + --claim if omitted)")
299
543
  .option("--team", "Write to the first product workspace instead of the active workspace")
@@ -304,6 +548,32 @@ program
304
548
  const { captureKnowledge } = await import("./commands/knowledge.js");
305
549
  await captureKnowledge({ ...opts, text });
306
550
  });
551
+ // ─── import ─────────────────────────────────────────────────────────────────
552
+ // "capture, but for files and URLs." Each input (file/folder/URL) routes through
553
+ // the SAME AI capture pipeline (/capture/structure → /capture/execute), so it
554
+ // inherits entity extraction, the relation graph, and workspace/project routing.
555
+ program
556
+ .command("import <inputs...>")
557
+ .description("Import files, folders, or URLs into the pod (AI capture pipeline, or Superwhisper store-first)")
558
+ .option("--workspace <id|name>", "Override AI workspace routing")
559
+ .option("--project <id|name>", "Override AI project routing")
560
+ .option("--dry-run", "Preview only — do not write")
561
+ .option("--yes", "Skip confirmation / auto-confirm store-first")
562
+ .option("--session", "Link created entities to the active session")
563
+ .option("--json", "Output as JSON")
564
+ .option("--pod-url <url>", "Pod URL override")
565
+ .option("--api-key <key>", "API key override")
566
+ .option("--source <name>", "Adapter: superwhisper (paired meta.json+output.wav store-first)")
567
+ .option("--store-first", "Skip AI structure; store units as pod-wide notes (+ optional audio)")
568
+ .option("--with-audio", "Upload WAV provenance (default on for --source superwhisper --store-first)")
569
+ .option("--no-with-audio", "Transcript-only (no WAV upload)")
570
+ .option("--limit <n>", "Max Superwhisper units to process", (v) => parseInt(v, 10))
571
+ .option("--concurrency <n>", "Parallel unit uploads (1–4)", (v) => parseInt(v, 10))
572
+ .option("--no-resume", "Ignore local import ledger (re-import all)")
573
+ .action(async (inputs, opts) => {
574
+ const { importData } = await import("./commands/import.js");
575
+ await importData(inputs, opts);
576
+ });
307
577
  program
308
578
  .command("subscribe")
309
579
  .description("Stream pod events as NDJSON (long-poll)")
@@ -346,6 +616,8 @@ program
346
616
  .option("--json", "Output as JSON (default: human-readable)")
347
617
  .option("--profiles", "Show only profiles (use with --json for machine-readable schema)")
348
618
  .option("--commands", "Show only the command tree")
619
+ .option("--summary", "List profile kinds without property schemas")
620
+ .option("--profile-slugs <slugs>", "Comma-separated profile slugs to load in full")
349
621
  .option("--workspace <id>", "Workspace to query (defaults to active workspace)")
350
622
  .action(async (opts) => {
351
623
  const { discover } = await import("./commands/discover.js");
@@ -368,6 +640,18 @@ workspace
368
640
  const { provisionAgentWorkspace } = await import("./commands/knowledge.js");
369
641
  await provisionAgentWorkspace({ ...opts, agentUserId: opts.agentUserId });
370
642
  });
643
+ workspace
644
+ .command("purge <target>")
645
+ .description("HARD teardown: delete a workspace + all its entities and blobs (owner-only, irreversible)")
646
+ .option("--confirm <name>", "Confirm non-interactively by passing the exact workspace name")
647
+ .option("--yes", "Skip the interactive name prompt (uses the resolved name)")
648
+ .option("--json", "Output raw JSON")
649
+ .option("--pod-url <url>", "Pod URL override")
650
+ .option("--api-key <key>", "API key override")
651
+ .action(async (target, opts) => {
652
+ const { workspacePurge } = await import("./commands/purge.js");
653
+ await workspacePurge(target, opts);
654
+ });
371
655
  // ─── list ─────────────────────────────────────────────────────────────────────
372
656
  const list = program
373
657
  .command("list")
@@ -408,6 +692,7 @@ list
408
692
  .description("List entities on the pod")
409
693
  .option("--workspace <id>", "Scope to a workspace (omit for pod-wide)")
410
694
  .option("--profile <slug>", "Filter by profile slug (e.g. person, task, note)")
695
+ .option("--role <slug>", "Filter to entities carrying this role (e.g. client, partner)")
411
696
  .option("--limit <n>", "Max results", "50")
412
697
  .option("--json", "Output as JSON")
413
698
  .option("--pod-url <url>", "Pod URL override")
@@ -428,6 +713,51 @@ program
428
713
  const { showEntity } = await import("./commands/data-extra.js");
429
714
  await showEntity(id, opts);
430
715
  });
716
+ // ─── facet ────────────────────────────────────────────────────────────────────
717
+ // Roles — one identity, many roles. A role-profile (client, partner, contact…)
718
+ // attached to an existing entity, never a second entity. Governed writes: an
719
+ // attach/detach may come back "proposed for review" instead of applying live.
720
+ const facet = program
721
+ .command("facet")
722
+ .description("Manage roles attached to an entity (client, partner, contact, …)");
723
+ facet
724
+ .command("attach <entityId> <roleSlug>")
725
+ .description("Attach a role to an entity")
726
+ .option("--property <kv>", "Role property as key=value (repeatable)", collect, [])
727
+ .option("--workspace <id>", "Role's lens (defaults to the active workspace)")
728
+ .option("--json", "Output as JSON")
729
+ .option("--pod-url <url>", "Pod URL override")
730
+ .option("--api-key <key>", "API key override")
731
+ .action(async (entityId, roleSlug, opts) => {
732
+ const { attachFacet } = await import("./commands/facet.js");
733
+ await attachFacet(entityId, roleSlug, opts);
734
+ });
735
+ facet
736
+ .command("list <entityId>")
737
+ .description("List the roles attached to an entity")
738
+ .option("--json", "Output as JSON")
739
+ .option("--pod-url <url>", "Pod URL override")
740
+ .option("--api-key <key>", "API key override")
741
+ .action(async (entityId, opts) => {
742
+ const { listFacets } = await import("./commands/facet.js");
743
+ await listFacets(entityId, opts);
744
+ });
745
+ facet
746
+ .command("detach [facetId]")
747
+ .description("Detach a role — pass the facet id, or --entity <id> --role <slug>")
748
+ .option("--entity <id>", "Entity id (with --role, resolves the facet to detach)")
749
+ .option("--role <slug>", "Role slug (with --entity)")
750
+ .option("--json", "Output as JSON")
751
+ .option("--pod-url <url>", "Pod URL override")
752
+ .option("--api-key <key>", "API key override")
753
+ .action(async (facetId, opts) => {
754
+ if (!facetId && !(opts.entity && opts.role)) {
755
+ console.error("Provide a facet id, or both --entity <id> and --role <slug>.");
756
+ process.exit(1);
757
+ }
758
+ const { detachFacet } = await import("./commands/facet.js");
759
+ await detachFacet(facetId ?? "", opts);
760
+ });
431
761
  // ─── proposals ────────────────────────────────────────────────────────────────
432
762
  // Governance inbox — pending proposals attributed to this agent.
433
763
  const proposals = program
@@ -603,6 +933,36 @@ skillCmd
603
933
  const { getSkill } = await import("./commands/skills-commands.js");
604
934
  await getSkill(slug, opts);
605
935
  });
936
+ skillCmd
937
+ .command("add <source>")
938
+ .description("Add skill(s) to your pod from: bundled · a local path · ~/.claude/skills/ · owner/repo · a git URL")
939
+ .option("--pod-url <url>", "Pod URL override")
940
+ .option("--api-key <key>", "API key override")
941
+ .action(async (source, opts) => {
942
+ const { addSkill } = await import("./commands/skill-manage.js");
943
+ await addSkill(source, opts);
944
+ });
945
+ skillCmd
946
+ .command("list")
947
+ .alias("ls")
948
+ .description("List the instruction skills installed on your pod")
949
+ .option("--pod-url <url>", "Pod URL override")
950
+ .option("--api-key <key>", "API key override")
951
+ .option("--debug", "Show resolved credentials")
952
+ .action(async (opts) => {
953
+ const { listSkills } = await import("./commands/skill-manage.js");
954
+ await listSkills(opts);
955
+ });
956
+ skillCmd
957
+ .command("remove <slug>")
958
+ .alias("rm")
959
+ .description("Remove a skill from your pod by slug")
960
+ .option("--pod-url <url>", "Pod URL override")
961
+ .option("--api-key <key>", "API key override")
962
+ .action(async (slug, opts) => {
963
+ const { removeSkill } = await import("./commands/skill-manage.js");
964
+ await removeSkill(slug, opts);
965
+ });
606
966
  skillCmd
607
967
  .command("sync")
608
968
  .description("Bulk-import local skills from ~/.claude/skills/ into the pod")
@@ -630,8 +990,9 @@ skillCmd
630
990
  // Paginated entity list — cleaner than `list entities`.
631
991
  program
632
992
  .command("browse [profile]")
633
- .description("Browse entities in the active workspace, optionally filtered by profile type")
993
+ .description("Browse entities in the active workspace, optionally filtered by profile type or role")
634
994
  .option("--workspace <id>", "Scope to a specific workspace")
995
+ .option("--role <slug>", "Filter to entities carrying this role (e.g. client, partner)")
635
996
  .option("--limit <n>", "Max results", "20")
636
997
  .option("--json", "Output as JSON")
637
998
  .option("--pod-url <url>", "Pod URL override")
@@ -795,6 +1156,35 @@ agents
795
1156
  const agent = program
796
1157
  .command("agent")
797
1158
  .description("Run autonomous agent loops against the IS, or schedule recurring goals");
1159
+ agent
1160
+ .command("ask <message>")
1161
+ .description("Send one message to the workspace's deployed agent and print its reply (multi-turn: reuses one thread)")
1162
+ .option("--workspace <id|name>", "Workspace to talk to (uses active workspace/lens if omitted)")
1163
+ .option("--thread <id>", "Target an existing thread/channel id instead of the default CLI chat thread")
1164
+ .option("--new", "Start a fresh thread instead of continuing the persistent CLI chat thread")
1165
+ .option("--agent-type <type>", "Requested agent type hint (backend currently routes to the orchestrator)")
1166
+ .option("--timeout <seconds>", "How long to wait for the agent's reply (default: 90)")
1167
+ .option("--json", "Machine-readable output { ok, reply, threadId, workspaceId }")
1168
+ .option("--pod-url <url>", "Override pod URL")
1169
+ .option("--api-key <key>", "Override API key")
1170
+ .action(async (message, opts) => {
1171
+ const { agentAsk } = await import("./commands/agent-chat.js");
1172
+ await agentAsk({ ...opts, message });
1173
+ });
1174
+ agent
1175
+ .command("chat")
1176
+ .description("Interactive REPL conversation with the workspace's deployed agent")
1177
+ .option("--workspace <id|name>", "Workspace to talk to (uses active workspace/lens if omitted)")
1178
+ .option("--thread <id>", "Target an existing thread/channel id instead of the default CLI chat thread")
1179
+ .option("--new", "Start a fresh thread instead of continuing the persistent CLI chat thread")
1180
+ .option("--agent-type <type>", "Requested agent type hint (backend currently routes to the orchestrator)")
1181
+ .option("--timeout <seconds>", "How long to wait for each reply (default: 90)")
1182
+ .option("--pod-url <url>", "Override pod URL")
1183
+ .option("--api-key <key>", "Override API key")
1184
+ .action(async (opts) => {
1185
+ const { agentChat } = await import("./commands/agent-chat.js");
1186
+ await agentChat(opts);
1187
+ });
798
1188
  agent
799
1189
  .command("run")
800
1190
  .description("Run an autonomous agent toward a goal using the Intelligence Service")
@@ -926,6 +1316,32 @@ program
926
1316
  const { graphTraverse } = await import("./commands/graph.js");
927
1317
  await graphTraverse(opts);
928
1318
  });
1319
+ // ─── centrality ────────────────────────────────────────────────────────────────
1320
+ // Window onto the Phase-3 PageRank centrality signal (entity_centrality):
1321
+ // see if it has populated, and trigger a recompute on demand.
1322
+ const centrality = program
1323
+ .command("centrality")
1324
+ .description("Inspect PageRank centrality (entity_centrality) and trigger a recompute");
1325
+ centrality
1326
+ .command("status", { isDefault: true })
1327
+ .description("Show whether PageRank centrality has populated + the top central entities")
1328
+ .option("--json", "Output as JSON")
1329
+ .option("--pod-url <url>", "Pod URL override")
1330
+ .option("--api-key <key>", "API key override")
1331
+ .action(async (opts) => {
1332
+ const { centralityStatus } = await import("./commands/centrality.js");
1333
+ await centralityStatus(opts);
1334
+ });
1335
+ centrality
1336
+ .command("recompute")
1337
+ .description("Enqueue a PageRank centrality recompute (runs in the background)")
1338
+ .option("--json", "Output as JSON")
1339
+ .option("--pod-url <url>", "Pod URL override")
1340
+ .option("--api-key <key>", "API key override")
1341
+ .action(async (opts) => {
1342
+ const { centralityRecompute } = await import("./commands/centrality.js");
1343
+ await centralityRecompute(opts);
1344
+ });
929
1345
  // ─── events ───────────────────────────────────────────────────────────────────
930
1346
  program
931
1347
  .command("events")
@@ -999,15 +1415,24 @@ program
999
1415
  });
1000
1416
  // ─── open ─────────────────────────────────────────────────────────────────────
1001
1417
  program
1002
- .command("open <kind> <id>")
1003
- .description("Open an entity, view, cell, or document in the Synap desktop app")
1004
- .action(async (kind, id) => {
1005
- if (kind !== "entity" && kind !== "view" && kind !== "cell" && kind !== "document") {
1006
- console.error(`Unknown kind: "${kind}". Use: entity | view | cell | document`);
1007
- process.exit(1);
1418
+ .command("open <kind-or-id> [id]")
1419
+ .description("Open in the Synap desktop app. Use: open <kind> <id> or open <id> (auto-resolves type)")
1420
+ .action(async (kindOrId, id) => {
1421
+ if (id) {
1422
+ // open entity|view|cell|document|proposal <id>
1423
+ const validKinds = ["entity", "view", "cell", "document", "proposal"];
1424
+ if (!validKinds.includes(kindOrId)) {
1425
+ console.error(`Unknown kind: "${kindOrId}". Use: ${validKinds.join(" | ")}`);
1426
+ process.exit(1);
1427
+ }
1428
+ const { openInBrowser } = await import("./commands/open.js");
1429
+ await openInBrowser({ kind: kindOrId, id });
1430
+ }
1431
+ else {
1432
+ // open <id> — resolve type automatically
1433
+ const { resolveAndOpen } = await import("./commands/open.js");
1434
+ await resolveAndOpen(kindOrId);
1008
1435
  }
1009
- const { openInBrowser } = await import("./commands/open.js");
1010
- await openInBrowser({ kind: kind, id });
1011
1436
  });
1012
1437
  // ─── doc ──────────────────────────────────────────────────────────────────────
1013
1438
  const doc = program
@@ -1133,47 +1558,311 @@ program
1133
1558
  .option("--pod-url <url>", "Pod URL override")
1134
1559
  .option("--api-key <key>", "API key override")
1135
1560
  .action(async (service, opts) => {
1136
- const { connectorsConnect } = await import("./commands/connectors.js");
1137
- await connectorsConnect(service, opts);
1138
- });
1139
- // ─── connectors ──────────────────────────────────────────────────────────────
1140
- const connectors = program
1141
- .command("connectors")
1142
- .description("Manage pod connector integrations (Nango-powered)");
1143
- connectors
1561
+ const { toolsConnect } = await import("./commands/tools.js");
1562
+ await toolsConnect(service, opts);
1563
+ });
1564
+ // ─── tools ──────────────────────────────────────────────────────────────────
1565
+ const tools = program
1566
+ .command("tools")
1567
+ .description("Add and manage external service tools and their credentials");
1568
+ tools
1144
1569
  .command("list")
1145
- .description("List available connectors and connection status")
1570
+ .description("List available tools and their connection status")
1146
1571
  .option("--json", "Output as JSON")
1147
1572
  .option("--workspace <id>", "Workspace context")
1148
1573
  .action(async (opts) => {
1149
- const { connectorsList } = await import("./commands/connectors.js");
1150
- await connectorsList(opts);
1574
+ const { toolsList } = await import("./commands/tools.js");
1575
+ await toolsList(opts);
1576
+ });
1577
+ tools
1578
+ .command("connect <service>")
1579
+ .description("Connect a credential to a tool (via Nango OAuth or vault)")
1580
+ .option("--workspace <id>", "Workspace context")
1581
+ .option("--pod-url <url>", "Pod URL override")
1582
+ .option("--api-key <key>", "API key override")
1583
+ .action(async (service, opts) => {
1584
+ const { toolsConnect } = await import("./commands/tools.js");
1585
+ await toolsConnect(service, opts);
1151
1586
  });
1152
- connectors
1587
+ tools
1153
1588
  .command("sync <provider>")
1154
- .description("Trigger a manual sync for a connected provider")
1589
+ .description("Trigger a manual sync for a connected tool")
1155
1590
  .option("--workspace <id>", "Workspace context")
1156
1591
  .action(async (provider, opts) => {
1157
- const { connectorsSync } = await import("./commands/connectors.js");
1158
- await connectorsSync(provider, opts);
1592
+ const { toolsSync } = await import("./commands/tools.js");
1593
+ await toolsSync(provider, opts);
1159
1594
  });
1160
- connectors
1595
+ tools
1161
1596
  .command("disconnect <provider>")
1162
- .description("Revoke a connector connection")
1597
+ .description("Revoke a tool's connection")
1163
1598
  .option("--workspace <id>", "Workspace context")
1164
1599
  .option("--force", "Skip confirmation")
1165
1600
  .action(async (provider, opts) => {
1166
- const { connectorsDisconnect } = await import("./commands/connectors.js");
1167
- await connectorsDisconnect(provider, opts);
1601
+ const { toolsDisconnect } = await import("./commands/tools.js");
1602
+ await toolsDisconnect(provider, opts);
1168
1603
  });
1169
- connectors
1604
+ tools
1170
1605
  .command("schema")
1171
- .description("Fetch connector schema and supported providers (AI context)")
1172
- .option("--write-context [path]", "Write to .claude/CONNECTOR_CONTEXT.md")
1606
+ .description("Fetch tool schema and supported providers (AI context)")
1607
+ .option("--write-context [path]", "Write to .claude/TOOLS_CONTEXT.md")
1173
1608
  .option("--json", "Output raw JSON instead of formatted markdown")
1174
1609
  .action(async (opts) => {
1175
- const { connectorsSchema } = await import("./commands/connectors.js");
1176
- await connectorsSchema(opts);
1610
+ const { toolsSchema } = await import("./commands/tools.js");
1611
+ await toolsSchema(opts);
1612
+ });
1613
+ // ─── pod — unified pod-configuration view ─────────────────────────────────────
1614
+ // `market installed` shows what packages are installed; `pod` answers the
1615
+ // bigger question: what does the WHOLE pod look like — every workspace with
1616
+ // its provenance (marketplace/composed/ad-hoc/orphan), pod-wide vs
1617
+ // per-workspace capabilities/automations/playbooks, and the give/need feed
1618
+ // links between workspaces. Read surface for GET /api/hub/pod/config.
1619
+ const podCmd = program
1620
+ .command("pod")
1621
+ .description("Show the whole configured pod — workspaces (with provenance), capabilities/automations/playbooks, and feed links")
1622
+ .option("--json", "Output the full structured graph as JSON")
1623
+ .option("--orphans", "Only show orphan/ad-hoc workspaces and their template-match suggestions")
1624
+ .option("--pod-url <url>", "Pod URL override")
1625
+ .option("--api-key <key>", "API key override")
1626
+ .action(async (opts) => {
1627
+ const { pod } = await import("./commands/pod.js");
1628
+ await pod(opts);
1629
+ });
1630
+ podCmd
1631
+ .command("adopt <workspaceNameOrId>")
1632
+ .description("Link an orphan/ad-hoc workspace (by name or id) to a matching template — makes it version-tracked")
1633
+ .requiredOption("--template <slug>", "The template slug to adopt this workspace into")
1634
+ .option("--json", "Output as JSON")
1635
+ .option("--pod-url <url>", "Pod URL override")
1636
+ .option("--api-key <key>", "API key override")
1637
+ .action(async (workspaceNameOrId, _opts, cmd) => {
1638
+ // `--json` collides with the parent `pod` command's own `--json` — same
1639
+ // gap `market install` has (see its comment). Merge across the chain.
1640
+ const opts = cmd.optsWithGlobals();
1641
+ const { podAdopt } = await import("./commands/pod.js");
1642
+ await podAdopt(workspaceNameOrId, opts);
1643
+ });
1644
+ // ─── market — discover + install ANY package type ────────────────────────────
1645
+ // launch is workspace-first (bundled, offline); market reaches every CP package
1646
+ // type (capability/skill/workflow/view/cell/workspace), public or private.
1647
+ const market = program
1648
+ .command("market")
1649
+ .description("Browse + install packages (workspaces, capabilities, skills, workflows, views, cells) into a project")
1650
+ .option("--list", "List and exit (the default action)")
1651
+ .option("--search <query>", "Filter by name/description/slug")
1652
+ .option("--type <type>", "Filter by package type (workspace|capability|skill|workflow|view|cell)")
1653
+ .option("--json", "Output as JSON")
1654
+ .action(async (opts) => {
1655
+ const { market: marketBrowse } = await import("./commands/market.js");
1656
+ await marketBrowse(opts);
1657
+ });
1658
+ market
1659
+ .command("install <slug>")
1660
+ .description("Install a package by slug into a project — workspaces install now; other types route you to the right surface")
1661
+ .option("--project <id>", "Optionally tag the seeded entities to a project (installs are pod-wide by default)")
1662
+ .option("--onto <workspaceId>", "Reconcile this template ONTO an existing workspace (additive) instead of creating a new one")
1663
+ .option("--timeout <seconds>", "How long to wait for the apply to finish (default: 120)")
1664
+ .option("--json", "Output as JSON")
1665
+ .option("--pod-url <url>", "Pod URL override")
1666
+ .option("--api-key <key>", "API key override")
1667
+ .action(async (slug, _opts, cmd) => {
1668
+ // `--json` collides with the parent `market` command's own `--json` —
1669
+ // commander then attributes the flag's VALUE to the parent's
1670
+ // `_optionValues`, leaving this action's own `opts` argument `{}` for it
1671
+ // (a real, pre-existing gap: `market install <slug> --json` silently fell
1672
+ // back to human output). `optsWithGlobals()` walks the whole command
1673
+ // chain and merges regardless of which level actually captured the flag.
1674
+ const opts = cmd.optsWithGlobals();
1675
+ const { marketInstall } = await import("./commands/market.js");
1676
+ await marketInstall(slug, opts);
1677
+ });
1678
+ market
1679
+ .command("update [slugs...]")
1680
+ .description("Check installed packages for drift against the catalog, and re-apply the ones that are stale (all with --yes, specific ones with explicit slugs)")
1681
+ .option("--yes", "Apply every available update without prompting (no slugs required)")
1682
+ .option("--dry-run", "Force the preview path — never apply, even with --yes")
1683
+ .option("--timeout <seconds>", "How long to wait for each package's apply to finish (default: 120)")
1684
+ .option("--json", "Output as JSON")
1685
+ .option("--pod-url <url>", "Pod URL override")
1686
+ .option("--api-key <key>", "API key override")
1687
+ .action(async (slugs, _opts, cmd) => {
1688
+ // Same parent/child `--json` collision as `market install` — see its comment.
1689
+ const opts = cmd.optsWithGlobals();
1690
+ const { marketUpdate } = await import("./commands/market.js");
1691
+ await marketUpdate(slugs && slugs.length > 0 ? slugs : undefined, opts);
1692
+ });
1693
+ market
1694
+ .command("installed")
1695
+ .description("List packages installed on this pod — a pure read, no writes (pairs with 'market update' to check drift)")
1696
+ .option("--outdated", "Only show packages with an update available")
1697
+ .option("--tree", "Show the composition graph — package → templates → resulting workspaces, marking shared nodes")
1698
+ .option("--layers", "Show the composition graph as a flat DAG — one row per slug, bedrock-first, with true fan-in counts")
1699
+ .option("--json", "Output as JSON")
1700
+ .action(async (_opts, cmd) => {
1701
+ // Same parent/child `--json` collision as `market install` — see its comment.
1702
+ const opts = cmd.optsWithGlobals();
1703
+ const { marketInstalled } = await import("./commands/market.js");
1704
+ await marketInstalled(opts);
1705
+ });
1706
+ // ─── capability ───────────────────────────────────────────────────────────────
1707
+ const capability = program
1708
+ .command("capability")
1709
+ .alias("cap")
1710
+ .description("The one capability-first root: list, add, enable, connect, show, run a capability pack");
1711
+ capability
1712
+ .command("list")
1713
+ .description("List capabilities — one row per pack, with status, connection, and verbs")
1714
+ .option("--json", "Output as JSON")
1715
+ .option("--workspace <id>", "Workspace context")
1716
+ .action(async (opts) => {
1717
+ const { capabilityList } = await import("./commands/capability.js");
1718
+ await capabilityList(opts);
1719
+ });
1720
+ capability
1721
+ .command("add [name]")
1722
+ .description("Install a capability from the catalog — omit the name to pick from a list")
1723
+ .option("--workspace <id>", "Workspace context")
1724
+ .action(async (name, opts) => {
1725
+ const { capabilityAdd } = await import("./commands/capability.js");
1726
+ await capabilityAdd(name, opts);
1727
+ });
1728
+ capability
1729
+ .command("create [file]")
1730
+ .description("Create a capability from a JSON definition (file path, or pipe JSON via stdin)")
1731
+ .option("--workspace <id>", "Workspace context")
1732
+ .action(async (file, opts) => {
1733
+ const { capabilityCreate } = await import("./commands/capability.js");
1734
+ await capabilityCreate(file, opts);
1735
+ });
1736
+ capability
1737
+ .command("rm <ids...>")
1738
+ .alias("remove")
1739
+ .description("Remove capability container(s) by id or name — member tools/skills untouched")
1740
+ .option("--workspace <id>", "Workspace context")
1741
+ .option("--force", "Skip the confirmation prompt")
1742
+ .action(async (ids, opts) => {
1743
+ const { capabilityRemove } = await import("./commands/capability.js");
1744
+ await capabilityRemove(ids, opts);
1745
+ });
1746
+ capability
1747
+ .command("enable [name]")
1748
+ .description("Turn on a capability — omit the name to pick from a list; ensures its connection, then pick which verbs it can do")
1749
+ .option("--workspace <id>", "Workspace context")
1750
+ .action(async (name, opts) => {
1751
+ const { capabilityEnable } = await import("./commands/capability.js");
1752
+ await capabilityEnable(name, opts);
1753
+ });
1754
+ capability
1755
+ .command("connect [name]")
1756
+ .description("Connect a service — omit the name to pick from connectable services")
1757
+ .option("--workspace <id>", "Workspace context")
1758
+ .action(async (name, opts) => {
1759
+ const { capabilityConnect } = await import("./commands/capability.js");
1760
+ await capabilityConnect(name, opts);
1761
+ });
1762
+ capability
1763
+ .command("disconnect <name>")
1764
+ .description("Disconnect a capability's service — accepts a capability name or a provider id")
1765
+ .option("--workspace <id>", "Workspace context")
1766
+ .option("--force", "Skip confirmation")
1767
+ .action(async (name, opts) => {
1768
+ const { capabilityDisconnect } = await import("./commands/capability.js");
1769
+ await capabilityDisconnect(name, opts);
1770
+ });
1771
+ capability
1772
+ .command("show <name>")
1773
+ .description("Show one capability's full detail: status, connection, verbs, next action")
1774
+ .option("--json", "Output as JSON")
1775
+ .option("--workspace <id>", "Workspace context")
1776
+ .action(async (name, opts) => {
1777
+ const { capabilityShow } = await import("./commands/capability.js");
1778
+ await capabilityShow(name, opts);
1779
+ });
1780
+ capability
1781
+ .command("run <verb> [params...]")
1782
+ .description("Launch a verb — pass inputs as `--key value` flags")
1783
+ .option("--workspace <id>", "Workspace context")
1784
+ .option("--connection <id>", "Run against a specific stored connection id")
1785
+ .option("--for <objId>", "Run against the connection bound to this context object id")
1786
+ .allowUnknownOption()
1787
+ .allowExcessArguments()
1788
+ .action(async (verb, params, opts) => {
1789
+ const { capabilityRun } = await import("./commands/capability.js");
1790
+ await capabilityRun(verb, params, opts);
1791
+ });
1792
+ capability
1793
+ .command("test <verb>")
1794
+ .description("Dry-run a verb (preview side effects without executing)")
1795
+ .option("--workspace <id>", "Workspace context")
1796
+ .action(async (verb, opts) => {
1797
+ const { capabilityTest } = await import("./commands/capability.js");
1798
+ await capabilityTest(verb, opts);
1799
+ });
1800
+ // ─── cap connections ──────────────────────────────────────────────────────────
1801
+ // Manage a capability's stored connections (credentials / OAuth accounts /
1802
+ // context bindings). Nested under `cap` — distinct from the top-level
1803
+ // `synap connections`, which shows agent-surface → pod wiring.
1804
+ const capConnections = capability
1805
+ .command("connections")
1806
+ .alias("conn")
1807
+ .description("Manage a capability's connections: list, add, update, rm");
1808
+ capConnections
1809
+ .command("list <capability>")
1810
+ .description("List a capability's connections (label, kind, default, context, id)")
1811
+ .option("--workspace <id>", "Workspace context")
1812
+ .action(async (capability, opts) => {
1813
+ const { capabilityConnectionsList } = await import("./commands/cap-connections.js");
1814
+ await capabilityConnectionsList(capability, opts);
1815
+ });
1816
+ capConnections
1817
+ .command("add <capability>")
1818
+ .description("Add a connection — prompts for label + masked value unless provided as flags")
1819
+ .option("--label <label>", "Connection label")
1820
+ .option("--value <value>", "Secret / credential value (else prompted, masked)")
1821
+ .option("--context-type <type>", "Context type this connection binds to")
1822
+ .option("--context-id <id>", "Context object id this connection binds to")
1823
+ .option("--account-hint <hint>", "Human-readable account hint (e.g. an email)")
1824
+ .option("--default", "Mark this connection as the capability's default")
1825
+ .option("--workspace <id>", "Workspace context")
1826
+ .action(async (capability, opts) => {
1827
+ const { capabilityConnectionsAdd } = await import("./commands/cap-connections.js");
1828
+ await capabilityConnectionsAdd(capability, opts);
1829
+ });
1830
+ capConnections
1831
+ .command("update <capability> <connectionId>")
1832
+ .description("Update a connection's fields; --rotate (or --value) rotates its secret")
1833
+ .option("--label <label>", "New connection label")
1834
+ .option("--value <value>", "New secret / credential value")
1835
+ .option("--rotate", "Prompt (masked) for a new secret value")
1836
+ .option("--context-type <type>", "New context type")
1837
+ .option("--context-id <id>", "New context object id")
1838
+ .option("--account-hint <hint>", "New account hint")
1839
+ .option("--default", "Mark this connection as the capability's default")
1840
+ .option("--workspace <id>", "Workspace context")
1841
+ .action(async (capability, connectionId, opts) => {
1842
+ const { capabilityConnectionsUpdate } = await import("./commands/cap-connections.js");
1843
+ await capabilityConnectionsUpdate(capability, connectionId, opts);
1844
+ });
1845
+ capConnections
1846
+ .command("rm <capability> <connectionId>")
1847
+ .alias("remove")
1848
+ .description("Remove a connection by id (confirms first)")
1849
+ .option("--workspace <id>", "Workspace context")
1850
+ .action(async (capability, connectionId, opts) => {
1851
+ const { capabilityConnectionsRemove } = await import("./commands/cap-connections.js");
1852
+ await capabilityConnectionsRemove(capability, connectionId, opts);
1853
+ });
1854
+ // ─── raycast ──────────────────────────────────────────────────────────────────
1855
+ const raycast = program
1856
+ .command("raycast")
1857
+ .description("Generate Raycast Script Commands from your enabled capabilities");
1858
+ raycast
1859
+ .command("generate")
1860
+ .description("Emit a Raycast Script Command per enabled runnable verb")
1861
+ .option("--out <dir>", "Output directory (default: ~/.synap/raycast-commands)")
1862
+ .option("--workspace <id>", "Workspace context")
1863
+ .action(async (opts) => {
1864
+ const { raycastGenerate } = await import("./commands/raycast.js");
1865
+ await raycastGenerate(opts);
1177
1866
  });
1178
1867
  // ─── providers ───────────────────────────────────────────────────────────────
1179
1868
  const providers = program
@@ -1210,5 +1899,32 @@ keys
1210
1899
  const { keysRotate } = await import("./commands/keys.js");
1211
1900
  await keysRotate({});
1212
1901
  });
1902
+ // Resolve a global `--pod <name>` before commander parses (it isn't registered
1903
+ // per-command). Fails fast with a clear message on an unknown profile name.
1904
+ try {
1905
+ bootstrapPodOverride(process.argv);
1906
+ }
1907
+ catch (err) {
1908
+ console.error(err instanceof Error ? err.message : String(err));
1909
+ process.exit(1);
1910
+ }
1911
+ // Last-resort net. Commander does not await async .action() handlers, so a
1912
+ // command that throws without its own catch becomes an unhandled rejection and
1913
+ // Node dumps a raw stack trace with dist/ paths at the user — e.g.
1914
+ // `synap digest --workspace <inaccessible>` printed the HubError constructor
1915
+ // frame. Render it through the one door instead. Commands that already catch
1916
+ // and render are unaffected: this only fires when nothing else handled it.
1917
+ process.on("unhandledRejection", (err) => {
1918
+ void (async () => {
1919
+ try {
1920
+ const { renderHubError } = await import("./lib/hub-client.js");
1921
+ renderHubError(err);
1922
+ }
1923
+ catch {
1924
+ console.error(err instanceof Error ? err.message : String(err));
1925
+ }
1926
+ process.exit(1);
1927
+ })();
1928
+ });
1213
1929
  program.parse();
1214
1930
  //# sourceMappingURL=index.js.map