@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
@@ -4,41 +4,318 @@
4
4
  "status": "active",
5
5
  "triggerConfig": {
6
6
  "eventPattern": "entity.create.completed",
7
- "filters": { "profileSlug": "bookmark" }
7
+ "filters": {
8
+ "profileSlug": "bookmark"
9
+ }
8
10
  },
9
11
  "flowDefinition": {
10
12
  "nodes": [
11
13
  {
12
14
  "id": "trigger",
13
15
  "type": "trigger",
14
- "position": { "x": 0, "y": 0 },
16
+ "position": {
17
+ "x": 0,
18
+ "y": 0
19
+ },
15
20
  "data": {
16
21
  "triggerType": "event",
17
22
  "label": "Bookmark created",
18
23
  "config": {
19
24
  "eventPattern": "entity.create.completed",
20
- "filters": { "profileSlug": "bookmark" }
25
+ "filters": {
26
+ "profileSlug": "bookmark"
27
+ }
21
28
  }
22
29
  }
23
30
  },
24
31
  {
25
- "id": "enrich",
26
- "type": "skill",
27
- "position": { "x": 0, "y": 120 },
32
+ "id": "read",
33
+ "type": "entity_read",
34
+ "position": {
35
+ "x": 0,
36
+ "y": 120
37
+ },
28
38
  "data": {
29
- "label": "Bookmark Enrichment",
30
- "skillName": "bookmark-enrichment",
31
- "skillTitle": "Bookmark Enrichment",
39
+ "label": "Read the bookmark",
40
+ "entityId": "{{trigger.payload.subjectId}}"
41
+ }
42
+ },
43
+ {
44
+ "id": "graph-context",
45
+ "type": "related_entities",
46
+ "position": {
47
+ "x": 0,
48
+ "y": 240
49
+ },
50
+ "data": {
51
+ "label": "What the graph already connects (deterministic)",
52
+ "entityId": "{{trigger.payload.subjectId}}",
53
+ "direction": "both",
54
+ "limit": 10
55
+ }
56
+ },
57
+ {
58
+ "id": "channel-talk",
59
+ "type": "messages_query",
60
+ "position": {
61
+ "x": 0,
62
+ "y": 360
63
+ },
64
+ "data": {
65
+ "label": "What was being discussed (deterministic)",
66
+ "channelId": "{{steps.read.output.entity.properties.sourceChannelId}}",
67
+ "limit": 10,
68
+ "errorHandling": {
69
+ "continueOnError": true
70
+ }
71
+ }
72
+ },
73
+ {
74
+ "id": "sharer-lookup",
75
+ "type": "query",
76
+ "position": {
77
+ "x": 0,
78
+ "y": 480
79
+ },
80
+ "data": {
81
+ "label": "Resolve the sharer to a person entity (deterministic)",
82
+ "profileSlug": "person",
83
+ "filter": "{\"title\": \"{{steps.read.output.entity.properties.sharedBy}}\"}",
84
+ "limit": 5
85
+ }
86
+ },
87
+ {
88
+ "id": "has-sharer-name",
89
+ "type": "condition",
90
+ "position": {
91
+ "x": 0,
92
+ "y": 600
93
+ },
94
+ "data": {
95
+ "label": "Bookmark carries a sharer name?",
96
+ "expression": "steps.read.output.entity.properties.sharedBy !== ''"
97
+ }
98
+ },
99
+ {
100
+ "id": "sharer-matches",
101
+ "type": "condition",
102
+ "position": {
103
+ "x": 0,
104
+ "y": 720
105
+ },
106
+ "data": {
107
+ "label": "Matched person's title equals the sharer name exactly?",
108
+ "expression": "steps.sharer-lookup.output.entities.0.title === steps.read.output.entity.properties.sharedBy"
109
+ }
110
+ },
111
+ {
112
+ "id": "link-sharer",
113
+ "type": "output",
114
+ "position": {
115
+ "x": 0,
116
+ "y": 840
117
+ },
118
+ "data": {
119
+ "label": "Link bookmark → the person who shared it",
120
+ "outputType": "relation_create",
121
+ "config": {
122
+ "fromEntityId": "{{trigger.payload.subjectId}}",
123
+ "toEntityId": "{{steps.sharer-lookup.output.entities.0.id}}",
124
+ "relationType": "created_by"
125
+ }
126
+ }
127
+ },
128
+ {
129
+ "id": "classify",
130
+ "type": "capability",
131
+ "position": {
132
+ "x": 0,
133
+ "y": 1200
134
+ },
135
+ "data": {
136
+ "label": "Describe + classify (AI) — title only if the captured one is unusable",
137
+ "verbId": "ai.generate",
32
138
  "inputMapping": {
33
- "entityId": "{{trigger.payload.subjectId}}"
139
+ "system": "You name saved links for a personal knowledge base. Answer with a JSON object and nothing else: {\"title\": string, \"description\": string, \"category\": string}. `title` is a short human-readable name for the link (max 70 chars, no URL, no quotes). `description` is one factual sentence (max 200 chars). `category` is ONE lowercase word from: article, video, tool, repo, docs, social, media, other. You CANNOT open the link. Use ONLY the URL, the already-resolved graph context and the surrounding conversation you are given. `description` and `category` are ALWAYS used. `title` is used ONLY when the link has no usable name yet — when 'Current name' below already reads like a real title, it is kept and yours is discarded, so never optimise for replacing it. If the material does not tell you what the page is, set `title` to the empty string rather than guessing.",
140
+ "prompt": "URL: {{steps.read.output.entity.properties.url}}\nCurrent name: {{steps.read.output.entity.title}}\nShared by: {{steps.read.output.entity.properties.sharedBy}}\n\nAlready connected in the graph:\n{{steps.graph-context.output.entities}}\n\nSurrounding conversation in the source channel:\n{{steps.channel-talk.output.messages}}\n\nThe message it arrived in:\n{{steps.read.output.entity.preview}}",
141
+ "json": "true",
142
+ "maxTokens": "2000"
143
+ }
144
+ }
145
+ },
146
+ {
147
+ "id": "apply-enrich",
148
+ "type": "output",
149
+ "position": {
150
+ "x": -400,
151
+ "y": 1500
152
+ },
153
+ "data": {
154
+ "label": "Write description + category back (always)",
155
+ "outputType": "entity_update",
156
+ "config": {
157
+ "entityId": "{{trigger.payload.subjectId}}",
158
+ "properties": {
159
+ "description": "{{steps.classify.output.description}}",
160
+ "category": "{{steps.classify.output.category}}"
161
+ }
162
+ }
163
+ }
164
+ },
165
+ {
166
+ "id": "title-present",
167
+ "type": "condition",
168
+ "position": {
169
+ "x": 400,
170
+ "y": 1350
171
+ },
172
+ "data": {
173
+ "label": "Did the link arrive with a name?",
174
+ "expression": "steps.read.output.entity.title !== ''"
175
+ }
176
+ },
177
+ {
178
+ "id": "title-not-url",
179
+ "type": "condition",
180
+ "position": {
181
+ "x": 400,
182
+ "y": 1470
183
+ },
184
+ "data": {
185
+ "label": "…and is that name more than the raw URL?",
186
+ "expression": "steps.read.output.entity.title !== steps.read.output.entity.properties.url"
187
+ }
188
+ },
189
+ {
190
+ "id": "usable-title",
191
+ "type": "guard",
192
+ "position": {
193
+ "x": 0,
194
+ "y": 1320
195
+ },
196
+ "data": {
197
+ "label": "Only rename when the model produced a real title",
198
+ "checks": [
199
+ {
200
+ "path": "steps.classify.output.title",
201
+ "minLength": 3,
202
+ "message": "ai.generate returned no usable title — leaving the bookmark's captured name untouched."
203
+ }
204
+ ]
205
+ }
206
+ },
207
+ {
208
+ "id": "apply-title",
209
+ "type": "output",
210
+ "position": {
211
+ "x": 0,
212
+ "y": 1440
213
+ },
214
+ "data": {
215
+ "label": "Write the AI title back (only when the captured one was unusable)",
216
+ "outputType": "entity_update",
217
+ "config": {
218
+ "entityId": "{{trigger.payload.subjectId}}",
219
+ "title": "{{steps.classify.output.title}}",
220
+ "properties": {
221
+ "title": "{{steps.classify.output.title}}"
222
+ }
34
223
  }
35
224
  }
36
225
  }
37
226
  ],
38
- "edges": [{ "id": "e1", "source": "trigger", "target": "enrich" }]
227
+ "edges": [
228
+ {
229
+ "id": "trigger->read",
230
+ "source": "trigger",
231
+ "target": "read"
232
+ },
233
+ {
234
+ "id": "read->graph-context",
235
+ "source": "read",
236
+ "target": "graph-context"
237
+ },
238
+ {
239
+ "id": "graph-context->channel-talk",
240
+ "source": "graph-context",
241
+ "target": "channel-talk"
242
+ },
243
+ {
244
+ "id": "channel-talk->sharer-lookup",
245
+ "source": "channel-talk",
246
+ "target": "sharer-lookup"
247
+ },
248
+ {
249
+ "id": "sharer-lookup->has-sharer-name",
250
+ "source": "sharer-lookup",
251
+ "target": "has-sharer-name"
252
+ },
253
+ {
254
+ "id": "has-sharer-name->sharer-matches",
255
+ "source": "has-sharer-name",
256
+ "target": "sharer-matches",
257
+ "sourceHandle": "yes"
258
+ },
259
+ {
260
+ "id": "sharer-matches->link-sharer",
261
+ "source": "sharer-matches",
262
+ "target": "link-sharer",
263
+ "sourceHandle": "yes"
264
+ },
265
+ {
266
+ "id": "link-sharer->classify",
267
+ "source": "link-sharer",
268
+ "target": "classify"
269
+ },
270
+ {
271
+ "id": "has-sharer-name->classify",
272
+ "source": "has-sharer-name",
273
+ "target": "classify",
274
+ "sourceHandle": "no"
275
+ },
276
+ {
277
+ "id": "sharer-matches->classify",
278
+ "source": "sharer-matches",
279
+ "target": "classify",
280
+ "sourceHandle": "no"
281
+ },
282
+ {
283
+ "id": "classify->apply-enrich",
284
+ "source": "classify",
285
+ "target": "apply-enrich"
286
+ },
287
+ {
288
+ "id": "classify->title-present",
289
+ "source": "classify",
290
+ "target": "title-present"
291
+ },
292
+ {
293
+ "id": "title-present->title-not-url",
294
+ "source": "title-present",
295
+ "target": "title-not-url",
296
+ "sourceHandle": "yes"
297
+ },
298
+ {
299
+ "id": "title-present->usable-title",
300
+ "source": "title-present",
301
+ "target": "usable-title",
302
+ "sourceHandle": "no"
303
+ },
304
+ {
305
+ "id": "title-not-url->usable-title",
306
+ "source": "title-not-url",
307
+ "target": "usable-title",
308
+ "sourceHandle": "no"
309
+ },
310
+ {
311
+ "id": "usable-title->apply-title",
312
+ "source": "usable-title",
313
+ "target": "apply-title"
314
+ }
315
+ ]
39
316
  },
