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,217 +1,8 @@
1
- /**
2
- * Internal tool dispatcher for the AgentLoop (v7 F4 T036 — extracted from the
3
- * index.ts monolith). A curated subset of read-mostly + bounded-write tools the
4
- * autonomous OODA loop is allowed to call; the whitelist itself is enforced in
5
- * agent-loop.ts (SAFE_INTERNAL_TOOLS). Lifted VERBATIM out of index.ts behind a
6
- * factory that captures the same subsystem singletons it always closed over —
7
- * the single-quoted `case` labels here are what tests/tool-surface-integrity.ts
8
- * scans to keep the whitelist and the dispatcher in lockstep.
9
- *
10
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
11
- * @license AGPL-3.0-or-later
12
- */
13
- import { sanitizeFtsQuery } from "./security.js";
14
- import { classifyCapture } from "./capture.js";
15
- export function makeInternalDispatch(deps) {
16
- const { db, failures, symbols, rehydration, causality, presence, federation, memory, groundTruths } = deps;
17
- const internalDispatch = async (name, args) => {
18
- try {
19
- switch (name) {
20
- case 'wyrm_search': {
21
- const q = String(args.query ?? args.q ?? '').slice(0, 200);
22
- if (!q)
23
- return { ok: false, error: 'query required' };
24
- const sanitized = sanitizeFtsQuery(q);
25
- const rows = db.getDatabase().prepare(`
1
+ import{sanitizeFtsQuery as k}from"./security.js";import{classifyCapture as _}from"./capture.js";function q(p){const{db:r,failures:i,symbols:a,rehydration:m,causality:u,presence:f,federation:j,memory:c,groundTruths:y}=p;return async(d,s)=>{try{switch(d){case"wyrm_search":{const e=String(s.query??s.q??"").slice(0,200);if(!e)return{ok:!1,error:"query required"};const t=k(e);return{ok:!0,result:r.getDatabase().prepare(`
26
2
  SELECT s.id, s.date, s.summary FROM sessions s
27
3
  JOIN sessions_fts fts ON fts.rowid = s.id
28
4
  WHERE sessions_fts MATCH ? LIMIT 10
29
- `).all(sanitized);
30
- return { ok: true, result: rows };
31
- }
32
- case 'wyrm_all_quests': {
33
- return { ok: true, result: db.getAllPendingQuests().slice(0, 30) };
34
- }
35
- case 'wyrm_truth_get': {
36
- const projPath = args.projectPath;
37
- const proj = projPath ? db.getProject(projPath) : null;
38
- const rows = proj
39
- ? db.getDatabase().prepare(`
5
+ `).all(t)}}case"wyrm_all_quests":return{ok:!0,result:r.getAllPendingQuests().slice(0,30)};case"wyrm_truth_get":{const e=s.projectPath,t=e?r.getProject(e):null;return{ok:!0,result:t?r.getDatabase().prepare(`
40
6
  SELECT category, key, value, rationale FROM ground_truths
41
7
  WHERE project_id = ? AND is_current = 1 ORDER BY confidence DESC LIMIT 30
42
- `).all(proj.id)
43
- : [];
44
- return { ok: true, result: rows };
45
- }
46
- case 'wyrm_failure_check': {
47
- const a = args;
48
- const proj = a.projectPath ? db.getProject(a.projectPath) : null;
49
- return { ok: true, result: failures.check(a.scope, a.target, a.description, proj?.id ?? null) };
50
- }
51
- case 'wyrm_failure_list': {
52
- const a = args;
53
- const proj = a.projectPath ? db.getProject(a.projectPath) : null;
54
- return { ok: true, result: failures.list(proj?.id ?? null, Math.min(50, a.limit ?? 20)) };
55
- }
56
- case 'wyrm_failure_record': {
57
- const a = args;
58
- const proj = a.projectPath ? db.getProject(a.projectPath) : null;
59
- return { ok: true, result: failures.record({ project_id: proj?.id ?? null, scope: a.scope, target: a.target, description: a.description, why_failed: a.why_failed, severity: a.severity }) };
60
- }
61
- case 'wyrm_symbol_search': {
62
- const a = args;
63
- if (!a.symbol)
64
- return { ok: false, error: 'symbol required' };
65
- const proj = a.projectPath ? db.getProject(a.projectPath) : null;
66
- return { ok: true, result: symbols.search(a.symbol, { projectId: proj?.id, kind: a.kind, language: a.language, exact: a.exact, limit: Math.min(50, a.limit ?? 20) }) };
67
- }
68
- case 'wyrm_symbol_callers': {
69
- const a = args;
70
- const proj = a.projectPath ? db.getProject(a.projectPath) : null;
71
- return { ok: true, result: symbols.callers(a.symbol, proj?.id).slice(0, 30) };
72
- }
73
- case 'wyrm_symbol_stats': {
74
- const a = args;
75
- const proj = a.projectPath ? db.getProject(a.projectPath) : null;
76
- return { ok: true, result: symbols.stats(proj?.id) };
77
- }
78
- case 'wyrm_session_rehydrate': {
79
- const a = args;
80
- const brief = rehydration.rehydrate(a.session_id);
81
- return { ok: brief != null, result: brief, error: brief ? undefined : 'session not found' };
82
- }
83
- case 'wyrm_decision_upstream': {
84
- const a = args;
85
- return { ok: true, result: causality.upstreamOf(a.kind, a.id) };
86
- }
87
- case 'wyrm_decision_downstream': {
88
- const a = args;
89
- return { ok: true, result: causality.downstreamOf(a.kind, a.id) };
90
- }
91
- case 'wyrm_decided_because': {
92
- const a = args;
93
- const proj = db.getProject(a.projectPath);
94
- if (!proj)
95
- return { ok: false, error: 'project not found' };
96
- return { ok: true, result: causality.link({ project_id: proj.id, ...a }) };
97
- }
98
- case 'wyrm_presence_list': {
99
- const a = args;
100
- const proj = a.projectPath ? db.getProject(a.projectPath) : null;
101
- return { ok: true, result: presence.liveAgents(proj?.id ?? null) };
102
- }
103
- case 'wyrm_sync_conflicts': {
104
- return { ok: true, result: federation.unresolvedConflicts(20) };
105
- }
106
- case 'wyrm_quest_add': {
107
- const a = args;
108
- const proj = db.getProject(a.projectPath);
109
- if (!proj)
110
- return { ok: false, error: 'project not found' };
111
- const q = db.addQuest(proj.id, a.title, a.description, a.priority || 'medium', a.tags);
112
- return { ok: true, result: { id: q.id, title: q.title } };
113
- }
114
- case 'wyrm_quest_complete': {
115
- const a = args;
116
- const q = db.updateQuest(a.questId, 'completed');
117
- return { ok: true, result: { id: q.id, status: 'completed' } };
118
- }
119
- case 'wyrm_project_context': {
120
- const a = args;
121
- const proj = db.getProject(a.projectPath);
122
- if (!proj)
123
- return { ok: false, error: 'project not found' };
124
- // Summary: open quests + latest session
125
- const ctx = {
126
- project: proj.name,
127
- quests: db.getAllPendingQuests().filter(q => q.project_id === proj.id).slice(0, 10),
128
- last_session: db.getDatabase().prepare('SELECT id, date, summary FROM sessions WHERE project_id = ? ORDER BY date DESC LIMIT 1').get(proj.id),
129
- };
130
- return { ok: true, result: ctx };
131
- }
132
- // ── Memory ops the OODA loop is whitelisted for (SAFE_INTERNAL_TOOLS).
133
- // These were promised by the whitelist but had no dispatch case until 6.8.1,
134
- // so the loop silently failed on them. Kept in lockstep by
135
- // tests/tool-surface-integrity.test.ts.
136
- case 'wyrm_global_context': {
137
- const a = args;
138
- const projects = db.getAllProjects(a.maxProjects ?? 20).map((p) => ({
139
- name: p.name, stack: p.stack ?? null, stats: db.getProjectStats(p.id),
140
- }));
141
- const result = { globalContext: db.getAllGlobalContext(), projects };
142
- if (a.includeQuests)
143
- result.quests = db.getAllPendingQuests().slice(0, 20);
144
- return { ok: true, result };
145
- }
146
- case 'wyrm_recall': {
147
- const a = args;
148
- const proj = a.projectPath ? db.getProject(a.projectPath) : null;
149
- if (!proj)
150
- return { ok: false, error: 'project not found' };
151
- if (!a.query)
152
- return { ok: false, error: 'query required' };
153
- const results = memory.recall(proj.id, a.query, { kind: a.kind, limit: Math.min(20, a.limit ?? 10), minConfidence: a.minConfidence });
154
- return { ok: true, result: results.map((r) => ({ id: r.artifact.id, kind: r.artifact.kind, problem: r.artifact.problem, validated_fix: r.artifact.validated_fix, relevance: r.relevance_score })) };
155
- }
156
- case 'wyrm_remember': {
157
- const a = args;
158
- const proj = a.projectPath ? db.getProject(a.projectPath) : null;
159
- if (!proj)
160
- return { ok: false, error: 'project not found' };
161
- if (!a.problem)
162
- return { ok: false, error: 'problem required' };
163
- const art = memory.add(proj.id, { kind: a.kind, problem: a.problem, constraints: a.constraints, validatedFix: a.validatedFix, whyItWorked: a.whyItWorked, outcome: a.outcome, tags: a.tags, confidence: a.confidence, sourceSessionId: a.sourceSessionId });
164
- return { ok: true, result: { id: art.id, kind: art.kind } };
165
- }
166
- case 'wyrm_distill': {
167
- const a = args;
168
- const proj = a.projectPath ? db.getProject(a.projectPath) : null;
169
- if (!proj)
170
- return { ok: false, error: 'project not found' };
171
- if (!a.candidates?.length)
172
- return { ok: false, error: 'candidates required' };
173
- const ids = a.candidates.map((c) => memory.add(proj.id, { kind: c.kind, problem: c.title, validatedFix: c.content, tags: c.tags ?? [], confidence: c.confidence ?? 0.7, needsReview: 1 }).id);
174
- return { ok: true, result: { queued: ids.length, ids } };
175
- }
176
- case 'wyrm_capture': {
177
- const a = args;
178
- if (!a.content)
179
- return { ok: false, error: 'content required' };
180
- let cls = classifyCapture(a.content);
181
- if (a.mode && a.mode !== 'auto') {
182
- const sub = { quest: 'quest', truth: 'decision', memory: 'pattern' };
183
- cls = { type: a.mode, subtype: sub[a.mode] ?? a.mode, confidence: 100, reasoning: `mode:${a.mode}` };
184
- }
185
- const pid = a.project_id ?? null;
186
- if (cls.type === 'quest') {
187
- if (pid === null)
188
- return { ok: false, error: 'project_id required for quest' };
189
- const q = db.addQuest(pid, a.content.slice(0, 200), '', 'medium', a.tags?.join(','));
190
- return { ok: true, result: { type: 'quest', id: q.id } };
191
- }
192
- if (cls.type === 'truth') {
193
- if (pid === null)
194
- return { ok: false, error: 'project_id required for truth' };
195
- if (a.mode === 'truth' || cls.confidence >= 100) {
196
- const t = groundTruths.set(pid, { category: 'decision', key: a.content.slice(0, 60), value: a.content });
197
- return { ok: true, result: { type: 'truth', id: t.id } };
198
- }
199
- const art = memory.add(pid, { kind: 'pattern', problem: a.content, tags: a.tags ?? [], confidence: cls.confidence / 100, needsReview: 1 });
200
- return { ok: true, result: { type: 'memory_review', id: art.id } };
201
- }
202
- if (pid === null)
203
- return { ok: false, error: 'project_id required for memory' };
204
- const art = memory.add(pid, { kind: 'pattern', problem: a.content, tags: a.tags ?? [], confidence: (cls.confidence ?? 70) / 100, needsReview: 1 });
205
- return { ok: true, result: { type: 'memory', id: art.id } };
206
- }
207
- default:
208
- return { ok: false, error: `Internal tool '${name}' not implemented in dispatcher` };
209
- }
210
- }
211
- catch (err) {
212
- return { ok: false, error: err.message };
213
- }
214
- };
215
- return internalDispatch;
216
- }
217
- //# sourceMappingURL=internal-dispatch.js.map
8
+ `).all(t.id):[]}}case"wyrm_failure_check":{const e=s,t=e.projectPath?r.getProject(e.projectPath):null;return{ok:!0,result:i.check(e.scope,e.target,e.description,t?.id??null)}}case"wyrm_failure_list":{const e=s,t=e.projectPath?r.getProject(e.projectPath):null;return{ok:!0,result:i.list(t?.id??null,Math.min(50,e.limit??20))}}case"wyrm_failure_record":{const e=s,t=e.projectPath?r.getProject(e.projectPath):null;return{ok:!0,result:i.record({project_id:t?.id??null,scope:e.scope,target:e.target,description:e.description,why_failed:e.why_failed,severity:e.severity})}}case"wyrm_symbol_search":{const e=s;if(!e.symbol)return{ok:!1,error:"symbol required"};const t=e.projectPath?r.getProject(e.projectPath):null;return{ok:!0,result:a.search(e.symbol,{projectId:t?.id,kind:e.kind,language:e.language,exact:e.exact,limit:Math.min(50,e.limit??20)})}}case"wyrm_symbol_callers":{const e=s,t=e.projectPath?r.getProject(e.projectPath):null;return{ok:!0,result:a.callers(e.symbol,t?.id).slice(0,30)}}case"wyrm_symbol_stats":{const e=s,t=e.projectPath?r.getProject(e.projectPath):null;return{ok:!0,result:a.stats(t?.id)}}case"wyrm_session_rehydrate":{const e=s,t=m.rehydrate(e.session_id);return{ok:t!=null,result:t,error:t?void 0:"session not found"}}case"wyrm_decision_upstream":{const e=s;return{ok:!0,result:u.upstreamOf(e.kind,e.id)}}case"wyrm_decision_downstream":{const e=s;return{ok:!0,result:u.downstreamOf(e.kind,e.id)}}case"wyrm_decided_because":{const e=s,t=r.getProject(e.projectPath);return t?{ok:!0,result:u.link({project_id:t.id,...e})}:{ok:!1,error:"project not found"}}case"wyrm_presence_list":{const e=s,t=e.projectPath?r.getProject(e.projectPath):null;return{ok:!0,result:f.liveAgents(t?.id??null)}}case"wyrm_sync_conflicts":return{ok:!0,result:j.unresolvedConflicts(20)};case"wyrm_quest_add":{const e=s,t=r.getProject(e.projectPath);if(!t)return{ok:!1,error:"project not found"};const o=r.addQuest(t.id,e.title,e.description,e.priority||"medium",e.tags);return{ok:!0,result:{id:o.id,title:o.title}}}case"wyrm_quest_complete":{const e=s;return{ok:!0,result:{id:r.updateQuest(e.questId,"completed").id,status:"completed"}}}case"wyrm_project_context":{const e=s,t=r.getProject(e.projectPath);return t?{ok:!0,result:{project:t.name,quests:r.getAllPendingQuests().filter(n=>n.project_id===t.id).slice(0,10),last_session:r.getDatabase().prepare("SELECT id, date, summary FROM sessions WHERE project_id = ? ORDER BY date DESC LIMIT 1").get(t.id)}}:{ok:!1,error:"project not found"}}case"wyrm_global_context":{const e=s,t=r.getAllProjects(e.maxProjects??20).map(n=>({name:n.name,stack:n.stack??null,stats:r.getProjectStats(n.id)})),o={globalContext:r.getAllGlobalContext(),projects:t};return e.includeQuests&&(o.quests=r.getAllPendingQuests().slice(0,20)),{ok:!0,result:o}}case"wyrm_recall":{const e=s,t=e.projectPath?r.getProject(e.projectPath):null;return t?e.query?{ok:!0,result:c.recall(t.id,e.query,{kind:e.kind,limit:Math.min(20,e.limit??10),minConfidence:e.minConfidence}).map(n=>({id:n.artifact.id,kind:n.artifact.kind,problem:n.artifact.problem,validated_fix:n.artifact.validated_fix,relevance:n.relevance_score}))}:{ok:!1,error:"query required"}:{ok:!1,error:"project not found"}}case"wyrm_remember":{const e=s,t=e.projectPath?r.getProject(e.projectPath):null;if(!t)return{ok:!1,error:"project not found"};if(!e.problem)return{ok:!1,error:"problem required"};const o=c.add(t.id,{kind:e.kind,problem:e.problem,constraints:e.constraints,validatedFix:e.validatedFix,whyItWorked:e.whyItWorked,outcome:e.outcome,tags:e.tags,confidence:e.confidence,sourceSessionId:e.sourceSessionId});return{ok:!0,result:{id:o.id,kind:o.kind}}}case"wyrm_distill":{const e=s,t=e.projectPath?r.getProject(e.projectPath):null;if(!t)return{ok:!1,error:"project not found"};if(!e.candidates?.length)return{ok:!1,error:"candidates required"};const o=e.candidates.map(n=>c.add(t.id,{kind:n.kind,problem:n.title,validatedFix:n.content,tags:n.tags??[],confidence:n.confidence??.7,needsReview:1}).id);return{ok:!0,result:{queued:o.length,ids:o}}}case"wyrm_capture":{const e=s;if(!e.content)return{ok:!1,error:"content required"};let t=_(e.content);if(e.mode&&e.mode!=="auto"){const l={quest:"quest",truth:"decision",memory:"pattern"};t={type:e.mode,subtype:l[e.mode]??e.mode,confidence:100,reasoning:`mode:${e.mode}`}}const o=e.project_id??null;return t.type==="quest"?o===null?{ok:!1,error:"project_id required for quest"}:{ok:!0,result:{type:"quest",id:r.addQuest(o,e.content.slice(0,200),"","medium",e.tags?.join(",")).id}}:t.type==="truth"?o===null?{ok:!1,error:"project_id required for truth"}:e.mode==="truth"||t.confidence>=100?{ok:!0,result:{type:"truth",id:y.set(o,{category:"decision",key:e.content.slice(0,60),value:e.content}).id}}:{ok:!0,result:{type:"memory_review",id:c.add(o,{kind:"pattern",problem:e.content,tags:e.tags??[],confidence:t.confidence/100,needsReview:1}).id}}:o===null?{ok:!1,error:"project_id required for memory"}:{ok:!0,result:{type:"memory",id:c.add(o,{kind:"pattern",problem:e.content,tags:e.tags??[],confidence:(t.confidence??70)/100,needsReview:1}).id}}}default:return{ok:!1,error:`Internal tool '${d}' not implemented in dispatcher`}}}catch(e){return{ok:!1,error:e.message}}}}export{q as makeInternalDispatch};
package/dist/keyset.js CHANGED
@@ -1,110 +1 @@
1
- /**
2
- * Keyset (cursor) pagination — the v7 F4 T035 context-economy primitive.
3
- *
4
- * THE MOVE: a big listing returns a PAGE plus an opaque `nextCursor`, not the
5
- * whole table. The cursor is a COMPOSITE `(sortKey, id)` — never a bare
6
- * sortKey. This is deliberate: the wyrm-cloud sync keyset bug (fixed at
7
- * cloud/client.ts:299 with a `"<updated_at>:<id>"` composite) is the
8
- * cautionary tale — a bare `sortKey` cursor SILENTLY DROPS every row that
9
- * shares the boundary row's sort value (e.g. three artifacts with identical
10
- * `confidence` straddling a page edge). The id tiebreak makes the keyset
11
- * total-ordered, so `(sortKey, id) > (lastSortKey, lastId)` resumes EXACTLY
12
- * after the last emitted row, dropping nothing and repeating nothing.
13
- *
14
- * The cursor is OPAQUE on the wire: a base64url-encoded `"<sortKey>:<id>"`
15
- * string. Callers MUST treat it as a token (round-trip it verbatim); they
16
- * never parse it. A malformed/garbage cursor decodes to `null` and the caller
17
- * degrades to "start from the first page" (never throws on the wire — a
18
- * resource-less or buggy client can't be wedged by a bad token).
19
- *
20
- * Article III: pure, deterministic, no network, no clock, no LLM. Same rows in
21
- * ⇒ same page + same cursor out. Article VII: hard default + max caps so an
22
- * unbounded `limit` can never be requested; the encode/decode is total (no
23
- * throw on adversarial input).
24
- *
25
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
26
- * @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
27
- */
28
- /** Default page size when a caller passes no `limit`. */
29
- export const DEFAULT_PAGE_SIZE = 50;
30
- /** Absolute ceiling on a single page — a caller can never exceed this. */
31
- export const MAX_PAGE_SIZE = 200;
32
- /**
33
- * Clamp a requested limit into `[1, MAX_PAGE_SIZE]`, defaulting to
34
- * `DEFAULT_PAGE_SIZE` when absent/NaN/≤0. The hard cap holds regardless of
35
- * what the caller asks for (Article VII: bounded by construction).
36
- */
37
- export function clampPageSize(requested, opts = {}) {
38
- const def = opts.defaultSize ?? DEFAULT_PAGE_SIZE;
39
- const max = opts.maxSize ?? MAX_PAGE_SIZE;
40
- if (requested == null || !Number.isFinite(requested) || requested <= 0)
41
- return Math.min(def, max);
42
- return Math.min(Math.floor(requested), max);
43
- }
44
- /**
45
- * Encode a composite `(sortKey, id)` anchor into an opaque base64url token.
46
- * The sortKey is length-prefixed (`<len>.<sortKey>:<id>`) so a sortKey that
47
- * itself contains a `:` (e.g. an ISO timestamp `2026-06-13T10:00:00`) round-
48
- * trips losslessly — decode reads exactly `<len>` chars for the sortKey.
49
- */
50
- export function encodeCursor(cursor) {
51
- const sk = String(cursor.sortKey);
52
- const raw = `${sk.length}.${sk}:${cursor.id}`;
53
- return Buffer.from(raw, 'utf8').toString('base64url');
54
- }
55
- /**
56
- * Decode an opaque cursor token back into `(sortKey, id)`. Returns `null` for
57
- * any malformed/garbage/empty token — the caller degrades to the first page
58
- * rather than throwing on the wire (Article VII: total on adversarial input).
59
- */
60
- export function decodeCursor(token) {
61
- if (typeof token !== 'string' || token.length === 0)
62
- return null;
63
- let raw;
64
- try {
65
- raw = Buffer.from(token, 'base64url').toString('utf8');
66
- }
67
- catch {
68
- return null;
69
- }
70
- // Grammar: <len>.<sortKey(len chars)>:<id>
71
- const dot = raw.indexOf('.');
72
- if (dot <= 0)
73
- return null;
74
- const lenStr = raw.slice(0, dot);
75
- if (!/^\d{1,9}$/.test(lenStr))
76
- return null;
77
- const len = Number(lenStr);
78
- const after = raw.slice(dot + 1);
79
- if (after.length < len + 1)
80
- return null;
81
- const sortKey = after.slice(0, len);
82
- const sep = after.charAt(len);
83
- if (sep !== ':')
84
- return null;
85
- const idStr = after.slice(len + 1);
86
- if (!/^\d{1,15}$/.test(idStr))
87
- return null;
88
- const id = Number(idStr);
89
- if (!Number.isSafeInteger(id) || id < 0)
90
- return null;
91
- return { sortKey, id };
92
- }
93
- /**
94
- * Build a page from an OVER-FETCHED row array. Call the underlying query with
95
- * `limit = pageSize + 1`; pass the result here. If `pageSize + 1` rows came
96
- * back there is a further page: slice to `pageSize` and mint a `nextCursor`
97
- * from the LAST emitted row via `anchorOf`. The over-fetch-by-one is how we
98
- * know "is there more" without a second COUNT query.
99
- *
100
- * `anchorOf` must return the SAME `(sortKey, id)` the query's WHERE/ORDER use,
101
- * or pages will skip/repeat. Keep them in lockstep at the call site.
102
- */
103
- export function buildPage(rows, pageSize, anchorOf) {
104
- if (rows.length <= pageSize)
105
- return { items: rows };
106
- const items = rows.slice(0, pageSize);
107
- const last = items[items.length - 1];
108
- return { items, nextCursor: encodeCursor(anchorOf(last)) };
109
- }
110
- //# sourceMappingURL=keyset.js.map
1
+ const a=50,m=200;function S(t,n={}){const r=n.defaultSize??50,e=n.maxSize??200;return t==null||!Number.isFinite(t)||t<=0?Math.min(r,e):Math.min(Math.floor(t),e)}function c(t){const n=String(t.sortKey),r=`${n.length}.${n}:${t.id}`;return Buffer.from(r,"utf8").toString("base64url")}function g(t){if(typeof t!="string"||t.length===0)return null;let n;try{n=Buffer.from(t,"base64url").toString("utf8")}catch{return null}const r=n.indexOf(".");if(r<=0)return null;const e=n.slice(0,r);if(!/^\d{1,9}$/.test(e))return null;const l=Number(e),u=n.slice(r+1);if(u.length<l+1)return null;const s=u.slice(0,l);if(u.charAt(l)!==":")return null;const o=u.slice(l+1);if(!/^\d{1,15}$/.test(o))return null;const i=Number(o);return!Number.isSafeInteger(i)||i<0?null:{sortKey:s,id:i}}function d(t,n,r){if(t.length<=n)return{items:t};const e=t.slice(0,n),l=e[e.length-1];return{items:e,nextCursor:c(r(l))}}export{a as DEFAULT_PAGE_SIZE,m as MAX_PAGE_SIZE,d as buildPage,S as clampPageSize,g as decodeCursor,c as encodeCursor};
@@ -1,139 +1,31 @@
1
- /**
2
- * Wyrm Knowledge Graph — Entity & Relationship Management
3
- *
4
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
5
- * @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
6
- *
7
- * Manual-first knowledge graph with provenance tracking:
8
- * - Named entities with types and metadata
9
- * - Typed, directed relationships between entities
10
- * - Aliases for deduplication
11
- * - Graph traversal via recursive CTEs (neighborhood, paths)
12
- * - FTS5 search on entity names
13
- */
14
- const MAX_DEPTH = 5;
15
- const MAX_RESULTS = 200;
16
- /**
17
- * Knowledge graph operations backed by SQLite.
18
- */
19
- export class KnowledgeGraph {
20
- db;
21
- constructor(db) {
22
- this.db = db;
23
- }
24
- // ==================== ENTITIES ====================
25
- addEntity(projectId, name, type, metadata, createdBy) {
26
- const result = this.db.prepare(`
1
+ const p=5,_=200;class l{db;constructor(t){this.db=t}addEntity(t,e,i,n,r){const s=this.db.prepare(`
27
2
  INSERT INTO entities (project_id, name, type, metadata, created_by)
28
3
  VALUES (?, ?, ?, ?, ?)
29
- `).run(projectId, name.trim(), type.trim(), metadata ?? null, createdBy ?? 'local');
30
- return this.db.prepare('SELECT * FROM entities WHERE id = ?').get(result.lastInsertRowid);
31
- }
32
- getEntity(id) {
33
- return this.db.prepare('SELECT * FROM entities WHERE id = ?').get(id) ?? null;
34
- }
35
- findEntity(projectId, name, type) {
36
- if (type) {
37
- return this.db.prepare('SELECT * FROM entities WHERE project_id = ? AND name = ? AND type = ?').get(projectId, name, type) ?? null;
38
- }
39
- return this.db.prepare('SELECT * FROM entities WHERE project_id = ? AND name = ?').get(projectId, name) ?? null;
40
- }
41
- updateEntity(id, updates) {
42
- const entity = this.getEntity(id);
43
- if (!entity)
44
- return null;
45
- this.db.prepare(`
4
+ `).run(t,e.trim(),i.trim(),n??null,r??"local");return this.db.prepare("SELECT * FROM entities WHERE id = ?").get(s.lastInsertRowid)}getEntity(t){return this.db.prepare("SELECT * FROM entities WHERE id = ?").get(t)??null}findEntity(t,e,i){return i?this.db.prepare("SELECT * FROM entities WHERE project_id = ? AND name = ? AND type = ?").get(t,e,i)??null:this.db.prepare("SELECT * FROM entities WHERE project_id = ? AND name = ?").get(t,e)??null}updateEntity(t,e){return this.getEntity(t)?(this.db.prepare(`
46
5
  UPDATE entities SET
47
6
  name = COALESCE(?, name),
48
7
  type = COALESCE(?, type),
49
8
  metadata = COALESCE(?, metadata),
50
9
  updated_at = datetime('now')
51
10
  WHERE id = ?
52
- `).run(updates.name ?? null, updates.type ?? null, updates.metadata ?? null, id);
53
- return this.getEntity(id);
54
- }
55
- deleteEntity(id) {
56
- const result = this.db.prepare('DELETE FROM entities WHERE id = ?').run(id);
57
- return result.changes > 0;
58
- }
59
- listEntities(projectId, options) {
60
- let sql = 'SELECT * FROM entities WHERE project_id = ?';
61
- const params = [projectId];
62
- if (options?.type) {
63
- sql += ' AND type = ?';
64
- params.push(options.type);
65
- }
66
- sql += ' ORDER BY name ASC';
67
- sql += ` LIMIT ? OFFSET ?`;
68
- params.push(options?.limit ?? 50, options?.offset ?? 0);
69
- return this.db.prepare(sql).all(...params);
70
- }
71
- searchEntities(projectId, query, limit = 20) {
72
- // Try FTS first, fall back to LIKE
73
- try {
74
- const ftsResults = this.db.prepare(`
11
+ `).run(e.name??null,e.type??null,e.metadata??null,t),this.getEntity(t)):null}deleteEntity(t){return this.db.prepare("DELETE FROM entities WHERE id = ?").run(t).changes>0}listEntities(t,e){let i="SELECT * FROM entities WHERE project_id = ?";const n=[t];return e?.type&&(i+=" AND type = ?",n.push(e.type)),i+=" ORDER BY name ASC",i+=" LIMIT ? OFFSET ?",n.push(e?.limit??50,e?.offset??0),this.db.prepare(i).all(...n)}searchEntities(t,e,i=20){try{const n=this.db.prepare(`
75
12
  SELECT e.* FROM entities e
76
13
  JOIN entities_fts f ON f.rowid = e.id
77
14
  WHERE f.entities_fts MATCH ? AND e.project_id = ?
78
15
  LIMIT ?
79
- `).all(query, projectId, limit);
80
- if (ftsResults.length > 0)
81
- return ftsResults;
82
- }
83
- catch {
84
- // FTS query syntax error — fall back to LIKE
85
- }
86
- return this.db.prepare(`
16
+ `).all(e,t,i);if(n.length>0)return n}catch{}return this.db.prepare(`
87
17
  SELECT * FROM entities WHERE project_id = ? AND (name LIKE ? OR type LIKE ?)
88
18
  ORDER BY name ASC LIMIT ?
89
- `).all(projectId, `%${query}%`, `%${query}%`, limit);
90
- }
91
- // ==================== ALIASES ====================
92
- addAlias(entityId, alias) {
93
- this.db.prepare('INSERT OR IGNORE INTO entity_aliases (entity_id, alias) VALUES (?, ?)').run(entityId, alias.trim());
94
- }
95
- getAliases(entityId) {
96
- const rows = this.db.prepare('SELECT alias FROM entity_aliases WHERE entity_id = ?').all(entityId);
97
- return rows.map(r => r.alias);
98
- }
99
- findByAlias(projectId, alias) {
100
- return this.db.prepare(`
19
+ `).all(t,`%${e}%`,`%${e}%`,i)}addAlias(t,e){this.db.prepare("INSERT OR IGNORE INTO entity_aliases (entity_id, alias) VALUES (?, ?)").run(t,e.trim())}getAliases(t){return this.db.prepare("SELECT alias FROM entity_aliases WHERE entity_id = ?").all(t).map(i=>i.alias)}findByAlias(t,e){return this.db.prepare(`
101
20
  SELECT e.* FROM entities e
102
21
  JOIN entity_aliases a ON a.entity_id = e.id
103
22
  WHERE e.project_id = ? AND a.alias = ?
104
- `).get(projectId, alias) ?? null;
105
- }
106
- // ==================== RELATIONSHIPS ====================
107
- addRelationship(projectId, sourceId, targetId, type, options) {
108
- const result = this.db.prepare(`
23
+ `).get(t,e)??null}addRelationship(t,e,i,n,r){const s=this.db.prepare(`
109
24
  INSERT INTO relationships (
110
25
  project_id, source_entity_id, target_entity_id, relationship_type,
111
26
  weight, confidence, source_memory, extraction_method, metadata, created_by
112
27
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
113
- `).run(projectId, sourceId, targetId, type.trim(), options?.weight ?? 1.0, options?.confidence ?? 1.0, options?.sourceMemory ?? null, options?.extractionMethod ?? 'manual', options?.metadata ?? null, options?.createdBy ?? 'local');
114
- return this.db.prepare('SELECT * FROM relationships WHERE id = ?').get(result.lastInsertRowid);
115
- }
116
- getRelationships(entityId, direction = 'both') {
117
- switch (direction) {
118
- case 'outgoing':
119
- return this.db.prepare('SELECT * FROM relationships WHERE source_entity_id = ?').all(entityId);
120
- case 'incoming':
121
- return this.db.prepare('SELECT * FROM relationships WHERE target_entity_id = ?').all(entityId);
122
- case 'both':
123
- return this.db.prepare('SELECT * FROM relationships WHERE source_entity_id = ? OR target_entity_id = ?').all(entityId, entityId);
124
- }
125
- }
126
- deleteRelationship(id) {
127
- return this.db.prepare('DELETE FROM relationships WHERE id = ?').run(id).changes > 0;
128
- }
129
- // ==================== GRAPH QUERIES ====================
130
- /**
131
- * Get neighborhood — all nodes within N hops of a given entity.
132
- * Uses recursive CTE with cycle detection.
133
- */
134
- getNeighborhood(entityId, maxDepth = 2) {
135
- const depth = Math.min(maxDepth, MAX_DEPTH);
136
- const nodes = this.db.prepare(`
28
+ `).run(t,e,i,n.trim(),r?.weight??1,r?.confidence??1,r?.sourceMemory??null,r?.extractionMethod??"manual",r?.metadata??null,r?.createdBy??"local");return this.db.prepare("SELECT * FROM relationships WHERE id = ?").get(s.lastInsertRowid)}getRelationships(t,e="both"){switch(e){case"outgoing":return this.db.prepare("SELECT * FROM relationships WHERE source_entity_id = ?").all(t);case"incoming":return this.db.prepare("SELECT * FROM relationships WHERE target_entity_id = ?").all(t);case"both":return this.db.prepare("SELECT * FROM relationships WHERE source_entity_id = ? OR target_entity_id = ?").all(t,t)}}deleteRelationship(t){return this.db.prepare("DELETE FROM relationships WHERE id = ?").run(t).changes>0}getNeighborhood(t,e=2){const i=Math.min(e,5),n=this.db.prepare(`
137
29
  WITH RECURSIVE neighbors(id, depth, visited) AS (
138
30
  SELECT ?, 0, ',' || ? || ','
139
31
  UNION ALL
@@ -152,31 +44,16 @@ export class KnowledgeGraph {
152
44
  GROUP BY e.id
153
45
  ORDER BY depth ASC
154
46
  LIMIT ?
155
- `).all(entityId, entityId, depth, MAX_RESULTS);
156
- // Get edges between all discovered nodes
157
- const nodeIds = nodes.map(n => n.id);
158
- if (nodeIds.length === 0)
159
- return { nodes: [], edges: [] };
160
- const placeholders = nodeIds.map(() => '?').join(',');
161
- const edges = this.db.prepare(`
47
+ `).all(t,t,i,200),r=n.map(a=>a.id);if(r.length===0)return{nodes:[],edges:[]};const s=r.map(()=>"?").join(","),E=this.db.prepare(`
162
48
  SELECT r.source_entity_id as source_id, s.name as source_name,
163
49
  r.target_entity_id as target_id, t.name as target_name,
164
50
  r.relationship_type, r.weight
165
51
  FROM relationships r
166
52
  JOIN entities s ON s.id = r.source_entity_id
167
53
  JOIN entities t ON t.id = r.target_entity_id
168
- WHERE r.source_entity_id IN (${placeholders})
169
- AND r.target_entity_id IN (${placeholders})
170
- `).all(...nodeIds, ...nodeIds);
171
- return { nodes, edges };
172
- }
173
- /**
174
- * Find path between two entities using BFS with cycle detection.
175
- * Returns the shortest path as a list of entity IDs, or null if no path exists.
176
- */
177
- findPath(sourceId, targetId, maxDepth = 5) {
178
- const depth = Math.min(maxDepth, MAX_DEPTH);
179
- const rows = this.db.prepare(`
54
+ WHERE r.source_entity_id IN (${s})
55
+ AND r.target_entity_id IN (${s})
56
+ `).all(...r,...r);return{nodes:n,edges:E}}findPath(t,e,i=5){const n=Math.min(i,5),r=this.db.prepare(`
180
57
  WITH RECURSIVE path_finder(id, path, depth) AS (
181
58
  SELECT ?, CAST(? AS TEXT), 0
182
59
  UNION ALL
@@ -191,45 +68,4 @@ export class KnowledgeGraph {
191
68
  AND INSTR(',' || pf.path || ',', ',' || CASE WHEN r.source_entity_id = pf.id THEN r.target_entity_id ELSE r.source_entity_id END || ',') = 0
192
69
  )
193
70
  SELECT path FROM path_finder WHERE id = ? LIMIT 1
194
- `).all(sourceId, sourceId, depth, targetId);
195
- if (rows.length === 0)
196
- return null;
197
- return rows[0].path.split(',').map(Number);
198
- }
199
- /**
200
- * Merge two entities: moves all relationships and aliases from source to target,
201
- * adds source name as alias on target, then deletes source.
202
- */
203
- mergeEntities(sourceId, targetId) {
204
- const source = this.getEntity(sourceId);
205
- const target = this.getEntity(targetId);
206
- if (!source || !target)
207
- return null;
208
- const merge = this.db.transaction(() => {
209
- // Add source name as alias on target
210
- this.addAlias(targetId, source.name);
211
- // Move source's aliases to target
212
- this.db.prepare('UPDATE entity_aliases SET entity_id = ? WHERE entity_id = ?').run(targetId, sourceId);
213
- // Redirect relationships from source to target
214
- this.db.prepare('UPDATE relationships SET source_entity_id = ? WHERE source_entity_id = ?').run(targetId, sourceId);
215
- this.db.prepare('UPDATE relationships SET target_entity_id = ? WHERE target_entity_id = ?').run(targetId, sourceId);
216
- // Remove self-loops created by merge
217
- this.db.prepare('DELETE FROM relationships WHERE source_entity_id = target_entity_id').run();
218
- // Delete source entity
219
- this.deleteEntity(sourceId);
220
- });
221
- merge();
222
- return this.getEntity(targetId);
223
- }
224
- // ==================== STATS ====================
225
- getStats(projectId) {
226
- const entities = this.db.prepare('SELECT COUNT(*) as c FROM entities WHERE project_id = ?').get(projectId).c;
227
- const relationships = this.db.prepare('SELECT COUNT(*) as c FROM relationships WHERE project_id = ?').get(projectId).c;
228
- const typeRows = this.db.prepare('SELECT type, COUNT(*) as cnt FROM entities WHERE project_id = ? GROUP BY type').all(projectId);
229
- const entityTypes = {};
230
- for (const r of typeRows)
231
- entityTypes[r.type] = r.cnt;
232
- return { entities, relationships, entityTypes };
233
- }
234
- }
235
- //# sourceMappingURL=knowledge-graph.js.map
71
+ `).all(t,t,n,e);return r.length===0?null:r[0].path.split(",").map(Number)}mergeEntities(t,e){const i=this.getEntity(t),n=this.getEntity(e);return!i||!n?null:(this.db.transaction(()=>{this.addAlias(e,i.name),this.db.prepare("UPDATE entity_aliases SET entity_id = ? WHERE entity_id = ?").run(e,t),this.db.prepare("UPDATE relationships SET source_entity_id = ? WHERE source_entity_id = ?").run(e,t),this.db.prepare("UPDATE relationships SET target_entity_id = ? WHERE target_entity_id = ?").run(e,t),this.db.prepare("DELETE FROM relationships WHERE source_entity_id = target_entity_id").run(),this.deleteEntity(t)})(),this.getEntity(e))}getStats(t){const e=this.db.prepare("SELECT COUNT(*) as c FROM entities WHERE project_id = ?").get(t).c,i=this.db.prepare("SELECT COUNT(*) as c FROM relationships WHERE project_id = ?").get(t).c,n=this.db.prepare("SELECT type, COUNT(*) as cnt FROM entities WHERE project_id = ? GROUP BY type").all(t),r={};for(const s of n)r[s.type]=s.cnt;return{entities:e,relationships:i,entityTypes:r}}}export{l as KnowledgeGraph};
package/dist/license.d.ts CHANGED
@@ -115,6 +115,17 @@ export declare function signLicense(license: WyrmLicense, privateKeyPem: string)
115
115
  * @param publicKeyPem - Optional PEM override; defaults to the embedded key
116
116
  */
117
117
  export declare function verifyLicense(signed: SignedLicense, publicKeyPem?: string): LicenseValidation;
118
+ /**
119
+ * Known-Answer Test for the official build: confirm the verifier still REJECTS a
120
+ * structurally-valid but badly-signed license. If a fork stubs `verifyLicense` to
121
+ * always-accept (so it can run on a forged `license.json` and bypass the activation
122
+ * gate), this self-test trips. It's a deterrent layer — a determined forker can
123
+ * remove this too — but it raises the effort beyond a one-line edit. Pure + offline.
124
+ */
125
+ export declare function selfTestVerifier(): {
126
+ ok: boolean;
127
+ reason?: string;
128
+ };
118
129
  /**
119
130
  * Check whether a specific feature is available in the current license.
120
131
  *
@@ -1 +1 @@
1
- {"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../src/license.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../src/license.ts"],"names":[],"mappings":"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"}