contentbit 0.1.0 → 0.2.0
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 +4 -0
- package/dist/bin.js +1064 -88
- package/dist/commands/agents.d.ts +11 -0
- package/dist/commands/agents.d.ts.map +1 -0
- package/dist/commands/agents.js +197 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +411 -39
- package/dist/commands/stats.d.ts +3 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +49 -0
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +5 -2
- package/dist/load-registry.d.ts.map +1 -1
- package/dist/load-registry.js +10 -1
- package/dist/run.d.ts +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +1062 -86
- package/package.json +7 -4
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Io } from '../run.js';
|
|
2
|
+
export interface AgentOptions {
|
|
3
|
+
/** Install Claude Code skills; defaults to detecting a .claude/ directory. */
|
|
4
|
+
claude?: boolean;
|
|
5
|
+
/** Manage the AGENTS.md block; defaults to true. */
|
|
6
|
+
agentsMd?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Install or refresh the agent integration. Shared by `agents` and `init`. */
|
|
9
|
+
export declare function installAgentIntegration(cwd: string, options: AgentOptions, io: Io): Promise<void>;
|
|
10
|
+
export declare function agentsCommand(args: string[], io: Io): Promise<number>;
|
|
11
|
+
//# sourceMappingURL=agents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/commands/agents.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,WAAW,CAAA;AA2JnC,MAAM,WAAW,YAAY;IAC3B,8EAA8E;IAC9E,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,+EAA+E;AAC/E,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,YAAY,EACrB,EAAE,EAAE,EAAE,GACL,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAkB3E"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { parseArgs } from 'node:util';
|
|
5
|
+
// Everything here is static and project-independent by design: skills fetch
|
|
6
|
+
// live data (authoring guide, stats, diagnostics) by running the CLI, so the
|
|
7
|
+
// registry stays the single source of truth and nothing can drift. Bump the
|
|
8
|
+
// frontmatter version when a template changes; `contentbit agents` re-runs
|
|
9
|
+
// overwrite in place.
|
|
10
|
+
const TEMPLATE_VERSION = 1;
|
|
11
|
+
const AUTHOR_SKILL = `---
|
|
12
|
+
name: contentbit-author
|
|
13
|
+
description: |
|
|
14
|
+
Write or edit contentbit Markdown content (directive blocks like :::callout).
|
|
15
|
+
Use when asked to create or modify content documents in a project that uses
|
|
16
|
+
contentbit — blog posts, docs pages, changelogs, any Markdown covered by
|
|
17
|
+
\`contentbit validate\`.
|
|
18
|
+
version: ${TEMPLATE_VERSION}
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Writing contentbit content
|
|
22
|
+
|
|
23
|
+
contentbit documents are plain Markdown plus directive blocks
|
|
24
|
+
(\`:::name{props} ... :::\`). Every block has a schema. Never guess block names,
|
|
25
|
+
props, or body shapes — fetch the live guide from the project's registry first.
|
|
26
|
+
|
|
27
|
+
## Find the project conventions
|
|
28
|
+
|
|
29
|
+
Check \`package.json\` for a \`content:check\` script. It holds the canonical
|
|
30
|
+
validate invocation for this project: the content glob and, if present, the
|
|
31
|
+
\`--registry <path>\` flag pointing at custom block definitions. Reuse both
|
|
32
|
+
below. No script? Default to \`content/**/*.md\` with no \`--registry\` flag.
|
|
33
|
+
|
|
34
|
+
## The loop
|
|
35
|
+
|
|
36
|
+
1. **Fetch the authoring guide** (always — it covers this project's custom blocks):
|
|
37
|
+
|
|
38
|
+
\`\`\`sh
|
|
39
|
+
contentbit instructions --audience llm [--registry <path from content:check>]
|
|
40
|
+
\`\`\`
|
|
41
|
+
|
|
42
|
+
Read it before writing. It documents every available block: props, body
|
|
43
|
+
shape, and when to use or avoid it.
|
|
44
|
+
|
|
45
|
+
2. **Write the document.** Plain Markdown everywhere; blocks only where the
|
|
46
|
+
guide's use-when guidance fits. Keep frontmatter consistent with sibling
|
|
47
|
+
documents in the same folder.
|
|
48
|
+
|
|
49
|
+
3. **Validate and fix until clean:**
|
|
50
|
+
|
|
51
|
+
\`\`\`sh
|
|
52
|
+
contentbit validate <file> [--registry <path>]
|
|
53
|
+
\`\`\`
|
|
54
|
+
|
|
55
|
+
Diagnostics print to stderr as \`file:line:col severity CODE message\`, often
|
|
56
|
+
with a \`hint:\` line suggesting the fix. Exit 0 means clean; exit 1 means
|
|
57
|
+
errors remain. Fix every diagnostic and re-run. Never finish with a failing
|
|
58
|
+
validate.
|
|
59
|
+
|
|
60
|
+
## Failure modes
|
|
61
|
+
|
|
62
|
+
- \`contentbit\` not found or no registry resolvable: the project is not set up.
|
|
63
|
+
Say so and suggest \`npx contentbit@latest init\` — do not invent block syntax.
|
|
64
|
+
- A block you want does not exist: use plain Markdown, or ask whether to define
|
|
65
|
+
a custom block in the registry. Never emit an unregistered block name.
|
|
66
|
+
`;
|
|
67
|
+
const AUDIT_SKILL = `---
|
|
68
|
+
name: contentbit-audit
|
|
69
|
+
description: |
|
|
70
|
+
Audit contentbit Markdown content health using document stats. Use when asked
|
|
71
|
+
to audit, review, or find improvements across content — thin pages, missing
|
|
72
|
+
structure, validation issues — in a project that uses contentbit.
|
|
73
|
+
version: ${TEMPLATE_VERSION}
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
# Auditing contentbit content
|
|
77
|
+
|
|
78
|
+
\`contentbit stats\` analyzes documents and prints JSON to stdout. It is a read
|
|
79
|
+
tool: it always exits 0, even when documents have validation errors.
|
|
80
|
+
|
|
81
|
+
## Gather
|
|
82
|
+
|
|
83
|
+
Check \`package.json\` for the \`content:check\` script to find this project's
|
|
84
|
+
content glob and \`--registry\` flag, then:
|
|
85
|
+
|
|
86
|
+
\`\`\`sh
|
|
87
|
+
contentbit stats "content/**/*.md" [--registry <path>]
|
|
88
|
+
\`\`\`
|
|
89
|
+
|
|
90
|
+
One matched file prints a single stats object; multiple files print an array.
|
|
91
|
+
Each entry includes the file path, frontmatter data, a heading \`outline\` with
|
|
92
|
+
per-section word counts, \`blocks.byName\` usage counts, \`links.domains\`, and
|
|
93
|
+
a \`validation\` summary (\`errors\`/\`warnings\`).
|
|
94
|
+
|
|
95
|
+
## Interpret
|
|
96
|
+
|
|
97
|
+
Prioritize findings in this order:
|
|
98
|
+
|
|
99
|
+
1. **Validation errors and warnings** — broken content ships broken pages.
|
|
100
|
+
2. **Thin documents** — outline sections with very low word counts.
|
|
101
|
+
3. **Block-less documents** — \`blocks.byName\` empty where sibling documents
|
|
102
|
+
use blocks; structure (steps, callouts, comparisons, faq) may be missing.
|
|
103
|
+
4. **Missing or inconsistent frontmatter** compared to sibling documents.
|
|
104
|
+
5. **Structural imbalance** — skipped heading levels, single-section walls of text.
|
|
105
|
+
|
|
106
|
+
## Report
|
|
107
|
+
|
|
108
|
+
Report findings per file with concrete suggestions, ordered by priority. Do not
|
|
109
|
+
edit files during the audit. To fix a finding, follow the contentbit-author
|
|
110
|
+
skill (fetch the guide, edit, validate until clean) — offer that as a follow-up.
|
|
111
|
+
`;
|
|
112
|
+
const AGENTS_MD_BLOCK = `<!-- contentbit:start -->
|
|
113
|
+
|
|
114
|
+
## contentbit content (generated — edits inside this block are overwritten)
|
|
115
|
+
|
|
116
|
+
This project validates Markdown content with contentbit. Documents are plain
|
|
117
|
+
Markdown plus directive blocks (\`:::name{props} ... :::\`), each with a schema.
|
|
118
|
+
The \`content:check\` script in package.json holds the canonical validate
|
|
119
|
+
command — the content glob and the \`--registry\` flag — reuse its arguments.
|
|
120
|
+
|
|
121
|
+
When writing or editing content:
|
|
122
|
+
|
|
123
|
+
1. Fetch the live authoring guide first — never guess block syntax:
|
|
124
|
+
\`contentbit instructions --audience llm [--registry <path>]\`
|
|
125
|
+
2. Write plain Markdown; use blocks where the guide's use-when guidance fits.
|
|
126
|
+
3. Validate until clean (exit 0): \`contentbit validate <file> [--registry <path>]\`.
|
|
127
|
+
Diagnostics print as \`file:line:col severity CODE message\` with fix hints.
|
|
128
|
+
|
|
129
|
+
When auditing content health:
|
|
130
|
+
|
|
131
|
+
- \`contentbit stats "content/**/*.md" [--registry <path>]\` prints JSON stats
|
|
132
|
+
and always exits 0: outline word counts, block usage, link domains, and
|
|
133
|
+
validation error/warning counts. Flag validation issues, thin documents, and
|
|
134
|
+
block-less pages first.
|
|
135
|
+
|
|
136
|
+
If \`contentbit\` is unavailable, suggest \`npx contentbit@latest init\` instead
|
|
137
|
+
of inventing block syntax.
|
|
138
|
+
|
|
139
|
+
<!-- contentbit:end -->`;
|
|
140
|
+
const START = '<!-- contentbit:start -->';
|
|
141
|
+
const END = '<!-- contentbit:end -->';
|
|
142
|
+
/** Insert or replace the fenced contentbit block, leaving the rest untouched. */
|
|
143
|
+
function upsertBlock(existing) {
|
|
144
|
+
const start = existing.indexOf(START);
|
|
145
|
+
const end = existing.indexOf(END);
|
|
146
|
+
if (start !== -1 && end !== -1) {
|
|
147
|
+
return existing.slice(0, start) + AGENTS_MD_BLOCK + existing.slice(end + END.length);
|
|
148
|
+
}
|
|
149
|
+
if (existing.trim() === '')
|
|
150
|
+
return `${AGENTS_MD_BLOCK}\n`;
|
|
151
|
+
return `${existing.replace(/\n*$/, '\n\n')}${AGENTS_MD_BLOCK}\n`;
|
|
152
|
+
}
|
|
153
|
+
/** Install or refresh the agent integration. Shared by `agents` and `init`. */
|
|
154
|
+
export async function installAgentIntegration(cwd, options, io) {
|
|
155
|
+
const claude = options.claude ?? existsSync(join(cwd, '.claude'));
|
|
156
|
+
const agentsMd = options.agentsMd ?? true;
|
|
157
|
+
if (agentsMd) {
|
|
158
|
+
const path = join(cwd, 'AGENTS.md');
|
|
159
|
+
let existing = '';
|
|
160
|
+
try {
|
|
161
|
+
existing = await readFile(path, 'utf8');
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
/* not there yet */
|
|
165
|
+
}
|
|
166
|
+
const created = existing === '';
|
|
167
|
+
await writeFile(path, upsertBlock(existing), 'utf8');
|
|
168
|
+
io.stdout(`${created ? 'created' : 'updated'}: AGENTS.md (contentbit block)`);
|
|
169
|
+
}
|
|
170
|
+
if (claude) {
|
|
171
|
+
const skills = [
|
|
172
|
+
['contentbit-author', AUTHOR_SKILL],
|
|
173
|
+
['contentbit-audit', AUDIT_SKILL],
|
|
174
|
+
];
|
|
175
|
+
for (const [name, content] of skills) {
|
|
176
|
+
const dir = join(cwd, '.claude/skills', name);
|
|
177
|
+
await mkdir(dir, { recursive: true });
|
|
178
|
+
await writeFile(join(dir, 'SKILL.md'), content, 'utf8');
|
|
179
|
+
io.stdout(`installed: .claude/skills/${name}/SKILL.md`);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
export async function agentsCommand(args, io) {
|
|
184
|
+
const { values } = parseArgs({
|
|
185
|
+
args,
|
|
186
|
+
options: {
|
|
187
|
+
claude: { type: 'boolean', default: false },
|
|
188
|
+
'no-agents-md': { type: 'boolean', default: false },
|
|
189
|
+
cwd: { type: 'string', default: process.cwd() },
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
await installAgentIntegration(values.cwd, {
|
|
193
|
+
claude: values.claude || undefined, // false means "detect", not "skip"
|
|
194
|
+
agentsMd: !values['no-agents-md'],
|
|
195
|
+
}, io);
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,WAAW,CAAA;AAgYnC,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAyNzE"}
|