total-recall-brain 3.43.3 → 3.44.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.
Files changed (93) hide show
  1. package/docs/reference/cli-reference.md +3 -1
  2. package/package.json +3 -3
  3. package/scaffold/.agent/skills/plugin/SKILL.md +7 -2
  4. package/scaffold/.agent/skills/plugin/evals/README.md +5 -0
  5. package/scaffold/.agent/skills/plugin/evals/cases/01-fabricated-seed.mjs +1 -0
  6. package/scaffold/.agent/skills/plugin/evals/cases/02-reassuring-default.mjs +1 -0
  7. package/scaffold/.agent/skills/plugin/evals/cases/03-declared-template.mjs +1 -0
  8. package/scaffold/.agent/skills/plugin/evals/cases/04-card-collects-credential.mjs +1 -0
  9. package/scaffold/.agent/skills/plugin/evals/cases/05-host-leak-in-scaffold.mjs +1 -0
  10. package/scaffold/.agent/skills/plugin/evals/cases/06-correct-plugin.mjs +1 -0
  11. package/scaffold/.agent/skills/plugin/evals/cases/07-missing-reuse.mjs +11 -0
  12. package/scaffold/.agent/skills/plugin/evals/cases/08-unresolved-owner-command.mjs +12 -0
  13. package/scaffold/.agent/skills/plugin/evals/cases/09-missing-brick.mjs +12 -0
  14. package/scaffold/.agent/skills/plugin/prompts/01-function.md +4 -3
  15. package/scaffold/.agent/skills/plugin/prompts/08-verify.md +1 -0
  16. package/scaffold/.agent/skills/plugin/references/surfaces.md +12 -2
  17. package/scaffold/.agent/skills/plugin/scripts/record.mjs +59 -2
  18. package/scaffold/.agent/skills/total-recall/plugins/auth/README.md +8 -0
  19. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +14 -13
  20. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +3 -3
  21. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +1 -1
  22. package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-gh-login.mjs +102 -0
  23. package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +18 -1
  24. package/scaffold/.agent/skills/total-recall/plugins/auth/src/login-projections.mjs +157 -13
  25. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-sync.mjs +161 -17
  26. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +14 -13
  27. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +3 -3
  28. package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +1 -1
  29. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +14 -13
  30. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +3 -3
  31. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +1 -1
  32. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +14 -13
  33. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +3 -3
  34. package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +1 -1
  35. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +14 -13
  36. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +3 -3
  37. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/plugin.json +1 -1
  38. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +14 -13
  39. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +3 -3
  40. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +1 -1
  41. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +38 -5
  42. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +38 -7
  43. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +14 -13
  44. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +3 -3
  45. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +85 -3
  46. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +2 -1
  47. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/adoption.mjs +104 -0
  48. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +12 -1
  49. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +15 -3
  50. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch-request.mjs +38 -0
  51. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +42 -11
  52. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +40 -13
  53. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/included-usage.mjs +249 -0
  54. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +3 -0
  55. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +16 -8
  56. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/process-manager.mjs +1 -0
  57. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/reasoning.mjs +5 -0
  58. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/remote-operation.mjs +1 -1
  59. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +27 -11
  60. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +28 -6
  61. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/usage-queue.mjs +110 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +322 -40
  63. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +14 -13
  64. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +3 -3
  65. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +1 -1
  66. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +14 -13
  67. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +3 -3
  68. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +1 -1
  69. package/scaffold/.agent/skills/total-recall/plugins/ssss/assets/scaffold.json +5 -5
  70. package/scaffold/.agent/skills/total-recall/plugins/ssss/package-lock.json +6 -6
  71. package/scaffold/.agent/skills/total-recall/plugins/ssss/package.json +2 -2
  72. package/scaffold/.agent/skills/total-recall/plugins/ssss/plugin.json +1 -1
  73. package/src/cli/connect.mjs +2 -29
  74. package/src/cli/context.mjs +1 -0
  75. package/src/cli/ingest-okf.mjs +4 -4
  76. package/src/cli/release.mjs +4 -1
  77. package/src/cli/update.mjs +4 -1
  78. package/src/core/automatic-brain-updates.mjs +11 -6
  79. package/src/core/brain-updates.mjs +11 -1
  80. package/src/core/context-compactor.mjs +7 -2
  81. package/src/core/context-compiler.mjs +6 -1
  82. package/src/core/context-policy.mjs +7 -3
  83. package/src/core/daemon-control.mjs +22 -0
  84. package/src/core/global-brain-updates.mjs +1 -1
  85. package/src/core/mesh-brain-updates.mjs +2 -1
  86. package/src/core/server-restart.mjs +128 -7
  87. package/src/core/ssss-kernel-bridge.mjs +1 -2
  88. package/src/core/surface.mjs +3 -3
  89. package/src/core/task-context.mjs +9 -8
  90. package/src/core/validated-write.mjs +4 -0
  91. package/src/core/vault-files.mjs +8 -2
  92. package/src/core/vault.mjs +1 -1
  93. package/src/server/index.mjs +3 -1
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://github.com/gregiteen/total-recall/blob/main/metadata.plugin.schema.json",
3
3
  "id": "openwiki",
