total-recall-brain 3.41.3 → 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 (80) hide show
  1. package/bin/total-recall.mjs +10 -1
  2. package/frontend/dist/assets/{index-DFenQQEQ.js → index-CRzjQLu7.js} +77 -72
  3. package/frontend/dist/index.html +1 -1
  4. package/package.json +7 -5
  5. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +2 -2
  6. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +1 -1
  7. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +1 -1
  8. package/scaffold/.agent/skills/total-recall/plugins/auth/src/cli-secret.mjs +48 -0
  9. package/scaffold/.agent/skills/total-recall/plugins/auth/src/login-projections.mjs +42 -0
  10. package/scaffold/.agent/skills/total-recall/plugins/auth/src/mesh-secrets.mjs +18 -0
  11. package/scaffold/.agent/skills/total-recall/plugins/auth/src/routes/secrets.mjs +5 -2
  12. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-carriers.mjs +76 -0
  13. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-prune.mjs +37 -0
  14. package/scaffold/.agent/skills/total-recall/plugins/auth/src/secrets-sync.mjs +53 -17
  15. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +12 -12
  16. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +1 -1
  17. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +12 -12
  18. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
  19. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +23 -8
  20. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +6 -2
  21. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +23 -8
  22. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +5 -1
  23. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +23 -10
  24. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +5 -3
  25. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +1 -1
  26. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/grants.mjs +7 -3
  27. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/cli/mesh.mjs +61 -38
  28. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/leader-election.mjs +57 -2
  29. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +220 -36
  30. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/server/routes/mesh.mjs +7 -2
  31. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/README.md +65 -0
  32. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/BRICK.md +59 -0
  33. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +534 -0
  34. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +139 -0
  35. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +2849 -0
  36. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +26 -0
  37. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +376 -0
  38. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +37 -0
  39. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/adapters/dsh.mjs +446 -0
  40. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +23 -0
  41. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +398 -0
  42. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +152 -0
  43. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +82 -0
  44. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +90 -0
  45. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +415 -0
  46. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +36 -0
  47. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/setup.mjs +35 -0
  48. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/tracker.mjs +133 -0
  49. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +233 -0
  50. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/DESIGN.md +32 -0
  51. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +845 -0
  52. package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/BRICK.md +64 -0
  53. package/scaffold/.agent/skills/total-recall/plugins/openwiki/capability/index.mjs +250 -0
  54. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +344 -14
  55. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +2917 -140
  56. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +9 -3
  57. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +223 -5
  58. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +129 -0
  59. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +355 -0
  60. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +375 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/DESIGN.md +35 -22
  62. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +947 -323
  63. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +23 -8
  64. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +5 -1
  65. package/src/cli/config.mjs +3 -0
  66. package/src/cli/connect.mjs +12 -116
  67. package/src/cli/harness.mjs +0 -1
  68. package/src/cli/plugin/create.mjs +56 -3
  69. package/src/cli/plugin/index.mjs +15 -3
  70. package/src/cli/plugin/monetization.mjs +232 -12
  71. package/src/cli/preflight.mjs +161 -0
  72. package/src/core/cli-commands.mjs +2 -0
  73. package/src/core/context-compiler.mjs +8 -1
  74. package/src/core/default-plugins.mjs +1 -1
  75. package/src/core/meta-harness.mjs +16 -38
  76. package/src/core/plugin-dependencies.mjs +6 -1
  77. package/src/core/preflight-gate.mjs +77 -0
  78. package/src/core/preflight-receipt.mjs +123 -0
  79. package/src/core/runtime.mjs +0 -3
  80. package/src/core/surface.mjs +38 -1
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Harness-neutral gate decision. Every harness adapter normalises its native
3
+ * hook payload into `{ tool, command, path, cwd }` and asks `decide`; the answer
4
+ * is the same in every harness.
5
+ *
6
+ * Rules, in order:
7
+ * 1. Tools that only display or discover (`meta`, `ui`) are always open.
8
+ * 2. Reads of skill files are open: reading them is how the preflight is earned.
9
+ * 3. A single plain Total Recall preflight, context, recall or help command is
10
+ * open, so the gate can always be satisfied or repaired. Chaining, piping,
11
+ * substitution and redirects are not plain, so the exemption cannot carry
12
+ * other work and a capsule cannot be truncated through a pipe.
13
+ * 4. Everything else needs a fresh receipt for the directory.
14
+ * 5. With a receipt, a repository-wide source sweep still needs a recent
15
+ * Total Recall consult (the rule DSH enforced alone until now).
16
+ * Any error inside the gate denies: most harnesses fail open when a hook crashes.
17
+ */
18
+ import { ACK_COMMAND } from './preflight-receipt.mjs';
19
+
20
+ export const TOOL_CLASSES = ['shell', 'read', 'write', 'search', 'web', 'mcp', 'agent', 'meta', 'ui', 'other'];
21
+ export const SWEEP_CONSULT_MS = 15 * 60 * 1000;
22
+
23
+ const SKILL_PATH = /\/\.(agent|claude)\/skills\//;
24
+ const SATISFYING = /^(cd\s+\S+\s*&&\s*)?(npx\s+)?(total-recall|node\s+\S*bin\/total-recall\.mjs)\s+(tr-preflight|preflight|context|recall|help|--help)(\s+[^;&|`<>$\n]*)?$/;
25
+
26
+ /** True when the whole command is one plain Total Recall invocation that satisfies or repairs the gate. */
27
+ export function isSatisfyingCommand(command) {
28
+ return SATISFYING.test(String(command || '').trim());
29
+ }
30
+
31
+ /** A repository-wide search used to answer a question, as the DSH `tr-first.sh` rule defined it. */
32
+ export function isRepoSweep(command) {
33
+ const c = String(command || '');
34
+ if (c.includes('total-recall')) return false;
35
+ const sweep = /(^|[\s;&|(])(rg|ripgrep|ag)\s/.test(c)
36
+ || /(^|[\s;&|(])grep\s+(-[A-Za-z]*[rR][A-Za-z]*|--recursive)(\s|$)/.test(c)
37
+ || /(^|[\s;&|(])find\s+(\.|\/Users)/.test(c)
38
+ || /(^|[\s;&|(])git\s+grep(\s|$)/.test(c);
39
+ if (!sweep) return false;
40
+ if (/\|\s*(grep|rg|ag)(\s|$)/.test(c)) return false; // filtering command output is not a source question
41
+ if (/node_modules|\.agent\/skills|\/tmp\/|\.git\//.test(c)) return false;
42
+ return true;
43
+ }
44
+
45
+ const allow = (rule) => ({ decision: 'allow', rule });
46
+ const deny = (rule, reason, fix = ACK_COMMAND) => ({ decision: 'deny', rule, reason, fix });
47
+
48
+ /**
49
+ * @param {{ tool: string, command?: string, path?: string, cwd?: string }} call
50
+ * @param {{ check: () => { ok: boolean, problems: string[] }, recentConsult?: () => boolean, readablePaths?: RegExp[] }} deps
51
+ */
52
+ export function decide(call, deps) {
53
+ try {
54
+ const tool = TOOL_CLASSES.includes(call?.tool) ? call.tool : 'other';
55
+ if (tool === 'meta' || tool === 'ui') return allow(`class:${tool}`);
56
+ if (tool === 'read') {
57
+ const target = String(call.path || '');
58
+ if (SKILL_PATH.test(target)) return allow('read:skill-file');
59
+ // Persisted output of an allowed command is readable; each adapter names its host's paths (audit F-019).
60
+ if ((deps.readablePaths || []).some((re) => re.test(target))) return allow('read:persisted-output');
61
+ }
62
+ if (tool === 'shell' && isSatisfyingCommand(call.command)) return allow('shell:satisfying-command');
63
+
64
+ const receipt = deps.check();
65
+ if (!receipt.ok) {
66
+ return deny('receipt', `TR-PREFLIGHT gate: ${receipt.problems[0] || 'check failed'} (directory: ${call.cwd || 'unknown'}). `
67
+ + 'No work may start until it passes. Read the complete context capsule (never pipe or truncate it), then acknowledge.');
68
+ }
69
+ if (tool === 'shell' && isRepoSweep(call.command) && !(deps.recentConsult ? deps.recentConsult() : false)) {
70
+ return deny('sweep', 'TR-PREFLIGHT gate: do not sweep the repository for an answer; Total Recall owns it. Run `total-recall help "<task>"` to find the owning command, or `total-recall recall "<topic>" --local`, then repeat this call.',
71
+ 'total-recall help "<task>"');
72
+ }
73
+ return allow('receipt:fresh');
74
+ } catch (err) {
75
+ return deny('gate-error', `TR-PREFLIGHT gate error: ${err.message}. The gate fails closed.`);
76
+ }
77
+ }
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Preflight receipt: the attestation that an agent read the mandatory skills and
3
+ * received a ready capsule for one repository. It is an ephemeral per-machine
4
+ * file (mode 0600), not application state: every hook reads it on every tool
5
+ * call, so it stays a plain file. Gate decisions are what go to the event log.
6
+ *
7
+ * The file location and fields are unchanged from the original `tr-preflight`
8
+ * command, so receipts written before this module remain valid.
9
+ */
10
+ import crypto from 'node:crypto';
11
+ import fs from 'node:fs';
12
+ import os from 'node:os';
13
+ import path from 'node:path';
14
+ import { spawnSync } from 'node:child_process';
15
+ import { fileURLToPath } from 'node:url';
16
+
17
+ export const SKILLS = ['.agent/skills/total-recall/SKILL.md', '.agent/skills/ssss/SKILL.md'];
18
+ export const DEFAULT_MAX_AGE_MS = 30 * 60 * 1000;
19
+ export const ACK_COMMAND = 'total-recall tr-preflight --ack --task "<task>" --action read,edit,test';
20
+
21
+ const BIN = path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', 'bin', 'total-recall.mjs');
22
+
23
+ /**
24
+ * The nearest ancestor holding `.agent`, else the directory itself, with symlinks
25
+ * resolved. A harness may report a symlinked path (`/var` for `/private/var`)
26
+ * where the shell reports the real one; both must find the same receipt.
27
+ */
28
+ export function findRoot(cwd = process.cwd()) {
29
+ const resolve = (p) => { try { return fs.realpathSync(p); } catch { return path.resolve(p); } };
30
+ const start = resolve(cwd);
31
+ let dir = start;
32
+ for (let i = 0; i < 40; i += 1) {
33
+ if (fs.existsSync(path.join(dir, '.agent'))) return dir;
34
+ const parent = path.dirname(dir);
35
+ if (parent === dir) break;
36
+ dir = parent;
37
+ }
38
+ return start;
39
+ }
40
+
41
+ const rootKey = (root) => crypto.createHash('sha256').update(root).digest('hex').slice(0, 16);
42
+ const stateDir = (home) => path.join(home, '.agent', 'tr-preflight');
43
+ export const receiptPath = (root, home = os.homedir()) => path.join(stateDir(home), `${rootKey(root)}.json`);
44
+ export const consultPath = (root, home = os.homedir()) => path.join(stateDir(home), `consult-${rootKey(root)}.stamp`);
45
+
46
+ const sha256 = (file) => crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
47
+
48
+ /** Hashes of the mandatory skills, or the list of ones that are missing. */
49
+ export function skillHashes(root) {
50
+ const hashes = {};
51
+ const missing = [];
52
+ for (const rel of SKILLS) {
53
+ const full = path.join(root, rel);
54
+ if (fs.existsSync(full)) hashes[rel] = sha256(full);
55
+ else missing.push(rel);
56
+ }
57
+ return { hashes, missing };
58
+ }
59
+
60
+ export function readReceipt(root, home = os.homedir()) {
61
+ try { return JSON.parse(fs.readFileSync(receiptPath(root, home), 'utf8')); } catch { return null; }
62
+ }
63
+
64
+ /**
65
+ * @returns {{ ok: boolean, problems: string[], receipt: object|null, ageMs: number|null }}
66
+ * `problems` read the same as the original command so existing guidance still fits.
67
+ */
68
+ export function checkReceipt(root, { now = Date.now(), maxAgeMs, home = os.homedir() } = {}) {
69
+ const { hashes, missing } = skillHashes(root);
70
+ if (missing.length) return { ok: false, problems: missing.map((rel) => `missing mandatory skill: ${rel}`), receipt: null, ageMs: null };
71
+ const receipt = readReceipt(root, home);
72
+ if (!receipt) return { ok: false, problems: ['no preflight receipt for this repository'], receipt: null, ageMs: null };
73
+ const problems = [];
74
+ const ageMs = now - Date.parse(receipt.at || 0);
75
+ // The window is decided when the receipt is written, so the hot path never loads configuration.
76
+ const limit = maxAgeMs ?? (Number.isFinite(receipt.max_age_ms) && receipt.max_age_ms > 0 ? receipt.max_age_ms : DEFAULT_MAX_AGE_MS);
77
+ if (!Number.isFinite(ageMs) || ageMs > limit) problems.push('preflight receipt is stale; re-run --ack');
78
+ for (const [rel, hash] of Object.entries(hashes)) {
79
+ if (!receipt.skills || receipt.skills[rel] !== hash) problems.push(`${rel} changed since the receipt; re-read and re-run --ack`);
80
+ }
81
+ if (receipt.ready !== true) problems.push('receipt does not record ready:true');
82
+ return { ok: problems.length === 0, problems, receipt, ageMs: Number.isFinite(ageMs) ? ageMs : null };
83
+ }
84
+
85
+ /** Run this package's own CLI, so `ack` uses exactly the semantics every caller gets. */
86
+ function runSelf(args, cwd) {
87
+ const r = spawnSync(process.execPath, [BIN, ...args], { cwd, encoding: 'utf8', timeout: 60000 });
88
+ return { ok: r.status === 0, out: r.stdout || '', err: r.stderr || '', code: r.status };
89
+ }
90
+
91
+ /**
92
+ * Record a receipt after proving the capsule is ready and the rules verify.
93
+ * `run` is injectable so the specs need no child process.
94
+ */
95
+ export function acknowledge({ root, task = '', actions = 'read,edit,test', maxAgeMs, run = runSelf, now = Date.now(), home = os.homedir() }) {
96
+ const { hashes, missing } = skillHashes(root);
97
+ if (missing.length) return { ok: false, problems: missing.map((rel) => `missing mandatory skill: ${rel}`) };
98
+ const context = run(['context', task || '(no task given)', '--action', actions], root);
99
+ if (!/ready:true/.test(context.out)) {
100
+ return { ok: false, problems: ['total-recall context did not return ready:true',
101
+ context.code === 2 ? 'exit 2: capsule overflow; raise --budget or curate applicability, then retry' : `context exit=${context.code ?? '?'}`] };
102
+ }
103
+ const version = (context.out.match(/version:([0-9a-f]+)/) || [])[1] || null;
104
+ const rules = run(['rules', 'verify'], root);
105
+ if (!rules.ok) return { ok: false, problems: ['total-recall rules verify failed', (rules.out || rules.err).trim().split('\n').slice(-3).join(' | ')] };
106
+ const receipt = { at: new Date(now).toISOString(), repo: root, task, actions, ready: true, capsule_version: version, skills: hashes, rules_verify: 'ok',
107
+ ...(Number.isFinite(maxAgeMs) && maxAgeMs > 0 ? { max_age_ms: maxAgeMs } : {}) };
108
+ const file = receiptPath(root, home);
109
+ fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
110
+ fs.writeFileSync(file, `${JSON.stringify(receipt, null, 2)}\n`, { mode: 0o600 });
111
+ return { ok: true, problems: [], receipt, file };
112
+ }
113
+
114
+ /** Marks that Total Recall was consulted just now; read by the repository-sweep policy. */
115
+ export function touchConsult(root, { now = Date.now(), home = os.homedir() } = {}) {
116
+ const file = consultPath(root, home);
117
+ fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
118
+ fs.writeFileSync(file, String(now), { mode: 0o600 });
119
+ }
120
+
121
+ export function lastConsultMs(root, { home = os.homedir() } = {}) {
122
+ try { return Number(fs.readFileSync(consultPath(root, home), 'utf8')) || 0; } catch { return 0; }
123
+ }
@@ -162,10 +162,8 @@ export function loadRuntimeConfig(_configPath) {
162
162
  const checkPaths = [
163
163
  instructionsFilePath(),
164
164
  path.join(surfaceDir(), 'AGENTS.md'),
165
- path.join(surfaceDir(), 'GEMINI.md'),
166
165
  path.join(agentDir, 'INSTRUCTIONS.md'),
167
166
  path.join(agentDir, 'AGENTS.md'),
168
- path.join(agentDir, 'GEMINI.md'),
169
167
  path.join(path.dirname(agentDir), 'INSTRUCTIONS.md'),
170
168
  path.join(path.dirname(agentDir), 'AGENTS.md'),
171
169
  path.join(process.cwd(), 'INSTRUCTIONS.md'),
@@ -173,7 +171,6 @@ export function loadRuntimeConfig(_configPath) {
173
171
  path.join(process.cwd(), 'Claude.md'),
174
172
  // legacy mistaken brainDir locations (kept as last resort)
175
173
  path.join(brainDir, 'INSTRUCTIONS.md'),
176
- path.join(brainDir, 'GEMINI.md'),
177
174
  path.join(brainDir, 'AGENTS.md'),
178
175
  ];
179
176
  for (const p of checkPaths) {
@@ -500,6 +500,30 @@ async function writeShim(shimPath, skillsDir, nodes = [], { vaultDir, derivedDir
500
500
  const fullContent = prependDirectives(`${mdcHeader}${baseline}`, rulesBlock);
501
501
 
502
502
  try {
503
+ const normShim = path.normalize(shimPath);
504
+ // Antigravity rules deduplication: .agents/rules/AGENTS.md should be a relative
505
+ // symlink to ../../AGENTS.md so Antigravity resolves realpath and loads it once.
506
+ if (normShim.endsWith(path.normalize('.agents/rules/AGENTS.md'))) {
507
+ if (!fs.existsSync(shimDir)) {
508
+ fs.mkdirSync(shimDir, { recursive: true });
509
+ }
510
+ const relTarget = path.join('..', '..', 'AGENTS.md');
511
+ try {
512
+ const stat = fs.lstatSync(shimPath, { throwIfNoEntry: false });
513
+ if (stat) {
514
+ if (!stat.isSymbolicLink() || fs.readlinkSync(shimPath) !== relTarget) {
515
+ fs.unlinkSync(shimPath);
516
+ fs.symlinkSync(relTarget, shimPath);
517
+ }
518
+ } else {
519
+ fs.symlinkSync(relTarget, shimPath);
520
+ }
521
+ return true;
522
+ } catch {
523
+ // Fall through to regular write if symlink cannot be created
524
+ }
525
+ }
526
+
503
527
  const stat = fs.lstatSync(shimPath, { throwIfNoEntry: false });
504
528
  if (stat) {
505
529
  if (stat.isSymbolicLink()) {
@@ -552,7 +576,6 @@ const CLIENT_SHIMS = {
552
576
  roo: ['.roo/rules/total-recall.md', '.clinerules/total-recall.md'],
553
577
  'roo-code': ['.roo/rules/total-recall.md', '.clinerules/total-recall.md'],
554
578
  antigravity: ['AGENTS.md', '.agents/rules/AGENTS.md'],
555
- gemini: ['GEMINI.md', '.agents/rules/GEMINI.md'],
556
579
  codex: ['AGENTS.md'],
557
580
  grok: ['AGENTS.md'],
558
581
  replit: ['replit.md'],
@@ -647,6 +670,20 @@ async function compilePointers(instructionsFile, skillsDir, nodes = [], { vaultD
647
670
  // plugin-store.mjs likewise), so the peel was never correct for either.
648
671
  const baseDir = agentDir;
649
672
 
673
+ // Eradicate deprecated Gemini shims so they do not consume context budgets or inject obsolete rules
674
+ const deprecatedGeminiPaths = [
675
+ path.join(baseDir, 'GEMINI.md'),
676
+ path.join(baseDir, '.agent', 'GEMINI.md'),
677
+ path.join(baseDir, '.agents', 'rules', 'GEMINI.md')
678
+ ];
679
+ for (const depPath of deprecatedGeminiPaths) {
680
+ try {
681
+ if (fs.existsSync(depPath)) {
682
+ fs.unlinkSync(depPath);
683
+ }
684
+ } catch {}
685
+ }
686
+
650
687
  // Determine which client shims to write.
651
688
  // `baseDir/.agent/skills/...` only holds for a PROJECT brain. For the global
652
689
  // brain baseDir already IS the agent dir, so that path became