@synap-core/cli 1.7.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 (371) 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.d.ts +47 -0
  5. package/dist/commands/agent-run.js +301 -0
  6. package/dist/commands/agent-run.js.map +1 -0
  7. package/dist/commands/agents.js +85 -46
  8. package/dist/commands/agents.js.map +1 -1
  9. package/dist/commands/artifact.d.ts +26 -0
  10. package/dist/commands/artifact.js +76 -0
  11. package/dist/commands/artifact.js.map +1 -0
  12. package/dist/commands/automation.d.ts +47 -0
  13. package/dist/commands/automation.js +601 -0
  14. package/dist/commands/automation.js.map +1 -0
  15. package/dist/commands/bridge-setup.d.ts +66 -0
  16. package/dist/commands/bridge-setup.js +1112 -0
  17. package/dist/commands/bridge-setup.js.map +1 -0
  18. package/dist/commands/cap-connections.d.ts +28 -0
  19. package/dist/commands/cap-connections.js +224 -0
  20. package/dist/commands/cap-connections.js.map +1 -0
  21. package/dist/commands/capability.d.ts +89 -0
  22. package/dist/commands/capability.js +1523 -0
  23. package/dist/commands/capability.js.map +1 -0
  24. package/dist/commands/cell.d.ts +55 -0
  25. package/dist/commands/cell.js +277 -0
  26. package/dist/commands/cell.js.map +1 -0
  27. package/dist/commands/centrality.d.ts +20 -0
  28. package/dist/commands/centrality.js +94 -0
  29. package/dist/commands/centrality.js.map +1 -0
  30. package/dist/commands/connect.d.ts +2 -0
  31. package/dist/commands/connect.js +25 -10
  32. package/dist/commands/connect.js.map +1 -1
  33. package/dist/commands/connections.js +0 -16
  34. package/dist/commands/connections.js.map +1 -1
  35. package/dist/commands/context.d.ts +22 -0
  36. package/dist/commands/context.js +149 -0
  37. package/dist/commands/context.js.map +1 -0
  38. package/dist/commands/data-extra.d.ts +14 -0
  39. package/dist/commands/data-extra.js +185 -0
  40. package/dist/commands/data-extra.js.map +1 -0
  41. package/dist/commands/data.d.ts +14 -10
  42. package/dist/commands/data.js +353 -192
  43. package/dist/commands/data.js.map +1 -1
  44. package/dist/commands/diagnose.d.ts +20 -0
  45. package/dist/commands/diagnose.js +143 -0
  46. package/dist/commands/diagnose.js.map +1 -0
  47. package/dist/commands/digest.d.ts +17 -0
  48. package/dist/commands/digest.js +121 -0
  49. package/dist/commands/digest.js.map +1 -0
  50. package/dist/commands/discover.d.ts +2 -0
  51. package/dist/commands/discover.js +25 -8
  52. package/dist/commands/discover.js.map +1 -1
  53. package/dist/commands/doc.d.ts +39 -0
  54. package/dist/commands/doc.js +130 -0
  55. package/dist/commands/doc.js.map +1 -0
  56. package/dist/commands/events.d.ts +26 -0
  57. package/dist/commands/events.js +69 -0
  58. package/dist/commands/events.js.map +1 -0
  59. package/dist/commands/explain.d.ts +21 -0
  60. package/dist/commands/explain.js +251 -0
  61. package/dist/commands/explain.js.map +1 -0
  62. package/dist/commands/facet.d.ts +29 -0
  63. package/dist/commands/facet.js +113 -0
  64. package/dist/commands/facet.js.map +1 -0
  65. package/dist/commands/graph.d.ts +18 -0
  66. package/dist/commands/graph.js +74 -0
  67. package/dist/commands/graph.js.map +1 -0
  68. package/dist/commands/home.d.ts +12 -0
  69. package/dist/commands/home.js +54 -0
  70. package/dist/commands/home.js.map +1 -0
  71. package/dist/commands/import.d.ts +38 -0
  72. package/dist/commands/import.js +440 -0
  73. package/dist/commands/import.js.map +1 -0
  74. package/dist/commands/init.d.ts +0 -2
  75. package/dist/commands/init.js +97 -118
  76. package/dist/commands/init.js.map +1 -1
  77. package/dist/commands/keys.d.ts +9 -0
  78. package/dist/commands/keys.js +78 -0
  79. package/dist/commands/keys.js.map +1 -0
  80. package/dist/commands/knowledge.d.ts +34 -18
  81. package/dist/commands/knowledge.js +355 -57
  82. package/dist/commands/knowledge.js.map +1 -1
  83. package/dist/commands/launch.d.ts +50 -0
  84. package/dist/commands/launch.js +790 -0
  85. package/dist/commands/launch.js.map +1 -0
  86. package/dist/commands/lens.d.ts +45 -0
  87. package/dist/commands/lens.js +386 -0
  88. package/dist/commands/lens.js.map +1 -0
  89. package/dist/commands/market.d.ts +209 -0
  90. package/dist/commands/market.js +1368 -0
  91. package/dist/commands/market.js.map +1 -0
  92. package/dist/commands/mcp.d.ts +42 -0
  93. package/dist/commands/mcp.js +184 -0
  94. package/dist/commands/mcp.js.map +1 -0
  95. package/dist/commands/observe.d.ts +9 -0
  96. package/dist/commands/observe.js +93 -0
  97. package/dist/commands/observe.js.map +1 -0
  98. package/dist/commands/open.d.ts +32 -0
  99. package/dist/commands/open.js +85 -0
  100. package/dist/commands/open.js.map +1 -0
  101. package/dist/commands/pod.d.ts +100 -0
  102. package/dist/commands/pod.js +359 -0
  103. package/dist/commands/pod.js.map +1 -0
  104. package/dist/commands/pods.d.ts +6 -0
  105. package/dist/commands/pods.js +160 -50
  106. package/dist/commands/pods.js.map +1 -1
  107. package/dist/commands/proposals-actions.d.ts +7 -0
  108. package/dist/commands/proposals-actions.js +77 -0
  109. package/dist/commands/proposals-actions.js.map +1 -0
  110. package/dist/commands/providers.d.ts +38 -0
  111. package/dist/commands/providers.js +170 -0
  112. package/dist/commands/providers.js.map +1 -0
  113. package/dist/commands/purge.d.ts +23 -0
  114. package/dist/commands/purge.js +148 -0
  115. package/dist/commands/purge.js.map +1 -0
  116. package/dist/commands/raycast.d.ts +15 -0
  117. package/dist/commands/raycast.js +153 -0
  118. package/dist/commands/raycast.js.map +1 -0
  119. package/dist/commands/sessions.d.ts +31 -0
  120. package/dist/commands/sessions.js +248 -0
  121. package/dist/commands/sessions.js.map +1 -0
  122. package/dist/commands/skill-manage.d.ts +21 -0
  123. package/dist/commands/skill-manage.js +195 -0
  124. package/dist/commands/skill-manage.js.map +1 -0
  125. package/dist/commands/skills-commands.d.ts +26 -0
  126. package/dist/commands/skills-commands.js +187 -0
  127. package/dist/commands/skills-commands.js.map +1 -0
  128. package/dist/commands/skills.d.ts +26 -0
  129. package/dist/commands/skills.js +196 -0
  130. package/dist/commands/skills.js.map +1 -0
  131. package/dist/commands/status.d.ts +3 -1
  132. package/dist/commands/status.js +231 -41
  133. package/dist/commands/status.js.map +1 -1
  134. package/dist/commands/statusline.d.ts +24 -0
  135. package/dist/commands/statusline.js +450 -0
  136. package/dist/commands/statusline.js.map +1 -0
  137. package/dist/commands/subscribe.d.ts +19 -0
  138. package/dist/commands/subscribe.js +91 -0
  139. package/dist/commands/subscribe.js.map +1 -0
  140. package/dist/commands/tools.d.ts +30 -0
  141. package/dist/commands/tools.js +315 -0
  142. package/dist/commands/tools.js.map +1 -0
  143. package/dist/commands/versions.d.ts +27 -0
  144. package/dist/commands/versions.js +277 -0
  145. package/dist/commands/versions.js.map +1 -0
  146. package/dist/commands/view.d.ts +57 -0
  147. package/dist/commands/view.js +195 -0
  148. package/dist/commands/view.js.map +1 -0
  149. package/dist/commands/whoami.d.ts +21 -0
  150. package/dist/commands/whoami.js +129 -0
  151. package/dist/commands/whoami.js.map +1 -0
  152. package/dist/index.d.ts +3 -4
  153. package/dist/index.js +1524 -202
  154. package/dist/index.js.map +1 -1
  155. package/dist/lib/agent-templates.d.ts +25 -0
  156. package/dist/lib/agent-templates.js +148 -0
  157. package/dist/lib/agent-templates.js.map +1 -0
  158. package/dist/lib/agents-config.d.ts +4 -1
  159. package/dist/lib/agents-config.js +19 -2
  160. package/dist/lib/agents-config.js.map +1 -1
  161. package/dist/lib/approval-poll.d.ts +42 -0
  162. package/dist/lib/approval-poll.js +52 -0
  163. package/dist/lib/approval-poll.js.map +1 -0
  164. package/dist/lib/auth.d.ts +29 -6
  165. package/dist/lib/auth.js +105 -94
  166. package/dist/lib/auth.js.map +1 -1
  167. package/dist/lib/bundle-version.d.ts +11 -0
  168. package/dist/lib/bundle-version.js +33 -0
  169. package/dist/lib/bundle-version.js.map +1 -0
  170. package/dist/lib/capture-lane.d.ts +67 -0
  171. package/dist/lib/capture-lane.js +136 -0
  172. package/dist/lib/capture-lane.js.map +1 -0
  173. package/dist/lib/cp-packages.d.ts +121 -0
  174. package/dist/lib/cp-packages.js +218 -0
  175. package/dist/lib/cp-packages.js.map +1 -0
  176. package/dist/lib/describe-lens.d.ts +46 -0
  177. package/dist/lib/describe-lens.js +33 -0
  178. package/dist/lib/describe-lens.js.map +1 -0
  179. package/dist/lib/hub-client.d.ts +84 -1
  180. package/dist/lib/hub-client.js +502 -22
  181. package/dist/lib/hub-client.js.map +1 -1
  182. package/dist/lib/installed.d.ts +51 -0
  183. package/dist/lib/installed.js +70 -0
  184. package/dist/lib/installed.js.map +1 -0
  185. package/dist/lib/next-steps.d.ts +61 -0
  186. package/dist/lib/next-steps.js +146 -0
  187. package/dist/lib/next-steps.js.map +1 -0
  188. package/dist/lib/pod.d.ts +104 -19
  189. package/dist/lib/pod.js +245 -57
  190. package/dist/lib/pod.js.map +1 -1
  191. package/dist/lib/project-ref.d.ts +95 -0
  192. package/dist/lib/project-ref.js +144 -0
  193. package/dist/lib/project-ref.js.map +1 -0
  194. package/dist/lib/project.d.ts +35 -0
  195. package/dist/lib/project.js +39 -0
  196. package/dist/lib/project.js.map +1 -0
  197. package/dist/lib/session-lens.d.ts +33 -0
  198. package/dist/lib/session-lens.js +76 -0
  199. package/dist/lib/session-lens.js.map +1 -0
  200. package/dist/lib/skill-import.d.ts +40 -0
  201. package/dist/lib/skill-import.js +203 -0
  202. package/dist/lib/skill-import.js.map +1 -0
  203. package/dist/lib/skills-installer.d.ts +16 -5
  204. package/dist/lib/skills-installer.js +132 -18
  205. package/dist/lib/skills-installer.js.map +1 -1
  206. package/dist/lib/suite.d.ts +28 -0
  207. package/dist/lib/suite.js +29 -0
  208. package/dist/lib/suite.js.map +1 -0
  209. package/dist/lib/superwhisper-import.d.ts +40 -0
  210. package/dist/lib/superwhisper-import.js +389 -0
  211. package/dist/lib/superwhisper-import.js.map +1 -0
  212. package/dist/lib/targets.d.ts +66 -2
  213. package/dist/lib/targets.js +914 -132
  214. package/dist/lib/targets.js.map +1 -1
  215. package/dist/lib/unwrapList.d.ts +1 -0
  216. package/dist/lib/unwrapList.js +20 -0
  217. package/dist/lib/unwrapList.js.map +1 -0
  218. package/dist/utils/logger.d.ts +2 -0
  219. package/dist/utils/logger.js +10 -2
  220. package/dist/utils/logger.js.map +1 -1
  221. package/package.json +10 -4
  222. package/skills/agent-os/SKILL.md +212 -0
  223. package/skills/manifest.json +5 -0
  224. package/skills/onboard/SKILL.md +186 -0
  225. package/skills/synap/SKILL.md +1524 -104
  226. package/skills/synap/_order.txt +37 -0
  227. package/skills/synap/_skill.yaml +24 -0
  228. package/skills/synap/authentication.md +10 -0
  229. package/skills/synap/automations.md +264 -0
  230. package/skills/synap/capabilities.md +107 -0
  231. package/skills/synap/capture.md +10 -0
  232. package/skills/synap/cli-operations.md +107 -0
  233. package/skills/synap/common-mistakes.md +12 -0
  234. package/skills/synap/creative-loop.md +43 -0
  235. package/skills/synap/crm.md +117 -0
  236. package/skills/synap/diagnostics.md +35 -0
  237. package/skills/synap/digesting-a-channel.md +38 -0
  238. package/skills/synap/document-embeds.md +123 -0
  239. package/skills/synap/escalation-ladder.md +71 -0
  240. package/skills/synap/focus-sessions.md +47 -0
  241. package/skills/synap/governance-rules.md +64 -0
  242. package/skills/synap/governance.md +6 -6
  243. package/skills/synap/graph-gardening.md +21 -0
  244. package/skills/synap/inline-patterns.md +38 -0
  245. package/skills/synap/lenses.md +38 -0
  246. package/skills/synap/linking-principle.md +39 -0
  247. package/skills/synap/linking.md +1 -0
  248. package/skills/synap/mental-model.md +45 -0
  249. package/skills/synap/more.md +7 -0
  250. package/skills/synap/multi-entity-capture.md +10 -0
  251. package/skills/synap/next-action.md +37 -0
  252. package/skills/synap/north-star.md +17 -0
  253. package/skills/synap/operating-mode-rules.md +45 -0
  254. package/skills/synap/operating-mode.md +9 -0
  255. package/skills/synap/quick-reference.md +67 -0
  256. package/skills/synap/reading.md +43 -0
  257. package/skills/synap/recap.md +21 -0
  258. package/skills/synap/reflexes.md +46 -0
  259. package/skills/synap/response-style.md +21 -0
  260. package/skills/synap/scope.md +13 -0
  261. package/skills/synap/showing.md +17 -0
  262. package/skills/synap/user-model.md +25 -0
  263. package/skills/synap/viewframe-cells.md +290 -0
  264. package/skills/synap/work-flow.md +113 -0
  265. package/skills/synap/worked-examples.md +53 -0
  266. package/skills/synap/workspace-design.md +45 -0
  267. package/skills/synap/workspace-edges.md +49 -0
  268. package/skills/synap/writes.md +156 -0
  269. package/skills/synap-schema/SKILL.md +97 -6
  270. package/skills/synap-schema/_order.txt +13 -0
  271. package/skills/synap-schema/_skill.yaml +22 -0
  272. package/skills/synap-schema/before-you-touch.md +14 -0
  273. package/skills/synap-schema/common-mistakes.md +9 -0
  274. package/skills/synap-schema/creating-profiles.md +17 -0
  275. package/skills/synap-schema/discover-profiles.md +24 -0
  276. package/skills/synap-schema/entity-scope.md +8 -0
  277. package/skills/synap-schema/extend-vs-create.md +31 -0
  278. package/skills/synap-schema/more.md +6 -0
  279. package/skills/synap-schema/overlay-properties.md +22 -0
  280. package/skills/synap-schema/profiles.md +3 -0
  281. package/skills/synap-schema/property-defs.md +29 -0
  282. package/skills/synap-schema/read-before-write.md +50 -0
  283. package/skills/synap-schema/relations.md +18 -0
  284. package/skills/synap-schema/worked-example.md +30 -0
  285. package/skills/synap-ui/SKILL.md +38 -11
  286. package/skills/synap-ui/_order.txt +13 -0
  287. package/skills/synap-ui/_skill.yaml +23 -0
  288. package/skills/synap-ui/ai-companion.md +27 -0
  289. package/skills/synap-ui/arranging-bento.md +8 -0
  290. package/skills/synap-ui/before-you-build.md +20 -0
  291. package/skills/synap-ui/bento-layouts.md +35 -0
  292. package/skills/synap-ui/common-mistakes.md +10 -0
  293. package/skills/synap-ui/creating-views.md +26 -0
  294. package/skills/synap-ui/four-builds.md +24 -0
  295. package/skills/synap-ui/more.md +7 -0
  296. package/skills/synap-ui/proposing-vs-extending.md +11 -0
  297. package/skills/synap-ui/view-list.md +24 -0
  298. package/skills/synap-ui/views.md +3 -0
  299. package/skills/synap-ui/worked-example.md +18 -0
  300. package/skills/synap-ui/workspaces.md +47 -0
  301. package/templates/automations/bookmark-enrichment.automation.json +44 -0
  302. package/templates/automations/mail-feed.automation.json +86 -0
  303. package/templates/automations/url-bookmark-capture.automation.json +70 -0
  304. package/templates/skills/README.md +21 -0
  305. package/templates/skills/authoring-automations/SKILL.md +95 -0
  306. package/templates/skills/authoring-automations/reference/node-matrix.md +49 -0
  307. package/templates/skills/authoring-capabilities/SKILL.md +93 -0
  308. package/templates/skills/authoring-capabilities/reference/template-anatomy.md +70 -0
  309. package/templates/skills/authoring-playbooks/SKILL.md +102 -0
  310. package/templates/skills/authoring-playbooks/reference/stages-contract.md +35 -0
  311. package/templates/skills/authoring-playbooks/reference/worked-example.md +64 -0
  312. package/templates/skills/bookmark-enrichment/SKILL.md +40 -0
  313. package/templates/skills/coordinating-agents/SKILL.md +32 -0
  314. package/templates/skills/coordinating-branches/SKILL.md +27 -0
  315. package/templates/skills/mapping-the-server/SKILL.md +54 -0
  316. package/templates/skills/reading-client-progress/SKILL.md +65 -0
  317. package/templates/skills/routing-to-channels/SKILL.md +54 -0
  318. package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-CHEATSHEET.md +133 -0
  319. package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-ONBOARDING-GUIDE.md +761 -0
  320. package/templates/skills/stellar-scf-grants-advisor/CLIENT-FAQ.md +181 -0
  321. package/templates/skills/stellar-scf-grants-advisor/PARTNER-HANDOVER.md +130 -0
  322. package/templates/skills/stellar-scf-grants-advisor/SKILL.md +102 -0
  323. package/templates/skills/stellar-scf-grants-advisor/examples/README.md +43 -0
  324. package/templates/skills/stellar-scf-grants-advisor/examples/chat-summary-templates.md +158 -0
  325. package/templates/skills/stellar-scf-grants-advisor/examples/corpus-comparable-rows.md +136 -0
  326. package/templates/skills/stellar-scf-grants-advisor/examples/q10-team-rewrites.md +109 -0
  327. package/templates/skills/stellar-scf-grants-advisor/examples/q2-description-rewrites.md +88 -0
  328. package/templates/skills/stellar-scf-grants-advisor/examples/q6-integration-rewrites.md +107 -0
  329. package/templates/skills/stellar-scf-grants-advisor/examples/tranche-structures.md +176 -0
  330. package/templates/skills/stellar-scf-grants-advisor/reference/01-methodology.md +96 -0
  331. package/templates/skills/stellar-scf-grants-advisor/reference/02-scoring-framework.md +199 -0
  332. package/templates/skills/stellar-scf-grants-advisor/reference/03-rejection-patterns.md +241 -0
  333. package/templates/skills/stellar-scf-grants-advisor/reference/04-winner-patterns.md +120 -0
  334. package/templates/skills/stellar-scf-grants-advisor/reference/05-comeback-patterns.md +92 -0
  335. package/templates/skills/stellar-scf-grants-advisor/reference/06-budget-benchmarks.md +125 -0
  336. package/templates/skills/stellar-scf-grants-advisor/reference/07-integration-list.md +147 -0
  337. package/templates/skills/stellar-scf-grants-advisor/reference/08-abstract-fields.md +258 -0
  338. package/templates/skills/stellar-scf-grants-advisor/reference/09-build-fields.md +259 -0
  339. package/templates/skills/stellar-scf-grants-advisor/reference/10-corpus-winners.md +135 -0
  340. package/templates/skills/stellar-scf-grants-advisor/reference/11-corpus-rejects.md +267 -0
  341. package/templates/skills/stellar-scf-grants-advisor/reference/12-client-communication.md +131 -0
  342. package/templates/skills/stellar-scf-grants-advisor/reference/13-excel-output-spec.md +199 -0
  343. package/templates/skills/stellar-scf-grants-advisor/reference/14-worked-examples.md +160 -0
  344. package/templates/skills/stellar-scf-grants-advisor/templates/abstract-review-builder.py +253 -0
  345. package/templates/skills/stellar-scf-grants-advisor/templates/build-review-builder.py +213 -0
  346. package/dist/commands/finish.d.ts +0 -25
  347. package/dist/commands/finish.js +0 -274
  348. package/dist/commands/finish.js.map +0 -1
  349. package/dist/commands/openclaw.d.ts +0 -40
  350. package/dist/commands/openclaw.js +0 -1148
  351. package/dist/commands/openclaw.js.map +0 -1
  352. package/dist/commands/security-audit.d.ts +0 -12
  353. package/dist/commands/security-audit.js +0 -100
  354. package/dist/commands/security-audit.js.map +0 -1
  355. package/dist/lib/hardening.d.ts +0 -18
  356. package/dist/lib/hardening.js +0 -214
  357. package/dist/lib/hardening.js.map +0 -1
  358. package/dist/lib/templates.d.ts +0 -11
  359. package/dist/lib/templates.js +0 -13
  360. package/dist/lib/templates.js.map +0 -1
  361. package/dist/templates/agent-os.json +0 -3090
  362. package/node_modules/@synap/hub-rest-client/dist/index.cjs +0 -881
  363. package/node_modules/@synap/hub-rest-client/dist/index.d.cts +0 -907
  364. package/node_modules/@synap/hub-rest-client/dist/index.d.ts +0 -907
  365. package/node_modules/@synap/hub-rest-client/dist/index.js +0 -851
  366. package/node_modules/@synap/hub-rest-client/package.json +0 -45
  367. package/node_modules/@synap/hub-rest-client/src/client.ts +0 -1143
  368. package/node_modules/@synap/hub-rest-client/src/errors.ts +0 -30
  369. package/node_modules/@synap/hub-rest-client/src/index.ts +0 -111
  370. package/node_modules/@synap/hub-rest-client/src/setup.ts +0 -77
  371. package/node_modules/@synap/hub-rest-client/src/types.ts +0 -639
