@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/commands/data.js
CHANGED
|
@@ -1,75 +1,128 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import { log } from "../utils/logger.js";
|
|
3
|
-
import { resolveHubConfig, resolveUserId, hubGet, hubPost, hubPatch } from "../lib/hub-client.js";
|
|
4
|
-
|
|
3
|
+
import { resolveHubConfig, resolveUserId, hubGet, hubPost, hubPatch, readActiveSessionId, renderHubError } from "../lib/hub-client.js";
|
|
4
|
+
import { unwrapList } from "../lib/unwrapList.js";
|
|
5
|
+
import { reportWrite } from "../lib/capture-lane.js";
|
|
6
|
+
import { renderNextSteps, FLOW } from "../lib/next-steps.js";
|
|
7
|
+
export const parseLimit = (s, def) => s ? parseInt(s, 10) : def;
|
|
8
|
+
export function formatHit(hit) {
|
|
9
|
+
const doc = (hit.document ?? hit);
|
|
10
|
+
return {
|
|
11
|
+
title: String(doc.title ?? doc.id ?? hit.id ?? ""),
|
|
12
|
+
// `type` is the entity's profile (entities carry `type`; search hits carry
|
|
13
|
+
// `entityType`/`collection`). Include `doc.type` or the badge renders blank.
|
|
14
|
+
type: String(doc.entityType ?? doc.profileSlug ?? doc.type ?? hit.collection ?? ""),
|
|
15
|
+
id: String(doc.id ?? hit.id ?? "").slice(0, 8),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
5
18
|
export async function orient(opts) {
|
|
6
19
|
try {
|
|
7
20
|
const cfg = await resolveHubConfig(opts);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
const userId = String(me
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
const wsDetails = await Promise.all(wsList.map(async (ws) => {
|
|
18
|
-
const wsId = String(ws.id ?? "");
|
|
19
|
-
const [profilesRes, entitiesRes] = await Promise.allSettled([
|
|
20
|
-
hubGet("/profiles", { userId, workspaceId: wsId }, cfg),
|
|
21
|
-
hubGet("/entities", { userId, workspaceId: wsId, limit: 1 }, cfg),
|
|
22
|
-
]);
|
|
23
|
-
const profiles = profilesRes.status === "fulfilled"
|
|
24
|
-
? (profilesRes.value.profiles ?? profilesRes.value)
|
|
25
|
-
: [];
|
|
26
|
-
const profileList = Array.isArray(profiles) ? profiles : [];
|
|
27
|
-
const entityTotal = entitiesRes.status === "fulfilled"
|
|
28
|
-
? Number(entitiesRes.value.total ?? 0)
|
|
29
|
-
: 0;
|
|
30
|
-
return { ws, profileList, entityTotal };
|
|
31
|
-
}));
|
|
21
|
+
// ONE canonical shape: the backend `discover()` service (via GET /orient)
|
|
22
|
+
// assembles the lens map — workspaces + projects + profile sample +
|
|
23
|
+
// disclosure (onboarding→goal, entity counts, per-ws profiles under full).
|
|
24
|
+
// The CLI only RENDERS it; `--details` maps to detail:'full'. No client-side
|
|
25
|
+
// assembly, no N+1 fanout — the server does the shaping.
|
|
26
|
+
const res = (await hubGet("/orient", opts.details ? { detail: "full" } : {}, cfg));
|
|
27
|
+
const userId = String(res.me?.userId ?? cfg.userId);
|
|
28
|
+
const projList = res.projects ?? [];
|
|
29
|
+
const wsList = res.workspaces ?? [];
|
|
32
30
|
if (opts.json) {
|
|
33
|
-
console.log(JSON.stringify({
|
|
31
|
+
console.log(JSON.stringify({ ...res, podUrl: cfg.podUrl, workspaceId: cfg.workspaceId, nextSteps: FLOW.afterOrient() }, null, 2));
|
|
34
32
|
return;
|
|
35
33
|
}
|
|
34
|
+
// Render content rows with console.log (default terminal fg) rather than
|
|
35
|
+
// log.info — log.info wraps every line in chalk.blue, and that blue fg
|
|
36
|
+
// persists through inner bold/dim (they reset weight, not color), flattening
|
|
37
|
+
// the hierarchy. We keep only targeted accents: bold=name, dim=metadata,
|
|
38
|
+
// green ▶ = active.
|
|
36
39
|
log.heading("Pod Orientation");
|
|
37
|
-
log
|
|
38
|
-
log
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
console.log(` User : ${userId}`);
|
|
41
|
+
console.log(` Pod URL : ${cfg.podUrl}`);
|
|
42
|
+
// The per-Claude-session lens (project + workspace + session) — "where am I".
|
|
43
|
+
// Full ids so they can be pasted into 'synap project use' / 'synap use'.
|
|
44
|
+
const { getClaudeSessionId, resolveActiveLens } = await import("../lib/session-lens.js");
|
|
45
|
+
let activeProjectId;
|
|
46
|
+
if (getClaudeSessionId()) {
|
|
47
|
+
const lens = resolveActiveLens();
|
|
48
|
+
activeProjectId = lens?.projectId ?? undefined;
|
|
49
|
+
const proj = lens?.projectId ?? chalk.dim("none");
|
|
50
|
+
const ws = lens?.workspaceId ?? cfg.workspaceId ?? chalk.dim("pod-wide");
|
|
51
|
+
const sess = lens?.focusSessionId ?? chalk.dim("none");
|
|
52
|
+
console.log(` Lens : ${chalk.dim("project")} ${proj} · ${chalk.dim("ws")} ${ws} · ${chalk.dim("session")} ${sess}`);
|
|
53
|
+
}
|
|
54
|
+
else if (cfg.workspaceId) {
|
|
55
|
+
console.log(` Workspace: ${cfg.workspaceId} ${chalk.dim("(active — use 'synap use <id>' to change)")}`);
|
|
56
|
+
}
|
|
57
|
+
// ── Projects (companies / initiatives) — the primary lens ───────────────
|
|
58
|
+
log.blank();
|
|
59
|
+
log.heading("Projects");
|
|
60
|
+
if (projList.length === 0) {
|
|
61
|
+
log.dim("No projects yet — a project is a company/initiative that ties workspaces together.");
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
for (const p of projList) {
|
|
65
|
+
const isActive = p.id === activeProjectId;
|
|
66
|
+
const marker = isActive ? chalk.green("▶ ") : " ";
|
|
67
|
+
const name = chalk.bold(String(p.name ?? p.id));
|
|
68
|
+
const id = chalk.dim(String(p.id ?? ""));
|
|
69
|
+
const status = p.status ? chalk.dim(String(p.status)) : "";
|
|
70
|
+
const homePart = p.homeWorkspace ? chalk.dim(`· ${p.homeWorkspace}`) : "";
|
|
71
|
+
console.log(` ${marker}${name} ${id} ${status}${homePart ? " " + homePart : ""}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// ── Workspaces (operational domains) ────────────────────────────────────
|
|
41
75
|
log.blank();
|
|
42
76
|
log.heading("Workspaces");
|
|
43
|
-
if (
|
|
77
|
+
if (wsList.length === 0) {
|
|
44
78
|
log.dim("No workspaces found.");
|
|
45
79
|
}
|
|
46
|
-
else {
|
|
47
|
-
for (const
|
|
80
|
+
else if (opts.details) {
|
|
81
|
+
for (const ws of wsList) {
|
|
48
82
|
const isActive = ws.id === cfg.workspaceId;
|
|
49
83
|
const marker = isActive ? chalk.green("▶ ") : " ";
|
|
50
84
|
const name = chalk.bold(String(ws.name ?? ws.id));
|
|
51
|
-
const id = chalk.dim(String(ws.id ?? "")
|
|
52
|
-
const count =
|
|
53
|
-
|
|
85
|
+
const id = chalk.dim(String(ws.id ?? ""));
|
|
86
|
+
const count = ws.entityCount > 0
|
|
87
|
+
? chalk.dim(`${ws.entityCount} entities`)
|
|
88
|
+
: chalk.dim("empty");
|
|
89
|
+
console.log(` ${marker}${name} ${id} ${count}`);
|
|
54
90
|
if (ws.description)
|
|
55
91
|
log.dim(` ${String(ws.description)}`);
|
|
56
|
-
if (
|
|
57
|
-
|
|
58
|
-
|
|
92
|
+
if (ws.onboarding?.goal && ws.entityCount === 0) {
|
|
93
|
+
log.dim(` ${chalk.cyan("→ onboard:")} ${String(ws.onboarding.goal)}`);
|
|
94
|
+
}
|
|
95
|
+
const profiles = ws.profiles ?? [];
|
|
96
|
+
if (profiles.length > 0) {
|
|
97
|
+
const slugs = profiles
|
|
98
|
+
.map((p) => p.slug)
|
|
59
99
|
.filter(Boolean)
|
|
60
100
|
.slice(0, 8)
|
|
61
101
|
.join(chalk.dim(", "));
|
|
62
|
-
log.dim(` profiles: ${slugs}${
|
|
102
|
+
log.dim(` profiles: ${slugs}${profiles.length > 8 ? chalk.dim(" …") : ""}`);
|
|
63
103
|
}
|
|
64
104
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
// Light: name + id + domain (operational-domain label = workspaceSubtype
|
|
108
|
+
// falling back to workspaceType, resolved server-side).
|
|
109
|
+
for (const ws of wsList) {
|
|
110
|
+
const isActive = ws.id === cfg.workspaceId;
|
|
111
|
+
const marker = isActive ? chalk.green("▶ ") : " ";
|
|
112
|
+
const name = chalk.bold(String(ws.name ?? ws.id));
|
|
113
|
+
const id = chalk.dim(String(ws.id ?? ""));
|
|
114
|
+
const domain = ws.domain ? chalk.dim(String(ws.domain)) : "";
|
|
115
|
+
console.log(` ${marker}${name} ${id} ${domain}`);
|
|
68
116
|
}
|
|
117
|
+
log.blank();
|
|
118
|
+
log.dim("Workspaces are operational domains; run 'synap orient --details' for profiles + entity counts.");
|
|
69
119
|
}
|
|
120
|
+
log.blank();
|
|
121
|
+
log.dim("Lenses compose — a project spans workspaces; a workspace spans projects. Omit them to stay pod-wide.");
|
|
122
|
+
renderNextSteps(FLOW.afterOrient());
|
|
70
123
|
}
|
|
71
124
|
catch (e) {
|
|
72
|
-
|
|
125
|
+
renderHubError(e);
|
|
73
126
|
process.exit(1);
|
|
74
127
|
}
|
|
75
128
|
}
|
|
@@ -80,8 +133,7 @@ export async function useWorkspace(workspaceId, opts) {
|
|
|
80
133
|
const userId = await resolveUserId(cfg);
|
|
81
134
|
// Verify the workspace exists and is accessible
|
|
82
135
|
const res = await hubGet("/workspaces", {}, cfg);
|
|
83
|
-
const
|
|
84
|
-
const list = Array.isArray(workspaces) ? workspaces : [];
|
|
136
|
+
const list = unwrapList(res, ["workspaces"]);
|
|
85
137
|
const match = list.find((w) => w.id === workspaceId || String(w.name).toLowerCase() === workspaceId.toLowerCase());
|
|
86
138
|
if (!match) {
|
|
87
139
|
const names = list.map((w) => `${String(w.name ?? w.id)}`).join(", ");
|
|
@@ -90,17 +142,26 @@ export async function useWorkspace(workspaceId, opts) {
|
|
|
90
142
|
log.dim(`Available: ${names}`);
|
|
91
143
|
process.exit(1);
|
|
92
144
|
}
|
|
93
|
-
|
|
94
|
-
|
|
145
|
+
// In a Claude Code session, scope to THIS session's lens (so concurrent
|
|
146
|
+
// sessions can be on different workspaces). Otherwise set the global default.
|
|
147
|
+
const { getClaudeSessionId, writeLens } = await import("../lib/session-lens.js");
|
|
148
|
+
const claudeSession = getClaudeSessionId();
|
|
149
|
+
if (claudeSession) {
|
|
150
|
+
writeLens(claudeSession, { workspaceId: String(match.id) });
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
const { setActiveWorkspaceId } = await import("../lib/pod.js");
|
|
154
|
+
setActiveWorkspaceId(String(match.id));
|
|
155
|
+
}
|
|
95
156
|
if (opts.json) {
|
|
96
|
-
console.log(JSON.stringify({ workspaceId: match.id, name: match.name }, null, 2));
|
|
157
|
+
console.log(JSON.stringify({ workspaceId: match.id, name: match.name, scope: claudeSession ? "session" : "global" }, null, 2));
|
|
97
158
|
return;
|
|
98
159
|
}
|
|
99
|
-
|
|
100
|
-
|
|
160
|
+
const scopeNote = claudeSession ? chalk.dim(" (this session)") : "";
|
|
161
|
+
log.success(`Now in workspace: ${chalk.bold(String(match.name ?? match.id))} ${chalk.dim(String(match.id ?? ""))}${scopeNote}`);
|
|
101
162
|
}
|
|
102
163
|
catch (e) {
|
|
103
|
-
|
|
164
|
+
renderHubError(e);
|
|
104
165
|
process.exit(1);
|
|
105
166
|
}
|
|
106
167
|
}
|
|
@@ -109,8 +170,7 @@ export async function listWorkspaces(opts) {
|
|
|
109
170
|
try {
|
|
110
171
|
const cfg = await resolveHubConfig(opts);
|
|
111
172
|
const res = await hubGet("/workspaces", {}, cfg);
|
|
112
|
-
const
|
|
113
|
-
const list = Array.isArray(workspaces) ? workspaces : [];
|
|
173
|
+
const list = unwrapList(res, ["workspaces"]);
|
|
114
174
|
if (opts.json) {
|
|
115
175
|
console.log(JSON.stringify({ workspaces: list }, null, 2));
|
|
116
176
|
return;
|
|
@@ -125,7 +185,7 @@ export async function listWorkspaces(opts) {
|
|
|
125
185
|
}
|
|
126
186
|
}
|
|
127
187
|
catch (e) {
|
|
128
|
-
|
|
188
|
+
renderHubError(e);
|
|
129
189
|
process.exit(1);
|
|
130
190
|
}
|
|
131
191
|
}
|
|
@@ -134,21 +194,53 @@ export async function listEntities(opts) {
|
|
|
134
194
|
try {
|
|
135
195
|
const cfg = await resolveHubConfig(opts);
|
|
136
196
|
const userId = await resolveUserId(cfg);
|
|
137
|
-
const limit =
|
|
197
|
+
const limit = parseLimit(opts.limit, 20);
|
|
198
|
+
const workspaceId = opts.workspace ?? cfg.workspaceId;
|
|
199
|
+
// --role needs a workspace to resolve facet scope (see browseEntities);
|
|
200
|
+
// without one the filter is silently dropped and "no entities" would lie.
|
|
201
|
+
if (opts.role && !workspaceId) {
|
|
202
|
+
throw new Error("--role needs an active workspace to resolve the role. Run 'synap use <workspace>' or pass --workspace <id>.");
|
|
203
|
+
}
|
|
138
204
|
const res = await hubGet("/entities", {
|
|
139
205
|
userId,
|
|
140
|
-
workspaceId
|
|
206
|
+
workspaceId,
|
|
141
207
|
profileSlug: opts.profile,
|
|
208
|
+
// Browse-by-role: the list route resolves facet scope from the
|
|
209
|
+
// `workspaceId` QUERY PARAM (already threaded above), not the
|
|
210
|
+
// X-Workspace-Id header — verified against the live pod.
|
|
211
|
+
facetSlug: opts.role,
|
|
142
212
|
limit,
|
|
143
213
|
}, cfg);
|
|
144
|
-
const
|
|
145
|
-
const list = Array.isArray(entities) ? entities : [];
|
|
214
|
+
const list = unwrapList(res, ["entities"]);
|
|
146
215
|
if (opts.json) {
|
|
147
|
-
console.log(JSON.stringify({ entities: list }, null, 2));
|
|
216
|
+
console.log(JSON.stringify({ entities: list, count: list.length, limit, truncated: list.length === limit }, null, 2));
|
|
148
217
|
return;
|
|
149
218
|
}
|
|
150
219
|
if (list.length === 0) {
|
|
151
220
|
log.dim("No entities found.");
|
|
221
|
+
// Whiteboards, kanbans, calendars… are VIEWS, not entity profiles.
|
|
222
|
+
// If the requested profile is actually a view type, point there.
|
|
223
|
+
if (opts.profile) {
|
|
224
|
+
try {
|
|
225
|
+
const viewsRes = await hubGet("/views", {
|
|
226
|
+
userId,
|
|
227
|
+
workspaceId: opts.workspace ?? cfg.workspaceId,
|
|
228
|
+
type: opts.profile,
|
|
229
|
+
}, cfg);
|
|
230
|
+
const views = unwrapList(viewsRes, ["views"]);
|
|
231
|
+
if (views.length > 0) {
|
|
232
|
+
log.blank();
|
|
233
|
+
log.info(`'${opts.profile}' is a ${chalk.bold("view type")}, not an entity profile — found ${views.length} view${views.length !== 1 ? "s" : ""}.`);
|
|
234
|
+
log.dim(` Run: synap list views --type ${opts.profile}`);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
catch {
|
|
239
|
+
// best-effort hint only — never fail the empty-result path
|
|
240
|
+
}
|
|
241
|
+
log.dim(` Profiles in this workspace: synap list profiles`);
|
|
242
|
+
log.dim(` Views (whiteboard, kanban, …): synap list views`);
|
|
243
|
+
}
|
|
152
244
|
return;
|
|
153
245
|
}
|
|
154
246
|
for (const entity of list) {
|
|
@@ -158,9 +250,12 @@ export async function listEntities(opts) {
|
|
|
158
250
|
const id = String(e.id ?? "").slice(0, 8);
|
|
159
251
|
log.info(`${name} ${chalk.dim(`(${profile})`)} — ${chalk.dim(id)}`);
|
|
160
252
|
}
|
|
253
|
+
if (list.length === limit) {
|
|
254
|
+
log.dim(`${list.length} shown (hit --limit ${limit}; more may exist — raise --limit or filter with --profile)`);
|
|
255
|
+
}
|
|
161
256
|
}
|
|
162
257
|
catch (e) {
|
|
163
|
-
|
|
258
|
+
renderHubError(e);
|
|
164
259
|
process.exit(1);
|
|
165
260
|
}
|
|
166
261
|
}
|
|
@@ -188,130 +283,178 @@ export async function getEntity(id, opts) {
|
|
|
188
283
|
}
|
|
189
284
|
}
|
|
190
285
|
catch (e) {
|
|
191
|
-
|
|
286
|
+
renderHubError(e);
|
|
192
287
|
process.exit(1);
|
|
193
288
|
}
|
|
194
289
|
}
|
|
195
|
-
|
|
196
|
-
|
|
290
|
+
/** Render one item according to its substrate. */
|
|
291
|
+
function formatAskItem(substrate, item) {
|
|
292
|
+
if (substrate === "procedural") {
|
|
293
|
+
// knowledge_keys rows: addressed by `key`, body in `value`.
|
|
294
|
+
const key = (item.key ?? item.slug ?? item.namespace);
|
|
295
|
+
const value = (item.value ?? "");
|
|
296
|
+
const snippet = value
|
|
297
|
+
? " — " + (value.length > 80 ? value.slice(0, 77) + "…" : value).replace(/\s+/g, " ")
|
|
298
|
+
: "";
|
|
299
|
+
return `${key ?? "(untitled)"}${chalk.dim(snippet)}`;
|
|
300
|
+
}
|
|
301
|
+
if (substrate === "episodic") {
|
|
302
|
+
// knowledge_facts rows: text is in `fact` (content/text are wire fallbacks).
|
|
303
|
+
const content = (item.fact ?? item.content ?? item.text ?? "");
|
|
304
|
+
return content.length > 120 ? content.slice(0, 117) + "…" : content || "(empty)";
|
|
305
|
+
}
|
|
306
|
+
// semantic — an entity. Surface a body snippet (not just a pointer): the
|
|
307
|
+
// entity carries its content in `preview` or a description-ish property, so a
|
|
308
|
+
// "how do I…" answer shows the gist inline instead of only an entity title.
|
|
309
|
+
const { title, type, id } = formatHit(item);
|
|
310
|
+
const props = (item.properties ?? {});
|
|
311
|
+
const desc = String(item.preview ??
|
|
312
|
+
props.description ??
|
|
313
|
+
props.recipeDescription ??
|
|
314
|
+
props.summary ??
|
|
315
|
+
props.body ??
|
|
316
|
+
props.content ??
|
|
317
|
+
"");
|
|
318
|
+
const snippet = desc
|
|
319
|
+
? chalk.dim(" — " +
|
|
320
|
+
(desc.length > 90 ? desc.slice(0, 87) + "…" : desc).replace(/\s+/g, " "))
|
|
321
|
+
: "";
|
|
322
|
+
return `${title} ${chalk.dim(`[${type}]`)} ${chalk.dim(id)}${snippet}`;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Render the A/B ranker diagnostic: baseline vs Horizon top-N side-by-side,
|
|
326
|
+
* then the diff. Comparison is by RANK POSITION (not score magnitude) — the two
|
|
327
|
+
* strategies score on different scales, so only the ordering is comparable.
|
|
328
|
+
*/
|
|
329
|
+
function renderComparison(query, comparison) {
|
|
330
|
+
if (!comparison) {
|
|
331
|
+
log.dim(`"${query}" → no ranker comparison returned (semantic pool empty?).`);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const { baseline, horizon, diff } = comparison;
|
|
335
|
+
const n = Math.max(baseline.length, horizon.length);
|
|
336
|
+
log.dim(`"${query}" → A/B ranker comparison (by RANK, not score magnitude)`);
|
|
337
|
+
log.blank();
|
|
338
|
+
// Side-by-side: rank · title for each column.
|
|
339
|
+
const trunc = (s, w) => (s.length > w ? s.slice(0, w - 1) + "…" : s).padEnd(w, " ");
|
|
340
|
+
const COL = 38;
|
|
341
|
+
log.info(" " + chalk.bold("BASELINE".padEnd(COL + 5)) + chalk.bold("HORIZON"));
|
|
342
|
+
for (let i = 0; i < n; i++) {
|
|
343
|
+
const b = baseline[i];
|
|
344
|
+
const h = horizon[i];
|
|
345
|
+
const bCell = b ? `${chalk.dim(`#${b.rank}`)} ${trunc(b.title, COL)}` : "".padEnd(COL + 4);
|
|
346
|
+
const hCell = h ? `${chalk.dim(`#${h.rank}`)} ${trunc(h.title, COL)}` : "";
|
|
347
|
+
log.info(" " + bCell + " " + hCell);
|
|
348
|
+
}
|
|
349
|
+
log.blank();
|
|
350
|
+
// Diff — overlap@N + items that moved rank between the two strategies.
|
|
351
|
+
const topN = Math.max(baseline.length, horizon.length);
|
|
352
|
+
log.info(chalk.bold("DIFF") +
|
|
353
|
+
chalk.dim(` · overlap@${topN}: ${diff.overlapAtN}/${topN} shared ids`));
|
|
354
|
+
if (diff.moved.length === 0) {
|
|
355
|
+
log.dim(" No shared item changed rank between the two rankers.");
|
|
356
|
+
}
|
|
357
|
+
else {
|
|
358
|
+
for (const m of diff.moved) {
|
|
359
|
+
const dir = m.horizonRank < m.baselineRank ? chalk.green("↑") : chalk.red("↓");
|
|
360
|
+
log.info(` ${dir} ${m.title} ${chalk.dim(`(baseline #${m.baselineRank} → horizon #${m.horizonRank})`)}`);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
log.blank();
|
|
364
|
+
}
|
|
365
|
+
export async function askKnowledge(query, opts) {
|
|
197
366
|
try {
|
|
198
367
|
const cfg = await resolveHubConfig(opts);
|
|
199
|
-
const
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
collections = "entities";
|
|
204
|
-
else if (opts.type === "doc")
|
|
205
|
-
collections = "documents";
|
|
206
|
-
const res = await hubGet("/search", {
|
|
207
|
-
userId,
|
|
368
|
+
const limit = parseLimit(opts.limit, 10);
|
|
369
|
+
const workspaceId = opts.workspace ?? cfg.workspaceId;
|
|
370
|
+
const sessionId = opts.session ? readActiveSessionId() : undefined;
|
|
371
|
+
const res = (await hubPost("/knowledge/ask", {
|
|
208
372
|
query,
|
|
209
|
-
workspaceId
|
|
373
|
+
...(workspaceId ? { workspaceId } : {}),
|
|
374
|
+
...(sessionId ? { sessionId } : {}),
|
|
210
375
|
limit,
|
|
211
|
-
|
|
212
|
-
}, cfg);
|
|
376
|
+
...(opts.compare ? { compare: true } : {}),
|
|
377
|
+
}, cfg));
|
|
213
378
|
if (opts.json) {
|
|
214
379
|
console.log(JSON.stringify(res, null, 2));
|
|
215
380
|
return;
|
|
216
381
|
}
|
|
217
|
-
|
|
218
|
-
//
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
(
|
|
222
|
-
if (rawHits.length === 0) {
|
|
223
|
-
const workspaceId = opts.workspace ?? cfg.workspaceId;
|
|
224
|
-
log.dim(`No results for "${query}".`);
|
|
225
|
-
if (workspaceId) {
|
|
226
|
-
// Show what IS in the workspace so the user isn't left with a blank wall
|
|
227
|
-
const [profilesRes, entitiesRes] = await Promise.allSettled([
|
|
228
|
-
hubGet("/profiles", { userId, workspaceId }, cfg),
|
|
229
|
-
hubGet("/entities", { userId, workspaceId, limit: 5 }, cfg),
|
|
230
|
-
]);
|
|
231
|
-
if (profilesRes.status === "fulfilled") {
|
|
232
|
-
const profiles = profilesRes.value.profiles ?? profilesRes.value;
|
|
233
|
-
const pList = Array.isArray(profiles) ? profiles : [];
|
|
234
|
-
if (pList.length > 0) {
|
|
235
|
-
const total = (entitiesRes.status === "fulfilled")
|
|
236
|
-
? Number(entitiesRes.value.total ?? 0)
|
|
237
|
-
: 0;
|
|
238
|
-
log.blank();
|
|
239
|
-
log.dim(`This workspace has ${total > 0 ? `${total} entities` : "no entities yet"} across ${pList.length} profile${pList.length !== 1 ? "s" : ""}:`);
|
|
240
|
-
for (const p of pList.slice(0, 6)) {
|
|
241
|
-
log.dim(` · ${String(p.name ?? p.slug ?? "")} ${chalk.dim(`--profile=${String(p.slug ?? "")}`)}`);
|
|
242
|
-
}
|
|
243
|
-
log.blank();
|
|
244
|
-
log.dim(`Try: synap search <term> --workspace ${workspaceId}`);
|
|
245
|
-
log.dim(` or synap list --workspace ${workspaceId} --profile <slug>`);
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
382
|
+
// A/B ranker diagnostic — render the comparison and STOP. This is a
|
|
383
|
+
// ranking diff (baseline vs Horizon on the same candidate pool), not the
|
|
384
|
+
// normal answer, so it replaces the substrate listing when requested.
|
|
385
|
+
if (opts.compare) {
|
|
386
|
+
renderComparison(query, res.comparison);
|
|
249
387
|
return;
|
|
250
388
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const cfg = await resolveHubConfig(opts);
|
|
270
|
-
const userId = await resolveUserId(cfg);
|
|
271
|
-
const res = await hubPost("/memory", {
|
|
272
|
-
userId,
|
|
273
|
-
fact: text,
|
|
274
|
-
sourceEntityId: opts.context,
|
|
275
|
-
}, cfg);
|
|
276
|
-
const data = res;
|
|
277
|
-
const id = String(data.id ?? "");
|
|
278
|
-
if (opts.json) {
|
|
279
|
-
console.log(JSON.stringify({ id, stored: true }, null, 2));
|
|
389
|
+
const routed = (res.routedTo ?? []).join(", ");
|
|
390
|
+
const verdict = res.verdict ? chalk.dim(` · ${res.verdict}`) : "";
|
|
391
|
+
// Honest routing: if the query's cue suggested one substrate but another
|
|
392
|
+
// actually answered (e.g. "how to…" cued procedural but the runbook is an
|
|
393
|
+
// entity), say so instead of dangling a "primary" that returned nothing.
|
|
394
|
+
const routeNote = res.intent && res.intent !== res.primary
|
|
395
|
+
? `${chalk.bold(routed)} · asked-for ${res.intent}, answered by ${chalk.bold(res.primary)}`
|
|
396
|
+
: `${chalk.bold(routed)} (primary: ${chalk.bold(res.primary)})`;
|
|
397
|
+
log.dim(`"${query}" → routed to ${routeNote}${verdict}`);
|
|
398
|
+
log.blank();
|
|
399
|
+
const answers = res.answers ?? [];
|
|
400
|
+
const total = answers.reduce((n, a) => n + (a.items?.length ?? 0), 0);
|
|
401
|
+
const anyErrored = (res.degraded?.length ?? 0) > 0;
|
|
402
|
+
// Only claim a clean "no results" when every store actually answered. If one
|
|
403
|
+
// errored, fall through to the per-substrate loop so the outage is shown.
|
|
404
|
+
if (total === 0 && !anyErrored) {
|
|
405
|
+
log.dim(`No results across ${routed || "any substrate"}.`);
|
|
406
|
+
log.dim(` Try broader terms, or capture knowledge with: synap capture`);
|
|
280
407
|
return;
|
|
281
408
|
}
|
|
282
|
-
|
|
409
|
+
for (const answer of answers) {
|
|
410
|
+
const items = answer.items ?? [];
|
|
411
|
+
// Glass-box: an errored store is NOT "found nothing" — say so, never hide it.
|
|
412
|
+
if (answer.status === "error") {
|
|
413
|
+
log.info(chalk.bold(answer.substrate.toUpperCase()) +
|
|
414
|
+
chalk.yellow(" — store unavailable (not searched)"));
|
|
415
|
+
log.blank();
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
if (items.length === 0)
|
|
419
|
+
continue;
|
|
420
|
+
log.info(chalk.bold(answer.substrate.toUpperCase()) + chalk.dim(` (${items.length})`));
|
|
421
|
+
for (const item of items) {
|
|
422
|
+
log.info(" " + formatAskItem(answer.substrate, item));
|
|
423
|
+
}
|
|
424
|
+
log.blank();
|
|
425
|
+
}
|
|
426
|
+
// res.degraded was only ever checked as a boolean (anyErrored) above —
|
|
427
|
+
// surface which substrate(s) actually degraded, verbatim, so the answer's
|
|
428
|
+
// incompleteness is visible rather than just its existence.
|
|
429
|
+
if (res.degraded && res.degraded.length > 0) {
|
|
430
|
+
log.dim(`Degraded: ${res.degraded.join(", ")}`);
|
|
431
|
+
}
|
|
283
432
|
}
|
|
284
433
|
catch (e) {
|
|
285
|
-
|
|
434
|
+
renderHubError(e);
|
|
286
435
|
process.exit(1);
|
|
287
436
|
}
|
|
288
437
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if (opts.json) {
|
|
299
|
-
console.log(JSON.stringify({ memories: list }, null, 2));
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
if (list.length === 0) {
|
|
303
|
-
log.dim("No memories found.");
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
list.forEach((mem, i) => {
|
|
307
|
-
const m = mem;
|
|
308
|
-
const content = String(m.fact ?? m.content ?? "").slice(0, 120);
|
|
309
|
-
log.info(`${i + 1}. ${content}`);
|
|
310
|
-
});
|
|
438
|
+
const refLabel = (r) => `${String(r.name ?? r.id ?? "?")}${r.profileSlug ? ` [${r.profileSlug}]` : ""}`;
|
|
439
|
+
/** Print 1-3 dim graph-impact lines for a create response. No-op if absent. */
|
|
440
|
+
function reportResolution(res) {
|
|
441
|
+
const resolution = res.resolution;
|
|
442
|
+
if (!resolution)
|
|
443
|
+
return;
|
|
444
|
+
const existing = resolution.existingSameProfile;
|
|
445
|
+
if (existing) {
|
|
446
|
+
log.dim(`⚠ an entity named "${String(existing.name ?? "?")}" already exists as profile ${String(existing.profileSlug ?? "?")} (${String(existing.id ?? "?").slice(0, 8)}) — consider updating it instead of duplicating`);
|
|
311
447
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
448
|
+
const autoConnected = resolution.autoConnected ?? [];
|
|
449
|
+
if (autoConnected.length > 0) {
|
|
450
|
+
const names = autoConnected.map(refLabel).join(", ");
|
|
451
|
+
log.dim(`→ auto-linked to ${autoConnected.length} existing same-name entit${autoConnected.length === 1 ? "y" : "ies"}: ${names}`);
|
|
452
|
+
}
|
|
453
|
+
// suggestions beyond what was already auto-connected
|
|
454
|
+
const autoIds = new Set(autoConnected.map((r) => r.id).filter(Boolean));
|
|
455
|
+
const suggestions = (resolution.suggestions ?? []).filter((s) => !autoIds.has(s.id));
|
|
456
|
+
if (suggestions.length > 0) {
|
|
457
|
+
log.dim(`· you may want to link: ${suggestions.map(refLabel).join(", ")}`);
|
|
315
458
|
}
|
|
316
459
|
}
|
|
317
460
|
// ─── createEntity ─────────────────────────────────────────────────────────────
|
|
@@ -319,7 +462,6 @@ export async function createEntity(opts) {
|
|
|
319
462
|
try {
|
|
320
463
|
const cfg = await resolveHubConfig(opts);
|
|
321
464
|
const userId = await resolveUserId(cfg);
|
|
322
|
-
// parse props as unknown then cast — user-supplied JSON
|
|
323
465
|
const properties = JSON.parse(opts.props ?? "{}");
|
|
324
466
|
const res = await hubPost("/entities", {
|
|
325
467
|
userId,
|
|
@@ -329,19 +471,20 @@ export async function createEntity(opts) {
|
|
|
329
471
|
properties,
|
|
330
472
|
}, cfg);
|
|
331
473
|
const entity = res;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
474
|
+
await reportWrite(entity, {
|
|
475
|
+
label: `Created: ${opts.name}`,
|
|
476
|
+
lane: "work",
|
|
477
|
+
workspaceId: opts.workspace ?? cfg.workspaceId,
|
|
478
|
+
cfg,
|
|
479
|
+
json: opts.json,
|
|
480
|
+
});
|
|
481
|
+
// Graph-impact feedback — human output only (the `--json` path already
|
|
482
|
+
// passed the raw response, including `resolution`, through reportWrite).
|
|
483
|
+
if (!opts.json)
|
|
484
|
+
reportResolution(entity);
|
|
342
485
|
}
|
|
343
486
|
catch (e) {
|
|
344
|
-
|
|
487
|
+
renderHubError(e);
|
|
345
488
|
process.exit(1);
|
|
346
489
|
}
|
|
347
490
|
}
|
|
@@ -355,8 +498,8 @@ export async function listProfiles(opts) {
|
|
|
355
498
|
console.error(chalk.red("No workspace set. Run: synap use <workspace-id>"));
|
|
356
499
|
process.exit(1);
|
|
357
500
|
}
|
|
358
|
-
const res = await hubGet("/profiles", { userId, workspaceId }, cfg);
|
|
359
|
-
const profiles = (res
|
|
501
|
+
const res = await hubGet("/profiles", { userId, workspaceId, ...(opts.json ? { detail: "full" } : {}) }, cfg);
|
|
502
|
+
const profiles = unwrapList(res, ["profiles"]);
|
|
360
503
|
if (opts.json) {
|
|
361
504
|
console.log(JSON.stringify(profiles, null, 2));
|
|
362
505
|
return;
|
|
@@ -369,11 +512,18 @@ export async function listProfiles(opts) {
|
|
|
369
512
|
for (const p of profiles) {
|
|
370
513
|
const scope = String(p.entityScope ?? "workspace");
|
|
371
514
|
const desc = p.description ? chalk.dim(` — ${String(p.description).slice(0, 60)}`) : "";
|
|
372
|
-
|
|
515
|
+
// A role-profile (client, partner, …) is a hat an existing entity wears
|
|
516
|
+
// via `synap facet attach` — never created as its own entity. Label it
|
|
517
|
+
// distinctly so it's never confused with a primary kind.
|
|
518
|
+
const applicableKinds = p.applicableKinds;
|
|
519
|
+
const kindLabel = p.profileKind === "role"
|
|
520
|
+
? chalk.magenta(`[Role${applicableKinds?.length ? ` of ${applicableKinds.join("/")}` : ""}]`)
|
|
521
|
+
: chalk.green("[Kind]");
|
|
522
|
+
log.info(`${chalk.bold(String(p.slug ?? ""))} ${kindLabel} ${chalk.dim(scope)}${desc}`);
|
|
373
523
|
}
|
|
374
524
|
}
|
|
375
525
|
catch (e) {
|
|
376
|
-
|
|
526
|
+
renderHubError(e);
|
|
377
527
|
process.exit(1);
|
|
378
528
|
}
|
|
379
529
|
}
|
|
@@ -390,14 +540,16 @@ export async function createRelation(opts) {
|
|
|
390
540
|
type: opts.type,
|
|
391
541
|
}, cfg);
|
|
392
542
|
const relation = res;
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
543
|
+
await reportWrite(relation, {
|
|
544
|
+
label: `Relation: ${opts.type} (${opts.source} → ${opts.target})`,
|
|
545
|
+
lane: "work",
|
|
546
|
+
workspaceId: opts.workspace ?? cfg.workspaceId,
|
|
547
|
+
cfg,
|
|
548
|
+
json: opts.json,
|
|
549
|
+
});
|
|
398
550
|
}
|
|
399
551
|
catch (e) {
|
|
400
|
-
|
|
552
|
+
renderHubError(e);
|
|
401
553
|
process.exit(1);
|
|
402
554
|
}
|
|
403
555
|
}
|
|
@@ -405,21 +557,30 @@ export async function createRelation(opts) {
|
|
|
405
557
|
export async function updateEntity(id, opts) {
|
|
406
558
|
try {
|
|
407
559
|
const cfg = await resolveHubConfig(opts);
|
|
560
|
+
const workspaceId = opts.workspace ?? cfg.workspaceId;
|
|
408
561
|
// parse props as unknown then cast — user-supplied JSON
|
|
409
562
|
const metadata = JSON.parse(opts.props);
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
563
|
+
const body = { userId: cfg.userId, metadata };
|
|
564
|
+
// backend reads body.workspaceId to scope automation matching — without it
|
|
565
|
+
// the update lands pod-wide and workspace-gated automations never fire
|
|
566
|
+
if (workspaceId)
|
|
567
|
+
body.workspaceId = workspaceId;
|
|
568
|
+
const res = await hubPatch(`/entities/${id}`, body, cfg);
|
|
414
569
|
const entity = res;
|
|
415
570
|
if (opts.json) {
|
|
416
571
|
console.log(JSON.stringify(entity, null, 2));
|
|
417
572
|
return;
|
|
418
573
|
}
|
|
419
574
|
log.success(`Updated: ${id}`);
|
|
575
|
+
// Graph-impact feedback — shallow immediate neighbors the edit may touch.
|
|
576
|
+
// Additive + graceful: absent on older backends, so output is unchanged.
|
|
577
|
+
const impact = entity.impact;
|
|
578
|
+
if (Array.isArray(impact) && impact.length > 0) {
|
|
579
|
+
log.dim(`→ ${impact.length} connected entit${impact.length === 1 ? "y" : "ies"} may be affected: ${impact.map(refLabel).join(", ")}`);
|
|
580
|
+
}
|
|
420
581
|
}
|
|
421
582
|
catch (e) {
|
|
422
|
-
|
|
583
|
+
renderHubError(e);
|
|
423
584
|
process.exit(1);
|
|
424
585
|
}
|
|
425
586
|
}
|