skillwiki 0.10.114 → 0.10.116
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-5RHR4FEK.js → chunk-WV7NLVCD.js} +37 -23
- package/dist/cli.js +12 -12
- package/dist/{managed-write-preflight-2BMHZWVJ.js → managed-write-preflight-KCQHTIHI.js} +2 -2
- package/dist/{migrate-SRRCXI2K.js → migrate-4K6SXESR.js} +2 -2
- package/dist/skillwiki-mcp.js +3 -4
- package/dist/vault-sync/scripts/lib/deploy-runtime.py +126 -0
- package/dist/vault-sync/scripts/lib/git-operation-journal.sh +6 -60
- package/dist/vault-sync/scripts/lib/runtime-manifest.sh +8 -0
- package/dist/vault-sync/scripts/lib/verify-stash-inventory.py +105 -0
- package/dist/vault-sync/scripts/wiki-pull-with-auto-resolve.sh +18 -16
- 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
- package/dist/{chunk-XJ5VEIH7.js → chunk-4ZKCGX4V.js} +3 -3
- package/dist/{chunk-FQERKMD7.js → chunk-CNELLIZ2.js} +3 -3
- package/dist/{watcher-VJ3TOU6J.js → watcher-2PBZQLKL.js} +6 -6
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
satelliteGateFromFleetLoad,
|
|
49
49
|
snapshotterAliasForLocalHost,
|
|
50
50
|
toUndirectedWeighted
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-CNELLIZ2.js";
|
|
52
52
|
import {
|
|
53
53
|
eventPathFor,
|
|
54
54
|
writeLogEvent
|
|
@@ -71,12 +71,6 @@ import {
|
|
|
71
71
|
mergeMcpAuthIntoEnv,
|
|
72
72
|
redactMcpSecret
|
|
73
73
|
} from "./chunk-OGEAFXON.js";
|
|
74
|
-
import {
|
|
75
|
-
xml
|
|
76
|
-
} from "./chunk-XJ5VEIH7.js";
|
|
77
|
-
import {
|
|
78
|
-
atomicWriteText
|
|
79
|
-
} from "./chunk-6VUK2FTX.js";
|
|
80
74
|
import {
|
|
81
75
|
CLIP_NOT_CONFIGURED,
|
|
82
76
|
PRODUCTION_MIRROR_LABEL,
|
|
@@ -94,6 +88,9 @@ import {
|
|
|
94
88
|
resolveSkillwikiHome,
|
|
95
89
|
writeDotenv
|
|
96
90
|
} from "./chunk-IJKJGQKL.js";
|
|
91
|
+
import {
|
|
92
|
+
atomicWriteText
|
|
93
|
+
} from "./chunk-6VUK2FTX.js";
|
|
97
94
|
import {
|
|
98
95
|
CompoundSchema,
|
|
99
96
|
ExitCode,
|
|
@@ -4423,8 +4420,8 @@ var mcpHandshakeProbe = {
|
|
|
4423
4420
|
};
|
|
4424
4421
|
|
|
4425
4422
|
// src/doctor/probes/clip-outbox.ts
|
|
4426
|
-
import { existsSync as existsSync18
|
|
4427
|
-
import { execSync as execSync7 } from "child_process";
|
|
4423
|
+
import { existsSync as existsSync18 } from "fs";
|
|
4424
|
+
import { execSync as execSync7, execFileSync } from "child_process";
|
|
4428
4425
|
import { platform as platform6 } from "os";
|
|
4429
4426
|
import { join as join21 } from "path";
|
|
4430
4427
|
var CLIP_CHECK_IDS = [
|
|
@@ -4477,6 +4474,27 @@ function launchdLoaded(label) {
|
|
|
4477
4474
|
return false;
|
|
4478
4475
|
}
|
|
4479
4476
|
}
|
|
4477
|
+
function validateClipLaunchdPlist(value, label, command, root) {
|
|
4478
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
4479
|
+
const plist = value;
|
|
4480
|
+
const args = plist.ProgramArguments;
|
|
4481
|
+
if (plist.Label !== label || !Array.isArray(args) || args.length < 4 || !args.every((arg) => typeof arg === "string") || !args[0] || args[2] !== "clip-outbox" || args[3] !== command) return false;
|
|
4482
|
+
return root === void 0 ? plist.WatchPaths === void 0 : Array.isArray(plist.WatchPaths) && plist.WatchPaths.length === 1 && plist.WatchPaths[0] === root;
|
|
4483
|
+
}
|
|
4484
|
+
function launchdExplicitlyDisabled(text, label) {
|
|
4485
|
+
return text.split("\n").some((line) => {
|
|
4486
|
+
const match = line.trim().match(/^"([^"]+)"\s*=>\s*(true|false|enabled|disabled)\s*;?$/);
|
|
4487
|
+
return match?.[1] === label && (match[2] === "true" || match[2] === "disabled");
|
|
4488
|
+
});
|
|
4489
|
+
}
|
|
4490
|
+
function validInstalledPlist(path, label, command, root) {
|
|
4491
|
+
const decoded = JSON.parse(execFileSync("/usr/bin/plutil", ["-convert", "json", "-o", "-", path], {
|
|
4492
|
+
encoding: "utf8",
|
|
4493
|
+
timeout: 2e3,
|
|
4494
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
4495
|
+
}));
|
|
4496
|
+
return validateClipLaunchdPlist(decoded, label, command, root);
|
|
4497
|
+
}
|
|
4480
4498
|
function watcherStatus(env, label, home, root) {
|
|
4481
4499
|
const fixture = env.CLIP_WATCHER_FIXTURE;
|
|
4482
4500
|
if (fixture === "loaded-enabled") return { loaded: true, enabled: true, kind: "production" };
|
|
@@ -4491,11 +4509,9 @@ function watcherStatus(env, label, home, root) {
|
|
|
4491
4509
|
}
|
|
4492
4510
|
const plist = join21(home, "Library", "LaunchAgents", `${label}.plist`);
|
|
4493
4511
|
try {
|
|
4494
|
-
const
|
|
4495
|
-
const xmlRoot = xml(root);
|
|
4496
|
-
const matchesRoot = text.includes(`<key>WatchPaths</key><array><string>${xmlRoot}</string></array>`);
|
|
4512
|
+
const matchesRoot = validInstalledPlist(plist, label, "watch", root);
|
|
4497
4513
|
const disabled = execSync7(`launchctl print-disabled gui/${process.getuid()}`, { encoding: "utf8", timeout: 2e3, stdio: ["ignore", "pipe", "ignore"] });
|
|
4498
|
-
const explicitlyDisabled = disabled
|
|
4514
|
+
const explicitlyDisabled = launchdExplicitlyDisabled(disabled, label);
|
|
4499
4515
|
return { loaded: true, enabled: matchesRoot && !explicitlyDisabled, kind: "production" };
|
|
4500
4516
|
} catch {
|
|
4501
4517
|
return { loaded: true, enabled: false, kind: "unknown" };
|
|
@@ -4518,11 +4534,9 @@ function listenerOk(env, home) {
|
|
|
4518
4534
|
if (!launchdLoaded(PRODUCTION_MIRROR_LABEL)) return false;
|
|
4519
4535
|
const plist = join21(home, "Library", "LaunchAgents", `${PRODUCTION_MIRROR_LABEL}.plist`);
|
|
4520
4536
|
try {
|
|
4521
|
-
const
|
|
4522
|
-
if (text.includes("<key>WatchPaths</key>")) return false;
|
|
4537
|
+
const valid = validInstalledPlist(plist, PRODUCTION_MIRROR_LABEL, "mirror-watch");
|
|
4523
4538
|
const disabled = execSync7(`launchctl print-disabled gui/${process.getuid()}`, { encoding: "utf8", timeout: 2e3, stdio: ["ignore", "pipe", "ignore"] });
|
|
4524
|
-
|
|
4525
|
-
return text.includes("mirror-watch") && text.includes(PRODUCTION_MIRROR_LABEL) && !explicitlyDisabled;
|
|
4539
|
+
return valid && !launchdExplicitlyDisabled(disabled, PRODUCTION_MIRROR_LABEL);
|
|
4526
4540
|
} catch {
|
|
4527
4541
|
return false;
|
|
4528
4542
|
}
|
|
@@ -4701,7 +4715,7 @@ async function runDoctor(input) {
|
|
|
4701
4715
|
}
|
|
4702
4716
|
|
|
4703
4717
|
// src/utils/package-info.ts
|
|
4704
|
-
import { readFileSync as
|
|
4718
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
4705
4719
|
function packageJsonCandidateUrls(baseUrl = import.meta.url) {
|
|
4706
4720
|
return [
|
|
4707
4721
|
new URL("../package.json", baseUrl),
|
|
@@ -4711,7 +4725,7 @@ function packageJsonCandidateUrls(baseUrl = import.meta.url) {
|
|
|
4711
4725
|
function readCliPackageJson(baseUrl = import.meta.url) {
|
|
4712
4726
|
for (const url of packageJsonCandidateUrls(baseUrl)) {
|
|
4713
4727
|
try {
|
|
4714
|
-
const pkg = JSON.parse(
|
|
4728
|
+
const pkg = JSON.parse(readFileSync12(url, "utf8"));
|
|
4715
4729
|
if (typeof pkg.version === "string") {
|
|
4716
4730
|
return { ...pkg, version: pkg.version };
|
|
4717
4731
|
}
|
|
@@ -4722,8 +4736,8 @@ function readCliPackageJson(baseUrl = import.meta.url) {
|
|
|
4722
4736
|
}
|
|
4723
4737
|
|
|
4724
4738
|
// src/utils/vault-write-gates.ts
|
|
4725
|
-
import { execFileSync } from "child_process";
|
|
4726
|
-
import { existsSync as existsSync20, readdirSync as readdirSync7, readFileSync as
|
|
4739
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
4740
|
+
import { existsSync as existsSync20, readdirSync as readdirSync7, readFileSync as readFileSync13, statSync as statSync3 } from "fs";
|
|
4727
4741
|
import { join as join22, relative as relative2 } from "path";
|
|
4728
4742
|
var DEFAULT_DIRTY_VOLUME_THRESHOLD = 50;
|
|
4729
4743
|
var DEFAULT_CAPTURE_BUDGET = 20;
|
|
@@ -4805,7 +4819,7 @@ function measureDirtyVolume(vault) {
|
|
|
4805
4819
|
}
|
|
4806
4820
|
let porcelain = "";
|
|
4807
4821
|
try {
|
|
4808
|
-
porcelain =
|
|
4822
|
+
porcelain = execFileSync2("git", ["status", "--porcelain"], {
|
|
4809
4823
|
cwd: vault,
|
|
4810
4824
|
encoding: "utf8",
|
|
4811
4825
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -4996,7 +5010,7 @@ function listProjectDayCaptures(vault, project, day) {
|
|
|
4996
5010
|
}
|
|
4997
5011
|
if (norm.startsWith("raw/transcripts/")) {
|
|
4998
5012
|
try {
|
|
4999
|
-
const body =
|
|
5013
|
+
const body = readFileSync13(abs, "utf8");
|
|
5000
5014
|
if (body.includes(`project: ${slug}`) || body.includes(`project: "[[${slug}]]"`) || body.includes(`project: [[${slug}]]`)) {
|
|
5001
5015
|
found.push(norm);
|
|
5002
5016
|
} else if (base.includes(slug)) {
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
CLIP_MIGRATION_HINT,
|
|
4
|
+
refreshInstalledClipPlist
|
|
5
|
+
} from "./chunk-4ZKCGX4V.js";
|
|
2
6
|
import {
|
|
3
7
|
buildDeleteIntent,
|
|
4
8
|
normalizeVaultRelPath,
|
|
@@ -64,7 +68,7 @@ import {
|
|
|
64
68
|
upsertIndexEntry,
|
|
65
69
|
vectorIndexStatus,
|
|
66
70
|
withMcpClient
|
|
67
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-WV7NLVCD.js";
|
|
68
72
|
import {
|
|
69
73
|
applySourceDisposition,
|
|
70
74
|
decodeSourceActionApproval,
|
|
@@ -174,7 +178,7 @@ import {
|
|
|
174
178
|
stageVaultContentChanges,
|
|
175
179
|
supersedeStaleReviewRequiredJournals,
|
|
176
180
|
taxonomyCommentForPage
|
|
177
|
-
} from "./chunk-
|
|
181
|
+
} from "./chunk-CNELLIZ2.js";
|
|
178
182
|
import {
|
|
179
183
|
authorizeRawOperation,
|
|
180
184
|
buildSourceReferenceIndex,
|
|
@@ -217,13 +221,6 @@ import {
|
|
|
217
221
|
nonEmptyEnvValue,
|
|
218
222
|
redactMcpSecret
|
|
219
223
|
} from "./chunk-OGEAFXON.js";
|
|
220
|
-
import {
|
|
221
|
-
CLIP_MIGRATION_HINT,
|
|
222
|
-
refreshInstalledClipPlist
|
|
223
|
-
} from "./chunk-XJ5VEIH7.js";
|
|
224
|
-
import {
|
|
225
|
-
atomicWriteText
|
|
226
|
-
} from "./chunk-6VUK2FTX.js";
|
|
227
224
|
import {
|
|
228
225
|
CLIP_NOT_CONFIGURED,
|
|
229
226
|
loadClipOutboxConfig
|
|
@@ -239,6 +236,9 @@ import {
|
|
|
239
236
|
resolveSkillwikiHome,
|
|
240
237
|
writeDotenv
|
|
241
238
|
} from "./chunk-IJKJGQKL.js";
|
|
239
|
+
import {
|
|
240
|
+
atomicWriteText
|
|
241
|
+
} from "./chunk-6VUK2FTX.js";
|
|
242
242
|
import {
|
|
243
243
|
ExitCode,
|
|
244
244
|
MetaSchema,
|
|
@@ -3608,7 +3608,7 @@ async function runClipOutboxStatus(home) {
|
|
|
3608
3608
|
}
|
|
3609
3609
|
async function runClipOutboxInstall(input) {
|
|
3610
3610
|
try {
|
|
3611
|
-
const { migrateClipOutbox } = await import("./migrate-
|
|
3611
|
+
const { migrateClipOutbox } = await import("./migrate-4K6SXESR.js");
|
|
3612
3612
|
return { exitCode: ExitCode.OK, result: ok(await migrateClipOutbox(input)) };
|
|
3613
3613
|
} catch (e) {
|
|
3614
3614
|
return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: e instanceof Error ? e.message : "clip migration failed" }) };
|
|
@@ -3624,7 +3624,7 @@ async function runClipOutboxWatch(home) {
|
|
|
3624
3624
|
const { loadClipCredentials, validateRuntime } = await import("./runtime-LQZIG3XN.js");
|
|
3625
3625
|
const { createS3CreateOnlyPut, parseDestination } = await import("./upload-HTE62TOV.js");
|
|
3626
3626
|
const { postReadyHint } = await import("./ready-S7F53Q2D.js");
|
|
3627
|
-
const { startClipWorker } = await import("./watcher-
|
|
3627
|
+
const { startClipWorker } = await import("./watcher-2PBZQLKL.js");
|
|
3628
3628
|
const cfg = resolved.config;
|
|
3629
3629
|
const credentials = await loadClipCredentials(home, cfg);
|
|
3630
3630
|
await validateRuntime(home, cfg, credentials.s3.endpoint);
|
|
@@ -11715,7 +11715,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
|
|
|
11715
11715
|
if (dirty) {
|
|
11716
11716
|
return emit(dirty, void 0, { postCommit: false });
|
|
11717
11717
|
}
|
|
11718
|
-
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-
|
|
11718
|
+
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-KCQHTIHI.js");
|
|
11719
11719
|
const run = await runManagedWriteTransaction2({
|
|
11720
11720
|
vault,
|
|
11721
11721
|
command,
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
runManagedWritePeerGate,
|
|
7
7
|
runManagedWritePreflight,
|
|
8
8
|
runManagedWriteTransaction
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-CNELLIZ2.js";
|
|
10
10
|
import "./chunk-K3YZESND.js";
|
|
11
11
|
import "./chunk-3TKNAOJH.js";
|
|
12
12
|
import "./chunk-JL2SCLXT.js";
|
|
13
|
-
import "./chunk-6VUK2FTX.js";
|
|
14
13
|
import "./chunk-IJKJGQKL.js";
|
|
14
|
+
import "./chunk-6VUK2FTX.js";
|
|
15
15
|
import "./chunk-VNSZCK5V.js";
|
|
16
16
|
export {
|
|
17
17
|
DEFAULT_MANAGED_WRITE_WAIT_MS,
|
|
@@ -6,11 +6,11 @@ import {
|
|
|
6
6
|
refreshInstalledClipPlist,
|
|
7
7
|
stableCliBinary,
|
|
8
8
|
xml
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-6VUK2FTX.js";
|
|
9
|
+
} from "./chunk-4ZKCGX4V.js";
|
|
11
10
|
import "./chunk-OWWWO2XS.js";
|
|
12
11
|
import "./chunk-5D5HFQ76.js";
|
|
13
12
|
import "./chunk-IJKJGQKL.js";
|
|
13
|
+
import "./chunk-6VUK2FTX.js";
|
|
14
14
|
import "./chunk-VNSZCK5V.js";
|
|
15
15
|
export {
|
|
16
16
|
CLIP_MIGRATION_HINT,
|
package/dist/skillwiki-mcp.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runSkillwikiMcpStdio
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-WV7NLVCD.js";
|
|
5
5
|
import "./chunk-CBT35FAW.js";
|
|
6
6
|
import "./chunk-7I2TPIV5.js";
|
|
7
7
|
import "./chunk-IJWZDQDH.js";
|
|
8
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-CNELLIZ2.js";
|
|
9
9
|
import "./chunk-K3YZESND.js";
|
|
10
10
|
import "./chunk-3TKNAOJH.js";
|
|
11
11
|
import "./chunk-JL2SCLXT.js";
|
|
12
12
|
import "./chunk-OGEAFXON.js";
|
|
13
|
-
import "./chunk-XJ5VEIH7.js";
|
|
14
|
-
import "./chunk-6VUK2FTX.js";
|
|
15
13
|
import "./chunk-OWWWO2XS.js";
|
|
16
14
|
import "./chunk-5D5HFQ76.js";
|
|
17
15
|
import "./chunk-IJKJGQKL.js";
|
|
16
|
+
import "./chunk-6VUK2FTX.js";
|
|
18
17
|
import "./chunk-VNSZCK5V.js";
|
|
19
18
|
|
|
20
19
|
// src/mcp-entry.ts
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Upgrade installed helpers without touching configuration or scheduler state.
|
|
3
|
+
|
|
4
|
+
Each entry point execs an immutable payload path, so an in-flight helper and
|
|
5
|
+
its late-loaded libraries stay on the same release across subsequent upgrades.
|
|
6
|
+
Legacy directory migration refuses while an installed helper is running.
|
|
7
|
+
"""
|
|
8
|
+
import datetime
|
|
9
|
+
import hashlib
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
import shutil
|
|
14
|
+
import signal
|
|
15
|
+
import subprocess
|
|
16
|
+
import sys
|
|
17
|
+
import tempfile
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def deploy(root, share, role, version, commit, host, dry_run=False):
|
|
21
|
+
root, share = Path(root).resolve(), Path(share).resolve()
|
|
22
|
+
current = share / "bin"
|
|
23
|
+
if not current.is_dir() or not (share / "runtime-manifest.json").is_file():
|
|
24
|
+
raise ValueError("runtime-only requires an existing installation and manifest")
|
|
25
|
+
if dry_run:
|
|
26
|
+
print("runtime-only: stage immutable payload, validate, back up and switch bin; preserve configuration and scheduler")
|
|
27
|
+
return
|
|
28
|
+
lock = share / ".runtime-upgrade.lock"
|
|
29
|
+
lock.mkdir() # No age-based reclamation of another deployer's lock.
|
|
30
|
+
release = None
|
|
31
|
+
backup = None
|
|
32
|
+
swapped = False
|
|
33
|
+
old_link = os.readlink(current) if current.is_symlink() else None
|
|
34
|
+
manifest = share / "runtime-manifest.json"
|
|
35
|
+
old_manifest = manifest.read_bytes()
|
|
36
|
+
try:
|
|
37
|
+
# Existing old-style entry points cannot pin their late-loaded libs.
|
|
38
|
+
# Refuse migration until they finish; never stop or start a content job.
|
|
39
|
+
processes = subprocess.check_output(["ps", "-axww", "-o", "args="], text=True)
|
|
40
|
+
if not current.is_symlink() and any(str(current) + "/" in line for line in processes.splitlines()):
|
|
41
|
+
raise ValueError("installed helper is active; retry runtime upgrade after it exits")
|
|
42
|
+
releases = share / "runtime-releases"
|
|
43
|
+
releases.mkdir(exist_ok=True)
|
|
44
|
+
release = Path(tempfile.mkdtemp(prefix="runtime-", dir=releases))
|
|
45
|
+
payload = release / "payload"
|
|
46
|
+
shutil.copytree(root / "scripts", payload, ignore=shutil.ignore_patterns("__pycache__", "*.pyc"))
|
|
47
|
+
shutil.copy2(root / "skills/vault-presync/wiki-sync.sh", payload / "wiki-sync.sh")
|
|
48
|
+
# Keep auxiliary installed files while replacing package-owned helpers.
|
|
49
|
+
for source in current.iterdir():
|
|
50
|
+
if source.name in ("lib", "payload", "runtime-manifest.json", "previous-runtime-manifest.json"):
|
|
51
|
+
continue
|
|
52
|
+
if source.is_file():
|
|
53
|
+
shutil.copy2(source, release / source.name)
|
|
54
|
+
shutil.copytree(payload / "lib", release / "lib")
|
|
55
|
+
for file in payload.rglob("*"):
|
|
56
|
+
if file.suffix == ".sh":
|
|
57
|
+
subprocess.run(["bash", "-n", str(file)], check=True)
|
|
58
|
+
elif file.suffix == ".py":
|
|
59
|
+
compile(file.read_bytes(), str(file), "exec")
|
|
60
|
+
for file in payload.glob("*.sh"):
|
|
61
|
+
file.chmod(0o755)
|
|
62
|
+
# Quote absolute immutable path using shell single-quote escaping.
|
|
63
|
+
quoted = "'" + str(file).replace("'", "'\\''") + "'"
|
|
64
|
+
launcher = release / file.name
|
|
65
|
+
launcher.write_text("#!/bin/sh\nexec /bin/bash " + quoted + ' "$@"\n')
|
|
66
|
+
launcher.chmod(0o755)
|
|
67
|
+
files = {"bin/" + str(p.relative_to(release)): hashlib.sha256(p.read_bytes()).hexdigest()
|
|
68
|
+
for p in sorted(release.rglob("*")) if p.is_file()}
|
|
69
|
+
agents = Path.home() / "Library/LaunchAgents"
|
|
70
|
+
for p in sorted(agents.glob("com.karlchow.wiki-*.plist")):
|
|
71
|
+
files["LaunchAgents/" + p.name] = hashlib.sha256(p.read_bytes()).hexdigest()
|
|
72
|
+
new_manifest = dict(schema_version=1, package_version=version, package_commit=commit,
|
|
73
|
+
installer_version=version, installed_at=datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
|
74
|
+
role=role, host_id=host, files=files)
|
|
75
|
+
(release / "runtime-manifest.json").write_text(json.dumps(new_manifest, indent=2) + "\n")
|
|
76
|
+
(release / "previous-runtime-manifest.json").write_bytes(old_manifest)
|
|
77
|
+
if os.environ.get("VS_RUNTIME_TEST_FAIL") == "before-switch":
|
|
78
|
+
raise ValueError("injected pre-switch failure")
|
|
79
|
+
candidate = share / ".bin-next"
|
|
80
|
+
candidate.symlink_to(release)
|
|
81
|
+
if old_link is None:
|
|
82
|
+
backup = share / ("bin-backup-" + release.name)
|
|
83
|
+
current.rename(backup)
|
|
84
|
+
# A legacy runner that opened its script during staging must finish
|
|
85
|
+
# against the old libraries; refuse before exposing new libraries.
|
|
86
|
+
processes = subprocess.check_output(["ps", "-axww", "-o", "args="], text=True)
|
|
87
|
+
if any(str(current) + "/" in line for line in processes.splitlines()):
|
|
88
|
+
raise ValueError("legacy helper started during staging; runtime restored, retry later")
|
|
89
|
+
os.replace(candidate, current)
|
|
90
|
+
swapped = True
|
|
91
|
+
if os.environ.get("VS_RUNTIME_TEST_FAIL") == "after-switch":
|
|
92
|
+
raise ValueError("injected post-switch failure")
|
|
93
|
+
staged_manifest = share / ".runtime-manifest-next.json"
|
|
94
|
+
staged_manifest.write_bytes((release / "runtime-manifest.json").read_bytes())
|
|
95
|
+
os.replace(staged_manifest, manifest)
|
|
96
|
+
for relative, digest in files.items():
|
|
97
|
+
if relative.startswith("bin/") and hashlib.sha256((share / relative).read_bytes()).hexdigest() != digest:
|
|
98
|
+
raise ValueError("installed runtime hash mismatch")
|
|
99
|
+
print("runtime-only installed " + version + "; rollback=" + str(backup or old_link))
|
|
100
|
+
except BaseException:
|
|
101
|
+
if swapped:
|
|
102
|
+
current.unlink()
|
|
103
|
+
if backup is not None and backup.exists():
|
|
104
|
+
backup.rename(current)
|
|
105
|
+
elif swapped and old_link is not None:
|
|
106
|
+
current.symlink_to(old_link)
|
|
107
|
+
manifest.write_bytes(old_manifest)
|
|
108
|
+
if release is not None:
|
|
109
|
+
shutil.rmtree(release)
|
|
110
|
+
raise
|
|
111
|
+
finally:
|
|
112
|
+
(share / ".bin-next").unlink(missing_ok=True)
|
|
113
|
+
(share / ".runtime-manifest-next.json").unlink(missing_ok=True)
|
|
114
|
+
lock.rmdir()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if __name__ == "__main__":
|
|
118
|
+
def interrupted(_signal, _frame):
|
|
119
|
+
raise KeyboardInterrupt("runtime upgrade interrupted")
|
|
120
|
+
signal.signal(signal.SIGTERM, interrupted)
|
|
121
|
+
signal.signal(signal.SIGINT, interrupted)
|
|
122
|
+
try:
|
|
123
|
+
deploy(*sys.argv[1:7], dry_run=sys.argv[7:] == ["--dry-run"])
|
|
124
|
+
except (OSError, ValueError, subprocess.SubprocessError) as error:
|
|
125
|
+
print("runtime-only refused: " + str(error), file=sys.stderr)
|
|
126
|
+
sys.exit(1)
|
|
@@ -456,67 +456,13 @@ vault_sync_op_write_inventory() {
|
|
|
456
456
|
# Fail closed on any mismatch.
|
|
457
457
|
vault_sync_op_verify_inventory() {
|
|
458
458
|
local repo="$1" op_id="$2" stash_oid="${3:-}" skip_content_paths="${4:-}"
|
|
459
|
-
local inv
|
|
460
|
-
|
|
459
|
+
local inv restore_head helper
|
|
461
460
|
inv="$(vault_sync_op_get_field "$repo" "$op_id" inventory_path)" || return 1
|
|
462
|
-
[ -f "$inv" ] || return 1
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
has_u3=1
|
|
468
|
-
fi
|
|
469
|
-
section=""
|
|
470
|
-
while IFS= read -r path || [ -n "$path" ]; do
|
|
471
|
-
case "$path" in
|
|
472
|
-
"# staged") section="staged"; continue ;;
|
|
473
|
-
"# tracked") section="tracked"; continue ;;
|
|
474
|
-
"# untracked") section="untracked"; continue ;;
|
|
475
|
-
""|\#*) continue ;;
|
|
476
|
-
esac
|
|
477
|
-
[ -n "$path" ] || continue
|
|
478
|
-
[ -n "$section" ] || continue
|
|
479
|
-
|
|
480
|
-
# Skip content checks for currently-unmerged conflict paths.
|
|
481
|
-
if printf '%s\n' "$unmerged" | grep -Fxq -- "$path"; then
|
|
482
|
-
continue
|
|
483
|
-
fi
|
|
484
|
-
|
|
485
|
-
skip=0
|
|
486
|
-
if [ -n "$skip_content_paths" ] && printf '%s\n' "$skip_content_paths" | grep -Fxq -- "$path"; then
|
|
487
|
-
skip=1
|
|
488
|
-
fi
|
|
489
|
-
|
|
490
|
-
case "$section" in
|
|
491
|
-
staged|tracked)
|
|
492
|
-
if [ -n "$stash_oid" ] && git -C "$repo" cat-file -e "$stash_oid:$path" 2>/dev/null; then
|
|
493
|
-
if [ ! -f "$repo/$path" ] && [ ! -L "$repo/$path" ]; then
|
|
494
|
-
return 1
|
|
495
|
-
fi
|
|
496
|
-
if [ "$skip" -eq 0 ]; then
|
|
497
|
-
expected_hash="$(git -C "$repo" rev-parse "$stash_oid:$path" 2>/dev/null || echo missing)"
|
|
498
|
-
actual_hash="$(git -C "$repo" hash-object -- "$repo/$path" 2>/dev/null || echo missing)"
|
|
499
|
-
[ "$expected_hash" = "$actual_hash" ] || return 1
|
|
500
|
-
fi
|
|
501
|
-
fi
|
|
502
|
-
;;
|
|
503
|
-
untracked)
|
|
504
|
-
if [ ! -e "$repo/$path" ] && [ ! -L "$repo/$path" ]; then
|
|
505
|
-
return 1
|
|
506
|
-
fi
|
|
507
|
-
if [ "$skip" -eq 0 ] && [ "$has_u3" -eq 1 ]; then
|
|
508
|
-
if git -C "$repo" cat-file -e "${stash_oid}^3:$path" 2>/dev/null; then
|
|
509
|
-
expected_hash="$(git -C "$repo" rev-parse "${stash_oid}^3:$path" 2>/dev/null || echo missing)"
|
|
510
|
-
if [ -f "$repo/$path" ]; then
|
|
511
|
-
actual_hash="$(git -C "$repo" hash-object -- "$repo/$path" 2>/dev/null || echo missing)"
|
|
512
|
-
[ "$expected_hash" = "$actual_hash" ] || return 1
|
|
513
|
-
fi
|
|
514
|
-
fi
|
|
515
|
-
fi
|
|
516
|
-
;;
|
|
517
|
-
esac
|
|
518
|
-
done <"$inv"
|
|
519
|
-
return 0
|
|
461
|
+
[ -f "$inv" ] && [ -n "$stash_oid" ] || return 1
|
|
462
|
+
restore_head="$(vault_sync_op_get_field "$repo" "$op_id" restore_head)"
|
|
463
|
+
[ -n "$restore_head" ] || restore_head="$(git -C "$repo" rev-parse HEAD)" || return 1
|
|
464
|
+
helper="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/verify-stash-inventory.py"
|
|
465
|
+
python3 "$helper" "$repo" "$inv" "$stash_oid" "$restore_head" "$skip_content_paths"
|
|
520
466
|
}
|
|
521
467
|
|
|
522
468
|
vault_sync_op_stash_push_owned() {
|
|
@@ -99,6 +99,14 @@ vault_sync_package_commit() {
|
|
|
99
99
|
printf '%s\n' "$_override"
|
|
100
100
|
return 0
|
|
101
101
|
fi
|
|
102
|
+
# Exported deployment bundles have no .git; the bundle pin is the exact commit.
|
|
103
|
+
if [ -f "$_root/../../.deploy-pin" ]; then
|
|
104
|
+
_pin="$(cat "$_root/../../.deploy-pin")"
|
|
105
|
+
if printf '%s\n' "$_pin" | LC_ALL=C grep -Eq '^[0-9a-f]{40,64}$'; then
|
|
106
|
+
printf '%s\n' "$_pin"
|
|
107
|
+
return 0
|
|
108
|
+
fi
|
|
109
|
+
fi
|
|
102
110
|
if command -v git >/dev/null 2>&1 && [ -d "$_root/../../.git" -o -f "$_root/../../.git" ] 2>/dev/null; then
|
|
103
111
|
git -C "$_root/../.." rev-parse HEAD 2>/dev/null || echo ""
|
|
104
112
|
return 0
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Verify an owned stash restore against its frozen post-rebase baseline."""
|
|
3
|
+
import os
|
|
4
|
+
import pathlib
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
import tempfile
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def verify(repo, inventory, stash, head, skipped):
|
|
11
|
+
def git(*args, data=None, stream=None):
|
|
12
|
+
return subprocess.run(["git", "--literal-pathspecs", "-C", repo, *args], input=data, stdin=stream,
|
|
13
|
+
stdout=subprocess.PIPE, stderr=subprocess.PIPE, check=True).stdout
|
|
14
|
+
|
|
15
|
+
def entry(tree, path):
|
|
16
|
+
raw = git("ls-tree", "-z", tree, "--", path)
|
|
17
|
+
if not raw:
|
|
18
|
+
return None
|
|
19
|
+
meta, name = raw.rstrip(b"\0").split(b"\t", 1)
|
|
20
|
+
mode, kind, oid = meta.decode().split()
|
|
21
|
+
if name.decode() != path or kind != "blob":
|
|
22
|
+
raise ValueError("unsupported inventory entry")
|
|
23
|
+
return mode, oid
|
|
24
|
+
|
|
25
|
+
def expected(path):
|
|
26
|
+
base, local, upstream = (entry(tree, path) for tree in (stash + "^1", stash, head))
|
|
27
|
+
if local == base:
|
|
28
|
+
return upstream
|
|
29
|
+
if upstream == base or local == upstream:
|
|
30
|
+
return local
|
|
31
|
+
if not base or not local or not upstream:
|
|
32
|
+
raise ValueError("ambiguous add/delete restore")
|
|
33
|
+
if any(mode not in ("100644", "100755") for mode, _ in (base, local, upstream)):
|
|
34
|
+
raise ValueError("ambiguous file-type restore")
|
|
35
|
+
mode = local[0] if upstream[0] == base[0] else upstream[0]
|
|
36
|
+
with tempfile.TemporaryDirectory(prefix="stash-merge-") as directory:
|
|
37
|
+
files = [pathlib.Path(directory, name) for name in ("upstream", "base", "local")]
|
|
38
|
+
for file, value in zip(files, (upstream, base, local)):
|
|
39
|
+
if int(git("cat-file", "-s", value[1])) > 16 * 1024 * 1024:
|
|
40
|
+
raise ValueError("merge verification exceeds bounded file size")
|
|
41
|
+
file.write_bytes(git("cat-file", "blob", value[1]))
|
|
42
|
+
merged = subprocess.run(["git", "merge-file", "-p", *map(str, files)],
|
|
43
|
+
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
44
|
+
if merged.returncode:
|
|
45
|
+
raise ValueError("ambiguous content restore")
|
|
46
|
+
return mode, git("hash-object", "--stdin", data=merged.stdout).decode().strip()
|
|
47
|
+
|
|
48
|
+
if git("rev-parse", "HEAD").strip() != git("rev-parse", head).strip():
|
|
49
|
+
raise ValueError("restore baseline moved")
|
|
50
|
+
section = None
|
|
51
|
+
for path in pathlib.Path(inventory).read_text().splitlines():
|
|
52
|
+
if path in ("# staged", "# tracked", "# untracked"):
|
|
53
|
+
section = path[2:]
|
|
54
|
+
continue
|
|
55
|
+
if not section or not path or path.startswith("#"):
|
|
56
|
+
continue
|
|
57
|
+
if pathlib.PurePosixPath(path).is_absolute() or ".." in pathlib.PurePosixPath(path).parts:
|
|
58
|
+
raise ValueError("invalid inventory path")
|
|
59
|
+
file = pathlib.Path(repo, path)
|
|
60
|
+
if any(parent.is_symlink() for parent in file.parents if parent != pathlib.Path(repo) and pathlib.Path(repo) in parent.parents):
|
|
61
|
+
raise ValueError("inventory parent changed type")
|
|
62
|
+
# Unknown conflicts must never be treated as verified restoration.
|
|
63
|
+
if git("ls-files", "-u", "--", path):
|
|
64
|
+
raise ValueError("unresolved inventory path")
|
|
65
|
+
if path in skipped:
|
|
66
|
+
derived = path in ("index.md", "SCHEMA.md", "log.md") or path.endswith("/log.md") or (path.startswith("projects/") and path.count("/") == 2 and path.endswith("/knowledge.md"))
|
|
67
|
+
if not derived:
|
|
68
|
+
raise ValueError("non-derived inventory exemption")
|
|
69
|
+
want = entry(stash, path) or entry(head, path)
|
|
70
|
+
else:
|
|
71
|
+
want = entry(stash + "^3", path) if section == "untracked" else expected(path)
|
|
72
|
+
if want is None:
|
|
73
|
+
if os.path.lexists(file):
|
|
74
|
+
raise ValueError("deleted inventory path reappeared")
|
|
75
|
+
continue
|
|
76
|
+
mode, oid = want
|
|
77
|
+
if mode == "120000":
|
|
78
|
+
if not file.is_symlink():
|
|
79
|
+
raise ValueError("inventory symlink type changed")
|
|
80
|
+
data = os.fsencode(os.readlink(file))
|
|
81
|
+
else:
|
|
82
|
+
if file.is_symlink() or not file.is_file():
|
|
83
|
+
raise ValueError("inventory regular file missing or type changed")
|
|
84
|
+
if mode not in ("100644", "100755"):
|
|
85
|
+
raise ValueError("unsupported inventory mode")
|
|
86
|
+
if bool(file.stat().st_mode & 0o111) != (mode == "100755"):
|
|
87
|
+
raise ValueError("inventory executable mode changed")
|
|
88
|
+
data = None
|
|
89
|
+
if path not in skipped:
|
|
90
|
+
if data is None:
|
|
91
|
+
with file.open("rb") as stream:
|
|
92
|
+
actual = git("hash-object", "--stdin", stream=stream)
|
|
93
|
+
else:
|
|
94
|
+
actual = git("hash-object", "--stdin", data=data)
|
|
95
|
+
if actual.decode().strip() != oid:
|
|
96
|
+
raise ValueError("inventory content mismatch")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
if __name__ == "__main__":
|
|
100
|
+
try:
|
|
101
|
+
repo, inventory, stash, head, skip = sys.argv[1:]
|
|
102
|
+
verify(repo, inventory, stash, head, set(skip.splitlines()))
|
|
103
|
+
except (OSError, ValueError, subprocess.SubprocessError):
|
|
104
|
+
print("inventory verification refused: missing, changed or ambiguous restore", file=sys.stderr)
|
|
105
|
+
sys.exit(1)
|
|
@@ -220,6 +220,7 @@ try_auto_resolve_derived_conflicts() {
|
|
|
220
220
|
cmd_rc=$?
|
|
221
221
|
printf '%s\n' "$resolver_out" >>"$LOG_FILE"
|
|
222
222
|
if [ "$cmd_rc" -eq 0 ]; then
|
|
223
|
+
RESOLVED_PATHS="$(printf '%s\n' "$resolver_out" | python3 -c 'import json,sys; print("\n".join(json.load(sys.stdin)["data"]["resolved_paths"]))')" || return 1
|
|
223
224
|
log "AUTO-RESOLVE composite derived artifacts op=$op_id"
|
|
224
225
|
return 0
|
|
225
226
|
elif [ "$cmd_rc" -eq 60 ]; then
|
|
@@ -243,6 +244,7 @@ except: pass
|
|
|
243
244
|
cmd_rc=$?
|
|
244
245
|
printf '%s\n' "$resolver_out" >>"$LOG_FILE"
|
|
245
246
|
if [ "$cmd_rc" -eq 0 ]; then
|
|
247
|
+
RESOLVED_PATHS="$(printf '%s\n' "$resolver_out" | python3 -c 'import json,sys; print("\n".join(json.load(sys.stdin)["data"]["resolved_paths"]))')" || return 1
|
|
246
248
|
log "AUTO-RESOLVE composite derived artifacts op=$op_id (skillwiki)"
|
|
247
249
|
return 0
|
|
248
250
|
elif [ "$cmd_rc" -eq 60 ]; then
|
|
@@ -615,12 +617,11 @@ while [ $REBASE_RC -ne 0 ]; do
|
|
|
615
617
|
continue
|
|
616
618
|
fi
|
|
617
619
|
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
fi
|
|
620
|
+
RESOLVER_RC=0
|
|
621
|
+
try_auto_resolve_derived_conflicts "$OP_ID" || RESOLVER_RC=$?
|
|
622
|
+
if [ "$RESOLVER_RC" -eq 0 ]; then
|
|
623
|
+
GIT_EDITOR=true git rebase --continue 2>>"$LOG_FILE"
|
|
624
|
+
REBASE_RC=$?
|
|
624
625
|
continue
|
|
625
626
|
fi
|
|
626
627
|
|
|
@@ -628,8 +629,7 @@ while [ $REBASE_RC -ne 0 ]; do
|
|
|
628
629
|
# The unknown paths must go through the manual-conflict path (retry/handoff).
|
|
629
630
|
# The derived paths are already git-added; rebase --continue will fail on
|
|
630
631
|
# the remaining unknowns, so we go straight to handle_manual_conflict.
|
|
631
|
-
if [ "
|
|
632
|
-
local unknown_conflicts
|
|
632
|
+
if [ "$RESOLVER_RC" -eq 60 ]; then
|
|
633
633
|
unknown_conflicts="$(git diff --name-only --diff-filter=U 2>/dev/null)"
|
|
634
634
|
if [ -n "$unknown_conflicts" ]; then
|
|
635
635
|
STOPPED_SHA=$(cat "$WIKI_DIR/.git/rebase-merge/stopped-sha" 2>/dev/null || echo "")
|
|
@@ -659,6 +659,7 @@ while [ $REBASE_RC -ne 0 ]; do
|
|
|
659
659
|
done
|
|
660
660
|
|
|
661
661
|
if [ -n "$OWNED_STASH_OID" ]; then
|
|
662
|
+
vault_sync_op_set_field "$WIKI_DIR" "$OP_ID" restore_head "$(git rev-parse HEAD)" || exit 1
|
|
662
663
|
if vault_sync_op_stash_apply_owned "$WIKI_DIR" "$OWNED_STASH_OID" 2>>"$LOG_FILE"; then
|
|
663
664
|
if ! vault_sync_op_verify_inventory "$WIKI_DIR" "$OP_ID" "$OWNED_STASH_OID" 2>>"$LOG_FILE"; then
|
|
664
665
|
vault_sync_op_mark_review_required "$WIKI_DIR" "$OP_ID" "inventory-verify-failed"
|
|
@@ -673,7 +674,12 @@ if [ -n "$OWNED_STASH_OID" ]; then
|
|
|
673
674
|
else
|
|
674
675
|
CONFLICTS=$(git diff --name-only --diff-filter=U 2>/dev/null)
|
|
675
676
|
vault_sync_op_set_phase "$WIKI_DIR" "$OP_ID" "restoring"
|
|
676
|
-
|
|
677
|
+
RESOLVER_RC=1
|
|
678
|
+
if [ -n "$CONFLICTS" ]; then
|
|
679
|
+
RESOLVER_RC=0
|
|
680
|
+
try_auto_resolve_derived_conflicts "$OP_ID" || RESOLVER_RC=$?
|
|
681
|
+
fi
|
|
682
|
+
if [ "$RESOLVER_RC" -eq 0 ]; then
|
|
677
683
|
if [ -n "$(git diff --name-only --diff-filter=U 2>/dev/null)" ]; then
|
|
678
684
|
vault_sync_op_mark_review_required "$WIKI_DIR" "$OP_ID" "stash-restore-conflicts"
|
|
679
685
|
log "FAIL stash apply derived auto-resolve left conflicts"
|
|
@@ -681,7 +687,7 @@ if [ -n "$OWNED_STASH_OID" ]; then
|
|
|
681
687
|
fi
|
|
682
688
|
# Derived regeneration rewrites conflicted paths; verify presence for those
|
|
683
689
|
# paths and content for everything else.
|
|
684
|
-
SKIP_CONTENT="$
|
|
690
|
+
SKIP_CONTENT="${RESOLVED_PATHS:-}"
|
|
685
691
|
if ! vault_sync_op_verify_inventory "$WIKI_DIR" "$OP_ID" "$OWNED_STASH_OID" "$SKIP_CONTENT" 2>>"$LOG_FILE"; then
|
|
686
692
|
vault_sync_op_mark_review_required "$WIKI_DIR" "$OP_ID" "inventory-verify-failed"
|
|
687
693
|
log "FAIL inventory verification after derived auto-resolve oid=$OWNED_STASH_OID"
|
|
@@ -690,7 +696,7 @@ if [ -n "$OWNED_STASH_OID" ]; then
|
|
|
690
696
|
|
|
691
697
|
vault_sync_op_stash_drop_owned "$WIKI_DIR" "$OWNED_STASH_OID" 2>>"$LOG_FILE" || true
|
|
692
698
|
log "STASH apply derived conflicts auto-resolved"
|
|
693
|
-
elif [
|
|
699
|
+
elif [ "$RESOLVER_RC" -eq 60 ]; then
|
|
694
700
|
# M4: Partial-decline during stash-apply. The resolver resolved the
|
|
695
701
|
# derived subset and returned resolved_paths. Unknown paths remain
|
|
696
702
|
# conflicted — surface as review-required.
|
|
@@ -704,11 +710,7 @@ if [ -n "$OWNED_STASH_OID" ]; then
|
|
|
704
710
|
# derived paths. The conflict set alone is insufficient because the
|
|
705
711
|
# resolver regenerates derived files that may not have been in the
|
|
706
712
|
# stash-apply conflict set (derived-conflicts.ts:100-134).
|
|
707
|
-
SKIP_CONTENT="$
|
|
708
|
-
if [ -n "${RESOLVED_PATHS:-}" ]; then
|
|
709
|
-
SKIP_CONTENT="${SKIP_CONTENT}
|
|
710
|
-
${RESOLVED_PATHS}"
|
|
711
|
-
fi
|
|
713
|
+
SKIP_CONTENT="${RESOLVED_PATHS:-}"
|
|
712
714
|
if ! vault_sync_op_verify_inventory "$WIKI_DIR" "$OP_ID" "$OWNED_STASH_OID" "$SKIP_CONTENT" 2>>"$LOG_FILE"; then
|
|
713
715
|
vault_sync_op_mark_review_required "$WIKI_DIR" "$OP_ID" "inventory-verify-failed-partial"
|
|
714
716
|
log "FAIL inventory verification after partial-decline oid=$OWNED_STASH_OID"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.116",
|
|
4
4
|
"skills": "./",
|
|
5
5
|
"description": "Project-aware Karpathy-style knowledge base for Claude Code: 22 prompt-only skills (wiki-*, proj-*, using-skillwiki, skillwiki-mcp, skillwiki-connect) 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.116",
|
|
4
4
|
"description": "Project-aware Karpathy-style knowledge base: 22 prompt-only skills (wiki-*, proj-*, using-skillwiki, skillwiki-mcp, skillwiki-connect) backed by HTTP MCP wiki_capture.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "karlorz"
|
package/skills/package.json
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
atomicWriteText
|
|
4
|
-
} from "./chunk-6VUK2FTX.js";
|
|
5
2
|
import {
|
|
6
3
|
PRODUCTION_MIRROR_LABEL,
|
|
7
4
|
PRODUCTION_WATCHER_LABEL,
|
|
@@ -15,6 +12,9 @@ import {
|
|
|
15
12
|
import {
|
|
16
13
|
parseDotenvFile
|
|
17
14
|
} from "./chunk-IJKJGQKL.js";
|
|
15
|
+
import {
|
|
16
|
+
atomicWriteText
|
|
17
|
+
} from "./chunk-6VUK2FTX.js";
|
|
18
18
|
|
|
19
19
|
// src/clip-outbox/migrate.ts
|
|
20
20
|
import { access, mkdir, readFile } from "fs/promises";
|
|
@@ -35,15 +35,15 @@ import {
|
|
|
35
35
|
splitFrontmatter,
|
|
36
36
|
vaultIoConcurrency
|
|
37
37
|
} from "./chunk-JL2SCLXT.js";
|
|
38
|
-
import {
|
|
39
|
-
atomicWriteText
|
|
40
|
-
} from "./chunk-6VUK2FTX.js";
|
|
41
38
|
import {
|
|
42
39
|
parseDotenvFile,
|
|
43
40
|
parseDotenvText,
|
|
44
41
|
profileKey,
|
|
45
42
|
resolveSkillwikiHome
|
|
46
43
|
} from "./chunk-IJKJGQKL.js";
|
|
44
|
+
import {
|
|
45
|
+
atomicWriteText
|
|
46
|
+
} from "./chunk-6VUK2FTX.js";
|
|
47
47
|
import {
|
|
48
48
|
ExitCode,
|
|
49
49
|
FleetManifestSchema,
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
readJournal,
|
|
4
|
-
upsertJournal,
|
|
5
|
-
writeJournal
|
|
6
|
-
} from "./chunk-SEY4N4CT.js";
|
|
7
2
|
import {
|
|
8
3
|
buildReadyHint
|
|
9
4
|
} from "./chunk-OSL4J7GF.js";
|
|
@@ -14,10 +9,15 @@ import {
|
|
|
14
9
|
sha256Hex
|
|
15
10
|
} from "./chunk-ZRGZBAVS.js";
|
|
16
11
|
import "./chunk-QESNTTVY.js";
|
|
17
|
-
import "./chunk-6VUK2FTX.js";
|
|
18
12
|
import {
|
|
19
13
|
assertPublicHttpsUrl
|
|
20
14
|
} from "./chunk-5D5HFQ76.js";
|
|
15
|
+
import {
|
|
16
|
+
readJournal,
|
|
17
|
+
upsertJournal,
|
|
18
|
+
writeJournal
|
|
19
|
+
} from "./chunk-SEY4N4CT.js";
|
|
20
|
+
import "./chunk-6VUK2FTX.js";
|
|
21
21
|
import "./chunk-VNSZCK5V.js";
|
|
22
22
|
|
|
23
23
|
// src/clip-outbox/watcher.ts
|