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.
Files changed (131) hide show
  1. package/bin/total-recall.mjs +7 -4
  2. package/frontend/dist/assets/index-4tGQfTa2.js +5605 -0
  3. package/frontend/dist/assets/index-DtwsDyFM.css +1 -0
  4. package/frontend/dist/index.html +2 -2
  5. package/frontend/package.json +11 -0
  6. package/frontend/src/App.tsx +47 -122
  7. package/frontend/src/components/plugins/plugin-frame.ts +1 -0
  8. package/frontend/src/index.css +152 -86
  9. package/frontend/src/pages/HelpPage.tsx +13 -10
  10. package/frontend/src/pages/MemoryPage.tsx +28 -30
  11. package/frontend/src/pages/NetworkPage.tsx +3 -3
  12. package/frontend/src/pages/PluginsPage.tsx +6 -5
  13. package/frontend/src/pages/RulesPage.tsx +16 -12
  14. package/package.json +3 -2
  15. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +8 -8
  16. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +3 -0
  17. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +8 -8
  18. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +3 -0
  19. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +8 -8
  20. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +3 -0
  21. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +8 -8
  22. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +3 -0
  23. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +8 -8
  24. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +4 -1
  25. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +1 -1
  26. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +136 -7
  27. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +135 -26
  28. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +8 -8
  29. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +4 -1
  30. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +228 -9
  31. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +24 -30
  32. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +29 -16
  33. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +73 -0
  34. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +182 -365
  35. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +33 -0
  36. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +9 -3
  37. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +4 -4
  38. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/agy.mjs +187 -0
  39. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/claude.mjs +275 -0
  40. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cline.mjs +132 -0
  41. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/codex.mjs +187 -0
  42. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cursor.mjs +158 -0
  43. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/devin.mjs +157 -0
  44. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/dsh.mjs +183 -0
  45. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/grok.mjs +132 -0
  46. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +173 -0
  47. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +87 -0
  48. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/openclaw.mjs +173 -0
  49. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/pi.mjs +129 -0
  50. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate.mjs +12 -0
  51. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/json-reply.mjs +22 -0
  52. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +72 -70
  53. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-catalog.mjs +195 -0
  54. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/paths.mjs +11 -0
  55. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +36 -0
  56. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +169 -0
  57. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +136 -346
  58. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +1 -1
  59. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/ssss-store.mjs +20 -0
  60. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/telemetry.mjs +43 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +156 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +117 -35
  63. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +51 -0
  64. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +398 -57
  65. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +10 -0
  66. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +3 -3
  67. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +3 -0
  68. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +42 -190
  69. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/openwiki.mjs +1 -1
  70. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/mermaid-diagrams/SKILL.md +44 -0
  71. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/write-connector/SKILL.md +56 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +8 -8
  73. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +3 -0
  74. package/src/cli/agent.mjs +12 -1
  75. package/src/cli/compact.mjs +2 -2
  76. package/src/cli/connect.mjs +56 -1
  77. package/src/cli/context.mjs +10 -7
  78. package/src/cli/doctor.mjs +5 -2
  79. package/src/cli/harness.mjs +62 -50
  80. package/src/cli/memory-entry.mjs +2 -2
  81. package/src/cli/preflight.mjs +152 -16
  82. package/src/cli/remember.mjs +19 -1
  83. package/src/cli/rules.mjs +54 -12
  84. package/src/cli/startup.mjs +1 -1
  85. package/src/cli/status.mjs +12 -2
  86. package/src/core/claude-hooks.mjs +41 -3
  87. package/src/core/cli-semantic-index.mjs +3 -2
  88. package/src/core/conflict-detector.mjs +23 -12
  89. package/src/core/context-compactor.mjs +2 -0
  90. package/src/core/context-policy.mjs +20 -0
  91. package/src/core/duplicate-guard.mjs +350 -0
  92. package/src/core/meta-harness.mjs +31 -11
  93. package/src/core/preflight-gate.mjs +2 -2
  94. package/src/core/preflight-receipt.mjs +28 -0
  95. package/src/core/scaffold-plugins.mjs +7 -0
  96. package/src/core/stdio-flush.mjs +23 -0
  97. package/src/core/surface.mjs +33 -10
  98. package/src/server/routes/plugins.mjs +2 -2
  99. package/frontend/dist/assets/index-BIQmqDKP.css +0 -1
  100. package/frontend/dist/assets/index-WT3gs-x6.js +0 -5631
  101. package/frontend/src/components/DaemonLogsTab.tsx +0 -54
  102. package/frontend/src/components/ResearchAgendaTab.tsx +0 -712
  103. package/frontend/src/components/TaskQueueTab.tsx +0 -193
  104. package/frontend/src/components/VoiceInput.tsx +0 -112
  105. package/frontend/src/pages/ChatPage.tsx +0 -1059
  106. package/frontend/src/pages/CollabPage.tsx +0 -470
  107. package/frontend/src/pages/DesignDocsPage.tsx +0 -621
  108. package/frontend/src/pages/FilesPage.tsx +0 -393
  109. package/frontend/src/pages/HealthPage.tsx +0 -359
  110. package/frontend/src/pages/InboxPage.tsx +0 -83
  111. package/frontend/src/pages/InstructionsPage.tsx +0 -583
  112. package/frontend/src/pages/IntegrationsPage.tsx +0 -761
  113. package/frontend/src/pages/MeshPage.css +0 -58
  114. package/frontend/src/pages/MeshPage.tsx +0 -1219
  115. package/frontend/src/pages/OkfPage.tsx +0 -535
  116. package/frontend/src/pages/SandboxPage.tsx +0 -113
  117. package/frontend/src/pages/SkillsPage.tsx +0 -1994
  118. package/frontend/src/pages/TasksPage.tsx +0 -427
  119. package/frontend/src/pages/UsagePage.tsx +0 -702
  120. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/README.md +0 -65
  121. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/cli.mjs +0 -76
  122. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/package.json +0 -19
  123. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +0 -266
  124. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/adapters/dsh.mjs +0 -446
  125. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/documentation.mjs +0 -152
  126. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/executor.mjs +0 -71
  127. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/runtime.mjs +0 -36
  128. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/setup.mjs +0 -35
  129. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/worker.mjs +0 -175
  130. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +0 -32
  131. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +0 -575
