gencode-ai 0.1.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. package/README.md +2 -1
  2. package/dist/agent/agent.d.ts +44 -2
  3. package/dist/agent/agent.d.ts.map +1 -1
  4. package/dist/agent/agent.js +130 -11
  5. package/dist/agent/agent.js.map +1 -1
  6. package/dist/agent/types.d.ts +11 -1
  7. package/dist/agent/types.d.ts.map +1 -1
  8. package/dist/checkpointing/checkpoint-manager.d.ts +87 -0
  9. package/dist/checkpointing/checkpoint-manager.d.ts.map +1 -0
  10. package/dist/checkpointing/checkpoint-manager.js +281 -0
  11. package/dist/checkpointing/checkpoint-manager.js.map +1 -0
  12. package/dist/checkpointing/index.d.ts +29 -0
  13. package/dist/checkpointing/index.d.ts.map +1 -0
  14. package/dist/checkpointing/index.js +29 -0
  15. package/dist/checkpointing/index.js.map +1 -0
  16. package/dist/checkpointing/types.d.ts +98 -0
  17. package/dist/checkpointing/types.d.ts.map +1 -0
  18. package/dist/checkpointing/types.js +7 -0
  19. package/dist/checkpointing/types.js.map +1 -0
  20. package/dist/cli/components/App.d.ts.map +1 -1
  21. package/dist/cli/components/App.js +171 -14
  22. package/dist/cli/components/App.js.map +1 -1
  23. package/dist/cli/components/CommandSuggestions.d.ts.map +1 -1
  24. package/dist/cli/components/CommandSuggestions.js +5 -0
  25. package/dist/cli/components/CommandSuggestions.js.map +1 -1
  26. package/dist/cli/components/Messages.d.ts +7 -1
  27. package/dist/cli/components/Messages.d.ts.map +1 -1
  28. package/dist/cli/components/Messages.js +12 -3
  29. package/dist/cli/components/Messages.js.map +1 -1
  30. package/dist/cli/components/ModeIndicator.d.ts +42 -0
  31. package/dist/cli/components/ModeIndicator.d.ts.map +1 -0
  32. package/dist/cli/components/ModeIndicator.js +52 -0
  33. package/dist/cli/components/ModeIndicator.js.map +1 -0
  34. package/dist/cli/components/ModelSelector.d.ts +4 -3
  35. package/dist/cli/components/ModelSelector.d.ts.map +1 -1
  36. package/dist/cli/components/ModelSelector.js +54 -37
  37. package/dist/cli/components/ModelSelector.js.map +1 -1
  38. package/dist/cli/components/PlanApproval.d.ts +36 -0
  39. package/dist/cli/components/PlanApproval.d.ts.map +1 -0
  40. package/dist/cli/components/PlanApproval.js +154 -0
  41. package/dist/cli/components/PlanApproval.js.map +1 -0
  42. package/dist/cli/components/ProviderManager.d.ts +2 -2
  43. package/dist/cli/components/ProviderManager.d.ts.map +1 -1
  44. package/dist/cli/components/ProviderManager.js +137 -156
  45. package/dist/cli/components/ProviderManager.js.map +1 -1
  46. package/dist/cli/components/theme.d.ts +2 -0
  47. package/dist/cli/components/theme.d.ts.map +1 -1
  48. package/dist/cli/components/theme.js +3 -0
  49. package/dist/cli/components/theme.js.map +1 -1
  50. package/dist/cli/index.js +30 -13
  51. package/dist/cli/index.js.map +1 -1
  52. package/dist/config/index.d.ts +2 -2
  53. package/dist/config/index.d.ts.map +1 -1
  54. package/dist/config/index.js +1 -1
  55. package/dist/config/index.js.map +1 -1
  56. package/dist/config/levels.d.ts +5 -5
  57. package/dist/config/levels.d.ts.map +1 -1
  58. package/dist/config/levels.js +20 -20
  59. package/dist/config/levels.js.map +1 -1
  60. package/dist/config/merger.js +1 -1
  61. package/dist/config/merger.js.map +1 -1
  62. package/dist/config/providers-config.d.ts +8 -5
  63. package/dist/config/providers-config.d.ts.map +1 -1
  64. package/dist/config/providers-config.js +19 -22
  65. package/dist/config/providers-config.js.map +1 -1
  66. package/dist/config/test-utils.d.ts +2 -2
  67. package/dist/config/test-utils.d.ts.map +1 -1
  68. package/dist/config/test-utils.js +4 -4
  69. package/dist/config/test-utils.js.map +1 -1
  70. package/dist/config/types.d.ts +23 -17
  71. package/dist/config/types.d.ts.map +1 -1
  72. package/dist/config/types.js +14 -14
  73. package/dist/config/types.js.map +1 -1
  74. package/dist/index.d.ts +1 -0
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +2 -0
  77. package/dist/index.js.map +1 -1
  78. package/dist/memory/memory-manager.d.ts +25 -12
  79. package/dist/memory/memory-manager.d.ts.map +1 -1
  80. package/dist/memory/memory-manager.js +241 -112
  81. package/dist/memory/memory-manager.js.map +1 -1
  82. package/dist/memory/test-utils.d.ts +1 -1
  83. package/dist/memory/test-utils.d.ts.map +1 -1
  84. package/dist/memory/test-utils.js +3 -3
  85. package/dist/memory/test-utils.js.map +1 -1
  86. package/dist/memory/types.d.ts +20 -10
  87. package/dist/memory/types.d.ts.map +1 -1
  88. package/dist/memory/types.js +13 -13
  89. package/dist/memory/types.js.map +1 -1
  90. package/dist/migration/migrate.d.ts +24 -0
  91. package/dist/migration/migrate.d.ts.map +1 -0
  92. package/dist/migration/migrate.js +164 -0
  93. package/dist/migration/migrate.js.map +1 -0
  94. package/dist/permissions/persistence.d.ts +2 -2
  95. package/dist/permissions/persistence.js +4 -4
  96. package/dist/permissions/persistence.js.map +1 -1
  97. package/dist/planning/index.d.ts +13 -0
  98. package/dist/planning/index.d.ts.map +1 -0
  99. package/dist/planning/index.js +15 -0
  100. package/dist/planning/index.js.map +1 -0
  101. package/dist/planning/plan-file.d.ts +59 -0
  102. package/dist/planning/plan-file.d.ts.map +1 -0
  103. package/dist/planning/plan-file.js +278 -0
  104. package/dist/planning/plan-file.js.map +1 -0
  105. package/dist/planning/state.d.ts +127 -0
  106. package/dist/planning/state.d.ts.map +1 -0
  107. package/dist/planning/state.js +261 -0
  108. package/dist/planning/state.js.map +1 -0
  109. package/dist/planning/tools/enter-plan-mode.d.ts +25 -0
  110. package/dist/planning/tools/enter-plan-mode.d.ts.map +1 -0
  111. package/dist/planning/tools/enter-plan-mode.js +98 -0
  112. package/dist/planning/tools/enter-plan-mode.js.map +1 -0
  113. package/dist/planning/tools/exit-plan-mode.d.ts +24 -0
  114. package/dist/planning/tools/exit-plan-mode.d.ts.map +1 -0
  115. package/dist/planning/tools/exit-plan-mode.js +149 -0
  116. package/dist/planning/tools/exit-plan-mode.js.map +1 -0
  117. package/dist/planning/types.d.ts +100 -0
  118. package/dist/planning/types.d.ts.map +1 -0
  119. package/dist/planning/types.js +28 -0
  120. package/dist/planning/types.js.map +1 -0
  121. package/dist/pricing/calculator.d.ts +21 -0
  122. package/dist/pricing/calculator.d.ts.map +1 -0
  123. package/dist/pricing/calculator.js +59 -0
  124. package/dist/pricing/calculator.js.map +1 -0
  125. package/dist/pricing/index.d.ts +7 -0
  126. package/dist/pricing/index.d.ts.map +1 -0
  127. package/dist/pricing/index.js +7 -0
  128. package/dist/pricing/index.js.map +1 -0
  129. package/dist/pricing/models.d.ts +20 -0
  130. package/dist/pricing/models.d.ts.map +1 -0
  131. package/dist/pricing/models.js +322 -0
  132. package/dist/pricing/models.js.map +1 -0
  133. package/dist/pricing/types.d.ts +30 -0
  134. package/dist/pricing/types.d.ts.map +1 -0
  135. package/dist/pricing/types.js +5 -0
  136. package/dist/pricing/types.js.map +1 -0
  137. package/dist/prompts/index.d.ts +5 -4
  138. package/dist/prompts/index.d.ts.map +1 -1
  139. package/dist/prompts/index.js +11 -8
  140. package/dist/prompts/index.js.map +1 -1
  141. package/dist/providers/anthropic.d.ts +2 -1
  142. package/dist/providers/anthropic.d.ts.map +1 -1
  143. package/dist/providers/anthropic.js +24 -10
  144. package/dist/providers/anthropic.js.map +1 -1
  145. package/dist/providers/gemini.d.ts +2 -1
  146. package/dist/providers/gemini.d.ts.map +1 -1
  147. package/dist/providers/gemini.js +28 -14
  148. package/dist/providers/gemini.js.map +1 -1
  149. package/dist/providers/index.d.ts +20 -10
  150. package/dist/providers/index.d.ts.map +1 -1
  151. package/dist/providers/index.js +48 -24
  152. package/dist/providers/index.js.map +1 -1
  153. package/dist/providers/openai.d.ts +2 -1
  154. package/dist/providers/openai.d.ts.map +1 -1
  155. package/dist/providers/openai.js +19 -8
  156. package/dist/providers/openai.js.map +1 -1
  157. package/dist/providers/registry.d.ts +48 -34
  158. package/dist/providers/registry.d.ts.map +1 -1
  159. package/dist/providers/registry.js +72 -88
  160. package/dist/providers/registry.js.map +1 -1
  161. package/dist/providers/store.d.ts +43 -17
  162. package/dist/providers/store.d.ts.map +1 -1
  163. package/dist/providers/store.js +112 -19
  164. package/dist/providers/store.js.map +1 -1
  165. package/dist/providers/types.d.ts +25 -0
  166. package/dist/providers/types.d.ts.map +1 -1
  167. package/dist/providers/vertex-ai.d.ts +15 -7
  168. package/dist/providers/vertex-ai.d.ts.map +1 -1
  169. package/dist/providers/vertex-ai.js +63 -23
  170. package/dist/providers/vertex-ai.js.map +1 -1
  171. package/dist/session/manager.d.ts +4 -0
  172. package/dist/session/manager.d.ts.map +1 -1
  173. package/dist/session/manager.js +8 -0
  174. package/dist/session/manager.js.map +1 -1
  175. package/dist/session/types.js +1 -1
  176. package/dist/session/types.js.map +1 -1
  177. package/dist/tools/index.d.ts +7 -1
  178. package/dist/tools/index.d.ts.map +1 -1
  179. package/dist/tools/index.js +7 -0
  180. package/dist/tools/index.js.map +1 -1
  181. package/dist/tools/registry.d.ts +13 -0
  182. package/dist/tools/registry.d.ts.map +1 -1
  183. package/dist/tools/registry.js +79 -2
  184. package/dist/tools/registry.js.map +1 -1
  185. package/docs/config-system-comparison.md +50 -50
  186. package/docs/cost-tracking-comparison.md +904 -0
  187. package/docs/memory-system.md +124 -31
  188. package/docs/operating-modes.md +96 -0
  189. package/docs/permissions.md +2 -2
  190. package/docs/proposals/0006-memory-system.md +4 -4
  191. package/docs/proposals/0008-checkpointing.md +109 -2
  192. package/docs/proposals/0011-custom-commands.md +2 -1
  193. package/docs/proposals/0021-skills-system.md +2 -1
  194. package/docs/proposals/0023-permission-enhancements.md +2 -2
  195. package/docs/proposals/0025-cost-tracking.md +60 -2
  196. package/docs/proposals/0033-enterprise-deployment.md +1 -1
  197. package/docs/proposals/0041-configuration-system.md +17 -19
  198. package/docs/proposals/0042-prompt-optimization.md +17 -9
  199. package/docs/proposals/README.md +6 -6
  200. package/docs/providers.md +94 -9
  201. package/examples/test-checkpointing.ts +121 -0
  202. package/examples/test-cost-tracking.ts +77 -0
  203. package/examples/test-interrupt-cleanup.ts +94 -0
  204. package/package.json +3 -2
  205. package/scripts/migrate.ts +449 -0
  206. package/src/agent/agent.ts +161 -12
  207. package/src/agent/types.ts +11 -1
  208. package/src/checkpointing/checkpoint-manager.ts +327 -0
  209. package/src/checkpointing/index.ts +45 -0
  210. package/src/checkpointing/types.ts +104 -0
  211. package/src/cli/components/App.tsx +221 -13
  212. package/src/cli/components/CommandSuggestions.tsx +5 -0
  213. package/src/cli/components/Messages.tsx +24 -5
  214. package/src/cli/components/ModeIndicator.tsx +174 -0
  215. package/src/cli/components/ModelSelector.tsx +62 -43
  216. package/src/cli/components/PlanApproval.tsx +327 -0
  217. package/src/cli/components/ProviderManager.tsx +278 -323
  218. package/src/cli/components/theme.ts +3 -0
  219. package/src/cli/index.tsx +36 -17
  220. package/src/config/index.ts +5 -3
  221. package/src/config/levels.test.ts +22 -22
  222. package/src/config/levels.ts +22 -22
  223. package/src/config/loader.test.ts +14 -14
  224. package/src/config/manager.test.ts +19 -19
  225. package/src/config/merger.test.ts +23 -23
  226. package/src/config/merger.ts +1 -1
  227. package/src/config/providers-config.ts +23 -21
  228. package/src/config/test-utils.ts +6 -6
  229. package/src/config/types.ts +30 -20
  230. package/src/index.ts +15 -0
  231. package/src/memory/memory-manager.test.ts +242 -24
  232. package/src/memory/memory-manager.ts +270 -141
  233. package/src/memory/test-utils.ts +4 -4
  234. package/src/memory/types.ts +28 -17
  235. package/src/permissions/persistence.ts +4 -4
  236. package/src/planning/index.ts +53 -0
  237. package/src/planning/plan-file.ts +326 -0
  238. package/src/planning/state.ts +305 -0
  239. package/src/planning/tools/enter-plan-mode.ts +111 -0
  240. package/src/planning/tools/exit-plan-mode.ts +170 -0
  241. package/src/planning/types.ts +150 -0
  242. package/src/pricing/calculator.ts +71 -0
  243. package/src/pricing/index.ts +7 -0
  244. package/src/pricing/models.ts +334 -0
  245. package/src/pricing/types.ts +32 -0
  246. package/src/prompts/index.ts +13 -9
  247. package/src/providers/anthropic.ts +30 -10
  248. package/src/providers/gemini.ts +34 -14
  249. package/src/providers/index.ts +76 -33
  250. package/src/providers/openai.ts +26 -8
  251. package/src/providers/registry.ts +116 -111
  252. package/src/providers/store.ts +130 -28
  253. package/src/providers/types.ts +36 -1
  254. package/src/providers/vertex-ai.ts +70 -23
  255. package/src/session/manager.ts +9 -0
  256. package/src/session/types.ts +1 -1
  257. package/src/tools/index.ts +8 -0
  258. package/src/tools/registry.ts +95 -2
  259. package/.gencode/settings.local.json +0 -7
  260. package/CLAUDE.md +0 -86