@@ -0,0 +1,78 @@
1
+ /**
2
+ * synap keys — Manage pod API keys
3
+ *
4
+ * Subcommands: rotate
5
+ */
6
+ import chalk from "chalk";
7
+ import ora from "ora";
8
+ import fs from "node:fs";
9
+ import path from "node:path";
10
+ import os from "node:os";
11
+ import { resolveHubConfig, hubPost, HubError, renderHubError } from "../lib/hub-client.js";
12
+ import { log } from "../utils/logger.js";
13
+ // ── Helpers ───────────────────────────────────────────────────────────────────
14
+ const CONFIG_FILE = path.join(os.homedir(), ".synap", "config.json");
15
+ function updateConfigKey(newApiKey) {
16
+ const raw = fs.readFileSync(CONFIG_FILE, "utf-8");
17
+ const config = JSON.parse(raw);
18
+ const activePod = config.activePod;
19
+ const pods = config.pods;
20
+ if (activePod && pods && pods[activePod]) {
21
+ pods[activePod].hubApiKey = newApiKey;
22
+ config.pods = pods;
23
+ }
24
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
25
+ }
26
+ export async function keysRotate(opts) {
27
+ let cfg;
28
+ try {
29
+ cfg = await resolveHubConfig({ podUrl: opts.podUrl });
30
+ }
31
+ catch (err) {
32
+ log.error(err.message);
33
+ process.exit(1);
34
+ }
35
+ const spinner = ora({ text: "Rotating CLI key…", color: "cyan" }).start();
36
+ let result;
37
+ try {
38
+ result = (await hubPost("/keys/rotate-cli", {}, cfg));
39
+ spinner.succeed(chalk.green("Key rotated"));
40
+ }
41
+ catch (err) {
42
+ spinner.fail(chalk.red("Failed to rotate key"));
43
+ if (err instanceof HubError && (err.status === 401 || err.status === 403)) {
44
+ log.error("The current key is already invalid (401/403).");
45
+ log.dim("Run `synap init` to fully re-provision your credentials.");
46
+ }
47
+ else {
48
+ renderHubError(err);
49
+ }
50
+ process.exit(1);
51
+ }
52
+ // Update config file and current process env
53
+ try {
54
+ updateConfigKey(result.apiKey);
55
+ }
56
+ catch (err) {
57
+ log.warn(`Key rotated but could not update config file: ${err.message}`);
58
+ log.dim(`Set it manually: SYNAP_HUB_API_KEY=${result.apiKey}`);
59
+ }
60
+ process.env.SYNAP_HUB_API_KEY = result.apiKey;
61
+ // Print scope table
62
+ console.log();
63
+ log.heading("New key details");
64
+ console.log();
65
+ console.log(` ${chalk.dim("Key ID:")} ${result.keyId}`);
66
+ console.log();
67
+ if (result.scopes && result.scopes.length > 0) {
68
+ console.log(` ${chalk.dim("Scopes:")}`);
69
+ for (const scope of result.scopes) {
70
+ console.log(` ${chalk.green("✓")} ${scope}`);
71
+ }
72
+ }
73
+ else {
74
+ console.log(` ${chalk.dim("Scopes: (none returned)")}`);
75
+ }
76
+ console.log();
77
+ }
78
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/commands/keys.ts"],"names":[],"mappings":"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"}
@@ -1,36 +1,52 @@
1
1
  /**
2
- * synap capture / synap recall --structured
2
+ * synap capture — the one canonical structured-WRITE verb.
3
3
  *
4
- * Structured knowledge capture and retrieval using the engineering_knowledge
5
- * entity profile. Backed by Hub Protocol entity endpoints — separate from the
6
- * episodic /memory endpoints used by `synap remember` / `synap recall`.
4
+ * SMART MODE (no --type): `synap capture "free text"`
5
+ * → POST /capture/structure (AI pipeline: proposals + relations + followUp)
6
+ * → renders a proposal table, prompts y/N, then POST /capture/execute.
7
+ *
8
+ * TYPED MODE (--type): `synap capture --type gotcha --claim "…" [--why] [--evidence] [--tags]`
9
+ * → POST /entities as a typed `knowledge` entity; `ek_type` (gotcha|lesson|decision|
10
+ * reference) discriminates the kind — ONE store, type tags (the canonical pattern,
11
+ * NOT a residual dump). The workspace lens supplies the domain (no
12
+ * `engineering_knowledge`). A formal decision RECORD (rationale/alternatives/status
13
+ * lifecycle) comes from smart `capture "<text>"` or `create entity --profile=decision`.
14
+ *
15
+ * Workspace routing: --workspace > --team (first product ws) > memory ws (default,
16
+ * auto-approved, agent-private) > active ws.
7
17
  */
