@phmotad/fire-code 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands/index-cmd.d.ts +1 -0
- package/dist/cli/commands/index-cmd.d.ts.map +1 -1
- package/dist/cli/commands/index-cmd.js +83 -14
- package/dist/cli/commands/index-cmd.js.map +1 -1
- package/dist/cli/commands/install.d.ts.map +1 -1
- package/dist/cli/commands/install.js +290 -171
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/core/ExecutionEngine.d.ts +3 -1
- package/dist/core/ExecutionEngine.d.ts.map +1 -1
- package/dist/core/ExecutionEngine.js +36 -17
- package/dist/core/ExecutionEngine.js.map +1 -1
- package/dist/db/DatabaseManager.d.ts +4 -0
- package/dist/db/DatabaseManager.d.ts.map +1 -1
- package/dist/db/DatabaseManager.js +13 -0
- package/dist/db/DatabaseManager.js.map +1 -1
- package/dist/db/schema.d.ts +1 -1
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +20 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/git/GitManager.d.ts +10 -0
- package/dist/git/GitManager.d.ts.map +1 -1
- package/dist/git/GitManager.js +46 -0
- package/dist/git/GitManager.js.map +1 -1
- package/dist/graph/GraphStore.d.ts +6 -1
- package/dist/graph/GraphStore.d.ts.map +1 -1
- package/dist/graph/InMemoryGraphStore.d.ts +1 -0
- package/dist/graph/InMemoryGraphStore.d.ts.map +1 -1
- package/dist/graph/InMemoryGraphStore.js +13 -2
- package/dist/graph/InMemoryGraphStore.js.map +1 -1
- package/dist/graph/SQLiteGraphStore.d.ts.map +1 -1
- package/dist/graph/SQLiteGraphStore.js +8 -2
- package/dist/graph/SQLiteGraphStore.js.map +1 -1
- package/dist/indexing/ASTParser.d.ts +1 -1
- package/dist/indexing/ASTParser.d.ts.map +1 -1
- package/dist/indexing/ASTParser.js +7 -1
- package/dist/indexing/ASTParser.js.map +1 -1
- package/dist/indexing/EmbeddingGenerator.d.ts.map +1 -1
- package/dist/indexing/EmbeddingGenerator.js +2 -25
- package/dist/indexing/EmbeddingGenerator.js.map +1 -1
- package/dist/indexing/FileScanner.d.ts.map +1 -1
- package/dist/indexing/FileScanner.js +2 -1
- package/dist/indexing/FileScanner.js.map +1 -1
- package/dist/indexing/GitIndexer.d.ts +4 -0
- package/dist/indexing/GitIndexer.d.ts.map +1 -0
- package/dist/indexing/GitIndexer.js +59 -0
- package/dist/indexing/GitIndexer.js.map +1 -0
- package/dist/indexing/GraphBuilder.d.ts.map +1 -1
- package/dist/indexing/GraphBuilder.js +21 -1
- package/dist/indexing/GraphBuilder.js.map +1 -1
- package/dist/indexing/Indexer.d.ts +3 -2
- package/dist/indexing/Indexer.d.ts.map +1 -1
- package/dist/indexing/Indexer.js +25 -6
- package/dist/indexing/Indexer.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +20 -7
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/execute.d.ts +3 -0
- package/dist/mcp/tools/execute.d.ts.map +1 -1
- package/dist/mcp/tools/execute.js +2 -0
- package/dist/mcp/tools/execute.js.map +1 -1
- package/dist/mcp/tools/find_similar.d.ts +17 -0
- package/dist/mcp/tools/find_similar.d.ts.map +1 -0
- package/dist/mcp/tools/find_similar.js +95 -0
- package/dist/mcp/tools/find_similar.js.map +1 -0
- package/dist/mcp/tools/get_context.d.ts +3 -0
- package/dist/mcp/tools/get_context.d.ts.map +1 -1
- package/dist/mcp/tools/get_context.js +68 -7
- package/dist/mcp/tools/get_context.js.map +1 -1
- package/dist/mcp/tools/search_code.d.ts.map +1 -1
- package/dist/mcp/tools/search_code.js +22 -4
- package/dist/mcp/tools/search_code.js.map +1 -1
- package/dist/mcp/tools/smart_search.d.ts.map +1 -1
- package/dist/mcp/tools/smart_search.js +122 -29
- package/dist/mcp/tools/smart_search.js.map +1 -1
- package/dist/memory/HybridMemory.d.ts +4 -0
- package/dist/memory/HybridMemory.d.ts.map +1 -1
- package/dist/memory/HybridMemory.js +120 -29
- package/dist/memory/HybridMemory.js.map +1 -1
- package/dist/utils/modelManager.d.ts +37 -0
- package/dist/utils/modelManager.d.ts.map +1 -0
- package/dist/utils/modelManager.js +90 -0
- package/dist/utils/modelManager.js.map +1 -0
- package/dist/utils/workerPool.d.ts +8 -0
- package/dist/utils/workerPool.d.ts.map +1 -0
- package/dist/utils/workerPool.js +75 -0
- package/dist/utils/workerPool.js.map +1 -0
- package/dist/vector/MemoryVectorStore.d.ts.map +1 -1
- package/dist/vector/MemoryVectorStore.js +19 -13
- package/dist/vector/MemoryVectorStore.js.map +1 -1
- package/dist/vector/SQLiteVectorStore.d.ts +13 -0
- package/dist/vector/SQLiteVectorStore.d.ts.map +1 -0
- package/dist/vector/SQLiteVectorStore.js +111 -0
- package/dist/vector/SQLiteVectorStore.js.map +1 -0
- package/dist/vector/VectorStore.d.ts +0 -1
- package/dist/vector/VectorStore.d.ts.map +1 -1
- package/dist/workers/embeddingWorker.d.ts +2 -0
- package/dist/workers/embeddingWorker.d.ts.map +1 -0
- package/dist/workers/embeddingWorker.js +42 -0
- package/dist/workers/embeddingWorker.js.map +1 -0
- package/package.json +3 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
|
@@ -10,24 +10,28 @@ const os_1 = require("os");
|
|
|
10
10
|
const path_1 = require("path");
|
|
11
11
|
const chalk_1 = __importDefault(require("chalk"));
|
|
12
12
|
const ora_1 = __importDefault(require("ora"));
|
|
13
|
-
// __dirname is CJS-native; resolves to dist/cli/commands → 3 levels up = package root
|
|
14
13
|
const PLUGIN_ROOT = (0, path_1.resolve)(__dirname, '..', '..', '..');
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
|
|
14
|
+
const INJECT_SCRIPT = (0, path_1.join)(PLUGIN_ROOT, 'plugin', 'scripts', 'context-inject.js');
|
|
15
|
+
const IDE_ALIASES = {
|
|
16
|
+
claude: 'claude-code',
|
|
17
|
+
'claude-code': 'claude-code',
|
|
18
|
+
cursor: 'cursor',
|
|
19
|
+
windsurf: 'windsurf',
|
|
20
|
+
opencode: 'opencode',
|
|
21
|
+
codex: 'codex',
|
|
22
|
+
gemini: 'gemini',
|
|
23
|
+
goose: 'goose',
|
|
24
|
+
generic: 'generic',
|
|
25
|
+
};
|
|
26
|
+
function resolveIde(input) {
|
|
27
|
+
return IDE_ALIASES[input.toLowerCase()];
|
|
28
|
+
}
|
|
25
29
|
const MCP_SERVER_ENTRY = {
|
|
26
30
|
command: 'npx',
|
|
27
31
|
args: ['@phmotad/fire-code', 'dev'],
|
|
28
32
|
description: 'Fire Code — intelligent MCP execution engine',
|
|
29
33
|
};
|
|
30
|
-
// ──
|
|
34
|
+
// ── JSON helpers ─────────────────────────────────────────────────────────────
|
|
31
35
|
function readJson(filePath) {
|
|
32
36
|
try {
|
|
33
37
|
if (!(0, fs_1.existsSync)(filePath))
|
|
@@ -39,29 +43,43 @@ function readJson(filePath) {
|
|
|
39
43
|
}
|
|
40
44
|
}
|
|
41
45
|
function writeJson(filePath, data) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
46
|
+
ensureDir(filePath);
|
|
47
|
+
(0, fs_1.writeFileSync)(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
|
|
48
|
+
}
|
|
49
|
+
function ensureDir(filePath) {
|
|
50
|
+
const sep = filePath.includes('/') ? '/' : '\\';
|
|
51
|
+
const dir = filePath.substring(0, filePath.lastIndexOf(sep));
|
|
45
52
|
if (dir && !(0, fs_1.existsSync)(dir))
|
|
46
53
|
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
47
|
-
(0, fs_1.writeFileSync)(filePath, JSON.stringify(data, null, 2) + '\n', 'utf8');
|
|
48
54
|
}
|
|
49
55
|
function registerMcp(mcpPath, serverKey = 'fire-code') {
|
|
50
|
-
const
|
|
51
|
-
if (!
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
writeJson(mcpPath,
|
|
56
|
+
const cfg = readJson(mcpPath);
|
|
57
|
+
if (!cfg['mcpServers'])
|
|
58
|
+
cfg['mcpServers'] = {};
|
|
59
|
+
cfg['mcpServers'][serverKey] = MCP_SERVER_ENTRY;
|
|
60
|
+
writeJson(mcpPath, cfg);
|
|
61
|
+
}
|
|
62
|
+
function hookCmd(event) {
|
|
63
|
+
return `node "${INJECT_SCRIPT}" ${event}`;
|
|
64
|
+
}
|
|
65
|
+
function isFireCodeHook(entry) {
|
|
66
|
+
const cmd = String(entry['command'] ?? '');
|
|
67
|
+
return cmd.includes('context-inject.js');
|
|
68
|
+
}
|
|
69
|
+
function appendHook(array, entry) {
|
|
70
|
+
if (array.some(isFireCodeHook))
|
|
71
|
+
return array;
|
|
72
|
+
return [...array, entry];
|
|
73
|
+
}
|
|
74
|
+
function removeFireCodeHooks(array) {
|
|
75
|
+
return array.filter(e => !isFireCodeHook(e));
|
|
55
76
|
}
|
|
56
|
-
// ──
|
|
77
|
+
// ── Claude Code ───────────────────────────────────────────────────────────────
|
|
57
78
|
function installClaudeCode() {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
const mcpPath = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'claude_desktop_config.json');
|
|
79
|
+
const h = (0, os_1.homedir)();
|
|
80
|
+
const mcpPath = (0, path_1.join)(h, '.claude', 'claude_desktop_config.json');
|
|
61
81
|
registerMcp(mcpPath);
|
|
62
|
-
|
|
63
|
-
// Plugin hooks
|
|
64
|
-
const settingsPath = (0, path_1.join)((0, os_1.homedir)(), '.claude', 'settings.json');
|
|
82
|
+
const settingsPath = (0, path_1.join)(h, '.claude', 'settings.json');
|
|
65
83
|
const settings = readJson(settingsPath);
|
|
66
84
|
if (!settings['plugins'])
|
|
67
85
|
settings['plugins'] = {};
|
|
@@ -70,68 +88,177 @@ function installClaudeCode() {
|
|
|
70
88
|
hooksPath: (0, path_1.join)(PLUGIN_ROOT, 'plugin', 'hooks', 'hooks.json'),
|
|
71
89
|
};
|
|
72
90
|
writeJson(settingsPath, settings);
|
|
73
|
-
|
|
74
|
-
|
|
91
|
+
return [
|
|
92
|
+
'MCP server → ~/.claude/claude_desktop_config.json',
|
|
93
|
+
'Hooks (SessionStart, PostToolUse, Stop) → ~/.claude/settings.json',
|
|
94
|
+
];
|
|
75
95
|
}
|
|
96
|
+
// ── Cursor ────────────────────────────────────────────────────────────────────
|
|
76
97
|
function installCursor() {
|
|
77
|
-
const
|
|
78
|
-
registerMcp(
|
|
79
|
-
|
|
98
|
+
const h = (0, os_1.homedir)();
|
|
99
|
+
registerMcp((0, path_1.join)(h, '.cursor', 'mcp.json'));
|
|
100
|
+
const hooksPath = (0, path_1.join)(h, '.cursor', 'hooks.json');
|
|
101
|
+
const cfg = readJson(hooksPath);
|
|
102
|
+
if (!cfg['version'])
|
|
103
|
+
cfg['version'] = 1;
|
|
104
|
+
if (!cfg['hooks'])
|
|
105
|
+
cfg['hooks'] = {};
|
|
106
|
+
const hooks = cfg['hooks'];
|
|
107
|
+
hooks['beforeSubmitPrompt'] = appendHook(hooks['beforeSubmitPrompt'] ?? [], { command: hookCmd('session-start'), timeout: 10 });
|
|
108
|
+
hooks['beforeReadFile'] = appendHook(hooks['beforeReadFile'] ?? [], { command: hookCmd('pre-read'), timeout: 5 });
|
|
109
|
+
hooks['afterFileEdit'] = appendHook(hooks['afterFileEdit'] ?? [], { command: hookCmd('post-tool'), timeout: 30 });
|
|
110
|
+
hooks['stop'] = appendHook(hooks['stop'] ?? [], { command: hookCmd('stop'), timeout: 30 });
|
|
111
|
+
writeJson(hooksPath, cfg);
|
|
112
|
+
return [
|
|
113
|
+
'MCP server → ~/.cursor/mcp.json',
|
|
114
|
+
'Hooks (beforeSubmitPrompt, beforeReadFile, afterFileEdit, stop) → ~/.cursor/hooks.json',
|
|
115
|
+
];
|
|
80
116
|
}
|
|
117
|
+
// ── Windsurf ──────────────────────────────────────────────────────────────────
|
|
81
118
|
function installWindsurf() {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
119
|
+
const h = (0, os_1.homedir)();
|
|
120
|
+
registerMcp((0, path_1.join)(h, '.codeium', 'windsurf', 'mcp_config.json'));
|
|
121
|
+
const hooksPath = (0, path_1.join)(h, '.codeium', 'windsurf', 'hooks.json');
|
|
122
|
+
const cfg = readJson(hooksPath);
|
|
123
|
+
if (!cfg['hooks'])
|
|
124
|
+
cfg['hooks'] = {};
|
|
125
|
+
const hooks = cfg['hooks'];
|
|
126
|
+
hooks['pre_read_code'] = appendHook(hooks['pre_read_code'] ?? [], { command: hookCmd('pre-read'), show_output: false });
|
|
127
|
+
hooks['post_write_code'] = appendHook(hooks['post_write_code'] ?? [], { command: hookCmd('post-tool'), show_output: false });
|
|
128
|
+
hooks['post_mcp_tool_use'] = appendHook(hooks['post_mcp_tool_use'] ?? [], { command: hookCmd('post-tool'), show_output: false });
|
|
129
|
+
writeJson(hooksPath, cfg);
|
|
130
|
+
return [
|
|
131
|
+
'MCP server → ~/.codeium/windsurf/mcp_config.json',
|
|
132
|
+
'Hooks (pre_read_code, post_write_code, post_mcp_tool_use) → ~/.codeium/windsurf/hooks.json',
|
|
133
|
+
];
|
|
86
134
|
}
|
|
135
|
+
// ── OpenCode ──────────────────────────────────────────────────────────────────
|
|
87
136
|
function installOpenCode() {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
137
|
+
const h = (0, os_1.homedir)();
|
|
138
|
+
// MCP
|
|
139
|
+
const configPath = (0, path_1.join)(h, '.config', 'opencode', 'config.json');
|
|
140
|
+
const cfg = readJson(configPath);
|
|
141
|
+
if (!cfg['mcp'])
|
|
142
|
+
cfg['mcp'] = {};
|
|
143
|
+
const mcp = cfg['mcp'];
|
|
94
144
|
if (!mcp['servers'])
|
|
95
145
|
mcp['servers'] = {};
|
|
96
146
|
mcp['servers']['fire-code'] = MCP_SERVER_ENTRY;
|
|
97
|
-
|
|
98
|
-
|
|
147
|
+
// Plugin: generate JS plugin file with the baked-in script path
|
|
148
|
+
const pluginContent = buildOpenCodePlugin();
|
|
149
|
+
if (!cfg['plugins'])
|
|
150
|
+
cfg['plugins'] = {};
|
|
151
|
+
cfg['plugins']['fire-code'] = { enabled: true };
|
|
152
|
+
writeJson(configPath, cfg);
|
|
153
|
+
const pluginsDir = (0, path_1.join)(h, '.config', 'opencode', 'plugins');
|
|
154
|
+
if (!(0, fs_1.existsSync)(pluginsDir))
|
|
155
|
+
(0, fs_1.mkdirSync)(pluginsDir, { recursive: true });
|
|
156
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(pluginsDir, 'fire-code.js'), pluginContent, 'utf8');
|
|
157
|
+
return [
|
|
158
|
+
'MCP server → ~/.config/opencode/config.json',
|
|
159
|
+
'Plugin (session.created, tool.execute.after) → ~/.config/opencode/plugins/fire-code.js',
|
|
160
|
+
];
|
|
161
|
+
}
|
|
162
|
+
function buildOpenCodePlugin() {
|
|
163
|
+
return `'use strict';
|
|
164
|
+
// Fire Code — OpenCode plugin (auto-generated by fire-code install)
|
|
165
|
+
const { execSync } = require('child_process');
|
|
166
|
+
const SCRIPT = ${JSON.stringify(INJECT_SCRIPT)};
|
|
167
|
+
|
|
168
|
+
function run(event, env) {
|
|
169
|
+
try { execSync('node "' + SCRIPT + '" ' + event, { env: { ...process.env, ...env }, stdio: 'ignore', timeout: 30000 }); } catch {}
|
|
99
170
|
}
|
|
171
|
+
|
|
172
|
+
module.exports = async (ctx) => ({
|
|
173
|
+
'session.created': () => run('session-start', { CLAUDE_CWD: ctx.directory ?? process.cwd() }),
|
|
174
|
+
'tool.execute.after': (input) => run('post-tool', {
|
|
175
|
+
CLAUDE_CWD: ctx.directory ?? process.cwd(),
|
|
176
|
+
CLAUDE_TOOL_NAME: String(input?.tool ?? ''),
|
|
177
|
+
CLAUDE_TOOL_INPUT_JSON: JSON.stringify(input?.args ?? {}),
|
|
178
|
+
}),
|
|
179
|
+
'session.compacted': () => run('stop', { CLAUDE_CWD: ctx.directory ?? process.cwd() }),
|
|
180
|
+
});
|
|
181
|
+
`;
|
|
182
|
+
}
|
|
183
|
+
// ── Codex CLI ─────────────────────────────────────────────────────────────────
|
|
100
184
|
function installCodex() {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
185
|
+
const h = (0, os_1.homedir)();
|
|
186
|
+
registerMcp((0, path_1.join)(h, '.codex', 'config.json'));
|
|
187
|
+
// Enable hooks feature flag in config.toml
|
|
188
|
+
const tomlPath = (0, path_1.join)(h, '.codex', 'config.toml');
|
|
189
|
+
const toml = (0, fs_1.existsSync)(tomlPath) ? (0, fs_1.readFileSync)(tomlPath, 'utf8') : '';
|
|
190
|
+
if (!toml.includes('codex_hooks')) {
|
|
191
|
+
ensureDir(tomlPath);
|
|
192
|
+
(0, fs_1.writeFileSync)(tomlPath, toml + '\n[features]\ncodex_hooks = true\n', 'utf8');
|
|
193
|
+
}
|
|
194
|
+
// Register hooks
|
|
195
|
+
const hooksPath = (0, path_1.join)(h, '.codex', 'hooks.json');
|
|
196
|
+
const cfg = readJson(hooksPath);
|
|
197
|
+
if (!cfg['hooks'])
|
|
198
|
+
cfg['hooks'] = {};
|
|
199
|
+
const hooks = cfg['hooks'];
|
|
200
|
+
hooks['SessionStart'] = mergeCodexHook(hooks['SessionStart'] ?? [], hookCmd('session-start'), '*', 10);
|
|
201
|
+
hooks['PostToolUse'] = mergeCodexHook(hooks['PostToolUse'] ?? [], hookCmd('post-tool'), '*', 30);
|
|
202
|
+
hooks['Stop'] = mergeCodexHookStop(hooks['Stop'] ?? [], hookCmd('stop'), 30);
|
|
203
|
+
writeJson(hooksPath, cfg);
|
|
204
|
+
return [
|
|
205
|
+
'MCP server → ~/.codex/config.json',
|
|
206
|
+
'Feature flag codex_hooks → ~/.codex/config.toml',
|
|
207
|
+
'Hooks (SessionStart, PostToolUse, Stop) → ~/.codex/hooks.json',
|
|
208
|
+
];
|
|
209
|
+
}
|
|
210
|
+
function mergeCodexHook(arr, cmd, matcher, timeout) {
|
|
211
|
+
const alreadySet = arr.some(g => (g['hooks'] ?? []).some(isFireCodeHook));
|
|
212
|
+
if (alreadySet)
|
|
213
|
+
return arr;
|
|
214
|
+
return [...arr, { matcher, hooks: [{ type: 'command', command: cmd, timeout }] }];
|
|
105
215
|
}
|
|
216
|
+
function mergeCodexHookStop(arr, cmd, timeout) {
|
|
217
|
+
const alreadySet = arr.some(g => (g['hooks'] ?? []).some(isFireCodeHook));
|
|
218
|
+
if (alreadySet)
|
|
219
|
+
return arr;
|
|
220
|
+
return [...arr, { hooks: [{ type: 'command', command: cmd, timeout }] }];
|
|
221
|
+
}
|
|
222
|
+
// ── Gemini CLI ────────────────────────────────────────────────────────────────
|
|
106
223
|
function installGemini() {
|
|
107
|
-
|
|
108
|
-
const settingsPath = (0, path_1.join)(
|
|
224
|
+
const h = (0, os_1.homedir)();
|
|
225
|
+
const settingsPath = (0, path_1.join)(h, '.gemini', 'settings.json');
|
|
109
226
|
const settings = readJson(settingsPath);
|
|
110
227
|
if (!settings['mcpServers'])
|
|
111
228
|
settings['mcpServers'] = {};
|
|
112
229
|
settings['mcpServers']['fire-code'] = MCP_SERVER_ENTRY;
|
|
230
|
+
if (!settings['hooks'])
|
|
231
|
+
settings['hooks'] = {};
|
|
232
|
+
const hooks = settings['hooks'];
|
|
233
|
+
hooks['SessionStart'] = mergeGeminiHook(hooks['SessionStart'] ?? [], hookCmd('session-start'), '*', 5000);
|
|
234
|
+
hooks['AfterTool'] = mergeGeminiHook(hooks['AfterTool'] ?? [], hookCmd('post-tool'), '.*', 30000);
|
|
235
|
+
hooks['SessionEnd'] = mergeGeminiHook(hooks['SessionEnd'] ?? [], hookCmd('stop'), '*', 30000);
|
|
113
236
|
writeJson(settingsPath, settings);
|
|
114
|
-
return [
|
|
237
|
+
return [
|
|
238
|
+
'MCP server → ~/.gemini/settings.json',
|
|
239
|
+
'Hooks (SessionStart, AfterTool, SessionEnd) → ~/.gemini/settings.json',
|
|
240
|
+
];
|
|
115
241
|
}
|
|
242
|
+
function mergeGeminiHook(arr, cmd, matcher, timeout) {
|
|
243
|
+
const alreadySet = arr.some(g => (g['hooks'] ?? []).some(isFireCodeHook));
|
|
244
|
+
if (alreadySet)
|
|
245
|
+
return arr;
|
|
246
|
+
return [...arr, { matcher, hooks: [{ type: 'command', command: cmd, timeout }] }];
|
|
247
|
+
}
|
|
248
|
+
// ── Goose ─────────────────────────────────────────────────────────────────────
|
|
116
249
|
function installGoose() {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
registerMcp(configPath);
|
|
120
|
-
return ['MCP server registered in ~/.config/goose/mcp.json'];
|
|
250
|
+
registerMcp((0, path_1.join)((0, os_1.homedir)(), '.config', 'goose', 'mcp.json'));
|
|
251
|
+
return ['MCP server → ~/.config/goose/mcp.json'];
|
|
121
252
|
}
|
|
253
|
+
// ── Generic ───────────────────────────────────────────────────────────────────
|
|
122
254
|
function installGeneric() {
|
|
123
|
-
// Write a standalone mcp.json in the current directory for manual wiring
|
|
124
255
|
const mcpPath = (0, path_1.join)(process.cwd(), '.firecode', 'mcp.json');
|
|
125
|
-
|
|
126
|
-
mcpServers: { 'fire-code': MCP_SERVER_ENTRY },
|
|
127
|
-
};
|
|
128
|
-
if (!(0, fs_1.existsSync)((0, path_1.join)(process.cwd(), '.firecode'))) {
|
|
256
|
+
if (!(0, fs_1.existsSync)((0, path_1.join)(process.cwd(), '.firecode')))
|
|
129
257
|
(0, fs_1.mkdirSync)((0, path_1.join)(process.cwd(), '.firecode'), { recursive: true });
|
|
130
|
-
}
|
|
131
|
-
(0, fs_1.writeFileSync)(mcpPath, JSON.stringify(config, null, 2) + '\n', 'utf8');
|
|
258
|
+
(0, fs_1.writeFileSync)(mcpPath, JSON.stringify({ mcpServers: { 'fire-code': MCP_SERVER_ENTRY } }, null, 2) + '\n', 'utf8');
|
|
132
259
|
return [
|
|
133
|
-
'MCP config
|
|
134
|
-
|
|
260
|
+
'MCP config → .firecode/mcp.json',
|
|
261
|
+
"Point your IDE's MCP setting to this file to complete setup",
|
|
135
262
|
];
|
|
136
263
|
}
|
|
137
264
|
// ── Global config bootstrap ──────────────────────────────────────────────────
|
|
@@ -142,10 +269,7 @@ function ensureGlobalConfig() {
|
|
|
142
269
|
const dir = (0, path_1.join)((0, os_1.homedir)(), '.firecode');
|
|
143
270
|
if (!(0, fs_1.existsSync)(dir))
|
|
144
271
|
(0, fs_1.mkdirSync)(dir, { recursive: true });
|
|
145
|
-
|
|
146
|
-
llm: { provider: 'openrouter' },
|
|
147
|
-
};
|
|
148
|
-
(0, fs_1.writeFileSync)(configPath, JSON.stringify(defaults, null, 2) + '\n', 'utf8');
|
|
272
|
+
(0, fs_1.writeFileSync)(configPath, JSON.stringify({ llm: { provider: 'openrouter' } }, null, 2) + '\n', 'utf8');
|
|
149
273
|
}
|
|
150
274
|
// ── agents.md ────────────────────────────────────────────────────────────────
|
|
151
275
|
function writeAgentsMd(cwd) {
|
|
@@ -154,30 +278,14 @@ function writeAgentsMd(cwd) {
|
|
|
154
278
|
return;
|
|
155
279
|
try {
|
|
156
280
|
const src = (0, path_1.join)(PLUGIN_ROOT, 'plugin', 'agents.md');
|
|
157
|
-
|
|
158
|
-
(0, fs_1.writeFileSync)(dest, content, 'utf8');
|
|
281
|
+
(0, fs_1.writeFileSync)(dest, (0, fs_1.existsSync)(src) ? (0, fs_1.readFileSync)(src, 'utf8') : defaultAgentsMd(), 'utf8');
|
|
159
282
|
}
|
|
160
283
|
catch { /* best-effort */ }
|
|
161
284
|
}
|
|
162
285
|
function defaultAgentsMd() {
|
|
163
|
-
return `# Fire Code — Agent Instructions
|
|
164
|
-
|
|
165
|
-
> This file is read automatically by your AI coding agent. Do not delete it.
|
|
166
|
-
|
|
167
|
-
You have Fire Code MCP tools available. **Use them without waiting to be asked.**
|
|
168
|
-
|
|
169
|
-
| Situation | Call |
|
|
170
|
-
|---|---|
|
|
171
|
-
| Before writing any code | \`firecode.smart_search({ query })\` then \`firecode.corpus_search({ query })\` |
|
|
172
|
-
| Before reading a file | \`firecode.smart_outline({ file_path })\` |
|
|
173
|
-
| Task touches > 2 files | \`firecode.get_context({ query: task })\` |
|
|
174
|
-
| Implement / fix / refactor | \`firecode.execute({ task, agent: "dev" })\` |
|
|
175
|
-
| Plan / design / coordinate | \`firecode.execute({ task, agent: "supervisor" })\` |
|
|
176
|
-
| Audit / review / inspect | \`firecode.execute({ task, agent: "review" })\` |
|
|
177
|
-
| Recall past work | \`firecode.observations({ query })\` |
|
|
178
|
-
`;
|
|
286
|
+
return `# Fire Code — Agent Instructions\n\n> Read automatically by your AI coding agent. Do not delete.\n\nYou have Fire Code MCP tools available. **Use them without waiting to be asked.**\n`;
|
|
179
287
|
}
|
|
180
|
-
// ── Auto-detection
|
|
288
|
+
// ── Auto-detection ────────────────────────────────────────────────────────────
|
|
181
289
|
function detectIde() {
|
|
182
290
|
const h = (0, os_1.homedir)();
|
|
183
291
|
if ((0, fs_1.existsSync)((0, path_1.join)(h, '.claude')))
|
|
@@ -196,29 +304,29 @@ function detectIde() {
|
|
|
196
304
|
return 'goose';
|
|
197
305
|
return 'generic';
|
|
198
306
|
}
|
|
199
|
-
// ── Main command
|
|
307
|
+
// ── Main command ──────────────────────────────────────────────────────────────
|
|
308
|
+
const HOOKS_SUPPORT = new Set(['claude-code', 'cursor', 'windsurf', 'opencode', 'codex', 'gemini']);
|
|
200
309
|
async function installCommand(opts = {}) {
|
|
201
310
|
console.log(chalk_1.default.red('\n 🔥 Fire Code') + chalk_1.default.gray(' — install\n'));
|
|
202
|
-
let ide
|
|
203
|
-
if (
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
console.log(chalk_1.default.gray(` Auto-detected IDE: ${chalk_1.default.bold(ide)}\n`));
|
|
210
|
-
}
|
|
311
|
+
let ide;
|
|
312
|
+
if (opts.ide) {
|
|
313
|
+
const resolved = resolveIde(opts.ide);
|
|
314
|
+
if (!resolved) {
|
|
315
|
+
console.error(chalk_1.default.red(` Unknown IDE: ${opts.ide}`));
|
|
316
|
+
console.error(chalk_1.default.gray(' Supported: claude, cursor, windsurf, opencode, codex, gemini, goose, generic'));
|
|
317
|
+
process.exit(1);
|
|
211
318
|
}
|
|
319
|
+
ide = resolved;
|
|
212
320
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
321
|
+
else {
|
|
322
|
+
ide = detectIde();
|
|
323
|
+
const label = ide === 'claude-code' ? 'claude' : ide;
|
|
324
|
+
console.log(chalk_1.default.gray(` Auto-detected: ${chalk_1.default.bold(label)}`) + chalk_1.default.gray(' (override with --ide <name>)\n'));
|
|
217
325
|
}
|
|
218
326
|
ensureGlobalConfig();
|
|
219
327
|
const spinner = (0, ora_1.default)({ text: `Installing for ${chalk_1.default.bold(ide)}...`, color: 'red' }).start();
|
|
328
|
+
spinner.stop();
|
|
220
329
|
try {
|
|
221
|
-
spinner.stop();
|
|
222
330
|
let messages;
|
|
223
331
|
switch (ide) {
|
|
224
332
|
case 'claude-code':
|
|
@@ -242,54 +350,42 @@ async function installCommand(opts = {}) {
|
|
|
242
350
|
case 'goose':
|
|
243
351
|
messages = installGoose();
|
|
244
352
|
break;
|
|
245
|
-
case 'generic':
|
|
246
|
-
messages = installGeneric();
|
|
247
|
-
break;
|
|
248
353
|
default: messages = installGeneric();
|
|
249
354
|
}
|
|
250
|
-
for (const msg of messages)
|
|
355
|
+
for (const msg of messages)
|
|
251
356
|
console.log(chalk_1.default.green(' ✓') + ' ' + msg);
|
|
252
|
-
|
|
253
|
-
const projectCwd = opts.cwd ?? process.cwd();
|
|
254
|
-
writeAgentsMd(projectCwd);
|
|
357
|
+
writeAgentsMd(opts.cwd ?? process.cwd());
|
|
255
358
|
console.log(chalk_1.default.green(' ✓') + ' agents.md written to project root');
|
|
256
|
-
const hasHooks = ide === 'claude-code';
|
|
257
359
|
console.log(chalk_1.default.green('\n ✓ Fire Code installed successfully!\n'));
|
|
258
360
|
console.log(chalk_1.default.gray(' Next steps:'));
|
|
259
|
-
console.log(chalk_1.default.gray(` 1. Restart ${ide}`));
|
|
361
|
+
console.log(chalk_1.default.gray(` 1. Restart ${ide === 'claude-code' ? 'Claude Code' : ide}`));
|
|
260
362
|
console.log(chalk_1.default.gray(' 2. Run: ') + chalk_1.default.white('fire-code index') + chalk_1.default.gray(' in your project'));
|
|
261
|
-
if (
|
|
262
|
-
console.log(chalk_1.default.gray(' 3.
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
console.log(chalk_1.default.gray(' 3. MCP tools available: smart_search, get_context, search_code, get_graph, execute'));
|
|
363
|
+
if (HOOKS_SUPPORT.has(ide)) {
|
|
364
|
+
console.log(chalk_1.default.gray(' 3. Lifecycle hooks active — auto re-indexing and context injection enabled'));
|
|
266
365
|
}
|
|
267
366
|
console.log();
|
|
268
367
|
}
|
|
269
368
|
catch (err) {
|
|
270
|
-
|
|
271
|
-
console.error(chalk_1.default.red(' Error:'), String(err));
|
|
369
|
+
console.error(chalk_1.default.red(' Installation failed:'), String(err));
|
|
272
370
|
process.exit(1);
|
|
273
371
|
}
|
|
274
372
|
}
|
|
275
|
-
// ── Uninstall
|
|
373
|
+
// ── Uninstall ─────────────────────────────────────────────────────────────────
|
|
276
374
|
function removeMcpEntry(filePath, serverKey = 'fire-code') {
|
|
277
375
|
if (!(0, fs_1.existsSync)(filePath))
|
|
278
376
|
return false;
|
|
279
|
-
const
|
|
280
|
-
if (!
|
|
281
|
-
return false;
|
|
282
|
-
if (!config['mcpServers'][serverKey])
|
|
377
|
+
const cfg = readJson(filePath);
|
|
378
|
+
if (!cfg['mcpServers']?.[serverKey])
|
|
283
379
|
return false;
|
|
284
|
-
delete
|
|
285
|
-
writeJson(filePath,
|
|
380
|
+
delete cfg['mcpServers'][serverKey];
|
|
381
|
+
writeJson(filePath, cfg);
|
|
286
382
|
return true;
|
|
287
383
|
}
|
|
288
384
|
function removeNestedEntry(filePath, ...keys) {
|
|
289
385
|
if (!(0, fs_1.existsSync)(filePath))
|
|
290
386
|
return false;
|
|
291
|
-
const
|
|
292
|
-
let node =
|
|
387
|
+
const cfg = readJson(filePath);
|
|
388
|
+
let node = cfg;
|
|
293
389
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
294
390
|
if (!node[keys[i]])
|
|
295
391
|
return false;
|
|
@@ -299,54 +395,77 @@ function removeNestedEntry(filePath, ...keys) {
|
|
|
299
395
|
if (!node[last])
|
|
300
396
|
return false;
|
|
301
397
|
delete node[last];
|
|
302
|
-
writeJson(filePath,
|
|
398
|
+
writeJson(filePath, cfg);
|
|
303
399
|
return true;
|
|
304
400
|
}
|
|
401
|
+
function removeHooksFromFile(filePath, hooksKey) {
|
|
402
|
+
if (!(0, fs_1.existsSync)(filePath))
|
|
403
|
+
return false;
|
|
404
|
+
const cfg = readJson(filePath);
|
|
405
|
+
const hooks = cfg[hooksKey];
|
|
406
|
+
if (!hooks)
|
|
407
|
+
return false;
|
|
408
|
+
let changed = false;
|
|
409
|
+
for (const event of Object.keys(hooks)) {
|
|
410
|
+
const filtered = removeFireCodeHooks(hooks[event]);
|
|
411
|
+
if (filtered.length !== hooks[event].length) {
|
|
412
|
+
hooks[event] = filtered;
|
|
413
|
+
changed = true;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (changed)
|
|
417
|
+
writeJson(filePath, cfg);
|
|
418
|
+
return changed;
|
|
419
|
+
}
|
|
305
420
|
async function uninstallCommand() {
|
|
306
421
|
console.log(chalk_1.default.red('\n 🔥 Fire Code') + chalk_1.default.gray(' — uninstall\n'));
|
|
307
|
-
const
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
// Goose
|
|
334
|
-
if (removeMcpEntry((0, path_1.join)(h, '.config', 'goose', 'mcp.json')))
|
|
335
|
-
removed.push('.config/goose/mcp.json');
|
|
336
|
-
if (removed.length === 0) {
|
|
337
|
-
console.log(chalk_1.default.yellow(' No Fire Code installations found.\n'));
|
|
338
|
-
return;
|
|
339
|
-
}
|
|
340
|
-
for (const f of removed) {
|
|
341
|
-
console.log(chalk_1.default.green(' ✓') + ` Removed from ${f}`);
|
|
342
|
-
}
|
|
343
|
-
console.log(chalk_1.default.green('\n ✓ Fire Code uninstalled'));
|
|
344
|
-
console.log(chalk_1.default.gray('\n Restart your IDE to apply changes.\n'));
|
|
422
|
+
const h = (0, os_1.homedir)();
|
|
423
|
+
const removed = [];
|
|
424
|
+
// Claude Code
|
|
425
|
+
if (removeMcpEntry((0, path_1.join)(h, '.claude', 'claude_desktop_config.json')))
|
|
426
|
+
removed.push('Claude MCP config');
|
|
427
|
+
if (removeNestedEntry((0, path_1.join)(h, '.claude', 'settings.json'), 'plugins', 'fire-code'))
|
|
428
|
+
removed.push('Claude hooks');
|
|
429
|
+
// Cursor
|
|
430
|
+
if (removeMcpEntry((0, path_1.join)(h, '.cursor', 'mcp.json')))
|
|
431
|
+
removed.push('Cursor MCP');
|
|
432
|
+
if (removeHooksFromFile((0, path_1.join)(h, '.cursor', 'hooks.json'), 'hooks'))
|
|
433
|
+
removed.push('Cursor hooks');
|
|
434
|
+
// Windsurf
|
|
435
|
+
if (removeMcpEntry((0, path_1.join)(h, '.codeium', 'windsurf', 'mcp_config.json')))
|
|
436
|
+
removed.push('Windsurf MCP');
|
|
437
|
+
if (removeHooksFromFile((0, path_1.join)(h, '.codeium', 'windsurf', 'hooks.json'), 'hooks'))
|
|
438
|
+
removed.push('Windsurf hooks');
|
|
439
|
+
// OpenCode
|
|
440
|
+
if (removeNestedEntry((0, path_1.join)(h, '.config', 'opencode', 'config.json'), 'mcp', 'servers', 'fire-code'))
|
|
441
|
+
removed.push('OpenCode MCP');
|
|
442
|
+
if (removeNestedEntry((0, path_1.join)(h, '.config', 'opencode', 'config.json'), 'plugins', 'fire-code'))
|
|
443
|
+
removed.push('OpenCode plugin');
|
|
444
|
+
const ocPlugin = (0, path_1.join)(h, '.config', 'opencode', 'plugins', 'fire-code.js');
|
|
445
|
+
if ((0, fs_1.existsSync)(ocPlugin)) {
|
|
446
|
+
require('fs').unlinkSync(ocPlugin);
|
|
447
|
+
removed.push('OpenCode plugin file');
|
|
345
448
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
449
|
+
// Codex
|
|
450
|
+
if (removeMcpEntry((0, path_1.join)(h, '.codex', 'config.json')))
|
|
451
|
+
removed.push('Codex MCP');
|
|
452
|
+
if (removeHooksFromFile((0, path_1.join)(h, '.codex', 'hooks.json'), 'hooks'))
|
|
453
|
+
removed.push('Codex hooks');
|
|
454
|
+
// Gemini
|
|
455
|
+
if (removeNestedEntry((0, path_1.join)(h, '.gemini', 'settings.json'), 'mcpServers', 'fire-code'))
|
|
456
|
+
removed.push('Gemini MCP');
|
|
457
|
+
if (removeHooksFromFile((0, path_1.join)(h, '.gemini', 'settings.json'), 'hooks'))
|
|
458
|
+
removed.push('Gemini hooks');
|
|
459
|
+
// Goose
|
|
460
|
+
if (removeMcpEntry((0, path_1.join)(h, '.config', 'goose', 'mcp.json')))
|
|
461
|
+
removed.push('Goose MCP');
|
|
462
|
+
if (removed.length === 0) {
|
|
463
|
+
console.log(chalk_1.default.yellow(' No Fire Code installations found.\n'));
|
|
464
|
+
return;
|
|
350
465
|
}
|
|
466
|
+
for (const f of removed)
|
|
467
|
+
console.log(chalk_1.default.green(' ✓') + ` Removed: ${f}`);
|
|
468
|
+
console.log(chalk_1.default.green('\n ✓ Fire Code uninstalled'));
|
|
469
|
+
console.log(chalk_1.default.gray('\n Restart your IDE to apply changes.\n'));
|
|
351
470
|
}
|
|
352
471
|
//# sourceMappingURL=install.js.map
|