@codebakers/cli 2.3.0 โ 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/mcp/server.js +230 -0
- package/package.json +1 -1
- package/src/mcp/server.ts +251 -0
package/dist/mcp/server.js
CHANGED
|
@@ -502,6 +502,76 @@ class CodeBakersServer {
|
|
|
502
502
|
properties: {},
|
|
503
503
|
},
|
|
504
504
|
},
|
|
505
|
+
{
|
|
506
|
+
name: 'run_tests',
|
|
507
|
+
description: 'Run the project test suite (npm test or configured test command). Use after completing a feature to verify everything works. Returns test results with pass/fail status.',
|
|
508
|
+
inputSchema: {
|
|
509
|
+
type: 'object',
|
|
510
|
+
properties: {
|
|
511
|
+
filter: {
|
|
512
|
+
type: 'string',
|
|
513
|
+
description: 'Optional filter to run specific tests (passed to test runner)',
|
|
514
|
+
},
|
|
515
|
+
watch: {
|
|
516
|
+
type: 'boolean',
|
|
517
|
+
description: 'Run in watch mode (default: false)',
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
},
|
|
521
|
+
},
|
|
522
|
+
{
|
|
523
|
+
name: 'report_pattern_gap',
|
|
524
|
+
description: 'Report when a user request cannot be fully handled by existing patterns. This helps improve CodeBakers by tracking what patterns are missing. The AI should automatically call this when it encounters something outside pattern coverage.',
|
|
525
|
+
inputSchema: {
|
|
526
|
+
type: 'object',
|
|
527
|
+
properties: {
|
|
528
|
+
category: {
|
|
529
|
+
type: 'string',
|
|
530
|
+
description: 'Category of the gap (e.g., "third-party-apis", "mobile", "blockchain", "iot")',
|
|
531
|
+
},
|
|
532
|
+
request: {
|
|
533
|
+
type: 'string',
|
|
534
|
+
description: 'What the user asked for',
|
|
535
|
+
},
|
|
536
|
+
context: {
|
|
537
|
+
type: 'string',
|
|
538
|
+
description: 'Additional context about what was needed',
|
|
539
|
+
},
|
|
540
|
+
handledWith: {
|
|
541
|
+
type: 'string',
|
|
542
|
+
description: 'Which existing patterns were used as fallback',
|
|
543
|
+
},
|
|
544
|
+
wasSuccessful: {
|
|
545
|
+
type: 'boolean',
|
|
546
|
+
description: 'Whether the request was handled successfully despite the gap',
|
|
547
|
+
},
|
|
548
|
+
},
|
|
549
|
+
required: ['category', 'request'],
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
name: 'track_analytics',
|
|
554
|
+
description: 'Track CLI usage analytics for improving smart triggers and recommendations. Called automatically by the system for key events.',
|
|
555
|
+
inputSchema: {
|
|
556
|
+
type: 'object',
|
|
557
|
+
properties: {
|
|
558
|
+
eventType: {
|
|
559
|
+
type: 'string',
|
|
560
|
+
enum: ['trigger_fired', 'trigger_accepted', 'trigger_dismissed', 'topic_learned', 'command_used', 'pattern_fetched', 'build_started', 'build_completed', 'feature_added', 'audit_run', 'design_cloned'],
|
|
561
|
+
description: 'Type of event to track',
|
|
562
|
+
},
|
|
563
|
+
eventData: {
|
|
564
|
+
type: 'object',
|
|
565
|
+
description: 'Additional data specific to the event',
|
|
566
|
+
},
|
|
567
|
+
projectHash: {
|
|
568
|
+
type: 'string',
|
|
569
|
+
description: 'Hash of project path for grouping analytics',
|
|
570
|
+
},
|
|
571
|
+
},
|
|
572
|
+
required: ['eventType'],
|
|
573
|
+
},
|
|
574
|
+
},
|
|
505
575
|
],
|
|
506
576
|
}));
|
|
507
577
|
// Handle tool calls
|
|
@@ -543,6 +613,12 @@ class CodeBakersServer {
|
|
|
543
613
|
return this.handleUpgrade(args);
|
|
544
614
|
case 'project_status':
|
|
545
615
|
return this.handleProjectStatus();
|
|
616
|
+
case 'run_tests':
|
|
617
|
+
return this.handleRunTests(args);
|
|
618
|
+
case 'report_pattern_gap':
|
|
619
|
+
return this.handleReportPatternGap(args);
|
|
620
|
+
case 'track_analytics':
|
|
621
|
+
return this.handleTrackAnalytics(args);
|
|
546
622
|
default:
|
|
547
623
|
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
548
624
|
}
|
|
@@ -1676,6 +1752,160 @@ Just describe what you want to build! I'll automatically:
|
|
|
1676
1752
|
}],
|
|
1677
1753
|
};
|
|
1678
1754
|
}
|
|
1755
|
+
handleRunTests(args) {
|
|
1756
|
+
const { filter, watch = false } = args;
|
|
1757
|
+
const cwd = process.cwd();
|
|
1758
|
+
// Detect test runner from package.json
|
|
1759
|
+
let testCommand = 'npm test';
|
|
1760
|
+
try {
|
|
1761
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
1762
|
+
if (fs.existsSync(pkgPath)) {
|
|
1763
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
1764
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1765
|
+
if (deps['@playwright/test']) {
|
|
1766
|
+
testCommand = 'npx playwright test';
|
|
1767
|
+
}
|
|
1768
|
+
else if (deps['vitest']) {
|
|
1769
|
+
testCommand = 'npx vitest run';
|
|
1770
|
+
}
|
|
1771
|
+
else if (deps['jest']) {
|
|
1772
|
+
testCommand = 'npx jest';
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
catch {
|
|
1777
|
+
// Use default
|
|
1778
|
+
}
|
|
1779
|
+
// Add filter if provided
|
|
1780
|
+
if (filter) {
|
|
1781
|
+
testCommand += ` ${filter}`;
|
|
1782
|
+
}
|
|
1783
|
+
// Add watch mode
|
|
1784
|
+
if (watch) {
|
|
1785
|
+
testCommand = testCommand.replace(' run', ''); // Remove 'run' for vitest watch
|
|
1786
|
+
if (testCommand.includes('vitest')) {
|
|
1787
|
+
testCommand = testCommand.replace('vitest run', 'vitest');
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
let response = `# ๐งช Running Tests\n\n`;
|
|
1791
|
+
response += `**Command:** \`${testCommand}\`\n\n`;
|
|
1792
|
+
try {
|
|
1793
|
+
const output = (0, child_process_1.execSync)(testCommand, {
|
|
1794
|
+
cwd,
|
|
1795
|
+
encoding: 'utf-8',
|
|
1796
|
+
timeout: 120000, // 2 minute timeout
|
|
1797
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1798
|
+
});
|
|
1799
|
+
response += `## โ
Tests Passed\n\n`;
|
|
1800
|
+
response += '```\n' + output.slice(-2000) + '\n```\n';
|
|
1801
|
+
}
|
|
1802
|
+
catch (error) {
|
|
1803
|
+
const execError = error;
|
|
1804
|
+
response += `## โ Tests Failed\n\n`;
|
|
1805
|
+
if (execError.stdout) {
|
|
1806
|
+
response += '### Output\n```\n' + execError.stdout.slice(-2000) + '\n```\n\n';
|
|
1807
|
+
}
|
|
1808
|
+
if (execError.stderr) {
|
|
1809
|
+
response += '### Errors\n```\n' + execError.stderr.slice(-1000) + '\n```\n\n';
|
|
1810
|
+
}
|
|
1811
|
+
response += `**Exit Code:** ${execError.status || 1}\n\n`;
|
|
1812
|
+
response += `---\n\n*Fix the failing tests and run again.*`;
|
|
1813
|
+
}
|
|
1814
|
+
return {
|
|
1815
|
+
content: [{
|
|
1816
|
+
type: 'text',
|
|
1817
|
+
text: response,
|
|
1818
|
+
}],
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
async handleReportPatternGap(args) {
|
|
1822
|
+
const { category, request, context, handledWith, wasSuccessful = true } = args;
|
|
1823
|
+
try {
|
|
1824
|
+
const response = await fetch(`${this.apiUrl}/api/pattern-gaps`, {
|
|
1825
|
+
method: 'POST',
|
|
1826
|
+
headers: {
|
|
1827
|
+
'Content-Type': 'application/json',
|
|
1828
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
1829
|
+
},
|
|
1830
|
+
body: JSON.stringify({
|
|
1831
|
+
category,
|
|
1832
|
+
request,
|
|
1833
|
+
context,
|
|
1834
|
+
handledWith,
|
|
1835
|
+
wasSuccessful,
|
|
1836
|
+
}),
|
|
1837
|
+
});
|
|
1838
|
+
if (!response.ok) {
|
|
1839
|
+
const error = await response.json().catch(() => ({}));
|
|
1840
|
+
throw new Error(error.error || 'Failed to report pattern gap');
|
|
1841
|
+
}
|
|
1842
|
+
const result = await response.json();
|
|
1843
|
+
if (result.deduplicated) {
|
|
1844
|
+
return {
|
|
1845
|
+
content: [{
|
|
1846
|
+
type: 'text',
|
|
1847
|
+
text: `๐ Pattern gap already reported recently (category: ${category}). No duplicate created.`,
|
|
1848
|
+
}],
|
|
1849
|
+
};
|
|
1850
|
+
}
|
|
1851
|
+
return {
|
|
1852
|
+
content: [{
|
|
1853
|
+
type: 'text',
|
|
1854
|
+
text: `โ
Pattern gap reported successfully.\n\n**Category:** ${category}\n**Request:** ${request}\n\nThis helps improve CodeBakers for everyone!`,
|
|
1855
|
+
}],
|
|
1856
|
+
};
|
|
1857
|
+
}
|
|
1858
|
+
catch (error) {
|
|
1859
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
1860
|
+
return {
|
|
1861
|
+
content: [{
|
|
1862
|
+
type: 'text',
|
|
1863
|
+
text: `โ ๏ธ Could not report pattern gap: ${message}\n\n(This doesn't affect your current work)`,
|
|
1864
|
+
}],
|
|
1865
|
+
};
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1868
|
+
async handleTrackAnalytics(args) {
|
|
1869
|
+
const { eventType, eventData, projectHash } = args;
|
|
1870
|
+
try {
|
|
1871
|
+
const response = await fetch(`${this.apiUrl}/api/cli/analytics`, {
|
|
1872
|
+
method: 'POST',
|
|
1873
|
+
headers: {
|
|
1874
|
+
'Content-Type': 'application/json',
|
|
1875
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
1876
|
+
},
|
|
1877
|
+
body: JSON.stringify({
|
|
1878
|
+
eventType,
|
|
1879
|
+
eventData,
|
|
1880
|
+
projectHash,
|
|
1881
|
+
}),
|
|
1882
|
+
});
|
|
1883
|
+
if (!response.ok) {
|
|
1884
|
+
// Silently fail - analytics shouldn't interrupt user workflow
|
|
1885
|
+
return {
|
|
1886
|
+
content: [{
|
|
1887
|
+
type: 'text',
|
|
1888
|
+
text: `๐ Analytics tracked: ${eventType}`,
|
|
1889
|
+
}],
|
|
1890
|
+
};
|
|
1891
|
+
}
|
|
1892
|
+
return {
|
|
1893
|
+
content: [{
|
|
1894
|
+
type: 'text',
|
|
1895
|
+
text: `๐ Analytics tracked: ${eventType}`,
|
|
1896
|
+
}],
|
|
1897
|
+
};
|
|
1898
|
+
}
|
|
1899
|
+
catch {
|
|
1900
|
+
// Silently fail
|
|
1901
|
+
return {
|
|
1902
|
+
content: [{
|
|
1903
|
+
type: 'text',
|
|
1904
|
+
text: `๐ Analytics tracked: ${eventType}`,
|
|
1905
|
+
}],
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1679
1909
|
async run() {
|
|
1680
1910
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
1681
1911
|
await this.server.connect(transport);
|
package/package.json
CHANGED
package/src/mcp/server.ts
CHANGED
|
@@ -532,6 +532,79 @@ class CodeBakersServer {
|
|
|
532
532
|
properties: {},
|
|
533
533
|
},
|
|
534
534
|
},
|
|
535
|
+
{
|
|
536
|
+
name: 'run_tests',
|
|
537
|
+
description:
|
|
538
|
+
'Run the project test suite (npm test or configured test command). Use after completing a feature to verify everything works. Returns test results with pass/fail status.',
|
|
539
|
+
inputSchema: {
|
|
540
|
+
type: 'object' as const,
|
|
541
|
+
properties: {
|
|
542
|
+
filter: {
|
|
543
|
+
type: 'string',
|
|
544
|
+
description: 'Optional filter to run specific tests (passed to test runner)',
|
|
545
|
+
},
|
|
546
|
+
watch: {
|
|
547
|
+
type: 'boolean',
|
|
548
|
+
description: 'Run in watch mode (default: false)',
|
|
549
|
+
},
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
{
|
|
554
|
+
name: 'report_pattern_gap',
|
|
555
|
+
description:
|
|
556
|
+
'Report when a user request cannot be fully handled by existing patterns. This helps improve CodeBakers by tracking what patterns are missing. The AI should automatically call this when it encounters something outside pattern coverage.',
|
|
557
|
+
inputSchema: {
|
|
558
|
+
type: 'object' as const,
|
|
559
|
+
properties: {
|
|
560
|
+
category: {
|
|
561
|
+
type: 'string',
|
|
562
|
+
description: 'Category of the gap (e.g., "third-party-apis", "mobile", "blockchain", "iot")',
|
|
563
|
+
},
|
|
564
|
+
request: {
|
|
565
|
+
type: 'string',
|
|
566
|
+
description: 'What the user asked for',
|
|
567
|
+
},
|
|
568
|
+
context: {
|
|
569
|
+
type: 'string',
|
|
570
|
+
description: 'Additional context about what was needed',
|
|
571
|
+
},
|
|
572
|
+
handledWith: {
|
|
573
|
+
type: 'string',
|
|
574
|
+
description: 'Which existing patterns were used as fallback',
|
|
575
|
+
},
|
|
576
|
+
wasSuccessful: {
|
|
577
|
+
type: 'boolean',
|
|
578
|
+
description: 'Whether the request was handled successfully despite the gap',
|
|
579
|
+
},
|
|
580
|
+
},
|
|
581
|
+
required: ['category', 'request'],
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
name: 'track_analytics',
|
|
586
|
+
description:
|
|
587
|
+
'Track CLI usage analytics for improving smart triggers and recommendations. Called automatically by the system for key events.',
|
|
588
|
+
inputSchema: {
|
|
589
|
+
type: 'object' as const,
|
|
590
|
+
properties: {
|
|
591
|
+
eventType: {
|
|
592
|
+
type: 'string',
|
|
593
|
+
enum: ['trigger_fired', 'trigger_accepted', 'trigger_dismissed', 'topic_learned', 'command_used', 'pattern_fetched', 'build_started', 'build_completed', 'feature_added', 'audit_run', 'design_cloned'],
|
|
594
|
+
description: 'Type of event to track',
|
|
595
|
+
},
|
|
596
|
+
eventData: {
|
|
597
|
+
type: 'object',
|
|
598
|
+
description: 'Additional data specific to the event',
|
|
599
|
+
},
|
|
600
|
+
projectHash: {
|
|
601
|
+
type: 'string',
|
|
602
|
+
description: 'Hash of project path for grouping analytics',
|
|
603
|
+
},
|
|
604
|
+
},
|
|
605
|
+
required: ['eventType'],
|
|
606
|
+
},
|
|
607
|
+
},
|
|
535
608
|
],
|
|
536
609
|
}));
|
|
537
610
|
|
|
@@ -595,6 +668,15 @@ class CodeBakersServer {
|
|
|
595
668
|
case 'project_status':
|
|
596
669
|
return this.handleProjectStatus();
|
|
597
670
|
|
|
671
|
+
case 'run_tests':
|
|
672
|
+
return this.handleRunTests(args as { filter?: string; watch?: boolean });
|
|
673
|
+
|
|
674
|
+
case 'report_pattern_gap':
|
|
675
|
+
return this.handleReportPatternGap(args as { category: string; request: string; context?: string; handledWith?: string; wasSuccessful?: boolean });
|
|
676
|
+
|
|
677
|
+
case 'track_analytics':
|
|
678
|
+
return this.handleTrackAnalytics(args as { eventType: string; eventData?: Record<string, unknown>; projectHash?: string });
|
|
679
|
+
|
|
598
680
|
default:
|
|
599
681
|
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
600
682
|
}
|
|
@@ -1888,6 +1970,175 @@ Just describe what you want to build! I'll automatically:
|
|
|
1888
1970
|
};
|
|
1889
1971
|
}
|
|
1890
1972
|
|
|
1973
|
+
private handleRunTests(args: { filter?: string; watch?: boolean }) {
|
|
1974
|
+
const { filter, watch = false } = args;
|
|
1975
|
+
const cwd = process.cwd();
|
|
1976
|
+
|
|
1977
|
+
// Detect test runner from package.json
|
|
1978
|
+
let testCommand = 'npm test';
|
|
1979
|
+
try {
|
|
1980
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
1981
|
+
if (fs.existsSync(pkgPath)) {
|
|
1982
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
1983
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
1984
|
+
|
|
1985
|
+
if (deps['@playwright/test']) {
|
|
1986
|
+
testCommand = 'npx playwright test';
|
|
1987
|
+
} else if (deps['vitest']) {
|
|
1988
|
+
testCommand = 'npx vitest run';
|
|
1989
|
+
} else if (deps['jest']) {
|
|
1990
|
+
testCommand = 'npx jest';
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
} catch {
|
|
1994
|
+
// Use default
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
// Add filter if provided
|
|
1998
|
+
if (filter) {
|
|
1999
|
+
testCommand += ` ${filter}`;
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
// Add watch mode
|
|
2003
|
+
if (watch) {
|
|
2004
|
+
testCommand = testCommand.replace(' run', ''); // Remove 'run' for vitest watch
|
|
2005
|
+
if (testCommand.includes('vitest')) {
|
|
2006
|
+
testCommand = testCommand.replace('vitest run', 'vitest');
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
let response = `# ๐งช Running Tests\n\n`;
|
|
2011
|
+
response += `**Command:** \`${testCommand}\`\n\n`;
|
|
2012
|
+
|
|
2013
|
+
try {
|
|
2014
|
+
const output = execSync(testCommand, {
|
|
2015
|
+
cwd,
|
|
2016
|
+
encoding: 'utf-8',
|
|
2017
|
+
timeout: 120000, // 2 minute timeout
|
|
2018
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
2019
|
+
});
|
|
2020
|
+
|
|
2021
|
+
response += `## โ
Tests Passed\n\n`;
|
|
2022
|
+
response += '```\n' + output.slice(-2000) + '\n```\n';
|
|
2023
|
+
} catch (error) {
|
|
2024
|
+
const execError = error as { stdout?: string; stderr?: string; status?: number };
|
|
2025
|
+
response += `## โ Tests Failed\n\n`;
|
|
2026
|
+
|
|
2027
|
+
if (execError.stdout) {
|
|
2028
|
+
response += '### Output\n```\n' + execError.stdout.slice(-2000) + '\n```\n\n';
|
|
2029
|
+
}
|
|
2030
|
+
if (execError.stderr) {
|
|
2031
|
+
response += '### Errors\n```\n' + execError.stderr.slice(-1000) + '\n```\n\n';
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
response += `**Exit Code:** ${execError.status || 1}\n\n`;
|
|
2035
|
+
response += `---\n\n*Fix the failing tests and run again.*`;
|
|
2036
|
+
}
|
|
2037
|
+
|
|
2038
|
+
return {
|
|
2039
|
+
content: [{
|
|
2040
|
+
type: 'text' as const,
|
|
2041
|
+
text: response,
|
|
2042
|
+
}],
|
|
2043
|
+
};
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
private async handleReportPatternGap(args: { category: string; request: string; context?: string; handledWith?: string; wasSuccessful?: boolean }) {
|
|
2047
|
+
const { category, request, context, handledWith, wasSuccessful = true } = args;
|
|
2048
|
+
|
|
2049
|
+
try {
|
|
2050
|
+
const response = await fetch(`${this.apiUrl}/api/pattern-gaps`, {
|
|
2051
|
+
method: 'POST',
|
|
2052
|
+
headers: {
|
|
2053
|
+
'Content-Type': 'application/json',
|
|
2054
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
2055
|
+
},
|
|
2056
|
+
body: JSON.stringify({
|
|
2057
|
+
category,
|
|
2058
|
+
request,
|
|
2059
|
+
context,
|
|
2060
|
+
handledWith,
|
|
2061
|
+
wasSuccessful,
|
|
2062
|
+
}),
|
|
2063
|
+
});
|
|
2064
|
+
|
|
2065
|
+
if (!response.ok) {
|
|
2066
|
+
const error = await response.json().catch(() => ({}));
|
|
2067
|
+
throw new Error(error.error || 'Failed to report pattern gap');
|
|
2068
|
+
}
|
|
2069
|
+
|
|
2070
|
+
const result = await response.json();
|
|
2071
|
+
|
|
2072
|
+
if (result.deduplicated) {
|
|
2073
|
+
return {
|
|
2074
|
+
content: [{
|
|
2075
|
+
type: 'text' as const,
|
|
2076
|
+
text: `๐ Pattern gap already reported recently (category: ${category}). No duplicate created.`,
|
|
2077
|
+
}],
|
|
2078
|
+
};
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
return {
|
|
2082
|
+
content: [{
|
|
2083
|
+
type: 'text' as const,
|
|
2084
|
+
text: `โ
Pattern gap reported successfully.\n\n**Category:** ${category}\n**Request:** ${request}\n\nThis helps improve CodeBakers for everyone!`,
|
|
2085
|
+
}],
|
|
2086
|
+
};
|
|
2087
|
+
} catch (error) {
|
|
2088
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
2089
|
+
return {
|
|
2090
|
+
content: [{
|
|
2091
|
+
type: 'text' as const,
|
|
2092
|
+
text: `โ ๏ธ Could not report pattern gap: ${message}\n\n(This doesn't affect your current work)`,
|
|
2093
|
+
}],
|
|
2094
|
+
};
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2098
|
+
private async handleTrackAnalytics(args: { eventType: string; eventData?: Record<string, unknown>; projectHash?: string }) {
|
|
2099
|
+
const { eventType, eventData, projectHash } = args;
|
|
2100
|
+
|
|
2101
|
+
try {
|
|
2102
|
+
const response = await fetch(`${this.apiUrl}/api/cli/analytics`, {
|
|
2103
|
+
method: 'POST',
|
|
2104
|
+
headers: {
|
|
2105
|
+
'Content-Type': 'application/json',
|
|
2106
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
2107
|
+
},
|
|
2108
|
+
body: JSON.stringify({
|
|
2109
|
+
eventType,
|
|
2110
|
+
eventData,
|
|
2111
|
+
projectHash,
|
|
2112
|
+
}),
|
|
2113
|
+
});
|
|
2114
|
+
|
|
2115
|
+
if (!response.ok) {
|
|
2116
|
+
// Silently fail - analytics shouldn't interrupt user workflow
|
|
2117
|
+
return {
|
|
2118
|
+
content: [{
|
|
2119
|
+
type: 'text' as const,
|
|
2120
|
+
text: `๐ Analytics tracked: ${eventType}`,
|
|
2121
|
+
}],
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
return {
|
|
2126
|
+
content: [{
|
|
2127
|
+
type: 'text' as const,
|
|
2128
|
+
text: `๐ Analytics tracked: ${eventType}`,
|
|
2129
|
+
}],
|
|
2130
|
+
};
|
|
2131
|
+
} catch {
|
|
2132
|
+
// Silently fail
|
|
2133
|
+
return {
|
|
2134
|
+
content: [{
|
|
2135
|
+
type: 'text' as const,
|
|
2136
|
+
text: `๐ Analytics tracked: ${eventType}`,
|
|
2137
|
+
}],
|
|
2138
|
+
};
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
|
|
1891
2142
|
async run(): Promise<void> {
|
|
1892
2143
|
const transport = new StdioServerTransport();
|
|
1893
2144
|
await this.server.connect(transport);
|