@csark0812/skeleton 1.1.1 → 1.1.2

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/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Skeleton
2
2
 
3
+ **Source of truth for** Package overview.
4
+
5
+ <!-- doc-meta: owner=eng | last-reviewed=2026-07-13 -->
6
+
3
7
  Single source of truth (SSOT) linter for agent-enabled repos.
4
8
 
5
9
  Agent repos accumulate skills, rules, registries, and cross-linked docs faster than anyone can keep them straight by hand. Code repos solved this decades ago with ESLint — deterministic checks, CI gates, fix what you can before merge. Skeleton does the same job for documentation architecture: what's canonical, what links where, what must not exist, and whether your skill overrides are wired correctly.
@@ -83,12 +87,12 @@ skeleton customize resolve <slug>
83
87
 
84
88
  **Validate changed** routes git diffs to the right audit:
85
89
 
86
- | Path | Action |
87
- | -------------------------------------------- | --------------------------- |
88
- | Docs/skills in scan perimeter | path-scoped audit |
89
- | `.sh`, `.bash`, `.zsh` | shellcheck or `bash -n` |
90
- | Other `.json` | JSONC-tolerant syntax check |
91
- | `.ts`, `.py`, `package.json`, `project.json` | skip |
90
+ | Path | Action |
91
+ | ----------------------------------------------------------------- | --------------------------- |
92
+ | Docs/skills in scan perimeter | path-scoped audit |
93
+ | `.sh`, `.bash`, `.zsh` | shellcheck or `bash -n` |
94
+ | Other `.json` | JSONC-tolerant syntax check |
95
+ | `.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`, `.cjs`, `.py`, `package.json`, `project.json` | skip (exits 1 if all skip) |
92
96
 
93
97
  Pre-commit: `skeleton validate changed --staged` (path-scoped, fast).
94
98
  CI: `skeleton validate changed --base origin/main` (global rules first, then changed files).
@@ -128,11 +132,18 @@ One command for humans: `npx skeleton init --skills`.
128
132
 
129
133
  ## Development
130
134
 
131
- Requires Node ≥ 22. Uses Bun for dev and tests.
135
+ Requires Node ≥ 22. Uses Bun for dev and tests. Agent cold-start: [AGENTS.md](AGENTS.md).
132
136
 
133
137
  ```bash
134
138
  bun install
135
139
  bun test
140
+ bun run typecheck
136
141
  bun run build
137
142
  bun run audit:self
138
143
  ```
