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.
@@ -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":"AAKA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,WAAW,CAAA;AAmGnC,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA8GzE"}
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"}