@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 +18 -7
- package/dist/cli.js +41 -5
- package/package.json +3 -2
- package/schemas/config.schema.json +6 -1
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
|
|
87
|
-
|
|
|
88
|
-
| Docs/skills in scan perimeter
|
|
89
|
-
| `.sh`, `.bash`, `.zsh`
|
|
90
|
-
| Other `.json`
|
|
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) => !
|
|
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
|
|
28770
|
-
if (!
|
|
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(
|
|
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.
|
|
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
|
-
|
|
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
|
},
|