wyrm-mcp 7.2.0 → 7.2.2
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/LICENSE +26 -667
- package/NOTICE +14 -33
- package/dist/activation.d.ts.map +1 -1
- package/dist/activation.js +1 -44
- package/dist/activation.js.map +1 -1
- package/dist/agent-daemon.js +4 -281
- package/dist/agent-loop.js +7 -332
- package/dist/analytics.js +13 -236
- package/dist/attribution.js +1 -49
- package/dist/audit.js +2 -457
- package/dist/auto-capture.js +3 -138
- package/dist/auto-orchestrator.js +1 -325
- package/dist/autoconfig.js +39 -840
- package/dist/buddy-runner.js +1 -109
- package/dist/buddy.js +14 -564
- package/dist/build-flags.js +1 -17
- package/dist/capabilities.js +3 -183
- package/dist/capture.js +1 -56
- package/dist/causality.js +6 -107
- package/dist/cli.js +20 -281
- package/dist/cloud/cli.js +5 -541
- package/dist/cloud/client.js +1 -221
- package/dist/cloud/crypto.js +1 -85
- package/dist/cloud/machine-id.js +2 -113
- package/dist/cloud/recovery.js +1 -60
- package/dist/cloud/sync-engine.js +7 -543
- package/dist/cloud-backup.js +5 -579
- package/dist/cloud-profile.js +1 -138
- package/dist/cloud-sync-entrypoint.js +1 -47
- package/dist/cloud-sync.js +2 -309
- package/dist/constellation.js +12 -168
- package/dist/context-build-budgeted.js +4 -144
- package/dist/context-ranking.js +1 -69
- package/dist/crypto.js +1 -179
- package/dist/daemon-write-endpoint.js +1 -290
- package/dist/daemon-writer.js +2 -406
- package/dist/database.js +43 -1110
- package/dist/deprecations.js +2 -162
- package/dist/design.js +13 -141
- package/dist/event-replication.js +1 -112
- package/dist/events-sse.js +7 -43
- package/dist/events.js +6 -238
- package/dist/failure-patterns.js +42 -659
- package/dist/federation.js +12 -236
- package/dist/goals.js +13 -101
- package/dist/golden.js +3 -355
- package/dist/handlers/agent.js +4 -165
- package/dist/handlers/alias-adapters.js +1 -129
- package/dist/handlers/aliases.js +1 -171
- package/dist/handlers/audit.js +1 -87
- package/dist/handlers/boundary.js +1 -221
- package/dist/handlers/capture.js +73 -1109
- package/dist/handlers/causality.js +7 -114
- package/dist/handlers/cloud.js +85 -382
- package/dist/handlers/companion.js +28 -459
- package/dist/handlers/datalake.js +7 -187
- package/dist/handlers/dispatch-context.js +0 -22
- package/dist/handlers/entity.js +25 -256
- package/dist/handlers/events.js +16 -335
- package/dist/handlers/failure.js +13 -340
- package/dist/handlers/goals.js +4 -296
- package/dist/handlers/intelligence.js +126 -674
- package/dist/handlers/invoicing.js +1 -70
- package/dist/handlers/mcpclient.js +6 -137
- package/dist/handlers/orchestration.js +40 -125
- package/dist/handlers/output-schemas.js +1 -24
- package/dist/handlers/presence.js +3 -99
- package/dist/handlers/project.js +28 -182
- package/dist/handlers/prompts.js +6 -157
- package/dist/handlers/quest.js +4 -224
- package/dist/handlers/recall.js +11 -218
- package/dist/handlers/registry.js +1 -167
- package/dist/handlers/resources.js +1 -288
- package/dist/handlers/review.js +11 -74
- package/dist/handlers/run.js +17 -487
- package/dist/handlers/search.js +15 -326
- package/dist/handlers/session.js +28 -615
- package/dist/handlers/share.js +8 -184
- package/dist/handlers/shims.js +1 -464
- package/dist/handlers/skill.js +67 -449
- package/dist/handlers/survivors.js +1 -120
- package/dist/handlers/symbols.js +8 -109
- package/dist/handlers/syncops.js +4 -302
- package/dist/handlers/types.js +1 -27
- package/dist/harvest.js +5 -191
- package/dist/hours.js +7 -156
- package/dist/http-auth.js +3 -321
- package/dist/http-fast.js +21 -1137
- package/dist/icons.js +1 -47
- package/dist/index.js +2 -924
- package/dist/indexer.js +4 -145
- package/dist/intelligence.js +31 -261
- package/dist/internal-dispatch.js +3 -212
- package/dist/keyset.js +1 -110
- package/dist/knowledge-graph.js +12 -176
- package/dist/license.d.ts +11 -0
- package/dist/license.d.ts.map +1 -1
- package/dist/license.js +2 -414
- package/dist/license.js.map +1 -1
- package/dist/logger.js +2 -199
- package/dist/maintenance.js +2 -148
- package/dist/mcp-client.js +6 -262
- package/dist/memory-artifacts.js +30 -449
- package/dist/migrate-prompt.js +2 -124
- package/dist/migrations.js +40 -655
- package/dist/performance.js +1 -228
- package/dist/presence.js +11 -140
- package/dist/priority-embed.js +5 -164
- package/dist/providers/embedding-provider.js +1 -196
- package/dist/readonly-gate.js +1 -29
- package/dist/rehydration.js +9 -157
- package/dist/reindex.js +1 -88
- package/dist/render-target.js +21 -514
- package/dist/render.js +4 -280
- package/dist/repl-guard.js +1 -173
- package/dist/replication-daemon-entrypoint.js +1 -31
- package/dist/replication-daemon.js +2 -262
- package/dist/resilience.js +1 -591
- package/dist/reverse-bridge.js +5 -360
- package/dist/security.js +1 -244
- package/dist/session-seen.js +3 -51
- package/dist/setup.js +1 -260
- package/dist/skill-author.js +5 -168
- package/dist/spec-kit.js +1 -191
- package/dist/sqlite-busy.js +1 -154
- package/dist/statusline.js +11 -315
- package/dist/sub-agent.js +13 -262
- package/dist/summarizer.js +13 -139
- package/dist/symbols.js +7 -283
- package/dist/sync.js +5 -359
- package/dist/tasks-dispatch.js +1 -84
- package/dist/tasks.js +1 -282
- package/dist/token-budget.js +1 -143
- package/dist/tool-analytics.js +7 -129
- package/dist/tool-annotations.js +1 -365
- package/dist/tool-manifest-v2.json +1 -1
- package/dist/tool-manifest.json +1 -1
- package/dist/tool-profiles.js +1 -75
- package/dist/trace-harvest.js +6 -244
- package/dist/types.js +1 -30
- package/dist/ui-dashboard.js +41 -50
- package/dist/ulid.js +1 -81
- package/dist/validate.js +1 -129
- package/dist/vault.js +1 -534
- package/dist/vectors.js +3 -184
- package/dist/version-check.js +4 -136
- package/dist/visibility.js +19 -155
- package/dist/wyrm-cli.js +98 -2451
- package/dist/wyrm-cli.js.map +1 -1
- package/dist/wyrm-guard.js +14 -424
- package/dist/wyrm-loop.js +3 -150
- package/dist/wyrm-manifest.json +1 -1
- package/dist/wyrm-statusline-daemon.js +1 -11
- package/dist/wyrm-statusline.js +4 -56
- package/dist/wyrm-ui.js +9 -77
- package/package.json +4 -2
|
@@ -1,288 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* MCP resources — `wyrm://` URI scheme (v7 F4 T034, spec FR-3 context economy).
|
|
3
|
-
*
|
|
4
|
-
* THE CONTEXT-ECONOMY MOVE: big payloads (a project's full truths/failures/
|
|
5
|
-
* quests, the capability inventory, an individual memory artifact) return as
|
|
6
|
-
* LINKS, not inlined bytes. A resource-capable client fetches the body on
|
|
7
|
-
* demand via `resources/read`; a resource-LESS client loses NO data because
|
|
8
|
-
* every hot-path return that emits a `resourceLink` also carries a
|
|
9
|
-
* `detail=full` FALLBACK (the full inline body) — the link is an ADDITIONAL
|
|
10
|
-
* affordance, never a substitution. This module is the single source of truth
|
|
11
|
-
* for the URI grammar, the listing, and the read backends.
|
|
12
|
-
*
|
|
13
|
-
* URI grammar (path-safe, NO network — Article VII):
|
|
14
|
-
* wyrm://capabilities the feature inventory (markdown)
|
|
15
|
-
* wyrm://stats the global DB stats (json)
|
|
16
|
-
* wyrm://memory/{id} one memory artifact by id (json)
|
|
17
|
-
* wyrm://project/{id}/truths a project's current ground truths
|
|
18
|
-
* wyrm://project/{id}/failures a project's unresolved failures
|
|
19
|
-
* wyrm://project/{id}/quests a project's open quests
|
|
20
|
-
* wyrm://project/{id}/memory a project's validated artifacts
|
|
21
|
-
* wyrm://project/{id}/stats a project's memory stats
|
|
22
|
-
*
|
|
23
|
-
* Every dynamic segment is validated against a strict allowlist before any DB
|
|
24
|
-
* access: project/memory ids are non-negative integers, the leaf is one of a
|
|
25
|
-
* fixed set. A malformed URI yields a clean structured error, never a path
|
|
26
|
-
* escape, never an SQL injection vector (ids are bound params), never a fetch.
|
|
27
|
-
*
|
|
28
|
-
* Article III: zero LLM, zero network, zero clock — a resource read is a pure
|
|
29
|
-
* function of the URI and the local SQLite state.
|
|
30
|
-
*
|
|
31
|
-
* @copyright 2026 Ghost Protocol (Pvt) Ltd.
|
|
32
|
-
* @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
|
|
33
|
-
*/
|
|
34
|
-
import { getCapabilities, renderCapabilityBriefing } from '../capabilities.js';
|
|
35
|
-
import { decodeCursor } from '../keyset.js';
|
|
36
|
-
/** The single URI scheme. */
|
|
37
|
-
export const WYRM_URI_SCHEME = 'wyrm://';
|
|
38
|
-
/** JSON MIME for structured resource bodies; markdown for the capability prose. */
|
|
39
|
-
const MIME_JSON = 'application/json';
|
|
40
|
-
const MIME_MARKDOWN = 'text/markdown';
|
|
41
|
-
/** The leaf names a project-scoped resource may carry (closed set). */
|
|
42
|
-
const PROJECT_LEAVES = ['truths', 'failures', 'quests', 'memory', 'stats'];
|
|
43
|
-
// ── URI builders (the ONE place a wyrm:// URI is constructed) ────────────────
|
|
44
|
-
export function memoryUri(id) {
|
|
45
|
-
return `${WYRM_URI_SCHEME}memory/${id}`;
|
|
46
|
-
}
|
|
47
|
-
export function projectUri(projectId, leaf, cursor) {
|
|
48
|
-
const base = `${WYRM_URI_SCHEME}project/${projectId}/${leaf}`;
|
|
49
|
-
return cursor ? `${base}?cursor=${cursor}` : base;
|
|
50
|
-
}
|
|
51
|
-
export const CAPABILITIES_URI = `${WYRM_URI_SCHEME}capabilities`;
|
|
52
|
-
export const STATS_URI = `${WYRM_URI_SCHEME}stats`;
|
|
53
|
-
/** Build a resource_link content block. */
|
|
54
|
-
export function resourceLink(uri, name, opts) {
|
|
55
|
-
return {
|
|
56
|
-
type: 'resource_link',
|
|
57
|
-
uri,
|
|
58
|
-
name,
|
|
59
|
-
...(opts?.description ? { description: opts.description } : {}),
|
|
60
|
-
...(opts?.mimeType ? { mimeType: opts.mimeType } : {}),
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
/** Non-negative integer, no leading zeros surprise, no sign, ≤ 15 digits. */
|
|
64
|
-
function parseId(segment) {
|
|
65
|
-
if (!/^\d{1,15}$/.test(segment))
|
|
66
|
-
return null;
|
|
67
|
-
const n = Number(segment);
|
|
68
|
-
return Number.isSafeInteger(n) && n >= 0 ? n : null;
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Parse a wyrm:// URI into a typed shape, or null when malformed/unknown.
|
|
72
|
-
* Defensive against path traversal: only the scheme + a fixed grammar of
|
|
73
|
-
* allowlisted segments is accepted; '..', empty segments, extra depth, and any
|
|
74
|
-
* non-grammar leaf all reject. There is NO filesystem and NO network behind a
|
|
75
|
-
* resource read — this guards the DB-query dispatch, not a path open.
|
|
76
|
-
*/
|
|
77
|
-
export function parseWyrmUri(uri) {
|
|
78
|
-
if (typeof uri !== 'string' || !uri.startsWith(WYRM_URI_SCHEME))
|
|
79
|
-
return null;
|
|
80
|
-
let rest = uri.slice(WYRM_URI_SCHEME.length);
|
|
81
|
-
// A single optional `?cursor=<opaque>` query is permitted on the project
|
|
82
|
-
// listings (v7 F4 T035 keyset pagination). The cursor is base64url (alnum +
|
|
83
|
-
// '-' '_'); anything else is rejected outright so the query suffix can never
|
|
84
|
-
// smuggle a traversal/control byte past the path grammar below.
|
|
85
|
-
let cursor;
|
|
86
|
-
const q = rest.indexOf('?');
|
|
87
|
-
if (q >= 0) {
|
|
88
|
-
const query = rest.slice(q + 1);
|
|
89
|
-
rest = rest.slice(0, q);
|
|
90
|
-
const m = /^cursor=([A-Za-z0-9_-]{1,512})$/.exec(query);
|
|
91
|
-
if (!m)
|
|
92
|
-
return null;
|
|
93
|
-
cursor = m[1];
|
|
94
|
-
}
|
|
95
|
-
// Reject control chars, traversal, and query/fragment noise outright.
|
|
96
|
-
if (/[\x00-\x1f\x7f]/.test(rest) || rest.includes('..'))
|
|
97
|
-
return null;
|
|
98
|
-
const segs = rest.split('/');
|
|
99
|
-
if (segs.some((s) => s.length === 0))
|
|
100
|
-
return null;
|
|
101
|
-
if (segs.length === 1) {
|
|
102
|
-
if (cursor !== undefined)
|
|
103
|
-
return null;
|
|
104
|
-
if (segs[0] === 'capabilities')
|
|
105
|
-
return { kind: 'capabilities' };
|
|
106
|
-
if (segs[0] === 'stats')
|
|
107
|
-
return { kind: 'stats' };
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
if (segs.length === 2 && segs[0] === 'memory') {
|
|
111
|
-
if (cursor !== undefined)
|
|
112
|
-
return null;
|
|
113
|
-
const id = parseId(segs[1]);
|
|
114
|
-
return id === null ? null : { kind: 'memory', id };
|
|
115
|
-
}
|
|
116
|
-
if (segs.length === 3 && segs[0] === 'project') {
|
|
117
|
-
const id = parseId(segs[1]);
|
|
118
|
-
if (id === null)
|
|
119
|
-
return null;
|
|
120
|
-
const leaf = segs[2];
|
|
121
|
-
if (PROJECT_LEAVES.includes(leaf)) {
|
|
122
|
-
// Cursor only meaningful on the paginated `memory` leaf; reject it on the
|
|
123
|
-
// others rather than silently ignoring (strict grammar).
|
|
124
|
-
if (cursor !== undefined && leaf !== 'memory')
|
|
125
|
-
return null;
|
|
126
|
-
return { kind: 'project', id, leaf: leaf, ...(cursor !== undefined ? { cursor } : {}) };
|
|
127
|
-
}
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
|
-
// ── resources/list + resources/templates/list ───────────────────────────────
|
|
133
|
-
/**
|
|
134
|
-
* The static, always-available resources (no project context needed). The
|
|
135
|
-
* project-scoped resources are advertised as TEMPLATES (their id is a
|
|
136
|
-
* parameter), so resources/list stays small and stable while every project's
|
|
137
|
-
* data is still reachable by URI.
|
|
138
|
-
*/
|
|
139
|
-
export function listWyrmResources() {
|
|
140
|
-
return [
|
|
141
|
-
{
|
|
142
|
-
uri: CAPABILITIES_URI,
|
|
143
|
-
name: 'Wyrm capabilities',
|
|
144
|
-
description: 'Feature inventory + runtime state — what this memory system can do and which tool to reach for. The resource form of wyrm_capabilities.',
|
|
145
|
-
mimeType: MIME_MARKDOWN,
|
|
146
|
-
},
|
|
147
|
-
{
|
|
148
|
-
uri: STATS_URI,
|
|
149
|
-
name: 'Wyrm global stats',
|
|
150
|
-
description: 'Global database stats (projects, sessions, quests, data points, size). The resource form of wyrm_stats.',
|
|
151
|
-
mimeType: MIME_JSON,
|
|
152
|
-
},
|
|
153
|
-
];
|
|
154
|
-
}
|
|
155
|
-
/** Resource templates for the project-scoped + by-id resources. */
|
|
156
|
-
export function listWyrmResourceTemplates() {
|
|
157
|
-
return [
|
|
158
|
-
{
|
|
159
|
-
uriTemplate: `${WYRM_URI_SCHEME}memory/{id}`,
|
|
160
|
-
name: 'Memory artifact',
|
|
161
|
-
description: 'A single memory artifact (lesson/pattern/anti-pattern/heuristic/reasoning trace) by id.',
|
|
162
|
-
mimeType: MIME_JSON,
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
uriTemplate: `${WYRM_URI_SCHEME}project/{id}/truths`,
|
|
166
|
-
name: 'Project ground truths',
|
|
167
|
-
description: "A project's current ground truths (the authoritative facts).",
|
|
168
|
-
mimeType: MIME_JSON,
|
|
169
|
-
},
|
|
170
|
-
{
|
|
171
|
-
uriTemplate: `${WYRM_URI_SCHEME}project/{id}/failures`,
|
|
172
|
-
name: 'Project failures',
|
|
173
|
-
description: "A project's unresolved failure patterns (the negative-learning set).",
|
|
174
|
-
mimeType: MIME_JSON,
|
|
175
|
-
},
|
|
176
|
-
{
|
|
177
|
-
uriTemplate: `${WYRM_URI_SCHEME}project/{id}/quests`,
|
|
178
|
-
name: 'Project quests',
|
|
179
|
-
description: "A project's open quests (pending + in-progress).",
|
|
180
|
-
mimeType: MIME_JSON,
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
uriTemplate: `${WYRM_URI_SCHEME}project/{id}/memory`,
|
|
184
|
-
name: 'Project memory',
|
|
185
|
-
description: "A project's validated memory artifacts.",
|
|
186
|
-
mimeType: MIME_JSON,
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
uriTemplate: `${WYRM_URI_SCHEME}project/{id}/stats`,
|
|
190
|
-
name: 'Project memory stats',
|
|
191
|
-
description: "A project's memory artifact stats (totals by kind, avg confidence).",
|
|
192
|
-
mimeType: MIME_JSON,
|
|
193
|
-
},
|
|
194
|
-
];
|
|
195
|
-
}
|
|
196
|
-
// ── resources/read backends ──────────────────────────────────────────────────
|
|
197
|
-
/** Hard read caps so a resource read can never inline an unbounded payload. */
|
|
198
|
-
const PROJECT_LIST_CAP = 200;
|
|
199
|
-
/** Raised when a URI is well-formed-but-not-found / malformed. The caller maps
|
|
200
|
-
* it to a clean MCP error; it is never a crash or a leaked stack. */
|
|
201
|
-
export class ResourceNotFoundError extends Error {
|
|
202
|
-
uri;
|
|
203
|
-
constructor(uri, message) {
|
|
204
|
-
super(message);
|
|
205
|
-
this.uri = uri;
|
|
206
|
-
this.name = 'ResourceNotFoundError';
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
/** Deterministic 2-space JSON (Article III/VIII: same state ⇒ same bytes). */
|
|
210
|
-
function jsonContent(uri, body) {
|
|
211
|
-
return { uri, mimeType: MIME_JSON, text: JSON.stringify(body, null, 2) };
|
|
212
|
-
}
|
|
213
|
-
/**
|
|
214
|
-
* Read a wyrm:// resource against the local DB. Pure read — no writes, no
|
|
215
|
-
* network, no clock. Throws ResourceNotFoundError for a malformed/unknown URI
|
|
216
|
-
* or a missing row.
|
|
217
|
-
*/
|
|
218
|
-
export function readWyrmResource(uri, ctx) {
|
|
219
|
-
const parsed = parseWyrmUri(uri);
|
|
220
|
-
if (!parsed)
|
|
221
|
-
throw new ResourceNotFoundError(uri, `Unknown or malformed resource URI: ${uri}`);
|
|
222
|
-
switch (parsed.kind) {
|
|
223
|
-
case 'capabilities': {
|
|
224
|
-
const report = getCapabilities(ctx.db.getDatabase(), ctx.WYRM_TOOL_COUNT, {
|
|
225
|
-
detectVectorProvider: () => (process.env.WYRM_VECTOR_PROVIDER === 'openai' ? 'openai' : 'ollama'),
|
|
226
|
-
hasEncryption: () => !!process.env.WYRM_ENCRYPTION_KEY,
|
|
227
|
-
isFederationEnabled: () => true,
|
|
228
|
-
isAgentRunning: () => {
|
|
229
|
-
try {
|
|
230
|
-
return ctx.agentDaemon.status().running;
|
|
231
|
-
}
|
|
232
|
-
catch {
|
|
233
|
-
return null;
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
});
|
|
237
|
-
// Markdown body — the human briefing, same bytes wyrm_capabilities emits.
|
|
238
|
-
return { uri, mimeType: MIME_MARKDOWN, text: renderCapabilityBriefing(report) };
|
|
239
|
-
}
|
|
240
|
-
case 'stats': {
|
|
241
|
-
return jsonContent(uri, ctx.db.getStats());
|
|
242
|
-
}
|
|
243
|
-
case 'memory': {
|
|
244
|
-
const artifact = ctx.memory.get(parsed.id);
|
|
245
|
-
if (!artifact)
|
|
246
|
-
throw new ResourceNotFoundError(uri, `Memory artifact not found: ${parsed.id}`);
|
|
247
|
-
return jsonContent(uri, artifact);
|
|
248
|
-
}
|
|
249
|
-
case 'project': {
|
|
250
|
-
const project = ctx.db.getProjectById(parsed.id);
|
|
251
|
-
if (!project)
|
|
252
|
-
throw new ResourceNotFoundError(uri, `Project not found: ${parsed.id}`);
|
|
253
|
-
switch (parsed.leaf) {
|
|
254
|
-
case 'truths':
|
|
255
|
-
return jsonContent(uri, { project_id: parsed.id, truths: ctx.groundTruths.getCurrent(parsed.id) });
|
|
256
|
-
case 'failures':
|
|
257
|
-
return jsonContent(uri, { project_id: parsed.id, failures: ctx.failures.list(parsed.id, PROJECT_LIST_CAP) });
|
|
258
|
-
case 'quests': {
|
|
259
|
-
const quests = ctx.db
|
|
260
|
-
.getDatabase()
|
|
261
|
-
.prepare("SELECT * FROM quests WHERE project_id = ? AND status IN ('pending','in_progress') ORDER BY CASE priority WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 ELSE 3 END, id LIMIT ?")
|
|
262
|
-
.all(parsed.id, PROJECT_LIST_CAP);
|
|
263
|
-
return jsonContent(uri, { project_id: parsed.id, quests });
|
|
264
|
-
}
|
|
265
|
-
case 'memory': {
|
|
266
|
-
// Keyset-paginated (v7 F4 T035): a project's full artifact set can be
|
|
267
|
-
// larger than one inline payload, so the listing returns a PAGE +
|
|
268
|
-
// an opaque nextCursor instead of a hard 200-row truncation that
|
|
269
|
-
// silently drops the tail. A bad/garbage cursor decodes to null → the
|
|
270
|
-
// first page (never throws on the wire).
|
|
271
|
-
const after = decodeCursor(parsed.cursor);
|
|
272
|
-
const page = ctx.memory.listPage(parsed.id, { pageSize: PROJECT_LIST_CAP, after });
|
|
273
|
-
const content = jsonContent(uri, {
|
|
274
|
-
project_id: parsed.id,
|
|
275
|
-
artifacts: page.items,
|
|
276
|
-
...(page.nextCursor ? { next_cursor: page.nextCursor } : {}),
|
|
277
|
-
});
|
|
278
|
-
if (page.nextCursor)
|
|
279
|
-
content.nextCursor = page.nextCursor;
|
|
280
|
-
return content;
|
|
281
|
-
}
|
|
282
|
-
case 'stats':
|
|
283
|
-
return jsonContent(uri, { project_id: parsed.id, stats: ctx.memory.getStats(parsed.id) });
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
//# sourceMappingURL=resources.js.map
|
|
1
|
+
import{getCapabilities as f,renderCapabilityBriefing as y}from"../capabilities.js";import{decodeCursor as g}from"../keyset.js";const o="wyrm://",c="application/json",l="text/markdown",T=["truths","failures","quests","memory","stats"];function b(r){return`${o}memory/${r}`}function C(r,t,e){const i=`${o}project/${r}/${t}`;return e?`${i}?cursor=${e}`:i}const h=`${o}capabilities`,j=`${o}stats`;function $(r,t,e){return{type:"resource_link",uri:r,name:t,...e?.description?{description:e.description}:{},...e?.mimeType?{mimeType:e.mimeType}:{}}}function d(r){if(!/^\d{1,15}$/.test(r))return null;const t=Number(r);return Number.isSafeInteger(t)&&t>=0?t:null}function E(r){if(typeof r!="string"||!r.startsWith(o))return null;let t=r.slice(o.length),e;const i=t.indexOf("?");if(i>=0){const s=t.slice(i+1);t=t.slice(0,i);const a=/^cursor=([A-Za-z0-9_-]{1,512})$/.exec(s);if(!a)return null;e=a[1]}if(/[\x00-\x1f\x7f]/.test(t)||t.includes(".."))return null;const n=t.split("/");if(n.some(s=>s.length===0))return null;if(n.length===1)return e!==void 0?null:n[0]==="capabilities"?{kind:"capabilities"}:n[0]==="stats"?{kind:"stats"}:null;if(n.length===2&&n[0]==="memory"){if(e!==void 0)return null;const s=d(n[1]);return s===null?null:{kind:"memory",id:s}}if(n.length===3&&n[0]==="project"){const s=d(n[1]);if(s===null)return null;const a=n[2];return T.includes(a)?e!==void 0&&a!=="memory"?null:{kind:"project",id:s,leaf:a,...e!==void 0?{cursor:e}:{}}:null}return null}function N(){return[{uri:h,name:"Wyrm capabilities",description:"Feature inventory + runtime state \u2014 what this memory system can do and which tool to reach for. The resource form of wyrm_capabilities.",mimeType:l},{uri:j,name:"Wyrm global stats",description:"Global database stats (projects, sessions, quests, data points, size). The resource form of wyrm_stats.",mimeType:c}]}function I(){return[{uriTemplate:`${o}memory/{id}`,name:"Memory artifact",description:"A single memory artifact (lesson/pattern/anti-pattern/heuristic/reasoning trace) by id.",mimeType:c},{uriTemplate:`${o}project/{id}/truths`,name:"Project ground truths",description:"A project's current ground truths (the authoritative facts).",mimeType:c},{uriTemplate:`${o}project/{id}/failures`,name:"Project failures",description:"A project's unresolved failure patterns (the negative-learning set).",mimeType:c},{uriTemplate:`${o}project/{id}/quests`,name:"Project quests",description:"A project's open quests (pending + in-progress).",mimeType:c},{uriTemplate:`${o}project/{id}/memory`,name:"Project memory",description:"A project's validated memory artifacts.",mimeType:c},{uriTemplate:`${o}project/{id}/stats`,name:"Project memory stats",description:"A project's memory artifact stats (totals by kind, avg confidence).",mimeType:c}]}const m=200;class p extends Error{uri;constructor(t,e){super(e),this.uri=t,this.name="ResourceNotFoundError"}}function u(r,t){return{uri:r,mimeType:c,text:JSON.stringify(t,null,2)}}function x(r,t){const e=E(r);if(!e)throw new p(r,`Unknown or malformed resource URI: ${r}`);switch(e.kind){case"capabilities":{const i=f(t.db.getDatabase(),t.WYRM_TOOL_COUNT,{detectVectorProvider:()=>process.env.WYRM_VECTOR_PROVIDER==="openai"?"openai":"ollama",hasEncryption:()=>!!process.env.WYRM_ENCRYPTION_KEY,isFederationEnabled:()=>!0,isAgentRunning:()=>{try{return t.agentDaemon.status().running}catch{return null}}});return{uri:r,mimeType:l,text:y(i)}}case"stats":return u(r,t.db.getStats());case"memory":{const i=t.memory.get(e.id);if(!i)throw new p(r,`Memory artifact not found: ${e.id}`);return u(r,i)}case"project":{if(!t.db.getProjectById(e.id))throw new p(r,`Project not found: ${e.id}`);switch(e.leaf){case"truths":return u(r,{project_id:e.id,truths:t.groundTruths.getCurrent(e.id)});case"failures":return u(r,{project_id:e.id,failures:t.failures.list(e.id,m)});case"quests":{const n=t.db.getDatabase().prepare("SELECT * FROM quests WHERE project_id = ? AND status IN ('pending','in_progress') ORDER BY CASE priority WHEN 'critical' THEN 0 WHEN 'high' THEN 1 WHEN 'medium' THEN 2 ELSE 3 END, id LIMIT ?").all(e.id,m);return u(r,{project_id:e.id,quests:n})}case"memory":{const n=g(e.cursor),s=t.memory.listPage(e.id,{pageSize:m,after:n}),a=u(r,{project_id:e.id,artifacts:s.items,...s.nextCursor?{next_cursor:s.nextCursor}:{}});return s.nextCursor&&(a.nextCursor=s.nextCursor),a}case"stats":return u(r,{project_id:e.id,stats:t.memory.getStats(e.id)})}}}}export{h as CAPABILITIES_URI,p as ResourceNotFoundError,j as STATS_URI,o as WYRM_URI_SCHEME,I as listWyrmResourceTemplates,N as listWyrmResources,b as memoryUri,E as parseWyrmUri,C as projectUri,x as readWyrmResource,$ as resourceLink};
|
package/dist/handlers/review.js
CHANGED
|
@@ -1,74 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import { TOOL_ANNOTATIONS } from '../tool-annotations.js';
|
|
13
|
-
import { renderResult, withGlyph } from '../render.js';
|
|
14
|
-
import { reverseBridgeSigFromTags, recordReverseBridgeRejection } from '../reverse-bridge.js';
|
|
15
|
-
export const reviewToolSpecs = [
|
|
16
|
-
{
|
|
17
|
-
name: "wyrm_review",
|
|
18
|
-
description: "Use to process the review queue - approve or reject the pending memory candidates waiting from extraction, harvest, imports, capture conflicts, or session distillation. Approve activates the artifact for recall; reject permanently deletes it (unrecoverable).",
|
|
19
|
-
inputSchema: {
|
|
20
|
-
type: "object",
|
|
21
|
-
properties: {
|
|
22
|
-
artifactId: { type: "number" },
|
|
23
|
-
approved: { type: "boolean", description: "true = activate, false = hard delete" },
|
|
24
|
-
notes: { type: "string" },
|
|
25
|
-
},
|
|
26
|
-
required: ["artifactId", "approved"],
|
|
27
|
-
},
|
|
28
|
-
outputSchema: {
|
|
29
|
-
type: "object",
|
|
30
|
-
properties: {
|
|
31
|
-
artifact_id: { type: "integer" },
|
|
32
|
-
approved: { type: "boolean" },
|
|
33
|
-
deleted: { type: "boolean" },
|
|
34
|
-
problem: { type: "string" },
|
|
35
|
-
notes: { type: ["string", "null"] },
|
|
36
|
-
},
|
|
37
|
-
required: ["artifact_id", "approved", "deleted", "problem", "notes"],
|
|
38
|
-
},
|
|
39
|
-
annotations: TOOL_ANNOTATIONS.wyrm_review,
|
|
40
|
-
aliases: [],
|
|
41
|
-
handler: (args, { memory, raw }) => {
|
|
42
|
-
const { artifactId: rvId, approved, notes: rvNotes } = args;
|
|
43
|
-
const artifact = memory.get(rvId);
|
|
44
|
-
if (!artifact)
|
|
45
|
-
return { content: [{ type: "text", text: `Artifact #${rvId} not found.` }], isError: true };
|
|
46
|
-
if (approved) {
|
|
47
|
-
memory.update(rvId, { needs_review: 0 });
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
// A reverse-bridge candidate (rb:-tagged) that the operator rejects gets
|
|
51
|
-
// a rejection tombstone BEFORE the delete, so the next bridge sweep does
|
|
52
|
-
// not re-extract + re-queue the identical outside-prose (security pass
|
|
53
|
-
// #2, finding #1). Non-bridge artifacts have no rb: sig → no tombstone.
|
|
54
|
-
const rbSig = reverseBridgeSigFromTags(artifact.tags);
|
|
55
|
-
if (rbSig)
|
|
56
|
-
recordReverseBridgeRejection(raw(), artifact.project_id, rbSig);
|
|
57
|
-
raw().prepare('DELETE FROM memory_artifacts WHERE id = ?').run(rvId);
|
|
58
|
-
}
|
|
59
|
-
const body = {
|
|
60
|
-
artifact_id: rvId,
|
|
61
|
-
approved,
|
|
62
|
-
deleted: !approved,
|
|
63
|
-
problem: artifact.problem.slice(0, 80),
|
|
64
|
-
notes: rvNotes ?? null,
|
|
65
|
-
};
|
|
66
|
-
return renderResult(body, (b, g) => b.approved
|
|
67
|
-
? withGlyph(g.ok, `**Approved** -- Artifact #${b.artifact_id} is now active.`) +
|
|
68
|
-
`\n\n"${b.problem}"\n\nIt will appear in future \`wyrm_recall\` and \`wyrm_context_build\` results.${b.notes ? `\n\nNotes: ${b.notes}` : ''}`
|
|
69
|
-
: withGlyph(g.fail, `**Rejected** -- Artifact #${b.artifact_id} permanently deleted.`) +
|
|
70
|
-
`\n\n"${b.problem}"${b.notes ? `\n\nNotes: ${b.notes}` : ''}`);
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
];
|
|
74
|
-
//# sourceMappingURL=review.js.map
|
|
1
|
+
import{TOOL_ANNOTATIONS as l}from"../tool-annotations.js";import{renderResult as f,withGlyph as p}from"../render.js";import{reverseBridgeSigFromTags as m,recordReverseBridgeRejection as u}from"../reverse-bridge.js";const g=[{name:"wyrm_review",description:"Use to process the review queue - approve or reject the pending memory candidates waiting from extraction, harvest, imports, capture conflicts, or session distillation. Approve activates the artifact for recall; reject permanently deletes it (unrecoverable).",inputSchema:{type:"object",properties:{artifactId:{type:"number"},approved:{type:"boolean",description:"true = activate, false = hard delete"},notes:{type:"string"}},required:["artifactId","approved"]},outputSchema:{type:"object",properties:{artifact_id:{type:"integer"},approved:{type:"boolean"},deleted:{type:"boolean"},problem:{type:"string"},notes:{type:["string","null"]}},required:["artifact_id","approved","deleted","problem","notes"]},annotations:l.wyrm_review,aliases:[],handler:(s,{memory:i,raw:a})=>{const{artifactId:t,approved:o,notes:d}=s,r=i.get(t);if(!r)return{content:[{type:"text",text:`Artifact #${t} not found.`}],isError:!0};if(o)i.update(t,{needs_review:0});else{const e=m(r.tags);e&&u(a(),r.project_id,e),a().prepare("DELETE FROM memory_artifacts WHERE id = ?").run(t)}const c={artifact_id:t,approved:o,deleted:!o,problem:r.problem.slice(0,80),notes:d??null};return f(c,(e,n)=>e.approved?p(n.ok,`**Approved** -- Artifact #${e.artifact_id} is now active.`)+`
|
|
2
|
+
|
|
3
|
+
"${e.problem}"
|
|
4
|
+
|
|
5
|
+
It will appear in future \`wyrm_recall\` and \`wyrm_context_build\` results.${e.notes?`
|
|
6
|
+
|
|
7
|
+
Notes: ${e.notes}`:""}`:p(n.fail,`**Rejected** -- Artifact #${e.artifact_id} permanently deleted.`)+`
|
|
8
|
+
|
|
9
|
+
"${e.problem}"${e.notes?`
|
|
10
|
+
|
|
11
|
+
Notes: ${e.notes}`:""}`)}}];export{g as reviewToolSpecs};
|