skillwiki 0.2.1 → 0.2.3

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
@@ -101,6 +101,7 @@ var sha256Hex = z.string().regex(/^[0-9a-f]{64}$/);
101
101
  var RawSourceSchema = z.object({
102
102
  title: z.string().min(1).optional(),
103
103
  source_url: z.string().nullable(),
104
+ created: isoDate.optional(),
104
105
  ingested: isoDate,
105
106
  ingested_by: z.enum(["wiki-ingest", "proj-work", "manual"]).optional(),
106
107
  sha256: sha256Hex.optional(),
@@ -1649,7 +1650,8 @@ async function runInit(input) {
1649
1650
  return [
1650
1651
  "---",
1651
1652
  "source_url:",
1652
- "ingested: {{date:YYYY-MM-DD}}",
1653
+ "created: {{date:YYYY-MM-DD}}",
1654
+ "ingested: # filled by ingest pipeline",
1653
1655
  "kind: # idea | bug | task | note | other",
1654
1656
  'project: # optional: "[[slug]]"',
1655
1657
  "---",
@@ -2964,21 +2966,35 @@ function checkSkillsInstalled(home, cwd) {
2964
2966
  function checkDuplicateSkills(home) {
2965
2967
  const plugin = findPlugin(home);
2966
2968
  const skillsDir = join21(home, ".claude", "skills");
2967
- if (!plugin || !existsSync5(skillsDir)) {
2969
+ const agentSkillDirs = [
2970
+ { label: "~/.codex/skills/", path: join21(home, ".codex", "skills") },
2971
+ { label: "~/.agents/skills/", path: join21(home, ".agents", "skills") }
2972
+ ];
2973
+ if (!plugin) {
2968
2974
  return check("pass", "skills_duplicate", "Skills not duplicated", "Single install channel");
2969
2975
  }
2970
2976
  const pluginSkills = findSkillNames(plugin.installPath);
2971
2977
  const cliSkills = findSkillNames(skillsDir);
2972
- const duplicates = pluginSkills.filter((name) => cliSkills.includes(name));
2973
- if (duplicates.length === 0) {
2974
- return check("pass", "skills_duplicate", "Skills not duplicated", "No overlap between plugin and CLI install");
2978
+ const cliDuplicates = cliSkills.filter((name) => pluginSkills.includes(name));
2979
+ const agentDuplicates = [];
2980
+ for (const { label, path } of agentSkillDirs) {
2981
+ const overlap = findSkillNames(path).filter((name) => pluginSkills.includes(name));
2982
+ if (overlap.length > 0) {
2983
+ agentDuplicates.push({ dir: label, names: overlap });
2984
+ }
2975
2985
  }
2976
- return check(
2977
- "warn",
2978
- "skills_duplicate",
2979
- "Skills not duplicated",
2980
- `${duplicates.length} skill(s) in both plugin and ~/.claude/skills/ \u2014 remove CLI copies: rm -r ~/.claude/skills/{${duplicates.slice(0, 3).join(",")}${duplicates.length > 3 ? ",\u2026" : ""}}`
2981
- );
2986
+ if (cliDuplicates.length === 0 && agentDuplicates.length === 0) {
2987
+ return check("pass", "skills_duplicate", "Skills not duplicated", "No overlap between plugin and other channels");
2988
+ }
2989
+ const parts = [];
2990
+ if (cliDuplicates.length > 0) {
2991
+ parts.push(`${cliDuplicates.length} skill(s) in both plugin and ~/.claude/skills/ \u2014 remove CLI copies: rm -r ~/.claude/skills/{${cliDuplicates.slice(0, 3).join(",")}${cliDuplicates.length > 3 ? ",\u2026" : ""}}`);
2992
+ }
2993
+ for (const { dir, names } of agentDuplicates) {
2994
+ parts.push(`${names.length} stale skill(s) in ${dir} \u2014 plugin provides: ${names.slice(0, 3).join(", ")}${names.length > 3 ? ", \u2026" : ""}`);
2995
+ }
2996
+ const status = cliDuplicates.length > 0 ? "warn" : "info";
2997
+ return check(status, "skills_duplicate", "Skills not duplicated", parts.join("; "));
2982
2998
  }
2983
2999
  function checkNpmUpdate(home, currentVersion) {
2984
3000
  const { hasUpdate, latest } = latestFromCache(home, currentVersion);
@@ -3097,7 +3113,7 @@ function checkDotStoreClean(resolvedPath) {
3097
3113
  if (found.length === 0) {
3098
3114
  return check("pass", "dsstore_clean", "No .DS_Store in raw/", "No .DS_Store files found");
3099
3115
  }
3100
- return check("warn", "dsstore_clean", "No .DS_Store in raw/", `${found.length} .DS_Store file(s) found \u2014 remove with: find ${rawDir} -name .DS_Store -delete`);
3116
+ return check("info", "dsstore_clean", "No .DS_Store in raw/", `${found.length} .DS_Store file(s) found \u2014 remove with: find ${rawDir} -name .DS_Store -delete`);
3101
3117
  }
3102
3118
  function checkSyncLastPush(resolvedPath) {
3103
3119
  if (resolvedPath === void 0) {
@@ -3193,18 +3209,22 @@ async function runDoctor(input) {
3193
3209
  checks.push(checkPluginVersionDrift(input.home, input.currentVersion));
3194
3210
  const summary = {
3195
3211
  pass: checks.filter((c) => c.status === "pass").length,
3212
+ info: checks.filter((c) => c.status === "info").length,
3196
3213
  warn: checks.filter((c) => c.status === "warn").length,
3197
3214
  error: checks.filter((c) => c.status === "error").length
3198
3215
  };
3199
3216
  const exitCode = summary.error > 0 ? ExitCode.DOCTOR_HAS_ERRORS : summary.warn > 0 ? ExitCode.DOCTOR_HAS_WARNINGS : ExitCode.OK;
3200
- const statusIcon = { pass: "\u2713", warn: "\u26A0", error: "\u2717" };
3217
+ const statusIcon = { pass: "\u2713", info: "i", warn: "\u26A0", error: "\u2717" };
3201
3218
  const lines = checks.map((c) => {
3202
3219
  const icon = statusIcon[c.status];
3203
3220
  const padded = c.label.padEnd(24);
3204
3221
  return ` ${icon} ${padded} ${c.detail}`;
3205
3222
  });
3206
3223
  lines.push("");
3207
- lines.push(`${summary.pass} pass \xB7 ${summary.warn} warn \xB7 ${summary.error} error`);
3224
+ const summaryParts = [`${summary.pass} pass`];
3225
+ if (summary.info > 0) summaryParts.push(`${summary.info} info`);
3226
+ summaryParts.push(`${summary.warn} warn`, `${summary.error} error`);
3227
+ lines.push(summaryParts.join(" \xB7 "));
3208
3228
  const humanHint = lines.join("\n");
3209
3229
  return { exitCode, result: ok({ checks, summary, humanHint }) };
3210
3230
  }
@@ -4430,6 +4450,7 @@ function buildRawContent(sourceUrl, ingested, sha256, body) {
4430
4450
  const lines = [
4431
4451
  "---",
4432
4452
  sourceUrl !== null ? `source_url: "${sourceUrl}"` : "source_url:",
4453
+ `created: ${ingested}`,
4433
4454
  `ingested: ${ingested}`,
4434
4455
  `sha256: ${sha256}`,
4435
4456
  `ingested_by: wiki-ingest`,
@@ -5373,6 +5394,7 @@ This is a seed concept page. Concept pages capture topics, patterns, and ideas t
5373
5394
  };
5374
5395
  var EXAMPLE_RAW = `---
5375
5396
  source_url: https://example.com
5397
+ created: ${TODAY}
5376
5398
  ingested: ${TODAY}
5377
5399
  sha256: 0000000000000000000000000000000000000000000000000000000000000000
5378
5400
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
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.2.1",
3
+ "version": "0.2.3",
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/skills",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",
@@ -33,6 +33,12 @@ When reading retros as source material:
33
33
  `provenance: project` and
34
34
  `provenance_projects: ["[[slug]]"]`. Validate with
35
35
  `skillwiki validate`.
36
+ - **Tag hygiene:** `tags:` must only contain entries from
37
+ `{vault}/SCHEMA.md` taxonomy. Never derive tags from prose text
38
+ (lesson/evidence sections) — use only established taxonomy tags
39
+ (e.g., `dev-loop`, `lint`, `vault`). If no relevant taxonomy tag
40
+ exists, use `[dev-loop]` as the safe default rather than inventing
41
+ new tags. New tags must be added to SCHEMA.md first.
36
42
  3. **Backlink.** Set `promoted_to: "[[concept-slug]]"` on the source
37
43
  compound entry. For retro-sourced distillation, skip backlink (log.md
38
44
  entries are append-only) and instead add `sources:` citing the vault