skillwiki 0.10.46 → 0.10.48

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.
@@ -1190,27 +1190,90 @@ async function applyRawStructuralMove(input) {
1190
1190
  }
1191
1191
 
1192
1192
  // src/utils/transcript-claims.ts
1193
+ var REDACTED_MALFORMED_REFERENCE = "[redacted]";
1194
+ var MAX_DIAGNOSTIC_VALUE_LENGTH = 1024;
1195
+ var UNSAFE_CHAR_RE = /[\u0000-\u001f\u007f\u0080-\u009f\u2028\u2029]/;
1196
+ function safeDiagnosticValue(value) {
1197
+ if (UNSAFE_CHAR_RE.test(value) || value.length > MAX_DIAGNOSTIC_VALUE_LENGTH) {
1198
+ return REDACTED_MALFORMED_REFERENCE;
1199
+ }
1200
+ return value;
1201
+ }
1193
1202
  function normalizeRawTranscriptRef(value) {
1194
1203
  if (typeof value !== "string") return void 0;
1195
1204
  const trimmed = value.trim();
1196
1205
  if (!trimmed.startsWith("raw/transcripts/") || !trimmed.endsWith(".md")) return void 0;
1197
1206
  if (trimmed.includes("..") || trimmed.includes("\\")) return void 0;
1207
+ if (UNSAFE_CHAR_RE.test(trimmed)) return void 0;
1198
1208
  return trimmed;
1199
1209
  }
