@owrede/vault-memory 2.0.0-rc.2 → 2.0.0-rc.5
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/CHANGELOG.md +1304 -0
- package/dist/cli.js +696 -262
- package/dist/cli.js.map +1 -1
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -760,6 +760,52 @@ var init_suppress_contract_write = __esm({
|
|
|
760
760
|
}
|
|
761
761
|
});
|
|
762
762
|
|
|
763
|
+
// src/plugin-tools/source-tools.ts
|
|
764
|
+
import { z as z8 } from "zod";
|
|
765
|
+
async function refreshHandler(args2, deps) {
|
|
766
|
+
const info = await deps.refresh(args2.name);
|
|
767
|
+
if (info === void 0) {
|
|
768
|
+
return { ok: false, name: args2.name, error: `unknown source: ${args2.name}` };
|
|
769
|
+
}
|
|
770
|
+
const result = {
|
|
771
|
+
ok: true,
|
|
772
|
+
name: args2.name,
|
|
773
|
+
status: info.status,
|
|
774
|
+
tool_count: info.tools.length
|
|
775
|
+
};
|
|
776
|
+
if (info.error !== void 0) result.error = info.error;
|
|
777
|
+
return result;
|
|
778
|
+
}
|
|
779
|
+
async function unsetHandler(args2, deps) {
|
|
780
|
+
const removed = deps.remove(args2.name);
|
|
781
|
+
return { ok: true, name: args2.name, removed };
|
|
782
|
+
}
|
|
783
|
+
var RefreshSourceArgs, refreshSourceTool, UnsetMcpClientArgs, unsetMcpClientTool;
|
|
784
|
+
var init_source_tools = __esm({
|
|
785
|
+
"src/plugin-tools/source-tools.ts"() {
|
|
786
|
+
"use strict";
|
|
787
|
+
init_esm_shims();
|
|
788
|
+
RefreshSourceArgs = z8.object({
|
|
789
|
+
name: z8.string().min(1).describe("Peer-MCP source name to refresh (re-poll tools/list).")
|
|
790
|
+
});
|
|
791
|
+
refreshSourceTool = {
|
|
792
|
+
name: "refresh_source",
|
|
793
|
+
description: "Re-poll tools/list against a live peer-MCP source and refresh its cached tool list. Returns the updated status (connected/unavailable/unreachable) and tool_count. SOURCES-REGISTRY \xA76.3.",
|
|
794
|
+
inputSchema: RefreshSourceArgs,
|
|
795
|
+
handler: refreshHandler
|
|
796
|
+
};
|
|
797
|
+
UnsetMcpClientArgs = z8.object({
|
|
798
|
+
name: z8.string().min(1).describe("Peer-MCP source name to disconnect + drop from the registry.")
|
|
799
|
+
});
|
|
800
|
+
unsetMcpClientTool = {
|
|
801
|
+
name: "unset_mcp_client",
|
|
802
|
+
description: "Disconnect a live peer-MCP source and drop it from the running registry. Idempotent (removed:false when the name is unknown). Affects the running process only \u2014 pair with set_mcp_client({name, remove:true}) to also delete the persisted config entry. SOURCES-REGISTRY \xA76.2.",
|
|
803
|
+
inputSchema: UnsetMcpClientArgs,
|
|
804
|
+
handler: unsetHandler
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
|
|
763
809
|
// src/plugin-tools/index.ts
|
|
764
810
|
function ok(data) {
|
|
765
811
|
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
@@ -921,6 +967,54 @@ function syncPluginTools(server, registered, opts) {
|
|
|
921
967
|
}
|
|
922
968
|
}
|
|
923
969
|
)
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
name: "refresh_source",
|
|
973
|
+
reg: () => server.registerTool(
|
|
974
|
+
refreshSourceTool.name,
|
|
975
|
+
{
|
|
976
|
+
description: refreshSourceTool.description,
|
|
977
|
+
inputSchema: refreshSourceTool.inputSchema.shape
|
|
978
|
+
},
|
|
979
|
+
async (args2) => {
|
|
980
|
+
try {
|
|
981
|
+
const validated = refreshSourceTool.inputSchema.parse(
|
|
982
|
+
args2
|
|
983
|
+
);
|
|
984
|
+
const result = await refreshSourceTool.handler(
|
|
985
|
+
validated,
|
|
986
|
+
opts.sourceRegistry
|
|
987
|
+
);
|
|
988
|
+
return ok(result);
|
|
989
|
+
} catch (err) {
|
|
990
|
+
return errorResponse(err instanceof Error ? err.message : String(err));
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
)
|
|
994
|
+
},
|
|
995
|
+
{
|
|
996
|
+
name: "unset_mcp_client",
|
|
997
|
+
reg: () => server.registerTool(
|
|
998
|
+
unsetMcpClientTool.name,
|
|
999
|
+
{
|
|
1000
|
+
description: unsetMcpClientTool.description,
|
|
1001
|
+
inputSchema: unsetMcpClientTool.inputSchema.shape
|
|
1002
|
+
},
|
|
1003
|
+
async (args2) => {
|
|
1004
|
+
try {
|
|
1005
|
+
const validated = unsetMcpClientTool.inputSchema.parse(
|
|
1006
|
+
args2
|
|
1007
|
+
);
|
|
1008
|
+
const result = await unsetMcpClientTool.handler(
|
|
1009
|
+
validated,
|
|
1010
|
+
opts.sourceRegistry
|
|
1011
|
+
);
|
|
1012
|
+
return ok(result);
|
|
1013
|
+
} catch (err) {
|
|
1014
|
+
return errorResponse(err instanceof Error ? err.message : String(err));
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
)
|
|
924
1018
|
}
|
|
925
1019
|
];
|
|
926
1020
|
for (const { name, reg } of adds) {
|
|
@@ -941,12 +1035,14 @@ var init_plugin_tools = __esm({
|
|
|
941
1035
|
init_get_runtime_stats();
|
|
942
1036
|
init_trigger_reindex();
|
|
943
1037
|
init_suppress_contract_write();
|
|
1038
|
+
init_source_tools();
|
|
944
1039
|
init_set_runtime_config();
|
|
945
1040
|
init_resolve_secret();
|
|
946
1041
|
init_set_mcp_client();
|
|
947
1042
|
init_get_runtime_stats();
|
|
948
1043
|
init_trigger_reindex();
|
|
949
1044
|
init_suppress_contract_write();
|
|
1045
|
+
init_source_tools();
|
|
950
1046
|
init_runtime_config();
|
|
951
1047
|
PLUGIN_TOOL_NAMES = [
|
|
952
1048
|
"set_runtime_config",
|
|
@@ -954,7 +1050,10 @@ var init_plugin_tools = __esm({
|
|
|
954
1050
|
"set_mcp_client",
|
|
955
1051
|
"get_runtime_stats",
|
|
956
1052
|
"trigger_reindex",
|
|
957
|
-
"suppress_contract_write"
|
|
1053
|
+
"suppress_contract_write",
|
|
1054
|
+
// SOURCES-REGISTRY.md §6 (Stage 2) — live-registry source management.
|
|
1055
|
+
"refresh_source",
|
|
1056
|
+
"unset_mcp_client"
|
|
958
1057
|
];
|
|
959
1058
|
}
|
|
960
1059
|
});
|
|
@@ -3525,7 +3624,7 @@ var init_retry = __esm({
|
|
|
3525
3624
|
});
|
|
3526
3625
|
|
|
3527
3626
|
// src/ollama/client.ts
|
|
3528
|
-
import { z as
|
|
3627
|
+
import { z as z9 } from "zod";
|
|
3529
3628
|
function isRetryable(err) {
|
|
3530
3629
|
if (err instanceof OllamaHttpError) {
|
|
3531
3630
|
return err.status >= 500 && err.status < 600;
|
|
@@ -3548,26 +3647,26 @@ var init_client = __esm({
|
|
|
3548
3647
|
DEFAULT_BATCH_SIZE = 10;
|
|
3549
3648
|
DEFAULT_TIMEOUT_MS = 3e4;
|
|
3550
3649
|
DEFAULT_RETRIES = 3;
|
|
3551
|
-
EmbedResponseSchema =
|
|
3552
|
-
embeddings:
|
|
3553
|
-
model:
|
|
3650
|
+
EmbedResponseSchema = z9.object({
|
|
3651
|
+
embeddings: z9.array(z9.array(z9.number())),
|
|
3652
|
+
model: z9.string().optional()
|
|
3554
3653
|
});
|
|
3555
|
-
TagsResponseSchema =
|
|
3556
|
-
models:
|
|
3557
|
-
|
|
3558
|
-
name:
|
|
3654
|
+
TagsResponseSchema = z9.object({
|
|
3655
|
+
models: z9.array(
|
|
3656
|
+
z9.object({
|
|
3657
|
+
name: z9.string()
|
|
3559
3658
|
})
|
|
3560
3659
|
)
|
|
3561
3660
|
});
|
|
3562
|
-
ChatResponseSchema =
|
|
3563
|
-
model:
|
|
3564
|
-
message:
|
|
3565
|
-
role:
|
|
3566
|
-
content:
|
|
3661
|
+
ChatResponseSchema = z9.object({
|
|
3662
|
+
model: z9.string(),
|
|
3663
|
+
message: z9.object({
|
|
3664
|
+
role: z9.literal("assistant"),
|
|
3665
|
+
content: z9.string()
|
|
3567
3666
|
}),
|
|
3568
|
-
done:
|
|
3569
|
-
total_duration:
|
|
3570
|
-
eval_count:
|
|
3667
|
+
done: z9.boolean().optional(),
|
|
3668
|
+
total_duration: z9.number().optional(),
|
|
3669
|
+
eval_count: z9.number().optional()
|
|
3571
3670
|
});
|
|
3572
3671
|
OllamaHttpError = class extends Error {
|
|
3573
3672
|
status;
|
|
@@ -5434,7 +5533,16 @@ var init_obsidian_fs = __esm({
|
|
|
5434
5533
|
if (since !== void 0 && mtime < since) continue;
|
|
5435
5534
|
const body = await fs4.readFile(abs, "utf-8");
|
|
5436
5535
|
const hash = computeBodyHash(body);
|
|
5437
|
-
|
|
5536
|
+
let id;
|
|
5537
|
+
try {
|
|
5538
|
+
id = this.pathToDocId(rel);
|
|
5539
|
+
} catch (err) {
|
|
5540
|
+
console.error(
|
|
5541
|
+
`[obsidian-fs:${this.vault.name}] skipping un-addressable file ${JSON.stringify(rel)}: ${err instanceof Error ? err.message : String(err)}`
|
|
5542
|
+
);
|
|
5543
|
+
continue;
|
|
5544
|
+
}
|
|
5545
|
+
yield { id, mtime, hash };
|
|
5438
5546
|
yielded++;
|
|
5439
5547
|
}
|
|
5440
5548
|
}
|
|
@@ -7395,7 +7503,7 @@ var init_validator = __esm({
|
|
|
7395
7503
|
});
|
|
7396
7504
|
|
|
7397
7505
|
// src/memory/contract/default-v1.ts
|
|
7398
|
-
import { z as
|
|
7506
|
+
import { z as z10 } from "zod";
|
|
7399
7507
|
var requiredKeys, baseShape, DEFAULT_MEMORY_V1;
|
|
7400
7508
|
var init_default_v1 = __esm({
|
|
7401
7509
|
"src/memory/contract/default-v1.ts"() {
|
|
@@ -7410,15 +7518,15 @@ var init_default_v1 = __esm({
|
|
|
7410
7518
|
"superseded_by",
|
|
7411
7519
|
"type"
|
|
7412
7520
|
];
|
|
7413
|
-
baseShape =
|
|
7414
|
-
source:
|
|
7415
|
-
confidence:
|
|
7416
|
-
evidence:
|
|
7417
|
-
status:
|
|
7418
|
-
observed_at:
|
|
7419
|
-
superseded_by:
|
|
7420
|
-
type:
|
|
7421
|
-
superseded_reason:
|
|
7521
|
+
baseShape = z10.object({
|
|
7522
|
+
source: z10.enum(["agent", "user", "imported"]),
|
|
7523
|
+
confidence: z10.enum(["direct", "inferred", "uncertain"]),
|
|
7524
|
+
evidence: z10.array(z10.string()),
|
|
7525
|
+
status: z10.enum(["active", "superseded", "archived"]).default("active"),
|
|
7526
|
+
observed_at: z10.string().datetime({ offset: true }),
|
|
7527
|
+
superseded_by: z10.string().nullable().default(null),
|
|
7528
|
+
type: z10.string().min(1),
|
|
7529
|
+
superseded_reason: z10.string().optional()
|
|
7422
7530
|
}).passthrough().superRefine((data, ctx) => {
|
|
7423
7531
|
if (data.status === "superseded") {
|
|
7424
7532
|
if (data.superseded_by === null || data.superseded_by === void 0) {
|
|
@@ -7451,7 +7559,7 @@ var init_default_v1 = __esm({
|
|
|
7451
7559
|
});
|
|
7452
7560
|
|
|
7453
7561
|
// src/memory/contract/default-brief-v1.ts
|
|
7454
|
-
import { z as
|
|
7562
|
+
import { z as z11 } from "zod";
|
|
7455
7563
|
var requiredKeys2, baseShape2, DEFAULT_BRIEF_V1;
|
|
7456
7564
|
var init_default_brief_v1 = __esm({
|
|
7457
7565
|
"src/memory/contract/default-brief-v1.ts"() {
|
|
@@ -7473,29 +7581,29 @@ var init_default_brief_v1 = __esm({
|
|
|
7473
7581
|
"compiled_at",
|
|
7474
7582
|
"source_hashes"
|
|
7475
7583
|
];
|
|
7476
|
-
baseShape2 =
|
|
7584
|
+
baseShape2 = z11.object({
|
|
7477
7585
|
// ── Base shape inherited from default-v1 ────────────────────────
|
|
7478
|
-
source:
|
|
7479
|
-
confidence:
|
|
7480
|
-
evidence:
|
|
7586
|
+
source: z11.enum(["agent", "user", "imported"]),
|
|
7587
|
+
confidence: z11.enum(["direct", "inferred", "uncertain"]),
|
|
7588
|
+
evidence: z11.array(z11.string()),
|
|
7481
7589
|
// ── Status enum WIDENED for briefs: + "stale" ──────────────────
|
|
7482
|
-
status:
|
|
7483
|
-
observed_at:
|
|
7484
|
-
superseded_by:
|
|
7485
|
-
type:
|
|
7486
|
-
superseded_reason:
|
|
7590
|
+
status: z11.enum(["active", "stale", "superseded", "archived"]).default("active"),
|
|
7591
|
+
observed_at: z11.string().datetime({ offset: true }),
|
|
7592
|
+
superseded_by: z11.string().nullable().default(null),
|
|
7593
|
+
type: z11.string().min(1),
|
|
7594
|
+
superseded_reason: z11.string().optional(),
|
|
7487
7595
|
// ── Brief-specific properties (D-11 brief shape) ───────────────
|
|
7488
|
-
target:
|
|
7596
|
+
target: z11.string().min(1),
|
|
7489
7597
|
/**
|
|
7490
7598
|
* Brief purpose — free text but bounded at 500 chars so
|
|
7491
7599
|
* `list_briefs` stays scannable. Lower bound `min(1)` matches
|
|
7492
7600
|
* BRF-03 "no empty purpose".
|
|
7493
7601
|
*/
|
|
7494
|
-
purpose:
|
|
7602
|
+
purpose: z11.string().min(1).max(500),
|
|
7495
7603
|
/** DocId list of all sources the brief was compiled from. */
|
|
7496
|
-
compiled_from:
|
|
7604
|
+
compiled_from: z11.array(z11.string()).min(1),
|
|
7497
7605
|
/** ISO-8601 datetime with offset (mirrors observed_at). */
|
|
7498
|
-
compiled_at:
|
|
7606
|
+
compiled_at: z11.string().datetime({ offset: true }),
|
|
7499
7607
|
/**
|
|
7500
7608
|
* Record<ChunkId, BriefSourceHash> — staleness contract. The map
|
|
7501
7609
|
* key is the public ChunkId (`<DocId>#chunk-<7-hex>`); the value
|
|
@@ -7503,12 +7611,12 @@ var init_default_brief_v1 = __esm({
|
|
|
7503
7611
|
* the cross-field invariant below only REQUIRES it on stale; the
|
|
7504
7612
|
* validator still rejects `status: "stale"` writes that omit it.
|
|
7505
7613
|
*/
|
|
7506
|
-
source_hashes:
|
|
7614
|
+
source_hashes: z11.record(z11.string(), z11.string()).optional(),
|
|
7507
7615
|
/**
|
|
7508
7616
|
* Daemon-computed list of source DocIds whose hashes have
|
|
7509
7617
|
* diverged. Populated when `status` flips to `"stale"`.
|
|
7510
7618
|
*/
|
|
7511
|
-
changed_sources:
|
|
7619
|
+
changed_sources: z11.array(z11.string()).optional()
|
|
7512
7620
|
}).passthrough().superRefine((data, ctx) => {
|
|
7513
7621
|
if (data.status === "superseded") {
|
|
7514
7622
|
if (data.superseded_by === null || data.superseded_by === void 0) {
|
|
@@ -7578,36 +7686,36 @@ var init_contract_yaml_read = __esm({
|
|
|
7578
7686
|
});
|
|
7579
7687
|
|
|
7580
7688
|
// src/memory/contract/schema.ts
|
|
7581
|
-
import { z as
|
|
7689
|
+
import { z as z12 } from "zod";
|
|
7582
7690
|
var PropertyRuleSchema, CrossFieldRuleSchema, MemoryContractYamlSchema;
|
|
7583
7691
|
var init_schema2 = __esm({
|
|
7584
7692
|
"src/memory/contract/schema.ts"() {
|
|
7585
7693
|
"use strict";
|
|
7586
7694
|
init_esm_shims();
|
|
7587
|
-
PropertyRuleSchema =
|
|
7588
|
-
type:
|
|
7589
|
-
allowed:
|
|
7590
|
-
default:
|
|
7591
|
-
items:
|
|
7592
|
-
min_length:
|
|
7695
|
+
PropertyRuleSchema = z12.object({
|
|
7696
|
+
type: z12.enum(["string", "datetime", "array", "doc_id", "number", "boolean", "reference", "date"]),
|
|
7697
|
+
allowed: z12.array(z12.string()).optional(),
|
|
7698
|
+
default: z12.unknown().optional(),
|
|
7699
|
+
items: z12.object({ type: z12.string() }).optional(),
|
|
7700
|
+
min_length: z12.number().optional(),
|
|
7593
7701
|
/** When true, the property accepts `null` as a sentinel value (in
|
|
7594
7702
|
* addition to whatever `type` says). Used for required-but-null-by-
|
|
7595
7703
|
* default properties like `superseded_by` on active observations. */
|
|
7596
|
-
nullable:
|
|
7704
|
+
nullable: z12.boolean().optional()
|
|
7597
7705
|
});
|
|
7598
|
-
CrossFieldRuleSchema =
|
|
7599
|
-
when:
|
|
7600
|
-
require:
|
|
7706
|
+
CrossFieldRuleSchema = z12.object({
|
|
7707
|
+
when: z12.string(),
|
|
7708
|
+
require: z12.string()
|
|
7601
7709
|
});
|
|
7602
|
-
MemoryContractYamlSchema =
|
|
7603
|
-
name:
|
|
7604
|
-
version:
|
|
7605
|
-
required_properties:
|
|
7606
|
-
optional_properties:
|
|
7607
|
-
cross_field_rules:
|
|
7608
|
-
naming:
|
|
7609
|
-
strategy:
|
|
7610
|
-
pattern:
|
|
7710
|
+
MemoryContractYamlSchema = z12.object({
|
|
7711
|
+
name: z12.string().min(1),
|
|
7712
|
+
version: z12.string().default("1.0"),
|
|
7713
|
+
required_properties: z12.record(z12.string(), PropertyRuleSchema),
|
|
7714
|
+
optional_properties: z12.record(z12.string(), PropertyRuleSchema).default({}),
|
|
7715
|
+
cross_field_rules: z12.array(CrossFieldRuleSchema).default([]),
|
|
7716
|
+
naming: z12.object({
|
|
7717
|
+
strategy: z12.enum(["caller-provided", "date-slug", "adapter-assigned"]),
|
|
7718
|
+
pattern: z12.string().optional()
|
|
7611
7719
|
})
|
|
7612
7720
|
});
|
|
7613
7721
|
}
|
|
@@ -7615,7 +7723,7 @@ var init_schema2 = __esm({
|
|
|
7615
7723
|
|
|
7616
7724
|
// src/memory/contract/loader.ts
|
|
7617
7725
|
import { parse as parseYaml } from "yaml";
|
|
7618
|
-
import { z as
|
|
7726
|
+
import { z as z13 } from "zod";
|
|
7619
7727
|
function __cacheContract(name, contract) {
|
|
7620
7728
|
contractCache.set(name, contract);
|
|
7621
7729
|
}
|
|
@@ -9213,7 +9321,7 @@ var init_memory_stats = __esm({
|
|
|
9213
9321
|
});
|
|
9214
9322
|
|
|
9215
9323
|
// src/memory/resources/index.ts
|
|
9216
|
-
var RESOURCE_URI_LIST_SINKS, RESOURCE_URI_MEMORY_STATS, RESOURCE_URI_LIST_BRIEFS, RESOURCE_URI_LIST_CONTRACTS, RESOURCE_URI_LIST_CONTRACT_VERBS, RESOURCE_URI_VAULTS, RESOURCE_URI_MODELS, RESOURCE_URI_RECENT, RESOURCE_URI_STATS, RESOURCE_URI_BACKLINKS;
|
|
9324
|
+
var RESOURCE_URI_LIST_SINKS, RESOURCE_URI_MEMORY_STATS, RESOURCE_URI_LIST_BRIEFS, RESOURCE_URI_LIST_CONTRACTS, RESOURCE_URI_LIST_CONTRACT_VERBS, RESOURCE_URI_SOURCES, RESOURCE_URI_VAULTS, RESOURCE_URI_MODELS, RESOURCE_URI_RECENT, RESOURCE_URI_STATS, RESOURCE_URI_BACKLINKS;
|
|
9217
9325
|
var init_resources = __esm({
|
|
9218
9326
|
"src/memory/resources/index.ts"() {
|
|
9219
9327
|
"use strict";
|
|
@@ -9225,6 +9333,7 @@ var init_resources = __esm({
|
|
|
9225
9333
|
RESOURCE_URI_LIST_BRIEFS = "vault-memory://briefs";
|
|
9226
9334
|
RESOURCE_URI_LIST_CONTRACTS = "vault-memory://contracts";
|
|
9227
9335
|
RESOURCE_URI_LIST_CONTRACT_VERBS = "vault-memory://contract-verbs";
|
|
9336
|
+
RESOURCE_URI_SOURCES = "vault-memory://sources";
|
|
9228
9337
|
RESOURCE_URI_VAULTS = "vault-memory://vaults";
|
|
9229
9338
|
RESOURCE_URI_MODELS = "vault-memory://models";
|
|
9230
9339
|
RESOURCE_URI_RECENT = "vault-memory://recent";
|
|
@@ -9286,6 +9395,25 @@ var init_resource_registry = __esm({
|
|
|
9286
9395
|
description: "List baseline assembly verbs + custom (mcp://) verbs in use, with invocation_count + last_seen aggregated from contract_audit (D-A2b). Baseline verbs are constant per ADR-006 \xA7Decision 3.",
|
|
9287
9396
|
mimeType: "application/json"
|
|
9288
9397
|
},
|
|
9398
|
+
// ─── SOURCES-REGISTRY.md §5 (Stage 2) — peer-MCP source discovery ───────
|
|
9399
|
+
{
|
|
9400
|
+
name: "sources",
|
|
9401
|
+
uriTemplate: "vault-memory://sources",
|
|
9402
|
+
description: "List peer MCP servers vault-memory connects to, with per-source status (connected/unavailable/unreachable), tool_count, and last_refreshed. vault-memory itself is not included. SOURCES-REGISTRY \xA75.1.",
|
|
9403
|
+
mimeType: "application/json"
|
|
9404
|
+
},
|
|
9405
|
+
{
|
|
9406
|
+
name: "source-tools",
|
|
9407
|
+
uriTemplate: "vault-memory://sources/{name}/tools",
|
|
9408
|
+
description: "List the cached tools/list for one peer MCP source. Empty when the source is not connected. SOURCES-REGISTRY \xA75.2.",
|
|
9409
|
+
mimeType: "application/json"
|
|
9410
|
+
},
|
|
9411
|
+
{
|
|
9412
|
+
name: "source-tool",
|
|
9413
|
+
uriTemplate: "vault-memory://sources/{name}/tools/{tool}",
|
|
9414
|
+
description: "Read a single tool's schema from one peer MCP source, inlined from the cached tools/list. SOURCES-REGISTRY \xA75.3.",
|
|
9415
|
+
mimeType: "application/json"
|
|
9416
|
+
},
|
|
9289
9417
|
// ─── Phase 8 (Plan 08-05 / REL-08) — promoted from v1 tools ─────────────
|
|
9290
9418
|
{
|
|
9291
9419
|
name: "vaults",
|
|
@@ -11797,11 +11925,11 @@ var init_obsidian_fs3 = __esm({
|
|
|
11797
11925
|
});
|
|
11798
11926
|
|
|
11799
11927
|
// src/tool-registry.ts
|
|
11800
|
-
import { z as
|
|
11928
|
+
import { z as z14 } from "zod";
|
|
11801
11929
|
function buildToolSchema(name) {
|
|
11802
11930
|
const builder = SCHEMA_BUILDERS[name];
|
|
11803
11931
|
if (builder) return builder();
|
|
11804
|
-
return
|
|
11932
|
+
return z14.object(TOOL_SCHEMAS[name]);
|
|
11805
11933
|
}
|
|
11806
11934
|
var TOOLS, DOC_ID_PATTERN2, PredicateSchema, TOOL_SCHEMAS, SCHEMA_BUILDERS;
|
|
11807
11935
|
var init_tool_registry = __esm({
|
|
@@ -12674,243 +12802,243 @@ var init_tool_registry = __esm({
|
|
|
12674
12802
|
}
|
|
12675
12803
|
];
|
|
12676
12804
|
DOC_ID_PATTERN2 = /^[a-z][a-z0-9-]*:\/\/[^/]+\/.+$/;
|
|
12677
|
-
PredicateSchema =
|
|
12678
|
-
|
|
12679
|
-
|
|
12680
|
-
|
|
12681
|
-
|
|
12682
|
-
|
|
12683
|
-
|
|
12684
|
-
|
|
12805
|
+
PredicateSchema = z14.union([
|
|
12806
|
+
z14.string(),
|
|
12807
|
+
z14.number(),
|
|
12808
|
+
z14.boolean(),
|
|
12809
|
+
z14.null(),
|
|
12810
|
+
z14.object({ $in: z14.array(z14.union([z14.string(), z14.number(), z14.boolean(), z14.null()])) }),
|
|
12811
|
+
z14.object({ $exists: z14.boolean() }),
|
|
12812
|
+
z14.object({ $contains: z14.union([z14.string(), z14.number(), z14.boolean(), z14.null()]) })
|
|
12685
12813
|
]);
|
|
12686
12814
|
TOOL_SCHEMAS = {
|
|
12687
12815
|
list_vaults: {},
|
|
12688
12816
|
read_note: {
|
|
12689
|
-
vault:
|
|
12690
|
-
path:
|
|
12817
|
+
vault: z14.string(),
|
|
12818
|
+
path: z14.string()
|
|
12691
12819
|
},
|
|
12692
12820
|
search_semantic: {
|
|
12693
|
-
query:
|
|
12694
|
-
vaults:
|
|
12695
|
-
top_k:
|
|
12696
|
-
exclude_paths:
|
|
12821
|
+
query: z14.string().min(1),
|
|
12822
|
+
vaults: z14.array(z14.string()).optional(),
|
|
12823
|
+
top_k: z14.number().int().positive().max(100).optional().default(10),
|
|
12824
|
+
exclude_paths: z14.array(z14.string()).optional()
|
|
12697
12825
|
},
|
|
12698
12826
|
search_text: {
|
|
12699
|
-
query:
|
|
12700
|
-
vaults:
|
|
12701
|
-
top_k:
|
|
12702
|
-
exclude_paths:
|
|
12827
|
+
query: z14.string().min(1),
|
|
12828
|
+
vaults: z14.array(z14.string()).optional(),
|
|
12829
|
+
top_k: z14.number().int().positive().max(100).optional().default(10),
|
|
12830
|
+
exclude_paths: z14.array(z14.string()).optional()
|
|
12703
12831
|
},
|
|
12704
12832
|
search_hybrid: {
|
|
12705
|
-
query:
|
|
12706
|
-
vaults:
|
|
12707
|
-
top_k:
|
|
12708
|
-
rrf_k:
|
|
12709
|
-
exclude_paths:
|
|
12710
|
-
rerank:
|
|
12833
|
+
query: z14.string().min(1),
|
|
12834
|
+
vaults: z14.array(z14.string()).optional(),
|
|
12835
|
+
top_k: z14.number().int().positive().max(100).optional().default(10),
|
|
12836
|
+
rrf_k: z14.number().int().positive().max(1e3).optional().default(60),
|
|
12837
|
+
exclude_paths: z14.array(z14.string()).optional(),
|
|
12838
|
+
rerank: z14.boolean().optional().default(false),
|
|
12711
12839
|
// Phase 3 / 03-05 additive params — D-07, D-08, ASM-07, ASM-08.
|
|
12712
12840
|
// All `.optional()` with defaults that vanish when unset, so v1
|
|
12713
12841
|
// callers see no behavior change.
|
|
12714
|
-
recency_weight:
|
|
12715
|
-
authority_weight:
|
|
12716
|
-
half_life_days:
|
|
12717
|
-
include_superseded:
|
|
12842
|
+
recency_weight: z14.number().optional().default(0),
|
|
12843
|
+
authority_weight: z14.number().optional().default(0),
|
|
12844
|
+
half_life_days: z14.number().positive().optional().default(30),
|
|
12845
|
+
include_superseded: z14.boolean().optional().default(false),
|
|
12718
12846
|
// ── Phase 4 / 04-04 / GRA-03 (D-15): additive auto-expansion ──
|
|
12719
12847
|
// Nested under a single optional `expand` object per D-15. When
|
|
12720
12848
|
// omitted, hybridSearch behavior is byte-identical to v1 (the
|
|
12721
12849
|
// guard `if (opts.expand && opts.expandDeps && ...)` at the end of
|
|
12722
12850
|
// `src/search/hybrid.ts` short-circuits entirely). The literal-
|
|
12723
12851
|
// union for `hops` enforces the D-05 hop cap at the boundary.
|
|
12724
|
-
expand:
|
|
12725
|
-
hops:
|
|
12726
|
-
direction:
|
|
12727
|
-
edge_types:
|
|
12852
|
+
expand: z14.object({
|
|
12853
|
+
hops: z14.union([z14.literal(1), z14.literal(2)]),
|
|
12854
|
+
direction: z14.enum(["forward", "backward", "both"]).optional(),
|
|
12855
|
+
edge_types: z14.array(z14.enum(["wikilink", "mention", "frontmatter-ref", "hyperlink"])).optional()
|
|
12728
12856
|
}).optional()
|
|
12729
12857
|
},
|
|
12730
12858
|
list_backlinks: {
|
|
12731
|
-
vault:
|
|
12732
|
-
path:
|
|
12859
|
+
vault: z14.string(),
|
|
12860
|
+
path: z14.string()
|
|
12733
12861
|
},
|
|
12734
12862
|
list_forward_links: {
|
|
12735
|
-
vault:
|
|
12736
|
-
path:
|
|
12737
|
-
include_broken:
|
|
12863
|
+
vault: z14.string(),
|
|
12864
|
+
path: z14.string(),
|
|
12865
|
+
include_broken: z14.boolean().optional().default(true)
|
|
12738
12866
|
},
|
|
12739
12867
|
find_broken_links: {
|
|
12740
|
-
vault:
|
|
12868
|
+
vault: z14.string()
|
|
12741
12869
|
},
|
|
12742
12870
|
query_frontmatter: {
|
|
12743
|
-
vault:
|
|
12744
|
-
where:
|
|
12745
|
-
limit:
|
|
12871
|
+
vault: z14.string(),
|
|
12872
|
+
where: z14.record(z14.string(), PredicateSchema),
|
|
12873
|
+
limit: z14.number().int().positive().max(1e3).optional().default(100)
|
|
12746
12874
|
},
|
|
12747
12875
|
write_note: {
|
|
12748
|
-
vault:
|
|
12749
|
-
path:
|
|
12750
|
-
content:
|
|
12751
|
-
frontmatter:
|
|
12752
|
-
expected_hash:
|
|
12753
|
-
client_id:
|
|
12876
|
+
vault: z14.string(),
|
|
12877
|
+
path: z14.string(),
|
|
12878
|
+
content: z14.string(),
|
|
12879
|
+
frontmatter: z14.record(z14.string(), z14.unknown()).nullable().optional(),
|
|
12880
|
+
expected_hash: z14.string().optional(),
|
|
12881
|
+
client_id: z14.string().optional()
|
|
12754
12882
|
},
|
|
12755
12883
|
update_frontmatter: {
|
|
12756
|
-
vault:
|
|
12757
|
-
path:
|
|
12758
|
-
merge:
|
|
12759
|
-
expected_hash:
|
|
12760
|
-
client_id:
|
|
12884
|
+
vault: z14.string(),
|
|
12885
|
+
path: z14.string(),
|
|
12886
|
+
merge: z14.record(z14.string(), z14.unknown()),
|
|
12887
|
+
expected_hash: z14.string().optional(),
|
|
12888
|
+
client_id: z14.string().optional()
|
|
12761
12889
|
},
|
|
12762
12890
|
delete_note: {
|
|
12763
|
-
vault:
|
|
12764
|
-
path:
|
|
12765
|
-
expected_hash:
|
|
12766
|
-
client_id:
|
|
12891
|
+
vault: z14.string(),
|
|
12892
|
+
path: z14.string(),
|
|
12893
|
+
expected_hash: z14.string(),
|
|
12894
|
+
client_id: z14.string().optional()
|
|
12767
12895
|
},
|
|
12768
12896
|
audit_log: {
|
|
12769
|
-
vault:
|
|
12770
|
-
note_path:
|
|
12771
|
-
op:
|
|
12772
|
-
since:
|
|
12773
|
-
limit:
|
|
12897
|
+
vault: z14.string(),
|
|
12898
|
+
note_path: z14.string().optional(),
|
|
12899
|
+
op: z14.enum(["create", "update", "delete"]).optional(),
|
|
12900
|
+
since: z14.number().int().nonnegative().optional(),
|
|
12901
|
+
limit: z14.number().int().positive().max(1e3).optional().default(50),
|
|
12774
12902
|
// Plan 02-06 (MEM-08): additive optional filter. The MCP tool's
|
|
12775
12903
|
// `description` string is INTENTIONALLY unchanged — Phase 1 byte-identity
|
|
12776
12904
|
// is preserved. New capability is documented in docs/tools/audit_log.md.
|
|
12777
|
-
is_memory_sink_write:
|
|
12905
|
+
is_memory_sink_write: z14.boolean().optional()
|
|
12778
12906
|
},
|
|
12779
12907
|
list_models: {
|
|
12780
|
-
vault:
|
|
12908
|
+
vault: z14.string()
|
|
12781
12909
|
},
|
|
12782
12910
|
start_shadow_index: {
|
|
12783
|
-
vault:
|
|
12784
|
-
model:
|
|
12785
|
-
batch_size:
|
|
12911
|
+
vault: z14.string(),
|
|
12912
|
+
model: z14.string().min(1),
|
|
12913
|
+
batch_size: z14.number().int().positive().max(256).optional()
|
|
12786
12914
|
},
|
|
12787
12915
|
switch_active_model: {
|
|
12788
|
-
vault:
|
|
12789
|
-
model_name:
|
|
12916
|
+
vault: z14.string(),
|
|
12917
|
+
model_name: z14.string().min(1)
|
|
12790
12918
|
},
|
|
12791
12919
|
vacuum_embeddings: {
|
|
12792
|
-
vault:
|
|
12920
|
+
vault: z14.string()
|
|
12793
12921
|
},
|
|
12794
12922
|
index_runs: {
|
|
12795
|
-
vault:
|
|
12796
|
-
limit:
|
|
12923
|
+
vault: z14.string(),
|
|
12924
|
+
limit: z14.number().int().positive().max(200).optional().default(20)
|
|
12797
12925
|
},
|
|
12798
12926
|
search: {
|
|
12799
|
-
query:
|
|
12800
|
-
limit:
|
|
12927
|
+
query: z14.string().min(1),
|
|
12928
|
+
limit: z14.number().int().positive().max(50).optional().default(10)
|
|
12801
12929
|
},
|
|
12802
12930
|
fetch: {
|
|
12803
|
-
id:
|
|
12931
|
+
id: z14.string().min(1)
|
|
12804
12932
|
},
|
|
12805
12933
|
vault_stats: {
|
|
12806
|
-
vault:
|
|
12934
|
+
vault: z14.string().optional()
|
|
12807
12935
|
},
|
|
12808
12936
|
recent_notes: {
|
|
12809
|
-
vault:
|
|
12810
|
-
limit:
|
|
12811
|
-
since:
|
|
12937
|
+
vault: z14.string().optional(),
|
|
12938
|
+
limit: z14.number().int().positive().max(200).optional().default(20),
|
|
12939
|
+
since: z14.number().int().nonnegative().optional()
|
|
12812
12940
|
},
|
|
12813
12941
|
suggest_frontmatter: {
|
|
12814
|
-
vault:
|
|
12815
|
-
path:
|
|
12816
|
-
content:
|
|
12817
|
-
title:
|
|
12818
|
-
folder_hint:
|
|
12942
|
+
vault: z14.string(),
|
|
12943
|
+
path: z14.string().optional(),
|
|
12944
|
+
content: z14.string().optional(),
|
|
12945
|
+
title: z14.string().optional(),
|
|
12946
|
+
folder_hint: z14.string().optional()
|
|
12819
12947
|
},
|
|
12820
12948
|
// ── Phase 2 memory tools (Plan 02-04) ───────────────────────────────────
|
|
12821
12949
|
record_observation: {
|
|
12822
|
-
vault:
|
|
12823
|
-
claim:
|
|
12824
|
-
evidence:
|
|
12825
|
-
confidence:
|
|
12826
|
-
type:
|
|
12950
|
+
vault: z14.string().min(1).describe("Vault name (registered in [vaults] config block)"),
|
|
12951
|
+
claim: z14.string().min(1).describe("Short natural-language statement of the observation (becomes title + body)"),
|
|
12952
|
+
evidence: z14.array(z14.string()).describe("DocIds or quoted source spans supporting the claim; empty array allowed"),
|
|
12953
|
+
confidence: z14.enum(["direct", "inferred", "uncertain"]).describe("How the agent arrived at this claim"),
|
|
12954
|
+
type: z14.string().min(1).describe(
|
|
12827
12955
|
"Observation type per the sink contract (e.g. 'observation', 'hypothesis', 'decision')"
|
|
12828
12956
|
),
|
|
12829
|
-
sink:
|
|
12957
|
+
sink: z14.string().min(1).optional().describe(
|
|
12830
12958
|
"Memory sink name OR full obsidian-fs://\u2026 handle. Defaults to the vault's default sink."
|
|
12831
12959
|
),
|
|
12832
|
-
properties:
|
|
12960
|
+
properties: z14.record(z14.string(), z14.unknown()).optional().describe(
|
|
12833
12961
|
"Escape-hatch: contract-allowed extra properties; merged AFTER sugar args (caller wins)"
|
|
12834
12962
|
)
|
|
12835
12963
|
},
|
|
12836
12964
|
supersede: {
|
|
12837
|
-
doc_id:
|
|
12838
|
-
replacement_doc_id:
|
|
12839
|
-
reason:
|
|
12965
|
+
doc_id: z14.string().regex(DOC_ID_PATTERN2).describe("DocId of the document being superseded"),
|
|
12966
|
+
replacement_doc_id: z14.string().regex(DOC_ID_PATTERN2).describe("DocId of the replacement document"),
|
|
12967
|
+
reason: z14.string().min(1).describe("Why the old document is being retired; written to superseded_reason")
|
|
12840
12968
|
},
|
|
12841
12969
|
// ── Phase 5 brief tools (Plan 05-02 / BRF-03, BRF-04) ───────────────────
|
|
12842
12970
|
compile_brief: {
|
|
12843
|
-
vault:
|
|
12844
|
-
target:
|
|
12845
|
-
source_doc_ids:
|
|
12846
|
-
purpose:
|
|
12847
|
-
max_tokens:
|
|
12848
|
-
prepared_text:
|
|
12849
|
-
sink:
|
|
12971
|
+
vault: z14.string().min(1).describe("Vault name (registered in [vaults] config block)"),
|
|
12972
|
+
target: z14.string().min(1).describe("Stable cross-version handle for the brief (e.g. 'atlas-q3')"),
|
|
12973
|
+
source_doc_ids: z14.array(z14.string().regex(DOC_ID_PATTERN2)).min(1).max(50).describe("DocIds the brief is compiled from; deduped, capped at 50 (D-03)"),
|
|
12974
|
+
purpose: z14.string().min(1).max(500).describe("Free-form purpose; bounded so list_briefs stays scannable"),
|
|
12975
|
+
max_tokens: z14.number().int().positive().optional().default(2e3).describe("Hint for the LLM ladder; default 2000"),
|
|
12976
|
+
prepared_text: z14.string().min(1).optional().describe("D-10 tier 3 fallback when no LLM is reachable \u2014 verbatim body to stitch in"),
|
|
12977
|
+
sink: z14.string().min(1).optional().describe("Override the default `_memory/_briefs` sink")
|
|
12850
12978
|
},
|
|
12851
12979
|
get_brief: {
|
|
12852
|
-
vault:
|
|
12853
|
-
target:
|
|
12854
|
-
max_age_days:
|
|
12855
|
-
allow_stale:
|
|
12980
|
+
vault: z14.string().min(1).describe("Vault name (registered in [vaults] config block)"),
|
|
12981
|
+
target: z14.string().min(1).describe("Stable cross-version handle for the brief"),
|
|
12982
|
+
max_age_days: z14.number().int().nonnegative().optional().describe("Reject briefs older than this many days unless allow_stale=true"),
|
|
12983
|
+
allow_stale: z14.boolean().optional().default(false).describe(
|
|
12856
12984
|
"When true, return briefs flagged stale or too_old with annotation rather than null"
|
|
12857
12985
|
)
|
|
12858
12986
|
},
|
|
12859
12987
|
// ── Phase 3 assembly tools (Plan 03-02 / ASM-02) ────────────────────────
|
|
12860
12988
|
get_outline: {
|
|
12861
|
-
doc_id:
|
|
12862
|
-
vaults:
|
|
12989
|
+
doc_id: z14.string().regex(DOC_ID_PATTERN2).describe("Opaque DocId (obsidian-fs://<vault>/<path>) of the document"),
|
|
12990
|
+
vaults: z14.array(z14.string().min(1)).optional().describe("Optional vault filter; usually omitted (the DocId names a vault)")
|
|
12863
12991
|
},
|
|
12864
12992
|
// ── Phase 3 assembly tools (Plan 03-03) ─────────────────────────────────
|
|
12865
12993
|
search_sections: {
|
|
12866
|
-
query:
|
|
12867
|
-
limit:
|
|
12868
|
-
vaults:
|
|
12994
|
+
query: z14.string().min(1),
|
|
12995
|
+
limit: z14.number().int().positive().max(50).optional().default(10),
|
|
12996
|
+
vaults: z14.array(z14.string().min(1)).optional(),
|
|
12869
12997
|
// Forward-compat with slice 03-05's authority/staleness rescore.
|
|
12870
12998
|
// Accepted today; ignored by the controller until 03-05 wires the
|
|
12871
12999
|
// forwarding inside hybridSearch. See 03-03-DEVIATIONS.md.
|
|
12872
|
-
recency_weight:
|
|
12873
|
-
authority_weight:
|
|
12874
|
-
include_superseded:
|
|
13000
|
+
recency_weight: z14.number().min(0).optional().default(0),
|
|
13001
|
+
authority_weight: z14.number().min(0).optional().default(0),
|
|
13002
|
+
include_superseded: z14.boolean().optional().default(false)
|
|
12875
13003
|
},
|
|
12876
13004
|
// ── Phase 2 memory tools (Plan 02-05) ───────────────────────────────────
|
|
12877
13005
|
recall: {
|
|
12878
|
-
query:
|
|
12879
|
-
min_confidence:
|
|
13006
|
+
query: z14.string().min(1).describe("Natural-language query; routes through hybrid (semantic + BM25) search"),
|
|
13007
|
+
min_confidence: z14.enum(["direct", "inferred", "uncertain"]).optional().describe(
|
|
12880
13008
|
"Exclude docs whose confidence ordinal is lower than this (direct=3, inferred=2, uncertain=1)"
|
|
12881
13009
|
),
|
|
12882
|
-
types:
|
|
12883
|
-
max_age_days:
|
|
12884
|
-
sink:
|
|
13010
|
+
types: z14.array(z14.string().min(1)).optional().describe("Restrict to docs whose `type` property is in this set"),
|
|
13011
|
+
max_age_days: z14.number().int().positive().optional().describe("Exclude docs whose `observed_at` is older than this many days"),
|
|
13012
|
+
sink: z14.string().min(1).optional().describe(
|
|
12885
13013
|
"Memory sink name OR full obsidian-fs://\u2026 handle. Defaults to all configured sinks."
|
|
12886
13014
|
),
|
|
12887
|
-
limit:
|
|
12888
|
-
vaults:
|
|
13015
|
+
limit: z14.number().int().positive().max(200).optional().describe("Maximum results AFTER filter+sort; default 20"),
|
|
13016
|
+
vaults: z14.array(z14.string().min(1)).optional().describe("Restrict to these vault names; defaults to all configured")
|
|
12889
13017
|
},
|
|
12890
13018
|
// ── Phase 3 assembly tools (Plan 03-04 / ASM-01) ────────────────────────
|
|
12891
13019
|
get_document_bundle: {
|
|
12892
|
-
doc_id:
|
|
13020
|
+
doc_id: z14.string().regex(DOC_ID_PATTERN2).describe("Opaque DocId (obsidian-fs://<vault>/<path>) of the anchor document"),
|
|
12893
13021
|
// v2.0.0 accepts only depth:1. The literal pin guarantees Zod
|
|
12894
13022
|
// rejects any other value at the boundary so the controller does
|
|
12895
13023
|
// not need to clamp. Phase 4 may widen additively (z.union of
|
|
12896
13024
|
// literals, or `z.number().int().min(1).max(2)`).
|
|
12897
|
-
depth:
|
|
12898
|
-
vaults:
|
|
13025
|
+
depth: z14.literal(1).optional().default(1).describe("Link-walk depth. v2.0.0: only 1 (one-hop). Phase 4 may widen."),
|
|
13026
|
+
vaults: z14.array(z14.string().min(1)).optional().describe("Optional vault filter; usually omitted (the DocId names a vault)")
|
|
12899
13027
|
},
|
|
12900
13028
|
// ── Phase 4 graph tools (Plan 04-03 / GRA-01) ───────────────────────────
|
|
12901
13029
|
expand: {
|
|
12902
|
-
seed_doc_ids:
|
|
13030
|
+
seed_doc_ids: z14.array(z14.string().regex(DOC_ID_PATTERN2)).min(1).describe(
|
|
12903
13031
|
"1+ opaque DocIds (e.g. obsidian-fs://<vault>/<path>) \u2014 seeds of the BFS."
|
|
12904
13032
|
),
|
|
12905
13033
|
// Hops hard-capped at 2 (D-05) via Zod literal union — `hops: 3`
|
|
12906
13034
|
// is rejected at the boundary; the controller does not clamp.
|
|
12907
|
-
hops:
|
|
12908
|
-
direction:
|
|
12909
|
-
edge_types:
|
|
12910
|
-
filter_properties:
|
|
13035
|
+
hops: z14.union([z14.literal(1), z14.literal(2)]).describe("Hop cap (1 or 2). v2.0.0 hard-caps at 2."),
|
|
13036
|
+
direction: z14.enum(["forward", "backward", "both"]).optional().default("both").describe("Edge traversal direction; default 'both'."),
|
|
13037
|
+
edge_types: z14.array(z14.enum(["wikilink", "mention", "frontmatter-ref", "hyperlink"])).optional().describe("Optional filter on edge types; default = all four types."),
|
|
13038
|
+
filter_properties: z14.record(z14.string(), z14.unknown()).optional().describe(
|
|
12911
13039
|
"Strict-equality predicate on document properties (e.g. {type: 'Project'})."
|
|
12912
13040
|
),
|
|
12913
|
-
include_superseded:
|
|
13041
|
+
include_superseded: z14.boolean().optional().default(false).describe(
|
|
12914
13042
|
"When false (default), docs whose properties.status === 'superseded' are dropped."
|
|
12915
13043
|
)
|
|
12916
13044
|
},
|
|
@@ -12924,50 +13052,50 @@ var init_tool_registry = __esm({
|
|
|
12924
13052
|
// works. The runtime path goes through `buildToolSchema("cluster")`
|
|
12925
13053
|
// which calls the SCHEMA_BUILDERS entry.
|
|
12926
13054
|
cluster: {
|
|
12927
|
-
query:
|
|
12928
|
-
seed_doc_ids:
|
|
13055
|
+
query: z14.string().min(1).optional(),
|
|
13056
|
+
seed_doc_ids: z14.array(z14.string().regex(DOC_ID_PATTERN2)).min(1).optional(),
|
|
12929
13057
|
// CR-02: `vault` scopes the `query` path on multi-vault setups so
|
|
12930
13058
|
// search_hybrid is not silently restricted to whichever vault
|
|
12931
13059
|
// sorts first in VaultManager insertion order. Optional at the
|
|
12932
13060
|
// schema layer; the runtime cluster() entry enforces the
|
|
12933
13061
|
// multi-vault-without-vault error.
|
|
12934
|
-
vault:
|
|
12935
|
-
method:
|
|
12936
|
-
query_top_k:
|
|
12937
|
-
force:
|
|
13062
|
+
vault: z14.string().min(1).optional(),
|
|
13063
|
+
method: z14.literal("edge-community"),
|
|
13064
|
+
query_top_k: z14.number().int().positive().max(200).optional().default(50),
|
|
13065
|
+
force: z14.boolean().optional().default(false)
|
|
12938
13066
|
},
|
|
12939
13067
|
// ── Phase 3 assembly tools (Plan 03-06) ─────────────────────────────────
|
|
12940
13068
|
assemble_dossier: {
|
|
12941
|
-
type:
|
|
13069
|
+
type: z14.string().min(1).describe(
|
|
12942
13070
|
"Exact-match value for properties.type on the anchor document (D-03 \u2014 no fuzzy match)"
|
|
12943
13071
|
),
|
|
12944
|
-
key:
|
|
13072
|
+
key: z14.string().min(1).describe(
|
|
12945
13073
|
"Candidate key \u2014 matches the document's title OR any entry in properties.aliases (D-04)"
|
|
12946
13074
|
),
|
|
12947
|
-
vaults:
|
|
13075
|
+
vaults: z14.array(z14.string().min(1)).optional().describe("Restrict to these vault names; defaults to all configured")
|
|
12948
13076
|
},
|
|
12949
13077
|
// ── Phase 6 task-contract DSL (Plan 06-02 / D-A1 escape valve) ─────────
|
|
12950
13078
|
register_contracts_as_tools: {
|
|
12951
|
-
vault:
|
|
13079
|
+
vault: z14.string().min(1).optional().describe("Vault name; omit to apply to all vaults")
|
|
12952
13080
|
},
|
|
12953
13081
|
// ── Phase 6 task-contract DSL (Plan 06-03 / CON-05, Q-DESCRIBE) ────────
|
|
12954
13082
|
describe_contract: {
|
|
12955
|
-
name:
|
|
12956
|
-
vault:
|
|
13083
|
+
name: z14.string().min(1).describe("Registered contract name (see register_contracts_as_tools)"),
|
|
13084
|
+
vault: z14.string().min(1).optional().describe("Vault name; omit on single-vault setups")
|
|
12957
13085
|
},
|
|
12958
13086
|
// ── Phase 6 task-contract DSL (Plan 06-03 / CON-06) ────────────────────
|
|
12959
13087
|
instantiate_contract: {
|
|
12960
|
-
name:
|
|
12961
|
-
inputs:
|
|
12962
|
-
source_overrides:
|
|
12963
|
-
sink_overrides:
|
|
13088
|
+
name: z14.string().min(1).describe("Registered contract name"),
|
|
13089
|
+
inputs: z14.record(z14.string(), z14.unknown()).optional().default({}).describe("Contract inputs; validated against the contract's inputZodSchema"),
|
|
13090
|
+
source_overrides: z14.record(z14.string(), z14.string()).optional().describe("Override declared source handles by handle name"),
|
|
13091
|
+
sink_overrides: z14.record(z14.string(), z14.string()).optional().describe(
|
|
12964
13092
|
"Override declared sink handles by handle name. Targets MUST resolve through MemorySinkRegistry (D-A4c)."
|
|
12965
13093
|
),
|
|
12966
|
-
vault:
|
|
13094
|
+
vault: z14.string().min(1).optional().describe("Vault name; omit on single-vault setups")
|
|
12967
13095
|
}
|
|
12968
13096
|
};
|
|
12969
13097
|
SCHEMA_BUILDERS = {
|
|
12970
|
-
suggest_frontmatter: () =>
|
|
13098
|
+
suggest_frontmatter: () => z14.object(TOOL_SCHEMAS.suggest_frontmatter).refine((v) => v.path !== void 0 || v.content !== void 0, {
|
|
12971
13099
|
message: "suggest_frontmatter requires either `path` or `content`"
|
|
12972
13100
|
}),
|
|
12973
13101
|
// Plan 04-05 / D-15a — EXACTLY ONE of `query` or `seed_doc_ids` must
|
|
@@ -12976,7 +13104,7 @@ var init_tool_registry = __esm({
|
|
|
12976
13104
|
// so this Zod refinement is the early-rejection gate at the MCP
|
|
12977
13105
|
// boundary (cluster's internal validator handles the same case for
|
|
12978
13106
|
// direct callers that bypass Zod).
|
|
12979
|
-
cluster: () =>
|
|
13107
|
+
cluster: () => z14.object(TOOL_SCHEMAS.cluster).refine(
|
|
12980
13108
|
(v) => v.query !== void 0 && v.seed_doc_ids === void 0 || v.query === void 0 && v.seed_doc_ids !== void 0,
|
|
12981
13109
|
{
|
|
12982
13110
|
message: "cluster requires EXACTLY ONE of `query` or `seed_doc_ids` (D-15a mutual exclusion)"
|
|
@@ -13071,7 +13199,7 @@ var init_json_schema_ref = __esm({
|
|
|
13071
13199
|
});
|
|
13072
13200
|
|
|
13073
13201
|
// src/contracts/input-schema.ts
|
|
13074
|
-
import { z as
|
|
13202
|
+
import { z as z15 } from "zod";
|
|
13075
13203
|
function buildInputSchema(yamlInputs, required = []) {
|
|
13076
13204
|
const resolvedProperties = resolveRefs(yamlInputs);
|
|
13077
13205
|
const jsonSchema = {
|
|
@@ -13080,7 +13208,7 @@ function buildInputSchema(yamlInputs, required = []) {
|
|
|
13080
13208
|
required,
|
|
13081
13209
|
additionalProperties: false
|
|
13082
13210
|
};
|
|
13083
|
-
const zodSchema =
|
|
13211
|
+
const zodSchema = z15.fromJSONSchema(
|
|
13084
13212
|
jsonSchema
|
|
13085
13213
|
);
|
|
13086
13214
|
return { zodSchema, jsonSchema };
|
|
@@ -13166,7 +13294,7 @@ var init_audit4 = __esm({
|
|
|
13166
13294
|
});
|
|
13167
13295
|
|
|
13168
13296
|
// src/contracts/schema.ts
|
|
13169
|
-
import { z as
|
|
13297
|
+
import { z as z16 } from "zod";
|
|
13170
13298
|
var BASELINE_VERBS, MCP_VERB_RE, VerbSchema, StepSchema, HandleDeclSchema, WriteBackSchema, ContractFileSchema;
|
|
13171
13299
|
var init_schema4 = __esm({
|
|
13172
13300
|
"src/contracts/schema.ts"() {
|
|
@@ -13186,40 +13314,40 @@ var init_schema4 = __esm({
|
|
|
13186
13314
|
"read_note"
|
|
13187
13315
|
];
|
|
13188
13316
|
MCP_VERB_RE = /^mcp:\/\/[a-z][a-z0-9_-]*\/[a-z][a-z0-9_-]*$/;
|
|
13189
|
-
VerbSchema =
|
|
13190
|
-
|
|
13191
|
-
|
|
13317
|
+
VerbSchema = z16.union([
|
|
13318
|
+
z16.enum([...BASELINE_VERBS, "literal"]),
|
|
13319
|
+
z16.string().regex(MCP_VERB_RE)
|
|
13192
13320
|
]);
|
|
13193
|
-
StepSchema =
|
|
13194
|
-
as:
|
|
13321
|
+
StepSchema = z16.object({
|
|
13322
|
+
as: z16.string().min(1).regex(/^[a-z_][a-z0-9_]*$/, "alias must be snake_case").describe("D-A2c \u2014 unique snake_case alias for this step's output"),
|
|
13195
13323
|
verb: VerbSchema.describe(
|
|
13196
13324
|
"Closed enum + literal + mcp:// extension (D-A2a / C-1)"
|
|
13197
13325
|
),
|
|
13198
|
-
args:
|
|
13199
|
-
value:
|
|
13326
|
+
args: z16.record(z16.string(), z16.unknown()).optional(),
|
|
13327
|
+
value: z16.unknown().optional()
|
|
13200
13328
|
}).describe("One step in an assembly: array");
|
|
13201
|
-
HandleDeclSchema =
|
|
13202
|
-
handle:
|
|
13203
|
-
required:
|
|
13329
|
+
HandleDeclSchema = z16.object({
|
|
13330
|
+
handle: z16.string().min(1),
|
|
13331
|
+
required: z16.boolean().default(true)
|
|
13204
13332
|
}).describe("Source or sink handle declaration (D-A4a)");
|
|
13205
|
-
WriteBackSchema =
|
|
13206
|
-
sink:
|
|
13207
|
-
document_kind:
|
|
13208
|
-
properties:
|
|
13209
|
-
body_from:
|
|
13333
|
+
WriteBackSchema = z16.object({
|
|
13334
|
+
sink: z16.string().min(1).describe("Template expression OR literal sink handle"),
|
|
13335
|
+
document_kind: z16.enum(["brief", "observation", "custom"]),
|
|
13336
|
+
properties: z16.record(z16.string(), z16.unknown()).default({}),
|
|
13337
|
+
body_from: z16.string().min(1).describe("Template expression that resolves to the body string")
|
|
13210
13338
|
}).describe(
|
|
13211
13339
|
"DeliveryAdapter.write chokepoint \u2014 only ground-truth DocId source (C-3)"
|
|
13212
13340
|
);
|
|
13213
|
-
ContractFileSchema =
|
|
13214
|
-
version:
|
|
13215
|
-
name:
|
|
13216
|
-
description:
|
|
13217
|
-
inputs:
|
|
13218
|
-
required:
|
|
13219
|
-
sources:
|
|
13220
|
-
sinks:
|
|
13221
|
-
assembly:
|
|
13222
|
-
output_shape:
|
|
13341
|
+
ContractFileSchema = z16.object({
|
|
13342
|
+
version: z16.literal(1).describe("v2.0.0 supports version 1 only; v2.x may extend additively"),
|
|
13343
|
+
name: z16.string().min(1).regex(/^[a-z][a-z0-9-]*$/, "name must be kebab-case").describe("Contract name \u2014 used by instantiate_contract and slugify"),
|
|
13344
|
+
description: z16.string().default(""),
|
|
13345
|
+
inputs: z16.record(z16.string(), z16.unknown()).default({}),
|
|
13346
|
+
required: z16.array(z16.string()).default([]),
|
|
13347
|
+
sources: z16.record(z16.string(), HandleDeclSchema).default({}),
|
|
13348
|
+
sinks: z16.record(z16.string(), HandleDeclSchema).default({}),
|
|
13349
|
+
assembly: z16.array(StepSchema).min(1, "assembly must contain at least one step"),
|
|
13350
|
+
output_shape: z16.unknown().optional(),
|
|
13223
13351
|
write_back: WriteBackSchema.optional()
|
|
13224
13352
|
}).superRefine((data, ctx) => {
|
|
13225
13353
|
const aliases = /* @__PURE__ */ new Set();
|
|
@@ -13571,6 +13699,9 @@ var init_templates = __esm({
|
|
|
13571
13699
|
// src/contracts/mcp-clients.ts
|
|
13572
13700
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
13573
13701
|
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
13702
|
+
function nowSeconds() {
|
|
13703
|
+
return Math.floor(Date.now() / 1e3);
|
|
13704
|
+
}
|
|
13574
13705
|
function wrapAvailable(client, transport) {
|
|
13575
13706
|
return {
|
|
13576
13707
|
available: true,
|
|
@@ -13592,6 +13723,27 @@ function wrapAvailable(client, transport) {
|
|
|
13592
13723
|
}
|
|
13593
13724
|
return res;
|
|
13594
13725
|
},
|
|
13726
|
+
async listTools() {
|
|
13727
|
+
if (typeof client.listTools !== "function") return [];
|
|
13728
|
+
const res = await client.listTools();
|
|
13729
|
+
const tools = res.tools;
|
|
13730
|
+
if (!Array.isArray(tools)) return [];
|
|
13731
|
+
const out = [];
|
|
13732
|
+
for (const t of tools) {
|
|
13733
|
+
if (!t || typeof t !== "object") continue;
|
|
13734
|
+
const name = t.name;
|
|
13735
|
+
if (typeof name !== "string") continue;
|
|
13736
|
+
const tool = { name };
|
|
13737
|
+
const description = t.description;
|
|
13738
|
+
if (typeof description === "string") tool.description = description;
|
|
13739
|
+
const inputSchema = t.inputSchema;
|
|
13740
|
+
if (inputSchema && typeof inputSchema === "object") {
|
|
13741
|
+
tool.inputSchema = inputSchema;
|
|
13742
|
+
}
|
|
13743
|
+
out.push(tool);
|
|
13744
|
+
}
|
|
13745
|
+
return out;
|
|
13746
|
+
},
|
|
13595
13747
|
[Symbol.dispose]() {
|
|
13596
13748
|
transport.close();
|
|
13597
13749
|
}
|
|
@@ -13603,6 +13755,9 @@ function wrapUnavailable() {
|
|
|
13603
13755
|
async callTool() {
|
|
13604
13756
|
throw new Error("peer-MCP client unavailable");
|
|
13605
13757
|
},
|
|
13758
|
+
async listTools() {
|
|
13759
|
+
throw new Error("peer-MCP client unavailable");
|
|
13760
|
+
},
|
|
13606
13761
|
[Symbol.dispose]() {
|
|
13607
13762
|
}
|
|
13608
13763
|
};
|
|
@@ -13613,49 +13768,155 @@ var init_mcp_clients = __esm({
|
|
|
13613
13768
|
"use strict";
|
|
13614
13769
|
init_esm_shims();
|
|
13615
13770
|
PeerMcpRegistry = class {
|
|
13616
|
-
|
|
13771
|
+
entries = /* @__PURE__ */ new Map();
|
|
13617
13772
|
clientFactory;
|
|
13618
13773
|
constructor(clientFactory) {
|
|
13619
13774
|
this.clientFactory = clientFactory;
|
|
13620
13775
|
}
|
|
13621
13776
|
get size() {
|
|
13622
|
-
return this.
|
|
13777
|
+
return this.entries.size;
|
|
13623
13778
|
}
|
|
13624
13779
|
/**
|
|
13625
13780
|
* Boot every `[contracts.mcp_clients.<name>]` entry. Failures are
|
|
13626
13781
|
* non-fatal: the name is recorded as unavailable and a WARN line is
|
|
13627
13782
|
* written to stderr. Returns when all attempts have settled.
|
|
13783
|
+
*
|
|
13784
|
+
* On a successful connect we prime the tools cache via tools/list. A
|
|
13785
|
+
* tools/list failure does NOT mark the source unavailable — the
|
|
13786
|
+
* connection is live and callTool may still work — but the status
|
|
13787
|
+
* becomes "unreachable" so the UI can prompt a retry.
|
|
13628
13788
|
*/
|
|
13629
13789
|
async start(configs) {
|
|
13630
13790
|
for (const [name, cfg] of Object.entries(configs)) {
|
|
13791
|
+
await this.connectAndStore(name, cfg);
|
|
13792
|
+
}
|
|
13793
|
+
}
|
|
13794
|
+
get(name) {
|
|
13795
|
+
return this.entries.get(name)?.client;
|
|
13796
|
+
}
|
|
13797
|
+
/** All registered source names, in insertion order. */
|
|
13798
|
+
names() {
|
|
13799
|
+
return Array.from(this.entries.keys());
|
|
13800
|
+
}
|
|
13801
|
+
/** Cached metadata projection for one source; undefined if unknown. */
|
|
13802
|
+
getInfo(name) {
|
|
13803
|
+
const e = this.entries.get(name);
|
|
13804
|
+
if (e === void 0) return void 0;
|
|
13805
|
+
return {
|
|
13806
|
+
status: e.status,
|
|
13807
|
+
tools: e.tools,
|
|
13808
|
+
lastRefreshed: e.lastRefreshed,
|
|
13809
|
+
...e.error !== void 0 ? { error: e.error } : {}
|
|
13810
|
+
};
|
|
13811
|
+
}
|
|
13812
|
+
/**
|
|
13813
|
+
* Register a new source at runtime: spawn + connect, then prime the
|
|
13814
|
+
* tools cache. Replaces any existing entry of the same name (the old
|
|
13815
|
+
* client is disposed first). Returns the resulting info projection.
|
|
13816
|
+
*/
|
|
13817
|
+
async add(name, cfg) {
|
|
13818
|
+
const existing = this.entries.get(name);
|
|
13819
|
+
if (existing !== void 0) {
|
|
13631
13820
|
try {
|
|
13632
|
-
|
|
13633
|
-
|
|
13634
|
-
} catch (err) {
|
|
13635
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
13636
|
-
process.stderr.write(
|
|
13637
|
-
`[contracts] peer-MCP client '${name}' failed to start: ${msg}
|
|
13638
|
-
`
|
|
13639
|
-
);
|
|
13640
|
-
this.clients.set(name, wrapUnavailable());
|
|
13821
|
+
existing.client[Symbol.dispose]();
|
|
13822
|
+
} catch {
|
|
13641
13823
|
}
|
|
13642
13824
|
}
|
|
13825
|
+
await this.connectAndStore(name, cfg);
|
|
13826
|
+
return this.getInfo(name);
|
|
13643
13827
|
}
|
|
13644
|
-
|
|
13645
|
-
|
|
13828
|
+
/**
|
|
13829
|
+
* Dispose a source and drop it from the registry. Idempotent —
|
|
13830
|
+
* removing an unknown name is a no-op that returns false.
|
|
13831
|
+
*/
|
|
13832
|
+
remove(name) {
|
|
13833
|
+
const e = this.entries.get(name);
|
|
13834
|
+
if (e === void 0) return false;
|
|
13835
|
+
try {
|
|
13836
|
+
e.client[Symbol.dispose]();
|
|
13837
|
+
} catch (err) {
|
|
13838
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
13839
|
+
process.stderr.write(`[contracts] peer-MCP dispose error: ${msg}
|
|
13840
|
+
`);
|
|
13841
|
+
}
|
|
13842
|
+
this.entries.delete(name);
|
|
13843
|
+
return true;
|
|
13844
|
+
}
|
|
13845
|
+
/**
|
|
13846
|
+
* Re-issue tools/list against the live client and refresh the cache.
|
|
13847
|
+
* Returns the updated info, or undefined if the name is unknown.
|
|
13848
|
+
*
|
|
13849
|
+
* If the client is currently unavailable this only updates the error;
|
|
13850
|
+
* re-spawning a failed source requires `add(name, cfg)` with the
|
|
13851
|
+
* config (the registry does not retain configs).
|
|
13852
|
+
*/
|
|
13853
|
+
async refresh(name) {
|
|
13854
|
+
const e = this.entries.get(name);
|
|
13855
|
+
if (e === void 0) return void 0;
|
|
13856
|
+
if (!e.client.available) {
|
|
13857
|
+
e.status = "unavailable";
|
|
13858
|
+
return this.getInfo(name);
|
|
13859
|
+
}
|
|
13860
|
+
await this.primeTools(e);
|
|
13861
|
+
return this.getInfo(name);
|
|
13646
13862
|
}
|
|
13647
13863
|
/** Dispose every client and clear the internal map. Idempotent. */
|
|
13648
13864
|
async shutdown() {
|
|
13649
|
-
for (const
|
|
13865
|
+
for (const e of this.entries.values()) {
|
|
13650
13866
|
try {
|
|
13651
|
-
|
|
13867
|
+
e.client[Symbol.dispose]();
|
|
13652
13868
|
} catch (err) {
|
|
13653
13869
|
const msg = err instanceof Error ? err.message : String(err);
|
|
13654
13870
|
process.stderr.write(`[contracts] peer-MCP dispose error: ${msg}
|
|
13655
13871
|
`);
|
|
13656
13872
|
}
|
|
13657
13873
|
}
|
|
13658
|
-
this.
|
|
13874
|
+
this.entries.clear();
|
|
13875
|
+
}
|
|
13876
|
+
// ─── internals ─────────────────────────────────────────────────────────
|
|
13877
|
+
/** Connect (factory or default), store the entry, prime tools cache. */
|
|
13878
|
+
async connectAndStore(name, cfg) {
|
|
13879
|
+
try {
|
|
13880
|
+
const { client, transport } = this.clientFactory ? await this.clientFactory(cfg) : await this.defaultConnect(cfg);
|
|
13881
|
+
const entry = {
|
|
13882
|
+
client: wrapAvailable(client, transport),
|
|
13883
|
+
status: "connected",
|
|
13884
|
+
tools: [],
|
|
13885
|
+
lastRefreshed: null
|
|
13886
|
+
};
|
|
13887
|
+
this.entries.set(name, entry);
|
|
13888
|
+
await this.primeTools(entry);
|
|
13889
|
+
} catch (err) {
|
|
13890
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
13891
|
+
process.stderr.write(
|
|
13892
|
+
`[contracts] peer-MCP client '${name}' failed to start: ${msg}
|
|
13893
|
+
`
|
|
13894
|
+
);
|
|
13895
|
+
this.entries.set(name, {
|
|
13896
|
+
client: wrapUnavailable(),
|
|
13897
|
+
status: "unavailable",
|
|
13898
|
+
tools: [],
|
|
13899
|
+
lastRefreshed: null,
|
|
13900
|
+
error: msg
|
|
13901
|
+
});
|
|
13902
|
+
}
|
|
13903
|
+
}
|
|
13904
|
+
/**
|
|
13905
|
+
* Call tools/list and update the entry's cache + status. A failure
|
|
13906
|
+
* keeps the connection (status → "unreachable") rather than tearing it
|
|
13907
|
+
* down — the source is reachable for callTool even if discovery failed.
|
|
13908
|
+
*/
|
|
13909
|
+
async primeTools(entry) {
|
|
13910
|
+
try {
|
|
13911
|
+
const tools = await entry.client.listTools();
|
|
13912
|
+
entry.tools = tools;
|
|
13913
|
+
entry.lastRefreshed = nowSeconds();
|
|
13914
|
+
entry.status = "connected";
|
|
13915
|
+
delete entry.error;
|
|
13916
|
+
} catch (err) {
|
|
13917
|
+
entry.status = "unreachable";
|
|
13918
|
+
entry.error = err instanceof Error ? err.message : String(err);
|
|
13919
|
+
}
|
|
13659
13920
|
}
|
|
13660
13921
|
async defaultConnect(cfg) {
|
|
13661
13922
|
const transport = new StdioClientTransport({
|
|
@@ -13760,7 +14021,7 @@ var init_verbs = __esm({
|
|
|
13760
14021
|
});
|
|
13761
14022
|
|
|
13762
14023
|
// src/contracts/instantiate.ts
|
|
13763
|
-
import { z as
|
|
14024
|
+
import { z as z17 } from "zod";
|
|
13764
14025
|
async function instantiateContract(deps, args2) {
|
|
13765
14026
|
const parsed = deps.registry.get(args2.name);
|
|
13766
14027
|
if (!parsed) return { ok: false, reason: "unknown_contract", name: args2.name };
|
|
@@ -13908,7 +14169,7 @@ async function instantiateContract(deps, args2) {
|
|
|
13908
14169
|
};
|
|
13909
14170
|
if (parsed.output_shape) {
|
|
13910
14171
|
try {
|
|
13911
|
-
const outputSchema =
|
|
14172
|
+
const outputSchema = z17.fromJSONSchema(
|
|
13912
14173
|
parsed.output_shape
|
|
13913
14174
|
);
|
|
13914
14175
|
const check = outputSchema.safeParse(bundle);
|
|
@@ -13996,6 +14257,12 @@ var init_instantiate = __esm({
|
|
|
13996
14257
|
});
|
|
13997
14258
|
|
|
13998
14259
|
// src/contracts/describe.ts
|
|
14260
|
+
function glossFor(verb) {
|
|
14261
|
+
if (VERB_GLOSS[verb]) return VERB_GLOSS[verb];
|
|
14262
|
+
if (verb === "literal") return "Use a fixed inline value";
|
|
14263
|
+
if (verb.startsWith("mcp://")) return `Call an external tool (${verb})`;
|
|
14264
|
+
return verb;
|
|
14265
|
+
}
|
|
13999
14266
|
function describeContract(deps, args2) {
|
|
14000
14267
|
const parsed = deps.registry.get(args2.name);
|
|
14001
14268
|
if (!parsed) return { ok: false, reason: "unknown_contract", name: args2.name };
|
|
@@ -14045,7 +14312,9 @@ function renderSummary(parsed) {
|
|
|
14045
14312
|
lines.push("## Assembly");
|
|
14046
14313
|
parsed.assembly.forEach((step, i) => {
|
|
14047
14314
|
const argsRender = step.args ? `(${Object.keys(step.args).join(", ")})` : "()";
|
|
14048
|
-
lines.push(
|
|
14315
|
+
lines.push(
|
|
14316
|
+
`${i + 1}. **${step.as}** \u2014 ${glossFor(step.verb)} _(\`${step.verb}${argsRender}\`)_`
|
|
14317
|
+
);
|
|
14049
14318
|
});
|
|
14050
14319
|
lines.push("");
|
|
14051
14320
|
}
|
|
@@ -14069,10 +14338,24 @@ function renderSummary(parsed) {
|
|
|
14069
14338
|
}
|
|
14070
14339
|
return lines.join("\n").trim() + "\n";
|
|
14071
14340
|
}
|
|
14341
|
+
var VERB_GLOSS;
|
|
14072
14342
|
var init_describe = __esm({
|
|
14073
14343
|
"src/contracts/describe.ts"() {
|
|
14074
14344
|
"use strict";
|
|
14075
14345
|
init_esm_shims();
|
|
14346
|
+
VERB_GLOSS = {
|
|
14347
|
+
read_note: "Read a note's content",
|
|
14348
|
+
search_hybrid: "Search the vault (semantic + keyword)",
|
|
14349
|
+
search_sections: "Search for matching sections within notes",
|
|
14350
|
+
query_frontmatter: "Find notes by their properties (frontmatter)",
|
|
14351
|
+
expand: "Gather notes linked to the starting note (follow the graph)",
|
|
14352
|
+
cluster: "Group the gathered notes into related communities",
|
|
14353
|
+
recall: "Recall earlier agent observations from memory",
|
|
14354
|
+
compile_brief: "Compile the gathered notes into a brief",
|
|
14355
|
+
get_brief: "Fetch an already-compiled brief",
|
|
14356
|
+
list_backlinks: "List notes that link back to this one",
|
|
14357
|
+
get_outline: "Read a note's heading outline"
|
|
14358
|
+
};
|
|
14076
14359
|
}
|
|
14077
14360
|
});
|
|
14078
14361
|
|
|
@@ -14143,6 +14426,59 @@ var init_resources3 = __esm({
|
|
|
14143
14426
|
}
|
|
14144
14427
|
});
|
|
14145
14428
|
|
|
14429
|
+
// src/contracts/sources-resources.ts
|
|
14430
|
+
function readListSources(reg, configMeta) {
|
|
14431
|
+
const sources = [];
|
|
14432
|
+
for (const name of reg.names()) {
|
|
14433
|
+
const info = reg.getInfo(name);
|
|
14434
|
+
if (info === void 0) continue;
|
|
14435
|
+
const meta = configMeta[name];
|
|
14436
|
+
const entry = {
|
|
14437
|
+
name,
|
|
14438
|
+
transport: "stdio",
|
|
14439
|
+
command: meta?.command ?? "",
|
|
14440
|
+
args: meta?.args ?? [],
|
|
14441
|
+
status: info.status,
|
|
14442
|
+
tool_count: info.tools.length,
|
|
14443
|
+
last_refreshed: info.lastRefreshed
|
|
14444
|
+
};
|
|
14445
|
+
if (info.error !== void 0) entry.error = info.error;
|
|
14446
|
+
sources.push(entry);
|
|
14447
|
+
}
|
|
14448
|
+
return { sources };
|
|
14449
|
+
}
|
|
14450
|
+
function readSourceTools(reg, name) {
|
|
14451
|
+
const info = reg.getInfo(name);
|
|
14452
|
+
if (info === void 0) {
|
|
14453
|
+
return { error: `unknown source: ${name}` };
|
|
14454
|
+
}
|
|
14455
|
+
const out = {
|
|
14456
|
+
name,
|
|
14457
|
+
status: info.status,
|
|
14458
|
+
last_refreshed: info.lastRefreshed,
|
|
14459
|
+
tools: info.tools
|
|
14460
|
+
};
|
|
14461
|
+
if (info.error !== void 0) out.error = info.error;
|
|
14462
|
+
return out;
|
|
14463
|
+
}
|
|
14464
|
+
function readSourceTool(reg, name, toolName) {
|
|
14465
|
+
const info = reg.getInfo(name);
|
|
14466
|
+
if (info === void 0) {
|
|
14467
|
+
return { found: false, error: `unknown source: ${name}` };
|
|
14468
|
+
}
|
|
14469
|
+
const tool = info.tools.find((t) => t.name === toolName);
|
|
14470
|
+
if (tool === void 0) {
|
|
14471
|
+
return { found: false, error: `unknown tool: ${name}/${toolName}` };
|
|
14472
|
+
}
|
|
14473
|
+
return { found: true, name, tool };
|
|
14474
|
+
}
|
|
14475
|
+
var init_sources_resources = __esm({
|
|
14476
|
+
"src/contracts/sources-resources.ts"() {
|
|
14477
|
+
"use strict";
|
|
14478
|
+
init_esm_shims();
|
|
14479
|
+
}
|
|
14480
|
+
});
|
|
14481
|
+
|
|
14146
14482
|
// src/contracts/index.ts
|
|
14147
14483
|
var init_contracts = __esm({
|
|
14148
14484
|
"src/contracts/index.ts"() {
|
|
@@ -14165,6 +14501,7 @@ var init_contracts = __esm({
|
|
|
14165
14501
|
init_instantiate();
|
|
14166
14502
|
init_describe();
|
|
14167
14503
|
init_resources3();
|
|
14504
|
+
init_sources_resources();
|
|
14168
14505
|
}
|
|
14169
14506
|
});
|
|
14170
14507
|
|
|
@@ -14359,6 +14696,20 @@ async function serve(options = {}) {
|
|
|
14359
14696
|
process.on("SIGTERM", () => {
|
|
14360
14697
|
void shutdown().finally(() => process.exit(0));
|
|
14361
14698
|
});
|
|
14699
|
+
let stdinClosing = false;
|
|
14700
|
+
const onStdinClose = (reason) => {
|
|
14701
|
+
if (stdinClosing) return;
|
|
14702
|
+
stdinClosing = true;
|
|
14703
|
+
process.stderr.write(
|
|
14704
|
+
`[vault-memory] stdin ${reason} \u2014 parent process gone; shutting down.
|
|
14705
|
+
`
|
|
14706
|
+
);
|
|
14707
|
+
setTimeout(() => {
|
|
14708
|
+
void shutdown().finally(() => process.exit(0));
|
|
14709
|
+
}, 500);
|
|
14710
|
+
};
|
|
14711
|
+
process.stdin.on("end", () => onStdinClose("end"));
|
|
14712
|
+
process.stdin.on("close", () => onStdinClose("close"));
|
|
14362
14713
|
const server = new McpServer(
|
|
14363
14714
|
{ name: "vault-memory", version: VERSION },
|
|
14364
14715
|
// Plan 02-06 (MEM-09): advertise `resources` capability so MCP clients
|
|
@@ -15404,6 +15755,86 @@ async function serve(options = {}) {
|
|
|
15404
15755
|
};
|
|
15405
15756
|
}
|
|
15406
15757
|
);
|
|
15758
|
+
const sourceConfigMeta = () => {
|
|
15759
|
+
const out = {};
|
|
15760
|
+
for (const [name, cfg] of Object.entries(config.contracts.mcp_clients)) {
|
|
15761
|
+
out[name] = { command: cfg.command, args: cfg.args ?? [] };
|
|
15762
|
+
}
|
|
15763
|
+
return out;
|
|
15764
|
+
};
|
|
15765
|
+
server.registerResource(
|
|
15766
|
+
"sources",
|
|
15767
|
+
RESOURCE_URI_SOURCES,
|
|
15768
|
+
{
|
|
15769
|
+
title: "Peer MCP sources",
|
|
15770
|
+
description: "List peer MCP servers vault-memory connects to, with per-source status (connected/unavailable/unreachable), tool_count, and last_refreshed. vault-memory itself is not included. SOURCES-REGISTRY \xA75.1.",
|
|
15771
|
+
mimeType: "application/json"
|
|
15772
|
+
},
|
|
15773
|
+
async (uri) => ({
|
|
15774
|
+
contents: [
|
|
15775
|
+
{
|
|
15776
|
+
uri: uri.href,
|
|
15777
|
+
mimeType: "application/json",
|
|
15778
|
+
text: JSON.stringify(
|
|
15779
|
+
readListSources(peerMcpRegistry, sourceConfigMeta()),
|
|
15780
|
+
null,
|
|
15781
|
+
2
|
|
15782
|
+
)
|
|
15783
|
+
}
|
|
15784
|
+
]
|
|
15785
|
+
})
|
|
15786
|
+
);
|
|
15787
|
+
server.registerResource(
|
|
15788
|
+
"source-tools",
|
|
15789
|
+
new ResourceTemplate(`${RESOURCE_URI_SOURCES}/{name}/tools`, {
|
|
15790
|
+
list: void 0
|
|
15791
|
+
}),
|
|
15792
|
+
{
|
|
15793
|
+
title: "Peer MCP source tools",
|
|
15794
|
+
description: "List the cached tools/list for one peer MCP source. Empty when the source is not connected. SOURCES-REGISTRY \xA75.2.",
|
|
15795
|
+
mimeType: "application/json"
|
|
15796
|
+
},
|
|
15797
|
+
async (uri, variables) => {
|
|
15798
|
+
const name = String(variables.name ?? "");
|
|
15799
|
+
return {
|
|
15800
|
+
contents: [
|
|
15801
|
+
{
|
|
15802
|
+
uri: uri.href,
|
|
15803
|
+
mimeType: "application/json",
|
|
15804
|
+
text: JSON.stringify(readSourceTools(peerMcpRegistry, name), null, 2)
|
|
15805
|
+
}
|
|
15806
|
+
]
|
|
15807
|
+
};
|
|
15808
|
+
}
|
|
15809
|
+
);
|
|
15810
|
+
server.registerResource(
|
|
15811
|
+
"source-tool",
|
|
15812
|
+
new ResourceTemplate(`${RESOURCE_URI_SOURCES}/{name}/tools/{tool}`, {
|
|
15813
|
+
list: void 0
|
|
15814
|
+
}),
|
|
15815
|
+
{
|
|
15816
|
+
title: "Peer MCP source tool",
|
|
15817
|
+
description: "Read a single tool's schema from one peer MCP source, inlined from the cached tools/list (no extra peer call). SOURCES-REGISTRY \xA75.3.",
|
|
15818
|
+
mimeType: "application/json"
|
|
15819
|
+
},
|
|
15820
|
+
async (uri, variables) => {
|
|
15821
|
+
const name = String(variables.name ?? "");
|
|
15822
|
+
const tool = String(variables.tool ?? "");
|
|
15823
|
+
return {
|
|
15824
|
+
contents: [
|
|
15825
|
+
{
|
|
15826
|
+
uri: uri.href,
|
|
15827
|
+
mimeType: "application/json",
|
|
15828
|
+
text: JSON.stringify(
|
|
15829
|
+
readSourceTool(peerMcpRegistry, name, tool),
|
|
15830
|
+
null,
|
|
15831
|
+
2
|
|
15832
|
+
)
|
|
15833
|
+
}
|
|
15834
|
+
]
|
|
15835
|
+
};
|
|
15836
|
+
}
|
|
15837
|
+
);
|
|
15407
15838
|
const rel08Vaults = RESOURCES.find((r) => r.name === "vaults");
|
|
15408
15839
|
const rel08Models = RESOURCES.find((r) => r.name === "models");
|
|
15409
15840
|
const rel08Recent = RESOURCES.find((r) => r.name === "recent");
|
|
@@ -15716,6 +16147,9 @@ async function serve(options = {}) {
|
|
|
15716
16147
|
// sees, so the plugin's `suppress_contract_write` call and the
|
|
15717
16148
|
// change-feed handler observe the same entries.
|
|
15718
16149
|
suppression,
|
|
16150
|
+
// SOURCES-REGISTRY.md §6 (Stage 2) — live registry for refresh_source
|
|
16151
|
+
// + unset_mcp_client. The singleton booted above.
|
|
16152
|
+
sourceRegistry: peerMcpRegistry,
|
|
15719
16153
|
notifier: (notification) => {
|
|
15720
16154
|
server.server.notification(notification);
|
|
15721
16155
|
}
|