total-recall-brain 3.41.3 → 3.41.5
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 +12 -2
- package/docs/reference/cli-reference.md +18 -0
- package/frontend/dist/assets/{index-DFenQQEQ.js → index-WT3gs-x6.js} +75 -70
- package/frontend/dist/index.html +1 -1
- package/package.json +7 -5
- package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +2 -2
- package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +48 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/login-projections.mjs +42 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/mesh-secrets.mjs +18 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/routes/secrets.mjs +5 -2
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-carriers.mjs +76 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-prune.mjs +37 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-sync.mjs +53 -17
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +3114 -36
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +3114 -36
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +3131 -28
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +6 -2
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +3132 -29
- package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +5 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +3164 -73
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +5 -3
- package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/grants.mjs +7 -3
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +61 -38
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/leader-election.mjs +57 -2
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +220 -36
- package/scaffold/.agent/skills/total-recall/plugins/mesh/src/server/routes/mesh.mjs +7 -2
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +65 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/BRICK.md +59 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +534 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +139 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +5937 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +26 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +376 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +37 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/adapters/dsh.mjs +446 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +23 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +398 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +172 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +82 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +90 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +415 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/setup.mjs +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/tracker.mjs +133 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +233 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +32 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +845 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/BRICK.md +64 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/index.mjs +250 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +619 -41
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +3134 -31
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +9 -3
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +413 -14
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +129 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +159 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +197 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/lint.mjs +153 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +261 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +502 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +114 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/token.mjs +96 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +375 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +35 -22
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +1225 -364
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/openwiki.mjs +8987 -0
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +3114 -83
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +5 -1
- package/src/cli/compact.mjs +108 -0
- package/src/cli/config.mjs +3 -0
- package/src/cli/connect.mjs +12 -116
- package/src/cli/context.mjs +52 -23
- package/src/cli/forget.mjs +2 -0
- package/src/cli/harness.mjs +0 -1
- package/src/cli/plugin/create.mjs +56 -3
- package/src/cli/plugin/index.mjs +15 -3
- package/src/cli/plugin/monetization.mjs +232 -12
- package/src/cli/preflight.mjs +161 -0
- package/src/cli/release.mjs +386 -0
- package/src/core/cli-commands.mjs +4 -0
- package/src/core/context-compactor.mjs +143 -0
- package/src/core/context-compiler.mjs +8 -1
- package/src/core/default-plugins.mjs +1 -1
- package/src/core/meta-harness.mjs +16 -38
- package/src/core/plugin-dependencies.mjs +6 -1
- package/src/core/preflight-gate.mjs +77 -0
- package/src/core/preflight-receipt.mjs +123 -0
- package/src/core/runtime.mjs +0 -3
- package/src/core/surface.mjs +39 -2
- package/src/server/invoke-durability.mjs +39 -0
- package/src/server/invoke-write-child.mjs +25 -0
- package/src/server/routes/invoke.mjs +7 -0
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
"description": "Standalone security suite for Total Recall: static analysis, file and permission hardening schemes, AES-256-GCM encryption tools, and egress audit controls",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"test": "node --test test/*.test.mjs",
|
|
8
|
-
"build:ui": "node scripts/build-ui.mjs"
|
|
8
|
+
"build:ui": "node scripts/build-ui.mjs",
|
|
9
|
+
"ssss": "ssss"
|
|
9
10
|
},
|
|
10
11
|
"license": "MIT",
|
|
11
12
|
"files": [
|
|
@@ -21,5 +22,8 @@
|
|
|
21
22
|
],
|
|
22
23
|
"publishConfig": {
|
|
23
24
|
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@gregiteen/ssss-cli": "0.14.4"
|
|
24
28
|
}
|
|
25
29
|
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { parseLayerFlag } from './agent-dir.mjs';
|
|
2
|
+
import { loadContextNodes } from './context.mjs';
|
|
3
|
+
import { curatedRules, selectRules } from '../core/context-policy.mjs';
|
|
4
|
+
import { compactRules } from '../core/context-compactor.mjs';
|
|
5
|
+
import { cosineSimilarity, getEmbedding, loadEmbeddingsIndex } from '../core/embeddings.mjs';
|
|
6
|
+
import { legacyRuleContributions } from '../core/surface.mjs';
|
|
7
|
+
|
|
8
|
+
const DEFAULT_BUDGET = 4000;
|
|
9
|
+
const EMBED_TIMEOUT_MS = 8000;
|
|
10
|
+
|
|
11
|
+
const USAGE = `Usage: total-recall compact "task" [--budget 4000] [--action edit,test] [--expand slug,slug] [--format text|json] [--project|--global]
|
|
12
|
+
Fits the applicable rules into --budget estimated tokens, ranked against the task. Rules keep their own words: full text, a leading excerpt, or a slug under Referenced. Read any of them in full with --expand. The output is partial by design; \`total-recall context\` prints the complete capsule.`;
|
|
13
|
+
|
|
14
|
+
function parseArgs(args) {
|
|
15
|
+
const options = { budget: DEFAULT_BUDGET, actions: [], expand: [], format: 'text' };
|
|
16
|
+
for (let i = 1; i < args.length; i++) {
|
|
17
|
+
const flag = args[i];
|
|
18
|
+
const value = args[++i];
|
|
19
|
+
if (flag === '--budget') options.budget = Number(value);
|
|
20
|
+
else if (flag === '--action') options.actions = value?.split(',').filter(Boolean) || [];
|
|
21
|
+
else if (flag === '--expand') options.expand = value?.split(',').filter(Boolean) || [];
|
|
22
|
+
else if (flag === '--format' && ['json', 'text'].includes(value)) options.format = value;
|
|
23
|
+
else throw new Error(`Unknown compact option: ${flag}`);
|
|
24
|
+
}
|
|
25
|
+
if (!Number.isFinite(options.budget) || options.budget < 1) throw new Error('--budget must be a positive number of tokens');
|
|
26
|
+
return options;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function loadVectors(derivedDirs) {
|
|
30
|
+
const vectors = {};
|
|
31
|
+
for (const dir of derivedDirs) {
|
|
32
|
+
try {
|
|
33
|
+
for (const [slug, entry] of Object.entries(loadEmbeddingsIndex(dir))) vectors[slug] ??= entry.embedding;
|
|
34
|
+
} catch { /* a brain without an index simply contributes no vectors */ }
|
|
35
|
+
}
|
|
36
|
+
return vectors;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function embedTask(task) {
|
|
40
|
+
let timer;
|
|
41
|
+
const timeout = new Promise(resolve => { timer = setTimeout(() => resolve(null), EMBED_TIMEOUT_MS); });
|
|
42
|
+
try {
|
|
43
|
+
return await Promise.race([getEmbedding(task), timeout]);
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
} finally {
|
|
47
|
+
clearTimeout(timer);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function lexicalScore(terms, text) {
|
|
52
|
+
if (!terms.length) return 0;
|
|
53
|
+
const haystack = text.toLowerCase();
|
|
54
|
+
return terms.filter(term => haystack.includes(term)).length / terms.length;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Rank the applicable rules against the task and fit them into `budget`. Shared by `compact` and `context`. */
|
|
58
|
+
export async function compactNodes({ task, actions = [], budget, expand = [], complete = false, nodes, skillsDir, derivedDirs, header }) {
|
|
59
|
+
const rules = selectRules(curatedRules(nodes), { actions, projectRoot: process.cwd() });
|
|
60
|
+
const vectors = loadVectors(derivedDirs);
|
|
61
|
+
const taskVector = await embedTask(task);
|
|
62
|
+
const terms = String(task).toLowerCase().match(/[\p{L}\p{N}_-]{3,}/gu) || [];
|
|
63
|
+
const semantic = Boolean(taskVector);
|
|
64
|
+
|
|
65
|
+
const score = (slug, text) => semantic && vectors[slug] ? cosineSimilarity(taskVector, vectors[slug]) : lexicalScore(terms, text);
|
|
66
|
+
const items = rules.map(node => {
|
|
67
|
+
const body = (node._directive || node.body || node.content || '').trim();
|
|
68
|
+
return {
|
|
69
|
+
slug: node.slug, body, priority: node.priority, importance: node.importance,
|
|
70
|
+
text: node._directive ? `[${node.slug}] ${node._directive}` : `## ${node.title || node.slug} [${node.slug}]\n\n${body}`,
|
|
71
|
+
vector: vectors[node.slug], score: score(node.slug, `${node.title || ''} ${body}`),
|
|
72
|
+
};
|
|
73
|
+
});
|
|
74
|
+
for (const { id, text } of legacyRuleContributions(skillsDir)) {
|
|
75
|
+
items.push({ slug: id, body: text, text, score: lexicalScore(terms, text) });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const ranking = semantic ? 'semantic' : 'lexical';
|
|
79
|
+
return { ranking, ...compactRules(items, { budget, expand, complete, header: (counts, tokens) => header(counts, tokens, ranking) }) };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export default async function compact(args = []) {
|
|
83
|
+
if (!args.length || args.includes('--help') || args.includes('-h')) {
|
|
84
|
+
console.log(USAGE);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const { layer, remainingArgs } = parseLayerFlag(args);
|
|
88
|
+
const task = remainingArgs[0];
|
|
89
|
+
const { budget, actions, expand, format } = parseArgs(remainingArgs);
|
|
90
|
+
const { nodes, skillsDir, derivedDirs } = loadContextNodes(layer);
|
|
91
|
+
const header = (counts, tokens, ranking) => [
|
|
92
|
+
`compacted:true tokens:${tokens} budget:${budget} rules:${counts.rules} full:${counts.full} summarized:${counts.summarized} referenced:${counts.referenced} duplicate:${counts.duplicate} omitted:${counts.omitted} ranking:${ranking}`,
|
|
93
|
+
'PARTIAL: read any rule in full with --expand <slug>; total-recall context prints the complete capsule.',
|
|
94
|
+
].join('\n');
|
|
95
|
+
|
|
96
|
+
let result;
|
|
97
|
+
try {
|
|
98
|
+
result = await compactNodes({ task, actions, budget, expand, nodes, skillsDir, derivedDirs, header });
|
|
99
|
+
} catch (error) {
|
|
100
|
+
console.log(error.requiredBudget ? `compacted:false reason:budget-too-small budget:${budget} required_budget:${error.requiredBudget}` : `compacted:false reason:${error.message}`);
|
|
101
|
+
process.exitCode = 2;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const { context, counts, tokens, tiers, ranking } = result;
|
|
105
|
+
console.log(format === 'json'
|
|
106
|
+
? JSON.stringify({ compacted: true, ranking, budget, tokens, counts, tiers, context })
|
|
107
|
+
: context);
|
|
108
|
+
}
|
package/src/cli/config.mjs
CHANGED
|
@@ -17,6 +17,9 @@ const KEY_MAP = {
|
|
|
17
17
|
'public_health': { file: 'security', path: 'network.public_health', type: 'boolean' },
|
|
18
18
|
'allowed_origins': { file: 'security', path: 'network.allowed_origins', type: 'array' },
|
|
19
19
|
|
|
20
|
+
// How long a `total-recall preflight ack` receipt stays fresh. Recorded in the receipt when it is written.
|
|
21
|
+
'preflight_max_age_minutes': { file: 'preflight', path: 'preflight.max_age_minutes', type: 'number' },
|
|
22
|
+
|
|
20
23
|
'daily_cap_usd': { file: 'budget', path: 'budget.daily_cap_usd', type: 'number' },
|
|
21
24
|
'weekly_cap_usd': { file: 'budget', path: 'budget.weekly_cap_usd', type: 'number' },
|
|
22
25
|
'budget_enabled': { file: 'budget', path: 'budget.enabled', type: 'boolean' },
|
package/src/cli/connect.mjs
CHANGED
|
@@ -151,17 +151,7 @@ export const CLIENTS = {
|
|
|
151
151
|
label: 'Antigravity',
|
|
152
152
|
mode: 'symlink',
|
|
153
153
|
target: '.agents/rules/AGENTS.md',
|
|
154
|
-
// Antigravity reads workspace skills from .agents/skills and exposes
|
|
155
|
-
// native /name invocation; Gemini TOML commands are a separate surface.
|
|
156
|
-
skillsProjection: { scope: 'project', dir: path.join('.agents', 'skills') }
|
|
157
|
-
},
|
|
158
|
-
gemini: {
|
|
159
|
-
label: 'Gemini',
|
|
160
|
-
mode: 'symlink',
|
|
161
|
-
target: '.agents/rules/GEMINI.md',
|
|
162
|
-
writeSlashCommands: true,
|
|
163
|
-
// Gemini CLI activates workspace skills from .agents/skills via /skills;
|
|
164
|
-
// explicit /name commands require separate .gemini/commands/*.toml files.
|
|
154
|
+
// Antigravity reads workspace skills from .agents/skills and exposes native /name invocation
|
|
165
155
|
skillsProjection: { scope: 'project', dir: path.join('.agents', 'skills') }
|
|
166
156
|
},
|
|
167
157
|
aider: {
|
|
@@ -233,7 +223,6 @@ function printHelp() {
|
|
|
233
223
|
claude-code
|
|
234
224
|
codex
|
|
235
225
|
antigravity
|
|
236
|
-
gemini
|
|
237
226
|
grok
|
|
238
227
|
replit
|
|
239
228
|
lovable
|
|
@@ -643,94 +632,6 @@ $ARGUMENTS`
|
|
|
643
632
|
return written;
|
|
644
633
|
}
|
|
645
634
|
|
|
646
|
-
function writeGeminiSlashCommands(opts) {
|
|
647
|
-
const globalDir = path.join(os.homedir(), '.gemini', 'commands');
|
|
648
|
-
const localDir = path.join(process.cwd(), '.gemini', 'commands');
|
|
649
|
-
|
|
650
|
-
fs.mkdirSync(globalDir, { recursive: true });
|
|
651
|
-
fs.mkdirSync(localDir, { recursive: true });
|
|
652
|
-
|
|
653
|
-
const base = (opts.brain || 'http://127.0.0.1:3000').replace(/\/$/, '');
|
|
654
|
-
const token = '<YOUR_PAT_TOKEN>';
|
|
655
|
-
|
|
656
|
-
const commands = {
|
|
657
|
-
'memory.toml': {
|
|
658
|
-
description: 'Search or manage Total Recall memory',
|
|
659
|
-
prompt: `You are Antigravity, an AI assistant with the Total Recall SSSS v2 memory vault.
|
|
660
|
-
Search the semantic memory vault or fetch nodes using the following query:
|
|
661
|
-
{{args}}
|
|
662
|
-
|
|
663
|
-
Instructions:
|
|
664
|
-
Perform a POST request to \`${base}/api/memory/search/semantic\` with the body \`{"query": "{{args}}", "top_k": 5}\` and Authorization: Bearer ${token}.`
|
|
665
|
-
},
|
|
666
|
-
'brain.toml': {
|
|
667
|
-
description: 'Show Total Recall brain status and health',
|
|
668
|
-
prompt: `Show the health, loaded model status, and statistics of the local Total Recall Total Recall System brain.
|
|
669
|
-
|
|
670
|
-
Instructions:
|
|
671
|
-
Query the health of the local brain by sending a GET request to \`${base}/health\` with Authorization: Bearer ${token}.`
|
|
672
|
-
},
|
|
673
|
-
'vault.toml': {
|
|
674
|
-
description: 'Compile or inspect the Total Recall SSSS memory vault',
|
|
675
|
-
prompt: `Compile, rebuild, or inspect the Structured Semantic Syntax System (SSSS) memory vault.
|
|
676
|
-
|
|
677
|
-
Instructions:
|
|
678
|
-
1. If the argument is "compile", send a POST request to \`${base}/api/vault/compile\` with Authorization: Bearer ${token} or run \`npx total-recall compile\`.
|
|
679
|
-
2. If the argument is "nodes", send a GET request to \`${base}/api/memory\` with Authorization: Bearer ${token}.
|
|
680
|
-
3. Summarize the changes and verify rule propagation across the workspace.`
|
|
681
|
-
},
|
|
682
|
-
'ssss.toml': {
|
|
683
|
-
description: 'Explore SSSS cognitive graph, backlinks, and network statistics',
|
|
684
|
-
prompt: `You are Antigravity, an AI assistant with the Total Recall SSSS v2 memory vault.
|
|
685
|
-
Explore the SSSS cognitive graph, backlinks, and network topology using the query:
|
|
686
|
-
{{args}}
|
|
687
|
-
|
|
688
|
-
Instructions:
|
|
689
|
-
1. Parse the arguments.
|
|
690
|
-
2. If "stats", run \`npx total-recall map --relations\` to retrieve and summarize cognitive graph metrics, Highly Connected Hubs, and unlinked Orphans.
|
|
691
|
-
3. If "map <slug>", print the inbound backlinks and outbound relations for the specified memory node slug using \`npx total-recall map --relations\`.
|
|
692
|
-
4. If "compile", send a POST request to \`${base}/api/vault/compile\` with Authorization: Bearer ${token} or run \`npx total-recall compile\`.
|
|
693
|
-
5. If "help", explain the SSSS v2 specification, categories (invariants, preferences, anti-patterns, patterns, decisions, concepts, facts, lore) and the bidirectional backlink structure.`
|
|
694
|
-
},
|
|
695
|
-
'recall.toml': {
|
|
696
|
-
description: 'Ask Total Recall brain a question or run a specialized agent task',
|
|
697
|
-
prompt: `Send a direct conversational query or task instruction to the Total Recall local brain.
|
|
698
|
-
Query: {{args}}
|
|
699
|
-
|
|
700
|
-
Instructions:
|
|
701
|
-
1. Query the memory vault for relevant context by sending a POST request to \`${base}/api/memory/search/semantic\` with the body \`{"query": "{{args}}", "top_k": 5}\` and Authorization: Bearer ${token}.
|
|
702
|
-
2. Address the user's inquiry thoroughly, referencing active memory nodes where applicable.`
|
|
703
|
-
}
|
|
704
|
-
};
|
|
705
|
-
|
|
706
|
-
const written = [];
|
|
707
|
-
for (const [filename, cmd] of Object.entries(commands)) {
|
|
708
|
-
const tomlContent = `description = "${cmd.description}"\nprompt = """\n${cmd.prompt}\n"""\n`;
|
|
709
|
-
|
|
710
|
-
// Write global command
|
|
711
|
-
const globalPath = path.join(globalDir, filename);
|
|
712
|
-
const globalExisted = fs.existsSync(globalPath);
|
|
713
|
-
if (!globalExisted || opts.force) {
|
|
714
|
-
fs.writeFileSync(globalPath, tomlContent, 'utf8');
|
|
715
|
-
written.push({ file: `global/${filename}`, action: globalExisted ? 'updated' : 'created' });
|
|
716
|
-
} else {
|
|
717
|
-
written.push({ file: `global/${filename}`, action: 'exists' });
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
// Write local command
|
|
721
|
-
const localPath = path.join(localDir, filename);
|
|
722
|
-
const localExisted = fs.existsSync(localPath);
|
|
723
|
-
if (!localExisted || opts.force) {
|
|
724
|
-
fs.writeFileSync(localPath, tomlContent, 'utf8');
|
|
725
|
-
written.push({ file: `local/${filename}`, action: localExisted ? 'updated' : 'created' });
|
|
726
|
-
} else {
|
|
727
|
-
written.push({ file: `local/${filename}`, action: 'exists' });
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
return written;
|
|
732
|
-
}
|
|
733
|
-
|
|
734
635
|
|
|
735
636
|
export default async function connect(args) {
|
|
736
637
|
const opts = parseArgs(args);
|
|
@@ -739,6 +640,11 @@ export default async function connect(args) {
|
|
|
739
640
|
return;
|
|
740
641
|
}
|
|
741
642
|
|
|
643
|
+
if (opts.client === 'gemini') {
|
|
644
|
+
console.error("Gemini CLI was deprecated by Google; Antigravity (agy) is the official Google agent harness. Run 'total-recall connect antigravity' instead.");
|
|
645
|
+
process.exit(1);
|
|
646
|
+
}
|
|
647
|
+
|
|
742
648
|
const preset = CLIENTS[opts.client];
|
|
743
649
|
if (!preset) {
|
|
744
650
|
console.error(`Unknown client: ${opts.client}`);
|
|
@@ -967,22 +873,12 @@ export default async function connect(args) {
|
|
|
967
873
|
|
|
968
874
|
// Write slash commands
|
|
969
875
|
if (preset.writeSlashCommands) {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
created.map(r => ` ${r.file} (${r.action})`).join('\n'));
|
|
977
|
-
}
|
|
978
|
-
} else {
|
|
979
|
-
const slashResults = writeClaudeCodeSlashCommands(opts);
|
|
980
|
-
result.slash_commands = slashResults;
|
|
981
|
-
const created = slashResults.filter(r => r.action !== 'exists');
|
|
982
|
-
if (created.length > 0) {
|
|
983
|
-
result.notes.push(` Slash commands written to ~/.claude/commands/:\n` +
|
|
984
|
-
created.map(r => ` /${r.file.replace('.md', '')} (${r.action})`).join('\n'));
|
|
985
|
-
}
|
|
876
|
+
const slashResults = writeClaudeCodeSlashCommands(opts);
|
|
877
|
+
result.slash_commands = slashResults;
|
|
878
|
+
const created = slashResults.filter(r => r.action !== 'exists');
|
|
879
|
+
if (created.length > 0) {
|
|
880
|
+
result.notes.push(` Slash commands written to ~/.claude/commands/:\n` +
|
|
881
|
+
created.map(r => ` /${r.file.replace('.md', '')} (${r.action})`).join('\n'));
|
|
986
882
|
}
|
|
987
883
|
}
|
|
988
884
|
|
package/src/cli/context.mjs
CHANGED
|
@@ -2,15 +2,61 @@ import path from 'node:path';
|
|
|
2
2
|
import { getBothBrains, parseLayerFlag } from './agent-dir.mjs';
|
|
3
3
|
import { getNodes } from '../core/vault-cache.mjs';
|
|
4
4
|
import { mergeGlobalRuleNodes, legacyRuleContributions } from '../core/surface.mjs';
|
|
5
|
-
import { compileContext, capsuleResponse, renderCapsule } from '../core/context-compiler.mjs';
|
|
5
|
+
import { compileContext, capsuleResponse, renderCapsule, PREFLIGHT_NOTICE } from '../core/context-compiler.mjs';
|
|
6
6
|
import { isBrainEnabled } from '../core/brain-registry.mjs';
|
|
7
7
|
import { surfaceInputsHash } from '../core/command-surface.mjs';
|
|
8
8
|
import { readConfigValue } from './config.mjs';
|
|
9
9
|
import { recordCapsule } from '../core/context-telemetry.mjs';
|
|
10
10
|
|
|
11
|
+
/** About 28 KB: harnesses save output over about 30 KB to a file instead of showing it, which agents then cannot read (audit C-005, F-019). */
|
|
12
|
+
export const CAPSULE_LIMIT = 7000;
|
|
13
|
+
const JSON_ESCAPE_SHARE = 0.97;
|
|
14
|
+
const JSON_WRAPPER_TOKENS = 128;
|
|
15
|
+
|
|
16
|
+
/** The merged rule nodes a capsule draws from, for the selected layer. */
|
|
17
|
+
export function loadContextNodes(layer) {
|
|
18
|
+
const brains = getBothBrains();
|
|
19
|
+
const own = layer !== 'global' && brains.project && isBrainEnabled(brains.project.brainDir) ? brains.project.brainDir : null;
|
|
20
|
+
const global = layer !== 'project' && brains.global && isBrainEnabled(brains.global.brainDir) ? brains.global.brainDir : null;
|
|
21
|
+
if (!own && !global) throw new Error('No enabled brain in selected scope');
|
|
22
|
+
const nodes = own ? mergeGlobalRuleNodes(getNodes(path.join(own, 'memory-vault')), global ? getNodes(path.join(global, 'memory-vault')) : []) :
|
|
23
|
+
getNodes(path.join(global, 'memory-vault')).map(n => ({ ...n, _layer: 'global' }));
|
|
24
|
+
return { nodes, skillsDir: path.dirname(own || global),
|
|
25
|
+
derivedDirs: [own, global].filter(Boolean).map(dir => path.join(dir, 'memory-derived')) };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Compact the over-budget capsule, or explain the budget it needs. `fullRequired` is what the uncompacted capsule would take. */
|
|
29
|
+
async function printCompacted({ query, actions, budget, format, version, fullRequired, nodes, skillsDir, derivedDirs }) {
|
|
30
|
+
const { compactNodes } = await import('./compact.mjs');
|
|
31
|
+
// JSON escaping and its wrapper count against the budget too.
|
|
32
|
+
const target = format === 'json' ? Math.floor(budget * JSON_ESCAPE_SHARE) - JSON_WRAPPER_TOKENS : budget;
|
|
33
|
+
const header = (counts, tokens, ranking) => [
|
|
34
|
+
`ready:true compacted:true tokens:${tokens} budget:${budget} version:${version} rules:${counts.rules} full:${counts.full} summarized:${counts.summarized} referenced:${counts.referenced} duplicate:${counts.duplicate} ranking:${ranking}`,
|
|
35
|
+
PREFLIGHT_NOTICE,
|
|
36
|
+
`COMPACTED: every rule below still applies. Read a referenced rule with: total-recall compact "<task>" --expand <slug>`,
|
|
37
|
+
].join('\n');
|
|
38
|
+
let result;
|
|
39
|
+
try {
|
|
40
|
+
result = await compactNodes({ task: query, actions, budget: Math.max(target, 1), complete: true, nodes, skillsDir, derivedDirs, header });
|
|
41
|
+
} catch (error) {
|
|
42
|
+
if (!error.requiredBudget) throw error;
|
|
43
|
+
const floor = format === 'json' ? Math.ceil((error.requiredBudget + JSON_WRAPPER_TOKENS) / JSON_ESCAPE_SHARE) : error.requiredBudget;
|
|
44
|
+
const requiredBudget = Math.min(fullRequired, floor);
|
|
45
|
+
console.log(format === 'json'
|
|
46
|
+
? JSON.stringify({ ready: false, reason: 'budget-overflow', context: '', stats: { version, budget, required_budget: requiredBudget, token_measurement: 'estimated_chars_divided_by_four' } })
|
|
47
|
+
: `ready:false reason:budget-overflow budget:${budget} required_budget:${requiredBudget} version:${version}\nThis budget cannot hold every rule even compacted. Retry with --budget ${requiredBudget}; do not act until ready:true.`);
|
|
48
|
+
process.exitCode = 2;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
console.log(format === 'json'
|
|
52
|
+
? JSON.stringify({ ready: true, compacted: true, ranking: result.ranking, context: result.context, counts: result.counts,
|
|
53
|
+
stats: { version, budget, total_tokens: result.tokens, token_measurement: 'estimated_chars_divided_by_four' } })
|
|
54
|
+
: result.context);
|
|
55
|
+
}
|
|
56
|
+
|
|
11
57
|
export default async function context(args = []) {
|
|
12
58
|
if (!args.length || args.includes('--help')) {
|
|
13
|
-
console.log(
|
|
59
|
+
console.log(`Usage: total-recall context "task" [--action edit,test,publish] [--budget ${CAPSULE_LIMIT}] [--format text|json] [--knowledge] [--debug] [--project|--global]\nLocal rules only by default. Unknown applicability is required. Over budget, the capsule compacts automatically: absolute rules keep at least a summary and every other rule keeps at least its slug. Configured budgets are capped at ${CAPSULE_LIMIT}; pass a larger --budget to print the full capsule. Exit 2 means the budget cannot hold every rule; do not act until ready:true. --knowledge adds supporting documents; --debug exposes inventories within the same budget. Refresh on task/action/project or policy changes.`);
|
|
14
60
|
return;
|
|
15
61
|
}
|
|
16
62
|
const { layer, remainingArgs } = parseLayerFlag(args);
|
|
@@ -24,7 +70,7 @@ export default async function context(args = []) {
|
|
|
24
70
|
}
|
|
25
71
|
return undefined;
|
|
26
72
|
})();
|
|
27
|
-
let actions = [], budget = configuredBudget ??
|
|
73
|
+
let actions = [], budget = Math.min(configuredBudget ?? CAPSULE_LIMIT, CAPSULE_LIMIT), format = 'text', includeKnowledge = false, debug = false;
|
|
28
74
|
for (let i = 1; i < remainingArgs.length; i++) {
|
|
29
75
|
const flag = remainingArgs[i];
|
|
30
76
|
if (flag === '--knowledge') { includeKnowledge = true; continue; }
|
|
@@ -35,14 +81,8 @@ export default async function context(args = []) {
|
|
|
35
81
|
else if (flag === '--format' && ['json', 'text'].includes(value)) format = value;
|
|
36
82
|
else throw new Error(`Unknown context option: ${flag}`);
|
|
37
83
|
}
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const global = layer !== 'project' && brains.global && isBrainEnabled(brains.global.brainDir) ? brains.global.brainDir : null;
|
|
41
|
-
if (!own && !global) throw new Error('No enabled brain in selected scope');
|
|
42
|
-
const nodes = own ? mergeGlobalRuleNodes(getNodes(path.join(own, 'memory-vault')), global ? getNodes(path.join(global, 'memory-vault')) : []) :
|
|
43
|
-
getNodes(path.join(global, 'memory-vault')).map(n => ({ ...n, _layer: 'global' }));
|
|
44
|
-
const skillsDir = path.dirname(own || global);
|
|
45
|
-
const derivedDir = own ? path.join(own, 'memory-derived') : (global ? path.join(global, 'memory-derived') : null);
|
|
84
|
+
const { nodes, skillsDir, derivedDirs } = loadContextNodes(layer);
|
|
85
|
+
const derivedDir = derivedDirs[0];
|
|
46
86
|
const result = await compileContext({ query, actions, nodes, includeKnowledge, budget: { total: budget }, projectRoot: process.cwd(),
|
|
47
87
|
derivedDir, contributions: legacyRuleContributions(skillsDir), versionInputs: surfaceInputsHash({ skillsDir }) });
|
|
48
88
|
if (debug && format === 'text') throw new Error('--debug requires --format json');
|
|
@@ -55,18 +95,7 @@ export default async function context(args = []) {
|
|
|
55
95
|
derivedDir, action: actions, query, consumer: 'cli',
|
|
56
96
|
});
|
|
57
97
|
if (!response.ready && !debug) {
|
|
58
|
-
|
|
59
|
-
// same rules again. Keep the full set in the compiler/API, and admit it only
|
|
60
|
-
// after the caller explicitly raises the budget or curates applicability.
|
|
61
|
-
const requiredBudget = response.stats.total_tokens + 32;
|
|
62
|
-
const diagnostic = { ready: false, reason: 'budget-overflow', context: '', stats: {
|
|
63
|
-
version: response.stats.version, required_count: response.stats.required_count,
|
|
64
|
-
budget, required_budget: requiredBudget,
|
|
65
|
-
token_measurement: 'estimated_chars_divided_by_four',
|
|
66
|
-
} };
|
|
67
|
-
console.log(format === 'json' ? JSON.stringify(diagnostic) :
|
|
68
|
-
`ready:false reason:budget-overflow budget:${budget} required_budget:${requiredBudget} required_rules:${response.stats.required_count} version:${response.stats.version}\nRetry with --budget ${requiredBudget}; do not act until ready:true.\nTo shorten the rules for good: total-recall rules audit, then rules draft/apply.`);
|
|
69
|
-
process.exitCode = 2;
|
|
98
|
+
await printCompacted({ query, actions, budget, format, version: response.stats.version, fullRequired: response.stats.total_tokens + 32, nodes, skillsDir, derivedDirs });
|
|
70
99
|
return;
|
|
71
100
|
}
|
|
72
101
|
console.log(renderCapsule(response, format));
|
package/src/cli/forget.mjs
CHANGED
|
@@ -33,6 +33,8 @@ function printHelp() {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export default async function forget(args) {
|
|
36
|
+
// Checked first: a destructive command must never act on a request for help.
|
|
37
|
+
if (args.includes('--help') || args.includes('-h')) { printHelp(); return; }
|
|
36
38
|
const { layer: explicitLayer, remainingArgs } = parseLayerFlag(args);
|
|
37
39
|
|
|
38
40
|
// Check for --project-all
|
package/src/cli/harness.mjs
CHANGED
|
@@ -21,7 +21,6 @@ Available Harness IDs:
|
|
|
21
21
|
claude Claude Code CLI (Deep codebase refactoring & Unix execution)
|
|
22
22
|
codex OpenAI Codex CLI (Program synthesis & sandbox execution)
|
|
23
23
|
grok xAI Grok Build CLI (Autonomous coding, inspection, shell execution)
|
|
24
|
-
gemini Google Gemini CLI (Fast utilities & completion chaining)
|
|
25
24
|
ollama Ollama Local LLM (Local neural reasoning, zero API cost)
|
|
26
25
|
hermes Hermes Agent Runtime (Autonomous supervisor & messaging gateway)
|
|
27
26
|
dsh DeepSeek Harness DSH (High-throughput reasoning engine)
|
|
@@ -289,6 +289,17 @@ export async function createPlugin(args = []) {
|
|
|
289
289
|
{ name: "status", description: `Show which ${pluginName} subcommands are implemented`, effect: "read", output: "json" }
|
|
290
290
|
]
|
|
291
291
|
};
|
|
292
|
+
if (apiKeys.length) {
|
|
293
|
+
manifest.cli.subcommands.push({
|
|
294
|
+
name: "token",
|
|
295
|
+
description: `Manage ${pluginName} API credentials in the secrets store`,
|
|
296
|
+
effect: "write",
|
|
297
|
+
args: [
|
|
298
|
+
{ name: "action", positional: true, type: "choice", options: ["status", "set"], label: "Action" },
|
|
299
|
+
{ name: "value", secret: true, type: "string", label: "Secret value passed over stdin" }
|
|
300
|
+
]
|
|
301
|
+
});
|
|
302
|
+
}
|
|
292
303
|
// The card contract reads the plugin's real state through a declared read
|
|
293
304
|
// command; a scaffold without this shows no live status.
|
|
294
305
|
manifest.status = { command: "status", refresh_seconds: 60 };
|
|
@@ -433,6 +444,10 @@ export default generateContext;
|
|
|
433
444
|
fs.writeFileSync(path.join(pluginDir, "generator.mjs"), generatorContent, "utf8");
|
|
434
445
|
}
|
|
435
446
|
|
|
447
|
+
manifest.capability = {
|
|
448
|
+
entry: "capability/index.mjs",
|
|
449
|
+
exports: ["getCapabilityStatus"]
|
|
450
|
+
};
|
|
436
451
|
|
|
437
452
|
const validation = validatePluginManifest(manifest);
|
|
438
453
|
if (!validation.valid) {
|
|
@@ -490,13 +505,51 @@ export default generateContext;
|
|
|
490
505
|
private: true,
|
|
491
506
|
type: 'module',
|
|
492
507
|
description: pluginDesc,
|
|
493
|
-
scripts: {
|
|
494
|
-
|
|
508
|
+
scripts: {
|
|
509
|
+
test: 'node --test test/*.test.mjs',
|
|
510
|
+
ssss: 'ssss',
|
|
511
|
+
export: 'ssss export vault --profile sale --out dist/bundle.ucw.json',
|
|
512
|
+
validate: 'ssss conformance --engine'
|
|
513
|
+
},
|
|
514
|
+
dependencies: {
|
|
515
|
+
'@gregiteen/ssss-cli': '0.14.3'
|
|
516
|
+
},
|
|
517
|
+
devDependencies: {
|
|
518
|
+
'total-recall-brain': '3.41.3'
|
|
519
|
+
},
|
|
495
520
|
license: 'MIT'
|
|
496
521
|
}, null, 2) + '\n', 'utf8');
|
|
497
|
-
fs.writeFileSync(path.join(pluginDir, '.gitignore'), 'node_modules/\n.env*\n.agent/skills/total-recall/\ndist/\nreports/\n.DS_Store\nINSTRUCTIONS.md\nAGENTS.md\
|
|
522
|
+
fs.writeFileSync(path.join(pluginDir, '.gitignore'), 'node_modules/\n.env*\n.agent/skills/total-recall/\ndist/\nreports/\n.DS_Store\nINSTRUCTIONS.md\nAGENTS.md\n', 'utf8');
|
|
498
523
|
fs.writeFileSync(path.join(pluginDir, 'LICENSE'), mitLicense(holder), 'utf8');
|
|
524
|
+
|
|
525
|
+
// Capability brick
|
|
526
|
+
fs.mkdirSync(path.join(pluginDir, 'capability'), { recursive: true });
|
|
527
|
+
fs.writeFileSync(path.join(pluginDir, 'capability', 'index.mjs'), `/**
|
|
528
|
+
* Portable capability brick for ${pluginName}.
|
|
529
|
+
* Zero host dependencies; pure portable JavaScript.
|
|
530
|
+
*/
|
|
531
|
+
export async function getCapabilityStatus() {
|
|
532
|
+
return { ready: true, initialized: true };
|
|
533
|
+
}
|
|
534
|
+
`, 'utf8');
|
|
535
|
+
fs.writeFileSync(path.join(pluginDir, 'capability', 'BRICK.md'), `# ${pluginName} — Capability Brick
|
|
536
|
+
|
|
537
|
+
Portable core capability for ${pluginName}.
|
|
538
|
+
|
|
539
|
+
## Exported Functions
|
|
540
|
+
- \`getCapabilityStatus()\`: Returns capability readiness and initialization status.
|
|
541
|
+
`, 'utf8');
|
|
542
|
+
|
|
499
543
|
fs.mkdirSync(path.join(pluginDir, 'test'), { recursive: true });
|
|
544
|
+
fs.writeFileSync(path.join(pluginDir, 'test', 'capability.test.mjs'), `import test from 'node:test';
|
|
545
|
+
import assert from 'node:assert/strict';
|
|
546
|
+
import { getCapabilityStatus } from '../capability/index.mjs';
|
|
547
|
+
|
|
548
|
+
test('capability brick loads and exports status', async () => {
|
|
549
|
+
const status = await getCapabilityStatus();
|
|
550
|
+
assert.equal(status.ready, true);
|
|
551
|
+
});
|
|
552
|
+
`, 'utf8');
|
|
500
553
|
fs.writeFileSync(path.join(pluginDir, 'test', 'manifest.test.mjs'), `import test from 'node:test';
|
|
501
554
|
import assert from 'node:assert/strict';
|
|
502
555
|
import fs from 'node:fs';
|
package/src/cli/plugin/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { listAvailable, listPeers, searchPlugins } from './search.mjs';
|
|
|
5
5
|
import { createPlugin } from './create.mjs';
|
|
6
6
|
import { vendorPlugin, listProjectBricks } from './vendor.mjs';
|
|
7
7
|
import { manageProjectPluginCopies } from './copies.mjs';
|
|
8
|
-
import { managePluginLicense } from './monetization.mjs';
|
|
8
|
+
import { managePluginLicense, monetizePlugin, publishPluginToStore } from './monetization.mjs';
|
|
9
9
|
import { getPlugin, getPluginMonetization, globalPluginsDir, projectPluginsDir } from '../../core/plugin-loader.mjs';
|
|
10
10
|
import { describePlugin, pruneReplacementArchives, replacementArchiveDir } from '../../core/plugin-store.mjs';
|
|
11
11
|
import { buildPluginCatalog } from '../../core/plugin-catalog.mjs';
|
|
@@ -55,8 +55,10 @@ Commands:
|
|
|
55
55
|
in 'update --automatic')
|
|
56
56
|
share <id> Offer an installed plugin by direct link and mesh
|
|
57
57
|
unshare <id> Stop offering it
|
|
58
|
+
publish <id> Publish plugin to the Store and lock release (--no-lock)
|
|
59
|
+
monetize <id> Configure plugin pricing, period, and payout recipient
|
|
58
60
|
remove <id> Uninstall (--global for the machine-wide copy)
|
|
59
|
-
license <id> [cmd] Check or activate plugin license (status, activate, verify)
|
|
61
|
+
license <id> [cmd] Check or activate plugin license (status, activate, checkout, verify)
|
|
60
62
|
info <id> Manifest, provenance, hash and task history
|
|
61
63
|
vendor <source> [dir] Add a plugin to this project as a brick (default bricks/<id>); the
|
|
62
64
|
project then owns the code. <source>: bundled id, git URL or path.
|
|
@@ -244,7 +246,17 @@ export async function run(argv = []) {
|
|
|
244
246
|
return;
|
|
245
247
|
}
|
|
246
248
|
|
|
247
|
-
if (command === '
|
|
249
|
+
if (command === 'publish' || command === 'deploy-store') {
|
|
250
|
+
await publishPluginToStore(rest);
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (command === 'monetize') {
|
|
255
|
+
await monetizePlugin(rest);
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (command === 'license' || command === 'lic') {
|
|
248
260
|
await managePluginLicense(rest);
|
|
249
261
|
return;
|
|
250
262
|
}
|