4
4
  "name": "OpenWiki",
5
- "version": "0.1.9",
5
+ "version": "0.1.10",
6
6
  "description": "Multi-repo knowledge graph and documentation wiki engine for Total Recall.",
7
7
  "license": "MIT",
8
8
  "runtime": {
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "tr-plugin-security",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "tr-plugin-security",
9
- "version": "0.3.5",
9
+ "version": "0.3.6",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "@gregiteen/ssss-cli": "0.14.4"
12
+ "@gregiteen/ssss-cli": "0.14.5"
13
13
  },
14
14
  "devDependencies": {
15
15
  "jsdom": "^26.1.0",
16
- "total-recall-brain": "3.42.1"
16
+ "total-recall-brain": "3.43.3"
17
17
  }
18
18
  },
19
19
  "node_modules/@alcalzone/ansi-tokenize": {
@@ -845,9 +845,9 @@
845
845
  }
846
846
  },
847
847
  "node_modules/@gregiteen/ssss-cli": {
848
- "version": "0.14.4",
849
- "resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.4.tgz",
850
- "integrity": "sha512-R6JIgPRvS9xXp0xb6BYO3rauv+72r35GIiDrJcvbjPdTSHFZXr8/jRxFOgoF8yTed/5xyGFF3ey3DI9bOjmHVA==",
848
+ "version": "0.14.5",
849
+ "resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.5.tgz",
850
+ "integrity": "sha512-qVEYOocnwn97uJ0eDzmuwN06CYsYWr2t3+iKylpisBHX4wlLWk7P8EmFFdBlx7NyKVIZDDeYT164Gd7/T8UGgw==",
851
851
  "license": "ISC",
852
852
  "bin": {
853
853
  "ssss": "scripts/ssss.mjs"
@@ -1686,9 +1686,9 @@
1686
1686
  },
1687
1687
  "node_modules/@ssss/cli": {
1688
1688
  "name": "@gregiteen/ssss-cli",
1689
- "version": "0.14.4",
1690
- "resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.4.tgz",
1691
- "integrity": "sha512-R6JIgPRvS9xXp0xb6BYO3rauv+72r35GIiDrJcvbjPdTSHFZXr8/jRxFOgoF8yTed/5xyGFF3ey3DI9bOjmHVA==",
1689
+ "version": "0.14.5",
1690
+ "resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.5.tgz",
1691
+ "integrity": "sha512-qVEYOocnwn97uJ0eDzmuwN06CYsYWr2t3+iKylpisBHX4wlLWk7P8EmFFdBlx7NyKVIZDDeYT164Gd7/T8UGgw==",
1692
1692
  "dev": true,
1693
1693
  "license": "ISC",
1694
1694
  "bin": {
@@ -5698,9 +5698,9 @@
5698
5698
  }
5699
5699
  },
5700
5700
  "node_modules/total-recall-brain": {
5701
- "version": "3.42.1",
5702
- "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.42.1.tgz",
5703
- "integrity": "sha512-woH7mdkGwPFYlKPZurhE8L3BPe+cSeIruNGaPOjGZJm/O8C92Bbr1gsdOY0tTLg5QHlgPHcXG1GMtsm9lPDz8w==",
5701
+ "version": "3.43.3",
5702
+ "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.43.3.tgz",
5703
+ "integrity": "sha512-yjfPN/BQxEEa+iodyFXQov/6fRt1pZg/7RcmgsbpALwBt6Ki3JJjT3tzArBC7NxHQmXgGYyKnCYId6xe/W2rPg==",
5704
5704
  "dev": true,
5705
5705
  "license": "MIT",
5706
5706
  "workspaces": [
@@ -5731,6 +5731,7 @@
5731
5731
  "antigravity": "bin/antigravity.mjs",
5732
5732
  "total-recall": "bin/total-recall.mjs",
5733
5733
  "total-recall-memory": "bin/total-recall-memory.mjs",
5734
+ "total-recall-server-release": "bin/total-recall-server-release.mjs",
5734
5735
  "vibebrain": "bin/total-recall.mjs"
5735
5736
  },
5736
5737
  "optionalDependencies": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tr-plugin-security",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "type": "module",
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": {
@@ -24,9 +24,9 @@
24
24
  "access": "public"
25
25
  },
26
26
  "dependencies": {
27
- "@gregiteen/ssss-cli": "0.14.4"
27
+ "@gregiteen/ssss-cli": "0.14.5"
28
28
  },
29
29
  "overrides": {
30
- "@ssss/cli": "npm:@gregiteen/ssss-cli@0.14.4"
30
+ "@ssss/cli": "npm:@gregiteen/ssss-cli@0.14.5"
31
31
  }
32
32
  }
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://github.com/gregiteen/total-recall/blob/main/metadata.plugin.schema.json",
3
3
  "id": "security",
4
4
  "name": "Security Assessments",
