total-recall-brain 3.41.4 → 3.41.6

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 (147) hide show
  1. package/bin/total-recall.mjs +10 -6
  2. package/docs/reference/cli-reference.md +18 -0
  3. package/frontend/dist/assets/index-4tGQfTa2.js +5605 -0
  4. package/frontend/dist/assets/index-DtwsDyFM.css +1 -0
  5. package/frontend/dist/index.html +2 -2
  6. package/frontend/package.json +11 -0
  7. package/frontend/src/App.tsx +47 -122
  8. package/frontend/src/components/plugins/plugin-frame.ts +1 -0
  9. package/frontend/src/index.css +152 -86
  10. package/frontend/src/pages/HelpPage.tsx +13 -10
  11. package/frontend/src/pages/MemoryPage.tsx +28 -30
  12. package/frontend/src/pages/NetworkPage.tsx +3 -3
  13. package/frontend/src/pages/PluginsPage.tsx +6 -5
  14. package/frontend/src/pages/RulesPage.tsx +16 -12
  15. package/package.json +4 -3
  16. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +3114 -36
  17. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +4 -1
  18. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +3114 -36
  19. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +4 -1
  20. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +3121 -33
  21. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +4 -1
  22. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package-lock.json +3122 -34
  23. package/scaffold/.agent/skills/total-recall/plugins/git-sentinel/package.json +4 -1
  24. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +3127 -49
  25. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +5 -2
  26. package/scaffold/.agent/skills/total-recall/plugins/mesh/src/core/mesh.mjs +1 -1
  27. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/capability/index.mjs +136 -7
  28. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +135 -26
  29. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +3121 -33
  30. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +5 -2
  31. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +228 -9
  32. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/skills/meta-harness/SKILL.md +24 -30
  33. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/alerts.mjs +29 -16
  34. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +73 -0
  35. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +182 -365
  36. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +33 -0
  37. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/documentation.mjs +40 -14
  38. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/executor.mjs +4 -4
  39. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/agy.mjs +187 -0
  40. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/claude.mjs +275 -0
  41. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cline.mjs +132 -0
  42. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/codex.mjs +187 -0
  43. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/cursor.mjs +158 -0
  44. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/devin.mjs +157 -0
  45. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/dsh.mjs +183 -0
  46. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/grok.mjs +132 -0
  47. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/hermes.mjs +173 -0
  48. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/index.mjs +87 -0
  49. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/openclaw.mjs +173 -0
  50. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate-adapters/pi.mjs +129 -0
  51. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/gate.mjs +12 -0
  52. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/json-reply.mjs +22 -0
  53. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +72 -70
  54. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-catalog.mjs +195 -0
  55. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/paths.mjs +11 -0
  56. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +36 -0
  57. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/review.mjs +169 -0
  58. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +136 -346
  59. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/runtime.mjs +1 -1
  60. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/ssss-store.mjs +20 -0
  61. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/telemetry.mjs +43 -0
  62. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/threads.mjs +156 -0
  63. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +117 -35
  64. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worktree.mjs +51 -0
  65. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/card.js +398 -57
  66. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +304 -46
  67. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +367 -41
  68. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +5 -2
  69. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +33 -0
  70. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +2 -2
  71. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +159 -0
  72. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +197 -0
  73. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/lint.mjs +153 -0
  74. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +261 -0
  75. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +151 -4
  76. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +114 -0
  77. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/token.mjs +96 -0
  78. package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/card.js +899 -662
  79. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/openwiki.mjs +8987 -0
  80. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/mermaid-diagrams/SKILL.md +44 -0
  81. package/scaffold/.agent/skills/total-recall/plugins/openwiki/vendor/skills/write-connector/SKILL.md +56 -0
  82. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +3097 -81
  83. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +4 -1
  84. package/src/cli/agent.mjs +12 -1
  85. package/src/cli/compact.mjs +108 -0
  86. package/src/cli/connect.mjs +56 -1
  87. package/src/cli/context.mjs +55 -23
  88. package/src/cli/doctor.mjs +5 -2
  89. package/src/cli/forget.mjs +2 -0
  90. package/src/cli/harness.mjs +62 -50
  91. package/src/cli/memory-entry.mjs +2 -2
  92. package/src/cli/preflight.mjs +152 -16
  93. package/src/cli/release.mjs +386 -0
  94. package/src/cli/remember.mjs +19 -1
  95. package/src/cli/rules.mjs +54 -12
  96. package/src/cli/startup.mjs +1 -1
  97. package/src/cli/status.mjs +12 -2
  98. package/src/core/claude-hooks.mjs +41 -3
  99. package/src/core/cli-commands.mjs +2 -0
  100. package/src/core/cli-semantic-index.mjs +3 -2
  101. package/src/core/conflict-detector.mjs +23 -12
  102. package/src/core/context-compactor.mjs +145 -0
  103. package/src/core/context-policy.mjs +20 -0
  104. package/src/core/duplicate-guard.mjs +350 -0
  105. package/src/core/meta-harness.mjs +31 -11
  106. package/src/core/preflight-gate.mjs +2 -2
  107. package/src/core/preflight-receipt.mjs +29 -1
  108. package/src/core/scaffold-plugins.mjs +7 -0
  109. package/src/core/stdio-flush.mjs +23 -0
  110. package/src/core/surface.mjs +33 -10
  111. package/src/server/invoke-durability.mjs +39 -0
  112. package/src/server/invoke-write-child.mjs +25 -0
  113. package/src/server/routes/invoke.mjs +7 -0
  114. package/src/server/routes/plugins.mjs +2 -2
  115. package/frontend/dist/assets/index-BIQmqDKP.css +0 -1
  116. package/frontend/dist/assets/index-CRzjQLu7.js +0 -5631
  117. package/frontend/src/components/DaemonLogsTab.tsx +0 -54
  118. package/frontend/src/components/ResearchAgendaTab.tsx +0 -712
  119. package/frontend/src/components/TaskQueueTab.tsx +0 -193
  120. package/frontend/src/components/VoiceInput.tsx +0 -112
  121. package/frontend/src/pages/ChatPage.tsx +0 -1059
  122. package/frontend/src/pages/CollabPage.tsx +0 -470
  123. package/frontend/src/pages/DesignDocsPage.tsx +0 -621
  124. package/frontend/src/pages/FilesPage.tsx +0 -393
  125. package/frontend/src/pages/HealthPage.tsx +0 -359
  126. package/frontend/src/pages/InboxPage.tsx +0 -83
  127. package/frontend/src/pages/InstructionsPage.tsx +0 -583
  128. package/frontend/src/pages/IntegrationsPage.tsx +0 -761
  129. package/frontend/src/pages/MeshPage.css +0 -58
  130. package/frontend/src/pages/MeshPage.tsx +0 -1219
  131. package/frontend/src/pages/OkfPage.tsx +0 -535
  132. package/frontend/src/pages/SandboxPage.tsx +0 -113
  133. package/frontend/src/pages/SkillsPage.tsx +0 -1994
  134. package/frontend/src/pages/TasksPage.tsx +0 -427
  135. package/frontend/src/pages/UsagePage.tsx +0 -702
  136. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/README.md +0 -65
  137. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/cli.mjs +0 -76
  138. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/package.json +0 -19
  139. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/plugin.json +0 -266
  140. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/adapters/dsh.mjs +0 -446
  141. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/documentation.mjs +0 -152
  142. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/executor.mjs +0 -71
  143. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/runtime.mjs +0 -36
  144. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/setup.mjs +0 -35
  145. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/src/worker.mjs +0 -175
  146. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/DESIGN.md +0 -32
  147. package/scaffold/.agent/skills/total-recall/plugins/cli-agents/ui/card.js +0 -575
