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
@@ -3,12 +3,134 @@
3
3
  * OpenWiki CLI Handler
4
4
  * Executed via: npx total-recall openwiki <subcommand>
5
5
  */
6
- // Scaffold: report honestly what exists. Add each real subcommand to
7
- // IMPLEMENTED and to plugin.json "cli.subcommands" as it is built.
8
-
9
6
  import fs from "node:fs";
10
7
  import path from "node:path";
11
8
  import { runBootstrapCommand } from './src/bootstrap.mjs';
9
+ import { describeRetention, hasWiki, isDue, readProjects, refreshProject, resolveKey, staleness } from './src/refresh.mjs';
10
+ import { announceNewVersion, checkUpstreamStatus, propagateUpdates, readUpstreamState } from './src/upstream-watcher.mjs';
11
+ import { loadOpenWikiConfig, setOpenWikiConfigValue, resetOpenWikiConfig, resolveConfigPath, ALLOWED_CONFIG_KEYS, ALLOWED_PROVIDERS } from './src/config.mjs';
12
+
13
+ /**
14
+ * Regenerate the generated pages of every registered project that carries them.
15
+ *
16
+ * Fleet-wide by design: the plugin ships from the shared brain, so one
17
+ * implementation covers every repository and every node that resolves it.
18
+ * Defaults to a report; --apply performs the refreshes, because regenerating a
19
+ * repository's documentation is a write to that repository.
20
+ */
21
+ async function refreshCommand(args) {
22
+ const json = args.includes('--json');
23
+ const apply = args.includes('--apply');
24
+ const force = args.includes('--force');
25
+ const repoIndex = args.indexOf('--repo');
26
+ const onlyArg = args.find((a) => a.startsWith('--repo='));
27
+ const only = onlyArg
28
+ ? onlyArg.slice('--repo='.length)
29
+ : (repoIndex >= 0 && args[repoIndex + 1] && !args[repoIndex + 1].startsWith('--') ? args[repoIndex + 1] : null);
30
+
31
+ let projects;
32
+ try {
33
+ projects = readProjects();
34
+ } catch (err) {
35
+ if (json) console.log(JSON.stringify({ ok: false, error: err.message }));
36
+ else console.error(`OpenWiki refresh: ${err.message}`);
37
+ process.exitCode = 2;
38
+ return;
39
+ }
40
+ if (only) projects = projects.filter((p) => p.name === only || p.root === only);
41
+ if (!projects.length) {
42
+ if (json) console.log(JSON.stringify({ ok: false, error: only ? `No registered project matches ${only}` : 'No registered projects' }));
43
+ else console.error(`OpenWiki refresh: ${only ? `no registered project matches ${only}` : 'no registered projects'}`);
44
+ process.exitCode = 2;
45
+ return;
46
+ }
47
+
48
+ const reports = [];
49
+ for (const project of projects) {
50
+ let state;
51
+ try {
52
+ state = force ? { due: true, ...staleness(project.root) } : isDue(project);
53
+ } catch (err) {
54
+ reports.push({ ...project, action: 'skipped', reason: err.message });
55
+ continue;
56
+ }
57
+ if (!state.due) {
58
+ reports.push({ ...project, action: 'current', generatedAt: state.generatedAt, commitsSince: state.commitsSince });
59
+ continue;
60
+ }
61
+ reports.push({
62
+ ...project,
63
+ action: 'due',
64
+ uninitialized: Boolean(state.uninitialized),
65
+ generatedAt: state.generatedAt,
66
+ commitsSince: state.commitsSince,
67
+ reason: state.reason
68
+ });
69
+ }
70
+
71
+ const due = reports.filter((r) => r.action === 'due');
72
+ let payloadBudgetNote = null;
73
+ if (apply && due.length) {
74
+ const config = loadOpenWikiConfig();
75
+ const { key, from } = resolveKey({ provider: config.provider });
76
+ if (!key) {
77
+ const keyName = config.provider === 'google' ? 'GOOGLE_API_KEY' : 'OPENROUTER_API_KEY';
78
+ const error = `No model credential for provider '${config.provider}'. Save via: total-recall auth secret set ${keyName} --stdin`;
79
+ if (json) console.log(JSON.stringify({ ok: false, error, reports }));
80
+ else console.error(`OpenWiki refresh: ${error}`);
81
+ process.exitCode = 1;
82
+ return;
83
+ }
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.`;
101
+ }
102
+ }
103
+
104
+ const failed = reports.filter((r) => r.action === 'failed');
105
+ const payload = {
106
+ ok: failed.length === 0,
107
+ applied: apply,
108
+ retention: describeRetention(),
109
+ note: payloadBudgetNote,
110
+ counts: {
111
+ registered: projects.length,
112
+ withPages: reports.filter((r) => r.action !== 'skipped' && !r.uninitialized).length,
113
+ due: due.length,
114
+ uninitialized: reports.filter((r) => r.uninitialized).length,
115
+ refreshed: reports.filter((r) => r.action === 'refreshed' || r.action === 'initialized').length,
116
+ failed: failed.length,
117
+ current: reports.filter((r) => r.action === 'current').length,
118
+ },
119
+ reports,
120
+ };
121
+ if (json) console.log(JSON.stringify(payload, null, 2));
122
+ else {
123
+ console.log(`OpenWiki refresh (${apply ? 'apply' : 'report'}): ${payload.counts.registered} registered, ${payload.counts.due} due (${payload.counts.uninitialized} uninitialized)`);
124
+ for (const r of reports) {
125
+ if (r.action === 'current') continue;
126
+ const age = r.uninitialized ? 'uninitialized' : (r.generatedAt ? `generated ${r.generatedAt.slice(0, 10)}` : 'never generated');
127
+ console.log(` ${r.action.padEnd(9)} ${r.name.padEnd(28)} ${age}${Number.isFinite(r.commitsSince) && r.commitsSince !== Infinity ? `, ${r.commitsSince} commits since` : ''}${r.reason ? ` — ${r.reason}` : ''}`);
128
+ }
129
+ if (payloadBudgetNote) console.log(payloadBudgetNote);
130
+ if (!apply && due.length) console.log('Re-run with --apply to regenerate. Pages are a projection; vault content is never touched.');
131
+ }
132
+ if (failed.length) process.exitCode = 1;
133
+ }
12
134
 
13
135
  async function probeCommand(args) {
14
136
  const json = args.includes("--json");
@@ -79,24 +201,218 @@ async function ingestCommand(args) {
79
201
  }
80
202
  }
81
203
 
204
+ /**
205
+ * Surveillance command for monitoring the upstream open-source OpenWiki package.
206
+ */
207
+ async function watchCommand(args) {
208
+ const json = args.includes('--json');
209
+ const checkOnly = args.includes('--check-only');
210
+ const announce = args.includes('--announce') || (!checkOnly && !args.includes('--no-announce'));
211
+ const propagate = args.includes('--propagate');
212
+
213
+ const status = await checkUpstreamStatus();
214
+ let announcement = null;
215
+ let propagation = null;
216
+
217
+ if (status.ok && status.updateAvailable) {
218
+ if (announce) {
219
+ announcement = await announceNewVersion({
220
+ latestVersion: status.latestVersion,
221
+ currentVersion: status.currentVersion,
222
+ releaseNotesUrl: status.releaseNotesUrl
223
+ });
224
+ }
225
+ if (propagate) {
226
+ propagation = await propagateUpdates({ force: true });
227
+ }
228
+ }
229
+
230
+ const payload = {
231
+ ok: status.ok,
232
+ status,
233
+ announcement,
234
+ propagation
235
+ };
236
+
237
+ if (json) {
238
+ console.log(JSON.stringify(payload, null, 2));
239
+ } else {
240
+ console.log('\nOpenWiki Upstream Watcher:');
241
+ console.log(` Active Recorded Version : v${status.currentVersion}`);
242
+ console.log(` Latest Upstream Version : v${status.latestVersion}`);
243
+ console.log(` Update Available : ${status.updateAvailable ? 'YES (Increment Detected)' : 'No (Current)'}`);
244
+ if (status.releaseNotesUrl) {
245
+ console.log(` Release Notes : ${status.releaseNotesUrl}`);
246
+ }
247
+ if (announcement?.announced) {
248
+ console.log(` Operator Announcement : Dispatched successfully`);
249
+ }
250
+ if (propagation) {
251
+ console.log(` Fleet Propagation : ${propagation.ok ? 'Completed' : 'Failed'} (${propagation.updatedCount} projects updated)`);
252
+ }
253
+ console.log('');
254
+ }
255
+
256
+ if (!status.ok) process.exitCode = 1;
257
+ }
258
+
259
+ /**
260
+ * Propagate updated generator across registered repositories.
261
+ */
262
+ async function propagateCommand(args) {
263
+ if (args.includes('--help') || args.includes('-h')) {
264
+ console.log(`
265
+ Usage:
266
+ total-recall openwiki propagate [options]
267
+
268
+ Options:
269
+ --repo <name> Limit propagation to a specific repository
270
+ --force Force regeneration even if not due
271
+ --dry-run Preview propagation actions without writing
272
+ --json Output result as JSON
273
+ --help, -h Show this help
274
+ `);
275
+ return;
276
+ }
277
+ const json = args.includes('--json');
278
+ const force = args.includes('--force');
279
+ const dryRun = args.includes('--dry-run');
280
+ const repoIndex = args.indexOf('--repo');
281
+ const onlyArg = args.find((a) => a.startsWith('--repo='));
282
+ const repo = onlyArg
283
+ ? onlyArg.slice('--repo='.length)
284
+ : (repoIndex >= 0 && args[repoIndex + 1] && !args[repoIndex + 1].startsWith('--') ? args[repoIndex + 1] : null);
285
+
286
+ const result = await propagateUpdates({ repo, force, dryRun });
287
+
288
+ if (json) {
289
+ console.log(JSON.stringify(result, null, 2));
290
+ } else {
291
+ console.log(`\nOpenWiki Fleet Propagation (${dryRun ? 'DRY RUN' : 'APPLY'}):`);
292
+ console.log(` Eligible Repositories : ${result.eligibleCount || 0}`);
293
+ console.log(` Updated Repositories : ${result.updatedCount || 0}`);
294
+ console.log(` Failed Repositories : ${result.failedCount || 0}`);
295
+ if (Array.isArray(result.reports)) {
296
+ for (const r of result.reports) {
297
+ console.log(` • ${r.name}: ${r.action}${r.reason ? ` — ${r.reason}` : ''}`);
298
+ }
299
+ }
300
+ console.log('');
301
+ }
302
+
303
+ if (!result.ok) process.exitCode = 1;
304
+ }
305
+
306
+ /**
307
+ * Configure OpenWiki generation parameters and cheap model routing.
308
+ */
309
+ async function configCommand(args) {
310
+ const json = args.includes('--json');
311
+ const cleanArgs = args.filter((a) => a !== '--json');
312
+ const verb = cleanArgs[0] || 'show';
313
+
314
+ try {
315
+ if (verb === 'show') {
316
+ const config = loadOpenWikiConfig();
317
+ const configPath = resolveConfigPath();
318
+ const payload = { ok: true, path: configPath, config };
319
+ if (json) console.log(JSON.stringify(payload, null, 2));
320
+ else {
321
+ console.log(`\nOpenWiki Configuration (${configPath}):`);
322
+ console.log(` Provider : ${config.provider}`);
323
+ console.log(` Model : ${config.model}`);
324
+ console.log(` Fallback Model : ${config.fallback_model}`);
325
+ console.log(` Max Tokens : ${config.max_tokens}`);
326
+ console.log(` Timeout (ms) : ${config.timeout_ms}\n`);
327
+ }
328
+ return;
329
+ }
330
+
331
+ if (verb === 'get') {
332
+ const key = cleanArgs[1];
333
+ if (!key) {
334
+ throw new Error('Key argument required: openwiki config get <key>');
335
+ }
336
+ if (!ALLOWED_CONFIG_KEYS.includes(key)) {
337
+ throw new Error(`Unknown configuration key '${key}'. Allowed: ${ALLOWED_CONFIG_KEYS.join(', ')}`);
338
+ }
339
+ const config = loadOpenWikiConfig();
340
+ const value = config[key];
341
+ if (json) console.log(JSON.stringify({ ok: true, key, value }));
342
+ else console.log(value);
343
+ return;
344
+ }
345
+
346
+ if (verb === 'set') {
347
+ const key = cleanArgs[1];
348
+ const value = cleanArgs[2];
349
+ if (!key || value === undefined) {
350
+ throw new Error('Key and value required: openwiki config set <key> <value>');
351
+ }
352
+ const updated = setOpenWikiConfigValue(key, value);
353
+ const payload = { ok: true, key, value: updated[key], config: updated };
354
+ if (json) console.log(JSON.stringify(payload, null, 2));
355
+ else console.log(`OpenWiki configuration updated: ${key} = ${updated[key]}`);
356
+ return;
357
+ }
358
+
359
+ if (verb === 'reset') {
360
+ const reset = resetOpenWikiConfig();
361
+ const payload = { ok: true, message: 'Configuration reset to defaults', config: reset };
362
+ if (json) console.log(JSON.stringify(payload, null, 2));
363
+ else console.log('OpenWiki configuration reset to defaults');
364
+ return;
365
+ }
366
+
367
+ throw new Error(`Unknown config action '${verb}'. Supported verbs: show, get, set, reset`);
368
+ } catch (err) {
369
+ if (json) console.log(JSON.stringify({ ok: false, error: err.message }));
370
+ else console.error(`OpenWiki config error: ${err.message}`);
371
+ process.exitCode = 1;
372
+ }
373
+ }
374
+
82
375
  const IMPLEMENTED = {};
83
376
  IMPLEMENTED.probe = probeCommand;
84
377
  IMPLEMENTED.hubs = hubsCommand;
85
378
  IMPLEMENTED.ingest = ingestCommand;
86
379
  IMPLEMENTED.bootstrap = runBootstrapCommand;
380
+ IMPLEMENTED.refresh = refreshCommand;
381
+ IMPLEMENTED.watch = watchCommand;
382
+ IMPLEMENTED.propagate = propagateCommand;
383
+ IMPLEMENTED.config = configCommand;
87
384
 
385
+ export async function run(argv = process.argv) {
386
+ let rawArgs = Array.isArray(argv) && argv.length > 0 ? [...argv] : process.argv.slice(2);
387
+ while (rawArgs.length > 0 && (
388
+ rawArgs[0].endsWith('node') ||
389
+ rawArgs[0].endsWith('total-recall') ||
390
+ rawArgs[0].endsWith('cli.mjs') ||
391
+ rawArgs[0] === 'openwiki'
392
+ )) {
393
+ rawArgs.shift();
394
+ }
88
395
 
89
- export async function run(argv = []) {
90
- const args = Array.isArray(argv) ? argv.slice(3) : [];
91
- const sub = args[0] || "status";
92
- const json = args.includes("--json");
396
+ const sub = rawArgs[0] || "status";
397
+ const json = rawArgs.includes("--json");
93
398
 
94
399
  if (sub === "status") {
95
- const status = { plugin: "openwiki", implemented: Object.keys(IMPLEMENTED) };
96
- if (json) console.log(JSON.stringify(status));
97
- else console.log(status.implemented.length
98
- ? `OpenWiki: implemented subcommands: ${status.implemented.join(", ")}`
99
- : `OpenWiki: scaffold only — no subcommands implemented yet.`);
400
+ const upstream = readUpstreamState();
401
+ const status = {
402
+ plugin: "openwiki",
403
+ implemented: Object.keys(IMPLEMENTED),
404
+ upstream: {
405
+ recordedVersion: upstream.currentRecordedVersion,
406
+ latestVersion: upstream.latestKnownVersion,
407
+ lastChecked: upstream.lastCheckedAt,
408
+ lastPropagated: upstream.lastPropagatedAt
409
+ }
410
+ };
411
+ if (json) console.log(JSON.stringify(status, null, 2));
412
+ else {
413
+ console.log(`OpenWiki: implemented subcommands: ${status.implemented.join(", ")}`);
414
+ console.log(`Upstream Status: recorded v${status.upstream.recordedVersion}, latest v${status.upstream.latestVersion}`);
415
+ }
100
416
  return;
101
417
  }
102
418
 
@@ -108,20 +424,34 @@ export async function run(argv = []) {
108
424
  total-recall openwiki <subcommand> [options]
109
425
 
110
426
  Subcommands:
111
- status Show OpenWiki plugin status
427
+ status Show OpenWiki plugin and upstream status
112
428
  probe [--json] Check subsystem health
113
429
  hubs [--json] List indexed documentation hubs
114
430
  ingest <path> [options] Ingest Markdown files into knowledge graph
115
431
  bootstrap --brain <path> [--project-root <path>] [--dry-run] [--json]
116
432
  Create missing plugin-owned documentation pages
433
+ refresh [--repo <name>] [--apply] [--force] [--json]
434
+ Report which registered projects' generated pages are stale;
435
+ --apply regenerates stale pages (writes openwiki/ only)
436
+ config [show|get <key>|set <key> <value>|reset] [--json]
437
+ Configure generator provider, model, tokens, and timeout
438
+ watch [--check-only] [--announce] [--propagate] [--json]
439
+ Watch upstream OpenWiki repository and announce new versions
440
+ propagate [--repo <name>] [--force] [--dry-run] [--json]
441
+ Propagate updated generator across registered repositories
117
442
  `);
118
443
  return;
119
444
  }
120
445
 
121
- if (Object.hasOwn(IMPLEMENTED, sub)) return IMPLEMENTED[sub](args.slice(1));
446
+ if (Object.hasOwn(IMPLEMENTED, sub)) return IMPLEMENTED[sub](rawArgs.slice(1));
122
447
 
123
448
  if (json) console.log(JSON.stringify({ ok: false, error: `OpenWiki operation is not implemented: ${sub}` }));
124
449
  console.error(`OpenWiki: "${sub}" is not implemented.`);
125
450
  process.exitCode = 2;
126
451
  }
452
+
453
+ if (process.argv[1] && (process.argv[1].endsWith('cli.mjs') || process.argv[1].endsWith('tr-plugin-openwiki'))) {
454
+ run(process.argv);
455
+ }
456
+
127
457
  export default run;