skillwiki 0.10.110 → 0.10.112
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-25OXNFDV.js +133 -0
- package/dist/{chunk-R2DJ7IJ5.js → chunk-7POLZOFY.js} +44 -375
- package/dist/chunk-ABRYBO4T.js +275 -0
- package/dist/{chunk-6X6PPQNI.js → chunk-APKDTEVV.js} +280 -446
- package/dist/{chunk-5MV5SSRM.js → chunk-CKQPUHM2.js} +5 -3
- package/dist/chunk-DOHWNPAZ.js +60 -0
- package/dist/chunk-EE7W3GLA.js +55 -0
- package/dist/chunk-FCA3RRNF.js +60 -0
- package/dist/{chunk-KX5Y3GSX.js → chunk-IR2DI4Y5.js} +5 -3
- package/dist/chunk-K3M6OSUW.js +77 -0
- package/dist/{chunk-WPJHDRTP.js → chunk-KJG2CSYD.js} +12 -57
- package/dist/chunk-LOVLZNLX.js +111 -0
- package/dist/chunk-OSL4J7GF.js +32 -0
- package/dist/{chunk-QU2CKXM4.js → chunk-Q6EZF37H.js} +91 -199
- package/dist/chunk-QESNTTVY.js +50 -0
- package/dist/{chunk-NA3TZ4JN.js → chunk-RR6VDWSI.js} +8 -6
- package/dist/chunk-SKOLE6US.js +126 -0
- package/dist/chunk-TKX6PSWZ.js +344 -0
- package/dist/chunk-ZRGZBAVS.js +98 -0
- package/dist/cli.js +359 -305
- package/dist/{index-projection-6XGESSHV.js → index-projection-UNZG5UJZ.js} +5 -3
- package/dist/journal-5IW3TZ5F.js +13 -0
- package/dist/{managed-write-preflight-JPOBVVSU.js → managed-write-preflight-L7IRQ76C.js} +7 -4
- package/dist/mcp-auth-env-X5MI5IX6.js +25 -0
- package/dist/migrate-RO4BJP5T.js +22 -0
- package/dist/mirror-H5BTBAON.js +151 -0
- package/dist/ready-S7F53Q2D.js +9 -0
- package/dist/runtime-VMFYW2K3.js +20 -0
- package/dist/skillwiki-mcp.js +14 -7
- package/dist/sources-AOYP6ROO.js +10 -0
- package/dist/upload-HTE62TOV.js +14 -0
- package/dist/watcher-MGHQD3UI.js +526 -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/skills/skills/using-skillwiki/SKILL.md +1 -1
- package/skills/skills/wiki-init/SKILL.md +3 -0
- package/skills/using-skillwiki/SKILL.md +1 -1
- package/skills/wiki-init/SKILL.md +3 -0
- package/templates/launchd/com.karlchow.skillwiki-clip-outbox.plist +12 -13
- package/templates/launchd/com.karlchow.skillwiki-mirror-sse.plist +20 -0
- package/dist/sources-CLOF5VAT.js +0 -9
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
buildDeleteIntent,
|
|
4
|
+
normalizeVaultRelPath,
|
|
5
|
+
pathToIntentFilename,
|
|
6
|
+
writeDeleteIntent
|
|
7
|
+
} from "./chunk-QESNTTVY.js";
|
|
2
8
|
import {
|
|
3
9
|
CAPTURE_HYGIENE_CONTRACT,
|
|
4
|
-
CLIP_NOT_CONFIGURED,
|
|
5
10
|
DEFAULT_CAPTURE_BUDGET,
|
|
6
11
|
DEFAULT_DIRTY_VOLUME_THRESHOLD,
|
|
7
12
|
DEFAULT_MCP_URL,
|
|
8
13
|
DEFAULT_NO_DECISION_STREAK,
|
|
9
14
|
GateError,
|
|
10
|
-
MCP_HOST_ID_ENV,
|
|
11
|
-
MCP_TOKEN_ENV,
|
|
12
|
-
MCP_URL_ENV,
|
|
13
15
|
PUSH_NOT_IN_PROFILE,
|
|
14
16
|
SATELLITE_STALE_MS,
|
|
15
17
|
buildVectorIndex,
|
|
@@ -22,18 +24,13 @@ import {
|
|
|
22
24
|
guardProtectedVaultWrite,
|
|
23
25
|
isEventLedgerPath,
|
|
24
26
|
isFailedRunStatus,
|
|
25
|
-
loadClipOutboxConfig,
|
|
26
|
-
mcpAuthFromEnv,
|
|
27
27
|
measureDirtyVolume,
|
|
28
28
|
memoryAuthorityTiersRank,
|
|
29
|
-
mergeMcpAuthIntoEnv,
|
|
30
|
-
nonEmptyEnvValue,
|
|
31
29
|
pruneVectorIndex,
|
|
32
30
|
readCliPackageJson,
|
|
33
31
|
readSatelliteLatestRunAt,
|
|
34
32
|
readSatelliteLatestRunFromText,
|
|
35
33
|
readVaultSyncConfig,
|
|
36
|
-
redactMcpSecret,
|
|
37
34
|
reindexPageInVectorIndex,
|
|
38
35
|
renderIndexUpsert,
|
|
39
36
|
renderProjectIndex,
|
|
@@ -67,7 +64,15 @@ import {
|
|
|
67
64
|
upsertIndexEntry,
|
|
68
65
|
vectorIndexStatus,
|
|
69
66
|
withMcpClient
|
|
70
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-APKDTEVV.js";
|
|
68
|
+
import {
|
|
69
|
+
applySourceDisposition,
|
|
70
|
+
decodeSourceActionApproval,
|
|
71
|
+
encodeSourceActionApproval,
|
|
72
|
+
inventorySources,
|
|
73
|
+
planSourceDisposition,
|
|
74
|
+
runSourcesPending
|
|
75
|
+
} from "./chunk-RR6VDWSI.js";
|
|
71
76
|
import {
|
|
72
77
|
normalizeDistTag,
|
|
73
78
|
readCache,
|
|
@@ -80,7 +85,7 @@ import {
|
|
|
80
85
|
UNMANAGED_START,
|
|
81
86
|
renderRootIndex,
|
|
82
87
|
writeRootIndexProjection
|
|
83
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-IR2DI4Y5.js";
|
|
84
89
|
import {
|
|
85
90
|
FLEET_REL_PATH,
|
|
86
91
|
REDACTED_MALFORMED_REFERENCE,
|
|
@@ -120,13 +125,10 @@ import {
|
|
|
120
125
|
normalizeProjectSlug,
|
|
121
126
|
normalizeRemoteRoot,
|
|
122
127
|
parseActiveWorkPath,
|
|
123
|
-
parseDotenvFile,
|
|
124
|
-
parseDotenvText,
|
|
125
128
|
parseJournalEnv,
|
|
126
129
|
planAndMaybePruneRemoteObjects,
|
|
127
130
|
planRawStructuralMove,
|
|
128
131
|
probeS3Reachability,
|
|
129
|
-
profileKey,
|
|
130
132
|
readJournal,
|
|
131
133
|
readLastOp,
|
|
132
134
|
readSkillWikiConfig,
|
|
@@ -137,7 +139,6 @@ import {
|
|
|
137
139
|
resolveFleetHostId,
|
|
138
140
|
resolveInitTimePath,
|
|
139
141
|
resolveRuntimePath,
|
|
140
|
-
resolveSkillwikiHome,
|
|
141
142
|
resolveWikiS3Remote,
|
|
142
143
|
rewriteRawSourceReferences,
|
|
143
144
|
runAudit,
|
|
@@ -171,22 +172,8 @@ import {
|
|
|
171
172
|
snapshotterAliasForLocalHost,
|
|
172
173
|
stageVaultContentChanges,
|
|
173
174
|
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";
|
|
175
|
+
taxonomyCommentForPage
|
|
176
|
+
} from "./chunk-Q6EZF37H.js";
|
|
190
177
|
import {
|
|
191
178
|
authorizeRawOperation,
|
|
192
179
|
buildSourceReferenceIndex,
|
|
@@ -203,31 +190,67 @@ import {
|
|
|
203
190
|
resolveExistingRegularFileInsideVault,
|
|
204
191
|
validateLogEvent,
|
|
205
192
|
writeLogEvent
|
|
206
|
-
} from "./chunk-
|
|
193
|
+
} from "./chunk-CKQPUHM2.js";
|
|
194
|
+
import {
|
|
195
|
+
assertTargetInsideVault,
|
|
196
|
+
prepareTypedPage
|
|
197
|
+
} from "./chunk-KJG2CSYD.js";
|
|
207
198
|
import {
|
|
208
|
-
ExitCode,
|
|
209
|
-
MetaSchema,
|
|
210
|
-
RawSourceSchema,
|
|
211
|
-
TypedKnowledgeSchema,
|
|
212
|
-
detectSchema,
|
|
213
|
-
err,
|
|
214
199
|
extractFrontmatter,
|
|
215
|
-
isBlockedHost,
|
|
216
200
|
mapWithConcurrency,
|
|
217
|
-
ok,
|
|
218
201
|
readPage,
|
|
219
202
|
readPageCached,
|
|
220
203
|
redactSensitiveContent,
|
|
221
204
|
resolveReadOnlyVaultRoot,
|
|
222
|
-
resolveSessionKind,
|
|
223
205
|
scanSensitiveContent,
|
|
224
206
|
scanVault,
|
|
225
207
|
splitFrontmatter,
|
|
226
208
|
vaultIoConcurrency
|
|
227
|
-
} from "./chunk-
|
|
209
|
+
} from "./chunk-TKX6PSWZ.js";
|
|
210
|
+
import {
|
|
211
|
+
MCP_HOST_ID_ENV,
|
|
212
|
+
MCP_TOKEN_ENV,
|
|
213
|
+
MCP_URL_ENV,
|
|
214
|
+
mcpAuthFromEnv,
|
|
215
|
+
mergeMcpAuthIntoEnv,
|
|
216
|
+
nonEmptyEnvValue,
|
|
217
|
+
redactMcpSecret
|
|
218
|
+
} from "./chunk-DOHWNPAZ.js";
|
|
219
|
+
import {
|
|
220
|
+
CLIP_MIGRATION_HINT,
|
|
221
|
+
refreshInstalledClipPlist
|
|
222
|
+
} from "./chunk-25OXNFDV.js";
|
|
223
|
+
import {
|
|
224
|
+
atomicWriteText
|
|
225
|
+
} from "./chunk-EE7W3GLA.js";
|
|
226
|
+
import {
|
|
227
|
+
CLIP_NOT_CONFIGURED,
|
|
228
|
+
loadClipOutboxConfig
|
|
229
|
+
} from "./chunk-ABRYBO4T.js";
|
|
230
|
+
import {
|
|
231
|
+
runFetchGuard,
|
|
232
|
+
runFetchGuardSync
|
|
233
|
+
} from "./chunk-LOVLZNLX.js";
|
|
234
|
+
import {
|
|
235
|
+
parseDotenvFile,
|
|
236
|
+
parseDotenvText,
|
|
237
|
+
profileKey,
|
|
238
|
+
resolveSkillwikiHome,
|
|
239
|
+
writeDotenv
|
|
240
|
+
} from "./chunk-SKOLE6US.js";
|
|
241
|
+
import {
|
|
242
|
+
ExitCode,
|
|
243
|
+
MetaSchema,
|
|
244
|
+
RawSourceSchema,
|
|
245
|
+
TypedKnowledgeSchema,
|
|
246
|
+
detectSchema,
|
|
247
|
+
err,
|
|
248
|
+
ok,
|
|
249
|
+
resolveSessionKind
|
|
250
|
+
} from "./chunk-7POLZOFY.js";
|
|
228
251
|
|
|
229
252
|
// src/cli.ts
|
|
230
|
-
import { join as
|
|
253
|
+
import { join as join44 } from "path";
|
|
231
254
|
import { Command } from "commander";
|
|
232
255
|
|
|
233
256
|
// src/utils/output.ts
|
|
@@ -343,48 +366,6 @@ async function runHash(input) {
|
|
|
343
366
|
};
|
|
344
367
|
}
|
|
345
368
|
|
|
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
369
|
// src/commands/eval.ts
|
|
389
370
|
import { execFileSync } from "child_process";
|
|
390
371
|
import { existsSync, mkdtempSync, rmSync } from "fs";
|
|
@@ -3604,14 +3585,117 @@ async function runClipOutboxStatus(home) {
|
|
|
3604
3585
|
result: ok({ enabled: false, humanHint: CLIP_NOT_CONFIGURED })
|
|
3605
3586
|
};
|
|
3606
3587
|
}
|
|
3588
|
+
const { readJournal: readJournal2 } = await import("./journal-5IW3TZ5F.js");
|
|
3589
|
+
let queue;
|
|
3590
|
+
try {
|
|
3591
|
+
queue = (await readJournal2(resolved.config.stateRoot)).map(({ captureId, state, reason, attempts }) => ({ captureId, state, reason, attempts }));
|
|
3592
|
+
} catch {
|
|
3593
|
+
return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "clip journal unreadable; retain it for attended recovery" }) };
|
|
3594
|
+
}
|
|
3607
3595
|
return {
|
|
3608
3596
|
exitCode: ExitCode.OK,
|
|
3609
3597
|
result: ok({
|
|
3610
3598
|
enabled: true,
|
|
3611
|
-
|
|
3599
|
+
queue,
|
|
3600
|
+
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
3601
|
})
|
|
3613
3602
|
};
|
|
3614
3603
|
}
|
|
3604
|
+
async function runClipOutboxInstall(input) {
|
|
3605
|
+
try {
|
|
3606
|
+
const { migrateClipOutbox } = await import("./migrate-RO4BJP5T.js");
|
|
3607
|
+
return { exitCode: ExitCode.OK, result: ok(await migrateClipOutbox(input)) };
|
|
3608
|
+
} catch (e) {
|
|
3609
|
+
return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: e instanceof Error ? e.message : "clip migration failed" }) };
|
|
3610
|
+
}
|
|
3611
|
+
}
|
|
3612
|
+
async function runClipOutboxWatch(home) {
|
|
3613
|
+
const resolved = await loadClipOutboxConfig(home);
|
|
3614
|
+
if (!resolved.ok || !resolved.enabled) return { exitCode: ExitCode.INVALID_CONFIG_VALUE, result: err("INVALID_CONFIG_VALUE", { message: resolved.ok ? CLIP_NOT_CONFIGURED : resolved.message }) };
|
|
3615
|
+
if (process.platform !== "darwin") return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "clip-outbox watch requires macOS FSEvents" }) };
|
|
3616
|
+
let client;
|
|
3617
|
+
try {
|
|
3618
|
+
const { S3Client: S3Client3 } = await import("@aws-sdk/client-s3");
|
|
3619
|
+
const { loadClipCredentials, validateRuntime } = await import("./runtime-VMFYW2K3.js");
|
|
3620
|
+
const { createS3CreateOnlyPut, parseDestination } = await import("./upload-HTE62TOV.js");
|
|
3621
|
+
const { postReadyHint } = await import("./ready-S7F53Q2D.js");
|
|
3622
|
+
const { startClipWorker } = await import("./watcher-MGHQD3UI.js");
|
|
3623
|
+
const cfg = resolved.config;
|
|
3624
|
+
const credentials = await loadClipCredentials(home, cfg);
|
|
3625
|
+
await validateRuntime(home, cfg, credentials.s3.endpoint);
|
|
3626
|
+
const destination = parseDestination(cfg.destination);
|
|
3627
|
+
client = new S3Client3({ endpoint: credentials.s3.endpoint, region: credentials.s3.region, credentials: credentials.s3, forcePathStyle: true, maxAttempts: 1 });
|
|
3628
|
+
let finish;
|
|
3629
|
+
const done = new Promise((r) => {
|
|
3630
|
+
finish = r;
|
|
3631
|
+
});
|
|
3632
|
+
let failed = false;
|
|
3633
|
+
const worker = await startClipWorker(cfg, {
|
|
3634
|
+
put: createS3CreateOnlyPut({ client, bucket: destination.bucket, prefix: destination.prefix }),
|
|
3635
|
+
ready: (hint) => postReadyHint({ url: cfg.readyUrl, token: credentials.readyToken, hint }),
|
|
3636
|
+
validate: () => validateRuntime(home, cfg, credentials.s3.endpoint),
|
|
3637
|
+
onError: () => {
|
|
3638
|
+
failed = true;
|
|
3639
|
+
finish();
|
|
3640
|
+
}
|
|
3641
|
+
});
|
|
3642
|
+
process.once("SIGTERM", finish);
|
|
3643
|
+
process.once("SIGINT", finish);
|
|
3644
|
+
try {
|
|
3645
|
+
await done;
|
|
3646
|
+
} finally {
|
|
3647
|
+
process.removeListener("SIGTERM", finish);
|
|
3648
|
+
process.removeListener("SIGINT", finish);
|
|
3649
|
+
await worker.stop();
|
|
3650
|
+
}
|
|
3651
|
+
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." }) };
|
|
3652
|
+
} catch {
|
|
3653
|
+
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" }) };
|
|
3654
|
+
} finally {
|
|
3655
|
+
client?.destroy();
|
|
3656
|
+
}
|
|
3657
|
+
}
|
|
3658
|
+
async function runClipOutboxMirrorWatch(home) {
|
|
3659
|
+
const resolved = await loadClipOutboxConfig(home);
|
|
3660
|
+
if (!resolved.ok || !resolved.enabled) return { exitCode: ExitCode.INVALID_CONFIG_VALUE, result: err("INVALID_CONFIG_VALUE", { message: resolved.ok ? CLIP_NOT_CONFIGURED : resolved.message }) };
|
|
3661
|
+
let client;
|
|
3662
|
+
const abort = new AbortController();
|
|
3663
|
+
try {
|
|
3664
|
+
const { S3Client: S3Client3 } = await import("@aws-sdk/client-s3");
|
|
3665
|
+
const { loadClipCredentials, validateRuntime } = await import("./runtime-VMFYW2K3.js");
|
|
3666
|
+
const { createS3GetObject, eventsUrlFromMcp, parseDestinationForMirror, startMirrorListener } = await import("./mirror-H5BTBAON.js");
|
|
3667
|
+
const { resolveMcpAuthEnv } = await import("./mcp-auth-env-X5MI5IX6.js");
|
|
3668
|
+
const cfg = resolved.config;
|
|
3669
|
+
const credentials = await loadClipCredentials(home, cfg);
|
|
3670
|
+
await validateRuntime(home, cfg, credentials.s3.endpoint);
|
|
3671
|
+
const auth = await resolveMcpAuthEnv({ home });
|
|
3672
|
+
if (!auth.url || !auth.token) throw new Error("MCP bearer required for inbound SSE");
|
|
3673
|
+
const destination = parseDestinationForMirror(cfg.destination);
|
|
3674
|
+
client = new S3Client3({ endpoint: credentials.s3.endpoint, region: credentials.s3.region, credentials: credentials.s3, forcePathStyle: true, maxAttempts: 1 });
|
|
3675
|
+
const done = new Promise((resolve9) => {
|
|
3676
|
+
abort.signal.addEventListener("abort", () => resolve9(), { once: true });
|
|
3677
|
+
});
|
|
3678
|
+
process.once("SIGTERM", () => abort.abort());
|
|
3679
|
+
process.once("SIGINT", () => abort.abort());
|
|
3680
|
+
await Promise.race([
|
|
3681
|
+
startMirrorListener({
|
|
3682
|
+
home,
|
|
3683
|
+
config: cfg,
|
|
3684
|
+
eventsUrl: eventsUrlFromMcp(auth.url),
|
|
3685
|
+
mcpToken: auth.token,
|
|
3686
|
+
getObject: createS3GetObject({ client, bucket: destination.bucket, prefix: destination.prefix, maxBytes: cfg.maxBundleBytes }),
|
|
3687
|
+
signal: abort.signal
|
|
3688
|
+
}),
|
|
3689
|
+
done
|
|
3690
|
+
]);
|
|
3691
|
+
return { exitCode: ExitCode.OK, result: ok({ humanHint: "Inbound SSE listener stopped." }) };
|
|
3692
|
+
} catch {
|
|
3693
|
+
return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "inbound SSE listener startup failed; check MCP bearer, clip credentials, frozen mirror and wiki-push isolation" }) };
|
|
3694
|
+
} finally {
|
|
3695
|
+
abort.abort();
|
|
3696
|
+
client?.destroy();
|
|
3697
|
+
}
|
|
3698
|
+
}
|
|
3615
3699
|
|
|
3616
3700
|
// src/commands/connect.ts
|
|
3617
3701
|
import { chmod, mkdir as mkdir5, readFile as readFile6, stat as stat3 } from "fs/promises";
|
|
@@ -3922,50 +4006,8 @@ async function runConnect(input) {
|
|
|
3922
4006
|
}
|
|
3923
4007
|
|
|
3924
4008
|
// 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
|
|
4009
|
+
import { rename as rename2, mkdir as mkdir6, readFile as readFile7 } from "fs/promises";
|
|
4010
|
+
import { join as join19, dirname as dirname5 } from "path";
|
|
3969
4011
|
function countWikilinks(body, slug) {
|
|
3970
4012
|
const escaped = slug.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3971
4013
|
const re = new RegExp(`\\[\\[${escaped}(?:[|#][^\\]]*)?\\]\\]`, "g");
|
|
@@ -4001,7 +4043,7 @@ async function runArchive(input) {
|
|
|
4001
4043
|
const slug = relPath.replace(/\.md$/, "").split("/").pop();
|
|
4002
4044
|
const rawArchive = isRaw ? lifecycleDestination(relPath, "archive") : void 0;
|
|
4003
4045
|
if (rawArchive && !rawArchive.ok) return { exitCode: ExitCode.USAGE, result: rawArchive };
|
|
4004
|
-
const archivePath = isRaw ? rawArchive.data :
|
|
4046
|
+
const archivePath = isRaw ? rawArchive.data : join19("_archive", relPath).replace(/\\/g, "/");
|
|
4005
4047
|
const remoteRoot = normalizeRemoteRoot(input.remote);
|
|
4006
4048
|
const remoteObjectPath = buildRemoteObjectPath(remoteRoot, relPath);
|
|
4007
4049
|
let cascade;
|
|
@@ -4031,7 +4073,7 @@ async function runArchive(input) {
|
|
|
4031
4073
|
const indexRefs = [];
|
|
4032
4074
|
if (!isRaw) {
|
|
4033
4075
|
try {
|
|
4034
|
-
const idx = await
|
|
4076
|
+
const idx = await readFile7(join19(input.vault, "index.md"), "utf8");
|
|
4035
4077
|
idx.split("\n").forEach((line, i) => {
|
|
4036
4078
|
if (line.includes(`[[${slug}]]`)) indexRefs.push({ line: i + 1, text: line });
|
|
4037
4079
|
});
|
|
@@ -4089,8 +4131,8 @@ async function runArchive(input) {
|
|
|
4089
4131
|
const rewrittenCascadePages = [];
|
|
4090
4132
|
if ((input.cascade || isRaw) && input.apply && cascade) {
|
|
4091
4133
|
for (const ref of cascade.source_array_refs) {
|
|
4092
|
-
const absPath =
|
|
4093
|
-
const text = await
|
|
4134
|
+
const absPath = join19(input.vault, ref.page);
|
|
4135
|
+
const text = await readFile7(absPath, "utf8");
|
|
4094
4136
|
if (!arraysEqual(ref.sources_after, ref.sources_before)) {
|
|
4095
4137
|
let updated;
|
|
4096
4138
|
if (isRaw) {
|
|
@@ -4116,8 +4158,8 @@ ${fmRewritten}
|
|
|
4116
4158
|
if (isRaw) {
|
|
4117
4159
|
for (const ref of cascade.citation_refs) {
|
|
4118
4160
|
if (cascade.source_array_refs.some((sourceRef) => sourceRef.page === ref.page)) continue;
|
|
4119
|
-
const absPath =
|
|
4120
|
-
const original = await
|
|
4161
|
+
const absPath = join19(input.vault, ref.page);
|
|
4162
|
+
const original = await readFile7(absPath, "utf8");
|
|
4121
4163
|
const updated = rewriteRawSourceReferences(original, relPath, archivePath).text;
|
|
4122
4164
|
if (updated !== original) {
|
|
4123
4165
|
const write = await safeWritePage(absPath, updated);
|
|
@@ -4128,13 +4170,13 @@ ${fmRewritten}
|
|
|
4128
4170
|
}
|
|
4129
4171
|
}
|
|
4130
4172
|
if (!isRaw) {
|
|
4131
|
-
await
|
|
4132
|
-
await rename2(
|
|
4173
|
+
await mkdir6(dirname5(join19(input.vault, archivePath)), { recursive: true });
|
|
4174
|
+
await rename2(join19(input.vault, relPath), join19(input.vault, archivePath));
|
|
4133
4175
|
}
|
|
4134
4176
|
let indexUpdated = false;
|
|
4135
4177
|
if (!isRaw) {
|
|
4136
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
4137
|
-
const before = await
|
|
4178
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-UNZG5UJZ.js");
|
|
4179
|
+
const before = await readFile7(join19(input.vault, "index.md"), "utf8").catch(() => "");
|
|
4138
4180
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
4139
4181
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
|
4140
4182
|
const hadIndexEntry = before.includes(`[[${fullTarget}]]`) || before.includes(`[[${bare}]]`);
|
|
@@ -4188,7 +4230,7 @@ ${fmRewritten}
|
|
|
4188
4230
|
|
|
4189
4231
|
// src/commands/remove.ts
|
|
4190
4232
|
import { unlink as unlink2, access } from "fs/promises";
|
|
4191
|
-
import { join as
|
|
4233
|
+
import { join as join20 } from "path";
|
|
4192
4234
|
async function pathExists(abs) {
|
|
4193
4235
|
try {
|
|
4194
4236
|
await access(abs);
|
|
@@ -4214,7 +4256,7 @@ async function runRemove(input) {
|
|
|
4214
4256
|
if (!relPath) {
|
|
4215
4257
|
try {
|
|
4216
4258
|
const candidate = normalizeVaultRelPath(input.page);
|
|
4217
|
-
if (await pathExists(
|
|
4259
|
+
if (await pathExists(join20(input.vault, candidate))) {
|
|
4218
4260
|
relPath = candidate;
|
|
4219
4261
|
}
|
|
4220
4262
|
} catch {
|
|
@@ -4252,12 +4294,12 @@ async function runRemove(input) {
|
|
|
4252
4294
|
reason: input.reason
|
|
4253
4295
|
});
|
|
4254
4296
|
const tombstonePath = await writeDeleteIntent(input.vault, intent);
|
|
4255
|
-
await unlink2(
|
|
4297
|
+
await unlink2(join20(input.vault, relPath));
|
|
4256
4298
|
if (relPath.endsWith(".md") && !relPath.startsWith("raw/")) {
|
|
4257
|
-
const { readFile:
|
|
4299
|
+
const { readFile: readFile23 } = await import("fs/promises");
|
|
4258
4300
|
const { join: pathJoin } = await import("path");
|
|
4259
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
4260
|
-
const before = await
|
|
4301
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-UNZG5UJZ.js");
|
|
4302
|
+
const before = await readFile23(pathJoin(input.vault, "index.md"), "utf8").catch(() => "");
|
|
4261
4303
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
4262
4304
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
|
4263
4305
|
const hadIndexEntry = before.includes(`[[${fullTarget}]]`) || before.includes(`[[${bare}]]`);
|
|
@@ -4606,7 +4648,7 @@ ${migratedBody}${newFooter}`;
|
|
|
4606
4648
|
|
|
4607
4649
|
// src/commands/update.ts
|
|
4608
4650
|
import { execSync } from "child_process";
|
|
4609
|
-
import { join as
|
|
4651
|
+
import { join as join21 } from "path";
|
|
4610
4652
|
function parseCoreSemver(version) {
|
|
4611
4653
|
const m = version.match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
4612
4654
|
if (!m) return null;
|
|
@@ -4650,6 +4692,8 @@ function migrationNotesForUpgrade(previousVersion, newVersion) {
|
|
|
4650
4692
|
"- frozen-leaf hosts write via HTTP MCP only; do not local-write raw/transcripts/ or vault git"
|
|
4651
4693
|
);
|
|
4652
4694
|
}
|
|
4695
|
+
const next = parseCoreSemver(newVersion);
|
|
4696
|
+
if (next && isAtLeast(next, 0, 10, 111)) notes.push(CLIP_MIGRATION_HINT);
|
|
4653
4697
|
return notes;
|
|
4654
4698
|
}
|
|
4655
4699
|
function resolveGlobalSkillsRoot() {
|
|
@@ -4658,7 +4702,7 @@ function resolveGlobalSkillsRoot() {
|
|
|
4658
4702
|
encoding: "utf8",
|
|
4659
4703
|
timeout: 5e3
|
|
4660
4704
|
}).trim();
|
|
4661
|
-
return
|
|
4705
|
+
return join21(globalRoot, "skillwiki", "skills");
|
|
4662
4706
|
} catch {
|
|
4663
4707
|
return null;
|
|
4664
4708
|
}
|
|
@@ -4686,7 +4730,7 @@ async function runUpdate(input) {
|
|
|
4686
4730
|
const pkg2 = readCliPackageJson();
|
|
4687
4731
|
const currentVersion = pkg2.version;
|
|
4688
4732
|
const tag = normalizeDistTag(input.distTag);
|
|
4689
|
-
const target =
|
|
4733
|
+
const target = join21(input.home, ".claude", "skills");
|
|
4690
4734
|
let latest;
|
|
4691
4735
|
try {
|
|
4692
4736
|
latest = execSync(`npm view skillwiki@${tag} version`, {
|
|
@@ -4719,7 +4763,8 @@ async function runUpdate(input) {
|
|
|
4719
4763
|
version_warnings: [],
|
|
4720
4764
|
skills_refreshed: false,
|
|
4721
4765
|
deferred_to_plugin: false,
|
|
4722
|
-
humanHint: `Already on npm@${tag}: v${currentVersion}
|
|
4766
|
+
humanHint: `Already on npm@${tag}: v${currentVersion}
|
|
4767
|
+
${CLIP_MIGRATION_HINT}`
|
|
4723
4768
|
})
|
|
4724
4769
|
};
|
|
4725
4770
|
}
|
|
@@ -4750,6 +4795,12 @@ async function runUpdate(input) {
|
|
|
4750
4795
|
for (const line of migrationNotesForUpgrade(currentVersion, latest)) {
|
|
4751
4796
|
hintLines.push(line);
|
|
4752
4797
|
}
|
|
4798
|
+
try {
|
|
4799
|
+
const clipHint = await refreshInstalledClipPlist(input.home);
|
|
4800
|
+
if (clipHint) hintLines.push(clipHint);
|
|
4801
|
+
} catch (e) {
|
|
4802
|
+
hintLines.push(`clip plist refresh skipped: ${e instanceof Error ? e.message : "migration failed"}`);
|
|
4803
|
+
}
|
|
4753
4804
|
return {
|
|
4754
4805
|
exitCode: ExitCode.OK,
|
|
4755
4806
|
result: ok({
|
|
@@ -4767,13 +4818,13 @@ async function runUpdate(input) {
|
|
|
4767
4818
|
// src/commands/self-update.ts
|
|
4768
4819
|
import { execSync as execSync2 } from "child_process";
|
|
4769
4820
|
import { existsSync as existsSync8, readFileSync as readFileSync11 } from "fs";
|
|
4770
|
-
import { join as
|
|
4821
|
+
import { join as join22 } from "path";
|
|
4771
4822
|
var DEFAULT_SOURCE_ROOT_SUFFIX = "/Desktop/code/llm-wiki";
|
|
4772
4823
|
async function runSelfUpdate(input) {
|
|
4773
4824
|
const currentVersion = readCliPackageJson().version;
|
|
4774
4825
|
const sourceRoot = input.sourceRoot ?? `${input.home}${DEFAULT_SOURCE_ROOT_SUFFIX}`;
|
|
4775
4826
|
const distTag = normalizeDistTag(input.distTag);
|
|
4776
|
-
const localPkgPath =
|
|
4827
|
+
const localPkgPath = join22(sourceRoot, "packages", "cli", "package.json");
|
|
4777
4828
|
const hasLocalSource = existsSync8(localPkgPath);
|
|
4778
4829
|
if (input.check) {
|
|
4779
4830
|
let availableVersion = null;
|
|
@@ -4905,21 +4956,21 @@ async function runSelfUpdate(input) {
|
|
|
4905
4956
|
}
|
|
4906
4957
|
|
|
4907
4958
|
// src/commands/transcripts.ts
|
|
4908
|
-
import { readdir as
|
|
4909
|
-
import { join as
|
|
4959
|
+
import { readdir as readdir4, stat as stat4, readFile as readFile9 } from "fs/promises";
|
|
4960
|
+
import { join as join23 } from "path";
|
|
4910
4961
|
async function runTranscripts(input) {
|
|
4911
|
-
const dir =
|
|
4962
|
+
const dir = join23(input.vault, "raw", "transcripts");
|
|
4912
4963
|
let entries;
|
|
4913
4964
|
try {
|
|
4914
|
-
entries = await
|
|
4965
|
+
entries = await readdir4(dir, { withFileTypes: true });
|
|
4915
4966
|
} catch {
|
|
4916
4967
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: { ok: false, error: "VAULT_PATH_INVALID", detail: `raw/transcripts/ not found: ${dir}` } };
|
|
4917
4968
|
}
|
|
4918
4969
|
const transcripts = [];
|
|
4919
4970
|
for (const entry of entries) {
|
|
4920
4971
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
4921
|
-
const filePath =
|
|
4922
|
-
const content = await
|
|
4972
|
+
const filePath = join23(dir, entry.name);
|
|
4973
|
+
const content = await readFile9(filePath, "utf8");
|
|
4923
4974
|
const fm = extractFrontmatter(content);
|
|
4924
4975
|
if (!fm.ok) continue;
|
|
4925
4976
|
const ingested = typeof fm.data.ingested === "string" ? fm.data.ingested : "";
|
|
@@ -4936,8 +4987,8 @@ async function runTranscripts(input) {
|
|
|
4936
4987
|
}
|
|
4937
4988
|
|
|
4938
4989
|
// src/commands/claims-audit.ts
|
|
4939
|
-
import { readFile as
|
|
4940
|
-
import { join as
|
|
4990
|
+
import { readFile as readFile10 } from "fs/promises";
|
|
4991
|
+
import { join as join24 } from "path";
|
|
4941
4992
|
function safeProjectPresentation(raw) {
|
|
4942
4993
|
if (safeDiagnosticValue(raw) === REDACTED_MALFORMED_REFERENCE) {
|
|
4943
4994
|
return REDACTED_MALFORMED_REFERENCE;
|
|
@@ -4977,9 +5028,9 @@ async function runClaimsAudit(input) {
|
|
|
4977
5028
|
return !input.project || slugByDir.get(relDir) === input.project;
|
|
4978
5029
|
});
|
|
4979
5030
|
const claimSourceResults = await mapWithConcurrency(scopedSpecDirs, vaultIoConcurrency(), async (relDir) => {
|
|
4980
|
-
const specPath =
|
|
5031
|
+
const specPath = join24(input.vault, relDir, "spec.md");
|
|
4981
5032
|
try {
|
|
4982
|
-
const specText = await
|
|
5033
|
+
const specText = await readFile10(specPath, "utf8");
|
|
4983
5034
|
const fm = extractFrontmatter(specText);
|
|
4984
5035
|
if (!fm.ok) return null;
|
|
4985
5036
|
return {
|
|
@@ -5073,10 +5124,10 @@ async function runClaimsAudit(input) {
|
|
|
5073
5124
|
}
|
|
5074
5125
|
|
|
5075
5126
|
// src/commands/compound.ts
|
|
5076
|
-
import { writeFile as
|
|
5077
|
-
import { join as
|
|
5127
|
+
import { writeFile as writeFile5, mkdir as mkdir7, readdir as readdir5, unlink as unlink3 } from "fs/promises";
|
|
5128
|
+
import { join as join25 } from "path";
|
|
5078
5129
|
import { existsSync as existsSync9 } from "fs";
|
|
5079
|
-
import { readFile as
|
|
5130
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
5080
5131
|
var RETRO_HEADING_RE = /^## \[(\d{4}-\d{2}-\d{2})(?:\s+[^\]]+)?\] retro \| loop cycle(?: (\d+))?: (.+)$/;
|
|
5081
5132
|
var FIELD_RE = {
|
|
5082
5133
|
improve: /^-\s+\*?\*?Improve:?\*?\*?\s*(.+)$/m,
|
|
@@ -5174,17 +5225,17 @@ function extractRetroFields(date, cycleName, block) {
|
|
|
5174
5225
|
};
|
|
5175
5226
|
}
|
|
5176
5227
|
async function runCompound(input) {
|
|
5177
|
-
const logPath =
|
|
5228
|
+
const logPath = join25(input.vault, "log.md");
|
|
5178
5229
|
let logText;
|
|
5179
5230
|
try {
|
|
5180
|
-
logText = await
|
|
5231
|
+
logText = await readFile11(logPath, "utf8");
|
|
5181
5232
|
} catch {
|
|
5182
5233
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: logPath }) };
|
|
5183
5234
|
}
|
|
5184
5235
|
const entries = parseRetroEntries(logText);
|
|
5185
5236
|
const promoted = [];
|
|
5186
5237
|
const skipped = [];
|
|
5187
|
-
const compoundDir =
|
|
5238
|
+
const compoundDir = join25(input.vault, "projects", input.project, "compound");
|
|
5188
5239
|
for (const entry of entries) {
|
|
5189
5240
|
const generalizeValue = entry.generalize.trim();
|
|
5190
5241
|
if (!/^yes/i.test(generalizeValue)) {
|
|
@@ -5192,7 +5243,7 @@ async function runCompound(input) {
|
|
|
5192
5243
|
continue;
|
|
5193
5244
|
}
|
|
5194
5245
|
const slug = slugify(entry.cycleName);
|
|
5195
|
-
const compoundPath =
|
|
5246
|
+
const compoundPath = join25(compoundDir, `${slug}.md`);
|
|
5196
5247
|
if (existsSync9(compoundPath)) {
|
|
5197
5248
|
skipped.push(entry.date);
|
|
5198
5249
|
continue;
|
|
@@ -5232,9 +5283,9 @@ async function runCompound(input) {
|
|
|
5232
5283
|
const content = frontmatter + "\n" + body;
|
|
5233
5284
|
if (!input.dryRun) {
|
|
5234
5285
|
if (!existsSync9(compoundDir)) {
|
|
5235
|
-
await
|
|
5286
|
+
await mkdir7(compoundDir, { recursive: true });
|
|
5236
5287
|
}
|
|
5237
|
-
await
|
|
5288
|
+
await writeFile5(compoundPath, content, "utf8");
|
|
5238
5289
|
}
|
|
5239
5290
|
promoted.push(`${slug}.md`);
|
|
5240
5291
|
}
|
|
@@ -5253,7 +5304,7 @@ async function runCompound(input) {
|
|
|
5253
5304
|
};
|
|
5254
5305
|
}
|
|
5255
5306
|
async function runCompoundDelete(input) {
|
|
5256
|
-
const projectDir =
|
|
5307
|
+
const projectDir = join25(input.vault, "projects", input.project);
|
|
5257
5308
|
if (!existsSync9(projectDir)) {
|
|
5258
5309
|
return {
|
|
5259
5310
|
exitCode: ExitCode.PROJECT_NOT_FOUND,
|
|
@@ -5261,7 +5312,7 @@ async function runCompoundDelete(input) {
|
|
|
5261
5312
|
};
|
|
5262
5313
|
}
|
|
5263
5314
|
const entryName = input.entry.replace(/\.md$/, "");
|
|
5264
|
-
const compoundPath =
|
|
5315
|
+
const compoundPath = join25(projectDir, "compound", `${entryName}.md`);
|
|
5265
5316
|
if (!existsSync9(compoundPath)) {
|
|
5266
5317
|
return {
|
|
5267
5318
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -5295,7 +5346,7 @@ knowledge.md regenerated`
|
|
|
5295
5346
|
};
|
|
5296
5347
|
}
|
|
5297
5348
|
async function runCompoundList(input) {
|
|
5298
|
-
const compoundDir =
|
|
5349
|
+
const compoundDir = join25(input.vault, "projects", input.project, "compound");
|
|
5299
5350
|
if (!existsSync9(compoundDir)) {
|
|
5300
5351
|
return {
|
|
5301
5352
|
exitCode: ExitCode.OK,
|
|
@@ -5310,7 +5361,7 @@ no compound directory found`
|
|
|
5310
5361
|
}
|
|
5311
5362
|
let dirents;
|
|
5312
5363
|
try {
|
|
5313
|
-
dirents = await
|
|
5364
|
+
dirents = await readdir5(compoundDir, { withFileTypes: true });
|
|
5314
5365
|
} catch {
|
|
5315
5366
|
return {
|
|
5316
5367
|
exitCode: ExitCode.OK,
|
|
@@ -5326,10 +5377,10 @@ could not read compound directory`
|
|
|
5326
5377
|
const entries = [];
|
|
5327
5378
|
for (const dirent of dirents) {
|
|
5328
5379
|
if (!dirent.isFile() || !dirent.name.endsWith(".md")) continue;
|
|
5329
|
-
const filePath =
|
|
5380
|
+
const filePath = join25(compoundDir, dirent.name);
|
|
5330
5381
|
let text;
|
|
5331
5382
|
try {
|
|
5332
|
-
text = await
|
|
5383
|
+
text = await readFile11(filePath, "utf8");
|
|
5333
5384
|
} catch {
|
|
5334
5385
|
continue;
|
|
5335
5386
|
}
|
|
@@ -5358,8 +5409,8 @@ no compound entries found`;
|
|
|
5358
5409
|
}
|
|
5359
5410
|
|
|
5360
5411
|
// src/commands/session-brief.ts
|
|
5361
|
-
import { mkdir as
|
|
5362
|
-
import { join as
|
|
5412
|
+
import { mkdir as mkdir8, readFile as readFile12, writeFile as writeFile6 } from "fs/promises";
|
|
5413
|
+
import { join as join26, relative, sep } from "path";
|
|
5363
5414
|
var MAX_WORDS = 900;
|
|
5364
5415
|
async function runSessionBrief(input) {
|
|
5365
5416
|
const { root: scanRoot } = resolveReadOnlyVaultRoot(input.vault);
|
|
@@ -5473,7 +5524,7 @@ async function resolveProject(input) {
|
|
|
5473
5524
|
const envProject = input.env?.SKILLWIKI_PROJECT;
|
|
5474
5525
|
if (envProject) return envProject;
|
|
5475
5526
|
const cwd = input.cwd ?? process.cwd();
|
|
5476
|
-
const projectDotenv = await readProjectSlug(
|
|
5527
|
+
const projectDotenv = await readProjectSlug(join26(cwd, ".skillwiki", ".env"));
|
|
5477
5528
|
if (projectDotenv) return projectDotenv;
|
|
5478
5529
|
const inferred = inferProjectFromPath(input.vault, cwd);
|
|
5479
5530
|
if (inferred) return inferred;
|
|
@@ -5482,7 +5533,7 @@ async function resolveProject(input) {
|
|
|
5482
5533
|
async function readProjectSlug(file) {
|
|
5483
5534
|
let text;
|
|
5484
5535
|
try {
|
|
5485
|
-
text = await
|
|
5536
|
+
text = await readFile12(file, "utf8");
|
|
5486
5537
|
} catch {
|
|
5487
5538
|
return void 0;
|
|
5488
5539
|
}
|
|
@@ -5573,7 +5624,7 @@ async function loadTrendPages(typedPages, pathPattern) {
|
|
|
5573
5624
|
return out;
|
|
5574
5625
|
}
|
|
5575
5626
|
async function loadSessionPins(vault, project) {
|
|
5576
|
-
const text = await readIfExists(
|
|
5627
|
+
const text = await readIfExists(join26(vault, "meta", "session-pins.md"));
|
|
5577
5628
|
if (!text) return [];
|
|
5578
5629
|
const fm = extractFrontmatter(text);
|
|
5579
5630
|
if (!fm.ok) return [];
|
|
@@ -5719,7 +5770,7 @@ function satelliteHealthWarning(health) {
|
|
|
5719
5770
|
return null;
|
|
5720
5771
|
}
|
|
5721
5772
|
async function loadHealthWarnings(vault) {
|
|
5722
|
-
const text = await readIfExists(
|
|
5773
|
+
const text = await readIfExists(join26(vault, ".skillwiki", "health.json"));
|
|
5723
5774
|
if (!text) return [];
|
|
5724
5775
|
try {
|
|
5725
5776
|
const parsed = JSON.parse(text);
|
|
@@ -5732,7 +5783,7 @@ async function loadHealthWarnings(vault) {
|
|
|
5732
5783
|
}
|
|
5733
5784
|
}
|
|
5734
5785
|
async function loadMemoryTopics(vault, project) {
|
|
5735
|
-
const text = await readIfExists(
|
|
5786
|
+
const text = await readIfExists(join26(vault, ".skillwiki", "memory", project, "topics.json"));
|
|
5736
5787
|
if (!text) return [];
|
|
5737
5788
|
try {
|
|
5738
5789
|
const parsed = JSON.parse(text);
|
|
@@ -5757,18 +5808,18 @@ async function loadMemoryTopics(vault, project) {
|
|
|
5757
5808
|
}
|
|
5758
5809
|
}
|
|
5759
5810
|
async function writeBriefArtifacts(vault, input) {
|
|
5760
|
-
const metaPath =
|
|
5761
|
-
const cacheMdPath =
|
|
5762
|
-
const cacheJsonPath =
|
|
5763
|
-
await
|
|
5764
|
-
await
|
|
5811
|
+
const metaPath = join26(vault, "meta", "latest-session-brief.md");
|
|
5812
|
+
const cacheMdPath = join26(vault, ".skillwiki", "session-brief.md");
|
|
5813
|
+
const cacheJsonPath = join26(vault, ".skillwiki", "session-brief.json");
|
|
5814
|
+
await mkdir8(join26(vault, "meta"), { recursive: true });
|
|
5815
|
+
await mkdir8(join26(vault, ".skillwiki"), { recursive: true });
|
|
5765
5816
|
const committed = renderCommittedBrief(input);
|
|
5766
5817
|
const previousComparable = comparableBrief(await readIfExists(metaPath));
|
|
5767
5818
|
const nextComparable = comparableBrief(committed);
|
|
5768
5819
|
const materialChange = previousComparable !== nextComparable;
|
|
5769
|
-
await
|
|
5770
|
-
await
|
|
5771
|
-
await
|
|
5820
|
+
await writeFile6(metaPath, committed, "utf8");
|
|
5821
|
+
await writeFile6(cacheMdPath, input.brief, "utf8");
|
|
5822
|
+
await writeFile6(cacheJsonPath, `${JSON.stringify({
|
|
5772
5823
|
project: input.project,
|
|
5773
5824
|
brief: input.brief,
|
|
5774
5825
|
word_count: input.wordCount,
|
|
@@ -5834,7 +5885,7 @@ function renderCommittedBrief(input) {
|
|
|
5834
5885
|
].filter((line) => line !== "").join("\n");
|
|
5835
5886
|
}
|
|
5836
5887
|
async function rebuildRootIndexProjection(vault) {
|
|
5837
|
-
const before = await readIfExists(
|
|
5888
|
+
const before = await readIfExists(join26(vault, "index.md"));
|
|
5838
5889
|
if (!before) return false;
|
|
5839
5890
|
const projection = await renderRootIndex({ vault, currentText: before });
|
|
5840
5891
|
if (!projection.ok) return false;
|
|
@@ -5844,7 +5895,7 @@ async function rebuildRootIndexProjection(vault) {
|
|
|
5844
5895
|
}
|
|
5845
5896
|
async function readIfExists(path) {
|
|
5846
5897
|
try {
|
|
5847
|
-
return await
|
|
5898
|
+
return await readFile12(path, "utf8");
|
|
5848
5899
|
} catch {
|
|
5849
5900
|
return "";
|
|
5850
5901
|
}
|
|
@@ -5886,14 +5937,14 @@ function dateFromPath(path) {
|
|
|
5886
5937
|
}
|
|
5887
5938
|
|
|
5888
5939
|
// src/commands/ingest.ts
|
|
5889
|
-
import { readFile as
|
|
5890
|
-
import { join as
|
|
5940
|
+
import { readFile as readFile15, open, unlink as unlink4, mkdir as mkdir10 } from "fs/promises";
|
|
5941
|
+
import { join as join31 } from "path";
|
|
5891
5942
|
import { createHash as createHash5 } from "crypto";
|
|
5892
5943
|
|
|
5893
5944
|
// src/commands/page-publish.ts
|
|
5894
5945
|
import { readFileSync as readFileSync13, realpathSync as realpathSync2 } from "fs";
|
|
5895
|
-
import { mkdir as
|
|
5896
|
-
import { dirname as dirname8, join as
|
|
5946
|
+
import { mkdir as mkdir9, readFile as readFile14 } from "fs/promises";
|
|
5947
|
+
import { dirname as dirname8, join as join30, resolve as resolve4 } from "path";
|
|
5897
5948
|
|
|
5898
5949
|
// src/utils/publication-approval.ts
|
|
5899
5950
|
import { createHash as createHash4 } from "crypto";
|
|
@@ -6121,8 +6172,8 @@ function redactApprovalTokens(text) {
|
|
|
6121
6172
|
}
|
|
6122
6173
|
|
|
6123
6174
|
// src/publish/pipeline.ts
|
|
6124
|
-
import { readFile as
|
|
6125
|
-
import { dirname as dirname7, join as
|
|
6175
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
6176
|
+
import { dirname as dirname7, join as join29, resolve as resolve3 } from "path";
|
|
6126
6177
|
|
|
6127
6178
|
// src/utils/publication-operation-journal.ts
|
|
6128
6179
|
import {
|
|
@@ -6135,7 +6186,7 @@ import {
|
|
|
6135
6186
|
unlinkSync,
|
|
6136
6187
|
writeFileSync as writeFileSync5
|
|
6137
6188
|
} from "fs";
|
|
6138
|
-
import { dirname as dirname6, join as
|
|
6189
|
+
import { dirname as dirname6, join as join27 } from "path";
|
|
6139
6190
|
var PUBLICATION_JOURNAL_SCHEMA = "skillwiki-publication-operation-v1";
|
|
6140
6191
|
var PHASE_ORDER2 = [
|
|
6141
6192
|
"locked",
|
|
@@ -6164,16 +6215,16 @@ function vaultIdentity(vaultPath) {
|
|
|
6164
6215
|
return sha256Hex(real).slice(0, 16);
|
|
6165
6216
|
}
|
|
6166
6217
|
function publicationJournalRoot(home = resolveSkillwikiHome()) {
|
|
6167
|
-
return
|
|
6218
|
+
return join27(resolveSkillwikiHome(home), ".skillwiki", "publication-operations");
|
|
6168
6219
|
}
|
|
6169
6220
|
function resolveJournalPaths(vaultPath, operationId2, home = resolveSkillwikiHome()) {
|
|
6170
6221
|
const identity = vaultIdentity(vaultPath);
|
|
6171
6222
|
const rootDir = publicationJournalRoot(home);
|
|
6172
|
-
const vaultDir =
|
|
6223
|
+
const vaultDir = join27(rootDir, identity);
|
|
6173
6224
|
return {
|
|
6174
6225
|
rootDir,
|
|
6175
6226
|
vaultDir,
|
|
6176
|
-
journalPath:
|
|
6227
|
+
journalPath: join27(vaultDir, `${operationId2}.json`)
|
|
6177
6228
|
};
|
|
6178
6229
|
}
|
|
6179
6230
|
function ensurePrivateDir(dir) {
|
|
@@ -6394,7 +6445,7 @@ function completePublicationJournal(input) {
|
|
|
6394
6445
|
}
|
|
6395
6446
|
|
|
6396
6447
|
// src/publish/hold-gates.ts
|
|
6397
|
-
import { join as
|
|
6448
|
+
import { join as join28 } from "path";
|
|
6398
6449
|
function evaluateSchemaGate(content, target, publisherKind) {
|
|
6399
6450
|
const frontmatter = extractFrontmatter(content);
|
|
6400
6451
|
if (!frontmatter.ok) return false;
|
|
@@ -6430,7 +6481,7 @@ function evaluateSchemaGate(content, target, publisherKind) {
|
|
|
6430
6481
|
return false;
|
|
6431
6482
|
}
|
|
6432
6483
|
function evaluateBrokenWikilinkGate(body, scan, ownTarget) {
|
|
6433
|
-
const draftPage = { absPath:
|
|
6484
|
+
const draftPage = { absPath: join28(scan.root, ownTarget), relPath: ownTarget };
|
|
6434
6485
|
const resolver = buildWikilinkResolver([...scan.allMarkdown, draftPage]);
|
|
6435
6486
|
const wikilinks = extractBodyWikilinks(body);
|
|
6436
6487
|
for (const link of wikilinks) {
|
|
@@ -6617,7 +6668,7 @@ function phaseAtLeast(current, needed) {
|
|
|
6617
6668
|
}
|
|
6618
6669
|
async function readPageChanged(targetPath, content) {
|
|
6619
6670
|
try {
|
|
6620
|
-
return ok(await
|
|
6671
|
+
return ok(await readFile13(targetPath, "utf8") !== content);
|
|
6621
6672
|
} catch (error) {
|
|
6622
6673
|
if (error.code === "ENOENT") return ok(true);
|
|
6623
6674
|
return err("WRITE_FAILED", { path: targetPath, message: String(error) });
|
|
@@ -6625,7 +6676,7 @@ async function readPageChanged(targetPath, content) {
|
|
|
6625
6676
|
}
|
|
6626
6677
|
async function readPriorTargetSha(targetPath) {
|
|
6627
6678
|
try {
|
|
6628
|
-
const text = await
|
|
6679
|
+
const text = await readFile13(targetPath, "utf8");
|
|
6629
6680
|
return ok(sha256Hex(text));
|
|
6630
6681
|
} catch (error) {
|
|
6631
6682
|
if (error.code === "ENOENT") return ok("absent");
|
|
@@ -6658,10 +6709,10 @@ function successReceipt(strategy, prepared, details) {
|
|
|
6658
6709
|
};
|
|
6659
6710
|
}
|
|
6660
6711
|
async function runPipelinePreview(strategy, prepared, vault) {
|
|
6661
|
-
const schemaPath =
|
|
6712
|
+
const schemaPath = join29(vault, "SCHEMA.md");
|
|
6662
6713
|
let schemaText;
|
|
6663
6714
|
try {
|
|
6664
|
-
schemaText = await
|
|
6715
|
+
schemaText = await readFile13(schemaPath, "utf8");
|
|
6665
6716
|
} catch (error) {
|
|
6666
6717
|
const result = err("FILE_NOT_FOUND", { path: schemaPath, message: String(error) });
|
|
6667
6718
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result };
|
|
@@ -6685,10 +6736,10 @@ async function runPipelinePreview(strategy, prepared, vault) {
|
|
|
6685
6736
|
if (!indices.ok) {
|
|
6686
6737
|
return { exitCode: indices.exitCode, result: indices.result };
|
|
6687
6738
|
}
|
|
6688
|
-
const logPath =
|
|
6739
|
+
const logPath = join29(vault, "log.md");
|
|
6689
6740
|
let logAppended;
|
|
6690
6741
|
try {
|
|
6691
|
-
const logText = await
|
|
6742
|
+
const logText = await readFile13(logPath, "utf8");
|
|
6692
6743
|
const marker = strategy.publisherKind === "page" ? `<!-- skillwiki-page-publish:${prepared.operationId} -->` : `<!-- skillwiki-project-page-publish:${prepared.operationId} -->`;
|
|
6693
6744
|
logAppended = !logText.includes(marker);
|
|
6694
6745
|
} catch (error) {
|
|
@@ -6779,10 +6830,10 @@ async function runPipelineLockedPrimaryStages(strategy, prepared, vault, deps, j
|
|
|
6779
6830
|
return { ok: false, exitCode: ExitCode.WRITE_FAILED, stage: "journal", state, cause: journalHook };
|
|
6780
6831
|
}
|
|
6781
6832
|
}
|
|
6782
|
-
const schemaPath =
|
|
6833
|
+
const schemaPath = join29(vault, "SCHEMA.md");
|
|
6783
6834
|
let schemaText;
|
|
6784
6835
|
try {
|
|
6785
|
-
schemaText = await
|
|
6836
|
+
schemaText = await readFile13(schemaPath, "utf8");
|
|
6786
6837
|
} catch (error) {
|
|
6787
6838
|
return {
|
|
6788
6839
|
ok: false,
|
|
@@ -6831,8 +6882,8 @@ async function runPipelineLockedPrimaryStages(strategy, prepared, vault, deps, j
|
|
|
6831
6882
|
if (!strategy.usesJournal || !phaseAtLeast(currentPhase, "page")) {
|
|
6832
6883
|
if (strategy.publisherKind === "project-page") {
|
|
6833
6884
|
try {
|
|
6834
|
-
const { mkdir:
|
|
6835
|
-
await
|
|
6885
|
+
const { mkdir: mkdir13 } = await import("fs/promises");
|
|
6886
|
+
await mkdir13(dirname7(prepared.targetPath), { recursive: true });
|
|
6836
6887
|
} catch (error) {
|
|
6837
6888
|
return {
|
|
6838
6889
|
ok: false,
|
|
@@ -6880,8 +6931,8 @@ async function runPipelineLockedPrimaryStages(strategy, prepared, vault, deps, j
|
|
|
6880
6931
|
let visibleSchema;
|
|
6881
6932
|
try {
|
|
6882
6933
|
[visible, visibleSchema] = await Promise.all([
|
|
6883
|
-
|
|
6884
|
-
|
|
6934
|
+
readFile13(prepared.targetPath, "utf8"),
|
|
6935
|
+
readFile13(schemaPath, "utf8")
|
|
6885
6936
|
]);
|
|
6886
6937
|
} catch (error) {
|
|
6887
6938
|
return {
|
|
@@ -7273,16 +7324,16 @@ async function refreshProjectIndexForTarget(vault, projectSlugs, today) {
|
|
|
7273
7324
|
for (const slug of projectSlugs) {
|
|
7274
7325
|
const rendered = await renderProjectIndex(vault, slug, { today });
|
|
7275
7326
|
if (!rendered.ok) return rendered;
|
|
7276
|
-
const indexPath =
|
|
7327
|
+
const indexPath = join30(vault, rendered.data.index_path);
|
|
7277
7328
|
try {
|
|
7278
|
-
await
|
|
7329
|
+
await mkdir9(dirname8(indexPath), { recursive: true });
|
|
7279
7330
|
} catch (error) {
|
|
7280
7331
|
return err("WRITE_FAILED", { path: indexPath, message: String(error) });
|
|
7281
7332
|
}
|
|
7282
7333
|
const written = await atomicWriteText(indexPath, rendered.data.text);
|
|
7283
7334
|
if (!written.ok) return written;
|
|
7284
7335
|
try {
|
|
7285
|
-
const visible = await
|
|
7336
|
+
const visible = await readFile14(indexPath, "utf8");
|
|
7286
7337
|
if (visible !== rendered.data.text) {
|
|
7287
7338
|
return err("WRITE_FAILED", { path: indexPath, message: "project index verification failed" });
|
|
7288
7339
|
}
|
|
@@ -7383,7 +7434,7 @@ function preparePagePublicationFromContent(input) {
|
|
|
7383
7434
|
async function preparePagePublication(input) {
|
|
7384
7435
|
let content;
|
|
7385
7436
|
try {
|
|
7386
|
-
content = await
|
|
7437
|
+
content = await readFile14(input.draftPath, "utf8");
|
|
7387
7438
|
} catch (error) {
|
|
7388
7439
|
return err("FILE_NOT_FOUND", { path: input.draftPath, message: String(error) });
|
|
7389
7440
|
}
|
|
@@ -7471,10 +7522,10 @@ var PAGE_PUBLISH_STRATEGY = {
|
|
|
7471
7522
|
return void 0;
|
|
7472
7523
|
},
|
|
7473
7524
|
async previewIndices(prepared, vault, pageChanged) {
|
|
7474
|
-
const indexPath =
|
|
7525
|
+
const indexPath = join30(vault, "index.md");
|
|
7475
7526
|
let indexText;
|
|
7476
7527
|
try {
|
|
7477
|
-
indexText = await
|
|
7528
|
+
indexText = await readFile14(indexPath, "utf8");
|
|
7478
7529
|
} catch (error) {
|
|
7479
7530
|
const result = err("FILE_NOT_FOUND", { path: indexPath, message: String(error) });
|
|
7480
7531
|
return { ok: false, exitCode: ExitCode.FILE_NOT_FOUND, result };
|
|
@@ -7492,7 +7543,7 @@ var PAGE_PUBLISH_STRATEGY = {
|
|
|
7492
7543
|
if (!renderedProject.ok) {
|
|
7493
7544
|
return { ok: false, exitCode: errorExitCode(renderedProject.error), result: renderedProject };
|
|
7494
7545
|
}
|
|
7495
|
-
const projectIndexPath =
|
|
7546
|
+
const projectIndexPath = join30(vault, renderedProject.data.index_path);
|
|
7496
7547
|
const projectIndexChanged = await readPageChanged(projectIndexPath, renderedProject.data.text);
|
|
7497
7548
|
if (!projectIndexChanged.ok) {
|
|
7498
7549
|
return { ok: false, exitCode: errorExitCode(projectIndexChanged.error), result: projectIndexChanged };
|
|
@@ -7680,7 +7731,7 @@ function buildTypedContent(title, ingested, type, tags, rawRelPath, provenance)
|
|
|
7680
7731
|
}
|
|
7681
7732
|
async function resolveRawCapture(input) {
|
|
7682
7733
|
try {
|
|
7683
|
-
const existing = await
|
|
7734
|
+
const existing = await readFile15(input.path, "utf8");
|
|
7684
7735
|
const frontmatter = extractFrontmatter(existing);
|
|
7685
7736
|
if (!frontmatter.ok) {
|
|
7686
7737
|
return err("INGEST_VALIDATION_FAILED", {
|
|
@@ -7819,7 +7870,7 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
|
|
|
7819
7870
|
sourceContent = fetchResult.data.body;
|
|
7820
7871
|
} else {
|
|
7821
7872
|
try {
|
|
7822
|
-
sourceContent = await
|
|
7873
|
+
sourceContent = await readFile15(input.source, "utf8");
|
|
7823
7874
|
} catch {
|
|
7824
7875
|
return {
|
|
7825
7876
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -7844,7 +7895,7 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
|
|
|
7844
7895
|
const rawRelPath = `raw/articles/${slug}.md`;
|
|
7845
7896
|
const typedDir = TYPE_DIR[input.type] ?? `${input.type}s`;
|
|
7846
7897
|
const typedRelPath = `${typedDir}/${slug}.md`;
|
|
7847
|
-
const rawAbsPath =
|
|
7898
|
+
const rawAbsPath = join31(input.vault, rawRelPath);
|
|
7848
7899
|
const identity = assessSourceIdentity({
|
|
7849
7900
|
rawPath: rawRelPath,
|
|
7850
7901
|
sourceUrl: sourceUrl ?? void 0,
|
|
@@ -7888,11 +7939,11 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
|
|
|
7888
7939
|
);
|
|
7889
7940
|
if (!input.dryRun) {
|
|
7890
7941
|
try {
|
|
7891
|
-
await
|
|
7942
|
+
await mkdir10(join31(input.vault, typedDir), { recursive: true });
|
|
7892
7943
|
} catch (error) {
|
|
7893
7944
|
return {
|
|
7894
7945
|
exitCode: ExitCode.WRITE_FAILED,
|
|
7895
|
-
result: err("WRITE_FAILED", { path:
|
|
7946
|
+
result: err("WRITE_FAILED", { path: join31(input.vault, typedDir), message: String(error) })
|
|
7896
7947
|
};
|
|
7897
7948
|
}
|
|
7898
7949
|
}
|
|
@@ -7946,11 +7997,11 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
|
|
|
7946
7997
|
preflight: pagePublishDeps.preflight,
|
|
7947
7998
|
mutate: async (receipt) => {
|
|
7948
7999
|
try {
|
|
7949
|
-
await
|
|
8000
|
+
await mkdir10(join31(input.vault, "raw", "articles"), { recursive: true });
|
|
7950
8001
|
} catch (error) {
|
|
7951
8002
|
return {
|
|
7952
8003
|
exitCode: ExitCode.WRITE_FAILED,
|
|
7953
|
-
result: err("WRITE_FAILED", { path:
|
|
8004
|
+
result: err("WRITE_FAILED", { path: join31(input.vault, "raw", "articles"), message: String(error) })
|
|
7954
8005
|
};
|
|
7955
8006
|
}
|
|
7956
8007
|
const rawWrite = await writeResolvedRaw({
|
|
@@ -8186,8 +8237,8 @@ ${body}`;
|
|
|
8186
8237
|
}
|
|
8187
8238
|
|
|
8188
8239
|
// src/commands/tag-reconcile.ts
|
|
8189
|
-
import { readFile as
|
|
8190
|
-
import { join as
|
|
8240
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
8241
|
+
import { join as join32, posix } from "path";
|
|
8191
8242
|
var TYPED_TARGET_RE = /^(entities|concepts|comparisons|queries|meta)\/[a-z0-9][a-z0-9./_-]*\.md$/;
|
|
8192
8243
|
function errorExitCode2(error) {
|
|
8193
8244
|
switch (error) {
|
|
@@ -8230,7 +8281,7 @@ function asTagArray(frontmatter, path) {
|
|
|
8230
8281
|
async function readTagsFromFile(path) {
|
|
8231
8282
|
let text;
|
|
8232
8283
|
try {
|
|
8233
|
-
text = await
|
|
8284
|
+
text = await readFile16(path, "utf8");
|
|
8234
8285
|
} catch (error) {
|
|
8235
8286
|
if (error.code === "ENOENT") {
|
|
8236
8287
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path }) };
|
|
@@ -8251,7 +8302,7 @@ async function resolveRequestedTags(input, page) {
|
|
|
8251
8302
|
result: err("INVALID_FRONTMATTER", { message: "explicit tags must be an array of strings" })
|
|
8252
8303
|
};
|
|
8253
8304
|
}
|
|
8254
|
-
const source = input.from ?? (explicit.length === 0 ?
|
|
8305
|
+
const source = input.from ?? (explicit.length === 0 ? join32(input.vault, page) : void 0);
|
|
8255
8306
|
if (!source) return { exitCode: ExitCode.OK, result: ok({ tags: [...new Set(explicit)].sort() }) };
|
|
8256
8307
|
const sourced = await readTagsFromFile(source);
|
|
8257
8308
|
if (!sourced.result.ok) return { exitCode: sourced.exitCode, result: sourced.result };
|
|
@@ -8262,7 +8313,7 @@ async function resolveRequestedTags(input, page) {
|
|
|
8262
8313
|
}
|
|
8263
8314
|
async function readSchema(schemaPath) {
|
|
8264
8315
|
try {
|
|
8265
|
-
return { exitCode: ExitCode.OK, result: ok(await
|
|
8316
|
+
return { exitCode: ExitCode.OK, result: ok(await readFile16(schemaPath, "utf8")) };
|
|
8266
8317
|
} catch (error) {
|
|
8267
8318
|
if (error.code === "ENOENT") {
|
|
8268
8319
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: schemaPath }) };
|
|
@@ -8290,7 +8341,7 @@ function previewResult(page, tags, reconciled, dryRun, filesChanged) {
|
|
|
8290
8341
|
};
|
|
8291
8342
|
}
|
|
8292
8343
|
async function reconcileTagsWhileLocked(input, page, tags, comment) {
|
|
8293
|
-
const schemaPath =
|
|
8344
|
+
const schemaPath = join32(input.vault, "SCHEMA.md");
|
|
8294
8345
|
const current = await readSchema(schemaPath);
|
|
8295
8346
|
if (!current.result.ok) return { exitCode: current.exitCode, result: current.result };
|
|
8296
8347
|
const next = reconcileTaxonomyDocument(current.result.data, { tags, comment });
|
|
@@ -8301,7 +8352,7 @@ async function reconcileTagsWhileLocked(input, page, tags, comment) {
|
|
|
8301
8352
|
}
|
|
8302
8353
|
let verifiedText;
|
|
8303
8354
|
try {
|
|
8304
|
-
verifiedText = await
|
|
8355
|
+
verifiedText = await readFile16(schemaPath, "utf8");
|
|
8305
8356
|
} catch (error) {
|
|
8306
8357
|
return {
|
|
8307
8358
|
exitCode: ExitCode.WRITE_FAILED,
|
|
@@ -8327,7 +8378,7 @@ async function runTagReconcile(input) {
|
|
|
8327
8378
|
const comment = taxonomyCommentForPage(page.data, date, input.reason);
|
|
8328
8379
|
if (!comment.ok) return { exitCode: ExitCode.SCHEME_REJECTED, result: comment };
|
|
8329
8380
|
if (!input.write) {
|
|
8330
|
-
const schema = await readSchema(
|
|
8381
|
+
const schema = await readSchema(join32(input.vault, "SCHEMA.md"));
|
|
8331
8382
|
if (!schema.result.ok) return { exitCode: schema.exitCode, result: schema.result };
|
|
8332
8383
|
const preview = reconcileTaxonomyDocument(schema.result.data, { tags, comment: comment.data });
|
|
8333
8384
|
return previewResult(page.data, tags, preview, true, []);
|
|
@@ -8380,8 +8431,8 @@ async function runTagReconcile(input) {
|
|
|
8380
8431
|
|
|
8381
8432
|
// src/commands/project-page-publish.ts
|
|
8382
8433
|
import { realpathSync as realpathSync4 } from "fs";
|
|
8383
|
-
import { mkdir as
|
|
8384
|
-
import { dirname as dirname10, join as
|
|
8434
|
+
import { mkdir as mkdir11, readFile as readFile17 } from "fs/promises";
|
|
8435
|
+
import { dirname as dirname10, join as join33, resolve as resolve6 } from "path";
|
|
8385
8436
|
|
|
8386
8437
|
// src/utils/architecture-page.ts
|
|
8387
8438
|
import { lstatSync, realpathSync as realpathSync3 } from "fs";
|
|
@@ -8553,7 +8604,7 @@ function validateLogNote(logNote) {
|
|
|
8553
8604
|
async function prepareProjectPagePublication(input) {
|
|
8554
8605
|
let content;
|
|
8555
8606
|
try {
|
|
8556
|
-
content = await
|
|
8607
|
+
content = await readFile17(input.draftPath, "utf8");
|
|
8557
8608
|
} catch (error) {
|
|
8558
8609
|
return err("FILE_NOT_FOUND", { path: input.draftPath, message: String(error) });
|
|
8559
8610
|
}
|
|
@@ -8686,9 +8737,9 @@ var PROJECT_PAGE_PUBLISH_STRATEGY = {
|
|
|
8686
8737
|
async updateIndicesLocked(prepared, vault, state, observe) {
|
|
8687
8738
|
const rendered = await renderProjectIndex(vault, prepared.page.project, { today: prepared.date });
|
|
8688
8739
|
if (!rendered.ok) return rendered;
|
|
8689
|
-
const knowledgePath =
|
|
8740
|
+
const knowledgePath = join33(vault, rendered.data.index_path);
|
|
8690
8741
|
try {
|
|
8691
|
-
await
|
|
8742
|
+
await mkdir11(dirname10(knowledgePath), { recursive: true });
|
|
8692
8743
|
} catch (error) {
|
|
8693
8744
|
return err("WRITE_FAILED", { message: String(error) });
|
|
8694
8745
|
}
|
|
@@ -8697,7 +8748,7 @@ var PROJECT_PAGE_PUBLISH_STRATEGY = {
|
|
|
8697
8748
|
state.projectIndexUpdated = knowledgeWrite.data.changed;
|
|
8698
8749
|
if (state.projectIndexUpdated) state.changed.add(rendered.data.index_path);
|
|
8699
8750
|
try {
|
|
8700
|
-
const visibleIndex = await
|
|
8751
|
+
const visibleIndex = await readFile17(knowledgePath, "utf8");
|
|
8701
8752
|
if (visibleIndex !== rendered.data.text) {
|
|
8702
8753
|
return err("WRITE_FAILED", { message: "project knowledge.md verification failed" });
|
|
8703
8754
|
}
|
|
@@ -8717,9 +8768,9 @@ var PROJECT_PAGE_PUBLISH_STRATEGY = {
|
|
|
8717
8768
|
}
|
|
8718
8769
|
let projectIndexChanged = true;
|
|
8719
8770
|
if (projectIndex.ok) {
|
|
8720
|
-
const indexPath =
|
|
8771
|
+
const indexPath = join33(vault, projectIndex.data.index_path);
|
|
8721
8772
|
try {
|
|
8722
|
-
const existing = await
|
|
8773
|
+
const existing = await readFile17(indexPath, "utf8");
|
|
8723
8774
|
projectIndexChanged = existing !== projectIndex.data.text || pageChanged;
|
|
8724
8775
|
} catch {
|
|
8725
8776
|
projectIndexChanged = true;
|
|
@@ -8879,7 +8930,7 @@ import { existsSync as existsSync11, writeFileSync as writeFileSync6, mkdirSync
|
|
|
8879
8930
|
import { createHash as createHash6 } from "crypto";
|
|
8880
8931
|
import { execSync as execSync3, spawn } from "child_process";
|
|
8881
8932
|
import { platform as platform2 } from "os";
|
|
8882
|
-
import { join as
|
|
8933
|
+
import { join as join34, resolve as resolvePath } from "path";
|
|
8883
8934
|
var MAINTENANCE_SCHEMA_VERSION = 1;
|
|
8884
8935
|
var MAINTENANCE_COMMAND = "snapshot-maintenance journal clear-stale";
|
|
8885
8936
|
var REPAIR_COMMAND = "snapshot-maintenance projection-conflict repair";
|
|
@@ -8944,7 +8995,7 @@ async function runSnapshotMaintenanceDryRun(input) {
|
|
|
8944
8995
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_WRONG_WORKTREE"));
|
|
8945
8996
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_WRONG_WORKTREE", `requested path '${requested}' is not the configured snapshot worktree '${canonicalize(configuredWorktree)}'`) };
|
|
8946
8997
|
}
|
|
8947
|
-
if (!existsSync11(requested) || !existsSync11(
|
|
8998
|
+
if (!existsSync11(requested) || !existsSync11(join34(requested, ".git"))) {
|
|
8948
8999
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_MISSING_GIT_REPO"));
|
|
8949
9000
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_MISSING_GIT_REPO", `snapshot worktree is not a git repository: ${requested}`) };
|
|
8950
9001
|
}
|
|
@@ -9024,14 +9075,14 @@ async function resolveLiveVault(input) {
|
|
|
9024
9075
|
return resolved.ok ? canonicalize(resolved.data.path) : void 0;
|
|
9025
9076
|
}
|
|
9026
9077
|
function snapshotMaintenanceAuditLogPath(home) {
|
|
9027
|
-
const stateDir = platform2() === "darwin" ?
|
|
9028
|
-
return
|
|
9078
|
+
const stateDir = platform2() === "darwin" ? join34(home, "Library", "Application Support", "vault-sync") : join34(home, ".local", "state", "vault-sync");
|
|
9079
|
+
return join34(stateDir, "snapshot-maintenance-audit.jsonl");
|
|
9029
9080
|
}
|
|
9030
9081
|
function defaultAuditSink(home) {
|
|
9031
9082
|
return (event) => {
|
|
9032
9083
|
try {
|
|
9033
9084
|
const logPath = snapshotMaintenanceAuditLogPath(home);
|
|
9034
|
-
mkdirSync4(
|
|
9085
|
+
mkdirSync4(join34(logPath, ".."), { recursive: true });
|
|
9035
9086
|
appendFileSync(logPath, JSON.stringify(event) + "\n", { encoding: "utf8" });
|
|
9036
9087
|
} catch {
|
|
9037
9088
|
}
|
|
@@ -9179,9 +9230,9 @@ function nonMergeSequencerActive(repo) {
|
|
|
9179
9230
|
const gitDir = git(repo, ["rev-parse", "--absolute-git-dir"]);
|
|
9180
9231
|
if (!gitDir) return false;
|
|
9181
9232
|
for (const m of ["CHERRY_PICK_HEAD", "REVERT_HEAD"]) {
|
|
9182
|
-
if (existsSync11(
|
|
9233
|
+
if (existsSync11(join34(gitDir, m))) return true;
|
|
9183
9234
|
}
|
|
9184
|
-
return existsSync11(
|
|
9235
|
+
return existsSync11(join34(gitDir, "rebase-merge")) || existsSync11(join34(gitDir, "rebase-apply"));
|
|
9185
9236
|
}
|
|
9186
9237
|
function extraUnmergedPaths(unmerged) {
|
|
9187
9238
|
const allow = new Set(PROJECTION_CONFLICT_ALLOWLIST);
|
|
@@ -9220,7 +9271,7 @@ async function authorizeRepairContext(input) {
|
|
|
9220
9271
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_WRONG_WORKTREE", void 0, REPAIR_COMMAND));
|
|
9221
9272
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_WRONG_WORKTREE", `requested path '${requested}' is not the configured snapshot worktree '${canonicalize(configuredWorktree)}'`) };
|
|
9222
9273
|
}
|
|
9223
|
-
if (!existsSync11(requested) || !existsSync11(
|
|
9274
|
+
if (!existsSync11(requested) || !existsSync11(join34(requested, ".git"))) {
|
|
9224
9275
|
audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_MISSING_GIT_REPO", void 0, REPAIR_COMMAND));
|
|
9225
9276
|
return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_MISSING_GIT_REPO", `snapshot worktree is not a git repository: ${requested}`) };
|
|
9226
9277
|
}
|
|
@@ -9321,8 +9372,8 @@ async function performProjectionRepair(input, plan, audit, now) {
|
|
|
9321
9372
|
return { exitCode: ExitCode.WRITE_FAILED, result: rendered };
|
|
9322
9373
|
}
|
|
9323
9374
|
try {
|
|
9324
|
-
writeFileSync6(
|
|
9325
|
-
writeFileSync6(
|
|
9375
|
+
writeFileSync6(join34(plan.snapshot_worktree, "index.md"), rendered.data.index);
|
|
9376
|
+
writeFileSync6(join34(plan.snapshot_worktree, "log.md"), rendered.data.log);
|
|
9326
9377
|
gitStrict(plan.snapshot_worktree, ["add", "--", "index.md", "log.md"]);
|
|
9327
9378
|
gitStrict(plan.snapshot_worktree, [
|
|
9328
9379
|
"commit",
|
|
@@ -9430,7 +9481,7 @@ function releaseSnapshotFlock(handle) {
|
|
|
9430
9481
|
|
|
9431
9482
|
// src/commands/backup.ts
|
|
9432
9483
|
import { statSync as statSync3, readdirSync as readdirSync2, readFileSync as readFileSync15, mkdirSync as mkdirSync5, writeFileSync as writeFileSync7 } from "fs";
|
|
9433
|
-
import { join as
|
|
9484
|
+
import { join as join35, relative as relative3, dirname as dirname11 } from "path";
|
|
9434
9485
|
import { PutObjectCommand, HeadObjectCommand, ListObjectsV2Command, GetObjectCommand, DeleteObjectsCommand } from "@aws-sdk/client-s3";
|
|
9435
9486
|
|
|
9436
9487
|
// src/utils/s3-client.ts
|
|
@@ -9454,7 +9505,7 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([".git", ".obsidian", "_archive", "node_
|
|
|
9454
9505
|
function* walkMarkdown(dir, base) {
|
|
9455
9506
|
for (const entry of readdirSync2(dir, { withFileTypes: true })) {
|
|
9456
9507
|
if (SKIP_DIRS.has(entry.name)) continue;
|
|
9457
|
-
const full =
|
|
9508
|
+
const full = join35(dir, entry.name);
|
|
9458
9509
|
if (entry.isDirectory()) {
|
|
9459
9510
|
yield* walkMarkdown(full, base);
|
|
9460
9511
|
} else if (entry.name.endsWith(".md")) {
|
|
@@ -9477,7 +9528,7 @@ async function runBackupSync(input) {
|
|
|
9477
9528
|
let failed = 0;
|
|
9478
9529
|
const files = [...walkMarkdown(input.vault, input.vault)];
|
|
9479
9530
|
for (const relPath of files) {
|
|
9480
|
-
const absPath =
|
|
9531
|
+
const absPath = join35(input.vault, relPath);
|
|
9481
9532
|
const localStat = statSync3(absPath);
|
|
9482
9533
|
let needsUpload = true;
|
|
9483
9534
|
try {
|
|
@@ -9553,7 +9604,7 @@ async function runBackupRestore(input) {
|
|
|
9553
9604
|
const objects = list.Contents ?? [];
|
|
9554
9605
|
for (const obj of objects) {
|
|
9555
9606
|
if (!obj.Key) continue;
|
|
9556
|
-
const localPath =
|
|
9607
|
+
const localPath = join35(target, obj.Key);
|
|
9557
9608
|
try {
|
|
9558
9609
|
const localStat = statSync3(localPath);
|
|
9559
9610
|
if (obj.LastModified && localStat.mtime > obj.LastModified) {
|
|
@@ -9600,8 +9651,8 @@ async function runBackupRestore(input) {
|
|
|
9600
9651
|
|
|
9601
9652
|
// src/commands/status.ts
|
|
9602
9653
|
import { existsSync as existsSync12, statSync as statSync4 } from "fs";
|
|
9603
|
-
import { readFile as
|
|
9604
|
-
import { join as
|
|
9654
|
+
import { readFile as readFile18 } from "fs/promises";
|
|
9655
|
+
import { join as join36 } from "path";
|
|
9605
9656
|
var FUSE_NO_MIRROR_NOTE = "FUSE vault with no read mirror - status scan may be slow";
|
|
9606
9657
|
async function runStatus(input) {
|
|
9607
9658
|
if (!existsSync12(input.vault)) {
|
|
@@ -9640,7 +9691,7 @@ async function runStatus(input) {
|
|
|
9640
9691
|
const compound = scan.data.compound.length;
|
|
9641
9692
|
let schemaVersion = "v1";
|
|
9642
9693
|
try {
|
|
9643
|
-
const schemaContent = await
|
|
9694
|
+
const schemaContent = await readFile18(join36(scanRoot, "SCHEMA.md"), "utf8");
|
|
9644
9695
|
const versionMatch = schemaContent.match(/version:\s*["']?([^"'\s\n]+)/i);
|
|
9645
9696
|
if (versionMatch) schemaVersion = versionMatch[1];
|
|
9646
9697
|
} catch {
|
|
@@ -9708,13 +9759,13 @@ async function runStatus(input) {
|
|
|
9708
9759
|
|
|
9709
9760
|
// src/commands/copy-status.ts
|
|
9710
9761
|
import { existsSync as existsSync13, realpathSync as realpathSync5 } from "fs";
|
|
9711
|
-
import { isAbsolute as isAbsolute2, join as
|
|
9762
|
+
import { isAbsolute as isAbsolute2, join as join38, relative as relative5, resolve as resolve8 } from "path";
|
|
9712
9763
|
|
|
9713
9764
|
// src/utils/fetch-projection.ts
|
|
9714
|
-
import { isAbsolute, join as
|
|
9765
|
+
import { isAbsolute, join as join37, resolve as resolve7 } from "path";
|
|
9715
9766
|
function inspectConfiguredFetchProjection(home) {
|
|
9716
9767
|
if (!home) return { configured: false };
|
|
9717
|
-
const config = readSkillWikiConfig(
|
|
9768
|
+
const config = readSkillWikiConfig(join37(home, ".skillwiki", ".env"));
|
|
9718
9769
|
const configured = config["vault_sync.fetch_projection"];
|
|
9719
9770
|
if (!configured || configured === "none") return { configured: false };
|
|
9720
9771
|
if (!isAbsolute(configured)) {
|
|
@@ -9725,7 +9776,7 @@ function inspectConfiguredFetchProjection(home) {
|
|
|
9725
9776
|
|
|
9726
9777
|
// src/utils/live-drift.ts
|
|
9727
9778
|
import { createHash as createHash7 } from "crypto";
|
|
9728
|
-
import { readFile as
|
|
9779
|
+
import { readFile as readFile19 } from "fs/promises";
|
|
9729
9780
|
import { relative as relative4, sep as sep3 } from "path";
|
|
9730
9781
|
|
|
9731
9782
|
// src/utils/git-promotion.ts
|
|
@@ -9770,7 +9821,7 @@ async function measureAuthoritativeLiveDrift(liveVault, projection) {
|
|
|
9770
9821
|
const rel = relative4(liveVault, page.absPath).split(sep3).join("/");
|
|
9771
9822
|
if (!isGitPromotablePath(rel)) continue;
|
|
9772
9823
|
livePromotable.add(rel);
|
|
9773
|
-
const bytes = await
|
|
9824
|
+
const bytes = await readFile19(page.absPath);
|
|
9774
9825
|
if (projectionBlobs.get(rel) !== gitBlobOid(bytes)) content += 1;
|
|
9775
9826
|
}
|
|
9776
9827
|
for (const rel of projectionBlobs.keys()) {
|
|
@@ -9965,7 +10016,7 @@ function defaultCopyStatusDeps(input) {
|
|
|
9965
10016
|
const projectionWarning = selection.configured ? `configured fetch projection ignored for Git status; using live vault${projectionProblem ? ` (${projectionProblem})` : ""}` : void 0;
|
|
9966
10017
|
const invalidProjectionDetail = projectionProblem ?? "configured fetch projection is not a git repository";
|
|
9967
10018
|
const gitRootProblem = () => {
|
|
9968
|
-
if (!existsSync13(
|
|
10019
|
+
if (!existsSync13(join38(gitVault, ".git"))) {
|
|
9969
10020
|
return "vault is not a git repository";
|
|
9970
10021
|
}
|
|
9971
10022
|
return void 0;
|
|
@@ -10045,7 +10096,7 @@ function defaultCopyStatusDeps(input) {
|
|
|
10045
10096
|
detail: projectionProblem ?? "live drift requires a configured fetch projection"
|
|
10046
10097
|
};
|
|
10047
10098
|
}
|
|
10048
|
-
if (!existsSync13(
|
|
10099
|
+
if (!existsSync13(join38(configuredProjection, ".git"))) {
|
|
10049
10100
|
return {
|
|
10050
10101
|
unknown: true,
|
|
10051
10102
|
reason_code: "fetch_projection_invalid",
|
|
@@ -10065,8 +10116,8 @@ async function runCopyStatusCommand(input) {
|
|
|
10065
10116
|
}
|
|
10066
10117
|
|
|
10067
10118
|
// src/commands/seed.ts
|
|
10068
|
-
import { mkdir as
|
|
10069
|
-
import { join as
|
|
10119
|
+
import { mkdir as mkdir12, writeFile as writeFile7, stat as stat5 } from "fs/promises";
|
|
10120
|
+
import { join as join39 } from "path";
|
|
10070
10121
|
var TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
10071
10122
|
var EXAMPLE_PAGES = {
|
|
10072
10123
|
"entities/example-project.md": `---
|
|
@@ -10135,30 +10186,30 @@ Real sources are immutable after ingestion \u2014 never edit them.
|
|
|
10135
10186
|
`;
|
|
10136
10187
|
async function runSeed(input) {
|
|
10137
10188
|
try {
|
|
10138
|
-
await stat5(
|
|
10189
|
+
await stat5(join39(input.vault, "SCHEMA.md"));
|
|
10139
10190
|
} catch {
|
|
10140
10191
|
return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { root: input.vault, reason: "SCHEMA.md missing \u2014 run `skillwiki init` first" }) };
|
|
10141
10192
|
}
|
|
10142
10193
|
const created = [];
|
|
10143
10194
|
const skipped = [];
|
|
10144
10195
|
for (const [relPath, content] of Object.entries(EXAMPLE_PAGES)) {
|
|
10145
|
-
const absPath =
|
|
10196
|
+
const absPath = join39(input.vault, relPath);
|
|
10146
10197
|
try {
|
|
10147
10198
|
await stat5(absPath);
|
|
10148
10199
|
skipped.push(relPath);
|
|
10149
10200
|
} catch {
|
|
10150
|
-
await
|
|
10151
|
-
await
|
|
10201
|
+
await mkdir12(join39(absPath, ".."), { recursive: true });
|
|
10202
|
+
await writeFile7(absPath, content, "utf8");
|
|
10152
10203
|
created.push(relPath);
|
|
10153
10204
|
}
|
|
10154
10205
|
}
|
|
10155
|
-
const rawPath =
|
|
10206
|
+
const rawPath = join39(input.vault, "raw", "articles", "example-source.md");
|
|
10156
10207
|
try {
|
|
10157
10208
|
await stat5(rawPath);
|
|
10158
10209
|
skipped.push("raw/articles/example-source.md");
|
|
10159
10210
|
} catch {
|
|
10160
|
-
await
|
|
10161
|
-
await
|
|
10211
|
+
await mkdir12(join39(rawPath, ".."), { recursive: true });
|
|
10212
|
+
await writeFile7(rawPath, EXAMPLE_RAW, "utf8");
|
|
10162
10213
|
created.push("raw/articles/example-source.md");
|
|
10163
10214
|
}
|
|
10164
10215
|
if (created.length > 0) {
|
|
@@ -10180,9 +10231,9 @@ async function runSeed(input) {
|
|
|
10180
10231
|
}
|
|
10181
10232
|
|
|
10182
10233
|
// src/commands/canvas.ts
|
|
10183
|
-
import { readFile as
|
|
10234
|
+
import { readFile as readFile20, writeFile as writeFile8 } from "fs/promises";
|
|
10184
10235
|
import { existsSync as existsSync14 } from "fs";
|
|
10185
|
-
import { join as
|
|
10236
|
+
import { join as join40 } from "path";
|
|
10186
10237
|
var NODE_WIDTH = 240;
|
|
10187
10238
|
var NODE_HEIGHT = 60;
|
|
10188
10239
|
var COLUMN_SPACING = 400;
|
|
@@ -10260,7 +10311,7 @@ function buildCanvasEdges(adjacency) {
|
|
|
10260
10311
|
return edges;
|
|
10261
10312
|
}
|
|
10262
10313
|
async function runCanvasGenerate(input) {
|
|
10263
|
-
const graphPath = input.graphPath ??
|
|
10314
|
+
const graphPath = input.graphPath ?? join40(input.vault, ".skillwiki", "graph.json");
|
|
10264
10315
|
if (!existsSync14(graphPath)) {
|
|
10265
10316
|
return {
|
|
10266
10317
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -10272,7 +10323,7 @@ async function runCanvasGenerate(input) {
|
|
|
10272
10323
|
}
|
|
10273
10324
|
let raw;
|
|
10274
10325
|
try {
|
|
10275
|
-
raw = await
|
|
10326
|
+
raw = await readFile20(graphPath, "utf8");
|
|
10276
10327
|
} catch (e) {
|
|
10277
10328
|
return {
|
|
10278
10329
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
@@ -10298,9 +10349,9 @@ async function runCanvasGenerate(input) {
|
|
|
10298
10349
|
const nodes = buildCanvasNodes(paths);
|
|
10299
10350
|
const edges = buildCanvasEdges(graph.adjacency);
|
|
10300
10351
|
const canvas = { nodes, edges };
|
|
10301
|
-
const outPath =
|
|
10352
|
+
const outPath = join40(input.vault, "vault-graph.canvas");
|
|
10302
10353
|
try {
|
|
10303
|
-
await
|
|
10354
|
+
await writeFile8(outPath, JSON.stringify(canvas, null, 2));
|
|
10304
10355
|
} catch (e) {
|
|
10305
10356
|
return {
|
|
10306
10357
|
exitCode: ExitCode.WRITE_FAILED,
|
|
@@ -10443,22 +10494,22 @@ async function runSourceDisposition(input) {
|
|
|
10443
10494
|
|
|
10444
10495
|
// src/utils/source-disposal.ts
|
|
10445
10496
|
import { createHash as createHash8 } from "crypto";
|
|
10446
|
-
import { readFile as
|
|
10497
|
+
import { readFile as readFile22, unlink as unlink5 } from "fs/promises";
|
|
10447
10498
|
|
|
10448
10499
|
// src/utils/raw-asset-reference-index.ts
|
|
10449
|
-
import { readdir as
|
|
10450
|
-
import { join as
|
|
10500
|
+
import { readdir as readdir6, readFile as readFile21 } from "fs/promises";
|
|
10501
|
+
import { join as join41, relative as relative6, sep as sep4 } from "path";
|
|
10451
10502
|
var PREVIEW_EXTENSIONS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "webp", "svg", "bmp", "avif", "pdf", "mp3", "wav", "m4a", "mp4", "webm"]);
|
|
10452
10503
|
async function walkFiles(root, dir = root) {
|
|
10453
10504
|
let entries;
|
|
10454
10505
|
try {
|
|
10455
|
-
entries = await
|
|
10506
|
+
entries = await readdir6(dir, { withFileTypes: true });
|
|
10456
10507
|
} catch {
|
|
10457
10508
|
return [];
|
|
10458
10509
|
}
|
|
10459
10510
|
const out = [];
|
|
10460
10511
|
for (const entry of entries) {
|
|
10461
|
-
const path =
|
|
10512
|
+
const path = join41(dir, entry.name);
|
|
10462
10513
|
if (entry.isDirectory()) out.push(...await walkFiles(root, path));
|
|
10463
10514
|
else if (entry.isFile()) out.push(relative6(root, path).split(sep4).join("/"));
|
|
10464
10515
|
}
|
|
@@ -10474,7 +10525,7 @@ function addInbound(map, target, source) {
|
|
|
10474
10525
|
map.set(target, refs);
|
|
10475
10526
|
}
|
|
10476
10527
|
async function buildRawAssetReferenceIndex(vault) {
|
|
10477
|
-
const assetRoot =
|
|
10528
|
+
const assetRoot = join41(vault, "raw", "assets");
|
|
10478
10529
|
const relativeAssets = await walkFiles(assetRoot);
|
|
10479
10530
|
const assets = relativeAssets.map((path) => `raw/assets/${path}`).sort((a, b) => a.localeCompare(b));
|
|
10480
10531
|
const assetSet = new Set(assets);
|
|
@@ -10490,7 +10541,7 @@ async function buildRawAssetReferenceIndex(vault) {
|
|
|
10490
10541
|
for (const page of scan.data.allMarkdown) {
|
|
10491
10542
|
let text;
|
|
10492
10543
|
try {
|
|
10493
|
-
text = await
|
|
10544
|
+
text = await readFile21(page.absPath, "utf8");
|
|
10494
10545
|
} catch {
|
|
10495
10546
|
continue;
|
|
10496
10547
|
}
|
|
@@ -10550,7 +10601,7 @@ async function planSourceDisposal(input) {
|
|
|
10550
10601
|
if (sensitive.length > 0) return err("SENSITIVE_CONTENT_DETECTED", { findings: sensitive });
|
|
10551
10602
|
const target = await resolveExistingRegularFileInsideVault(input.vault, input.rawPath);
|
|
10552
10603
|
if (!target.ok) return err("RAW_DISPOSAL_TARGET_INVALID", { path: input.rawPath, cause: target });
|
|
10553
|
-
const bytes = await
|
|
10604
|
+
const bytes = await readFile22(target.data);
|
|
10554
10605
|
const size = bytes.byteLength;
|
|
10555
10606
|
let typedReferences = [];
|
|
10556
10607
|
let otherReferences = [];
|
|
@@ -10674,7 +10725,7 @@ async function runSourceDisposal(input) {
|
|
|
10674
10725
|
import { existsSync as existsSync15, readFileSync as readFileSync16 } from "fs";
|
|
10675
10726
|
import { execSync as nodeExecSync } from "child_process";
|
|
10676
10727
|
import { hostname as nodeHostname, platform as nodePlatform } from "os";
|
|
10677
|
-
import { join as
|
|
10728
|
+
import { join as join42 } from "path";
|
|
10678
10729
|
var SSH_TIMEOUT_MS = 15e3;
|
|
10679
10730
|
var TIMER_UNIT = "agent-memory-trends.timer";
|
|
10680
10731
|
var SERVICE_UNIT = "agent-memory-trends.service";
|
|
@@ -10904,7 +10955,7 @@ async function runFleetHealth(input) {
|
|
|
10904
10955
|
const home = resolveSkillwikiHome(input.home, env);
|
|
10905
10956
|
const osHostname = input.osHostname ?? env.HOSTNAME ?? nodeHostname();
|
|
10906
10957
|
const vault = input.vault ?? env.WIKI_PATH;
|
|
10907
|
-
const file = input.file ?? (vault ?
|
|
10958
|
+
const file = input.file ?? (vault ? join42(vault, FLEET_REL_PATH) : void 0);
|
|
10908
10959
|
if (!file) {
|
|
10909
10960
|
return {
|
|
10910
10961
|
exitCode: ExitCode.NO_VAULT_CONFIGURED,
|
|
@@ -10989,7 +11040,7 @@ async function runFleetHealth(input) {
|
|
|
10989
11040
|
|
|
10990
11041
|
// src/utils/auto-commit.ts
|
|
10991
11042
|
import { existsSync as existsSync16 } from "fs";
|
|
10992
|
-
import { isAbsolute as isAbsolute3, join as
|
|
11043
|
+
import { isAbsolute as isAbsolute3, join as join43, normalize } from "path";
|
|
10993
11044
|
function isValidLastOpPath(file) {
|
|
10994
11045
|
if (!file || typeof file !== "string") return false;
|
|
10995
11046
|
const trimmed = file.trim();
|
|
@@ -11010,7 +11061,7 @@ async function postCommit(vault, exitCode) {
|
|
|
11010
11061
|
const dotenv = await parseDotenvFile(configPath(home));
|
|
11011
11062
|
const autoCommit = process.env.AUTO_COMMIT ?? dotenv["AUTO_COMMIT"];
|
|
11012
11063
|
if (autoCommit === "false") return;
|
|
11013
|
-
if (!existsSync16(
|
|
11064
|
+
if (!existsSync16(join43(vault, ".git"))) return;
|
|
11014
11065
|
const lastOps = readLastOp(vault);
|
|
11015
11066
|
if (lastOps.length === 0) return;
|
|
11016
11067
|
const porcelain = git(vault, ["status", "--porcelain", "--", ...VAULT_COMMIT_PATHSPEC]);
|
|
@@ -11058,8 +11109,8 @@ function preflight(error) {
|
|
|
11058
11109
|
}
|
|
11059
11110
|
async function runMcpAuthIssueHost(input) {
|
|
11060
11111
|
const isTty = input.isTty ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
11061
|
-
const
|
|
11062
|
-
const
|
|
11112
|
+
const readFile23 = input.readFile ?? readFileSync17;
|
|
11113
|
+
const writeFile9 = input.writeFile ?? writeFileSync8;
|
|
11063
11114
|
const stderrWrite = input.stderrWrite ?? ((s) => {
|
|
11064
11115
|
process.stderr.write(s);
|
|
11065
11116
|
});
|
|
@@ -11073,7 +11124,7 @@ async function runMcpAuthIssueHost(input) {
|
|
|
11073
11124
|
if (write && !isTty) return preflight("NO_TTY");
|
|
11074
11125
|
let yamlText = "";
|
|
11075
11126
|
try {
|
|
11076
|
-
yamlText =
|
|
11127
|
+
yamlText = readFile23(mapPath, "utf8");
|
|
11077
11128
|
} catch (error) {
|
|
11078
11129
|
if (!isEnoent(error)) throw error;
|
|
11079
11130
|
}
|
|
@@ -11095,7 +11146,7 @@ async function runMcpAuthIssueHost(input) {
|
|
|
11095
11146
|
const appended = appendHostHash(yamlText, hashHex, hostId, granted.vaults);
|
|
11096
11147
|
if ("error" in appended) return preflight(appended.error);
|
|
11097
11148
|
try {
|
|
11098
|
-
|
|
11149
|
+
writeFile9(mapPath, appended.yaml, { encoding: "utf8", mode: 416 });
|
|
11099
11150
|
} catch (error) {
|
|
11100
11151
|
if (isEnoent(error)) {
|
|
11101
11152
|
return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND") };
|
|
@@ -11255,7 +11306,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
|
|
|
11255
11306
|
if (dirty) {
|
|
11256
11307
|
return emit(dirty, void 0, { postCommit: false });
|
|
11257
11308
|
}
|
|
11258
|
-
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-
|
|
11309
|
+
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-L7IRQ76C.js");
|
|
11259
11310
|
const run = await runManagedWriteTransaction2({
|
|
11260
11311
|
vault,
|
|
11261
11312
|
command,
|
|
@@ -11285,7 +11336,7 @@ program.command("validate <file>").description("validate vault page frontmatter
|
|
|
11285
11336
|
emit(await runValidate({ file, apply: !!opts.apply, vault }), vault);
|
|
11286
11337
|
});
|
|
11287
11338
|
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 ??
|
|
11339
|
+
const out = opts.out ?? join44(vault, ".skillwiki", "graph.json");
|
|
11289
11340
|
return emitGuardedVaultWrite(vault, "graph build", () => runGraphBuild({ vault, out }));
|
|
11290
11341
|
});
|
|
11291
11342
|
var canvasCmd = program.command("canvas").description("manage Obsidian canvas files");
|
|
@@ -11901,6 +11952,9 @@ program.command("doctor").description("diagnose skillwiki setup issues").option(
|
|
|
11901
11952
|
})));
|
|
11902
11953
|
var clipOutboxCmd = program.command("clip-outbox").description("dedicated file-level web-clip outbox");
|
|
11903
11954
|
clipOutboxCmd.command("status").description("show whether the clip-outbox channel is configured").action(async () => emit(await runClipOutboxStatus(resolveSkillwikiHome())));
|
|
11955
|
+
clipOutboxCmd.command("watch").description("run the enabled dedicated outbox worker using macOS FSEvents").action(async () => emit(await runClipOutboxWatch(resolveSkillwikiHome())));
|
|
11956
|
+
clipOutboxCmd.command("mirror-watch").description("copy admitted raw/articles and raw/assets from storage into the frozen mirror using MCP SSE").action(async () => emit(await runClipOutboxMirrorWatch(resolveSkillwikiHome())));
|
|
11957
|
+
clipOutboxCmd.command("install-or-migrate").description("refresh the packaged launchd plist without enabling the channel").option("--load", "attended clip watcher bootstrap; requires existing enabled=true", false).option("--load-mirror", "attended inbound SSE bootstrap; requires existing enabled=true; never auto-loaded on upgrade", 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, loadMirror: opts.loadMirror, conditionalCreateProven: opts.conditionalCreateProven })));
|
|
11904
11958
|
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
11959
|
home: resolveSkillwikiHome(),
|
|
11906
11960
|
fromFile: opts.fromFile,
|