wyrm-mcp 7.2.1 → 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.
Files changed (150) hide show
  1. package/LICENSE +26 -667
  2. package/NOTICE +14 -33
  3. package/dist/activation.js +1 -60
  4. package/dist/agent-daemon.js +4 -281
  5. package/dist/agent-loop.js +7 -332
  6. package/dist/analytics.js +13 -236
  7. package/dist/attribution.js +1 -49
  8. package/dist/audit.js +2 -457
  9. package/dist/auto-capture.js +3 -138
  10. package/dist/auto-orchestrator.js +1 -325
  11. package/dist/autoconfig.js +39 -840
  12. package/dist/buddy-runner.js +1 -109
  13. package/dist/buddy.js +14 -564
  14. package/dist/build-flags.js +1 -17
  15. package/dist/capabilities.js +3 -183
  16. package/dist/capture.js +1 -56
  17. package/dist/causality.js +6 -107
  18. package/dist/cli.js +20 -281
  19. package/dist/cloud/cli.js +5 -541
  20. package/dist/cloud/client.js +1 -221
  21. package/dist/cloud/crypto.js +1 -85
  22. package/dist/cloud/machine-id.js +2 -113
  23. package/dist/cloud/recovery.js +1 -60
  24. package/dist/cloud/sync-engine.js +7 -543
  25. package/dist/cloud-backup.js +5 -579
  26. package/dist/cloud-profile.js +1 -138
  27. package/dist/cloud-sync-entrypoint.js +1 -47
  28. package/dist/cloud-sync.js +2 -309
  29. package/dist/constellation.js +12 -168
  30. package/dist/context-build-budgeted.js +4 -144
  31. package/dist/context-ranking.js +1 -69
  32. package/dist/crypto.js +1 -179
  33. package/dist/daemon-write-endpoint.js +1 -290
  34. package/dist/daemon-writer.js +2 -406
  35. package/dist/database.js +43 -1110
  36. package/dist/deprecations.js +2 -162
  37. package/dist/design.js +13 -141
  38. package/dist/event-replication.js +1 -112
  39. package/dist/events-sse.js +7 -43
  40. package/dist/events.js +6 -238
  41. package/dist/failure-patterns.js +42 -659
  42. package/dist/federation.js +12 -236
  43. package/dist/goals.js +13 -101
  44. package/dist/golden.js +3 -355
  45. package/dist/handlers/agent.js +4 -165
  46. package/dist/handlers/alias-adapters.js +1 -129
  47. package/dist/handlers/aliases.js +1 -171
  48. package/dist/handlers/audit.js +1 -87
  49. package/dist/handlers/boundary.js +1 -221
  50. package/dist/handlers/capture.js +73 -1109
  51. package/dist/handlers/causality.js +7 -114
  52. package/dist/handlers/cloud.js +85 -382
  53. package/dist/handlers/companion.js +28 -459
  54. package/dist/handlers/datalake.js +7 -187
  55. package/dist/handlers/dispatch-context.js +0 -22
  56. package/dist/handlers/entity.js +25 -256
  57. package/dist/handlers/events.js +16 -335
  58. package/dist/handlers/failure.js +13 -340
  59. package/dist/handlers/goals.js +4 -296
  60. package/dist/handlers/intelligence.js +126 -674
  61. package/dist/handlers/invoicing.js +1 -70
  62. package/dist/handlers/mcpclient.js +6 -137
  63. package/dist/handlers/orchestration.js +40 -125
  64. package/dist/handlers/output-schemas.js +1 -24
  65. package/dist/handlers/presence.js +3 -99
  66. package/dist/handlers/project.js +28 -182
  67. package/dist/handlers/prompts.js +6 -157
  68. package/dist/handlers/quest.js +4 -224
  69. package/dist/handlers/recall.js +11 -218
  70. package/dist/handlers/registry.js +1 -167
  71. package/dist/handlers/resources.js +1 -288
  72. package/dist/handlers/review.js +11 -74
  73. package/dist/handlers/run.js +17 -487
  74. package/dist/handlers/search.js +15 -326
  75. package/dist/handlers/session.js +28 -615
  76. package/dist/handlers/share.js +8 -184
  77. package/dist/handlers/shims.js +1 -464
  78. package/dist/handlers/skill.js +67 -449
  79. package/dist/handlers/survivors.js +1 -120
  80. package/dist/handlers/symbols.js +8 -109
  81. package/dist/handlers/syncops.js +4 -302
  82. package/dist/handlers/types.js +1 -27
  83. package/dist/harvest.js +5 -191
  84. package/dist/hours.js +7 -156
  85. package/dist/http-auth.js +3 -321
  86. package/dist/http-fast.js +21 -1137
  87. package/dist/icons.js +1 -47
  88. package/dist/index.js +2 -924
  89. package/dist/indexer.js +4 -145
  90. package/dist/intelligence.js +31 -261
  91. package/dist/internal-dispatch.js +3 -212
  92. package/dist/keyset.js +1 -110
  93. package/dist/knowledge-graph.js +12 -176
  94. package/dist/license.js +2 -441
  95. package/dist/logger.js +2 -199
  96. package/dist/maintenance.js +2 -148
  97. package/dist/mcp-client.js +6 -262
  98. package/dist/memory-artifacts.js +30 -449
  99. package/dist/migrate-prompt.js +2 -124
  100. package/dist/migrations.js +40 -655
  101. package/dist/performance.js +1 -228
  102. package/dist/presence.js +11 -140
  103. package/dist/priority-embed.js +5 -164
  104. package/dist/providers/embedding-provider.js +1 -196
  105. package/dist/readonly-gate.js +1 -29
  106. package/dist/rehydration.js +9 -157
  107. package/dist/reindex.js +1 -88
  108. package/dist/render-target.js +21 -514
  109. package/dist/render.js +4 -280
  110. package/dist/repl-guard.js +1 -173
  111. package/dist/replication-daemon-entrypoint.js +1 -31
  112. package/dist/replication-daemon.js +2 -262
  113. package/dist/resilience.js +1 -591
  114. package/dist/reverse-bridge.js +5 -360
  115. package/dist/security.js +1 -244
  116. package/dist/session-seen.js +3 -51
  117. package/dist/setup.js +1 -260
  118. package/dist/skill-author.js +5 -168
  119. package/dist/spec-kit.js +1 -191
  120. package/dist/sqlite-busy.js +1 -154
  121. package/dist/statusline.js +11 -315
  122. package/dist/sub-agent.js +13 -262
  123. package/dist/summarizer.js +13 -139
  124. package/dist/symbols.js +7 -283
  125. package/dist/sync.js +5 -359
  126. package/dist/tasks-dispatch.js +1 -84
  127. package/dist/tasks.js +1 -282
  128. package/dist/token-budget.js +1 -143
  129. package/dist/tool-analytics.js +7 -129
  130. package/dist/tool-annotations.js +1 -365
  131. package/dist/tool-manifest-v2.json +1 -1
  132. package/dist/tool-manifest.json +1 -1
  133. package/dist/tool-profiles.js +1 -75
  134. package/dist/trace-harvest.js +6 -244
  135. package/dist/types.js +1 -30
  136. package/dist/ui-dashboard.js +41 -50
  137. package/dist/ulid.js +1 -81
  138. package/dist/validate.js +1 -129
  139. package/dist/vault.js +1 -534
  140. package/dist/vectors.js +3 -184
  141. package/dist/version-check.js +4 -136
  142. package/dist/visibility.js +19 -155
  143. package/dist/wyrm-cli.js +98 -2464
  144. package/dist/wyrm-guard.js +14 -424
  145. package/dist/wyrm-loop.js +3 -150
  146. package/dist/wyrm-manifest.json +1 -1
  147. package/dist/wyrm-statusline-daemon.js +1 -11
  148. package/dist/wyrm-statusline.js +4 -56
  149. package/dist/wyrm-ui.js +9 -77
  150. package/package.json +4 -2
