@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/index.js
CHANGED
|
@@ -1,32 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @synap/cli — Connect AI agents to your Synap data pod
|
|
3
|
+
* @synap-core/cli — Connect AI agents to your Synap data pod
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
|
-
* npx @synap/cli init Full setup: detect, harden, connect, install
|
|
7
|
-
* npx @synap/cli connect Connect an AI surface to a Synap pod
|
|
8
|
-
* npx @synap/cli status Show pod health and API status
|
|
9
|
-
* npx @synap/cli update
|
|
6
|
+
* npx @synap-core/cli init Full setup: detect, harden, connect, install
|
|
7
|
+
* npx @synap-core/cli connect Connect an AI surface to a Synap pod
|
|
8
|
+
* npx @synap-core/cli status Show pod health and API status
|
|
9
|
+
* npx @synap-core/cli update Show how to update the CLI
|
|
10
10
|
*
|
|
11
11
|
* Or install globally:
|
|
12
|
-
* npm i -g @synap/cli
|
|
12
|
+
* npm i -g @synap-core/cli
|
|
13
13
|
* synap init
|
|
14
14
|
*/
|
|
15
|
-
import { Command } from "commander";
|
|
16
|
-
import { readFileSync } from "fs";
|
|
17
|
-
import { fileURLToPath } from "url";
|
|
18
|
-
import { dirname, join } from "path";
|
|
15
|
+
import { Command, Option } from "commander";
|
|
19
16
|
import { bootstrapPodOverride } from "./lib/pod.js";
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const pkg = JSON.parse(readFileSync(join(__dirname, "..", "package.json"), "utf-8"));
|
|
25
|
-
version = pkg.version;
|
|
26
|
-
}
|
|
27
|
-
catch {
|
|
28
|
-
// use default
|
|
29
|
-
}
|
|
17
|
+
import { INIT_EXIT_HELP } from "./lib/init-exit.js";
|
|
18
|
+
import { cliBuild, formatCliBuild } from "./lib/cli-build.js";
|
|
19
|
+
// The version AND the commit this build came from — a stale build is visible.
|
|
20
|
+
const version = formatCliBuild(cliBuild());
|
|
30
21
|
const program = new Command();
|
|
31
22
|
program
|
|
32
23
|
.name("synap")
|
|
@@ -42,7 +33,12 @@ program
|
|
|
42
33
|
.description("Full setup: connect to a Synap pod and install the skill")
|
|
43
34
|
.option("--pod-url <url>", "Synap pod URL (skip pod choice prompt)")
|
|
44
35
|
.option("--api-key <key>", "Hub Protocol API key (skip key generation)")
|
|
45
|
-
|
|
36
|
+
// Deprecated no-op, kept so old scripts do not fail on an unknown option.
|
|
37
|
+
.addOption(new Option("--skip-is", "deprecated, ignored").hideHelp())
|
|
38
|
+
.option("-y, --yes", "Accept the defaults, no prompts (connects the agents found on this machine)")
|
|
39
|
+
.option("--agents <list>", "Agents to connect, comma-separated: claude-code,codex,cursor")
|
|
40
|
+
.option("--json", "Print a JSON summary on stdout: {podUrl, connected, notApproved, failed, pairLink, exitCode}")
|
|
41
|
+
.addHelpText("after", INIT_EXIT_HELP)
|
|
46
42
|
.action(async (opts) => {
|
|
47
43
|
const { init } = await import("./commands/init.js");
|
|
48
44
|
await init(opts);
|
|
@@ -71,31 +67,61 @@ program
|
|
|
71
67
|
.option("--bot-token <token>", "Discord bot token — provisioned into the pod vault")
|
|
72
68
|
.option("--guild-id <id>", "Discord server (guild) id — written to the bridge .env")
|
|
73
69
|
.option("--bridge-dir <path>", "Path to the telegram-discord-bridge repo")
|
|
74
|
-
.option("--workspace-id <uuid>", "
|
|
70
|
+
.option("--workspace-id <uuid>", "Advanced/legacy: pin the bridge to one workspace (default: pod-wide, never prompted)")
|
|
71
|
+
.option("--project-id <uuid>", "Scope the bridge to one project (default: prompt, pod-wide if declined)")
|
|
75
72
|
.option("--proactive-channel <id>", "Discord channel id for the agent's proactive posts")
|
|
76
73
|
.option("--enable-react", "Turn on ✅-react capture")
|
|
74
|
+
// Re-running bridge-setup on an already-provisioned pod now DETECTS what is
|
|
75
|
+
// configured and skips it (the bot token is already in the vault — re-asking
|
|
76
|
+
// for a secret the pod already holds was the sharpest instance). This flag
|
|
77
|
+
// restores the old behaviour for a genuine rotation or repoint.
|
|
78
|
+
.option("--reconfigure", "Re-ask every question and re-provision from scratch (ignore what a previous run configured)")
|
|
77
79
|
.option("--pod <name>", "Pod profile to connect the bridge to (default: prompt)")
|
|
78
|
-
.option("--governance <mode>", "Agent
|
|
80
|
+
.option("--governance <mode>", "Agent approval preset: safe | creates | normal | crazy (default: prompt; \"follow the pod default\" writes nothing)")
|
|
79
81
|
.option("--pod-url <url>", "Synap pod URL (override)")
|
|
80
82
|
.option("--api-key <key>", "Hub Protocol API key (override)")
|
|
81
83
|
.action(async (opts) => {
|
|
82
84
|
const { bridgeSetup } = await import("./commands/bridge-setup.js");
|
|
83
85
|
await bridgeSetup(opts);
|
|
84
86
|
});
|
|
87
|
+
// Hidden: one-shot Proton Mail↔Synap bridge provisioning (dogfood/dev convenience).
|
|
88
|
+
// Fork of bridge-setup for the sovereign self-host Proton Bridge path — see
|
|
89
|
+
// the catalog capability synap-app/packages/workspace-templates/capabilities/proton.capability.json.
|
|
85
90
|
program
|
|
86
|
-
.command("
|
|
87
|
-
.description("
|
|
88
|
-
.option("--
|
|
91
|
+
.command("proton-setup", { hidden: true })
|
|
92
|
+
.description("(hidden) One-shot Proton Mail↔Synap bridge provisioning")
|
|
93
|
+
.option("--proton-email <email>", "Proton account email — provisioned into the pod vault")
|
|
94
|
+
.option("--proton-password <password>", "Proton account password (not a bridge-generated value) — provisioned into the pod vault")
|
|
95
|
+
.option("--proton-totp-seed <seed>", "Proton account 2FA/TOTP seed, base32 (optional) — provisioned into the pod vault")
|
|
96
|
+
.option("--proton-mailbox-password <password>", "Proton mailbox password — ONLY for two-password-mode accounts (optional) — provisioned into the pod vault")
|
|
97
|
+
.option("--bridge-dir <path>", "Path to the synap-proton-bridge repo")
|
|
98
|
+
.option("--workspace-id <uuid>", "Advanced/legacy: pin the bridge to one workspace (default: pod-wide, never prompted)")
|
|
99
|
+
.option("--project-id <uuid>", "Scope the bridge to one project (default: prompt, pod-wide if declined)")
|
|
100
|
+
.option("--pod <name>", "Pod profile to connect the bridge to (default: prompt)")
|
|
101
|
+
.option("--governance <mode>", "Agent approval preset: safe | creates | normal | crazy (default: prompt; \"follow the pod default\" writes nothing)")
|
|
102
|
+
.option("--pod-url <url>", "Synap pod URL (override)")
|
|
103
|
+
.option("--api-key <key>", "Hub Protocol API key (override)")
|
|
104
|
+
.action(async (opts) => {
|
|
105
|
+
const { protonSetup } = await import("./commands/proton-setup.js");
|
|
106
|
+
await protonSetup(opts);
|
|
107
|
+
});
|
|
108
|
+
program
|
|
109
|
+
.command("connect [thing]")
|
|
110
|
+
.description("Plug something into your pod: an AI agent (claude-code, cursor, codex, …) or a tool/account (gmail, github, …)")
|
|
111
|
+
.option("--tool", "Treat <thing> as a tool/account even if it is also an agent name (no <thing>: list connectable services)")
|
|
112
|
+
.option("--workspace <id>", "Focus on one workspace (default: pod-wide)")
|
|
113
|
+
.option("--project <id>", "Focus on one project (agents only; composable with --workspace)")
|
|
89
114
|
.option("--pod-url <url>", "Synap pod URL")
|
|
90
115
|
.option("--api-key <key>", "Hub Protocol API key")
|
|
91
|
-
.option("--name <name>", "Pod profile
|
|
92
|
-
.option("--list", "List
|
|
93
|
-
.
|
|
94
|
-
.option("--
|
|
95
|
-
.option("--pin-
|
|
96
|
-
.
|
|
116
|
+
.option("--name <name>", "Pod profile to use (default: active pod)")
|
|
117
|
+
.option("--list", "List what can be connected and exit")
|
|
118
|
+
.addOption(new Option("--with-mcp", "deprecated, ignored: Raycast always gets the pod's MCP server").hideHelp())
|
|
119
|
+
.option("--target <name>", "Legacy spelling of <thing>")
|
|
120
|
+
.option("--pin-workspace <id>", "Legacy spelling of --workspace")
|
|
121
|
+
.option("--pin-project <id>", "Legacy spelling of --project")
|
|
122
|
+
.action(async (thing, opts) => {
|
|
97
123
|
const { connect } = await import("./commands/connect.js");
|
|
98
|
-
await connect(opts);
|
|
124
|
+
await connect(thing, opts);
|
|
99
125
|
});
|
|
100
126
|
// ─── pods ─────────────────────────────────────────────────────────────────────
|
|
101
127
|
const pods = program
|
|
@@ -131,7 +157,8 @@ pods
|
|
|
131
157
|
.option("--yes", "Non-interactive: skip prompts (won't recreate a rejected key)")
|
|
132
158
|
.action(async (name, url, opts) => {
|
|
133
159
|
const { podsUpdate } = await import("./commands/pods.js");
|
|
134
|
-
await podsUpdate(name, url, { url: opts.url, yes: opts.yes })
|
|
160
|
+
if (!(await podsUpdate(name, url, { url: opts.url, yes: opts.yes })))
|
|
161
|
+
process.exitCode = 1;
|
|
135
162
|
});
|
|
136
163
|
pods
|
|
137
164
|
.command("remove <name>")
|
|
@@ -158,8 +185,11 @@ program
|
|
|
158
185
|
});
|
|
159
186
|
program
|
|
160
187
|
.command("doctor")
|
|
161
|
-
.description("Coherence preflight: pod host resolves, key authenticates, workspace/project exist on THIS pod — catches config drift in one call")
|
|
188
|
+
.description("Coherence preflight: pod host resolves, key authenticates, workspace/project exist on THIS pod, and why each configured key does or does not work — catches config drift in one call")
|
|
162
189
|
.option("--json", "Output as JSON")
|
|
190
|
+
.option("--fix", "Fix key problems: finish a pending approval, give this computer its own key, or rewrite stale copies — then verify over MCP")
|
|
191
|
+
.option("-v, --verbose", "Every check with its details, ids and addresses")
|
|
192
|
+
.option("--pod-url <url>", "Probe this pod URL (works with no pod configured)")
|
|
163
193
|
.action(async (opts) => {
|
|
164
194
|
const { doctor } = await import("./commands/doctor.js");
|
|
165
195
|
await doctor(opts);
|
|
@@ -174,10 +204,11 @@ program
|
|
|
174
204
|
});
|
|
175
205
|
program
|
|
176
206
|
.command("whoami")
|
|
177
|
-
.description("Show
|
|
178
|
-
.
|
|
207
|
+
.description("Show key owner vs EFFECTIVE user (+ isAgent), scopes/workspace, and flag env-vs-surface key divergence")
|
|
208
|
+
.option("--json", "Output as JSON")
|
|
209
|
+
.action(async (opts) => {
|
|
179
210
|
const { whoami } = await import("./commands/whoami.js");
|
|
180
|
-
await whoami();
|
|
211
|
+
await whoami(opts);
|
|
181
212
|
});
|
|
182
213
|
// Hidden: compact ANSI line for the Claude Code statusLine (reads stdin JSON).
|
|
183
214
|
program
|
|
@@ -190,59 +221,10 @@ program
|
|
|
190
221
|
});
|
|
191
222
|
program
|
|
192
223
|
.command("update")
|
|
193
|
-
.description("
|
|
194
|
-
.option("--server", "Also trigger a Dokploy redeploy of the control-plane")
|
|
195
|
-
.option("--all", "Trigger a Dokploy redeploy of all registered services")
|
|
196
|
-
.action(async (opts) => {
|
|
197
|
-
const { update } = await import("./commands/update.js");
|
|
198
|
-
await update(opts);
|
|
199
|
-
});
|
|
200
|
-
// ─── infra ────────────────────────────────────────────────────────────────────
|
|
201
|
-
const infra = program
|
|
202
|
-
.command("infra")
|
|
203
|
-
.description("Manage servers and deployments via Dokploy");
|
|
204
|
-
infra
|
|
205
|
-
.command("status", { isDefault: true })
|
|
206
|
-
.description("Overview: all servers and services status")
|
|
224
|
+
.description("Show how to update the CLI")
|
|
207
225
|
.action(async () => {
|
|
208
|
-
const {
|
|
209
|
-
await
|
|
210
|
-
});
|
|
211
|
-
infra
|
|
212
|
-
.command("deploy <app>")
|
|
213
|
-
.description("Trigger a redeploy for a named service")
|
|
214
|
-
.action(async (app) => {
|
|
215
|
-
const { infraDeploy } = await import("./commands/infra.js");
|
|
216
|
-
await infraDeploy(app);
|
|
217
|
-
});
|
|
218
|
-
infra
|
|
219
|
-
.command("logs <app>")
|
|
220
|
-
.description("Tail logs for a service")
|
|
221
|
-
.option("-n, --lines <n>", "Number of log lines", "100")
|
|
222
|
-
.option("-f, --follow", "Follow log output")
|
|
223
|
-
.action(async (app, opts) => {
|
|
224
|
-
const { infraLogs } = await import("./commands/infra.js");
|
|
225
|
-
await infraLogs(app, { lines: opts.lines ? parseInt(opts.lines, 10) : 100, follow: opts.follow });
|
|
226
|
-
});
|
|
227
|
-
infra
|
|
228
|
-
.command("sync")
|
|
229
|
-
.description("Pull Dokploy state into Synap entities (server + deployment profiles)")
|
|
230
|
-
.option("--pod-url <url>", "Synap pod URL", process.env.SYNAP_POD_URL)
|
|
231
|
-
.option("--api-key <key>", "Hub Protocol API key", process.env.SYNAP_API_KEY)
|
|
232
|
-
.action(async (opts) => {
|
|
233
|
-
if (!opts.podUrl || !opts.apiKey) {
|
|
234
|
-
console.error(" --pod-url and --api-key are required (or set SYNAP_POD_URL / SYNAP_API_KEY)");
|
|
235
|
-
process.exit(1);
|
|
236
|
-
}
|
|
237
|
-
const { infraSync } = await import("./commands/infra.js");
|
|
238
|
-
await infraSync(opts.podUrl, opts.apiKey);
|
|
239
|
-
});
|
|
240
|
-
infra
|
|
241
|
-
.command("open")
|
|
242
|
-
.description("Open the Dokploy dashboard in your browser")
|
|
243
|
-
.action(async () => {
|
|
244
|
-
const { infraOpen } = await import("./commands/infra.js");
|
|
245
|
-
infraOpen();
|
|
226
|
+
const { update } = await import("./commands/update.js");
|
|
227
|
+
await update();
|
|
246
228
|
});
|
|
247
229
|
program
|
|
248
230
|
.command("switch [name]")
|
|
@@ -254,11 +236,31 @@ program
|
|
|
254
236
|
program
|
|
255
237
|
.command("connections")
|
|
256
238
|
.alias("conn")
|
|
257
|
-
.description("Show which pod each agent
|
|
239
|
+
.description("Show everything connected: which pod each agent points at, and which tools the pod has connected")
|
|
258
240
|
.action(async () => {
|
|
259
241
|
const { connections } = await import("./commands/connections.js");
|
|
260
242
|
await connections();
|
|
261
243
|
});
|
|
244
|
+
// ─── app ────────────────────────────────────────────────────────────────────
|
|
245
|
+
// The App Connect flow: a `synap.app.json` in your app repo → one command wires
|
|
246
|
+
// the app's key into its deploy target. See APP-CONNECT-SPEC §5.
|
|
247
|
+
const app = program
|
|
248
|
+
.command("app")
|
|
249
|
+
.description("Connect an app in this repo to your pod (synap.app.json)");
|
|
250
|
+
app
|
|
251
|
+
.command("init")
|
|
252
|
+
.description("Write synap.app.json (asks name, pod, permissions) and register the app")
|
|
253
|
+
.action(async () => {
|
|
254
|
+
const { appInitCommand } = await import("./commands/app.js");
|
|
255
|
+
await appInitCommand();
|
|
256
|
+
});
|
|
257
|
+
app
|
|
258
|
+
.command("connect")
|
|
259
|
+
.description("Request the app's access, await approval, then write its key into the deploy target")
|
|
260
|
+
.action(async () => {
|
|
261
|
+
const { appConnectCommand } = await import("./commands/app.js");
|
|
262
|
+
await appConnectCommand();
|
|
263
|
+
});
|
|
262
264
|
// ─── mcp ────────────────────────────────────────────────────────────────────
|
|
263
265
|
// The MCP front door: point any AI client at the pod's /mcp server.
|
|
264
266
|
const mcp = program
|
|
@@ -288,13 +290,45 @@ mcp
|
|
|
288
290
|
const { mcpVerify } = await import("./commands/mcp.js");
|
|
289
291
|
await mcpVerify(opts);
|
|
290
292
|
});
|
|
293
|
+
mcp
|
|
294
|
+
.command("bridge")
|
|
295
|
+
.description("Stdio MCP server for Claude Code: forwards to the pod and names the conversation (spawned by Claude Code, not run by hand)")
|
|
296
|
+
.option("--url <url>", "The pod MCP URL to forward to")
|
|
297
|
+
.action(async (opts) => {
|
|
298
|
+
const { mcpBridge } = await import("./commands/mcp.js");
|
|
299
|
+
await mcpBridge(opts);
|
|
300
|
+
});
|
|
301
|
+
mcp
|
|
302
|
+
.command("use-bridge")
|
|
303
|
+
.description("Connect Claude Code through the stdio bridge, so work can be traced to and reopened in its conversation")
|
|
304
|
+
.option("--off", "Switch back to the direct http connection")
|
|
305
|
+
.action(async (opts) => {
|
|
306
|
+
const { mcpUseBridge } = await import("./commands/mcp.js");
|
|
307
|
+
await mcpUseBridge(opts);
|
|
308
|
+
});
|
|
291
309
|
mcp
|
|
292
310
|
.command("connect [client]")
|
|
293
|
-
.description("Write the MCP config for a file-configurable client (Claude Code, Cursor, Desktop, …) — alias of `synap
|
|
311
|
+
.description("Write the MCP config for a file-configurable client (Claude Code, Cursor, Desktop, ChatGPT, …) — alias of `synap agents add <client>`")
|
|
294
312
|
.option("--name <name>", "Pod profile to connect")
|
|
295
313
|
.action(async (client, opts) => {
|
|
296
314
|
const { connect } = await import("./commands/connect.js");
|
|
297
|
-
await connect(
|
|
315
|
+
await connect(client, { name: opts.name });
|
|
316
|
+
});
|
|
317
|
+
mcp
|
|
318
|
+
.command("connect-chatgpt")
|
|
319
|
+
.description("Connect ChatGPT (web) to Synap — API-key connector to your pod")
|
|
320
|
+
.option("--name <name>", "Pod profile to connect")
|
|
321
|
+
.action(async (opts) => {
|
|
322
|
+
const { connect } = await import("./commands/connect.js");
|
|
323
|
+
await connect("chatgpt", { name: opts.name });
|
|
324
|
+
});
|
|
325
|
+
mcp
|
|
326
|
+
.command("connect-chatgpt-oauth")
|
|
327
|
+
.description("Connect ChatGPT (web) via Control Plane OAuth — multi-pod, no key to paste")
|
|
328
|
+
.option("--name <name>", "Pod profile to connect")
|
|
329
|
+
.action(async (opts) => {
|
|
330
|
+
const { connect } = await import("./commands/connect.js");
|
|
331
|
+
await connect("chatgpt-oauth", { name: opts.name });
|
|
298
332
|
});
|
|
299
333
|
mcp
|
|
300
334
|
.command("connect-claude")
|
|
@@ -307,6 +341,17 @@ mcp
|
|
|
307
341
|
const { mcpConnectClaudeWeb } = await import("./commands/mcp.js");
|
|
308
342
|
await mcpConnectClaudeWeb(opts);
|
|
309
343
|
});
|
|
344
|
+
mcp
|
|
345
|
+
.command("ui-setup <client>")
|
|
346
|
+
.description("Print the exact form fields to fill in the client's MCP/Connector UI (ChatGPT, Codex, Cursor, etc.)")
|
|
347
|
+
.option("--name <name>", "Pod profile to use (default: active)")
|
|
348
|
+
.option("--workspace <id>", "Scope to a specific workspace")
|
|
349
|
+
.option("--project <id>", "Focus the agent on a project")
|
|
350
|
+
.option("--json", "Output as JSON")
|
|
351
|
+
.action(async (client, opts) => {
|
|
352
|
+
const { mcpUiSetup } = await import("./commands/mcp.js");
|
|
353
|
+
await mcpUiSetup(client, opts);
|
|
354
|
+
});
|
|
310
355
|
program
|
|
311
356
|
.command("login")
|
|
312
357
|
.description("Connect your Synap account (private templates) + your pods")
|
|
@@ -323,11 +368,9 @@ program
|
|
|
323
368
|
}
|
|
324
369
|
const profiles = listPodProfiles();
|
|
325
370
|
if (profiles.length === 0) {
|
|
326
|
-
// No pod saved
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const { podsAdd } = await import("./commands/pods.js");
|
|
330
|
-
await podsAdd();
|
|
371
|
+
// No pod saved: sign in to the account first, it finds the pods.
|
|
372
|
+
const { podsFirstLogin } = await import("./commands/pods.js");
|
|
373
|
+
await podsFirstLogin();
|
|
331
374
|
return;
|
|
332
375
|
}
|
|
333
376
|
// Already have pods — show status and offer reconnect if any are unreachable
|
|
@@ -366,8 +409,23 @@ program
|
|
|
366
409
|
console.log(` ${active}${chalk.bold(p.name.padEnd(14))} ${status} ${chalk.dim(p.config.podUrl)}`);
|
|
367
410
|
}
|
|
368
411
|
console.log();
|
|
412
|
+
// A computer key (device flow) that expires within 7 days, or has: connect
|
|
413
|
+
// this computer again now — the pod offers the same computer, so its
|
|
414
|
+
// agents, history and rules are kept. Never without a person to approve.
|
|
415
|
+
const { computerKeyNeedsRenewal, connectThisComputer } = await import("./lib/device-connect.js");
|
|
416
|
+
const renewed = new Set();
|
|
417
|
+
for (const p of checks.filter((c) => c.healthy && computerKeyNeedsRenewal(c.config))) {
|
|
418
|
+
const when = `this computer's key ${p.keyValid ? "expires" : "expired"} ${p.config.keyExpiresAt}`;
|
|
419
|
+
if (!process.stdin.isTTY) {
|
|
420
|
+
console.log(chalk.yellow(` ${p.name}: ${when}. Run synap login in a terminal to renew it.`));
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
console.log(chalk.yellow(` ${p.name}: ${when}. Renewing it.`));
|
|
424
|
+
if (await connectThisComputer(p.config.podUrl, { name: p.name }))
|
|
425
|
+
renewed.add(p.name);
|
|
426
|
+
}
|
|
369
427
|
// Anything that won't authenticate — unreachable OR a revoked/expired key.
|
|
370
|
-
const needsReconnect = checks.filter((p) => !p.healthy || !p.keyValid);
|
|
428
|
+
const needsReconnect = checks.filter((p) => !renewed.has(p.name) && (!p.healthy || !p.keyValid));
|
|
371
429
|
if (needsReconnect.length > 0) {
|
|
372
430
|
console.log(chalk.yellow(` ${needsReconnect.length} pod(s) need re-authentication. Refresh credentials:`));
|
|
373
431
|
for (const p of needsReconnect) {
|
|
@@ -412,7 +470,7 @@ program
|
|
|
412
470
|
}
|
|
413
471
|
}
|
|
414
472
|
else {
|
|
415
|
-
console.log(chalk.dim(" Later: synap login
|
|
473
|
+
console.log(chalk.dim(" Later: synap login (prints a link you can open on any device)"));
|
|
416
474
|
}
|
|
417
475
|
}
|
|
418
476
|
const { renderNextSteps, FLOW } = await import("./lib/next-steps.js");
|
|
@@ -424,6 +482,7 @@ program
|
|
|
424
482
|
.description("Show a lightweight lens map: who you are, your projects (companies/initiatives), and workspaces (operational domains)")
|
|
425
483
|
.option("--json", "Output as JSON")
|
|
426
484
|
.option("--details", "Include per-workspace profiles + entity counts (heavier)")
|
|
485
|
+
.option("--workspace <space>", "Orient ONE space by name or id, for this call only — shows its brief (purpose, kinds, rules, skills) without changing your pinned lens")
|
|
427
486
|
.option("--pod-url <url>", "Pod URL override")
|
|
428
487
|
.option("--api-key <key>", "API key override")
|
|
429
488
|
.action(async (opts) => {
|
|
@@ -449,9 +508,9 @@ program
|
|
|
449
508
|
// See what an AI did across flows: the unified run feed, or one run's activity
|
|
450
509
|
// timeline (for a capture: WHY a facet/entity dropped, with a fixHint).
|
|
451
510
|
program
|
|
452
|
-
.command("diagnose [
|
|
453
|
-
.description("See what an AI did — the run feed, or one run's
|
|
454
|
-
.option("--flow <automation|playbook|capture|session>", "Restrict the feed, or the run
|
|
511
|
+
.command("diagnose [run]")
|
|
512
|
+
.description("See what an AI did — the run feed, or one run's nodes (by id or flow name)")
|
|
513
|
+
.option("--flow <automation|playbook|capture|capability|session|chat>", "Restrict the feed, or narrow the run lookup to one flow")
|
|
455
514
|
.option("--flow-id <id>", "Restrict the feed to one flow's runs (automationId / playbookId)")
|
|
456
515
|
.option("--limit <n>", "Max runs in the feed")
|
|
457
516
|
.option("--json", "Output raw JSON")
|
|
@@ -464,7 +523,9 @@ program
|
|
|
464
523
|
// ─── use ──────────────────────────────────────────────────────────────────────
|
|
465
524
|
program
|
|
466
525
|
.command("use <workspace>")
|
|
467
|
-
.description("Set the active workspace (by ID or name) —
|
|
526
|
+
.description("Set the active workspace (by ID or name) — short form of `synap workspace use`. Default scope: this directory")
|
|
527
|
+
.option("--session", "Ephemeral: scope only this Claude Code session, don't persist")
|
|
528
|
+
.option("--global", "Durable machine-wide default (~/.synap/config.json) instead of this directory's .synap/lens.json")
|
|
468
529
|
.option("--json", "Output as JSON")
|
|
469
530
|
.option("--pod-url <url>", "Pod URL override")
|
|
470
531
|
.option("--api-key <key>", "API key override")
|
|
@@ -475,7 +536,7 @@ program
|
|
|
475
536
|
// ─── project / lens (per-Claude-session scoping) ──────────────────────────────
|
|
476
537
|
const project = program
|
|
477
538
|
.command("project")
|
|
478
|
-
.description("Manage + focus the
|
|
539
|
+
.description("Manage + focus the project lens (a commitment, spanning workspaces): list, new, use, clear");
|
|
479
540
|
project
|
|
480
541
|
.command("list", { isDefault: true })
|
|
481
542
|
.description("List projects on the active pod, with the pinned one marked (bare `synap project` runs this)")
|
|
@@ -488,7 +549,7 @@ project
|
|
|
488
549
|
});
|
|
489
550
|
project
|
|
490
551
|
.command("new <name>")
|
|
491
|
-
.description("Create a project (a
|
|
552
|
+
.description("Create a project (a commitment you are driving, with whom) on the active pod, then guide you to pin + add to it")
|
|
492
553
|
.option("--description <text>", "Optional one-line description")
|
|
493
554
|
.option("--json", "Output as JSON (incl. nextSteps for agents)")
|
|
494
555
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -501,6 +562,7 @@ project
|
|
|
501
562
|
.command("use <ref>")
|
|
502
563
|
.description("Pin the active project (durable, like `synap use <workspace>`). Ref = uuid, slug, or <pod>/<slug> — cross-pod refs switch the active pod too")
|
|
503
564
|
.option("--session", "Ephemeral: scope only this Claude Code session, don't persist (cross-pod refs refused)")
|
|
565
|
+
.option("--global", "Durable machine-wide default (~/.synap/config.json) instead of this directory's .synap/lens.json")
|
|
504
566
|
.option("--json", "Output as JSON")
|
|
505
567
|
.option("--pod-url <url>", "Pod URL override")
|
|
506
568
|
.option("--api-key <key>", "API key override")
|
|
@@ -531,8 +593,10 @@ project
|
|
|
531
593
|
});
|
|
532
594
|
program
|
|
533
595
|
.command("lens")
|
|
534
|
-
.description("Show
|
|
596
|
+
.description("Show the effective lens (workspace + project + focus session) and WHICH rung set each one")
|
|
535
597
|
.option("--json", "Output as JSON")
|
|
598
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
599
|
+
.option("--api-key <key>", "API key override")
|
|
536
600
|
.action(async (opts) => {
|
|
537
601
|
const { showLens } = await import("./commands/lens.js");
|
|
538
602
|
await showLens(opts);
|
|
@@ -542,11 +606,12 @@ program
|
|
|
542
606
|
// procedural (how-to docs), episodic (captures) — and returns a glass-box answer.
|
|
543
607
|
program
|
|
544
608
|
.command("ask <query>")
|
|
545
|
-
.description("Ask your pod anything —
|
|
609
|
+
.description("Ask your pod anything — returns a synthesized answer with its sources")
|
|
546
610
|
.option("--workspace <id>", "Scope to a specific workspace (omit for pod-wide)")
|
|
547
611
|
.option("--limit <n>", "Max results per substrate", "10")
|
|
548
612
|
.option("--json", "Output as JSON")
|
|
549
613
|
.option("--session", "Scope retrieval to the active session context")
|
|
614
|
+
.option("--raw", "Skip synthesis: show the raw per-substrate matches instead")
|
|
550
615
|
.option("--compare", "A/B diagnostic: show baseline vs Horizon rankers side-by-side (read-only, does not change the answer)")
|
|
551
616
|
.option("--pod-url <url>", "Pod URL override")
|
|
552
617
|
.option("--api-key <key>", "API key override")
|
|
@@ -555,21 +620,25 @@ program
|
|
|
555
620
|
await askKnowledge(query, opts);
|
|
556
621
|
});
|
|
557
622
|
// ─── capture ──────────────────────────────────────────────────────────────────
|
|
558
|
-
// Uses the active pod
|
|
559
|
-
//
|
|
623
|
+
// Uses the active pod from config. Work-lane knowledge does NOT default-pin
|
|
624
|
+
// the active workspace (omit workspaceId → server-derived / pod-wide preferred);
|
|
625
|
+
// pin only with --workspace or --team.
|
|
560
626
|
program
|
|
561
627
|
.command("capture [text]")
|
|
562
|
-
.description("Capture knowledge: smart `capture \"<free text>\"` (AI structures it)
|
|
563
|
-
.option("--type <type>", "
|
|
628
|
+
.description("Capture knowledge: smart `capture \"<free text>\"` (AI structures it). For canonical typed Knowledge, use `create entity --profile=knowledge --props='{\"knowledgeForm\":\"insight|caution\"}'`.")
|
|
629
|
+
.option("--type <type>", "Legacy compatibility typed mode (gotcha|lesson|decision|reference); new automation should use knowledgeForm")
|
|
564
630
|
.option("--claim <text>", "Typed mode: one-line assertion (required with --type)")
|
|
631
|
+
.option("--title <text>", "Typed mode: short name, 80 characters or less (default: the claim's first sentence, never cut)")
|
|
632
|
+
.option("--content <markdown>", "Typed mode: full Markdown explanation, stored as the linked Knowledge note")
|
|
565
633
|
.option("--why <text>", "Reasoning or context")
|
|
566
634
|
.option("--evidence <text>", "Supporting file path, URL, or code snippet")
|
|
567
635
|
.option("--tags <csv>", "Comma-separated tags e.g. repo:synap-backend,layer:migrations")
|
|
568
636
|
.option("--session", "Link captured knowledge to the active session")
|
|
569
|
-
.option("--
|
|
570
|
-
.option("--
|
|
571
|
-
.option("--
|
|
572
|
-
.option("--
|
|
637
|
+
.option("--pod-wide", "GLOBAL lane: pod-wide cross-cutting runbook (→ knowledge_keys), visible in every workspace")
|
|
638
|
+
.option("--global", "Alias for --pod-wide")
|
|
639
|
+
.option("--key <ns:slug>", "Stable key for a --pod-wide runbook (derived from --type + --claim if omitted)")
|
|
640
|
+
.option("--team", "Pin to the first product workspace (default: omit workspaceId — server-derived / pod-wide preferred for knowledge)")
|
|
641
|
+
.option("--workspace <id>", "Explicit workspace pin (otherwise workspaceId is omitted for knowledge)")
|
|
573
642
|
.option("--project <id|name>", "Pin the capture to a project (id or name) — overrides SYNAP_PROJECT_ID / the session lens")
|
|
574
643
|
.option("--yes", "Skip the y/N confirmation prompt (smart mode)")
|
|
575
644
|
.option("--json", "Output as JSON")
|
|
@@ -582,10 +651,14 @@ program
|
|
|
582
651
|
// the SAME AI capture pipeline (/capture/structure → /capture/execute), so it
|
|
583
652
|
// inherits entity extraction, the relation graph, and workspace/project routing.
|
|
584
653
|
program
|
|
585
|
-
.command("import
|
|
654
|
+
.command("import [inputs...]")
|
|
586
655
|
.description("Import files, folders, or URLs into the pod (AI capture pipeline, or Superwhisper store-first)")
|
|
587
656
|
.option("--workspace <id|name>", "Override AI workspace routing")
|
|
588
657
|
.option("--project <id|name>", "Override AI project routing")
|
|
658
|
+
.option("--home-map <pairs>", "Multi-home path map: pathSubstring=workspaceNameOrId pairs " +
|
|
659
|
+
'(e.g. "Projects=Builder,Posts=Content OS"). Matched batch paths are ' +
|
|
660
|
+
"rewritten with the workspace name as the first segment so placement " +
|
|
661
|
+
"heuristics pin the right home. No product defaults.")
|
|
589
662
|
.option("--dry-run", "Preview only — do not write")
|
|
590
663
|
.option("--yes", "Skip confirmation / auto-confirm store-first")
|
|
591
664
|
.option("--session", "Link created entities to the active session")
|
|
@@ -594,14 +667,20 @@ program
|
|
|
594
667
|
.option("--api-key <key>", "API key override")
|
|
595
668
|
.option("--source <name>", "Adapter: superwhisper (paired meta.json+output.wav store-first)")
|
|
596
669
|
.option("--store-first", "Skip AI structure; store units as pod-wide notes (+ optional audio)")
|
|
670
|
+
.option("--keep-raw", "Keep the original file and link it to the created entity (default: extract, then discard the bytes)")
|
|
597
671
|
.option("--with-audio", "Upload WAV provenance (default on for --source superwhisper --store-first)")
|
|
598
672
|
.option("--no-with-audio", "Transcript-only (no WAV upload)")
|
|
599
673
|
.option("--limit <n>", "Max Superwhisper units to process", (v) => parseInt(v, 10))
|
|
600
674
|
.option("--concurrency <n>", "Parallel unit uploads (1–4)", (v) => parseInt(v, 10))
|
|
601
675
|
.option("--no-resume", "Ignore local import ledger (re-import all)")
|
|
676
|
+
.option("--job-status <jobId>", "Re-poll a background corpus import started by an earlier run (no waiting)")
|
|
602
677
|
.action(async (inputs, opts) => {
|
|
603
|
-
const
|
|
604
|
-
|
|
678
|
+
const mod = await import("./commands/import.js");
|
|
679
|
+
if (opts.jobStatus) {
|
|
680
|
+
await mod.importJobStatus(opts.jobStatus, opts);
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
await mod.importData(inputs ?? [], opts);
|
|
605
684
|
});
|
|
606
685
|
// ─── upload ───────────────────────────────────────────────────────────────────
|
|
607
686
|
// Store a real file (arbitrary bytes) on the pod — the door an AI/CLI needs to
|
|
@@ -609,8 +688,10 @@ program
|
|
|
609
688
|
// which mints a `file` entity for the bytes.
|
|
610
689
|
program
|
|
611
690
|
.command("upload <path>")
|
|
612
|
-
.description("Upload a file
|
|
613
|
-
.option("--workspace <id>", "
|
|
691
|
+
.description("Upload a file to the pod as an entity (>10MB goes direct to storage: video ≤500MB, audio ≤100MB, zip ≤200MB)")
|
|
692
|
+
.option("--workspace <id>", "Pin the entity to this workspace (explicit placement)")
|
|
693
|
+
.option("--profile <slug>", "Entity kind to create (default: file), e.g. brand-asset")
|
|
694
|
+
.option("--prop <key=value>", "Entity property (repeatable)", (v, acc = []) => [...acc, v])
|
|
614
695
|
.option("--attach <entityId>", "After upload, link the document to this entity (references relation)")
|
|
615
696
|
.option("--title <title>", "Title for the created document")
|
|
616
697
|
.option("--open", "Open in the Synap desktop app after upload")
|
|
@@ -622,6 +703,8 @@ Examples:
|
|
|
622
703
|
synap upload ./report.pdf
|
|
623
704
|
synap upload ./logo.png --title "Brand logo" --workspace <id>
|
|
624
705
|
synap upload ./spec.pdf --attach <entityId>
|
|
706
|
+
synap upload ./logo.svg --profile brand-asset --prop variant=dark --workspace <id>
|
|
707
|
+
synap upload ./launch.mp4 --workspace <id>
|
|
625
708
|
synap upload ./report.pdf --open
|
|
626
709
|
`)
|
|
627
710
|
.action(async (path, opts) => {
|
|
@@ -682,7 +765,42 @@ program
|
|
|
682
765
|
// commands (capture, recall, search, …) inherit the active pod + workspace.
|
|
683
766
|
const workspace = program
|
|
684
767
|
.command("workspace")
|
|
685
|
-
.description("
|
|
768
|
+
.description("Manage + focus the workspace lens (an operational domain): list, use, clear");
|
|
769
|
+
// `workspace use|list|clear` mirror `project use|list|clear` so the two
|
|
770
|
+
// composable lenses read as siblings. ADDITIVE: the original short form
|
|
771
|
+
// `synap use <workspace>` and `synap list workspaces` are untouched and keep
|
|
772
|
+
// working exactly as before — these are aliases, not replacements.
|
|
773
|
+
workspace
|
|
774
|
+
.command("use <workspace>")
|
|
775
|
+
.description("Pin the active workspace by ID or name (durable, like `synap use <workspace>`). Default scope: this directory")
|
|
776
|
+
.option("--session", "Ephemeral: scope only this Claude Code session, don't persist")
|
|
777
|
+
.option("--global", "Durable machine-wide default (~/.synap/config.json) instead of this directory's .synap/lens.json")
|
|
778
|
+
.option("--json", "Output as JSON")
|
|
779
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
780
|
+
.option("--api-key <key>", "API key override")
|
|
781
|
+
.action(async (ws, opts) => {
|
|
782
|
+
const { useWorkspace } = await import("./commands/data.js");
|
|
783
|
+
await useWorkspace(ws, opts);
|
|
784
|
+
});
|
|
785
|
+
workspace
|
|
786
|
+
.command("list", { isDefault: true })
|
|
787
|
+
.description("List workspaces you belong to (bare `synap workspace` runs this)")
|
|
788
|
+
.option("--json", "Output as JSON")
|
|
789
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
790
|
+
.option("--api-key <key>", "API key override")
|
|
791
|
+
.action(async (opts) => {
|
|
792
|
+
const { listWorkspaces } = await import("./commands/data.js");
|
|
793
|
+
await listWorkspaces(opts);
|
|
794
|
+
});
|
|
795
|
+
workspace
|
|
796
|
+
.command("clear")
|
|
797
|
+
.description("Clear the active workspace focus (durable by default)")
|
|
798
|
+
.option("--session", "Ephemeral: clear only this Claude Code session's workspace")
|
|
799
|
+
.option("--json", "Output as JSON")
|
|
800
|
+
.action(async (opts) => {
|
|
801
|
+
const { clearWorkspace } = await import("./commands/data.js");
|
|
802
|
+
await clearWorkspace(opts);
|
|
803
|
+
});
|
|
686
804
|
workspace
|
|
687
805
|
.command("provision-agent")
|
|
688
806
|
.description("Provision an agent-owned workspace and set it as active (idempotent)")
|
|
@@ -706,6 +824,54 @@ workspace
|
|
|
706
824
|
const { workspacePurge } = await import("./commands/purge.js");
|
|
707
825
|
await workspacePurge(target, opts);
|
|
708
826
|
});
|
|
827
|
+
// R8a — governed lifecycle: an agent key gets a proposal, an owner key applies.
|
|
828
|
+
workspace
|
|
829
|
+
.command("archive <workspace>")
|
|
830
|
+
.description("Archive a workspace (hides it, pauses its workspace automations). Governed: agents propose")
|
|
831
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
832
|
+
.option("--json", "Output as JSON")
|
|
833
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
834
|
+
.option("--api-key <key>", "API key override")
|
|
835
|
+
.action(async (target, opts) => {
|
|
836
|
+
const { workspaceArchive } = await import("./commands/workspace-ops.js");
|
|
837
|
+
await workspaceArchive(target, opts);
|
|
838
|
+
});
|
|
839
|
+
workspace
|
|
840
|
+
.command("restore <workspace>")
|
|
841
|
+
.description("Restore an archived workspace (by id). Re-enables nothing; lists automations still paused")
|
|
842
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
843
|
+
.option("--json", "Output as JSON")
|
|
844
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
845
|
+
.option("--api-key <key>", "API key override")
|
|
846
|
+
.action(async (target, opts) => {
|
|
847
|
+
const { workspaceRestore } = await import("./commands/workspace-ops.js");
|
|
848
|
+
await workspaceRestore(target, opts);
|
|
849
|
+
});
|
|
850
|
+
workspace
|
|
851
|
+
.command("rename <workspace> <newName>")
|
|
852
|
+
.description("Rename a workspace. Governed: agents propose")
|
|
853
|
+
.option("--json", "Output as JSON")
|
|
854
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
855
|
+
.option("--api-key <key>", "API key override")
|
|
856
|
+
.action(async (target, newName, opts) => {
|
|
857
|
+
const { workspaceRename } = await import("./commands/workspace-ops.js");
|
|
858
|
+
await workspaceRename(target, newName, opts);
|
|
859
|
+
});
|
|
860
|
+
// R8a — `synap entity move`. (`get/create/set entity` stay under their verbs.)
|
|
861
|
+
program
|
|
862
|
+
.command("entity")
|
|
863
|
+
.description("Entity operations: move")
|
|
864
|
+
.command("move <entityIds...>")
|
|
865
|
+
.description("Move entities into another workspace. Governed per entity: moved / proposed / errors")
|
|
866
|
+
.requiredOption("--to <workspace>", "Destination workspace id or name")
|
|
867
|
+
.option("--reason <text>", "Why they belong there — shown to the reviewer")
|
|
868
|
+
.option("--json", "Output as JSON")
|
|
869
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
870
|
+
.option("--api-key <key>", "API key override")
|
|
871
|
+
.action(async (entityIds, opts) => {
|
|
872
|
+
const { entityMove } = await import("./commands/workspace-ops.js");
|
|
873
|
+
await entityMove(entityIds, opts);
|
|
874
|
+
});
|
|
709
875
|
// ─── list ─────────────────────────────────────────────────────────────────────
|
|
710
876
|
const list = program
|
|
711
877
|
.command("list")
|
|
@@ -819,8 +985,10 @@ const proposals = program
|
|
|
819
985
|
.description("Review and act on governance proposals");
|
|
820
986
|
proposals
|
|
821
987
|
.command("list", { isDefault: true })
|
|
822
|
-
.description("List
|
|
988
|
+
.description("List governance proposals (default: the pending queue)")
|
|
989
|
+
.option("--status <status>", "pending (default) | approved | auto_approved (what the agent already did) | rejected | expired (never decided) | all", "pending")
|
|
823
990
|
.option("--workspace <id>", "Scope to a specific workspace")
|
|
991
|
+
.option("--session <id>", "Scope to one focus session (the agent run that filed them)")
|
|
824
992
|
.option("--limit <n>", "Max results", "20")
|
|
825
993
|
.option("--json", "Output as JSON")
|
|
826
994
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -831,8 +999,11 @@ proposals
|
|
|
831
999
|
});
|
|
832
1000
|
proposals
|
|
833
1001
|
.command("approve <id>")
|
|
834
|
-
.description("Approve a pending proposal")
|
|
1002
|
+
.description("Approve a pending proposal (interactive only — requires a TTY and a typed confirmation)")
|
|
835
1003
|
.option("--reason <text>", "Optional approval note")
|
|
1004
|
+
.option("--verb <verb>", "Same-name choice: fill_empty | keep_existing | use_capture | separate")
|
|
1005
|
+
.option("--existing <uuid>", "Existing record id — required for fill_empty, keep_existing, and use_capture")
|
|
1006
|
+
.option("--yes", "Accepted for symmetry with other commands, but does NOT skip the typed confirmation — approval is always deliberate")
|
|
836
1007
|
.option("--json", "Output as JSON")
|
|
837
1008
|
.option("--pod-url <url>", "Pod URL override")
|
|
838
1009
|
.option("--api-key <key>", "API key override")
|
|
@@ -851,6 +1022,61 @@ proposals
|
|
|
851
1022
|
const { rejectProposal } = await import("./commands/proposals-actions.js");
|
|
852
1023
|
await rejectProposal(id, opts);
|
|
853
1024
|
});
|
|
1025
|
+
proposals
|
|
1026
|
+
.command("await <id>")
|
|
1027
|
+
.description("Block until a proposal is decided. Exit 0 approved · 1 rejected/expired/withdrawn · 2 timeout")
|
|
1028
|
+
.option("--timeout <duration>", "Give up after this long (e.g. 30m, 2h)", "30m")
|
|
1029
|
+
.option("--interval <duration>", "Delay between checks (e.g. 10s)", "10s")
|
|
1030
|
+
.option("--json", "Output the final status as JSON")
|
|
1031
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1032
|
+
.option("--api-key <key>", "API key override")
|
|
1033
|
+
.action(async (id, opts) => {
|
|
1034
|
+
const { awaitProposalCommand } = await import("./commands/proposals-await.js");
|
|
1035
|
+
await awaitProposalCommand(id, opts);
|
|
1036
|
+
});
|
|
1037
|
+
// ─── worker ───────────────────────────────────────────────────────────────────
|
|
1038
|
+
// Run Claude Code unattended on THIS machine for the sessions handed to an agent
|
|
1039
|
+
// (the session roster → orient handedToYou). See src/commands/worker.ts.
|
|
1040
|
+
program
|
|
1041
|
+
.command("worker")
|
|
1042
|
+
.description("Run Claude Code unattended here for the sessions handed to an agent")
|
|
1043
|
+
.requiredOption("--agent <name>", "The named agent this machine works as (its key comes from ~/.synap)")
|
|
1044
|
+
.option("--interval <dur>", "How often to check for handed sessions (e.g. 30s, 2m)", "30s")
|
|
1045
|
+
.option("--once", "Check once, run what is handed, wait for it, exit")
|
|
1046
|
+
.option("--cwd <dir>", "Where code sessions' Claude Code works (default ~/Documents/Code/synap)")
|
|
1047
|
+
.option("--work-root <dir>", "Where playbook runs over pod data (no repo) get a folder each, <dir>/<session id> (default ~/synap-work)")
|
|
1048
|
+
.option("--max-parallel <n>", "Runs at the same time", "1")
|
|
1049
|
+
.option("--claude-bin <path>", "The claude binary", "claude")
|
|
1050
|
+
.option("--claude-config-dir <dir>", "CLAUDE_CONFIG_DIR for launched runs — picks which Claude subscription they use")
|
|
1051
|
+
.option("--accounts <file>", "Claude accounts to rotate across ({version:1, reserve, accounts:[{id,label,token,design?}]}, mode 600); default ~/.config/synap-worker/accounts.json when it exists, else the environment's login")
|
|
1052
|
+
.option("--allowed-tools <list>", "Comma-separated Claude tools allowed without asking (the pod MCP server is always added)")
|
|
1053
|
+
.option("--skip-permissions", "Launch with --dangerously-skip-permissions instead of an allow-list")
|
|
1054
|
+
.option("--dry-run", "Claim and log what would launch, without launching Claude")
|
|
1055
|
+
.action(async (opts) => {
|
|
1056
|
+
const { workerCommand } = await import("./commands/worker.js");
|
|
1057
|
+
await workerCommand(opts);
|
|
1058
|
+
});
|
|
1059
|
+
// ─── box ──────────────────────────────────────────────────────────────────────
|
|
1060
|
+
// Run THIS computer as a run box provisioner: lease the box runs queued on the
|
|
1061
|
+
// pod, run each in a fresh isolated LXC, hand back the evidence. See src/commands/box.ts.
|
|
1062
|
+
const box = program.command("box").description("Run scripts in fresh isolated boxes on this computer (run box provisioner)");
|
|
1063
|
+
box
|
|
1064
|
+
.command("serve")
|
|
1065
|
+
.description("Lease queued box runs from the pod and run each in a fresh box")
|
|
1066
|
+
.option("--config <file>", "Provisioner config", "/etc/synap-box/config.json")
|
|
1067
|
+
.option("--once", "Lease at most one run, work it, exit")
|
|
1068
|
+
.action(async (opts) => {
|
|
1069
|
+
const { boxServeCommand } = await import("./commands/box.js");
|
|
1070
|
+
await boxServeCommand(opts);
|
|
1071
|
+
});
|
|
1072
|
+
box
|
|
1073
|
+
.command("reap")
|
|
1074
|
+
.description("Destroy every box no run holds (after a crash)")
|
|
1075
|
+
.option("--config <file>", "Provisioner config", "/etc/synap-box/config.json")
|
|
1076
|
+
.action(async (opts) => {
|
|
1077
|
+
const { boxReapCommand } = await import("./commands/box.js");
|
|
1078
|
+
await boxReapCommand(opts);
|
|
1079
|
+
});
|
|
854
1080
|
// ─── session ──────────────────────────────────────────────────────────────────
|
|
855
1081
|
// Focus sessions — goal-bound work rooms tracked on the pod.
|
|
856
1082
|
// AI agents: use start_session to begin, update_session to report progress,
|
|
@@ -864,7 +1090,14 @@ session
|
|
|
864
1090
|
.description("Start a new focus session and return its ID")
|
|
865
1091
|
.requiredOption("--goal <text>", "What this session is working toward")
|
|
866
1092
|
.option("--workspace <id>", "Workspace that owns the session")
|
|
1093
|
+
.option("--project <id>", "Project that owns the session (defaults to the active project lens; the pod accepts a workspace OR a project)")
|
|
867
1094
|
.option("--task-id <id>", "Link session to an existing task entity")
|
|
1095
|
+
.option("--track <id>", "Born inside a track (a project's goal) — implies its project")
|
|
1096
|
+
.option("--template <id>", "Start from a playbook (seeds currentStage from its stages)")
|
|
1097
|
+
.option("--no-template", "Opt out of auto-matching a playbook — start ad-hoc")
|
|
1098
|
+
.option("--parent <id>", "Push from another session — records session --spawned_from--> session (the parent stays open)")
|
|
1099
|
+
.option("--suspended-intent <text>", "With --parent: this session BLOCKS the parent. One line naming what the parent was about to do; the parent waits until this session closes")
|
|
1100
|
+
.option("--criteria <file.json>", "Path to a JSON file of binary acceptance criteria (SessionCriterion[])")
|
|
868
1101
|
.option("--json", "Output as JSON")
|
|
869
1102
|
.option("--pod-url <url>", "Pod URL override")
|
|
870
1103
|
.option("--api-key <key>", "API key override")
|
|
@@ -876,7 +1109,9 @@ session
|
|
|
876
1109
|
.command("list", { isDefault: true })
|
|
877
1110
|
.description("List focus sessions in the active workspace")
|
|
878
1111
|
.option("--workspace <id>", "Scope to a specific workspace")
|
|
1112
|
+
.option("--project <id>", "Scope to a project (its sessions across spaces)")
|
|
879
1113
|
.option("--status <status>", "Filter by status: active | paused | closed")
|
|
1114
|
+
.option("--kind <kind>", "Filter by population: work | run | receipt | all", "all")
|
|
880
1115
|
.option("--limit <n>", "Max results", "20")
|
|
881
1116
|
.option("--json", "Output as JSON")
|
|
882
1117
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -887,8 +1122,8 @@ session
|
|
|
887
1122
|
});
|
|
888
1123
|
session
|
|
889
1124
|
.command("get <id>")
|
|
890
|
-
.description("Show details for a specific focus session")
|
|
891
|
-
.option("--workspace <id>", "Workspace
|
|
1125
|
+
.description("Show details for a specific focus session (works for project-scoped sessions)")
|
|
1126
|
+
.option("--workspace <id>", "Workspace hint if the pod still requires it for GET")
|
|
892
1127
|
.option("--json", "Output as JSON")
|
|
893
1128
|
.option("--pod-url <url>", "Pod URL override")
|
|
894
1129
|
.option("--api-key <key>", "API key override")
|
|
@@ -898,10 +1133,14 @@ session
|
|
|
898
1133
|
});
|
|
899
1134
|
session
|
|
900
1135
|
.command("update <id>")
|
|
901
|
-
.description("Update progress
|
|
902
|
-
|
|
903
|
-
|
|
1136
|
+
.description("Update a focus session's progress, status, stage or goal")
|
|
1137
|
+
// NOT required: `workspaceId` is `.optional()` on the pod's UpdateBodySchema
|
|
1138
|
+
// and the session is addressed by <id>. Demanding it made an already-attached
|
|
1139
|
+
// or project-scoped session un-updatable without restating a known lens.
|
|
1140
|
+
.option("--workspace <id>", "Workspace that owns the session (optional; inferred from the active lens)")
|
|
1141
|
+
.option("--progress <0-100>", "Progress percentage — a whole number 0-100, not prose")
|
|
904
1142
|
.option("--status <status>", "New status: active | paused")
|
|
1143
|
+
.option("--stage <key>", "Advance the session's current stage (playbook stage key)")
|
|
905
1144
|
.option("--goal <text>", "Revised goal")
|
|
906
1145
|
.option("--json", "Output as JSON")
|
|
907
1146
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -912,10 +1151,18 @@ session
|
|
|
912
1151
|
});
|
|
913
1152
|
session
|
|
914
1153
|
.command("close <id>")
|
|
915
|
-
.description("
|
|
916
|
-
.
|
|
917
|
-
.option("--recap <text>", "Short summary of what was accomplished")
|
|
918
|
-
|
|
1154
|
+
.description("End a focus session (proposal pack) and optionally attach a recap")
|
|
1155
|
+
.option("--workspace <id>", "Workspace hint (optional; not required for complete)")
|
|
1156
|
+
.option("--recap <text>", "Short summary of what was accomplished (maps to summary)")
|
|
1157
|
+
// Deliberately NOT validated here, unlike --progress. A bad --progress
|
|
1158
|
+
// serialized to NaN and came back as an unreadable zod echo; a bad --as comes
|
|
1159
|
+
// back naming the three legal values, because the pod's enum derives from
|
|
1160
|
+
// TERMINAL_SESSION_STATUSES. Re-listing them here would be a second copy of
|
|
1161
|
+
// an enum this CLI cannot import — the hand-mirrored-vocabulary defect.
|
|
1162
|
+
.option("--as <status>", "How it ended: closed (default, finished) | cancelled (abandoned) | failed (could not complete)")
|
|
1163
|
+
.option("--withdraw <messageId=note>", "An open question you asked that your work overtook, with why (repeatable)", collect, [])
|
|
1164
|
+
.option("--keep-owed <messageId>", "An open question the person still owes you an answer to after this session (repeatable)", collect, [])
|
|
1165
|
+
.option("--json", "Output full pack (or close result) as JSON")
|
|
919
1166
|
.option("--pod-url <url>", "Pod URL override")
|
|
920
1167
|
.option("--api-key <key>", "API key override")
|
|
921
1168
|
.action(async (id, opts) => {
|
|
@@ -942,12 +1189,271 @@ session
|
|
|
942
1189
|
});
|
|
943
1190
|
session
|
|
944
1191
|
.command("current")
|
|
945
|
-
.description("Show the active session for this terminal (
|
|
1192
|
+
.description("Show the active session for this terminal (SYNAP_SESSION_ID, Claude-session lens, or .synap/lens.json)")
|
|
946
1193
|
.option("--json", "Output as JSON")
|
|
947
1194
|
.action(async (opts) => {
|
|
948
1195
|
const { sessionStatus } = await import("./commands/sessions.js");
|
|
949
1196
|
sessionStatus(opts);
|
|
950
1197
|
});
|
|
1198
|
+
session
|
|
1199
|
+
.command("evidence <key>")
|
|
1200
|
+
.description("Post your own pass/fail report for one evidence-checked acceptance criterion")
|
|
1201
|
+
.option("--session <id>", "Focus session ID (defaults to this terminal's active session)")
|
|
1202
|
+
.option("--passed", "The criterion is satisfied")
|
|
1203
|
+
.option("--failed", "The criterion is not satisfied")
|
|
1204
|
+
.option("--detail <text>", "Optional note explaining the verdict")
|
|
1205
|
+
.option("--json", "Output as JSON")
|
|
1206
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1207
|
+
.option("--api-key <key>", "API key override")
|
|
1208
|
+
.action(async (key, opts) => {
|
|
1209
|
+
const { evidenceSession } = await import("./commands/sessions.js");
|
|
1210
|
+
await evidenceSession(key, opts);
|
|
1211
|
+
});
|
|
1212
|
+
session
|
|
1213
|
+
.command("evaluate")
|
|
1214
|
+
.description("Run every pending acceptance-criterion check (evidence, capability, judge) and print the verdicts")
|
|
1215
|
+
.option("--session <id>", "Focus session ID (defaults to this terminal's active session)")
|
|
1216
|
+
.option("--json", "Output as JSON")
|
|
1217
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1218
|
+
.option("--api-key <key>", "API key override")
|
|
1219
|
+
.action(async (opts) => {
|
|
1220
|
+
const { evaluateSession } = await import("./commands/sessions.js");
|
|
1221
|
+
await evaluateSession(opts);
|
|
1222
|
+
});
|
|
1223
|
+
session
|
|
1224
|
+
.command("wait [sessionId]")
|
|
1225
|
+
.description("Block until the human replies in the session room (or, with --events, until the session changes), then print it. Session: the argument, else the one attached to this terminal. Exit 0 replied · 1 timeout · 2 failure (auth/network/broken read); with --hook: 2 wake · 0 anything else")
|
|
1226
|
+
.option("--since <iso>", "Only events strictly after this ISO timestamp (default: now — skips anything that predates this wait; with --events: the unread ones)")
|
|
1227
|
+
.option("--events <kinds>", "Wait on the session change feed: comma list of answer, proposal_decided, stage_moved, owner_message, session_message (a message from another session's agent), or all")
|
|
1228
|
+
.option("--wake-only", "Stop only on what should wake an agent: answers, owner messages, and agent messages the pod marked wake (the rest is read and skipped)")
|
|
1229
|
+
.option("--once", "One read, no waiting loop")
|
|
1230
|
+
.option("--peek", "Mark nothing picked up or read (a watcher that is not the agent doing the work)")
|
|
1231
|
+
.option("--hook", "Run as a Claude Code asyncRewake Stop hook: wait for a wake-worthy event, print it on stderr, exit 2 (see: synap hooks install-wake)")
|
|
1232
|
+
.option("--timeout <duration>", "Give up after this long (e.g. 30m, 2h)", "30m")
|
|
1233
|
+
.option("--interval <duration>", "Delay between checks of the answer-only wait (e.g. 10s)", "10s")
|
|
1234
|
+
.option("--limit <n>", "Max answers / events per page, 1-100", "20")
|
|
1235
|
+
.option("--json", "Output the reply(ies) or events — or the timeout — as JSON")
|
|
1236
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1237
|
+
.option("--api-key <key>", "API key override")
|
|
1238
|
+
.action(async (sessionId, opts) => {
|
|
1239
|
+
const { waitSessionCommand } = await import("./commands/session-wait.js");
|
|
1240
|
+
await waitSessionCommand(sessionId, opts);
|
|
1241
|
+
});
|
|
1242
|
+
session
|
|
1243
|
+
.command("post <toSessionId> <text...>")
|
|
1244
|
+
.description("Message ANOTHER of your sessions' agent: blocked_on_you / handoff may wake it, done / fyi never do. Replying to a message that woke you? Pass its id as --cause. Exit 0 delivered · 1 pod does not deliver agent messages · 2 failure")
|
|
1245
|
+
.option("--intent <intent>", "blocked_on_you | handoff | done | fyi", "fyi")
|
|
1246
|
+
.option("--cause <messageId>", "The message that woke you (the id `synap session wait` printed), when this replies to it")
|
|
1247
|
+
.option("--from <sessionId>", "Your session, when this terminal is not bound to it")
|
|
1248
|
+
.option("--ref <kind:id[:label]>", "The state behind the message: session:<id>, blocked_by:<id>, proposal:<id>, slot:<sessionId>:<label> (repeatable)", collect, [])
|
|
1249
|
+
.option("--json", "Output the pod's reply as JSON")
|
|
1250
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1251
|
+
.option("--api-key <key>", "API key override")
|
|
1252
|
+
.action(async (toSessionId, text, opts) => {
|
|
1253
|
+
const { sessionPostCommand } = await import("./commands/session-post.js");
|
|
1254
|
+
await sessionPostCommand(toSessionId, text, opts);
|
|
1255
|
+
});
|
|
1256
|
+
// ─── hooks ────────────────────────────────────────────────────────────────────
|
|
1257
|
+
// Claude Code hooks the CLI owns. install-wake: the asyncRewake Stop hook that
|
|
1258
|
+
// lets another session's agent (or the person) wake an idle terminal.
|
|
1259
|
+
const hooksCmd = program
|
|
1260
|
+
.command("hooks")
|
|
1261
|
+
.description("Claude Code hooks that connect a terminal to its Synap session");
|
|
1262
|
+
hooksCmd
|
|
1263
|
+
.command("install-wake")
|
|
1264
|
+
.description("Add the wake hook (a Stop hook running `synap session wait --hook`) to this project's .claude/settings.json — idempotent, other hooks kept")
|
|
1265
|
+
.option("--uninstall", "Remove the wake hook instead")
|
|
1266
|
+
.option("--user", "Use ~/.claude/settings.json (every project) instead of the project's")
|
|
1267
|
+
.option("--dir <path>", "The project directory (default: the current one)")
|
|
1268
|
+
.option("--json", "Output the result as JSON")
|
|
1269
|
+
.action(async (opts) => {
|
|
1270
|
+
const { installWakeCommand } = await import("./commands/hooks.js");
|
|
1271
|
+
installWakeCommand(opts);
|
|
1272
|
+
});
|
|
1273
|
+
// ─── playbook ─────────────────────────────────────────────────────────────────
|
|
1274
|
+
// Start a governed process in one step — the Hub door MCP synap_run_playbook
|
|
1275
|
+
// shares. A proposal ("queued for your review") is success.
|
|
1276
|
+
const playbookCmd = program
|
|
1277
|
+
.command("playbook")
|
|
1278
|
+
.description("Run playbooks — governed, reusable processes");
|
|
1279
|
+
playbookCmd
|
|
1280
|
+
.command("run <name-or-id>")
|
|
1281
|
+
.description("Run a playbook by name or id, optionally on a subject entity")
|
|
1282
|
+
.option("--subject <entityId>", "The entity the playbook runs on")
|
|
1283
|
+
.option("--param <key=value>", "Answer a declared param (repeatable; typed by the playbook)", collect, [])
|
|
1284
|
+
.option("--workspace <id>", "Write home for the run (defaults to the playbook's own workspace)")
|
|
1285
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1286
|
+
.option("--json", "Output as JSON")
|
|
1287
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1288
|
+
.option("--api-key <key>", "API key override")
|
|
1289
|
+
.action(async (ref, opts) => {
|
|
1290
|
+
const { runPlaybook } = await import("./commands/playbook.js");
|
|
1291
|
+
await runPlaybook(ref, opts);
|
|
1292
|
+
});
|
|
1293
|
+
// ─── track ────────────────────────────────────────────────────────────────────
|
|
1294
|
+
// A goal inside a project, worked in sessions (`session start --track`); a
|
|
1295
|
+
// person closes it with a verdict. Legacy tracks also run a method with steps. Writes are governed —
|
|
1296
|
+
// "queued for your review" is success.
|
|
1297
|
+
const track = program
|
|
1298
|
+
.command("track")
|
|
1299
|
+
.description("Manage tracks — the goals a project pursues");
|
|
1300
|
+
track
|
|
1301
|
+
.command("list")
|
|
1302
|
+
.description("List a project's goals (the active project lens); with no project in scope, every goal on the pod")
|
|
1303
|
+
.option("--project <id>", "Project id (defaults to the active project lens)")
|
|
1304
|
+
.option("--everywhere", "List every goal on the pod, ignoring the project lens")
|
|
1305
|
+
.option("--limit <n>", "Pod-wide: page size (default 50)")
|
|
1306
|
+
.option("--cursor <cursor>", "Pod-wide: the next page (printed under the last one)")
|
|
1307
|
+
.option("--all", "Include dropped (archived) tracks")
|
|
1308
|
+
.option("--json", "Output as JSON")
|
|
1309
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1310
|
+
.option("--api-key <key>", "API key override")
|
|
1311
|
+
.action(async (opts) => {
|
|
1312
|
+
const { listTracks } = await import("./commands/tracks.js");
|
|
1313
|
+
await listTracks(opts);
|
|
1314
|
+
});
|
|
1315
|
+
track
|
|
1316
|
+
.command("show <id>")
|
|
1317
|
+
.description("Show one track: its steps and where it stands")
|
|
1318
|
+
.option("--json", "Output as JSON")
|
|
1319
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1320
|
+
.option("--api-key <key>", "API key override")
|
|
1321
|
+
.action(async (id, opts) => {
|
|
1322
|
+
const { showTrack } = await import("./commands/tracks.js");
|
|
1323
|
+
await showTrack(id, opts);
|
|
1324
|
+
});
|
|
1325
|
+
track
|
|
1326
|
+
.command("start")
|
|
1327
|
+
.description("Start a track — a goal — on a project")
|
|
1328
|
+
.option("--name <name>", "The track's name (required without --playbook)")
|
|
1329
|
+
.option("--direction <text>", "Where it is heading, one line")
|
|
1330
|
+
.option("--playbook <id>", "Legacy: a track template (project-scoped playbook with steps)")
|
|
1331
|
+
.option("--project <id>", "Project id (defaults to the active project lens)")
|
|
1332
|
+
.option("--param <key=value>", "Answer a declared param (repeatable)", collect, [])
|
|
1333
|
+
.option("--end-state <text>", "What done looks like, in your words")
|
|
1334
|
+
.option("--criterion <text>", "How it is judged done — '[measured|judged|handed_over|learning|decided_outside|certified:] statement'; give 0 or 2-5 (repeatable)", collect, [])
|
|
1335
|
+
.option("--drop-condition <text>", "When to stop pursuing it (repeatable, at most 5)", collect, [])
|
|
1336
|
+
.option("--kind <kind>", "Kind of work: project|flow|operation|investigation|incident|commission|pathway (a proposal until you confirm)")
|
|
1337
|
+
.option("--uncertainty <level>", "How well the way is known: clear|complicated|complex|chaotic|unknown")
|
|
1338
|
+
.option("--loop <on|off|n>", "Let the goal propose its next session: on, off, or n sessions a week")
|
|
1339
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1340
|
+
.option("--json", "Output as JSON")
|
|
1341
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1342
|
+
.option("--api-key <key>", "API key override")
|
|
1343
|
+
.action(async (opts) => {
|
|
1344
|
+
const { startTrack } = await import("./commands/tracks.js");
|
|
1345
|
+
await startTrack(opts);
|
|
1346
|
+
});
|
|
1347
|
+
track
|
|
1348
|
+
.command("update <id>")
|
|
1349
|
+
.description("Set a goal's direction, KPI and what it holds (each field is written whole; kpi is merged)")
|
|
1350
|
+
.option("--direction <text>", "Where it is heading, one line")
|
|
1351
|
+
.option("--kpi-current <n>", "The KPI's latest value (stated, never measured)")
|
|
1352
|
+
.option("--kpi-target <n>", "Move the KPI's target")
|
|
1353
|
+
.option("--end-state <text>", "What done looks like, in your words")
|
|
1354
|
+
.option("--criterion <text>", "How it is judged done — '[measured|judged|handed_over|learning|decided_outside|certified:] statement'; give 0 or 2-5 (repeatable)", collect, [])
|
|
1355
|
+
.option("--drop-condition <text>", "When to stop pursuing it (repeatable, at most 5)", collect, [])
|
|
1356
|
+
.option("--kind <kind>", "Kind of work: project|flow|operation|investigation|incident|commission|pathway (a proposal until you confirm)")
|
|
1357
|
+
.option("--uncertainty <level>", "How well the way is known: clear|complicated|complex|chaotic|unknown")
|
|
1358
|
+
.option("--loop <on|off|n>", "Let the goal propose its next session: on, off, or n sessions a week")
|
|
1359
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1360
|
+
.option("--json", "Output as JSON")
|
|
1361
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1362
|
+
.option("--api-key <key>", "API key override")
|
|
1363
|
+
.action(async (id, opts) => {
|
|
1364
|
+
const { updateTrack } = await import("./commands/tracks.js");
|
|
1365
|
+
await updateTrack(id, opts);
|
|
1366
|
+
});
|
|
1367
|
+
track
|
|
1368
|
+
.command("accept <id> <criterion> <decision>")
|
|
1369
|
+
.description("The goal's judge decides a claimed criterion: accepted | changes_asked | rejected (a person's act)")
|
|
1370
|
+
.option("--note <text>", "What to change, or why it was rejected")
|
|
1371
|
+
.option("--json", "Output as JSON")
|
|
1372
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1373
|
+
.option("--api-key <key>", "API key override")
|
|
1374
|
+
.action(async (id, criterion, decision, opts) => {
|
|
1375
|
+
const { acceptCriterion } = await import("./commands/tracks.js");
|
|
1376
|
+
await acceptCriterion(id, criterion, decision, opts);
|
|
1377
|
+
});
|
|
1378
|
+
track
|
|
1379
|
+
.command("advance <id> <stage>")
|
|
1380
|
+
.description("Legacy (tracks with steps): move a track to a step; prints the session that step offers")
|
|
1381
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1382
|
+
.option("--json", "Output as JSON")
|
|
1383
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1384
|
+
.option("--api-key <key>", "API key override")
|
|
1385
|
+
.action(async (id, stage, opts) => {
|
|
1386
|
+
const { advanceTrack } = await import("./commands/tracks.js");
|
|
1387
|
+
await advanceTrack(id, stage, opts);
|
|
1388
|
+
});
|
|
1389
|
+
track
|
|
1390
|
+
.command("status <id> <status>")
|
|
1391
|
+
.description("Move a track: proposed|agreed|ready|active|paused|completed (Closed)|archived (Dropped). " +
|
|
1392
|
+
"Closing needs --verdict met|partly_met|not_met (an operation closes retired, and only one does); dropping should carry " +
|
|
1393
|
+
"no_longer_needed|impossible|replaced|mistake (impossible and replaced need --verdict-reason). " +
|
|
1394
|
+
"Both are final — reopen makes a new version.")
|
|
1395
|
+
.option("--verdict <verdict>", "How the goal ended (required to close; advised to drop)")
|
|
1396
|
+
.option("--verdict-reason <text>", "Why — required for impossible and replaced")
|
|
1397
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1398
|
+
.option("--json", "Output as JSON")
|
|
1399
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1400
|
+
.option("--api-key <key>", "API key override")
|
|
1401
|
+
.action(async (id, status, opts) => {
|
|
1402
|
+
const { setTrackStatus } = await import("./commands/tracks.js");
|
|
1403
|
+
await setTrackStatus(id, status, opts);
|
|
1404
|
+
});
|
|
1405
|
+
track
|
|
1406
|
+
.command("reopen <id>")
|
|
1407
|
+
.description("Reopen a closed or dropped goal as a NEW version (the old one keeps its verdict)")
|
|
1408
|
+
.option("--name <name>", "A new name (default: the old one's)")
|
|
1409
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1410
|
+
.option("--json", "Output as JSON")
|
|
1411
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1412
|
+
.option("--api-key <key>", "API key override")
|
|
1413
|
+
.action(async (id, opts) => {
|
|
1414
|
+
const { reopenTrack } = await import("./commands/tracks.js");
|
|
1415
|
+
await reopenTrack(id, opts);
|
|
1416
|
+
});
|
|
1417
|
+
const goal = program
|
|
1418
|
+
.command("goal")
|
|
1419
|
+
.description("Goals — what people call a track");
|
|
1420
|
+
goal
|
|
1421
|
+
.command("convert <entityId>")
|
|
1422
|
+
.description("Make a goal, objective or OKR entity a goal (once; the entity is kept and linked)")
|
|
1423
|
+
.option("--project <id>", "The goal's project — only when the entity is filed in none or several")
|
|
1424
|
+
.option("--name <name>", "A name other than the entity's title")
|
|
1425
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1426
|
+
.option("--json", "Output as JSON")
|
|
1427
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1428
|
+
.option("--api-key <key>", "API key override")
|
|
1429
|
+
.action(async (entityId, opts) => {
|
|
1430
|
+
const { convertToGoal } = await import("./commands/tracks.js");
|
|
1431
|
+
await convertToGoal(entityId, opts);
|
|
1432
|
+
});
|
|
1433
|
+
track
|
|
1434
|
+
.command("params <id> <pairs...>")
|
|
1435
|
+
.description("Answer the method's params as key=value (merged; key=null clears one)")
|
|
1436
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1437
|
+
.option("--json", "Output as JSON")
|
|
1438
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1439
|
+
.option("--api-key <key>", "API key override")
|
|
1440
|
+
.action(async (id, pairs, opts) => {
|
|
1441
|
+
const { setTrackParams } = await import("./commands/tracks.js");
|
|
1442
|
+
await setTrackParams(id, pairs, opts);
|
|
1443
|
+
});
|
|
1444
|
+
track
|
|
1445
|
+
.command("start-step <id>")
|
|
1446
|
+
.description("Legacy (tracks with steps): start one step's session — on a track with no steps, use 'session start --track'")
|
|
1447
|
+
.option("--stage <key>", "Step key (defaults to the current step)")
|
|
1448
|
+
.option("--title <text>", "Session name (defaults to the step's name)")
|
|
1449
|
+
.option("--goal <text>", "Outcome (defaults to the step's goal)")
|
|
1450
|
+
.option("--json", "Output as JSON")
|
|
1451
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1452
|
+
.option("--api-key <key>", "API key override")
|
|
1453
|
+
.action(async (id, opts) => {
|
|
1454
|
+
const { startStep } = await import("./commands/tracks.js");
|
|
1455
|
+
await startStep(id, opts);
|
|
1456
|
+
});
|
|
951
1457
|
// ─── skill ────────────────────────────────────────────────────────────────────
|
|
952
1458
|
// Autonomous workspace session skills — context gathering, task planning, etc.
|
|
953
1459
|
const skillCmd = program
|
|
@@ -981,6 +1487,7 @@ skillCmd
|
|
|
981
1487
|
skillCmd
|
|
982
1488
|
.command("get <slug>")
|
|
983
1489
|
.description("Fetch a skill from the knowledge base by slug and print its body")
|
|
1490
|
+
.option("--raw", "Print only the stored body, exactly (for scripts)")
|
|
984
1491
|
.option("--pod-url <url>", "Pod URL override")
|
|
985
1492
|
.option("--api-key <key>", "API key override")
|
|
986
1493
|
.action(async (slug, opts) => {
|
|
@@ -1007,6 +1514,16 @@ skillCmd
|
|
|
1007
1514
|
const { listSkills } = await import("./commands/skill-manage.js");
|
|
1008
1515
|
await listSkills(opts);
|
|
1009
1516
|
});
|
|
1517
|
+
skillCmd
|
|
1518
|
+
.command("approve <slug-or-id>")
|
|
1519
|
+
.description("Approve a skill so it loads (agent-authored skills are born unapproved)")
|
|
1520
|
+
.option("--revoke", "Revoke approval instead of granting it")
|
|
1521
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1522
|
+
.option("--api-key <key>", "API key override")
|
|
1523
|
+
.action(async (ref, opts) => {
|
|
1524
|
+
const { approveSkill } = await import("./commands/skill-manage.js");
|
|
1525
|
+
await approveSkill(ref, opts);
|
|
1526
|
+
});
|
|
1010
1527
|
skillCmd
|
|
1011
1528
|
.command("remove <slug>")
|
|
1012
1529
|
.alias("rm")
|
|
@@ -1063,12 +1580,34 @@ const observe = program
|
|
|
1063
1580
|
observe
|
|
1064
1581
|
.command("write <text>", { isDefault: true })
|
|
1065
1582
|
.description("Record an observation about the user (pod-scoped, AI-maintained)")
|
|
1066
|
-
.option("--category <cat>", "working_style | communication | focus |
|
|
1583
|
+
.option("--category <cat>", "working_style | communication | focus | preferences | habits | technical", "preferences")
|
|
1067
1584
|
.option("--confidence <n>", "Confidence score 0-1", "0.5")
|
|
1068
1585
|
.option("--json", "Output as JSON")
|
|
1069
1586
|
.option("--pod-url <url>", "Pod URL override")
|
|
1070
1587
|
.option("--api-key <key>", "API key override")
|
|
1071
1588
|
.action(async (text, opts) => {
|
|
1589
|
+
// `write` is the DEFAULT subcommand, so an unrecognized token lands here as
|
|
1590
|
+
// `text` instead of erroring — and this default WRITES. `synap observe recal`
|
|
1591
|
+
// therefore recorded an observation literally reading "recal" into the
|
|
1592
|
+
// AI-maintained user model, silently. Every other `isDefault` group in this
|
|
1593
|
+
// file has a zero-arg default, which commander rejects on its own; this is
|
|
1594
|
+
// the only one that can absorb a typo, and the only one where absorbing it
|
|
1595
|
+
// is a mutation.
|
|
1596
|
+
//
|
|
1597
|
+
// The guard keys off whether `write` was named EXPLICITLY, not off the text:
|
|
1598
|
+
// a mistyped subcommand is always a single bare token, and a real
|
|
1599
|
+
// observation is a sentence. Going through `observe write <text>` skips the
|
|
1600
|
+
// check entirely, so the escape hatch is real rather than circular.
|
|
1601
|
+
const argv = process.argv;
|
|
1602
|
+
const observeAt = argv.indexOf("observe");
|
|
1603
|
+
const explicitWrite = observeAt !== -1 && argv[observeAt + 1] === "write";
|
|
1604
|
+
if (!explicitWrite && !/\s/.test(text.trim())) {
|
|
1605
|
+
const siblings = observe.commands.map((c) => c.name()).filter((n) => n !== "write");
|
|
1606
|
+
console.error(`error: '${text}' looks like a subcommand, not observation text — nothing was recorded.\n` +
|
|
1607
|
+
` Available: ${siblings.map((n) => `synap observe ${n}`).join(", ")}\n` +
|
|
1608
|
+
` To record it as an observation anyway: synap observe write ${JSON.stringify(text)}`);
|
|
1609
|
+
process.exit(1);
|
|
1610
|
+
}
|
|
1072
1611
|
const { observeWrite } = await import("./commands/observe.js");
|
|
1073
1612
|
await observeWrite(text, opts);
|
|
1074
1613
|
});
|
|
@@ -1108,6 +1647,7 @@ create
|
|
|
1108
1647
|
.description("Create a new entity")
|
|
1109
1648
|
.requiredOption("--profile <slug>", "Profile slug (e.g. person, note, task)")
|
|
1110
1649
|
.requiredOption("--name <name>", "Entity name")
|
|
1650
|
+
.option("--content <markdown>", "Long-form Markdown body, stored as the entity's linked document")
|
|
1111
1651
|
.option("--workspace <id>", "Create in this workspace")
|
|
1112
1652
|
.option("--props <json>", "Properties as JSON string", "{}")
|
|
1113
1653
|
.option("--json", "Output as JSON")
|
|
@@ -1150,43 +1690,48 @@ set
|
|
|
1150
1690
|
// ─── agents ───────────────────────────────────────────────────────────────────
|
|
1151
1691
|
const agents = program
|
|
1152
1692
|
.command("agents")
|
|
1153
|
-
.description("Manage
|
|
1693
|
+
.description("Manage agent principals on your pod (one per type for you; local keys are a cache)");
|
|
1154
1694
|
agents
|
|
1155
1695
|
.command("list", { isDefault: true })
|
|
1156
|
-
.description("List
|
|
1696
|
+
.description("List your agents on this pod (one per type). Use --local for ~/.synap cache only.")
|
|
1157
1697
|
.option("--json", "Output as JSON")
|
|
1698
|
+
.option("--local", "List only the local ~/.synap agent cache")
|
|
1158
1699
|
.action(async (opts) => {
|
|
1159
1700
|
const { agentsList } = await import("./commands/agents.js");
|
|
1160
|
-
agentsList(opts);
|
|
1701
|
+
await agentsList(opts);
|
|
1161
1702
|
});
|
|
1162
1703
|
agents
|
|
1163
|
-
.command("add")
|
|
1164
|
-
.description("
|
|
1165
|
-
.option("--name <name>", "
|
|
1166
|
-
.option("--
|
|
1167
|
-
.option("--
|
|
1168
|
-
.option("--
|
|
1704
|
+
.command("add [kind]")
|
|
1705
|
+
.description("Bring an agent into the pod: a client (claude-code, cursor, codex, …), your own (--name → URL + key), or pick from this machine (no kind)")
|
|
1706
|
+
.option("--name <name>", "Name your own agent (e.g. researcher) — prints a URL + key to paste")
|
|
1707
|
+
.option("--template <tmpl>", "Your own agent's template: twin | assistant | custom (default: custom)")
|
|
1708
|
+
.option("--type <type>", "Explicit agent type for your own agent (default: a slug of --name)")
|
|
1709
|
+
.option("--role <role>", "Workspace role: admin | editor | viewer (default: editor)")
|
|
1710
|
+
.option("--workspace <id>", "Focus on one workspace (default: pod-wide)")
|
|
1711
|
+
.option("--project <id>", "Focus on one project (composable with --workspace)")
|
|
1712
|
+
.addOption(new Option("--with-mcp", "deprecated, ignored: Raycast always gets the pod's MCP server").hideHelp())
|
|
1713
|
+
.option("--api-key <key>", "Register a key you already hold, on this machine only (mints nothing)")
|
|
1169
1714
|
.option("--label <label>", "Human-readable description")
|
|
1170
|
-
.action(async (opts) => {
|
|
1715
|
+
.action(async (kind, opts) => {
|
|
1171
1716
|
const { agentsAdd } = await import("./commands/agents.js");
|
|
1172
|
-
await agentsAdd(opts);
|
|
1717
|
+
await agentsAdd(kind, opts);
|
|
1173
1718
|
});
|
|
1174
1719
|
agents
|
|
1175
1720
|
.command("create")
|
|
1176
|
-
.description("
|
|
1721
|
+
.description("Deprecated — use `synap agents add` (same flags)")
|
|
1177
1722
|
.option("--template <tmpl>", "Agent template: twin | assistant | custom (default: custom)")
|
|
1178
1723
|
.option("--name <name>", "Agent name (not needed for twin — auto-generated)")
|
|
1179
1724
|
.option("--type <type>", "Agent type string for custom agents (default: matches template)")
|
|
1180
|
-
.option("--role <role>", "Workspace role: admin | editor | viewer (default: editor
|
|
1181
|
-
.option("--workspace <id>", "
|
|
1182
|
-
.option("--
|
|
1725
|
+
.option("--role <role>", "Workspace role: admin | editor | viewer (default: editor)")
|
|
1726
|
+
.option("--workspace <id>", "Focus on one workspace (default: pod-wide)")
|
|
1727
|
+
.option("--project <id>", "Focus on one project")
|
|
1183
1728
|
.action(async (opts) => {
|
|
1184
1729
|
const { agentsCreate } = await import("./commands/agents.js");
|
|
1185
1730
|
await agentsCreate(opts);
|
|
1186
1731
|
});
|
|
1187
1732
|
agents
|
|
1188
1733
|
.command("rotate-key <name-or-id>")
|
|
1189
|
-
.description("Rotate the Hub Protocol API key for an agent (
|
|
1734
|
+
.description("Rotate the Hub Protocol API key for an agent (local cache only)")
|
|
1190
1735
|
.action(async (nameOrId) => {
|
|
1191
1736
|
const { agentsRotateKey } = await import("./commands/agents.js");
|
|
1192
1737
|
await agentsRotateKey(nameOrId);
|
|
@@ -1194,17 +1739,19 @@ agents
|
|
|
1194
1739
|
agents
|
|
1195
1740
|
.command("remove <name>")
|
|
1196
1741
|
.alias("rm")
|
|
1197
|
-
.description("Remove a named agent identity")
|
|
1742
|
+
.description("Remove a named agent identity (local cache only)")
|
|
1198
1743
|
.action(async (name) => {
|
|
1199
1744
|
const { agentsRemove } = await import("./commands/agents.js");
|
|
1200
1745
|
agentsRemove(name);
|
|
1201
1746
|
});
|
|
1202
1747
|
agents
|
|
1203
1748
|
.command("info <name>")
|
|
1204
|
-
.description("Show details for a named agent identity")
|
|
1205
|
-
.
|
|
1749
|
+
.description("Show details for a named agent identity (local cache only)")
|
|
1750
|
+
.option("--show-key", "Print the MCP URL and the full API key")
|
|
1751
|
+
.option("--snippets", "Print paste-ready configs (Claude Code, Cursor, stdio clients)")
|
|
1752
|
+
.action(async (name, opts) => {
|
|
1206
1753
|
const { agentsInfo } = await import("./commands/agents.js");
|
|
1207
|
-
agentsInfo(name);
|
|
1754
|
+
await agentsInfo(name, opts);
|
|
1208
1755
|
});
|
|
1209
1756
|
// ─── agent (autonomous runner) ───────────────────────────────────────────────
|
|
1210
1757
|
const agent = program
|
|
@@ -1282,6 +1829,52 @@ agent
|
|
|
1282
1829
|
const { agentTick } = await import("./commands/agent-run.js");
|
|
1283
1830
|
await agentTick(opts);
|
|
1284
1831
|
});
|
|
1832
|
+
// ─── automate ───────────────────────────────────────────────────────────────
|
|
1833
|
+
// The natural-language automation door. It stays deliberately separate from
|
|
1834
|
+
// `automation create`, which remains the expert, explicit-DSL path.
|
|
1835
|
+
program
|
|
1836
|
+
.command("automate <instruction>")
|
|
1837
|
+
.description("Ask the workspace agent to prepare a governed automation proposal")
|
|
1838
|
+
.option("--workspace <id|name>", "Workspace to use (uses active workspace/lens if omitted)")
|
|
1839
|
+
.option("--thread <id>", "Continue an existing agent thread/channel")
|
|
1840
|
+
.option("--new", "Start a fresh agent thread")
|
|
1841
|
+
.option("--timeout <seconds>", "How long to wait for the agent's reply (default: 90)")
|
|
1842
|
+
.option("--json", "Machine-readable output { ok, reply, threadId, workspaceId }")
|
|
1843
|
+
.option("--pod-url <url>", "Override pod URL")
|
|
1844
|
+
.option("--api-key <key>", "Override API key")
|
|
1845
|
+
.action(async (instruction, opts) => {
|
|
1846
|
+
const { automate } = await import("./commands/automate.js");
|
|
1847
|
+
await automate(instruction, opts);
|
|
1848
|
+
});
|
|
1849
|
+
// ─── rule ────────────────────────────────────────────────────────────────────
|
|
1850
|
+
// The fourth door, beside `ask` (recall), `capture` (write) and `diagnose`
|
|
1851
|
+
// (inspect): a STANDING instruction. It classifies the sentence and shows the
|
|
1852
|
+
// reading before writing anything — and it records the rule only. Building the
|
|
1853
|
+
// behaviour half is still `synap automate`.
|
|
1854
|
+
const ruleCmd = program
|
|
1855
|
+
.command("rule [text]")
|
|
1856
|
+
.description("State a standing rule in plain language — classified, shown, then governed-created")
|
|
1857
|
+
.option("--workspace <id>", "Workspace to scope the rule to (uses active workspace if omitted)")
|
|
1858
|
+
.option("--pod-wide", "Scope the rule to the whole pod, ignoring the active workspace")
|
|
1859
|
+
.option("--yes", "Skip the one-off confirmation (never skips a clarification)")
|
|
1860
|
+
.option("--json", "Output raw JSON")
|
|
1861
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1862
|
+
.option("--api-key <key>", "API key override")
|
|
1863
|
+
.action(async (text, opts) => {
|
|
1864
|
+
const { rule } = await import("./commands/rule.js");
|
|
1865
|
+
await rule(text ?? "", opts);
|
|
1866
|
+
});
|
|
1867
|
+
ruleCmd
|
|
1868
|
+
.command("list")
|
|
1869
|
+
.description("List rules with their intent, scope, and whether a behaviour is attached")
|
|
1870
|
+
.option("--workspace <id>", "Filter by workspace")
|
|
1871
|
+
.option("--json", "Output raw JSON")
|
|
1872
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1873
|
+
.option("--api-key <key>", "API key override")
|
|
1874
|
+
.action(async (opts) => {
|
|
1875
|
+
const { ruleList } = await import("./commands/rule.js");
|
|
1876
|
+
await ruleList(opts);
|
|
1877
|
+
});
|
|
1285
1878
|
// ─── automation ──────────────────────────────────────────────────────────────
|
|
1286
1879
|
function collect(val, prev) { return [...prev, val]; }
|
|
1287
1880
|
const automation = program
|
|
@@ -1473,12 +2066,11 @@ program
|
|
|
1473
2066
|
.description("Open in the Synap desktop app. Use: open <kind> <id> or open <id> (auto-resolves type)")
|
|
1474
2067
|
.action(async (kindOrId, id) => {
|
|
1475
2068
|
if (id) {
|
|
1476
|
-
// open
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
}
|
|
2069
|
+
// open <kind> <id> — the browser's object-nav.ts is the one route
|
|
2070
|
+
// table for openable kinds (21 and growing); the CLI doesn't
|
|
2071
|
+
// duplicate it here. An unroutable kind still opens the app and
|
|
2072
|
+
// is reported via the printed deep link (objectNavTarget decides
|
|
2073
|
+
// routability on the other side).
|
|
1482
2074
|
const { openInBrowser } = await import("./commands/open.js");
|
|
1483
2075
|
await openInBrowser({ kind: kindOrId, id });
|
|
1484
2076
|
}
|
|
@@ -1515,10 +2107,12 @@ Examples:
|
|
|
1515
2107
|
});
|
|
1516
2108
|
doc
|
|
1517
2109
|
.command("update <documentId>")
|
|
1518
|
-
.description("Update a document's content
|
|
2110
|
+
.description("Update a document's content: the whole body, or one section (--section). Governed: an agent's edit is proposed.")
|
|
1519
2111
|
.option("--content <text>", "New markdown content (inline)")
|
|
1520
2112
|
.option("--file <path>", "Read new content from a file")
|
|
1521
|
-
.option("--
|
|
2113
|
+
.option("--section <id>", "Write ONE section by id (content = the section body) instead of the whole document")
|
|
2114
|
+
.option("--section-title <title>", "The section heading (required with --section)")
|
|
2115
|
+
.option("--base-revision <n>", "The revision you read; refused if the document changed since")
|
|
1522
2116
|
.option("--open", "Open in the Synap desktop app after update")
|
|
1523
2117
|
.option("--json", "JSON output")
|
|
1524
2118
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -1528,6 +2122,7 @@ Examples:
|
|
|
1528
2122
|
synap doc update <id> --content "# Updated"
|
|
1529
2123
|
synap doc update <id> --file ./notes.md
|
|
1530
2124
|
cat notes.md | synap doc update <id>
|
|
2125
|
+
synap doc update <id> --section risks --section-title "Risks" --file ./risks.md
|
|
1531
2126
|
`)
|
|
1532
2127
|
.action(async (documentId, opts) => {
|
|
1533
2128
|
const { docUpdate } = await import("./commands/doc.js");
|
|
@@ -1560,17 +2155,30 @@ cell
|
|
|
1560
2155
|
.requiredOption("--name <name>", "Cell display name")
|
|
1561
2156
|
.option("--file <path>", "ESM source file (or pipe stdin)")
|
|
1562
2157
|
.option("--type-key <key>", "Explicit typeKey (default: generated:<slug>)")
|
|
1563
|
-
.option("--deps <json>", 'Dependency map JSON, e.g. \'{"recharts":"2.12.0"}\'
|
|
1564
|
-
.option("--
|
|
2158
|
+
.option("--deps <json>", 'Dependency map JSON, e.g. \'{"recharts":"2.12.0"}\'')
|
|
2159
|
+
.option("--view-types <list>", 'Comma-separated view types this cell can render as a VIEW RENDERER, e.g. "list,table,kanban". Omit to leave an existing affinity untouched; pass "" to clear it')
|
|
2160
|
+
.option("--content-kind <kind>", "What this cell renders — entity-detail | entity-card | entity-profile | collection | widget (default: widget, which is placeable but never offered as a profile renderer)")
|
|
2161
|
+
// NOT "omit for pod-wide": `cell.ts` resolves `opts.workspace ?? cfg.workspaceId`,
|
|
2162
|
+
// and `cfg.workspaceId` is the resolved lens (session › directory › env ›
|
|
2163
|
+
// profile default). Omitting therefore scopes the cell to whatever workspace
|
|
2164
|
+
// your lens currently points at — which is pod-wide ONLY when nothing resolves.
|
|
2165
|
+
// Verified 2026-09-05: run from a directory with no `.synap/lens.json` and the
|
|
2166
|
+
// cell silently lands in the pod profile's default workspace.
|
|
2167
|
+
.option("--workspace <id>", "Workspace to scope the cell to (default: your active workspace lens — run `synap lens` to see it)")
|
|
1565
2168
|
.option("--description <text>", "Short description")
|
|
1566
2169
|
.option("--open", "Open in the Synap desktop app after define")
|
|
1567
2170
|
.option("--json", "JSON output")
|
|
1568
2171
|
.option("--pod-url <url>", "Pod URL override")
|
|
1569
2172
|
.option("--api-key <key>", "API key override")
|
|
1570
2173
|
.addHelpText("after", `
|
|
2174
|
+
Without --view-types / --content-kind a cell installs cleanly but can never be
|
|
2175
|
+
PICKED as a view or profile renderer — it is only placeable on a bento.
|
|
2176
|
+
|
|
1571
2177
|
Examples:
|
|
1572
2178
|
synap cell define --name "Revenue Chart" --file ./chart.js
|
|
1573
2179
|
synap cell define --name "Revenue Chart" --file ./chart.js --deps '{"recharts":"2.12.0"}'
|
|
2180
|
+
synap cell define --name "Deal Board" --file ./board.js --view-types kanban,table --content-kind collection
|
|
2181
|
+
synap cell define --name "Contact Page" --file ./contact.js --content-kind entity-detail
|
|
1574
2182
|
cat chart.js | synap cell define --name "Revenue Chart"
|
|
1575
2183
|
`)
|
|
1576
2184
|
.action(async (opts) => {
|
|
@@ -1581,10 +2189,16 @@ cell
|
|
|
1581
2189
|
.command("build <entry>")
|
|
1582
2190
|
.description("Bundle a multi-file cell/app into a single ESM module the runtime expects")
|
|
1583
2191
|
.option("--out <file>", "Output file path (default: <entry>.bundle.js)")
|
|
2192
|
+
.option("--bundle-deps", "Inline all third-party deps into the bundle (only react/react-dom stay external) — output has deps={} and the runtime CSP drops esm.sh entirely")
|
|
2193
|
+
.option("--self-contained", 'Build ONE complete HTML document (React, CSS, brand fonts inlined; nothing external) — the code of a rendererType "mcp-app" cell')
|
|
2194
|
+
.option("--fonts", "With --self-contained: require the inlined brand fonts (default: include when @synap-core/design-tokens resolves)")
|
|
2195
|
+
.option("--no-fonts", "With --self-contained: skip the inlined brand fonts")
|
|
1584
2196
|
.option("--define", "Chain into cell define after bundling (requires --name)")
|
|
1585
2197
|
.option("--name <name>", "Cell name (required with --define)")
|
|
1586
2198
|
.option("--type-key <key>", "Explicit typeKey (used with --define)")
|
|
1587
2199
|
.option("--deps <json>", "Override dependency versions as JSON, e.g. '{\"react\":\"18.3.0\"}'")
|
|
2200
|
+
.option("--view-types <list>", 'Comma-separated view-renderer affinity (used with --define), e.g. "list,table"')
|
|
2201
|
+
.option("--content-kind <kind>", "entity-detail | entity-card | entity-profile | collection | widget (used with --define)")
|
|
1588
2202
|
.option("--workspace <id>", "Workspace (used with --define)")
|
|
1589
2203
|
.option("--description <text>", "Description (used with --define)")
|
|
1590
2204
|
.option("--open", "Open in browser after define (used with --define)")
|
|
@@ -1592,12 +2206,20 @@ cell
|
|
|
1592
2206
|
.option("--pod-url <url>", "Pod URL override")
|
|
1593
2207
|
.option("--api-key <key>", "API key override")
|
|
1594
2208
|
.addHelpText("after", `
|
|
1595
|
-
Output: a single ESM file.
|
|
1596
|
-
|
|
2209
|
+
Output: a single ESM file.
|
|
2210
|
+
|
|
2211
|
+
Default mode: bare imports (react, recharts, …) are externalized and emitted
|
|
2212
|
+
as a deps map. At runtime Synap resolves them via esm.sh importmap.
|
|
2213
|
+
|
|
2214
|
+
--bundle-deps mode: only react/react-dom are externalized (React is
|
|
2215
|
+
host-inlined at runtime, never via esm.sh); everything else is bundled into
|
|
2216
|
+
the output, so the deps map is empty. A cell built this way reaches no esm.sh
|
|
2217
|
+
origin at runtime — the runtime CSP collapses to drop it entirely.
|
|
1597
2218
|
|
|
1598
2219
|
Examples:
|
|
1599
2220
|
synap cell build ./src/chart.tsx --out ./dist/chart.js
|
|
1600
2221
|
synap cell build ./src/chart.tsx --out ./dist/chart.js --define --name "Revenue Chart"
|
|
2222
|
+
synap cell build ./src/chart.tsx --out ./dist/chart.js --bundle-deps
|
|
1601
2223
|
`)
|
|
1602
2224
|
.action(async (entry, opts) => {
|
|
1603
2225
|
const { cellBuild } = await import("./commands/cell.js");
|
|
@@ -1606,12 +2228,12 @@ Examples:
|
|
|
1606
2228
|
// ─── artifact ─────────────────────────────────────────────────────────────────
|
|
1607
2229
|
const artifact = program
|
|
1608
2230
|
.command("artifact")
|
|
1609
|
-
.description("Create
|
|
2231
|
+
.description("Create HTML artifacts as Synap cells: an HTML/JS page that opens in the desktop app and can read pod data");
|
|
1610
2232
|
artifact
|
|
1611
2233
|
.command("create")
|
|
1612
|
-
.description("
|
|
2234
|
+
.description("Define a cell from a local HTML file (governed: an agent key files a proposal)")
|
|
1613
2235
|
.requiredOption("--html <file>", "HTML file to upload")
|
|
1614
|
-
.option("--name <name>", "
|
|
2236
|
+
.option("--name <name>", "Cell name (default: filename)")
|
|
1615
2237
|
.option("--workspace <id>", "Workspace context")
|
|
1616
2238
|
.option("--open", "Open in the Synap desktop app after creation")
|
|
1617
2239
|
.option("--json", "JSON output")
|
|
@@ -1647,7 +2269,7 @@ tools
|
|
|
1647
2269
|
});
|
|
1648
2270
|
tools
|
|
1649
2271
|
.command("connect <service>")
|
|
1650
|
-
.description("Connect a credential to a tool (via
|
|
2272
|
+
.description("Connect a credential to a tool (OAuth via the connection broker, or vault)")
|
|
1651
2273
|
.option("--workspace <id>", "Workspace context")
|
|
1652
2274
|
.option("--pod-url <url>", "Pod URL override")
|
|
1653
2275
|
.option("--api-key <key>", "API key override")
|
|
@@ -1712,6 +2334,33 @@ podCmd
|
|
|
1712
2334
|
const { podAdopt } = await import("./commands/pod.js");
|
|
1713
2335
|
await podAdopt(workspaceNameOrId, opts);
|
|
1714
2336
|
});
|
|
2337
|
+
// ─── vendor — the author's publisher profile ─────────────────────────────────
|
|
2338
|
+
// Attribution is write-time-only at the CP: a package published before a vendor
|
|
2339
|
+
// exists is orphaned from its author forever. See src/commands/vendor.ts.
|
|
2340
|
+
const vendor = program
|
|
2341
|
+
.command("vendor")
|
|
2342
|
+
.description("Your marketplace publisher profile (what packages are attributed to)");
|
|
2343
|
+
vendor
|
|
2344
|
+
.command("create <slug>")
|
|
2345
|
+
.description("Create your publisher profile — do this BEFORE your first publish")
|
|
2346
|
+
.option("--name <name>", "Display name (defaults to a title-cased slug)")
|
|
2347
|
+
.option("--description <text>", "Short description of you or your studio")
|
|
2348
|
+
.option("--website <url>", "Website URL (must be a full URL)")
|
|
2349
|
+
.option("--json", "Output as JSON")
|
|
2350
|
+
.action(async (slug, _opts, cmd) => {
|
|
2351
|
+
const opts = cmd.optsWithGlobals();
|
|
2352
|
+
const { vendorCreate } = await import("./commands/vendor.js");
|
|
2353
|
+
await vendorCreate(slug, opts);
|
|
2354
|
+
});
|
|
2355
|
+
vendor
|
|
2356
|
+
.command("show")
|
|
2357
|
+
.description("Show whether you have a publisher profile")
|
|
2358
|
+
.option("--json", "Output as JSON")
|
|
2359
|
+
.action(async (_opts, cmd) => {
|
|
2360
|
+
const opts = cmd.optsWithGlobals();
|
|
2361
|
+
const { vendorShow } = await import("./commands/vendor.js");
|
|
2362
|
+
await vendorShow(opts);
|
|
2363
|
+
});
|
|
1715
2364
|
// ─── market — discover + install ANY package type ────────────────────────────
|
|
1716
2365
|
// launch is workspace-first (bundled, offline); market reaches every CP package
|
|
1717
2366
|
// type (capability/skill/workflow/view/cell/workspace), public or private.
|
|
@@ -1730,6 +2379,7 @@ market
|
|
|
1730
2379
|
.command("install <slug>")
|
|
1731
2380
|
.description("Install a package by slug into a project — workspaces install now; other types route you to the right surface")
|
|
1732
2381
|
.option("--project <id>", "Optionally tag the seeded entities to a project (installs are pod-wide by default)")
|
|
2382
|
+
.option("--workspace <id>", "Acting workspace (UUID) a workflow/automation package is added to (required for that kind; defaults to your active lens). Ignored for pod-wide kinds")
|
|
1733
2383
|
.option("--onto <workspaceId>", "Reconcile this template ONTO an existing workspace (additive) instead of creating a new one")
|
|
1734
2384
|
.option("--dry-run", "Preview the create path write-free — report would-create / reuse / conflicts, install nothing")
|
|
1735
2385
|
.option("--timeout <seconds>", "How long to wait for the apply to finish (default: 120)")
|
|
@@ -1750,7 +2400,8 @@ market
|
|
|
1750
2400
|
market
|
|
1751
2401
|
.command("update [slugs...]")
|
|
1752
2402
|
.description("Check installed packages for drift against the catalog, and re-apply the ones that are stale (all with --yes, specific ones with explicit slugs)")
|
|
1753
|
-
.option("--yes", "Apply every available update without prompting (no slugs required)")
|
|
2403
|
+
.option("--yes", "Apply every available update without prompting (no slugs required), agreeing to every data change it lists")
|
|
2404
|
+
.option("--accept-data-changes <opKeys>", "Agree to exactly these data changes (comma-separated opKeys from the preview)")
|
|
1754
2405
|
.option("--dry-run", "Force the preview path — never apply, even with --yes")
|
|
1755
2406
|
.option("--timeout <seconds>", "How long to wait for each package's apply to finish (default: 120)")
|
|
1756
2407
|
.option("--json", "Output as JSON")
|
|
@@ -1775,10 +2426,113 @@ market
|
|
|
1775
2426
|
const { marketInstalled } = await import("./commands/market.js");
|
|
1776
2427
|
await marketInstalled(opts);
|
|
1777
2428
|
});
|
|
2429
|
+
market
|
|
2430
|
+
.command("workspaces")
|
|
2431
|
+
.description("List your workspaces with their template-attachment status — find the one that isn't attached yet (pure read)")
|
|
2432
|
+
.option("--unattached", "Only show workspaces that need attention (unattached or missing a version stamp)")
|
|
2433
|
+
.option("--json", "Output as JSON")
|
|
2434
|
+
.action(async (_opts, cmd) => {
|
|
2435
|
+
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
2436
|
+
const opts = cmd.optsWithGlobals();
|
|
2437
|
+
const { marketWorkspaces } = await import("./commands/market.js");
|
|
2438
|
+
await marketWorkspaces(opts);
|
|
2439
|
+
});
|
|
2440
|
+
market
|
|
2441
|
+
.command("attach <workspaceId>")
|
|
2442
|
+
.description("Reconcile a marketplace template onto an existing workspace + version-stamp it — how you relink a workspace installed before the marketplace")
|
|
2443
|
+
.option("--slug <slug>", "Template to attach (inferred from the workspace's existing attachment or domain when omitted)")
|
|
2444
|
+
.option("--project <id>", "Optionally tag the reconciled entities to a project")
|
|
2445
|
+
.option("--timeout <seconds>", "How long to wait for the apply to finish (default: 120)")
|
|
2446
|
+
.option("--json", "Output as JSON")
|
|
2447
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2448
|
+
.option("--api-key <key>", "API key override")
|
|
2449
|
+
.action(async (workspaceId, _opts, cmd) => {
|
|
2450
|
+
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
2451
|
+
const opts = cmd.optsWithGlobals();
|
|
2452
|
+
const { marketAttach } = await import("./commands/market.js");
|
|
2453
|
+
await marketAttach(workspaceId, opts);
|
|
2454
|
+
});
|
|
2455
|
+
// ── `synap templates` — the ONE home for workspace ↔ template health ─────────
|
|
2456
|
+
// Consolidates `market update`/`workspaces`/`installed`: one grouped, action-
|
|
2457
|
+
// ranked view where an UNATTACHED workspace is visible (it wasn't in `update`),
|
|
2458
|
+
// with a suggested template and a one-word attach. The `market *` subcommands
|
|
2459
|
+
// still work — this is the front door, not a breaking rename.
|
|
2460
|
+
const templates = program
|
|
2461
|
+
.command("templates")
|
|
2462
|
+
.description("See every workspace's template status (attached, drifted, or unattached) and connect them — the one home for template health")
|
|
2463
|
+
.option("--needs-attention", "Show only workspaces that need action (drifted / unstamped / unattached-with-suggestion)")
|
|
2464
|
+
.option("--json", "Output as JSON")
|
|
2465
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2466
|
+
.option("--api-key <key>", "API key override")
|
|
2467
|
+
.action(async (_opts, cmd) => {
|
|
2468
|
+
const opts = cmd.optsWithGlobals();
|
|
2469
|
+
const { marketTemplates } = await import("./commands/market.js");
|
|
2470
|
+
await marketTemplates(opts);
|
|
2471
|
+
});
|
|
2472
|
+
templates
|
|
2473
|
+
.command("attach <workspace>")
|
|
2474
|
+
.description("Connect a workspace (by NAME or id) to a template — suggests the right one so you don't guess a slug")
|
|
2475
|
+
.option("--slug <slug>", "Force a specific template instead of the suggestion")
|
|
2476
|
+
.option("--yes", "Accept a confident (domain-match) suggestion without prompting — for scripts")
|
|
2477
|
+
.option("--project <id>", "Optionally tag the reconciled entities to a project")
|
|
2478
|
+
.option("--timeout <seconds>", "How long to wait for the apply to finish (default: 120)")
|
|
2479
|
+
.option("--json", "Output as JSON")
|
|
2480
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2481
|
+
.option("--api-key <key>", "API key override")
|
|
2482
|
+
.action(async (workspace, _opts, cmd) => {
|
|
2483
|
+
const opts = cmd.optsWithGlobals();
|
|
2484
|
+
const { templatesAttach } = await import("./commands/market.js");
|
|
2485
|
+
await templatesAttach(workspace, opts);
|
|
2486
|
+
});
|
|
2487
|
+
templates
|
|
2488
|
+
.command("update [slugs...]")
|
|
2489
|
+
.alias("updates")
|
|
2490
|
+
.description("Apply template updates — 'update all' (or --yes) for every drifted workspace, or name specific slugs. Bare 'update' previews what's available.")
|
|
2491
|
+
.option("--yes", "Apply every available update without prompting, agreeing to every data change it lists")
|
|
2492
|
+
.option("--accept-data-changes <opKeys>", "Agree to exactly these data changes (comma-separated opKeys from the preview)")
|
|
2493
|
+
.option("--dry-run", "Preview only — never apply")
|
|
2494
|
+
.option("--timeout <seconds>", "How long to wait for each apply (default: 120)")
|
|
2495
|
+
.option("--json", "Output as JSON")
|
|
2496
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2497
|
+
.option("--api-key <key>", "API key override")
|
|
2498
|
+
.action(async (slugs, _opts, cmd) => {
|
|
2499
|
+
const opts = cmd.optsWithGlobals();
|
|
2500
|
+
// `update all` reads more naturally than `--yes` and is what people type —
|
|
2501
|
+
// treat the literal word "all" as "apply every available update". It is NOT
|
|
2502
|
+
// `--yes`: data changes still need the person's agreement (asked, or flagged).
|
|
2503
|
+
const wantsAll = !!slugs?.some((s) => s.toLowerCase() === "all");
|
|
2504
|
+
const explicit = (slugs ?? []).filter((s) => s.toLowerCase() !== "all");
|
|
2505
|
+
const { marketUpdate } = await import("./commands/market.js");
|
|
2506
|
+
await marketUpdate(explicit.length > 0 ? explicit : undefined, wantsAll ? { ...opts, all: true } : opts);
|
|
2507
|
+
});
|
|
2508
|
+
templates
|
|
2509
|
+
.command("retire <target>")
|
|
2510
|
+
.description("Move a retired template's space into its replacement (by template slug, workspace name or id). Shows the plan, asks, then moves through the pod — never deletes.")
|
|
2511
|
+
.option("--dry-run", "Show the plan only — move nothing")
|
|
2512
|
+
.option("--yes", "Move without asking (for scripts)")
|
|
2513
|
+
.option("--json", "Output as JSON")
|
|
2514
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2515
|
+
.option("--api-key <key>", "API key override")
|
|
2516
|
+
.action(async (target, _opts, cmd) => {
|
|
2517
|
+
const opts = cmd.optsWithGlobals();
|
|
2518
|
+
const { templatesRetire } = await import("./commands/templates-retire.js");
|
|
2519
|
+
await templatesRetire(target, opts);
|
|
2520
|
+
});
|
|
1778
2521
|
// ── Authoring loop: scaffold → validate → publish → unpublish ────────────────
|
|
1779
2522
|
market
|
|
1780
2523
|
.command("scaffold <slug>")
|
|
1781
2524
|
.description("Write a minimal valid <slug>.template.yaml to edit in place (refuses to overwrite)")
|
|
2525
|
+
// This list MUST equal `SCAFFOLDABLE_KINDS` (src/lib/kind-package.ts). It is
|
|
2526
|
+
// written out rather than imported because index.ts keeps its eager module
|
|
2527
|
+
// graph to commander + one lib — importing kind-package.ts here would pull
|
|
2528
|
+
// `yaml` into the startup path of every `synap` invocation. What keeps the two
|
|
2529
|
+
// honest is `test/scaffold-kind-help-parity.test.ts`, which source-scans both.
|
|
2530
|
+
//
|
|
2531
|
+
// It advertised `skill` — which `marketScaffold` refuses, since the CP package
|
|
2532
|
+
// schema has no standalone slot for one — and omitted `workflow`, which
|
|
2533
|
+
// `market validate` has always accepted. A help string that offers a refused
|
|
2534
|
+
// option and hides a working one is the documented-loop defect class.
|
|
2535
|
+
.option("--kind <kind>", "Scaffold a standalone package instead of a workspace template: cell, view, workflow, capability, skill")
|
|
1782
2536
|
.option("--json", "Output as JSON")
|
|
1783
2537
|
.action(async (slug, _opts, cmd) => {
|
|
1784
2538
|
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
@@ -1797,19 +2551,44 @@ market
|
|
|
1797
2551
|
await marketValidate(file, opts);
|
|
1798
2552
|
});
|
|
1799
2553
|
market
|
|
1800
|
-
.command("publish [
|
|
1801
|
-
.description("Validate then publish a template to the marketplace (private by default) — pass a file, or --from-
|
|
2554
|
+
.command("publish [targets...]")
|
|
2555
|
+
.description("Validate then publish a template (or a standalone cell/view package) to the marketplace (private by default) — pass a file, --from-workspace <id>, or --from-project <id>. Non-official publish never uses the synap-official vendor. Founder: --official [slug...] publishes the official catalog from the monorepo checkout (alias of `synap catalog publish --official --kind workspace`)")
|
|
2556
|
+
.option("--official", "Publish the OFFICIAL Synap catalog (all templates, or the named slugs) from the monorepo checkout — requires a `synap login` session that owns the synap-official vendor; previews and asks first")
|
|
2557
|
+
.option("--templates-dir <dir>", "With --official: path to the catalog package — synap-app/packages/catalog or workspace-templates (default: found by walking up from cwd)")
|
|
2558
|
+
.option("--dry-run", "With --official: preview what would change against the live catalog, publish nothing")
|
|
2559
|
+
.option("--yes", "With --official: skip the confirmation prompt")
|
|
1802
2560
|
.option("--public", "Publish as PUBLIC (default is private)")
|
|
1803
2561
|
.option("--private", "Publish as private (the default — stated explicitly)")
|
|
1804
2562
|
.option("--from-workspace <id>", "Serialize a live workspace into a template and publish it (instead of a file)")
|
|
2563
|
+
.option("--from-project <id>", "Serialize a live project's used workspaces into a suite package (tags: suite, require deps) and publish it")
|
|
2564
|
+
.option("--price <usd>", "Stamp pricingModel=one_time + priceUsd (dollars→cents). Settlement/Stripe is not this wave — columns only.")
|
|
1805
2565
|
.option("--json", "Output as JSON")
|
|
1806
|
-
.option("--pod-url <url>", "Pod URL override (for --from-workspace)")
|
|
1807
|
-
.option("--api-key <key>", "API key override (for --from-workspace)")
|
|
1808
|
-
|
|
2566
|
+
.option("--pod-url <url>", "Pod URL override (for --from-workspace / --from-project)")
|
|
2567
|
+
.option("--api-key <key>", "API key override (for --from-workspace / --from-project)")
|
|
2568
|
+
// Default ON for a cell package's `codeFile` resolution — see `cell build
|
|
2569
|
+
// --bundle-deps`'s doc comment for why: a published cell's `deps` map is
|
|
2570
|
+
// otherwise resolved through esm.sh at RUNTIME, so the artifact reviewed at
|
|
2571
|
+
// publish time isn't what actually executes. `synap cell build` invoked
|
|
2572
|
+
// directly is unaffected — its own default stays external-deps-via-esm.sh.
|
|
2573
|
+
.option("--no-bundle-deps", "Publish a cell's codeFile with external deps via esm.sh instead of bundling them in (default: bundled)")
|
|
2574
|
+
.action(async (targets, _opts, cmd) => {
|
|
1809
2575
|
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
1810
2576
|
const opts = cmd.optsWithGlobals();
|
|
2577
|
+
const args = targets ?? [];
|
|
2578
|
+
if (opts.official) {
|
|
2579
|
+
const { marketPublishOfficial } = await import("./commands/market-official.js");
|
|
2580
|
+
process.exitCode = await marketPublishOfficial(args, opts);
|
|
2581
|
+
return;
|
|
2582
|
+
}
|
|
2583
|
+
const { nonOfficialUsageError } = await import("./commands/market-official.js");
|
|
2584
|
+
const usage = nonOfficialUsageError(args, opts);
|
|
2585
|
+
if (usage) {
|
|
2586
|
+
console.error(` ✗ ${usage}`);
|
|
2587
|
+
process.exitCode = 2;
|
|
2588
|
+
return;
|
|
2589
|
+
}
|
|
1811
2590
|
const { marketPublish } = await import("./commands/market-authoring.js");
|
|
1812
|
-
await marketPublish(
|
|
2591
|
+
await marketPublish(args[0], opts);
|
|
1813
2592
|
});
|
|
1814
2593
|
market
|
|
1815
2594
|
.command("unpublish <slug>")
|
|
@@ -1821,6 +2600,35 @@ market
|
|
|
1821
2600
|
const { marketUnpublish } = await import("./commands/market-authoring.js");
|
|
1822
2601
|
await marketUnpublish(slug, opts);
|
|
1823
2602
|
});
|
|
2603
|
+
// ─── catalog ──────────────────────────────────────────────────────────────────
|
|
2604
|
+
// The team's ONE door to the official catalog (every installable kind). Thin
|
|
2605
|
+
// wiring: `runCatalog` (commands/catalog.ts) calls the ONE catalog lib in the
|
|
2606
|
+
// monorepo checkout. `market publish --official` is its alias (kind workspace).
|
|
2607
|
+
const catalog = program
|
|
2608
|
+
.command("catalog")
|
|
2609
|
+
.description("Validate, diff and publish the OFFICIAL template catalog (workspaces, capabilities, skills, packs, automations) from the monorepo checkout");
|
|
2610
|
+
for (const verb of ["validate", "diff", "publish"]) {
|
|
2611
|
+
const sub = catalog
|
|
2612
|
+
.command(`${verb} [slugs...]`)
|
|
2613
|
+
.description(verb === "validate"
|
|
2614
|
+
? "Validate the catalog (per-kind schema, cross-kind refs, goal grammar, duplicates) — offline"
|
|
2615
|
+
: verb === "diff"
|
|
2616
|
+
? "Show what would change against the live control-plane catalog (new / changed / unchanged)"
|
|
2617
|
+
: "Validate, preview the diff, confirm, then publish to the control plane — founder only: --official + a `synap login` session that owns synap-official")
|
|
2618
|
+
.option("--kind <kind>", "Only this kind: workspace | capability | skill | pack | automation")
|
|
2619
|
+
.option("--catalog-dir <dir>", "Path to the catalog package (default: found by walking up from cwd)")
|
|
2620
|
+
.option("--json", "Output as JSON");
|
|
2621
|
+
if (verb === "publish") {
|
|
2622
|
+
sub
|
|
2623
|
+
.option("--official", "Publish as the synap-official vendor (required)")
|
|
2624
|
+
.option("--dry-run", "Preview the diff only — publish nothing")
|
|
2625
|
+
.option("--yes", "Skip the confirmation prompt");
|
|
2626
|
+
}
|
|
2627
|
+
sub.action(async (slugs, opts) => {
|
|
2628
|
+
const { runCatalog } = await import("./commands/catalog.js");
|
|
2629
|
+
process.exitCode = await runCatalog(verb, slugs ?? [], opts);
|
|
2630
|
+
});
|
|
2631
|
+
}
|
|
1824
2632
|
// ─── capability ───────────────────────────────────────────────────────────────
|
|
1825
2633
|
const capability = program
|
|
1826
2634
|
.command("capability")
|
|
@@ -1873,6 +2681,7 @@ capability
|
|
|
1873
2681
|
.command("connect [name]")
|
|
1874
2682
|
.description("Connect a service — omit the name to pick from connectable services")
|
|
1875
2683
|
.option("--workspace <id>", "Workspace context")
|
|
2684
|
+
.option("--reconnect", "Force a fresh sign-in even if a connection already exists — fixes an expired or revoked token")
|
|
1876
2685
|
.action(async (name, opts) => {
|
|
1877
2686
|
const { capabilityConnect } = await import("./commands/capability.js");
|
|
1878
2687
|
await capabilityConnect(name, opts);
|
|
@@ -1969,13 +2778,38 @@ capConnections
|
|
|
1969
2778
|
const { capabilityConnectionsRemove } = await import("./commands/cap-connections.js");
|
|
1970
2779
|
await capabilityConnectionsRemove(capability, connectionId, opts);
|
|
1971
2780
|
});
|
|
1972
|
-
|
|
2781
|
+
capability
|
|
2782
|
+
.command("sync-status [provider]")
|
|
2783
|
+
.description("Show sync status per provider × kind × connection (phase, counts, errors) — omit provider to see all")
|
|
2784
|
+
.option("--workspace <id>", "Workspace context")
|
|
2785
|
+
.option("--json", "Output as JSON")
|
|
2786
|
+
.action(async (provider, opts) => {
|
|
2787
|
+
const { capabilitySyncStatus } = await import("./commands/sync-status.js");
|
|
2788
|
+
await capabilitySyncStatus(provider, opts);
|
|
2789
|
+
});
|
|
2790
|
+
// ─── sync (thin alias root for `cap sync-status`) ──────────────────────────────
|
|
2791
|
+
const sync = program
|
|
2792
|
+
.command("sync")
|
|
2793
|
+
.description("Sync status for connected providers — see `cap sync-status`");
|
|
2794
|
+
sync
|
|
2795
|
+
.command("status [provider]")
|
|
2796
|
+
.description("Show sync status per provider × kind × connection (phase, counts, errors) — omit provider to see all. Alias of `synap cap sync-status`.")
|
|
2797
|
+
.option("--workspace <id>", "Workspace context")
|
|
2798
|
+
.option("--json", "Output as JSON")
|
|
2799
|
+
.action(async (provider, opts) => {
|
|
2800
|
+
const { capabilitySyncStatus } = await import("./commands/sync-status.js");
|
|
2801
|
+
await capabilitySyncStatus(provider, opts);
|
|
2802
|
+
});
|
|
2803
|
+
// ─── raycast (hidden power-user escape) ───────────────────────────────────────
|
|
2804
|
+
// Prefer Raycast AI on the pod's MCP server (`synap connect raycast`), where
|
|
2805
|
+
// capability verbs run through synap_run_capability. Script Commands are a
|
|
2806
|
+
// per-verb escape hatch.
|
|
1973
2807
|
const raycast = program
|
|
1974
|
-
.command("raycast")
|
|
1975
|
-
.description("
|
|
2808
|
+
.command("raycast", { hidden: true })
|
|
2809
|
+
.description("(hidden) Power-user escape: generate Raycast Script Commands per capability verb");
|
|
1976
2810
|
raycast
|
|
1977
2811
|
.command("generate")
|
|
1978
|
-
.description("
|
|
2812
|
+
.description("Power-user escape: emit a Script Command per enabled verb (Raycast AI uses the pod's MCP server)")
|
|
1979
2813
|
.option("--out <dir>", "Output directory (default: ~/.synap/raycast-commands)")
|
|
1980
2814
|
.option("--workspace <id>", "Workspace context")
|
|
1981
2815
|
.action(async (opts) => {
|
|
@@ -1985,7 +2819,7 @@ raycast
|
|
|
1985
2819
|
// ─── providers ───────────────────────────────────────────────────────────────
|
|
1986
2820
|
const providers = program
|
|
1987
2821
|
.command("providers")
|
|
1988
|
-
.description("
|
|
2822
|
+
.description("LLM providers on the pod (OpenAI/Anthropic/…) for local coding tools — not capability packs");
|
|
1989
2823
|
providers
|
|
1990
2824
|
.command("list", { isDefault: true })
|
|
1991
2825
|
.description("Show enabled AI providers and their models")
|
|
@@ -1998,14 +2832,36 @@ providers
|
|
|
1998
2832
|
});
|
|
1999
2833
|
providers
|
|
2000
2834
|
.command("pull")
|
|
2001
|
-
.description("Write pod
|
|
2835
|
+
.description("Write pod LLM credentials into opencode or aider, or print the OpenAI-compatible {pod}/v1 endpoint")
|
|
2002
2836
|
.option("--target <name>", "Target tool: opencode | aider")
|
|
2003
2837
|
.option("--pod-url <url>", "Pod URL override")
|
|
2004
2838
|
.option("--api-key <key>", "API key override")
|
|
2839
|
+
.option("--show-key", "With --target show: print the full API key (default: redacted)")
|
|
2005
2840
|
.action(async (opts) => {
|
|
2006
2841
|
const { providersPull } = await import("./commands/providers.js");
|
|
2007
2842
|
await providersPull(opts);
|
|
2008
2843
|
});
|
|
2844
|
+
providers
|
|
2845
|
+
.command("set-key <providerId>")
|
|
2846
|
+
.description("Store your own API key override for a provider (BYOI)")
|
|
2847
|
+
.option("--workspace <id>", "Workspace ID for workspace-scoped override")
|
|
2848
|
+
.option("--api-key <key>", "API key (prompted if omitted)")
|
|
2849
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2850
|
+
.option("--hub-api-key <key>", "Hub API key override")
|
|
2851
|
+
.action(async (opts) => {
|
|
2852
|
+
const { providersSetKey } = await import("./commands/providers.js");
|
|
2853
|
+
await providersSetKey({ ...opts, providerId: opts.providerId });
|
|
2854
|
+
});
|
|
2855
|
+
providers
|
|
2856
|
+
.command("list-keys")
|
|
2857
|
+
.description("List user/workspace-level provider key overrides")
|
|
2858
|
+
.option("--workspace <id>", "Workspace ID to check")
|
|
2859
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2860
|
+
.option("--hub-api-key <key>", "Hub API key override")
|
|
2861
|
+
.action(async (opts) => {
|
|
2862
|
+
const { providersListKeys } = await import("./commands/providers.js");
|
|
2863
|
+
await providersListKeys(opts);
|
|
2864
|
+
});
|
|
2009
2865
|
// ─── keys ────────────────────────────────────────────────────────────────────
|
|
2010
2866
|
const keys = program
|
|
2011
2867
|
.command("keys")
|
|
@@ -2013,9 +2869,10 @@ const keys = program
|
|
|
2013
2869
|
keys
|
|
2014
2870
|
.command("rotate")
|
|
2015
2871
|
.description("Rotate your CLI key to pick up the latest scope set")
|
|
2016
|
-
.
|
|
2872
|
+
.option("--show-key", "Print the new key in full if it could not be saved to the config")
|
|
2873
|
+
.action(async (opts) => {
|
|
2017
2874
|
const { keysRotate } = await import("./commands/keys.js");
|
|
2018
|
-
await keysRotate({});
|
|
2875
|
+
await keysRotate({ showKey: opts.showKey });
|
|
2019
2876
|
});
|
|
2020
2877
|
// Resolve a global `--pod <name>` before commander parses (it isn't registered
|
|
2021
2878
|
// per-command). Fails fast with a clear message on an unknown profile name.
|