5
- "version": "0.3.5",
5
+ "version": "0.3.6",
6
6
  "description": "Machine and device security assessments for macOS, Linux, Windows, Android, Chromebook, iPhone and iPad, with explicit measured and manual coverage.",
7
7
  "license": "MIT",
8
8
  "requires": [{ "id": "auth", "range": ">=1.2.1" }],
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.14.4",
2
+ "version": "0.14.5",
3
3
  "files": {
4
4
  ".gitignore": {
5
5
  "sha256": "0d6c69a5cbd2270c9163d8e1563976b6d15131d0ef599e6fbc413ee287a86da0",
@@ -18,8 +18,8 @@
18
18
  "content": "# ssss-project — System Architecture & Design\n\n> Technical design and architecture specification for ssss-project.\n\n## Overview\n\n<High-level summary of the system and its primary goals.>\n\n## Component Architecture\n\n- **Vault Structure**: Typed Markdown documents under `vault/` serving as the source of truth.\n- **Workflows & Execution**: Automated procedures defined in `vault/workflows/` triggered by operational events.\n- **Capabilities & Resources**: Tools and external service integrations required for execution.\n\n## Data & Schema Contracts\n\n<Core entities, external dependencies, and integration interfaces.>\n\n## Open Decisions & Invariants\n\n- SSSS VFS is the single source of truth for application state.\n- Structural business logic is strictly decoupled from private tenant operational data.\n- App-specific primitives reside in `registry/extensions/` within this repository and extend `core`.\n- Core SSSS library (`@gregiteen/ssss-cli`) remains vendor-neutral and dependency-free.\n"
19
19
  },
20
20
  "package.json": {
21
- "sha256": "18389bfc91857c6d5917a3ac1af9da8a992c99b013f42f2843921cdc7b41bdfe",
22
- "content": "{\n \"name\": \"ssss-project\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"description\": \"An SSSS-native project — Markdown vault as source of truth.\",\n \"scripts\": {\n \"ssss\": \"ssss\",\n \"test\": \"node --test\",\n \"export\": \"ssss export vault --profile sale --out dist/bundle.ucw.json\",\n \"validate\": \"ssss conformance --engine\"\n },\n \"dependencies\": {\n \"@gregiteen/ssss-cli\": \"github:gregiteen/ssss#v0.14.4\"\n }\n}\n"
21
+ "sha256": "ea77c2944b853999741a8e603de257604048c63b5db8754a0e8b92f383ff973b",
22
+ "content": "{\n \"name\": \"ssss-project\",\n \"version\": \"0.1.0\",\n \"private\": true,\n \"type\": \"module\",\n \"description\": \"An SSSS-native project — Markdown vault as source of truth.\",\n \"scripts\": {\n \"ssss\": \"ssss\",\n \"test\": \"node --test\",\n \"export\": \"ssss export vault --profile sale --out dist/bundle.ucw.json\",\n \"validate\": \"ssss conformance --engine\"\n },\n \"dependencies\": {\n \"@gregiteen/ssss-cli\": \"github:gregiteen/ssss#v0.14.5\"\n }\n}\n"
23
23
  },
24
24
  "test/ssss-conformance.test.mjs": {
25
25
  "sha256": "f626d2f56799fcfda74375d3ddf546cc181a10caf2df08b72b7f2e36782c9bc1",
@@ -43,8 +43,8 @@
43
43
  }
44
44
  },
45
45
  "skill": {
46
- "SKILL.md": "4976c9615482f257fd023761dd3ef36b5aa278305ff22ae110295fe4945f5d4c",
47
- "core/SKILL.md": "96c6479ad06b84c5f7ffd8bb05bff414dbb8c22a040ec1f1c05d8fa4fdbd976e",
46
+ "SKILL.md": "e5c2c0aa2c0fb5480c1f7bdb37928f935e1160bff18fd6b63366a04f3e281938",
47
+ "core/SKILL.md": "12543720135f13650efcd7afd751e3253996692c6ab805fd7da99788b6fc4af9",
48
48
  "core/references/core-registry.json": "16831aa3b6be3f561a9ca7abdc36065a4843ff595aa3acf5c3fb8af2d733b7e3",
49
49
  "core/references/ssss-spec.md": "cc319e78b1b568651d5717695348363349d502c0e20663da9858369022ddfc3b",
50
50
  "core/scripts/maintain.mjs": "eebcae898f2ce0cf3f0059c6f6737bee8877409de2d370d54a4015a9a82414e9",
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "tr-plugin-ssss",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "tr-plugin-ssss",
9
- "version": "0.1.2",
9
+ "version": "0.1.3",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "@gregiteen/ssss-cli": "0.14.4"
12
+ "@gregiteen/ssss-cli": "0.14.5"
13
13
  }
14
14
  },
