@baseline-studio/cli 2.2.5 → 2.6.1

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 CHANGED
@@ -36,7 +36,10 @@ Updates come from git tags via `npx baseline update`, not from npm.
36
36
 
37
37
  ```
38
38
  your-system/
39
- ├── CLAUDE.md # Claude Code automation (don't edit)
39
+ ├── AGENTS.md # AI instructions for all coding tools (don't edit)
40
+ ├── CLAUDE.md # Claude Code pointer to AGENTS.md
41
+ ├── .github/
42
+ │ └── copilot-instructions.md # GitHub Copilot pointer to AGENTS.md
40
43
  ├── baseline.config.json # Version tracking
41
44
  ├── skills/ # 12 domain expertise modules
42
45
  ├── context/ # Your business knowledge (you own this)
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.context = context;
4
37
  const readline_1 = require("readline");
@@ -6,6 +39,7 @@ const fs_1 = require("fs");
6
39
  const path_1 = require("path");
7
40
  const js_yaml_1 = require("js-yaml");
8
41
  const config_js_1 = require("../config.js");
42
+ const ui = __importStar(require("../ui.js"));
9
43
  let rlClosed = false;
10
44
  function ask(rl, question) {
11
45
  if (rlClosed)
@@ -32,33 +66,41 @@ async function contextRefresh() {
32
66
  const config = (0, config_js_1.readConfig)();
33
67
  const cwd = process.cwd();
34
68
  const contextDir = (0, path_1.join)(cwd, config.client.contextPath || "./context");
69
+ ui.header("Baseline Context", "Update Context Files");
35
70
  // Load prompts from local skills (they were pulled from core via update)
36
- const skillsDir = (0, path_1.join)(cwd, "skills");
71
+ const spin = ui.spinner("Fetching latest prompts...");
37
72
  const prompts = loadPromptsFromLocal(cwd);
73
+ spin.stop("Prompts loaded");
38
74
  if (Object.keys(prompts).length === 0) {
39
- console.error(" Error: No context prompts found. Run `baseline update` first.\n");
75
+ ui.error("No context prompts found. Run `baseline update` first.");
76
+ console.log();
40
77
  process.exit(1);
41
78
  }
42
79
  const rl = (0, readline_1.createInterface)({ input: process.stdin, output: process.stdout });
43
80
  rl.on("close", () => { rlClosed = true; });
44
- console.log(`\n Baseline Context — Update Context Files`);
45
- console.log(` ────────────────────────────────────────\n`);
46
- console.log(` Existing answers shown in [brackets]. Press Enter to keep them.\n`);
81
+ console.log();
82
+ ui.info("Existing answers shown in [brackets]. Press Enter to keep them.");
83
+ console.log();
47
84
  let filesUpdated = 0;
48
- for (const [ctxFile, prompt] of Object.entries(prompts)) {
85
+ const entries = Object.entries(prompts);
86
+ let sectionIndex = 0;
87
+ for (const [ctxFile, prompt] of entries) {
88
+ sectionIndex++;
49
89
  const fullPath = (0, path_1.join)(contextDir, ctxFile);
50
90
  const existingContent = (0, fs_1.existsSync)(fullPath) ? (0, fs_1.readFileSync)(fullPath, "utf-8") : "";
51
91
  const existingAnswers = parseExistingAnswers(existingContent, prompt.questions);
52
- console.log(` ── ${prompt.title} ──\n`);
92
+ ui.sectionHeader(prompt.title, sectionIndex, entries.length);
53
93
  const answers = [];
94
+ let answeredCount = 0;
54
95
  for (let i = 0; i < prompt.questions.length; i++) {
55
96
  const q = prompt.questions[i];
56
97
  const existing = existingAnswers[i] || "";
57
- const hint = existing ? ` [${truncate(existing, 60)}]` : "";
58
- const answer = await ask(rl, ` ${q}${hint}\n > `);
98
+ const hint = existing ? truncate(existing, 60) : undefined;
99
+ const answer = await ask(rl, ui.formatPromptWithProgress(q, i + 1, prompt.questions.length, hint));
59
100
  const final = answer.trim() || existing;
60
101
  if (final) {
61
102
  answers.push(`**${q}**\n${final}`);
103
+ answeredCount++;
62
104
  }
63
105
  console.log();
64
106
  }
@@ -70,10 +112,12 @@ async function contextRefresh() {
70
112
  else if (!(0, fs_1.existsSync)(fullPath)) {
71
113
  (0, fs_1.writeFileSync)(fullPath, `# ${prompt.title}\n\n<!-- Add your content here -->\n`);
72
114
  }
115
+ ui.sectionComplete(prompt.title, answeredCount, prompt.questions.length);
73
116
  }
74
117
  rl.close();
75
- console.log(` ────────────────────────────────────────`);
76
- console.log(` Updated ${filesUpdated} context files.\n`);
118
+ ui.divider();
119
+ ui.success(`Updated ${filesUpdated} context files.`);
120
+ console.log();
77
121
  }
78
122
  /** Create a new context file and wire it into context.yaml */