@@ -6,9 +6,15 @@
6
6
  import fs from "node:fs";
7
7
  import path from "node:path";
8
8
  import { runBootstrapCommand } from './src/bootstrap.mjs';
9
- import { describeRetention, hasWiki, isDue, readProjects, refreshProject, resolveKey, staleness } from './src/refresh.mjs';
9
+ import { describeRetention, hasWiki, isDue, readProjects, refreshProject, refreshProjectAsync, resolveKey, staleness } from './src/refresh.mjs';
10
10
  import { announceNewVersion, checkUpstreamStatus, propagateUpdates, readUpstreamState } from './src/upstream-watcher.mjs';
11
11
  import { loadOpenWikiConfig, setOpenWikiConfigValue, resetOpenWikiConfig, resolveConfigPath, ALLOWED_CONFIG_KEYS, ALLOWED_PROVIDERS } from './src/config.mjs';
12
+ import { discoverAllHubs } from './src/mesh-vaults.mjs';
13
+ import { searchWikiHubs } from './src/search.mjs';
14
+ import { buildKnowledgeGraph } from './src/graph.mjs';
15
+ import { getTokenStatus, setTokenValue } from './src/token.mjs';
16
+ import { lintWikiHubs } from './src/lint.mjs';
17
+ import { generateWiki } from './src/generate.mjs';
12
18
 
