infra-kit 0.1.111 → 0.1.114

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.
Files changed (99) hide show
  1. package/.eslintcache +1 -1
  2. package/.omc/state/agent-replay-0d1515ce-4ebe-4ce8-a865-2897f68de168.jsonl +1 -0
  3. package/.omc/state/agent-replay-127837d3-a000-4656-9453-2324ab353723.jsonl +5 -0
  4. package/.omc/state/agent-replay-15c409af-24fa-4026-88d3-a82dd1e68b87.jsonl +11 -0
  5. package/.omc/state/agent-replay-74afa912-1443-4011-b4f2-db9f055cdd9f.jsonl +3 -0
  6. package/.omc/state/agent-replay-8dd0ad2f-3a90-4158-b9de-ec8e19a7c983.jsonl +3 -0
  7. package/.omc/state/agent-replay-f99d8dad-81d1-4987-8183-62edf0843d0c.jsonl +2 -0
  8. package/.omc/state/idle-notif-cooldown.json +1 -1
  9. package/.omc/state/sessions/0d1515ce-4ebe-4ce8-a865-2897f68de168/pre-tool-advisory-throttle.json +10 -0
  10. package/.omc/state/sessions/127837d3-a000-4656-9453-2324ab353723/mission-state.json +61 -0
  11. package/.omc/state/sessions/127837d3-a000-4656-9453-2324ab353723/pre-tool-advisory-throttle.json +22 -0
  12. package/.omc/state/sessions/127837d3-a000-4656-9453-2324ab353723/skill-active-state.json +15 -0
  13. package/.omc/state/sessions/127837d3-a000-4656-9453-2324ab353723/subagent-tracking-state.json +26 -0
  14. package/.omc/state/sessions/15c409af-24fa-4026-88d3-a82dd1e68b87/last-tool-error-state.json +7 -0
  15. package/.omc/state/sessions/15c409af-24fa-4026-88d3-a82dd1e68b87/mission-state.json +89 -0
  16. package/.omc/state/sessions/15c409af-24fa-4026-88d3-a82dd1e68b87/pre-tool-advisory-throttle.json +34 -0
  17. package/.omc/state/sessions/15c409af-24fa-4026-88d3-a82dd1e68b87/ralph-state.json +13 -0
  18. package/.omc/state/sessions/15c409af-24fa-4026-88d3-a82dd1e68b87/skill-active-state.json +15 -0
  19. package/.omc/state/sessions/15c409af-24fa-4026-88d3-a82dd1e68b87/subagent-tracking-state.json +44 -0
  20. package/.omc/state/sessions/15c409af-24fa-4026-88d3-a82dd1e68b87/ultrawork-state.json +11 -0
  21. package/.omc/state/sessions/560ea519-574a-4713-b134-5bf6cfaf3c33/pre-tool-advisory-throttle.json +18 -0
  22. package/.omc/state/sessions/74afa912-1443-4011-b4f2-db9f055cdd9f/pre-tool-advisory-throttle.json +18 -0
  23. package/.omc/state/sessions/74afa912-1443-4011-b4f2-db9f055cdd9f/skill-active-state.json +15 -0
  24. package/.omc/state/sessions/74afa912-1443-4011-b4f2-db9f055cdd9f/subagent-tracking-state.json +17 -0
  25. package/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/pre-tool-advisory-throttle.json +14 -0
  26. package/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/ralph-state.json +13 -0
  27. package/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/subagent-tracking-state.json +17 -0
  28. package/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/ultrawork-state.json +11 -0
  29. package/.omc/state/sessions/f99d8dad-81d1-4987-8183-62edf0843d0c/pre-tool-advisory-throttle.json +14 -0
  30. package/.omc/state/sessions/f99d8dad-81d1-4987-8183-62edf0843d0c/ralph-state.json +13 -0
  31. package/.omc/state/sessions/f99d8dad-81d1-4987-8183-62edf0843d0c/ultrawork-state.json +11 -0
  32. package/.turbo/turbo-build.log +3 -4
  33. package/.turbo/turbo-eslint-check.log +1 -2
  34. package/.turbo/turbo-prettier-check.log +1 -2
  35. package/.turbo/turbo-prettier-fix.log +1 -2
  36. package/.turbo/turbo-test.log +25 -18
  37. package/.turbo/turbo-ts-check.log +1 -2
  38. package/dist/cli.js +62 -54
  39. package/dist/cli.js.map +4 -4
  40. package/dist/mcp.js +36 -36
  41. package/dist/mcp.js.map +4 -4
  42. package/package.json +1 -1
  43. package/src/.omc/state/agent-replay-8dd0ad2f-3a90-4158-b9de-ec8e19a7c983.jsonl +11 -0
  44. package/src/.omc/state/idle-notif-cooldown.json +3 -0
  45. package/src/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/mission-state.json +79 -0
  46. package/src/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/pre-tool-advisory-throttle.json +22 -0
  47. package/src/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/ralph-state.json +13 -0
  48. package/src/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/subagent-tracking-state.json +26 -0
  49. package/src/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/ultrawork-state.json +11 -0
  50. package/src/.omc/state/sessions/f99d8dad-81d1-4987-8183-62edf0843d0c/pre-tool-advisory-throttle.json +14 -0
  51. package/src/commands/doctor/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/pre-tool-advisory-throttle.json +14 -0
  52. package/src/commands/doctor/__tests__/check-ide-installed.test.ts +142 -0
  53. package/src/commands/doctor/doctor.ts +104 -1
  54. package/src/commands/gh-release-deliver/gh-release-deliver.ts +32 -1
  55. package/src/commands/init/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/pre-tool-advisory-throttle.json +18 -0
  56. package/src/commands/init/__tests__/migrate-config.test.ts +132 -1
  57. package/src/commands/init/init.ts +19 -6
  58. package/src/commands/init/migrate-config.ts +104 -0
  59. package/src/commands/worktrees-add/index.ts +1 -2
  60. package/src/commands/worktrees-add/worktrees-add.ts +24 -60
  61. package/src/commands/worktrees-open/worktrees-open.ts +55 -68
  62. package/src/commands/worktrees-reload/__tests__/reload-cmux.test.ts +119 -0
  63. package/src/commands/worktrees-reload/index.ts +1 -0
  64. package/src/commands/worktrees-reload/worktrees-reload.ts +229 -0
  65. package/src/commands/worktrees-remove/worktrees-remove.ts +2 -44
  66. package/src/commands/worktrees-sync/worktrees-sync.ts +2 -44
  67. package/src/entry/cli.ts +32 -11
  68. package/src/integrations/cursor/.omc/state/agent-replay-f99d8dad-81d1-4987-8183-62edf0843d0c.jsonl +2 -0
  69. package/src/integrations/cursor/.omc/state/idle-notif-cooldown.json +3 -0
  70. package/src/integrations/cursor/.omc/state/sessions/f99d8dad-81d1-4987-8183-62edf0843d0c/pre-tool-advisory-throttle.json +18 -0
  71. package/src/integrations/cursor/.omc/state/sessions/f99d8dad-81d1-4987-8183-62edf0843d0c/subagent-tracking-state.json +17 -0
  72. package/src/integrations/cursor/index.ts +2 -0
  73. package/src/integrations/cursor/launch-cursor.ts +12 -0
  74. package/src/integrations/cursor/open-cursor-workspace.ts +69 -0
  75. package/src/integrations/ide/__tests__/ide-facade.test.ts +250 -0
  76. package/src/integrations/ide/add-ide-worktree-folders.ts +77 -0
  77. package/src/integrations/ide/index.ts +6 -0
  78. package/src/integrations/ide/open-ide-workspace.ts +51 -0
  79. package/src/integrations/ide/provider-label.ts +24 -0
  80. package/src/integrations/ide/remove-ide-worktree-folders.ts +80 -0
  81. package/src/integrations/ide/types.ts +32 -0
  82. package/src/integrations/zed/__tests__/open-zed-workspace.test.ts +85 -0
  83. package/src/integrations/zed/add-folders-to-zed-workspace.ts +30 -0
  84. package/src/integrations/zed/index.ts +2 -0
  85. package/src/integrations/zed/open-zed-workspace.ts +57 -0
  86. package/src/lib/assert-never/assert-never.ts +15 -0
  87. package/src/lib/assert-never/index.ts +1 -0
  88. package/src/lib/git-utils/__tests__/git-primitives.test.ts +122 -1
  89. package/src/lib/git-utils/git-utils.ts +35 -0
  90. package/src/lib/git-utils/index.ts +2 -0
  91. package/src/lib/infra-kit-config/.omc/state/sessions/8dd0ad2f-3a90-4158-b9de-ec8e19a7c983/pre-tool-advisory-throttle.json +18 -0
  92. package/src/lib/infra-kit-config/__tests__/infra-kit-config.test.ts +172 -9
  93. package/src/lib/infra-kit-config/index.ts +2 -1
  94. package/src/lib/infra-kit-config/infra-kit-config.ts +80 -22
  95. package/src/lib/package-config/.omc/state/sessions/dde22a92-a0e9-4948-905d-25c9a812ab35/last-tool-error-state.json +7 -0
  96. package/src/lib/package-config/.omc/state/sessions/dde22a92-a0e9-4948-905d-25c9a812ab35/pre-tool-advisory-throttle.json +10 -0
  97. package/src/lib/worktrees/remove-worktrees.ts +15 -0
  98. package/src/mcp/tools/index.ts +2 -0
  99. package/tsconfig.tsbuildinfo +1 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "infra-kit",
