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
@@ -1,340 +1,13 @@
1
- /**
2
- * Failure domain — ToolSpec contract v2 (v7 F3 T026, hot-path extraction).
3
- *
4
- * wyrm_failure_check / wyrm_failure_record / wyrm_failure_list /
5
- * wyrm_failure_resolve, moved VERBATIM from the index.ts dispatch switch +
6
- * buildAllTools(). The T012 daemonOr write seam, the T014 verdict dual-emit,
7
- * the T015 ambient-gated promote flag (Article VII: unauthorized promotion is
8
- * reported, never silent) and the T017 recordBlock ledger all moved with
9
- * their handlers unchanged.
10
- *
11
- * FAILURE_CHECK_OUTPUT_SCHEMA moved here from handlers/output-schemas.ts per
12
- * the T018 contract ("when T026 extracts the owning domain, the schema moves
13
- * onto the domain's ToolSpec and the entry there is deleted"). Its field
14
- * descriptions were dropped in the same commit: the schema is advertised on
15
- * the frozen default surface and the ≤8K-token pin (spec §7 criterion 1) now
16
- * also funds the six NEW hot-path outputSchemas — structure is the contract,
17
- * prose was advisory (the T022/T025 schema-chars-fund-the-surface trade).
18
- *
19
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
20
- * @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
21
- */
22
- import { TOOL_ANNOTATIONS } from '../tool-annotations.js';
23
- import { renderResult, withGlyph } from '../render.js';
24
- import { asEnum } from '../validate.js';
25
- import { daemonOr } from '../daemon-writer.js';
26
- /** Canonical wyrm_failure_check verdict shape (FailureCheckVerdict, T014). */
27
- export const FAILURE_CHECK_OUTPUT_SCHEMA = {
28
- type: "object",
29
- properties: {
30
- blocked: { type: "boolean" },
31
- matches: {
32
- type: "array",
33
- items: {
34
- type: "object",
35
- properties: {
36
- id: { type: "integer" },
37
- pattern: { type: "string" },
38
- scope: { type: "string" },
39
- quarantine_scope: { type: "string" },
40
- target: { type: "string" },
41
- description: { type: "string" },
42
- why_failed: { type: ["string", "null"] },
43
- severity: { type: "string" },
44
- occurrences: { type: "integer" },
45
- last_seen: { type: "string" },
46
- recorded_by_agent: { type: "string" },
47
- run_id: { type: ["string", "null"] },
48
- match: { type: "string", enum: ["exact", "fuzzy", "target"] },
49
- confidence: { type: "number", minimum: 0, maximum: 1 },
50
- },
51
- required: [
52
- "id", "pattern", "scope", "quarantine_scope", "target", "description",
53
- "why_failed", "severity", "occurrences", "last_seen",
54
- "recorded_by_agent", "run_id", "match", "confidence",
55
- ],
56
- },
57
- },
58
- recorded_by_agent: { type: ["string", "null"] },
59
- run_id: { type: ["string", "null"] },
60
- confidence: { type: "number", minimum: 0, maximum: 1 },
61
- },
62
- required: ["blocked", "matches", "recorded_by_agent", "run_id", "confidence"],
63
- };
64
- /** Structured outcome of a promote flag (failure_record / failure_resolve). */
65
- const PROMOTE_OUTCOME_SCHEMA = {
66
- type: ["object", "null"],
67
- properties: {
68
- requested: { type: "string" },
69
- authorized: { type: "boolean" },
70
- changed: { type: "boolean" },
71
- // T027 budget trim: quarantine_scope still rides the body undeclared.
72
- },
73
- required: ["requested", "authorized", "changed"],
74
- };
75
- /** The unauthorized-promotion note (Article VII: reported, never silent). */
76
- function promoteNoteFor(p, quarantineScope) {
77
- if (!p)
78
- return '';
79
- if (!p.authorized) {
80
- return ` - promote:'${p.requested}' IGNORED -- caller carries no explicit identity (pass actor/run_id, _meta['wyrm/actor'], or WYRM_AGENT_ID/WYRM_RUN_ID)`;
81
- }
82
- if (!p.changed)
83
- return ` - promote:'${p.requested}' was a no-op (already ${quarantineScope}-scoped)`;
84
- return '';
85
- }
86
- export const failureToolSpecs = [
87
- {
88
- name: "wyrm_failure_record",
89
- description: "Use when an approach failed or something broke - log the dead end so nobody tries it again. Identical (scope, target, description) coalesces with occurrences++; when the root cause is fixed, stop flagging it via wyrm_failure_resolve. Run-scoped failures quarantine until confirmed.",
90
- inputSchema: {
91
- type: "object",
92
- properties: {
93
- // v7 F3 (T026): property prose compressed to fund the hot-path
94
- // outputSchemas under the 8K default-surface pin (T022/T025 trade).
95
- projectPath: { type: "string", description: "Global if omitted" },
96
- scope: { type: "string", enum: ["file", "symbol", "command", "prompt", "edit"] },
97
- target: { type: "string", description: "File, symbol, command, or prompt" },
98
- description: { type: "string", description: "What was tried" },
99
- why_failed: { type: "string", description: "Diagnosis if known" },
100
- severity: { type: "string", enum: ["low", "medium", "high", "critical"] },
101
- promote: { type: "string", enum: ["project", "global"], description: "Widen the tier (explicitly attributed callers only)" },
102
- },
103
- required: ["scope", "target", "description"],
104
- },
105
- outputSchema: {
106
- type: "object",
107
- properties: {
108
- id: { type: "integer" },
109
- occurrences: { type: "integer" },
110
- scope: { type: "string" },
111
- target: { type: "string" },
112
- quarantine_scope: { type: "string" },
113
- run_id: { type: ["string", "null"] },
114
- promote: PROMOTE_OUTCOME_SCHEMA,
115
- },
116
- required: ["id", "occurrences", "scope", "target", "quarantine_scope", "run_id", "promote"],
117
- },
118
- annotations: TOOL_ANNOTATIONS.wyrm_failure_record,
119
- aliases: [],
120
- handler: async (args, { store, failures }) => {
121
- const { projectPath, scope, target, description, why_failed, severity, promote } = args;
122
- // Closed enum, mirrors the failure_patterns.severity schema CHECK:
123
- // boundary-enforced (the MCP SDK treats inputSchema as advisory) so a
124
- // one-token model typo ('normal', 'sev1') is a clean structured
125
- // client error here — never a daemon-side SQLITE_CONSTRAINT round
126
- // trip on the forwarded write.
127
- const safeSeverity = asEnum('severity', severity, ['low', 'medium', 'high', 'critical']);
128
- const project = projectPath ? store.getProject(projectPath) : null;
129
- // v7 F2 (T012): canonical write seam — failure_record (project_id may
130
- // legitimately be null: global cross-project failures).
131
- let rec = await daemonOr('failure_record', project?.id ?? null, { scope, target, description, why_failed, severity: safeSeverity }, () => failures.record({
132
- project_id: project?.id ?? null,
133
- scope, target, description, why_failed, severity: safeSeverity,
134
- }));
135
- // v7 F2 (T015): orchestrator promote flag. Boundary-validated to the
136
- // closed enum and applied OUTSIDE the daemon hop on purpose — the
137
- // authority decision must read THIS caller's envelope, not the
138
- // daemon's. promote() is ambient-gated (Article VII): an unattributed
139
- // caller's flag is reported as ignored, never honored and NEVER
140
- // silent.
141
- let promoteOutcome = null;
142
- if (promote === 'project' || promote === 'global') {
143
- const p = failures.promote(rec.id, promote);
144
- if (p.authorized)
145
- rec = p.row ?? rec;
146
- promoteOutcome = {
147
- requested: promote, authorized: p.authorized, changed: p.changed,
148
- quarantine_scope: p.row?.quarantine_scope ?? rec.quarantine_scope ?? null,
149
- };
150
- }
151
- const body = {
152
- id: rec.id,
153
- occurrences: rec.occurrences,
154
- scope,
155
- target,
156
- // v7 F2 (T014): surface the run-tag. record() defaults quarantine to
157
- // 'run' when the envelope carries a run_id (same-run siblings see it
158
- // instantly; everyone else after T015 promotion), else project/global.
159
- quarantine_scope: rec.quarantine_scope,
160
- run_id: rec.run_id ?? null,
161
- promote: promoteOutcome,
162
- };
163
- return renderResult(body, (b, g) => {
164
- const tag = b.run_id
165
- ? ` - ${b.quarantine_scope}-scoped (run ${b.run_id})`
166
- : ` - ${b.quarantine_scope}-scoped`;
167
- return withGlyph(g.brand, `Failure #${b.id} recorded (x${b.occurrences}) -- ${b.scope}:${b.target}${tag}` +
168
- promoteNoteFor(b.promote, b.quarantine_scope));
169
- });
170
- },
171
- },
172
- {
173
- name: "wyrm_failure_check",
174
- description: "Use before proposing or executing any fix, command, or approach - did this fail before? Is it a known landmine? Counter-pattern memory: returns unresolved matching failures (empty = safe to proceed); show the mistakes already made on a project with wyrm_failure_list. Subagents: check before retrying anything flagged.",
175
- inputSchema: {
176
- type: "object",
177
- properties: {
178
- projectPath: { type: "string" },
179
- scope: { type: "string", enum: ["file", "symbol", "command", "prompt", "edit"] },
180
- target: { type: "string" },
181
- description: { type: "string" },
182
- run_scope: { type: "string", enum: ["run", "project", "global"], description: "Quarantine tier filter (run = same-run only)" },
183
- },
184
- required: ["scope", "target", "description"],
185
- },
186
- outputSchema: FAILURE_CHECK_OUTPUT_SCHEMA,
187
- annotations: TOOL_ANNOTATIONS.wyrm_failure_check,
188
- aliases: [],
189
- handler: async (args, { store, raw, failures }) => {
190
- const { projectPath, scope, target, description, run_scope } = args;
191
- const project = projectPath ? store.getProject(projectPath) : null;
192
- // v7 F2 (T014): the structured verdict is the canonical shape; the 6.x
193
- // prose is DERIVED from the same verdict by the T019 renderer (drift
194
- // impossible by construction). Boundary-validate run_scope to the
195
- // closed enum — anything else means 'any'.
196
- const runScope = run_scope === 'run' || run_scope === 'project' || run_scope === 'global'
197
- ? run_scope : 'any';
198
- const verdict = failures.checkVerdict(scope, target, description, project?.id ?? null, { runScope });
199
- if (verdict.blocked) {
200
- // v7 F2 (T017): count the prevented repeat — one blocked verdict files
201
- // ONE failure_blocks row attributed to the CHECKING agent/run (ambient
202
- // envelope), feeding wyrm_stats view=failures. recordBlock is
203
- // failure-isolated inside (never throws): a read tool must never fail
204
- // because analytics could not be written.
205
- failures.recordBlock(verdict, project?.id ?? null);
206
- // Spec 018: log blocked-retry savings. Each blocked retry saves
207
- // ~1500 tokens of failed exploration (conservative estimate).
208
- try {
209
- const { logSavings } = await import('../statusline.js');
210
- const rawDb = raw();
211
- const lastSession = project ? rawDb.prepare(`SELECT id FROM sessions WHERE project_id = ? ORDER BY created_at DESC LIMIT 1`).get(project.id) : undefined;
212
- logSavings(rawDb, 'wyrm_failure_check', 'blocked_retry', 1500 * verdict.matches.length, lastSession?.id);
213
- }
214
- catch { /* best-effort */ }
215
- }
216
- return renderResult(verdict, (b, g) => {
217
- if (!b.blocked)
218
- return withGlyph(g.ok, 'No matching failures -- safe to proceed.');
219
- const list = b.matches.map(m => `${withGlyph(g.fail, `#${m.id} ${m.scope}:${m.target}`)} -- tried ${m.occurrences}x (${m.severity}); last ${m.last_seen}\n ${m.description}` +
220
- (m.why_failed ? `\n Why: ${m.why_failed}` : '') +
221
- (m.run_id ? `\n Recorded by ${m.recorded_by_agent} in run ${m.run_id} (${m.quarantine_scope}-scoped)` : '')).join('\n\n');
222
- return `${withGlyph(g.brand, `${b.matches.length} failure(s) match this action:`)}\n\n${list}`;
223
- });
224
- },
225
- },
226
- {
227
- name: "wyrm_failure_list",
228
- description: "List unresolved failures for a project (or globally), most-recent-first.",
229
- inputSchema: {
230
- type: "object",
231
- properties: {
232
- projectPath: { type: "string", description: "Project path (omit for global)" },
233
- limit: { type: "number", description: "Max rows (default 20, max 200)" },
234
- },
235
- },
236
- outputSchema: {
237
- type: "object",
238
- properties: {
239
- count: { type: "integer" },
240
- failures: {
241
- type: "array",
242
- items: {
243
- type: "object",
244
- properties: {
245
- id: { type: "integer" },
246
- severity: { type: "string", enum: ["low", "medium", "high", "critical"] },
247
- scope: { type: "string" },
248
- target: { type: "string" },
249
- occurrences: { type: "integer" },
250
- last_seen: { type: "string" },
251
- description: { type: "string" },
252
- },
253
- required: ["id", "severity", "scope", "target", "occurrences", "last_seen", "description"],
254
- },
255
- },
256
- },
257
- required: ["count", "failures"],
258
- },
259
- annotations: TOOL_ANNOTATIONS.wyrm_failure_list,
260
- aliases: [],
261
- handler: (args, { store, failures }) => {
262
- const { projectPath, limit } = args;
263
- const project = projectPath ? store.getProject(projectPath) : null;
264
- const cap = Math.min(Math.max(1, limit ?? 20), 200);
265
- const rows = failures.list(project?.id ?? null, cap);
266
- const body = {
267
- count: rows.length,
268
- failures: rows.map((r) => ({
269
- id: r.id, severity: r.severity, scope: r.scope, target: r.target,
270
- occurrences: r.occurrences, last_seen: r.last_seen, description: r.description,
271
- })),
272
- };
273
- return renderResult(body, (b, g) => {
274
- if (b.count === 0)
275
- return withGlyph(g.brand, 'No unresolved failures.');
276
- const list = b.failures.map(r => `#${r.id} [${r.severity}] ${r.scope}:${r.target} x${r.occurrences} (last ${r.last_seen})\n ${r.description}`).join('\n\n');
277
- return `${withGlyph(g.brand, `${b.count} unresolved failure(s):`)}\n\n${list}`;
278
- }, {
279
- // WYRM_CHANNEL=structured: the per-row failure detail rides the body;
280
- // the text channel keeps the count roll-up.
281
- summary: (b, g) => b.count === 0
282
- ? withGlyph(g.brand, 'No unresolved failures.')
283
- : withGlyph(g.brand, `${b.count} unresolved failure(s):`),
284
- });
285
- },
286
- },
287
- {
288
- name: "wyrm_failure_resolve",
289
- description: "Mark a failure as resolved (the underlying issue was fixed). Keeps history but excludes from check() results.",
290
- inputSchema: {
291
- type: "object",
292
- properties: {
293
- id: { type: "number", description: "Failure pattern ID" },
294
- note: { type: "string", description: "How it was resolved" },
295
- promote: { type: "string", enum: ["project", "global"], description: "Widen the tier before resolving (same authority rule as wyrm_failure_record)." },
296
- },
297
- required: ["id"],
298
- },
299
- outputSchema: {
300
- type: "object",
301
- properties: {
302
- id: { type: "integer" },
303
- resolved: { type: "boolean", enum: [true] },
304
- promote: PROMOTE_OUTCOME_SCHEMA,
305
- },
306
- required: ["id", "resolved", "promote"],
307
- },
308
- annotations: TOOL_ANNOTATIONS.wyrm_failure_resolve,
309
- aliases: [],
310
- handler: (args, { failures }) => {
311
- const { id, note, promote } = args;
312
- // v7 F2 (T015): optional promote-before-resolve. The lesson keeps the
313
- // widened tier in history, and if the failure ever RECURS (record()'s
314
- // dedup path sets resolved=0 again) it is instantly visible at the
315
- // promoted tier instead of re-quarantining to a dead run. Same
316
- // ambient authority rule as wyrm_failure_record.
317
- let promoteOutcome = null;
318
- if (promote === 'project' || promote === 'global') {
319
- const p = failures.promote(id, promote);
320
- promoteOutcome = {
321
- requested: promote, authorized: p.authorized, changed: p.changed,
322
- quarantine_scope: p.row?.quarantine_scope ?? null,
323
- };
324
- }
325
- const row = failures.resolve(id, note);
326
- if (!row)
327
- return { content: [{ type: "text", text: `Failure #${id} not found.` }], isError: true };
328
- const body = { id, resolved: true, promote: promoteOutcome };
329
- return renderResult(body, (b, g) => {
330
- let note2 = '';
331
- if (b.promote && !b.promote.authorized)
332
- note2 = ` promote:'${b.promote.requested}' IGNORED -- caller carries no explicit identity.`;
333
- else if (b.promote?.changed)
334
- note2 = ` Promoted to ${b.promote.quarantine_scope}-scoped.`;
335
- return withGlyph(g.ok, `Failure #${b.id} resolved.${note2}`);
336
- });
337
- },
338
- },
339
- ];
340
- //# sourceMappingURL=failure.js.map
1
+ import{TOOL_ANNOTATIONS as h}from"../tool-annotations.js";import{renderResult as f,withGlyph as y}from"../render.js";import{asEnum as j}from"../validate.js";import{daemonOr as q}from"../daemon-writer.js";const v={type:"object",properties:{blocked:{type:"boolean"},matches:{type:"array",items:{type:"object",properties:{id:{type:"integer"},pattern:{type:"string"},scope:{type:"string"},quarantine_scope:{type:"string"},target:{type:"string"},description:{type:"string"},why_failed:{type:["string","null"]},severity:{type:"string"},occurrences:{type:"integer"},last_seen:{type:"string"},recorded_by_agent:{type:"string"},run_id:{type:["string","null"]},match:{type:"string",enum:["exact","fuzzy","target"]},confidence:{type:"number",minimum:0,maximum:1}},required:["id","pattern","scope","quarantine_scope","target","description","why_failed","severity","occurrences","last_seen","recorded_by_agent","run_id","match","confidence"]}},recorded_by_agent:{type:["string","null"]},run_id:{type:["string","null"]},confidence:{type:"number",minimum:0,maximum:1}},required:["blocked","matches","recorded_by_agent","run_id","confidence"]},w={type:["object","null"],properties:{requested:{type:"string"},authorized:{type:"boolean"},changed:{type:"boolean"}},required:["requested","authorized","changed"]};function x(n,a){return n?n.authorized?n.changed?"":` - promote:'${n.requested}' was a no-op (already ${a}-scoped)`:` - promote:'${n.requested}' IGNORED -- caller carries no explicit identity (pass actor/run_id, _meta['wyrm/actor'], or WYRM_AGENT_ID/WYRM_RUN_ID)`:""}const R=[{name:"wyrm_failure_record",description:"Use when an approach failed or something broke - log the dead end so nobody tries it again. Identical (scope, target, description) coalesces with occurrences++; when the root cause is fixed, stop flagging it via wyrm_failure_resolve. Run-scoped failures quarantine until confirmed.",inputSchema:{type:"object",properties:{projectPath:{type:"string",description:"Global if omitted"},scope:{type:"string",enum:["file","symbol","command","prompt","edit"]},target:{type:"string",description:"File, symbol, command, or prompt"},description:{type:"string",description:"What was tried"},why_failed:{type:"string",description:"Diagnosis if known"},severity:{type:"string",enum:["low","medium","high","critical"]},promote:{type:"string",enum:["project","global"],description:"Widen the tier (explicitly attributed callers only)"}},required:["scope","target","description"]},outputSchema:{type:"object",properties:{id:{type:"integer"},occurrences:{type:"integer"},scope:{type:"string"},target:{type:"string"},quarantine_scope:{type:"string"},run_id:{type:["string","null"]},promote:w},required:["id","occurrences","scope","target","quarantine_scope","run_id","promote"]},annotations:h.wyrm_failure_record,aliases:[],handler:async(n,{store:a,failures:c})=>{const{projectPath:p,scope:s,target:d,description:g,why_failed:m,severity:o,promote:t}=n,i=j("severity",o,["low","medium","high","critical"]),u=p?a.getProject(p):null;let r=await q("failure_record",u?.id??null,{scope:s,target:d,description:g,why_failed:m,severity:i},()=>c.record({project_id:u?.id??null,scope:s,target:d,description:g,why_failed:m,severity:i})),l=null;if(t==="project"||t==="global"){const e=c.promote(r.id,t);e.authorized&&(r=e.row??r),l={requested:t,authorized:e.authorized,changed:e.changed,quarantine_scope:e.row?.quarantine_scope??r.quarantine_scope??null}}const _={id:r.id,occurrences:r.occurrences,scope:s,target:d,quarantine_scope:r.quarantine_scope,run_id:r.run_id??null,promote:l};return f(_,(e,b)=>{const $=e.run_id?` - ${e.quarantine_scope}-scoped (run ${e.run_id})`:` - ${e.quarantine_scope}-scoped`;return y(b.brand,`Failure #${e.id} recorded (x${e.occurrences}) -- ${e.scope}:${e.target}${$}`+x(e.promote,e.quarantine_scope))})}},{name:"wyrm_failure_check",description:"Use before proposing or executing any fix, command, or approach - did this fail before? Is it a known landmine? Counter-pattern memory: returns unresolved matching failures (empty = safe to proceed); show the mistakes already made on a project with wyrm_failure_list. Subagents: check before retrying anything flagged.",inputSchema:{type:"object",properties:{projectPath:{type:"string"},scope:{type:"string",enum:["file","symbol","command","prompt","edit"]},target:{type:"string"},description:{type:"string"},run_scope:{type:"string",enum:["run","project","global"],description:"Quarantine tier filter (run = same-run only)"}},required:["scope","target","description"]},outputSchema:v,annotations:h.wyrm_failure_check,aliases:[],handler:async(n,{store:a,raw:c,failures:p})=>{const{projectPath:s,scope:d,target:g,description:m,run_scope:o}=n,t=s?a.getProject(s):null,i=o==="run"||o==="project"||o==="global"?o:"any",u=p.checkVerdict(d,g,m,t?.id??null,{runScope:i});if(u.blocked){p.recordBlock(u,t?.id??null);try{const{logSavings:r}=await import("../statusline.js"),l=c(),_=t?l.prepare("SELECT id FROM sessions WHERE project_id = ? ORDER BY created_at DESC LIMIT 1").get(t.id):void 0;r(l,"wyrm_failure_check","blocked_retry",1500*u.matches.length,_?.id)}catch{}}return f(u,(r,l)=>{if(!r.blocked)return y(l.ok,"No matching failures -- safe to proceed.");const _=r.matches.map(e=>`${y(l.fail,`#${e.id} ${e.scope}:${e.target}`)} -- tried ${e.occurrences}x (${e.severity}); last ${e.last_seen}
2
+ ${e.description}`+(e.why_failed?`
3
+ Why: ${e.why_failed}`:"")+(e.run_id?`
4
+ Recorded by ${e.recorded_by_agent} in run ${e.run_id} (${e.quarantine_scope}-scoped)`:"")).join(`
5
+
6
+ `);return`${y(l.brand,`${r.matches.length} failure(s) match this action:`)}
7
+
8
+ ${_}`})}},{name:"wyrm_failure_list",description:"List unresolved failures for a project (or globally), most-recent-first.",inputSchema:{type:"object",properties:{projectPath:{type:"string",description:"Project path (omit for global)"},limit:{type:"number",description:"Max rows (default 20, max 200)"}}},outputSchema:{type:"object",properties:{count:{type:"integer"},failures:{type:"array",items:{type:"object",properties:{id:{type:"integer"},severity:{type:"string",enum:["low","medium","high","critical"]},scope:{type:"string"},target:{type:"string"},occurrences:{type:"integer"},last_seen:{type:"string"},description:{type:"string"}},required:["id","severity","scope","target","occurrences","last_seen","description"]}}},required:["count","failures"]},annotations:h.wyrm_failure_list,aliases:[],handler:(n,{store:a,failures:c})=>{const{projectPath:p,limit:s}=n,d=p?a.getProject(p):null,g=Math.min(Math.max(1,s??20),200),m=c.list(d?.id??null,g),o={count:m.length,failures:m.map(t=>({id:t.id,severity:t.severity,scope:t.scope,target:t.target,occurrences:t.occurrences,last_seen:t.last_seen,description:t.description}))};return f(o,(t,i)=>{if(t.count===0)return y(i.brand,"No unresolved failures.");const u=t.failures.map(r=>`#${r.id} [${r.severity}] ${r.scope}:${r.target} x${r.occurrences} (last ${r.last_seen})
9
+ ${r.description}`).join(`
10
+
11
+ `);return`${y(i.brand,`${t.count} unresolved failure(s):`)}
12
+
13
+ ${u}`},{summary:(t,i)=>t.count===0?y(i.brand,"No unresolved failures."):y(i.brand,`${t.count} unresolved failure(s):`)})}},{name:"wyrm_failure_resolve",description:"Mark a failure as resolved (the underlying issue was fixed). Keeps history but excludes from check() results.",inputSchema:{type:"object",properties:{id:{type:"number",description:"Failure pattern ID"},note:{type:"string",description:"How it was resolved"},promote:{type:"string",enum:["project","global"],description:"Widen the tier before resolving (same authority rule as wyrm_failure_record)."}},required:["id"]},outputSchema:{type:"object",properties:{id:{type:"integer"},resolved:{type:"boolean",enum:[!0]},promote:w},required:["id","resolved","promote"]},annotations:h.wyrm_failure_resolve,aliases:[],handler:(n,{failures:a})=>{const{id:c,note:p,promote:s}=n;let d=null;if(s==="project"||s==="global"){const o=a.promote(c,s);d={requested:s,authorized:o.authorized,changed:o.changed,quarantine_scope:o.row?.quarantine_scope??null}}return a.resolve(c,p)?f({id:c,resolved:!0,promote:d},(o,t)=>{let i="";return o.promote&&!o.promote.authorized?i=` promote:'${o.promote.requested}' IGNORED -- caller carries no explicit identity.`:o.promote?.changed&&(i=` Promoted to ${o.promote.quarantine_scope}-scoped.`),y(t.ok,`Failure #${o.id} resolved.${i}`)}):{content:[{type:"text",text:`Failure #${c} not found.`}],isError:!0}}}];export{v as FAILURE_CHECK_OUTPUT_SCHEMA,R as failureToolSpecs};