15
15
  "node_modules/@gregiteen/ssss-cli": {
16
- "version": "0.14.4",
17
- "resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.4.tgz",
18
- "integrity": "sha512-R6JIgPRvS9xXp0xb6BYO3rauv+72r35GIiDrJcvbjPdTSHFZXr8/jRxFOgoF8yTed/5xyGFF3ey3DI9bOjmHVA==",
16
+ "version": "0.14.5",
17
+ "resolved": "https://registry.npmjs.org/@gregiteen/ssss-cli/-/ssss-cli-0.14.5.tgz",
18
+ "integrity": "sha512-qVEYOocnwn97uJ0eDzmuwN06CYsYWr2t3+iKylpisBHX4wlLWk7P8EmFFdBlx7NyKVIZDDeYT164Gd7/T8UGgw==",
19
19
  "license": "ISC",
20
20
  "bin": {
21
21
  "ssss": "scripts/ssss.mjs"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tr-plugin-ssss",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "Canonical SSSS distribution, scaffolding and validation for Total Recall installations.",
@@ -19,7 +19,7 @@
19
19
  "check:ssss-conformance": "node cli.mjs conformance"
20
20
  },
21
21
  "dependencies": {
22
- "@gregiteen/ssss-cli": "0.14.4"
22
+ "@gregiteen/ssss-cli": "0.14.5"
23
23
  },
24
24
  "license": "MIT"
25
25
  }
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://github.com/gregiteen/total-recall/blob/main/metadata.plugin.schema.json",
3
3
  "id": "ssss",
4
4
  "name": "SSSS",
5
- "version": "0.1.2",
5
+ "version": "0.1.3",
6
6
  "description": "Canonical SSSS distribution, scaffolding and validation for Total Recall installations.",
7
7
  "license": "MIT",
8
8
  "use_cases": ["software-development", "state-conformance"],
@@ -80,11 +80,10 @@ export const CLIENTS = {
80
80
  },
81
81
  openclaw: {
82
82
  label: 'OpenClaw',
83
- mode: 'openclaw',
83
+ mode: 'symlink',
84
84
  enforcement: 'enforced',
85
85
  enforcementReason: 'before_tool_call hook denies unreceipted tool calls with exit 2',
86
- memoryTarget: 'MEMORY.md',
87
- agentsTarget: 'AGENTS.md',
86
+ target: 'AGENTS.md',
88
87
  },
