@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.
- package/LICENSE +21 -0
- package/README.md +40 -198
- package/dist/build-info.json +6 -0
- package/dist/commands/agent-run.js +3 -2
- package/dist/commands/agent-run.js.map +1 -1
- package/dist/commands/agents.d.ts +32 -17
- package/dist/commands/agents.js +203 -237
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/app.d.ts +143 -0
- package/dist/commands/app.js +524 -0
- package/dist/commands/app.js.map +1 -0
- package/dist/commands/automate.d.ts +21 -0
- package/dist/commands/automate.js +42 -0
- package/dist/commands/automate.js.map +1 -0
- package/dist/commands/automation-schema.test.d.ts +16 -0
- package/dist/commands/automation-schema.test.js +77 -0
- package/dist/commands/automation-schema.test.js.map +1 -0
- package/dist/commands/automation.d.ts +12 -0
- package/dist/commands/automation.js +116 -66
- package/dist/commands/automation.js.map +1 -1
- package/dist/commands/box.d.ts +42 -0
- package/dist/commands/box.js +89 -0
- package/dist/commands/box.js.map +1 -0
- package/dist/commands/bridge-setup.d.ts +14 -1
- package/dist/commands/bridge-setup.js +395 -129
- package/dist/commands/bridge-setup.js.map +1 -1
- package/dist/commands/cap-connections.d.ts +4 -4
- package/dist/commands/cap-connections.js +14 -14
- package/dist/commands/cap-connections.js.map +1 -1
- package/dist/commands/capability.d.ts +3 -1
- package/dist/commands/capability.js +249 -176
- package/dist/commands/capability.js.map +1 -1
- package/dist/commands/catalog.d.ts +275 -0
- package/dist/commands/catalog.js +481 -0
- package/dist/commands/catalog.js.map +1 -0
- package/dist/commands/cell.d.ts +155 -8
- package/dist/commands/cell.js +416 -40
- package/dist/commands/cell.js.map +1 -1
- package/dist/commands/centrality.js +1 -13
- package/dist/commands/centrality.js.map +1 -1
- package/dist/commands/close-questions.d.ts +27 -0
- package/dist/commands/close-questions.js +49 -0
- package/dist/commands/close-questions.js.map +1 -0
- package/dist/commands/close-questions.test.d.ts +1 -0
- package/dist/commands/close-questions.test.js +52 -0
- package/dist/commands/close-questions.test.js.map +1 -0
- package/dist/commands/connect.d.ts +36 -13
- package/dist/commands/connect.js +68 -167
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/connections.d.ts +3 -2
- package/dist/commands/connections.js +95 -25
- package/dist/commands/connections.js.map +1 -1
- package/dist/commands/context.js +79 -44
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/data-extra.d.ts +34 -0
- package/dist/commands/data-extra.js +203 -25
- package/dist/commands/data-extra.js.map +1 -1
- package/dist/commands/data.d.ts +120 -2
- package/dist/commands/data.js +295 -21
- package/dist/commands/data.js.map +1 -1
- package/dist/commands/diagnose.d.ts +66 -4
- package/dist/commands/diagnose.js +285 -28
- package/dist/commands/diagnose.js.map +1 -1
- package/dist/commands/doc.d.ts +11 -4
- package/dist/commands/doc.js +39 -14
- package/dist/commands/doc.js.map +1 -1
- package/dist/commands/doctor.d.ts +133 -3
- package/dist/commands/doctor.js +761 -41
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain.js +5 -5
- package/dist/commands/explain.js.map +1 -1
- package/dist/commands/hooks.d.ts +19 -0
- package/dist/commands/hooks.js +70 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/import.d.ts +393 -13
- package/dist/commands/import.js +1150 -54
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/init.d.ts +34 -9
- package/dist/commands/init.js +481 -981
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys.d.ts +1 -0
- package/dist/commands/keys.js +15 -2
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/knowledge.d.ts +22 -6
- package/dist/commands/knowledge.js +121 -57
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/lens.d.ts +37 -1
- package/dist/commands/lens.js +194 -72
- package/dist/commands/lens.js.map +1 -1
- package/dist/commands/market-authoring.d.ts +29 -2
- package/dist/commands/market-authoring.js +348 -7
- package/dist/commands/market-authoring.js.map +1 -1
- package/dist/commands/market-official.d.ts +58 -0
- package/dist/commands/market-official.js +84 -0
- package/dist/commands/market-official.js.map +1 -0
- package/dist/commands/market.d.ts +400 -16
- package/dist/commands/market.js +1802 -146
- package/dist/commands/market.js.map +1 -1
- package/dist/commands/mcp.d.ts +60 -25
- package/dist/commands/mcp.js +251 -64
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/observe.category.test.d.ts +1 -0
- package/dist/commands/observe.category.test.js +59 -0
- package/dist/commands/observe.category.test.js.map +1 -0
- package/dist/commands/observe.d.ts +3 -0
- package/dist/commands/observe.js +7 -5
- package/dist/commands/observe.js.map +1 -1
- package/dist/commands/observe.title.test.d.ts +1 -0
- package/dist/commands/observe.title.test.js +37 -0
- package/dist/commands/observe.title.test.js.map +1 -0
- package/dist/commands/open.d.ts +39 -9
- package/dist/commands/open.js +80 -25
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/playbook.d.ts +42 -0
- package/dist/commands/playbook.js +171 -0
- package/dist/commands/playbook.js.map +1 -0
- package/dist/commands/pod.js +1 -1
- package/dist/commands/pod.js.map +1 -1
- package/dist/commands/pods.d.ts +11 -1
- package/dist/commands/pods.js +129 -131
- package/dist/commands/pods.js.map +1 -1
- package/dist/commands/proposals-actions.d.ts +62 -0
- package/dist/commands/proposals-actions.js +143 -8
- package/dist/commands/proposals-actions.js.map +1 -1
- package/dist/commands/proposals-await.d.ts +68 -0
- package/dist/commands/proposals-await.js +248 -0
- package/dist/commands/proposals-await.js.map +1 -0
- package/dist/commands/proton-setup.d.ts +73 -0
- package/dist/commands/proton-setup.js +579 -0
- package/dist/commands/proton-setup.js.map +1 -0
- package/dist/commands/providers.d.ts +23 -0
- package/dist/commands/providers.js +126 -1
- package/dist/commands/providers.js.map +1 -1
- package/dist/commands/raycast.js +6 -2
- package/dist/commands/raycast.js.map +1 -1
- package/dist/commands/rule.d.ts +150 -0
- package/dist/commands/rule.js +447 -0
- package/dist/commands/rule.js.map +1 -0
- package/dist/commands/session-feed-wait.d.ts +48 -0
- package/dist/commands/session-feed-wait.js +261 -0
- package/dist/commands/session-feed-wait.js.map +1 -0
- package/dist/commands/session-post.d.ts +40 -0
- package/dist/commands/session-post.js +96 -0
- package/dist/commands/session-post.js.map +1 -0
- package/dist/commands/session-wait.d.ts +116 -0
- package/dist/commands/session-wait.js +224 -0
- package/dist/commands/session-wait.js.map +1 -0
- package/dist/commands/sessions.d.ts +54 -0
- package/dist/commands/sessions.js +501 -58
- package/dist/commands/sessions.js.map +1 -1
- package/dist/commands/skill-manage.d.ts +21 -0
- package/dist/commands/skill-manage.js +136 -19
- package/dist/commands/skill-manage.js.map +1 -1
- package/dist/commands/skills-commands.d.ts +2 -0
- package/dist/commands/skills-commands.js +9 -1
- package/dist/commands/skills-commands.js.map +1 -1
- package/dist/commands/skills-commands.test.d.ts +1 -0
- package/dist/commands/skills-commands.test.js +57 -0
- package/dist/commands/skills-commands.test.js.map +1 -0
- package/dist/commands/skills.js +16 -0
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/status.d.ts +1 -4
- package/dist/commands/status.js +6 -35
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/statusline.backoff.test.d.ts +13 -0
- package/dist/commands/statusline.backoff.test.js +100 -0
- package/dist/commands/statusline.backoff.test.js.map +1 -0
- package/dist/commands/statusline.js +16 -9
- package/dist/commands/statusline.js.map +1 -1
- package/dist/commands/sync-status.d.ts +12 -0
- package/dist/commands/sync-status.js +125 -0
- package/dist/commands/sync-status.js.map +1 -0
- package/dist/commands/templates-retire.d.ts +34 -0
- package/dist/commands/templates-retire.js +192 -0
- package/dist/commands/templates-retire.js.map +1 -0
- package/dist/commands/tools.js +6 -21
- package/dist/commands/tools.js.map +1 -1
- package/dist/commands/tracks.d.ts +112 -0
- package/dist/commands/tracks.js +543 -0
- package/dist/commands/tracks.js.map +1 -0
- package/dist/commands/update.d.ts +3 -11
- package/dist/commands/update.js +5 -134
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/upload.d.ts +41 -3
- package/dist/commands/upload.js +120 -18
- package/dist/commands/upload.js.map +1 -1
- package/dist/commands/vendor.d.ts +28 -0
- package/dist/commands/vendor.js +110 -0
- package/dist/commands/vendor.js.map +1 -0
- package/dist/commands/versions.js +6 -0
- package/dist/commands/versions.js.map +1 -1
- package/dist/commands/view.js +10 -5
- package/dist/commands/view.js.map +1 -1
- package/dist/commands/whoami.d.ts +30 -3
- package/dist/commands/whoami.js +186 -23
- package/dist/commands/whoami.js.map +1 -1
- package/dist/commands/worker-accounts.d.ts +149 -0
- package/dist/commands/worker-accounts.js +339 -0
- package/dist/commands/worker-accounts.js.map +1 -0
- package/dist/commands/worker-accounts.test.d.ts +1 -0
- package/dist/commands/worker-accounts.test.js +224 -0
- package/dist/commands/worker-accounts.test.js.map +1 -0
- package/dist/commands/worker.d.ts +331 -0
- package/dist/commands/worker.js +1067 -0
- package/dist/commands/worker.js.map +1 -0
- package/dist/commands/worker.test.d.ts +1 -0
- package/dist/commands/worker.test.js +427 -0
- package/dist/commands/worker.test.js.map +1 -0
- package/dist/commands/workspace-ops.d.ts +35 -0
- package/dist/commands/workspace-ops.js +153 -0
- package/dist/commands/workspace-ops.js.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +1043 -186
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-connections.d.ts +31 -0
- package/dist/lib/agent-connections.js +33 -0
- package/dist/lib/agent-connections.js.map +1 -0
- package/dist/lib/agent-detect.d.ts +27 -0
- package/dist/lib/agent-detect.js +71 -0
- package/dist/lib/agent-detect.js.map +1 -0
- package/dist/lib/agent-door.d.ts +136 -0
- package/dist/lib/agent-door.js +429 -0
- package/dist/lib/agent-door.js.map +1 -0
- package/dist/lib/agents-config.d.ts +2 -0
- package/dist/lib/agents-config.js +4 -9
- package/dist/lib/agents-config.js.map +1 -1
- package/dist/lib/approval-poll.d.ts +31 -2
- package/dist/lib/approval-poll.js +20 -7
- package/dist/lib/approval-poll.js.map +1 -1
- package/dist/lib/atomic-file.d.ts +48 -0
- package/dist/lib/atomic-file.js +129 -0
- package/dist/lib/atomic-file.js.map +1 -0
- package/dist/lib/auth.d.ts +17 -11
- package/dist/lib/auth.js +47 -64
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/batch-approval.d.ts +85 -0
- package/dist/lib/batch-approval.js +170 -0
- package/dist/lib/batch-approval.js.map +1 -0
- package/dist/lib/box/egress.d.ts +82 -0
- package/dist/lib/box/egress.js +264 -0
- package/dist/lib/box/egress.js.map +1 -0
- package/dist/lib/box/evidence.d.ts +86 -0
- package/dist/lib/box/evidence.js +121 -0
- package/dist/lib/box/evidence.js.map +1 -0
- package/dist/lib/box/job-server.d.ts +72 -0
- package/dist/lib/box/job-server.js +246 -0
- package/dist/lib/box/job-server.js.map +1 -0
- package/dist/lib/box/provisioner.d.ts +83 -0
- package/dist/lib/box/provisioner.js +312 -0
- package/dist/lib/box/provisioner.js.map +1 -0
- package/dist/lib/box/proxmox.d.ts +112 -0
- package/dist/lib/box/proxmox.js +211 -0
- package/dist/lib/box/proxmox.js.map +1 -0
- package/dist/lib/box/wire.d.ts +98 -0
- package/dist/lib/box/wire.js +70 -0
- package/dist/lib/box/wire.js.map +1 -0
- package/dist/lib/capture-lane.d.ts +6 -5
- package/dist/lib/capture-lane.js +6 -5
- package/dist/lib/capture-lane.js.map +1 -1
- package/dist/lib/capture-structure.d.ts +230 -11
- package/dist/lib/capture-structure.js +251 -13
- package/dist/lib/capture-structure.js.map +1 -1
- package/dist/lib/catalog-templates.d.ts +59 -0
- package/dist/lib/catalog-templates.js +126 -0
- package/dist/lib/catalog-templates.js.map +1 -0
- package/dist/lib/cli-build.d.ts +19 -0
- package/dist/lib/cli-build.js +37 -0
- package/dist/lib/cli-build.js.map +1 -0
- package/dist/lib/client-header.test.d.ts +1 -0
- package/dist/lib/client-header.test.js +85 -0
- package/dist/lib/client-header.test.js.map +1 -0
- package/dist/lib/conversation-headers.d.ts +33 -0
- package/dist/lib/conversation-headers.js +69 -0
- package/dist/lib/conversation-headers.js.map +1 -0
- package/dist/lib/cp-packages.d.ts +167 -11
- package/dist/lib/cp-packages.js +253 -21
- package/dist/lib/cp-packages.js.map +1 -1
- package/dist/lib/credential-class.d.ts +144 -0
- package/dist/lib/credential-class.js +138 -0
- package/dist/lib/credential-class.js.map +1 -0
- package/dist/lib/describe-lens.d.ts +35 -0
- package/dist/lib/describe-lens.js +40 -0
- package/dist/lib/describe-lens.js.map +1 -1
- package/dist/lib/device-connect.d.ts +125 -0
- package/dist/lib/device-connect.js +256 -0
- package/dist/lib/device-connect.js.map +1 -0
- package/dist/lib/directory-lens.d.ts +99 -0
- package/dist/lib/directory-lens.js +187 -0
- package/dist/lib/directory-lens.js.map +1 -0
- package/dist/lib/exporter-coverage.d.ts +71 -0
- package/dist/lib/exporter-coverage.js +97 -0
- package/dist/lib/exporter-coverage.js.map +1 -0
- package/dist/lib/goal-words.d.ts +38 -0
- package/dist/lib/goal-words.js +112 -0
- package/dist/lib/goal-words.js.map +1 -0
- package/dist/lib/hub-client.d.ts +57 -15
- package/dist/lib/hub-client.js +396 -82
- package/dist/lib/hub-client.js.map +1 -1
- package/dist/lib/init-connect.d.ts +41 -0
- package/dist/lib/init-connect.js +75 -0
- package/dist/lib/init-connect.js.map +1 -0
- package/dist/lib/init-exit.d.ts +24 -0
- package/dist/lib/init-exit.js +41 -0
- package/dist/lib/init-exit.js.map +1 -0
- package/dist/lib/init-flow.d.ts +25 -0
- package/dist/lib/init-flow.js +40 -0
- package/dist/lib/init-flow.js.map +1 -0
- package/dist/lib/init-handoff.d.ts +24 -0
- package/dist/lib/init-handoff.js +26 -0
- package/dist/lib/init-handoff.js.map +1 -0
- package/dist/lib/init-output.d.ts +18 -0
- package/dist/lib/init-output.js +43 -0
- package/dist/lib/init-output.js.map +1 -0
- package/dist/lib/init-pod.d.ts +45 -0
- package/dist/lib/init-pod.js +36 -0
- package/dist/lib/init-pod.js.map +1 -0
- package/dist/lib/installed.d.ts +210 -11
- package/dist/lib/installed.js +234 -36
- package/dist/lib/installed.js.map +1 -1
- package/dist/lib/key-approval.d.ts +57 -0
- package/dist/lib/key-approval.js +117 -0
- package/dist/lib/key-approval.js.map +1 -0
- package/dist/lib/key-diagnosis.d.ts +56 -0
- package/dist/lib/key-diagnosis.js +227 -0
- package/dist/lib/key-diagnosis.js.map +1 -0
- package/dist/lib/key-doctor.d.ts +136 -0
- package/dist/lib/key-doctor.js +286 -0
- package/dist/lib/key-doctor.js.map +1 -0
- package/dist/lib/key-locations.d.ts +120 -0
- package/dist/lib/key-locations.js +326 -0
- package/dist/lib/key-locations.js.map +1 -0
- package/dist/lib/key-source.d.ts +68 -0
- package/dist/lib/key-source.js +109 -0
- package/dist/lib/key-source.js.map +1 -0
- package/dist/lib/key-state.d.ts +70 -0
- package/dist/lib/key-state.js +115 -0
- package/dist/lib/key-state.js.map +1 -0
- package/dist/lib/kind-package.d.ts +181 -0
- package/dist/lib/kind-package.js +679 -0
- package/dist/lib/kind-package.js.map +1 -0
- package/dist/lib/knowledge-title.d.ts +25 -0
- package/dist/lib/knowledge-title.js +47 -0
- package/dist/lib/knowledge-title.js.map +1 -0
- package/dist/lib/knowledge-title.test.d.ts +1 -0
- package/dist/lib/knowledge-title.test.js +34 -0
- package/dist/lib/knowledge-title.test.js.map +1 -0
- package/dist/lib/machine-instance.d.ts +64 -0
- package/dist/lib/machine-instance.js +142 -0
- package/dist/lib/machine-instance.js.map +1 -0
- package/dist/lib/mcp-bridge.d.ts +49 -0
- package/dist/lib/mcp-bridge.js +180 -0
- package/dist/lib/mcp-bridge.js.map +1 -0
- package/dist/lib/mcp-bridge.test.d.ts +1 -0
- package/dist/lib/mcp-bridge.test.js +118 -0
- package/dist/lib/mcp-bridge.test.js.map +1 -0
- package/dist/lib/mcp-call.d.ts +30 -0
- package/dist/lib/mcp-call.js +107 -0
- package/dist/lib/mcp-call.js.map +1 -0
- package/dist/lib/mcp-snippets.d.ts +53 -0
- package/dist/lib/mcp-snippets.js +82 -0
- package/dist/lib/mcp-snippets.js.map +1 -0
- package/dist/lib/next-steps.d.ts +8 -0
- package/dist/lib/next-steps.js +31 -1
- package/dist/lib/next-steps.js.map +1 -1
- package/dist/lib/openclaw.js +3 -2
- package/dist/lib/openclaw.js.map +1 -1
- package/dist/lib/package-wire.d.ts +179 -0
- package/dist/lib/package-wire.js +68 -0
- package/dist/lib/package-wire.js.map +1 -0
- package/dist/lib/pair-link.d.ts +38 -0
- package/dist/lib/pair-link.js +68 -0
- package/dist/lib/pair-link.js.map +1 -0
- package/dist/lib/pod-moved.d.ts +70 -0
- package/dist/lib/pod-moved.js +146 -0
- package/dist/lib/pod-moved.js.map +1 -0
- package/dist/lib/pod-reach.d.ts +39 -0
- package/dist/lib/pod-reach.js +117 -0
- package/dist/lib/pod-reach.js.map +1 -0
- package/dist/lib/pod-reach.test.d.ts +1 -0
- package/dist/lib/pod-reach.test.js +67 -0
- package/dist/lib/pod-reach.test.js.map +1 -0
- package/dist/lib/pod-wide.d.ts +40 -0
- package/dist/lib/pod-wide.js +46 -0
- package/dist/lib/pod-wide.js.map +1 -0
- package/dist/lib/pod.d.ts +74 -112
- package/dist/lib/pod.js +146 -415
- package/dist/lib/pod.js.map +1 -1
- package/dist/lib/project-ref.d.ts +9 -3
- package/dist/lib/project-ref.js +10 -4
- package/dist/lib/project-ref.js.map +1 -1
- package/dist/lib/register-claude-code-mcp.test.d.ts +1 -0
- package/dist/lib/register-claude-code-mcp.test.js +78 -0
- package/dist/lib/register-claude-code-mcp.test.js.map +1 -0
- package/dist/lib/review-credential.d.ts +119 -0
- package/dist/lib/review-credential.js +149 -0
- package/dist/lib/review-credential.js.map +1 -0
- package/dist/lib/safe-open.d.ts +49 -0
- package/dist/lib/safe-open.js +119 -0
- package/dist/lib/safe-open.js.map +1 -0
- package/dist/lib/session-feed.d.ts +185 -0
- package/dist/lib/session-feed.js +257 -0
- package/dist/lib/session-feed.js.map +1 -0
- package/dist/lib/session-lens.d.ts +40 -1
- package/dist/lib/session-lens.js +54 -4
- package/dist/lib/session-lens.js.map +1 -1
- package/dist/lib/superwhisper-import.d.ts +8 -0
- package/dist/lib/superwhisper-import.js +14 -7
- package/dist/lib/superwhisper-import.js.map +1 -1
- package/dist/lib/superwhisper-title.test.d.ts +1 -0
- package/dist/lib/superwhisper-title.test.js +18 -0
- package/dist/lib/superwhisper-title.test.js.map +1 -0
- package/dist/lib/targets.d.ts +152 -10
- package/dist/lib/targets.js +974 -325
- package/dist/lib/targets.js.map +1 -1
- package/dist/lib/template-file.d.ts +4 -0
- package/dist/lib/template-file.js.map +1 -1
- package/dist/lib/template-lifecycle.d.ts +217 -0
- package/dist/lib/template-lifecycle.js +433 -0
- package/dist/lib/template-lifecycle.js.map +1 -0
- package/dist/lib/template-steps.d.ts +88 -0
- package/dist/lib/template-steps.js +118 -0
- package/dist/lib/template-steps.js.map +1 -0
- package/dist/lib/time-ago.d.ts +2 -0
- package/dist/lib/time-ago.js +15 -0
- package/dist/lib/time-ago.js.map +1 -0
- package/dist/lib/wake-hook-settings.d.ts +57 -0
- package/dist/lib/wake-hook-settings.js +153 -0
- package/dist/lib/wake-hook-settings.js.map +1 -0
- package/dist/lib/wake-state.d.ts +65 -0
- package/dist/lib/wake-state.js +122 -0
- package/dist/lib/wake-state.js.map +1 -0
- package/dist/utils/logger.js +5 -2
- package/dist/utils/logger.js.map +1 -1
- package/package.json +26 -17
- package/skills/README.md +13 -11
- package/skills/agent-os/SKILL.md +214 -99
- package/skills/manifest.json +1 -1
- package/skills/onboard/SKILL.md +55 -26
- package/skills/synap/README.md +5 -8
- package/skills/synap/SKILL.md +1149 -289
- package/skills/synap/_order.txt +7 -0
- package/skills/synap/_skill.yaml +1 -1
- package/skills/synap/automations.md +15 -0
- package/skills/synap/capture.md +5 -0
- package/skills/synap/cli-operations.md +24 -18
- package/skills/synap/code-skills.md +70 -0
- package/skills/synap/concepts.md +36 -0
- package/skills/synap/content-os.md +10 -1
- package/skills/synap/creative-loop.md +15 -10
- package/skills/synap/crm.md +21 -52
- package/skills/synap/document-embeds.md +143 -47
- package/skills/synap/escalation-ladder.md +20 -10
- package/skills/synap/focus-sessions.md +56 -21
- package/skills/synap/from-intent.md +158 -0
- package/skills/synap/governance-rules.md +5 -5
- package/skills/synap/governance.md +10 -7
- package/skills/synap/hand-off.md +33 -0
- package/skills/synap/inline-patterns.md +15 -7
- package/skills/synap/lenses.md +34 -16
- package/skills/synap/linking.md +42 -41
- package/skills/synap/mcp-remote-servers.md +64 -0
- package/skills/synap/mental-model.md +17 -15
- package/skills/synap/operating-mode-rules.md +2 -2
- package/skills/synap/processes.md +118 -0
- package/skills/synap/quick-reference.md +7 -2
- package/skills/synap/reading.md +3 -1
- package/skills/synap/reflexes.md +12 -42
- package/skills/synap/viewframe-cells.md +38 -5
- package/skills/synap/work-flow.md +1 -1
- package/skills/synap/work-model.md +110 -0
- package/skills/synap/worked-examples.md +4 -5
- package/skills/synap/workspace-design.md +15 -11
- package/skills/synap/writes.md +105 -25
- package/skills/synap/writing-titles.md +63 -0
- package/skills/synap-app/SKILL.md +149 -67
- package/skills/synap-app/_skill.yaml +1 -1
- package/skills/synap-app/creating-the-base-app.md +12 -7
- package/skills/synap-app/governance.md +27 -16
- package/skills/synap-app/install-commands.md +18 -9
- package/skills/synap-app/overview.md +16 -9
- package/skills/synap-app/using-the-sdk.md +75 -25
- package/skills/synap-design/SKILL.md +474 -0
- package/skills/synap-design/_order.txt +4 -0
- package/skills/synap-design/_skill.yaml +21 -0
- package/skills/synap-design/loop.md +134 -0
- package/skills/synap-design/overview.md +44 -0
- package/skills/synap-design/principles.md +130 -0
- package/skills/synap-design/system.md +133 -0
- package/skills/synap-market/SKILL.md +306 -16
- package/skills/synap-market/_skill.yaml +1 -1
- package/skills/synap-market/author-and-publish.md +145 -8
- package/skills/synap-market/governance-and-catalog.md +7 -0
- package/skills/synap-market/install.md +79 -1
- package/skills/synap-market/overview.md +74 -6
- package/skills/synap-schema/SKILL.md +172 -10
- package/skills/synap-schema/_order.txt +2 -0
- package/skills/synap-schema/_skill.yaml +4 -2
- package/skills/synap-schema/common-mistakes.md +4 -2
- package/skills/synap-schema/discover-profiles.md +1 -1
- package/skills/synap-schema/entity-scope.md +15 -3
- package/skills/synap-schema/extend-first.md +29 -0
- package/skills/synap-schema/extend-vs-create.md +1 -1
- package/skills/synap-schema/intent-vocabulary-ssot.md +111 -0
- package/skills/synap-schema/property-types.md +1 -1
- package/skills/synap-schema/relations.md +1 -1
- package/skills/synap-ui/SKILL.md +19 -12
- package/skills/synap-ui/_skill.yaml +1 -1
- package/skills/synap-ui/ai-companion.md +1 -1
- package/skills/synap-ui/arranging-bento.md +2 -0
- package/skills/synap-ui/bento-layouts.md +10 -10
- package/skills/synap-ui/bento-recipes.md +313 -543
- package/skills/synap-ui/four-builds.md +5 -0
- package/skills/synap-ui/view-types.md +2 -2
- package/skills/synap-ui/widget-catalog.md +22 -278
- package/templates/automations/bookmark-enrichment.automation.json +290 -13
- package/templates/automations/url-bookmark-capture.automation.json +73 -11
- package/templates/box/runner.py +206 -0
- package/templates/skills/authoring-playbooks/SKILL.md +6 -3
- package/templates/skills/authoring-playbooks/reference/stages-contract.md +15 -0
- package/templates/skills/authoring-playbooks/reference/worked-example.md +3 -0
- package/dist/commands/infra.d.ts +0 -21
- package/dist/commands/infra.js +0 -262
- package/dist/commands/infra.js.map +0 -1
- package/node_modules/@synap/hub-rest-client/dist/index.cjs +0 -1261
- package/node_modules/@synap/hub-rest-client/dist/index.d.cts +0 -1647
- package/node_modules/@synap/hub-rest-client/dist/index.d.ts +0 -1647
- package/node_modules/@synap/hub-rest-client/dist/index.js +0 -1231
- package/node_modules/@synap/hub-rest-client/package.json +0 -45
- package/node_modules/@synap/hub-rest-client/src/client.ts +0 -1631
- package/node_modules/@synap/hub-rest-client/src/errors.ts +0 -30
- package/node_modules/@synap/hub-rest-client/src/index.ts +0 -153
- package/node_modules/@synap/hub-rest-client/src/setup.ts +0 -133
- package/node_modules/@synap/hub-rest-client/src/types.ts +0 -1299
package/dist/lib/pod.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Synap pod connection and management utilities.
|
|
3
3
|
*/
|
|
4
|
+
import { readJsonStrict, writeFileAtomic, ensureSecretDir } from "./atomic-file.js";
|
|
5
|
+
import { PodMovedError, podFetch } from "./pod-moved.js";
|
|
6
|
+
import { classifyFetchError, classifyHttpStatus } from "./pod-reach.js";
|
|
4
7
|
import { execSync } from "child_process";
|
|
5
8
|
import fs from "node:fs";
|
|
6
9
|
import path from "node:path";
|
|
7
10
|
import os from "node:os";
|
|
8
|
-
const CP_URL = process.env.SYNAP_CP_URL ?? "https://api.synap.live";
|
|
9
11
|
// ─── Local CLI config (persists pod connections) ──────────────────────────────
|
|
10
12
|
const CONFIG_DIR = path.join(os.homedir(), ".synap");
|
|
11
13
|
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
@@ -18,45 +20,49 @@ export const SURFACE_NAMES = [
|
|
|
18
20
|
"claude-desktop",
|
|
19
21
|
"cursor",
|
|
20
22
|
"codex",
|
|
23
|
+
"chatgpt",
|
|
24
|
+
"chatgpt-oauth",
|
|
21
25
|
"opencode",
|
|
22
26
|
"aider",
|
|
23
27
|
"windsurf",
|
|
24
28
|
"goose",
|
|
25
29
|
"zed",
|
|
26
30
|
"vscode",
|
|
31
|
+
"grok",
|
|
27
32
|
"discord",
|
|
33
|
+
"proton",
|
|
34
|
+
"generic",
|
|
28
35
|
];
|
|
29
36
|
/**
|
|
30
|
-
* agentTypes already owned by OTHER doors —
|
|
31
|
-
*
|
|
32
|
-
* one of these would
|
|
33
|
-
* surfaces above plus the non-surface provisioning types (generic/openwebui
|
|
34
|
-
* mappings;
|
|
37
|
+
* agentTypes already owned by OTHER doors — provisioning is singleton per
|
|
38
|
+
* (createdByUserId, agentType), so `agents create` deriving a slug that collides
|
|
39
|
+
* with one of these would reuse that surface's agent for this user. Superset of
|
|
40
|
+
* the surfaces above plus the non-surface provisioning types (generic/openwebui
|
|
41
|
+
* MCP mappings; cli/memory, and the retired "openclaw", which pods may still
|
|
42
|
+
* hold an agent of). Single source of truth for the collision guard.
|
|
35
43
|
*/
|
|
36
44
|
export const RESERVED_AGENT_TYPES = new Set([
|
|
37
45
|
...SURFACE_NAMES,
|
|
38
|
-
"generic",
|
|
39
46
|
"openwebui",
|
|
40
47
|
"openclaw",
|
|
41
48
|
"cli",
|
|
42
49
|
"memory",
|
|
43
50
|
]);
|
|
44
51
|
function ensureConfigDir() {
|
|
45
|
-
|
|
46
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
47
|
-
}
|
|
52
|
+
ensureSecretDir(CONFIG_DIR);
|
|
48
53
|
}
|
|
49
54
|
function readMultiConfig() {
|
|
50
|
-
// Read new format
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
55
|
+
// Read new format. A file that exists but does not parse THROWS
|
|
56
|
+
// (`ConfigUnreadableError`): read as "no pods", the next write would have
|
|
57
|
+
// persisted that and wiped every profile.
|
|
58
|
+
{
|
|
59
|
+
const parsed = readJsonStrict(CONFIG_FILE);
|
|
60
|
+
if (parsed) {
|
|
54
61
|
if (parsed.pods)
|
|
55
|
-
return { activePod: parsed.activePod ?? "", pods: parsed.pods, activeWorkspaceId: parsed.activeWorkspaceId, activeWorkspace: parsed.activeWorkspace, activeProjectId: parsed.activeProjectId, activeProject: parsed.activeProject, surfaces: parsed.surfaces, agentKeys: parsed.agentKeys, agentWorkspaceRouting: parsed.agentWorkspaceRouting };
|
|
62
|
+
return { activePod: parsed.activePod ?? "", pods: parsed.pods, activeWorkspaceId: parsed.activeWorkspaceId, activeWorkspace: parsed.activeWorkspace, activeProjectId: parsed.activeProjectId, activeProject: parsed.activeProject, surfaces: parsed.surfaces, agentKeys: parsed.agentKeys, agentKeysByPod: parsed.agentKeysByPod, pendingAgentKeys: parsed.pendingAgentKeys, agentWorkspaceRouting: parsed.agentWorkspaceRouting };
|
|
56
63
|
// File exists but has old/unrecognized shape — fall through to migration
|
|
57
64
|
}
|
|
58
65
|
}
|
|
59
|
-
catch { /* fall through */ }
|
|
60
66
|
// Migrate from legacy flat format
|
|
61
67
|
try {
|
|
62
68
|
if (fs.existsSync(LEGACY_CONFIG_FILE)) {
|
|
@@ -75,14 +81,10 @@ function writeMultiConfig(config) {
|
|
|
75
81
|
ensureConfigDir();
|
|
76
82
|
// Merge with existing file so fields managed by other modules (e.g. `agents`)
|
|
77
83
|
// are preserved when pod.ts only updates its own subset.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
catch { /* start fresh */ }
|
|
85
|
-
fs.writeFileSync(CONFIG_FILE, JSON.stringify({ ...existing, ...config }, null, 2), { mode: 0o600 });
|
|
84
|
+
// An unreadable file throws here — never "start fresh" over someone's profiles.
|
|
85
|
+
const existing = readJsonStrict(CONFIG_FILE) ?? {};
|
|
86
|
+
// temp + fsync + rename: a crash mid-write never leaves a truncated config.
|
|
87
|
+
writeFileAtomic(CONFIG_FILE, JSON.stringify({ ...existing, ...config }, null, 2), { mode: 0o600 });
|
|
86
88
|
}
|
|
87
89
|
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
88
90
|
/**
|
|
@@ -162,12 +164,17 @@ export function setPodOverrideByName(name) {
|
|
|
162
164
|
return pod;
|
|
163
165
|
}
|
|
164
166
|
/** Top-level commands that declare their OWN `--pod <name>` — their native handling must win. */
|
|
165
|
-
|
|
167
|
+
// bridge-setup owns a command-local --pod with custom prompt UX — leave it alone.
|
|
168
|
+
// agents used to be here too, but commander root also registers --pod and the
|
|
169
|
+
// flag never reached `agents create` (opts.pod stayed undefined), so create
|
|
170
|
+
// fell through to env agent keys → SURFACE_AGENT_TYPE_REQUIRED. Agents now
|
|
171
|
+
// rely on this bootstrap override like every other command.
|
|
172
|
+
const NATIVE_POD_FLAG_COMMANDS = new Set(["bridge-setup"]);
|
|
166
173
|
/**
|
|
167
174
|
* Consume a position-independent `--pod <name>` (or `--pod=<name>`) from argv and
|
|
168
175
|
* register it as the per-invocation override. Mutates `argv` in place so commander
|
|
169
176
|
* never sees the flag (it isn't registered per-command). No-op when the argv
|
|
170
|
-
* targets a command that owns `--pod` itself (
|
|
177
|
+
* targets a command that owns `--pod` itself (bridge-setup). Throws with a
|
|
171
178
|
* helpful message when the named profile is unknown.
|
|
172
179
|
*/
|
|
173
180
|
export function bootstrapPodOverride(argv) {
|
|
@@ -248,19 +255,41 @@ export function findPodNameByUrl(url) {
|
|
|
248
255
|
export function resolveWorkspaceForPod(config, podName) {
|
|
249
256
|
const targetPod = podName ? config.pods[podName] : undefined;
|
|
250
257
|
const override = config.activeWorkspaceId;
|
|
251
|
-
if (!override)
|
|
252
|
-
return targetPod?.workspaceId || undefined;
|
|
253
258
|
const binding = config.activeWorkspace;
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
return
|
|
259
|
+
// Prefer a binding that matches the target pod even when activeWorkspaceId
|
|
260
|
+
// drifted to a foreign UUID (common after dual-pod work).
|
|
261
|
+
if (binding && binding.podName === podName) {
|
|
262
|
+
return binding.workspaceId;
|
|
263
|
+
}
|
|
264
|
+
if (binding && binding.podName !== podName) {
|
|
265
|
+
// Binding is for another pod — never use its workspace; only the target
|
|
266
|
+
// profile default if it doesn't look stolen from another profile.
|
|
267
|
+
return safePodDefaultWorkspace(config, podName, targetPod?.workspaceId);
|
|
268
|
+
}
|
|
269
|
+
if (!override) {
|
|
270
|
+
return safePodDefaultWorkspace(config, podName, targetPod?.workspaceId);
|
|
258
271
|
}
|
|
259
272
|
const belongsToAnotherPod = Object.entries(config.pods).some(([name, p]) => name !== podName && p.workspaceId === override);
|
|
260
|
-
if (belongsToAnotherPod)
|
|
261
|
-
return targetPod?.workspaceId
|
|
273
|
+
if (belongsToAnotherPod) {
|
|
274
|
+
return safePodDefaultWorkspace(config, podName, targetPod?.workspaceId);
|
|
275
|
+
}
|
|
262
276
|
return override;
|
|
263
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* Profile `workspaceId` can drift to a UUID that belongs on another pod
|
|
280
|
+
* (dual-pod dogfood). Never return a default that is another profile's
|
|
281
|
+
* configured workspaceId. If the default is still suspect and differs from
|
|
282
|
+
* every other profile default, we cannot prove it's foreign without the
|
|
283
|
+
* server — return it only when unique among profile defaults.
|
|
284
|
+
*/
|
|
285
|
+
function safePodDefaultWorkspace(config, podName, defaultWs) {
|
|
286
|
+
if (!defaultWs || !podName)
|
|
287
|
+
return defaultWs || undefined;
|
|
288
|
+
const stolenAsOtherDefault = Object.entries(config.pods).some(([name, p]) => name !== podName && p.workspaceId === defaultWs);
|
|
289
|
+
if (stolenAsOtherDefault)
|
|
290
|
+
return undefined;
|
|
291
|
+
return defaultWs;
|
|
292
|
+
}
|
|
264
293
|
/**
|
|
265
294
|
* Get the active workspace ID for a pod (by profile NAME). Applies the cross-pod
|
|
266
295
|
* rule in {@link resolveWorkspaceForPod}. Omit `podName` for the active pod.
|
|
@@ -300,10 +329,22 @@ export function getActiveProjectId() {
|
|
|
300
329
|
const config = readMultiConfig();
|
|
301
330
|
return config.activeProjectId || undefined;
|
|
302
331
|
}
|
|
303
|
-
/**
|
|
304
|
-
|
|
332
|
+
/**
|
|
333
|
+
* Persist a project as the active context for all subsequent commands.
|
|
334
|
+
* Records the pod it was set against (defaults to the active pod) so
|
|
335
|
+
* {@link resolveHubConfig} can refuse to send it to a foreign pod.
|
|
336
|
+
* Peer of {@link setActiveWorkspaceId}.
|
|
337
|
+
*/
|
|
338
|
+
export function setActiveProjectId(projectId, podName) {
|
|
305
339
|
const config = readMultiConfig();
|
|
306
340
|
config.activeProjectId = projectId;
|
|
341
|
+
const boundPod = podName ?? config.activePod;
|
|
342
|
+
if (boundPod && config.pods[boundPod]) {
|
|
343
|
+
config.activeProject = { projectId, podName: boundPod };
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
delete config.activeProject;
|
|
347
|
+
}
|
|
307
348
|
writeMultiConfig(config);
|
|
308
349
|
}
|
|
309
350
|
/**
|
|
@@ -325,20 +366,74 @@ export function getActiveProjectBinding() {
|
|
|
325
366
|
export function clearActiveProjectId() {
|
|
326
367
|
const config = readMultiConfig();
|
|
327
368
|
delete config.activeProjectId;
|
|
369
|
+
delete config.activeProject;
|
|
328
370
|
writeMultiConfig(config);
|
|
329
371
|
}
|
|
330
372
|
// ─── Surface agent keys ───────────────────────────────────────────────────────
|
|
331
|
-
/**
|
|
373
|
+
/** Normalize a pod URL for map keys (strip trailing slashes). */
|
|
374
|
+
function normalizePodUrl(url) {
|
|
375
|
+
return url.replace(/\/+$/, "");
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Store a dedicated agent key for a specific surface (e.g. "raycast", "claude-code").
|
|
379
|
+
* Always writes `agentKeys[surface]` (last-write, backward compat). When `key.podUrl`
|
|
380
|
+
* is set, also stores under `agentKeysByPod[surface][normalizedPodUrl]` so multi-pod
|
|
381
|
+
* surfaces can look up the key for the pod they are actually talking to.
|
|
382
|
+
*/
|
|
332
383
|
export function setSurfaceAgentKey(surface, key) {
|
|
333
384
|
const config = readMultiConfig();
|
|
334
385
|
config.agentKeys = config.agentKeys ?? {};
|
|
335
|
-
config.agentKeys[surface] = key;
|
|
386
|
+
config.agentKeys[surface] = key; // last write for backward compat
|
|
387
|
+
if (key.podUrl) {
|
|
388
|
+
config.agentKeysByPod = config.agentKeysByPod ?? {};
|
|
389
|
+
const bySurface = config.agentKeysByPod[surface] ?? {};
|
|
390
|
+
bySurface[normalizePodUrl(key.podUrl)] = key;
|
|
391
|
+
config.agentKeysByPod[surface] = bySurface;
|
|
392
|
+
}
|
|
393
|
+
writeMultiConfig(config);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Read back the stored agent key for a surface.
|
|
397
|
+
* When `podUrl` is provided, prefer `agentKeysByPod` for that pod; if only a legacy
|
|
398
|
+
* `agentKeys[surface]` entry exists, return it only when its podUrl matches (or is
|
|
399
|
+
* unset). Never return a key known to belong to a different pod.
|
|
400
|
+
*/
|
|
401
|
+
export function getSurfaceAgentKey(surface, podUrl) {
|
|
402
|
+
const config = readMultiConfig();
|
|
403
|
+
if (podUrl && config.agentKeysByPod?.[surface]) {
|
|
404
|
+
const hit = config.agentKeysByPod[surface][normalizePodUrl(podUrl)];
|
|
405
|
+
if (hit)
|
|
406
|
+
return hit;
|
|
407
|
+
}
|
|
408
|
+
const legacy = config.agentKeys?.[surface] ?? null;
|
|
409
|
+
if (podUrl && legacy?.podUrl && normalizePodUrl(legacy.podUrl) !== normalizePodUrl(podUrl)) {
|
|
410
|
+
return null; // do not return wrong-pod key
|
|
411
|
+
}
|
|
412
|
+
return legacy;
|
|
413
|
+
}
|
|
414
|
+
export function getPendingAgentKey(surface, podUrl) {
|
|
415
|
+
return readMultiConfig().pendingAgentKeys?.[surface]?.[normalizePodUrl(podUrl)] ?? null;
|
|
416
|
+
}
|
|
417
|
+
export function setPendingAgentKey(surface, key) {
|
|
418
|
+
const config = readMultiConfig();
|
|
419
|
+
config.pendingAgentKeys = config.pendingAgentKeys ?? {};
|
|
420
|
+
const bySurface = config.pendingAgentKeys[surface] ?? {};
|
|
421
|
+
bySurface[normalizePodUrl(key.podUrl)] = key;
|
|
422
|
+
config.pendingAgentKeys[surface] = bySurface;
|
|
336
423
|
writeMultiConfig(config);
|
|
337
424
|
}
|
|
338
|
-
|
|
339
|
-
export function getSurfaceAgentKey(surface) {
|
|
425
|
+
export function clearPendingAgentKey(surface, podUrl) {
|
|
340
426
|
const config = readMultiConfig();
|
|
341
|
-
|
|
427
|
+
const bySurface = config.pendingAgentKeys?.[surface];
|
|
428
|
+
if (!bySurface || !(normalizePodUrl(podUrl) in bySurface))
|
|
429
|
+
return;
|
|
430
|
+
delete bySurface[normalizePodUrl(podUrl)];
|
|
431
|
+
if (Object.keys(bySurface).length === 0)
|
|
432
|
+
delete config.pendingAgentKeys[surface];
|
|
433
|
+
// writeMultiConfig MERGES over the file, so an emptied map must be written
|
|
434
|
+
// as an empty object, never dropped (a dropped key would keep the old value).
|
|
435
|
+
config.pendingAgentKeys = config.pendingAgentKeys ?? {};
|
|
436
|
+
writeMultiConfig(config);
|
|
342
437
|
}
|
|
343
438
|
export function setAgentWorkspaceRouting(routing) {
|
|
344
439
|
const config = readMultiConfig();
|
|
@@ -366,22 +461,13 @@ export function removePodProfile(name) {
|
|
|
366
461
|
}
|
|
367
462
|
writeMultiConfig(config);
|
|
368
463
|
}
|
|
369
|
-
/** @deprecated Use addPodProfile("default", config) */
|
|
370
|
-
export function saveLocalPodConfig(podConfig) {
|
|
371
|
-
const config = readMultiConfig();
|
|
372
|
-
const name = config.activePod || "default";
|
|
373
|
-
config.pods[name] = podConfig;
|
|
374
|
-
if (!config.activePod)
|
|
375
|
-
config.activePod = name;
|
|
376
|
-
writeMultiConfig(config);
|
|
377
|
-
}
|
|
378
464
|
/**
|
|
379
465
|
* Check if a Synap pod is healthy.
|
|
380
466
|
*/
|
|
381
467
|
export async function checkPodHealth(podUrl) {
|
|
382
468
|
const status = { url: podUrl, healthy: false };
|
|
383
469
|
try {
|
|
384
|
-
const res = await
|
|
470
|
+
const res = await podFetch(`${podUrl}/health`, {
|
|
385
471
|
signal: AbortSignal.timeout(5000),
|
|
386
472
|
});
|
|
387
473
|
if (res.ok) {
|
|
@@ -389,9 +475,16 @@ export async function checkPodHealth(podUrl) {
|
|
|
389
475
|
const data = (await res.json());
|
|
390
476
|
status.version = data.version;
|
|
391
477
|
}
|
|
478
|
+
else {
|
|
479
|
+
status.failure = classifyHttpStatus(res.status, podUrl);
|
|
480
|
+
}
|
|
392
481
|
}
|
|
393
|
-
catch {
|
|
394
|
-
// pod unreachable
|
|
482
|
+
catch (err) {
|
|
483
|
+
// pod unreachable — or it answered with a redirect to another host
|
|
484
|
+
if (err instanceof PodMovedError)
|
|
485
|
+
status.moved = true;
|
|
486
|
+
else
|
|
487
|
+
status.failure = classifyFetchError(err, podUrl);
|
|
395
488
|
}
|
|
396
489
|
return status;
|
|
397
490
|
}
|
|
@@ -401,366 +494,4 @@ export async function checkPodHealth(podUrl) {
|
|
|
401
494
|
export function startSelfHostedPod() {
|
|
402
495
|
execSync('curl -fsSL https://raw.githubusercontent.com/Synap-core/backend/main/install.sh | bash', { stdio: "inherit" });
|
|
403
496
|
}
|
|
404
|
-
/**
|
|
405
|
-
* Install the synap skill into OpenClaw.
|
|
406
|
-
*/
|
|
407
|
-
/**
|
|
408
|
-
* Open a Pod session for the CP-authenticated user.
|
|
409
|
-
* Calls the issuer for a short-lived generic assertion, then exchanges that
|
|
410
|
-
* assertion directly with the Pod. The issuer never receives a Pod session.
|
|
411
|
-
*
|
|
412
|
-
* Returns the Kratos session token the Pod mints after its own membership check.
|
|
413
|
-
* That token authenticates subsequent pod tRPC calls (e.g.
|
|
414
|
-
* `apiKeys.connectIntegration`) as the pod user, via the X-Session-Token header.
|
|
415
|
-
* `sessionToken` is null only if the pod handshake returned no token (e.g. 409).
|
|
416
|
-
*/
|
|
417
|
-
export async function provisionUserOnPod(podUrl, cpToken) {
|
|
418
|
-
// Step 1: get an issuer assertion for this Pod.
|
|
419
|
-
const assertionRes = await fetch(`${CP_URL}/pods/federation/assertion`, {
|
|
420
|
-
method: "POST",
|
|
421
|
-
headers: {
|
|
422
|
-
"Content-Type": "application/json",
|
|
423
|
-
Authorization: `Bearer ${cpToken}`,
|
|
424
|
-
},
|
|
425
|
-
body: JSON.stringify({ podUrl }),
|
|
426
|
-
signal: AbortSignal.timeout(10000),
|
|
427
|
-
});
|
|
428
|
-
if (!assertionRes.ok) {
|
|
429
|
-
const body = await assertionRes.text().catch(() => "");
|
|
430
|
-
throw new Error(`Could not get Pod issuer assertion (HTTP ${assertionRes.status}): ${body.slice(0, 200)}`);
|
|
431
|
-
}
|
|
432
|
-
const { assertion } = (await assertionRes.json());
|
|
433
|
-
if (!assertion) {
|
|
434
|
-
throw new Error("Control Plane did not return a Pod issuer assertion");
|
|
435
|
-
}
|
|
436
|
-
// Step 2: exchange only with the Pod. It derives the issuer from `iss` and
|
|
437
|
-
// verifies its own trusted-issuer registry and local membership.
|
|
438
|
-
const exchangeRes = await fetch(`${podUrl}/api/federation/exchange`, {
|
|
439
|
-
method: "POST",
|
|
440
|
-
headers: { "Content-Type": "application/json" },
|
|
441
|
-
body: JSON.stringify({ assertion }),
|
|
442
|
-
signal: AbortSignal.timeout(15000),
|
|
443
|
-
});
|
|
444
|
-
if (!exchangeRes.ok) {
|
|
445
|
-
const body = await exchangeRes.text().catch(() => "");
|
|
446
|
-
throw new Error(`Pod issuer assertion exchange failed (HTTP ${exchangeRes.status}): ${body.slice(0, 200)}`);
|
|
447
|
-
}
|
|
448
|
-
// The pod returns the Kratos session token in the handshake body (the same
|
|
449
|
-
// value the browser receives as the ory_kratos_session cookie).
|
|
450
|
-
let sessionToken = null;
|
|
451
|
-
try {
|
|
452
|
-
const data = (await exchangeRes.json());
|
|
453
|
-
sessionToken = data.session_token ?? null;
|
|
454
|
-
}
|
|
455
|
-
catch {
|
|
456
|
-
// 409 or an empty body — no token to capture.
|
|
457
|
-
}
|
|
458
|
-
return { sessionToken };
|
|
459
|
-
}
|
|
460
|
-
/**
|
|
461
|
-
* Issue a scoped Hub Protocol API key on the pod for an authenticated user.
|
|
462
|
-
*
|
|
463
|
-
* Canonical path: the pod's `apiKeys.connectIntegration` tRPC procedure — the
|
|
464
|
-
* same one the pod-admin `/connect` page and the browser's LocalCliRow use.
|
|
465
|
-
* Auth is the Kratos session token minted by {@link provisionUserOnPod},
|
|
466
|
-
* forwarded as the `X-Session-Token` header. (Replaces the removed CP relay
|
|
467
|
-
* `POST /pods/setup-agent`, which now returns 410.)
|
|
468
|
-
*
|
|
469
|
-
* Backend tRPC uses the superjson transformer, so the input rides in a
|
|
470
|
-
* `{ json: ... }` envelope and the output is unwrapped from `result.data.json`.
|
|
471
|
-
*/
|
|
472
|
-
export async function setupAgentViaPod(podUrl, sessionToken, integration = "openclaw") {
|
|
473
|
-
const res = await fetch(`${podUrl}/trpc/apiKeys.connectIntegration`, {
|
|
474
|
-
method: "POST",
|
|
475
|
-
headers: {
|
|
476
|
-
"Content-Type": "application/json",
|
|
477
|
-
"X-Session-Token": sessionToken,
|
|
478
|
-
},
|
|
479
|
-
// strategy: "replace_existing" makes re-running `synap init` idempotent —
|
|
480
|
-
// it revokes any prior key for this integration and mints a fresh one.
|
|
481
|
-
body: JSON.stringify({
|
|
482
|
-
json: { integration, strategy: "replace_existing" },
|
|
483
|
-
}),
|
|
484
|
-
signal: AbortSignal.timeout(15000),
|
|
485
|
-
});
|
|
486
|
-
const body = (await res.json().catch(() => null));
|
|
487
|
-
if (!res.ok || !body || body.error) {
|
|
488
|
-
const msg = body?.error?.message ?? `HTTP ${res.status}`;
|
|
489
|
-
throw new Error(`Pod key issuance failed: ${msg}`);
|
|
490
|
-
}
|
|
491
|
-
const data = body.result?.data?.json;
|
|
492
|
-
if (!data?.apiKey) {
|
|
493
|
-
throw new Error("Pod returned no API key from connectIntegration");
|
|
494
|
-
}
|
|
495
|
-
return {
|
|
496
|
-
hubApiKey: data.apiKey,
|
|
497
|
-
// The connectIntegration key is owned by the human pod user directly — there
|
|
498
|
-
// is no separate agent user in this model (same as the browser flow). Left
|
|
499
|
-
// empty; the hub client resolves the acting user via /users/me at runtime.
|
|
500
|
-
agentUserId: "",
|
|
501
|
-
workspaceId: data.workspaceId ?? "",
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* Enable OpenClaw as a free addon on a SELF-HOSTED pod.
|
|
506
|
-
* Uses the PROVISIONING_TOKEN directly against the pod.
|
|
507
|
-
*
|
|
508
|
-
* Routes through the shared `provisionAgentKey()` wrapper (dynamic import to
|
|
509
|
-
* avoid a circular pod.ts <-> targets.ts static import). `workspaceId` is no
|
|
510
|
-
* longer part of the response — agents are pod-wide singletons now; scope is
|
|
511
|
-
* granted separately via `enrollAgentIfNeeded()`, not returned from setup.
|
|
512
|
-
*/
|
|
513
|
-
export async function enableOpenClawAddon(podUrl, provisioningToken) {
|
|
514
|
-
const { provisionAgentKey } = await import("./targets.js");
|
|
515
|
-
const { hubApiKey, agentUserId } = await provisionAgentKey(podUrl, provisioningToken, "openclaw");
|
|
516
|
-
return { hubApiKey, agentUserId, workspaceId: "" };
|
|
517
|
-
}
|
|
518
|
-
/**
|
|
519
|
-
* Enable OpenClaw as an addon on a MANAGED pod via the Control Plane.
|
|
520
|
-
* Calls POST /openclaw/provision on the CP (requires CP session token).
|
|
521
|
-
* Returns the podId so the caller can poll status if needed.
|
|
522
|
-
*/
|
|
523
|
-
export async function enableOpenClawAddonManaged(cpToken, podUrl) {
|
|
524
|
-
// Find the pod ID from the CP
|
|
525
|
-
const podsRes = await fetch(`${CP_URL}/pods`, {
|
|
526
|
-
headers: { Authorization: `Bearer ${cpToken}` },
|
|
527
|
-
signal: AbortSignal.timeout(10000),
|
|
528
|
-
});
|
|
529
|
-
if (!podsRes.ok)
|
|
530
|
-
throw new Error(`Could not fetch pods (HTTP ${podsRes.status})`);
|
|
531
|
-
const { pods } = (await podsRes.json());
|
|
532
|
-
const appDomain = "synap.live";
|
|
533
|
-
const pod = pods.find((p) => {
|
|
534
|
-
const url = p.customDomain ? `https://${p.customDomain}` : `https://${p.subdomain}.${appDomain}`;
|
|
535
|
-
return url === podUrl || podUrl.includes(p.subdomain);
|
|
536
|
-
});
|
|
537
|
-
// Not a local profile miss — this is a lookup against the pods the Control
|
|
538
|
-
// Plane says you own, so podNotFoundError's "synap pods add" is the wrong fix.
|
|
539
|
-
if (!pod) {
|
|
540
|
-
const owned = pods.map((p) => p.customDomain ?? `${p.subdomain}.${appDomain}`).join(", ") || "(none)";
|
|
541
|
-
throw new Error(`No pod matching ${podUrl} on your account. Pods on this account: ${owned}.`);
|
|
542
|
-
}
|
|
543
|
-
const provRes = await fetch(`${CP_URL}/openclaw/provision`, {
|
|
544
|
-
method: "POST",
|
|
545
|
-
headers: {
|
|
546
|
-
"Content-Type": "application/json",
|
|
547
|
-
Authorization: `Bearer ${cpToken}`,
|
|
548
|
-
},
|
|
549
|
-
body: JSON.stringify({ podId: pod.id }),
|
|
550
|
-
signal: AbortSignal.timeout(15000),
|
|
551
|
-
});
|
|
552
|
-
if (!provRes.ok) {
|
|
553
|
-
const body = await provRes.text().catch(() => "");
|
|
554
|
-
throw new Error(`OpenClaw provision failed (HTTP ${provRes.status}): ${body.slice(0, 200)}`);
|
|
555
|
-
}
|
|
556
|
-
return { podId: pod.id };
|
|
557
|
-
}
|
|
558
|
-
/**
|
|
559
|
-
* Check server resources (RAM, disk).
|
|
560
|
-
*/
|
|
561
|
-
export function checkServerResources() {
|
|
562
|
-
let ramTotal = 0;
|
|
563
|
-
let ramFree = 0;
|
|
564
|
-
let diskFree = "unknown";
|
|
565
|
-
try {
|
|
566
|
-
const mem = execSync("free -m 2>/dev/null || sysctl -n hw.memsize 2>/dev/null", {
|
|
567
|
-
encoding: "utf-8",
|
|
568
|
-
timeout: 3000,
|
|
569
|
-
});
|
|
570
|
-
const lines = mem.trim().split("\n");
|
|
571
|
-
if (lines.length > 1) {
|
|
572
|
-
const parts = lines[1].split(/\s+/);
|
|
573
|
-
ramTotal = parseInt(parts[1], 10) || 0;
|
|
574
|
-
ramFree = parseInt(parts[6] || parts[3], 10) || 0;
|
|
575
|
-
}
|
|
576
|
-
else {
|
|
577
|
-
const bytes = parseInt(lines[0], 10);
|
|
578
|
-
if (bytes > 0) {
|
|
579
|
-
ramTotal = Math.round(bytes / 1024 / 1024);
|
|
580
|
-
ramFree = Math.round(ramTotal * 0.5);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
catch { /* can't detect */ }
|
|
585
|
-
try {
|
|
586
|
-
const df = execSync("df -h / 2>/dev/null | tail -1", {
|
|
587
|
-
encoding: "utf-8",
|
|
588
|
-
timeout: 3000,
|
|
589
|
-
});
|
|
590
|
-
diskFree = df.trim().split(/\s+/)[3] || "unknown";
|
|
591
|
-
}
|
|
592
|
-
catch { /* can't detect */ }
|
|
593
|
-
return { ramTotal, ramFree, diskFree };
|
|
594
|
-
}
|
|
595
|
-
/**
|
|
596
|
-
* Start OpenClaw as a Docker addon on the local server.
|
|
597
|
-
* Writes env vars to the pod's .env file and runs docker compose --profile openclaw.
|
|
598
|
-
* Only works when the CLI is running ON the pod server.
|
|
599
|
-
*/
|
|
600
|
-
/**
|
|
601
|
-
* Find the Synap deploy directory — where the .env and docker-compose files live.
|
|
602
|
-
*
|
|
603
|
-
* Strategy (most reliable first):
|
|
604
|
-
* 1. Docker label — inspect any running synap container for
|
|
605
|
-
* com.docker.compose.project.working_dir (always accurate, zero guessing)
|
|
606
|
-
* 2. Walk up from cwd — works when running from inside the repo
|
|
607
|
-
* 3. Common install paths as a last resort
|
|
608
|
-
*/
|
|
609
|
-
export function findSynapDeployDir() {
|
|
610
|
-
// ── 1. Ask Docker itself ───────────────────────────────────────────────
|
|
611
|
-
try {
|
|
612
|
-
// Find any container that belongs to a synap compose project
|
|
613
|
-
const psOut = execSync("docker ps --format '{{.Names}}' 2>/dev/null", { encoding: "utf-8", timeout: 4000 });
|
|
614
|
-
const synapContainer = psOut
|
|
615
|
-
.split("\n")
|
|
616
|
-
.map((l) => l.trim())
|
|
617
|
-
.find((n) => /synap|openclaw/i.test(n));
|
|
618
|
-
if (synapContainer) {
|
|
619
|
-
const workDir = execSync(`docker inspect --format '{{index .Config.Labels "com.docker.compose.project.working_dir"}}' ${synapContainer} 2>/dev/null`, { encoding: "utf-8", timeout: 4000 }).trim();
|
|
620
|
-
if (workDir && workDir !== "<no value>" && fs.existsSync(workDir)) {
|
|
621
|
-
// compose project.working_dir is the folder containing docker-compose.yml
|
|
622
|
-
// but the .env may be in a "deploy" subdirectory
|
|
623
|
-
if (hasSynapCompose(workDir))
|
|
624
|
-
return workDir;
|
|
625
|
-
const deploySub = path.join(workDir, "deploy");
|
|
626
|
-
if (hasSynapCompose(deploySub))
|
|
627
|
-
return deploySub;
|
|
628
|
-
return workDir; // trust Docker even if compose check fails
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
catch {
|
|
633
|
-
// Docker not available or no containers — fall through
|
|
634
|
-
}
|
|
635
|
-
// ── 2. Walk up from cwd ────────────────────────────────────────────────
|
|
636
|
-
let dir = process.cwd();
|
|
637
|
-
for (let i = 0; i < 6; i++) {
|
|
638
|
-
if (hasSynapCompose(dir))
|
|
639
|
-
return dir;
|
|
640
|
-
const parent = path.dirname(dir);
|
|
641
|
-
if (parent === dir)
|
|
642
|
-
break;
|
|
643
|
-
dir = parent;
|
|
644
|
-
}
|
|
645
|
-
// ── 3. Common install paths ────────────────────────────────────────────
|
|
646
|
-
const home = os.homedir();
|
|
647
|
-
const fallbacks = [
|
|
648
|
-
"/srv/synap",
|
|
649
|
-
"/opt/synap",
|
|
650
|
-
path.join(home, "synap-backend", "deploy"),
|
|
651
|
-
path.join(home, "synap-backend"),
|
|
652
|
-
path.join(home, "synap"),
|
|
653
|
-
];
|
|
654
|
-
for (const d of fallbacks) {
|
|
655
|
-
if (hasSynapCompose(d))
|
|
656
|
-
return d;
|
|
657
|
-
}
|
|
658
|
-
return null;
|
|
659
|
-
}
|
|
660
|
-
function hasSynapCompose(dir) {
|
|
661
|
-
try {
|
|
662
|
-
for (const name of ["docker-compose.standalone.yml", "docker-compose.yml"]) {
|
|
663
|
-
const f = path.join(dir, name);
|
|
664
|
-
if (fs.existsSync(f)) {
|
|
665
|
-
const content = fs.readFileSync(f, "utf-8");
|
|
666
|
-
if (/ghcr\.io\/synap-core\/backend|synap-backend/i.test(content))
|
|
667
|
-
return true;
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
catch {
|
|
672
|
-
// unreadable
|
|
673
|
-
}
|
|
674
|
-
return false;
|
|
675
|
-
}
|
|
676
|
-
/**
|
|
677
|
-
* Write OpenClaw env vars into the deploy dir .env and start the container.
|
|
678
|
-
* Does NOT wait for health — OpenClaw can take several minutes to initialize
|
|
679
|
-
* (first run pulls ~1GB image + runs setup). Caller should tell user to run
|
|
680
|
-
* `synap finish` once it's up.
|
|
681
|
-
*
|
|
682
|
-
* Returns the deploy dir used.
|
|
683
|
-
*/
|
|
684
|
-
export function startOpenClawOnServer(hubApiKey, agentUserId, workspaceId, podUrl, projectId) {
|
|
685
|
-
const deployDir = findSynapDeployDir();
|
|
686
|
-
if (!deployDir) {
|
|
687
|
-
throw new Error("Could not find your Synap deploy directory.\n" +
|
|
688
|
-
"Run from inside the synap-backend folder, or set SYNAP_DEPLOY_DIR env var.");
|
|
689
|
-
}
|
|
690
|
-
// ── Write env vars ───────────────────────────────────────────────────────
|
|
691
|
-
const envFile = path.join(deployDir, ".env");
|
|
692
|
-
const envVars = {
|
|
693
|
-
OPENCLAW_HUB_API_KEY: hubApiKey,
|
|
694
|
-
SYNAP_AGENT_USER_ID: agentUserId,
|
|
695
|
-
SYNAP_WORKSPACE_ID: workspaceId,
|
|
696
|
-
SYNAP_POD_URL: podUrl,
|
|
697
|
-
};
|
|
698
|
-
// Project is a peer lens to workspace — only injected when one is resolved.
|
|
699
|
-
if (projectId)
|
|
700
|
-
envVars.SYNAP_PROJECT_ID = projectId;
|
|
701
|
-
let envContent = "";
|
|
702
|
-
try {
|
|
703
|
-
envContent = fs.existsSync(envFile) ? fs.readFileSync(envFile, "utf-8") : "";
|
|
704
|
-
}
|
|
705
|
-
catch { /* start fresh */ }
|
|
706
|
-
for (const [key, value] of Object.entries(envVars)) {
|
|
707
|
-
const regex = new RegExp(`^${key}=.*`, "m");
|
|
708
|
-
const line = `${key}=${value}`;
|
|
709
|
-
envContent = regex.test(envContent)
|
|
710
|
-
? envContent.replace(regex, line)
|
|
711
|
-
: (envContent.endsWith("\n") || envContent === ""
|
|
712
|
-
? envContent + line + "\n"
|
|
713
|
-
: envContent + "\n" + line + "\n");
|
|
714
|
-
}
|
|
715
|
-
fs.writeFileSync(envFile, envContent, { mode: 0o600 });
|
|
716
|
-
// ── Start container ──────────────────────────────────────────────────────
|
|
717
|
-
const composeFile = fs.existsSync(path.join(deployDir, "docker-compose.standalone.yml"))
|
|
718
|
-
? "docker-compose.standalone.yml"
|
|
719
|
-
: "docker-compose.yml";
|
|
720
|
-
// pipe stderr to /dev/null to suppress WARN lines about unset env vars
|
|
721
|
-
// (those warnings are cosmetic — other services' vars not needed by openclaw)
|
|
722
|
-
execSync(`docker compose -f ${composeFile} --profile openclaw up -d openclaw 2>/dev/null`, { stdio: ["ignore", "inherit", "ignore"], cwd: deployDir, timeout: 300_000 });
|
|
723
|
-
return deployDir;
|
|
724
|
-
}
|
|
725
|
-
/**
|
|
726
|
-
* Install the synap skill into OpenClaw.
|
|
727
|
-
*/
|
|
728
|
-
const SKILL_SLUG = "synap";
|
|
729
|
-
/**
|
|
730
|
-
* Install the synap skill into OpenClaw.
|
|
731
|
-
* Automatically chooses the right execution path:
|
|
732
|
-
* - Local install: runs `openclaw skills install synap` directly
|
|
733
|
-
* - Docker container: runs `docker exec <container> openclaw skills install synap`
|
|
734
|
-
*/
|
|
735
|
-
export function installSynapSkill(containerName) {
|
|
736
|
-
const cmd = containerName
|
|
737
|
-
? `docker exec ${containerName} openclaw skills install ${SKILL_SLUG}`
|
|
738
|
-
: `openclaw skills install ${SKILL_SLUG}`;
|
|
739
|
-
try {
|
|
740
|
-
execSync(cmd, { stdio: "inherit", timeout: 60000 });
|
|
741
|
-
}
|
|
742
|
-
catch {
|
|
743
|
-
if (containerName) {
|
|
744
|
-
throw new Error(`Could not install skill via docker exec.\n` +
|
|
745
|
-
`Run manually: docker exec ${containerName} openclaw skills install ${SKILL_SLUG}`);
|
|
746
|
-
}
|
|
747
|
-
else {
|
|
748
|
-
throw new Error(`openclaw not found in PATH.\n` +
|
|
749
|
-
`Run manually: openclaw skills install ${SKILL_SLUG}\n` +
|
|
750
|
-
`Or if OpenClaw is in Docker: docker exec openclaw openclaw skills install ${SKILL_SLUG}`);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
}
|
|
754
|
-
/**
|
|
755
|
-
* Check whether the synap skill is installed inside a Docker container.
|
|
756
|
-
*/
|
|
757
|
-
export function isSynapSkillInstalledInDocker(containerName) {
|
|
758
|
-
try {
|
|
759
|
-
const out = execSync(`docker exec ${containerName} openclaw skills list 2>/dev/null`, { encoding: "utf-8", timeout: 10000 });
|
|
760
|
-
return /synap/i.test(out);
|
|
761
|
-
}
|
|
762
|
-
catch {
|
|
763
|
-
return false;
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
497
|
//# sourceMappingURL=pod.js.map
|