8
- interface BaseOpts {
9
- podUrl?: string;
10
- apiKey?: string;
11
- }
12
18
  export type KnowledgeType = "gotcha" | "lesson" | "decision" | "reference";
13
19
  export interface CaptureOpts {
14
- type: KnowledgeType;
15
- claim: string;
20
+ /** Smart mode: positional free-text (no --type). When present, uses AI /capture/structure pipeline. */
21
+ text?: string;
22
+ /** Typed mode: one of gotcha|lesson|decision|reference */
23
+ type?: KnowledgeType;
24
+ claim?: string;
16
25
  why?: string;
17
26
  evidence?: string;
18
27
  tags?: string;
19
- json?: boolean;
20
- }
21
- export interface RecallStructuredOpts extends BaseOpts {
22
- type?: KnowledgeType;
23
- tags?: string;
24
- limit?: string;
28
+ /** Override to first product workspace instead of the active workspace */
29
+ team?: boolean;
30
+ /** Explicit workspace override — highest priority */
25
31
  workspace?: string;
32
+ /**
33
+ * GLOBAL lane: write a pod-wide procedural runbook to `knowledge_keys`
34
+ * (cross-cutting best-practice/how-to, visible in every workspace) instead of
35
+ * a domain `knowledge` entity in the active workspace.
36
+ */
37
+ global?: boolean;
38
+ /** Optional stable key (namespace:slug) for a --global runbook; derived if absent. */
39
+ key?: string;
26
40
  json?: boolean;
41
+ /** Skip the y/N confirmation prompt (smart mode only) */
42
+ yes?: boolean;
43
+ /** Link the captured knowledge to the active session */
44
+ session?: boolean;
27
45
  }