@@ -2,15 +2,15 @@
2
2
  * Memory System Types
3
3
  *
4
4
  * Hierarchical memory loading compatible with Claude Code:
5
- * At each level, both .gencode and .claude are loaded and merged (gencode has higher priority).
5
+ * At each level, both .gen and .claude are loaded and merged (gen has higher priority).
6
6
  *
7
7
  * Levels:
8
8
  * - Enterprise: System-wide managed memory (enforced)
9
- * - User: ~/.gencode/ + ~/.claude/ (both loaded, gencode content appears later)
10
- * - User Rules: ~/.gencode/rules/ + ~/.claude/rules/
11
- * - Extra: GENCODE_CONFIG_DIRS directories
12
- * - Project: ./AGENT.md, .gencode/, ./CLAUDE.md, .claude/ (recursive upward search)
13
- * - Project Rules: .gencode/rules/ + .claude/rules/
9
+ * - User: ~/.gen/ + ~/.claude/ (both loaded, gen content appears later)
10
+ * - User Rules: ~/.gen/rules/ + ~/.claude/rules/
11
+ * - Extra: GEN_CONFIG_DIRS directories
12
+ * - Project: ./GEN.md, .gen/, ./CLAUDE.md, .claude/ (recursive upward search)
13
+ * - Project Rules: .gen/rules/ + .claude/rules/
14
14
  * - Local: *.local.md files (gitignored)
