@synap-core/cli 1.11.0 → 1.13.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 (533) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +40 -198
  3. package/dist/build-info.json +6 -0
  4. package/dist/commands/agent-run.js +3 -2
  5. package/dist/commands/agent-run.js.map +1 -1
  6. package/dist/commands/agents.d.ts +32 -17
  7. package/dist/commands/agents.js +203 -237
  8. package/dist/commands/agents.js.map +1 -1
  9. package/dist/commands/app.d.ts +143 -0
  10. package/dist/commands/app.js +524 -0
  11. package/dist/commands/app.js.map +1 -0
  12. package/dist/commands/automate.d.ts +21 -0
  13. package/dist/commands/automate.js +42 -0
  14. package/dist/commands/automate.js.map +1 -0
  15. package/dist/commands/automation-schema.test.d.ts +16 -0
  16. package/dist/commands/automation-schema.test.js +77 -0
  17. package/dist/commands/automation-schema.test.js.map +1 -0
  18. package/dist/commands/automation.d.ts +12 -0
  19. package/dist/commands/automation.js +116 -66
  20. package/dist/commands/automation.js.map +1 -1
  21. package/dist/commands/box.d.ts +42 -0
  22. package/dist/commands/box.js +89 -0
  23. package/dist/commands/box.js.map +1 -0
  24. package/dist/commands/bridge-setup.d.ts +14 -1
  25. package/dist/commands/bridge-setup.js +395 -129
  26. package/dist/commands/bridge-setup.js.map +1 -1
  27. package/dist/commands/cap-connections.d.ts +4 -4
  28. package/dist/commands/cap-connections.js +14 -14
  29. package/dist/commands/cap-connections.js.map +1 -1
  30. package/dist/commands/capability.d.ts +3 -1
  31. package/dist/commands/capability.js +249 -176
  32. package/dist/commands/capability.js.map +1 -1
  33. package/dist/commands/catalog.d.ts +275 -0
  34. package/dist/commands/catalog.js +481 -0
  35. package/dist/commands/catalog.js.map +1 -0
  36. package/dist/commands/cell.d.ts +155 -8
  37. package/dist/commands/cell.js +416 -40
  38. package/dist/commands/cell.js.map +1 -1
  39. package/dist/commands/centrality.js +1 -13
  40. package/dist/commands/centrality.js.map +1 -1
  41. package/dist/commands/close-questions.d.ts +27 -0
  42. package/dist/commands/close-questions.js +49 -0
  43. package/dist/commands/close-questions.js.map +1 -0
  44. package/dist/commands/close-questions.test.d.ts +1 -0
  45. package/dist/commands/close-questions.test.js +52 -0
  46. package/dist/commands/close-questions.test.js.map +1 -0
  47. package/dist/commands/connect.d.ts +36 -13
  48. package/dist/commands/connect.js +68 -167
  49. package/dist/commands/connect.js.map +1 -1
  50. package/dist/commands/connections.d.ts +3 -2
  51. package/dist/commands/connections.js +95 -25
  52. package/dist/commands/connections.js.map +1 -1
  53. package/dist/commands/context.js +79 -44
  54. package/dist/commands/context.js.map +1 -1
  55. package/dist/commands/data-extra.d.ts +34 -0
  56. package/dist/commands/data-extra.js +203 -25
  57. package/dist/commands/data-extra.js.map +1 -1
  58. package/dist/commands/data.d.ts +120 -2
  59. package/dist/commands/data.js +295 -21
  60. package/dist/commands/data.js.map +1 -1
  61. package/dist/commands/diagnose.d.ts +66 -4
  62. package/dist/commands/diagnose.js +285 -28
  63. package/dist/commands/diagnose.js.map +1 -1
  64. package/dist/commands/doc.d.ts +11 -4
  65. package/dist/commands/doc.js +39 -14
  66. package/dist/commands/doc.js.map +1 -1
  67. package/dist/commands/doctor.d.ts +133 -3
  68. package/dist/commands/doctor.js +761 -41
  69. package/dist/commands/doctor.js.map +1 -1
  70. package/dist/commands/explain.js +5 -5
  71. package/dist/commands/explain.js.map +1 -1
  72. package/dist/commands/hooks.d.ts +19 -0
  73. package/dist/commands/hooks.js +70 -0
  74. package/dist/commands/hooks.js.map +1 -0
  75. package/dist/commands/import.d.ts +393 -13
  76. package/dist/commands/import.js +1150 -54
  77. package/dist/commands/import.js.map +1 -1
  78. package/dist/commands/init.d.ts +34 -9
  79. package/dist/commands/init.js +481 -981
  80. package/dist/commands/init.js.map +1 -1
  81. package/dist/commands/keys.d.ts +1 -0
  82. package/dist/commands/keys.js +15 -2
  83. package/dist/commands/keys.js.map +1 -1
  84. package/dist/commands/knowledge.d.ts +22 -6
  85. package/dist/commands/knowledge.js +121 -57
  86. package/dist/commands/knowledge.js.map +1 -1
  87. package/dist/commands/lens.d.ts +37 -1
  88. package/dist/commands/lens.js +194 -72
  89. package/dist/commands/lens.js.map +1 -1
  90. package/dist/commands/market-authoring.d.ts +29 -2
  91. package/dist/commands/market-authoring.js +348 -7
  92. package/dist/commands/market-authoring.js.map +1 -1
  93. package/dist/commands/market-official.d.ts +58 -0
  94. package/dist/commands/market-official.js +84 -0
  95. package/dist/commands/market-official.js.map +1 -0
  96. package/dist/commands/market.d.ts +400 -16
  97. package/dist/commands/market.js +1802 -146
  98. package/dist/commands/market.js.map +1 -1
  99. package/dist/commands/mcp.d.ts +60 -25
  100. package/dist/commands/mcp.js +251 -64
  101. package/dist/commands/mcp.js.map +1 -1
  102. package/dist/commands/observe.category.test.d.ts +1 -0
  103. package/dist/commands/observe.category.test.js +59 -0
  104. package/dist/commands/observe.category.test.js.map +1 -0
  105. package/dist/commands/observe.d.ts +3 -0
  106. package/dist/commands/observe.js +7 -5
  107. package/dist/commands/observe.js.map +1 -1
  108. package/dist/commands/observe.title.test.d.ts +1 -0
  109. package/dist/commands/observe.title.test.js +37 -0
  110. package/dist/commands/observe.title.test.js.map +1 -0
  111. package/dist/commands/open.d.ts +39 -9
  112. package/dist/commands/open.js +80 -25
  113. package/dist/commands/open.js.map +1 -1
  114. package/dist/commands/playbook.d.ts +42 -0
  115. package/dist/commands/playbook.js +171 -0
  116. package/dist/commands/playbook.js.map +1 -0
  117. package/dist/commands/pod.js +1 -1
  118. package/dist/commands/pod.js.map +1 -1
  119. package/dist/commands/pods.d.ts +11 -1
  120. package/dist/commands/pods.js +129 -131
  121. package/dist/commands/pods.js.map +1 -1
  122. package/dist/commands/proposals-actions.d.ts +62 -0
  123. package/dist/commands/proposals-actions.js +143 -8
  124. package/dist/commands/proposals-actions.js.map +1 -1
  125. package/dist/commands/proposals-await.d.ts +68 -0
  126. package/dist/commands/proposals-await.js +248 -0
  127. package/dist/commands/proposals-await.js.map +1 -0
  128. package/dist/commands/proton-setup.d.ts +73 -0
  129. package/dist/commands/proton-setup.js +579 -0
  130. package/dist/commands/proton-setup.js.map +1 -0
  131. package/dist/commands/providers.d.ts +23 -0
  132. package/dist/commands/providers.js +126 -1
  133. package/dist/commands/providers.js.map +1 -1
  134. package/dist/commands/raycast.js +6 -2
  135. package/dist/commands/raycast.js.map +1 -1
  136. package/dist/commands/rule.d.ts +150 -0
  137. package/dist/commands/rule.js +447 -0
  138. package/dist/commands/rule.js.map +1 -0
  139. package/dist/commands/session-feed-wait.d.ts +48 -0
  140. package/dist/commands/session-feed-wait.js +261 -0
  141. package/dist/commands/session-feed-wait.js.map +1 -0
  142. package/dist/commands/session-post.d.ts +40 -0
  143. package/dist/commands/session-post.js +96 -0
  144. package/dist/commands/session-post.js.map +1 -0
  145. package/dist/commands/session-wait.d.ts +116 -0
  146. package/dist/commands/session-wait.js +224 -0
  147. package/dist/commands/session-wait.js.map +1 -0
  148. package/dist/commands/sessions.d.ts +54 -0
  149. package/dist/commands/sessions.js +501 -58
  150. package/dist/commands/sessions.js.map +1 -1
  151. package/dist/commands/skill-manage.d.ts +21 -0
  152. package/dist/commands/skill-manage.js +136 -19
  153. package/dist/commands/skill-manage.js.map +1 -1
  154. package/dist/commands/skills-commands.d.ts +2 -0
  155. package/dist/commands/skills-commands.js +9 -1
  156. package/dist/commands/skills-commands.js.map +1 -1
  157. package/dist/commands/skills-commands.test.d.ts +1 -0
  158. package/dist/commands/skills-commands.test.js +57 -0
  159. package/dist/commands/skills-commands.test.js.map +1 -0
  160. package/dist/commands/skills.js +16 -0
  161. package/dist/commands/skills.js.map +1 -1
  162. package/dist/commands/status.d.ts +1 -4
  163. package/dist/commands/status.js +6 -35
  164. package/dist/commands/status.js.map +1 -1
  165. package/dist/commands/statusline.backoff.test.d.ts +13 -0
  166. package/dist/commands/statusline.backoff.test.js +100 -0
  167. package/dist/commands/statusline.backoff.test.js.map +1 -0
  168. package/dist/commands/statusline.js +16 -9
  169. package/dist/commands/statusline.js.map +1 -1
  170. package/dist/commands/sync-status.d.ts +12 -0
  171. package/dist/commands/sync-status.js +125 -0
  172. package/dist/commands/sync-status.js.map +1 -0
  173. package/dist/commands/templates-retire.d.ts +34 -0
  174. package/dist/commands/templates-retire.js +192 -0
  175. package/dist/commands/templates-retire.js.map +1 -0
  176. package/dist/commands/tools.js +6 -21
  177. package/dist/commands/tools.js.map +1 -1
  178. package/dist/commands/tracks.d.ts +112 -0
  179. package/dist/commands/tracks.js +543 -0
  180. package/dist/commands/tracks.js.map +1 -0
  181. package/dist/commands/update.d.ts +3 -11
  182. package/dist/commands/update.js +5 -134
  183. package/dist/commands/update.js.map +1 -1
  184. package/dist/commands/upload.d.ts +41 -3
  185. package/dist/commands/upload.js +120 -18
  186. package/dist/commands/upload.js.map +1 -1
  187. package/dist/commands/vendor.d.ts +28 -0
  188. package/dist/commands/vendor.js +110 -0
  189. package/dist/commands/vendor.js.map +1 -0
  190. package/dist/commands/versions.js +6 -0
  191. package/dist/commands/versions.js.map +1 -1
  192. package/dist/commands/view.js +10 -5
  193. package/dist/commands/view.js.map +1 -1
  194. package/dist/commands/whoami.d.ts +30 -3
  195. package/dist/commands/whoami.js +186 -23
  196. package/dist/commands/whoami.js.map +1 -1
  197. package/dist/commands/worker-accounts.d.ts +149 -0
  198. package/dist/commands/worker-accounts.js +339 -0
  199. package/dist/commands/worker-accounts.js.map +1 -0
  200. package/dist/commands/worker-accounts.test.d.ts +1 -0
  201. package/dist/commands/worker-accounts.test.js +224 -0
  202. package/dist/commands/worker-accounts.test.js.map +1 -0
  203. package/dist/commands/worker.d.ts +331 -0
  204. package/dist/commands/worker.js +1067 -0
  205. package/dist/commands/worker.js.map +1 -0
  206. package/dist/commands/worker.test.d.ts +1 -0
  207. package/dist/commands/worker.test.js +427 -0
  208. package/dist/commands/worker.test.js.map +1 -0
  209. package/dist/commands/workspace-ops.d.ts +35 -0
  210. package/dist/commands/workspace-ops.js +153 -0
  211. package/dist/commands/workspace-ops.js.map +1 -0
  212. package/dist/index.d.ts +6 -6
  213. package/dist/index.js +1043 -186
  214. package/dist/index.js.map +1 -1
  215. package/dist/lib/agent-connections.d.ts +31 -0
  216. package/dist/lib/agent-connections.js +33 -0
  217. package/dist/lib/agent-connections.js.map +1 -0
  218. package/dist/lib/agent-detect.d.ts +27 -0
  219. package/dist/lib/agent-detect.js +71 -0
  220. package/dist/lib/agent-detect.js.map +1 -0
  221. package/dist/lib/agent-door.d.ts +136 -0
  222. package/dist/lib/agent-door.js +429 -0
  223. package/dist/lib/agent-door.js.map +1 -0
  224. package/dist/lib/agents-config.d.ts +2 -0
  225. package/dist/lib/agents-config.js +4 -9
  226. package/dist/lib/agents-config.js.map +1 -1
  227. package/dist/lib/approval-poll.d.ts +31 -2
  228. package/dist/lib/approval-poll.js +20 -7
  229. package/dist/lib/approval-poll.js.map +1 -1
  230. package/dist/lib/atomic-file.d.ts +48 -0
  231. package/dist/lib/atomic-file.js +129 -0
  232. package/dist/lib/atomic-file.js.map +1 -0
  233. package/dist/lib/auth.d.ts +17 -11
  234. package/dist/lib/auth.js +47 -64
  235. package/dist/lib/auth.js.map +1 -1
  236. package/dist/lib/batch-approval.d.ts +85 -0
  237. package/dist/lib/batch-approval.js +170 -0
  238. package/dist/lib/batch-approval.js.map +1 -0
  239. package/dist/lib/box/egress.d.ts +82 -0
  240. package/dist/lib/box/egress.js +264 -0
  241. package/dist/lib/box/egress.js.map +1 -0
  242. package/dist/lib/box/evidence.d.ts +86 -0
  243. package/dist/lib/box/evidence.js +121 -0
  244. package/dist/lib/box/evidence.js.map +1 -0
  245. package/dist/lib/box/job-server.d.ts +72 -0
  246. package/dist/lib/box/job-server.js +246 -0
  247. package/dist/lib/box/job-server.js.map +1 -0
  248. package/dist/lib/box/provisioner.d.ts +83 -0
  249. package/dist/lib/box/provisioner.js +312 -0
  250. package/dist/lib/box/provisioner.js.map +1 -0
  251. package/dist/lib/box/proxmox.d.ts +112 -0
  252. package/dist/lib/box/proxmox.js +211 -0
  253. package/dist/lib/box/proxmox.js.map +1 -0
  254. package/dist/lib/box/wire.d.ts +98 -0
  255. package/dist/lib/box/wire.js +70 -0
  256. package/dist/lib/box/wire.js.map +1 -0
  257. package/dist/lib/capture-lane.d.ts +6 -5
  258. package/dist/lib/capture-lane.js +6 -5
  259. package/dist/lib/capture-lane.js.map +1 -1
  260. package/dist/lib/capture-structure.d.ts +230 -11
  261. package/dist/lib/capture-structure.js +251 -13
  262. package/dist/lib/capture-structure.js.map +1 -1
  263. package/dist/lib/catalog-templates.d.ts +59 -0
  264. package/dist/lib/catalog-templates.js +126 -0
  265. package/dist/lib/catalog-templates.js.map +1 -0
  266. package/dist/lib/cli-build.d.ts +19 -0
  267. package/dist/lib/cli-build.js +37 -0
  268. package/dist/lib/cli-build.js.map +1 -0
  269. package/dist/lib/client-header.test.d.ts +1 -0
  270. package/dist/lib/client-header.test.js +85 -0
  271. package/dist/lib/client-header.test.js.map +1 -0
  272. package/dist/lib/conversation-headers.d.ts +33 -0
  273. package/dist/lib/conversation-headers.js +69 -0
  274. package/dist/lib/conversation-headers.js.map +1 -0
  275. package/dist/lib/cp-packages.d.ts +167 -11
  276. package/dist/lib/cp-packages.js +253 -21
  277. package/dist/lib/cp-packages.js.map +1 -1
  278. package/dist/lib/credential-class.d.ts +144 -0
  279. package/dist/lib/credential-class.js +138 -0
  280. package/dist/lib/credential-class.js.map +1 -0
  281. package/dist/lib/describe-lens.d.ts +35 -0
  282. package/dist/lib/describe-lens.js +40 -0
  283. package/dist/lib/describe-lens.js.map +1 -1
  284. package/dist/lib/device-connect.d.ts +125 -0
  285. package/dist/lib/device-connect.js +256 -0
  286. package/dist/lib/device-connect.js.map +1 -0
  287. package/dist/lib/directory-lens.d.ts +99 -0
  288. package/dist/lib/directory-lens.js +187 -0
  289. package/dist/lib/directory-lens.js.map +1 -0
  290. package/dist/lib/exporter-coverage.d.ts +71 -0
  291. package/dist/lib/exporter-coverage.js +97 -0
  292. package/dist/lib/exporter-coverage.js.map +1 -0
  293. package/dist/lib/goal-words.d.ts +38 -0
  294. package/dist/lib/goal-words.js +112 -0
  295. package/dist/lib/goal-words.js.map +1 -0
  296. package/dist/lib/hub-client.d.ts +57 -15
  297. package/dist/lib/hub-client.js +396 -82
  298. package/dist/lib/hub-client.js.map +1 -1
  299. package/dist/lib/init-connect.d.ts +41 -0
  300. package/dist/lib/init-connect.js +75 -0
  301. package/dist/lib/init-connect.js.map +1 -0
  302. package/dist/lib/init-exit.d.ts +24 -0
  303. package/dist/lib/init-exit.js +41 -0
  304. package/dist/lib/init-exit.js.map +1 -0
  305. package/dist/lib/init-flow.d.ts +25 -0
  306. package/dist/lib/init-flow.js +40 -0
  307. package/dist/lib/init-flow.js.map +1 -0
  308. package/dist/lib/init-handoff.d.ts +24 -0
  309. package/dist/lib/init-handoff.js +26 -0
  310. package/dist/lib/init-handoff.js.map +1 -0
  311. package/dist/lib/init-output.d.ts +18 -0
  312. package/dist/lib/init-output.js +43 -0
  313. package/dist/lib/init-output.js.map +1 -0
  314. package/dist/lib/init-pod.d.ts +45 -0
  315. package/dist/lib/init-pod.js +36 -0
  316. package/dist/lib/init-pod.js.map +1 -0
  317. package/dist/lib/installed.d.ts +210 -11
  318. package/dist/lib/installed.js +234 -36
  319. package/dist/lib/installed.js.map +1 -1
  320. package/dist/lib/key-approval.d.ts +57 -0
  321. package/dist/lib/key-approval.js +117 -0
  322. package/dist/lib/key-approval.js.map +1 -0
  323. package/dist/lib/key-diagnosis.d.ts +56 -0
  324. package/dist/lib/key-diagnosis.js +227 -0
  325. package/dist/lib/key-diagnosis.js.map +1 -0
  326. package/dist/lib/key-doctor.d.ts +136 -0
  327. package/dist/lib/key-doctor.js +286 -0
  328. package/dist/lib/key-doctor.js.map +1 -0
  329. package/dist/lib/key-locations.d.ts +120 -0
  330. package/dist/lib/key-locations.js +326 -0
  331. package/dist/lib/key-locations.js.map +1 -0
  332. package/dist/lib/key-source.d.ts +68 -0
  333. package/dist/lib/key-source.js +109 -0
  334. package/dist/lib/key-source.js.map +1 -0
  335. package/dist/lib/key-state.d.ts +70 -0
  336. package/dist/lib/key-state.js +115 -0
  337. package/dist/lib/key-state.js.map +1 -0
  338. package/dist/lib/kind-package.d.ts +181 -0
  339. package/dist/lib/kind-package.js +679 -0
  340. package/dist/lib/kind-package.js.map +1 -0
  341. package/dist/lib/knowledge-title.d.ts +25 -0
  342. package/dist/lib/knowledge-title.js +47 -0
  343. package/dist/lib/knowledge-title.js.map +1 -0
  344. package/dist/lib/knowledge-title.test.d.ts +1 -0
  345. package/dist/lib/knowledge-title.test.js +34 -0
  346. package/dist/lib/knowledge-title.test.js.map +1 -0
  347. package/dist/lib/machine-instance.d.ts +64 -0
  348. package/dist/lib/machine-instance.js +142 -0
  349. package/dist/lib/machine-instance.js.map +1 -0
  350. package/dist/lib/mcp-bridge.d.ts +49 -0
  351. package/dist/lib/mcp-bridge.js +180 -0
  352. package/dist/lib/mcp-bridge.js.map +1 -0
  353. package/dist/lib/mcp-bridge.test.d.ts +1 -0
  354. package/dist/lib/mcp-bridge.test.js +118 -0
  355. package/dist/lib/mcp-bridge.test.js.map +1 -0
  356. package/dist/lib/mcp-call.d.ts +30 -0
  357. package/dist/lib/mcp-call.js +107 -0
  358. package/dist/lib/mcp-call.js.map +1 -0
  359. package/dist/lib/mcp-snippets.d.ts +53 -0
  360. package/dist/lib/mcp-snippets.js +82 -0
  361. package/dist/lib/mcp-snippets.js.map +1 -0
  362. package/dist/lib/next-steps.d.ts +8 -0
  363. package/dist/lib/next-steps.js +31 -1
  364. package/dist/lib/next-steps.js.map +1 -1
  365. package/dist/lib/openclaw.js +3 -2
  366. package/dist/lib/openclaw.js.map +1 -1
  367. package/dist/lib/package-wire.d.ts +179 -0
  368. package/dist/lib/package-wire.js +68 -0
  369. package/dist/lib/package-wire.js.map +1 -0
  370. package/dist/lib/pair-link.d.ts +38 -0
  371. package/dist/lib/pair-link.js +68 -0
  372. package/dist/lib/pair-link.js.map +1 -0
  373. package/dist/lib/pod-moved.d.ts +70 -0
  374. package/dist/lib/pod-moved.js +146 -0
  375. package/dist/lib/pod-moved.js.map +1 -0
  376. package/dist/lib/pod-reach.d.ts +39 -0
  377. package/dist/lib/pod-reach.js +117 -0
  378. package/dist/lib/pod-reach.js.map +1 -0
  379. package/dist/lib/pod-reach.test.d.ts +1 -0
  380. package/dist/lib/pod-reach.test.js +67 -0
  381. package/dist/lib/pod-reach.test.js.map +1 -0
  382. package/dist/lib/pod-wide.d.ts +40 -0
  383. package/dist/lib/pod-wide.js +46 -0
  384. package/dist/lib/pod-wide.js.map +1 -0
  385. package/dist/lib/pod.d.ts +74 -112
  386. package/dist/lib/pod.js +146 -415
  387. package/dist/lib/pod.js.map +1 -1
  388. package/dist/lib/project-ref.d.ts +9 -3
  389. package/dist/lib/project-ref.js +10 -4
  390. package/dist/lib/project-ref.js.map +1 -1
  391. package/dist/lib/register-claude-code-mcp.test.d.ts +1 -0
  392. package/dist/lib/register-claude-code-mcp.test.js +78 -0
  393. package/dist/lib/register-claude-code-mcp.test.js.map +1 -0
  394. package/dist/lib/review-credential.d.ts +119 -0
  395. package/dist/lib/review-credential.js +149 -0
  396. package/dist/lib/review-credential.js.map +1 -0
  397. package/dist/lib/safe-open.d.ts +49 -0
  398. package/dist/lib/safe-open.js +119 -0
  399. package/dist/lib/safe-open.js.map +1 -0
  400. package/dist/lib/session-feed.d.ts +185 -0
  401. package/dist/lib/session-feed.js +257 -0
  402. package/dist/lib/session-feed.js.map +1 -0
  403. package/dist/lib/session-lens.d.ts +40 -1
  404. package/dist/lib/session-lens.js +54 -4
  405. package/dist/lib/session-lens.js.map +1 -1
  406. package/dist/lib/superwhisper-import.d.ts +8 -0
  407. package/dist/lib/superwhisper-import.js +14 -7
  408. package/dist/lib/superwhisper-import.js.map +1 -1
  409. package/dist/lib/superwhisper-title.test.d.ts +1 -0
  410. package/dist/lib/superwhisper-title.test.js +18 -0
  411. package/dist/lib/superwhisper-title.test.js.map +1 -0
  412. package/dist/lib/targets.d.ts +152 -10
  413. package/dist/lib/targets.js +974 -325
  414. package/dist/lib/targets.js.map +1 -1
  415. package/dist/lib/template-file.d.ts +4 -0
  416. package/dist/lib/template-file.js.map +1 -1
  417. package/dist/lib/template-lifecycle.d.ts +217 -0
  418. package/dist/lib/template-lifecycle.js +433 -0
  419. package/dist/lib/template-lifecycle.js.map +1 -0
  420. package/dist/lib/template-steps.d.ts +88 -0
  421. package/dist/lib/template-steps.js +118 -0
  422. package/dist/lib/template-steps.js.map +1 -0
  423. package/dist/lib/time-ago.d.ts +2 -0
  424. package/dist/lib/time-ago.js +15 -0
  425. package/dist/lib/time-ago.js.map +1 -0
  426. package/dist/lib/wake-hook-settings.d.ts +57 -0
  427. package/dist/lib/wake-hook-settings.js +153 -0
  428. package/dist/lib/wake-hook-settings.js.map +1 -0
  429. package/dist/lib/wake-state.d.ts +65 -0
  430. package/dist/lib/wake-state.js +122 -0
  431. package/dist/lib/wake-state.js.map +1 -0
  432. package/dist/utils/logger.js +5 -2
  433. package/dist/utils/logger.js.map +1 -1
  434. package/package.json +26 -17
  435. package/skills/README.md +13 -11
  436. package/skills/agent-os/SKILL.md +214 -99
  437. package/skills/manifest.json +1 -1
  438. package/skills/onboard/SKILL.md +55 -26
  439. package/skills/synap/README.md +5 -8
  440. package/skills/synap/SKILL.md +1149 -289
  441. package/skills/synap/_order.txt +7 -0
  442. package/skills/synap/_skill.yaml +1 -1
  443. package/skills/synap/automations.md +15 -0
  444. package/skills/synap/capture.md +5 -0
  445. package/skills/synap/cli-operations.md +24 -18
  446. package/skills/synap/code-skills.md +70 -0
  447. package/skills/synap/concepts.md +36 -0
  448. package/skills/synap/content-os.md +10 -1
  449. package/skills/synap/creative-loop.md +15 -10
  450. package/skills/synap/crm.md +21 -52
  451. package/skills/synap/document-embeds.md +143 -47
  452. package/skills/synap/escalation-ladder.md +20 -10
  453. package/skills/synap/focus-sessions.md +56 -21
  454. package/skills/synap/from-intent.md +158 -0
  455. package/skills/synap/governance-rules.md +5 -5
  456. package/skills/synap/governance.md +10 -7
  457. package/skills/synap/hand-off.md +33 -0
  458. package/skills/synap/inline-patterns.md +15 -7
  459. package/skills/synap/lenses.md +34 -16
  460. package/skills/synap/linking.md +42 -41
  461. package/skills/synap/mcp-remote-servers.md +64 -0
  462. package/skills/synap/mental-model.md +17 -15
  463. package/skills/synap/operating-mode-rules.md +2 -2
  464. package/skills/synap/processes.md +118 -0
  465. package/skills/synap/quick-reference.md +7 -2
  466. package/skills/synap/reading.md +3 -1
  467. package/skills/synap/reflexes.md +12 -42
  468. package/skills/synap/viewframe-cells.md +38 -5
  469. package/skills/synap/work-flow.md +1 -1
  470. package/skills/synap/work-model.md +110 -0
  471. package/skills/synap/worked-examples.md +4 -5
  472. package/skills/synap/workspace-design.md +15 -11
  473. package/skills/synap/writes.md +105 -25
  474. package/skills/synap/writing-titles.md +63 -0
  475. package/skills/synap-app/SKILL.md +149 -67
  476. package/skills/synap-app/_skill.yaml +1 -1
  477. package/skills/synap-app/creating-the-base-app.md +12 -7
  478. package/skills/synap-app/governance.md +27 -16
  479. package/skills/synap-app/install-commands.md +18 -9
  480. package/skills/synap-app/overview.md +16 -9
  481. package/skills/synap-app/using-the-sdk.md +75 -25
  482. package/skills/synap-design/SKILL.md +474 -0
  483. package/skills/synap-design/_order.txt +4 -0
  484. package/skills/synap-design/_skill.yaml +21 -0
  485. package/skills/synap-design/loop.md +134 -0
  486. package/skills/synap-design/overview.md +44 -0
  487. package/skills/synap-design/principles.md +130 -0
  488. package/skills/synap-design/system.md +133 -0
  489. package/skills/synap-market/SKILL.md +306 -16
  490. package/skills/synap-market/_skill.yaml +1 -1
  491. package/skills/synap-market/author-and-publish.md +145 -8
  492. package/skills/synap-market/governance-and-catalog.md +7 -0
  493. package/skills/synap-market/install.md +79 -1
  494. package/skills/synap-market/overview.md +74 -6
  495. package/skills/synap-schema/SKILL.md +172 -10
  496. package/skills/synap-schema/_order.txt +2 -0
  497. package/skills/synap-schema/_skill.yaml +4 -2
  498. package/skills/synap-schema/common-mistakes.md +4 -2
  499. package/skills/synap-schema/discover-profiles.md +1 -1
  500. package/skills/synap-schema/entity-scope.md +15 -3
  501. package/skills/synap-schema/extend-first.md +29 -0
  502. package/skills/synap-schema/extend-vs-create.md +1 -1
  503. package/skills/synap-schema/intent-vocabulary-ssot.md +111 -0
  504. package/skills/synap-schema/property-types.md +1 -1
  505. package/skills/synap-schema/relations.md +1 -1
  506. package/skills/synap-ui/SKILL.md +19 -12
  507. package/skills/synap-ui/_skill.yaml +1 -1
  508. package/skills/synap-ui/ai-companion.md +1 -1
  509. package/skills/synap-ui/arranging-bento.md +2 -0
  510. package/skills/synap-ui/bento-layouts.md +10 -10
  511. package/skills/synap-ui/bento-recipes.md +313 -543
  512. package/skills/synap-ui/four-builds.md +5 -0
  513. package/skills/synap-ui/view-types.md +2 -2
  514. package/skills/synap-ui/widget-catalog.md +22 -278
  515. package/templates/automations/bookmark-enrichment.automation.json +290 -13
  516. package/templates/automations/url-bookmark-capture.automation.json +73 -11
  517. package/templates/box/runner.py +206 -0
  518. package/templates/skills/authoring-playbooks/SKILL.md +6 -3
  519. package/templates/skills/authoring-playbooks/reference/stages-contract.md +15 -0
  520. package/templates/skills/authoring-playbooks/reference/worked-example.md +3 -0
  521. package/dist/commands/infra.d.ts +0 -21
  522. package/dist/commands/infra.js +0 -262
  523. package/dist/commands/infra.js.map +0 -1
  524. package/node_modules/@synap/hub-rest-client/dist/index.cjs +0 -1261
  525. package/node_modules/@synap/hub-rest-client/dist/index.d.cts +0 -1647
  526. package/node_modules/@synap/hub-rest-client/dist/index.d.ts +0 -1647
  527. package/node_modules/@synap/hub-rest-client/dist/index.js +0 -1231
  528. package/node_modules/@synap/hub-rest-client/package.json +0 -45
  529. package/node_modules/@synap/hub-rest-client/src/client.ts +0 -1631
  530. package/node_modules/@synap/hub-rest-client/src/errors.ts +0 -30
  531. package/node_modules/@synap/hub-rest-client/src/index.ts +0 -153
  532. package/node_modules/@synap/hub-rest-client/src/setup.ts +0 -133
  533. package/node_modules/@synap/hub-rest-client/src/types.ts +0 -1299
