@nexrall/code-core 1.4.71 → 1.4.72
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/agent/agentRegistry.d.ts.map +1 -1
- package/dist/agent/agentRegistry.js +28 -10
- package/dist/agent/agentTypes.d.ts.map +1 -1
- package/dist/agent/agentTypes.js +159 -48
- package/dist/agent/askOnce.d.ts.map +1 -1
- package/dist/agent/askOnce.js +14 -5
- package/dist/agent/backgroundAgents.d.ts.map +1 -1
- package/dist/agent/backgroundAgents.js +22 -8
- package/dist/agent/claimEvidence.d.ts.map +1 -1
- package/dist/agent/claimEvidence.js +2 -1
- package/dist/agent/compaction.d.ts.map +1 -1
- package/dist/agent/compaction.js +31 -10
- package/dist/agent/crossProcessLock.d.ts.map +1 -1
- package/dist/agent/crossProcessLock.js +14 -6
- package/dist/agent/editCompleteness.d.ts.map +1 -1
- package/dist/agent/fileLocks.d.ts.map +1 -1
- package/dist/agent/fileLocks.js +14 -5
- package/dist/agent/flaky.d.ts.map +1 -1
- package/dist/agent/hooks.d.ts.map +1 -1
- package/dist/agent/hooks.js +284 -75
- package/dist/agent/iterationPolicy.d.ts.map +1 -1
- package/dist/agent/iterationPolicy.js +26 -23
- package/dist/agent/lifecycleHost.d.ts.map +1 -1
- package/dist/agent/lifecycleHost.js +35 -11
- package/dist/agent/loop.d.ts +22 -4
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +223 -51
- package/dist/agent/memory.d.ts.map +1 -1
- package/dist/agent/memory.js +13 -7
- package/dist/agent/modelCatalogue.d.ts.map +1 -1
- package/dist/agent/modelCatalogue.js +4 -1
- package/dist/agent/nestedInstructions.d.ts +122 -0
- package/dist/agent/nestedInstructions.d.ts.map +1 -0
- package/dist/agent/nestedInstructions.js +696 -0
- package/dist/agent/peerRegistry.d.ts.map +1 -1
- package/dist/agent/peerRegistry.js +44 -6
- package/dist/agent/peerTransport.d.ts.map +1 -1
- package/dist/agent/peerTransport.js +18 -6
- package/dist/agent/planMode.d.ts.map +1 -1
- package/dist/agent/planMode.js +194 -41
- package/dist/agent/readDedupe.d.ts.map +1 -1
- package/dist/agent/readDedupe.js +3 -1
- package/dist/agent/securityLint.d.ts.map +1 -1
- package/dist/agent/sharedTasks.d.ts.map +1 -1
- package/dist/agent/sharedTasks.js +20 -5
- package/dist/agent/skills.d.ts +79 -0
- package/dist/agent/skills.d.ts.map +1 -1
- package/dist/agent/skills.js +403 -14
- package/dist/agent/subAgentBudget.d.ts.map +1 -1
- package/dist/agent/subTask.d.ts.map +1 -1
- package/dist/agent/subTask.js +87 -37
- package/dist/agent/subTaskSupport.d.ts.map +1 -1
- package/dist/agent/subTaskSupport.js +43 -14
- package/dist/agent/testIntegrity.d.ts.map +1 -1
- package/dist/agent/testIntegrity.js +4 -2
- package/dist/agent/toolDescriptions.d.ts.map +1 -1
- package/dist/agent/toolPrefetch.d.ts.map +1 -1
- package/dist/agent/toolPrefetch.js +15 -11
- package/dist/agent/trust.d.ts.map +1 -1
- package/dist/agent/trust.js +6 -2
- package/dist/agent/worktree.d.ts.map +1 -1
- package/dist/agent/worktree.js +70 -16
- package/dist/agent/worktreeEnforcement.d.ts.map +1 -1
- package/dist/agent/worktreeEnforcement.js +9 -4
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +63 -31
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +3 -1
- package/dist/checkpoint/manager.d.ts.map +1 -1
- package/dist/checkpoint/manager.js +22 -7
- package/dist/commands/loader.d.ts.map +1 -1
- package/dist/commands/loader.js +6 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/mcp/client.d.ts +34 -0
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/mcp/client.js +89 -24
- package/dist/mcp/httpClient.d.ts +24 -1
- package/dist/mcp/httpClient.d.ts.map +1 -1
- package/dist/mcp/httpClient.js +80 -14
- package/dist/mcp/instructions.d.ts +11 -0
- package/dist/mcp/instructions.d.ts.map +1 -0
- package/dist/mcp/instructions.js +42 -0
- package/dist/mcp/manager.d.ts +24 -0
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +117 -24
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +48 -14
- package/dist/mcp/sseClient.d.ts +9 -1
- package/dist/mcp/sseClient.d.ts.map +1 -1
- package/dist/mcp/sseClient.js +43 -10
- package/dist/mcp/stats.d.ts.map +1 -1
- package/dist/permissions/bashClassify.d.ts.map +1 -1
- package/dist/permissions/bashClassify.js +25 -3
- package/dist/permissions/destructive.d.ts.map +1 -1
- package/dist/permissions/destructive.js +7 -2
- package/dist/permissions/destructiveTokens.d.ts.map +1 -1
- package/dist/permissions/destructiveTokens.js +104 -24
- package/dist/permissions/modePolicy.d.ts.map +1 -1
- package/dist/permissions/modePolicy.js +40 -17
- package/dist/permissions/rules.d.ts.map +1 -1
- package/dist/permissions/rules.js +7 -5
- package/dist/plugins/data.d.ts.map +1 -1
- package/dist/plugins/data.js +6 -2
- package/dist/plugins/index.d.ts.map +1 -1
- package/dist/plugins/index.js +18 -7
- package/dist/plugins/installer.d.ts.map +1 -1
- package/dist/plugins/installer.js +17 -10
- package/dist/plugins/sources.d.ts.map +1 -1
- package/dist/plugins/sources.js +9 -3
- package/dist/tools/executor.d.ts.map +1 -1
- package/dist/tools/executor.js +454 -168
- package/dist/tools/sandbox.d.ts.map +1 -1
- package/dist/tools/sandbox.js +5 -1
- package/dist/tools/symbols.d.ts.map +1 -1
- package/dist/tools/symbols.js +30 -8
- package/dist/tools/tsLangService.d.ts.map +1 -1
- package/dist/tools/tsLangService.js +12 -4
- package/dist/types.d.ts +17 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/util/frontmatter.d.ts.map +1 -1
- package/dist/util/miniYaml.d.ts.map +1 -1
- package/dist/util/miniYaml.js +3 -1
- package/package.json +1 -1
package/dist/mcp/manager.js
CHANGED
|
@@ -76,6 +76,36 @@ class McpManager {
|
|
|
76
76
|
for (const client of this._clients.values())
|
|
77
77
|
client.setElicitationHandler(handler);
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Route server→client notifications for one client: `tools/list_changed` re-fetches
|
|
81
|
+
* the tool table and rebuilds the prefixed map in place (new tools appear on the next
|
|
82
|
+
* turn — no restart), `prompts/list_changed` drops the cached prompt list. A failed
|
|
83
|
+
* refresh keeps the OLD table: a transient error must not empty the toolset.
|
|
84
|
+
*/
|
|
85
|
+
_wireNotifications(name, client) {
|
|
86
|
+
client.setNotificationHandler((method) => {
|
|
87
|
+
if (method === 'notifications/tools/list_changed') {
|
|
88
|
+
void client
|
|
89
|
+
.refreshTools()
|
|
90
|
+
.then(() => this._refreshToolMap(name, client.tools))
|
|
91
|
+
.catch(() => {
|
|
92
|
+
/* keep the old table on failure */
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
else if (method === 'notifications/prompts/list_changed') {
|
|
96
|
+
this._promptCache.delete(name);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/** Replace one server's entries in the prefixed tool map with its current list. */
|
|
101
|
+
_refreshToolMap(name, tools) {
|
|
102
|
+
for (const key of [...this._toolMap.keys()]) {
|
|
103
|
+
if (this._toolMap.get(key) === name)
|
|
104
|
+
this._toolMap.delete(key);
|
|
105
|
+
}
|
|
106
|
+
for (const tool of tools)
|
|
107
|
+
this._toolMap.set(`${name}__${tool.name}`, name);
|
|
108
|
+
}
|
|
79
109
|
/** Pick the transport for a server config: stdio (command), Streamable HTTP, or legacy SSE. */
|
|
80
110
|
static makeClient(name, cfg) {
|
|
81
111
|
if (cfg.type === 'sse')
|
|
@@ -91,11 +121,10 @@ class McpManager {
|
|
|
91
121
|
try {
|
|
92
122
|
Object.assign(merged.mcpServers, (0, index_1.pluginMcpServers)(workDir));
|
|
93
123
|
}
|
|
94
|
-
catch {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
];
|
|
124
|
+
catch {
|
|
125
|
+
/* plugin scan is best-effort */
|
|
126
|
+
}
|
|
127
|
+
const locations = [path.join(os.homedir(), '.nexrall', 'mcp.json'), path.join(workDir, '.nexrall', 'mcp.json')];
|
|
99
128
|
// A list, so the two scopes UNION rather than override: switching a server off in
|
|
100
129
|
// the project must add to whatever the user file already silences.
|
|
101
130
|
const disabled = new Set();
|
|
@@ -128,16 +157,14 @@ class McpManager {
|
|
|
128
157
|
}
|
|
129
158
|
const client = McpManager.makeClient(name, serverCfg);
|
|
130
159
|
client.setElicitationHandler(this._elicitationHandler);
|
|
160
|
+
this._wireNotifications(name, client);
|
|
131
161
|
try {
|
|
132
162
|
await client.connect();
|
|
133
163
|
this._clients.set(name, client);
|
|
134
164
|
this._errors.delete(name);
|
|
135
165
|
this._needsAuth.delete(name);
|
|
136
166
|
// Register tools with prefixed names: serverName__toolName
|
|
137
|
-
|
|
138
|
-
const prefixed = `${name}__${tool.name}`;
|
|
139
|
-
this._toolMap.set(prefixed, name);
|
|
140
|
-
}
|
|
167
|
+
this._refreshToolMap(name, client.tools);
|
|
141
168
|
}
|
|
142
169
|
catch (err) {
|
|
143
170
|
if (err instanceof httpClient_1.McpOAuthRequiredError) {
|
|
@@ -204,7 +231,21 @@ class McpManager {
|
|
|
204
231
|
// stats of two servers with a same-named tool never merge.
|
|
205
232
|
const startedAt = Date.now();
|
|
206
233
|
this.stats.begin();
|
|
207
|
-
const timed = (p) => p.then((v) => {
|
|
234
|
+
const timed = (p) => p.then((v) => {
|
|
235
|
+
this.stats.ok(prefixedName, Date.now() - startedAt);
|
|
236
|
+
return v;
|
|
237
|
+
}, (e) => {
|
|
238
|
+
this.stats.fail(prefixedName, Date.now() - startedAt, e.message || String(e));
|
|
239
|
+
throw e;
|
|
240
|
+
});
|
|
241
|
+
// A 401 mid-CALL is different from one at connect: the server is already up and
|
|
242
|
+
// some tools work — record it so /mcp flips to needs-auth (with the missing
|
|
243
|
+
// scope) and let the enriched message reach the caller (the model sees WHY).
|
|
244
|
+
const trackAuth = (p) => p.catch((err) => {
|
|
245
|
+
if (err instanceof httpClient_1.McpOAuthRequiredError)
|
|
246
|
+
this._needsAuth.set(serverName, err.wwwAuthenticate);
|
|
247
|
+
throw err;
|
|
248
|
+
});
|
|
208
249
|
const racers = [timed(client.callTool(toolName, input)), timed(timeoutPromise)];
|
|
209
250
|
if (abortSignal) {
|
|
210
251
|
let pollId;
|
|
@@ -220,9 +261,9 @@ class McpManager {
|
|
|
220
261
|
// Clearing the poll on whichever branch wins avoids leaving a live interval
|
|
221
262
|
// (and the closure it holds) running for the rest of the process lifetime —
|
|
222
263
|
// the same leak-prevention pattern client.ts uses for its own abort poll.
|
|
223
|
-
return Promise.race(racers).finally(() => clearInterval(pollId));
|
|
264
|
+
return trackAuth(Promise.race(racers).finally(() => clearInterval(pollId)));
|
|
224
265
|
}
|
|
225
|
-
return Promise.race(racers);
|
|
266
|
+
return trackAuth(Promise.race(racers));
|
|
226
267
|
}
|
|
227
268
|
/** Resources across connected, enabled servers. One server failing never hides the others. */
|
|
228
269
|
async listResources(server) {
|
|
@@ -241,7 +282,9 @@ class McpManager {
|
|
|
241
282
|
if (!client)
|
|
242
283
|
throw new Error(`No connected MCP server named "${server}". Connected: ${[...this._clients.keys()].join(', ') || '(none)'}`);
|
|
243
284
|
let timer;
|
|
244
|
-
const timeout = new Promise((_, rej) => {
|
|
285
|
+
const timeout = new Promise((_, rej) => {
|
|
286
|
+
timer = setTimeout(() => rej(new Error(`Reading ${uri} timed out after 60s`)), 60000);
|
|
287
|
+
});
|
|
245
288
|
try {
|
|
246
289
|
return await Promise.race([client.readResource(uri), timeout]);
|
|
247
290
|
}
|
|
@@ -300,13 +343,18 @@ class McpManager {
|
|
|
300
343
|
throw new Error(`MCP prompt "${server}:${name}" takes ${declared.length} argument(s)${declared.length ? ` (${declared.map((a) => a.name).join(', ')})` : ''} — got ${values.length}.`);
|
|
301
344
|
}
|
|
302
345
|
const args = {};
|
|
303
|
-
declared.forEach((a, i) => {
|
|
304
|
-
|
|
346
|
+
declared.forEach((a, i) => {
|
|
347
|
+
const v = values[i];
|
|
348
|
+
if (v !== undefined && v !== '')
|
|
349
|
+
args[a.name] = v;
|
|
350
|
+
});
|
|
305
351
|
const missing = declared.filter((a) => a.required && args[a.name] === undefined);
|
|
306
352
|
if (missing.length)
|
|
307
353
|
throw new Error(`MCP prompt "${server}:${name}" is missing required argument(s): ${missing.map((a) => a.name).join(', ')}.`);
|
|
308
354
|
let timer;
|
|
309
|
-
const timeout = new Promise((_, rej) => {
|
|
355
|
+
const timeout = new Promise((_, rej) => {
|
|
356
|
+
timer = setTimeout(() => rej(new Error(`MCP prompt ${server}:${name} timed out after 60s`)), 60000);
|
|
357
|
+
});
|
|
310
358
|
try {
|
|
311
359
|
return await Promise.race([client.getPrompt(name, args), timeout]);
|
|
312
360
|
}
|
|
@@ -334,7 +382,18 @@ class McpManager {
|
|
|
334
382
|
getStatus() {
|
|
335
383
|
const out = [];
|
|
336
384
|
for (const [name, client] of this._clients) {
|
|
337
|
-
out.push({
|
|
385
|
+
out.push({
|
|
386
|
+
name,
|
|
387
|
+
transport: McpManager.transportOf(this._configs.get(name)),
|
|
388
|
+
tools: client.tools,
|
|
389
|
+
connected: true,
|
|
390
|
+
disabled: false,
|
|
391
|
+
// A server can be UP and still have recorded a 401 from a mid-call
|
|
392
|
+
// insufficient_scope challenge — the row says so, the detail says which scope.
|
|
393
|
+
needsAuth: this._needsAuth.has(name),
|
|
394
|
+
missingScope: this.missingScope(name) || undefined,
|
|
395
|
+
protocolVersion: client.protocolVersion,
|
|
396
|
+
});
|
|
338
397
|
}
|
|
339
398
|
for (const name of this._configs.keys()) {
|
|
340
399
|
if (this._clients.has(name))
|
|
@@ -344,12 +403,24 @@ class McpManager {
|
|
|
344
403
|
// A disabled server that never connected has no error to report — say nothing
|
|
345
404
|
// rather than repeat "disconnected" as if it were a failure.
|
|
346
405
|
if (disabled && !error) {
|
|
347
|
-
out.push({
|
|
406
|
+
out.push({
|
|
407
|
+
name,
|
|
408
|
+
transport: McpManager.transportOf(this._configs.get(name)),
|
|
409
|
+
tools: [],
|
|
410
|
+
connected: false,
|
|
411
|
+
disabled: true,
|
|
412
|
+
});
|
|
348
413
|
continue;
|
|
349
414
|
}
|
|
350
415
|
out.push({
|
|
351
|
-
name,
|
|
352
|
-
|
|
416
|
+
name,
|
|
417
|
+
transport: McpManager.transportOf(this._configs.get(name)),
|
|
418
|
+
tools: [],
|
|
419
|
+
connected: false,
|
|
420
|
+
disabled,
|
|
421
|
+
error,
|
|
422
|
+
needsAuth: this._needsAuth.has(name),
|
|
423
|
+
missingScope: this.missingScope(name) || undefined,
|
|
353
424
|
});
|
|
354
425
|
}
|
|
355
426
|
return out.sort((a, b) => a.name.localeCompare(b.name));
|
|
@@ -358,6 +429,23 @@ class McpManager {
|
|
|
358
429
|
authChallenge(name) {
|
|
359
430
|
return this._needsAuth.get(name) ?? '';
|
|
360
431
|
}
|
|
432
|
+
/** Permissions an auth-required server says are missing ('' when unknown/plain 401). */
|
|
433
|
+
missingScope(name) {
|
|
434
|
+
return (0, httpClient_1.parseOAuthChallenge)(this._needsAuth.get(name) ?? '').scope ?? '';
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* `initialize.instructions` from every connected server that sent one — static
|
|
438
|
+
* reference notes (workflow rules, repo layout) the conversation should carry.
|
|
439
|
+
* The caller decides where they go; ordering is by server name for stable output.
|
|
440
|
+
*/
|
|
441
|
+
serverInstructions() {
|
|
442
|
+
const out = [];
|
|
443
|
+
for (const [name, client] of this._clients) {
|
|
444
|
+
if (client.instructions)
|
|
445
|
+
out.push({ server: name, instructions: client.instructions });
|
|
446
|
+
}
|
|
447
|
+
return out.sort((a, b) => a.server.localeCompare(b.server));
|
|
448
|
+
}
|
|
361
449
|
/** True when the user has switched this server off for the session. */
|
|
362
450
|
isDisabled(name) {
|
|
363
451
|
return this._disabled.has(name);
|
|
@@ -386,6 +474,7 @@ class McpManager {
|
|
|
386
474
|
this._dropClient(name);
|
|
387
475
|
const client = McpManager.makeClient(name, cfg);
|
|
388
476
|
client.setElicitationHandler(this._elicitationHandler);
|
|
477
|
+
this._wireNotifications(name, client);
|
|
389
478
|
try {
|
|
390
479
|
await client.connect();
|
|
391
480
|
}
|
|
@@ -399,8 +488,7 @@ class McpManager {
|
|
|
399
488
|
this._clients.set(name, client);
|
|
400
489
|
this._errors.delete(name);
|
|
401
490
|
this._needsAuth.delete(name);
|
|
402
|
-
|
|
403
|
-
this._toolMap.set(`${name}__${tool.name}`, name);
|
|
491
|
+
this._refreshToolMap(name, client.tools);
|
|
404
492
|
return null;
|
|
405
493
|
}
|
|
406
494
|
/** Disconnect one server for the session (its config stays; `enable` brings it back). */
|
|
@@ -415,9 +503,12 @@ class McpManager {
|
|
|
415
503
|
const client = this._clients.get(name);
|
|
416
504
|
if (client) {
|
|
417
505
|
try {
|
|
506
|
+
client.setNotificationHandler(null);
|
|
418
507
|
client.disconnect();
|
|
419
508
|
}
|
|
420
|
-
catch {
|
|
509
|
+
catch {
|
|
510
|
+
/* best effort */
|
|
511
|
+
}
|
|
421
512
|
}
|
|
422
513
|
this._clients.delete(name);
|
|
423
514
|
for (const key of [...this._toolMap.keys()]) {
|
|
@@ -491,7 +582,9 @@ class McpManager {
|
|
|
491
582
|
if ((0, index_1.pluginMcpServers)(workDir)[name])
|
|
492
583
|
return 'plugin';
|
|
493
584
|
}
|
|
494
|
-
catch {
|
|
585
|
+
catch {
|
|
586
|
+
/* plugin scan is best-effort */
|
|
587
|
+
}
|
|
495
588
|
return 'none';
|
|
496
589
|
}
|
|
497
590
|
/** Remove a server from whichever scope(s) define it. Returns true if anything was removed. */
|
package/dist/mcp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAGjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAI3C,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CACpF;AAED,MAAM,WAAW,YAAY;IAC3B,4EAA4E;IAC5E,OAAO,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;IACxB,0DAA0D;IAC1D,KAAK,CAAC,EAAE,QAAQ,CAAC;IACjB,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,wDAAwD;IACxD,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAaD;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,EAAE,CA8ClD;AAcD;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAyIhE"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.readOnlyMcpTools = readOnlyMcpTools;
|
|
16
16
|
exports.serveMcp = serveMcp;
|
|
17
17
|
const executor_1 = require("../tools/executor");
|
|
18
|
+
const client_1 = require("./client");
|
|
18
19
|
// ─── The toolset ──────────────────────────────────────────────────────────────
|
|
19
20
|
/** Wrap one executor tool. The executor is the single source of behaviour — same caps, same
|
|
20
21
|
* error messages, same path resolution as the CLI's own turns. */
|
|
@@ -31,32 +32,52 @@ const fromExecutor = (name, description, inputSchema) => ({
|
|
|
31
32
|
*/
|
|
32
33
|
function readOnlyMcpTools() {
|
|
33
34
|
return [
|
|
34
|
-
fromExecutor('read_file', 'Read a text file. Returns numbered lines so later edits can cite them. Binary files are refused.', {
|
|
35
|
+
fromExecutor('read_file', 'Read a text file. Returns numbered lines so later edits can cite them. Binary files are refused.', {
|
|
36
|
+
type: 'object',
|
|
37
|
+
properties: {
|
|
35
38
|
path: { type: 'string', description: 'File path, absolute or relative to the workspace root' },
|
|
36
39
|
offset: { type: 'number', description: '0-based line to start from (default 0)' },
|
|
37
40
|
limit: { type: 'number', description: 'How many lines to return' },
|
|
38
|
-
},
|
|
39
|
-
|
|
41
|
+
},
|
|
42
|
+
required: ['path'],
|
|
43
|
+
}),
|
|
44
|
+
fromExecutor('list_directory', 'List the entries of a directory, each marked as file or directory.', {
|
|
45
|
+
type: 'object',
|
|
46
|
+
properties: {
|
|
40
47
|
path: { type: 'string', description: 'Directory path (default: the workspace root)' },
|
|
41
|
-
}
|
|
42
|
-
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
fromExecutor('glob', 'Find files by glob pattern, e.g. "**/*.ts" or "src/**/*.test.js".', {
|
|
51
|
+
type: 'object',
|
|
52
|
+
properties: {
|
|
43
53
|
pattern: { type: 'string', description: 'Glob pattern' },
|
|
44
54
|
path: { type: 'string', description: 'Directory to search from (default: the workspace root)' },
|
|
45
|
-
},
|
|
46
|
-
|
|
55
|
+
},
|
|
56
|
+
required: ['pattern'],
|
|
57
|
+
}),
|
|
58
|
+
fromExecutor('search_files', 'Search file contents with a regular expression. Returns matching file paths by default; ask for context lines to get the matches themselves.', {
|
|
59
|
+
type: 'object',
|
|
60
|
+
properties: {
|
|
47
61
|
pattern: { type: 'string', description: 'Regular expression' },
|
|
48
62
|
path: { type: 'string', description: 'Directory to search (default: the workspace root)' },
|
|
49
63
|
type: { type: 'string', description: '"files" (paths only) or "content" (matching lines)' },
|
|
50
64
|
include: { type: 'string', description: 'Only files matching this glob, e.g. "*.ts"' },
|
|
51
65
|
case_insensitive: { type: 'boolean', description: 'Case-insensitive match' },
|
|
52
66
|
context_lines: { type: 'number', description: 'Lines of context around each match (implies type "content")' },
|
|
53
|
-
},
|
|
67
|
+
},
|
|
68
|
+
required: ['pattern'],
|
|
69
|
+
}),
|
|
54
70
|
];
|
|
55
71
|
}
|
|
56
72
|
// ─── Protocol ─────────────────────────────────────────────────────────────────
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
73
|
+
// Shared with the client half of the module so the two cannot drift. All listed
|
|
74
|
+
// revisions have the same framing for our surface (initialize/tools/resources);
|
|
75
|
+
// when a client asks for a revision we do not implement, the answer is the LATEST
|
|
76
|
+
// we do — that is what the MCP spec requires ("another protocol version it
|
|
77
|
+
// supports, preferably the latest"), and it keeps modern clients on a modern
|
|
78
|
+
// negotiation instead of downgrading them to the 2024 framing by default.
|
|
79
|
+
const SUPPORTED_PROTOCOLS = client_1.MCP_PROTOCOL_VERSIONS;
|
|
80
|
+
const DEFAULT_PROTOCOL = client_1.MCP_PROTOCOL_VERSION;
|
|
60
81
|
const SERVER_NAME = 'nexrall';
|
|
61
82
|
/**
|
|
62
83
|
* Serve MCP on stdio until the client closes the pipe. Resolves (never rejects) at EOF — the
|
|
@@ -69,7 +90,9 @@ async function serveMcp(opts) {
|
|
|
69
90
|
const tools = opts.tools ?? readOnlyMcpTools();
|
|
70
91
|
const version = opts.version ?? '0.0.0';
|
|
71
92
|
const byName = new Map(tools.map((t) => [t.name, t]));
|
|
72
|
-
const send = (msg) => {
|
|
93
|
+
const send = (msg) => {
|
|
94
|
+
output.write(JSON.stringify(msg) + '\n');
|
|
95
|
+
};
|
|
73
96
|
const reply = (id, result) => send({ jsonrpc: '2.0', id, result });
|
|
74
97
|
const replyError = (id, code, message) => send({ jsonrpc: '2.0', id, error: { code, message } });
|
|
75
98
|
async function handle(message) {
|
|
@@ -110,7 +133,15 @@ async function serveMcp(opts) {
|
|
|
110
133
|
if (!tool) {
|
|
111
134
|
// A RESULT, not a protocol error: the calling model should read "not offered" as tool
|
|
112
135
|
// output and pick another route, not see the whole call fail.
|
|
113
|
-
reply(id, {
|
|
136
|
+
reply(id, {
|
|
137
|
+
content: [
|
|
138
|
+
{
|
|
139
|
+
type: 'text',
|
|
140
|
+
text: `Tool "${name}" is not offered by this server (read-only). Available: ${[...byName.keys()].join(', ')}.`,
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
isError: true,
|
|
144
|
+
});
|
|
114
145
|
return;
|
|
115
146
|
}
|
|
116
147
|
try {
|
|
@@ -122,7 +153,10 @@ async function serveMcp(opts) {
|
|
|
122
153
|
}
|
|
123
154
|
catch (err) {
|
|
124
155
|
// A throwing tool is the tool's problem, not the session's — answer and keep serving.
|
|
125
|
-
reply(id, {
|
|
156
|
+
reply(id, {
|
|
157
|
+
content: [{ type: 'text', text: err instanceof Error ? err.message : String(err) }],
|
|
158
|
+
isError: true,
|
|
159
|
+
});
|
|
126
160
|
}
|
|
127
161
|
return;
|
|
128
162
|
}
|
package/dist/mcp/sseClient.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServerConfig, McpToolDefinition, McpTransport, McpResource, McpPrompt, McpElicitationHandler } from './client';
|
|
1
|
+
import type { McpServerConfig, McpToolDefinition, McpTransport, McpResource, McpPrompt, McpElicitationHandler, McpNotificationHandler } from './client';
|
|
2
2
|
export declare class McpSseClient implements McpTransport {
|
|
3
3
|
private readonly config;
|
|
4
4
|
private _nextId;
|
|
@@ -10,11 +10,19 @@ export declare class McpSseClient implements McpTransport {
|
|
|
10
10
|
private readonly _pending;
|
|
11
11
|
private _endpointWaiter;
|
|
12
12
|
private _elicitationHandler;
|
|
13
|
+
private _notificationHandler;
|
|
14
|
+
private _protocolVersion;
|
|
15
|
+
private _instructions;
|
|
13
16
|
readonly name: string;
|
|
14
17
|
constructor(name: string, config: McpServerConfig);
|
|
15
18
|
get tools(): McpToolDefinition[];
|
|
19
|
+
get protocolVersion(): string | undefined;
|
|
20
|
+
get instructions(): string | undefined;
|
|
16
21
|
setElicitationHandler(handler: McpElicitationHandler | null): void;
|
|
22
|
+
setNotificationHandler(handler: McpNotificationHandler | null): void;
|
|
17
23
|
connect(): Promise<void>;
|
|
24
|
+
/** Re-fetch `tools/list` (see McpClient.refreshTools for the failure rule). */
|
|
25
|
+
refreshTools(): Promise<void>;
|
|
18
26
|
listResources(): Promise<McpResource[]>;
|
|
19
27
|
readResource(uri: string): Promise<string>;
|
|
20
28
|
listPrompts(): Promise<McpPrompt[]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sseClient.d.ts","sourceRoot":"","sources":["../../src/mcp/sseClient.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sseClient.d.ts","sourceRoot":"","sources":["../../src/mcp/sseClient.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EACV,eAAe,EACf,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,UAAU,CAAC;AA6BlB,qBAAa,YAAa,YAAW,YAAY;IAoB7C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAnBzB,OAAO,CAAC,OAAO,CAAK;IACpB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,OAAO,CAAM;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAGrB;IACJ,OAAO,CAAC,eAAe,CAAoE;IAC3F,OAAO,CAAC,mBAAmB,CAAsC;IACjE,OAAO,CAAC,oBAAoB,CAAuC;IACnE,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,aAAa,CAAqB;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAGpB,IAAI,EAAE,MAAM,EACK,MAAM,EAAE,eAAe;IAK1C,IAAI,KAAK,IAAI,iBAAiB,EAAE,CAE/B;IAED,IAAI,eAAe,IAAI,MAAM,GAAG,SAAS,CAExC;IAED,IAAI,YAAY,IAAI,MAAM,GAAG,SAAS,CAErC;IAED,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,GAAG,IAAI;IAIlE,sBAAsB,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,GAAG,IAAI;IAI9D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB9B,+EAA+E;IACzE,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAK7B,aAAa,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IASvC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAI1C,WAAW,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IASnC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAMtE,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC;IAc5E,UAAU,IAAI,IAAI;IAalB,4EAA4E;YAC9D,WAAW;IA4CzB,OAAO,CAAC,eAAe;IAYvB,oFAAoF;IACpF,OAAO,CAAC,KAAK;IAWb,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,cAAc;IA0DtB,OAAO,CAAC,IAAI;YAoBE,OAAO;IAIrB,6EAA6E;YAC/D,YAAY;CAwB3B"}
|
package/dist/mcp/sseClient.js
CHANGED
|
@@ -21,22 +21,42 @@ class McpSseClient {
|
|
|
21
21
|
this._pending = new Map();
|
|
22
22
|
this._endpointWaiter = null;
|
|
23
23
|
this._elicitationHandler = null;
|
|
24
|
+
this._notificationHandler = null;
|
|
24
25
|
this.name = name;
|
|
25
26
|
}
|
|
26
27
|
get tools() {
|
|
27
28
|
return this._tools;
|
|
28
29
|
}
|
|
29
|
-
|
|
30
|
+
get protocolVersion() {
|
|
31
|
+
return this._protocolVersion;
|
|
32
|
+
}
|
|
33
|
+
get instructions() {
|
|
34
|
+
return this._instructions;
|
|
35
|
+
}
|
|
36
|
+
setElicitationHandler(handler) {
|
|
37
|
+
this._elicitationHandler = handler;
|
|
38
|
+
}
|
|
39
|
+
setNotificationHandler(handler) {
|
|
40
|
+
this._notificationHandler = handler;
|
|
41
|
+
}
|
|
30
42
|
async connect() {
|
|
31
43
|
if (!this.config.url)
|
|
32
44
|
throw new Error(`MCP server "${this.name}" has no url (sse transport requires one).`);
|
|
33
45
|
await this._openStream();
|
|
34
|
-
await this._rpc('initialize', {
|
|
35
|
-
protocolVersion:
|
|
46
|
+
const init = (await this._rpc('initialize', {
|
|
47
|
+
protocolVersion: client_1.MCP_PROTOCOL_VERSION,
|
|
36
48
|
capabilities: (0, client_1.elicitationCapability)(this.config.bareElicitationCapability),
|
|
37
49
|
clientInfo: { name: 'nexrall-code', version: '1.0' },
|
|
38
|
-
});
|
|
50
|
+
}));
|
|
51
|
+
this._protocolVersion =
|
|
52
|
+
typeof init?.protocolVersion === 'string' && init.protocolVersion ? init.protocolVersion : undefined;
|
|
53
|
+
this._instructions =
|
|
54
|
+
typeof init?.instructions === 'string' && init.instructions.trim() ? init.instructions : undefined;
|
|
39
55
|
await this._notify('notifications/initialized');
|
|
56
|
+
await this.refreshTools();
|
|
57
|
+
}
|
|
58
|
+
/** Re-fetch `tools/list` (see McpClient.refreshTools for the failure rule). */
|
|
59
|
+
async refreshTools() {
|
|
40
60
|
const res = (await this._rpc('tools/list', {}));
|
|
41
61
|
this._tools = res?.tools ?? [];
|
|
42
62
|
}
|
|
@@ -111,8 +131,10 @@ class McpSseClient {
|
|
|
111
131
|
const stream = resp.body;
|
|
112
132
|
stream.on('data', (chunk) => this._feed(chunk.toString('utf-8')));
|
|
113
133
|
stream.on('end', () => this._onStreamClosed(new Error('MCP SSE stream ended')));
|
|
114
|
-
stream.on('error', (err) => {
|
|
115
|
-
this.
|
|
134
|
+
stream.on('error', (err) => {
|
|
135
|
+
if (!this._closed)
|
|
136
|
+
this._onStreamClosed(err);
|
|
137
|
+
});
|
|
116
138
|
// Wait for the `endpoint` event so we know where to POST messages.
|
|
117
139
|
await new Promise((resolve, reject) => {
|
|
118
140
|
const timer = setTimeout(() => {
|
|
@@ -120,8 +142,14 @@ class McpSseClient {
|
|
|
120
142
|
reject(new Error('Timed out waiting for SSE endpoint event'));
|
|
121
143
|
}, ENDPOINT_TIMEOUT_MS);
|
|
122
144
|
this._endpointWaiter = {
|
|
123
|
-
resolve: () => {
|
|
124
|
-
|
|
145
|
+
resolve: () => {
|
|
146
|
+
clearTimeout(timer);
|
|
147
|
+
resolve();
|
|
148
|
+
},
|
|
149
|
+
reject: (e) => {
|
|
150
|
+
clearTimeout(timer);
|
|
151
|
+
reject(e);
|
|
152
|
+
},
|
|
125
153
|
};
|
|
126
154
|
});
|
|
127
155
|
}
|
|
@@ -199,7 +227,9 @@ class McpSseClient {
|
|
|
199
227
|
void (async () => {
|
|
200
228
|
const reply = await (0, client_1.serverRequestReply)(this.name, this._elicitationHandler, method, params);
|
|
201
229
|
await this._postMessage({ jsonrpc: '2.0', id: reqId, ...reply });
|
|
202
|
-
})().catch(() => {
|
|
230
|
+
})().catch(() => {
|
|
231
|
+
/* server times the request out itself */
|
|
232
|
+
});
|
|
203
233
|
return;
|
|
204
234
|
}
|
|
205
235
|
if (typeof msg.id === 'number' && this._pending.has(msg.id)) {
|
|
@@ -212,7 +242,10 @@ class McpSseClient {
|
|
|
212
242
|
resolve(msg.result ?? null);
|
|
213
243
|
return;
|
|
214
244
|
}
|
|
215
|
-
// Server-initiated
|
|
245
|
+
// Server-initiated notification (no id): list_changed for tools/prompts/resources.
|
|
246
|
+
if (typeof msg.method === 'string' && msg.id == null) {
|
|
247
|
+
this._notificationHandler?.(msg.method, msg.params);
|
|
248
|
+
}
|
|
216
249
|
}
|
|
217
250
|
_rpc(method, params) {
|
|
218
251
|
const id = this._nextId++;
|
package/dist/mcp/stats.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/mcp/stats.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,QAAQ,CAAK;IAErB,6DAA6D;IAC7D,KAAK,IAAI,IAAI;IAIb,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI;IAUpD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI;IAWrE,6EAA6E;IAC7E,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIvC,6FAA6F;IAC7F,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,SAAO,GAAG,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC;IAYjF,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,SAAO,GAAG,YAAY;IAS5D,iFAAiF;IACjF,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/mcp/stats.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAC;IAChB,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA+B;IACvD,OAAO,CAAC,QAAQ,CAAK;IAErB,6DAA6D;IAC7D,KAAK,IAAI,IAAI;IAIb,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI;IAUpD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,SAAa,GAAG,IAAI;IAWrE,6EAA6E;IAC7E,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIvC,6FAA6F;IAC7F,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,SAAO,GAAG,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,CAAC;IAYjF,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,SAAO,GAAG,YAAY;IAS5D,iFAAiF;IACjF,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAQ1B,OAAO,CAAC,MAAM;CAQf;AAED,6DAA6D;AAC7D,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAI3C;AAED,sFAAsF;AACtF,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,EAAE,GAAG,UAAO,GAAG,MAAM,CAS5E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bashClassify.d.ts","sourceRoot":"","sources":["../../src/permissions/bashClassify.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bashClassify.d.ts","sourceRoot":"","sources":["../../src/permissions/bashClassify.ts"],"names":[],"mappings":"AA2DA;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAkB1D"}
|
|
@@ -32,9 +32,31 @@ exports.bashNeedsRepoLock = bashNeedsRepoLock;
|
|
|
32
32
|
* a lockfile, or mutate a shared build/dependency directory.
|
|
33
33
|
*/
|
|
34
34
|
const MUTATING_BASH_VERBS = new Set([
|
|
35
|
-
'git',
|
|
36
|
-
'
|
|
37
|
-
'
|
|
35
|
+
'git',
|
|
36
|
+
'npm',
|
|
37
|
+
'pnpm',
|
|
38
|
+
'yarn',
|
|
39
|
+
'bun',
|
|
40
|
+
'cargo',
|
|
41
|
+
'go',
|
|
42
|
+
'pip',
|
|
43
|
+
'pip3',
|
|
44
|
+
'poetry',
|
|
45
|
+
'uv',
|
|
46
|
+
'bundle',
|
|
47
|
+
'composer',
|
|
48
|
+
'gradle',
|
|
49
|
+
'mvn',
|
|
50
|
+
'make',
|
|
51
|
+
'terraform',
|
|
52
|
+
'helm',
|
|
53
|
+
'docker',
|
|
54
|
+
'vsce',
|
|
55
|
+
'tsc',
|
|
56
|
+
'pytest',
|
|
57
|
+
'dotnet',
|
|
58
|
+
'swift',
|
|
59
|
+
'gem',
|
|
38
60
|
]);
|
|
39
61
|
/**
|
|
40
62
|
* Whether a bash command should take the repo-state lock.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"destructive.d.ts","sourceRoot":"","sources":["../../src/permissions/destructive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,MAAM,WAAW,gBAAgB;IAC/B,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;
|
|
1
|
+
{"version":3,"file":"destructive.d.ts","sourceRoot":"","sources":["../../src/permissions/destructive.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAIH,MAAM,WAAW,gBAAgB;IAC/B,0FAA0F;IAC1F,QAAQ,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAsRD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAGnF;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,gBAAgB,GAAG,IAAI,CASvG"}
|
|
@@ -60,7 +60,11 @@ const RAW_RULES = [
|
|
|
60
60
|
{
|
|
61
61
|
category: 'database',
|
|
62
62
|
reason: 'DELETE without a WHERE clause (deletes every row)',
|
|
63
|
-
re: new RegExp(CMD_POS +
|
|
63
|
+
re: new RegExp(CMD_POS +
|
|
64
|
+
DB_CLIENT +
|
|
65
|
+
String.raw `\b[\s\S]*?\bdelete\s+from\s+[\w.` +
|
|
66
|
+
'`' +
|
|
67
|
+
String.raw `"]+\s*(?:;|"|'|$)(?![\s\S]*\bwhere\b)`, 'i'),
|
|
64
68
|
},
|
|
65
69
|
{
|
|
66
70
|
category: 'database',
|
|
@@ -94,7 +98,8 @@ const STRIPPED_RULES = [
|
|
|
94
98
|
{
|
|
95
99
|
category: 'database',
|
|
96
100
|
reason: 'reverses or resets database migrations (may drop columns/tables)',
|
|
97
|
-
re: new RegExp(CMD_POS +
|
|
101
|
+
re: new RegExp(CMD_POS +
|
|
102
|
+
String.raw `(?:rails\s+db:(?:drop|reset)|rake\s+db:(?:drop|reset)|(?:npx\s+)?prisma\s+migrate\s+reset|(?:npx\s+)?sequelize(?:-cli)?\s+db:drop|python\s+manage\.py\s+flush|knex\s+migrate:rollback\s+--all|alembic\s+downgrade\s+base)`, 'i'),
|
|
98
103
|
},
|
|
99
104
|
// ── Git history / remotes ───────────────────────────────────────────────────
|
|
100
105
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"destructiveTokens.d.ts","sourceRoot":"","sources":["../../src/permissions/destructiveTokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAID,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"destructiveTokens.d.ts","sourceRoot":"","sources":["../../src/permissions/destructiveTokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAID,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,CA6DhD;AAsVD,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EAAE,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,UAAU,GAAG,IAAI,EAC/C,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,UAAU,GAAG,IAAI,GAC7C,UAAU,GAAG,IAAI,CA+HnB"}
|