@kognai/orchestrator-core 0.1.0

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 (144) hide show
  1. package/README.md +44 -0
  2. package/dist/index.d.ts +63 -0
  3. package/dist/index.js +175 -0
  4. package/dist/lib/aar-middleware.d.ts +6 -0
  5. package/dist/lib/aar-middleware.js +70 -0
  6. package/dist/lib/aar-types.d.ts +34 -0
  7. package/dist/lib/aar-types.js +4 -0
  8. package/dist/lib/acp-engine.d.ts +68 -0
  9. package/dist/lib/acp-engine.js +123 -0
  10. package/dist/lib/acp.d.ts +61 -0
  11. package/dist/lib/acp.js +425 -0
  12. package/dist/lib/agent-registry.d.ts +50 -0
  13. package/dist/lib/agent-registry.js +137 -0
  14. package/dist/lib/anthropic-direct.d.ts +27 -0
  15. package/dist/lib/anthropic-direct.js +109 -0
  16. package/dist/lib/asmr-extractor.d.ts +40 -0
  17. package/dist/lib/asmr-extractor.js +151 -0
  18. package/dist/lib/asmr-retrieval.d.ts +76 -0
  19. package/dist/lib/asmr-retrieval.js +311 -0
  20. package/dist/lib/asmr.d.ts +8 -0
  21. package/dist/lib/asmr.js +24 -0
  22. package/dist/lib/brainx-client.d.ts +72 -0
  23. package/dist/lib/brainx-client.js +200 -0
  24. package/dist/lib/brainx-embed.d.ts +14 -0
  25. package/dist/lib/brainx-embed.js +139 -0
  26. package/dist/lib/brainx-swarm-bridge.d.ts +93 -0
  27. package/dist/lib/brainx-swarm-bridge.js +242 -0
  28. package/dist/lib/byterover-client.d.ts +19 -0
  29. package/dist/lib/byterover-client.js +59 -0
  30. package/dist/lib/ceo-wallet.d.ts +37 -0
  31. package/dist/lib/ceo-wallet.js +176 -0
  32. package/dist/lib/chomsky-gate.d.ts +24 -0
  33. package/dist/lib/chomsky-gate.js +178 -0
  34. package/dist/lib/chomsky-runner.d.ts +29 -0
  35. package/dist/lib/chomsky-runner.js +157 -0
  36. package/dist/lib/citizen-score-contract.d.ts +72 -0
  37. package/dist/lib/citizen-score-contract.js +16 -0
  38. package/dist/lib/citizen-score-registry.d.ts +25 -0
  39. package/dist/lib/citizen-score-registry.js +65 -0
  40. package/dist/lib/citizenship.d.ts +103 -0
  41. package/dist/lib/citizenship.js +272 -0
  42. package/dist/lib/clawrouter-client.d.ts +37 -0
  43. package/dist/lib/clawrouter-client.js +148 -0
  44. package/dist/lib/code-asset-crystalliser.d.ts +41 -0
  45. package/dist/lib/code-asset-crystalliser.js +181 -0
  46. package/dist/lib/code-failure-logger.d.ts +27 -0
  47. package/dist/lib/code-failure-logger.js +42 -0
  48. package/dist/lib/cto-approval-gate.d.ts +45 -0
  49. package/dist/lib/cto-approval-gate.js +478 -0
  50. package/dist/lib/cto-gate-types.d.ts +28 -0
  51. package/dist/lib/cto-gate-types.js +8 -0
  52. package/dist/lib/decomposer-feedback.d.ts +54 -0
  53. package/dist/lib/decomposer-feedback.js +115 -0
  54. package/dist/lib/emotional-safety-gate.d.ts +48 -0
  55. package/dist/lib/emotional-safety-gate.js +97 -0
  56. package/dist/lib/engine-paths.d.ts +13 -0
  57. package/dist/lib/engine-paths.js +32 -0
  58. package/dist/lib/event-bus-listener.d.ts +8 -0
  59. package/dist/lib/event-bus-listener.js +144 -0
  60. package/dist/lib/event-bus-publisher.d.ts +25 -0
  61. package/dist/lib/event-bus-publisher.js +188 -0
  62. package/dist/lib/event-bus-types.d.ts +73 -0
  63. package/dist/lib/event-bus-types.js +23 -0
  64. package/dist/lib/failure-library.d.ts +178 -0
  65. package/dist/lib/failure-library.js +349 -0
  66. package/dist/lib/ksl/error-log.d.ts +28 -0
  67. package/dist/lib/ksl/error-log.js +43 -0
  68. package/dist/lib/ksl/index.d.ts +9 -0
  69. package/dist/lib/ksl/index.js +25 -0
  70. package/dist/lib/ksl/orchestrator-tap.d.ts +16 -0
  71. package/dist/lib/ksl/orchestrator-tap.js +85 -0
  72. package/dist/lib/ksl/record-writer.d.ts +46 -0
  73. package/dist/lib/ksl/record-writer.js +45 -0
  74. package/dist/lib/llm-cost-table.d.ts +36 -0
  75. package/dist/lib/llm-cost-table.js +90 -0
  76. package/dist/lib/local-model-router.d.ts +27 -0
  77. package/dist/lib/local-model-router.js +61 -0
  78. package/dist/lib/mc-client.d.ts +51 -0
  79. package/dist/lib/mc-client.js +249 -0
  80. package/dist/lib/model-router-contract.d.ts +91 -0
  81. package/dist/lib/model-router-contract.js +19 -0
  82. package/dist/lib/model-router-registry.d.ts +24 -0
  83. package/dist/lib/model-router-registry.js +52 -0
  84. package/dist/lib/model-router.d.ts +20 -0
  85. package/dist/lib/model-router.js +79 -0
  86. package/dist/lib/monotask-state-machine.d.ts +19 -0
  87. package/dist/lib/monotask-state-machine.js +131 -0
  88. package/dist/lib/neutral-prompt-checker.d.ts +22 -0
  89. package/dist/lib/neutral-prompt-checker.js +130 -0
  90. package/dist/lib/notion-direct.d.ts +92 -0
  91. package/dist/lib/notion-direct.js +381 -0
  92. package/dist/lib/ollama-client.d.ts +37 -0
  93. package/dist/lib/ollama-client.js +158 -0
  94. package/dist/lib/omel/credential-vault.d.ts +57 -0
  95. package/dist/lib/omel/credential-vault.js +324 -0
  96. package/dist/lib/omel/human-brake.d.ts +32 -0
  97. package/dist/lib/omel/human-brake.js +289 -0
  98. package/dist/lib/omel/index.d.ts +10 -0
  99. package/dist/lib/omel/index.js +26 -0
  100. package/dist/lib/omel/phantom-workspace.d.ts +31 -0
  101. package/dist/lib/omel/phantom-workspace.js +256 -0
  102. package/dist/lib/omel/wipe-witness.d.ts +75 -0
  103. package/dist/lib/omel/wipe-witness.js +398 -0
  104. package/dist/lib/orchestrate-engine.d.ts +25 -0
  105. package/dist/lib/orchestrate-engine.js +4436 -0
  106. package/dist/lib/perm-judge.d.ts +46 -0
  107. package/dist/lib/perm-judge.js +173 -0
  108. package/dist/lib/plumber/conformance.d.ts +54 -0
  109. package/dist/lib/plumber/conformance.js +121 -0
  110. package/dist/lib/plumber/index.d.ts +9 -0
  111. package/dist/lib/plumber/index.js +25 -0
  112. package/dist/lib/plumber/observer.d.ts +52 -0
  113. package/dist/lib/plumber/observer.js +180 -0
  114. package/dist/lib/plumber/types.d.ts +78 -0
  115. package/dist/lib/plumber/types.js +29 -0
  116. package/dist/lib/research-impl-gate.d.ts +16 -0
  117. package/dist/lib/research-impl-gate.js +105 -0
  118. package/dist/lib/sherlock-memory.d.ts +29 -0
  119. package/dist/lib/sherlock-memory.js +105 -0
  120. package/dist/lib/skill-crystalliser.d.ts +44 -0
  121. package/dist/lib/skill-crystalliser.js +60 -0
  122. package/dist/lib/sprint-runner-engine.d.ts +27 -0
  123. package/dist/lib/sprint-runner-engine.js +1042 -0
  124. package/dist/lib/sprint-state.d.ts +71 -0
  125. package/dist/lib/sprint-state.js +202 -0
  126. package/dist/lib/stuck-handler.d.ts +17 -0
  127. package/dist/lib/stuck-handler.js +249 -0
  128. package/dist/lib/task-contract-checker.d.ts +17 -0
  129. package/dist/lib/task-contract-checker.js +29 -0
  130. package/dist/lib/task-router/index.d.ts +17 -0
  131. package/dist/lib/task-router/index.js +52 -0
  132. package/dist/lib/task-router/router/generate-execution-id.d.ts +10 -0
  133. package/dist/lib/task-router/router/generate-execution-id.js +24 -0
  134. package/dist/lib/task-router/router/resolve-route.d.ts +2 -0
  135. package/dist/lib/task-router/router/resolve-route.js +49 -0
  136. package/dist/lib/task-router/types.d.ts +79 -0
  137. package/dist/lib/task-router/types.js +39 -0
  138. package/dist/lib/token-budget-validator.d.ts +44 -0
  139. package/dist/lib/token-budget-validator.js +84 -0
  140. package/dist/lib/trust-score-updater.d.ts +30 -0
  141. package/dist/lib/trust-score-updater.js +107 -0
  142. package/dist/lib/wallet-state.d.ts +26 -0
  143. package/dist/lib/wallet-state.js +85 -0
  144. package/package.json +27 -0
