total-recall-brain 3.47.0 → 3.47.2

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 (73) hide show
  1. package/bin/total-recall.mjs +5 -0
  2. package/package.json +1 -1
  3. package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +4 -4
  4. package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +3 -2
  5. package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +30 -5
  6. package/scaffold/.agent/skills/total-recall/plugins/auth/skills/auth/SKILL.md +35 -0
  7. package/scaffold/.agent/skills/total-recall/plugins/auth/ui/home.js +494 -79
  8. package/scaffold/.agent/skills/total-recall/plugins/automations/package-lock.json +4 -4
  9. package/scaffold/.agent/skills/total-recall/plugins/automations/package.json +3 -2
  10. package/scaffold/.agent/skills/total-recall/plugins/automations/plugin.json +33 -8
  11. package/scaffold/.agent/skills/total-recall/plugins/automations/skills/automations/SKILL.md +29 -0
  12. package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/dream-consolidation.md +17 -0
  13. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +4 -4
  14. package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +3 -2
  15. package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +31 -4
  16. package/scaffold/.agent/skills/total-recall/plugins/code-quality/skills/code-quality/SKILL.md +27 -0
  17. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +4 -4
  18. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
  19. package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +17 -3
  20. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +4 -4
  21. package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +3 -2
  22. package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +24 -4
  23. package/scaffold/.agent/skills/total-recall/plugins/embeddings/skills/embeddings/SKILL.md +25 -0
  24. package/scaffold/.agent/skills/total-recall/plugins/git/package-lock.json +4 -4
  25. package/scaffold/.agent/skills/total-recall/plugins/git/package.json +3 -2
  26. package/scaffold/.agent/skills/total-recall/plugins/git/plugin.json +293 -58
  27. package/scaffold/.agent/skills/total-recall/plugins/git/skills/git/SKILL.md +36 -0
  28. package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +4 -4
  29. package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +3 -2
  30. package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +47 -14
  31. package/scaffold/.agent/skills/total-recall/plugins/mesh/skills/mesh/SKILL.md +36 -0
  32. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +6 -3
  33. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package-lock.json +6 -6
  34. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +1 -1
  35. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +5 -2
  36. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +4 -2
  37. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +28 -9
  38. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +8 -2
  39. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/included-usage.mjs +2 -2
  40. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/learner.mjs +7 -0
  41. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-selection.mjs +59 -0
  42. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/pool.mjs +2 -2
  43. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/remote-operation.mjs +3 -3
  44. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +11 -5
  45. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +50 -6
  46. package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/session-controls.md +16 -0
  47. package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +56 -7
  48. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +6 -6
  49. package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +3 -2
  50. package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +199 -36
  51. package/scaffold/.agent/skills/total-recall/plugins/openwiki/skills/openwiki/SKILL.md +32 -0
  52. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +34 -8
  53. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +6 -0
  54. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +15 -7
  55. package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +4 -3
  56. package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +4 -4
  57. package/scaffold/.agent/skills/total-recall/plugins/security/package.json +1 -1
  58. package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +22 -5
  59. package/scaffold/.agent/skills/total-recall/plugins/ssss/package.json +3 -2
  60. package/scaffold/.agent/skills/total-recall/plugins/ssss/plugin.json +169 -37
  61. package/scaffold/.agent/skills/total-recall/plugins/ssss/skills/ssss/SKILL.md +30 -0
  62. package/src/cli/plugin/create.mjs +2 -1
  63. package/src/cli/plugin/monetization.mjs +66 -32
  64. package/src/cli/plugin/search.mjs +25 -3
  65. package/src/cli/preflight.mjs +40 -6
  66. package/src/cli/update.mjs +20 -1
  67. package/src/core/automatic-brain-updates.mjs +8 -4
  68. package/src/core/brain-updates.mjs +25 -6
  69. package/src/core/gate-mode.mjs +13 -24
  70. package/src/core/plugin-distribution.mjs +35 -1
  71. package/src/core/preflight-gate.mjs +28 -8
  72. package/src/core/preflight-receipt.mjs +11 -0
  73. package/src/core/release-defaults-handoff.mjs +89 -0
