wyrm-mcp 7.2.1 → 7.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/LICENSE +26 -667
  2. package/NOTICE +14 -33
  3. package/dist/activation.js +1 -60
  4. package/dist/agent-daemon.js +4 -281
  5. package/dist/agent-loop.js +7 -332
  6. package/dist/analytics.js +13 -236
  7. package/dist/attribution.js +1 -49
  8. package/dist/audit.js +2 -457
  9. package/dist/auto-capture.js +3 -138
  10. package/dist/auto-orchestrator.js +1 -325
  11. package/dist/autoconfig.js +39 -840
  12. package/dist/buddy-runner.js +1 -109
  13. package/dist/buddy.js +14 -564
  14. package/dist/build-flags.js +1 -17
  15. package/dist/capabilities.js +3 -183
  16. package/dist/capture.js +1 -56
  17. package/dist/causality.js +6 -107
  18. package/dist/cli.js +20 -281
  19. package/dist/cloud/cli.js +5 -541
  20. package/dist/cloud/client.js +1 -221
  21. package/dist/cloud/crypto.js +1 -85
  22. package/dist/cloud/machine-id.js +2 -113
  23. package/dist/cloud/recovery.js +1 -60
  24. package/dist/cloud/sync-engine.js +7 -543
  25. package/dist/cloud-backup.js +5 -579
  26. package/dist/cloud-profile.js +1 -138
  27. package/dist/cloud-sync-entrypoint.js +1 -47
  28. package/dist/cloud-sync.js +2 -309
  29. package/dist/constellation.js +12 -168
  30. package/dist/context-build-budgeted.js +4 -144
  31. package/dist/context-ranking.js +1 -69
  32. package/dist/crypto.js +1 -179
  33. package/dist/daemon-write-endpoint.js +1 -290
  34. package/dist/daemon-writer.js +2 -406
  35. package/dist/database.js +43 -1110
  36. package/dist/deprecations.js +2 -162
  37. package/dist/design.js +13 -141
  38. package/dist/event-replication.js +1 -112
  39. package/dist/events-sse.js +7 -43
  40. package/dist/events.js +6 -238
  41. package/dist/failure-patterns.js +42 -659
  42. package/dist/federation.js +12 -236
  43. package/dist/goals.js +13 -101
  44. package/dist/golden.js +3 -355
  45. package/dist/handlers/agent.js +4 -165
  46. package/dist/handlers/alias-adapters.js +1 -129
  47. package/dist/handlers/aliases.js +1 -171
  48. package/dist/handlers/audit.js +1 -87
  49. package/dist/handlers/boundary.js +1 -221
  50. package/dist/handlers/capture.js +73 -1109
  51. package/dist/handlers/causality.js +7 -114
  52. package/dist/handlers/cloud.js +85 -382
  53. package/dist/handlers/companion.js +28 -459
  54. package/dist/handlers/datalake.js +7 -187
  55. package/dist/handlers/dispatch-context.js +0 -22
  56. package/dist/handlers/entity.js +25 -256
  57. package/dist/handlers/events.js +16 -335
  58. package/dist/handlers/failure.js +13 -340
  59. package/dist/handlers/goals.js +4 -296
  60. package/dist/handlers/intelligence.js +126 -674
  61. package/dist/handlers/invoicing.js +1 -70
  62. package/dist/handlers/mcpclient.js +6 -137
  63. package/dist/handlers/orchestration.js +40 -125
  64. package/dist/handlers/output-schemas.js +1 -24
  65. package/dist/handlers/presence.js +3 -99
  66. package/dist/handlers/project.js +28 -182
  67. package/dist/handlers/prompts.js +6 -157
  68. package/dist/handlers/quest.js +4 -224
  69. package/dist/handlers/recall.js +11 -218
  70. package/dist/handlers/registry.js +1 -167
  71. package/dist/handlers/resources.js +1 -288
  72. package/dist/handlers/review.js +11 -74
  73. package/dist/handlers/run.js +17 -487
  74. package/dist/handlers/search.js +15 -326
  75. package/dist/handlers/session.js +28 -615
  76. package/dist/handlers/share.js +8 -184
  77. package/dist/handlers/shims.js +1 -464
  78. package/dist/handlers/skill.js +67 -449
  79. package/dist/handlers/survivors.js +1 -120
  80. package/dist/handlers/symbols.js +8 -109
  81. package/dist/handlers/syncops.js +4 -302
  82. package/dist/handlers/types.js +1 -27
  83. package/dist/harvest.js +5 -191
  84. package/dist/hours.js +7 -156
  85. package/dist/http-auth.js +3 -321
  86. package/dist/http-fast.js +21 -1137
  87. package/dist/icons.js +1 -47
  88. package/dist/index.js +2 -924
  89. package/dist/indexer.js +4 -145
  90. package/dist/intelligence.js +31 -261
  91. package/dist/internal-dispatch.js +3 -212
  92. package/dist/keyset.js +1 -110
  93. package/dist/knowledge-graph.js +12 -176
  94. package/dist/license.js +2 -441
  95. package/dist/logger.js +2 -199
  96. package/dist/maintenance.js +2 -148
  97. package/dist/mcp-client.js +6 -262
  98. package/dist/memory-artifacts.js +30 -449
  99. package/dist/migrate-prompt.js +2 -124
  100. package/dist/migrations.js +40 -655
  101. package/dist/performance.js +1 -228
  102. package/dist/presence.js +11 -140
  103. package/dist/priority-embed.js +5 -164
  104. package/dist/providers/embedding-provider.js +1 -196
  105. package/dist/readonly-gate.js +1 -29
  106. package/dist/rehydration.js +9 -157
  107. package/dist/reindex.js +1 -88
  108. package/dist/render-target.js +21 -514
  109. package/dist/render.js +4 -280
  110. package/dist/repl-guard.js +1 -173
  111. package/dist/replication-daemon-entrypoint.js +1 -31
  112. package/dist/replication-daemon.js +2 -262
  113. package/dist/resilience.js +1 -591
  114. package/dist/reverse-bridge.js +5 -360
  115. package/dist/security.js +1 -244
  116. package/dist/session-seen.js +3 -51
  117. package/dist/setup.js +1 -260
  118. package/dist/skill-author.js +5 -168
  119. package/dist/spec-kit.js +1 -191
  120. package/dist/sqlite-busy.js +1 -154
  121. package/dist/statusline.js +11 -315
  122. package/dist/sub-agent.js +13 -262
  123. package/dist/summarizer.js +13 -139
  124. package/dist/symbols.js +7 -283
  125. package/dist/sync.js +5 -359
  126. package/dist/tasks-dispatch.js +1 -84
  127. package/dist/tasks.js +1 -282
  128. package/dist/token-budget.js +1 -143
  129. package/dist/tool-analytics.js +7 -129
  130. package/dist/tool-annotations.js +1 -365
  131. package/dist/tool-manifest-v2.json +1 -1
  132. package/dist/tool-manifest.json +1 -1
  133. package/dist/tool-profiles.js +1 -75
  134. package/dist/trace-harvest.js +6 -244
  135. package/dist/types.js +1 -30
  136. package/dist/ui-dashboard.js +41 -50
  137. package/dist/ulid.js +1 -81
  138. package/dist/validate.js +1 -129
  139. package/dist/vault.js +1 -534
  140. package/dist/vectors.js +3 -184
  141. package/dist/version-check.js +4 -136
  142. package/dist/visibility.js +19 -155
  143. package/dist/wyrm-cli.js +98 -2464
  144. package/dist/wyrm-guard.js +14 -424
  145. package/dist/wyrm-loop.js +3 -150
  146. package/dist/wyrm-manifest.json +1 -1
  147. package/dist/wyrm-statusline-daemon.js +1 -11
  148. package/dist/wyrm-statusline.js +4 -56
  149. package/dist/wyrm-ui.js +9 -77
  150. package/package.json +4 -2
