acmecode 1.0.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 (131) hide show
  1. package/.acmecode/config.json +6 -0
  2. package/README.md +124 -0
  3. package/dist/agent/index.js +161 -0
  4. package/dist/cli/bin/acmecode.js +3 -0
  5. package/dist/cli/package.json +25 -0
  6. package/dist/cli/src/index.d.ts +1 -0
  7. package/dist/cli/src/index.js +53 -0
  8. package/dist/config/index.js +92 -0
  9. package/dist/context/index.js +30 -0
  10. package/dist/core/src/agent/index.d.ts +52 -0
  11. package/dist/core/src/agent/index.js +476 -0
  12. package/dist/core/src/config/index.d.ts +83 -0
  13. package/dist/core/src/config/index.js +318 -0
  14. package/dist/core/src/context/index.d.ts +1 -0
  15. package/dist/core/src/context/index.js +30 -0
  16. package/dist/core/src/llm/provider.d.ts +27 -0
  17. package/dist/core/src/llm/provider.js +202 -0
  18. package/dist/core/src/llm/vision.d.ts +7 -0
  19. package/dist/core/src/llm/vision.js +37 -0
  20. package/dist/core/src/mcp/index.d.ts +10 -0
  21. package/dist/core/src/mcp/index.js +84 -0
  22. package/dist/core/src/prompt/anthropic.d.ts +1 -0
  23. package/dist/core/src/prompt/anthropic.js +32 -0
  24. package/dist/core/src/prompt/architect.d.ts +1 -0
  25. package/dist/core/src/prompt/architect.js +17 -0
  26. package/dist/core/src/prompt/autopilot.d.ts +1 -0
  27. package/dist/core/src/prompt/autopilot.js +18 -0
  28. package/dist/core/src/prompt/beast.d.ts +1 -0
  29. package/dist/core/src/prompt/beast.js +83 -0
  30. package/dist/core/src/prompt/gemini.d.ts +1 -0
  31. package/dist/core/src/prompt/gemini.js +45 -0
  32. package/dist/core/src/prompt/index.d.ts +18 -0
  33. package/dist/core/src/prompt/index.js +239 -0
  34. package/dist/core/src/prompt/zen.d.ts +1 -0
  35. package/dist/core/src/prompt/zen.js +13 -0
  36. package/dist/core/src/session/index.d.ts +18 -0
  37. package/dist/core/src/session/index.js +97 -0
  38. package/dist/core/src/skills/index.d.ts +6 -0
  39. package/dist/core/src/skills/index.js +72 -0
  40. package/dist/core/src/tools/batch.d.ts +2 -0
  41. package/dist/core/src/tools/batch.js +65 -0
  42. package/dist/core/src/tools/browser.d.ts +7 -0
  43. package/dist/core/src/tools/browser.js +86 -0
  44. package/dist/core/src/tools/edit.d.ts +11 -0
  45. package/dist/core/src/tools/edit.js +312 -0
  46. package/dist/core/src/tools/index.d.ts +13 -0
  47. package/dist/core/src/tools/index.js +980 -0
  48. package/dist/core/src/tools/lsp-client.d.ts +11 -0
  49. package/dist/core/src/tools/lsp-client.js +224 -0
  50. package/dist/index.js +41 -0
  51. package/dist/llm/provider.js +34 -0
  52. package/dist/mcp/index.js +84 -0
  53. package/dist/session/index.js +74 -0
  54. package/dist/skills/index.js +32 -0
  55. package/dist/tools/index.js +96 -0
  56. package/dist/tui/App.js +297 -0
  57. package/dist/tui/Spinner.js +16 -0
  58. package/dist/tui/TextInput.js +98 -0
  59. package/dist/tui/src/App.d.ts +11 -0
  60. package/dist/tui/src/App.js +1211 -0
  61. package/dist/tui/src/CatLogo.d.ts +10 -0
  62. package/dist/tui/src/CatLogo.js +99 -0
  63. package/dist/tui/src/OptionList.d.ts +15 -0
  64. package/dist/tui/src/OptionList.js +60 -0
  65. package/dist/tui/src/Spinner.d.ts +7 -0
  66. package/dist/tui/src/Spinner.js +18 -0
  67. package/dist/tui/src/TextInput.d.ts +28 -0
  68. package/dist/tui/src/TextInput.js +139 -0
  69. package/dist/tui/src/Tips.d.ts +2 -0
  70. package/dist/tui/src/Tips.js +62 -0
  71. package/dist/tui/src/Toast.d.ts +19 -0
  72. package/dist/tui/src/Toast.js +39 -0
  73. package/dist/tui/src/TodoItem.d.ts +7 -0
  74. package/dist/tui/src/TodoItem.js +21 -0
  75. package/dist/tui/src/i18n.d.ts +172 -0
  76. package/dist/tui/src/i18n.js +189 -0
  77. package/dist/tui/src/markdown.d.ts +6 -0
  78. package/dist/tui/src/markdown.js +356 -0
  79. package/dist/tui/src/theme.d.ts +31 -0
  80. package/dist/tui/src/theme.js +239 -0
  81. package/output.txt +0 -0
  82. package/package.json +44 -0
  83. package/packages/cli/package.json +25 -0
  84. package/packages/cli/src/index.ts +59 -0
  85. package/packages/cli/tsconfig.json +26 -0
  86. package/packages/core/package.json +39 -0
  87. package/packages/core/src/agent/index.ts +588 -0
  88. package/packages/core/src/config/index.ts +383 -0
  89. package/packages/core/src/context/index.ts +34 -0
  90. package/packages/core/src/llm/provider.ts +237 -0
  91. package/packages/core/src/llm/vision.ts +43 -0
  92. package/packages/core/src/mcp/index.ts +110 -0
  93. package/packages/core/src/prompt/anthropic.ts +32 -0
  94. package/packages/core/src/prompt/architect.ts +17 -0
  95. package/packages/core/src/prompt/autopilot.ts +18 -0
  96. package/packages/core/src/prompt/beast.ts +83 -0
  97. package/packages/core/src/prompt/gemini.ts +45 -0
  98. package/packages/core/src/prompt/index.ts +267 -0
  99. package/packages/core/src/prompt/zen.ts +13 -0
  100. package/packages/core/src/session/index.ts +129 -0
  101. package/packages/core/src/skills/index.ts +86 -0
  102. package/packages/core/src/tools/batch.ts +73 -0
  103. package/packages/core/src/tools/browser.ts +95 -0
  104. package/packages/core/src/tools/edit.ts +317 -0
  105. package/packages/core/src/tools/index.ts +1112 -0
  106. package/packages/core/src/tools/lsp-client.ts +303 -0
  107. package/packages/core/tsconfig.json +19 -0
  108. package/packages/tui/package.json +24 -0
  109. package/packages/tui/src/App.tsx +1702 -0
  110. package/packages/tui/src/CatLogo.tsx +134 -0
  111. package/packages/tui/src/OptionList.tsx +95 -0
  112. package/packages/tui/src/Spinner.tsx +28 -0
  113. package/packages/tui/src/TextInput.tsx +202 -0
  114. package/packages/tui/src/Tips.tsx +64 -0
  115. package/packages/tui/src/Toast.tsx +60 -0
  116. package/packages/tui/src/TodoItem.tsx +29 -0
  117. package/packages/tui/src/i18n.ts +203 -0
  118. package/packages/tui/src/markdown.ts +403 -0
  119. package/packages/tui/src/theme.ts +287 -0
  120. package/packages/tui/tsconfig.json +24 -0
  121. package/tsconfig.json +18 -0
  122. package/vscode-acmecode/.vscodeignore +11 -0
  123. package/vscode-acmecode/README.md +57 -0
  124. package/vscode-acmecode/esbuild.js +46 -0
  125. package/vscode-acmecode/images/button-dark.svg +5 -0
  126. package/vscode-acmecode/images/button-light.svg +5 -0
  127. package/vscode-acmecode/images/icon.png +1 -0
  128. package/vscode-acmecode/package-lock.json +490 -0
  129. package/vscode-acmecode/package.json +87 -0
  130. package/vscode-acmecode/src/extension.ts +128 -0
  131. package/vscode-acmecode/tsconfig.json +16 -0