79
123
  async function contextAdd(name) {
@@ -85,7 +129,8 @@ async function contextAdd(name) {
85
129
  const fileName = name.endsWith(".md") ? name : `${name}.md`;
86
130
  const filePath = (0, path_1.join)(contextDir, "extended", fileName);
87
131
  if ((0, fs_1.existsSync)(filePath)) {
88
- console.error(`\n Error: context/extended/${fileName} already exists.\n`);
132
+ ui.error(`context/extended/${fileName} already exists.`);
133
+ console.log();
89
134
  process.exit(1);
90
135
  }
91
136
  // Get available skills
@@ -101,21 +146,21 @@ async function contextAdd(name) {
101
146
  skills.sort();
102
147
  const rl = (0, readline_1.createInterface)({ input: process.stdin, output: process.stdout });
103
148
  rl.on("close", () => { rlClosed = true; });
104
- console.log(`\n Baseline Context Add New File`);
105
- console.log(` ───────────────────────────────\n`);
106
- console.log(` Creating: context/extended/${fileName}\n`);
149
+ ui.header("Baseline Context", "Add New File");
150
+ ui.info(`Creating: context/extended/${fileName}`);
151
+ console.log();
107
152
  // Ask for a title
108
- const title = await ask(rl, ` Title for this context file: `);
153
+ const title = await ask(rl, ui.formatPrompt("Title for this context file"));
109
154
  const fileTitle = title.trim() || name.replace(/\.md$/, "").replace(/-/g, " ");
110
155
  console.log();
111
156
  // Ask which skills should use this context
112
- console.log(` Which skills should use this context file?`);
113
- console.log(` Available skills:\n`);
157
+ console.log(` ${ui.bold("Which skills should use this context file?")}`);
158
+ console.log();
114
159
  for (let i = 0; i < skills.length; i++) {
115
- console.log(` ${i + 1}. ${skills[i]}`);
160
+ console.log(` ${ui.dim(`${i + 1}.`)} ${skills[i]}`);
116
161
  }
117
162
  console.log();
118
- const selection = await ask(rl, ` Enter skill numbers (comma-separated) or "all":\n > `);
163
+ const selection = await ask(rl, ui.formatPrompt(`Enter skill numbers (comma-separated) or "all"`));
119
164
  let selectedSkills;
120
165
  if (selection.trim().toLowerCase() === "all") {
121
166
  selectedSkills = [...skills];
@@ -150,8 +195,8 @@ async function contextAdd(name) {
150
195
  yamlOut += ` - ${c}\n`;
151
196
  }
152
197
  yamlOut += "extended:\n";
153
- const entries = Object.entries(contextYaml.extended || {}).sort(([a], [b]) => a.localeCompare(b));
154
- for (const [file, skillList] of entries) {
198
+ const yamlEntries = Object.entries(contextYaml.extended || {}).sort(([a], [b]) => a.localeCompare(b));
199
+ for (const [file, skillList] of yamlEntries) {
155
200
  yamlOut += ` ${file}:\n`;
156
201
  for (const s of skillList) {
157
202
  yamlOut += ` - ${s}\n`;
@@ -159,12 +204,14 @@ async function contextAdd(name) {
159
204
  }
160
205
  (0, fs_1.writeFileSync)(contextYamlPath, yamlOut);
161
206
  rl.close();
162
- console.log(`\n ───────────────────────────────`);
163
- console.log(` Created context/extended/${fileName}`);
207
+ console.log();
208
+ ui.divider();
209
+ ui.success(`Created context/extended/${fileName}`);
164
210
  if (selectedSkills.length > 0) {
165
- console.log(` Wired to: ${selectedSkills.join(", ")}`);
211
+ ui.info(`Wired to: ${selectedSkills.join(", ")}`);
166
212
  }
167
- console.log(` Updated context/context.yaml\n`);
213
+ ui.success("Updated context/context.yaml");
214
+ console.log();
168
215
  }
169
216
  /** Load context prompts from the local context-prompts.yaml or skill manifests */
170
217
  function loadPromptsFromLocal(cwd) {
@@ -1 +1,9 @@
1
1
  export declare function init(): Promise<void>;
2
+ /** Generate AGENTS.md — canonical AI instructions for all tools */
3
+ export declare function generateAgentsMd(clientName: string): string;
4
+ /** Generate CLAUDE.md — thin pointer to AGENTS.md for Claude Code */
5
+ export declare function generateClaudeMdPointer(): string;
6
+ /** Generate .github/copilot-instructions.md — thin pointer to AGENTS.md for GitHub Copilot */
7
+ export declare function generateCopilotInstructions(): string;
8
+ /** Generate README.md for client systems */
9
+ export declare function generateReadme(clientName: string): string;
@@ -1,12 +1,50 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.init = init;
37
+ exports.generateAgentsMd = generateAgentsMd;
38
+ exports.generateClaudeMdPointer = generateClaudeMdPointer;
39
+ exports.generateCopilotInstructions = generateCopilotInstructions;
40
+ exports.generateReadme = generateReadme;
4
41
  const readline_1 = require("readline");
5
42
  const fs_1 = require("fs");
6
43
  const path_1 = require("path");
7
44
  const js_yaml_1 = require("js-yaml");
8
45
  const git_js_1 = require("../git.js");
9
46
  const child_process_1 = require("child_process");
47
+ const ui = __importStar(require("../ui.js"));
10
48
  const SYNC_DIRS = ["skills", "frameworks", "scripts", "cli"];
11
49
  let rlClosed = false;
12
50
  function ask(rl, question) {
@@ -24,23 +62,27 @@ function ask(rl, question) {
24
62
  async function init() {
25
63
  const rl = (0, readline_1.createInterface)({ input: process.stdin, output: process.stdout });
26
64
  rl.on("close", () => { rlClosed = true; });
27
- console.log(`\n Baseline System New Client Setup`);
28
- console.log(` ───────────────────────────────────\n`);
29
- // 1. Gather basic info
30
- const clientName = await ask(rl, " What's your company or project name? ");
65
+ // 1. Banner and gather basic info
66
+ ui.banner("New Client Setup");
67
+ const clientName = await ask(rl, ui.formatPrompt("What's your company or project name?"));
31
68
  const repo = "TrentM6/baseline-core";
32
69
  // Always scaffold in the current directory
33
70
  const destDir = process.cwd();
34
71
  // 2. Fetch latest from core
35
- console.log(`\n Fetching latest from ${repo}...`);
72
+ console.log();
73
+ const spin1 = ui.spinner("Fetching latest version...");
36
74
  const latest = (0, git_js_1.getLatestTag)(repo);
37
75
  if (!latest) {
38
- console.error(" Could not determine latest version.\n");
76
+ spin1.stop();
77
+ ui.error("Could not determine latest version.");
78
+ console.log();
39
79
  rl.close();
40
80
  process.exit(1);
41
81
  }
42
- console.log(` Using v${latest}\n`);
82
+ spin1.stop(`Using v${latest}`);
83
+ const spin2 = ui.spinner("Downloading system files...");
43
84
  const tmpDir = (0, git_js_1.cloneAtTag)(repo, latest);
85
+ spin2.stop("System files downloaded");
44
86
  // 3. Create folder structure
45
87
  (0, fs_1.mkdirSync)((0, path_1.join)(destDir, "context", "core"), { recursive: true });
46
88
  (0, fs_1.mkdirSync)((0, path_1.join)(destDir, "context", "extended"), { recursive: true });
@@ -60,34 +102,43 @@ async function init() {
60
102
  }
61
103
  // 5. Collect unique context file paths from manifests
62
104
  const contextFiles = collectContextPaths(tmpDir);
63
- // 6. Load context-prompts.yaml from core
64
- const promptsPath = (0, path_1.join)(tmpDir, "context-prompts.yaml");
65
- let prompts = {};
66
- if ((0, fs_1.existsSync)(promptsPath)) {
67
- prompts = (0, js_yaml_1.load)((0, fs_1.readFileSync)(promptsPath, "utf-8"));
105
+ // 6. Load prompts
106
+ // init-prompts.yaml has the slim essential questions for onboarding
107
+ // context-prompts.yaml has the full question set (used for template titles)
108
+ const initPromptsPath = (0, path_1.join)(tmpDir, "init-prompts.yaml");
109
+ const fullPromptsPath = (0, path_1.join)(tmpDir, "context-prompts.yaml");
110
+ let initPrompts = {};
111
+ let fullPrompts = {};
112
+ if ((0, fs_1.existsSync)(initPromptsPath)) {
113
+ initPrompts = (0, js_yaml_1.load)((0, fs_1.readFileSync)(initPromptsPath, "utf-8"));
68
114
  }
69
- // 7. Ask questions and write context files
70
- console.log(" Let's set up your context files.\n");
71
- console.log(" (Press Enter to skip any question)\n");
72
- for (const ctxFile of contextFiles) {
73
- const prompt = prompts[ctxFile];
74
- if (!prompt) {
75
- // Create empty template for files without prompts
76
- const fullPath = (0, path_1.join)(destDir, "context", ctxFile);
77
- (0, fs_1.mkdirSync)((0, path_1.dirname)(fullPath), { recursive: true });
78
- (0, fs_1.writeFileSync)(fullPath, `# ${ctxFile}\n\n<!-- Add your content here -->\n`);
115
+ if ((0, fs_1.existsSync)(fullPromptsPath)) {
116
+ fullPrompts = (0, js_yaml_1.load)((0, fs_1.readFileSync)(fullPromptsPath, "utf-8"));
117
+ }
118
+ // 7. Ask essential questions (slim init)
119
+ console.log();
120
+ ui.info("Let's set up your core context — the essential info that powers every skill.");
121
+ ui.skipHint();
122
+ const initSections = Object.keys(initPrompts);
123
+ let sectionIndex = 0;
124
+ for (const ctxFile of initSections) {
125
+ const prompt = initPrompts[ctxFile];
126
+ if (!prompt)
79
127
  continue;
80
- }
81
- console.log(` ── ${prompt.title} ──\n`);
128
+ sectionIndex++;
129
+ ui.sectionHeader(prompt.title, sectionIndex, initSections.length);
82
130
  const answers = [];
131
+ let answeredCount = 0;
83
132
  // Pre-fill company name into identity file
84
133
  if (ctxFile === "core/identity.md") {
85
134
  answers.push(`**What is your company name?**\n${clientName}`);
86
135
  }
87
- for (const q of prompt.questions) {
88
- const answer = await ask(rl, ` ${q}\n > `);
136
+ for (let qi = 0; qi < prompt.questions.length; qi++) {
137
+ const q = prompt.questions[qi];
138
+ const answer = await ask(rl, ui.formatPromptWithProgress(q, qi + 1, prompt.questions.length));
89
139
  if (answer.trim()) {
90
140
  answers.push(`**${q}**\n${answer.trim()}`);
141
+ answeredCount++;
91
142
  }
92
143
  console.log();
93
144
  }
@@ -99,8 +150,20 @@ async function init() {
99
150
  else {
100
151
  (0, fs_1.writeFileSync)(fullPath, `# ${prompt.title}\n\n<!-- Add your content here -->\n`);
101
152
  }
153
+ ui.sectionComplete(prompt.title, answeredCount, prompt.questions.length);
102
154
  }
103
- // 8. Create context.yaml
155
+ // 8. Create empty templates for all remaining context files
156
+ for (const ctxFile of contextFiles) {
157
+ if (initPrompts[ctxFile])
158
+ continue; // Already handled above
159
+ const fullPath = (0, path_1.join)(destDir, "context", ctxFile);
160
+ if ((0, fs_1.existsSync)(fullPath))
161
+ continue; // Don't overwrite
162
+ (0, fs_1.mkdirSync)((0, path_1.dirname)(fullPath), { recursive: true });
163
+ const title = fullPrompts[ctxFile]?.title || ctxFile;
164
+ (0, fs_1.writeFileSync)(fullPath, `# ${title}\n\n<!-- Add your content here -->\n`);
165
+ }
166
+ // 9. Create context.yaml
104
167
  const contextYaml = buildContextYaml(tmpDir, contextFiles);
105
168
  (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "context", "context.yaml"), contextYaml);
106
169
  // 9. Create baseline.config.json
@@ -114,16 +177,24 @@ async function init() {
114
177
  },
115
178
  };
116
179
  (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "baseline.config.json"), JSON.stringify(config, null, 2) + "\n");
117
- // 10. Create CLAUDE.md
118
- const templatePath = (0, path_1.join)(tmpDir, "claude-template.md");
119
- if ((0, fs_1.existsSync)(templatePath)) {
120
- let template = (0, fs_1.readFileSync)(templatePath, "utf-8");
180
+ // 10. Create AI instruction files
181
+ // 10a. AGENTS.md canonical instructions for all AI tools
182
+ const agentsTemplatePath = (0, path_1.join)(tmpDir, "agents-template.md");
183
+ if ((0, fs_1.existsSync)(agentsTemplatePath)) {
184
+ let template = (0, fs_1.readFileSync)(agentsTemplatePath, "utf-8");
121
185
  template = template.replace(/\{client_name\}/g, clientName);
122
- (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "CLAUDE.md"), template);
186
+ (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "AGENTS.md"), template);
123
187
  }
124
188
  else {
125
- (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "CLAUDE.md"), generateClaudeMd(clientName));
189
+ (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "AGENTS.md"), generateAgentsMd(clientName));
126
190
  }
191
+ // 10b. CLAUDE.md — pointer for Claude Code
192
+ (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "CLAUDE.md"), generateClaudeMdPointer());
193
+ // 10c. .github/copilot-instructions.md — pointer for GitHub Copilot Chat
194
+ (0, fs_1.mkdirSync)((0, path_1.join)(destDir, ".github"), { recursive: true });
195
+ (0, fs_1.writeFileSync)((0, path_1.join)(destDir, ".github", "copilot-instructions.md"), generateCopilotInstructions());
196
+ // 10d. README.md — system documentation
197
+ (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "README.md"), generateReadme(clientName));
127
198
  // 11. Create root package.json for local CLI access
128
199
  const rootPkg = {
129
200
  name: `${clientName.toLowerCase().replace(/\s+/g, "-")}-system`,
@@ -136,27 +207,35 @@ async function init() {
136
207
  };
137
208
  (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "package.json"), JSON.stringify(rootPkg, null, 2) + "\n");
138
209
  // 12. Install CLI locally so npx baseline works
139
- console.log(`\n Installing CLI...`);
210
+ const spin3 = ui.spinner("Installing CLI...");
140
211
  (0, child_process_1.execSync)("npm install --silent", { cwd: destDir, stdio: "pipe" });
212
+ spin3.stop("CLI installed");
141
213
  // 13. Create .gitignore
142
214
  (0, fs_1.writeFileSync)((0, path_1.join)(destDir, ".gitignore"), "node_modules/\n.DS_Store\n");
143
215
  // 14. Initialize git repo
216
+ const spin4 = ui.spinner("Initializing repository...");
144
217
  (0, child_process_1.execSync)("git init", { cwd: destDir, stdio: "pipe" });
145
218
  (0, child_process_1.execSync)("git add -A", { cwd: destDir, stdio: "pipe" });
146
219
  (0, child_process_1.execSync)(`git commit -m "Initialize ${clientName} Baseline System (v${latest})"`, { cwd: destDir, stdio: "pipe" });
220
+ spin4.stop("Repository initialized");
147
221
  // Clean up
148
222
  (0, fs_1.rmSync)(tmpDir, { recursive: true });
149
223
  rl.close();
150
224
  const skillCount = (0, fs_1.existsSync)((0, path_1.join)(destDir, "skills")) ? (0, fs_1.readdirSync)((0, path_1.join)(destDir, "skills")).filter((f) => !f.startsWith(".") && !f.startsWith("_")).length : 0;
151
225
  const frameworkCount = (0, fs_1.existsSync)((0, path_1.join)(destDir, "frameworks")) ? (0, fs_1.readdirSync)((0, path_1.join)(destDir, "frameworks")).filter((f) => !f.startsWith(".") && !f.startsWith("_")).length : 0;
152
226
  const scriptCount = (0, fs_1.existsSync)((0, path_1.join)(destDir, "scripts")) ? (0, fs_1.readdirSync)((0, path_1.join)(destDir, "scripts")).filter((f) => !f.startsWith(".") && !f.startsWith("_")).length : 0;
153
- console.log(` ───────────────────────────────────`);
154
- console.log(` ${clientName} system ready!`);
155
- console.log(` Version: v${latest}`);
156
- console.log(` ${skillCount} skills | ${frameworkCount} frameworks | ${scriptCount} scripts`);
157
- console.log(`\n Next steps:`);
158
- console.log(` Edit context/ files to add more detail`);
159
- console.log(` Run \`npx baseline status\` to check for updates\n`);
227
+ ui.summary(`${clientName} system ready!`, [
228
+ ["Version:", `v${latest}`],
229
+ ["Skills:", `${skillCount}`],
230
+ ["Frameworks:", `${frameworkCount}`],
231
+ ["Scripts:", `${scriptCount}`],
232
+ ]);
233
+ console.log(` ${ui.bold("Add more context to improve output quality:")}`);
234
+ console.log(` The more context you provide, the better every skill performs.`);
235
+ console.log(` Run ${ui.accent("npx baseline context")} to fill out any section.\n`);
236
+ console.log(` ${ui.dim("Priority:")} ${ui.accent("product")} ${ui.dim("→")} ${ui.accent("users")} ${ui.dim("→")} ${ui.accent("icp")} ${ui.dim("→")} ${ui.accent("competitive")}`);
237
+ console.log(` ${ui.dim("Also:")} ${ui.accent("pricing")} ${ui.dim("·")} ${ui.accent("technical")} ${ui.dim("·")} ${ui.accent("visual-identity")} ${ui.dim("·")} ${ui.accent("formatting")}`);
238
+ console.log();
160
239
  }
161
240
  /** Scan all skill manifests and return unique context file paths (relative to context/) */
162
241
  function collectContextPaths(coreDir) {
@@ -167,6 +246,8 @@ function collectContextPaths(coreDir) {
167
246
  // Always include core files
168
247
  paths.add("core/identity.md");
169
248
  paths.add("core/voice.md");
249
+ // Always include co-founder context (used by Co-Founder Mode, not a skill)
250
+ paths.add("extended/co-founder.md");
170
251
  for (const skill of (0, fs_1.readdirSync)(skillsDir)) {
171
252
  const manifestPath = (0, path_1.join)(skillsDir, skill, "manifest.yaml");
172
253
  if (!(0, fs_1.existsSync)(manifestPath))
@@ -232,6 +313,8 @@ function buildContextYaml(coreDir, contextFiles) {
232
313
  yaml += " - identity.md # loaded by all skills\n";
233
314
  yaml += " - voice.md # loaded by all skills\n";
234
315
  yaml += "extended:\n";
316
+ yaml += " co-founder.md:\n";
317
+ yaml += " - co-founder-mode # loaded by Co-Founder Mode (not a skill)\n";
235
318
  for (const [file, skills] of [...extendedMap.entries()].sort()) {
236
319
  yaml += ` ${file}:\n`;
237
320
  for (const s of skills.sort()) {
@@ -240,11 +323,11 @@ function buildContextYaml(coreDir, contextFiles) {
240
323
  }
241
324
  return yaml;
242
325
  }
243
- /** Generate a CLAUDE.md for the client if no template exists in core */
244
- function generateClaudeMd(clientName) {
326
+ /** Generate AGENTS.md canonical AI instructions for all tools */
327
+ function generateAgentsMd(clientName) {
245
328
  return `# ${clientName} — Baseline System
246
329
 
247
- > This file is automatically loaded at the start of every Claude Code session. It enforces consistent skill execution.
330
+ > This file provides instructions for AI coding agents. It enforces consistent skill execution across all AI tools.
248
331
 
249
332
  ---
250
333
 
@@ -321,11 +404,53 @@ If the user wants output delivered to an external tool, read the relevant script
321
404
 
322
405
  ---
323
406
 
407
+ ## Co-Founder Mode
408
+
409
+ When the user wants to brainstorm, strategize, or think through problems without invoking a specific skill, activate co-founder mode.
410
+
411
+ ### When to Activate
412
+
413
+ Activate when the user:
414
+ - Asks to "brainstorm" or "strategize" without naming a skill
415
+ - Wants to "talk through" a problem or decision
416
+ - Asks for strategic advice or a thinking partner
417
+ - Phrases requests as open-ended questions about direction or approach
418
+
419
+ **Do NOT activate when:**
420
+ - The user invokes a specific skill by name or task mapping
421
+ - The user asks for a specific deliverable (PRD, wireframe, content, etc.)
422
+ - The request maps clearly to a skill in the table above
423
+
424
+ ### How to Use
425
+
426
+ 1. **Load context files:**
427
+ \`\`\`
428
+ context/core/identity.md
429
+ context/core/voice.md
430
+ context/extended/co-founder.md
431
+ \`\`\`
432
+ If \`co-founder.md\` does not exist, load only core context and proceed without the persona.
433
+
434
+ 2. **Adopt the persona.** Use the co-founder file to guide your thinking style, questions, and decision-making approach.
435
+
436
+ 3. **No workflow structure.** This is NOT a skill. No Plan/Clarify/Execute/Validate steps. No deliverables. No quality checks. Just strategic thinking partnership.
437
+
438
+ 4. **Ask probing questions.** Use the Default Questions and Assumptions to Challenge from the co-founder file to surface blind spots.
439
+
440
+ 5. **Reference principles when relevant.** When the conversation touches on strategic decisions, reference the Strategic Principles and Non-Negotiables from the co-founder file.
441
+
442
+ ### When to Exit
443
+
444
+ If the conversation shifts to executing a specific deliverable (e.g., "now write a PRD for this"), switch to the appropriate skill and follow the Skill Execution Protocol above.
445
+
446
+ ---
447
+
324
448
  ## Session Management
325
449
 
326
450
  - Scope each session to one major task. Multi-task sessions degrade output quality.
327
451
  - After completing a major deliverable, recommend starting a fresh session.
328
452
  - If the conversation has gone through 3+ revision cycles, proactively suggest a session break.
453
+ - For work that spans multiple sessions, use the Session Planning Framework (\`frameworks/session-planning.md\`) to generate a project plan. The project plan is a standalone markdown file the user brings into each new session — it specifies what to do, what context to load, and what was decided in prior sessions.
329
454
 
330
455
  ---
331
456
 
@@ -339,3 +464,177 @@ If the user wants output delivered to an external tool, read the relevant script
339
464
  - **Overload the session** — One major task per session. Recommend fresh sessions after milestones.
340
465
  `;
341
466
  }
467
+ /** Generate CLAUDE.md — thin pointer to AGENTS.md for Claude Code */
468
+ function generateClaudeMdPointer() {
469
+ return `# Baseline System
470
+
471
+ Read and follow all instructions in AGENTS.md in this directory. That file is the canonical source of truth for how this system works, including the Skill Execution Protocol, skill mapping, Co-Founder Mode, and session management guidelines.
472
+ `;
473
+ }
474
+ /** Generate .github/copilot-instructions.md — thin pointer to AGENTS.md for GitHub Copilot */
475
+ function generateCopilotInstructions() {
476
+ return `# Baseline System
477
+
478
+ Read and follow all instructions in AGENTS.md at the repository root. That file contains the Skill Execution Protocol, skill mapping table, Co-Founder Mode instructions, and session management guidelines for this project.
479
+ `;
480
+ }
481
+ /** Generate README.md for client systems */
482
+ function generateReadme(clientName) {
483
+ return `# ${clientName} — Baseline System
484
+
485
+ > A complete AI system for product teams. Skills provide methodology. Context makes it yours. Frameworks give structure. Scripts deliver to your tools.
486
+
487
+ ## Getting Started
488
+
489
+ \`\`\`bash
490
+ npx baseline status # Check for updates
491
+ npx baseline update # Pull latest version
492
+ \`\`\`
493
+
494
+ ---
495
+
496
+ ## What This Is
497
+
498
+ The Baseline System is an AI-powered workflow system that helps product teams do research, strategy, design, communication, and delivery — faster and at a higher quality than working without it.
499
+
500
+ It works with any AI coding tool by giving it structured knowledge about how to do product work and specific knowledge about your business.
501
+
502
+ **Four components:**
503
+
504
+ | Component | What It Does | Details |
505
+ |-----------|-------------|---------|
506
+ | **Skills** | Domain expertise modules that teach AI how to execute specific work | [\`skills/_README.md\`](skills/_README.md) |
507
+ | **Context** | Your business-specific knowledge — identity, voice, customers, product | \`context/\` |
508
+ | **Frameworks** | Reusable methodologies — prioritization, research, decision-making | [\`frameworks/_README.md\`](frameworks/_README.md) |
509
+ | **Scripts** | Delivery to external tools — Figma, Asana, Confluence, etc. | [\`scripts/_README.md\`](scripts/_README.md) |
510
+
511
+ Skills are universal. Context is yours. When you run a skill, it loads both — producing output that follows proven methodology and sounds like your brand.
512
+
513
+ ---
514
+
515
+ ## How It Works
516
+
517
+ 1. **You describe a task** — "Write a PRD for the new onboarding flow" or "Help me prioritize Q2 roadmap"
518
+ 2. **The system identifies the skill** — PRDs map to \`product-communications\`, prioritization maps to \`strategic-advisory\`
519
+ 3. **The skill loads its files** — The skill's \`manifest.yaml\` lists what to load: the skill file, frameworks, and your context
520
+ 4. **The system executes** — Plan, clarify, execute, validate
521
+
522
+ In AI coding tools, this is fully automated via the \`AGENTS.md\` file. Just describe what you need.
523
+
524
+ ### The 12 Skills
525
+
526
+ | Skill | What It Does |
527
+ |-------|-------------|
528
+ | **Strategic Advisory** | Roadmaps, prioritization, OKRs, strategic decisions |
529
+ | **Research Synthesis** | User interviews, research reports, validation testing |
530
+ | **Product Communications** | PRDs, specs, briefs, stakeholder updates |
531
+ | **UX Design** | Wireframes, user flows, UI copy, design critique |
532
+ | **Product Analytics** | Metrics frameworks, dashboards, A/B test plans |
533
+ | **Prototyping** | Coded prototypes, demos, proof-of-concepts |
534
+ | **Project Management** | Sprint planning, tracking, retrospectives |
535
+ | **Technical Documentation** | User guides, API docs, release notes, help content |
536
+ | **Brand Design** | Presentations, graphics, visual design direction |
537
+ | **Marketing** | LinkedIn posts, website copy, campaigns, case studies |
538
+ | **Sales** | Outreach emails, proposals, discovery call prep |
539
+ | **Skill Building** | Create new custom skills for your team |
540
+
541
+ See [\`skills/_README.md\`](skills/_README.md) for detailed documentation on each skill.
542
+
543
+ ---
544
+
545
+ ## Using the System
546
+
547
+ ### AI Coding Tools (Automated)
548
+
549
+ \`AGENTS.md\` is the canonical instruction file. It tells AI tools how to find skills, load manifests, read context, and execute workflows. Here's how each tool picks it up:
550
+
551
+ | Tool | How It Works |
552
+ |------|-------------|
553
+ | **Codex, Cursor, Windsurf, JetBrains AI** | Reads \`AGENTS.md\` directly |
554
+ | **Claude Code** | Reads \`CLAUDE.md\`, which points to \`AGENTS.md\` |
555
+ | **GitHub Copilot Chat** | Reads \`.github/copilot-instructions.md\`, which points to \`AGENTS.md\` |
556
+
557
+ 1. Open this folder in your AI coding tool
558
+ 2. Describe what you need
559
+ 3. Done — the tool reads \`AGENTS.md\` (directly or via pointer) and handles the rest
560
+
561
+ ### ChatGPT / Gemini / Other Chat Tools
562
+
563
+ Chat tools can't auto-read project files. Upload or paste the files listed in the skill's \`manifest.yaml\` into your conversation, then describe your task.
564
+
565
+ ---
566
+
567
+ ## Context
568
+
569
+ Context is what makes the system yours. The system's output quality is directly proportional to the quality of your context.
570
+
571
+ **Core context** (loaded by every skill):
572
+ - \`context/core/identity.md\` — Who you are, what you do, positioning, differentiators
573
+ - \`context/core/voice.md\` — How you sound, language rules, tone by channel
574
+
575
+ **Extended context** (loaded by relevant skills):
576
+ - \`context/extended/product.md\` — Product details, features, workflow
577
+ - \`context/extended/users.md\` — User personas, goals, pain points
578
+ - \`context/extended/icp.md\` — Ideal customer profile, buyer psychology
579
+ - \`context/extended/competitive.md\` — Competitors, positioning, alternatives
580
+ - \`context/extended/pricing.md\` — Pricing tiers, objection handling
581
+ - \`context/extended/technical.md\` — Tech stack, integrations, constraints
582
+ - \`context/extended/visual-identity.md\` — Colors, fonts, visual style
583
+ - \`context/extended/formatting.md\` — Document structure, heading rules
584
+ - \`context/extended/proof-points.md\` — Metrics, case studies, credibility
585
+
586
+ Start with \`identity.md\` and \`voice.md\`, then fill out extended files as needed. Run \`npx baseline context\` to update files or \`npx baseline context add <name>\` to create new ones.
587
+
588
+ ---
589
+
590
+ ## CLI Reference
591
+
592
+ | Command | What It Does |
593
+ |---------|-------------|
594
+ | \`npx baseline status\` | Show current version, check for updates |
595
+ | \`npx baseline update\` | Pull latest skills, frameworks, scripts, and CLI |
596
+ | \`npx baseline context\` | Re-run context prompts to update existing files |
597
+ | \`npx baseline context add <name>\` | Create a new context file and wire it to skills |
598
+
599
+ ---
600
+
601
+ ## File Structure
602
+
603
+ \`\`\`
604
+ ${clientName.toLowerCase().replace(/\\s+/g, "-")}-system/
605
+ ├── AGENTS.md # AI instructions for all coding tools (don't edit)
606
+ ├── CLAUDE.md # Claude Code pointer to AGENTS.md
607
+ ├── .github/
608
+ │ └── copilot-instructions.md # GitHub Copilot pointer to AGENTS.md
609
+ ├── baseline.config.json # Version tracking and config
610
+ ├── skills/ # 12 domain expertise modules
611
+ ├── context/ # YOUR business knowledge (you own this)
612
+ │ ├── core/ # Identity and voice (loaded by every skill)
613
+ │ └── extended/ # Product, users, pricing, etc.
614
+ ├── frameworks/ # Reusable methodologies
615
+ ├── scripts/ # Delivery to external tools
616
+ └── cli/ # Bundled CLI for daily use
617
+ \`\`\`
618
+
619
+ **You own \`context/\`.** Everything else is managed by the system and updated via \`npx baseline update\`.
620
+
621
+ ---
622
+
623
+ ## FAQ
624
+
625
+ **Can I edit skill files?**
626
+ You can, but changes are overwritten on \`baseline update\`. Put custom behavior in context files instead.
627
+
628
+ **What if I don't have all the context files filled out?**
629
+ Skills work with whatever context is available. Missing context means more generic output, but nothing breaks.
630
+
631
+ **Can I add my own context files?**
632
+ Yes. Run \`npx baseline context add <name>\` to create a new file and wire it to skills.
633
+
634
+ **What AI tools does this work with?**
635
+ Any AI tool. The \`AGENTS.md\` file is automatically read by Claude Code, Codex, Cursor, Windsurf, GitHub Copilot, JetBrains AI, and others. Chat tools like ChatGPT work when you upload skill and context files.
636
+
637
+ **How do I get help?**
638
+ Email trent@baselinestudio.design.
639
+ `;
640
+ }
@@ -1,27 +1,64 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.status = status;
4
37
  const config_js_1 = require("../config.js");
5
38
  const git_js_1 = require("../git.js");
39
+ const ui = __importStar(require("../ui.js"));
6
40
  function status() {
7
41
  const config = (0, config_js_1.readConfig)();
8
- console.log(`\n Baseline System`);
9
- console.log(` ───────────────────────────`);
10
- console.log(` Client: ${config.client.name}`);
11
- console.log(` Version: v${config.version}`);
12
- console.log(` Core repo: ${config.coreRepo}`);
13
- console.log(` Last updated: ${config.lastUpdated}`);
14
- console.log(`\n Checking for updates...`);
42
+ ui.header("Baseline System");
43
+ console.log(` ${ui.dim("Client:")} ${config.client.name}`);
44
+ console.log(` ${ui.dim("Version:")} v${config.version}`);
45
+ console.log(` ${ui.dim("Core repo:")} ${config.coreRepo}`);
46
+ console.log(` ${ui.dim("Last updated:")} ${ui.formatDate(config.lastUpdated)}`);
47
+ console.log();
48
+ const spin = ui.spinner("Checking for updates...");
15
49
  const latest = (0, git_js_1.getLatestTag)(config.coreRepo);
50
+ spin.stop("Checked for updates");
16
51
  if (!latest) {
17
- console.log(` Could not determine latest version.\n`);
52
+ ui.error("Could not determine latest version.");
53
+ console.log();
18
54
  return;
19
55
  }
20
56
  if ((0, git_js_1.isNewer)(latest, config.version)) {
21
- console.log(` Update available: v${config.version} → v${latest}`);
22
- console.log(` Run \`baseline update\` to pull the latest.\n`);
57
+ ui.warn(`Update available: v${config.version} ${ui.accent("")} v${latest}`);
58
+ console.log(` Run ${ui.accent("npx baseline update")} to pull the latest.\n`);
23
59
  }
24
60
  else {
25
- console.log(` Up to date (v${config.version}).\n`);
61
+ ui.success(`Up to date (v${config.version})`);
62
+ console.log();
26
63
  }
27
64
  }
@@ -1,41 +1,85 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.update = update;
4
37
  const fs_1 = require("fs");
5
38
  const path_1 = require("path");
6
39
  const config_js_1 = require("../config.js");
7
40
  const git_js_1 = require("../git.js");
41
+ const init_js_1 = require("./init.js");
8
42
  const js_yaml_1 = require("js-yaml");
9
43
  const child_process_1 = require("child_process");
10
- const SYNC_DIRS = ["skills", "frameworks", "scripts", "cli"];
44
+ const ui = __importStar(require("../ui.js"));
45
+ // Sync skills, frameworks, scripts first — cli/ is replaced LAST
46
+ // so the currently running process doesn't lose its own files mid-execution.
47
+ const CONTENT_DIRS = ["skills", "frameworks", "scripts"];
11
48
  function update() {
12
49
  const config = (0, config_js_1.readConfig)();
13
50
  const cwd = process.cwd();
14
- console.log(`\n Checking for updates...`);
51
+ console.log();
52
+ const spin1 = ui.spinner("Checking for updates...");
15
53
  const latest = (0, git_js_1.getLatestTag)(config.coreRepo);
16
54
  if (!latest) {
17
- console.log(` Could not determine latest version.\n`);
55
+ spin1.stop();
56
+ ui.error("Could not determine latest version.");
57
+ console.log();
18
58
  return;
19
59
  }
20
60
  if (!(0, git_js_1.isNewer)(latest, config.version)) {
21
- console.log(` Already up to date (v${config.version}).\n`);
61
+ spin1.stop(`Already up to date (v${config.version})`);
62
+ console.log();
22
63
  return;
23
64
  }
24
- console.log(` Updating v${config.version} → v${latest}...`);
65
+ spin1.stop(`Update available: v${config.version} ${ui.accent("")} v${latest}`);
66
+ console.log();
25
67
  // Clone the latest tag to a temp directory
68
+ const spin2 = ui.spinner("Downloading...");
26
69
  const tmpDir = (0, git_js_1.cloneAtTag)(config.coreRepo, latest);
27
- // Sync each directory: full replace
70
+ spin2.stop("Downloaded");
71
+ // Sync content directories first (skills, frameworks, scripts)
28
72
  const stats = { skills: 0, frameworks: 0, scripts: 0 };
29
- for (const dir of SYNC_DIRS) {
73
+ for (const dir of CONTENT_DIRS) {
30
74
  const srcDir = (0, path_1.join)(tmpDir, dir);
31
75
  const destDir = (0, path_1.join)(cwd, dir);
32
76
  if (!(0, fs_1.existsSync)(srcDir))
33
77
  continue;
34
- // Count items for summary (skip cli in counts)
78
+ // Count items for summary
35
79
  if (dir === "skills") {
36
80
  stats.skills = (0, fs_1.readdirSync)(srcDir).filter((f) => (0, fs_1.statSync)((0, path_1.join)(srcDir, f)).isDirectory()).length;
37
81
  }
38
- else if (dir !== "cli") {
82
+ else {
39
83
  stats[dir] = (0, fs_1.readdirSync)(srcDir).filter((f) => f.endsWith(".md") || (0, fs_1.statSync)((0, path_1.join)(srcDir, f)).isDirectory()).length;
40
84
  }
41
85
  // Full replace
@@ -43,34 +87,69 @@ function update() {
43
87
  (0, fs_1.rmSync)(destDir, { recursive: true });
44
88
  }
45
89
  (0, fs_1.cpSync)(srcDir, destDir, { recursive: true });
90
+ ui.success(`${dir.charAt(0).toUpperCase() + dir.slice(1)} updated (${stats[dir]})`);
91
+ }
92
+ // Regenerate AI instruction files
93
+ const clientName = config.client.name;
94
+ const agentsTemplatePath = (0, path_1.join)(tmpDir, "agents-template.md");
95
+ if ((0, fs_1.existsSync)(agentsTemplatePath)) {
96
+ let template = (0, fs_1.readFileSync)(agentsTemplatePath, "utf-8");
97
+ template = template.replace(/\{client_name\}/g, clientName);
98
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, "AGENTS.md"), template);
99
+ }
100
+ else {
101
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, "AGENTS.md"), (0, init_js_1.generateAgentsMd)(clientName));
46
102
  }
47
- // Remove CLI source files (clients only need bin/, dist/, package.json)
48
- const cliCleanup = ["src", "tsconfig.json", "package-lock.json"];
49
- for (const item of cliCleanup) {
50
- const p = (0, path_1.join)(cwd, "cli", item);
51
- if ((0, fs_1.existsSync)(p))
52
- (0, fs_1.rmSync)(p, { recursive: true });
103
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, "CLAUDE.md"), (0, init_js_1.generateClaudeMdPointer)());
104
+ (0, fs_1.mkdirSync)((0, path_1.join)(cwd, ".github"), { recursive: true });
105
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, ".github", "copilot-instructions.md"), (0, init_js_1.generateCopilotInstructions)());
106
+ (0, fs_1.writeFileSync)((0, path_1.join)(cwd, "README.md"), (0, init_js_1.generateReadme)(clientName));
107
+ ui.success("AI instructions regenerated");
108
+ // Check for missing context files
109
+ const contextPath = config.client.contextPath || "./context";
110
+ checkMissingContext(tmpDir, (0, path_1.join)(cwd, contextPath));
111
+ // Update config version BEFORE replacing cli/ — if the cli/ swap
112
+ // causes the process to error, the version is already recorded so
113
+ // a re-run won't re-download and re-apply the same update.
114
+ config.version = latest;
115
+ config.lastUpdated = new Date().toISOString();
116
+ (0, config_js_1.writeConfig)(config);
117
+ // Replace cli/ LAST — this is the currently running code, so anything
118
+ // after this point may fail if Node can't resolve replaced modules.
119
+ // IMPORTANT: Overwrite in-place instead of delete-then-copy. The client's
120
+ // node_modules/baseline-cli is a symlink to cli/, so deleting cli/ first
121
+ // would break the symlink and leave dist/index.js missing if anything fails.
122
+ const cliSrc = (0, path_1.join)(tmpDir, "cli");
123
+ const cliDest = (0, path_1.join)(cwd, "cli");
124
+ if ((0, fs_1.existsSync)(cliSrc)) {
125
+ (0, fs_1.cpSync)(cliSrc, cliDest, { recursive: true, force: true });
126
+ // Remove CLI source files (clients only need bin/, dist/, package.json)
127
+ const cliCleanup = ["src", "tsconfig.json", "package-lock.json"];
128
+ for (const item of cliCleanup) {
129
+ const p = (0, path_1.join)(cwd, "cli", item);
130
+ if ((0, fs_1.existsSync)(p))
131
+ (0, fs_1.rmSync)(p, { recursive: true });
132
+ }
53
133
  }
134
+ ui.success("CLI updated");
54
135
  // Re-install CLI dependencies after update
55
136
  if ((0, fs_1.existsSync)((0, path_1.join)(cwd, "package.json"))) {
137
+ const spin3 = ui.spinner("Installing dependencies...");
56
138
  try {
57
139
  (0, child_process_1.execSync)("npm install --silent", { cwd, stdio: "pipe" });
140
+ spin3.stop("Dependencies installed");
58
141
  }
59
142
  catch {
60
- // Non-fatal — CLI still works from previous install
143
+ spin3.stop("Dependencies (using previous install)");
61
144
  }
62
145
  }
63
- // Check for missing context files
64
- const contextPath = config.client.contextPath || "./context";
65
- checkMissingContext(tmpDir, (0, path_1.join)(cwd, contextPath));
66
146
  // Clean up temp dir
67
147
  (0, fs_1.rmSync)(tmpDir, { recursive: true });
68
- // Update config
69
- config.version = latest;
70
- config.lastUpdated = new Date().toISOString();
71
- (0, config_js_1.writeConfig)(config);
72
- console.log(`\n Updated v${config.version} successfully.`);
73
- console.log(` Skills: ${stats.skills} | Frameworks: ${stats.frameworks} | Scripts: ${stats.scripts}`);
148
+ ui.summary(`Updated to v${latest}`, [
149
+ ["Skills:", `${stats.skills}`],
150
+ ["Frameworks:", `${stats.frameworks}`],
151
+ ["Scripts:", `${stats.scripts}`],
152
+ ]);
74
153
  console.log();
75
154
  }
76
155
  function checkMissingContext(coreDir, contextDir) {
@@ -104,10 +183,11 @@ function checkMissingContext(coreDir, contextDir) {
104
183
  }
105
184
  }
106
185
  if (missingMap.size > 0) {
107
- console.log(`\n Missing context files:`);
186
+ console.log();
187
+ ui.warn("Missing context files:");
108
188
  for (const [file, skills] of missingMap) {
109
- console.log(` → ${file} (used by ${skills.join(", ")})`);
189
+ console.log(` ${ui.dim("")} ${file} ${ui.dim(`(used by ${skills.join(", ")})`)}`);
110
190
  }
111
- console.log(` Create these files to get the most out of these skills.`);
191
+ ui.info("Create these files to get the most out of these skills.");
112
192
  }
113
193
  }
package/dist/index.js CHANGED
@@ -1,15 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const commander_1 = require("commander");
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
4
6
  const status_js_1 = require("./commands/status.js");
5
7
  const update_js_1 = require("./commands/update.js");
6
8
  const init_js_1 = require("./commands/init.js");
7
9
  const context_js_1 = require("./commands/context.js");
10
+ const pkg = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, "..", "package.json"), "utf-8"));
8
11
  const program = new commander_1.Command();
9
12
  program
10
13
  .name("baseline")
11
14
  .description("Distribute and update the Baseline System")
12
- .version("2.2.5");
15
+ .version(pkg.version);
13
16
  program
14
17
  .command("status")
15
18
  .description("Show current version and check for updates")
package/dist/ui.d.ts ADDED
@@ -0,0 +1,25 @@
1
+ import chalk from "chalk";
2
+ declare const brand: chalk.Chalk;
3
+ declare const accent: chalk.Chalk;
4
+ declare const dim: chalk.Chalk;
5
+ declare const bold: chalk.Chalk;
6
+ export declare function banner(subtitle?: string): void;
7
+ export declare function header(title: string, subtitle?: string): void;
8
+ export declare function sectionHeader(title: string, index: number, total: number): void;
9
+ export declare function questionPrefix(current: number, total: number): string;
10
+ export declare function formatPrompt(question: string, hint?: string): string;
11
+ export declare function formatPromptWithProgress(question: string, current: number, total: number, hint?: string): string;
12
+ export declare function sectionComplete(title: string, answered: number, total: number): void;
13
+ export declare function spinner(message: string): {
14
+ stop: (finalMessage?: string) => void;
15
+ };
16
+ export declare function success(message: string): void;
17
+ export declare function error(message: string): void;
18
+ export declare function warn(message: string): void;
19
+ export declare function info(message: string): void;
20
+ export declare function summary(title: string, rows: [string, string][]): void;
21
+ export declare function nextSteps(steps: string[]): void;
22
+ export declare function divider(): void;
23
+ export declare function formatDate(isoString: string): string;
24
+ export declare function skipHint(): void;
25
+ export { brand, accent, dim, bold };
package/dist/ui.js ADDED
@@ -0,0 +1,179 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.bold = exports.dim = exports.accent = exports.brand = void 0;
7
+ exports.banner = banner;
8
+ exports.header = header;
9
+ exports.sectionHeader = sectionHeader;
10
+ exports.questionPrefix = questionPrefix;
11
+ exports.formatPrompt = formatPrompt;
12
+ exports.formatPromptWithProgress = formatPromptWithProgress;
13
+ exports.sectionComplete = sectionComplete;
14
+ exports.spinner = spinner;
15
+ exports.success = success;
16
+ exports.error = error;
17
+ exports.warn = warn;
18
+ exports.info = info;
19
+ exports.summary = summary;
20
+ exports.nextSteps = nextSteps;
21
+ exports.divider = divider;
22
+ exports.formatDate = formatDate;
23
+ exports.skipHint = skipHint;
24
+ const chalk_1 = __importDefault(require("chalk"));
25
+ // ── Brand Color Theme ──────────────────────────────────────────────
26
+ const brand = chalk_1.default.hex("#FE4506");
27
+ exports.brand = brand;
28
+ const accent = chalk_1.default.cyan;
29
+ exports.accent = accent;
30
+ const dim = chalk_1.default.gray;
31
+ exports.dim = dim;
32
+ const bold = chalk_1.default.bold;
33
+ exports.bold = bold;
34
+ // ── ASCII Art Wordmark ─────────────────────────────────────────────
35
+ const WORDMARK = [
36
+ "██████ █████ ███████ ███████ ██ ██ ███ ██ ███████",
37
+ "██ ██ ██ ██ ██ ██ ██ ██ ████ ██ ██ ",
38
+ "██████ ███████ ███████ █████ ██ ██ ██ ██ ██ █████ ",
39
+ "██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ",
40
+ "██████ ██ ██ ███████ ███████ ███████ ██ ██ ████ ███████",
41
+ ];
42
+ // ── Spinner Frames ─────────────────────────────────────────────────
43
+ const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
44
+ const SPINNER_INTERVAL = 80;
45
+ // ── Banner (ASCII art, used for init) ──────────────────────────────
46
+ function banner(subtitle) {
47
+ console.log();
48
+ for (const line of WORDMARK) {
49
+ console.log(` ${brand(line)}`);
50
+ }
51
+ if (subtitle) {
52
+ console.log();
53
+ console.log(` ${dim(subtitle)}`);
54
+ }
55
+ console.log();
56
+ }
57
+ // ── Header (boxed, used for other commands) ────────────────────────
58
+ function header(title, subtitle) {
59
+ const content = subtitle ? [title, subtitle] : [title];
60
+ const maxLen = Math.max(...content.map((s) => s.length));
61
+ const width = maxLen + 6;
62
+ console.log();
63
+ console.log(` ${dim("╭" + "─".repeat(width) + "╮")}`);
64
+ console.log(` ${dim("│")}${" ".repeat(width)}${dim("│")}`);
65
+ for (const line of content) {
66
+ const padding = width - line.length - 3;
67
+ if (line === title) {
68
+ console.log(` ${dim("│")} ${brand.bold(line)}${" ".repeat(padding)}${dim("│")}`);
69
+ }
70
+ else {
71
+ console.log(` ${dim("│")} ${dim(line)}${" ".repeat(padding)}${dim("│")}`);
72
+ }
73
+ }
74
+ console.log(` ${dim("│")}${" ".repeat(width)}${dim("│")}`);
75
+ console.log(` ${dim("╰" + "─".repeat(width) + "╯")}`);
76
+ console.log();
77
+ }
78
+ // ── Section Header ─────────────────────────────────────────────────
79
+ function sectionHeader(title, index, total) {
80
+ const label = `Section ${index} of ${total}`;
81
+ const titlePart = `── ${title} `;
82
+ const fill = "─".repeat(Math.max(2, 40 - titlePart.length));
83
+ console.log(` ${brand(titlePart)}${dim(fill + " " + label)}\n`);
84
+ }
85
+ // ── Question Prefix ────────────────────────────────────────────────
86
+ function questionPrefix(current, total) {
87
+ return dim(`[${current}/${total}]`);
88
+ }
89
+ // ── Format Prompt (for readline) ───────────────────────────────────
90
+ function formatPrompt(question, hint) {
91
+ const hintStr = hint ? ` ${accent(`[${hint}]`)}` : "";
92
+ return ` ${bold(question)}${hintStr}\n ${brand("›")} `;
93
+ }
94
+ function formatPromptWithProgress(question, current, total, hint) {
95
+ const prefix = dim(`[${current}/${total}]`);
96
+ const hintStr = hint ? ` ${accent(`[${hint}]`)}` : "";
97
+ return ` ${prefix} ${bold(question)}${hintStr}\n ${brand("›")} `;
98
+ }
99
+ // ── Section Complete ───────────────────────────────────────────────
100
+ function sectionComplete(title, answered, total) {
101
+ console.log(` ${chalk_1.default.green("✓")} ${brand(title)} ${dim(`— ${answered} of ${total} answered`)}\n`);
102
+ }
103
+ // ── Spinner ────────────────────────────────────────────────────────
104
+ function spinner(message) {
105
+ let i = 0;
106
+ const id = setInterval(() => {
107
+ process.stdout.write(`\r ${accent(SPINNER_FRAMES[i++ % SPINNER_FRAMES.length])} ${message}`);
108
+ }, SPINNER_INTERVAL);
109
+ return {
110
+ stop(finalMessage) {
111
+ clearInterval(id);
112
+ const text = finalMessage || message;
113
+ process.stdout.write(`\r ${chalk_1.default.green("✓")} ${text}${" ".repeat(20)}\n`);
114
+ },
115
+ };
116
+ }
117
+ // ── Semantic Output ────────────────────────────────────────────────
118
+ function success(message) {
119
+ console.log(` ${chalk_1.default.green("✓")} ${message}`);
120
+ }
121
+ function error(message) {
122
+ console.log(` ${chalk_1.default.red("✗")} ${message}`);
123
+ }
124
+ function warn(message) {
125
+ console.log(` ${chalk_1.default.yellow("⚠")} ${message}`);
126
+ }
127
+ function info(message) {
128
+ console.log(` ${dim(message)}`);
129
+ }
130
+ // ── Summary Box ────────────────────────────────────────────────────
131
+ function summary(title, rows) {
132
+ const labelWidth = Math.max(...rows.map(([label]) => label.length));
133
+ const valueWidth = Math.max(...rows.map(([, value]) => value.length));
134
+ const contentWidth = labelWidth + valueWidth + 4; // " label value"
135
+ const width = Math.max(contentWidth + 6, title.length + 6);
136
+ console.log();
137
+ console.log(` ${dim("╭" + "─".repeat(width) + "╮")}`);
138
+ console.log(` ${dim("│")}${" ".repeat(width)}${dim("│")}`);
139
+ const titlePad = width - title.length - 3;
140
+ console.log(` ${dim("│")} ${chalk_1.default.green.bold(title)}${" ".repeat(titlePad)}${dim("│")}`);
141
+ console.log(` ${dim("│")}${" ".repeat(width)}${dim("│")}`);
142
+ for (const [label, value] of rows) {
143
+ const line = `${dim(label.padEnd(labelWidth))} ${value}`;
144
+ const linePad = width - labelWidth - value.length - 5;
145
+ console.log(` ${dim("│")} ${line}${" ".repeat(Math.max(0, linePad))}${dim("│")}`);
146
+ }
147
+ console.log(` ${dim("│")}${" ".repeat(width)}${dim("│")}`);
148
+ console.log(` ${dim("╰" + "─".repeat(width) + "╯")}`);
149
+ }
150
+ // ── Next Steps ─────────────────────────────────────────────────────
151
+ function nextSteps(steps) {
152
+ console.log(`\n ${bold("Next steps:")}`);
153
+ for (let i = 0; i < steps.length; i++) {
154
+ console.log(` ${dim(`${i + 1}.`)} ${steps[i]}`);
155
+ }
156
+ console.log();
157
+ }
158
+ // ── Divider ────────────────────────────────────────────────────────
159
+ function divider() {
160
+ console.log(` ${dim("─".repeat(40))}`);
161
+ }
162
+ // ── Format Date ────────────────────────────────────────────────────
163
+ function formatDate(isoString) {
164
+ try {
165
+ const d = new Date(isoString);
166
+ return d.toLocaleDateString("en-US", {
167
+ year: "numeric",
168
+ month: "short",
169
+ day: "numeric",
170
+ });
171
+ }
172
+ catch {
173
+ return isoString;
174
+ }
175
+ }
176
+ // ── Skip Hint (shown once at start of questionnaire) ───────────────
177
+ function skipHint() {
178
+ console.log(` ${dim("Press Enter to skip any question.")}\n`);
179
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baseline-studio/cli",
3
- "version": "2.2.5",
3
+ "version": "2.6.1",
4
4
  "description": "CLI for distributing and updating the Baseline System — an AI-powered workflow system for product teams",
5
5
  "keywords": [
6
6
  "baseline",
@@ -8,7 +8,12 @@
8
8
  "cli",
9
9
  "workflow",
10
10
  "product-management",
11
- "claude-code"
11
+ "agents-md",
12
+ "claude-code",
13
+ "cursor",
14
+ "copilot",
15
+ "windsurf",
16
+ "codex"
12
17
  ],
13
18
  "homepage": "https://github.com/TrentM6/baseline-core#readme",
14
19
  "repository": {
@@ -38,6 +43,7 @@
38
43
  "node": ">=18.0.0"
39
44
  },
40
45
  "dependencies": {
46
+ "chalk": "^4.1.2",
41
47
  "commander": "^12.0.0",
42
48
  "js-yaml": "^4.1.0",
43
49
  "semver": "^7.6.0"