40
317
  "metadata": {
41
318
  "source": "bridge-template",
42
- "note": "The skill node carries `skillName`; the CLI seed command resolves it to the live `skillId` at install time (GET /skills by name)."
319
+ "note": "DETERMINISTIC-FIRST. Everything reachable without a network call runs BEFORE the AI: `related_entities` (what the graph already connects to this bookmark — the capture flow's `references` edge to the channel's bound entity lands here), `messages_query` on the captured `sourceChannelId` (what was being discussed), and a `query` on `person` resolving the captured `sharedBy` display name to a real person entity, linked with the EXISTING `created_by` relation def (no new def, no new node type). ai.generate is now the LAST RESORT: it runs only when the captured name is empty OR is the raw URL — the branch `title-present`→`title-not-url` — so a human-written message preview is never overwritten by a guess, and when the AI does run it is handed the deterministic context instead of a bare URL. Two condition merges (`title-present`, `classify`) rely on markDescendantsSkipped's live-parent rule (graph-topology.ts) — a merge node survives as long as ONE incoming edge is unpruned. `sharer-lookup` uses the STRING filter form on purpose: `parseQueryFilterConditions` template-resolves a STRING filter but pushes an OBJECT filter's values RAW, so the object form would have compared the literal `{{...}}` text and silently matched nothing. The `sharer-matches` exact-equality condition is the containment for that string form: if a name with a quote breaks JSON.parse the filter is dropped and the query widens, and this check refuses to link a non-identical title. `messages_query` carries `continueOnError` because it THROWS when the channel is not visible in the automation's workspace. NOT expressible today: host→company/tool matching. `transform` has no host/hostname pipe and the query filter compiles only exact equality ($eq/$gt/$gte/$lt/$lte/$ne — no substring/LIKE), so a host could never be matched against a `website` property holding a full URL. A page `fetch` is deliberately still absent."
43
320
  }
