@synap-core/cli 1.10.0 → 1.12.2

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 (461) hide show
  1. package/README.md +23 -198
  2. package/dist/build-info.json +6 -0
  3. package/dist/commands/agent-run.js +3 -2
  4. package/dist/commands/agent-run.js.map +1 -1
  5. package/dist/commands/agents.d.ts +33 -17
  6. package/dist/commands/agents.js +203 -237
  7. package/dist/commands/agents.js.map +1 -1
  8. package/dist/commands/app.d.ts +143 -0
  9. package/dist/commands/app.js +523 -0
  10. package/dist/commands/app.js.map +1 -0
  11. package/dist/commands/automate.d.ts +21 -0
  12. package/dist/commands/automate.js +42 -0
  13. package/dist/commands/automate.js.map +1 -0
  14. package/dist/commands/automation-schema.test.d.ts +16 -0
  15. package/dist/commands/automation-schema.test.js +77 -0
  16. package/dist/commands/automation-schema.test.js.map +1 -0
  17. package/dist/commands/automation.d.ts +12 -0
  18. package/dist/commands/automation.js +80 -35
  19. package/dist/commands/automation.js.map +1 -1
  20. package/dist/commands/bridge-setup.d.ts +14 -1
  21. package/dist/commands/bridge-setup.js +392 -128
  22. package/dist/commands/bridge-setup.js.map +1 -1
  23. package/dist/commands/cap-connections.d.ts +4 -4
  24. package/dist/commands/cap-connections.js +14 -14
  25. package/dist/commands/cap-connections.js.map +1 -1
  26. package/dist/commands/capability.d.ts +2 -0
  27. package/dist/commands/capability.js +297 -176
  28. package/dist/commands/capability.js.map +1 -1
  29. package/dist/commands/catalog.d.ts +275 -0
  30. package/dist/commands/catalog.js +481 -0
  31. package/dist/commands/catalog.js.map +1 -0
  32. package/dist/commands/cell.d.ts +155 -8
  33. package/dist/commands/cell.js +416 -40
  34. package/dist/commands/cell.js.map +1 -1
  35. package/dist/commands/centrality.js +3 -14
  36. package/dist/commands/centrality.js.map +1 -1
  37. package/dist/commands/connect.d.ts +38 -13
  38. package/dist/commands/connect.js +68 -167
  39. package/dist/commands/connect.js.map +1 -1
  40. package/dist/commands/connections.d.ts +3 -2
  41. package/dist/commands/connections.js +95 -25
  42. package/dist/commands/connections.js.map +1 -1
  43. package/dist/commands/context.js +9 -2
  44. package/dist/commands/context.js.map +1 -1
  45. package/dist/commands/data-extra.d.ts +34 -0
  46. package/dist/commands/data-extra.js +198 -25
  47. package/dist/commands/data-extra.js.map +1 -1
  48. package/dist/commands/data.d.ts +120 -2
  49. package/dist/commands/data.js +307 -24
  50. package/dist/commands/data.js.map +1 -1
  51. package/dist/commands/diagnose.d.ts +66 -4
  52. package/dist/commands/diagnose.js +329 -29
  53. package/dist/commands/diagnose.js.map +1 -1
  54. package/dist/commands/digest.js +2 -1
  55. package/dist/commands/digest.js.map +1 -1
  56. package/dist/commands/doc.d.ts +25 -4
  57. package/dist/commands/doc.js +100 -18
  58. package/dist/commands/doc.js.map +1 -1
  59. package/dist/commands/doctor.d.ts +130 -0
  60. package/dist/commands/doctor.js +814 -0
  61. package/dist/commands/doctor.js.map +1 -0
  62. package/dist/commands/events.js +3 -1
  63. package/dist/commands/events.js.map +1 -1
  64. package/dist/commands/explain.js +5 -5
  65. package/dist/commands/explain.js.map +1 -1
  66. package/dist/commands/graph.js +5 -3
  67. package/dist/commands/graph.js.map +1 -1
  68. package/dist/commands/import.d.ts +368 -13
  69. package/dist/commands/import.js +1096 -55
  70. package/dist/commands/import.js.map +1 -1
  71. package/dist/commands/init.d.ts +20 -9
  72. package/dist/commands/init.js +433 -973
  73. package/dist/commands/init.js.map +1 -1
  74. package/dist/commands/keys.d.ts +1 -0
  75. package/dist/commands/keys.js +15 -2
  76. package/dist/commands/keys.js.map +1 -1
  77. package/dist/commands/knowledge.d.ts +28 -6
  78. package/dist/commands/knowledge.js +358 -73
  79. package/dist/commands/knowledge.js.map +1 -1
  80. package/dist/commands/launch.js +2 -2
  81. package/dist/commands/launch.js.map +1 -1
  82. package/dist/commands/lens.d.ts +37 -1
  83. package/dist/commands/lens.js +193 -72
  84. package/dist/commands/lens.js.map +1 -1
  85. package/dist/commands/market-authoring.d.ts +72 -0
  86. package/dist/commands/market-authoring.js +566 -0
  87. package/dist/commands/market-authoring.js.map +1 -0
  88. package/dist/commands/market-official.d.ts +58 -0
  89. package/dist/commands/market-official.js +84 -0
  90. package/dist/commands/market-official.js.map +1 -0
  91. package/dist/commands/market.d.ts +419 -20
  92. package/dist/commands/market.js +2124 -193
  93. package/dist/commands/market.js.map +1 -1
  94. package/dist/commands/mcp.d.ts +70 -13
  95. package/dist/commands/mcp.js +308 -40
  96. package/dist/commands/mcp.js.map +1 -1
  97. package/dist/commands/open.d.ts +39 -9
  98. package/dist/commands/open.js +80 -25
  99. package/dist/commands/open.js.map +1 -1
  100. package/dist/commands/playbook.d.ts +42 -0
  101. package/dist/commands/playbook.js +162 -0
  102. package/dist/commands/playbook.js.map +1 -0
  103. package/dist/commands/pod.js +1 -1
  104. package/dist/commands/pod.js.map +1 -1
  105. package/dist/commands/pods.d.ts +19 -0
  106. package/dist/commands/pods.js +220 -85
  107. package/dist/commands/pods.js.map +1 -1
  108. package/dist/commands/proposals-actions.d.ts +62 -0
  109. package/dist/commands/proposals-actions.js +146 -8
  110. package/dist/commands/proposals-actions.js.map +1 -1
  111. package/dist/commands/proposals-await.d.ts +68 -0
  112. package/dist/commands/proposals-await.js +248 -0
  113. package/dist/commands/proposals-await.js.map +1 -0
  114. package/dist/commands/proton-setup.d.ts +73 -0
  115. package/dist/commands/proton-setup.js +577 -0
  116. package/dist/commands/proton-setup.js.map +1 -0
  117. package/dist/commands/providers.d.ts +23 -0
  118. package/dist/commands/providers.js +126 -1
  119. package/dist/commands/providers.js.map +1 -1
  120. package/dist/commands/raycast.js +6 -2
  121. package/dist/commands/raycast.js.map +1 -1
  122. package/dist/commands/rule.d.ts +150 -0
  123. package/dist/commands/rule.js +447 -0
  124. package/dist/commands/rule.js.map +1 -0
  125. package/dist/commands/session-wait.d.ts +111 -0
  126. package/dist/commands/session-wait.js +209 -0
  127. package/dist/commands/session-wait.js.map +1 -0
  128. package/dist/commands/sessions.d.ts +52 -0
  129. package/dist/commands/sessions.js +479 -58
  130. package/dist/commands/sessions.js.map +1 -1
  131. package/dist/commands/skill-manage.d.ts +21 -0
  132. package/dist/commands/skill-manage.js +136 -19
  133. package/dist/commands/skill-manage.js.map +1 -1
  134. package/dist/commands/skills.js +19 -1
  135. package/dist/commands/skills.js.map +1 -1
  136. package/dist/commands/status.d.ts +1 -4
  137. package/dist/commands/status.js +5 -34
  138. package/dist/commands/status.js.map +1 -1
  139. package/dist/commands/statusline.backoff.test.d.ts +13 -0
  140. package/dist/commands/statusline.backoff.test.js +100 -0
  141. package/dist/commands/statusline.backoff.test.js.map +1 -0
  142. package/dist/commands/statusline.js +16 -9
  143. package/dist/commands/statusline.js.map +1 -1
  144. package/dist/commands/sync-status.d.ts +12 -0
  145. package/dist/commands/sync-status.js +125 -0
  146. package/dist/commands/sync-status.js.map +1 -0
  147. package/dist/commands/templates-retire.d.ts +34 -0
  148. package/dist/commands/templates-retire.js +192 -0
  149. package/dist/commands/templates-retire.js.map +1 -0
  150. package/dist/commands/tools.js +6 -21
  151. package/dist/commands/tools.js.map +1 -1
  152. package/dist/commands/tracks.d.ts +51 -0
  153. package/dist/commands/tracks.js +291 -0
  154. package/dist/commands/tracks.js.map +1 -0
  155. package/dist/commands/update.d.ts +3 -11
  156. package/dist/commands/update.js +5 -134
  157. package/dist/commands/update.js.map +1 -1
  158. package/dist/commands/upload.d.ts +68 -0
  159. package/dist/commands/upload.js +257 -0
  160. package/dist/commands/upload.js.map +1 -0
  161. package/dist/commands/vendor.d.ts +28 -0
  162. package/dist/commands/vendor.js +110 -0
  163. package/dist/commands/vendor.js.map +1 -0
  164. package/dist/commands/versions.js +6 -0
  165. package/dist/commands/versions.js.map +1 -1
  166. package/dist/commands/view.js +10 -5
  167. package/dist/commands/view.js.map +1 -1
  168. package/dist/commands/whoami.d.ts +23 -3
  169. package/dist/commands/whoami.js +169 -23
  170. package/dist/commands/whoami.js.map +1 -1
  171. package/dist/commands/worker.d.ts +122 -0
  172. package/dist/commands/worker.js +435 -0
  173. package/dist/commands/worker.js.map +1 -0
  174. package/dist/commands/worker.test.d.ts +1 -0
  175. package/dist/commands/worker.test.js +116 -0
  176. package/dist/commands/worker.test.js.map +1 -0
  177. package/dist/commands/workspace-ops.d.ts +35 -0
  178. package/dist/commands/workspace-ops.js +153 -0
  179. package/dist/commands/workspace-ops.js.map +1 -0
  180. package/dist/index.d.ts +6 -6
  181. package/dist/index.js +1009 -171
  182. package/dist/index.js.map +1 -1
  183. package/dist/lib/agent-connections.d.ts +31 -0
  184. package/dist/lib/agent-connections.js +33 -0
  185. package/dist/lib/agent-connections.js.map +1 -0
  186. package/dist/lib/agent-detect.d.ts +27 -0
  187. package/dist/lib/agent-detect.js +71 -0
  188. package/dist/lib/agent-detect.js.map +1 -0
  189. package/dist/lib/agent-door.d.ts +138 -0
  190. package/dist/lib/agent-door.js +426 -0
  191. package/dist/lib/agent-door.js.map +1 -0
  192. package/dist/lib/agents-config.d.ts +2 -0
  193. package/dist/lib/agents-config.js +4 -9
  194. package/dist/lib/agents-config.js.map +1 -1
  195. package/dist/lib/approval-poll.d.ts +31 -2
  196. package/dist/lib/approval-poll.js +20 -7
  197. package/dist/lib/approval-poll.js.map +1 -1
  198. package/dist/lib/atomic-file.d.ts +48 -0
  199. package/dist/lib/atomic-file.js +129 -0
  200. package/dist/lib/atomic-file.js.map +1 -0
  201. package/dist/lib/auth.d.ts +14 -9
  202. package/dist/lib/auth.js +44 -61
  203. package/dist/lib/auth.js.map +1 -1
  204. package/dist/lib/batch-approval.d.ts +85 -0
  205. package/dist/lib/batch-approval.js +170 -0
  206. package/dist/lib/batch-approval.js.map +1 -0
  207. package/dist/lib/capture-lane.d.ts +6 -5
  208. package/dist/lib/capture-lane.js +11 -8
  209. package/dist/lib/capture-lane.js.map +1 -1
  210. package/dist/lib/capture-structure.d.ts +342 -0
  211. package/dist/lib/capture-structure.js +295 -0
  212. package/dist/lib/capture-structure.js.map +1 -0
  213. package/dist/lib/catalog-templates.d.ts +59 -0
  214. package/dist/lib/catalog-templates.js +126 -0
  215. package/dist/lib/catalog-templates.js.map +1 -0
  216. package/dist/lib/cli-build.d.ts +19 -0
  217. package/dist/lib/cli-build.js +37 -0
  218. package/dist/lib/cli-build.js.map +1 -0
  219. package/dist/lib/conversation-headers.d.ts +18 -0
  220. package/dist/lib/conversation-headers.js +32 -0
  221. package/dist/lib/conversation-headers.js.map +1 -0
  222. package/dist/lib/cp-packages.d.ts +216 -4
  223. package/dist/lib/cp-packages.js +414 -11
  224. package/dist/lib/cp-packages.js.map +1 -1
  225. package/dist/lib/credential-class.d.ts +117 -0
  226. package/dist/lib/credential-class.js +116 -0
  227. package/dist/lib/credential-class.js.map +1 -0
  228. package/dist/lib/describe-lens.d.ts +35 -0
  229. package/dist/lib/describe-lens.js +40 -0
  230. package/dist/lib/describe-lens.js.map +1 -1
  231. package/dist/lib/device-connect.d.ts +125 -0
  232. package/dist/lib/device-connect.js +256 -0
  233. package/dist/lib/device-connect.js.map +1 -0
  234. package/dist/lib/directory-lens.d.ts +99 -0
  235. package/dist/lib/directory-lens.js +187 -0
  236. package/dist/lib/directory-lens.js.map +1 -0
  237. package/dist/lib/exporter-coverage.d.ts +71 -0
  238. package/dist/lib/exporter-coverage.js +97 -0
  239. package/dist/lib/exporter-coverage.js.map +1 -0
  240. package/dist/lib/hub-client.d.ts +43 -9
  241. package/dist/lib/hub-client.js +429 -65
  242. package/dist/lib/hub-client.js.map +1 -1
  243. package/dist/lib/id.d.ts +23 -0
  244. package/dist/lib/id.js +35 -0
  245. package/dist/lib/id.js.map +1 -0
  246. package/dist/lib/init-connect.d.ts +41 -0
  247. package/dist/lib/init-connect.js +75 -0
  248. package/dist/lib/init-connect.js.map +1 -0
  249. package/dist/lib/init-exit.d.ts +24 -0
  250. package/dist/lib/init-exit.js +41 -0
  251. package/dist/lib/init-exit.js.map +1 -0
  252. package/dist/lib/init-flow.d.ts +25 -0
  253. package/dist/lib/init-flow.js +40 -0
  254. package/dist/lib/init-flow.js.map +1 -0
  255. package/dist/lib/init-handoff.d.ts +16 -0
  256. package/dist/lib/init-handoff.js +19 -0
  257. package/dist/lib/init-handoff.js.map +1 -0
  258. package/dist/lib/init-output.d.ts +18 -0
  259. package/dist/lib/init-output.js +43 -0
  260. package/dist/lib/init-output.js.map +1 -0
  261. package/dist/lib/init-pod.d.ts +45 -0
  262. package/dist/lib/init-pod.js +36 -0
  263. package/dist/lib/init-pod.js.map +1 -0
  264. package/dist/lib/installed.d.ts +210 -11
  265. package/dist/lib/installed.js +234 -36
  266. package/dist/lib/installed.js.map +1 -1
  267. package/dist/lib/key-approval.d.ts +57 -0
  268. package/dist/lib/key-approval.js +117 -0
  269. package/dist/lib/key-approval.js.map +1 -0
  270. package/dist/lib/key-diagnosis.d.ts +56 -0
  271. package/dist/lib/key-diagnosis.js +227 -0
  272. package/dist/lib/key-diagnosis.js.map +1 -0
  273. package/dist/lib/key-doctor.d.ts +136 -0
  274. package/dist/lib/key-doctor.js +286 -0
  275. package/dist/lib/key-doctor.js.map +1 -0
  276. package/dist/lib/key-locations.d.ts +120 -0
  277. package/dist/lib/key-locations.js +326 -0
  278. package/dist/lib/key-locations.js.map +1 -0
  279. package/dist/lib/key-source.d.ts +66 -0
  280. package/dist/lib/key-source.js +106 -0
  281. package/dist/lib/key-source.js.map +1 -0
  282. package/dist/lib/key-state.d.ts +70 -0
  283. package/dist/lib/key-state.js +115 -0
  284. package/dist/lib/key-state.js.map +1 -0
  285. package/dist/lib/kind-package.d.ts +181 -0
  286. package/dist/lib/kind-package.js +679 -0
  287. package/dist/lib/kind-package.js.map +1 -0
  288. package/dist/lib/knowledge-title.d.ts +24 -0
  289. package/dist/lib/knowledge-title.js +46 -0
  290. package/dist/lib/knowledge-title.js.map +1 -0
  291. package/dist/lib/knowledge-title.test.d.ts +1 -0
  292. package/dist/lib/knowledge-title.test.js +34 -0
  293. package/dist/lib/knowledge-title.test.js.map +1 -0
  294. package/dist/lib/machine-instance.d.ts +64 -0
  295. package/dist/lib/machine-instance.js +142 -0
  296. package/dist/lib/machine-instance.js.map +1 -0
  297. package/dist/lib/mcp-bridge.d.ts +42 -0
  298. package/dist/lib/mcp-bridge.js +147 -0
  299. package/dist/lib/mcp-bridge.js.map +1 -0
  300. package/dist/lib/mcp-bridge.test.d.ts +1 -0
  301. package/dist/lib/mcp-bridge.test.js +90 -0
  302. package/dist/lib/mcp-bridge.test.js.map +1 -0
  303. package/dist/lib/mcp-call.d.ts +30 -0
  304. package/dist/lib/mcp-call.js +107 -0
  305. package/dist/lib/mcp-call.js.map +1 -0
  306. package/dist/lib/mcp-snippets.d.ts +53 -0
  307. package/dist/lib/mcp-snippets.js +82 -0
  308. package/dist/lib/mcp-snippets.js.map +1 -0
  309. package/dist/lib/next-steps.d.ts +8 -0
  310. package/dist/lib/next-steps.js +31 -1
  311. package/dist/lib/next-steps.js.map +1 -1
  312. package/dist/lib/package-wire.d.ts +179 -0
  313. package/dist/lib/package-wire.js +68 -0
  314. package/dist/lib/package-wire.js.map +1 -0
  315. package/dist/lib/pair-link.d.ts +38 -0
  316. package/dist/lib/pair-link.js +68 -0
  317. package/dist/lib/pair-link.js.map +1 -0
  318. package/dist/lib/pod-wide.d.ts +40 -0
  319. package/dist/lib/pod-wide.js +46 -0
  320. package/dist/lib/pod-wide.js.map +1 -0
  321. package/dist/lib/pod.d.ts +119 -115
  322. package/dist/lib/pod.js +206 -412
  323. package/dist/lib/pod.js.map +1 -1
  324. package/dist/lib/project-ref.d.ts +9 -3
  325. package/dist/lib/project-ref.js +10 -4
  326. package/dist/lib/project-ref.js.map +1 -1
  327. package/dist/lib/review-credential.d.ts +119 -0
  328. package/dist/lib/review-credential.js +147 -0
  329. package/dist/lib/review-credential.js.map +1 -0
  330. package/dist/lib/safe-open.d.ts +49 -0
  331. package/dist/lib/safe-open.js +119 -0
  332. package/dist/lib/safe-open.js.map +1 -0
  333. package/dist/lib/session-lens.d.ts +40 -1
  334. package/dist/lib/session-lens.js +54 -4
  335. package/dist/lib/session-lens.js.map +1 -1
  336. package/dist/lib/superwhisper-import.d.ts +8 -0
  337. package/dist/lib/superwhisper-import.js +14 -7
  338. package/dist/lib/superwhisper-import.js.map +1 -1
  339. package/dist/lib/superwhisper-title.test.d.ts +1 -0
  340. package/dist/lib/superwhisper-title.test.js +18 -0
  341. package/dist/lib/superwhisper-title.test.js.map +1 -0
  342. package/dist/lib/targets.d.ts +134 -10
  343. package/dist/lib/targets.js +962 -258
  344. package/dist/lib/targets.js.map +1 -1
  345. package/dist/lib/template-file.d.ts +78 -0
  346. package/dist/lib/template-file.js +140 -0
  347. package/dist/lib/template-file.js.map +1 -0
  348. package/dist/lib/template-lifecycle.d.ts +217 -0
  349. package/dist/lib/template-lifecycle.js +433 -0
  350. package/dist/lib/template-lifecycle.js.map +1 -0
  351. package/dist/lib/template-steps.d.ts +88 -0
  352. package/dist/lib/template-steps.js +118 -0
  353. package/dist/lib/template-steps.js.map +1 -0
  354. package/dist/lib/time-ago.d.ts +2 -0
  355. package/dist/lib/time-ago.js +15 -0
  356. package/dist/lib/time-ago.js.map +1 -0
  357. package/dist/utils/logger.js +5 -2
  358. package/dist/utils/logger.js.map +1 -1
  359. package/package.json +25 -18
  360. package/skills/README.md +12 -10
  361. package/skills/agent-os/SKILL.md +220 -99
  362. package/skills/manifest.json +2 -2
  363. package/skills/onboard/SKILL.md +61 -25
  364. package/skills/synap/README.md +5 -8
  365. package/skills/synap/SKILL.md +1185 -301
  366. package/skills/synap/_order.txt +7 -0
  367. package/skills/synap/_skill.yaml +1 -1
  368. package/skills/synap/automations.md +15 -0
  369. package/skills/synap/capture.md +54 -151
  370. package/skills/synap/cli-operations.md +24 -18
  371. package/skills/synap/common-mistakes.md +1 -0
  372. package/skills/synap/concepts.md +28 -0
  373. package/skills/synap/content-os.md +92 -0
  374. package/skills/synap/creative-loop.md +15 -10
  375. package/skills/synap/crm.md +21 -52
  376. package/skills/synap/digesting-a-channel.md +25 -0
  377. package/skills/synap/document-embeds.md +141 -47
  378. package/skills/synap/escalation-ladder.md +20 -10
  379. package/skills/synap/focus-sessions.md +47 -21
  380. package/skills/synap/from-intent.md +142 -0
  381. package/skills/synap/governance-rules.md +4 -4
  382. package/skills/synap/governance.md +10 -7
  383. package/skills/synap/hand-off.md +33 -0
  384. package/skills/synap/inline-patterns.md +15 -7
  385. package/skills/synap/lenses.md +33 -15
  386. package/skills/synap/linking.md +41 -40
  387. package/skills/synap/mcp-remote-servers.md +64 -0
  388. package/skills/synap/mental-model.md +24 -22
  389. package/skills/synap/multi-entity-capture.md +6 -4
  390. package/skills/synap/operating-mode-rules.md +1 -1
  391. package/skills/synap/processes.md +118 -0
  392. package/skills/synap/quick-reference.md +5 -1
  393. package/skills/synap/reading.md +3 -1
  394. package/skills/synap/reflexes.md +12 -42
  395. package/skills/synap/viewframe-cells.md +38 -5
  396. package/skills/synap/work-flow.md +1 -1
  397. package/skills/synap/work-model.md +96 -0
  398. package/skills/synap/worked-examples.md +21 -1
  399. package/skills/synap/workspace-design.md +14 -10
  400. package/skills/synap/writes.md +165 -35
  401. package/skills/synap/writing-titles.md +63 -0
  402. package/skills/synap-app/SKILL.md +319 -0
  403. package/skills/synap-app/_order.txt +5 -0
  404. package/skills/synap-app/_skill.yaml +20 -0
  405. package/skills/synap-app/creating-the-base-app.md +64 -0
  406. package/skills/synap-app/governance.md +42 -0
  407. package/skills/synap-app/install-commands.md +55 -0
  408. package/skills/synap-app/overview.md +50 -0
  409. package/skills/synap-app/using-the-sdk.md +73 -0
  410. package/skills/synap-design/SKILL.md +474 -0
  411. package/skills/synap-design/_order.txt +4 -0
  412. package/skills/synap-design/_skill.yaml +21 -0
  413. package/skills/synap-design/loop.md +134 -0
  414. package/skills/synap-design/overview.md +44 -0
  415. package/skills/synap-design/principles.md +130 -0
  416. package/skills/synap-design/system.md +133 -0
  417. package/skills/synap-market/SKILL.md +625 -0
  418. package/skills/synap-market/_order.txt +5 -0
  419. package/skills/synap-market/_skill.yaml +24 -0
  420. package/skills/synap-market/author-and-publish.md +212 -0
  421. package/skills/synap-market/discover-and-fetch.md +59 -0
  422. package/skills/synap-market/governance-and-catalog.md +63 -0
  423. package/skills/synap-market/install.md +133 -0
  424. package/skills/synap-market/overview.md +119 -0
  425. package/skills/synap-schema/SKILL.md +172 -10
  426. package/skills/synap-schema/_order.txt +2 -0
  427. package/skills/synap-schema/_skill.yaml +4 -2
  428. package/skills/synap-schema/common-mistakes.md +4 -2
  429. package/skills/synap-schema/discover-profiles.md +1 -1
  430. package/skills/synap-schema/entity-scope.md +15 -3
  431. package/skills/synap-schema/extend-first.md +29 -0
  432. package/skills/synap-schema/extend-vs-create.md +1 -1
  433. package/skills/synap-schema/intent-vocabulary-ssot.md +111 -0
  434. package/skills/synap-schema/property-types.md +1 -1
  435. package/skills/synap-schema/relations.md +1 -1
  436. package/skills/synap-ui/SKILL.md +19 -12
  437. package/skills/synap-ui/_skill.yaml +1 -1
  438. package/skills/synap-ui/ai-companion.md +1 -1
  439. package/skills/synap-ui/arranging-bento.md +2 -0
  440. package/skills/synap-ui/bento-layouts.md +10 -10
  441. package/skills/synap-ui/bento-recipes.md +313 -543
  442. package/skills/synap-ui/four-builds.md +5 -0
  443. package/skills/synap-ui/view-types.md +2 -2
  444. package/skills/synap-ui/widget-catalog.md +22 -278
  445. package/templates/automations/bookmark-enrichment.automation.json +290 -13
  446. package/templates/automations/url-bookmark-capture.automation.json +73 -11
  447. package/templates/skills/authoring-playbooks/SKILL.md +6 -3
  448. package/templates/skills/authoring-playbooks/reference/stages-contract.md +15 -0
  449. package/templates/skills/authoring-playbooks/reference/worked-example.md +3 -0
  450. package/dist/commands/infra.d.ts +0 -21
  451. package/dist/commands/infra.js +0 -262
  452. package/dist/commands/infra.js.map +0 -1
  453. package/dist/lib/browser-auth.d.ts +0 -35
  454. package/dist/lib/browser-auth.js +0 -170
  455. package/dist/lib/browser-auth.js.map +0 -1
  456. package/dist/lib/openclaw.d.ts +0 -32
  457. package/dist/lib/openclaw.js +0 -164
  458. package/dist/lib/openclaw.js.map +0 -1
  459. package/dist/lib/seed.d.ts +0 -13
  460. package/dist/lib/seed.js +0 -135
  461. package/dist/lib/seed.js.map +0 -1