@@ -11,7 +11,7 @@ import { CREDIT_REFUSAL, NO_MODEL, describeRetention, hasWiki, isDue, readProjec
11
11
 
12
12
  const DEFAULT_REPO_CONCURRENCY = 2;
13
13
  import { watchUpstream, propagateUpdates, readUpstreamState, bundledGeneratorVersion } from './src/upstream-watcher.mjs';
14
- import { loadOpenWikiConfig, setOpenWikiConfigValue, resetOpenWikiConfig, resolveConfigPath, ALLOWED_CONFIG_KEYS, ALLOWED_PROVIDERS } from './src/config.mjs';
14
+ import { loadOpenWikiConfig, setOpenWikiConfigValue, resetOpenWikiConfig, resolveConfigPath, setExcludedRoots, ALLOWED_CONFIG_KEYS, ALLOWED_PROVIDERS } from './src/config.mjs';
15
15
  import { discoverAllHubs } from './src/mesh-vaults.mjs';
16
16
  import { searchWikiHubs } from './src/search.mjs';
17
17
  import { buildKnowledgeGraph } from './src/graph.mjs';
@@ -83,8 +83,12 @@ export async function refreshCommand(args, {
83
83
  continue;
84
84
  }
85
85
  if (!state.due) {
86
- if (state.skipped) {
86
+ if (state.excluded) {
87
+ reports.push({ ...project, action: 'excluded', reason: state.reason });
88
+ } else if (state.skipped) {
87
89
  reports.push({ ...project, action: 'skipped', reason: state.reason });
90
+ } else if (state.uninitialized && !state.held) {
91
+ reports.push({ ...project, action: 'no-wiki', uninitialized: true, reason: state.reason, generatedAt: state.generatedAt });
88
92
  } else if (state.held) {
89
93
  reports.push({ ...project, action: 'held', uninitialized: Boolean(state.uninitialized), reason: state.reason, generationCommit: state.generationCommit, generationTime: state.generationTime, generatedAt: state.generatedAt, commitsSince: state.commitsSince });
90
94
  } else {
@@ -202,9 +206,10 @@ export async function refreshCommand(args, {
202
206
  note: payloadBudgetNote,
203
207
  counts: {
204
208
  registered: projects.length,
205
- withPages: reports.filter((r) => r.action !== 'skipped' && !r.uninitialized).length,
209
+ withPages: reports.filter((r) => !['skipped', 'excluded'].includes(r.action) && !r.uninitialized).length,
206
210
  due: due.length,
207
211
  uninitialized: reports.filter((r) => r.uninitialized).length,
212
+ excluded: reports.filter((r) => r.action === 'excluded').length,
208
213
  refreshed: reports.filter((r) => r.action === 'refreshed' || r.action === 'initialized').length,
209
214
  failed: failed.length,
210
215
  partial: partial.length,
@@ -217,11 +222,11 @@ export async function refreshCommand(args, {
217
222
  };
218
223
  if (json) console.log(JSON.stringify(payload, null, 2));
219
224
  else {
220
- console.log(`OpenWiki refresh (${apply ? 'apply' : 'report'}): ${payload.counts.registered} registered, ${payload.counts.due} due (${payload.counts.uninitialized} uninitialized)`);
225
+ console.log(`OpenWiki refresh (${apply ? 'apply' : 'report'}): ${payload.counts.registered} registered, ${payload.counts.due} due, ${payload.counts.uninitialized} without a finished wiki, ${payload.counts.excluded} excluded`);
221
226
  // Put failures last so bounded scheduler tails retain their causes.
222
227
  for (const r of [...reports].sort((a, b) => Number(['failed', 'partial'].includes(a.action)) - Number(['failed', 'partial'].includes(b.action)))) {
223
- if (r.action === 'current') continue;
224
- const age = r.action === 'skipped' ? 'outside repository generation' : r.generationTime ? `generated ${r.generationTime} at ${r.generationCommit}` : r.uninitialized ? 'uninitialized' : (r.generatedAt ? `last attempt ${r.generatedAt}; generation commit unknown` : 'never generated');
228
+ if (r.action === 'current' || r.action === 'excluded') continue;
229
+ const age = r.action === 'skipped' ? 'outside repository generation' : r.generationTime ? `generated ${r.generationTime} at ${r.generationCommit}` : r.uninitialized ? 'no finished wiki' : (r.generatedAt ? `last attempt ${r.generatedAt}; generation commit unknown` : 'never generated');
225
230
  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}` : ''}`);
226
231
  }
227
232
  if (payloadBudgetNote) console.log(payloadBudgetNote);
@@ -730,6 +735,46 @@ export async function scheduleCommand(args = [], { core = null, config = loadOpe
730
735
  }
731
736
  }
732
737
 
738
+ /**
739
+ * List, add or remove repositories the refresh never touches. Takes registered
740
+ * project names or absolute paths; with none, lists the current exclusions.
741
+ */
742
+ export async function excludeCommand(args = [], { read = readProjects, load = loadOpenWikiConfig, save = setExcludedRoots } = {}) {
743
+ const json = args.includes('--json');
744
+ const usage = 'Usage: total-recall openwiki exclude [<name|absolute path>...] [--remove] [--json]';
745
+ if (args.includes('--help') || args.includes('-h')) { console.log(usage); return; }
746
+ const remove = args.includes('--remove');
747
+ const targets = args.filter((a) => !a.startsWith('--'));
748
+ try {
749
+ if (remove && !targets.length) throw new Error(usage);
750
+ let roots = load().exclude || [];
751
+ if (targets.length) {
752
+ let projects = [];
753
+ try { projects = read({ exclude: [] }); } catch { projects = []; }
754
+ const chosen = [];
755
+ for (const target of targets) {
756
+ const matches = projects.filter((p) => p.name === target || (path.isAbsolute(target) && path.resolve(p.root) === path.resolve(target)));
757
+ if (matches.length > 1) throw new Error(`${target} names ${matches.length} registered projects; pass its absolute path`);
758
+ if (matches.length === 1) chosen.push(path.resolve(matches[0].root));
759
+ else if (path.isAbsolute(target)) chosen.push(path.resolve(target));
760
+ else throw new Error(`${target} is not a registered project name or an absolute path`);
761
+ }
762
+ roots = save(remove ? roots.filter((root) => !chosen.includes(root)) : [...roots, ...chosen]).exclude;
763
+ }
764
+ const payload = { ok: true, changed: targets.length > 0, exclude: roots };
765
+ if (json) console.log(JSON.stringify(payload, null, 2));
766
+ else {
767
+ console.log(`OpenWiki never refreshes ${roots.length} ${roots.length === 1 ? 'repository' : 'repositories'}${roots.length ? ':' : '.'}`);
768
+ for (const root of roots) console.log(` ${root}`);
769
+ }
770
+ return payload;
771
+ } catch (err) {
772
+ if (json) console.log(JSON.stringify({ ok: false, error: err.message }));
773
+ else console.error(`OpenWiki exclude: ${err.message}`);
774
+ process.exitCode = 1;
775
+ }
776
+ }
777
+
733
778
  async function autoRefreshCommand(args = []) {
734
779
  const forwardArgs = args.includes('--apply') ? [...args] : ['--apply', ...args];
735
780
  if (!forwardArgs.some((a) => a === '--budget-ms' || a.startsWith('--budget-ms='))) {
@@ -760,6 +805,7 @@ IMPLEMENTED.watch = watchCommand;
760
805
  IMPLEMENTED.propagate = propagateCommand;
761
806
  IMPLEMENTED.config = configCommand;
762
807
  IMPLEMENTED.schedule = scheduleCommand;
808
+ IMPLEMENTED.exclude = excludeCommand;
763
809
  IMPLEMENTED.search = searchCommand;
764
810
  IMPLEMENTED.graph = graphCommand;
765
811
  IMPLEMENTED.token = tokenCommand;
@@ -830,7 +876,10 @@ export async function run(argv = process.argv) {
830
876
  Create missing plugin-owned documentation pages
831
877
  refresh [--repo <name>] [--apply] [--force] [--json]
832
878
  Report which registered projects' generated pages are stale;
833
- --apply regenerates stale pages (writes openwiki/ only)
879
+ --apply regenerates stale pages (writes openwiki/ only).
880
+ Never creates a wiki: use generate for that
881
+ exclude [<name|path>...] [--remove] [--json]
882
+ List, add or remove repositories the refresh never touches
834
883
  auto-refresh [--repo <name>] [--force] [--json]
835
884
  Automated daemon trigger to regenerate stale pages across repositories
836
885
  config [show|get <key>|set <key> <value>|reset] [--json]
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "tr-plugin-openwiki",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "tr-plugin-openwiki",
9
- "version": "0.3.0",
9
+ "version": "0.4.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@gregiteen/ssss-cli": "0.14.5"
13
13
  },
14
14
  "devDependencies": {
15
- "total-recall-brain": "3.46.2"
15
+ "total-recall-brain": "3.47.0"
16
16
  }
17
17
  },
18
18
  "node_modules/@alcalzone/ansi-tokenize": {
@@ -5529,9 +5529,9 @@
5529
5529
  }
5530
5530
  },
5531
5531
  "node_modules/total-recall-brain": {
5532
- "version": "3.46.2",
5533
- "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.46.2.tgz",
5534
- "integrity": "sha512-xEVtIA/lLbMtDJ4fO6WT37N4tDGbDjL/8imvrbFygOA+C17v6Y5M5023A5Wbm8PvwiUE18j8vzBdX5DJl8H3cg==",
5532
+ "version": "3.47.0",
5533
+ "resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.47.0.tgz",
5534
+ "integrity": "sha512-S4UIdbbTyxw7C4+rix+7oHMm/6gYkcxwNBcP6kRDySX40p5IgqVTKgHk1n8rmaKiyYFoIX/HZHlHSjNrHgn0Gw==",
5535
5535
  "dev": true,
5536
5536
  "license": "MIT",
5537
5537
  "workspaces": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tr-plugin-openwiki",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "type": "module",
5
5
  "description": "Multi-repo knowledge graph and documentation wiki engine for Total Recall",
6
6
  "scripts": {
@@ -18,7 +18,8 @@
18
18
  "src/",
19
19
  "vendor/",
20
20
  "capability/",
21
- "templates/"
21
+ "templates/",
22
+ "skills/"
22
23
  ],
23
24
  "dependencies": {
24
25
  "@gregiteen/ssss-cli": "0.14.5"
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://github.com/gregiteen/total-recall/blob/main/metadata.plugin.schema.json",
3
3
  "id": "openwiki",
4
4
  "name": "OpenWiki",
5
- "version": "0.3.0",
5
+ "version": "0.4.1",
6
6
  "description": "Multi-repo knowledge graph and documentation wiki engine for Total Recall.",
7
7
  "license": "MIT",
8
8
  "runtime": {
@@ -72,7 +72,11 @@
72
72
  ]
73
73
  },
74
74
  "gate": {
75
- "tasks": ["Search or read a repository's wiki", "Generate or refresh wiki pages", "Ingest documentation into memory"],
75
+ "tasks": [
76
+ "Search or read a repository's wiki",
77
+ "Generate or refresh wiki pages",
78
+ "Ingest documentation into memory"
79
+ ],
76
80
  "owned_commands": []
77
81
  },
78
82
  "cli": {
@@ -85,8 +89,19 @@
85
89
  "effect": "read",
86
90
  "output": "json",
87
91
  "args": [
88
- { "name": "task", "label": "Task description", "type": "string", "positional": true, "required": true },
89
- { "name": "json", "label": "JSON output", "type": "boolean", "flag": "--json" }
92
+ {
93
+ "name": "task",
94
+ "label": "Task description",
95
+ "type": "string",
96
+ "positional": true,
97
+ "required": true
98
+ },
99
+ {
100
+ "name": "json",
101
+ "label": "JSON output",
102
+ "type": "boolean",
103
+ "flag": "--json"
104
+ }
90
105
  ]
91
106
  },
92
107
  {
@@ -95,11 +110,37 @@
95
110
  "effect": "read",
96
111
  "output": "json",
97
112
  "args": [
98
- { "name": "query", "label": "Search terms", "type": "string", "positional": true, "required": true },
99
- { "name": "allVaults", "label": "Search all registered vaults", "type": "boolean", "flag": "--all-vaults" },
100
- { "name": "node", "label": "Mesh node", "type": "string", "flag": "--node" },
101
- { "name": "limit", "label": "Maximum results", "type": "number", "flag": "--limit" },
102
- { "name": "json", "label": "JSON output", "type": "boolean", "flag": "--json" }
113
+ {
114
+ "name": "query",
115
+ "label": "Search terms",
116
+ "type": "string",
117
+ "positional": true,
118
+ "required": true
119
+ },
120
+ {
121
+ "name": "allVaults",
122
+ "label": "Search all registered vaults",
123
+ "type": "boolean",
124
+ "flag": "--all-vaults"
125
+ },
126
+ {
127
+ "name": "node",
128
+ "label": "Mesh node",
129
+ "type": "string",
130
+ "flag": "--node"
131
+ },
132
+ {
133
+ "name": "limit",
134
+ "label": "Maximum results",
135
+ "type": "number",
136
+ "flag": "--limit"
137
+ },
138
+ {
139
+ "name": "json",
140
+ "label": "JSON output",
141
+ "type": "boolean",
142
+ "flag": "--json"
143
+ }
103
144
  ]
104
145
  },
105
146
  {
@@ -108,10 +149,35 @@
108
149
  "effect": "read",
109
150
  "output": "json",
110
151
  "args": [
111
- { "name": "allVaults", "label": "Inspect all registered vaults", "type": "boolean", "flag": "--all-vaults" },
112
- { "name": "node", "label": "Mesh node", "type": "string", "flag": "--node" },
113
- { "name": "format", "label": "Graph format", "type": "choice", "options": ["json", "mermaid", "dot"], "flag": "--format" },
114
- { "name": "json", "label": "JSON output", "type": "boolean", "flag": "--json" }
152
+ {
153
+ "name": "allVaults",
154
+ "label": "Inspect all registered vaults",
155
+ "type": "boolean",
156
+ "flag": "--all-vaults"
157
+ },
158
+ {
159
+ "name": "node",
160
+ "label": "Mesh node",
161
+ "type": "string",
162
+ "flag": "--node"
163
+ },
164
+ {
165
+ "name": "format",
166
+ "label": "Graph format",
167
+ "type": "choice",
168
+ "options": [
169
+ "json",
170
+ "mermaid",
171
+ "dot"
172
+ ],
173
+ "flag": "--format"
174
+ },
175
+ {
176
+ "name": "json",
177
+ "label": "JSON output",
178
+ "type": "boolean",
179
+ "flag": "--json"
180
+ }
115
181
  ]
116
182
  },
117
183
  {
@@ -121,11 +187,36 @@
121
187
  "output": "json",
122
188
  "timeout_ms": 600000,
123
189
  "args": [
124
- { "name": "repo", "label": "Registered repository", "type": "string", "flag": "--repo" },
125
- { "name": "node", "label": "Mesh node", "type": "string", "flag": "--node" },
126
- { "name": "force", "label": "Regenerate existing pages", "type": "boolean", "flag": "--force" },
127
- { "name": "dryRun", "label": "Describe generation without writing", "type": "boolean", "flag": "--dry-run" },
128
- { "name": "json", "label": "JSON output", "type": "boolean", "flag": "--json" }
190
+ {
191
+ "name": "repo",
192
+ "label": "Registered repository",
193
+ "type": "string",
194
+ "flag": "--repo"
195
+ },
196
+ {
197
+ "name": "node",
198
+ "label": "Mesh node",
199
+ "type": "string",
200
+ "flag": "--node"
201
+ },
202
+ {
203
+ "name": "force",
204
+ "label": "Regenerate existing pages",
205
+ "type": "boolean",
206
+ "flag": "--force"
207
+ },
208
+ {
209
+ "name": "dryRun",
210
+ "label": "Describe generation without writing",
211
+ "type": "boolean",
212
+ "flag": "--dry-run"
213
+ },
214
+ {
215
+ "name": "json",
216
+ "label": "JSON output",
217
+ "type": "boolean",
218
+ "flag": "--json"
219
+ }
129
220
  ]
130
221
  },
131
222
  {
@@ -134,11 +225,44 @@
134
225
  "effect": "write",
135
226
  "output": "json",
136
227
  "args": [
137
- { "name": "action", "label": "Credential action", "type": "choice", "options": ["status", "set"], "positional": true },
138
- { "name": "provider", "label": "Credential provider", "type": "choice", "options": ["openrouter", "google"], "positional": true },
139
- { "name": "value", "label": "Secret value through stdin", "type": "string", "secret": true },
140
- { "name": "stdin", "label": "Read secret from stdin", "type": "boolean", "flag": "--stdin" },
141
- { "name": "json", "label": "JSON output", "type": "boolean", "flag": "--json" }
228
+ {
229
+ "name": "action",
230
+ "label": "Credential action",
231
+ "type": "choice",
232
+ "options": [
233
+ "status",
234
+ "set"
235
+ ],
236
+ "positional": true
237
+ },
238
+ {
239
+ "name": "provider",
240
+ "label": "Credential provider",
241
+ "type": "choice",
242
+ "options": [
243
+ "openrouter",
244
+ "google"
245
+ ],
246
+ "positional": true
247
+ },
248
+ {
249
+ "name": "value",
250
+ "label": "Secret value through stdin",
251
+ "type": "string",
252
+ "secret": true
253
+ },
254
+ {
255
+ "name": "stdin",
256
+ "label": "Read secret from stdin",
257
+ "type": "boolean",
258
+ "flag": "--stdin"
259
+ },
260
+ {
261
+ "name": "json",
262
+ "label": "JSON output",
263
+ "type": "boolean",
264
+ "flag": "--json"
265
+ }
142
266
  ]
143
267
  },
144
268
  {
@@ -147,9 +271,24 @@
147
271
  "effect": "read",
148
272
  "output": "json",
149
273
  "args": [
150
- { "name": "allVaults", "label": "Inspect all registered vaults", "type": "boolean", "flag": "--all-vaults" },
151
- { "name": "node", "label": "Mesh node", "type": "string", "flag": "--node" },
152
- { "name": "json", "label": "JSON output", "type": "boolean", "flag": "--json" }
274
+ {
275
+ "name": "allVaults",
276
+ "label": "Inspect all registered vaults",
277
+ "type": "boolean",
278
+ "flag": "--all-vaults"
279
+ },
280
+ {
281
+ "name": "node",
282
+ "label": "Mesh node",
283
+ "type": "string",
284
+ "flag": "--node"
285
+ },
286
+ {
287
+ "name": "json",
288
+ "label": "JSON output",
289
+ "type": "boolean",
290
+ "flag": "--json"
291
+ }
153
292
  ]
154
293
  },
155
294
  {
@@ -269,7 +408,7 @@
269
408
  },
270
409
  {
271
410
  "name": "refresh",
272
- "description": "Report which registered projects' generated OpenWiki pages are stale; --apply regenerates them (openwiki/ only)",
411
+ "description": "Report which registered projects' generated OpenWiki pages are stale; --apply updates existing wikis (openwiki/ only), never creates one, and skips excluded repositories",
273
412
  "timeout_ms": 600000,
274
413
  "effect": "write",
275
414
  "output": "json",
@@ -455,6 +594,31 @@
455
594
  "type": "boolean"
456
595
  }
457
596
  ]
597
+ },
598
+ {
599
+ "name": "exclude",
600
+ "description": "List, add or remove repositories the wiki refresh and generate never touch (clones, forks, backups)",
601
+ "effect": "write",
602
+ "args": [
603
+ {
604
+ "name": "targets",
605
+ "type": "string",
606
+ "label": "Registered project name or absolute path",
607
+ "positional": true
608
+ },
609
+ {
610
+ "name": "remove",
611
+ "flag": "--remove",
612
+ "label": "Take the repositories off the list",
613
+ "type": "boolean"
614
+ },
615
+ {
616
+ "name": "json",
617
+ "flag": "--json",
618
+ "label": "JSON output",
619
+ "type": "boolean"
620
+ }
621
+ ]
458
622
  }
459
623
  ]
460
624
  },
@@ -493,14 +657,6 @@
493
657
  "formatPropagationReceipt"
494
658
  ]
495
659
  },
496
- "auth": {
497
- "plugin": "auth",
498
- "methods": [
499
- "passkey",
500
- "google-oauth2"
501
- ],
502
- "session_verification": true
503
- },
504
660
  "status": {
505
661
  "command": "status",
506
662
  "refresh_seconds": 300
@@ -511,5 +667,12 @@
511
667
  "total-recall ssss status"
512
668
  ],
513
669
  "owned": "Documentation hub discovery, wiki page auditing, staleness tracking, and OpenWiki knowledge ingestion."
514
- }
670
+ },
671
+ "skills": [
672
+ {
673
+ "id": "openwiki",
674
+ "path": "./skills/openwiki/SKILL.md",
675
+ "description": "Multi-repo knowledge graph and documentation wiki engine for Total Recall."
676
+ }
677
+ ]
515
678
  }
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: openwiki
3
+ description: "Multi-repo knowledge graph and documentation wiki engine for Total Recall."
4
+ version: 0.4.0
5
+ repo_scoped: false
6
+ ---
7
+
8
+ # OpenWiki
9
+
10
+ Multi-repo knowledge graph and documentation wiki engine for Total Recall.
11
+
12
+ ## When to Use
13
+
14
+ Use the `openwiki` Total Recall plugin (`total-recall openwiki`) instead of ad-hoc scripts or raw commands whenever working on openwiki tasks.
15
+
16
+ ## Commands
17
+
18
+ ```bash
19
+ total-recall openwiki --help
20
+ total-recall openwiki context # Retrieve task-relevant wiki and explicitly linked source evidence with provenance and freshness
21
+ total-recall openwiki search # Search evidence passages in workspace, registered-vault or mesh documentation hubs
22
+ total-recall openwiki graph # Extract documentation link topology as JSON, Mermaid or DOT
23
+ total-recall openwiki generate # Generate documentation for the selected registered repository or current workspace
24
+ total-recall openwiki token # Inspect provider credential status or save a provider key through the shared auth owner
25
+ total-recall openwiki lint # Inspect documentation links and orphaned hubs without rewriting files
26
+ total-recall openwiki status # Show which OpenWiki subcommands are implemented
27
+ total-recall openwiki hubs # List indexed OpenWiki hubs and page counts
28
+ total-recall openwiki ingest # Ingest markdown documentation into the semantic knowledge graph
29
+ total-recall openwiki bootstrap # Create missing OpenWiki documentation pages in explicit brain and project directories
30
+ total-recall openwiki probe # Run HTTP 200 health verification probe
31
+ total-recall openwiki refresh # Report which registered projects' generated OpenWiki pages are stale; --apply updates existing wikis (openwiki/ only), never creates one, and skips excluded repositories
32
+ ```
@@ -9,14 +9,28 @@ import path from 'node:path';
9
9
  // No model default: models and prices change too often to fix one in code, and a stale
