UNPKG

@agentled/cli

Version:

CLI for Agentled — manage workflows, apps, and knowledge from the command line. Zero context-window cost for AI agents.

133 lines 5.16 kB
/** * Bootstrap `~/.agentled/` on `agentled setup` runs. * * Writes: * ~/.agentled/README.md (top-level pointer) * ~/.agentled/.content-version (refresh marker) * ~/.agentled/docs/WORKFLOW-SHAPE.md (canonical shape) * ~/.agentled/docs/GETTING-STARTED.md (5-min first workflow) * ~/.agentled/docs/GOTCHAS.md (silent failure modes) * ~/.agentled/docs/PATTERNS.md (scaffold index) * ~/.agentled/examples/scaffolds/* (copied from packages/cli/scaffolds/) * * **`docs/` and `examples/scaffolds/` are CLI-managed.** When the * bundled `HOME_CONTENT_VERSION` advances past the on-disk marker, the * bootstrap unconditionally rewrites every bundled file — user edits * to those files WILL be overwritten. Treat them as read-only and put * your own notes in `~/.agentled/docs/local/` (never touched) or in * the per-workspace `agentled_<slug>/` folder. * * `config.json` is never touched. * * `HOME_CONTENT_VERSION` is decoupled from the CLI semver — it bumps * only when bundled docs change, so a CLI patch release with no doc * change does NOT trigger a rewrite. * * Idempotent: a re-run with the same marker version is a no-op. */ import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, copyFileSync } from 'node:fs'; import { join } from 'node:path'; import { homedir } from 'node:os'; import { bundledScaffoldsDir } from './workspace-folder.js'; import { HOME_CONTENT_VERSION, HOME_README_MD, WORKFLOW_SHAPE_MD, GETTING_STARTED_MD, GOTCHAS_MD, PATTERNS_MD, } from './agentled-home-content.js'; const MARKER_FILE = '.content-version'; function readMarker(homeDir) { const path = join(homeDir, MARKER_FILE); if (!existsSync(path)) return null; try { return readFileSync(path, 'utf-8').trim() || null; } catch { return null; } } function writeMarker(homeDir) { writeFileSync(join(homeDir, MARKER_FILE), HOME_CONTENT_VERSION + '\n'); } /** * Compare integer-like marker versions: -1, 0, 1. * * `HOME_CONTENT_VERSION` is intentionally an opaque integer string * ("1", "2", …), but parsed defensively in case a future maintainer * uses a semver-shaped value. */ function compareVersions(a, b) { const parse = (v) => v.replace(/^v/, '').split('-')[0].split('.').map(n => parseInt(n, 10) || 0); const [a1, a2 = 0, a3 = 0] = parse(a); const [b1, b2 = 0, b3 = 0] = parse(b); if (a1 !== b1) return a1 < b1 ? -1 : 1; if (a2 !== b2) return a2 < b2 ? -1 : 1; if (a3 !== b3) return a3 < b3 ? -1 : 1; return 0; } function shouldRefresh(homeDir) { const installed = readMarker(homeDir); if (!installed) return true; // first run return compareVersions(installed, HOME_CONTENT_VERSION) < 0; } /** * Copy bundled scaffold assets into `examples/scaffolds/`. Includes * any `.json` pipeline scaffold and any `.md` companion documentation. * Other extensions are skipped — keep this whitelist tight so a stray * file in `packages/cli/scaffolds/` never lands in user-visible space. */ function copyBundledScaffolds(targetDir) { const sourceDir = bundledScaffoldsDir(); if (!existsSync(sourceDir)) return 0; mkdirSync(targetDir, { recursive: true }); let count = 0; for (const entry of readdirSync(sourceDir)) { if (!entry.endsWith('.json') && !entry.endsWith('.md')) continue; const src = join(sourceDir, entry); const dest = join(targetDir, entry); copyFileSync(src, dest); count++; } return count; } /** * Idempotent. Creates `~/.agentled/` if missing and rewrites the * bundled docs + scaffolds when the on-disk content version is older * than `HOME_CONTENT_VERSION`. Bundled files are unconditionally * overwritten on refresh; never touches `config.json` or any file * under `docs/local/`. */ export function bootstrapAgentledHome() { const homeDir = join(homedir(), '.agentled'); const docsDir = join(homeDir, 'docs'); const examplesDir = join(homeDir, 'examples'); const scaffoldsDir = join(examplesDir, 'scaffolds'); if (!existsSync(homeDir)) mkdirSync(homeDir, { recursive: true }); if (!shouldRefresh(homeDir)) { return { homeDir, refreshed: false, scaffoldsCopied: 0, version: readMarker(homeDir) ?? HOME_CONTENT_VERSION, }; } mkdirSync(docsDir, { recursive: true }); mkdirSync(scaffoldsDir, { recursive: true }); writeFileSync(join(homeDir, 'README.md'), HOME_README_MD); writeFileSync(join(docsDir, 'WORKFLOW-SHAPE.md'), WORKFLOW_SHAPE_MD); writeFileSync(join(docsDir, 'GETTING-STARTED.md'), GETTING_STARTED_MD); writeFileSync(join(docsDir, 'GOTCHAS.md'), GOTCHAS_MD); writeFileSync(join(docsDir, 'PATTERNS.md'), PATTERNS_MD); const scaffoldsCopied = copyBundledScaffolds(scaffoldsDir); writeMarker(homeDir); return { homeDir, refreshed: true, scaffoldsCopied, version: HOME_CONTENT_VERSION, }; } //# sourceMappingURL=home-bootstrap.js.map