skillwiki 0.9.32 → 0.9.34

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.
@@ -152,6 +152,26 @@ var CompoundSchema = z.object({
152
152
  promoted_to: wikilink.optional(),
153
153
  cssclasses: z.array(z.string()).optional()
154
154
  });
155
+ var sessionPinPath = z.string().regex(
156
+ /^(entities|concepts|comparisons|queries|meta)\/.+\.md$/,
157
+ "must reference a typed-knowledge markdown page"
158
+ );
159
+ var SessionPinSchema = z.object({
160
+ title: z.string().min(1),
161
+ path: sessionPinPath,
162
+ scope: z.enum(["global", "project"]),
163
+ project: wikilink.optional(),
164
+ summary: z.string().min(1).optional(),
165
+ updated: isoDate.optional()
166
+ }).superRefine((v, ctx) => {
167
+ if (v.scope === "project" && v.project === void 0) {
168
+ ctx.addIssue({
169
+ code: z.ZodIssueCode.custom,
170
+ path: ["project"],
171
+ message: "project is required when scope is project"
172
+ });
173
+ }
174
+ });
155
175
  var MetaSchema = z.object({
156
176
  title: z.string().min(1),
157
177
  aliases: z.array(z.string()).optional(),
@@ -164,9 +184,17 @@ var MetaSchema = z.object({
164
184
  provenance_projects: z.array(wikilink).optional(),
165
185
  generated_by: z.string().min(1).optional(),
166
186
  generated_at: z.string().datetime().optional(),
167
- generated_kind: z.enum(["session-brief"]).optional()
187
+ generated_kind: z.enum(["session-brief"]).optional(),
188
+ meta_kind: z.enum(["session-pins"]).optional(),
189
+ stale_ttl: z.number().int().positive().optional(),
190
+ pins: z.array(SessionPinSchema).optional()
168
191
  }).superRefine((v, ctx) => {
169
- if (v.generated_kind !== "session-brief" && (!v.provenance_projects || v.provenance_projects.length < 2)) {
192
+ const isGeneratedSessionBrief = v.generated_kind === "session-brief";
193
+ const isSessionPins = v.meta_kind === "session-pins";
194
+ if (isSessionPins && (!v.pins || v.pins.length === 0)) {
195
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["pins"], message: "required when meta_kind is session-pins" });
196
+ }
197
+ if (!isGeneratedSessionBrief && !isSessionPins && (!v.provenance_projects || v.provenance_projects.length < 2)) {
170
198
  ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["provenance_projects"], message: "meta pages must reference \u22652 projects" });
171
199
  }
172
200
  if (v.provenance && v.provenance !== "research" && (!v.provenance_projects || v.provenance_projects.length === 0)) {
@@ -8848,6 +8876,7 @@ export {
8848
8876
  ok,
8849
8877
  err,
8850
8878
  TypedKnowledgeSchema,
8879
+ MetaSchema,
8851
8880
  detectSchema,
8852
8881
  isBlockedHost,
8853
8882
  splitFrontmatter,
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,
@@ -73,7 +74,7 @@ import {
73
74
  triggerAutoUpdate,
74
75
  writeCache,
75
76
  writeDotenv
76
- } from "./chunk-OPXMAS4O.js";
77
+ } from "./chunk-KUDZOG52.js";
77
78
  import {
78
79
  normalizeDistTag
79
80
  } from "./chunk-E6UWZ3S3.js";
@@ -1082,6 +1083,19 @@ function runVaultSyncHealth(home, syncMode) {
1082
1083
  const filterPath = join9(home, ".config", "rclone", "wiki-push-filters.txt");
1083
1084
  const checks = [];
1084
1085
  const pushScript = join9(shareDir, "wiki-push.sh");
1086
+ if (syncMode === "optional" && !existsSync3(pushScript)) {
1087
+ return {
1088
+ status: "pass",
1089
+ blocking: false,
1090
+ installed: false,
1091
+ summary: { pass: 1, info: 0, warn: 0, error: 0, skipped: 1 },
1092
+ checks: [{
1093
+ id: "vault_sync_installed",
1094
+ status: "pass",
1095
+ detail: `vault-sync not installed at ${pushScript}; optional check skipped`
1096
+ }]
1097
+ };
1098
+ }
1085
1099
  checks.push(existsSync3(pushScript) ? { id: "vault_sync_installed", label: "Vault sync installed", status: "pass", detail: `Found: ${pushScript}` } : { id: "vault_sync_installed", label: "Vault sync installed", status: "error", detail: `Script missing: ${pushScript}` });
1086
1100
  if (isMac) {
1087
1101
  const pushPlist = join9(home, "Library", "LaunchAgents", "com.karlchow.wiki-push.plist");
@@ -1221,6 +1235,7 @@ async function runHealth(input) {
1221
1235
  if (!lint.result.ok) return { exitCode: lint.exitCode, result: lint.result };
1222
1236
  const doctorStatus = statusFromCounts(doctor.result.data.summary);
1223
1237
  const vaultSync = runVaultSyncHealth(input.home, syncMode);
1238
+ const vaultSyncCoverage = syncMode === "off" ? { state: "skipped", status: "pass", reason: "--sync off" } : !vaultSync.installed && vaultSync.summary.skipped > 0 && vaultSync.summary.warn === 0 && vaultSync.summary.error === 0 ? { state: "skipped", status: vaultSync.status, reason: "vault-sync not installed and --sync optional" } : { state: "checked", status: vaultSync.status };
1224
1239
  const queryReadiness = deriveQueryReadiness(lint.result.data);
1225
1240
  const sourceFreshness = {
1226
1241
  status: bucketCount(lint.result.data.buckets, "stale_page") > 0 || bucketCount(lint.result.data.buckets, "file_source_url") > 0 ? "warn" : "pass",
@@ -1273,7 +1288,7 @@ async function runHealth(input) {
1273
1288
  coverage: {
1274
1289
  doctor: { state: "checked", status: doctorStatus },
1275
1290
  lint: { state: "checked", status: lintComponent.status },
1276
- vault_sync: syncMode === "off" ? { state: "skipped", status: "pass", reason: "--sync off" } : { state: "checked", status: vaultSync.status },
1291
+ vault_sync: vaultSyncCoverage,
1277
1292
  query_readiness: { state: "checked", status: queryReadiness.status },
1278
1293
  source_freshness: { state: "checked", status: sourceFreshness.status }
1279
1294
  },
@@ -2372,14 +2387,27 @@ async function runSessionBrief(input) {
2372
2387
  const today = generatedAt.slice(0, 10);
2373
2388
  const project = await resolveProject(input);
2374
2389
  try {
2375
- const transcripts = await loadTranscriptInfo(scan.data.raw);
2376
- const workItems = await loadWorkItems(scan.data.workItems);
2377
- const digests = await loadTrendDigests(scan.data.typedKnowledge);
2390
+ const [
2391
+ transcripts,
2392
+ workItems,
2393
+ digests,
2394
+ baseHealthWarnings,
2395
+ satelliteHealth,
2396
+ sessionPins,
2397
+ memoryTopics
2398
+ ] = await Promise.all([
2399
+ loadTranscriptInfo(scan.data.raw),
2400
+ loadWorkItems(scan.data.workItems),
2401
+ loadTrendDigests(scan.data.typedKnowledge),
2402
+ loadHealthWarnings(input.vault),
2403
+ loadSatelliteHealth(input.vault),
2404
+ loadSessionPins(input.vault, project),
2405
+ project ? loadMemoryTopics(input.vault, project) : Promise.resolve([])
2406
+ ]);
2378
2407
  const healthWarnings = [
2379
- ...await loadHealthWarnings(input.vault),
2380
- ...satelliteHealthWarnings(await loadSatelliteHealth(input.vault))
2408
+ ...baseHealthWarnings,
2409
+ ...satelliteHealthWarnings(satelliteHealth)
2381
2410
  ];
2382
- const memoryTopics = project ? await loadMemoryTopics(input.vault, project) : [];
2383
2411
  const latestLogs = newest(transcripts.filter((t) => t.kind === "session-log"), 3);
2384
2412
  const unclaimedCaptures = newest(transcripts.filter((t) => {
2385
2413
  if (t.kind !== "task" && t.kind !== "bug") return false;
@@ -2394,6 +2422,7 @@ async function runSessionBrief(input) {
2394
2422
  const brief = capWords(renderBrief({
2395
2423
  project,
2396
2424
  generatedAt,
2425
+ sessionPins,
2397
2426
  latestLogs,
2398
2427
  unclaimedCaptures,
2399
2428
  activeWork,
@@ -2429,6 +2458,7 @@ async function runSessionBrief(input) {
2429
2458
  index_updated: indexUpdated,
2430
2459
  log_updated: logUpdated,
2431
2460
  generated_at: generatedAt,
2461
+ session_pins: sessionPins,
2432
2462
  memory_topics: memoryTopics,
2433
2463
  humanHint
2434
2464
  })
@@ -2530,6 +2560,29 @@ async function loadTrendDigests(typedPages) {
2530
2560
  }
2531
2561
  return out;
2532
2562
  }
2563
+ async function loadSessionPins(vault, project) {
2564
+ const text = await readIfExists(join15(vault, "meta", "session-pins.md"));
2565
+ if (!text) return [];
2566
+ const fm = extractFrontmatter(text);
2567
+ if (!fm.ok) return [];
2568
+ const parsed = MetaSchema.safeParse(fm.data);
2569
+ if (!parsed.success || parsed.data.meta_kind !== "session-pins") return [];
2570
+ const registryUpdated = parsed.data.updated;
2571
+ const out = [];
2572
+ for (const pin of parsed.data.pins ?? []) {
2573
+ const pinProject = wikilinkSlug(pin.project);
2574
+ if (pin.scope === "project" && (!project || pinProject !== project)) continue;
2575
+ out.push({
2576
+ path: pin.path,
2577
+ title: pin.title,
2578
+ summary: pin.summary ?? "",
2579
+ date: pin.updated ?? registryUpdated,
2580
+ project: pinProject,
2581
+ kind: "session-pin"
2582
+ });
2583
+ }
2584
+ return newest(out, 5);
2585
+ }
2533
2586
  function renderBrief(input) {
2534
2587
  const lines = [
2535
2588
  "# Session Brief",
@@ -2538,6 +2591,7 @@ function renderBrief(input) {
2538
2591
  `Scope: ${input.project ? `[[${input.project}]] plus global context` : "global context"}`,
2539
2592
  ""
2540
2593
  ];
2594
+ appendPinnedContextSection(lines, input.sessionPins);
2541
2595
  appendSection(lines, "Active Work", input.activeWork, "No active project work found.");
2542
2596
  appendSection(lines, "Unclaimed Captures", input.unclaimedCaptures, "No unclaimed task or bug captures found.");
2543
2597
  appendSection(lines, "Recent Session Logs", input.project ? input.projectLogs : input.latestLogs, "No recent session logs found.");
@@ -2563,6 +2617,16 @@ function appendMemoryTopicsSection(lines, project, topics) {
2563
2617
  }
2564
2618
  lines.push("");
2565
2619
  }
2620
+ function appendPinnedContextSection(lines, pins) {
2621
+ if (pins.length === 0) return;
2622
+ lines.push("## Pinned Context", "");
2623
+ for (const pin of pins) {
2624
+ const date = pin.date ? `${pin.date} ` : "";
2625
+ const summary = pin.summary ? ` \u2014 ${pin.summary}` : "";
2626
+ lines.push(`- ${date}${pin.title} (${pin.path})${summary}`);
2627
+ }
2628
+ lines.push("");
2629
+ }
2566
2630
  function appendSection(lines, title, items, empty) {
2567
2631
  lines.push(`## ${title}`, "");
2568
2632
  if (items.length === 0) {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runSkillwikiMcpStdio
4
- } from "./chunk-OPXMAS4O.js";
4
+ } from "./chunk-KUDZOG52.js";
5
5
  import "./chunk-E6UWZ3S3.js";
6
6
 
7
7
  // src/mcp-entry.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.9.32",
3
+ "version": "0.9.34",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "skillwiki": "dist/cli.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.9.32",
3
+ "version": "0.9.34",
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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.9.32",
3
+ "version": "0.9.34",
4
4
  "description": "Project-aware Karpathy-style knowledge base for Codex with 18 prompt-only skills backed by the deterministic skillwiki CLI.",
5
5
  "author": {
6
6
  "name": "karlorz",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillwiki/skills",
3
- "version": "0.9.32",
3
+ "version": "0.9.34",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",