package/dist/golden.js CHANGED
@@ -1,355 +1,3 @@
1
- /**
2
- * Golden-transcript capture Wyrm 7.0 BROOD, Phase F1 (T003b).
3
- *
4
- * Opt-in (`WYRM_GOLDEN_CAPTURE=1`, default OFF — Article VII) full-fidelity
5
- * request/response JSONL capture at the single CallTool dispatch choke point
6
- * (src/index.ts), covering BOTH dispatch families (handlerRegistry + the
7
- * switch) plus the cache-hit early return and both catch returns. This is the
8
- * fidelity `tool_call_log` deliberately lacks (its args_summary is truncated +
9
- * value-stripped by design — frequency/coverage ranking only, NOT replayable).
10
- * The corpus feeds the T021 alias-spine replay gate.
11
- *
12
- * Design spec: specs/wyrm-v7-brood/research/golden-capture-spec.md
13
- *
14
- * Contract (the `emitEvent` contract — src/events.ts):
15
- * - NEVER throws and never blocks the tool path; entire body try/catch,
16
- * warn to stderr only (stdout is the MCP transport).
17
- * - Circuit breaker: 5 consecutive write failures disable capture for the
18
- * process lifetime with a single warning (no warn-per-call storm on a
19
- * full disk).
20
- * - Lazy init: dir creation attempted on first capture, not at startup.
21
- * - Article III: pure local fs append — no LLM, no network, no new deps.
22
- * - Secrets redacted BY KEY (recursive, request AND response, on a deep
23
- * clone — the live result object is still on its way to the client and is
24
- * never mutated), plus a value-pattern safety net for secrets smuggled
25
- * through benign fields. Redacted paths are recorded in `redactions[]` so
26
- * replay can wildcard them.
27
- */
28
- import { appendFileSync, mkdirSync, existsSync, readFileSync } from "fs";
29
- import { homedir } from "os";
30
- import { join, dirname } from "path";
31
- import { fileURLToPath } from "url";
32
- /**
33
- * Failure warnings go DIRECTLY to stderr (the deprecations.ts pattern) — never
34
- * through the logger. The header contract ("warn to stderr only") must hold by
35
- * construction on the stdio CallTool path, independent of any logger console
36
- * configuration. Failure-isolated: never throws.
37
- */
38
- function warnStderr(message, err) {
39
- try {
40
- const detail = err === undefined ? "" : ` (${err instanceof Error ? err.message : String(err)})`;
41
- process.stderr.write(`[wyrm] ${message}${detail}\n`);
42
- }
43
- catch {
44
- /* warnings must never break a tool call */
45
- }
46
- }
47
- // ---------------------------------------------------------------------------
48
- // Redaction rules (golden-capture-spec.md §3)
49
- // ---------------------------------------------------------------------------
50
- /** Rule 1 — substring match on key names (case-insensitive): always redact. */
51
- const SUBSTRING_REDACT = [
52
- "token",
53
- "secret",
54
- "password",
55
- "passwd",
56
- "authorization",
57
- "passphrase",
58
- "bearer",
59
- "credential",
60
- "apikey",
61
- "api_key",
62
- // wyrm_activate's `license` arg is a signed bearer-style entitlement
63
- // credential; no VALUE_PATTERN recognizes signed-license JSON, so the key
64
- // rule must catch it (golden-capture-spec.md §3 amendment).
65
- "license",
66
- ];
67
- /**
68
- * Rule 3 — per-tool overrides: keys whose ENTIRE value subtree has every value
69
- * redacted regardless of key names (arbitrary env names can carry secrets that
70
- * no key rule catches).
71
- */
72
- const TOOL_REDACT_ALL_VALUES = {
73
- wyrm_mcp_register: new Set(["env"]),
74
- };
75
- /**
76
- * Rule 4 — value-pattern safety net on every string value regardless of key
77
- * name. Catches secrets smuggled through benign fields (value, notes,
78
- * response text).
79
- */
80
- const VALUE_PATTERNS = [
81
- { label: "jwt", re: /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]*/ },
82
- { label: "github-token", re: /\bgh[posu]_[A-Za-z0-9]{16,}\b/ },
83
- { label: "npm-token", re: /\bnpm_[A-Za-z0-9]{16,}\b/ },
84
- { label: "api-key", re: /\b[sp]k-[A-Za-z0-9_-]{16,}\b/ },
85
- { label: "aws-access-key", re: /\bAKIA[0-9A-Z]{16}\b/ },
86
- { label: "slack-token", re: /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/ },
87
- { label: "pem-private-key", re: /-----BEGIN [A-Z ]*PRIVATE KEY-----/ },
88
- // Generic bearer credentials smuggled under benign keys (plausible inside
89
- // wyrm_call_external proxied args). The {16,} run keeps prose like
90
- // "Bearer token authentication" unmatched.
91
- { label: "bearer", re: /\bBearer\s+[A-Za-z0-9._~+\/-]{16,}/ },
92
- ];
93
- /** Operator escape hatch: extra key names (exact, case-insensitive) to redact. */
94
- function extraRedactKeys() {
95
- const raw = process.env.WYRM_GOLDEN_REDACT_EXTRA;
96
- if (!raw)
97
- return new Set();
98
- return new Set(raw
99
- .split(",")
100
- .map((s) => s.trim().toLowerCase())
101
- .filter(Boolean));
102
- }
103
- /**
104
- * Should this key's value be redacted outright?
105
- * - Rule 1: substring match against SUBSTRING_REDACT (+ exact extras).
106
- * - Rule 2: compound-suffix `*key` (privateKey, ssh_key, access-key,
107
- * signingKey) — EXCEPT the exact bare name `key`, which in Wyrm is a
108
- * required benign identifier on 6+ core tools (data store, set_global,
109
- * references, design tokens — incl. the #3 most-called tool). Redacting it
110
- * would make those write transcripts unreplayable; the value-pattern net
111
- * backstops the residual risk. Deliberate, documented deviation
112
- * (golden-capture-spec.md §6.1).
113
- */
114
- function keyIsSecret(key, extras) {
115
- const lower = key.toLowerCase();
116
- if (extras.has(lower))
117
- return true;
118
- for (const s of SUBSTRING_REDACT) {
119
- if (lower.includes(s))
120
- return true;
121
- }
122
- if (lower !== "key" && lower.endsWith("key"))
123
- return true;
124
- return false;
125
- }
126
- /**
127
- * Deep-clone-and-redact in one pass. Walks the ORIGINAL (never mutates it) and
128
- * builds the redacted copy. Cycles and non-serializable leaves degrade to
129
- * `{"$unserializable": true}` — the record still captures rather than being
130
- * dropped whole (mirrors emitEvent's payload-stringify isolation).
131
- */
132
- function redactWalk(value, path, ctx, redactAll) {
133
- // Primitives
134
- if (value === null || value === undefined)
135
- return value;
136
- const t = typeof value;
137
- if (t === "string") {
138
- if (redactAll) {
139
- ctx.redactions.push(path);
140
- return "[REDACTED]";
141
- }
142
- for (const { label, re } of VALUE_PATTERNS) {
143
- if (re.test(value)) {
144
- ctx.redactions.push(path);
145
- return `[REDACTED:${label}]`;
146
- }
147
- }
148
- return value;
149
- }
150
- if (t === "number" || t === "boolean") {
151
- if (redactAll) {
152
- ctx.redactions.push(path);
153
- return "[REDACTED]";
154
- }
155
- return value;
156
- }
157
- if (t === "bigint" || t === "function" || t === "symbol") {
158
- return { $unserializable: true };
159
- }
160
- // Binary views (Buffer, TypedArray, DataView, ArrayBuffer) must NOT fall
161
- // through to Object.entries(): a Buffer would serialize as numeric byte
162
- // values ({"0":115,"1":101,…} — trivially reconstructible) and the
163
- // string-only VALUE_PATTERNS net would never see the content. Degrade like
164
- // every other non-serializable leaf (golden-capture-spec.md §3 amendment).
165
- if (Buffer.isBuffer(value) || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
166
- return { $unserializable: true };
167
- }
168
- // Objects / arrays
169
- const obj = value;
170
- if (ctx.seen.has(obj))
171
- return { $unserializable: true };
172
- ctx.seen.add(obj);
173
- try {
174
- if (Array.isArray(value)) {
175
- return value.map((item, i) => redactWalk(item, `${path}.${i}`, ctx, redactAll));
176
- }
177
- if (value instanceof Date)
178
- return value.toISOString();
179
- const out = {};
180
- const overrides = TOOL_REDACT_ALL_VALUES[ctx.tool];
181
- for (const [k, v] of Object.entries(value)) {
182
- const childPath = `${path}.${k}`;
183
- if (redactAll) {
184
- // Inside a redact-all subtree: every leaf value is redacted.
185
- out[k] = redactWalk(v, childPath, ctx, true);
186
- }
187
- else if (keyIsSecret(k, ctx.extras)) {
188
- ctx.redactions.push(childPath);
189
- out[k] = "[REDACTED]";
190
- }
191
- else if (overrides?.has(k)) {
192
- out[k] = redactWalk(v, childPath, ctx, true);
193
- }
194
- else {
195
- out[k] = redactWalk(v, childPath, ctx, false);
196
- }
197
- }
198
- return out;
199
- }
200
- finally {
201
- ctx.seen.delete(obj);
202
- }
203
- }
204
- /**
205
- * Redact a value tree for a given tool, recording redacted paths into
206
- * `redactions`. Exported for direct unit testing.
207
- */
208
- export function redactForGolden(tool, value, rootPath, redactions) {
209
- const ctx = { tool, extras: extraRedactKeys(), redactions, seen: new WeakSet() };
210
- return redactWalk(value, rootPath, ctx, false);
211
- }
212
- // ---------------------------------------------------------------------------
213
- // Capture state (per process)
214
- // ---------------------------------------------------------------------------
215
- const MAX_CONSECUTIVE_WRITE_FAILURES = 5;
216
- const state = {
217
- seq: 0,
218
- writeFailures: 0,
219
- disabled: false,
220
- warned: false,
221
- };
222
- const SESSION_ID = `${process.pid}-${Math.floor(Date.now() / 1000)}`;
223
- let _version = null;
224
- /** Lazy wyrm-mcp version (same package.json walk as index.ts; cached). */
225
- function wyrmVersion() {
226
- if (_version)
227
- return _version;
228
- try {
229
- const here = dirname(fileURLToPath(import.meta.url));
230
- for (const p of [join(here, "..", "package.json"), join(here, "..", "..", "package.json")]) {
231
- if (existsSync(p)) {
232
- const v = JSON.parse(readFileSync(p, "utf-8")).version;
233
- if (typeof v === "string") {
234
- _version = v;
235
- return v;
236
- }
237
- }
238
- }
239
- }
240
- catch {
241
- /* fall through */
242
- }
243
- _version = "unknown";
244
- return _version;
245
- }
246
- /** Flag check — lazy per call (cheap string compare), default OFF. */
247
- export function isGoldenCaptureEnabled() {
248
- const v = process.env.WYRM_GOLDEN_CAPTURE;
249
- return v === "1" || v === "true";
250
- }
251
- function goldenDir() {
252
- const d = process.env.WYRM_GOLDEN_DIR?.trim();
253
- return d && d.length > 0 ? d : join(homedir(), ".wyrm", "golden");
254
- }
255
- function goldenFilePath(dir) {
256
- const now = new Date();
257
- const ymd = `${now.getUTCFullYear()}${String(now.getUTCMonth() + 1).padStart(2, "0")}${String(now.getUTCDate()).padStart(2, "0")}`;
258
- return join(dir, `golden-${ymd}-${process.pid}.jsonl`);
259
- }
260
- /**
261
- * Append one pre-serialized line. Failure feeds the circuit breaker — after
262
- * MAX_CONSECUTIVE_WRITE_FAILURES consecutive failures, capture is disabled for
263
- * the rest of the process lifetime (warned once).
264
- */
265
- function writeLine(line) {
266
- try {
267
- const dir = goldenDir();
268
- mkdirSync(dir, { recursive: true, mode: 0o700 });
269
- appendFileSync(goldenFilePath(dir), line, { mode: 0o600 });
270
- state.writeFailures = 0;
271
- }
272
- catch (err) {
273
- state.writeFailures++;
274
- if (state.writeFailures >= MAX_CONSECUTIVE_WRITE_FAILURES) {
275
- state.disabled = true;
276
- if (!state.warned) {
277
- state.warned = true;
278
- warnStderr(`golden: capture disabled for this process after ${state.writeFailures} consecutive write failures`, err);
279
- }
280
- }
281
- else {
282
- warnStderr("golden: capture dropped (write failed)", err);
283
- }
284
- }
285
- }
286
- /** Derive outcome from a response when the call site didn't pin one. */
287
- function deriveOutcome(response) {
288
- const r = response;
289
- if (r && typeof r === "object" && r.isError) {
290
- const text = Array.isArray(r.content) ? r.content[0]?.text : undefined;
291
- if (typeof text === "string" && text.startsWith("Unknown tool:"))
292
- return "unknown_tool";
293
- return "soft_error";
294
- }
295
- return "ok";
296
- }
297
- // ---------------------------------------------------------------------------
298
- // The capture entry point — called at all four response-producing sites
299
- // ---------------------------------------------------------------------------
300
- /**
301
- * Capture one CallTool round-trip as a JSONL golden record. NEVER throws,
302
- * never blocks; no-op unless WYRM_GOLDEN_CAPTURE=1 (Article VII: default OFF).
303
- */
304
- export function goldenCapture(input) {
305
- try {
306
- if (state.disabled)
307
- return;
308
- if (!isGoldenCaptureEnabled())
309
- return;
310
- const redactions = [];
311
- const args = redactForGolden(input.tool, input.args ?? {}, "request.arguments", redactions);
312
- const meta = input.meta !== undefined ? redactForGolden(input.tool, input.meta, "request._meta", redactions) : undefined;
313
- const response = redactForGolden(input.tool, input.response, "response", redactions);
314
- const record = {
315
- v: 1,
316
- ts: new Date().toISOString(),
317
- seq: ++state.seq,
318
- session: SESSION_ID,
319
- wyrm_version: wyrmVersion(),
320
- tool: input.tool,
321
- dispatch: input.dispatch,
322
- request: {
323
- name: input.tool,
324
- arguments: args,
325
- ...(meta !== undefined ? { _meta: meta } : {}),
326
- },
327
- response,
328
- outcome: input.outcome ?? deriveOutcome(input.response),
329
- cached: input.cached === true,
330
- ms: input.ms,
331
- redactions,
332
- };
333
- writeLine(JSON.stringify(record) + "\n");
334
- }
335
- catch (err) {
336
- // log-and-drop: the tool result is already on its way to the client; the
337
- // golden record is best-effort (the emitEvent contract).
338
- warnStderr("golden: capture dropped", err);
339
- }
340
- }
341
- // ---------------------------------------------------------------------------
342
- // Test hooks (additive; no production caller)
343
- // ---------------------------------------------------------------------------
344
- /** Reset breaker/sequence state between tests. */
345
- export function __resetGoldenForTests() {
346
- state.seq = 0;
347
- state.writeFailures = 0;
348
- state.disabled = false;
349
- state.warned = false;
350
- }
351
- /** Read-only view of the capture state for tests. */
352
- export function __goldenStateForTests() {
353
- return { ...state };
354
- }
355
- //# sourceMappingURL=golden.js.map
1
+ import{appendFileSync as y,mkdirSync as _,existsSync as g,readFileSync as A}from"fs";import{homedir as S}from"os";import{join as p,dirname as E}from"path";import{fileURLToPath as h}from"url";function b(e,r){try{const t=r===void 0?"":` (${r instanceof Error?r.message:String(r)})`;process.stderr.write(`[wyrm] ${e}${t}
2
+ `)}catch{}}const k=["token","secret","password","passwd","authorization","passphrase","bearer","credential","apikey","api_key","license"],D={wyrm_mcp_register:new Set(["env"])},T=[{label:"jwt",re:/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{4,}\.[A-Za-z0-9_-]*/},{label:"github-token",re:/\bgh[posu]_[A-Za-z0-9]{16,}\b/},{label:"npm-token",re:/\bnpm_[A-Za-z0-9]{16,}\b/},{label:"api-key",re:/\b[sp]k-[A-Za-z0-9_-]{16,}\b/},{label:"aws-access-key",re:/\bAKIA[0-9A-Z]{16}\b/},{label:"slack-token",re:/\bxox[baprs]-[A-Za-z0-9-]{10,}\b/},{label:"pem-private-key",re:/-----BEGIN [A-Z ]*PRIVATE KEY-----/},{label:"bearer",re:/\bBearer\s+[A-Za-z0-9._~+\/-]{16,}/}];function R(){const e=process.env.WYRM_GOLDEN_REDACT_EXTRA;return e?new Set(e.split(",").map(r=>r.trim().toLowerCase()).filter(Boolean)):new Set}function $(e,r){const t=e.toLowerCase();if(r.has(t))return!0;for(const o of k)if(t.includes(o))return!0;return!!(t!=="key"&&t.endsWith("key"))}function u(e,r,t,o){if(e==null)return e;const s=typeof e;if(s==="string"){if(o)return t.redactions.push(r),"[REDACTED]";for(const{label:a,re:m}of T)if(m.test(e))return t.redactions.push(r),`[REDACTED:${a}]`;return e}if(s==="number"||s==="boolean")return o?(t.redactions.push(r),"[REDACTED]"):e;if(s==="bigint"||s==="function"||s==="symbol")return{$unserializable:!0};if(Buffer.isBuffer(e)||ArrayBuffer.isView(e)||e instanceof ArrayBuffer)return{$unserializable:!0};const c=e;if(t.seen.has(c))return{$unserializable:!0};t.seen.add(c);try{if(Array.isArray(e))return e.map((i,f)=>u(i,`${r}.${f}`,t,o));if(e instanceof Date)return e.toISOString();const a={},m=D[t.tool];for(const[i,f]of Object.entries(e)){const l=`${r}.${i}`;o?a[i]=u(f,l,t,!0):$(i,t.extras)?(t.redactions.push(l),a[i]="[REDACTED]"):m?.has(i)?a[i]=u(f,l,t,!0):a[i]=u(f,l,t,!1)}return a}finally{t.seen.delete(c)}}function w(e,r,t,o){const s={tool:e,extras:R(),redactions:o,seen:new WeakSet};return u(r,t,s,!1)}const C=5,n={seq:0,writeFailures:0,disabled:!1,warned:!1},F=`${process.pid}-${Math.floor(Date.now()/1e3)}`;let d=null;function I(){if(d)return d;try{const e=E(h(import.meta.url));for(const r of[p(e,"..","package.json"),p(e,"..","..","package.json")])if(g(r)){const t=JSON.parse(A(r,"utf-8")).version;if(typeof t=="string")return d=t,t}}catch{}return d="unknown",d}function L(){const e=process.env.WYRM_GOLDEN_CAPTURE;return e==="1"||e==="true"}function O(){const e=process.env.WYRM_GOLDEN_DIR?.trim();return e&&e.length>0?e:p(S(),".wyrm","golden")}function z(e){const r=new Date,t=`${r.getUTCFullYear()}${String(r.getUTCMonth()+1).padStart(2,"0")}${String(r.getUTCDate()).padStart(2,"0")}`;return p(e,`golden-${t}-${process.pid}.jsonl`)}function U(e){try{const r=O();_(r,{recursive:!0,mode:448}),y(z(r),e,{mode:384}),n.writeFailures=0}catch(r){n.writeFailures++,n.writeFailures>=C?(n.disabled=!0,n.warned||(n.warned=!0,b(`golden: capture disabled for this process after ${n.writeFailures} consecutive write failures`,r))):b("golden: capture dropped (write failed)",r)}}function N(e){const r=e;if(r&&typeof r=="object"&&r.isError){const t=Array.isArray(r.content)?r.content[0]?.text:void 0;return typeof t=="string"&&t.startsWith("Unknown tool:")?"unknown_tool":"soft_error"}return"ok"}function W(e){try{if(n.disabled||!L())return;const r=[],t=w(e.tool,e.args??{},"request.arguments",r),o=e.meta!==void 0?w(e.tool,e.meta,"request._meta",r):void 0,s=w(e.tool,e.response,"response",r),c={v:1,ts:new Date().toISOString(),seq:++n.seq,session:F,wyrm_version:I(),tool:e.tool,dispatch:e.dispatch,request:{name:e.tool,arguments:t,...o!==void 0?{_meta:o}:{}},response:s,outcome:e.outcome??N(e.response),cached:e.cached===!0,ms:e.ms,redactions:r};U(JSON.stringify(c)+`
3
+ `)}catch(r){b("golden: capture dropped",r)}}function q(){n.seq=0,n.writeFailures=0,n.disabled=!1,n.warned=!1}function M(){return{...n}}export{M as __goldenStateForTests,q as __resetGoldenForTests,W as goldenCapture,L as isGoldenCaptureEnabled,w as redactForGolden};
@@ -1,165 +1,4 @@
1
- /**
2
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
3
- * @license AGPL-3.0-or-later
4
- */
5
- import { TOOL_ANNOTATIONS } from "../tool-annotations.js";
6
- export const agentToolSpecs = [
7
- {
8
- name: "wyrm_agent_init",
9
- description: "Bootstrap Wyrm's autonomous agent loop in one call. Starts the wyrm-loop daemon as a detached background process so subsequent ticks happen automatically every interval_seconds. Optionally seeds a first goal in the same call. Idempotent — if already running, returns status without spawning a second instance.",
10
- inputSchema: {
11
- type: "object",
12
- properties: {
13
- interval_seconds: { type: "number", description: "Seconds between OODA ticks (default 600 = 10 min, min 10)" },
14
- max_steps: { type: "number", description: "Max iterations per goal per tick (default 3, max 20)" },
15
- project_path: { type: "string", description: "Scope the daemon to a project root (optional)" },
16
- verbose: { type: "boolean", description: "Log every tick to ~/.wyrm/wyrm-loop.log" },
17
- seed_goal: {
18
- type: "object",
19
- description: "Optional first goal to set in the same call",
20
- properties: {
21
- title: { type: "string" },
22
- description: { type: "string" },
23
- success_criteria: { type: "string" },
24
- priority: { type: "string", enum: ["critical", "high", "medium", "low"] },
25
- deadline: { type: "string" },
26
- max_iterations: { type: "number" },
27
- },
28
- required: ["title"],
29
- },
30
- },
31
- },
32
- annotations: TOOL_ANNOTATIONS["wyrm_agent_init"],
33
- aliases: [],
34
- handler: async (args, ctx) => {
35
- const { agentDaemon, db, goals } = ctx;
36
- const a = args;
37
- const interval = Math.max(10, Math.min(a.interval_seconds ?? 600, 86400));
38
- const r = agentDaemon.start({
39
- interval_seconds: interval,
40
- max_steps: a.max_steps,
41
- project_path: a.project_path,
42
- verbose: a.verbose ?? false,
43
- });
44
- if (!r.ok) {
45
- return { content: [{ type: "text", text: `󱅝 Agent init failed: ${r.error}` }], isError: true };
46
- }
47
- let seedNote = '';
48
- if (a.seed_goal) {
49
- const proj = a.project_path ? db.getProject(a.project_path) : null;
50
- const goal = goals.set({
51
- project_id: proj?.id ?? null,
52
- title: a.seed_goal.title,
53
- description: a.seed_goal.description,
54
- success_criteria: a.seed_goal.success_criteria,
55
- deadline: a.seed_goal.deadline,
56
- priority: a.seed_goal.priority,
57
- max_iterations: a.seed_goal.max_iterations,
58
- });
59
- seedNote = `\n Seeded goal #${goal.id}: ${goal.title}`;
60
- }
61
- const status = r.status;
62
- const wasAlready = status.pid != null && status.pid !== r.pid;
63
- const text = [
64
- `󱅝 Agent ${wasAlready ? 'already running' : 'started'} — pid ${status.pid}`,
65
- ` Interval: ${interval}s · Active goals: ${status.active_goals} · Total iterations: ${status.total_iterations}`,
66
- ` Log: ${status.log_file}` + seedNote,
67
- ].join('\n');
68
- return { content: [{ type: "text", text }] };
69
- },
70
- },
71
- {
72
- name: "wyrm_agent_status",
73
- description: "Inspect the autonomous agent: is the wyrm-loop daemon running, what was the last action, how many active goals + total iterations. Use to confirm bootstrap worked.",
74
- inputSchema: {
75
- type: "object",
76
- properties: {
77
- include_log: { type: "boolean", description: "Include last ~40 lines of the daemon log" },
78
- },
79
- },
80
- annotations: TOOL_ANNOTATIONS["wyrm_agent_status"],
81
- aliases: [],
82
- handler: async (args, ctx) => {
83
- const { agentDaemon, goals } = ctx;
84
- const a = args;
85
- const status = agentDaemon.status();
86
- const lines = [];
87
- if (status.running) {
88
- lines.push(`󱅝 Agent RUNNING — pid ${status.pid}${status.started_at ? ` (since ${status.started_at})` : ''}`);
89
- if (status.uptime_seconds != null) {
90
- const m = Math.floor(status.uptime_seconds / 60);
91
- const s = status.uptime_seconds % 60;
92
- lines.push(` Uptime: ${m}m ${s}s`);
93
- }
94
- }
95
- else {
96
- lines.push(`󱅝 Agent NOT RUNNING. Call wyrm_agent_init to start it.`);
97
- }
98
- lines.push(` Active goals: ${status.active_goals} · Total iterations: ${status.total_iterations}`);
99
- if (status.last_action) {
100
- lines.push(` Last action (${status.last_action.ran_at}): ${status.last_action.summary} [${status.last_action.result_status ?? '?'}]`);
101
- }
102
- if (a.include_log) {
103
- lines.push('');
104
- lines.push('=== Recent log ===');
105
- lines.push(agentDaemon.recentLog(40));
106
- }
107
- return { content: [{ type: "text", text: lines.join('\n') }] };
108
- },
109
- },
110
- {
111
- name: "wyrm_agent_stop",
112
- description: "Stop the autonomous agent daemon (SIGTERM with grace, then SIGKILL). Goals remain in DB and can be resumed by calling wyrm_agent_init again.",
113
- inputSchema: {
114
- type: "object",
115
- properties: {
116
- grace_ms: { type: "number", description: "Wait time before SIGKILL (default 3000, max 30000)" },
117
- },
118
- },
119
- annotations: TOOL_ANNOTATIONS["wyrm_agent_stop"],
120
- aliases: [],
121
- handler: async (args, ctx) => {
122
- const { agentDaemon } = ctx;
123
- const a = args;
124
- const r = await agentDaemon.stop({ grace_ms: a.grace_ms });
125
- if (!r.ok) {
126
- return { content: [{ type: "text", text: `󱅝 Stop failed: ${r.error}` }], isError: true };
127
- }
128
- const text = r.was_running
129
- ? `󱅝 Agent stopped (was pid ${r.pid}). Goals remain in DB — wyrm_agent_init resumes.`
130
- : `󱅝 Agent was not running. (No-op.)`;
131
- return { content: [{ type: "text", text }] };
132
- },
133
- },
134
- {
135
- name: "wyrm_agent_restart",
136
- description: "Stop the daemon and start it again with optional new settings. Useful when changing interval_seconds or max_steps without manually stopping first.",
137
- inputSchema: {
138
- type: "object",
139
- properties: {
140
- interval_seconds: { type: "number" },
141
- max_steps: { type: "number" },
142
- project_path: { type: "string" },
143
- verbose: { type: "boolean" },
144
- },
145
- },
146
- annotations: TOOL_ANNOTATIONS["wyrm_agent_restart"],
147
- aliases: [],
148
- handler: async (args, ctx) => {
149
- const { agentDaemon, goals } = ctx;
150
- const a = args;
151
- const r = await agentDaemon.restart({
152
- interval_seconds: a.interval_seconds,
153
- max_steps: a.max_steps,
154
- project_path: a.project_path,
155
- verbose: a.verbose,
156
- });
157
- if (!r.ok) {
158
- return { content: [{ type: "text", text: `󱅝 Restart failed: ${r.error}` }], isError: true };
159
- }
160
- const s = r.status;
161
- return { content: [{ type: "text", text: `󱅝 Agent restarted — pid ${s.pid}. Active goals: ${s.active_goals}.` }] };
162
- },
163
- },
164
- ];
165
- //# sourceMappingURL=agent.js.map
1
+ import{TOOL_ANNOTATIONS as l}from"../tool-annotations.js";const y=[{name:"wyrm_agent_init",description:"Bootstrap Wyrm's autonomous agent loop in one call. Starts the wyrm-loop daemon as a detached background process so subsequent ticks happen automatically every interval_seconds. Optionally seeds a first goal in the same call. Idempotent \u2014 if already running, returns status without spawning a second instance.",inputSchema:{type:"object",properties:{interval_seconds:{type:"number",description:"Seconds between OODA ticks (default 600 = 10 min, min 10)"},max_steps:{type:"number",description:"Max iterations per goal per tick (default 3, max 20)"},project_path:{type:"string",description:"Scope the daemon to a project root (optional)"},verbose:{type:"boolean",description:"Log every tick to ~/.wyrm/wyrm-loop.log"},seed_goal:{type:"object",description:"Optional first goal to set in the same call",properties:{title:{type:"string"},description:{type:"string"},success_criteria:{type:"string"},priority:{type:"string",enum:["critical","high","medium","low"]},deadline:{type:"string"},max_iterations:{type:"number"}},required:["title"]}}},annotations:l.wyrm_agent_init,aliases:[],handler:async(s,o)=>{const{agentDaemon:a,db:p,goals:n}=o,t=s,e=Math.max(10,Math.min(t.interval_seconds??600,86400)),i=a.start({interval_seconds:e,max_steps:t.max_steps,project_path:t.project_path,verbose:t.verbose??!1});if(!i.ok)return{content:[{type:"text",text:`\u{F115D} Agent init failed: ${i.error}`}],isError:!0};let c="";if(t.seed_goal){const m=t.project_path?p.getProject(t.project_path):null,d=n.set({project_id:m?.id??null,title:t.seed_goal.title,description:t.seed_goal.description,success_criteria:t.seed_goal.success_criteria,deadline:t.seed_goal.deadline,priority:t.seed_goal.priority,max_iterations:t.seed_goal.max_iterations});c=`
2
+ Seeded goal #${d.id}: ${d.title}`}const r=i.status;return{content:[{type:"text",text:[`\u{F115D} Agent ${r.pid!=null&&r.pid!==i.pid?"already running":"started"} \u2014 pid ${r.pid}`,` Interval: ${e}s \xB7 Active goals: ${r.active_goals} \xB7 Total iterations: ${r.total_iterations}`,` Log: ${r.log_file}`+c].join(`
3
+ `)}]}}},{name:"wyrm_agent_status",description:"Inspect the autonomous agent: is the wyrm-loop daemon running, what was the last action, how many active goals + total iterations. Use to confirm bootstrap worked.",inputSchema:{type:"object",properties:{include_log:{type:"boolean",description:"Include last ~40 lines of the daemon log"}}},annotations:l.wyrm_agent_status,aliases:[],handler:async(s,o)=>{const{agentDaemon:a,goals:p}=o,n=s,t=a.status(),e=[];if(t.running){if(e.push(`\u{F115D} Agent RUNNING \u2014 pid ${t.pid}${t.started_at?` (since ${t.started_at})`:""}`),t.uptime_seconds!=null){const i=Math.floor(t.uptime_seconds/60),c=t.uptime_seconds%60;e.push(` Uptime: ${i}m ${c}s`)}}else e.push("\u{F115D} Agent NOT RUNNING. Call wyrm_agent_init to start it.");return e.push(` Active goals: ${t.active_goals} \xB7 Total iterations: ${t.total_iterations}`),t.last_action&&e.push(` Last action (${t.last_action.ran_at}): ${t.last_action.summary} [${t.last_action.result_status??"?"}]`),n.include_log&&(e.push(""),e.push("=== Recent log ==="),e.push(a.recentLog(40))),{content:[{type:"text",text:e.join(`
4
+ `)}]}}},{name:"wyrm_agent_stop",description:"Stop the autonomous agent daemon (SIGTERM with grace, then SIGKILL). Goals remain in DB and can be resumed by calling wyrm_agent_init again.",inputSchema:{type:"object",properties:{grace_ms:{type:"number",description:"Wait time before SIGKILL (default 3000, max 30000)"}}},annotations:l.wyrm_agent_stop,aliases:[],handler:async(s,o)=>{const{agentDaemon:a}=o,p=s,n=await a.stop({grace_ms:p.grace_ms});return n.ok?{content:[{type:"text",text:n.was_running?`\u{F115D} Agent stopped (was pid ${n.pid}). Goals remain in DB \u2014 wyrm_agent_init resumes.`:"\u{F115D} Agent was not running. (No-op.)"}]}:{content:[{type:"text",text:`\u{F115D} Stop failed: ${n.error}`}],isError:!0}}},{name:"wyrm_agent_restart",description:"Stop the daemon and start it again with optional new settings. Useful when changing interval_seconds or max_steps without manually stopping first.",inputSchema:{type:"object",properties:{interval_seconds:{type:"number"},max_steps:{type:"number"},project_path:{type:"string"},verbose:{type:"boolean"}}},annotations:l.wyrm_agent_restart,aliases:[],handler:async(s,o)=>{const{agentDaemon:a,goals:p}=o,n=s,t=await a.restart({interval_seconds:n.interval_seconds,max_steps:n.max_steps,project_path:n.project_path,verbose:n.verbose});if(!t.ok)return{content:[{type:"text",text:`\u{F115D} Restart failed: ${t.error}`}],isError:!0};const e=t.status;return{content:[{type:"text",text:`\u{F115D} Agent restarted \u2014 pid ${e.pid}. Active goals: ${e.active_goals}.`}]}}}];export{y as agentToolSpecs};
@@ -1,129 +1 @@
1
- /**
2
- * v7 F3 (T021) — hand-written argument adapters for the alias spine.
3
- *
4
- * The spine itself (src/handlers/aliases.ts) is GENERATED from the live
5
- * ListTools surface by scripts/gen-alias-spine.mjs; this module is the one
6
- * hand-authored input it consumes: per-alias ROUTE OVERRIDES that map a 6.x
7
- * name onto a different (surviving) tool with an argument adapter.
8
- *
9
- * Adapters TRANSLATE arguments — they never reimplement handler behavior
10
- * (spec FR-4: "aliases route to the SAME handler code paths with argument
11
- * adapters — never reimplementations"). Every override is double-verified:
12
- * - tests/alias-spine.test.ts replays adapter output against the TARGET's
13
- * advertised inputSchema (the original handler's declared expectations);
14
- * - tests/golden-replay.test.ts replays the alias's golden fixtures BOTH
15
- * ways on the live wire (direct name vs adapted route) and asserts
16
- * equivalent results.
17
- *
18
- * Default route for every alias NOT listed here is IDENTITY (the alias's own
19
- * 6.x dispatcher path) until T022 flips routes to the survivor shims —
20
- * aliases must be provably equivalent BEFORE anything is hidden.
21
- *
22
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
23
- * @license AGPL-3.0-or-later
24
- */
25
- import { SHIM_ROUTES } from './shims.js';
26
- /**
27
- * T021 buddy fold — the companion params wyrm_buddy contributed to the
28
- * well-known `buddy` tool as ADDITIVE optional args. Their presence is what
29
- * switches `buddy` from the Buddy Protocol v1.0 peer reply onto the SAME
30
- * companion code path wyrm_buddy runs (runCompanionBuddy in index.ts).
31
- * `size` is deliberately NOT a discriminator: the peer protocol already
32
- * carries it, and a bare peer call must stay protocol-identical (spec FR-4:
33
- * "protocol behavior unchanged when absent").
34
- */
35
- export const COMPANION_BUDDY_PARAMS = [
36
- 'project_path',
37
- 'persona',
38
- 'persona_name',
39
- 'mood',
40
- 'federate',
41
- ];
42
- /** True iff any companion-only param is present — the buddy-fold mode switch. */
43
- export function isCompanionBuddyCall(args) {
44
- return COMPANION_BUDDY_PARAMS.some((k) => args[k] !== undefined);
45
- }
46
- /**
47
- * wyrm_buddy → buddy argument adapter. Param names are identical on the
48
- * grown buddy schema, so the only translation is injecting the resolved
49
- * project_path when absent — exactly the resolution the original handler
50
- * performs first (`const cwd = bdPath ?? process.cwd()`), hoisted into the
51
- * adapter so a BARE wyrm_buddy call still discriminates as companion mode.
52
- * Same process, same value — equivalence holds byte-for-byte.
53
- */
54
- export function adaptWyrmBuddyToBuddy(args) {
55
- const out = { ...args };
56
- if (out.project_path === undefined)
57
- out.project_path = process.cwd();
58
- return out;
59
- }
60
- /**
61
- * v7 F3 (T022) — the noun-shim absorptions, INVERTED from the same
62
- * SHIM_ROUTES table resolveShimCall() dispatches with (src/handlers/shims.ts).
63
- * One source of truth, two directions:
64
- *
65
- * alias call: wyrm_quest_add(args)
66
- * → spine adapt: wyrm_quest({ ...args, action: 'add' })
67
- * → resolveShimCall: wyrm_quest_add(args) // discriminator stripped
68
- *
69
- * i.e. every generated override roundtrips to the ORIGINAL dispatcher case
70
- * with the ORIGINAL args by construction — the same handler code path, never
71
- * a reimplementation (locked exhaustively by tests/alias-spine.test.ts, which
72
- * asserts the roundtrip identity for every override on its fixture args).
73
- *
74
- * The discriminator is spread LAST so it is authoritative; no absorbed 6.x
75
- * tool declares its own `action`/`mode`/`source` param (audited against the
76
- * live schemas at T022 — wyrm_sync_resolve's own `mode` rides through the
77
- * `action`-discriminated replication route untouched).
78
- */
79
- function invertShimRoutes() {
80
- const out = {};
81
- const claim = (aliasName, override) => {
82
- if (out[aliasName] !== undefined) {
83
- // fail LOUD at module load — a double absorption would make the
84
- // disposition table ambiguous and the roundtrip lock meaningless
85
- throw new Error(`alias-adapters: ${aliasName} absorbed by two shims (${out[aliasName].target} and ${override.target})`);
86
- }
87
- out[aliasName] = override;
88
- };
89
- for (const [shimName, entry] of Object.entries(SHIM_ROUTES)) {
90
- for (const [value, route] of Object.entries(entry.routes)) {
91
- if (typeof route === 'string') {
92
- if (route === shimName)
93
- continue; // self-route (capture mode=classify) — not an absorption
94
- claim(route, {
95
- target: shimName,
96
- adapt: (args) => ({ ...args, [entry.discriminator]: value }),
97
- note: `T022: absorbed by ${shimName} ${entry.discriminator}=${value}; resolveShimCall strips the discriminator back onto the original ${route} dispatcher case — same code path by construction (roundtrip-locked).`,
98
- });
99
- }
100
- else {
101
- for (const [subValue, target] of Object.entries(route.routes)) {
102
- claim(target, {
103
- target: shimName,
104
- adapt: (args) => ({ ...args, [entry.discriminator]: value, [route.key]: subValue }),
105
- note: `T022: absorbed by ${shimName} ${entry.discriminator}=${value} ${route.key}=${subValue}; resolveShimCall strips both back onto the original ${target} dispatcher case — same code path by construction (roundtrip-locked).`,
106
- });
107
- }
108
- }
109
- }
110
- }
111
- return out;
112
- }
113
- /**
114
- * Route overrides keyed by 6.x alias name: the T021 buddy fold plus the T022
115
- * shim absorptions (generated from SHIM_ROUTES — see invertShimRoutes above).
116
- * Every key MUST be in the generated alias keyset and every target MUST be a
117
- * survivor — locked by tests/alias-spine.test.ts.
118
- */
119
- export const ALIAS_ROUTE_OVERRIDES = {
120
- ...invertShimRoutes(),
121
- wyrm_buddy: {
122
- target: 'buddy',
123
- adapt: adaptWyrmBuddyToBuddy,
124
- note: 'T021 buddy fold: companion params (persona/mood/size/federation) merged into the ' +
125
- 'well-known buddy tool as additive optional args; both names run runCompanionBuddy ' +
126
- '(index.ts) — one code path, not a duplicate.',
127
- },
128
- };
129
- //# sourceMappingURL=alias-adapters.js.map
1
+ import{SHIM_ROUTES as c}from"./shims.js";const p=["project_path","persona","persona_name","mood","federate"];function f(o){return p.some(e=>o[e]!==void 0)}function u(o){const e={...o};return e.project_path===void 0&&(e.project_path=process.cwd()),e}function m(){const o={},e=(t,r)=>{if(o[t]!==void 0)throw new Error(`alias-adapters: ${t} absorbed by two shims (${o[t].target} and ${r.target})`);o[t]=r};for(const[t,r]of Object.entries(c))for(const[a,n]of Object.entries(r.routes))if(typeof n=="string"){if(n===t)continue;e(n,{target:t,adapt:i=>({...i,[r.discriminator]:a}),note:`T022: absorbed by ${t} ${r.discriminator}=${a}; resolveShimCall strips the discriminator back onto the original ${n} dispatcher case \u2014 same code path by construction (roundtrip-locked).`})}else for(const[i,d]of Object.entries(n.routes))e(d,{target:t,adapt:s=>({...s,[r.discriminator]:a,[n.key]:i}),note:`T022: absorbed by ${t} ${r.discriminator}=${a} ${n.key}=${i}; resolveShimCall strips both back onto the original ${d} dispatcher case \u2014 same code path by construction (roundtrip-locked).`});return o}const h={...m(),wyrm_buddy:{target:"buddy",adapt:u,note:"T021 buddy fold: companion params (persona/mood/size/federation) merged into the well-known buddy tool as additive optional args; both names run runCompanionBuddy (index.ts) \u2014 one code path, not a duplicate."}};export{h as ALIAS_ROUTE_OVERRIDES,p as COMPANION_BUDDY_PARAMS,u as adaptWyrmBuddyToBuddy,f as isCompanionBuddyCall};