28
46
  export declare function captureKnowledge(opts: CaptureOpts): Promise<void>;
29
- export declare function recallStructured(query: string, opts: RecallStructuredOpts): Promise<void>;
30
47
  export declare function provisionAgentWorkspace(opts: {
31
48
  agentUserId?: string;
32
49
  name?: string;
33
50
  use?: boolean;
34
51
  json?: boolean;
35
52
  }): Promise<void>;
36
- export {};
@@ -1,33 +1,344 @@
1
1
  /**
2
- * synap capture / synap recall --structured
2
+ * synap capture — the one canonical structured-WRITE verb.
3
3
  *
4
- * Structured knowledge capture and retrieval using the engineering_knowledge
5
- * entity profile. Backed by Hub Protocol entity endpoints — separate from the
6
- * episodic /memory endpoints used by `synap remember` / `synap recall`.
4
+ * SMART MODE (no --type): `synap capture "free text"`
5
+ * → POST /capture/structure (AI pipeline: proposals + relations + followUp)
6
+ * → renders a proposal table, prompts y/N, then POST /capture/execute.
7
+ *
8
+ * TYPED MODE (--type): `synap capture --type gotcha --claim "…" [--why] [--evidence] [--tags]`
9
+ * → POST /entities as a typed `knowledge` entity; `ek_type` (gotcha|lesson|decision|
10
+ * reference) discriminates the kind — ONE store, type tags (the canonical pattern,
11
+ * NOT a residual dump). The workspace lens supplies the domain (no
12
+ * `engineering_knowledge`). A formal decision RECORD (rationale/alternatives/status
13
+ * lifecycle) comes from smart `capture "<text>"` or `create entity --profile=decision`.
14
+ *
15
+ * Workspace routing: --workspace > --team (first product ws) > memory ws (default,
16
+ * auto-approved, agent-private) > active ws.
7
17
  */
