fivocell 4.1.9 → 4.2.1

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.
@@ -0,0 +1,164 @@
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
+ exports.CURSORRULES_TEMPLATE = exports.AGENTS_MD_TEMPLATE = exports.CELL_RULES_MARKER = exports.CURSORRULES_FILENAME = exports.AGENTS_MD_FILENAME = void 0;
37
+ exports.isCellRulesFile = isCellRulesFile;
38
+ exports.writeAgentsMd = writeAgentsMd;
39
+ exports.writeCursorRules = writeCursorRules;
40
+ exports.writeCellRules = writeCellRules;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ exports.AGENTS_MD_FILENAME = 'AGENTS.md';
44
+ exports.CURSORRULES_FILENAME = '.cursorrules';
45
+ exports.CELL_RULES_MARKER = '# fivo-cell:rules:v1';
46
+ exports.AGENTS_MD_TEMPLATE = `${exports.CELL_RULES_MARKER}
47
+ # FIVO Cell — AI Memory Rules
48
+
49
+ FIVO Cell is installed and configured for this project. Use its MCP tools
50
+ (named \`cell_*\`) to maintain permanent memory across sessions.
51
+
52
+ ## The @cell Convention
53
+
54
+ Whenever the user types \`@cell\` in their message (e.g. "@cell what did I
55
+ just edit?" or "@cell fix this bug"), you MUST do the following BEFORE
56
+ responding:
57
+
58
+ 1. **Call \`cell_get_context\` FIRST** to load this project's full context.
59
+ 2. **Pass \`project\` as the current folder name** — derive it from
60
+ \`path.basename(process.cwd())\` or the absolute path the IDE is open
61
+ in. If unsure, call \`cell_list_projects\` and pick the matching one.
62
+ 3. **Also pass \`tool\`** set to your IDE/tool name so the block is
63
+ formatted for you (e.g. \`antigravity\`, \`cursor\`, \`opencode\`,
64
+ \`claude-code\`, \`codex\`, \`windsurf\`, \`copilot\`, \`aider\`).
65
+ 4. **Use the returned context** to inform your answer — it contains the
66
+ last session, recent file edits (live events), blind spots, style
67
+ hints, predictions, and tried approaches.
68
+
69
+ ## Common Cell Tools
70
+
71
+ | Task | Tool |
72
+ |------|------|
73
+ | Load project context (\`@cell\`) | \`cell_get_context\` |
74
+ | Open a work session | \`cell_session_start\` |
75
+ | Close a session with key decisions | \`cell_session_end\` |
76
+ | See recent sessions | \`cell_session_recent\` |
77
+ | See recent file saves | \`cell_watch_events\` |
78
+ | Start the file watcher | \`cell_watch_start\` |
79
+ | Stop the file watcher | \`cell_watch_stop\` |
80
+ | Detect code risks (try/catch, null checks, validation) | \`cell_blindspots\` |
81
+ | Scan the project | \`cell_scan\` |
82
+ | Log an error you hit | \`cell_log_error\` |
83
+ | Log how you fixed it | \`cell_log_fix\` |
84
+ | Log a key decision | \`cell_log_decision\` |
85
+ | List all registered projects | \`cell_list_projects\` |
86
+
87
+ There are 67 cell tools in total. Run \`cell --help\` to see all of them.
88
+
89
+ ## Session Discipline
90
+
91
+ - **At the start of a non-trivial task** (multi-file work, refactor,
92
+ feature, debugging session): call \`cell_session_start\` to open a
93
+ session.
94
+ - **At the end** (or before a long break): call \`cell_session_end\` with
95
+ \`keyDecisions\` summarising what you decided and \`filesTouched\`
96
+ listing the files you changed.
97
+ - If the user switches tools (e.g. Cursor → Antigravity) within a
98
+ project, the bridge context is auto-loaded — read it from the @cell
99
+ block to understand what was just done.
100
+
101
+ ## Watcher Awareness
102
+
103
+ - If the watcher is active, the @cell block includes the most recent
104
+ file edits. Trust those for "what did I just edit" questions.
105
+ - If the user reports a file change you don't know about, call
106
+ \`cell_watch_events\` directly.
107
+
108
+ ## Anti-Patterns to Avoid
109
+
110
+ - Do NOT guess a project name. If unsure, call \`cell_list_projects\`.
111
+ - Do NOT skip \`cell_get_context\` when @cell is in the prompt — the
112
+ whole point of the convention is automatic context.
113
+ - Do NOT call \`cell_get_context\` for every message. Only when @cell
114
+ appears, or when context is genuinely needed.
115
+ - Do NOT modify or remove this file. To regenerate it, run
116
+ \`cell scan\` again (it is idempotent — existing files are kept).
117
+
118
+ ## Regeneration
119
+
120
+ This file is auto-generated by \`cell scan\`. To remove it: \`cell scan --no-rules\`.
121
+ `;
122
+ exports.CURSORRULES_TEMPLATE = `${exports.CELL_RULES_MARKER}
123
+ # FIVO Cell — Cursor Rules
124
+
125
+ When the user types \`@cell\` in chat or Composer, you MUST call the
126
+ \`cell_get_context\` MCP tool FIRST, with \`project\` set to the current
127
+ folder name and \`tool\` set to \`cursor\`. Then use the returned block
128
+ to inform your response. See AGENTS.md for the full convention.
129
+ `;
130
+ function isCellRulesFile(content) {
131
+ return content.includes(exports.CELL_RULES_MARKER);
132
+ }
133
+ function writeAgentsMd(projectPath, opts = {}) {
134
+ const filePath = path.join(projectPath, exports.AGENTS_MD_FILENAME);
135
+ if (fs.existsSync(filePath) && !opts.overwrite) {
136
+ return 'exists';
137
+ }
138
+ try {
139
+ fs.writeFileSync(filePath, exports.AGENTS_MD_TEMPLATE, 'utf8');
140
+ return 'written';
141
+ }
142
+ catch {
143
+ return 'skipped';
144
+ }
145
+ }
146
+ function writeCursorRules(projectPath, opts = {}) {
147
+ const filePath = path.join(projectPath, exports.CURSORRULES_FILENAME);
148
+ if (fs.existsSync(filePath) && !opts.overwrite) {
149
+ return 'exists';
150
+ }
151
+ try {
152
+ fs.writeFileSync(filePath, exports.CURSORRULES_TEMPLATE, 'utf8');
153
+ return 'written';
154
+ }
155
+ catch {
156
+ return 'skipped';
157
+ }
158
+ }
159
+ function writeCellRules(projectPath, opts = {}) {
160
+ const agentsMd = writeAgentsMd(projectPath, opts);
161
+ const cursorRules = opts.cursor === false ? 'skipped' : writeCursorRules(projectPath, opts);
162
+ return { agentsMd, cursorRules };
163
+ }
164
+ //# sourceMappingURL=agents-md.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents-md.js","sourceRoot":"","sources":["../../src/core/agents-md.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmGA,0CAEC;AAED,sCAWC;AAED,4CAWC;AAED,wCAIC;AArID,uCAAyB;AACzB,2CAA6B;AAEhB,QAAA,kBAAkB,GAAG,WAAW,CAAC;AACjC,QAAA,oBAAoB,GAAG,cAAc,CAAC;AACtC,QAAA,iBAAiB,GAAG,sBAAsB,CAAC;AAE3C,QAAA,kBAAkB,GAAG,GAAG,yBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2ErD,CAAC;AAEW,QAAA,oBAAoB,GAAG,GAAG,yBAAiB;;;;;;;CAOvD,CAAC;AAQF,SAAgB,eAAe,CAAC,OAAe;IAC7C,OAAO,OAAO,CAAC,QAAQ,CAAC,yBAAiB,CAAC,CAAC;AAC7C,CAAC;AAED,SAAgB,aAAa,CAAC,WAAmB,EAAE,OAAgC,EAAE;IACnF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,0BAAkB,CAAC,CAAC;IAC5D,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QAC/C,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,0BAAkB,EAAE,MAAM,CAAC,CAAC;QACvD,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAgB,gBAAgB,CAAC,WAAmB,EAAE,OAAgC,EAAE;IACtF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,4BAAoB,CAAC,CAAC;IAC9D,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;QAC/C,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,IAAI,CAAC;QACH,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,4BAAoB,EAAE,MAAM,CAAC,CAAC;QACzD,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,SAAgB,cAAc,CAAC,WAAmB,EAAE,OAAkD,EAAE;IACtG,MAAM,QAAQ,GAAG,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAClD,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAC5F,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACnC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/daemon/server.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAiDrD,QAAA,MAAM,GAAG,6CAAY,CAAC;AAItB,QAAA,MAAM,OAAO;;;mBAGuB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqChD,CAAC;AAulFF,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/daemon/server.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AACrE,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAiDrD,QAAA,MAAM,GAAG,6CAAY,CAAC;AAItB,QAAA,MAAM,OAAO;;;mBAGuB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqChD,CAAC;AA2oFF,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC"}
@@ -1766,7 +1766,7 @@ const MCP_TOOLS = [
1766
1766
  { name: 'cell_deep_scan', description: 'Deep scan codebase', inputSchema: { type: 'object', properties: { dir: { type: 'string' }, project: { type: 'string' } }, required: ['dir'] } },
1767
1767
  { name: 'cell_scan_report', description: 'Full scan report', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1768
1768
  { name: 'cell_send_signal', description: 'Send learning signal', inputSchema: { type: 'object', properties: { type: { type: 'string' }, originalCode: { type: 'string' }, editedCode: { type: 'string' }, file: { type: 'string' }, language: { type: 'string' } }, required: ['type'] } },
1769
- { name: 'cell_get_context', description: 'Full context injection', inputSchema: { type: 'object', properties: { project: { type: 'string' }, tool: { type: 'string' } }, required: ['project'] } },
1769
+ { name: 'cell_get_context', description: 'Full context injection. Pass `project` (folder name), or `cwd` (full path, auto-resolves basename), or omit to use daemon cwd. Pass `tool` for tool-specific formatting (cursor, antigravity, opencode, claude-code, codex, windsurf, copilot, aider).', inputSchema: { type: 'object', properties: { project: { type: 'string', description: 'Project name (folder basename). Optional if cwd is provided.' }, cwd: { type: 'string', description: 'Absolute path to the project root. Will be resolved to its basename.' }, tool: { type: 'string', description: 'AI tool name for formatting' } }, required: [] } },
1770
1770
  { name: 'cell_scan_full_pc', description: 'Scan entire PC for all code projects', inputSchema: { type: 'object', properties: {} } },
1771
1771
  { name: 'cell_behavior_summary', description: 'Behavioral summary', inputSchema: { type: 'object', properties: { project: { type: 'string' } }, required: ['project'] } },
1772
1772
  { name: 'cell_log_error', description: 'Log an error encounter', inputSchema: { type: 'object', properties: { project: { type: 'string' }, file: { type: 'string' }, errorType: { type: 'string' }, errorMessage: { type: 'string' }, line: { type: 'number' } }, required: ['errorType', 'errorMessage'] } },
@@ -1869,9 +1869,65 @@ async function handleMCPToolCall(name, args) {
1869
1869
  }
1870
1870
  case 'cell_get_context': {
1871
1871
  const { buildContext, formatContextForTool } = require('../core/prompt-builder');
1872
- const ctx = buildContext(args.project, args.tool);
1873
- const toolName = args.tool || (args.project ? 'claude-code' : undefined);
1874
- return { content: [{ type: 'text', text: formatContextForTool(ctx, toolName, args.project) }], context: ctx };
1872
+ // Auto-detect project name when AI doesn't know it. Order of resolution:
1873
+ // 1. args.project (explicit) highest priority
1874
+ // 2. args.cwd (IDE's current dir basename) Antigravity/Cursor pass this
1875
+ // 3. process.cwd() of the daemon (last resort)
1876
+ // If still nothing, return a helpful error listing registered projects.
1877
+ const explicitProject = args.project;
1878
+ const cwdArg = args.cwd;
1879
+ const path = require('path');
1880
+ const fs = require('fs');
1881
+ let resolvedProject = explicitProject;
1882
+ if (!resolvedProject && cwdArg) {
1883
+ try {
1884
+ if (fs.existsSync(cwdArg)) {
1885
+ resolvedProject = path.basename(path.resolve(cwdArg));
1886
+ }
1887
+ else {
1888
+ // Maybe they passed just a folder name
1889
+ resolvedProject = path.basename(cwdArg);
1890
+ }
1891
+ }
1892
+ catch { /* fall through */ }
1893
+ }
1894
+ if (!resolvedProject) {
1895
+ try {
1896
+ resolvedProject = path.basename(process.cwd());
1897
+ }
1898
+ catch { /* ignore */ }
1899
+ }
1900
+ // If we have a project but no data, check if it's actually registered.
1901
+ // If not, return a useful error with the list of known projects.
1902
+ if (resolvedProject) {
1903
+ try {
1904
+ const { ProjectRegistry } = require('../core/project-registry');
1905
+ const reg = new ProjectRegistry();
1906
+ const projects = reg.listProjects();
1907
+ const known = projects.find((p) => p.name === resolvedProject || p.path === path.resolve(resolvedProject || ''));
1908
+ if (!known) {
1909
+ // Project name might still work if it matches `cwd` of a previous scan
1910
+ // or if it's the same as a directory basename. Don't error out — just
1911
+ // let buildContext handle the empty-data case naturally.
1912
+ }
1913
+ }
1914
+ catch { /* ignore */ }
1915
+ }
1916
+ const ctx = buildContext(resolvedProject, args.tool);
1917
+ const toolName = args.tool || (resolvedProject ? 'claude-code' : undefined);
1918
+ const formatted = formatContextForTool(ctx, toolName, resolvedProject);
1919
+ // When no project resolved, prepend a hint to the output so the AI knows
1920
+ // what to do next.
1921
+ let hint = '';
1922
+ if (!explicitProject && !cwdArg) {
1923
+ hint = '> Tip: pass `project` (folder name) or `cwd` (full path) for richer context.\n\n';
1924
+ }
1925
+ return {
1926
+ content: [{ type: 'text', text: hint + formatted }],
1927
+ context: ctx,
1928
+ resolvedProject: resolvedProject || null,
1929
+ hint: !explicitProject && !cwdArg ? 'pass `project` or `cwd` for richer context' : undefined,
1930
+ };
1875
1931
  }
1876
1932
  case 'cell_scan_full_pc': {
1877
1933
  const { scanFullPC } = require('../pc-scanner');