@@ -0,0 +1,303 @@
1
+ import { spawn, type ChildProcessWithoutNullStreams } from "child_process";
2
+ import path from "path";
3
+ import { pathToFileURL } from "url";
4
+ import {
5
+ createMessageConnection,
6
+ StreamMessageReader,
7
+ StreamMessageWriter,
8
+ MessageConnection,
9
+ } from "vscode-jsonrpc/lib/node/main.js";
10
+ import type { Diagnostic } from "vscode-languageserver-types";
11
+ import * as fs from "fs/promises";
12
+
13
+ export interface LspClient {
14
+ connection: MessageConnection;
15
+ process: ChildProcessWithoutNullStreams;
16
+ diagnostics: Map<string, Diagnostic[]>;
17
+ openFile: (filePath: string, timeoutMs?: number) => Promise<void>;
18
+ shutdown: () => Promise<void>;
19
+ }
20
+
21
+ type LanguageId = "typescript" | "python" | "go" | "rust";
22
+
23
+ interface ServerConfig {
24
+ command: string;
25
+ args: string[];
26
+ languageIdResolver: (filePath: string) => string;
27
+ }
28
+
29
+ const SERVER_CONFIGS: Record<LanguageId, ServerConfig> = {
30
+ typescript: {
31
+ command: process.platform === "win32" ? "npx.cmd" : "npx",
32
+ args: ["--no-install", "typescript-language-server", "--stdio"],
33
+ languageIdResolver: (filePath) =>
34
+ filePath.endsWith(".tsx")
35
+ ? "typescriptreact"
36
+ : filePath.endsWith(".jsx")
37
+ ? "javascriptreact"
38
+ : filePath.endsWith(".js")
39
+ ? "javascript"
40
+ : "typescript",
41
+ },
42
+ python: {
43
+ command: process.platform === "win32" ? "npx.cmd" : "npx",
44
+ // npx pyright-langserver will use standard pyright if available
45
+ args: ["--no-install", "pyright-langserver", "--stdio"],
46
+ languageIdResolver: () => "python",
47
+ },
48
+ go: {
49
+ command: "gopls",
50
+ args: [], // gopls runs in stdio mode by default
51
+ languageIdResolver: () => "go",
52
+ },
53
+ rust: {
54
+ command: "rust-analyzer",
55
+ args: [],
56
+ languageIdResolver: () => "rust",
57
+ },
58
+ };
59
+
60
+ const clients = new Map<LanguageId, LspClient>();
61
+ const clientInitializationPromises = new Map<LanguageId, Promise<LspClient>>();
62
+
63
+ // Track file versions globally across all servers
64
+ const fileVersions = new Map<string, number>();
65
+
66
+ function getLanguageIdForExtension(filePath: string): LanguageId | null {
67
+ const ext = path.extname(filePath).toLowerCase();
68
+ if ([".ts", ".tsx", ".js", ".jsx", ".cjs", ".mjs"].includes(ext))
69
+ return "typescript";
70
+ if ([".py", ".pyi"].includes(ext)) return "python";
71
+ if ([".go"].includes(ext)) return "go";
72
+ if ([".rs"].includes(ext)) return "rust";
73
+ return null;
74
+ }
75
+
76
+ async function getTsServerPath(workspaceRoot: string): Promise<string | null> {
77
+ const localTsServer = path.join(
78
+ workspaceRoot,
79
+ "node_modules",
80
+ "typescript",
81
+ "lib",
82
+ "tsserver.js",
83
+ );
84
+ try {
85
+ await fs.stat(localTsServer);
86
+ return localTsServer;
87
+ } catch {}
88
+ return null;
89
+ }
90
+
91
+ async function resolveTsLsCommand(
92
+ workspaceRoot: string,
93
+ ): Promise<{ command: string; args: string[] }> {
94
+ // Walk up from workspaceRoot looking for node_modules/.bin/typescript-language-server
95
+ const bin =
96
+ process.platform === "win32"
97
+ ? "typescript-language-server.cmd"
98
+ : "typescript-language-server";
99
+ let dir = workspaceRoot;
100
+ for (let i = 0; i < 5; i++) {
101
+ const candidate = path.join(dir, "node_modules", ".bin", bin);
102
+ try {
103
+ await fs.access(candidate);
104
+ return { command: candidate, args: ["--stdio"] };
105
+ } catch {}
106
+ const parent = path.dirname(dir);
107
+ if (parent === dir) break;
108
+ dir = parent;
109
+ }
110
+ // Fallback: try global install via npx (with --no-install to avoid slow download)
111
+ return {
112
+ command: process.platform === "win32" ? "npx.cmd" : "npx",
113
+ args: ["--no-install", "typescript-language-server", "--stdio"],
114
+ };
115
+ }
116
+
117
+ export async function getLspClientForFile(
118
+ workspaceRoot: string,
119
+ filePath: string,
120
+ ): Promise<LspClient> {
121
+ const langId = getLanguageIdForExtension(filePath);
122
+ if (!langId) {
123
+ throw new Error(`Unsupported file extension for LSP: ${filePath}`);
124
+ }
125
+
126
+ if (clients.has(langId)) {
127
+ return clients.get(langId)!;
128
+ }
129
+
130
+ if (!clientInitializationPromises.has(langId)) {
131
+ const promise = initializeLspClient(workspaceRoot, langId).catch((err) => {
132
+ clientInitializationPromises.delete(langId);
133
+ throw err;
134
+ });
135
+ clientInitializationPromises.set(langId, promise);
136
+ }
137
+
138
+ return clientInitializationPromises.get(langId)!;
139
+ }
140
+
141
+ async function initializeLspClient(
142
+ workspaceRoot: string,
143
+ langId: LanguageId,
144
+ ): Promise<LspClient> {
145
+ let config = SERVER_CONFIGS[langId];
146
+
147
+ // For TypeScript, prefer the local node_modules binary over npx
148
+ if (langId === "typescript") {
149
+ const resolved = await resolveTsLsCommand(workspaceRoot);
150
+ config = { ...config, ...resolved };
151
+ }
152
+
153
+ console.log(
154
+ `[LSP] Starting ${langId} language server (${config.command} ${config.args.join(" ")})...`,
155
+ );
156
+
157
+ const proc = spawn(config.command, config.args, {
158
+ cwd: workspaceRoot,
159
+ env: { ...process.env },
160
+ shell: false, // direct binary, no shell needed
161
+ });
162
+
163
+ // Fast-fail: if the process exits immediately, it's not installed
164
+ await new Promise<void>((resolve, reject) => {
165
+ const onExit = (code: number | null) => {
166
+ reject(
167
+ new Error(
168
+ `[LSP] ${langId} server exited immediately (code ${code}). Is it installed?`,
169
+ ),
170
+ );
171
+ };
172
+ proc.once("exit", onExit);
173
+ // Give it 500ms to either crash or start successfully
174
+ setTimeout(() => {
175
+ proc.removeListener("exit", onExit);
176
+ resolve();
177
+ }, 500);
178
+ });
179
+
180
+ // Capture stderr for debug logging
181
+ proc.stderr.on("data", (data) => {
182
+ // console.error(`[LSP ${langId}] ${data.toString()}`);
183
+ });
184
+
185
+ const connection = createMessageConnection(
186
+ new StreamMessageReader(proc.stdout),
187
+ new StreamMessageWriter(proc.stdin),
188
+ );
189
+
190
+ const diagnosticsMap = new Map<string, Diagnostic[]>();
191
+ // Listeners waiting for diagnostics on a specific URI
192
+ const diagnosticsListeners = new Map<string, Array<() => void>>();
193
+
194
+ connection.onNotification(
195
+ "textDocument/publishDiagnostics",
196
+ (params: any) => {
197
+ diagnosticsMap.set(params.uri, params.diagnostics);
198
+ // Notify any waiters for this URI
199
+ const listeners = diagnosticsListeners.get(params.uri);
200
+ if (listeners) {
201
+ diagnosticsListeners.delete(params.uri);
202
+ for (const cb of listeners) cb();
203
+ }
204
+ },
205
+ );
206
+
207
+ connection.onRequest("window/workDoneProgress/create", () => null);
208
+ connection.onRequest("workspace/configuration", () => [{}]);
209
+
210
+ connection.listen();
211
+
212
+ let initializationOptions: any = {};
213
+ if (langId === "typescript") {
214
+ const tsserverPath = await getTsServerPath(workspaceRoot);
215
+ if (tsserverPath) {
216
+ initializationOptions = { tsserver: { path: tsserverPath } };
217
+ }
218
+ }
219
+
220
+ // 1. Initialize (with timeout to avoid hanging on slow server startup)
221
+ const INIT_TIMEOUT_MS = 15000;
222
+ await Promise.race([
223
+ connection.sendRequest("initialize", {
224
+ processId: process.pid,
225
+ rootUri: pathToFileURL(workspaceRoot).href,
226
+ capabilities: {
227
+ textDocument: {
228
+ synchronization: { didOpen: true, didChange: true },
229
+ publishDiagnostics: { relatedInformation: true },
230
+ },
231
+ },
232
+ initializationOptions,
233
+ }),
234
+ new Promise<never>((_, reject) =>
235
+ setTimeout(
236
+ () =>
237
+ reject(
238
+ new Error(`[LSP] initialize timed out after ${INIT_TIMEOUT_MS}ms`),
239
+ ),
240
+ INIT_TIMEOUT_MS,
241
+ ),
242
+ ),
243
+ ]);
244
+
245
+ // 2. Initialized
246
+ await connection.sendNotification("initialized", {});
247
+
248
+ const client: LspClient = {
249
+ connection,
250
+ process: proc,
251
+ diagnostics: diagnosticsMap,
252
+ openFile: async (filePath: string, timeoutMs = 3000) => {
253
+ const uri = pathToFileURL(filePath).href;
254
+ const content = await fs.readFile(filePath, "utf8");
255
+ const version = fileVersions.get(uri);
256
+ const resolvedLangId = config.languageIdResolver(filePath);
257
+
258
+ // Set up a promise that resolves when publishDiagnostics fires for this URI
259
+ const diagReady = new Promise<void>((resolve) => {
260
+ const existing = diagnosticsListeners.get(uri) ?? [];
261
+ existing.push(resolve);
262
+ diagnosticsListeners.set(uri, existing);
263
+ });
264
+
265
+ if (version !== undefined) {
266
+ const nextVersion = version + 1;
267
+ fileVersions.set(uri, nextVersion);
268
+ await connection.sendNotification("textDocument/didChange", {
269
+ textDocument: { uri, version: nextVersion },
270
+ contentChanges: [{ text: content }],
271
+ });
272
+ } else {
273
+ fileVersions.set(uri, 0);
274
+ await connection.sendNotification("textDocument/didOpen", {
275
+ textDocument: {
276
+ uri,
277
+ languageId: resolvedLangId,
278
+ version: 0,
279
+ text: content,
280
+ },
281
+ });
282
+ }
283
+
284
+ // Wait for diagnostics or timeout — whichever comes first
285
+ await Promise.race([
286
+ diagReady,
287
+ new Promise<void>((resolve) => setTimeout(resolve, timeoutMs)),
288
+ ]);
289
+ },
290
+ shutdown: async () => {
291
+ await connection.sendRequest("shutdown");
292
+ await connection.sendNotification("exit");
293
+ connection.dispose();
294
+ proc.kill();
295
+ clients.delete(langId);
296
+ clientInitializationPromises.delete(langId);
297
+ // Note: fileVersions is global, we don't clear it here so documents stay "open" if another server needs them
298
+ },
299
+ };
300
+
301
+ clients.set(langId, client);
302
+ return client;
303
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "esModuleInterop": true,
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "outDir": "dist",
11
+ "rootDir": "src",
12
+ "declaration": true,
13
+ "composite": true,
14
+ "jsx": "react"
15
+ },
16
+ "include": [
17
+ "src/**/*"
18
+ ]
19
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@acmecode/tui",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "main": "dist/index.js",
6
+ "exports": {
7
+ "./*": "./dist/*"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc"
11
+ },
12
+ "dependencies": {
13
+ "@acmecode/core": "^1.0.0",
14
+ "ink": "^6.8.0",
15
+ "ink-text-input": "^6.0.0",
16
+ "marked": "^17.0.3",
17
+ "picocolors": "^1.1.1",
18
+ "react": "^19.2.4"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^25.3.0",
22
+ "@types/react": "^19.2.14"
23
+ }
24
+ }