skillwiki 0.9.33 → 0.9.35
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.
|
@@ -63,7 +63,8 @@ var ExitCode = {
|
|
|
63
63
|
LOG_APPEND_LOCK_HELD: 49,
|
|
64
64
|
FLEET_MANIFEST_INVALID: 50,
|
|
65
65
|
SENSITIVE_CONTENT_DETECTED: 51,
|
|
66
|
-
FLEET_SATELLITE_HEALTH_FAILED: 52
|
|
66
|
+
FLEET_SATELLITE_HEALTH_FAILED: 52,
|
|
67
|
+
PROTECTED_SNAPSHOTTER_WRITE_BLOCKED: 53
|
|
67
68
|
};
|
|
68
69
|
|
|
69
70
|
// ../shared/src/json-output.ts
|
|
@@ -152,6 +153,26 @@ var CompoundSchema = z.object({
|
|
|
152
153
|
promoted_to: wikilink.optional(),
|
|
153
154
|
cssclasses: z.array(z.string()).optional()
|
|
154
155
|
});
|
|
156
|
+
var sessionPinPath = z.string().regex(
|
|
157
|
+
/^(entities|concepts|comparisons|queries|meta)\/.+\.md$/,
|
|
158
|
+
"must reference a typed-knowledge markdown page"
|
|
159
|
+
);
|
|
160
|
+
var SessionPinSchema = z.object({
|
|
161
|
+
title: z.string().min(1),
|
|
162
|
+
path: sessionPinPath,
|
|
163
|
+
scope: z.enum(["global", "project"]),
|
|
164
|
+
project: wikilink.optional(),
|
|
165
|
+
summary: z.string().min(1).optional(),
|
|
166
|
+
updated: isoDate.optional()
|
|
167
|
+
}).superRefine((v, ctx) => {
|
|
168
|
+
if (v.scope === "project" && v.project === void 0) {
|
|
169
|
+
ctx.addIssue({
|
|
170
|
+
code: z.ZodIssueCode.custom,
|
|
171
|
+
path: ["project"],
|
|
172
|
+
message: "project is required when scope is project"
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
});
|
|
155
176
|
var MetaSchema = z.object({
|
|
156
177
|
title: z.string().min(1),
|
|
157
178
|
aliases: z.array(z.string()).optional(),
|
|
@@ -164,9 +185,17 @@ var MetaSchema = z.object({
|
|
|
164
185
|
provenance_projects: z.array(wikilink).optional(),
|
|
165
186
|
generated_by: z.string().min(1).optional(),
|
|
166
187
|
generated_at: z.string().datetime().optional(),
|
|
167
|
-
generated_kind: z.enum(["session-brief"]).optional()
|
|
188
|
+
generated_kind: z.enum(["session-brief"]).optional(),
|
|
189
|
+
meta_kind: z.enum(["session-pins"]).optional(),
|
|
190
|
+
stale_ttl: z.number().int().positive().optional(),
|
|
191
|
+
pins: z.array(SessionPinSchema).optional()
|
|
168
192
|
}).superRefine((v, ctx) => {
|
|
169
|
-
|
|
193
|
+
const isGeneratedSessionBrief = v.generated_kind === "session-brief";
|
|
194
|
+
const isSessionPins = v.meta_kind === "session-pins";
|
|
195
|
+
if (isSessionPins && (!v.pins || v.pins.length === 0)) {
|
|
196
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["pins"], message: "required when meta_kind is session-pins" });
|
|
197
|
+
}
|
|
198
|
+
if (!isGeneratedSessionBrief && !isSessionPins && (!v.provenance_projects || v.provenance_projects.length < 2)) {
|
|
170
199
|
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["provenance_projects"], message: "meta pages must reference \u22652 projects" });
|
|
171
200
|
}
|
|
172
201
|
if (v.provenance && v.provenance !== "research" && (!v.provenance_projects || v.provenance_projects.length === 0)) {
|
|
@@ -4370,7 +4399,7 @@ function formatKnownContext(input) {
|
|
|
4370
4399
|
const selfAliases = collectSelfAliases(input.manifest, input.hostId);
|
|
4371
4400
|
const outbound = collectOutboundAccess(input.manifest, input.hostId);
|
|
4372
4401
|
const maintenanceLines = formatMaintenanceLines(host);
|
|
4373
|
-
const guidance = input.hostId === "macos-dev" ? "use declared SSH aliases for remote work when needed; do not assume undeclared hosts have reciprocal SSH access." : `this session is already on \`${input.hostId}\`; do not SSH to self aliases unless the user explicitly asks. Do not assume outbound SSH to other fleet hosts is configured.`;
|
|
4402
|
+
const guidance = host.role === "snapshotter" && host.protected === true ? `this session is already on \`${input.hostId}\`; this is a protected snapshotter host. Do not mutate the vault or repo-local project workspaces from this session except explicitly approved snapshot maintenance. Use read-only investigation here and route authoring to a leaf host.` : input.hostId === "macos-dev" ? "use declared SSH aliases for remote work when needed; do not assume undeclared hosts have reciprocal SSH access." : `this session is already on \`${input.hostId}\`; do not SSH to self aliases unless the user explicitly asks. Do not assume outbound SSH to other fleet hosts is configured.`;
|
|
4374
4403
|
return [
|
|
4375
4404
|
"## Runtime Host Context",
|
|
4376
4405
|
"",
|
|
@@ -8848,6 +8877,7 @@ export {
|
|
|
8848
8877
|
ok,
|
|
8849
8878
|
err,
|
|
8850
8879
|
TypedKnowledgeSchema,
|
|
8880
|
+
MetaSchema,
|
|
8851
8881
|
detectSchema,
|
|
8852
8882
|
isBlockedHost,
|
|
8853
8883
|
splitFrontmatter,
|
|
@@ -8899,6 +8929,7 @@ export {
|
|
|
8899
8929
|
FLEET_REL_PATH,
|
|
8900
8930
|
runFleetValidate,
|
|
8901
8931
|
runFleetContext,
|
|
8932
|
+
loadFleetManifestAndHost,
|
|
8902
8933
|
loadFleetManifest,
|
|
8903
8934
|
resolveFleetHostId,
|
|
8904
8935
|
SATELLITE_STALE_MS,
|
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ExitCode,
|
|
4
4
|
FLEET_REL_PATH,
|
|
5
|
+
MetaSchema,
|
|
5
6
|
SATELLITE_STALE_MS,
|
|
6
7
|
TypedKnowledgeSchema,
|
|
7
8
|
appendLastOp,
|
|
@@ -21,6 +22,7 @@ import {
|
|
|
21
22
|
isFailedRunStatus,
|
|
22
23
|
isValidRemoteDeleteCap,
|
|
23
24
|
loadFleetManifest,
|
|
25
|
+
loadFleetManifestAndHost,
|
|
24
26
|
normalizeRemoteRoot,
|
|
25
27
|
ok,
|
|
26
28
|
parseDotenvFile,
|
|
@@ -73,7 +75,7 @@ import {
|
|
|
73
75
|
triggerAutoUpdate,
|
|
74
76
|
writeCache,
|
|
75
77
|
writeDotenv
|
|
76
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-TK4ZIQNE.js";
|
|
77
79
|
import {
|
|
78
80
|
normalizeDistTag
|
|
79
81
|
} from "./chunk-E6UWZ3S3.js";
|
|
@@ -2386,14 +2388,27 @@ async function runSessionBrief(input) {
|
|
|
2386
2388
|
const today = generatedAt.slice(0, 10);
|
|
2387
2389
|
const project = await resolveProject(input);
|
|
2388
2390
|
try {
|
|
2389
|
-
const
|
|
2390
|
-
|
|
2391
|
-
|
|
2391
|
+
const [
|
|
2392
|
+
transcripts,
|
|
2393
|
+
workItems,
|
|
2394
|
+
digests,
|
|
2395
|
+
baseHealthWarnings,
|
|
2396
|
+
satelliteHealth,
|
|
2397
|
+
sessionPins,
|
|
2398
|
+
memoryTopics
|
|
2399
|
+
] = await Promise.all([
|
|
2400
|
+
loadTranscriptInfo(scan.data.raw),
|
|
2401
|
+
loadWorkItems(scan.data.workItems),
|
|
2402
|
+
loadTrendDigests(scan.data.typedKnowledge),
|
|
2403
|
+
loadHealthWarnings(input.vault),
|
|
2404
|
+
loadSatelliteHealth(input.vault),
|
|
2405
|
+
loadSessionPins(input.vault, project),
|
|
2406
|
+
project ? loadMemoryTopics(input.vault, project) : Promise.resolve([])
|
|
2407
|
+
]);
|
|
2392
2408
|
const healthWarnings = [
|
|
2393
|
-
...
|
|
2394
|
-
...satelliteHealthWarnings(
|
|
2409
|
+
...baseHealthWarnings,
|
|
2410
|
+
...satelliteHealthWarnings(satelliteHealth)
|
|
2395
2411
|
];
|
|
2396
|
-
const memoryTopics = project ? await loadMemoryTopics(input.vault, project) : [];
|
|
2397
2412
|
const latestLogs = newest(transcripts.filter((t) => t.kind === "session-log"), 3);
|
|
2398
2413
|
const unclaimedCaptures = newest(transcripts.filter((t) => {
|
|
2399
2414
|
if (t.kind !== "task" && t.kind !== "bug") return false;
|
|
@@ -2408,6 +2423,7 @@ async function runSessionBrief(input) {
|
|
|
2408
2423
|
const brief = capWords(renderBrief({
|
|
2409
2424
|
project,
|
|
2410
2425
|
generatedAt,
|
|
2426
|
+
sessionPins,
|
|
2411
2427
|
latestLogs,
|
|
2412
2428
|
unclaimedCaptures,
|
|
2413
2429
|
activeWork,
|
|
@@ -2443,6 +2459,7 @@ async function runSessionBrief(input) {
|
|
|
2443
2459
|
index_updated: indexUpdated,
|
|
2444
2460
|
log_updated: logUpdated,
|
|
2445
2461
|
generated_at: generatedAt,
|
|
2462
|
+
session_pins: sessionPins,
|
|
2446
2463
|
memory_topics: memoryTopics,
|
|
2447
2464
|
humanHint
|
|
2448
2465
|
})
|
|
@@ -2544,6 +2561,29 @@ async function loadTrendDigests(typedPages) {
|
|
|
2544
2561
|
}
|
|
2545
2562
|
return out;
|
|
2546
2563
|
}
|
|
2564
|
+
async function loadSessionPins(vault, project) {
|
|
2565
|
+
const text = await readIfExists(join15(vault, "meta", "session-pins.md"));
|
|
2566
|
+
if (!text) return [];
|
|
2567
|
+
const fm = extractFrontmatter(text);
|
|
2568
|
+
if (!fm.ok) return [];
|
|
2569
|
+
const parsed = MetaSchema.safeParse(fm.data);
|
|
2570
|
+
if (!parsed.success || parsed.data.meta_kind !== "session-pins") return [];
|
|
2571
|
+
const registryUpdated = parsed.data.updated;
|
|
2572
|
+
const out = [];
|
|
2573
|
+
for (const pin of parsed.data.pins ?? []) {
|
|
2574
|
+
const pinProject = wikilinkSlug(pin.project);
|
|
2575
|
+
if (pin.scope === "project" && (!project || pinProject !== project)) continue;
|
|
2576
|
+
out.push({
|
|
2577
|
+
path: pin.path,
|
|
2578
|
+
title: pin.title,
|
|
2579
|
+
summary: pin.summary ?? "",
|
|
2580
|
+
date: pin.updated ?? registryUpdated,
|
|
2581
|
+
project: pinProject,
|
|
2582
|
+
kind: "session-pin"
|
|
2583
|
+
});
|
|
2584
|
+
}
|
|
2585
|
+
return newest(out, 5);
|
|
2586
|
+
}
|
|
2547
2587
|
function renderBrief(input) {
|
|
2548
2588
|
const lines = [
|
|
2549
2589
|
"# Session Brief",
|
|
@@ -2552,6 +2592,7 @@ function renderBrief(input) {
|
|
|
2552
2592
|
`Scope: ${input.project ? `[[${input.project}]] plus global context` : "global context"}`,
|
|
2553
2593
|
""
|
|
2554
2594
|
];
|
|
2595
|
+
appendPinnedContextSection(lines, input.sessionPins);
|
|
2555
2596
|
appendSection(lines, "Active Work", input.activeWork, "No active project work found.");
|
|
2556
2597
|
appendSection(lines, "Unclaimed Captures", input.unclaimedCaptures, "No unclaimed task or bug captures found.");
|
|
2557
2598
|
appendSection(lines, "Recent Session Logs", input.project ? input.projectLogs : input.latestLogs, "No recent session logs found.");
|
|
@@ -2577,6 +2618,16 @@ function appendMemoryTopicsSection(lines, project, topics) {
|
|
|
2577
2618
|
}
|
|
2578
2619
|
lines.push("");
|
|
2579
2620
|
}
|
|
2621
|
+
function appendPinnedContextSection(lines, pins) {
|
|
2622
|
+
if (pins.length === 0) return;
|
|
2623
|
+
lines.push("## Pinned Context", "");
|
|
2624
|
+
for (const pin of pins) {
|
|
2625
|
+
const date = pin.date ? `${pin.date} ` : "";
|
|
2626
|
+
const summary = pin.summary ? ` \u2014 ${pin.summary}` : "";
|
|
2627
|
+
lines.push(`- ${date}${pin.title} (${pin.path})${summary}`);
|
|
2628
|
+
}
|
|
2629
|
+
lines.push("");
|
|
2630
|
+
}
|
|
2580
2631
|
function appendSection(lines, title, items, empty) {
|
|
2581
2632
|
lines.push(`## ${title}`, "");
|
|
2582
2633
|
if (items.length === 0) {
|
|
@@ -4704,6 +4755,36 @@ async function postCommit(vault, exitCode) {
|
|
|
4704
4755
|
clearLastOp(vault);
|
|
4705
4756
|
}
|
|
4706
4757
|
|
|
4758
|
+
// src/utils/protected-vault-write-guard.ts
|
|
4759
|
+
async function guardProtectedVaultWrite(input) {
|
|
4760
|
+
const load = await loadFleetManifestAndHost({
|
|
4761
|
+
vault: input.vault,
|
|
4762
|
+
hostId: input.hostId,
|
|
4763
|
+
env: input.env ?? process.env,
|
|
4764
|
+
home: input.home ?? process.env.HOME ?? "",
|
|
4765
|
+
cwd: input.cwd ?? process.cwd(),
|
|
4766
|
+
osHostname: input.osHostname ?? process.env.HOSTNAME,
|
|
4767
|
+
user: input.user ?? process.env.USER
|
|
4768
|
+
});
|
|
4769
|
+
if (!load?.hostId || load.identityStatus !== "known") {
|
|
4770
|
+
return { blocked: false };
|
|
4771
|
+
}
|
|
4772
|
+
const host = load.manifest.hosts[load.hostId];
|
|
4773
|
+
if (!host || host.role !== "snapshotter" || host.protected !== true) {
|
|
4774
|
+
return { blocked: false };
|
|
4775
|
+
}
|
|
4776
|
+
return {
|
|
4777
|
+
blocked: true,
|
|
4778
|
+
exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED,
|
|
4779
|
+
result: err("PROTECTED_SNAPSHOTTER_WRITE_BLOCKED", {
|
|
4780
|
+
host_id: load.hostId,
|
|
4781
|
+
command: input.command,
|
|
4782
|
+
reason: `refusing vault mutation from protected snapshotter host '${load.hostId}'`,
|
|
4783
|
+
guidance: "Use a leaf authoring host for vault/project writes. Keep protected snapshotter sessions read-only except explicit snapshot maintenance."
|
|
4784
|
+
})
|
|
4785
|
+
};
|
|
4786
|
+
}
|
|
4787
|
+
|
|
4707
4788
|
// src/cli.ts
|
|
4708
4789
|
var pkg = readCliPackageJson();
|
|
4709
4790
|
var program = new Command();
|
|
@@ -4715,6 +4796,21 @@ async function emit(r, vault, opts) {
|
|
|
4715
4796
|
if (vault && opts?.postCommit !== false) await postCommit(vault, r.exitCode);
|
|
4716
4797
|
process.exit(r.exitCode);
|
|
4717
4798
|
}
|
|
4799
|
+
async function emitGuardedVaultWrite(vault, command, run, opts) {
|
|
4800
|
+
const guard = await guardProtectedVaultWrite({
|
|
4801
|
+
vault,
|
|
4802
|
+
command,
|
|
4803
|
+
env: process.env,
|
|
4804
|
+
home: process.env.HOME ?? "",
|
|
4805
|
+
cwd: process.cwd(),
|
|
4806
|
+
osHostname: process.env.HOSTNAME,
|
|
4807
|
+
user: process.env.USER
|
|
4808
|
+
});
|
|
4809
|
+
if (guard.blocked) {
|
|
4810
|
+
return emit({ exitCode: guard.exitCode, result: guard.result }, void 0, { postCommit: false });
|
|
4811
|
+
}
|
|
4812
|
+
return emit(await run(), vault, opts);
|
|
4813
|
+
}
|
|
4718
4814
|
program.command("hash <file>").description("compute SHA-256 hash of a vault page body").action(async (file) => emit(await runHash({ file })));
|
|
4719
4815
|
program.command("fetch-guard <url>").description("check if a URL passes fetch guard rules and sanitize secrets").action(async (url) => emit(await runFetchGuard({ url })));
|
|
4720
4816
|
program.command("validate <file>").description("validate vault page frontmatter against its detected schema").option("--apply", "auto-update vault index.md and log.md after successful validation", false).option("--vault <dir>", "vault root directory (required with --apply)").option("--wiki <name>", "wiki profile name").action(async (file, opts) => {
|
|
@@ -4724,17 +4820,20 @@ program.command("validate <file>").description("validate vault page frontmatter
|
|
|
4724
4820
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4725
4821
|
else vault = v.vault;
|
|
4726
4822
|
}
|
|
4823
|
+
if (opts.apply && vault) {
|
|
4824
|
+
return emitGuardedVaultWrite(vault, "validate --apply", () => runValidate({ file, apply: true, vault }), void 0);
|
|
4825
|
+
}
|
|
4727
4826
|
emit(await runValidate({ file, apply: !!opts.apply, vault }), vault);
|
|
4728
4827
|
});
|
|
4729
4828
|
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) => {
|
|
4730
4829
|
const out = opts.out ?? join25(vault, ".skillwiki", "graph.json");
|
|
4731
|
-
|
|
4830
|
+
return emitGuardedVaultWrite(vault, "graph build", () => runGraphBuild({ vault, out }));
|
|
4732
4831
|
});
|
|
4733
4832
|
var canvasCmd = program.command("canvas").description("manage Obsidian canvas files");
|
|
4734
4833
|
canvasCmd.command("generate [vault]").description("generate .canvas from graph.json").option("--graph-path <path>", "explicit path to graph.json").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4735
4834
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4736
4835
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4737
|
-
else
|
|
4836
|
+
else return emitGuardedVaultWrite(v.vault, "canvas generate", () => runCanvasGenerate({ vault: v.vault, graphPath: opts.graphPath }));
|
|
4738
4837
|
});
|
|
4739
4838
|
program.command("overlap [vault]").description("detect typed-knowledge pages that share the same raw sources").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4740
4839
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
@@ -4836,12 +4935,21 @@ program.command("topic-map-check [vault]").description("check whether a topic ma
|
|
|
4836
4935
|
program.command("stale [vault]").description("identify stale transcripts and incomplete work items").option("--archive", "move stale items to _archive/", false).option("--days <n>", "staleness threshold in days", (s) => parseInt(s, 10), 3).option("--force-scan", "infer kind/project from filename and content when frontmatter is missing", false).option("--project <slug>", "scope to a single project").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4837
4936
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4838
4937
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4839
|
-
else
|
|
4938
|
+
else if (opts.archive) return emitGuardedVaultWrite(
|
|
4939
|
+
v.vault,
|
|
4940
|
+
"stale --archive",
|
|
4941
|
+
() => runStale({ vault: v.vault, days: opts.days, archive: true, forceScan: !!opts.forceScan, project: opts.project })
|
|
4942
|
+
);
|
|
4943
|
+
else emit(await runStale({ vault: v.vault, days: opts.days, archive: false, forceScan: !!opts.forceScan, project: opts.project }), v.vault);
|
|
4840
4944
|
});
|
|
4841
4945
|
program.command("claim <transcript> [vault]").description("claim an unclaimed transcript by creating a work item with source: link").option("--project <slug>", "project slug (overrides transcript frontmatter)").option("--slug <slug>", "work-item slug (defaults to transcript filename without date/kind prefix)").option("--wiki <name>", "wiki profile name").action(async (transcript, vault, opts) => {
|
|
4842
4946
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4843
4947
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4844
|
-
else
|
|
4948
|
+
else return emitGuardedVaultWrite(
|
|
4949
|
+
v.vault,
|
|
4950
|
+
"claim",
|
|
4951
|
+
() => runClaim({ vault: v.vault, transcript, project: opts.project, slug: opts.slug })
|
|
4952
|
+
);
|
|
4845
4953
|
});
|
|
4846
4954
|
program.command("pagesize [vault]").description("report page sizes and flag oversized pages").option("--lines <n>", "max body lines", (s) => parseInt(s, 10), 200).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4847
4955
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
@@ -4851,23 +4959,47 @@ program.command("pagesize [vault]").description("report page sizes and flag over
|
|
|
4851
4959
|
program.command("log-rotate [vault]").description("rotate or trim the vault log file").option("--threshold <n>", "entry count threshold", (s) => parseInt(s, 10), 500).option("--apply", "actually rotate", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4852
4960
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4853
4961
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4854
|
-
else
|
|
4962
|
+
else if (opts.apply) return emitGuardedVaultWrite(
|
|
4963
|
+
v.vault,
|
|
4964
|
+
"log-rotate --apply",
|
|
4965
|
+
() => runLogRotate({ vault: v.vault, threshold: opts.threshold, apply: true })
|
|
4966
|
+
);
|
|
4967
|
+
else emit(await runLogRotate({ vault: v.vault, threshold: opts.threshold, apply: false }), v.vault);
|
|
4855
4968
|
});
|
|
4856
4969
|
program.command("log-append [vault]").description("append a single entry to the vault log under a short advisory lock").requiredOption("--content <text>", "log entry text to append").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4857
4970
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4858
4971
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4859
|
-
else
|
|
4972
|
+
else return emitGuardedVaultWrite(
|
|
4973
|
+
v.vault,
|
|
4974
|
+
"log-append",
|
|
4975
|
+
() => runLogAppend({ vault: v.vault, content: opts.content })
|
|
4976
|
+
);
|
|
4860
4977
|
});
|
|
4861
4978
|
program.command("lint [vault]").description("run all vault health checks").option("--days <n>", "stale threshold", (s) => parseInt(s, 10), 90).option("--lines <n>", "pagesize threshold", (s) => parseInt(s, 10), 200).option("--log-threshold <n>", "log rotation threshold", (s) => parseInt(s, 10), 500).option("--fix", "auto-fix supported lint violations").option("--only <bucket>", "run only the specified lint bucket").option("--summary", "emit bounded bucket counts instead of full item arrays", false).option("--examples <n>", "example count per bucket in summary mode", (s) => parseInt(s, 10), 3).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4862
4979
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4863
4980
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4981
|
+
else if (opts.fix) return emitGuardedVaultWrite(
|
|
4982
|
+
v.vault,
|
|
4983
|
+
"lint --fix",
|
|
4984
|
+
() => runLint({
|
|
4985
|
+
vault: v.vault,
|
|
4986
|
+
source: vault ? "flag" : void 0,
|
|
4987
|
+
days: opts.days,
|
|
4988
|
+
lines: opts.lines,
|
|
4989
|
+
logThreshold: opts.logThreshold,
|
|
4990
|
+
fix: true,
|
|
4991
|
+
only: opts.only,
|
|
4992
|
+
summary: !!opts.summary,
|
|
4993
|
+
examplesLimit: opts.summary ? opts.examples : void 0
|
|
4994
|
+
})
|
|
4995
|
+
);
|
|
4864
4996
|
else if (opts.summary) emit(await runLint({
|
|
4865
4997
|
vault: v.vault,
|
|
4866
4998
|
source: vault ? "flag" : void 0,
|
|
4867
4999
|
days: opts.days,
|
|
4868
5000
|
lines: opts.lines,
|
|
4869
5001
|
logThreshold: opts.logThreshold,
|
|
4870
|
-
fix:
|
|
5002
|
+
fix: false,
|
|
4871
5003
|
only: opts.only,
|
|
4872
5004
|
summary: true,
|
|
4873
5005
|
examplesLimit: opts.examples
|
|
@@ -4878,7 +5010,7 @@ program.command("lint [vault]").description("run all vault health checks").optio
|
|
|
4878
5010
|
days: opts.days,
|
|
4879
5011
|
lines: opts.lines,
|
|
4880
5012
|
logThreshold: opts.logThreshold,
|
|
4881
|
-
fix:
|
|
5013
|
+
fix: false,
|
|
4882
5014
|
only: opts.only
|
|
4883
5015
|
}), v.vault);
|
|
4884
5016
|
});
|
|
@@ -4927,24 +5059,56 @@ program.command("status [vault]").description("output vault diagnostics").option
|
|
|
4927
5059
|
program.command("archive <page> [vault]").description("archive a typed-knowledge or raw page").option("--wiki <name>", "wiki profile name").option("--cascade", "scan vault for references (wikilinks + sources arrays); preview by default", false).option("--apply", "with --cascade: mutate sources arrays and archive (without --apply, --cascade is preview-only)", false).option("--remote <remote>", "rclone remote root to prune the archived source path, for example seaweed-wiki:cloud/wiki").option("--remote-delete", "delete the archived source path from the remote after local archive", false).option("--max-remote-deletes <n>", "maximum remote object deletes allowed", "1").action(async (page, vault, opts) => {
|
|
4928
5060
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4929
5061
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4930
|
-
else emit(await runArchive({
|
|
5062
|
+
else if (opts.cascade && !opts.apply) emit(await runArchive({
|
|
4931
5063
|
vault: v.vault,
|
|
4932
5064
|
page,
|
|
4933
|
-
cascade:
|
|
4934
|
-
apply:
|
|
5065
|
+
cascade: true,
|
|
5066
|
+
apply: false,
|
|
4935
5067
|
remote: opts.remote,
|
|
4936
5068
|
remoteDelete: !!opts.remoteDelete,
|
|
4937
5069
|
maxRemoteDeletes: Number.parseInt(opts.maxRemoteDeletes, 10)
|
|
4938
5070
|
}), v.vault);
|
|
5071
|
+
else return emitGuardedVaultWrite(
|
|
5072
|
+
v.vault,
|
|
5073
|
+
"archive",
|
|
5074
|
+
() => runArchive({
|
|
5075
|
+
vault: v.vault,
|
|
5076
|
+
page,
|
|
5077
|
+
cascade: !!opts.cascade,
|
|
5078
|
+
apply: !!opts.apply,
|
|
5079
|
+
remote: opts.remote,
|
|
5080
|
+
remoteDelete: !!opts.remoteDelete,
|
|
5081
|
+
maxRemoteDeletes: Number.parseInt(opts.maxRemoteDeletes, 10)
|
|
5082
|
+
})
|
|
5083
|
+
);
|
|
4939
5084
|
});
|
|
4940
5085
|
program.command("drift [vault]").description("detect content drift in raw sources").option("--apply", "update sha256 in drifted sources").option("--new <date>", "list raw files ingested on/after this date (YYYY-MM-DD)").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4941
5086
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4942
5087
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4943
|
-
else
|
|
5088
|
+
else if (opts.apply) return emitGuardedVaultWrite(
|
|
5089
|
+
v.vault,
|
|
5090
|
+
"drift --apply",
|
|
5091
|
+
() => runDrift({ vault: v.vault, apply: true, newSince: opts.new })
|
|
5092
|
+
);
|
|
5093
|
+
else emit(await runDrift({ vault: v.vault, apply: false, newSince: opts.new }), v.vault);
|
|
4944
5094
|
});
|
|
4945
5095
|
program.command("dedup [vault]").description("detect duplicate raw sources by sha256").option("--apply", "rewire citations and remove duplicate raw files", false).option("--canonical-policy <policy>", "canonical policy: stable-path or scan-order", "stable-path").option("--manifest-out <path>", "write raw dedup delete manifest before applying").option("--manifest-in <path>", "read existing raw dedup delete manifest for remote pruning").option("--remote <remote>", "rclone remote root, for example seaweed-wiki:cloud/wiki").option("--remote-delete", "delete manifest duplicate paths from the remote", false).option("--max-remote-deletes <n>", "maximum remote object deletes allowed", "50").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4946
5096
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4947
5097
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5098
|
+
else if (opts.apply || opts.manifestOut) return emitGuardedVaultWrite(
|
|
5099
|
+
v.vault,
|
|
5100
|
+
opts.apply ? "dedup --apply" : "dedup --manifest-out",
|
|
5101
|
+
() => runDedup({
|
|
5102
|
+
vault: v.vault,
|
|
5103
|
+
apply: opts.apply,
|
|
5104
|
+
canonicalPolicy: opts.canonicalPolicy,
|
|
5105
|
+
manifestOut: opts.manifestOut,
|
|
5106
|
+
manifestIn: opts.manifestIn,
|
|
5107
|
+
remote: opts.remote,
|
|
5108
|
+
remoteDelete: !!opts.remoteDelete,
|
|
5109
|
+
maxRemoteDeletes: Number.parseInt(opts.maxRemoteDeletes, 10)
|
|
5110
|
+
})
|
|
5111
|
+
);
|
|
4948
5112
|
else emit(await runDedup({
|
|
4949
5113
|
vault: v.vault,
|
|
4950
5114
|
apply: opts.apply,
|
|
@@ -4959,12 +5123,22 @@ program.command("dedup [vault]").description("detect duplicate raw sources by sh
|
|
|
4959
5123
|
program.command("migrate-citations [vault]").description("migrate ^[raw/...] markers to paragraph-end citations").option("--dry-run", "preview changes without writing", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4960
5124
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4961
5125
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4962
|
-
else emit(await runMigrateCitations({ vault: v.vault, dryRun:
|
|
5126
|
+
else if (opts.dryRun) emit(await runMigrateCitations({ vault: v.vault, dryRun: true }), v.vault);
|
|
5127
|
+
else return emitGuardedVaultWrite(
|
|
5128
|
+
v.vault,
|
|
5129
|
+
"migrate-citations",
|
|
5130
|
+
() => runMigrateCitations({ vault: v.vault, dryRun: false })
|
|
5131
|
+
);
|
|
4963
5132
|
});
|
|
4964
5133
|
program.command("frontmatter-fix [vault]").description("fix common frontmatter issues on typed-knowledge pages").option("--dry-run", "preview changes without writing", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4965
5134
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4966
5135
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4967
|
-
else emit(await runFrontmatterFix({ vault: v.vault, dryRun:
|
|
5136
|
+
else if (opts.dryRun) emit(await runFrontmatterFix({ vault: v.vault, dryRun: true }), v.vault);
|
|
5137
|
+
else return emitGuardedVaultWrite(
|
|
5138
|
+
v.vault,
|
|
5139
|
+
"frontmatter-fix",
|
|
5140
|
+
() => runFrontmatterFix({ vault: v.vault, dryRun: false })
|
|
5141
|
+
);
|
|
4968
5142
|
});
|
|
4969
5143
|
program.command("update").description("update skillwiki CLI from npm dist-tag").option("--tag <tag>", "npm dist-tag", "latest").action(async (opts) => emit(await runUpdate({
|
|
4970
5144
|
home: process.env.HOME ?? "",
|
|
@@ -4983,13 +5157,23 @@ program.command("transcripts [vault]").description("list transcript files in raw
|
|
|
4983
5157
|
program.command("project-index <slug> [vault]").description("generate a knowledge index for a project workspace").option("--apply", "write knowledge.md to the project directory", false).option("--wiki <name>", "wiki profile name").action(async (slug, vault, opts) => {
|
|
4984
5158
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4985
5159
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4986
|
-
else
|
|
5160
|
+
else if (opts.apply) return emitGuardedVaultWrite(
|
|
5161
|
+
v.vault,
|
|
5162
|
+
"project-index --apply",
|
|
5163
|
+
() => runProjectIndex({ vault: v.vault, slug, apply: true })
|
|
5164
|
+
);
|
|
5165
|
+
else emit(await runProjectIndex({ vault: v.vault, slug, apply: false }), v.vault);
|
|
4987
5166
|
});
|
|
4988
5167
|
var compoundCmd = program.command("compound").description("manage project compound entries");
|
|
4989
5168
|
compoundCmd.command("promote [vault]").description("promote retros with Generalize?: yes to compound entries").requiredOption("--project <slug>", "project slug (e.g., llm-wiki)").option("--dry-run", "preview promotions without writing files", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4990
5169
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
4991
5170
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
4992
|
-
else emit(await runCompound({ vault: v.vault, project: opts.project, dryRun:
|
|
5171
|
+
else if (opts.dryRun) emit(await runCompound({ vault: v.vault, project: opts.project, dryRun: true }), v.vault);
|
|
5172
|
+
else return emitGuardedVaultWrite(
|
|
5173
|
+
v.vault,
|
|
5174
|
+
"compound promote",
|
|
5175
|
+
() => runCompound({ vault: v.vault, project: opts.project, dryRun: false })
|
|
5176
|
+
);
|
|
4993
5177
|
});
|
|
4994
5178
|
compoundCmd.command("list [vault]").description("list compound entries for a project").requiredOption("--project <slug>", "project slug (e.g., llm-wiki)").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
4995
5179
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
@@ -4999,12 +5183,21 @@ compoundCmd.command("list [vault]").description("list compound entries for a pro
|
|
|
4999
5183
|
compoundCmd.command("delete <entry> [vault]").description("delete a compound entry and regenerate knowledge index").requiredOption("--project <slug>", "project slug (e.g., llm-wiki)").option("--wiki <name>", "wiki profile name").action(async (entry, vault, opts) => {
|
|
5000
5184
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
5001
5185
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5002
|
-
else
|
|
5186
|
+
else return emitGuardedVaultWrite(
|
|
5187
|
+
v.vault,
|
|
5188
|
+
"compound delete",
|
|
5189
|
+
() => runCompoundDelete({ vault: v.vault, project: opts.project, entry })
|
|
5190
|
+
);
|
|
5003
5191
|
});
|
|
5004
5192
|
program.command("tag-sync [vault]").description("mirror frontmatter enum values to nested Obsidian tags").option("--dry-run", "preview changes without writing", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5005
5193
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
5006
5194
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5007
|
-
else emit(await runTagSync({ vault: v.vault, dryRun:
|
|
5195
|
+
else if (opts.dryRun) emit(await runTagSync({ vault: v.vault, dryRun: true }), v.vault);
|
|
5196
|
+
else return emitGuardedVaultWrite(
|
|
5197
|
+
v.vault,
|
|
5198
|
+
"tag-sync",
|
|
5199
|
+
() => runTagSync({ vault: v.vault, dryRun: false })
|
|
5200
|
+
);
|
|
5008
5201
|
});
|
|
5009
5202
|
var syncCmd = program.command("sync").description("manage vault sync");
|
|
5010
5203
|
syncCmd.command("status [vault]").description("check vault git sync status").option("--wiki <name>", "wiki profile name").option("--include-stashes", "enumerate all stashes in output", false).action(async (vault, opts) => {
|
|
@@ -5015,25 +5208,41 @@ syncCmd.command("status [vault]").description("check vault git sync status").opt
|
|
|
5015
5208
|
syncCmd.command("push [vault]").description("lint, commit, and push vault changes to remote").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5016
5209
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
5017
5210
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5018
|
-
else
|
|
5211
|
+
else return emitGuardedVaultWrite(
|
|
5212
|
+
v.vault,
|
|
5213
|
+
"sync push",
|
|
5214
|
+
() => runSyncPush({ vault: v.vault })
|
|
5215
|
+
);
|
|
5019
5216
|
});
|
|
5020
5217
|
syncCmd.command("pull [vault]").description("pull remote vault changes and lint").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5021
5218
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
5022
5219
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5023
|
-
else
|
|
5220
|
+
else return emitGuardedVaultWrite(
|
|
5221
|
+
v.vault,
|
|
5222
|
+
"sync pull",
|
|
5223
|
+
() => runSyncPull({ vault: v.vault })
|
|
5224
|
+
);
|
|
5024
5225
|
});
|
|
5025
5226
|
syncCmd.command("lock [vault]").description("acquire advisory lock on vault").option("--summary <text>", "lock description", "skillwiki sync").option("--ttl-minutes <n>", "lock time-to-live in minutes", "30").option("--force", "overwrite existing lock", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5026
5227
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
5027
5228
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5028
5229
|
else {
|
|
5029
5230
|
const ttl = parseInt(opts.ttlMinutes, 10) || 30;
|
|
5030
|
-
|
|
5231
|
+
return emitGuardedVaultWrite(
|
|
5232
|
+
v.vault,
|
|
5233
|
+
"sync lock",
|
|
5234
|
+
async () => runSyncLock({ vault: v.vault, summary: opts.summary, ttlMinutes: ttl, force: !!opts.force, sessionId: getCliSessionId() })
|
|
5235
|
+
);
|
|
5031
5236
|
}
|
|
5032
5237
|
});
|
|
5033
5238
|
syncCmd.command("unlock [vault]").description("release advisory lock on vault").option("--force", "release lock regardless of holder", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5034
5239
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
5035
5240
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5036
|
-
else
|
|
5241
|
+
else return emitGuardedVaultWrite(
|
|
5242
|
+
v.vault,
|
|
5243
|
+
"sync unlock",
|
|
5244
|
+
async () => runSyncUnlock({ vault: v.vault, force: !!opts.force, sessionId: getCliSessionId() })
|
|
5245
|
+
);
|
|
5037
5246
|
});
|
|
5038
5247
|
syncCmd.command("peers [vault]").description("list active locks and recent wiki-sync stashes").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5039
5248
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
@@ -5068,41 +5277,65 @@ backupCmd.command("restore [vault]").description("restore vault from S3-compatib
|
|
|
5068
5277
|
}
|
|
5069
5278
|
const home = process.env.HOME ?? process.env.USERPROFILE ?? "/tmp";
|
|
5070
5279
|
const dotenv = await parseDotenvFile(configPath(home));
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5280
|
+
return emitGuardedVaultWrite(
|
|
5281
|
+
v.vault,
|
|
5282
|
+
"backup restore",
|
|
5283
|
+
() => runBackupRestore({
|
|
5284
|
+
vault: v.vault,
|
|
5285
|
+
bucket: opts.bucket ?? dotenv["BACKUP_BUCKET"] ?? "",
|
|
5286
|
+
endpoint: opts.endpoint ?? dotenv["BACKUP_ENDPOINT"] ?? "",
|
|
5287
|
+
region: opts.region ?? dotenv["BACKUP_REGION"] ?? "us-east-1",
|
|
5288
|
+
accessKeyId: dotenv["BACKUP_ACCESS_KEY_ID"] ?? "",
|
|
5289
|
+
secretAccessKey: dotenv["BACKUP_SECRET_ACCESS_KEY"] ?? "",
|
|
5290
|
+
target: opts.target
|
|
5291
|
+
})
|
|
5292
|
+
);
|
|
5080
5293
|
});
|
|
5081
5294
|
program.command("seed [vault]").description("populate a vault with example content").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5082
5295
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
5083
5296
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5084
|
-
else
|
|
5297
|
+
else return emitGuardedVaultWrite(
|
|
5298
|
+
v.vault,
|
|
5299
|
+
"seed",
|
|
5300
|
+
() => runSeed({ vault: v.vault })
|
|
5301
|
+
);
|
|
5085
5302
|
});
|
|
5086
5303
|
program.command("observe [vault]").description("create a raw transcript observation entry").requiredOption("--text <text>", "observation text").option("--kind <kind>", "observation kind (note|bug|task|idea|session-log)", "task").option("--project <slug>", "associated project slug (required for task/bug claim detection)").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5087
5304
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
5088
5305
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5089
|
-
else
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5306
|
+
else return emitGuardedVaultWrite(
|
|
5307
|
+
v.vault,
|
|
5308
|
+
"observe",
|
|
5309
|
+
() => runObserve({
|
|
5310
|
+
vault: v.vault,
|
|
5311
|
+
text: opts.text,
|
|
5312
|
+
kind: opts.kind,
|
|
5313
|
+
project: opts.project
|
|
5314
|
+
})
|
|
5315
|
+
);
|
|
5095
5316
|
});
|
|
5096
5317
|
program.command("session-brief [vault]").description("render or refresh the bounded startup session brief").option("--project <slug>", "project slug, or auto for deterministic detection", "auto").option("--write", "write meta/latest-session-brief.md and local cache files", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5097
5318
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
5098
5319
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5320
|
+
else if (opts.write) return emitGuardedVaultWrite(
|
|
5321
|
+
v.vault,
|
|
5322
|
+
"session-brief --write",
|
|
5323
|
+
() => runSessionBrief({
|
|
5324
|
+
vault: v.vault,
|
|
5325
|
+
project: opts.project,
|
|
5326
|
+
write: true,
|
|
5327
|
+
cwd: process.cwd(),
|
|
5328
|
+
env: { SKILLWIKI_PROJECT: process.env.SKILLWIKI_PROJECT }
|
|
5329
|
+
}),
|
|
5330
|
+
{ postCommit: true }
|
|
5331
|
+
);
|
|
5099
5332
|
else emit(await runSessionBrief({
|
|
5100
5333
|
vault: v.vault,
|
|
5101
5334
|
project: opts.project,
|
|
5102
|
-
write:
|
|
5335
|
+
write: false,
|
|
5103
5336
|
cwd: process.cwd(),
|
|
5104
5337
|
env: { SKILLWIKI_PROJECT: process.env.SKILLWIKI_PROJECT }
|
|
5105
|
-
}), v.vault, { postCommit:
|
|
5338
|
+
}), v.vault, { postCommit: false });
|
|
5106
5339
|
});
|
|
5107
5340
|
var memoryCmd = program.command("memory").description("inspect derived agent memory caches");
|
|
5108
5341
|
memoryCmd.command("topics [vault]").description("list topic-oriented memory from the optional derived cache").option("--project <slug>", "filter topics by project slug").option("--limit <n>", "maximum topics to return", (s) => parseInt(s, 10), 10).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
@@ -5117,12 +5350,23 @@ memoryCmd.command("topics [vault]").description("list topic-oriented memory from
|
|
|
5117
5350
|
memoryCmd.command("index [vault]").description("build the derived project memory topic cache").requiredOption("--project <slug>", "project slug").option("--check", "report whether the local project memory cache is missing or stale without writing", false).option("--if-stale", "rebuild the local project memory cache only when it is missing or stale", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5118
5351
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
5119
5352
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5120
|
-
else emit(await runMemoryIndex({
|
|
5353
|
+
else if (opts.check) emit(await runMemoryIndex({
|
|
5121
5354
|
vault: v.vault,
|
|
5122
5355
|
project: opts.project,
|
|
5123
|
-
check:
|
|
5356
|
+
check: true,
|
|
5124
5357
|
ifStale: !!opts.ifStale
|
|
5125
|
-
}), v.vault, { postCommit:
|
|
5358
|
+
}), v.vault, { postCommit: false });
|
|
5359
|
+
else return emitGuardedVaultWrite(
|
|
5360
|
+
v.vault,
|
|
5361
|
+
opts.ifStale ? "memory index --if-stale" : "memory index",
|
|
5362
|
+
() => runMemoryIndex({
|
|
5363
|
+
vault: v.vault,
|
|
5364
|
+
project: opts.project,
|
|
5365
|
+
check: false,
|
|
5366
|
+
ifStale: !!opts.ifStale
|
|
5367
|
+
}),
|
|
5368
|
+
{ postCommit: true }
|
|
5369
|
+
);
|
|
5126
5370
|
});
|
|
5127
5371
|
memoryCmd.command("recall [vault]").description("recall bounded source summaries for a memory topic").requiredOption("--project <slug>", "project slug").requiredOption("--topic <slug>", "memory topic slug").option("--scope <scope>", "memory scope: project, global, cross-agent, or all").option("--limit <n>", "maximum sources to return", (s) => parseInt(s, 10), 10).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5128
5372
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
@@ -5148,25 +5392,53 @@ memoryCmd.command("review [vault]").description("review deterministic memory gap
|
|
|
5148
5392
|
memoryCmd.command("import [vault]").description("preview or apply local memory imports into raw captures").requiredOption("--from <path>", "source file or directory to scan").requiredOption("--project <slug>", "project slug").option("--dry-run", "preview only; do not write captures", false).option("--apply", "write validated raw captures for ready entries", false).option("--max-bytes <n>", "reject source files above this size", (s) => parseInt(s, 10), 2e5).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
5149
5393
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
5150
5394
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
5395
|
+
else if (!!opts.apply && !opts.dryRun) return emitGuardedVaultWrite(
|
|
5396
|
+
v.vault,
|
|
5397
|
+
"memory import --apply",
|
|
5398
|
+
() => runMemoryImport({
|
|
5399
|
+
vault: v.vault,
|
|
5400
|
+
from: opts.from,
|
|
5401
|
+
project: opts.project,
|
|
5402
|
+
apply: true,
|
|
5403
|
+
maxBytes: opts.maxBytes
|
|
5404
|
+
}),
|
|
5405
|
+
{ postCommit: true }
|
|
5406
|
+
);
|
|
5151
5407
|
else emit(await runMemoryImport({
|
|
5152
5408
|
vault: v.vault,
|
|
5153
5409
|
from: opts.from,
|
|
5154
5410
|
project: opts.project,
|
|
5155
|
-
apply:
|
|
5411
|
+
apply: false,
|
|
5156
5412
|
maxBytes: opts.maxBytes
|
|
5157
|
-
}), v.vault, { postCommit:
|
|
5413
|
+
}), v.vault, { postCommit: false });
|
|
5158
5414
|
});
|
|
5159
5415
|
program.command("ingest <source>").description("ingest a source URL or local file into the vault").requiredOption("--vault <path>", "vault root directory").requiredOption("--type <type>", "typed-knowledge type (entity|concept|comparison|query)").requiredOption("--title <title>", "page title").option("--tags <csv>", "comma-separated tags").option("--provenance <provenance>", "provenance (research|project)").option("--dry-run", "preview without writing files", false).action(async (source, opts) => {
|
|
5160
5416
|
const tags = typeof opts.tags === "string" ? opts.tags.split(",").map((s) => s.trim()).filter((s) => s.length > 0) : [];
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5417
|
+
if (opts.dryRun) {
|
|
5418
|
+
emit(await runIngest({
|
|
5419
|
+
source,
|
|
5420
|
+
vault: opts.vault,
|
|
5421
|
+
type: opts.type,
|
|
5422
|
+
title: opts.title,
|
|
5423
|
+
tags,
|
|
5424
|
+
provenance: opts.provenance,
|
|
5425
|
+
dryRun: true
|
|
5426
|
+
}), opts.vault);
|
|
5427
|
+
return;
|
|
5428
|
+
}
|
|
5429
|
+
return emitGuardedVaultWrite(
|
|
5430
|
+
opts.vault,
|
|
5431
|
+
"ingest",
|
|
5432
|
+
() => runIngest({
|
|
5433
|
+
source,
|
|
5434
|
+
vault: opts.vault,
|
|
5435
|
+
type: opts.type,
|
|
5436
|
+
title: opts.title,
|
|
5437
|
+
tags,
|
|
5438
|
+
provenance: opts.provenance,
|
|
5439
|
+
dryRun: false
|
|
5440
|
+
})
|
|
5441
|
+
);
|
|
5170
5442
|
});
|
|
5171
5443
|
var fleetCmd = program.command("fleet").description("manage fleet topology metadata");
|
|
5172
5444
|
fleetCmd.command("validate <file>").description("validate a fleet manifest").action(async (file) => {
|
package/dist/skillwiki-mcp.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.35",
|
|
4
4
|
"skills": "./",
|
|
5
5
|
"description": "Project-aware Karpathy-style knowledge base for Claude Code: 18 prompt-only skills (wiki-*, proj-*, using-skillwiki) backed by the deterministic `skillwiki` CLI.",
|
|
6
6
|
"author": {
|