@synap-core/cli 1.11.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +40 -198
- package/dist/build-info.json +6 -0
- package/dist/commands/agent-run.js +3 -2
- package/dist/commands/agent-run.js.map +1 -1
- package/dist/commands/agents.d.ts +32 -17
- package/dist/commands/agents.js +203 -237
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/app.d.ts +143 -0
- package/dist/commands/app.js +524 -0
- package/dist/commands/app.js.map +1 -0
- package/dist/commands/automate.d.ts +21 -0
- package/dist/commands/automate.js +42 -0
- package/dist/commands/automate.js.map +1 -0
- package/dist/commands/automation-schema.test.d.ts +16 -0
- package/dist/commands/automation-schema.test.js +77 -0
- package/dist/commands/automation-schema.test.js.map +1 -0
- package/dist/commands/automation.d.ts +12 -0
- package/dist/commands/automation.js +116 -66
- package/dist/commands/automation.js.map +1 -1
- package/dist/commands/box.d.ts +42 -0
- package/dist/commands/box.js +89 -0
- package/dist/commands/box.js.map +1 -0
- package/dist/commands/bridge-setup.d.ts +14 -1
- package/dist/commands/bridge-setup.js +395 -129
- package/dist/commands/bridge-setup.js.map +1 -1
- package/dist/commands/cap-connections.d.ts +4 -4
- package/dist/commands/cap-connections.js +14 -14
- package/dist/commands/cap-connections.js.map +1 -1
- package/dist/commands/capability.d.ts +3 -1
- package/dist/commands/capability.js +249 -176
- package/dist/commands/capability.js.map +1 -1
- package/dist/commands/catalog.d.ts +275 -0
- package/dist/commands/catalog.js +481 -0
- package/dist/commands/catalog.js.map +1 -0
- package/dist/commands/cell.d.ts +155 -8
- package/dist/commands/cell.js +416 -40
- package/dist/commands/cell.js.map +1 -1
- package/dist/commands/centrality.js +1 -13
- package/dist/commands/centrality.js.map +1 -1
- package/dist/commands/close-questions.d.ts +27 -0
- package/dist/commands/close-questions.js +49 -0
- package/dist/commands/close-questions.js.map +1 -0
- package/dist/commands/close-questions.test.d.ts +1 -0
- package/dist/commands/close-questions.test.js +52 -0
- package/dist/commands/close-questions.test.js.map +1 -0
- package/dist/commands/connect.d.ts +36 -13
- package/dist/commands/connect.js +68 -167
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/connections.d.ts +3 -2
- package/dist/commands/connections.js +95 -25
- package/dist/commands/connections.js.map +1 -1
- package/dist/commands/context.js +79 -44
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/data-extra.d.ts +34 -0
- package/dist/commands/data-extra.js +203 -25
- package/dist/commands/data-extra.js.map +1 -1
- package/dist/commands/data.d.ts +120 -2
- package/dist/commands/data.js +295 -21
- package/dist/commands/data.js.map +1 -1
- package/dist/commands/diagnose.d.ts +66 -4
- package/dist/commands/diagnose.js +285 -28
- package/dist/commands/diagnose.js.map +1 -1
- package/dist/commands/doc.d.ts +11 -4
- package/dist/commands/doc.js +39 -14
- package/dist/commands/doc.js.map +1 -1
- package/dist/commands/doctor.d.ts +133 -3
- package/dist/commands/doctor.js +761 -41
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain.js +5 -5
- package/dist/commands/explain.js.map +1 -1
- package/dist/commands/hooks.d.ts +19 -0
- package/dist/commands/hooks.js +70 -0
- package/dist/commands/hooks.js.map +1 -0
- package/dist/commands/import.d.ts +393 -13
- package/dist/commands/import.js +1150 -54
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/init.d.ts +34 -9
- package/dist/commands/init.js +481 -981
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys.d.ts +1 -0
- package/dist/commands/keys.js +15 -2
- package/dist/commands/keys.js.map +1 -1
- package/dist/commands/knowledge.d.ts +22 -6
- package/dist/commands/knowledge.js +121 -57
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/lens.d.ts +37 -1
- package/dist/commands/lens.js +194 -72
- package/dist/commands/lens.js.map +1 -1
- package/dist/commands/market-authoring.d.ts +29 -2
- package/dist/commands/market-authoring.js +348 -7
- package/dist/commands/market-authoring.js.map +1 -1
- package/dist/commands/market-official.d.ts +58 -0
- package/dist/commands/market-official.js +84 -0
- package/dist/commands/market-official.js.map +1 -0
- package/dist/commands/market.d.ts +400 -16
- package/dist/commands/market.js +1802 -146
- package/dist/commands/market.js.map +1 -1
- package/dist/commands/mcp.d.ts +60 -25
- package/dist/commands/mcp.js +251 -64
- package/dist/commands/mcp.js.map +1 -1
- package/dist/commands/observe.category.test.d.ts +1 -0
- package/dist/commands/observe.category.test.js +59 -0
- package/dist/commands/observe.category.test.js.map +1 -0
- package/dist/commands/observe.d.ts +3 -0
- package/dist/commands/observe.js +7 -5
- package/dist/commands/observe.js.map +1 -1
- package/dist/commands/observe.title.test.d.ts +1 -0
- package/dist/commands/observe.title.test.js +37 -0
- package/dist/commands/observe.title.test.js.map +1 -0
- package/dist/commands/open.d.ts +39 -9
- package/dist/commands/open.js +80 -25
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/playbook.d.ts +42 -0
- package/dist/commands/playbook.js +171 -0
- package/dist/commands/playbook.js.map +1 -0
- package/dist/commands/pod.js +1 -1
- package/dist/commands/pod.js.map +1 -1
- package/dist/commands/pods.d.ts +11 -1
- package/dist/commands/pods.js +129 -131
- package/dist/commands/pods.js.map +1 -1
- package/dist/commands/proposals-actions.d.ts +62 -0
- package/dist/commands/proposals-actions.js +143 -8
- package/dist/commands/proposals-actions.js.map +1 -1
- package/dist/commands/proposals-await.d.ts +68 -0
- package/dist/commands/proposals-await.js +248 -0
- package/dist/commands/proposals-await.js.map +1 -0
- package/dist/commands/proton-setup.d.ts +73 -0
- package/dist/commands/proton-setup.js +579 -0
- package/dist/commands/proton-setup.js.map +1 -0
- package/dist/commands/providers.d.ts +23 -0
- package/dist/commands/providers.js +126 -1
- package/dist/commands/providers.js.map +1 -1
- package/dist/commands/raycast.js +6 -2
- package/dist/commands/raycast.js.map +1 -1
- package/dist/commands/rule.d.ts +150 -0
- package/dist/commands/rule.js +447 -0
- package/dist/commands/rule.js.map +1 -0
- package/dist/commands/session-feed-wait.d.ts +48 -0
- package/dist/commands/session-feed-wait.js +261 -0
- package/dist/commands/session-feed-wait.js.map +1 -0
- package/dist/commands/session-post.d.ts +40 -0
- package/dist/commands/session-post.js +96 -0
- package/dist/commands/session-post.js.map +1 -0
- package/dist/commands/session-wait.d.ts +116 -0
- package/dist/commands/session-wait.js +224 -0
- package/dist/commands/session-wait.js.map +1 -0
- package/dist/commands/sessions.d.ts +54 -0
- package/dist/commands/sessions.js +501 -58
- package/dist/commands/sessions.js.map +1 -1
- package/dist/commands/skill-manage.d.ts +21 -0
- package/dist/commands/skill-manage.js +136 -19
- package/dist/commands/skill-manage.js.map +1 -1
- package/dist/commands/skills-commands.d.ts +2 -0
- package/dist/commands/skills-commands.js +9 -1
- package/dist/commands/skills-commands.js.map +1 -1
- package/dist/commands/skills-commands.test.d.ts +1 -0
- package/dist/commands/skills-commands.test.js +57 -0
- package/dist/commands/skills-commands.test.js.map +1 -0
- package/dist/commands/skills.js +16 -0
- package/dist/commands/skills.js.map +1 -1
- package/dist/commands/status.d.ts +1 -4
- package/dist/commands/status.js +6 -35
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/statusline.backoff.test.d.ts +13 -0
- package/dist/commands/statusline.backoff.test.js +100 -0
- package/dist/commands/statusline.backoff.test.js.map +1 -0
- package/dist/commands/statusline.js +16 -9
- package/dist/commands/statusline.js.map +1 -1
- package/dist/commands/sync-status.d.ts +12 -0
- package/dist/commands/sync-status.js +125 -0
- package/dist/commands/sync-status.js.map +1 -0
- package/dist/commands/templates-retire.d.ts +34 -0
- package/dist/commands/templates-retire.js +192 -0
- package/dist/commands/templates-retire.js.map +1 -0
- package/dist/commands/tools.js +6 -21
- package/dist/commands/tools.js.map +1 -1
- package/dist/commands/tracks.d.ts +112 -0
- package/dist/commands/tracks.js +543 -0
- package/dist/commands/tracks.js.map +1 -0
- package/dist/commands/update.d.ts +3 -11
- package/dist/commands/update.js +5 -134
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/upload.d.ts +41 -3
- package/dist/commands/upload.js +120 -18
- package/dist/commands/upload.js.map +1 -1
- package/dist/commands/vendor.d.ts +28 -0
- package/dist/commands/vendor.js +110 -0
- package/dist/commands/vendor.js.map +1 -0
- package/dist/commands/versions.js +6 -0
- package/dist/commands/versions.js.map +1 -1
- package/dist/commands/view.js +10 -5
- package/dist/commands/view.js.map +1 -1
- package/dist/commands/whoami.d.ts +30 -3
- package/dist/commands/whoami.js +186 -23
- package/dist/commands/whoami.js.map +1 -1
- package/dist/commands/worker-accounts.d.ts +149 -0
- package/dist/commands/worker-accounts.js +339 -0
- package/dist/commands/worker-accounts.js.map +1 -0
- package/dist/commands/worker-accounts.test.d.ts +1 -0
- package/dist/commands/worker-accounts.test.js +224 -0
- package/dist/commands/worker-accounts.test.js.map +1 -0
- package/dist/commands/worker.d.ts +331 -0
- package/dist/commands/worker.js +1067 -0
- package/dist/commands/worker.js.map +1 -0
- package/dist/commands/worker.test.d.ts +1 -0
- package/dist/commands/worker.test.js +427 -0
- package/dist/commands/worker.test.js.map +1 -0
- package/dist/commands/workspace-ops.d.ts +35 -0
- package/dist/commands/workspace-ops.js +153 -0
- package/dist/commands/workspace-ops.js.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +1043 -186
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-connections.d.ts +31 -0
- package/dist/lib/agent-connections.js +33 -0
- package/dist/lib/agent-connections.js.map +1 -0
- package/dist/lib/agent-detect.d.ts +27 -0
- package/dist/lib/agent-detect.js +71 -0
- package/dist/lib/agent-detect.js.map +1 -0
- package/dist/lib/agent-door.d.ts +136 -0
- package/dist/lib/agent-door.js +429 -0
- package/dist/lib/agent-door.js.map +1 -0
- package/dist/lib/agents-config.d.ts +2 -0
- package/dist/lib/agents-config.js +4 -9
- package/dist/lib/agents-config.js.map +1 -1
- package/dist/lib/approval-poll.d.ts +31 -2
- package/dist/lib/approval-poll.js +20 -7
- package/dist/lib/approval-poll.js.map +1 -1
- package/dist/lib/atomic-file.d.ts +48 -0
- package/dist/lib/atomic-file.js +129 -0
- package/dist/lib/atomic-file.js.map +1 -0
- package/dist/lib/auth.d.ts +17 -11
- package/dist/lib/auth.js +47 -64
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/batch-approval.d.ts +85 -0
- package/dist/lib/batch-approval.js +170 -0
- package/dist/lib/batch-approval.js.map +1 -0
- package/dist/lib/box/egress.d.ts +82 -0
- package/dist/lib/box/egress.js +264 -0
- package/dist/lib/box/egress.js.map +1 -0
- package/dist/lib/box/evidence.d.ts +86 -0
- package/dist/lib/box/evidence.js +121 -0
- package/dist/lib/box/evidence.js.map +1 -0
- package/dist/lib/box/job-server.d.ts +72 -0
- package/dist/lib/box/job-server.js +246 -0
- package/dist/lib/box/job-server.js.map +1 -0
- package/dist/lib/box/provisioner.d.ts +83 -0
- package/dist/lib/box/provisioner.js +312 -0
- package/dist/lib/box/provisioner.js.map +1 -0
- package/dist/lib/box/proxmox.d.ts +112 -0
- package/dist/lib/box/proxmox.js +211 -0
- package/dist/lib/box/proxmox.js.map +1 -0
- package/dist/lib/box/wire.d.ts +98 -0
- package/dist/lib/box/wire.js +70 -0
- package/dist/lib/box/wire.js.map +1 -0
- package/dist/lib/capture-lane.d.ts +6 -5
- package/dist/lib/capture-lane.js +6 -5
- package/dist/lib/capture-lane.js.map +1 -1
- package/dist/lib/capture-structure.d.ts +230 -11
- package/dist/lib/capture-structure.js +251 -13
- package/dist/lib/capture-structure.js.map +1 -1
- package/dist/lib/catalog-templates.d.ts +59 -0
- package/dist/lib/catalog-templates.js +126 -0
- package/dist/lib/catalog-templates.js.map +1 -0
- package/dist/lib/cli-build.d.ts +19 -0
- package/dist/lib/cli-build.js +37 -0
- package/dist/lib/cli-build.js.map +1 -0
- package/dist/lib/client-header.test.d.ts +1 -0
- package/dist/lib/client-header.test.js +85 -0
- package/dist/lib/client-header.test.js.map +1 -0
- package/dist/lib/conversation-headers.d.ts +33 -0
- package/dist/lib/conversation-headers.js +69 -0
- package/dist/lib/conversation-headers.js.map +1 -0
- package/dist/lib/cp-packages.d.ts +167 -11
- package/dist/lib/cp-packages.js +253 -21
- package/dist/lib/cp-packages.js.map +1 -1
- package/dist/lib/credential-class.d.ts +144 -0
- package/dist/lib/credential-class.js +138 -0
- package/dist/lib/credential-class.js.map +1 -0
- package/dist/lib/describe-lens.d.ts +35 -0
- package/dist/lib/describe-lens.js +40 -0
- package/dist/lib/describe-lens.js.map +1 -1
- package/dist/lib/device-connect.d.ts +125 -0
- package/dist/lib/device-connect.js +256 -0
- package/dist/lib/device-connect.js.map +1 -0
- package/dist/lib/directory-lens.d.ts +99 -0
- package/dist/lib/directory-lens.js +187 -0
- package/dist/lib/directory-lens.js.map +1 -0
- package/dist/lib/exporter-coverage.d.ts +71 -0
- package/dist/lib/exporter-coverage.js +97 -0
- package/dist/lib/exporter-coverage.js.map +1 -0
- package/dist/lib/goal-words.d.ts +38 -0
- package/dist/lib/goal-words.js +112 -0
- package/dist/lib/goal-words.js.map +1 -0
- package/dist/lib/hub-client.d.ts +57 -15
- package/dist/lib/hub-client.js +396 -82
- package/dist/lib/hub-client.js.map +1 -1
- package/dist/lib/init-connect.d.ts +41 -0
- package/dist/lib/init-connect.js +75 -0
- package/dist/lib/init-connect.js.map +1 -0
- package/dist/lib/init-exit.d.ts +24 -0
- package/dist/lib/init-exit.js +41 -0
- package/dist/lib/init-exit.js.map +1 -0
- package/dist/lib/init-flow.d.ts +25 -0
- package/dist/lib/init-flow.js +40 -0
- package/dist/lib/init-flow.js.map +1 -0
- package/dist/lib/init-handoff.d.ts +24 -0
- package/dist/lib/init-handoff.js +26 -0
- package/dist/lib/init-handoff.js.map +1 -0
- package/dist/lib/init-output.d.ts +18 -0
- package/dist/lib/init-output.js +43 -0
- package/dist/lib/init-output.js.map +1 -0
- package/dist/lib/init-pod.d.ts +45 -0
- package/dist/lib/init-pod.js +36 -0
- package/dist/lib/init-pod.js.map +1 -0
- package/dist/lib/installed.d.ts +210 -11
- package/dist/lib/installed.js +234 -36
- package/dist/lib/installed.js.map +1 -1
- package/dist/lib/key-approval.d.ts +57 -0
- package/dist/lib/key-approval.js +117 -0
- package/dist/lib/key-approval.js.map +1 -0
- package/dist/lib/key-diagnosis.d.ts +56 -0
- package/dist/lib/key-diagnosis.js +227 -0
- package/dist/lib/key-diagnosis.js.map +1 -0
- package/dist/lib/key-doctor.d.ts +136 -0
- package/dist/lib/key-doctor.js +286 -0
- package/dist/lib/key-doctor.js.map +1 -0
- package/dist/lib/key-locations.d.ts +120 -0
- package/dist/lib/key-locations.js +326 -0
- package/dist/lib/key-locations.js.map +1 -0
- package/dist/lib/key-source.d.ts +68 -0
- package/dist/lib/key-source.js +109 -0
- package/dist/lib/key-source.js.map +1 -0
- package/dist/lib/key-state.d.ts +70 -0
- package/dist/lib/key-state.js +115 -0
- package/dist/lib/key-state.js.map +1 -0
- package/dist/lib/kind-package.d.ts +181 -0
- package/dist/lib/kind-package.js +679 -0
- package/dist/lib/kind-package.js.map +1 -0
- package/dist/lib/knowledge-title.d.ts +25 -0
- package/dist/lib/knowledge-title.js +47 -0
- package/dist/lib/knowledge-title.js.map +1 -0
- package/dist/lib/knowledge-title.test.d.ts +1 -0
- package/dist/lib/knowledge-title.test.js +34 -0
- package/dist/lib/knowledge-title.test.js.map +1 -0
- package/dist/lib/machine-instance.d.ts +64 -0
- package/dist/lib/machine-instance.js +142 -0
- package/dist/lib/machine-instance.js.map +1 -0
- package/dist/lib/mcp-bridge.d.ts +49 -0
- package/dist/lib/mcp-bridge.js +180 -0
- package/dist/lib/mcp-bridge.js.map +1 -0
- package/dist/lib/mcp-bridge.test.d.ts +1 -0
- package/dist/lib/mcp-bridge.test.js +118 -0
- package/dist/lib/mcp-bridge.test.js.map +1 -0
- package/dist/lib/mcp-call.d.ts +30 -0
- package/dist/lib/mcp-call.js +107 -0
- package/dist/lib/mcp-call.js.map +1 -0
- package/dist/lib/mcp-snippets.d.ts +53 -0
- package/dist/lib/mcp-snippets.js +82 -0
- package/dist/lib/mcp-snippets.js.map +1 -0
- package/dist/lib/next-steps.d.ts +8 -0
- package/dist/lib/next-steps.js +31 -1
- package/dist/lib/next-steps.js.map +1 -1
- package/dist/lib/openclaw.js +3 -2
- package/dist/lib/openclaw.js.map +1 -1
- package/dist/lib/package-wire.d.ts +179 -0
- package/dist/lib/package-wire.js +68 -0
- package/dist/lib/package-wire.js.map +1 -0
- package/dist/lib/pair-link.d.ts +38 -0
- package/dist/lib/pair-link.js +68 -0
- package/dist/lib/pair-link.js.map +1 -0
- package/dist/lib/pod-moved.d.ts +70 -0
- package/dist/lib/pod-moved.js +146 -0
- package/dist/lib/pod-moved.js.map +1 -0
- package/dist/lib/pod-reach.d.ts +39 -0
- package/dist/lib/pod-reach.js +117 -0
- package/dist/lib/pod-reach.js.map +1 -0
- package/dist/lib/pod-reach.test.d.ts +1 -0
- package/dist/lib/pod-reach.test.js +67 -0
- package/dist/lib/pod-reach.test.js.map +1 -0
- package/dist/lib/pod-wide.d.ts +40 -0
- package/dist/lib/pod-wide.js +46 -0
- package/dist/lib/pod-wide.js.map +1 -0
- package/dist/lib/pod.d.ts +74 -112
- package/dist/lib/pod.js +146 -415
- package/dist/lib/pod.js.map +1 -1
- package/dist/lib/project-ref.d.ts +9 -3
- package/dist/lib/project-ref.js +10 -4
- package/dist/lib/project-ref.js.map +1 -1
- package/dist/lib/register-claude-code-mcp.test.d.ts +1 -0
- package/dist/lib/register-claude-code-mcp.test.js +78 -0
- package/dist/lib/register-claude-code-mcp.test.js.map +1 -0
- package/dist/lib/review-credential.d.ts +119 -0
- package/dist/lib/review-credential.js +149 -0
- package/dist/lib/review-credential.js.map +1 -0
- package/dist/lib/safe-open.d.ts +49 -0
- package/dist/lib/safe-open.js +119 -0
- package/dist/lib/safe-open.js.map +1 -0
- package/dist/lib/session-feed.d.ts +185 -0
- package/dist/lib/session-feed.js +257 -0
- package/dist/lib/session-feed.js.map +1 -0
- package/dist/lib/session-lens.d.ts +40 -1
- package/dist/lib/session-lens.js +54 -4
- package/dist/lib/session-lens.js.map +1 -1
- package/dist/lib/superwhisper-import.d.ts +8 -0
- package/dist/lib/superwhisper-import.js +14 -7
- package/dist/lib/superwhisper-import.js.map +1 -1
- package/dist/lib/superwhisper-title.test.d.ts +1 -0
- package/dist/lib/superwhisper-title.test.js +18 -0
- package/dist/lib/superwhisper-title.test.js.map +1 -0
- package/dist/lib/targets.d.ts +152 -10
- package/dist/lib/targets.js +974 -325
- package/dist/lib/targets.js.map +1 -1
- package/dist/lib/template-file.d.ts +4 -0
- package/dist/lib/template-file.js.map +1 -1
- package/dist/lib/template-lifecycle.d.ts +217 -0
- package/dist/lib/template-lifecycle.js +433 -0
- package/dist/lib/template-lifecycle.js.map +1 -0
- package/dist/lib/template-steps.d.ts +88 -0
- package/dist/lib/template-steps.js +118 -0
- package/dist/lib/template-steps.js.map +1 -0
- package/dist/lib/time-ago.d.ts +2 -0
- package/dist/lib/time-ago.js +15 -0
- package/dist/lib/time-ago.js.map +1 -0
- package/dist/lib/wake-hook-settings.d.ts +57 -0
- package/dist/lib/wake-hook-settings.js +153 -0
- package/dist/lib/wake-hook-settings.js.map +1 -0
- package/dist/lib/wake-state.d.ts +65 -0
- package/dist/lib/wake-state.js +122 -0
- package/dist/lib/wake-state.js.map +1 -0
- package/dist/utils/logger.js +5 -2
- package/dist/utils/logger.js.map +1 -1
- package/package.json +26 -17
- package/skills/README.md +13 -11
- package/skills/agent-os/SKILL.md +214 -99
- package/skills/manifest.json +1 -1
- package/skills/onboard/SKILL.md +55 -26
- package/skills/synap/README.md +5 -8
- package/skills/synap/SKILL.md +1149 -289
- package/skills/synap/_order.txt +7 -0
- package/skills/synap/_skill.yaml +1 -1
- package/skills/synap/automations.md +15 -0
- package/skills/synap/capture.md +5 -0
- package/skills/synap/cli-operations.md +24 -18
- package/skills/synap/code-skills.md +70 -0
- package/skills/synap/concepts.md +36 -0
- package/skills/synap/content-os.md +10 -1
- package/skills/synap/creative-loop.md +15 -10
- package/skills/synap/crm.md +21 -52
- package/skills/synap/document-embeds.md +143 -47
- package/skills/synap/escalation-ladder.md +20 -10
- package/skills/synap/focus-sessions.md +56 -21
- package/skills/synap/from-intent.md +158 -0
- package/skills/synap/governance-rules.md +5 -5
- package/skills/synap/governance.md +10 -7
- package/skills/synap/hand-off.md +33 -0
- package/skills/synap/inline-patterns.md +15 -7
- package/skills/synap/lenses.md +34 -16
- package/skills/synap/linking.md +42 -41
- package/skills/synap/mcp-remote-servers.md +64 -0
- package/skills/synap/mental-model.md +17 -15
- package/skills/synap/operating-mode-rules.md +2 -2
- package/skills/synap/processes.md +118 -0
- package/skills/synap/quick-reference.md +7 -2
- package/skills/synap/reading.md +3 -1
- package/skills/synap/reflexes.md +12 -42
- package/skills/synap/viewframe-cells.md +38 -5
- package/skills/synap/work-flow.md +1 -1
- package/skills/synap/work-model.md +110 -0
- package/skills/synap/worked-examples.md +4 -5
- package/skills/synap/workspace-design.md +15 -11
- package/skills/synap/writes.md +105 -25
- package/skills/synap/writing-titles.md +63 -0
- package/skills/synap-app/SKILL.md +149 -67
- package/skills/synap-app/_skill.yaml +1 -1
- package/skills/synap-app/creating-the-base-app.md +12 -7
- package/skills/synap-app/governance.md +27 -16
- package/skills/synap-app/install-commands.md +18 -9
- package/skills/synap-app/overview.md +16 -9
- package/skills/synap-app/using-the-sdk.md +75 -25
- package/skills/synap-design/SKILL.md +474 -0
- package/skills/synap-design/_order.txt +4 -0
- package/skills/synap-design/_skill.yaml +21 -0
- package/skills/synap-design/loop.md +134 -0
- package/skills/synap-design/overview.md +44 -0
- package/skills/synap-design/principles.md +130 -0
- package/skills/synap-design/system.md +133 -0
- package/skills/synap-market/SKILL.md +306 -16
- package/skills/synap-market/_skill.yaml +1 -1
- package/skills/synap-market/author-and-publish.md +145 -8
- package/skills/synap-market/governance-and-catalog.md +7 -0
- package/skills/synap-market/install.md +79 -1
- package/skills/synap-market/overview.md +74 -6
- package/skills/synap-schema/SKILL.md +172 -10
- package/skills/synap-schema/_order.txt +2 -0
- package/skills/synap-schema/_skill.yaml +4 -2
- package/skills/synap-schema/common-mistakes.md +4 -2
- package/skills/synap-schema/discover-profiles.md +1 -1
- package/skills/synap-schema/entity-scope.md +15 -3
- package/skills/synap-schema/extend-first.md +29 -0
- package/skills/synap-schema/extend-vs-create.md +1 -1
- package/skills/synap-schema/intent-vocabulary-ssot.md +111 -0
- package/skills/synap-schema/property-types.md +1 -1
- package/skills/synap-schema/relations.md +1 -1
- package/skills/synap-ui/SKILL.md +19 -12
- package/skills/synap-ui/_skill.yaml +1 -1
- package/skills/synap-ui/ai-companion.md +1 -1
- package/skills/synap-ui/arranging-bento.md +2 -0
- package/skills/synap-ui/bento-layouts.md +10 -10
- package/skills/synap-ui/bento-recipes.md +313 -543
- package/skills/synap-ui/four-builds.md +5 -0
- package/skills/synap-ui/view-types.md +2 -2
- package/skills/synap-ui/widget-catalog.md +22 -278
- package/templates/automations/bookmark-enrichment.automation.json +290 -13
- package/templates/automations/url-bookmark-capture.automation.json +73 -11
- package/templates/box/runner.py +206 -0
- package/templates/skills/authoring-playbooks/SKILL.md +6 -3
- package/templates/skills/authoring-playbooks/reference/stages-contract.md +15 -0
- package/templates/skills/authoring-playbooks/reference/worked-example.md +3 -0
- package/dist/commands/infra.d.ts +0 -21
- package/dist/commands/infra.js +0 -262
- package/dist/commands/infra.js.map +0 -1
- package/node_modules/@synap/hub-rest-client/dist/index.cjs +0 -1261
- package/node_modules/@synap/hub-rest-client/dist/index.d.cts +0 -1647
- package/node_modules/@synap/hub-rest-client/dist/index.d.ts +0 -1647
- package/node_modules/@synap/hub-rest-client/dist/index.js +0 -1231
- package/node_modules/@synap/hub-rest-client/package.json +0 -45
- package/node_modules/@synap/hub-rest-client/src/client.ts +0 -1631
- package/node_modules/@synap/hub-rest-client/src/errors.ts +0 -30
- package/node_modules/@synap/hub-rest-client/src/index.ts +0 -153
- package/node_modules/@synap/hub-rest-client/src/setup.ts +0 -133
- package/node_modules/@synap/hub-rest-client/src/types.ts +0 -1299
|
@@ -1,13 +1,130 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { log } from "../utils/logger.js";
|
|
3
|
-
import { resolveHubConfig, hubGet, hubPatch, hubPost,
|
|
3
|
+
import { resolveHubConfig, hubGet, hubPatch, hubPost, attachActiveSessionId, detachActiveSessionId, resolveActiveSessionId, renderHubError, HubError, } from "../lib/hub-client.js";
|
|
4
|
+
import { closeQuestionDispositions, openQuestionsRefusal, } from "./close-questions.js";
|
|
5
|
+
import { readFileSync, existsSync } from "fs";
|
|
6
|
+
import { resolve } from "path";
|
|
7
|
+
/**
|
|
8
|
+
* The three session-population lenses ("kind"), and their human labels.
|
|
9
|
+
*
|
|
10
|
+
* `@synap-core/types/vocabulary` (`resolveStatusLabel`) is the SSOT for this —
|
|
11
|
+
* `work`/`run`/`receipt` are pinned there verbatim (`.claude/rules/
|
|
12
|
+
* vocabulary.md` forbids a local `charAt(0).toUpperCase()` guess). But this
|
|
13
|
+
* package cannot import it: the CLI links only `@synap-core/workspace-
|
|
14
|
+
* templates` (a real npm dep already), and `@synap-core/types` pulls in
|
|
15
|
+
* drizzle-orm/drizzle-zod/yjs as transitive deps for a globally-installed
|
|
16
|
+
* binary — an install-topology change, not a labelling fix. Same shape as
|
|
17
|
+
* `KIND_HEADINGS` in `market.ts`: a local table, pinned by a source-scan
|
|
18
|
+
* parity test (`test/session-kind-vocabulary-parity.test.ts`) against the
|
|
19
|
+
* registry across the repo boundary, so it cannot silently drift.
|
|
20
|
+
*/
|
|
21
|
+
const SESSION_KIND_LABELS = {
|
|
22
|
+
work: "Work",
|
|
23
|
+
run: "Run",
|
|
24
|
+
receipt: "Receipt",
|
|
25
|
+
};
|
|
26
|
+
export function sessionKindLabel(kind) {
|
|
27
|
+
return SESSION_KIND_LABELS[kind] ?? kind;
|
|
28
|
+
}
|
|
29
|
+
const SESSION_KIND_FILTERS = ["work", "run", "receipt", "all"];
|
|
30
|
+
/**
|
|
31
|
+
* The name to show for a session: mirrors `resolveSessionTitle` in
|
|
32
|
+
* `synap-backend/packages/types/src/focus-sessions/title.ts` — the
|
|
33
|
+
* platform's ONE resolver (title when set, else the goal's first line,
|
|
34
|
+
* clipped at a word boundary). This package cannot import that file (see the
|
|
35
|
+
* doc comment on `SESSION_KIND_LABELS` above for why), so only the DISPLAY
|
|
36
|
+
* half of the rule is mirrored: the row's `title` already arrives
|
|
37
|
+
* server-normalized (HTML-entity decoded, one line), so the write-path
|
|
38
|
+
* decode step has nothing to do here. Pinned by
|
|
39
|
+
* `test/session-title-resolver-parity.test.ts`, which runs the registry's
|
|
40
|
+
* OWN fixtures (from `title.test.ts`) through this copy.
|
|
41
|
+
*/
|
|
42
|
+
const SESSION_TITLE_FALLBACK_MAX = 80;
|
|
43
|
+
function oneLine(value) {
|
|
44
|
+
return value.replace(/\s+/g, " ").trim();
|
|
45
|
+
}
|
|
46
|
+
function clipAtWordBoundary(line, max) {
|
|
47
|
+
if (line.length <= max)
|
|
48
|
+
return line;
|
|
49
|
+
let cut = line.slice(0, Math.max(1, max - 1));
|
|
50
|
+
const lastSpace = cut.lastIndexOf(" ");
|
|
51
|
+
// Only back off to a word boundary when it keeps most of the budget; a
|
|
52
|
+
// single very long first word is cut mid-word rather than reduced to
|
|
53
|
+
// nothing.
|
|
54
|
+
if (lastSpace >= Math.floor(max / 2))
|
|
55
|
+
cut = cut.slice(0, lastSpace);
|
|
56
|
+
return `${cut.replace(/[\s,;:.\-–—]+$/, "")}…`;
|
|
57
|
+
}
|
|
58
|
+
export function resolveSessionTitle(session, opts = {}) {
|
|
59
|
+
const title = typeof session.title === "string" ? oneLine(session.title) : "";
|
|
60
|
+
if (title)
|
|
61
|
+
return title;
|
|
62
|
+
const goal = typeof session.goal === "string" ? session.goal : "";
|
|
63
|
+
const firstLine = goal
|
|
64
|
+
.split(/\r?\n/)
|
|
65
|
+
.map(oneLine)
|
|
66
|
+
.find((l) => l.length > 0) ?? "";
|
|
67
|
+
return clipAtWordBoundary(firstLine, opts.maxLength ?? SESSION_TITLE_FALLBACK_MAX);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Session-evaluation verdicts (`session_evaluations.verdict`). SSOT is
|
|
71
|
+
* `@synap-core/types/vocabulary`'s `STATUS_LABELS` (`pass`/`fail`/
|
|
72
|
+
* `unmeasured`) — same cross-boundary constraint as `SESSION_KIND_LABELS`
|
|
73
|
+
* above, mirrored here and pinned by
|
|
74
|
+
* `test/verdict-label-vocabulary-parity.test.ts`.
|
|
75
|
+
*/
|
|
76
|
+
const VERDICT_LABELS = {
|
|
77
|
+
pass: "Passed",
|
|
78
|
+
fail: "Failed",
|
|
79
|
+
unmeasured: "Not checked",
|
|
80
|
+
};
|
|
81
|
+
function verdictLabel(verdict) {
|
|
82
|
+
return VERDICT_LABELS[verdict] ?? verdict;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* One-glance verdict summary for a list/detail row: "1 unmet" when a
|
|
86
|
+
* required criterion is failing or unmeasured (the thing worth flagging),
|
|
87
|
+
* else "2/3 ✓". `null` when the session carries no criteria at all — most
|
|
88
|
+
* sessions don't, and a bare session shouldn't grow a verdict column.
|
|
89
|
+
*/
|
|
90
|
+
function verdictSummary(v) {
|
|
91
|
+
const verdict = v;
|
|
92
|
+
if (!verdict || typeof verdict.total !== "number" || verdict.total === 0) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
if (verdict.requiredUnmet && verdict.requiredUnmet > 0) {
|
|
96
|
+
return `${verdict.requiredUnmet} unmet`;
|
|
97
|
+
}
|
|
98
|
+
return `${verdict.passed ?? 0}/${verdict.total} ✓`;
|
|
99
|
+
}
|
|
100
|
+
/** Human phrasing for where an attach landed — so scope is never a mystery. */
|
|
101
|
+
function describeAttachTarget(target) {
|
|
102
|
+
return target === "session-lens"
|
|
103
|
+
? "in this Claude Code session (~/.synap/lenses)"
|
|
104
|
+
: "in this working tree (.synap/lens.json)";
|
|
105
|
+
}
|
|
4
106
|
// ─── startSession ─────────────────────────────────────────────────────────────
|
|
5
107
|
export async function startSession(opts) {
|
|
6
108
|
try {
|
|
7
109
|
const cfg = await resolveHubConfig(opts);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
110
|
+
// LENS PARITY. `resolveHubConfig` already resolves the active project
|
|
111
|
+
// ("write paths should consume resolveHubConfig().projectId" —
|
|
112
|
+
// lib/hub-client.ts), and `synap lens` / `synap capture` both honour it.
|
|
113
|
+
// This door read `cfg.workspaceId` and dropped `cfg.projectId` on the
|
|
114
|
+
// floor, so the same terminal answered differently depending on which
|
|
115
|
+
// command you used: capture filed into the project, `session start` wrote
|
|
116
|
+
// projectId: null. The value was one field away the whole time.
|
|
117
|
+
// A track names its own project (the pod refuses a different projectId):
|
|
118
|
+
// with `--track`, only an EXPLICIT --workspace / --project is sent, never
|
|
119
|
+
// the ambient lens, which may point at another project.
|
|
120
|
+
const workspaceId = opts.track ? opts.workspace : opts.workspace || cfg.workspaceId;
|
|
121
|
+
const projectId = opts.track ? opts.project : opts.project || cfg.projectId;
|
|
122
|
+
// The POD accepts workspaceId OR projectId ("Provide a workspaceId or a
|
|
123
|
+
// projectId" — rest/focus-sessions.ts). Requiring a workspace here was a
|
|
124
|
+
// CLI-only rule, stricter than the contract, and it made a project-scoped
|
|
125
|
+
// session unreachable from the terminal.
|
|
126
|
+
if (!workspaceId && !projectId && !opts.track) {
|
|
127
|
+
console.error(chalk.red("Error: no workspace or project in scope — pass --workspace <id> or --project <id>, or set one with 'synap use' / 'synap project use'"));
|
|
11
128
|
process.exit(1);
|
|
12
129
|
}
|
|
13
130
|
// Resolve caller userId from the hub key
|
|
@@ -17,33 +134,93 @@ export async function startSession(opts) {
|
|
|
17
134
|
console.error(chalk.red("Error: could not resolve userId from /users/me"));
|
|
18
135
|
process.exit(1);
|
|
19
136
|
}
|
|
20
|
-
const body = {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
137
|
+
const body = { userId, goal: opts.goal };
|
|
138
|
+
// Send only what is in scope: the pod's refine accepts either, and sending
|
|
139
|
+
// an undefined workspaceId would fail the "min(1)" on the wire.
|
|
140
|
+
if (workspaceId)
|
|
141
|
+
body.workspaceId = workspaceId;
|
|
142
|
+
if (projectId)
|
|
143
|
+
body.projectId = projectId;
|
|
144
|
+
if (opts.track)
|
|
145
|
+
body.trackId = opts.track;
|
|
25
146
|
if (opts.taskId)
|
|
26
147
|
body.correlationId = `task:${opts.taskId}`;
|
|
148
|
+
// `--no-template` → opts.template === false → send an explicit `null`,
|
|
149
|
+
// which SKIPS matching (`TEMPLATE_OPT_OUT` in match-session-template.ts).
|
|
150
|
+
// `--template <id>` → send that id, the one way a playbook binds. Neither
|
|
151
|
+
// → omit, so the start comes back with the pod's playbooks to choose from
|
|
152
|
+
// (suggestions; nothing is applied).
|
|
153
|
+
if (opts.template === false)
|
|
154
|
+
body.templateId = null;
|
|
155
|
+
else if (opts.template)
|
|
156
|
+
body.templateId = opts.template;
|
|
157
|
+
// Detour push: the pod records `session --spawned_from--> session` and (with
|
|
158
|
+
// --suspended-intent) writes the "what were you about to do" line onto the
|
|
159
|
+
// PARENT and a `parent --blocked_by--> this session` edge. The parent is
|
|
160
|
+
// NOT closed or paused — it waits, and popping back is `synap session attach <parent>`.
|
|
161
|
+
if (opts.parent)
|
|
162
|
+
body.parentSessionId = opts.parent;
|
|
163
|
+
if (opts.suspendedIntent)
|
|
164
|
+
body.suspendedIntent = opts.suspendedIntent;
|
|
165
|
+
if (opts.criteria) {
|
|
166
|
+
const path = resolve(process.cwd(), opts.criteria);
|
|
167
|
+
if (!existsSync(path)) {
|
|
168
|
+
console.error(chalk.red(`Error: --criteria file not found: ${path}`));
|
|
169
|
+
process.exit(1);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
body.criteria = JSON.parse(readFileSync(path, "utf-8"));
|
|
174
|
+
}
|
|
175
|
+
catch (parseErr) {
|
|
176
|
+
console.error(chalk.red(`Error: --criteria file is not valid JSON — ${parseErr.message}`));
|
|
177
|
+
process.exit(1);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
27
181
|
const session = (await hubPost("/focus-sessions", body, cfg));
|
|
28
182
|
if (opts.json) {
|
|
29
183
|
console.log(JSON.stringify(session, null, 2));
|
|
30
184
|
return;
|
|
31
185
|
}
|
|
186
|
+
// A governed start comes back as a PROPOSAL, not a session: say so, and
|
|
187
|
+
// attach nothing — there is no session id to attach yet.
|
|
188
|
+
if (session.status === "proposed" && typeof session.proposalId === "string") {
|
|
189
|
+
log.warn("Starting this session is queued for your review — not started yet.");
|
|
190
|
+
if (typeof session.reviewUrl === "string")
|
|
191
|
+
log.hint(`Review: ${session.reviewUrl}`);
|
|
192
|
+
else
|
|
193
|
+
log.hint(`Proposal ${session.proposalId} — see: synap proposals list`);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
32
196
|
const id = String(session.id ?? "");
|
|
33
|
-
// Auto-attach: make this session active
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
const { getClaudeSessionId, writeLens } = await import("../lib/session-lens.js");
|
|
38
|
-
const cs = getClaudeSessionId();
|
|
39
|
-
if (cs)
|
|
40
|
-
writeLens(cs, { focusSessionId: id });
|
|
197
|
+
// Auto-attach: make this session active so the statusline and every scoped
|
|
198
|
+
// call reflect it. Lands on the Claude-session lens inside Claude Code,
|
|
199
|
+
// otherwise on this working tree's directory lens.
|
|
200
|
+
const target = attachActiveSessionId(id);
|
|
41
201
|
log.success(`Session started and attached`);
|
|
42
202
|
console.log(` ID: ${chalk.bold(id)}`);
|
|
203
|
+
console.log(` Name: ${chalk.white(resolveSessionTitle(session))}`);
|
|
43
204
|
console.log(` Goal: ${chalk.white(opts.goal)}`);
|
|
44
205
|
if (opts.taskId)
|
|
45
206
|
console.log(` Task: ${chalk.dim(opts.taskId)}`);
|
|
46
|
-
|
|
207
|
+
if (opts.parent)
|
|
208
|
+
console.log(` Forked from: ${chalk.dim(opts.parent)}`);
|
|
209
|
+
if (session.adopted === true) {
|
|
210
|
+
log.dim(` Continued your auto-opened session`);
|
|
211
|
+
}
|
|
212
|
+
// `playbooks` (SessionPlaybookCandidates) is present iff matching ran —
|
|
213
|
+
// see match-session-template.ts. SUGGESTIONS ONLY: nothing was applied, so
|
|
214
|
+
// say what fits and how to bind one, never that one is in force.
|
|
215
|
+
const playbooks = session.playbooks;
|
|
216
|
+
if (playbooks?.candidates?.length) {
|
|
217
|
+
log.dim(` Playbooks that fit this goal (none applied):`);
|
|
218
|
+
for (const c of playbooks.candidates) {
|
|
219
|
+
log.dim(` - ${c.name} (${c.reason})`);
|
|
220
|
+
log.dim(` ${chalk.dim(`--template ${c.id}`)}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
log.dim(` Active ${describeAttachTarget(target)}`);
|
|
47
224
|
console.log();
|
|
48
225
|
// Print the ID alone on a final line so scripts can grab it easily
|
|
49
226
|
console.log(id);
|
|
@@ -56,18 +233,37 @@ export async function startSession(opts) {
|
|
|
56
233
|
// ─── listSessions ─────────────────────────────────────────────────────────────
|
|
57
234
|
export async function listSessions(opts) {
|
|
58
235
|
try {
|
|
236
|
+
// Validate at the edge, same reasoning as `--progress` above: a typo should
|
|
237
|
+
// fail here with the legal values, not reach the pod and bounce as a raw
|
|
238
|
+
// zod echo.
|
|
239
|
+
if (opts.kind !== undefined &&
|
|
240
|
+
!SESSION_KIND_FILTERS.includes(opts.kind)) {
|
|
241
|
+
console.error(chalk.red(`Error: --kind must be one of ${SESSION_KIND_FILTERS.join(" | ")} (got ${JSON.stringify(opts.kind)}).`));
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
59
244
|
const cfg = await resolveHubConfig(opts);
|
|
60
245
|
const params = {};
|
|
61
246
|
// Fall back to the active workspace (config/env) like `start` does — the
|
|
62
247
|
// focus-sessions REST requires workspaceId, and an operator with an active
|
|
63
248
|
// workspace shouldn't have to repeat --workspace on every session command.
|
|
64
|
-
|
|
249
|
+
// `--project` is a scope of its own (the pod accepts projectId alone,
|
|
250
|
+
// project-member floor): a project's sessions span spaces, so with it only
|
|
251
|
+
// an EXPLICIT --workspace narrows — never the ambient one, which would hide
|
|
252
|
+
// every session the project runs in another space.
|
|
253
|
+
const wsId = opts.project ? opts.workspace : opts.workspace || cfg.workspaceId;
|
|
65
254
|
if (wsId)
|
|
66
255
|
params.workspaceId = wsId;
|
|
256
|
+
if (opts.project)
|
|
257
|
+
params.projectId = opts.project;
|
|
67
258
|
if (opts.status)
|
|
68
259
|
params.status = opts.status;
|
|
69
260
|
if (opts.limit)
|
|
70
261
|
params.limit = parseInt(opts.limit, 10);
|
|
262
|
+
// Population lens (`services/focus-sessions/session-kind.ts` on the pod).
|
|
263
|
+
// The Hub REST door defaults to "all" itself, so omit rather than send a
|
|
264
|
+
// redundant param when the flag isn't given.
|
|
265
|
+
if (opts.kind && opts.kind !== "all")
|
|
266
|
+
params.kind = opts.kind;
|
|
71
267
|
// The Hub REST GET /focus-sessions returns a bare array of sessions.
|
|
72
268
|
// (Tolerate a { sessions: [...] } envelope too, for forward-compat.)
|
|
73
269
|
const res = await hubGet("/focus-sessions", params, cfg);
|
|
@@ -90,8 +286,17 @@ export async function listSessions(opts) {
|
|
|
90
286
|
? chalk.yellow(status)
|
|
91
287
|
: chalk.dim(status);
|
|
92
288
|
const progress = typeof s.progress === "number" ? ` ${chalk.dim(`[${s.progress}%]`)}` : "";
|
|
289
|
+
// `kind` is projected on every row by the Hub REST door regardless of the
|
|
290
|
+
// `--kind` filter — an older pod without the kind wave simply omits it.
|
|
291
|
+
const kindLabel = typeof s.kind === "string" ? sessionKindLabel(s.kind) : null;
|
|
292
|
+
const kindCol = kindLabel ? ` ${chalk.dim(`[${kindLabel}]`)}` : "";
|
|
293
|
+
// Present only when the door lifts `verdict` onto the row (today: the
|
|
294
|
+
// single-session GET, not this list) — `verdictSummary` returns null on
|
|
295
|
+
// an absent field, so an older/list door just omits the marker.
|
|
296
|
+
const verdict = verdictSummary(s.verdict);
|
|
297
|
+
const verdictCol = verdict ? ` ${chalk.dim(`(${verdict})`)}` : "";
|
|
93
298
|
// Full id — feeds straight into `synap session get/update/attach <id>`.
|
|
94
|
-
console.log(` ${chalk.bold(String(s.id ?? ""))} ${statusColor}${progress} ${chalk.white(
|
|
299
|
+
console.log(` ${chalk.bold(String(s.id ?? ""))} ${statusColor}${kindCol}${progress} ${chalk.white(resolveSessionTitle(s))}${verdictCol}`);
|
|
95
300
|
}
|
|
96
301
|
}
|
|
97
302
|
catch (e) {
|
|
@@ -100,22 +305,62 @@ export async function listSessions(opts) {
|
|
|
100
305
|
}
|
|
101
306
|
}
|
|
102
307
|
// ─── getSession ───────────────────────────────────────────────────────────────
|
|
308
|
+
/**
|
|
309
|
+
* Fetch a focus session by id.
|
|
310
|
+
*
|
|
311
|
+
* Prefer GET without workspaceId so project-scoped sessions (workspaceId null)
|
|
312
|
+
* resolve. Older pods still require the query param — if the bare GET fails
|
|
313
|
+
* with 400 and we have a workspace, retry with it.
|
|
314
|
+
*/
|
|
315
|
+
async function fetchSessionById(id, cfg, workspaceHint) {
|
|
316
|
+
try {
|
|
317
|
+
return (await hubGet(`/focus-sessions/${id}`, {}, cfg));
|
|
318
|
+
}
|
|
319
|
+
catch (e) {
|
|
320
|
+
const wsId = workspaceHint || cfg.workspaceId;
|
|
321
|
+
if (e instanceof HubError && e.status === 400 && wsId) {
|
|
322
|
+
return (await hubGet(`/focus-sessions/${id}`, { workspaceId: wsId }, cfg));
|
|
323
|
+
}
|
|
324
|
+
throw e;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
103
327
|
export async function getSession(id, opts) {
|
|
104
328
|
try {
|
|
105
329
|
const cfg = await resolveHubConfig(opts);
|
|
106
|
-
const
|
|
107
|
-
const wsId = opts.workspace || cfg.workspaceId;
|
|
108
|
-
if (wsId)
|
|
109
|
-
params.workspaceId = wsId;
|
|
110
|
-
const res = await hubGet(`/focus-sessions/${id}`, params, cfg);
|
|
330
|
+
const res = await fetchSessionById(id, cfg, opts.workspace);
|
|
111
331
|
if (opts.json) {
|
|
112
332
|
console.log(JSON.stringify(res, null, 2));
|
|
113
333
|
return;
|
|
114
334
|
}
|
|
115
335
|
const s = res;
|
|
116
336
|
log.info(`Session ${chalk.bold(String(s.id ?? ""))}`);
|
|
337
|
+
console.log(` Name: ${chalk.white(resolveSessionTitle(s))}`);
|
|
117
338
|
console.log(` Goal: ${chalk.white(String(s.goal ?? ""))}`);
|
|
118
339
|
console.log(` Status: ${chalk.cyan(String(s.status ?? ""))}`);
|
|
340
|
+
if (typeof s.kind === "string")
|
|
341
|
+
console.log(` Kind: ${chalk.dim(sessionKindLabel(s.kind))}`);
|
|
342
|
+
// `verdict` (SessionVerdict) is present iff the session carries criteria —
|
|
343
|
+
// see `test/verdict-label-vocabulary-parity.test.ts` for the label SSOT.
|
|
344
|
+
const verdict = s.verdict;
|
|
345
|
+
if (verdict && typeof verdict.total === "number" && verdict.total > 0) {
|
|
346
|
+
const summary = verdictSummary(verdict);
|
|
347
|
+
console.log(` Criteria: ${chalk.white(`${verdict.passed ?? 0}/${verdict.total}`)}` +
|
|
348
|
+
(summary && verdict.requiredUnmet
|
|
349
|
+
? ` ${chalk.yellow(summary)}`
|
|
350
|
+
: ""));
|
|
351
|
+
}
|
|
352
|
+
// Project-scoped sessions have workspaceId null — show scope honestly.
|
|
353
|
+
if (s.workspaceId != null && s.workspaceId !== "") {
|
|
354
|
+
console.log(` Workspace: ${chalk.dim(String(s.workspaceId))}`);
|
|
355
|
+
}
|
|
356
|
+
else if (s.projectId) {
|
|
357
|
+
console.log(` Project: ${chalk.dim(String(s.projectId))} ${chalk.dim("(no workspace)")}`);
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
console.log(` Scope: ${chalk.dim("project/unscoped (workspace null)")}`);
|
|
361
|
+
}
|
|
362
|
+
if (s.projectId && s.workspaceId)
|
|
363
|
+
console.log(` Project: ${chalk.dim(String(s.projectId))}`);
|
|
119
364
|
if (typeof s.progress === "number")
|
|
120
365
|
console.log(` Progress: ${s.progress}%`);
|
|
121
366
|
if (s.templateId)
|
|
@@ -136,16 +381,31 @@ export async function getSession(id, opts) {
|
|
|
136
381
|
export async function updateSession(id, opts) {
|
|
137
382
|
try {
|
|
138
383
|
const cfg = await resolveHubConfig(opts);
|
|
384
|
+
// The session is identified by `id` in the URL and `workspaceId` is
|
|
385
|
+
// `.optional()` on the pod's UpdateBodySchema — so demanding one here was a
|
|
386
|
+
// CLI-only rule that made an already-attached (or project-scoped) session
|
|
387
|
+
// un-updatable without re-stating a lens the terminal already holds.
|
|
139
388
|
const wsId = opts.workspace || cfg.workspaceId;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
389
|
+
const body = {};
|
|
390
|
+
if (wsId)
|
|
391
|
+
body.workspaceId = wsId;
|
|
392
|
+
// `progress` is `z.number().int().min(0).max(100)` on the pod. `parseInt`
|
|
393
|
+
// on prose yields NaN, which serialized to the wire and came back as a raw
|
|
394
|
+
// zod echo — an unreadable error for a mistake the CLI could name here.
|
|
395
|
+
// Validate at the edge and say what the flag actually takes.
|
|
396
|
+
if (opts.progress !== undefined) {
|
|
397
|
+
const pct = Number(opts.progress);
|
|
398
|
+
if (!Number.isInteger(pct) || pct < 0 || pct > 100) {
|
|
399
|
+
console.error(chalk.red(`Error: --progress takes a whole number 0-100 (got ${JSON.stringify(opts.progress)}).`));
|
|
400
|
+
log.hint("For a free-text note, use --goal to restate the goal, or capture the note: synap capture --type lesson --claim \"...\"");
|
|
401
|
+
process.exit(1);
|
|
402
|
+
}
|
|
403
|
+
body.progress = pct;
|
|
143
404
|
}
|
|
144
|
-
const body = { workspaceId: wsId };
|
|
145
|
-
if (opts.progress !== undefined)
|
|
146
|
-
body.progress = parseInt(opts.progress, 10);
|
|
147
405
|
if (opts.status)
|
|
148
406
|
body.status = opts.status;
|
|
407
|
+
if (opts.stage)
|
|
408
|
+
body.currentStage = opts.stage;
|
|
149
409
|
if (opts.goal)
|
|
150
410
|
body.goal = opts.goal;
|
|
151
411
|
const res = await hubPatch(`/focus-sessions/${id}`, body, cfg);
|
|
@@ -158,6 +418,8 @@ export async function updateSession(id, opts) {
|
|
|
158
418
|
log.dim(` progress → ${opts.progress}%`);
|
|
159
419
|
if (opts.status)
|
|
160
420
|
log.dim(` status → ${opts.status}`);
|
|
421
|
+
if (opts.stage)
|
|
422
|
+
log.dim(` stage → ${opts.stage}`);
|
|
161
423
|
}
|
|
162
424
|
catch (e) {
|
|
163
425
|
renderHubError(e);
|
|
@@ -166,34 +428,27 @@ export async function updateSession(id, opts) {
|
|
|
166
428
|
}
|
|
167
429
|
// ─── attachSession ────────────────────────────────────────────────────────────
|
|
168
430
|
export async function attachSession(id, opts) {
|
|
169
|
-
// Validate the session exists before attaching
|
|
431
|
+
// Validate the session exists before attaching (project-scoped OK — no workspace required)
|
|
170
432
|
try {
|
|
171
433
|
const cfg = await resolveHubConfig(opts);
|
|
172
|
-
|
|
173
|
-
if (cfg.workspaceId)
|
|
174
|
-
params.workspaceId = cfg.workspaceId;
|
|
175
|
-
await hubGet(`/focus-sessions/${id}`, params, cfg);
|
|
434
|
+
await fetchSessionById(id, cfg, opts.workspace);
|
|
176
435
|
}
|
|
177
436
|
catch (e) {
|
|
178
437
|
console.error(chalk.red("Error: session not found — " + e.message));
|
|
179
438
|
process.exit(1);
|
|
180
439
|
}
|
|
181
|
-
|
|
182
|
-
const { getClaudeSessionId, writeLens } = await import("../lib/session-lens.js");
|
|
183
|
-
const cs = getClaudeSessionId();
|
|
184
|
-
if (cs)
|
|
185
|
-
writeLens(cs, { focusSessionId: id });
|
|
440
|
+
const target = attachActiveSessionId(id);
|
|
186
441
|
if (opts.json) {
|
|
187
|
-
console.log(JSON.stringify({ ok: true, sessionId: id }));
|
|
442
|
+
console.log(JSON.stringify({ ok: true, sessionId: id, scope: target }));
|
|
188
443
|
return;
|
|
189
444
|
}
|
|
190
445
|
log.success(`Session attached ${chalk.dim(id.slice(0, 8))}`);
|
|
446
|
+
log.dim(` Active ${describeAttachTarget(target)}`);
|
|
191
447
|
log.dim(` All hub calls in this terminal will tag X-Session-Id: ${id.slice(0, 8)}…`);
|
|
192
448
|
}
|
|
193
449
|
// ─── detachSession ────────────────────────────────────────────────────────────
|
|
194
450
|
export function detachSession(opts) {
|
|
195
|
-
const current =
|
|
196
|
-
clearActiveSessionId();
|
|
451
|
+
const current = detachActiveSessionId();
|
|
197
452
|
if (opts.json) {
|
|
198
453
|
console.log(JSON.stringify({ ok: true }));
|
|
199
454
|
return;
|
|
@@ -207,39 +462,227 @@ export function detachSession(opts) {
|
|
|
207
462
|
}
|
|
208
463
|
// ─── sessionStatus ────────────────────────────────────────────────────────────
|
|
209
464
|
export function sessionStatus(opts) {
|
|
210
|
-
const id =
|
|
465
|
+
const id = resolveActiveSessionId();
|
|
211
466
|
if (opts.json) {
|
|
212
467
|
console.log(JSON.stringify({ sessionId: id ?? null }));
|
|
213
468
|
return;
|
|
214
469
|
}
|
|
215
470
|
if (id) {
|
|
216
|
-
log.info(`Active session: ${chalk.bold(id.slice(0, 8))}… ${chalk.dim("(
|
|
471
|
+
log.info(`Active session: ${chalk.bold(id.slice(0, 8))}… ${chalk.dim("(SYNAP_SESSION_ID, session lens, or .synap/lens.json)")}`);
|
|
217
472
|
}
|
|
218
473
|
else {
|
|
219
474
|
log.dim("No active session — run `synap session start` or `synap session attach <id>`");
|
|
220
475
|
}
|
|
221
476
|
}
|
|
222
|
-
|
|
477
|
+
/**
|
|
478
|
+
* Close a focus session via Hub complete (proposal pack).
|
|
479
|
+
*
|
|
480
|
+
* Prefer POST /focus-sessions/:id/complete with `{ summary }` from `--recap`.
|
|
481
|
+
* On 404 (older pods without the route) fall back to PATCH status=closed and
|
|
482
|
+
* write verificationReport.summary — graceful degrade, pack unavailable.
|
|
483
|
+
*
|
|
484
|
+
* --workspace is optional: complete loads the row by id; PATCH also scopes
|
|
485
|
+
* from the row (workspaceId body is back-compat only).
|
|
486
|
+
*/
|
|
223
487
|
export async function closeSession(id, opts) {
|
|
488
|
+
const settled = closeQuestionDispositions(opts);
|
|
489
|
+
if (!settled.ok) {
|
|
490
|
+
console.error(chalk.red(`Error: ${settled.error}`));
|
|
491
|
+
process.exit(1);
|
|
492
|
+
}
|
|
224
493
|
try {
|
|
225
494
|
const cfg = await resolveHubConfig(opts);
|
|
226
495
|
const wsId = opts.workspace || cfg.workspaceId;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
496
|
+
let pack = null;
|
|
497
|
+
let usedPack = false;
|
|
498
|
+
try {
|
|
499
|
+
// Canonical close: completeFocusSession — returns proposal pack.
|
|
500
|
+
// Map CLI --recap → body.summary (server field; there is no `recap` key).
|
|
501
|
+
const body = {};
|
|
502
|
+
if (opts.recap)
|
|
503
|
+
body.summary = opts.recap;
|
|
504
|
+
// How the session ended. Validated at the edge (see index.ts) so a typo
|
|
505
|
+
// fails here with the three legal values, rather than reaching the pod
|
|
506
|
+
// and being rejected by a zod enum the user cannot see.
|
|
507
|
+
if (opts.as)
|
|
508
|
+
body.terminalStatus = opts.as;
|
|
509
|
+
if (settled.dispositions.length > 0)
|
|
510
|
+
body.questionDispositions = settled.dispositions;
|
|
511
|
+
pack = (await hubPost(`/focus-sessions/${id}/complete`, body, cfg));
|
|
512
|
+
usedPack = true;
|
|
513
|
+
}
|
|
514
|
+
catch (e) {
|
|
515
|
+
if (!(e instanceof HubError) || e.status !== 404)
|
|
516
|
+
throw e;
|
|
517
|
+
// Older pod: no complete route — close via PATCH and warn that pack is
|
|
518
|
+
// unavailable. verificationReport.summary is the field the complete path
|
|
519
|
+
// writes (complete-session.ts); UpdateBodySchema accepts it as z.unknown().
|
|
520
|
+
log.dim("Pack unavailable on this pod (POST …/complete → 404); falling back to status close.");
|
|
521
|
+
const patchBody = {
|
|
522
|
+
status: opts.as ?? "closed",
|
|
523
|
+
};
|
|
524
|
+
if (wsId)
|
|
525
|
+
patchBody.workspaceId = wsId;
|
|
526
|
+
if (opts.recap)
|
|
527
|
+
patchBody.verificationReport = { summary: opts.recap };
|
|
528
|
+
await hubPatch(`/focus-sessions/${id}`, patchBody, cfg);
|
|
230
529
|
}
|
|
231
|
-
// Close via PATCH — the /focus-sessions/:id endpoint sets closedAt automatically
|
|
232
|
-
// when status transitions to "closed"
|
|
233
|
-
const body = { workspaceId: wsId, status: "closed" };
|
|
234
|
-
await hubPatch(`/focus-sessions/${id}`, body, cfg);
|
|
235
530
|
// Detach if this was the active terminal session
|
|
236
|
-
if (
|
|
237
|
-
|
|
531
|
+
if (resolveActiveSessionId(cfg.podUrl) === id)
|
|
532
|
+
detachActiveSessionId(cfg.podUrl);
|
|
533
|
+
if (opts.json) {
|
|
534
|
+
if (usedPack && pack) {
|
|
535
|
+
console.log(JSON.stringify(pack, null, 2));
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
console.log(JSON.stringify({
|
|
539
|
+
ok: true,
|
|
540
|
+
status: "closed",
|
|
541
|
+
pack: false,
|
|
542
|
+
summary: opts.recap ?? null,
|
|
543
|
+
}, null, 2));
|
|
544
|
+
}
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
const sessionStatus = (pack?.session && String(pack.session.status ?? "")) ||
|
|
548
|
+
pack?.status ||
|
|
549
|
+
"closed";
|
|
550
|
+
// Close never blocks on criteria — a required-but-unmet criterion is a
|
|
551
|
+
// flag on the closed session, never a refusal.
|
|
552
|
+
const closeVerdict = pack?.verdict && pack.verdict.requiredUnmet
|
|
553
|
+
? ` · ${pack.verdict.requiredUnmet} criteri${pack.verdict.requiredUnmet === 1 ? "on" : "a"} not met`
|
|
554
|
+
: "";
|
|
555
|
+
log.success(`Session closed ${chalk.dim(id.slice(0, 8))} ${chalk.cyan(sessionStatus)}${chalk.yellow(closeVerdict)}`);
|
|
556
|
+
if (opts.recap)
|
|
557
|
+
log.dim(` recap: ${opts.recap}`);
|
|
558
|
+
if (usedPack && pack) {
|
|
559
|
+
const pending = pack.counts?.pending ??
|
|
560
|
+
(Array.isArray(pack.pendingProposals) ? pack.pendingProposals.length : 0);
|
|
561
|
+
const unfinished = pack.counts?.unfinishedOutputs ?? 0;
|
|
562
|
+
console.log(` Pack: ${chalk.white(String(pending))} pending proposal(s)` +
|
|
563
|
+
(unfinished > 0
|
|
564
|
+
? ` ${chalk.yellow(`${unfinished} unfinished output(s)`)}`
|
|
565
|
+
: ""));
|
|
566
|
+
if (Array.isArray(pack.warnings)) {
|
|
567
|
+
for (const w of pack.warnings) {
|
|
568
|
+
log.warn(String(w));
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
if (pack.note)
|
|
572
|
+
log.dim(` ${pack.note}`);
|
|
573
|
+
if (pending > 0) {
|
|
574
|
+
log.dim(` Review: synap proposals list --session ${id}`);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
catch (e) {
|
|
579
|
+
const refusal = openQuestionsRefusal(e);
|
|
580
|
+
if (refusal) {
|
|
581
|
+
if (opts.json) {
|
|
582
|
+
console.log(JSON.stringify({ ok: false, status: "refused", ...refusal }, null, 2));
|
|
583
|
+
}
|
|
584
|
+
else {
|
|
585
|
+
log.error("Not closed: questions you asked in this session are still open.");
|
|
586
|
+
for (const q of refusal.openQuestions) {
|
|
587
|
+
console.log(` ${chalk.white(q.shortId ?? q.messageId.slice(0, 8))} ${q.text} ${chalk.dim(q.messageId)}`);
|
|
588
|
+
}
|
|
589
|
+
log.dim(" Relay the person's chat answer first (relay_answer), or close again with " +
|
|
590
|
+
"--withdraw <messageId>=<why> or --keep-owed <messageId> for each.");
|
|
591
|
+
}
|
|
592
|
+
process.exit(1);
|
|
593
|
+
}
|
|
594
|
+
renderHubError(e);
|
|
595
|
+
process.exit(1);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
// ─── evidenceSession / evaluateSession ─────────────────────────────────────────
|
|
599
|
+
/** Resolve the target session: `--session <id>`, else this terminal's active one. */
|
|
600
|
+
function resolveTargetSessionId(opts, cfg) {
|
|
601
|
+
const id = opts.session || resolveActiveSessionId(cfg.podUrl);
|
|
602
|
+
if (!id) {
|
|
603
|
+
console.error(chalk.red("Error: no session in scope — pass --session <id> or attach one with 'synap session attach <id>'"));
|
|
604
|
+
process.exit(1);
|
|
605
|
+
}
|
|
606
|
+
return id;
|
|
607
|
+
}
|
|
608
|
+
function printEvaluateResult(result) {
|
|
609
|
+
if (result.status === "not_found") {
|
|
610
|
+
log.warn("Session not found");
|
|
611
|
+
return;
|
|
612
|
+
}
|
|
613
|
+
for (const r of result.results ?? []) {
|
|
614
|
+
if (r.status === "recorded" && r.verdict) {
|
|
615
|
+
const label = verdictLabel(r.verdict);
|
|
616
|
+
const colored = r.verdict === "pass"
|
|
617
|
+
? chalk.green(label)
|
|
618
|
+
: r.verdict === "fail"
|
|
619
|
+
? chalk.red(label)
|
|
620
|
+
: chalk.dim(label);
|
|
621
|
+
console.log(` ${chalk.bold(r.key)}: ${colored}${r.escalated ? chalk.yellow(" (escalated)") : ""}`);
|
|
622
|
+
}
|
|
623
|
+
else {
|
|
624
|
+
console.log(` ${chalk.bold(r.key)}: ${chalk.dim(`skipped — ${r.reason ?? "not applicable"}`)}`);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
const summary = verdictSummary(result.verdict);
|
|
628
|
+
if (summary)
|
|
629
|
+
log.dim(` Verdict: ${summary}`);
|
|
630
|
+
if (result.resumed)
|
|
631
|
+
log.dim(` Resumed a paused check-gate`);
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* `synap session evidence <key> --passed|--failed [--detail "…"]`
|
|
635
|
+
*
|
|
636
|
+
* POST /focus-sessions/:id/evidence — the agent's own deterministic report
|
|
637
|
+
* for an `evidence`-checked criterion. Grades ONLY evidence-checked
|
|
638
|
+
* criteria; never spends a judge call or runs a capability
|
|
639
|
+
* (`rest/focus-sessions.ts`, the `onlyEvidence` branch).
|
|
640
|
+
*/
|
|
641
|
+
export async function evidenceSession(key, opts) {
|
|
642
|
+
try {
|
|
643
|
+
const cfg = await resolveHubConfig(opts);
|
|
644
|
+
const id = resolveTargetSessionId(opts, cfg);
|
|
645
|
+
if (opts.passed === opts.failed) {
|
|
646
|
+
// Both or neither given — commander gives us two independent booleans,
|
|
647
|
+
// not an enum, so this is the edge check for "exactly one".
|
|
648
|
+
console.error(chalk.red("Error: pass exactly one of --passed or --failed"));
|
|
649
|
+
process.exit(1);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
const evidence = {
|
|
653
|
+
[key]: { passed: !!opts.passed, ...(opts.detail ? { detail: opts.detail } : {}) },
|
|
654
|
+
};
|
|
655
|
+
const result = (await hubPost(`/focus-sessions/${id}/evidence`, { evidence }, cfg));
|
|
656
|
+
if (opts.json) {
|
|
657
|
+
console.log(JSON.stringify(result, null, 2));
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
log.success(`Evidence recorded ${chalk.dim(id.slice(0, 8))}`);
|
|
661
|
+
printEvaluateResult(result);
|
|
662
|
+
}
|
|
663
|
+
catch (e) {
|
|
664
|
+
renderHubError(e);
|
|
665
|
+
process.exit(1);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* `synap session evaluate [--session <id>]`
|
|
670
|
+
*
|
|
671
|
+
* POST /focus-sessions/:id/evaluations — runs every PENDING criterion check
|
|
672
|
+
* (evidence already posted, then capability, then judge) and prints the
|
|
673
|
+
* per-criterion verdicts.
|
|
674
|
+
*/
|
|
675
|
+
export async function evaluateSession(opts) {
|
|
676
|
+
try {
|
|
677
|
+
const cfg = await resolveHubConfig(opts);
|
|
678
|
+
const id = resolveTargetSessionId(opts, cfg);
|
|
679
|
+
const result = (await hubPost(`/focus-sessions/${id}/evaluations`, {}, cfg));
|
|
238
680
|
if (opts.json) {
|
|
239
|
-
console.log(JSON.stringify(
|
|
681
|
+
console.log(JSON.stringify(result, null, 2));
|
|
240
682
|
return;
|
|
241
683
|
}
|
|
242
|
-
log.success(`Session
|
|
684
|
+
log.success(`Session evaluated ${chalk.dim(id.slice(0, 8))}`);
|
|
685
|
+
printEvaluateResult(result);
|
|
243
686
|
}
|
|
244
687
|
catch (e) {
|
|
245
688
|
renderHubError(e);
|