infra-kit 0.1.102 → 0.1.107
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-0a58307d-2a37-4c69-851c-83a646502d62.jsonl +1 -0
- package/.omc/state/agent-replay-11c41aa0-51fa-49e1-a1dc-26dcd6ac26cc.jsonl +16 -0
- package/.omc/state/agent-replay-4cf1c186-81b2-497c-b002-d7f84e7839f3.jsonl +9 -0
- package/.omc/state/agent-replay-5c4ab554-64f1-42ae-83e3-21e0237e955c.jsonl +11 -0
- package/.omc/state/agent-replay-a60ac2ec-afbd-449f-a540-6df287392fc2.jsonl +1 -0
- package/.omc/state/agent-replay-afc6290b-40d3-4bef-b3b6-14484c034ab9.jsonl +14 -0
- package/.omc/state/agent-replay-be37e426-6fc8-47f4-8178-221c8494551c.jsonl +3 -0
- package/.omc/state/agent-replay-c967c819-3d1c-447b-ab48-56a8448ef9f8.jsonl +2 -0
- package/.omc/state/agent-replay-e947a3c6-989d-4a60-91dd-6b0ddd827b2d.jsonl +3 -0
- package/.omc/state/idle-notif-cooldown.json +3 -0
- package/.omc/state/last-tool-error.json +4 -4
- package/.omc/state/mission-state.json +53 -0
- package/.omc/state/sessions/0a58307d-2a37-4c69-851c-83a646502d62/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/0a58307d-2a37-4c69-851c-83a646502d62/subagent-tracking-state.json +7 -0
- package/.omc/state/sessions/11c41aa0-51fa-49e1-a1dc-26dcd6ac26cc/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/11c41aa0-51fa-49e1-a1dc-26dcd6ac26cc/mission-state.json +117 -0
- package/.omc/state/sessions/11c41aa0-51fa-49e1-a1dc-26dcd6ac26cc/pre-tool-advisory-throttle.json +42 -0
- package/.omc/state/sessions/11c41aa0-51fa-49e1-a1dc-26dcd6ac26cc/subagent-tracking-state.json +53 -0
- package/.omc/state/sessions/4cf1c186-81b2-497c-b002-d7f84e7839f3/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/4cf1c186-81b2-497c-b002-d7f84e7839f3/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/4cf1c186-81b2-497c-b002-d7f84e7839f3/subagent-tracking-state.json +7 -0
- package/.omc/state/sessions/5c4ab554-64f1-42ae-83e3-21e0237e955c/mission-state.json +117 -0
- package/.omc/state/sessions/5c4ab554-64f1-42ae-83e3-21e0237e955c/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/5c4ab554-64f1-42ae-83e3-21e0237e955c/subagent-tracking-state.json +17 -0
- package/.omc/state/sessions/a60ac2ec-afbd-449f-a540-6df287392fc2/pre-tool-advisory-throttle.json +18 -0
- package/.omc/state/sessions/a60ac2ec-afbd-449f-a540-6df287392fc2/subagent-tracking-state.json +7 -0
- package/.omc/state/sessions/afc6290b-40d3-4bef-b3b6-14484c034ab9/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/afc6290b-40d3-4bef-b3b6-14484c034ab9/mission-state.json +89 -0
- package/.omc/state/sessions/afc6290b-40d3-4bef-b3b6-14484c034ab9/pre-tool-advisory-throttle.json +34 -0
- package/.omc/state/sessions/afc6290b-40d3-4bef-b3b6-14484c034ab9/ralph-state.json +13 -0
- package/.omc/state/sessions/afc6290b-40d3-4bef-b3b6-14484c034ab9/skill-active-state.json +15 -0
- package/.omc/state/sessions/afc6290b-40d3-4bef-b3b6-14484c034ab9/subagent-tracking-state.json +35 -0
- package/.omc/state/sessions/afc6290b-40d3-4bef-b3b6-14484c034ab9/ultrawork-state.json +11 -0
- package/.omc/state/sessions/c967c819-3d1c-447b-ab48-56a8448ef9f8/pre-tool-advisory-throttle.json +10 -0
- package/.omc/state/sessions/c967c819-3d1c-447b-ab48-56a8448ef9f8/subagent-tracking-state.json +7 -0
- package/.omc/state/sessions/e947a3c6-989d-4a60-91dd-6b0ddd827b2d/last-tool-error-state.json +7 -0
- package/.omc/state/sessions/e947a3c6-989d-4a60-91dd-6b0ddd827b2d/pre-tool-advisory-throttle.json +10 -0
- package/.omc/state/sessions/e947a3c6-989d-4a60-91dd-6b0ddd827b2d/subagent-tracking-state.json +26 -0
- package/.omc/state/subagent-tracking.json +14 -4
- package/.turbo/turbo-build.log +7 -0
- package/.turbo/turbo-check.log +14 -0
- package/.turbo/turbo-prettier-fix.log +2 -1
- package/.turbo/turbo-test.log +28 -5
- package/.turbo/turbo-validate.log +14 -0
- package/dist/cli.js +88 -74
- package/dist/cli.js.map +4 -4
- package/dist/entry/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +7 -0
- package/dist/lib/package-config/package-config.d.ts +71 -0
- package/dist/mcp.js +43 -41
- package/dist/mcp.js.map +4 -4
- package/eslint.config.js +1 -1
- package/infra-kit.config.ts +5 -0
- package/package.json +20 -13
- package/scripts/build.js +32 -3
- package/src/.omc/state/sessions/0a58307d-2a37-4c69-851c-83a646502d62/pre-tool-advisory-throttle.json +18 -0
- package/src/commands/.omc/state/sessions/afc6290b-40d3-4bef-b3b6-14484c034ab9/pre-tool-advisory-throttle.json +14 -0
- package/src/commands/.omc/state/sessions/c967c819-3d1c-447b-ab48-56a8448ef9f8/pre-tool-advisory-throttle.json +18 -0
- package/src/commands/audit/__tests__/audit.test.ts +59 -0
- package/src/commands/audit/audit.ts +177 -0
- package/src/commands/audit/index.ts +1 -0
- package/src/commands/config/config.ts +49 -7
- package/src/commands/doctor/__tests__/agent-files.test.ts +110 -0
- package/src/commands/doctor/doctor.ts +69 -4
- package/src/commands/env-clear/env-clear.ts +1 -1
- package/src/commands/env-list/env-list.ts +3 -3
- package/src/commands/env-load/env-load.ts +1 -1
- package/src/commands/env-status/env-status.ts +1 -1
- package/src/commands/gh-merge-dev/gh-merge-dev.ts +3 -8
- package/src/commands/gh-release-deliver/gh-release-deliver.ts +47 -21
- package/src/commands/gh-release-deploy-all/gh-release-deploy-all.ts +13 -7
- package/src/commands/gh-release-deploy-selected/gh-release-deploy-selected.ts +12 -6
- package/src/commands/gh-release-list/gh-release-list.ts +19 -8
- package/src/commands/init/__tests__/agent-files.test.ts +147 -0
- package/src/commands/init/__tests__/migrate-config.test.ts +160 -0
- package/src/commands/init/agent-files.ts +199 -0
- package/src/commands/init/index.ts +7 -0
- package/src/commands/init/init.ts +82 -60
- package/src/commands/init/migrate-config.ts +146 -0
- package/src/commands/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/src/commands/release-create/__tests__/release-create.test.ts +55 -0
- package/src/commands/release-create/release-create.ts +142 -38
- package/src/commands/release-desc-edit/release-desc-edit.ts +28 -8
- package/src/commands/version/version.ts +1 -1
- package/src/commands/worktrees-add/worktrees-add.ts +7 -12
- package/src/commands/worktrees-list/worktrees-list.ts +13 -5
- package/src/commands/worktrees-open/worktrees-open.ts +1 -1
- package/src/commands/worktrees-remove/worktrees-remove.ts +6 -10
- package/src/commands/worktrees-sync/worktrees-sync.ts +3 -5
- package/src/entry/cli.ts +50 -7
- package/src/entry/index.ts +5 -0
- package/src/integrations/cmux/open-workspace-with-layout.ts +4 -4
- package/src/integrations/cmux/workspace-title.ts +10 -4
- package/src/integrations/doppler/doppler-project.ts +1 -1
- package/src/integrations/gh/gh-release-prs/__tests__/gh-release-prs.test.ts +115 -0
- package/src/integrations/gh/gh-release-prs/gh-release-prs.ts +49 -32
- package/src/lib/.omc/state/sessions/a60ac2ec-afbd-449f-a540-6df287392fc2/pre-tool-advisory-throttle.json +14 -0
- package/src/lib/constants/index.ts +15 -0
- package/src/lib/git-utils/__tests__/git-utils.test.ts +49 -0
- package/src/lib/git-utils/git-utils.ts +3 -1
- package/src/lib/infra-kit-config/__tests__/infra-kit-config.test.ts +270 -0
- package/src/lib/infra-kit-config/index.ts +7 -1
- package/src/lib/infra-kit-config/infra-kit-config.ts +46 -28
- package/src/lib/managed-block/__tests__/managed-block.test.ts +121 -0
- package/src/lib/managed-block/index.ts +8 -0
- package/src/lib/managed-block/managed-block.ts +145 -0
- package/src/lib/package-config/__tests__/package-config.test.ts +95 -0
- package/src/lib/package-config/index.ts +3 -0
- package/src/lib/package-config/package-config-schema.ts +19 -0
- package/src/lib/package-config/package-config.ts +99 -0
- package/src/lib/package-validator/__tests__/package-validator.test.ts +263 -0
- package/src/lib/package-validator/checks/__tests__/checks.test.ts +130 -0
- package/src/lib/package-validator/checks/config-check.ts +30 -0
- package/src/lib/package-validator/checks/files-check.ts +29 -0
- package/src/lib/package-validator/checks/index.ts +4 -0
- package/src/lib/package-validator/checks/scripts-check.ts +23 -0
- package/src/lib/package-validator/checks/turbo-check.ts +47 -0
- package/src/lib/package-validator/fs-utils.ts +18 -0
- package/src/lib/package-validator/index.ts +3 -0
- package/src/lib/package-validator/loader/config-loader.ts +77 -0
- package/src/lib/package-validator/loader/index.ts +2 -0
- package/src/lib/package-validator/loader/package-discovery.ts +98 -0
- package/src/lib/package-validator/package-validator.ts +48 -0
- package/src/lib/package-validator/types.ts +15 -0
- package/src/lib/release-id/__tests__/release-id.test.ts +351 -0
- package/src/lib/release-id/__tests__/versioned-regression.test.ts +69 -0
- package/src/lib/release-id/index.ts +15 -0
- package/src/lib/release-id/release-id.ts +257 -0
- package/src/lib/release-utils/__tests__/release-utils.test.ts +122 -0
- package/src/lib/release-utils/index.ts +4 -0
- package/src/lib/release-utils/release-utils.ts +85 -17
- package/src/lib/version-utils/__tests__/load-existing-versions.test.ts +37 -0
- package/src/lib/version-utils/__tests__/next-version.test.ts +119 -13
- package/src/lib/version-utils/index.ts +3 -0
- package/src/lib/version-utils/load-existing-versions.ts +29 -10
- package/src/lib/version-utils/next-version.ts +67 -12
- package/src/lib/version-utils/version-utils.ts +13 -4
- package/src/mcp/tools/index.ts +2 -0
- package/src/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -0
- package/src/types.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/src/lib/__tests__/infra-kit-config.test.ts +0 -231
- /package/src/integrations/{clickup → linear}/.gitkeep +0 -0
- /package/src/lib/{__tests__ → constants/__tests__}/constants.test.ts +0 -0
- /package/src/lib/{constants.ts → constants/constants.ts} +0 -0
|
@@ -3,6 +3,10 @@ import os from 'node:os'
|
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
|
|
5
5
|
import { logger } from 'src/lib/logger'
|
|
6
|
+
import { removeManagedBlock, upsertManagedBlock } from 'src/lib/managed-block'
|
|
7
|
+
|
|
8
|
+
import { writeAgentFiles } from './agent-files'
|
|
9
|
+
import { migrateLegacyConfig } from './migrate-config'
|
|
6
10
|
|
|
7
11
|
export const MARKER_START = '# -- infra-kit:begin --'
|
|
8
12
|
export const MARKER_END = '# -- infra-kit:end --'
|
|
@@ -10,76 +14,94 @@ export const MARKER_END = '# -- infra-kit:end --'
|
|
|
10
14
|
const LEGACY_PAIRED: [start: string, end: string][] = [['# region infra-kit', '# endregion infra-kit']]
|
|
11
15
|
const LEGACY_SINGLE = '# infra-kit shell functions'
|
|
12
16
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
17
|
+
// JSON can't carry comments, so the real config is an empty-but-valid object…
|
|
18
|
+
const USER_GLOBAL_CONFIG_STUB = '{}\n'
|
|
19
|
+
|
|
20
|
+
// …and the annotated guidance lives next to it in a non-loaded .example.jsonc
|
|
21
|
+
// (the loader only reads the three exact `infra-kit.json` / `config.json` files).
|
|
22
|
+
const USER_GLOBAL_CONFIG_EXAMPLE = `// infra-kit user-global config — ~/.infra-kit/config.json
|
|
23
|
+
//
|
|
24
|
+
// Merge chain (later layers override earlier ones at top-level keys):
|
|
25
|
+
// 1. <repo>/infra-kit.json — committed project config (required)
|
|
26
|
+
// 2. ~/.infra-kit/config.json — user-global (the sibling of this file)
|
|
27
|
+
// 3. ~/.infra-kit/projects/<repo-name>/infra-kit.json — user-scope per-project override
|
|
28
|
+
//
|
|
29
|
+
// Merge is shallow: setting a top-level key replaces that whole section from
|
|
30
|
+
// layer 1. Arrays do not concatenate. Top-level keys recognized:
|
|
31
|
+
// environments, envManagement, ide, taskManager, worktrees.
|
|
32
|
+
//
|
|
33
|
+
// This .example.jsonc is reference only — it is NOT loaded. Put real global
|
|
34
|
+
// overrides in the sibling config.json (strict JSON: no comments, double-quoted
|
|
35
|
+
// keys). Per-project tweaks belong in layer 3 — run \`infra-kit config edit\`.
|
|
36
|
+
{
|
|
37
|
+
// "ide": {
|
|
38
|
+
// "provider": "cursor",
|
|
39
|
+
// "config": { "mode": "workspace", "workspaceConfigPath": "/path/to/your.code-workspace" }
|
|
40
|
+
// },
|
|
41
|
+
// "worktrees": { "openInGithubDesktop": false, "openInCmux": true }
|
|
42
|
+
}
|
|
38
43
|
`
|
|
39
44
|
|
|
40
45
|
/**
|
|
41
|
-
* Append infra-kit shell functions to .zshrc
|
|
42
|
-
*
|
|
43
|
-
*
|
|
46
|
+
* Append infra-kit shell functions to .zshrc, migrate any legacy
|
|
47
|
+
* `infra-kit.yml` config layers to JSON, and seed the user-global config at
|
|
48
|
+
* ~/.infra-kit/config.json on first run. Idempotent: a subsequent run replaces
|
|
49
|
+
* the existing zshrc block in place, has nothing left to migrate, and leaves
|
|
44
50
|
* the user-global config untouched.
|
|
45
51
|
*
|
|
46
52
|
* @example
|
|
47
53
|
* // CLI: `infra-kit init` (or via the `pnpm dx-init` alias)
|
|
48
54
|
* // INFO: Added infra-kit shell functions to /Users/me/.zshrc
|
|
49
|
-
* // INFO: Wrote user-global config
|
|
55
|
+
* // INFO: Wrote user-global config to /Users/me/.infra-kit/config.json (see …/config.example.jsonc …)
|
|
50
56
|
* // INFO: Run `source ~/.zshrc` or open a new terminal to activate.
|
|
51
57
|
*/
|
|
52
58
|
export const init = async (): Promise<void> => {
|
|
53
59
|
const zshrcPath = path.join(os.homedir(), '.zshrc')
|
|
54
|
-
const shellBlock = buildShellBlock()
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
// Strip any prior block (current or legacy markers) anywhere in the file, then
|
|
62
|
+
// append a fresh block at end-of-file via the shared managed-block utility —
|
|
63
|
+
// the historical `removeExistingBlock` + append behavior, now centralized.
|
|
64
|
+
const existing = fs.existsSync(zshrcPath) ? removeExistingBlock(fs.readFileSync(zshrcPath, 'utf-8')) : ''
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
|
|
66
|
+
const updated = upsertManagedBlock({
|
|
67
|
+
content: existing,
|
|
68
|
+
body: buildShellBody(),
|
|
69
|
+
startMarker: MARKER_START,
|
|
70
|
+
endMarker: MARKER_END,
|
|
71
|
+
placement: 'append-end',
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
fs.writeFileSync(zshrcPath, updated)
|
|
62
75
|
|
|
63
|
-
fs.appendFileSync(zshrcPath, `\n${shellBlock}\n`)
|
|
64
76
|
logger.info(`Added infra-kit shell functions to ${zshrcPath}`)
|
|
65
77
|
|
|
78
|
+
// Convert any legacy infra-kit.yml config layers to JSON before seeding, so a
|
|
79
|
+
// migrated config.json is not re-seeded as an empty stub.
|
|
80
|
+
await migrateLegacyConfig()
|
|
81
|
+
|
|
66
82
|
seedUserGlobalConfig()
|
|
67
83
|
|
|
84
|
+
// Best-effort, non-fatal, repo-gated: keep the agent-instruction files in sync
|
|
85
|
+
// with the CLI surface. A no-op outside an infra-kit repo.
|
|
86
|
+
await writeAgentFiles()
|
|
87
|
+
|
|
68
88
|
logger.info('Run `source ~/.zshrc` or open a new terminal to activate.')
|
|
69
89
|
}
|
|
70
90
|
|
|
71
91
|
/**
|
|
72
|
-
* Create `~/.infra-kit/config.
|
|
73
|
-
*
|
|
92
|
+
* Create `~/.infra-kit/config.json` (empty `{}`) plus an annotated
|
|
93
|
+
* `~/.infra-kit/config.example.jsonc` reference when absent. Skips silently if
|
|
94
|
+
* the config already exists so user edits are preserved.
|
|
74
95
|
*
|
|
75
96
|
* @example
|
|
76
97
|
* seedUserGlobalConfig()
|
|
77
|
-
* // first call: writes ~/.infra-kit/config.
|
|
78
|
-
* // later calls: leaves the
|
|
98
|
+
* // first call: writes ~/.infra-kit/config.json ({}) + config.example.jsonc
|
|
99
|
+
* // later calls: leaves the config alone, logs that it is already present
|
|
79
100
|
*/
|
|
80
101
|
const seedUserGlobalConfig = (): void => {
|
|
81
102
|
const userConfigDir = path.join(os.homedir(), '.infra-kit')
|
|
82
|
-
const userConfigPath = path.join(userConfigDir, 'config.
|
|
103
|
+
const userConfigPath = path.join(userConfigDir, 'config.json')
|
|
104
|
+
const userConfigExamplePath = path.join(userConfigDir, 'config.example.jsonc')
|
|
83
105
|
|
|
84
106
|
if (fs.existsSync(userConfigPath)) {
|
|
85
107
|
logger.info(`User-global config already present at ${userConfigPath}`)
|
|
@@ -89,8 +111,11 @@ const seedUserGlobalConfig = (): void => {
|
|
|
89
111
|
|
|
90
112
|
fs.mkdirSync(userConfigDir, { recursive: true })
|
|
91
113
|
fs.writeFileSync(userConfigPath, USER_GLOBAL_CONFIG_STUB, 'utf-8')
|
|
114
|
+
fs.writeFileSync(userConfigExamplePath, USER_GLOBAL_CONFIG_EXAMPLE, 'utf-8')
|
|
92
115
|
|
|
93
|
-
logger.info(
|
|
116
|
+
logger.info(
|
|
117
|
+
`Wrote user-global config to ${userConfigPath} (see ${userConfigExamplePath} for the annotated reference)`,
|
|
118
|
+
)
|
|
94
119
|
}
|
|
95
120
|
|
|
96
121
|
const isBlockLine = (line: string): boolean => {
|
|
@@ -112,28 +137,15 @@ const isBlockLine = (line: string): boolean => {
|
|
|
112
137
|
)
|
|
113
138
|
}
|
|
114
139
|
|
|
115
|
-
const removeBetween = (content: string, start: string, end: string): string | null => {
|
|
116
|
-
const startIdx = content.indexOf(start)
|
|
117
|
-
const endIdx = content.indexOf(end)
|
|
118
|
-
|
|
119
|
-
if (startIdx === -1 || endIdx === -1) return null
|
|
120
|
-
|
|
121
|
-
// eslint-disable-next-line sonarjs/slow-regex
|
|
122
|
-
const before = content.slice(0, startIdx).replace(/\n+$/, '')
|
|
123
|
-
const after = content.slice(endIdx + end.length).replace(/^\n+/, '')
|
|
124
|
-
|
|
125
|
-
return before + (after ? `\n${after}` : '')
|
|
126
|
-
}
|
|
127
|
-
|
|
128
140
|
const removeExistingBlock = (content: string): string => {
|
|
129
141
|
// 1. Current markers
|
|
130
|
-
const result =
|
|
142
|
+
const result = removeManagedBlock(content, MARKER_START, MARKER_END)
|
|
131
143
|
|
|
132
144
|
if (result !== null) return result
|
|
133
145
|
|
|
134
146
|
// 2. Legacy paired markers (# region / # endregion)
|
|
135
147
|
for (const [start, end] of LEGACY_PAIRED) {
|
|
136
|
-
const legacyResult =
|
|
148
|
+
const legacyResult = removeManagedBlock(content, start, end)
|
|
137
149
|
|
|
138
150
|
if (legacyResult !== null) return legacyResult
|
|
139
151
|
}
|
|
@@ -158,11 +170,14 @@ const removeExistingBlock = (content: string): string => {
|
|
|
158
170
|
return before + (remaining ? `\n${remaining}` : '')
|
|
159
171
|
}
|
|
160
172
|
|
|
161
|
-
|
|
173
|
+
/**
|
|
174
|
+
* The inner shell-function lines (no markers). Composed into the full marked
|
|
175
|
+
* block by {@link buildShellBlock} and fed to `upsertManagedBlock` by `init()`.
|
|
176
|
+
*/
|
|
177
|
+
export const buildShellBody = (): string => {
|
|
162
178
|
const runCmd = 'pnpm exec infra-kit'
|
|
163
179
|
|
|
164
180
|
return [
|
|
165
|
-
MARKER_START,
|
|
166
181
|
'zmodload zsh/stat 2>/dev/null',
|
|
167
182
|
'zmodload zsh/datetime 2>/dev/null',
|
|
168
183
|
// eslint-disable-next-line no-template-curly-in-string
|
|
@@ -210,6 +225,13 @@ export const buildShellBlock = (): string => {
|
|
|
210
225
|
'if (( _INFRA_KIT_SHELL_STARTED > 0 )); then',
|
|
211
226
|
' add-zsh-hook precmd _infra_kit_autoload',
|
|
212
227
|
'fi',
|
|
213
|
-
MARKER_END,
|
|
214
228
|
].join('\n')
|
|
215
229
|
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* The full marker-delimited shell block (`MARKER_START … MARKER_END`). Kept as
|
|
233
|
+
* a single composed string so `doctor`'s exact-match freshness check stays valid.
|
|
234
|
+
*/
|
|
235
|
+
export const buildShellBlock = (): string => {
|
|
236
|
+
return `${MARKER_START}\n${buildShellBody()}\n${MARKER_END}`
|
|
237
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import fs from 'node:fs/promises'
|
|
2
|
+
import os from 'node:os'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
import yaml from 'yaml'
|
|
5
|
+
import { z } from 'zod'
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
getInfraKitConfigPaths,
|
|
9
|
+
infraKitConfigSchema,
|
|
10
|
+
infraKitOverrideConfigSchema,
|
|
11
|
+
resetInfraKitConfigCache,
|
|
12
|
+
} from 'src/lib/infra-kit-config'
|
|
13
|
+
import { logger } from 'src/lib/logger'
|
|
14
|
+
|
|
15
|
+
interface MigrateLayer {
|
|
16
|
+
label: string
|
|
17
|
+
/** Legacy YAML source path. */
|
|
18
|
+
yml: string
|
|
19
|
+
/** Target JSON path. */
|
|
20
|
+
json: string
|
|
21
|
+
/** Validates the parsed object before any write (main vs override schema). */
|
|
22
|
+
schema: z.ZodType
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Replace the user's home prefix with `~` so logged paths stay short.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* // os.homedir() === '/Users/arthur'
|
|
30
|
+
* tildify('/Users/arthur/.infra-kit/config.yml') // => '~/.infra-kit/config.yml'
|
|
31
|
+
*/
|
|
32
|
+
const tildify = (filePath: string): string => {
|
|
33
|
+
const home = os.homedir()
|
|
34
|
+
|
|
35
|
+
return filePath.startsWith(home) ? `~${filePath.slice(home.length)}` : filePath
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* `fs.access` reduced to a boolean, swallowing ENOENT.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* await fileExists('/etc/hosts') // => true
|
|
43
|
+
*/
|
|
44
|
+
const fileExists = async (filePath: string): Promise<boolean> => {
|
|
45
|
+
try {
|
|
46
|
+
await fs.access(filePath)
|
|
47
|
+
|
|
48
|
+
return true
|
|
49
|
+
} catch {
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Swap a resolved `.json` config path back to its legacy `.yml` sibling.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* legacyYmlPath('/repo/infra-kit.json') // => '/repo/infra-kit.yml'
|
|
59
|
+
*/
|
|
60
|
+
const legacyYmlPath = (jsonPath: string): string => {
|
|
61
|
+
return jsonPath.replace(/\.json$/, '.yml')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Convert any legacy `infra-kit.yml` config layers to `infra-kit.json` as part
|
|
66
|
+
* of `infra-kit init`. Best-effort and non-fatal: each merge-chain layer
|
|
67
|
+
* (project, user-global, user-project) is migrated independently, and a
|
|
68
|
+
* conflict (both `.yml` and `.json` present) or an invalid `.yml` warns and
|
|
69
|
+
* skips that layer rather than aborting init or touching the other layers.
|
|
70
|
+
* Idempotent — already-JSON layers are left untouched.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* await migrateLegacyConfig()
|
|
74
|
+
* // INFO: ✓ Migrated infra-kit.yml → infra-kit.json
|
|
75
|
+
* // (no output when there is nothing legacy to convert)
|
|
76
|
+
*/
|
|
77
|
+
export const migrateLegacyConfig = async (): Promise<void> => {
|
|
78
|
+
let paths: Awaited<ReturnType<typeof getInfraKitConfigPaths>>
|
|
79
|
+
|
|
80
|
+
try {
|
|
81
|
+
paths = await getInfraKitConfigPaths()
|
|
82
|
+
} catch {
|
|
83
|
+
// No resolvable project (e.g. init run outside a repo) — nothing to migrate.
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const layers: MigrateLayer[] = [
|
|
88
|
+
{ label: 'infra-kit.json', yml: legacyYmlPath(paths.main), json: paths.main, schema: infraKitConfigSchema },
|
|
89
|
+
{
|
|
90
|
+
label: '~/.infra-kit/config.json',
|
|
91
|
+
yml: legacyYmlPath(paths.userGlobal),
|
|
92
|
+
json: paths.userGlobal,
|
|
93
|
+
schema: infraKitOverrideConfigSchema,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
label: `~/.infra-kit/projects/${paths.projectName}/infra-kit.json`,
|
|
97
|
+
yml: legacyYmlPath(paths.userProject),
|
|
98
|
+
json: paths.userProject,
|
|
99
|
+
schema: infraKitOverrideConfigSchema,
|
|
100
|
+
},
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
let migrated = 0
|
|
104
|
+
|
|
105
|
+
for (const layer of layers) {
|
|
106
|
+
const [ymlExists, jsonExists] = await Promise.all([fileExists(layer.yml), fileExists(layer.json)])
|
|
107
|
+
|
|
108
|
+
if (!ymlExists) continue
|
|
109
|
+
|
|
110
|
+
if (jsonExists) {
|
|
111
|
+
logger.info(
|
|
112
|
+
`⚠ Skipped ${tildify(layer.yml)} — ${tildify(layer.json)} already exists (remove the stale .yml manually)`,
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
continue
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Keep per-layer migration non-fatal even for malformed YAML or I/O errors
|
|
119
|
+
// (TOCTOU after the existence probe, EACCES, read-only FS): warn and skip
|
|
120
|
+
// so one bad layer never aborts `init` or the other layers.
|
|
121
|
+
try {
|
|
122
|
+
const raw = await fs.readFile(layer.yml, 'utf-8')
|
|
123
|
+
const parsed = (yaml.parse(raw) ?? {}) as unknown
|
|
124
|
+
const result = layer.schema.safeParse(parsed)
|
|
125
|
+
|
|
126
|
+
if (!result.success) {
|
|
127
|
+
logger.info(`⚠ Skipped ${tildify(layer.yml)} — invalid config: ${z.prettifyError(result.error)}`)
|
|
128
|
+
|
|
129
|
+
continue
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
await fs.mkdir(path.dirname(layer.json), { recursive: true })
|
|
133
|
+
await fs.writeFile(layer.json, `${JSON.stringify(result.data, null, 2)}\n`, 'utf-8')
|
|
134
|
+
await fs.rm(layer.yml, { force: true })
|
|
135
|
+
|
|
136
|
+
logger.info(`✓ Migrated ${tildify(layer.yml)} → ${tildify(layer.json)}`)
|
|
137
|
+
migrated++
|
|
138
|
+
} catch (err) {
|
|
139
|
+
logger.info(`⚠ Skipped ${tildify(layer.yml)} — ${(err as Error).message}`)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (migrated > 0) {
|
|
144
|
+
resetInfraKitConfigCache()
|
|
145
|
+
}
|
|
146
|
+
}
|
package/src/commands/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"4.1.8","results":[[":audit/__tests__/audit.test.ts",{"duration":0,"failed":true}]]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import type { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
import { releaseCreateMcpTool } from '../release-create'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The MCP `releases[]` entry schema enforces that exactly one of `version` or
|
|
8
|
+
* `name` is supplied, and transforms each entry into the internal ReleaseInput
|
|
9
|
+
* shape. We exercise the schema directly (the array element) so we do not need
|
|
10
|
+
* to run the full handler (which performs git/Jira side effects).
|
|
11
|
+
*/
|
|
12
|
+
const entrySchema = (releaseCreateMcpTool.inputSchema.releases as z.ZodArray<z.ZodTypeAny>).element
|
|
13
|
+
|
|
14
|
+
describe('release-create MCP releases[] entry schema', () => {
|
|
15
|
+
it('accepts a versioned entry and transforms it into a version ReleaseInput', () => {
|
|
16
|
+
expect(entrySchema.parse({ version: '1.2.5', type: 'hotfix' })).toEqual({
|
|
17
|
+
version: '1.2.5',
|
|
18
|
+
type: 'hotfix',
|
|
19
|
+
})
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('defaults type to regular', () => {
|
|
23
|
+
expect(entrySchema.parse({ version: '1.2.5' })).toEqual({
|
|
24
|
+
version: '1.2.5',
|
|
25
|
+
type: 'regular',
|
|
26
|
+
})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('accepts a named entry and transforms it into a name ReleaseInput', () => {
|
|
30
|
+
expect(entrySchema.parse({ name: 'checkout-redesign', type: 'regular' })).toEqual({
|
|
31
|
+
name: 'checkout-redesign',
|
|
32
|
+
type: 'regular',
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it('carries description through for named entries', () => {
|
|
37
|
+
expect(entrySchema.parse({ name: 'checkout-redesign', description: 'Q3' })).toEqual({
|
|
38
|
+
name: 'checkout-redesign',
|
|
39
|
+
type: 'regular',
|
|
40
|
+
description: 'Q3',
|
|
41
|
+
})
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('rejects an entry with both version and name (mutually exclusive)', () => {
|
|
45
|
+
expect(() => {
|
|
46
|
+
return entrySchema.parse({ version: '1.2.5', name: 'checkout-redesign' })
|
|
47
|
+
}).toThrow(/exactly one of/)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('rejects an entry with neither version nor name', () => {
|
|
51
|
+
expect(() => {
|
|
52
|
+
return entrySchema.parse({ type: 'regular' })
|
|
53
|
+
}).toThrow(/exactly one of/)
|
|
54
|
+
})
|
|
55
|
+
})
|