@ddse/acm-aicoder 0.5.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 (165) hide show
  1. package/.aicoder/index.json +304 -0
  2. package/AICODER_IMPLEMENTATION_PLAN_PHASE2.md +284 -0
  3. package/LICENSE +21 -0
  4. package/README.md +490 -0
  5. package/bin/interactive.tsx +232 -0
  6. package/dist/bin/interactive.d.ts +3 -0
  7. package/dist/bin/interactive.d.ts.map +1 -0
  8. package/dist/bin/interactive.js +155 -0
  9. package/dist/bin/interactive.js.map +1 -0
  10. package/dist/src/config/providers.d.ts +15 -0
  11. package/dist/src/config/providers.d.ts.map +1 -0
  12. package/dist/src/config/providers.js +142 -0
  13. package/dist/src/config/providers.js.map +1 -0
  14. package/dist/src/config/session.d.ts +25 -0
  15. package/dist/src/config/session.d.ts.map +1 -0
  16. package/dist/src/config/session.js +97 -0
  17. package/dist/src/config/session.js.map +1 -0
  18. package/dist/src/context/bm25.d.ts +68 -0
  19. package/dist/src/context/bm25.d.ts.map +1 -0
  20. package/dist/src/context/bm25.js +131 -0
  21. package/dist/src/context/bm25.js.map +1 -0
  22. package/dist/src/context/code-search.d.ts +30 -0
  23. package/dist/src/context/code-search.d.ts.map +1 -0
  24. package/dist/src/context/code-search.js +150 -0
  25. package/dist/src/context/code-search.js.map +1 -0
  26. package/dist/src/context/context-pack.d.ts +25 -0
  27. package/dist/src/context/context-pack.d.ts.map +1 -0
  28. package/dist/src/context/context-pack.js +92 -0
  29. package/dist/src/context/context-pack.js.map +1 -0
  30. package/dist/src/context/dependency-mapper.d.ts +10 -0
  31. package/dist/src/context/dependency-mapper.d.ts.map +1 -0
  32. package/dist/src/context/dependency-mapper.js +62 -0
  33. package/dist/src/context/dependency-mapper.js.map +1 -0
  34. package/dist/src/context/index.d.ts +8 -0
  35. package/dist/src/context/index.d.ts.map +1 -0
  36. package/dist/src/context/index.js +9 -0
  37. package/dist/src/context/index.js.map +1 -0
  38. package/dist/src/context/symbol-extractor.d.ts +26 -0
  39. package/dist/src/context/symbol-extractor.d.ts.map +1 -0
  40. package/dist/src/context/symbol-extractor.js +129 -0
  41. package/dist/src/context/symbol-extractor.js.map +1 -0
  42. package/dist/src/context/test-mapper.d.ts +16 -0
  43. package/dist/src/context/test-mapper.d.ts.map +1 -0
  44. package/dist/src/context/test-mapper.js +66 -0
  45. package/dist/src/context/test-mapper.js.map +1 -0
  46. package/dist/src/context/types.d.ts +61 -0
  47. package/dist/src/context/types.d.ts.map +1 -0
  48. package/dist/src/context/types.js +3 -0
  49. package/dist/src/context/types.js.map +1 -0
  50. package/dist/src/context/workspace-indexer.d.ts +39 -0
  51. package/dist/src/context/workspace-indexer.d.ts.map +1 -0
  52. package/dist/src/context/workspace-indexer.js +222 -0
  53. package/dist/src/context/workspace-indexer.js.map +1 -0
  54. package/dist/src/index.d.ts +5 -0
  55. package/dist/src/index.d.ts.map +1 -0
  56. package/dist/src/index.js +6 -0
  57. package/dist/src/index.js.map +1 -0
  58. package/dist/src/registries.d.ts +34 -0
  59. package/dist/src/registries.d.ts.map +1 -0
  60. package/dist/src/registries.js +87 -0
  61. package/dist/src/registries.js.map +1 -0
  62. package/dist/src/runtime/budget-manager.d.ts +42 -0
  63. package/dist/src/runtime/budget-manager.d.ts.map +1 -0
  64. package/dist/src/runtime/budget-manager.js +82 -0
  65. package/dist/src/runtime/budget-manager.js.map +1 -0
  66. package/dist/src/runtime/interactive-runtime.d.ts +39 -0
  67. package/dist/src/runtime/interactive-runtime.d.ts.map +1 -0
  68. package/dist/src/runtime/interactive-runtime.js +321 -0
  69. package/dist/src/runtime/interactive-runtime.js.map +1 -0
  70. package/dist/src/tasks-v2/analysis-tasks.d.ts +117 -0
  71. package/dist/src/tasks-v2/analysis-tasks.d.ts.map +1 -0
  72. package/dist/src/tasks-v2/analysis-tasks.js +209 -0
  73. package/dist/src/tasks-v2/analysis-tasks.js.map +1 -0
  74. package/dist/src/tasks-v2/developer-tasks.d.ts +226 -0
  75. package/dist/src/tasks-v2/developer-tasks.d.ts.map +1 -0
  76. package/dist/src/tasks-v2/developer-tasks.js +322 -0
  77. package/dist/src/tasks-v2/developer-tasks.js.map +1 -0
  78. package/dist/src/tasks-v2/index.d.ts +3 -0
  79. package/dist/src/tasks-v2/index.d.ts.map +1 -0
  80. package/dist/src/tasks-v2/index.js +4 -0
  81. package/dist/src/tasks-v2/index.js.map +1 -0
  82. package/dist/src/tools-v2/edit-tools.d.ts +67 -0
  83. package/dist/src/tools-v2/edit-tools.d.ts.map +1 -0
  84. package/dist/src/tools-v2/edit-tools.js +117 -0
  85. package/dist/src/tools-v2/edit-tools.js.map +1 -0
  86. package/dist/src/tools-v2/index.d.ts +6 -0
  87. package/dist/src/tools-v2/index.d.ts.map +1 -0
  88. package/dist/src/tools-v2/index.js +7 -0
  89. package/dist/src/tools-v2/index.js.map +1 -0
  90. package/dist/src/tools-v2/read-tools.d.ts +129 -0
  91. package/dist/src/tools-v2/read-tools.d.ts.map +1 -0
  92. package/dist/src/tools-v2/read-tools.js +216 -0
  93. package/dist/src/tools-v2/read-tools.js.map +1 -0
  94. package/dist/src/tools-v2/search-tools.d.ts +73 -0
  95. package/dist/src/tools-v2/search-tools.d.ts.map +1 -0
  96. package/dist/src/tools-v2/search-tools.js +132 -0
  97. package/dist/src/tools-v2/search-tools.js.map +1 -0
  98. package/dist/src/tools-v2/test-tools.d.ts +59 -0
  99. package/dist/src/tools-v2/test-tools.d.ts.map +1 -0
  100. package/dist/src/tools-v2/test-tools.js +111 -0
  101. package/dist/src/tools-v2/test-tools.js.map +1 -0
  102. package/dist/src/tools-v2/workspace-context.d.ts +65 -0
  103. package/dist/src/tools-v2/workspace-context.d.ts.map +1 -0
  104. package/dist/src/tools-v2/workspace-context.js +336 -0
  105. package/dist/src/tools-v2/workspace-context.js.map +1 -0
  106. package/dist/src/ui/App.d.ts +9 -0
  107. package/dist/src/ui/App.d.ts.map +1 -0
  108. package/dist/src/ui/App.js +257 -0
  109. package/dist/src/ui/App.js.map +1 -0
  110. package/dist/src/ui/components/ChatPane.d.ts +12 -0
  111. package/dist/src/ui/components/ChatPane.d.ts.map +1 -0
  112. package/dist/src/ui/components/ChatPane.js +41 -0
  113. package/dist/src/ui/components/ChatPane.js.map +1 -0
  114. package/dist/src/ui/components/EventsPane.d.ts +12 -0
  115. package/dist/src/ui/components/EventsPane.d.ts.map +1 -0
  116. package/dist/src/ui/components/EventsPane.js +48 -0
  117. package/dist/src/ui/components/EventsPane.js.map +1 -0
  118. package/dist/src/ui/components/GoalsTasksPane.d.ts +18 -0
  119. package/dist/src/ui/components/GoalsTasksPane.d.ts.map +1 -0
  120. package/dist/src/ui/components/GoalsTasksPane.js +83 -0
  121. package/dist/src/ui/components/GoalsTasksPane.js.map +1 -0
  122. package/dist/src/ui/store.d.ts +74 -0
  123. package/dist/src/ui/store.d.ts.map +1 -0
  124. package/dist/src/ui/store.js +260 -0
  125. package/dist/src/ui/store.js.map +1 -0
  126. package/dist/tests/integration.test.d.ts +2 -0
  127. package/dist/tests/integration.test.d.ts.map +1 -0
  128. package/dist/tests/integration.test.js +415 -0
  129. package/dist/tests/integration.test.js.map +1 -0
  130. package/dist/tsconfig.tsbuildinfo +1 -0
  131. package/docs/AICODER.png +0 -0
  132. package/docs/INTERACTIVE_CLI_GUIDE.md +201 -0
  133. package/docs/TUI_MOCKUP.md +180 -0
  134. package/package.json +52 -0
  135. package/src/config/providers.ts +174 -0
  136. package/src/config/session.ts +143 -0
  137. package/src/context/bm25.ts +173 -0
  138. package/src/context/code-search.ts +188 -0
  139. package/src/context/context-pack.ts +133 -0
  140. package/src/context/dependency-mapper.ts +72 -0
  141. package/src/context/index.ts +8 -0
  142. package/src/context/symbol-extractor.ts +149 -0
  143. package/src/context/test-mapper.ts +77 -0
  144. package/src/context/types.ts +69 -0
  145. package/src/context/workspace-indexer.ts +249 -0
  146. package/src/index.ts +5 -0
  147. package/src/registries.ts +118 -0
  148. package/src/runtime/budget-manager.ts +118 -0
  149. package/src/runtime/interactive-runtime.ts +423 -0
  150. package/src/tasks-v2/analysis-tasks.ts +311 -0
  151. package/src/tasks-v2/developer-tasks.ts +437 -0
  152. package/src/tasks-v2/index.ts +3 -0
  153. package/src/tools-v2/edit-tools.ts +153 -0
  154. package/src/tools-v2/index.ts +6 -0
  155. package/src/tools-v2/read-tools.ts +286 -0
  156. package/src/tools-v2/search-tools.ts +175 -0
  157. package/src/tools-v2/test-tools.ts +147 -0
  158. package/src/tools-v2/workspace-context.ts +428 -0
  159. package/src/ui/App.tsx +392 -0
  160. package/src/ui/components/ChatPane.tsx +84 -0
  161. package/src/ui/components/EventsPane.tsx +81 -0
  162. package/src/ui/components/GoalsTasksPane.tsx +149 -0
  163. package/src/ui/store.ts +362 -0
  164. package/tests/integration.test.ts +537 -0
  165. package/tsconfig.json +22 -0