15
15
  */
16
16
 
@@ -23,7 +23,16 @@ export type MemoryLevel =
23
23
  | 'project-rules'
24
24
  | 'local';
25
25
 
26
- export type MemoryNamespace = 'gencode' | 'claude' | 'extra';
26
+ export type MemoryNamespace = 'gen' | 'claude' | 'extra';
27
+
28
+ /**
29
+ * Memory merge strategy - how to combine CLAUDE.md and GEN.md at each level
30
+ * - fallback: Load GEN.md if exists, else CLAUDE.md (reduces context, default)
31
+ * - both: Load both CLAUDE.md and GEN.md (current behavior, max context)
32
+ * - gen-only: Only load .gen/GEN.md files
33
+ * - claude-only: Only load .claude/CLAUDE.md files
34
+ */
35
+ export type MemoryMergeStrategy = 'fallback' | 'both' | 'gen-only' | 'claude-only';
27
36
 
28
37
  export interface MemoryFile {
29
38
  path: string;
@@ -46,9 +55,9 @@ export interface MemoryRule {
46
55
 
47
56
  export interface MemoryConfig {
48
57
  // GenCode file names (higher priority)
49
- gencodeFilename: string;
50
- gencodeLocalFilename: string;
51
- gencodeDir: string;
58
+ genFilename: string;
59
+ genLocalFilename: string;
60
+ genDir: string;
52
61
 
53
62
  // Claude file names (lower priority, loaded first)
54
63
  claudeFilename: string;
@@ -64,9 +73,9 @@ export interface MemoryConfig {
64
73
 
65
74
  export const DEFAULT_MEMORY_CONFIG: MemoryConfig = {
66
75
  // GenCode
67
- gencodeFilename: 'AGENT.md',
68
- gencodeLocalFilename: 'AGENT.local.md',
69
- gencodeDir: '.gencode',
76
+ genFilename: 'GEN.md',
77
+ genLocalFilename: 'GEN.local.md',
78
+ genDir: '.gen',
70
79
 
71
80
  // Claude
72
81
  claudeFilename: 'CLAUDE.md',
@@ -82,13 +91,13 @@ export const DEFAULT_MEMORY_CONFIG: MemoryConfig = {
82
91
 
83
92
  // Legacy compatibility
84
93
  export const LEGACY_MEMORY_CONFIG = {
85
- primaryFilename: 'AGENT.md',
94
+ primaryFilename: 'GEN.md',
86
95
  fallbackFilename: 'CLAUDE.md',
87
- localFilename: 'AGENT.local.md',
96
+ localFilename: 'GEN.local.md',
88
97
  localFallbackFilename: 'CLAUDE.local.md',
89
- primaryUserDir: '.gencode',
98
+ primaryUserDir: '.gen',
90
99
  fallbackUserDir: '.claude',
91
- primaryLocalDir: '.gencode',
100
+ primaryLocalDir: '.gen',
92
101
  fallbackLocalDir: '.claude',
93
102
  rulesDir: 'rules',
94
103
  maxFileSize: 100 * 1024,
@@ -103,6 +112,7 @@ export interface LoadedMemory {
103
112
  context: string;
104
113
  errors: string[];
105
114
  sources: MemorySource[]; // For debugging
115
+ skippedFiles: string[]; // Files skipped due to merge strategy
106
116
  }
107
117
 
108
118
  export interface MemorySource {
@@ -116,4 +126,5 @@ export interface MemorySource {
116
126
  export interface MemoryLoadOptions {
117
127
  cwd: string;
118
128
  currentFile?: string; // For activating path-scoped rules
129
+ strategy?: MemoryMergeStrategy; // How to merge CLAUDE.md and AGENT.md (default: 'fallback')
119
130
  }
@@ -2,8 +2,8 @@
2
2
  * Permission Persistence - Store and load permission rules
3
3
  *
4
4
  * Handles persistent storage of permission rules at:
5
- * - Global: ~/.gencode/permissions.json
6
- * - Project: .gencode/permissions.json
5
+ * - Global: ~/.gen/permissions.json
6
+ * - Project: .gen/permissions.json
7
7
  */
8
8
 
9
9
  import * as fs from 'fs/promises';
@@ -21,7 +21,7 @@ import { parsePatternString } from './prompt-matcher.js';
21
21
 
22
22
  const PERMISSIONS_VERSION = 1;
23
23
  const PERMISSIONS_FILE = 'permissions.json';
24
- const GLOBAL_DIR = path.join(os.homedir(), '.gencode');
24
+ const GLOBAL_DIR = path.join(os.homedir(), '.gen');
25
25
 
26
26
  /**
27
27
  * Permission Persistence Manager
@@ -32,7 +32,7 @@ export class PermissionPersistence {
32
32
 
33
33
  constructor(projectPath?: string) {
34
34
  this.globalDir = GLOBAL_DIR;
35
- this.projectDir = projectPath ? path.join(projectPath, '.gencode') : null;
35
+ this.projectDir = projectPath ? path.join(projectPath, '.gen') : null;
36
36
  }
37
37
 
38
38
  /**
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Planning Module
3
+ *
4
+ * Plan Mode for GenCode - allows the LLM to design implementation
5
+ * approaches before writing code, with read-only exploration tools.
6
+ */
7
+
8
+ // Types
9
+ export type {
10
+ PlanPhase,
11
+ PlanApprovalOption,
12
+ AllowedPrompt,
13
+ PlanModeState,
14
+ PlanFile,
15
+ PlanModeAllowedTool,
16
+ PlanModeBlockedTool,
17
+ ModeType,
18
+ PlanApprovalState,
19
+ PlanModeEvent,
20
+ } from './types.js';
21
+
22
+ export { PLAN_MODE_ALLOWED_TOOLS, PLAN_MODE_BLOCKED_TOOLS } from './types.js';
23
+
24
+ // State Management
25
+ export {
26
+ PlanModeManager,
27
+ getPlanModeManager,
28
+ resetPlanModeManager,
29
+ isPlanModeActive,
30
+ getCurrentMode,
31
+ enterPlanMode,
32
+ exitPlanMode,
33
+ togglePlanMode,
34
+ } from './state.js';
35
+
36
+ // Plan File Utilities
37
+ export {
38
+ generatePlanFileName,
39
+ getPlansDir,
40
+ ensurePlansDir,
41
+ createPlanFile,
42
+ readPlanFile,
43
+ writePlanFile,
44
+ listPlanFiles,
45
+ deletePlanFile,
46
+ parseFilesToChange,
47
+ parsePreApprovedPermissions,
48
+ getDisplayPath,
49
+ } from './plan-file.js';
50
+
51
+ // Tools
52
+ export { enterPlanModeTool } from './tools/enter-plan-mode.js';
53
+ export { exitPlanModeTool } from './tools/exit-plan-mode.js';
@@ -0,0 +1,326 @@
1
+ /**
2
+ * Plan File Utilities
3
+ *
4
+ * Manages plan files stored in .gen/plans/ directory.
5
+ * Generates unique filenames with timestamps and slugs.
6
+ */
7
+
8
+ import * as fs from 'fs/promises';
9
+ import * as path from 'path';
10
+ import { existsSync } from 'fs';
11
+ import type { PlanFile } from './types.js';
12
+
13
+ // ============================================================================
14
+ // Constants
15
+ // ============================================================================
16
+
17
+ const PLANS_DIR = '.gen/plans';
18
+ const PLAN_FILE_EXTENSION = '.md';
19
+
20
+ // Word lists for generating memorable names (like Claude Code)
21
+ const ADJECTIVES = [
22
+ 'agile', 'bold', 'calm', 'deft', 'eager', 'fair', 'glad', 'humble',
23
+ 'ideal', 'jolly', 'keen', 'lively', 'merry', 'noble', 'polite', 'quiet',
24
+ 'rapid', 'smart', 'tidy', 'unique', 'vivid', 'warm', 'zealous', 'bright',
25
+ 'clear', 'crisp', 'fresh', 'golden', 'happy', 'lovely', 'neat', 'proud',
26
+ ];
27
+
28
+ const NOUNS = [
29
+ 'alpine', 'beacon', 'cipher', 'delta', 'ember', 'falcon', 'glacier', 'harbor',
30
+ 'island', 'jasper', 'kayak', 'lantern', 'marble', 'nebula', 'oracle', 'prism',
31
+ 'quartz', 'rapids', 'summit', 'timber', 'unity', 'vertex', 'willow', 'zenith',
32
+ 'arrow', 'bridge', 'canyon', 'dawn', 'echo', 'forest', 'grove', 'hollow',
33
+ ];
34
+
35
+ // ============================================================================
36
+ // Name Generation
37
+ // ============================================================================
38
+
39
+ /**
40
+ * Generate a memorable plan name (adjective-noun)
41
+ * Example: "agile-beacon", "bold-cipher"
42
+ */
43
+ function generateMemorableName(): string {
44
+ const adjective = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
45
+ const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)];
46
+ return `${adjective}-${noun}`;
47
+ }
48
+
49
+ /**
50
+ * Generate a slug from text (for task-specific naming)
51
+ */
52
+ function generateSlug(text: string): string {
53
+ return text
54
+ .toLowerCase()
55
+ .replace(/[^a-z0-9\s-]/g, '') // Remove special chars
56
+ .replace(/\s+/g, '-') // Replace spaces with dashes
57
+ .replace(/-+/g, '-') // Collapse multiple dashes
58
+ .slice(0, 30) // Limit length
59
+ .replace(/^-|-$/g, ''); // Trim dashes from ends
60
+ }
61
+
62
+ /**
63
+ * Generate plan file name
64
+ * Format: <memorable-name>.md (like Claude Code)
65
+ */
66
+ export function generatePlanFileName(taskDescription?: string): string {
67
+ // Use memorable name like Claude Code (melodic-humming-lampson)
68
+ const name = generateMemorableName();
69
+ return `${name}${PLAN_FILE_EXTENSION}`;
70
+ }
71
+
72
+ // ============================================================================
73
+ // Directory Management
74
+ // ============================================================================
75
+
76
+ /**
77
+ * Get the plans directory path for a project
78
+ */
79
+ export function getPlansDir(cwd: string): string {
80
+ return path.join(cwd, PLANS_DIR);
81
+ }
82
+
83
+ /**
84
+ * Ensure the plans directory exists
85
+ */
86
+ export async function ensurePlansDir(cwd: string): Promise<string> {
87
+ const plansDir = getPlansDir(cwd);
88
+
89
+ if (!existsSync(plansDir)) {
90
+ await fs.mkdir(plansDir, { recursive: true });
91
+ }
92
+
93
+ return plansDir;
94
+ }
95
+
96
+ // ============================================================================
97
+ // Plan File Operations
98
+ // ============================================================================
99
+
100
+ /**
101
+ * Create a new plan file
102
+ */
103
+ export async function createPlanFile(
104
+ cwd: string,
105
+ taskDescription?: string
106
+ ): Promise<PlanFile> {
107
+ const plansDir = await ensurePlansDir(cwd);
108
+ const fileName = generatePlanFileName(taskDescription);
109
+ const filePath = path.join(plansDir, fileName);
110
+
111
+ // Initial plan template
112
+ const initialContent = `# Implementation Plan
113
+
114
+ ## Task
115
+ ${taskDescription || 'Describe the task here...'}
116
+
117
+ ## Analysis
118
+ _Understanding the codebase and requirements..._
119
+
120
+ ## Approach
121
+ _Design decisions and implementation strategy..._
122
+
123
+ ## Files to Change
124
+ - [ ] File 1 (action)
125
+ - [ ] File 2 (action)
126
+
127
+ ## Steps
128
+ 1. Step 1
129
+ 2. Step 2
130
+ 3. Step 3
131
+
132
+ ## Pre-approved Permissions
133
+ _Commands that will be allowed during execution..._
134
+
135
+ ---
136
+ _Generated by GenCode Plan Mode_
137
+ `;
138
+
139
+ const now = new Date();
140
+ await fs.writeFile(filePath, initialContent, 'utf-8');
141
+
142
+ return {
143
+ path: filePath,
144
+ content: initialContent,
145
+ createdAt: now,
146
+ updatedAt: now,
147
+ };
148
+ }
149
+
150
+ /**
151
+ * Read a plan file
152
+ */
153
+ export async function readPlanFile(filePath: string): Promise<PlanFile | null> {
154
+ try {
155
+ const content = await fs.readFile(filePath, 'utf-8');
156
+ const stats = await fs.stat(filePath);
157
+
158
+ return {
159
+ path: filePath,
160
+ content,
161
+ createdAt: stats.birthtime,
162
+ updatedAt: stats.mtime,
163
+ };
164
+ } catch {
165
+ return null;
166
+ }
167
+ }
168
+
169
+ /**
170
+ * Write to a plan file
171
+ */
172
+ export async function writePlanFile(filePath: string, content: string): Promise<void> {
173
+ // Ensure directory exists
174
+ const dir = path.dirname(filePath);
175
+ if (!existsSync(dir)) {
176
+ await fs.mkdir(dir, { recursive: true });
177
+ }
178
+
179
+ await fs.writeFile(filePath, content, 'utf-8');
180
+ }
181
+
182
+ /**
183
+ * List all plan files in the project
184
+ */
185
+ export async function listPlanFiles(cwd: string): Promise<PlanFile[]> {
186
+ const plansDir = getPlansDir(cwd);
187
+
188
+ if (!existsSync(plansDir)) {
189
+ return [];
190
+ }
191
+
192
+ try {
193
+ const files = await fs.readdir(plansDir);
194
+ const planFiles: PlanFile[] = [];
195
+
196
+ for (const file of files) {
197
+ if (file.endsWith(PLAN_FILE_EXTENSION)) {
198
+ const filePath = path.join(plansDir, file);
199
+ const planFile = await readPlanFile(filePath);
200
+ if (planFile) {
201
+ planFiles.push(planFile);
202
+ }
203
+ }
204
+ }
205
+
206
+ // Sort by updated time, newest first
207
+ planFiles.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
208
+
209
+ return planFiles;
210
+ } catch {
211
+ return [];
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Delete a plan file
217
+ */
218
+ export async function deletePlanFile(filePath: string): Promise<boolean> {
219
+ try {
220
+ await fs.unlink(filePath);
221
+ return true;
222
+ } catch {
223
+ return false;
224
+ }
225
+ }
226
+
227
+ // ============================================================================
228
+ // Plan Content Parsing
229
+ // ============================================================================
230
+
231
+ /**
232
+ * Extract files to change from plan content
233
+ */
234
+ export function parseFilesToChange(
235
+ content: string
236
+ ): Array<{ path: string; action: 'create' | 'modify' | 'delete' }> {
237
+ const files: Array<{ path: string; action: 'create' | 'modify' | 'delete' }> = [];
238
+
239
+ // Look for patterns like:
240
+ // - [ ] src/file.ts (create)
241
+ // - [x] src/file.ts (modify)
242
+ // + src/file.ts (create)
243
+ // ~ src/file.ts (modify)
244
+ // - src/file.ts (delete)
245
+
246
+ const lines = content.split('\n');
247
+ for (const line of lines) {
248
+ // Checkbox format
249
+ let match = line.match(/^[-*]\s*\[[ x]\]\s+([^\s(]+)\s*\((\w+)\)/);
250
+ if (match) {
251
+ const [, filePath, action] = match;
252
+ if (action === 'create' || action === 'modify' || action === 'delete') {
253
+ files.push({ path: filePath, action });
254
+ }
255
+ continue;
256
+ }
257
+
258
+ // Symbol format (+, ~, -)
259
+ match = line.match(/^\s*([+~-])\s+([^\s(]+)(?:\s*\((\w+)\))?/);
260
+ if (match) {
261
+ const [, symbol, filePath, explicitAction] = match;
262
+ let action: 'create' | 'modify' | 'delete';
263
+
264
+ if (explicitAction === 'create' || explicitAction === 'modify' || explicitAction === 'delete') {
265
+ action = explicitAction;
266
+ } else {
267
+ action = symbol === '+' ? 'create' : symbol === '~' ? 'modify' : 'delete';
268
+ }
269
+
270
+ files.push({ path: filePath, action });
271
+ }
272
+ }
273
+
274
+ return files;
275
+ }
276
+
277
+ /**
278
+ * Extract pre-approved permissions from plan content
279
+ */
280
+ export function parsePreApprovedPermissions(content: string): Array<{ tool: 'Bash'; prompt: string }> {
281
+ const permissions: Array<{ tool: 'Bash'; prompt: string }> = [];
282
+
283
+ // Look for patterns like:
284
+ // - Bash: run tests
285
+ // - npm test
286
+ // - npm install
287
+
288
+ const permissionSection = content.match(/## Pre-approved Permissions[\s\S]*?(?=##|$)/i);
289
+ if (!permissionSection) {
290
+ return permissions;
291
+ }
292
+
293
+ const lines = permissionSection[0].split('\n');
294
+ for (const line of lines) {
295
+ // Skip header and empty lines
296
+ if (line.startsWith('##') || line.startsWith('_') || !line.trim()) {
297
+ continue;
298
+ }
299
+
300
+ // Match "- Bash: description" or "- description"
301
+ const match = line.match(/^[-*]\s+(?:Bash:\s+)?(.+)/);
302
+ if (match) {
303
+ permissions.push({ tool: 'Bash', prompt: match[1].trim() });
304
+ }
305
+ }
306
+
307
+ return permissions;
308
+ }
309
+
310
+ /**
311
+ * Get relative path for display
312
+ */
313
+ export function getDisplayPath(fullPath: string, cwd: string): string {
314
+ const relativePath = path.relative(cwd, fullPath);
315
+ const home = process.env.HOME || '';
316
+
317
+ if (relativePath.startsWith('..')) {
318
+ // Path is outside cwd, try home-relative
319
+ if (fullPath.startsWith(home)) {
320
+ return '~' + fullPath.slice(home.length);
321
+ }
322
+ return fullPath;
323
+ }
324
+
325
+ return relativePath;
326
+ }