skillwiki 0.9.23 → 0.9.26
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/cli.js
CHANGED
|
@@ -3469,7 +3469,7 @@ function buildCliSurface() {
|
|
|
3469
3469
|
program2.command("index-check").option("--wiki <name>");
|
|
3470
3470
|
program2.command("index-link-format").option("--wiki <name>");
|
|
3471
3471
|
program2.command("topic-map-check").option("--threshold <n>").option("--wiki <name>");
|
|
3472
|
-
program2.command("stale").option("--archive").option("--days <n>").option("--force-scan").option("--project <slug>").option("--
|
|
3472
|
+
program2.command("stale").option("--archive").option("--days <n>").option("--force-scan").option("--project <slug>").option("--wiki <name>");
|
|
3473
3473
|
program2.command("claim").option("--project <slug>").option("--slug <slug>").option("--wiki <name>");
|
|
3474
3474
|
program2.command("pagesize").option("--lines <n>").option("--wiki <name>");
|
|
3475
3475
|
program2.command("log-rotate").option("--threshold <n>").option("--apply").option("--wiki <name>");
|
|
@@ -3512,7 +3512,7 @@ function buildCliSurface() {
|
|
|
3512
3512
|
compoundCmd2.command("list").requiredOption("--project <slug>").option("--wiki <name>");
|
|
3513
3513
|
compoundCmd2.command("delete").requiredOption("--project <slug>").option("--wiki <name>");
|
|
3514
3514
|
const syncCmd2 = program2.commands.find((c) => c.name() === "sync");
|
|
3515
|
-
syncCmd2.command("status").option("--wiki <name>");
|
|
3515
|
+
syncCmd2.command("status").option("--wiki <name>").option("--include-stashes");
|
|
3516
3516
|
syncCmd2.command("push").option("--wiki <name>");
|
|
3517
3517
|
syncCmd2.command("pull").option("--wiki <name>");
|
|
3518
3518
|
syncCmd2.command("lock").option("--summary <text>").option("--ttl-minutes <n>").option("--force").option("--wiki <name>");
|
|
@@ -3525,7 +3525,7 @@ function buildCliSurface() {
|
|
|
3525
3525
|
memoryCmd2.command("topics").option("--project <slug>").option("--limit <n>").option("--wiki <name>");
|
|
3526
3526
|
memoryCmd2.command("index").requiredOption("--project <slug>").option("--check").option("--if-stale").option("--wiki <name>");
|
|
3527
3527
|
memoryCmd2.command("recall").requiredOption("--project <slug>").requiredOption("--topic <slug>").option("--scope <scope>").option("--limit <n>").option("--wiki <name>");
|
|
3528
|
-
memoryCmd2.command("review").requiredOption("--project <slug>").option("--dry-run").option("--wiki <name>");
|
|
3528
|
+
memoryCmd2.command("review").requiredOption("--project <slug>").option("--dry-run").option("--pre-action <target>").option("--wiki <name>");
|
|
3529
3529
|
memoryCmd2.command("import").requiredOption("--from <path>").requiredOption("--project <slug>").option("--dry-run").option("--apply").option("--max-bytes <n>").option("--wiki <name>");
|
|
3530
3530
|
const fleetCmd2 = program2.commands.find((c) => c.name() === "fleet");
|
|
3531
3531
|
fleetCmd2.command("validate");
|
|
@@ -7004,9 +7004,12 @@ function summarizeChecks(checks) {
|
|
|
7004
7004
|
function classifyLog(path, id, label, okPattern) {
|
|
7005
7005
|
if (!existsSync12(path)) return { id, label, status: "warn", detail: `log file missing: ${path}` };
|
|
7006
7006
|
const lines = readFileSync8(path, "utf8").split(/\r?\n/).filter(Boolean);
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7007
|
+
if (lines.length === 0) return { id, label, status: "warn", detail: `log file empty: ${path}` };
|
|
7008
|
+
const statusLine = [...lines].reverse().find(
|
|
7009
|
+
(line) => /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z /.test(line) && (okPattern.test(line) || /\bFAIL\b|\bERROR\b/i.test(line))
|
|
7010
|
+
);
|
|
7011
|
+
const last = statusLine ?? lines[lines.length - 1];
|
|
7012
|
+
if (/\bFAIL\b|\bERROR\b/i.test(last)) return { id, label, status: "error", detail: last.slice(0, 120) };
|
|
7010
7013
|
if (okPattern.test(last)) return { id, label, status: "pass", detail: last.slice(0, 120) };
|
|
7011
7014
|
return { id, label, status: "warn", detail: last.slice(0, 120) };
|
|
7012
7015
|
}
|
|
@@ -9156,6 +9159,11 @@ async function runMemoryReview(input) {
|
|
|
9156
9159
|
indexState: state,
|
|
9157
9160
|
reviewPages: state.reviewPages
|
|
9158
9161
|
});
|
|
9162
|
+
const preAction = input.preAction?.trim();
|
|
9163
|
+
if (preAction) {
|
|
9164
|
+
findings.push(...await buildPastFailureFindings(scan.data.allMarkdown, input.project, preAction));
|
|
9165
|
+
findings.sort(compareMemoryReviewFindings);
|
|
9166
|
+
}
|
|
9159
9167
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
9160
9168
|
return {
|
|
9161
9169
|
exitCode: ExitCode.OK,
|
|
@@ -9474,6 +9482,135 @@ function buildMemoryReviewFindings(input) {
|
|
|
9474
9482
|
}
|
|
9475
9483
|
return findings.sort(compareMemoryReviewFindings);
|
|
9476
9484
|
}
|
|
9485
|
+
var COMMON_FAILURE_MATCH_TOKENS = /* @__PURE__ */ new Set([
|
|
9486
|
+
"memory",
|
|
9487
|
+
"review",
|
|
9488
|
+
"test",
|
|
9489
|
+
"tests",
|
|
9490
|
+
"plugin",
|
|
9491
|
+
"cache",
|
|
9492
|
+
"command",
|
|
9493
|
+
"feature",
|
|
9494
|
+
"project",
|
|
9495
|
+
"status",
|
|
9496
|
+
"error",
|
|
9497
|
+
"warning",
|
|
9498
|
+
"warn",
|
|
9499
|
+
"info",
|
|
9500
|
+
"skillwiki",
|
|
9501
|
+
"dev",
|
|
9502
|
+
"loop"
|
|
9503
|
+
]);
|
|
9504
|
+
var FAILURE_MARKER_RE = /\b(?:miss|root cause|symptom|problem|friction|regression|bug)\b/i;
|
|
9505
|
+
async function buildPastFailureFindings(pages, project, target) {
|
|
9506
|
+
const targetProfile = buildPastFailureTargetProfile(target);
|
|
9507
|
+
if (!targetProfile) return [];
|
|
9508
|
+
const findings = [];
|
|
9509
|
+
for (const page of dedupePages(pages)) {
|
|
9510
|
+
const body = await readPastFailureCandidateBody(page, project);
|
|
9511
|
+
if (!body) continue;
|
|
9512
|
+
const match = matchPastFailureTarget(targetProfile, body);
|
|
9513
|
+
if (!match) continue;
|
|
9514
|
+
findings.push({
|
|
9515
|
+
id: `past_failure_match:${page.relPath}`,
|
|
9516
|
+
severity: "warn",
|
|
9517
|
+
kind: "past_failure_match",
|
|
9518
|
+
path: page.relPath,
|
|
9519
|
+
message: `${page.relPath} matches pre-action target ${targetProfile.summary}: ${match.reason}`,
|
|
9520
|
+
suggested_action: `Read ${page.relPath} before executing; reuse the prior miss/root-cause notes if relevant.`
|
|
9521
|
+
});
|
|
9522
|
+
}
|
|
9523
|
+
return findings.sort(compareMemoryReviewFindings);
|
|
9524
|
+
}
|
|
9525
|
+
function buildPastFailureTargetProfile(target) {
|
|
9526
|
+
const normalizedTarget = normalizeMatchText(target);
|
|
9527
|
+
if (!normalizedTarget) return null;
|
|
9528
|
+
const distinctiveTokens = extractDistinctiveTargetTokens(target);
|
|
9529
|
+
const includeFullPhrase = normalizedTarget.length >= 12 && distinctiveTokens.length >= 2;
|
|
9530
|
+
const exactNeedles = uniqueStrings([
|
|
9531
|
+
includeFullPhrase ? normalizedTarget : "",
|
|
9532
|
+
...extractPathLikeNeedles(target),
|
|
9533
|
+
...extractFlagNeedles(target),
|
|
9534
|
+
...extractCodeLikeNeedles(target)
|
|
9535
|
+
].map(normalizeMatchText).filter((needle) => needle.length >= 4).filter(hasDistinctiveNeedle));
|
|
9536
|
+
if (exactNeedles.length === 0 && distinctiveTokens.length < 2) return null;
|
|
9537
|
+
return {
|
|
9538
|
+
summary: summarizeTarget(target),
|
|
9539
|
+
exactNeedles,
|
|
9540
|
+
distinctiveTokens
|
|
9541
|
+
};
|
|
9542
|
+
}
|
|
9543
|
+
async function readPastFailureCandidateBody(page, project) {
|
|
9544
|
+
if (isProjectRetroPath(page.relPath, project)) {
|
|
9545
|
+
return bodyWithoutFrontmatter(await readPage(page));
|
|
9546
|
+
}
|
|
9547
|
+
if (!isRawBugCapturePath(page.relPath)) return null;
|
|
9548
|
+
const text = await readPage(page);
|
|
9549
|
+
const fm = extractFrontmatter(text);
|
|
9550
|
+
if (!fm.ok || !frontmatterProjectMatches(fm.data.project, project)) return null;
|
|
9551
|
+
return bodyWithoutFrontmatter(text);
|
|
9552
|
+
}
|
|
9553
|
+
function isProjectRetroPath(path, project) {
|
|
9554
|
+
return path.startsWith(`projects/${project}/work/`) && path.endsWith("/retro.md") || path.startsWith(`projects/${project}/history/`) && path.endsWith("/retro.md");
|
|
9555
|
+
}
|
|
9556
|
+
function isRawBugCapturePath(path) {
|
|
9557
|
+
return /^raw\/transcripts\/.*-bug-.*\.md$/.test(path);
|
|
9558
|
+
}
|
|
9559
|
+
function frontmatterProjectMatches(value, project) {
|
|
9560
|
+
if (typeof value === "string") return wikilinkSlug2(value) === project;
|
|
9561
|
+
if (Array.isArray(value)) {
|
|
9562
|
+
return value.some((item) => typeof item === "string" && wikilinkSlug2(item) === project);
|
|
9563
|
+
}
|
|
9564
|
+
return false;
|
|
9565
|
+
}
|
|
9566
|
+
function bodyWithoutFrontmatter(text) {
|
|
9567
|
+
const split = splitFrontmatter(text);
|
|
9568
|
+
return split.ok ? split.data.body : text;
|
|
9569
|
+
}
|
|
9570
|
+
function matchPastFailureTarget(target, candidateBody) {
|
|
9571
|
+
const candidate = normalizeMatchText(candidateBody);
|
|
9572
|
+
if (!candidate) return null;
|
|
9573
|
+
const exactMatch = target.exactNeedles.find((needle) => candidate.includes(needle));
|
|
9574
|
+
if (exactMatch) {
|
|
9575
|
+
return { reason: `exact signal "${exactMatch}" appeared in prior failure memory` };
|
|
9576
|
+
}
|
|
9577
|
+
if (!FAILURE_MARKER_RE.test(candidateBody)) return null;
|
|
9578
|
+
const candidateTokens = new Set(tokenizeForMatch(candidate));
|
|
9579
|
+
const overlappingTokens = target.distinctiveTokens.filter((token) => candidateTokens.has(token));
|
|
9580
|
+
if (overlappingTokens.length >= 2) {
|
|
9581
|
+
return { reason: `distinctive target terms overlapped prior failure memory (${overlappingTokens.slice(0, 4).join(", ")})` };
|
|
9582
|
+
}
|
|
9583
|
+
return null;
|
|
9584
|
+
}
|
|
9585
|
+
function extractPathLikeNeedles(value) {
|
|
9586
|
+
return value.match(/[A-Za-z0-9_.-]+(?:\/[A-Za-z0-9_.-]+)+/g) ?? [];
|
|
9587
|
+
}
|
|
9588
|
+
function extractFlagNeedles(value) {
|
|
9589
|
+
return value.match(/--[a-z][a-z0-9-]*/gi) ?? [];
|
|
9590
|
+
}
|
|
9591
|
+
function extractCodeLikeNeedles(value) {
|
|
9592
|
+
return (value.match(/[A-Za-z0-9_.:-]*[_.:-][A-Za-z0-9_.:-]+/g) ?? []).filter((needle) => /[A-Za-z]/.test(needle));
|
|
9593
|
+
}
|
|
9594
|
+
function extractDistinctiveTargetTokens(value) {
|
|
9595
|
+
return uniqueStrings(tokenizeForMatch(value).filter((token) => token.length >= 4).filter((token) => !/^\d+$/.test(token)).filter((token) => !COMMON_FAILURE_MATCH_TOKENS.has(token)));
|
|
9596
|
+
}
|
|
9597
|
+
function hasDistinctiveNeedle(value) {
|
|
9598
|
+
return extractDistinctiveTargetTokens(value).length > 0;
|
|
9599
|
+
}
|
|
9600
|
+
function tokenizeForMatch(value) {
|
|
9601
|
+
return normalizeMatchText(value).match(/[a-z0-9]+/g) ?? [];
|
|
9602
|
+
}
|
|
9603
|
+
function normalizeMatchText(value) {
|
|
9604
|
+
return value.toLowerCase().replace(/[`"'“”‘’]/g, "").replace(/\s+/g, " ").trim();
|
|
9605
|
+
}
|
|
9606
|
+
function summarizeTarget(target) {
|
|
9607
|
+
const summary = target.replace(/\s+/g, " ").trim();
|
|
9608
|
+
if (summary.length <= 96) return JSON.stringify(summary);
|
|
9609
|
+
return JSON.stringify(`${summary.slice(0, 93).trimEnd()}...`);
|
|
9610
|
+
}
|
|
9611
|
+
function uniqueStrings(values) {
|
|
9612
|
+
return [...new Set(values.filter((value) => value.length > 0))];
|
|
9613
|
+
}
|
|
9477
9614
|
function parseInvalidTopicWarning(warning) {
|
|
9478
9615
|
const match = warning.match(/^(.*): invalid memory topic slug (.+)$/);
|
|
9479
9616
|
if (!match) return null;
|
|
@@ -12019,13 +12156,14 @@ memoryCmd.command("recall [vault]").description("recall bounded source summaries
|
|
|
12019
12156
|
limit: opts.limit
|
|
12020
12157
|
}), v.vault, { postCommit: false });
|
|
12021
12158
|
});
|
|
12022
|
-
memoryCmd.command("review [vault]").description("review deterministic memory gaps and cache drift without writing").requiredOption("--project <slug>", "project slug").option("--dry-run", "preview only; writes are not supported on this surface", false).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
12159
|
+
memoryCmd.command("review [vault]").description("review deterministic memory gaps and cache drift without writing").requiredOption("--project <slug>", "project slug").option("--dry-run", "preview only; writes are not supported on this surface", false).option("--pre-action <target>", "target slug, file path, command, or error signature to check against past failure memory").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
|
|
12023
12160
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
12024
12161
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
12025
12162
|
else emit(await runMemoryReview({
|
|
12026
12163
|
vault: v.vault,
|
|
12027
12164
|
project: opts.project,
|
|
12028
|
-
dryRun: !!opts.dryRun
|
|
12165
|
+
dryRun: !!opts.dryRun,
|
|
12166
|
+
preAction: opts.preAction
|
|
12029
12167
|
}), v.vault, { postCommit: false });
|
|
12030
12168
|
});
|
|
12031
12169
|
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) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.26",
|
|
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": {
|