fivocell 4.2.3 → 4.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.
- package/dist/__tests__/antigravity-rich-format.test.d.ts +2 -0
- package/dist/__tests__/antigravity-rich-format.test.d.ts.map +1 -0
- package/dist/__tests__/antigravity-rich-format.test.js +110 -0
- package/dist/__tests__/antigravity-rich-format.test.js.map +1 -0
- package/dist/__tests__/setup.test.d.ts +2 -0
- package/dist/__tests__/setup.test.d.ts.map +1 -0
- package/dist/__tests__/setup.test.js +186 -0
- package/dist/__tests__/setup.test.js.map +1 -0
- package/dist/cli.js +195 -52
- package/dist/cli.js.map +1 -1
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +41 -0
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/setup.d.ts +53 -0
- package/dist/core/setup.d.ts.map +1 -0
- package/dist/core/setup.js +371 -0
- package/dist/core/setup.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"antigravity-rich-format.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/antigravity-rich-format.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const prompt_builder_1 = require("../core/prompt-builder");
|
|
4
|
+
const mockDb = {
|
|
5
|
+
prepare: jest.fn(),
|
|
6
|
+
};
|
|
7
|
+
jest.mock('../core/database', () => ({
|
|
8
|
+
getDb: () => mockDb,
|
|
9
|
+
}));
|
|
10
|
+
function fakeStmt(rows) {
|
|
11
|
+
return { all: () => rows, get: () => rows[0] || undefined };
|
|
12
|
+
}
|
|
13
|
+
describe('formatForAntigravity rich output (v4.2.4)', () => {
|
|
14
|
+
function setupMocks(opts = {}) {
|
|
15
|
+
const ts = new Date().toISOString();
|
|
16
|
+
mockDb.prepare.mockReset();
|
|
17
|
+
mockDb.prepare.mockImplementation((sql) => {
|
|
18
|
+
const s = sql.trim().toUpperCase();
|
|
19
|
+
if (s.startsWith('SELECT * FROM DEVELOPER_PROFILES')) {
|
|
20
|
+
return fakeStmt([{ id: 1, project: 'Uos', files_scanned: 100, total_lines: 50000, scanned_at: ts }]);
|
|
21
|
+
}
|
|
22
|
+
if (s.startsWith('SELECT * FROM SCANS')) {
|
|
23
|
+
return fakeStmt([{ id: 1, project: 'Uos', started_at: ts, completed_at: ts, files_scanned: 100 }]);
|
|
24
|
+
}
|
|
25
|
+
if (s.startsWith('SELECT PATTERN_TYPE, PATTERN_VALUE, CATEGORY, COUNT, TRUST_SCORE FROM CODE_PATTERNS')) {
|
|
26
|
+
if (s.includes("CATEGORY = 'BLIND_SPOTS'") || s.includes("CATEGORY = 'BLIND_SPOTS'")) {
|
|
27
|
+
return fakeStmt(opts.blindSpots || []);
|
|
28
|
+
}
|
|
29
|
+
return fakeStmt([{ pattern_type: 'naming', pattern_value: 'camelCase', category: 'naming', count: 10, trust_score: 90 }]);
|
|
30
|
+
}
|
|
31
|
+
// Production readBlindSpots query (no CATEGORY column in SELECT)
|
|
32
|
+
if (s.startsWith("SELECT PATTERN_TYPE, PATTERN_VALUE, COUNT, TRUST_SCORE FROM CODE_PATTERNS") || s.includes("FROM CODE_PATTERNS WHERE CATEGORY = 'BLIND_SPOTS'")) {
|
|
33
|
+
return fakeStmt(opts.blindSpots || []);
|
|
34
|
+
}
|
|
35
|
+
if (s.startsWith('SELECT * FROM ERROR_LOG'))
|
|
36
|
+
return fakeStmt([]);
|
|
37
|
+
if (s.startsWith('SELECT PATTERN_VALUE FROM CODE_PATTERNS'))
|
|
38
|
+
return fakeStmt([]);
|
|
39
|
+
if (s.startsWith('SELECT * FROM SESSIONS'))
|
|
40
|
+
return fakeStmt([]);
|
|
41
|
+
if (s.startsWith('SELECT * FROM LIVE_EVENTS'))
|
|
42
|
+
return fakeStmt(opts.liveEvents || []);
|
|
43
|
+
if (s.includes('SESSION_APPROACHES') && s.includes('GROUP BY'))
|
|
44
|
+
return fakeStmt([]);
|
|
45
|
+
if (s.startsWith('SELECT FILE_PATH') && s.includes('SESSION_FILES')) {
|
|
46
|
+
return fakeStmt(opts.mostTouched || []);
|
|
47
|
+
}
|
|
48
|
+
if (s.startsWith('SELECT * FROM SESSION_QUESTIONS'))
|
|
49
|
+
return fakeStmt([]);
|
|
50
|
+
return fakeStmt([]);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
it('includes blind_spots in YAML when present', () => {
|
|
54
|
+
setupMocks({
|
|
55
|
+
blindSpots: [
|
|
56
|
+
{ pattern_type: 'async_without_trycatch', pattern_value: '81/191', count: 81, trust_score: 95 },
|
|
57
|
+
{ pattern_type: 'missing_return_types', pattern_value: '176', count: 176, trust_score: 90 },
|
|
58
|
+
],
|
|
59
|
+
});
|
|
60
|
+
const ctx = (0, prompt_builder_1.buildContext)('Uos', 'antigravity');
|
|
61
|
+
const out = (0, prompt_builder_1.formatContextForTool)(ctx, 'antigravity', 'Uos');
|
|
62
|
+
expect(out).toContain('blind_spots:');
|
|
63
|
+
expect(out).toContain('[81x');
|
|
64
|
+
});
|
|
65
|
+
it('includes last_live_file fallback when no session exists', () => {
|
|
66
|
+
const eventTs = new Date(Date.now() - 60_000).toISOString();
|
|
67
|
+
setupMocks({
|
|
68
|
+
liveEvents: [{ id: 1, project: 'Uos', event_type: 'file_save', file_path: 'src/Zavi.tsx', created_at: eventTs }],
|
|
69
|
+
});
|
|
70
|
+
const ctx = (0, prompt_builder_1.buildContext)('Uos', 'antigravity');
|
|
71
|
+
const out = (0, prompt_builder_1.formatContextForTool)(ctx, 'antigravity', 'Uos');
|
|
72
|
+
expect(out).toContain('last_live_file:');
|
|
73
|
+
expect(out).toContain('file_save');
|
|
74
|
+
expect(out).toContain('src/Zavi.tsx');
|
|
75
|
+
expect(out).toContain('no session open');
|
|
76
|
+
});
|
|
77
|
+
it('includes hot_files section when session_files data exists', () => {
|
|
78
|
+
setupMocks({
|
|
79
|
+
mostTouched: [
|
|
80
|
+
{ file_path: 'src/App.tsx', total_touches: 10, session_count: 3, last_touched: new Date().toISOString() },
|
|
81
|
+
{ file_path: 'server/index.ts', total_touches: 8, session_count: 2, last_touched: new Date().toISOString() },
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
const ctx = (0, prompt_builder_1.buildContext)('Uos', 'antigravity');
|
|
85
|
+
const out = (0, prompt_builder_1.formatContextForTool)(ctx, 'antigravity', 'Uos');
|
|
86
|
+
expect(out).toContain('hot_files:');
|
|
87
|
+
expect(out).toContain('src/App.tsx');
|
|
88
|
+
expect(out).toContain('touches: 10');
|
|
89
|
+
});
|
|
90
|
+
it('includes style summary line', () => {
|
|
91
|
+
setupMocks();
|
|
92
|
+
const ctx = (0, prompt_builder_1.buildContext)('Uos', 'antigravity');
|
|
93
|
+
const out = (0, prompt_builder_1.formatContextForTool)(ctx, 'antigravity', 'Uos');
|
|
94
|
+
expect(out).toMatch(/style: "/);
|
|
95
|
+
});
|
|
96
|
+
it('routes opencode tool name to formatForAntigravity (rich YAML)', () => {
|
|
97
|
+
setupMocks();
|
|
98
|
+
const ctx = (0, prompt_builder_1.buildContext)('Uos', 'opencode');
|
|
99
|
+
const out = (0, prompt_builder_1.formatContextForTool)(ctx, 'opencode', 'Uos');
|
|
100
|
+
expect(out).toContain('## Cell Context — Structured');
|
|
101
|
+
expect(out).toContain('project: Uos');
|
|
102
|
+
});
|
|
103
|
+
it('routes gemini tool name to formatForAntigravity', () => {
|
|
104
|
+
setupMocks();
|
|
105
|
+
const ctx = (0, prompt_builder_1.buildContext)('Uos', 'gemini');
|
|
106
|
+
const out = (0, prompt_builder_1.formatContextForTool)(ctx, 'gemini', 'Uos');
|
|
107
|
+
expect(out).toContain('## Cell Context — Structured');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
//# sourceMappingURL=antigravity-rich-format.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"antigravity-rich-format.test.js","sourceRoot":"","sources":["../../src/__tests__/antigravity-rich-format.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/setup.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const fs = __importStar(require("fs"));
|
|
37
|
+
const os = __importStar(require("os"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const setup_1 = require("../core/setup");
|
|
40
|
+
describe('setup (idempotency checks)', () => {
|
|
41
|
+
let tmpDir;
|
|
42
|
+
let homedir;
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cell-setup-'));
|
|
45
|
+
homedir = fs.mkdtempSync(path.join(os.tmpdir(), 'cell-setup-home-'));
|
|
46
|
+
});
|
|
47
|
+
afterEach(() => {
|
|
48
|
+
try {
|
|
49
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
50
|
+
}
|
|
51
|
+
catch { }
|
|
52
|
+
try {
|
|
53
|
+
fs.rmSync(homedir, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
catch { }
|
|
56
|
+
});
|
|
57
|
+
describe('detectProject', () => {
|
|
58
|
+
it('uses package.json name when present', () => {
|
|
59
|
+
const pkg = { name: 'my-cool-app', version: '1.0.0' };
|
|
60
|
+
fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify(pkg), 'utf8');
|
|
61
|
+
const result = (0, setup_1.detectProject)(tmpDir);
|
|
62
|
+
expect(result.name).toBe('my-cool-app');
|
|
63
|
+
expect(result.source).toBe('package.json');
|
|
64
|
+
expect(result.packageJsonPath).toBe(path.join(tmpDir, 'package.json'));
|
|
65
|
+
});
|
|
66
|
+
it('falls back to folder basename when no package.json', () => {
|
|
67
|
+
const subdir = path.join(tmpDir, 'no-pkg-here');
|
|
68
|
+
fs.mkdirSync(subdir);
|
|
69
|
+
const result = (0, setup_1.detectProject)(subdir);
|
|
70
|
+
expect(result.name).toBe('no-pkg-here');
|
|
71
|
+
expect(result.source).toBe('folder-basename');
|
|
72
|
+
});
|
|
73
|
+
it('uses override when provided', () => {
|
|
74
|
+
fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({ name: 'real-name' }), 'utf8');
|
|
75
|
+
const result = (0, setup_1.detectProject)(tmpDir, 'override-name');
|
|
76
|
+
expect(result.name).toBe('override-name');
|
|
77
|
+
expect(result.source).toBe('override');
|
|
78
|
+
});
|
|
79
|
+
it('ignores malformed package.json', () => {
|
|
80
|
+
fs.writeFileSync(path.join(tmpDir, 'package.json'), '{ not valid json', 'utf8');
|
|
81
|
+
const result = (0, setup_1.detectProject)(tmpDir);
|
|
82
|
+
expect(result.source).toBe('folder-basename');
|
|
83
|
+
});
|
|
84
|
+
it('ignores package.json without a name field', () => {
|
|
85
|
+
fs.writeFileSync(path.join(tmpDir, 'package.json'), JSON.stringify({ version: '1.0.0' }), 'utf8');
|
|
86
|
+
const result = (0, setup_1.detectProject)(tmpDir);
|
|
87
|
+
expect(result.source).toBe('folder-basename');
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
describe('checkScanState', () => {
|
|
91
|
+
it('returns done=true when .cell/personal/ has files', () => {
|
|
92
|
+
const personalDir = path.join(tmpDir, '.cell', 'personal');
|
|
93
|
+
fs.mkdirSync(personalDir, { recursive: true });
|
|
94
|
+
fs.writeFileSync(path.join(personalDir, 'profile.json'), '{}', 'utf8');
|
|
95
|
+
const state = (0, setup_1.checkScanState)(tmpDir);
|
|
96
|
+
expect(state.done).toBe(true);
|
|
97
|
+
expect(state.reason).toContain('1 files');
|
|
98
|
+
expect(state.personalDir).toBe(personalDir);
|
|
99
|
+
expect(state.scannedAt).toBeTruthy();
|
|
100
|
+
});
|
|
101
|
+
it('returns done=true when AGENTS.md exists (even with no .cell/personal)', () => {
|
|
102
|
+
fs.writeFileSync(path.join(tmpDir, 'AGENTS.md'), '# user content', 'utf8');
|
|
103
|
+
const state = (0, setup_1.checkScanState)(tmpDir);
|
|
104
|
+
expect(state.done).toBe(true);
|
|
105
|
+
expect(state.reason).toContain('AGENTS.md');
|
|
106
|
+
});
|
|
107
|
+
it('returns done=false when neither exists', () => {
|
|
108
|
+
const state = (0, setup_1.checkScanState)(tmpDir);
|
|
109
|
+
expect(state.done).toBe(false);
|
|
110
|
+
expect(state.reason).toContain('no ');
|
|
111
|
+
});
|
|
112
|
+
it('returns done=false when .cell/personal exists but is empty', () => {
|
|
113
|
+
fs.mkdirSync(path.join(tmpDir, '.cell', 'personal'), { recursive: true });
|
|
114
|
+
const state = (0, setup_1.checkScanState)(tmpDir);
|
|
115
|
+
expect(state.done).toBe(false);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
describe('checkMcpState', () => {
|
|
119
|
+
it('reports all IDEs as needsWrite when no config files exist', () => {
|
|
120
|
+
// homedir is empty -> none of the IDE config paths exist
|
|
121
|
+
const state = (0, setup_1.checkMcpState)(homedir);
|
|
122
|
+
expect(state.total).toBeGreaterThan(0);
|
|
123
|
+
expect(state.done).toBe(0);
|
|
124
|
+
expect(state.skipped).toBe(0);
|
|
125
|
+
expect(state.needsWrite.length).toBe(state.total);
|
|
126
|
+
expect(state.needsWrite).toContain('Cursor');
|
|
127
|
+
});
|
|
128
|
+
it('reports done=N when N IDE config files have fivo-cell wired', () => {
|
|
129
|
+
// Write a Cursor config with fivo-cell already wired
|
|
130
|
+
const cursorDir = path.join(homedir, '.cursor');
|
|
131
|
+
fs.mkdirSync(cursorDir, { recursive: true });
|
|
132
|
+
fs.writeFileSync(path.join(cursorDir, 'mcp.json'), JSON.stringify({ mcpServers: { 'fivo-cell': { url: 'http://localhost:9876/mcp' } } }), 'utf8');
|
|
133
|
+
const state = (0, setup_1.checkMcpState)(homedir);
|
|
134
|
+
expect(state.done).toBe(1);
|
|
135
|
+
expect(state.needsWrite).not.toContain('Cursor');
|
|
136
|
+
// Other IDEs should still need write
|
|
137
|
+
expect(state.needsWrite.length).toBe(state.total - 1);
|
|
138
|
+
});
|
|
139
|
+
it('counts skipped when config file has parse errors', () => {
|
|
140
|
+
const cursorDir = path.join(homedir, '.cursor');
|
|
141
|
+
fs.mkdirSync(cursorDir, { recursive: true });
|
|
142
|
+
fs.writeFileSync(path.join(cursorDir, 'mcp.json'), '{ not valid json', 'utf8');
|
|
143
|
+
const state = (0, setup_1.checkMcpState)(homedir);
|
|
144
|
+
expect(state.skipped).toBe(1);
|
|
145
|
+
expect(state.done).toBe(0);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe('isDaemonRunning', () => {
|
|
149
|
+
it('returns false when nothing is listening on a random port', async () => {
|
|
150
|
+
// Use a random high port that nothing should be on
|
|
151
|
+
const result = await (0, setup_1.isDaemonRunning)(19878, 500);
|
|
152
|
+
expect(result).toBe(false);
|
|
153
|
+
});
|
|
154
|
+
it('returns true when an HTTP server responds on the port', async () => {
|
|
155
|
+
const http = require('http');
|
|
156
|
+
const server = http.createServer((_req, res) => {
|
|
157
|
+
res.statusCode = 200;
|
|
158
|
+
res.end('OK');
|
|
159
|
+
});
|
|
160
|
+
await new Promise((resolve) => server.listen(19876, '127.0.0.1', resolve));
|
|
161
|
+
try {
|
|
162
|
+
const result = await (0, setup_1.isDaemonRunning)(19876, 1000);
|
|
163
|
+
expect(result).toBe(true);
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
it('returns false when server returns non-200', async () => {
|
|
170
|
+
const http = require('http');
|
|
171
|
+
const server = http.createServer((_req, res) => {
|
|
172
|
+
res.statusCode = 500;
|
|
173
|
+
res.end('error');
|
|
174
|
+
});
|
|
175
|
+
await new Promise((resolve) => server.listen(19877, '127.0.0.1', resolve));
|
|
176
|
+
try {
|
|
177
|
+
const result = await (0, setup_1.isDaemonRunning)(19877, 1000);
|
|
178
|
+
expect(result).toBe(false);
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
//# sourceMappingURL=setup.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.test.js","sourceRoot":"","sources":["../../src/__tests__/setup.test.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -99,6 +99,13 @@ switch (cmd) {
|
|
|
99
99
|
case 'stop':
|
|
100
100
|
doStop();
|
|
101
101
|
break;
|
|
102
|
+
case 'setup':
|
|
103
|
+
doSetup().catch((e) => {
|
|
104
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
105
|
+
console.log(C.warn(' Setup crashed: ' + msg));
|
|
106
|
+
process.exit(1);
|
|
107
|
+
});
|
|
108
|
+
break;
|
|
102
109
|
case 'scan':
|
|
103
110
|
doScan();
|
|
104
111
|
break;
|
|
@@ -152,6 +159,37 @@ function doStart() {
|
|
|
152
159
|
firstRunGreeting();
|
|
153
160
|
}
|
|
154
161
|
catch { }
|
|
162
|
+
// 1. Check if daemon is already running (cheap /health probe) — if so,
|
|
163
|
+
// skip restart and just print status. This makes `cell start` re-run safe.
|
|
164
|
+
const http = require('http');
|
|
165
|
+
const probeReq = http.request({
|
|
166
|
+
hostname: '127.0.0.1', port: 9876, path: '/health', method: 'GET', timeout: 1000,
|
|
167
|
+
}, (res) => {
|
|
168
|
+
if (res.statusCode === 200) {
|
|
169
|
+
let data = '';
|
|
170
|
+
res.on('data', (chunk) => { data += chunk ? chunk.toString() : ''; });
|
|
171
|
+
res.on('end', () => {
|
|
172
|
+
let up = 0;
|
|
173
|
+
try {
|
|
174
|
+
up = JSON.parse(data).uptimeSeconds || 0;
|
|
175
|
+
}
|
|
176
|
+
catch { }
|
|
177
|
+
const upH = Math.floor(up / 3600);
|
|
178
|
+
const upM = Math.floor((up % 3600) / 60);
|
|
179
|
+
const upStr = upH > 0 ? `${upH}h ${upM}m` : upM > 0 ? `${upM}m` : `${up}s`;
|
|
180
|
+
console.log(C.success(` Daemon: already running on port 9876 (uptime ${upStr})`));
|
|
181
|
+
printProjectStatusAndExit();
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
startDaemon();
|
|
186
|
+
}
|
|
187
|
+
});
|
|
188
|
+
probeReq.on('error', () => { startDaemon(); });
|
|
189
|
+
probeReq.on('timeout', () => { probeReq.destroy(); startDaemon(); });
|
|
190
|
+
probeReq.end();
|
|
191
|
+
}
|
|
192
|
+
function startDaemon() {
|
|
155
193
|
// 1. Kill any stale daemon (clean restart)
|
|
156
194
|
try {
|
|
157
195
|
const { stopDaemon } = require('./daemon/lifecycle');
|
|
@@ -196,64 +234,45 @@ function doStart() {
|
|
|
196
234
|
console.log(C.dim(' Daemon + MCP: http://localhost:9876'));
|
|
197
235
|
console.log(C.dim(' MCP endpoint: POST http://localhost:9876/mcp'));
|
|
198
236
|
console.log();
|
|
199
|
-
//
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
catch { /* ignore */ }
|
|
227
|
-
console.log();
|
|
228
|
-
console.log(C.dim(' Next: cell scan (scan codebase + build layers)'));
|
|
229
|
-
console.log(C.dim(' Then: cell status'));
|
|
230
|
-
console.log();
|
|
231
|
-
process.exit(0);
|
|
232
|
-
});
|
|
233
|
-
});
|
|
234
|
-
req.on('error', () => {
|
|
235
|
-
console.log(C.dim(' Next: cell scan (scan codebase + build layers)'));
|
|
236
|
-
console.log(C.dim(' Then: cell status'));
|
|
237
|
-
console.log();
|
|
238
|
-
process.exit(0);
|
|
239
|
-
});
|
|
240
|
-
req.setTimeout(3000, () => { req.destroy(); process.exit(0); });
|
|
241
|
-
req.write(body);
|
|
242
|
-
req.end();
|
|
243
|
-
return;
|
|
237
|
+
// Give the daemon a moment to bind to the port, then print project status.
|
|
238
|
+
setTimeout(() => { printProjectStatusAndExit(); }, 500);
|
|
239
|
+
}
|
|
240
|
+
catch (e) {
|
|
241
|
+
console.log(C.warn(' Start failed: ' + String(e)));
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function printProjectStatusAndExit() {
|
|
246
|
+
try {
|
|
247
|
+
const { detectProject, checkScanState, checkWatchState, checkMcpState, isDaemonRunning } = require('./core/setup');
|
|
248
|
+
const httpMod = require('http');
|
|
249
|
+
const project = detectProject(process.cwd());
|
|
250
|
+
const scan = checkScanState(process.cwd());
|
|
251
|
+
const watch = checkWatchState(project.name);
|
|
252
|
+
const mcp = checkMcpState(os.homedir());
|
|
253
|
+
console.log();
|
|
254
|
+
console.log(C.bold(' Project:'), C.num(project.name), C.dim(`(${project.source})`));
|
|
255
|
+
console.log();
|
|
256
|
+
console.log(` ${scan.done ? C.success('OK') : C.dim('--')} scan: ${scan.reason}`);
|
|
257
|
+
console.log(` ${watch.done ? C.success('OK') : C.dim('--')} watch: ${watch.reason}`);
|
|
258
|
+
console.log(` ${mcp.done === mcp.total ? C.success('OK') : C.dim('--')} mcp: ${mcp.done}/${mcp.total} IDEs wired${mcp.needsWrite.length > 0 ? C.warn(' (need: ' + mcp.needsWrite.join(', ') + ')') : ''}`);
|
|
259
|
+
console.log();
|
|
260
|
+
const allReady = scan.done && watch.done && mcp.done === mcp.total;
|
|
261
|
+
if (allReady) {
|
|
262
|
+
console.log(C.dim(' Cell is fully ready. Use @cell in your AI chat.'));
|
|
244
263
|
}
|
|
245
|
-
|
|
246
|
-
|
|
264
|
+
else {
|
|
265
|
+
console.log(C.primary(' Run: cell setup (one-time, idempotent) to finish setup'));
|
|
247
266
|
}
|
|
267
|
+
console.log();
|
|
268
|
+
process.exit(0);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
248
271
|
console.log(C.dim(' Next: cell scan (scan codebase + build layers)'));
|
|
249
272
|
console.log(C.dim(' Then: cell status'));
|
|
250
273
|
console.log();
|
|
251
274
|
process.exit(0);
|
|
252
275
|
}
|
|
253
|
-
catch (e) {
|
|
254
|
-
console.log(C.warn(' Start failed: ' + String(e)));
|
|
255
|
-
process.exit(1);
|
|
256
|
-
}
|
|
257
276
|
}
|
|
258
277
|
// ─── cell stop ──────────────────────────────────────────────────────────────
|
|
259
278
|
function doStop() {
|
|
@@ -401,6 +420,129 @@ function doScan() {
|
|
|
401
420
|
console.log();
|
|
402
421
|
}
|
|
403
422
|
}
|
|
423
|
+
// ─── cell setup (idempotent one-time project setup) ─────────────────────────
|
|
424
|
+
/**
|
|
425
|
+
* One-command setup for a new project. Runs scan + watcher + MCP config
|
|
426
|
+
* with full idempotency — safe to re-run any number of times. Skips steps
|
|
427
|
+
* that are already done and only does the missing pieces.
|
|
428
|
+
*
|
|
429
|
+
* Flags:
|
|
430
|
+
* --project <name> Override project name (default: package.json name or folder basename)
|
|
431
|
+
* --no-rules Skip writing AGENTS.md / .cursorrules
|
|
432
|
+
* --force-rules Overwrite existing AGENTS.md / .cursorrules
|
|
433
|
+
* --skip-scan Don't run scan
|
|
434
|
+
* --skip-watch Don't start watcher
|
|
435
|
+
* --skip-mcp Don't write MCP configs
|
|
436
|
+
* --dir <path> Watch dir (default: cwd)
|
|
437
|
+
* --dry-run Print what would happen, don't change anything
|
|
438
|
+
*/
|
|
439
|
+
async function doSetup() {
|
|
440
|
+
const banner = figlet_1.default.textSync('CELL', { font: 'ANSI Shadow', horizontalLayout: 'fitted' });
|
|
441
|
+
console.log((0, gradient_string_1.default)(['#FF6B35', '#FFAB91'])(banner));
|
|
442
|
+
console.log(C.dim(' Setting up project (idempotent)...\n'));
|
|
443
|
+
// ─── Flag parsing ─────────────────────────────────────────────────────
|
|
444
|
+
const noRules = args.includes('--no-rules');
|
|
445
|
+
const forceRules = args.includes('--force-rules');
|
|
446
|
+
const skipScan = args.includes('--skip-scan');
|
|
447
|
+
const skipWatch = args.includes('--skip-watch');
|
|
448
|
+
const skipMcp = args.includes('--skip-mcp');
|
|
449
|
+
const dryRun = args.includes('--dry-run');
|
|
450
|
+
const projectIdx = args.indexOf('--project');
|
|
451
|
+
const projectName = projectIdx > 0 ? args[projectIdx + 1] : undefined;
|
|
452
|
+
const dirIdx = args.indexOf('--dir');
|
|
453
|
+
const dir = dirIdx > 0 ? args[dirIdx + 1] : undefined;
|
|
454
|
+
try {
|
|
455
|
+
const { runSetup, detectProject, checkScanState, checkWatchState, checkMcpState, isDaemonRunning, } = require('./core/setup');
|
|
456
|
+
const cwd = process.cwd();
|
|
457
|
+
const project = detectProject(cwd, projectName);
|
|
458
|
+
console.log(C.bold(` Project: ${C.num(project.name)}`));
|
|
459
|
+
console.log(C.dim(` Source: ${project.source}${project.packageJsonPath ? ' (' + project.packageJsonPath + ')' : ''}`));
|
|
460
|
+
console.log(C.dim(` Cwd: ${cwd}`));
|
|
461
|
+
if (dryRun)
|
|
462
|
+
console.log(C.warn(' Mode: DRY RUN (no changes will be made)'));
|
|
463
|
+
console.log();
|
|
464
|
+
// ─── Daemon check ────────────────────────────────────────────────────
|
|
465
|
+
const daemonUp = await isDaemonRunning();
|
|
466
|
+
if (daemonUp) {
|
|
467
|
+
console.log(C.success(' [daemon] running on http://localhost:9876'));
|
|
468
|
+
}
|
|
469
|
+
else {
|
|
470
|
+
console.log(C.warn(' [daemon] not running — watcher will be skipped'));
|
|
471
|
+
console.log(C.dim(' run `cell start` to bring it up, then re-run `cell setup`'));
|
|
472
|
+
}
|
|
473
|
+
console.log();
|
|
474
|
+
// ─── Pre-flight state report ────────────────────────────────────────
|
|
475
|
+
if (!dryRun) {
|
|
476
|
+
const scan = checkScanState(cwd);
|
|
477
|
+
const watch = daemonUp ? checkWatchState(project.name) : { done: false, reason: 'daemon not running' };
|
|
478
|
+
const mcp = checkMcpState(os.homedir());
|
|
479
|
+
console.log(C.bold(' Pre-flight:'));
|
|
480
|
+
console.log(` scan: ${scan.done ? C.success('done') : C.dim('missing')} (${scan.reason})`);
|
|
481
|
+
console.log(` watch: ${watch.done ? C.success('active') : C.dim('inactive')} (${watch.reason})`);
|
|
482
|
+
console.log(` mcp: ${mcp.done}/${mcp.total} IDEs wired${mcp.needsWrite.length > 0 ? C.warn(' (need: ' + mcp.needsWrite.join(', ') + ')') : ''}`);
|
|
483
|
+
console.log();
|
|
484
|
+
const allDone = scan.done && watch.done && mcp.done === mcp.total;
|
|
485
|
+
if (allDone) {
|
|
486
|
+
console.log(C.success(' Already fully set up — nothing to do.'));
|
|
487
|
+
console.log(C.dim(' Tip: re-run anytime; it is safe and idempotent.'));
|
|
488
|
+
console.log();
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
// ─── Run setup ───────────────────────────────────────────────────────
|
|
493
|
+
const start = Date.now();
|
|
494
|
+
const result = await runSetup({
|
|
495
|
+
cwd,
|
|
496
|
+
homedir: os.homedir(),
|
|
497
|
+
noRules,
|
|
498
|
+
forceRules,
|
|
499
|
+
projectName,
|
|
500
|
+
skipScan,
|
|
501
|
+
skipWatch: skipWatch || !daemonUp,
|
|
502
|
+
skipMcp,
|
|
503
|
+
dir,
|
|
504
|
+
dryRun,
|
|
505
|
+
});
|
|
506
|
+
const ms = Date.now() - start;
|
|
507
|
+
// ─── Result summary ─────────────────────────────────────────────────
|
|
508
|
+
console.log(C.bold(' Result:'));
|
|
509
|
+
console.log(` ${result.scan.done ? C.success('OK') : C.warn('FAIL')} scan: ${result.scan.reason}`);
|
|
510
|
+
console.log(` ${result.watch.done ? C.success('OK') : C.warn('FAIL')} watch: ${result.watch.reason}`);
|
|
511
|
+
const mcpOk = result.mcp.done === result.mcp.total;
|
|
512
|
+
console.log(` ${mcpOk ? C.success('OK') : C.warn('PARTIAL')} mcp: ${result.mcp.done}/${result.mcp.total} IDEs wired${result.mcp.written.length > 0 ? ' (' + result.mcp.written.length + ' just written)' : ''}`);
|
|
513
|
+
console.log();
|
|
514
|
+
if (result.warnings.length > 0) {
|
|
515
|
+
console.log(C.warn(' Warnings:'));
|
|
516
|
+
for (const w of result.warnings)
|
|
517
|
+
console.log(C.warn(` ! ${w}`));
|
|
518
|
+
console.log();
|
|
519
|
+
}
|
|
520
|
+
if (result.errors.length > 0) {
|
|
521
|
+
console.log(C.warn(' Errors:'));
|
|
522
|
+
for (const e of result.errors)
|
|
523
|
+
console.log(C.warn(` x ${e}`));
|
|
524
|
+
console.log();
|
|
525
|
+
}
|
|
526
|
+
// ─── Final verdict ──────────────────────────────────────────────────
|
|
527
|
+
const allGood = result.scan.done && result.watch.done && mcpOk && result.errors.length === 0;
|
|
528
|
+
if (allGood) {
|
|
529
|
+
console.log(C.success(` Setup complete in ${ms}ms. Cell is ready.`));
|
|
530
|
+
}
|
|
531
|
+
else {
|
|
532
|
+
console.log(C.warn(` Setup finished in ${ms}ms with warnings (see above).`));
|
|
533
|
+
}
|
|
534
|
+
console.log();
|
|
535
|
+
console.log(C.dim(' Run: cell status Check what Cell knows about you'));
|
|
536
|
+
console.log(C.dim(' Run: cell context Inject @cell block into your AI prompt'));
|
|
537
|
+
console.log();
|
|
538
|
+
}
|
|
539
|
+
catch (e) {
|
|
540
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
541
|
+
console.log(C.warn(' Setup failed: ' + msg));
|
|
542
|
+
console.log();
|
|
543
|
+
}
|
|
544
|
+
process.exit(0);
|
|
545
|
+
}
|
|
404
546
|
// ─── cell status ────────────────────────────────────────────────────────────
|
|
405
547
|
function semiLabel(s) {
|
|
406
548
|
if (s === 'with semicolons' || s === 'always')
|
|
@@ -1368,8 +1510,9 @@ function doHelp() {
|
|
|
1368
1510
|
console.log(C.bold(' Cell Commands'));
|
|
1369
1511
|
console.log(C.dim(' ─────────────'));
|
|
1370
1512
|
console.log();
|
|
1371
|
-
console.log(` ${C.primary('cell start')} Start daemon + MCP (port 9876)`);
|
|
1513
|
+
console.log(` ${C.primary('cell start')} Start daemon + MCP (port 9876) — re-run safe`);
|
|
1372
1514
|
console.log(` ${C.primary('cell stop')} Stop daemon`);
|
|
1515
|
+
console.log(` ${C.primary('cell setup')} One-time project setup: scan + watcher + MCP (idempotent)`);
|
|
1373
1516
|
console.log(` ${C.primary('cell --version')} Print version + daemon status`);
|
|
1374
1517
|
console.log(` ${C.primary('cell mcp-config')} Auto-register cell MCP in Cursor/Antigravity/Codex/OpenCode`);
|
|
1375
1518
|
console.log(` ${C.primary('cell scan')} Scan codebase + build layers`);
|