@synap-core/cli 1.12.2 → 1.13.1-next.20261102.246dc73
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 +38 -11
- package/dist/build-info.json +2 -3
- package/dist/commands/agents.d.ts +0 -1
- package/dist/commands/agents.js +13 -3
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/app.js +2 -1
- package/dist/commands/app.js.map +1 -1
- package/dist/commands/automation.js +46 -41
- 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.js +3 -1
- package/dist/commands/bridge-setup.js.map +1 -1
- package/dist/commands/capability.d.ts +87 -1
- package/dist/commands/capability.js +174 -64
- package/dist/commands/capability.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 +1 -3
- package/dist/commands/connect.js +2 -2
- package/dist/commands/connect.js.map +1 -1
- package/dist/commands/context.js +74 -44
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/data-extra.d.ts +13 -0
- package/dist/commands/data-extra.js +35 -6
- package/dist/commands/data-extra.js.map +1 -1
- package/dist/commands/data.js +2 -1
- package/dist/commands/data.js.map +1 -1
- package/dist/commands/doctor.d.ts +39 -0
- package/dist/commands/doctor.js +136 -14
- package/dist/commands/doctor.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 +25 -0
- package/dist/commands/import.js +98 -12
- package/dist/commands/import.js.map +1 -1
- package/dist/commands/init.d.ts +14 -0
- package/dist/commands/init.js +63 -21
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/keys-request.d.ts +48 -0
- package/dist/commands/keys-request.js +236 -0
- package/dist/commands/keys-request.js.map +1 -0
- package/dist/commands/keys-request.test.d.ts +1 -0
- package/dist/commands/keys-request.test.js +176 -0
- package/dist/commands/keys-request.test.js.map +1 -0
- package/dist/commands/knowledge.d.ts +42 -5
- package/dist/commands/knowledge.js +94 -29
- package/dist/commands/knowledge.js.map +1 -1
- package/dist/commands/lens.js +2 -1
- package/dist/commands/lens.js.map +1 -1
- package/dist/commands/market-authoring.js +1 -1
- package/dist/commands/market-authoring.js.map +1 -1
- package/dist/commands/market.d.ts +89 -31
- package/dist/commands/market.js +215 -222
- package/dist/commands/market.js.map +1 -1
- package/dist/commands/mcp.d.ts +1 -1
- package/dist/commands/mcp.js +14 -9
- 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/playbook.js +9 -0
- package/dist/commands/playbook.js.map +1 -1
- package/dist/commands/pods.d.ts +6 -1
- package/dist/commands/pods.js +38 -17
- package/dist/commands/pods.js.map +1 -1
- package/dist/commands/proposals-actions.js +7 -1
- package/dist/commands/proposals-actions.js.map +1 -1
- package/dist/commands/proton-setup.js +3 -1
- package/dist/commands/proton-setup.js.map +1 -1
- package/dist/commands/providers.d.ts +22 -6
- package/dist/commands/providers.js +39 -32
- package/dist/commands/providers.js.map +1 -1
- package/dist/commands/raycast.d.ts +15 -0
- package/dist/commands/raycast.js +36 -10
- package/dist/commands/raycast.js.map +1 -1
- 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 +9 -4
- package/dist/commands/session-wait.js +20 -5
- package/dist/commands/session-wait.js.map +1 -1
- package/dist/commands/sessions.d.ts +2 -0
- package/dist/commands/sessions.js +23 -0
- package/dist/commands/sessions.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/status.js +13 -7
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/statusline.backoff.test.js +13 -3
- package/dist/commands/statusline.backoff.test.js.map +1 -1
- package/dist/commands/statusline.d.ts +104 -9
- package/dist/commands/statusline.js +392 -148
- package/dist/commands/statusline.js.map +1 -1
- package/dist/commands/statusline.line2.test.d.ts +15 -0
- package/dist/commands/statusline.line2.test.js +226 -0
- package/dist/commands/statusline.line2.test.js.map +1 -0
- package/dist/commands/statusline.needs-you.test.d.ts +1 -0
- package/dist/commands/statusline.needs-you.test.js +17 -0
- package/dist/commands/statusline.needs-you.test.js.map +1 -0
- package/dist/commands/statusline.now.test.d.ts +10 -0
- package/dist/commands/statusline.now.test.js +250 -0
- package/dist/commands/statusline.now.test.js.map +1 -0
- package/dist/commands/tracks.d.ts +68 -6
- package/dist/commands/tracks.js +272 -16
- package/dist/commands/tracks.js.map +1 -1
- package/dist/commands/upload.js +12 -0
- package/dist/commands/upload.js.map +1 -1
- package/dist/commands/wait.d.ts +124 -0
- package/dist/commands/wait.js +384 -0
- package/dist/commands/wait.js.map +1 -0
- package/dist/commands/wait.test.d.ts +8 -0
- package/dist/commands/wait.test.js +308 -0
- package/dist/commands/wait.test.js.map +1 -0
- package/dist/commands/whoami.d.ts +7 -0
- package/dist/commands/whoami.js +17 -0
- 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-github-app.d.ts +63 -0
- package/dist/commands/worker-github-app.js +161 -0
- package/dist/commands/worker-github-app.js.map +1 -0
- package/dist/commands/worker-github-app.test.d.ts +1 -0
- package/dist/commands/worker-github-app.test.js +102 -0
- package/dist/commands/worker-github-app.test.js.map +1 -0
- package/dist/commands/worker-github-broker.d.ts +39 -0
- package/dist/commands/worker-github-broker.js +106 -0
- package/dist/commands/worker-github-broker.js.map +1 -0
- package/dist/commands/worker-github-broker.test.d.ts +1 -0
- package/dist/commands/worker-github-broker.test.js +90 -0
- package/dist/commands/worker-github-broker.test.js.map +1 -0
- package/dist/commands/worker-runs.test.d.ts +1 -0
- package/dist/commands/worker-runs.test.js +150 -0
- package/dist/commands/worker-runs.test.js.map +1 -0
- package/dist/commands/worker-worktrees.d.ts +34 -0
- package/dist/commands/worker-worktrees.js +87 -0
- package/dist/commands/worker-worktrees.js.map +1 -0
- package/dist/commands/worker.d.ts +406 -10
- package/dist/commands/worker.js +1180 -126
- package/dist/commands/worker.js.map +1 -1
- package/dist/commands/worker.test.js +588 -11
- package/dist/commands/worker.test.js.map +1 -1
- package/dist/index.js +220 -28
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-door.d.ts +1 -3
- package/dist/lib/agent-door.js +10 -7
- package/dist/lib/agent-door.js.map +1 -1
- package/dist/lib/agents-config.d.ts +9 -0
- package/dist/lib/agents-config.js +20 -0
- package/dist/lib/agents-config.js.map +1 -1
- package/dist/lib/atomic-file.d.ts +20 -1
- package/dist/lib/atomic-file.js +100 -2
- package/dist/lib/atomic-file.js.map +1 -1
- package/dist/lib/auth.d.ts +28 -2
- package/dist/lib/auth.js +52 -12
- package/dist/lib/auth.js.map +1 -1
- 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 +250 -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/bridge-invocation.test.d.ts +1 -0
- package/dist/lib/bridge-invocation.test.js +75 -0
- package/dist/lib/bridge-invocation.test.js.map +1 -0
- package/dist/lib/bridge-status.d.ts +144 -0
- package/dist/lib/bridge-status.js +227 -0
- package/dist/lib/bridge-status.js.map +1 -0
- package/dist/lib/bridge-status.test.d.ts +6 -0
- package/dist/lib/bridge-status.test.js +197 -0
- package/dist/lib/bridge-status.test.js.map +1 -0
- package/dist/lib/client-header.test.d.ts +1 -0
- package/dist/lib/client-header.test.js +103 -0
- package/dist/lib/client-header.test.js.map +1 -0
- package/dist/lib/conversation-headers.d.ts +89 -9
- package/dist/lib/conversation-headers.js +156 -3
- package/dist/lib/conversation-headers.js.map +1 -1
- package/dist/lib/conversation-headers.test.d.ts +1 -0
- package/dist/lib/conversation-headers.test.js +78 -0
- package/dist/lib/conversation-headers.test.js.map +1 -0
- package/dist/lib/credential-class.d.ts +40 -2
- package/dist/lib/credential-class.js +48 -6
- package/dist/lib/credential-class.js.map +1 -1
- package/dist/lib/device-connect.d.ts +45 -0
- package/dist/lib/device-connect.js +60 -0
- package/dist/lib/device-connect.js.map +1 -1
- package/dist/lib/exporter-coverage.d.ts +1 -1
- package/dist/lib/exporter-coverage.js +1 -1
- package/dist/lib/goal-words.d.ts +38 -0
- package/dist/lib/goal-words.js +115 -0
- package/dist/lib/goal-words.js.map +1 -0
- package/dist/lib/hub-client.d.ts +87 -8
- package/dist/lib/hub-client.js +205 -70
- package/dist/lib/hub-client.js.map +1 -1
- package/dist/lib/init-handoff.d.ts +8 -0
- package/dist/lib/init-handoff.js +9 -2
- package/dist/lib/init-handoff.js.map +1 -1
- package/dist/lib/key-locations.d.ts +3 -3
- package/dist/lib/key-locations.js +3 -39
- package/dist/lib/key-locations.js.map +1 -1
- package/dist/lib/key-source.d.ts +3 -1
- package/dist/lib/key-source.js +7 -4
- package/dist/lib/key-source.js.map +1 -1
- package/dist/lib/knowledge-title.d.ts +3 -2
- package/dist/lib/knowledge-title.js +3 -2
- package/dist/lib/knowledge-title.js.map +1 -1
- package/dist/lib/machine-instance.d.ts +7 -5
- package/dist/lib/machine-instance.js +7 -5
- package/dist/lib/machine-instance.js.map +1 -1
- package/dist/lib/mcp-bridge.d.ts +50 -0
- package/dist/lib/mcp-bridge.js +232 -11
- package/dist/lib/mcp-bridge.js.map +1 -1
- package/dist/lib/mcp-bridge.test.js +224 -4
- package/dist/lib/mcp-bridge.test.js.map +1 -1
- package/dist/lib/mcp-call.d.ts +5 -1
- package/dist/lib/mcp-call.js +7 -6
- package/dist/lib/mcp-call.js.map +1 -1
- package/dist/lib/mcp-connector-url.test.d.ts +1 -0
- package/dist/lib/mcp-connector-url.test.js +13 -0
- package/dist/lib/mcp-connector-url.test.js.map +1 -0
- package/dist/lib/mcp-snippets.d.ts +16 -0
- package/dist/lib/mcp-snippets.js +20 -2
- package/dist/lib/mcp-snippets.js.map +1 -1
- package/dist/lib/now-line.d.ts +66 -0
- package/dist/lib/now-line.js +193 -0
- package/dist/lib/now-line.js.map +1 -0
- package/dist/lib/now-line.test.d.ts +5 -0
- package/dist/lib/now-line.test.js +177 -0
- package/dist/lib/now-line.test.js.map +1 -0
- package/dist/lib/package-updates.d.ts +66 -0
- package/dist/lib/package-updates.js +76 -0
- package/dist/lib/package-updates.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.d.ts +8 -4
- package/dist/lib/pod.js +12 -10
- package/dist/lib/pod.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 +97 -0
- package/dist/lib/register-claude-code-mcp.test.js.map +1 -0
- package/dist/lib/review-credential.js +3 -1
- package/dist/lib/review-credential.js.map +1 -1
- package/dist/lib/safe-open.d.ts +5 -3
- package/dist/lib/safe-open.js +9 -8
- package/dist/lib/safe-open.js.map +1 -1
- package/dist/lib/self-host.d.ts +17 -0
- package/dist/lib/self-host.js +24 -0
- package/dist/lib/self-host.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/targets.d.ts +52 -3
- package/dist/lib/targets.js +150 -209
- package/dist/lib/targets.js.map +1 -1
- package/dist/lib/template-lifecycle.d.ts +0 -31
- package/dist/lib/template-lifecycle.js +0 -74
- package/dist/lib/template-lifecycle.js.map +1 -1
- package/dist/lib/term.d.ts +24 -0
- package/dist/lib/term.js +52 -0
- package/dist/lib/term.js.map +1 -0
- package/dist/lib/term.test.d.ts +1 -0
- package/dist/lib/term.test.js +29 -0
- package/dist/lib/term.test.js.map +1 -0
- package/dist/lib/transcript-index.d.ts +94 -0
- package/dist/lib/transcript-index.js +321 -0
- package/dist/lib/transcript-index.js.map +1 -0
- package/dist/lib/transcript-index.test.d.ts +10 -0
- package/dist/lib/transcript-index.test.js +200 -0
- package/dist/lib/transcript-index.test.js.map +1 -0
- package/dist/lib/wait-help.d.ts +11 -0
- package/dist/lib/wait-help.js +25 -0
- package/dist/lib/wait-help.js.map +1 -0
- package/dist/lib/wait-state.d.ts +57 -0
- package/dist/lib/wait-state.js +114 -0
- package/dist/lib/wait-state.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/package.json +5 -2
- package/skills/README.md +1 -1
- package/skills/agent-os/SKILL.md +8 -8
- package/skills/synap/SKILL.md +188 -94
- package/skills/synap/code-skills.md +84 -0
- package/skills/synap/concepts.md +38 -20
- package/skills/synap/creative-loop.md +1 -1
- package/skills/synap/document-embeds.md +17 -1
- package/skills/synap/focus-sessions.md +17 -8
- package/skills/synap/from-intent.md +33 -17
- package/skills/synap/governance-rules.md +3 -1
- package/skills/synap/hand-off.md +10 -6
- package/skills/synap/lenses.md +4 -4
- package/skills/synap/linking.md +2 -2
- package/skills/synap/mental-model.md +1 -1
- package/skills/synap/operating-mode-rules.md +1 -1
- package/skills/synap/quick-reference.md +2 -1
- package/skills/synap/reflexes.md +8 -8
- package/skills/synap/viewframe-cells.md +1 -1
- package/skills/synap/work-model.md +24 -10
- package/skills/synap/workspace-design.md +5 -5
- package/skills/synap/writes.md +16 -9
- package/skills/synap/writing-titles.md +7 -0
- package/skills/synap-app/SKILL.md +148 -66
- 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-market/SKILL.md +1 -1
- package/skills/synap-market/governance-and-catalog.md +1 -1
- package/skills/synap-schema/SKILL.md +24 -21
- package/skills/synap-schema/intent-vocabulary-ssot.md +24 -21
- package/templates/box/runner.py +206 -0
package/dist/commands/market.js
CHANGED
|
@@ -32,13 +32,15 @@ import { renderNextSteps, FLOW } from "../lib/next-steps.js";
|
|
|
32
32
|
import { getStoredToken, isTokenLocallyExpired } from "../lib/auth.js";
|
|
33
33
|
import prompts from "prompts";
|
|
34
34
|
import { fetchPublicBrowseRows, fetchMyRows, fetchAvailableSlugs, fetchRetiredWorkspaceSlugs, fetchPackageDefinition, fetchPackageRecord, hydrateMineCategories, } from "../lib/cp-packages.js";
|
|
35
|
-
import { fetchInstalledSlugs, fetchInstalledTemplates, fetchInstalledInventory,
|
|
35
|
+
import { fetchInstalledSlugs, fetchInstalledTemplates, fetchInstalledInventory, installedRowsToTemplates, fetchWorkspaceAttachments, fetchWorkspaceAttachmentsStrict, verifyStampLanded, INSTALLED_KINDS } from "../lib/installed.js";
|
|
36
36
|
import { isSuite } from "../lib/suite.js";
|
|
37
37
|
import { TEMPLATE_STEP_LABELS, classifyTemplateStep, proposalsDoor, stepFromApplyState, templateStepGlyph, templateStepPhrase, } from "../lib/template-steps.js";
|
|
38
38
|
import { capabilityAdd } from "./capability.js";
|
|
39
39
|
import { bundledTemplatesVersion } from "../lib/bundle-version.js";
|
|
40
40
|
import { HubNetworkError } from "../lib/hub-client.js";
|
|
41
|
-
import {
|
|
41
|
+
import { checksFromStandings, fetchPackageStandings, StandingsUnavailableError, } from "../lib/package-updates.js";
|
|
42
|
+
import { podAdminOrigin } from "../lib/safe-open.js";
|
|
43
|
+
import { parseDataChanges, printDataChanges, parseAcceptList, decideConsent, consentRerunCommand, lifecycleNotice, overlayNotice, overlayNeedsAttention, } from "../lib/template-lifecycle.js";
|
|
42
44
|
// Same longer budget launch uses — an apply writes profiles/views/entities.
|
|
43
45
|
const APPLY_TIMEOUT_MS = 120_000;
|
|
44
46
|
/** `--timeout <seconds>` → ms, falling back to `APPLY_TIMEOUT_MS` when unset/invalid. */
|
|
@@ -167,8 +169,8 @@ const KIND_HEADINGS = {
|
|
|
167
169
|
// (`GET /installed`) calls the same thing `automation`. Both tokens reach
|
|
168
170
|
// `kindHeading()` — `market --list` speaks CP, `market installed` speaks pod —
|
|
169
171
|
// so both are mapped, to the ONE plural the registry says.
|
|
170
|
-
workflow: "
|
|
171
|
-
automation: "
|
|
172
|
+
workflow: "Automations",
|
|
173
|
+
automation: "Automations",
|
|
172
174
|
view: "Views",
|
|
173
175
|
cell: "Cards",
|
|
174
176
|
workspace: "Spaces",
|
|
@@ -383,8 +385,8 @@ function printSeedOutcomes(dependencies, seedSummary) {
|
|
|
383
385
|
log.hint(`${d.slug}: failed${d.seedOutcome.error ? ` (${d.seedOutcome.error})` : ""}`);
|
|
384
386
|
}
|
|
385
387
|
}
|
|
386
|
-
// ── Apply-outcome honesty —
|
|
387
|
-
//
|
|
388
|
+
// ── Apply-outcome honesty — `marketInstall`'s reading of `/packages/apply` ───
|
|
389
|
+
// Every install reads the same `/packages/apply` answer and must render the SAME honest
|
|
388
390
|
// verdict from its response: a partial capability-seed failure, a version
|
|
389
391
|
// stamp that silently didn't take, or a compose-overlay result are never a
|
|
390
392
|
// plain "✓ success" — in the human text OR in `--json`.
|
|
@@ -437,8 +439,8 @@ export function podApplyState(res) {
|
|
|
437
439
|
return null;
|
|
438
440
|
}
|
|
439
441
|
/**
|
|
440
|
-
* The verdict of one `/packages/apply` response — the ONE reader
|
|
441
|
-
* `marketInstall`
|
|
442
|
+
* The verdict of one `/packages/apply` response — the ONE reader
|
|
443
|
+
* `marketInstall` calls. Layer 2's outcome comes from the
|
|
442
444
|
* pod's own state (`podApplyState`): an apply the pod says is unfinished is
|
|
443
445
|
* never "updated", and never a stamp contradiction (the pod held the version
|
|
444
446
|
* on purpose — redeploying fixes nothing).
|
|
@@ -457,12 +459,11 @@ export function classifyApplyResponse(entry, res, ctx) {
|
|
|
457
459
|
return classifyApplyResult(entry, res.workspace, res.dependencies, res.seedSummary, ctx);
|
|
458
460
|
}
|
|
459
461
|
/**
|
|
460
|
-
* Classify one `/packages/apply` response into the honest verdict
|
|
461
|
-
* `marketInstall`
|
|
462
|
+
* Classify one `/packages/apply` response into the honest verdict
|
|
463
|
+
* `marketInstall` prints (and puts in `--json`).
|
|
462
464
|
* `wasUnstamped` = the slug was already installed with no recorded version
|
|
463
465
|
* BEFORE this call (only `marketInstall` can detect this today — see its
|
|
464
|
-
* `fetchInstalledTemplates` call
|
|
465
|
-
* already-versioned slugs, so it always passes `false`).
|
|
466
|
+
* `fetchInstalledTemplates` call).
|
|
466
467
|
*/
|
|
467
468
|
export function classifyApplyResult(entry, ws, dependencies, seedSummary, ctx) {
|
|
468
469
|
// A post-workspace LAYER failure counts the same as a seed failure: the
|
|
@@ -517,7 +518,7 @@ export function deferredPlacementLines(res) {
|
|
|
517
518
|
export function heldVersionLine(res) {
|
|
518
519
|
return typeof res.templateApplyWarning === "string" ? res.templateApplyWarning : null;
|
|
519
520
|
}
|
|
520
|
-
/** Render a `classifyApplyResult` verdict — the ONE honest-text door
|
|
521
|
+
/** Render a `classifyApplyResult` verdict — the ONE honest-text door of `marketInstall`. */
|
|
521
522
|
export function printApplyVerdict(entry, verdict) {
|
|
522
523
|
switch (verdict.status) {
|
|
523
524
|
case "installed":
|
|
@@ -1260,17 +1261,50 @@ function stampVersion(pkg, slug, version) {
|
|
|
1260
1261
|
const meta = pkg._meta ?? {};
|
|
1261
1262
|
return { ...pkg, _meta: { ...meta, slug, ...(version ? { version } : {}) } };
|
|
1262
1263
|
}
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1264
|
+
/**
|
|
1265
|
+
* The slugs with an update that `synap market update <slug>` can apply. Every
|
|
1266
|
+
* installed kind (space, capability, view, skill, automation) updates through
|
|
1267
|
+
* the pod's ONE update door (`POST /package-updates/{slug}/apply`), so every
|
|
1268
|
+
* slug with an update is offered; what only the person can do is said by the
|
|
1269
|
+
* pod at apply time (`NEEDS_PERSON`), never guessed here. Next-step
|
|
1270
|
+
* suggestions use it.
|
|
1271
|
+
*/
|
|
1272
|
+
export function cliUpdatableSlugs(checks) {
|
|
1273
|
+
return checks.filter((c) => c.updateAvailable).map((c) => c.slug);
|
|
1274
|
+
}
|
|
1275
|
+
/** The status of an update left for the person to apply in pod admin (not a failure). */
|
|
1276
|
+
export const APPLY_IN_POD_ADMIN = "apply-in-pod-admin";
|
|
1277
|
+
/**
|
|
1278
|
+
* Where the person finishes ONE package's update: pod admin's review page for
|
|
1279
|
+
* it (`/marketplace/updates/<slug>`), when the pod-admin origin derives from
|
|
1280
|
+
* the pod's; else the pod's own link (`reviewUrl`, pod-relative
|
|
1281
|
+
* `/open/update/<slug>`, which the pod sends on to pod admin); else the
|
|
1282
|
+
* Updates tab's words.
|
|
1283
|
+
*/
|
|
1284
|
+
export function packageReviewLink(podUrl, slug, reviewUrl) {
|
|
1285
|
+
const admin = podAdminOrigin(podUrl);
|
|
1286
|
+
if (admin)
|
|
1287
|
+
return `${admin}/marketplace/updates/${encodeURIComponent(slug)}`;
|
|
1288
|
+
if (typeof reviewUrl === "string" && reviewUrl.startsWith("/"))
|
|
1289
|
+
return `${podUrl.replace(/\/+$/, "")}${reviewUrl}`;
|
|
1290
|
+
if (typeof reviewUrl === "string" && /^https?:\/\//.test(reviewUrl))
|
|
1291
|
+
return reviewUrl;
|
|
1292
|
+
return undefined;
|
|
1293
|
+
}
|
|
1294
|
+
/** The one row for an update only the person can finish: on pod admin, not a failure. */
|
|
1295
|
+
function applyInPodAdminResult(c, podUrl, json, pod = {}) {
|
|
1296
|
+
const link = podUrl ? packageReviewLink(podUrl, c.slug, pod.reviewUrl) : undefined;
|
|
1297
|
+
if (!json) {
|
|
1298
|
+
log.warn(`${c.slug} is a ${c.kind ?? "workspace"} — to apply in pod admin${pod.why ? `: ${pod.why}` : "."} Nothing was written.`);
|
|
1299
|
+
log.hint(link ? `Apply it yourself: ${link}` : podUrl ? marketUpdatesDoor(podUrl) : "Apply it yourself from pod admin → Marketplace → Updates.");
|
|
1273
1300
|
}
|
|
1301
|
+
return {
|
|
1302
|
+
slug: c.slug,
|
|
1303
|
+
outcome: APPLY_IN_POD_ADMIN,
|
|
1304
|
+
status: APPLY_IN_POD_ADMIN,
|
|
1305
|
+
warnings: [],
|
|
1306
|
+
...(link ? { reviewUrl: link } : {}),
|
|
1307
|
+
};
|
|
1274
1308
|
}
|
|
1275
1309
|
/**
|
|
1276
1310
|
* Per-installed-slug drift check. SERVER-FIRST: when the pod runs the
|
|
@@ -1335,113 +1369,137 @@ export function dedupeBySlug(checks) {
|
|
|
1335
1369
|
const seen = new Set();
|
|
1336
1370
|
return checks.filter((c) => (seen.has(c.slug) ? false : (seen.add(c.slug), true)));
|
|
1337
1371
|
}
|
|
1372
|
+
/** The pod's typed refusals of an update (`services/package-updates/refusals.ts`). */
|
|
1373
|
+
const NEEDS_THE_PERSON = new Set(["NEEDS_PERSON", "CHOICES_NEEDED"]);
|
|
1338
1374
|
/**
|
|
1339
|
-
* Apply
|
|
1340
|
-
*
|
|
1341
|
-
*
|
|
1342
|
-
*
|
|
1375
|
+
* Apply ONE installed package's update through the pod's ONE update door,
|
|
1376
|
+
* `POST /package-updates/{slug}/apply`, whatever its kind (space, capability,
|
|
1377
|
+
* view, skill, automation) and whoever holds the key. The pod applies the
|
|
1378
|
+
* rule (backend `services/package-updates/`): a person's apply lands; an
|
|
1379
|
+
* agent key's is filed for the person's approval (`proposed`) and lands when
|
|
1380
|
+
* they approve it; what only the person can do (agree to changes to existing
|
|
1381
|
+
* records, choose for a field both sides changed, change a view) is
|
|
1382
|
+
* `NEEDS_PERSON` / `CHOICES_NEEDED` with that package's review page. An
|
|
1383
|
+
* older pod that refuses an agent here (403, no `reasonCode`) keeps today's
|
|
1384
|
+
* line: to apply in pod admin.
|
|
1343
1385
|
*/
|
|
1344
|
-
async function
|
|
1345
|
-
if (
|
|
1346
|
-
const
|
|
1386
|
+
export async function applyUpdateThroughDoor(c, cfg, opts, applyTimeoutMs = APPLY_TIMEOUT_MS, acceptDataChanges = []) {
|
|
1387
|
+
if (!c.latestVersion) {
|
|
1388
|
+
const error = "the pod named no catalog version to update to";
|
|
1347
1389
|
if (!opts.json)
|
|
1348
|
-
log.
|
|
1349
|
-
return { slug:
|
|
1350
|
-
}
|
|
1351
|
-
const cpToken = getStoredToken()?.token;
|
|
1352
|
-
// Same honest payload as `marketInstall` (see `resolveInstallPayload`).
|
|
1353
|
-
const payload = extra.payload !== undefined ? extra.payload : await resolveInstallPayload(entry.slug, cat, cpToken);
|
|
1354
|
-
if (!payload) {
|
|
1355
|
-
if (!opts.json) {
|
|
1356
|
-
log.error(`Couldn't fetch "${entry.name}"'s definition from the control plane.`);
|
|
1357
|
-
if (!cat.loggedIn)
|
|
1358
|
-
log.hint("It may be private — try: synap login");
|
|
1359
|
-
}
|
|
1360
|
-
return { slug: entry.slug, outcome: "fetch-failed", status: "fetch-failed", warnings: [] };
|
|
1390
|
+
log.error(`${c.slug} not updated — ${error}.`);
|
|
1391
|
+
return { slug: c.slug, outcome: "failed", status: "failed", warnings: [], error };
|
|
1361
1392
|
}
|
|
1362
|
-
const
|
|
1363
|
-
|
|
1364
|
-
:
|
|
1365
|
-
|
|
1393
|
+
const body = {
|
|
1394
|
+
expectedVersion: c.latestVersion,
|
|
1395
|
+
choices: {},
|
|
1396
|
+
...(acceptDataChanges.length > 0 ? { acceptDataChanges } : {}),
|
|
1397
|
+
};
|
|
1398
|
+
const s = opts.json ? null : ora(`Updating ${c.slug}…`).start();
|
|
1366
1399
|
try {
|
|
1367
|
-
const res = (await hubPost(
|
|
1400
|
+
const res = (await hubPost(`/package-updates/${encodeURIComponent(c.slug)}/apply`, body, cfg, applyTimeoutMs));
|
|
1368
1401
|
s?.stop();
|
|
1369
|
-
if (
|
|
1370
|
-
const
|
|
1402
|
+
if (res?.status === "proposed") {
|
|
1403
|
+
const proposalIds = Array.isArray(res.proposalIds) ? res.proposalIds.map(String) : [];
|
|
1404
|
+
const links = proposalIds.map((id) => approvalLink(cfg.podUrl, id, undefined) ?? `${cfg.podUrl.replace(/\/+$/, "")}/open/${encodeURIComponent(id)}`);
|
|
1371
1405
|
if (!opts.json) {
|
|
1372
|
-
log.info(`${
|
|
1373
|
-
|
|
1374
|
-
log.hint(`
|
|
1406
|
+
log.info(`${c.slug} — update filed for your approval (not applied yet).`);
|
|
1407
|
+
for (const link of links)
|
|
1408
|
+
log.hint(`Approve it: ${link}`);
|
|
1375
1409
|
}
|
|
1376
|
-
return {
|
|
1410
|
+
return {
|
|
1411
|
+
slug: c.slug,
|
|
1412
|
+
outcome: "proposed",
|
|
1413
|
+
status: "proposed",
|
|
1414
|
+
warnings: [],
|
|
1415
|
+
...(proposalIds[0] ? { proposalId: proposalIds[0], proposalIds } : {}),
|
|
1416
|
+
...(links[0] ? { reviewUrl: links[0] } : {}),
|
|
1417
|
+
};
|
|
1377
1418
|
}
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
printApplyVerdict(entry, verdict);
|
|
1392
|
-
printSeedOutcomes(dependencies, seedSummary);
|
|
1393
|
-
printLayerOutcomes(ws?.layers);
|
|
1394
|
-
for (const line of deferredPlacementLines(res))
|
|
1395
|
-
log.info(line);
|
|
1419
|
+
if (res?.status === "applied") {
|
|
1420
|
+
const warning = typeof res.warning === "string" && res.warning ? res.warning : undefined;
|
|
1421
|
+
const receipt = res.receipt;
|
|
1422
|
+
// A field update whose every field stayed yours changed nothing.
|
|
1423
|
+
const unchanged = !!receipt && Array.isArray(receipt.changes) && receipt.changes.length === 0;
|
|
1424
|
+
const status = warning ? "updated-with-failures" : unchanged ? "unchanged" : "updated";
|
|
1425
|
+
if (!opts.json) {
|
|
1426
|
+
if (warning)
|
|
1427
|
+
log.warn(`${c.slug} — updated, not finished: ${warning}`);
|
|
1428
|
+
else
|
|
1429
|
+
log.success(`${c.slug} — ${status}`);
|
|
1430
|
+
}
|
|
1431
|
+
return { slug: c.slug, outcome: status, status, warnings: warning ? [warning] : [] };
|
|
1396
1432
|
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
warnings: verdict.warnings,
|
|
1402
|
-
dependencies,
|
|
1403
|
-
seedSummary,
|
|
1404
|
-
};
|
|
1433
|
+
const error = "the pod answered with a result this CLI can't read — not assuming it updated";
|
|
1434
|
+
if (!opts.json)
|
|
1435
|
+
log.error(`${c.slug} — ${error}`);
|
|
1436
|
+
return { slug: c.slug, outcome: "failed", status: "failed", warnings: [], error };
|
|
1405
1437
|
}
|
|
1406
1438
|
catch (e) {
|
|
1407
1439
|
s?.stop();
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
const
|
|
1411
|
-
if (
|
|
1440
|
+
const refusal = e instanceof HubError ? (e.body ?? {}) : {};
|
|
1441
|
+
const reasonCode = typeof refusal.reasonCode === "string" ? refusal.reasonCode : undefined;
|
|
1442
|
+
const said = e instanceof HubError ? (e.detail ?? e.message) : e instanceof Error ? e.message : String(e);
|
|
1443
|
+
if (reasonCode && NEEDS_THE_PERSON.has(reasonCode)) {
|
|
1444
|
+
return applyInPodAdminResult(c, cfg.podUrl, opts.json, { why: said, reviewUrl: refusal.reviewUrl });
|
|
1445
|
+
}
|
|
1446
|
+
// An older pod refuses an agent's space or capability update here: today's line.
|
|
1447
|
+
if (e instanceof HubError && e.status === 403 && !reasonCode && /\bagent\b/i.test(said)) {
|
|
1448
|
+
return applyInPodAdminResult(c, cfg.podUrl, opts.json);
|
|
1449
|
+
}
|
|
1450
|
+
if (reasonCode === "INVALID_CATALOG_DEFINITION") {
|
|
1451
|
+
const fieldErrors = (refusal.fieldErrors ?? undefined);
|
|
1412
1452
|
if (!opts.json) {
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
for (const hint of said.hints)
|
|
1417
|
-
log.hint(hint);
|
|
1453
|
+
log.error(`${c.slug} not updated — ${said}`);
|
|
1454
|
+
for (const [field, messages] of Object.entries(fieldErrors ?? {}))
|
|
1455
|
+
log.dim(` ${field || "(the definition)"}: ${messages.join("; ")}`);
|
|
1418
1456
|
}
|
|
1419
1457
|
return {
|
|
1420
|
-
slug:
|
|
1421
|
-
outcome: "
|
|
1422
|
-
status: "
|
|
1458
|
+
slug: c.slug,
|
|
1459
|
+
outcome: "failed",
|
|
1460
|
+
status: "failed",
|
|
1423
1461
|
warnings: [],
|
|
1424
|
-
|
|
1462
|
+
error: said,
|
|
1463
|
+
...(fieldErrors ? { fieldErrors } : {}),
|
|
1425
1464
|
};
|
|
1426
1465
|
}
|
|
1427
1466
|
const timedOut = e instanceof HubNetworkError && e.code === "TIMEOUT";
|
|
1428
|
-
const refusal = dataChangeRefusalMessage(e);
|
|
1429
1467
|
if (!opts.json) {
|
|
1430
|
-
log.error(`${
|
|
1431
|
-
|
|
1432
|
-
log.warn(refusal);
|
|
1433
|
-
else
|
|
1434
|
-
renderHubError(e);
|
|
1468
|
+
log.error(`${c.slug} update failed`);
|
|
1469
|
+
renderHubError(e, { personDoor: marketUpdatesDoor(cfg.podUrl) });
|
|
1435
1470
|
}
|
|
1436
1471
|
return {
|
|
1437
|
-
slug:
|
|
1472
|
+
slug: c.slug,
|
|
1438
1473
|
outcome: timedOut ? "timed-out" : "failed",
|
|
1439
1474
|
status: timedOut ? "timed-out" : "failed",
|
|
1440
1475
|
warnings: [],
|
|
1441
|
-
error:
|
|
1476
|
+
error: said,
|
|
1442
1477
|
};
|
|
1443
1478
|
}
|
|
1444
1479
|
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Where the person approves a filed update: pod admin's proposal page, the
|
|
1482
|
+
* approval door (`/proposal/<id>`), when the pod-admin origin derives from the
|
|
1483
|
+
* pod's; else the link the pod sent (`reviewUrl`); else nothing.
|
|
1484
|
+
*/
|
|
1485
|
+
export function approvalLink(podUrl, proposalId, reviewUrl) {
|
|
1486
|
+
const admin = podAdminOrigin(podUrl);
|
|
1487
|
+
if (admin && proposalId)
|
|
1488
|
+
return `${admin}/proposal/${encodeURIComponent(proposalId)}`;
|
|
1489
|
+
return typeof reviewUrl === "string" && reviewUrl.length > 0 ? reviewUrl : undefined;
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
* Where the person applies a package update a limited key may not apply
|
|
1493
|
+
* (a computer key's grant leaves out `workspace.update`, by design: applying a
|
|
1494
|
+
* workspace package is the person's act). Pod admin's Marketplace, Updates
|
|
1495
|
+
* tab, named by URL when the pod-admin origin derives from the pod's.
|
|
1496
|
+
*/
|
|
1497
|
+
export function marketUpdatesDoor(podUrl) {
|
|
1498
|
+
const admin = podAdminOrigin(podUrl);
|
|
1499
|
+
return admin
|
|
1500
|
+
? `Apply it yourself from pod admin → Marketplace → Updates: ${admin}/marketplace/updates`
|
|
1501
|
+
: "Apply it yourself from pod admin → Marketplace → Updates.";
|
|
1502
|
+
}
|
|
1445
1503
|
/**
|
|
1446
1504
|
* Ask the pod's write-free preview door (`POST /packages/preflight`, the same
|
|
1447
1505
|
* body `/packages/apply` takes) which data changes an update would run.
|
|
@@ -1459,76 +1517,30 @@ async function previewDataChanges(entry, cat, cfg) {
|
|
|
1459
1517
|
return { payload, error: `the pod's preview failed: ${status}` };
|
|
1460
1518
|
}
|
|
1461
1519
|
}
|
|
1462
|
-
/** One slug's outcome out of the shared pod-wide config reconcile. */
|
|
1463
|
-
async function reconcileOutcome(c, report, opts) {
|
|
1464
|
-
let r;
|
|
1465
|
-
try {
|
|
1466
|
-
r = await report;
|
|
1467
|
-
}
|
|
1468
|
-
catch (e) {
|
|
1469
|
-
if (!opts.json) {
|
|
1470
|
-
log.error(`${c.slug} update failed`);
|
|
1471
|
-
renderHubError(e);
|
|
1472
|
-
}
|
|
1473
|
-
return { slug: c.slug, outcome: "failed", status: "failed", warnings: [], error: e instanceof Error ? e.message : String(e) };
|
|
1474
|
-
}
|
|
1475
|
-
// A report this CLI cannot read is a FAILED read — never "up to date".
|
|
1476
|
-
const lists = [r?.updated, r?.ownerOwnedSkipped, r?.skipped, r?.conflicts];
|
|
1477
|
-
if (!lists.some(Array.isArray) || lists.some((l) => l !== undefined && !Array.isArray(l))) {
|
|
1478
|
-
const error = "the pod's reconcile answered with a report this CLI can't read — not assuming it updated";
|
|
1479
|
-
if (!opts.json)
|
|
1480
|
-
log.error(`${c.slug} — ${error}`);
|
|
1481
|
-
return { slug: c.slug, outcome: "failed", status: "failed", warnings: [], error };
|
|
1482
|
-
}
|
|
1483
|
-
const mine = (rows) => (rows ?? []).filter((e) => e.packageSlug === c.slug);
|
|
1484
|
-
const conflicts = mine(r.conflicts);
|
|
1485
|
-
const owned = mine(r.ownerOwnedSkipped);
|
|
1486
|
-
const updated = mine(r.updated);
|
|
1487
|
-
const warnings = owned.map((e) => `${e.name}: kept your edits — ${e.reason}`);
|
|
1488
|
-
if (conflicts.length > 0) {
|
|
1489
|
-
const error = conflicts.map((e) => `${e.name}: ${e.reason}`).join("; ");
|
|
1490
|
-
if (!opts.json)
|
|
1491
|
-
log.error(`${c.slug} update failed — ${error}`);
|
|
1492
|
-
return { slug: c.slug, outcome: "failed", status: updated.length > 0 ? "updated-with-failures" : "failed", warnings, error };
|
|
1493
|
-
}
|
|
1494
|
-
if (!opts.json)
|
|
1495
|
-
for (const w of warnings)
|
|
1496
|
-
log.warn(`${c.slug} — ${w}`);
|
|
1497
|
-
if (updated.length > 0 || owned.length > 0) {
|
|
1498
|
-
// Every field it could advance did; a field you edited stays yours (warned above).
|
|
1499
|
-
const status = updated.length > 0 ? "updated" : "unchanged";
|
|
1500
|
-
if (!opts.json)
|
|
1501
|
-
log.success(`${c.slug} — ${status}`);
|
|
1502
|
-
return { slug: c.slug, outcome: status, status, warnings };
|
|
1503
|
-
}
|
|
1504
|
-
// Skipped (cache miss, unresolved definition…) or not reported at all: NOT updated — never "current".
|
|
1505
|
-
const error = mine(r.skipped).map((e) => `${e.name}: ${e.reason}`).join("; ") || "the pod's reconcile did not report this package";
|
|
1506
|
-
if (!opts.json)
|
|
1507
|
-
log.warn(`${c.slug} was not updated — ${error}`);
|
|
1508
|
-
return { slug: c.slug, outcome: "not-updated", status: "not-updated", warnings, error };
|
|
1509
|
-
}
|
|
1510
1520
|
export async function marketUpdate(slugsArg, opts) {
|
|
1511
1521
|
const applyTimeoutMs = parseApplyTimeoutMs(opts.timeout);
|
|
1512
|
-
// STRICT fetch: distinguish "pod unreachable" (transient — don't claim the
|
|
1513
|
-
// pod is empty, that reads as data loss) from "genuinely nothing installed".
|
|
1514
1522
|
const cat = await buildMarketCatalog();
|
|
1515
|
-
|
|
1516
|
-
//
|
|
1517
|
-
//
|
|
1518
|
-
//
|
|
1519
|
-
//
|
|
1520
|
-
|
|
1523
|
+
// THE POD'S ANSWER, never the CLI's: which installed package has an update
|
|
1524
|
+
// is derived once on the pod, for every kind, with one rule (Hub
|
|
1525
|
+
// `GET /package-updates` → `installed[]`), and pod admin's Updates tab reads
|
|
1526
|
+
// the same list. A pod that cannot answer is said out loud, never replaced
|
|
1527
|
+
// by a verdict computed here (that fork is how the CLI said "content
|
|
1528
|
+
// changed" while pod admin said nothing, 2 Nov 2026).
|
|
1529
|
+
let standings;
|
|
1521
1530
|
try {
|
|
1522
|
-
|
|
1523
|
-
installedTemplates = installedRowsToTemplates(inv.rows);
|
|
1524
|
-
degraded = inv.degraded;
|
|
1531
|
+
standings = await fetchPackageStandings(await resolveHubConfig(opts));
|
|
1525
1532
|
}
|
|
1526
1533
|
catch (e) {
|
|
1527
1534
|
// Unreachable ≠ success — a script checking `$?` (or `&&`-chaining) must see
|
|
1528
1535
|
// failure, not exit 0, even though the JSON payload also carries the reason.
|
|
1529
1536
|
process.exitCode = 1;
|
|
1537
|
+
const unavailable = e instanceof StandingsUnavailableError ? e.reason : null;
|
|
1530
1538
|
if (opts.json) {
|
|
1531
|
-
console.log(JSON.stringify({ checks: [], loggedIn: cat.loggedIn, error: "pod-unreachable" }, null, 2));
|
|
1539
|
+
console.log(JSON.stringify({ checks: [], loggedIn: cat.loggedIn, error: unavailable ?? "pod-unreachable" }, null, 2));
|
|
1540
|
+
return;
|
|
1541
|
+
}
|
|
1542
|
+
if (e instanceof StandingsUnavailableError) {
|
|
1543
|
+
log.error(e.message);
|
|
1532
1544
|
return;
|
|
1533
1545
|
}
|
|
1534
1546
|
log.error("Couldn't reach your pod to read what's installed — not saying it's empty.");
|
|
@@ -1536,26 +1548,21 @@ export async function marketUpdate(slugsArg, opts) {
|
|
|
1536
1548
|
log.hint("Check the pod is up / you're on the right --pod, then retry.");
|
|
1537
1549
|
return;
|
|
1538
1550
|
}
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
if (
|
|
1551
|
+
// Kept in the JSON for readers of the older shape: the pod's list covers
|
|
1552
|
+
// every kind, so it is never the workspace-only view of an old pod.
|
|
1553
|
+
const degraded = false;
|
|
1554
|
+
if (standings.length === 0) {
|
|
1543
1555
|
if (opts.json) {
|
|
1544
|
-
console.log(JSON.stringify({ checks: [], loggedIn: cat.loggedIn, degraded
|
|
1556
|
+
console.log(JSON.stringify({ checks: [], loggedIn: cat.loggedIn, degraded }, null, 2));
|
|
1545
1557
|
return;
|
|
1546
1558
|
}
|
|
1547
1559
|
log.warn("No installed packages found on this pod.");
|
|
1548
|
-
if (degradedNote)
|
|
1549
|
-
log.dim(degradedNote);
|
|
1550
1560
|
log.hint("Install one: synap market install <slug>");
|
|
1551
1561
|
return;
|
|
1552
1562
|
}
|
|
1553
|
-
//
|
|
1554
|
-
//
|
|
1555
|
-
|
|
1556
|
-
// `task-views-pack` four times and the "N up to date" tally counted it four
|
|
1557
|
-
// times. `market installed` has always deduped the same way.
|
|
1558
|
-
let checks = dedupeBySlug(computeUpdates(installedTemplates, cat));
|
|
1563
|
+
// One check per slug: the pod answers per package (slug + kind); a slug
|
|
1564
|
+
// installed as two kinds is updated per kind by its own door, but listed once.
|
|
1565
|
+
let checks = dedupeBySlug(checksFromStandings(standings));
|
|
1559
1566
|
const entryBySlug = new Map(cat.entries.map((e) => [e.slug, e]));
|
|
1560
1567
|
const explicitSlugs = !!slugsArg && slugsArg.length > 0;
|
|
1561
1568
|
let unknownSlugs = [];
|
|
@@ -1622,8 +1629,9 @@ export async function marketUpdate(slugsArg, opts) {
|
|
|
1622
1629
|
process.exit(1);
|
|
1623
1630
|
}
|
|
1624
1631
|
for (const c of withUpdates) {
|
|
1625
|
-
//
|
|
1626
|
-
|
|
1632
|
+
// Only a space's update changes existing records: the preview of its
|
|
1633
|
+
// data changes is the template door's (`/packages/preflight`).
|
|
1634
|
+
if ((c.kind ?? "workspace") !== "workspace")
|
|
1627
1635
|
continue;
|
|
1628
1636
|
const entry = entryBySlug.get(c.slug);
|
|
1629
1637
|
if (entry)
|
|
@@ -1663,6 +1671,8 @@ export async function marketUpdate(slugsArg, opts) {
|
|
|
1663
1671
|
}
|
|
1664
1672
|
log.heading(" Installed packages");
|
|
1665
1673
|
log.blank();
|
|
1674
|
+
// The slug column fits the longest slug (capped), with at least 2 spaces after it.
|
|
1675
|
+
const slugW = Math.min(Math.max(28, ...checks.map((c) => c.slug.length + 2)), 46);
|
|
1666
1676
|
for (const c of checks) {
|
|
1667
1677
|
// ONE label door. This was a hand-rolled second copy that diverged from
|
|
1668
1678
|
// `installedStatusLabel` in two ways that both LIED: it had no cache-cold
|
|
@@ -1673,14 +1683,12 @@ export async function marketUpdate(slugsArg, opts) {
|
|
|
1673
1683
|
const label = retiredSlugs.has(c.slug)
|
|
1674
1684
|
? chalk.yellow("retired") + chalk.dim(` · synap templates retire ${c.slug}`)
|
|
1675
1685
|
: installedStatusLabel(c, entryBySlug.get(c.slug)?.isPrivate ?? false, cat.loggedIn);
|
|
1676
|
-
console.log(" " + chalk.cyan(c.slug.padEnd(
|
|
1686
|
+
console.log(" " + chalk.cyan(clip(c.slug, slugW - 2).padEnd(slugW)) + label);
|
|
1677
1687
|
}
|
|
1678
1688
|
log.blank();
|
|
1679
1689
|
if (noVersionInfo.length > 0) {
|
|
1680
1690
|
log.dim(`${noVersionInfo.length} installed without a version stamp — can't check ${noVersionInfo.length === 1 ? "it" : "them"} for updates.`);
|
|
1681
1691
|
}
|
|
1682
|
-
if (degradedNote)
|
|
1683
|
-
log.dim(degradedNote);
|
|
1684
1692
|
}
|
|
1685
1693
|
// What the JSON carries for the new facts: per slug, the pod's data changes
|
|
1686
1694
|
// (`null` = this pod sent none: an older pod) and the template lifecycle.
|
|
@@ -1722,7 +1730,9 @@ export async function marketUpdate(slugsArg, opts) {
|
|
|
1722
1730
|
return;
|
|
1723
1731
|
}
|
|
1724
1732
|
if (!shouldApply) {
|
|
1725
|
-
|
|
1733
|
+
// Every update applies through the pod's one update door, so every one
|
|
1734
|
+
// is offered; what only the person can do is said when it is applied.
|
|
1735
|
+
const steps = FLOW.afterMarketUpdateCheck(cliUpdatableSlugs(withUpdates));
|
|
1726
1736
|
if (opts.json) {
|
|
1727
1737
|
console.log(JSON.stringify({
|
|
1728
1738
|
checks,
|
|
@@ -1744,31 +1754,7 @@ export async function marketUpdate(slugsArg, opts) {
|
|
|
1744
1754
|
}
|
|
1745
1755
|
const acceptList = parseAcceptList(opts.acceptDataChanges);
|
|
1746
1756
|
const results = [];
|
|
1747
|
-
// One pod-wide reconcile serves every view/skill/automation update — run it
|
|
1748
|
-
// at most once, lazily, and read each slug's outcome from its report.
|
|
1749
|
-
let configsReport;
|
|
1750
1757
|
for (const c of withUpdates) {
|
|
1751
|
-
const door = updateDoorFor(c.kind);
|
|
1752
|
-
if (door === null) {
|
|
1753
|
-
if (!opts.json)
|
|
1754
|
-
log.warn(`${c.slug} is a ${c.kind} — the pod has no per-package update for this kind, so it was not updated. Nothing was written.`);
|
|
1755
|
-
results.push({ slug: c.slug, outcome: "no-updater", status: "no-updater", warnings: [] });
|
|
1756
|
-
continue;
|
|
1757
|
-
}
|
|
1758
|
-
if (door === "configs-reconcile") {
|
|
1759
|
-
configsReport ??= hubPost("/configs/reconcile", {}, cfg, applyTimeoutMs);
|
|
1760
|
-
results.push(await reconcileOutcome(c, configsReport, { json: opts.json }));
|
|
1761
|
-
continue;
|
|
1762
|
-
}
|
|
1763
|
-
const entry = entryBySlug.get(c.slug);
|
|
1764
|
-
if (!entry) {
|
|
1765
|
-
// Absent from the catalog THIS CLI read — not proof it left the catalog
|
|
1766
|
-
// (that is the pod's `unlisted`, shown above, and only after a complete sync).
|
|
1767
|
-
if (!opts.json)
|
|
1768
|
-
log.warn(`Couldn't find "${c.slug}" in the catalog read just now — skipping.`);
|
|
1769
|
-
results.push({ slug: c.slug, outcome: "not-in-catalog", status: "not-in-catalog", warnings: [] });
|
|
1770
|
-
continue;
|
|
1771
|
-
}
|
|
1772
1758
|
const pv = previews.get(c.slug);
|
|
1773
1759
|
const pending = pv?.changes ?? [];
|
|
1774
1760
|
let accepted = [];
|
|
@@ -1793,17 +1779,14 @@ export async function marketUpdate(slugsArg, opts) {
|
|
|
1793
1779
|
}
|
|
1794
1780
|
if (missing.length > 0) {
|
|
1795
1781
|
if (!opts.json) {
|
|
1796
|
-
log.warn(`${
|
|
1782
|
+
log.warn(`${c.slug} not updated: you have not agreed to its data changes. Nothing was written.`);
|
|
1797
1783
|
log.hint(`To agree and update: ${consentRerunCommand(c.slug, missing)}`);
|
|
1798
1784
|
}
|
|
1799
1785
|
results.push({ slug: c.slug, outcome: "needs-consent", status: "needs-consent", warnings: [], pendingDataChanges: missing });
|
|
1800
1786
|
continue;
|
|
1801
1787
|
}
|
|
1802
1788
|
}
|
|
1803
|
-
results.push(await
|
|
1804
|
-
payload: pv?.payload,
|
|
1805
|
-
acceptDataChanges: accepted,
|
|
1806
|
-
}));
|
|
1789
|
+
results.push(await applyUpdateThroughDoor(c, cfg, { json: opts.json }, applyTimeoutMs, accepted));
|
|
1807
1790
|
}
|
|
1808
1791
|
if (results.some((r) => r.status === "needs-consent"))
|
|
1809
1792
|
process.exitCode = 1;
|
|
@@ -1827,16 +1810,18 @@ export async function marketUpdate(slugsArg, opts) {
|
|
|
1827
1810
|
renderNextSteps(steps);
|
|
1828
1811
|
}
|
|
1829
1812
|
/**
|
|
1830
|
-
* One-line rollup over a batch of `
|
|
1831
|
-
* the SAME per-item `status`
|
|
1813
|
+
* One-line rollup over a batch of update outcomes (`applyUpdateThroughDoor`) — computed from
|
|
1814
|
+
* the SAME per-item `status` the
|
|
1832
1815
|
* loop already collects, not a separate tally. `"installed"`/`"updated"`/
|
|
1833
1816
|
* `"composed"`/`"legacy-unknown"` count as a clean update, `"unchanged"` as
|
|
1834
1817
|
* already-current, the `*-with-failures` and `"stamp-contradiction"` statuses
|
|
1835
1818
|
* get their OWN bucket — a partial capability-seed failure or a stamp that
|
|
1836
1819
|
* silently didn't take is never folded into a clean "updated" count.
|
|
1837
|
-
* `"timed-out"` is broken out from the generic `"failed"` bucket;
|
|
1838
|
-
*
|
|
1839
|
-
*
|
|
1820
|
+
* `"timed-out"` is broken out from the generic `"failed"` bucket;
|
|
1821
|
+
* `"proposed"`/`"awaiting-approval"` count as waiting for the person's
|
|
1822
|
+
* approval (never failed); everything else
|
|
1823
|
+
* (locked/fetch-failed/not-in-catalog/no-workspace/unknown) rolls into
|
|
1824
|
+
* "failed".
|
|
1840
1825
|
*/
|
|
1841
1826
|
export function summarizeApplyResults(results) {
|
|
1842
1827
|
let updated = 0;
|
|
@@ -1846,6 +1831,7 @@ export function summarizeApplyResults(results) {
|
|
|
1846
1831
|
let failed = 0;
|
|
1847
1832
|
let proposed = 0;
|
|
1848
1833
|
let needsConsent = 0;
|
|
1834
|
+
let toApplyInPodAdmin = 0;
|
|
1849
1835
|
for (const r of results) {
|
|
1850
1836
|
switch (r.status) {
|
|
1851
1837
|
case "installed":
|
|
@@ -1880,17 +1866,23 @@ export function summarizeApplyResults(results) {
|
|
|
1880
1866
|
case "needs-consent":
|
|
1881
1867
|
needsConsent++;
|
|
1882
1868
|
break;
|
|
1869
|
+
// The person's act (pod admin → Marketplace → Updates): nothing failed.
|
|
1870
|
+
case APPLY_IN_POD_ADMIN:
|
|
1871
|
+
toApplyInPodAdmin++;
|
|
1872
|
+
break;
|
|
1883
1873
|
default:
|
|
1884
1874
|
failed++;
|
|
1885
1875
|
}
|
|
1886
1876
|
}
|
|
1887
1877
|
const parts = [`${updated} updated`, `${unchanged} already current`];
|
|
1888
1878
|
if (proposed > 0)
|
|
1889
|
-
parts.push(`${proposed}
|
|
1879
|
+
parts.push(`${proposed} waiting for your approval`);
|
|
1890
1880
|
// The vocabulary's `unfinished` ("Not finished"): one state, one name on
|
|
1891
1881
|
// every surface — never "completed with failures" (review2 UX §1 #2).
|
|
1892
1882
|
if (withFailures > 0)
|
|
1893
1883
|
parts.push(`${withFailures} ${templateStepPhrase("unfinished")}`);
|
|
1884
|
+
if (toApplyInPodAdmin > 0)
|
|
1885
|
+
parts.push(`${toApplyInPodAdmin} to apply in pod admin`);
|
|
1894
1886
|
if (failed > 0)
|
|
1895
1887
|
parts.push(`${failed} failed`);
|
|
1896
1888
|
if (timedOut > 0)
|
|
@@ -1899,9 +1891,9 @@ export function summarizeApplyResults(results) {
|
|
|
1899
1891
|
parts.push(`${needsConsent} waiting for your agreement to data changes`);
|
|
1900
1892
|
const clean = withFailures === 0 && failed === 0 && timedOut === 0 && needsConsent === 0;
|
|
1901
1893
|
// Proposed isn't a failure (never ⚠) but isn't live yet (not a bare ✓) —
|
|
1902
|
-
// a distinct "→
|
|
1903
|
-
const marker = !clean ? "⚠" : proposed > 0 ? "→" : "✓";
|
|
1904
|
-
const color = !clean ? chalk.yellow : proposed > 0 ? chalk.cyan : chalk.green;
|
|
1894
|
+
// a distinct "→ waiting for your approval" marker keeps the summary honest.
|
|
1895
|
+
const marker = !clean ? "⚠" : proposed > 0 || toApplyInPodAdmin > 0 ? "→" : "✓";
|
|
1896
|
+
const color = !clean ? chalk.yellow : proposed > 0 || toApplyInPodAdmin > 0 ? chalk.cyan : chalk.green;
|
|
1905
1897
|
return {
|
|
1906
1898
|
updated,
|
|
1907
1899
|
unchanged,
|
|
@@ -1910,6 +1902,7 @@ export function summarizeApplyResults(results) {
|
|
|
1910
1902
|
timedOut,
|
|
1911
1903
|
proposed,
|
|
1912
1904
|
needsConsent,
|
|
1905
|
+
toApplyInPodAdmin,
|
|
1913
1906
|
line: color(`${marker} ${parts.join(" · ")}`),
|
|
1914
1907
|
};
|
|
1915
1908
|
}
|
|
@@ -2389,7 +2382,7 @@ export async function marketInstalled(opts) {
|
|
|
2389
2382
|
const entryBySlug = new Map(cat.entries.map((e) => [e.slug, e]));
|
|
2390
2383
|
if (opts.layers) {
|
|
2391
2384
|
const graph = await buildInstallationGraph(installedTemplates, cat, checks);
|
|
2392
|
-
const steps = FLOW.afterMarketInstalledCheck(rows
|
|
2385
|
+
const steps = FLOW.afterMarketInstalledCheck(cliUpdatableSlugs(rows));
|
|
2393
2386
|
if (opts.json) {
|
|
2394
2387
|
console.log(JSON.stringify({
|
|
2395
2388
|
nodes: [...graph.nodes.values()],
|
|
@@ -2416,7 +2409,7 @@ export async function marketInstalled(opts) {
|
|
|
2416
2409
|
}
|
|
2417
2410
|
if (opts.tree) {
|
|
2418
2411
|
const { packages, leafRows } = await buildCompositionTrees(rows, cat, installedTemplates, workspaceCountBySlug);
|
|
2419
|
-
const steps = FLOW.afterMarketInstalledCheck(rows
|
|
2412
|
+
const steps = FLOW.afterMarketInstalledCheck(cliUpdatableSlugs(rows));
|
|
2420
2413
|
if (opts.json) {
|
|
2421
2414
|
console.log(JSON.stringify({
|
|
2422
2415
|
packages,
|
|
@@ -2476,7 +2469,7 @@ export async function marketInstalled(opts) {
|
|
|
2476
2469
|
return;
|
|
2477
2470
|
}
|
|
2478
2471
|
if (opts.json) {
|
|
2479
|
-
const steps = FLOW.afterMarketInstalledCheck(rows
|
|
2472
|
+
const steps = FLOW.afterMarketInstalledCheck(cliUpdatableSlugs(rows));
|
|
2480
2473
|
console.log(JSON.stringify({
|
|
2481
2474
|
rows: rows.map((c) => {
|
|
2482
2475
|
const entry = entryBySlug.get(c.slug);
|
|
@@ -2594,7 +2587,7 @@ export async function marketInstalled(opts) {
|
|
|
2594
2587
|
log.dim(degradedNote);
|
|
2595
2588
|
if (!cat.loggedIn)
|
|
2596
2589
|
log.dim("Not logged in — private template updates aren't visible. Run: synap login");
|
|
2597
|
-
renderNextSteps(FLOW.afterMarketInstalledCheck(rows
|
|
2590
|
+
renderNextSteps(FLOW.afterMarketInstalledCheck(cliUpdatableSlugs(rows)));
|
|
2598
2591
|
}
|
|
2599
2592
|
/** Classify one workspace's attachment, reusing `computeUpdates`' drift verdict for the stamped case. */
|
|
2600
2593
|
function classifyAttachment(ws, check) {
|