13
19
  /**
14
20
  * Regenerate the generated pages of every registered project that carries them.
@@ -55,7 +61,11 @@ async function refreshCommand(args) {
55
61
  continue;
56
62
  }
57
63
  if (!state.due) {
58
- reports.push({ ...project, action: 'current', generatedAt: state.generatedAt, commitsSince: state.commitsSince });
64
+ if (state.skipped) {
65
+ reports.push({ ...project, action: 'skipped', reason: state.reason });
66
+ } else {
67
+ reports.push({ ...project, action: 'current', generatedAt: state.generatedAt, commitsSince: state.commitsSince });
68
+ }
59
69
  continue;
60
70
  }
61
71
  reports.push({
@@ -81,24 +91,44 @@ async function refreshCommand(args) {
81
91
  process.exitCode = 1;
82
92
  return;
83
93
  }
84
- const RUNNER_BUDGET_MS = 600000;
85
- const REPORT_RESERVE_MS = 45000;
86
- const deadline = Date.now() + RUNNER_BUDGET_MS - REPORT_RESERVE_MS;
87
- let skippedForBudget = 0;
88
- for (const entry of due) {
89
- const remaining = deadline - Date.now();
90
- if (remaining < 60000) { skippedForBudget += 1; continue; }
91
- const result = refreshProject(
92
- { name: entry.name, root: entry.root },
93
- { key, model: config.model, provider: config.provider, timeoutMs: Math.min(remaining, config.timeout_ms) }
94
- );
95
- const index = reports.findIndex((r) => r.root === entry.root);
96
- reports[index] = { ...reports[index], ...result, credential: from };
97
- if (Date.now() >= deadline) { skippedForBudget += 1; }
98
- }
99
- if (skippedForBudget > 0) {
100
- payloadBudgetNote = `${skippedForBudget} project(s) left due: one regeneration can consume this command's 600 s runner budget; run again to continue.`;
94
+ const concurrencyArg = args.find((a) => a.startsWith('--concurrency='));
95
+ const concurrencyIndex = args.indexOf('--concurrency');
96
+ const concurrency = Math.max(1, parseInt(
97
+ concurrencyArg ? concurrencyArg.slice('--concurrency='.length) : (concurrencyIndex >= 0 ? args[concurrencyIndex + 1] : '8'),
98
+ 10
99
+ ) || 8);
100
+
101
+ if (!json) {
102
+ console.log(`OpenWiki refresh (apply): dispatching ${due.length} projects with concurrency ${concurrency}`);
101
103
  }
104
+
105
+ let queueIndex = 0;
106
+ let completedCount = 0;
107
+ const worker = async () => {
108
+ while (queueIndex < due.length) {
109
+ const itemIndex = queueIndex++;
110
+ const entry = due[itemIndex];
111
+ const mode = entry.uninitialized ? 'init' : 'update';
112
+ if (!json) {
113
+ console.log(`[${itemIndex + 1}/${due.length}] ▶ ${entry.name.padEnd(28)} starting ${mode}...`);
114
+ }
115
+ const result = await refreshProjectAsync(
116
+ { name: entry.name, root: entry.root },
117
+ { key, model: config.model, provider: config.provider, timeoutMs: config.timeout_ms }
118
+ );
119
+ completedCount++;
120
+ const index = reports.findIndex((r) => r.root === entry.root);
121
+ reports[index] = { ...reports[index], ...result, credential: from };
122
+ if (!json) {
123
+ const duration = Math.round((Date.now() - (result.startedAt || Date.now())) / 1000);
124
+ const icon = result.action === 'failed' ? '✖' : '✔';
125
+ console.log(`[${completedCount}/${due.length}] ${icon} ${entry.name.padEnd(28)} ${result.action} (${duration}s)${result.reason ? ` — ${result.reason}` : ''}`);
126
+ }
127
+ }
128
+ };
129
+
130
+ const workers = Array.from({ length: Math.min(concurrency, due.length) }, () => worker());
131
+ await Promise.all(workers);
102
132
  }
103
133
 
104
134
  const failed = reports.filter((r) => r.action === 'failed');
@@ -156,39 +186,241 @@ async function probeCommand(args) {
156
186
 
157
187
  async function hubsCommand(args) {
158
188
  const json = args.includes("--json");
159
- const targetDir = path.resolve(process.cwd(), "openwiki");
160
- const hubs = [];
161
-
162
- if (fs.existsSync(targetDir)) {
163
- const entries = fs.readdirSync(targetDir, { withFileTypes: true });
164
- for (const ent of entries) {
165
- if (ent.isFile() && ent.name.endsWith(".md")) {
166
- const fullPath = path.join(targetDir, ent.name);
167
- const content = fs.readFileSync(fullPath, "utf8");
168
- const titleMatch = content.match(/^#\s+(.+)$/m);
169
- const title = titleMatch ? titleMatch[1].trim() : ent.name.replace(/\.md$/, "");
170
- const lines = content.split("\n").length;
171
- hubs.push({
172
- title,
173
- path: path.relative(process.cwd(), fullPath),
174
- lines,
175
- size_bytes: content.length
176
- });
189
+ const allVaults = args.includes("--all-vaults") || args.includes("--all");
190
+ const nodeArg = args.find((a) => a.startsWith('--node='));
191
+ const nodeIndex = args.indexOf('--node');
192
+ const node = nodeArg
193
+ ? nodeArg.slice('--node='.length)
194
+ : (nodeIndex >= 0 && args[nodeIndex + 1] && !args[nodeIndex + 1].startsWith('--') ? args[nodeIndex + 1] : null);
195
+
196
+ try {
197
+ const res = await discoverAllHubs({ allVaults, node });
198
+ if (json) {
199
+ console.log(JSON.stringify(res, null, 2));
200
+ } else {
201
+ if (!res.hubs || res.hubs.length === 0) {
202
+ console.log(`No markdown hubs found (${res.scope || 'workspace'})`);
203
+ } else {
204
+ const prefix = res.isRemote ? `[Node ${res.node}] ` : '';
205
+ console.log(`${prefix}Discovered ${res.hubs.length} OpenWiki Hub(s) (${res.scope || 'workspace'}):`);
206
+ for (const h of res.hubs) {
207
+ const repoTag = h.repoName ? `[${h.repoName}] ` : '';
208
+ console.log(` - ${repoTag}${h.title}: ${h.path} (${h.lines} lines, ${h.size_bytes} bytes)`);
209
+ }
177
210
  }
178
211
  }
212
+ } catch (err) {
213
+ if (json) console.log(JSON.stringify({ ok: false, error: err.message }));
214
+ else console.error(`OpenWiki hubs error: ${err.message}`);
215
+ process.exitCode = 1;
179
216
  }
217
+ }
180
218
 
181
- if (json) {
182
- console.log(JSON.stringify({ hubs, count: hubs.length, directory: targetDir }));
183
- } else {
184
- if (hubs.length === 0) {
185
- console.log(`No markdown hubs found in ${targetDir}`);
219
+ async function searchCommand(args) {
220
+ const json = args.includes("--json");
221
+ const allVaults = args.includes("--all-vaults") || args.includes("--all");
222
+ const nodeArg = args.find((a) => a.startsWith('--node='));
223
+ const nodeIndex = args.indexOf('--node');
224
+ const node = nodeArg
225
+ ? nodeArg.slice('--node='.length)
226
+ : (nodeIndex >= 0 && args[nodeIndex + 1] && !args[nodeIndex + 1].startsWith('--') ? args[nodeIndex + 1] : null);
227
+
228
+ const limitArg = args.find((a) => a.startsWith('--limit='));
229
+ const limitIndex = args.indexOf('--limit');
230
+ const limit = limitArg
231
+ ? parseInt(limitArg.slice('--limit='.length), 10)
232
+ : (limitIndex >= 0 && args[limitIndex + 1] ? parseInt(args[limitIndex + 1], 10) : 20);
233
+
234
+ const queryTerms = args.filter((a, idx) => {
235
+ if (a.startsWith('--')) return false;
236
+ if (nodeIndex >= 0 && idx === nodeIndex + 1) return false;
237
+ if (limitIndex >= 0 && idx === limitIndex + 1) return false;
238
+ return true;
239
+ });
240
+ const query = queryTerms.join(' ').trim();
241
+
242
+ if (!query) {
243
+ if (json) console.log(JSON.stringify({ ok: false, error: 'Query argument required: openwiki search <query>' }));
244
+ else console.error('OpenWiki search error: query required. Usage: total-recall openwiki search <query> [--all-vaults] [--node <node>]');
245
+ process.exitCode = 1;
246
+ return;
247
+ }
248
+
249
+ try {
250
+ const res = await searchWikiHubs(query, { allVaults, node, limit });
251
+ if (json) {
252
+ console.log(JSON.stringify(res, null, 2));
186
253
  } else {
187
- console.log(`Discovered ${hubs.length} OpenWiki Hub(s) in ${targetDir}:`);
188
- for (const h of hubs) {
189
- console.log(` - ${h.title}: ${h.path} (${h.lines} lines, ${h.size_bytes} bytes)`);
254
+ console.log(`\nOpenWiki Evidence Search: "${query}" (${res.count} match${res.count === 1 ? '' : 'es'} across ${res.totalHubsScanned} hubs, ${res.scope})`);
255
+ if (res.results.length === 0) {
256
+ console.log(' No matching evidence passages found.\n');
257
+ } else {
258
+ for (const r of res.results) {
259
+ console.log(`\n • [${r.repoName}] ${r.title} > ${r.section} (line ${r.line}):`);
260
+ console.log(` "${r.snippet}"`);
261
+ }
262
+ console.log('');
190
263
  }
191
264
  }
265
+ } catch (err) {
266
+ if (json) console.log(JSON.stringify({ ok: false, error: err.message }));
267
+ else console.error(`OpenWiki search error: ${err.message}`);
268
+ process.exitCode = 1;
269
+ }
270
+ }
271
+
272
+ async function graphCommand(args) {
273
+ const json = args.includes("--json");
274
+ const allVaults = args.includes("--all-vaults") || args.includes("--all");
275
+ const nodeArg = args.find((a) => a.startsWith('--node='));
276
+ const nodeIndex = args.indexOf('--node');
277
+ const node = nodeArg
278
+ ? nodeArg.slice('--node='.length)
279
+ : (nodeIndex >= 0 && args[nodeIndex + 1] && !args[nodeIndex + 1].startsWith('--') ? args[nodeIndex + 1] : null);
280
+
281
+ const formatArg = args.find((a) => a.startsWith('--format='));
282
+ const formatIndex = args.indexOf('--format');
283
+ const format = formatArg
284
+ ? formatArg.slice('--format='.length)
285
+ : (formatIndex >= 0 && args[formatIndex + 1] ? args[formatIndex + 1] : (args.includes('--mermaid') ? 'mermaid' : (args.includes('--dot') ? 'dot' : 'json')));
286
+
287
+ try {
288
+ const res = await buildKnowledgeGraph({ allVaults, node, format });
289
+ if (json || format === 'json') {
290
+ console.log(JSON.stringify(res, null, 2));
291
+ } else if (format === 'mermaid') {
292
+ console.log(res.mermaid);
293
+ } else if (format === 'dot') {
294
+ console.log(res.dot);
295
+ }
296
+ } catch (err) {
297
+ if (json) console.log(JSON.stringify({ ok: false, error: err.message }));
298
+ else console.error(`OpenWiki graph error: ${err.message}`);
299
+ process.exitCode = 1;
300
+ }
301
+ }
302
+
303
+ async function tokenCommand(args) {
304
+ const json = args.includes("--json");
305
+ const verb = args.find((a) => !a.startsWith('--')) || 'status';
306
+
307
+ try {
308
+ if (verb === 'status') {
309
+ const res = getTokenStatus();
310
+ if (json) {
311
+ console.log(JSON.stringify(res, null, 2));
312
+ } else {
313
+ console.log('\nOpenWiki Token Status (Total Recall Auth Store):');
314
+ for (const [provider, t] of Object.entries(res.tokens)) {
315
+ const icon = t.configured ? '✔' : '✖';
316
+ console.log(` ${icon} ${provider.padEnd(12)} : ${t.key} (${t.status})`);
317
+ }
318
+ console.log('\nTo set a token: total-recall openwiki token set <openrouter|google> <key>');
319
+ console.log('Or via stdin: echo "$KEY" | total-recall openwiki token set <provider> --stdin\n');
320
+ }
321
+ return;
322
+ }
323
+
324
+ if (verb === 'set') {
325
+ const clean = args.filter((a) => !a.startsWith('--'));
326
+ const provider = clean[1];
327
+ let value = clean[2];
328
+ if (args.includes('--stdin')) {
329
+ value = fs.readFileSync(0, 'utf8').trim();
330
+ }
331
+ if (!provider || !value) {
332
+ throw new Error('Provider and secret value required: openwiki token set <provider> <value> (or --stdin)');
333
+ }
334
+ const res = setTokenValue(provider, value);
335
+ if (json) console.log(JSON.stringify(res, null, 2));
336
+ else console.log(`✔ ${res.message}`);
337
+ return;
338
+ }
339
+
340
+ throw new Error(`Unknown token action '${verb}'. Supported: status, set`);
341
+ } catch (err) {
342
+ if (json) console.log(JSON.stringify({ ok: false, error: err.message }));
343
+ else console.error(`OpenWiki token error: ${err.message}`);
344
+ process.exitCode = 1;
345
+ }
346
+ }
347
+
348
+ async function lintCommand(args) {
349
+ const json = args.includes("--json");
350
+ const allVaults = args.includes("--all-vaults") || args.includes("--all");
351
+ const nodeArg = args.find((a) => a.startsWith('--node='));
352
+ const nodeIndex = args.indexOf('--node');
353
+ const node = nodeArg
354
+ ? nodeArg.slice('--node='.length)
355
+ : (nodeIndex >= 0 && args[nodeIndex + 1] && !args[nodeIndex + 1].startsWith('--') ? args[nodeIndex + 1] : null);
356
+
357
+ try {
358
+ const res = await lintWikiHubs({ allVaults, node });
359
+ if (json) {
360
+ console.log(JSON.stringify(res, null, 2));
361
+ } else {
362
+ console.log(`\nOpenWiki Documentation Health & Hygiene:`);
363
+ console.log(` Health Score : ${res.healthScore}%`);
364
+ console.log(` Total Hubs Scanned : ${res.totalHubs}`);
365
+ console.log(` Total Links Tested : ${res.totalLinks}`);
366
+ console.log(` Broken Links : ${res.brokenLinksCount}`);
367
+ console.log(` Orphaned Hubs : ${res.orphanCount}`);
368
+
369
+ if (res.issues.length > 0) {
370
+ console.log('\nIssues Found:');
371
+ for (const iss of res.issues) {
372
+ console.log(` ✖ [${iss.type}] in ${path.basename(iss.file)}: ${iss.message}`);
373
+ }
374
+ } else {
375
+ console.log('\n✔ All wiki links and headers verified clean!');
376
+ }
377
+ console.log('');
378
+ }
379
+ if (!res.ok) process.exitCode = 1;
380
+ } catch (err) {
381
+ if (json) console.log(JSON.stringify({ ok: false, error: err.message }));
382
+ else console.error(`OpenWiki lint error: ${err.message}`);
383
+ process.exitCode = 1;
384
+ }
385
+ }
386
+
387
+ async function generateCommand(args) {
388
+ const json = args.includes("--json");
389
+ const force = args.includes("--force");
390
+ const dryRun = args.includes("--dry-run");
391
+ const repoIndex = args.indexOf('--repo');
392
+ const repoArg = args.find((a) => a.startsWith('--repo='));
393
+ const repo = repoArg
394
+ ? repoArg.slice('--repo='.length)
395
+ : (repoIndex >= 0 && args[repoIndex + 1] && !args[repoIndex + 1].startsWith('--') ? args[repoIndex + 1] : null);
396
+
397
+ const nodeArg = args.find((a) => a.startsWith('--node='));
398
+ const nodeIndex = args.indexOf('--node');
399
+ const node = nodeArg
400
+ ? nodeArg.slice('--node='.length)
401
+ : (nodeIndex >= 0 && args[nodeIndex + 1] && !args[nodeIndex + 1].startsWith('--') ? args[nodeIndex + 1] : null);
402
+
403
+ try {
404
+ const res = await generateWiki({
405
+ repo,
406
+ force,
407
+ dryRun,
408
+ node,
409
+ onProgress: (msg) => {
410
+ if (!json) console.log(` ▶ ${msg}`);
411
+ },
412
+ });
413
+
414
+ if (json) {
415
+ console.log(JSON.stringify(res, null, 2));
416
+ } else {
417
+ console.log(`\n✔ Generated documentation for ${res.repoName} (${Math.round((res.durationMs || 0)/1000)}s) via ${res.generatorVia}`);
418
+ console.log(` Output: ${res.outputDir}\n`);
419
+ }
420
+ } catch (err) {
421
+ if (json) console.log(JSON.stringify({ ok: false, error: err.message }));
422
+ else console.error(`OpenWiki generate error: ${err.message}`);
423
+ process.exitCode = 1;
192
424
  }
193
425
  }
194
426
 
@@ -372,15 +604,28 @@ async function configCommand(args) {
372
604
  }
373
605
  }
374
606
 
607
+ async function autoRefreshCommand(args = []) {
608
+ const hasApply = args.includes('--apply');
609
+ const forwardArgs = hasApply ? args : ['--apply', ...args];
610
+ return refreshCommand(forwardArgs);
611
+ }
612
+
375
613
  const IMPLEMENTED = {};
376
614
  IMPLEMENTED.probe = probeCommand;
377
615
  IMPLEMENTED.hubs = hubsCommand;
378
616
  IMPLEMENTED.ingest = ingestCommand;
379
617
  IMPLEMENTED.bootstrap = runBootstrapCommand;
380
618
  IMPLEMENTED.refresh = refreshCommand;
619
+ IMPLEMENTED['auto-refresh'] = autoRefreshCommand;
620
+ IMPLEMENTED.autorefresh = autoRefreshCommand;
381
621
  IMPLEMENTED.watch = watchCommand;
382
622
  IMPLEMENTED.propagate = propagateCommand;
383
623
  IMPLEMENTED.config = configCommand;
624
+ IMPLEMENTED.search = searchCommand;
625
+ IMPLEMENTED.graph = graphCommand;
626
+ IMPLEMENTED.token = tokenCommand;
627
+ IMPLEMENTED.lint = lintCommand;
628
+ IMPLEMENTED.generate = generateCommand;
384
629
 
385
630
  export async function run(argv = process.argv) {
386
631
  let rawArgs = Array.isArray(argv) && argv.length > 0 ? [...argv] : process.argv.slice(2);
@@ -426,13 +671,26 @@ export async function run(argv = process.argv) {
426
671
  Subcommands:
427
672
  status Show OpenWiki plugin and upstream status
428
673
  probe [--json] Check subsystem health
429
- hubs [--json] List indexed documentation hubs
674
+ hubs [--all-vaults] [--node <node>] [--json]
675
+ List indexed documentation hubs across workspace, all vaults, or mesh
676
+ search <query> [--all-vaults] [--node <node>] [--limit <n>] [--json]
677
+ Evidence passage search across knowledge hubs and vaults
678
+ graph [--all-vaults] [--node <node>] [--format json|mermaid|dot] [--json]
679
+ Extract knowledge graph topology, nodes, and inter-hub links
680
+ generate [--repo <name>] [--path <dir>] [--output <dir>] [--force] [--dry-run] [--node <node>] [--json]
681
+ Targeted on-demand documentation generation
682
+ token [status|set <provider> <value>] [--stdin] [--json]
683
+ Check or securely configure Total Recall secrets store keys
684
+ lint [--all-vaults] [--node <node>] [--json]
685
+ Validate link integrity, dead targets, and orphaned hubs
430
686
  ingest <path> [options] Ingest Markdown files into knowledge graph
431
687
  bootstrap --brain <path> [--project-root <path>] [--dry-run] [--json]
432
688
  Create missing plugin-owned documentation pages
433
689
  refresh [--repo <name>] [--apply] [--force] [--json]
434
690
  Report which registered projects' generated pages are stale;
435
691
  --apply regenerates stale pages (writes openwiki/ only)
692
+ auto-refresh [--repo <name>] [--force] [--json]
693
+ Automated daemon trigger to regenerate stale pages across repositories
436
694
  config [show|get <key>|set <key> <value>|reset] [--json]
437
695
  Configure generator provider, model, tokens, and timeout
438
696
  watch [--check-only] [--announce] [--propagate] [--json]