@@ -0,0 +1,814 @@
1
+ /**
2
+ * synap doctor — coherence preflight.
3
+ *
4
+ * Catches CLI-side config drift in ONE call instead of scattered 404/403
5
+ * failures partway through a real command. Checks, in order:
6
+ * (a) SYNAP_POD_URL resolves — the host is actually served (catches the
7
+ * classic failure: a stale/migrated domain that still LOOKS configured).
8
+ * (b) the key authenticates against that pod.
9
+ * (c) the configured workspace (and project) actually exist on THIS pod —
10
+ * via `GET /orient`, which is the pod's own answer to "what's valid here".
11
+ * (d) the Intelligence Service is reachable — the dependency that capture,
12
+ * import and all AI structuring run through. Without it doctor once
13
+ * printed "All checks passed" while every import was 502-ing.
14
+ * (e) the connection broker answers — and when it does not, WHY: broker
15
+ * kind, relay credential presence + expiry, control-plane issuer trust
16
+ * and the owner's identity link, with the one fix for that reason.
17
+ * (f) prints the active lens (pod, workspace, project) so the user sees
18
+ * exactly where they're pointed.
19
+ *
20
+ * Degrades gracefully on older pods (missing /orient, no dependency probe) — a
21
+ * check that can't run says so and moves on, it never throws. Crucially, a
22
+ * check that could not run reports "could not determine" and is NOT green: an
23
+ * unknown is not a pass. Only a PROVEN failure sets a non-zero exit code.
24
+ */
25
+ import chalk from "chalk";
26
+ import { log } from "../utils/logger.js";
27
+ import { getActivePodConfig, getActiveWorkspaceId, getActiveProjectId, listPodProfiles, checkPodHealth } from "../lib/pod.js";
28
+ import { resolveHubConfig, hubGet, HubError } from "../lib/hub-client.js";
29
+ import { formatKeySource, resolveKeySource } from "../lib/key-source.js";
30
+ import { resolveLensProvenance } from "../lib/describe-lens.js";
31
+ import { samePodOrigin } from "../lib/project-ref.js";
32
+ import { fetchKeyState } from "../lib/key-state.js";
33
+ import { describeKeyState } from "../lib/key-diagnosis.js";
34
+ import { isFixable } from "../lib/key-doctor.js";
35
+ import { connectionLines } from "../lib/agent-connections.js";
36
+ import { thisComputerInstanceIds } from "../lib/machine-instance.js";
37
+ import { tildify } from "../lib/key-locations.js";
38
+ import { cliBuild, formatCliBuild } from "../lib/cli-build.js";
39
+ import os from "node:os";
40
+ import path from "node:path";
41
+ import { unwrapList } from "../lib/unwrapList.js";
42
+ /**
43
+ * Each agent with a live connection, and the computers it is connected from —
44
+ * one line per agent. Agents with none are ONE summary line (OMIT, with the
45
+ * door to the full list). A failed read says so — never an empty list; an older
46
+ * pod that sends no connections is "cannot tell".
47
+ */
48
+ async function printAgentConnections(cfg) {
49
+ let rows;
50
+ try {
51
+ rows = unwrapList(await hubGet("/agent-users?mine=1", {}, cfg));
52
+ }
53
+ catch (err) {
54
+ console.log(` ${chalk.yellow("?")} Could not read your agents' connections: ${err instanceof Error ? err.message : String(err)}`);
55
+ return;
56
+ }
57
+ if (rows.length === 0) {
58
+ log.dim(" No agents on this pod for you yet — connect one: synap connect");
59
+ return;
60
+ }
61
+ const live = [];
62
+ let idle = 0;
63
+ let olderPod = false;
64
+ for (const row of rows) {
65
+ // Keys are minted with the SURFACE's hash: compare against every surface
66
+ // minting under this agentType, and only when the pod named the type.
67
+ const mine = row.agentType ? thisComputerInstanceIds(row.agentType) : null;
68
+ const lines = connectionLines(row.connections, { isThisComputer: (id) => !!mine?.has(id) });
69
+ if (lines === null)
70
+ olderPod = true;
71
+ else if (lines.length === 0)
72
+ idle++;
73
+ else
74
+ live.push({ name: row.name ?? row.agentType ?? "Agent", lines });
75
+ }
76
+ const width = Math.min(18, Math.max(0, ...live.map((r) => r.name.length)) + 2);
77
+ for (const r of live)
78
+ console.log(` ${r.name.padEnd(width)}${r.lines.join(chalk.dim(" · "))}`);
79
+ if (idle)
80
+ console.log(chalk.dim(` +${idle} agent${idle === 1 ? "" : "s"} with no live connection — synap agents list`));
81
+ if (olderPod)
82
+ console.log(chalk.dim(" (this pod predates per-computer connections — update it to see them)"));
83
+ }
84
+ /**
85
+ * Read the Intelligence-Service entry out of `GET /api/hub/health/dependencies`.
86
+ *
87
+ * Keys off the pod's real contract: `{ dependencies: [{ name:
88
+ * "intelligence-service", state: "reachable"|"unreachable"|"unresolved",
89
+ * reachable: boolean, reason?, endpoint?, httpStatus?, latencyMs? }] }`.
90
+ *
91
+ * Anything this cannot positively recognise degrades to `unknown` — the CLI
92
+ * ships independently of the pod, so a future field rename must surface as
93
+ * "could not determine", never as a silent green.
94
+ */
95
+ /**
96
+ * Describe which lens the pod resolved the IS under, from its `resolution`
97
+ * echo. Silent when the pod did not say — never guess a lens.
98
+ */
99
+ function readLens(resolution) {
100
+ if (!resolution || typeof resolution !== "object")
101
+ return "";
102
+ const ws = resolution.workspaceId;
103
+ if (typeof ws === "string" && ws)
104
+ return ` (checked as workspace ${ws})`;
105
+ if (ws === null)
106
+ return " (checked pod-level)";
107
+ return "";
108
+ }
109
+ export function readIntelligenceHealth(payload) {
110
+ if (!payload || typeof payload !== "object") {
111
+ return { state: "unknown", detail: "the pod returned no dependency payload" };
112
+ }
113
+ const root = payload;
114
+ const deps = root.dependencies;
115
+ if (!Array.isArray(deps)) {
116
+ return { state: "unknown", detail: "the dependency report carried no `dependencies` array" };
117
+ }
118
+ // The pod echoes back the lens it actually resolved under. Report it: a
119
+ // pod-level "reachable" does not prove the workspace the user imports into
120
+ // routes to a live service, and vice versa.
121
+ const lens = readLens(root.resolution);
122
+ const entry = deps.find((d) => Boolean(d) && typeof d === "object" && d.name === "intelligence-service");
123
+ if (!entry) {
124
+ return {
125
+ state: "unknown",
126
+ detail: "the pod's dependency report listed no intelligence-service entry",
127
+ };
128
+ }
129
+ const reason = typeof entry.reason === "string" ? entry.reason : undefined;
130
+ const where = typeof entry.endpoint === "string" ? entry.endpoint : undefined;
131
+ const suffix = reason ? ` — ${reason}` : "";
132
+ switch (entry.state) {
133
+ case "reachable": {
134
+ const ms = typeof entry.latencyMs === "number" ? ` in ${entry.latencyMs}ms` : "";
135
+ return {
136
+ state: "up",
137
+ detail: `intelligence-service answered${where ? ` at ${where}` : ""}${ms}${lens}`,
138
+ };
139
+ }
140
+ case "unreachable":
141
+ return {
142
+ state: "down",
143
+ detail: `intelligence-service${where ? ` at ${where}` : ""} did not answer${lens}${suffix}`,
144
+ };
145
+ case "unresolved":
146
+ // Determinate, not undetermined: the pod positively told us resolution
147
+ // failed, and a real capture hits that same failure. It is a proven
148
+ // break with a different CAUSE than "the service is down".
149
+ return {
150
+ state: "unresolved",
151
+ detail: `the pod could not determine which Intelligence Service it routes to${lens}${suffix}`,
152
+ };
153
+ default:
154
+ // No readable `state`. Fall back to the boolean mirror ONLY when it is a
155
+ // real boolean — never treat a missing field as healthy.
156
+ if (entry.reachable === true)
157
+ return { state: "up", detail: "intelligence-service answered" };
158
+ if (entry.reachable === false) {
159
+ return { state: "down", detail: `intelligence-service did not answer${suffix}` };
160
+ }
161
+ return { state: "unknown", detail: "the intelligence-service entry carried no readable state" };
162
+ }
163
+ }
164
+ const IS_CHECK_NAME = "Intelligence Service reachable";
165
+ /**
166
+ * Turn an IS verdict into a check row. Names the CONSEQUENCE, not just the
167
+ * dependency: the incident this fixes had a green doctor while every capture /
168
+ * import was 502-ing, so "IS unreachable" alone does not tell the user that the
169
+ * command they are about to run cannot work.
170
+ */
171
+ export function intelligenceCheck(verdict) {
172
+ const consequence = "capture / import / AI structuring WILL FAIL (files import as 0 entities, reported degraded)";
173
+ switch (verdict.state) {
174
+ case "up":
175
+ return { name: IS_CHECK_NAME, ok: true, detail: verdict.detail };
176
+ case "down":
177
+ return {
178
+ name: IS_CHECK_NAME,
179
+ ok: false,
180
+ detail: `${verdict.detail} — ${consequence}`,
181
+ fix: "The pod is up but its Intelligence Service is not. Restart/redeploy the IS, then re-run: synap doctor",
182
+ };
183
+ case "unresolved":
184
+ return {
185
+ name: IS_CHECK_NAME,
186
+ ok: false,
187
+ detail: `${verdict.detail} — ${consequence}`,
188
+ // A different fault from "down": nothing to restart, the routing itself
189
+ // is empty/misconfigured, so the fix points at configuration.
190
+ fix: "No Intelligence Service is configured for this pod/workspace. Check the pod's intelligence-service registry, then re-run: synap doctor",
191
+ };
192
+ default:
193
+ return {
194
+ name: IS_CHECK_NAME,
195
+ ok: false,
196
+ unknown: true,
197
+ detail: `could not determine — ${verdict.detail}. If it is down, ${consequence}.`,
198
+ // `import --dry-run` calls POST /capture/structure and stops before
199
+ // /capture/execute — it exercises the exact door that 502s when the IS
200
+ // is down, and writes nothing. (`capture` has no --dry-run.)
201
+ fix: "This pod build may predate GET /api/hub/health/dependencies. Probe by hand (writes nothing): synap import <a-file.md> --dry-run",
202
+ };
203
+ }
204
+ }
205
+ export async function doctor(opts = {}) {
206
+ const checks = [];
207
+ const activeName = listPodProfiles().find((p) => p.active)?.name ?? "default";
208
+ // Resolve lens FIRST so `--pod` / env / profile agree on URL + workspace
209
+ // (host check used to use only active profile → `synap --pod team doctor`
210
+ // reported perso's host while Active Lens showed team).
211
+ let cfgResolved;
212
+ try {
213
+ cfgResolved = await resolveHubConfig();
214
+ }
215
+ catch {
216
+ /* fall through to profile/env */
217
+ }
218
+ // ── (a) Host resolves — the pod is actually served at this URL ───────────
219
+ const localConfig = getActivePodConfig();
220
+ const podUrl = cfgResolved?.podUrl ?? localConfig?.podUrl ?? process.env.SYNAP_POD_URL;
221
+ if (!podUrl) {
222
+ checks.push({
223
+ name: "Pod URL configured",
224
+ ok: false,
225
+ detail: "no pod URL configured",
226
+ fix: "Run: synap init (or synap pods add, if you already have a pod)",
227
+ });
228
+ return finish(checks, opts, { podUrl: undefined, workspaceId: undefined, projectId: undefined });
229
+ }
230
+ let hostServed = false;
231
+ const names = {};
232
+ const health = await checkPodHealth(podUrl);
233
+ names.podVersion = health.version;
234
+ if (health.healthy) {
235
+ hostServed = true;
236
+ checks.push({
237
+ name: "Pod host resolves",
238
+ ok: true,
239
+ detail: `${podUrl} is served${health.version ? ` (v${health.version})` : ""}`,
240
+ });
241
+ }
242
+ else {
243
+ // The classic failure this check exists for: a saved profile URL that no
244
+ // longer resolves to a live pod — most often a stale/migrated domain, not
245
+ // a transient network blip (checkPodHealth already retried the timeout).
246
+ checks.push({
247
+ name: "Pod host resolves",
248
+ ok: false,
249
+ detail: `${podUrl} did not answer /health`,
250
+ fix: `Your profile URL may be stale. Run: synap pods list (see saved pods) — or: synap pods update ${activeName} <new-url>`,
251
+ });
252
+ }
253
+ // ── (b) Key authenticates against this pod ────────────────────────────────
254
+ let keyValid = false;
255
+ if (!hostServed) {
256
+ checks.push({
257
+ name: "API key authenticates",
258
+ ok: false,
259
+ detail: "skipped — pod host is unreachable",
260
+ fix: "Fix the pod host check above first.",
261
+ });
262
+ }
263
+ else {
264
+ try {
265
+ const cfg = cfgResolved ?? (await resolveHubConfig());
266
+ cfgResolved = cfg;
267
+ await hubGet("/users/me", {}, cfg);
268
+ keyValid = true;
269
+ checks.push({ name: "API key authenticates", ok: true, detail: "key accepted" });
270
+ }
271
+ catch (err) {
272
+ const is401 = err instanceof HubError ? err.status === 401 : false;
273
+ // Say WHY — awaiting approval, replaced, expired — never a guess.
274
+ const why = is401 && cfgResolved ? describeKeyState(await fetchKeyState(cfgResolved.podUrl, cfgResolved.apiKey)) : null;
275
+ checks.push({
276
+ name: "API key authenticates",
277
+ ok: false,
278
+ detail: is401 ? `the pod rejected this key: it ${why}` : `could not verify (${err instanceof Error ? err.message : String(err)})`,
279
+ fix: is401 ? "See the key health below — run: synap doctor --fix" : `Run: synap login --reconnect ${activeName}`,
280
+ });
281
+ }
282
+ }
283
+ // ── (c) Configured workspace/project exist on THIS pod ────────────────────
284
+ let workspaceOk = null;
285
+ let projectOk = null;
286
+ if (!keyValid || !cfgResolved) {
287
+ checks.push({
288
+ name: "Workspace + project exist on this pod",
289
+ ok: false,
290
+ detail: "skipped — key did not authenticate",
291
+ fix: "Fix the API key check above first.",
292
+ });
293
+ }
294
+ else {
295
+ try {
296
+ const res = (await hubGet("/orient", {}, cfgResolved));
297
+ const workspaces = res.workspaces ?? [];
298
+ const projects = res.projects ?? [];
299
+ if (cfgResolved.workspaceId) {
300
+ const match = workspaces.find((w) => w.id === cfgResolved.workspaceId);
301
+ workspaceOk = Boolean(match);
302
+ names.workspace = match?.name;
303
+ checks.push({
304
+ name: "Configured workspace exists on this pod",
305
+ ok: workspaceOk,
306
+ detail: workspaceOk
307
+ ? `${match.name} (${cfgResolved.workspaceId})`
308
+ : `workspace ${cfgResolved.workspaceId} not found among ${workspaces.length} workspace(s) on this pod`,
309
+ fix: workspaceOk ? undefined : "Run: synap orient (see valid workspaces on this pod), then: synap use <id>",
310
+ });
311
+ }
312
+ else {
313
+ checks.push({
314
+ name: "Configured workspace exists on this pod",
315
+ ok: true,
316
+ detail: "no workspace pinned — pod-wide lens",
317
+ });
318
+ }
319
+ if (cfgResolved.projectId) {
320
+ const match = projects.find((p) => p.id === cfgResolved.projectId);
321
+ projectOk = Boolean(match);
322
+ names.project = match?.name;
323
+ checks.push({
324
+ name: "Configured project exists on this pod",
325
+ ok: projectOk,
326
+ detail: projectOk
327
+ ? `${match.name} (${cfgResolved.projectId})`
328
+ : `project ${cfgResolved.projectId} not found among ${projects.length} project(s) on this pod`,
329
+ fix: projectOk ? undefined : "Run: synap orient (see valid projects on this pod), then: synap project use <id>",
330
+ });
331
+ }
332
+ }
333
+ catch (err) {
334
+ // Older pod without /orient (or a transient failure) — degrade, don't fail.
335
+ const is404 = err instanceof HubError && err.status === 404;
336
+ checks.push({
337
+ name: "Workspace + project exist on this pod",
338
+ ok: true,
339
+ detail: is404
340
+ ? "skipped — this pod does not expose /orient (older build)"
341
+ : `skipped — could not check (${err instanceof Error ? err.message : String(err)})`,
342
+ });
343
+ }
344
+ }
345
+ // ── (d) The Intelligence Service the capture/import pipeline depends on ───
346
+ // Doctor used to stop at config coherence and print "All checks passed"
347
+ // while POST /api/hub/capture/structure was 502-ing — a diagnostic that
348
+ // reports all-clear over a dead core dependency actively misdirects.
349
+ if (!keyValid || !cfgResolved) {
350
+ checks.push({
351
+ name: "Intelligence Service reachable",
352
+ ok: false,
353
+ unknown: true,
354
+ detail: "could not determine — the key did not authenticate, so the pod's dependency probe was not called",
355
+ fix: "Fix the API key check above first.",
356
+ });
357
+ }
358
+ else {
359
+ checks.push(intelligenceCheck(await probeIntelligence(cfgResolved)));
360
+ }
361
+ // ── (e) The connection broker, and why it fails when it does ─────────────
362
+ if (!keyValid || !cfgResolved) {
363
+ checks.push({
364
+ name: BROKER_CHECK_NAME,
365
+ ok: false,
366
+ unknown: true,
367
+ detail: "could not determine — the key did not authenticate",
368
+ fix: "Fix the API key check above first.",
369
+ });
370
+ }
371
+ else {
372
+ const [providers, diagnostics] = await Promise.all([
373
+ probeBrokerProviders(cfgResolved),
374
+ probeBrokerDiagnostics(cfgResolved),
375
+ ]);
376
+ checks.push(brokerCheck(providers, diagnostics));
377
+ }
378
+ // ── (f) Every key configured for this pod, and why each one fails ───────
379
+ let keyHealth;
380
+ if (hostServed) {
381
+ const { checkKeyHealth, keyProblems } = await import("../lib/key-doctor.js");
382
+ keyHealth = await checkKeyHealth(cfgResolved?.podUrl ?? podUrl);
383
+ const problems = keyProblems(keyHealth);
384
+ const failing = problems.filter((d) => d.severity === "error");
385
+ const unverifiable = problems.filter((d) => d.code === "unverifiable");
386
+ const why = [...new Set(unverifiable.map((d) => (d.key && keyHealth.states.get(d.key)?.error) || "no answer"))].join("; ");
387
+ checks.push({
388
+ name: "Keys on this computer",
389
+ ok: problems.length === 0,
390
+ unknown: problems.length > 0 && failing.length === 0 && problems.every((d) => d.code === "unverifiable"),
391
+ detail: problems.length === 0
392
+ ? `${keyHealth.locations.length} configured cop${keyHealth.locations.length === 1 ? "y" : "ies"}, all working`
393
+ : unverifiable.length === problems.length
394
+ ? `${unverifiable.length} key${unverifiable.length === 1 ? "" : "s"} could not be checked (${why})`
395
+ : `${problems.length} problem${problems.length === 1 ? "" : "s"}`,
396
+ // Only a problem --fix can act on earns the --fix hint.
397
+ fix: problems.some(isFixable) ? "Run: synap doctor --fix" : undefined,
398
+ });
399
+ }
400
+ await finish(checks, opts, {
401
+ // Prefer the pod resolveHubConfig actually hit — health-check URL can lag
402
+ // the active profile when the shell is env-pinned to another pod.
403
+ podUrl: cfgResolved?.podUrl ?? podUrl,
404
+ workspaceId: cfgResolved?.workspaceId,
405
+ projectId: cfgResolved?.projectId,
406
+ ...names,
407
+ }, keyHealth, cfgResolved);
408
+ }
409
+ /**
410
+ * Call the pod's dependency probe. Every failure mode that is not a positive
411
+ * "the IS is down" answer maps to `unknown` — an older pod that 404s the door
412
+ * must never read as healthy.
413
+ */
414
+ async function probeIntelligence(cfg) {
415
+ try {
416
+ // Pass the configured workspace so the pod resolves the IS exactly as a
417
+ // capture FROM THAT WORKSPACE would (resolution is capability → workspace →
418
+ // user → pod default). A pod-level probe could pass while the workspace the
419
+ // user actually imports into routes to a dead service.
420
+ return readIntelligenceHealth(await hubGet("/health/dependencies", { workspaceId: cfg.workspaceId }, cfg));
421
+ }
422
+ catch (err) {
423
+ if (err instanceof HubError && err.status === 404) {
424
+ return {
425
+ state: "unknown",
426
+ detail: "this pod does not expose GET /api/hub/health/dependencies (older build)",
427
+ };
428
+ }
429
+ if (err instanceof HubError && err.status === 403) {
430
+ return {
431
+ state: "unknown",
432
+ detail: "this key lacks the hub-protocol.read scope needed to read the dependency probe",
433
+ };
434
+ }
435
+ // The probe itself failing is not proof the IS is down — say only that.
436
+ return {
437
+ state: "unknown",
438
+ detail: `the dependency probe did not answer (${err instanceof Error ? err.message : String(err)})`,
439
+ };
440
+ }
441
+ }
442
+ const BROKER_CHECK_NAME = "Connection broker";
443
+ export function readProvidersEnvelope(payload) {
444
+ if (!payload || typeof payload !== "object") {
445
+ return { state: "unknown", detail: "the providers door returned no payload" };
446
+ }
447
+ const p = payload;
448
+ if (p.nangoStatus === "ok")
449
+ return { state: "ok" };
450
+ if (p.nangoStatus === "error") {
451
+ return {
452
+ state: "error",
453
+ reason: typeof p.nangoError?.reason === "string" ? p.nangoError.reason : "unknown",
454
+ message: typeof p.nangoError?.message === "string" ? p.nangoError.message : undefined,
455
+ };
456
+ }
457
+ return { state: "unknown", detail: "the providers door carried no readable nangoStatus" };
458
+ }
459
+ export function readBrokerDiagnostics(payload) {
460
+ const r = payload;
461
+ const readable = !!r &&
462
+ typeof r.cpIssuer?.present === "boolean" &&
463
+ typeof r.cpIssuer?.hasSourceConfigWrite === "boolean" &&
464
+ typeof r.ownerIdentityLink?.present === "boolean" &&
465
+ typeof r.relayCredential?.present === "boolean" &&
466
+ typeof r.broker?.kind === "string";
467
+ if (!readable) {
468
+ return { state: "unknown", detail: "the broker diagnostics payload was not readable" };
469
+ }
470
+ return { state: "read", report: r };
471
+ }
472
+ /** The one fix for a broker fault, sharpened by the trust diagnostics when readable. */
473
+ export function brokerFixHint(reason, diagnostics, message) {
474
+ if (reason === "broker-credential-missing") {
475
+ if (diagnostics.state !== "read") {
476
+ return "The pod holds no usable relay key from its control plane. Its trust state is unreadable here (needs a pod owner/admin key on a pod serving /connectors/broker-diagnostics) — check the control plane log for the relay-key delivery refusal, then rotate the pod's relay key from the control plane.";
477
+ }
478
+ return credentialMissingHint(diagnostics.report);
479
+ }
480
+ switch (reason) {
481
+ case "unauthenticated":
482
+ return "The broker rejected this pod's credential. Rotate the pod's relay key from the control plane (or, for a self-brokered pod, re-save its Nango key).";
483
+ case "unreachable":
484
+ return "The broker did not answer. Check that the control plane / Nango host is up and reachable from the pod.";
485
+ case "vault-unreadable":
486
+ return "The pod could not decrypt its broker credential. Check VAULT_SERVER_KEY on the pod.";
487
+ case "vault-unresolved":
488
+ return "The pod holds a relay key from its control plane but cannot read it from its vault. Rotate the pod's relay key from the control plane — it re-delivers a readable key.";
489
+ case "db-unavailable":
490
+ return "The pod could not read its database. Check the pod's health and logs.";
491
+ default:
492
+ return message ?? `The broker reported ${reason}.`;
493
+ }
494
+ }
495
+ function credentialMissingHint(r) {
496
+ if (!r.cpIssuer.present) {
497
+ return "The pod has no control plane issuer, so it cannot accept a relay key. Check CONTROL_PLANE_URL on the pod and restart it, then rotate the relay key from the control plane.";
498
+ }
499
+ if (r.cpIssuer.status !== "approved" || !r.cpIssuer.hasSourceConfigWrite) {
500
+ return "Approve the Synap Control Plane issuer with 'Configure data sources' (source-config:write) in pod-admin → Trust & Keys → Trusted issuers, then rotate the relay key from the control plane.";
501
+ }
502
+ if (!r.ownerIdentityLink.present) {
503
+ return "The pod owner's control plane identity is not linked on this pod, so relay-key delivery is refused. Link it (sign in to this pod through the control plane), then rotate the relay key from the control plane.";
504
+ }
505
+ return "Trust is in place but no valid relay key has been delivered. Rotate the pod's relay key from the control plane.";
506
+ }
507
+ /** Human summary of the trust facts; "unknown" for any part that could not be read. */
508
+ function describeBrokerTrust(diagnostics) {
509
+ if (diagnostics.state !== "read") {
510
+ return `broker kind unknown; credential unknown; issuer unknown; owner link unknown (${diagnostics.detail})`;
511
+ }
512
+ const r = diagnostics.report;
513
+ const credential = !r.relayCredential.present
514
+ ? "credential missing"
515
+ : r.relayCredential.resolvable === false
516
+ ? "credential present but unreadable"
517
+ : `credential present, valid until ${r.relayCredential.validUntil ?? "unknown"}`;
518
+ if (r.broker.kind !== "control-plane") {
519
+ return `broker ${r.broker.kind}`;
520
+ }
521
+ const issuer = !r.cpIssuer.present
522
+ ? "CP issuer missing"
523
+ : r.cpIssuer.status === "approved" && r.cpIssuer.hasSourceConfigWrite
524
+ ? "CP issuer ok"
525
+ : `CP issuer ${r.cpIssuer.status ?? "unknown"}${r.cpIssuer.hasSourceConfigWrite ? "" : " without source-config:write"}`;
526
+ const link = r.ownerIdentityLink.present ? "owner link ok" : "owner link missing";
527
+ return `broker ${r.broker.kind}; ${credential}; ${issuer}; ${link}`;
528
+ }
529
+ export function brokerCheck(providers, diagnostics) {
530
+ const trust = describeBrokerTrust(diagnostics);
531
+ if (providers.state === "unknown") {
532
+ return {
533
+ name: BROKER_CHECK_NAME,
534
+ ok: false,
535
+ unknown: true,
536
+ detail: `could not determine — ${providers.detail}; ${trust}`,
537
+ fix: "This pod build may predate GET /api/hub/connectors/providers, or the key lacks hub-protocol.read.",
538
+ };
539
+ }
540
+ if (providers.state === "not-configured") {
541
+ return {
542
+ name: BROKER_CHECK_NAME,
543
+ ok: true,
544
+ detail: "no connection broker is configured on this pod — connectors are unavailable",
545
+ };
546
+ }
547
+ if (providers.state === "ok") {
548
+ return { name: BROKER_CHECK_NAME, ok: true, detail: `broker answered; ${trust}` };
549
+ }
550
+ return {
551
+ name: BROKER_CHECK_NAME,
552
+ ok: false,
553
+ detail: `${providers.reason}; ${trust}`,
554
+ fix: brokerFixHint(providers.reason, diagnostics, providers.message),
555
+ };
556
+ }
557
+ async function probeBrokerProviders(cfg) {
558
+ try {
559
+ return readProvidersEnvelope(await hubGet("/connectors/providers", {}, cfg));
560
+ }
561
+ catch (err) {
562
+ const body = err instanceof HubError ? err.body : undefined;
563
+ if (err instanceof HubError && err.status === 503 && body?.error === "Nango not configured") {
564
+ return { state: "not-configured" };
565
+ }
566
+ return {
567
+ state: "unknown",
568
+ detail: `the providers door did not answer (${err instanceof Error ? err.message : String(err)})`,
569
+ };
570
+ }
571
+ }
572
+ async function probeBrokerDiagnostics(cfg) {
573
+ try {
574
+ return readBrokerDiagnostics(await hubGet("/connectors/broker-diagnostics", {}, cfg));
575
+ }
576
+ catch (err) {
577
+ if (err instanceof HubError && err.status === 404) {
578
+ return { state: "unknown", detail: "this pod does not expose broker diagnostics (older build)" };
579
+ }
580
+ if (err instanceof HubError && err.status === 403) {
581
+ return { state: "unknown", detail: "broker diagnostics need a pod owner/admin key" };
582
+ }
583
+ return {
584
+ state: "unknown",
585
+ detail: `broker diagnostics did not answer (${err instanceof Error ? err.message : String(err)})`,
586
+ };
587
+ }
588
+ }
589
+ /**
590
+ * Build the same provenance rungs as `synap lens` (session › directory › env ›
591
+ * global), pod-qualified against the active pod so a cross-pod directory lens
592
+ * is not claimed as the origin.
593
+ */
594
+ async function activeLensProvenance(podUrl) {
595
+ const { getClaudeSessionId, resolveActiveLensForPod } = await import("../lib/session-lens.js");
596
+ const { resolveDirectoryLensForPod, effectiveDirectoryLens } = await import("../lib/directory-lens.js");
597
+ const session = getClaudeSessionId();
598
+ const sessionLens = resolveActiveLensForPod(podUrl);
599
+ const dir = resolveDirectoryLensForPod(podUrl);
600
+ const rungs = [
601
+ { source: "session", detail: session ? session.slice(0, 8) : undefined, ...(sessionLens ?? {}) },
602
+ { source: "directory", detail: dir?.file, ...(dir ? effectiveDirectoryLens(dir.lens) : {}) },
603
+ {
604
+ source: "env",
605
+ detail: "SYNAP_WORKSPACE_ID",
606
+ workspaceId: process.env.SYNAP_WORKSPACE_ID,
607
+ projectId: process.env.SYNAP_PROJECT_ID,
608
+ },
609
+ {
610
+ source: "global",
611
+ detail: "~/.synap/config.json",
612
+ workspaceId: getActiveWorkspaceId(),
613
+ projectId: getActiveProjectId(),
614
+ },
615
+ ];
616
+ return resolveLensProvenance(rungs);
617
+ }
618
+ /** A diagnosis for JSON output — never a key's plaintext. */
619
+ function publicDiagnosis(d) {
620
+ return {
621
+ code: d.code,
622
+ severity: d.severity,
623
+ surface: d.surface,
624
+ title: d.title,
625
+ lines: d.lines,
626
+ command: d.command,
627
+ action: d.action,
628
+ approvalUrl: d.approvalUrl,
629
+ locations: d.locations.map((l) => l.label),
630
+ };
631
+ }
632
+ /** One word per check for the collapsed "✓ Pod · key · …" line. */
633
+ const SHORT_NAME = {
634
+ "Pod URL configured": "pod URL",
635
+ "Pod host resolves": "Pod",
636
+ "API key authenticates": "key",
637
+ "Configured workspace exists on this pod": "workspace",
638
+ "Configured project exists on this pod": "project",
639
+ "Workspace + project exist on this pod": "workspace",
640
+ [IS_CHECK_NAME]: "intelligence",
641
+ [BROKER_CHECK_NAME]: "broker",
642
+ "Keys on this computer": "agent keys",
643
+ };
644
+ const UUID = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi;
645
+ const ISO = /\b(\d{4}-\d{2}-\d{2})T\d{2}:\d{2}(:\d{2}(\.\d+)?)?(Z|[+-]\d{2}:?\d{2})?/g;
646
+ const INTERNAL_URL = /\s*(?:at\s+)?\bhttps?:\/\/(?:localhost|127\.\d+\.\d+\.\d+|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(?:1[6-9]|2\d|3[01])\.\d+\.\d+|[a-z0-9-]+(?::\d+)?(?=[\s/)]|$))[^\s)]*/gi;
647
+ /**
648
+ * Default output never shows internal addresses, ids or raw timestamps — they
649
+ * are noise to a person and stay one `-v` away. A parenthetical that only
650
+ * carried an id ("(checked as workspace <uuid>)") goes entirely.
651
+ */
652
+ export function forDisplay(text, verbose = false) {
653
+ if (verbose)
654
+ return text;
655
+ return text
656
+ .replace(/\s*\([^()]*\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b[^()]*\)/gi, "")
657
+ .replace(UUID, "…")
658
+ .replace(INTERNAL_URL, "")
659
+ .replace(ISO, "$1")
660
+ .replace(/\s{2,}/g, " ")
661
+ .trim();
662
+ }
663
+ /** Where a lens field came from, short: "./.synap/lens.json", "SYNAP_WORKSPACE_ID", "this Claude session". */
664
+ function lensOrigin(p) {
665
+ if (!p)
666
+ return undefined;
667
+ if (p.source === "session")
668
+ return "this Claude session";
669
+ if (p.source === "env")
670
+ return p.detail ?? "environment";
671
+ if (p.source === "global")
672
+ return "~/.synap/config.json";
673
+ if (p.detail) {
674
+ const rel = path.relative(process.cwd(), p.detail);
675
+ return rel && !rel.startsWith("..") && !path.isAbsolute(rel) ? `./${rel}` : tildify(p.detail, os.homedir());
676
+ }
677
+ return p.source;
678
+ }
679
+ async function finish(checks, opts, lens, keyHealth, hubCfg) {
680
+ // Green requires every check to have VERIFIED something. An undetermined
681
+ // check suppresses green (it is not a pass) but does not fail the run — only
682
+ // a proven failure sets a non-zero exit code.
683
+ const allOk = checks.every((c) => c.ok);
684
+ const anyFailed = checks.some((c) => !c.ok && !c.unknown);
685
+ const anyUnknown = checks.some((c) => c.unknown);
686
+ const activeName = listPodProfiles().find((p) => p.active)?.name ?? "default";
687
+ const keySource = resolveKeySource();
688
+ const provenance = await activeLensProvenance(lens.podUrl);
689
+ if (opts.json) {
690
+ console.log(JSON.stringify({
691
+ ok: allOk,
692
+ undetermined: anyUnknown,
693
+ checks,
694
+ keyHealth: keyHealth ? keyHealth.diagnoses.map(publicDiagnosis) : null,
695
+ keysNotChecked: keyHealth
696
+ ? {
697
+ unreadable: keyHealth.unchecked ?? [],
698
+ notSentToThisPod: (keyHealth.notSent ?? []).map((l) => l.label),
699
+ }
700
+ : null,
701
+ cli: cliBuild(),
702
+ lens: {
703
+ pod: activeName,
704
+ podUrl: lens.podUrl,
705
+ workspaceId: lens.workspaceId,
706
+ projectId: lens.projectId,
707
+ keySource,
708
+ provenance,
709
+ },
710
+ }, null, 2));
711
+ if (anyFailed)
712
+ process.exitCode = 1;
713
+ return;
714
+ }
715
+ const v = !!opts.verbose;
716
+ const show = (t) => forDisplay(t, v);
717
+ // ── Header: which pod, which lens — names, not ids ──────────────────────
718
+ const lensPodName = (lens.podUrl &&
719
+ listPodProfiles().find((p) => p.config.podUrl.replace(/\/$/, "") === lens.podUrl.replace(/\/$/, ""))?.name) ||
720
+ activeName;
721
+ let host = lens.podUrl ?? "no pod";
722
+ try {
723
+ if (lens.podUrl)
724
+ host = new URL(lens.podUrl).host;
725
+ }
726
+ catch {
727
+ /* keep raw */
728
+ }
729
+ log.blank();
730
+ console.log(`${chalk.bold("synap doctor")} ${chalk.dim("·")} ${lensPodName} ${chalk.dim("·")} ${host}${lens.podVersion ? chalk.dim(` (v${lens.podVersion})`) : ""}`);
731
+ const wsName = lens.workspaceId ? lens.workspace ?? (v ? lens.workspaceId : "a workspace this pod does not list") : "pod-wide";
732
+ const lensText = lens.projectId ? `${wsName} › ${lens.project ?? (v ? lens.projectId : "a project this pod does not list")}` : wsName;
733
+ const origin = lensOrigin(provenance.project ?? provenance.workspace);
734
+ console.log(`${chalk.dim("Lens")} ${lensText}${origin && (lens.workspaceId || lens.projectId) ? chalk.dim(` (from ${origin})`) : ""}`);
735
+ // Which build is talking: a stale CLI is the first thing to rule out.
736
+ console.log(`${chalk.dim("CLI")} ${formatCliBuild(cliBuild())}`);
737
+ if (v) {
738
+ console.log(`${chalk.dim("Key")} ${formatKeySource(keySource)}`);
739
+ if (lens.podUrl)
740
+ console.log(`${chalk.dim("URL")} ${lens.podUrl}`);
741
+ }
742
+ log.blank();
743
+ // ── Checks: passes collapse to one line, failures/unknowns in full ───────
744
+ const keyRow = checks.find((c) => c.name === "Keys on this computer");
745
+ const printRow = (c) => {
746
+ const mark = c.ok ? chalk.green("✓") : c.unknown ? chalk.yellow("?") : chalk.red("✗");
747
+ console.log(`${mark} ${chalk.bold(c.name)} — ${show(c.detail)}`);
748
+ if (!c.ok && c.fix)
749
+ console.log(chalk.dim(` → ${show(c.fix)}`));
750
+ };
751
+ const passed = checks.filter((c) => c.ok);
752
+ if (v)
753
+ for (const c of checks)
754
+ printRow(c);
755
+ else if (passed.length) {
756
+ const words = [...new Set(passed.map((c) => SHORT_NAME[c.name] ?? c.name))];
757
+ console.log(`${chalk.green("✓")} ${words.join(" · ")}${chalk.dim(" (details with -v)")}`);
758
+ }
759
+ if (!v)
760
+ for (const c of checks.filter((c) => !c.ok && c !== keyRow))
761
+ printRow(c);
762
+ // The key row's problems are the key-health lines themselves — no second copy.
763
+ if (keyHealth) {
764
+ const { printKeyHealth, fixKeyHealth, keyProblems } = await import("../lib/key-doctor.js");
765
+ printKeyHealth(keyHealth, { fixHint: !opts.fix, verbose: v, showOk: v, indent: "" });
766
+ if (opts.fix && keyProblems(keyHealth).some(isFixable)) {
767
+ log.blank();
768
+ console.log(chalk.bold("Fixing"));
769
+ const outcomes = await fixKeyHealth(keyHealth);
770
+ for (const o of outcomes)
771
+ console.log(` ${o.ok ? chalk.green("✓") : chalk.red("✗")} ${o.message}`);
772
+ // Every problem fixed AND verified live over MCP: the key row is green now.
773
+ if (keyRow && outcomes.length > 0 && outcomes.every((o) => o.ok)) {
774
+ keyRow.ok = true;
775
+ keyRow.unknown = false;
776
+ keyRow.detail = "fixed and verified (MCP initialize)";
777
+ }
778
+ }
779
+ }
780
+ // ── One agent, several computers ─────────────────────────────────────────
781
+ if (hubCfg) {
782
+ log.blank();
783
+ console.log(chalk.bold("Connected agents"));
784
+ await printAgentConnections(hubCfg);
785
+ }
786
+ // Env pin beats the active profile in resolveHubConfig — same divergence
787
+ // `synap pods list` already names. Surface it here so doctor alone is enough
788
+ // to catch "profile says perso, every write goes to team".
789
+ const envPod = process.env.SYNAP_POD_URL?.trim();
790
+ const activeProfile = listPodProfiles().find((p) => p.active);
791
+ if (envPod && activeProfile && !samePodOrigin(envPod, activeProfile.config.podUrl)) {
792
+ log.blank();
793
+ log.warn(`SYNAP_POD_URL overrides the active profile — commands are talking to ${envPod}, not ${activeProfile.config.podUrl}.`);
794
+ log.dim(" The env var wins over the ● active profile. Unset it (or open a fresh shell) for the profile to apply.");
795
+ }
796
+ // ── Verdict: the last line. Recomputed: --fix may have turned keys green.
797
+ const finalOk = checks.every((c) => c.ok);
798
+ const finalFailed = checks.some((c) => !c.ok && !c.unknown);
799
+ log.blank();
800
+ if (finalOk) {
801
+ console.log(chalk.green("✓ All checks passed."));
802
+ }
803
+ else if (finalFailed) {
804
+ const n = checks.filter((c) => !c.ok && !c.unknown).length;
805
+ console.log(chalk.red(`✗ ${n} check${n === 1 ? "" : "s"} failed — the actions above fix ${n === 1 ? "it" : "them"}.`));
806
+ process.exitCode = 1;
807
+ }
808
+ else {
809
+ // Not green: something could not be determined. Saying "all clear" here is
810
+ // the failure mode this command exists to avoid.
811
+ console.log(chalk.yellow("? Nothing failed, but not everything could be checked — see the ? lines."));
812
+ }
813
+ }
814
+ //# sourceMappingURL=doctor.js.map