skillwiki 0.10.12 → 0.10.14
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-YYWGP7DN.js → chunk-2AOOMDZ7.js} +148 -73
- package/dist/{chunk-TYN2IHBY.js → chunk-OWPQJOFG.js} +19 -11
- package/dist/{chunk-3ZVZ2YEE.js → chunk-UJLSUJB6.js} +5 -2
- package/dist/cli.js +476 -52
- package/dist/{managed-write-preflight-7TWSEZJZ.js → managed-write-preflight-M2HL6DDY.js} +2 -2
- package/dist/skillwiki-mcp.js +2 -2
- package/dist/vault-sync/scripts/lib/git-operation-journal.sh +106 -13
- package/dist/vault-sync/scripts/lib/managed-write-lock.sh +10 -7
- package/dist/vault-sync/scripts/wiki-snapshot.sh +14 -0
- package/package.json +1 -1
- package/skills/.claude-plugin/plugin.json +1 -1
- package/skills/.codex-plugin/plugin.json +1 -1
- package/skills/package.json +1 -1
- package/skills/skills/using-skillwiki/SKILL.md +3 -2
- package/skills/using-skillwiki/SKILL.md +3 -2
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
satelliteGateFromFleetLoad,
|
|
34
34
|
snapshotterAliasForLocalHost,
|
|
35
35
|
writeDotenv
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-OWPQJOFG.js";
|
|
37
37
|
import {
|
|
38
38
|
CompoundSchema,
|
|
39
39
|
ExitCode,
|
|
@@ -3211,6 +3211,7 @@ function buildCliSurface() {
|
|
|
3211
3211
|
program.command("tag");
|
|
3212
3212
|
program.command("tag-sync").option("--dry-run").option("--wiki <name>");
|
|
3213
3213
|
program.command("sync");
|
|
3214
|
+
program.command("snapshot-maintenance");
|
|
3214
3215
|
program.command("backup");
|
|
3215
3216
|
program.command("seed").option("--wiki <name>");
|
|
3216
3217
|
program.command("observe").requiredOption("--text <text>").option("--kind <kind>").option("--project <slug>").option("--severity <level>").option("--capture-budget <n>").option("--wiki <name>");
|
|
@@ -3252,6 +3253,9 @@ function buildCliSurface() {
|
|
|
3252
3253
|
const backupCmd = program.commands.find((c) => c.name() === "backup");
|
|
3253
3254
|
backupCmd.command("sync").option("--dry-run").option("--bucket <name>").option("--endpoint <url>").option("--region <region>").option("--prune").option("--wiki <name>");
|
|
3254
3255
|
backupCmd.command("restore").option("--bucket <name>").option("--endpoint <url>").option("--region <region>").option("--target <dir>").option("--wiki <name>");
|
|
3256
|
+
const snapshotMaintenanceCmd = program.commands.find((c) => c.name() === "snapshot-maintenance");
|
|
3257
|
+
const snapMaintJournalCmd = snapshotMaintenanceCmd.command("journal");
|
|
3258
|
+
snapMaintJournalCmd.command("clear-stale").option("--dry-run").option("--approve <id>").option("--reason <text>").option("--wiki <name>");
|
|
3255
3259
|
const memoryCmd = program.commands.find((c) => c.name() === "memory");
|
|
3256
3260
|
memoryCmd.command("topics").option("--project <slug>").option("--limit <n>").option("--wiki <name>");
|
|
3257
3261
|
memoryCmd.command("index").requiredOption("--project <slug>").option("--check").option("--if-stale").option("--wiki <name>");
|
|
@@ -6517,6 +6521,142 @@ function resolveSnapshotGitWorktree(config) {
|
|
|
6517
6521
|
const defaultPath = "/root/wiki-git";
|
|
6518
6522
|
return existsSync13(defaultPath) ? defaultPath : void 0;
|
|
6519
6523
|
}
|
|
6524
|
+
function loadSnapshotFixture(env) {
|
|
6525
|
+
const path = env.VS_SNAPSHOT_HEALTH_FIXTURE;
|
|
6526
|
+
if (!path || !existsSync13(path)) return null;
|
|
6527
|
+
try {
|
|
6528
|
+
return JSON.parse(readFileSync10(path, "utf8"));
|
|
6529
|
+
} catch {
|
|
6530
|
+
return null;
|
|
6531
|
+
}
|
|
6532
|
+
}
|
|
6533
|
+
function systemctlShowProperty(scope, unit, prop) {
|
|
6534
|
+
try {
|
|
6535
|
+
const cmd = scope === "system" ? `systemctl show ${unit} --property=${prop} --value` : `systemctl --user show ${unit} --property=${prop} --value`;
|
|
6536
|
+
const out = execSync2(cmd, {
|
|
6537
|
+
encoding: "utf8",
|
|
6538
|
+
timeout: 2e3,
|
|
6539
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
6540
|
+
}).trim();
|
|
6541
|
+
return out || void 0;
|
|
6542
|
+
} catch {
|
|
6543
|
+
return void 0;
|
|
6544
|
+
}
|
|
6545
|
+
}
|
|
6546
|
+
function snapshotProp(kind, prop, fixture, scope) {
|
|
6547
|
+
if (fixture) {
|
|
6548
|
+
const v = fixture[kind][prop];
|
|
6549
|
+
return v == null ? void 0 : String(v);
|
|
6550
|
+
}
|
|
6551
|
+
const unit = kind === "timer" ? "wiki-snapshot.timer" : "wiki-snapshot.service";
|
|
6552
|
+
return systemctlShowProperty(scope, unit, prop);
|
|
6553
|
+
}
|
|
6554
|
+
function parseIsoToMs(ts) {
|
|
6555
|
+
if (!ts || ts === "MISSING") return null;
|
|
6556
|
+
const ms = Date.parse(ts);
|
|
6557
|
+
return Number.isFinite(ms) ? ms : null;
|
|
6558
|
+
}
|
|
6559
|
+
function ageMinutes(nowMs, tsMs) {
|
|
6560
|
+
if (tsMs == null) return null;
|
|
6561
|
+
return Math.floor((nowMs - tsMs) / 6e4);
|
|
6562
|
+
}
|
|
6563
|
+
function snapshotterHealthChecks(scope, logDir, env) {
|
|
6564
|
+
const fixture = loadSnapshotFixture(env);
|
|
6565
|
+
const cadence = fixture ? fixture.cadence_minutes : parseInt(env.VS_SNAPSHOT_CADENCE_MINUTES ?? "30", 10) || 30;
|
|
6566
|
+
const timeout = fixture ? fixture.service_timeout_seconds : parseInt(env.VS_SNAPSHOT_SERVICE_TIMEOUT_SECONDS ?? "900", 10) || 900;
|
|
6567
|
+
const nowMs = fixture ? Date.parse(fixture.now) : Date.now();
|
|
6568
|
+
const warnAge = cadence * 2 + 15;
|
|
6569
|
+
const errorAge = cadence * 4 + 15;
|
|
6570
|
+
const tUnitfile = snapshotProp("timer", "unit_file_state", fixture, scope);
|
|
6571
|
+
const tActive = snapshotProp("timer", "active_state", fixture, scope);
|
|
6572
|
+
const tNext = snapshotProp("timer", "next_elapse", fixture, scope);
|
|
6573
|
+
let jobs;
|
|
6574
|
+
if (tUnitfile == null && tActive == null) {
|
|
6575
|
+
jobs = check("warn", "vault_sync_jobs_enabled", "Vault sync jobs enabled", "wiki-snapshot.timer properties unavailable (read-only)");
|
|
6576
|
+
} else if (tUnitfile === "enabled" && tActive === "active" && tNext) {
|
|
6577
|
+
jobs = check("pass", "vault_sync_jobs_enabled", "Vault sync jobs enabled", `wiki-snapshot.timer enabled+active, next=${tNext} (${scope})`);
|
|
6578
|
+
} else {
|
|
6579
|
+
jobs = check("error", "vault_sync_jobs_enabled", "Vault sync jobs enabled", `wiki-snapshot.timer not eligible: unit_file_state=${tUnitfile ?? "missing"} active_state=${tActive ?? "missing"} next_elapse=${tNext ?? "missing"} (${scope})`);
|
|
6580
|
+
}
|
|
6581
|
+
const sActive = snapshotProp("service", "active_state", fixture, scope) ?? null;
|
|
6582
|
+
const sResult = snapshotProp("service", "result", fixture, scope) ?? null;
|
|
6583
|
+
const sExecMainStatus = snapshotProp("service", "exec_main_status", fixture, scope);
|
|
6584
|
+
const sActiveEnter = snapshotProp("service", "active_enter_timestamp", fixture, scope) ?? null;
|
|
6585
|
+
let serviceResult;
|
|
6586
|
+
if (sActive == null && sResult == null) {
|
|
6587
|
+
serviceResult = check("warn", "vault_sync_snapshot_service_result", "Vault sync snapshot service result", "wiki-snapshot.service properties unavailable (read-only)");
|
|
6588
|
+
} else if (sActive === "active" || sActive === "activating") {
|
|
6589
|
+
const startMs = parseIsoToMs(sActiveEnter);
|
|
6590
|
+
const runSec = startMs == null ? null : Math.floor((nowMs - startMs) / 1e3);
|
|
6591
|
+
if (runSec != null && runSec > timeout) {
|
|
6592
|
+
serviceResult = check("error", "vault_sync_snapshot_service_result", "Vault sync snapshot service result", `wiki-snapshot.service running ${runSec}s beyond timeout ${timeout}s`);
|
|
6593
|
+
} else {
|
|
6594
|
+
serviceResult = check("pass", "vault_sync_snapshot_service_result", "Vault sync snapshot service result", `wiki-snapshot.service in progress (running ${runSec ?? "?"}s)`);
|
|
6595
|
+
}
|
|
6596
|
+
} else if (sResult === "success" && (sExecMainStatus ?? "0") === "0" && sActiveEnter != null) {
|
|
6597
|
+
serviceResult = check("pass", "vault_sync_snapshot_service_result", "Vault sync snapshot service result", "wiki-snapshot.service result=success ExecMainStatus=0");
|
|
6598
|
+
} else if (sResult === "failed" || sExecMainStatus != null && sExecMainStatus !== "0") {
|
|
6599
|
+
serviceResult = check("error", "vault_sync_snapshot_service_result", "Vault sync snapshot service result", `wiki-snapshot.service result=${sResult ?? "missing"} ExecMainStatus=${sExecMainStatus ?? "missing"}`);
|
|
6600
|
+
} else {
|
|
6601
|
+
serviceResult = check("warn", "vault_sync_snapshot_service_result", "Vault sync snapshot service result", `wiki-snapshot.service result=${sResult ?? "missing"} (never ran or unrecognized)`);
|
|
6602
|
+
}
|
|
6603
|
+
let completionTs = null;
|
|
6604
|
+
let completionOutcome = "unknown";
|
|
6605
|
+
const logRecords = fixture ? fixture.log_records : (() => {
|
|
6606
|
+
try {
|
|
6607
|
+
const content = readFileSync10(join25(logDir, "wiki-snapshot.log"), "utf8");
|
|
6608
|
+
return content.split(/\r?\n/).filter(Boolean);
|
|
6609
|
+
} catch {
|
|
6610
|
+
return [];
|
|
6611
|
+
}
|
|
6612
|
+
})();
|
|
6613
|
+
for (let i = logRecords.length - 1; i >= 0; i--) {
|
|
6614
|
+
const m = logRecords[i].match(/SNAPSHOT_COMPLETE schema=v1 .*ts=(\S+)/);
|
|
6615
|
+
if (m) {
|
|
6616
|
+
completionTs = m[1];
|
|
6617
|
+
const om = logRecords[i].match(/outcome=(\S+)/);
|
|
6618
|
+
if (om) completionOutcome = om[1];
|
|
6619
|
+
break;
|
|
6620
|
+
}
|
|
6621
|
+
}
|
|
6622
|
+
let freshness;
|
|
6623
|
+
if (!completionTs || completionTs === "MISSING") {
|
|
6624
|
+
if (sActive === "active" || sActive === "activating") {
|
|
6625
|
+
freshness = check("warn", "vault_sync_last_push_age", "Vault sync last snapshot recency", "snapshot in progress; no prior canonical completion record");
|
|
6626
|
+
} else {
|
|
6627
|
+
freshness = check("error", "vault_sync_last_push_age", "Vault sync last snapshot recency", "no canonical SNAPSHOT_COMPLETE record found");
|
|
6628
|
+
}
|
|
6629
|
+
} else {
|
|
6630
|
+
const ageMin = ageMinutes(nowMs, parseIsoToMs(completionTs));
|
|
6631
|
+
if (ageMin == null) {
|
|
6632
|
+
freshness = check("error", "vault_sync_last_push_age", "Vault sync last snapshot recency", `unparseable completion timestamp: ${completionTs}`);
|
|
6633
|
+
} else if (ageMin <= warnAge) {
|
|
6634
|
+
freshness = check("pass", "vault_sync_last_push_age", "Vault sync last snapshot recency", `last snapshot ${ageMin}m ago (outcome=${completionOutcome}, <=${warnAge}m)`);
|
|
6635
|
+
} else if (ageMin <= errorAge) {
|
|
6636
|
+
freshness = check("warn", "vault_sync_last_push_age", "Vault sync last snapshot recency", `last snapshot ${ageMin}m ago (outcome=${completionOutcome}, >${warnAge}m)`);
|
|
6637
|
+
} else {
|
|
6638
|
+
freshness = check("error", "vault_sync_last_push_age", "Vault sync last snapshot recency", `last snapshot ${ageMin}m ago (outcome=${completionOutcome}, >${errorAge}m)`);
|
|
6639
|
+
}
|
|
6640
|
+
}
|
|
6641
|
+
if (serviceResult.status === "error" && sActive !== "active" && sActive !== "activating") {
|
|
6642
|
+
freshness = check("error", "vault_sync_last_push_age", "Vault sync last snapshot recency", `latest service result failed: ${serviceResult.detail}`);
|
|
6643
|
+
}
|
|
6644
|
+
let failCount = 0;
|
|
6645
|
+
let mostRecentFail = "";
|
|
6646
|
+
for (let i = logRecords.length - 1; i >= 0 && i >= logRecords.length - 60; i--) {
|
|
6647
|
+
const line = logRecords[i];
|
|
6648
|
+
if (/SNAPSHOT_COMPLETE schema=v1/.test(line)) break;
|
|
6649
|
+
if (/ERROR/.test(line)) {
|
|
6650
|
+
failCount++;
|
|
6651
|
+
if (!mostRecentFail) {
|
|
6652
|
+
const m = line.match(/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/);
|
|
6653
|
+
mostRecentFail = m ? m[1] : "unknown";
|
|
6654
|
+
}
|
|
6655
|
+
}
|
|
6656
|
+
}
|
|
6657
|
+
const consecutiveFailures = failCount >= 2 ? check("error", "vault_sync_snapshot_consecutive_failures", "Vault sync snapshot consecutive failures", `${failCount} consecutive snapshot failure(s); most recent: ${mostRecentFail || "unknown"}`) : check("pass", "vault_sync_snapshot_consecutive_failures", "Vault sync snapshot consecutive failures", `${failCount} consecutive failure(s) in recent window (recurrence threshold: 2)`);
|
|
6658
|
+
return [jobs, serviceResult, freshness, consecutiveFailures];
|
|
6659
|
+
}
|
|
6520
6660
|
function vaultSyncChecks(input) {
|
|
6521
6661
|
const os = input.os ?? platform2();
|
|
6522
6662
|
const home = input.home;
|
|
@@ -6525,7 +6665,9 @@ function vaultSyncChecks(input) {
|
|
|
6525
6665
|
return [
|
|
6526
6666
|
skip("vault_sync_installed", "Vault sync installed"),
|
|
6527
6667
|
skip("vault_sync_jobs_enabled", "Vault sync jobs enabled"),
|
|
6668
|
+
skip("vault_sync_snapshot_service_result", "Vault sync snapshot service result"),
|
|
6528
6669
|
skip("vault_sync_last_push_age", "Vault sync last push recency"),
|
|
6670
|
+
skip("vault_sync_snapshot_consecutive_failures", "Vault sync snapshot consecutive failures"),
|
|
6529
6671
|
skip("vault_sync_last_fetch_status", "Vault sync last fetch status"),
|
|
6530
6672
|
skip("vault_sync_filter_present", "Vault sync filter file present"),
|
|
6531
6673
|
skip("vault_sync_snapshot_guard", "Snapshot script guard")
|
|
@@ -6538,79 +6680,10 @@ function vaultSyncChecks(input) {
|
|
|
6538
6680
|
const packagedSnapshotPath = join25(shareDir, "wiki-snapshot.sh");
|
|
6539
6681
|
const legacySnapshotPath = "/root/.hermes/scripts/wiki-snapshot-v3.sh";
|
|
6540
6682
|
const snapshotPath = input.snapshotScriptPath ?? (existsSync13(packagedSnapshotPath) ? packagedSnapshotPath : legacySnapshotPath);
|
|
6541
|
-
function snapshotLastStatusCheck() {
|
|
6542
|
-
const snapshotLog = join25(logDir, "wiki-snapshot.log");
|
|
6543
|
-
try {
|
|
6544
|
-
const logContent = readFileSync10(snapshotLog, "utf8");
|
|
6545
|
-
const lines = logContent.trim().split("\n").filter(Boolean);
|
|
6546
|
-
if (lines.length === 0) {
|
|
6547
|
-
return check(
|
|
6548
|
-
"warn",
|
|
6549
|
-
"vault_sync_last_push_age",
|
|
6550
|
-
"Vault sync last snapshot status",
|
|
6551
|
-
"Snapshot log file is empty"
|
|
6552
|
-
);
|
|
6553
|
-
}
|
|
6554
|
-
const lastLine = [...lines].reverse().find(
|
|
6555
|
-
(line) => /ERROR|Status: complete|Push successful|No changes to commit/.test(line)
|
|
6556
|
-
) ?? lines[lines.length - 1];
|
|
6557
|
-
if (/ERROR/.test(lastLine)) {
|
|
6558
|
-
return check(
|
|
6559
|
-
"error",
|
|
6560
|
-
"vault_sync_last_push_age",
|
|
6561
|
-
"Vault sync last snapshot status",
|
|
6562
|
-
`Last snapshot failed: ${lastLine.slice(0, 160)}`
|
|
6563
|
-
);
|
|
6564
|
-
}
|
|
6565
|
-
if (/Status: complete|Push successful|No changes to commit/.test(lastLine)) {
|
|
6566
|
-
return check(
|
|
6567
|
-
"pass",
|
|
6568
|
-
"vault_sync_last_push_age",
|
|
6569
|
-
"Vault sync last snapshot status",
|
|
6570
|
-
lastLine.slice(0, 160)
|
|
6571
|
-
);
|
|
6572
|
-
}
|
|
6573
|
-
return check(
|
|
6574
|
-
"warn",
|
|
6575
|
-
"vault_sync_last_push_age",
|
|
6576
|
-
"Vault sync last snapshot status",
|
|
6577
|
-
`Last snapshot log entry: ${lastLine.slice(0, 160)}`
|
|
6578
|
-
);
|
|
6579
|
-
} catch {
|
|
6580
|
-
return check(
|
|
6581
|
-
"warn",
|
|
6582
|
-
"vault_sync_last_push_age",
|
|
6583
|
-
"Vault sync last snapshot status",
|
|
6584
|
-
`Snapshot log not found at ${snapshotLog}`
|
|
6585
|
-
);
|
|
6586
|
-
}
|
|
6587
|
-
}
|
|
6588
6683
|
if (input.vaultSyncRole === "snapshotter") {
|
|
6589
6684
|
const c12 = existsSync13(snapshotPath) ? check("pass", "vault_sync_installed", "Vault sync installed", `Found snapshot script: ${snapshotPath}`) : check("error", "vault_sync_installed", "Vault sync installed", `Snapshot script not found at ${snapshotPath}`);
|
|
6590
6685
|
const serviceScope = input.vaultSyncServiceScope ?? "user";
|
|
6591
|
-
const
|
|
6592
|
-
const systemTimerPath = "/etc/systemd/system/wiki-snapshot.timer";
|
|
6593
|
-
let c22;
|
|
6594
|
-
if (serviceScope === "user" && existsSync13(userTimerPath)) {
|
|
6595
|
-
c22 = check("pass", "vault_sync_jobs_enabled", "Vault sync jobs enabled", `Found: ${userTimerPath}`);
|
|
6596
|
-
} else if (serviceScope === "system" && existsSync13(systemTimerPath)) {
|
|
6597
|
-
c22 = check("pass", "vault_sync_jobs_enabled", "Vault sync jobs enabled", `Found: ${systemTimerPath}`);
|
|
6598
|
-
} else if (os !== "linux") {
|
|
6599
|
-
c22 = check("warn", "vault_sync_jobs_enabled", "Vault sync jobs enabled", "Snapshotter scheduler is Linux-only and no wiki-snapshot.timer file was found");
|
|
6600
|
-
} else {
|
|
6601
|
-
try {
|
|
6602
|
-
const command = serviceScope === "system" ? "systemctl is-enabled wiki-snapshot.timer" : "systemctl --user is-enabled wiki-snapshot.timer";
|
|
6603
|
-
const out = execSync2(command, {
|
|
6604
|
-
encoding: "utf8",
|
|
6605
|
-
timeout: 2e3,
|
|
6606
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
6607
|
-
}).trim();
|
|
6608
|
-
c22 = out === "enabled" ? check("pass", "vault_sync_jobs_enabled", "Vault sync jobs enabled", `systemd: wiki-snapshot.timer enabled (${serviceScope})`) : check("error", "vault_sync_jobs_enabled", "Vault sync jobs enabled", `systemd: wiki-snapshot.timer is ${out || "not enabled"} (${serviceScope})`);
|
|
6609
|
-
} catch {
|
|
6610
|
-
c22 = check("error", "vault_sync_jobs_enabled", "Vault sync jobs enabled", `wiki-snapshot.timer check failed (${serviceScope})`);
|
|
6611
|
-
}
|
|
6612
|
-
}
|
|
6613
|
-
const c32 = snapshotLastStatusCheck();
|
|
6686
|
+
const healthChecks = snapshotterHealthChecks(serviceScope, logDir, input.env ?? process.env);
|
|
6614
6687
|
const cFetch2 = check(
|
|
6615
6688
|
"pass",
|
|
6616
6689
|
"vault_sync_last_fetch_status",
|
|
@@ -6658,7 +6731,7 @@ function vaultSyncChecks(input) {
|
|
|
6658
6731
|
`Cannot read ${snapshotPath}`
|
|
6659
6732
|
);
|
|
6660
6733
|
}
|
|
6661
|
-
return [c12,
|
|
6734
|
+
return [c12, ...healthChecks, cFetch2, c42, c52];
|
|
6662
6735
|
}
|
|
6663
6736
|
const pushScriptPath = join25(shareDir, "wiki-push.sh");
|
|
6664
6737
|
const c1 = existsSync13(pushScriptPath) ? check("pass", "vault_sync_installed", "Vault sync installed", `Found: ${pushScriptPath}`) : check("error", "vault_sync_installed", "Vault sync installed", `Script not found at ${pushScriptPath} \u2014 run vault-sync-install`);
|
|
@@ -7075,7 +7148,8 @@ async function runDoctor(input) {
|
|
|
7075
7148
|
vaultSyncInstalled: vsConfig.installed,
|
|
7076
7149
|
vaultSyncRole: vsConfig.role,
|
|
7077
7150
|
vaultSyncServiceScope: vsConfig.serviceScope,
|
|
7078
|
-
snapshotScriptPath: vsConfig.snapshotScript
|
|
7151
|
+
snapshotScriptPath: vsConfig.snapshotScript,
|
|
7152
|
+
env: input.env ?? process.env
|
|
7079
7153
|
}));
|
|
7080
7154
|
checks.push(checkVaultSyncPullHelper(input.home, input.env ?? process.env));
|
|
7081
7155
|
checks.push(checkVaultSyncReviewRequiredJournals(resolvedPath));
|
|
@@ -9915,6 +9989,7 @@ export {
|
|
|
9915
9989
|
isFailedRunStatus,
|
|
9916
9990
|
readSatelliteLatestRunFromText,
|
|
9917
9991
|
evaluateSatelliteRunHealth,
|
|
9992
|
+
snapshotterHealthChecks,
|
|
9918
9993
|
runDoctor,
|
|
9919
9994
|
readCliPackageJson,
|
|
9920
9995
|
DEFAULT_DIRTY_VOLUME_THRESHOLD,
|
|
@@ -702,16 +702,23 @@ function isWorktreeClean(vault) {
|
|
|
702
702
|
const porcelain = git(vault, ["status", "--porcelain"]);
|
|
703
703
|
return !porcelain || porcelain.trim() === "";
|
|
704
704
|
}
|
|
705
|
-
function
|
|
706
|
-
if (hasUnmergedPaths(vault).length > 0)
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
const target = fields.target_oid?.trim();
|
|
710
|
-
if (!target) return false;
|
|
705
|
+
function journalSupersedeHead(vault, requireClean) {
|
|
706
|
+
if (hasUnmergedPaths(vault).length > 0 || hasActiveGitSequencer(vault) || requireClean && !isWorktreeClean(vault)) {
|
|
707
|
+
return null;
|
|
708
|
+
}
|
|
711
709
|
const head = git(vault, ["rev-parse", "HEAD"]);
|
|
710
|
+
return head || null;
|
|
711
|
+
}
|
|
712
|
+
function canSupersedeJournalInContext(vault, fields, head) {
|
|
712
713
|
if (!head) return false;
|
|
714
|
+
const target = fields.target_oid?.trim();
|
|
715
|
+
if (!target) return false;
|
|
713
716
|
return gitMergeBaseIsAncestor(vault, target, head);
|
|
714
717
|
}
|
|
718
|
+
function canSupersedeJournal(vault, fields, opts = {}) {
|
|
719
|
+
const head = journalSupersedeHead(vault, opts.requireClean !== false);
|
|
720
|
+
return canSupersedeJournalInContext(vault, fields, head);
|
|
721
|
+
}
|
|
715
722
|
function gitMergeBaseIsAncestor(vault, ancestor, tip) {
|
|
716
723
|
if (ancestor === tip) return true;
|
|
717
724
|
const mb = git(vault, ["merge-base", ancestor, tip]);
|
|
@@ -733,14 +740,12 @@ function markJournalSuperseded(vault, opId, fields, by) {
|
|
|
733
740
|
}
|
|
734
741
|
function supersedeStaleReviewRequiredJournals(vault, opts = {}) {
|
|
735
742
|
const by = opts.by ?? "skillwiki-preflight";
|
|
743
|
+
const requireClean = opts.requireClean !== false;
|
|
736
744
|
const superseded = [];
|
|
737
745
|
const skipped = [];
|
|
738
|
-
|
|
739
|
-
for (const { opId } of listReviewRequiredOps(vault)) skipped.push(opId);
|
|
740
|
-
return { superseded, skipped };
|
|
741
|
-
}
|
|
746
|
+
const head = journalSupersedeHead(vault, requireClean);
|
|
742
747
|
for (const { opId, fields } of listReviewRequiredOps(vault)) {
|
|
743
|
-
if (!
|
|
748
|
+
if (!canSupersedeJournalInContext(vault, fields, head)) {
|
|
744
749
|
skipped.push(opId);
|
|
745
750
|
continue;
|
|
746
751
|
}
|
|
@@ -886,6 +891,9 @@ export {
|
|
|
886
891
|
findReviewRequiredOp,
|
|
887
892
|
hasUnmergedPaths,
|
|
888
893
|
hasActiveGitSequencer,
|
|
894
|
+
isWorktreeClean,
|
|
895
|
+
canSupersedeJournal,
|
|
896
|
+
markJournalSuperseded,
|
|
889
897
|
supersedeStaleReviewRequiredJournals,
|
|
890
898
|
resolveVaultSyncPullHelper,
|
|
891
899
|
runVaultSyncPullHelper
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
loadFleetManifestAndHost,
|
|
9
9
|
runVaultSyncPullHelper,
|
|
10
10
|
supersedeStaleReviewRequiredJournals
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-OWPQJOFG.js";
|
|
12
12
|
import {
|
|
13
13
|
ExitCode,
|
|
14
14
|
err,
|
|
@@ -163,7 +163,10 @@ function preflightBlocker(vault) {
|
|
|
163
163
|
if (hasActiveGitSequencer(vault)) {
|
|
164
164
|
return { reason: "git-operation-in-progress" };
|
|
165
165
|
}
|
|
166
|
-
supersedeStaleReviewRequiredJournals(vault, {
|
|
166
|
+
supersedeStaleReviewRequiredJournals(vault, {
|
|
167
|
+
by: "skillwiki-managed-write-preflight",
|
|
168
|
+
requireClean: false
|
|
169
|
+
});
|
|
167
170
|
const op = findReviewRequiredOp(vault);
|
|
168
171
|
if (op) return { reason: "review-required", operation_id: op };
|
|
169
172
|
return null;
|