total-recall-brain 3.8.1 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -5
- package/scaffold/.agent/skills/total-recall/SKILL.md +1 -0
- package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/SKILL.md +3 -2
- package/scaffold/.agent/skills/total-recall/skills/{research → tr-research}/SKILL.md +2 -1
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/SKILL.md +3 -2
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/evals/evals.json +3 -3
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/hooks/on-skill-add.sh +1 -1
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/hooks/on-skill-delete.sh +1 -1
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/create-skill.sh +3 -3
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/find-skills.mjs +25 -1
- package/scaffold/.agent/skills/total-recall/skills/tr-skill/scripts/install-skill.mjs +117 -0
- package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/scan-skill.mjs +20 -0
- package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/SKILL.md +58 -15
- package/src/cli/connect.mjs +47 -5
- package/src/cli/init.mjs +42 -2
- package/src/cli/skill-projection.mjs +214 -0
- package/src/cli/skill.mjs +44 -18
- package/src/core/daemon-loop.mjs +13 -2
- package/src/core/operation-validator.mjs +19 -1
- package/src/core/research.mjs +47 -9
- package/src/core/runtime.mjs +14 -7
- package/src/core/schema.mjs +23 -1
- package/src/server/api.mjs +2 -2
- package/src/server/rest.mjs +3 -3
- package/src/server/routes/skills.mjs +25 -4
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/agents.yml +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/evals/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/antigravity.txt +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/claude.txt +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/codex.txt +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/references/gemini.txt +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/scripts/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{cli-agents → tr-cli-agents}/subagents/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/assets/skill-template/SKILL.md +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/learnings/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/references/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/.gitkeep +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/enforce-skill-optimization.mjs +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/skill-watcher.mjs +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/subagents/audit-all-skills.md +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/evals/evals.json +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/references/CHANGELOG.md +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/references/ssss-spec.md +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/scripts/validate-schema.mjs +0 -0
- /package/scaffold/.agent/skills/total-recall/skills/{ssss → tr-ssss}/subagents/audit-ssss-node.md +0 -0
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "total-recall-brain",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.10.0",
|
|
4
4
|
"description": "Sovereign AI system — database-free, SSSS-powered personal intelligence engine deployable to any POSIX host.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"total-recall": "
|
|
8
|
-
"antigravity": "
|
|
7
|
+
"total-recall": "bin/total-recall.mjs",
|
|
8
|
+
"antigravity": "bin/antigravity.mjs"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"bin/",
|
|
@@ -56,6 +56,7 @@
|
|
|
56
56
|
},
|
|
57
57
|
"homepage": "https://github.com/gregiteen/total-recall#readme",
|
|
58
58
|
"dependencies": {
|
|
59
|
+
"@ssss/cli": "github:gregiteen/ssss#v0.4.0",
|
|
59
60
|
"bcrypt": "^6.0.0",
|
|
60
61
|
"cookie-parser": "^1.4.7",
|
|
61
62
|
"cors": "^2.8.6",
|
|
@@ -64,9 +65,9 @@
|
|
|
64
65
|
"gray-matter": "^4.0.3",
|
|
65
66
|
"jsonwebtoken": "^9.0.3",
|
|
66
67
|
"natural": "^8.1.1",
|
|
68
|
+
"ws": "^8.18.0",
|
|
67
69
|
"yaml": "^2.9.0",
|
|
68
|
-
"zod": "^4.4.3"
|
|
69
|
-
"ws": "^8.18.0"
|
|
70
|
+
"zod": "^4.4.3"
|
|
70
71
|
},
|
|
71
72
|
"devDependencies": {
|
|
72
73
|
"skills": "^1.5.7",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: total-recall
|
|
3
|
+
provenance: total-recall
|
|
3
4
|
description: "Use this skill as the master guide to understand the entire Total Recall Sovereign AI OS setup, VFS topologies, SSSS protocol, CLI parameter reference, troubleshooting, and automated upstream repository sync. MANDATORY: Read this file before attempting major setup modifications or diagnoses."
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: cli-agents
|
|
2
|
+
name: tr-cli-agents
|
|
3
|
+
provenance: total-recall
|
|
3
4
|
description: "Orchestrate headlessly spawned CLI agents from the central registry."
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -12,7 +13,7 @@ This system skill governs the discovery, configuration, and execution of headles
|
|
|
12
13
|
## 🎯 SYSTEM OVERVIEW
|
|
13
14
|
|
|
14
15
|
The CLI Agent Dispatch Engine parses agent profiles from the central registry file:
|
|
15
|
-
`.agent/skills/total-recall/skills/cli-agents/agents.yml`
|
|
16
|
+
`.agent/skills/total-recall/skills/tr-cli-agents/agents.yml`
|
|
16
17
|
|
|
17
18
|
```mermaid
|
|
18
19
|
flowchart TD
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: skill
|
|
2
|
+
name: tr-skill
|
|
3
|
+
provenance: total-recall
|
|
3
4
|
description: "Use this skill when creating, auditing, or modifying any skill in the .agent/skills/ ecosystem. MANDATORY: You MUST read the full SKILL.md file before executing."
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -186,7 +187,7 @@ Contains standalone prompt files for subtasks that can be delegated to parallel
|
|
|
186
187
|
|
|
187
188
|
### Quick method (script):
|
|
188
189
|
```bash
|
|
189
|
-
bash .agent/skills/skill/scripts/create-skill.sh my-new-skill
|
|
190
|
+
bash .agent/skills/tr-skill/scripts/create-skill.sh my-new-skill
|
|
190
191
|
```
|
|
191
192
|
|
|
192
193
|
### Manual method:
|
|
@@ -2,19 +2,19 @@
|
|
|
2
2
|
{
|
|
3
3
|
"id": "skill-eval-1",
|
|
4
4
|
"description": "SKILL.md exists",
|
|
5
|
-
"command": "test -f .agent/skills/skill/SKILL.md",
|
|
5
|
+
"command": "test -f .agent/skills/tr-skill/SKILL.md",
|
|
6
6
|
"expected_exit_code": 0
|
|
7
7
|
},
|
|
8
8
|
{
|
|
9
9
|
"id": "skill-eval-2",
|
|
10
10
|
"description": "Evals validation",
|
|
11
|
-
"command": "test -f .agent/skills/skill/scripts/run-evals.mjs",
|
|
11
|
+
"command": "test -f .agent/skills/tr-skill/scripts/run-evals.mjs",
|
|
12
12
|
"expected_exit_code": 0
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"id": "skill-eval-3",
|
|
16
16
|
"description": "Optimization enforcement",
|
|
17
|
-
"command": "test -f .agent/skills/skill/scripts/enforce-skill-optimization.mjs",
|
|
17
|
+
"command": "test -f .agent/skills/tr-skill/scripts/enforce-skill-optimization.mjs",
|
|
18
18
|
"expected_exit_code": 0
|
|
19
19
|
}
|
|
20
20
|
]
|
|
@@ -10,5 +10,5 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
10
10
|
ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
|
|
11
11
|
|
|
12
12
|
echo "🔄 OnSkillAdd hook triggered — regenerating skill index..."
|
|
13
|
-
node "$ROOT/.agent/skills/skill/scripts/update-skill-index.mjs"
|
|
13
|
+
node "$ROOT/.agent/skills/tr-skill/scripts/update-skill-index.mjs"
|
|
14
14
|
echo "✅ Routing table and INSTRUCTIONS.md updated."
|
package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/hooks/on-skill-delete.sh
RENAMED
|
@@ -10,5 +10,5 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
|
10
10
|
ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
|
|
11
11
|
|
|
12
12
|
echo "🧹 OnSkillDelete hook triggered — cleaning skill index..."
|
|
13
|
-
node "$ROOT/.agent/skills/skill/scripts/update-skill-index.mjs"
|
|
13
|
+
node "$ROOT/.agent/skills/tr-skill/scripts/update-skill-index.mjs"
|
|
14
14
|
echo "✅ Routing table and INSTRUCTIONS.md cleaned."
|
package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/create-skill.sh
RENAMED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# create-skill.sh — Scaffold a new Dev Skill from the template
|
|
3
3
|
#
|
|
4
|
-
# Usage: bash .agent/skills/skill/scripts/create-skill.sh <skill-name>
|
|
5
|
-
# Example: bash .agent/skills/skill/scripts/create-skill.sh my-new-skill
|
|
4
|
+
# Usage: bash .agent/skills/tr-skill/scripts/create-skill.sh <skill-name>
|
|
5
|
+
# Example: bash .agent/skills/tr-skill/scripts/create-skill.sh my-new-skill
|
|
6
6
|
|
|
7
7
|
set -euo pipefail
|
|
8
8
|
|
|
@@ -60,6 +60,6 @@ echo ""
|
|
|
60
60
|
echo "📝 Next steps:"
|
|
61
61
|
echo " 1. Edit $TARGET/SKILL.md with real instructions"
|
|
62
62
|
echo " 2. Write a trigger-optimized description in the frontmatter"
|
|
63
|
-
echo " 3. Run: node .agent/skills/skill/scripts/update-skill-index.mjs"
|
|
63
|
+
echo " 3. Run: node .agent/skills/tr-skill/scripts/update-skill-index.mjs"
|
|
64
64
|
echo ""
|
|
65
65
|
echo "🏁 Done."
|
package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/find-skills.mjs
RENAMED
|
@@ -77,6 +77,7 @@ export function parseFindOutput(rawOutput) {
|
|
|
77
77
|
|
|
78
78
|
const name = skillMatch[1];
|
|
79
79
|
const installs = parseInstalls(skillMatch[2], skillMatch[3] || '');
|
|
80
|
+
const installsStr = `${skillMatch[2]}${skillMatch[3] || ''}`;
|
|
80
81
|
|
|
81
82
|
// Next non-empty line should be the URL (prefixed with └ or similar box-drawing chars)
|
|
82
83
|
let url = '';
|
|
@@ -92,12 +93,19 @@ export function parseFindOutput(rawOutput) {
|
|
|
92
93
|
break; // only check the very next non-empty line
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
results.push({ name, installs, url });
|
|
96
|
+
results.push({ name, installs, installsStr, url });
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
return results;
|
|
99
100
|
}
|
|
100
101
|
|
|
102
|
+
function formatInstalls(installs) {
|
|
103
|
+
if (installs >= 1_000_000_000) return `${(installs / 1_000_000_000).toFixed(1).replace(/\.0$/, '')}B`;
|
|
104
|
+
if (installs >= 1_000_000) return `${(installs / 1_000_000).toFixed(1).replace(/\.0$/, '')}M`;
|
|
105
|
+
if (installs >= 1_000) return `${(installs / 1_000).toFixed(1).replace(/\.0$/, '')}K`;
|
|
106
|
+
return String(installs);
|
|
107
|
+
}
|
|
108
|
+
|
|
101
109
|
// ─── Live Registry Search ───────────────────────────────────────────────────
|
|
102
110
|
|
|
103
111
|
/**
|
|
@@ -122,3 +130,19 @@ export function searchRegistry(query, { timeoutMs = 15_000 } = {}) {
|
|
|
122
130
|
return [];
|
|
123
131
|
}
|
|
124
132
|
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Search skills.sh and sort by absolute install count, highest first.
|
|
136
|
+
*
|
|
137
|
+
* @param {string} query
|
|
138
|
+
* @param {object} [options]
|
|
139
|
+
* @returns {Array<{ name: string, installs: number, installsStr: string, url: string }>}
|
|
140
|
+
*/
|
|
141
|
+
export function searchAndSort(query, options = {}) {
|
|
142
|
+
return searchRegistry(query, options)
|
|
143
|
+
.map(result => ({
|
|
144
|
+
...result,
|
|
145
|
+
installsStr: result.installsStr || formatInstalls(result.installs || 0),
|
|
146
|
+
}))
|
|
147
|
+
.sort((a, b) => (b.installs || 0) - (a.installs || 0));
|
|
148
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* install-skill.mjs — safe wrapper around the Skills CLI installer.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { spawnSync } from 'node:child_process';
|
|
8
|
+
import { scanDirectory, formatReport } from './scan-skill.mjs';
|
|
9
|
+
|
|
10
|
+
const BLOCKED_SOURCE_CHARS = /[\0\r\n;&|<>`$]/;
|
|
11
|
+
|
|
12
|
+
export function validateSkillSource(source) {
|
|
13
|
+
if (typeof source !== 'string') return false;
|
|
14
|
+
const trimmed = source.trim();
|
|
15
|
+
if (!trimmed || trimmed.length > 500) return false;
|
|
16
|
+
return !BLOCKED_SOURCE_CHARS.test(trimmed);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function inferSkillName(source) {
|
|
20
|
+
const trimmed = String(source || '').trim().replace(/\/+$/, '');
|
|
21
|
+
if (!trimmed) return null;
|
|
22
|
+
if (!trimmed.startsWith('git@') && trimmed.includes('@')) {
|
|
23
|
+
return trimmed.split('@').pop() || null;
|
|
24
|
+
}
|
|
25
|
+
const last = trimmed.split('/').filter(Boolean).pop();
|
|
26
|
+
return last ? last.replace(/\.git$/i, '') : null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function uniqueExistingDirs(paths) {
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
const dirs = [];
|
|
32
|
+
for (const candidate of paths) {
|
|
33
|
+
if (!candidate) continue;
|
|
34
|
+
const resolved = path.resolve(candidate);
|
|
35
|
+
if (seen.has(resolved) || !fs.existsSync(resolved)) continue;
|
|
36
|
+
seen.add(resolved);
|
|
37
|
+
dirs.push(resolved);
|
|
38
|
+
}
|
|
39
|
+
return dirs;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function installedSkillCandidates(source, { cwd = process.cwd(), agentDir = path.join(cwd, '.agent') } = {}) {
|
|
43
|
+
const skillName = inferSkillName(source);
|
|
44
|
+
if (!skillName) return [];
|
|
45
|
+
return [
|
|
46
|
+
path.join(agentDir, 'skills', skillName),
|
|
47
|
+
path.join(cwd, '.agent', 'skills', skillName),
|
|
48
|
+
path.join(cwd, '.agents', 'skills', skillName),
|
|
49
|
+
path.join(cwd, '.claude', 'skills', skillName),
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Install a skill with the Skills CLI, then scan installed script files.
|
|
55
|
+
*
|
|
56
|
+
* @param {string} source skills add source, e.g. owner/repo@skill or URL
|
|
57
|
+
* @param {object} [options]
|
|
58
|
+
* @param {string} [options.cwd]
|
|
59
|
+
* @param {string} [options.agentDir]
|
|
60
|
+
* @param {boolean} [options.dryRun=false]
|
|
61
|
+
* @returns {{ success: boolean, source: string, command?: string[], findings?: Array, error?: string }}
|
|
62
|
+
*/
|
|
63
|
+
export function installSkill(source, options = {}) {
|
|
64
|
+
const cwd = options.cwd || process.cwd();
|
|
65
|
+
const agentDir = options.agentDir || path.join(cwd, '.agent');
|
|
66
|
+
const normalized = String(source || '').trim();
|
|
67
|
+
|
|
68
|
+
if (!validateSkillSource(normalized)) {
|
|
69
|
+
const error = 'Invalid skill source. Use a repository, URL, git source, local path, or owner/repo@skill without shell metacharacters.';
|
|
70
|
+
console.error(`❌ ${error}`);
|
|
71
|
+
return { success: false, source: normalized, error };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const command = ['npx', '-y', 'skills', 'add', normalized, '-y'];
|
|
75
|
+
if (options.dryRun) {
|
|
76
|
+
return { success: true, source: normalized, command };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log(`📦 Installing skill: ${normalized}`);
|
|
80
|
+
const child = spawnSync(command[0], command.slice(1), {
|
|
81
|
+
cwd,
|
|
82
|
+
encoding: 'utf8',
|
|
83
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
if (child.stdout) process.stdout.write(child.stdout);
|
|
87
|
+
if (child.stderr) process.stderr.write(child.stderr);
|
|
88
|
+
|
|
89
|
+
if (child.error || child.status !== 0) {
|
|
90
|
+
const error = child.error?.message || `skills CLI exited with status ${child.status}`;
|
|
91
|
+
console.error(`❌ Skill installation failed: ${error}`);
|
|
92
|
+
return { success: false, source: normalized, command, error };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const installedDirs = uniqueExistingDirs(installedSkillCandidates(normalized, { cwd, agentDir }));
|
|
96
|
+
const findings = installedDirs.flatMap(dir => scanDirectory(dir));
|
|
97
|
+
const report = formatReport(findings);
|
|
98
|
+
console.log(report.trimEnd());
|
|
99
|
+
|
|
100
|
+
if (findings.some(f => f.severity === 'CRITICAL')) {
|
|
101
|
+
const error = 'Installed skill contains critical scanner findings.';
|
|
102
|
+
console.error(`❌ ${error}`);
|
|
103
|
+
return { success: false, source: normalized, command, findings, error };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const compile = spawnSync('npx', ['total-recall', 'compile'], {
|
|
107
|
+
cwd,
|
|
108
|
+
encoding: 'utf8',
|
|
109
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
110
|
+
env: { ...process.env, AGENT_DIR: agentDir },
|
|
111
|
+
});
|
|
112
|
+
if (compile.status !== 0) {
|
|
113
|
+
console.warn('⚠️ Skill installed, but surface recompilation returned a warning.');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { success: true, source: normalized, command, findings };
|
|
117
|
+
}
|
package/scaffold/.agent/skills/total-recall/skills/{skill → tr-skill}/scripts/scan-skill.mjs
RENAMED
|
@@ -205,3 +205,23 @@ export function formatReport(findings) {
|
|
|
205
205
|
|
|
206
206
|
return report;
|
|
207
207
|
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* CLI-friendly scanner entrypoint.
|
|
211
|
+
*
|
|
212
|
+
* @param {string} targetDir
|
|
213
|
+
* @returns {{ success: boolean, findings: Array, report: string }}
|
|
214
|
+
*/
|
|
215
|
+
export function runScan(targetDir) {
|
|
216
|
+
if (!targetDir || !fs.existsSync(targetDir)) {
|
|
217
|
+
const report = `Skill directory not found: ${targetDir}\n`;
|
|
218
|
+
console.error(report.trim());
|
|
219
|
+
return { success: false, findings: [], report };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const findings = scanDirectory(targetDir);
|
|
223
|
+
const report = formatReport(findings);
|
|
224
|
+
const blocked = findings.some(f => f.severity === 'CRITICAL');
|
|
225
|
+
console.log(report.trimEnd());
|
|
226
|
+
return { success: !blocked, findings, report };
|
|
227
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: ssss
|
|
2
|
+
name: tr-ssss
|
|
3
|
+
provenance: total-recall
|
|
3
4
|
description: "Use this skill to inspect, validate, write, and manage SSSS primitives, memory nodes, operation envelopes, scope overlays, projections, and VFS specifications in the Total Recall reference kernel. MANDATORY: Read this file before editing SSSS files or code."
|
|
4
5
|
---
|
|
5
6
|
|
|
@@ -12,9 +13,16 @@ schema/reference files.
|
|
|
12
13
|
|
|
13
14
|
## Ground Truth
|
|
14
15
|
|
|
15
|
-
The vendor-neutral contract is
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
The vendor-neutral contract is now a published package, **`@ssss/cli`** (pinned to
|
|
17
|
+
**`v0.4.0`**; source <https://github.com/gregiteen/ssss>), declared in
|
|
18
|
+
`package.json`. `references/ssss-spec.md` is the local mirror. The canon owns the
|
|
19
|
+
spec (§5.5 portability, §6 Operation Contract incl. `delete`, §16 the `.ucw` bundle
|
|
20
|
+
format, §17 provisioning), the core registry (`@ssss/cli/registry/core.json`: 13
|
|
21
|
+
document + 5 contract primitives), the reference engine, and the conformance
|
|
22
|
+
fixtures. Total Recall's kernel was the engine the canon's reference implementation
|
|
23
|
+
was harvested from; keep them aligned. If this skill conflicts with the canon,
|
|
24
|
+
correct this skill unless the implementation has intentionally advanced beyond it
|
|
25
|
+
and the difference is documented here.
|
|
18
26
|
|
|
19
27
|
Current local implementation entry points:
|
|
20
28
|
|
|
@@ -27,6 +35,32 @@ Current local implementation entry points:
|
|
|
27
35
|
- `src/core/vector-store.mjs` and `src/core/semantic-index.mjs` — canonical
|
|
28
36
|
search/index path.
|
|
29
37
|
|
|
38
|
+
## Using the `@ssss/cli` CLI
|
|
39
|
+
|
|
40
|
+
`@ssss/cli` ships a `ssss` command (available via `npx`, since it's a dependency).
|
|
41
|
+
It operates on a **vault directory** of Markdown files and `.ucw` bundles, using
|
|
42
|
+
the canon's own reference engine — separate from this kernel's `processOperation`.
|
|
43
|
+
Use it for bundle/tenant tooling and conformance; for in-kernel memory writes keep
|
|
44
|
+
using `writeNodeValidated()` / `processOperation()`.
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npx ssss help # list doc topics; e.g. `ssss help portability|bundle|provisioning`
|
|
48
|
+
npx ssss <command> --help # flags for any command
|
|
49
|
+
|
|
50
|
+
# Vault → bundle → vault lifecycle (§16/§17)
|
|
51
|
+
npx ssss export <vault-dir> --profile sale --out pack.ucw.json # backup | template | sale
|
|
52
|
+
npx ssss validate pack.ucw.json # schema + portability + content hash
|
|
53
|
+
npx ssss inspect pack.ucw.json --files # manifest, inventory, params, steps
|
|
54
|
+
npx ssss provision pack.ucw.json --param domain=acme.live --out plan.json # pure: params + links → envelopes
|
|
55
|
+
npx ssss import pack.ucw.json --vault ./new-vault --param domain=acme.live # idempotent replay
|
|
56
|
+
|
|
57
|
+
npx ssss conformance --engine # replay the canonical fixtures + round-trip the reference bundle
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`export` is pure/deterministic and `template`/`sale` drop every `tenant_private`
|
|
61
|
+
file (§5.5). Note: the canon's `.ucw` bundle (§16) is distinct from §7.4's OKF
|
|
62
|
+
memory-vault `importBundle`/`exportBundle` in `repo-expert`.
|
|
63
|
+
|
|
30
64
|
## Current Contract
|
|
31
65
|
|
|
32
66
|
All agent-generated mutations must flow through the SSSS operation pipeline:
|
|
@@ -45,17 +79,16 @@ processOperation(envelope, vaultRoot, options)
|
|
|
45
79
|
Use `writeNodeValidated()` for Total Recall memory writes. Do not call raw
|
|
46
80
|
`writeNode()` or write files directly when an agent is mutating an SSSS vault.
|
|
47
81
|
|
|
48
|
-
Total Recall
|
|
82
|
+
Total Recall implements all four canonical envelope types in
|
|
49
83
|
`processOperation()`:
|
|
50
84
|
|
|
51
85
|
- `operation` — full file create/replace.
|
|
52
86
|
- `patch` — partial frontmatter/body merge.
|
|
53
87
|
- `event` — append-only JSON event payload.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
the CLI/API forget/archive flow.
|
|
88
|
+
- `delete` — remove a replace-type VFS file (SSSS spec §6.2). Refuses to delete
|
|
89
|
+
append-type documents (`conversation`, `run`), and emits an auditable deletion
|
|
90
|
+
event so history is never lost. Idempotent. For *memory* removal, still prefer
|
|
91
|
+
the CLI/API forget/archive flow over a raw `delete` envelope.
|
|
59
92
|
|
|
60
93
|
Use `dry_run: true` for preflight validation when constructing writes from model
|
|
61
94
|
output.
|
|
@@ -157,7 +190,7 @@ spec and tests are updated together.
|
|
|
157
190
|
Validate an individual SSSS Markdown file with:
|
|
158
191
|
|
|
159
192
|
```bash
|
|
160
|
-
node .agent/skills/ssss/scripts/validate-schema.mjs <path-to-node.md>
|
|
193
|
+
node .agent/skills/tr-ssss/scripts/validate-schema.mjs <path-to-node.md>
|
|
161
194
|
```
|
|
162
195
|
|
|
163
196
|
Run focused kernel tests after changing the operation contract, schema registry,
|
|
@@ -168,9 +201,17 @@ npx vitest run \
|
|
|
168
201
|
src/core/schema.spec.mjs \
|
|
169
202
|
src/core/operation-validator.spec.mjs \
|
|
170
203
|
src/core/total-recall-memory-validator.spec.mjs \
|
|
171
|
-
src/core/vault-cache.spec.mjs
|
|
204
|
+
src/core/vault-cache.spec.mjs \
|
|
205
|
+
src/core/ssss-conformance.bridge.spec.mjs
|
|
172
206
|
```
|
|
173
207
|
|
|
208
|
+
The **conformance bridge** (`src/core/ssss-conformance.bridge.spec.mjs`) runs the
|
|
209
|
+
canonical fixtures from `@ssss/cli` through this kernel's `processOperation` and
|
|
210
|
+
asserts every canonical core primitive is present in `SSSS_SCHEMAS`. It proves the
|
|
211
|
+
kernel implements the *same* standard as the festech and UltraChat hosts. If you
|
|
212
|
+
change the operation contract or the registry, keep this green; to adopt a newer
|
|
213
|
+
standard, bump the `@ssss/cli` pin and re-run it.
|
|
214
|
+
|
|
174
215
|
## Do Not
|
|
175
216
|
|
|
176
217
|
- Do not write agent mutations directly to vault files.
|
|
@@ -179,8 +220,7 @@ npx vitest run \
|
|
|
179
220
|
- Do not collapse `global`/`project` or `system`/`account`/`workspace` scope
|
|
180
221
|
boundaries.
|
|
181
222
|
- Do not represent copied seeded skills as canonical system primitives.
|
|
182
|
-
- Do not
|
|
183
|
-
supports them.
|
|
223
|
+
- Do not delete append-type documents (`conversation`, `run`); they are immutable.
|
|
184
224
|
- Do not add host-specific required fields to the vendor-neutral spec unless they
|
|
185
225
|
are being standardized.
|
|
186
226
|
|
|
@@ -188,7 +228,10 @@ npx vitest run \
|
|
|
188
228
|
|
|
189
229
|
| For | Read |
|
|
190
230
|
| --- | --- |
|
|
191
|
-
|
|
|
231
|
+
| Upstream canon (package) | `@ssss/cli` (`v0.4.0`, github:gregiteen/ssss) |
|
|
232
|
+
| Canonical core registry | `@ssss/cli/registry/core.json` |
|
|
233
|
+
| Conformance bridge | `src/core/ssss-conformance.bridge.spec.mjs` |
|
|
234
|
+
| SSSS standard (local mirror) | `references/ssss-spec.md` |
|
|
192
235
|
| Implemented schemas | `src/core/schema.mjs` |
|
|
193
236
|
| Operation pipeline | `src/core/operation-validator.mjs` |
|
|
194
237
|
| Validated memory writes | `src/core/validated-write.mjs` |
|
package/src/cli/connect.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import { agentDir as configAgentDir, brainDir as configBrainDir, xdgConfigHome, trBrain, trPat } from '../core/config.mjs';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { resolveAgentDir, getBothBrains, detectProjectBrain } from './agent-dir.mjs';
|
|
7
|
+
import { discoverRepoSkills, projectSkillsAsCommands } from './skill-projection.mjs';
|
|
7
8
|
|
|
8
9
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
9
10
|
// Resolve templates dir relative to this file (src/cli/ → ../../templates/)
|
|
@@ -52,24 +53,37 @@ const CLIENTS = {
|
|
|
52
53
|
label: 'Claude Code',
|
|
53
54
|
mode: 'symlink',
|
|
54
55
|
target: 'CLAUDE.md',
|
|
55
|
-
writeSlashCommands: true
|
|
56
|
+
writeSlashCommands: true,
|
|
57
|
+
// Project-scoped: repo skills are repo-specific. Claude Code discovers
|
|
58
|
+
// these as native skills / slash commands under <project>/.claude/skills/.
|
|
59
|
+
skillsProjection: { scope: 'project', dir: path.join('.claude', 'skills') }
|
|
56
60
|
},
|
|
57
61
|
codex: {
|
|
58
62
|
label: 'Codex',
|
|
59
63
|
mode: 'symlink',
|
|
60
|
-
target: 'AGENTS.md'
|
|
64
|
+
target: 'AGENTS.md',
|
|
65
|
+
// Codex only discovers skills globally under $CODEX_HOME/skills (~/.codex/skills).
|
|
66
|
+
// There is no project-local skills dir, so this projection is global by necessity.
|
|
67
|
+
skillsProjection: { scope: 'home', dir: path.join('.codex', 'skills') }
|
|
61
68
|
},
|
|
62
69
|
antigravity: {
|
|
63
70
|
label: 'Antigravity',
|
|
64
71
|
mode: 'symlink',
|
|
65
72
|
target: '.agents/rules/AGENTS.md',
|
|
66
|
-
writeSlashCommands: true
|
|
73
|
+
writeSlashCommands: true,
|
|
74
|
+
// Antigravity CLI (the Agent Skills standard) reads project workspace skills
|
|
75
|
+
// from <project>/.agents/skills/ and turns each into a /name slash command.
|
|
76
|
+
skillsProjection: { scope: 'project', dir: path.join('.agents', 'skills') }
|
|
67
77
|
},
|
|
68
78
|
gemini: {
|
|
69
79
|
label: 'Gemini',
|
|
70
80
|
mode: 'symlink',
|
|
71
81
|
target: '.agents/rules/GEMINI.md',
|
|
72
|
-
writeSlashCommands: true
|
|
82
|
+
writeSlashCommands: true,
|
|
83
|
+
// Gemini CLI reads project workspace skills from <project>/.agents/skills/
|
|
84
|
+
// (the same Agent Skills location Antigravity uses) and turns each into a
|
|
85
|
+
// /name slash command.
|
|
86
|
+
skillsProjection: { scope: 'project', dir: path.join('.agents', 'skills') }
|
|
73
87
|
},
|
|
74
88
|
aider: {
|
|
75
89
|
label: 'Aider',
|
|
@@ -293,7 +307,12 @@ function writeSymlinkProjection(cwd, preset, opts) {
|
|
|
293
307
|
fs.rmSync(targetPath, { force: true, recursive: true });
|
|
294
308
|
}
|
|
295
309
|
}
|
|
296
|
-
|
|
310
|
+
// Ensure the parent dir exists (nested targets like .agents/rules/AGENTS.md)
|
|
311
|
+
// and point the symlink at INSTRUCTIONS.md using a path relative to the
|
|
312
|
+
// link's own directory, so nested projections don't dangle.
|
|
313
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
314
|
+
const linkTarget = path.relative(path.dirname(targetPath), instructionsPath);
|
|
315
|
+
fs.symlinkSync(linkTarget, targetPath);
|
|
297
316
|
return { targetPath, action: 'symlinked' };
|
|
298
317
|
}
|
|
299
318
|
|
|
@@ -844,6 +863,29 @@ export default async function connect(args) {
|
|
|
844
863
|
}
|
|
845
864
|
}
|
|
846
865
|
|
|
866
|
+
// Project repo skills as native slash commands via the Agent Skills standard.
|
|
867
|
+
// Each <agentDir>/skills/<name>/SKILL.md becomes /<name> in the target IDE.
|
|
868
|
+
if (preset.skillsProjection) {
|
|
869
|
+
const skills = discoverRepoSkills(agentDir);
|
|
870
|
+
if (skills.length > 0) {
|
|
871
|
+
const destDir = preset.skillsProjection.scope === 'home'
|
|
872
|
+
? path.join(os.homedir(), preset.skillsProjection.dir)
|
|
873
|
+
: path.join(cwd, preset.skillsProjection.dir);
|
|
874
|
+
const skillResults = projectSkillsAsCommands(destDir, skills, opts);
|
|
875
|
+
result.skill_commands = skillResults;
|
|
876
|
+
const fresh = skillResults.filter(r => r.action === 'linked');
|
|
877
|
+
if (fresh.length > 0) {
|
|
878
|
+
const destLabel = preset.skillsProjection.scope === 'home'
|
|
879
|
+
? destDir
|
|
880
|
+
: (path.relative(cwd, destDir) || destDir);
|
|
881
|
+
result.notes.push(
|
|
882
|
+
` Repo skills projected as slash commands → ${destLabel}/:\n` +
|
|
883
|
+
fresh.map(r => ` /${r.name}`).join('\n')
|
|
884
|
+
);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
847
889
|
// Record this client in the registry so `status` can report freshness
|
|
848
890
|
registerClient(brainDir, opts.client, preset, result.projection?.targetPath || null);
|
|
849
891
|
|
package/src/cli/init.mjs
CHANGED
|
@@ -30,6 +30,7 @@ import path from 'node:path';
|
|
|
30
30
|
import os from 'node:os';
|
|
31
31
|
import { fileURLToPath } from 'node:url';
|
|
32
32
|
import { exec, spawn, spawnSync } from 'node:child_process';
|
|
33
|
+
import { projectSkillsForScope, detectActiveSkillTargets } from './skill-projection.mjs';
|
|
33
34
|
|
|
34
35
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
35
36
|
const ROOT = path.join(__dirname, '..', '..');
|
|
@@ -83,7 +84,8 @@ function parseArgs(args) {
|
|
|
83
84
|
domain: null,
|
|
84
85
|
tunnelName: null,
|
|
85
86
|
tunnelCredentials: null,
|
|
86
|
-
yes: false
|
|
87
|
+
yes: false,
|
|
88
|
+
force: false
|
|
87
89
|
};
|
|
88
90
|
for (let i = 0; i < args.length; i++) {
|
|
89
91
|
const arg = args[i];
|
|
@@ -97,6 +99,7 @@ function parseArgs(args) {
|
|
|
97
99
|
else if (arg === '--tunnel-name') opts.tunnelName = args[++i];
|
|
98
100
|
else if (arg === '--tunnel-credentials') opts.tunnelCredentials = args[++i];
|
|
99
101
|
else if (arg === '--yes' || arg === '-y') opts.yes = true;
|
|
102
|
+
else if (arg === '--force') opts.force = true;
|
|
100
103
|
}
|
|
101
104
|
return opts;
|
|
102
105
|
}
|
|
@@ -474,7 +477,7 @@ export default async function init(args) {
|
|
|
474
477
|
}
|
|
475
478
|
|
|
476
479
|
// ── Symlink nested brain skills to top-level .agent/skills/ ──
|
|
477
|
-
// Skills inside the brain (e.g. .agent/skills/total-recall/skills/ssss/) are
|
|
480
|
+
// Skills inside the brain (e.g. .agent/skills/total-recall/skills/tr-ssss/) are
|
|
478
481
|
// invisible to IDEs because they only scan .agent/skills/<name>/ one level
|
|
479
482
|
// deep. Create symlinks so they appear as slash commands.
|
|
480
483
|
const nestedSkillsDir = path.join(brainDir, 'skills');
|
|
@@ -498,6 +501,43 @@ export default async function init(args) {
|
|
|
498
501
|
}
|
|
499
502
|
}
|
|
500
503
|
|
|
504
|
+
// ── Step 3.7: Project skills as slash commands into the IDEs in use ──
|
|
505
|
+
// Scope matches the brain: `init --project` projects PROJECT skills into the
|
|
506
|
+
// repo's IDE skill dirs for IDEs actually used here (.claude/, .agents/, or
|
|
507
|
+
// the current process); `init` projects GLOBAL skills into installed IDEs'
|
|
508
|
+
// global skill dirs. Codex (global-only) is opt-in for project skills.
|
|
509
|
+
const skillScope = isProject ? 'project' : 'global';
|
|
510
|
+
logStep('3.7/4', `Projecting ${skillScope} skills as slash commands (IDEs in use)`);
|
|
511
|
+
if (opts.dryRun) {
|
|
512
|
+
const targets = detectActiveSkillTargets({ scope: skillScope, cwd });
|
|
513
|
+
for (const t of targets.filter(t => t.supported)) {
|
|
514
|
+
const destLabel = t.destDir ? path.relative(cwd, t.destDir) || t.destDir : '(n/a)';
|
|
515
|
+
log(` ${t.active ? 'would wire' : 'available (opt-in)'}: ${t.label} → ${destLabel}/`);
|
|
516
|
+
}
|
|
517
|
+
} else {
|
|
518
|
+
try {
|
|
519
|
+
const { skills, wired, available } = projectSkillsForScope({
|
|
520
|
+
scope: skillScope, cwd, agentDir, opts: { force: opts.force }
|
|
521
|
+
});
|
|
522
|
+
if (skills.length === 0) {
|
|
523
|
+
log(' No skills found yet — author one under .agent/skills/<name>/SKILL.md');
|
|
524
|
+
} else if (wired.length === 0) {
|
|
525
|
+
log(` No in-use IDE detected for ${skillScope} skills — run \`npx total-recall connect <ide>\` to wire them.`);
|
|
526
|
+
} else {
|
|
527
|
+
for (const t of wired) {
|
|
528
|
+
const n = t.results.filter(r => ['linked', 'exists', 'source'].includes(r.action)).length;
|
|
529
|
+
logOk(`${t.label}: ${n} skill(s) → ${path.relative(cwd, t.destDir) || t.destDir}/`);
|
|
530
|
+
}
|
|
531
|
+
log(` Slash commands: ${skills.map(s => '/' + s.name).join(', ')}`);
|
|
532
|
+
if (available.length > 0) {
|
|
533
|
+
log(` Also available (opt-in): ${available.map(t => t.clients.join('/')).join(', ')} — \`npx total-recall connect <ide>\``);
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
} catch (err) {
|
|
537
|
+
logWarn(`Could not project skills into IDEs: ${err.message}`);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
|
|
501
541
|
// ── Step 4: Run compile to inject memory block into existing IDE files ──
|
|
502
542
|
logStep('4/4', 'Compiling vault and injecting into IDE instruction files');
|
|
503
543
|
|