@@ -1,257 +1,33 @@
1
- /**
2
- * Federated team Wyrm (Tier 2.8).
3
- *
4
- * Each operator runs a local Wyrm; opt-in tagged data syncs to a shared
5
- * "team Wyrm" instance. PII never leaves the local box unless explicitly
6
- * shared (per-row `is_shared=1` flag — set when the operator marks a
7
- * truth/quest/artifact as team-visible).
8
- *
9
- * Sync surface:
10
- * POST /sync/push pushes is_shared=1 local rows changed since cursor
11
- * GET /sync/pull pulls remote rows changed since cursor
12
- *
13
- * Conflict policy: if a remote push lands on top of a local edit whose
14
- * `updated_at` is newer, we DO NOT silently overwrite. Instead we record
15
- * the conflict in `sync_conflicts` and mint a quest for the operator to
16
- * resolve. Last-write-wins is the failure mode of every team sync tool;
17
- * Wyrm refuses to silently lose work.
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
- const KIND_TO_TABLE = {
23
- session: { table: 'sessions', ts: 'created_at' },
24
- quest: { table: 'quests', ts: 'created_at' },
25
- truth: { table: 'ground_truths', ts: 'updated_at' },
26
- artifact: { table: 'memory_artifacts', ts: 'last_accessed_at' },
27
- edge: { table: 'decision_edges', ts: 'created_at' },
28
- };
29
- export class Federation {
30
- db;
31
- constructor(db) {
32
- this.db = db;
33
- }
34
- /** Mark a row as shared (will be picked up on next push). */
35
- share(kind, id) {
36
- const t = KIND_TO_TABLE[kind];
37
- if (!t)
38
- return false;
39
- // [grove isolation] Refuse to share a row that belongs to a PRIVATE grove.
40
- // A private grove (projects.sync_policy='private') must never federate to a
41
- // team Wyrm, so we block the is_shared flag at the source (defense in depth
42
- // alongside the collectForPush grove gate).
43
- if (this.isPrivateGroveRow(t.table, id))
44
- return false;
45
- const info = this.db.prepare(`UPDATE ${t.table} SET is_shared = 1 WHERE id = ?`).run(id);
46
- return info.changes > 0;
47
- }
48
- /** True if the row's project grove has sync_policy='private' (never federates). */
49
- isPrivateGroveRow(table, id) {
50
- try {
51
- const row = this.db.prepare(`SELECT (SELECT sync_policy FROM projects WHERE id = t.project_id) AS policy
52
- FROM ${table} t WHERE t.id = ?`).get(id);
53
- // No row, or a project-less / unknown-project row: not grove-private here
54
- // (governed by is_shared alone). An explicit 'private' policy blocks it.
55
- if (!row || row.policy == null)
56
- return false;
57
- return row.policy === 'private';
58
- }
59
- catch {
60
- // projects.sync_policy not present yet (pre-migration) → grove feature off.
61
- return false;
62
- }
63
- }
64
- /** Whether the grove-policy column exists (feature gate, pre-migration safe). */
65
- projectsHasSyncPolicy() {
66
- try {
67
- return this.db.prepare(`PRAGMA table_info(projects)`).all()
68
- .some((c) => c.name === 'sync_policy');
69
- }
70
- catch {
71
- return false;
72
- }
73
- }
74
- /** Unshare (revoke from team visibility). Local row stays. */
75
- unshare(kind, id) {
76
- const t = KIND_TO_TABLE[kind];
77
- if (!t)
78
- return false;
79
- const info = this.db.prepare(`UPDATE ${t.table} SET is_shared = 0 WHERE id = ?`).run(id);
80
- return info.changes > 0;
81
- }
82
- /** Collect rows to push: is_shared=1 AND ts > since_cursor. */
83
- collectForPush(since_cursor, limit = 500) {
84
- const cursor = since_cursor ?? '1970-01-01';
85
- const out = [];
86
- // [grove isolation] Only federate rows whose grove opts into team sharing
87
- // (projects.sync_policy='team'). Project-less rows fall back to is_shared.
88
- const groveGate = this.projectsHasSyncPolicy()
89
- ? `AND (project_id IS NULL OR project_id IN (SELECT id FROM projects WHERE sync_policy = 'team'))`
90
- : ``;
91
- for (const [kindStr, t] of Object.entries(KIND_TO_TABLE)) {
92
- if (out.length >= limit)
93
- break;
94
- const kind = kindStr;
95
- const rows = this.db.prepare(`SELECT * FROM ${t.table}
96
- WHERE is_shared = 1 ${groveGate} AND ${t.ts} > ?
97
- ORDER BY ${t.ts} ASC
98
- LIMIT ?`).all(cursor, Math.max(1, limit - out.length));
99
- for (const r of rows) {
100
- out.push({
101
- kind,
102
- id: r.id,
103
- project_id: (r.project_id ?? null),
104
- payload: r,
105
- updated_at: r[t.ts] || new Date().toISOString(),
106
- });
107
- }
108
- }
109
- return out;
110
- }
111
- /** Apply a remote row locally. Returns:
112
- * { kind: 'inserted' } — fresh row, no conflict
113
- * { kind: 'overwritten' } — local row was older, remote wins
114
- * { kind: 'conflict', conflict_id } — local row newer, conflict recorded
115
- * Idempotent — applying the same payload twice is a no-op.
116
- *
117
- * Conflict policy: if local updated_at > remote updated_at, the remote
118
- * is REJECTED into sync_conflicts; a quest is minted. The local row stays.
119
- */
120
- applyRemote(row, remoteOrigin) {
121
- const t = KIND_TO_TABLE[row.kind];
122
- if (!t)
123
- return { kind: 'skipped' };
124
- const localTs = this.db.prepare(`SELECT ${t.ts} as ts FROM ${t.table} WHERE id = ?`).get(row.id);
125
- if (!localTs) {
126
- // Fresh insert. Build columns from payload, skipping id (auto-incremented)
127
- // — but we want to preserve the same id so future syncs are stable.
128
- // SQLite allows explicit id insert.
129
- const cols = Object.keys(row.payload).filter(c => c !== 'rowid');
130
- const placeholders = cols.map(() => '?').join(',');
131
- const values = cols.map(c => row.payload[c]);
132
- try {
133
- this.db.prepare(`INSERT OR IGNORE INTO ${t.table} (${cols.join(',')}) VALUES (${placeholders})`).run(...values);
134
- return { kind: 'inserted' };
135
- }
136
- catch {
137
- return { kind: 'skipped' };
138
- }
139
- }
140
- // Existing row — compare timestamps.
141
- const localNewer = localTs.ts > row.updated_at;
142
- if (localNewer) {
143
- // Conflict — record it and mint a quest if this row has a project_id.
144
- const conflictInfo = this.db.prepare(`
1
+ const d={session:{table:"sessions",ts:"created_at"},quest:{table:"quests",ts:"created_at"},truth:{table:"ground_truths",ts:"updated_at"},artifact:{table:"memory_artifacts",ts:"last_accessed_at"},edge:{table:"decision_edges",ts:"created_at"}};class E{db;constructor(t){this.db=t}share(t,r){const e=d[t];return!e||this.isPrivateGroveRow(e.table,r)?!1:this.db.prepare(`UPDATE ${e.table} SET is_shared = 1 WHERE id = ?`).run(r).changes>0}isPrivateGroveRow(t,r){try{const e=this.db.prepare(`SELECT (SELECT sync_policy FROM projects WHERE id = t.project_id) AS policy
2
+ FROM ${t} t WHERE t.id = ?`).get(r);return!e||e.policy==null?!1:e.policy==="private"}catch{return!1}}projectsHasSyncPolicy(){try{return this.db.prepare("PRAGMA table_info(projects)").all().some(t=>t.name==="sync_policy")}catch{return!1}}unshare(t,r){const e=d[t];return e?this.db.prepare(`UPDATE ${e.table} SET is_shared = 0 WHERE id = ?`).run(r).changes>0:!1}collectForPush(t,r=500){const e=t??"1970-01-01",s=[],o=this.projectsHasSyncPolicy()?"AND (project_id IS NULL OR project_id IN (SELECT id FROM projects WHERE sync_policy = 'team'))":"";for(const[a,c]of Object.entries(d)){if(s.length>=r)break;const l=a,n=this.db.prepare(`SELECT * FROM ${c.table}
3
+ WHERE is_shared = 1 ${o} AND ${c.ts} > ?
4
+ ORDER BY ${c.ts} ASC
5
+ LIMIT ?`).all(e,Math.max(1,r-s.length));for(const i of n)s.push({kind:l,id:i.id,project_id:i.project_id??null,payload:i,updated_at:i[c.ts]||new Date().toISOString()})}return s}applyRemote(t,r){const e=d[t.kind];if(!e)return{kind:"skipped"};const s=this.db.prepare(`SELECT ${e.ts} as ts FROM ${e.table} WHERE id = ?`).get(t.id);if(!s){const n=Object.keys(t.payload).filter(p=>p!=="rowid"),i=n.map(()=>"?").join(","),u=n.map(p=>t.payload[p]);try{return this.db.prepare(`INSERT OR IGNORE INTO ${e.table} (${n.join(",")}) VALUES (${i})`).run(...u),{kind:"inserted"}}catch{return{kind:"skipped"}}}if(s.ts>t.updated_at){const i=this.db.prepare(`
145
6
  INSERT INTO sync_conflicts
146
7
  (local_kind, local_id, remote_payload, remote_origin)
147
8
  VALUES (?, ?, ?, ?)
148
- `).run(row.kind, row.id, JSON.stringify(row.payload), remoteOrigin);
149
- const conflict_id = conflictInfo.lastInsertRowid;
150
- // Best-effort: mint a quest so the operator sees it on next session
151
- if (row.project_id != null) {
152
- try {
153
- this.db.prepare(`
9
+ `).run(t.kind,t.id,JSON.stringify(t.payload),r).lastInsertRowid;if(t.project_id!=null)try{this.db.prepare(`
154
10
  INSERT INTO quests (project_id, title, description, priority, status, tags)
155
11
  VALUES (?, ?, ?, 'high', 'pending', 'sync-conflict')
156
- `).run(row.project_id, `[sync] Resolve conflict on ${row.kind} #${row.id}`, `A remote ${remoteOrigin} pushed a ${row.kind} that conflicts with a newer local edit. ` +
157
- `See sync_conflicts row #${conflict_id} for the remote payload. ` +
158
- `Resolve with wyrm_sync_resolve (kept_local | kept_remote | merged).`);
159
- }
160
- catch { /* best-effort */ }
161
- }
162
- return { kind: 'conflict', conflict_id };
163
- }
164
- // Local is older — accept remote overwrite.
165
- const cols = Object.keys(row.payload).filter(c => c !== 'id');
166
- const setClause = cols.map(c => `${c} = ?`).join(', ');
167
- const values = cols.map(c => row.payload[c]);
168
- try {
169
- this.db.prepare(`UPDATE ${t.table} SET ${setClause} WHERE id = ?`).run(...values, row.id);
170
- return { kind: 'overwritten' };
171
- }
172
- catch {
173
- return { kind: 'skipped' };
174
- }
175
- }
176
- /** Bulk push — record one sync_log row, return summary. Caller does HTTP. */
177
- recordPush(rows, remoteOrigin, duration_ms, since_cursor) {
178
- const newCursor = new Date().toISOString();
179
- this.db.prepare(`
12
+ `).run(t.project_id,`[sync] Resolve conflict on ${t.kind} #${t.id}`,`A remote ${r} pushed a ${t.kind} that conflicts with a newer local edit. See sync_conflicts row #${i} for the remote payload. Resolve with wyrm_sync_resolve (kept_local | kept_remote | merged).`)}catch{}return{kind:"conflict",conflict_id:i}}const a=Object.keys(t.payload).filter(n=>n!=="id"),c=a.map(n=>`${n} = ?`).join(", "),l=a.map(n=>t.payload[n]);try{return this.db.prepare(`UPDATE ${e.table} SET ${c} WHERE id = ?`).run(...l,t.id),{kind:"overwritten"}}catch{return{kind:"skipped"}}}recordPush(t,r,e,s){const o=new Date().toISOString();return this.db.prepare(`
180
13
  INSERT INTO sync_log
181
14
  (direction, remote_origin, kind, count, since_cursor, new_cursor, duration_ms)
182
15
  VALUES ('push', ?, 'mixed', ?, ?, ?, ?)
183
- `).run(remoteOrigin, rows.length, since_cursor ?? null, newCursor, duration_ms);
184
- return {
185
- pushed: rows.length,
186
- conflicts: 0,
187
- new_cursor: newCursor,
188
- conflict_ids: [],
189
- };
190
- }
191
- /** Bulk pull — apply each remote row, record sync_log, return summary. */
192
- applyPull(rows, remoteOrigin, duration_ms, since_cursor) {
193
- const byKind = {};
194
- let pulled = 0;
195
- for (const row of rows) {
196
- const result = this.applyRemote(row, remoteOrigin);
197
- if (result.kind === 'inserted' || result.kind === 'overwritten') {
198
- pulled++;
199
- byKind[row.kind] = (byKind[row.kind] ?? 0) + 1;
200
- }
201
- }
202
- const newCursor = new Date().toISOString();
203
- this.db.prepare(`
16
+ `).run(r,t.length,s??null,o,e),{pushed:t.length,conflicts:0,new_cursor:o,conflict_ids:[]}}applyPull(t,r,e,s){const o={};let a=0;for(const l of t){const n=this.applyRemote(l,r);(n.kind==="inserted"||n.kind==="overwritten")&&(a++,o[l.kind]=(o[l.kind]??0)+1)}const c=new Date().toISOString();return this.db.prepare(`
204
17
  INSERT INTO sync_log
205
18
  (direction, remote_origin, kind, count, since_cursor, new_cursor, duration_ms)
206
19
  VALUES ('pull', ?, 'mixed', ?, ?, ?, ?)
207
- `).run(remoteOrigin, pulled, since_cursor ?? null, newCursor, duration_ms);
208
- return { pulled, new_cursor: newCursor, by_kind: byKind };
209
- }
210
- /** Get the latest cursor from a previous sync. */
211
- latestCursor(direction, remoteOrigin) {
212
- const row = this.db.prepare(`
20
+ `).run(r,a,s??null,c,e),{pulled:a,new_cursor:c,by_kind:o}}latestCursor(t,r){return this.db.prepare(`
213
21
  SELECT new_cursor FROM sync_log
214
22
  WHERE direction = ? AND remote_origin = ?
215
23
  ORDER BY id DESC LIMIT 1
216
- `).get(direction, remoteOrigin);
217
- return row?.new_cursor ?? null;
218
- }
219
- /** List unresolved sync conflicts. */
220
- unresolvedConflicts(limit = 50) {
221
- return this.db.prepare(`
24
+ `).get(t,r)?.new_cursor??null}unresolvedConflicts(t=50){return this.db.prepare(`
222
25
  SELECT id, local_kind, local_id, remote_origin, detected_at, quest_id
223
26
  FROM sync_conflicts
224
27
  WHERE resolved_at IS NULL
225
28
  ORDER BY detected_at DESC LIMIT ?
226
- `).all(limit);
227
- }
228
- /** Resolve a conflict. mode: 'kept_local' | 'kept_remote' | 'merged'. */
229
- resolveConflict(conflict_id, mode, merged_payload) {
230
- const conflict = this.db.prepare('SELECT * FROM sync_conflicts WHERE id = ? AND resolved_at IS NULL').get(conflict_id);
231
- if (!conflict)
232
- return false;
233
- if (mode === 'kept_remote' || mode === 'merged') {
234
- const t = KIND_TO_TABLE[conflict.local_kind];
235
- if (t) {
236
- const payload = mode === 'merged' && merged_payload
237
- ? merged_payload
238
- : JSON.parse(conflict.remote_payload);
239
- const cols = Object.keys(payload).filter(c => c !== 'id');
240
- const setClause = cols.map(c => `${c} = ?`).join(', ');
241
- const values = cols.map(c => payload[c]);
242
- try {
243
- this.db.prepare(`UPDATE ${t.table} SET ${setClause} WHERE id = ?`).run(...values, conflict.local_id);
244
- }
245
- catch { /* best-effort */ }
246
- }
247
- }
248
- // 'kept_local' = no row mutation needed.
249
- this.db.prepare(`
29
+ `).all(t)}resolveConflict(t,r,e){const s=this.db.prepare("SELECT * FROM sync_conflicts WHERE id = ? AND resolved_at IS NULL").get(t);if(!s)return!1;if(r==="kept_remote"||r==="merged"){const o=d[s.local_kind];if(o){const a=r==="merged"&&e?e:JSON.parse(s.remote_payload),c=Object.keys(a).filter(i=>i!=="id"),l=c.map(i=>`${i} = ?`).join(", "),n=c.map(i=>a[i]);try{this.db.prepare(`UPDATE ${o.table} SET ${l} WHERE id = ?`).run(...n,s.local_id)}catch{}}}return this.db.prepare(`
250
30
  UPDATE sync_conflicts
251
31
  SET resolved_at = datetime('now'), resolution = ?
252
32
  WHERE id = ?
253
- `).run(mode, conflict_id);
254
- return true;
255
- }
256
- }
257
- //# sourceMappingURL=federation.js.map
33
+ `).run(r,t),!0}}export{E as Federation};
package/dist/goals.js CHANGED
@@ -1,97 +1,32 @@
1
- /**
2
- * Goals — persistent objectives Wyrm pursues across sessions.
3
- *
4
- * A goal is a long-lived row. Each `pursue` invocation runs one OODA
5
- * iteration (Observe → Orient → Decide → Act), appends a row to
6
- * `goal_iterations`, and updates the goal's `last_pursued_at` +
7
- * `iterations_count`. The agent loop (`wyrm-loop` daemon) picks the
8
- * highest-priority active goal each tick.
9
- *
10
- * Goals carry `max_iterations` to prevent infinite spinning on
11
- * unresolvable objectives. `success_criteria` is the operator-defined
12
- * "done when X" — the LLM checks against it each iteration.
13
- *
14
- * @copyright 2026 Ghost Protocol (Pvt) Ltd.
15
- * @license AGPL-3.0-or-later — dual-licensed; commercial terms: ghosts.lk@proton.me. See LICENSE.
16
- */
17
- export class Goals {
18
- db;
19
- constructor(db) {
20
- this.db = db;
21
- }
22
- set(input) {
23
- const info = this.db.prepare(`
1
+ class n{db;constructor(t){this.db=t}set(t){const e=this.db.prepare(`
24
2
  INSERT INTO goals
25
3
  (project_id, title, description, success_criteria, deadline,
26
4
  priority, max_iterations)
27
5
  VALUES (?, ?, ?, ?, ?, ?, ?)
28
- `).run(input.project_id ?? null, input.title, input.description ?? null, input.success_criteria ?? null, input.deadline ?? null, input.priority ?? 'medium', Math.max(1, Math.min(input.max_iterations ?? 20, 200)));
29
- return this.get(info.lastInsertRowid);
30
- }
31
- get(id) {
32
- return this.db.prepare('SELECT * FROM goals WHERE id = ?').get(id) ?? null;
33
- }
34
- list(opts) {
35
- const where = [];
36
- const params = [];
37
- if (opts?.status) {
38
- where.push('status = ?');
39
- params.push(opts.status);
40
- }
41
- if (opts?.project_id != null) {
42
- where.push('project_id = ?');
43
- params.push(opts.project_id);
44
- }
45
- const sql = `
6
+ `).run(t.project_id??null,t.title,t.description??null,t.success_criteria??null,t.deadline??null,t.priority??"medium",Math.max(1,Math.min(t.max_iterations??20,200)));return this.get(e.lastInsertRowid)}get(t){return this.db.prepare("SELECT * FROM goals WHERE id = ?").get(t)??null}list(t){const e=[],a=[];t?.status&&(e.push("status = ?"),a.push(t.status)),t?.project_id!=null&&(e.push("project_id = ?"),a.push(t.project_id));const s=`
46
7
  SELECT * FROM goals
47
- ${where.length ? 'WHERE ' + where.join(' AND ') : ''}
8
+ ${e.length?"WHERE "+e.join(" AND "):""}
48
9
  ORDER BY
49
10
  CASE priority WHEN 'critical' THEN 0 WHEN 'high' THEN 1
50
11
  WHEN 'medium' THEN 2 ELSE 3 END,
51
12
  COALESCE(last_pursued_at, '1970-01-01') ASC,
52
13
  created_at ASC
53
14
  LIMIT ?
54
- `;
55
- params.push(opts?.limit ?? 50);
56
- return this.db.prepare(sql).all(...params);
57
- }
58
- /** Pick the next goal to pursue: highest priority, least-recently
59
- * pursued, only active goals that haven't hit iteration cap. Returns
60
- * null when there's nothing to do. */
61
- nextToPursue(projectId) {
62
- const params = [];
63
- let where = `status = 'active' AND iterations_count < max_iterations`;
64
- if (projectId != null) {
65
- where += ` AND project_id = ?`;
66
- params.push(projectId);
67
- }
68
- const sql = `
15
+ `;return a.push(t?.limit??50),this.db.prepare(s).all(...a)}nextToPursue(t){const e=[];let a="status = 'active' AND iterations_count < max_iterations";t!=null&&(a+=" AND project_id = ?",e.push(t));const s=`
69
16
  SELECT * FROM goals
70
- WHERE ${where}
17
+ WHERE ${a}
71
18
  ORDER BY
72
19
  CASE priority WHEN 'critical' THEN 0 WHEN 'high' THEN 1
73
20
  WHEN 'medium' THEN 2 ELSE 3 END,
74
21
  COALESCE(last_pursued_at, '1970-01-01') ASC
75
22
  LIMIT 1
76
- `;
77
- return this.db.prepare(sql).get(...params) ?? null;
78
- }
79
- /** Record one OODA iteration result and bump the goal's counters. */
80
- recordIteration(goal_id, input) {
81
- const goal = this.get(goal_id);
82
- if (!goal)
83
- throw new Error(`Goal ${goal_id} not found`);
84
- const iterationNum = goal.iterations_count + 1;
85
- const info = this.db.prepare(`
23
+ `;return this.db.prepare(s).get(...e)??null}recordIteration(t,e){const a=this.get(t);if(!a)throw new Error(`Goal ${t} not found`);const s=a.iterations_count+1,r=this.db.prepare(`
86
24
  INSERT INTO goal_iterations
87
25
  (goal_id, iteration_num, observe_summary, orient_summary,
88
26
  decided_action, action_result, outcome, notes,
89
27
  latency_ms, tokens_in, tokens_out, model)
90
28
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
91
- `).run(goal_id, iterationNum, input.observe_summary ?? null, input.orient_summary ?? null, input.decided_action ?? null, input.action_result ?? null, input.outcome, input.notes ?? null, Math.max(0, Math.round(input.latency_ms)), input.tokens_in ?? null, input.tokens_out ?? null, input.model ?? null);
92
- // Update goal counters + last_outcome. If outcome=='done', mark completed.
93
- const shouldComplete = input.outcome === 'done';
94
- this.db.prepare(`
29
+ `).run(t,s,e.observe_summary??null,e.orient_summary??null,e.decided_action??null,e.action_result??null,e.outcome,e.notes??null,Math.max(0,Math.round(e.latency_ms)),e.tokens_in??null,e.tokens_out??null,e.model??null),o=e.outcome==="done";return this.db.prepare(`
95
30
  UPDATE goals
96
31
  SET iterations_count = iterations_count + 1,
97
32
  last_pursued_at = datetime('now'),
@@ -100,47 +35,24 @@ export class Goals {
100
35
  status = CASE WHEN ? = 1 THEN 'completed' ELSE status END,
101
36
  completed_at = CASE WHEN ? = 1 THEN datetime('now') ELSE completed_at END
102
37
  WHERE id = ?
103
- `).run(input.outcome, shouldComplete ? 1 : 0, shouldComplete ? 1 : 0, goal_id);
104
- return (this.db.prepare('SELECT * FROM goal_iterations WHERE id = ?').get(info.lastInsertRowid));
105
- }
106
- iterationsFor(goal_id, limit = 50) {
107
- return this.db.prepare(`
38
+ `).run(e.outcome,o?1:0,o?1:0,t),this.db.prepare("SELECT * FROM goal_iterations WHERE id = ?").get(r.lastInsertRowid)}iterationsFor(t,e=50){return this.db.prepare(`
108
39
  SELECT * FROM goal_iterations
109
40
  WHERE goal_id = ? ORDER BY iteration_num DESC LIMIT ?
110
- `).all(goal_id, limit);
111
- }
112
- complete(id, note) {
113
- this.db.prepare(`
41
+ `).all(t,e)}complete(t,e){return this.db.prepare(`
114
42
  UPDATE goals
115
43
  SET status = 'completed',
116
44
  completed_at = datetime('now'),
117
45
  updated_at = datetime('now'),
118
46
  last_outcome = COALESCE(?, last_outcome)
119
47
  WHERE id = ?
120
- `).run(note ?? null, id);
121
- return this.get(id);
122
- }
123
- pause(id) {
124
- this.db.prepare(`
48
+ `).run(e??null,t),this.get(t)}pause(t){return this.db.prepare(`
125
49
  UPDATE goals SET status = 'paused', updated_at = datetime('now') WHERE id = ?
126
- `).run(id);
127
- return this.get(id);
128
- }
129
- resume(id) {
130
- this.db.prepare(`
50
+ `).run(t),this.get(t)}resume(t){return this.db.prepare(`
131
51
  UPDATE goals SET status = 'active', updated_at = datetime('now') WHERE id = ?
132
- `).run(id);
133
- return this.get(id);
134
- }
135
- abandon(id, reason) {
136
- this.db.prepare(`
52
+ `).run(t),this.get(t)}abandon(t,e){return this.db.prepare(`
137
53
  UPDATE goals
138
54
  SET status = 'abandoned',
139
55
  updated_at = datetime('now'),
140
56
  last_outcome = COALESCE(?, last_outcome)
141
57
  WHERE id = ?
142
- `).run(reason ?? null, id);
143
- return this.get(id);
144
- }
145
- }
146
- //# sourceMappingURL=goals.js.map
58
+ `).run(e??null,t),this.get(t)}}export{n as Goals};