skillwiki 0.10.91 → 0.10.94
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-ZUHA2EXE.js → chunk-3KEMRVWR.js} +2 -2
- package/dist/{chunk-ZYVP52PM.js → chunk-BXEG5OWD.js} +12 -7
- package/dist/{chunk-JHDN3FSF.js → chunk-C5WOEVX3.js} +1 -1
- package/dist/{chunk-QFRZDTJY.js → chunk-LTSIHHKD.js} +1 -1
- package/dist/{chunk-6WE7E6VB.js → chunk-OTESAW36.js} +13 -4
- package/dist/{chunk-XJR3XXP5.js → chunk-SXNKZGNM.js} +1 -0
- package/dist/{chunk-ECOEJABP.js → chunk-UDOZKMCN.js} +2 -2
- package/dist/cli.js +215 -80
- package/dist/{index-projection-YP4JIMIQ.js → index-projection-3ZMM53WL.js} +3 -3
- package/dist/{managed-write-preflight-2Y5Q2WH4.js → managed-write-preflight-T4WOM52R.js} +4 -4
- package/dist/skillwiki-mcp.js +7 -7
- package/dist/sources-4KCCBNCO.js +9 -0
- package/dist/vault-sync/scripts/lib/git-promotion-policy.sh +20 -0
- package/dist/vault-sync/scripts/wiki-fetch-notify.sh +55 -2
- package/dist/vault-sync/scripts/wiki-snapshot.sh +62 -33
- 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/sources-A5GFRY3F.js +0 -9
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
ROOT_INDEX_SECTION_ORDER,
|
|
4
4
|
atomicWriteText,
|
|
5
5
|
buildRootIndexUniverse
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-C5WOEVX3.js";
|
|
7
7
|
import {
|
|
8
8
|
err,
|
|
9
9
|
ok
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-SXNKZGNM.js";
|
|
11
11
|
|
|
12
12
|
// src/utils/index-projection.ts
|
|
13
13
|
import { readFile } from "fs/promises";
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
renderRootIndex,
|
|
8
8
|
writeRootIndexProjection
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-3KEMRVWR.js";
|
|
10
10
|
import {
|
|
11
11
|
CONFIG_KEYS,
|
|
12
12
|
VAULT_HYGIENE_GENERATED_COMMIT_PATHS,
|
|
@@ -40,11 +40,11 @@ import {
|
|
|
40
40
|
snapshotterAliasForLocalHost,
|
|
41
41
|
toUndirectedWeighted,
|
|
42
42
|
writeDotenv
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-OTESAW36.js";
|
|
44
44
|
import {
|
|
45
45
|
atomicWriteText,
|
|
46
46
|
prepareTypedPage
|
|
47
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-C5WOEVX3.js";
|
|
48
48
|
import {
|
|
49
49
|
applySourceCompileClaim,
|
|
50
50
|
applySourceCompilePublished,
|
|
@@ -57,11 +57,11 @@ import {
|
|
|
57
57
|
planSourceCompileRelease,
|
|
58
58
|
planSourceReview,
|
|
59
59
|
runSourcesPending
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-UDOZKMCN.js";
|
|
61
61
|
import {
|
|
62
62
|
eventPathFor,
|
|
63
63
|
writeLogEvent
|
|
64
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-LTSIHHKD.js";
|
|
65
65
|
import {
|
|
66
66
|
CompoundSchema,
|
|
67
67
|
ExitCode,
|
|
@@ -82,7 +82,7 @@ import {
|
|
|
82
82
|
scanVault,
|
|
83
83
|
splitFrontmatter,
|
|
84
84
|
systemdPropertyFor
|
|
85
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-SXNKZGNM.js";
|
|
86
86
|
|
|
87
87
|
// src/commands/log-append.ts
|
|
88
88
|
import { readFile, stat } from "fs/promises";
|
|
@@ -4516,6 +4516,9 @@ function isEventLedgerPath(rel) {
|
|
|
4516
4516
|
const n = rel.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
4517
4517
|
return n === "meta/log-events" || n.startsWith("meta/log-events/");
|
|
4518
4518
|
}
|
|
4519
|
+
function countEventLedgerFiles(vault) {
|
|
4520
|
+
return listFilesRecursive(join21(vault, "meta", "log-events")).length;
|
|
4521
|
+
}
|
|
4519
4522
|
function measureDirtyVolume(vault) {
|
|
4520
4523
|
const empty = (extra = {}) => ({
|
|
4521
4524
|
porcelain_lines: 0,
|
|
@@ -6482,7 +6485,7 @@ async function runQuery(input) {
|
|
|
6482
6485
|
}
|
|
6483
6486
|
let pendingSources;
|
|
6484
6487
|
if (input.includePending) {
|
|
6485
|
-
const { runSourcesPending: runSourcesPending2 } = await import("./sources-
|
|
6488
|
+
const { runSourcesPending: runSourcesPending2 } = await import("./sources-4KCCBNCO.js");
|
|
6486
6489
|
const pending = await runSourcesPending2({
|
|
6487
6490
|
vault: input.vault,
|
|
6488
6491
|
match: input.text,
|
|
@@ -7847,6 +7850,8 @@ export {
|
|
|
7847
7850
|
DEFAULT_CAPTURE_BUDGET,
|
|
7848
7851
|
DEFAULT_NO_DECISION_STREAK,
|
|
7849
7852
|
GateError,
|
|
7853
|
+
isEventLedgerPath,
|
|
7854
|
+
countEventLedgerFiles,
|
|
7850
7855
|
measureDirtyVolume,
|
|
7851
7856
|
evaluateDirtyVolumeGate,
|
|
7852
7857
|
CAPTURE_HYGIENE_CONTRACT,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
atomicWriteText,
|
|
4
4
|
buildRootIndexUniverse
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-C5WOEVX3.js";
|
|
6
6
|
import {
|
|
7
7
|
authorizeRawOperation,
|
|
8
8
|
buildSourceReferenceIndex,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
resolveExistingRegularFileInsideVault,
|
|
23
23
|
stripFencedBlocks,
|
|
24
24
|
writeLogEvent
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-LTSIHHKD.js";
|
|
26
26
|
import {
|
|
27
27
|
ExitCode,
|
|
28
28
|
FleetManifestSchema,
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
scanVault,
|
|
42
42
|
splitFrontmatter,
|
|
43
43
|
vaultIoConcurrency
|
|
44
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-SXNKZGNM.js";
|
|
45
45
|
|
|
46
46
|
// src/utils/managed-write-preflight.ts
|
|
47
47
|
import { existsSync as existsSync11 } from "fs";
|
|
@@ -5340,12 +5340,14 @@ async function runSyncLintDelta(input) {
|
|
|
5340
5340
|
|
|
5341
5341
|
// src/utils/git.ts
|
|
5342
5342
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
5343
|
+
var GIT_OUTPUT_MAX_BUFFER = 16 * 1024 * 1024;
|
|
5343
5344
|
function git(cwd, args, opts) {
|
|
5344
5345
|
try {
|
|
5345
5346
|
return execFileSync2("git", args, {
|
|
5346
5347
|
cwd,
|
|
5347
5348
|
encoding: "utf8",
|
|
5348
5349
|
stdio: ["pipe", "pipe", "pipe"],
|
|
5350
|
+
maxBuffer: GIT_OUTPUT_MAX_BUFFER,
|
|
5349
5351
|
...opts?.timeoutMs !== void 0 ? { timeout: opts.timeoutMs } : {}
|
|
5350
5352
|
}).trim();
|
|
5351
5353
|
} catch {
|
|
@@ -5353,7 +5355,12 @@ function git(cwd, args, opts) {
|
|
|
5353
5355
|
}
|
|
5354
5356
|
}
|
|
5355
5357
|
function gitStrict(cwd, args) {
|
|
5356
|
-
return execFileSync2("git", args, {
|
|
5358
|
+
return execFileSync2("git", args, {
|
|
5359
|
+
cwd,
|
|
5360
|
+
encoding: "utf8",
|
|
5361
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
5362
|
+
maxBuffer: GIT_OUTPUT_MAX_BUFFER
|
|
5363
|
+
}).trim();
|
|
5357
5364
|
}
|
|
5358
5365
|
|
|
5359
5366
|
// src/utils/sync-lock.ts
|
|
@@ -5538,6 +5545,7 @@ var VAULT_HYGIENE_GENERATED_COMMIT_PATHS = VAULT_HYGIENE_GITIGNORE_PATTERNS.map(
|
|
|
5538
5545
|
(pattern) => pattern.replace(/\/$/, "")
|
|
5539
5546
|
);
|
|
5540
5547
|
var VAULT_SYNC_FILTER_REQUIRED_EXCLUDES = [
|
|
5548
|
+
"/.WIKI_GIT_FROZEN",
|
|
5541
5549
|
"remotely-save/data.json",
|
|
5542
5550
|
".skillwiki/sync.lock",
|
|
5543
5551
|
".skillwiki/managed-write.lock",
|
|
@@ -7442,6 +7450,7 @@ export {
|
|
|
7442
7450
|
canSupersedeJournal,
|
|
7443
7451
|
markJournalSuperseded,
|
|
7444
7452
|
supersedeStaleReviewRequiredJournals,
|
|
7453
|
+
readSkillWikiConfig,
|
|
7445
7454
|
resolveConfiguredSnapshotWorktree,
|
|
7446
7455
|
DEFAULT_MANAGED_WRITE_WAIT_MS,
|
|
7447
7456
|
MANAGED_WRITE_POLL_INTERVAL_MS,
|
|
@@ -389,6 +389,7 @@ var VaultSyncConfigSchema = z.object({
|
|
|
389
389
|
"vault_sync.snapshot_profile": vaultSyncPathOrNone,
|
|
390
390
|
"vault_sync.snapshot_script": vaultSyncPathOrNone,
|
|
391
391
|
"vault_sync.snapshot_worktree": vaultSyncPathOrNone,
|
|
392
|
+
"vault_sync.fetch_projection": vaultSyncPathOrNone,
|
|
392
393
|
"vault_sync.push_enabled": vaultSyncBool,
|
|
393
394
|
"vault_sync.fuse_refresh_enabled": vaultSyncBool,
|
|
394
395
|
"vault_sync.fuse_refresh_interval": vaultSyncDuration,
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
readLogEvents,
|
|
9
9
|
resolveExistingRegularFileInsideVault,
|
|
10
10
|
writeLogEvent
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LTSIHHKD.js";
|
|
12
12
|
import {
|
|
13
13
|
ExitCode,
|
|
14
14
|
RawSourceSchema,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
scanSensitiveContent,
|
|
20
20
|
scanVault,
|
|
21
21
|
splitFrontmatter
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-SXNKZGNM.js";
|
|
23
23
|
|
|
24
24
|
// src/commands/sources.ts
|
|
25
25
|
import { readFile as readFile4 } from "fs/promises";
|
package/dist/cli.js
CHANGED
|
@@ -9,11 +9,13 @@ import {
|
|
|
9
9
|
SATELLITE_STALE_MS,
|
|
10
10
|
buildVectorIndex,
|
|
11
11
|
configPath,
|
|
12
|
+
countEventLedgerFiles,
|
|
12
13
|
detectFuseMount,
|
|
13
14
|
evaluateDirtyVolumeGate,
|
|
14
15
|
evaluateSatelliteRunHealth,
|
|
15
16
|
findPlugin,
|
|
16
17
|
guardProtectedVaultWrite,
|
|
18
|
+
isEventLedgerPath,
|
|
17
19
|
isFailedRunStatus,
|
|
18
20
|
measureDirtyVolume,
|
|
19
21
|
memoryAuthorityTiersRank,
|
|
@@ -53,7 +55,7 @@ import {
|
|
|
53
55
|
snapshotterHealthChecks,
|
|
54
56
|
upsertIndexEntry,
|
|
55
57
|
vectorIndexStatus
|
|
56
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-BXEG5OWD.js";
|
|
57
59
|
import {
|
|
58
60
|
normalizeDistTag,
|
|
59
61
|
readCache,
|
|
@@ -66,7 +68,7 @@ import {
|
|
|
66
68
|
UNMANAGED_START,
|
|
67
69
|
renderRootIndex,
|
|
68
70
|
writeRootIndexProjection
|
|
69
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-3KEMRVWR.js";
|
|
70
72
|
import {
|
|
71
73
|
FLEET_REL_PATH,
|
|
72
74
|
REDACTED_MALFORMED_REFERENCE,
|
|
@@ -115,6 +117,7 @@ import {
|
|
|
115
117
|
profileKey,
|
|
116
118
|
readJournal,
|
|
117
119
|
readLastOp,
|
|
120
|
+
readSkillWikiConfig,
|
|
118
121
|
reconcileTaxonomyDocument,
|
|
119
122
|
releaseOwnedSyncLock,
|
|
120
123
|
renderVaultGitignoreTemplate,
|
|
@@ -157,12 +160,12 @@ import {
|
|
|
157
160
|
supersedeStaleReviewRequiredJournals,
|
|
158
161
|
taxonomyCommentForPage,
|
|
159
162
|
writeDotenv
|
|
160
|
-
} from "./chunk-
|
|
163
|
+
} from "./chunk-OTESAW36.js";
|
|
161
164
|
import {
|
|
162
165
|
assertTargetInsideVault,
|
|
163
166
|
atomicWriteText,
|
|
164
167
|
prepareTypedPage
|
|
165
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-C5WOEVX3.js";
|
|
166
169
|
import {
|
|
167
170
|
applySourceDisposition,
|
|
168
171
|
decodeSourceActionApproval,
|
|
@@ -170,7 +173,7 @@ import {
|
|
|
170
173
|
inventorySources,
|
|
171
174
|
planSourceDisposition,
|
|
172
175
|
runSourcesPending
|
|
173
|
-
} from "./chunk-
|
|
176
|
+
} from "./chunk-UDOZKMCN.js";
|
|
174
177
|
import {
|
|
175
178
|
authorizeRawOperation,
|
|
176
179
|
buildSourceReferenceIndex,
|
|
@@ -187,7 +190,7 @@ import {
|
|
|
187
190
|
resolveExistingRegularFileInsideVault,
|
|
188
191
|
validateLogEvent,
|
|
189
192
|
writeLogEvent
|
|
190
|
-
} from "./chunk-
|
|
193
|
+
} from "./chunk-LTSIHHKD.js";
|
|
191
194
|
import {
|
|
192
195
|
ExitCode,
|
|
193
196
|
MetaSchema,
|
|
@@ -208,10 +211,10 @@ import {
|
|
|
208
211
|
scanVault,
|
|
209
212
|
splitFrontmatter,
|
|
210
213
|
vaultIoConcurrency
|
|
211
|
-
} from "./chunk-
|
|
214
|
+
} from "./chunk-SXNKZGNM.js";
|
|
212
215
|
|
|
213
216
|
// src/cli.ts
|
|
214
|
-
import { join as
|
|
217
|
+
import { join as join44 } from "path";
|
|
215
218
|
import { Command } from "commander";
|
|
216
219
|
|
|
217
220
|
// src/utils/output.ts
|
|
@@ -1604,21 +1607,21 @@ function rollbackPath(vault, path, stage2, stage3) {
|
|
|
1604
1607
|
function hasMarkers(path, text) {
|
|
1605
1608
|
const lines = text.split(/\r?\n/);
|
|
1606
1609
|
let open2 = false;
|
|
1607
|
-
let
|
|
1610
|
+
let sep5 = false;
|
|
1608
1611
|
for (const line of lines) {
|
|
1609
1612
|
if (line.startsWith("<<<<<<< ")) {
|
|
1610
1613
|
open2 = true;
|
|
1611
|
-
|
|
1614
|
+
sep5 = false;
|
|
1612
1615
|
continue;
|
|
1613
1616
|
}
|
|
1614
1617
|
if (line === "=======" && open2) {
|
|
1615
|
-
|
|
1618
|
+
sep5 = true;
|
|
1616
1619
|
continue;
|
|
1617
1620
|
}
|
|
1618
|
-
if (line.startsWith(">>>>>>> ") && open2 &&
|
|
1621
|
+
if (line.startsWith(">>>>>>> ") && open2 && sep5) return true;
|
|
1619
1622
|
if (line.startsWith(">>>>>>> ")) {
|
|
1620
1623
|
open2 = false;
|
|
1621
|
-
|
|
1624
|
+
sep5 = false;
|
|
1622
1625
|
}
|
|
1623
1626
|
}
|
|
1624
1627
|
return false;
|
|
@@ -3785,7 +3788,7 @@ ${fmRewritten}
|
|
|
3785
3788
|
}
|
|
3786
3789
|
let indexUpdated = false;
|
|
3787
3790
|
if (!isRaw) {
|
|
3788
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
3791
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-3ZMM53WL.js");
|
|
3789
3792
|
const before = await readFile7(join19(input.vault, "index.md"), "utf8").catch(() => "");
|
|
3790
3793
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
3791
3794
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
|
@@ -3906,10 +3909,10 @@ async function runRemove(input) {
|
|
|
3906
3909
|
const tombstonePath = await writeDeleteIntent(input.vault, intent);
|
|
3907
3910
|
await unlink2(join20(input.vault, relPath));
|
|
3908
3911
|
if (relPath.endsWith(".md") && !relPath.startsWith("raw/")) {
|
|
3909
|
-
const { readFile:
|
|
3912
|
+
const { readFile: readFile23 } = await import("fs/promises");
|
|
3910
3913
|
const { join: pathJoin } = await import("path");
|
|
3911
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
3912
|
-
const before = await
|
|
3914
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-3ZMM53WL.js");
|
|
3915
|
+
const before = await readFile23(pathJoin(input.vault, "index.md"), "utf8").catch(() => "");
|
|
3913
3916
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
3914
3917
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
|
3915
3918
|
const hadIndexEntry = before.includes(`[[${fullTarget}]]`) || before.includes(`[[${bare}]]`);
|
|
@@ -7366,7 +7369,7 @@ async function acquireRawCaptureLock(path) {
|
|
|
7366
7369
|
if (error.code !== "EEXIST") {
|
|
7367
7370
|
return err("WRITE_FAILED", { path: lockPath, phase: "raw-lock", message: String(error) });
|
|
7368
7371
|
}
|
|
7369
|
-
await new Promise((
|
|
7372
|
+
await new Promise((resolve9) => setTimeout(resolve9, 10));
|
|
7370
7373
|
}
|
|
7371
7374
|
}
|
|
7372
7375
|
return err("WRITE_FAILED", { path: lockPath, phase: "raw-lock", message: "raw capture lock held" });
|
|
@@ -9328,8 +9331,83 @@ async function runStatus(input) {
|
|
|
9328
9331
|
}
|
|
9329
9332
|
|
|
9330
9333
|
// src/commands/copy-status.ts
|
|
9331
|
-
import { existsSync as existsSync13 } from "fs";
|
|
9332
|
-
import { join as
|
|
9334
|
+
import { existsSync as existsSync13, realpathSync as realpathSync5 } from "fs";
|
|
9335
|
+
import { isAbsolute as isAbsolute2, join as join38, relative as relative5, resolve as resolve8 } from "path";
|
|
9336
|
+
|
|
9337
|
+
// src/utils/fetch-projection.ts
|
|
9338
|
+
import { isAbsolute, join as join37, resolve as resolve7 } from "path";
|
|
9339
|
+
function inspectConfiguredFetchProjection(home) {
|
|
9340
|
+
if (!home) return { configured: false };
|
|
9341
|
+
const config = readSkillWikiConfig(join37(home, ".skillwiki", ".env"));
|
|
9342
|
+
const configured = config["vault_sync.fetch_projection"];
|
|
9343
|
+
if (!configured || configured === "none") return { configured: false };
|
|
9344
|
+
if (!isAbsolute(configured)) {
|
|
9345
|
+
return { configured: true, invalidDetail: "configured fetch projection path must be absolute" };
|
|
9346
|
+
}
|
|
9347
|
+
return { configured: true, path: resolve7(configured) };
|
|
9348
|
+
}
|
|
9349
|
+
|
|
9350
|
+
// src/utils/live-drift.ts
|
|
9351
|
+
import { createHash as createHash6 } from "crypto";
|
|
9352
|
+
import { readFile as readFile19 } from "fs/promises";
|
|
9353
|
+
import { relative as relative4, sep as sep3 } from "path";
|
|
9354
|
+
|
|
9355
|
+
// src/utils/git-promotion.ts
|
|
9356
|
+
function normalizedRelativePath(path) {
|
|
9357
|
+
return path.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
9358
|
+
}
|
|
9359
|
+
function isGitPromotablePath(path) {
|
|
9360
|
+
const rel = normalizedRelativePath(path);
|
|
9361
|
+
if (/^(?:\.skillwiki|\.claude|\.obsidian|\.antigravitycli|\.playwright-cli|\.superpowers|\.snapshots|\.git|\.drafts)(?:\/|$)/.test(rel)) {
|
|
9362
|
+
return false;
|
|
9363
|
+
}
|
|
9364
|
+
if (/^(?:tmp|logs)(?:\/|$)/.test(rel) || isEventLedgerPath(rel)) return false;
|
|
9365
|
+
if (rel === "raw/._.DS_Store" || rel === "._.DS_Store" || rel.startsWith("._")) return false;
|
|
9366
|
+
if (rel.startsWith(".conflict") || rel.includes(".conflict-")) return false;
|
|
9367
|
+
return true;
|
|
9368
|
+
}
|
|
9369
|
+
|
|
9370
|
+
// src/utils/live-drift.ts
|
|
9371
|
+
function gitBlobOid(bytes) {
|
|
9372
|
+
const header = Buffer.from(`blob ${bytes.length}\0`);
|
|
9373
|
+
return createHash6("sha1").update(header).update(bytes).digest("hex");
|
|
9374
|
+
}
|
|
9375
|
+
function headBlobOids(projection) {
|
|
9376
|
+
const output = git(projection, ["ls-tree", "-rz", "-r", "HEAD"]);
|
|
9377
|
+
if (!output) return void 0;
|
|
9378
|
+
const blobs = /* @__PURE__ */ new Map();
|
|
9379
|
+
for (const entry of output.split("\0")) {
|
|
9380
|
+
if (!entry) continue;
|
|
9381
|
+
const match = entry.match(/^\d+\s+blob\s+([0-9a-f]{40})\t(.+)$/s);
|
|
9382
|
+
if (match) blobs.set(match[2], match[1]);
|
|
9383
|
+
}
|
|
9384
|
+
return blobs;
|
|
9385
|
+
}
|
|
9386
|
+
async function measureAuthoritativeLiveDrift(liveVault, projection) {
|
|
9387
|
+
const projectionBlobs = headBlobOids(projection);
|
|
9388
|
+
if (!projectionBlobs) return { unknown: true, detail: "projection HEAD unreadable" };
|
|
9389
|
+
const scan = await scanVault(liveVault);
|
|
9390
|
+
if (!scan.ok) return { unknown: true, detail: "live Markdown inventory unavailable" };
|
|
9391
|
+
let content = 0;
|
|
9392
|
+
const livePromotable = /* @__PURE__ */ new Set();
|
|
9393
|
+
for (const page of scan.data.allMarkdown) {
|
|
9394
|
+
const rel = relative4(liveVault, page.absPath).split(sep3).join("/");
|
|
9395
|
+
if (!isGitPromotablePath(rel)) continue;
|
|
9396
|
+
livePromotable.add(rel);
|
|
9397
|
+
const bytes = await readFile19(page.absPath);
|
|
9398
|
+
if (projectionBlobs.get(rel) !== gitBlobOid(bytes)) content += 1;
|
|
9399
|
+
}
|
|
9400
|
+
for (const rel of projectionBlobs.keys()) {
|
|
9401
|
+
if (rel.endsWith(".md") && isGitPromotablePath(rel) && !livePromotable.has(rel)) content += 1;
|
|
9402
|
+
}
|
|
9403
|
+
const events = await readLogEvents(liveVault);
|
|
9404
|
+
if (!events.ok) return { unknown: true, detail: "live event ledger unreadable" };
|
|
9405
|
+
return {
|
|
9406
|
+
content,
|
|
9407
|
+
ledger: events.data.length,
|
|
9408
|
+
detail: content > 0 || events.data.length > 0 ? "authoritative live data ahead of GitHub" : void 0
|
|
9409
|
+
};
|
|
9410
|
+
}
|
|
9333
9411
|
|
|
9334
9412
|
// src/copy-status/copy-status.ts
|
|
9335
9413
|
function liveRecord(p) {
|
|
@@ -9413,7 +9491,28 @@ function localRecord(p, githubOid) {
|
|
|
9413
9491
|
p
|
|
9414
9492
|
);
|
|
9415
9493
|
}
|
|
9416
|
-
return withDirty({ state: "unknown", detail: p.detail ?? "
|
|
9494
|
+
return withDirty({ state: "unknown", detail: p.detail ?? "live-vault Git unmeasured" }, p);
|
|
9495
|
+
}
|
|
9496
|
+
function liveDriftRecord(p) {
|
|
9497
|
+
if (!p || p.unknown || p.content === void 0 && p.ledger === void 0) {
|
|
9498
|
+
return { state: "unknown", detail: p?.detail ?? "live drift unmeasured" };
|
|
9499
|
+
}
|
|
9500
|
+
const content = p.content ?? 0;
|
|
9501
|
+
const ledger = p.ledger ?? 0;
|
|
9502
|
+
const rec = {
|
|
9503
|
+
state: content > 0 || ledger > 0 ? "drifted" : "clean"
|
|
9504
|
+
};
|
|
9505
|
+
if (p.content !== void 0) rec.content = content;
|
|
9506
|
+
if (p.ledger !== void 0) rec.ledger = ledger;
|
|
9507
|
+
if (p.detail) rec.detail = p.detail;
|
|
9508
|
+
return rec;
|
|
9509
|
+
}
|
|
9510
|
+
function formatLiveDrift(rec) {
|
|
9511
|
+
const parts = [`live_drift: ${rec.state}`];
|
|
9512
|
+
if (rec.content !== void 0) parts.push(`content=${rec.content}`);
|
|
9513
|
+
if (rec.ledger !== void 0) parts.push(`ledger=${rec.ledger}`);
|
|
9514
|
+
if (rec.detail) parts.push(rec.detail);
|
|
9515
|
+
return parts.join(" ");
|
|
9417
9516
|
}
|
|
9418
9517
|
function formatPlane(name, rec) {
|
|
9419
9518
|
const parts = [`${name}: ${rec.state}`];
|
|
@@ -9432,31 +9531,59 @@ function composeCopyStatus(input) {
|
|
|
9432
9531
|
const live = liveRecord(input.live);
|
|
9433
9532
|
const github = githubRecord(input.github);
|
|
9434
9533
|
const local_git = localRecord(input.local, input.github.oid);
|
|
9534
|
+
const live_drift = liveDriftRecord(input.liveDrift);
|
|
9435
9535
|
const humanHint = [
|
|
9436
9536
|
formatPlane("live", live),
|
|
9437
9537
|
formatPlane("github", github),
|
|
9438
|
-
formatPlane("local_git", local_git)
|
|
9538
|
+
formatPlane("local_git", local_git),
|
|
9539
|
+
formatLiveDrift(live_drift)
|
|
9439
9540
|
].join("\n");
|
|
9440
|
-
return { live, github, local_git, humanHint };
|
|
9541
|
+
return { live, github, local_git, live_drift, humanHint };
|
|
9441
9542
|
}
|
|
9442
9543
|
async function runCopyStatus(deps) {
|
|
9443
|
-
const [live, github, local] = await Promise.all([
|
|
9544
|
+
const [live, github, local, liveDrift] = await Promise.all([
|
|
9444
9545
|
deps.probeLive(),
|
|
9445
9546
|
deps.probeGithub(),
|
|
9446
|
-
deps.probeLocalGit()
|
|
9547
|
+
deps.probeLocalGit(),
|
|
9548
|
+
deps.probeLiveDrift?.()
|
|
9447
9549
|
]);
|
|
9448
|
-
return composeCopyStatus({ live, github, local });
|
|
9550
|
+
return composeCopyStatus({ live, github, local, liveDrift });
|
|
9449
9551
|
}
|
|
9450
9552
|
|
|
9451
9553
|
// src/commands/copy-status.ts
|
|
9554
|
+
function comparablePath(path) {
|
|
9555
|
+
try {
|
|
9556
|
+
return realpathSync5(path);
|
|
9557
|
+
} catch {
|
|
9558
|
+
return resolve8(path);
|
|
9559
|
+
}
|
|
9560
|
+
}
|
|
9561
|
+
function pathsAreNested(left, right) {
|
|
9562
|
+
const rel = relative5(comparablePath(left), comparablePath(right));
|
|
9563
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute2(rel);
|
|
9564
|
+
}
|
|
9452
9565
|
function defaultCopyStatusDeps(input) {
|
|
9566
|
+
const selection = inspectConfiguredFetchProjection(input.home);
|
|
9567
|
+
const sameAsLive = selection.path !== void 0 && comparablePath(selection.path) === comparablePath(input.vault);
|
|
9568
|
+
const nestedWithLive = selection.path !== void 0 && (pathsAreNested(selection.path, input.vault) || pathsAreNested(input.vault, selection.path));
|
|
9569
|
+
const configuredProjection = sameAsLive || nestedWithLive ? void 0 : selection.path;
|
|
9570
|
+
const projectionProblem = selection.invalidDetail ?? (sameAsLive ? "configured fetch projection must be distinct from live vault" : nestedWithLive ? "configured fetch projection and live vault must not be nested" : void 0);
|
|
9571
|
+
const gitVault = input.vault;
|
|
9572
|
+
const projectionWarning = selection.configured ? `configured fetch projection ignored for Git status; using live vault${projectionProblem ? ` (${projectionProblem})` : ""}` : void 0;
|
|
9573
|
+
const invalidProjectionDetail = projectionProblem ?? "configured fetch projection is not a git repository";
|
|
9574
|
+
const gitRootProblem = () => {
|
|
9575
|
+
if (!existsSync13(join38(gitVault, ".git"))) {
|
|
9576
|
+
return "vault is not a git repository";
|
|
9577
|
+
}
|
|
9578
|
+
return void 0;
|
|
9579
|
+
};
|
|
9453
9580
|
return {
|
|
9454
9581
|
probeLive() {
|
|
9455
9582
|
if (input.s3Ok === true) return { reachable: true, detail: "MCP S3 ok" };
|
|
9456
9583
|
if (input.s3Ok === false) return { reachable: false, detail: "MCP S3 not ok" };
|
|
9457
9584
|
const remote = resolveWikiS3Remote({ home: input.home });
|
|
9458
9585
|
if (!remote) {
|
|
9459
|
-
return { unknown: true, detail: "
|
|
9586
|
+
return { unknown: true, detail: "Git worktree is not the live plane; S3 remote unconfigured" };
|
|
9460
9587
|
}
|
|
9461
9588
|
const reach = probeS3Reachability(remote);
|
|
9462
9589
|
if (reach === "ok") return { reachable: true, detail: "S3 reachable" };
|
|
@@ -9464,18 +9591,17 @@ function defaultCopyStatusDeps(input) {
|
|
|
9464
9591
|
return { unknown: true, detail: "S3 unmeasured" };
|
|
9465
9592
|
},
|
|
9466
9593
|
probeGithub() {
|
|
9467
|
-
|
|
9468
|
-
|
|
9469
|
-
|
|
9470
|
-
const ls = git(input.vault, ["ls-remote", "origin", "refs/heads/main"], {
|
|
9594
|
+
const problem = gitRootProblem();
|
|
9595
|
+
if (problem) return { unknown: true, detail: problem };
|
|
9596
|
+
const ls = git(gitVault, ["ls-remote", "origin", "refs/heads/main"], {
|
|
9471
9597
|
timeoutMs: REMOTE_PROBE_TIMEOUT_MS
|
|
9472
9598
|
});
|
|
9473
9599
|
const oid = ls.split(/\s+/)[0];
|
|
9474
9600
|
if (!oid) return { unknown: true, detail: "git ls-remote origin main failed" };
|
|
9475
|
-
const originMain = git(
|
|
9601
|
+
const originMain = git(gitVault, ["rev-parse", "--verify", "origin/main"]);
|
|
9476
9602
|
let ageHours;
|
|
9477
9603
|
if (originMain && originMain === oid) {
|
|
9478
|
-
const ct = git(
|
|
9604
|
+
const ct = git(gitVault, ["log", "-1", "--format=%ct", "origin/main"]);
|
|
9479
9605
|
const sec = Number.parseInt(ct, 10);
|
|
9480
9606
|
if (Number.isFinite(sec) && sec > 0) {
|
|
9481
9607
|
ageHours = Math.max(0, Math.round((Date.now() / 1e3 - sec) / 3600));
|
|
@@ -9484,31 +9610,40 @@ function defaultCopyStatusDeps(input) {
|
|
|
9484
9610
|
return { oid, ageHours, detail: "git ls-remote origin main" };
|
|
9485
9611
|
},
|
|
9486
9612
|
probeLocalGit() {
|
|
9487
|
-
|
|
9488
|
-
|
|
9489
|
-
|
|
9490
|
-
const head = git(input.vault, ["rev-parse", "HEAD"]);
|
|
9613
|
+
const problem = gitRootProblem();
|
|
9614
|
+
if (problem) return { unknown: true, detail: problem };
|
|
9615
|
+
const head = git(gitVault, ["rev-parse", "HEAD"]);
|
|
9491
9616
|
if (!head) return { unknown: true, detail: "HEAD unreadable" };
|
|
9492
|
-
const behindRaw = git(
|
|
9617
|
+
const behindRaw = git(gitVault, ["rev-list", "--count", "HEAD..origin/main"]);
|
|
9493
9618
|
const behind = behindRaw === "" ? void 0 : Number.parseInt(behindRaw, 10);
|
|
9494
|
-
const review = listReviewRequiredOps(
|
|
9619
|
+
const review = listReviewRequiredOps(gitVault)[0];
|
|
9495
9620
|
const blockedReason = review ? `review-required:${review.opId}` : void 0;
|
|
9496
|
-
const dirty = measureDirtyVolume(
|
|
9621
|
+
const dirty = measureDirtyVolume(gitVault);
|
|
9497
9622
|
const dirtyCount = dirty.is_git_repo ? dirty.expanded_files : void 0;
|
|
9498
9623
|
const untrackedCount = dirty.is_git_repo ? dirty.untracked : void 0;
|
|
9499
|
-
const ledgerUntracked = dirty.is_git_repo ?
|
|
9624
|
+
const ledgerUntracked = dirty.is_git_repo ? countEventLedgerFiles(gitVault) : void 0;
|
|
9500
9625
|
const contentUntracked = dirty.is_git_repo ? dirty.content_files : void 0;
|
|
9501
|
-
const dirtyHint =
|
|
9626
|
+
const dirtyHint = ledgerUntracked && ledgerUntracked > 0 ? `event-ledger live-ahead of GitHub; do not git add` : dirtyCount && dirtyCount > 0 ? `live-ahead of GitHub; do not git add` : void 0;
|
|
9627
|
+
const detail = [dirtyHint, blockedReason, projectionWarning].filter(Boolean).join("; ") || void 0;
|
|
9502
9628
|
return {
|
|
9503
9629
|
head,
|
|
9504
9630
|
behind: Number.isFinite(behind) ? behind : void 0,
|
|
9505
9631
|
blockedReason,
|
|
9506
9632
|
dirty: dirtyCount,
|
|
9507
9633
|
untracked: untrackedCount,
|
|
9508
|
-
ledger_untracked:
|
|
9509
|
-
content_untracked:
|
|
9510
|
-
detail
|
|
9634
|
+
ledger_untracked: ledgerUntracked && ledgerUntracked > 0 ? ledgerUntracked : void 0,
|
|
9635
|
+
content_untracked: contentUntracked && contentUntracked > 0 ? contentUntracked : void 0,
|
|
9636
|
+
detail
|
|
9511
9637
|
};
|
|
9638
|
+
},
|
|
9639
|
+
probeLiveDrift() {
|
|
9640
|
+
if (!configuredProjection) {
|
|
9641
|
+
return { unknown: true, detail: projectionProblem ?? "live drift requires a configured fetch projection" };
|
|
9642
|
+
}
|
|
9643
|
+
if (!existsSync13(join38(configuredProjection, ".git"))) {
|
|
9644
|
+
return { unknown: true, detail: invalidProjectionDetail };
|
|
9645
|
+
}
|
|
9646
|
+
return measureAuthoritativeLiveDrift(input.vault, configuredProjection);
|
|
9512
9647
|
}
|
|
9513
9648
|
};
|
|
9514
9649
|
}
|
|
@@ -9522,7 +9657,7 @@ async function runCopyStatusCommand(input) {
|
|
|
9522
9657
|
|
|
9523
9658
|
// src/commands/seed.ts
|
|
9524
9659
|
import { mkdir as mkdir12, writeFile as writeFile8, stat as stat4 } from "fs/promises";
|
|
9525
|
-
import { join as
|
|
9660
|
+
import { join as join39 } from "path";
|
|
9526
9661
|
var TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
9527
9662
|
var EXAMPLE_PAGES = {
|
|
9528
9663
|
"entities/example-project.md": `---
|
|
@@ -9591,29 +9726,29 @@ Real sources are immutable after ingestion \u2014 never edit them.
|
|
|
9591
9726
|
`;
|
|
9592
9727
|
async function runSeed(input) {
|
|
9593
9728
|
try {
|
|
9594
|
-
await stat4(
|
|
9729
|
+
await stat4(join39(input.vault, "SCHEMA.md"));
|
|
9595
9730
|
} catch {
|
|
9596
9731
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { root: input.vault, reason: "SCHEMA.md missing \u2014 run `skillwiki init` first" }) };
|
|
9597
9732
|
}
|
|
9598
9733
|
const created = [];
|
|
9599
9734
|
const skipped = [];
|
|
9600
9735
|
for (const [relPath, content] of Object.entries(EXAMPLE_PAGES)) {
|
|
9601
|
-
const absPath =
|
|
9736
|
+
const absPath = join39(input.vault, relPath);
|
|
9602
9737
|
try {
|
|
9603
9738
|
await stat4(absPath);
|
|
9604
9739
|
skipped.push(relPath);
|
|
9605
9740
|
} catch {
|
|
9606
|
-
await mkdir12(
|
|
9741
|
+
await mkdir12(join39(absPath, ".."), { recursive: true });
|
|
9607
9742
|
await writeFile8(absPath, content, "utf8");
|
|
9608
9743
|
created.push(relPath);
|
|
9609
9744
|
}
|
|
9610
9745
|
}
|
|
9611
|
-
const rawPath =
|
|
9746
|
+
const rawPath = join39(input.vault, "raw", "articles", "example-source.md");
|
|
9612
9747
|
try {
|
|
9613
9748
|
await stat4(rawPath);
|
|
9614
9749
|
skipped.push("raw/articles/example-source.md");
|
|
9615
9750
|
} catch {
|
|
9616
|
-
await mkdir12(
|
|
9751
|
+
await mkdir12(join39(rawPath, ".."), { recursive: true });
|
|
9617
9752
|
await writeFile8(rawPath, EXAMPLE_RAW, "utf8");
|
|
9618
9753
|
created.push("raw/articles/example-source.md");
|
|
9619
9754
|
}
|
|
@@ -9636,9 +9771,9 @@ async function runSeed(input) {
|
|
|
9636
9771
|
}
|
|
9637
9772
|
|
|
9638
9773
|
// src/commands/canvas.ts
|
|
9639
|
-
import { readFile as
|
|
9774
|
+
import { readFile as readFile20, writeFile as writeFile9 } from "fs/promises";
|
|
9640
9775
|
import { existsSync as existsSync14 } from "fs";
|
|
9641
|
-
import { join as
|
|
9776
|
+
import { join as join40 } from "path";
|
|
9642
9777
|
var NODE_WIDTH = 240;
|
|
9643
9778
|
var NODE_HEIGHT = 60;
|
|
9644
9779
|
var COLUMN_SPACING = 400;
|
|
@@ -9716,7 +9851,7 @@ function buildCanvasEdges(adjacency) {
|
|
|
9716
9851
|
return edges;
|
|
9717
9852
|
}
|
|
9718
9853
|
async function runCanvasGenerate(input) {
|
|
9719
|
-
const graphPath = input.graphPath ??
|
|
9854
|
+
const graphPath = input.graphPath ?? join40(input.vault, ".skillwiki", "graph.json");
|
|
9720
9855
|
if (!existsSync14(graphPath)) {
|
|
9721
9856
|
return {
|
|
9722
9857
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -9728,7 +9863,7 @@ async function runCanvasGenerate(input) {
|
|
|
9728
9863
|
}
|
|
9729
9864
|
let raw;
|
|
9730
9865
|
try {
|
|
9731
|
-
raw = await
|
|
9866
|
+
raw = await readFile20(graphPath, "utf8");
|
|
9732
9867
|
} catch (e) {
|
|
9733
9868
|
return {
|
|
9734
9869
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -9754,7 +9889,7 @@ async function runCanvasGenerate(input) {
|
|
|
9754
9889
|
const nodes = buildCanvasNodes(paths);
|
|
9755
9890
|
const edges = buildCanvasEdges(graph.adjacency);
|
|
9756
9891
|
const canvas = { nodes, edges };
|
|
9757
|
-
const outPath =
|
|
9892
|
+
const outPath = join40(input.vault, "vault-graph.canvas");
|
|
9758
9893
|
try {
|
|
9759
9894
|
await writeFile9(outPath, JSON.stringify(canvas, null, 2));
|
|
9760
9895
|
} catch (e) {
|
|
@@ -9898,12 +10033,12 @@ async function runSourceDisposition(input) {
|
|
|
9898
10033
|
}
|
|
9899
10034
|
|
|
9900
10035
|
// src/utils/source-disposal.ts
|
|
9901
|
-
import { createHash as
|
|
9902
|
-
import { readFile as
|
|
10036
|
+
import { createHash as createHash7 } from "crypto";
|
|
10037
|
+
import { readFile as readFile22, unlink as unlink5 } from "fs/promises";
|
|
9903
10038
|
|
|
9904
10039
|
// src/utils/raw-asset-reference-index.ts
|
|
9905
|
-
import { readdir as readdir7, readFile as
|
|
9906
|
-
import { join as
|
|
10040
|
+
import { readdir as readdir7, readFile as readFile21 } from "fs/promises";
|
|
10041
|
+
import { join as join41, relative as relative6, sep as sep4 } from "path";
|
|
9907
10042
|
var PREVIEW_EXTENSIONS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "webp", "svg", "bmp", "avif", "pdf", "mp3", "wav", "m4a", "mp4", "webm"]);
|
|
9908
10043
|
async function walkFiles(root, dir = root) {
|
|
9909
10044
|
let entries;
|
|
@@ -9914,9 +10049,9 @@ async function walkFiles(root, dir = root) {
|
|
|
9914
10049
|
}
|
|
9915
10050
|
const out = [];
|
|
9916
10051
|
for (const entry of entries) {
|
|
9917
|
-
const path =
|
|
10052
|
+
const path = join41(dir, entry.name);
|
|
9918
10053
|
if (entry.isDirectory()) out.push(...await walkFiles(root, path));
|
|
9919
|
-
else if (entry.isFile()) out.push(
|
|
10054
|
+
else if (entry.isFile()) out.push(relative6(root, path).split(sep4).join("/"));
|
|
9920
10055
|
}
|
|
9921
10056
|
return out;
|
|
9922
10057
|
}
|
|
@@ -9930,7 +10065,7 @@ function addInbound(map, target, source) {
|
|
|
9930
10065
|
map.set(target, refs);
|
|
9931
10066
|
}
|
|
9932
10067
|
async function buildRawAssetReferenceIndex(vault) {
|
|
9933
|
-
const assetRoot =
|
|
10068
|
+
const assetRoot = join41(vault, "raw", "assets");
|
|
9934
10069
|
const relativeAssets = await walkFiles(assetRoot);
|
|
9935
10070
|
const assets = relativeAssets.map((path) => `raw/assets/${path}`).sort((a, b) => a.localeCompare(b));
|
|
9936
10071
|
const assetSet = new Set(assets);
|
|
@@ -9946,7 +10081,7 @@ async function buildRawAssetReferenceIndex(vault) {
|
|
|
9946
10081
|
for (const page of scan.data.allMarkdown) {
|
|
9947
10082
|
let text;
|
|
9948
10083
|
try {
|
|
9949
|
-
text = await
|
|
10084
|
+
text = await readFile21(page.absPath, "utf8");
|
|
9950
10085
|
} catch {
|
|
9951
10086
|
continue;
|
|
9952
10087
|
}
|
|
@@ -9982,7 +10117,7 @@ async function buildRawAssetReferenceIndex(vault) {
|
|
|
9982
10117
|
|
|
9983
10118
|
// src/utils/source-disposal.ts
|
|
9984
10119
|
function sha256(bytes) {
|
|
9985
|
-
return
|
|
10120
|
+
return createHash7("sha256").update(bytes).digest("hex");
|
|
9986
10121
|
}
|
|
9987
10122
|
function exactTarget(path) {
|
|
9988
10123
|
if (/[?*\[\]{}]/.test(path) || !path.includes("/") || path.endsWith("/")) return err("RAW_DISPOSAL_TARGET_INVALID", { path, message: "exact file path required; globs, basenames, and directories are refused" });
|
|
@@ -10006,7 +10141,7 @@ async function planSourceDisposal(input) {
|
|
|
10006
10141
|
if (sensitive.length > 0) return err("SENSITIVE_CONTENT_DETECTED", { findings: sensitive });
|
|
10007
10142
|
const target = await resolveExistingRegularFileInsideVault(input.vault, input.rawPath);
|
|
10008
10143
|
if (!target.ok) return err("RAW_DISPOSAL_TARGET_INVALID", { path: input.rawPath, cause: target });
|
|
10009
|
-
const bytes = await
|
|
10144
|
+
const bytes = await readFile22(target.data);
|
|
10010
10145
|
const size = bytes.byteLength;
|
|
10011
10146
|
let typedReferences = [];
|
|
10012
10147
|
let otherReferences = [];
|
|
@@ -10130,7 +10265,7 @@ async function runSourceDisposal(input) {
|
|
|
10130
10265
|
import { existsSync as existsSync15, readFileSync as readFileSync16 } from "fs";
|
|
10131
10266
|
import { execSync as nodeExecSync } from "child_process";
|
|
10132
10267
|
import { hostname as nodeHostname, platform as nodePlatform } from "os";
|
|
10133
|
-
import { join as
|
|
10268
|
+
import { join as join42 } from "path";
|
|
10134
10269
|
var SSH_TIMEOUT_MS = 15e3;
|
|
10135
10270
|
var TIMER_UNIT = "agent-memory-trends.timer";
|
|
10136
10271
|
var SERVICE_UNIT = "agent-memory-trends.service";
|
|
@@ -10360,7 +10495,7 @@ async function runFleetHealth(input) {
|
|
|
10360
10495
|
const home = input.home ?? env.HOME ?? "";
|
|
10361
10496
|
const osHostname = input.osHostname ?? env.HOSTNAME ?? nodeHostname();
|
|
10362
10497
|
const vault = input.vault ?? env.WIKI_PATH;
|
|
10363
|
-
const file = input.file ?? (vault ?
|
|
10498
|
+
const file = input.file ?? (vault ? join42(vault, FLEET_REL_PATH) : void 0);
|
|
10364
10499
|
if (!file) {
|
|
10365
10500
|
return {
|
|
10366
10501
|
exitCode: ExitCode.NO_VAULT_CONFIGURED,
|
|
@@ -10445,12 +10580,12 @@ async function runFleetHealth(input) {
|
|
|
10445
10580
|
|
|
10446
10581
|
// src/utils/auto-commit.ts
|
|
10447
10582
|
import { existsSync as existsSync16 } from "fs";
|
|
10448
|
-
import { isAbsolute, join as
|
|
10583
|
+
import { isAbsolute as isAbsolute3, join as join43, normalize } from "path";
|
|
10449
10584
|
function isValidLastOpPath(file) {
|
|
10450
10585
|
if (!file || typeof file !== "string") return false;
|
|
10451
10586
|
const trimmed = file.trim();
|
|
10452
10587
|
if (trimmed.length === 0) return false;
|
|
10453
|
-
if (
|
|
10588
|
+
if (isAbsolute3(trimmed)) return false;
|
|
10454
10589
|
const normalized = normalize(trimmed).replace(/\\/g, "/");
|
|
10455
10590
|
if (normalized.startsWith("../") || normalized === ".." || normalized.includes("/../")) return false;
|
|
10456
10591
|
for (const generatedPath of VAULT_GENERATED_COMMIT_PATHS) {
|
|
@@ -10466,7 +10601,7 @@ async function postCommit(vault, exitCode) {
|
|
|
10466
10601
|
const dotenv = await parseDotenvFile(configPath(home));
|
|
10467
10602
|
const autoCommit = process.env.AUTO_COMMIT ?? dotenv["AUTO_COMMIT"];
|
|
10468
10603
|
if (autoCommit === "false") return;
|
|
10469
|
-
if (!existsSync16(
|
|
10604
|
+
if (!existsSync16(join43(vault, ".git"))) return;
|
|
10470
10605
|
const lastOps = readLastOp(vault);
|
|
10471
10606
|
if (lastOps.length === 0) return;
|
|
10472
10607
|
const porcelain = git(vault, ["status", "--porcelain", "--", ...VAULT_COMMIT_PATHSPEC]);
|
|
@@ -10508,7 +10643,7 @@ async function postCommit(vault, exitCode) {
|
|
|
10508
10643
|
import { readFileSync as readFileSync17, writeFileSync as writeFileSync8 } from "fs";
|
|
10509
10644
|
|
|
10510
10645
|
// src/utils/mcp-token-map.ts
|
|
10511
|
-
import { createHash as
|
|
10646
|
+
import { createHash as createHash8, randomBytes } from "crypto";
|
|
10512
10647
|
import yaml from "js-yaml";
|
|
10513
10648
|
var HOST_ID_RE = /^[a-z][a-z0-9-]{1,62}$/;
|
|
10514
10649
|
function parseMcpTokenMap(yamlText) {
|
|
@@ -10532,7 +10667,7 @@ function parseMcpTokenMap(yamlText) {
|
|
|
10532
10667
|
function generateHostBearer(rng) {
|
|
10533
10668
|
const bytes = (rng ?? (() => randomBytes(32)))();
|
|
10534
10669
|
const raw = bytes.toString("base64url");
|
|
10535
|
-
const hashHex =
|
|
10670
|
+
const hashHex = createHash8("sha256").update(raw, "utf8").digest("hex");
|
|
10536
10671
|
return { raw, hashHex };
|
|
10537
10672
|
}
|
|
10538
10673
|
function appendHostHash(yamlText, hashHex, hostId) {
|
|
@@ -10561,7 +10696,7 @@ function preflight(error) {
|
|
|
10561
10696
|
}
|
|
10562
10697
|
async function runMcpAuthIssueHost(input) {
|
|
10563
10698
|
const isTty = input.isTty ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
10564
|
-
const
|
|
10699
|
+
const readFile23 = input.readFile ?? readFileSync17;
|
|
10565
10700
|
const writeFile10 = input.writeFile ?? writeFileSync8;
|
|
10566
10701
|
const stderrWrite = input.stderrWrite ?? ((s) => {
|
|
10567
10702
|
process.stderr.write(s);
|
|
@@ -10574,7 +10709,7 @@ async function runMcpAuthIssueHost(input) {
|
|
|
10574
10709
|
if (write && !isTty) return preflight("NO_TTY");
|
|
10575
10710
|
let yamlText = "";
|
|
10576
10711
|
try {
|
|
10577
|
-
yamlText =
|
|
10712
|
+
yamlText = readFile23(mapPath, "utf8");
|
|
10578
10713
|
} catch (error) {
|
|
10579
10714
|
if (!isEnoent(error)) throw error;
|
|
10580
10715
|
}
|
|
@@ -10689,8 +10824,8 @@ async function emit(r, vault, opts) {
|
|
|
10689
10824
|
printJson(r.result);
|
|
10690
10825
|
}
|
|
10691
10826
|
if (vault && opts?.postCommit !== false) await postCommit(vault, r.exitCode);
|
|
10692
|
-
await new Promise((
|
|
10693
|
-
process.stdout.write("", (error) => error ? reject(error) :
|
|
10827
|
+
await new Promise((resolve9, reject) => {
|
|
10828
|
+
process.stdout.write("", (error) => error ? reject(error) : resolve9());
|
|
10694
10829
|
});
|
|
10695
10830
|
process.exit(r.exitCode);
|
|
10696
10831
|
}
|
|
@@ -10753,7 +10888,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
|
|
|
10753
10888
|
if (dirty) {
|
|
10754
10889
|
return emit(dirty, void 0, { postCommit: false });
|
|
10755
10890
|
}
|
|
10756
|
-
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-
|
|
10891
|
+
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-T4WOM52R.js");
|
|
10757
10892
|
const run = await runManagedWriteTransaction2({
|
|
10758
10893
|
vault,
|
|
10759
10894
|
command,
|
|
@@ -10783,7 +10918,7 @@ program.command("validate <file>").description("validate vault page frontmatter
|
|
|
10783
10918
|
emit(await runValidate({ file, apply: !!opts.apply, vault }), vault);
|
|
10784
10919
|
});
|
|
10785
10920
|
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) => {
|
|
10786
|
-
const out = opts.out ??
|
|
10921
|
+
const out = opts.out ?? join44(vault, ".skillwiki", "graph.json");
|
|
10787
10922
|
return emitGuardedVaultWrite(vault, "graph build", () => runGraphBuild({ vault, out }));
|
|
10788
10923
|
});
|
|
10789
10924
|
var canvasCmd = program.command("canvas").description("manage Obsidian canvas files");
|
|
@@ -11405,7 +11540,7 @@ program.command("status [vault]").description("output vault diagnostics").option
|
|
|
11405
11540
|
langEnvValue: process.env.WIKI_LANG
|
|
11406
11541
|
}), v.vault);
|
|
11407
11542
|
});
|
|
11408
|
-
program.command("copy-status [vault]").description("plane-tagged vault freshness: live S3 vs GitHub snapshot vs
|
|
11543
|
+
program.command("copy-status [vault]").description("plane-tagged vault freshness: live S3 vs GitHub snapshot vs live-vault Git").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
11409
11544
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
11410
11545
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
11411
11546
|
else emit(await runCopyStatusCommand({
|
|
@@ -4,9 +4,9 @@ import {
|
|
|
4
4
|
UNMANAGED_START,
|
|
5
5
|
renderRootIndex,
|
|
6
6
|
writeRootIndexProjection
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-3KEMRVWR.js";
|
|
8
|
+
import "./chunk-C5WOEVX3.js";
|
|
9
|
+
import "./chunk-SXNKZGNM.js";
|
|
10
10
|
export {
|
|
11
11
|
UNMANAGED_END,
|
|
12
12
|
UNMANAGED_START,
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
runManagedWritePeerGate,
|
|
7
7
|
runManagedWritePreflight,
|
|
8
8
|
runManagedWriteTransaction
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-OTESAW36.js";
|
|
10
|
+
import "./chunk-C5WOEVX3.js";
|
|
11
|
+
import "./chunk-LTSIHHKD.js";
|
|
12
|
+
import "./chunk-SXNKZGNM.js";
|
|
13
13
|
export {
|
|
14
14
|
DEFAULT_MANAGED_WRITE_WAIT_MS,
|
|
15
15
|
MANAGED_WRITE_POLL_INTERVAL_MS,
|
package/dist/skillwiki-mcp.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runSkillwikiMcpStdio
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-BXEG5OWD.js";
|
|
5
5
|
import "./chunk-7I2TPIV5.js";
|
|
6
|
-
import "./chunk-
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-3KEMRVWR.js";
|
|
7
|
+
import "./chunk-OTESAW36.js";
|
|
8
|
+
import "./chunk-C5WOEVX3.js";
|
|
9
|
+
import "./chunk-UDOZKMCN.js";
|
|
10
|
+
import "./chunk-LTSIHHKD.js";
|
|
11
|
+
import "./chunk-SXNKZGNM.js";
|
|
12
12
|
|
|
13
13
|
// src/mcp-entry.ts
|
|
14
14
|
runSkillwikiMcpStdio().catch((error) => {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# GitHub promotion policy shared by snapshot execution and CLI parity tests.
|
|
3
|
+
# This is intentionally narrower than S3 ownership.
|
|
4
|
+
|
|
5
|
+
snapshot_non_promotable_path() {
|
|
6
|
+
local p="${1#./}"
|
|
7
|
+
case "$p" in
|
|
8
|
+
.skillwiki|.skillwiki/*|.claude|.claude/*|.obsidian|.obsidian/*|.antigravitycli|.antigravitycli/*|.playwright-cli|.playwright-cli/*|.superpowers|.superpowers/*|.snapshots|.snapshots/*|.git|.git/*|.drafts|.drafts/*)
|
|
9
|
+
return 0 ;;
|
|
10
|
+
tmp|tmp/*|logs|logs/*|meta/log-events|meta/log-events/*)
|
|
11
|
+
return 0 ;;
|
|
12
|
+
raw/._.DS_Store|._.DS_Store)
|
|
13
|
+
return 0 ;;
|
|
14
|
+
._*)
|
|
15
|
+
return 0 ;;
|
|
16
|
+
.conflict*|*.conflict-*)
|
|
17
|
+
return 0 ;;
|
|
18
|
+
esac
|
|
19
|
+
return 1
|
|
20
|
+
}
|
|
@@ -21,7 +21,37 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]:-$0}" )" && pwd )"
|
|
|
21
21
|
. "$SCRIPT_DIR/lib/git-operation-journal.sh"
|
|
22
22
|
platform_detect_os
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
CONFIG_FILE="$HOME/.skillwiki/.env"
|
|
25
|
+
config_value() {
|
|
26
|
+
local key="$1"
|
|
27
|
+
[ -f "$CONFIG_FILE" ] || return 0
|
|
28
|
+
awk -F= -v key="$key" '$1==key { value=substr($0, index($0, "=") + 1); found=1 } END { if (found) print value }' "$CONFIG_FILE"
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
canonical_compare_path() {
|
|
32
|
+
local path="$1" probe suffix="" base
|
|
33
|
+
while [ "$path" != "/" ] && [ "${path%/}" != "$path" ]; do path="${path%/}"; done
|
|
34
|
+
probe="$path"
|
|
35
|
+
while [ ! -d "$probe" ] && [ "$probe" != "/" ]; do
|
|
36
|
+
base="$(basename "$probe")"
|
|
37
|
+
suffix="/$base$suffix"
|
|
38
|
+
probe="$(dirname "$probe")"
|
|
39
|
+
done
|
|
40
|
+
printf '%s%s\n' "$(cd "$probe" 2>/dev/null && pwd -P)" "$suffix"
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
LIVE_WIKI_DIR="${WIKI_PATH:-$(config_value WIKI_PATH)}"
|
|
44
|
+
LIVE_WIKI_DIR="${LIVE_WIKI_DIR:-$HOME/wiki}"
|
|
45
|
+
CONFIG_FETCH_PROJECTION="$(config_value vault_sync.fetch_projection)"
|
|
46
|
+
FETCH_PROJECTION="${WIKI_FETCH_PROJECTION:-$CONFIG_FETCH_PROJECTION}"
|
|
47
|
+
FETCH_PROJECTION_CONFIGURED=0
|
|
48
|
+
if [ -n "$FETCH_PROJECTION" ] && [ "$FETCH_PROJECTION" != "none" ]; then
|
|
49
|
+
WIKI_DIR="$FETCH_PROJECTION"
|
|
50
|
+
FETCH_PROJECTION_CONFIGURED=1
|
|
51
|
+
else
|
|
52
|
+
WIKI_DIR="$LIVE_WIKI_DIR"
|
|
53
|
+
fi
|
|
54
|
+
export WIKI_DIR
|
|
25
55
|
BRANCH="${WIKI_BRANCH:-main}"
|
|
26
56
|
STATE_DIR="$(platform_cache_dir)/wiki-fetch"
|
|
27
57
|
STATE_FILE="$STATE_DIR/last-behind"
|
|
@@ -71,6 +101,25 @@ log() {
|
|
|
71
101
|
printf '%s %s\n' "$(date -u +%FT%TZ)" "$*" >>"$LOG_FILE"
|
|
72
102
|
}
|
|
73
103
|
|
|
104
|
+
if [ "$FETCH_PROJECTION_CONFIGURED" -eq 1 ]; then
|
|
105
|
+
case "$WIKI_DIR" in
|
|
106
|
+
/*) ;;
|
|
107
|
+
*) log "ERROR: fetch projection path must be absolute: $WIKI_DIR"; exit 0 ;;
|
|
108
|
+
esac
|
|
109
|
+
LIVE_WIKI_IDENTITY="$(canonical_compare_path "$LIVE_WIKI_DIR")"
|
|
110
|
+
FETCH_PROJECTION_IDENTITY="$(canonical_compare_path "$WIKI_DIR")"
|
|
111
|
+
if [ "$LIVE_WIKI_IDENTITY" = "$FETCH_PROJECTION_IDENTITY" ]; then
|
|
112
|
+
log "ERROR: fetch projection must be distinct from live vault: $WIKI_DIR"
|
|
113
|
+
exit 0
|
|
114
|
+
fi
|
|
115
|
+
case "$FETCH_PROJECTION_IDENTITY/" in
|
|
116
|
+
"$LIVE_WIKI_IDENTITY/"*) log "ERROR: fetch projection and live vault must not be nested: $WIKI_DIR"; exit 0 ;;
|
|
117
|
+
esac
|
|
118
|
+
case "$LIVE_WIKI_IDENTITY/" in
|
|
119
|
+
"$FETCH_PROJECTION_IDENTITY/"*) log "ERROR: fetch projection and live vault must not be nested: $WIKI_DIR"; exit 0 ;;
|
|
120
|
+
esac
|
|
121
|
+
fi
|
|
122
|
+
|
|
74
123
|
handle_existing_handoff() {
|
|
75
124
|
local blocker reason op identity previous_identity notified_at now before after
|
|
76
125
|
# Same altitude as managed-write preflight: a review-required whose target_oid
|
|
@@ -187,7 +236,11 @@ attempt_pull_on_delta() {
|
|
|
187
236
|
|
|
188
237
|
# Guard: working tree present.
|
|
189
238
|
if [ ! -d "$WIKI_DIR/.git" ]; then
|
|
190
|
-
|
|
239
|
+
if [ "$FETCH_PROJECTION_CONFIGURED" -eq 1 ]; then
|
|
240
|
+
log "ERROR: configured fetch projection is not a git repo: $WIKI_DIR"
|
|
241
|
+
else
|
|
242
|
+
log "ERROR: $WIKI_DIR is not a git repo"
|
|
243
|
+
fi
|
|
191
244
|
exit 0
|
|
192
245
|
fi
|
|
193
246
|
|
|
@@ -69,6 +69,14 @@ elif [ -f "$SCRIPT_DIR/../../scripts/lib/runtime-manifest.sh" ]; then
|
|
|
69
69
|
source "$SCRIPT_DIR/../../scripts/lib/runtime-manifest.sh"
|
|
70
70
|
fi
|
|
71
71
|
|
|
72
|
+
if [ -f "$SCRIPT_DIR/lib/git-promotion-policy.sh" ]; then
|
|
73
|
+
source "$SCRIPT_DIR/lib/git-promotion-policy.sh"
|
|
74
|
+
elif [ -f "$SCRIPT_DIR/scripts/lib/git-promotion-policy.sh" ]; then
|
|
75
|
+
source "$SCRIPT_DIR/scripts/lib/git-promotion-policy.sh"
|
|
76
|
+
elif [ -f "$SCRIPT_DIR/../../scripts/lib/git-promotion-policy.sh" ]; then
|
|
77
|
+
source "$SCRIPT_DIR/../../scripts/lib/git-promotion-policy.sh"
|
|
78
|
+
fi
|
|
79
|
+
|
|
72
80
|
if ! command -v vault_sync_scan_conflict_markers >/dev/null 2>&1; then
|
|
73
81
|
echo "[wiki-snapshot] ERROR: conflict-marker helper unavailable; refusing to run." >&2
|
|
74
82
|
exit 1
|
|
@@ -77,6 +85,10 @@ if ! command -v vault_sync_sha256 >/dev/null 2>&1; then
|
|
|
77
85
|
echo "[wiki-snapshot] ERROR: SHA-256 helper unavailable; refusing to run." >&2
|
|
78
86
|
exit 1
|
|
79
87
|
fi
|
|
88
|
+
if ! command -v snapshot_non_promotable_path >/dev/null 2>&1; then
|
|
89
|
+
echo "[wiki-snapshot] ERROR: Git promotion policy helper unavailable; refusing to run." >&2
|
|
90
|
+
exit 1
|
|
91
|
+
fi
|
|
80
92
|
|
|
81
93
|
# ── Guard: Linux-only operation ────────────────────────────
|
|
82
94
|
platform_require linux
|
|
@@ -101,42 +113,43 @@ REPAIR_SCRIPT="${WIKI_GIT_REPAIR_SCRIPT:-$SCRIPT_DIR/wiki-git-repair-v3.sh}"
|
|
|
101
113
|
MAX_S3_ONLY_NOTES="${WIKI_SNAPSHOT_MAX_S3_ONLY_NOTES:-200}"
|
|
102
114
|
MAX_TOMBSTONE_PRUNES="${WIKI_SNAPSHOT_MAX_TOMBSTONE_PRUNES:-10}"
|
|
103
115
|
|
|
104
|
-
#
|
|
105
|
-
#
|
|
106
|
-
#
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
raw/._.DS_Store|._.DS_Store)
|
|
115
|
-
return 0 ;;
|
|
116
|
-
._*)
|
|
117
|
-
return 0 ;;
|
|
118
|
-
.conflict*|*.conflict-*)
|
|
119
|
-
return 0 ;;
|
|
120
|
-
esac
|
|
121
|
-
return 1
|
|
116
|
+
# rclone leaves non-promotable and ignored files in the worktree. Passing the
|
|
117
|
+
# ignored directory names as negative pathspecs still makes `git add` exit 1,
|
|
118
|
+
# so build an exact NUL-delimited inventory of tracked/untracked/deleted paths
|
|
119
|
+
# and retain only the Git-promotion class. Already-tracked ledger history is
|
|
120
|
+
# left as-is until the attended branch-tip cleanup stages its deletions.
|
|
121
|
+
snapshot_promotable_pathspecs() {
|
|
122
|
+
local rel_path
|
|
123
|
+
while IFS= read -r -d '' rel_path; do
|
|
124
|
+
snapshot_non_promotable_path "$rel_path" || printf '%s\0' "$rel_path"
|
|
125
|
+
done < <(git ls-files --cached --others --deleted --exclude-standard -z)
|
|
122
126
|
}
|
|
123
127
|
|
|
124
|
-
# rclone exclude leaves leftover non-promotable files in the worktree.
|
|
125
|
-
# `git add -A` would promote them (live 0.10.90 leak). Pathspecs match
|
|
126
|
-
# snapshot_non_promotable_path. Already-tracked ledger history is left as-is.
|
|
127
128
|
snapshot_git_add_promotable() {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
129
|
+
snapshot_promotable_pathspecs \
|
|
130
|
+
| git add --all --pathspec-from-file=- --pathspec-file-nul
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
snapshot_ledger_free_git_required() {
|
|
134
|
+
case "$(printf '%s' "${WIKI_SNAPSHOT_REQUIRE_LEDGER_FREE_GIT:-0}" | tr '[:upper:]' '[:lower:]')" in
|
|
135
|
+
1|true|yes|on) return 0 ;;
|
|
136
|
+
*) return 1 ;;
|
|
137
|
+
esac
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
snapshot_assert_ledger_free_git() {
|
|
141
|
+
local context="${1:-snapshot gate}"
|
|
142
|
+
|
|
143
|
+
snapshot_ledger_free_git_required || return 0
|
|
144
|
+
if git -C "$SNAPSHOT_WORKTREE" ls-files -- meta/log-events 2>/dev/null | grep -q .; then
|
|
145
|
+
log "ERROR: ledger-free Git gate failed ($context); meta/log-events remains in index or HEAD"
|
|
146
|
+
return 1
|
|
147
|
+
fi
|
|
148
|
+
if git -C "$SNAPSHOT_WORKTREE" ls-tree -r --name-only HEAD -- meta/log-events 2>/dev/null | grep -q .; then
|
|
149
|
+
log "ERROR: ledger-free Git gate failed ($context); meta/log-events remains in index or HEAD"
|
|
150
|
+
return 1
|
|
151
|
+
fi
|
|
152
|
+
return 0
|
|
140
153
|
}
|
|
141
154
|
|
|
142
155
|
PROJECTION_PARITY_TIMEOUT_SECONDS="${WIKI_SNAPSHOT_PROJECTION_PARITY_TIMEOUT_SECONDS:-120}"
|
|
@@ -906,6 +919,9 @@ if [ "$(git -C "$SNAPSHOT_WORKTREE" rev-parse --is-inside-work-tree 2>/dev/null)
|
|
|
906
919
|
fi
|
|
907
920
|
|
|
908
921
|
refresh_git_baseline
|
|
922
|
+
if ! snapshot_assert_ledger_free_git "after baseline refresh"; then
|
|
923
|
+
exit 1
|
|
924
|
+
fi
|
|
909
925
|
|
|
910
926
|
# Dual-path requires distinct live mutation vs Git convergence roots.
|
|
911
927
|
# Same-path would materialize projections then immediately rclone-overwrite them.
|
|
@@ -1263,6 +1279,9 @@ if [ "$needs_repair" = true ]; then
|
|
|
1263
1279
|
log "ERROR: could not refresh snapshot transaction receipt after repair"
|
|
1264
1280
|
exit 1
|
|
1265
1281
|
fi
|
|
1282
|
+
if ! snapshot_assert_ledger_free_git "after initial repair"; then
|
|
1283
|
+
exit 1
|
|
1284
|
+
fi
|
|
1266
1285
|
fi
|
|
1267
1286
|
|
|
1268
1287
|
if ! raw_dedup_guard; then
|
|
@@ -1276,6 +1295,9 @@ fi
|
|
|
1276
1295
|
# Check for changes
|
|
1277
1296
|
if [ -z "$(git status --porcelain)" ]; then
|
|
1278
1297
|
log "No changes to commit"
|
|
1298
|
+
if ! snapshot_assert_ledger_free_git "before no-change completion"; then
|
|
1299
|
+
exit 1
|
|
1300
|
+
fi
|
|
1279
1301
|
if ! snapshot_verify_git_receipt; then
|
|
1280
1302
|
log "ERROR: snapshot transaction changed before no-change proof"
|
|
1281
1303
|
exit 1
|
|
@@ -1353,12 +1375,19 @@ if [ "$PULL_SUCCESS" = false ]; then
|
|
|
1353
1375
|
fi
|
|
1354
1376
|
fi
|
|
1355
1377
|
|
|
1378
|
+
if ! snapshot_assert_ledger_free_git "after pull/rebase/repair"; then
|
|
1379
|
+
exit 1
|
|
1380
|
+
fi
|
|
1381
|
+
|
|
1356
1382
|
# Push (with retry)
|
|
1357
1383
|
echo "Pushing to origin..."
|
|
1358
1384
|
PUSH_RETRIES=3
|
|
1359
1385
|
PUSH_SUCCESS=false
|
|
1360
1386
|
|
|
1361
1387
|
for i in $(seq 1 $PUSH_RETRIES); do
|
|
1388
|
+
if ! snapshot_assert_ledger_free_git "immediately before push attempt $i"; then
|
|
1389
|
+
exit 1
|
|
1390
|
+
fi
|
|
1362
1391
|
if git push origin "$DEFAULT_BRANCH" 2>&1 | tee -a "$LOG_FILE"; then
|
|
1363
1392
|
PUSH_SUCCESS=true
|
|
1364
1393
|
break
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.94",
|
|
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.94",
|
|
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"
|
package/skills/package.json
CHANGED