44
- }
321
+ }
@@ -22,18 +22,36 @@
22
22
  }
23
23
  },
24
24
  {
25
- "id": "extract",
25
+ "id": "content",
26
26
  "type": "transform",
27
27
  "position": { "x": 0, "y": 120 },
28
28
  "data": {
29
- "label": "Extract URLs",
30
- "expression": "{{trigger.payload.data.content}} | url_extract"
29
+ "label": "Trim message text",
30
+ "expression": "{{trigger.payload.data.content}} | trim"
31
+ }
32
+ },
33
+ {
34
+ "id": "title-src",
35
+ "type": "transform",
36
+ "position": { "x": 0, "y": 240 },
37
+ "data": {
38
+ "label": "Human text (title source)",
39
+ "expression": "{{trigger.payload.data.messagePreview}} | trim"
40
+ }
41
+ },
42
+ {
43
+ "id": "extract",
44
+ "type": "transform",
45
+ "position": { "x": 0, "y": 360 },
46
+ "data": {
47
+ "label": "Extract URLs · drop bare-link noise",
48
+ "expression": "{{trigger.payload.data.content}} | url_extract | unique | filter:item !== steps.content.output.result | slice:5"
31
49
  }
32
50
  },
33
51
  {
34
52
  "id": "url-loop",
35
53
  "type": "loop",
36
- "position": { "x": 0, "y": 240 },
54
+ "position": { "x": 0, "y": 480 },
37
55
  "data": {
38
56
  "label": "For each URL",
39
57
  "iteratorExpression": "steps.extract.output.result",
@@ -43,28 +61,72 @@
43
61
  {
44
62
  "id": "create-bookmark",
45
63
  "type": "output",
46
- "position": { "x": 0, "y": 360 },
64
+ "position": { "x": 0, "y": 600 },
47
65
  "data": {
48
66
  "label": "Create bookmark",
49
67
  "outputType": "entity_create",
50
68
  "config": {
51
69
  "profileSlug": "bookmark",
52
- "title": "{{loop.item}}",
70
+ "title": "{{steps.title-src.output.result}}",
53
71
  "dedupeBy": "url",
72
+ "body": "{{steps.content.output.result}}",
54
73
  "properties": {
55
74
  "url": "{{loop.item}}",
75
+ "sourceChannelId": "{{trigger.payload.data.channelId}}",
76
+ "sourceThreadId": "{{trigger.payload.data.threadId}}",
56
77
  "sourceMessageId": "{{trigger.payload.data.messageId}}",
57
- "sourceChannelId": "{{trigger.payload.data.threadId}}"
78
+ "sourceProvider": "{{trigger.payload.data.provider}}",
79
+ "sharedBy": "{{trigger.payload.data.participantName}}"
58
80
  }
59
81
  }
60
82
  }
83
+ },
84
+ {
85
+ "id": "has-bookmark-id",
86
+ "type": "condition",
87
+ "position": { "x": 0, "y": 720 },
88
+ "data": {
89
+ "label": "Bookmark row exists?",
90
+ "expression": "steps.create-bookmark.output.entityId !== ''"
91
+ }
92
+ },
93
+ {
94
+ "id": "has-context-entity",
95
+ "type": "condition",
96
+ "position": { "x": 0, "y": 840 },
97
+ "data": {
98
+ "label": "Channel bound to an entity?",
99
+ "expression": "trigger.payload.data.entityId !== ''"
100
+ }
101
+ },
102
+ {
103
+ "id": "link-context",
104
+ "type": "output",
105
+ "position": { "x": 0, "y": 960 },
106
+ "data": {
107
+ "label": "Link bookmark → channel's entity",
108
+ "outputType": "relation_create",
109
+ "config": {
110
+ "fromEntityId": "{{steps.create-bookmark.output.entityId}}",
111
+ "toEntityId": "{{trigger.payload.data.entityId}}",
112
+ "relationType": "references"
113
+ }
114
+ }
61
115
  }
62
116
  ],
63
117
  "edges": [
64
- { "id": "e1", "source": "trigger", "target": "extract" },
65
- { "id": "e2", "source": "extract", "target": "url-loop" },
66
- { "id": "e3", "source": "url-loop", "target": "create-bookmark" }
118
+ { "id": "e1", "source": "trigger", "target": "content" },
119
+ { "id": "e2", "source": "content", "target": "title-src" },
120
+ { "id": "e3", "source": "title-src", "target": "extract" },
121
+ { "id": "e4", "source": "extract", "target": "url-loop" },
122
+ { "id": "e5", "source": "url-loop", "target": "create-bookmark" },
123
+ { "id": "e6", "source": "create-bookmark", "target": "has-bookmark-id" },
124
+ { "id": "e7", "source": "has-bookmark-id", "target": "has-context-entity", "sourceHandle": "yes" },
125
+ { "id": "e8", "source": "has-context-entity", "target": "link-context", "sourceHandle": "yes" }
67
126
  ]
68
127
  },
