total-recall-brain 3.41.2 → 3.41.4

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 (128) hide show
  1. package/bin/total-recall.mjs +19 -4
  2. package/frontend/dist/assets/{index-BG9NkVUy.css → index-BIQmqDKP.css} +1 -1
  3. package/frontend/dist/assets/{index-BtuiZqwP.js → index-CRzjQLu7.js} +7 -7
  4. package/frontend/dist/index.html +2 -2
  5. package/frontend/dist/sw.js +8 -5
  6. package/frontend/src/api/auth.ts +0 -3
  7. package/frontend/src/components/plugins/PluginPanel.tsx +7 -3
  8. package/frontend/src/components/plugins/card/CardEngine.tsx +1 -1
  9. package/frontend/src/pages/LoginPage.tsx +1 -41
  10. package/frontend/src/pages/PluginsPage.tsx +14 -7
  11. package/package.json +7 -5
  12. package/scaffold/.agent/skills/plugin/scripts/record.mjs +6 -3
  13. package/scaffold/.agent/skills/total-recall/plugins/auth/cli.mjs +197 -31
  14. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +6 -6
  15. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +1 -1
  16. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +8 -1
  17. package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +48 -0
  18. package/scaffold/.agent/skills/total-recall/plugins/auth/src/login-projections.mjs +42 -0
  19. package/scaffold/.agent/skills/total-recall/plugins/auth/src/mesh-secrets.mjs +18 -0
  20. package/scaffold/.agent/skills/total-recall/plugins/auth/src/routes/secrets.mjs +5 -2
  21. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-carriers.mjs +76 -0
  22. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-prune.mjs +37 -0
  23. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-sync.mjs +53 -17
  24. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/DESIGN.md +56 -8
  25. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/card.js +1068 -204
  26. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/panel.js +4 -2
  27. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +32 -0
  28. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +436 -274
  29. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +12 -12
  30. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +1 -1
  31. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/DESIGN.md +16 -2
  32. package/scaffold/.agent/skills/total-recall/plugins/code-quality/ui/card.js +461 -242
  33. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +12 -12
  34. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
  35. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +1 -7
  36. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/DESIGN.md +17 -2
  37. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/ui/card.js +426 -300
  38. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +23 -8
  39. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +6 -2
  40. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/DESIGN.md +32 -0
  41. package/scaffold/.agent/skills/total-recall/plugins/embeddings/ui/card.js +350 -283
  42. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +23 -8
  43. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +5 -1
  44. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/ui/card.js +31 -19
  45. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +23 -10
  46. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +5 -3
  47. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +1 -1
  48. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/grants.mjs +7 -3
  49. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +61 -38
  50. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/leader-election.mjs +57 -2
  51. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +220 -36
  52. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/server/routes/mesh.mjs +7 -2
  53. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +65 -0
  54. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/BRICK.md +59 -0
  55. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +534 -0
  56. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +139 -0
  57. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +2849 -0
  58. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +26 -0
  59. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +376 -0
  60. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +37 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/adapters/dsh.mjs +446 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +23 -0
  63. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +398 -0
  64. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +152 -0
  65. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +82 -0
  66. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +90 -0
  67. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +415 -0
  68. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +36 -0
  69. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/setup.mjs +35 -0
  70. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/tracker.mjs +133 -0
  71. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +233 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +32 -0
  73. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +845 -0
  74. package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/BRICK.md +64 -0
  75. package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/index.mjs +250 -0
  76. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +344 -14
  77. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +2917 -140
  78. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +9 -3
  79. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +223 -5
  80. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +129 -0
  81. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +355 -0
  82. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +375 -0
  83. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +37 -10
  84. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +986 -280
  85. package/scaffold/.agent/skills/total-recall/plugins/security/cli.mjs +7 -1
  86. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +25 -10
  87. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +6 -2
  88. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +1 -1
  89. package/scaffold/.agent/skills/total-recall/plugins/security/src/scanner.mjs +17 -3
  90. package/scaffold/.agent/skills/total-recall/plugins/security/ui/DESIGN.md +38 -15
  91. package/scaffold/.agent/skills/total-recall/plugins/security/ui/card.js +60 -34
  92. package/src/cli/command.mjs +23 -18
  93. package/src/cli/config.mjs +3 -0
  94. package/src/cli/connect.mjs +12 -116
  95. package/src/cli/daemon.mjs +23 -1
  96. package/src/cli/harness.mjs +0 -1
  97. package/src/cli/plugin/copies.mjs +8 -5
  98. package/src/cli/plugin/create.mjs +56 -3
  99. package/src/cli/plugin/index.mjs +40 -5
  100. package/src/cli/plugin/monetization.mjs +232 -12
  101. package/src/cli/preflight.mjs +161 -0
  102. package/src/cli/rebuild.mjs +22 -0
  103. package/src/cli/reset-password.mjs +3 -2
  104. package/src/cli/skill.mjs +8 -2
  105. package/src/cli/status.mjs +25 -7
  106. package/src/core/automatic-brain-updates.mjs +9 -3
  107. package/src/core/brain-updates.mjs +63 -5
  108. package/src/core/cli-commands.mjs +2 -0
  109. package/src/core/context-compiler.mjs +8 -1
  110. package/src/core/default-plugins.mjs +1 -1
  111. package/src/core/global-brain-updates.mjs +21 -1
  112. package/src/core/mesh-brain-updates.mjs +5 -2
  113. package/src/core/meta-harness.mjs +32 -79
  114. package/src/core/plugin-dependencies.mjs +6 -1
  115. package/src/core/plugin-runner.mjs +6 -1
  116. package/src/core/plugin-store.mjs +67 -1
  117. package/src/core/plugin-updates.mjs +1 -1
  118. package/src/core/portable-skills-maintenance.mjs +19 -0
  119. package/src/core/preflight-gate.mjs +77 -0
  120. package/src/core/preflight-receipt.mjs +123 -0
  121. package/src/core/required-plugins.mjs +7 -0
  122. package/src/core/runtime.mjs +0 -3
  123. package/src/core/skills-registry.mjs +33 -3
  124. package/src/core/surface.mjs +38 -1
  125. package/src/server/auth.mjs +41 -1
  126. package/src/server/memory-app.mjs +2 -1
  127. package/src/server/routes/auth.mjs +25 -1
  128. package/src/server/routes/plugins.mjs +17 -4