3
3
  "type": "module",
4
- "version": "0.1.111",
4
+ "version": "0.1.114",
5
5
  "description": "infra-kit",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -0,0 +1,11 @@
1
+ {"t":0,"agent":"a5fb1bc","agent_type":"architect","event":"agent_start","parent_mode":"none"}
2
+ {"t":0,"agent":"a5fb1bc","agent_type":"architect","event":"agent_stop","success":true,"duration_ms":171283}
3
+ {"t":0,"agent":"ad5fb86","agent_type":"critic","event":"agent_start","parent_mode":"none"}
4
+ {"t":0,"agent":"ad5fb86","agent_type":"critic","event":"agent_stop","success":true,"duration_ms":150448}
5
+ {"t":0,"agent":"ad5fb86","agent_type":"critic","event":"agent_start","parent_mode":"none"}
6
+ {"t":0,"agent":"ad5fb86","agent_type":"critic","event":"agent_stop","success":true,"duration_ms":34852}
7
+ {"t":0,"agent":"system","event":"keyword_detected","keyword":"ralph"}
8
+ {"t":0,"agent":"system","event":"mode_change","mode_from":"none","mode_to":"ralph"}
9
+ {"t":0,"agent":"system","event":"skill_invoked","skill_name":"oh-my-claudecode:cancel"}
10
+ {"t":0,"agent":"system","event":"keyword_detected","keyword":"ralph"}
11
+ {"t":0,"agent":"system","event":"mode_change","mode_from":"none","mode_to":"ralph"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "lastSentAt": "2026-06-21T11:09:39.757Z"
3
+ }
@@ -0,0 +1,79 @@
1
+ {
2
+ "updatedAt": "2026-06-21T11:08:54.543Z",
3
+ "missions": [
4
+ {
5
+ "id": "session:8dd0ad2f-3a90-4158-b9de-ec8e19a7c983:none",
6
+ "source": "session",
7
+ "name": "none",
8
+ "objective": "Session mission",
9
+ "createdAt": "2026-06-21T11:00:23.527Z",
10
+ "updatedAt": "2026-06-21T11:08:54.543Z",
11
+ "status": "done",
12
+ "workerCount": 2,
13
+ "taskCounts": {
14
+ "total": 2,
15
+ "pending": 0,
16
+ "blocked": 0,
17
+ "inProgress": 0,
18
+ "completed": 2,
19
+ "failed": 0
20
+ },
21
+ "agents": [
22
+ {
23
+ "name": "architect:a5fb1bc",
24
+ "role": "architect",
25
+ "ownership": "a5fb1bc4dd2207983",
26
+ "status": "done",
27
+ "currentStep": null,
28
+ "latestUpdate": "completed",
29
+ "completedSummary": null,
30
+ "updatedAt": "2026-06-21T11:03:14.810Z"
31
+ },
32
+ {
33
+ "name": "critic:ad5fb86",
34
+ "role": "critic",
35
+ "ownership": "ad5fb865bf84b1924",
36
+ "status": "done",
37
+ "currentStep": null,
38
+ "latestUpdate": "completed",
39
+ "completedSummary": null,
40
+ "updatedAt": "2026-06-21T11:08:54.543Z"
41
+ }
42
+ ],
43
+ "timeline": [
44
+ {
45
+ "id": "session-start:ad5fb865bf84b1924:2026-06-21T11:04:55.259Z",
46
+ "at": "2026-06-21T11:04:55.259Z",
47
+ "kind": "update",
48
+ "agent": "critic:ad5fb86",
49
+ "detail": "started critic:ad5fb86",
50
+ "sourceKey": "session-start:ad5fb865bf84b1924"
51
+ },
52
+ {
53
+ "id": "session-stop:ad5fb865bf84b1924:2026-06-21T11:07:25.707Z",
54
+ "at": "2026-06-21T11:07:25.707Z",
55
+ "kind": "completion",
56
+ "agent": "critic:ad5fb86",
57
+ "detail": "completed",
58
+ "sourceKey": "session-stop:ad5fb865bf84b1924"
59
+ },
60
+ {
61
+ "id": "session-start:ad5fb865bf84b1924:2026-06-21T11:08:19.691Z",
62
+ "at": "2026-06-21T11:08:19.691Z",
63
+ "kind": "update",
64
+ "agent": "critic:ad5fb86",
65
+ "detail": "started critic:ad5fb86",
66
+ "sourceKey": "session-start:ad5fb865bf84b1924"
67
+ },
68
+ {
69
+ "id": "session-stop:ad5fb865bf84b1924:2026-06-21T11:08:54.543Z",
70
+ "at": "2026-06-21T11:08:54.543Z",
71
+ "kind": "completion",
72
+ "agent": "critic:ad5fb86",
73
+ "detail": "completed",
74
+ "sourceKey": "session-stop:ad5fb865bf84b1924"
75
+ }
76
+ ]
77
+ }
78
+ ]
79
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "version": 1,
3
+ "entries": {
4
+ "79a93d4a2f8f50b95f852280616242fee1855dc99a3c75211917f55e72e95fae": {
5
+ "last_emitted_at_ms": 1782045856683,
6
+ "message": "Use parallel execution for independent tasks. Use run_in_background for long operations (npm install, builds, tests)."
7
+ },
8
+ "445ed27a3872b681d98190bae61ccb84954e1bc4e140df5370be958dee776b3a": {
9
+ "last_emitted_at_ms": 1782045791692,
10
+ "message": "Verify changes work after editing. Test functionality before marking complete."
11
+ },
12
+ "466399dafa2d20f60587180bad0a07358eb7f2bce724df0ff682f038ad33f5ad": {
13
+ "last_emitted_at_ms": 1782045769114,
14
+ "message": "Read multiple files in parallel when possible for faster analysis."
15
+ },
16
+ "1bb6914bc42b891c26d46c8ae2fd4f44071f59862e89dc550f4c82877b700216": {
17
+ "last_emitted_at_ms": 1782045534124,
18
+ "message": "The boulder never stops. Continue until all tasks complete."
19
+ }
20
+ },
21
+ "updated_at": "2026-06-21T12:44:16.683Z"
22
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "active": true,
3
+ "iteration": 1,
4
+ "max_iterations": 100,
5
+ "started_at": "2026-06-21T12:41:30.413Z",
6
+ "prompt": "/ralph do it",
7
+ "session_id": "8dd0ad2f-3a90-4158-b9de-ec8e19a7c983",
8
+ "project_path": "/Users/arthur/projects/infra-kit/apps/infra-kit/cli/src",
9
+ "linked_ultrawork": true,
10
+ "awaiting_confirmation": true,
11
+ "awaiting_confirmation_set_at": "2026-06-21T12:41:30.413Z",
12
+ "last_checked_at": "2026-06-21T12:41:30.413Z"
13
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "agents": [
3
+ {
4
+ "agent_id": "a5fb1bc4dd2207983",
5
+ "agent_type": "oh-my-claudecode:architect",
6
+ "started_at": "2026-06-21T11:00:23.527Z",
7
+ "parent_mode": "none",
8
+ "status": "completed",
9
+ "completed_at": "2026-06-21T11:03:14.810Z",
10
+ "duration_ms": 171283
11
+ },
12
+ {
13
+ "agent_id": "ad5fb865bf84b1924",
14
+ "agent_type": "oh-my-claudecode:critic",
15
+ "started_at": "2026-06-21T11:08:19.691Z",
16
+ "parent_mode": "none",
17
+ "status": "completed",
18
+ "completed_at": "2026-06-21T11:08:54.543Z",
19
+ "duration_ms": 34852
20
+ }
21
+ ],
22
+ "total_spawned": 3,
23
+ "total_completed": 3,
24
+ "total_failed": 0,
25
+ "last_updated": "2026-06-21T11:08:54.646Z"
26
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "active": true,
3
+ "started_at": "2026-06-21T12:41:30.430Z",
4
+ "original_prompt": "/ralph do it",
5
+ "session_id": "8dd0ad2f-3a90-4158-b9de-ec8e19a7c983",
6
+ "project_path": "/Users/arthur/projects/infra-kit/apps/infra-kit/cli/src",
7
+ "reinforcement_count": 0,
8
+ "awaiting_confirmation": true,
9
+ "awaiting_confirmation_set_at": "2026-06-21T12:41:30.430Z",
10
+ "last_checked_at": "2026-06-21T12:41:30.430Z"
11
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "version": 1,
3
+ "entries": {
4
+ "79a93d4a2f8f50b95f852280616242fee1855dc99a3c75211917f55e72e95fae": {
5
+ "last_emitted_at_ms": 1782111727397,
6
+ "message": "Use parallel execution for independent tasks. Use run_in_background for long operations (npm install, builds, tests)."
7
+ },
8
+ "466399dafa2d20f60587180bad0a07358eb7f2bce724df0ff682f038ad33f5ad": {
9
+ "last_emitted_at_ms": 1782111707131,
10
+ "message": "Read multiple files in parallel when possible for faster analysis."
11
+ }
12
+ },
13
+ "updated_at": "2026-06-22T07:02:07.397Z"
14
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "version": 1,
3
+ "entries": {
4
+ "79a93d4a2f8f50b95f852280616242fee1855dc99a3c75211917f55e72e95fae": {
5
+ "last_emitted_at_ms": 1782040957960,
6
+ "message": "Use parallel execution for independent tasks. Use run_in_background for long operations (npm install, builds, tests)."
7
+ },
8
+ "445ed27a3872b681d98190bae61ccb84954e1bc4e140df5370be958dee776b3a": {
9
+ "last_emitted_at_ms": 1782040931719,
10
+ "message": "Verify changes work after editing. Test functionality before marking complete."
11
+ }
12
+ },
13
+ "updated_at": "2026-06-21T11:22:37.960Z"
14
+ }
@@ -0,0 +1,142 @@
1
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
+
3
+ import { checkIdeInstalled } from '../doctor'
4
+
5
+ const config = vi.hoisted(() => {
6
+ return { value: {} as { ide?: unknown }, shouldThrow: false }
7
+ })
8
+
9
+ vi.mock('src/lib/infra-kit-config', () => {
10
+ return {
11
+ resetInfraKitConfigCache: vi.fn(),
12
+ getInfraKitConfig: vi.fn(() => {
13
+ if (config.shouldThrow) {
14
+ return Promise.reject(new Error('bad config'))
15
+ }
16
+
17
+ return Promise.resolve(config.value)
18
+ }),
19
+ // Mirror the real normalizer (single → [ide], array → as-is, undefined → []).
20
+ resolveConfiguredIdes: vi.fn((cfg: { ide?: unknown }) => {
21
+ const ide = cfg.ide
22
+
23
+ if (!ide) return []
24
+
25
+ return Array.isArray(ide) ? ide : [ide]
26
+ }),
27
+ }
28
+ })
29
+
30
+ const zx = vi.hoisted(() => {
31
+ return { shouldThrow: false }
32
+ })
33
+
34
+ vi.mock('zx', () => {
35
+ return {
36
+ $: vi.fn(() => {
37
+ if (zx.shouldThrow) {
38
+ return Promise.reject(new Error('command not found'))
39
+ }
40
+
41
+ return Promise.resolve({ stdout: '' })
42
+ }),
43
+ }
44
+ })
45
+
46
+ vi.mock('src/lib/logger', () => {
47
+ return { logger: { info: vi.fn(), warn: vi.fn(), error: vi.fn() } }
48
+ })
49
+
50
+ describe('checkIdeInstalled', () => {
51
+ beforeEach(() => {
52
+ config.value = {}
53
+ config.shouldThrow = false
54
+ zx.shouldThrow = false
55
+ vi.clearAllMocks()
56
+ })
57
+
58
+ it('passes informationally when no IDE is configured', async () => {
59
+ config.value = { ide: undefined }
60
+
61
+ const result = await checkIdeInstalled()
62
+
63
+ expect(result.status).toBe('pass')
64
+ expect(result.message).toMatch(/No IDE configured/)
65
+ })
66
+
67
+ it('passes when the configured Cursor binary is present', async () => {
68
+ config.value = { ide: { provider: 'cursor', config: { workspaceConfigPath: 'ws' } } }
69
+
70
+ const result = await checkIdeInstalled()
71
+
72
+ expect(result.status).toBe('pass')
73
+ expect(result.message).toMatch(/Installed: Cursor/)
74
+ })
75
+
76
+ it('fails when the configured Cursor binary is missing', async () => {
77
+ config.value = { ide: { provider: 'cursor', config: { workspaceConfigPath: 'ws' } } }
78
+ zx.shouldThrow = true
79
+
80
+ const result = await checkIdeInstalled()
81
+
82
+ expect(result.status).toBe('fail')
83
+ expect(result.message).toMatch(/Cursor is not installed/)
84
+ })
85
+
86
+ it('passes when the configured Zed binary is present', async () => {
87
+ config.value = { ide: { provider: 'zed', config: {} } }
88
+
89
+ const result = await checkIdeInstalled()
90
+
91
+ expect(result.status).toBe('pass')
92
+ expect(result.message).toMatch(/Installed: Zed/)
93
+ })
94
+
95
+ it('fails when the configured Zed binary is missing', async () => {
96
+ config.value = { ide: { provider: 'zed', config: {} } }
97
+ zx.shouldThrow = true
98
+
99
+ const result = await checkIdeInstalled()
100
+
101
+ expect(result.status).toBe('fail')
102
+ expect(result.message).toMatch(/Zed is not installed/)
103
+ })
104
+
105
+ it('passes listing all editors when multiple are configured and present', async () => {
106
+ config.value = {
107
+ ide: [
108
+ { provider: 'cursor', config: { workspaceConfigPath: 'ws' } },
109
+ { provider: 'zed', config: {} },
110
+ ],
111
+ }
112
+
113
+ const result = await checkIdeInstalled()
114
+
115
+ expect(result.status).toBe('pass')
116
+ expect(result.message).toMatch(/Installed: Cursor, Zed/)
117
+ })
118
+
119
+ it('fails when one of several configured editors is missing', async () => {
120
+ config.value = {
121
+ ide: [
122
+ { provider: 'cursor', config: { workspaceConfigPath: 'ws' } },
123
+ { provider: 'zed', config: {} },
124
+ ],
125
+ }
126
+ zx.shouldThrow = true
127
+
128
+ const result = await checkIdeInstalled()
129
+
130
+ expect(result.status).toBe('fail')
131
+ expect(result.message).toMatch(/Cursor is not installed/)
132
+ })
133
+
134
+ it('passes informationally when the config cannot be read', async () => {
135
+ config.shouldThrow = true
136
+
137
+ const result = await checkIdeInstalled()
138
+
139
+ expect(result.status).toBe('pass')
140
+ expect(result.message).toMatch(/Skipped/)
141
+ })
142
+ })
@@ -12,7 +12,12 @@ import {
12
12
  } from 'src/commands/init/agent-files'
