@elliotding/ai-agent-mcp 0.1.8 → 0.1.10
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/ai-resource-telemetry.json +1 -1
- package/dist/git/multi-source-manager.d.ts +1 -1
- package/dist/git/multi-source-manager.d.ts.map +1 -1
- package/dist/git/multi-source-manager.js +54 -10
- package/dist/git/multi-source-manager.js.map +1 -1
- package/dist/prompts/manager.d.ts.map +1 -1
- package/dist/prompts/manager.js +59 -2
- package/dist/prompts/manager.js.map +1 -1
- package/dist/tools/sync-resources.d.ts.map +1 -1
- package/dist/tools/sync-resources.js +85 -18
- package/dist/tools/sync-resources.js.map +1 -1
- package/dist/tools/uninstall-resource.d.ts.map +1 -1
- package/dist/tools/uninstall-resource.js +20 -76
- package/dist/tools/uninstall-resource.js.map +1 -1
- package/dist/utils/cursor-paths.d.ts +25 -0
- package/dist/utils/cursor-paths.d.ts.map +1 -1
- package/dist/utils/cursor-paths.js +37 -0
- package/dist/utils/cursor-paths.js.map +1 -1
- package/package.json +1 -1
- package/src/git/multi-source-manager.ts +74 -15
- package/src/prompts/manager.ts +72 -2
- package/src/tools/sync-resources.ts +118 -21
- package/src/tools/uninstall-resource.ts +23 -44
- package/src/utils/cursor-paths.ts +39 -0
|
@@ -6,46 +6,10 @@
|
|
|
6
6
|
* For MCP resources this also removes the mcpServers entry from ~/.cursor/mcp.json.
|
|
7
7
|
* For directory-based resources (skill, mcp) the entire install directory is removed.
|
|
8
8
|
*/
|
|
9
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
-
}
|
|
15
|
-
Object.defineProperty(o, k2, desc);
|
|
16
|
-
}) : (function(o, m, k, k2) {
|
|
17
|
-
if (k2 === undefined) k2 = k;
|
|
18
|
-
o[k2] = m[k];
|
|
19
|
-
}));
|
|
20
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
-
}) : function(o, v) {
|
|
23
|
-
o["default"] = v;
|
|
24
|
-
});
|
|
25
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
-
var ownKeys = function(o) {
|
|
27
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
-
var ar = [];
|
|
29
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
-
return ar;
|
|
31
|
-
};
|
|
32
|
-
return ownKeys(o);
|
|
33
|
-
};
|
|
34
|
-
return function (mod) {
|
|
35
|
-
if (mod && mod.__esModule) return mod;
|
|
36
|
-
var result = {};
|
|
37
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
-
__setModuleDefault(result, mod);
|
|
39
|
-
return result;
|
|
40
|
-
};
|
|
41
|
-
})();
|
|
42
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
10
|
exports.uninstallResourceTool = void 0;
|
|
44
11
|
exports.uninstallResource = uninstallResource;
|
|
45
|
-
const fs = __importStar(require("fs/promises"));
|
|
46
|
-
const path = __importStar(require("path"));
|
|
47
12
|
const logger_1 = require("../utils/logger");
|
|
48
|
-
const manager_1 = require("../filesystem/manager");
|
|
49
13
|
const client_1 = require("../api/client");
|
|
50
14
|
const cursor_paths_js_1 = require("../utils/cursor-paths.js");
|
|
51
15
|
const errors_1 = require("../types/errors");
|
|
@@ -113,47 +77,27 @@ async function uninstallResource(params) {
|
|
|
113
77
|
// Agent performs them on the user's LOCAL machine.
|
|
114
78
|
logger_1.logger.debug({ pattern }, 'Building local uninstall actions for Rule/MCP resource...');
|
|
115
79
|
const localActions = [];
|
|
116
|
-
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
catch { /* rules dir may not exist */ }
|
|
131
|
-
// MCP: delete install directory + remove mcp.json entry
|
|
132
|
-
try {
|
|
133
|
-
const mcpDir = (0, cursor_paths_js_1.getCursorTypeDir)('mcp');
|
|
134
|
-
const entries = await fs.readdir(mcpDir, { withFileTypes: true });
|
|
135
|
-
for (const entry of entries) {
|
|
136
|
-
if (!entry.isDirectory())
|
|
137
|
-
continue;
|
|
138
|
-
if (entry.name === pattern || entry.name.includes(pattern)) {
|
|
139
|
-
const dirPath = path.join(mcpDir, entry.name);
|
|
140
|
-
localActions.push({ action: 'delete_file', path: dirPath, recursive: true });
|
|
141
|
-
localActions.push({ action: 'remove_mcp_json_entry', mcp_json_path: mcpJsonPath, server_name: entry.name });
|
|
142
|
-
removedResources.push({ id: entry.name, name: entry.name, path: dirPath });
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
catch { /* mcp-servers dir may not exist */ }
|
|
147
|
-
// Also check Remote-URL MCPs whose entry is only in mcp.json (no local dir).
|
|
148
|
-
// The pattern might match a server name in mcp.json directly.
|
|
149
|
-
if (localActions.filter(a => a.action === 'remove_mcp_json_entry').length === 0) {
|
|
150
|
-
// Add a conditional remove action — the AI will check if the key exists.
|
|
151
|
-
localActions.push({
|
|
152
|
-
action: 'remove_mcp_json_entry',
|
|
153
|
-
mcp_json_path: mcpJsonPath,
|
|
154
|
-
server_name: pattern,
|
|
155
|
-
});
|
|
80
|
+
// Use client-side tilde-based paths; the MCP server may be running remotely
|
|
81
|
+
// and its os.homedir() would resolve to the server's home, not the user's.
|
|
82
|
+
const mcpJsonPath = `${(0, cursor_paths_js_1.getCursorRootDirForClient)()}/mcp.json`;
|
|
83
|
+
// Rule: queue delete for ~/.cursor/rules/<pattern>.mdc and .md variants.
|
|
84
|
+
// We cannot scan the server's filesystem for the user's rules, so we emit
|
|
85
|
+
// delete actions for the two common extensions and let the AI skip missing files.
|
|
86
|
+
const rulesDir = (0, cursor_paths_js_1.getCursorTypeDirForClient)('rule');
|
|
87
|
+
for (const ext of ['.mdc', '.md']) {
|
|
88
|
+
const filePath = `${rulesDir}/${pattern}${ext}`;
|
|
89
|
+
localActions.push({ action: 'delete_file', path: filePath });
|
|
90
|
+
removedResources.push({ id: pattern, name: pattern, path: filePath });
|
|
156
91
|
}
|
|
92
|
+
// MCP: queue delete of install directory (Format A) + remove mcp.json entry.
|
|
93
|
+
// For Format B (remote URL only) there is no local directory, but we still
|
|
94
|
+
// need to remove the mcp.json entry — the AI will skip the delete if the
|
|
95
|
+
// directory does not exist.
|
|
96
|
+
const mcpDir = (0, cursor_paths_js_1.getCursorTypeDirForClient)('mcp');
|
|
97
|
+
const mcpInstallDir = `${mcpDir}/${pattern}`;
|
|
98
|
+
localActions.push({ action: 'delete_file', path: mcpInstallDir, recursive: true });
|
|
99
|
+
localActions.push({ action: 'remove_mcp_json_entry', mcp_json_path: mcpJsonPath, server_name: pattern });
|
|
100
|
+
removedResources.push({ id: pattern, name: pattern, path: mcpInstallDir });
|
|
157
101
|
if (removedResources.length === 0 && localActions.length === 0) {
|
|
158
102
|
throw (0, errors_1.createValidationError)(pattern, 'resource_id_or_name', 'No installed Rule or MCP resources found matching pattern. Use search_resources to find available resources');
|
|
159
103
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uninstall-resource.js","sourceRoot":"","sources":["../../src/tools/uninstall-resource.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG
|
|
1
|
+
{"version":3,"file":"uninstall-resource.js","sourceRoot":"","sources":["../../src/tools/uninstall-resource.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,8 +15,33 @@ export declare const CURSOR_TYPE_DIRS: Record<string, string>;
|
|
|
15
15
|
*
|
|
16
16
|
* macOS / Linux : ~/.cursor
|
|
17
17
|
* Windows : %APPDATA%\Cursor\User
|
|
18
|
+
*
|
|
19
|
+
* NOTE: Only use this when running code on the USER's local machine.
|
|
20
|
+
* When generating paths for LocalAction instructions (which are executed by the
|
|
21
|
+
* AI on the user's machine, not on this server), use getCursorRootDirForClient()
|
|
22
|
+
* instead to avoid returning the server's home directory.
|
|
18
23
|
*/
|
|
19
24
|
export declare function getCursorRootDir(): string;
|
|
25
|
+
/**
|
|
26
|
+
* Returns a platform-neutral Cursor root path for use in LocalAction instructions.
|
|
27
|
+
*
|
|
28
|
+
* LocalAction paths are sent to the AI Agent running on the USER's local machine,
|
|
29
|
+
* not executed on this (possibly remote) server. Using os.homedir() here would
|
|
30
|
+
* produce the server's home directory (e.g. /root/.cursor on a Linux server),
|
|
31
|
+
* which is wrong when the user is on macOS or Windows.
|
|
32
|
+
*
|
|
33
|
+
* We return a tilde-prefixed path ("~/.cursor") which the AI / shell on the
|
|
34
|
+
* user's machine will expand to the correct home directory automatically.
|
|
35
|
+
* For Windows we still return the APPDATA-relative form as a hint, but note
|
|
36
|
+
* that the AI is expected to expand %APPDATA% on the client side.
|
|
37
|
+
*/
|
|
38
|
+
export declare function getCursorRootDirForClient(): string;
|
|
39
|
+
/**
|
|
40
|
+
* Returns the Cursor subdirectory for a given resource type, using a
|
|
41
|
+
* client-side portable path (tilde-based). Use this when building paths
|
|
42
|
+
* that will be included in LocalAction instructions.
|
|
43
|
+
*/
|
|
44
|
+
export declare function getCursorTypeDirForClient(resourceType: string): string;
|
|
20
45
|
/**
|
|
21
46
|
* Returns the Cursor subdirectory for a given resource type.
|
|
22
47
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-paths.d.ts","sourceRoot":"","sources":["../../src/utils/cursor-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CASnD,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"cursor-paths.d.ts","sourceRoot":"","sources":["../../src/utils/cursor-paths.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,iEAAiE;AACjE,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CASnD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAQzC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAGlD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAStE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAS7D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM,CAExF;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
|
|
@@ -45,6 +45,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
45
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
46
|
exports.CURSOR_TYPE_DIRS = void 0;
|
|
47
47
|
exports.getCursorRootDir = getCursorRootDir;
|
|
48
|
+
exports.getCursorRootDirForClient = getCursorRootDirForClient;
|
|
49
|
+
exports.getCursorTypeDirForClient = getCursorTypeDirForClient;
|
|
48
50
|
exports.getCursorTypeDir = getCursorTypeDir;
|
|
49
51
|
exports.getCursorResourcePath = getCursorResourcePath;
|
|
50
52
|
exports.getTelemetryFilePath = getTelemetryFilePath;
|
|
@@ -66,6 +68,11 @@ exports.CURSOR_TYPE_DIRS = {
|
|
|
66
68
|
*
|
|
67
69
|
* macOS / Linux : ~/.cursor
|
|
68
70
|
* Windows : %APPDATA%\Cursor\User
|
|
71
|
+
*
|
|
72
|
+
* NOTE: Only use this when running code on the USER's local machine.
|
|
73
|
+
* When generating paths for LocalAction instructions (which are executed by the
|
|
74
|
+
* AI on the user's machine, not on this server), use getCursorRootDirForClient()
|
|
75
|
+
* instead to avoid returning the server's home directory.
|
|
69
76
|
*/
|
|
70
77
|
function getCursorRootDir() {
|
|
71
78
|
if (process.platform === 'win32') {
|
|
@@ -76,6 +83,36 @@ function getCursorRootDir() {
|
|
|
76
83
|
// macOS and Linux both use ~/.cursor
|
|
77
84
|
return path.join(os.homedir(), '.cursor');
|
|
78
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Returns a platform-neutral Cursor root path for use in LocalAction instructions.
|
|
88
|
+
*
|
|
89
|
+
* LocalAction paths are sent to the AI Agent running on the USER's local machine,
|
|
90
|
+
* not executed on this (possibly remote) server. Using os.homedir() here would
|
|
91
|
+
* produce the server's home directory (e.g. /root/.cursor on a Linux server),
|
|
92
|
+
* which is wrong when the user is on macOS or Windows.
|
|
93
|
+
*
|
|
94
|
+
* We return a tilde-prefixed path ("~/.cursor") which the AI / shell on the
|
|
95
|
+
* user's machine will expand to the correct home directory automatically.
|
|
96
|
+
* For Windows we still return the APPDATA-relative form as a hint, but note
|
|
97
|
+
* that the AI is expected to expand %APPDATA% on the client side.
|
|
98
|
+
*/
|
|
99
|
+
function getCursorRootDirForClient() {
|
|
100
|
+
// Return a portable ~-based path; the AI on the user's machine expands it.
|
|
101
|
+
return '~/.cursor';
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Returns the Cursor subdirectory for a given resource type, using a
|
|
105
|
+
* client-side portable path (tilde-based). Use this when building paths
|
|
106
|
+
* that will be included in LocalAction instructions.
|
|
107
|
+
*/
|
|
108
|
+
function getCursorTypeDirForClient(resourceType) {
|
|
109
|
+
const subdir = exports.CURSOR_TYPE_DIRS[resourceType.toLowerCase()];
|
|
110
|
+
if (!subdir) {
|
|
111
|
+
throw new Error(`Unknown resource type "${resourceType}". ` +
|
|
112
|
+
`Supported types: ${Object.keys(exports.CURSOR_TYPE_DIRS).join(', ')}`);
|
|
113
|
+
}
|
|
114
|
+
return `${getCursorRootDirForClient()}/${subdir}`;
|
|
115
|
+
}
|
|
79
116
|
/**
|
|
80
117
|
* Returns the Cursor subdirectory for a given resource type.
|
|
81
118
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-paths.js","sourceRoot":"","sources":["../../src/utils/cursor-paths.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"cursor-paths.js","sourceRoot":"","sources":["../../src/utils/cursor-paths.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BH,4CAQC;AAeD,8DAGC;AAOD,8DASC;AAeD,4CASC;AAgBD,sDAEC;AAWD,oDAEC;AA3HD,uCAAyB;AACzB,2CAA6B;AAE7B,iEAAiE;AACpD,QAAA,gBAAgB,GAA2B;IACtD,KAAK,EAAI,QAAQ;IACjB,MAAM,EAAG,QAAQ;IACjB,OAAO,EAAE,UAAU;IACnB,QAAQ,EAAC,UAAU;IACnB,IAAI,EAAK,OAAO;IAChB,KAAK,EAAI,OAAO;IAChB,GAAG,EAAM,aAAa;IACtB,aAAa,EAAE,aAAa;CAC7B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,SAAgB,gBAAgB;IAC9B,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QACjC,6EAA6E;QAC7E,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QACrF,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC9C,CAAC;IACD,qCAAqC;IACrC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,yBAAyB;IACvC,2EAA2E;IAC3E,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,SAAgB,yBAAyB,CAAC,YAAoB;IAC5D,MAAM,MAAM,GAAG,wBAAgB,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,0BAA0B,YAAY,KAAK;YAC3C,oBAAoB,MAAM,CAAC,IAAI,CAAC,wBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,yBAAyB,EAAE,IAAI,MAAM,EAAE,CAAC;AACpD,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,gBAAgB,CAAC,YAAoB;IACnD,MAAM,MAAM,GAAG,wBAAgB,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;IAC5D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,0BAA0B,YAAY,KAAK;YAC3C,oBAAoB,MAAM,CAAC,IAAI,CAAC,wBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/D,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,MAAM,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,SAAgB,qBAAqB,CAAC,YAAoB,EAAE,YAAoB;IAC9E,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,EAAE,YAAY,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,oBAAoB;IAClC,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,4BAA4B,CAAC,CAAC;AACrE,CAAC"}
|
package/package.json
CHANGED
|
@@ -309,13 +309,34 @@ class MultiSourceGitManager {
|
|
|
309
309
|
*/
|
|
310
310
|
async readResourceFiles(
|
|
311
311
|
resourceName: string,
|
|
312
|
-
resourceType: 'command' | 'skill',
|
|
312
|
+
resourceType: 'command' | 'skill' | 'rule' | 'mcp',
|
|
313
313
|
): Promise<Array<{ path: string; content: string }>> {
|
|
314
314
|
const sources = await this.getEnabledSources();
|
|
315
315
|
// Sort by priority descending so higher-priority sources win.
|
|
316
316
|
sources.sort((a, b) => b.priority - a.priority);
|
|
317
317
|
|
|
318
|
-
|
|
318
|
+
// Map singular type names to the plural directory keys used in config.
|
|
319
|
+
const typeToDirKey: Record<string, keyof SourceConfig['resources']> = {
|
|
320
|
+
command: 'commands',
|
|
321
|
+
commands: 'commands',
|
|
322
|
+
skill: 'skills',
|
|
323
|
+
skills: 'skills',
|
|
324
|
+
rule: 'rules',
|
|
325
|
+
rules: 'rules',
|
|
326
|
+
mcp: 'mcp',
|
|
327
|
+
};
|
|
328
|
+
const typeDir = typeToDirKey[resourceType] ?? 'skills';
|
|
329
|
+
|
|
330
|
+
logger.info(
|
|
331
|
+
{
|
|
332
|
+
resourceName,
|
|
333
|
+
resourceType,
|
|
334
|
+
resolvedDirKey: typeDir,
|
|
335
|
+
sourceCount: sources.length,
|
|
336
|
+
sourceNames: sources.map((s) => s.name),
|
|
337
|
+
},
|
|
338
|
+
'readResourceFiles: start — searching git sources for resource',
|
|
339
|
+
);
|
|
319
340
|
|
|
320
341
|
for (const source of sources) {
|
|
321
342
|
const sourcePath = path.join(this.baseDir, source.path);
|
|
@@ -323,7 +344,18 @@ class MultiSourceGitManager {
|
|
|
323
344
|
const resourceDir = path.join(sourcePath, resourcesSubDir, resourceName);
|
|
324
345
|
const resourceFile = path.join(sourcePath, resourcesSubDir, `${resourceName}.md`);
|
|
325
346
|
|
|
326
|
-
|
|
347
|
+
logger.info(
|
|
348
|
+
{
|
|
349
|
+
source: source.name,
|
|
350
|
+
resourceName,
|
|
351
|
+
resourceType,
|
|
352
|
+
tryDirPath: resourceDir,
|
|
353
|
+
tryFilePath: resourceFile,
|
|
354
|
+
},
|
|
355
|
+
'readResourceFiles: trying source',
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
// Try directory-based layout first (e.g. rules/<name>/ or mcp/<name>/)
|
|
327
359
|
try {
|
|
328
360
|
const stat = await fs.stat(resourceDir);
|
|
329
361
|
if (stat.isDirectory()) {
|
|
@@ -336,28 +368,55 @@ class MultiSourceGitManager {
|
|
|
336
368
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
337
369
|
results.push({ path: f, content });
|
|
338
370
|
}
|
|
339
|
-
logger.
|
|
340
|
-
{
|
|
371
|
+
logger.info(
|
|
372
|
+
{
|
|
373
|
+
source: source.name,
|
|
374
|
+
resourceName,
|
|
375
|
+
resourceType,
|
|
376
|
+
dirPath: resourceDir,
|
|
377
|
+
fileCount: results.length,
|
|
378
|
+
files: results.map((r) => r.path),
|
|
379
|
+
},
|
|
341
380
|
'readResourceFiles: found files in directory layout',
|
|
342
381
|
);
|
|
343
382
|
return results;
|
|
344
383
|
}
|
|
384
|
+
logger.info(
|
|
385
|
+
{ source: source.name, resourceName, resourceType, dirPath: resourceDir },
|
|
386
|
+
'readResourceFiles: directory exists but contains no .md/.mdc files — trying flat file',
|
|
387
|
+
);
|
|
345
388
|
}
|
|
346
389
|
} catch { /* not a directory or doesn't exist — try flat file */ }
|
|
347
390
|
|
|
348
|
-
// Try flat file layout (e.g.
|
|
349
|
-
try
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
391
|
+
// Try flat file layout (e.g. rules/<name>.mdc or rules/<name>.md)
|
|
392
|
+
// Also try .mdc extension for rule resources.
|
|
393
|
+
const mdcFile = path.join(sourcePath, resourcesSubDir, `${resourceName}.mdc`);
|
|
394
|
+
for (const [filePath, ext] of [[resourceFile, '.md'], [mdcFile, '.mdc']] as const) {
|
|
395
|
+
try {
|
|
396
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
397
|
+
logger.info(
|
|
398
|
+
{
|
|
399
|
+
source: source.name,
|
|
400
|
+
resourceName,
|
|
401
|
+
resourceType,
|
|
402
|
+
filePath,
|
|
403
|
+
ext,
|
|
404
|
+
contentLength: content.length,
|
|
405
|
+
},
|
|
406
|
+
'readResourceFiles: found flat file',
|
|
407
|
+
);
|
|
408
|
+
return [{ path: `${resourceName}${ext}`, content }];
|
|
409
|
+
} catch { /* not found — try next extension or source */ }
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
logger.info(
|
|
413
|
+
{ source: source.name, resourceName, resourceType },
|
|
414
|
+
'readResourceFiles: resource not found in this source — trying next',
|
|
415
|
+
);
|
|
357
416
|
}
|
|
358
417
|
|
|
359
418
|
logger.warn(
|
|
360
|
-
{ resourceName, resourceType },
|
|
419
|
+
{ resourceName, resourceType, resolvedDirKey: typeDir, sourceCount: sources.length },
|
|
361
420
|
'readResourceFiles: resource not found in any git source',
|
|
362
421
|
);
|
|
363
422
|
return [];
|
package/src/prompts/manager.ts
CHANGED
|
@@ -97,8 +97,11 @@ export class PromptManager {
|
|
|
97
97
|
this.installedServers.add(server);
|
|
98
98
|
|
|
99
99
|
// List all registered prompts.
|
|
100
|
+
// A fixed setup prompt is always injected at the top of the list so that
|
|
101
|
+
// Cursor's AI Agent picks it up on connection and performs the initial sync,
|
|
102
|
+
// which writes Rule files and MCP entries to the user's local machine.
|
|
100
103
|
server.setRequestHandler(ListPromptsRequestSchema, () => {
|
|
101
|
-
const
|
|
104
|
+
const resourcePrompts = Array.from(this.prompts.values()).map(({ name, description }) => ({
|
|
102
105
|
name,
|
|
103
106
|
description,
|
|
104
107
|
arguments: [
|
|
@@ -109,13 +112,80 @@ export class PromptManager {
|
|
|
109
112
|
},
|
|
110
113
|
],
|
|
111
114
|
}));
|
|
112
|
-
|
|
115
|
+
|
|
116
|
+
const setupPrompt = {
|
|
117
|
+
name: 'csp-ai-agent-setup',
|
|
118
|
+
description:
|
|
119
|
+
'CSP AI Agent initialisation — run sync_resources and apply local actions. ' +
|
|
120
|
+
'This prompt is automatically injected and should be invoked by the AI on first connect.',
|
|
121
|
+
arguments: [],
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const prompts = [setupPrompt, ...resourcePrompts];
|
|
125
|
+
logger.info(
|
|
126
|
+
{
|
|
127
|
+
total: prompts.length,
|
|
128
|
+
setupPromptIncluded: true,
|
|
129
|
+
resourcePromptCount: resourcePrompts.length,
|
|
130
|
+
resourcePromptNames: resourcePrompts.map((p) => p.name),
|
|
131
|
+
},
|
|
132
|
+
'ListPrompts called — csp-ai-agent-setup injected as first entry',
|
|
133
|
+
);
|
|
113
134
|
return { prompts };
|
|
114
135
|
});
|
|
115
136
|
|
|
116
137
|
// Serve the content of a specific prompt.
|
|
117
138
|
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
118
139
|
const { name, arguments: args } = request.params;
|
|
140
|
+
|
|
141
|
+
// ── Setup prompt: drives initial sync + local action execution ───────────
|
|
142
|
+
if (name === 'csp-ai-agent-setup') {
|
|
143
|
+
logger.info(
|
|
144
|
+
{
|
|
145
|
+
promptName: name,
|
|
146
|
+
userToken: userToken ? `${userToken.slice(0, 12)}...` : 'none',
|
|
147
|
+
registeredPromptCount: this.prompts.size,
|
|
148
|
+
},
|
|
149
|
+
'GetPrompt: serving csp-ai-agent-setup — AI will sync resources and apply local actions',
|
|
150
|
+
);
|
|
151
|
+
const setupContent =
|
|
152
|
+
`## CSP AI Agent — Initialisation\n\n` +
|
|
153
|
+
`**[MANDATORY — Execute immediately, do not skip any step]**\n\n` +
|
|
154
|
+
`You MUST perform the following steps in order right now:\n\n` +
|
|
155
|
+
`### Step 1 — Sync AI resources\n` +
|
|
156
|
+
`Call the \`sync_resources\` tool with:\n` +
|
|
157
|
+
`- \`mode\`: \`"incremental"\`\n` +
|
|
158
|
+
`- \`scope\`: \`"global"\`\n\n` +
|
|
159
|
+
`### Step 2 — Apply local actions\n` +
|
|
160
|
+
`If the \`sync_resources\` result contains a \`local_actions_required\` array, ` +
|
|
161
|
+
`you MUST execute every action in it on the user's LOCAL machine:\n\n` +
|
|
162
|
+
`- **\`write_file\`**: Create the file at the given \`path\` with the given \`content\`. ` +
|
|
163
|
+
`Expand \`~\` to the user's home directory. Create parent directories if they do not exist.\n` +
|
|
164
|
+
`- **\`merge_mcp_json\`**: Read \`~/.cursor/mcp.json\` (create if missing), ` +
|
|
165
|
+
`add or update the entry under \`mcpServers[server_name]\` with the provided \`entry\` object, ` +
|
|
166
|
+
`then write the file back. Do not remove existing entries.\n` +
|
|
167
|
+
`- **\`delete_file\`**: Delete the file or directory at \`path\`. ` +
|
|
168
|
+
`If \`recursive\` is true, delete the directory and all its contents. Skip if it does not exist.\n` +
|
|
169
|
+
`- **\`remove_mcp_json_entry\`**: Read \`~/.cursor/mcp.json\`, ` +
|
|
170
|
+
`remove the entry at \`mcpServers[server_name]\` if it exists, then write the file back.\n\n` +
|
|
171
|
+
`### Step 3 — Report\n` +
|
|
172
|
+
`After completing all steps, briefly tell the user:\n` +
|
|
173
|
+
`- How many resources were synced\n` +
|
|
174
|
+
`- Which local files/MCP entries were written (if any)\n` +
|
|
175
|
+
`- Any failures or pending manual actions\n\n` +
|
|
176
|
+
`Do NOT ask the user for confirmation before starting. Begin immediately.\n`;
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
description: 'CSP AI Agent initialisation — sync resources and apply local actions',
|
|
180
|
+
messages: [
|
|
181
|
+
{
|
|
182
|
+
role: 'user' as const,
|
|
183
|
+
content: { type: 'text' as const, text: setupContent },
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
119
189
|
const registered = this.prompts.get(name);
|
|
120
190
|
|
|
121
191
|
logger.info(
|