skillwiki 0.10.110 → 0.10.111
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-5MV5SSRM.js → chunk-5IBLXGLY.js} +5 -3
- package/dist/chunk-6OQLBNKR.js +250 -0
- package/dist/chunk-GQWCTJTU.js +55 -0
- package/dist/{chunk-QU2CKXM4.js → chunk-HBJLFPQP.js} +91 -199
- package/dist/chunk-I2J3IJB7.js +54 -0
- package/dist/{chunk-WPJHDRTP.js → chunk-I6IRJCUJ.js} +12 -57
- package/dist/{chunk-NA3TZ4JN.js → chunk-JQV5KNPT.js} +8 -6
- package/dist/chunk-KWEYA3OE.js +60 -0
- package/dist/{chunk-KX5Y3GSX.js → chunk-MRPJ7X7W.js} +5 -3
- package/dist/{chunk-6X6PPQNI.js → chunk-OJJBZDPR.js} +162 -296
- package/dist/chunk-OSL4J7GF.js +32 -0
- package/dist/chunk-PYPPG7RF.js +126 -0
- package/dist/chunk-QESNTTVY.js +50 -0
- package/dist/chunk-TDBUJUYH.js +109 -0
- package/dist/{chunk-R2DJ7IJ5.js → chunk-UIEQIJXP.js} +5 -336
- package/dist/chunk-X5GL2FCU.js +344 -0
- package/dist/chunk-ZRGZBAVS.js +98 -0
- package/dist/cli.js +308 -298
- package/dist/{index-projection-6XGESSHV.js → index-projection-2K672CBO.js} +5 -3
- package/dist/journal-QU5IDXQF.js +13 -0
- package/dist/{managed-write-preflight-JPOBVVSU.js → managed-write-preflight-GRSHQYKC.js} +7 -4
- package/dist/migrate-PIB4QA54.js +21 -0
- package/dist/ready-S7F53Q2D.js +9 -0
- package/dist/runtime-GLMI5OCT.js +15 -0
- package/dist/skillwiki-mcp.js +12 -7
- package/dist/sources-D2MGP246.js +10 -0
- package/dist/upload-HTE62TOV.js +14 -0
- package/dist/watcher-MHG46J3R.js +616 -0
- package/docs/clip-outbox.md +119 -0
- package/package.json +5 -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/templates/launchd/com.karlchow.skillwiki-clip-outbox.plist +12 -13
- package/dist/sources-CLOF5VAT.js +0 -9
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
runFetchGuard,
|
|
4
|
+
runFetchGuardSync
|
|
5
|
+
} from "./chunk-I2J3IJB7.js";
|
|
6
|
+
import {
|
|
7
|
+
buildDeleteIntent,
|
|
8
|
+
normalizeVaultRelPath,
|
|
9
|
+
pathToIntentFilename,
|
|
10
|
+
writeDeleteIntent
|
|
11
|
+
} from "./chunk-QESNTTVY.js";
|
|
2
12
|
import {
|
|
3
13
|
CAPTURE_HYGIENE_CONTRACT,
|
|
4
|
-
CLIP_NOT_CONFIGURED,
|
|
5
14
|
DEFAULT_CAPTURE_BUDGET,
|
|
6
15
|
DEFAULT_DIRTY_VOLUME_THRESHOLD,
|
|
7
16
|
DEFAULT_MCP_URL,
|
|
@@ -22,7 +31,6 @@ import {
|
|
|
22
31
|
guardProtectedVaultWrite,
|
|
23
32
|
isEventLedgerPath,
|
|
24
33
|
isFailedRunStatus,
|
|
25
|
-
loadClipOutboxConfig,
|
|
26
34
|
mcpAuthFromEnv,
|
|
27
35
|
measureDirtyVolume,
|
|
28
36
|
memoryAuthorityTiersRank,
|
|
@@ -67,7 +75,15 @@ import {
|
|
|
67
75
|
upsertIndexEntry,
|
|
68
76
|
vectorIndexStatus,
|
|
69
77
|
withMcpClient
|
|
70
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-OJJBZDPR.js";
|
|
79
|
+
import {
|
|
80
|
+
applySourceDisposition,
|
|
81
|
+
decodeSourceActionApproval,
|
|
82
|
+
encodeSourceActionApproval,
|
|
83
|
+
inventorySources,
|
|
84
|
+
planSourceDisposition,
|
|
85
|
+
runSourcesPending
|
|
86
|
+
} from "./chunk-JQV5KNPT.js";
|
|
71
87
|
import {
|
|
72
88
|
normalizeDistTag,
|
|
73
89
|
readCache,
|
|
@@ -80,7 +96,7 @@ import {
|
|
|
80
96
|
UNMANAGED_START,
|
|
81
97
|
renderRootIndex,
|
|
82
98
|
writeRootIndexProjection
|
|
83
|
-
} from "./chunk-
|
|
99
|
+
} from "./chunk-MRPJ7X7W.js";
|
|
84
100
|
import {
|
|
85
101
|
FLEET_REL_PATH,
|
|
86
102
|
REDACTED_MALFORMED_REFERENCE,
|
|
@@ -120,13 +136,10 @@ import {
|
|
|
120
136
|
normalizeProjectSlug,
|
|
121
137
|
normalizeRemoteRoot,
|
|
122
138
|
parseActiveWorkPath,
|
|
123
|
-
parseDotenvFile,
|
|
124
|
-
parseDotenvText,
|
|
125
139
|
parseJournalEnv,
|
|
126
140
|
planAndMaybePruneRemoteObjects,
|
|
127
141
|
planRawStructuralMove,
|
|
128
142
|
probeS3Reachability,
|
|
129
|
-
profileKey,
|
|
130
143
|
readJournal,
|
|
131
144
|
readLastOp,
|
|
132
145
|
readSkillWikiConfig,
|
|
@@ -137,7 +150,6 @@ import {
|
|
|
137
150
|
resolveFleetHostId,
|
|
138
151
|
resolveInitTimePath,
|
|
139
152
|
resolveRuntimePath,
|
|
140
|
-
resolveSkillwikiHome,
|
|
141
153
|
resolveWikiS3Remote,
|
|
142
154
|
rewriteRawSourceReferences,
|
|
143
155
|
runAudit,
|
|
@@ -171,22 +183,8 @@ import {
|
|
|
171
183
|
snapshotterAliasForLocalHost,
|
|
172
184
|
stageVaultContentChanges,
|
|
173
185
|
supersedeStaleReviewRequiredJournals,
|
|
174
|
-
taxonomyCommentForPage
|
|
175
|
-
|
|
176
|
-
} from "./chunk-QU2CKXM4.js";
|
|
177
|
-
import {
|
|
178
|
-
assertTargetInsideVault,
|
|
179
|
-
atomicWriteText,
|
|
180
|
-
prepareTypedPage
|
|
181
|
-
} from "./chunk-WPJHDRTP.js";
|
|
182
|
-
import {
|
|
183
|
-
applySourceDisposition,
|
|
184
|
-
decodeSourceActionApproval,
|
|
185
|
-
encodeSourceActionApproval,
|
|
186
|
-
inventorySources,
|
|
187
|
-
planSourceDisposition,
|
|
188
|
-
runSourcesPending
|
|
189
|
-
} from "./chunk-NA3TZ4JN.js";
|
|
186
|
+
taxonomyCommentForPage
|
|
187
|
+
} from "./chunk-HBJLFPQP.js";
|
|
190
188
|
import {
|
|
191
189
|
authorizeRawOperation,
|
|
192
190
|
buildSourceReferenceIndex,
|
|
@@ -203,31 +201,54 @@ import {
|
|
|
203
201
|
resolveExistingRegularFileInsideVault,
|
|
204
202
|
validateLogEvent,
|
|
205
203
|
writeLogEvent
|
|
206
|
-
} from "./chunk-
|
|
204
|
+
} from "./chunk-5IBLXGLY.js";
|
|
205
|
+
import {
|
|
206
|
+
assertTargetInsideVault,
|
|
207
|
+
prepareTypedPage
|
|
208
|
+
} from "./chunk-I6IRJCUJ.js";
|
|
207
209
|
import {
|
|
208
|
-
ExitCode,
|
|
209
|
-
MetaSchema,
|
|
210
|
-
RawSourceSchema,
|
|
211
|
-
TypedKnowledgeSchema,
|
|
212
|
-
detectSchema,
|
|
213
|
-
err,
|
|
214
210
|
extractFrontmatter,
|
|
215
|
-
isBlockedHost,
|
|
216
211
|
mapWithConcurrency,
|
|
217
|
-
ok,
|
|
218
212
|
readPage,
|
|
219
213
|
readPageCached,
|
|
220
214
|
redactSensitiveContent,
|
|
221
215
|
resolveReadOnlyVaultRoot,
|
|
222
|
-
resolveSessionKind,
|
|
223
216
|
scanSensitiveContent,
|
|
224
217
|
scanVault,
|
|
225
218
|
splitFrontmatter,
|
|
226
219
|
vaultIoConcurrency
|
|
227
|
-
} from "./chunk-
|
|
220
|
+
} from "./chunk-X5GL2FCU.js";
|
|
221
|
+
import {
|
|
222
|
+
CLIP_MIGRATION_HINT,
|
|
223
|
+
refreshInstalledClipPlist
|
|
224
|
+
} from "./chunk-TDBUJUYH.js";
|
|
225
|
+
import {
|
|
226
|
+
CLIP_NOT_CONFIGURED,
|
|
227
|
+
loadClipOutboxConfig
|
|
228
|
+
} from "./chunk-6OQLBNKR.js";
|
|
229
|
+
import {
|
|
230
|
+
parseDotenvFile,
|
|
231
|
+
parseDotenvText,
|
|
232
|
+
profileKey,
|
|
233
|
+
resolveSkillwikiHome,
|
|
234
|
+
writeDotenv
|
|
235
|
+
} from "./chunk-PYPPG7RF.js";
|
|
236
|
+
import {
|
|
237
|
+
atomicWriteText
|
|
238
|
+
} from "./chunk-GQWCTJTU.js";
|
|
239
|
+
import {
|
|
240
|
+
ExitCode,
|
|
241
|
+
MetaSchema,
|
|
242
|
+
RawSourceSchema,
|
|
243
|
+
TypedKnowledgeSchema,
|
|
244
|
+
detectSchema,
|
|
245
|
+
err,
|
|
246
|
+
ok,
|
|
247
|
+
resolveSessionKind
|
|
248
|
+
} from "./chunk-UIEQIJXP.js";
|
|
228
249
|
|
|
229
250
|
// src/cli.ts
|
|
230
|
-
import { join as
|
|
251
|
+
import { join as join44 } from "path";
|
|
231
252
|
import { Command } from "commander";
|
|
232
253
|
|
|
233
254
|
// src/utils/output.ts
|
|
@@ -343,48 +364,6 @@ async function runHash(input) {
|
|
|
343
364
|
};
|
|
344
365
|
}
|
|
345
366
|
|
|
346
|
-
// src/commands/fetch-guard.ts
|
|
347
|
-
var REDACT_PARAMS = /* @__PURE__ */ new Set(["api_key", "token", "key", "auth", "password", "secret", "access_token"]);
|
|
348
|
-
var PATH_TOKEN_RE = /[A-Fa-f0-9]{32,}|[A-Za-z0-9_\-]{40,}/g;
|
|
349
|
-
function runFetchGuard(input) {
|
|
350
|
-
return Promise.resolve(runFetchGuardSync(input));
|
|
351
|
-
}
|
|
352
|
-
function runFetchGuardSync(input) {
|
|
353
|
-
let u;
|
|
354
|
-
try {
|
|
355
|
-
u = new URL(input.url);
|
|
356
|
-
} catch {
|
|
357
|
-
return { exitCode: ExitCode.MALFORMED_URL, result: err("MALFORMED_URL", { url: input.url }) };
|
|
358
|
-
}
|
|
359
|
-
const sanitized = sanitizeUrl(u);
|
|
360
|
-
if (u.protocol !== "https:") {
|
|
361
|
-
return {
|
|
362
|
-
exitCode: ExitCode.SCHEME_REJECTED,
|
|
363
|
-
result: err("SCHEME_REJECTED", { sanitized_url: sanitized, scheme: u.protocol })
|
|
364
|
-
};
|
|
365
|
-
}
|
|
366
|
-
if (isBlockedHost(u.hostname)) {
|
|
367
|
-
return {
|
|
368
|
-
exitCode: ExitCode.HOST_BLOCKED,
|
|
369
|
-
result: err("HOST_BLOCKED", { sanitized_url: sanitized, host: u.hostname })
|
|
370
|
-
};
|
|
371
|
-
}
|
|
372
|
-
return { exitCode: ExitCode.OK, result: ok({ allowed: true, sanitized_url: sanitized, humanHint: `ALLOWED: ${sanitized}` }) };
|
|
373
|
-
}
|
|
374
|
-
function sanitizeUrl(u) {
|
|
375
|
-
const clone = new URL(u.toString());
|
|
376
|
-
if (clone.username || clone.password) {
|
|
377
|
-
clone.username = "";
|
|
378
|
-
clone.password = "";
|
|
379
|
-
}
|
|
380
|
-
for (const k of Array.from(clone.searchParams.keys())) {
|
|
381
|
-
if (REDACT_PARAMS.has(k.toLowerCase())) clone.searchParams.set(k, "REDACTED");
|
|
382
|
-
}
|
|
383
|
-
let s = clone.toString();
|
|
384
|
-
s = s.replace(PATH_TOKEN_RE, "REDACTED");
|
|
385
|
-
return s;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
367
|
// src/commands/eval.ts
|
|
389
368
|
import { execFileSync } from "child_process";
|
|
390
369
|
import { existsSync, mkdtempSync, rmSync } from "fs";
|
|
@@ -3604,14 +3583,76 @@ async function runClipOutboxStatus(home) {
|
|
|
3604
3583
|
result: ok({ enabled: false, humanHint: CLIP_NOT_CONFIGURED })
|
|
3605
3584
|
};
|
|
3606
3585
|
}
|
|
3586
|
+
const { readJournal: readJournal2 } = await import("./journal-QU5IDXQF.js");
|
|
3587
|
+
let queue;
|
|
3588
|
+
try {
|
|
3589
|
+
queue = (await readJournal2(resolved.config.stateRoot)).map(({ captureId, state, reason, attempts }) => ({ captureId, state, reason, attempts }));
|
|
3590
|
+
} catch {
|
|
3591
|
+
return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "clip journal unreadable; retain it for attended recovery" }) };
|
|
3592
|
+
}
|
|
3607
3593
|
return {
|
|
3608
3594
|
exitCode: ExitCode.OK,
|
|
3609
3595
|
result: ok({
|
|
3610
3596
|
enabled: true,
|
|
3611
|
-
|
|
3597
|
+
queue,
|
|
3598
|
+
humanHint: [`clip-outbox enabled root=${resolved.config.root} mode=${resolved.config.mode}`, ...queue.map((e) => `${e.captureId}: ${e.state}${e.reason ? ` (${e.reason})` : ""}; attempts=${e.attempts ?? 0}`)].join("\n")
|
|
3612
3599
|
})
|
|
3613
3600
|
};
|
|
3614
3601
|
}
|
|
3602
|
+
async function runClipOutboxInstall(input) {
|
|
3603
|
+
try {
|
|
3604
|
+
const { migrateClipOutbox } = await import("./migrate-PIB4QA54.js");
|
|
3605
|
+
return { exitCode: ExitCode.OK, result: ok(await migrateClipOutbox(input)) };
|
|
3606
|
+
} catch (e) {
|
|
3607
|
+
return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: e instanceof Error ? e.message : "clip migration failed" }) };
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
async function runClipOutboxWatch(home) {
|
|
3611
|
+
const resolved = await loadClipOutboxConfig(home);
|
|
3612
|
+
if (!resolved.ok || !resolved.enabled) return { exitCode: ExitCode.INVALID_CONFIG_VALUE, result: err("INVALID_CONFIG_VALUE", { message: resolved.ok ? CLIP_NOT_CONFIGURED : resolved.message }) };
|
|
3613
|
+
if (process.platform !== "darwin") return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "clip-outbox watch requires macOS FSEvents" }) };
|
|
3614
|
+
let client;
|
|
3615
|
+
try {
|
|
3616
|
+
const { S3Client: S3Client3 } = await import("@aws-sdk/client-s3");
|
|
3617
|
+
const { loadClipCredentials, validateRuntime } = await import("./runtime-GLMI5OCT.js");
|
|
3618
|
+
const { createS3CreateOnlyPut, parseDestination } = await import("./upload-HTE62TOV.js");
|
|
3619
|
+
const { postReadyHint } = await import("./ready-S7F53Q2D.js");
|
|
3620
|
+
const { startClipWorker } = await import("./watcher-MHG46J3R.js");
|
|
3621
|
+
const cfg = resolved.config;
|
|
3622
|
+
const credentials = await loadClipCredentials(home, cfg);
|
|
3623
|
+
await validateRuntime(home, cfg, credentials.s3.endpoint);
|
|
3624
|
+
const destination = parseDestination(cfg.destination);
|
|
3625
|
+
client = new S3Client3({ endpoint: credentials.s3.endpoint, region: credentials.s3.region, credentials: credentials.s3, forcePathStyle: true, maxAttempts: 1 });
|
|
3626
|
+
let finish;
|
|
3627
|
+
const done = new Promise((r) => {
|
|
3628
|
+
finish = r;
|
|
3629
|
+
});
|
|
3630
|
+
let failed = false;
|
|
3631
|
+
const worker = await startClipWorker(cfg, {
|
|
3632
|
+
put: createS3CreateOnlyPut({ client, bucket: destination.bucket, prefix: destination.prefix }),
|
|
3633
|
+
ready: (hint) => postReadyHint({ url: cfg.readyUrl, token: credentials.readyToken, hint }),
|
|
3634
|
+
validate: () => validateRuntime(home, cfg, credentials.s3.endpoint),
|
|
3635
|
+
onError: () => {
|
|
3636
|
+
failed = true;
|
|
3637
|
+
finish();
|
|
3638
|
+
}
|
|
3639
|
+
});
|
|
3640
|
+
process.once("SIGTERM", finish);
|
|
3641
|
+
process.once("SIGINT", finish);
|
|
3642
|
+
try {
|
|
3643
|
+
await done;
|
|
3644
|
+
} finally {
|
|
3645
|
+
process.removeListener("SIGTERM", finish);
|
|
3646
|
+
process.removeListener("SIGINT", finish);
|
|
3647
|
+
await worker.stop();
|
|
3648
|
+
}
|
|
3649
|
+
return failed ? { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "clip worker stopped; inspect configuration and retained journal" }) } : { exitCode: ExitCode.OK, result: ok({ humanHint: "Clip worker stopped; snapshots and journal retained." }) };
|
|
3650
|
+
} catch {
|
|
3651
|
+
return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "clip worker startup failed; check configuration, protected credential references, conditional-create evidence and worker lock" }) };
|
|
3652
|
+
} finally {
|
|
3653
|
+
client?.destroy();
|
|
3654
|
+
}
|
|
3655
|
+
}
|
|
3615
3656
|
|
|
3616
3657
|
// src/commands/connect.ts
|
|
3617
3658
|
import { chmod, mkdir as mkdir5, readFile as readFile6, stat as stat3 } from "fs/promises";
|
|
@@ -3922,50 +3963,8 @@ async function runConnect(input) {
|
|
|
3922
3963
|
}
|
|
3923
3964
|
|
|
3924
3965
|
// src/commands/archive.ts
|
|
3925
|
-
import { rename as rename2, mkdir as
|
|
3926
|
-
import { join as
|
|
3927
|
-
|
|
3928
|
-
// src/utils/delete-intent.ts
|
|
3929
|
-
import { mkdir as mkdir6, writeFile as writeFile4, readdir as readdir4, readFile as readFile7 } from "fs/promises";
|
|
3930
|
-
import { join as join19 } from "path";
|
|
3931
|
-
var DELETE_INTENT_SCHEMA = "vault-delete-intent/v1";
|
|
3932
|
-
var DELETE_INTENT_DIR = "meta/delete-intents";
|
|
3933
|
-
function normalizeVaultRelPath(path) {
|
|
3934
|
-
const p = path.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
3935
|
-
if (!p || p.includes("..") || p.startsWith(".git/")) {
|
|
3936
|
-
throw new Error(`invalid vault-relative path: ${path}`);
|
|
3937
|
-
}
|
|
3938
|
-
return p;
|
|
3939
|
-
}
|
|
3940
|
-
function pathToIntentFilename(path) {
|
|
3941
|
-
const p = normalizeVaultRelPath(path);
|
|
3942
|
-
return `${p.replace(/\//g, "__")}.json`;
|
|
3943
|
-
}
|
|
3944
|
-
function intentHostId() {
|
|
3945
|
-
return process.env.SKILLWIKI_HOST_ID ?? process.env.AGENT_HOST_ID ?? "unknown";
|
|
3946
|
-
}
|
|
3947
|
-
function buildDeleteIntent(input) {
|
|
3948
|
-
return {
|
|
3949
|
-
schema: DELETE_INTENT_SCHEMA,
|
|
3950
|
-
path: normalizeVaultRelPath(input.path),
|
|
3951
|
-
action: input.action,
|
|
3952
|
-
created: input.created ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
3953
|
-
host: input.host ?? intentHostId(),
|
|
3954
|
-
actor: input.actor,
|
|
3955
|
-
reason: input.reason,
|
|
3956
|
-
source: input.source,
|
|
3957
|
-
expires: input.expires ?? null
|
|
3958
|
-
};
|
|
3959
|
-
}
|
|
3960
|
-
async function writeDeleteIntent(vault, intent) {
|
|
3961
|
-
const dir = join19(vault, DELETE_INTENT_DIR);
|
|
3962
|
-
await mkdir6(dir, { recursive: true });
|
|
3963
|
-
const rel = `${DELETE_INTENT_DIR}/${pathToIntentFilename(intent.path)}`;
|
|
3964
|
-
await writeFile4(join19(vault, rel), JSON.stringify(intent, null, 2) + "\n", "utf8");
|
|
3965
|
-
return rel;
|
|
3966
|
-
}
|
|
3967
|
-
|
|
3968
|
-
// src/commands/archive.ts
|
|
3966
|
+
import { rename as rename2, mkdir as mkdir6, readFile as readFile7 } from "fs/promises";
|
|
3967
|
+
import { join as join19, dirname as dirname5 } from "path";
|
|
3969
3968
|
function countWikilinks(body, slug) {
|
|
3970
3969
|
const escaped = slug.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3971
3970
|
const re = new RegExp(`\\[\\[${escaped}(?:[|#][^\\]]*)?\\]\\]`, "g");
|
|
@@ -4001,7 +4000,7 @@ async function runArchive(input) {
|
|
|
4001
4000
|
const slug = relPath.replace(/\.md$/, "").split("/").pop();
|
|
4002
4001
|
const rawArchive = isRaw ? lifecycleDestination(relPath, "archive") : void 0;
|
|
4003
4002
|
if (rawArchive && !rawArchive.ok) return { exitCode: ExitCode.USAGE, result: rawArchive };
|
|
4004
|
-
const archivePath = isRaw ? rawArchive.data :
|
|
4003
|
+
const archivePath = isRaw ? rawArchive.data : join19("_archive", relPath).replace(/\\/g, "/");
|
|
4005
4004
|
const remoteRoot = normalizeRemoteRoot(input.remote);
|
|
4006
4005
|
const remoteObjectPath = buildRemoteObjectPath(remoteRoot, relPath);
|
|
4007
4006
|
let cascade;
|
|
@@ -4031,7 +4030,7 @@ async function runArchive(input) {
|
|
|
4031
4030
|
const indexRefs = [];
|
|
4032
4031
|
if (!isRaw) {
|
|
4033
4032
|
try {
|
|
4034
|
-
const idx = await
|
|
4033
|
+
const idx = await readFile7(join19(input.vault, "index.md"), "utf8");
|
|
4035
4034
|
idx.split("\n").forEach((line, i) => {
|
|
4036
4035
|
if (line.includes(`[[${slug}]]`)) indexRefs.push({ line: i + 1, text: line });
|
|
4037
4036
|
});
|
|
@@ -4089,8 +4088,8 @@ async function runArchive(input) {
|
|
|
4089
4088
|
const rewrittenCascadePages = [];
|
|
4090
4089
|
if ((input.cascade || isRaw) && input.apply && cascade) {
|
|
4091
4090
|
for (const ref of cascade.source_array_refs) {
|
|
4092
|
-
const absPath =
|
|
4093
|
-
const text = await
|
|
4091
|
+
const absPath = join19(input.vault, ref.page);
|
|
4092
|
+
const text = await readFile7(absPath, "utf8");
|
|
4094
4093
|
if (!arraysEqual(ref.sources_after, ref.sources_before)) {
|
|
4095
4094
|
let updated;
|
|
4096
4095
|
if (isRaw) {
|
|
@@ -4116,8 +4115,8 @@ ${fmRewritten}
|
|
|
4116
4115
|
if (isRaw) {
|
|
4117
4116
|
for (const ref of cascade.citation_refs) {
|
|
4118
4117
|
if (cascade.source_array_refs.some((sourceRef) => sourceRef.page === ref.page)) continue;
|
|
4119
|
-
const absPath =
|
|
4120
|
-
const original = await
|
|
4118
|
+
const absPath = join19(input.vault, ref.page);
|
|
4119
|
+
const original = await readFile7(absPath, "utf8");
|
|
4121
4120
|
const updated = rewriteRawSourceReferences(original, relPath, archivePath).text;
|
|
4122
4121
|
if (updated !== original) {
|
|
4123
4122
|
const write = await safeWritePage(absPath, updated);
|
|
@@ -4128,13 +4127,13 @@ ${fmRewritten}
|
|
|
4128
4127
|
}
|
|
4129
4128
|
}
|
|
4130
4129
|
if (!isRaw) {
|
|
4131
|
-
await
|
|
4132
|
-
await rename2(
|
|
4130
|
+
await mkdir6(dirname5(join19(input.vault, archivePath)), { recursive: true });
|
|
4131
|
+
await rename2(join19(input.vault, relPath), join19(input.vault, archivePath));
|
|
4133
4132
|
}
|
|
4134
4133
|
let indexUpdated = false;
|
|
4135
4134
|
if (!isRaw) {
|
|
4136
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
4137
|
-
const before = await
|
|
4135
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-2K672CBO.js");
|
|
4136
|
+
const before = await readFile7(join19(input.vault, "index.md"), "utf8").catch(() => "");
|
|
4138
4137
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
4139
4138
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
|
4140
4139
|
const hadIndexEntry = before.includes(`[[${fullTarget}]]`) || before.includes(`[[${bare}]]`);
|
|
@@ -4188,7 +4187,7 @@ ${fmRewritten}
|
|
|
4188
4187
|
|
|
4189
4188
|
// src/commands/remove.ts
|
|
4190
4189
|
import { unlink as unlink2, access } from "fs/promises";
|
|
4191
|
-
import { join as
|
|
4190
|
+
import { join as join20 } from "path";
|
|
4192
4191
|
async function pathExists(abs) {
|
|
4193
4192
|
try {
|
|
4194
4193
|
await access(abs);
|
|
@@ -4214,7 +4213,7 @@ async function runRemove(input) {
|
|
|
4214
4213
|
if (!relPath) {
|
|
4215
4214
|
try {
|
|
4216
4215
|
const candidate = normalizeVaultRelPath(input.page);
|
|
4217
|
-
if (await pathExists(
|
|
4216
|
+
if (await pathExists(join20(input.vault, candidate))) {
|
|
4218
4217
|
relPath = candidate;
|
|
4219
4218
|
}
|
|
4220
4219
|
} catch {
|
|
@@ -4252,12 +4251,12 @@ async function runRemove(input) {
|
|
|
4252
4251
|
reason: input.reason
|
|
4253
4252
|
});
|
|
4254
4253
|
const tombstonePath = await writeDeleteIntent(input.vault, intent);
|
|
4255
|
-
await unlink2(
|
|
4254
|
+
await unlink2(join20(input.vault, relPath));
|
|
4256
4255
|
if (relPath.endsWith(".md") && !relPath.startsWith("raw/")) {
|
|
4257
|
-
const { readFile:
|
|
4256
|
+
const { readFile: readFile23 } = await import("fs/promises");
|
|
4258
4257
|
const { join: pathJoin } = await import("path");
|
|
4259
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
4260
|
-
const before = await
|
|
4258
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-2K672CBO.js");
|
|
4259
|
+
const before = await readFile23(pathJoin(input.vault, "index.md"), "utf8").catch(() => "");
|
|
4261
4260
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
4262
4261
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
|
4263
4262
|
const hadIndexEntry = before.includes(`[[${fullTarget}]]`) || before.includes(`[[${bare}]]`);
|
|
@@ -4606,7 +4605,7 @@ ${migratedBody}${newFooter}`;
|
|
|
4606
4605
|
|
|
4607
4606
|
// src/commands/update.ts
|
|
4608
4607
|
import { execSync } from "child_process";
|
|
4609
|
-
import { join as
|
|
4608
|
+
import { join as join21 } from "path";
|
|
4610
4609
|
function parseCoreSemver(version) {
|
|
4611
4610
|
const m = version.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
4612
4611
|
if (!m) return null;
|
|
@@ -4650,6 +4649,8 @@ function migrationNotesForUpgrade(previousVersion, newVersion) {
|
|
|
4650
4649
|
"- frozen-leaf hosts write via HTTP MCP only; do not local-write raw/transcripts/ or vault git"
|
|
4651
4650
|
);
|
|
4652
4651
|
}
|
|
4652
|
+
const next = parseCoreSemver(newVersion);
|
|
4653
|
+
if (next && isAtLeast(next, 0, 10, 111)) notes.push(CLIP_MIGRATION_HINT);
|
|
4653
4654
|
return notes;
|
|
4654
4655
|
}
|
|
4655
4656
|
function resolveGlobalSkillsRoot() {
|
|
@@ -4658,7 +4659,7 @@ function resolveGlobalSkillsRoot() {
|
|
|
4658
4659
|
encoding: "utf8",
|
|
4659
4660
|
timeout: 5e3
|
|
4660
4661
|
}).trim();
|
|
4661
|
-
return
|
|
4662
|
+
return join21(globalRoot, "skillwiki", "skills");
|
|
4662
4663
|
} catch {
|
|
4663
4664
|
return null;
|
|
4664
4665
|
}
|
|
@@ -4686,7 +4687,7 @@ async function runUpdate(input) {
|
|
|
4686
4687
|
const pkg2 = readCliPackageJson();
|
|
4687
4688
|
const currentVersion = pkg2.version;
|
|
4688
4689
|
const tag = normalizeDistTag(input.distTag);
|
|
4689
|
-
const target =
|
|
4690
|
+
const target = join21(input.home, ".claude", "skills");
|
|
4690
4691
|
let latest;
|
|
4691
4692
|
try {
|
|
4692
4693
|
latest = execSync(`npm view skillwiki@${tag} version`, {
|
|
@@ -4719,7 +4720,8 @@ async function runUpdate(input) {
|
|
|
4719
4720
|
version_warnings: [],
|
|
4720
4721
|
skills_refreshed: false,
|
|
4721
4722
|
deferred_to_plugin: false,
|
|
4722
|
-
humanHint: `Already on npm@${tag}: v${currentVersion}
|
|
4723
|
+
humanHint: `Already on npm@${tag}: v${currentVersion}
|
|
4724
|
+
${CLIP_MIGRATION_HINT}`
|
|
4723
4725
|
})
|
|
4724
4726
|
};
|
|
4725
4727
|
}
|
|
@@ -4750,6 +4752,12 @@ async function runUpdate(input) {
|
|
|
4750
4752
|
for (const line of migrationNotesForUpgrade(currentVersion, latest)) {
|
|
4751
4753
|
hintLines.push(line);
|
|
4752
4754
|
}
|
|
4755
|
+
try {
|
|
4756
|
+
const clipHint = await refreshInstalledClipPlist(input.home);
|
|
4757
|
+
if (clipHint) hintLines.push(clipHint);
|
|
4758
|
+
} catch (e) {
|
|
4759
|
+
hintLines.push(`clip plist refresh skipped: ${e instanceof Error ? e.message : "migration failed"}`);
|
|
4760
|
+
}
|
|
4753
4761
|
return {
|
|
4754
4762
|
exitCode: ExitCode.OK,
|
|
4755
4763
|
result: ok({
|
|
@@ -4767,13 +4775,13 @@ async function runUpdate(input) {
|
|
|
4767
4775
|
// src/commands/self-update.ts
|
|
4768
4776
|
import { execSync as execSync2 } from "child_process";
|
|
4769
4777
|
import { existsSync as existsSync8, readFileSync as readFileSync11 } from "fs";
|
|
4770
|
-
import { join as
|
|
4778
|
+
import { join as join22 } from "path";
|
|
4771
4779
|
var DEFAULT_SOURCE_ROOT_SUFFIX = "/Desktop/code/llm-wiki";
|
|
4772
4780
|
async function runSelfUpdate(input) {
|
|
4773
4781
|
const currentVersion = readCliPackageJson().version;
|
|
4774
4782
|
const sourceRoot = input.sourceRoot ?? `${input.home}${DEFAULT_SOURCE_ROOT_SUFFIX}`;
|
|
4775
4783
|
const distTag = normalizeDistTag(input.distTag);
|
|
4776
|
-
const localPkgPath =
|
|
4784
|
+
const localPkgPath = join22(sourceRoot, "packages", "cli", "package.json");
|
|
4777
4785
|
const hasLocalSource = existsSync8(localPkgPath);
|
|
4778
4786
|
if (input.check) {
|
|
4779
4787
|
let availableVersion = null;
|
|
@@ -4905,21 +4913,21 @@ async function runSelfUpdate(input) {
|
|
|
4905
4913
|
}
|
|
4906
4914
|
|
|
4907
4915
|
// src/commands/transcripts.ts
|
|
4908
|
-
import { readdir as
|
|
4909
|
-
import { join as
|
|
4916
|
+
import { readdir as readdir4, stat as stat4, readFile as readFile9 } from "fs/promises";
|
|
4917
|
+
import { join as join23 } from "path";
|
|
4910
4918
|
async function runTranscripts(input) {
|
|
4911
|
-
const dir =
|
|
4919
|
+
const dir = join23(input.vault, "raw", "transcripts");
|
|
4912
4920
|
let entries;
|
|
4913
4921
|
try {
|
|
4914
|
-
entries = await
|
|
4922
|
+
entries = await readdir4(dir, { withFileTypes: true });
|
|
4915
4923
|
} catch {
|
|
4916
4924
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: { ok: false, error: "VAULT_PATH_INVALID", detail: `raw/transcripts/ not found: ${dir}` } };
|
|
4917
4925
|
}
|
|
4918
4926
|
const transcripts = [];
|
|
4919
4927
|
for (const entry of entries) {
|
|
4920
4928
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
4921
|
-
const filePath =
|
|
4922
|
-
const content = await
|
|
4929
|
+
const filePath = join23(dir, entry.name);
|
|
4930
|
+
const content = await readFile9(filePath, "utf8");
|
|
4923
4931
|
const fm = extractFrontmatter(content);
|
|
4924
4932
|
if (!fm.ok) continue;
|
|
4925
4933
|
const ingested = typeof fm.data.ingested === "string" ? fm.data.ingested : "";
|
|
@@ -4936,8 +4944,8 @@ async function runTranscripts(input) {
|
|
|
4936
4944
|
}
|
|
4937
4945
|
|
|
4938
4946
|
// src/commands/claims-audit.ts
|
|
4939
|
-
import { readFile as
|
|
4940
|
-
import { join as
|
|
4947
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
4948
|
+
import { join as join24 } from "path";
|
|
4941
4949
|
function safeProjectPresentation(raw) {
|
|
4942
4950
|
if (safeDiagnosticValue(raw) === REDACTED_MALFORMED_REFERENCE) {
|
|
4943
4951
|
return REDACTED_MALFORMED_REFERENCE;
|
|
@@ -4977,9 +4985,9 @@ async function runClaimsAudit(input) {
|
|
|
4977
4985
|
return !input.project || slugByDir.get(relDir) === input.project;
|
|
4978
4986
|
});
|
|
4979
4987
|
const claimSourceResults = await mapWithConcurrency(scopedSpecDirs, vaultIoConcurrency(), async (relDir) => {
|
|
4980
|
-
const specPath =
|
|
4988
|
+
const specPath = join24(input.vault, relDir, "spec.md");
|
|
4981
4989
|
try {
|
|
4982
|
-
const specText = await
|
|
4990
|
+
const specText = await readFile10(specPath, "utf8");
|
|
4983
4991
|
const fm = extractFrontmatter(specText);
|
|
4984
4992
|
if (!fm.ok) return null;
|
|
4985
4993
|
return {
|
|
@@ -5073,10 +5081,10 @@ async function runClaimsAudit(input) {
|
|
|
5073
5081
|
}
|
|
5074
5082
|
|
|
5075
5083
|
// src/commands/compound.ts
|
|
5076
|
-
import { writeFile as
|
|
5077
|
-
import { join as
|
|
5084
|
+
import { writeFile as writeFile5, mkdir as mkdir7, readdir as readdir5, unlink as unlink3 } from "fs/promises";
|
|
5085
|
+
import { join as join25 } from "path";
|
|
5078
5086
|
import { existsSync as existsSync9 } from "fs";
|
|
5079
|
-
import { readFile as
|
|
5087
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
5080
5088
|
var RETRO_HEADING_RE = /^## \[(\d{4}-\d{2}-\d{2})(?:\s+[^\]]+)?\] retro \| loop cycle(?: (\d+))?: (.+)$/;
|
|
5081
5089
|
var FIELD_RE = {
|
|
5082
5090
|
improve: /^-\s+\*?\*?Improve:?\*?\*?\s*(.+)$/m,
|
|
@@ -5174,17 +5182,17 @@ function extractRetroFields(date, cycleName, block) {
|
|
|
5174
5182
|
};
|
|
5175
5183
|
}
|
|
5176
5184
|
async function runCompound(input) {
|
|
5177
|
-
const logPath =
|
|
5185
|
+
const logPath = join25(input.vault, "log.md");
|
|
5178
5186
|
let logText;
|
|
5179
5187
|
try {
|
|
5180
|
-
logText = await
|
|
5188
|
+
logText = await readFile11(logPath, "utf8");
|
|
5181
5189
|
} catch {
|
|
5182
5190
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: logPath }) };
|
|
5183
5191
|
}
|
|
5184
5192
|
const entries = parseRetroEntries(logText);
|
|
5185
5193
|
const promoted = [];
|
|
5186
5194
|
const skipped = [];
|
|
5187
|
-
const compoundDir =
|
|
5195
|
+
const compoundDir = join25(input.vault, "projects", input.project, "compound");
|
|
5188
5196
|
for (const entry of entries) {
|
|
5189
5197
|
const generalizeValue = entry.generalize.trim();
|
|
5190
5198
|
if (!/^yes/i.test(generalizeValue)) {
|
|
@@ -5192,7 +5200,7 @@ async function runCompound(input) {
|
|
|
5192
5200
|
continue;
|
|
5193
5201
|
}
|
|
5194
5202
|
const slug = slugify(entry.cycleName);
|
|
5195
|
-
const compoundPath =
|
|
5203
|
+
const compoundPath = join25(compoundDir, `${slug}.md`);
|
|
5196
5204
|
if (existsSync9(compoundPath)) {
|
|
5197
5205
|
skipped.push(entry.date);
|
|
5198
5206
|
continue;
|
|
@@ -5232,9 +5240,9 @@ async function runCompound(input) {
|
|
|
5232
5240
|
const content = frontmatter + "\n" + body;
|
|
5233
5241
|
if (!input.dryRun) {
|
|
5234
5242
|
if (!existsSync9(compoundDir)) {
|
|
5235
|
-
await
|
|
5243
|
+
await mkdir7(compoundDir, { recursive: true });
|
|
5236
5244
|
}
|
|
5237
|
-
await
|
|
5245
|
+
await writeFile5(compoundPath, content, "utf8");
|
|
5238
5246
|
}
|
|
5239
5247
|
promoted.push(`${slug}.md`);
|
|
5240
5248
|
}
|
|
@@ -5253,7 +5261,7 @@ async function runCompound(input) {
|
|
|
5253
5261
|
};
|
|
5254
5262
|
}
|
|
5255
5263
|
async function runCompoundDelete(input) {
|
|
5256
|
-
const projectDir =
|
|
5264
|
+
const projectDir = join25(input.vault, "projects", input.project);
|
|
5257
5265
|
if (!existsSync9(projectDir)) {
|
|
5258
5266
|
return {
|
|
5259
5267
|
exitCode: ExitCode.PROJECT_NOT_FOUND,
|
|
@@ -5261,7 +5269,7 @@ async function runCompoundDelete(input) {
|
|
|
5261
5269
|
};
|
|
5262
5270
|
}
|
|
5263
5271
|
const entryName = input.entry.replace(/\.md$/, "");
|
|
5264
|
-
const compoundPath =
|
|
5272
|
+
const compoundPath = join25(projectDir, "compound", `${entryName}.md`);
|
|
5265
5273
|
if (!existsSync9(compoundPath)) {
|
|
5266
5274
|
return {
|
|
5267
5275
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -5295,7 +5303,7 @@ knowledge.md regenerated`
|
|
|
5295
5303
|
};
|
|
5296
5304
|
}
|
|
5297
5305
|
async function runCompoundList(input) {
|
|
5298
|
-
const compoundDir =
|
|
5306
|
+
const compoundDir = join25(input.vault, "projects", input.project, "compound");
|
|
5299
5307
|
if (!existsSync9(compoundDir)) {
|
|
5300
5308
|
return {
|
|
5301
5309
|
exitCode: ExitCode.OK,
|
|
@@ -5310,7 +5318,7 @@ no compound directory found`
|
|
|
5310
5318
|
}
|
|
5311
5319
|
let dirents;
|
|
5312
5320
|
try {
|
|
5313
|
-
dirents = await
|
|
5321
|
+
dirents = await readdir5(compoundDir, { withFileTypes: true });
|
|
5314
5322
|
} catch {
|
|
5315
5323
|
return {
|
|
5316
5324
|
exitCode: ExitCode.OK,
|
|
@@ -5326,10 +5334,10 @@ could not read compound directory`
|
|
|
5326
5334
|
const entries = [];
|
|
5327
5335
|
for (const dirent of dirents) {
|
|
5328
5336
|
if (!dirent.isFile() || !dirent.name.endsWith(".md")) continue;
|
|
5329
|
-
const filePath =
|
|
5337
|
+
const filePath = join25(compoundDir, dirent.name);
|
|
5330
5338
|
let text;
|
|
5331
5339
|
try {
|
|
5332
|
-
text = await
|
|
5340
|
+
text = await readFile11(filePath, "utf8");
|
|
5333
5341
|
} catch {
|
|
5334
5342
|
continue;
|
|
5335
5343
|
}
|
|
@@ -5358,8 +5366,8 @@ no compound entries found`;
|
|
|
5358
5366
|
}
|
|
5359
5367
|
|
|
5360
5368
|
// src/commands/session-brief.ts
|
|
5361
|
-
import { mkdir as
|
|
5362
|
-
import { join as
|
|
5369
|
+
import { mkdir as mkdir8, readFile as readFile12, writeFile as writeFile6 } from "fs/promises";
|
|
5370
|
+
import { join as join26, relative, sep } from "path";
|
|
5363
5371
|
var MAX_WORDS = 900;
|
|
5364
5372
|
async function runSessionBrief(input) {
|
|
5365
5373
|
const { root: scanRoot } = resolveReadOnlyVaultRoot(input.vault);
|
|
@@ -5473,7 +5481,7 @@ async function resolveProject(input) {
|
|
|
5473
5481
|
const envProject = input.env?.SKILLWIKI_PROJECT;
|
|
5474
5482
|
if (envProject) return envProject;
|
|
5475
5483
|
const cwd = input.cwd ?? process.cwd();
|
|
5476
|
-
const projectDotenv = await readProjectSlug(
|
|
5484
|
+
const projectDotenv = await readProjectSlug(join26(cwd, ".skillwiki", ".env"));
|
|
5477
5485
|
if (projectDotenv) return projectDotenv;
|
|
5478
5486
|
const inferred = inferProjectFromPath(input.vault, cwd);
|
|
5479
5487
|
if (inferred) return inferred;
|
|
@@ -5482,7 +5490,7 @@ async function resolveProject(input) {
|
|
|
5482
5490
|
async function readProjectSlug(file) {
|
|
5483
5491
|
let text;
|
|
5484
5492
|
try {
|
|
5485
|
-
text = await
|
|
5493
|
+
text = await readFile12(file, "utf8");
|
|
5486
5494
|
} catch {
|
|
5487
5495
|
return void 0;
|
|
5488
5496
|
}
|
|
@@ -5573,7 +5581,7 @@ async function loadTrendPages(typedPages, pathPattern) {
|
|
|
5573
5581
|
return out;
|
|
5574
5582
|
}
|
|
5575
5583
|
async function loadSessionPins(vault, project) {
|
|
5576
|
-
const text = await readIfExists(
|
|
5584
|
+
const text = await readIfExists(join26(vault, "meta", "session-pins.md"));
|
|
5577
5585
|
if (!text) return [];
|
|
5578
5586
|
const fm = extractFrontmatter(text);
|
|
5579
5587
|
if (!fm.ok) return [];
|
|
@@ -5719,7 +5727,7 @@ function satelliteHealthWarning(health) {
|
|
|
5719
5727
|
return null;
|
|
5720
5728
|
}
|
|
5721
5729
|
async function loadHealthWarnings(vault) {
|
|
5722
|
-
const text = await readIfExists(
|
|
5730
|
+
const text = await readIfExists(join26(vault, ".skillwiki", "health.json"));
|
|
5723
5731
|
if (!text) return [];
|
|
5724
5732
|
try {
|
|
5725
5733
|
const parsed = JSON.parse(text);
|
|
@@ -5732,7 +5740,7 @@ async function loadHealthWarnings(vault) {
|
|
|
5732
5740
|
}
|
|
5733
5741
|
}
|
|
5734
5742
|
async function loadMemoryTopics(vault, project) {
|
|
5735
|
-
const text = await readIfExists(
|
|
5743
|
+
const text = await readIfExists(join26(vault, ".skillwiki", "memory", project, "topics.json"));
|
|
5736
5744
|
if (!text) return [];
|
|
5737
5745
|
try {
|
|
5738
5746
|
const parsed = JSON.parse(text);
|
|
@@ -5757,18 +5765,18 @@ async function loadMemoryTopics(vault, project) {
|
|
|
5757
5765
|
}
|
|
5758
5766
|
}
|
|
5759
5767
|
async function writeBriefArtifacts(vault, input) {
|
|
5760
|
-
const metaPath =
|
|
5761
|
-
const cacheMdPath =
|
|
5762
|
-
const cacheJsonPath =
|
|
5763
|
-
await
|
|
5764
|
-
await
|
|
5768
|
+
const metaPath = join26(vault, "meta", "latest-session-brief.md");
|
|
5769
|
+
const cacheMdPath = join26(vault, ".skillwiki", "session-brief.md");
|
|
5770
|
+
const cacheJsonPath = join26(vault, ".skillwiki", "session-brief.json");
|
|
5771
|
+
await mkdir8(join26(vault, "meta"), { recursive: true });
|
|
5772
|
+
await mkdir8(join26(vault, ".skillwiki"), { recursive: true });
|
|
5765
5773
|
const committed = renderCommittedBrief(input);
|
|
5766
5774
|
const previousComparable = comparableBrief(await readIfExists(metaPath));
|
|
5767
5775
|
const nextComparable = comparableBrief(committed);
|
|
5768
5776
|
const materialChange = previousComparable !== nextComparable;
|
|
5769
|
-
await
|
|
5770
|
-
await
|
|
5771
|
-
await
|
|
5777
|
+
await writeFile6(metaPath, committed, "utf8");
|
|
5778
|
+
await writeFile6(cacheMdPath, input.brief, "utf8");
|
|
5779
|
+
await writeFile6(cacheJsonPath, `${JSON.stringify({
|
|
5772
5780
|
project: input.project,
|
|
5773
5781
|
brief: input.brief,
|
|
5774
5782
|
word_count: input.wordCount,
|
|
@@ -5834,7 +5842,7 @@ function renderCommittedBrief(input) {
|
|
|
5834
5842
|
].filter((line) => line !== "").join("\n");
|
|
5835
5843
|
}
|
|
5836
5844
|
async function rebuildRootIndexProjection(vault) {
|
|
5837
|
-
const before = await readIfExists(
|
|
5845
|
+
const before = await readIfExists(join26(vault, "index.md"));
|
|
5838
5846
|
if (!before) return false;
|
|
5839
5847
|
const projection = await renderRootIndex({ vault, currentText: before });
|
|
5840
5848
|
if (!projection.ok) return false;
|
|
@@ -5844,7 +5852,7 @@ async function rebuildRootIndexProjection(vault) {
|
|
|
5844
5852
|
}
|
|
5845
5853
|
async function readIfExists(path) {
|
|
5846
5854
|
try {
|
|
5847
|
-
return await
|
|
5855
|
+
return await readFile12(path, "utf8");
|
|
5848
5856
|
} catch {
|
|
5849
5857
|
return "";
|
|
5850
5858
|
}
|
|
@@ -5886,14 +5894,14 @@ function dateFromPath(path) {
|
|
|
5886
5894
|
}
|
|
5887
5895
|
|
|
5888
5896
|
// src/commands/ingest.ts
|
|
5889
|
-
import { readFile as
|
|
5890
|
-
import { join as
|
|
5897
|
+
import { readFile as readFile15, open, unlink as unlink4, mkdir as mkdir10 } from "fs/promises";
|
|
5898
|
+
import { join as join31 } from "path";
|
|
5891
5899
|
import { createHash as createHash5 } from "crypto";
|
|
5892
5900
|
|
|
5893
5901
|
// src/commands/page-publish.ts
|
|
5894
5902
|
import { readFileSync as readFileSync13, realpathSync as realpathSync2 } from "fs";
|
|
5895
|
-
import { mkdir as
|
|
5896
|
-
import { dirname as dirname8, join as
|
|
5903
|
+
import { mkdir as mkdir9, readFile as readFile14 } from "fs/promises";
|
|
5904
|
+
import { dirname as dirname8, join as join30, resolve as resolve4 } from "path";
|
|
5897
5905
|
|
|
5898
5906
|
// src/utils/publication-approval.ts
|
|
5899
5907
|
import { createHash as createHash4 } from "crypto";
|
|
@@ -6121,8 +6129,8 @@ function redactApprovalTokens(text) {
|
|
|
6121
6129
|
}
|
|
6122
6130
|
|
|
6123
6131
|
// src/publish/pipeline.ts
|
|
6124
|
-
import { readFile as
|
|
6125
|
-
import { dirname as dirname7, join as
|
|
6132
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
6133
|
+
import { dirname as dirname7, join as join29, resolve as resolve3 } from "path";
|
|
6126
6134
|
|
|
6127
6135
|
// src/utils/publication-operation-journal.ts
|
|
6128
6136
|
import {
|
|
@@ -6135,7 +6143,7 @@ import {
|
|
|
6135
6143
|
unlinkSync,
|
|
6136
6144
|
writeFileSync as writeFileSync5
|
|
6137
6145
|
} from "fs";
|
|
6138
|
-
import { dirname as dirname6, join as
|
|
6146
|
+
import { dirname as dirname6, join as join27 } from "path";
|
|
6139
6147
|
var PUBLICATION_JOURNAL_SCHEMA = "skillwiki-publication-operation-v1";
|
|
6140
6148
|
var PHASE_ORDER2 = [
|
|
6141
6149
|
"locked",
|
|
@@ -6164,16 +6172,16 @@ function vaultIdentity(vaultPath) {
|
|
|
6164
6172
|
return sha256Hex(real).slice(0, 16);
|
|
6165
6173
|
}
|
|
6166
6174
|
function publicationJournalRoot(home = resolveSkillwikiHome()) {
|
|
6167
|
-
return
|
|
6175
|
+
return join27(resolveSkillwikiHome(home), ".skillwiki", "publication-operations");
|
|
6168
6176
|
}
|
|
6169
6177
|
function resolveJournalPaths(vaultPath, operationId2, home = resolveSkillwikiHome()) {
|
|
6170
6178
|
const identity = vaultIdentity(vaultPath);
|
|
6171
6179
|
const rootDir = publicationJournalRoot(home);
|
|
6172
|
-
const vaultDir =
|
|
6180
|
+
const vaultDir = join27(rootDir, identity);
|
|
6173
6181
|
return {
|
|
6174
6182
|
rootDir,
|
|
6175
6183
|
vaultDir,
|
|
6176
|
-
journalPath:
|
|
6184
|
+
journalPath: join27(vaultDir, `${operationId2}.json`)
|
|
6177
6185
|
};
|
|
6178
6186
|
}
|
|
6179
6187
|
function ensurePrivateDir(dir) {
|
|
@@ -6394,7 +6402,7 @@ function completePublicationJournal(input) {
|
|
|
6394
6402
|
}
|
|
6395
6403
|
|
|
6396
6404
|
// src/publish/hold-gates.ts
|
|
6397
|
-
import { join as
|
|
6405
|
+
import { join as join28 } from "path";
|
|
6398
6406
|
function evaluateSchemaGate(content, target, publisherKind) {
|
|
6399
6407
|
const frontmatter = extractFrontmatter(content);
|
|
6400
6408
|
if (!frontmatter.ok) return false;
|
|
@@ -6430,7 +6438,7 @@ function evaluateSchemaGate(content, target, publisherKind) {
|
|
|
6430
6438
|
return false;
|
|
6431
6439
|
}
|
|
6432
6440
|
function evaluateBrokenWikilinkGate(body, scan, ownTarget) {
|
|
6433
|
-
const draftPage = { absPath:
|
|
6441
|
+
const draftPage = { absPath: join28(scan.root, ownTarget), relPath: ownTarget };
|
|
6434
6442
|
const resolver = buildWikilinkResolver([...scan.allMarkdown, draftPage]);
|
|
6435
6443
|
const wikilinks = extractBodyWikilinks(body);
|
|
6436
6444
|
for (const link of wikilinks) {
|
|
@@ -6617,7 +6625,7 @@ function phaseAtLeast(current, needed) {
|
|
|
6617
6625
|
}
|
|
6618
6626
|
async function readPageChanged(targetPath, content) {
|
|
6619
6627
|
try {
|
|
6620
|
-
return ok(await
|
|
6628
|
+
return ok(await readFile13(targetPath, "utf8") !== content);
|
|
6621
6629
|
} catch (error) {
|
|
6622
6630
|
if (error.code === "ENOENT") return ok(true);
|
|
6623
6631
|
return err("WRITE_FAILED", { path: targetPath, message: String(error) });
|
|
@@ -6625,7 +6633,7 @@ async function readPageChanged(targetPath, content) {
|
|
|
6625
6633
|
}
|
|
6626
6634
|
async function readPriorTargetSha(targetPath) {
|
|
6627
6635
|
try {
|
|
6628
|
-
const text = await
|
|
6636
|
+
const text = await readFile13(targetPath, "utf8");
|
|
6629
6637
|
return ok(sha256Hex(text));
|
|
6630
6638
|
} catch (error) {
|
|
6631
6639
|
if (error.code === "ENOENT") return ok("absent");
|
|
@@ -6658,10 +6666,10 @@ function successReceipt(strategy, prepared, details) {
|
|
|
6658
6666
|
};
|
|
6659
6667
|
}
|
|
6660
6668
|
async function runPipelinePreview(strategy, prepared, vault) {
|
|
6661
|
-
const schemaPath =
|
|
6669
|
+
const schemaPath = join29(vault, "SCHEMA.md");
|
|
6662
6670
|
let schemaText;
|
|
6663
6671
|
try {
|
|
6664
|
-
schemaText = await
|
|
6672
|
+
schemaText = await readFile13(schemaPath, "utf8");
|
|
6665
6673
|
} catch (error) {
|
|
6666
6674
|
const result = err("FILE_NOT_FOUND", { path: schemaPath, message: String(error) });
|
|
6667
6675
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result };
|
|
@@ -6685,10 +6693,10 @@ async function runPipelinePreview(strategy, prepared, vault) {
|
|
|
6685
6693
|
if (!indices.ok) {
|
|
6686
6694
|
return { exitCode: indices.exitCode, result: indices.result };
|
|
6687
6695
|
}
|
|
6688
|
-
const logPath =
|
|
6696
|
+
const logPath = join29(vault, "log.md");
|
|
6689
6697
|
let logAppended;
|
|
6690
6698
|
try {
|
|
6691
|
-
const logText = await
|
|
6699
|
+
const logText = await readFile13(logPath, "utf8");
|
|
6692
6700
|
const marker = strategy.publisherKind === "page" ? `<!-- skillwiki-page-publish:${prepared.operationId} -->` : `<!-- skillwiki-project-page-publish:${prepared.operationId} -->`;
|
|
6693
6701
|
logAppended = !logText.includes(marker);
|
|
6694
6702
|
} catch (error) {
|
|
@@ -6779,10 +6787,10 @@ async function runPipelineLockedPrimaryStages(strategy, prepared, vault, deps, j
|
|
|
6779
6787
|
return { ok: false, exitCode: ExitCode.WRITE_FAILED, stage: "journal", state, cause: journalHook };
|
|
6780
6788
|
}
|
|
6781
6789
|
}
|
|
6782
|
-
const schemaPath =
|
|
6790
|
+
const schemaPath = join29(vault, "SCHEMA.md");
|
|
6783
6791
|
let schemaText;
|
|
6784
6792
|
try {
|
|
6785
|
-
schemaText = await
|
|
6793
|
+
schemaText = await readFile13(schemaPath, "utf8");
|
|
6786
6794
|
} catch (error) {
|
|
6787
6795
|
return {
|
|
6788
6796
|
ok: false,
|
|
@@ -6831,8 +6839,8 @@ async function runPipelineLockedPrimaryStages(strategy, prepared, vault, deps, j
|
|
|
6831
6839
|
if (!strategy.usesJournal || !phaseAtLeast(currentPhase, "page")) {
|
|
6832
6840
|
if (strategy.publisherKind === "project-page") {
|
|
6833
6841
|
try {
|
|
6834
|
-
const { mkdir:
|
|
6835
|
-
await
|
|
6842
|
+
const { mkdir: mkdir13 } = await import("fs/promises");
|
|
6843
|
+
await mkdir13(dirname7(prepared.targetPath), { recursive: true });
|
|
6836
6844
|
} catch (error) {
|
|
6837
6845
|
return {
|
|
6838
6846
|
ok: false,
|
|
@@ -6880,8 +6888,8 @@ async function runPipelineLockedPrimaryStages(strategy, prepared, vault, deps, j
|
|
|
6880
6888
|
let visibleSchema;
|
|
6881
6889
|
try {
|
|
6882
6890
|
[visible, visibleSchema] = await Promise.all([
|
|
6883
|
-
|
|
6884
|
-
|
|
6891
|
+
readFile13(prepared.targetPath, "utf8"),
|
|
6892
|
+
readFile13(schemaPath, "utf8")
|
|
6885
6893
|
]);
|
|
6886
6894
|
} catch (error) {
|
|
6887
6895
|
return {
|
|
@@ -7273,16 +7281,16 @@ async function refreshProjectIndexForTarget(vault, projectSlugs, today) {
|
|
|
7273
7281
|
for (const slug of projectSlugs) {
|
|
7274
7282
|
const rendered = await renderProjectIndex(vault, slug, { today });
|
|
7275
7283
|
if (!rendered.ok) return rendered;
|
|
7276
|
-
const indexPath =
|
|
7284
|
+
const indexPath = join30(vault, rendered.data.index_path);
|
|
7277
7285
|
try {
|
|
7278
|
-
await
|
|
7286
|
+
await mkdir9(dirname8(indexPath), { recursive: true });
|
|
7279
7287
|
} catch (error) {
|
|
7280
7288
|
return err("WRITE_FAILED", { path: indexPath, message: String(error) });
|
|
7281
7289
|
}
|
|
7282
7290
|
const written = await atomicWriteText(indexPath, rendered.data.text);
|
|
7283
7291
|
if (!written.ok) return written;
|
|
7284
7292
|
try {
|
|
7285
|
-
const visible = await
|
|
7293
|
+
const visible = await readFile14(indexPath, "utf8");
|
|
7286
7294
|
if (visible !== rendered.data.text) {
|
|
7287
7295
|
return err("WRITE_FAILED", { path: indexPath, message: "project index verification failed" });
|
|
7288
7296
|
}
|
|
@@ -7383,7 +7391,7 @@ function preparePagePublicationFromContent(input) {
|
|
|
7383
7391
|
async function preparePagePublication(input) {
|
|
7384
7392
|
let content;
|
|
7385
7393
|
try {
|
|
7386
|
-
content = await
|
|
7394
|
+
content = await readFile14(input.draftPath, "utf8");
|
|
7387
7395
|
} catch (error) {
|
|
7388
7396
|
return err("FILE_NOT_FOUND", { path: input.draftPath, message: String(error) });
|
|
7389
7397
|
}
|
|
@@ -7471,10 +7479,10 @@ var PAGE_PUBLISH_STRATEGY = {
|
|
|
7471
7479
|
return void 0;
|
|
7472
7480
|
},
|
|
7473
7481
|
async previewIndices(prepared, vault, pageChanged) {
|
|
7474
|
-
const indexPath =
|
|
7482
|
+
const indexPath = join30(vault, "index.md");
|
|
7475
7483
|
let indexText;
|
|
7476
7484
|
try {
|
|
7477
|
-
indexText = await
|
|
7485
|
+
indexText = await readFile14(indexPath, "utf8");
|
|
7478
7486
|
} catch (error) {
|
|
7479
7487
|
const result = err("FILE_NOT_FOUND", { path: indexPath, message: String(error) });
|
|
7480
7488
|
return { ok: false, exitCode: ExitCode.FILE_NOT_FOUND, result };
|
|
@@ -7492,7 +7500,7 @@ var PAGE_PUBLISH_STRATEGY = {
|
|
|
7492
7500
|
if (!renderedProject.ok) {
|
|
7493
7501
|
return { ok: false, exitCode: errorExitCode(renderedProject.error), result: renderedProject };
|
|
7494
7502
|
}
|
|
7495
|
-
const projectIndexPath =
|
|
7503
|
+
const projectIndexPath = join30(vault, renderedProject.data.index_path);
|
|
7496
7504
|
const projectIndexChanged = await readPageChanged(projectIndexPath, renderedProject.data.text);
|
|
7497
7505
|
if (!projectIndexChanged.ok) {
|
|
7498
7506
|
return { ok: false, exitCode: errorExitCode(projectIndexChanged.error), result: projectIndexChanged };
|
|
@@ -7680,7 +7688,7 @@ function buildTypedContent(title, ingested, type, tags, rawRelPath, provenance)
|
|
|
7680
7688
|
}
|
|
7681
7689
|
async function resolveRawCapture(input) {
|
|
7682
7690
|
try {
|
|
7683
|
-
const existing = await
|
|
7691
|
+
const existing = await readFile15(input.path, "utf8");
|
|
7684
7692
|
const frontmatter = extractFrontmatter(existing);
|
|
7685
7693
|
if (!frontmatter.ok) {
|
|
7686
7694
|
return err("INGEST_VALIDATION_FAILED", {
|
|
@@ -7819,7 +7827,7 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
|
|
|
7819
7827
|
sourceContent = fetchResult.data.body;
|
|
7820
7828
|
} else {
|
|
7821
7829
|
try {
|
|
7822
|
-
sourceContent = await
|
|
7830
|
+
sourceContent = await readFile15(input.source, "utf8");
|
|
7823
7831
|
} catch {
|
|
7824
7832
|
return {
|
|
7825
7833
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -7844,7 +7852,7 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
|
|
|
7844
7852
|
const rawRelPath = `raw/articles/${slug}.md`;
|
|
7845
7853
|
const typedDir = TYPE_DIR[input.type] ?? `${input.type}s`;
|
|
7846
7854
|
const typedRelPath = `${typedDir}/${slug}.md`;
|
|
7847
|
-
const rawAbsPath =
|
|
7855
|
+
const rawAbsPath = join31(input.vault, rawRelPath);
|
|
7848
7856
|
const identity = assessSourceIdentity({
|
|
7849
7857
|
rawPath: rawRelPath,
|
|
7850
7858
|
sourceUrl: sourceUrl ?? void 0,
|
|
@@ -7888,11 +7896,11 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
|
|
|
7888
7896
|
);
|
|
7889
7897
|
if (!input.dryRun) {
|
|
7890
7898
|
try {
|
|
7891
|
-
await
|
|
7899
|
+
await mkdir10(join31(input.vault, typedDir), { recursive: true });
|
|
7892
7900
|
} catch (error) {
|
|
7893
7901
|
return {
|
|
7894
7902
|
exitCode: ExitCode.WRITE_FAILED,
|
|
7895
|
-
result: err("WRITE_FAILED", { path:
|
|
7903
|
+
result: err("WRITE_FAILED", { path: join31(input.vault, typedDir), message: String(error) })
|
|
7896
7904
|
};
|
|
7897
7905
|
}
|
|
7898
7906
|
}
|
|
@@ -7946,11 +7954,11 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
|
|
|
7946
7954
|
preflight: pagePublishDeps.preflight,
|
|
7947
7955
|
mutate: async (receipt) => {
|
|
7948
7956
|
try {
|
|
7949
|
-
await
|
|
7957
|
+
await mkdir10(join31(input.vault, "raw", "articles"), { recursive: true });
|
|
7950
7958
|
} catch (error) {
|
|
7951
7959
|
return {
|
|
7952
7960
|
exitCode: ExitCode.WRITE_FAILED,
|
|
7953
|
-
result: err("WRITE_FAILED", { path:
|
|
7961
|
+
result: err("WRITE_FAILED", { path: join31(input.vault, "raw", "articles"), message: String(error) })
|
|
7954
7962
|
};
|
|
7955
7963
|
}
|
|
7956
7964
|
const rawWrite = await writeResolvedRaw({
|
|
@@ -8186,8 +8194,8 @@ ${body}`;
|
|
|
8186
8194
|
}
|
|
8187
8195
|
|
|
8188
8196
|
// src/commands/tag-reconcile.ts
|
|
8189
|
-
import { readFile as
|
|
8190
|
-
import { join as
|
|
8197
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
8198
|
+
import { join as join32, posix } from "path";
|
|
8191
8199
|
var TYPED_TARGET_RE = /^(entities|concepts|comparisons|queries|meta)\/[a-z0-9][a-z0-9./_-]*\.md$/;
|
|
8192
8200
|
function errorExitCode2(error) {
|
|
8193
8201
|
switch (error) {
|
|
@@ -8230,7 +8238,7 @@ function asTagArray(frontmatter, path) {
|
|
|
8230
8238
|
async function readTagsFromFile(path) {
|
|
8231
8239
|
let text;
|
|
8232
8240
|
try {
|
|
8233
|
-
text = await
|
|
8241
|
+
text = await readFile16(path, "utf8");
|
|
8234
8242
|
} catch (error) {
|
|
8235
8243
|
if (error.code === "ENOENT") {
|
|
8236
8244
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path }) };
|
|
@@ -8251,7 +8259,7 @@ async function resolveRequestedTags(input, page) {
|
|
|
8251
8259
|
result: err("INVALID_FRONTMATTER", { message: "explicit tags must be an array of strings" })
|
|
8252
8260
|
};
|
|
8253
8261
|
}
|
|
8254
|
-
const source = input.from ?? (explicit.length === 0 ?
|
|
8262
|
+
const source = input.from ?? (explicit.length === 0 ? join32(input.vault, page) : void 0);
|
|
8255
8263
|
if (!source) return { exitCode: ExitCode.OK, result: ok({ tags: [...new Set(explicit)].sort() }) };
|
|
8256
8264
|
const sourced = await readTagsFromFile(source);
|
|
8257
8265
|
if (!sourced.result.ok) return { exitCode: sourced.exitCode, result: sourced.result };
|
|
@@ -8262,7 +8270,7 @@ async function resolveRequestedTags(input, page) {
|
|
|
8262
8270
|
}
|
|
8263
8271
|
async function readSchema(schemaPath) {
|
|
8264
8272
|
try {
|
|
8265
|
-
return { exitCode: ExitCode.OK, result: ok(await
|
|
8273
|
+
return { exitCode: ExitCode.OK, result: ok(await readFile16(schemaPath, "utf8")) };
|
|
8266
8274
|
} catch (error) {
|
|
8267
8275
|
if (error.code === "ENOENT") {
|
|
8268
8276
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: schemaPath }) };
|
|
@@ -8290,7 +8298,7 @@ function previewResult(page, tags, reconciled, dryRun, filesChanged) {
|
|
|
8290
8298
|
};
|
|
8291
8299
|
}
|
|
8292
8300
|
async function reconcileTagsWhileLocked(input, page, tags, comment) {
|
|
8293
|
-
const schemaPath =
|
|
8301
|
+
const schemaPath = join32(input.vault, "SCHEMA.md");
|
|
8294
8302
|
const current = await readSchema(schemaPath);
|
|
8295
8303
|
if (!current.result.ok) return { exitCode: current.exitCode, result: current.result };
|
|
8296
8304
|
const next = reconcileTaxonomyDocument(current.result.data, { tags, comment });
|
|
@@ -8301,7 +8309,7 @@ async function reconcileTagsWhileLocked(input, page, tags, comment) {
|
|
|
8301
8309
|
}
|
|
8302
8310
|
let verifiedText;
|
|
8303
8311
|
try {
|
|
8304
|
-
verifiedText = await
|
|
8312
|
+
verifiedText = await readFile16(schemaPath, "utf8");
|
|
8305
8313
|
} catch (error) {
|
|
8306
8314
|
return {
|
|
8307
8315
|
exitCode: ExitCode.WRITE_FAILED,
|
|
@@ -8327,7 +8335,7 @@ async function runTagReconcile(input) {
|
|
|
8327
8335
|
const comment = taxonomyCommentForPage(page.data, date, input.reason);
|
|
8328
8336
|
if (!comment.ok) return { exitCode: ExitCode.SCHEME_REJECTED, result: comment };
|
|
8329
8337
|
if (!input.write) {
|
|
8330
|
-
const schema = await readSchema(
|
|
8338
|
+
const schema = await readSchema(join32(input.vault, "SCHEMA.md"));
|
|
8331
8339
|
if (!schema.result.ok) return { exitCode: schema.exitCode, result: schema.result };
|
|
8332
8340
|
const preview = reconcileTaxonomyDocument(schema.result.data, { tags, comment: comment.data });
|
|
8333
8341
|
return previewResult(page.data, tags, preview, true, []);
|
|
@@ -8380,8 +8388,8 @@ async function runTagReconcile(input) {
|
|
|
8380
8388
|
|
|
8381
8389
|
// src/commands/project-page-publish.ts
|
|
8382
8390
|
import { realpathSync as realpathSync4 } from "fs";
|
|
8383
|
-
import { mkdir as
|
|
8384
|
-
import { dirname as dirname10, join as
|
|
8391
|
+
import { mkdir as mkdir11, readFile as readFile17 } from "fs/promises";
|
|
8392
|
+
import { dirname as dirname10, join as join33, resolve as resolve6 } from "path";
|
|
8385
8393
|
|
|
8386
8394
|
// src/utils/architecture-page.ts
|
|
8387
8395
|
import { lstatSync, realpathSync as realpathSync3 } from "fs";
|
|
@@ -8553,7 +8561,7 @@ function validateLogNote(logNote) {
|
|
|
8553
8561
|
async function prepareProjectPagePublication(input) {
|
|
8554
8562
|
let content;
|
|
8555
8563
|
try {
|
|
8556
|
-
content = await
|
|
8564
|
+
content = await readFile17(input.draftPath, "utf8");
|
|
8557
8565
|
} catch (error) {
|
|
8558
8566
|
return err("FILE_NOT_FOUND", { path: input.draftPath, message: String(error) });
|
|
8559
8567
|
}
|
|
@@ -8686,9 +8694,9 @@ var PROJECT_PAGE_PUBLISH_STRATEGY = {
|
|
|
8686
8694
|
async updateIndicesLocked(prepared, vault, state, observe) {
|
|
8687
8695
|
const rendered = await renderProjectIndex(vault, prepared.page.project, { today: prepared.date });
|
|
8688
8696
|
if (!rendered.ok) return rendered;
|
|
8689
|
-
const knowledgePath =
|
|
8697
|
+
const knowledgePath = join33(vault, rendered.data.index_path);
|
|
8690
8698
|
try {
|
|
8691
|
-
await
|
|
8699
|
+
await mkdir11(dirname10(knowledgePath), { recursive: true });
|
|
8692
8700
|
} catch (error) {
|
|
8693
8701
|
return err("WRITE_FAILED", { message: String(error) });
|
|
8694
8702
|
}
|
|
@@ -8697,7 +8705,7 @@ var PROJECT_PAGE_PUBLISH_STRATEGY = {
|
|
|
8697
8705
|
state.projectIndexUpdated = knowledgeWrite.data.changed;
|
|
8698
8706
|
if (state.projectIndexUpdated) state.changed.add(rendered.data.index_path);
|
|
8699
8707
|
try {
|
|
8700
|
-
const visibleIndex = await
|
|
8708
|
+
const visibleIndex = await readFile17(knowledgePath, "utf8");
|
|
8701
8709
|
if (visibleIndex !== rendered.data.text) {
|
|
8702
8710
|
return err("WRITE_FAILED", { message: "project knowledge.md verification failed" });
|
|
8703
8711
|
}
|
|
@@ -8717,9 +8725,9 @@ var PROJECT_PAGE_PUBLISH_STRATEGY = {
|
|
|
8717
8725
|
}
|
|
8718
8726
|
let projectIndexChanged = true;
|
|
8719
8727
|
if (projectIndex.ok) {
|
|
8720
|
-
const indexPath =
|
|
8728
|
+
const indexPath = join33(vault, projectIndex.data.index_path);
|
|
8721
8729
|
try {
|
|
8722
|
-
const existing = await
|
|
8730
|
+
const existing = await readFile17(indexPath, "utf8");
|
|
8723
8731
|
projectIndexChanged = existing !== projectIndex.data.text || pageChanged;
|
|
8724
8732
|
} catch {
|
|
8725
8733
|
projectIndexChanged = true;
|
|
@@ -8879,7 +8887,7 @@ import { existsSync as existsSync11, writeFileSync as writeFileSync6, mkdirSync
|
|
|
8879
8887
|
import { createHash as createHash6 } from "crypto";
|
|
8880
8888
|
import { execSync as execSync3, spawn } from "child_process";
|
|
8881
8889
|
import { platform as platform2 } from "os";
|
|
8882
|
-
import { join as
|
|
8890
|
+
import { join as join34, resolve as resolvePath } from "path";
|
|
8883
8891
|
var MAINTENANCE_SCHEMA_VERSION = 1;
|
|
8884
8892
|
var MAINTENANCE_COMMAND = "snapshot-maintenance journal clear-stale";
|
|
8885
8893
|
var REPAIR_COMMAND = "snapshot-maintenance projection-conflict repair";
|
|
@@ -8944,7 +8952,7 @@ async function runSnapshotMaintenanceDryRun(input) {
|
|
|
8944
8952
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_WRONG_WORKTREE"));
|
|
8945
8953
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_WRONG_WORKTREE", `requested path '${requested}' is not the configured snapshot worktree '${canonicalize(configuredWorktree)}'`) };
|
|
8946
8954
|
}
|
|
8947
|
-
if (!existsSync11(requested) || !existsSync11(
|
|
8955
|
+
if (!existsSync11(requested) || !existsSync11(join34(requested, ".git"))) {
|
|
8948
8956
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_MISSING_GIT_REPO"));
|
|
8949
8957
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_MISSING_GIT_REPO", `snapshot worktree is not a git repository: ${requested}`) };
|
|
8950
8958
|
}
|
|
@@ -9024,14 +9032,14 @@ async function resolveLiveVault(input) {
|
|
|
9024
9032
|
return resolved.ok ? canonicalize(resolved.data.path) : void 0;
|
|
9025
9033
|
}
|
|
9026
9034
|
function snapshotMaintenanceAuditLogPath(home) {
|
|
9027
|
-
const stateDir = platform2() === "darwin" ?
|
|
9028
|
-
return
|
|
9035
|
+
const stateDir = platform2() === "darwin" ? join34(home, "Library", "Application Support", "vault-sync") : join34(home, ".local", "state", "vault-sync");
|
|
9036
|
+
return join34(stateDir, "snapshot-maintenance-audit.jsonl");
|
|
9029
9037
|
}
|
|
9030
9038
|
function defaultAuditSink(home) {
|
|
9031
9039
|
return (event) => {
|
|
9032
9040
|
try {
|
|
9033
9041
|
const logPath = snapshotMaintenanceAuditLogPath(home);
|
|
9034
|
-
mkdirSync4(
|
|
9042
|
+
mkdirSync4(join34(logPath, ".."), { recursive: true });
|
|
9035
9043
|
appendFileSync(logPath, JSON.stringify(event) + "\n", { encoding: "utf8" });
|
|
9036
9044
|
} catch {
|
|
9037
9045
|
}
|
|
@@ -9179,9 +9187,9 @@ function nonMergeSequencerActive(repo) {
|
|
|
9179
9187
|
const gitDir = git(repo, ["rev-parse", "--absolute-git-dir"]);
|
|
9180
9188
|
if (!gitDir) return false;
|
|
9181
9189
|
for (const m of ["CHERRY_PICK_HEAD", "REVERT_HEAD"]) {
|
|
9182
|
-
if (existsSync11(
|
|
9190
|
+
if (existsSync11(join34(gitDir, m))) return true;
|
|
9183
9191
|
}
|
|
9184
|
-
return existsSync11(
|
|
9192
|
+
return existsSync11(join34(gitDir, "rebase-merge")) || existsSync11(join34(gitDir, "rebase-apply"));
|
|
9185
9193
|
}
|
|
9186
9194
|
function extraUnmergedPaths(unmerged) {
|
|
9187
9195
|
const allow = new Set(PROJECTION_CONFLICT_ALLOWLIST);
|
|
@@ -9220,7 +9228,7 @@ async function authorizeRepairContext(input) {
|
|
|
9220
9228
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_WRONG_WORKTREE", void 0, REPAIR_COMMAND));
|
|
9221
9229
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_WRONG_WORKTREE", `requested path '${requested}' is not the configured snapshot worktree '${canonicalize(configuredWorktree)}'`) };
|
|
9222
9230
|
}
|
|
9223
|
-
if (!existsSync11(requested) || !existsSync11(
|
|
9231
|
+
if (!existsSync11(requested) || !existsSync11(join34(requested, ".git"))) {
|
|
9224
9232
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_MISSING_GIT_REPO", void 0, REPAIR_COMMAND));
|
|
9225
9233
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_MISSING_GIT_REPO", `snapshot worktree is not a git repository: ${requested}`) };
|
|
9226
9234
|
}
|
|
@@ -9321,8 +9329,8 @@ async function performProjectionRepair(input, plan, audit, now) {
|
|
|
9321
9329
|
return { exitCode: ExitCode.WRITE_FAILED, result: rendered };
|
|
9322
9330
|
}
|
|
9323
9331
|
try {
|
|
9324
|
-
writeFileSync6(
|
|
9325
|
-
writeFileSync6(
|
|
9332
|
+
writeFileSync6(join34(plan.snapshot_worktree, "index.md"), rendered.data.index);
|
|
9333
|
+
writeFileSync6(join34(plan.snapshot_worktree, "log.md"), rendered.data.log);
|
|
9326
9334
|
gitStrict(plan.snapshot_worktree, ["add", "--", "index.md", "log.md"]);
|
|
9327
9335
|
gitStrict(plan.snapshot_worktree, [
|
|
9328
9336
|
"commit",
|
|
@@ -9430,7 +9438,7 @@ function releaseSnapshotFlock(handle) {
|
|
|
9430
9438
|
|
|
9431
9439
|
// src/commands/backup.ts
|
|
9432
9440
|
import { statSync as statSync3, readdirSync as readdirSync2, readFileSync as readFileSync15, mkdirSync as mkdirSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
9433
|
-
import { join as
|
|
9441
|
+
import { join as join35, relative as relative3, dirname as dirname11 } from "path";
|
|
9434
9442
|
import { PutObjectCommand, HeadObjectCommand, ListObjectsV2Command, GetObjectCommand, DeleteObjectsCommand } from "@aws-sdk/client-s3";
|
|
9435
9443
|
|
|
9436
9444
|
// src/utils/s3-client.ts
|
|
@@ -9454,7 +9462,7 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([".git", ".obsidian", "_archive", "node_
|
|
|
9454
9462
|
function* walkMarkdown(dir, base) {
|
|
9455
9463
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
9456
9464
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
9457
|
-
const full =
|
|
9465
|
+
const full = join35(dir, entry.name);
|
|
9458
9466
|
if (entry.isDirectory()) {
|
|
9459
9467
|
yield* walkMarkdown(full, base);
|
|
9460
9468
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -9477,7 +9485,7 @@ async function runBackupSync(input) {
|
|
|
9477
9485
|
let failed = 0;
|
|
9478
9486
|
const files = [...walkMarkdown(input.vault, input.vault)];
|
|
9479
9487
|
for (const relPath of files) {
|
|
9480
|
-
const absPath =
|
|
9488
|
+
const absPath = join35(input.vault, relPath);
|
|
9481
9489
|
const localStat = statSync3(absPath);
|
|
9482
9490
|
let needsUpload = true;
|
|
9483
9491
|
try {
|
|
@@ -9553,7 +9561,7 @@ async function runBackupRestore(input) {
|
|
|
9553
9561
|
const objects = list.Contents ?? [];
|
|
9554
9562
|
for (const obj of objects) {
|
|
9555
9563
|
if (!obj.Key) continue;
|
|
9556
|
-
const localPath =
|
|
9564
|
+
const localPath = join35(target, obj.Key);
|
|
9557
9565
|
try {
|
|
9558
9566
|
const localStat = statSync3(localPath);
|
|
9559
9567
|
if (obj.LastModified && localStat.mtime > obj.LastModified) {
|
|
@@ -9600,8 +9608,8 @@ async function runBackupRestore(input) {
|
|
|
9600
9608
|
|
|
9601
9609
|
// src/commands/status.ts
|
|
9602
9610
|
import { existsSync as existsSync12, statSync as statSync4 } from "fs";
|
|
9603
|
-
import { readFile as
|
|
9604
|
-
import { join as
|
|
9611
|
+
import { readFile as readFile18 } from "fs/promises";
|
|
9612
|
+
import { join as join36 } from "path";
|
|
9605
9613
|
var FUSE_NO_MIRROR_NOTE = "FUSE vault with no read mirror - status scan may be slow";
|
|
9606
9614
|
async function runStatus(input) {
|
|
9607
9615
|
if (!existsSync12(input.vault)) {
|
|
@@ -9640,7 +9648,7 @@ async function runStatus(input) {
|
|
|
9640
9648
|
const compound = scan.data.compound.length;
|
|
9641
9649
|
let schemaVersion = "v1";
|
|
9642
9650
|
try {
|
|
9643
|
-
const schemaContent = await
|
|
9651
|
+
const schemaContent = await readFile18(join36(scanRoot, "SCHEMA.md"), "utf8");
|
|
9644
9652
|
const versionMatch = schemaContent.match(/version:\s*["']?([^"'\s\n]+)/i);
|
|
9645
9653
|
if (versionMatch) schemaVersion = versionMatch[1];
|
|
9646
9654
|
} catch {
|
|
@@ -9708,13 +9716,13 @@ async function runStatus(input) {
|
|
|
9708
9716
|
|
|
9709
9717
|
// src/commands/copy-status.ts
|
|
9710
9718
|
import { existsSync as existsSync13, realpathSync as realpathSync5 } from "fs";
|
|
9711
|
-
import { isAbsolute as isAbsolute2, join as
|
|
9719
|
+
import { isAbsolute as isAbsolute2, join as join38, relative as relative5, resolve as resolve8 } from "path";
|
|
9712
9720
|
|
|
9713
9721
|
// src/utils/fetch-projection.ts
|
|
9714
|
-
import { isAbsolute, join as
|
|
9722
|
+
import { isAbsolute, join as join37, resolve as resolve7 } from "path";
|
|
9715
9723
|
function inspectConfiguredFetchProjection(home) {
|
|
9716
9724
|
if (!home) return { configured: false };
|
|
9717
|
-
const config = readSkillWikiConfig(
|
|
9725
|
+
const config = readSkillWikiConfig(join37(home, ".skillwiki", ".env"));
|
|
9718
9726
|
const configured = config["vault_sync.fetch_projection"];
|
|
9719
9727
|
if (!configured || configured === "none") return { configured: false };
|
|
9720
9728
|
if (!isAbsolute(configured)) {
|
|
@@ -9725,7 +9733,7 @@ function inspectConfiguredFetchProjection(home) {
|
|
|
9725
9733
|
|
|
9726
9734
|
// src/utils/live-drift.ts
|
|
9727
9735
|
import { createHash as createHash7 } from "crypto";
|
|
9728
|
-
import { readFile as
|
|
9736
|
+
import { readFile as readFile19 } from "fs/promises";
|
|
9729
9737
|
import { relative as relative4, sep as sep3 } from "path";
|
|
9730
9738
|
|
|
9731
9739
|
// src/utils/git-promotion.ts
|
|
@@ -9770,7 +9778,7 @@ async function measureAuthoritativeLiveDrift(liveVault, projection) {
|
|
|
9770
9778
|
const rel = relative4(liveVault, page.absPath).split(sep3).join("/");
|
|
9771
9779
|
if (!isGitPromotablePath(rel)) continue;
|
|
9772
9780
|
livePromotable.add(rel);
|
|
9773
|
-
const bytes = await
|
|
9781
|
+
const bytes = await readFile19(page.absPath);
|
|
9774
9782
|
if (projectionBlobs.get(rel) !== gitBlobOid(bytes)) content += 1;
|
|
9775
9783
|
}
|
|
9776
9784
|
for (const rel of projectionBlobs.keys()) {
|
|
@@ -9965,7 +9973,7 @@ function defaultCopyStatusDeps(input) {
|
|
|
9965
9973
|
const projectionWarning = selection.configured ? `configured fetch projection ignored for Git status; using live vault${projectionProblem ? ` (${projectionProblem})` : ""}` : void 0;
|
|
9966
9974
|
const invalidProjectionDetail = projectionProblem ?? "configured fetch projection is not a git repository";
|
|
9967
9975
|
const gitRootProblem = () => {
|
|
9968
|
-
if (!existsSync13(
|
|
9976
|
+
if (!existsSync13(join38(gitVault, ".git"))) {
|
|
9969
9977
|
return "vault is not a git repository";
|
|
9970
9978
|
}
|
|
9971
9979
|
return void 0;
|
|
@@ -10045,7 +10053,7 @@ function defaultCopyStatusDeps(input) {
|
|
|
10045
10053
|
detail: projectionProblem ?? "live drift requires a configured fetch projection"
|
|
10046
10054
|
};
|
|
10047
10055
|
}
|
|
10048
|
-
if (!existsSync13(
|
|
10056
|
+
if (!existsSync13(join38(configuredProjection, ".git"))) {
|
|
10049
10057
|
return {
|
|
10050
10058
|
unknown: true,
|
|
10051
10059
|
reason_code: "fetch_projection_invalid",
|
|
@@ -10065,8 +10073,8 @@ async function runCopyStatusCommand(input) {
|
|
|
10065
10073
|
}
|
|
10066
10074
|
|
|
10067
10075
|
// src/commands/seed.ts
|
|
10068
|
-
import { mkdir as
|
|
10069
|
-
import { join as
|
|
10076
|
+
import { mkdir as mkdir12, writeFile as writeFile7, stat as stat5 } from "fs/promises";
|
|
10077
|
+
import { join as join39 } from "path";
|
|
10070
10078
|
var TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
10071
10079
|
var EXAMPLE_PAGES = {
|
|
10072
10080
|
"entities/example-project.md": `---
|
|
@@ -10135,30 +10143,30 @@ Real sources are immutable after ingestion \u2014 never edit them.
|
|
|
10135
10143
|
`;
|
|
10136
10144
|
async function runSeed(input) {
|
|
10137
10145
|
try {
|
|
10138
|
-
await stat5(
|
|
10146
|
+
await stat5(join39(input.vault, "SCHEMA.md"));
|
|
10139
10147
|
} catch {
|
|
10140
10148
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { root: input.vault, reason: "SCHEMA.md missing \u2014 run `skillwiki init` first" }) };
|
|
10141
10149
|
}
|
|
10142
10150
|
const created = [];
|
|
10143
10151
|
const skipped = [];
|
|
10144
10152
|
for (const [relPath, content] of Object.entries(EXAMPLE_PAGES)) {
|
|
10145
|
-
const absPath =
|
|
10153
|
+
const absPath = join39(input.vault, relPath);
|
|
10146
10154
|
try {
|
|
10147
10155
|
await stat5(absPath);
|
|
10148
10156
|
skipped.push(relPath);
|
|
10149
10157
|
} catch {
|
|
10150
|
-
await
|
|
10151
|
-
await
|
|
10158
|
+
await mkdir12(join39(absPath, ".."), { recursive: true });
|
|
10159
|
+
await writeFile7(absPath, content, "utf8");
|
|
10152
10160
|
created.push(relPath);
|
|
10153
10161
|
}
|
|
10154
10162
|
}
|
|
10155
|
-
const rawPath =
|
|
10163
|
+
const rawPath = join39(input.vault, "raw", "articles", "example-source.md");
|
|
10156
10164
|
try {
|
|
10157
10165
|
await stat5(rawPath);
|
|
10158
10166
|
skipped.push("raw/articles/example-source.md");
|
|
10159
10167
|
} catch {
|
|
10160
|
-
await
|
|
10161
|
-
await
|
|
10168
|
+
await mkdir12(join39(rawPath, ".."), { recursive: true });
|
|
10169
|
+
await writeFile7(rawPath, EXAMPLE_RAW, "utf8");
|
|
10162
10170
|
created.push("raw/articles/example-source.md");
|
|
10163
10171
|
}
|
|
10164
10172
|
if (created.length > 0) {
|
|
@@ -10180,9 +10188,9 @@ async function runSeed(input) {
|
|
|
10180
10188
|
}
|
|
10181
10189
|
|
|
10182
10190
|
// src/commands/canvas.ts
|
|
10183
|
-
import { readFile as
|
|
10191
|
+
import { readFile as readFile20, writeFile as writeFile8 } from "fs/promises";
|
|
10184
10192
|
import { existsSync as existsSync14 } from "fs";
|
|
10185
|
-
import { join as
|
|
10193
|
+
import { join as join40 } from "path";
|
|
10186
10194
|
var NODE_WIDTH = 240;
|
|
10187
10195
|
var NODE_HEIGHT = 60;
|
|
10188
10196
|
var COLUMN_SPACING = 400;
|
|
@@ -10260,7 +10268,7 @@ function buildCanvasEdges(adjacency) {
|
|
|
10260
10268
|
return edges;
|
|
10261
10269
|
}
|
|
10262
10270
|
async function runCanvasGenerate(input) {
|
|
10263
|
-
const graphPath = input.graphPath ??
|
|
10271
|
+
const graphPath = input.graphPath ?? join40(input.vault, ".skillwiki", "graph.json");
|
|
10264
10272
|
if (!existsSync14(graphPath)) {
|
|
10265
10273
|
return {
|
|
10266
10274
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -10272,7 +10280,7 @@ async function runCanvasGenerate(input) {
|
|
|
10272
10280
|
}
|
|
10273
10281
|
let raw;
|
|
10274
10282
|
try {
|
|
10275
|
-
raw = await
|
|
10283
|
+
raw = await readFile20(graphPath, "utf8");
|
|
10276
10284
|
} catch (e) {
|
|
10277
10285
|
return {
|
|
10278
10286
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -10298,9 +10306,9 @@ async function runCanvasGenerate(input) {
|
|
|
10298
10306
|
const nodes = buildCanvasNodes(paths);
|
|
10299
10307
|
const edges = buildCanvasEdges(graph.adjacency);
|
|
10300
10308
|
const canvas = { nodes, edges };
|
|
10301
|
-
const outPath =
|
|
10309
|
+
const outPath = join40(input.vault, "vault-graph.canvas");
|
|
10302
10310
|
try {
|
|
10303
|
-
await
|
|
10311
|
+
await writeFile8(outPath, JSON.stringify(canvas, null, 2));
|
|
10304
10312
|
} catch (e) {
|
|
10305
10313
|
return {
|
|
10306
10314
|
exitCode: ExitCode.WRITE_FAILED,
|
|
@@ -10443,22 +10451,22 @@ async function runSourceDisposition(input) {
|
|
|
10443
10451
|
|
|
10444
10452
|
// src/utils/source-disposal.ts
|
|
10445
10453
|
import { createHash as createHash8 } from "crypto";
|
|
10446
|
-
import { readFile as
|
|
10454
|
+
import { readFile as readFile22, unlink as unlink5 } from "fs/promises";
|
|
10447
10455
|
|
|
10448
10456
|
// src/utils/raw-asset-reference-index.ts
|
|
10449
|
-
import { readdir as
|
|
10450
|
-
import { join as
|
|
10457
|
+
import { readdir as readdir6, readFile as readFile21 } from "fs/promises";
|
|
10458
|
+
import { join as join41, relative as relative6, sep as sep4 } from "path";
|
|
10451
10459
|
var PREVIEW_EXTENSIONS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "webp", "svg", "bmp", "avif", "pdf", "mp3", "wav", "m4a", "mp4", "webm"]);
|
|
10452
10460
|
async function walkFiles(root, dir = root) {
|
|
10453
10461
|
let entries;
|
|
10454
10462
|
try {
|
|
10455
|
-
entries = await
|
|
10463
|
+
entries = await readdir6(dir, { withFileTypes: true });
|
|
10456
10464
|
} catch {
|
|
10457
10465
|
return [];
|
|
10458
10466
|
}
|
|
10459
10467
|
const out = [];
|
|
10460
10468
|
for (const entry of entries) {
|
|
10461
|
-
const path =
|
|
10469
|
+
const path = join41(dir, entry.name);
|
|
10462
10470
|
if (entry.isDirectory()) out.push(...await walkFiles(root, path));
|
|
10463
10471
|
else if (entry.isFile()) out.push(relative6(root, path).split(sep4).join("/"));
|
|
10464
10472
|
}
|
|
@@ -10474,7 +10482,7 @@ function addInbound(map, target, source) {
|
|
|
10474
10482
|
map.set(target, refs);
|
|
10475
10483
|
}
|
|
10476
10484
|
async function buildRawAssetReferenceIndex(vault) {
|
|
10477
|
-
const assetRoot =
|
|
10485
|
+
const assetRoot = join41(vault, "raw", "assets");
|
|
10478
10486
|
const relativeAssets = await walkFiles(assetRoot);
|
|
10479
10487
|
const assets = relativeAssets.map((path) => `raw/assets/${path}`).sort((a, b) => a.localeCompare(b));
|
|
10480
10488
|
const assetSet = new Set(assets);
|
|
@@ -10490,7 +10498,7 @@ async function buildRawAssetReferenceIndex(vault) {
|
|
|
10490
10498
|
for (const page of scan.data.allMarkdown) {
|
|
10491
10499
|
let text;
|
|
10492
10500
|
try {
|
|
10493
|
-
text = await
|
|
10501
|
+
text = await readFile21(page.absPath, "utf8");
|
|
10494
10502
|
} catch {
|
|
10495
10503
|
continue;
|
|
10496
10504
|
}
|
|
@@ -10550,7 +10558,7 @@ async function planSourceDisposal(input) {
|
|
|
10550
10558
|
if (sensitive.length > 0) return err("SENSITIVE_CONTENT_DETECTED", { findings: sensitive });
|
|
10551
10559
|
const target = await resolveExistingRegularFileInsideVault(input.vault, input.rawPath);
|
|
10552
10560
|
if (!target.ok) return err("RAW_DISPOSAL_TARGET_INVALID", { path: input.rawPath, cause: target });
|
|
10553
|
-
const bytes = await
|
|
10561
|
+
const bytes = await readFile22(target.data);
|
|
10554
10562
|
const size = bytes.byteLength;
|
|
10555
10563
|
let typedReferences = [];
|
|
10556
10564
|
let otherReferences = [];
|
|
@@ -10674,7 +10682,7 @@ async function runSourceDisposal(input) {
|
|
|
10674
10682
|
import { existsSync as existsSync15, readFileSync as readFileSync16 } from "fs";
|
|
10675
10683
|
import { execSync as nodeExecSync } from "child_process";
|
|
10676
10684
|
import { hostname as nodeHostname, platform as nodePlatform } from "os";
|
|
10677
|
-
import { join as
|
|
10685
|
+
import { join as join42 } from "path";
|
|
10678
10686
|
var SSH_TIMEOUT_MS = 15e3;
|
|
10679
10687
|
var TIMER_UNIT = "agent-memory-trends.timer";
|
|
10680
10688
|
var SERVICE_UNIT = "agent-memory-trends.service";
|
|
@@ -10904,7 +10912,7 @@ async function runFleetHealth(input) {
|
|
|
10904
10912
|
const home = resolveSkillwikiHome(input.home, env);
|
|
10905
10913
|
const osHostname = input.osHostname ?? env.HOSTNAME ?? nodeHostname();
|
|
10906
10914
|
const vault = input.vault ?? env.WIKI_PATH;
|
|
10907
|
-
const file = input.file ?? (vault ?
|
|
10915
|
+
const file = input.file ?? (vault ? join42(vault, FLEET_REL_PATH) : void 0);
|
|
10908
10916
|
if (!file) {
|
|
10909
10917
|
return {
|
|
10910
10918
|
exitCode: ExitCode.NO_VAULT_CONFIGURED,
|
|
@@ -10989,7 +10997,7 @@ async function runFleetHealth(input) {
|
|
|
10989
10997
|
|
|
10990
10998
|
// src/utils/auto-commit.ts
|
|
10991
10999
|
import { existsSync as existsSync16 } from "fs";
|
|
10992
|
-
import { isAbsolute as isAbsolute3, join as
|
|
11000
|
+
import { isAbsolute as isAbsolute3, join as join43, normalize } from "path";
|
|
10993
11001
|
function isValidLastOpPath(file) {
|
|
10994
11002
|
if (!file || typeof file !== "string") return false;
|
|
10995
11003
|
const trimmed = file.trim();
|
|
@@ -11010,7 +11018,7 @@ async function postCommit(vault, exitCode) {
|
|
|
11010
11018
|
const dotenv = await parseDotenvFile(configPath(home));
|
|
11011
11019
|
const autoCommit = process.env.AUTO_COMMIT ?? dotenv["AUTO_COMMIT"];
|
|
11012
11020
|
if (autoCommit === "false") return;
|
|
11013
|
-
if (!existsSync16(
|
|
11021
|
+
if (!existsSync16(join43(vault, ".git"))) return;
|
|
11014
11022
|
const lastOps = readLastOp(vault);
|
|
11015
11023
|
if (lastOps.length === 0) return;
|
|
11016
11024
|
const porcelain = git(vault, ["status", "--porcelain", "--", ...VAULT_COMMIT_PATHSPEC]);
|
|
@@ -11058,8 +11066,8 @@ function preflight(error) {
|
|
|
11058
11066
|
}
|
|
11059
11067
|
async function runMcpAuthIssueHost(input) {
|
|
11060
11068
|
const isTty = input.isTty ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
11061
|
-
const
|
|
11062
|
-
const
|
|
11069
|
+
const readFile23 = input.readFile ?? readFileSync17;
|
|
11070
|
+
const writeFile9 = input.writeFile ?? writeFileSync8;
|
|
11063
11071
|
const stderrWrite = input.stderrWrite ?? ((s) => {
|
|
11064
11072
|
process.stderr.write(s);
|
|
11065
11073
|
});
|
|
@@ -11073,7 +11081,7 @@ async function runMcpAuthIssueHost(input) {
|
|
|
11073
11081
|
if (write && !isTty) return preflight("NO_TTY");
|
|
11074
11082
|
let yamlText = "";
|
|
11075
11083
|
try {
|
|
11076
|
-
yamlText =
|
|
11084
|
+
yamlText = readFile23(mapPath, "utf8");
|
|
11077
11085
|
} catch (error) {
|
|
11078
11086
|
if (!isEnoent(error)) throw error;
|
|
11079
11087
|
}
|
|
@@ -11095,7 +11103,7 @@ async function runMcpAuthIssueHost(input) {
|
|
|
11095
11103
|
const appended = appendHostHash(yamlText, hashHex, hostId, granted.vaults);
|
|
11096
11104
|
if ("error" in appended) return preflight(appended.error);
|
|
11097
11105
|
try {
|
|
11098
|
-
|
|
11106
|
+
writeFile9(mapPath, appended.yaml, { encoding: "utf8", mode: 416 });
|
|
11099
11107
|
} catch (error) {
|
|
11100
11108
|
if (isEnoent(error)) {
|
|
11101
11109
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND") };
|
|
@@ -11255,7 +11263,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
|
|
|
11255
11263
|
if (dirty) {
|
|
11256
11264
|
return emit(dirty, void 0, { postCommit: false });
|
|
11257
11265
|
}
|
|
11258
|
-
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-
|
|
11266
|
+
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-GRSHQYKC.js");
|
|
11259
11267
|
const run = await runManagedWriteTransaction2({
|
|
11260
11268
|
vault,
|
|
11261
11269
|
command,
|
|
@@ -11285,7 +11293,7 @@ program.command("validate <file>").description("validate vault page frontmatter
|
|
|
11285
11293
|
emit(await runValidate({ file, apply: !!opts.apply, vault }), vault);
|
|
11286
11294
|
});
|
|
11287
11295
|
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) => {
|
|
11288
|
-
const out = opts.out ??
|
|
11296
|
+
const out = opts.out ?? join44(vault, ".skillwiki", "graph.json");
|
|
11289
11297
|
return emitGuardedVaultWrite(vault, "graph build", () => runGraphBuild({ vault, out }));
|
|
11290
11298
|
});
|
|
11291
11299
|
var canvasCmd = program.command("canvas").description("manage Obsidian canvas files");
|
|
@@ -11901,6 +11909,8 @@ program.command("doctor").description("diagnose skillwiki setup issues").option(
|
|
|
11901
11909
|
})));
|
|
11902
11910
|
var clipOutboxCmd = program.command("clip-outbox").description("dedicated file-level web-clip outbox");
|
|
11903
11911
|
clipOutboxCmd.command("status").description("show whether the clip-outbox channel is configured").action(async () => emit(await runClipOutboxStatus(resolveSkillwikiHome())));
|
|
11912
|
+
clipOutboxCmd.command("watch").description("run the enabled dedicated outbox worker using macOS FSEvents").action(async () => emit(await runClipOutboxWatch(resolveSkillwikiHome())));
|
|
11913
|
+
clipOutboxCmd.command("install-or-migrate").description("refresh the packaged launchd plist without enabling the channel").option("--load", "attended launchd bootstrap; requires existing enabled=true", false).option("--conditional-create-proven", "attest the deployed SeaweedFS If-None-Match:* race test passed", false).action(async (opts) => emit(await runClipOutboxInstall({ home: resolveSkillwikiHome(), load: opts.load, conditionalCreateProven: opts.conditionalCreateProven })));
|
|
11904
11914
|
program.command("connect").description(CONNECT_DESCRIPTION).option("--from-file <path>", "chat-attached env file (not Drive / \u4E91\u76D8)").option("--from-stdin", "read env file from stdin (no echo)").option("--dry-run", "validate without writing ~/.skillwiki/.env").option("--force", "overwrite a different existing token").action(async (opts) => emit(await runConnect({
|
|
11905
11915
|
home: resolveSkillwikiHome(),
|
|
11906
11916
|
fromFile: opts.fromFile,
|