@bbyqtbean/taco-helper 0.1.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.
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Config writer — reads, merges, and writes agent MCP config files.
3
+ */
4
+ import { AgentConfig } from './index.js';
5
+ /**
6
+ * Write the "taco" MCP entry into the agent's config file.
7
+ *
8
+ * - If the file doesn't exist, create it with only taco added as a tool.
9
+ * - If the file exists, parse it and add "taco" as a value under the
10
+ * agent's wrapper key (e.g. "mcpServers"), preserving all existing entries.
11
+ */
12
+ export declare function writeConfig(agent: AgentConfig): Promise<void>;
13
+ /**
14
+ * Remove the "taco" MCP entry from the agent's config file.
15
+ *
16
+ * - If the file doesn't exist, there's nothing to remove.
17
+ * - Only removes the "taco" key — all other entries are preserved.
18
+ * - If the wrapper key is empty after removal, it's cleaned up too.
19
+ */
20
+ export declare function removeConfig(agent: AgentConfig): Promise<boolean>;
21
+ /**
22
+ * Clean taco-specific lines from the agent's rules file.
23
+ *
24
+ * During setup, taco-helper wraps its injected content with sentinel comments:
25
+ * # --- taco-start ---
26
+ * ...taco rules...
27
+ * # --- taco-end ---
28
+ *
29
+ * This function removes only the lines between the sentinels (inclusive),
30
+ * preserving any user-authored content outside the sentinels.
31
+ * The file is never deleted — even if empty after cleanup.
32
+ *
33
+ * @param agent - The agent config (must have a non-null rulesFileName)
34
+ * @param projectDir - The project directory containing the rules file
35
+ * @returns true if taco lines were found and removed
36
+ */
37
+ export declare function cleanRulesFile(agent: AgentConfig, projectDir: string): Promise<boolean>;
38
+ //# sourceMappingURL=config-writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-writer.d.ts","sourceRoot":"","sources":["../../src/agents/config-writer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAQzC;;;;;;GAMG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BnE;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAgCvE;AAKD;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAoD7F"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Config writer — reads, merges, and writes agent MCP config files.
3
+ */
4
+ import { readFile, writeFile, mkdir } from 'fs/promises';
5
+ import { existsSync } from 'fs';
6
+ import { dirname, join } from 'path';
7
+ /** The MCP server entry that taco-helper writes into agent configs. */
8
+ const TACO_MCP_ENTRY = {
9
+ command: 'npx',
10
+ args: ['-y', '@bbyqtbean/taco-helper@latest'],
11
+ };
12
+ /**
13
+ * Write the "taco" MCP entry into the agent's config file.
14
+ *
15
+ * - If the file doesn't exist, create it with only taco added as a tool.
16
+ * - If the file exists, parse it and add "taco" as a value under the
17
+ * agent's wrapper key (e.g. "mcpServers"), preserving all existing entries.
18
+ */
19
+ export async function writeConfig(agent) {
20
+ const { configPath, wrapperKey } = agent;
21
+ // Ensure the parent directory exists
22
+ const dir = dirname(configPath);
23
+ if (!existsSync(dir)) {
24
+ await mkdir(dir, { recursive: true });
25
+ }
26
+ let config = {};
27
+ // If the file already exists, parse it
28
+ if (existsSync(configPath)) {
29
+ try {
30
+ const raw = await readFile(configPath, 'utf-8');
31
+ config = JSON.parse(raw);
32
+ }
33
+ catch {
34
+ // If parsing fails, start fresh but warn the user
35
+ console.error(`⚠️ Could not parse ${configPath} — creating a fresh config.`);
36
+ config = {};
37
+ }
38
+ }
39
+ // Add "taco" under the wrapper key, preserving existing entries
40
+ const servers = config[wrapperKey] ?? {};
41
+ servers['taco'] = TACO_MCP_ENTRY;
42
+ config[wrapperKey] = servers;
43
+ // Write back
44
+ await writeFile(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
45
+ }
46
+ /**
47
+ * Remove the "taco" MCP entry from the agent's config file.
48
+ *
49
+ * - If the file doesn't exist, there's nothing to remove.
50
+ * - Only removes the "taco" key — all other entries are preserved.
51
+ * - If the wrapper key is empty after removal, it's cleaned up too.
52
+ */
53
+ export async function removeConfig(agent) {
54
+ const { configPath, wrapperKey } = agent;
55
+ if (!existsSync(configPath)) {
56
+ return false; // Nothing to remove
57
+ }
58
+ let config;
59
+ try {
60
+ const raw = await readFile(configPath, 'utf-8');
61
+ config = JSON.parse(raw);
62
+ }
63
+ catch {
64
+ console.error(`⚠️ Could not parse ${configPath} — nothing to remove.`);
65
+ return false;
66
+ }
67
+ const servers = config[wrapperKey];
68
+ if (!servers || !('taco' in servers)) {
69
+ return false; // "taco" entry doesn't exist
70
+ }
71
+ // Remove just the "taco" key
72
+ delete servers['taco'];
73
+ // If the wrapper key is now empty, remove it too
74
+ if (Object.keys(servers).length === 0) {
75
+ delete config[wrapperKey];
76
+ }
77
+ // Write back
78
+ await writeFile(configPath, JSON.stringify(config, null, 2) + '\n', 'utf-8');
79
+ return true;
80
+ }
81
+ const SENTINEL_START = '# --- taco-start ---';
82
+ const SENTINEL_END = '# --- taco-end ---';
83
+ /**
84
+ * Clean taco-specific lines from the agent's rules file.
85
+ *
86
+ * During setup, taco-helper wraps its injected content with sentinel comments:
87
+ * # --- taco-start ---
88
+ * ...taco rules...
89
+ * # --- taco-end ---
90
+ *
91
+ * This function removes only the lines between the sentinels (inclusive),
92
+ * preserving any user-authored content outside the sentinels.
93
+ * The file is never deleted — even if empty after cleanup.
94
+ *
95
+ * @param agent - The agent config (must have a non-null rulesFileName)
96
+ * @param projectDir - The project directory containing the rules file
97
+ * @returns true if taco lines were found and removed
98
+ */
99
+ export async function cleanRulesFile(agent, projectDir) {
100
+ const { rulesFileName } = agent;
101
+ if (!rulesFileName) {
102
+ return false; // Agent has no rules file
103
+ }
104
+ const rulesPath = join(projectDir, rulesFileName);
105
+ if (!existsSync(rulesPath)) {
106
+ return false; // Nothing to clean
107
+ }
108
+ let content;
109
+ try {
110
+ content = await readFile(rulesPath, 'utf-8');
111
+ }
112
+ catch {
113
+ console.error(`⚠️ Could not read ${rulesPath} — skipping rules cleanup.`);
114
+ return false;
115
+ }
116
+ const lines = content.split('\n');
117
+ const resultLines = [];
118
+ let insideSentinel = false;
119
+ let foundSentinel = false;
120
+ for (const line of lines) {
121
+ const trimmed = line.trim();
122
+ if (trimmed === SENTINEL_START) {
123
+ insideSentinel = true;
124
+ foundSentinel = true;
125
+ continue; // Skip this line
126
+ }
127
+ if (trimmed === SENTINEL_END) {
128
+ insideSentinel = false;
129
+ continue; // Skip this line
130
+ }
131
+ if (!insideSentinel) {
132
+ resultLines.push(line);
133
+ }
134
+ }
135
+ if (!foundSentinel) {
136
+ return false; // No taco content found
137
+ }
138
+ // Write back the cleaned content (file is kept even if empty)
139
+ await writeFile(rulesPath, resultLines.join('\n'), 'utf-8');
140
+ return true;
141
+ }
142
+ //# sourceMappingURL=config-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-writer.js","sourceRoot":"","sources":["../../src/agents/config-writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Agent registry — maps agent IDs to their config file paths and formats.
3
+ */
4
+ export interface AgentConfig {
5
+ name: string;
6
+ agentId: string;
7
+ /** Absolute path to the agent's MCP config file */
8
+ configPath: string;
9
+ /** The top-level key that holds MCP server entries (e.g. "mcpServers") */
10
+ wrapperKey: string;
11
+ /** Filename for the agent's rules file (e.g. ".cursorrules", "CLAUDE.md"). null if the agent has no rules file. */
12
+ rulesFileName: string | null;
13
+ }
14
+ export declare const AGENTS: Record<string, AgentConfig>;
15
+ /**
16
+ * Look up an agent by its --agent flag value.
17
+ * Returns undefined if the agent ID is not recognised.
18
+ */
19
+ export declare function getAgent(agentId: string): AgentConfig | undefined;
20
+ /**
21
+ * List all supported agent IDs (for help text / error messages).
22
+ */
23
+ export declare function listAgentIds(): string[];
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,mDAAmD;IACnD,UAAU,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB,mHAAmH;IACnH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAID,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CA2C9C,CAAC;AAEF;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAEjE;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAEvC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Agent registry — maps agent IDs to their config file paths and formats.
3
+ */
4
+ import { homedir } from 'os';
5
+ import { join } from 'path';
6
+ const home = homedir();
7
+ export const AGENTS = {
8
+ cursor: {
9
+ name: 'Cursor',
10
+ agentId: 'cursor',
11
+ configPath: join(home, '.cursor', 'mcp.json'),
12
+ wrapperKey: 'mcpServers',
13
+ rulesFileName: '.cursorrules',
14
+ },
15
+ 'claude-desktop': {
16
+ name: 'Claude Desktop',
17
+ agentId: 'claude-desktop',
18
+ configPath: join(home, 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json'),
19
+ wrapperKey: 'mcpServers',
20
+ rulesFileName: null,
21
+ },
22
+ 'claude-code': {
23
+ name: 'Claude Code',
24
+ agentId: 'claude-code',
25
+ configPath: join(home, '.claude.json'),
26
+ wrapperKey: 'mcpServers',
27
+ rulesFileName: 'CLAUDE.md',
28
+ },
29
+ windsurf: {
30
+ name: 'Windsurf',
31
+ agentId: 'windsurf',
32
+ configPath: join(home, '.windsurf', 'mcp.json'),
33
+ wrapperKey: 'mcpServers',
34
+ rulesFileName: '.windsurfrules',
35
+ },
36
+ antigravity: {
37
+ name: 'Antigravity',
38
+ agentId: 'antigravity',
39
+ configPath: join(home, '.antigravity', 'mcp.json'),
40
+ wrapperKey: 'mcpServers',
41
+ rulesFileName: '.antigravityrules',
42
+ },
43
+ codex: {
44
+ name: 'Codex (ChatGPT)',
45
+ agentId: 'codex',
46
+ configPath: join(home, '.codex', 'mcp.json'),
47
+ wrapperKey: 'mcpServers',
48
+ rulesFileName: '.codexrules',
49
+ },
50
+ };
51
+ /**
52
+ * Look up an agent by its --agent flag value.
53
+ * Returns undefined if the agent ID is not recognised.
54
+ */
55
+ export function getAgent(agentId) {
56
+ return AGENTS[agentId];
57
+ }
58
+ /**
59
+ * List all supported agent IDs (for help text / error messages).
60
+ */
61
+ export function listAgentIds() {
62
+ return Object.keys(AGENTS);
63
+ }
64
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agents/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAa5B,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;AAEvB,MAAM,CAAC,MAAM,MAAM,GAAgC;IAC/C,MAAM,EAAE;QACJ,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,QAAQ;QACjB,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC;QAC7C,UAAU,EAAE,YAAY;QACxB,aAAa,EAAE,cAAc;KAChC;IACD,gBAAgB,EAAE;QACd,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,gBAAgB;QACzB,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,qBAAqB,EAAE,QAAQ,EAAE,4BAA4B,CAAC;QAChG,UAAU,EAAE,YAAY;QACxB,aAAa,EAAE,IAAI;KACtB;IACD,aAAa,EAAE;QACX,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,aAAa;QACtB,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC;QACtC,UAAU,EAAE,YAAY;QACxB,aAAa,EAAE,WAAW;KAC7B;IACD,QAAQ,EAAE;QACN,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,UAAU;QACnB,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,UAAU,CAAC;QAC/C,UAAU,EAAE,YAAY;QACxB,aAAa,EAAE,gBAAgB;KAClC;IACD,WAAW,EAAE;QACT,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,aAAa;QACtB,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,UAAU,CAAC;QAClD,UAAU,EAAE,YAAY;QACxB,aAAa,EAAE,mBAAmB;KACrC;IACD,KAAK,EAAE;QACH,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC;QAC5C,UAAU,EAAE,YAAY;QACxB,aAAa,EAAE,aAAa;KAC/B;CACJ,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe;IACpC,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY;IACxB,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC/B,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * CLI commands — setup and uninstall.
3
+ * These are run by the user directly via npx.
4
+ */
5
+ export declare function runSetup(args: string[]): Promise<void>;
6
+ export declare function runUninstall(args: string[]): Promise<void>;
7
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA2B5D;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAsChE"}
package/dist/cli.js ADDED
@@ -0,0 +1,74 @@
1
+ /**
2
+ * CLI commands — setup and uninstall.
3
+ * These are run by the user directly via npx.
4
+ */
5
+ import { getAgent, listAgentIds } from './agents/index.js';
6
+ import { writeConfig, removeConfig, cleanRulesFile } from './agents/config-writer.js';
7
+ export async function runSetup(args) {
8
+ const agentId = getArgValue(args, '--agent');
9
+ if (!agentId) {
10
+ console.error('Usage: npx taco-helper setup --agent <agent_id>');
11
+ console.error(`\nSupported agents: ${listAgentIds().join(', ')}`);
12
+ process.exit(1);
13
+ }
14
+ const agent = getAgent(agentId);
15
+ if (!agent) {
16
+ console.error(`❌ Unknown agent: "${agentId}"`);
17
+ console.error(`Supported agents: ${listAgentIds().join(', ')}`);
18
+ process.exit(1);
19
+ }
20
+ console.log(`\n🌮 Setting up Taco for ${agent.name}...\n`);
21
+ try {
22
+ await writeConfig(agent);
23
+ console.log(`✅ Taco has been added to ${agent.name}'s MCP config.`);
24
+ console.log(` Config file: ${agent.configPath}`);
25
+ console.log(`\n👉 Restart ${agent.name} to activate the connection.\n`);
26
+ }
27
+ catch (err) {
28
+ console.error(`❌ Failed to write config:`, err);
29
+ process.exit(1);
30
+ }
31
+ }
32
+ export async function runUninstall(args) {
33
+ const agentId = getArgValue(args, '--agent');
34
+ if (!agentId) {
35
+ console.error('Usage: npx taco-helper uninstall --agent <agent_id>');
36
+ console.error(`\nSupported agents: ${listAgentIds().join(', ')}`);
37
+ process.exit(1);
38
+ }
39
+ const agent = getAgent(agentId);
40
+ if (!agent) {
41
+ console.error(`❌ Unknown agent: "${agentId}"`);
42
+ console.error(`Supported agents: ${listAgentIds().join(', ')}`);
43
+ process.exit(1);
44
+ }
45
+ console.log(`\n🌮 Removing Taco from ${agent.name}...\n`);
46
+ try {
47
+ const removed = await removeConfig(agent);
48
+ if (removed) {
49
+ console.log(`✅ Taco has been removed from ${agent.name}'s MCP config.`);
50
+ console.log(` Config file: ${agent.configPath}`);
51
+ }
52
+ else {
53
+ console.log(`ℹ️ No Taco entry found in ${agent.name}'s config. Nothing to remove.`);
54
+ }
55
+ // Clean taco-specific lines from the agent's rules file
56
+ const rulesCleaned = await cleanRulesFile(agent, process.cwd());
57
+ if (rulesCleaned) {
58
+ console.log(`✅ Taco lines cleaned from ${agent.rulesFileName}.`);
59
+ }
60
+ console.log(`\n👉 Restart ${agent.name} to complete the disconnection.\n`);
61
+ }
62
+ catch (err) {
63
+ console.error(`❌ Failed to remove config:`, err);
64
+ process.exit(1);
65
+ }
66
+ }
67
+ /** Extract a --flag value from an args array. */
68
+ function getArgValue(args, flag) {
69
+ const idx = args.indexOf(flag);
70
+ if (idx === -1 || idx + 1 >= args.length)
71
+ return undefined;
72
+ return args[idx + 1];
73
+ }
74
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * In-memory comment store — shared between the MCP server and HTTP server.
3
+ *
4
+ * Comments live only in memory. When the agent restarts, the store is fresh
5
+ * and the Chrome extension re-pushes comments on connect.
6
+ */
7
+ import { EventEmitter } from 'events';
8
+ export interface TacoComment {
9
+ id: string;
10
+ text: string;
11
+ selector: string;
12
+ pageUrl: string;
13
+ screenshot?: string;
14
+ timestamp: string;
15
+ resolved: boolean;
16
+ elementName?: string;
17
+ metadata?: Record<string, unknown>;
18
+ }
19
+ export declare class CommentStore extends EventEmitter {
20
+ private comments;
21
+ /**
22
+ * Add one or more comments to the store.
23
+ * If a comment with the same ID already exists, it is overwritten.
24
+ * Returns the number of comments added.
25
+ */
26
+ addComments(comments: TacoComment[]): number;
27
+ /**
28
+ * Get all comments. By default, only returns unresolved comments.
29
+ * Pass `true` to include resolved ones.
30
+ */
31
+ getComments(includeResolved?: boolean): TacoComment[];
32
+ /**
33
+ * Mark a comment as resolved by ID.
34
+ * Returns true if the comment was found and updated, false otherwise.
35
+ */
36
+ markResolved(id: string): boolean;
37
+ /** Remove all comments from the store. */
38
+ clear(): void;
39
+ /** Get the total number of comments in the store. */
40
+ get size(): number;
41
+ }
42
+ //# sourceMappingURL=comment-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment-store.d.ts","sourceRoot":"","sources":["../src/comment-store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC,MAAM,WAAW,WAAW;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,qBAAa,YAAa,SAAQ,YAAY;IAC1C,OAAO,CAAC,QAAQ,CAAuC;IAEvD;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM;IAQ5C;;;OAGG;IACH,WAAW,CAAC,eAAe,UAAQ,GAAG,WAAW,EAAE;IAMnD;;;OAGG;IACH,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO;IAQjC,0CAA0C;IAC1C,KAAK,IAAI,IAAI;IAIb,qDAAqD;IACrD,IAAI,IAAI,IAAI,MAAM,CAEjB;CACJ"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * In-memory comment store — shared between the MCP server and HTTP server.
3
+ *
4
+ * Comments live only in memory. When the agent restarts, the store is fresh
5
+ * and the Chrome extension re-pushes comments on connect.
6
+ */
7
+ import { EventEmitter } from 'events';
8
+ export class CommentStore extends EventEmitter {
9
+ comments = new Map();
10
+ /**
11
+ * Add one or more comments to the store.
12
+ * If a comment with the same ID already exists, it is overwritten.
13
+ * Returns the number of comments added.
14
+ */
15
+ addComments(comments) {
16
+ for (const comment of comments) {
17
+ this.comments.set(comment.id, comment);
18
+ this.emit('comment-received', { id: comment.id });
19
+ }
20
+ return comments.length;
21
+ }
22
+ /**
23
+ * Get all comments. By default, only returns unresolved comments.
24
+ * Pass `true` to include resolved ones.
25
+ */
26
+ getComments(includeResolved = false) {
27
+ const all = Array.from(this.comments.values());
28
+ if (includeResolved)
29
+ return all;
30
+ return all.filter((c) => !c.resolved);
31
+ }
32
+ /**
33
+ * Mark a comment as resolved by ID.
34
+ * Returns true if the comment was found and updated, false otherwise.
35
+ */
36
+ markResolved(id) {
37
+ const comment = this.comments.get(id);
38
+ if (!comment)
39
+ return false;
40
+ comment.resolved = true;
41
+ this.emit('comment-resolved', { id });
42
+ return true;
43
+ }
44
+ /** Remove all comments from the store. */
45
+ clear() {
46
+ this.comments.clear();
47
+ }
48
+ /** Get the total number of comments in the store. */
49
+ get size() {
50
+ return this.comments.size;
51
+ }
52
+ }
53
+ //# sourceMappingURL=comment-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment-store.js","sourceRoot":"","sources":["../src/comment-store.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AActC,MAAM,OAAO,YAAa,SAAQ,YAAY;IAClC,QAAQ,GAA6B,IAAI,GAAG,EAAE,CAAC;IAEvD;;;;OAIG;IACH,WAAW,CAAC,QAAuB;QAC/B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;YACvC,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,OAAO,QAAQ,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,eAAe,GAAG,KAAK;QAC/B,MAAM,GAAG,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/C,IAAI,eAAe;YAAE,OAAO,GAAG,CAAC;QAChC,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC1C,CAAC;IAED;;;OAGG;IACH,YAAY,CAAC,EAAU;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAC3B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,0CAA0C;IAC1C,KAAK;QACD,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;IAED,qDAAqD;IACrD,IAAI,IAAI;QACJ,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC9B,CAAC;CACJ"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * HTTP server — listens on localhost:7867.
3
+ * The Taco Chrome extension pushes comments here via fetch().
4
+ */
5
+ import { IncomingMessage, ServerResponse } from 'http';
6
+ import { CommentStore } from './comment-store.js';
7
+ /**
8
+ * Start the HTTP server on localhost:7867.
9
+ * Returns a reference to the server so it can be closed in tests.
10
+ */
11
+ export declare function startHttpServer(store: CommentStore): import("http").Server<typeof IncomingMessage, typeof ServerResponse>;
12
+ //# sourceMappingURL=http-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAgB,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAGrE,OAAO,EAAE,YAAY,EAAe,MAAM,oBAAoB,CAAC;AAoD/D;;;GAGG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,wEA+JlD"}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * HTTP server — listens on localhost:7867.
3
+ * The Taco Chrome extension pushes comments here via fetch().
4
+ */
5
+ import { createServer } from 'http';
6
+ import { readFile } from 'fs/promises';
7
+ import { join } from 'path';
8
+ import { getAgent } from './agents/index.js';
9
+ import { removeConfig, cleanRulesFile } from './agents/config-writer.js';
10
+ const PORT = 7867;
11
+ /** Active SSE connections */
12
+ const sseClients = new Set();
13
+ /** Read the full request body as a string. */
14
+ function readBody(req) {
15
+ return new Promise((resolve, reject) => {
16
+ const chunks = [];
17
+ req.on('data', (chunk) => chunks.push(chunk));
18
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
19
+ req.on('error', reject);
20
+ });
21
+ }
22
+ /** Send a JSON response. */
23
+ function json(res, status, data) {
24
+ res.writeHead(status, {
25
+ 'Content-Type': 'application/json',
26
+ 'Access-Control-Allow-Origin': '*',
27
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
28
+ 'Access-Control-Allow-Headers': 'Content-Type',
29
+ });
30
+ res.end(JSON.stringify(data));
31
+ }
32
+ /** Set CORS headers and handle preflight. Returns true if this was a preflight request. */
33
+ function handleCors(req, res) {
34
+ if (req.method === 'OPTIONS') {
35
+ res.writeHead(204, {
36
+ 'Access-Control-Allow-Origin': '*',
37
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
38
+ 'Access-Control-Allow-Headers': 'Content-Type',
39
+ });
40
+ res.end();
41
+ return true;
42
+ }
43
+ return false;
44
+ }
45
+ /** Broadcast an SSE event to all connected clients. */
46
+ function broadcastSSE(event, data) {
47
+ const message = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
48
+ for (const client of sseClients) {
49
+ client.write(message);
50
+ }
51
+ }
52
+ /**
53
+ * Start the HTTP server on localhost:7867.
54
+ * Returns a reference to the server so it can be closed in tests.
55
+ */
56
+ export function startHttpServer(store) {
57
+ // Wire store events to SSE broadcasts
58
+ store.on('comment-resolved', (payload) => {
59
+ console.error(`🌮 [SSE] Broadcasting comment-resolved: ${payload.id}`);
60
+ broadcastSSE('comment-resolved', payload);
61
+ });
62
+ store.on('comment-received', (payload) => {
63
+ broadcastSSE('comment-received', payload);
64
+ });
65
+ const server = createServer(async (req, res) => {
66
+ // Handle CORS preflight
67
+ if (handleCors(req, res))
68
+ return;
69
+ const url = req.url ?? '/';
70
+ const method = req.method ?? 'GET';
71
+ try {
72
+ // GET /health
73
+ if (url === '/health' && method === 'GET') {
74
+ // Try to read project name from package.json in working directory
75
+ let projectName = null;
76
+ try {
77
+ const pkgPath = join(process.cwd(), 'package.json');
78
+ const pkgContent = await readFile(pkgPath, 'utf-8');
79
+ const pkg = JSON.parse(pkgContent);
80
+ projectName = pkg.name || null;
81
+ }
82
+ catch {
83
+ // package.json not found or unreadable — that's okay
84
+ }
85
+ json(res, 200, { status: 'ok', projectName });
86
+ return;
87
+ }
88
+ // GET /events — Server-Sent Events stream
89
+ if (url === '/events' && method === 'GET') {
90
+ res.writeHead(200, {
91
+ 'Content-Type': 'text/event-stream',
92
+ 'Cache-Control': 'no-cache',
93
+ 'Connection': 'keep-alive',
94
+ 'Access-Control-Allow-Origin': '*',
95
+ });
96
+ // Send initial connected event
97
+ res.write(`event: connected\ndata: {}\n\n`);
98
+ // Add to active clients
99
+ sseClients.add(res);
100
+ console.error(`🌮 [SSE] Client connected (${sseClients.size} active)`);
101
+ // Remove on disconnect
102
+ req.on('close', () => {
103
+ sseClients.delete(res);
104
+ console.error(`🌮 [SSE] Client disconnected (${sseClients.size} active)`);
105
+ });
106
+ // Keep connection alive with periodic heartbeat
107
+ const heartbeat = setInterval(() => {
108
+ res.write(`: heartbeat\n\n`);
109
+ }, 30_000);
110
+ req.on('close', () => clearInterval(heartbeat));
111
+ return;
112
+ }
113
+ // GET /comments — retrieve current comments
114
+ // Supports ?include_resolved=true to include resolved comments
115
+ const parsedUrl = new URL(url, 'http://localhost');
116
+ if (parsedUrl.pathname === '/comments' && method === 'GET') {
117
+ const includeResolved = parsedUrl.searchParams.get('include_resolved') === 'true';
118
+ const comments = store.getComments(includeResolved);
119
+ json(res, 200, comments);
120
+ return;
121
+ }
122
+ // POST /comments — push new comments from the extension
123
+ if (url === '/comments' && method === 'POST') {
124
+ const body = await readBody(req);
125
+ const comments = JSON.parse(body);
126
+ const count = store.addComments(comments);
127
+ json(res, 200, { received: count });
128
+ return;
129
+ }
130
+ // POST /comments/:id/resolve — mark a comment as resolved
131
+ const resolveMatch = url.match(/^\/comments\/([^/]+)\/resolve$/);
132
+ if (resolveMatch && method === 'POST') {
133
+ const id = decodeURIComponent(resolveMatch[1]);
134
+ const success = store.markResolved(id);
135
+ if (success) {
136
+ json(res, 200, { success: true });
137
+ }
138
+ else {
139
+ json(res, 404, { error: 'Comment not found' });
140
+ }
141
+ return;
142
+ }
143
+ // POST /uninstall — self-uninstall: remove MCP config + clean rules file, then shut down
144
+ if (url === '/uninstall' && method === 'POST') {
145
+ const body = await readBody(req);
146
+ const { agent_id } = JSON.parse(body);
147
+ const agent = getAgent(agent_id);
148
+ if (!agent) {
149
+ json(res, 400, { error: `Unknown agent: "${agent_id}"` });
150
+ return;
151
+ }
152
+ console.error(`🌮 Uninstalling Taco from ${agent.name}...`);
153
+ const removed = [];
154
+ try {
155
+ const configRemoved = await removeConfig(agent);
156
+ if (configRemoved)
157
+ removed.push('mcp_config');
158
+ }
159
+ catch (err) {
160
+ console.error(`⚠️ Failed to remove MCP config:`, err);
161
+ }
162
+ try {
163
+ const rulesRemoved = await cleanRulesFile(agent, process.cwd());
164
+ if (rulesRemoved)
165
+ removed.push('rules_file');
166
+ }
167
+ catch (err) {
168
+ console.error(`⚠️ Failed to clean rules file:`, err);
169
+ }
170
+ json(res, 200, { success: true, removed });
171
+ // Shut down after a brief delay to allow the response to flush
172
+ setTimeout(() => {
173
+ console.error('🌮 Taco Helper shutting down after uninstall.');
174
+ process.exit(0);
175
+ }, 100);
176
+ return;
177
+ }
178
+ // 404 for anything else
179
+ json(res, 404, { error: 'Not found' });
180
+ }
181
+ catch (err) {
182
+ console.error('HTTP error:', err);
183
+ json(res, 500, { error: 'Internal server error' });
184
+ }
185
+ });
186
+ server.listen(PORT, '127.0.0.1', () => {
187
+ // Log to stderr — stdout is reserved for MCP
188
+ console.error(`🌮 Taco Helper HTTP server listening on http://127.0.0.1:${PORT}`);
189
+ });
190
+ server.on('error', (err) => {
191
+ if (err.code === 'EADDRINUSE') {
192
+ console.error(`❌ Port ${PORT} is already in use. Is another instance of taco-helper running?`);
193
+ process.exit(1);
194
+ }
195
+ throw err;
196
+ });
197
+ return server;
198
+ }
199
+ //# sourceMappingURL=http-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * taco-helper — entry point.
4
+ *
5
+ * This file detects how the package was invoked:
6
+ *
7
+ * CLI mode (user runs manually):
8
+ * npx taco-helper setup --agent cursor
9
+ * npx taco-helper uninstall --agent cursor
10
+ *
11
+ * Server mode (agent launches automatically):
12
+ * npx taco-helper
13
+ * → starts MCP server on stdio + HTTP server on :7867
14
+ */
15
+ export {};
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG"}
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * taco-helper — entry point.
4
+ *
5
+ * This file detects how the package was invoked:
6
+ *
7
+ * CLI mode (user runs manually):
8
+ * npx taco-helper setup --agent cursor
9
+ * npx taco-helper uninstall --agent cursor
10
+ *
11
+ * Server mode (agent launches automatically):
12
+ * npx taco-helper
13
+ * → starts MCP server on stdio + HTTP server on :7867
14
+ */
15
+ import { runSetup, runUninstall } from './cli.js';
16
+ import { CommentStore } from './comment-store.js';
17
+ import { startHttpServer } from './http-server.js';
18
+ import { startMcpServer } from './mcp-server.js';
19
+ const command = process.argv[2];
20
+ if (command === 'setup') {
21
+ // CLI mode: write MCP config and exit
22
+ await runSetup(process.argv.slice(2));
23
+ }
24
+ else if (command === 'uninstall') {
25
+ // CLI mode: remove MCP config and exit
26
+ await runUninstall(process.argv.slice(2));
27
+ }
28
+ else {
29
+ // Server mode: start both servers
30
+ const store = new CommentStore();
31
+ // Start the HTTP server (for the Chrome extension)
32
+ startHttpServer(store);
33
+ // Start the MCP server on stdio (for the agent)
34
+ await startMcpServer(store);
35
+ console.error('🌮 Taco Helper is running. Press Ctrl+C to stop.');
36
+ }
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAEhC,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;IACtB,sCAAsC;IACtC,MAAM,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1C,CAAC;KAAM,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;IACjC,uCAAuC;IACvC,MAAM,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,CAAC;KAAM,CAAC;IACJ,kCAAkC;IAClC,MAAM,KAAK,GAAG,IAAI,YAAY,EAAE,CAAC;IAEjC,mDAAmD;IACnD,eAAe,CAAC,KAAK,CAAC,CAAC;IAEvB,gDAAgD;IAChD,MAAM,cAAc,CAAC,KAAK,CAAC,CAAC;IAE5B,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;AACtE,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * MCP server — speaks MCP protocol over stdio.
3
+ * Exposes tools for AI agents to query and manage comments.
4
+ * Supports sampling to autonomously trigger implementation when comments arrive.
5
+ */
6
+ import { CommentStore } from './comment-store.js';
7
+ /**
8
+ * Create and start the MCP server on stdio.
9
+ * The agent communicates with this server via stdin/stdout.
10
+ */
11
+ export declare function startMcpServer(store: CommentStore): Promise<void>;
12
+ //# sourceMappingURL=mcp-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.d.ts","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,YAAY,EAAe,MAAM,oBAAoB,CAAC;AAE/D;;;GAGG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA4FvE"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * MCP server — speaks MCP protocol over stdio.
3
+ * Exposes tools for AI agents to query and manage comments.
4
+ * Supports sampling to autonomously trigger implementation when comments arrive.
5
+ */
6
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
8
+ import { z } from 'zod';
9
+ /**
10
+ * Create and start the MCP server on stdio.
11
+ * The agent communicates with this server via stdin/stdout.
12
+ */
13
+ export async function startMcpServer(store) {
14
+ const server = new McpServer({
15
+ name: 'taco-helper',
16
+ version: '0.1.0',
17
+ });
18
+ // Tool: get_comments — retrieve all pending (unresolved) comments
19
+ server.tool('get_comments', 'Retrieve all pending (unresolved) comments left by the user in the Taco Chrome extension. Each comment includes the text, CSS selector of the annotated element, page URL, and optionally a screenshot.', {}, async () => {
20
+ const comments = store.getComments(false);
21
+ return {
22
+ content: [
23
+ {
24
+ type: 'text',
25
+ text: comments.length === 0
26
+ ? 'No pending comments.'
27
+ : JSON.stringify(comments, null, 2),
28
+ },
29
+ ],
30
+ };
31
+ });
32
+ // Tool: get_all_comments — retrieve all comments including resolved
33
+ server.tool('get_all_comments', 'Retrieve all comments including resolved ones. Use this to see the full history of comments.', {
34
+ include_resolved: z.boolean().optional().describe('Whether to include resolved comments (default: true)'),
35
+ }, async ({ include_resolved }) => {
36
+ const comments = store.getComments(include_resolved ?? true);
37
+ return {
38
+ content: [
39
+ {
40
+ type: 'text',
41
+ text: comments.length === 0
42
+ ? 'No comments found.'
43
+ : JSON.stringify(comments, null, 2),
44
+ },
45
+ ],
46
+ };
47
+ });
48
+ // Tool: mark_resolved — mark a comment as resolved
49
+ server.tool('mark_resolved', 'Mark a comment as resolved by its ID. Use this after you have addressed a comment.', {
50
+ id: z.string().describe('The ID of the comment to mark as resolved'),
51
+ }, async ({ id }) => {
52
+ const success = store.markResolved(id);
53
+ return {
54
+ content: [
55
+ {
56
+ type: 'text',
57
+ text: success
58
+ ? `Comment ${id} marked as resolved.`
59
+ : `Comment ${id} not found.`,
60
+ },
61
+ ],
62
+ };
63
+ });
64
+ // Connect to stdio transport
65
+ const transport = new StdioServerTransport();
66
+ await server.connect(transport);
67
+ console.error('🌮 Taco Helper MCP server running on stdio');
68
+ // --- Sampling: auto-trigger agent when new comments arrive ---
69
+ // After connection, listen for new comments and request the agent to implement them.
70
+ // This only works if the connected agent supports the sampling capability.
71
+ store.on('comment-received', async () => {
72
+ // Debounce: wait briefly for batch of comments to arrive
73
+ // (the extension sends multiple comments in one POST, which triggers
74
+ // multiple 'comment-received' events — we only want one sampling request)
75
+ if (samplingDebounceTimer)
76
+ clearTimeout(samplingDebounceTimer);
77
+ samplingDebounceTimer = setTimeout(() => {
78
+ requestAgentImplementation(server, store).catch((err) => {
79
+ console.error('🌮 [Sampling] Error requesting agent implementation:', err.message ?? err);
80
+ });
81
+ }, 1000);
82
+ });
83
+ console.error('🌮 Taco Helper sampling listener registered');
84
+ }
85
+ let samplingDebounceTimer = null;
86
+ /**
87
+ * Request the connected agent to implement pending comments via MCP sampling.
88
+ * If the agent doesn't support sampling, this silently does nothing.
89
+ */
90
+ async function requestAgentImplementation(mcpServer, store) {
91
+ const comments = store.getComments(false); // unresolved only
92
+ if (comments.length === 0)
93
+ return;
94
+ const commentSummary = comments.map((c, i) => {
95
+ let desc = `${i + 1}. [${c.id}] "${c.text}"`;
96
+ if (c.elementName)
97
+ desc += ` (element: ${c.elementName})`;
98
+ if (c.selector)
99
+ desc += ` [selector: ${c.selector}]`;
100
+ if (c.pageUrl)
101
+ desc += ` on ${c.pageUrl}`;
102
+ return desc;
103
+ }).join('\n');
104
+ const prompt = `You have received ${comments.length} new UI feedback comment(s) from the Taco Chrome extension. Please implement each requested change:
105
+
106
+ ${commentSummary}
107
+
108
+ For each comment:
109
+ 1. Understand the requested change
110
+ 2. Implement it in the codebase
111
+ 3. Call the mark_resolved tool with the comment ID after implementing
112
+
113
+ Begin implementing now.`;
114
+ try {
115
+ console.error(`🌮 [Sampling] Requesting agent to implement ${comments.length} comment(s)...`);
116
+ await mcpServer.server.createMessage({
117
+ messages: [
118
+ {
119
+ role: 'user',
120
+ content: {
121
+ type: 'text',
122
+ text: prompt,
123
+ },
124
+ },
125
+ ],
126
+ maxTokens: 4096,
127
+ });
128
+ console.error('🌮 [Sampling] Agent acknowledged the request');
129
+ }
130
+ catch (err) {
131
+ // Expected failure if agent doesn't support sampling — not an error
132
+ if (err?.code === -32601 || err?.message?.includes('not supported') || err?.message?.includes('Method not found')) {
133
+ console.error('🌮 [Sampling] Agent does not support sampling — user must prompt manually');
134
+ }
135
+ else {
136
+ throw err;
137
+ }
138
+ }
139
+ }
140
+ //# sourceMappingURL=mcp-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-server.js","sourceRoot":"","sources":["../src/mcp-server.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@bbyqtbean/taco-helper",
3
+ "version": "0.1.0",
4
+ "description": "MCP server + CLI for connecting the Taco Chrome extension to AI agents",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "bin": {
8
+ "taco-helper": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "keywords": [
16
+ "mcp",
17
+ "taco",
18
+ "chrome-extension",
19
+ "ai-agent"
20
+ ],
21
+ "license": "MIT",
22
+ "dependencies": {
23
+ "@modelcontextprotocol/sdk": "^1.26.0"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^20.11.0",
27
+ "typescript": "^5.3.3"
28
+ },
29
+ "engines": {
30
+ "node": ">=18.0.0"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "files": [
36
+ "dist"
37
+ ]
38
+ }