13
13
  import { MARKER_END, MARKER_START, buildShellBlock } from 'src/commands/init/init'
14
14
  import { getProjectRoot } from 'src/lib/git-utils/git-utils'
15
- import { getInfraKitConfig, getInfraKitConfigPaths, resetInfraKitConfigCache } from 'src/lib/infra-kit-config'
15
+ import {
16
+ getInfraKitConfig,
17
+ getInfraKitConfigPaths,
18
+ resetInfraKitConfigCache,
19
+ resolveConfiguredIdes,
20
+ } from 'src/lib/infra-kit-config'
16
21
  import { logger } from 'src/lib/logger'
17
22
  import { hasManagedBlock } from 'src/lib/managed-block'
18
23
  import { defineMcpTool, textContent } from 'src/types'
@@ -155,6 +160,97 @@ const checkUserOverridePath = async (): Promise<CheckResult> => {
155
160
  }
156
161
  }
157
162
 
163
+ interface IdeProbe {
164
+ ok: boolean
165
+ label: string
166
+ failMsg: string
167
+ }
168
+
169
+ const IDE_PROBE_META: Record<'cursor' | 'zed', { command: string[]; label: string; failMsg: string }> = {
170
+ cursor: {
171
+ command: ['cursor', '--version'],
172
+ label: 'Cursor',
173
+ failMsg: 'Cursor is not installed. Install from: https://cursor.com/',
174
+ },
175
+ zed: {
176
+ command: ['zed', '--version'],
177
+ label: 'Zed',
178
+ failMsg: 'Zed is not installed. Install from: https://zed.dev/',
179
+ },
180
+ }
181
+
182
+ const probeIde = async (provider: 'cursor' | 'zed'): Promise<IdeProbe> => {
183
+ const meta = IDE_PROBE_META[provider]
184
+
185
+ try {
186
+ await $`${meta.command}`
187
+
188
+ return { ok: true, label: meta.label, failMsg: meta.failMsg }
189
+ } catch {
190
+ return { ok: false, label: meta.label, failMsg: meta.failMsg }
191
+ }
192
+ }
193
+
194
+ /**
195
+ * Check that every editor configured under `ide` is installed. Reads the merged
196
+ * infra-kit config and probes each matching binary (`cursor`/`zed`). Passes only
197
+ * if all configured editors are present; fails listing any that are missing.
198
+ * Informational pass when no IDE is configured or the config can't be read — an
199
+ * unconfigured editor is a valid setup, and config validity is reported
200
+ * separately by `checkInfraKitConfigValid`.
201
+ */
202
+ export const checkIdeInstalled = async (): Promise<CheckResult> => {
203
+ const name = 'ide installed'
204
+
205
+ let providers: ('cursor' | 'zed')[]
206
+
207
+ try {
208
+ resetInfraKitConfigCache()
209
+ const config = await getInfraKitConfig()
210
+
211
+ providers = resolveConfiguredIdes(config).map((ide) => {
212
+ return ide.provider
213
+ })
214
+ } catch {
215
+ return { name, status: 'pass', message: 'Skipped — infra-kit config could not be read (see config check)' }
216
+ }
217
+
218
+ if (providers.length === 0) {
219
+ return { name, status: 'pass', message: 'No IDE configured (ide unset)' }
220
+ }
221
+
222
+ const probes = await Promise.all(
223
+ providers.map((provider) => {
224
+ return probeIde(provider)
225
+ }),
226
+ )
227
+ const missing = probes.filter((probe) => {
228
+ return !probe.ok
229
+ })
230
+
231
+ if (missing.length === 0) {
232
+ return {
233
+ name,
234
+ status: 'pass',
235
+ message: `Installed: ${probes
236
+ .map((probe) => {
237
+ return probe.label
238
+ })
239
+ .join(', ')}`,
240
+ }
241
+ }
242
+
243
+ return {
244
+ name,
245
+ status: 'fail',
246
+ message: missing
247
+ .map((probe) => {
248
+ return probe.failMsg
249
+ })
250
+ .join('; '),
251
+ }
252
+ }
253
+
158
254
  const RTK_REQUIRED_INDEXES = [1, 2, 3, 5, 7] as const