@@ -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
- if (opts.client === 'gemini') {
971
- const slashResults = writeGeminiSlashCommands(opts);
972
- result.slash_commands = slashResults;
973
- const created = slashResults.filter(r => r.action !== 'exists');
974
- if (created.length > 0) {
975
- result.notes.push(` Slash commands written to ~/.gemini/commands/ and .gemini/commands/:\n` +
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
 
@@ -218,7 +218,29 @@ export default async function daemon(args) {
218
218
 
219
219
  switch (subcommand) {
220
220
  case 'ensure': {
221
- if(!useSystemd)throw new Error('Managed daemon ensure currently requires systemd on the daemon host');
221
+ if(useLaunchd){
222
+ // macOS: the launchd agent owns the daemon. Load it if needed, restart it
223
+ // on --restart (or start it when nothing runs), then verify the process
224
+ // launchd reports is the one holding the brain lock.
225
+ const label='com.totalrecall.daemon',target=`gui/${process.getuid()}/${label}`;
226
+ const launchdPid=()=>{const r=spawnSync('launchctl',['list',label],{encoding:'utf8'});const m=r.status===0&&/"PID"\s*=\s*(\d+)/.exec(r.stdout||'');return m?Number(m[1]):0;};
227
+ if(spawnSync('launchctl',['list',label],{stdio:'ignore'}).status!==0){
228
+ const boot=spawnSync('launchctl',['bootstrap',`gui/${process.getuid()}`,launchAgentPlist(label)],{encoding:'utf8'});
229
+ if(boot.status!==0)throw new Error(`Cannot load ${label}: ${(boot.stderr||'').trim()}`);
230
+ }
231
+ const owner=readPid(),managedPid=launchdPid();
232
+ if(owner && owner!==managedPid && !await stopDaemon())throw new Error('Cannot stop verified detached daemon');
233
+ if(args.includes('--restart') || !managedPid || (owner && owner!==managedPid)){
234
+ const kick=spawnSync('launchctl',['kickstart','-k',target],{encoding:'utf8'});
235
+ if(kick.status!==0)throw new Error(`launchctl kickstart failed: ${(kick.stderr||'').trim()}`);
236
+ }
237
+ await new Promise(resolve=>setTimeout(resolve,3000));
238
+ const pid=readPid(),current=launchdPid();
239
+ if(!pid || pid!==current)throw new Error('Managed daemon did not retain ownership of the brain lock');
240
+ console.log(JSON.stringify({ok:true,manager:'launchd',pid,enabled:true}));
241
+ break;
242
+ }
243
+ if(!useSystemd)throw new Error('Managed daemon ensure needs systemd or a launchd agent on the daemon host');
222
244
  // A detached worker can hold the same brain lock while systemd reports a
223
245
  // successful short-lived start. Stop that verified owner before takeover.
224
246
  const managed=spawnSync('systemctl',['show','total-recall-daemon','--property=MainPID','--value'],{encoding:'utf8'});
@@ -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)
@@ -17,8 +17,9 @@ export function pluginCopyRows(projectRoot = process.cwd(), { sharedDir = global
17
17
  root: projectRoot,
18
18
  sharedDir,
19
19
  count: audit.count,
20
- removable: audit.copies.filter(copy => copy.edited === false).map(copy => copy.id),
21
- edited: audit.copies.filter(copy => copy.edited === true).map(copy => copy.id),
20
+ removable: audit.copies.filter(copy => copy.edited === false || copy.stale === true).map(copy => copy.id),
21
+ edited: audit.copies.filter(copy => copy.edited === true && copy.stale !== true).map(copy => copy.id),
22
+ stale: audit.copies.filter(copy => copy.stale === true).map(copy => copy.id),
22
23
  unverified: audit.copies.filter(copy => copy.edited === null).map(copy => copy.id),
23
24
  copies: audit.copies
24
25
  };
@@ -58,11 +59,13 @@ export async function manageProjectPluginCopies(args = []) {
58
59
  return;
59
60
  }
60
61
  for (const copy of report.copies) {
61
- const verdict = copy.edited === false ? 'identical to the shared install' : copy.edited === true ? 'DIFFERS from the shared install' : 'no shared install to compare';
62
+ const verdict = copy.stale === true ? 'STALE — older than the shared install; it shadows the shared plugin and must be removed'
63
+ : copy.edited === false ? 'identical to the shared install'
64
+ : copy.edited === true ? 'DIFFERS from the shared install' : 'no shared install to compare';
62
65
  console.log(` ${copy.id} v${copy.version || '?'} (shared: v${copy.sharedVersion || '—'}) — ${verdict}`);
63
66
  }
64
- console.log(`\n ${report.removable.length} removable, ${report.edited.length} edited, ${report.unverified.length} unverified`);
67
+ console.log(`\n ${report.removable.length} removable (${report.stale.length} stale), ${report.edited.length} edited, ${report.unverified.length} unverified`);
65
68
  if (report.removal) console.log(` Removed: ${report.removal.removed.join(', ') || 'none'}${report.removal.failed.length ? `; failed: ${report.removal.failed.map(row => row.id).join(', ')}` : ''}`);
66
- else if (report.removable.length) console.log(' Re-run with --apply to remove the identical copies.');
69
+ else if (report.removable.length) console.log(' Re-run with --apply to remove the removable copies.');
67
70
  console.log();
68
71
  }
@@ -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: { test: 'node --test test/*.test.mjs' },
494
- devDependencies: { 'total-recall-brain': '^3.35.0' },
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\nGEMINI.md\n', 'utf8');
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';
@@ -5,9 +5,9 @@ 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';
9
- import { getPlugin, getPluginMonetization } from '../../core/plugin-loader.mjs';
10
- import { describePlugin } from '../../core/plugin-store.mjs';
8
+ import { managePluginLicense, monetizePlugin, publishPluginToStore } from './monetization.mjs';
9
+ import { getPlugin, getPluginMonetization, globalPluginsDir, projectPluginsDir } from '../../core/plugin-loader.mjs';
10
+ import { describePlugin, pruneReplacementArchives, replacementArchiveDir } from '../../core/plugin-store.mjs';
11
11
  import { buildPluginCatalog } from '../../core/plugin-catalog.mjs';
12
12
  import { setPluginActive } from '../../core/plugin-activation.mjs';
13
13
 
@@ -29,6 +29,10 @@ Commands:
29
29
  refresh Rebuild installed command inventories and instruction surfaces
30
30
  copies [dir] [--apply] Audit this repository's leftover copies of the shared default
31
31
  plugins; --apply removes only the ones identical to the shared install
32
+ replacements [--prune] [--keep N] [--project] [--json]
33
+ Copies kept by install --replace (default: shared folder). Reports
34
+ the space; --prune keeps the newest N per plugin (default 1) and
35
+ drops node_modules from the kept ones
32
36
  on <id> / off <id> Enable/disable host execution for this repository alone
33
37
  --all-repos Change the shared setting for every repository
34
38
  --clear Drop this repository's override; follow the shared setting
@@ -51,8 +55,10 @@ Commands:
51
55
  in 'update --automatic')
52
56
  share <id> Offer an installed plugin by direct link and mesh
53
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
54
60
  remove <id> Uninstall (--global for the machine-wide copy)
55
- license <id> [cmd] Check or activate plugin license (status, activate, verify)
61
+ license <id> [cmd] Check or activate plugin license (status, activate, checkout, verify)
56
62
  info <id> Manifest, provenance, hash and task history
57
63
  vendor <source> [dir] Add a plugin to this project as a brick (default bricks/<id>); the
58
64
  project then owns the code. <source>: bundled id, git URL or path.
@@ -136,6 +142,25 @@ export async function run(argv = []) {
136
142
  return;
137
143
  }
138
144
 
145
+ if (command === 'replacements') {
146
+ const keepAt = rest.indexOf('--keep');
147
+ const keep = keepAt === -1 ? 1 : Number(rest[keepAt + 1]);
148
+ if (!Number.isInteger(keep) || keep < 0) {
149
+ console.error('Usage: total-recall plugin replacements [--prune] [--keep N] [--project] [--json]');
150
+ process.exitCode = 1;
151
+ return;
152
+ }
153
+ const dir = replacementArchiveDir(rest.includes('--project') ? projectPluginsDir(process.cwd()) : globalPluginsDir());
154
+ const apply = rest.includes('--prune');
155
+ const r = pruneReplacementArchives(dir, { keep, apply });
156
+ if (rest.includes('--json')) { console.log(JSON.stringify({ ...r, applied: apply }, null, 2)); return; }
157
+ const gb = (r.bytesFreed / 1073741824).toFixed(2);
158
+ console.log(`\n ${r.archiveDir}`);
159
+ console.log(` ${r.kept.length + r.removed.length} retained cop${r.kept.length + r.removed.length === 1 ? 'y' : 'ies'}; keeping ${r.kept.length}, ${apply ? 'removed' : 'would remove'} ${r.removed.length}, ${apply ? 'stripped' : 'would strip'} node_modules from ${r.stripped.length}`);
160
+ console.log(` ${apply ? 'Freed' : 'Would free'} ${gb} GB${apply ? '' : ' — run with --prune to apply'}\n`);
161
+ return;
162
+ }
163
+
139
164
  if (command === 'copies' || command === 'duplicates') {
140
165
  await manageProjectPluginCopies(rest);
141
166
  return;
@@ -221,7 +246,17 @@ export async function run(argv = []) {
221
246
  return;
222
247
  }
223
248
 
224
- if (command === 'license' || command === 'lic' || command === 'monetize') {
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') {
225
260
  await managePluginLicense(rest);
226
261
  return;
227
262
  }