skillwiki 0.10.86 → 0.10.88
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/dist/{chunk-GZKT2XC5.js → chunk-5QFHISNH.js} +5 -4
- package/dist/{chunk-BO7JIJIA.js → chunk-6WE7E6VB.js} +11 -4
- package/dist/{chunk-CGQQS7MO.js → chunk-ECOEJABP.js} +1 -1
- package/dist/{chunk-5BNCYHRN.js → chunk-QFRZDTJY.js} +2 -2
- package/dist/cli.js +256 -79
- package/dist/{managed-write-preflight-BAIL5GMW.js → managed-write-preflight-2Y5Q2WH4.js} +2 -2
- package/dist/skillwiki-mcp.js +4 -4
- package/dist/{sources-TNX2VEMB.js → sources-A5GFRY3F.js} +2 -2
- package/dist/vault-sync/scripts/wiki-snapshot.sh +43 -6
- package/package.json +1 -1
- package/skills/.claude-plugin/plugin.json +1 -1
- package/skills/.codex-plugin/plugin.json +1 -1
- package/skills/.cursor-plugin/plugin.json +1 -1
- package/skills/package.json +1 -1
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
snapshotterAliasForLocalHost,
|
|
41
41
|
toUndirectedWeighted,
|
|
42
42
|
writeDotenv
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-6WE7E6VB.js";
|
|
44
44
|
import {
|
|
45
45
|
atomicWriteText,
|
|
46
46
|
prepareTypedPage
|
|
@@ -57,11 +57,11 @@ import {
|
|
|
57
57
|
planSourceCompileRelease,
|
|
58
58
|
planSourceReview,
|
|
59
59
|
runSourcesPending
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-ECOEJABP.js";
|
|
61
61
|
import {
|
|
62
62
|
eventPathFor,
|
|
63
63
|
writeLogEvent
|
|
64
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-QFRZDTJY.js";
|
|
65
65
|
import {
|
|
66
66
|
CompoundSchema,
|
|
67
67
|
ExitCode,
|
|
@@ -4496,6 +4496,7 @@ var HYGIENE_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
4496
4496
|
"lint",
|
|
4497
4497
|
"lint --fix",
|
|
4498
4498
|
"status",
|
|
4499
|
+
"copy-status",
|
|
4499
4500
|
"path",
|
|
4500
4501
|
"fleet context",
|
|
4501
4502
|
"fleet validate",
|
|
@@ -6462,7 +6463,7 @@ async function runQuery(input) {
|
|
|
6462
6463
|
}
|
|
6463
6464
|
let pendingSources;
|
|
6464
6465
|
if (input.includePending) {
|
|
6465
|
-
const { runSourcesPending: runSourcesPending2 } = await import("./sources-
|
|
6466
|
+
const { runSourcesPending: runSourcesPending2 } = await import("./sources-A5GFRY3F.js");
|
|
6466
6467
|
const pending = await runSourcesPending2({
|
|
6467
6468
|
vault: input.vault,
|
|
6468
6469
|
match: input.text,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
resolveExistingRegularFileInsideVault,
|
|
23
23
|
stripFencedBlocks,
|
|
24
24
|
writeLogEvent
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-QFRZDTJY.js";
|
|
26
26
|
import {
|
|
27
27
|
ExitCode,
|
|
28
28
|
FleetManifestSchema,
|
|
@@ -3333,6 +3333,7 @@ function buildCliSurface() {
|
|
|
3333
3333
|
program.command("health").option("--wiki <name>").option("--sync <mode>").option("--no-fail").option("--out <path>").option("--examples <n>");
|
|
3334
3334
|
program.command("doctor").option("--check-snapshotter").option("--check-mcp");
|
|
3335
3335
|
program.command("status").option("--wiki <name>");
|
|
3336
|
+
program.command("copy-status").option("--wiki <name>");
|
|
3336
3337
|
program.command("archive").option("--wiki <name>").option("--cascade").option("--apply").option("--approve <token>").option("--remote <remote>").option("--remote-delete").option("--max-remote-deletes <n>");
|
|
3337
3338
|
program.command("remove").option("--wiki <name>").option("--remote <remote>").option("--remote-delete").option("--max-remote-deletes <n>").option("--reason <text>");
|
|
3338
3339
|
program.command("drift").option("--apply").option("--affected-pages").option("--new <date>").option("--wiki <name>");
|
|
@@ -3405,7 +3406,7 @@ function buildCliSurface() {
|
|
|
3405
3406
|
const indexCmd = program.commands.find((c) => c.name() === "index");
|
|
3406
3407
|
indexCmd.command("rebuild").option("--write").option("--wiki <name>");
|
|
3407
3408
|
const projectionsCmd = program.commands.find((c) => c.name() === "projections");
|
|
3408
|
-
projectionsCmd.command("materialize").option("--write").option("--converge-vault <dir>").option("--wiki <name>");
|
|
3409
|
+
projectionsCmd.command("materialize").option("--write").option("--converge-vault <dir>").option("--events-from <dir>").option("--wiki <name>");
|
|
3409
3410
|
projectionsCmd.command("repair-legacy").requiredOption("--event-operation-id <id>").option("--write").option("--converge-vault <dir>").option("--wiki <name>");
|
|
3410
3411
|
const syncCmd = program.commands.find((c) => c.name() === "sync");
|
|
3411
3412
|
syncCmd.command("status").option("--wiki <name>").option("--include-stashes").option("--include-remote-health").option("--check-snapshotter");
|
|
@@ -5339,9 +5340,14 @@ async function runSyncLintDelta(input) {
|
|
|
5339
5340
|
|
|
5340
5341
|
// src/utils/git.ts
|
|
5341
5342
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
5342
|
-
function git(cwd, args) {
|
|
5343
|
+
function git(cwd, args, opts) {
|
|
5343
5344
|
try {
|
|
5344
|
-
return execFileSync2("git", args, {
|
|
5345
|
+
return execFileSync2("git", args, {
|
|
5346
|
+
cwd,
|
|
5347
|
+
encoding: "utf8",
|
|
5348
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
5349
|
+
...opts?.timeoutMs !== void 0 ? { timeout: opts.timeoutMs } : {}
|
|
5350
|
+
}).trim();
|
|
5345
5351
|
} catch {
|
|
5346
5352
|
return "";
|
|
5347
5353
|
}
|
|
@@ -7413,6 +7419,7 @@ export {
|
|
|
7413
7419
|
VAULT_GENERATED_COMMIT_PATHS,
|
|
7414
7420
|
VAULT_COMMIT_PATHSPEC,
|
|
7415
7421
|
stageVaultContentChanges,
|
|
7422
|
+
REMOTE_PROBE_TIMEOUT_MS,
|
|
7416
7423
|
resolveWikiS3Remote,
|
|
7417
7424
|
probeGithubReachability,
|
|
7418
7425
|
probeS3Reachability,
|
|
@@ -203,8 +203,8 @@ async function writeLogEvent(vault, event) {
|
|
|
203
203
|
return err("WRITE_FAILED", { path: rel, message: String(error) });
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
|
-
async function readLogEvents(vault) {
|
|
207
|
-
const root = join(vault, "meta", "log-events");
|
|
206
|
+
async function readLogEvents(vault, opts) {
|
|
207
|
+
const root = opts?.eventsRoot ?? join(vault, "meta", "log-events");
|
|
208
208
|
let days;
|
|
209
209
|
try {
|
|
210
210
|
days = (await readdir(root, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => d.name).sort();
|
package/dist/cli.js
CHANGED
|
@@ -52,7 +52,7 @@ import {
|
|
|
52
52
|
snapshotterHealthChecks,
|
|
53
53
|
upsertIndexEntry,
|
|
54
54
|
vectorIndexStatus
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-5QFHISNH.js";
|
|
56
56
|
import {
|
|
57
57
|
normalizeDistTag,
|
|
58
58
|
readCache,
|
|
@@ -69,6 +69,7 @@ import {
|
|
|
69
69
|
import {
|
|
70
70
|
FLEET_REL_PATH,
|
|
71
71
|
REDACTED_MALFORMED_REFERENCE,
|
|
72
|
+
REMOTE_PROBE_TIMEOUT_MS,
|
|
72
73
|
VAULT_COMMIT_PATHSPEC,
|
|
73
74
|
VAULT_GENERATED_COMMIT_PATHS,
|
|
74
75
|
VAULT_HYGIENE_GITIGNORE_PATTERNS,
|
|
@@ -109,6 +110,7 @@ import {
|
|
|
109
110
|
parseJournalEnv,
|
|
110
111
|
planAndMaybePruneRemoteObjects,
|
|
111
112
|
planRawStructuralMove,
|
|
113
|
+
probeS3Reachability,
|
|
112
114
|
profileKey,
|
|
113
115
|
readJournal,
|
|
114
116
|
readLastOp,
|
|
@@ -119,6 +121,7 @@ import {
|
|
|
119
121
|
resolveFleetHostId,
|
|
120
122
|
resolveInitTimePath,
|
|
121
123
|
resolveRuntimePath,
|
|
124
|
+
resolveWikiS3Remote,
|
|
122
125
|
rewriteRawSourceReferences,
|
|
123
126
|
runAudit,
|
|
124
127
|
runDedup,
|
|
@@ -153,7 +156,7 @@ import {
|
|
|
153
156
|
supersedeStaleReviewRequiredJournals,
|
|
154
157
|
taxonomyCommentForPage,
|
|
155
158
|
writeDotenv
|
|
156
|
-
} from "./chunk-
|
|
159
|
+
} from "./chunk-6WE7E6VB.js";
|
|
157
160
|
import {
|
|
158
161
|
assertTargetInsideVault,
|
|
159
162
|
atomicWriteText,
|
|
@@ -166,7 +169,7 @@ import {
|
|
|
166
169
|
inventorySources,
|
|
167
170
|
planSourceDisposition,
|
|
168
171
|
runSourcesPending
|
|
169
|
-
} from "./chunk-
|
|
172
|
+
} from "./chunk-ECOEJABP.js";
|
|
170
173
|
import {
|
|
171
174
|
authorizeRawOperation,
|
|
172
175
|
buildSourceReferenceIndex,
|
|
@@ -183,7 +186,7 @@ import {
|
|
|
183
186
|
resolveExistingRegularFileInsideVault,
|
|
184
187
|
validateLogEvent,
|
|
185
188
|
writeLogEvent
|
|
186
|
-
} from "./chunk-
|
|
189
|
+
} from "./chunk-QFRZDTJY.js";
|
|
187
190
|
import {
|
|
188
191
|
ExitCode,
|
|
189
192
|
MetaSchema,
|
|
@@ -207,7 +210,7 @@ import {
|
|
|
207
210
|
} from "./chunk-XJR3XXP5.js";
|
|
208
211
|
|
|
209
212
|
// src/cli.ts
|
|
210
|
-
import { join as
|
|
213
|
+
import { join as join43 } from "path";
|
|
211
214
|
import { Command } from "commander";
|
|
212
215
|
|
|
213
216
|
// src/utils/output.ts
|
|
@@ -2030,7 +2033,7 @@ async function runLogMigrateLegacy(input) {
|
|
|
2030
2033
|
}
|
|
2031
2034
|
|
|
2032
2035
|
// src/commands/projections-materialize.ts
|
|
2033
|
-
import { readFileSync as readFileSync7 } from "fs";
|
|
2036
|
+
import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
|
|
2034
2037
|
import { join as join12 } from "path";
|
|
2035
2038
|
var defaultDeps = {
|
|
2036
2039
|
writeText: (path, text) => atomicWriteText(path, text)
|
|
@@ -2039,9 +2042,18 @@ async function runProjectionsMaterialize(input, deps = defaultDeps) {
|
|
|
2039
2042
|
const fleet = await loadFleetManifestAndHost({ vault: input.vault, hostId: input.hostId });
|
|
2040
2043
|
const auth = resolveProjectionAuthority(fleet);
|
|
2041
2044
|
if (!auth.ok) return { exitCode: ExitCode.PREFLIGHT_FAILED, result: auth };
|
|
2045
|
+
if (input.eventsFrom && !existsSync3(input.eventsFrom)) {
|
|
2046
|
+
return {
|
|
2047
|
+
exitCode: ExitCode.PREFLIGHT_FAILED,
|
|
2048
|
+
result: err("PREFLIGHT_FAILED", {
|
|
2049
|
+
reason: "events-from-missing",
|
|
2050
|
+
events_from: input.eventsFrom
|
|
2051
|
+
})
|
|
2052
|
+
};
|
|
2053
|
+
}
|
|
2042
2054
|
const indexProj = await renderRootIndex({ vault: input.vault });
|
|
2043
2055
|
if (!indexProj.ok) return { exitCode: ExitCode.SCHEME_REJECTED, result: indexProj };
|
|
2044
|
-
const events = await readLogEvents(input.vault);
|
|
2056
|
+
const events = await readLogEvents(input.vault, { eventsRoot: input.eventsFrom });
|
|
2045
2057
|
if (!events.ok) return { exitCode: ExitCode.SCHEME_REJECTED, result: events };
|
|
2046
2058
|
const logText = renderLogProjection(events.data);
|
|
2047
2059
|
let curIndex = "";
|
|
@@ -2382,7 +2394,7 @@ async function runProjectionsRepairLegacy(input, deps = defaultDeps2) {
|
|
|
2382
2394
|
|
|
2383
2395
|
// src/commands/claim.ts
|
|
2384
2396
|
import { mkdir as mkdir4, writeFile as writeFile3, readFile as readFile5 } from "fs/promises";
|
|
2385
|
-
import { existsSync as
|
|
2397
|
+
import { existsSync as existsSync4, statSync } from "fs";
|
|
2386
2398
|
import { join as join14 } from "path";
|
|
2387
2399
|
function extractDate(filename) {
|
|
2388
2400
|
const m = filename.match(/^(\d{4}-\d{2}-\d{2})/);
|
|
@@ -2392,11 +2404,11 @@ function extractSlugFromFilename(filename) {
|
|
|
2392
2404
|
return filename.replace(/^\d{4}-\d{2}-\d{2}-/, "").replace(/^(task|bug|idea|note|observation)-/, "").replace(/\.md$/, "");
|
|
2393
2405
|
}
|
|
2394
2406
|
async function runClaim(input) {
|
|
2395
|
-
if (!
|
|
2407
|
+
if (!existsSync4(input.vault) || !statSync(input.vault).isDirectory()) {
|
|
2396
2408
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { path: input.vault }) };
|
|
2397
2409
|
}
|
|
2398
2410
|
const absTranscript = join14(input.vault, input.transcript);
|
|
2399
|
-
if (!
|
|
2411
|
+
if (!existsSync4(absTranscript)) {
|
|
2400
2412
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: input.transcript }) };
|
|
2401
2413
|
}
|
|
2402
2414
|
const content = await readFile5(absTranscript, "utf8");
|
|
@@ -2421,7 +2433,7 @@ async function runClaim(input) {
|
|
|
2421
2433
|
};
|
|
2422
2434
|
}
|
|
2423
2435
|
const projectDir = join14(input.vault, "projects", projectSlug);
|
|
2424
|
-
if (!
|
|
2436
|
+
if (!existsSync4(projectDir) || !statSync(projectDir).isDirectory()) {
|
|
2425
2437
|
return {
|
|
2426
2438
|
exitCode: ExitCode.PROJECT_NOT_FOUND,
|
|
2427
2439
|
result: err("PROJECT_NOT_FOUND", { project: projectSlug })
|
|
@@ -2440,7 +2452,7 @@ async function runClaim(input) {
|
|
|
2440
2452
|
const workDir = join14(projectDir, "work", dirName);
|
|
2441
2453
|
const relWorkDir = `projects/${projectSlug}/work/${dirName}`;
|
|
2442
2454
|
const relSpecPath = `${relWorkDir}/spec.md`;
|
|
2443
|
-
if (
|
|
2455
|
+
if (existsSync4(workDir)) {
|
|
2444
2456
|
return {
|
|
2445
2457
|
exitCode: ExitCode.OK,
|
|
2446
2458
|
result: ok({
|
|
@@ -2485,11 +2497,11 @@ async function runClaim(input) {
|
|
|
2485
2497
|
}
|
|
2486
2498
|
|
|
2487
2499
|
// src/commands/work-complete.ts
|
|
2488
|
-
import { existsSync as
|
|
2500
|
+
import { existsSync as existsSync6, mkdirSync, readFileSync as readFileSync9, renameSync, writeFileSync as writeFileSync3 } from "fs";
|
|
2489
2501
|
import { join as join16 } from "path";
|
|
2490
2502
|
|
|
2491
2503
|
// src/commands/work-validate.ts
|
|
2492
|
-
import { existsSync as
|
|
2504
|
+
import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync8, statSync as statSync2 } from "fs";
|
|
2493
2505
|
import { join as join15 } from "path";
|
|
2494
2506
|
var GOAL_PLAN_MODE_FILES = /* @__PURE__ */ new Set(["spec.md", "plan.md", "build-report.md"]);
|
|
2495
2507
|
function normalizeWorkItemRel(workItem) {
|
|
@@ -2565,7 +2577,7 @@ function validatePrMetadata(meta, findings) {
|
|
|
2565
2577
|
async function runWorkValidate(input) {
|
|
2566
2578
|
const rel = normalizeWorkItemRel(input.workItem);
|
|
2567
2579
|
const workDir = join15(input.vault, rel);
|
|
2568
|
-
if (!
|
|
2580
|
+
if (!existsSync5(workDir)) {
|
|
2569
2581
|
return {
|
|
2570
2582
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
2571
2583
|
result: err("FILE_NOT_FOUND", { path: rel })
|
|
@@ -2699,7 +2711,7 @@ function workCompleteJournalPath(vault, opId) {
|
|
|
2699
2711
|
}
|
|
2700
2712
|
function readWorkJournal(vault, opId) {
|
|
2701
2713
|
const path = workCompleteJournalPath(vault, opId);
|
|
2702
|
-
if (!
|
|
2714
|
+
if (!existsSync6(path)) return null;
|
|
2703
2715
|
try {
|
|
2704
2716
|
return parseJournalEnv(readFileSync9(path, "utf8"));
|
|
2705
2717
|
} catch {
|
|
@@ -2729,10 +2741,10 @@ var PHASE_ORDER = ["validate", "evidence", "log", "projection", "commit", "done"
|
|
|
2729
2741
|
function resolveWorkDir(vault, workItem) {
|
|
2730
2742
|
const rel = normalizeWorkItemRel(workItem);
|
|
2731
2743
|
const abs = join16(vault, rel);
|
|
2732
|
-
if (!
|
|
2744
|
+
if (!existsSync6(abs)) {
|
|
2733
2745
|
return err("FILE_NOT_FOUND", { path: rel });
|
|
2734
2746
|
}
|
|
2735
|
-
if (!
|
|
2747
|
+
if (!existsSync6(join16(abs, "spec.md"))) {
|
|
2736
2748
|
return err("PREFLIGHT_FAILED", { reason: "missing-spec", path: rel });
|
|
2737
2749
|
}
|
|
2738
2750
|
return ok(abs);
|
|
@@ -2799,7 +2811,7 @@ async function writeEvidence(workDir, opId, phases, writeText) {
|
|
|
2799
2811
|
}
|
|
2800
2812
|
async function markPlanComplete(workDir) {
|
|
2801
2813
|
const planPath = join16(workDir, "plan.md");
|
|
2802
|
-
if (!
|
|
2814
|
+
if (!existsSync6(planPath)) return ok(null);
|
|
2803
2815
|
return patchFrontmatterStatus(planPath, (body) => body.replace(/- \[ \]/g, "- [x]"));
|
|
2804
2816
|
}
|
|
2805
2817
|
function writeFailure(stage, result) {
|
|
@@ -2924,7 +2936,7 @@ async function runWorkComplete(input, deps = DEFAULT_DEPS) {
|
|
|
2924
2936
|
advance("projection");
|
|
2925
2937
|
}
|
|
2926
2938
|
if (phaseIndex(phase) <= phaseIndex("projection")) {
|
|
2927
|
-
if (!
|
|
2939
|
+
if (!existsSync6(join16(workDir, "evidence.md"))) {
|
|
2928
2940
|
const evidenceWrite = await writeEvidence(
|
|
2929
2941
|
workDir,
|
|
2930
2942
|
opId,
|
|
@@ -2954,7 +2966,7 @@ async function runWorkComplete(input, deps = DEFAULT_DEPS) {
|
|
|
2954
2966
|
}
|
|
2955
2967
|
let committed = false;
|
|
2956
2968
|
if (phaseIndex(phase) <= phaseIndex("commit")) {
|
|
2957
|
-
if (!input.noCommit &&
|
|
2969
|
+
if (!input.noCommit && existsSync6(join16(input.vault, ".git"))) {
|
|
2958
2970
|
try {
|
|
2959
2971
|
appendLastOp(input.vault, {
|
|
2960
2972
|
operation: "work-complete",
|
|
@@ -3014,7 +3026,7 @@ async function runWorkComplete(input, deps = DEFAULT_DEPS) {
|
|
|
3014
3026
|
}
|
|
3015
3027
|
|
|
3016
3028
|
// src/commands/health.ts
|
|
3017
|
-
import { existsSync as
|
|
3029
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync2, readFileSync as readFileSync10, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "fs";
|
|
3018
3030
|
import { dirname as dirname4, join as join17, resolve as resolve2 } from "path";
|
|
3019
3031
|
import { platform } from "os";
|
|
3020
3032
|
function statusFromCounts(counts) {
|
|
@@ -3126,7 +3138,7 @@ function summarizeChecks(checks) {
|
|
|
3126
3138
|
};
|
|
3127
3139
|
}
|
|
3128
3140
|
function classifyLog(path, id, label, okPattern) {
|
|
3129
|
-
if (!
|
|
3141
|
+
if (!existsSync7(path)) return { id, label, status: "warn", detail: `log file missing: ${path}` };
|
|
3130
3142
|
const lines = readFileSync10(path, "utf8").split(/\r?\n/).filter(Boolean);
|
|
3131
3143
|
if (lines.length === 0) return { id, label, status: "warn", detail: `log file empty: ${path}` };
|
|
3132
3144
|
const journalFailRe = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z (FAIL|ERROR)\b/;
|
|
@@ -3156,7 +3168,7 @@ function runVaultSyncHealth(home, syncMode, env = process.env) {
|
|
|
3156
3168
|
const vsConfig = readVaultSyncConfig(home);
|
|
3157
3169
|
const fetchOnly = vsConfig.pushEnabled === false;
|
|
3158
3170
|
const installedScript = fetchOnly ? join17(shareDir, "wiki-fetch-notify.sh") : join17(shareDir, "wiki-push.sh");
|
|
3159
|
-
if (syncMode === "optional" && !
|
|
3171
|
+
if (syncMode === "optional" && !existsSync7(installedScript)) {
|
|
3160
3172
|
return {
|
|
3161
3173
|
status: "pass",
|
|
3162
3174
|
blocking: false,
|
|
@@ -3171,12 +3183,12 @@ function runVaultSyncHealth(home, syncMode, env = process.env) {
|
|
|
3171
3183
|
}
|
|
3172
3184
|
if (vsConfig.role === "snapshotter") {
|
|
3173
3185
|
const snapshotScript = vsConfig.snapshotScript ?? join17(shareDir, "wiki-snapshot.sh");
|
|
3174
|
-
const installed =
|
|
3186
|
+
const installed = existsSync7(snapshotScript) ? { id: "vault_sync_installed", label: "Vault sync installed", status: "pass", detail: `Found snapshot script: ${snapshotScript}` } : { id: "vault_sync_installed", label: "Vault sync installed", status: "error", detail: `Snapshot script not found at ${snapshotScript}` };
|
|
3175
3187
|
const healthChecks = snapshotterHealthChecks(vsConfig.serviceScope ?? "user", logDir, env);
|
|
3176
3188
|
const fetchNA = { id: "vault_sync_last_fetch_status", label: "Vault sync last fetch status", status: "pass", detail: "Snapshotter host \u2014 leaf wiki-fetch-notify log not applicable" };
|
|
3177
3189
|
const filterNA = { id: "vault_sync_filter_present", label: "Vault sync filter file present", status: "pass", detail: "Snapshotter host \u2014 leaf wiki-push filter not applicable" };
|
|
3178
3190
|
let guard;
|
|
3179
|
-
if (!
|
|
3191
|
+
if (!existsSync7(snapshotScript)) {
|
|
3180
3192
|
guard = { id: "vault_sync_snapshot_guard", label: "Snapshot script guard", status: "error", detail: `Snapshot script not found at ${snapshotScript}` };
|
|
3181
3193
|
} else {
|
|
3182
3194
|
const content = readFileSync10(snapshotScript, "utf8");
|
|
@@ -3192,11 +3204,11 @@ function runVaultSyncHealth(home, syncMode, env = process.env) {
|
|
|
3192
3204
|
checks: allChecks.map((c) => ({ id: c.id, status: c.status, detail: c.detail }))
|
|
3193
3205
|
};
|
|
3194
3206
|
}
|
|
3195
|
-
checks.push(
|
|
3207
|
+
checks.push(existsSync7(installedScript) ? { id: "vault_sync_installed", label: "Vault sync installed", status: "pass", detail: `Found: ${installedScript}` } : { id: "vault_sync_installed", label: "Vault sync installed", status: "error", detail: `Script missing: ${installedScript}` });
|
|
3196
3208
|
if (isMac) {
|
|
3197
3209
|
const pushPlist = join17(home, "Library", "LaunchAgents", "com.karlchow.wiki-push.plist");
|
|
3198
3210
|
const fetchPlist = join17(home, "Library", "LaunchAgents", "com.karlchow.wiki-fetch.plist");
|
|
3199
|
-
const jobsOk = fetchOnly ?
|
|
3211
|
+
const jobsOk = fetchOnly ? existsSync7(fetchPlist) : existsSync7(pushPlist) && existsSync7(fetchPlist);
|
|
3200
3212
|
checks.push(jobsOk ? { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "pass", detail: fetchOnly ? "launchd: wiki-fetch unit file present (read-only mode)" : "launchd unit files present (read-only mode)" } : { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "warn", detail: fetchOnly ? "launchd wiki-fetch unit file missing (read-only mode)" : "launchd unit files missing (read-only mode)" });
|
|
3201
3213
|
checks.push({ id: "vault_sync_fuse_refresh_job", label: "Vault sync fuse refresh job", status: "pass", detail: "macOS host \u2014 check skipped" });
|
|
3202
3214
|
} else {
|
|
@@ -3204,9 +3216,9 @@ function runVaultSyncHealth(home, syncMode, env = process.env) {
|
|
|
3204
3216
|
const fetchTimer = join17(home, ".config", "systemd", "user", "wiki-fetch.timer");
|
|
3205
3217
|
const fuseTimer = join17(home, ".config", "systemd", "user", "wiki-fuse-refresh.timer");
|
|
3206
3218
|
const fuseService = join17(home, ".config", "systemd", "user", "wiki-fuse-refresh.service");
|
|
3207
|
-
const jobsOk = fetchOnly ?
|
|
3219
|
+
const jobsOk = fetchOnly ? existsSync7(fetchTimer) : existsSync7(pushTimer) && existsSync7(fetchTimer);
|
|
3208
3220
|
checks.push(jobsOk ? { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "pass", detail: fetchOnly ? "systemd: wiki-fetch.timer unit file present (read-only mode)" : "systemd timer unit files present (read-only mode)" } : { id: "vault_sync_jobs_enabled", label: "Vault sync jobs enabled", status: "warn", detail: fetchOnly ? "systemd wiki-fetch.timer unit file missing (read-only mode)" : "systemd timer unit files missing (read-only mode)" });
|
|
3209
|
-
checks.push(
|
|
3221
|
+
checks.push(existsSync7(fuseTimer) && existsSync7(fuseService) ? { id: "vault_sync_fuse_refresh_job", label: "Vault sync fuse refresh job", status: "pass", detail: "wiki-fuse-refresh unit files present (read-only mode)" } : { id: "vault_sync_fuse_refresh_job", label: "Vault sync fuse refresh job", status: "warn", detail: "wiki-fuse-refresh unit files missing (read-only mode)" });
|
|
3210
3222
|
}
|
|
3211
3223
|
if (fetchOnly) {
|
|
3212
3224
|
checks.push({ id: "vault_sync_last_push_age", label: "Vault sync last push recency", status: "pass", detail: PUSH_NOT_IN_PROFILE });
|
|
@@ -3216,7 +3228,7 @@ function runVaultSyncHealth(home, syncMode, env = process.env) {
|
|
|
3216
3228
|
checks.push(classifyLog(join17(logDir, "wiki-fetch.log"), "vault_sync_last_fetch_status", "Vault sync last fetch status", /NOTIFY|OK behind|OK/));
|
|
3217
3229
|
if (fetchOnly) {
|
|
3218
3230
|
checks.push({ id: "vault_sync_filter_present", label: "Vault sync filter file present", status: "pass", detail: PUSH_NOT_IN_PROFILE });
|
|
3219
|
-
} else if (!
|
|
3231
|
+
} else if (!existsSync7(filterPath)) {
|
|
3220
3232
|
checks.push({ id: "vault_sync_filter_present", label: "Vault sync filter file present", status: "error", detail: `Filter missing: ${filterPath}` });
|
|
3221
3233
|
} else {
|
|
3222
3234
|
const content = readFileSync10(filterPath, "utf8");
|
|
@@ -4405,7 +4417,7 @@ async function runUpdate(input) {
|
|
|
4405
4417
|
|
|
4406
4418
|
// src/commands/self-update.ts
|
|
4407
4419
|
import { execSync as execSync2 } from "child_process";
|
|
4408
|
-
import { existsSync as
|
|
4420
|
+
import { existsSync as existsSync8, readFileSync as readFileSync11 } from "fs";
|
|
4409
4421
|
import { join as join22 } from "path";
|
|
4410
4422
|
var DEFAULT_SOURCE_ROOT_SUFFIX = "/Desktop/code/llm-wiki";
|
|
4411
4423
|
async function runSelfUpdate(input) {
|
|
@@ -4413,7 +4425,7 @@ async function runSelfUpdate(input) {
|
|
|
4413
4425
|
const sourceRoot = input.sourceRoot ?? `${input.home}${DEFAULT_SOURCE_ROOT_SUFFIX}`;
|
|
4414
4426
|
const distTag = normalizeDistTag(input.distTag);
|
|
4415
4427
|
const localPkgPath = join22(sourceRoot, "packages", "cli", "package.json");
|
|
4416
|
-
const hasLocalSource =
|
|
4428
|
+
const hasLocalSource = existsSync8(localPkgPath);
|
|
4417
4429
|
if (input.check) {
|
|
4418
4430
|
let availableVersion = null;
|
|
4419
4431
|
let source;
|
|
@@ -4714,7 +4726,7 @@ async function runClaimsAudit(input) {
|
|
|
4714
4726
|
// src/commands/compound.ts
|
|
4715
4727
|
import { writeFile as writeFile6, mkdir as mkdir7, readdir as readdir6, unlink as unlink3 } from "fs/promises";
|
|
4716
4728
|
import { join as join25 } from "path";
|
|
4717
|
-
import { existsSync as
|
|
4729
|
+
import { existsSync as existsSync9 } from "fs";
|
|
4718
4730
|
import { readFile as readFile11 } from "fs/promises";
|
|
4719
4731
|
var RETRO_HEADING_RE = /^## \[(\d{4}-\d{2}-\d{2})(?:\s+[^\]]+)?\] retro \| loop cycle(?: (\d+))?: (.+)$/;
|
|
4720
4732
|
var FIELD_RE = {
|
|
@@ -4832,7 +4844,7 @@ async function runCompound(input) {
|
|
|
4832
4844
|
}
|
|
4833
4845
|
const slug = slugify(entry.cycleName);
|
|
4834
4846
|
const compoundPath = join25(compoundDir, `${slug}.md`);
|
|
4835
|
-
if (
|
|
4847
|
+
if (existsSync9(compoundPath)) {
|
|
4836
4848
|
skipped.push(entry.date);
|
|
4837
4849
|
continue;
|
|
4838
4850
|
}
|
|
@@ -4870,7 +4882,7 @@ async function runCompound(input) {
|
|
|
4870
4882
|
].join("\n");
|
|
4871
4883
|
const content = frontmatter + "\n" + body;
|
|
4872
4884
|
if (!input.dryRun) {
|
|
4873
|
-
if (!
|
|
4885
|
+
if (!existsSync9(compoundDir)) {
|
|
4874
4886
|
await mkdir7(compoundDir, { recursive: true });
|
|
4875
4887
|
}
|
|
4876
4888
|
await writeFile6(compoundPath, content, "utf8");
|
|
@@ -4893,7 +4905,7 @@ async function runCompound(input) {
|
|
|
4893
4905
|
}
|
|
4894
4906
|
async function runCompoundDelete(input) {
|
|
4895
4907
|
const projectDir = join25(input.vault, "projects", input.project);
|
|
4896
|
-
if (!
|
|
4908
|
+
if (!existsSync9(projectDir)) {
|
|
4897
4909
|
return {
|
|
4898
4910
|
exitCode: ExitCode.PROJECT_NOT_FOUND,
|
|
4899
4911
|
result: err("PROJECT_NOT_FOUND", { slug: input.project, path: projectDir })
|
|
@@ -4901,7 +4913,7 @@ async function runCompoundDelete(input) {
|
|
|
4901
4913
|
}
|
|
4902
4914
|
const entryName = input.entry.replace(/\.md$/, "");
|
|
4903
4915
|
const compoundPath = join25(projectDir, "compound", `${entryName}.md`);
|
|
4904
|
-
if (!
|
|
4916
|
+
if (!existsSync9(compoundPath)) {
|
|
4905
4917
|
return {
|
|
4906
4918
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
4907
4919
|
result: err("FILE_NOT_FOUND", { path: compoundPath })
|
|
@@ -4935,7 +4947,7 @@ knowledge.md regenerated`
|
|
|
4935
4947
|
}
|
|
4936
4948
|
async function runCompoundList(input) {
|
|
4937
4949
|
const compoundDir = join25(input.vault, "projects", input.project, "compound");
|
|
4938
|
-
if (!
|
|
4950
|
+
if (!existsSync9(compoundDir)) {
|
|
4939
4951
|
return {
|
|
4940
4952
|
exitCode: ExitCode.OK,
|
|
4941
4953
|
result: ok({
|
|
@@ -5734,7 +5746,7 @@ import { dirname as dirname7, join as join29, resolve as resolve3 } from "path";
|
|
|
5734
5746
|
// src/utils/publication-operation-journal.ts
|
|
5735
5747
|
import {
|
|
5736
5748
|
chmodSync,
|
|
5737
|
-
existsSync as
|
|
5749
|
+
existsSync as existsSync10,
|
|
5738
5750
|
mkdirSync as mkdirSync3,
|
|
5739
5751
|
readFileSync as readFileSync12,
|
|
5740
5752
|
realpathSync,
|
|
@@ -5886,7 +5898,7 @@ function buildIdentitySummary(input) {
|
|
|
5886
5898
|
}
|
|
5887
5899
|
function readPublicationJournal(vaultPath, operationId2, home = process.env.HOME || homedir()) {
|
|
5888
5900
|
const { journalPath: journalPath2 } = resolveJournalPaths(vaultPath, operationId2, home);
|
|
5889
|
-
if (!
|
|
5901
|
+
if (!existsSync10(journalPath2)) return ok(null);
|
|
5890
5902
|
let text;
|
|
5891
5903
|
try {
|
|
5892
5904
|
text = readFileSync12(journalPath2, "utf8");
|
|
@@ -5904,7 +5916,7 @@ function readPublicationJournal(vaultPath, operationId2, home = process.env.HOME
|
|
|
5904
5916
|
function createPublicationJournal(input) {
|
|
5905
5917
|
const home = input.home ?? process.env.HOME ?? homedir();
|
|
5906
5918
|
const paths = resolveJournalPaths(input.vaultPath, input.operationId, home);
|
|
5907
|
-
if (
|
|
5919
|
+
if (existsSync10(paths.journalPath)) {
|
|
5908
5920
|
return err("WRITE_FAILED", { message: "journal already exists", path: paths.journalPath });
|
|
5909
5921
|
}
|
|
5910
5922
|
const record = {
|
|
@@ -5976,7 +5988,7 @@ function advancePublicationJournal(input) {
|
|
|
5976
5988
|
}
|
|
5977
5989
|
function deletePublicationJournal(vaultPath, operationId2, home = process.env.HOME || homedir()) {
|
|
5978
5990
|
const { journalPath: journalPath2 } = resolveJournalPaths(vaultPath, operationId2, home);
|
|
5979
|
-
if (!
|
|
5991
|
+
if (!existsSync10(journalPath2)) return ok({ deleted: false });
|
|
5980
5992
|
try {
|
|
5981
5993
|
unlinkSync(journalPath2);
|
|
5982
5994
|
return ok({ deleted: true });
|
|
@@ -8483,7 +8495,7 @@ function runSyncJournalClearStale(input) {
|
|
|
8483
8495
|
}
|
|
8484
8496
|
|
|
8485
8497
|
// src/commands/snapshot-maintenance.ts
|
|
8486
|
-
import { existsSync as
|
|
8498
|
+
import { existsSync as existsSync11, writeFileSync as writeFileSync6, mkdirSync as mkdirSync4, appendFileSync } from "fs";
|
|
8487
8499
|
import { createHash as createHash5 } from "crypto";
|
|
8488
8500
|
import { execSync as execSync3, spawn } from "child_process";
|
|
8489
8501
|
import { platform as platform2 } from "os";
|
|
@@ -8552,7 +8564,7 @@ async function runSnapshotMaintenanceDryRun(input) {
|
|
|
8552
8564
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_WRONG_WORKTREE"));
|
|
8553
8565
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_WRONG_WORKTREE", `requested path '${requested}' is not the configured snapshot worktree '${canonicalize(configuredWorktree)}'`) };
|
|
8554
8566
|
}
|
|
8555
|
-
if (!
|
|
8567
|
+
if (!existsSync11(requested) || !existsSync11(join34(requested, ".git"))) {
|
|
8556
8568
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_MISSING_GIT_REPO"));
|
|
8557
8569
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_MISSING_GIT_REPO", `snapshot worktree is not a git repository: ${requested}`) };
|
|
8558
8570
|
}
|
|
@@ -8787,9 +8799,9 @@ function nonMergeSequencerActive(repo) {
|
|
|
8787
8799
|
const gitDir = git(repo, ["rev-parse", "--absolute-git-dir"]);
|
|
8788
8800
|
if (!gitDir) return false;
|
|
8789
8801
|
for (const m of ["CHERRY_PICK_HEAD", "REVERT_HEAD"]) {
|
|
8790
|
-
if (
|
|
8802
|
+
if (existsSync11(join34(gitDir, m))) return true;
|
|
8791
8803
|
}
|
|
8792
|
-
return
|
|
8804
|
+
return existsSync11(join34(gitDir, "rebase-merge")) || existsSync11(join34(gitDir, "rebase-apply"));
|
|
8793
8805
|
}
|
|
8794
8806
|
function extraUnmergedPaths(unmerged) {
|
|
8795
8807
|
const allow = new Set(PROJECTION_CONFLICT_ALLOWLIST);
|
|
@@ -8828,7 +8840,7 @@ async function authorizeRepairContext(input) {
|
|
|
8828
8840
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_WRONG_WORKTREE", void 0, REPAIR_COMMAND));
|
|
8829
8841
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_WRONG_WORKTREE", `requested path '${requested}' is not the configured snapshot worktree '${canonicalize(configuredWorktree)}'`) };
|
|
8830
8842
|
}
|
|
8831
|
-
if (!
|
|
8843
|
+
if (!existsSync11(requested) || !existsSync11(join34(requested, ".git"))) {
|
|
8832
8844
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_MISSING_GIT_REPO", void 0, REPAIR_COMMAND));
|
|
8833
8845
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_MISSING_GIT_REPO", `snapshot worktree is not a git repository: ${requested}`) };
|
|
8834
8846
|
}
|
|
@@ -9207,12 +9219,12 @@ async function runBackupRestore(input) {
|
|
|
9207
9219
|
}
|
|
9208
9220
|
|
|
9209
9221
|
// src/commands/status.ts
|
|
9210
|
-
import { existsSync as
|
|
9222
|
+
import { existsSync as existsSync12, statSync as statSync4 } from "fs";
|
|
9211
9223
|
import { readFile as readFile18 } from "fs/promises";
|
|
9212
9224
|
import { join as join36 } from "path";
|
|
9213
9225
|
var FUSE_NO_MIRROR_NOTE = "FUSE vault with no read mirror - status scan may be slow";
|
|
9214
9226
|
async function runStatus(input) {
|
|
9215
|
-
if (!
|
|
9227
|
+
if (!existsSync12(input.vault)) {
|
|
9216
9228
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { vault: input.vault }) };
|
|
9217
9229
|
}
|
|
9218
9230
|
const { root: scanRoot, mirrored } = resolveReadOnlyVaultRoot(input.vault);
|
|
@@ -9314,9 +9326,166 @@ async function runStatus(input) {
|
|
|
9314
9326
|
};
|
|
9315
9327
|
}
|
|
9316
9328
|
|
|
9329
|
+
// src/commands/copy-status.ts
|
|
9330
|
+
import { existsSync as existsSync13 } from "fs";
|
|
9331
|
+
import { join as join37 } from "path";
|
|
9332
|
+
|
|
9333
|
+
// src/copy-status/copy-status.ts
|
|
9334
|
+
function liveRecord(p) {
|
|
9335
|
+
if (p.unknown || p.reachable === void 0) {
|
|
9336
|
+
return { state: "unknown", reachable: p.reachable, detail: p.detail ?? "S3/MCP unmeasured" };
|
|
9337
|
+
}
|
|
9338
|
+
if (p.reachable) {
|
|
9339
|
+
return { state: "ok", reachable: true, detail: p.detail ?? "S3 reachable" };
|
|
9340
|
+
}
|
|
9341
|
+
return { state: "unknown", reachable: false, detail: p.detail ?? "S3 unreachable" };
|
|
9342
|
+
}
|
|
9343
|
+
function githubRecord(p) {
|
|
9344
|
+
if (p.unknown || !p.oid) {
|
|
9345
|
+
return { state: "unknown", age_hours: p.ageHours, detail: p.detail ?? "GitHub HEAD unmeasured" };
|
|
9346
|
+
}
|
|
9347
|
+
const rec = { state: "ok", oid: p.oid, detail: p.detail ?? "ls-remote origin main" };
|
|
9348
|
+
if (p.ageHours !== void 0) rec.age_hours = p.ageHours;
|
|
9349
|
+
return rec;
|
|
9350
|
+
}
|
|
9351
|
+
function localRecord(p, githubOid) {
|
|
9352
|
+
if (p.blockedReason) {
|
|
9353
|
+
return {
|
|
9354
|
+
state: "blocked",
|
|
9355
|
+
oid: p.head,
|
|
9356
|
+
behind: p.behind,
|
|
9357
|
+
blocked_reason: p.blockedReason,
|
|
9358
|
+
detail: p.detail ?? p.blockedReason
|
|
9359
|
+
};
|
|
9360
|
+
}
|
|
9361
|
+
if (p.head && githubOid && p.head === githubOid && (p.behind === void 0 || p.behind === 0)) {
|
|
9362
|
+
return {
|
|
9363
|
+
state: "ok",
|
|
9364
|
+
oid: p.head,
|
|
9365
|
+
behind: p.behind,
|
|
9366
|
+
detail: p.detail ?? "HEAD matches GitHub"
|
|
9367
|
+
};
|
|
9368
|
+
}
|
|
9369
|
+
if (p.behind !== void 0 && p.behind > 0) {
|
|
9370
|
+
return {
|
|
9371
|
+
state: "stale",
|
|
9372
|
+
oid: p.head,
|
|
9373
|
+
behind: p.behind,
|
|
9374
|
+
detail: p.detail ?? `behind origin/main by ${p.behind}`
|
|
9375
|
+
};
|
|
9376
|
+
}
|
|
9377
|
+
if (p.head && githubOid && p.head !== githubOid) {
|
|
9378
|
+
return {
|
|
9379
|
+
state: "stale",
|
|
9380
|
+
oid: p.head,
|
|
9381
|
+
behind: p.behind,
|
|
9382
|
+
detail: p.detail ?? "HEAD differs from GitHub"
|
|
9383
|
+
};
|
|
9384
|
+
}
|
|
9385
|
+
if (p.head) {
|
|
9386
|
+
return {
|
|
9387
|
+
state: "ok",
|
|
9388
|
+
oid: p.head,
|
|
9389
|
+
behind: p.behind,
|
|
9390
|
+
detail: p.detail ?? "HEAD present"
|
|
9391
|
+
};
|
|
9392
|
+
}
|
|
9393
|
+
return { state: "unknown", detail: p.detail ?? "leaf clone unmeasured" };
|
|
9394
|
+
}
|
|
9395
|
+
function formatPlane(name, rec) {
|
|
9396
|
+
const parts = [`${name}: ${rec.state}`];
|
|
9397
|
+
if (rec.oid) parts.push(`oid=${rec.oid.slice(0, 12)}`);
|
|
9398
|
+
if (rec.behind !== void 0) parts.push(`behind=${rec.behind}`);
|
|
9399
|
+
if (rec.age_hours !== void 0) parts.push(`age_hours=${rec.age_hours}`);
|
|
9400
|
+
if (rec.blocked_reason) parts.push(rec.blocked_reason);
|
|
9401
|
+
if (rec.detail) parts.push(rec.detail);
|
|
9402
|
+
return parts.join(" ");
|
|
9403
|
+
}
|
|
9404
|
+
function composeCopyStatus(input) {
|
|
9405
|
+
const live = liveRecord(input.live);
|
|
9406
|
+
const github = githubRecord(input.github);
|
|
9407
|
+
const local_git = localRecord(input.local, input.github.oid);
|
|
9408
|
+
const humanHint = [
|
|
9409
|
+
formatPlane("live", live),
|
|
9410
|
+
formatPlane("github", github),
|
|
9411
|
+
formatPlane("local_git", local_git)
|
|
9412
|
+
].join("\n");
|
|
9413
|
+
return { live, github, local_git, humanHint };
|
|
9414
|
+
}
|
|
9415
|
+
async function runCopyStatus(deps) {
|
|
9416
|
+
const [live, github, local] = await Promise.all([
|
|
9417
|
+
deps.probeLive(),
|
|
9418
|
+
deps.probeGithub(),
|
|
9419
|
+
deps.probeLocalGit()
|
|
9420
|
+
]);
|
|
9421
|
+
return composeCopyStatus({ live, github, local });
|
|
9422
|
+
}
|
|
9423
|
+
|
|
9424
|
+
// src/commands/copy-status.ts
|
|
9425
|
+
function defaultCopyStatusDeps(input) {
|
|
9426
|
+
return {
|
|
9427
|
+
probeLive() {
|
|
9428
|
+
if (input.s3Ok === true) return { reachable: true, detail: "MCP S3 ok" };
|
|
9429
|
+
if (input.s3Ok === false) return { reachable: false, detail: "MCP S3 not ok" };
|
|
9430
|
+
const remote = resolveWikiS3Remote({ home: input.home });
|
|
9431
|
+
if (!remote) {
|
|
9432
|
+
return { unknown: true, detail: "leaf clone is not the live plane; S3 remote unconfigured" };
|
|
9433
|
+
}
|
|
9434
|
+
const reach = probeS3Reachability(remote);
|
|
9435
|
+
if (reach === "ok") return { reachable: true, detail: "S3 reachable" };
|
|
9436
|
+
if (reach === "unreachable") return { reachable: false, detail: "S3 unreachable" };
|
|
9437
|
+
return { unknown: true, detail: "S3 unmeasured" };
|
|
9438
|
+
},
|
|
9439
|
+
probeGithub() {
|
|
9440
|
+
if (!existsSync13(join37(input.vault, ".git"))) {
|
|
9441
|
+
return { unknown: true, detail: "vault is not a git repository" };
|
|
9442
|
+
}
|
|
9443
|
+
const ls = git(input.vault, ["ls-remote", "origin", "refs/heads/main"], {
|
|
9444
|
+
timeoutMs: REMOTE_PROBE_TIMEOUT_MS
|
|
9445
|
+
});
|
|
9446
|
+
const oid = ls.split(/\s+/)[0];
|
|
9447
|
+
if (!oid) return { unknown: true, detail: "git ls-remote origin main failed" };
|
|
9448
|
+
const originMain = git(input.vault, ["rev-parse", "--verify", "origin/main"]);
|
|
9449
|
+
let ageHours;
|
|
9450
|
+
if (originMain && originMain === oid) {
|
|
9451
|
+
const ct = git(input.vault, ["log", "-1", "--format=%ct", "origin/main"]);
|
|
9452
|
+
const sec = Number.parseInt(ct, 10);
|
|
9453
|
+
if (Number.isFinite(sec) && sec > 0) {
|
|
9454
|
+
ageHours = Math.max(0, Math.round((Date.now() / 1e3 - sec) / 3600));
|
|
9455
|
+
}
|
|
9456
|
+
}
|
|
9457
|
+
return { oid, ageHours, detail: "git ls-remote origin main" };
|
|
9458
|
+
},
|
|
9459
|
+
probeLocalGit() {
|
|
9460
|
+
if (!existsSync13(join37(input.vault, ".git"))) {
|
|
9461
|
+
return { unknown: true, detail: "vault is not a git repository" };
|
|
9462
|
+
}
|
|
9463
|
+
const head = git(input.vault, ["rev-parse", "HEAD"]);
|
|
9464
|
+
if (!head) return { unknown: true, detail: "HEAD unreadable" };
|
|
9465
|
+
const behindRaw = git(input.vault, ["rev-list", "--count", "HEAD..origin/main"]);
|
|
9466
|
+
const behind = behindRaw === "" ? void 0 : Number.parseInt(behindRaw, 10);
|
|
9467
|
+
const review = listReviewRequiredOps(input.vault)[0];
|
|
9468
|
+
const blockedReason = review ? `review-required:${review.opId}` : void 0;
|
|
9469
|
+
return {
|
|
9470
|
+
head,
|
|
9471
|
+
behind: Number.isFinite(behind) ? behind : void 0,
|
|
9472
|
+
blockedReason,
|
|
9473
|
+
detail: blockedReason
|
|
9474
|
+
};
|
|
9475
|
+
}
|
|
9476
|
+
};
|
|
9477
|
+
}
|
|
9478
|
+
async function runCopyStatusCommand(input) {
|
|
9479
|
+
if (!existsSync13(input.vault)) {
|
|
9480
|
+
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { vault: input.vault }) };
|
|
9481
|
+
}
|
|
9482
|
+
const data = await runCopyStatus(input.deps ?? defaultCopyStatusDeps(input));
|
|
9483
|
+
return { exitCode: ExitCode.OK, result: ok(data) };
|
|
9484
|
+
}
|
|
9485
|
+
|
|
9317
9486
|
// src/commands/seed.ts
|
|
9318
9487
|
import { mkdir as mkdir12, writeFile as writeFile8, stat as stat4 } from "fs/promises";
|
|
9319
|
-
import { join as
|
|
9488
|
+
import { join as join38 } from "path";
|
|
9320
9489
|
var TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
9321
9490
|
var EXAMPLE_PAGES = {
|
|
9322
9491
|
"entities/example-project.md": `---
|
|
@@ -9385,29 +9554,29 @@ Real sources are immutable after ingestion \u2014 never edit them.
|
|
|
9385
9554
|
`;
|
|
9386
9555
|
async function runSeed(input) {
|
|
9387
9556
|
try {
|
|
9388
|
-
await stat4(
|
|
9557
|
+
await stat4(join38(input.vault, "SCHEMA.md"));
|
|
9389
9558
|
} catch {
|
|
9390
9559
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { root: input.vault, reason: "SCHEMA.md missing \u2014 run `skillwiki init` first" }) };
|
|
9391
9560
|
}
|
|
9392
9561
|
const created = [];
|
|
9393
9562
|
const skipped = [];
|
|
9394
9563
|
for (const [relPath, content] of Object.entries(EXAMPLE_PAGES)) {
|
|
9395
|
-
const absPath =
|
|
9564
|
+
const absPath = join38(input.vault, relPath);
|
|
9396
9565
|
try {
|
|
9397
9566
|
await stat4(absPath);
|
|
9398
9567
|
skipped.push(relPath);
|
|
9399
9568
|
} catch {
|
|
9400
|
-
await mkdir12(
|
|
9569
|
+
await mkdir12(join38(absPath, ".."), { recursive: true });
|
|
9401
9570
|
await writeFile8(absPath, content, "utf8");
|
|
9402
9571
|
created.push(relPath);
|
|
9403
9572
|
}
|
|
9404
9573
|
}
|
|
9405
|
-
const rawPath =
|
|
9574
|
+
const rawPath = join38(input.vault, "raw", "articles", "example-source.md");
|
|
9406
9575
|
try {
|
|
9407
9576
|
await stat4(rawPath);
|
|
9408
9577
|
skipped.push("raw/articles/example-source.md");
|
|
9409
9578
|
} catch {
|
|
9410
|
-
await mkdir12(
|
|
9579
|
+
await mkdir12(join38(rawPath, ".."), { recursive: true });
|
|
9411
9580
|
await writeFile8(rawPath, EXAMPLE_RAW, "utf8");
|
|
9412
9581
|
created.push("raw/articles/example-source.md");
|
|
9413
9582
|
}
|
|
@@ -9431,8 +9600,8 @@ async function runSeed(input) {
|
|
|
9431
9600
|
|
|
9432
9601
|
// src/commands/canvas.ts
|
|
9433
9602
|
import { readFile as readFile19, writeFile as writeFile9 } from "fs/promises";
|
|
9434
|
-
import { existsSync as
|
|
9435
|
-
import { join as
|
|
9603
|
+
import { existsSync as existsSync14 } from "fs";
|
|
9604
|
+
import { join as join39 } from "path";
|
|
9436
9605
|
var NODE_WIDTH = 240;
|
|
9437
9606
|
var NODE_HEIGHT = 60;
|
|
9438
9607
|
var COLUMN_SPACING = 400;
|
|
@@ -9510,8 +9679,8 @@ function buildCanvasEdges(adjacency) {
|
|
|
9510
9679
|
return edges;
|
|
9511
9680
|
}
|
|
9512
9681
|
async function runCanvasGenerate(input) {
|
|
9513
|
-
const graphPath = input.graphPath ??
|
|
9514
|
-
if (!
|
|
9682
|
+
const graphPath = input.graphPath ?? join39(input.vault, ".skillwiki", "graph.json");
|
|
9683
|
+
if (!existsSync14(graphPath)) {
|
|
9515
9684
|
return {
|
|
9516
9685
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
9517
9686
|
result: err("FILE_NOT_FOUND", {
|
|
@@ -9548,7 +9717,7 @@ async function runCanvasGenerate(input) {
|
|
|
9548
9717
|
const nodes = buildCanvasNodes(paths);
|
|
9549
9718
|
const edges = buildCanvasEdges(graph.adjacency);
|
|
9550
9719
|
const canvas = { nodes, edges };
|
|
9551
|
-
const outPath =
|
|
9720
|
+
const outPath = join39(input.vault, "vault-graph.canvas");
|
|
9552
9721
|
try {
|
|
9553
9722
|
await writeFile9(outPath, JSON.stringify(canvas, null, 2));
|
|
9554
9723
|
} catch (e) {
|
|
@@ -9697,7 +9866,7 @@ import { readFile as readFile21, unlink as unlink5 } from "fs/promises";
|
|
|
9697
9866
|
|
|
9698
9867
|
// src/utils/raw-asset-reference-index.ts
|
|
9699
9868
|
import { readdir as readdir7, readFile as readFile20 } from "fs/promises";
|
|
9700
|
-
import { join as
|
|
9869
|
+
import { join as join40, relative as relative4, sep as sep3 } from "path";
|
|
9701
9870
|
var PREVIEW_EXTENSIONS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "webp", "svg", "bmp", "avif", "pdf", "mp3", "wav", "m4a", "mp4", "webm"]);
|
|
9702
9871
|
async function walkFiles(root, dir = root) {
|
|
9703
9872
|
let entries;
|
|
@@ -9708,7 +9877,7 @@ async function walkFiles(root, dir = root) {
|
|
|
9708
9877
|
}
|
|
9709
9878
|
const out = [];
|
|
9710
9879
|
for (const entry of entries) {
|
|
9711
|
-
const path =
|
|
9880
|
+
const path = join40(dir, entry.name);
|
|
9712
9881
|
if (entry.isDirectory()) out.push(...await walkFiles(root, path));
|
|
9713
9882
|
else if (entry.isFile()) out.push(relative4(root, path).split(sep3).join("/"));
|
|
9714
9883
|
}
|
|
@@ -9724,7 +9893,7 @@ function addInbound(map, target, source) {
|
|
|
9724
9893
|
map.set(target, refs);
|
|
9725
9894
|
}
|
|
9726
9895
|
async function buildRawAssetReferenceIndex(vault) {
|
|
9727
|
-
const assetRoot =
|
|
9896
|
+
const assetRoot = join40(vault, "raw", "assets");
|
|
9728
9897
|
const relativeAssets = await walkFiles(assetRoot);
|
|
9729
9898
|
const assets = relativeAssets.map((path) => `raw/assets/${path}`).sort((a, b) => a.localeCompare(b));
|
|
9730
9899
|
const assetSet = new Set(assets);
|
|
@@ -9921,10 +10090,10 @@ async function runSourceDisposal(input) {
|
|
|
9921
10090
|
}
|
|
9922
10091
|
|
|
9923
10092
|
// src/commands/fleet-health.ts
|
|
9924
|
-
import { existsSync as
|
|
10093
|
+
import { existsSync as existsSync15, readFileSync as readFileSync16 } from "fs";
|
|
9925
10094
|
import { execSync as nodeExecSync } from "child_process";
|
|
9926
10095
|
import { hostname as nodeHostname, platform as nodePlatform } from "os";
|
|
9927
|
-
import { join as
|
|
10096
|
+
import { join as join41 } from "path";
|
|
9928
10097
|
var SSH_TIMEOUT_MS = 15e3;
|
|
9929
10098
|
var TIMER_UNIT = "agent-memory-trends.timer";
|
|
9930
10099
|
var SERVICE_UNIT = "agent-memory-trends.service";
|
|
@@ -10021,7 +10190,7 @@ function applyServiceFailedOverlay(run, serviceFailed) {
|
|
|
10021
10190
|
function probeLocal(vaultPath, deps) {
|
|
10022
10191
|
const latestPath = satelliteLatestRunPath(vaultPath);
|
|
10023
10192
|
let parsed = null;
|
|
10024
|
-
if (
|
|
10193
|
+
if (existsSync15(latestPath)) {
|
|
10025
10194
|
try {
|
|
10026
10195
|
const wire = readSatelliteLatestRunFromText(readFileSync16(latestPath, "utf8"));
|
|
10027
10196
|
if (wire) {
|
|
@@ -10154,7 +10323,7 @@ async function runFleetHealth(input) {
|
|
|
10154
10323
|
const home = input.home ?? env.HOME ?? "";
|
|
10155
10324
|
const osHostname = input.osHostname ?? env.HOSTNAME ?? nodeHostname();
|
|
10156
10325
|
const vault = input.vault ?? env.WIKI_PATH;
|
|
10157
|
-
const file = input.file ?? (vault ?
|
|
10326
|
+
const file = input.file ?? (vault ? join41(vault, FLEET_REL_PATH) : void 0);
|
|
10158
10327
|
if (!file) {
|
|
10159
10328
|
return {
|
|
10160
10329
|
exitCode: ExitCode.NO_VAULT_CONFIGURED,
|
|
@@ -10238,8 +10407,8 @@ async function runFleetHealth(input) {
|
|
|
10238
10407
|
}
|
|
10239
10408
|
|
|
10240
10409
|
// src/utils/auto-commit.ts
|
|
10241
|
-
import { existsSync as
|
|
10242
|
-
import { isAbsolute, join as
|
|
10410
|
+
import { existsSync as existsSync16 } from "fs";
|
|
10411
|
+
import { isAbsolute, join as join42, normalize } from "path";
|
|
10243
10412
|
function isValidLastOpPath(file) {
|
|
10244
10413
|
if (!file || typeof file !== "string") return false;
|
|
10245
10414
|
const trimmed = file.trim();
|
|
@@ -10260,7 +10429,7 @@ async function postCommit(vault, exitCode) {
|
|
|
10260
10429
|
const dotenv = await parseDotenvFile(configPath(home));
|
|
10261
10430
|
const autoCommit = process.env.AUTO_COMMIT ?? dotenv["AUTO_COMMIT"];
|
|
10262
10431
|
if (autoCommit === "false") return;
|
|
10263
|
-
if (!
|
|
10432
|
+
if (!existsSync16(join42(vault, ".git"))) return;
|
|
10264
10433
|
const lastOps = readLastOp(vault);
|
|
10265
10434
|
if (lastOps.length === 0) return;
|
|
10266
10435
|
const porcelain = git(vault, ["status", "--porcelain", "--", ...VAULT_COMMIT_PATHSPEC]);
|
|
@@ -10410,9 +10579,9 @@ async function runMcpAuthIssueHost(input) {
|
|
|
10410
10579
|
}
|
|
10411
10580
|
|
|
10412
10581
|
// src/commands/write-preflight.ts
|
|
10413
|
-
import { existsSync as
|
|
10582
|
+
import { existsSync as existsSync17, readFileSync as readFileSync18, statSync as statSync5 } from "fs";
|
|
10414
10583
|
async function runWritePreflightCommand(input) {
|
|
10415
|
-
if (!
|
|
10584
|
+
if (!existsSync17(input.vault) || !statSync5(input.vault).isDirectory()) {
|
|
10416
10585
|
return {
|
|
10417
10586
|
exitCode: ExitCode.VAULT_PATH_INVALID,
|
|
10418
10587
|
result: err(GateError.VAULT_PATH_INVALID, { path: input.vault })
|
|
@@ -10420,7 +10589,7 @@ async function runWritePreflightCommand(input) {
|
|
|
10420
10589
|
}
|
|
10421
10590
|
let priorText = input.priorArtifactText;
|
|
10422
10591
|
if (input.priorArtifactFile) {
|
|
10423
|
-
if (!
|
|
10592
|
+
if (!existsSync17(input.priorArtifactFile)) {
|
|
10424
10593
|
return {
|
|
10425
10594
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
10426
10595
|
result: err("FILE_NOT_FOUND", { path: input.priorArtifactFile })
|
|
@@ -10547,7 +10716,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
|
|
|
10547
10716
|
if (dirty) {
|
|
10548
10717
|
return emit(dirty, void 0, { postCommit: false });
|
|
10549
10718
|
}
|
|
10550
|
-
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-
|
|
10719
|
+
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-2Y5Q2WH4.js");
|
|
10551
10720
|
const run = await runManagedWriteTransaction2({
|
|
10552
10721
|
vault,
|
|
10553
10722
|
command,
|
|
@@ -10577,7 +10746,7 @@ program.command("validate <file>").description("validate vault page frontmatter
|
|
|
10577
10746
|
emit(await runValidate({ file, apply: !!opts.apply, vault }), vault);
|
|
10578
10747
|
});
|
|
10579
10748
|
program.command("graph").description("graph subcommands").command("build <vault>").option("--out <path>", "graph output path (default: <vault>/.skillwiki/graph.json)").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
10580
|
-
const out = opts.out ??
|
|
10749
|
+
const out = opts.out ?? join43(vault, ".skillwiki", "graph.json");
|
|
10581
10750
|
return emitGuardedVaultWrite(vault, "graph build", () => runGraphBuild({ vault, out }));
|
|
10582
10751
|
});
|
|
10583
10752
|
var canvasCmd = program.command("canvas").description("manage Obsidian canvas files");
|
|
@@ -11060,17 +11229,17 @@ logCmd.command("migrate-legacy [vault]").description("backfill immutable events
|
|
|
11060
11229
|
} else emit(await runLogMigrateLegacy({ vault: v.vault, write: false }), v.vault);
|
|
11061
11230
|
});
|
|
11062
11231
|
var projectionsCmd = program.command("projections").description("root index/log projection materialization");
|
|
11063
|
-
projectionsCmd.command("materialize [vault]").description("preview or write root index.md and log.md as a pair").option("--write", "write projections", false).option("--converge-vault <dir>", "Git vault used for managed pull and base-OID proof").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
11232
|
+
projectionsCmd.command("materialize [vault]").description("preview or write root index.md and log.md as a pair").option("--write", "write projections", false).option("--converge-vault <dir>", "Git vault used for managed pull and base-OID proof").option("--events-from <dir>", "log-events directory (day folders) instead of vault meta/log-events").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
11064
11233
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
11065
11234
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
11066
11235
|
else if (opts.write) {
|
|
11067
11236
|
return emitManagedVaultWrite(
|
|
11068
11237
|
v.vault,
|
|
11069
11238
|
"projections materialize",
|
|
11070
|
-
() => runProjectionsMaterialize({ vault: v.vault, write: true }),
|
|
11239
|
+
() => runProjectionsMaterialize({ vault: v.vault, write: true, eventsFrom: opts.eventsFrom }),
|
|
11071
11240
|
{ convergenceVault: opts.convergeVault }
|
|
11072
11241
|
);
|
|
11073
|
-
} else emit(await runProjectionsMaterialize({ vault: v.vault, write: false }), v.vault);
|
|
11242
|
+
} else emit(await runProjectionsMaterialize({ vault: v.vault, write: false, eventsFrom: opts.eventsFrom }), v.vault);
|
|
11074
11243
|
});
|
|
11075
11244
|
projectionsCmd.command("repair-legacy [vault]").description("repair one supported legacy root-index marker pair and log event").requiredOption("--event-operation-id <id>", "exact legacy event operation ID").option("--write", "write the bounded repairs", false).option("--converge-vault <dir>", "Git vault used for managed pull and base-OID proof").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
11076
11245
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
@@ -11199,6 +11368,14 @@ program.command("status [vault]").description("output vault diagnostics").option
|
|
|
11199
11368
|
langEnvValue: process.env.WIKI_LANG
|
|
11200
11369
|
}), v.vault);
|
|
11201
11370
|
});
|
|
11371
|
+
program.command("copy-status [vault]").description("plane-tagged vault freshness: live S3 vs GitHub snapshot vs leaf clone").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
11372
|
+
const v = await resolveVaultArg(vault, opts.wiki);
|
|
11373
|
+
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
11374
|
+
else emit(await runCopyStatusCommand({
|
|
11375
|
+
vault: v.vault,
|
|
11376
|
+
home: process.env.HOME ?? ""
|
|
11377
|
+
}), v.vault, { postCommit: false });
|
|
11378
|
+
});
|
|
11202
11379
|
program.command("archive <page> [vault]").description("archive a typed-knowledge or raw page").option("--wiki <name>", "wiki profile name").option("--cascade", "scan vault for references (wikilinks + sources arrays); preview by default", false).option("--apply", "with --cascade: mutate sources arrays and archive (without --apply, --cascade is preview-only)", false).option("--approve <token>", "approve an exact state-bound raw archive plan").option("--remote <remote>", "rclone remote root to prune the archived source path, for example seaweed-wiki:cloud/wiki").option("--remote-delete", "delete the archived source path from the remote after local archive", false).option("--max-remote-deletes <n>", "maximum remote object deletes allowed", "1").action(async (page, vault, opts) => {
|
|
11203
11380
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
11204
11381
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
@@ -6,9 +6,9 @@ import {
|
|
|
6
6
|
runManagedWritePeerGate,
|
|
7
7
|
runManagedWritePreflight,
|
|
8
8
|
runManagedWriteTransaction
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-6WE7E6VB.js";
|
|
10
10
|
import "./chunk-JHDN3FSF.js";
|
|
11
|
-
import "./chunk-
|
|
11
|
+
import "./chunk-QFRZDTJY.js";
|
|
12
12
|
import "./chunk-XJR3XXP5.js";
|
|
13
13
|
export {
|
|
14
14
|
DEFAULT_MANAGED_WRITE_WAIT_MS,
|
package/dist/skillwiki-mcp.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runSkillwikiMcpStdio
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5QFHISNH.js";
|
|
5
5
|
import "./chunk-7I2TPIV5.js";
|
|
6
6
|
import "./chunk-ZUHA2EXE.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-6WE7E6VB.js";
|
|
8
8
|
import "./chunk-JHDN3FSF.js";
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-ECOEJABP.js";
|
|
10
|
+
import "./chunk-QFRZDTJY.js";
|
|
11
11
|
import "./chunk-XJR3XXP5.js";
|
|
12
12
|
|
|
13
13
|
// src/mcp-entry.ts
|
|
@@ -108,6 +108,7 @@ RCLONE_LOG="/tmp/rclone-${DATE}.log"
|
|
|
108
108
|
SNAPSHOT_DIRECT_S3_NOT_GIT_COUNT=0
|
|
109
109
|
SNAPSHOT_REMOTE_INVENTORY_READY=0
|
|
110
110
|
PROJECTION_STATE_DIR=""
|
|
111
|
+
SNAPSHOT_S3_LOG_EVENTS=""
|
|
111
112
|
PROJECTION_EXPECTED_INDEX_SHA256=""
|
|
112
113
|
PROJECTION_EXPECTED_LOG_SHA256=""
|
|
113
114
|
SNAPSHOT_BASE_OID=""
|
|
@@ -118,6 +119,9 @@ cleanup_projection_state() {
|
|
|
118
119
|
if [ -n "$PROJECTION_STATE_DIR" ] && [ -d "$PROJECTION_STATE_DIR" ]; then
|
|
119
120
|
rm -rf "$PROJECTION_STATE_DIR"
|
|
120
121
|
fi
|
|
122
|
+
if [ -n "$SNAPSHOT_S3_LOG_EVENTS" ] && [ -d "$SNAPSHOT_S3_LOG_EVENTS" ]; then
|
|
123
|
+
rm -rf "$SNAPSHOT_S3_LOG_EVENTS"
|
|
124
|
+
fi
|
|
121
125
|
}
|
|
122
126
|
trap cleanup_projection_state EXIT
|
|
123
127
|
|
|
@@ -460,6 +464,25 @@ validate_projection_parity_config() {
|
|
|
460
464
|
return 0
|
|
461
465
|
}
|
|
462
466
|
|
|
467
|
+
# Direct-S3 log-event inventory shared by freeze and semantic preview so
|
|
468
|
+
# FUSE dir cache vs wiki-git find cannot disagree on the event set.
|
|
469
|
+
snapshot_capture_direct_s3_log_events() {
|
|
470
|
+
if [ -z "$CLOUD_REMOTE" ]; then
|
|
471
|
+
log "ERROR: CLOUD_REMOTE unset; cannot capture S3 log-events"
|
|
472
|
+
return 1
|
|
473
|
+
fi
|
|
474
|
+
SNAPSHOT_S3_LOG_EVENTS="$(mktemp -d)" || {
|
|
475
|
+
log "ERROR: could not create temp dir for S3 log-events"
|
|
476
|
+
return 1
|
|
477
|
+
}
|
|
478
|
+
if ! rclone copy "${CLOUD_REMOTE%/}/meta/log-events" "$SNAPSHOT_S3_LOG_EVENTS" 2>>"$LOG_FILE"; then
|
|
479
|
+
log "ERROR: rclone copy of S3 meta/log-events failed"
|
|
480
|
+
return 1
|
|
481
|
+
fi
|
|
482
|
+
log "OK captured S3 log-events at $SNAPSHOT_S3_LOG_EVENTS"
|
|
483
|
+
return 0
|
|
484
|
+
}
|
|
485
|
+
|
|
463
486
|
snapshot_freeze_projection_expectations() {
|
|
464
487
|
if [ "${WIKI_SNAPSHOT_TEST_SKIP_PROJECTION_PARITY:-0}" = "1" ] \
|
|
465
488
|
&& [ -n "${SNAPSHOT_TEST_ROOT:-}" ]; then
|
|
@@ -472,10 +495,12 @@ snapshot_freeze_projection_expectations() {
|
|
|
472
495
|
return 1
|
|
473
496
|
fi
|
|
474
497
|
|
|
475
|
-
PROJECTION_STATE_DIR
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
498
|
+
if [ -z "$PROJECTION_STATE_DIR" ] || [ ! -d "$PROJECTION_STATE_DIR" ]; then
|
|
499
|
+
PROJECTION_STATE_DIR="$(mktemp -d)" || {
|
|
500
|
+
log "ERROR: could not create private projection parity state"
|
|
501
|
+
return 1
|
|
502
|
+
}
|
|
503
|
+
fi
|
|
479
504
|
if ! cp "$WIKI_DIR/index.md" "$PROJECTION_STATE_DIR/expected-index.md" \
|
|
480
505
|
|| ! cp "$WIKI_DIR/log.md" "$PROJECTION_STATE_DIR/expected-log.md"; then
|
|
481
506
|
log "ERROR: could not freeze live projection bytes"
|
|
@@ -523,6 +548,9 @@ snapshot_wait_for_direct_projection_parity() {
|
|
|
523
548
|
# Test-only skip path above. Production always has frozen state.
|
|
524
549
|
return 0
|
|
525
550
|
fi
|
|
551
|
+
if [ ! -f "$PROJECTION_STATE_DIR/expected-index.md" ] || [ ! -f "$PROJECTION_STATE_DIR/expected-log.md" ]; then
|
|
552
|
+
return 0
|
|
553
|
+
fi
|
|
526
554
|
|
|
527
555
|
local started deadline now attempts
|
|
528
556
|
local remote_index="$PROJECTION_STATE_DIR/remote-index.md"
|
|
@@ -655,7 +683,11 @@ snapshot_verify_semantic_projection_preview() {
|
|
|
655
683
|
return 0
|
|
656
684
|
fi
|
|
657
685
|
local preview="$PROJECTION_STATE_DIR/worktree-preview.json"
|
|
658
|
-
|
|
686
|
+
local -a preview_args=("projections" "materialize" "$SNAPSHOT_WORKTREE")
|
|
687
|
+
if [ -n "${SNAPSHOT_S3_LOG_EVENTS:-}" ] && [ -d "$SNAPSHOT_S3_LOG_EVENTS" ]; then
|
|
688
|
+
preview_args+=(--events-from "$SNAPSHOT_S3_LOG_EVENTS")
|
|
689
|
+
fi
|
|
690
|
+
if ! "$SKILLWIKI_BIN" "${preview_args[@]}" >"$preview" 2>>"$LOG_FILE"; then
|
|
659
691
|
log "ERROR: projection semantic preview failed"
|
|
660
692
|
return 1
|
|
661
693
|
fi
|
|
@@ -867,8 +899,13 @@ if command -v "$SKILLWIKI_BIN" >/dev/null 2>&1; then
|
|
|
867
899
|
;;
|
|
868
900
|
esac
|
|
869
901
|
proj_out="$(mktemp)"
|
|
902
|
+
if ! snapshot_capture_direct_s3_log_events; then
|
|
903
|
+
log "FAIL S3 log-events capture; snapshot promotion refused"
|
|
904
|
+
exit 1
|
|
905
|
+
fi
|
|
870
906
|
if ! "$SKILLWIKI_BIN" projections materialize "$WIKI_DIR" --write \
|
|
871
|
-
--converge-vault "$SNAPSHOT_WORKTREE"
|
|
907
|
+
--converge-vault "$SNAPSHOT_WORKTREE" \
|
|
908
|
+
--events-from "$SNAPSHOT_S3_LOG_EVENTS" >"$proj_out" 2>&1; then
|
|
872
909
|
cat "$proj_out" >>"$LOG_FILE" 2>/dev/null || true
|
|
873
910
|
snapshot_inhibit_record_failure "$(snapshot_parse_operation_id "$proj_out")"
|
|
874
911
|
rm -f "$proj_out"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.88",
|
|
4
4
|
"skills": "./",
|
|
5
5
|
"description": "Project-aware Karpathy-style knowledge base for Claude Code: 21 prompt-only skills (wiki-*, proj-*, using-skillwiki, skillwiki-mcp) backed by the deterministic `skillwiki` CLI.",
|
|
6
6
|
"author": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.88",
|
|
4
4
|
"description": "Project-aware Karpathy-style knowledge base: 21 prompt-only skills (wiki-*, proj-*, using-skillwiki, skillwiki-mcp) backed by HTTP MCP wiki_capture.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "karlorz"
|