159
255
 
160
256
  const checkRtkConfigured = async (): Promise<CheckResult> => {
@@ -307,11 +403,18 @@ export const doctor = async () => {
307
403
  'RTK is installed',
308
404
  'RTK is not installed. Install from: https://github.com/rtk-ai/rtk',
309
405
  ),
406
+ checkCommand(
407
+ 'typescript-language-server installed',
408
+ ['typescript-language-server', '--version'],
409
+ 'typescript-language-server is installed',
410
+ 'typescript-language-server is not installed. Install from: https://github.com/typescript-language-server/typescript-language-server#installing',
411
+ ),
310
412
  checkRtkConfigured(),
311
413
  Promise.resolve(checkZshrcInitialized()),
312
414
  checkPnpmWorkspaceVirtualStore(),
313
415
  checkInfraKitConfigValid(),
314
416
  checkUserOverridePath(),
417
+ checkIdeInstalled(),
315
418
  ])
316
419
 
317
420
  const checks: CheckResult[] = [...baseChecks, ...(await checkAgentFiles())]
@@ -11,7 +11,13 @@ import { WORKTREES_DIR_SUFFIX } from 'src/lib/constants'
11
11
  import { formatZxError } from 'src/lib/errors/format-zx-error'
12
12
  import { OperationError } from 'src/lib/errors/operation-error'
