@synap-core/cli 1.7.0 → 1.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/agent-chat.d.ts +47 -0
- package/dist/commands/agent-chat.js +250 -0
- package/dist/commands/agent-chat.js.map +1 -0
- package/dist/commands/agent-run.d.ts +47 -0
- package/dist/commands/agent-run.js +301 -0
- package/dist/commands/agent-run.js.map +1 -0
- package/dist/commands/agents.js +85 -46
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/artifact.d.ts +26 -0
- package/dist/commands/artifact.js +76 -0
- package/dist/commands/artifact.js.map +1 -0
- package/dist/commands/automation.d.ts +47 -0
- package/dist/commands/automation.js +601 -0
- package/dist/commands/automation.js.map +1 -0
- package/dist/commands/bridge-setup.d.ts +66 -0
- package/dist/commands/bridge-setup.js +1112 -0
- package/dist/commands/bridge-setup.js.map +1 -0
- package/dist/commands/cap-connections.d.ts +28 -0
- package/dist/commands/cap-connections.js +224 -0
- package/dist/commands/cap-connections.js.map +1 -0
- package/dist/commands/capability.d.ts +89 -0
- package/dist/commands/capability.js +1523 -0
- package/dist/commands/capability.js.map +1 -0
- package/dist/commands/cell.d.ts +55 -0
- package/dist/commands/cell.js +277 -0
- package/dist/commands/cell.js.map +1 -0
- package/dist/commands/centrality.d.ts +20 -0
- package/dist/commands/centrality.js +94 -0
- package/dist/commands/centrality.js.map +1 -0
- package/dist/commands/connect.d.ts +2 -0
- package/dist/commands/connect.js +25 -10
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/connections.js +0 -16
- package/dist/commands/connections.js.map +1 -1
- package/dist/commands/context.d.ts +22 -0
- package/dist/commands/context.js +149 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/data-extra.d.ts +14 -0
- package/dist/commands/data-extra.js +185 -0
- package/dist/commands/data-extra.js.map +1 -0
- package/dist/commands/data.d.ts +14 -10
- package/dist/commands/data.js +353 -192
- package/dist/commands/data.js.map +1 -1
- package/dist/commands/diagnose.d.ts +20 -0
- package/dist/commands/diagnose.js +143 -0
- package/dist/commands/diagnose.js.map +1 -0
- package/dist/commands/digest.d.ts +17 -0
- package/dist/commands/digest.js +121 -0
- package/dist/commands/digest.js.map +1 -0
- package/dist/commands/discover.d.ts +2 -0
- package/dist/commands/discover.js +25 -8
- package/dist/commands/discover.js.map +1 -1
- package/dist/commands/doc.d.ts +39 -0
- package/dist/commands/doc.js +130 -0
- package/dist/commands/doc.js.map +1 -0
- package/dist/commands/events.d.ts +26 -0
- package/dist/commands/events.js +69 -0
- package/dist/commands/events.js.map +1 -0
- package/dist/commands/explain.d.ts +21 -0
- package/dist/commands/explain.js +251 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/facet.d.ts +29 -0
- package/dist/commands/facet.js +113 -0
- package/dist/commands/facet.js.map +1 -0
- package/dist/commands/graph.d.ts +18 -0
- package/dist/commands/graph.js +74 -0
- package/dist/commands/graph.js.map +1 -0
- package/dist/commands/home.d.ts +12 -0
- package/dist/commands/home.js +54 -0
- package/dist/commands/home.js.map +1 -0
- package/dist/commands/import.d.ts +38 -0
- package/dist/commands/import.js +440 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/init.d.ts +0 -2
- package/dist/commands/init.js +97 -118
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys.d.ts +9 -0
- package/dist/commands/keys.js +78 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/knowledge.d.ts +34 -18
- package/dist/commands/knowledge.js +355 -57
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/launch.d.ts +50 -0
- package/dist/commands/launch.js +790 -0
- package/dist/commands/launch.js.map +1 -0
- package/dist/commands/lens.d.ts +45 -0
- package/dist/commands/lens.js +386 -0
- package/dist/commands/lens.js.map +1 -0
- package/dist/commands/market.d.ts +209 -0
- package/dist/commands/market.js +1368 -0
- package/dist/commands/market.js.map +1 -0
- package/dist/commands/mcp.d.ts +42 -0
- package/dist/commands/mcp.js +184 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/observe.d.ts +9 -0
- package/dist/commands/observe.js +93 -0
- package/dist/commands/observe.js.map +1 -0
- package/dist/commands/open.d.ts +32 -0
- package/dist/commands/open.js +85 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/pod.d.ts +100 -0
- package/dist/commands/pod.js +359 -0
- package/dist/commands/pod.js.map +1 -0
- package/dist/commands/pods.d.ts +6 -0
- package/dist/commands/pods.js +160 -50
- package/dist/commands/pods.js.map +1 -1
- package/dist/commands/proposals-actions.d.ts +7 -0
- package/dist/commands/proposals-actions.js +77 -0
- package/dist/commands/proposals-actions.js.map +1 -0
- package/dist/commands/providers.d.ts +38 -0
- package/dist/commands/providers.js +170 -0
- package/dist/commands/providers.js.map +1 -0
- package/dist/commands/purge.d.ts +23 -0
- package/dist/commands/purge.js +148 -0
- package/dist/commands/purge.js.map +1 -0
- package/dist/commands/raycast.d.ts +15 -0
- package/dist/commands/raycast.js +153 -0
- package/dist/commands/raycast.js.map +1 -0
- package/dist/commands/sessions.d.ts +31 -0
- package/dist/commands/sessions.js +248 -0
- package/dist/commands/sessions.js.map +1 -0
- package/dist/commands/skill-manage.d.ts +21 -0
- package/dist/commands/skill-manage.js +195 -0
- package/dist/commands/skill-manage.js.map +1 -0
- package/dist/commands/skills-commands.d.ts +26 -0
- package/dist/commands/skills-commands.js +187 -0
- package/dist/commands/skills-commands.js.map +1 -0
- package/dist/commands/skills.d.ts +26 -0
- package/dist/commands/skills.js +196 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/status.d.ts +3 -1
- package/dist/commands/status.js +231 -41
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/statusline.d.ts +24 -0
- package/dist/commands/statusline.js +450 -0
- package/dist/commands/statusline.js.map +1 -0
- package/dist/commands/subscribe.d.ts +19 -0
- package/dist/commands/subscribe.js +91 -0
- package/dist/commands/subscribe.js.map +1 -0
- package/dist/commands/tools.d.ts +30 -0
- package/dist/commands/tools.js +315 -0
- package/dist/commands/tools.js.map +1 -0
- package/dist/commands/versions.d.ts +27 -0
- package/dist/commands/versions.js +277 -0
- package/dist/commands/versions.js.map +1 -0
- package/dist/commands/view.d.ts +57 -0
- package/dist/commands/view.js +195 -0
- package/dist/commands/view.js.map +1 -0
- package/dist/commands/whoami.d.ts +21 -0
- package/dist/commands/whoami.js +129 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1524 -202
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-templates.d.ts +25 -0
- package/dist/lib/agent-templates.js +148 -0
- package/dist/lib/agent-templates.js.map +1 -0
- package/dist/lib/agents-config.d.ts +4 -1
- package/dist/lib/agents-config.js +19 -2
- package/dist/lib/agents-config.js.map +1 -1
- package/dist/lib/approval-poll.d.ts +42 -0
- package/dist/lib/approval-poll.js +52 -0
- package/dist/lib/approval-poll.js.map +1 -0
- package/dist/lib/auth.d.ts +29 -6
- package/dist/lib/auth.js +105 -94
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/bundle-version.d.ts +11 -0
- package/dist/lib/bundle-version.js +33 -0
- package/dist/lib/bundle-version.js.map +1 -0
- package/dist/lib/capture-lane.d.ts +67 -0
- package/dist/lib/capture-lane.js +136 -0
- package/dist/lib/capture-lane.js.map +1 -0
- package/dist/lib/cp-packages.d.ts +121 -0
- package/dist/lib/cp-packages.js +218 -0
- package/dist/lib/cp-packages.js.map +1 -0
- package/dist/lib/describe-lens.d.ts +46 -0
- package/dist/lib/describe-lens.js +33 -0
- package/dist/lib/describe-lens.js.map +1 -0
- package/dist/lib/hub-client.d.ts +84 -1
- package/dist/lib/hub-client.js +502 -22
- package/dist/lib/hub-client.js.map +1 -1
- package/dist/lib/installed.d.ts +51 -0
- package/dist/lib/installed.js +70 -0
- package/dist/lib/installed.js.map +1 -0
- package/dist/lib/next-steps.d.ts +61 -0
- package/dist/lib/next-steps.js +146 -0
- package/dist/lib/next-steps.js.map +1 -0
- package/dist/lib/pod.d.ts +104 -19
- package/dist/lib/pod.js +245 -57
- package/dist/lib/pod.js.map +1 -1
- package/dist/lib/project-ref.d.ts +95 -0
- package/dist/lib/project-ref.js +144 -0
- package/dist/lib/project-ref.js.map +1 -0
- package/dist/lib/project.d.ts +35 -0
- package/dist/lib/project.js +39 -0
- package/dist/lib/project.js.map +1 -0
- package/dist/lib/session-lens.d.ts +33 -0
- package/dist/lib/session-lens.js +76 -0
- package/dist/lib/session-lens.js.map +1 -0
- package/dist/lib/skill-import.d.ts +40 -0
- package/dist/lib/skill-import.js +203 -0
- package/dist/lib/skill-import.js.map +1 -0
- package/dist/lib/skills-installer.d.ts +16 -5
- package/dist/lib/skills-installer.js +132 -18
- package/dist/lib/skills-installer.js.map +1 -1
- package/dist/lib/suite.d.ts +28 -0
- package/dist/lib/suite.js +29 -0
- package/dist/lib/suite.js.map +1 -0
- package/dist/lib/superwhisper-import.d.ts +40 -0
- package/dist/lib/superwhisper-import.js +389 -0
- package/dist/lib/superwhisper-import.js.map +1 -0
- package/dist/lib/targets.d.ts +66 -2
- package/dist/lib/targets.js +914 -132
- package/dist/lib/targets.js.map +1 -1
- package/dist/lib/unwrapList.d.ts +1 -0
- package/dist/lib/unwrapList.js +20 -0
- package/dist/lib/unwrapList.js.map +1 -0
- package/dist/utils/logger.d.ts +2 -0
- package/dist/utils/logger.js +10 -2
- package/dist/utils/logger.js.map +1 -1
- package/package.json +10 -4
- package/skills/agent-os/SKILL.md +212 -0
- package/skills/manifest.json +5 -0
- package/skills/onboard/SKILL.md +186 -0
- package/skills/synap/SKILL.md +1524 -104
- package/skills/synap/_order.txt +37 -0
- package/skills/synap/_skill.yaml +24 -0
- package/skills/synap/authentication.md +10 -0
- package/skills/synap/automations.md +264 -0
- package/skills/synap/capabilities.md +107 -0
- package/skills/synap/capture.md +10 -0
- package/skills/synap/cli-operations.md +107 -0
- package/skills/synap/common-mistakes.md +12 -0
- package/skills/synap/creative-loop.md +43 -0
- package/skills/synap/crm.md +117 -0
- package/skills/synap/diagnostics.md +35 -0
- package/skills/synap/digesting-a-channel.md +38 -0
- package/skills/synap/document-embeds.md +123 -0
- package/skills/synap/escalation-ladder.md +71 -0
- package/skills/synap/focus-sessions.md +47 -0
- package/skills/synap/governance-rules.md +64 -0
- package/skills/synap/governance.md +6 -6
- package/skills/synap/graph-gardening.md +21 -0
- package/skills/synap/inline-patterns.md +38 -0
- package/skills/synap/lenses.md +38 -0
- package/skills/synap/linking-principle.md +39 -0
- package/skills/synap/linking.md +1 -0
- package/skills/synap/mental-model.md +45 -0
- package/skills/synap/more.md +7 -0
- package/skills/synap/multi-entity-capture.md +10 -0
- package/skills/synap/next-action.md +37 -0
- package/skills/synap/north-star.md +17 -0
- package/skills/synap/operating-mode-rules.md +45 -0
- package/skills/synap/operating-mode.md +9 -0
- package/skills/synap/quick-reference.md +67 -0
- package/skills/synap/reading.md +43 -0
- package/skills/synap/recap.md +21 -0
- package/skills/synap/reflexes.md +46 -0
- package/skills/synap/response-style.md +21 -0
- package/skills/synap/scope.md +13 -0
- package/skills/synap/showing.md +17 -0
- package/skills/synap/user-model.md +25 -0
- package/skills/synap/viewframe-cells.md +290 -0
- package/skills/synap/work-flow.md +113 -0
- package/skills/synap/worked-examples.md +53 -0
- package/skills/synap/workspace-design.md +45 -0
- package/skills/synap/workspace-edges.md +49 -0
- package/skills/synap/writes.md +156 -0
- package/skills/synap-schema/SKILL.md +97 -6
- package/skills/synap-schema/_order.txt +13 -0
- package/skills/synap-schema/_skill.yaml +22 -0
- package/skills/synap-schema/before-you-touch.md +14 -0
- package/skills/synap-schema/common-mistakes.md +9 -0
- package/skills/synap-schema/creating-profiles.md +17 -0
- package/skills/synap-schema/discover-profiles.md +24 -0
- package/skills/synap-schema/entity-scope.md +8 -0
- package/skills/synap-schema/extend-vs-create.md +31 -0
- package/skills/synap-schema/more.md +6 -0
- package/skills/synap-schema/overlay-properties.md +22 -0
- package/skills/synap-schema/profiles.md +3 -0
- package/skills/synap-schema/property-defs.md +29 -0
- package/skills/synap-schema/read-before-write.md +50 -0
- package/skills/synap-schema/relations.md +18 -0
- package/skills/synap-schema/worked-example.md +30 -0
- package/skills/synap-ui/SKILL.md +38 -11
- package/skills/synap-ui/_order.txt +13 -0
- package/skills/synap-ui/_skill.yaml +23 -0
- package/skills/synap-ui/ai-companion.md +27 -0
- package/skills/synap-ui/arranging-bento.md +8 -0
- package/skills/synap-ui/before-you-build.md +20 -0
- package/skills/synap-ui/bento-layouts.md +35 -0
- package/skills/synap-ui/common-mistakes.md +10 -0
- package/skills/synap-ui/creating-views.md +26 -0
- package/skills/synap-ui/four-builds.md +24 -0
- package/skills/synap-ui/more.md +7 -0
- package/skills/synap-ui/proposing-vs-extending.md +11 -0
- package/skills/synap-ui/view-list.md +24 -0
- package/skills/synap-ui/views.md +3 -0
- package/skills/synap-ui/worked-example.md +18 -0
- package/skills/synap-ui/workspaces.md +47 -0
- package/templates/automations/bookmark-enrichment.automation.json +44 -0
- package/templates/automations/mail-feed.automation.json +86 -0
- package/templates/automations/url-bookmark-capture.automation.json +70 -0
- package/templates/skills/README.md +21 -0
- package/templates/skills/authoring-automations/SKILL.md +95 -0
- package/templates/skills/authoring-automations/reference/node-matrix.md +49 -0
- package/templates/skills/authoring-capabilities/SKILL.md +93 -0
- package/templates/skills/authoring-capabilities/reference/template-anatomy.md +70 -0
- package/templates/skills/authoring-playbooks/SKILL.md +102 -0
- package/templates/skills/authoring-playbooks/reference/stages-contract.md +35 -0
- package/templates/skills/authoring-playbooks/reference/worked-example.md +64 -0
- package/templates/skills/bookmark-enrichment/SKILL.md +40 -0
- package/templates/skills/coordinating-agents/SKILL.md +32 -0
- package/templates/skills/coordinating-branches/SKILL.md +27 -0
- package/templates/skills/mapping-the-server/SKILL.md +54 -0
- package/templates/skills/reading-client-progress/SKILL.md +65 -0
- package/templates/skills/routing-to-channels/SKILL.md +54 -0
- package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-CHEATSHEET.md +133 -0
- package/templates/skills/stellar-scf-grants-advisor/ASSOCIATE-ONBOARDING-GUIDE.md +761 -0
- package/templates/skills/stellar-scf-grants-advisor/CLIENT-FAQ.md +181 -0
- package/templates/skills/stellar-scf-grants-advisor/PARTNER-HANDOVER.md +130 -0
- package/templates/skills/stellar-scf-grants-advisor/SKILL.md +102 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/README.md +43 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/chat-summary-templates.md +158 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/corpus-comparable-rows.md +136 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/q10-team-rewrites.md +109 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/q2-description-rewrites.md +88 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/q6-integration-rewrites.md +107 -0
- package/templates/skills/stellar-scf-grants-advisor/examples/tranche-structures.md +176 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/01-methodology.md +96 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/02-scoring-framework.md +199 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/03-rejection-patterns.md +241 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/04-winner-patterns.md +120 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/05-comeback-patterns.md +92 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/06-budget-benchmarks.md +125 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/07-integration-list.md +147 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/08-abstract-fields.md +258 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/09-build-fields.md +259 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/10-corpus-winners.md +135 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/11-corpus-rejects.md +267 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/12-client-communication.md +131 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/13-excel-output-spec.md +199 -0
- package/templates/skills/stellar-scf-grants-advisor/reference/14-worked-examples.md +160 -0
- package/templates/skills/stellar-scf-grants-advisor/templates/abstract-review-builder.py +253 -0
- package/templates/skills/stellar-scf-grants-advisor/templates/build-review-builder.py +213 -0
- package/dist/commands/finish.d.ts +0 -25
- package/dist/commands/finish.js +0 -274
- package/dist/commands/finish.js.map +0 -1
- package/dist/commands/openclaw.d.ts +0 -40
- package/dist/commands/openclaw.js +0 -1148
- package/dist/commands/openclaw.js.map +0 -1
- package/dist/commands/security-audit.d.ts +0 -12
- package/dist/commands/security-audit.js +0 -100
- package/dist/commands/security-audit.js.map +0 -1
- package/dist/lib/hardening.d.ts +0 -18
- package/dist/lib/hardening.js +0 -214
- package/dist/lib/hardening.js.map +0 -1
- package/dist/lib/templates.d.ts +0 -11
- package/dist/lib/templates.js +0 -13
- package/dist/lib/templates.js.map +0 -1
- package/dist/templates/agent-os.json +0 -3090
- package/node_modules/@synap/hub-rest-client/dist/index.cjs +0 -881
- package/node_modules/@synap/hub-rest-client/dist/index.d.cts +0 -907
- package/node_modules/@synap/hub-rest-client/dist/index.d.ts +0 -907
- package/node_modules/@synap/hub-rest-client/dist/index.js +0 -851
- package/node_modules/@synap/hub-rest-client/package.json +0 -45
- package/node_modules/@synap/hub-rest-client/src/client.ts +0 -1143
- package/node_modules/@synap/hub-rest-client/src/errors.ts +0 -30
- package/node_modules/@synap/hub-rest-client/src/index.ts +0 -111
- package/node_modules/@synap/hub-rest-client/src/setup.ts +0 -77
- package/node_modules/@synap/hub-rest-client/src/types.ts +0 -639
package/dist/index.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @synap/cli — Connect
|
|
3
|
+
* @synap/cli — Connect AI agents to your Synap data pod
|
|
4
4
|
*
|
|
5
5
|
* Usage:
|
|
6
6
|
* npx @synap/cli init Full setup: detect, harden, connect, install
|
|
7
|
-
* npx @synap/cli connect Connect
|
|
8
|
-
* npx @synap/cli
|
|
9
|
-
* npx @synap/cli status Show pod + OpenClaw health
|
|
7
|
+
* npx @synap/cli connect Connect an AI surface to a Synap pod
|
|
8
|
+
* npx @synap/cli status Show pod health and API status
|
|
10
9
|
* npx @synap/cli update Update skill + check for CLI updates
|
|
11
10
|
*
|
|
12
11
|
* Or install globally:
|
|
@@ -17,6 +16,7 @@ import { Command } from "commander";
|
|
|
17
16
|
import { readFileSync } from "fs";
|
|
18
17
|
import { fileURLToPath } from "url";
|
|
19
18
|
import { dirname, join } from "path";
|
|
19
|
+
import { bootstrapPodOverride } from "./lib/pod.js";
|
|
20
20
|
const __filename = fileURLToPath(import.meta.url);
|
|
21
21
|
const __dirname = dirname(__filename);
|
|
22
22
|
let version = "0.1.0";
|
|
@@ -30,38 +30,69 @@ catch {
|
|
|
30
30
|
const program = new Command();
|
|
31
31
|
program
|
|
32
32
|
.name("synap")
|
|
33
|
-
.description("Synap CLI — connect
|
|
34
|
-
.version(version)
|
|
33
|
+
.description("Synap CLI — connect AI agents to your data pod")
|
|
34
|
+
.version(version)
|
|
35
|
+
.showSuggestionAfterError(true)
|
|
36
|
+
// Global, position-independent: target a saved pod profile for THIS command
|
|
37
|
+
// only (see `synap pods`). Consumed pre-parse by bootstrapPodOverride so it
|
|
38
|
+
// works in any position and overrides the default/env pod for one invocation.
|
|
39
|
+
.option("--pod <name>", "Run this command against a saved pod profile (overrides the default pod for this invocation only)");
|
|
35
40
|
program
|
|
36
41
|
.command("init")
|
|
37
|
-
.description("Full setup:
|
|
42
|
+
.description("Full setup: connect to a Synap pod and install the skill")
|
|
38
43
|
.option("--pod-url <url>", "Synap pod URL (skip pod choice prompt)")
|
|
39
44
|
.option("--api-key <key>", "Hub Protocol API key (skip key generation)")
|
|
40
|
-
.option("--skip-security", "Skip security hardening step")
|
|
41
45
|
.option("--skip-is", "Skip Intelligence Service provider setup")
|
|
42
46
|
.action(async (opts) => {
|
|
43
47
|
const { init } = await import("./commands/init.js");
|
|
44
48
|
await init(opts);
|
|
45
49
|
});
|
|
50
|
+
// ── launch — nothing → a working company (project + domain workspaces) ────────
|
|
51
|
+
// Not a template browser: `--list` shows what's launchable (local, no pod),
|
|
52
|
+
// bare `synap launch` runs the guided one-per-company setup.
|
|
46
53
|
program
|
|
47
|
-
.command("
|
|
48
|
-
.description("
|
|
49
|
-
.option("--
|
|
50
|
-
.option("--
|
|
51
|
-
.option("--
|
|
54
|
+
.command("launch")
|
|
55
|
+
.description("Stand up a NEW company/OS on a pod — creates a project + its core workspaces (interactive)")
|
|
56
|
+
.option("--list", "List what can be launched (local templates, no pod needed) and exit")
|
|
57
|
+
.option("--search <query>", "Filter --list by name/description/slug")
|
|
58
|
+
.option("--type <type>", "Filter --list by package type (workspace|capability|skill|workflow|view|cell)")
|
|
59
|
+
.option("--json", "Output as JSON")
|
|
60
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
61
|
+
.option("--api-key <key>", "API key override")
|
|
52
62
|
.action(async (opts) => {
|
|
53
|
-
const {
|
|
54
|
-
await
|
|
63
|
+
const { launch } = await import("./commands/launch.js");
|
|
64
|
+
await launch(opts);
|
|
65
|
+
});
|
|
66
|
+
// Hidden: one-shot Discord↔Synap bridge provisioning (dogfood/dev convenience).
|
|
67
|
+
program
|
|
68
|
+
.command("bridge-setup", { hidden: true })
|
|
69
|
+
.description("(hidden) One-shot Discord↔Synap bridge provisioning")
|
|
70
|
+
.option("--client-id <id>", "Discord application (client) id — prints the invite URL")
|
|
71
|
+
.option("--bot-token <token>", "Discord bot token — provisioned into the pod vault")
|
|
72
|
+
.option("--guild-id <id>", "Discord server (guild) id — written to the bridge .env")
|
|
73
|
+
.option("--bridge-dir <path>", "Path to the telegram-discord-bridge repo")
|
|
74
|
+
.option("--workspace-id <uuid>", "Target workspace (default: pod profile's)")
|
|
75
|
+
.option("--proactive-channel <id>", "Discord channel id for the agent's proactive posts")
|
|
76
|
+
.option("--enable-react", "Turn on ✅-react capture")
|
|
77
|
+
.option("--pod <name>", "Pod profile to connect the bridge to (default: prompt)")
|
|
78
|
+
.option("--governance <mode>", "Agent governance preset: safe | normal | crazy (default: prompt)")
|
|
79
|
+
.option("--pod-url <url>", "Synap pod URL (override)")
|
|
80
|
+
.option("--api-key <key>", "Hub Protocol API key (override)")
|
|
81
|
+
.action(async (opts) => {
|
|
82
|
+
const { bridgeSetup } = await import("./commands/bridge-setup.js");
|
|
83
|
+
await bridgeSetup(opts);
|
|
55
84
|
});
|
|
56
85
|
program
|
|
57
86
|
.command("connect")
|
|
58
|
-
.description("Connect an AI surface (Claude Code, Claude Desktop, Cursor, Raycast
|
|
59
|
-
.option("--target <name>", "AI surface: claude-code | claude-desktop | cursor | raycast |
|
|
87
|
+
.description("Connect an AI surface (Claude Code, Claude Desktop, Cursor, Raycast) to a Synap pod")
|
|
88
|
+
.option("--target <name>", "AI surface: claude-code | claude-desktop | cursor | raycast | custom")
|
|
60
89
|
.option("--pod-url <url>", "Synap pod URL")
|
|
61
90
|
.option("--api-key <key>", "Hub Protocol API key")
|
|
62
91
|
.option("--name <name>", "Pod profile name to save credentials under (default: 'default')")
|
|
63
92
|
.option("--list", "List supported targets and exit")
|
|
64
93
|
.option("--manual-key", "Skip the browser approval flow and paste a key (or provisioning token)")
|
|
94
|
+
.option("--pin-workspace <id>", "Pin the connection to one workspace (default: pod-wide lens)")
|
|
95
|
+
.option("--pin-project <id>", "Pin the connection to one project (composable with --pin-workspace)")
|
|
65
96
|
.action(async (opts) => {
|
|
66
97
|
const { connect } = await import("./commands/connect.js");
|
|
67
98
|
await connect(opts);
|
|
@@ -87,10 +118,11 @@ pods
|
|
|
87
118
|
pods
|
|
88
119
|
.command("use <name>")
|
|
89
120
|
.description("Switch active pod and propagate credentials to all agent surfaces")
|
|
90
|
-
.option("--surface <surface>", "Only switch this surface (raycast, claude-code, claude-desktop, cursor
|
|
121
|
+
.option("--surface <surface>", "Only switch this surface (raycast, claude-code, claude-desktop, cursor)")
|
|
122
|
+
.option("--json", "Output as JSON (incl. nextSteps for agents; full-switch only)")
|
|
91
123
|
.action(async (name, opts) => {
|
|
92
124
|
const { podsUse } = await import("./commands/pods.js");
|
|
93
|
-
await podsUse(name, { surface: opts.surface });
|
|
125
|
+
await podsUse(name, { surface: opts.surface, json: opts.json });
|
|
94
126
|
});
|
|
95
127
|
pods
|
|
96
128
|
.command("remove <name>")
|
|
@@ -100,22 +132,44 @@ pods
|
|
|
100
132
|
const { podsRemove } = await import("./commands/pods.js");
|
|
101
133
|
await podsRemove(name);
|
|
102
134
|
});
|
|
135
|
+
pods
|
|
136
|
+
.command("reconnect [name]")
|
|
137
|
+
.description("Re-authenticate a saved pod (refresh API key without re-entering the URL)")
|
|
138
|
+
.action(async (name) => {
|
|
139
|
+
const { podsReconnect } = await import("./commands/pods.js");
|
|
140
|
+
await podsReconnect(name);
|
|
141
|
+
});
|
|
103
142
|
program
|
|
104
|
-
.command("
|
|
105
|
-
.
|
|
106
|
-
.
|
|
107
|
-
.option("--fix", "Auto-fix issues where possible")
|
|
108
|
-
.option("--json", "Output results as JSON")
|
|
143
|
+
.command("status")
|
|
144
|
+
.description("Show Synap pod health and API status")
|
|
145
|
+
.option("--json", "Dump raw status (incl. release/migration detail) as JSON")
|
|
109
146
|
.action(async (opts) => {
|
|
110
|
-
const {
|
|
111
|
-
await
|
|
147
|
+
const { status } = await import("./commands/status.js");
|
|
148
|
+
await status({ json: opts.json });
|
|
112
149
|
});
|
|
113
150
|
program
|
|
114
|
-
.command("
|
|
115
|
-
.description("Show
|
|
151
|
+
.command("versions")
|
|
152
|
+
.description("Show LOCAL vs NPM vs CONTROL-PLANE vs POD version drift for workspace-templates, api-types, and capabilities")
|
|
153
|
+
.option("--json", "Output structured {artifacts:[...]} JSON")
|
|
154
|
+
.action(async (opts) => {
|
|
155
|
+
const { versions } = await import("./commands/versions.js");
|
|
156
|
+
await versions({ json: opts.json });
|
|
157
|
+
});
|
|
158
|
+
program
|
|
159
|
+
.command("whoami")
|
|
160
|
+
.description("Show the winning API key's identity/scopes/workspace and flag env-vs-surface key divergence")
|
|
116
161
|
.action(async () => {
|
|
117
|
-
const {
|
|
118
|
-
await
|
|
162
|
+
const { whoami } = await import("./commands/whoami.js");
|
|
163
|
+
await whoami();
|
|
164
|
+
});
|
|
165
|
+
// Hidden: compact ANSI line for the Claude Code statusLine (reads stdin JSON).
|
|
166
|
+
program
|
|
167
|
+
.command("statusline", { hidden: true })
|
|
168
|
+
.description("(internal) Compact ANSI status line for Claude Code")
|
|
169
|
+
.option("--refresh", "Refresh the pod cache (run detached in the background)")
|
|
170
|
+
.action(async (opts) => {
|
|
171
|
+
const { statusline } = await import("./commands/statusline.js");
|
|
172
|
+
await statusline({ refresh: opts.refresh });
|
|
119
173
|
});
|
|
120
174
|
program
|
|
121
175
|
.command("update")
|
|
@@ -126,101 +180,6 @@ program
|
|
|
126
180
|
const { update } = await import("./commands/update.js");
|
|
127
181
|
await update(opts);
|
|
128
182
|
});
|
|
129
|
-
const oc = program
|
|
130
|
-
.command("openclaw")
|
|
131
|
-
.alias("oc")
|
|
132
|
-
.description("Access, configure, and connect OpenClaw");
|
|
133
|
-
oc
|
|
134
|
-
.command("status", { isDefault: true })
|
|
135
|
-
.description("Overview: gateway status, AI key, skill, how to connect")
|
|
136
|
-
.action(async () => {
|
|
137
|
-
const { openclawOverview } = await import("./commands/openclaw.js");
|
|
138
|
-
await openclawOverview();
|
|
139
|
-
});
|
|
140
|
-
oc
|
|
141
|
-
.command("dashboard")
|
|
142
|
-
.alias("dash")
|
|
143
|
-
.description("Open the OpenClaw web UI (or print SSH tunnel instructions for remote servers)")
|
|
144
|
-
.action(async () => {
|
|
145
|
-
const { openclawDashboard } = await import("./commands/openclaw.js");
|
|
146
|
-
openclawDashboard();
|
|
147
|
-
});
|
|
148
|
-
oc
|
|
149
|
-
.command("connect")
|
|
150
|
-
.description("Show MCP client configs for Claude Desktop, Cursor, Windsurf")
|
|
151
|
-
.option("--client <name>", "Specific client: claude, cursor, windsurf")
|
|
152
|
-
.action(async (opts) => {
|
|
153
|
-
const { openclawConnect } = await import("./commands/openclaw.js");
|
|
154
|
-
await openclawConnect(opts);
|
|
155
|
-
});
|
|
156
|
-
oc
|
|
157
|
-
.command("configure")
|
|
158
|
-
.alias("config")
|
|
159
|
-
.description("Set AI provider API key via OpenClaw's own config system")
|
|
160
|
-
.option("-i, --interactive", "Run OpenClaw's own interactive wizard")
|
|
161
|
-
.option("--provider <name>", "Provider: anthropic | openai | google")
|
|
162
|
-
.option("--key <key>", "API key (non-interactive)")
|
|
163
|
-
.option("--model <id>", "Model id (e.g. anthropic/claude-sonnet-4-6)")
|
|
164
|
-
.option("--show", "Print the current config")
|
|
165
|
-
.action(async (opts) => {
|
|
166
|
-
const { openclawConfigure } = await import("./commands/openclaw.js");
|
|
167
|
-
await openclawConfigure(opts);
|
|
168
|
-
});
|
|
169
|
-
oc
|
|
170
|
-
.command("token")
|
|
171
|
-
.description("Print the OpenClaw gateway token (for MCP clients)")
|
|
172
|
-
.option("--copy", "Copy to clipboard instead of printing")
|
|
173
|
-
.option("--for <client>", "Print a pre-filled MCP config (claude, cursor, windsurf)")
|
|
174
|
-
.action(async (opts) => {
|
|
175
|
-
const { openclawToken } = await import("./commands/openclaw.js");
|
|
176
|
-
openclawToken(opts);
|
|
177
|
-
});
|
|
178
|
-
oc
|
|
179
|
-
.command("doctor")
|
|
180
|
-
.description("Run OpenClaw's diagnostic (openclaw doctor)")
|
|
181
|
-
.option("--fix", "Auto-fix detected issues")
|
|
182
|
-
.action(async (opts) => {
|
|
183
|
-
const { openclawDoctor } = await import("./commands/openclaw.js");
|
|
184
|
-
openclawDoctor(opts);
|
|
185
|
-
});
|
|
186
|
-
oc
|
|
187
|
-
.command("logs")
|
|
188
|
-
.description("Tail OpenClaw container logs")
|
|
189
|
-
.option("-n, --lines <n>", "Number of log lines", "50")
|
|
190
|
-
.option("-f, --follow", "Follow log output")
|
|
191
|
-
.action(async (opts) => {
|
|
192
|
-
const { openclawLogs } = await import("./commands/openclaw.js");
|
|
193
|
-
openclawLogs({ lines: opts.lines ? parseInt(opts.lines, 10) : 50, follow: opts.follow });
|
|
194
|
-
});
|
|
195
|
-
oc
|
|
196
|
-
.command("restart")
|
|
197
|
-
.description("Restart the OpenClaw container")
|
|
198
|
-
.action(async () => {
|
|
199
|
-
const { openclawRestart } = await import("./commands/openclaw.js");
|
|
200
|
-
await openclawRestart();
|
|
201
|
-
});
|
|
202
|
-
oc
|
|
203
|
-
.command("setup-domain")
|
|
204
|
-
.description("Expose the OpenClaw dashboard via a public HTTPS subdomain (Caddy)")
|
|
205
|
-
.action(async () => {
|
|
206
|
-
const { openclawSetupDomain } = await import("./commands/openclaw.js");
|
|
207
|
-
openclawSetupDomain();
|
|
208
|
-
});
|
|
209
|
-
oc
|
|
210
|
-
.command("connections")
|
|
211
|
-
.alias("conn")
|
|
212
|
-
.description("Unified view: AI providers, skills, channels, MCP clients")
|
|
213
|
-
.action(async () => {
|
|
214
|
-
const { openclawConnections } = await import("./commands/openclaw.js");
|
|
215
|
-
openclawConnections();
|
|
216
|
-
});
|
|
217
|
-
oc
|
|
218
|
-
.command("open [section]")
|
|
219
|
-
.description("Open the OpenClaw dashboard (optionally at a section: channels, skills, config, chat, sessions, logs)")
|
|
220
|
-
.action(async (section) => {
|
|
221
|
-
const { openclawOpen } = await import("./commands/openclaw.js");
|
|
222
|
-
openclawOpen(section);
|
|
223
|
-
});
|
|
224
183
|
// ─── infra ────────────────────────────────────────────────────────────────────
|
|
225
184
|
const infra = program
|
|
226
185
|
.command("infra")
|
|
@@ -278,73 +237,202 @@ program
|
|
|
278
237
|
program
|
|
279
238
|
.command("connections")
|
|
280
239
|
.alias("conn")
|
|
281
|
-
.description("Show which pod each agent surface (Claude Code, Desktop, Cursor,
|
|
240
|
+
.description("Show which pod each agent surface (Claude Code, Desktop, Cursor, Raycast) is connected to")
|
|
282
241
|
.action(async () => {
|
|
283
242
|
const { connections } = await import("./commands/connections.js");
|
|
284
243
|
await connections();
|
|
285
244
|
});
|
|
245
|
+
// ─── mcp ────────────────────────────────────────────────────────────────────
|
|
246
|
+
// The MCP front door: point any AI client at the pod's /mcp server.
|
|
247
|
+
const mcp = program
|
|
248
|
+
.command("mcp")
|
|
249
|
+
.description("Connect any AI client to your pod's MCP server (the ambient tool layer)");
|
|
250
|
+
mcp
|
|
251
|
+
.command("url")
|
|
252
|
+
.description("Print a ready-to-paste MCP connection (URL + key + snippets) for UI clients like ChatGPT")
|
|
253
|
+
.option("--client <name>", "Name the dedicated agent key after the target client")
|
|
254
|
+
.option("--workspace <id>", "Scope to a specific workspace (omit for pod-wide)")
|
|
255
|
+
.option("--project <id>", "Focus the agent on a project (narrows every tool call; orthogonal to --workspace)")
|
|
256
|
+
.option("--json", "Output as JSON")
|
|
257
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
258
|
+
.option("--api-key <key>", "API key override")
|
|
259
|
+
.action(async (opts) => {
|
|
260
|
+
const { mcpUrl } = await import("./commands/mcp.js");
|
|
261
|
+
await mcpUrl(opts);
|
|
262
|
+
});
|
|
263
|
+
mcp
|
|
264
|
+
.command("verify")
|
|
265
|
+
.description("Health-check: is the pod's /mcp endpoint reachable and the key valid?")
|
|
266
|
+
.option("--workspace <id>", "Scope to a specific workspace")
|
|
267
|
+
.option("--json", "Output as JSON")
|
|
268
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
269
|
+
.option("--api-key <key>", "API key override")
|
|
270
|
+
.action(async (opts) => {
|
|
271
|
+
const { mcpVerify } = await import("./commands/mcp.js");
|
|
272
|
+
await mcpVerify(opts);
|
|
273
|
+
});
|
|
274
|
+
mcp
|
|
275
|
+
.command("connect [client]")
|
|
276
|
+
.description("Write the MCP config for a file-configurable client (Claude Code, Cursor, Desktop, …) — alias of `synap connect`")
|
|
277
|
+
.option("--name <name>", "Pod profile to connect")
|
|
278
|
+
.action(async (client, opts) => {
|
|
279
|
+
const { connect } = await import("./commands/connect.js");
|
|
280
|
+
await connect({ target: client, name: opts.name });
|
|
281
|
+
});
|
|
286
282
|
program
|
|
287
283
|
.command("login")
|
|
288
|
-
.description("
|
|
289
|
-
.option("--
|
|
284
|
+
.description("Connect your Synap account (private templates) + your pods")
|
|
285
|
+
.option("--reconnect [name]", "Re-authenticate a saved pod without re-entering its URL")
|
|
290
286
|
.action(async (opts) => {
|
|
291
287
|
const chalk = (await import("chalk")).default;
|
|
292
|
-
const
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
if (creds) {
|
|
299
|
-
spinner.succeed(`Authenticated as ${creds.email}`);
|
|
300
|
-
}
|
|
301
|
-
else {
|
|
302
|
-
spinner.fail("Token is invalid or expired. Get a token at https://synap.live/account/tokens");
|
|
303
|
-
}
|
|
288
|
+
const { listPodProfiles } = await import("./lib/pod.js");
|
|
289
|
+
// --reconnect: delegate to reconnect flow
|
|
290
|
+
if (opts.reconnect !== undefined) {
|
|
291
|
+
const name = typeof opts.reconnect === "string" ? opts.reconnect : undefined;
|
|
292
|
+
const { podsReconnect } = await import("./commands/pods.js");
|
|
293
|
+
await podsReconnect(name);
|
|
304
294
|
return;
|
|
305
295
|
}
|
|
306
|
-
const
|
|
307
|
-
if (
|
|
308
|
-
|
|
296
|
+
const profiles = listPodProfiles();
|
|
297
|
+
if (profiles.length === 0) {
|
|
298
|
+
// No pod saved — guide to pods add
|
|
299
|
+
console.log(chalk.dim(" No pod configured yet."));
|
|
300
|
+
console.log(chalk.blue(" Adding a new pod...\n"));
|
|
301
|
+
const { podsAdd } = await import("./commands/pods.js");
|
|
302
|
+
await podsAdd();
|
|
309
303
|
return;
|
|
310
304
|
}
|
|
311
|
-
|
|
312
|
-
const
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
305
|
+
// Already have pods — show status and offer reconnect if any are unreachable
|
|
306
|
+
const { checkPodHealth } = await import("./lib/pod.js");
|
|
307
|
+
const ora = (await import("ora")).default;
|
|
308
|
+
const spinner = ora("Checking pods + credentials...").start();
|
|
309
|
+
const checks = await Promise.all(profiles.map(async (p) => {
|
|
310
|
+
const h = await checkPodHealth(p.config.podUrl).catch(() => ({ healthy: false }));
|
|
311
|
+
// A pod can be HEALTHY (public /health) while the saved key is REVOKED.
|
|
312
|
+
// Validate the actual credential too — otherwise a dead key looks "ok"
|
|
313
|
+
// and the user gets cryptic 401s downstream (the connect trap).
|
|
314
|
+
let keyValid = false;
|
|
315
|
+
if (h.healthy && p.config.hubApiKey) {
|
|
316
|
+
try {
|
|
317
|
+
const res = await fetch(`${p.config.podUrl.replace(/\/$/, "")}/api/hub/auth/status`, {
|
|
318
|
+
headers: { Authorization: `Bearer ${p.config.hubApiKey}` },
|
|
319
|
+
signal: AbortSignal.timeout(6000),
|
|
320
|
+
});
|
|
321
|
+
keyValid = res.ok;
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
keyValid = false;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return { ...p, healthy: h.healthy, keyValid };
|
|
328
|
+
}));
|
|
329
|
+
spinner.stop();
|
|
330
|
+
console.log("\n Configured pods:\n");
|
|
331
|
+
for (const p of checks) {
|
|
332
|
+
const active = p.active ? chalk.green(" ● ") : " ";
|
|
333
|
+
const status = !p.healthy
|
|
334
|
+
? chalk.red("unreachable")
|
|
335
|
+
: p.keyValid
|
|
336
|
+
? chalk.green("ok")
|
|
337
|
+
: chalk.yellow("key expired");
|
|
338
|
+
console.log(` ${active}${chalk.bold(p.name.padEnd(14))} ${status} ${chalk.dim(p.config.podUrl)}`);
|
|
339
|
+
}
|
|
340
|
+
console.log();
|
|
341
|
+
// Anything that won't authenticate — unreachable OR a revoked/expired key.
|
|
342
|
+
const needsReconnect = checks.filter((p) => !p.healthy || !p.keyValid);
|
|
343
|
+
if (needsReconnect.length > 0) {
|
|
344
|
+
console.log(chalk.yellow(` ${needsReconnect.length} pod(s) need re-authentication. Refresh credentials:`));
|
|
345
|
+
for (const p of needsReconnect) {
|
|
346
|
+
console.log(chalk.dim(` synap login --reconnect ${p.name}`));
|
|
347
|
+
}
|
|
348
|
+
console.log();
|
|
316
349
|
}
|
|
317
350
|
else {
|
|
318
|
-
|
|
319
|
-
|
|
351
|
+
console.log(chalk.green(" All pods healthy."));
|
|
352
|
+
const active = checks.find((p) => p.active);
|
|
353
|
+
if (active)
|
|
354
|
+
console.log(chalk.dim(` Active: ${active.name} (${active.config.podUrl})`));
|
|
320
355
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
const {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
356
|
+
// ── Synap ACCOUNT (control plane) — a FIRST-CLASS half of "login" ──────
|
|
357
|
+
// Pods authenticate DATA access; the ACCOUNT authenticates the control plane
|
|
358
|
+
// (private templates like The Arch, hosted pods, marketplace publishing).
|
|
359
|
+
// They are different credentials, and pods alone never unlock private
|
|
360
|
+
// templates — so this gets its own headed section, not a footnote. `synap
|
|
361
|
+
// launch`'s "private templates after 'synap login'" hint lands HERE.
|
|
362
|
+
const { isLoggedIn: cpLoggedIn, login: cpLogin } = await import("./lib/auth.js");
|
|
363
|
+
console.log("\n Synap account:\n");
|
|
364
|
+
const account = await cpLoggedIn();
|
|
365
|
+
let accountEmail;
|
|
366
|
+
if (account.valid) {
|
|
367
|
+
accountEmail = account.email;
|
|
368
|
+
console.log(` ${chalk.green("●")} ${chalk.bold(account.email ?? "logged in")} ${chalk.dim("— private templates available")}`);
|
|
332
369
|
}
|
|
333
370
|
else {
|
|
334
|
-
console.log(chalk.
|
|
371
|
+
console.log(` ${chalk.yellow("○")} ${chalk.bold("not logged in")} ${chalk.dim("— your private templates (e.g. The Arch) are hidden until you log in")}`);
|
|
372
|
+
const prompts = (await import("prompts")).default;
|
|
373
|
+
const { doLogin } = await prompts({
|
|
374
|
+
type: "confirm",
|
|
375
|
+
name: "doLogin",
|
|
376
|
+
message: "Log in to your Synap account now?",
|
|
377
|
+
initial: true,
|
|
378
|
+
});
|
|
379
|
+
if (doLogin) {
|
|
380
|
+
const creds = await cpLogin();
|
|
381
|
+
if (creds?.email) {
|
|
382
|
+
accountEmail = creds.email;
|
|
383
|
+
console.log(chalk.green(` ✓ Logged in as ${creds.email} — private templates unlocked.`));
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
console.log(chalk.dim(" Later: synap login · or synap login --token <token> (synap.live/account/tokens)"));
|
|
388
|
+
}
|
|
335
389
|
}
|
|
390
|
+
const { renderNextSteps, FLOW } = await import("./lib/next-steps.js");
|
|
391
|
+
renderNextSteps(FLOW.afterLogin(accountEmail));
|
|
336
392
|
});
|
|
337
393
|
// ─── orient ───────────────────────────────────────────────────────────────────
|
|
338
394
|
program
|
|
339
395
|
.command("orient")
|
|
340
|
-
.description("Show
|
|
396
|
+
.description("Show a lightweight lens map: who you are, your projects (companies/initiatives), and workspaces (operational domains)")
|
|
341
397
|
.option("--json", "Output as JSON")
|
|
398
|
+
.option("--details", "Include per-workspace profiles + entity counts (heavier)")
|
|
342
399
|
.option("--pod-url <url>", "Pod URL override")
|
|
343
400
|
.option("--api-key <key>", "API key override")
|
|
344
401
|
.action(async (opts) => {
|
|
345
402
|
const { orient } = await import("./commands/data.js");
|
|
346
403
|
await orient(opts);
|
|
347
404
|
});
|
|
405
|
+
// ─── digest ─────────────────────────────────────────────────────────────────
|
|
406
|
+
// A quick read of what's already in a workspace or project (counts + key
|
|
407
|
+
// entities + summary). Default = the active workspace lens.
|
|
408
|
+
program
|
|
409
|
+
.command("digest")
|
|
410
|
+
.description("Summarize what's in a workspace or project (counts + key entities)")
|
|
411
|
+
.option("--workspace <id|name>", "Workspace to digest (defaults to active workspace lens)")
|
|
412
|
+
.option("--project <id|name>", "Project to digest (cross-cutting lens)")
|
|
413
|
+
.option("--json", "Output raw JSON")
|
|
414
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
415
|
+
.option("--api-key <key>", "API key override")
|
|
416
|
+
.action(async (opts) => {
|
|
417
|
+
const { digest } = await import("./commands/digest.js");
|
|
418
|
+
await digest(opts);
|
|
419
|
+
});
|
|
420
|
+
// ─── diagnose ────────────────────────────────────────────────────────────────
|
|
421
|
+
// See what an AI did across flows: the unified run feed, or one run's activity
|
|
422
|
+
// timeline (for a capture: WHY a facet/entity dropped, with a fixHint).
|
|
423
|
+
program
|
|
424
|
+
.command("diagnose [runId]")
|
|
425
|
+
.description("See what an AI did — the run feed, or one run's activity (why it did what it did)")
|
|
426
|
+
.option("--flow <automation|playbook|capture|session>", "Restrict the feed, or the run's flow (default capture for a runId)")
|
|
427
|
+
.option("--flow-id <id>", "Restrict the feed to one flow's runs (automationId / playbookId)")
|
|
428
|
+
.option("--limit <n>", "Max runs in the feed")
|
|
429
|
+
.option("--json", "Output raw JSON")
|
|
430
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
431
|
+
.option("--api-key <key>", "API key override")
|
|
432
|
+
.action(async (runId, opts) => {
|
|
433
|
+
const { diagnose } = await import("./commands/diagnose.js");
|
|
434
|
+
await diagnose(runId, opts);
|
|
435
|
+
});
|
|
348
436
|
// ─── use ──────────────────────────────────────────────────────────────────────
|
|
349
437
|
program
|
|
350
438
|
.command("use <workspace>")
|
|
@@ -356,68 +444,171 @@ program
|
|
|
356
444
|
const { useWorkspace } = await import("./commands/data.js");
|
|
357
445
|
await useWorkspace(workspace, opts);
|
|
358
446
|
});
|
|
359
|
-
// ───
|
|
360
|
-
program
|
|
361
|
-
.command("
|
|
362
|
-
.description("
|
|
363
|
-
|
|
364
|
-
.
|
|
365
|
-
.
|
|
447
|
+
// ─── project / lens (per-Claude-session scoping) ──────────────────────────────
|
|
448
|
+
const project = program
|
|
449
|
+
.command("project")
|
|
450
|
+
.description("Manage + focus the cross-cutting project lens (a company/initiative): list, new, use, clear");
|
|
451
|
+
project
|
|
452
|
+
.command("list", { isDefault: true })
|
|
453
|
+
.description("List projects on the active pod, with the pinned one marked (bare `synap project` runs this)")
|
|
454
|
+
.option("--json", "Output as JSON (incl. nextSteps for agents)")
|
|
455
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
456
|
+
.option("--api-key <key>", "API key override")
|
|
457
|
+
.action(async (opts) => {
|
|
458
|
+
const { projectList } = await import("./commands/lens.js");
|
|
459
|
+
await projectList(opts);
|
|
460
|
+
});
|
|
461
|
+
project
|
|
462
|
+
.command("new <name>")
|
|
463
|
+
.description("Create a project (a company/initiative) on the active pod, then guide you to pin + add to it")
|
|
464
|
+
.option("--description <text>", "Optional one-line description")
|
|
465
|
+
.option("--json", "Output as JSON (incl. nextSteps for agents)")
|
|
466
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
467
|
+
.option("--api-key <key>", "API key override")
|
|
468
|
+
.action(async (name, opts) => {
|
|
469
|
+
const { projectNew } = await import("./commands/lens.js");
|
|
470
|
+
await projectNew(name, opts);
|
|
471
|
+
});
|
|
472
|
+
project
|
|
473
|
+
.command("use <ref>")
|
|
474
|
+
.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
|
+
.option("--session", "Ephemeral: scope only this Claude Code session, don't persist (cross-pod refs refused)")
|
|
366
476
|
.option("--json", "Output as JSON")
|
|
367
477
|
.option("--pod-url <url>", "Pod URL override")
|
|
368
478
|
.option("--api-key <key>", "API key override")
|
|
369
|
-
.action(async (
|
|
370
|
-
const {
|
|
371
|
-
await
|
|
479
|
+
.action(async (ref, opts) => {
|
|
480
|
+
const { useProject } = await import("./commands/lens.js");
|
|
481
|
+
await useProject(ref, opts);
|
|
372
482
|
});
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
.
|
|
376
|
-
.
|
|
377
|
-
.option("--context <entity-id>", "Link memory to an entity")
|
|
483
|
+
project
|
|
484
|
+
.command("clear")
|
|
485
|
+
.description("Clear the active project focus (durable by default)")
|
|
486
|
+
.option("--session", "Ephemeral: clear only this Claude Code session's project")
|
|
378
487
|
.option("--json", "Output as JSON")
|
|
488
|
+
.action(async (opts) => {
|
|
489
|
+
const { clearProject } = await import("./commands/lens.js");
|
|
490
|
+
await clearProject(opts);
|
|
491
|
+
});
|
|
492
|
+
project
|
|
493
|
+
.command("purge <target>")
|
|
494
|
+
.description("HARD teardown: delete a project + its pod-wide-exclusive entities (owner-only, irreversible)")
|
|
495
|
+
.option("--confirm <name>", "Confirm non-interactively by passing the exact project name")
|
|
496
|
+
.option("--yes", "Skip the interactive name prompt (uses the resolved name)")
|
|
497
|
+
.option("--json", "Output raw JSON")
|
|
379
498
|
.option("--pod-url <url>", "Pod URL override")
|
|
380
499
|
.option("--api-key <key>", "API key override")
|
|
381
|
-
.action(async (
|
|
382
|
-
const {
|
|
383
|
-
await
|
|
500
|
+
.action(async (target, opts) => {
|
|
501
|
+
const { projectPurge } = await import("./commands/purge.js");
|
|
502
|
+
await projectPurge(target, opts);
|
|
384
503
|
});
|
|
385
504
|
program
|
|
386
|
-
.command("
|
|
387
|
-
.description("
|
|
388
|
-
.option("--structured", "Search structured knowledge entities instead of episodic memory")
|
|
389
|
-
.option("--type <type>", "Filter by entry type: gotcha|lesson|decision|reference (--structured only)")
|
|
390
|
-
.option("--tags <csv>", "Filter by tags e.g. repo:synap-backend (--structured only)")
|
|
391
|
-
.option("--workspace <id>", "Workspace to search (--structured only, defaults to active)")
|
|
392
|
-
.option("--limit <n>", "Max results", "10")
|
|
505
|
+
.command("lens")
|
|
506
|
+
.description("Show this Claude session's lens (workspace + project + focus session)")
|
|
393
507
|
.option("--json", "Output as JSON")
|
|
508
|
+
.action(async (opts) => {
|
|
509
|
+
const { showLens } = await import("./commands/lens.js");
|
|
510
|
+
await showLens(opts);
|
|
511
|
+
});
|
|
512
|
+
// ─── ask (unified knowledge access) ─────────────────────────────────────────────
|
|
513
|
+
// The ONE read verb. Routes to the right substrate(s) — semantic (entities),
|
|
514
|
+
// procedural (how-to docs), episodic (captures) — and returns a glass-box answer.
|
|
515
|
+
program
|
|
516
|
+
.command("ask <query>")
|
|
517
|
+
.description("Ask your pod anything — routes to the right knowledge substrate(s) and shows which answered")
|
|
518
|
+
.option("--workspace <id>", "Scope to a specific workspace (omit for pod-wide)")
|
|
519
|
+
.option("--limit <n>", "Max results per substrate", "10")
|
|
520
|
+
.option("--json", "Output as JSON")
|
|
521
|
+
.option("--session", "Scope retrieval to the active session context")
|
|
522
|
+
.option("--compare", "A/B diagnostic: show baseline vs Horizon rankers side-by-side (read-only, does not change the answer)")
|
|
394
523
|
.option("--pod-url <url>", "Pod URL override")
|
|
395
524
|
.option("--api-key <key>", "API key override")
|
|
396
525
|
.action(async (query, opts) => {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
await recallStructured(query, opts);
|
|
400
|
-
}
|
|
401
|
-
else {
|
|
402
|
-
const { recallData } = await import("./commands/data.js");
|
|
403
|
-
await recallData(query, opts);
|
|
404
|
-
}
|
|
526
|
+
const { askKnowledge } = await import("./commands/data.js");
|
|
527
|
+
await askKnowledge(query, opts);
|
|
405
528
|
});
|
|
406
529
|
// ─── capture ──────────────────────────────────────────────────────────────────
|
|
407
530
|
// Uses the active pod + workspace from config (set via `synap pods use` /
|
|
408
531
|
// `synap use` / `synap workspace provision-agent`). No auth flags needed.
|
|
409
532
|
program
|
|
410
|
-
.command("capture")
|
|
411
|
-
.description("Capture
|
|
412
|
-
.
|
|
413
|
-
.
|
|
533
|
+
.command("capture [text]")
|
|
534
|
+
.description("Capture knowledge: smart `capture \"<free text>\"` (AI structures it) OR typed `capture --type gotcha --claim \"…\"`")
|
|
535
|
+
.option("--type <type>", "Typed mode: gotcha|lesson|decision|reference")
|
|
536
|
+
.option("--claim <text>", "Typed mode: one-line assertion (required with --type)")
|
|
414
537
|
.option("--why <text>", "Reasoning or context")
|
|
415
538
|
.option("--evidence <text>", "Supporting file path, URL, or code snippet")
|
|
416
539
|
.option("--tags <csv>", "Comma-separated tags e.g. repo:synap-backend,layer:migrations")
|
|
540
|
+
.option("--session", "Link captured knowledge to the active session")
|
|
541
|
+
.option("--global", "GLOBAL lane: pod-wide cross-cutting runbook (→ knowledge_keys), visible in every workspace")
|
|
542
|
+
.option("--key <ns:slug>", "Stable key for a --global runbook (derived from --type + --claim if omitted)")
|
|
543
|
+
.option("--team", "Write to the first product workspace instead of the active workspace")
|
|
544
|
+
.option("--workspace <id>", "Explicit workspace override")
|
|
545
|
+
.option("--yes", "Skip the y/N confirmation prompt (smart mode)")
|
|
417
546
|
.option("--json", "Output as JSON")
|
|
418
|
-
.action(async (opts) => {
|
|
547
|
+
.action(async (text, opts) => {
|
|
419
548
|
const { captureKnowledge } = await import("./commands/knowledge.js");
|
|
420
|
-
await captureKnowledge(opts);
|
|
549
|
+
await captureKnowledge({ ...opts, text });
|
|
550
|
+
});
|
|
551
|
+
// ─── import ─────────────────────────────────────────────────────────────────
|
|
552
|
+
// "capture, but for files and URLs." Each input (file/folder/URL) routes through
|
|
553
|
+
// the SAME AI capture pipeline (/capture/structure → /capture/execute), so it
|
|
554
|
+
// inherits entity extraction, the relation graph, and workspace/project routing.
|
|
555
|
+
program
|
|
556
|
+
.command("import <inputs...>")
|
|
557
|
+
.description("Import files, folders, or URLs into the pod (AI capture pipeline, or Superwhisper store-first)")
|
|
558
|
+
.option("--workspace <id|name>", "Override AI workspace routing")
|
|
559
|
+
.option("--project <id|name>", "Override AI project routing")
|
|
560
|
+
.option("--dry-run", "Preview only — do not write")
|
|
561
|
+
.option("--yes", "Skip confirmation / auto-confirm store-first")
|
|
562
|
+
.option("--session", "Link created entities to the active session")
|
|
563
|
+
.option("--json", "Output as JSON")
|
|
564
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
565
|
+
.option("--api-key <key>", "API key override")
|
|
566
|
+
.option("--source <name>", "Adapter: superwhisper (paired meta.json+output.wav store-first)")
|
|
567
|
+
.option("--store-first", "Skip AI structure; store units as pod-wide notes (+ optional audio)")
|
|
568
|
+
.option("--with-audio", "Upload WAV provenance (default on for --source superwhisper --store-first)")
|
|
569
|
+
.option("--no-with-audio", "Transcript-only (no WAV upload)")
|
|
570
|
+
.option("--limit <n>", "Max Superwhisper units to process", (v) => parseInt(v, 10))
|
|
571
|
+
.option("--concurrency <n>", "Parallel unit uploads (1–4)", (v) => parseInt(v, 10))
|
|
572
|
+
.option("--no-resume", "Ignore local import ledger (re-import all)")
|
|
573
|
+
.action(async (inputs, opts) => {
|
|
574
|
+
const { importData } = await import("./commands/import.js");
|
|
575
|
+
await importData(inputs, opts);
|
|
576
|
+
});
|
|
577
|
+
program
|
|
578
|
+
.command("subscribe")
|
|
579
|
+
.description("Stream pod events as NDJSON (long-poll)")
|
|
580
|
+
.option("--event <pattern>", "Filter by event type pattern (e.g. proposal.*)")
|
|
581
|
+
.option("--limit <n>", "Events per poll", "20")
|
|
582
|
+
.option("--json", "NDJSON output")
|
|
583
|
+
.option("--pod-url <url>")
|
|
584
|
+
.option("--api-key <key>")
|
|
585
|
+
.action(async (opts) => {
|
|
586
|
+
const { subscribeEvents } = await import("./commands/subscribe.js");
|
|
587
|
+
await subscribeEvents(opts);
|
|
588
|
+
});
|
|
589
|
+
program
|
|
590
|
+
.command("home")
|
|
591
|
+
.description("Show the active workspace's home bento layout (what cells are on screen)")
|
|
592
|
+
.option("--workspace <id>", "Workspace to read (defaults to active workspace)")
|
|
593
|
+
.option("--json", "Output as JSON")
|
|
594
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
595
|
+
.option("--api-key <key>", "API key override")
|
|
596
|
+
.action(async (opts) => {
|
|
597
|
+
const { showHome } = await import("./commands/home.js");
|
|
598
|
+
await showHome(opts);
|
|
599
|
+
});
|
|
600
|
+
program
|
|
601
|
+
.command("context")
|
|
602
|
+
.description("Session-start context: knowledge, proposals, tasks, active sessions")
|
|
603
|
+
.option("--repo <name>", "Filter knowledge by repo tag")
|
|
604
|
+
.option("--limit <n>", "Entries per section", "5")
|
|
605
|
+
.option("--json", "NDJSON output")
|
|
606
|
+
.option("--workspace <id>", "Override workspace")
|
|
607
|
+
.option("--pod-url <url>")
|
|
608
|
+
.option("--api-key <key>")
|
|
609
|
+
.action(async (opts) => {
|
|
610
|
+
const { contextSummary } = await import("./commands/context.js");
|
|
611
|
+
await contextSummary(opts);
|
|
421
612
|
});
|
|
422
613
|
program
|
|
423
614
|
.command("discover")
|
|
@@ -425,6 +616,8 @@ program
|
|
|
425
616
|
.option("--json", "Output as JSON (default: human-readable)")
|
|
426
617
|
.option("--profiles", "Show only profiles (use with --json for machine-readable schema)")
|
|
427
618
|
.option("--commands", "Show only the command tree")
|
|
619
|
+
.option("--summary", "List profile kinds without property schemas")
|
|
620
|
+
.option("--profile-slugs <slugs>", "Comma-separated profile slugs to load in full")
|
|
428
621
|
.option("--workspace <id>", "Workspace to query (defaults to active workspace)")
|
|
429
622
|
.action(async (opts) => {
|
|
430
623
|
const { discover } = await import("./commands/discover.js");
|
|
@@ -447,6 +640,18 @@ workspace
|
|
|
447
640
|
const { provisionAgentWorkspace } = await import("./commands/knowledge.js");
|
|
448
641
|
await provisionAgentWorkspace({ ...opts, agentUserId: opts.agentUserId });
|
|
449
642
|
});
|
|
643
|
+
workspace
|
|
644
|
+
.command("purge <target>")
|
|
645
|
+
.description("HARD teardown: delete a workspace + all its entities and blobs (owner-only, irreversible)")
|
|
646
|
+
.option("--confirm <name>", "Confirm non-interactively by passing the exact workspace name")
|
|
647
|
+
.option("--yes", "Skip the interactive name prompt (uses the resolved name)")
|
|
648
|
+
.option("--json", "Output raw JSON")
|
|
649
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
650
|
+
.option("--api-key <key>", "API key override")
|
|
651
|
+
.action(async (target, opts) => {
|
|
652
|
+
const { workspacePurge } = await import("./commands/purge.js");
|
|
653
|
+
await workspacePurge(target, opts);
|
|
654
|
+
});
|
|
450
655
|
// ─── list ─────────────────────────────────────────────────────────────────────
|
|
451
656
|
const list = program
|
|
452
657
|
.command("list")
|
|
@@ -470,11 +675,24 @@ list
|
|
|
470
675
|
const { listProfiles } = await import("./commands/data.js");
|
|
471
676
|
await listProfiles(opts);
|
|
472
677
|
});
|
|
678
|
+
list
|
|
679
|
+
.command("views")
|
|
680
|
+
.description("List views in a workspace (whiteboard, kanban, bento, …)")
|
|
681
|
+
.option("--type <type>", "Filter by view type (e.g. whiteboard, kanban, calendar)")
|
|
682
|
+
.option("--workspace <id>", "Workspace (defaults to active)")
|
|
683
|
+
.option("--json", "Output as JSON")
|
|
684
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
685
|
+
.option("--api-key <key>", "API key override")
|
|
686
|
+
.action(async (opts) => {
|
|
687
|
+
const { viewList } = await import("./commands/view.js");
|
|
688
|
+
await viewList(opts);
|
|
689
|
+
});
|
|
473
690
|
list
|
|
474
691
|
.command("entities")
|
|
475
692
|
.description("List entities on the pod")
|
|
476
693
|
.option("--workspace <id>", "Scope to a workspace (omit for pod-wide)")
|
|
477
694
|
.option("--profile <slug>", "Filter by profile slug (e.g. person, task, note)")
|
|
695
|
+
.option("--role <slug>", "Filter to entities carrying this role (e.g. client, partner)")
|
|
478
696
|
.option("--limit <n>", "Max results", "50")
|
|
479
697
|
.option("--json", "Output as JSON")
|
|
480
698
|
.option("--pod-url <url>", "Pod URL override")
|
|
@@ -483,6 +701,335 @@ list
|
|
|
483
701
|
const { listEntities } = await import("./commands/data.js");
|
|
484
702
|
await listEntities(opts);
|
|
485
703
|
});
|
|
704
|
+
// ─── show ─────────────────────────────────────────────────────────────────────
|
|
705
|
+
// Entity detail + its relations — one command to understand any node in the graph.
|
|
706
|
+
program
|
|
707
|
+
.command("show <id>")
|
|
708
|
+
.description("Show an entity with its properties and all linked relations")
|
|
709
|
+
.option("--json", "Output as JSON")
|
|
710
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
711
|
+
.option("--api-key <key>", "API key override")
|
|
712
|
+
.action(async (id, opts) => {
|
|
713
|
+
const { showEntity } = await import("./commands/data-extra.js");
|
|
714
|
+
await showEntity(id, opts);
|
|
715
|
+
});
|
|
716
|
+
// ─── facet ────────────────────────────────────────────────────────────────────
|
|
717
|
+
// Roles — one identity, many roles. A role-profile (client, partner, contact…)
|
|
718
|
+
// attached to an existing entity, never a second entity. Governed writes: an
|
|
719
|
+
// attach/detach may come back "proposed for review" instead of applying live.
|
|
720
|
+
const facet = program
|
|
721
|
+
.command("facet")
|
|
722
|
+
.description("Manage roles attached to an entity (client, partner, contact, …)");
|
|
723
|
+
facet
|
|
724
|
+
.command("attach <entityId> <roleSlug>")
|
|
725
|
+
.description("Attach a role to an entity")
|
|
726
|
+
.option("--property <kv>", "Role property as key=value (repeatable)", collect, [])
|
|
727
|
+
.option("--workspace <id>", "Role's lens (defaults to the active workspace)")
|
|
728
|
+
.option("--json", "Output as JSON")
|
|
729
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
730
|
+
.option("--api-key <key>", "API key override")
|
|
731
|
+
.action(async (entityId, roleSlug, opts) => {
|
|
732
|
+
const { attachFacet } = await import("./commands/facet.js");
|
|
733
|
+
await attachFacet(entityId, roleSlug, opts);
|
|
734
|
+
});
|
|
735
|
+
facet
|
|
736
|
+
.command("list <entityId>")
|
|
737
|
+
.description("List the roles attached to an entity")
|
|
738
|
+
.option("--json", "Output as JSON")
|
|
739
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
740
|
+
.option("--api-key <key>", "API key override")
|
|
741
|
+
.action(async (entityId, opts) => {
|
|
742
|
+
const { listFacets } = await import("./commands/facet.js");
|
|
743
|
+
await listFacets(entityId, opts);
|
|
744
|
+
});
|
|
745
|
+
facet
|
|
746
|
+
.command("detach [facetId]")
|
|
747
|
+
.description("Detach a role — pass the facet id, or --entity <id> --role <slug>")
|
|
748
|
+
.option("--entity <id>", "Entity id (with --role, resolves the facet to detach)")
|
|
749
|
+
.option("--role <slug>", "Role slug (with --entity)")
|
|
750
|
+
.option("--json", "Output as JSON")
|
|
751
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
752
|
+
.option("--api-key <key>", "API key override")
|
|
753
|
+
.action(async (facetId, opts) => {
|
|
754
|
+
if (!facetId && !(opts.entity && opts.role)) {
|
|
755
|
+
console.error("Provide a facet id, or both --entity <id> and --role <slug>.");
|
|
756
|
+
process.exit(1);
|
|
757
|
+
}
|
|
758
|
+
const { detachFacet } = await import("./commands/facet.js");
|
|
759
|
+
await detachFacet(facetId ?? "", opts);
|
|
760
|
+
});
|
|
761
|
+
// ─── proposals ────────────────────────────────────────────────────────────────
|
|
762
|
+
// Governance inbox — pending proposals attributed to this agent.
|
|
763
|
+
const proposals = program
|
|
764
|
+
.command("proposals")
|
|
765
|
+
.description("Review and act on governance proposals");
|
|
766
|
+
proposals
|
|
767
|
+
.command("list", { isDefault: true })
|
|
768
|
+
.description("List pending governance proposals for this agent")
|
|
769
|
+
.option("--workspace <id>", "Scope to a specific workspace")
|
|
770
|
+
.option("--limit <n>", "Max results", "20")
|
|
771
|
+
.option("--json", "Output as JSON")
|
|
772
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
773
|
+
.option("--api-key <key>", "API key override")
|
|
774
|
+
.action(async (opts) => {
|
|
775
|
+
const { listProposals } = await import("./commands/data-extra.js");
|
|
776
|
+
await listProposals(opts);
|
|
777
|
+
});
|
|
778
|
+
proposals
|
|
779
|
+
.command("approve <id>")
|
|
780
|
+
.description("Approve a pending proposal")
|
|
781
|
+
.option("--reason <text>", "Optional approval note")
|
|
782
|
+
.option("--json", "Output as JSON")
|
|
783
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
784
|
+
.option("--api-key <key>", "API key override")
|
|
785
|
+
.action(async (id, opts) => {
|
|
786
|
+
const { approveProposal } = await import("./commands/proposals-actions.js");
|
|
787
|
+
await approveProposal(id, opts);
|
|
788
|
+
});
|
|
789
|
+
proposals
|
|
790
|
+
.command("reject <id>")
|
|
791
|
+
.description("Reject a pending proposal")
|
|
792
|
+
.option("--reason <text>", "Rejection reason")
|
|
793
|
+
.option("--json", "Output as JSON")
|
|
794
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
795
|
+
.option("--api-key <key>", "API key override")
|
|
796
|
+
.action(async (id, opts) => {
|
|
797
|
+
const { rejectProposal } = await import("./commands/proposals-actions.js");
|
|
798
|
+
await rejectProposal(id, opts);
|
|
799
|
+
});
|
|
800
|
+
// ─── session ──────────────────────────────────────────────────────────────────
|
|
801
|
+
// Focus sessions — goal-bound work rooms tracked on the pod.
|
|
802
|
+
// AI agents: use start_session to begin, update_session to report progress,
|
|
803
|
+
// update_session({status:"closed"}) to finish. Sessions link goals, context,
|
|
804
|
+
// plans, execution logs, and verification reports together.
|
|
805
|
+
const session = program
|
|
806
|
+
.command("session")
|
|
807
|
+
.description("Manage focus sessions (goal-bound AI work rooms)");
|
|
808
|
+
session
|
|
809
|
+
.command("start")
|
|
810
|
+
.description("Start a new focus session and return its ID")
|
|
811
|
+
.requiredOption("--goal <text>", "What this session is working toward")
|
|
812
|
+
.option("--workspace <id>", "Workspace that owns the session")
|
|
813
|
+
.option("--task-id <id>", "Link session to an existing task entity")
|
|
814
|
+
.option("--json", "Output as JSON")
|
|
815
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
816
|
+
.option("--api-key <key>", "API key override")
|
|
817
|
+
.action(async (opts) => {
|
|
818
|
+
const { startSession } = await import("./commands/sessions.js");
|
|
819
|
+
await startSession(opts);
|
|
820
|
+
});
|
|
821
|
+
session
|
|
822
|
+
.command("list", { isDefault: true })
|
|
823
|
+
.description("List focus sessions in the active workspace")
|
|
824
|
+
.option("--workspace <id>", "Scope to a specific workspace")
|
|
825
|
+
.option("--status <status>", "Filter by status: active | paused | closed")
|
|
826
|
+
.option("--limit <n>", "Max results", "20")
|
|
827
|
+
.option("--json", "Output as JSON")
|
|
828
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
829
|
+
.option("--api-key <key>", "API key override")
|
|
830
|
+
.action(async (opts) => {
|
|
831
|
+
const { listSessions } = await import("./commands/sessions.js");
|
|
832
|
+
await listSessions(opts);
|
|
833
|
+
});
|
|
834
|
+
session
|
|
835
|
+
.command("get <id>")
|
|
836
|
+
.description("Show details for a specific focus session")
|
|
837
|
+
.option("--workspace <id>", "Workspace that owns the session (required for scoped fetch)")
|
|
838
|
+
.option("--json", "Output as JSON")
|
|
839
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
840
|
+
.option("--api-key <key>", "API key override")
|
|
841
|
+
.action(async (id, opts) => {
|
|
842
|
+
const { getSession } = await import("./commands/sessions.js");
|
|
843
|
+
await getSession(id, opts);
|
|
844
|
+
});
|
|
845
|
+
session
|
|
846
|
+
.command("update <id>")
|
|
847
|
+
.description("Update progress or status of a focus session")
|
|
848
|
+
.requiredOption("--workspace <id>", "Workspace that owns the session")
|
|
849
|
+
.option("--progress <0-100>", "Progress percentage")
|
|
850
|
+
.option("--status <status>", "New status: active | paused")
|
|
851
|
+
.option("--goal <text>", "Revised goal")
|
|
852
|
+
.option("--json", "Output as JSON")
|
|
853
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
854
|
+
.option("--api-key <key>", "API key override")
|
|
855
|
+
.action(async (id, opts) => {
|
|
856
|
+
const { updateSession } = await import("./commands/sessions.js");
|
|
857
|
+
await updateSession(id, opts);
|
|
858
|
+
});
|
|
859
|
+
session
|
|
860
|
+
.command("close <id>")
|
|
861
|
+
.description("Close a focus session and optionally attach a recap")
|
|
862
|
+
.requiredOption("--workspace <id>", "Workspace that owns the session")
|
|
863
|
+
.option("--recap <text>", "Short summary of what was accomplished")
|
|
864
|
+
.option("--json", "Output as JSON")
|
|
865
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
866
|
+
.option("--api-key <key>", "API key override")
|
|
867
|
+
.action(async (id, opts) => {
|
|
868
|
+
const { closeSession } = await import("./commands/sessions.js");
|
|
869
|
+
await closeSession(id, opts);
|
|
870
|
+
});
|
|
871
|
+
session
|
|
872
|
+
.command("attach <id>")
|
|
873
|
+
.description("Attach a session to this terminal — all hub calls tag X-Session-Id until detached")
|
|
874
|
+
.option("--json", "Output as JSON")
|
|
875
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
876
|
+
.option("--api-key <key>", "API key override")
|
|
877
|
+
.action(async (id, opts) => {
|
|
878
|
+
const { attachSession } = await import("./commands/sessions.js");
|
|
879
|
+
await attachSession(id, opts);
|
|
880
|
+
});
|
|
881
|
+
session
|
|
882
|
+
.command("detach")
|
|
883
|
+
.description("Remove the active session from this terminal")
|
|
884
|
+
.option("--json", "Output as JSON")
|
|
885
|
+
.action(async (opts) => {
|
|
886
|
+
const { detachSession } = await import("./commands/sessions.js");
|
|
887
|
+
detachSession(opts);
|
|
888
|
+
});
|
|
889
|
+
session
|
|
890
|
+
.command("current")
|
|
891
|
+
.description("Show the active session for this terminal (from .synap-session or SYNAP_SESSION_ID)")
|
|
892
|
+
.option("--json", "Output as JSON")
|
|
893
|
+
.action(async (opts) => {
|
|
894
|
+
const { sessionStatus } = await import("./commands/sessions.js");
|
|
895
|
+
sessionStatus(opts);
|
|
896
|
+
});
|
|
897
|
+
// ─── skill ────────────────────────────────────────────────────────────────────
|
|
898
|
+
// Autonomous workspace session skills — context gathering, task planning, etc.
|
|
899
|
+
const skillCmd = program
|
|
900
|
+
.command("skill")
|
|
901
|
+
.description("Execute a skill in an autonomous workspace session")
|
|
902
|
+
.action(() => {
|
|
903
|
+
skillCmd.help();
|
|
904
|
+
});
|
|
905
|
+
skillCmd
|
|
906
|
+
.command("gather-context")
|
|
907
|
+
.description("Gather pod KG + local context (CLAUDE.md, .claude/kg-verify) for a session")
|
|
908
|
+
.option("--session <id>", "Focus session ID (required)")
|
|
909
|
+
.option("--workspace <id>", "Workspace ID (defaults to active workspace)")
|
|
910
|
+
.option("--json", "Output as JSON")
|
|
911
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
912
|
+
.option("--api-key <key>", "API key override")
|
|
913
|
+
.allowUnknownOption()
|
|
914
|
+
.action(async (opts) => {
|
|
915
|
+
const { gatherContext } = await import("./commands/skills.js");
|
|
916
|
+
await gatherContext(opts);
|
|
917
|
+
});
|
|
918
|
+
skillCmd
|
|
919
|
+
.command("suggest <topic>")
|
|
920
|
+
.description("Search the skill knowledge base by topic or keyword")
|
|
921
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
922
|
+
.option("--api-key <key>", "API key override")
|
|
923
|
+
.action(async (topic, opts) => {
|
|
924
|
+
const { suggestSkills } = await import("./commands/skills-commands.js");
|
|
925
|
+
await suggestSkills(topic, opts);
|
|
926
|
+
});
|
|
927
|
+
skillCmd
|
|
928
|
+
.command("get <slug>")
|
|
929
|
+
.description("Fetch a skill from the knowledge base by slug and print its body")
|
|
930
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
931
|
+
.option("--api-key <key>", "API key override")
|
|
932
|
+
.action(async (slug, opts) => {
|
|
933
|
+
const { getSkill } = await import("./commands/skills-commands.js");
|
|
934
|
+
await getSkill(slug, opts);
|
|
935
|
+
});
|
|
936
|
+
skillCmd
|
|
937
|
+
.command("add <source>")
|
|
938
|
+
.description("Add skill(s) to your pod from: bundled · a local path · ~/.claude/skills/ · owner/repo · a git URL")
|
|
939
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
940
|
+
.option("--api-key <key>", "API key override")
|
|
941
|
+
.action(async (source, opts) => {
|
|
942
|
+
const { addSkill } = await import("./commands/skill-manage.js");
|
|
943
|
+
await addSkill(source, opts);
|
|
944
|
+
});
|
|
945
|
+
skillCmd
|
|
946
|
+
.command("list")
|
|
947
|
+
.alias("ls")
|
|
948
|
+
.description("List the instruction skills installed on your pod")
|
|
949
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
950
|
+
.option("--api-key <key>", "API key override")
|
|
951
|
+
.option("--debug", "Show resolved credentials")
|
|
952
|
+
.action(async (opts) => {
|
|
953
|
+
const { listSkills } = await import("./commands/skill-manage.js");
|
|
954
|
+
await listSkills(opts);
|
|
955
|
+
});
|
|
956
|
+
skillCmd
|
|
957
|
+
.command("remove <slug>")
|
|
958
|
+
.alias("rm")
|
|
959
|
+
.description("Remove a skill from your pod by slug")
|
|
960
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
961
|
+
.option("--api-key <key>", "API key override")
|
|
962
|
+
.action(async (slug, opts) => {
|
|
963
|
+
const { removeSkill } = await import("./commands/skill-manage.js");
|
|
964
|
+
await removeSkill(slug, opts);
|
|
965
|
+
});
|
|
966
|
+
skillCmd
|
|
967
|
+
.command("sync")
|
|
968
|
+
.description("Bulk-import local skills from ~/.claude/skills/ into the pod")
|
|
969
|
+
.option("--from <path>", "Skills directory path (default: ~/.claude/skills)")
|
|
970
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
971
|
+
.option("--api-key <key>", "API key override")
|
|
972
|
+
.action(async (opts) => {
|
|
973
|
+
const { syncSkills } = await import("./commands/skills-commands.js");
|
|
974
|
+
await syncSkills(opts);
|
|
975
|
+
});
|
|
976
|
+
skillCmd
|
|
977
|
+
.command("verify-code")
|
|
978
|
+
.description("Run the project's type-check/test gate and store the result on the session")
|
|
979
|
+
.requiredOption("--session <id>", "Focus session ID")
|
|
980
|
+
.requiredOption("--workspace <id>", "Workspace that owns the session")
|
|
981
|
+
.requiredOption("--cmd <command>", "Gate command to run (e.g. 'pnpm type-check')")
|
|
982
|
+
.option("--json", "Output as JSON")
|
|
983
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
984
|
+
.option("--api-key <key>", "API key override")
|
|
985
|
+
.action(async (opts) => {
|
|
986
|
+
const { verifyCode } = await import("./commands/skills.js");
|
|
987
|
+
await verifyCode(opts);
|
|
988
|
+
});
|
|
989
|
+
// ─── browse ───────────────────────────────────────────────────────────────────
|
|
990
|
+
// Paginated entity list — cleaner than `list entities`.
|
|
991
|
+
program
|
|
992
|
+
.command("browse [profile]")
|
|
993
|
+
.description("Browse entities in the active workspace, optionally filtered by profile type or role")
|
|
994
|
+
.option("--workspace <id>", "Scope to a specific workspace")
|
|
995
|
+
.option("--role <slug>", "Filter to entities carrying this role (e.g. client, partner)")
|
|
996
|
+
.option("--limit <n>", "Max results", "20")
|
|
997
|
+
.option("--json", "Output as JSON")
|
|
998
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
999
|
+
.option("--api-key <key>", "API key override")
|
|
1000
|
+
.action(async (profile, opts) => {
|
|
1001
|
+
const { browseEntities } = await import("./commands/data-extra.js");
|
|
1002
|
+
await browseEntities({ ...opts, profile });
|
|
1003
|
+
});
|
|
1004
|
+
// ─── observe ──────────────────────────────────────────────────────────────────
|
|
1005
|
+
// AI-maintained user model — write and query pod-scoped user observations.
|
|
1006
|
+
const observe = program
|
|
1007
|
+
.command("observe")
|
|
1008
|
+
.description("Write and recall pod-wide user observations (AI-maintained user model)");
|
|
1009
|
+
observe
|
|
1010
|
+
.command("write <text>", { isDefault: true })
|
|
1011
|
+
.description("Record an observation about the user (pod-scoped, AI-maintained)")
|
|
1012
|
+
.option("--category <cat>", "working_style | communication | focus | technical | preference", "preference")
|
|
1013
|
+
.option("--confidence <n>", "Confidence score 0-1", "0.5")
|
|
1014
|
+
.option("--json", "Output as JSON")
|
|
1015
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1016
|
+
.option("--api-key <key>", "API key override")
|
|
1017
|
+
.action(async (text, opts) => {
|
|
1018
|
+
const { observeWrite } = await import("./commands/observe.js");
|
|
1019
|
+
await observeWrite(text, opts);
|
|
1020
|
+
});
|
|
1021
|
+
observe
|
|
1022
|
+
.command("recall <query>")
|
|
1023
|
+
.description("Search recorded user observations")
|
|
1024
|
+
.option("--category <cat>", "Filter by category")
|
|
1025
|
+
.option("--limit <n>", "Max results", "10")
|
|
1026
|
+
.option("--json", "Output as JSON")
|
|
1027
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1028
|
+
.option("--api-key <key>", "API key override")
|
|
1029
|
+
.action(async (query, opts) => {
|
|
1030
|
+
const { observeRecall } = await import("./commands/observe.js");
|
|
1031
|
+
await observeRecall(query, opts);
|
|
1032
|
+
});
|
|
486
1033
|
// ─── get ──────────────────────────────────────────────────────────────────────
|
|
487
1034
|
const get = program
|
|
488
1035
|
.command("get")
|
|
@@ -538,6 +1085,7 @@ set
|
|
|
538
1085
|
.command("entity <id>")
|
|
539
1086
|
.description("Update entity properties")
|
|
540
1087
|
.requiredOption("--props <json>", "Properties as JSON string")
|
|
1088
|
+
.option("--workspace <id>", "Workspace ID (sent in PATCH body so workspace-scoped automations fire)")
|
|
541
1089
|
.option("--json", "Output as JSON")
|
|
542
1090
|
.option("--pod-url <url>", "Pod URL override")
|
|
543
1091
|
.option("--api-key <key>", "API key override")
|
|
@@ -604,5 +1152,779 @@ agents
|
|
|
604
1152
|
const { agentsInfo } = await import("./commands/agents.js");
|
|
605
1153
|
agentsInfo(name);
|
|
606
1154
|
});
|
|
1155
|
+
// ─── agent (autonomous runner) ───────────────────────────────────────────────
|
|
1156
|
+
const agent = program
|
|
1157
|
+
.command("agent")
|
|
1158
|
+
.description("Run autonomous agent loops against the IS, or schedule recurring goals");
|
|
1159
|
+
agent
|
|
1160
|
+
.command("ask <message>")
|
|
1161
|
+
.description("Send one message to the workspace's deployed agent and print its reply (multi-turn: reuses one thread)")
|
|
1162
|
+
.option("--workspace <id|name>", "Workspace to talk to (uses active workspace/lens if omitted)")
|
|
1163
|
+
.option("--thread <id>", "Target an existing thread/channel id instead of the default CLI chat thread")
|
|
1164
|
+
.option("--new", "Start a fresh thread instead of continuing the persistent CLI chat thread")
|
|
1165
|
+
.option("--agent-type <type>", "Requested agent type hint (backend currently routes to the orchestrator)")
|
|
1166
|
+
.option("--timeout <seconds>", "How long to wait for the agent's reply (default: 90)")
|
|
1167
|
+
.option("--json", "Machine-readable output { ok, reply, threadId, workspaceId }")
|
|
1168
|
+
.option("--pod-url <url>", "Override pod URL")
|
|
1169
|
+
.option("--api-key <key>", "Override API key")
|
|
1170
|
+
.action(async (message, opts) => {
|
|
1171
|
+
const { agentAsk } = await import("./commands/agent-chat.js");
|
|
1172
|
+
await agentAsk({ ...opts, message });
|
|
1173
|
+
});
|
|
1174
|
+
agent
|
|
1175
|
+
.command("chat")
|
|
1176
|
+
.description("Interactive REPL conversation with the workspace's deployed agent")
|
|
1177
|
+
.option("--workspace <id|name>", "Workspace to talk to (uses active workspace/lens if omitted)")
|
|
1178
|
+
.option("--thread <id>", "Target an existing thread/channel id instead of the default CLI chat thread")
|
|
1179
|
+
.option("--new", "Start a fresh thread instead of continuing the persistent CLI chat thread")
|
|
1180
|
+
.option("--agent-type <type>", "Requested agent type hint (backend currently routes to the orchestrator)")
|
|
1181
|
+
.option("--timeout <seconds>", "How long to wait for each reply (default: 90)")
|
|
1182
|
+
.option("--pod-url <url>", "Override pod URL")
|
|
1183
|
+
.option("--api-key <key>", "Override API key")
|
|
1184
|
+
.action(async (opts) => {
|
|
1185
|
+
const { agentChat } = await import("./commands/agent-chat.js");
|
|
1186
|
+
await agentChat(opts);
|
|
1187
|
+
});
|
|
1188
|
+
agent
|
|
1189
|
+
.command("run")
|
|
1190
|
+
.description("Run an autonomous agent toward a goal using the Intelligence Service")
|
|
1191
|
+
.requiredOption("--goal <text>", "What the agent should accomplish")
|
|
1192
|
+
.option("--persona <type>", "researcher | assistant | developer (default: researcher)")
|
|
1193
|
+
.option("--model <model>", "IS model alias, e.g. synap/advanced (default: synap/advanced)")
|
|
1194
|
+
.option("--workspace <id>", "Workspace to store results in (uses active workspace if omitted)")
|
|
1195
|
+
.option("--max-steps <n>", "Max reasoning steps before auto-saving (default: 12)", parseInt)
|
|
1196
|
+
.option("--dry-run", "Print config without running")
|
|
1197
|
+
.option("--pod-url <url>", "Override pod URL")
|
|
1198
|
+
.option("--api-key <key>", "Override API key")
|
|
1199
|
+
.action(async (opts) => {
|
|
1200
|
+
const { agentRun } = await import("./commands/agent-run.js");
|
|
1201
|
+
await agentRun(opts);
|
|
1202
|
+
});
|
|
1203
|
+
agent
|
|
1204
|
+
.command("schedule")
|
|
1205
|
+
.description("Add, list, or remove recurring agent schedules")
|
|
1206
|
+
.option("--goal <text>", "Goal for the scheduled agent")
|
|
1207
|
+
.option("--name <label>", "Name for this schedule (required when adding)")
|
|
1208
|
+
.option("--every <interval>", "hourly | daily | weekly")
|
|
1209
|
+
.option("--persona <type>", "researcher | assistant | developer (default: researcher)")
|
|
1210
|
+
.option("--model <model>", "IS model alias (default: synap/advanced)")
|
|
1211
|
+
.option("--workspace <id>", "Workspace to store results in")
|
|
1212
|
+
.option("--run-now", "Also run immediately after creating the schedule")
|
|
1213
|
+
.option("--list", "List all configured schedules")
|
|
1214
|
+
.option("--remove <name>", "Remove a schedule by name")
|
|
1215
|
+
.option("--pod-url <url>", "Override pod URL")
|
|
1216
|
+
.option("--api-key <key>", "Override API key")
|
|
1217
|
+
.action(async (opts) => {
|
|
1218
|
+
const { agentSchedule } = await import("./commands/agent-run.js");
|
|
1219
|
+
await agentSchedule(opts);
|
|
1220
|
+
});
|
|
1221
|
+
agent
|
|
1222
|
+
.command("tick")
|
|
1223
|
+
.description("Check due schedules and run them — wire this to crontab: `0 * * * * synap agent tick`")
|
|
1224
|
+
.option("--dry-run", "Show what would run without executing")
|
|
1225
|
+
.option("--pod-url <url>", "Override pod URL")
|
|
1226
|
+
.option("--api-key <key>", "Override API key")
|
|
1227
|
+
.action(async (opts) => {
|
|
1228
|
+
const { agentTick } = await import("./commands/agent-run.js");
|
|
1229
|
+
await agentTick(opts);
|
|
1230
|
+
});
|
|
1231
|
+
// ─── automation ──────────────────────────────────────────────────────────────
|
|
1232
|
+
function collect(val, prev) { return [...prev, val]; }
|
|
1233
|
+
const automation = program
|
|
1234
|
+
.command("automation")
|
|
1235
|
+
.description("Create, manage, and inspect pod automations");
|
|
1236
|
+
automation
|
|
1237
|
+
.command("list")
|
|
1238
|
+
.description("List automations on the pod")
|
|
1239
|
+
.option("--workspace <id>", "Filter by workspace")
|
|
1240
|
+
.option("--status <status>", "Filter by status (active|draft|paused|error)")
|
|
1241
|
+
.option("--json", "Output raw JSON")
|
|
1242
|
+
.action(async (opts) => {
|
|
1243
|
+
const { automationList } = await import("./commands/automation.js");
|
|
1244
|
+
await automationList(opts);
|
|
1245
|
+
});
|
|
1246
|
+
automation
|
|
1247
|
+
.command("describe <id>")
|
|
1248
|
+
.description("Show full details of an automation")
|
|
1249
|
+
.option("--workspace <id>")
|
|
1250
|
+
.option("--json")
|
|
1251
|
+
.action(async (id, opts) => {
|
|
1252
|
+
const { automationDescribe } = await import("./commands/automation.js");
|
|
1253
|
+
await automationDescribe(id, opts);
|
|
1254
|
+
});
|
|
1255
|
+
automation
|
|
1256
|
+
.command("create")
|
|
1257
|
+
.description("Create an automation (quick flags or --from file.yaml)")
|
|
1258
|
+
.option("--name <name>", "Automation name (required in quick mode)")
|
|
1259
|
+
.option("--trigger <spec>", "event:<pattern> | cron:<expr> | webhook | manual")
|
|
1260
|
+
.option("--filter <kv>", "key=value filter (event triggers, repeatable)", collect, [])
|
|
1261
|
+
.option("--action <type>", "notify | channel-message | none (default: none)")
|
|
1262
|
+
.option("--message <text>", "Message content for notify/channel-message")
|
|
1263
|
+
.option("--channel <id>", "Channel ID for channel-message action")
|
|
1264
|
+
.option("--status <status>", "draft (default) | active")
|
|
1265
|
+
.option("--description <text>", "Description")
|
|
1266
|
+
.option("--workspace <id>", "Workspace ID")
|
|
1267
|
+
.option("--from <file>", "Create from YAML/JSON file instead of flags")
|
|
1268
|
+
.action(async (opts) => {
|
|
1269
|
+
const { automationCreate } = await import("./commands/automation.js");
|
|
1270
|
+
await automationCreate(opts);
|
|
1271
|
+
});
|
|
1272
|
+
automation
|
|
1273
|
+
.command("enable <id>")
|
|
1274
|
+
.description("Activate an automation")
|
|
1275
|
+
.option("--workspace <id>")
|
|
1276
|
+
.action(async (id, opts) => {
|
|
1277
|
+
const { automationEnable } = await import("./commands/automation.js");
|
|
1278
|
+
await automationEnable(id, opts);
|
|
1279
|
+
});
|
|
1280
|
+
automation
|
|
1281
|
+
.command("disable <id>")
|
|
1282
|
+
.description("Pause an automation")
|
|
1283
|
+
.option("--workspace <id>")
|
|
1284
|
+
.action(async (id, opts) => {
|
|
1285
|
+
const { automationDisable } = await import("./commands/automation.js");
|
|
1286
|
+
await automationDisable(id, opts);
|
|
1287
|
+
});
|
|
1288
|
+
automation
|
|
1289
|
+
.command("delete <id>")
|
|
1290
|
+
.description("Delete an automation")
|
|
1291
|
+
.option("--workspace <id>")
|
|
1292
|
+
.option("--force", "Skip confirmation prompt")
|
|
1293
|
+
.action(async (id, opts) => {
|
|
1294
|
+
const { automationDelete } = await import("./commands/automation.js");
|
|
1295
|
+
await automationDelete(id, opts);
|
|
1296
|
+
});
|
|
1297
|
+
automation
|
|
1298
|
+
.command("schema")
|
|
1299
|
+
.description("Fetch the automation DSL schema from the pod (AI context)")
|
|
1300
|
+
.option("--write-context [path]", "Write markdown context file for Claude Code")
|
|
1301
|
+
.option("--json", "Output raw JSON instead of formatted markdown")
|
|
1302
|
+
.action(async (opts) => {
|
|
1303
|
+
const { automationSchema } = await import("./commands/automation.js");
|
|
1304
|
+
await automationSchema(opts);
|
|
1305
|
+
});
|
|
1306
|
+
// ─── graph ────────────────────────────────────────────────────────────────────
|
|
1307
|
+
program
|
|
1308
|
+
.command("graph")
|
|
1309
|
+
.description("Low-level BFS graph traversal from an entity (prefer `synap ask` — graph is one of its signals)")
|
|
1310
|
+
.requiredOption("--entity <id>", "Start entity ID")
|
|
1311
|
+
.option("--depth <n>", "Traversal depth (max 3)", "2")
|
|
1312
|
+
.option("--json", "Raw JSON output")
|
|
1313
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1314
|
+
.option("--api-key <key>", "API key override")
|
|
1315
|
+
.action(async (opts) => {
|
|
1316
|
+
const { graphTraverse } = await import("./commands/graph.js");
|
|
1317
|
+
await graphTraverse(opts);
|
|
1318
|
+
});
|
|
1319
|
+
// ─── centrality ────────────────────────────────────────────────────────────────
|
|
1320
|
+
// Window onto the Phase-3 PageRank centrality signal (entity_centrality):
|
|
1321
|
+
// see if it has populated, and trigger a recompute on demand.
|
|
1322
|
+
const centrality = program
|
|
1323
|
+
.command("centrality")
|
|
1324
|
+
.description("Inspect PageRank centrality (entity_centrality) and trigger a recompute");
|
|
1325
|
+
centrality
|
|
1326
|
+
.command("status", { isDefault: true })
|
|
1327
|
+
.description("Show whether PageRank centrality has populated + the top central entities")
|
|
1328
|
+
.option("--json", "Output as JSON")
|
|
1329
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1330
|
+
.option("--api-key <key>", "API key override")
|
|
1331
|
+
.action(async (opts) => {
|
|
1332
|
+
const { centralityStatus } = await import("./commands/centrality.js");
|
|
1333
|
+
await centralityStatus(opts);
|
|
1334
|
+
});
|
|
1335
|
+
centrality
|
|
1336
|
+
.command("recompute")
|
|
1337
|
+
.description("Enqueue a PageRank centrality recompute (runs in the background)")
|
|
1338
|
+
.option("--json", "Output as JSON")
|
|
1339
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1340
|
+
.option("--api-key <key>", "API key override")
|
|
1341
|
+
.action(async (opts) => {
|
|
1342
|
+
const { centralityRecompute } = await import("./commands/centrality.js");
|
|
1343
|
+
await centralityRecompute(opts);
|
|
1344
|
+
});
|
|
1345
|
+
// ─── events ───────────────────────────────────────────────────────────────────
|
|
1346
|
+
program
|
|
1347
|
+
.command("events")
|
|
1348
|
+
.description("Show event chain for an entity or recent pod events")
|
|
1349
|
+
.option("--entity <id>", "Filter by entity ID (subjectId)")
|
|
1350
|
+
.option("--limit <n>", "Number of events", "20")
|
|
1351
|
+
.option("--json", "Raw JSON output")
|
|
1352
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1353
|
+
.option("--api-key <key>", "API key override")
|
|
1354
|
+
.action(async (opts) => {
|
|
1355
|
+
const { listEvents } = await import("./commands/events.js");
|
|
1356
|
+
await listEvents(opts);
|
|
1357
|
+
});
|
|
1358
|
+
// ─── view ─────────────────────────────────────────────────────────────────────
|
|
1359
|
+
const view = program
|
|
1360
|
+
.command("view")
|
|
1361
|
+
.description("Manage views");
|
|
1362
|
+
view
|
|
1363
|
+
.command("create")
|
|
1364
|
+
.description("Create a view (table, kanban, bento, …)")
|
|
1365
|
+
.requiredOption("--type <type>", "View type: table|kanban|bento|list|grid|gallery|calendar|masonry|flow|matrix|branch_tree|whiteboard")
|
|
1366
|
+
.option("--profile <slug>", "Entity profile to display (passed as profileId)")
|
|
1367
|
+
.option("--name <name>", "View name")
|
|
1368
|
+
.option("--workspace <id>", "Workspace ID")
|
|
1369
|
+
.option("--json", "JSON output")
|
|
1370
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1371
|
+
.option("--api-key <key>", "API key override")
|
|
1372
|
+
.action(async (opts) => {
|
|
1373
|
+
const { viewCreate } = await import("./commands/view.js");
|
|
1374
|
+
await viewCreate(opts);
|
|
1375
|
+
});
|
|
1376
|
+
view
|
|
1377
|
+
.command("list", { isDefault: true })
|
|
1378
|
+
.description("List views in the active workspace")
|
|
1379
|
+
.option("--type <type>", "Filter by view type (e.g. whiteboard, kanban, calendar)")
|
|
1380
|
+
.option("--workspace <id>", "Workspace ID")
|
|
1381
|
+
.option("--json", "JSON output")
|
|
1382
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1383
|
+
.option("--api-key <key>", "API key override")
|
|
1384
|
+
.action(async (opts) => {
|
|
1385
|
+
const { viewList } = await import("./commands/view.js");
|
|
1386
|
+
await viewList(opts);
|
|
1387
|
+
});
|
|
1388
|
+
view
|
|
1389
|
+
.command("arrange <viewId>")
|
|
1390
|
+
.description("Replace the widget arrangement of a bento view")
|
|
1391
|
+
.option("--file <path>", "JSON file containing widget layout (array or { widgets: [...] })")
|
|
1392
|
+
.option("--workspace <id>", "Workspace ID")
|
|
1393
|
+
.option("--json", "JSON output")
|
|
1394
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1395
|
+
.option("--api-key <key>", "API key override")
|
|
1396
|
+
.addHelpText("after", `
|
|
1397
|
+
Examples:
|
|
1398
|
+
synap view arrange <viewId> --file layout.json
|
|
1399
|
+
echo '[{"id":"w1","kind":"widget","x":0,"y":0,"w":6,"h":4}]' | synap view arrange <viewId>
|
|
1400
|
+
|
|
1401
|
+
Layout format (array of BentoWidget):
|
|
1402
|
+
[{ "id": "<widgetId>", "kind": "widget|view|entity", "x": 0, "y": 0, "w": 6, "h": 4, "config": {} }]
|
|
1403
|
+
`)
|
|
1404
|
+
.action(async (viewId, opts) => {
|
|
1405
|
+
const { viewArrange } = await import("./commands/view.js");
|
|
1406
|
+
await viewArrange(viewId, opts);
|
|
1407
|
+
});
|
|
1408
|
+
// ─── explain ──────────────────────────────────────────────────────────────────
|
|
1409
|
+
program
|
|
1410
|
+
.command("explain [topic]")
|
|
1411
|
+
.description("Full capability map — what Synap can do and how (no network required)")
|
|
1412
|
+
.action(async (topic) => {
|
|
1413
|
+
const { explain } = await import("./commands/explain.js");
|
|
1414
|
+
await explain({ topic });
|
|
1415
|
+
});
|
|
1416
|
+
// ─── open ─────────────────────────────────────────────────────────────────────
|
|
1417
|
+
program
|
|
1418
|
+
.command("open <kind-or-id> [id]")
|
|
1419
|
+
.description("Open in the Synap desktop app. Use: open <kind> <id> or open <id> (auto-resolves type)")
|
|
1420
|
+
.action(async (kindOrId, id) => {
|
|
1421
|
+
if (id) {
|
|
1422
|
+
// open entity|view|cell|document|proposal <id>
|
|
1423
|
+
const validKinds = ["entity", "view", "cell", "document", "proposal"];
|
|
1424
|
+
if (!validKinds.includes(kindOrId)) {
|
|
1425
|
+
console.error(`Unknown kind: "${kindOrId}". Use: ${validKinds.join(" | ")}`);
|
|
1426
|
+
process.exit(1);
|
|
1427
|
+
}
|
|
1428
|
+
const { openInBrowser } = await import("./commands/open.js");
|
|
1429
|
+
await openInBrowser({ kind: kindOrId, id });
|
|
1430
|
+
}
|
|
1431
|
+
else {
|
|
1432
|
+
// open <id> — resolve type automatically
|
|
1433
|
+
const { resolveAndOpen } = await import("./commands/open.js");
|
|
1434
|
+
await resolveAndOpen(kindOrId);
|
|
1435
|
+
}
|
|
1436
|
+
});
|
|
1437
|
+
// ─── doc ──────────────────────────────────────────────────────────────────────
|
|
1438
|
+
const doc = program
|
|
1439
|
+
.command("doc")
|
|
1440
|
+
.description("Create and update markdown documents on the pod");
|
|
1441
|
+
doc
|
|
1442
|
+
.command("create")
|
|
1443
|
+
.description("Create a new markdown document")
|
|
1444
|
+
.requiredOption("--title <title>", "Document title")
|
|
1445
|
+
.option("--content <text>", "Markdown content (inline)")
|
|
1446
|
+
.option("--file <path>", "Read content from a file")
|
|
1447
|
+
.option("--workspace <id>", "Workspace to create the document in")
|
|
1448
|
+
.option("--open", "Open in the Synap desktop app after creation")
|
|
1449
|
+
.option("--json", "JSON output")
|
|
1450
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1451
|
+
.option("--api-key <key>", "API key override")
|
|
1452
|
+
.addHelpText("after", `
|
|
1453
|
+
Examples:
|
|
1454
|
+
synap doc create --title "My Notes" --content "# Hello"
|
|
1455
|
+
synap doc create --title "My Notes" --file ./notes.md --open
|
|
1456
|
+
echo "# Draft" | synap doc create --title "Draft"
|
|
1457
|
+
`)
|
|
1458
|
+
.action(async (opts) => {
|
|
1459
|
+
const { docCreate } = await import("./commands/doc.js");
|
|
1460
|
+
await docCreate(opts);
|
|
1461
|
+
});
|
|
1462
|
+
doc
|
|
1463
|
+
.command("update <documentId>")
|
|
1464
|
+
.description("Update a document's content (full replacement, proposal-gated)")
|
|
1465
|
+
.option("--content <text>", "New markdown content (inline)")
|
|
1466
|
+
.option("--file <path>", "Read new content from a file")
|
|
1467
|
+
.option("--title <title>", "Update document title (requires --content too)")
|
|
1468
|
+
.option("--open", "Open in the Synap desktop app after update")
|
|
1469
|
+
.option("--json", "JSON output")
|
|
1470
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1471
|
+
.option("--api-key <key>", "API key override")
|
|
1472
|
+
.addHelpText("after", `
|
|
1473
|
+
Examples:
|
|
1474
|
+
synap doc update <id> --content "# Updated"
|
|
1475
|
+
synap doc update <id> --file ./notes.md
|
|
1476
|
+
cat notes.md | synap doc update <id>
|
|
1477
|
+
`)
|
|
1478
|
+
.action(async (documentId, opts) => {
|
|
1479
|
+
const { docUpdate } = await import("./commands/doc.js");
|
|
1480
|
+
await docUpdate(documentId, opts);
|
|
1481
|
+
});
|
|
1482
|
+
// ─── cell ─────────────────────────────────────────────────────────────────────
|
|
1483
|
+
const cell = program
|
|
1484
|
+
.command("cell")
|
|
1485
|
+
.description("Define and bundle frame cells for the Synap runtime");
|
|
1486
|
+
cell
|
|
1487
|
+
.command("define")
|
|
1488
|
+
.description("Create or update a frame cell on the pod from ESM source")
|
|
1489
|
+
.requiredOption("--name <name>", "Cell display name")
|
|
1490
|
+
.option("--file <path>", "ESM source file (or pipe stdin)")
|
|
1491
|
+
.option("--type-key <key>", "Explicit typeKey (default: generated:<slug>)")
|
|
1492
|
+
.option("--deps <json>", 'Dependency map JSON, e.g. \'{"recharts":"2.12.0"}\' (sent in payload; backend support pending)')
|
|
1493
|
+
.option("--workspace <id>", "Workspace to scope the cell to (omit for pod-global)")
|
|
1494
|
+
.option("--description <text>", "Short description")
|
|
1495
|
+
.option("--open", "Open in the Synap desktop app after define")
|
|
1496
|
+
.option("--json", "JSON output")
|
|
1497
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1498
|
+
.option("--api-key <key>", "API key override")
|
|
1499
|
+
.addHelpText("after", `
|
|
1500
|
+
Examples:
|
|
1501
|
+
synap cell define --name "Revenue Chart" --file ./chart.js
|
|
1502
|
+
synap cell define --name "Revenue Chart" --file ./chart.js --deps '{"recharts":"2.12.0"}'
|
|
1503
|
+
cat chart.js | synap cell define --name "Revenue Chart"
|
|
1504
|
+
`)
|
|
1505
|
+
.action(async (opts) => {
|
|
1506
|
+
const { cellDefine } = await import("./commands/cell.js");
|
|
1507
|
+
await cellDefine(opts);
|
|
1508
|
+
});
|
|
1509
|
+
cell
|
|
1510
|
+
.command("build <entry>")
|
|
1511
|
+
.description("Bundle a multi-file cell/app into a single ESM module the runtime expects")
|
|
1512
|
+
.option("--out <file>", "Output file path (default: <entry>.bundle.js)")
|
|
1513
|
+
.option("--define", "Chain into cell define after bundling (requires --name)")
|
|
1514
|
+
.option("--name <name>", "Cell name (required with --define)")
|
|
1515
|
+
.option("--type-key <key>", "Explicit typeKey (used with --define)")
|
|
1516
|
+
.option("--deps <json>", "Override dependency versions as JSON, e.g. '{\"react\":\"18.3.0\"}'")
|
|
1517
|
+
.option("--workspace <id>", "Workspace (used with --define)")
|
|
1518
|
+
.option("--description <text>", "Description (used with --define)")
|
|
1519
|
+
.option("--open", "Open in browser after define (used with --define)")
|
|
1520
|
+
.option("--json", "JSON output")
|
|
1521
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1522
|
+
.option("--api-key <key>", "API key override")
|
|
1523
|
+
.addHelpText("after", `
|
|
1524
|
+
Output: a single ESM file. Bare imports (react, recharts, …) are externalized
|
|
1525
|
+
and emitted as a deps map. At runtime Synap resolves them via esm.sh importmap.
|
|
1526
|
+
|
|
1527
|
+
Examples:
|
|
1528
|
+
synap cell build ./src/chart.tsx --out ./dist/chart.js
|
|
1529
|
+
synap cell build ./src/chart.tsx --out ./dist/chart.js --define --name "Revenue Chart"
|
|
1530
|
+
`)
|
|
1531
|
+
.action(async (entry, opts) => {
|
|
1532
|
+
const { cellBuild } = await import("./commands/cell.js");
|
|
1533
|
+
await cellBuild(entry, opts);
|
|
1534
|
+
});
|
|
1535
|
+
// ─── artifact ─────────────────────────────────────────────────────────────────
|
|
1536
|
+
const artifact = program
|
|
1537
|
+
.command("artifact")
|
|
1538
|
+
.description("Create and manage HTML artifacts as Synap documents");
|
|
1539
|
+
artifact
|
|
1540
|
+
.command("create")
|
|
1541
|
+
.description("Create an HTML artifact from a local file")
|
|
1542
|
+
.requiredOption("--html <file>", "HTML file to upload")
|
|
1543
|
+
.option("--name <name>", "Document title (default: filename)")
|
|
1544
|
+
.option("--workspace <id>", "Workspace context")
|
|
1545
|
+
.option("--open", "Open in the Synap desktop app after creation")
|
|
1546
|
+
.option("--json", "JSON output")
|
|
1547
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1548
|
+
.option("--api-key <key>", "API key override")
|
|
1549
|
+
.action(async (opts) => {
|
|
1550
|
+
const { artifactCreate } = await import("./commands/artifact.js");
|
|
1551
|
+
await artifactCreate(opts);
|
|
1552
|
+
});
|
|
1553
|
+
// ─── connect (top-level shorthand) ───────────────────────────────────────────
|
|
1554
|
+
program
|
|
1555
|
+
.command("connect-service [service]")
|
|
1556
|
+
.description("Connect an external service (Google, GitHub, Notion, Linear, Slack, …)")
|
|
1557
|
+
.option("--workspace <id>", "Workspace context")
|
|
1558
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1559
|
+
.option("--api-key <key>", "API key override")
|
|
1560
|
+
.action(async (service, opts) => {
|
|
1561
|
+
const { toolsConnect } = await import("./commands/tools.js");
|
|
1562
|
+
await toolsConnect(service, opts);
|
|
1563
|
+
});
|
|
1564
|
+
// ─── tools ──────────────────────────────────────────────────────────────────
|
|
1565
|
+
const tools = program
|
|
1566
|
+
.command("tools")
|
|
1567
|
+
.description("Add and manage external service tools and their credentials");
|
|
1568
|
+
tools
|
|
1569
|
+
.command("list")
|
|
1570
|
+
.description("List available tools and their connection status")
|
|
1571
|
+
.option("--json", "Output as JSON")
|
|
1572
|
+
.option("--workspace <id>", "Workspace context")
|
|
1573
|
+
.action(async (opts) => {
|
|
1574
|
+
const { toolsList } = await import("./commands/tools.js");
|
|
1575
|
+
await toolsList(opts);
|
|
1576
|
+
});
|
|
1577
|
+
tools
|
|
1578
|
+
.command("connect <service>")
|
|
1579
|
+
.description("Connect a credential to a tool (via Nango OAuth or vault)")
|
|
1580
|
+
.option("--workspace <id>", "Workspace context")
|
|
1581
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1582
|
+
.option("--api-key <key>", "API key override")
|
|
1583
|
+
.action(async (service, opts) => {
|
|
1584
|
+
const { toolsConnect } = await import("./commands/tools.js");
|
|
1585
|
+
await toolsConnect(service, opts);
|
|
1586
|
+
});
|
|
1587
|
+
tools
|
|
1588
|
+
.command("sync <provider>")
|
|
1589
|
+
.description("Trigger a manual sync for a connected tool")
|
|
1590
|
+
.option("--workspace <id>", "Workspace context")
|
|
1591
|
+
.action(async (provider, opts) => {
|
|
1592
|
+
const { toolsSync } = await import("./commands/tools.js");
|
|
1593
|
+
await toolsSync(provider, opts);
|
|
1594
|
+
});
|
|
1595
|
+
tools
|
|
1596
|
+
.command("disconnect <provider>")
|
|
1597
|
+
.description("Revoke a tool's connection")
|
|
1598
|
+
.option("--workspace <id>", "Workspace context")
|
|
1599
|
+
.option("--force", "Skip confirmation")
|
|
1600
|
+
.action(async (provider, opts) => {
|
|
1601
|
+
const { toolsDisconnect } = await import("./commands/tools.js");
|
|
1602
|
+
await toolsDisconnect(provider, opts);
|
|
1603
|
+
});
|
|
1604
|
+
tools
|
|
1605
|
+
.command("schema")
|
|
1606
|
+
.description("Fetch tool schema and supported providers (AI context)")
|
|
1607
|
+
.option("--write-context [path]", "Write to .claude/TOOLS_CONTEXT.md")
|
|
1608
|
+
.option("--json", "Output raw JSON instead of formatted markdown")
|
|
1609
|
+
.action(async (opts) => {
|
|
1610
|
+
const { toolsSchema } = await import("./commands/tools.js");
|
|
1611
|
+
await toolsSchema(opts);
|
|
1612
|
+
});
|
|
1613
|
+
// ─── pod — unified pod-configuration view ─────────────────────────────────────
|
|
1614
|
+
// `market installed` shows what packages are installed; `pod` answers the
|
|
1615
|
+
// bigger question: what does the WHOLE pod look like — every workspace with
|
|
1616
|
+
// its provenance (marketplace/composed/ad-hoc/orphan), pod-wide vs
|
|
1617
|
+
// per-workspace capabilities/automations/playbooks, and the give/need feed
|
|
1618
|
+
// links between workspaces. Read surface for GET /api/hub/pod/config.
|
|
1619
|
+
const podCmd = program
|
|
1620
|
+
.command("pod")
|
|
1621
|
+
.description("Show the whole configured pod — workspaces (with provenance), capabilities/automations/playbooks, and feed links")
|
|
1622
|
+
.option("--json", "Output the full structured graph as JSON")
|
|
1623
|
+
.option("--orphans", "Only show orphan/ad-hoc workspaces and their template-match suggestions")
|
|
1624
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1625
|
+
.option("--api-key <key>", "API key override")
|
|
1626
|
+
.action(async (opts) => {
|
|
1627
|
+
const { pod } = await import("./commands/pod.js");
|
|
1628
|
+
await pod(opts);
|
|
1629
|
+
});
|
|
1630
|
+
podCmd
|
|
1631
|
+
.command("adopt <workspaceNameOrId>")
|
|
1632
|
+
.description("Link an orphan/ad-hoc workspace (by name or id) to a matching template — makes it version-tracked")
|
|
1633
|
+
.requiredOption("--template <slug>", "The template slug to adopt this workspace into")
|
|
1634
|
+
.option("--json", "Output as JSON")
|
|
1635
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1636
|
+
.option("--api-key <key>", "API key override")
|
|
1637
|
+
.action(async (workspaceNameOrId, _opts, cmd) => {
|
|
1638
|
+
// `--json` collides with the parent `pod` command's own `--json` — same
|
|
1639
|
+
// gap `market install` has (see its comment). Merge across the chain.
|
|
1640
|
+
const opts = cmd.optsWithGlobals();
|
|
1641
|
+
const { podAdopt } = await import("./commands/pod.js");
|
|
1642
|
+
await podAdopt(workspaceNameOrId, opts);
|
|
1643
|
+
});
|
|
1644
|
+
// ─── market — discover + install ANY package type ────────────────────────────
|
|
1645
|
+
// launch is workspace-first (bundled, offline); market reaches every CP package
|
|
1646
|
+
// type (capability/skill/workflow/view/cell/workspace), public or private.
|
|
1647
|
+
const market = program
|
|
1648
|
+
.command("market")
|
|
1649
|
+
.description("Browse + install packages (workspaces, capabilities, skills, workflows, views, cells) into a project")
|
|
1650
|
+
.option("--list", "List and exit (the default action)")
|
|
1651
|
+
.option("--search <query>", "Filter by name/description/slug")
|
|
1652
|
+
.option("--type <type>", "Filter by package type (workspace|capability|skill|workflow|view|cell)")
|
|
1653
|
+
.option("--json", "Output as JSON")
|
|
1654
|
+
.action(async (opts) => {
|
|
1655
|
+
const { market: marketBrowse } = await import("./commands/market.js");
|
|
1656
|
+
await marketBrowse(opts);
|
|
1657
|
+
});
|
|
1658
|
+
market
|
|
1659
|
+
.command("install <slug>")
|
|
1660
|
+
.description("Install a package by slug into a project — workspaces install now; other types route you to the right surface")
|
|
1661
|
+
.option("--project <id>", "Optionally tag the seeded entities to a project (installs are pod-wide by default)")
|
|
1662
|
+
.option("--onto <workspaceId>", "Reconcile this template ONTO an existing workspace (additive) instead of creating a new one")
|
|
1663
|
+
.option("--timeout <seconds>", "How long to wait for the apply to finish (default: 120)")
|
|
1664
|
+
.option("--json", "Output as JSON")
|
|
1665
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1666
|
+
.option("--api-key <key>", "API key override")
|
|
1667
|
+
.action(async (slug, _opts, cmd) => {
|
|
1668
|
+
// `--json` collides with the parent `market` command's own `--json` —
|
|
1669
|
+
// commander then attributes the flag's VALUE to the parent's
|
|
1670
|
+
// `_optionValues`, leaving this action's own `opts` argument `{}` for it
|
|
1671
|
+
// (a real, pre-existing gap: `market install <slug> --json` silently fell
|
|
1672
|
+
// back to human output). `optsWithGlobals()` walks the whole command
|
|
1673
|
+
// chain and merges regardless of which level actually captured the flag.
|
|
1674
|
+
const opts = cmd.optsWithGlobals();
|
|
1675
|
+
const { marketInstall } = await import("./commands/market.js");
|
|
1676
|
+
await marketInstall(slug, opts);
|
|
1677
|
+
});
|
|
1678
|
+
market
|
|
1679
|
+
.command("update [slugs...]")
|
|
1680
|
+
.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)")
|
|
1682
|
+
.option("--dry-run", "Force the preview path — never apply, even with --yes")
|
|
1683
|
+
.option("--timeout <seconds>", "How long to wait for each package's apply to finish (default: 120)")
|
|
1684
|
+
.option("--json", "Output as JSON")
|
|
1685
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1686
|
+
.option("--api-key <key>", "API key override")
|
|
1687
|
+
.action(async (slugs, _opts, cmd) => {
|
|
1688
|
+
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
1689
|
+
const opts = cmd.optsWithGlobals();
|
|
1690
|
+
const { marketUpdate } = await import("./commands/market.js");
|
|
1691
|
+
await marketUpdate(slugs && slugs.length > 0 ? slugs : undefined, opts);
|
|
1692
|
+
});
|
|
1693
|
+
market
|
|
1694
|
+
.command("installed")
|
|
1695
|
+
.description("List packages installed on this pod — a pure read, no writes (pairs with 'market update' to check drift)")
|
|
1696
|
+
.option("--outdated", "Only show packages with an update available")
|
|
1697
|
+
.option("--tree", "Show the composition graph — package → templates → resulting workspaces, marking shared nodes")
|
|
1698
|
+
.option("--layers", "Show the composition graph as a flat DAG — one row per slug, bedrock-first, with true fan-in counts")
|
|
1699
|
+
.option("--json", "Output as JSON")
|
|
1700
|
+
.action(async (_opts, cmd) => {
|
|
1701
|
+
// Same parent/child `--json` collision as `market install` — see its comment.
|
|
1702
|
+
const opts = cmd.optsWithGlobals();
|
|
1703
|
+
const { marketInstalled } = await import("./commands/market.js");
|
|
1704
|
+
await marketInstalled(opts);
|
|
1705
|
+
});
|
|
1706
|
+
// ─── capability ───────────────────────────────────────────────────────────────
|
|
1707
|
+
const capability = program
|
|
1708
|
+
.command("capability")
|
|
1709
|
+
.alias("cap")
|
|
1710
|
+
.description("The one capability-first root: list, add, enable, connect, show, run a capability pack");
|
|
1711
|
+
capability
|
|
1712
|
+
.command("list")
|
|
1713
|
+
.description("List capabilities — one row per pack, with status, connection, and verbs")
|
|
1714
|
+
.option("--json", "Output as JSON")
|
|
1715
|
+
.option("--workspace <id>", "Workspace context")
|
|
1716
|
+
.action(async (opts) => {
|
|
1717
|
+
const { capabilityList } = await import("./commands/capability.js");
|
|
1718
|
+
await capabilityList(opts);
|
|
1719
|
+
});
|
|
1720
|
+
capability
|
|
1721
|
+
.command("add [name]")
|
|
1722
|
+
.description("Install a capability from the catalog — omit the name to pick from a list")
|
|
1723
|
+
.option("--workspace <id>", "Workspace context")
|
|
1724
|
+
.action(async (name, opts) => {
|
|
1725
|
+
const { capabilityAdd } = await import("./commands/capability.js");
|
|
1726
|
+
await capabilityAdd(name, opts);
|
|
1727
|
+
});
|
|
1728
|
+
capability
|
|
1729
|
+
.command("create [file]")
|
|
1730
|
+
.description("Create a capability from a JSON definition (file path, or pipe JSON via stdin)")
|
|
1731
|
+
.option("--workspace <id>", "Workspace context")
|
|
1732
|
+
.action(async (file, opts) => {
|
|
1733
|
+
const { capabilityCreate } = await import("./commands/capability.js");
|
|
1734
|
+
await capabilityCreate(file, opts);
|
|
1735
|
+
});
|
|
1736
|
+
capability
|
|
1737
|
+
.command("rm <ids...>")
|
|
1738
|
+
.alias("remove")
|
|
1739
|
+
.description("Remove capability container(s) by id or name — member tools/skills untouched")
|
|
1740
|
+
.option("--workspace <id>", "Workspace context")
|
|
1741
|
+
.option("--force", "Skip the confirmation prompt")
|
|
1742
|
+
.action(async (ids, opts) => {
|
|
1743
|
+
const { capabilityRemove } = await import("./commands/capability.js");
|
|
1744
|
+
await capabilityRemove(ids, opts);
|
|
1745
|
+
});
|
|
1746
|
+
capability
|
|
1747
|
+
.command("enable [name]")
|
|
1748
|
+
.description("Turn on a capability — omit the name to pick from a list; ensures its connection, then pick which verbs it can do")
|
|
1749
|
+
.option("--workspace <id>", "Workspace context")
|
|
1750
|
+
.action(async (name, opts) => {
|
|
1751
|
+
const { capabilityEnable } = await import("./commands/capability.js");
|
|
1752
|
+
await capabilityEnable(name, opts);
|
|
1753
|
+
});
|
|
1754
|
+
capability
|
|
1755
|
+
.command("connect [name]")
|
|
1756
|
+
.description("Connect a service — omit the name to pick from connectable services")
|
|
1757
|
+
.option("--workspace <id>", "Workspace context")
|
|
1758
|
+
.action(async (name, opts) => {
|
|
1759
|
+
const { capabilityConnect } = await import("./commands/capability.js");
|
|
1760
|
+
await capabilityConnect(name, opts);
|
|
1761
|
+
});
|
|
1762
|
+
capability
|
|
1763
|
+
.command("disconnect <name>")
|
|
1764
|
+
.description("Disconnect a capability's service — accepts a capability name or a provider id")
|
|
1765
|
+
.option("--workspace <id>", "Workspace context")
|
|
1766
|
+
.option("--force", "Skip confirmation")
|
|
1767
|
+
.action(async (name, opts) => {
|
|
1768
|
+
const { capabilityDisconnect } = await import("./commands/capability.js");
|
|
1769
|
+
await capabilityDisconnect(name, opts);
|
|
1770
|
+
});
|
|
1771
|
+
capability
|
|
1772
|
+
.command("show <name>")
|
|
1773
|
+
.description("Show one capability's full detail: status, connection, verbs, next action")
|
|
1774
|
+
.option("--json", "Output as JSON")
|
|
1775
|
+
.option("--workspace <id>", "Workspace context")
|
|
1776
|
+
.action(async (name, opts) => {
|
|
1777
|
+
const { capabilityShow } = await import("./commands/capability.js");
|
|
1778
|
+
await capabilityShow(name, opts);
|
|
1779
|
+
});
|
|
1780
|
+
capability
|
|
1781
|
+
.command("run <verb> [params...]")
|
|
1782
|
+
.description("Launch a verb — pass inputs as `--key value` flags")
|
|
1783
|
+
.option("--workspace <id>", "Workspace context")
|
|
1784
|
+
.option("--connection <id>", "Run against a specific stored connection id")
|
|
1785
|
+
.option("--for <objId>", "Run against the connection bound to this context object id")
|
|
1786
|
+
.allowUnknownOption()
|
|
1787
|
+
.allowExcessArguments()
|
|
1788
|
+
.action(async (verb, params, opts) => {
|
|
1789
|
+
const { capabilityRun } = await import("./commands/capability.js");
|
|
1790
|
+
await capabilityRun(verb, params, opts);
|
|
1791
|
+
});
|
|
1792
|
+
capability
|
|
1793
|
+
.command("test <verb>")
|
|
1794
|
+
.description("Dry-run a verb (preview side effects without executing)")
|
|
1795
|
+
.option("--workspace <id>", "Workspace context")
|
|
1796
|
+
.action(async (verb, opts) => {
|
|
1797
|
+
const { capabilityTest } = await import("./commands/capability.js");
|
|
1798
|
+
await capabilityTest(verb, opts);
|
|
1799
|
+
});
|
|
1800
|
+
// ─── cap connections ──────────────────────────────────────────────────────────
|
|
1801
|
+
// Manage a capability's stored connections (credentials / OAuth accounts /
|
|
1802
|
+
// context bindings). Nested under `cap` — distinct from the top-level
|
|
1803
|
+
// `synap connections`, which shows agent-surface → pod wiring.
|
|
1804
|
+
const capConnections = capability
|
|
1805
|
+
.command("connections")
|
|
1806
|
+
.alias("conn")
|
|
1807
|
+
.description("Manage a capability's connections: list, add, update, rm");
|
|
1808
|
+
capConnections
|
|
1809
|
+
.command("list <capability>")
|
|
1810
|
+
.description("List a capability's connections (label, kind, default, context, id)")
|
|
1811
|
+
.option("--workspace <id>", "Workspace context")
|
|
1812
|
+
.action(async (capability, opts) => {
|
|
1813
|
+
const { capabilityConnectionsList } = await import("./commands/cap-connections.js");
|
|
1814
|
+
await capabilityConnectionsList(capability, opts);
|
|
1815
|
+
});
|
|
1816
|
+
capConnections
|
|
1817
|
+
.command("add <capability>")
|
|
1818
|
+
.description("Add a connection — prompts for label + masked value unless provided as flags")
|
|
1819
|
+
.option("--label <label>", "Connection label")
|
|
1820
|
+
.option("--value <value>", "Secret / credential value (else prompted, masked)")
|
|
1821
|
+
.option("--context-type <type>", "Context type this connection binds to")
|
|
1822
|
+
.option("--context-id <id>", "Context object id this connection binds to")
|
|
1823
|
+
.option("--account-hint <hint>", "Human-readable account hint (e.g. an email)")
|
|
1824
|
+
.option("--default", "Mark this connection as the capability's default")
|
|
1825
|
+
.option("--workspace <id>", "Workspace context")
|
|
1826
|
+
.action(async (capability, opts) => {
|
|
1827
|
+
const { capabilityConnectionsAdd } = await import("./commands/cap-connections.js");
|
|
1828
|
+
await capabilityConnectionsAdd(capability, opts);
|
|
1829
|
+
});
|
|
1830
|
+
capConnections
|
|
1831
|
+
.command("update <capability> <connectionId>")
|
|
1832
|
+
.description("Update a connection's fields; --rotate (or --value) rotates its secret")
|
|
1833
|
+
.option("--label <label>", "New connection label")
|
|
1834
|
+
.option("--value <value>", "New secret / credential value")
|
|
1835
|
+
.option("--rotate", "Prompt (masked) for a new secret value")
|
|
1836
|
+
.option("--context-type <type>", "New context type")
|
|
1837
|
+
.option("--context-id <id>", "New context object id")
|
|
1838
|
+
.option("--account-hint <hint>", "New account hint")
|
|
1839
|
+
.option("--default", "Mark this connection as the capability's default")
|
|
1840
|
+
.option("--workspace <id>", "Workspace context")
|
|
1841
|
+
.action(async (capability, connectionId, opts) => {
|
|
1842
|
+
const { capabilityConnectionsUpdate } = await import("./commands/cap-connections.js");
|
|
1843
|
+
await capabilityConnectionsUpdate(capability, connectionId, opts);
|
|
1844
|
+
});
|
|
1845
|
+
capConnections
|
|
1846
|
+
.command("rm <capability> <connectionId>")
|
|
1847
|
+
.alias("remove")
|
|
1848
|
+
.description("Remove a connection by id (confirms first)")
|
|
1849
|
+
.option("--workspace <id>", "Workspace context")
|
|
1850
|
+
.action(async (capability, connectionId, opts) => {
|
|
1851
|
+
const { capabilityConnectionsRemove } = await import("./commands/cap-connections.js");
|
|
1852
|
+
await capabilityConnectionsRemove(capability, connectionId, opts);
|
|
1853
|
+
});
|
|
1854
|
+
// ─── raycast ──────────────────────────────────────────────────────────────────
|
|
1855
|
+
const raycast = program
|
|
1856
|
+
.command("raycast")
|
|
1857
|
+
.description("Generate Raycast Script Commands from your enabled capabilities");
|
|
1858
|
+
raycast
|
|
1859
|
+
.command("generate")
|
|
1860
|
+
.description("Emit a Raycast Script Command per enabled runnable verb")
|
|
1861
|
+
.option("--out <dir>", "Output directory (default: ~/.synap/raycast-commands)")
|
|
1862
|
+
.option("--workspace <id>", "Workspace context")
|
|
1863
|
+
.action(async (opts) => {
|
|
1864
|
+
const { raycastGenerate } = await import("./commands/raycast.js");
|
|
1865
|
+
await raycastGenerate(opts);
|
|
1866
|
+
});
|
|
1867
|
+
// ─── providers ───────────────────────────────────────────────────────────────
|
|
1868
|
+
const providers = program
|
|
1869
|
+
.command("providers")
|
|
1870
|
+
.description("Discover AI providers from the pod and configure local tools");
|
|
1871
|
+
providers
|
|
1872
|
+
.command("list", { isDefault: true })
|
|
1873
|
+
.description("Show enabled AI providers and their models")
|
|
1874
|
+
.option("--json", "Output as JSON")
|
|
1875
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1876
|
+
.option("--api-key <key>", "API key override")
|
|
1877
|
+
.action(async (opts) => {
|
|
1878
|
+
const { providersList } = await import("./commands/providers.js");
|
|
1879
|
+
await providersList(opts);
|
|
1880
|
+
});
|
|
1881
|
+
providers
|
|
1882
|
+
.command("pull")
|
|
1883
|
+
.description("Write pod provider config to a local AI tool (opencode, aider)")
|
|
1884
|
+
.option("--target <name>", "Target tool: opencode | aider")
|
|
1885
|
+
.option("--pod-url <url>", "Pod URL override")
|
|
1886
|
+
.option("--api-key <key>", "API key override")
|
|
1887
|
+
.action(async (opts) => {
|
|
1888
|
+
const { providersPull } = await import("./commands/providers.js");
|
|
1889
|
+
await providersPull(opts);
|
|
1890
|
+
});
|
|
1891
|
+
// ─── keys ────────────────────────────────────────────────────────────────────
|
|
1892
|
+
const keys = program
|
|
1893
|
+
.command("keys")
|
|
1894
|
+
.description("Manage pod API keys");
|
|
1895
|
+
keys
|
|
1896
|
+
.command("rotate")
|
|
1897
|
+
.description("Rotate your CLI key to pick up the latest scope set")
|
|
1898
|
+
.action(async () => {
|
|
1899
|
+
const { keysRotate } = await import("./commands/keys.js");
|
|
1900
|
+
await keysRotate({});
|
|
1901
|
+
});
|
|
1902
|
+
// Resolve a global `--pod <name>` before commander parses (it isn't registered
|
|
1903
|
+
// per-command). Fails fast with a clear message on an unknown profile name.
|
|
1904
|
+
try {
|
|
1905
|
+
bootstrapPodOverride(process.argv);
|
|
1906
|
+
}
|
|
1907
|
+
catch (err) {
|
|
1908
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1909
|
+
process.exit(1);
|
|
1910
|
+
}
|
|
1911
|
+
// Last-resort net. Commander does not await async .action() handlers, so a
|
|
1912
|
+
// command that throws without its own catch becomes an unhandled rejection and
|
|
1913
|
+
// Node dumps a raw stack trace with dist/ paths at the user — e.g.
|
|
1914
|
+
// `synap digest --workspace <inaccessible>` printed the HubError constructor
|
|
1915
|
+
// frame. Render it through the one door instead. Commands that already catch
|
|
1916
|
+
// and render are unaffected: this only fires when nothing else handled it.
|
|
1917
|
+
process.on("unhandledRejection", (err) => {
|
|
1918
|
+
void (async () => {
|
|
1919
|
+
try {
|
|
1920
|
+
const { renderHubError } = await import("./lib/hub-client.js");
|
|
1921
|
+
renderHubError(err);
|
|
1922
|
+
}
|
|
1923
|
+
catch {
|
|
1924
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
1925
|
+
}
|
|
1926
|
+
process.exit(1);
|
|
1927
|
+
})();
|
|
1928
|
+
});
|
|
607
1929
|
program.parse();
|
|
608
1930
|
//# sourceMappingURL=index.js.map
|