@@ -0,0 +1,180 @@
1
+ # ACM AI Coder - Interactive TUI Mockup
2
+
3
+ ```
4
+ ╔═══════════════════════════════════════════════════════════════════════════════╗
5
+ ║ ACM AI Coder - Interactive Mode ⟳ Processing║
6
+ ╠═════════════════════════╤═════════════════════════════╤═════════════════════════╣
7
+ ║ │ │ ║
8
+ ║ ┌─────────────────┐ │ ┌─────────────────────┐ │ ┌─────────────────┐ ║
9
+ ║ │ Chat │ │ │ Goal/Tasks/Progress │ │ │ Event Stream │ ║
10
+ ║ └─────────────────┘ │ └─────────────────────┘ │ └─────────────────┘ ║
11
+ ║ │ │ ║
12
+ ║ System: │ Goal: │ [14:23:45] GOAL_ ║
13
+ ║ Welcome to ACM AI │ Analyze src/index.ts │ CREATED: goal-123 ║
14
+ ║ Coder (Phase 2) │ and find bugs │ ║
15
+ ║ │ │ [14:23:46] BUDGET_ ║
16
+ ║ Configuration: │ Tasks: │ CHECK: $0.0024 ║
17
+ ║ Model: gpt-4o │ ○ analyze_workspace │ ║
18
+ ║ Engine: langgraph │ ○ collect_context_pack │ [14:23:47] PLAN_ ║
19
+ ║ Workspace: /project │ ○ search_code │ SELECTED: plan-456 ║
20
+ ║ Budget: $10.00 │ │ ║
21
+ ║ │ Budget: │ [14:23:48] TASK_ ║
22
+ ║ Type your goal to │ Spent: $0.0024 / $10.00 │ START: task-0 ║
23
+ ║ start planning. │ Used: 0.0% │ ║
24
+ ║ │ Remaining: $9.9976 │ [14:23:49] CONTEXT_ ║
25
+ ║ You: │ Calls: 1 │ INTERNALIZED: 3 files ║
26
+ ║ Analyze src/index.ts │ │ ║
27
+ ║ and find bugs │ │ [14:23:50] TASK_ ║
28
+ ║ │ │ END: task-0 ║
29
+ ║ Planner (streaming...):│ │ ║
30
+ ║ I'll analyze the file │ │ [14:23:51] NUCLEUS_ ║
31
+ ║ by first collecting │ │ INFERENCE: context ok ║
32
+ ║ context from the │ │ ║
33
+ ║ workspace, then... │ │ ║
34
+ ║ │ │ ║
35
+ ║ │ │ ║
36
+ ║ │ │ ║
37
+ ╠═════════════════════════╧═════════════════════════════╧═════════════════════════╣
38
+ ║ > Type your goal or command (e.g., /help)... ║
39
+ ╚═══════════════════════════════════════════════════════════════════════════════╝
40
+ ```
41
+
42
+ ## Layout Breakdown
43
+
44
+ ### Left Column (40%) - Chat Pane
45
+ - **Purpose:** User messages, planner reasoning, nucleus thoughts, system messages
46
+ - **Colors:**
47
+ - User: white
48
+ - Planner: yellow (streaming indicator when active)
49
+ - Nucleus: magenta
50
+ - System: gray
51
+ - **Scrolling:** Shows most recent messages that fit in viewport
52
+
53
+ ### Middle Column (30%) - Goals/Tasks/Progress
54
+ - **Goal Section:** Current goal intent
55
+ - **Tasks Section:** Live task list with status icons
56
+ - ○ pending (gray)
57
+ - ◐ running (yellow)
58
+ - ● succeeded (green)
59
+ - ✗ failed (red)
60
+ - ⟳ retrying (yellow)
61
+ - **Budget Section:** Real-time spend tracking
62
+ - Total spent vs. limit
63
+ - Percentage used (color-coded)
64
+ - Remaining budget
65
+ - API call count
66
+
67
+ ### Right Column (30%) - Event Stream
68
+ - **Purpose:** Ledger entries, tool calls, context updates, policy decisions
69
+ - **Format:** [timestamp] TYPE: data
70
+ - **Colors:**
71
+ - PLAN_SELECTED, TASK_END: green
72
+ - TASK_START: blue
73
+ - ERROR: red
74
+ - POLICY_DECISION: yellow
75
+ - Others: gray
76
+ - **Pruning:** Keeps last 100 events
77
+
78
+ ### Bottom - Command Input
79
+ - **Text input:** Accepts goals or commands
80
+ - **Commands:** /exit, /help, /budget, /context, /reset
81
+ - **File mentions:** #path/to/file syntax
82
+ - **Submit:** Press Enter to send
83
+
84
+ ## Example Session Flow
85
+
86
+ ### 1. Startup
87
+ ```
88
+ > acm-aicoder --provider vllm --model gpt-4o --base-url https://api.openai.com \
89
+ --workspace /myproject
90
+
91
+ [TUI launches with welcome message]
92
+ ```
93
+
94
+ ### 2. User Types Goal
95
+ ```
96
+ > Find all TypeScript errors in src/ directory
97
+ [ENTER]
98
+ ```
99
+
100
+ ### 3. Budget Check
101
+ ```
102
+ Event Stream:
103
+ [14:25:01] BUDGET_CHECK: estimated $0.0035, 1200 tokens
104
+ ```
105
+
106
+ ### 4. Planner Streams Reasoning
107
+ ```
108
+ Chat Pane:
109
+ Planner (streaming...):
110
+ First, I'll analyze the TypeScript files in src/...
111
+ Then I'll run the type checker...
112
+ Finally, I'll categorize the errors...
113
+ ```
114
+
115
+ ### 5. Tasks Execute
116
+ ```
117
+ Tasks Pane:
118
+ ◐ analyze_workspace (running)
119
+ ○ collect_context_pack
120
+ ○ fix_type_error
121
+
122
+ Event Stream:
123
+ [14:25:02] TASK_START: task-0
124
+ [14:25:03] CONTEXT_INTERNALIZED: 15 files
125
+ [14:25:04] TASK_END: task-0
126
+ ```
127
+
128
+ ### 6. Completion
129
+ ```
130
+ System:
131
+ Goal completed successfully!
132
+ Replay bundle saved to: /myproject/.aicoder/replays/2025-01-04T14-25-05
133
+ ```
134
+
135
+ ## Interactive Commands
136
+
137
+ ### /help
138
+ Shows available commands and usage examples.
139
+
140
+ ### /budget
141
+ ```
142
+ Budget Status:
143
+ Total Spent: $0.0124
144
+ Limit: $10.00
145
+ Remaining: $9.9876
146
+ Used: 0.1%
147
+ API Calls: 4
148
+ ```
149
+
150
+ ### /context
151
+ ```
152
+ Current Context:
153
+ ID: ctx-1735998305123
154
+ Facts: 3 entries
155
+ ```
156
+
157
+ ### /reset
158
+ Clears current goal and tasks, resets budget, keeps chat history.
159
+
160
+ ### /exit or /quit
161
+ Saves replay bundle and exits cleanly.
162
+
163
+ ## Visual Styling
164
+
165
+ - **Borders:** Single-line for panes, double-line for header/footer
166
+ - **Colors:** ANSI terminal colors (cyan, yellow, green, red, blue, magenta)
167
+ - **Responsive:** Adjusts to terminal size (minimum 80 columns)
168
+ - **Updates:** Real-time re-renders on state changes
169
+
170
+ ## Terminal Requirements
171
+
172
+ - **Minimum Width:** 80 columns
173
+ - **Minimum Height:** 24 rows
174
+ - **Terminal Type:** xterm-compatible (supports ANSI colors)
175
+ - **Not Recommended:** tmux/screen nested sessions (may cause layout issues)
176
+
177
+ ---
178
+
179
+ This mockup represents the actual TUI layout implemented in Phase 2.
180
+ All components are functional and wired to the ACM framework.
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@ddse/acm-aicoder",
3
+ "version": "0.5.0",
4
+ "description": "ACM AI Coder Demo - Production-ready developer workflow automation",
5
+ "type": "module",
6
+ "main": "./dist/src/index.js",
7
+ "types": "./dist/src/index.d.ts",
8
+ "bin": {
9
+ "acm-aicoder": "./dist/bin/interactive.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/src/index.d.ts",
14
+ "import": "./dist/src/index.js"
15
+ }
16
+ },
17
+ "dependencies": {
18
+ "enquirer": "^2.4.1",
19
+ "chalk": "^5.3.0",
20
+ "ora": "^8.0.1",
21
+ "execa": "^9.0.0",
22
+ "ink": "^5.0.1",
23
+ "ink-text-input": "^6.0.0",
24
+ "react": "^18.3.1",
25
+ "@ddse/acm-sdk": "0.5.0",
26
+ "@ddse/acm-runtime": "0.5.0",
27
+ "@ddse/acm-planner": "0.5.0",
28
+ "@ddse/acm-replay": "0.5.0",
29
+ "@ddse/acm-framework": "0.5.0",
30
+ "@ddse/acm-llm": "0.5.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.0.0",
34
+ "@types/react": "^18.3.3",
35
+ "typescript": "^5.3.0"
36
+ },
37
+ "keywords": [
38
+ "acm",
39
+ "ai",
40
+ "coder",
41
+ "developer",
42
+ "automation"
43
+ ],
44
+ "license": "MIT",
45
+ "scripts": {
46
+ "build": "tsc",
47
+ "clean": "rm -rf dist",
48
+ "test": "tsc && node ./dist/tests/integration.test.js",
49
+ "dev": "tsc --watch",
50
+ "acm-aicoder": "node ./dist/bin/interactive.js"
51
+ }
52
+ }
@@ -0,0 +1,174 @@
1
+ // Provider metadata for budget governance
2
+ // Token costs and context limits per model/provider
3
+
4
+ export interface ProviderMetadata {
5
+ provider: string;
6
+ model: string;
7
+
8
+ // Cost per 1M tokens (USD)
9
+ inputCostPer1M?: number;
10
+ outputCostPer1M?: number;
11
+
12
+ // Context window
13
+ maxContextTokens?: number;
14
+
15
+ // Concurrency limits
16
+ maxConcurrentRequests?: number;
17
+
18
+ // Recommended settings
19
+ recommendedTemperature?: number;
20
+ supportsStreaming: boolean;
21
+ }
22
+
23
+ // Provider metadata registry
24
+ // Sources: OpenAI pricing, Anthropic pricing, Azure OpenAI, local models
25
+ export const PROVIDER_METADATA: Record<string, ProviderMetadata> = {
26
+ // OpenAI models
27
+ 'gpt-4o': {
28
+ provider: 'openai',
29
+ model: 'gpt-4o',
30
+ inputCostPer1M: 2.50,
31
+ outputCostPer1M: 10.00,
32
+ maxContextTokens: 128000,
33
+ maxConcurrentRequests: 10,
34
+ recommendedTemperature: 0.7,
35
+ supportsStreaming: true,
36
+ },
37
+ 'gpt-4o-mini': {
38
+ provider: 'openai',
39
+ model: 'gpt-4o-mini',
40
+ inputCostPer1M: 0.15,
41
+ outputCostPer1M: 0.60,
42
+ maxContextTokens: 128000,
43
+ maxConcurrentRequests: 10,
44
+ recommendedTemperature: 0.7,
45
+ supportsStreaming: true,
46
+ },
47
+ 'gpt-4-turbo': {
48
+ provider: 'openai',
49
+ model: 'gpt-4-turbo',
50
+ inputCostPer1M: 10.00,
51
+ outputCostPer1M: 30.00,
52
+ maxContextTokens: 128000,
53
+ maxConcurrentRequests: 10,
54
+ recommendedTemperature: 0.7,
55
+ supportsStreaming: true,
56
+ },
57
+ 'gpt-3.5-turbo': {
58
+ provider: 'openai',
59
+ model: 'gpt-3.5-turbo',
60
+ inputCostPer1M: 0.50,
61
+ outputCostPer1M: 1.50,
62
+ maxContextTokens: 16385,
63
+ maxConcurrentRequests: 10,
64
+ recommendedTemperature: 0.7,
65
+ supportsStreaming: true,
66
+ },
67
+
68
+ // Anthropic models
69
+ 'claude-3-opus-20240229': {
70
+ provider: 'anthropic',
71
+ model: 'claude-3-opus-20240229',
72
+ inputCostPer1M: 15.00,
73
+ outputCostPer1M: 75.00,
74
+ maxContextTokens: 200000,
75
+ maxConcurrentRequests: 5,
76
+ recommendedTemperature: 0.7,
77
+ supportsStreaming: true,
78
+ },
79
+ 'claude-3-sonnet-20240229': {
80
+ provider: 'anthropic',
81
+ model: 'claude-3-sonnet-20240229',
82
+ inputCostPer1M: 3.00,
83
+ outputCostPer1M: 15.00,
84
+ maxContextTokens: 200000,
85
+ maxConcurrentRequests: 5,
86
+ recommendedTemperature: 0.7,
87
+ supportsStreaming: true,
88
+ },
89
+ 'claude-3-haiku-20240307': {
90
+ provider: 'anthropic',
91
+ model: 'claude-3-haiku-20240307',
92
+ inputCostPer1M: 0.25,
93
+ outputCostPer1M: 1.25,
94
+ maxContextTokens: 200000,
95
+ maxConcurrentRequests: 5,
96
+ recommendedTemperature: 0.7,
97
+ supportsStreaming: true,
98
+ },
99
+
100
+ // Local/self-hosted models (no cost)
101
+ 'llama3.1': {
102
+ provider: 'ollama',
103
+ model: 'llama3.1',
104
+ inputCostPer1M: 0,
105
+ outputCostPer1M: 0,
106
+ maxContextTokens: 128000,
107
+ recommendedTemperature: 0.7,
108
+ supportsStreaming: true,
109
+ },
110
+ 'qwen2.5:7b': {
111
+ provider: 'ollama',
112
+ model: 'qwen2.5:7b',
113
+ inputCostPer1M: 0,
114
+ outputCostPer1M: 0,
115
+ maxContextTokens: 32768,
116
+ recommendedTemperature: 0.7,
117
+ supportsStreaming: true,
118
+ },
119
+ 'deepseek-coder': {
120
+ provider: 'ollama',
121
+ model: 'deepseek-coder',
122
+ inputCostPer1M: 0,
123
+ outputCostPer1M: 0,
124
+ maxContextTokens: 16000,
125
+ recommendedTemperature: 0.7,
126
+ supportsStreaming: true,
127
+ },
128
+ };
129
+
130
+ export function getProviderMetadata(model: string): ProviderMetadata {
131
+ // Try exact match first
132
+ if (PROVIDER_METADATA[model]) {
133
+ return PROVIDER_METADATA[model];
134
+ }
135
+
136
+ // Try prefix match (e.g., "gpt-4o-2024-05-13" matches "gpt-4o")
137
+ for (const [key, metadata] of Object.entries(PROVIDER_METADATA)) {
138
+ if (model.startsWith(key)) {
139
+ return metadata;
140
+ }
141
+ }
142
+
143
+ // Default metadata for unknown models (assume local/free)
144
+ return {
145
+ provider: 'unknown',
146
+ model,
147
+ inputCostPer1M: 0,
148
+ outputCostPer1M: 0,
149
+ maxContextTokens: 8192,
150
+ recommendedTemperature: 0.7,
151
+ supportsStreaming: true,
152
+ };
153
+ }
154
+
155
+ export function estimateTokenCount(text: string): number {
156
+ // Rough approximation: 1 token ≈ 4 characters for English text
157
+ // More accurate would use tiktoken library, but this is sufficient for budget estimation
158
+ return Math.ceil(text.length / 4);
159
+ }
160
+
161
+ export function estimateCost(
162
+ inputTokens: number,
163
+ outputTokens: number,
164
+ metadata: ProviderMetadata
165
+ ): number {
166
+ if (!metadata.inputCostPer1M || !metadata.outputCostPer1M) {
167
+ return 0;
168
+ }
169
+
170
+ const inputCost = (inputTokens / 1_000_000) * metadata.inputCostPer1M;
171
+ const outputCost = (outputTokens / 1_000_000) * metadata.outputCostPer1M;
172
+
173
+ return inputCost + outputCost;
174
+ }
@@ -0,0 +1,143 @@
1
+ // Session configuration for AI Coder Phase 2
2
+ // Manages CLI arguments and session metadata using provider/model semantics
3
+
4
+ import { existsSync, statSync } from 'fs';
5
+ import path from 'path';
6
+ import os from 'os';
7
+
8
+ export type Provider = 'ollama' | 'vllm';
9
+
10
+ export interface SessionConfig {
11
+ provider: Provider;
12
+ model: string;
13
+ baseUrl?: string;
14
+ workspace: string;
15
+ temperature: number;
16
+ seed?: number;
17
+ planCount: 1 | 2;
18
+ sessionId: string;
19
+ timestamp: number;
20
+ }
21
+
22
+ export interface CLIArgs {
23
+ provider?: string;
24
+ model?: string;
25
+ 'base-url'?: string;
26
+ workspace?: string;
27
+ temperature?: string;
28
+ seed?: string;
29
+ plans?: string;
30
+ [key: string]: string | undefined;
31
+ }
32
+
33
+ export function parseCliArgs(argv: string[]): CLIArgs {
34
+ const args: CLIArgs = {};
35
+
36
+ for (let i = 0; i < argv.length; i++) {
37
+ const arg = argv[i];
38
+ if (arg.startsWith('--')) {
39
+ // Support --key=value form
40
+ if (arg.includes('=')) {
41
+ const pair = arg.slice(2);
42
+ const eqIndex = pair.indexOf('=');
43
+ const key = pair.slice(0, eqIndex);
44
+ const value = pair.slice(eqIndex + 1);
45
+ if (key.length > 0) {
46
+ args[key] = value;
47
+ }
48
+ continue;
49
+ }
50
+
51
+ // Support space-separated --key value form
52
+ const key = arg.slice(2);
53
+ const value = argv[i + 1];
54
+ if (value && !value.startsWith('--')) {
55
+ args[key] = value;
56
+ i++;
57
+ }
58
+ }
59
+ }
60
+
61
+ return args;
62
+ }
63
+
64
+ export function validateAndNormalizeConfig(args: CLIArgs): SessionConfig {
65
+ const provider = (args.provider as Provider) || 'ollama';
66
+ if (!['ollama', 'vllm'].includes(provider)) {
67
+ throw new Error(`Invalid --provider: ${args.provider}. Must be "ollama" or "vllm".`);
68
+ }
69
+
70
+ const model = args.model || (provider === 'ollama' ? 'llama3.1' : undefined);
71
+ const missing: string[] = [];
72
+
73
+ if (!model) missing.push('--model');
74
+ if (!args.workspace || args.workspace.trim().length === 0) missing.push('--workspace');
75
+
76
+ if (missing.length > 0) {
77
+ throw new Error(
78
+ `Missing required parameters: ${missing.join(', ')}\n\n` +
79
+ `ACM AI Coder requires these parameters to start:\n` +
80
+ ` --provider <ollama|vllm> LLM provider (default: ollama)\n` +
81
+ ` --model <name> Model identifier (e.g., llama3.1, gpt-4o)\n` +
82
+ ` --workspace <path> REQUIRED: absolute or relative path to project root\n\n` +
83
+ `Optional parameters:\n` +
84
+ ` --base-url <url> Override provider base URL\n` +
85
+ ` --temperature <0-2> LLM temperature (default: 0.7)\n` +
86
+ ` --seed <number> Random seed for reproducibility\n` +
87
+ ` --plans <1|2> Number of alternative plans (default: 1)\n\n` +
88
+ `Examples:\n` +
89
+ ` acm-aicoder --provider vllm --model gpt-4o --workspace /abs/path\n` +
90
+ ` acm-aicoder --provider ollama --model llama3.1 --workspace=~/myproject`
91
+ );
92
+ }
93
+
94
+ const temperature = args.temperature ? parseFloat(args.temperature) : 0.7;
95
+ if (isNaN(temperature) || temperature < 0 || temperature > 2) {
96
+ throw new Error(`Invalid --temperature: must be between 0 and 2`);
97
+ }
98
+
99
+ const seed = args.seed ? parseInt(args.seed, 10) : undefined;
100
+ if (seed !== undefined && Number.isNaN(seed)) {
101
+ throw new Error(`Invalid --seed: must be a number`);
102
+ }
103
+
104
+ const planCount = args.plans === '2' ? 2 : 1;
105
+
106
+ // Enforce explicit workspace and normalize
107
+ const baseCwd = process.env.INIT_CWD || process.env.PWD || process.cwd();
108
+ let workspaceInput = args.workspace!;
109
+
110
+ // Expand ~ to user home
111
+ if (workspaceInput.startsWith('~/')) {
112
+ workspaceInput = path.join(os.homedir(), workspaceInput.slice(2));
113
+ }
114
+
115
+ const resolvedWorkspace = path.isAbsolute(workspaceInput)
116
+ ? workspaceInput
117
+ : path.resolve(baseCwd, workspaceInput);
118
+
119
+ if (!existsSync(resolvedWorkspace)) {
120
+ throw new Error(
121
+ `Workspace path "${resolvedWorkspace}" does not exist. Please provide a valid --workspace.`
122
+ );
123
+ }
124
+
125
+ const stats = statSync(resolvedWorkspace);
126
+ if (!stats.isDirectory()) {
127
+ throw new Error(
128
+ `Workspace path "${resolvedWorkspace}" is not a directory. Please provide a valid --workspace.`
129
+ );
130
+ }
131
+
132
+ return {
133
+ provider,
134
+ model: model!,
135
+ baseUrl: args['base-url'],
136
+ workspace: resolvedWorkspace,
137
+ temperature,
138
+ seed,
139
+ planCount,
140
+ sessionId: `session-${Date.now()}`,
141
+ timestamp: Date.now(),
142
+ };
143
+ }