8
18
  import chalk from "chalk";
19
+ import * as readline from "node:readline/promises";
20
+ import { stdin as input, stdout as output } from "node:process";
9
21
  import { log } from "../utils/logger.js";
10
- import { resolveHubConfig, resolveUserId, hubPost, hubGet, } from "../lib/hub-client.js";
22
+ import { resolveHubConfig, resolveUserId, hubPost, readActiveSessionId, renderHubError, } from "../lib/hub-client.js";
23
+ import { getAgentWorkspaceRouting } from "../lib/pod.js";
24
+ import { laneFromSource, resolveWorkspaceName, formatLaneLine, laneJsonFields, } from "../lib/capture-lane.js";
25
+ /**
26
+ * Resolve the workspace for a DOMAIN capture (the `knowledge` entity, the Work
27
+ * lane). Knowledge is workspace-scoped, so the destination IS the separation:
28
+ * a Builder lesson stays in Builder, a marketing one in marketing.
29
+ *
30
+ * Priority: --workspace > --team (first product ws) > active ws.
31
+ *
32
+ * NOTE: the agent-memory ("AI-self") lane was removed — the AI no longer dumps
33
+ * captures into a private agent workspace. Everything it learns routes to a real
34
+ * lane: Work (here), Global (`--global` → knowledge_keys), or User
35
+ * (`record_observation` → user_observation). The per-adjunct memory workspace is
36
+ * being decommissioned.
37
+ */
38
+ async function resolveKnowledgeWorkspace(opts, _cfg, activeWorkspaceId) {
39
+ if (opts.workspace) {
40
+ return { workspaceId: opts.workspace, source: "explicit" };
41
+ }
42
+ if (opts.team) {
43
+ const routing = getAgentWorkspaceRouting();
44
+ const teamWs = routing?.productWorkspaceIds?.[0];
45
+ return { workspaceId: teamWs ?? activeWorkspaceId, source: teamWs ? "team" : "active (no team workspace configured)" };
46
+ }
47
+ return {
48
+ workspaceId: activeWorkspaceId,
49
+ source: activeWorkspaceId ? "active" : "active (run `synap use <id>` to set a workspace)",
50
+ };
51
+ }
52
+ /** Slugify free text into a knowledge_keys slug fragment. */
53
+ function slugify(text) {
54
+ return text
55
+ .toLowerCase()
56
+ .replace(/[^a-z0-9]+/g, "-")
57
+ .replace(/^-+|-+$/g, "")
58
+ .slice(0, 80) || "entry";
59
+ }
60
+ /**
61
+ * GLOBAL lane: write a pod-wide procedural runbook to `knowledge_keys`.
62
+ * Cross-cutting best-practice/how-to, addressed by a stable `namespace:slug` key
63
+ * and visible in every workspace (pod-wide). The kind (gotcha/lesson/decision/
64
+ * reference) becomes the namespace; the claim derives the slug unless --key given.
65
+ */
66
+ async function captureGlobalRunbook(opts, cfg, authorUserId) {
67
+ const type = opts.type ?? "reference";
68
+ const claim = opts.claim ?? opts.text ?? "";
69
+ const key = opts.key ?? `${type}:${slugify(claim)}`;
70
+ const [namespace, ...slugParts] = key.split(":");
71
+ const slug = slugParts.join(":") || slugify(claim);
72
+ const valueParts = [claim];
73
+ if (opts.why)
74
+ valueParts.push(`\n**Why:** ${opts.why}`);
75
+ if (opts.evidence)
76
+ valueParts.push(`\n**Evidence:** ${opts.evidence}`);
77
+ if (opts.tags)
78
+ valueParts.push(`\n_tags: ${opts.tags}_`);
79
+ const res = await hubPost("/knowledge", {
80
+ key,
81
+ namespace,
82
+ slug,
83
+ value: valueParts.join("\n"),
84
+ author: authorUserId,
85
+ // workspaceId omitted → pod-wide (null). The Global lane is, by definition,
86
+ // cross-workspace. (Workspace-scoped knowledge_keys await a backend fix —
87
+ // POST /knowledge currently drops workspaceId; domain knowledge uses the
88
+ // `knowledge` entity instead, which IS workspace-scoped.)
89
+ }, cfg);
90
+ const report = {
91
+ lane: "global",
92
+ workspaceId: undefined,
93
+ workspaceName: "pod-wide",
94
+ governance: "auto",
95
+ };
96
+ if (opts.json) {
97
+ console.log(JSON.stringify({ key, id: res.id, stored: true, ...laneJsonFields(report) }, null, 2));
98
+ return;
99
+ }
100
+ log.success(`[${type}] ${claim.slice(0, 80)}`);
101
+ log.dim(` key: ${key}`);
102
+ console.log(" " + formatLaneLine(report));
103
+ }
104
+ /** Render the /capture/structure result as a compact human-readable summary. */
105
+ function renderStructureResult(result) {
106
+ const { proposals, relations, followUp, degraded } = result;
107
+ if (degraded) {
108
+ log.warn("AI structuring unavailable — degraded fallback.");
109
+ }
110
+ if (proposals.length === 0) {
111
+ log.dim("No entity proposals extracted.");
112
+ return;
113
+ }
114
+ log.heading("Proposed entities");
115
+ // Column widths
116
+ const typeW = Math.min(18, Math.max(6, ...proposals.map((p) => p.profileSlug.length)));
117
+ const titleW = Math.min(48, Math.max(10, ...proposals.map((p) => p.title.length)));
118
+ const header = [
119
+ chalk.bold("#".padEnd(3)),
120
+ chalk.bold("Type".padEnd(typeW)),
121
+ chalk.bold("Title".padEnd(titleW)),
122
+ ].join(" ");
123
+ console.log(" " + header);
124
+ console.log(" " + chalk.dim("-".repeat(3 + 2 + typeW + 2 + titleW)));
125
+ for (let i = 0; i < proposals.length; i++) {
126
+ const p = proposals[i];
127
+ const row = [
128
+ chalk.dim(String(i + 1).padEnd(3)),
129
+ chalk.cyan(p.profileSlug.slice(0, typeW).padEnd(typeW)),
130
+ p.title.slice(0, titleW).padEnd(titleW),
131
+ ].join(" ");
132
+ console.log(" " + row);
133
+ if (p.description) {
134
+ log.dim(` ${p.description.slice(0, 80)}`);
135
+ }
136
+ }
137
+ if (relations.length > 0) {
138
+ log.blank();
139
+ log.dim(` ${relations.length} relation${relations.length !== 1 ? "s" : ""} will be created.`);
140
+ }
141
+ if (result.targetWorkspaceId || result.targetProjectId) {
142
+ log.blank();
143
+ if (result.targetWorkspaceId) {
144
+ const conf = typeof result.targetWorkspaceConfidence === "number"
145
+ ? ` (${Math.round(result.targetWorkspaceConfidence * 100)}%)`
146
+ : "";
147
+ log.dim(` → workspace: ${result.targetWorkspaceId}${conf}`);
148
+ if (result.targetWorkspaceReason) {
149
+ log.dim(` ${result.targetWorkspaceReason.slice(0, 90)}`);
150
+ }
151
+ }
152
+ if (result.targetProjectId) {
153
+ const conf = typeof result.targetProjectConfidence === "number"
154
+ ? ` (${Math.round(result.targetProjectConfidence * 100)}%)`
155
+ : "";
156
+ log.dim(` → project: ${result.targetProjectId}${conf}`);
157
+ if (result.targetProjectReason) {
158
+ log.dim(` ${result.targetProjectReason.slice(0, 90)}`);
159
+ }
160
+ }
161
+ }
162
+ // followUp may be a bare string (previously dropped — the `.question` guard
163
+ // never matched) or a { question, suggestions[] } object (chips previously
164
+ // rendered as "[object Object]"). Handle both; render each chip by its label.
165
+ if (followUp) {
166
+ const question = typeof followUp === "string" ? followUp : followUp.question;
167
+ if (question) {
168
+ log.blank();
169
+ log.info(`Follow-up: ${question}`);
170
+ const chips = typeof followUp === "string" ? [] : followUp.suggestions ?? [];
171
+ for (const c of chips) {
172
+ log.dim(` · ${c.label ?? c.value}`);
173
+ }
174
+ }
175
+ }
176
+ }
177
+ async function runSmartCapture(text, opts) {
178
+ const cfg = await resolveHubConfig();
179
+ const userId = await resolveUserId(cfg);
180
+ const { workspaceId, source } = await resolveKnowledgeWorkspace(opts, cfg, cfg.workspaceId);
181
+ if (!workspaceId) {
182
+ console.error(chalk.red("No workspace set. Run:\n" +
183
+ " synap connect (sets up memory + team workspace routing)\n" +
184
+ " synap use <workspace-id> (manual override)"));
185
+ process.exit(1);
186
+ }
187
+ // 1. Structure
188
+ const smartSessionId = opts.session ? readActiveSessionId() : undefined;
189
+ const structureBody = { userId, text, workspaceId, ...(smartSessionId ? { sessionId: smartSessionId } : {}) };
190
+ const structureRes = await hubPost("/capture/structure", structureBody, cfg);
191
+ // Explicit --workspace is a deliberate pin: send it as-is, no AI routing hints.
192
+ // Otherwise forward the AI's routing signal and let the backend decide
193
+ // (auto = AI target wins over ambient when confidence is high enough AND the
194
+ // user is a member). Project from structure is forwarded when present.
195
+ const isExplicitOverride = Boolean(opts.workspace);
196
+ const routingFields = isExplicitOverride
197
+ ? {}
198
+ : {
199
+ workspaceRouting: "auto",
200
+ aiWorkspaceId: structureRes.targetWorkspaceId,
201
+ aiWorkspaceConfidence: structureRes.targetWorkspaceConfidence,
202
+ aiWorkspaceReason: structureRes.targetWorkspaceReason,
203
+ };
204
+ if (structureRes.targetProjectId) {
205
+ routingFields.projectId = structureRes.targetProjectId;
206
+ }
207
+ if (opts.json) {
208
+ // --json without --yes: print structure result and exit
209
+ if (!opts.yes) {
210
+ console.log(JSON.stringify(structureRes, null, 2));
211
+ return;
212
+ }
213
+ // --json + --yes: also execute and print combined result
214
+ const executeRes = await hubPost("/capture/execute", {
215
+ userId,
216
+ workspaceId,
217
+ ...(smartSessionId ? { sessionId: smartSessionId } : {}),
218
+ ...routingFields,
219
+ entities: structureRes.proposals,
220
+ relations: structureRes.relations ?? [],
221
+ }, cfg);
222
+ const report = await buildSmartLaneReport(executeRes, workspaceId, source, cfg);
223
+ console.log(JSON.stringify({ structure: structureRes, execute: executeRes, ...laneJsonFields(report) }, null, 2));
224
+ return;
225
+ }
226
+ // 2. Render proposals
227
+ renderStructureResult(structureRes);
228
+ const count = structureRes.proposals?.length ?? 0;
229
+ if (count === 0)
230
+ return;
231
+ // 3. Confirm
232
+ let confirmed = opts.yes ?? false;
233
+ if (!confirmed) {
234
+ log.blank();
235
+ const rl = readline.createInterface({ input, output });
236
+ try {
237
+ const answer = await rl.question(chalk.bold(` Create ${count} entr${count !== 1 ? "ies" : "y"}? [y/N] `));
238
+ confirmed = answer.trim().toLowerCase() === "y";
239
+ }
240
+ finally {
241
+ rl.close();
242
+ }
243
+ }
244
+ if (!confirmed) {
245
+ log.dim("Aborted.");
246
+ return;
247
+ }
248
+ // 4. Execute
249
+ const executeRes = await hubPost("/capture/execute", {
250
+ userId,
251
+ workspaceId,
252
+ ...(smartSessionId ? { sessionId: smartSessionId } : {}),
253
+ ...routingFields,
254
+ entities: structureRes.proposals,
255
+ relations: structureRes.relations ?? [],
256
+ }, cfg);
257
+ const created = executeRes.entitiesCreated
258
+ ?? executeRes.created
259
+ ?? count;
260
+ log.success(`${created} entr${created !== 1 ? "ies" : "y"} created.`);
261
+ if (executeRes.relationsCreated) {
262
+ log.dim(` ${executeRes.relationsCreated} relation${Number(executeRes.relationsCreated) !== 1 ? "s" : ""} created.`);
263
+ }
264
+ if (executeRes.movedToWorkspace) {
265
+ log.dim(` → filed into workspace ${String(executeRes.movedToWorkspace)}`);
266
+ }
267
+ const report = await buildSmartLaneReport(executeRes, workspaceId, source, cfg);
268
+ console.log(" " + formatLaneLine(report));
269
+ }
270
+ /**
271
+ * Build the lane report for a smart-capture execute response. Smart capture may
272
+ * land directly or be queued as proposals — detect the latter from the execute
273
+ * payload (proposed/proposalsCreated/status) and fall back to auto otherwise.
274
+ */
275
+ async function buildSmartLaneReport(executeRes, workspaceId, source, cfg) {
276
+ const isProposed = executeRes.status === "proposed" ||
277
+ Boolean(executeRes.proposalId) ||
278
+ Number(executeRes.proposalsCreated ?? 0) > 0;
279
+ return {
280
+ lane: laneFromSource(source),
281
+ workspaceId,
282
+ workspaceName: await resolveWorkspaceName(workspaceId, cfg),
283
+ governance: isProposed ? "proposed" : "auto",
284
+ };
285
+ }
286
+ // ─── Legacy engineering-memory capture ────────────────────────────────────────
11
287
  export async function captureKnowledge(opts) {
12
288
  try {
289
+ // Mutual exclusion: smart mode (positional text) and typed mode (--type/--claim)
290
+ // are two distinct flows. Mixing them silently drops one — fail loud instead.
291
+ if (opts.text !== undefined && opts.type !== undefined) {
292
+ console.error(chalk.red("Cannot mix smart mode (positional text) with typed mode (--type/--claim)."));
293
+ console.error(chalk.dim(" Use one: `synap capture \"free text\"` OR `synap capture --type gotcha --claim \"…\"`"));
294
+ process.exit(1);
295
+ }
296
+ // Smart mode: positional text with no --type
297
+ if (opts.text !== undefined && opts.type === undefined) {
298
+ await runSmartCapture(opts.text, opts);
299
+ return;
300
+ }
301
+ // Legacy mode: --type is required
302
+ if (!opts.type) {
303
+ console.error(chalk.red("Missing required option: --type <gotcha|lesson|decision|reference>"));
304
+ console.error(chalk.dim(" Or pass free text as a positional arg for smart capture: synap capture \"your text\""));
305
+ process.exit(1);
306
+ }
307
+ if (!opts.claim) {
308
+ console.error(chalk.red("Missing required option: --claim <text>"));
309
+ process.exit(1);
310
+ }
13
311
  const cfg = await resolveHubConfig();
14
312
  const userId = await resolveUserId(cfg);
15
- const workspaceId = cfg.workspaceId;
313
+ // GLOBAL lane: pod-wide procedural runbook → knowledge_keys.
314
+ if (opts.global) {
315
+ await captureGlobalRunbook(opts, cfg, userId);
316
+ return;
317
+ }
318
+ const { workspaceId, source } = await resolveKnowledgeWorkspace(opts, cfg, cfg.workspaceId);
16
319
  if (!workspaceId) {
17
320
  console.error(chalk.red("No workspace set. Run:\n" +
18
- " synap workspace provision-agent (create your agent workspace)\n" +
19
- " synap use <workspace-id> (set it as active)"));
321
+ " synap connect (sets up memory + team workspace routing)\n" +
322
+ " synap use <workspace-id> (manual override)"));
20
323
  process.exit(1);
21
324
  }