@@ -1,13 +1,130 @@
1
1
  import chalk from "chalk";
2
2
  import { log } from "../utils/logger.js";
3
- import { resolveHubConfig, hubGet, hubPatch, hubPost, writeActiveSessionId, clearActiveSessionId, readActiveSessionId, renderHubError, } from "../lib/hub-client.js";
3
+ import { resolveHubConfig, hubGet, hubPatch, hubPost, attachActiveSessionId, detachActiveSessionId, resolveActiveSessionId, renderHubError, HubError, } from "../lib/hub-client.js";
4
+ import { closeQuestionDispositions, openQuestionsRefusal, } from "./close-questions.js";
5
+ import { readFileSync, existsSync } from "fs";
6
+ import { resolve } from "path";
7
+ /**
8
+ * The three session-population lenses ("kind"), and their human labels.
9
+ *
10
+ * `@synap-core/types/vocabulary` (`resolveStatusLabel`) is the SSOT for this —
11
+ * `work`/`run`/`receipt` are pinned there verbatim (`.claude/rules/
12
+ * vocabulary.md` forbids a local `charAt(0).toUpperCase()` guess). But this
13
+ * package cannot import it: the CLI links only `@synap-core/workspace-
14
+ * templates` (a real npm dep already), and `@synap-core/types` pulls in
15
+ * drizzle-orm/drizzle-zod/yjs as transitive deps for a globally-installed
16
+ * binary — an install-topology change, not a labelling fix. Same shape as
17
+ * `KIND_HEADINGS` in `market.ts`: a local table, pinned by a source-scan
18
+ * parity test (`test/session-kind-vocabulary-parity.test.ts`) against the
19
+ * registry across the repo boundary, so it cannot silently drift.
20
+ */
21
+ const SESSION_KIND_LABELS = {
22
+ work: "Work",
23
+ run: "Run",
24
+ receipt: "Receipt",
25
+ };
26
+ export function sessionKindLabel(kind) {
27
+ return SESSION_KIND_LABELS[kind] ?? kind;
28
+ }
29
+ const SESSION_KIND_FILTERS = ["work", "run", "receipt", "all"];
30
+ /**
31
+ * The name to show for a session: mirrors `resolveSessionTitle` in
32
+ * `synap-backend/packages/types/src/focus-sessions/title.ts` — the
33
+ * platform's ONE resolver (title when set, else the goal's first line,
34
+ * clipped at a word boundary). This package cannot import that file (see the
35
+ * doc comment on `SESSION_KIND_LABELS` above for why), so only the DISPLAY
36
+ * half of the rule is mirrored: the row's `title` already arrives
37
+ * server-normalized (HTML-entity decoded, one line), so the write-path
38
+ * decode step has nothing to do here. Pinned by
39
+ * `test/session-title-resolver-parity.test.ts`, which runs the registry's
40
+ * OWN fixtures (from `title.test.ts`) through this copy.
41
+ */
42
+ const SESSION_TITLE_FALLBACK_MAX = 80;
43
+ function oneLine(value) {
44
+ return value.replace(/\s+/g, " ").trim();
45
+ }
46
+ function clipAtWordBoundary(line, max) {
47
+ if (line.length <= max)
48
+ return line;
49
+ let cut = line.slice(0, Math.max(1, max - 1));
50
+ const lastSpace = cut.lastIndexOf(" ");
51
+ // Only back off to a word boundary when it keeps most of the budget; a
52
+ // single very long first word is cut mid-word rather than reduced to
53
+ // nothing.
54
+ if (lastSpace >= Math.floor(max / 2))
55
+ cut = cut.slice(0, lastSpace);
56
+ return `${cut.replace(/[\s,;:.\-–—]+$/, "")}…`;
57
+ }
58
+ export function resolveSessionTitle(session, opts = {}) {
59
+ const title = typeof session.title === "string" ? oneLine(session.title) : "";
60
+ if (title)
61
+ return title;
62
+ const goal = typeof session.goal === "string" ? session.goal : "";
63
+ const firstLine = goal
64
+ .split(/\r?\n/)
65
+ .map(oneLine)
66
+ .find((l) => l.length > 0) ?? "";
67
+ return clipAtWordBoundary(firstLine, opts.maxLength ?? SESSION_TITLE_FALLBACK_MAX);
68
+ }
69
+ /**
70
+ * Session-evaluation verdicts (`session_evaluations.verdict`). SSOT is
71
+ * `@synap-core/types/vocabulary`'s `STATUS_LABELS` (`pass`/`fail`/
72
+ * `unmeasured`) — same cross-boundary constraint as `SESSION_KIND_LABELS`
73
+ * above, mirrored here and pinned by
74
+ * `test/verdict-label-vocabulary-parity.test.ts`.
75
+ */
76
+ const VERDICT_LABELS = {
77
+ pass: "Passed",
78
+ fail: "Failed",
79
+ unmeasured: "Not checked",
80
+ };
81
+ function verdictLabel(verdict) {
82
+ return VERDICT_LABELS[verdict] ?? verdict;
83
+ }
84
+ /**
85
+ * One-glance verdict summary for a list/detail row: "1 unmet" when a
86
+ * required criterion is failing or unmeasured (the thing worth flagging),
87
+ * else "2/3 ✓". `null` when the session carries no criteria at all — most
88
+ * sessions don't, and a bare session shouldn't grow a verdict column.
89
+ */
90
+ function verdictSummary(v) {
91
+ const verdict = v;
92
+ if (!verdict || typeof verdict.total !== "number" || verdict.total === 0) {
93
+ return null;
94
+ }
95
+ if (verdict.requiredUnmet && verdict.requiredUnmet > 0) {
96
+ return `${verdict.requiredUnmet} unmet`;
97
+ }
98
+ return `${verdict.passed ?? 0}/${verdict.total} ✓`;
99
+ }
100
+ /** Human phrasing for where an attach landed — so scope is never a mystery. */
101
+ function describeAttachTarget(target) {
102
+ return target === "session-lens"
103
+ ? "in this Claude Code session (~/.synap/lenses)"
104
+ : "in this working tree (.synap/lens.json)";
105
+ }
4
106
  // ─── startSession ─────────────────────────────────────────────────────────────
