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.
Files changed (156) hide show
  1. package/LICENSE +26 -667
  2. package/NOTICE +14 -33
  3. package/dist/activation.d.ts.map +1 -1
  4. package/dist/activation.js +1 -44
  5. package/dist/activation.js.map +1 -1
  6. package/dist/agent-daemon.js +4 -281
  7. package/dist/agent-loop.js +7 -332
  8. package/dist/analytics.js +13 -236
  9. package/dist/attribution.js +1 -49
  10. package/dist/audit.js +2 -457
  11. package/dist/auto-capture.js +3 -138
  12. package/dist/auto-orchestrator.js +1 -325
  13. package/dist/autoconfig.js +39 -840
  14. package/dist/buddy-runner.js +1 -109
  15. package/dist/buddy.js +14 -564
  16. package/dist/build-flags.js +1 -17
  17. package/dist/capabilities.js +3 -183
  18. package/dist/capture.js +1 -56
  19. package/dist/causality.js +6 -107
  20. package/dist/cli.js +20 -281
  21. package/dist/cloud/cli.js +5 -541
  22. package/dist/cloud/client.js +1 -221
  23. package/dist/cloud/crypto.js +1 -85
  24. package/dist/cloud/machine-id.js +2 -113
  25. package/dist/cloud/recovery.js +1 -60
  26. package/dist/cloud/sync-engine.js +7 -543
  27. package/dist/cloud-backup.js +5 -579
  28. package/dist/cloud-profile.js +1 -138
  29. package/dist/cloud-sync-entrypoint.js +1 -47
  30. package/dist/cloud-sync.js +2 -309
  31. package/dist/constellation.js +12 -168
  32. package/dist/context-build-budgeted.js +4 -144
  33. package/dist/context-ranking.js +1 -69
  34. package/dist/crypto.js +1 -179
  35. package/dist/daemon-write-endpoint.js +1 -290
  36. package/dist/daemon-writer.js +2 -406
  37. package/dist/database.js +43 -1110
  38. package/dist/deprecations.js +2 -162
  39. package/dist/design.js +13 -141
  40. package/dist/event-replication.js +1 -112
  41. package/dist/events-sse.js +7 -43
  42. package/dist/events.js +6 -238
  43. package/dist/failure-patterns.js +42 -659
  44. package/dist/federation.js +12 -236
  45. package/dist/goals.js +13 -101
  46. package/dist/golden.js +3 -355
  47. package/dist/handlers/agent.js +4 -165
  48. package/dist/handlers/alias-adapters.js +1 -129
  49. package/dist/handlers/aliases.js +1 -171
  50. package/dist/handlers/audit.js +1 -87
  51. package/dist/handlers/boundary.js +1 -221
  52. package/dist/handlers/capture.js +73 -1109
  53. package/dist/handlers/causality.js +7 -114
  54. package/dist/handlers/cloud.js +85 -382
  55. package/dist/handlers/companion.js +28 -459
  56. package/dist/handlers/datalake.js +7 -187
  57. package/dist/handlers/dispatch-context.js +0 -22
  58. package/dist/handlers/entity.js +25 -256
  59. package/dist/handlers/events.js +16 -335
  60. package/dist/handlers/failure.js +13 -340
  61. package/dist/handlers/goals.js +4 -296
  62. package/dist/handlers/intelligence.js +126 -674
  63. package/dist/handlers/invoicing.js +1 -70
  64. package/dist/handlers/mcpclient.js +6 -137
  65. package/dist/handlers/orchestration.js +40 -125
  66. package/dist/handlers/output-schemas.js +1 -24
  67. package/dist/handlers/presence.js +3 -99
  68. package/dist/handlers/project.js +28 -182
  69. package/dist/handlers/prompts.js +6 -157
  70. package/dist/handlers/quest.js +4 -224
  71. package/dist/handlers/recall.js +11 -218
  72. package/dist/handlers/registry.js +1 -167
  73. package/dist/handlers/resources.js +1 -288
  74. package/dist/handlers/review.js +11 -74
  75. package/dist/handlers/run.js +17 -487
  76. package/dist/handlers/search.js +15 -326
  77. package/dist/handlers/session.js +28 -615
  78. package/dist/handlers/share.js +8 -184
  79. package/dist/handlers/shims.js +1 -464
  80. package/dist/handlers/skill.js +67 -449
  81. package/dist/handlers/survivors.js +1 -120
  82. package/dist/handlers/symbols.js +8 -109
  83. package/dist/handlers/syncops.js +4 -302
  84. package/dist/handlers/types.js +1 -27
  85. package/dist/harvest.js +5 -191
  86. package/dist/hours.js +7 -156
  87. package/dist/http-auth.js +3 -321
  88. package/dist/http-fast.js +21 -1137
  89. package/dist/icons.js +1 -47
  90. package/dist/index.js +2 -924
  91. package/dist/indexer.js +4 -145
  92. package/dist/intelligence.js +31 -261
  93. package/dist/internal-dispatch.js +3 -212
  94. package/dist/keyset.js +1 -110
  95. package/dist/knowledge-graph.js +12 -176
  96. package/dist/license.d.ts +11 -0
  97. package/dist/license.d.ts.map +1 -1
  98. package/dist/license.js +2 -414
  99. package/dist/license.js.map +1 -1
  100. package/dist/logger.js +2 -199
  101. package/dist/maintenance.js +2 -148
  102. package/dist/mcp-client.js +6 -262
  103. package/dist/memory-artifacts.js +30 -449
  104. package/dist/migrate-prompt.js +2 -124
  105. package/dist/migrations.js +40 -655
  106. package/dist/performance.js +1 -228
  107. package/dist/presence.js +11 -140
  108. package/dist/priority-embed.js +5 -164
  109. package/dist/providers/embedding-provider.js +1 -196
  110. package/dist/readonly-gate.js +1 -29
  111. package/dist/rehydration.js +9 -157
  112. package/dist/reindex.js +1 -88
  113. package/dist/render-target.js +21 -514
  114. package/dist/render.js +4 -280
  115. package/dist/repl-guard.js +1 -173
  116. package/dist/replication-daemon-entrypoint.js +1 -31
  117. package/dist/replication-daemon.js +2 -262
  118. package/dist/resilience.js +1 -591
  119. package/dist/reverse-bridge.js +5 -360
  120. package/dist/security.js +1 -244
  121. package/dist/session-seen.js +3 -51
  122. package/dist/setup.js +1 -260
  123. package/dist/skill-author.js +5 -168
  124. package/dist/spec-kit.js +1 -191
  125. package/dist/sqlite-busy.js +1 -154
  126. package/dist/statusline.js +11 -315
  127. package/dist/sub-agent.js +13 -262
  128. package/dist/summarizer.js +13 -139
  129. package/dist/symbols.js +7 -283
  130. package/dist/sync.js +5 -359
  131. package/dist/tasks-dispatch.js +1 -84
  132. package/dist/tasks.js +1 -282
  133. package/dist/token-budget.js +1 -143
  134. package/dist/tool-analytics.js +7 -129
  135. package/dist/tool-annotations.js +1 -365
  136. package/dist/tool-manifest-v2.json +1 -1
  137. package/dist/tool-manifest.json +1 -1
  138. package/dist/tool-profiles.js +1 -75
  139. package/dist/trace-harvest.js +6 -244
  140. package/dist/types.js +1 -30
  141. package/dist/ui-dashboard.js +41 -50
  142. package/dist/ulid.js +1 -81
  143. package/dist/validate.js +1 -129
  144. package/dist/vault.js +1 -534
  145. package/dist/vectors.js +3 -184
  146. package/dist/version-check.js +4 -136
  147. package/dist/visibility.js +19 -155
  148. package/dist/wyrm-cli.js +98 -2451
  149. package/dist/wyrm-cli.js.map +1 -1
  150. package/dist/wyrm-guard.js +14 -424
  151. package/dist/wyrm-loop.js +3 -150
  152. package/dist/wyrm-manifest.json +1 -1
  153. package/dist/wyrm-statusline-daemon.js +1 -11
  154. package/dist/wyrm-statusline.js +4 -56
  155. package/dist/wyrm-ui.js +9 -77
  156. 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};