@tacuchi/agent-workflow-cli 22.4.2 → 24.0.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/README.md +39 -3
- package/dist/adapters/git-cli.js +59 -17
- package/dist/adapters/git-cli.js.map +1 -1
- package/dist/adapters/node-file-system.js +55 -1
- package/dist/adapters/node-file-system.js.map +1 -1
- package/dist/adapters/postgres-readonly-tools.js +277 -0
- package/dist/adapters/postgres-readonly-tools.js.map +1 -0
- package/dist/application/artifacts-service.js +2 -2
- package/dist/application/artifacts-service.js.map +1 -1
- package/dist/application/capability/dispatcher.js +2 -2
- package/dist/application/capability/dispatcher.js.map +1 -1
- package/dist/application/capability/installed-inventory.js +2 -2
- package/dist/application/capability/installed-inventory.js.map +1 -1
- package/dist/application/capability/readiness.js +1 -1
- package/dist/application/capability/readiness.js.map +1 -1
- package/dist/application/check-branch-service.js +2 -2
- package/dist/application/check-branch-service.js.map +1 -1
- package/dist/application/checkpoint/files-touched.js +271 -0
- package/dist/application/checkpoint/files-touched.js.map +1 -0
- package/dist/application/checkpoint/markdown.js +61 -8
- package/dist/application/checkpoint/markdown.js.map +1 -1
- package/dist/application/checkpoint/state-reader.js +8 -2
- package/dist/application/checkpoint/state-reader.js.map +1 -1
- package/dist/application/checkpoint-write-service.js +16 -5
- package/dist/application/checkpoint-write-service.js.map +1 -1
- package/dist/application/claims-ledger.js +330 -0
- package/dist/application/claims-ledger.js.map +1 -0
- package/dist/application/claims-recovery.js +338 -0
- package/dist/application/claims-recovery.js.map +1 -0
- package/dist/application/database-mcp-server.js +168 -0
- package/dist/application/database-mcp-server.js.map +1 -0
- package/dist/application/database-mcp-stdio.js +137 -0
- package/dist/application/database-mcp-stdio.js.map +1 -0
- package/dist/application/database-tool-catalog.js +226 -0
- package/dist/application/database-tool-catalog.js.map +1 -0
- package/dist/application/dev-only-services.js +154 -44
- package/dist/application/dev-only-services.js.map +1 -1
- package/dist/application/dsn-reader-service.js +1 -1
- package/dist/application/elicitation-server.js +382 -0
- package/dist/application/elicitation-server.js.map +1 -0
- package/dist/application/elicitation-stdio.js +48 -0
- package/dist/application/elicitation-stdio.js.map +1 -0
- package/dist/application/flow/advance.js +86 -5
- package/dist/application/flow/advance.js.map +1 -1
- package/dist/application/flow/checkout-observation.js +152 -0
- package/dist/application/flow/checkout-observation.js.map +1 -0
- package/dist/application/flow/flow-service.js +72 -13
- package/dist/application/flow/flow-service.js.map +1 -1
- package/dist/application/flow/internal-actions.js +460 -1
- package/dist/application/flow/internal-actions.js.map +1 -1
- package/dist/application/flow/internal-drive.js +22 -9
- package/dist/application/flow/internal-drive.js.map +1 -1
- package/dist/application/flow/prove.js +205 -0
- package/dist/application/flow/prove.js.map +1 -0
- package/dist/application/flow/run-journey.js +15 -0
- package/dist/application/flow/run-journey.js.map +1 -0
- package/dist/application/flow/run-projection.js +15 -3
- package/dist/application/flow/run-projection.js.map +1 -1
- package/dist/application/flow/run-state-service.js +19 -4
- package/dist/application/flow/run-state-service.js.map +1 -1
- package/dist/application/flow/submit.js +250 -72
- package/dist/application/flow/submit.js.map +1 -1
- package/dist/application/generate-launch-service.js +4 -4
- package/dist/application/generate-launch-service.js.map +1 -1
- package/dist/application/git-flow-service.js +9 -0
- package/dist/application/git-flow-service.js.map +1 -1
- package/dist/application/local-proposal.js +9 -0
- package/dist/application/local-proposal.js.map +1 -1
- package/dist/application/lock-service.js +96 -28
- package/dist/application/lock-service.js.map +1 -1
- package/dist/application/logging/log-events.js +19 -3
- package/dist/application/logging/log-events.js.map +1 -1
- package/dist/application/logging/logger.js +2 -2
- package/dist/application/logging/logger.js.map +1 -1
- package/dist/application/mcp-connections-service.js +115 -41
- package/dist/application/mcp-connections-service.js.map +1 -1
- package/dist/application/mcp-doctor-service.js +98 -54
- package/dist/application/mcp-doctor-service.js.map +1 -1
- package/dist/application/mcp-entry-classification.js +60 -0
- package/dist/application/mcp-entry-classification.js.map +1 -0
- package/dist/application/mcp-host-reader.js +114 -81
- package/dist/application/mcp-host-reader.js.map +1 -1
- package/dist/application/mcp-host-receipt-service.js +399 -0
- package/dist/application/mcp-host-receipt-service.js.map +1 -0
- package/dist/application/mcp-host-receipt-store.js +122 -0
- package/dist/application/mcp-host-receipt-store.js.map +1 -0
- package/dist/application/mcp-host-receipts.js +28 -0
- package/dist/application/mcp-host-receipts.js.map +1 -0
- package/dist/application/mcp-host-writer.js +321 -126
- package/dist/application/mcp-host-writer.js.map +1 -1
- package/dist/application/mcp-launch-probe-service.js +142 -0
- package/dist/application/mcp-launch-probe-service.js.map +1 -0
- package/dist/application/mcp-migration-service.js +351 -0
- package/dist/application/mcp-migration-service.js.map +1 -0
- package/dist/application/mcp-native-host-check-service.js +154 -0
- package/dist/application/mcp-native-host-check-service.js.map +1 -0
- package/dist/application/mcp-receipt-registration-service.js +105 -0
- package/dist/application/mcp-receipt-registration-service.js.map +1 -0
- package/dist/application/mcp-receipt-removal-service.js +62 -0
- package/dist/application/mcp-receipt-removal-service.js.map +1 -0
- package/dist/application/mcp-remove-service.js +84 -21
- package/dist/application/mcp-remove-service.js.map +1 -1
- package/dist/application/mcp-scope-common.js +2 -4
- package/dist/application/mcp-scope-common.js.map +1 -1
- package/dist/application/mcp-setup-service.js +60 -21
- package/dist/application/mcp-setup-service.js.map +1 -1
- package/dist/application/mcp-stdio-probe.js +526 -0
- package/dist/application/mcp-stdio-probe.js.map +1 -0
- package/dist/application/mcp-test-connection-service.js +23 -50
- package/dist/application/mcp-test-connection-service.js.map +1 -1
- package/dist/application/merge-state-service.js +10 -16
- package/dist/application/merge-state-service.js.map +1 -1
- package/dist/application/multiroot/claude.js +34 -15
- package/dist/application/multiroot/claude.js.map +1 -1
- package/dist/application/multiroot/codex.js +9 -5
- package/dist/application/multiroot/codex.js.map +1 -1
- package/dist/application/multiroot-service.js +20 -11
- package/dist/application/multiroot-service.js.map +1 -1
- package/dist/application/parsers/project-block.js +25 -2
- package/dist/application/parsers/project-block.js.map +1 -1
- package/dist/application/paths-service.js +30 -31
- package/dist/application/paths-service.js.map +1 -1
- package/dist/application/plan-exec-batch-service.js +549 -0
- package/dist/application/plan-exec-batch-service.js.map +1 -0
- package/dist/application/plan-exec-decision-service.js +273 -0
- package/dist/application/plan-exec-decision-service.js.map +1 -0
- package/dist/application/project-md-service.js +2 -2
- package/dist/application/project-md-service.js.map +1 -1
- package/dist/application/project-md-upsert-service.js +4 -4
- package/dist/application/project-md-upsert-service.js.map +1 -1
- package/dist/application/project-tab-data.js +12 -7
- package/dist/application/project-tab-data.js.map +1 -1
- package/dist/application/release-data-service.js +2 -2
- package/dist/application/release-data-service.js.map +1 -1
- package/dist/application/resume-service.js +32 -11
- package/dist/application/resume-service.js.map +1 -1
- package/dist/application/retirement/apply.js +84 -0
- package/dist/application/retirement/apply.js.map +1 -1
- package/dist/application/retirement/attribution.js +31 -1
- package/dist/application/retirement/attribution.js.map +1 -1
- package/dist/application/retirement/graph.js +19 -1
- package/dist/application/retirement/graph.js.map +1 -1
- package/dist/application/retirement/journal.js +11 -0
- package/dist/application/retirement/journal.js.map +1 -1
- package/dist/application/retirement/prepare.js +89 -3
- package/dist/application/retirement/prepare.js.map +1 -1
- package/dist/application/retirement/preview.js +16 -0
- package/dist/application/retirement/preview.js.map +1 -1
- package/dist/application/retirement/resolve.js +65 -0
- package/dist/application/retirement/resolve.js.map +1 -1
- package/dist/application/self/host-states.js +2 -0
- package/dist/application/self/host-states.js.map +1 -1
- package/dist/application/self/install-skill.js +21 -17
- package/dist/application/self/install-skill.js.map +1 -1
- package/dist/application/self/mcp-config.js +392 -84
- package/dist/application/self/mcp-config.js.map +1 -1
- package/dist/application/self/mcp-via-state.js +62 -0
- package/dist/application/self/mcp-via-state.js.map +1 -0
- package/dist/application/self/uninstall.js +15 -5
- package/dist/application/self/uninstall.js.map +1 -1
- package/dist/application/session-close-service.js +24 -1
- package/dist/application/session-close-service.js.map +1 -1
- package/dist/application/session-create-service.js +7 -0
- package/dist/application/session-create-service.js.map +1 -1
- package/dist/application/session-resume-service.js +2 -2
- package/dist/application/session-resume-service.js.map +1 -1
- package/dist/application/sessions-service.js +2 -4
- package/dist/application/sessions-service.js.map +1 -1
- package/dist/application/skills-resolver-service.js +4 -4
- package/dist/application/skills-resolver-service.js.map +1 -1
- package/dist/application/source-boundary-policy.js +18 -7
- package/dist/application/source-boundary-policy.js.map +1 -1
- package/dist/application/source-remove-service.js +12 -1
- package/dist/application/source-remove-service.js.map +1 -1
- package/dist/application/sources-service.js +2 -2
- package/dist/application/sources-service.js.map +1 -1
- package/dist/application/status-service.js +4 -0
- package/dist/application/status-service.js.map +1 -1
- package/dist/application/visibility-doctor-service.js +1 -1
- package/dist/application/visibility-doctor-service.js.map +1 -1
- package/dist/application/workline-index-service.js +182 -27
- package/dist/application/workline-index-service.js.map +1 -1
- package/dist/application/workspace-init-service.js +89 -271
- package/dist/application/workspace-init-service.js.map +1 -1
- package/dist/application/workspace-materialization-service.js +300 -0
- package/dist/application/workspace-materialization-service.js.map +1 -0
- package/dist/application/worktree-service.js +32 -3
- package/dist/application/worktree-service.js.map +1 -1
- package/dist/cli/commands/capability.js +4 -7
- package/dist/cli/commands/capability.js.map +1 -1
- package/dist/cli/commands/claims.js +72 -0
- package/dist/cli/commands/claims.js.map +1 -0
- package/dist/cli/commands/dev-only.js +73 -25
- package/dist/cli/commands/dev-only.js.map +1 -1
- package/dist/cli/commands/flow.js +145 -42
- package/dist/cli/commands/flow.js.map +1 -1
- package/dist/cli/commands/index.js +4 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/mcp.js +752 -76
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/multiroot.js +40 -7
- package/dist/cli/commands/multiroot.js.map +1 -1
- package/dist/cli/commands/resume.js +9 -3
- package/dist/cli/commands/resume.js.map +1 -1
- package/dist/cli/commands/retirement.js +9 -0
- package/dist/cli/commands/retirement.js.map +1 -1
- package/dist/cli/commands/session-create.js +1 -1
- package/dist/cli/commands/session-create.js.map +1 -1
- package/dist/cli/commands/skills.js +1 -1
- package/dist/cli/commands/skills.js.map +1 -1
- package/dist/cli/commands/status.js +72 -24
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/tool.js +141 -0
- package/dist/cli/commands/tool.js.map +1 -0
- package/dist/cli/commands/workspace-init.js +5 -5
- package/dist/cli/commands/workspace-init.js.map +1 -1
- package/dist/cli/help-groups.js +6 -1
- package/dist/cli/help-groups.js.map +1 -1
- package/dist/cli/main.js +272 -67
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/parser.js +8 -1
- package/dist/cli/parser.js.map +1 -1
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli/render.js +15 -2
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/tui/app.js +3 -2
- package/dist/cli/tui/app.js.map +1 -1
- package/dist/cli/tui/components/workspace-init-form.js +7 -7
- package/dist/cli/tui/components/workspace-init-form.js.map +1 -1
- package/dist/cli/tui/data/workflow-content.js +2 -2
- package/dist/cli/tui/data/workflow-content.js.map +1 -1
- package/dist/cli/tui/tabs/config-tab.js +4 -3
- package/dist/cli/tui/tabs/config-tab.js.map +1 -1
- package/dist/cli/tui/tabs/mcp-tab-helpers.js +72 -1
- package/dist/cli/tui/tabs/mcp-tab-helpers.js.map +1 -1
- package/dist/cli/tui/tabs/mcp-tab.js +101 -42
- package/dist/cli/tui/tabs/mcp-tab.js.map +1 -1
- package/dist/cli/tui/tabs/project-tab.js +18 -21
- package/dist/cli/tui/tabs/project-tab.js.map +1 -1
- package/dist/cli/tui/workspace-root.js +13 -0
- package/dist/cli/tui/workspace-root.js.map +1 -0
- package/dist/domain/capability/protocol.js +2 -2
- package/dist/domain/capability/protocol.js.map +1 -1
- package/dist/domain/database-tools.js +445 -0
- package/dist/domain/database-tools.js.map +1 -0
- package/dist/domain/degradation-notice.js +60 -0
- package/dist/domain/degradation-notice.js.map +1 -0
- package/dist/domain/elicitation.js +152 -0
- package/dist/domain/elicitation.js.map +1 -0
- package/dist/domain/flow/answer.js +173 -42
- package/dist/domain/flow/answer.js.map +1 -1
- package/dist/domain/flow/authority.js +184 -127
- package/dist/domain/flow/authority.js.map +1 -1
- package/dist/domain/flow/directive.js +47 -1
- package/dist/domain/flow/directive.js.map +1 -1
- package/dist/domain/flow/rules.js +7 -4
- package/dist/domain/flow/rules.js.map +1 -1
- package/dist/domain/flow/run-state.js +636 -31
- package/dist/domain/flow/run-state.js.map +1 -1
- package/dist/domain/harnesses.js +16 -0
- package/dist/domain/harnesses.js.map +1 -1
- package/dist/domain/mcp-entry.js +164 -28
- package/dist/domain/mcp-entry.js.map +1 -1
- package/dist/domain/postgres-object-search.js +320 -0
- package/dist/domain/postgres-object-search.js.map +1 -0
- package/dist/domain/redaction.js +47 -0
- package/dist/domain/redaction.js.map +1 -0
- package/dist/domain/retirement/proposal.js +1 -0
- package/dist/domain/retirement/proposal.js.map +1 -1
- package/dist/domain/structured-choice-stamp.js +32 -4
- package/dist/domain/structured-choice-stamp.js.map +1 -1
- package/dist/domain/workline-mcp-entry.js +34 -0
- package/dist/domain/workline-mcp-entry.js.map +1 -0
- package/dist/ports/postgres-tools.js +10 -0
- package/dist/ports/postgres-tools.js.map +1 -0
- package/dist/runtime/namespace-resolver.js +104 -18
- package/dist/runtime/namespace-resolver.js.map +1 -1
- package/package.json +5 -1
- package/skills/w/README.md +2 -2
- package/skills/w/SKILL.md +9 -10
- package/skills/w/artifacts/README.md +1 -1
- package/skills/w/commands/README.md +3 -3
- package/skills/w/commands/persist.md +3 -1
- package/skills/w/commands/resume.md +1 -1
- package/skills/w/commands/spec-new.md +2 -2
- package/skills/w/commands/status.md +1 -1
- package/skills/w/commands/workspace-init.md +9 -10
- package/skills/w/context/MANIFEST.json +1 -4
- package/skills/w/harness/HARNESS.md +1 -1
- package/skills/w/loops/quick-loop/LOOP.md +1 -1
- package/skills/w/modules/PROMPT-CONTINUITY.md +1 -1
- package/skills/w/modules/WORKSPACE-SCAFFOLD.md +17 -20
- package/skills/w/schemas/capability-descriptor.schema.json +1 -1
- package/dist/application/mcp-dbhub-launcher.js +0 -216
- package/dist/application/mcp-dbhub-launcher.js.map +0 -1
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { MCP_FILE_HOSTS, harnessForMcpHost } from "../../domain/harnesses.js";
|
|
3
|
-
import { buildMcpEntry,
|
|
3
|
+
import { buildMcpEntry, mcpEntryNameFor, normalizeDsnVarName, validateDsnVarName, validateMcpInstance, } from "../../domain/mcp-entry.js";
|
|
4
4
|
import { dsnKeyForInstance, readDsnFile } from "../dsn-reader-service.js";
|
|
5
|
-
import { deleteMcpConnection, readMcpConnections, upsertMcpConnection, } from "../mcp-connections-service.js";
|
|
5
|
+
import { McpConnectionsError, deleteMcpConnection, readMcpConnections, upsertMcpConnection, } from "../mcp-connections-service.js";
|
|
6
6
|
import { runMcpDoctor } from "../mcp-doctor-service.js";
|
|
7
|
+
import { classifyMcpEntry } from "../mcp-entry-classification.js";
|
|
7
8
|
import { readMcpEntry } from "../mcp-host-reader.js";
|
|
9
|
+
import { McpHostReceiptError, digestMcpReceiptDescriptor, parseMcpHostReceiptBook, } from "../mcp-host-receipt-service.js";
|
|
10
|
+
import { mcpHostReceiptFile } from "../mcp-host-receipt-store.js";
|
|
11
|
+
import { probePersistedMcpSetupEntries } from "../mcp-launch-probe-service.js";
|
|
12
|
+
import { checkNativeMcpHosts, recordNativeMcpHostChecks, } from "../mcp-native-host-check-service.js";
|
|
13
|
+
import { registerMcpSetupReceipts } from "../mcp-receipt-registration-service.js";
|
|
14
|
+
import { removeMcpRemoveReceipts } from "../mcp-receipt-removal-service.js";
|
|
8
15
|
import { runMcpRemove } from "../mcp-remove-service.js";
|
|
9
16
|
import { runMcpSetup } from "../mcp-setup-service.js";
|
|
10
17
|
import { buildWarpPostInstallHint, } from "../mcp-warp-postinstall-hint.js";
|
|
@@ -33,26 +40,39 @@ function isPromptSeparator(choice) {
|
|
|
33
40
|
export async function selfMcpConfig(args, ctx, prompts) {
|
|
34
41
|
const prompt = prompts ?? (await loadPrompts());
|
|
35
42
|
const resolved = await resolveAction(args, prompt);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
43
|
+
try {
|
|
44
|
+
switch (resolved.action) {
|
|
45
|
+
case "list":
|
|
46
|
+
return resolved.fromArgs
|
|
47
|
+
? listConnections(ctx)
|
|
48
|
+
: await listConnectionsMenu(args, ctx, prompt);
|
|
49
|
+
case "use-env":
|
|
50
|
+
return await useExistingDsnVar(args, ctx, prompt);
|
|
51
|
+
case "create-env":
|
|
52
|
+
return await createDsnEnvHelp(args, prompt);
|
|
53
|
+
case "cancel":
|
|
54
|
+
return {
|
|
55
|
+
ok: true,
|
|
56
|
+
data: { action: "cancel", connection: null, summary: "Operación cancelada." },
|
|
57
|
+
exitCode: 0,
|
|
58
|
+
};
|
|
59
|
+
default:
|
|
60
|
+
// install-<host> | doctor | remove — all operate on a registered connection.
|
|
61
|
+
return await runConnectionAction(args, ctx, prompt, resolved.action);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error instanceof McpConnectionsError) {
|
|
66
|
+
return invalidRegistryResult(resolved.action, mcpRegistryIssue(ctx));
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
52
69
|
}
|
|
53
70
|
}
|
|
54
71
|
function listConnections(ctx) {
|
|
55
|
-
const
|
|
72
|
+
const views = connectionViews(ctx);
|
|
73
|
+
if (views.kind === "invalid")
|
|
74
|
+
return invalidRegistryResult("list", views.issue);
|
|
75
|
+
const { connections } = views;
|
|
56
76
|
return {
|
|
57
77
|
ok: true,
|
|
58
78
|
data: {
|
|
@@ -68,7 +88,10 @@ function listConnections(ctx) {
|
|
|
68
88
|
};
|
|
69
89
|
}
|
|
70
90
|
async function listConnectionsMenu(args, ctx, prompts) {
|
|
71
|
-
const
|
|
91
|
+
const views = connectionViews(ctx);
|
|
92
|
+
if (views.kind === "invalid")
|
|
93
|
+
return invalidRegistryResult("list", views.issue);
|
|
94
|
+
const { connections } = views;
|
|
72
95
|
if (connections.length === 0) {
|
|
73
96
|
return {
|
|
74
97
|
ok: true,
|
|
@@ -86,7 +109,7 @@ async function listConnectionsMenu(args, ctx, prompts) {
|
|
|
86
109
|
message: formatConnectionsBlock(connections),
|
|
87
110
|
default: "install-claude",
|
|
88
111
|
choices: [
|
|
89
|
-
{ type: "separator", separator: "── Instalar /
|
|
112
|
+
{ type: "separator", separator: "── Instalar / Reinstalar ──" },
|
|
90
113
|
...FILE_HOSTS.map((h) => ({
|
|
91
114
|
name: `▸ ${hostLabel(h)}`,
|
|
92
115
|
value: `install-${h}`,
|
|
@@ -136,15 +159,19 @@ async function useExistingDsnVar(args, ctx, prompts) {
|
|
|
136
159
|
const connection = connectionView(ctx, {
|
|
137
160
|
name: write.connection.name,
|
|
138
161
|
dsnVar: write.connection.dsnVar,
|
|
162
|
+
provider: write.connection.provider,
|
|
139
163
|
dsnPresent: true,
|
|
140
164
|
});
|
|
165
|
+
const views = connectionViews(ctx);
|
|
166
|
+
if (views.kind === "invalid")
|
|
167
|
+
return invalidRegistryResult("use-env", views.issue);
|
|
141
168
|
return {
|
|
142
169
|
ok: true,
|
|
143
170
|
data: {
|
|
144
171
|
action: "use-env",
|
|
145
172
|
connection,
|
|
146
|
-
connections:
|
|
147
|
-
table: formatConnectionsTable(
|
|
173
|
+
connections: views.connections,
|
|
174
|
+
table: formatConnectionsTable(views.connections),
|
|
148
175
|
registry: { path: write.path, changed: true },
|
|
149
176
|
summary: `Conexión '${connection.nombre}' registrada con ${connection.dsn_var}.`,
|
|
150
177
|
},
|
|
@@ -166,8 +193,10 @@ async function createDsnEnvHelp(args, prompts) {
|
|
|
166
193
|
};
|
|
167
194
|
}
|
|
168
195
|
async function runConnectionAction(args, ctx, prompts, action) {
|
|
169
|
-
const
|
|
170
|
-
if (
|
|
196
|
+
const resolved = await resolveRegisteredConnection(args, ctx, prompts);
|
|
197
|
+
if (resolved.kind === "invalid")
|
|
198
|
+
return invalidRegistryResult(action, resolved.issue);
|
|
199
|
+
if (resolved.kind === "none") {
|
|
171
200
|
return {
|
|
172
201
|
ok: false,
|
|
173
202
|
error: {
|
|
@@ -178,6 +207,7 @@ async function runConnectionAction(args, ctx, prompts, action) {
|
|
|
178
207
|
exitCode: 1,
|
|
179
208
|
};
|
|
180
209
|
}
|
|
210
|
+
const { connection } = resolved;
|
|
181
211
|
switch (action) {
|
|
182
212
|
case "doctor":
|
|
183
213
|
return doctorConnection(ctx, connection);
|
|
@@ -188,48 +218,96 @@ async function runConnectionAction(args, ctx, prompts, action) {
|
|
|
188
218
|
return installConnection(args, ctx, connection, action.slice("install-".length));
|
|
189
219
|
}
|
|
190
220
|
}
|
|
191
|
-
function installConnection(args, ctx, connection, host) {
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
const
|
|
221
|
+
async function installConnection(args, ctx, connection, host) {
|
|
222
|
+
// The explicit install action (CLI/TUI) carries its own narrow global consent;
|
|
223
|
+
// it is not the public broad `--force` escape hatch.
|
|
224
|
+
const setupInput = {
|
|
195
225
|
hosts: [host],
|
|
196
226
|
connections: [connection],
|
|
227
|
+
namespace: ctx.paths.namespace,
|
|
197
228
|
scope: "global",
|
|
198
|
-
|
|
229
|
+
globalApproval: "explicit-self-action",
|
|
199
230
|
dryRun: args.flags.has("--dry-run"),
|
|
200
|
-
}
|
|
231
|
+
};
|
|
232
|
+
const setup = await runGlobalSetupWithEvidence(ctx, setupInput);
|
|
201
233
|
if ("ok" in setup)
|
|
202
234
|
return refusal(hostAction(host), connectionView(ctx, connection), setup.hint);
|
|
203
235
|
const doctor = runDoctor(ctx, connection, [host]);
|
|
204
|
-
const
|
|
236
|
+
const hasProblems = setup.errors.length > 0 || setup.conflicts.length > 0;
|
|
237
|
+
const views = connectionViews(ctx);
|
|
238
|
+
if (views.kind === "invalid")
|
|
239
|
+
return invalidRegistryResult(hostAction(host), views.issue);
|
|
205
240
|
// The hint cites the file actually written (per-platform global path).
|
|
206
241
|
const warpTarget = [...setup.applied, ...setup.skipped].find((r) => r.host === "warp")?.target;
|
|
207
|
-
const warpHint = host === "warp" && !
|
|
242
|
+
const warpHint = host === "warp" && !hasProblems && warpTarget
|
|
208
243
|
? buildWarpPostInstallHint(mcpEntryNameFor(connection.name), "global", warpTarget)
|
|
209
244
|
: undefined;
|
|
210
245
|
return {
|
|
211
|
-
ok: !
|
|
246
|
+
ok: !hasProblems,
|
|
212
247
|
data: {
|
|
213
248
|
action: hostAction(host),
|
|
214
249
|
connection: connectionView(ctx, connection),
|
|
215
|
-
connections:
|
|
216
|
-
table: formatConnectionsTable(
|
|
250
|
+
connections: views.connections,
|
|
251
|
+
table: formatConnectionsTable(views.connections),
|
|
217
252
|
setup,
|
|
218
253
|
doctor,
|
|
219
254
|
...(warpHint ? { warp_hint: warpHint } : {}),
|
|
220
255
|
summary: warpHint
|
|
221
256
|
? `Conexión '${connection.name}' escrita en ${warpHint.file}. Activá 'File-based MCP Servers' en Warp Settings para que la spawnee.`
|
|
222
|
-
: `Conexión '${connection.name}' instalada
|
|
257
|
+
: `Conexión '${connection.name}' instalada en ${hostLabel(host)}.`,
|
|
223
258
|
},
|
|
224
|
-
...(
|
|
259
|
+
...(hasProblems
|
|
225
260
|
? {
|
|
226
261
|
error: {
|
|
227
262
|
code: "MCP_SETUP_PARTIAL",
|
|
228
|
-
message: `${setup.errors.length} error(es) durante setup; ver data.setup.errors`,
|
|
263
|
+
message: `${setup.errors.length} error(es) y ${setup.conflicts.length} conflicto(s) durante setup; ver data.setup.errors y data.setup.conflicts`,
|
|
229
264
|
},
|
|
230
265
|
}
|
|
231
266
|
: {}),
|
|
232
|
-
exitCode:
|
|
267
|
+
exitCode: hasProblems ? 1 : 0,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* The self wizard writes user-scope descriptors, so it must finish the same
|
|
272
|
+
* durable lifecycle as `mcp setup --global`: receipt, exact persisted launch
|
|
273
|
+
* probe, then native host visibility. Keeping that sequence behind one local
|
|
274
|
+
* boundary prevents a future wizard branch from treating a file write as host
|
|
275
|
+
* readiness.
|
|
276
|
+
*/
|
|
277
|
+
async function runGlobalSetupWithEvidence(ctx, input) {
|
|
278
|
+
const setup = runMcpSetup(ctx.env, input);
|
|
279
|
+
if ("ok" in setup)
|
|
280
|
+
return setup;
|
|
281
|
+
const receiptRegistration = await registerMcpSetupReceipts(ctx.paths, input, setup);
|
|
282
|
+
const withReceipts = {
|
|
283
|
+
...setup,
|
|
284
|
+
errors: [...setup.errors, ...receiptRegistration.errors],
|
|
285
|
+
...(receiptRegistration.registered.length === 0
|
|
286
|
+
? {}
|
|
287
|
+
: { receipts: receiptRegistration.registered }),
|
|
288
|
+
};
|
|
289
|
+
const launch = await probePersistedMcpSetupEntries(ctx.paths, withReceipts, receiptRegistration.probeTargets);
|
|
290
|
+
const native = await checkNativeMcpHosts(receiptRegistration.probeTargets);
|
|
291
|
+
await recordNativeMcpHostChecks({
|
|
292
|
+
paths: ctx.paths,
|
|
293
|
+
scope: withReceipts.scope,
|
|
294
|
+
scopeDir: withReceipts.scope_dir,
|
|
295
|
+
targets: receiptRegistration.probeTargets,
|
|
296
|
+
checks: native.checks,
|
|
297
|
+
});
|
|
298
|
+
if (receiptRegistration.registered.length === 0 &&
|
|
299
|
+
receiptRegistration.errors.length === 0 &&
|
|
300
|
+
launch.probes.length === 0 &&
|
|
301
|
+
launch.errors.length === 0 &&
|
|
302
|
+
native.checks.length === 0 &&
|
|
303
|
+
native.errors.length === 0) {
|
|
304
|
+
return setup;
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
...withReceipts,
|
|
308
|
+
errors: [...withReceipts.errors, ...launch.errors, ...native.errors],
|
|
309
|
+
...(launch.probes.length === 0 ? {} : { launch_probes: launch.probes }),
|
|
310
|
+
...(native.checks.length === 0 ? {} : { native_checks: native.checks }),
|
|
233
311
|
};
|
|
234
312
|
}
|
|
235
313
|
function doctorConnection(ctx, connection) {
|
|
@@ -254,87 +332,307 @@ function doctorConnection(ctx, connection) {
|
|
|
254
332
|
exitCode: allOk ? 0 : 1,
|
|
255
333
|
};
|
|
256
334
|
}
|
|
257
|
-
function removeConnection(args, ctx, connection) {
|
|
335
|
+
async function removeConnection(args, ctx, connection) {
|
|
258
336
|
const dryRun = args.flags.has("--dry-run");
|
|
259
|
-
//
|
|
260
|
-
//
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
});
|
|
266
|
-
const removableHosts = FILE_HOSTS.filter((host) => !preservedForeign.includes(host));
|
|
267
|
-
// User scope; the explicit remove action is the consent the guard asks for.
|
|
268
|
-
const remove = runMcpRemove(ctx.env, {
|
|
269
|
-
hosts: removableHosts,
|
|
337
|
+
// The explicit remove action carries its own narrow global consent.
|
|
338
|
+
// The writer verifies exact ownership per host and returns a conflict for an
|
|
339
|
+
// homonymous foreign entry, so this never has to infer ownership from a word
|
|
340
|
+
// in the command line.
|
|
341
|
+
const removeInput = {
|
|
342
|
+
hosts: [...FILE_HOSTS],
|
|
270
343
|
connections: [connection],
|
|
344
|
+
namespace: ctx.paths.namespace,
|
|
271
345
|
scope: "global",
|
|
272
|
-
|
|
346
|
+
globalApproval: "explicit-self-action",
|
|
273
347
|
dryRun,
|
|
274
|
-
}
|
|
348
|
+
};
|
|
349
|
+
const remove = runMcpRemove(ctx.env, removeInput);
|
|
275
350
|
if ("ok" in remove)
|
|
276
351
|
return refusal("remove", connectionView(ctx, connection), remove.hint);
|
|
277
|
-
const
|
|
278
|
-
const
|
|
352
|
+
const receiptErrors = await removeMcpRemoveReceipts(ctx.paths, removeInput, remove);
|
|
353
|
+
const removeWithReceipts = {
|
|
354
|
+
...remove,
|
|
355
|
+
errors: [...remove.errors, ...receiptErrors],
|
|
356
|
+
};
|
|
357
|
+
const hasProblems = removeWithReceipts.errors.length > 0 || removeWithReceipts.conflicts.length > 0;
|
|
358
|
+
const preservedForeign = [
|
|
359
|
+
...new Set(removeWithReceipts.conflicts.map((conflict) => conflict.host)),
|
|
360
|
+
];
|
|
361
|
+
const deleted = !dryRun && !hasProblems ? deleteMcpConnection(ctx.paths, connection) : null;
|
|
279
362
|
const preservedNote = preservedForeign.length > 0
|
|
280
363
|
? ` Se conservó la entrada ajena homónima en: ${preservedForeign.join(", ")}.`
|
|
281
364
|
: "";
|
|
365
|
+
const reloadNotice = removalReloadNotice(removeWithReceipts);
|
|
366
|
+
const views = connectionViews(ctx);
|
|
367
|
+
if (views.kind === "invalid")
|
|
368
|
+
return invalidRegistryResult("remove", views.issue);
|
|
282
369
|
return {
|
|
283
|
-
ok: !
|
|
370
|
+
ok: !hasProblems,
|
|
284
371
|
data: {
|
|
285
372
|
action: "remove",
|
|
286
373
|
connection: connectionView(ctx, connection),
|
|
287
|
-
connections:
|
|
288
|
-
table: formatConnectionsTable(
|
|
289
|
-
remove,
|
|
374
|
+
connections: views.connections,
|
|
375
|
+
table: formatConnectionsTable(views.connections),
|
|
376
|
+
remove: removeWithReceipts,
|
|
290
377
|
...(preservedForeign.length > 0 ? { preserved_foreign: preservedForeign } : {}),
|
|
291
378
|
...(deleted ? { registry: { path: deleted.path, changed: deleted.removed } } : {}),
|
|
292
379
|
summary: dryRun
|
|
293
380
|
? `Previsualización de eliminación para '${connection.name}'.${preservedNote}`
|
|
294
|
-
:
|
|
381
|
+
: hasProblems
|
|
382
|
+
? `Eliminación parcial de '${connection.name}'.${preservedNote}${reloadNotice}`
|
|
383
|
+
: `Conexión '${connection.name}' eliminada de los hosts con MCP y del registro local.${preservedNote}${reloadNotice}`,
|
|
295
384
|
},
|
|
296
|
-
...(
|
|
385
|
+
...(hasProblems
|
|
297
386
|
? {
|
|
298
387
|
error: {
|
|
299
388
|
code: "MCP_REMOVE_PARTIAL",
|
|
300
|
-
message: `${
|
|
389
|
+
message: `${removeWithReceipts.errors.length} error(es) y ${removeWithReceipts.conflicts.length} conflicto(s) durante remove; ver data.remove.errors y data.remove.conflicts`,
|
|
301
390
|
},
|
|
302
391
|
}
|
|
303
392
|
: {}),
|
|
304
|
-
exitCode:
|
|
393
|
+
exitCode: hasProblems ? 1 : 0,
|
|
305
394
|
};
|
|
306
395
|
}
|
|
396
|
+
function removalReloadNotice(remove) {
|
|
397
|
+
const requirements = remove.reload_required ?? [];
|
|
398
|
+
if (requirements.length === 0)
|
|
399
|
+
return "";
|
|
400
|
+
return ` Recarga requerida: ${requirements
|
|
401
|
+
.map((requirement) => `${hostLabel(requirement.host)}: ${requirement.next_step}`)
|
|
402
|
+
.join(" ")}`;
|
|
403
|
+
}
|
|
307
404
|
function runDoctor(ctx, connection, hosts) {
|
|
308
405
|
return runMcpDoctor(ctx.env, ctx.paths, {
|
|
309
406
|
hosts,
|
|
310
407
|
connections: [connection],
|
|
408
|
+
namespace: ctx.paths.namespace,
|
|
311
409
|
scope: "global",
|
|
312
410
|
});
|
|
313
411
|
}
|
|
314
412
|
function connectionViews(ctx) {
|
|
315
|
-
|
|
413
|
+
try {
|
|
414
|
+
const receiptLedger = readHostReceipts(ctx);
|
|
415
|
+
return {
|
|
416
|
+
kind: "ok",
|
|
417
|
+
connections: readMcpConnections(ctx.paths, ctx.env).map((connection) => connectionView(ctx, connection, receiptLedger)),
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
catch (error) {
|
|
421
|
+
if (error instanceof McpConnectionsError) {
|
|
422
|
+
return { kind: "invalid", issue: mcpRegistryIssue(ctx) };
|
|
423
|
+
}
|
|
424
|
+
throw error;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
function mcpRegistryIssue(ctx) {
|
|
428
|
+
return {
|
|
429
|
+
code: "MCP_CONNECTION_INVALID",
|
|
430
|
+
path: ctx.paths.userMcpConnectionsFile(),
|
|
431
|
+
recovery: "Restaurá mcp-connections.json desde una copia válida o corregí su forma antes de volver a operar.",
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
function invalidRegistryResult(action, issue) {
|
|
435
|
+
return {
|
|
436
|
+
ok: false,
|
|
437
|
+
error: {
|
|
438
|
+
code: issue.code,
|
|
439
|
+
message: "El registro MCP local no es válido y requiere reparación antes de operar.",
|
|
440
|
+
},
|
|
441
|
+
data: {
|
|
442
|
+
action,
|
|
443
|
+
connection: null,
|
|
444
|
+
connections: [],
|
|
445
|
+
table: formatConnectionsTable([]),
|
|
446
|
+
registry_error: issue,
|
|
447
|
+
summary: issue.recovery,
|
|
448
|
+
},
|
|
449
|
+
exitCode: 2,
|
|
450
|
+
};
|
|
316
451
|
}
|
|
317
|
-
function connectionView(ctx, connection) {
|
|
452
|
+
function connectionView(ctx, connection, receiptLedger = readHostReceipts(ctx)) {
|
|
453
|
+
const hostStatus = Object.fromEntries(FILE_HOSTS.map((host) => [host, installStatus(ctx, connection, host, receiptLedger)]));
|
|
318
454
|
return {
|
|
319
455
|
nombre: connection.name,
|
|
320
456
|
server_name: mcpEntryNameFor(connection.name),
|
|
321
457
|
dsn_var: connection.dsnVar,
|
|
322
458
|
dsn_visible: isDsnVisible(ctx, connection.dsnVar),
|
|
323
|
-
instalado: Object.fromEntries(FILE_HOSTS.map((
|
|
459
|
+
instalado: Object.fromEntries(FILE_HOSTS.map((host) => [host, installMark(hostStatus[host])])),
|
|
460
|
+
host_status: hostStatus,
|
|
324
461
|
};
|
|
325
462
|
}
|
|
326
|
-
|
|
327
|
-
|
|
463
|
+
/**
|
|
464
|
+
* Status must be derived from the exact descriptor that this host would load,
|
|
465
|
+
* not from a host-agnostic default. Global descriptors carry the resolved
|
|
466
|
+
* namespace and host identity in their argv, so both are part of ownership.
|
|
467
|
+
*/
|
|
468
|
+
function installStatus(ctx, connection, host, receiptLedger) {
|
|
469
|
+
const entry = buildMcpEntry(connection.name, connection.dsnVar, {
|
|
470
|
+
host,
|
|
471
|
+
scope: "global",
|
|
472
|
+
namespace: ctx.paths.namespace,
|
|
473
|
+
});
|
|
328
474
|
const snapshot = readMcpEntry(host, ctx.env.homeDir(), entry.name, "global");
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
if (
|
|
332
|
-
return
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
475
|
+
const classification = classifyMcpEntry(host, snapshot, entry, connection);
|
|
476
|
+
const ledgerFailure = receiptLedgerFailureStatus(classification.state, receiptLedger);
|
|
477
|
+
if (ledgerFailure !== undefined)
|
|
478
|
+
return ledgerFailure;
|
|
479
|
+
const entryStatus = nonCurrentEntryStatus(classification.state);
|
|
480
|
+
if (entryStatus !== undefined)
|
|
481
|
+
return entryStatus;
|
|
482
|
+
const receipt = receiptLedger.receipts.find((candidate) => candidate.host === host &&
|
|
483
|
+
candidate.scope === "global" &&
|
|
484
|
+
candidate.connection === connection.name);
|
|
485
|
+
if (receipt !== undefined && !receiptMatchesDescriptor(receipt, snapshot)) {
|
|
486
|
+
return staleReceiptStatus(classification.state);
|
|
487
|
+
}
|
|
488
|
+
return currentDescriptorStatus(classification.state, receipt);
|
|
489
|
+
}
|
|
490
|
+
function receiptLedgerFailureStatus(entryState, receiptLedger) {
|
|
491
|
+
if (receiptLedger.failure === undefined)
|
|
492
|
+
return undefined;
|
|
493
|
+
return {
|
|
494
|
+
state: "failed",
|
|
495
|
+
entry_state: entryState,
|
|
496
|
+
launchable: false,
|
|
497
|
+
reload_required: false,
|
|
498
|
+
receipt_failure: { phase: "receipt", code: receiptLedger.failure.code },
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
function nonCurrentEntryStatus(entryState) {
|
|
502
|
+
switch (entryState) {
|
|
503
|
+
case "missing":
|
|
504
|
+
return {
|
|
505
|
+
state: "registered",
|
|
506
|
+
entry_state: entryState,
|
|
507
|
+
launchable: false,
|
|
508
|
+
reload_required: false,
|
|
509
|
+
};
|
|
510
|
+
case "known-legacy":
|
|
511
|
+
return {
|
|
512
|
+
state: "legacy",
|
|
513
|
+
entry_state: entryState,
|
|
514
|
+
launchable: false,
|
|
515
|
+
reload_required: true,
|
|
516
|
+
};
|
|
517
|
+
case "foreign":
|
|
518
|
+
return {
|
|
519
|
+
state: "conflict",
|
|
520
|
+
entry_state: entryState,
|
|
521
|
+
launchable: false,
|
|
522
|
+
reload_required: false,
|
|
523
|
+
};
|
|
524
|
+
case "malformed":
|
|
525
|
+
return {
|
|
526
|
+
state: "failed",
|
|
527
|
+
entry_state: entryState,
|
|
528
|
+
launchable: false,
|
|
529
|
+
reload_required: false,
|
|
530
|
+
};
|
|
531
|
+
case "current":
|
|
532
|
+
return undefined;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
function staleReceiptStatus(entryState) {
|
|
536
|
+
return {
|
|
537
|
+
state: "failed",
|
|
538
|
+
entry_state: entryState,
|
|
539
|
+
launchable: false,
|
|
540
|
+
reload_required: true,
|
|
541
|
+
receipt_failure: { phase: "descriptor", code: "MCP_RECEIPT_DESCRIPTOR_STALE" },
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
function currentDescriptorStatus(entryState, receipt) {
|
|
545
|
+
// A current descriptor without a receipt may be the aftermath of a busy
|
|
546
|
+
// receipt ledger after the host file was already written. It has no durable
|
|
547
|
+
// descriptor digest, lifecycle evidence, or way for a later host reload to
|
|
548
|
+
// clear reload_required, so presenting it as merely configured would hide
|
|
549
|
+
// the required recovery action.
|
|
550
|
+
if (receipt === undefined) {
|
|
551
|
+
return {
|
|
552
|
+
state: "failed",
|
|
553
|
+
entry_state: entryState,
|
|
554
|
+
launchable: false,
|
|
555
|
+
reload_required: true,
|
|
556
|
+
receipt_failure: { phase: "receipt", code: "MCP_RECEIPT_NOT_FOUND" },
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
const lastProbe = receipt?.last_launch_probe;
|
|
560
|
+
const nativeCheckFailure = receipt?.last_native_check_failure;
|
|
561
|
+
const launchable = lastProbe?.outcome === "passed";
|
|
562
|
+
const reloadRequired = receipt?.reload_required ?? false;
|
|
563
|
+
const evidence = {
|
|
564
|
+
entry_state: entryState,
|
|
565
|
+
launchable,
|
|
566
|
+
reload_required: reloadRequired,
|
|
567
|
+
...(lastProbe === undefined
|
|
568
|
+
? {}
|
|
569
|
+
: {
|
|
570
|
+
last_probe: {
|
|
571
|
+
outcome: lastProbe.outcome,
|
|
572
|
+
phase: lastProbe.phase,
|
|
573
|
+
observed_at: lastProbe.observed_at,
|
|
574
|
+
},
|
|
575
|
+
}),
|
|
576
|
+
...(receipt?.last_host_load_observed === undefined
|
|
577
|
+
? {}
|
|
578
|
+
: { last_host_load_observed: receipt.last_host_load_observed.observed_at }),
|
|
579
|
+
...(nativeCheckFailure === undefined
|
|
580
|
+
? {}
|
|
581
|
+
: {
|
|
582
|
+
native_check_failure: {
|
|
583
|
+
code: nativeCheckFailure.code,
|
|
584
|
+
observed_at: nativeCheckFailure.observed_at,
|
|
585
|
+
},
|
|
586
|
+
}),
|
|
587
|
+
};
|
|
588
|
+
if (lastProbe?.outcome === "failed" || nativeCheckFailure !== undefined) {
|
|
589
|
+
return { state: "failed", ...evidence };
|
|
590
|
+
}
|
|
591
|
+
if (receipt?.last_host_load_observed !== undefined && !reloadRequired) {
|
|
592
|
+
return { state: "host-load-observed", ...evidence };
|
|
593
|
+
}
|
|
594
|
+
if (reloadRequired)
|
|
595
|
+
return { state: "reload-required", ...evidence };
|
|
596
|
+
if (launchable)
|
|
597
|
+
return { state: "launchable", ...evidence };
|
|
598
|
+
return { state: "configured", ...evidence };
|
|
599
|
+
}
|
|
600
|
+
function receiptMatchesDescriptor(receipt, snapshot) {
|
|
601
|
+
if (snapshot.command === undefined || snapshot.args === undefined)
|
|
602
|
+
return false;
|
|
603
|
+
try {
|
|
604
|
+
return (receipt.descriptor_digest ===
|
|
605
|
+
digestMcpReceiptDescriptor({ command: snapshot.command, args: snapshot.args }));
|
|
606
|
+
}
|
|
607
|
+
catch {
|
|
608
|
+
return false;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
function installMark(status) {
|
|
612
|
+
return status.entry_state === "missing"
|
|
613
|
+
? "no"
|
|
614
|
+
: status.entry_state === "current"
|
|
615
|
+
? "si"
|
|
616
|
+
: "drift";
|
|
617
|
+
}
|
|
618
|
+
function readHostReceipts(ctx) {
|
|
619
|
+
const file = mcpHostReceiptFile(ctx.paths);
|
|
620
|
+
if (!existsSync(file))
|
|
621
|
+
return { receipts: [] };
|
|
622
|
+
try {
|
|
623
|
+
return { receipts: parseMcpHostReceiptBook(readFileSync(file, "utf8")).receipts };
|
|
624
|
+
}
|
|
625
|
+
catch (error) {
|
|
626
|
+
// The registry remains readable, but no lifecycle claim survives a corrupt
|
|
627
|
+
// receipt ledger. Every host becomes explicitly actionable rather than
|
|
628
|
+
// quietly falling back to an unproven "configured" state.
|
|
629
|
+
return {
|
|
630
|
+
receipts: [],
|
|
631
|
+
failure: {
|
|
632
|
+
code: error instanceof McpHostReceiptError ? error.code : "MCP_RECEIPT_UNREADABLE",
|
|
633
|
+
},
|
|
634
|
+
};
|
|
635
|
+
}
|
|
338
636
|
}
|
|
339
637
|
export function isDsnVisible(ctx, dsnVar) {
|
|
340
638
|
if (ctx.env.get(dsnVar))
|
|
@@ -385,9 +683,18 @@ function renderBoxTable(headers, rows) {
|
|
|
385
683
|
return out.join("\n");
|
|
386
684
|
}
|
|
387
685
|
async function resolveRegisteredConnection(args, ctx, prompts) {
|
|
388
|
-
|
|
686
|
+
let connections;
|
|
687
|
+
try {
|
|
688
|
+
connections = readMcpConnections(ctx.paths, ctx.env);
|
|
689
|
+
}
|
|
690
|
+
catch (error) {
|
|
691
|
+
if (error instanceof McpConnectionsError) {
|
|
692
|
+
return { kind: "invalid", issue: mcpRegistryIssue(ctx) };
|
|
693
|
+
}
|
|
694
|
+
throw error;
|
|
695
|
+
}
|
|
389
696
|
if (connections.length === 0)
|
|
390
|
-
return
|
|
697
|
+
return { kind: "none" };
|
|
391
698
|
const raw = args.values.get("name") ?? args.values.get("instance");
|
|
392
699
|
if (raw !== undefined) {
|
|
393
700
|
const validation = validateMcpInstance(raw);
|
|
@@ -397,7 +704,7 @@ async function resolveRegisteredConnection(args, ctx, prompts) {
|
|
|
397
704
|
if (found === undefined) {
|
|
398
705
|
throw new Error(`conexión MCP no registrada: '${validation.value}'`);
|
|
399
706
|
}
|
|
400
|
-
return found;
|
|
707
|
+
return { kind: "found", connection: found };
|
|
401
708
|
}
|
|
402
709
|
const defaultConnection = connections[0]?.name;
|
|
403
710
|
const selected = await prompts.select({
|
|
@@ -408,7 +715,8 @@ async function resolveRegisteredConnection(args, ctx, prompts) {
|
|
|
408
715
|
value: item.name,
|
|
409
716
|
})),
|
|
410
717
|
});
|
|
411
|
-
|
|
718
|
+
const connection = connections.find((item) => item.name === selected);
|
|
719
|
+
return connection === undefined ? { kind: "none" } : { kind: "found", connection };
|
|
412
720
|
}
|
|
413
721
|
async function resolveConnectionName(args, prompts) {
|
|
414
722
|
const raw = args.values.get("name") ?? args.values.get("instance");
|
|
@@ -506,7 +814,7 @@ async function resolveAction(args, prompts) {
|
|
|
506
814
|
return { action: raw, fromArgs: true };
|
|
507
815
|
return {
|
|
508
816
|
action: await prompts.select({
|
|
509
|
-
message: "Configurar MCP database (
|
|
817
|
+
message: "Configurar MCP database (PostgreSQL Workline)",
|
|
510
818
|
default: "list",
|
|
511
819
|
choices: [
|
|
512
820
|
{ type: "separator", separator: "── Conexiones existentes ──" },
|