@@ -0,0 +1,398 @@
1
+ "use strict";
2
+ // OMEL Wipe Witness — Sprint 178 + Sprint 183 Hardening (AMD-13)
3
+ // Detection layer for destructive agent writes and file deletions.
4
+ // Would have caught Sprint 171 qwen3:14b 2800-line file rewrites.
5
+ //
6
+ // Public API:
7
+ // beforeWrite(filePath, agentId) → WitnessToken (SHA-256 + size before write)
8
+ // afterWrite(token, newSizeBytes) → void (shrink alert if new < 50% old)
9
+ // beforeDelete(filePath, agentId) → void (log deletion event)
10
+ // getShrinkAlerts() → ShrinkAlert[]
11
+ // rollback(filePath, stepsBack?) → boolean (Sprint 183)
12
+ // integrityReport(scanDir) → IntegrityReport (Sprint 183)
13
+ //
14
+ // Sprint 183 hardening additions:
15
+ // - Last-3-state rollback: restore file to any of last 3 pre-write states
16
+ // - Auto-rollback on ShrinkAlert unless WIPE_WITNESS_NO_ROLLBACK=true
17
+ // - Nightly integrity report: scan agent files vs last known hashes
18
+ // - run-swarm.sh integration: pre-run snapshot + post-run drift report
19
+ //
20
+ // Audit log: logs/omel/wipe-witness-YYYY-MM-DD.jsonl
21
+ // Telegram: TELEGRAM_BOT_TOKEN / OWNER_TELEGRAM_CHAT_ID (fire-and-forget)
22
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ var desc = Object.getOwnPropertyDescriptor(m, k);
25
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
26
+ desc = { enumerable: true, get: function() { return m[k]; } };
27
+ }
28
+ Object.defineProperty(o, k2, desc);
29
+ }) : (function(o, m, k, k2) {
30
+ if (k2 === undefined) k2 = k;
31
+ o[k2] = m[k];
32
+ }));
33
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
34
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
35
+ }) : function(o, v) {
36
+ o["default"] = v;
37
+ });
38
+ var __importStar = (this && this.__importStar) || (function () {
39
+ var ownKeys = function(o) {
40
+ ownKeys = Object.getOwnPropertyNames || function (o) {
41
+ var ar = [];
42
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
43
+ return ar;
44
+ };
45
+ return ownKeys(o);
46
+ };
47
+ return function (mod) {
48
+ if (mod && mod.__esModule) return mod;
49
+ var result = {};
50
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
51
+ __setModuleDefault(result, mod);
52
+ return result;
53
+ };
54
+ })();
55
+ Object.defineProperty(exports, "__esModule", { value: true });
56
+ exports.wipeWitness = exports.WipeWitness = void 0;
57
+ const fs = __importStar(require("fs"));
58
+ const path = __importStar(require("path"));
59
+ const engine_paths_1 = require("../engine-paths");
60
+ const https = __importStar(require("https"));
61
+ const crypto_1 = require("crypto");
62
+ const LOGS_DIR = path.join((0, engine_paths_1.resolveEnginePaths)().root, 'logs', 'omel');
63
+ const SNAPSHOTS_DIR = path.join(LOGS_DIR, 'wipe-witness-snapshots');
64
+ const HASHES_FILE = path.join(LOGS_DIR, 'wipe-witness-hashes.json');
65
+ fs.mkdirSync(LOGS_DIR, { recursive: true });
66
+ fs.mkdirSync(SNAPSHOTS_DIR, { recursive: true });
67
+ const LOG_FILE = () => {
68
+ const date = new Date().toISOString().slice(0, 10);
69
+ return path.join(LOGS_DIR, `wipe-witness-${date}.jsonl`);
70
+ };
71
+ // ── Internal helpers ──────────────────────────────────────────────────────────
72
+ function appendLog(entry) {
73
+ try {
74
+ fs.appendFileSync(LOG_FILE(), JSON.stringify(entry) + '\n');
75
+ }
76
+ catch { /* never crash caller */ }
77
+ }
78
+ function sha256File(filePath) {
79
+ try {
80
+ const data = fs.readFileSync(filePath);
81
+ return (0, crypto_1.createHash)('sha256').update(data).digest('hex');
82
+ }
83
+ catch {
84
+ return '';
85
+ }
86
+ }
87
+ function sha256Buf(buf) {
88
+ return (0, crypto_1.createHash)('sha256').update(buf).digest('hex');
89
+ }
90
+ function sendTelegramAlert(message) {
91
+ const botToken = process.env.TELEGRAM_BOT_TOKEN || '';
92
+ const chatId = process.env.OWNER_TELEGRAM_CHAT_ID || '';
93
+ if (!botToken || !chatId)
94
+ return; // silently skip if not configured
95
+ const payload = JSON.stringify({ chat_id: chatId, text: message, parse_mode: 'Markdown' });
96
+ try {
97
+ const req = https.request({
98
+ hostname: 'api.telegram.org',
99
+ path: `/bot${botToken}/sendMessage`,
100
+ method: 'POST',
101
+ headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) },
102
+ });
103
+ req.on('error', () => { }); // fire-and-forget, never crash server
104
+ req.write(payload);
105
+ req.end();
106
+ }
107
+ catch { /* silent */ }
108
+ }
109
+ function loadSnapshotStore() {
110
+ const storePath = path.join(SNAPSHOTS_DIR, 'index.json');
111
+ try {
112
+ if (fs.existsSync(storePath)) {
113
+ return JSON.parse(fs.readFileSync(storePath, 'utf-8'));
114
+ }
115
+ }
116
+ catch { /* ignore */ }
117
+ return {};
118
+ }
119
+ function saveSnapshotStore(store) {
120
+ const storePath = path.join(SNAPSHOTS_DIR, 'index.json');
121
+ try {
122
+ fs.writeFileSync(storePath, JSON.stringify(store, null, 2), 'utf-8');
123
+ }
124
+ catch { /* non-fatal */ }
125
+ }
126
+ function snapshotFile(filePath) {
127
+ try {
128
+ if (!fs.existsSync(filePath))
129
+ return null;
130
+ const data = fs.readFileSync(filePath);
131
+ const hash = sha256Buf(data);
132
+ const key = Buffer.from(filePath).toString('base64').replace(/[/+=]/g, '_');
133
+ const ts = Date.now();
134
+ const snapName = `${key}-${ts}.snap`;
135
+ const snapPath = path.join(SNAPSHOTS_DIR, snapName);
136
+ fs.writeFileSync(snapPath, data);
137
+ return {
138
+ snapshotPath: snapPath,
139
+ hash,
140
+ sizeBytes: data.length,
141
+ savedAt: new Date(ts).toISOString(),
142
+ };
143
+ }
144
+ catch {
145
+ return null;
146
+ }
147
+ }
148
+ function saveSnapshot(filePath) {
149
+ const store = loadSnapshotStore();
150
+ const snap = snapshotFile(filePath);
151
+ if (!snap)
152
+ return null;
153
+ if (!store[filePath])
154
+ store[filePath] = [];
155
+ store[filePath].unshift(snap); // newest first
156
+ // Keep only last 3
157
+ const evicted = store[filePath].splice(3);
158
+ for (const old of evicted) {
159
+ try {
160
+ fs.unlinkSync(old.snapshotPath);
161
+ }
162
+ catch { /* ok */ }
163
+ }
164
+ saveSnapshotStore(store);
165
+ return snap.snapshotPath;
166
+ }
167
+ function loadHashStore() {
168
+ try {
169
+ if (fs.existsSync(HASHES_FILE)) {
170
+ return JSON.parse(fs.readFileSync(HASHES_FILE, 'utf-8'));
171
+ }
172
+ }
173
+ catch { /* ignore */ }
174
+ return {};
175
+ }
176
+ function saveHashStore(store) {
177
+ try {
178
+ fs.writeFileSync(HASHES_FILE, JSON.stringify(store, null, 2), 'utf-8');
179
+ }
180
+ catch { /* non-fatal */ }
181
+ }
182
+ // ── WipeWitness class ─────────────────────────────────────────────────────────
183
+ class WipeWitness {
184
+ shrinkAlerts = [];
185
+ /**
186
+ * Capture SHA-256 hash + size of file before write.
187
+ * Saves a snapshot for rollback (last 3 states).
188
+ * If file does not exist (new file): returns token with oldSizeBytes=0 and oldHash=''.
189
+ */
190
+ beforeWrite(filePath, agentId) {
191
+ const exists = fs.existsSync(filePath);
192
+ const snapshotKey = exists ? (saveSnapshot(filePath) ?? undefined) : undefined;
193
+ const token = {
194
+ filePath,
195
+ agentId,
196
+ oldHash: exists ? sha256File(filePath) : '',
197
+ oldSizeBytes: exists ? fs.statSync(filePath).size : 0,
198
+ createdAt: new Date().toISOString(),
199
+ snapshotKey,
200
+ };
201
+ appendLog({ event: 'before_write', ...token });
202
+ return token;
203
+ }
204
+ /**
205
+ * Compare new size against old size.
206
+ * If new_size < 0.5 * old_size → emit ShrinkAlert + Telegram notification.
207
+ * Auto-rollback unless WIPE_WITNESS_NO_ROLLBACK=true.
208
+ * Skips shrink check if oldSizeBytes === 0 (new file creation).
209
+ */
210
+ afterWrite(token, newSizeBytes) {
211
+ appendLog({
212
+ event: 'after_write',
213
+ filePath: token.filePath,
214
+ agentId: token.agentId,
215
+ oldSizeBytes: token.oldSizeBytes,
216
+ newSizeBytes,
217
+ ts: new Date().toISOString(),
218
+ });
219
+ if (token.oldSizeBytes === 0)
220
+ return; // new file — no baseline to compare
221
+ const ratio = newSizeBytes / token.oldSizeBytes;
222
+ if (newSizeBytes < 0.5 * token.oldSizeBytes) {
223
+ let rolledBack = false;
224
+ // Auto-rollback unless disabled
225
+ if (process.env.WIPE_WITNESS_NO_ROLLBACK !== 'true' && token.snapshotKey) {
226
+ try {
227
+ fs.copyFileSync(token.snapshotKey, token.filePath);
228
+ rolledBack = true;
229
+ appendLog({
230
+ event: 'auto_rollback',
231
+ filePath: token.filePath,
232
+ agentId: token.agentId,
233
+ from: token.snapshotKey,
234
+ ts: new Date().toISOString(),
235
+ });
236
+ }
237
+ catch (err) {
238
+ appendLog({
239
+ event: 'auto_rollback_failed',
240
+ filePath: token.filePath,
241
+ error: err.message,
242
+ ts: new Date().toISOString(),
243
+ });
244
+ }
245
+ }
246
+ const alert = {
247
+ filePath: token.filePath,
248
+ agentId: token.agentId,
249
+ oldSizeBytes: token.oldSizeBytes,
250
+ newSizeBytes,
251
+ ratio,
252
+ ts: new Date().toISOString(),
253
+ rolledBack,
254
+ };
255
+ this.shrinkAlerts.push(alert);
256
+ appendLog({ event: 'shrink_alert', ...alert });
257
+ const pct = (ratio * 100).toFixed(1);
258
+ sendTelegramAlert(`⚠️ *[OMEL WipeWitness] Shrink Alert*\n` +
259
+ `File: \`${token.filePath}\`\n` +
260
+ `Agent: ${token.agentId}\n` +
261
+ `${token.oldSizeBytes} bytes → ${newSizeBytes} bytes (${pct}% of original)\n` +
262
+ `Threshold: <50% triggers alert\n` +
263
+ (rolledBack
264
+ ? `✅ Auto-rolled back to previous state.`
265
+ : `⚠️ Auto-rollback skipped (WIPE_WITNESS_NO_ROLLBACK=true or no snapshot).`));
266
+ }
267
+ }
268
+ /**
269
+ * Log a deletion event before the file is removed.
270
+ * Captures hash + size for audit trail.
271
+ */
272
+ beforeDelete(filePath, agentId) {
273
+ const exists = fs.existsSync(filePath);
274
+ appendLog({
275
+ event: 'before_delete',
276
+ filePath,
277
+ agentId,
278
+ sizeBytes: exists ? fs.statSync(filePath).size : 0,
279
+ hash: exists ? sha256File(filePath) : '',
280
+ ts: new Date().toISOString(),
281
+ });
282
+ }
283
+ /**
284
+ * Return all shrink alerts accumulated in this session.
285
+ */
286
+ getShrinkAlerts() {
287
+ return [...this.shrinkAlerts];
288
+ }
289
+ /**
290
+ * Restore a file to a previous state (one of last 3 snapshots).
291
+ * @param filePath Absolute path to the file to restore
292
+ * @param stepsBack 1 = most recent snapshot, 2 = second most recent, 3 = oldest. Default 1.
293
+ * @returns true if rollback succeeded, false otherwise.
294
+ */
295
+ rollback(filePath, stepsBack = 1) {
296
+ const store = loadSnapshotStore();
297
+ const snaps = store[filePath];
298
+ if (!snaps || snaps.length === 0) {
299
+ appendLog({ event: 'rollback_no_snapshot', filePath, stepsBack, ts: new Date().toISOString() });
300
+ return false;
301
+ }
302
+ const idx = Math.min(stepsBack - 1, snaps.length - 1);
303
+ const snap = snaps[idx];
304
+ try {
305
+ fs.copyFileSync(snap.snapshotPath, filePath);
306
+ appendLog({
307
+ event: 'rollback',
308
+ filePath,
309
+ stepsBack,
310
+ snapshotPath: snap.snapshotPath,
311
+ savedAt: snap.savedAt,
312
+ ts: new Date().toISOString(),
313
+ });
314
+ return true;
315
+ }
316
+ catch (err) {
317
+ appendLog({
318
+ event: 'rollback_failed',
319
+ filePath,
320
+ stepsBack,
321
+ error: err.message,
322
+ ts: new Date().toISOString(),
323
+ });
324
+ return false;
325
+ }
326
+ }
327
+ /**
328
+ * Take a hash snapshot of all .ts files in a directory.
329
+ * Returns a HashStore map for later comparison.
330
+ * Used by run-swarm.sh pre-run.
331
+ */
332
+ snapshotDir(scanDir) {
333
+ const store = {};
334
+ function walk(dir) {
335
+ try {
336
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
337
+ const full = path.join(dir, entry.name);
338
+ if (entry.isDirectory() && entry.name !== 'node_modules' && entry.name !== '.git') {
339
+ walk(full);
340
+ }
341
+ else if (entry.isFile() && entry.name.endsWith('.ts')) {
342
+ const rel = path.relative(scanDir, full);
343
+ store[rel] = sha256File(full);
344
+ }
345
+ }
346
+ }
347
+ catch { /* skip unreadable dirs */ }
348
+ }
349
+ walk(scanDir);
350
+ saveHashStore(store);
351
+ appendLog({ event: 'snapshot_taken', scan_dir: scanDir, file_count: Object.keys(store).length, ts: new Date().toISOString() });
352
+ return store;
353
+ }
354
+ /**
355
+ * Nightly integrity report: compare current file hashes vs last snapshot.
356
+ * Returns drifted, new, and deleted files.
357
+ */
358
+ integrityReport(scanDir) {
359
+ const oldStore = loadHashStore();
360
+ const newStore = this.snapshotDir(scanDir);
361
+ const ts = new Date().toISOString();
362
+ const drifted = [];
363
+ const newFiles = [];
364
+ const delFiles = [];
365
+ for (const [file, newHash] of Object.entries(newStore)) {
366
+ if (!oldStore[file]) {
367
+ newFiles.push(file);
368
+ }
369
+ else if (oldStore[file] !== newHash) {
370
+ drifted.push({ file, old_hash: oldStore[file], new_hash: newHash });
371
+ }
372
+ }
373
+ for (const file of Object.keys(oldStore)) {
374
+ if (!newStore[file])
375
+ delFiles.push(file);
376
+ }
377
+ const report = {
378
+ ts,
379
+ scan_dir: scanDir,
380
+ total_files: Object.keys(newStore).length,
381
+ drifted,
382
+ new_files: newFiles,
383
+ deleted_files: delFiles,
384
+ };
385
+ appendLog({ event: 'integrity_report', ...report });
386
+ if (drifted.length > 0 || delFiles.length > 0) {
387
+ sendTelegramAlert(`🔍 *[OMEL WipeWitness] Integrity Drift*\n` +
388
+ `Drifted: ${drifted.length} files\n` +
389
+ `Deleted: ${delFiles.length} files\n` +
390
+ `New: ${newFiles.length} files\n` +
391
+ `Run: \`npx ts-node scripts/lib/omel/wipe-witness.ts report\` for details.`);
392
+ }
393
+ return report;
394
+ }
395
+ }
396
+ exports.WipeWitness = WipeWitness;
397
+ // Exported singleton
398
+ exports.wipeWitness = new WipeWitness();
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ts-node
2
+ /**
3
+ * Invoica Agent Orchestrator v2
4
+ *
5
+ * Dynamic Agent Architecture:
6
+ * Leadership (Claude via Anthropic API):
7
+ * - CEO: Sprint planning, strategy, decisions, daily reports
8
+ * - Supervisor 1: Code review & quality gate (DeepSeek via ClawRouter,
9
+ * Claude Sonnet 4.6 for high-stakes; was OpenAI Codex originally)
10
+ * - Supervisor 2: Code review & quality gate (Claude Haiku 4.5,
11
+ * DeepSeek via ClawRouter as drain fallback; was OpenAI Codex originally)
12
+ * - Skills: Agent/skill factory
13
+ * Marketing (Manus AI — runs independently):
14
+ * - CMO: Brand strategy, market intelligence, product proposals (reports loaded from files)
15
+ * Technology (MiniMax M2.5):
16
+ * - CTO: Data-driven analysis, OpenClaw/ClawHub monitoring, agent spawning proposals
17
+ * Execution (MiniMax M2.5 — dynamically loaded from agents/ directory):
18
+ * - Coding agents auto-discovered from agents/{name}/prompt.md
19
+ * - New agents created by CTO proposals + CEO approval
20
+ *
21
+ * Flow: CEO plans → MiniMax codes → Dual Supervisor review (DeepSeek + Haiku)
22
+ * → CEO resolves conflicts → CTO analyzes → CMO reports → CEO daily report
23
+ */
24
+ declare function main(): Promise<void>;
25
+ export { main as runOrchestrator };