1210
+ function isMalformedRawTranscriptAttempt(value) {
1211
+ if (typeof value !== "string") return false;
1212
+ const trimmed = value.trim();
1213
+ const attemptsTranscript = trimmed.startsWith("raw/transcripts/") || trimmed.startsWith("raw\\transcripts\\");
1214
+ return attemptsTranscript && normalizeRawTranscriptRef(trimmed) === void 0;
1215
+ }
1200
1216
  function collectClaimedTranscripts(workItems) {
1201
1217
  const claimedByPath = /* @__PURE__ */ new Map();
1218
+ const diagnostics = [];
1219
+ const ownersByPath = /* @__PURE__ */ new Map();
1202
1220
  for (const item of workItems) {
1203
- const candidates = [item.source];
1204
- for (const list of [item.sources, item.closes]) {
1205
- if (Array.isArray(list)) candidates.push(...list);
1206
- else if (list !== void 0) candidates.push(list);
1221
+ const candidates = [
1222
+ { field: "source", value: item.source }
1223
+ ];
1224
+ for (const field of ["sources", "closes"]) {
1225
+ const list = item[field];
1226
+ if (Array.isArray(list)) {
1227
+ for (const value of list) candidates.push({ field, value });
1228
+ } else if (list !== void 0) {
1229
+ candidates.push({ field, value: list });
1230
+ }
1207
1231
  }
1208
- for (const value of candidates) {
1232
+ for (const { field, value } of candidates) {
1209
1233
  const normalized = normalizeRawTranscriptRef(value);
1210
- if (normalized) claimedByPath.set(normalized, item.relDir);
1234
+ if (normalized) {
1235
+ const owners = ownersByPath.get(normalized);
1236
+ if (owners) {
1237
+ if (!owners.includes(item.relDir)) owners.push(item.relDir);
1238
+ } else {
1239
+ ownersByPath.set(normalized, [item.relDir]);
1240
+ }
1241
+ } else if (isMalformedRawTranscriptAttempt(value)) {
1242
+ diagnostics.push({
1243
+ kind: "malformed",
1244
+ relDir: item.relDir,
1245
+ field,
1246
+ value: safeDiagnosticValue(value.trim())
1247
+ });
1248
+ }
1249
+ }
1250
+ }
1251
+ for (const [path, owners] of ownersByPath) {
1252
+ claimedByPath.set(path, owners[owners.length - 1]);
1253
+ if (owners.length > 1) {
1254
+ diagnostics.push({ kind: "duplicate", path, owners });
1211
1255
  }
1212
1256
  }
1213
- return { claimedByPath };
1257
+ return { claimedByPath, diagnostics };
1258
+ }
1259
+
1260
+ // src/utils/project-slug.ts
1261
+ function normalizeProjectSlug(value) {
1262
+ if (typeof value !== "string") return void 0;
1263
+ const slug = value.trim().replace(/^\[\[/, "").replace(/(?:\|[^\[\]]*)?\]\]$/, "").replace(/^["']|["']$/g, "").trim();
1264
+ return slug === "" ? void 0 : slug;
1265
+ }
1266
+
1267
+ // src/utils/work-item-path.ts
1268
+ function parseActiveWorkPath(relDir) {
1269
+ const parts = relDir.split("/");
1270
+ if (parts.length !== 4) return void 0;
1271
+ if (parts[0] !== "projects") return void 0;
1272
+ if (parts[2] !== "work") return void 0;
1273
+ const project = parts[1];
1274
+ const item = parts[3];
1275
+ if (project === "" || item === "") return void 0;
1276
+ return { project, item };
1214
1277
  }
1215
1278
 
1216
1279
  // src/commands/stale.ts
@@ -1272,7 +1335,7 @@ async function runStale(input) {
1272
1335
  }
1273
1336
  }
1274
1337
  function extractSlug(projectField) {
1275
- return projectField.replace(/^\[\[/, "").replace(/\]\]$/, "").replace(/^"|"$/g, "");
1338
+ return normalizeProjectSlug(projectField) ?? "";
1276
1339
  }
1277
1340
  const TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "abandoned", "done", "invalid"]);
1278
1341
  const KIND_FROM_FILENAME = /^(?:\d{4}-\d{2}-\d{2})-(task|bug|idea|note|observation)-.+\.md$/;
@@ -1285,7 +1348,7 @@ async function runStale(input) {
1285
1348
  const fm = extractFrontmatter(content);
1286
1349
  let kind = fm.ok && typeof fm.data.kind === "string" ? fm.data.kind : "";
1287
1350
  let project = fm.ok && typeof fm.data.project === "string" ? fm.data.project : "";
1288
- if (input.project && !project.includes(input.project)) return null;
1351
+ if (input.project && normalizeProjectSlug(project) !== input.project) return null;
1289
1352
  let inferred = false;
1290
1353
  if (input.forceScan && !kind) {
1291
1354
  const basename = t.relPath.split("/").pop();
@@ -1385,7 +1448,7 @@ async function runStale(input) {
1385
1448
  if (fm.ok && typeof fm.data.updated === "string") {
1386
1449
  if (input.project) {
1387
1450
  const pp = fm.data.provenance_projects;
1388
- const linked = Array.isArray(pp) && pp.some((p) => String(p).includes(input.project));
1451
+ const linked = Array.isArray(pp) && pp.some((p) => normalizeProjectSlug(p) === input.project);
1389
1452
  if (!linked) return null;
1390
1453
  }
1391
1454
  const age = daysSince(fm.data.updated);
@@ -1409,7 +1472,7 @@ async function runStale(input) {
1409
1472
  const fm = extractFrontmatter(text);
1410
1473
  if (fm.ok) {
1411
1474
  const pp = fm.data.provenance_projects;
1412
- const linked = Array.isArray(pp) && pp.some((p) => String(p).includes(projectFilter));
1475
+ const linked = Array.isArray(pp) && pp.some((p) => normalizeProjectSlug(p) === projectFilter);
1413
1476
  if (!linked) return pageSections;
1414
1477
  }
1415
1478
  }
@@ -1500,10 +1563,9 @@ async function runStale(input) {
1500
1563
  archived.push(plan.from);
1501
1564
  }
1502
1565
  for (const w of [...incompleteWorkItems, ...doneWorkItems]) {
1503
- const parts = w.path.split("/");
1504
- if (parts.length >= 4 && parts[0] === "projects") {
1505
- const slug = parts[1];
1506
- const itemName = parts[3];
1566
+ const active = parseActiveWorkPath(w.path);
1567
+ if (active) {
1568
+ const { project: slug, item: itemName } = active;
1507
1569
  const histDir = join5(input.vault, "projects", slug, "history", "archived-work");
1508
1570
  await mkdir3(histDir, { recursive: true });
1509
1571
  const dest = join5(histDir, itemName);
@@ -2995,6 +3057,7 @@ function buildCliSurface() {
2995
3057
  program.command("self-update").option("--check");
2996
3058
  program.command("transcripts").option("--since <date>").option("--wiki <name>");
2997
3059
  program.command("project-index").option("--apply").option("--check").option("--wiki <name>");
3060
+ program.command("claims");
2998
3061
  program.command("compound");
2999
3062
  program.command("tag");
3000
3063
  program.command("tag-sync").option("--dry-run").option("--wiki <name>");
@@ -3034,6 +3097,8 @@ function buildCliSurface() {
3034
3097
  pageCmd.command("publish").requiredOption("--target <path>").option("--log-note <text>").option("--write").option("--approve <token>").option("--wiki <name>");
3035
3098
  const projectPageCmd = program.commands.find((c) => c.name() === "project-page");
3036
3099
  projectPageCmd.command("publish").requiredOption("--project <slug>").requiredOption("--target <path>").option("--log-note <text>").option("--write").option("--approve <token>").option("--wiki <name>");
3100
+ const claimsCmd = program.commands.find((c) => c.name() === "claims");
3101
+ claimsCmd.command("audit").option("--project <slug>").option("--wiki <name>");
3037
3102
  const logCmd = program.commands.find((c) => c.name() === "log");
3038
3103
  logCmd.command("materialize").option("--write").option("--wiki <name>");
3039
3104
  logCmd.command("migrate-legacy").option("--write").option("--converge-vault <dir>").option("--wiki <name>");
@@ -6387,7 +6452,11 @@ export {
6387
6452
  resolveFleetHostId,
6388
6453
  planRawStructuralMove,
6389
6454
  applyRawStructuralMove,
6455
+ REDACTED_MALFORMED_REFERENCE,
6456
+ safeDiagnosticValue,
6390
6457
  collectClaimedTranscripts,
6458
+ normalizeProjectSlug,
6459
+ parseActiveWorkPath,
6391
6460
  runStale,
6392
6461
  runPagesize,
6393
6462
  runLogRotate,
@@ -35,7 +35,7 @@ import {
35
35
  snapshotterAliasForLocalHost,
36
36
  toUndirectedWeighted,
37
37
  writeDotenv
38
- } from "./chunk-4SINVFR3.js";
38
+ } from "./chunk-FXASPB3C.js";
39
39
  import {
40
40
  atomicWriteText,
41
41
  prepareTypedPage