fivocell 4.1.0 → 4.1.2
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/bin/cell.js +1 -1
- package/dist/__tests__/enhanced-blind-spots.test.js +45 -0
- package/dist/__tests__/enhanced-blind-spots.test.js.map +1 -1
- package/dist/__tests__/tool-specific-format.test.js +8 -10
- package/dist/__tests__/tool-specific-format.test.js.map +1 -1
- package/dist/cli.js +40 -4
- package/dist/cli.js.map +1 -1
- package/dist/code-scanner.d.ts.map +1 -1
- package/dist/code-scanner.js +47 -9
- package/dist/code-scanner.js.map +1 -1
- package/dist/core/enhanced-blind-spots.d.ts.map +1 -1
- package/dist/core/enhanced-blind-spots.js +146 -19
- package/dist/core/enhanced-blind-spots.js.map +1 -1
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +61 -3
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/syntax-engine.d.ts.map +1 -1
- package/dist/core/syntax-engine.js +5 -2
- package/dist/core/syntax-engine.js.map +1 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +963 -930
- package/dist/daemon/server.js.map +1 -1
- package/dist/pc-scanner.d.ts.map +1 -1
- package/dist/pc-scanner.js +6 -3
- package/dist/pc-scanner.js.map +1 -1
- package/package.json +1 -1
package/dist/daemon/server.js
CHANGED
|
@@ -1830,1017 +1830,1050 @@ const MCP_TOOLS = [
|
|
|
1830
1830
|
{ name: 'cell_model_recommend', description: 'Get AI model recommendations — which tool works best for which task', inputSchema: { type: 'object', properties: {} } },
|
|
1831
1831
|
];
|
|
1832
1832
|
async function handleMCPToolCall(name, args) {
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
catch (err) {
|
|
1948
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1949
|
-
return { error: `Session bridge failed: ${msg}`, crossedSession: false };
|
|
1950
|
-
}
|
|
1951
|
-
}
|
|
1952
|
-
case 'cell_session_end': {
|
|
1953
|
-
const { SessionMemory } = require('../core/session-memory');
|
|
1954
|
-
const memory = new SessionMemory();
|
|
1955
|
-
const sessionId = args.sessionId;
|
|
1956
|
-
try {
|
|
1957
|
-
memory.endSession(sessionId, {
|
|
1958
|
-
filesTouched: Array.isArray(args.filesTouched) ? args.filesTouched : [],
|
|
1959
|
-
keyDecisions: Array.isArray(args.keyDecisions) ? args.keyDecisions : [],
|
|
1960
|
-
contextSnapshot: args.contextSnapshot || '',
|
|
1961
|
-
});
|
|
1962
|
-
return { ended: true, sessionId };
|
|
1963
|
-
}
|
|
1964
|
-
catch (err) {
|
|
1965
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
1966
|
-
return { error: `Session end failed: ${msg}`, ended: false };
|
|
1967
|
-
}
|
|
1968
|
-
}
|
|
1969
|
-
case 'cell_session_log': {
|
|
1970
|
-
const { SessionMemory } = require('../core/session-memory');
|
|
1971
|
-
const memory = new SessionMemory();
|
|
1972
|
-
try {
|
|
1973
|
-
const sessionId = args.sessionId || 0;
|
|
1974
|
-
const project = args.project || 'unknown';
|
|
1975
|
-
if (args.type === 'approach' && args.approach) {
|
|
1976
|
-
const id = memory.recordApproach({
|
|
1977
|
-
sessionId: sessionId || undefined,
|
|
1978
|
-
project,
|
|
1979
|
-
approach: args.approach,
|
|
1980
|
-
status: args.status || 'tried',
|
|
1981
|
-
reason: args.reason,
|
|
1982
|
-
});
|
|
1983
|
-
return { recorded: 'approach', id };
|
|
1833
|
+
try {
|
|
1834
|
+
switch (name) {
|
|
1835
|
+
case 'cell_get_dev_profile': {
|
|
1836
|
+
const { getDeveloperProfile } = require('../code-scanner');
|
|
1837
|
+
const profile = getDeveloperProfile(args.project);
|
|
1838
|
+
if (!profile)
|
|
1839
|
+
return { error: 'no profile — run cell scan first' };
|
|
1840
|
+
return { project: args.project, profile };
|
|
1841
|
+
}
|
|
1842
|
+
case 'cell_get_code_patterns': {
|
|
1843
|
+
const { getCodePatterns } = require('../code-scanner');
|
|
1844
|
+
return { project: args.project, patterns: getCodePatterns(args.project, args.category) };
|
|
1845
|
+
}
|
|
1846
|
+
case 'cell_deep_scan': {
|
|
1847
|
+
const { scanCodebase } = require('../code-scanner');
|
|
1848
|
+
const result = scanCodebase(args.dir, args.project || path.basename(args.dir));
|
|
1849
|
+
return { project: result.project, filesScanned: result.filesScanned, totalLines: result.totalLines, profile: result.profile, strengths: result.profile.strengths, improvements: result.profile.improvements };
|
|
1850
|
+
}
|
|
1851
|
+
case 'cell_scan_report': {
|
|
1852
|
+
const { getDeveloperProfile, getCodePatterns } = require('../code-scanner');
|
|
1853
|
+
const profile = getDeveloperProfile(args.project);
|
|
1854
|
+
const patterns = getCodePatterns(args.project);
|
|
1855
|
+
return { project: args.project, profile, patterns, patternCount: patterns.length };
|
|
1856
|
+
}
|
|
1857
|
+
case 'cell_send_signal': {
|
|
1858
|
+
const { logError, logDecision, logContext, logStuck } = require('../behavioral-tracker');
|
|
1859
|
+
const type = args.type;
|
|
1860
|
+
if (type === 'error')
|
|
1861
|
+
return logError({ project: args.project, file: args.file, errorType: 'manual', errorMessage: String(args.editedCode || ''), line: 0 });
|
|
1862
|
+
if (type === 'decision')
|
|
1863
|
+
return logDecision({ project: args.project, file: args.file, decision: String(args.originalCode || ''), approach: String(args.editedCode || ''), worked: true });
|
|
1864
|
+
if (type === 'context')
|
|
1865
|
+
return logContext({ project: args.project, task: String(args.originalCode || ''), files: [] });
|
|
1866
|
+
if (type === 'stuck')
|
|
1867
|
+
return logStuck({ project: args.project, file: args.file, description: String(args.originalCode || '') });
|
|
1868
|
+
return { recorded: true };
|
|
1869
|
+
}
|
|
1870
|
+
case 'cell_get_context': {
|
|
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) }], context: ctx };
|
|
1875
|
+
}
|
|
1876
|
+
case 'cell_scan_full_pc': {
|
|
1877
|
+
const { scanFullPC } = require('../pc-scanner');
|
|
1878
|
+
const result = scanFullPC();
|
|
1879
|
+
return { totalProjects: result.totalProjects, totalFiles: result.totalFiles, totalLines: result.totalLines, profile: result.aggregatedProfile };
|
|
1880
|
+
}
|
|
1881
|
+
case 'cell_behavior_summary': {
|
|
1882
|
+
const { getBehaviorSummary } = require('../behavioral-tracker');
|
|
1883
|
+
return getBehaviorSummary(args.project);
|
|
1884
|
+
}
|
|
1885
|
+
case 'cell_log_error': {
|
|
1886
|
+
const { logError } = require('../behavioral-tracker');
|
|
1887
|
+
return logError({ project: args.project, file: args.file, errorType: args.errorType, errorMessage: args.errorMessage, line: args.line });
|
|
1888
|
+
}
|
|
1889
|
+
case 'cell_log_fix': {
|
|
1890
|
+
const { logErrorFix } = require('../behavioral-tracker');
|
|
1891
|
+
logErrorFix({ errorId: args.errorId, fixApplied: args.fixApplied, worked: args.worked, timeToFixMs: args.timeToFixMs });
|
|
1892
|
+
return { recorded: true };
|
|
1893
|
+
}
|
|
1894
|
+
case 'cell_log_decision': {
|
|
1895
|
+
const { logDecision } = require('../behavioral-tracker');
|
|
1896
|
+
return logDecision({ project: args.project, file: args.file, decision: args.decision, approach: args.approach, worked: args.worked });
|
|
1897
|
+
}
|
|
1898
|
+
case 'cell_log_context': {
|
|
1899
|
+
const { logContext } = require('../behavioral-tracker');
|
|
1900
|
+
return logContext({ project: args.project, task: args.task, files: args.files });
|
|
1901
|
+
}
|
|
1902
|
+
case 'cell_log_stuck': {
|
|
1903
|
+
const { logStuck } = require('../behavioral-tracker');
|
|
1904
|
+
return logStuck({ project: args.project, file: args.file, description: args.description });
|
|
1905
|
+
}
|
|
1906
|
+
case 'cell_session_bridge': {
|
|
1907
|
+
const { SessionMemory } = require('../core/session-memory');
|
|
1908
|
+
const memory = new SessionMemory();
|
|
1909
|
+
const project = args.project;
|
|
1910
|
+
const tool = args.tool || 'unknown';
|
|
1911
|
+
try {
|
|
1912
|
+
const lastSession = memory.getLastSessionForProject(project);
|
|
1913
|
+
const newSessionId = memory.startSession(tool, project);
|
|
1914
|
+
let bridgeContext = '';
|
|
1915
|
+
if (lastSession && lastSession.toolName !== tool) {
|
|
1916
|
+
const triedApproaches = memory.getRecentApproaches(project, 5);
|
|
1917
|
+
const openQuestions = memory.getOpenQuestions(project);
|
|
1918
|
+
const hotFiles = memory.getMostTouchedFiles(project, 5);
|
|
1919
|
+
const decisions = Array.isArray(lastSession.keyDecisions) ? JSON.stringify(lastSession.keyDecisions) : 'none';
|
|
1920
|
+
bridgeContext = formatSessionBridge(lastSession.toolName, tool, lastSession.contextSnapshot, decisions, {
|
|
1921
|
+
triedApproaches,
|
|
1922
|
+
openQuestions,
|
|
1923
|
+
hotFiles,
|
|
1924
|
+
});
|
|
1925
|
+
}
|
|
1926
|
+
const recentSessions = memory.getRecentSessions(3).filter((s) => s.project === project);
|
|
1927
|
+
const sessionHistory = recentSessions.map((s) => ({
|
|
1928
|
+
tool: s.toolName,
|
|
1929
|
+
when: s.startTime,
|
|
1930
|
+
files: s.filesTouched,
|
|
1931
|
+
decisions: s.keyDecisions,
|
|
1932
|
+
}));
|
|
1933
|
+
return {
|
|
1934
|
+
newSessionId,
|
|
1935
|
+
lastSession: lastSession ? {
|
|
1936
|
+
tool: lastSession.toolName,
|
|
1937
|
+
startedAt: lastSession.startTime,
|
|
1938
|
+
context: lastSession.contextSnapshot,
|
|
1939
|
+
} : null,
|
|
1940
|
+
bridgeContext,
|
|
1941
|
+
sessionHistory,
|
|
1942
|
+
triedApproaches: memory.getRecentApproaches(project, 5),
|
|
1943
|
+
openQuestions: memory.getOpenQuestions(project),
|
|
1944
|
+
hotFiles: memory.getMostTouchedFiles(project, 5),
|
|
1945
|
+
message: bridgeContext || 'No previous session to bridge. Start a new session!',
|
|
1946
|
+
};
|
|
1984
1947
|
}
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
return {
|
|
1948
|
+
catch (err) {
|
|
1949
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1950
|
+
return { error: `Session bridge failed: ${msg}`, crossedSession: false };
|
|
1988
1951
|
}
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1952
|
+
}
|
|
1953
|
+
case 'cell_session_end': {
|
|
1954
|
+
const { SessionMemory } = require('../core/session-memory');
|
|
1955
|
+
const memory = new SessionMemory();
|
|
1956
|
+
const sessionId = args.sessionId;
|
|
1957
|
+
try {
|
|
1958
|
+
memory.endSession(sessionId, {
|
|
1959
|
+
filesTouched: Array.isArray(args.filesTouched) ? args.filesTouched : [],
|
|
1960
|
+
keyDecisions: Array.isArray(args.keyDecisions) ? args.keyDecisions : [],
|
|
1961
|
+
contextSnapshot: args.contextSnapshot || '',
|
|
1995
1962
|
});
|
|
1996
|
-
return {
|
|
1963
|
+
return { ended: true, sessionId };
|
|
1997
1964
|
}
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
return {
|
|
1965
|
+
catch (err) {
|
|
1966
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1967
|
+
return { error: `Session end failed: ${msg}`, ended: false };
|
|
2001
1968
|
}
|
|
2002
|
-
return { error: 'unknown log type or missing field' };
|
|
2003
|
-
}
|
|
2004
|
-
catch (err) {
|
|
2005
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2006
|
-
return { error: `Session log failed: ${msg}` };
|
|
2007
|
-
}
|
|
2008
|
-
}
|
|
2009
|
-
case 'cell_session_start': {
|
|
2010
|
-
const { SessionMemory } = require('../core/session-memory');
|
|
2011
|
-
const memory = new SessionMemory();
|
|
2012
|
-
try {
|
|
2013
|
-
const project = args.project || 'unknown';
|
|
2014
|
-
const tool = args.tool || 'unknown';
|
|
2015
|
-
const sessionId = memory.startSession(tool, project);
|
|
2016
|
-
return {
|
|
2017
|
-
sessionId,
|
|
2018
|
-
project,
|
|
2019
|
-
tool,
|
|
2020
|
-
startedAt: new Date().toISOString(),
|
|
2021
|
-
message: `Session ${sessionId} started for ${project} on ${tool}`,
|
|
2022
|
-
};
|
|
2023
|
-
}
|
|
2024
|
-
catch (err) {
|
|
2025
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2026
|
-
return { error: `Session start failed: ${msg}` };
|
|
2027
|
-
}
|
|
2028
|
-
}
|
|
2029
|
-
case 'cell_session_status': {
|
|
2030
|
-
const { SessionMemory } = require('../core/session-memory');
|
|
2031
|
-
const memory = new SessionMemory();
|
|
2032
|
-
try {
|
|
2033
|
-
const sessionId = args.sessionId;
|
|
2034
|
-
const db = (0, database_1.getDb)();
|
|
2035
|
-
const sess = db.prepare('SELECT * FROM sessions WHERE id = ?').get(sessionId);
|
|
2036
|
-
if (!sess)
|
|
2037
|
-
return { error: 'Session not found', sessionId };
|
|
2038
|
-
const files = memory.getSessionFiles(sessionId);
|
|
2039
|
-
const approaches = memory.getSessionApproaches(sessionId);
|
|
2040
|
-
const isActive = !sess.end_time;
|
|
2041
|
-
return {
|
|
2042
|
-
sessionId,
|
|
2043
|
-
tool: String(sess.tool_name || ''),
|
|
2044
|
-
project: String(sess.project || ''),
|
|
2045
|
-
startTime: String(sess.start_time || ''),
|
|
2046
|
-
endTime: sess.end_time ? String(sess.end_time) : null,
|
|
2047
|
-
isActive,
|
|
2048
|
-
filesCount: files.length,
|
|
2049
|
-
approachesCount: approaches.length,
|
|
2050
|
-
files: files.slice(0, 10),
|
|
2051
|
-
approaches: approaches.slice(0, 10),
|
|
2052
|
-
};
|
|
2053
|
-
}
|
|
2054
|
-
catch (err) {
|
|
2055
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2056
|
-
return { error: `Session status failed: ${msg}` };
|
|
2057
|
-
}
|
|
2058
|
-
}
|
|
2059
|
-
case 'cell_session_recent': {
|
|
2060
|
-
const { SessionMemory } = require('../core/session-memory');
|
|
2061
|
-
const memory = new SessionMemory();
|
|
2062
|
-
try {
|
|
2063
|
-
const project = args.project;
|
|
2064
|
-
const limit = args.limit || 10;
|
|
2065
|
-
let sessions = memory.getRecentSessions(limit);
|
|
2066
|
-
if (project)
|
|
2067
|
-
sessions = sessions.filter((s) => s.project === project);
|
|
2068
|
-
return {
|
|
2069
|
-
count: sessions.length,
|
|
2070
|
-
sessions: sessions.slice(0, limit).map((s) => ({
|
|
2071
|
-
sessionId: s.id,
|
|
2072
|
-
tool: s.toolName,
|
|
2073
|
-
project: s.project,
|
|
2074
|
-
startTime: s.startTime,
|
|
2075
|
-
endTime: s.endTime || null,
|
|
2076
|
-
filesCount: s.filesTouched.length,
|
|
2077
|
-
decisionsCount: s.keyDecisions.length,
|
|
2078
|
-
})),
|
|
2079
|
-
};
|
|
2080
1969
|
}
|
|
2081
|
-
|
|
2082
|
-
const
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
if (
|
|
2098
|
-
|
|
1970
|
+
case 'cell_session_log': {
|
|
1971
|
+
const { SessionMemory } = require('../core/session-memory');
|
|
1972
|
+
const memory = new SessionMemory();
|
|
1973
|
+
try {
|
|
1974
|
+
const sessionId = args.sessionId || 0;
|
|
1975
|
+
const project = args.project || 'unknown';
|
|
1976
|
+
if (args.type === 'approach' && args.approach) {
|
|
1977
|
+
const id = memory.recordApproach({
|
|
1978
|
+
sessionId: sessionId || undefined,
|
|
1979
|
+
project,
|
|
1980
|
+
approach: args.approach,
|
|
1981
|
+
status: args.status || 'tried',
|
|
1982
|
+
reason: args.reason,
|
|
1983
|
+
});
|
|
1984
|
+
return { recorded: 'approach', id };
|
|
1985
|
+
}
|
|
1986
|
+
if (args.type === 'file' && args.filePath) {
|
|
1987
|
+
memory.recordFileTouch({ sessionId: sessionId || undefined, project, filePath: args.filePath });
|
|
1988
|
+
return { recorded: 'file' };
|
|
1989
|
+
}
|
|
1990
|
+
if (args.type === 'question' && args.question) {
|
|
1991
|
+
const id = memory.recordQuestion({
|
|
1992
|
+
sessionId: sessionId || undefined,
|
|
1993
|
+
project,
|
|
1994
|
+
question: args.question,
|
|
1995
|
+
priority: args.priority || 'medium',
|
|
1996
|
+
});
|
|
1997
|
+
return { recorded: 'question', id };
|
|
2099
1998
|
}
|
|
2100
|
-
|
|
2101
|
-
|
|
1999
|
+
if (args.type === 'resolve' && args.questionId) {
|
|
2000
|
+
memory.resolveQuestion(args.questionId, args.answer || '');
|
|
2001
|
+
return { recorded: 'resolve' };
|
|
2102
2002
|
}
|
|
2003
|
+
return { error: 'unknown log type or missing field' };
|
|
2004
|
+
}
|
|
2005
|
+
catch (err) {
|
|
2006
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2007
|
+
return { error: `Session log failed: ${msg}` };
|
|
2103
2008
|
}
|
|
2104
|
-
return {
|
|
2105
|
-
avoid,
|
|
2106
|
-
openQuestions: openQuestions.map((q) => ({ id: q.id, question: q.question, priority: q.priority })),
|
|
2107
|
-
hotFiles: hotFiles.slice(0, 5).map((f) => ({ path: f.filePath, touches: f.touchCount })),
|
|
2108
|
-
lastSession: lastSession ? {
|
|
2109
|
-
tool: lastSession.toolName,
|
|
2110
|
-
when: lastSession.endTime,
|
|
2111
|
-
context: lastSession.contextSnapshot,
|
|
2112
|
-
} : null,
|
|
2113
|
-
message: avoid.length > 0
|
|
2114
|
-
? `Don't suggest: ${avoid.map(a => a.approach).slice(0, 3).join(', ')}`
|
|
2115
|
-
: 'No anti-repetition data yet',
|
|
2116
|
-
};
|
|
2117
2009
|
}
|
|
2118
|
-
|
|
2119
|
-
const
|
|
2120
|
-
|
|
2010
|
+
case 'cell_session_start': {
|
|
2011
|
+
const { SessionMemory } = require('../core/session-memory');
|
|
2012
|
+
const memory = new SessionMemory();
|
|
2013
|
+
try {
|
|
2014
|
+
const project = args.project || 'unknown';
|
|
2015
|
+
const tool = args.tool || 'unknown';
|
|
2016
|
+
const sessionId = memory.startSession(tool, project);
|
|
2017
|
+
return {
|
|
2018
|
+
sessionId,
|
|
2019
|
+
project,
|
|
2020
|
+
tool,
|
|
2021
|
+
startedAt: new Date().toISOString(),
|
|
2022
|
+
message: `Session ${sessionId} started for ${project} on ${tool}`,
|
|
2023
|
+
};
|
|
2024
|
+
}
|
|
2025
|
+
catch (err) {
|
|
2026
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2027
|
+
return { error: `Session start failed: ${msg}` };
|
|
2028
|
+
}
|
|
2121
2029
|
}
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2030
|
+
case 'cell_session_status': {
|
|
2031
|
+
const { SessionMemory } = require('../core/session-memory');
|
|
2032
|
+
const memory = new SessionMemory();
|
|
2033
|
+
try {
|
|
2034
|
+
const sessionId = args.sessionId;
|
|
2035
|
+
const db = (0, database_1.getDb)();
|
|
2036
|
+
const sess = db.prepare('SELECT * FROM sessions WHERE id = ?').get(sessionId);
|
|
2037
|
+
if (!sess)
|
|
2038
|
+
return { error: 'Session not found', sessionId };
|
|
2039
|
+
const files = memory.getSessionFiles(sessionId);
|
|
2040
|
+
const approaches = memory.getSessionApproaches(sessionId);
|
|
2041
|
+
const isActive = !sess.end_time;
|
|
2042
|
+
return {
|
|
2043
|
+
sessionId,
|
|
2044
|
+
tool: String(sess.tool_name || ''),
|
|
2045
|
+
project: String(sess.project || ''),
|
|
2046
|
+
startTime: String(sess.start_time || ''),
|
|
2047
|
+
endTime: sess.end_time ? String(sess.end_time) : null,
|
|
2048
|
+
isActive,
|
|
2049
|
+
filesCount: files.length,
|
|
2050
|
+
approachesCount: approaches.length,
|
|
2051
|
+
files: files.slice(0, 10),
|
|
2052
|
+
approaches: approaches.slice(0, 10),
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
catch (err) {
|
|
2056
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2057
|
+
return { error: `Session status failed: ${msg}` };
|
|
2058
|
+
}
|
|
2138
2059
|
}
|
|
2139
|
-
|
|
2140
|
-
const
|
|
2141
|
-
|
|
2060
|
+
case 'cell_session_recent': {
|
|
2061
|
+
const { SessionMemory } = require('../core/session-memory');
|
|
2062
|
+
const memory = new SessionMemory();
|
|
2063
|
+
try {
|
|
2064
|
+
const project = args.project;
|
|
2065
|
+
const limit = args.limit || 10;
|
|
2066
|
+
let sessions = memory.getRecentSessions(limit);
|
|
2067
|
+
if (project)
|
|
2068
|
+
sessions = sessions.filter((s) => s.project === project);
|
|
2069
|
+
return {
|
|
2070
|
+
count: sessions.length,
|
|
2071
|
+
sessions: sessions.slice(0, limit).map((s) => ({
|
|
2072
|
+
sessionId: s.id,
|
|
2073
|
+
tool: s.toolName,
|
|
2074
|
+
project: s.project,
|
|
2075
|
+
startTime: s.startTime,
|
|
2076
|
+
endTime: s.endTime || null,
|
|
2077
|
+
filesCount: s.filesTouched.length,
|
|
2078
|
+
decisionsCount: s.keyDecisions.length,
|
|
2079
|
+
})),
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
2082
|
+
catch (err) {
|
|
2083
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2084
|
+
return { error: `Session recent failed: ${msg}` };
|
|
2085
|
+
}
|
|
2142
2086
|
}
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2087
|
+
case 'cell_session_recommendations': {
|
|
2088
|
+
const { SessionMemory } = require('../core/session-memory');
|
|
2089
|
+
const memory = new SessionMemory();
|
|
2090
|
+
try {
|
|
2091
|
+
const project = args.project || 'unknown';
|
|
2092
|
+
const triedApproaches = memory.getRecentApproaches(project, 10);
|
|
2093
|
+
const openQuestions = memory.getOpenQuestions(project);
|
|
2094
|
+
const hotFiles = memory.getMostTouchedFiles(project, 10);
|
|
2095
|
+
const lastSession = memory.getLastSessionForProject(project);
|
|
2096
|
+
const avoid = [];
|
|
2097
|
+
for (const a of triedApproaches) {
|
|
2098
|
+
if (a.status === 'failed') {
|
|
2099
|
+
avoid.push({ approach: a.approach, reason: `failed ${a.count}x` });
|
|
2100
|
+
}
|
|
2101
|
+
else if (a.status === 'partial') {
|
|
2102
|
+
avoid.push({ approach: a.approach, reason: `partial (${a.count}x)` });
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
return {
|
|
2106
|
+
avoid,
|
|
2107
|
+
openQuestions: openQuestions.map((q) => ({ id: q.id, question: q.question, priority: q.priority })),
|
|
2108
|
+
hotFiles: hotFiles.slice(0, 5).map((f) => ({ path: f.filePath, touches: f.touchCount })),
|
|
2109
|
+
lastSession: lastSession ? {
|
|
2110
|
+
tool: lastSession.toolName,
|
|
2111
|
+
when: lastSession.endTime,
|
|
2112
|
+
context: lastSession.contextSnapshot,
|
|
2113
|
+
} : null,
|
|
2114
|
+
message: avoid.length > 0
|
|
2115
|
+
? `Don't suggest: ${avoid.map(a => a.approach).slice(0, 3).join(', ')}`
|
|
2116
|
+
: 'No anti-repetition data yet',
|
|
2117
|
+
};
|
|
2118
|
+
}
|
|
2119
|
+
catch (err) {
|
|
2120
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2121
|
+
return { error: `Session recommendations failed: ${msg}` };
|
|
2122
|
+
}
|
|
2159
2123
|
}
|
|
2160
|
-
|
|
2161
|
-
const
|
|
2162
|
-
|
|
2124
|
+
case 'cell_list_projects': {
|
|
2125
|
+
const { ProjectRegistry } = require('../core/project-registry');
|
|
2126
|
+
const registry = new ProjectRegistry();
|
|
2127
|
+
try {
|
|
2128
|
+
const projects = registry.listProjects();
|
|
2129
|
+
return {
|
|
2130
|
+
count: projects.length,
|
|
2131
|
+
projects: projects.map((p) => ({
|
|
2132
|
+
name: p.name,
|
|
2133
|
+
path: p.path,
|
|
2134
|
+
stack: p.stack,
|
|
2135
|
+
fileCount: p.fileCount,
|
|
2136
|
+
lastScanAt: p.lastScanAt,
|
|
2137
|
+
})),
|
|
2138
|
+
};
|
|
2139
|
+
}
|
|
2140
|
+
catch (err) {
|
|
2141
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2142
|
+
return { error: `List projects failed: ${msg}` };
|
|
2143
|
+
}
|
|
2163
2144
|
}
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
return {
|
|
2173
|
-
}
|
|
2174
|
-
const project = registry.getProject(detected);
|
|
2175
|
-
return {
|
|
2176
|
-
detected,
|
|
2177
|
-
cwd,
|
|
2178
|
-
project: project ? {
|
|
2145
|
+
case 'cell_get_project': {
|
|
2146
|
+
const { ProjectRegistry } = require('../core/project-registry');
|
|
2147
|
+
const registry = new ProjectRegistry();
|
|
2148
|
+
try {
|
|
2149
|
+
const name = args.name || '';
|
|
2150
|
+
const project = registry.getProject(name);
|
|
2151
|
+
if (!project)
|
|
2152
|
+
return { error: 'Project not found', name };
|
|
2153
|
+
return {
|
|
2179
2154
|
name: project.name,
|
|
2155
|
+
path: project.path,
|
|
2180
2156
|
stack: project.stack,
|
|
2181
2157
|
fileCount: project.fileCount,
|
|
2182
2158
|
lastScanAt: project.lastScanAt,
|
|
2183
|
-
}
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
return { error: `Detect project failed: ${msg}` };
|
|
2190
|
-
}
|
|
2191
|
-
}
|
|
2192
|
-
case 'cell_register_project': {
|
|
2193
|
-
const { ProjectRegistry } = require('../core/project-registry');
|
|
2194
|
-
const registry = new ProjectRegistry();
|
|
2195
|
-
try {
|
|
2196
|
-
const id = registry.registerProject({
|
|
2197
|
-
name: args.name || '',
|
|
2198
|
-
path: args.path || '',
|
|
2199
|
-
stack: args.stack,
|
|
2200
|
-
fileCount: args.fileCount,
|
|
2201
|
-
});
|
|
2202
|
-
return { id, name: args.name, registered: true };
|
|
2203
|
-
}
|
|
2204
|
-
catch (err) {
|
|
2205
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2206
|
-
return { error: `Register project failed: ${msg}` };
|
|
2207
|
-
}
|
|
2208
|
-
}
|
|
2209
|
-
case 'cell_graph_files': {
|
|
2210
|
-
try {
|
|
2211
|
-
const project = args.project || '';
|
|
2212
|
-
const limit = args.limit || 20;
|
|
2213
|
-
const { getFileKnowledgeGraph } = require('../core/knowledge-graph-store');
|
|
2214
|
-
const graph = getFileKnowledgeGraph(project);
|
|
2215
|
-
return {
|
|
2216
|
-
stats: graph.stats,
|
|
2217
|
-
topRiskFiles: graph.files.slice(0, limit),
|
|
2218
|
-
entryPoints: graph.files.filter((f) => f.isEntryPoint).slice(0, 10),
|
|
2219
|
-
sampleDeps: graph.deps.slice(0, limit),
|
|
2220
|
-
};
|
|
2221
|
-
}
|
|
2222
|
-
catch (err) {
|
|
2223
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2224
|
-
return { error: `Graph files failed: ${msg}` };
|
|
2225
|
-
}
|
|
2226
|
-
}
|
|
2227
|
-
case 'cell_graph_blast_radius': {
|
|
2228
|
-
try {
|
|
2229
|
-
const project = args.project || '';
|
|
2230
|
-
const file = args.file || '';
|
|
2231
|
-
const { computeBlastRadius } = require('../core/knowledge-graph-store');
|
|
2232
|
-
const radius = computeBlastRadius(project, file);
|
|
2233
|
-
return radius;
|
|
2234
|
-
}
|
|
2235
|
-
catch (err) {
|
|
2236
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2237
|
-
return { error: `Blast radius failed: ${msg}` };
|
|
2238
|
-
}
|
|
2239
|
-
}
|
|
2240
|
-
case 'cell_graph_tech': {
|
|
2241
|
-
try {
|
|
2242
|
-
const project = args.project || '';
|
|
2243
|
-
const { getTechProficiency } = require('../core/knowledge-graph-store');
|
|
2244
|
-
const techs = getTechProficiency(project);
|
|
2245
|
-
const strong = techs.filter((t) => t.proficiencyScore >= 70);
|
|
2246
|
-
const learning = techs.filter((t) => t.proficiencyScore < 50);
|
|
2247
|
-
return {
|
|
2248
|
-
totalTechs: techs.length,
|
|
2249
|
-
strong,
|
|
2250
|
-
learning,
|
|
2251
|
-
all: techs,
|
|
2252
|
-
message: strong.length > 0
|
|
2253
|
-
? `Strong in: ${strong.map((t) => t.technology).slice(0, 3).join(', ')}`
|
|
2254
|
-
: 'No strong tech tracked yet',
|
|
2255
|
-
};
|
|
2256
|
-
}
|
|
2257
|
-
catch (err) {
|
|
2258
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2259
|
-
return { error: `Graph tech failed: ${msg}` };
|
|
2260
|
-
}
|
|
2261
|
-
}
|
|
2262
|
-
case 'cell_graph_stats': {
|
|
2263
|
-
try {
|
|
2264
|
-
const project = args.project || '';
|
|
2265
|
-
const { getPatternGraphStats, getFileKnowledgeGraph, getTechProficiency } = require('../core/knowledge-graph-store');
|
|
2266
|
-
const patternStats = getPatternGraphStats(project);
|
|
2267
|
-
const fileGraph = getFileKnowledgeGraph(project);
|
|
2268
|
-
const techs = getTechProficiency(project);
|
|
2269
|
-
return {
|
|
2270
|
-
patternGraph: patternStats,
|
|
2271
|
-
fileGraph: fileGraph.stats,
|
|
2272
|
-
techCount: techs.length,
|
|
2273
|
-
highRiskFiles: fileGraph.files.filter((f) => f.riskScore >= 50).length,
|
|
2274
|
-
};
|
|
2275
|
-
}
|
|
2276
|
-
catch (err) {
|
|
2277
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2278
|
-
return { error: `Graph stats failed: ${msg}` };
|
|
2279
|
-
}
|
|
2280
|
-
}
|
|
2281
|
-
case 'cell_team_silos': {
|
|
2282
|
-
try {
|
|
2283
|
-
const { detectKnowledgeSilos } = require('../team-collaboration');
|
|
2284
|
-
const silos = detectKnowledgeSilos();
|
|
2285
|
-
return {
|
|
2286
|
-
count: silos.length,
|
|
2287
|
-
high: silos.filter((s) => s.riskLevel === 'high').length,
|
|
2288
|
-
silos,
|
|
2289
|
-
message: silos.length > 0
|
|
2290
|
-
? `${silos.filter((s) => s.riskLevel === 'high').length} high-risk silos detected`
|
|
2291
|
-
: 'No knowledge silos detected',
|
|
2292
|
-
};
|
|
2293
|
-
}
|
|
2294
|
-
catch (err) {
|
|
2295
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2296
|
-
return { error: `Team silos failed: ${msg}` };
|
|
2297
|
-
}
|
|
2298
|
-
}
|
|
2299
|
-
case 'cell_team_bus_factor': {
|
|
2300
|
-
try {
|
|
2301
|
-
const { calculateBusFactor } = require('../team-collaboration');
|
|
2302
|
-
return calculateBusFactor();
|
|
2303
|
-
}
|
|
2304
|
-
catch (err) {
|
|
2305
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2306
|
-
return { error: `Bus factor failed: ${msg}` };
|
|
2307
|
-
}
|
|
2308
|
-
}
|
|
2309
|
-
case 'cell_team_health': {
|
|
2310
|
-
try {
|
|
2311
|
-
const { getTeamHealth } = require('../team-collaboration');
|
|
2312
|
-
return getTeamHealth(args.project || undefined);
|
|
2313
|
-
}
|
|
2314
|
-
catch (err) {
|
|
2315
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2316
|
-
return { error: `Team health failed: ${msg}` };
|
|
2317
|
-
}
|
|
2318
|
-
}
|
|
2319
|
-
case 'cell_team_onboard': {
|
|
2320
|
-
try {
|
|
2321
|
-
const { generateOnboardingDoc } = require('../team-collaboration');
|
|
2322
|
-
const teamName = args.teamName || 'Team';
|
|
2323
|
-
const project = args.project || undefined;
|
|
2324
|
-
return generateOnboardingDoc(teamName, project);
|
|
2325
|
-
}
|
|
2326
|
-
catch (err) {
|
|
2327
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2328
|
-
return { error: `Onboard failed: ${msg}` };
|
|
2329
|
-
}
|
|
2330
|
-
}
|
|
2331
|
-
case 'cell_team_retro': {
|
|
2332
|
-
try {
|
|
2333
|
-
const { generateSprintRetro } = require('../team-collaboration');
|
|
2334
|
-
const days = args.days || 14;
|
|
2335
|
-
const project = args.project || undefined;
|
|
2336
|
-
return generateSprintRetro(days, project);
|
|
2337
|
-
}
|
|
2338
|
-
catch (err) {
|
|
2339
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2340
|
-
return { error: `Retro failed: ${msg}` };
|
|
2341
|
-
}
|
|
2342
|
-
}
|
|
2343
|
-
case 'cell_team_handoff': {
|
|
2344
|
-
try {
|
|
2345
|
-
const { generateHandoff } = require('../team-collaboration');
|
|
2346
|
-
return generateHandoff(args.from || '', args.to || '', args.project || '');
|
|
2347
|
-
}
|
|
2348
|
-
catch (err) {
|
|
2349
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2350
|
-
return { error: `Handoff failed: ${msg}` };
|
|
2351
|
-
}
|
|
2352
|
-
}
|
|
2353
|
-
case 'cell_team_knowledge_transfer': {
|
|
2354
|
-
try {
|
|
2355
|
-
const { suggestKnowledgeTransfer } = require('../team-collaboration');
|
|
2356
|
-
const suggestions = suggestKnowledgeTransfer();
|
|
2357
|
-
return {
|
|
2358
|
-
count: suggestions.length,
|
|
2359
|
-
suggestions,
|
|
2360
|
-
message: suggestions.length > 0
|
|
2361
|
-
? `${suggestions.length} transfer pairs suggested`
|
|
2362
|
-
: 'No urgent transfers needed',
|
|
2363
|
-
};
|
|
2364
|
-
}
|
|
2365
|
-
catch (err) {
|
|
2366
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2367
|
-
return { error: `Knowledge transfer failed: ${msg}` };
|
|
2368
|
-
}
|
|
2369
|
-
}
|
|
2370
|
-
case 'cell_team_style': {
|
|
2371
|
-
try {
|
|
2372
|
-
const { composeTeamStyle } = require('../team-collaboration');
|
|
2373
|
-
return composeTeamStyle(args.project || undefined);
|
|
2374
|
-
}
|
|
2375
|
-
catch (err) {
|
|
2376
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2377
|
-
return { error: `Team style failed: ${msg}` };
|
|
2378
|
-
}
|
|
2379
|
-
}
|
|
2380
|
-
case 'cell_team_dashboard': {
|
|
2381
|
-
try {
|
|
2382
|
-
const { detectKnowledgeSilos, calculateBusFactor, getTeamHealth, composeTeamStyle } = require('../team-collaboration');
|
|
2383
|
-
const project = args.project || undefined;
|
|
2384
|
-
const silos = detectKnowledgeSilos();
|
|
2385
|
-
const busFactor = calculateBusFactor();
|
|
2386
|
-
const health = getTeamHealth(project);
|
|
2387
|
-
const style = composeTeamStyle(project);
|
|
2388
|
-
return {
|
|
2389
|
-
silos: { count: silos.length, high: silos.filter((s) => s.riskLevel === 'high').length, top: silos.slice(0, 5) },
|
|
2390
|
-
busFactor,
|
|
2391
|
-
health,
|
|
2392
|
-
style,
|
|
2393
|
-
generatedAt: new Date().toISOString(),
|
|
2394
|
-
};
|
|
2395
|
-
}
|
|
2396
|
-
catch (err) {
|
|
2397
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2398
|
-
return { error: `Team dashboard failed: ${msg}` };
|
|
2399
|
-
}
|
|
2400
|
-
}
|
|
2401
|
-
case 'cell_community_stats': {
|
|
2402
|
-
try {
|
|
2403
|
-
const { getCommunityStats } = require('../core/community-store');
|
|
2404
|
-
return getCommunityStats();
|
|
2405
|
-
}
|
|
2406
|
-
catch (err) {
|
|
2407
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2408
|
-
return { error: `Community stats failed: ${msg}` };
|
|
2409
|
-
}
|
|
2410
|
-
}
|
|
2411
|
-
case 'cell_community_share': {
|
|
2412
|
-
try {
|
|
2413
|
-
const { shareCommunityPattern, validatePrivacy } = require('../core/community-store');
|
|
2414
|
-
const rule = args.rule || '';
|
|
2415
|
-
const validation = validatePrivacy(rule);
|
|
2416
|
-
if (!validation.safe) {
|
|
2417
|
-
return { shared: false, errors: validation.errors, warnings: validation.warnings };
|
|
2418
|
-
}
|
|
2419
|
-
const result = shareCommunityPattern({
|
|
2420
|
-
category: args.category || 'unknown',
|
|
2421
|
-
rule,
|
|
2422
|
-
language: args.language,
|
|
2423
|
-
framework: args.framework,
|
|
2424
|
-
successRate: args.successRate,
|
|
2425
|
-
});
|
|
2426
|
-
return { ...result, warnings: [...validation.warnings, ...result.warnings] };
|
|
2427
|
-
}
|
|
2428
|
-
catch (err) {
|
|
2429
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2430
|
-
return { error: `Community share failed: ${msg}` };
|
|
2431
|
-
}
|
|
2432
|
-
}
|
|
2433
|
-
case 'cell_community_patterns': {
|
|
2434
|
-
try {
|
|
2435
|
-
const { getCommunityPatterns } = require('../core/community-store');
|
|
2436
|
-
const patterns = getCommunityPatterns({
|
|
2437
|
-
category: args.category,
|
|
2438
|
-
language: args.language,
|
|
2439
|
-
minVotes: args.minVotes,
|
|
2440
|
-
limit: args.limit || 20,
|
|
2441
|
-
});
|
|
2442
|
-
return { count: patterns.length, patterns };
|
|
2443
|
-
}
|
|
2444
|
-
catch (err) {
|
|
2445
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2446
|
-
return { error: `Community patterns failed: ${msg}` };
|
|
2447
|
-
}
|
|
2448
|
-
}
|
|
2449
|
-
case 'cell_community_vote': {
|
|
2450
|
-
try {
|
|
2451
|
-
const { voteCommunityPattern } = require('../core/community-store');
|
|
2452
|
-
return voteCommunityPattern(args.patternId || '', args.upvote !== false);
|
|
2453
|
-
}
|
|
2454
|
-
catch (err) {
|
|
2455
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2456
|
-
return { error: `Community vote failed: ${msg}` };
|
|
2457
|
-
}
|
|
2458
|
-
}
|
|
2459
|
-
case 'cell_community_insights': {
|
|
2460
|
-
try {
|
|
2461
|
-
const { getCommunityInsights } = require('../core/community-store');
|
|
2462
|
-
const insights = getCommunityInsights({
|
|
2463
|
-
severity: args.severity,
|
|
2464
|
-
category: args.category,
|
|
2465
|
-
limit: args.limit || 20,
|
|
2466
|
-
});
|
|
2467
|
-
return { count: insights.length, insights };
|
|
2159
|
+
};
|
|
2160
|
+
}
|
|
2161
|
+
catch (err) {
|
|
2162
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2163
|
+
return { error: `Get project failed: ${msg}` };
|
|
2164
|
+
}
|
|
2468
2165
|
}
|
|
2469
|
-
|
|
2470
|
-
const
|
|
2471
|
-
|
|
2166
|
+
case 'cell_detect_project': {
|
|
2167
|
+
const { ProjectRegistry } = require('../core/project-registry');
|
|
2168
|
+
const registry = new ProjectRegistry();
|
|
2169
|
+
try {
|
|
2170
|
+
const cwd = args.cwd || '';
|
|
2171
|
+
const detected = registry.detectProjectFromCwd(cwd);
|
|
2172
|
+
if (!detected) {
|
|
2173
|
+
return { detected: null, cwd, message: 'No matching project found for this path' };
|
|
2174
|
+
}
|
|
2175
|
+
const project = registry.getProject(detected);
|
|
2176
|
+
return {
|
|
2177
|
+
detected,
|
|
2178
|
+
cwd,
|
|
2179
|
+
project: project ? {
|
|
2180
|
+
name: project.name,
|
|
2181
|
+
stack: project.stack,
|
|
2182
|
+
fileCount: project.fileCount,
|
|
2183
|
+
lastScanAt: project.lastScanAt,
|
|
2184
|
+
} : null,
|
|
2185
|
+
message: `Detected project: ${detected}`,
|
|
2186
|
+
};
|
|
2187
|
+
}
|
|
2188
|
+
catch (err) {
|
|
2189
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2190
|
+
return { error: `Detect project failed: ${msg}` };
|
|
2191
|
+
}
|
|
2472
2192
|
}
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2193
|
+
case 'cell_register_project': {
|
|
2194
|
+
const { ProjectRegistry } = require('../core/project-registry');
|
|
2195
|
+
const registry = new ProjectRegistry();
|
|
2196
|
+
try {
|
|
2197
|
+
const id = registry.registerProject({
|
|
2198
|
+
name: args.name || '',
|
|
2199
|
+
path: args.path || '',
|
|
2200
|
+
stack: args.stack,
|
|
2201
|
+
fileCount: args.fileCount,
|
|
2202
|
+
});
|
|
2203
|
+
return { id, name: args.name, registered: true };
|
|
2204
|
+
}
|
|
2205
|
+
catch (err) {
|
|
2206
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2207
|
+
return { error: `Register project failed: ${msg}` };
|
|
2208
|
+
}
|
|
2482
2209
|
}
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2210
|
+
case 'cell_graph_files': {
|
|
2211
|
+
try {
|
|
2212
|
+
const project = args.project || '';
|
|
2213
|
+
const limit = args.limit || 20;
|
|
2214
|
+
const { getFileKnowledgeGraph } = require('../core/knowledge-graph-store');
|
|
2215
|
+
const graph = getFileKnowledgeGraph(project);
|
|
2216
|
+
return {
|
|
2217
|
+
stats: graph.stats,
|
|
2218
|
+
topRiskFiles: graph.files.slice(0, limit),
|
|
2219
|
+
entryPoints: graph.files.filter((f) => f.isEntryPoint).slice(0, 10),
|
|
2220
|
+
sampleDeps: graph.deps.slice(0, limit),
|
|
2221
|
+
};
|
|
2222
|
+
}
|
|
2223
|
+
catch (err) {
|
|
2224
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2225
|
+
return { error: `Graph files failed: ${msg}` };
|
|
2226
|
+
}
|
|
2486
2227
|
}
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2228
|
+
case 'cell_graph_blast_radius': {
|
|
2229
|
+
try {
|
|
2230
|
+
const project = args.project || '';
|
|
2231
|
+
const file = args.file || '';
|
|
2232
|
+
const { computeBlastRadius } = require('../core/knowledge-graph-store');
|
|
2233
|
+
const radius = computeBlastRadius(project, file);
|
|
2234
|
+
return radius;
|
|
2235
|
+
}
|
|
2236
|
+
catch (err) {
|
|
2237
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2238
|
+
return { error: `Blast radius failed: ${msg}` };
|
|
2239
|
+
}
|
|
2492
2240
|
}
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2241
|
+
case 'cell_graph_tech': {
|
|
2242
|
+
try {
|
|
2243
|
+
const project = args.project || '';
|
|
2244
|
+
const { getTechProficiency } = require('../core/knowledge-graph-store');
|
|
2245
|
+
const techs = getTechProficiency(project);
|
|
2246
|
+
const strong = techs.filter((t) => t.proficiencyScore >= 70);
|
|
2247
|
+
const learning = techs.filter((t) => t.proficiencyScore < 50);
|
|
2248
|
+
return {
|
|
2249
|
+
totalTechs: techs.length,
|
|
2250
|
+
strong,
|
|
2251
|
+
learning,
|
|
2252
|
+
all: techs,
|
|
2253
|
+
message: strong.length > 0
|
|
2254
|
+
? `Strong in: ${strong.map((t) => t.technology).slice(0, 3).join(', ')}`
|
|
2255
|
+
: 'No strong tech tracked yet',
|
|
2256
|
+
};
|
|
2257
|
+
}
|
|
2258
|
+
catch (err) {
|
|
2259
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2260
|
+
return { error: `Graph tech failed: ${msg}` };
|
|
2261
|
+
}
|
|
2496
2262
|
}
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2263
|
+
case 'cell_graph_stats': {
|
|
2264
|
+
try {
|
|
2265
|
+
const project = args.project || '';
|
|
2266
|
+
const { getPatternGraphStats, getFileKnowledgeGraph, getTechProficiency } = require('../core/knowledge-graph-store');
|
|
2267
|
+
const patternStats = getPatternGraphStats(project);
|
|
2268
|
+
const fileGraph = getFileKnowledgeGraph(project);
|
|
2269
|
+
const techs = getTechProficiency(project);
|
|
2270
|
+
return {
|
|
2271
|
+
patternGraph: patternStats,
|
|
2272
|
+
fileGraph: fileGraph.stats,
|
|
2273
|
+
techCount: techs.length,
|
|
2274
|
+
highRiskFiles: fileGraph.files.filter((f) => f.riskScore >= 50).length,
|
|
2275
|
+
};
|
|
2276
|
+
}
|
|
2277
|
+
catch (err) {
|
|
2278
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2279
|
+
return { error: `Graph stats failed: ${msg}` };
|
|
2280
|
+
}
|
|
2506
2281
|
}
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2282
|
+
case 'cell_team_silos': {
|
|
2283
|
+
try {
|
|
2284
|
+
const { detectKnowledgeSilos } = require('../team-collaboration');
|
|
2285
|
+
const silos = detectKnowledgeSilos();
|
|
2286
|
+
return {
|
|
2287
|
+
count: silos.length,
|
|
2288
|
+
high: silos.filter((s) => s.riskLevel === 'high').length,
|
|
2289
|
+
silos,
|
|
2290
|
+
message: silos.length > 0
|
|
2291
|
+
? `${silos.filter((s) => s.riskLevel === 'high').length} high-risk silos detected`
|
|
2292
|
+
: 'No knowledge silos detected',
|
|
2293
|
+
};
|
|
2294
|
+
}
|
|
2295
|
+
catch (err) {
|
|
2296
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2297
|
+
return { error: `Team silos failed: ${msg}` };
|
|
2298
|
+
}
|
|
2510
2299
|
}
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2300
|
+
case 'cell_team_bus_factor': {
|
|
2301
|
+
try {
|
|
2302
|
+
const { calculateBusFactor } = require('../team-collaboration');
|
|
2303
|
+
return calculateBusFactor();
|
|
2304
|
+
}
|
|
2305
|
+
catch (err) {
|
|
2306
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2307
|
+
return { error: `Bus factor failed: ${msg}` };
|
|
2308
|
+
}
|
|
2516
2309
|
}
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2310
|
+
case 'cell_team_health': {
|
|
2311
|
+
try {
|
|
2312
|
+
const { getTeamHealth } = require('../team-collaboration');
|
|
2313
|
+
return getTeamHealth(args.project || undefined);
|
|
2314
|
+
}
|
|
2315
|
+
catch (err) {
|
|
2316
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2317
|
+
return { error: `Team health failed: ${msg}` };
|
|
2318
|
+
}
|
|
2520
2319
|
}
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
insights,
|
|
2533
|
-
benchmarks,
|
|
2534
|
-
generatedAt: new Date().toISOString(),
|
|
2535
|
-
};
|
|
2320
|
+
case 'cell_team_onboard': {
|
|
2321
|
+
try {
|
|
2322
|
+
const { generateOnboardingDoc } = require('../team-collaboration');
|
|
2323
|
+
const teamName = args.teamName || 'Team';
|
|
2324
|
+
const project = args.project || undefined;
|
|
2325
|
+
return generateOnboardingDoc(teamName, project);
|
|
2326
|
+
}
|
|
2327
|
+
catch (err) {
|
|
2328
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2329
|
+
return { error: `Onboard failed: ${msg}` };
|
|
2330
|
+
}
|
|
2536
2331
|
}
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2332
|
+
case 'cell_team_retro': {
|
|
2333
|
+
try {
|
|
2334
|
+
const { generateSprintRetro } = require('../team-collaboration');
|
|
2335
|
+
const days = args.days || 14;
|
|
2336
|
+
const project = args.project || undefined;
|
|
2337
|
+
return generateSprintRetro(days, project);
|
|
2338
|
+
}
|
|
2339
|
+
catch (err) {
|
|
2340
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2341
|
+
return { error: `Retro failed: ${msg}` };
|
|
2342
|
+
}
|
|
2540
2343
|
}
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
wasRight: args.wasRight === true,
|
|
2551
|
-
confidence: args.confidence,
|
|
2552
|
-
});
|
|
2344
|
+
case 'cell_team_handoff': {
|
|
2345
|
+
try {
|
|
2346
|
+
const { generateHandoff } = require('../team-collaboration');
|
|
2347
|
+
return generateHandoff(args.from || '', args.to || '', args.project || '');
|
|
2348
|
+
}
|
|
2349
|
+
catch (err) {
|
|
2350
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2351
|
+
return { error: `Handoff failed: ${msg}` };
|
|
2352
|
+
}
|
|
2553
2353
|
}
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2354
|
+
case 'cell_team_knowledge_transfer': {
|
|
2355
|
+
try {
|
|
2356
|
+
const { suggestKnowledgeTransfer } = require('../team-collaboration');
|
|
2357
|
+
const suggestions = suggestKnowledgeTransfer();
|
|
2358
|
+
return {
|
|
2359
|
+
count: suggestions.length,
|
|
2360
|
+
suggestions,
|
|
2361
|
+
message: suggestions.length > 0
|
|
2362
|
+
? `${suggestions.length} transfer pairs suggested`
|
|
2363
|
+
: 'No urgent transfers needed',
|
|
2364
|
+
};
|
|
2365
|
+
}
|
|
2366
|
+
catch (err) {
|
|
2367
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2368
|
+
return { error: `Knowledge transfer failed: ${msg}` };
|
|
2369
|
+
}
|
|
2557
2370
|
}
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
? `Analyzed ${patterns.length} technology decision patterns`
|
|
2568
|
-
: 'Need more decisions (>= 2 per tech) to detect patterns',
|
|
2569
|
-
};
|
|
2371
|
+
case 'cell_team_style': {
|
|
2372
|
+
try {
|
|
2373
|
+
const { composeTeamStyle } = require('../team-collaboration');
|
|
2374
|
+
return composeTeamStyle(args.project || undefined);
|
|
2375
|
+
}
|
|
2376
|
+
catch (err) {
|
|
2377
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2378
|
+
return { error: `Team style failed: ${msg}` };
|
|
2379
|
+
}
|
|
2570
2380
|
}
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2381
|
+
case 'cell_team_dashboard': {
|
|
2382
|
+
try {
|
|
2383
|
+
const { detectKnowledgeSilos, calculateBusFactor, getTeamHealth, composeTeamStyle } = require('../team-collaboration');
|
|
2384
|
+
const project = args.project || undefined;
|
|
2385
|
+
const silos = detectKnowledgeSilos();
|
|
2386
|
+
const busFactor = calculateBusFactor();
|
|
2387
|
+
const health = getTeamHealth(project);
|
|
2388
|
+
const style = composeTeamStyle(project);
|
|
2389
|
+
return {
|
|
2390
|
+
silos: { count: silos.length, high: silos.filter((s) => s.riskLevel === 'high').length, top: silos.slice(0, 5) },
|
|
2391
|
+
busFactor,
|
|
2392
|
+
health,
|
|
2393
|
+
style,
|
|
2394
|
+
generatedAt: new Date().toISOString(),
|
|
2395
|
+
};
|
|
2396
|
+
}
|
|
2397
|
+
catch (err) {
|
|
2398
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2399
|
+
return { error: `Team dashboard failed: ${msg}` };
|
|
2400
|
+
}
|
|
2574
2401
|
}
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
message: mistakes.length > 0
|
|
2585
|
-
? `Found ${mistakes.length} repeated error patterns`
|
|
2586
|
-
: 'No repeated mistakes — clean track record',
|
|
2587
|
-
};
|
|
2402
|
+
case 'cell_community_stats': {
|
|
2403
|
+
try {
|
|
2404
|
+
const { getCommunityStats } = require('../core/community-store');
|
|
2405
|
+
return getCommunityStats();
|
|
2406
|
+
}
|
|
2407
|
+
catch (err) {
|
|
2408
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2409
|
+
return { error: `Community stats failed: ${msg}` };
|
|
2410
|
+
}
|
|
2588
2411
|
}
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2412
|
+
case 'cell_community_share': {
|
|
2413
|
+
try {
|
|
2414
|
+
const { shareCommunityPattern, validatePrivacy } = require('../core/community-store');
|
|
2415
|
+
const rule = args.rule || '';
|
|
2416
|
+
const validation = validatePrivacy(rule);
|
|
2417
|
+
if (!validation.safe) {
|
|
2418
|
+
return { shared: false, errors: validation.errors, warnings: validation.warnings };
|
|
2419
|
+
}
|
|
2420
|
+
const result = shareCommunityPattern({
|
|
2421
|
+
category: args.category || 'unknown',
|
|
2422
|
+
rule,
|
|
2423
|
+
language: args.language,
|
|
2424
|
+
framework: args.framework,
|
|
2425
|
+
successRate: args.successRate,
|
|
2426
|
+
});
|
|
2427
|
+
return { ...result, warnings: [...validation.warnings, ...result.warnings] };
|
|
2428
|
+
}
|
|
2429
|
+
catch (err) {
|
|
2430
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2431
|
+
return { error: `Community share failed: ${msg}` };
|
|
2432
|
+
}
|
|
2592
2433
|
}
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2434
|
+
case 'cell_community_patterns': {
|
|
2435
|
+
try {
|
|
2436
|
+
const { getCommunityPatterns } = require('../core/community-store');
|
|
2437
|
+
const patterns = getCommunityPatterns({
|
|
2438
|
+
category: args.category,
|
|
2439
|
+
language: args.language,
|
|
2440
|
+
minVotes: args.minVotes,
|
|
2441
|
+
limit: args.limit || 20,
|
|
2442
|
+
});
|
|
2443
|
+
return { count: patterns.length, patterns };
|
|
2444
|
+
}
|
|
2445
|
+
catch (err) {
|
|
2446
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2447
|
+
return { error: `Community patterns failed: ${msg}` };
|
|
2448
|
+
}
|
|
2598
2449
|
}
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2450
|
+
case 'cell_community_vote': {
|
|
2451
|
+
try {
|
|
2452
|
+
const { voteCommunityPattern } = require('../core/community-store');
|
|
2453
|
+
return voteCommunityPattern(args.patternId || '', args.upvote !== false);
|
|
2454
|
+
}
|
|
2455
|
+
catch (err) {
|
|
2456
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2457
|
+
return { error: `Community vote failed: ${msg}` };
|
|
2458
|
+
}
|
|
2602
2459
|
}
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
const result = logProductivitySignal({
|
|
2611
|
-
project,
|
|
2612
|
-
signalType: args.signalType,
|
|
2613
|
-
durationMinutes: args.durationMinutes,
|
|
2614
|
-
filesTouched: args.filesTouched || 0,
|
|
2615
|
-
contextSwitches: args.contextSwitches || 0,
|
|
2460
|
+
case 'cell_community_insights': {
|
|
2461
|
+
try {
|
|
2462
|
+
const { getCommunityInsights } = require('../core/community-store');
|
|
2463
|
+
const insights = getCommunityInsights({
|
|
2464
|
+
severity: args.severity,
|
|
2465
|
+
category: args.category,
|
|
2466
|
+
limit: args.limit || 20,
|
|
2616
2467
|
});
|
|
2617
|
-
return {
|
|
2468
|
+
return { count: insights.length, insights };
|
|
2469
|
+
}
|
|
2470
|
+
catch (err) {
|
|
2471
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2472
|
+
return { error: `Community insights failed: ${msg}` };
|
|
2618
2473
|
}
|
|
2619
|
-
return getProductivitySignals(project, 30);
|
|
2620
|
-
}
|
|
2621
|
-
catch (err) {
|
|
2622
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2623
|
-
return { error: `Productivity failed: ${msg}` };
|
|
2624
2474
|
}
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2475
|
+
case 'cell_community_benchmarks': {
|
|
2476
|
+
try {
|
|
2477
|
+
const { getBenchmarks } = require('../core/community-store');
|
|
2478
|
+
const benchmarks = getBenchmarks({
|
|
2479
|
+
category: args.category,
|
|
2480
|
+
limit: args.limit || 50,
|
|
2481
|
+
});
|
|
2482
|
+
return { count: benchmarks.length, benchmarks };
|
|
2483
|
+
}
|
|
2484
|
+
catch (err) {
|
|
2485
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2486
|
+
return { error: `Community benchmarks failed: ${msg}` };
|
|
2487
|
+
}
|
|
2630
2488
|
}
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2489
|
+
case 'cell_community_trends': {
|
|
2490
|
+
try {
|
|
2491
|
+
const { getTechEvolution } = require('../core/community-store');
|
|
2492
|
+
return getTechEvolution();
|
|
2493
|
+
}
|
|
2494
|
+
catch (err) {
|
|
2495
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2496
|
+
return { error: `Community trends failed: ${msg}` };
|
|
2497
|
+
}
|
|
2634
2498
|
}
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2499
|
+
case 'cell_community_failures': {
|
|
2500
|
+
try {
|
|
2501
|
+
const { getFailurePatterns } = require('../core/community-store');
|
|
2502
|
+
const failures = getFailurePatterns({
|
|
2503
|
+
language: args.language,
|
|
2504
|
+
limit: args.limit || 10,
|
|
2505
|
+
});
|
|
2506
|
+
return { count: failures.length, failures };
|
|
2507
|
+
}
|
|
2508
|
+
catch (err) {
|
|
2509
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2510
|
+
return { error: `Community failures failed: ${msg}` };
|
|
2511
|
+
}
|
|
2640
2512
|
}
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2513
|
+
case 'cell_community_validate': {
|
|
2514
|
+
try {
|
|
2515
|
+
const { validatePrivacy } = require('../core/community-store');
|
|
2516
|
+
return validatePrivacy(args.rule || '');
|
|
2517
|
+
}
|
|
2518
|
+
catch (err) {
|
|
2519
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2520
|
+
return { error: `Community validate failed: ${msg}` };
|
|
2521
|
+
}
|
|
2644
2522
|
}
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2523
|
+
case 'cell_community_dashboard': {
|
|
2524
|
+
try {
|
|
2525
|
+
const { getCommunityStats, getTechEvolution, getCommunityInsights, getBenchmarks } = require('../core/community-store');
|
|
2526
|
+
const stats = getCommunityStats();
|
|
2527
|
+
const trends = getTechEvolution();
|
|
2528
|
+
const insights = getCommunityInsights({ severity: 'critical', limit: 5 });
|
|
2529
|
+
const benchmarks = getBenchmarks({ limit: 5 });
|
|
2530
|
+
return {
|
|
2531
|
+
stats,
|
|
2532
|
+
trends: trends.slice(0, 10),
|
|
2533
|
+
insights,
|
|
2534
|
+
benchmarks,
|
|
2535
|
+
generatedAt: new Date().toISOString(),
|
|
2536
|
+
};
|
|
2537
|
+
}
|
|
2538
|
+
catch (err) {
|
|
2539
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2540
|
+
return { error: `Community dashboard failed: ${msg}` };
|
|
2541
|
+
}
|
|
2650
2542
|
}
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2543
|
+
case 'cell_usage_decision_log': {
|
|
2544
|
+
try {
|
|
2545
|
+
const { logDecisionOutcome } = require('../core/usage-intelligence-store');
|
|
2546
|
+
return logDecisionOutcome({
|
|
2547
|
+
project: args.project || 'unknown',
|
|
2548
|
+
technology: args.technology || '',
|
|
2549
|
+
reason: args.reason || '',
|
|
2550
|
+
outcome: args.outcome || '',
|
|
2551
|
+
wasRight: args.wasRight === true,
|
|
2552
|
+
confidence: args.confidence,
|
|
2553
|
+
});
|
|
2554
|
+
}
|
|
2555
|
+
catch (err) {
|
|
2556
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2557
|
+
return { error: `Decision log failed: ${msg}` };
|
|
2558
|
+
}
|
|
2654
2559
|
}
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2560
|
+
case 'cell_usage_decision_patterns': {
|
|
2561
|
+
try {
|
|
2562
|
+
const { getDecisionPatterns } = require('../core/usage-intelligence-store');
|
|
2563
|
+
const patterns = getDecisionPatterns(args.project || 'unknown');
|
|
2564
|
+
return {
|
|
2565
|
+
count: patterns.length,
|
|
2566
|
+
patterns,
|
|
2567
|
+
message: patterns.length > 0
|
|
2568
|
+
? `Analyzed ${patterns.length} technology decision patterns`
|
|
2569
|
+
: 'Need more decisions (>= 2 per tech) to detect patterns',
|
|
2570
|
+
};
|
|
2571
|
+
}
|
|
2572
|
+
catch (err) {
|
|
2573
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2574
|
+
return { error: `Decision patterns failed: ${msg}` };
|
|
2575
|
+
}
|
|
2660
2576
|
}
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2577
|
+
case 'cell_usage_repeat_mistakes': {
|
|
2578
|
+
try {
|
|
2579
|
+
const { detectRepeatMistakes } = require('../core/usage-intelligence-store');
|
|
2580
|
+
const mistakes = detectRepeatMistakes(args.project || 'unknown');
|
|
2581
|
+
return {
|
|
2582
|
+
count: mistakes.length,
|
|
2583
|
+
critical: mistakes.filter((m) => m.severity === 'critical').length,
|
|
2584
|
+
mistakes: mistakes.slice(0, 20),
|
|
2585
|
+
message: mistakes.length > 0
|
|
2586
|
+
? `Found ${mistakes.length} repeated error patterns`
|
|
2587
|
+
: 'No repeated mistakes — clean track record',
|
|
2588
|
+
};
|
|
2589
|
+
}
|
|
2590
|
+
catch (err) {
|
|
2591
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2592
|
+
return { error: `Repeat mistakes failed: ${msg}` };
|
|
2593
|
+
}
|
|
2664
2594
|
}
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2595
|
+
case 'cell_usage_ai_stats': {
|
|
2596
|
+
try {
|
|
2597
|
+
const { getAIInteractionStats } = require('../core/usage-intelligence-store');
|
|
2598
|
+
return getAIInteractionStats(args.project || 'unknown');
|
|
2599
|
+
}
|
|
2600
|
+
catch (err) {
|
|
2601
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2602
|
+
return { error: `AI stats failed: ${msg}` };
|
|
2603
|
+
}
|
|
2670
2604
|
}
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2605
|
+
case 'cell_usage_productivity': {
|
|
2606
|
+
try {
|
|
2607
|
+
const { logProductivitySignal, getProductivitySignals } = require('../core/usage-intelligence-store');
|
|
2608
|
+
const project = args.project || 'unknown';
|
|
2609
|
+
// If signalType + duration provided, log; otherwise just read
|
|
2610
|
+
if (args.signalType && args.durationMinutes !== undefined) {
|
|
2611
|
+
const result = logProductivitySignal({
|
|
2612
|
+
project,
|
|
2613
|
+
signalType: args.signalType,
|
|
2614
|
+
durationMinutes: args.durationMinutes,
|
|
2615
|
+
filesTouched: args.filesTouched || 0,
|
|
2616
|
+
contextSwitches: args.contextSwitches || 0,
|
|
2617
|
+
});
|
|
2618
|
+
return { logged: true, ...result };
|
|
2619
|
+
}
|
|
2620
|
+
return getProductivitySignals(project, 30);
|
|
2621
|
+
}
|
|
2622
|
+
catch (err) {
|
|
2623
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2624
|
+
return { error: `Productivity failed: ${msg}` };
|
|
2625
|
+
}
|
|
2674
2626
|
}
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
const isLive = status.active;
|
|
2684
|
-
return { ...status, message: isLive ? 'Live' : 'Stopped' };
|
|
2627
|
+
case 'cell_usage_skills': {
|
|
2628
|
+
try {
|
|
2629
|
+
const { getSkillProgression } = require('../core/usage-intelligence-store');
|
|
2630
|
+
return getSkillProgression(args.project || 'unknown');
|
|
2631
|
+
}
|
|
2632
|
+
catch (err) {
|
|
2633
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2634
|
+
return { error: `Skill progression failed: ${msg}` };
|
|
2685
2635
|
}
|
|
2686
|
-
return { active: getActiveWatchers() };
|
|
2687
2636
|
}
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2637
|
+
case 'cell_usage_burnout': {
|
|
2638
|
+
try {
|
|
2639
|
+
const { getBurnoutSignals } = require('../core/usage-intelligence-store');
|
|
2640
|
+
return getBurnoutSignals(args.project || 'unknown');
|
|
2641
|
+
}
|
|
2642
|
+
catch (err) {
|
|
2643
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2644
|
+
return { error: `Burnout check failed: ${msg}` };
|
|
2645
|
+
}
|
|
2691
2646
|
}
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2647
|
+
case 'cell_usage_dashboard': {
|
|
2648
|
+
try {
|
|
2649
|
+
const { getUsageDashboard } = require('../core/usage-intelligence-store');
|
|
2650
|
+
return getUsageDashboard(args.project || 'unknown');
|
|
2651
|
+
}
|
|
2652
|
+
catch (err) {
|
|
2653
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2654
|
+
return { error: `Usage dashboard failed: ${msg}` };
|
|
2655
|
+
}
|
|
2697
2656
|
}
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2657
|
+
case 'cell_watch_start': {
|
|
2658
|
+
try {
|
|
2659
|
+
const { startWatcher } = require('../core/live-watcher');
|
|
2660
|
+
return startWatcher(args.project || 'unknown', args.dir || process.cwd());
|
|
2661
|
+
}
|
|
2662
|
+
catch (err) {
|
|
2663
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2664
|
+
return { error: `Watch start failed: ${msg}` };
|
|
2665
|
+
}
|
|
2701
2666
|
}
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2667
|
+
case 'cell_watch_stop': {
|
|
2668
|
+
try {
|
|
2669
|
+
const { stopWatcher } = require('../core/live-watcher');
|
|
2670
|
+
return stopWatcher(args.project || 'unknown');
|
|
2671
|
+
}
|
|
2672
|
+
catch (err) {
|
|
2673
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2674
|
+
return { error: `Watch stop failed: ${msg}` };
|
|
2675
|
+
}
|
|
2707
2676
|
}
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2677
|
+
case 'cell_watch_status': {
|
|
2678
|
+
try {
|
|
2679
|
+
const { getWatcherStatus, getActiveWatchers } = require('../core/live-watcher');
|
|
2680
|
+
if (args.project) {
|
|
2681
|
+
const status = getWatcherStatus(args.project);
|
|
2682
|
+
if (!status)
|
|
2683
|
+
return { project: args.project, active: false, message: 'No watcher found' };
|
|
2684
|
+
const isLive = status.active;
|
|
2685
|
+
return { ...status, message: isLive ? 'Live' : 'Stopped' };
|
|
2686
|
+
}
|
|
2687
|
+
return { active: getActiveWatchers() };
|
|
2688
|
+
}
|
|
2689
|
+
catch (err) {
|
|
2690
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2691
|
+
return { error: `Watch status failed: ${msg}` };
|
|
2692
|
+
}
|
|
2711
2693
|
}
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2694
|
+
case 'cell_watch_events': {
|
|
2695
|
+
try {
|
|
2696
|
+
const { getLiveEvents } = require('../core/live-watcher');
|
|
2697
|
+
return { events: getLiveEvents(args.project || 'unknown', args.limit || 50, args.eventType) };
|
|
2698
|
+
}
|
|
2699
|
+
catch (err) {
|
|
2700
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2701
|
+
return { error: `Watch events failed: ${msg}` };
|
|
2702
|
+
}
|
|
2717
2703
|
}
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2704
|
+
case 'cell_watch_refresh': {
|
|
2705
|
+
try {
|
|
2706
|
+
const { performAutoRefresh } = require('../core/live-watcher');
|
|
2707
|
+
return performAutoRefresh(args.project || 'unknown', args.force === true);
|
|
2708
|
+
}
|
|
2709
|
+
catch (err) {
|
|
2710
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2711
|
+
return { error: `Auto-refresh failed: ${msg}` };
|
|
2712
|
+
}
|
|
2721
2713
|
}
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2714
|
+
case 'cell_watch_check': {
|
|
2715
|
+
try {
|
|
2716
|
+
const { checkIfNeedsRefresh } = require('../core/live-watcher');
|
|
2717
|
+
return checkIfNeedsRefresh(args.project || 'unknown');
|
|
2718
|
+
}
|
|
2719
|
+
catch (err) {
|
|
2720
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2721
|
+
return { error: `Refresh check failed: ${msg}` };
|
|
2722
|
+
}
|
|
2730
2723
|
}
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2724
|
+
case 'cell_blindspots_scan': {
|
|
2725
|
+
try {
|
|
2726
|
+
const { scanDirectoryForBlindSpots } = require('../core/enhanced-blind-spots');
|
|
2727
|
+
const dir = args.dir || process.cwd();
|
|
2728
|
+
const max = args.maxFiles || 200;
|
|
2729
|
+
const spots = scanDirectoryForBlindSpots(dir, max);
|
|
2730
|
+
return { directory: dir, scanned: max, count: spots.length, blindSpots: spots };
|
|
2731
|
+
}
|
|
2732
|
+
catch (err) {
|
|
2733
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2734
|
+
return { error: `Blind spot scan failed: ${msg}` };
|
|
2735
|
+
}
|
|
2734
2736
|
}
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
}
|
|
2737
|
+
case 'cell_blindspots_report': {
|
|
2738
|
+
try {
|
|
2739
|
+
const { scanDirectoryForBlindSpots, formatBlindSpotReport, summarizeBlindSpots } = require('../core/enhanced-blind-spots');
|
|
2740
|
+
const dir = args.dir || process.cwd();
|
|
2741
|
+
const max = args.maxFiles || 200;
|
|
2742
|
+
const spots = scanDirectoryForBlindSpots(dir, max);
|
|
2743
|
+
return {
|
|
2744
|
+
directory: dir,
|
|
2745
|
+
summary: summarizeBlindSpots(spots),
|
|
2746
|
+
report: formatBlindSpotReport(spots),
|
|
2747
|
+
blindSpots: spots,
|
|
2748
|
+
};
|
|
2749
|
+
}
|
|
2750
|
+
catch (err) {
|
|
2751
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2752
|
+
return { error: `Blind spot report failed: ${msg}` };
|
|
2753
|
+
}
|
|
2748
2754
|
}
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2755
|
+
case 'cell_blindspots_summary': {
|
|
2756
|
+
try {
|
|
2757
|
+
const { getCategoryCounts } = require('../core/enhanced-blind-spots');
|
|
2758
|
+
const dir = args.dir || process.cwd();
|
|
2759
|
+
return { directory: dir, byCategory: getCategoryCounts(dir) };
|
|
2760
|
+
}
|
|
2761
|
+
catch (err) {
|
|
2762
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2763
|
+
return { error: `Blind spot summary failed: ${msg}` };
|
|
2764
|
+
}
|
|
2752
2765
|
}
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2766
|
+
case 'cell_predict': {
|
|
2767
|
+
const { generatePredictions } = require('../predictive-engine');
|
|
2768
|
+
return generatePredictions(args.project);
|
|
2769
|
+
}
|
|
2770
|
+
case 'cell_model_track': {
|
|
2771
|
+
const { recordModelInteraction } = require('../cross-model-engine');
|
|
2772
|
+
recordModelInteraction({
|
|
2773
|
+
modelName: args.modelName,
|
|
2774
|
+
taskType: args.taskType,
|
|
2775
|
+
accepted: args.accepted,
|
|
2776
|
+
responseTimeMs: args.responseTimeMs,
|
|
2777
|
+
project: args.project,
|
|
2778
|
+
suggestion: args.suggestion,
|
|
2779
|
+
});
|
|
2780
|
+
return { recorded: true };
|
|
2759
2781
|
}
|
|
2760
|
-
|
|
2761
|
-
const
|
|
2762
|
-
return {
|
|
2782
|
+
case 'cell_model_recommend': {
|
|
2783
|
+
const { getModelRecommendations } = require('../cross-model-engine');
|
|
2784
|
+
return { recommendations: getModelRecommendations() };
|
|
2763
2785
|
}
|
|
2786
|
+
default:
|
|
2787
|
+
return { error: `unknown tool: ${name}` };
|
|
2764
2788
|
}
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
recordModelInteraction({
|
|
2772
|
-
modelName: args.modelName,
|
|
2773
|
-
taskType: args.taskType,
|
|
2774
|
-
accepted: args.accepted,
|
|
2775
|
-
responseTimeMs: args.responseTimeMs,
|
|
2776
|
-
project: args.project,
|
|
2777
|
-
suggestion: args.suggestion,
|
|
2778
|
-
});
|
|
2779
|
-
return { recorded: true };
|
|
2780
|
-
}
|
|
2781
|
-
case 'cell_model_recommend': {
|
|
2782
|
-
const { getModelRecommendations } = require('../cross-model-engine');
|
|
2783
|
-
return { recommendations: getModelRecommendations() };
|
|
2784
|
-
}
|
|
2785
|
-
default:
|
|
2786
|
-
return { error: `unknown tool: ${name}` };
|
|
2789
|
+
}
|
|
2790
|
+
catch (err) {
|
|
2791
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2792
|
+
const stack = err instanceof Error ? err.stack : String(err);
|
|
2793
|
+
console.error(`[mcp] tool ${name} threw:`, msg, '\n', stack);
|
|
2794
|
+
return { error: `Tool ${name} failed: ${msg}` };
|
|
2787
2795
|
}
|
|
2788
2796
|
}
|
|
2789
2797
|
app.post('/mcp', async (req, res) => {
|
|
2790
|
-
//
|
|
2791
|
-
const { checkRateLimit, getClientId, validateToolArgs, securityHeaders } = require('../core/security');
|
|
2792
|
-
for (const [k, v] of Object.entries(securityHeaders()))
|
|
2793
|
-
res.setHeader(k, v);
|
|
2794
|
-
const clientId = getClientId(req);
|
|
2795
|
-
const rl = checkRateLimit(clientId);
|
|
2796
|
-
res.setHeader('X-RateLimit-Remaining', String(rl.remaining));
|
|
2797
|
-
if (!rl.allowed) {
|
|
2798
|
-
res.status(429).json({ jsonrpc: '2.0', id: null, error: { code: -32000, message: `Rate limit exceeded. Retry in ${Math.ceil(rl.resetIn / 1000)}s` } });
|
|
2799
|
-
return;
|
|
2800
|
-
}
|
|
2801
|
-
const rpc = req.body;
|
|
2802
|
-
const { method, params, id } = rpc;
|
|
2798
|
+
// Wrap entire handler in try/catch so uncaught errors don't 500 silently
|
|
2803
2799
|
try {
|
|
2804
|
-
//
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2800
|
+
// ─── Security: rate limit + input validation ─────────────────────────
|
|
2801
|
+
const { checkRateLimit, getClientId, validateToolArgs, securityHeaders } = require('../core/security');
|
|
2802
|
+
for (const [k, v] of Object.entries(securityHeaders()))
|
|
2803
|
+
res.setHeader(k, v);
|
|
2804
|
+
const clientId = getClientId(req);
|
|
2805
|
+
const rl = checkRateLimit(clientId);
|
|
2806
|
+
res.setHeader('X-RateLimit-Remaining', String(rl.remaining));
|
|
2807
|
+
if (!rl.allowed) {
|
|
2808
|
+
res.status(429).json({ jsonrpc: '2.0', id: null, error: { code: -32000, message: `Rate limit exceeded. Retry in ${Math.ceil(rl.resetIn / 1000)}s` } });
|
|
2809
|
+
return;
|
|
2811
2810
|
}
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2811
|
+
const rpc = req.body || {};
|
|
2812
|
+
const { method, params, id } = rpc;
|
|
2813
|
+
try {
|
|
2814
|
+
// Validate tool args before execution
|
|
2815
|
+
if (method === 'tools/call') {
|
|
2816
|
+
const validation = validateToolArgs(params?.name || '', params?.arguments);
|
|
2817
|
+
if (!validation.valid) {
|
|
2818
|
+
res.status(400).json({ jsonrpc: '2.0', id, error: { code: -32602, message: `Invalid arguments: ${validation.reason}` } });
|
|
2819
|
+
return;
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
let result;
|
|
2823
|
+
switch (method) {
|
|
2824
|
+
case 'initialize':
|
|
2825
|
+
result = { protocolVersion: params?.protocolVersion || '2024-11-05', capabilities: { tools: { listChanged: false } }, serverInfo: { name: 'fivo-cell', version: '3.0.0' } };
|
|
2826
|
+
break;
|
|
2827
|
+
case 'notifications/initialized':
|
|
2828
|
+
res.status(204).end();
|
|
2829
|
+
return;
|
|
2830
|
+
case 'ping':
|
|
2831
|
+
result = {};
|
|
2832
|
+
break;
|
|
2833
|
+
case 'tools/list':
|
|
2834
|
+
result = { tools: MCP_TOOLS };
|
|
2835
|
+
break;
|
|
2836
|
+
case 'tools/call':
|
|
2837
|
+
result = await handleMCPToolCall(params?.name || '', params?.arguments || {});
|
|
2838
|
+
break;
|
|
2839
|
+
default:
|
|
2840
|
+
res.status(200).json({ jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}` } });
|
|
2841
|
+
return;
|
|
2842
|
+
}
|
|
2843
|
+
res.status(200).json({ jsonrpc: '2.0', id, result });
|
|
2844
|
+
}
|
|
2845
|
+
catch (err) {
|
|
2846
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2847
|
+
const stack = err instanceof Error ? err.stack : String(err);
|
|
2848
|
+
console.error('[mcp] handler error:', message, '\n', stack);
|
|
2849
|
+
try {
|
|
2850
|
+
res.status(200).json({ jsonrpc: '2.0', id, error: { code: -1, message } });
|
|
2851
|
+
}
|
|
2852
|
+
catch {
|
|
2853
|
+
try {
|
|
2854
|
+
res.status(500).json({ error: 'internal server error' });
|
|
2855
|
+
}
|
|
2856
|
+
catch { /* noop */ }
|
|
2857
|
+
}
|
|
2832
2858
|
}
|
|
2833
|
-
res.status(200).json({ jsonrpc: '2.0', id, result });
|
|
2834
2859
|
}
|
|
2835
2860
|
catch (err) {
|
|
2836
2861
|
const message = err instanceof Error ? err.message : String(err);
|
|
2837
|
-
|
|
2862
|
+
const stack = err instanceof Error ? err.stack : String(err);
|
|
2863
|
+
process.stderr.write(`[mcp] OUTER handler error: ${message}\n${stack}\n`);
|
|
2864
|
+
try {
|
|
2865
|
+
res.status(500).json({ error: 'internal server error' });
|
|
2866
|
+
}
|
|
2867
|
+
catch { /* noop */ }
|
|
2838
2868
|
}
|
|
2839
2869
|
});
|
|
2840
2870
|
app.use((_req, res) => { res.status(404).json({ error: 'not found' }); });
|
|
2841
2871
|
app.use((err, _req, res, _next) => {
|
|
2842
|
-
console.error('Daemon error:', err.message);
|
|
2843
|
-
|
|
2872
|
+
console.error('Daemon error:', err.message, '\n', err.stack);
|
|
2873
|
+
try {
|
|
2874
|
+
res.status(500).json({ error: 'internal server error' });
|
|
2875
|
+
}
|
|
2876
|
+
catch { /* noop */ }
|
|
2844
2877
|
});
|
|
2845
2878
|
// ─── Self-Healing ──────────────────────────────────────────────────────
|
|
2846
2879
|
process.on('uncaughtException', (err) => {
|