compose-md-cli 0.0.0 → 0.1.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.
@@ -1,5 +1,5 @@
1
1
  import { existsSync, mkdirSync, rmSync, writeFileSync } from 'fs';
2
- import { dirname, join } from 'path';
2
+ import { basename, dirname, join, relative } from 'path';
3
3
  import { loadApproach } from '../lib/approaches.js';
4
4
  import { scanFragments } from '../lib/fragments.js';
5
5
  import { getActiveApproach, setActiveApproach } from '../lib/active.js';
@@ -18,6 +18,24 @@ function resolveContent(fragmentIds, fragments) {
18
18
  }
19
19
  return parts.join('\n\n');
20
20
  }
21
+ function generateIndexContent(docsRoot, fragments) {
22
+ const described = [...fragments.values()].filter((f) => f.description);
23
+ const sorted = described.sort((a, b) => {
24
+ const relA = relative(docsRoot, a.filePath);
25
+ const relB = relative(docsRoot, b.filePath);
26
+ const dirA = dirname(relA);
27
+ const dirB = dirname(relB);
28
+ if (dirA !== dirB)
29
+ return dirA.localeCompare(dirB);
30
+ return basename(relA).localeCompare(basename(relB));
31
+ });
32
+ const lines = ['# Fragment Index', ''];
33
+ for (const fragment of sorted) {
34
+ const relPath = relative(docsRoot, fragment.filePath);
35
+ lines.push(`- **${fragment.name}** (${relPath}): ${fragment.description}`);
36
+ }
37
+ return lines.join('\n') + '\n';
38
+ }
21
39
  export async function applyApproach(docsRoot, name, cwd) {
22
40
  const previousActive = getActiveApproach(cwd);
23
41
  if (previousActive && previousActive !== name) {
@@ -44,6 +62,8 @@ export async function applyApproach(docsRoot, name, cwd) {
44
62
  writeFileSync(fullPath, composed + '\n');
45
63
  console.log(`Written: ${outputPath}`);
46
64
  }
65
+ const indexContent = generateIndexContent(docsRoot, fragments);
66
+ writeFileSync(join(docsRoot, '_index.md'), indexContent);
47
67
  setActiveApproach(cwd, name);
48
68
  console.log(`\nApplied: ${name}`);
49
69
  }
@@ -2,7 +2,8 @@ import { input, confirm } from '@inquirer/prompts';
2
2
  import { existsSync, mkdirSync, writeFileSync, readFileSync, appendFileSync, readdirSync } from 'fs';
3
3
  import { join, relative, basename, dirname, sep } from 'path';
4
4
  import { fileURLToPath } from 'url';
5
- import { CONFIG_FILE, setDocsRootConfig } from '../lib/config.js';
5
+ import { setDocsRootConfig } from '../lib/config.js';
6
+ import { applyApproach } from './apply.js';
6
7
  // Filenames recognized anywhere in the project tree.
7
8
  const AGENT_FILENAMES = new Set([
8
9
  'AGENTS.md', // OpenAI Codex, generic
@@ -146,7 +147,6 @@ function buildDefaultYaml(agentFiles, startingPrompts, startingSkills) {
146
147
  'outputs:',
147
148
  ` ${rootSourcePath}:`,
148
149
  ...startingIncludes,
149
- ' - "@getting-started"',
150
150
  ];
151
151
  if (rootFile) {
152
152
  lines.push(` - "@${rootFile.fragmentId}"`);
@@ -165,7 +165,6 @@ function ensureGitignore(cwd, docsRootName) {
165
165
  const gitignorePath = join(cwd, '.gitignore');
166
166
  const entries = [
167
167
  '.compose-active',
168
- CONFIG_FILE,
169
168
  `${docsRootName}/_index.md`,
170
169
  ];
171
170
  const gitignoreExisted = existsSync(gitignorePath);
@@ -183,22 +182,6 @@ export function scaffoldProject(cwd, docsRootName) {
183
182
  // Directories
184
183
  mkdirSync(join(docsRoot, '_approaches'), { recursive: true });
185
184
  created.push(`${docsRootName}/_approaches/`);
186
- // Sample fragment
187
- const sampleFragment = join(docsRoot, 'getting-started.md');
188
- if (!existsSync(sampleFragment)) {
189
- writeFileSync(sampleFragment, [
190
- '---',
191
- 'name: getting-started',
192
- 'description: quick-start guide for new contributors',
193
- '---',
194
- '',
195
- '# Getting Started',
196
- '',
197
- '<!-- Add your getting started content here -->',
198
- '',
199
- ].join('\n'));
200
- created.push(`${docsRootName}/getting-started.md`);
201
- }
202
185
  // Curated starter fragments shipped with compose-md
203
186
  const startingPrompts = copyStartingPrompts(docsRoot, docsRootName, created);
204
187
  const startingSkills = copyStartingSkills(docsRoot, docsRootName, created);
@@ -269,6 +252,16 @@ export async function runInit(cwd) {
269
252
  console.log(` ${sourcePath} → @${fragmentId}`);
270
253
  }
271
254
  }
272
- console.log('\nDone. Run `compose` to select and apply an approach.');
255
+ const shouldApply = await confirm({
256
+ message: "Now run 'compose apply'?",
257
+ default: true,
258
+ });
259
+ if (shouldApply) {
260
+ console.log('');
261
+ await applyApproach(docsRoot, 'default', cwd);
262
+ }
263
+ else {
264
+ console.log('\nDone. Run `compose apply default` when you are ready.');
265
+ }
273
266
  }
274
267
  export { findAgentFiles };
@@ -5,7 +5,7 @@ function parseFrontmatter(raw) {
5
5
  if (!match)
6
6
  return { data: {}, body: raw };
7
7
  const data = {};
8
- for (const line of (match[1] ?? '').split('\n')) {
8
+ for (const line of match[1].split('\n')) {
9
9
  const colonIdx = line.indexOf(':');
10
10
  if (colonIdx === -1)
11
11
  continue;
@@ -13,7 +13,7 @@ function parseFrontmatter(raw) {
13
13
  const value = line.slice(colonIdx + 1).trim().replace(/^["']|["']$/g, '');
14
14
  data[key] = value;
15
15
  }
16
- return { data, body: match[2] ?? '' };
16
+ return { data, body: match[2] };
17
17
  }
18
18
  export function scanFragments(docsRoot) {
19
19
  const fragments = new Map();
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: compose-docs
3
- description: Edit and regenerate this project's agent instruction files (AGENTS.md, CLAUDE.md, SKILL.md, etc.), which are generated by compose-md from fragments and approaches. Use this whenever you would normally write durable memory directly into one of those files.
3
+ description: Edit and regenerate this project's agent instruction files (AGENTS.md, CLAUDE.md, SKILL.md, etc.), which are generated by compose-md from fragments and approaches. Use this whenever you would normally create or edit agent instruction files, including updating your memory.
4
4
  ---
5
5
 
6
6
  # compose-docs
package/package.json CHANGED
@@ -1,10 +1,17 @@
1
1
  {
2
2
  "name": "compose-md-cli",
3
- "module": "index.ts",
3
+ "version": "0.1.0",
4
+ "description": "A CLI for composing markdown agent context files (CLAUDE.md, AGENTS.md, etc.) from reusable fragments and YAML approach configs.",
4
5
  "type": "module",
5
- "private": false,
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/dwjohnston/compose-md.git"
10
+ },
11
+ "main": "./dist/cli.js",
12
+ "exports": "./dist/cli.js",
6
13
  "bin": {
7
- "compose": "dist/cli.js"
14
+ "compose": "./dist/cli.js"
8
15
  },
9
16
  "files": [
10
17
  "dist"
@@ -17,9 +24,13 @@
17
24
  "clean": "rm -rf projectDocs && git checkout -- .gitignore",
18
25
  "docs:dev": "vitepress dev",
19
26
  "docs:build": "vitepress build",
20
- "docs:preview": "vitepress preview"
27
+ "docs:preview": "vitepress preview",
28
+ "changeset": "changeset",
29
+ "version": "changeset version",
30
+ "release": "changeset publish"
21
31
  },
22
32
  "devDependencies": {
33
+ "@changesets/cli": "^2.31.0",
23
34
  "@types/bun": "latest",
24
35
  "@types/js-yaml": "^4.0.9",
25
36
  "typescript": "^5",
@@ -31,6 +42,5 @@
31
42
  "dependencies": {
32
43
  "@inquirer/prompts": "^8.5.2",
33
44
  "js-yaml": "^5.2.0"
34
- },
35
- "version": "0.0.0"
45
+ }
36
46
  }