69
- "metadata": { "source": "bridge-template" }
128
+ "metadata": {
129
+ "source": "bridge-template",
130
+ "note": "Phase 1 is DETERMINISTIC — no AI. It keeps the context the trigger already hands it: data.channelId (the INTERNAL Synap channel UUID, not the Discord snowflake, which is kept separately as sourceThreadId), data.content (as the bookmark body) and data.entityId (the channel's bound entity, linked with a `references` relation). Title = the message's own 120-char preview; when the message is nothing but a link the item is dropped by the noise filter rather than named, so the title is never invented. Noise filter: `filter:item !== steps.content.output.result` keeps only links that arrived WITH human text — a Tenor/giphy GIF drop or a bare Google Photos paste is exactly a message whose whole trimmed text IS the URL. A host denylist is NOT expressible: the condition grammar (condition-eval.ts) has no substring/regex operator and `contains` is exact set intersection, so any 'tenor.com'-style match would silently never fire."
131
+ }
70
132
  }
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env python3
2
+ """The synap box runner: the only program the box template starts on boot.
3
+
4
+ It holds no credential. It fetches its job from the provisioner by the
5
+ provisioner's address on the isolated bridge, installs the declared packages
6
+ (setup phase: the egress proxy lets only the package registries through),
7
+ tells the provisioner it is done installing (run phase: only the declared
8
+ hosts), runs the script as the unprivileged user `box` with /in and /out,
9
+ streams the log back, uploads /out and reports the exit code.
10
+
11
+ The provisioner, not this program, enforces the wall clock: it destroys the box.
12
+ Python stdlib only (Debian 12's python3), so the template needs nothing else to
13
+ run it. Contract with the provisioner: synap-cli src/lib/box/job-server.ts.
14
+ """
15
+
16
+ import json
17
+ import os
18
+ import pwd
19
+ import subprocess
20
+ import sys
21
+ import threading
22
+ import time
23
+ import urllib.parse
24
+ import urllib.request
25
+
26
+ BASE = os.environ.get("SYNAP_BOX_PROVISIONER", "http://10.20.0.1:8790")
27
+ PROXY = os.environ.get("SYNAP_BOX_PROXY", "http://10.20.0.1:3128")
28
+ WORK, IN, OUT = "/work", "/in", "/out"
29
+ USER = "box"
30
+ MAX_OUT_FILES = 20
31
+
32
+ # The job server is on the bridge: never through the proxy.
33
+ _direct = urllib.request.build_opener(urllib.request.ProxyHandler({}))
34
+
35
+
36
+ def call(method, path, body=None, ctype="application/json", timeout=60):
37
+ data = body if isinstance(body, (bytes, type(None))) else json.dumps(body).encode()
38
+ req = urllib.request.Request(BASE + path, data=data, method=method)
39
+ if data is not None:
40
+ req.add_header("Content-Type", ctype)
41
+ with _direct.open(req, timeout=timeout) as res:
42
+ raw = res.read()
43
+ return json.loads(raw) if raw and res.headers.get("content-type", "").startswith("application/json") else None
44
+
45
+
46
+ def fetch_job():
47
+ # The box may boot before the provisioner registers its address: retry.
48
+ deadline = time.time() + 180
49
+ while True:
50
+ try:
51
+ return call("GET", "/job")
52
+ except Exception as err: # noqa: BLE001
53
+ if time.time() > deadline:
54
+ raise SystemExit(f"no job from {BASE}: {err}")
55
+ time.sleep(2)
56
+
57
+
58
+ class LogPump:
59
+ """Batches output and POSTs it to /log about twice a second."""
60
+
61
+ def __init__(self):
62
+ self.buf = bytearray()
63
+ self.lock = threading.Lock()
64
+ self.stop = threading.Event()
65
+ self.thread = threading.Thread(target=self._loop, daemon=True)
66
+ self.thread.start()
67
+
68
+ def write(self, data):
69
+ with self.lock:
70
+ self.buf += data
71
+
72
+ def _flush(self):
73
+ with self.lock:
74
+ chunk, self.buf = bytes(self.buf), bytearray()
75
+ if chunk:
76
+ try:
77
+ call("POST", "/log", chunk, "application/octet-stream")
78
+ except Exception: # noqa: BLE001 - a lost log chunk must not kill the run
79
+ pass
80
+
81
+ def _loop(self):
82
+ while not self.stop.wait(0.5):
83
+ self._flush()
84
+
85
+ def close(self):
86
+ self.stop.set()
87
+ self.thread.join()
88
+ self._flush()
89
+
90
+
91
+ def demote(user):
92
+ pw = pwd.getpwnam(user)
93
+
94
+ def run_as():
95
+ os.setgroups([])
96
+ os.setgid(pw.pw_gid)
97
+ os.setuid(pw.pw_uid)
98
+
99
+ return run_as, pw
100
+
101
+
102
+ def run(cmd, env, pump):
103
+ """Run cmd as the box user; its stdout+stderr go to the log. Returns the exit code."""
104
+ pre, pw = demote(USER)
105
+ pump.write(("$ " + " ".join(cmd) + "\n").encode())
106
+ proc = subprocess.Popen(
107
+ cmd, cwd=WORK, env={**env, "HOME": pw.pw_dir, "USER": USER},
108
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn=pre,
109
+ )
110
+ for chunk in iter(lambda: proc.stdout.read1(65536), b""):
111
+ pump.write(chunk)
112
+ return proc.wait()
113
+
114
+
115
+ def installed(job, env):
116
+ try:
117
+ if job["language"] == "python":
118
+ out = subprocess.run(
119
+ ["uv", "pip", "list", "--python", f"{WORK}/.venv/bin/python", "--format", "json"],
120
+ cwd=WORK, env=env, capture_output=True, timeout=60,
121
+ ).stdout
122
+ return [{"name": p["name"], "version": p["version"], "manager": "pip"} for p in json.loads(out or b"[]")]
123
+ out = subprocess.run(
124
+ ["pnpm", "list", "--json", "--depth", "0"], cwd=WORK, env=env, capture_output=True, timeout=60,
125
+ ).stdout
126
+ deps = (json.loads(out or b"[{}]") or [{}])[0].get("dependencies", {}) or {}
127
+ return [{"name": n, "version": d.get("version", ""), "manager": "npm"} for n, d in deps.items()]
128
+ except Exception: # noqa: BLE001 - the list is evidence, not the verdict
129
+ return []
130
+
131
+
132
+ def upload_out(pump):
133
+ sent = 0
134
+ for root, _dirs, files in os.walk(OUT):
135
+ for name in sorted(files):
136
+ full = os.path.join(root, name)
137
+ if os.path.islink(full) or not os.path.isfile(full):
138
+ continue
139
+ rel = os.path.relpath(full, OUT)
140
+ if sent >= MAX_OUT_FILES:
141
+ pump.write(f"\n[synap box] /out/{rel} skipped: at most {MAX_OUT_FILES} files\n".encode())
142
+ continue
143
+ try:
144
+ with open(full, "rb") as fh:
145
+ call("PUT", "/out/" + urllib.parse.quote(rel), fh.read(), "application/octet-stream", timeout=600)
146
+ sent += 1
147
+ except Exception as err: # noqa: BLE001
148
+ pump.write(f"\n[synap box] /out/{rel} not uploaded: {err}\n".encode())
149
+
150
+
151
+ def main():
152
+ job = fetch_job()
153
+ pump = LogPump()
154
+ for d in (WORK, IN, OUT):
155
+ os.makedirs(d, exist_ok=True)
156
+ pw = pwd.getpwnam(USER)
157
+ for d in (WORK, OUT):
158
+ os.chown(d, pw.pw_uid, pw.pw_gid)
159
+
160
+ entry = os.path.normpath(job["entrypoint"])
161
+ if entry.startswith("..") or os.path.isabs(entry):
162
+ raise SystemExit(f"bad entrypoint {job['entrypoint']!r}")
163
+ os.makedirs(os.path.dirname(os.path.join(WORK, entry)), exist_ok=True)
164
+ with open(os.path.join(WORK, entry), "w") as fh:
165
+ fh.write(job["code"])
166
+ os.chown(os.path.join(WORK, entry), pw.pw_uid, pw.pw_gid)
167
+ with open(os.path.join(IN, "parameters.json"), "w") as fh:
168
+ json.dump(job.get("parameters"), fh)
169
+
170
+ env = {
171
+ "PATH": "/usr/local/bin:/usr/bin:/bin",
172
+ "LANG": "C.UTF-8",
173
+ "HTTP_PROXY": PROXY, "HTTPS_PROXY": PROXY, "http_proxy": PROXY, "https_proxy": PROXY,
174
+ "npm_config_proxy": PROXY, "npm_config_https_proxy": PROXY,
175
+ # Node's own fetch ignores HTTP(S)_PROXY unless told (Node >= 22.21 / 24).
176
+ "NODE_USE_ENV_PROXY": "1",
177
+ "UV_CACHE_DIR": f"{WORK}/.cache/uv", "npm_config_cache": f"{WORK}/.cache/npm",
178
+ "SYNAP_PARAMETERS_FILE": f"{IN}/parameters.json", "SYNAP_OUT_DIR": OUT,
179
+ }
180
+ pkgs = job.get("packages") or []
181
+ if job["language"] == "python":
182
+ code = run(["uv", "venv", f"{WORK}/.venv"], env, pump)
183
+ if code == 0 and pkgs:
184
+ code = run(["uv", "pip", "install", "--python", f"{WORK}/.venv/bin/python",
185
+ *[f"{p['name']}=={p['version']}" for p in pkgs]], env, pump)
186
+ cmd = [f"{WORK}/.venv/bin/python", entry]
187
+ else:
188
+ with open(os.path.join(WORK, "package.json"), "w") as fh:
189
+ json.dump({"private": True}, fh)
190
+ os.chown(os.path.join(WORK, "package.json"), pw.pw_uid, pw.pw_gid)
191
+ code = run(["pnpm", "add", *[f"{p['name']}@{p['version']}" for p in pkgs]], env, pump) if pkgs else 0
192
+ cmd = ["node", entry]
193
+
194
+ call("POST", "/phase", {"phase": "run"})
195
+ if code == 0:
196
+ code = run(cmd, env, pump)
197
+ else:
198
+ pump.write(f"\n[synap box] packages did not install (exit {code}); the script was not run\n".encode())
199
+
200
+ upload_out(pump)
201
+ pump.close()
202
+ call("POST", "/done", {"exitCode": code, "installedPackages": installed(job, env)})
203
+
204
+
205
+ if __name__ == "__main__":
206
+ sys.exit(main())