@jungjaehoon/mama-os 0.20.1 → 0.21.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.
- package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
- package/dist/agent/code-act/host-bridge.js +14 -3
- package/dist/agent/code-act/host-bridge.js.map +1 -1
- package/dist/agent/gateway-tool-executor.d.ts +8 -10
- package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
- package/dist/agent/gateway-tool-executor.js +201 -28
- package/dist/agent/gateway-tool-executor.js.map +1 -1
- package/dist/agent/gateway-tools.md +1 -1
- package/dist/agent/os-agent-capabilities.md +13 -12
- package/dist/agent/tool-registry.js +1 -1
- package/dist/agent/tool-registry.js.map +1 -1
- package/dist/agent/types.d.ts +4 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/api/graph-api.d.ts.map +1 -1
- package/dist/api/graph-api.js +78 -5
- package/dist/api/graph-api.js.map +1 -1
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +5 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/operator-handler.d.ts +17 -0
- package/dist/api/operator-handler.d.ts.map +1 -0
- package/dist/api/operator-handler.js +88 -0
- package/dist/api/operator-handler.js.map +1 -0
- package/dist/api/report-handler.d.ts +7 -0
- package/dist/api/report-handler.d.ts.map +1 -1
- package/dist/api/report-handler.js +30 -0
- package/dist/api/report-handler.js.map +1 -1
- package/dist/api/report-persistence.d.ts +17 -0
- package/dist/api/report-persistence.d.ts.map +1 -0
- package/dist/api/report-persistence.js +91 -0
- package/dist/api/report-persistence.js.map +1 -0
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +351 -249
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/config/config-manager.d.ts.map +1 -1
- package/dist/cli/config/config-manager.js +93 -55
- package/dist/cli/config/config-manager.js.map +1 -1
- package/dist/cli/config/types.d.ts +17 -2
- package/dist/cli/config/types.d.ts.map +1 -1
- package/dist/cli/config/types.js +4 -0
- package/dist/cli/config/types.js.map +1 -1
- package/dist/cli/runtime/agent-loop-init.d.ts +1 -0
- package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
- package/dist/cli/runtime/agent-loop-init.js +1 -0
- package/dist/cli/runtime/agent-loop-init.js.map +1 -1
- package/dist/cli/runtime/api-routes-init.d.ts.map +1 -1
- package/dist/cli/runtime/api-routes-init.js +386 -258
- package/dist/cli/runtime/api-routes-init.js.map +1 -1
- package/dist/cli/runtime/api-server-init.d.ts.map +1 -1
- package/dist/cli/runtime/api-server-init.js +12 -7
- package/dist/cli/runtime/api-server-init.js.map +1 -1
- package/dist/cli/runtime/connector-init.d.ts +19 -1
- package/dist/cli/runtime/connector-init.d.ts.map +1 -1
- package/dist/cli/runtime/connector-init.js +32 -2
- package/dist/cli/runtime/connector-init.js.map +1 -1
- package/dist/cli/runtime/message-router-config.d.ts +4 -0
- package/dist/cli/runtime/message-router-config.d.ts.map +1 -0
- package/dist/cli/runtime/message-router-config.js +11 -0
- package/dist/cli/runtime/message-router-config.js.map +1 -0
- package/dist/cli/runtime/scheduler-init.d.ts.map +1 -1
- package/dist/cli/runtime/scheduler-init.js +12 -12
- package/dist/cli/runtime/scheduler-init.js.map +1 -1
- package/dist/connectors/framework/polling-scheduler.d.ts.map +1 -1
- package/dist/connectors/framework/polling-scheduler.js +53 -2
- package/dist/connectors/framework/polling-scheduler.js.map +1 -1
- package/dist/connectors/kagemusha/query-tools.d.ts.map +1 -1
- package/dist/connectors/kagemusha/query-tools.js +14 -3
- package/dist/connectors/kagemusha/query-tools.js.map +1 -1
- package/dist/db/migrations/wiki-artifacts.d.ts +3 -0
- package/dist/db/migrations/wiki-artifacts.d.ts.map +1 -0
- package/dist/db/migrations/wiki-artifacts.js +24 -0
- package/dist/db/migrations/wiki-artifacts.js.map +1 -0
- package/dist/gateways/message-router.d.ts.map +1 -1
- package/dist/gateways/message-router.js +15 -3
- package/dist/gateways/message-router.js.map +1 -1
- package/dist/gateways/types.d.ts +4 -0
- package/dist/gateways/types.d.ts.map +1 -1
- package/dist/multi-agent/agent-event-bus.d.ts +10 -0
- package/dist/multi-agent/agent-event-bus.d.ts.map +1 -1
- package/dist/multi-agent/agent-event-bus.js +34 -0
- package/dist/multi-agent/agent-event-bus.js.map +1 -1
- package/dist/multi-agent/conductor-persona.js +2 -2
- package/dist/multi-agent/dashboard-agent-persona.d.ts +6 -2
- package/dist/multi-agent/dashboard-agent-persona.d.ts.map +1 -1
- package/dist/multi-agent/dashboard-agent-persona.js +53 -33
- package/dist/multi-agent/dashboard-agent-persona.js.map +1 -1
- package/dist/multi-agent/memory-agent-persona.d.ts +1 -1
- package/dist/multi-agent/memory-agent-persona.d.ts.map +1 -1
- package/dist/multi-agent/memory-agent-persona.js +25 -4
- package/dist/multi-agent/memory-agent-persona.js.map +1 -1
- package/dist/multi-agent/types.d.ts +1 -1
- package/dist/multi-agent/wiki-agent-persona.d.ts +7 -1
- package/dist/multi-agent/wiki-agent-persona.d.ts.map +1 -1
- package/dist/multi-agent/wiki-agent-persona.js +82 -68
- package/dist/multi-agent/wiki-agent-persona.js.map +1 -1
- package/dist/operator/board-slot-instructions.d.ts +18 -0
- package/dist/operator/board-slot-instructions.d.ts.map +1 -0
- package/dist/operator/board-slot-instructions.js +52 -0
- package/dist/operator/board-slot-instructions.js.map +1 -0
- package/dist/operator/connector-delta-repo.d.ts +33 -0
- package/dist/operator/connector-delta-repo.d.ts.map +1 -0
- package/dist/operator/connector-delta-repo.js +0 -0
- package/dist/operator/connector-delta-repo.js.map +1 -0
- package/dist/operator/mama-memory-port.d.ts +13 -0
- package/dist/operator/mama-memory-port.d.ts.map +1 -0
- package/dist/operator/mama-memory-port.js +35 -0
- package/dist/operator/mama-memory-port.js.map +1 -0
- package/dist/operator/operator-interfaces.d.ts +136 -0
- package/dist/operator/operator-interfaces.d.ts.map +1 -0
- package/dist/operator/operator-interfaces.js +15 -0
- package/dist/operator/operator-interfaces.js.map +1 -0
- package/dist/operator/operator-trigger-loop.d.ts +106 -0
- package/dist/operator/operator-trigger-loop.d.ts.map +1 -0
- package/dist/operator/operator-trigger-loop.js +228 -0
- package/dist/operator/operator-trigger-loop.js.map +1 -0
- package/dist/operator/report-run.d.ts +78 -0
- package/dist/operator/report-run.d.ts.map +1 -0
- package/dist/operator/report-run.js +141 -0
- package/dist/operator/report-run.js.map +1 -0
- package/dist/operator/report-scheduler.d.ts +43 -0
- package/dist/operator/report-scheduler.d.ts.map +1 -0
- package/dist/operator/report-scheduler.js +87 -0
- package/dist/operator/report-scheduler.js.map +1 -0
- package/dist/operator/situation-report.d.ts +86 -0
- package/dist/operator/situation-report.d.ts.map +1 -0
- package/dist/operator/situation-report.js +211 -0
- package/dist/operator/situation-report.js.map +1 -0
- package/dist/operator/trigger-author.d.ts +45 -0
- package/dist/operator/trigger-author.d.ts.map +1 -0
- package/dist/operator/trigger-author.js +217 -0
- package/dist/operator/trigger-author.js.map +1 -0
- package/dist/operator/trigger-evolve.d.ts +31 -0
- package/dist/operator/trigger-evolve.d.ts.map +1 -0
- package/dist/operator/trigger-evolve.js +51 -0
- package/dist/operator/trigger-evolve.js.map +1 -0
- package/dist/operator/trigger-fire.d.ts +29 -0
- package/dist/operator/trigger-fire.d.ts.map +1 -0
- package/dist/operator/trigger-fire.js +41 -0
- package/dist/operator/trigger-fire.js.map +1 -0
- package/dist/operator/trigger-matcher.d.ts +19 -0
- package/dist/operator/trigger-matcher.d.ts.map +1 -0
- package/dist/operator/trigger-matcher.js +61 -0
- package/dist/operator/trigger-matcher.js.map +1 -0
- package/dist/operator/trigger-registry.d.ts +36 -0
- package/dist/operator/trigger-registry.d.ts.map +1 -0
- package/dist/operator/trigger-registry.js +135 -0
- package/dist/operator/trigger-registry.js.map +1 -0
- package/dist/operator/trigger-review.d.ts +23 -0
- package/dist/operator/trigger-review.d.ts.map +1 -0
- package/dist/operator/trigger-review.js +127 -0
- package/dist/operator/trigger-review.js.map +1 -0
- package/dist/operator/trigger-types.d.ts +84 -0
- package/dist/operator/trigger-types.d.ts.map +1 -0
- package/dist/operator/trigger-types.js +14 -0
- package/dist/operator/trigger-types.js.map +1 -0
- package/dist/scheduler/cron-worker.d.ts.map +1 -1
- package/dist/scheduler/cron-worker.js +3 -1
- package/dist/scheduler/cron-worker.js.map +1 -1
- package/dist/security/security-monitor.d.ts.map +1 -1
- package/dist/security/security-monitor.js +1 -0
- package/dist/security/security-monitor.js.map +1 -1
- package/dist/wiki/obsidian-writer.d.ts +1 -1
- package/dist/wiki/obsidian-writer.d.ts.map +1 -1
- package/dist/wiki/obsidian-writer.js +67 -27
- package/dist/wiki/obsidian-writer.js.map +1 -1
- package/dist/wiki/path-safety.d.ts +2 -0
- package/dist/wiki/path-safety.d.ts.map +1 -0
- package/dist/wiki/path-safety.js +40 -0
- package/dist/wiki/path-safety.js.map +1 -0
- package/dist/wiki/types.d.ts +4 -2
- package/dist/wiki/types.d.ts.map +1 -1
- package/dist/wiki/types.js +1 -1
- package/dist/wiki/types.js.map +1 -1
- package/dist/wiki-artifacts/normalization.d.ts +8 -0
- package/dist/wiki-artifacts/normalization.d.ts.map +1 -0
- package/dist/wiki-artifacts/normalization.js +41 -0
- package/dist/wiki-artifacts/normalization.js.map +1 -0
- package/dist/wiki-artifacts/types.d.ts +52 -0
- package/dist/wiki-artifacts/types.d.ts.map +1 -0
- package/dist/wiki-artifacts/types.js +3 -0
- package/dist/wiki-artifacts/types.js.map +1 -0
- package/dist/wiki-artifacts/wiki-publish-adapter.d.ts +14 -0
- package/dist/wiki-artifacts/wiki-publish-adapter.d.ts.map +1 -0
- package/dist/wiki-artifacts/wiki-publish-adapter.js +71 -0
- package/dist/wiki-artifacts/wiki-publish-adapter.js.map +1 -0
- package/package.json +5 -3
- package/public/ui/assets/index-BDsaQNGd.js +62 -0
- package/public/ui/assets/index-C4URnm_X.css +1 -0
- package/public/ui/index.html +13 -0
- package/public/viewer/js/utils/api.js +2 -2
- package/public/viewer/src/utils/api.ts +9 -2
- package/public/viewer/sw.js +1 -1
- package/public/viewer/viewer.html +6 -0
|
@@ -200,46 +200,43 @@ async function registerApiRoutes(params) {
|
|
|
200
200
|
}
|
|
201
201
|
// Wire EventBus to tool executor for agent_notices tool
|
|
202
202
|
toolExecutor.setAgentEventBus(eventBus);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
routesLogger.debug(`[Report] Agent published briefing slot`);
|
|
221
|
-
eventBus.emit({
|
|
222
|
-
type: 'agent:action',
|
|
223
|
-
agent: 'dashboard-agent',
|
|
224
|
-
action: 'publish',
|
|
225
|
-
target: 'briefing',
|
|
226
|
-
});
|
|
227
|
-
});
|
|
228
|
-
// ── Conductor Persona (section injection — non-destructive) ────────
|
|
229
|
-
const { ensureConductorPersona } = await import('../../multi-agent/conductor-persona.js');
|
|
230
|
-
ensureConductorPersona();
|
|
231
|
-
// ── Dashboard Agent ─────────────────────────────────────────────────
|
|
232
|
-
const { ensureDashboardPersona } = await import('../../multi-agent/dashboard-agent-persona.js');
|
|
233
|
-
ensureDashboardPersona();
|
|
234
|
-
routesLogger.debug('[Dashboard Agent] Persona ensured at ~/.mama/personas/dashboard.md');
|
|
235
|
-
// Merge code-act MCP server into mama-mcp-config.json
|
|
236
|
-
// Makes code_act available to all CLI processes (AgentProcessManager agents)
|
|
203
|
+
const hasEnabledAgentConfig = (agentId) => {
|
|
204
|
+
const agentConfig = config.multi_agent?.agents?.[agentId];
|
|
205
|
+
return Boolean(agentConfig && agentConfig.enabled !== false);
|
|
206
|
+
};
|
|
207
|
+
// ── Report Slots + legacy dashboard/wiki fanout ───────────────────────
|
|
208
|
+
const dashboardAgentConfigured = hasEnabledAgentConfig('dashboard-agent');
|
|
209
|
+
const wikiAgentConfigured = hasEnabledAgentConfig('wiki-agent');
|
|
210
|
+
// Manual refresh endpoint (kept for compatibility)
|
|
211
|
+
apiServer.app.post('/api/report/refresh', auth_middleware_js_1.requireAuth, (_req, res) => {
|
|
212
|
+
res.json({ ok: true, message: 'Viewer now renders data directly from Intelligence API' });
|
|
213
|
+
});
|
|
214
|
+
// ── Conductor Persona (section injection — non-destructive) ────────
|
|
215
|
+
const { ensureConductorPersona } = await import('../../multi-agent/conductor-persona.js');
|
|
216
|
+
ensureConductorPersona();
|
|
217
|
+
if (dashboardAgentConfigured || wikiAgentConfigured) {
|
|
218
|
+
// Merge code-act MCP server into mama-mcp-config.json.
|
|
219
|
+
// Makes code_act available to configured legacy self-paced agents.
|
|
237
220
|
const codeActServerPath = node_path_1.default.join(__dirname, '../../mcp/code-act-server.js');
|
|
238
221
|
try {
|
|
239
222
|
const mamaMcpConfigPath = node_path_1.default.join((0, node_os_1.homedir)(), '.mama', 'mama-mcp-config.json');
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
223
|
+
let existing = { mcpServers: {} };
|
|
224
|
+
if ((0, node_fs_1.existsSync)(mamaMcpConfigPath)) {
|
|
225
|
+
try {
|
|
226
|
+
const parsedConfig = JSON.parse((0, node_fs_1.readFileSync)(mamaMcpConfigPath, 'utf-8'));
|
|
227
|
+
if (parsedConfig && typeof parsedConfig === 'object' && !Array.isArray(parsedConfig)) {
|
|
228
|
+
existing = parsedConfig;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch (parseErr) {
|
|
232
|
+
routesLogger.warn('[api-routes-init] Invalid MCP config JSON; recreating code-act entry:', parseErr);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (!existing.mcpServers ||
|
|
236
|
+
typeof existing.mcpServers !== 'object' ||
|
|
237
|
+
Array.isArray(existing.mcpServers)) {
|
|
238
|
+
existing.mcpServers = {};
|
|
239
|
+
}
|
|
243
240
|
existing.mcpServers['code-act'] = {
|
|
244
241
|
command: 'node',
|
|
245
242
|
args: [codeActServerPath],
|
|
@@ -251,6 +248,19 @@ async function registerApiRoutes(params) {
|
|
|
251
248
|
catch (err) {
|
|
252
249
|
routesLogger.warn('[api-routes-init] Failed to merge code-act into MCP config:', err);
|
|
253
250
|
}
|
|
251
|
+
}
|
|
252
|
+
// report_publish is a core surface (feeds the /ui operator board), not a
|
|
253
|
+
// multi-agent feature: wire it unconditionally. All slot ids are accepted;
|
|
254
|
+
// size/count caps and loud logging live in createReportPublisher.
|
|
255
|
+
{
|
|
256
|
+
const { createReportPublisher } = await import('../../api/report-handler.js');
|
|
257
|
+
toolExecutor.setReportPublisher(createReportPublisher(apiServer.reportStore, apiServer.reportSseClients));
|
|
258
|
+
}
|
|
259
|
+
if (dashboardAgentConfigured) {
|
|
260
|
+
// ── Dashboard Agent ───────────────────────────────────────────────
|
|
261
|
+
const { ensureDashboardPersona } = await import('../../multi-agent/dashboard-agent-persona.js');
|
|
262
|
+
ensureDashboardPersona();
|
|
263
|
+
routesLogger.debug('[Dashboard Agent] Persona ensured at ~/.mama/personas/dashboard.md');
|
|
254
264
|
// Dashboard cron: 30-min interval via AgentProcessManager
|
|
255
265
|
const dashboardPrompt = `You are triggered on a schedule. Before writing anything, determine if an update is needed:
|
|
256
266
|
|
|
@@ -260,279 +270,397 @@ async function registerApiRoutes(params) {
|
|
|
260
270
|
Do not include dashboard_briefing, wiki_compilation, system-audit, or audit-log labels in the context_compile task text; filter those operational summaries after the packet returns.
|
|
261
271
|
If context_compile is unavailable because there is no active worker envelope, fall back to mama_search once (limit 20).
|
|
262
272
|
3. If NO substantive decisions or agent alerts exist since the last dashboard publish → respond "NO_UPDATE" and stop. Do NOT call report_publish.
|
|
263
|
-
4. If new substantive information exists
|
|
273
|
+
4. If new substantive information exists -> analyze it and publish ALL FOUR board slots (briefing, action_required, decisions, pipeline) in a SINGLE report_publish call, using the board HTML vocabulary from your persona.
|
|
264
274
|
5. Do NOT call mama_save for the briefing; report_publish and agent_activity are the durable operational record.
|
|
265
275
|
|
|
266
276
|
This saves resources. Only publish when there is genuinely new information to report.`;
|
|
267
|
-
|
|
277
|
+
// Owner-initiated refresh skips the NO_UPDATE delta gate: an explicit
|
|
278
|
+
// request means "rebuild the board now", not "tell me nothing changed".
|
|
279
|
+
const forcedDashboardPrompt = dashboardPrompt.replace(/3\. If NO substantive decisions[^\n]*\n/, '3. The owner explicitly requested a fresh board: do NOT reply NO_UPDATE. Rebuild and publish even if nothing changed since the last publish.\n');
|
|
280
|
+
const doDashboardRun = async (opts) => {
|
|
268
281
|
const pm = toolExecutor.getAgentProcessManager();
|
|
269
282
|
if (!pm) {
|
|
270
283
|
routesLogger.warn('[Dashboard Agent] AgentProcessManager not available yet');
|
|
271
284
|
return;
|
|
272
285
|
}
|
|
273
286
|
try {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
287
|
+
// console.log on run outcomes: the DebugLogger only surfaces warn/error in the
|
|
288
|
+
// daemon log, and a silent outcome reads as a hang from the outside.
|
|
289
|
+
console.log(`[Dashboard Agent] run started${opts?.force ? ' (owner-forced, delta gate bypassed)' : ''}`);
|
|
290
|
+
const { noUpdate } = await executeValidatedRun('dashboard-agent', opts?.force ? forcedDashboardPrompt : dashboardPrompt);
|
|
291
|
+
console.log(noUpdate
|
|
292
|
+
? '[Dashboard Agent] no changes detected, publish skipped'
|
|
293
|
+
: '[Dashboard Agent] board published');
|
|
282
294
|
}
|
|
283
295
|
catch (err) {
|
|
284
296
|
routesLogger.error('[Dashboard Agent] Error:', err instanceof Error ? err.message : err);
|
|
285
297
|
}
|
|
286
298
|
};
|
|
299
|
+
// Serialize ALL dashboard runs (boot, interval, manual) on one chain -- the shared
|
|
300
|
+
// agent process rejects concurrent requests, so unserialized triggers raced into
|
|
301
|
+
// 'Process is busy' errors (same pattern as CronWorker's executionQueue).
|
|
302
|
+
let dashboardRunChain = Promise.resolve();
|
|
303
|
+
const runDashboardAgent = (opts) => {
|
|
304
|
+
// Trailing catch keeps one failed link from poisoning every future run:
|
|
305
|
+
// a rejected chain would silently skip all subsequent .then() links.
|
|
306
|
+
dashboardRunChain = dashboardRunChain.then(() => doDashboardRun(opts)).catch(() => { });
|
|
307
|
+
return dashboardRunChain;
|
|
308
|
+
};
|
|
287
309
|
// First run after 10s (let connectors poll first), then every 30 min
|
|
288
310
|
setTimeout(runDashboardAgent, 10_000);
|
|
289
311
|
setInterval(runDashboardAgent, 30 * 60 * 1000);
|
|
290
|
-
// Manual trigger
|
|
312
|
+
// Manual trigger (owner-forced: bypasses the delta gate)
|
|
291
313
|
apiServer.app.post('/api/report/agent-refresh', auth_middleware_js_1.requireAuth, async (_req, res) => {
|
|
292
|
-
runDashboardAgent().catch(() => { });
|
|
293
|
-
res.json({ ok: true, message: 'Dashboard agent triggered' });
|
|
314
|
+
runDashboardAgent({ force: true }).catch(() => { });
|
|
315
|
+
res.json({ ok: true, message: 'Dashboard agent triggered (forced refresh)' });
|
|
294
316
|
});
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
routesLogger.debug('[Dashboard Agent] Skipped; dashboard-agent is not configured');
|
|
320
|
+
}
|
|
321
|
+
// ── Wiki Agent ──────────────────────────────────────────────────────
|
|
322
|
+
const wikiConfig = config.wiki;
|
|
323
|
+
if (wikiAgentConfigured && wikiConfig?.enabled && wikiConfig.vaultPath) {
|
|
324
|
+
const { ensureWikiPersona } = await import('../../multi-agent/wiki-agent-persona.js');
|
|
325
|
+
const { ObsidianWriter } = await import('../../wiki/obsidian-writer.js');
|
|
326
|
+
ensureWikiPersona();
|
|
327
|
+
const obsWriter = new ObsidianWriter(wikiConfig.vaultPath, wikiConfig.wikiDir || 'wiki');
|
|
328
|
+
obsWriter.ensureDirectories();
|
|
329
|
+
routesLogger.debug(`[Wiki Agent] Persona ensured, vault: ${obsWriter.getWikiPath()}`);
|
|
330
|
+
// Wire Obsidian vault path for CLI tool. The wiki directory itself is what
|
|
331
|
+
// gets registered as an Obsidian vault (agent-facing paths like daily/... are
|
|
332
|
+
// relative to it), so the CLI vault name is the wiki path's basename.
|
|
333
|
+
const fullWikiPath = obsWriter.getWikiPath();
|
|
334
|
+
const obsidianVaultName = node_path_1.default.basename(fullWikiPath);
|
|
335
|
+
toolExecutor.setObsidianVaultPath(fullWikiPath, obsidianVaultName);
|
|
336
|
+
routesLogger.debug(`[Wiki Agent] Obsidian CLI vault: ${fullWikiPath} (vault=${obsidianVaultName})`);
|
|
337
|
+
// Ensure Obsidian is running with the wiki vault open (macOS only).
|
|
338
|
+
// NOTE: obsidian://open?vault= only opens vaults ALREADY registered in
|
|
339
|
+
// Obsidian; registering the wiki directory as a vault is a one-time manual
|
|
340
|
+
// setup step. If it is not registered, the CLI reports unavailable and the
|
|
341
|
+
// agent falls back to wiki_publish (direct file writes still work).
|
|
342
|
+
if (process.platform === 'darwin') {
|
|
309
343
|
try {
|
|
310
|
-
const {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
stdio: 'ignore',
|
|
344
|
+
const { execFile: execFileChild } = await import('child_process');
|
|
345
|
+
execFileChild('open', [`obsidian://open?vault=${encodeURIComponent(obsidianVaultName)}`], { timeout: 5000 }, () => {
|
|
346
|
+
/* non-fatal: CLI will return error, agent falls back to wiki_publish */
|
|
314
347
|
});
|
|
315
348
|
}
|
|
316
349
|
catch {
|
|
317
|
-
/* non-fatal
|
|
350
|
+
/* non-fatal */
|
|
318
351
|
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
352
|
+
}
|
|
353
|
+
// Wire wiki_publish tool to shared gateway executor (used by code-act path)
|
|
354
|
+
toolExecutor.setWikiPublisher((pages) => {
|
|
355
|
+
for (const page of pages) {
|
|
356
|
+
obsWriter.writePage(page);
|
|
357
|
+
}
|
|
358
|
+
if (pages.length > 0) {
|
|
359
|
+
obsWriter.updateIndex(pages);
|
|
360
|
+
obsWriter.appendLog('compile', `Published ${pages.length} pages`);
|
|
361
|
+
}
|
|
362
|
+
routesLogger.debug(`[Wiki Agent] Published ${pages.length} pages to vault`);
|
|
363
|
+
eventBus.emit({
|
|
364
|
+
type: 'wiki:compiled',
|
|
365
|
+
pages: pages.map((p) => p.path || ''),
|
|
333
366
|
});
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
367
|
+
});
|
|
368
|
+
// Wiki trigger via executeValidatedRun
|
|
369
|
+
const doWikiRun = async () => {
|
|
370
|
+
if (!toolExecutor.getAgentProcessManager()) {
|
|
371
|
+
routesLogger.warn('[Wiki Agent] AgentProcessManager not available yet');
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
try {
|
|
375
|
+
routesLogger.debug('[Wiki Agent] Checking for updates...');
|
|
376
|
+
const wikiPrompt = `You are triggered on a schedule. Before writing anything, determine if an update is needed:
|
|
343
377
|
|
|
344
378
|
1. Use agent_notices({limit: 100}) to find the most recent wiki-agent compiled/publish/task_complete notice. Treat that as the last compilation boundary.
|
|
345
|
-
2.
|
|
379
|
+
2. NOVELTY CHECK by recency, not semantics: call mama_search({limit: 30}) with NO query -- that returns the newest decisions in creation order regardless of language or wording (semantic/lexical search misses cross-language items, which caused missed compilations). Compare created_at against the boundary.
|
|
380
|
+
3. If NO substantive decisions are newer than the boundary -> respond "NO_UPDATE" and stop. Do NOT call obsidian or wiki_publish.
|
|
381
|
+
4. If new items exist, use context_compile first to gather supporting context (limit 30, max_tool_calls 3, strictness "balanced").
|
|
346
382
|
Use this exact task text for context_compile: "recent substantive project decisions, task progress, agent alerts, and major changes".
|
|
347
383
|
Do not include dashboard_briefing, wiki_compilation, system-audit, or audit-log labels in the context_compile task text; filter those operational summaries after the packet returns.
|
|
348
|
-
If
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
384
|
+
If the packet misses some of the new items from step 2 (it often will for cross-language content), write from the step-2 items directly -- the recency list is authoritative for WHAT is new; the packet only enriches.
|
|
385
|
+
If context_compile is unavailable because there is no active worker envelope, fall back to ONE queried mama_search for enrichment and continue from the step-2 recency list.
|
|
386
|
+
5. Then follow your persona: APPEND today's daily note (daily/YYYY-MM-DD.md, create with the section skeleton on first write of the day), then promote qualifying lesson candidates into lessons/ pages (search before create; update, never duplicate). Do NOT write per-task status pages.
|
|
387
|
+
6. Do NOT call mama_save for the compilation; Obsidian/wiki files plus agent_activity are the durable operational record.
|
|
352
388
|
|
|
353
389
|
This saves resources. Only compile when there is genuinely new information to document.`;
|
|
354
|
-
|
|
355
|
-
|
|
390
|
+
const { noUpdate } = await executeValidatedRun('wiki-agent', wikiPrompt, {
|
|
391
|
+
requestTimeout: 600_000,
|
|
392
|
+
});
|
|
393
|
+
if (noUpdate) {
|
|
394
|
+
routesLogger.debug('[Wiki Agent] No changes detected, skipped');
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
routesLogger.debug('[Wiki Agent] Compilation complete');
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
catch (err) {
|
|
401
|
+
routesLogger.error('[Wiki Agent] Error:', err instanceof Error ? err.message : err);
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
// Serialize ALL wiki runs (boot, event-driven, manual) on one chain -- the
|
|
405
|
+
// shared agent process rejects concurrent requests, so the boot run and a
|
|
406
|
+
// manual trigger raced into 'Process is busy' (same pattern as the
|
|
407
|
+
// dashboard agent's runDashboardAgent chain above).
|
|
408
|
+
let wikiRunChain = Promise.resolve();
|
|
409
|
+
const runWikiAgent = () => {
|
|
410
|
+
wikiRunChain = wikiRunChain.then(doWikiRun).catch(() => { });
|
|
411
|
+
return wikiRunChain;
|
|
412
|
+
};
|
|
413
|
+
// Event-driven: compile when extraction completes. Trailing-edge debounce so
|
|
414
|
+
// bursts of extraction:completed events coalesce into one wiki compile run.
|
|
415
|
+
eventBus.onDebounced('extraction:completed', () => runWikiAgent(), 30_000);
|
|
416
|
+
// Promotion feeds the wiki: freshly promoted decisions are exactly the
|
|
417
|
+
// material daily notes and lessons compile from.
|
|
418
|
+
eventBus.onDebounced('memory:promoted', () => runWikiAgent(), 30_000);
|
|
419
|
+
// Emit agent:action notices when wiki pages are compiled
|
|
420
|
+
eventBus.on('wiki:compiled', (event) => {
|
|
421
|
+
if (event.type === 'wiki:compiled') {
|
|
422
|
+
for (const page of event.pages) {
|
|
423
|
+
eventBus.emit({
|
|
424
|
+
type: 'agent:action',
|
|
425
|
+
agent: 'Wiki Agent',
|
|
426
|
+
action: 'compiled',
|
|
427
|
+
target: page,
|
|
356
428
|
});
|
|
357
|
-
if (noUpdate) {
|
|
358
|
-
routesLogger.debug('[Wiki Agent] No changes detected, skipped');
|
|
359
|
-
}
|
|
360
|
-
else {
|
|
361
|
-
routesLogger.debug('[Wiki Agent] Compilation complete');
|
|
362
|
-
}
|
|
363
429
|
}
|
|
364
|
-
|
|
365
|
-
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
// Manual trigger API
|
|
433
|
+
apiServer.app.post('/api/wiki/compile', auth_middleware_js_1.requireAuth, async (_req, res) => {
|
|
434
|
+
runWikiAgent().catch(() => { });
|
|
435
|
+
res.json({ ok: true, message: 'Wiki compilation triggered' });
|
|
436
|
+
});
|
|
437
|
+
// First run after 15s (let connectors and dashboard agent go first)
|
|
438
|
+
setTimeout(runWikiAgent, 15_000);
|
|
439
|
+
routesLogger.info('[Wiki Agent] Ready — triggers: extraction:completed event, POST /api/wiki/compile');
|
|
440
|
+
}
|
|
441
|
+
// -- Memory Promotion: scheduled observation->decision curation --
|
|
442
|
+
// Owner directive 2026-07-11: the decision layer starved after the 07-03/04
|
|
443
|
+
// backfill because nothing periodically judges connector-ingested business
|
|
444
|
+
// data (the M0 kill switch removed direct LLM extraction, and the memory
|
|
445
|
+
// agent only audits owner conversation turns). This pass has the memory
|
|
446
|
+
// agent promote DURABLE judgments only -- task states stay on the board.
|
|
447
|
+
const memoryAgentConfigured = hasEnabledAgentConfig('memory');
|
|
448
|
+
if (memoryAgentConfigured) {
|
|
449
|
+
const PROMOTION_INTERVAL_MS = Math.max(1, Number(process.env.MAMA_MEMORY_PROMOTION_HOURS) || 6) * 60 * 60 * 1000;
|
|
450
|
+
const PROMOTION_INITIAL_DELAY_MS = 10 * 60 * 1000; // let connectors poll first
|
|
451
|
+
const buildPromotionPrompt = (nowIso) => 'PROMOTION RUN. You are curating durable business memory from recent data. ' +
|
|
452
|
+
`The current time is ${nowIso}.\n` +
|
|
453
|
+
'1. agent_notices({limit: 100}): find your latest promotion notice (action "promoted" ' +
|
|
454
|
+
'or "no_update") and treat it as the boundary; default to the last 24h when absent.\n' +
|
|
455
|
+
'2. kagemusha_entities({activeOnly: true}) to find the rooms active since the boundary, ' +
|
|
456
|
+
'then kagemusha_messages({channelId, since: <boundary ISO>}) on the busiest 3-4 rooms.\n' +
|
|
457
|
+
'3. For each candidate judgment, mama_search first to find the existing topic; reuse it ' +
|
|
458
|
+
'so the evolution chain stays intact.\n' +
|
|
459
|
+
'4. Promote at most 5 durable judgments per run via mama_save, following the PROMOTION RUN ' +
|
|
460
|
+
'rules in your persona (pricing/scope agreements, standing client preferences, process ' +
|
|
461
|
+
'rules, recurring risk patterns; NEVER task lifecycle states, greetings, or logistics). ' +
|
|
462
|
+
'Include scopes (the source channel, and the project when identifiable) and event_date.\n' +
|
|
463
|
+
'5. Finish with exactly PROMOTED <n> or NO_UPDATE.';
|
|
464
|
+
const doPromotionRun = async () => {
|
|
465
|
+
if (!toolExecutor.getAgentProcessManager()) {
|
|
466
|
+
routesLogger.warn('[Memory Promotion] AgentProcessManager not available yet');
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
try {
|
|
470
|
+
const { response, noUpdate } = await executeValidatedRun('memory', buildPromotionPrompt(new Date().toISOString()), { requestTimeout: 600_000 });
|
|
471
|
+
const promotedMatch = response?.match(/PROMOTED\s+(\d+)/);
|
|
472
|
+
const saved = promotedMatch ? Number(promotedMatch[1]) : 0;
|
|
473
|
+
eventBus.emit({
|
|
474
|
+
type: 'agent:action',
|
|
475
|
+
agent: 'Memory Agent',
|
|
476
|
+
action: noUpdate || saved === 0 ? 'no_update' : 'promoted',
|
|
477
|
+
target: `promotion run: ${saved} saved`,
|
|
478
|
+
});
|
|
479
|
+
if (saved > 0) {
|
|
480
|
+
eventBus.emit({ type: 'memory:promoted', saved });
|
|
481
|
+
console.log(`[Memory Promotion] Promoted ${saved} durable judgments`);
|
|
366
482
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
eventBus.on('extraction:completed', () => runWikiAgent());
|
|
370
|
-
// Emit agent:action notices when wiki pages are compiled
|
|
371
|
-
eventBus.on('wiki:compiled', (event) => {
|
|
372
|
-
if (event.type === 'wiki:compiled') {
|
|
373
|
-
for (const page of event.pages) {
|
|
374
|
-
eventBus.emit({
|
|
375
|
-
type: 'agent:action',
|
|
376
|
-
agent: 'Wiki Agent',
|
|
377
|
-
action: 'compiled',
|
|
378
|
-
target: page,
|
|
379
|
-
});
|
|
380
|
-
}
|
|
483
|
+
else {
|
|
484
|
+
routesLogger.debug('[Memory Promotion] Nothing qualified for promotion');
|
|
381
485
|
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
486
|
+
}
|
|
487
|
+
catch (err) {
|
|
488
|
+
routesLogger.error('[Memory Promotion] Error:', err instanceof Error ? err.message : err);
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
// Serialize all promotion runs on one chain (same 'Process is busy' class
|
|
492
|
+
// as the dashboard and wiki agents).
|
|
493
|
+
let promotionRunChain = Promise.resolve();
|
|
494
|
+
const runMemoryPromotion = () => {
|
|
495
|
+
promotionRunChain = promotionRunChain.then(doPromotionRun).catch(() => { });
|
|
496
|
+
return promotionRunChain;
|
|
497
|
+
};
|
|
498
|
+
setTimeout(runMemoryPromotion, PROMOTION_INITIAL_DELAY_MS);
|
|
499
|
+
setInterval(runMemoryPromotion, PROMOTION_INTERVAL_MS);
|
|
500
|
+
apiServer.app.post('/api/memory/promote', auth_middleware_js_1.requireAuth, (_req, res) => {
|
|
501
|
+
runMemoryPromotion().catch(() => { });
|
|
502
|
+
res.json({ ok: true, message: 'Memory promotion run triggered' });
|
|
503
|
+
});
|
|
504
|
+
console.log(`[Memory Promotion] Ready: every ${PROMOTION_INTERVAL_MS / 3_600_000}h, POST /api/memory/promote`);
|
|
392
505
|
}
|
|
393
506
|
// ── Conductor Audit — hourly system health check ──────────────────────
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
507
|
+
const AUDIT_INTERVAL_MS = 60 * 60 * 1000; // 1 hour
|
|
508
|
+
const AUDIT_INITIAL_DELAY_MS = 5 * 60 * 1000; // 5 min after startup
|
|
509
|
+
// Owner verdict 2026-07-11: the hourly audit re-sent the same MAJOR alert every
|
|
510
|
+
// run because each audit was stateless. agent_notices does not carry audit
|
|
511
|
+
// findings (review feedback on #134), so dedup state lives in a JSON file the
|
|
512
|
+
// conductor reads/writes itself, and the current time is interpolated per run
|
|
513
|
+
// so the 24h comparison is grounded.
|
|
514
|
+
const buildAuditPrompt = (nowIso) => 'Perform a system audit. Read ~/.mama/skills/audit-checklist.md and execute each step. ' +
|
|
515
|
+
'Classify findings as MINOR or MAJOR. ' +
|
|
516
|
+
'For MINOR items: execute the auto-fix command immediately (Bash curl). Do NOT just report — fix it. ' +
|
|
517
|
+
'For MAJOR items: report to human via channel alert, subject to the dedup rule below. ' +
|
|
518
|
+
`Alert dedup (MANDATORY): the current time is ${nowIso}. Read ~/.mama/state/audit-findings.json ` +
|
|
519
|
+
'(it may not exist on the first run). Re-alert a MAJOR finding only if it is NEW (no entry ' +
|
|
520
|
+
'with the same id), has ESCALATED, or its last_alerted_at is older than 24 hours compared to ' +
|
|
521
|
+
'the current time; otherwise stay silent about it. Never alert MINOR findings to the owner. ' +
|
|
522
|
+
'After the audit, Write ~/.mama/state/audit-findings.json with an array of every current ' +
|
|
523
|
+
'finding: {id (stable kebab-case slug), severity, first_seen, last_seen, last_alerted_at}. ' +
|
|
524
|
+
'Carry forward first_seen and last_alerted_at from the previous file; set last_alerted_at to ' +
|
|
525
|
+
'the current time only for findings you actually alerted this run. ' +
|
|
526
|
+
// Owner verdict 2026-07-10: hourly-audit self-notes are memory noise -- the two
|
|
527
|
+
// "durable policy" saves it produced were unscoped near-duplicates polluting
|
|
528
|
+
// global recall. The audit record lives in validation sessions + agent_activity;
|
|
529
|
+
// MAJOR findings reach the owner via the channel alert. No memory writes here.
|
|
530
|
+
'Do NOT call mama_save under any circumstances: the validation session and agent_activity ' +
|
|
531
|
+
'are the durable audit record, and repeated audits must not accumulate policy notes in memory.';
|
|
532
|
+
const runConductorAudit = async () => {
|
|
533
|
+
let auditSession = null;
|
|
534
|
+
let auditVersion = 0;
|
|
535
|
+
const auditStart = Date.now();
|
|
536
|
+
try {
|
|
537
|
+
routesLogger.debug('[Conductor Audit] Starting hourly audit...');
|
|
407
538
|
try {
|
|
408
|
-
|
|
539
|
+
const ver = sessionsDb ? (0, agent_store_js_1.getLatestVersion)(sessionsDb, 'conductor') : null;
|
|
540
|
+
auditVersion = ver?.version ?? 0;
|
|
541
|
+
auditSession =
|
|
542
|
+
validationService?.startSession('conductor', auditVersion, 'audit', {
|
|
543
|
+
goal: 'hourly system audit',
|
|
544
|
+
}) ?? null;
|
|
545
|
+
}
|
|
546
|
+
catch (bootstrapErr) {
|
|
547
|
+
routesLogger.warn('[Conductor Audit] Failed to initialize audit telemetry:', bootstrapErr);
|
|
548
|
+
auditVersion = 0;
|
|
549
|
+
auditSession = null;
|
|
550
|
+
}
|
|
551
|
+
if (sessionsDb) {
|
|
409
552
|
try {
|
|
410
|
-
const
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
if (sessionsDb) {
|
|
423
|
-
try {
|
|
424
|
-
const startRow = (0, agent_store_js_1.logActivity)(sessionsDb, {
|
|
425
|
-
agent_id: 'conductor',
|
|
426
|
-
agent_version: auditVersion,
|
|
427
|
-
type: 'audit_start',
|
|
428
|
-
input_summary: 'Hourly system audit',
|
|
429
|
-
run_id: auditSession?.id,
|
|
430
|
-
execution_status: 'started',
|
|
431
|
-
trigger_reason: 'audit',
|
|
432
|
-
});
|
|
433
|
-
if (auditSession) {
|
|
434
|
-
try {
|
|
435
|
-
validationService?.recordRun(auditSession.id, { activityId: startRow.id });
|
|
436
|
-
}
|
|
437
|
-
catch (telemetryErr) {
|
|
438
|
-
routesLogger.warn('[Conductor Audit] Failed to link startup activity to validation session:', telemetryErr);
|
|
439
|
-
}
|
|
553
|
+
const startRow = (0, agent_store_js_1.logActivity)(sessionsDb, {
|
|
554
|
+
agent_id: 'conductor',
|
|
555
|
+
agent_version: auditVersion,
|
|
556
|
+
type: 'audit_start',
|
|
557
|
+
input_summary: 'Hourly system audit',
|
|
558
|
+
run_id: auditSession?.id,
|
|
559
|
+
execution_status: 'started',
|
|
560
|
+
trigger_reason: 'audit',
|
|
561
|
+
});
|
|
562
|
+
if (auditSession) {
|
|
563
|
+
try {
|
|
564
|
+
validationService?.recordRun(auditSession.id, { activityId: startRow.id });
|
|
440
565
|
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
routesLogger.warn('[Conductor Audit] Failed to write startup telemetry:', telemetryErr);
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
const auditChannelId = `conductor-audit-${Date.now()}`;
|
|
447
|
-
await messageRouter.process({
|
|
448
|
-
source: 'system',
|
|
449
|
-
channelId: auditChannelId,
|
|
450
|
-
userId: 'system',
|
|
451
|
-
text: auditPrompt,
|
|
452
|
-
});
|
|
453
|
-
const auditDuration = Date.now() - auditStart;
|
|
454
|
-
try {
|
|
455
|
-
if (sessionsDb) {
|
|
456
|
-
const activityRow = (0, agent_store_js_1.logActivity)(sessionsDb, {
|
|
457
|
-
agent_id: 'conductor',
|
|
458
|
-
agent_version: auditVersion,
|
|
459
|
-
type: 'audit_complete',
|
|
460
|
-
input_summary: 'Hourly system audit',
|
|
461
|
-
duration_ms: auditDuration,
|
|
462
|
-
run_id: auditSession?.id,
|
|
463
|
-
execution_status: 'completed',
|
|
464
|
-
trigger_reason: 'audit',
|
|
465
|
-
});
|
|
466
|
-
if (auditSession) {
|
|
467
|
-
validationService?.recordRun(auditSession.id, { activityId: activityRow.id });
|
|
566
|
+
catch (telemetryErr) {
|
|
567
|
+
routesLogger.warn('[Conductor Audit] Failed to link startup activity to validation session:', telemetryErr);
|
|
468
568
|
}
|
|
469
569
|
}
|
|
470
570
|
}
|
|
471
571
|
catch (telemetryErr) {
|
|
472
|
-
routesLogger.warn('[Conductor Audit] Failed to write
|
|
473
|
-
}
|
|
474
|
-
try {
|
|
475
|
-
if (auditSession && validationService) {
|
|
476
|
-
validationService.finalizeSession(auditSession.id, {
|
|
477
|
-
execution_status: 'completed',
|
|
478
|
-
metrics: { duration_ms: auditDuration },
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
catch (telemetryErr) {
|
|
483
|
-
routesLogger.warn('[Conductor Audit] Failed to finalize validation session:', telemetryErr);
|
|
572
|
+
routesLogger.warn('[Conductor Audit] Failed to write startup telemetry:', telemetryErr);
|
|
484
573
|
}
|
|
485
|
-
routesLogger.debug('[Conductor Audit] Audit complete');
|
|
486
574
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
575
|
+
const auditChannelId = `conductor-audit-${Date.now()}`;
|
|
576
|
+
await messageRouter.process({
|
|
577
|
+
source: 'system',
|
|
578
|
+
channelId: auditChannelId,
|
|
579
|
+
userId: 'system',
|
|
580
|
+
text: buildAuditPrompt(new Date().toISOString()),
|
|
581
|
+
});
|
|
582
|
+
const auditDuration = Date.now() - auditStart;
|
|
583
|
+
try {
|
|
584
|
+
if (sessionsDb) {
|
|
585
|
+
const activityRow = (0, agent_store_js_1.logActivity)(sessionsDb, {
|
|
586
|
+
agent_id: 'conductor',
|
|
587
|
+
agent_version: auditVersion,
|
|
588
|
+
type: 'audit_complete',
|
|
589
|
+
input_summary: 'Hourly system audit',
|
|
590
|
+
duration_ms: auditDuration,
|
|
591
|
+
run_id: auditSession?.id,
|
|
592
|
+
execution_status: 'completed',
|
|
593
|
+
trigger_reason: 'audit',
|
|
594
|
+
});
|
|
595
|
+
if (auditSession) {
|
|
596
|
+
validationService?.recordRun(auditSession.id, { activityId: activityRow.id });
|
|
505
597
|
}
|
|
506
598
|
}
|
|
507
|
-
|
|
508
|
-
|
|
599
|
+
}
|
|
600
|
+
catch (telemetryErr) {
|
|
601
|
+
routesLogger.warn('[Conductor Audit] Failed to write completion telemetry:', telemetryErr);
|
|
602
|
+
}
|
|
603
|
+
try {
|
|
604
|
+
if (auditSession && validationService) {
|
|
605
|
+
validationService.finalizeSession(auditSession.id, {
|
|
606
|
+
execution_status: 'completed',
|
|
607
|
+
metrics: { duration_ms: auditDuration },
|
|
608
|
+
});
|
|
509
609
|
}
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
610
|
+
}
|
|
611
|
+
catch (telemetryErr) {
|
|
612
|
+
routesLogger.warn('[Conductor Audit] Failed to finalize validation session:', telemetryErr);
|
|
613
|
+
}
|
|
614
|
+
routesLogger.debug('[Conductor Audit] Audit complete');
|
|
615
|
+
}
|
|
616
|
+
catch (err) {
|
|
617
|
+
const auditDuration = Date.now() - auditStart;
|
|
618
|
+
try {
|
|
619
|
+
if (sessionsDb) {
|
|
620
|
+
const failRow = (0, agent_store_js_1.logActivity)(sessionsDb, {
|
|
621
|
+
agent_id: 'conductor',
|
|
622
|
+
agent_version: auditVersion,
|
|
623
|
+
type: 'audit_failed',
|
|
624
|
+
input_summary: 'Hourly system audit failed',
|
|
625
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
626
|
+
duration_ms: auditDuration,
|
|
627
|
+
run_id: auditSession?.id,
|
|
628
|
+
execution_status: 'failed',
|
|
629
|
+
trigger_reason: 'audit',
|
|
630
|
+
});
|
|
631
|
+
if (auditSession) {
|
|
632
|
+
validationService?.recordRun(auditSession.id, { activityId: failRow.id });
|
|
517
633
|
}
|
|
518
634
|
}
|
|
519
|
-
|
|
520
|
-
|
|
635
|
+
}
|
|
636
|
+
catch (telemetryErr) {
|
|
637
|
+
routesLogger.warn('[Conductor Audit] Failed to write failure telemetry:', telemetryErr);
|
|
638
|
+
}
|
|
639
|
+
try {
|
|
640
|
+
if (auditSession && validationService) {
|
|
641
|
+
validationService.finalizeSession(auditSession.id, {
|
|
642
|
+
execution_status: 'failed',
|
|
643
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
644
|
+
metrics: { duration_ms: auditDuration },
|
|
645
|
+
});
|
|
521
646
|
}
|
|
522
|
-
routesLogger.error('[Conductor Audit] Failed:', err instanceof Error ? err.message : String(err));
|
|
523
647
|
}
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
648
|
+
catch (telemetryErr) {
|
|
649
|
+
routesLogger.warn('[Conductor Audit] Failed to finalize failed session:', telemetryErr);
|
|
650
|
+
}
|
|
651
|
+
routesLogger.error('[Conductor Audit] Failed:', err instanceof Error ? err.message : String(err));
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
setTimeout(() => {
|
|
655
|
+
runConductorAudit();
|
|
656
|
+
setInterval(runConductorAudit, AUDIT_INTERVAL_MS);
|
|
657
|
+
}, AUDIT_INITIAL_DELAY_MS);
|
|
658
|
+
// Manual trigger
|
|
659
|
+
apiServer.app.post('/api/conductor/audit', auth_middleware_js_1.requireAuth, async (_req, res) => {
|
|
660
|
+
runConductorAudit().catch(() => { });
|
|
661
|
+
res.json({ ok: true, message: 'Conductor audit triggered' });
|
|
662
|
+
});
|
|
663
|
+
routesLogger.info('[Conductor Audit] Ready — runs every 60 min, POST /api/conductor/audit for manual trigger');
|
|
536
664
|
// ── Memory Agent stats API ────────────────────────────────────────────
|
|
537
665
|
apiServer.app.get('/api/memory-agent/stats', auth_middleware_js_1.requireAuth, (_req, res) => {
|
|
538
666
|
const stats = messageRouter.getMemoryAgentStats();
|
|
@@ -1187,7 +1315,7 @@ Keep the report under 2000 characters as it will be sent to Discord.`;
|
|
|
1187
1315
|
res.sendFile(node_path_1.default.join(publicDir, 'setup.html'));
|
|
1188
1316
|
});
|
|
1189
1317
|
apiServer.app.use(express_1.default.static(publicDir, {
|
|
1190
|
-
setHeaders: (res) => {
|
|
1318
|
+
setHeaders: (res, _filePath) => {
|
|
1191
1319
|
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
|
|
1192
1320
|
res.setHeader('Pragma', 'no-cache');
|
|
1193
1321
|
res.setHeader('Expires', '0');
|