@synap-core/cli 1.10.0 → 1.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -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 +33 -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 +523 -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 +80 -35
- package/dist/commands/automation.js.map +1 -1
- package/dist/commands/bridge-setup.d.ts +14 -1
- package/dist/commands/bridge-setup.js +392 -128
- 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 +2 -0
- package/dist/commands/capability.js +297 -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 +3 -14
- package/dist/commands/centrality.js.map +1 -1
- package/dist/commands/connect.d.ts +38 -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 +9 -2
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/data-extra.d.ts +34 -0
- package/dist/commands/data-extra.js +198 -25
- package/dist/commands/data-extra.js.map +1 -1
- package/dist/commands/data.d.ts +120 -2
- package/dist/commands/data.js +307 -24
- package/dist/commands/data.js.map +1 -1
- package/dist/commands/diagnose.d.ts +66 -4
- package/dist/commands/diagnose.js +329 -29
- package/dist/commands/diagnose.js.map +1 -1
- package/dist/commands/digest.js +2 -1
- package/dist/commands/digest.js.map +1 -1
- package/dist/commands/doc.d.ts +25 -4
- package/dist/commands/doc.js +100 -18
- package/dist/commands/doc.js.map +1 -1
- package/dist/commands/doctor.d.ts +130 -0
- package/dist/commands/doctor.js +814 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/events.js +3 -1
- package/dist/commands/events.js.map +1 -1
- package/dist/commands/explain.js +5 -5
- package/dist/commands/explain.js.map +1 -1
- package/dist/commands/graph.js +5 -3
- package/dist/commands/graph.js.map +1 -1
- package/dist/commands/import.d.ts +368 -13
- package/dist/commands/import.js +1096 -55
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/init.d.ts +20 -9
- package/dist/commands/init.js +433 -973
- 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 +28 -6
- package/dist/commands/knowledge.js +358 -73
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/launch.js +2 -2
- package/dist/commands/launch.js.map +1 -1
- package/dist/commands/lens.d.ts +37 -1
- package/dist/commands/lens.js +193 -72
- package/dist/commands/lens.js.map +1 -1
- package/dist/commands/market-authoring.d.ts +72 -0
- package/dist/commands/market-authoring.js +566 -0
- package/dist/commands/market-authoring.js.map +1 -0
- 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 +419 -20
- package/dist/commands/market.js +2124 -193
- package/dist/commands/market.js.map +1 -1
- package/dist/commands/mcp.d.ts +70 -13
- package/dist/commands/mcp.js +308 -40
- package/dist/commands/mcp.js.map +1 -1
- 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 +162 -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 +19 -0
- package/dist/commands/pods.js +220 -85
- package/dist/commands/pods.js.map +1 -1
- package/dist/commands/proposals-actions.d.ts +62 -0
- package/dist/commands/proposals-actions.js +146 -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 +577 -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-wait.d.ts +111 -0
- package/dist/commands/session-wait.js +209 -0
- package/dist/commands/session-wait.js.map +1 -0
- package/dist/commands/sessions.d.ts +52 -0
- package/dist/commands/sessions.js +479 -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.js +19 -1
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/status.d.ts +1 -4
- package/dist/commands/status.js +5 -34
- 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 +51 -0
- package/dist/commands/tracks.js +291 -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 +68 -0
- package/dist/commands/upload.js +257 -0
- package/dist/commands/upload.js.map +1 -0
- 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 +23 -3
- package/dist/commands/whoami.js +169 -23
- package/dist/commands/whoami.js.map +1 -1
- package/dist/commands/worker.d.ts +122 -0
- package/dist/commands/worker.js +435 -0
- package/dist/commands/worker.js.map +1 -0
- package/dist/commands/worker.test.d.ts +1 -0
- package/dist/commands/worker.test.js +116 -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 +1009 -171
- 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 +138 -0
- package/dist/lib/agent-door.js +426 -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 +14 -9
- package/dist/lib/auth.js +44 -61
- 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/capture-lane.d.ts +6 -5
- package/dist/lib/capture-lane.js +11 -8
- package/dist/lib/capture-lane.js.map +1 -1
- package/dist/lib/capture-structure.d.ts +342 -0
- package/dist/lib/capture-structure.js +295 -0
- package/dist/lib/capture-structure.js.map +1 -0
- 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/conversation-headers.d.ts +18 -0
- package/dist/lib/conversation-headers.js +32 -0
- package/dist/lib/conversation-headers.js.map +1 -0
- package/dist/lib/cp-packages.d.ts +216 -4
- package/dist/lib/cp-packages.js +414 -11
- package/dist/lib/cp-packages.js.map +1 -1
- package/dist/lib/credential-class.d.ts +117 -0
- package/dist/lib/credential-class.js +116 -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/hub-client.d.ts +43 -9
- package/dist/lib/hub-client.js +429 -65
- package/dist/lib/hub-client.js.map +1 -1
- package/dist/lib/id.d.ts +23 -0
- package/dist/lib/id.js +35 -0
- package/dist/lib/id.js.map +1 -0
- 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 +16 -0
- package/dist/lib/init-handoff.js +19 -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 +66 -0
- package/dist/lib/key-source.js +106 -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 +24 -0
- package/dist/lib/knowledge-title.js +46 -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 +42 -0
- package/dist/lib/mcp-bridge.js +147 -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 +90 -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/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-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 +119 -115
- package/dist/lib/pod.js +206 -412
- 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/review-credential.d.ts +119 -0
- package/dist/lib/review-credential.js +147 -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-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 +134 -10
- package/dist/lib/targets.js +962 -258
- package/dist/lib/targets.js.map +1 -1
- package/dist/lib/template-file.d.ts +78 -0
- package/dist/lib/template-file.js +140 -0
- package/dist/lib/template-file.js.map +1 -0
- 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/utils/logger.js +5 -2
- package/dist/utils/logger.js.map +1 -1
- package/package.json +25 -18
- package/skills/README.md +12 -10
- package/skills/agent-os/SKILL.md +220 -99
- package/skills/manifest.json +2 -2
- package/skills/onboard/SKILL.md +61 -25
- package/skills/synap/README.md +5 -8
- package/skills/synap/SKILL.md +1185 -301
- 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 +54 -151
- package/skills/synap/cli-operations.md +24 -18
- package/skills/synap/common-mistakes.md +1 -0
- package/skills/synap/concepts.md +28 -0
- package/skills/synap/content-os.md +92 -0
- package/skills/synap/creative-loop.md +15 -10
- package/skills/synap/crm.md +21 -52
- package/skills/synap/digesting-a-channel.md +25 -0
- package/skills/synap/document-embeds.md +141 -47
- package/skills/synap/escalation-ladder.md +20 -10
- package/skills/synap/focus-sessions.md +47 -21
- package/skills/synap/from-intent.md +142 -0
- package/skills/synap/governance-rules.md +4 -4
- 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 +33 -15
- package/skills/synap/linking.md +41 -40
- package/skills/synap/mcp-remote-servers.md +64 -0
- package/skills/synap/mental-model.md +24 -22
- package/skills/synap/multi-entity-capture.md +6 -4
- package/skills/synap/operating-mode-rules.md +1 -1
- package/skills/synap/processes.md +118 -0
- package/skills/synap/quick-reference.md +5 -1
- 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 +96 -0
- package/skills/synap/worked-examples.md +21 -1
- package/skills/synap/workspace-design.md +14 -10
- package/skills/synap/writes.md +165 -35
- package/skills/synap/writing-titles.md +63 -0
- package/skills/synap-app/SKILL.md +319 -0
- package/skills/synap-app/_order.txt +5 -0
- package/skills/synap-app/_skill.yaml +20 -0
- package/skills/synap-app/creating-the-base-app.md +64 -0
- package/skills/synap-app/governance.md +42 -0
- package/skills/synap-app/install-commands.md +55 -0
- package/skills/synap-app/overview.md +50 -0
- package/skills/synap-app/using-the-sdk.md +73 -0
- 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 +625 -0
- package/skills/synap-market/_order.txt +5 -0
- package/skills/synap-market/_skill.yaml +24 -0
- package/skills/synap-market/author-and-publish.md +212 -0
- package/skills/synap-market/discover-and-fetch.md +59 -0
- package/skills/synap-market/governance-and-catalog.md +63 -0
- package/skills/synap-market/install.md +133 -0
- package/skills/synap-market/overview.md +119 -0
- 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/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/dist/lib/browser-auth.d.ts +0 -35
- package/dist/lib/browser-auth.js +0 -170
- package/dist/lib/browser-auth.js.map +0 -1
- package/dist/lib/openclaw.d.ts +0 -32
- package/dist/lib/openclaw.js +0 -164
- package/dist/lib/openclaw.js.map +0 -1
- package/dist/lib/seed.d.ts +0 -13
- package/dist/lib/seed.js +0 -135
- package/dist/lib/seed.js.map +0 -1
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
|
-
.option("--
|
|
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
|
+
.option("--with-mcp", "Raycast only: also install the full 56-tool MCP server via mcp-remote (names overlap @synap)")
|
|
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
|
|
@@ -124,6 +150,15 @@ pods
|
|
|
124
150
|
const { podsUse } = await import("./commands/pods.js");
|
|
125
151
|
await podsUse(name, { surface: opts.surface, json: opts.json });
|
|
126
152
|
});
|
|
153
|
+
pods
|
|
154
|
+
.command("update <name> [url]")
|
|
155
|
+
.description("Change a saved pod's URL in place (verifies health + whether the key must be recreated)")
|
|
156
|
+
.option("--url <url>", "New pod URL (alternative to the positional arg)")
|
|
157
|
+
.option("--yes", "Non-interactive: skip prompts (won't recreate a rejected key)")
|
|
158
|
+
.action(async (name, url, opts) => {
|
|
159
|
+
const { podsUpdate } = await import("./commands/pods.js");
|
|
160
|
+
await podsUpdate(name, url, { url: opts.url, yes: opts.yes });
|
|
161
|
+
});
|
|
127
162
|
pods
|
|
128
163
|
.command("remove <name>")
|
|
129
164
|
.alias("rm")
|
|
@@ -147,6 +182,16 @@ program
|
|
|
147
182
|
const { status } = await import("./commands/status.js");
|
|
148
183
|
await status({ json: opts.json });
|
|
149
184
|
});
|
|
185
|
+
program
|
|
186
|
+
.command("doctor")
|
|
187
|
+
.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")
|
|
188
|
+
.option("--json", "Output as JSON")
|
|
189
|
+
.option("--fix", "Fix key problems: finish a pending approval, give this computer its own key, or rewrite stale copies — then verify over MCP")
|
|
190
|
+
.option("-v, --verbose", "Every check with its details, ids and addresses")
|
|
191
|
+
.action(async (opts) => {
|
|
192
|
+
const { doctor } = await import("./commands/doctor.js");
|
|
193
|
+
await doctor(opts);
|
|
194
|
+
});
|
|
150
195
|
program
|
|
151
196
|
.command("versions")
|
|
152
197
|
.description("Show LOCAL vs NPM vs CONTROL-PLANE vs POD version drift for workspace-templates, api-types, and capabilities")
|
|
@@ -157,10 +202,11 @@ program
|
|
|
157
202
|
});
|
|
158
203
|
program
|
|
159
204
|
.command("whoami")
|
|
160
|
-
.description("Show
|
|
161
|
-
.
|
|
205
|
+
.description("Show key owner vs EFFECTIVE user (+ isAgent), scopes/workspace, and flag env-vs-surface key divergence")
|
|
206
|
+
.option("--json", "Output as JSON")
|
|
207
|
+
.action(async (opts) => {
|
|
162
208
|
const { whoami } = await import("./commands/whoami.js");
|
|
163
|
-
await whoami();
|
|
209
|
+
await whoami(opts);
|
|
164
210
|
});
|
|
165
211
|
// Hidden: compact ANSI line for the Claude Code statusLine (reads stdin JSON).
|
|
166
212
|
program
|
|
@@ -173,59 +219,10 @@ program
|
|
|
173
219
|
});
|
|
174
220
|
program
|
|
175
221
|
.command("update")
|
|
176
|
-
.description("
|
|
177
|
-
.option("--server", "Also trigger a Dokploy redeploy of the control-plane")
|
|
178
|
-
.option("--all", "Trigger a Dokploy redeploy of all registered services")
|
|
179
|
-
.action(async (opts) => {
|
|
180
|
-
const { update } = await import("./commands/update.js");
|
|
181
|
-
await update(opts);
|
|
182
|
-
});
|
|
183
|
-
// ─── infra ────────────────────────────────────────────────────────────────────
|
|
184
|
-
const infra = program
|
|
185
|
-
.command("infra")
|
|
186
|
-
.description("Manage servers and deployments via Dokploy");
|
|
187
|
-
infra
|
|
188
|
-
.command("status", { isDefault: true })
|
|
189
|
-
.description("Overview: all servers and services status")
|
|
190
|
-
.action(async () => {
|
|
191
|
-
const { infraStatus } = await import("./commands/infra.js");
|
|
192
|
-
await infraStatus();
|
|
193
|
-
});
|
|
194
|
-
infra
|
|
195
|
-
.command("deploy <app>")
|
|
196
|
-
.description("Trigger a redeploy for a named service")
|
|
197
|
-
.action(async (app) => {
|
|
198
|
-
const { infraDeploy } = await import("./commands/infra.js");
|
|
199
|
-
await infraDeploy(app);
|
|
200
|
-
});
|
|
201
|
-
infra
|
|
202
|
-
.command("logs <app>")
|
|
203
|
-
.description("Tail logs for a service")
|
|
204
|
-
.option("-n, --lines <n>", "Number of log lines", "100")
|
|
205
|
-
.option("-f, --follow", "Follow log output")
|
|
206
|
-
.action(async (app, opts) => {
|
|
207
|
-
const { infraLogs } = await import("./commands/infra.js");
|
|
208
|
-
await infraLogs(app, { lines: opts.lines ? parseInt(opts.lines, 10) : 100, follow: opts.follow });
|
|
209
|
-
});
|
|
210
|
-
infra
|
|
211
|
-
.command("sync")
|
|
212
|
-
.description("Pull Dokploy state into Synap entities (server + deployment profiles)")
|
|
213
|
-
.option("--pod-url <url>", "Synap pod URL", process.env.SYNAP_POD_URL)
|
|
214
|
-
.option("--api-key <key>", "Hub Protocol API key", process.env.SYNAP_API_KEY)
|
|
215
|
-
.action(async (opts) => {
|
|
216
|
-
if (!opts.podUrl || !opts.apiKey) {
|
|
217
|
-
console.error(" --pod-url and --api-key are required (or set SYNAP_POD_URL / SYNAP_API_KEY)");
|
|
218
|
-
process.exit(1);
|
|
219
|
-
}
|
|
220
|
-
const { infraSync } = await import("./commands/infra.js");
|
|
221
|
-
await infraSync(opts.podUrl, opts.apiKey);
|
|
222
|
-
});
|
|
223
|
-
infra
|
|
224
|
-
.command("open")
|
|
225
|
-
.description("Open the Dokploy dashboard in your browser")
|
|
222
|
+
.description("Show how to update the CLI")
|
|
226
223
|
.action(async () => {
|
|
227
|
-
const {
|
|
228
|
-
|
|
224
|
+
const { update } = await import("./commands/update.js");
|
|
225
|
+
await update();
|
|
229
226
|
});
|
|
230
227
|
program
|
|
231
228
|
.command("switch [name]")
|
|
@@ -237,11 +234,31 @@ program
|
|
|
237
234
|
program
|
|
238
235
|
.command("connections")
|
|
239
236
|
.alias("conn")
|
|
240
|
-
.description("Show which pod each agent
|
|
237
|
+
.description("Show everything connected: which pod each agent points at, and which tools the pod has connected")
|
|
241
238
|
.action(async () => {
|
|
242
239
|
const { connections } = await import("./commands/connections.js");
|
|
243
240
|
await connections();
|
|
244
241
|
});
|
|
242
|
+
// ─── app ────────────────────────────────────────────────────────────────────
|
|
243
|
+
// The App Connect flow: a `synap.app.json` in your app repo → one command wires
|
|
244
|
+
// the app's key into its deploy target. See APP-CONNECT-SPEC §5.
|
|
245
|
+
const app = program
|
|
246
|
+
.command("app")
|
|
247
|
+
.description("Connect an app in this repo to your pod (synap.app.json)");
|
|
248
|
+
app
|
|
249
|
+
.command("init")
|
|
250
|
+
.description("Write synap.app.json (asks name, pod, permissions) and register the app")
|
|
251
|
+
.action(async () => {
|
|
252
|
+
const { appInitCommand } = await import("./commands/app.js");
|
|
253
|
+
await appInitCommand();
|
|
254
|
+
});
|
|
255
|
+
app
|
|
256
|
+
.command("connect")
|
|
257
|
+
.description("Request the app's access, await approval, then write its key into the deploy target")
|
|
258
|
+
.action(async () => {
|
|
259
|
+
const { appConnectCommand } = await import("./commands/app.js");
|
|
260
|
+
await appConnectCommand();
|
|
261
|
+
});
|
|
245
262
|
// ─── mcp ────────────────────────────────────────────────────────────────────
|
|
246
263
|
// The MCP front door: point any AI client at the pod's /mcp server.
|
|
247
264
|
const mcp = program
|
|
@@ -271,13 +288,67 @@ mcp
|
|
|
271
288
|
const { mcpVerify } = await import("./commands/mcp.js");
|
|
272
289
|
await mcpVerify(opts);
|
|
273
290
|
});
|
|
291
|
+
mcp
|
|
292
|
+
.command("bridge")
|
|
293
|
+
.description("Stdio MCP server for Claude Code: forwards to the pod and names the conversation (spawned by Claude Code, not run by hand)")
|
|
294
|
+
.option("--url <url>", "The pod MCP URL to forward to")
|
|
295
|
+
.action(async (opts) => {
|
|
296
|
+
const { mcpBridge } = await import("./commands/mcp.js");
|
|
297
|
+
await mcpBridge(opts);
|
|
298
|
+
});
|
|
299
|
+
mcp
|
|
300
|
+
.command("use-bridge")
|
|
301
|
+
.description("Connect Claude Code through the stdio bridge, so work can be traced to and reopened in its conversation")
|
|
302
|
+
.option("--off", "Switch back to the direct http connection")
|
|
303
|
+
.action(async (opts) => {
|
|
304
|
+
const { mcpUseBridge } = await import("./commands/mcp.js");
|
|
305
|
+
await mcpUseBridge(opts);
|
|
306
|
+
});
|
|
274
307
|
mcp
|
|
275
308
|
.command("connect [client]")
|
|
276
|
-
.description("Write the MCP config for a file-configurable client (Claude Code, Cursor, Desktop, …) — alias of `synap
|
|
309
|
+
.description("Write the MCP config for a file-configurable client (Claude Code, Cursor, Desktop, ChatGPT, …) — alias of `synap agents add <client>`")
|
|
277
310
|
.option("--name <name>", "Pod profile to connect")
|
|
278
311
|
.action(async (client, opts) => {
|
|
279
312
|
const { connect } = await import("./commands/connect.js");
|
|
280
|
-
await connect(
|
|
313
|
+
await connect(client, { name: opts.name });
|
|
314
|
+
});
|
|
315
|
+
mcp
|
|
316
|
+
.command("connect-chatgpt")
|
|
317
|
+
.description("Connect ChatGPT (web) to Synap — API-key connector to your pod")
|
|
318
|
+
.option("--name <name>", "Pod profile to connect")
|
|
319
|
+
.action(async (opts) => {
|
|
320
|
+
const { connect } = await import("./commands/connect.js");
|
|
321
|
+
await connect("chatgpt", { name: opts.name });
|
|
322
|
+
});
|
|
323
|
+
mcp
|
|
324
|
+
.command("connect-chatgpt-oauth")
|
|
325
|
+
.description("Connect ChatGPT (web) via Control Plane OAuth — multi-pod, no key to paste")
|
|
326
|
+
.option("--name <name>", "Pod profile to connect")
|
|
327
|
+
.action(async (opts) => {
|
|
328
|
+
const { connect } = await import("./commands/connect.js");
|
|
329
|
+
await connect("chatgpt-oauth", { name: opts.name });
|
|
330
|
+
});
|
|
331
|
+
mcp
|
|
332
|
+
.command("connect-claude")
|
|
333
|
+
.description("Print the claude.ai (web) OAuth connection steps — paste a URL, approve in the browser, done")
|
|
334
|
+
.option("--cp-url <url>", "Control-plane origin override (default: derived from the pod host)")
|
|
335
|
+
.option("--json", "Output as JSON")
|
|
336
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
337
|
+
.option("--api-key <key>", "API key override")
|
|
338
|
+
.action(async (opts) => {
|
|
339
|
+
const { mcpConnectClaudeWeb } = await import("./commands/mcp.js");
|
|
340
|
+
await mcpConnectClaudeWeb(opts);
|
|
341
|
+
});
|
|
342
|
+
mcp
|
|
343
|
+
.command("ui-setup <client>")
|
|
344
|
+
.description("Print the exact form fields to fill in the client's MCP/Connector UI (ChatGPT, Codex, Cursor, etc.)")
|
|
345
|
+
.option("--name <name>", "Pod profile to use (default: active)")
|
|
346
|
+
.option("--workspace <id>", "Scope to a specific workspace")
|
|
347
|
+
.option("--project <id>", "Focus the agent on a project")
|
|
348
|
+
.option("--json", "Output as JSON")
|
|
349
|
+
.action(async (client, opts) => {
|
|
350
|
+
const { mcpUiSetup } = await import("./commands/mcp.js");
|
|
351
|
+
await mcpUiSetup(client, opts);
|
|
281
352
|
});
|
|
282
353
|
program
|
|
283
354
|
.command("login")
|
|
@@ -295,11 +366,9 @@ program
|
|
|
295
366
|
}
|
|
296
367
|
const profiles = listPodProfiles();
|
|
297
368
|
if (profiles.length === 0) {
|
|
298
|
-
// No pod saved
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
const { podsAdd } = await import("./commands/pods.js");
|
|
302
|
-
await podsAdd();
|
|
369
|
+
// No pod saved: sign in to the account first, it finds the pods.
|
|
370
|
+
const { podsFirstLogin } = await import("./commands/pods.js");
|
|
371
|
+
await podsFirstLogin();
|
|
303
372
|
return;
|
|
304
373
|
}
|
|
305
374
|
// Already have pods — show status and offer reconnect if any are unreachable
|
|
@@ -338,8 +407,23 @@ program
|
|
|
338
407
|
console.log(` ${active}${chalk.bold(p.name.padEnd(14))} ${status} ${chalk.dim(p.config.podUrl)}`);
|
|
339
408
|
}
|
|
340
409
|
console.log();
|
|
410
|
+
// A computer key (device flow) that expires within 7 days, or has: connect
|
|
411
|
+
// this computer again now — the pod offers the same computer, so its
|
|
412
|
+
// agents, history and rules are kept. Never without a person to approve.
|
|
413
|
+
const { computerKeyNeedsRenewal, connectThisComputer } = await import("./lib/device-connect.js");
|
|
414
|
+
const renewed = new Set();
|
|
415
|
+
for (const p of checks.filter((c) => c.healthy && computerKeyNeedsRenewal(c.config))) {
|
|
416
|
+
const when = `this computer's key ${p.keyValid ? "expires" : "expired"} ${p.config.keyExpiresAt}`;
|
|
417
|
+
if (!process.stdin.isTTY) {
|
|
418
|
+
console.log(chalk.yellow(` ${p.name}: ${when}. Run synap login in a terminal to renew it.`));
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
console.log(chalk.yellow(` ${p.name}: ${when}. Renewing it.`));
|
|
422
|
+
if (await connectThisComputer(p.config.podUrl, { name: p.name }))
|
|
423
|
+
renewed.add(p.name);
|
|
424
|
+
}
|
|
341
425
|
// Anything that won't authenticate — unreachable OR a revoked/expired key.
|
|
342
|
-
const needsReconnect = checks.filter((p) => !p.healthy || !p.keyValid);
|
|
426
|
+
const needsReconnect = checks.filter((p) => !renewed.has(p.name) && (!p.healthy || !p.keyValid));
|
|
343
427
|
if (needsReconnect.length > 0) {
|
|
344
428
|
console.log(chalk.yellow(` ${needsReconnect.length} pod(s) need re-authentication. Refresh credentials:`));
|
|
345
429
|
for (const p of needsReconnect) {
|
|
@@ -396,6 +480,7 @@ program
|
|
|
396
480
|
.description("Show a lightweight lens map: who you are, your projects (companies/initiatives), and workspaces (operational domains)")
|
|
397
481
|
.option("--json", "Output as JSON")
|
|
398
482
|
.option("--details", "Include per-workspace profiles + entity counts (heavier)")
|
|
483
|
+
.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")
|
|
399
484
|
.option("--pod-url <url>", "Pod URL override")
|
|
400
485
|
.option("--api-key <key>", "API key override")
|
|
401
486
|
.action(async (opts) => {
|
|
@@ -421,9 +506,9 @@ program
|
|
|
421
506
|
// See what an AI did across flows: the unified run feed, or one run's activity
|
|
422
507
|
// timeline (for a capture: WHY a facet/entity dropped, with a fixHint).
|
|
423
508
|
program
|
|
424
|
-
.command("diagnose [
|
|
425
|
-
.description("See what an AI did — the run feed, or one run's
|
|
426
|
-
.option("--flow <automation|playbook|capture|session>", "Restrict the feed, or the run
|
|
509
|
+
.command("diagnose [run]")
|
|
510
|
+
.description("See what an AI did — the run feed, or one run's nodes (by id or flow name)")
|
|
511
|
+
.option("--flow <automation|playbook|capture|capability|session|chat>", "Restrict the feed, or narrow the run lookup to one flow")
|
|
427
512
|
.option("--flow-id <id>", "Restrict the feed to one flow's runs (automationId / playbookId)")
|
|
428
513
|
.option("--limit <n>", "Max runs in the feed")
|
|
429
514
|
.option("--json", "Output raw JSON")
|
|
@@ -436,7 +521,9 @@ program
|
|
|
436
521
|
// ─── use ──────────────────────────────────────────────────────────────────────
|
|
437
522
|
program
|
|
438
523
|
.command("use <workspace>")
|
|
439
|
-
.description("Set the active workspace (by ID or name) —
|
|
524
|
+
.description("Set the active workspace (by ID or name) — short form of `synap workspace use`. Default scope: this directory")
|
|
525
|
+
.option("--session", "Ephemeral: scope only this Claude Code session, don't persist")
|
|
526
|
+
.option("--global", "Durable machine-wide default (~/.synap/config.json) instead of this directory's .synap/lens.json")
|
|
440
527
|
.option("--json", "Output as JSON")
|
|
441
528
|
.option("--pod-url <url>", "Pod URL override")
|
|
442
529
|
.option("--api-key <key>", "API key override")
|
|
@@ -447,7 +534,7 @@ program
|
|
|
447
534
|
// ─── project / lens (per-Claude-session scoping) ──────────────────────────────
|
|
448
535
|
const project = program
|
|
449
536
|
.command("project")
|
|
450
|
-
.description("Manage + focus the
|
|
537
|
+
.description("Manage + focus the project lens (a commitment, spanning workspaces): list, new, use, clear");
|
|
451
538
|
project
|
|
452
539
|
.command("list", { isDefault: true })
|
|
453
540
|
.description("List projects on the active pod, with the pinned one marked (bare `synap project` runs this)")
|
|
@@ -460,7 +547,7 @@ project
|
|
|
460
547
|
});
|
|
461
548
|
project
|
|
462
549
|
.command("new <name>")
|
|
463
|
-
.description("Create a project (a
|
|
550
|
+
.description("Create a project (a commitment you are driving, with whom) on the active pod, then guide you to pin + add to it")
|
|
464
551
|
.option("--description <text>", "Optional one-line description")
|
|
465
552
|
.option("--json", "Output as JSON (incl. nextSteps for agents)")
|
|
466
553
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -473,6 +560,7 @@ project
|
|
|
473
560
|
.command("use <ref>")
|
|
474
561
|
.description("Pin the active project (durable, like `synap use <workspace>`). Ref = uuid, slug, or <pod>/<slug> — cross-pod refs switch the active pod too")
|
|
475
562
|
.option("--session", "Ephemeral: scope only this Claude Code session, don't persist (cross-pod refs refused)")
|
|
563
|
+
.option("--global", "Durable machine-wide default (~/.synap/config.json) instead of this directory's .synap/lens.json")
|
|
476
564
|
.option("--json", "Output as JSON")
|
|
477
565
|
.option("--pod-url <url>", "Pod URL override")
|
|
478
566
|
.option("--api-key <key>", "API key override")
|
|
@@ -503,8 +591,10 @@ project
|
|
|
503
591
|
});
|
|
504
592
|
program
|
|
505
593
|
.command("lens")
|
|
506
|
-
.description("Show
|
|
594
|
+
.description("Show the effective lens (workspace + project + focus session) and WHICH rung set each one")
|
|
507
595
|
.option("--json", "Output as JSON")
|
|
596
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
597
|
+
.option("--api-key <key>", "API key override")
|
|
508
598
|
.action(async (opts) => {
|
|
509
599
|
const { showLens } = await import("./commands/lens.js");
|
|
510
600
|
await showLens(opts);
|
|
@@ -514,11 +604,12 @@ program
|
|
|
514
604
|
// procedural (how-to docs), episodic (captures) — and returns a glass-box answer.
|
|
515
605
|
program
|
|
516
606
|
.command("ask <query>")
|
|
517
|
-
.description("Ask your pod anything —
|
|
607
|
+
.description("Ask your pod anything — returns a synthesized answer with its sources")
|
|
518
608
|
.option("--workspace <id>", "Scope to a specific workspace (omit for pod-wide)")
|
|
519
609
|
.option("--limit <n>", "Max results per substrate", "10")
|
|
520
610
|
.option("--json", "Output as JSON")
|
|
521
611
|
.option("--session", "Scope retrieval to the active session context")
|
|
612
|
+
.option("--raw", "Skip synthesis: show the raw per-substrate matches instead")
|
|
522
613
|
.option("--compare", "A/B diagnostic: show baseline vs Horizon rankers side-by-side (read-only, does not change the answer)")
|
|
523
614
|
.option("--pod-url <url>", "Pod URL override")
|
|
524
615
|
.option("--api-key <key>", "API key override")
|
|
@@ -527,21 +618,26 @@ program
|
|
|
527
618
|
await askKnowledge(query, opts);
|
|
528
619
|
});
|
|
529
620
|
// ─── capture ──────────────────────────────────────────────────────────────────
|
|
530
|
-
// Uses the active pod
|
|
531
|
-
//
|
|
621
|
+
// Uses the active pod from config. Work-lane knowledge does NOT default-pin
|
|
622
|
+
// the active workspace (omit workspaceId → server-derived / pod-wide preferred);
|
|
623
|
+
// pin only with --workspace or --team.
|
|
532
624
|
program
|
|
533
625
|
.command("capture [text]")
|
|
534
|
-
.description("Capture knowledge: smart `capture \"<free text>\"` (AI structures it)
|
|
535
|
-
.option("--type <type>", "
|
|
626
|
+
.description("Capture knowledge: smart `capture \"<free text>\"` (AI structures it). For canonical typed Knowledge, use `create entity --profile=knowledge --props='{\"knowledgeForm\":\"insight|caution\"}'`.")
|
|
627
|
+
.option("--type <type>", "Legacy compatibility typed mode (gotcha|lesson|decision|reference); new automation should use knowledgeForm")
|
|
536
628
|
.option("--claim <text>", "Typed mode: one-line assertion (required with --type)")
|
|
629
|
+
.option("--title <text>", "Typed mode: short name, 80 characters or less (default: the claim's first sentence, never cut)")
|
|
630
|
+
.option("--content <markdown>", "Typed mode: full Markdown explanation, stored as the linked Knowledge note")
|
|
537
631
|
.option("--why <text>", "Reasoning or context")
|
|
538
632
|
.option("--evidence <text>", "Supporting file path, URL, or code snippet")
|
|
539
633
|
.option("--tags <csv>", "Comma-separated tags e.g. repo:synap-backend,layer:migrations")
|
|
540
634
|
.option("--session", "Link captured knowledge to the active session")
|
|
541
|
-
.option("--
|
|
542
|
-
.option("--
|
|
543
|
-
.option("--
|
|
544
|
-
.option("--
|
|
635
|
+
.option("--pod-wide", "GLOBAL lane: pod-wide cross-cutting runbook (→ knowledge_keys), visible in every workspace")
|
|
636
|
+
.option("--global", "Alias for --pod-wide")
|
|
637
|
+
.option("--key <ns:slug>", "Stable key for a --pod-wide runbook (derived from --type + --claim if omitted)")
|
|
638
|
+
.option("--team", "Pin to the first product workspace (default: omit workspaceId — server-derived / pod-wide preferred for knowledge)")
|
|
639
|
+
.option("--workspace <id>", "Explicit workspace pin (otherwise workspaceId is omitted for knowledge)")
|
|
640
|
+
.option("--project <id|name>", "Pin the capture to a project (id or name) — overrides SYNAP_PROJECT_ID / the session lens")
|
|
545
641
|
.option("--yes", "Skip the y/N confirmation prompt (smart mode)")
|
|
546
642
|
.option("--json", "Output as JSON")
|
|
547
643
|
.action(async (text, opts) => {
|
|
@@ -553,10 +649,14 @@ program
|
|
|
553
649
|
// the SAME AI capture pipeline (/capture/structure → /capture/execute), so it
|
|
554
650
|
// inherits entity extraction, the relation graph, and workspace/project routing.
|
|
555
651
|
program
|
|
556
|
-
.command("import
|
|
652
|
+
.command("import [inputs...]")
|
|
557
653
|
.description("Import files, folders, or URLs into the pod (AI capture pipeline, or Superwhisper store-first)")
|
|
558
654
|
.option("--workspace <id|name>", "Override AI workspace routing")
|
|
559
655
|
.option("--project <id|name>", "Override AI project routing")
|
|
656
|
+
.option("--home-map <pairs>", "Multi-home path map: pathSubstring=workspaceNameOrId pairs " +
|
|
657
|
+
'(e.g. "Projects=Builder,Posts=Content OS"). Matched batch paths are ' +
|
|
658
|
+
"rewritten with the workspace name as the first segment so placement " +
|
|
659
|
+
"heuristics pin the right home. No product defaults.")
|
|
560
660
|
.option("--dry-run", "Preview only — do not write")
|
|
561
661
|
.option("--yes", "Skip confirmation / auto-confirm store-first")
|
|
562
662
|
.option("--session", "Link created entities to the active session")
|
|
@@ -565,14 +665,49 @@ program
|
|
|
565
665
|
.option("--api-key <key>", "API key override")
|
|
566
666
|
.option("--source <name>", "Adapter: superwhisper (paired meta.json+output.wav store-first)")
|
|
567
667
|
.option("--store-first", "Skip AI structure; store units as pod-wide notes (+ optional audio)")
|
|
668
|
+
.option("--keep-raw", "Keep the original file and link it to the created entity (default: extract, then discard the bytes)")
|
|
568
669
|
.option("--with-audio", "Upload WAV provenance (default on for --source superwhisper --store-first)")
|
|
569
670
|
.option("--no-with-audio", "Transcript-only (no WAV upload)")
|
|
570
671
|
.option("--limit <n>", "Max Superwhisper units to process", (v) => parseInt(v, 10))
|
|
571
672
|
.option("--concurrency <n>", "Parallel unit uploads (1–4)", (v) => parseInt(v, 10))
|
|
572
673
|
.option("--no-resume", "Ignore local import ledger (re-import all)")
|
|
674
|
+
.option("--job-status <jobId>", "Re-poll a background corpus import started by an earlier run (no waiting)")
|
|
573
675
|
.action(async (inputs, opts) => {
|
|
574
|
-
const
|
|
575
|
-
|
|
676
|
+
const mod = await import("./commands/import.js");
|
|
677
|
+
if (opts.jobStatus) {
|
|
678
|
+
await mod.importJobStatus(opts.jobStatus, opts);
|
|
679
|
+
return;
|
|
680
|
+
}
|
|
681
|
+
await mod.importData(inputs ?? [], opts);
|
|
682
|
+
});
|
|
683
|
+
// ─── upload ───────────────────────────────────────────────────────────────────
|
|
684
|
+
// Store a real file (arbitrary bytes) on the pod — the door an AI/CLI needs to
|
|
685
|
+
// persist an actual file, not just text. POSTs multipart to /api/hub/files,
|
|
686
|
+
// which mints a `file` entity for the bytes.
|
|
687
|
+
program
|
|
688
|
+
.command("upload <path>")
|
|
689
|
+
.description("Upload a file to the pod as an entity (>10MB goes direct to storage: video ≤500MB, audio ≤100MB, zip ≤200MB)")
|
|
690
|
+
.option("--workspace <id>", "Pin the entity to this workspace (explicit placement)")
|
|
691
|
+
.option("--profile <slug>", "Entity kind to create (default: file), e.g. brand-asset")
|
|
692
|
+
.option("--prop <key=value>", "Entity property (repeatable)", (v, acc = []) => [...acc, v])
|
|
693
|
+
.option("--attach <entityId>", "After upload, link the document to this entity (references relation)")
|
|
694
|
+
.option("--title <title>", "Title for the created document")
|
|
695
|
+
.option("--open", "Open in the Synap desktop app after upload")
|
|
696
|
+
.option("--json", "Output as JSON")
|
|
697
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
698
|
+
.option("--api-key <key>", "API key override")
|
|
699
|
+
.addHelpText("after", `
|
|
700
|
+
Examples:
|
|
701
|
+
synap upload ./report.pdf
|
|
702
|
+
synap upload ./logo.png --title "Brand logo" --workspace <id>
|
|
703
|
+
synap upload ./spec.pdf --attach <entityId>
|
|
704
|
+
synap upload ./logo.svg --profile brand-asset --prop variant=dark --workspace <id>
|
|
705
|
+
synap upload ./launch.mp4 --workspace <id>
|
|
706
|
+
synap upload ./report.pdf --open
|
|
707
|
+
`)
|
|
708
|
+
.action(async (path, opts) => {
|
|
709
|
+
const { uploadFile } = await import("./commands/upload.js");
|
|
710
|
+
await uploadFile(path, opts);
|
|
576
711
|
});
|
|
577
712
|
program
|
|
578
713
|
.command("subscribe")
|
|
@@ -628,7 +763,42 @@ program
|
|
|
628
763
|
// commands (capture, recall, search, …) inherit the active pod + workspace.
|
|
629
764
|
const workspace = program
|
|
630
765
|
.command("workspace")
|
|
631
|
-
.description("
|
|
766
|
+
.description("Manage + focus the workspace lens (an operational domain): list, use, clear");
|
|
767
|
+
// `workspace use|list|clear` mirror `project use|list|clear` so the two
|
|
768
|
+
// composable lenses read as siblings. ADDITIVE: the original short form
|
|
769
|
+
// `synap use <workspace>` and `synap list workspaces` are untouched and keep
|
|
770
|
+
// working exactly as before — these are aliases, not replacements.
|
|
771
|
+
workspace
|
|
772
|
+
.command("use <workspace>")
|
|
773
|
+
.description("Pin the active workspace by ID or name (durable, like `synap use <workspace>`). Default scope: this directory")
|
|
774
|
+
.option("--session", "Ephemeral: scope only this Claude Code session, don't persist")
|
|
775
|
+
.option("--global", "Durable machine-wide default (~/.synap/config.json) instead of this directory's .synap/lens.json")
|
|
776
|
+
.option("--json", "Output as JSON")
|
|
777
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
778
|
+
.option("--api-key <key>", "API key override")
|
|
779
|
+
.action(async (ws, opts) => {
|
|
780
|
+
const { useWorkspace } = await import("./commands/data.js");
|
|
781
|
+
await useWorkspace(ws, opts);
|
|
782
|
+
});
|
|
783
|
+
workspace
|
|
784
|
+
.command("list", { isDefault: true })
|
|
785
|
+
.description("List workspaces you belong to (bare `synap workspace` runs this)")
|
|
786
|
+
.option("--json", "Output as JSON")
|
|
787
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
788
|
+
.option("--api-key <key>", "API key override")
|
|
789
|
+
.action(async (opts) => {
|
|
790
|
+
const { listWorkspaces } = await import("./commands/data.js");
|
|
791
|
+
await listWorkspaces(opts);
|
|
792
|
+
});
|
|
793
|
+
workspace
|
|
794
|
+
.command("clear")
|
|
795
|
+
.description("Clear the active workspace focus (durable by default)")
|
|
796
|
+
.option("--session", "Ephemeral: clear only this Claude Code session's workspace")
|
|
797
|
+
.option("--json", "Output as JSON")
|
|
798
|
+
.action(async (opts) => {
|
|
799
|
+
const { clearWorkspace } = await import("./commands/data.js");
|
|
800
|
+
await clearWorkspace(opts);
|
|
801
|
+
});
|
|
632
802
|
workspace
|
|
633
803
|
.command("provision-agent")
|
|
634
804
|
.description("Provision an agent-owned workspace and set it as active (idempotent)")
|
|
@@ -652,6 +822,54 @@ workspace
|
|
|
652
822
|
const { workspacePurge } = await import("./commands/purge.js");
|
|
653
823
|
await workspacePurge(target, opts);
|
|
654
824
|
});
|
|
825
|
+
// R8a — governed lifecycle: an agent key gets a proposal, an owner key applies.
|
|
826
|
+
workspace
|
|
827
|
+
.command("archive <workspace>")
|
|
828
|
+
.description("Archive a workspace (hides it, pauses its workspace automations). Governed: agents propose")
|
|
829
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
830
|
+
.option("--json", "Output as JSON")
|
|
831
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
832
|
+
.option("--api-key <key>", "API key override")
|
|
833
|
+
.action(async (target, opts) => {
|
|
834
|
+
const { workspaceArchive } = await import("./commands/workspace-ops.js");
|
|
835
|
+
await workspaceArchive(target, opts);
|
|
836
|
+
});
|
|
837
|
+
workspace
|
|
838
|
+
.command("restore <workspace>")
|
|
839
|
+
.description("Restore an archived workspace (by id). Re-enables nothing; lists automations still paused")
|
|
840
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
841
|
+
.option("--json", "Output as JSON")
|
|
842
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
843
|
+
.option("--api-key <key>", "API key override")
|
|
844
|
+
.action(async (target, opts) => {
|
|
845
|
+
const { workspaceRestore } = await import("./commands/workspace-ops.js");
|
|
846
|
+
await workspaceRestore(target, opts);
|
|
847
|
+
});
|
|
848
|
+
workspace
|
|
849
|
+
.command("rename <workspace> <newName>")
|
|
850
|
+
.description("Rename a workspace. Governed: agents propose")
|
|
851
|
+
.option("--json", "Output as JSON")
|
|
852
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
853
|
+
.option("--api-key <key>", "API key override")
|
|
854
|
+
.action(async (target, newName, opts) => {
|
|
855
|
+
const { workspaceRename } = await import("./commands/workspace-ops.js");
|
|
856
|
+
await workspaceRename(target, newName, opts);
|
|
857
|
+
});
|
|
858
|
+
// R8a — `synap entity move`. (`get/create/set entity` stay under their verbs.)
|
|
859
|
+
program
|
|
860
|
+
.command("entity")
|
|
861
|
+
.description("Entity operations: move")
|
|
862
|
+
.command("move <entityIds...>")
|
|
863
|
+
.description("Move entities into another workspace. Governed per entity: moved / proposed / errors")
|
|
864
|
+
.requiredOption("--to <workspace>", "Destination workspace id or name")
|
|
865
|
+
.option("--reason <text>", "Why they belong there — shown to the reviewer")
|
|
866
|
+
.option("--json", "Output as JSON")
|
|
867
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
868
|
+
.option("--api-key <key>", "API key override")
|
|
869
|
+
.action(async (entityIds, opts) => {
|
|
870
|
+
const { entityMove } = await import("./commands/workspace-ops.js");
|
|
871
|
+
await entityMove(entityIds, opts);
|
|
872
|
+
});
|
|
655
873
|
// ─── list ─────────────────────────────────────────────────────────────────────
|
|
656
874
|
const list = program
|
|
657
875
|
.command("list")
|
|
@@ -765,8 +983,10 @@ const proposals = program
|
|
|
765
983
|
.description("Review and act on governance proposals");
|
|
766
984
|
proposals
|
|
767
985
|
.command("list", { isDefault: true })
|
|
768
|
-
.description("List
|
|
986
|
+
.description("List governance proposals (default: the pending queue)")
|
|
987
|
+
.option("--status <status>", "pending (default) | approved | auto_approved (what the agent already did) | rejected | expired (never decided) | all", "pending")
|
|
769
988
|
.option("--workspace <id>", "Scope to a specific workspace")
|
|
989
|
+
.option("--session <id>", "Scope to one focus session (the agent run that filed them)")
|
|
770
990
|
.option("--limit <n>", "Max results", "20")
|
|
771
991
|
.option("--json", "Output as JSON")
|
|
772
992
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -777,8 +997,11 @@ proposals
|
|
|
777
997
|
});
|
|
778
998
|
proposals
|
|
779
999
|
.command("approve <id>")
|
|
780
|
-
.description("Approve a pending proposal")
|
|
1000
|
+
.description("Approve a pending proposal (interactive only — requires a TTY and a typed confirmation)")
|
|
781
1001
|
.option("--reason <text>", "Optional approval note")
|
|
1002
|
+
.option("--verb <verb>", "Same-name choice: fill_empty | keep_existing | use_capture | separate")
|
|
1003
|
+
.option("--existing <uuid>", "Existing record id — required for fill_empty, keep_existing, and use_capture")
|
|
1004
|
+
.option("--yes", "Accepted for symmetry with other commands, but does NOT skip the typed confirmation — approval is always deliberate")
|
|
782
1005
|
.option("--json", "Output as JSON")
|
|
783
1006
|
.option("--pod-url <url>", "Pod URL override")
|
|
784
1007
|
.option("--api-key <key>", "API key override")
|
|
@@ -797,6 +1020,39 @@ proposals
|
|
|
797
1020
|
const { rejectProposal } = await import("./commands/proposals-actions.js");
|
|
798
1021
|
await rejectProposal(id, opts);
|
|
799
1022
|
});
|
|
1023
|
+
proposals
|
|
1024
|
+
.command("await <id>")
|
|
1025
|
+
.description("Block until a proposal is decided. Exit 0 approved · 1 rejected/expired/withdrawn · 2 timeout")
|
|
1026
|
+
.option("--timeout <duration>", "Give up after this long (e.g. 30m, 2h)", "30m")
|
|
1027
|
+
.option("--interval <duration>", "Delay between checks (e.g. 10s)", "10s")
|
|
1028
|
+
.option("--json", "Output the final status as JSON")
|
|
1029
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1030
|
+
.option("--api-key <key>", "API key override")
|
|
1031
|
+
.action(async (id, opts) => {
|
|
1032
|
+
const { awaitProposalCommand } = await import("./commands/proposals-await.js");
|
|
1033
|
+
await awaitProposalCommand(id, opts);
|
|
1034
|
+
});
|
|
1035
|
+
// ─── worker ───────────────────────────────────────────────────────────────────
|
|
1036
|
+
// Run Claude Code unattended on THIS machine for the sessions handed to an agent
|
|
1037
|
+
// (the session roster → orient handedToYou). See src/commands/worker.ts.
|
|
1038
|
+
program
|
|
1039
|
+
.command("worker")
|
|
1040
|
+
.description("Run Claude Code unattended here for the sessions handed to an agent")
|
|
1041
|
+
.requiredOption("--agent <name>", "The named agent this machine works as (its key comes from ~/.synap)")
|
|
1042
|
+
.option("--interval <dur>", "How often to check for handed sessions (e.g. 30s, 2m)", "30s")
|
|
1043
|
+
.option("--once", "Check once, run what is handed, wait for it, exit")
|
|
1044
|
+
.option("--cwd <dir>", "Where the launched Claude Code works (default ~/Documents/Code/synap)")
|
|
1045
|
+
.option("--max-parallel <n>", "Runs at the same time", "1")
|
|
1046
|
+
.option("--claude-bin <path>", "The claude binary", "claude")
|
|
1047
|
+
.option("--claude-config-dir <dir>", "CLAUDE_CONFIG_DIR for launched runs — picks which Claude subscription they use")
|
|
1048
|
+
.option("--mcp-server <name>", "Claude Code MCP server name for this pod (detected from ~/.claude.json by default)")
|
|
1049
|
+
.option("--allowed-tools <list>", "Comma-separated Claude tools allowed without asking (the pod MCP server is always added)")
|
|
1050
|
+
.option("--skip-permissions", "Launch with --dangerously-skip-permissions instead of an allow-list")
|
|
1051
|
+
.option("--dry-run", "Claim and log what would launch, without launching Claude")
|
|
1052
|
+
.action(async (opts) => {
|
|
1053
|
+
const { workerCommand } = await import("./commands/worker.js");
|
|
1054
|
+
await workerCommand(opts);
|
|
1055
|
+
});
|
|
800
1056
|
// ─── session ──────────────────────────────────────────────────────────────────
|
|
801
1057
|
// Focus sessions — goal-bound work rooms tracked on the pod.
|
|
802
1058
|
// AI agents: use start_session to begin, update_session to report progress,
|
|
@@ -810,7 +1066,14 @@ session
|
|
|
810
1066
|
.description("Start a new focus session and return its ID")
|
|
811
1067
|
.requiredOption("--goal <text>", "What this session is working toward")
|
|
812
1068
|
.option("--workspace <id>", "Workspace that owns the session")
|
|
1069
|
+
.option("--project <id>", "Project that owns the session (defaults to the active project lens; the pod accepts a workspace OR a project)")
|
|
813
1070
|
.option("--task-id <id>", "Link session to an existing task entity")
|
|
1071
|
+
.option("--track <id>", "Born inside a track (a project's lasting goal) — implies its project")
|
|
1072
|
+
.option("--template <id>", "Start from a playbook (seeds currentStage from its stages)")
|
|
1073
|
+
.option("--no-template", "Opt out of auto-matching a playbook — start ad-hoc")
|
|
1074
|
+
.option("--parent <id>", "Push from another session — records session --spawned_from--> session (the parent stays open)")
|
|
1075
|
+
.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")
|
|
1076
|
+
.option("--criteria <file.json>", "Path to a JSON file of binary acceptance criteria (SessionCriterion[])")
|
|
814
1077
|
.option("--json", "Output as JSON")
|
|
815
1078
|
.option("--pod-url <url>", "Pod URL override")
|
|
816
1079
|
.option("--api-key <key>", "API key override")
|
|
@@ -822,7 +1085,9 @@ session
|
|
|
822
1085
|
.command("list", { isDefault: true })
|
|
823
1086
|
.description("List focus sessions in the active workspace")
|
|
824
1087
|
.option("--workspace <id>", "Scope to a specific workspace")
|
|
1088
|
+
.option("--project <id>", "Scope to a project (its sessions across spaces)")
|
|
825
1089
|
.option("--status <status>", "Filter by status: active | paused | closed")
|
|
1090
|
+
.option("--kind <kind>", "Filter by population: work | run | receipt | all", "all")
|
|
826
1091
|
.option("--limit <n>", "Max results", "20")
|
|
827
1092
|
.option("--json", "Output as JSON")
|
|
828
1093
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -833,8 +1098,8 @@ session
|
|
|
833
1098
|
});
|
|
834
1099
|
session
|
|
835
1100
|
.command("get <id>")
|
|
836
|
-
.description("Show details for a specific focus session")
|
|
837
|
-
.option("--workspace <id>", "Workspace
|
|
1101
|
+
.description("Show details for a specific focus session (works for project-scoped sessions)")
|
|
1102
|
+
.option("--workspace <id>", "Workspace hint if the pod still requires it for GET")
|
|
838
1103
|
.option("--json", "Output as JSON")
|
|
839
1104
|
.option("--pod-url <url>", "Pod URL override")
|
|
840
1105
|
.option("--api-key <key>", "API key override")
|
|
@@ -844,10 +1109,14 @@ session
|
|
|
844
1109
|
});
|
|
845
1110
|
session
|
|
846
1111
|
.command("update <id>")
|
|
847
|
-
.description("Update progress
|
|
848
|
-
|
|
849
|
-
|
|
1112
|
+
.description("Update a focus session's progress, status, stage or goal")
|
|
1113
|
+
// NOT required: `workspaceId` is `.optional()` on the pod's UpdateBodySchema
|
|
1114
|
+
// and the session is addressed by <id>. Demanding it made an already-attached
|
|
1115
|
+
// or project-scoped session un-updatable without restating a known lens.
|
|
1116
|
+
.option("--workspace <id>", "Workspace that owns the session (optional; inferred from the active lens)")
|
|
1117
|
+
.option("--progress <0-100>", "Progress percentage — a whole number 0-100, not prose")
|
|
850
1118
|
.option("--status <status>", "New status: active | paused")
|
|
1119
|
+
.option("--stage <key>", "Advance the session's current stage (playbook stage key)")
|
|
851
1120
|
.option("--goal <text>", "Revised goal")
|
|
852
1121
|
.option("--json", "Output as JSON")
|
|
853
1122
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -858,10 +1127,16 @@ session
|
|
|
858
1127
|
});
|
|
859
1128
|
session
|
|
860
1129
|
.command("close <id>")
|
|
861
|
-
.description("
|
|
862
|
-
.
|
|
863
|
-
.option("--recap <text>", "Short summary of what was accomplished")
|
|
864
|
-
|
|
1130
|
+
.description("End a focus session (proposal pack) and optionally attach a recap")
|
|
1131
|
+
.option("--workspace <id>", "Workspace hint (optional; not required for complete)")
|
|
1132
|
+
.option("--recap <text>", "Short summary of what was accomplished (maps to summary)")
|
|
1133
|
+
// Deliberately NOT validated here, unlike --progress. A bad --progress
|
|
1134
|
+
// serialized to NaN and came back as an unreadable zod echo; a bad --as comes
|
|
1135
|
+
// back naming the three legal values, because the pod's enum derives from
|
|
1136
|
+
// TERMINAL_SESSION_STATUSES. Re-listing them here would be a second copy of
|
|
1137
|
+
// an enum this CLI cannot import — the hand-mirrored-vocabulary defect.
|
|
1138
|
+
.option("--as <status>", "How it ended: closed (default, finished) | cancelled (abandoned) | failed (could not complete)")
|
|
1139
|
+
.option("--json", "Output full pack (or close result) as JSON")
|
|
865
1140
|
.option("--pod-url <url>", "Pod URL override")
|
|
866
1141
|
.option("--api-key <key>", "API key override")
|
|
867
1142
|
.action(async (id, opts) => {
|
|
@@ -888,12 +1163,162 @@ session
|
|
|
888
1163
|
});
|
|
889
1164
|
session
|
|
890
1165
|
.command("current")
|
|
891
|
-
.description("Show the active session for this terminal (
|
|
1166
|
+
.description("Show the active session for this terminal (SYNAP_SESSION_ID, Claude-session lens, or .synap/lens.json)")
|
|
892
1167
|
.option("--json", "Output as JSON")
|
|
893
1168
|
.action(async (opts) => {
|
|
894
1169
|
const { sessionStatus } = await import("./commands/sessions.js");
|
|
895
1170
|
sessionStatus(opts);
|
|
896
1171
|
});
|
|
1172
|
+
session
|
|
1173
|
+
.command("evidence <key>")
|
|
1174
|
+
.description("Post your own pass/fail report for one evidence-checked acceptance criterion")
|
|
1175
|
+
.option("--session <id>", "Focus session ID (defaults to this terminal's active session)")
|
|
1176
|
+
.option("--passed", "The criterion is satisfied")
|
|
1177
|
+
.option("--failed", "The criterion is not satisfied")
|
|
1178
|
+
.option("--detail <text>", "Optional note explaining the verdict")
|
|
1179
|
+
.option("--json", "Output as JSON")
|
|
1180
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1181
|
+
.option("--api-key <key>", "API key override")
|
|
1182
|
+
.action(async (key, opts) => {
|
|
1183
|
+
const { evidenceSession } = await import("./commands/sessions.js");
|
|
1184
|
+
await evidenceSession(key, opts);
|
|
1185
|
+
});
|
|
1186
|
+
session
|
|
1187
|
+
.command("evaluate")
|
|
1188
|
+
.description("Run every pending acceptance-criterion check (evidence, capability, judge) and print the verdicts")
|
|
1189
|
+
.option("--session <id>", "Focus session ID (defaults to this terminal's active session)")
|
|
1190
|
+
.option("--json", "Output as JSON")
|
|
1191
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1192
|
+
.option("--api-key <key>", "API key override")
|
|
1193
|
+
.action(async (opts) => {
|
|
1194
|
+
const { evaluateSession } = await import("./commands/sessions.js");
|
|
1195
|
+
await evaluateSession(opts);
|
|
1196
|
+
});
|
|
1197
|
+
session
|
|
1198
|
+
.command("wait <sessionId>")
|
|
1199
|
+
.description("Block until the human replies in the session room, then print the reply. Exit 0 replied · 1 timeout · 2 failure (auth/network/broken read)")
|
|
1200
|
+
.option("--since <iso>", "Only answers strictly after this ISO timestamp (default: now — skips anything that predates this wait)")
|
|
1201
|
+
.option("--timeout <duration>", "Give up after this long (e.g. 30m, 2h)", "30m")
|
|
1202
|
+
.option("--interval <duration>", "Delay between checks (e.g. 10s)", "10s")
|
|
1203
|
+
.option("--limit <n>", "Max answers per page, 1-100", "20")
|
|
1204
|
+
.option("--json", "Output the reply(ies) — or the timeout — as JSON")
|
|
1205
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1206
|
+
.option("--api-key <key>", "API key override")
|
|
1207
|
+
.action(async (sessionId, opts) => {
|
|
1208
|
+
const { waitSessionCommand } = await import("./commands/session-wait.js");
|
|
1209
|
+
await waitSessionCommand(sessionId, opts);
|
|
1210
|
+
});
|
|
1211
|
+
// ─── playbook ─────────────────────────────────────────────────────────────────
|
|
1212
|
+
// Start a governed process in one step — the Hub door MCP synap_run_playbook
|
|
1213
|
+
// shares. A proposal ("queued for your review") is success.
|
|
1214
|
+
const playbookCmd = program
|
|
1215
|
+
.command("playbook")
|
|
1216
|
+
.description("Run playbooks — governed, reusable processes");
|
|
1217
|
+
playbookCmd
|
|
1218
|
+
.command("run <name-or-id>")
|
|
1219
|
+
.description("Run a playbook by name or id, optionally on a subject entity")
|
|
1220
|
+
.option("--subject <entityId>", "The entity the playbook runs on")
|
|
1221
|
+
.option("--param <key=value>", "Answer a declared param (repeatable; typed by the playbook)", collect, [])
|
|
1222
|
+
.option("--workspace <id>", "Write home for the run (defaults to the playbook's own workspace)")
|
|
1223
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1224
|
+
.option("--json", "Output as JSON")
|
|
1225
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1226
|
+
.option("--api-key <key>", "API key override")
|
|
1227
|
+
.action(async (ref, opts) => {
|
|
1228
|
+
const { runPlaybook } = await import("./commands/playbook.js");
|
|
1229
|
+
await runPlaybook(ref, opts);
|
|
1230
|
+
});
|
|
1231
|
+
// ─── track ────────────────────────────────────────────────────────────────────
|
|
1232
|
+
// A LASTING goal inside a project, worked in sessions (`session start --track`).
|
|
1233
|
+
// Legacy tracks also run a method with steps. Writes are governed —
|
|
1234
|
+
// "queued for your review" is success.
|
|
1235
|
+
const track = program
|
|
1236
|
+
.command("track")
|
|
1237
|
+
.description("Manage tracks — the lasting goals a project pursues");
|
|
1238
|
+
track
|
|
1239
|
+
.command("list")
|
|
1240
|
+
.description("List a project's tracks (defaults to the active project lens)")
|
|
1241
|
+
.option("--project <id>", "Project id (defaults to the active project lens)")
|
|
1242
|
+
.option("--all", "Include archived tracks")
|
|
1243
|
+
.option("--json", "Output as JSON")
|
|
1244
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1245
|
+
.option("--api-key <key>", "API key override")
|
|
1246
|
+
.action(async (opts) => {
|
|
1247
|
+
const { listTracks } = await import("./commands/tracks.js");
|
|
1248
|
+
await listTracks(opts);
|
|
1249
|
+
});
|
|
1250
|
+
track
|
|
1251
|
+
.command("show <id>")
|
|
1252
|
+
.description("Show one track: its steps and where it stands")
|
|
1253
|
+
.option("--json", "Output as JSON")
|
|
1254
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1255
|
+
.option("--api-key <key>", "API key override")
|
|
1256
|
+
.action(async (id, opts) => {
|
|
1257
|
+
const { showTrack } = await import("./commands/tracks.js");
|
|
1258
|
+
await showTrack(id, opts);
|
|
1259
|
+
});
|
|
1260
|
+
track
|
|
1261
|
+
.command("start")
|
|
1262
|
+
.description("Start a track — a lasting goal — on a project")
|
|
1263
|
+
.option("--name <name>", "The track's name (required without --playbook)")
|
|
1264
|
+
.option("--direction <text>", "Where it is heading, one line")
|
|
1265
|
+
.option("--playbook <id>", "Legacy: a track template (project-scoped playbook with steps)")
|
|
1266
|
+
.option("--project <id>", "Project id (defaults to the active project lens)")
|
|
1267
|
+
.option("--param <key=value>", "Answer a declared param (repeatable)", collect, [])
|
|
1268
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1269
|
+
.option("--json", "Output as JSON")
|
|
1270
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1271
|
+
.option("--api-key <key>", "API key override")
|
|
1272
|
+
.action(async (opts) => {
|
|
1273
|
+
const { startTrack } = await import("./commands/tracks.js");
|
|
1274
|
+
await startTrack(opts);
|
|
1275
|
+
});
|
|
1276
|
+
track
|
|
1277
|
+
.command("advance <id> <stage>")
|
|
1278
|
+
.description("Legacy (tracks with steps): move a track to a step; prints the session that step offers")
|
|
1279
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1280
|
+
.option("--json", "Output as JSON")
|
|
1281
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1282
|
+
.option("--api-key <key>", "API key override")
|
|
1283
|
+
.action(async (id, stage, opts) => {
|
|
1284
|
+
const { advanceTrack } = await import("./commands/tracks.js");
|
|
1285
|
+
await advanceTrack(id, stage, opts);
|
|
1286
|
+
});
|
|
1287
|
+
track
|
|
1288
|
+
.command("status <id> <status>")
|
|
1289
|
+
.description("Pause, resume or archive a track (active|paused|archived)")
|
|
1290
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1291
|
+
.option("--json", "Output as JSON")
|
|
1292
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1293
|
+
.option("--api-key <key>", "API key override")
|
|
1294
|
+
.action(async (id, status, opts) => {
|
|
1295
|
+
const { setTrackStatus } = await import("./commands/tracks.js");
|
|
1296
|
+
await setTrackStatus(id, status, opts);
|
|
1297
|
+
});
|
|
1298
|
+
track
|
|
1299
|
+
.command("params <id> <pairs...>")
|
|
1300
|
+
.description("Answer the method's params as key=value (merged; key=null clears one)")
|
|
1301
|
+
.option("--reason <text>", "Why — shown to the reviewer")
|
|
1302
|
+
.option("--json", "Output as JSON")
|
|
1303
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1304
|
+
.option("--api-key <key>", "API key override")
|
|
1305
|
+
.action(async (id, pairs, opts) => {
|
|
1306
|
+
const { setTrackParams } = await import("./commands/tracks.js");
|
|
1307
|
+
await setTrackParams(id, pairs, opts);
|
|
1308
|
+
});
|
|
1309
|
+
track
|
|
1310
|
+
.command("start-step <id>")
|
|
1311
|
+
.description("Legacy (tracks with steps): start one step's session — on a track with no steps, use 'session start --track'")
|
|
1312
|
+
.option("--stage <key>", "Step key (defaults to the current step)")
|
|
1313
|
+
.option("--title <text>", "Session name (defaults to the step's name)")
|
|
1314
|
+
.option("--goal <text>", "Outcome (defaults to the step's goal)")
|
|
1315
|
+
.option("--json", "Output as JSON")
|
|
1316
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1317
|
+
.option("--api-key <key>", "API key override")
|
|
1318
|
+
.action(async (id, opts) => {
|
|
1319
|
+
const { startStep } = await import("./commands/tracks.js");
|
|
1320
|
+
await startStep(id, opts);
|
|
1321
|
+
});
|
|
897
1322
|
// ─── skill ────────────────────────────────────────────────────────────────────
|
|
898
1323
|
// Autonomous workspace session skills — context gathering, task planning, etc.
|
|
899
1324
|
const skillCmd = program
|
|
@@ -953,6 +1378,16 @@ skillCmd
|
|
|
953
1378
|
const { listSkills } = await import("./commands/skill-manage.js");
|
|
954
1379
|
await listSkills(opts);
|
|
955
1380
|
});
|
|
1381
|
+
skillCmd
|
|
1382
|
+
.command("approve <slug-or-id>")
|
|
1383
|
+
.description("Approve a skill so it loads (agent-authored skills are born unapproved)")
|
|
1384
|
+
.option("--revoke", "Revoke approval instead of granting it")
|
|
1385
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1386
|
+
.option("--api-key <key>", "API key override")
|
|
1387
|
+
.action(async (ref, opts) => {
|
|
1388
|
+
const { approveSkill } = await import("./commands/skill-manage.js");
|
|
1389
|
+
await approveSkill(ref, opts);
|
|
1390
|
+
});
|
|
956
1391
|
skillCmd
|
|
957
1392
|
.command("remove <slug>")
|
|
958
1393
|
.alias("rm")
|
|
@@ -1015,6 +1450,28 @@ observe
|
|
|
1015
1450
|
.option("--pod-url <url>", "Pod URL override")
|
|
1016
1451
|
.option("--api-key <key>", "API key override")
|
|
1017
1452
|
.action(async (text, opts) => {
|
|
1453
|
+
// `write` is the DEFAULT subcommand, so an unrecognized token lands here as
|
|
1454
|
+
// `text` instead of erroring — and this default WRITES. `synap observe recal`
|
|
1455
|
+
// therefore recorded an observation literally reading "recal" into the
|
|
1456
|
+
// AI-maintained user model, silently. Every other `isDefault` group in this
|
|
1457
|
+
// file has a zero-arg default, which commander rejects on its own; this is
|
|
1458
|
+
// the only one that can absorb a typo, and the only one where absorbing it
|
|
1459
|
+
// is a mutation.
|
|
1460
|
+
//
|
|
1461
|
+
// The guard keys off whether `write` was named EXPLICITLY, not off the text:
|
|
1462
|
+
// a mistyped subcommand is always a single bare token, and a real
|
|
1463
|
+
// observation is a sentence. Going through `observe write <text>` skips the
|
|
1464
|
+
// check entirely, so the escape hatch is real rather than circular.
|
|
1465
|
+
const argv = process.argv;
|
|
1466
|
+
const observeAt = argv.indexOf("observe");
|
|
1467
|
+
const explicitWrite = observeAt !== -1 && argv[observeAt + 1] === "write";
|
|
1468
|
+
if (!explicitWrite && !/\s/.test(text.trim())) {
|
|
1469
|
+
const siblings = observe.commands.map((c) => c.name()).filter((n) => n !== "write");
|
|
1470
|
+
console.error(`error: '${text}' looks like a subcommand, not observation text — nothing was recorded.\n` +
|
|
1471
|
+
` Available: ${siblings.map((n) => `synap observe ${n}`).join(", ")}\n` +
|
|
1472
|
+
` To record it as an observation anyway: synap observe write ${JSON.stringify(text)}`);
|
|
1473
|
+
process.exit(1);
|
|
1474
|
+
}
|
|
1018
1475
|
const { observeWrite } = await import("./commands/observe.js");
|
|
1019
1476
|
await observeWrite(text, opts);
|
|
1020
1477
|
});
|
|
@@ -1054,6 +1511,7 @@ create
|
|
|
1054
1511
|
.description("Create a new entity")
|
|
1055
1512
|
.requiredOption("--profile <slug>", "Profile slug (e.g. person, note, task)")
|
|
1056
1513
|
.requiredOption("--name <name>", "Entity name")
|
|
1514
|
+
.option("--content <markdown>", "Long-form Markdown body, stored as the entity's linked document")
|
|
1057
1515
|
.option("--workspace <id>", "Create in this workspace")
|
|
1058
1516
|
.option("--props <json>", "Properties as JSON string", "{}")
|
|
1059
1517
|
.option("--json", "Output as JSON")
|
|
@@ -1096,43 +1554,48 @@ set
|
|
|
1096
1554
|
// ─── agents ───────────────────────────────────────────────────────────────────
|
|
1097
1555
|
const agents = program
|
|
1098
1556
|
.command("agents")
|
|
1099
|
-
.description("Manage
|
|
1557
|
+
.description("Manage agent principals on your pod (one per type for you; local keys are a cache)");
|
|
1100
1558
|
agents
|
|
1101
1559
|
.command("list", { isDefault: true })
|
|
1102
|
-
.description("List
|
|
1560
|
+
.description("List your agents on this pod (one per type). Use --local for ~/.synap cache only.")
|
|
1103
1561
|
.option("--json", "Output as JSON")
|
|
1562
|
+
.option("--local", "List only the local ~/.synap agent cache")
|
|
1104
1563
|
.action(async (opts) => {
|
|
1105
1564
|
const { agentsList } = await import("./commands/agents.js");
|
|
1106
|
-
agentsList(opts);
|
|
1565
|
+
await agentsList(opts);
|
|
1107
1566
|
});
|
|
1108
1567
|
agents
|
|
1109
|
-
.command("add")
|
|
1110
|
-
.description("
|
|
1111
|
-
.option("--name <name>", "
|
|
1112
|
-
.option("--
|
|
1113
|
-
.option("--
|
|
1114
|
-
.option("--
|
|
1568
|
+
.command("add [kind]")
|
|
1569
|
+
.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)")
|
|
1570
|
+
.option("--name <name>", "Name your own agent (e.g. researcher) — prints a URL + key to paste")
|
|
1571
|
+
.option("--template <tmpl>", "Your own agent's template: twin | assistant | custom (default: custom)")
|
|
1572
|
+
.option("--type <type>", "Explicit agent type for your own agent (default: a slug of --name)")
|
|
1573
|
+
.option("--role <role>", "Workspace role: admin | editor | viewer (default: editor)")
|
|
1574
|
+
.option("--workspace <id>", "Focus on one workspace (default: pod-wide)")
|
|
1575
|
+
.option("--project <id>", "Focus on one project (composable with --workspace)")
|
|
1576
|
+
.option("--with-mcp", "Raycast only: also install the full MCP server via mcp-remote")
|
|
1577
|
+
.option("--api-key <key>", "Register a key you already hold, on this machine only (mints nothing)")
|
|
1115
1578
|
.option("--label <label>", "Human-readable description")
|
|
1116
|
-
.action(async (opts) => {
|
|
1579
|
+
.action(async (kind, opts) => {
|
|
1117
1580
|
const { agentsAdd } = await import("./commands/agents.js");
|
|
1118
|
-
await agentsAdd(opts);
|
|
1581
|
+
await agentsAdd(kind, opts);
|
|
1119
1582
|
});
|
|
1120
1583
|
agents
|
|
1121
1584
|
.command("create")
|
|
1122
|
-
.description("
|
|
1585
|
+
.description("Deprecated — use `synap agents add` (same flags)")
|
|
1123
1586
|
.option("--template <tmpl>", "Agent template: twin | assistant | custom (default: custom)")
|
|
1124
1587
|
.option("--name <name>", "Agent name (not needed for twin — auto-generated)")
|
|
1125
1588
|
.option("--type <type>", "Agent type string for custom agents (default: matches template)")
|
|
1126
|
-
.option("--role <role>", "Workspace role: admin | editor | viewer (default: editor
|
|
1127
|
-
.option("--workspace <id>", "
|
|
1128
|
-
.option("--
|
|
1589
|
+
.option("--role <role>", "Workspace role: admin | editor | viewer (default: editor)")
|
|
1590
|
+
.option("--workspace <id>", "Focus on one workspace (default: pod-wide)")
|
|
1591
|
+
.option("--project <id>", "Focus on one project")
|
|
1129
1592
|
.action(async (opts) => {
|
|
1130
1593
|
const { agentsCreate } = await import("./commands/agents.js");
|
|
1131
1594
|
await agentsCreate(opts);
|
|
1132
1595
|
});
|
|
1133
1596
|
agents
|
|
1134
1597
|
.command("rotate-key <name-or-id>")
|
|
1135
|
-
.description("Rotate the Hub Protocol API key for an agent (
|
|
1598
|
+
.description("Rotate the Hub Protocol API key for an agent (local cache only)")
|
|
1136
1599
|
.action(async (nameOrId) => {
|
|
1137
1600
|
const { agentsRotateKey } = await import("./commands/agents.js");
|
|
1138
1601
|
await agentsRotateKey(nameOrId);
|
|
@@ -1140,17 +1603,19 @@ agents
|
|
|
1140
1603
|
agents
|
|
1141
1604
|
.command("remove <name>")
|
|
1142
1605
|
.alias("rm")
|
|
1143
|
-
.description("Remove a named agent identity")
|
|
1606
|
+
.description("Remove a named agent identity (local cache only)")
|
|
1144
1607
|
.action(async (name) => {
|
|
1145
1608
|
const { agentsRemove } = await import("./commands/agents.js");
|
|
1146
1609
|
agentsRemove(name);
|
|
1147
1610
|
});
|
|
1148
1611
|
agents
|
|
1149
1612
|
.command("info <name>")
|
|
1150
|
-
.description("Show details for a named agent identity")
|
|
1151
|
-
.
|
|
1613
|
+
.description("Show details for a named agent identity (local cache only)")
|
|
1614
|
+
.option("--show-key", "Print the MCP URL and the full API key")
|
|
1615
|
+
.option("--snippets", "Print paste-ready configs (Claude Code, Cursor, stdio clients)")
|
|
1616
|
+
.action(async (name, opts) => {
|
|
1152
1617
|
const { agentsInfo } = await import("./commands/agents.js");
|
|
1153
|
-
agentsInfo(name);
|
|
1618
|
+
await agentsInfo(name, opts);
|
|
1154
1619
|
});
|
|
1155
1620
|
// ─── agent (autonomous runner) ───────────────────────────────────────────────
|
|
1156
1621
|
const agent = program
|
|
@@ -1228,6 +1693,52 @@ agent
|
|
|
1228
1693
|
const { agentTick } = await import("./commands/agent-run.js");
|
|
1229
1694
|
await agentTick(opts);
|
|
1230
1695
|
});
|
|
1696
|
+
// ─── automate ───────────────────────────────────────────────────────────────
|
|
1697
|
+
// The natural-language automation door. It stays deliberately separate from
|
|
1698
|
+
// `automation create`, which remains the expert, explicit-DSL path.
|
|
1699
|
+
program
|
|
1700
|
+
.command("automate <instruction>")
|
|
1701
|
+
.description("Ask the workspace agent to prepare a governed automation proposal")
|
|
1702
|
+
.option("--workspace <id|name>", "Workspace to use (uses active workspace/lens if omitted)")
|
|
1703
|
+
.option("--thread <id>", "Continue an existing agent thread/channel")
|
|
1704
|
+
.option("--new", "Start a fresh agent thread")
|
|
1705
|
+
.option("--timeout <seconds>", "How long to wait for the agent's reply (default: 90)")
|
|
1706
|
+
.option("--json", "Machine-readable output { ok, reply, threadId, workspaceId }")
|
|
1707
|
+
.option("--pod-url <url>", "Override pod URL")
|
|
1708
|
+
.option("--api-key <key>", "Override API key")
|
|
1709
|
+
.action(async (instruction, opts) => {
|
|
1710
|
+
const { automate } = await import("./commands/automate.js");
|
|
1711
|
+
await automate(instruction, opts);
|
|
1712
|
+
});
|
|
1713
|
+
// ─── rule ────────────────────────────────────────────────────────────────────
|
|
1714
|
+
// The fourth door, beside `ask` (recall), `capture` (write) and `diagnose`
|
|
1715
|
+
// (inspect): a STANDING instruction. It classifies the sentence and shows the
|
|
1716
|
+
// reading before writing anything — and it records the rule only. Building the
|
|
1717
|
+
// behaviour half is still `synap automate`.
|
|
1718
|
+
const ruleCmd = program
|
|
1719
|
+
.command("rule [text]")
|
|
1720
|
+
.description("State a standing rule in plain language — classified, shown, then governed-created")
|
|
1721
|
+
.option("--workspace <id>", "Workspace to scope the rule to (uses active workspace if omitted)")
|
|
1722
|
+
.option("--pod-wide", "Scope the rule to the whole pod, ignoring the active workspace")
|
|
1723
|
+
.option("--yes", "Skip the one-off confirmation (never skips a clarification)")
|
|
1724
|
+
.option("--json", "Output raw JSON")
|
|
1725
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1726
|
+
.option("--api-key <key>", "API key override")
|
|
1727
|
+
.action(async (text, opts) => {
|
|
1728
|
+
const { rule } = await import("./commands/rule.js");
|
|
1729
|
+
await rule(text ?? "", opts);
|
|
1730
|
+
});
|
|
1731
|
+
ruleCmd
|
|
1732
|
+
.command("list")
|
|
1733
|
+
.description("List rules with their intent, scope, and whether a behaviour is attached")
|
|
1734
|
+
.option("--workspace <id>", "Filter by workspace")
|
|
1735
|
+
.option("--json", "Output raw JSON")
|
|
1736
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1737
|
+
.option("--api-key <key>", "API key override")
|
|
1738
|
+
.action(async (opts) => {
|
|
1739
|
+
const { ruleList } = await import("./commands/rule.js");
|
|
1740
|
+
await ruleList(opts);
|
|
1741
|
+
});
|
|
1231
1742
|
// ─── automation ──────────────────────────────────────────────────────────────
|
|
1232
1743
|
function collect(val, prev) { return [...prev, val]; }
|
|
1233
1744
|
const automation = program
|
|
@@ -1419,12 +1930,11 @@ program
|
|
|
1419
1930
|
.description("Open in the Synap desktop app. Use: open <kind> <id> or open <id> (auto-resolves type)")
|
|
1420
1931
|
.action(async (kindOrId, id) => {
|
|
1421
1932
|
if (id) {
|
|
1422
|
-
// open
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
}
|
|
1933
|
+
// open <kind> <id> — the browser's object-nav.ts is the one route
|
|
1934
|
+
// table for openable kinds (21 and growing); the CLI doesn't
|
|
1935
|
+
// duplicate it here. An unroutable kind still opens the app and
|
|
1936
|
+
// is reported via the printed deep link (objectNavTarget decides
|
|
1937
|
+
// routability on the other side).
|
|
1428
1938
|
const { openInBrowser } = await import("./commands/open.js");
|
|
1429
1939
|
await openInBrowser({ kind: kindOrId, id });
|
|
1430
1940
|
}
|
|
@@ -1461,10 +1971,12 @@ Examples:
|
|
|
1461
1971
|
});
|
|
1462
1972
|
doc
|
|
1463
1973
|
.command("update <documentId>")
|
|
1464
|
-
.description("Update a document's content
|
|
1974
|
+
.description("Update a document's content: the whole body, or one section (--section). Governed: an agent's edit is proposed.")
|
|
1465
1975
|
.option("--content <text>", "New markdown content (inline)")
|
|
1466
1976
|
.option("--file <path>", "Read new content from a file")
|
|
1467
|
-
.option("--
|
|
1977
|
+
.option("--section <id>", "Write ONE section by id (content = the section body) instead of the whole document")
|
|
1978
|
+
.option("--section-title <title>", "The section heading (required with --section)")
|
|
1979
|
+
.option("--base-revision <n>", "The revision you read; refused if the document changed since")
|
|
1468
1980
|
.option("--open", "Open in the Synap desktop app after update")
|
|
1469
1981
|
.option("--json", "JSON output")
|
|
1470
1982
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -1474,11 +1986,29 @@ Examples:
|
|
|
1474
1986
|
synap doc update <id> --content "# Updated"
|
|
1475
1987
|
synap doc update <id> --file ./notes.md
|
|
1476
1988
|
cat notes.md | synap doc update <id>
|
|
1989
|
+
synap doc update <id> --section risks --section-title "Risks" --file ./risks.md
|
|
1477
1990
|
`)
|
|
1478
1991
|
.action(async (documentId, opts) => {
|
|
1479
1992
|
const { docUpdate } = await import("./commands/doc.js");
|
|
1480
1993
|
await docUpdate(documentId, opts);
|
|
1481
1994
|
});
|
|
1995
|
+
doc
|
|
1996
|
+
.command("reference <url>")
|
|
1997
|
+
.description("Create an external reference document (points at a URL — no bytes stored)")
|
|
1998
|
+
.requiredOption("--title <title>", "Document title")
|
|
1999
|
+
.option("--workspace <id>", "Workspace to create the reference in")
|
|
2000
|
+
.option("--open", "Open in the Synap desktop app after creation")
|
|
2001
|
+
.option("--json", "JSON output")
|
|
2002
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2003
|
+
.option("--api-key <key>", "API key override")
|
|
2004
|
+
.addHelpText("after", `
|
|
2005
|
+
Examples:
|
|
2006
|
+
synap doc reference https://example.com/spec --title "Vendor spec"
|
|
2007
|
+
`)
|
|
2008
|
+
.action(async (url, opts) => {
|
|
2009
|
+
const { docReference } = await import("./commands/doc.js");
|
|
2010
|
+
await docReference(url, opts);
|
|
2011
|
+
});
|
|
1482
2012
|
// ─── cell ─────────────────────────────────────────────────────────────────────
|
|
1483
2013
|
const cell = program
|
|
1484
2014
|
.command("cell")
|
|
@@ -1489,17 +2019,30 @@ cell
|
|
|
1489
2019
|
.requiredOption("--name <name>", "Cell display name")
|
|
1490
2020
|
.option("--file <path>", "ESM source file (or pipe stdin)")
|
|
1491
2021
|
.option("--type-key <key>", "Explicit typeKey (default: generated:<slug>)")
|
|
1492
|
-
.option("--deps <json>", 'Dependency map JSON, e.g. \'{"recharts":"2.12.0"}\'
|
|
1493
|
-
.option("--
|
|
2022
|
+
.option("--deps <json>", 'Dependency map JSON, e.g. \'{"recharts":"2.12.0"}\'')
|
|
2023
|
+
.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')
|
|
2024
|
+
.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)")
|
|
2025
|
+
// NOT "omit for pod-wide": `cell.ts` resolves `opts.workspace ?? cfg.workspaceId`,
|
|
2026
|
+
// and `cfg.workspaceId` is the resolved lens (session › directory › env ›
|
|
2027
|
+
// profile default). Omitting therefore scopes the cell to whatever workspace
|
|
2028
|
+
// your lens currently points at — which is pod-wide ONLY when nothing resolves.
|
|
2029
|
+
// Verified 2026-09-05: run from a directory with no `.synap/lens.json` and the
|
|
2030
|
+
// cell silently lands in the pod profile's default workspace.
|
|
2031
|
+
.option("--workspace <id>", "Workspace to scope the cell to (default: your active workspace lens — run `synap lens` to see it)")
|
|
1494
2032
|
.option("--description <text>", "Short description")
|
|
1495
2033
|
.option("--open", "Open in the Synap desktop app after define")
|
|
1496
2034
|
.option("--json", "JSON output")
|
|
1497
2035
|
.option("--pod-url <url>", "Pod URL override")
|
|
1498
2036
|
.option("--api-key <key>", "API key override")
|
|
1499
2037
|
.addHelpText("after", `
|
|
2038
|
+
Without --view-types / --content-kind a cell installs cleanly but can never be
|
|
2039
|
+
PICKED as a view or profile renderer — it is only placeable on a bento.
|
|
2040
|
+
|
|
1500
2041
|
Examples:
|
|
1501
2042
|
synap cell define --name "Revenue Chart" --file ./chart.js
|
|
1502
2043
|
synap cell define --name "Revenue Chart" --file ./chart.js --deps '{"recharts":"2.12.0"}'
|
|
2044
|
+
synap cell define --name "Deal Board" --file ./board.js --view-types kanban,table --content-kind collection
|
|
2045
|
+
synap cell define --name "Contact Page" --file ./contact.js --content-kind entity-detail
|
|
1503
2046
|
cat chart.js | synap cell define --name "Revenue Chart"
|
|
1504
2047
|
`)
|
|
1505
2048
|
.action(async (opts) => {
|
|
@@ -1510,10 +2053,16 @@ cell
|
|
|
1510
2053
|
.command("build <entry>")
|
|
1511
2054
|
.description("Bundle a multi-file cell/app into a single ESM module the runtime expects")
|
|
1512
2055
|
.option("--out <file>", "Output file path (default: <entry>.bundle.js)")
|
|
2056
|
+
.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")
|
|
2057
|
+
.option("--self-contained", 'Build ONE complete HTML document (React, CSS, brand fonts inlined; nothing external) — the code of a rendererType "mcp-app" cell')
|
|
2058
|
+
.option("--fonts", "With --self-contained: require the inlined brand fonts (default: include when @synap-core/design-tokens resolves)")
|
|
2059
|
+
.option("--no-fonts", "With --self-contained: skip the inlined brand fonts")
|
|
1513
2060
|
.option("--define", "Chain into cell define after bundling (requires --name)")
|
|
1514
2061
|
.option("--name <name>", "Cell name (required with --define)")
|
|
1515
2062
|
.option("--type-key <key>", "Explicit typeKey (used with --define)")
|
|
1516
2063
|
.option("--deps <json>", "Override dependency versions as JSON, e.g. '{\"react\":\"18.3.0\"}'")
|
|
2064
|
+
.option("--view-types <list>", 'Comma-separated view-renderer affinity (used with --define), e.g. "list,table"')
|
|
2065
|
+
.option("--content-kind <kind>", "entity-detail | entity-card | entity-profile | collection | widget (used with --define)")
|
|
1517
2066
|
.option("--workspace <id>", "Workspace (used with --define)")
|
|
1518
2067
|
.option("--description <text>", "Description (used with --define)")
|
|
1519
2068
|
.option("--open", "Open in browser after define (used with --define)")
|
|
@@ -1521,12 +2070,20 @@ cell
|
|
|
1521
2070
|
.option("--pod-url <url>", "Pod URL override")
|
|
1522
2071
|
.option("--api-key <key>", "API key override")
|
|
1523
2072
|
.addHelpText("after", `
|
|
1524
|
-
Output: a single ESM file.
|
|
1525
|
-
|
|
2073
|
+
Output: a single ESM file.
|
|
2074
|
+
|
|
2075
|
+
Default mode: bare imports (react, recharts, …) are externalized and emitted
|
|
2076
|
+
as a deps map. At runtime Synap resolves them via esm.sh importmap.
|
|
2077
|
+
|
|
2078
|
+
--bundle-deps mode: only react/react-dom are externalized (React is
|
|
2079
|
+
host-inlined at runtime, never via esm.sh); everything else is bundled into
|
|
2080
|
+
the output, so the deps map is empty. A cell built this way reaches no esm.sh
|
|
2081
|
+
origin at runtime — the runtime CSP collapses to drop it entirely.
|
|
1526
2082
|
|
|
1527
2083
|
Examples:
|
|
1528
2084
|
synap cell build ./src/chart.tsx --out ./dist/chart.js
|
|
1529
2085
|
synap cell build ./src/chart.tsx --out ./dist/chart.js --define --name "Revenue Chart"
|
|
2086
|
+
synap cell build ./src/chart.tsx --out ./dist/chart.js --bundle-deps
|
|
1530
2087
|
`)
|
|
1531
2088
|
.action(async (entry, opts) => {
|
|
1532
2089
|
const { cellBuild } = await import("./commands/cell.js");
|
|
@@ -1576,7 +2133,7 @@ tools
|
|
|
1576
2133
|
});
|
|
1577
2134
|
tools
|
|
1578
2135
|
.command("connect <service>")
|
|
1579
|
-
.description("Connect a credential to a tool (via
|
|
2136
|
+
.description("Connect a credential to a tool (OAuth via the connection broker, or vault)")
|
|
1580
2137
|
.option("--workspace <id>", "Workspace context")
|
|
1581
2138
|
.option("--pod-url <url>", "Pod URL override")
|
|
1582
2139
|
.option("--api-key <key>", "API key override")
|
|
@@ -1641,6 +2198,33 @@ podCmd
|
|
|
1641
2198
|
const { podAdopt } = await import("./commands/pod.js");
|
|
1642
2199
|
await podAdopt(workspaceNameOrId, opts);
|
|
1643
2200
|
});
|
|
2201
|
+
// ─── vendor — the author's publisher profile ─────────────────────────────────
|
|
2202
|
+
// Attribution is write-time-only at the CP: a package published before a vendor
|
|
2203
|
+
// exists is orphaned from its author forever. See src/commands/vendor.ts.
|
|
2204
|
+
const vendor = program
|
|
2205
|
+
.command("vendor")
|
|
2206
|
+
.description("Your marketplace publisher profile (what packages are attributed to)");
|
|
2207
|
+
vendor
|
|
2208
|
+
.command("create <slug>")
|
|
2209
|
+
.description("Create your publisher profile — do this BEFORE your first publish")
|
|
2210
|
+
.option("--name <name>", "Display name (defaults to a title-cased slug)")
|
|
2211
|
+
.option("--description <text>", "Short description of you or your studio")
|
|
2212
|
+
.option("--website <url>", "Website URL (must be a full URL)")
|
|
2213
|
+
.option("--json", "Output as JSON")
|
|
2214
|
+
.action(async (slug, _opts, cmd) => {
|
|
2215
|
+
const opts = cmd.optsWithGlobals();
|
|
2216
|
+
const { vendorCreate } = await import("./commands/vendor.js");
|
|
2217
|
+
await vendorCreate(slug, opts);
|
|
2218
|
+
});
|
|
2219
|
+
vendor
|
|
2220
|
+
.command("show")
|
|
2221
|
+
.description("Show whether you have a publisher profile")
|
|
2222
|
+
.option("--json", "Output as JSON")
|
|
2223
|
+
.action(async (_opts, cmd) => {
|
|
2224
|
+
const opts = cmd.optsWithGlobals();
|
|
2225
|
+
const { vendorShow } = await import("./commands/vendor.js");
|
|
2226
|
+
await vendorShow(opts);
|
|
2227
|
+
});
|
|
1644
2228
|
// ─── market — discover + install ANY package type ────────────────────────────
|
|
1645
2229
|
// launch is workspace-first (bundled, offline); market reaches every CP package
|
|
1646
2230
|
// type (capability/skill/workflow/view/cell/workspace), public or private.
|
|
@@ -1659,7 +2243,9 @@ market
|
|
|
1659
2243
|
.command("install <slug>")
|
|
1660
2244
|
.description("Install a package by slug into a project — workspaces install now; other types route you to the right surface")
|
|
1661
2245
|
.option("--project <id>", "Optionally tag the seeded entities to a project (installs are pod-wide by default)")
|
|
2246
|
+
.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")
|
|
1662
2247
|
.option("--onto <workspaceId>", "Reconcile this template ONTO an existing workspace (additive) instead of creating a new one")
|
|
2248
|
+
.option("--dry-run", "Preview the create path write-free — report would-create / reuse / conflicts, install nothing")
|
|
1663
2249
|
.option("--timeout <seconds>", "How long to wait for the apply to finish (default: 120)")
|
|
1664
2250
|
.option("--json", "Output as JSON")
|
|
1665
2251
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -1678,7 +2264,8 @@ market
|
|
|
1678
2264
|
market
|
|
1679
2265
|
.command("update [slugs...]")
|
|
1680
2266
|
.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)")
|
|
1681
|
-
.option("--yes", "Apply every available update without prompting (no slugs required)")
|
|
2267
|
+
.option("--yes", "Apply every available update without prompting (no slugs required), agreeing to every data change it lists")
|
|
2268
|
+
.option("--accept-data-changes <opKeys>", "Agree to exactly these data changes (comma-separated opKeys from the preview)")
|
|
1682
2269
|
.option("--dry-run", "Force the preview path — never apply, even with --yes")
|
|
1683
2270
|
.option("--timeout <seconds>", "How long to wait for each package's apply to finish (default: 120)")
|
|
1684
2271
|
.option("--json", "Output as JSON")
|
|
@@ -1703,6 +2290,209 @@ market
|
|
|
1703
2290
|
const { marketInstalled } = await import("./commands/market.js");
|
|
1704
2291
|
await marketInstalled(opts);
|
|
1705
2292
|
});
|
|
2293
|
+
market
|
|
2294
|
+
.command("workspaces")
|
|
2295
|
+
.description("List your workspaces with their template-attachment status — find the one that isn't attached yet (pure read)")
|
|
2296
|
+
.option("--unattached", "Only show workspaces that need attention (unattached or missing a version stamp)")
|
|
2297
|
+
.option("--json", "Output as JSON")
|
|
2298
|
+
.action(async (_opts, cmd) => {
|
|
2299
|
+
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
2300
|
+
const opts = cmd.optsWithGlobals();
|
|
2301
|
+
const { marketWorkspaces } = await import("./commands/market.js");
|
|
2302
|
+
await marketWorkspaces(opts);
|
|
2303
|
+
});
|
|
2304
|
+
market
|
|
2305
|
+
.command("attach <workspaceId>")
|
|
2306
|
+
.description("Reconcile a marketplace template onto an existing workspace + version-stamp it — how you relink a workspace installed before the marketplace")
|
|
2307
|
+
.option("--slug <slug>", "Template to attach (inferred from the workspace's existing attachment or domain when omitted)")
|
|
2308
|
+
.option("--project <id>", "Optionally tag the reconciled entities to a project")
|
|
2309
|
+
.option("--timeout <seconds>", "How long to wait for the apply to finish (default: 120)")
|
|
2310
|
+
.option("--json", "Output as JSON")
|
|
2311
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2312
|
+
.option("--api-key <key>", "API key override")
|
|
2313
|
+
.action(async (workspaceId, _opts, cmd) => {
|
|
2314
|
+
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
2315
|
+
const opts = cmd.optsWithGlobals();
|
|
2316
|
+
const { marketAttach } = await import("./commands/market.js");
|
|
2317
|
+
await marketAttach(workspaceId, opts);
|
|
2318
|
+
});
|
|
2319
|
+
// ── `synap templates` — the ONE home for workspace ↔ template health ─────────
|
|
2320
|
+
// Consolidates `market update`/`workspaces`/`installed`: one grouped, action-
|
|
2321
|
+
// ranked view where an UNATTACHED workspace is visible (it wasn't in `update`),
|
|
2322
|
+
// with a suggested template and a one-word attach. The `market *` subcommands
|
|
2323
|
+
// still work — this is the front door, not a breaking rename.
|
|
2324
|
+
const templates = program
|
|
2325
|
+
.command("templates")
|
|
2326
|
+
.description("See every workspace's template status (attached, drifted, or unattached) and connect them — the one home for template health")
|
|
2327
|
+
.option("--needs-attention", "Show only workspaces that need action (drifted / unstamped / unattached-with-suggestion)")
|
|
2328
|
+
.option("--json", "Output as JSON")
|
|
2329
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2330
|
+
.option("--api-key <key>", "API key override")
|
|
2331
|
+
.action(async (_opts, cmd) => {
|
|
2332
|
+
const opts = cmd.optsWithGlobals();
|
|
2333
|
+
const { marketTemplates } = await import("./commands/market.js");
|
|
2334
|
+
await marketTemplates(opts);
|
|
2335
|
+
});
|
|
2336
|
+
templates
|
|
2337
|
+
.command("attach <workspace>")
|
|
2338
|
+
.description("Connect a workspace (by NAME or id) to a template — suggests the right one so you don't guess a slug")
|
|
2339
|
+
.option("--slug <slug>", "Force a specific template instead of the suggestion")
|
|
2340
|
+
.option("--yes", "Accept a confident (domain-match) suggestion without prompting — for scripts")
|
|
2341
|
+
.option("--project <id>", "Optionally tag the reconciled entities to a project")
|
|
2342
|
+
.option("--timeout <seconds>", "How long to wait for the apply to finish (default: 120)")
|
|
2343
|
+
.option("--json", "Output as JSON")
|
|
2344
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2345
|
+
.option("--api-key <key>", "API key override")
|
|
2346
|
+
.action(async (workspace, _opts, cmd) => {
|
|
2347
|
+
const opts = cmd.optsWithGlobals();
|
|
2348
|
+
const { templatesAttach } = await import("./commands/market.js");
|
|
2349
|
+
await templatesAttach(workspace, opts);
|
|
2350
|
+
});
|
|
2351
|
+
templates
|
|
2352
|
+
.command("update [slugs...]")
|
|
2353
|
+
.alias("updates")
|
|
2354
|
+
.description("Apply template updates — 'update all' (or --yes) for every drifted workspace, or name specific slugs. Bare 'update' previews what's available.")
|
|
2355
|
+
.option("--yes", "Apply every available update without prompting, agreeing to every data change it lists")
|
|
2356
|
+
.option("--accept-data-changes <opKeys>", "Agree to exactly these data changes (comma-separated opKeys from the preview)")
|
|
2357
|
+
.option("--dry-run", "Preview only — never apply")
|
|
2358
|
+
.option("--timeout <seconds>", "How long to wait for each apply (default: 120)")
|
|
2359
|
+
.option("--json", "Output as JSON")
|
|
2360
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2361
|
+
.option("--api-key <key>", "API key override")
|
|
2362
|
+
.action(async (slugs, _opts, cmd) => {
|
|
2363
|
+
const opts = cmd.optsWithGlobals();
|
|
2364
|
+
// `update all` reads more naturally than `--yes` and is what people type —
|
|
2365
|
+
// treat the literal word "all" as "apply every available update". It is NOT
|
|
2366
|
+
// `--yes`: data changes still need the person's agreement (asked, or flagged).
|
|
2367
|
+
const wantsAll = !!slugs?.some((s) => s.toLowerCase() === "all");
|
|
2368
|
+
const explicit = (slugs ?? []).filter((s) => s.toLowerCase() !== "all");
|
|
2369
|
+
const { marketUpdate } = await import("./commands/market.js");
|
|
2370
|
+
await marketUpdate(explicit.length > 0 ? explicit : undefined, wantsAll ? { ...opts, all: true } : opts);
|
|
2371
|
+
});
|
|
2372
|
+
templates
|
|
2373
|
+
.command("retire <target>")
|
|
2374
|
+
.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.")
|
|
2375
|
+
.option("--dry-run", "Show the plan only — move nothing")
|
|
2376
|
+
.option("--yes", "Move without asking (for scripts)")
|
|
2377
|
+
.option("--json", "Output as JSON")
|
|
2378
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2379
|
+
.option("--api-key <key>", "API key override")
|
|
2380
|
+
.action(async (target, _opts, cmd) => {
|
|
2381
|
+
const opts = cmd.optsWithGlobals();
|
|
2382
|
+
const { templatesRetire } = await import("./commands/templates-retire.js");
|
|
2383
|
+
await templatesRetire(target, opts);
|
|
2384
|
+
});
|
|
2385
|
+
// ── Authoring loop: scaffold → validate → publish → unpublish ────────────────
|
|
2386
|
+
market
|
|
2387
|
+
.command("scaffold <slug>")
|
|
2388
|
+
.description("Write a minimal valid <slug>.template.yaml to edit in place (refuses to overwrite)")
|
|
2389
|
+
// This list MUST equal `SCAFFOLDABLE_KINDS` (src/lib/kind-package.ts). It is
|
|
2390
|
+
// written out rather than imported because index.ts keeps its eager module
|
|
2391
|
+
// graph to commander + one lib — importing kind-package.ts here would pull
|
|
2392
|
+
// `yaml` into the startup path of every `synap` invocation. What keeps the two
|
|
2393
|
+
// honest is `test/scaffold-kind-help-parity.test.ts`, which source-scans both.
|
|
2394
|
+
//
|
|
2395
|
+
// It advertised `skill` — which `marketScaffold` refuses, since the CP package
|
|
2396
|
+
// schema has no standalone slot for one — and omitted `workflow`, which
|
|
2397
|
+
// `market validate` has always accepted. A help string that offers a refused
|
|
2398
|
+
// option and hides a working one is the documented-loop defect class.
|
|
2399
|
+
.option("--kind <kind>", "Scaffold a standalone package instead of a workspace template: cell, view, workflow, capability, skill")
|
|
2400
|
+
.option("--json", "Output as JSON")
|
|
2401
|
+
.action(async (slug, _opts, cmd) => {
|
|
2402
|
+
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
2403
|
+
const opts = cmd.optsWithGlobals();
|
|
2404
|
+
const { marketScaffold } = await import("./commands/market-authoring.js");
|
|
2405
|
+
await marketScaffold(slug, opts);
|
|
2406
|
+
});
|
|
2407
|
+
market
|
|
2408
|
+
.command("validate <file>")
|
|
2409
|
+
.description("Validate a local template file against the shared template validator — fast author feedback")
|
|
2410
|
+
.option("--json", "Output the validator result as JSON")
|
|
2411
|
+
.action(async (file, _opts, cmd) => {
|
|
2412
|
+
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
2413
|
+
const opts = cmd.optsWithGlobals();
|
|
2414
|
+
const { marketValidate } = await import("./commands/market-authoring.js");
|
|
2415
|
+
await marketValidate(file, opts);
|
|
2416
|
+
});
|
|
2417
|
+
market
|
|
2418
|
+
.command("publish [targets...]")
|
|
2419
|
+
.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`)")
|
|
2420
|
+
.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")
|
|
2421
|
+
.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)")
|
|
2422
|
+
.option("--dry-run", "With --official: preview what would change against the live catalog, publish nothing")
|
|
2423
|
+
.option("--yes", "With --official: skip the confirmation prompt")
|
|
2424
|
+
.option("--public", "Publish as PUBLIC (default is private)")
|
|
2425
|
+
.option("--private", "Publish as private (the default — stated explicitly)")
|
|
2426
|
+
.option("--from-workspace <id>", "Serialize a live workspace into a template and publish it (instead of a file)")
|
|
2427
|
+
.option("--from-project <id>", "Serialize a live project's used workspaces into a suite package (tags: suite, require deps) and publish it")
|
|
2428
|
+
.option("--price <usd>", "Stamp pricingModel=one_time + priceUsd (dollars→cents). Settlement/Stripe is not this wave — columns only.")
|
|
2429
|
+
.option("--json", "Output as JSON")
|
|
2430
|
+
.option("--pod-url <url>", "Pod URL override (for --from-workspace / --from-project)")
|
|
2431
|
+
.option("--api-key <key>", "API key override (for --from-workspace / --from-project)")
|
|
2432
|
+
// Default ON for a cell package's `codeFile` resolution — see `cell build
|
|
2433
|
+
// --bundle-deps`'s doc comment for why: a published cell's `deps` map is
|
|
2434
|
+
// otherwise resolved through esm.sh at RUNTIME, so the artifact reviewed at
|
|
2435
|
+
// publish time isn't what actually executes. `synap cell build` invoked
|
|
2436
|
+
// directly is unaffected — its own default stays external-deps-via-esm.sh.
|
|
2437
|
+
.option("--no-bundle-deps", "Publish a cell's codeFile with external deps via esm.sh instead of bundling them in (default: bundled)")
|
|
2438
|
+
.action(async (targets, _opts, cmd) => {
|
|
2439
|
+
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
2440
|
+
const opts = cmd.optsWithGlobals();
|
|
2441
|
+
const args = targets ?? [];
|
|
2442
|
+
if (opts.official) {
|
|
2443
|
+
const { marketPublishOfficial } = await import("./commands/market-official.js");
|
|
2444
|
+
process.exitCode = await marketPublishOfficial(args, opts);
|
|
2445
|
+
return;
|
|
2446
|
+
}
|
|
2447
|
+
const { nonOfficialUsageError } = await import("./commands/market-official.js");
|
|
2448
|
+
const usage = nonOfficialUsageError(args, opts);
|
|
2449
|
+
if (usage) {
|
|
2450
|
+
console.error(` ✗ ${usage}`);
|
|
2451
|
+
process.exitCode = 2;
|
|
2452
|
+
return;
|
|
2453
|
+
}
|
|
2454
|
+
const { marketPublish } = await import("./commands/market-authoring.js");
|
|
2455
|
+
await marketPublish(args[0], opts);
|
|
2456
|
+
});
|
|
2457
|
+
market
|
|
2458
|
+
.command("unpublish <slug>")
|
|
2459
|
+
.description("Flip a published package back to private (owner only)")
|
|
2460
|
+
.option("--json", "Output as JSON")
|
|
2461
|
+
.action(async (slug, _opts, cmd) => {
|
|
2462
|
+
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
2463
|
+
const opts = cmd.optsWithGlobals();
|
|
2464
|
+
const { marketUnpublish } = await import("./commands/market-authoring.js");
|
|
2465
|
+
await marketUnpublish(slug, opts);
|
|
2466
|
+
});
|
|
2467
|
+
// ─── catalog ──────────────────────────────────────────────────────────────────
|
|
2468
|
+
// The team's ONE door to the official catalog (every installable kind). Thin
|
|
2469
|
+
// wiring: `runCatalog` (commands/catalog.ts) calls the ONE catalog lib in the
|
|
2470
|
+
// monorepo checkout. `market publish --official` is its alias (kind workspace).
|
|
2471
|
+
const catalog = program
|
|
2472
|
+
.command("catalog")
|
|
2473
|
+
.description("Validate, diff and publish the OFFICIAL template catalog (workspaces, capabilities, skills, packs, automations) from the monorepo checkout");
|
|
2474
|
+
for (const verb of ["validate", "diff", "publish"]) {
|
|
2475
|
+
const sub = catalog
|
|
2476
|
+
.command(`${verb} [slugs...]`)
|
|
2477
|
+
.description(verb === "validate"
|
|
2478
|
+
? "Validate the catalog (per-kind schema, cross-kind refs, goal grammar, duplicates) — offline"
|
|
2479
|
+
: verb === "diff"
|
|
2480
|
+
? "Show what would change against the live control-plane catalog (new / changed / unchanged)"
|
|
2481
|
+
: "Validate, preview the diff, confirm, then publish to the control plane — founder only: --official + a `synap login` session that owns synap-official")
|
|
2482
|
+
.option("--kind <kind>", "Only this kind: workspace | capability | skill | pack | automation")
|
|
2483
|
+
.option("--catalog-dir <dir>", "Path to the catalog package (default: found by walking up from cwd)")
|
|
2484
|
+
.option("--json", "Output as JSON");
|
|
2485
|
+
if (verb === "publish") {
|
|
2486
|
+
sub
|
|
2487
|
+
.option("--official", "Publish as the synap-official vendor (required)")
|
|
2488
|
+
.option("--dry-run", "Preview the diff only — publish nothing")
|
|
2489
|
+
.option("--yes", "Skip the confirmation prompt");
|
|
2490
|
+
}
|
|
2491
|
+
sub.action(async (slugs, opts) => {
|
|
2492
|
+
const { runCatalog } = await import("./commands/catalog.js");
|
|
2493
|
+
process.exitCode = await runCatalog(verb, slugs ?? [], opts);
|
|
2494
|
+
});
|
|
2495
|
+
}
|
|
1706
2496
|
// ─── capability ───────────────────────────────────────────────────────────────
|
|
1707
2497
|
const capability = program
|
|
1708
2498
|
.command("capability")
|
|
@@ -1755,6 +2545,7 @@ capability
|
|
|
1755
2545
|
.command("connect [name]")
|
|
1756
2546
|
.description("Connect a service — omit the name to pick from connectable services")
|
|
1757
2547
|
.option("--workspace <id>", "Workspace context")
|
|
2548
|
+
.option("--reconnect", "Force a fresh sign-in even if a connection already exists — fixes an expired or revoked token")
|
|
1758
2549
|
.action(async (name, opts) => {
|
|
1759
2550
|
const { capabilityConnect } = await import("./commands/capability.js");
|
|
1760
2551
|
await capabilityConnect(name, opts);
|
|
@@ -1851,13 +2642,37 @@ capConnections
|
|
|
1851
2642
|
const { capabilityConnectionsRemove } = await import("./commands/cap-connections.js");
|
|
1852
2643
|
await capabilityConnectionsRemove(capability, connectionId, opts);
|
|
1853
2644
|
});
|
|
1854
|
-
|
|
2645
|
+
capability
|
|
2646
|
+
.command("sync-status [provider]")
|
|
2647
|
+
.description("Show sync status per provider × kind × connection (phase, counts, errors) — omit provider to see all")
|
|
2648
|
+
.option("--workspace <id>", "Workspace context")
|
|
2649
|
+
.option("--json", "Output as JSON")
|
|
2650
|
+
.action(async (provider, opts) => {
|
|
2651
|
+
const { capabilitySyncStatus } = await import("./commands/sync-status.js");
|
|
2652
|
+
await capabilitySyncStatus(provider, opts);
|
|
2653
|
+
});
|
|
2654
|
+
// ─── sync (thin alias root for `cap sync-status`) ──────────────────────────────
|
|
2655
|
+
const sync = program
|
|
2656
|
+
.command("sync")
|
|
2657
|
+
.description("Sync status for connected providers — see `cap sync-status`");
|
|
2658
|
+
sync
|
|
2659
|
+
.command("status [provider]")
|
|
2660
|
+
.description("Show sync status per provider × kind × connection (phase, counts, errors) — omit provider to see all. Alias of `synap cap sync-status`.")
|
|
2661
|
+
.option("--workspace <id>", "Workspace context")
|
|
2662
|
+
.option("--json", "Output as JSON")
|
|
2663
|
+
.action(async (provider, opts) => {
|
|
2664
|
+
const { capabilitySyncStatus } = await import("./commands/sync-status.js");
|
|
2665
|
+
await capabilitySyncStatus(provider, opts);
|
|
2666
|
+
});
|
|
2667
|
+
// ─── raycast (hidden power-user escape) ───────────────────────────────────────
|
|
2668
|
+
// Prefer the native Synap Raycast extension (@synap). Capability verbs there go
|
|
2669
|
+
// through list-actions / run-action. Script Commands are a per-verb escape hatch.
|
|
1855
2670
|
const raycast = program
|
|
1856
|
-
.command("raycast")
|
|
1857
|
-
.description("
|
|
2671
|
+
.command("raycast", { hidden: true })
|
|
2672
|
+
.description("(hidden) Power-user escape: generate Raycast Script Commands per capability verb");
|
|
1858
2673
|
raycast
|
|
1859
2674
|
.command("generate")
|
|
1860
|
-
.description("
|
|
2675
|
+
.description("Power-user escape: emit a Script Command per enabled verb (extension uses list-actions/run-action)")
|
|
1861
2676
|
.option("--out <dir>", "Output directory (default: ~/.synap/raycast-commands)")
|
|
1862
2677
|
.option("--workspace <id>", "Workspace context")
|
|
1863
2678
|
.action(async (opts) => {
|
|
@@ -1867,7 +2682,7 @@ raycast
|
|
|
1867
2682
|
// ─── providers ───────────────────────────────────────────────────────────────
|
|
1868
2683
|
const providers = program
|
|
1869
2684
|
.command("providers")
|
|
1870
|
-
.description("
|
|
2685
|
+
.description("LLM providers on the pod (OpenAI/Anthropic/…) for local coding tools — not capability packs");
|
|
1871
2686
|
providers
|
|
1872
2687
|
.command("list", { isDefault: true })
|
|
1873
2688
|
.description("Show enabled AI providers and their models")
|
|
@@ -1880,14 +2695,36 @@ providers
|
|
|
1880
2695
|
});
|
|
1881
2696
|
providers
|
|
1882
2697
|
.command("pull")
|
|
1883
|
-
.description("Write pod
|
|
2698
|
+
.description("Write pod LLM credentials into opencode or aider, or print the OpenAI-compatible {pod}/v1 endpoint")
|
|
1884
2699
|
.option("--target <name>", "Target tool: opencode | aider")
|
|
1885
2700
|
.option("--pod-url <url>", "Pod URL override")
|
|
1886
2701
|
.option("--api-key <key>", "API key override")
|
|
2702
|
+
.option("--show-key", "With --target show: print the full API key (default: redacted)")
|
|
1887
2703
|
.action(async (opts) => {
|
|
1888
2704
|
const { providersPull } = await import("./commands/providers.js");
|
|
1889
2705
|
await providersPull(opts);
|
|
1890
2706
|
});
|
|
2707
|
+
providers
|
|
2708
|
+
.command("set-key <providerId>")
|
|
2709
|
+
.description("Store your own API key override for a provider (BYOI)")
|
|
2710
|
+
.option("--workspace <id>", "Workspace ID for workspace-scoped override")
|
|
2711
|
+
.option("--api-key <key>", "API key (prompted if omitted)")
|
|
2712
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2713
|
+
.option("--hub-api-key <key>", "Hub API key override")
|
|
2714
|
+
.action(async (opts) => {
|
|
2715
|
+
const { providersSetKey } = await import("./commands/providers.js");
|
|
2716
|
+
await providersSetKey({ ...opts, providerId: opts.providerId });
|
|
2717
|
+
});
|
|
2718
|
+
providers
|
|
2719
|
+
.command("list-keys")
|
|
2720
|
+
.description("List user/workspace-level provider key overrides")
|
|
2721
|
+
.option("--workspace <id>", "Workspace ID to check")
|
|
2722
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
2723
|
+
.option("--hub-api-key <key>", "Hub API key override")
|
|
2724
|
+
.action(async (opts) => {
|
|
2725
|
+
const { providersListKeys } = await import("./commands/providers.js");
|
|
2726
|
+
await providersListKeys(opts);
|
|
2727
|
+
});
|
|
1891
2728
|
// ─── keys ────────────────────────────────────────────────────────────────────
|
|
1892
2729
|
const keys = program
|
|
1893
2730
|
.command("keys")
|
|
@@ -1895,9 +2732,10 @@ const keys = program
|
|
|
1895
2732
|
keys
|
|
1896
2733
|
.command("rotate")
|
|
1897
2734
|
.description("Rotate your CLI key to pick up the latest scope set")
|
|
1898
|
-
.
|
|
2735
|
+
.option("--show-key", "Print the new key in full if it could not be saved to the config")
|
|
2736
|
+
.action(async (opts) => {
|
|
1899
2737
|
const { keysRotate } = await import("./commands/keys.js");
|
|
1900
|
-
await keysRotate({});
|
|
2738
|
+
await keysRotate({ showKey: opts.showKey });
|
|
1901
2739
|
});
|
|
1902
2740
|
// Resolve a global `--pod <name>` before commander parses (it isn't registered
|
|
1903
2741
|
// per-command). Fails fast with a clear message on an unknown profile name.
|