total-recall-brain 3.46.2 → 3.47.1
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.
- package/bin/total-recall.mjs +5 -0
- package/frontend/dist/assets/index-CpsWeV4X.css +1 -0
- package/frontend/dist/assets/{index-D1goIPjC.js → index-poecbHSl.js} +100 -100
- package/frontend/dist/brand/total-recall-lockup-transparent.png +0 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/dist/sw.js +1 -1
- package/frontend/src/App.tsx +15 -81
- package/frontend/src/components/DashboardOverview.tsx +164 -0
- package/frontend/src/components/brand/BrandMark.tsx +8 -6
- package/frontend/src/components/plugins/PluginWorkspace.tsx +112 -57
- package/frontend/src/components/workspace/PluginHome.tsx +3 -3
- package/frontend/src/index.css +43 -11
- package/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/auth/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/auth/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/auth/plugin.json +30 -5
- package/scaffold/.agent/skills/total-recall/plugins/auth/skills/auth/SKILL.md +35 -0
- package/scaffold/.agent/skills/total-recall/plugins/auth/ui/home.js +494 -79
- package/scaffold/.agent/skills/total-recall/plugins/automations/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/automations/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/automations/plugin.json +33 -8
- package/scaffold/.agent/skills/total-recall/plugins/automations/skills/automations/SKILL.md +29 -0
- package/scaffold/.agent/skills/total-recall/plugins/automations/ui/chunks/dream-consolidation.md +17 -0
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/plugin.json +31 -4
- package/scaffold/.agent/skills/total-recall/plugins/code-quality/skills/code-quality/SKILL.md +27 -0
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/composable-cli/plugin.json +17 -3
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/plugin.json +24 -4
- package/scaffold/.agent/skills/total-recall/plugins/embeddings/skills/embeddings/SKILL.md +25 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/git/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/git/plugin.json +300 -58
- package/scaffold/.agent/skills/total-recall/plugins/git/skills/git/SKILL.md +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/src/ops/commit-memory.mjs +5 -33
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/git-fleet-ops.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/git/ui/chunks/git-publish.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/mesh/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/mesh/plugin.json +47 -14
- package/scaffold/.agent/skills/total-recall/plugins/mesh/skills/mesh/SKILL.md +36 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/cli.mjs +6 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/plugin.json +5 -2
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/cascade.mjs +4 -2
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/coordinator.mjs +28 -9
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/dispatch.mjs +7 -1
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/model-selection.mjs +59 -0
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/remote-operation.mjs +3 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/router.mjs +9 -3
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/src/worker.mjs +50 -6
- package/scaffold/.agent/skills/total-recall/plugins/meta-harness/ui/chunks/session-controls.md +16 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/cli.mjs +175 -17
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package-lock.json +6 -6
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/plugin.json +242 -31
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/skills/openwiki/SKILL.md +32 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/config.mjs +41 -15
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/generate.mjs +29 -22
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/graph.mjs +20 -33
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/lint.mjs +42 -49
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/markdown-links.mjs +112 -0
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/mesh-vaults.mjs +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/refresh.mjs +219 -65
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/search.mjs +2 -1
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/src/upstream-watcher.mjs +21 -3
- package/scaffold/.agent/skills/total-recall/plugins/openwiki/ui/panel.js +51 -2
- package/scaffold/.agent/skills/total-recall/plugins/security/package-lock.json +4 -4
- package/scaffold/.agent/skills/total-recall/plugins/security/package.json +1 -1
- package/scaffold/.agent/skills/total-recall/plugins/security/plugin.json +22 -5
- package/scaffold/.agent/skills/total-recall/plugins/ssss/package.json +3 -2
- package/scaffold/.agent/skills/total-recall/plugins/ssss/plugin.json +169 -37
- package/scaffold/.agent/skills/total-recall/plugins/ssss/skills/ssss/SKILL.md +30 -0
- package/src/cli/context.mjs +6 -2
- package/src/cli/plugin/create.mjs +2 -1
- package/src/cli/plugin/monetization.mjs +66 -32
- package/src/cli/plugin/search.mjs +25 -3
- package/src/cli/preflight.mjs +40 -6
- package/src/core/context-compactor.mjs +2 -0
- package/src/core/gate-mode.mjs +13 -24
- package/src/core/plugin-distribution.mjs +35 -1
- package/src/core/preflight-gate.mjs +28 -8
- package/src/core/preflight-receipt.mjs +11 -0
- package/src/server/routes/vault.mjs +1 -0
- package/frontend/dist/assets/index-BRYE1jmv.css +0 -1
|
@@ -5,10 +5,13 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import fs from "node:fs";
|
|
7
7
|
import path from "node:path";
|
|
8
|
+
import { pathToFileURL } from "node:url";
|
|
8
9
|
import { runBootstrapCommand } from './src/bootstrap.mjs';
|
|
9
|
-
import { describeRetention, hasWiki, isDue, readProjects, refreshProject, refreshProjectAsync, resolveKey, staleness } from './src/refresh.mjs';
|
|
10
|
+
import { CREDIT_REFUSAL, NO_MODEL, describeRetention, hasWiki, isDue, readProjects, refreshProject, refreshProjectAsync, resolveKey, staleness } from './src/refresh.mjs';
|
|
11
|
+
|
|
12
|
+
const DEFAULT_REPO_CONCURRENCY = 2;
|
|
10
13
|
import { watchUpstream, propagateUpdates, readUpstreamState, bundledGeneratorVersion } from './src/upstream-watcher.mjs';
|
|
11
|
-
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';
|
|
12
15
|
import { discoverAllHubs } from './src/mesh-vaults.mjs';
|
|
13
16
|
import { searchWikiHubs } from './src/search.mjs';
|
|
14
17
|
import { buildKnowledgeGraph } from './src/graph.mjs';
|
|
@@ -26,12 +29,14 @@ import { refreshDiagnostics } from './src/refresh-diagnostics.mjs';
|
|
|
26
29
|
* Defaults to a report; --apply performs the refreshes, because regenerating a
|
|
27
30
|
* repository's documentation is a write to that repository.
|
|
28
31
|
*/
|
|
32
|
+
// OpenRouter answers 402 when the balance cannot cover a request.
|
|
33
|
+
|
|
29
34
|
export async function refreshCommand(args, {
|
|
30
35
|
read = readProjects, dueFor = isDue, refresh = refreshProjectAsync,
|
|
31
|
-
getKey = resolveKey, configFor = loadOpenWikiConfig,
|
|
36
|
+
getKey = resolveKey, configFor = loadOpenWikiConfig, clock = Date.now,
|
|
32
37
|
} = {}) {
|
|
33
38
|
if (args.includes('--help') || args.includes('-h')) {
|
|
34
|
-
console.log('Usage: total-recall openwiki refresh [--repo <name>] [--apply] [--force] [--diagnostics [--slot <local-minute>]] [--json]');
|
|
39
|
+
console.log('Usage: total-recall openwiki refresh [--repo <name>] [--apply [--budget-ms <n>]] [--force] [--diagnostics [--slot <local-minute>]] [--json]');
|
|
35
40
|
return;
|
|
36
41
|
}
|
|
37
42
|
const json = args.includes('--json');
|
|
@@ -78,8 +83,14 @@ export async function refreshCommand(args, {
|
|
|
78
83
|
continue;
|
|
79
84
|
}
|
|
80
85
|
if (!state.due) {
|
|
81
|
-
if (state.
|
|
86
|
+
if (state.excluded) {
|
|
87
|
+
reports.push({ ...project, action: 'excluded', reason: state.reason });
|
|
88
|
+
} else if (state.skipped) {
|
|
82
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 });
|
|
92
|
+
} else if (state.held) {
|
|
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 });
|
|
83
94
|
} else {
|
|
84
95
|
reports.push({ ...project, action: 'current', reason: state.reason, generationCommit: state.generationCommit, generationTime: state.generationTime, generatedAt: state.generatedAt, commitsSince: state.commitsSince });
|
|
85
96
|
}
|
|
@@ -102,6 +113,12 @@ export async function refreshCommand(args, {
|
|
|
102
113
|
let payloadBudgetNote = null;
|
|
103
114
|
if (apply && due.length) {
|
|
104
115
|
const config = configFor();
|
|
116
|
+
if (!String(config.model || '').trim()) {
|
|
117
|
+
if (json) console.log(JSON.stringify({ ok: false, error: NO_MODEL, reports }));
|
|
118
|
+
else console.error(`OpenWiki refresh: ${NO_MODEL}`);
|
|
119
|
+
process.exitCode = 1;
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
105
122
|
const { key, from } = getKey({ provider: config.provider });
|
|
106
123
|
if (!key) {
|
|
107
124
|
const keyName = config.provider === 'google' ? 'GOOGLE_API_KEY' : 'OPENROUTER_API_KEY';
|
|
@@ -111,21 +128,37 @@ export async function refreshCommand(args, {
|
|
|
111
128
|
process.exitCode = 1;
|
|
112
129
|
return;
|
|
113
130
|
}
|
|
131
|
+
// Repositories refreshed at once. Each one is a separate paid generator run, so
|
|
132
|
+
// the default stays low; OpenWiki's own page concurrency is left at its default.
|
|
114
133
|
const concurrencyArg = args.find((a) => a.startsWith('--concurrency='));
|
|
115
134
|
const concurrencyIndex = args.indexOf('--concurrency');
|
|
116
135
|
const concurrency = Math.max(1, parseInt(
|
|
117
|
-
concurrencyArg ? concurrencyArg.slice('--concurrency='.length) : (concurrencyIndex >= 0 ? args[concurrencyIndex + 1] :
|
|
136
|
+
concurrencyArg ? concurrencyArg.slice('--concurrency='.length) : (concurrencyIndex >= 0 ? args[concurrencyIndex + 1] : String(DEFAULT_REPO_CONCURRENCY)),
|
|
118
137
|
10
|
|
119
|
-
) ||
|
|
138
|
+
) || DEFAULT_REPO_CONCURRENCY);
|
|
139
|
+
|
|
140
|
+
// A scheduled run passes the time it has left before the task runner kills
|
|
141
|
+
// it. A generation started without room to finish is killed part-way, marked
|
|
142
|
+
// interrupted and paid for again on the next attempt, so none is started.
|
|
143
|
+
const budgetArg = args.find((a) => a.startsWith('--budget-ms='));
|
|
144
|
+
const budgetIndex = args.indexOf('--budget-ms');
|
|
145
|
+
const budgetMs = Number(budgetArg ? budgetArg.slice('--budget-ms='.length) : (budgetIndex >= 0 ? args[budgetIndex + 1] : NaN));
|
|
146
|
+
const generationMs = Number.isInteger(config.timeout_ms) ? config.timeout_ms : 300000;
|
|
147
|
+
const dispatchStarted = clock();
|
|
148
|
+
let stopReason = null;
|
|
120
149
|
|
|
121
150
|
if (!json) {
|
|
122
|
-
console.log(`OpenWiki refresh (apply): dispatching ${due.length} projects with concurrency ${concurrency}`);
|
|
151
|
+
console.log(`OpenWiki refresh (apply): dispatching ${due.length} projects with concurrency ${concurrency}${Number.isFinite(budgetMs) ? ` within ${Math.round(budgetMs / 1000)}s` : ''}`);
|
|
123
152
|
}
|
|
124
153
|
|
|
125
154
|
let queueIndex = 0;
|
|
126
155
|
let completedCount = 0;
|
|
127
156
|
const worker = async () => {
|
|
128
157
|
while (queueIndex < due.length) {
|
|
158
|
+
if (!stopReason && Number.isFinite(budgetMs) && clock() - dispatchStarted + generationMs > budgetMs) {
|
|
159
|
+
stopReason = `not started: fewer than ${Math.round(generationMs / 1000)}s left in this run's ${Math.round(budgetMs / 1000)}s budget`;
|
|
160
|
+
}
|
|
161
|
+
if (stopReason) break;
|
|
129
162
|
const itemIndex = queueIndex++;
|
|
130
163
|
const entry = due[itemIndex];
|
|
131
164
|
const mode = entry.mode || (entry.uninitialized ? 'init' : 'update');
|
|
@@ -142,6 +175,9 @@ export async function refreshCommand(args, {
|
|
|
142
175
|
result = { action: 'failed', reason: error.message.split(key).join('[REDACTED]') };
|
|
143
176
|
}
|
|
144
177
|
completedCount++;
|
|
178
|
+
if (!stopReason && CREDIT_REFUSAL.test(String(result.reason || ''))) {
|
|
179
|
+
stopReason = `not started: the provider refused ${entry.name} for credit; add credit, then refresh again`;
|
|
180
|
+
}
|
|
145
181
|
const index = reports.findIndex((r) => r.root === entry.root);
|
|
146
182
|
reports[index] = { ...reports[index], ...result, credential: from };
|
|
147
183
|
if (!json) {
|
|
@@ -154,6 +190,11 @@ export async function refreshCommand(args, {
|
|
|
154
190
|
|
|
155
191
|
const workers = Array.from({ length: Math.min(concurrency, due.length) }, () => worker());
|
|
156
192
|
await Promise.all(workers);
|
|
193
|
+
for (const entry of due.slice(queueIndex)) {
|
|
194
|
+
const index = reports.findIndex((r) => r.root === entry.root);
|
|
195
|
+
reports[index] = { ...reports[index], action: 'deferred', reason: stopReason };
|
|
196
|
+
}
|
|
197
|
+
if (stopReason && queueIndex < due.length) payloadBudgetNote = `${due.length - queueIndex} project(s) ${stopReason}.`;
|
|
157
198
|
}
|
|
158
199
|
|
|
159
200
|
const failed = reports.filter((r) => r.action === 'failed');
|
|
@@ -165,12 +206,15 @@ export async function refreshCommand(args, {
|
|
|
165
206
|
note: payloadBudgetNote,
|
|
166
207
|
counts: {
|
|
167
208
|
registered: projects.length,
|
|
168
|
-
withPages: reports.filter((r) => r.action
|
|
209
|
+
withPages: reports.filter((r) => !['skipped', 'excluded'].includes(r.action) && !r.uninitialized).length,
|
|
169
210
|
due: due.length,
|
|
170
211
|
uninitialized: reports.filter((r) => r.uninitialized).length,
|
|
212
|
+
excluded: reports.filter((r) => r.action === 'excluded').length,
|
|
171
213
|
refreshed: reports.filter((r) => r.action === 'refreshed' || r.action === 'initialized').length,
|
|
172
214
|
failed: failed.length,
|
|
173
215
|
partial: partial.length,
|
|
216
|
+
held: reports.filter((r) => r.action === 'held').length,
|
|
217
|
+
deferred: reports.filter((r) => r.action === 'deferred').length,
|
|
174
218
|
skipped: reports.filter((r) => r.action === 'skipped').length,
|
|
175
219
|
current: reports.filter((r) => r.action === 'current').length,
|
|
176
220
|
},
|
|
@@ -178,11 +222,11 @@ export async function refreshCommand(args, {
|
|
|
178
222
|
};
|
|
179
223
|
if (json) console.log(JSON.stringify(payload, null, 2));
|
|
180
224
|
else {
|
|
181
|
-
console.log(`OpenWiki refresh (${apply ? 'apply' : 'report'}): ${payload.counts.registered} registered, ${payload.counts.due} due
|
|
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`);
|
|
182
226
|
// Put failures last so bounded scheduler tails retain their causes.
|
|
183
227
|
for (const r of [...reports].sort((a, b) => Number(['failed', 'partial'].includes(a.action)) - Number(['failed', 'partial'].includes(b.action)))) {
|
|
184
|
-
if (r.action === 'current') continue;
|
|
185
|
-
const age = r.action === 'skipped' ? 'outside repository generation' : r.generationTime ? `generated ${r.generationTime} at ${r.generationCommit}` : r.uninitialized ? '
|
|
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');
|
|
186
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}` : ''}`);
|
|
187
231
|
}
|
|
188
232
|
if (payloadBudgetNote) console.log(payloadBudgetNote);
|
|
@@ -438,6 +482,8 @@ async function generateCommand(args) {
|
|
|
438
482
|
|
|
439
483
|
if (json) {
|
|
440
484
|
console.log(JSON.stringify(res, null, 2));
|
|
485
|
+
} else if (res.dryRun) {
|
|
486
|
+
console.log(`\n${res.message}\n`);
|
|
441
487
|
} else {
|
|
442
488
|
console.log(`\n✔ Generated documentation for ${res.repoName} (${Math.round((res.durationMs || 0)/1000)}s) via ${res.generatorVia}`);
|
|
443
489
|
console.log(` Output: ${res.outputDir}\n`);
|
|
@@ -572,8 +618,8 @@ async function configCommand(args) {
|
|
|
572
618
|
else {
|
|
573
619
|
console.log(`\nOpenWiki Configuration (${configPath}):`);
|
|
574
620
|
console.log(` Provider : ${config.provider}`);
|
|
575
|
-
console.log(` Model : ${config.model}`);
|
|
576
|
-
console.log(` Fallback Model : ${config.fallback_model}`);
|
|
621
|
+
console.log(` Model : ${config.model || 'not set (refreshes stop until one is chosen)'}`);
|
|
622
|
+
console.log(` Fallback Model : ${config.fallback_model || 'not set'}`);
|
|
577
623
|
console.log(` Max Tokens : ${config.max_tokens}`);
|
|
578
624
|
console.log(` Timeout (ms) : ${config.timeout_ms}\n`);
|
|
579
625
|
}
|
|
@@ -624,9 +670,116 @@ async function configCommand(args) {
|
|
|
624
670
|
}
|
|
625
671
|
}
|
|
626
672
|
|
|
673
|
+
/**
|
|
674
|
+
* The scheduled run. The Automations runner kills it at the task's declared
|
|
675
|
+
* timeout_ms, so it dispatches only generations that can finish a minute
|
|
676
|
+
* before that.
|
|
677
|
+
*/
|
|
678
|
+
export function autoRefreshBudgetMs(manifestPath = new URL('./plugin.json', import.meta.url)) {
|
|
679
|
+
let timeout = null;
|
|
680
|
+
try {
|
|
681
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
682
|
+
timeout = manifest.tasks?.find((task) => task.command === 'auto-refresh')?.timeout_ms ?? null;
|
|
683
|
+
} catch { /* no readable manifest: use the runner's own limit */ }
|
|
684
|
+
return Math.max(60000, (Number.isInteger(timeout) ? timeout : 600000) - 60000);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
async function loadScheduleCore() {
|
|
688
|
+
const root = process.env.TR_PACKAGE_ROOT;
|
|
689
|
+
if (!root) throw new Error('Run through total-recall openwiki schedule');
|
|
690
|
+
const load = (module) => import(pathToFileURL(path.join(root, 'src', 'core', module)).href);
|
|
691
|
+
const [loader, store, mesh] = await Promise.all([load('plugin-loader.mjs'), load('plugin-store.mjs'), load('mesh.mjs')]);
|
|
692
|
+
return { getPlugin: loader.getPlugin, readPluginRecord: store.readPluginRecord, patchPluginRecord: store.patchPluginRecord, getMeshSelf: mesh.getMeshSelf };
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Where the nightly refresh runs. Like other selected-node tasks, the placement is
|
|
697
|
+
* task_nodes['auto-refresh'] in this plugin's record; with none, the task stays idle.
|
|
698
|
+
* Pick the node that holds the repository checkouts.
|
|
699
|
+
*/
|
|
700
|
+
export async function scheduleCommand(args = [], { core = null, config = loadOpenWikiConfig } = {}) {
|
|
701
|
+
const json = args.includes('--json');
|
|
702
|
+
const usage = 'Usage: total-recall openwiki schedule [--node <mesh hostname>|--node self|--off] [--json]';
|
|
703
|
+
try {
|
|
704
|
+
if (args.includes('--help') || args.includes('-h')) { console.log(usage); return; }
|
|
705
|
+
const nodeIndex = args.indexOf('--node');
|
|
706
|
+
const nodeArg = nodeIndex >= 0 ? args[nodeIndex + 1] : null;
|
|
707
|
+
if (nodeIndex >= 0 && (!nodeArg || nodeArg.startsWith('--'))) throw new Error(usage);
|
|
708
|
+
const off = args.includes('--off');
|
|
709
|
+
if (off && nodeArg) throw new Error(usage);
|
|
710
|
+
const owner = core || await loadScheduleCore();
|
|
711
|
+
const plugin = owner.getPlugin('openwiki');
|
|
712
|
+
if (!plugin?.valid) throw new Error('Install a valid OpenWiki plugin first');
|
|
713
|
+
const record = owner.readPluginRecord(plugin) || {};
|
|
714
|
+
const task = plugin.manifest?.tasks?.find((entry) => entry.command === 'auto-refresh') || null;
|
|
715
|
+
let node = record.task_nodes?.['auto-refresh'] || null;
|
|
716
|
+
if (off || nodeArg) {
|
|
717
|
+
node = off ? null : nodeArg === 'self' ? owner.getMeshSelf()?.hostname || null : nodeArg;
|
|
718
|
+
if (!off && !node) throw new Error('This machine has no mesh hostname; name the node with --node <hostname>');
|
|
719
|
+
const taskNodes = { ...(record.task_nodes || {}) };
|
|
720
|
+
if (node) taskNodes['auto-refresh'] = node;
|
|
721
|
+
else delete taskNodes['auto-refresh'];
|
|
722
|
+
await owner.patchPluginRecord(plugin, { task_nodes: taskNodes });
|
|
723
|
+
}
|
|
724
|
+
const model = config().model || null;
|
|
725
|
+
const payload = { ok: true, task: 'auto-refresh', schedule: task?.schedule || null, placement: task?.placement || null, node, model, ready: Boolean(node && model) };
|
|
726
|
+
if (json) console.log(JSON.stringify(payload, null, 2));
|
|
727
|
+
else {
|
|
728
|
+
console.log(`OpenWiki nightly refresh: ${node ? `runs on ${node}` : 'idle (no node selected)'} at "${payload.schedule}"`);
|
|
729
|
+
console.log(` Model: ${model || `not set — ${NO_MODEL}`}`);
|
|
730
|
+
}
|
|
731
|
+
} catch (err) {
|
|
732
|
+
if (json) console.log(JSON.stringify({ ok: false, error: err.message }));
|
|
733
|
+
else console.error(`OpenWiki schedule: ${err.message}`);
|
|
734
|
+
process.exitCode = 1;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
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
|
+
|
|
627
778
|
async function autoRefreshCommand(args = []) {
|
|
628
|
-
const
|
|
629
|
-
|
|
779
|
+
const forwardArgs = args.includes('--apply') ? [...args] : ['--apply', ...args];
|
|
780
|
+
if (!forwardArgs.some((a) => a === '--budget-ms' || a.startsWith('--budget-ms='))) {
|
|
781
|
+
forwardArgs.push(`--budget-ms=${autoRefreshBudgetMs()}`);
|
|
782
|
+
}
|
|
630
783
|
return refreshCommand(forwardArgs);
|
|
631
784
|
}
|
|
632
785
|
|
|
@@ -651,6 +804,8 @@ IMPLEMENTED.autorefresh = autoRefreshCommand;
|
|
|
651
804
|
IMPLEMENTED.watch = watchCommand;
|
|
652
805
|
IMPLEMENTED.propagate = propagateCommand;
|
|
653
806
|
IMPLEMENTED.config = configCommand;
|
|
807
|
+
IMPLEMENTED.schedule = scheduleCommand;
|
|
808
|
+
IMPLEMENTED.exclude = excludeCommand;
|
|
654
809
|
IMPLEMENTED.search = searchCommand;
|
|
655
810
|
IMPLEMENTED.graph = graphCommand;
|
|
656
811
|
IMPLEMENTED.token = tokenCommand;
|
|
@@ -721,7 +876,10 @@ export async function run(argv = process.argv) {
|
|
|
721
876
|
Create missing plugin-owned documentation pages
|
|
722
877
|
refresh [--repo <name>] [--apply] [--force] [--json]
|
|
723
878
|
Report which registered projects' generated pages are stale;
|
|
724
|
-
--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
|
|
725
883
|
auto-refresh [--repo <name>] [--force] [--json]
|
|
726
884
|
Automated daemon trigger to regenerate stale pages across repositories
|
|
727
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
|
+
"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.
|
|
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.
|
|
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.
|
|
5533
|
-
"resolved": "https://registry.npmjs.org/total-recall-brain/-/total-recall-brain-3.
|
|
5534
|
-
"integrity": "sha512-
|
|
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
|
+
"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"
|