infra-kit 0.1.114 → 0.1.117
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/.eslintcache +1 -1
- package/.omc/state/agent-replay-1fcfe0ec-7567-41c3-9bfd-501e99e86819.jsonl +19 -0
- package/.omc/state/agent-replay-38382db5-3088-4b5a-aff7-2561a60827c7.jsonl +17 -0
- package/.omc/state/agent-replay-50c36be9-a3a2-42b9-9c85-5a06d3e22f6a.jsonl +5 -0
- package/.omc/state/agent-replay-8198b3e5-fad6-4ee0-9c59-ef773ad89af4.jsonl +1 -0
- package/.omc/state/agent-replay-8cd7652a-b8b5-49cf-9b1f-bee8e5972458.jsonl +3 -0
- package/.omc/state/agent-replay-9bea518f-a9ee-4d14-bb53-a936ebaf647c.jsonl +7 -0
- package/.omc/state/agent-replay-b52d89fb-0e24-4901-bc66-27e3c1697126.jsonl +2 -0
- package/.omc/state/agent-replay-f581a1ae-0ee4-48a3-96f3-ce31a0633bb0.jsonl +1 -0
- package/.omc/state/agent-replay-fe1057b4-9a25-4e8e-8c3f-3e11652ee697.jsonl +5 -0
- package/.omc/state/idle-notif-cooldown.json +1 -1
- package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/mission-state.json +109 -0
- package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/pre-tool-advisory-throttle.json +42 -0
- package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/ralph-state.json +13 -0
- package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/skill-active-state.json +15 -0
- package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/subagent-tracking-state.json +62 -0
- package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/ultrawork-state.json +11 -0
- package/.omc/state/sessions/23d0ff82-17e5-428b-8743-38f7979bb6f3/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/23d0ff82-17e5-428b-8743-38f7979bb6f3/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/mission-state.json +145 -0
- package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/pre-tool-advisory-throttle.json +38 -0
- package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/ralplan-state.json +11 -0
- package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/subagent-tracking-state.json +98 -0
- package/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/mission-state.json +61 -0
- package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/pre-tool-advisory-throttle.json +22 -0
- package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/skill-active-state.json +15 -0
- package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/subagent-tracking-state.json +26 -0
- package/{src/lib/.omc/state/sessions/a60ac2ec-afbd-449f-a540-6df287392fc2 → .omc/state/sessions/8198b3e5-fad6-4ee0-9c59-ef773ad89af4}/pre-tool-advisory-throttle.json +3 -3
- package/.omc/state/sessions/8198b3e5-fad6-4ee0-9c59-ef773ad89af4/subagent-tracking-state.json +17 -0
- package/.omc/state/sessions/8cd7652a-b8b5-49cf-9b1f-bee8e5972458/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/8cd7652a-b8b5-49cf-9b1f-bee8e5972458/ralplan-state.json +11 -0
- package/.omc/state/sessions/8cd7652a-b8b5-49cf-9b1f-bee8e5972458/subagent-tracking-state.json +35 -0
- package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/mission-state.json +79 -0
- package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/pre-tool-advisory-throttle.json +22 -0
- package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/progress.txt +7 -0
- package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/skill-active-state.json +15 -0
- package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/subagent-tracking-state.json +26 -0
- package/.omc/state/sessions/b52d89fb-0e24-4901-bc66-27e3c1697126/pre-tool-advisory-throttle.json +14 -0
- package/.omc/state/sessions/b52d89fb-0e24-4901-bc66-27e3c1697126/subagent-tracking-state.json +17 -0
- package/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/f581a1ae-0ee4-48a3-96f3-ce31a0633bb0/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/f581a1ae-0ee4-48a3-96f3-ce31a0633bb0/subagent-tracking-state.json +17 -0
- package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/mission-state.json +61 -0
- package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/prd.json +22 -0
- package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/pre-tool-advisory-throttle.json +22 -0
- package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/progress.txt +22 -0
- package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/skill-active-state.json +15 -0
- package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/subagent-tracking-state.json +26 -0
- package/.turbo/turbo-build.log +3 -3
- package/.turbo/turbo-eslint-check.log +2 -0
- package/.turbo/turbo-test.log +90 -42
- package/dist/boot-K4QUAFSP.js +2 -0
- package/dist/boot-K4QUAFSP.js.map +7 -0
- package/dist/chunk-FEGOOVZE.js +166 -0
- package/dist/chunk-FEGOOVZE.js.map +7 -0
- package/dist/chunk-WA4BQRDC.js +2 -0
- package/dist/chunk-WA4BQRDC.js.map +7 -0
- package/dist/cli.js +11 -107
- package/dist/cli.js.map +4 -4
- package/dist/entry/index.d.ts +2 -0
- package/dist/index.js +1 -1
- package/dist/index.js.map +4 -4
- package/dist/lib/vendor/config-schema.d.ts +58 -0
- package/dist/mcp.js +1 -54
- package/dist/mcp.js.map +4 -4
- package/eslint.config.js +33 -1
- package/package.json +5 -1
- package/scripts/build.js +11 -1
- package/src/.omc/state/agent-replay-c513ef38-cc3e-4a29-9c4c-1e0137245dd5.jsonl +4 -0
- package/src/.omc/state/agent-replay-ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a.jsonl +2 -0
- package/src/.omc/state/idle-notif-cooldown.json +1 -1
- package/src/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/mission-state.json +79 -0
- package/src/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/pre-tool-advisory-throttle.json +22 -0
- package/src/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/subagent-tracking-state.json +26 -0
- package/src/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/pre-tool-advisory-throttle.json +18 -0
- package/src/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/ralph-state.json +13 -0
- package/src/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/ultrawork-state.json +11 -0
- package/src/commands/config/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/last-tool-error-state.json +7 -0
- package/src/commands/config/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/pre-tool-advisory-throttle.json +18 -0
- package/src/commands/config/config.ts +7 -37
- package/src/commands/doctor/__tests__/agent-files.test.ts +8 -30
- package/src/commands/doctor/__tests__/check-legacy-user-global-config.test.ts +110 -0
- package/src/commands/doctor/doctor.ts +104 -44
- package/src/commands/env-autoload/env-autoload.ts +12 -0
- package/src/commands/env-autoload/index.ts +1 -0
- package/src/commands/env-clear/__tests__/env-clear.test.ts +27 -0
- package/src/commands/env-clear/env-clear.ts +22 -8
- package/src/commands/env-load/__tests__/env-load.test.ts +36 -1
- package/src/commands/env-load/env-load.ts +152 -35
- package/src/commands/env-load/index.ts +2 -1
- package/src/commands/env-status/__tests__/env-status.test.ts +78 -0
- package/src/commands/env-status/env-status.ts +19 -7
- package/src/commands/gh-release-deploy-all/gh-release-deploy-all.ts +45 -1
- package/src/commands/gh-release-deploy-selected/gh-release-deploy-selected.ts +46 -1
- package/src/commands/init/__tests__/agent-files.test.ts +145 -27
- package/src/commands/init/__tests__/migrate-config.test.ts +136 -5
- package/src/commands/init/__tests__/migrate-factory-config.test.ts +93 -0
- package/src/commands/init/__tests__/seed-user-global-config.test.ts +64 -0
- package/src/commands/init/__tests__/shell-body.test.ts +30 -0
- package/src/commands/init/agent-files.ts +65 -45
- package/src/commands/init/init.ts +140 -31
- package/src/commands/init/migrate-config.ts +160 -32
- package/src/commands/vendor-check/__tests__/runtime-isolation.test.ts +71 -0
- package/src/commands/vendor-check/__tests__/vendor-check.test.ts +87 -0
- package/src/commands/vendor-check/index.ts +1 -0
- package/src/commands/vendor-check/vendor-check.ts +127 -0
- package/src/commands/vendor-config/__tests__/vendor-config.test.ts +103 -0
- package/src/commands/vendor-config/index.ts +1 -0
- package/src/commands/vendor-config/vendor-config.ts +162 -0
- package/src/commands/vendor-diff/__tests__/vendor-diff.test.ts +74 -0
- package/src/commands/vendor-diff/index.ts +1 -0
- package/src/commands/vendor-diff/vendor-diff.ts +77 -0
- package/src/commands/vendor-manifest/index.ts +1 -0
- package/src/commands/vendor-manifest/vendor-manifest.ts +60 -0
- package/src/commands/vendor-sync/__tests__/vendor-write.test.ts +86 -0
- package/src/commands/vendor-sync/index.ts +1 -0
- package/src/commands/vendor-sync/vendor-sync.ts +90 -0
- package/src/commands/worktrees-add/worktrees-add.ts +1 -1
- package/src/commands/worktrees-reload/worktrees-reload.ts +6 -5
- package/src/commands/worktrees-remove/worktrees-remove.ts +10 -1
- package/src/commands/worktrees-sync/worktrees-sync.ts +9 -1
- package/src/entry/cli.ts +417 -210
- package/src/entry/index.ts +7 -1
- package/src/integrations/cmux/__tests__/open-workspace-with-layout.test.ts +127 -0
- package/src/integrations/cmux/close-workspace-by-title.ts +2 -2
- package/src/integrations/cmux/list-workspace-titles.ts +1 -1
- package/src/integrations/cmux/open-workspace-with-layout.ts +15 -4
- package/src/integrations/cursor/open-cursor-workspace.ts +6 -11
- package/src/integrations/doppler/__tests__/doppler-errors.test.ts +76 -0
- package/src/integrations/doppler/doppler-cli-auth.ts +12 -4
- package/src/integrations/doppler/doppler-errors.ts +88 -0
- package/src/integrations/doppler/doppler-project.ts +80 -0
- package/src/integrations/doppler/index.ts +3 -1
- package/src/integrations/gh/gh-cli-auth/gh-cli-auth.ts +9 -5
- package/src/integrations/gh/gh-release-prs/gh-release-prs.ts +16 -8
- package/src/integrations/ide/__tests__/ide-facade.test.ts +49 -10
- package/src/integrations/ide/open-ide-workspace.ts +6 -6
- package/src/integrations/ide/remove-ide-worktree-folders.ts +95 -30
- package/src/integrations/ide/types.ts +10 -1
- package/src/integrations/zed/__tests__/open-zed-workspace.test.ts +1 -17
- package/src/integrations/zed/__tests__/reuse-zed-workspace.test.ts +86 -0
- package/src/integrations/zed/index.ts +1 -0
- package/src/integrations/zed/open-zed-workspace.ts +4 -10
- package/src/integrations/zed/reuse-zed-workspace.ts +57 -0
- package/src/lib/command-catalog/__tests__/__snapshots__/command-catalog.test.ts.snap +212 -0
- package/src/lib/command-catalog/__tests__/command-catalog.test.ts +193 -0
- package/src/lib/command-catalog/command-catalog.ts +141 -0
- package/src/lib/command-catalog/index.ts +2 -0
- package/src/lib/command-echo/__tests__/command-echo.test.ts +127 -0
- package/src/lib/constants/constants.ts +13 -0
- package/src/lib/constants/index.ts +2 -0
- package/src/lib/env-autoload/__tests__/env-autoload.test.ts +288 -0
- package/src/lib/env-autoload/env-autoload.ts +294 -0
- package/src/lib/env-autoload/index.ts +9 -0
- package/src/lib/errors/operation-error.ts +1 -1
- package/src/lib/infra-kit-config/__tests__/env-autoload-schema.test.ts +71 -0
- package/src/lib/infra-kit-config/__tests__/infra-kit-config.test.ts +77 -6
- package/src/lib/infra-kit-config/index.ts +9 -1
- package/src/lib/infra-kit-config/infra-kit-config.ts +71 -11
- package/src/lib/json-output/__tests__/json-output.test.ts +139 -0
- package/src/lib/json-output/index.ts +1 -0
- package/src/lib/json-output/json-output.ts +47 -0
- package/src/lib/managed-block/managed-block.ts +4 -4
- package/src/lib/package-config/package-config.ts +1 -3
- package/src/lib/path-display/index.ts +1 -0
- package/src/lib/path-display/path-display.ts +42 -0
- package/src/lib/render/__tests__/render.test.ts +48 -0
- package/src/lib/render/index.ts +1 -0
- package/src/lib/render/render.ts +24 -0
- package/src/lib/vendor/__tests__/config-schema.test.ts +31 -0
- package/src/lib/vendor/__tests__/config.test.ts +63 -0
- package/src/lib/vendor/__tests__/factory-config.test.ts +92 -0
- package/src/lib/vendor/__tests__/vendor-lib.test.ts +158 -0
- package/src/lib/vendor/__tests__/zx-mock.ts +32 -0
- package/src/lib/vendor/config-schema.ts +78 -0
- package/src/lib/vendor/config.ts +58 -0
- package/src/lib/vendor/factory-config-schema.ts +35 -0
- package/src/lib/vendor/factory-config.ts +91 -0
- package/src/lib/vendor/hash.ts +16 -0
- package/src/lib/vendor/index.ts +23 -0
- package/src/lib/vendor/manifest.ts +151 -0
- package/src/lib/vendor/skip-sets.ts +48 -0
- package/src/lib/vendor/sync-ops.ts +290 -0
- package/src/lib/vendor/walk.ts +56 -0
- package/src/mcp/tools/index.ts +5 -42
- package/src/sanity.test.tsx +1 -0
- package/src/tui/__tests__/no-react-boundary.test.ts +51 -0
- package/src/tui/boot.tsx +45 -0
- package/src/tui/screens/__tests__/command-palette.test.tsx +136 -0
- package/src/tui/screens/command-palette.tsx +159 -0
- package/src/tui/types.ts +8 -0
- package/tsconfig.json +1 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +8 -0
- package/src/commands/worktrees-open/__tests__/open-cmux.test.ts +0 -96
- package/src/commands/worktrees-open/index.ts +0 -1
- package/src/commands/worktrees-open/worktrees-open.ts +0 -195
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`command catalog — MCP exposure policy > matches the golden MCP tools/list surface (names + schema shape) 1`] = `
|
|
4
|
+
[
|
|
5
|
+
{
|
|
6
|
+
"input": [
|
|
7
|
+
"all",
|
|
8
|
+
"root",
|
|
9
|
+
],
|
|
10
|
+
"name": "audit",
|
|
11
|
+
"output": [
|
|
12
|
+
"allPassed",
|
|
13
|
+
"packages",
|
|
14
|
+
],
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"input": [],
|
|
18
|
+
"name": "env-clear",
|
|
19
|
+
"output": [
|
|
20
|
+
"filePath",
|
|
21
|
+
"unsetStatements",
|
|
22
|
+
"variableCount",
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"input": [],
|
|
27
|
+
"name": "env-list",
|
|
28
|
+
"output": [
|
|
29
|
+
"configs",
|
|
30
|
+
"project",
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"input": [
|
|
35
|
+
"config",
|
|
36
|
+
],
|
|
37
|
+
"name": "env-load",
|
|
38
|
+
"output": [
|
|
39
|
+
"config",
|
|
40
|
+
"filePath",
|
|
41
|
+
"project",
|
|
42
|
+
"variableCount",
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"input": [],
|
|
47
|
+
"name": "env-status",
|
|
48
|
+
"output": [
|
|
49
|
+
"autoLoaded",
|
|
50
|
+
"cleared",
|
|
51
|
+
"sessionConfig",
|
|
52
|
+
"sessionId",
|
|
53
|
+
"sessionLoadedAt",
|
|
54
|
+
"sessionLoadedCount",
|
|
55
|
+
"sessionProject",
|
|
56
|
+
"sessionTotalCount",
|
|
57
|
+
],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"input": [
|
|
61
|
+
"all",
|
|
62
|
+
],
|
|
63
|
+
"name": "gh-merge-dev",
|
|
64
|
+
"output": [
|
|
65
|
+
"failedBranches",
|
|
66
|
+
"failedMerges",
|
|
67
|
+
"successfulMerges",
|
|
68
|
+
"totalBranches",
|
|
69
|
+
],
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"input": [
|
|
73
|
+
"env",
|
|
74
|
+
"skipTerraform",
|
|
75
|
+
"version",
|
|
76
|
+
],
|
|
77
|
+
"name": "gh-release-deploy-all",
|
|
78
|
+
"output": [
|
|
79
|
+
"environment",
|
|
80
|
+
"releaseBranch",
|
|
81
|
+
"skipTerraformDeploy",
|
|
82
|
+
"success",
|
|
83
|
+
"version",
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"input": [
|
|
88
|
+
"env",
|
|
89
|
+
"services",
|
|
90
|
+
"skipTerraform",
|
|
91
|
+
"version",
|
|
92
|
+
],
|
|
93
|
+
"name": "gh-release-deploy-selected",
|
|
94
|
+
"output": [
|
|
95
|
+
"environment",
|
|
96
|
+
"releaseBranch",
|
|
97
|
+
"services",
|
|
98
|
+
"skipTerraformDeploy",
|
|
99
|
+
"success",
|
|
100
|
+
"version",
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"input": [],
|
|
105
|
+
"name": "gh-release-list",
|
|
106
|
+
"output": [
|
|
107
|
+
"count",
|
|
108
|
+
"releases",
|
|
109
|
+
],
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"input": [
|
|
113
|
+
"releases",
|
|
114
|
+
],
|
|
115
|
+
"name": "release-create",
|
|
116
|
+
"output": [
|
|
117
|
+
"createdBranches",
|
|
118
|
+
"failedReleases",
|
|
119
|
+
"failureCount",
|
|
120
|
+
"releases",
|
|
121
|
+
"successCount",
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"input": [
|
|
126
|
+
"description",
|
|
127
|
+
"version",
|
|
128
|
+
],
|
|
129
|
+
"name": "release-desc-edit",
|
|
130
|
+
"output": [
|
|
131
|
+
"branch",
|
|
132
|
+
"changed",
|
|
133
|
+
"jiraVersionUrl",
|
|
134
|
+
"newDescription",
|
|
135
|
+
"previousDescription",
|
|
136
|
+
"version",
|
|
137
|
+
],
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"input": [],
|
|
141
|
+
"name": "vendor-check",
|
|
142
|
+
"output": [
|
|
143
|
+
"added",
|
|
144
|
+
"fileCount",
|
|
145
|
+
"modified",
|
|
146
|
+
"ok",
|
|
147
|
+
"removed",
|
|
148
|
+
"status",
|
|
149
|
+
],
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"input": [
|
|
153
|
+
"repos",
|
|
154
|
+
],
|
|
155
|
+
"name": "vendor-diff",
|
|
156
|
+
"output": [
|
|
157
|
+
"drifted",
|
|
158
|
+
"entries",
|
|
159
|
+
"ok",
|
|
160
|
+
],
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
"input": [],
|
|
164
|
+
"name": "version",
|
|
165
|
+
"output": [
|
|
166
|
+
"version",
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"input": [
|
|
171
|
+
"all",
|
|
172
|
+
"cmux",
|
|
173
|
+
"cursor",
|
|
174
|
+
"githubDesktop",
|
|
175
|
+
"ide",
|
|
176
|
+
"versions",
|
|
177
|
+
],
|
|
178
|
+
"name": "worktrees-add",
|
|
179
|
+
"output": [
|
|
180
|
+
"count",
|
|
181
|
+
"createdWorktrees",
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"input": [],
|
|
186
|
+
"name": "worktrees-list",
|
|
187
|
+
"output": [
|
|
188
|
+
"count",
|
|
189
|
+
"worktrees",
|
|
190
|
+
],
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
"input": [],
|
|
194
|
+
"name": "worktrees-reload",
|
|
195
|
+
"output": [
|
|
196
|
+
"closedCmux",
|
|
197
|
+
"ideFoldersAdded",
|
|
198
|
+
"ideFoldersRemoved",
|
|
199
|
+
"ideProviders",
|
|
200
|
+
"openedCmux",
|
|
201
|
+
],
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
"input": [],
|
|
205
|
+
"name": "worktrees-sync",
|
|
206
|
+
"output": [
|
|
207
|
+
"count",
|
|
208
|
+
"removedWorktrees",
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
]
|
|
212
|
+
`;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { commandCatalog, getExposedMcpTools, getMenuGroupCommands } from '../command-catalog'
|
|
4
|
+
|
|
5
|
+
// The exact MCP tool surface that was hand-listed in src/mcp/tools/index.ts
|
|
6
|
+
// before the catalog refactor. The catalog must keep this byte-for-byte.
|
|
7
|
+
const EXPECTED_EXPOSED_TOOLS = [
|
|
8
|
+
'env-status',
|
|
9
|
+
'env-list',
|
|
10
|
+
'env-load',
|
|
11
|
+
'env-clear',
|
|
12
|
+
'gh-merge-dev',
|
|
13
|
+
'release-create',
|
|
14
|
+
'release-desc-edit',
|
|
15
|
+
'gh-release-deploy-all',
|
|
16
|
+
'gh-release-deploy-selected',
|
|
17
|
+
'gh-release-list',
|
|
18
|
+
'audit',
|
|
19
|
+
'vendor-check',
|
|
20
|
+
'vendor-diff',
|
|
21
|
+
'version',
|
|
22
|
+
'worktrees-add',
|
|
23
|
+
'worktrees-list',
|
|
24
|
+
'worktrees-reload',
|
|
25
|
+
'worktrees-sync',
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
// Deliberately NOT exposed as MCP tools (mutating / host-inspecting / irreversible).
|
|
29
|
+
// release-deliver (prod delivery + admin-merge) and worktrees-remove (rm -rf) are
|
|
30
|
+
// CLI-only by design.
|
|
31
|
+
const EXPECTED_UNEXPOSED_WITH_TOOL = [
|
|
32
|
+
'doctor',
|
|
33
|
+
'vendor-sync',
|
|
34
|
+
'vendor-manifest',
|
|
35
|
+
'gh-release-deliver',
|
|
36
|
+
'worktrees-remove',
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
describe('command catalog — MCP exposure policy', () => {
|
|
40
|
+
it('exposes exactly the expected 18 MCP tools (set-equal, order-independent)', () => {
|
|
41
|
+
const exposedNames = getExposedMcpTools()
|
|
42
|
+
.map((tool) => {
|
|
43
|
+
return tool.name
|
|
44
|
+
})
|
|
45
|
+
.sort()
|
|
46
|
+
|
|
47
|
+
expect(exposedNames).toEqual([...EXPECTED_EXPOSED_TOOLS].sort())
|
|
48
|
+
expect(exposedNames).toHaveLength(18)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it('never exposes the irreversible release-deliver / worktrees-remove tools', () => {
|
|
52
|
+
const exposedNames = new Set(
|
|
53
|
+
getExposedMcpTools().map((tool) => {
|
|
54
|
+
return tool.name
|
|
55
|
+
}),
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
expect(exposedNames.has('gh-release-deliver')).toBe(false)
|
|
59
|
+
expect(exposedNames.has('worktrees-remove')).toBe(false)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
it('keeps doctor, vendor-sync and vendor-manifest UNEXPOSED even though they have tools', () => {
|
|
63
|
+
const exposedNames = new Set(
|
|
64
|
+
getExposedMcpTools().map((tool) => {
|
|
65
|
+
return tool.name
|
|
66
|
+
}),
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
for (const unexposed of EXPECTED_UNEXPOSED_WITH_TOOL) {
|
|
70
|
+
const entry = commandCatalog.find((candidate) => {
|
|
71
|
+
return candidate.mcpTool?.name === unexposed
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
expect(entry, `catalog should carry a tool for ${unexposed}`).toBeDefined()
|
|
75
|
+
expect(entry?.mcpExposed, `${unexposed} must stay unexposed`).toBe(false)
|
|
76
|
+
expect(exposedNames.has(unexposed), `${unexposed} must not be registered`).toBe(false)
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
it('every exposed entry carries a tool, and every entry with mcpExposed=true has one', () => {
|
|
81
|
+
for (const entry of commandCatalog) {
|
|
82
|
+
if (entry.mcpExposed) {
|
|
83
|
+
expect(entry.mcpTool, `${entry.cliName} is exposed but has no tool`).not.toBeNull()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('mcpTool name matches a stable identifier (no duplicate registrations)', () => {
|
|
89
|
+
const names = getExposedMcpTools().map((tool) => {
|
|
90
|
+
return tool.name
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
expect(new Set(names).size).toBe(names.length)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
// Golden snapshot of the registered MCP surface: tool name + input/output
|
|
97
|
+
// schema field names. Locks names AND schema shape so any accidental change to
|
|
98
|
+
// the exposed tools/list fails CI (the "tools/list identical" guardrail).
|
|
99
|
+
it('matches the golden MCP tools/list surface (names + schema shape)', () => {
|
|
100
|
+
const surface = getExposedMcpTools()
|
|
101
|
+
.map((tool) => {
|
|
102
|
+
return {
|
|
103
|
+
name: tool.name,
|
|
104
|
+
input: Object.keys(tool.inputSchema).sort(),
|
|
105
|
+
output: Object.keys(tool.outputSchema).sort(),
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
.sort((a, b) => {
|
|
109
|
+
return a.name.localeCompare(b.name)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
expect(surface).toMatchSnapshot()
|
|
113
|
+
})
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
describe('command catalog — CLI/MCP name parity', () => {
|
|
117
|
+
// The authoritative (cliName -> mcpName) map. Divergences are INTENTIONAL and
|
|
118
|
+
// grandfathered here (the `gh-` prefix on release tools). Any new accidental
|
|
119
|
+
// divergence — or a typo that renames an MCP tool — fails this test.
|
|
120
|
+
const EXPECTED_PARITY: Record<string, string> = {
|
|
121
|
+
'merge-dev': 'gh-merge-dev',
|
|
122
|
+
'release-list': 'gh-release-list',
|
|
123
|
+
'release-create': 'release-create',
|
|
124
|
+
'release-desc-edit': 'release-desc-edit',
|
|
125
|
+
'release-deploy-all': 'gh-release-deploy-all',
|
|
126
|
+
'release-deploy-selected': 'gh-release-deploy-selected',
|
|
127
|
+
'release-deliver': 'gh-release-deliver',
|
|
128
|
+
'worktrees-add': 'worktrees-add',
|
|
129
|
+
'worktrees-list': 'worktrees-list',
|
|
130
|
+
'worktrees-reload': 'worktrees-reload',
|
|
131
|
+
'worktrees-remove': 'worktrees-remove',
|
|
132
|
+
'worktrees-sync': 'worktrees-sync',
|
|
133
|
+
audit: 'audit',
|
|
134
|
+
doctor: 'doctor',
|
|
135
|
+
version: 'version',
|
|
136
|
+
'env-status': 'env-status',
|
|
137
|
+
'env-list': 'env-list',
|
|
138
|
+
'env-load': 'env-load',
|
|
139
|
+
'env-clear': 'env-clear',
|
|
140
|
+
'vendor-check': 'vendor-check',
|
|
141
|
+
'vendor-diff': 'vendor-diff',
|
|
142
|
+
'vendor-manifest': 'vendor-manifest',
|
|
143
|
+
'vendor-sync': 'vendor-sync',
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
it('every catalog entry with a tool matches its expected (cliName, mcpName) pair', () => {
|
|
147
|
+
const actualParity: Record<string, string> = {}
|
|
148
|
+
|
|
149
|
+
for (const entry of commandCatalog) {
|
|
150
|
+
if (entry.mcpTool) {
|
|
151
|
+
actualParity[entry.cliName] = entry.mcpTool.name
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
expect(actualParity).toEqual(EXPECTED_PARITY)
|
|
156
|
+
})
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
describe('command catalog — menu grouping', () => {
|
|
160
|
+
it('preserves the three menu groups in display order', () => {
|
|
161
|
+
expect(getMenuGroupCommands('release')).toEqual([
|
|
162
|
+
'merge-dev',
|
|
163
|
+
'release-list',
|
|
164
|
+
'release-create',
|
|
165
|
+
'release-desc-edit',
|
|
166
|
+
'release-deploy-all',
|
|
167
|
+
'release-deploy-selected',
|
|
168
|
+
'release-deliver',
|
|
169
|
+
])
|
|
170
|
+
|
|
171
|
+
expect(getMenuGroupCommands('worktrees')).toEqual([
|
|
172
|
+
'worktrees-add',
|
|
173
|
+
'worktrees-list',
|
|
174
|
+
'worktrees-reload',
|
|
175
|
+
'worktrees-remove',
|
|
176
|
+
'worktrees-sync',
|
|
177
|
+
])
|
|
178
|
+
|
|
179
|
+
expect(getMenuGroupCommands('environment')).toEqual([
|
|
180
|
+
'audit',
|
|
181
|
+
'vendor',
|
|
182
|
+
'vendor-config',
|
|
183
|
+
'doctor',
|
|
184
|
+
'init',
|
|
185
|
+
'version',
|
|
186
|
+
'config',
|
|
187
|
+
'env-status',
|
|
188
|
+
'env-list',
|
|
189
|
+
'env-load',
|
|
190
|
+
'env-clear',
|
|
191
|
+
])
|
|
192
|
+
})
|
|
193
|
+
})
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type { z } from 'zod'
|
|
2
|
+
|
|
3
|
+
import { auditMcpTool } from 'src/commands/audit'
|
|
4
|
+
import { doctorMcpTool } from 'src/commands/doctor'
|
|
5
|
+
import { envClearMcpTool } from 'src/commands/env-clear'
|
|
6
|
+
import { envListMcpTool } from 'src/commands/env-list'
|
|
7
|
+
import { envLoadMcpTool } from 'src/commands/env-load'
|
|
8
|
+
import { envStatusMcpTool } from 'src/commands/env-status'
|
|
9
|
+
import { ghMergeDevMcpTool } from 'src/commands/gh-merge-dev'
|
|
10
|
+
import { ghReleaseDeliverMcpTool } from 'src/commands/gh-release-deliver'
|
|
11
|
+
import { ghReleaseDeployAllMcpTool } from 'src/commands/gh-release-deploy-all'
|
|
12
|
+
import { ghReleaseDeploySelectedMcpTool } from 'src/commands/gh-release-deploy-selected'
|
|
13
|
+
import { ghReleaseListMcpTool } from 'src/commands/gh-release-list'
|
|
14
|
+
import { releaseCreateMcpTool } from 'src/commands/release-create'
|
|
15
|
+
import { releaseDescEditMcpTool } from 'src/commands/release-desc-edit'
|
|
16
|
+
import { vendorCheckMcpTool } from 'src/commands/vendor-check'
|
|
17
|
+
import { vendorDiffMcpTool } from 'src/commands/vendor-diff'
|
|
18
|
+
import { vendorManifestMcpTool } from 'src/commands/vendor-manifest'
|
|
19
|
+
import { vendorSyncMcpTool } from 'src/commands/vendor-sync'
|
|
20
|
+
import { versionMcpTool } from 'src/commands/version'
|
|
21
|
+
import { worktreesAddMcpTool } from 'src/commands/worktrees-add'
|
|
22
|
+
import { worktreesListMcpTool } from 'src/commands/worktrees-list'
|
|
23
|
+
import { worktreesReloadMcpTool } from 'src/commands/worktrees-reload'
|
|
24
|
+
import { worktreesRemoveMcpTool } from 'src/commands/worktrees-remove'
|
|
25
|
+
import { worktreesSyncMcpTool } from 'src/commands/worktrees-sync'
|
|
26
|
+
import type { ToolsExecutionResult } from 'src/types'
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Registration-facing shape of an MCP tool. The concrete `*McpTool` definitions
|
|
30
|
+
* are generic over their Zod input/output shapes (and invariant), so they cannot
|
|
31
|
+
* share one precise `McpTool<...>` element type in an array. This widened, non-
|
|
32
|
+
* generic view exposes exactly what registration needs and every concrete tool
|
|
33
|
+
* assigns to it. Matches the loose handler typing already used in tool-handler.
|
|
34
|
+
*/
|
|
35
|
+
export interface CatalogMcpTool {
|
|
36
|
+
name: string
|
|
37
|
+
description: string
|
|
38
|
+
inputSchema: z.ZodRawShape
|
|
39
|
+
outputSchema: z.ZodRawShape
|
|
40
|
+
// Heterogeneous tool params; loose `any` mirrors the existing tool-handler typing.
|
|
41
|
+
handler: (params: any) => Promise<ToolsExecutionResult>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Single source of truth for the CLI command surface. It consolidates what used
|
|
46
|
+
* to live in three hand-maintained places (the MCP `tools[]` array and the
|
|
47
|
+
* three no-arg-menu name arrays) into one list, so they can no longer drift.
|
|
48
|
+
*
|
|
49
|
+
* It does NOT replace Commander's `.command().option()` wiring in entry/cli.ts —
|
|
50
|
+
* that stays the source of truth for argument parsing. This catalog only carries
|
|
51
|
+
* cross-surface metadata: the canonical names, which menu group a command shows
|
|
52
|
+
* in, and whether the command is exposed as an MCP tool.
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/** Top-level menu group for the no-arg interactive picker (null = not shown). */
|
|
56
|
+
export type MenuGroup = 'release' | 'worktrees' | 'environment'
|
|
57
|
+
|
|
58
|
+
export interface CommandCatalogEntry {
|
|
59
|
+
/** CLI command name as registered in Commander (flat form, e.g. `merge-dev`). */
|
|
60
|
+
cliName: string
|
|
61
|
+
/** Menu group, or null for subcommands not shown at the top level. */
|
|
62
|
+
menuGroup: MenuGroup | null
|
|
63
|
+
/** The co-located MCP tool, or null for CLI-only commands (init/config/vendor group). */
|
|
64
|
+
mcpTool: CatalogMcpTool | null
|
|
65
|
+
/**
|
|
66
|
+
* Whether the command is registered as an MCP tool. Explicit allowlist:
|
|
67
|
+
* `doctor`, `vendor-sync`, and `vendor-manifest` are deliberately UNEXPOSED
|
|
68
|
+
* (vendor-sync/manifest mutate consumer repos; doctor is host-inspecting), so
|
|
69
|
+
* they must never become agent-callable by accident.
|
|
70
|
+
*/
|
|
71
|
+
mcpExposed: boolean
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Authored in no-arg-menu display order so the interactive picker derives
|
|
76
|
+
* directly from this list (see entry/cli.ts). MCP registration filters this
|
|
77
|
+
* list by `mcpExposed`; MCP tool order is not contractual (clients address
|
|
78
|
+
* tools by name), so the registration order need not match the array order.
|
|
79
|
+
*/
|
|
80
|
+
export const commandCatalog: CommandCatalogEntry[] = [
|
|
81
|
+
// --- Release Management (menu group) ---
|
|
82
|
+
{ cliName: 'merge-dev', menuGroup: 'release', mcpTool: ghMergeDevMcpTool, mcpExposed: true },
|
|
83
|
+
{ cliName: 'release-list', menuGroup: 'release', mcpTool: ghReleaseListMcpTool, mcpExposed: true },
|
|
84
|
+
{ cliName: 'release-create', menuGroup: 'release', mcpTool: releaseCreateMcpTool, mcpExposed: true },
|
|
85
|
+
{ cliName: 'release-desc-edit', menuGroup: 'release', mcpTool: releaseDescEditMcpTool, mcpExposed: true },
|
|
86
|
+
{ cliName: 'release-deploy-all', menuGroup: 'release', mcpTool: ghReleaseDeployAllMcpTool, mcpExposed: true },
|
|
87
|
+
{
|
|
88
|
+
cliName: 'release-deploy-selected',
|
|
89
|
+
menuGroup: 'release',
|
|
90
|
+
mcpTool: ghReleaseDeploySelectedMcpTool,
|
|
91
|
+
mcpExposed: true,
|
|
92
|
+
},
|
|
93
|
+
// release-deliver does prod delivery + admin-merge — genuinely irreversible,
|
|
94
|
+
// so it is CLI-only by design (mirrors the vendor-sync/manifest rationale).
|
|
95
|
+
{ cliName: 'release-deliver', menuGroup: 'release', mcpTool: ghReleaseDeliverMcpTool, mcpExposed: false },
|
|
96
|
+
|
|
97
|
+
// --- Worktrees (menu group) ---
|
|
98
|
+
{ cliName: 'worktrees-add', menuGroup: 'worktrees', mcpTool: worktreesAddMcpTool, mcpExposed: true },
|
|
99
|
+
{ cliName: 'worktrees-list', menuGroup: 'worktrees', mcpTool: worktreesListMcpTool, mcpExposed: true },
|
|
100
|
+
{ cliName: 'worktrees-reload', menuGroup: 'worktrees', mcpTool: worktreesReloadMcpTool, mcpExposed: true },
|
|
101
|
+
// worktrees-remove runs rm -rf on worktree dirs — genuinely irreversible, so
|
|
102
|
+
// it is CLI-only by design (mirrors the vendor-sync/manifest rationale).
|
|
103
|
+
{ cliName: 'worktrees-remove', menuGroup: 'worktrees', mcpTool: worktreesRemoveMcpTool, mcpExposed: false },
|
|
104
|
+
{ cliName: 'worktrees-sync', menuGroup: 'worktrees', mcpTool: worktreesSyncMcpTool, mcpExposed: true },
|
|
105
|
+
|
|
106
|
+
// --- Environment (menu group) ---
|
|
107
|
+
{ cliName: 'audit', menuGroup: 'environment', mcpTool: auditMcpTool, mcpExposed: true },
|
|
108
|
+
{ cliName: 'vendor', menuGroup: 'environment', mcpTool: null, mcpExposed: false },
|
|
109
|
+
{ cliName: 'vendor-config', menuGroup: 'environment', mcpTool: null, mcpExposed: false },
|
|
110
|
+
{ cliName: 'doctor', menuGroup: 'environment', mcpTool: doctorMcpTool, mcpExposed: false },
|
|
111
|
+
{ cliName: 'init', menuGroup: 'environment', mcpTool: null, mcpExposed: false },
|
|
112
|
+
{ cliName: 'version', menuGroup: 'environment', mcpTool: versionMcpTool, mcpExposed: true },
|
|
113
|
+
{ cliName: 'config', menuGroup: 'environment', mcpTool: null, mcpExposed: false },
|
|
114
|
+
{ cliName: 'env-status', menuGroup: 'environment', mcpTool: envStatusMcpTool, mcpExposed: true },
|
|
115
|
+
{ cliName: 'env-list', menuGroup: 'environment', mcpTool: envListMcpTool, mcpExposed: true },
|
|
116
|
+
{ cliName: 'env-load', menuGroup: 'environment', mcpTool: envLoadMcpTool, mcpExposed: true },
|
|
117
|
+
{ cliName: 'env-clear', menuGroup: 'environment', mcpTool: envClearMcpTool, mcpExposed: true },
|
|
118
|
+
// Internal shell-startup trigger; hidden from the menu and never an MCP tool
|
|
119
|
+
// (it can't apply env to a shell — only the zsh integration sources the file).
|
|
120
|
+
{ cliName: 'env-autoload', menuGroup: null, mcpTool: null, mcpExposed: false },
|
|
121
|
+
|
|
122
|
+
// --- vendor subcommands (not top-level menu items; MCP tools where applicable) ---
|
|
123
|
+
{ cliName: 'vendor-check', menuGroup: null, mcpTool: vendorCheckMcpTool, mcpExposed: true },
|
|
124
|
+
{ cliName: 'vendor-diff', menuGroup: null, mcpTool: vendorDiffMcpTool, mcpExposed: true },
|
|
125
|
+
{ cliName: 'vendor-manifest', menuGroup: null, mcpTool: vendorManifestMcpTool, mcpExposed: false },
|
|
126
|
+
{ cliName: 'vendor-sync', menuGroup: null, mcpTool: vendorSyncMcpTool, mcpExposed: false },
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
/** The MCP tools to register: catalog entries that are exposed and carry a tool. */
|
|
130
|
+
export const getExposedMcpTools = (): CatalogMcpTool[] => {
|
|
131
|
+
return commandCatalog.flatMap((entry) => {
|
|
132
|
+
return entry.mcpExposed && entry.mcpTool ? [entry.mcpTool] : []
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** CLI command names for a menu group, in catalog (display) order. */
|
|
137
|
+
export const getMenuGroupCommands = (group: MenuGroup): string[] => {
|
|
138
|
+
return commandCatalog.flatMap((entry) => {
|
|
139
|
+
return entry.menuGroup === group ? [entry.cliName] : []
|
|
140
|
+
})
|
|
141
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { logger } from 'src/lib/logger'
|
|
4
|
+
|
|
5
|
+
import { commandEcho } from '../command-echo'
|
|
6
|
+
|
|
7
|
+
vi.mock('src/lib/logger', () => {
|
|
8
|
+
return { logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() } }
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const infoMock = vi.mocked(logger.info)
|
|
12
|
+
|
|
13
|
+
// The single printed argument, or undefined when print() emitted nothing.
|
|
14
|
+
const printedLine = (): string | undefined => {
|
|
15
|
+
return infoMock.mock.calls[0]?.[0] as string | undefined
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
commandEcho.reset()
|
|
20
|
+
infoMock.mockClear()
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
describe('commandEcho.print', () => {
|
|
24
|
+
it('emits nothing when the command was not interactive', () => {
|
|
25
|
+
commandEcho.start('release-create')
|
|
26
|
+
commandEcho.addOption('--yes', true)
|
|
27
|
+
|
|
28
|
+
commandEcho.print()
|
|
29
|
+
|
|
30
|
+
expect(infoMock).not.toHaveBeenCalled()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('emits nothing when interactive but no options were recorded', () => {
|
|
34
|
+
commandEcho.start('release-create')
|
|
35
|
+
commandEcho.setInteractive()
|
|
36
|
+
|
|
37
|
+
commandEcho.print()
|
|
38
|
+
|
|
39
|
+
expect(infoMock).not.toHaveBeenCalled()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it('renders a boolean true option as a bare flag and omits boolean false', () => {
|
|
43
|
+
commandEcho.start('release-create')
|
|
44
|
+
commandEcho.setInteractive()
|
|
45
|
+
commandEcho.addOption('--yes', true)
|
|
46
|
+
commandEcho.addOption('--all', false)
|
|
47
|
+
|
|
48
|
+
commandEcho.print()
|
|
49
|
+
|
|
50
|
+
const line = printedLine()
|
|
51
|
+
|
|
52
|
+
expect(line).toContain('--yes')
|
|
53
|
+
expect(line).not.toContain('--all')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('quotes a string option value', () => {
|
|
57
|
+
commandEcho.start('release-create')
|
|
58
|
+
commandEcho.setInteractive()
|
|
59
|
+
commandEcho.addOption('--release', 'checkout-redesign:regular:Q3 work')
|
|
60
|
+
|
|
61
|
+
commandEcho.print()
|
|
62
|
+
|
|
63
|
+
expect(printedLine()).toContain('--release "checkout-redesign:regular:Q3 work"')
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('joins and quotes an array option value', () => {
|
|
67
|
+
commandEcho.start('gh-merge-dev')
|
|
68
|
+
commandEcho.setInteractive()
|
|
69
|
+
commandEcho.addOption('--versions', ['1.2.5', '1.3.0'])
|
|
70
|
+
|
|
71
|
+
commandEcho.print()
|
|
72
|
+
|
|
73
|
+
expect(printedLine()).toContain('--versions "1.2.5, 1.3.0"')
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('formats the full equivalent command and round-trips the release description', () => {
|
|
77
|
+
commandEcho.start('release-create')
|
|
78
|
+
commandEcho.setInteractive()
|
|
79
|
+
commandEcho.addOption('--release', 'sponsored-banners-scroll-fix:regular:Fix scroll bug in results pages')
|
|
80
|
+
commandEcho.addOption('--yes', true)
|
|
81
|
+
|
|
82
|
+
commandEcho.print()
|
|
83
|
+
|
|
84
|
+
expect(printedLine()).toBe(
|
|
85
|
+
'📟 Equivalent command: \npnpm exec infra-kit release-create --release "sponsored-banners-scroll-fix:regular:Fix scroll bug in results pages" --yes\n',
|
|
86
|
+
)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('preserves option order and drops false-valued flags from the middle', () => {
|
|
90
|
+
commandEcho.start('release-create')
|
|
91
|
+
commandEcho.setInteractive()
|
|
92
|
+
commandEcho.addOption('--release', 'one')
|
|
93
|
+
commandEcho.addOption('--all', false)
|
|
94
|
+
commandEcho.addOption('--yes', true)
|
|
95
|
+
|
|
96
|
+
commandEcho.print()
|
|
97
|
+
|
|
98
|
+
expect(printedLine()).toBe('📟 Equivalent command: \npnpm exec infra-kit release-create --release "one" --yes\n')
|
|
99
|
+
})
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
describe('commandEcho lifecycle', () => {
|
|
103
|
+
it('start() clears options and interactive state from a prior command', () => {
|
|
104
|
+
commandEcho.start('release-create')
|
|
105
|
+
commandEcho.setInteractive()
|
|
106
|
+
commandEcho.addOption('--release', 'stale')
|
|
107
|
+
|
|
108
|
+
commandEcho.start('worktrees-add')
|
|
109
|
+
commandEcho.addOption('--versions', ['1.0.0'])
|
|
110
|
+
|
|
111
|
+
commandEcho.print()
|
|
112
|
+
|
|
113
|
+
// start() reset isInteractive to false, so print() stays silent.
|
|
114
|
+
expect(infoMock).not.toHaveBeenCalled()
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('reset() clears all state so a later print() emits nothing', () => {
|
|
118
|
+
commandEcho.start('release-create')
|
|
119
|
+
commandEcho.setInteractive()
|
|
120
|
+
commandEcho.addOption('--yes', true)
|
|
121
|
+
|
|
122
|
+
commandEcho.reset()
|
|
123
|
+
commandEcho.print()
|
|
124
|
+
|
|
125
|
+
expect(infoMock).not.toHaveBeenCalled()
|
|
126
|
+
})
|
|
127
|
+
})
|
|
@@ -10,6 +10,19 @@ export const INFRA_KIT_SESSION_VAR = 'INFRA_KIT_SESSION'
|
|
|
10
10
|
export const INFRA_KIT_ENV_CONFIG_VAR = 'INFRA_KIT_ENV_CONFIG'
|
|
11
11
|
export const INFRA_KIT_ENV_PROJECT_VAR = 'INFRA_KIT_ENV_PROJECT'
|
|
12
12
|
export const INFRA_KIT_ENV_LOADED_AT_VAR = 'INFRA_KIT_ENV_LOADED_AT'
|
|
13
|
+
/**
|
|
14
|
+
* Marker exported into env-load.sh ONLY when the load was triggered automatically
|
|
15
|
+
* (see lib/env-autoload). Its presence is the sole signal distinguishing an
|
|
16
|
+
* auto-loaded env from a deliberate manual `env-load`, so auto-load never
|
|
17
|
+
* clobbers a manual choice. A manual load unsets it.
|
|
18
|
+
*/
|
|
19
|
+
export const INFRA_KIT_ENV_AUTOLOADED_VAR = 'INFRA_KIT_ENV_AUTOLOADED'
|
|
20
|
+
/**
|
|
21
|
+
* Suppression sentinel exported by env-clear. While set in a shell, cli-invocation
|
|
22
|
+
* auto-load stays silent (a deliberate clear must not be immediately re-loaded).
|
|
23
|
+
* Lifted by a manual `env-load` or a new shell.
|
|
24
|
+
*/
|
|
25
|
+
export const INFRA_KIT_ENV_CLEARED_VAR = 'INFRA_KIT_ENV_CLEARED'
|
|
13
26
|
|
|
14
27
|
/**
|
|
15
28
|
* Matches a line of the form `KEY=...` where KEY is an env-var identifier
|