10
10
  // default (deepseek/deepseek-chat) cost about 5x a current model of the same family.
11
11
  // A refresh with no configured model stops before it calls a provider.
12
+ //
13
+ // exclude lists repository roots the refresh never touches: upstream clones,
14
+ // forks, backups and test probes. Registering a repository with Total Recall
15
+ // gives it a brain; it does not make its code something to document.
12
16
  export const DEFAULT_OPENWIKI_CONFIG = Object.freeze({
13
17
  provider: 'openrouter',
14
18
  model: null,
15
19
  fallback_model: null,
16
20
  max_tokens: 4096,
17
- timeout_ms: 300000
21
+ timeout_ms: 300000,
22
+ exclude: Object.freeze([])
18
23
  });
19
24
 
25
+ /** Absolute, de-duplicated, sorted repository roots. */
26
+ export function normalizeExclude(list) {
27
+ if (!Array.isArray(list)) return [];
28
+ const roots = list
29
+ .filter((entry) => typeof entry === 'string' && entry.trim() && path.isAbsolute(entry.trim()))
30
+ .map((entry) => path.resolve(entry.trim()));
31
+ return [...new Set(roots)].sort();
32
+ }
33
+
20
34
  export const ALLOWED_CONFIG_KEYS = Object.freeze([
21
35
  'provider',
22
36
  'model',
@@ -44,12 +58,12 @@ export function loadOpenWikiConfig(options = {}) {
44
58
  const filePath = resolveConfigPath(options);
45
59
  try {
46
60
  if (!fs.existsSync(filePath)) {
47
- return { ...DEFAULT_OPENWIKI_CONFIG };
61
+ return { ...DEFAULT_OPENWIKI_CONFIG, exclude: [] };
48
62
  }
49
63
  const raw = fs.readFileSync(filePath, 'utf8');
50
64
  const parsed = JSON.parse(raw);
51
65
  if (!parsed || typeof parsed !== 'object') {
52
- return { ...DEFAULT_OPENWIKI_CONFIG };
66
+ return { ...DEFAULT_OPENWIKI_CONFIG, exclude: [] };
53
67
  }
54
68
  return {
55
69
  provider: typeof parsed.provider === 'string' && parsed.provider ? parsed.provider : DEFAULT_OPENWIKI_CONFIG.provider,
@@ -60,10 +74,11 @@ export function loadOpenWikiConfig(options = {}) {
60
74
  : DEFAULT_OPENWIKI_CONFIG.max_tokens,
61
75
  timeout_ms: Number.isInteger(parsed.timeout_ms) && parsed.timeout_ms >= 30000 && parsed.timeout_ms <= 1800000
62
76
  ? parsed.timeout_ms
63
- : DEFAULT_OPENWIKI_CONFIG.timeout_ms
77
+ : DEFAULT_OPENWIKI_CONFIG.timeout_ms,
78
+ exclude: normalizeExclude(parsed.exclude)
64
79
  };
65
80
  } catch {
66
- return { ...DEFAULT_OPENWIKI_CONFIG };
81
+ return { ...DEFAULT_OPENWIKI_CONFIG, exclude: [] };
67
82
  }
68
83
  }
69
84
 
@@ -75,7 +90,8 @@ export function saveOpenWikiConfig(config, options = {}) {
75
90
  model: config.model ? String(config.model).trim() || null : null,
76
91
  fallback_model: config.fallback_model ? String(config.fallback_model).trim() || null : null,
77
92
  max_tokens: Number.isInteger(Number(config.max_tokens)) ? Math.max(512, Math.min(131072, Number(config.max_tokens))) : DEFAULT_OPENWIKI_CONFIG.max_tokens,
78
- timeout_ms: Number.isInteger(Number(config.timeout_ms)) ? Math.max(30000, Math.min(1800000, Number(config.timeout_ms))) : DEFAULT_OPENWIKI_CONFIG.timeout_ms
93
+ timeout_ms: Number.isInteger(Number(config.timeout_ms)) ? Math.max(30000, Math.min(1800000, Number(config.timeout_ms))) : DEFAULT_OPENWIKI_CONFIG.timeout_ms,
94
+ exclude: normalizeExclude(config.exclude)
79
95
  };
80
96
 
81
97
  if (!ALLOWED_PROVIDERS.includes(validated.provider)) {
@@ -123,7 +139,17 @@ export function setOpenWikiConfigValue(key, value, options = {}) {
123
139
  return saveOpenWikiConfig(current, options);
124
140
  }
125
141
 
126
- /** Reset configuration to defaults. */
142
+ /**
143
+ * Reset the generator settings to defaults. The exclude list is kept: a reset
144
+ * must not put clones and backups back into a paid refresh.
145
+ */
127
146
  export function resetOpenWikiConfig(options = {}) {
128
- return saveOpenWikiConfig(DEFAULT_OPENWIKI_CONFIG, options);
147
+ const { exclude } = loadOpenWikiConfig(options);
148
+ return saveOpenWikiConfig({ ...DEFAULT_OPENWIKI_CONFIG, exclude }, options);
149
+ }
150
+
151
+ /** Replace the list of repository roots the refresh never touches. */
152
+ export function setExcludedRoots(roots, options = {}) {
153
+ const current = loadOpenWikiConfig(options);
154
+ return saveOpenWikiConfig({ ...current, exclude: roots }, options);
129
155
  }
@@ -70,6 +70,12 @@ export async function generateWiki({
70
70
  throw new Error(`Target path does not exist: ${resolvedTarget}`);
71
71
  }
72
72
 
73
+ // An excluded repository (an upstream clone, fork, backup or probe) is never
74
+ // documented, even from inside its own checkout.
75
+ if ((loadOpenWikiConfig().exclude || []).includes(path.resolve(resolvedTarget))) {
76
+ throw new Error(`${repoName} is excluded from OpenWiki. To document it, first run: total-recall openwiki exclude --remove ${repoName}`);
77
+ }
78
+
73
79
  const outPath = outputDir ? path.resolve(resolvedTarget, outputDir) : path.join(resolvedTarget, 'openwiki');
74
80
 
75
81
  if (dryRun) {