total-recall-brain 3.41.5 → 3.41.6
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/bin/total-recall.mjs +7 -4
- package/frontend/dist/assets/index-4tGQfTa2.js +5605 -0
- package/frontend/dist/assets/index-DtwsDyFM.css +1 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package.json +11 -0
- package/frontend/src/App.tsx +47 -122
- package/frontend/src/components/plugins/plugin-frame.ts +1 -0
- package/frontend/src/index.css +152 -86
- package/frontend/src/pages/HelpPage.tsx +13 -10
- package/frontend/src/pages/MemoryPage.tsx +28 -30
- package/frontend/src/pages/NetworkPage.tsx +3 -3
- package/frontend/src/pages/PluginsPage.tsx +6 -5
- package/frontend/src/pages/RulesPage.tsx +16 -12
- package/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +3 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +3 -0
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +3 -0
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +3 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +4 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +136 -7
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +135 -26
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +4 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +228 -9
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +24 -30
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +29 -16
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +73 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +182 -365
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +33 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +9 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/agy.mjs +187 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/claude.mjs +275 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cline.mjs +132 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/codex.mjs +187 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cursor.mjs +158 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/devin.mjs +157 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/dsh.mjs +183 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/grok.mjs +132 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +173 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +87 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/openclaw.mjs +173 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/pi.mjs +129 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate.mjs +12 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/json-reply.mjs +22 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +72 -70
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-catalog.mjs +195 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/paths.mjs +11 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +169 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +136 -346
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/ssss-store.mjs +20 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/telemetry.mjs +43 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +156 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +117 -35
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +51 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +398 -57
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +10 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +3 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +42 -190
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/openwiki.mjs +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/mermaid-diagrams/SKILL.md +44 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/write-connector/SKILL.md +56 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +8 -8
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +3 -0
- package/src/cli/agent.mjs +12 -1
- package/src/cli/compact.mjs +2 -2
- package/src/cli/connect.mjs +56 -1
- package/src/cli/context.mjs +10 -7
- package/src/cli/doctor.mjs +5 -2
- package/src/cli/harness.mjs +62 -50
- package/src/cli/memory-entry.mjs +2 -2
- package/src/cli/preflight.mjs +152 -16
- package/src/cli/remember.mjs +19 -1
- package/src/cli/rules.mjs +54 -12
- package/src/cli/startup.mjs +1 -1
- package/src/cli/status.mjs +12 -2
- package/src/core/claude-hooks.mjs +41 -3
- package/src/core/cli-semantic-index.mjs +3 -2
- package/src/core/conflict-detector.mjs +23 -12
- package/src/core/context-compactor.mjs +2 -0
- package/src/core/context-policy.mjs +20 -0
- package/src/core/duplicate-guard.mjs +350 -0
- package/src/core/meta-harness.mjs +31 -11
- package/src/core/preflight-gate.mjs +2 -2
- package/src/core/preflight-receipt.mjs +28 -0
- package/src/core/scaffold-plugins.mjs +7 -0
- package/src/core/stdio-flush.mjs +23 -0
- package/src/core/surface.mjs +33 -10
- package/src/server/routes/plugins.mjs +2 -2
- package/frontend/dist/assets/index-BIQmqDKP.css +0 -1
- package/frontend/dist/assets/index-WT3gs-x6.js +0 -5631
- package/frontend/src/components/DaemonLogsTab.tsx +0 -54
- package/frontend/src/components/ResearchAgendaTab.tsx +0 -712
- package/frontend/src/components/TaskQueueTab.tsx +0 -193
- package/frontend/src/components/VoiceInput.tsx +0 -112
- package/frontend/src/pages/ChatPage.tsx +0 -1059
- package/frontend/src/pages/CollabPage.tsx +0 -470
- package/frontend/src/pages/DesignDocsPage.tsx +0 -621
- package/frontend/src/pages/FilesPage.tsx +0 -393
- package/frontend/src/pages/HealthPage.tsx +0 -359
- package/frontend/src/pages/InboxPage.tsx +0 -83
- package/frontend/src/pages/InstructionsPage.tsx +0 -583
- package/frontend/src/pages/IntegrationsPage.tsx +0 -761
- package/frontend/src/pages/MeshPage.css +0 -58
- package/frontend/src/pages/MeshPage.tsx +0 -1219
- package/frontend/src/pages/OkfPage.tsx +0 -535
- package/frontend/src/pages/SandboxPage.tsx +0 -113
- package/frontend/src/pages/SkillsPage.tsx +0 -1994
- package/frontend/src/pages/TasksPage.tsx +0 -427
- package/frontend/src/pages/UsagePage.tsx +0 -702
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/README.md +0 -65
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/cli.mjs +0 -76
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/package.json +0 -19
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +0 -266
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/adapters/dsh.mjs +0 -446
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/documentation.mjs +0 -152
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/executor.mjs +0 -71
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/runtime.mjs +0 -36
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/setup.mjs +0 -35
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/worker.mjs +0 -175
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +0 -32
- package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +0 -575
|
@@ -86,10 +86,10 @@ export const ADAPTER_CATALOG = {
|
|
|
86
86
|
name: 'Hermes Agent Runtime',
|
|
87
87
|
bin: 'hermes',
|
|
88
88
|
family: 'nous-open-weights',
|
|
89
|
-
tier: '
|
|
90
|
-
billingModel: '
|
|
89
|
+
tier: 'budget',
|
|
90
|
+
billingModel: 'metered',
|
|
91
91
|
speed: 'fast',
|
|
92
|
-
costScore:
|
|
92
|
+
costScore: 3,
|
|
93
93
|
qualityScore: 8.2,
|
|
94
94
|
contextLimit: 65536,
|
|
95
95
|
modalities: ['text', 'code'],
|
|
@@ -341,7 +341,9 @@ function resolveAdapterEntry(h, catalog = ADAPTER_CATALOG) {
|
|
|
341
341
|
export function selectOptimalHarness(taskDescription, availableHarnesses = [], quotaStatus = {}, options = {}) {
|
|
342
342
|
const catalog = options.catalog || ADAPTER_CATALOG;
|
|
343
343
|
const empiricalScorecard = options.empiricalScorecard || {};
|
|
344
|
-
const
|
|
344
|
+
const base = classifyTaskComplexity(taskDescription, options);
|
|
345
|
+
// A caller with a better classifier (such as a typed decision) may supply the tier.
|
|
346
|
+
const complexity = options.tierOverride ? { ...base, tier: options.tierOverride } : base;
|
|
345
347
|
|
|
346
348
|
const pool = availableHarnesses.length > 0
|
|
347
349
|
? availableHarnesses.map(h => resolveAdapterEntry(h, catalog))
|
|
@@ -357,7 +359,7 @@ export function selectOptimalHarness(taskDescription, availableHarnesses = [], q
|
|
|
357
359
|
return true;
|
|
358
360
|
});
|
|
359
361
|
|
|
360
|
-
const candidates = viable
|
|
362
|
+
const candidates = viable;
|
|
361
363
|
const isFrontier = complexity.tier === 'frontier';
|
|
362
364
|
const isLocal = complexity.tier === 'local';
|
|
363
365
|
|
|
@@ -378,6 +380,10 @@ export function selectOptimalHarness(taskDescription, availableHarnesses = [], q
|
|
|
378
380
|
if (q && q.status === 'needs_auth') {
|
|
379
381
|
rawUtility -= 6.0;
|
|
380
382
|
}
|
|
383
|
+
// No login probe exists for this harness, so it ranks below one verified as signed in
|
|
384
|
+
if (q && q.status === 'unverified') {
|
|
385
|
+
rawUtility -= 1.0;
|
|
386
|
+
}
|
|
381
387
|
|
|
382
388
|
// Factor in empirical local pass rate if at least 2 runs recorded
|
|
383
389
|
const emp = empiricalScorecard[h.id] || empiricalScorecard[h.bin];
|
|
@@ -397,7 +403,7 @@ export function selectOptimalHarness(taskDescription, availableHarnesses = [], q
|
|
|
397
403
|
}).sort((a, b) => b.utility - a.utility);
|
|
398
404
|
|
|
399
405
|
return {
|
|
400
|
-
selected: ranked[0]?.harness ||
|
|
406
|
+
selected: ranked[0]?.harness || null,
|
|
401
407
|
complexity,
|
|
402
408
|
candidates: ranked
|
|
403
409
|
};
|
|
@@ -495,6 +501,8 @@ export function evaluateGateCascade(currentHarness, gateResults = {}, availableH
|
|
|
495
501
|
export function computeEmpiricalScorecard(historyRuns = []) {
|
|
496
502
|
const summary = {};
|
|
497
503
|
for (const run of historyRuns) {
|
|
504
|
+
// Quota walls, sign-in gaps and process failures say nothing about the harness's work.
|
|
505
|
+
if (['quota', 'auth', 'process', 'not-ready'].includes(run.failureKind)) continue;
|
|
498
506
|
const h = run.harness || 'unknown';
|
|
499
507
|
if (!summary[h]) {
|
|
500
508
|
summary[h] = { total: 0, passed: 0, failed: 0, totalDurationMs: 0, passRate: 0, avgDurationMs: 0 };
|
|
@@ -517,6 +525,125 @@ export function computeEmpiricalScorecard(historyRuns = []) {
|
|
|
517
525
|
return summary;
|
|
518
526
|
}
|
|
519
527
|
|
|
528
|
+
/**
|
|
529
|
+
* Synthesize raw subagent output through a strict "One-Way Valve" filter.
|
|
530
|
+
* Compresses verbose exploratory dumps, file trees, and search outputs into
|
|
531
|
+
* a dense, structured context digest bounded by maxChars (default 2000 chars, ~500 tokens).
|
|
532
|
+
* Prevents downstream context rot across multi-step orchestration.
|
|
533
|
+
*/
|
|
534
|
+
export function synthesizeOneWayValve(rawOutput, options = {}) {
|
|
535
|
+
const maxChars = options.maxChars || 2000;
|
|
536
|
+
const text = String(rawOutput || '').trim();
|
|
537
|
+
if (!text) return 'No findings reported.';
|
|
538
|
+
|
|
539
|
+
// Extract file paths, line references, and key findings
|
|
540
|
+
const fileLines = text.split('\n');
|
|
541
|
+
const filesFound = new Set();
|
|
542
|
+
const keyObservations = [];
|
|
543
|
+
|
|
544
|
+
for (const line of fileLines) {
|
|
545
|
+
const trimmed = line.trim();
|
|
546
|
+
if (!trimmed) continue;
|
|
547
|
+
// Match potential file paths: e.g. src/foo.js, /path/to/file.mjs:42
|
|
548
|
+
const pathMatch = trimmed.match(/(?:[a-zA-Z0-9_-]+\/)+[a-zA-Z0-9._-]+\.[a-zA-Z0-9]+/);
|
|
549
|
+
if (pathMatch) {
|
|
550
|
+
filesFound.add(pathMatch[0]);
|
|
551
|
+
}
|
|
552
|
+
if (/^(found|note|warning|error|exports|function|class|symbol|defined|status|schema|todo|fixme)/i.test(trimmed) || trimmed.startsWith('- ') || trimmed.startsWith('* ')) {
|
|
553
|
+
if (keyObservations.length < 15) {
|
|
554
|
+
keyObservations.push(trimmed.replace(/^[-*]\s*/, ''));
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
const parts = [];
|
|
560
|
+
if (filesFound.size > 0) {
|
|
561
|
+
parts.push(`Relevant Files: ${Array.from(filesFound).slice(0, 10).join(', ')}`);
|
|
562
|
+
}
|
|
563
|
+
if (keyObservations.length > 0) {
|
|
564
|
+
parts.push(`Key Findings:\n- ${keyObservations.join('\n- ')}`);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
let digest = parts.join('\n\n');
|
|
568
|
+
if (!digest || digest.length < 50) {
|
|
569
|
+
digest = text.length > maxChars ? `${text.slice(0, maxChars - 20)}... [truncated]` : text;
|
|
570
|
+
} else if (digest.length > maxChars) {
|
|
571
|
+
digest = `${digest.slice(0, maxChars - 20)}... [truncated]`;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
return digest;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Decompose a multi-step task into specialized subagent stages:
|
|
579
|
+
* 1. Explorer (read-only codebase sweep, zero-cost / local preference)
|
|
580
|
+
* 2. Architect (modular design & file contracts, frontier preference)
|
|
581
|
+
* 3. Implementer (code authoring & unit test generation)
|
|
582
|
+
* 4. Verifier (adversarial code audit in isolated worktree, distinct model family)
|
|
583
|
+
*/
|
|
584
|
+
export function decomposeTask(taskDescription, options = {}) {
|
|
585
|
+
const task = String(taskDescription || '').trim();
|
|
586
|
+
if (!task) throw new Error('Task description is required for decomposition');
|
|
587
|
+
|
|
588
|
+
const complexity = classifyTaskComplexity(task, options);
|
|
589
|
+
const catalog = options.catalog || ADAPTER_CATALOG;
|
|
590
|
+
const available = options.availableHarnesses?.length ? options.availableHarnesses : Object.keys(catalog);
|
|
591
|
+
const entry = id => catalog[id] || {};
|
|
592
|
+
const byQuality = [...available].sort((a, b) => (entry(b).qualityScore ?? 0) - (entry(a).qualityScore ?? 0));
|
|
593
|
+
const byCost = [...available].sort((a, b) => (entry(a).costScore ?? 99) - (entry(b).costScore ?? 99));
|
|
594
|
+
|
|
595
|
+
// Explorer takes the cheapest harness, Architect the strongest
|
|
596
|
+
const explorerHarness = byCost[0] || null;
|
|
597
|
+
const architectHarness = byQuality[0] || null;
|
|
598
|
+
const implementerHarness = byQuality.find(id => id !== architectHarness && id !== explorerHarness) || architectHarness;
|
|
599
|
+
|
|
600
|
+
// Verifier must come from a different model family. Without one, it stays null rather than grading its own work.
|
|
601
|
+
const verifierHarness = byQuality.find(id => entry(id).family && entry(id).family !== entry(implementerHarness).family) || null;
|
|
602
|
+
const tierOf = id => entry(id).tier || null;
|
|
603
|
+
|
|
604
|
+
return {
|
|
605
|
+
task,
|
|
606
|
+
complexity,
|
|
607
|
+
crossFamilyVerification: Boolean(verifierHarness),
|
|
608
|
+
stages: [
|
|
609
|
+
{
|
|
610
|
+
id: 'stage-1-explore',
|
|
611
|
+
role: 'Explorer',
|
|
612
|
+
preferredHarness: explorerHarness,
|
|
613
|
+
tier: tierOf(explorerHarness),
|
|
614
|
+
permissions: { read: true, write: false },
|
|
615
|
+
objective: 'Sweep workspace, locate relevant files, inspect interfaces, and read official documentation without context bloat.',
|
|
616
|
+
valveFilter: true
|
|
617
|
+
},
|
|
618
|
+
{
|
|
619
|
+
id: 'stage-2-architect',
|
|
620
|
+
role: 'Architect',
|
|
621
|
+
preferredHarness: architectHarness,
|
|
622
|
+
tier: tierOf(architectHarness),
|
|
623
|
+
permissions: { read: true, write: false },
|
|
624
|
+
objective: 'Synthesize Explorer digest into modular architectural blueprint, interface contracts, and verification gates.'
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
id: 'stage-3-implement',
|
|
628
|
+
role: 'Implementer',
|
|
629
|
+
preferredHarness: implementerHarness,
|
|
630
|
+
tier: tierOf(implementerHarness),
|
|
631
|
+
permissions: { read: true, write: true },
|
|
632
|
+
objective: 'Author production implementation files and test cases strictly following the Architectural blueprint.'
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
id: 'stage-4-verify',
|
|
636
|
+
role: 'Verifier',
|
|
637
|
+
preferredHarness: verifierHarness,
|
|
638
|
+
tier: tierOf(verifierHarness),
|
|
639
|
+
worktreeIsolated: true,
|
|
640
|
+
permissions: { read: true, write: false },
|
|
641
|
+
objective: 'Adversarial code review and quality gate verification executed in an isolated Git worktree with a distinct model family.'
|
|
642
|
+
}
|
|
643
|
+
]
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
|
|
520
647
|
/**
|
|
521
648
|
* Meta Harness Brick Factory
|
|
522
649
|
*/
|
|
@@ -529,6 +656,8 @@ export function createMetaHarness(customAdapters = {}) {
|
|
|
529
656
|
select: (task, available, quotas, opts) => selectOptimalHarness(task, available, quotas, { ...opts, catalog: mergedAdapters }),
|
|
530
657
|
buildEnvelope: (task, opts) => buildBootstrapEnvelope(task, opts),
|
|
531
658
|
evaluateCascade: (harness, gates, available) => evaluateGateCascade(harness, gates, available),
|
|
532
|
-
scorecard: (runs) => computeEmpiricalScorecard(runs)
|
|
659
|
+
scorecard: (runs) => computeEmpiricalScorecard(runs),
|
|
660
|
+
decompose: (task, opts) => decomposeTask(task, { ...opts, catalog: mergedAdapters }),
|
|
661
|
+
valve: (raw, opts) => synthesizeOneWayValve(raw, opts)
|
|
533
662
|
};
|
|
534
663
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
3
4
|
import { pathToFileURL } from 'node:url';
|
|
4
|
-
import {
|
|
5
|
+
import { configDir } from './src/paths.mjs';
|
|
6
|
+
import { inspectAgents, getActiveAdapters, getCustomAdaptersDirs, loadCustomAdapters } from './src/worker.mjs';
|
|
5
7
|
import { inspectNode, listTargets, executeCommand, executeOnNode } from './src/executor.mjs';
|
|
6
8
|
import { DOC_SOURCES, documentationStatus, refreshDocumentation, ensureDocumentation, maintainDocumentation, readDocumentation, searchDocumentation } from './src/documentation.mjs';
|
|
7
9
|
import { manageRuntime } from './src/runtime.mjs';
|
|
@@ -9,14 +11,62 @@ import { setupIntegrations } from './src/setup.mjs';
|
|
|
9
11
|
import { inspectUpstreamFleet, getAgentChangelog } from './src/tracker.mjs';
|
|
10
12
|
import { inspectQuotas, getBenchmarks, routeTask } from './src/router.mjs';
|
|
11
13
|
import { coordinateTask } from './src/coordinator.mjs';
|
|
12
|
-
import {
|
|
14
|
+
import { executeRoutedTask } from './src/cascade.mjs';
|
|
15
|
+
import { dispatchWithReceipt } from './src/dispatch.mjs';
|
|
16
|
+
import { resolvePool } from './src/pool.mjs';
|
|
17
|
+
import { checkAlerts, notifyAlert } from './src/alerts.mjs';
|
|
18
|
+
import { learnFromHistory } from './src/learner.mjs';
|
|
19
|
+
import { decomposeTask } from './capability/index.mjs';
|
|
20
|
+
import { listThreads, getThread, createThread, closeThread, deleteThread } from './src/threads.mjs';
|
|
21
|
+
import { executeCodeReview } from './src/review.mjs';
|
|
22
|
+
|
|
23
|
+
const VALUE_FLAGS = ['--node', '--mode', '--orchestrator', '--branch', '--reviewer', '--thread', '--status', '--platform', '--agent', '--url', '--query', '--tier', '--threshold', '--author', '--explorer', '--architect', '--implementer', '--verifier'];
|
|
24
|
+
export function parseArguments(args) {
|
|
25
|
+
const positional = [];
|
|
26
|
+
for (let index = 1; index < args.length; index += 1) {
|
|
27
|
+
if (VALUE_FLAGS.includes(args[index])) { index += 1; continue; }
|
|
28
|
+
if (!args[index].startsWith('--')) positional.push(args[index]);
|
|
29
|
+
}
|
|
30
|
+
const value = name => {
|
|
31
|
+
const index = args.indexOf(name);
|
|
32
|
+
if (index < 0) return undefined;
|
|
33
|
+
if (!args[index + 1] || args[index + 1].startsWith('--')) throw new Error(`${name} requires a value`);
|
|
34
|
+
return args[index + 1];
|
|
35
|
+
};
|
|
36
|
+
return { positional, value, has: name => args.includes(name) };
|
|
37
|
+
}
|
|
13
38
|
|
|
14
39
|
export async function run(argv = []) {
|
|
40
|
+
try { await runOperation(argv); }
|
|
41
|
+
catch (error) {
|
|
42
|
+
const message = String(error?.message || error);
|
|
43
|
+
if (argv.includes('--json')) console.log(JSON.stringify({ ok: false, error: message }));
|
|
44
|
+
else console.error(`meta-harness: ${message}`);
|
|
45
|
+
process.exitCode = 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The host stops a plugin command after 10 minutes, so long runs detach and report through their thread and log. */
|
|
50
|
+
function detachRun(argv) {
|
|
51
|
+
const directory = path.join(configDir(), 'jobs');
|
|
52
|
+
fs.mkdirSync(directory, { recursive: true, mode: 0o700 });
|
|
53
|
+
const log = path.join(directory, `${Date.now().toString(36)}.log`);
|
|
54
|
+
const output = fs.openSync(log, 'a', 0o600);
|
|
55
|
+
const entry = new URL('./cli.mjs', import.meta.url).href;
|
|
56
|
+
const child = spawn(process.execPath, ['--input-type=module', '-e', `import(${JSON.stringify(entry)}).then(m=>m.run(${JSON.stringify(argv.filter(arg => arg !== '--background'))}))`], { cwd: process.cwd(), detached: true, stdio: ['ignore', output, output], env: process.env });
|
|
57
|
+
child.unref();
|
|
58
|
+
fs.closeSync(output);
|
|
59
|
+
return { ok: true, background: true, pid: child.pid, log, follow: 'total-recall meta-harness threads list --json' };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function runOperation(argv) {
|
|
15
63
|
const args = argv.slice(3); const operation = args[0] || 'status';
|
|
64
|
+
const { positional, value, has } = parseArguments(args);
|
|
65
|
+
if (has('--background') && ['route', 'coordinate', 'orchestrate'].includes(operation) && has('--execute')) { console.log(JSON.stringify(detachRun(argv))); return; }
|
|
16
66
|
// Help anywhere in the arguments prints usage; it must never run an operation.
|
|
17
67
|
if (operation === 'help' || args.some(arg => arg === '--help' || arg === '-h')) {
|
|
18
68
|
const manifest=JSON.parse(fs.readFileSync(new URL('./plugin.json',import.meta.url),'utf8'));
|
|
19
|
-
console.log('Usage: total-recall
|
|
69
|
+
console.log('Usage: total-recall meta-harness <operation> [options] (alias: cli-agents)\nEvery agent receives Total Recall bootstrap before dispatch. Runtime syntax: runtime <agent> <native-command...> [--node ID].\n');
|
|
20
70
|
for(const command of manifest.cli.subcommands)console.log(` ${command.name} ${(command.args || []).map(arg=>arg.flag?`${arg.flag} <${arg.name}>`:`<${arg.name}>`).join(' ')} — ${command.description}`);
|
|
21
71
|
return;
|
|
22
72
|
}
|
|
@@ -24,28 +74,82 @@ export async function run(argv = []) {
|
|
|
24
74
|
if (operation === 'status') result = {...await inspectAgents(),documentation:documentationStatus()};
|
|
25
75
|
else if (operation === 'catalog') result = { adapters: getActiveAdapters(), permissions: ['read', 'write', 'send', 'destructive'] };
|
|
26
76
|
else if (operation === 'nodes') result = await listTargets();
|
|
27
|
-
else if (operation === 'quota') {
|
|
28
|
-
|
|
29
|
-
result = await inspectQuotas({ node: index >= 0 ? args[index + 1] : 'local' });
|
|
30
|
-
}
|
|
31
|
-
else if (operation === 'benchmarks') result = getBenchmarks();
|
|
77
|
+
else if (operation === 'quota') result = await inspectQuotas({ node: value('--node') || 'local' });
|
|
78
|
+
else if (operation === 'benchmarks') result = await getBenchmarks();
|
|
32
79
|
else if (operation === 'route') {
|
|
33
|
-
const
|
|
34
|
-
const preferLocal = args.includes('--prefer-local');
|
|
35
|
-
const preferFrontier = args.includes('--prefer-frontier');
|
|
36
|
-
const task = args.slice(1).filter(a => !a.startsWith('--')).join(' ');
|
|
80
|
+
const task = positional.join(' ');
|
|
37
81
|
if (!task) throw new Error('route requires a task description');
|
|
38
|
-
|
|
82
|
+
const options = { jev: has('--jev'), preferLocal: has('--prefer-local'), preferFrontier: has('--prefer-frontier') };
|
|
83
|
+
result = has('--execute') ? await executeRoutedTask(task, { ...options, gate: has('--gate'), gateOptions: { tier: value('--tier') || 'fast' } }) : await routeTask(task, options);
|
|
84
|
+
if (!result.ok) process.exitCode = 1;
|
|
39
85
|
}
|
|
40
|
-
else if (operation === '
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
86
|
+
else if (operation === 'decompose') {
|
|
87
|
+
const task = positional.join(' ');
|
|
88
|
+
if (!task) throw new Error('decompose requires a task description');
|
|
89
|
+
const pool = await resolvePool();
|
|
90
|
+
result = { ...decomposeTask(task, { availableHarnesses: pool.ready.map(h => h.id) }), excluded: pool.excluded };
|
|
91
|
+
}
|
|
92
|
+
else if (operation === 'coordinate' || operation === 'orchestrate') {
|
|
93
|
+
const task = positional.join(' ');
|
|
94
|
+
if (!task) throw new Error(`${operation} requires a task description`);
|
|
95
|
+
result = await coordinateTask(task, {
|
|
96
|
+
mode: value('--mode') || 'pipeline', execute: has('--execute'), orchestrator: value('--orchestrator'), explorer: value('--explorer'), architect: value('--architect'), implementer: value('--implementer'), verifier: value('--verifier'),
|
|
97
|
+
branch: value('--branch'), subagents: !has('--no-subagents'), autoReview: has('--auto-review'), gate: has('--gate'), gateOptions: { tier: value('--tier') || 'fast' }, allowSameFamily: has('--allow-same-family'), reviewer: value('--reviewer'),
|
|
98
|
+
});
|
|
99
|
+
if (!result.ok) process.exitCode = 1;
|
|
100
|
+
}
|
|
101
|
+
else if (operation === 'threads') {
|
|
102
|
+
const sub = args[1] || 'list';
|
|
103
|
+
if (sub === 'list') {
|
|
104
|
+
const statusIdx = args.indexOf('--status');
|
|
105
|
+
const platformIdx = args.indexOf('--platform');
|
|
106
|
+
result = listThreads({
|
|
107
|
+
status: statusIdx >= 0 ? args[statusIdx + 1] : undefined,
|
|
108
|
+
platform: platformIdx >= 0 ? args[platformIdx + 1] : undefined
|
|
109
|
+
});
|
|
110
|
+
} else if (sub === 'show' || sub === 'get') {
|
|
111
|
+
const id = args[2];
|
|
112
|
+
if (!id) throw new Error('threads show requires a thread id');
|
|
113
|
+
result = getThread(id);
|
|
114
|
+
if (!result) throw new Error(`Thread not found: ${id}`);
|
|
115
|
+
} else if (sub === 'create') {
|
|
116
|
+
const title = args.slice(2).filter(a => !a.startsWith('--')).join(' ');
|
|
117
|
+
const platformIdx = args.indexOf('--platform');
|
|
118
|
+
const branchIdx = args.indexOf('--branch');
|
|
119
|
+
result = createThread({
|
|
120
|
+
title: title || 'New Agent Thread',
|
|
121
|
+
platform: platformIdx >= 0 ? args[platformIdx + 1] : 'universal',
|
|
122
|
+
branch: branchIdx >= 0 ? args[branchIdx + 1] : null
|
|
123
|
+
});
|
|
124
|
+
} else if (sub === 'close') {
|
|
125
|
+
const id = args[2];
|
|
126
|
+
if (!id) throw new Error('threads close requires a thread id');
|
|
127
|
+
result = closeThread(id);
|
|
128
|
+
} else if (sub === 'delete') {
|
|
129
|
+
const id = args[2];
|
|
130
|
+
if (!id) throw new Error('threads delete requires a thread id');
|
|
131
|
+
result = { ok: deleteThread(id) };
|
|
132
|
+
} else {
|
|
133
|
+
throw new Error(`Unsupported threads operation: ${sub}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else if (operation === 'review') {
|
|
137
|
+
result = await executeCodeReview({ target: positional[0] || null, reviewer: value('--reviewer'), author: value('--author'), threadId: value('--thread'), staged: has('--staged') });
|
|
138
|
+
if (!result.ok) process.exitCode = 1;
|
|
139
|
+
}
|
|
140
|
+
else if (operation === 'learn') {
|
|
141
|
+
result = await learnFromHistory({ emit: has('--emit') });
|
|
142
|
+
if (!result.ok) process.exitCode = 1;
|
|
143
|
+
}
|
|
144
|
+
else if (operation === 'alerts') {
|
|
145
|
+
const sub = positional[0] || 'check';
|
|
146
|
+
if (sub === 'check') {
|
|
147
|
+
const { quotas } = await inspectQuotas({});
|
|
148
|
+
result = await checkAlerts({ quotas, threshold: Number(value('--threshold')) || 85, dryRun: has('--dry-run') });
|
|
149
|
+
} else if (sub === 'test') result = await notifyAlert({ title: 'Meta Harness: test alert', message: 'Alert delivery check.', dryRun: has('--dry-run') });
|
|
150
|
+
else throw new Error(`Unsupported alerts operation: ${sub}`);
|
|
151
|
+
if (!result.ok) process.exitCode = 1;
|
|
47
152
|
}
|
|
48
|
-
else if (operation === 'learn') result = learnFromHistory();
|
|
49
153
|
else if (operation === 'upstream') result = await inspectUpstreamFleet(getActiveAdapters());
|
|
50
154
|
else if (operation === 'changelog') result = getAgentChangelog(args[1] || 'agy');
|
|
51
155
|
else if (operation === 'adapter') {
|
|
@@ -97,8 +201,13 @@ export async function run(argv = []) {
|
|
|
97
201
|
if (selected>=0 && (!args[selected+1] || args[selected+1].startsWith('-'))) throw new Error('--agent requires an adapter identifier');
|
|
98
202
|
const options = selected>=0 ? {agent:args[selected+1]} : {};
|
|
99
203
|
if(operation==='maintenance') {
|
|
100
|
-
|
|
101
|
-
|
|
204
|
+
if (has('--models')) {
|
|
205
|
+
const { syncModelCatalog } = await import('./src/model-catalog.mjs');
|
|
206
|
+
result = await syncModelCatalog();
|
|
207
|
+
} else {
|
|
208
|
+
const setup=await setupIntegrations();
|
|
209
|
+
result={...await maintainDocumentation(options),setup};
|
|
210
|
+
}
|
|
102
211
|
} else result = operation==='docs-status' ? documentationStatus(options) : operation==='docs-ensure' ? await ensureDocumentation(options) : await refreshDocumentation(options);
|
|
103
212
|
if(!result.ok)process.exitCode=1;
|
|
104
213
|
}
|
|
@@ -106,14 +215,14 @@ export async function run(argv = []) {
|
|
|
106
215
|
const runtimeArgs=args.slice(1).filter(arg=>arg!=='--json'), agent=runtimeArgs.shift();
|
|
107
216
|
const index=runtimeArgs.indexOf('--node'); let node='local';
|
|
108
217
|
if(index>=0){node=runtimeArgs[index+1];if(!node || node.startsWith('-'))throw new Error('--node requires an identifier');runtimeArgs.splice(index,2);}
|
|
109
|
-
result = node==='local' ? await manageRuntime(agent,runtimeArgs) : await executeOnNode(node,{operation:'direct',cwd:process.cwd(),argv:['total-recall','
|
|
218
|
+
result = node==='local' ? await manageRuntime(agent,runtimeArgs) : await executeOnNode(node,{operation:'direct',cwd:process.cwd(),argv:['total-recall','meta-harness','runtime',agent,...runtimeArgs,'--json']});
|
|
110
219
|
if(!result.ok)process.exitCode=1;
|
|
111
220
|
}
|
|
112
221
|
else if(operation==='dispatch') {
|
|
113
222
|
if(!args.includes('--stdin'))throw new Error('Task requests must arrive through stdin');
|
|
114
223
|
const input=fs.readFileSync(0,'utf8');if(Buffer.byteLength(input)>65536)throw new Error('Task request too large');
|
|
115
224
|
const request=JSON.parse(input);
|
|
116
|
-
result=await
|
|
225
|
+
result=await dispatchWithReceipt({...request,allowUnknownAuth:request.allowUnknownAuth===true},{node:request.node || 'local',role:'Dispatch'});
|
|
117
226
|
if(!result.ok)process.exitCode=1;
|
|
118
227
|
}
|
|
119
228
|
else if (operation === 'inspect') {
|
|
@@ -133,7 +242,7 @@ export async function run(argv = []) {
|
|
|
133
242
|
const plugin = getPlugin(request.pluginId, request.projectRoot || process.cwd());
|
|
134
243
|
result = await executeCommand({ ...request, plugin });
|
|
135
244
|
if (!result.ok) process.exitCode = 1;
|
|
136
|
-
} else throw new Error(
|
|
245
|
+
} else throw new Error(`Unknown operation: ${operation}`);
|
|
137
246
|
console.log(JSON.stringify(result));
|
|
138
247
|
}
|
|
139
248
|
export default run;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"@gregiteen/ssss-cli": "0.14.4"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"total-recall-brain": "3.41.
|
|
14
|
+
"total-recall-brain": "3.41.5"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"node_modules/@alcalzone/ansi-tokenize": {
|
|
@@ -1589,9 +1589,9 @@
|
|
|
1589
1589
|
},
|
|
1590
1590
|
"node_modules/@ssss/cli": {
|
|
1591
1591
|
"name": "@gregiteen/ssss-cli",
|
|
1592
|
-
"version": "0.14.
|
|
1593
|
-
"resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.
|
|
1594
|
-
"integrity": "sha512-
|
|
1592
|
+
"version": "0.14.4",
|
|
1593
|
+
"resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.4.tgz",
|
|
1594
|
+
"integrity": "sha512-R6JIgPRvS9xXp0xb6BYO3rauv+72r35GIiDrJcvbjPdTSHFZXr8/jRxFOgoF8yTed/5xyGFF3ey3DI9bOjmHVA==",
|
|
1595
1595
|
"dev": true,
|
|
1596
1596
|
"license": "ISC",
|
|
1597
1597
|
"bin": {
|
|
@@ -5546,9 +5546,9 @@
|
|
|
5546
5546
|
}
|
|
5547
5547
|
},
|
|
5548
5548
|
"node_modules/total-recall-brain": {
|
|
5549
|
-
"version": "3.41.
|
|
5550
|
-
"resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.
|
|
5551
|
-
"integrity": "sha512-
|
|
5549
|
+
"version": "3.41.5",
|
|
5550
|
+
"resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.41.5.tgz",
|
|
5551
|
+
"integrity": "sha512-gaW46xAtnFf+zfkv8LHYQLMzt27JjelyFggc8zAZafCnCJRbNSP8D02cbbcx49f3a70t/hkgA9RhJOY8HTqRFg==",
|
|
5552
5552
|
"dev": true,
|
|
5553
5553
|
"license": "MIT",
|
|
5554
5554
|
"workspaces": [
|
|
@@ -5556,7 +5556,7 @@
|
|
|
5556
5556
|
],
|
|
5557
5557
|
"dependencies": {
|
|
5558
5558
|
"@simplewebauthn/server": "^13.3.2",
|
|
5559
|
-
"@ssss/cli": "npm:@gregiteen/ssss-cli@0.14.
|
|
5559
|
+
"@ssss/cli": "npm:@gregiteen/ssss-cli@0.14.4",
|
|
5560
5560
|
"bcrypt": "^6.0.0",
|
|
5561
5561
|
"better-sqlite3": "^12.11.1",
|
|
5562
5562
|
"cookie-parser": "^1.4.7",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "Total Recall Meta Harness plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "node --test test/*.test.mjs",
|
|
7
|
+
"test": "node --import ./test/isolate.mjs --test test/*.test.mjs",
|
|
8
8
|
"ssss": "ssss"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
@@ -22,5 +22,8 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@gregiteen/ssss-cli": "0.14.4"
|
|
25
|
+
},
|
|
26
|
+
"overrides": {
|
|
27
|
+
"@ssss/cli": "npm:@gregiteen/ssss-cli@0.14.4"
|
|
25
28
|
}
|
|
26
29
|
}
|