total-recall-brain 3.13.0 → 3.13.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.
- package/README.md +91 -108
- package/bin/antigravity.mjs +81 -52
- package/bin/total-recall.mjs +32 -57
- package/extension/background.js +1 -1
- package/extension/options/options.js +9 -3
- package/extension/sidepanel/sidepanel.js +0 -2
- package/frontend/index.html +4 -3
- package/frontend/package.json +1 -0
- package/frontend/src/App.tsx +109 -152
- package/frontend/src/api.ts +605 -23
- package/frontend/src/components/BrainSelector.tsx +211 -199
- package/frontend/src/components/DocumentEditorModal.tsx +57 -0
- package/frontend/src/components/DocumentTable.tsx +47 -0
- package/frontend/src/components/Graph3D.tsx +120 -71
- package/frontend/src/components/UsageChart.tsx +3 -3
- package/frontend/src/components/brand/BrandMark.tsx +95 -0
- package/frontend/src/index.css +286 -86
- package/frontend/src/pages/ApiKeysPage.tsx +1878 -215
- package/frontend/src/pages/ChatPage.tsx +103 -45
- package/frontend/src/pages/DesignDocsPage.tsx +5 -5
- package/frontend/src/pages/FilesPage.tsx +10 -6
- package/frontend/src/pages/GraphPage.tsx +5 -3
- package/frontend/src/pages/HelpPage.tsx +2 -2
- package/frontend/src/pages/InboxPage.tsx +82 -0
- package/frontend/src/pages/InstructionsPage.tsx +1 -1
- package/frontend/src/pages/IntegrationsPage.tsx +21 -10
- package/frontend/src/pages/LoginPage.tsx +95 -77
- package/frontend/src/pages/MemoryPage.tsx +31 -8
- package/frontend/src/pages/OnboardingPage.tsx +690 -0
- package/frontend/src/pages/OpenWikiPage.tsx +412 -323
- package/frontend/src/pages/SettingsPage.tsx +825 -922
- package/frontend/src/pages/SkillsPage.tsx +272 -147
- package/frontend/src/pages/UsagePage.tsx +23 -31
- package/frontend/src/pages/VaultPage.tsx +223 -0
- package/frontend/src/types.ts +13 -0
- package/package.json +4 -4
- package/scaffold/.agent/skills/total-recall/SKILL.md +43 -4
- package/scaffold/.agent/skills/total-recall/modules/README.md +10 -0
- package/scaffold/.agent/skills/total-recall/modules/agents/README.md +5 -0
- package/scaffold/.agent/skills/total-recall/{skills/tr-cli-agents → modules/agents}/agents.yml +8 -0
- package/scaffold/.agent/skills/total-recall/modules/skill-deploy/README.md +9 -0
- package/scaffold/.agent/skills/total-recall/openwiki/README.md +10 -0
- package/scaffold/.agent/skills/total-recall/openwiki/architecture.md +5 -0
- package/scaffold/.agent/skills/total-recall/openwiki/ide.md +10 -0
- package/scaffold/.agent/skills/total-recall/openwiki/memory.md +11 -0
- package/scaffold/.agent/skills/total-recall/openwiki/secrets.md +7 -0
- package/scaffold/.agent/skills/total-recall/openwiki/skills.md +7 -0
- package/src/cli/brain.mjs +63 -5
- package/src/cli/connect.mjs +11 -19
- package/src/cli/daemon.mjs +5 -4
- package/src/cli/deploy-ui.mjs +8 -3
- package/src/cli/deploy.mjs +84 -27
- package/src/cli/ingest/index.mjs +1 -1
- package/src/cli/init.mjs +63 -34
- package/src/cli/remember.mjs +3 -3
- package/src/cli/secret.mjs +812 -0
- package/src/cli/setup.mjs +34 -7
- package/src/cli/share.mjs +2 -2
- package/src/cli/skill.mjs +396 -35
- package/src/cli/sync.mjs +4 -4
- package/src/cli/task.mjs +287 -0
- package/src/core/clarity-rewriter.mjs +5 -5
- package/src/core/config.mjs +44 -2
- package/src/core/conflict-detector.mjs +5 -5
- package/src/core/crons.mjs +54 -0
- package/src/core/daemon-loop.mjs +87 -235
- package/src/core/dream.mjs +170 -10
- package/src/core/env-import.mjs +456 -0
- package/src/core/fact-seeker.mjs +14 -14
- package/src/core/import-rules.mjs +20 -7
- package/src/core/inference-engine.mjs +3 -3
- package/src/core/migrate.mjs +14 -8
- package/src/core/okf-adapter.mjs +2 -2
- package/src/core/operation-validator.mjs +39 -331
- package/src/core/optimizer.mjs +7 -0
- package/src/core/post-mortem.mjs +2 -2
- package/src/core/project-brain.mjs +349 -0
- package/src/core/provider-catalog.mjs +296 -0
- package/src/core/quick-capture.mjs +1 -1
- package/src/core/remote-vault-sync.mjs +194 -0
- package/src/core/research-queue.mjs +7 -11
- package/src/core/runtime.mjs +33 -9
- package/src/core/scheduler.mjs +59 -5
- package/src/core/schema.mjs +14 -0
- package/src/core/search.mjs +1 -1
- package/src/core/secrets-env-export.mjs +323 -0
- package/src/core/secrets-rotate.mjs +245 -0
- package/src/core/secrets-store.mjs +645 -0
- package/src/core/semantic-index.mjs +3 -3
- package/src/core/skills-registry.mjs +1062 -0
- package/src/core/source-adapters.mjs +4 -1
- package/src/core/ssss-host-extension.mjs +94 -0
- package/src/core/ssss-kernel-bridge.mjs +530 -0
- package/src/core/surface.mjs +14 -0
- package/src/core/task-envelope.mjs +298 -0
- package/src/core/task-executors.mjs +600 -0
- package/src/core/validated-write.mjs +124 -56
- package/src/core/vault.mjs +21 -34
- package/src/core/webauthn-store.mjs +272 -0
- package/src/server/api.mjs +26 -16
- package/src/server/auth.mjs +51 -0
- package/src/server/index.mjs +3 -3
- package/src/server/keys.mjs +30 -4
- package/src/server/rest.mjs +198 -25
- package/src/server/route-manifest.json +156 -0
- package/src/server/routes/_shared.mjs +40 -1
- package/src/server/routes/docs.mjs +260 -0
- package/src/server/routes/memory.mjs +145 -32
- package/src/server/routes/research.mjs +30 -0
- package/src/server/routes/secrets.mjs +470 -0
- package/src/server/routes/share.mjs +2 -2
- package/src/server/routes/skills.mjs +452 -54
- package/src/server/routes/sync.mjs +48 -0
- package/src/server/routes/webauthn.mjs +184 -0
- package/src/server/update-route-manifest.mjs +39 -0
- package/templates/onboarding-interview.md +32 -22
- package/templates/openwiki/README.md +10 -0
- package/templates/openwiki/architecture.md +5 -0
- package/templates/openwiki/ide.md +10 -0
- package/templates/openwiki/memory.md +11 -0
- package/templates/openwiki/secrets.md +7 -0
- package/templates/openwiki/skills.md +7 -0
- package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/SKILL.md +0 -121
- package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/antigravity.txt +0 -20
- package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/claude.txt +0 -58
- package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/codex.txt +0 -81
- package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/references/gemini.txt +0 -44
- package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/scripts/.gitkeep +0 -0
- package/scaffold/.agent/skills/total-recall/skills/tr-cli-agents/subagents/.gitkeep +0 -0
- package/scaffold/.agent/skills/total-recall/skills/tr-research/SKILL.md +0 -338
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/SKILL.md +0 -282
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/assets/skill-template/SKILL.md +0 -20
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/evals/evals.json +0 -20
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/hooks/on-skill-add.sh +0 -14
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/hooks/on-skill-delete.sh +0 -14
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/learnings/.gitkeep +0 -0
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/references/.gitkeep +0 -0
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/.gitkeep +0 -0
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/create-skill.sh +0 -65
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/enforce-skill-optimization.mjs +0 -135
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/skill-watcher.mjs +0 -64
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/subagents/audit-all-skills.md +0 -62
- package/scaffold/.agent/skills/total-recall/skills/tr-ssss/SKILL.md +0 -298
- package/scaffold/.agent/skills/total-recall/skills/tr-ssss/evals/evals.json +0 -17
- package/scaffold/.agent/skills/total-recall/skills/tr-ssss/references/CHANGELOG.md +0 -124
- package/scaffold/.agent/skills/total-recall/skills/tr-ssss/references/ssss-spec.md +0 -1325
- package/scaffold/.agent/skills/total-recall/skills/tr-ssss/scripts/validate-schema.mjs +0 -232
- package/scaffold/.agent/skills/total-recall/skills/tr-ssss/subagents/audit-ssss-node.md +0 -9
- /package/scaffold/.agent/skills/total-recall/{skills/tr-cli-agents/evals → modules/skill-deploy/scripts}/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/{skills/tr-skill → modules/skill-deploy}/scripts/find-skills.mjs +0 -0
- /package/scaffold/.agent/skills/total-recall/{skills/tr-skill → modules/skill-deploy}/scripts/install-skill.mjs +0 -0
- /package/scaffold/.agent/skills/total-recall/{skills/tr-skill → modules/skill-deploy}/scripts/scan-skill.mjs +0 -0
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Executor registry for daemon tasks.
|
|
3
|
+
*
|
|
4
|
+
* resolveExecutor(task) → { id, run }
|
|
5
|
+
* Unknown executor → fail loudly (never silent success skip).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { normalizeTask, FORBIDDEN_CAPABILITIES } from './task-envelope.mjs';
|
|
11
|
+
import { logger } from './logger.mjs';
|
|
12
|
+
import { atomicWrite, safeStringify } from './vault.mjs';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @typedef {object} ExecutorContext
|
|
16
|
+
* @property {string} brainDir
|
|
17
|
+
* @property {string} vaultDir
|
|
18
|
+
* @property {string} skillsDir
|
|
19
|
+
* @property {string} derivedDir
|
|
20
|
+
* @property {string} sessionsDir
|
|
21
|
+
* @property {string} queueDir
|
|
22
|
+
* @property {string} conflictsDir
|
|
23
|
+
* @property {string} instructionsFile
|
|
24
|
+
* @property {object} [runtimeConfig]
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
function policyCheck(task) {
|
|
28
|
+
const caps = task.capabilities || [];
|
|
29
|
+
const hit = caps.filter((c) => FORBIDDEN_CAPABILITIES.includes(c));
|
|
30
|
+
if (hit.length) {
|
|
31
|
+
return {
|
|
32
|
+
ok: false,
|
|
33
|
+
error: `Policy denied capabilities: ${hit.join(', ')}`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return { ok: true };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// ─── Built-in executors ─────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
async function runDream(task, ctx) {
|
|
42
|
+
const { runDreamCycle } = await import('./dream.mjs');
|
|
43
|
+
await runDreamCycle({
|
|
44
|
+
vaultDir: ctx.vaultDir,
|
|
45
|
+
skillsDir: ctx.skillsDir,
|
|
46
|
+
derivedDir: ctx.derivedDir,
|
|
47
|
+
conflictsDir: ctx.conflictsDir,
|
|
48
|
+
instructionsFile: ctx.instructionsFile,
|
|
49
|
+
});
|
|
50
|
+
return { success: true, output: 'Dream cycle complete', executor: 'dream' };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function runSessionIngest(task, ctx) {
|
|
54
|
+
const { scanAndIngest } = await import('./session-watcher.mjs');
|
|
55
|
+
const result = scanAndIngest(ctx.sessionsDir);
|
|
56
|
+
return {
|
|
57
|
+
success: true,
|
|
58
|
+
output: `Ingested ${result.ingested} new sessions`,
|
|
59
|
+
executor: 'session-ingest',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function runSurfaceCompile(task, ctx) {
|
|
64
|
+
const { compileSurface } = await import('./surface.mjs');
|
|
65
|
+
await compileSurface({
|
|
66
|
+
vaultDir: ctx.vaultDir,
|
|
67
|
+
skillsDir: ctx.skillsDir,
|
|
68
|
+
derivedDir: ctx.derivedDir,
|
|
69
|
+
instructionsFile: ctx.instructionsFile,
|
|
70
|
+
});
|
|
71
|
+
return { success: true, output: 'Surface recompiled', executor: 'surface-compile' };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function runPrune(task, ctx) {
|
|
75
|
+
const { autoPruneStorage } = await import('./dream.mjs');
|
|
76
|
+
autoPruneStorage(ctx.brainDir, ctx.vaultDir, ctx.conflictsDir);
|
|
77
|
+
return { success: true, output: 'Storage prune complete', executor: 'prune' };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function runCustom(task, ctx) {
|
|
81
|
+
const land = task.result?.land || 'inbox';
|
|
82
|
+
const intent = task.intent || task.body || task.reason || task.slug;
|
|
83
|
+
const caps = task.capabilities || [];
|
|
84
|
+
|
|
85
|
+
if (land === 'log' || !caps.includes('vault:write')) {
|
|
86
|
+
logger.info({
|
|
87
|
+
subsystem: 'task-executors',
|
|
88
|
+
message: `Custom task (log only): ${task.slug} — ${intent}`,
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
success: true,
|
|
92
|
+
output: `Custom task recorded (no vault write): ${intent}`.slice(0, 500),
|
|
93
|
+
executor: 'custom',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// vault:write → draft in memory-inbox/pending for dream promotion
|
|
98
|
+
const inboxDir = path.join(ctx.brainDir, 'memory-inbox', 'pending');
|
|
99
|
+
if (!fs.existsSync(inboxDir)) fs.mkdirSync(inboxDir, { recursive: true });
|
|
100
|
+
|
|
101
|
+
const now = new Date().toISOString();
|
|
102
|
+
const draftSlug = `draft-task-${task.slug}`.replace(/[^a-zA-Z0-9_-]/g, '-').slice(0, 80);
|
|
103
|
+
const draft = {
|
|
104
|
+
type: 'memory',
|
|
105
|
+
slug: draftSlug,
|
|
106
|
+
category: 'facts',
|
|
107
|
+
title: `Task result: ${task.slug}`,
|
|
108
|
+
status: 'draft',
|
|
109
|
+
confidence: 0.5,
|
|
110
|
+
importance: 2,
|
|
111
|
+
tags: ['daemon-task', 'custom', ...(task.payload?.tags || [])],
|
|
112
|
+
modality: 'descriptive',
|
|
113
|
+
subject: 'agent',
|
|
114
|
+
predicate: 'completed_task',
|
|
115
|
+
object: task.slug,
|
|
116
|
+
schema_version: 2,
|
|
117
|
+
source: {
|
|
118
|
+
type: 'daemon-task',
|
|
119
|
+
session_id: task.origin?.session_id || task.slug,
|
|
120
|
+
evidence_count: 1,
|
|
121
|
+
},
|
|
122
|
+
created: now,
|
|
123
|
+
updated: now,
|
|
124
|
+
last_accessed: now,
|
|
125
|
+
decay: { half_life_days: 30, access_count: 0 },
|
|
126
|
+
sentiment_polarity: 'descriptive',
|
|
127
|
+
sentiment_target: 'system',
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const body = [
|
|
131
|
+
`# ${draft.title}`,
|
|
132
|
+
'',
|
|
133
|
+
`**Intent:** ${intent}`,
|
|
134
|
+
'',
|
|
135
|
+
task.body && task.body !== intent ? task.body : '',
|
|
136
|
+
'',
|
|
137
|
+
task.payload && Object.keys(task.payload).length
|
|
138
|
+
? `## Payload\n\n\`\`\`json\n${JSON.stringify(task.payload, null, 2)}\n\`\`\``
|
|
139
|
+
: '',
|
|
140
|
+
'',
|
|
141
|
+
`_Origin: ${task.origin?.agent || task.created_by || 'unknown'} @ ${task.origin?.created_at || now}_`,
|
|
142
|
+
]
|
|
143
|
+
.filter(Boolean)
|
|
144
|
+
.join('\n');
|
|
145
|
+
|
|
146
|
+
atomicWrite(path.join(inboxDir, `${draftSlug}.md`), safeStringify(body, draft));
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
success: true,
|
|
150
|
+
output: `Custom task drafted to memory-inbox/pending/${draftSlug}.md`,
|
|
151
|
+
executor: 'custom',
|
|
152
|
+
draftSlug,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function runLegacyDispatch(task, ctx) {
|
|
157
|
+
// Deferred import to keep registry load light; legacy path mirrors prior daemon-loop.
|
|
158
|
+
return runLegacyCategoryDispatch(task, ctx);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Legacy category handlers (research, system2, post-mortem, etc.).
|
|
163
|
+
* Kept so existing queue files keep working while open envelope is the new API.
|
|
164
|
+
*/
|
|
165
|
+
async function runLegacyCategoryDispatch(task, ctx) {
|
|
166
|
+
const category = task.category;
|
|
167
|
+
const VAULT_DIR = ctx.vaultDir;
|
|
168
|
+
const BRAIN_DIR = ctx.brainDir;
|
|
169
|
+
const QUEUE_DIR = ctx.queueDir;
|
|
170
|
+
const SKILLS_DIR = ctx.skillsDir;
|
|
171
|
+
const DERIVED_DIR = ctx.derivedDir;
|
|
172
|
+
const INSTRUCTIONS_FILE = ctx.instructionsFile;
|
|
173
|
+
|
|
174
|
+
let runtimeConfig = ctx.runtimeConfig;
|
|
175
|
+
if (!runtimeConfig) {
|
|
176
|
+
try {
|
|
177
|
+
const { loadRuntimeConfig } = await import('./runtime.mjs');
|
|
178
|
+
runtimeConfig = await loadRuntimeConfig();
|
|
179
|
+
} catch {
|
|
180
|
+
runtimeConfig = {};
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (
|
|
185
|
+
task._is_remote_vault_sync ||
|
|
186
|
+
String(task.slug || '').startsWith('remote-vault-sync-')
|
|
187
|
+
) {
|
|
188
|
+
if (process.env.TR_REMOTE_VAULT_SYNC !== '1') {
|
|
189
|
+
return {
|
|
190
|
+
success: false,
|
|
191
|
+
error: 'Remote vault sync off by default (set TR_REMOTE_VAULT_SYNC=1 to enable)',
|
|
192
|
+
executor: 'remote-vault-sync',
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
const { runSync } = await import('./remote-vault-sync.mjs');
|
|
196
|
+
await runSync();
|
|
197
|
+
return { success: true, output: 'Remote vault sync completed', executor: 'remote-vault-sync' };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (
|
|
201
|
+
String(task.slug || '').startsWith('research-') ||
|
|
202
|
+
category === 'proactive-research' ||
|
|
203
|
+
category === 'research-acquisition'
|
|
204
|
+
) {
|
|
205
|
+
return runResearchLegacy(task, { ...ctx, runtimeConfig });
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (category === 'system2-deliberation') {
|
|
209
|
+
if (process.env.TR_POWER_EXECUTORS !== '1' && !task._research_id) {
|
|
210
|
+
return {
|
|
211
|
+
success: false,
|
|
212
|
+
error: 'system2-deliberation requires TR_POWER_EXECUTORS=1 (or research-queue phase)',
|
|
213
|
+
executor: 'system2',
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
const { runInferenceTask } = await import('./inference-engine.mjs');
|
|
217
|
+
const slugs = task.target ? String(task.target).split(',') : [];
|
|
218
|
+
const result = await runInferenceTask(slugs, {
|
|
219
|
+
vaultDir: VAULT_DIR,
|
|
220
|
+
inboxDir: path.join(BRAIN_DIR, 'memory-inbox', 'pending'),
|
|
221
|
+
runtimeConfig,
|
|
222
|
+
});
|
|
223
|
+
return {
|
|
224
|
+
success: true,
|
|
225
|
+
output: `Inference complete: ${result.conclusions?.length || 0} conclusions`,
|
|
226
|
+
executor: 'system2',
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (category === 'cutoff-audit' || String(task.slug || '').startsWith('cutoff-audit-')) {
|
|
231
|
+
if (process.env.TR_POWER_EXECUTORS !== '1') {
|
|
232
|
+
return {
|
|
233
|
+
success: false,
|
|
234
|
+
error: 'cutoff-audit requires TR_POWER_EXECUTORS=1',
|
|
235
|
+
executor: 'cutoff-audit',
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const { runCutoffAudit } = await import('./clarity-rewriter.mjs');
|
|
239
|
+
const result = await runCutoffAudit({ vaultDir: VAULT_DIR, queueDir: QUEUE_DIR, runtimeConfig });
|
|
240
|
+
return {
|
|
241
|
+
success: true,
|
|
242
|
+
output: `Cutoff audit: ${result.audited} audited, ${result.flagged} flagged`,
|
|
243
|
+
executor: 'cutoff-audit',
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (category === 'conscious-enforcement' || String(task.slug || '').includes('self-diagnosis')) {
|
|
248
|
+
if (String(task.slug || '').startsWith('post-mortem-')) {
|
|
249
|
+
const { runPostMortem } = await import('./post-mortem.mjs');
|
|
250
|
+
const sessionPath = path.join(ctx.sessionsDir, task.target);
|
|
251
|
+
const result = await runPostMortem(sessionPath, {
|
|
252
|
+
vaultDir: VAULT_DIR,
|
|
253
|
+
inboxDir: path.join(BRAIN_DIR, 'memory-inbox', 'pending'),
|
|
254
|
+
runtimeConfig,
|
|
255
|
+
});
|
|
256
|
+
return {
|
|
257
|
+
success: true,
|
|
258
|
+
output: `Post-mortem: ${result.nodesCreated || 0} nodes`,
|
|
259
|
+
executor: 'post-mortem',
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
if (process.env.TR_POWER_EXECUTORS !== '1') {
|
|
263
|
+
return {
|
|
264
|
+
success: false,
|
|
265
|
+
error: 'self-diagnosis / conscious-enforcement requires TR_POWER_EXECUTORS=1',
|
|
266
|
+
executor: 'conscious',
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const { runSelfDiagnosis } = await import('./fact-seeker.mjs');
|
|
270
|
+
await runSelfDiagnosis({ vaultDir: VAULT_DIR, runtimeConfig });
|
|
271
|
+
return { success: true, output: 'Self-diagnosis complete', executor: 'conscious' };
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (category === 'memory-maintenance') {
|
|
275
|
+
if (String(task.slug || '').startsWith('clarity-review-')) {
|
|
276
|
+
const { runClarityReview } = await import('./clarity-rewriter.mjs');
|
|
277
|
+
const result = await runClarityReview(task.target, {
|
|
278
|
+
vaultDir: VAULT_DIR,
|
|
279
|
+
inboxDir: path.join(BRAIN_DIR, 'memory-inbox', 'pending'),
|
|
280
|
+
runtimeConfig,
|
|
281
|
+
});
|
|
282
|
+
return {
|
|
283
|
+
success: true,
|
|
284
|
+
output: `Clarity review: rewrote=${result.rewrote}`,
|
|
285
|
+
executor: 'clarity',
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
if (String(task.slug || '').startsWith('memory-compaction-')) {
|
|
289
|
+
const { runMemoryCompaction } = await import('./fact-seeker.mjs');
|
|
290
|
+
const result = await runMemoryCompaction({
|
|
291
|
+
vaultDir: VAULT_DIR,
|
|
292
|
+
inboxDir: path.join(BRAIN_DIR, 'memory-inbox', 'pending'),
|
|
293
|
+
runtimeConfig,
|
|
294
|
+
});
|
|
295
|
+
return {
|
|
296
|
+
success: true,
|
|
297
|
+
output: `Compaction: ${result.consolidatedCount || 0} nodes`,
|
|
298
|
+
executor: 'compaction',
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
// generic maintenance: lease vacuum
|
|
302
|
+
try {
|
|
303
|
+
const leasesDir = path.join(BRAIN_DIR, 'leases');
|
|
304
|
+
if (fs.existsSync(leasesDir)) {
|
|
305
|
+
for (const ws of fs.readdirSync(leasesDir)) {
|
|
306
|
+
const wsDir = path.join(leasesDir, ws);
|
|
307
|
+
if (!fs.statSync(wsDir).isDirectory()) continue;
|
|
308
|
+
for (const file of fs.readdirSync(wsDir)) {
|
|
309
|
+
if (!file.endsWith('.lease.json')) continue;
|
|
310
|
+
const fp = path.join(wsDir, file);
|
|
311
|
+
try {
|
|
312
|
+
const lease = JSON.parse(fs.readFileSync(fp, 'utf8'));
|
|
313
|
+
if (new Date(lease.expires_at) < new Date()) fs.unlinkSync(fp);
|
|
314
|
+
} catch {
|
|
315
|
+
try {
|
|
316
|
+
fs.unlinkSync(fp);
|
|
317
|
+
} catch {}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
} catch {}
|
|
323
|
+
return { success: true, output: 'Maintenance complete', executor: 'maintenance' };
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (category === 'exploration' || category === 'self-evaluation' || category === 'skill-engineering') {
|
|
327
|
+
return {
|
|
328
|
+
success: true,
|
|
329
|
+
output: `Acknowledged category ${category} (no-op in core mode)`,
|
|
330
|
+
executor: category,
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Unknown — fail loud
|
|
335
|
+
return {
|
|
336
|
+
success: false,
|
|
337
|
+
error: `Unknown task executor/category: executor=${task.executor || 'null'} category=${category || 'null'} kind=${task.kind || 'null'} slug=${task.slug}`,
|
|
338
|
+
executor: 'unknown',
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
async function runResearchLegacy(task, ctx) {
|
|
343
|
+
const VAULT_DIR = ctx.vaultDir;
|
|
344
|
+
const BRAIN_DIR = ctx.brainDir;
|
|
345
|
+
const QUEUE_DIR = ctx.queueDir;
|
|
346
|
+
const SKILLS_DIR = ctx.skillsDir;
|
|
347
|
+
const DERIVED_DIR = ctx.derivedDir;
|
|
348
|
+
const INSTRUCTIONS_FILE = ctx.instructionsFile;
|
|
349
|
+
const runtimeConfig = ctx.runtimeConfig || {};
|
|
350
|
+
const inboxDir = path.join(BRAIN_DIR, 'memory-inbox', 'pending');
|
|
351
|
+
|
|
352
|
+
if (String(task.slug || '').startsWith('staleness-check-')) {
|
|
353
|
+
const { runStalenessCheck } = await import('./clarity-rewriter.mjs');
|
|
354
|
+
const result = await runStalenessCheck(task.target, {
|
|
355
|
+
vaultDir: VAULT_DIR,
|
|
356
|
+
queueDir: QUEUE_DIR,
|
|
357
|
+
runtimeConfig,
|
|
358
|
+
});
|
|
359
|
+
return {
|
|
360
|
+
success: true,
|
|
361
|
+
output: `Staleness: ${result.verdict} (conf: ${result.confidence})`,
|
|
362
|
+
executor: 'research',
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (
|
|
367
|
+
String(task.slug || '').startsWith('research-acquisition-') ||
|
|
368
|
+
task.category === 'proactive-research' ||
|
|
369
|
+
String(task.slug || '').includes('fact-seeker') ||
|
|
370
|
+
String(task.slug || '').includes('knowledge-acquisition')
|
|
371
|
+
) {
|
|
372
|
+
const { runKnowledgeAcquisitionCycle } = await import('./fact-seeker.mjs');
|
|
373
|
+
const result = await runKnowledgeAcquisitionCycle({
|
|
374
|
+
vaultDir: VAULT_DIR,
|
|
375
|
+
inboxDir,
|
|
376
|
+
queueDir: QUEUE_DIR,
|
|
377
|
+
forceTopic: task.target || null,
|
|
378
|
+
skillsDir: SKILLS_DIR,
|
|
379
|
+
derivedDir: DERIVED_DIR,
|
|
380
|
+
instructionsFile: INSTRUCTIONS_FILE,
|
|
381
|
+
runtimeConfig,
|
|
382
|
+
});
|
|
383
|
+
if (result.skipped) {
|
|
384
|
+
return { success: true, output: `Knowledge acquisition: ${result.skipped}`, executor: 'research' };
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
success: true,
|
|
388
|
+
output: `Researched "${result.topic}": confidence ${result.confidence || 'n/a'} slug=${result.factSlug}`,
|
|
389
|
+
factSlug: result.factSlug,
|
|
390
|
+
executor: 'research',
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (String(task.slug || '').startsWith('research-deliberation-')) {
|
|
395
|
+
const { runResearchDeliberationCycle } = await import('./fact-seeker.mjs');
|
|
396
|
+
await runResearchDeliberationCycle({
|
|
397
|
+
vaultDir: VAULT_DIR,
|
|
398
|
+
nodeSlug: task._node_slug || 'pending',
|
|
399
|
+
topic: task.title || task.target || 'Unknown Topic',
|
|
400
|
+
runtimeConfig,
|
|
401
|
+
});
|
|
402
|
+
return { success: true, output: 'Deliberation complete', executor: 'research' };
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (String(task.slug || '').startsWith('research-improvement-')) {
|
|
406
|
+
const { runResearchImprovementCycle } = await import('./fact-seeker.mjs');
|
|
407
|
+
await runResearchImprovementCycle({
|
|
408
|
+
vaultDir: VAULT_DIR,
|
|
409
|
+
nodeSlug: task._node_slug || 'pending',
|
|
410
|
+
topic: task.title || task.target || 'Unknown Topic',
|
|
411
|
+
runtimeConfig,
|
|
412
|
+
});
|
|
413
|
+
return { success: true, output: 'Improvement complete', executor: 'research' };
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (String(task.slug || '').startsWith('research-monitoring-')) {
|
|
417
|
+
const { runResearchMonitoringCycle } = await import('./fact-seeker.mjs');
|
|
418
|
+
await runResearchMonitoringCycle({
|
|
419
|
+
vaultDir: VAULT_DIR,
|
|
420
|
+
nodeSlug: task._node_slug || 'pending',
|
|
421
|
+
topic: task.title || task.target || 'Unknown Topic',
|
|
422
|
+
runtimeConfig,
|
|
423
|
+
skillsDir: SKILLS_DIR,
|
|
424
|
+
derivedDir: DERIVED_DIR,
|
|
425
|
+
instructionsFile: INSTRUCTIONS_FILE,
|
|
426
|
+
});
|
|
427
|
+
return { success: true, output: 'Monitoring complete', executor: 'research' };
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
if (String(task.slug || '').startsWith('research-expansion-')) {
|
|
431
|
+
const { runResearchExpansionCycle } = await import('./fact-seeker.mjs');
|
|
432
|
+
await runResearchExpansionCycle({
|
|
433
|
+
vaultDir: VAULT_DIR,
|
|
434
|
+
nodeSlug: task._node_slug || 'pending',
|
|
435
|
+
topic: task.title || task.target || 'Unknown Topic',
|
|
436
|
+
runtimeConfig,
|
|
437
|
+
});
|
|
438
|
+
return { success: true, output: 'Expansion complete', executor: 'research' };
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (String(task.slug || '').includes('validate')) {
|
|
442
|
+
const { runConclusionWriter } = await import('./conclusion-writer.mjs');
|
|
443
|
+
const result = await runConclusionWriter({
|
|
444
|
+
inboxDir,
|
|
445
|
+
vaultDir: VAULT_DIR,
|
|
446
|
+
quarantineDir: path.join(BRAIN_DIR, 'memory-inbox', 'quarantine'),
|
|
447
|
+
});
|
|
448
|
+
if (result.skipped) {
|
|
449
|
+
return { success: true, output: `Conclusion writer: ${result.skipped}`, executor: 'research' };
|
|
450
|
+
}
|
|
451
|
+
return {
|
|
452
|
+
success: true,
|
|
453
|
+
output: `Validated ${result.processed}: ${result.approved} approved`,
|
|
454
|
+
executor: 'research',
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return { success: true, output: 'No-op research task', executor: 'research' };
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// ─── Registry ───────────────────────────────────────────────────────────────────
|
|
462
|
+
|
|
463
|
+
async function runSecretsRotationCheck(task, ctx) {
|
|
464
|
+
const { runSecretsRotationCheck: run } = await import('./secrets-rotate.mjs');
|
|
465
|
+
return run(ctx);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
async function runSecretsExportEnv(task, ctx) {
|
|
469
|
+
const { runSecretsExportAll } = await import('./secrets-rotate.mjs');
|
|
470
|
+
return runSecretsExportAll(ctx);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
async function runSecretsRotationAssist(task, ctx) {
|
|
474
|
+
// Supervised: ensure prompt is present; does not auto-browser without agent session
|
|
475
|
+
const key = task.payload?.secret_key || task.slug?.replace(/^secret-rotate-/, '');
|
|
476
|
+
if (!key) {
|
|
477
|
+
return { success: false, error: 'missing secret_key', executor: 'secrets-rotation-assist' };
|
|
478
|
+
}
|
|
479
|
+
const { getBrowserRotateAssist } = await import('./secrets-rotate.mjs');
|
|
480
|
+
const assist = await getBrowserRotateAssist(ctx.brainDir, key);
|
|
481
|
+
return {
|
|
482
|
+
success: true,
|
|
483
|
+
output: `Browser rotation assist ready for ${key}. Console: ${assist.console_url || 'n/a'}. Use browser tools with human 2FA; then secret rotate --export-env.`,
|
|
484
|
+
executor: 'secrets-rotation-assist',
|
|
485
|
+
assist: {
|
|
486
|
+
key: assist.key,
|
|
487
|
+
console_url: assist.console_url,
|
|
488
|
+
docs_url: assist.docs_url,
|
|
489
|
+
overdue: assist.overdue,
|
|
490
|
+
// prompt available to agent; do not echo secrets
|
|
491
|
+
prompt: assist.prompt,
|
|
492
|
+
},
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const EXECUTORS = {
|
|
497
|
+
'secrets-rotation-check': { id: 'secrets-rotation-check', run: runSecretsRotationCheck },
|
|
498
|
+
'secrets-export-env': { id: 'secrets-export-env', run: runSecretsExportEnv },
|
|
499
|
+
'secrets-rotation-assist': { id: 'secrets-rotation-assist', run: runSecretsRotationAssist },
|
|
500
|
+
dream: { id: 'dream', run: runDream },
|
|
501
|
+
'session-ingest': { id: 'session-ingest', run: runSessionIngest },
|
|
502
|
+
'surface-compile': { id: 'surface-compile', run: runSurfaceCompile },
|
|
503
|
+
prune: { id: 'prune', run: runPrune },
|
|
504
|
+
custom: { id: 'custom', run: runCustom },
|
|
505
|
+
research: { id: 'research', run: runResearchLegacy },
|
|
506
|
+
legacy: { id: 'legacy', run: runLegacyDispatch },
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Resolve which executor runs this task.
|
|
511
|
+
*/
|
|
512
|
+
export function resolveExecutor(task) {
|
|
513
|
+
const t = normalizeTask(task);
|
|
514
|
+
|
|
515
|
+
if (t.executor && EXECUTORS[t.executor]) {
|
|
516
|
+
return EXECUTORS[t.executor];
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// System / named slugs
|
|
520
|
+
if (t.slug === 'dream' || String(t.slug || '').startsWith('dream-') || t.executor === 'dream') {
|
|
521
|
+
return EXECUTORS.dream;
|
|
522
|
+
}
|
|
523
|
+
if (String(t.slug || '').startsWith('session-ingest')) return EXECUTORS['session-ingest'];
|
|
524
|
+
if (String(t.slug || '').startsWith('surface-compile')) return EXECUTORS['surface-compile'];
|
|
525
|
+
if (String(t.slug || '').startsWith('prune-') || t.slug === 'prune') return EXECUTORS.prune;
|
|
526
|
+
if (String(t.slug || '').startsWith('secret-rotate-') || t.category === 'secrets-rotation') {
|
|
527
|
+
return EXECUTORS['secrets-rotation-assist'];
|
|
528
|
+
}
|
|
529
|
+
if (String(t.slug || '').startsWith('secrets-rotation-check') || t.executor === 'secrets-rotation-check') {
|
|
530
|
+
return EXECUTORS['secrets-rotation-check'];
|
|
531
|
+
}
|
|
532
|
+
if (String(t.slug || '').startsWith('secrets-export') || t.executor === 'secrets-export-env') {
|
|
533
|
+
return EXECUTORS['secrets-export-env'];
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (t.kind === 'custom' || t.category === 'custom' || t.executor === 'custom') {
|
|
537
|
+
return EXECUTORS.custom;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Known legacy categories still registered
|
|
541
|
+
const legacyCategories = new Set([
|
|
542
|
+
'conscious-enforcement',
|
|
543
|
+
'system2-deliberation',
|
|
544
|
+
'cutoff-audit',
|
|
545
|
+
'memory-maintenance',
|
|
546
|
+
'research-acquisition',
|
|
547
|
+
'proactive-research',
|
|
548
|
+
'skill-engineering',
|
|
549
|
+
'self-evaluation',
|
|
550
|
+
'exploration',
|
|
551
|
+
]);
|
|
552
|
+
|
|
553
|
+
if (legacyCategories.has(t.category) || t._research_id || t._is_remote_vault_sync) {
|
|
554
|
+
return EXECUTORS.legacy;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
if (t.kind === 'research') return EXECUTORS.research;
|
|
558
|
+
if (t.kind === 'system' || t.kind === 'maintenance' || t.kind === 'memory') {
|
|
559
|
+
return EXECUTORS.legacy;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Truly unknown
|
|
563
|
+
return null;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Dispatch a task through the registry. Never silently succeeds on unknown.
|
|
568
|
+
*/
|
|
569
|
+
export async function dispatchTask(task, ctx) {
|
|
570
|
+
const normalized = normalizeTask(task);
|
|
571
|
+
|
|
572
|
+
const policy = policyCheck(normalized);
|
|
573
|
+
if (!policy.ok) {
|
|
574
|
+
return { success: false, error: policy.error, executor: 'policy' };
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const executor = resolveExecutor(normalized);
|
|
578
|
+
if (!executor) {
|
|
579
|
+
const msg =
|
|
580
|
+
`Unknown task executor for slug=${normalized.slug} ` +
|
|
581
|
+
`category=${normalized.category} kind=${normalized.kind} executor=${normalized.executor}`;
|
|
582
|
+
logger.info({ subsystem: 'task-executors', message: msg });
|
|
583
|
+
return { success: false, error: msg, executor: 'unknown' };
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
try {
|
|
587
|
+
const result = await executor.run(normalized, ctx);
|
|
588
|
+
return { ...result, executor: result.executor || executor.id };
|
|
589
|
+
} catch (err) {
|
|
590
|
+
return {
|
|
591
|
+
success: false,
|
|
592
|
+
error: err.message || String(err),
|
|
593
|
+
executor: executor.id,
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
export function listExecutorIds() {
|
|
599
|
+
return Object.keys(EXECUTORS);
|
|
600
|
+
}
|