13
13
  import { assertManagementContext } from 'src/lib/git-guard'
14
- import { getCurrentWorktrees, getProjectRoot, getRepoName } from 'src/lib/git-utils'
14
+ import {
15
+ deleteLocalBranch,
16
+ deleteRemoteBranch,
17
+ getCurrentWorktrees,
18
+ getProjectRoot,
19
+ getRepoName,
20
+ } from 'src/lib/git-utils'
15
21
  import { logger } from 'src/lib/logger'
16
22
  import { displayLabel, formatJiraName, formatRcTitle, parseBranchName } from 'src/lib/release-id'
17
23
  import type { ReleaseId } from 'src/lib/release-id'
@@ -309,6 +315,30 @@ const syncMainIntoDev = async (): Promise<void> => {
309
315
  )
310
316
  }
311
317
 
318
+ /**
319
+ * Best-effort cleanup of the delivered release branch, locally and on `origin`.
320
+ *
321
+ * Idempotent backstop to `gh pr merge --delete-branch` (in `mergeReleasePR`):
322
+ * that flag is skipped when the release PR was already merged on a prior
323
+ * attempt, so an idempotent re-run would otherwise leave the branch behind.
324
+ * Each delete is isolated — a failure (e.g. the branch checked out in a stray
325
+ * worktree, or a remote hiccup) logs a warning naming the branch and never
326
+ * aborts delivery, since the irreversible merge and deploy already happened.
327
+ */
328
+ const removeDeliveredReleaseBranch = async (branch: string): Promise<void> => {
329
+ try {
330
+ await deleteLocalBranch(branch)
331
+ } catch (error) {
332
+ logger.warn({ err: formatZxError(error) }, `Failed to delete local branch ${branch} (non-blocking)`)
333
+ }
334
+
335
+ try {
336
+ await deleteRemoteBranch(branch)
337
+ } catch (error) {
338
+ logger.warn({ err: formatZxError(error) }, `Failed to delete remote branch ${branch} (non-blocking)`)
339
+ }
340
+ }
341
+
312
342
  const deliverJiraReleaseSafely = async (id: ReleaseId): Promise<void> => {
313
343
  const jiraConfig = await loadJiraConfigOptional()
314
344
 
@@ -395,6 +425,7 @@ export const ghReleaseDeliver = async (args: GhReleaseDeliverArgs) => {
395
425
 
396
426
  await dispatchDeployWorkflow()
397
427
  await syncMainIntoDev()
428
+ await removeDeliveredReleaseBranch(selectedReleaseBranch)
398
429
 
399
430
  $.quiet = false
400
431
 
@@ -0,0 +1,18 @@
1
+ {
2
+ "version": 1,
3
+ "entries": {
4
+ "445ed27a3872b681d98190bae61ccb84954e1bc4e140df5370be958dee776b3a": {
5
+ "last_emitted_at_ms": 1782045486541,
6
+ "message": "Verify changes work after editing. Test functionality before marking complete."
7
+ },
8
+ "79a93d4a2f8f50b95f852280616242fee1855dc99a3c75211917f55e72e95fae": {
9
+ "last_emitted_at_ms": 1782045453587,
10
+ "message": "Use parallel execution for independent tasks. Use run_in_background for long operations (npm install, builds, tests)."
11
+ },
12
+ "466399dafa2d20f60587180bad0a07358eb7f2bce724df0ff682f038ad33f5ad": {
13
+ "last_emitted_at_ms": 1782045414993,
14
+ "message": "Read multiple files in parallel when possible for faster analysis."
15
+ }
16
+ },
17
+ "updated_at": "2026-06-21T12:38:06.541Z"
18
+ }