89
88
  cursor: {
90
89
  label: 'Cursor',
@@ -880,32 +879,6 @@ export default async function connect(args) {
880
879
  result.notes.push(` DeepSeek Harness MEMORY.md → ${globalMemPath}`);
881
880
  }
882
881
  result.notes.push(` DeepSeek Harness AGENTS.md → INSTRUCTIONS.md`);
883
- } else if (preset.mode === 'openclaw') {
884
- // OpenClaw: write MEMORY.md + symlink AGENTS.md in cwd
885
- const instructions = readInstructions(cwd, agentDir);
886
- if (!instructions) throw new Error('No INSTRUCTIONS.md found. Run npx total-recall init or compile first.');
887
- // MEMORY.md — curated facts extracted from instructions
888
- const memPath = path.join(cwd, preset.memoryTarget);
889
- if (!fs.existsSync(memPath) || opts.force) {
890
- fs.writeFileSync(memPath, instructions, 'utf8');
891
- }
892
- // AGENTS.md — symlink to INSTRUCTIONS.md
893
- const agentsPath = path.join(cwd, preset.agentsTarget);
894
- if (pathExists(agentsPath)) {
895
- if (opts.force) {
896
- try {
897
- fs.unlinkSync(agentsPath);
898
- } catch {
899
- fs.rmSync(agentsPath, { force: true, recursive: true });
900
- }
901
- fs.symlinkSync('INSTRUCTIONS.md', agentsPath);
902
- }
903
- } else {
904
- fs.symlinkSync('INSTRUCTIONS.md', agentsPath);
905
- }
906
- result.projection = { targetPath: memPath, action: 'written' };
907
- result.notes.push(` OpenClaw MEMORY.md written to ${memPath}`);
908
- result.notes.push(` OpenClaw AGENTS.md → INSTRUCTIONS.md`);
909
882
  } else if (preset.mode === 'vault') {
910
883
  result.projection = writeVaultProjection(agentDir, preset, opts);
911
884
  const folderName = result.projection.folderName || preset.folderName;
@@ -61,6 +61,7 @@ async function printCompacted({ query, actions, budget, format, version, rulesHa
61
61
  if (format !== 'json') return result.context;
62
62
  const payload = { ready: true, compacted: true, ranking: result.ranking, context: result.context, counts: result.counts,
63
63
  stats: { version, rules_hash: rulesHash, budget, retrieval: summarizeRetrieval(knowledge?.summary), token_measurement: 'estimated_chars_divided_by_four' } };
64
+ if (result.evidenceStart !== undefined) payload.evidence_start = result.evidenceStart;
64
65
  for (let index = 0; index < 10; index++) {
65
66
  const tokens = estimateTokens(`${JSON.stringify(payload)}\n`);
66
67
  if (tokens === payload.stats.total_tokens) break;
@@ -11,7 +11,7 @@ export async function runOkfIngest(args) {
11
11
  dryRun: false,
12
12
  category: null,
13
13
  importance: null,
14
- onConflict: 'warn',
14
+ onConflict: 'skip',
15
15
  typeMap: null,
16
16
  help: false
17
17
  };
@@ -118,10 +118,10 @@ function printIngestOkfHelp() {
118
118
 
119
119
  Options:
120
120
  --dry-run Validate concepts and preview import without writing
121
- --category <name> Override and force category for all imported concepts
121
+ --category <name> Choose a descriptive category for imported concepts
122
122
  --importance <1-5> Override default importance (default: 3)
123
- --on-conflict <strategy> Strategy for duplicate slugs: 'skip' | 'warn' | 'overwrite' (default: warn)
124
- --type-map <mapping> Custom type mappings. Format: "Type A=facts,Type B=concepts"
123
+ --on-conflict <strategy> 'skip' (default), 'warn' (report and skip), or 'overwrite' (same imported concept)
124
+ --type-map <mapping> Map types to descriptive categories, e.g. "Type A=facts,Type B=concepts"
125
125
  --global Target the global brain
126
126
  --project Target the project brain (default)
127
127
  --help, -h Show this help
@@ -141,7 +141,10 @@ export async function tarballServed(pkg, version, { exec = spawnSync, fetchImpl
141
141
  * Wait until a just-published version can be installed: listed as latest, and its tarball served.
142
142
  * 3.42.0 took about six minutes and 3.42.1 about eight, its listing four minutes ahead of its tarball.
143
143
  */
144
- export async function awaitPublished(pkg, version, { attempts = 45, delayMs = 20000, exec = spawnSync, sleep, tarball = tarballServed } = {}) {
144
+ /** npm has taken 8 and then 23 minutes to serve an accepted publish, so a shorter wait reports failure on a good release. */
145
+ export const REGISTRY_WAIT = Object.freeze({ attempts: 120, delayMs: 20000 });
146
+
147
+ export async function awaitPublished(pkg, version, { attempts = REGISTRY_WAIT.attempts, delayMs = REGISTRY_WAIT.delayMs, exec = spawnSync, sleep, tarball = tarballServed } = {}) {
145
148
  const pause = sleep || ((ms) => new Promise((r) => setTimeout(r, ms)));
146
149
  let last = null;
147
150
  for (let i = 0; i < attempts; i++) {
@@ -79,7 +79,9 @@ function printHelp() {
79
79
  writing package.json or the lockfile. Register it to develop it here.
80
80
  total-recall update --automatic [--json]
81
81
  Daemon maintenance: update both packages, ensure defaults, update every
82
- installed plugin from its recorded source and refresh surfaces.
82
+ installed plugin from its recorded source and refresh surfaces. Where a
83
+ per-user service (LaunchAgent, systemd user unit) runs the server from
84
+ the global install, also restart a stale server and verify /health.
83
85
  total-recall update --status [--json]
84
86
  Read the actual last automatic maintenance report without starting work.
85
87
  Also reports what the server on this host runs against the release.
@@ -96,6 +98,7 @@ function printHelp() {
96
98
 
97
99
  Env:
98
100
  TR_AUTO_UPDATE_PACKAGE=0 Disable daemon cron auto-update (default: on)
101
+ TR_SERVER_AUTO_RESTART=0 Report a stale server instead of restarting it (default: on)
99
102
  TR_SYNC_REPOS=/a:/b Extra project roots
100
103
 
101
104
  Source monorepos named ${PACKAGE_NAME} are skipped (use git, not npm into self).
@@ -13,6 +13,7 @@ import { updateMeshBrainPackages } from './mesh-brain-updates.mjs';
13
13
  import { updateSourceBrainPackages } from './source-brain-updates.mjs';
14
14
  import { updateInstalledPlugins } from './plugin-updates.mjs';
15
15
  import { runningServerStatus } from './running-server.mjs';
16
+ import { replaceStaleServer } from './server-restart.mjs';
16
17
 
17
18
  export function automaticUpdateStatus(brainDir) {
18
19
  let last;
@@ -37,7 +38,7 @@ export function startAutomaticBrainUpdates({brainDir,intervalMs=60*60*1000,run=r
37
38
  return {tick,stop(){stopped=true;clearInterval(timer);}};
38
39
  }
39
40
 
40
- export async function runAutomaticBrainUpdates({brainDir,fleet=false,force=false,skipThrottle=false,intervalMs=60*60*1000,update=updateAllBrains,compile=maintainCliSurfaces,globalUpdate=updateGlobalBrainPackages,meshUpdate=updateMeshBrainPackages,sourceUpdate=updateSourceBrainPackages,pluginUpdate=updateInstalledPlugins,skillMaintenance=maintainPortableSkills,serverCheck=runningServerStatus,now=Date.now}={}) {
41
+ export async function runAutomaticBrainUpdates({brainDir,fleet=false,force=false,skipThrottle=false,intervalMs=60*60*1000,update=updateAllBrains,compile=maintainCliSurfaces,globalUpdate=updateGlobalBrainPackages,meshUpdate=updateMeshBrainPackages,sourceUpdate=updateSourceBrainPackages,pluginUpdate=updateInstalledPlugins,skillMaintenance=maintainPortableSkills,serverCheck=runningServerStatus,replaceServer=replaceStaleServer,now=Date.now}={}) {
41
42
  if(!force && !isPackageAutoUpdateEnabled())return {skipped:true,reason:'disabled',results:[]};
42
43
  const file=path.join(brainDir,'memory-derived/automatic-brain-updates.json');
43
44
  let saved;try{saved=JSON.parse(fs.readFileSync(file,'utf8'));}catch{}
@@ -65,16 +66,20 @@ export async function runAutomaticBrainUpdates({brainDir,fleet=false,force=false
65
66
  const plugins=await pluginUpdate({roots:[path.resolve(brainDir,'../../..')]});
66
67
  const mesh=fleet && summary.versions?await meshUpdate({versions:summary.versions,version:summary.versions['total-recall-brain']}):{failed:0,results:[],scope:'local-only'};
67
68
  const changed=summary.updated>0 || plugins.updated>0 || global.results.some(row=>row.status==='updated') || sources.results.some(row=>row.status==='updated') || JSON.stringify(saved?.versions)!==JSON.stringify(summary.versions);
68
- // A lagging server is reported and not counted as a failure: maintenance cannot fix it, and
69
- // a failure would retry every five minutes. Replacing one in production is a deploy decision.
70
- const server=await serverCheck({brainDir,latest:summary.versions?.['total-recall-brain']});
71
- if(server.status==='stale' || server.status==='down')logger.error('automatic-brain-updates',`Running server: ${server.reason}`);
72
69
  const skills=await skillMaintenance({brainDir});
73
70
  const surfaces=await compile({brainDir,force:changed || skills.updated > 0});
71
+ // Last, so a replaced server starts on everything this run moved. Where maintenance cannot
72
+ // replace it, a lagging server is reported and not counted as a failure, which would retry
73
+ // every five minutes for nothing: in production that is a deploy decision. Where it can, a
74
+ // hold or a failed attempt is this machine's own failure, which is what makes a peer dispatch it again.
75
+ let server=await serverCheck({brainDir,latest:summary.versions?.['total-recall-brain']});
76
+ if(server.status==='stale')server=await replaceServer({brainDir,server,globalRoot:global.root,previous:saved?.server});
77
+ if(server.status==='stale' || server.status==='down')logger.error('automatic-brain-updates',`Running server: ${server.replacement?.reason || server.reason}`);
78
+ const serverFailed=['held','failed'].includes(server.replacement?.state)?1:0;
74
79
  // local_failed is this node's own maintenance. Peers judge a node by it, not by
75
80
  // `failed`, which also counts the node's view of its peers: judging by that made
76
81
  // every fleet pass mark every peer failed forever, each because the others had.
77
- const local_failed=(summary.failed || 0)+global.failed+sources.failed+plugins.failed+(skills.failed || 0)+(surfaces.ok?0:surfaces.results.filter(row=>row.status==='failed').length);
82
+ const local_failed=(summary.failed || 0)+global.failed+sources.failed+plugins.failed+(skills.failed || 0)+(surfaces.ok?0:surfaces.results.filter(row=>row.status==='failed').length)+serverFailed;
78
83
  report={...summary,global,sources,plugins,mesh,server,skills,surfaces,local_failed,failed:local_failed+mesh.failed,checkedAt:now()};
79
84
  }catch(error){report={failed:1,error:error.message,checkedAt:now(),results:[]};}
80
85
  const temporary=`${file}.${process.pid}.tmp`;fs.writeFileSync(temporary,JSON.stringify(report,null,2));fs.renameSync(temporary,file);
@@ -19,6 +19,13 @@ const sections = ['dependencies', 'devDependencies', 'optionalDependencies', 'pe
19
19
  const ignored = new Set(['node_modules', 'vendor', 'dist', 'build', 'coverage', 'venv',
20
20
  'test', 'tests', '__tests__', 'fixtures', 'tmp', 'scratch', 'scaffold', 'memory-derived']);
21
21
  const canonical = key => key === '@ssss/cli' ? '@gregiteen/ssss-cli' : key;
22
+ // Plugins also force the engine alias through `overrides`. Those pins move with the dependency,
23
+ // or a consumer ends up asking for two versions of the same package.
24
+ const overrideKeys = pkg => Object.entries(pkg.overrides || {})
25
+ .filter(([key, spec]) => typeof spec === 'string' && BRAIN_PACKAGES.includes(canonical(key)) && canonical(key) !== pkg.name)
26
+ .map(([key]) => key);
27
+ const overridesLag = (pkg, versions) => overrideKeys(pkg)
28
+ .some(key => versions[canonical(key)] && pkg.overrides[key] !== targetSpec(key, versions[canonical(key)]));
22
29
  const read = file => JSON.parse(fs.readFileSync(file, 'utf8'));
23
30
  const isLink = file => { try { return fs.lstatSync(file).isSymbolicLink(); } catch { return false; } };
24
31
  export const brainUpdateLockPath = owner => path.join(os.tmpdir(),
@@ -261,7 +268,7 @@ export async function updateAllBrains(opts = {}) {
261
268
  row.status = 'failed'; row.error = 'Newer local/preview package; refusing an implicit downgrade'; continue;
262
269
  }
263
270
  const shared = isLink(path.join(owner.owner, 'node_modules')) || isLink(path.join(consumer.root, 'node_modules'));
264
- const needsChange = shared || consumer.deps.some(dep => {
271
+ const needsChange = shared || (!consumer.runtimeOnly && overridesLag(consumer.pkg, versions)) || consumer.deps.some(dep => {
265
272
  const pinLags = !consumer.runtimeOnly && dep.declared !== targetSpec(dep.key, versions[dep.package]);
266
273
  if (absentDevDep(dep)) return pinLags;
267
274
  return pinLags || dep.version !== versions[dep.package]
@@ -296,6 +303,9 @@ export async function updateAllBrains(opts = {}) {
296
303
  saved.set(consumer.file, text);
297
304
  const pkg = read(consumer.file);
298
305
  for (const dep of consumer.deps) pkg[dep.section][dep.key] = targetSpec(dep.key, versions[dep.package]);
306
+ for (const key of overrideKeys(pkg)) {
307
+ if (versions[canonical(key)]) pkg.overrides[key] = targetSpec(key, versions[canonical(key)]);
308
+ }
299
309
  const indent = /\n([ \t]+)"/.exec(text)?.[1] || 2;
300
310
  fs.writeFileSync(consumer.file, JSON.stringify(pkg, null, indent) + '\n');
301
311
  }
@@ -62,6 +62,9 @@ export function compactRules(items, { budget, expand = [], header, complete = fa
62
62
  if (unknown.length) throw new Error(`Cannot expand rules not in this capsule: ${unknown.join(', ')}`);
63
63
  const duplicateOf = findDuplicates(ranked.filter(item => !expand.includes(item.slug)));
64
64
  const tiers = new Map(ranked.map(item => [item.slug, 'omitted']));
65
+ const isEvidence = item => item.taskEvidence && !item.required;
66
+ const supplement = supplemental.filter(item => item.text && !isEvidence(item)).map(item => item.text.trim());
67
+ const evidence = supplemental.filter(item => item.text && isEvidence(item)).map(item => item.text.trim()).join('\n\n---\n\n');
65
68
 
66
69
  const render = () => {
67
70
  const of = tier => ranked.filter(item => tiers.get(item.slug) === tier);
@@ -71,10 +74,11 @@ export function compactRules(items, { budget, expand = [], header, complete = fa
71
74
  const blocks = [
72
75
  ...full.map(item => item.text.trim()),
73
76
  ...summary.map(item => `[${item.slug}] ${summarizeRule(item.body)}`),
74
- ...supplemental.filter(item => item.text).map(item => item.text.trim()),
77
+ ...supplement,
75
78
  ];
76
79
  if (reference.length) blocks.push(`Referenced: ${reference.map(item => item.slug).join(', ')}`);
77
80
  if (duplicate.length) blocks.push(`Duplicates: ${duplicate.map(item => `${item.slug} (of ${duplicateOf.get(item.slug)})`).join(', ')}`);
81
+ if (evidence) blocks.push(evidence);
78
82
  const body = blocks.join('\n\n---\n\n');
79
83
  // The token count sits inside the text it counts, so iterate to a stable value.
80
84
  let tokens = estimateTokens(body);
@@ -142,5 +146,6 @@ export function compactRules(items, { budget, expand = [], header, complete = fa
142
146
  for (const slug of duplicateOf.keys()) tryTier(ranked.find(item => item.slug === slug), 'duplicate');
143
147
 
144
148
  const { context, counts, tokens } = render();
145
- return { context, counts, tokens, tiers: Object.fromEntries(tiers) };
149
+ return { context, counts, tokens, tiers: Object.fromEntries(tiers),
150
+ ...(evidence && { evidenceStart: context.length - evidence.length }) };
146
151
  }
@@ -109,7 +109,10 @@ export async function compileContext({
109
109
  }
110
110
 
111
111
  const cliContributions = cliVerbContribution ? [cliVerbContribution] : [];
112
- const supporting = [...knowledge.contributions, ...cliContributions];
112
+ const evidence = knowledge.summary.selected
113
+ ? knowledge.contributions.map(item => ({ ...item, taskEvidence: true }))
114
+ : knowledge.contributions;
115
+ const supporting = [...evidence, ...cliContributions];
113
116
  const result = assembleContext([...required, ...supporting, ...contributions], { total: b.total });
114
117
  const evidenceMissing = supporting.some(item => !result.stats.contributions.some(placed => placed.id === item.id));
115
118
  // Compaction may reclaim rule explanation space; never claim readiness after losing selected task evidence.
@@ -163,6 +166,8 @@ export function capsuleResponse(result, { total = 4000, debug = false, format =
163
166
  retrieval: summarizeRetrieval(result.stats.retrieval),
164
167
  };
165
168
  const response = { ready: result.ready, context: result.context, stats };
169
+ // This offset refers to the decoded context string, not the escaped JSON bytes.
170
+ if (result.evidenceStart !== undefined) response.evidence_start = result.evidenceStart;
166
171
  stats.budget = total;
167
172
  // Counts affect serialization themselves. Iterate to a stable representation.
168
173
  for (let i = 0; i < 20; i++) {
@@ -100,14 +100,18 @@ export function assembleContext(contributions, { total = 4000 } = {}) {
100
100
  if (estimateTokens(render([...selected, item])) <= total) selected.push(item);
101
101
  else excluded.push(item.id);
102
102
  }
103
- const context = render(selected);
103
+ const isEvidence = item => item.taskEvidence && !item.required;
104
+ const evidence = selected.filter(isEvidence);
105
+ const ordered = [...selected.filter(item => !isEvidence(item)), ...evidence];
106
+ const context = render(ordered);
107
+ const evidenceText = render(evidence);
104
108
  const totalTokens = estimateTokens(context);
105
- return { context, ready: requiredTokens <= total, stats: {
109
+ return { context, ...(evidenceText && { evidenceStart: context.length - evidenceText.length }), ready: requiredTokens <= total, stats: {
106
110
  token_measurement: 'estimated_chars_divided_by_four', total_tokens: totalTokens,
107
111
  budget_used: totalTokens, budget_remaining: Math.max(0, total - totalTokens),
108
112
  required_tokens: requiredTokens, overflow_tokens: Math.max(0, requiredTokens - total),
109
113
  required_ids: required.map(c => c.id), excluded_ids: excluded,
110
- contributions: selected.map(c => ({ id: c.id, required: Boolean(c.required), chars: c.text.length, estimated_tokens: estimateTokens(c.text) })),
114
+ contributions: ordered.map(c => ({ id: c.id, required: Boolean(c.required), chars: c.text.length, estimated_tokens: estimateTokens(c.text) })),
111
115
  version: crypto.createHash('sha256').update(JSON.stringify({ total, contributions })).digest('hex'),
112
116
  } };
113
117
  }
@@ -37,6 +37,28 @@ export function getDaemonStatus() {
37
37
  return status === 'not-started' ? 'not_started' : status === 'stopped' ? 'dead' : status;
38
38
  }
39
39
 
40
+ /**
41
+ * Remove the lock of a daemon that is gone, for a server told to run none.
42
+ *
43
+ * startDaemon is the only other thing that recovers this lock, and such a server never
44
+ * calls it. A daemon that went down with the machine left a lock nothing would ever
45
+ * clear, so the server reported `dead` and `degraded` for good. Only a lock whose process
46
+ * is verified gone is removed: a live process or one that cannot be identified keeps it.
47
+ * @returns {boolean} True if a lock was removed.
48
+ */
49
+ export function clearStaleDaemonLock({ observe = getDaemonObservation } = {}) {
50
+ try {
51
+ const before = fs.readFileSync(PID_FILE, 'utf8');
52
+ if (observe().status !== 'stopped') return false;
53
+ if (fs.readFileSync(PID_FILE, 'utf8') !== before) return false;
54
+ fs.unlinkSync(PID_FILE);
55
+ logger.info('daemon-control', `Removed the lock of daemon PID ${before.trim()}, which is gone. This server runs no daemon.`);
56
+ return true;
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+
40
62
  /**
41
63
  * Detaches the daemon script in the background and writes its PID to file.
42
64
  * @returns {number} The PID of the newly spawned daemon.
@@ -55,5 +55,5 @@ export function updateGlobalBrainPackages({versions,exec=spawnSync,sourceUpdate=
55
55
  if(row.status==='failed')row.error=result.error?.message || result.stderr?.slice(-1000) || 'Global version verification failed';
56
56
  }
57
57
  }
58
- return {failed:results.filter(row=>row.status==='failed').length,results};
58
+ return {failed:results.filter(row=>row.status==='failed').length,results,root};
59
59
  }
@@ -30,7 +30,8 @@ export async function updateMeshBrainPackages({version,versions,listNodes,exec,n
30
30
  let report,serving;try{const status=JSON.parse(observed.stdout);report=status.last;serving=status.server;}catch{}
31
31
  const localFailed=report?(report.local_failed ?? Math.max(0,(report.failed || 0)-(report.mesh?.failed || 0))):null;
32
32
  const current=observed.success && report && localFailed===0 && now()>=report.checkedAt && now()-report.checkedAt<2*60*60*1000 && report.versions?.['total-recall-brain']===version && (!versions?.['@gregiteen/ssss-cli'] || report.versions?.['@gregiteen/ssss-cli']===versions['@gregiteen/ssss-cli']);
33
- // Maintenance cannot fix a lagging server, so this is reported and not dispatched again.
33
+ // Maintenance could not fix this server, or it would have reported a local failure above and
34
+ // been dispatched again, so this is reported. One that lags since the last run waits for that run's report to age.
34
35
  if(current && serving?.status==='stale'){row.status='failed';row.report=report;row.server=serving;row.error=serving.reason;continue;}
35
36
  if(current){row.status='verified';row.report=report;continue;}
36
37
  // npm exec pins the verified release so an old installed CLI can bootstrap