144
+
145
+ `validate:changed` is docs/skills only — it skips code/config extensions (see table). All-skip inputs exit non-zero. Use `bun test` and `bun run typecheck` for code.
146
+
147
+ ### Publishing 1.1.2 (human)
148
+
149
+ Keep version `1.1.2` until `npm publish`. Preflight: `bun test && bun run typecheck && bun run build && bun run audit:self`. Then publish and tag when ready (npm is still on `1.1.1` until then).
package/dist/cli.js CHANGED
@@ -16595,6 +16595,9 @@ function mergedExcludes(config) {
16595
16595
  function retiredSkills(config) {
16596
16596
  return config.scan.retiredSkills ?? [];
16597
16597
  }
16598
+ function nonPublicSkills(config) {
16599
+ return config.scan.nonPublicSkills ?? [];
16600
+ }
16598
16601
 
16599
16602
  // src/audit/core/skill-roots.ts
16600
16603
  import { existsSync as existsSync2, readdirSync as readdirSync2, readlinkSync, realpathSync as realpathSync2 } from "node:fs";
@@ -28605,7 +28608,6 @@ function isGeneratedReference(content3) {
28605
28608
  }
28606
28609
 
28607
28610
  // src/audit/rules/skill-index.ts
28608
- var NON_PUBLIC_SLUGS = new Set(["align-commands"]);
28609
28611
  function walkSkillMarkdown(dir) {
28610
28612
  const files = [];
28611
28613
  if (!existsSync8(dir))
@@ -28659,6 +28661,7 @@ function scanFileForSkillLinks(ctx, filePath, index2) {
28659
28661
  }
28660
28662
  function validateReadmeTaxonomy(ctx, index2, diskSlugs) {
28661
28663
  const issues = [];
28664
+ const nonPublic = new Set(nonPublicSkills(ctx.config));
28662
28665
  for (const skillRoot of index2.roots) {
28663
28666
  if (skillRoot.kind !== "nested")
28664
28667
  continue;
@@ -28670,7 +28673,7 @@ function validateReadmeTaxonomy(ctx, index2, diskSlugs) {
28670
28673
  continue;
28671
28674
  const taxonomySlugs = parseReadmeTaxonomySlugs(readme);
28672
28675
  const nestedSlugs = diskSlugs.filter((slug2) => existsSync8(join8(ctx.root, skillRoot.relPath, slug2, "SKILL.md")));
28673
- const publicSlugs = nestedSlugs.filter((slug2) => !NON_PUBLIC_SLUGS.has(slug2));
28676
+ const publicSlugs = nestedSlugs.filter((slug2) => !nonPublic.has(slug2));
28674
28677
  const relReadme = `${skillRoot.relPath}/README.md`;
28675
28678
  for (const slug2 of publicSlugs) {
28676
28679
  if (!taxonomySlugs.includes(slug2)) {
@@ -28764,10 +28767,16 @@ function findLocalCanonicalLinks(root2, content3, sourceFile) {
28764
28767
  }
28765
28768
  const inReferencesDir = /\/references\//.test(sourceFile);
28766
28769
  if (inReferencesDir) {
28770
+ const refsIdx = sourceFile.lastIndexOf("/references/");
28771
+ const withinRefs = sourceFile.slice(refsIdx + "/references/".length);
28772
+ const withinDir = withinRefs.includes("/") ? withinRefs.slice(0, withinRefs.lastIndexOf("/")) : "";
28767
28773
  const siblingRe = /\((?!https?:|#|\.\.\/)([a-z0-9./_-]+\.md)\)/gi;
28768
28774
  for (const match of content3.matchAll(siblingRe)) {
28769
- const refPath = normalizeRelPath(match[1] ?? "");
28770
- if (!refPath || !canonicalExists(root2, refPath))
28775
+ const raw = normalizeRelPath(match[1] ?? "");
28776
+ if (!raw)
28777
+ continue;
28778
+ const refPath = withinDir ? normalizeRelPath(join9(withinDir, raw)) : raw;
28779
+ if (!canonicalExists(root2, refPath))
28771
28780
  continue;
28772
28781
  links.push({ refPath, sourceFile });
28773
28782
  }
@@ -28796,6 +28805,21 @@ function discoverSkillReferencePlans(root2) {
28796
28805
  links.push(link2);
28797
28806
  }
28798
28807
  }
28808
+ const queue = [...refPaths];
28809
+ while (queue.length > 0) {
28810
+ const refPath = queue.pop();
28811
+ if (!refPath || !canonicalExists(root2, refPath))
28812
+ continue;
28813
+ const canonicalContent = readFileSync8(join9(root2, CANONICAL_REFS_DIR, refPath), "utf8");
28814
+ const syntheticSource = generatedRefPath(slug2, refPath);
28815
+ for (const link2 of findLocalCanonicalLinks(root2, canonicalContent, syntheticSource)) {
28816
+ if (refPaths.has(link2.refPath))
28817
+ continue;
28818
+ refPaths.add(link2.refPath);
28819
+ links.push(link2);
28820
+ queue.push(link2.refPath);
28821
+ }
28822
+ }
28799
28823
  if (refPaths.size > 0) {
28800
28824
  plans.push({ skill: slug2, refPaths, links });
28801
28825
  }
@@ -29787,6 +29811,7 @@ function runValidateChanged(options = {}) {
29787
29811
  }
29788
29812
  buckets[bucket].push(relPath2);
29789
29813
  }
29814
+ const audited = buckets.docs.length + buckets.skills.length + buckets.shell.length + buckets.json.length;
29790
29815
  let exitCode = 0;
29791
29816
  if (options.base) {
29792
29817
  const globalExit = runAudit({
@@ -29801,6 +29826,12 @@ function runValidateChanged(options = {}) {
29801
29826
  if (globalExit !== 0)
29802
29827
  exitCode = 1;
29803
29828
  }
29829
+ if (skipped > 0 && audited === 0) {
29830
+ console.error(`validate changed: all paths were skipped (code/config). This does not verify TypeScript or app code.
29831
+ ` + ` In this repo: bun test && bun run typecheck
29832
+ ` + " Consumers: run your local code validation gates.");
29833
+ return 1;
29834
+ }
29804
29835
  if (buckets.docs.length > 0) {
29805
29836
  const docExit = runAudit({
29806
29837
  suite: "docs",
@@ -30062,7 +30093,12 @@ function main() {
30062
30093
  console.error("register: path required");
30063
30094
  process.exit(1);
30064
30095
  }
30065
- registerPath(opts);
30096
+ registerPath({
30097
+ path: opts.path,
30098
+ topic: opts.topic,
30099
+ dryRun: opts.dryRun,
30100
+ json: opts.json
30101
+ });
30066
30102
  process.exit(0);
30067
30103
  }
30068
30104
  if (command === "customize" && argv[1] === "resolve") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@csark0812/skeleton",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "SSOT audit CLI for agent harness repos",
5
5
  "type": "module",
6
6
  "bin": {
@@ -20,12 +20,13 @@
20
20
  "test": "bun test",
21
21
  "test:audit": "bun test src/audit/__tests__",
22
22
  "test:cli": "bun test src/__tests__/cli",
23
+ "typecheck": "tsc -p tsconfig.json --noEmit",
23
24
  "validate:changed": "bun src/cli.ts validate changed",
24
25
  "validate:ci": "bun src/cli.ts validate changed --base origin/main",
25
26
  "audit:docs": "bun src/cli.ts audit docs",
26
27
  "audit:skills": "bun src/cli.ts audit skills",
27
28
  "audit:self": "bun src/cli.ts audit self",
28
- "prepack": "bun test && bun run build"
29
+ "prepack": "bun test && bun run typecheck && bun run build"
29
30
  },
30
31
  "dependencies": {
31
32
  "ajv": "^8.17.1",
@@ -24,9 +24,14 @@
24
24
  "type": "array",
25
25
  "items": { "type": "string" }
26
26
  },
27
- "retiredSkills": {
27
+ "retiredSkills": {
28
28
  "type": "array",
29
29
  "items": { "type": "string", "pattern": "^[a-z0-9-]+$" }
30
+ },
31
+ "nonPublicSkills": {
32
+ "type": "array",
33
+ "items": { "type": "string", "pattern": "^[a-z0-9-]+$" },
34
+ "description": "Skill slugs that exist on disk but must not appear in README Taxonomy (consumer-internal skills)"
30
35
  }
31
36
  }
32
37
  },