@@ -1,71 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
- import { pathToFileURL } from 'node:url';
4
- import { runWorker, runProcess, ADAPTERS } from './worker.mjs';
5
-
6
- async function hostModule(name) {
7
- const selected = process.env.TR_PACKAGE_ROOT;
8
- if (!selected || !path.isAbsolute(selected)) throw new Error('Verified native Total Recall host required');
9
- const root = fs.realpathSync(selected);
10
- if (JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')).name !== 'total-recall-brain') throw new Error('Host package identity mismatch');
11
- return import(pathToFileURL(path.join(root, 'src/core', `${name}.mjs`)).href);
12
- }
13
-
14
- export const DEFAULT_PERMISSIONS = Object.freeze({ read: true, write: false, send: false, destructive: false });
15
- export function commandPermissions(value = DEFAULT_PERMISSIONS) {
16
- if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('Command permissions must be boolean values');
17
- for (const key of Object.keys(value)) if (!Object.hasOwn(DEFAULT_PERMISSIONS, key) || typeof value[key] !== 'boolean') throw new Error(`Invalid permission ${key}`);
18
- return { ...DEFAULT_PERMISSIONS, ...value };
19
- }
20
-
21
- export async function listTargets() {
22
- const mesh = await hostModule('mesh');
23
- return { nodes: mesh.listEnrichedMeshNodes().map(node => ({ id: node.hostname, name: node.title || node.hostname, online: node.online, self: node.self, accessConfigured: Boolean(node.access?.ssh_user) })), adapters: ADAPTERS.map(({ id, name, docs }) => ({ id, name, docs })) };
24
- }
25
-
26
- export function workerProgram(request) {
27
- const source = fs.readFileSync(new URL('./worker.mjs', import.meta.url), 'utf8');
28
- return source + '\nrunWorker(' + JSON.stringify(request) + ').then(result=>console.log(JSON.stringify(result))).catch(()=>{console.error("Selected agent worker failed");process.exitCode=1;});\n';
29
- }
30
-
31
- export async function executeOnNode(node, request, { worker = runWorker, processRunner = runProcess, mesh, access } = {}) {
32
- if (!node || node === 'local') return worker(request);
33
- mesh ||= await hostModule('mesh'); access ||= await hostModule('mesh-access');
34
- const target = mesh.findMeshNode(node);
35
- if (!target) throw new Error('Selected mesh node is not recorded');
36
- if (target.self) return worker(request);
37
- if (target.online === false) throw new Error('Selected mesh node is offline');
38
- const resolved = access.resolveNodeAccess(target);
39
- const args = access.buildSshArgs(resolved, { command: 'export PATH="$HOME/.local/bin:/opt/homebrew/bin:/usr/local/bin:$PATH"; exec node --input-type=module', extraOptions: ['BatchMode=yes', 'ConnectTimeout=10'] });
40
- if (!args) throw new Error('Selected mesh node has no verified SSH access');
41
- const result = await processRunner('ssh', args, { input: workerProgram(request), timeoutMs: request.operation === 'inspect' ? 120000 : 330000 });
42
- if (result.reason || result.exitCode !== 0) throw new Error('Selected mesh worker failed; verify node access, workspace and agent installation');
43
- try { return JSON.parse(result.stdout); } catch { throw new Error('Selected mesh worker returned invalid data'); }
44
- }
45
-
46
- export async function inspectNode(node = 'local', dependencies) {
47
- return executeOnNode(node, { operation: 'inspect' }, dependencies);
48
- }
49
-
50
- export function quoteArgument(value) { return "'" + String(value).replaceAll("'", "'\\''") + "'"; }
51
-
52
- export async function executeCommand({ plugin, subcommand, args = [], execution, projectRoot = process.cwd() }, dependencies = {}) {
53
- if (!plugin?.valid || !execution || typeof execution.agent !== 'string' || typeof execution.node !== 'string') throw new Error('Choose an installed agent and mesh node');
54
- if (!Array.isArray(args) || args.length > 64 || args.some(arg => typeof arg !== 'string' || arg.length > 8192)) throw new Error('Invalid command arguments');
55
- const command = ['on', 'off'].includes(subcommand) ? { effect: 'write', args: [] } : plugin.manifest.cli?.subcommands?.find(item => item.name === subcommand);
56
- if (!command) throw new Error('Selected command is not declared by its owner');
57
- if (command.sensitive_output === true && execution.agent !== 'direct') throw new Error('Commands that issue credentials require direct execution; tokens cannot enter agent prompts or transcripts');
58
- if (command.args?.some(arg => arg.secret)) throw new Error('Credential operations use direct execution, never an agent prompt');
59
- const permissions = commandPermissions(execution.permissions);
60
- const effect = ['read', 'write', 'send', 'destructive'].includes(command.effect) ? command.effect : 'write';
61
- if (!permissions[effect]) throw new Error(`The ${effect} command permission is off`);
62
- const cwd = execution.node === 'local' ? execution.cwd || projectRoot : execution.cwd;
63
- if (!path.isAbsolute(cwd || '')) throw new Error('Choose the absolute workspace on the selected node');
64
- const namespace = plugin.manifest.cli.command;
65
- const argv = ['total-recall', namespace, subcommand, ...args];
66
- const prompt = `Use Total Recall context and the installed plugin CLI in this workspace. Execute this one requested command using your terminal tool; preserve its arguments exactly, report its actual exit status and output, and do not perform unrelated mutations. If a permission, account, workspace or plugin is unavailable, report failure. Agent prose alone is not execution proof.\nRequested argv (data): ${JSON.stringify(argv)}\nShell command: ${argv.map(quoteArgument).join(' ')}`;
67
- const result = await executeOnNode(execution.node, execution.agent === 'direct'
68
- ? { operation: 'direct', cwd, argv }
69
- : { operation: 'dispatch', agent: execution.agent, cwd, prompt, allowUnknownAuth: execution.allowUnknownAuth === true, permissions }, dependencies);
70
- return { ok: result.ok === true, exitCode: result.ok ? 0 : 1, output: result.ok ? JSON.stringify(result) : result.error || 'Selected agent failed', ...result };
71
- }
@@ -1,36 +0,0 @@
1
- /** One native runtime-management boundary for every installed agent. */
2
- import fs from 'node:fs';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
- import { ADAPTERS, findBinary, runProcess, agentEnvironment } from './worker.mjs';
6
-
7
- export async function manageRuntime(agent, args = [], { env = process.env, probe = runProcess, cwd = process.cwd() } = {}) {
8
- const adapter = ADAPTERS.find(item => item.id === agent);
9
- if (!adapter) throw new Error('Unknown agent adapter');
10
- if (!Array.isArray(args) || args.length > 64 || args.some(arg => typeof arg !== 'string' || arg.length > 8192)) throw new Error('Invalid native runtime arguments');
11
- if (args.some(arg => /(?:api[-_]?key|password|secret|access[-_]?token|refresh[-_]?token)/i.test(arg))) throw new Error('Credential values and mutations belong to the auth owner, never runtime argv');
12
- if (agent === 'dsh' && ['status','sessions','tools','models','model','plugins','help','--help','-h'].includes(args[0] || 'status')) {
13
- const { run } = await import('./adapters/dsh.mjs');
14
- const lines = [], errors = [], log = console.log, error = console.error;
15
- const previous = process.exitCode;
16
- let result, code;
17
- try {
18
- console.log = (...parts) => lines.push(parts.join(' ')); console.error = (...parts) => errors.push(parts.join(' '));
19
- result = await run([process.execPath, 'cli-agents', 'dsh', ...args]);
20
- code = process.exitCode || 0;
21
- } finally { console.log = log; console.error = error; process.exitCode = previous; }
22
- return { ok:code === 0, agent, exitCode:code, data:result?.data, output:lines.join('\n'), error:errors.join('\n') || undefined };
23
- }
24
- if (agent === 'hermes' && args[0] === 'auth') {
25
- const binary = findBinary('total-recall', env);
26
- if (!binary) throw new Error('Total Recall auth CLI is unavailable');
27
- const home = env.HERMES_HOME || path.join(env.HOME || os.homedir(), '.hermes');
28
- fs.mkdirSync(home, { recursive:true, mode:0o700 });
29
- const result = await probe(binary, ['auth','secret','export-env','--path',home,'--keys','OPENROUTER_API_KEY,TELEGRAM_BOT_TOKEN,TELEGRAM_ALLOWED_USERS'], { cwd, timeoutMs:30000, env:agentEnvironment(env) });
30
- return { ok:result.exitCode===0 && !result.reason, agent, authority:'auth', exitCode:result.exitCode, output:result.stdout, error:result.reason || (result.exitCode ? 'Auth projection failed' : undefined) };
31
- }
32
- const binary = findBinary(adapter.binary, env);
33
- if (!binary) throw new Error(`${adapter.name} is not installed on the selected node`);
34
- const result = await probe(binary, args.length ? args : ['--help'], { cwd, timeoutMs:60000, env:agentEnvironment(env) });
35
- return { ok:result.exitCode===0 && !result.reason, agent, exitCode:result.exitCode, output:result.stdout, error:result.reason || (result.exitCode ? result.stderr || 'Runtime command failed' : undefined) };
36
- }
@@ -1,35 +0,0 @@
1
- /** Configure through Total Recall's existing connect, compilation and plugin-record owners. */
2
- import fs from 'node:fs';
3
- import path from 'node:path';
4
- import { pathToFileURL } from 'node:url';
5
- import { findBinary, runProcess, agentEnvironment } from './worker.mjs';
6
-
7
- export async function setupIntegrations({ node, cwd = process.cwd(), env = process.env, probe = runProcess } = {}) {
8
- const binary=findBinary('total-recall',env);
9
- if(!binary)throw new Error('Total Recall CLI is unavailable');
10
- const connected=[];
11
- for(const client of ['claude-code','codex','antigravity','cursor','dsh','grok','muse','pi','hermes']) {
12
- const result=await probe(binary,['connect',client],{cwd,env:agentEnvironment(env),timeoutMs:120000});
13
- if(result.exitCode!==0 || result.reason) {
14
- if(/Unknown client/i.test(result.stderr || result.stdout || '')) continue;
15
- throw new Error(`Total Recall connect ${client} failed`);
16
- }
17
- connected.push(client);
18
- }
19
- const root=env.TR_PACKAGE_ROOT;
20
- if(!root || !path.isAbsolute(root) || JSON.parse(fs.readFileSync(path.join(root,'package.json'),'utf8')).name!=='total-recall-brain')throw new Error('Verified native Total Recall host is required');
21
- let placement=null;
22
- if(node) {
23
- const {getPlugin}=await import(pathToFileURL(path.join(root,'src/core/plugin-loader.mjs')));
24
- const {patchPluginRecord,ensurePluginRecord}=await import(pathToFileURL(path.join(root,'src/core/plugin-store.mjs')));
25
- const mesh=await import(pathToFileURL(path.join(root,'src/core/mesh.mjs')));
26
- const target=mesh.findMeshNode(node);
27
- if(!target)throw new Error('Maintenance node is not recorded in the mesh');
28
- const plugin=getPlugin('cli-agents',cwd);
29
- if(!plugin?.valid)throw new Error('CLI-agents is not installed in the selected workspace');
30
- await ensurePluginRecord(plugin);
31
- placement=target.hostname;
32
- await patchPluginRecord(plugin,{task_nodes:{maintenance:placement}});
33
- }
34
- return {ok:true,connected,universalInstructions:'AGENTS.md; every dispatch also receives a freshly generated bootstrap',maintenanceNode:placement};
35
- }
@@ -1,175 +0,0 @@
1
- /** Portable read-only discovery / bounded dispatch worker; streamed to SSH stdin. */
2
- import fs from 'node:fs';
3
- import os from 'node:os';
4
- import path from 'node:path';
5
- import { spawn } from 'node:child_process';
6
-
7
- export const ADAPTERS = [
8
- { id: 'claude', name: 'Claude Code', binary: 'claude', args: ['--output-format', 'json', '--permission-mode', 'acceptEdits', '-p'], input: 'stdin', auth: ['auth', 'status'], docs: 'https://code.claude.com/docs/en/headless' },
9
- { id: 'codex', name: 'Codex', binary: 'codex', args: ['exec', '--sandbox', 'workspace-write', '--json', '-'], input: 'stdin', auth: ['login', 'status'], docs: 'https://developers.openai.com/codex/noninteractive' },
10
- { id: 'agy', name: 'Antigravity', binary: 'agy', args: ['--mode', 'accept-edits', '--sandbox', '--output-format', 'json', '-p'], input: 'argument', docs: 'https://antigravity.google/docs/cli/headless/' },
11
- { id: 'cursor', name: 'Cursor', binary: 'cursor-agent', args: ['--print', '--output-format', 'json'], input: 'argument', auth: ['status'], docs: 'https://docs.cursor.com/en/cli/reference/parameters' },
12
- { id: 'dsh', name: 'DSH', binary: 'dsh', args: ['--profile', 'headless', '--json', '-'], input: 'stdin', docs: 'https://github.com/deepseek-ai/deepseek-harness/blob/master/apps/cli/README.md' },
13
- { id: 'grok', name: 'Grok', binary: 'grok', args: ['--output-format', 'json', '-p'], input: 'argument', docs: 'https://docs.x.ai/build/cli/headless-scripting' },
14
- { id: 'muse', name: 'Muse', binary: 'muse', args: ['exec', '--json'], input: 'file', docs: 'https://dev.meta.ai/docs/muse-code/' },
15
- { id: 'pi', name: 'Pi', binary: 'pi', args: ['--print', '--mode', 'json', '--tools', 'read,bash', '--no-mcp', '--no-extensions'], input: 'stdin', docs: 'https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/docs/cli.md' },
16
- { id: 'hermes', name: 'Hermes', binary: 'hermes', args: ['chat', '--oneshot', '--format', 'stream-json', '--query-file', '-'], input: 'stdin', docs: 'https://github.com/NousResearch/hermes-agent/blob/main/website/docs/reference/cli-commands.md' },
17
- ];
18
-
19
- export function agentEnvironment(source = process.env) {
20
- const allowed = ['PATH', 'HOME', 'USER', 'LOGNAME', 'SHELL', 'TMPDIR', 'TMP', 'TEMP', 'LANG', 'LC_ALL', 'TERM', 'SYSTEMROOT', 'SystemRoot', 'APPDATA', 'LOCALAPPDATA', 'USERPROFILE', 'CODEX_HOME', 'CLAUDE_CONFIG_DIR', 'XDG_CONFIG_HOME', 'XDG_DATA_HOME', 'DSH_HOME', 'HERMES_HOME', 'PI_CODING_AGENT_DIR'];
21
- return Object.fromEntries(allowed.filter(key => typeof source[key] === 'string').map(key => [key, source[key]]));
22
- }
23
-
24
- export function findBinary(name, env = process.env) {
25
- const home = env.HOME || env.USERPROFILE || os.homedir();
26
- const installed = [path.dirname(process.execPath), path.join(home, '.local/bin'), path.join(home, '.npm-global/bin'), path.join(home, 'bin')];
27
- const versions = path.join(home, '.nvm/versions/node');
28
- try { for (const version of fs.readdirSync(versions).sort().reverse()) installed.push(path.join(versions, version, 'bin')); } catch {}
29
- for (const dir of [...new Set([...(env.PATH || '').split(path.delimiter), ...installed].filter(Boolean))]) {
30
- const file = path.join(dir, name);
31
- try { if (fs.statSync(file).isFile()) { fs.accessSync(file, fs.constants.X_OK); return file; } } catch {}
32
- }
33
- return null;
34
- }
35
-
36
- export function runProcess(binary, args, { cwd, input = '', timeoutMs = 300000, env = agentEnvironment(), maxBytes = 2 * 1024 * 1024 } = {}) {
37
- return new Promise(resolve => {
38
- let stdout = '', stderr = '', bytes = 0, reason = null, child, timer, escalation, settled = false;
39
- const kill = signal => { try { if (process.platform !== 'win32') process.kill(-child.pid, signal); else child.kill(signal); } catch {} };
40
- const finish = (exitCode, signal) => {
41
- if (settled) return;
42
- settled = true; clearTimeout(timer);
43
- // A parent can exit on TERM while a descendant still holds the process group.
44
- // Finish the owned group cleanup before releasing an aborted operation.
45
- if (reason && escalation) {
46
- clearTimeout(escalation);
47
- escalation = setTimeout(() => { kill('SIGKILL'); resolve({ exitCode, signal, stdout, stderr, reason }); }, 500);
48
- } else resolve({ exitCode, signal, stdout, stderr, reason });
49
- };
50
- const stop = cause => { if (reason) return; reason = cause; kill('SIGTERM'); escalation = setTimeout(() => kill('SIGKILL'), 500); };
51
- try { child = spawn(binary, args, { cwd, env, shell: false, detached: process.platform !== 'win32', stdio: ['pipe', 'pipe', 'pipe'] }); }
52
- catch { finish(null); return; }
53
- timer = setTimeout(() => stop('timeout'), timeoutMs);
54
- child.on('error', () => { reason = 'spawn-error'; finish(null); });
55
- child.stdin.on('error', () => {});
56
- for (const [stream, output] of [[child.stdout, true], [child.stderr, false]]) stream.on('data', chunk => {
57
- const part = chunk.subarray(0, Math.max(0, maxBytes - bytes)).toString(); bytes += chunk.length;
58
- if (output) stdout += part; else stderr += part;
59
- if (bytes > maxBytes) stop('output-limit');
60
- });
61
- child.on('close', finish); child.stdin.end(input);
62
- });
63
- }
64
-
65
- export function parseAgentResult(id, result) {
66
- if (result.reason || result.exitCode !== 0) return { ok: false, error: result.reason || 'Agent process failed' };
67
- let frames;
68
- try { const value = JSON.parse(result.stdout); frames = Array.isArray(value) ? value : [value]; }
69
- catch { try { frames = result.stdout.trim().split('\n').filter(Boolean).map(line => JSON.parse(line)); } catch { return { ok: false, error: 'Agent output is not valid structured data' }; } }
70
- if (!frames.length || frames.some(frame => !frame || typeof frame !== 'object')) return { ok: false, error: 'Agent returned no result' };
71
- if (frames.some(frame => frame.error || frame.is_error || ['error', 'turn.failed'].includes(frame.type) || ['FAILED', 'ERROR', 'CANCELED', 'WAITING'].includes(frame.status))) return { ok: false, error: 'Agent reported failure' };
72
- const last = frames.at(-1);
73
- let text;
74
- if (id === 'codex' && last.type === 'turn.completed') text = frames.filter(frame => frame.type === 'item.completed' && frame.item?.type === 'agent_message').map(frame => frame.item.text).join('\n');
75
- if (['claude', 'cursor', 'grok'].includes(id) && last.type === 'result' && last.subtype === 'success') text = last.result;
76
- if (id === 'agy' && last.status === 'SUCCESS') text = last.response;
77
- if (id === 'dsh' && last.type === 'final') text = last.text;
78
- if (id === 'hermes' && last.type === 'result' && last.exit_code === 0) text = last.text;
79
- if (id === 'pi' && last.type === 'agent_end') {
80
- const messages = last.messages || [];
81
- if (messages.some(message => ['error', 'aborted'].includes(message.stopReason))) return { ok: false, error: 'Pi turn failed' };
82
- text = messages.filter(message => message.role === 'assistant').flatMap(message => message.content || []).filter(part => part.type === 'text').map(part => part.text).join('\n');
83
- }
84
- // The official headless contract documents JSONL plus exit status, not MSP
85
- // notifications. Preserve the actual log rather than invent a headless schema.
86
- // Exit zero certifies a finished turn only; it never certifies the requested work.
87
- if (id === 'muse') return { ok: true, response: result.stdout.trim(), events: frames, completionEvidence: 'headless-process-exit', commandExecutionVerified: false };
88
- return typeof text === 'string' && text.trim() ? { ok: true, response: text, commandExecutionVerified: false } : { ok: false, error: 'Agent did not produce a recognized completed result' };
89
- }
90
-
91
- /** Rebuild the instruction payload from the selected node/workspace, never a cached prompt. */
92
- export async function totalRecallBootstrap(request, { probe = runProcess, env = process.env } = {}) {
93
- const binary = findBinary('total-recall', env);
94
- if (!binary) throw new Error('Total Recall is not installed on the selected node');
95
- const invoke = async args => {
96
- const result = await probe(binary, args, { cwd: request.cwd, timeoutMs: 120000, maxBytes: 4 * 1024 * 1024, env: agentEnvironment(env) });
97
- if (result.reason || result.exitCode !== 0) throw new Error(`Total Recall ${args[0]} failed; dispatch refused`);
98
- return result.stdout;
99
- };
100
- const actions = request.permissions?.write ? 'read,edit,test' : 'read';
101
- await invoke(['cli-agents','setup','--json']);
102
- const capsule = JSON.parse(await invoke(['context', request.prompt.slice(0,2000), '--action', actions, '--budget', '24000', '--format', 'json']));
103
- if (capsule.ready !== true || typeof capsule.context !== 'string') throw new Error('Required Total Recall context is not ready');
104
- const help = await invoke(['--help']);
105
- const plugins = JSON.parse(await invoke(['plugin', 'library', '--json']));
106
- const commands = JSON.parse(await invoke(['composable-cli', 'library', '--json']));
107
- const docs = JSON.parse(await invoke(['cli-agents', 'docs-ensure', '--agent', request.agent, '--json']));
108
- if (docs.ok !== true) throw new Error('Official agent documentation is unavailable or stale');
109
- return `Requester: the operator of this Total Recall workspace.\nUse Total Recall and its owning plugin CLI for this task. The following context and command inventories were obtained automatically on this node before dispatch. Official documentation is cached at ${docs.directory}. Read the applicable cached references before changing an integration.\n\nTask context:\n${capsule.context}\n\nComplete CLI help:\n${help}\n\nInstalled plugin command library:\n${JSON.stringify(plugins)}\n\nComposed command library:\n${JSON.stringify(commands)}\n\nRequested task:\n${request.prompt}`;
110
- }
111
-
112
- export async function inspectAgents({ probe = runProcess, env = process.env, ids } = {}) {
113
- const agents = [];
114
- for (const adapter of ADAPTERS) {
115
- if (ids && !ids.includes(adapter.id)) continue;
116
- const binary = findBinary(adapter.binary, env);
117
- const item = { id: adapter.id, name: adapter.name, installed: Boolean(binary), authenticated: 'unknown', executionVerified: false, docs: adapter.docs };
118
- if (binary) {
119
- const version = await probe(binary, ['--version'], { timeoutMs: 8000 });
120
- item.version = version.exitCode === 0 ? (version.stdout || version.stderr).match(/\b\d+\.\d+(?:\.\d+)?\b/)?.[0] || null : null;
121
- item.versionVerified = Boolean(item.version);
122
- if (adapter.auth) {
123
- const auth = await probe(binary, adapter.auth, { timeoutMs: 15000 });
124
- if (adapter.id === 'codex') item.authenticated = auth.exitCode === 0 && /Logged in using ChatGPT/i.test(auth.stdout + auth.stderr);
125
- if (adapter.id === 'claude') {
126
- try { const value = JSON.parse(auth.stdout); item.authenticated = auth.exitCode === 0 && value.loggedIn === true && value.authMethod === 'claude.ai' && value.apiProvider === 'firstParty' && !value.apiKeySource && Boolean(value.subscriptionType); } catch { item.authenticated = false; }
127
- }
128
- if (adapter.id === 'cursor') item.authenticated = auth.exitCode === 0 && /logged in|authenticated/i.test(auth.stdout) && !/not authenticated|not logged in/i.test(auth.stdout);
129
- }
130
- }
131
- agents.push(item);
132
- }
133
- return { agents, evidence: 'Installed version/auth metadata; actual command execution requires a separate completed run' };
134
- }
135
-
136
- export async function dispatchAgent(request, { probe = runProcess, env = process.env, bootstrap = totalRecallBootstrap } = {}) {
137
- const adapter = ADAPTERS.find(item => item.id === request.agent);
138
- if (!adapter || !path.isAbsolute(request.cwd || '') || typeof request.prompt !== 'string' || !request.prompt.trim() || Buffer.byteLength(request.prompt) > 65536) throw new Error('Explicit supported agent, absolute workspace and bounded prompt required');
139
- if (!fs.statSync(request.cwd).isDirectory()) throw new Error('Selected workspace is not a directory');
140
- const binary = findBinary(adapter.binary, env);
141
- if (!binary) throw new Error(`${adapter.name} is not installed on the selected node`);
142
- const inspected = await inspectAgents({ probe, env, ids: [adapter.id] });
143
- const state = inspected.agents.find(item => item.id === adapter.id);
144
- if (!state.versionVerified || state.authenticated === false) throw new Error('Selected agent version or account is not ready');
145
- if (state.authenticated === 'unknown' && request.allowUnknownAuth !== true) throw new Error('Selected account authentication is unknown; explicitly select this agent to verify it through execution');
146
- const prompt = await bootstrap(request, { probe, env });
147
- const args = [...adapter.args];
148
- const allowWrites = request.permissions?.write === true;
149
- if (adapter.id === 'codex') args[args.indexOf('--sandbox') + 1] = allowWrites ? 'workspace-write' : 'read-only';
150
- if (adapter.id === 'claude') args[args.indexOf('--permission-mode') + 1] = allowWrites ? 'acceptEdits' : 'plan';
151
- if (adapter.id === 'agy') args[args.indexOf('--mode') + 1] = allowWrites ? 'accept-edits' : 'plan';
152
- if (adapter.id === 'muse' && !allowWrites) args.push('--disable-write');
153
- let input = adapter.input === 'stdin' ? prompt : '', temporary;
154
- if (adapter.input === 'argument' || adapter.input === 'file') {
155
- temporary = fs.mkdtempSync(path.join(os.tmpdir(), 'cli-agent-prompt-'));
156
- const file = path.join(temporary, 'prompt.txt'); fs.writeFileSync(file, prompt, { mode: 0o600 });
157
- if (adapter.input === 'file') args.push('--prompt-file', file);
158
- else args.push(`Read ${file} completely before taking action. It contains the required Total Recall task context, full CLI/plugin/composed-command inventories, official documentation location and the requested task. Carry out that task using the supplied context.`);
159
- }
160
- try { return { agent: adapter.id, ...parseAgentResult(adapter.id, await probe(binary, args, { cwd: request.cwd, input, timeoutMs: 300000 })) }; }
161
- finally { if (temporary) fs.rmSync(temporary, { recursive: true, force: true }); }
162
- }
163
-
164
- export async function runWorker(request) {
165
- if (request.operation === 'inspect') return { ...await inspectAgents(), defaultCwd: os.homedir() };
166
- if (request.operation === 'dispatch') return dispatchAgent(request);
167
- if (request.operation === 'direct') {
168
- if (!path.isAbsolute(request.cwd || '') || !Array.isArray(request.argv) || request.argv.some(arg => typeof arg !== 'string')) throw new Error('Explicit workspace and argv required');
169
- const binary = findBinary('total-recall');
170
- if (!binary) throw new Error('Total Recall CLI is not installed on the selected node');
171
- const result = await runProcess(binary, request.argv.slice(1), { cwd: request.cwd });
172
- return { ok: result.exitCode === 0 && !result.reason, output: result.stdout, error: result.reason || (result.exitCode ? 'CLI command failed' : undefined), exitCode: result.exitCode, commandExecutionVerified: result.exitCode === 0 && !result.reason };
173
- }
174
- throw new Error('Unknown CLI-agent worker operation');
175
- }
@@ -1,32 +0,0 @@
1
- # DESIGN.md — Command Fleet
2
-
3
- ```yaml
4
- tokens:
5
- brand-name: "Command Fleet"
6
- wordmark: "[FLEET//COMMAND]"
7
- color-primary: "#3b82f6"
8
- color-background: "#0c1427"
9
- color-surface: "#1e293b"
10
- color-accent: "#38bdf8"
11
- color-ok: "#10b981"
12
- color-warn: "#f59e0b"
13
- color-danger: "#ef4444"
14
- color-text: "#f1f5f9"
15
- color-muted: "#94a3b8"
16
- color-line: "#1e293b"
17
- badge: "Agent Runtime Matrix"
18
- font-mono: "'JetBrains Mono', 'Fira Code', monospace"
19
- border-radius: "8px"
20
- ```
21
-
22
- ## Brand & Typographic Wordmark
23
- - **Name**: Command Fleet
24
- - **Wordmark Logo**: `[FLEET//COMMAND]` (custom vector typographic badge, no generic emojis)
25
- - **Palette**: Primary `#3b82f6`, Surface `#0c1427`, Secondary Surface `#1e293b`, Accent `#38bdf8`, Line `#1e293b`, Text `#f1f5f9`.
26
- - **States**: Verified Pass `#10b981`, Warning `#f59e0b`, Danger `#ef4444`.
27
-
28
- ## Interface Architecture
29
- 1. **Header**: Custom vector wordmark, mesh target chip, total verified agent counter.
30
- 2. **Mesh Node Switcher**: Quick toggle buttons for mesh nodes (`Local`, `Cloud`, `MacBook`).
31
- 3. **Multi-Agent Matrix**: Grid of supported CLI agents with binary status, auth badge, and version.
32
- 4. **Structured Fleet Inspector**: Interactive inspector displaying permissions, primary model, and doc freshness.