5
107
  export async function startSession(opts) {
6
108
  try {
7
109
  const cfg = await resolveHubConfig(opts);
8
- const workspaceId = opts.workspace || cfg.workspaceId;
9
- if (!workspaceId) {
10
- console.error(chalk.red("Error: --workspace <id> is required (or set active workspace with 'synap use')"));
110
+ // LENS PARITY. `resolveHubConfig` already resolves the active project
111
+ // ("write paths should consume resolveHubConfig().projectId" —
112
+ // lib/hub-client.ts), and `synap lens` / `synap capture` both honour it.
113
+ // This door read `cfg.workspaceId` and dropped `cfg.projectId` on the
114
+ // floor, so the same terminal answered differently depending on which
115
+ // command you used: capture filed into the project, `session start` wrote
116
+ // projectId: null. The value was one field away the whole time.
117
+ // A track names its own project (the pod refuses a different projectId):
118
+ // with `--track`, only an EXPLICIT --workspace / --project is sent, never
119
+ // the ambient lens, which may point at another project.
120
+ const workspaceId = opts.track ? opts.workspace : opts.workspace || cfg.workspaceId;
121
+ const projectId = opts.track ? opts.project : opts.project || cfg.projectId;
122
+ // The POD accepts workspaceId OR projectId ("Provide a workspaceId or a
123
+ // projectId" — rest/focus-sessions.ts). Requiring a workspace here was a
124
+ // CLI-only rule, stricter than the contract, and it made a project-scoped
125
+ // session unreachable from the terminal.
126
+ if (!workspaceId && !projectId && !opts.track) {
127
+ console.error(chalk.red("Error: no workspace or project in scope — pass --workspace <id> or --project <id>, or set one with 'synap use' / 'synap project use'"));
11
128
  process.exit(1);
12
129
  }
13
130
  // Resolve caller userId from the hub key
@@ -17,33 +134,93 @@ export async function startSession(opts) {
17
134
  console.error(chalk.red("Error: could not resolve userId from /users/me"));
18
135
  process.exit(1);
19
136
  }
20
- const body = {
21
- workspaceId,
22
- userId,
23
- goal: opts.goal,
24
- };
137
+ const body = { userId, goal: opts.goal };
138
+ // Send only what is in scope: the pod's refine accepts either, and sending
139
+ // an undefined workspaceId would fail the "min(1)" on the wire.
140
+ if (workspaceId)
141
+ body.workspaceId = workspaceId;
142
+ if (projectId)
143
+ body.projectId = projectId;
144
+ if (opts.track)
145
+ body.trackId = opts.track;
25
146
  if (opts.taskId)
26
147
  body.correlationId = `task:${opts.taskId}`;
148
+ // `--no-template` → opts.template === false → send an explicit `null`,
149
+ // which SKIPS matching (`TEMPLATE_OPT_OUT` in match-session-template.ts).
150
+ // `--template <id>` → send that id, the one way a playbook binds. Neither
151
+ // → omit, so the start comes back with the pod's playbooks to choose from
152
+ // (suggestions; nothing is applied).
153
+ if (opts.template === false)
154
+ body.templateId = null;
155
+ else if (opts.template)
156
+ body.templateId = opts.template;
157
+ // Detour push: the pod records `session --spawned_from--> session` and (with
158
+ // --suspended-intent) writes the "what were you about to do" line onto the
159
+ // PARENT and a `parent --blocked_by--> this session` edge. The parent is
160
+ // NOT closed or paused — it waits, and popping back is `synap session attach <parent>`.
161
+ if (opts.parent)
162
+ body.parentSessionId = opts.parent;
163
+ if (opts.suspendedIntent)
164
+ body.suspendedIntent = opts.suspendedIntent;
165
+ if (opts.criteria) {
166
+ const path = resolve(process.cwd(), opts.criteria);
167
+ if (!existsSync(path)) {
168
+ console.error(chalk.red(`Error: --criteria file not found: ${path}`));
169
+ process.exit(1);
170
+ return;
171
+ }
172
+ try {
173
+ body.criteria = JSON.parse(readFileSync(path, "utf-8"));
174
+ }
175
+ catch (parseErr) {
176
+ console.error(chalk.red(`Error: --criteria file is not valid JSON — ${parseErr.message}`));
177
+ process.exit(1);
178
+ return;
179
+ }
180
+ }
27
181
  const session = (await hubPost("/focus-sessions", body, cfg));
28
182
  if (opts.json) {
29
183
  console.log(JSON.stringify(session, null, 2));
30
184
  return;
31
185
  }
186
+ // A governed start comes back as a PROPOSAL, not a session: say so, and
187
+ // attach nothing — there is no session id to attach yet.
188
+ if (session.status === "proposed" && typeof session.proposalId === "string") {
189
+ log.warn("Starting this session is queued for your review — not started yet.");
190
+ if (typeof session.reviewUrl === "string")
191
+ log.hint(`Review: ${session.reviewUrl}`);
192
+ else
193
+ log.hint(`Proposal ${session.proposalId} — see: synap proposals list`);
194
+ return;
195
+ }
32
196
  const id = String(session.id ?? "");
33
- // Auto-attach: make this session active for the current terminal (per-CWD)
34
- // AND for this Claude Code session's lens (per-session), so the statusline
35
- // and every scoped call reflect it.
36
- writeActiveSessionId(id);
37
- const { getClaudeSessionId, writeLens } = await import("../lib/session-lens.js");
38
- const cs = getClaudeSessionId();
39
- if (cs)
40
- writeLens(cs, { focusSessionId: id });
197
+ // Auto-attach: make this session active so the statusline and every scoped
198
+ // call reflect it. Lands on the Claude-session lens inside Claude Code,
199
+ // otherwise on this working tree's directory lens.
200
+ const target = attachActiveSessionId(id);
41
201
  log.success(`Session started and attached`);
42
202
  console.log(` ID: ${chalk.bold(id)}`);
203
+ console.log(` Name: ${chalk.white(resolveSessionTitle(session))}`);
43
204
  console.log(` Goal: ${chalk.white(opts.goal)}`);
44
205
  if (opts.taskId)
45
206
  console.log(` Task: ${chalk.dim(opts.taskId)}`);
46
- log.dim(` Active in this terminal (.synap-session)`);
207
+ if (opts.parent)
208
+ console.log(` Forked from: ${chalk.dim(opts.parent)}`);
209
+ if (session.adopted === true) {
210
+ log.dim(` Continued your auto-opened session`);
211
+ }
212
+ // `playbooks` (SessionPlaybookCandidates) is present iff matching ran —
213
+ // see match-session-template.ts. SUGGESTIONS ONLY: nothing was applied, so
214
+ // say what fits and how to bind one, never that one is in force.
215
+ const playbooks = session.playbooks;
216
+ if (playbooks?.candidates?.length) {
217
+ log.dim(` Playbooks that fit this goal (none applied):`);
218
+ for (const c of playbooks.candidates) {
219
+ log.dim(` - ${c.name} (${c.reason})`);
220
+ log.dim(` ${chalk.dim(`--template ${c.id}`)}`);
221
+ }
222
+ }
223
+ log.dim(` Active ${describeAttachTarget(target)}`);
47
224
  console.log();
48
225
  // Print the ID alone on a final line so scripts can grab it easily
49
226
  console.log(id);
@@ -56,18 +233,37 @@ export async function startSession(opts) {
56
233
  // ─── listSessions ─────────────────────────────────────────────────────────────
57
234
  export async function listSessions(opts) {
58
235
  try {
236
+ // Validate at the edge, same reasoning as `--progress` above: a typo should
237
+ // fail here with the legal values, not reach the pod and bounce as a raw
238
+ // zod echo.
239
+ if (opts.kind !== undefined &&
240
+ !SESSION_KIND_FILTERS.includes(opts.kind)) {
241
+ console.error(chalk.red(`Error: --kind must be one of ${SESSION_KIND_FILTERS.join(" | ")} (got ${JSON.stringify(opts.kind)}).`));
242
+ process.exit(1);
243
+ }
59
244
  const cfg = await resolveHubConfig(opts);
60
245
  const params = {};
61
246
  // Fall back to the active workspace (config/env) like `start` does — the
62
247
  // focus-sessions REST requires workspaceId, and an operator with an active
63
248
  // workspace shouldn't have to repeat --workspace on every session command.
64
- const wsId = opts.workspace || cfg.workspaceId;
249
+ // `--project` is a scope of its own (the pod accepts projectId alone,
250
+ // project-member floor): a project's sessions span spaces, so with it only
251
+ // an EXPLICIT --workspace narrows — never the ambient one, which would hide
252
+ // every session the project runs in another space.
253
+ const wsId = opts.project ? opts.workspace : opts.workspace || cfg.workspaceId;
65
254
  if (wsId)
66
255
  params.workspaceId = wsId;
256
+ if (opts.project)
257
+ params.projectId = opts.project;
67
258
  if (opts.status)
68
259
  params.status = opts.status;
69
260
  if (opts.limit)
70
261
  params.limit = parseInt(opts.limit, 10);
262
+ // Population lens (`services/focus-sessions/session-kind.ts` on the pod).
263
+ // The Hub REST door defaults to "all" itself, so omit rather than send a
264
+ // redundant param when the flag isn't given.
265
+ if (opts.kind && opts.kind !== "all")
266
+ params.kind = opts.kind;
71
267
  // The Hub REST GET /focus-sessions returns a bare array of sessions.
72
268
  // (Tolerate a { sessions: [...] } envelope too, for forward-compat.)
73
269
  const res = await hubGet("/focus-sessions", params, cfg);
@@ -90,8 +286,17 @@ export async function listSessions(opts) {
90
286
  ? chalk.yellow(status)
91
287
  : chalk.dim(status);
92
288
  const progress = typeof s.progress === "number" ? ` ${chalk.dim(`[${s.progress}%]`)}` : "";
289
+ // `kind` is projected on every row by the Hub REST door regardless of the
290
+ // `--kind` filter — an older pod without the kind wave simply omits it.
291
+ const kindLabel = typeof s.kind === "string" ? sessionKindLabel(s.kind) : null;
292
+ const kindCol = kindLabel ? ` ${chalk.dim(`[${kindLabel}]`)}` : "";
293
+ // Present only when the door lifts `verdict` onto the row (today: the
294
+ // single-session GET, not this list) — `verdictSummary` returns null on
295
+ // an absent field, so an older/list door just omits the marker.
296
+ const verdict = verdictSummary(s.verdict);
297
+ const verdictCol = verdict ? ` ${chalk.dim(`(${verdict})`)}` : "";
93
298
  // Full id — feeds straight into `synap session get/update/attach <id>`.
94
- console.log(` ${chalk.bold(String(s.id ?? ""))} ${statusColor}${progress} ${chalk.white(String(s.goal ?? ""))}`);
299
+ console.log(` ${chalk.bold(String(s.id ?? ""))} ${statusColor}${kindCol}${progress} ${chalk.white(resolveSessionTitle(s))}${verdictCol}`);
95
300
  }
96
301
  }
97
302
  catch (e) {
@@ -100,22 +305,62 @@ export async function listSessions(opts) {
100
305
  }
101
306
  }
102
307
  // ─── getSession ───────────────────────────────────────────────────────────────
308
+ /**
309
+ * Fetch a focus session by id.
310
+ *
311
+ * Prefer GET without workspaceId so project-scoped sessions (workspaceId null)
312
+ * resolve. Older pods still require the query param — if the bare GET fails
313
+ * with 400 and we have a workspace, retry with it.
314
+ */
315
+ async function fetchSessionById(id, cfg, workspaceHint) {
316
+ try {
317
+ return (await hubGet(`/focus-sessions/${id}`, {}, cfg));
318
+ }
319
+ catch (e) {
320
+ const wsId = workspaceHint || cfg.workspaceId;
321
+ if (e instanceof HubError && e.status === 400 && wsId) {
322
+ return (await hubGet(`/focus-sessions/${id}`, { workspaceId: wsId }, cfg));
323
+ }
324
+ throw e;
325
+ }
326
+ }
103
327
  export async function getSession(id, opts) {
104
328
  try {
105
329
  const cfg = await resolveHubConfig(opts);
106
- const params = {};
107
- const wsId = opts.workspace || cfg.workspaceId;
108
- if (wsId)
109
- params.workspaceId = wsId;
110
- const res = await hubGet(`/focus-sessions/${id}`, params, cfg);
330
+ const res = await fetchSessionById(id, cfg, opts.workspace);
111
331
  if (opts.json) {
112
332
  console.log(JSON.stringify(res, null, 2));
113
333
  return;
114
334
  }
115
335
  const s = res;
116
336
  log.info(`Session ${chalk.bold(String(s.id ?? ""))}`);
337
+ console.log(` Name: ${chalk.white(resolveSessionTitle(s))}`);
117
338
  console.log(` Goal: ${chalk.white(String(s.goal ?? ""))}`);
118
339
  console.log(` Status: ${chalk.cyan(String(s.status ?? ""))}`);
340
+ if (typeof s.kind === "string")
341
+ console.log(` Kind: ${chalk.dim(sessionKindLabel(s.kind))}`);
342
+ // `verdict` (SessionVerdict) is present iff the session carries criteria —
343
+ // see `test/verdict-label-vocabulary-parity.test.ts` for the label SSOT.
344
+ const verdict = s.verdict;
345
+ if (verdict && typeof verdict.total === "number" && verdict.total > 0) {
346
+ const summary = verdictSummary(verdict);
347
+ console.log(` Criteria: ${chalk.white(`${verdict.passed ?? 0}/${verdict.total}`)}` +
348
+ (summary && verdict.requiredUnmet
349
+ ? ` ${chalk.yellow(summary)}`
350
+ : ""));
351
+ }
352
+ // Project-scoped sessions have workspaceId null — show scope honestly.
353
+ if (s.workspaceId != null && s.workspaceId !== "") {
354
+ console.log(` Workspace: ${chalk.dim(String(s.workspaceId))}`);
355
+ }
356
+ else if (s.projectId) {
357
+ console.log(` Project: ${chalk.dim(String(s.projectId))} ${chalk.dim("(no workspace)")}`);
358
+ }
359
+ else {
360
+ console.log(` Scope: ${chalk.dim("project/unscoped (workspace null)")}`);
361
+ }
362
+ if (s.projectId && s.workspaceId)
363
+ console.log(` Project: ${chalk.dim(String(s.projectId))}`);
119
364
  if (typeof s.progress === "number")
120
365
  console.log(` Progress: ${s.progress}%`);
121
366
  if (s.templateId)
@@ -136,16 +381,31 @@ export async function getSession(id, opts) {
136
381
  export async function updateSession(id, opts) {
137
382
  try {
138
383
  const cfg = await resolveHubConfig(opts);
384
+ // The session is identified by `id` in the URL and `workspaceId` is
385
+ // `.optional()` on the pod's UpdateBodySchema — so demanding one here was a
386
+ // CLI-only rule that made an already-attached (or project-scoped) session
387
+ // un-updatable without re-stating a lens the terminal already holds.
139
388
  const wsId = opts.workspace || cfg.workspaceId;
140
- if (!wsId) {
141
- console.error(chalk.red("Error: no active workspace — pass --workspace <id> or set one with `synap use`"));
142
- process.exit(1);
389
+ const body = {};
390
+ if (wsId)
391
+ body.workspaceId = wsId;
392
+ // `progress` is `z.number().int().min(0).max(100)` on the pod. `parseInt`
393
+ // on prose yields NaN, which serialized to the wire and came back as a raw
394
+ // zod echo — an unreadable error for a mistake the CLI could name here.
395
+ // Validate at the edge and say what the flag actually takes.
396
+ if (opts.progress !== undefined) {
397
+ const pct = Number(opts.progress);
398
+ if (!Number.isInteger(pct) || pct < 0 || pct > 100) {
399
+ console.error(chalk.red(`Error: --progress takes a whole number 0-100 (got ${JSON.stringify(opts.progress)}).`));
400
+ log.hint("For a free-text note, use --goal to restate the goal, or capture the note: synap capture --type lesson --claim \"...\"");
401
+ process.exit(1);
402
+ }
403
+ body.progress = pct;
143
404
  }
144
- const body = { workspaceId: wsId };
145
- if (opts.progress !== undefined)
146
- body.progress = parseInt(opts.progress, 10);
147
405
  if (opts.status)
148
406
  body.status = opts.status;
407
+ if (opts.stage)
408
+ body.currentStage = opts.stage;
149
409
  if (opts.goal)
150
410
  body.goal = opts.goal;
151
411
  const res = await hubPatch(`/focus-sessions/${id}`, body, cfg);
@@ -158,6 +418,8 @@ export async function updateSession(id, opts) {
158
418
  log.dim(` progress → ${opts.progress}%`);
159
419
  if (opts.status)
160
420
  log.dim(` status → ${opts.status}`);
421
+ if (opts.stage)
422
+ log.dim(` stage → ${opts.stage}`);
161
423
  }
162
424
  catch (e) {
163
425
  renderHubError(e);
@@ -166,34 +428,27 @@ export async function updateSession(id, opts) {
166
428
  }
167
429
  // ─── attachSession ────────────────────────────────────────────────────────────
168
430
  export async function attachSession(id, opts) {
169
- // Validate the session exists before attaching
431
+ // Validate the session exists before attaching (project-scoped OK — no workspace required)
170
432
  try {
171
433
  const cfg = await resolveHubConfig(opts);
172
- const params = {};
173
- if (cfg.workspaceId)
174
- params.workspaceId = cfg.workspaceId;
175
- await hubGet(`/focus-sessions/${id}`, params, cfg);
434
+ await fetchSessionById(id, cfg, opts.workspace);
176
435
  }
177
436
  catch (e) {
178
437
  console.error(chalk.red("Error: session not found — " + e.message));
179
438
  process.exit(1);
180
439
  }
181
- writeActiveSessionId(id);
182
- const { getClaudeSessionId, writeLens } = await import("../lib/session-lens.js");
183
- const cs = getClaudeSessionId();
184
- if (cs)
185
- writeLens(cs, { focusSessionId: id });
440
+ const target = attachActiveSessionId(id);
186
441
  if (opts.json) {
187
- console.log(JSON.stringify({ ok: true, sessionId: id }));
442
+ console.log(JSON.stringify({ ok: true, sessionId: id, scope: target }));
188
443
  return;
189
444
  }
190
445
  log.success(`Session attached ${chalk.dim(id.slice(0, 8))}`);
446
+ log.dim(` Active ${describeAttachTarget(target)}`);
191
447
  log.dim(` All hub calls in this terminal will tag X-Session-Id: ${id.slice(0, 8)}…`);
192
448
  }
193
449
  // ─── detachSession ────────────────────────────────────────────────────────────
194
450
  export function detachSession(opts) {
195
- const current = readActiveSessionId();
196
- clearActiveSessionId();
451
+ const current = detachActiveSessionId();
197
452
  if (opts.json) {
198
453
  console.log(JSON.stringify({ ok: true }));
199
454
  return;
@@ -207,39 +462,227 @@ export function detachSession(opts) {
207
462
  }
208
463
  // ─── sessionStatus ────────────────────────────────────────────────────────────
209
464
  export function sessionStatus(opts) {
210
- const id = readActiveSessionId();
465
+ const id = resolveActiveSessionId();
211
466
  if (opts.json) {
212
467
  console.log(JSON.stringify({ sessionId: id ?? null }));
213
468
  return;
214
469
  }
215
470
  if (id) {
216
- log.info(`Active session: ${chalk.bold(id.slice(0, 8))}… ${chalk.dim("(from .synap-session or SYNAP_SESSION_ID)")}`);
471
+ log.info(`Active session: ${chalk.bold(id.slice(0, 8))}… ${chalk.dim("(SYNAP_SESSION_ID, session lens, or .synap/lens.json)")}`);
217
472
  }
218
473
  else {
219
474
  log.dim("No active session — run `synap session start` or `synap session attach <id>`");
220
475
  }
221
476
  }
222
- // ─── closeSession ─────────────────────────────────────────────────────────────
477
+ /**
478
+ * Close a focus session via Hub complete (proposal pack).
479
+ *
480
+ * Prefer POST /focus-sessions/:id/complete with `{ summary }` from `--recap`.
481
+ * On 404 (older pods without the route) fall back to PATCH status=closed and
482
+ * write verificationReport.summary — graceful degrade, pack unavailable.
483
+ *
484
+ * --workspace is optional: complete loads the row by id; PATCH also scopes
485
+ * from the row (workspaceId body is back-compat only).
486
+ */
223
487
  export async function closeSession(id, opts) {
488
+ const settled = closeQuestionDispositions(opts);
489
+ if (!settled.ok) {
490
+ console.error(chalk.red(`Error: ${settled.error}`));
491
+ process.exit(1);
492
+ }
224
493
  try {
225
494
  const cfg = await resolveHubConfig(opts);
226
495
  const wsId = opts.workspace || cfg.workspaceId;
227
- if (!wsId) {
228
- console.error(chalk.red("Error: no active workspace — pass --workspace <id> or set one with `synap use`"));
229
- process.exit(1);
496
+ let pack = null;
497
+ let usedPack = false;
498
+ try {
499
+ // Canonical close: completeFocusSession — returns proposal pack.
500
+ // Map CLI --recap → body.summary (server field; there is no `recap` key).
501
+ const body = {};
502
+ if (opts.recap)
503
+ body.summary = opts.recap;
504
+ // How the session ended. Validated at the edge (see index.ts) so a typo
505
+ // fails here with the three legal values, rather than reaching the pod
506
+ // and being rejected by a zod enum the user cannot see.
507
+ if (opts.as)
508
+ body.terminalStatus = opts.as;
509
+ if (settled.dispositions.length > 0)
510
+ body.questionDispositions = settled.dispositions;
511
+ pack = (await hubPost(`/focus-sessions/${id}/complete`, body, cfg));
512
+ usedPack = true;
513
+ }
514
+ catch (e) {
515
+ if (!(e instanceof HubError) || e.status !== 404)
516
+ throw e;
517
+ // Older pod: no complete route — close via PATCH and warn that pack is
518
+ // unavailable. verificationReport.summary is the field the complete path
519
+ // writes (complete-session.ts); UpdateBodySchema accepts it as z.unknown().
520
+ log.dim("Pack unavailable on this pod (POST …/complete → 404); falling back to status close.");
521
+ const patchBody = {
522
+ status: opts.as ?? "closed",
523
+ };
524
+ if (wsId)
525
+ patchBody.workspaceId = wsId;
526
+ if (opts.recap)
527
+ patchBody.verificationReport = { summary: opts.recap };
528
+ await hubPatch(`/focus-sessions/${id}`, patchBody, cfg);
230
529
  }
231
- // Close via PATCH — the /focus-sessions/:id endpoint sets closedAt automatically
232
- // when status transitions to "closed"
233
- const body = { workspaceId: wsId, status: "closed" };
234
- await hubPatch(`/focus-sessions/${id}`, body, cfg);
235
530
  // Detach if this was the active terminal session
236
- if (readActiveSessionId() === id)
237
- clearActiveSessionId();
531
+ if (resolveActiveSessionId(cfg.podUrl) === id)
532
+ detachActiveSessionId(cfg.podUrl);
533
+ if (opts.json) {
534
+ if (usedPack && pack) {
535
+ console.log(JSON.stringify(pack, null, 2));
536
+ }
537
+ else {
538
+ console.log(JSON.stringify({
539
+ ok: true,
540
+ status: "closed",
541
+ pack: false,
542
+ summary: opts.recap ?? null,
543
+ }, null, 2));
544
+ }
545
+ return;
546
+ }
547
+ const sessionStatus = (pack?.session && String(pack.session.status ?? "")) ||
548
+ pack?.status ||
549
+ "closed";
550
+ // Close never blocks on criteria — a required-but-unmet criterion is a
551
+ // flag on the closed session, never a refusal.
552
+ const closeVerdict = pack?.verdict && pack.verdict.requiredUnmet
553
+ ? ` · ${pack.verdict.requiredUnmet} criteri${pack.verdict.requiredUnmet === 1 ? "on" : "a"} not met`
554
+ : "";
555
+ log.success(`Session closed ${chalk.dim(id.slice(0, 8))} ${chalk.cyan(sessionStatus)}${chalk.yellow(closeVerdict)}`);
556
+ if (opts.recap)
557
+ log.dim(` recap: ${opts.recap}`);
558
+ if (usedPack && pack) {
559
+ const pending = pack.counts?.pending ??
560
+ (Array.isArray(pack.pendingProposals) ? pack.pendingProposals.length : 0);
561
+ const unfinished = pack.counts?.unfinishedOutputs ?? 0;
562
+ console.log(` Pack: ${chalk.white(String(pending))} pending proposal(s)` +
563
+ (unfinished > 0
564
+ ? ` ${chalk.yellow(`${unfinished} unfinished output(s)`)}`
565
+ : ""));
566
+ if (Array.isArray(pack.warnings)) {
567
+ for (const w of pack.warnings) {
568
+ log.warn(String(w));
569
+ }
570
+ }
571
+ if (pack.note)
572
+ log.dim(` ${pack.note}`);
573
+ if (pending > 0) {
574
+ log.dim(` Review: synap proposals list --session ${id}`);
575
+ }
576
+ }
577
+ }
578
+ catch (e) {
579
+ const refusal = openQuestionsRefusal(e);
580
+ if (refusal) {
581
+ if (opts.json) {
582
+ console.log(JSON.stringify({ ok: false, status: "refused", ...refusal }, null, 2));
583
+ }
584
+ else {
585
+ log.error("Not closed: questions you asked in this session are still open.");
586
+ for (const q of refusal.openQuestions) {
587
+ console.log(` ${chalk.white(q.shortId ?? q.messageId.slice(0, 8))} ${q.text} ${chalk.dim(q.messageId)}`);
588
+ }
589
+ log.dim(" Relay the person's chat answer first (relay_answer), or close again with " +
590
+ "--withdraw <messageId>=<why> or --keep-owed <messageId> for each.");
591
+ }
592
+ process.exit(1);
593
+ }
594
+ renderHubError(e);
595
+ process.exit(1);
596
+ }
597
+ }
598
+ // ─── evidenceSession / evaluateSession ─────────────────────────────────────────
599
+ /** Resolve the target session: `--session <id>`, else this terminal's active one. */
600
+ function resolveTargetSessionId(opts, cfg) {
601
+ const id = opts.session || resolveActiveSessionId(cfg.podUrl);
602
+ if (!id) {
603
+ console.error(chalk.red("Error: no session in scope — pass --session <id> or attach one with 'synap session attach <id>'"));
604
+ process.exit(1);
605
+ }
606
+ return id;
607
+ }
608
+ function printEvaluateResult(result) {
609
+ if (result.status === "not_found") {
610
+ log.warn("Session not found");
611
+ return;
612
+ }
613
+ for (const r of result.results ?? []) {
614
+ if (r.status === "recorded" && r.verdict) {
615
+ const label = verdictLabel(r.verdict);
616
+ const colored = r.verdict === "pass"
617
+ ? chalk.green(label)
618
+ : r.verdict === "fail"
619
+ ? chalk.red(label)
620
+ : chalk.dim(label);
621
+ console.log(` ${chalk.bold(r.key)}: ${colored}${r.escalated ? chalk.yellow(" (escalated)") : ""}`);
622
+ }
623
+ else {
624
+ console.log(` ${chalk.bold(r.key)}: ${chalk.dim(`skipped — ${r.reason ?? "not applicable"}`)}`);
625
+ }
626
+ }
627
+ const summary = verdictSummary(result.verdict);
628
+ if (summary)
629
+ log.dim(` Verdict: ${summary}`);
630
+ if (result.resumed)
631
+ log.dim(` Resumed a paused check-gate`);
632
+ }
633
+ /**
634
+ * `synap session evidence <key> --passed|--failed [--detail "…"]`
635
+ *
636
+ * POST /focus-sessions/:id/evidence — the agent's own deterministic report
637
+ * for an `evidence`-checked criterion. Grades ONLY evidence-checked
638
+ * criteria; never spends a judge call or runs a capability
639
+ * (`rest/focus-sessions.ts`, the `onlyEvidence` branch).
640
+ */
641
+ export async function evidenceSession(key, opts) {
642
+ try {
643
+ const cfg = await resolveHubConfig(opts);
644
+ const id = resolveTargetSessionId(opts, cfg);
645
+ if (opts.passed === opts.failed) {
646
+ // Both or neither given — commander gives us two independent booleans,
647
+ // not an enum, so this is the edge check for "exactly one".
648
+ console.error(chalk.red("Error: pass exactly one of --passed or --failed"));
649
+ process.exit(1);
650
+ return;
651
+ }
652
+ const evidence = {
653
+ [key]: { passed: !!opts.passed, ...(opts.detail ? { detail: opts.detail } : {}) },
654
+ };
655
+ const result = (await hubPost(`/focus-sessions/${id}/evidence`, { evidence }, cfg));
656
+ if (opts.json) {
657
+ console.log(JSON.stringify(result, null, 2));
658
+ return;
659
+ }
660
+ log.success(`Evidence recorded ${chalk.dim(id.slice(0, 8))}`);
661
+ printEvaluateResult(result);
662
+ }
663
+ catch (e) {
664
+ renderHubError(e);
665
+ process.exit(1);
666
+ }
667
+ }
668
+ /**
669
+ * `synap session evaluate [--session <id>]`
670
+ *
671
+ * POST /focus-sessions/:id/evaluations — runs every PENDING criterion check
672
+ * (evidence already posted, then capability, then judge) and prints the
673
+ * per-criterion verdicts.
674
+ */
675
+ export async function evaluateSession(opts) {
676
+ try {
677
+ const cfg = await resolveHubConfig(opts);
678
+ const id = resolveTargetSessionId(opts, cfg);
679
+ const result = (await hubPost(`/focus-sessions/${id}/evaluations`, {}, cfg));
238
680
  if (opts.json) {
239
- console.log(JSON.stringify({ ok: true }));
681
+ console.log(JSON.stringify(result, null, 2));
240
682
  return;
241
683
  }
242
- log.success(`Session closed ${chalk.dim(id.slice(0, 8))}`);
684
+ log.success(`Session evaluated ${chalk.dim(id.slice(0, 8))}`);
685
+ printEvaluateResult(result);
243
686
  }
244
687
  catch (e) {
245
688
  renderHubError(e);