22
325
  const tags = opts.tags
23
326
  ? opts.tags.split(",").map((t) => t.trim()).filter(Boolean)
24
327
  : [];
25
328
  const title = opts.claim.slice(0, 120);
329
+ // Every --type entry is a typed `knowledge` entity; ek_type discriminates the
330
+ // kind. This is "one store, type tags" (the research-canonical pattern) — NOT a
331
+ // residual catch-all: each row is typed by ek_type and lives in the workspace
332
+ // lens that supplies its domain (so no `engineering_knowledge`). A structured
333
+ // decision RECORD (rationale/alternatives/status) is a different artifact, reached
334
+ // via smart `capture "<text>"` or `create entity --profile=decision`.
335
+ const sessionId = opts.session ? readActiveSessionId() : undefined;
26
336
  const res = await hubPost("/entities", {
27
337
  userId,
28
338
  workspaceId,
29
- profileSlug: "engineering_knowledge",
339
+ profileSlug: "knowledge",
30
340
  title,
341
+ ...(sessionId ? { sessionId } : {}),
31
342
  properties: {
32
343
  ek_type: opts.type,
33
344
  ek_claim: opts.claim,
@@ -36,61 +347,48 @@ export async function captureKnowledge(opts) {
36
347
  ...(tags.length > 0 ? { ek_tags: tags } : {}),
37
348
  },
38
349
  }, cfg);
39
- if (opts.json) {
40
- console.log(JSON.stringify({ id: res.id, stored: true }, null, 2));
41
- return;
42
- }
43
- log.success(`[${opts.type}] ${opts.claim.slice(0, 80)}`);
44
- if (res.id)
45
- log.dim(` id: ${res.id}`);
46
- }
47
- catch (e) {
48
- console.error(chalk.red("Error: " + e.message));
49
- process.exit(1);
50
- }
51
- }
52
- export async function recallStructured(query, opts) {
53
- try {
54
- const cfg = await resolveHubConfig(opts);
55
- const limit = parseInt(opts.limit ?? "10", 10);
56
- const params = {
57
- profileSlug: "engineering_knowledge",
58
- q: query,
59
- limit,
350
+ // Governance may queue the write as a proposal rather than creating directly
351
+ const isProposed = res.status === "proposed" || Boolean(res.proposalId);
352
+ // Declare which lane + workspace + governance this capture took, so the
353
+ // caller always knows where its knowledge landed.
354
+ const report = {
355
+ lane: laneFromSource(source),
356
+ workspaceId,
357
+ workspaceName: await resolveWorkspaceName(workspaceId, cfg),
358
+ governance: isProposed ? "proposed" : "auto",
60
359
  };
61
- const workspaceId = opts.workspace ?? cfg.workspaceId;
62
- if (workspaceId)
63
- params.workspaceId = workspaceId;
64
- const res = await hubGet("/entities", params, cfg);
65
- const entities = (res.entities ?? res.items ?? res);
66
- let list = Array.isArray(entities) ? entities : [];
67
- if (opts.type) {
68
- list = list.filter((e) => {
69
- const props = (e.properties ?? {});
70
- return props.ek_type === opts.type;
71
- });
72
- }
73
360
  if (opts.json) {
74
- console.log(JSON.stringify(list, null, 2));
361
+ if (isProposed) {
362
+ console.log(JSON.stringify({
363
+ proposed: true,
364
+ proposalId: res.proposalId ?? res.id,
365
+ reviewUrl: res.reviewUrl ?? null,
366
+ message: "Write queued for approval — not yet stored.",
367
+ ...laneJsonFields(report),
368
+ }, null, 2));
369
+ }
370
+ else {
371
+ console.log(JSON.stringify({ id: res.id, stored: true, workspace: source, ...laneJsonFields(report) }, null, 2));
372
+ }
75
373
  return;
76
374
  }
77
- if (list.length === 0) {
78
- log.dim(`No knowledge entries found for "${query}"`);
79
- return;
375
+ if (isProposed) {
376
+ log.warn(`Queued for approval — not yet stored.`);
377
+ log.dim(` The target workspace requires human review for agent writes.`);
378
+ if (res.reviewUrl)
379
+ log.dim(` Review: ${String(res.reviewUrl)}`);
380
+ else
381
+ log.dim(` Open Synap and approve the pending proposal to persist this entry.`);
382
+ console.log(" " + formatLaneLine(report));
80
383
  }
81
- for (const item of list) {
82
- const props = (item.properties ?? {});
83
- const type = String(props.ek_type ?? "–");
84
- const claim = String(props.ek_claim ?? item.name ?? "–");
85
- const why = props.ek_why ? `\n why: ${props.ek_why}` : "";
86
- const tags = Array.isArray(props.ek_tags) && props.ek_tags.length > 0
87
- ? chalk.dim(` [${props.ek_tags.join(", ")}]`)
88
- : "";
89
- console.log(` ${chalk.cyan(type.padEnd(10))} ${claim}${tags}${chalk.dim(why)}`);
384
+ else {
385
+ log.success(`[${opts.type}] ${opts.claim.slice(0, 80)}`);
386
+ log.dim(` workspace: ${source} id: ${String(res.id ?? "")}`);
387
+ console.log(" " + formatLaneLine(report));
90
388
  }
91
389
  }
92
390
  catch (e) {
93
- console.error(chalk.red("Error: " + e.message));
391
+ renderHubError(e);
94
392
  process.exit(1);
95
393
  }
96
394
  }
@@ -120,7 +418,7 @@ export async function provisionAgentWorkspace(opts) {
120
418
  }
121
419
  }
122
420
  catch (e) {
123
- console.error(chalk.red("Error: " + e.message));
421
+ renderHubError(e);
124
422
  process.exit(1);
125
423
  }
126
424
  }