@i4ctime/q-ring 0.16.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -6
- package/dist/{chunk-NCM5GHNW.js → chunk-KFILBHOY.js} +58 -7
- package/dist/chunk-KFILBHOY.js.map +1 -0
- package/dist/{chunk-5LFKBZ3Q.js → chunk-SQKTDYSO.js} +80 -7
- package/dist/chunk-SQKTDYSO.js.map +1 -0
- package/dist/dashboard-2MLSJZQR.js +658 -0
- package/dist/dashboard-2MLSJZQR.js.map +1 -0
- package/dist/dashboard-WVPR5BQO.js +658 -0
- package/dist/dashboard-WVPR5BQO.js.map +1 -0
- package/dist/index.js +96 -27
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +181 -161
- package/dist/mcp.js.map +1 -1
- package/package.json +14 -13
- package/dist/chunk-5LFKBZ3Q.js.map +0 -1
- package/dist/chunk-NCM5GHNW.js.map +0 -1
- package/dist/dashboard-A3GJQCJX.js +0 -658
- package/dist/dashboard-A3GJQCJX.js.map +0 -1
- package/dist/dashboard-R3FWTFFW.js +0 -658
- package/dist/dashboard-R3FWTFFW.js.map +0 -1
package/dist/mcp.js
CHANGED
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
tunnelList,
|
|
41
41
|
tunnelRead,
|
|
42
42
|
verifyAuditChain
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-KFILBHOY.js";
|
|
44
44
|
|
|
45
45
|
// src/mcp.ts
|
|
46
46
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -48,6 +48,82 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
48
48
|
// src/mcp/server.ts
|
|
49
49
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
50
50
|
|
|
51
|
+
// src/mcp/tool-annotations.ts
|
|
52
|
+
var hints = (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) => ({ readOnlyHint, destructiveHint, idempotentHint, openWorldHint });
|
|
53
|
+
var READ = hints(true, false, true, false);
|
|
54
|
+
var READ_OPEN = hints(true, false, true, true);
|
|
55
|
+
var TOOL_ANNOTATIONS = {
|
|
56
|
+
// secrets
|
|
57
|
+
get_secret: READ,
|
|
58
|
+
list_secrets: READ,
|
|
59
|
+
set_secret: hints(false, true, true, false),
|
|
60
|
+
delete_secret: hints(false, true, true, false),
|
|
61
|
+
has_secret: READ,
|
|
62
|
+
export_secrets: READ,
|
|
63
|
+
import_dotenv: hints(false, false, true, false),
|
|
64
|
+
// existing keys are skipped, not overwritten
|
|
65
|
+
inspect_secret: READ,
|
|
66
|
+
generate_secret: hints(false, true, false, false),
|
|
67
|
+
// saveAs overwrites; fresh value every call
|
|
68
|
+
entangle_secrets: hints(false, false, true, false),
|
|
69
|
+
disentangle_secrets: hints(false, false, true, false),
|
|
70
|
+
// project
|
|
71
|
+
check_project: READ,
|
|
72
|
+
env_generate: READ,
|
|
73
|
+
// renders text, never writes files
|
|
74
|
+
detect_environment: READ,
|
|
75
|
+
get_project_context: READ,
|
|
76
|
+
// tunnels (memory-only)
|
|
77
|
+
tunnel_create: hints(false, false, false, false),
|
|
78
|
+
tunnel_read: hints(false, true, false, false),
|
|
79
|
+
// may self-destruct on read
|
|
80
|
+
tunnel_list: READ,
|
|
81
|
+
tunnel_destroy: hints(false, true, true, false),
|
|
82
|
+
// teleport
|
|
83
|
+
teleport_pack: READ,
|
|
84
|
+
teleport_unpack: hints(false, true, true, false),
|
|
85
|
+
// imports may overwrite keys
|
|
86
|
+
// audit / health
|
|
87
|
+
audit_log: READ,
|
|
88
|
+
detect_anomalies: READ,
|
|
89
|
+
health_check: READ,
|
|
90
|
+
verify_audit_chain: READ,
|
|
91
|
+
export_audit: READ,
|
|
92
|
+
// validation / rotation (network)
|
|
93
|
+
validate_secret: READ_OPEN,
|
|
94
|
+
list_providers: READ,
|
|
95
|
+
rotate_secret: hints(false, true, false, true),
|
|
96
|
+
// replaces the credential upstream and locally
|
|
97
|
+
ci_validate_secrets: READ_OPEN,
|
|
98
|
+
// hooks
|
|
99
|
+
register_hook: hints(false, false, false, false),
|
|
100
|
+
list_hooks: READ,
|
|
101
|
+
remove_hook: hints(false, true, true, false),
|
|
102
|
+
// execution / scanning
|
|
103
|
+
exec_with_secrets: hints(false, true, false, true),
|
|
104
|
+
// arbitrary command
|
|
105
|
+
scan_codebase_for_secrets: READ,
|
|
106
|
+
lint_files: hints(false, true, true, false),
|
|
107
|
+
// fix:true rewrites source files
|
|
108
|
+
analyze_secrets: READ,
|
|
109
|
+
status_dashboard: hints(false, false, false, false),
|
|
110
|
+
// starts a local server, new token per launch
|
|
111
|
+
agent_scan: hints(false, true, false, true),
|
|
112
|
+
// autoRotate replaces expired credentials
|
|
113
|
+
// agent memory
|
|
114
|
+
agent_remember: hints(false, true, true, false),
|
|
115
|
+
agent_recall: READ,
|
|
116
|
+
agent_forget: hints(false, true, true, false),
|
|
117
|
+
// policy
|
|
118
|
+
check_policy: READ,
|
|
119
|
+
get_policy_summary: READ
|
|
120
|
+
};
|
|
121
|
+
function toolAnnotations(name) {
|
|
122
|
+
const a = TOOL_ANNOTATIONS[name];
|
|
123
|
+
if (!a) throw new Error(`q-ring: no tool annotations defined for "${name}"`);
|
|
124
|
+
return a;
|
|
125
|
+
}
|
|
126
|
+
|
|
51
127
|
// src/mcp/tools/secrets.ts
|
|
52
128
|
import { z as z2 } from "zod";
|
|
53
129
|
|
|
@@ -252,10 +328,7 @@ function opts(params) {
|
|
|
252
328
|
function enforceToolPolicy(toolName, projectPath8) {
|
|
253
329
|
const decision = checkToolPolicy(toolName, projectPath8);
|
|
254
330
|
if (!decision.allowed) {
|
|
255
|
-
return text(
|
|
256
|
-
`Policy Denied: ${decision.reason} (source: ${decision.policySource})`,
|
|
257
|
-
true
|
|
258
|
-
);
|
|
331
|
+
return text(`Policy Denied: ${decision.reason} (source: ${decision.policySource})`, true);
|
|
259
332
|
}
|
|
260
333
|
return null;
|
|
261
334
|
}
|
|
@@ -297,23 +370,18 @@ function registerSecretTools(server2) {
|
|
|
297
370
|
teamId,
|
|
298
371
|
orgId
|
|
299
372
|
},
|
|
373
|
+
toolAnnotations("get_secret"),
|
|
300
374
|
async (params) => {
|
|
301
375
|
const toolBlock = enforceToolPolicy("get_secret", params.projectPath);
|
|
302
376
|
if (toolBlock) return toolBlock;
|
|
303
377
|
try {
|
|
304
|
-
const keyBlock = checkKeyReadPolicy(
|
|
305
|
-
params.key,
|
|
306
|
-
void 0,
|
|
307
|
-
params.projectPath
|
|
308
|
-
);
|
|
378
|
+
const keyBlock = checkKeyReadPolicy(params.key, void 0, params.projectPath);
|
|
309
379
|
if (!keyBlock.allowed) {
|
|
310
380
|
return text(`Policy Denied: ${keyBlock.reason}`, true);
|
|
311
381
|
}
|
|
312
382
|
const value = getSecret(params.key, opts(params));
|
|
313
383
|
if (value === null) return text(`Secret "${params.key}" not found`, true);
|
|
314
|
-
return text(
|
|
315
|
-
JSON.stringify({ ok: true, data: { key: params.key, value } }, null, 2)
|
|
316
|
-
);
|
|
384
|
+
return text(JSON.stringify({ ok: true, data: { key: params.key, value } }, null, 2));
|
|
317
385
|
} catch (err) {
|
|
318
386
|
return text(err instanceof Error ? err.message : String(err), true);
|
|
319
387
|
}
|
|
@@ -344,22 +412,19 @@ function registerSecretTools(server2) {
|
|
|
344
412
|
teamId,
|
|
345
413
|
orgId
|
|
346
414
|
},
|
|
415
|
+
toolAnnotations("list_secrets"),
|
|
347
416
|
async (params) => {
|
|
348
417
|
const toolBlock = enforceToolPolicy("list_secrets", params.projectPath);
|
|
349
418
|
if (toolBlock) return toolBlock;
|
|
350
419
|
let entries = listSecrets(opts(params));
|
|
351
420
|
if (params.tag) {
|
|
352
|
-
entries = entries.filter(
|
|
353
|
-
(e) => e.envelope?.meta.tags?.includes(params.tag)
|
|
354
|
-
);
|
|
421
|
+
entries = entries.filter((e) => e.envelope?.meta.tags?.includes(params.tag));
|
|
355
422
|
}
|
|
356
423
|
if (params.expired) {
|
|
357
424
|
entries = entries.filter((e) => e.decay?.isExpired);
|
|
358
425
|
}
|
|
359
426
|
if (params.stale) {
|
|
360
|
-
entries = entries.filter(
|
|
361
|
-
(e) => e.decay?.isStale && !e.decay?.isExpired
|
|
362
|
-
);
|
|
427
|
+
entries = entries.filter((e) => e.decay?.isStale && !e.decay?.isExpired);
|
|
363
428
|
}
|
|
364
429
|
if (params.filter) {
|
|
365
430
|
entries = filterSecretsByKeyGlob(entries, params.filter);
|
|
@@ -386,9 +451,7 @@ function registerSecretTools(server2) {
|
|
|
386
451
|
"Mutates the keyring (overwrites any existing value at the same key/scope), writes a 'write' event to the audit log, and triggers any matching hooks. Subject to tool policy. Returns a short confirmation text like '[scope] KEY saved' (or '[scope] KEY set for env:NAME' when `env` is provided)."
|
|
387
452
|
].join(" "),
|
|
388
453
|
{
|
|
389
|
-
key: z2.string().describe(
|
|
390
|
-
"Secret key name (UPPER_SNAKE_CASE recommended). Example: 'STRIPE_SECRET_KEY'."
|
|
391
|
-
),
|
|
454
|
+
key: z2.string().describe("Secret key name (UPPER_SNAKE_CASE recommended). Example: 'STRIPE_SECRET_KEY'."),
|
|
392
455
|
value: z2.string().describe(
|
|
393
456
|
"The secret value to store. Stored as-is; never logged or echoed. May be empty only when `env` is provided to register a new env without a default."
|
|
394
457
|
),
|
|
@@ -403,18 +466,8 @@ function registerSecretTools(server2) {
|
|
|
403
466
|
description: z2.string().optional().describe(
|
|
404
467
|
"Free-text human-readable description shown in `inspect_secret` and the dashboard."
|
|
405
468
|
),
|
|
406
|
-
tags: z2.array(z2.string()).optional().describe(
|
|
407
|
-
|
|
408
|
-
),
|
|
409
|
-
rotationFormat: z2.enum([
|
|
410
|
-
"hex",
|
|
411
|
-
"base64",
|
|
412
|
-
"alphanumeric",
|
|
413
|
-
"uuid",
|
|
414
|
-
"api-key",
|
|
415
|
-
"token",
|
|
416
|
-
"password"
|
|
417
|
-
]).optional().describe(
|
|
469
|
+
tags: z2.array(z2.string()).optional().describe("Tag list for filtering and hook matching. Example: ['production', 'payments']."),
|
|
470
|
+
rotationFormat: z2.enum(["hex", "base64", "alphanumeric", "uuid", "api-key", "token", "password"]).optional().describe(
|
|
418
471
|
"Format used by `agent_scan --autoRotate` and `rotate_secret` when this secret expires. Pick the format that matches the upstream service's accepted shape."
|
|
419
472
|
),
|
|
420
473
|
rotationPrefix: z2.string().optional().describe(
|
|
@@ -423,6 +476,7 @@ function registerSecretTools(server2) {
|
|
|
423
476
|
teamId,
|
|
424
477
|
orgId
|
|
425
478
|
},
|
|
479
|
+
toolAnnotations("set_secret"),
|
|
426
480
|
async (params) => {
|
|
427
481
|
const toolBlock = enforceToolPolicy("set_secret", params.projectPath);
|
|
428
482
|
if (toolBlock) return toolBlock;
|
|
@@ -444,9 +498,7 @@ function registerSecretTools(server2) {
|
|
|
444
498
|
rotationFormat: params.rotationFormat,
|
|
445
499
|
rotationPrefix: params.rotationPrefix
|
|
446
500
|
});
|
|
447
|
-
return text(
|
|
448
|
-
`[${params.scope ?? "global"}] ${params.key} set for env:${params.env}`
|
|
449
|
-
);
|
|
501
|
+
return text(`[${params.scope ?? "global"}] ${params.key} set for env:${params.env}`);
|
|
450
502
|
}
|
|
451
503
|
setSecret(params.key, params.value, {
|
|
452
504
|
...o,
|
|
@@ -473,6 +525,7 @@ function registerSecretTools(server2) {
|
|
|
473
525
|
teamId,
|
|
474
526
|
orgId
|
|
475
527
|
},
|
|
528
|
+
toolAnnotations("delete_secret"),
|
|
476
529
|
async (params) => {
|
|
477
530
|
const toolBlock = enforceToolPolicy("delete_secret", params.projectPath);
|
|
478
531
|
if (toolBlock) return toolBlock;
|
|
@@ -497,6 +550,7 @@ function registerSecretTools(server2) {
|
|
|
497
550
|
teamId,
|
|
498
551
|
orgId
|
|
499
552
|
},
|
|
553
|
+
toolAnnotations("has_secret"),
|
|
500
554
|
async (params) => {
|
|
501
555
|
const toolBlock = enforceToolPolicy("has_secret", params.projectPath);
|
|
502
556
|
if (toolBlock) return toolBlock;
|
|
@@ -526,6 +580,7 @@ function registerSecretTools(server2) {
|
|
|
526
580
|
teamId,
|
|
527
581
|
orgId
|
|
528
582
|
},
|
|
583
|
+
toolAnnotations("export_secrets"),
|
|
529
584
|
async (params) => {
|
|
530
585
|
const toolBlock = enforceToolPolicy("export_secrets", params.projectPath);
|
|
531
586
|
if (toolBlock) return toolBlock;
|
|
@@ -559,6 +614,7 @@ function registerSecretTools(server2) {
|
|
|
559
614
|
"If true, parse and report what would happen but do not write to the keyring. Useful for previewing imports before committing."
|
|
560
615
|
)
|
|
561
616
|
},
|
|
617
|
+
toolAnnotations("import_dotenv"),
|
|
562
618
|
async (params) => {
|
|
563
619
|
const toolBlock = enforceToolPolicy("import_dotenv", params.projectPath);
|
|
564
620
|
if (toolBlock) return toolBlock;
|
|
@@ -595,6 +651,7 @@ function registerSecretTools(server2) {
|
|
|
595
651
|
teamId,
|
|
596
652
|
orgId
|
|
597
653
|
},
|
|
654
|
+
toolAnnotations("inspect_secret"),
|
|
598
655
|
async (params) => {
|
|
599
656
|
const toolBlock = enforceToolPolicy("inspect_secret", params.projectPath);
|
|
600
657
|
if (toolBlock) return toolBlock;
|
|
@@ -626,8 +683,7 @@ function registerSecretTools(server2) {
|
|
|
626
683
|
if (envelope.meta.entangled?.length) {
|
|
627
684
|
info.entangled = envelope.meta.entangled;
|
|
628
685
|
}
|
|
629
|
-
if (envelope.meta.description)
|
|
630
|
-
info.description = envelope.meta.description;
|
|
686
|
+
if (envelope.meta.description) info.description = envelope.meta.description;
|
|
631
687
|
if (envelope.meta.tags?.length) info.tags = envelope.meta.tags;
|
|
632
688
|
return text(JSON.stringify(info, null, 2));
|
|
633
689
|
}
|
|
@@ -640,15 +696,7 @@ function registerSecretTools(server2) {
|
|
|
640
696
|
"If `saveAs` is provided this mutates the keyring (one 'write' event) and returns a summary like 'Generated and saved as \"KEY\" (FORMAT, ~N bits entropy)'. Without `saveAs` the call is read-only and returns JSON `{ ok, data: { value } }` containing the freshly generated string."
|
|
641
697
|
].join(" "),
|
|
642
698
|
{
|
|
643
|
-
format: z2.enum([
|
|
644
|
-
"hex",
|
|
645
|
-
"base64",
|
|
646
|
-
"alphanumeric",
|
|
647
|
-
"uuid",
|
|
648
|
-
"api-key",
|
|
649
|
-
"token",
|
|
650
|
-
"password"
|
|
651
|
-
]).optional().default("api-key").describe(
|
|
699
|
+
format: z2.enum(["hex", "base64", "alphanumeric", "uuid", "api-key", "token", "password"]).optional().default("api-key").describe(
|
|
652
700
|
"Output shape. 'hex' / 'base64' / 'alphanumeric' = raw random string of `length` characters; 'uuid' = RFC4122 v4; 'api-key' / 'token' = random alphanumeric with optional `prefix`; 'password' = mixed-case alphanumeric with symbols. Defaults to 'api-key'."
|
|
653
701
|
),
|
|
654
702
|
length: z2.number().optional().describe(
|
|
@@ -665,6 +713,7 @@ function registerSecretTools(server2) {
|
|
|
665
713
|
teamId,
|
|
666
714
|
orgId
|
|
667
715
|
},
|
|
716
|
+
toolAnnotations("generate_secret"),
|
|
668
717
|
async (params) => {
|
|
669
718
|
const toolBlock = enforceToolPolicy("generate_secret", params.projectPath);
|
|
670
719
|
if (toolBlock) return toolBlock;
|
|
@@ -705,19 +754,14 @@ function registerSecretTools(server2) {
|
|
|
705
754
|
"Project root for targetKey when targetScope='project'. Defaults to the server cwd."
|
|
706
755
|
)
|
|
707
756
|
},
|
|
757
|
+
toolAnnotations("entangle_secrets"),
|
|
708
758
|
async (params) => {
|
|
709
|
-
const toolBlock = enforceToolPolicy(
|
|
710
|
-
"entangle_secrets",
|
|
711
|
-
params.sourceProjectPath
|
|
712
|
-
);
|
|
759
|
+
const toolBlock = enforceToolPolicy("entangle_secrets", params.sourceProjectPath);
|
|
713
760
|
if (toolBlock) return toolBlock;
|
|
714
761
|
for (const key of [params.sourceKey, params.targetKey]) {
|
|
715
762
|
const decision = checkKeyReadPolicy(key, void 0, params.sourceProjectPath);
|
|
716
763
|
if (!decision.allowed) {
|
|
717
|
-
return text(
|
|
718
|
-
`Policy Denied: ${decision.reason} (source: ${decision.policySource})`,
|
|
719
|
-
true
|
|
720
|
-
);
|
|
764
|
+
return text(`Policy Denied: ${decision.reason} (source: ${decision.policySource})`, true);
|
|
721
765
|
}
|
|
722
766
|
}
|
|
723
767
|
entangleSecrets(
|
|
@@ -752,11 +796,9 @@ function registerSecretTools(server2) {
|
|
|
752
796
|
sourceProjectPath: z2.string().optional().describe("Project root for sourceKey when sourceScope='project'."),
|
|
753
797
|
targetProjectPath: z2.string().optional().describe("Project root for targetKey when targetScope='project'.")
|
|
754
798
|
},
|
|
799
|
+
toolAnnotations("disentangle_secrets"),
|
|
755
800
|
async (params) => {
|
|
756
|
-
const toolBlock = enforceToolPolicy(
|
|
757
|
-
"disentangle_secrets",
|
|
758
|
-
params.sourceProjectPath
|
|
759
|
-
);
|
|
801
|
+
const toolBlock = enforceToolPolicy("disentangle_secrets", params.sourceProjectPath);
|
|
760
802
|
if (toolBlock) return toolBlock;
|
|
761
803
|
disentangleSecrets(
|
|
762
804
|
params.sourceKey,
|
|
@@ -789,9 +831,9 @@ var ProviderRegistry = class {
|
|
|
789
831
|
get(name) {
|
|
790
832
|
return this.providers.get(name);
|
|
791
833
|
}
|
|
792
|
-
detectProvider(value,
|
|
793
|
-
if (
|
|
794
|
-
return this.providers.get(
|
|
834
|
+
detectProvider(value, hints2) {
|
|
835
|
+
if (hints2?.provider) {
|
|
836
|
+
return this.providers.get(hints2.provider);
|
|
795
837
|
}
|
|
796
838
|
for (const provider of this.providers.values()) {
|
|
797
839
|
if (provider.prefixes) {
|
|
@@ -1147,6 +1189,7 @@ function registerProjectTools(server2) {
|
|
|
1147
1189
|
{
|
|
1148
1190
|
projectPath: projectPath2
|
|
1149
1191
|
},
|
|
1192
|
+
toolAnnotations("check_project"),
|
|
1150
1193
|
async (params) => {
|
|
1151
1194
|
const toolBlock = enforceToolPolicy("check_project", params.projectPath);
|
|
1152
1195
|
if (toolBlock) return toolBlock;
|
|
@@ -1219,6 +1262,7 @@ function registerProjectTools(server2) {
|
|
|
1219
1262
|
projectPath: projectPath2,
|
|
1220
1263
|
env: env2
|
|
1221
1264
|
},
|
|
1265
|
+
toolAnnotations("env_generate"),
|
|
1222
1266
|
async (params) => {
|
|
1223
1267
|
const toolBlock = enforceToolPolicy("env_generate", params.projectPath);
|
|
1224
1268
|
if (toolBlock) return toolBlock;
|
|
@@ -1269,19 +1313,15 @@ ${warnings.map((w) => `# ${w}`).join("\n")}` : output;
|
|
|
1269
1313
|
{
|
|
1270
1314
|
projectPath: projectPath2
|
|
1271
1315
|
},
|
|
1316
|
+
toolAnnotations("detect_environment"),
|
|
1272
1317
|
async (params) => {
|
|
1273
|
-
const toolBlock = enforceToolPolicy(
|
|
1274
|
-
"detect_environment",
|
|
1275
|
-
params.projectPath
|
|
1276
|
-
);
|
|
1318
|
+
const toolBlock = enforceToolPolicy("detect_environment", params.projectPath);
|
|
1277
1319
|
if (toolBlock) return toolBlock;
|
|
1278
1320
|
const result = collapseEnvironment({
|
|
1279
1321
|
projectPath: params.projectPath ?? process.cwd()
|
|
1280
1322
|
});
|
|
1281
1323
|
if (!result) {
|
|
1282
|
-
return text(
|
|
1283
|
-
"No environment detected. Set QRING_ENV, NODE_ENV, or create .q-ring.json"
|
|
1284
|
-
);
|
|
1324
|
+
return text("No environment detected. Set QRING_ENV, NODE_ENV, or create .q-ring.json");
|
|
1285
1325
|
}
|
|
1286
1326
|
return text(JSON.stringify(result, null, 2));
|
|
1287
1327
|
}
|
|
@@ -1299,11 +1339,9 @@ ${warnings.map((w) => `# ${w}`).join("\n")}` : output;
|
|
|
1299
1339
|
teamId: teamId2,
|
|
1300
1340
|
orgId: orgId2
|
|
1301
1341
|
},
|
|
1342
|
+
toolAnnotations("get_project_context"),
|
|
1302
1343
|
async (params) => {
|
|
1303
|
-
const toolBlock = enforceToolPolicy(
|
|
1304
|
-
"get_project_context",
|
|
1305
|
-
params.projectPath
|
|
1306
|
-
);
|
|
1344
|
+
const toolBlock = enforceToolPolicy("get_project_context", params.projectPath);
|
|
1307
1345
|
if (toolBlock) return toolBlock;
|
|
1308
1346
|
const context = getProjectContext(opts(params));
|
|
1309
1347
|
return text(JSON.stringify(context, null, 2));
|
|
@@ -1322,9 +1360,7 @@ function registerTunnelTools(server2) {
|
|
|
1322
1360
|
"Mutates only in-memory state \u2014 the value never touches disk and is lost on server restart. Subject to tool policy. Returns JSON `{ ok, data: { id } }` where `id` is an opaque string to pass to `tunnel_read`/`tunnel_destroy`."
|
|
1323
1361
|
].join(" "),
|
|
1324
1362
|
{
|
|
1325
|
-
value: z3.string().describe(
|
|
1326
|
-
"The plaintext value to tunnel. Held only in process memory; never logged."
|
|
1327
|
-
),
|
|
1363
|
+
value: z3.string().describe("The plaintext value to tunnel. Held only in process memory; never logged."),
|
|
1328
1364
|
ttlSeconds: z3.number().optional().describe(
|
|
1329
1365
|
"Auto-destroy the tunnel after this many seconds. Omit for no time limit (then a `maxReads` is highly recommended)."
|
|
1330
1366
|
),
|
|
@@ -1332,6 +1368,7 @@ function registerTunnelTools(server2) {
|
|
|
1332
1368
|
"Self-destruct after this many successful `tunnel_read` calls. Use 1 for true one-shot delivery."
|
|
1333
1369
|
)
|
|
1334
1370
|
},
|
|
1371
|
+
toolAnnotations("tunnel_create"),
|
|
1335
1372
|
async (params) => {
|
|
1336
1373
|
const toolBlock = enforceToolPolicy("tunnel_create");
|
|
1337
1374
|
if (toolBlock) return toolBlock;
|
|
@@ -1350,10 +1387,9 @@ function registerTunnelTools(server2) {
|
|
|
1350
1387
|
"Increments the read counter and may auto-destroy the tunnel if `maxReads` was set. Returns JSON `{ ok, data: { id, value } }` on success, or an error 'Tunnel \"...\" not found or expired' if the tunnel has been destroyed, hit its TTL, or never existed."
|
|
1351
1388
|
].join(" "),
|
|
1352
1389
|
{
|
|
1353
|
-
id: z3.string().describe(
|
|
1354
|
-
"The opaque tunnel ID returned by `tunnel_create`. Case-sensitive."
|
|
1355
|
-
)
|
|
1390
|
+
id: z3.string().describe("The opaque tunnel ID returned by `tunnel_create`. Case-sensitive.")
|
|
1356
1391
|
},
|
|
1392
|
+
toolAnnotations("tunnel_read"),
|
|
1357
1393
|
async (params) => {
|
|
1358
1394
|
const toolBlock = enforceToolPolicy("tunnel_read");
|
|
1359
1395
|
if (toolBlock) return toolBlock;
|
|
@@ -1361,9 +1397,7 @@ function registerTunnelTools(server2) {
|
|
|
1361
1397
|
if (value === null) {
|
|
1362
1398
|
return text(`Tunnel "${params.id}" not found or expired`, true);
|
|
1363
1399
|
}
|
|
1364
|
-
return text(
|
|
1365
|
-
JSON.stringify({ ok: true, data: { id: params.id, value } }, null, 2)
|
|
1366
|
-
);
|
|
1400
|
+
return text(JSON.stringify({ ok: true, data: { id: params.id, value } }, null, 2));
|
|
1367
1401
|
}
|
|
1368
1402
|
);
|
|
1369
1403
|
server2.tool(
|
|
@@ -1374,6 +1408,7 @@ function registerTunnelTools(server2) {
|
|
|
1374
1408
|
"Read-only. Returns one line per tunnel formatted as `id | reads:N | max:N | expires:Ns`, or the literal text 'No active tunnels' when the list is empty."
|
|
1375
1409
|
].join(" "),
|
|
1376
1410
|
{},
|
|
1411
|
+
toolAnnotations("tunnel_list"),
|
|
1377
1412
|
async () => {
|
|
1378
1413
|
const toolBlock = enforceToolPolicy("tunnel_list");
|
|
1379
1414
|
if (toolBlock) return toolBlock;
|
|
@@ -1384,10 +1419,7 @@ function registerTunnelTools(server2) {
|
|
|
1384
1419
|
parts.push(`reads:${t.accessCount}`);
|
|
1385
1420
|
if (t.maxReads) parts.push(`max:${t.maxReads}`);
|
|
1386
1421
|
if (t.expiresAt) {
|
|
1387
|
-
const rem = Math.max(
|
|
1388
|
-
0,
|
|
1389
|
-
Math.floor((t.expiresAt - Date.now()) / 1e3)
|
|
1390
|
-
);
|
|
1422
|
+
const rem = Math.max(0, Math.floor((t.expiresAt - Date.now()) / 1e3));
|
|
1391
1423
|
parts.push(`expires:${rem}s`);
|
|
1392
1424
|
}
|
|
1393
1425
|
return parts.join(" | ");
|
|
@@ -1405,6 +1437,7 @@ function registerTunnelTools(server2) {
|
|
|
1405
1437
|
{
|
|
1406
1438
|
id: z3.string().describe("The opaque tunnel ID to destroy.")
|
|
1407
1439
|
},
|
|
1440
|
+
toolAnnotations("tunnel_destroy"),
|
|
1408
1441
|
async (params) => {
|
|
1409
1442
|
const toolBlock = enforceToolPolicy("tunnel_destroy");
|
|
1410
1443
|
if (toolBlock) return toolBlock;
|
|
@@ -1558,6 +1591,7 @@ function registerTeleportTools(server2) {
|
|
|
1558
1591
|
teamId: teamId3,
|
|
1559
1592
|
orgId: orgId3
|
|
1560
1593
|
},
|
|
1594
|
+
toolAnnotations("teleport_pack"),
|
|
1561
1595
|
async (params) => {
|
|
1562
1596
|
const toolBlock = enforceToolPolicy("teleport_pack", params.projectPath);
|
|
1563
1597
|
if (toolBlock) return toolBlock;
|
|
@@ -1598,6 +1632,7 @@ function registerTeleportTools(server2) {
|
|
|
1598
1632
|
"If true, decrypt and report what would be written but do not mutate the keyring. Useful for verifying bundle contents before commit."
|
|
1599
1633
|
)
|
|
1600
1634
|
},
|
|
1635
|
+
toolAnnotations("teleport_unpack"),
|
|
1601
1636
|
async (params) => {
|
|
1602
1637
|
const toolBlock = enforceToolPolicy("teleport_unpack", params.projectPath);
|
|
1603
1638
|
if (toolBlock) return toolBlock;
|
|
@@ -1605,18 +1640,14 @@ function registerTeleportTools(server2) {
|
|
|
1605
1640
|
const payload = teleportUnpack(params.bundle, params.passphrase);
|
|
1606
1641
|
if (params.dryRun) {
|
|
1607
1642
|
const preview = payload.secrets.map((s) => `${s.key} [${s.scope ?? "global"}]`).join("\n");
|
|
1608
|
-
return text(
|
|
1609
|
-
|
|
1610
|
-
${preview}`
|
|
1611
|
-
);
|
|
1643
|
+
return text(`Would import ${payload.secrets.length} secrets:
|
|
1644
|
+
${preview}`);
|
|
1612
1645
|
}
|
|
1613
1646
|
const o = opts(params);
|
|
1614
1647
|
for (const s of payload.secrets) {
|
|
1615
1648
|
setSecret(s.key, s.value, o);
|
|
1616
1649
|
}
|
|
1617
|
-
return text(
|
|
1618
|
-
`Imported ${payload.secrets.length} secret(s) from teleport bundle`
|
|
1619
|
-
);
|
|
1650
|
+
return text(`Imported ${payload.secrets.length} secret(s) from teleport bundle`);
|
|
1620
1651
|
} catch (err) {
|
|
1621
1652
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1622
1653
|
return text(JSON.stringify({ ok: false, error: { message: msg } }), true);
|
|
@@ -1637,9 +1668,7 @@ function registerAuditTools(server2) {
|
|
|
1637
1668
|
"Read-only. Returns one line per event in chronological order, formatted `timestamp | action | key | [scope] | env:NAME | detail`. Returns 'No audit events found' when the filter matches nothing."
|
|
1638
1669
|
].join(" "),
|
|
1639
1670
|
{
|
|
1640
|
-
key: z6.string().optional().describe(
|
|
1641
|
-
"Limit to events touching this exact key. Omit for the full log."
|
|
1642
|
-
),
|
|
1671
|
+
key: z6.string().optional().describe("Limit to events touching this exact key. Omit for the full log."),
|
|
1643
1672
|
action: z6.enum([
|
|
1644
1673
|
"read",
|
|
1645
1674
|
"write",
|
|
@@ -1651,29 +1680,38 @@ function registerAuditTools(server2) {
|
|
|
1651
1680
|
"tunnel",
|
|
1652
1681
|
"teleport",
|
|
1653
1682
|
"collapse",
|
|
1654
|
-
"
|
|
1683
|
+
"approve",
|
|
1684
|
+
"revoke",
|
|
1685
|
+
"policy_deny",
|
|
1686
|
+
"rotate",
|
|
1687
|
+
"push",
|
|
1655
1688
|
"wrap"
|
|
1656
1689
|
]).optional().describe(
|
|
1657
1690
|
"Limit to a single action verb (e.g. 'read' to see only reads). Omit for all actions."
|
|
1658
1691
|
),
|
|
1692
|
+
agent: z6.string().optional().describe(
|
|
1693
|
+
"Limit to events stamped with this agent label (clientInfo name@version). Omit for all agents."
|
|
1694
|
+
),
|
|
1659
1695
|
limit: z6.number().optional().default(20).describe(
|
|
1660
1696
|
"Maximum events to return, newest first. Defaults to 20. Increase for deeper investigations."
|
|
1661
1697
|
)
|
|
1662
1698
|
},
|
|
1699
|
+
toolAnnotations("audit_log"),
|
|
1663
1700
|
async (params) => {
|
|
1664
1701
|
const toolBlock = enforceToolPolicy("audit_log");
|
|
1665
1702
|
if (toolBlock) return toolBlock;
|
|
1666
1703
|
const events = queryAudit({
|
|
1667
1704
|
key: params.key,
|
|
1668
1705
|
action: params.action,
|
|
1669
|
-
|
|
1670
|
-
});
|
|
1706
|
+
agent: params.agent
|
|
1707
|
+
}).filter((e) => e.action !== "canary").slice(0, params.limit);
|
|
1671
1708
|
if (events.length === 0) return text("No audit events found");
|
|
1672
1709
|
const lines = events.map((e) => {
|
|
1673
1710
|
const parts = [e.timestamp, e.action];
|
|
1674
1711
|
if (e.key) parts.push(e.key);
|
|
1675
1712
|
if (e.scope) parts.push(`[${e.scope}]`);
|
|
1676
1713
|
if (e.env) parts.push(`env:${e.env}`);
|
|
1714
|
+
if (e.agent) parts.push(`agent:${e.agent}`);
|
|
1677
1715
|
if (e.detail) parts.push(e.detail);
|
|
1678
1716
|
return parts.join(" | ");
|
|
1679
1717
|
});
|
|
@@ -1692,6 +1730,7 @@ function registerAuditTools(server2) {
|
|
|
1692
1730
|
"If provided, narrow the scan to this exact key. Omit to scan across every key in the audit log."
|
|
1693
1731
|
)
|
|
1694
1732
|
},
|
|
1733
|
+
toolAnnotations("detect_anomalies"),
|
|
1695
1734
|
async (params) => {
|
|
1696
1735
|
const toolBlock = enforceToolPolicy("detect_anomalies");
|
|
1697
1736
|
if (toolBlock) return toolBlock;
|
|
@@ -1714,6 +1753,7 @@ function registerAuditTools(server2) {
|
|
|
1714
1753
|
teamId: teamId4,
|
|
1715
1754
|
orgId: orgId4
|
|
1716
1755
|
},
|
|
1756
|
+
toolAnnotations("health_check"),
|
|
1717
1757
|
async (params) => {
|
|
1718
1758
|
const toolBlock = enforceToolPolicy("health_check", params.projectPath);
|
|
1719
1759
|
if (toolBlock) return toolBlock;
|
|
@@ -1750,11 +1790,7 @@ function registerAuditTools(server2) {
|
|
|
1750
1790
|
summary.push("", "Issues:", ...issues);
|
|
1751
1791
|
}
|
|
1752
1792
|
if (anomalies.length > 0) {
|
|
1753
|
-
summary.push(
|
|
1754
|
-
"",
|
|
1755
|
-
"Anomalies:",
|
|
1756
|
-
...anomalies.map((a) => `[${a.type}] ${a.description}`)
|
|
1757
|
-
);
|
|
1793
|
+
summary.push("", "Anomalies:", ...anomalies.map((a) => `[${a.type}] ${a.description}`));
|
|
1758
1794
|
}
|
|
1759
1795
|
return text(summary.join("\n"));
|
|
1760
1796
|
}
|
|
@@ -1767,6 +1803,7 @@ function registerAuditTools(server2) {
|
|
|
1767
1803
|
"Read-only. Returns JSON `{ ok, valid, brokenAt? }` where `valid` is `true` for an intact chain and `brokenAt` (when present) names the first event whose hash did not match."
|
|
1768
1804
|
].join(" "),
|
|
1769
1805
|
{},
|
|
1806
|
+
toolAnnotations("verify_audit_chain"),
|
|
1770
1807
|
async () => {
|
|
1771
1808
|
const toolBlock = enforceToolPolicy("verify_audit_chain");
|
|
1772
1809
|
if (toolBlock) return toolBlock;
|
|
@@ -1792,13 +1829,16 @@ function registerAuditTools(server2) {
|
|
|
1792
1829
|
"Output format. 'jsonl' (default) is most stream-friendly; 'json' is a single array; 'csv' is spreadsheet-friendly."
|
|
1793
1830
|
)
|
|
1794
1831
|
},
|
|
1832
|
+
toolAnnotations("export_audit"),
|
|
1795
1833
|
async (params) => {
|
|
1796
1834
|
const toolBlock = enforceToolPolicy("export_audit");
|
|
1797
1835
|
if (toolBlock) return toolBlock;
|
|
1798
1836
|
const output = exportAudit({
|
|
1799
1837
|
since: params.since,
|
|
1800
1838
|
until: params.until,
|
|
1801
|
-
format: params.format
|
|
1839
|
+
format: params.format,
|
|
1840
|
+
// Same rationale as audit_log: trip records stay operator-facing.
|
|
1841
|
+
excludeActions: ["canary"]
|
|
1802
1842
|
});
|
|
1803
1843
|
return text(output);
|
|
1804
1844
|
}
|
|
@@ -1828,6 +1868,7 @@ function registerValidationTools(server2) {
|
|
|
1828
1868
|
teamId: teamId5,
|
|
1829
1869
|
orgId: orgId5
|
|
1830
1870
|
},
|
|
1871
|
+
toolAnnotations("validate_secret"),
|
|
1831
1872
|
async (params) => {
|
|
1832
1873
|
const toolBlock = enforceToolPolicy("validate_secret", params.projectPath);
|
|
1833
1874
|
if (toolBlock) return toolBlock;
|
|
@@ -1847,6 +1888,7 @@ function registerValidationTools(server2) {
|
|
|
1847
1888
|
"Read-only. Returns JSON array of `{ name, description, prefixes }` objects. `prefixes` are the literal key-value prefixes (e.g. 'sk-' for OpenAI) used for auto-detection."
|
|
1848
1889
|
].join(" "),
|
|
1849
1890
|
{},
|
|
1891
|
+
toolAnnotations("list_providers"),
|
|
1850
1892
|
async () => {
|
|
1851
1893
|
const toolBlock = enforceToolPolicy("list_providers");
|
|
1852
1894
|
if (toolBlock) return toolBlock;
|
|
@@ -1875,6 +1917,7 @@ function registerValidationTools(server2) {
|
|
|
1875
1917
|
teamId: teamId5,
|
|
1876
1918
|
orgId: orgId5
|
|
1877
1919
|
},
|
|
1920
|
+
toolAnnotations("rotate_secret"),
|
|
1878
1921
|
async (params) => {
|
|
1879
1922
|
const toolBlock = enforceToolPolicy("rotate_secret", params.projectPath);
|
|
1880
1923
|
if (toolBlock) return toolBlock;
|
|
@@ -1904,11 +1947,9 @@ function registerValidationTools(server2) {
|
|
|
1904
1947
|
teamId: teamId5,
|
|
1905
1948
|
orgId: orgId5
|
|
1906
1949
|
},
|
|
1950
|
+
toolAnnotations("ci_validate_secrets"),
|
|
1907
1951
|
async (params) => {
|
|
1908
|
-
const toolBlock = enforceToolPolicy(
|
|
1909
|
-
"ci_validate_secrets",
|
|
1910
|
-
params.projectPath
|
|
1911
|
-
);
|
|
1952
|
+
const toolBlock = enforceToolPolicy("ci_validate_secrets", params.projectPath);
|
|
1912
1953
|
if (toolBlock) return toolBlock;
|
|
1913
1954
|
const entries = listSecrets(opts(params));
|
|
1914
1955
|
const secrets = entries.map((e) => {
|
|
@@ -1949,18 +1990,14 @@ function registerHookTools(server2) {
|
|
|
1949
1990
|
key: z8.string().optional().describe(
|
|
1950
1991
|
"Trigger only on this exact key name. Pick at most one of `key` / `keyPattern` / `tag` (or combine for stricter matching)."
|
|
1951
1992
|
),
|
|
1952
|
-
keyPattern: z8.string().optional().describe(
|
|
1953
|
-
"Trigger on any key matching this glob pattern. Examples: 'DB_*', 'STRIPE_*'."
|
|
1954
|
-
),
|
|
1993
|
+
keyPattern: z8.string().optional().describe("Trigger on any key matching this glob pattern. Examples: 'DB_*', 'STRIPE_*'."),
|
|
1955
1994
|
tag: z8.string().optional().describe(
|
|
1956
1995
|
"Trigger on any secret carrying this exact tag. Combinable with key/keyPattern as an AND filter."
|
|
1957
1996
|
),
|
|
1958
1997
|
scope: z8.enum(["global", "project"]).optional().describe(
|
|
1959
1998
|
"Restrict the hook to secrets in this scope. Omit to fire across both global and project secrets."
|
|
1960
1999
|
),
|
|
1961
|
-
actions: z8.array(z8.enum(["write", "delete", "rotate"])).optional().default(["write", "delete", "rotate"]).describe(
|
|
1962
|
-
"Which lifecycle actions trigger this hook. Defaults to all three."
|
|
1963
|
-
),
|
|
2000
|
+
actions: z8.array(z8.enum(["write", "delete", "rotate"])).optional().default(["write", "delete", "rotate"]).describe("Which lifecycle actions trigger this hook. Defaults to all three."),
|
|
1964
2001
|
command: z8.string().optional().describe(
|
|
1965
2002
|
"Required when type='shell'. The literal shell command to run; q-ring exposes the matching key as $QRING_HOOK_KEY and action as $QRING_HOOK_ACTION."
|
|
1966
2003
|
),
|
|
@@ -1977,14 +2014,12 @@ function registerHookTools(server2) {
|
|
|
1977
2014
|
"Free-text human-readable description, surfaced by `list_hooks` and the dashboard."
|
|
1978
2015
|
)
|
|
1979
2016
|
},
|
|
2017
|
+
toolAnnotations("register_hook"),
|
|
1980
2018
|
async (params) => {
|
|
1981
2019
|
const toolBlock = enforceToolPolicy("register_hook");
|
|
1982
2020
|
if (toolBlock) return toolBlock;
|
|
1983
2021
|
if (!params.key && !params.keyPattern && !params.tag) {
|
|
1984
|
-
return text(
|
|
1985
|
-
"At least one match criterion required: key, keyPattern, or tag",
|
|
1986
|
-
true
|
|
1987
|
-
);
|
|
2022
|
+
return text("At least one match criterion required: key, keyPattern, or tag", true);
|
|
1988
2023
|
}
|
|
1989
2024
|
const entry = registerHook({
|
|
1990
2025
|
type: params.type,
|
|
@@ -2012,6 +2047,7 @@ function registerHookTools(server2) {
|
|
|
2012
2047
|
"Read-only. Returns pretty-printed JSON array of hook entries, or 'No hooks registered' when the registry is empty."
|
|
2013
2048
|
].join(" "),
|
|
2014
2049
|
{},
|
|
2050
|
+
toolAnnotations("list_hooks"),
|
|
2015
2051
|
async () => {
|
|
2016
2052
|
const toolBlock = enforceToolPolicy("list_hooks");
|
|
2017
2053
|
if (toolBlock) return toolBlock;
|
|
@@ -2032,6 +2068,7 @@ function registerHookTools(server2) {
|
|
|
2032
2068
|
"Hook id returned by `register_hook` or visible in `list_hooks` (opaque string)."
|
|
2033
2069
|
)
|
|
2034
2070
|
},
|
|
2071
|
+
toolAnnotations("remove_hook"),
|
|
2035
2072
|
async (params) => {
|
|
2036
2073
|
const toolBlock = enforceToolPolicy("remove_hook");
|
|
2037
2074
|
if (toolBlock) return toolBlock;
|
|
@@ -2638,6 +2675,7 @@ function registerToolingTools(server2) {
|
|
|
2638
2675
|
teamId: teamId6,
|
|
2639
2676
|
orgId: orgId6
|
|
2640
2677
|
},
|
|
2678
|
+
toolAnnotations("exec_with_secrets"),
|
|
2641
2679
|
async (params) => {
|
|
2642
2680
|
const toolBlock = enforceToolPolicy("exec_with_secrets", params.projectPath);
|
|
2643
2681
|
if (toolBlock) return toolBlock;
|
|
@@ -2665,10 +2703,7 @@ ${result.stdout}`);
|
|
|
2665
2703
|
${result.stderr}`);
|
|
2666
2704
|
return text(output.join("\n\n"));
|
|
2667
2705
|
} catch (err) {
|
|
2668
|
-
return text(
|
|
2669
|
-
`Execution failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2670
|
-
true
|
|
2671
|
-
);
|
|
2706
|
+
return text(`Execution failed: ${err instanceof Error ? err.message : String(err)}`, true);
|
|
2672
2707
|
}
|
|
2673
2708
|
}
|
|
2674
2709
|
);
|
|
@@ -2684,6 +2719,7 @@ ${result.stderr}`);
|
|
|
2684
2719
|
"Directory to scan, absolute or relative to the server cwd. The scan recurses into subdirectories."
|
|
2685
2720
|
)
|
|
2686
2721
|
},
|
|
2722
|
+
toolAnnotations("scan_codebase_for_secrets"),
|
|
2687
2723
|
async (params) => {
|
|
2688
2724
|
const toolBlock = enforceToolPolicy("scan_codebase_for_secrets");
|
|
2689
2725
|
if (toolBlock) return toolBlock;
|
|
@@ -2694,10 +2730,7 @@ ${result.stderr}`);
|
|
|
2694
2730
|
}
|
|
2695
2731
|
return text(JSON.stringify(results, null, 2));
|
|
2696
2732
|
} catch (err) {
|
|
2697
|
-
return text(
|
|
2698
|
-
`Scan failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2699
|
-
true
|
|
2700
|
-
);
|
|
2733
|
+
return text(`Scan failed: ${err instanceof Error ? err.message : String(err)}`, true);
|
|
2701
2734
|
}
|
|
2702
2735
|
}
|
|
2703
2736
|
);
|
|
@@ -2709,9 +2742,7 @@ ${result.stderr}`);
|
|
|
2709
2742
|
"With `fix: false` this is read-only. With `fix: true` this MUTATES the listed source files in place (review with git diff!) and writes one new secret per finding to the keyring. Returns a JSON array of `{ file, line, key, value, kind }` findings, or 'No hardcoded secrets found in the specified files.'."
|
|
2710
2743
|
].join(" "),
|
|
2711
2744
|
{
|
|
2712
|
-
files: z9.array(z9.string()).describe(
|
|
2713
|
-
"Absolute or relative paths to lint. Non-existent paths surface as scan errors."
|
|
2714
|
-
),
|
|
2745
|
+
files: z9.array(z9.string()).describe("Absolute or relative paths to lint. Non-existent paths surface as scan errors."),
|
|
2715
2746
|
fix: z9.boolean().optional().default(false).describe(
|
|
2716
2747
|
"If true, rewrite the source files to read `process.env.KEY` and store the extracted value in the keyring. If false (default), only report findings."
|
|
2717
2748
|
),
|
|
@@ -2720,6 +2751,7 @@ ${result.stderr}`);
|
|
|
2720
2751
|
teamId: teamId6,
|
|
2721
2752
|
orgId: orgId6
|
|
2722
2753
|
},
|
|
2754
|
+
toolAnnotations("lint_files"),
|
|
2723
2755
|
async (params) => {
|
|
2724
2756
|
const toolBlock = enforceToolPolicy("lint_files", params.projectPath);
|
|
2725
2757
|
if (toolBlock) return toolBlock;
|
|
@@ -2734,10 +2766,7 @@ ${result.stderr}`);
|
|
|
2734
2766
|
}
|
|
2735
2767
|
return text(JSON.stringify(results, null, 2));
|
|
2736
2768
|
} catch (err) {
|
|
2737
|
-
return text(
|
|
2738
|
-
`Lint failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2739
|
-
true
|
|
2740
|
-
);
|
|
2769
|
+
return text(`Lint failed: ${err instanceof Error ? err.message : String(err)}`, true);
|
|
2741
2770
|
}
|
|
2742
2771
|
}
|
|
2743
2772
|
);
|
|
@@ -2754,6 +2783,7 @@ ${result.stderr}`);
|
|
|
2754
2783
|
teamId: teamId6,
|
|
2755
2784
|
orgId: orgId6
|
|
2756
2785
|
},
|
|
2786
|
+
toolAnnotations("analyze_secrets"),
|
|
2757
2787
|
async (params) => {
|
|
2758
2788
|
const toolBlock = enforceToolPolicy("analyze_secrets", params.projectPath);
|
|
2759
2789
|
if (toolBlock) return toolBlock;
|
|
@@ -2790,15 +2820,14 @@ ${result.stderr}`);
|
|
|
2790
2820
|
"TCP port to listen on (default 9876). Pick another port if 9876 is already in use; the call fails if binding errors."
|
|
2791
2821
|
)
|
|
2792
2822
|
},
|
|
2823
|
+
toolAnnotations("status_dashboard"),
|
|
2793
2824
|
async (params) => {
|
|
2794
2825
|
const toolBlock = enforceToolPolicy("status_dashboard");
|
|
2795
2826
|
if (toolBlock) return toolBlock;
|
|
2796
2827
|
if (dashboardInstance) {
|
|
2797
|
-
return text(
|
|
2798
|
-
`Dashboard already running at ${dashboardInstance.url}`
|
|
2799
|
-
);
|
|
2828
|
+
return text(`Dashboard already running at ${dashboardInstance.url}`);
|
|
2800
2829
|
}
|
|
2801
|
-
const { startDashboardServer } = await import("./dashboard-
|
|
2830
|
+
const { startDashboardServer } = await import("./dashboard-WVPR5BQO.js");
|
|
2802
2831
|
dashboardInstance = startDashboardServer({ port: params.port });
|
|
2803
2832
|
return text(
|
|
2804
2833
|
`Dashboard started at ${dashboardInstance.url}
|
|
@@ -2821,6 +2850,7 @@ Open this URL in a browser to see live quantum status. The token is required for
|
|
|
2821
2850
|
"List of absolute project roots to scan. Defaults to `[server.cwd]` when omitted."
|
|
2822
2851
|
)
|
|
2823
2852
|
},
|
|
2853
|
+
toolAnnotations("agent_scan"),
|
|
2824
2854
|
async (params) => {
|
|
2825
2855
|
const toolBlock = enforceToolPolicy("agent_scan");
|
|
2826
2856
|
if (toolBlock) return toolBlock;
|
|
@@ -2851,6 +2881,7 @@ function registerAgentTools(server2) {
|
|
|
2851
2881
|
"Plain-string value to store. JSON-stringify structured data on the caller side if needed."
|
|
2852
2882
|
)
|
|
2853
2883
|
},
|
|
2884
|
+
toolAnnotations("agent_remember"),
|
|
2854
2885
|
async (params) => {
|
|
2855
2886
|
const toolBlock = enforceToolPolicy("agent_remember");
|
|
2856
2887
|
if (toolBlock) return toolBlock;
|
|
@@ -2866,10 +2897,9 @@ function registerAgentTools(server2) {
|
|
|
2866
2897
|
"Read-only. With a `key` argument: returns JSON `{ ok, data: { key, value } }` or a not-found error. Without `key`: returns a JSON listing of every stored key (no values), or 'Agent memory is empty'."
|
|
2867
2898
|
].join(" "),
|
|
2868
2899
|
{
|
|
2869
|
-
key: z10.string().optional().describe(
|
|
2870
|
-
"Memory key to read. Omit to list every stored key (without values)."
|
|
2871
|
-
)
|
|
2900
|
+
key: z10.string().optional().describe("Memory key to read. Omit to list every stored key (without values).")
|
|
2872
2901
|
},
|
|
2902
|
+
toolAnnotations("agent_recall"),
|
|
2873
2903
|
async (params) => {
|
|
2874
2904
|
const toolBlock = enforceToolPolicy("agent_recall");
|
|
2875
2905
|
if (toolBlock) return toolBlock;
|
|
@@ -2879,11 +2909,8 @@ function registerAgentTools(server2) {
|
|
|
2879
2909
|
return text(JSON.stringify(entries, null, 2));
|
|
2880
2910
|
}
|
|
2881
2911
|
const value = recall(params.key);
|
|
2882
|
-
if (value === null)
|
|
2883
|
-
|
|
2884
|
-
return text(
|
|
2885
|
-
JSON.stringify({ ok: true, data: { key: params.key, value } }, null, 2)
|
|
2886
|
-
);
|
|
2912
|
+
if (value === null) return text(`No memory found for "${params.key}"`, true);
|
|
2913
|
+
return text(JSON.stringify({ ok: true, data: { key: params.key, value } }, null, 2));
|
|
2887
2914
|
}
|
|
2888
2915
|
);
|
|
2889
2916
|
server2.tool(
|
|
@@ -2896,6 +2923,7 @@ function registerAgentTools(server2) {
|
|
|
2896
2923
|
{
|
|
2897
2924
|
key: z10.string().describe("Memory key to delete.")
|
|
2898
2925
|
},
|
|
2926
|
+
toolAnnotations("agent_forget"),
|
|
2899
2927
|
async (params) => {
|
|
2900
2928
|
const toolBlock = enforceToolPolicy("agent_forget");
|
|
2901
2929
|
if (toolBlock) return toolBlock;
|
|
@@ -2923,17 +2951,14 @@ function registerPolicyTools(server2) {
|
|
|
2923
2951
|
action: z11.enum(["tool", "key_read", "exec"]).describe(
|
|
2924
2952
|
"Which policy surface to query. 'tool' = MCP tool gate (needs `toolName`); 'key_read' = secret read gate (needs `key`); 'exec' = exec_with_secrets command gate (needs `command`)."
|
|
2925
2953
|
),
|
|
2926
|
-
toolName: z11.string().optional().describe(
|
|
2927
|
-
|
|
2928
|
-
),
|
|
2929
|
-
key: z11.string().optional().describe(
|
|
2930
|
-
"Secret key name to evaluate. Required when `action` is 'key_read'."
|
|
2931
|
-
),
|
|
2954
|
+
toolName: z11.string().optional().describe("Tool id to evaluate, e.g. 'rotate_secret'. Required when `action` is 'tool'."),
|
|
2955
|
+
key: z11.string().optional().describe("Secret key name to evaluate. Required when `action` is 'key_read'."),
|
|
2932
2956
|
command: z11.string().optional().describe(
|
|
2933
2957
|
"Command to evaluate against the exec allowlist/denylist. Required when `action` is 'exec'."
|
|
2934
2958
|
),
|
|
2935
2959
|
projectPath: projectPath7
|
|
2936
2960
|
},
|
|
2961
|
+
toolAnnotations("check_policy"),
|
|
2937
2962
|
async (params) => {
|
|
2938
2963
|
if (params.action === "tool" && params.toolName) {
|
|
2939
2964
|
const d = checkToolPolicy(params.toolName, params.projectPath);
|
|
@@ -2947,10 +2972,7 @@ function registerPolicyTools(server2) {
|
|
|
2947
2972
|
const d = checkExecPolicy(params.command, params.projectPath);
|
|
2948
2973
|
return text(JSON.stringify(d, null, 2));
|
|
2949
2974
|
}
|
|
2950
|
-
return text(
|
|
2951
|
-
"Missing required parameter for the selected action type",
|
|
2952
|
-
true
|
|
2953
|
-
);
|
|
2975
|
+
return text("Missing required parameter for the selected action type", true);
|
|
2954
2976
|
}
|
|
2955
2977
|
);
|
|
2956
2978
|
server2.tool(
|
|
@@ -2963,11 +2985,9 @@ function registerPolicyTools(server2) {
|
|
|
2963
2985
|
{
|
|
2964
2986
|
projectPath: projectPath7
|
|
2965
2987
|
},
|
|
2988
|
+
toolAnnotations("get_policy_summary"),
|
|
2966
2989
|
async (params) => {
|
|
2967
|
-
const toolBlock = enforceToolPolicy(
|
|
2968
|
-
"get_policy_summary",
|
|
2969
|
-
params.projectPath
|
|
2970
|
-
);
|
|
2990
|
+
const toolBlock = enforceToolPolicy("get_policy_summary", params.projectPath);
|
|
2971
2991
|
if (toolBlock) return toolBlock;
|
|
2972
2992
|
const summary = getPolicySummary(params.projectPath);
|
|
2973
2993
|
return text(JSON.stringify(summary, null, 2));
|