@baseline-studio/cli 2.2.5 → 2.6.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 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 });
@@ -67,8 +109,12 @@ async function init() {
67
109
  prompts = (0, js_yaml_1.load)((0, fs_1.readFileSync)(promptsPath, "utf-8"));
68
110
  }
69
111
  // 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");
112
+ console.log();
113
+ ui.info("Let's set up your context files.");
114
+ ui.skipHint();
115
+ // Count sections with prompts for progress tracking
116
+ const promptSections = contextFiles.filter((f) => prompts[f]);
117
+ let sectionIndex = 0;
72
118
  for (const ctxFile of contextFiles) {
73
119
  const prompt = prompts[ctxFile];
74
120
  if (!prompt) {
@@ -78,16 +124,20 @@ async function init() {
78
124
  (0, fs_1.writeFileSync)(fullPath, `# ${ctxFile}\n\n<!-- Add your content here -->\n`);
79
125
  continue;
80
126
  }
81
- console.log(` ── ${prompt.title} ──\n`);
127
+ sectionIndex++;
128
+ ui.sectionHeader(prompt.title, sectionIndex, promptSections.length);
82
129
  const answers = [];
130
+ let answeredCount = 0;
83
131
  // Pre-fill company name into identity file
84
132
  if (ctxFile === "core/identity.md") {
85
133
  answers.push(`**What is your company name?**\n${clientName}`);
86
134
  }
87
- for (const q of prompt.questions) {
88
- const answer = await ask(rl, ` ${q}\n > `);
135
+ for (let qi = 0; qi < prompt.questions.length; qi++) {
136
+ const q = prompt.questions[qi];
137
+ const answer = await ask(rl, ui.formatPromptWithProgress(q, qi + 1, prompt.questions.length));
89
138
  if (answer.trim()) {
90
139
  answers.push(`**${q}**\n${answer.trim()}`);
140
+ answeredCount++;
91
141
  }
92
142
  console.log();
93
143
  }
@@ -99,6 +149,7 @@ async function init() {
99
149
  else {
100
150
  (0, fs_1.writeFileSync)(fullPath, `# ${prompt.title}\n\n<!-- Add your content here -->\n`);
101
151
  }
152
+ ui.sectionComplete(prompt.title, answeredCount, prompt.questions.length);
102
153
  }
103
154
  // 8. Create context.yaml
104
155
  const contextYaml = buildContextYaml(tmpDir, contextFiles);
@@ -114,16 +165,24 @@ async function init() {
114
165
  },
115
166
  };
116
167
  (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");
168
+ // 10. Create AI instruction files
169
+ // 10a. AGENTS.md canonical instructions for all AI tools
170
+ const agentsTemplatePath = (0, path_1.join)(tmpDir, "agents-template.md");
171
+ if ((0, fs_1.existsSync)(agentsTemplatePath)) {
172
+ let template = (0, fs_1.readFileSync)(agentsTemplatePath, "utf-8");
121
173
  template = template.replace(/\{client_name\}/g, clientName);
122
- (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "CLAUDE.md"), template);
174
+ (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "AGENTS.md"), template);
123
175
  }
124
176
  else {
125
- (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "CLAUDE.md"), generateClaudeMd(clientName));
177
+ (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "AGENTS.md"), generateAgentsMd(clientName));
126
178
  }
179
+ // 10b. CLAUDE.md — pointer for Claude Code
180
+ (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "CLAUDE.md"), generateClaudeMdPointer());
181
+ // 10c. .github/copilot-instructions.md — pointer for GitHub Copilot Chat
182
+ (0, fs_1.mkdirSync)((0, path_1.join)(destDir, ".github"), { recursive: true });
183
+ (0, fs_1.writeFileSync)((0, path_1.join)(destDir, ".github", "copilot-instructions.md"), generateCopilotInstructions());
184
+ // 10d. README.md — system documentation
185
+ (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "README.md"), generateReadme(clientName));
127
186
  // 11. Create root package.json for local CLI access
128
187
  const rootPkg = {
129
188
  name: `${clientName.toLowerCase().replace(/\s+/g, "-")}-system`,
@@ -136,27 +195,33 @@ async function init() {
136
195
  };
137
196
  (0, fs_1.writeFileSync)((0, path_1.join)(destDir, "package.json"), JSON.stringify(rootPkg, null, 2) + "\n");
138
197
  // 12. Install CLI locally so npx baseline works
139
- console.log(`\n Installing CLI...`);
198
+ const spin3 = ui.spinner("Installing CLI...");
140
199
  (0, child_process_1.execSync)("npm install --silent", { cwd: destDir, stdio: "pipe" });
200
+ spin3.stop("CLI installed");
141
201
  // 13. Create .gitignore
142
202
  (0, fs_1.writeFileSync)((0, path_1.join)(destDir, ".gitignore"), "node_modules/\n.DS_Store\n");
143
203
  // 14. Initialize git repo
204
+ const spin4 = ui.spinner("Initializing repository...");
144
205
  (0, child_process_1.execSync)("git init", { cwd: destDir, stdio: "pipe" });
145
206
  (0, child_process_1.execSync)("git add -A", { cwd: destDir, stdio: "pipe" });
146
207
  (0, child_process_1.execSync)(`git commit -m "Initialize ${clientName} Baseline System (v${latest})"`, { cwd: destDir, stdio: "pipe" });
208
+ spin4.stop("Repository initialized");
147
209
  // Clean up
148
210
  (0, fs_1.rmSync)(tmpDir, { recursive: true });
149
211
  rl.close();
150
212
  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
213
  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
214
  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`);
215
+ ui.summary(`${clientName} system ready!`, [
216
+ ["Version:", `v${latest}`],
217
+ ["Skills:", `${skillCount}`],
218
+ ["Frameworks:", `${frameworkCount}`],
219
+ ["Scripts:", `${scriptCount}`],
220
+ ]);
221
+ ui.nextSteps([
222
+ `Edit ${ui.accent("context/")} files to add more detail`,
223
+ `Run ${ui.accent("npx baseline status")} to check for updates`,
224
+ ]);
160
225
  }
161
226
  /** Scan all skill manifests and return unique context file paths (relative to context/) */
162
227
  function collectContextPaths(coreDir) {
@@ -167,6 +232,8 @@ function collectContextPaths(coreDir) {
167
232
  // Always include core files
168
233
  paths.add("core/identity.md");
169
234
  paths.add("core/voice.md");
235
+ // Always include co-founder context (used by Co-Founder Mode, not a skill)
236
+ paths.add("extended/co-founder.md");
170
237
  for (const skill of (0, fs_1.readdirSync)(skillsDir)) {
171
238
  const manifestPath = (0, path_1.join)(skillsDir, skill, "manifest.yaml");
172
239
  if (!(0, fs_1.existsSync)(manifestPath))
@@ -232,6 +299,8 @@ function buildContextYaml(coreDir, contextFiles) {
232
299
  yaml += " - identity.md # loaded by all skills\n";
233
300
  yaml += " - voice.md # loaded by all skills\n";
234
301
  yaml += "extended:\n";
302
+ yaml += " co-founder.md:\n";
303
+ yaml += " - co-founder-mode # loaded by Co-Founder Mode (not a skill)\n";
235
304
  for (const [file, skills] of [...extendedMap.entries()].sort()) {
236
305
  yaml += ` ${file}:\n`;
237
306
  for (const s of skills.sort()) {
@@ -240,11 +309,11 @@ function buildContextYaml(coreDir, contextFiles) {
240
309
  }
241
310
  return yaml;
242
311
  }
243
- /** Generate a CLAUDE.md for the client if no template exists in core */
244
- function generateClaudeMd(clientName) {
312
+ /** Generate AGENTS.md canonical AI instructions for all tools */
313
+ function generateAgentsMd(clientName) {
245
314
  return `# ${clientName} — Baseline System
246
315
 
247
- > This file is automatically loaded at the start of every Claude Code session. It enforces consistent skill execution.
316
+ > This file provides instructions for AI coding agents. It enforces consistent skill execution across all AI tools.
248
317
 
249
318
  ---
250
319
 
@@ -321,11 +390,53 @@ If the user wants output delivered to an external tool, read the relevant script
321
390
 
322
391
  ---
323
392
 
393
+ ## Co-Founder Mode
394
+
395
+ When the user wants to brainstorm, strategize, or think through problems without invoking a specific skill, activate co-founder mode.
396
+
397
+ ### When to Activate
398
+
399
+ Activate when the user:
400
+ - Asks to "brainstorm" or "strategize" without naming a skill
401
+ - Wants to "talk through" a problem or decision
402
+ - Asks for strategic advice or a thinking partner
403
+ - Phrases requests as open-ended questions about direction or approach
404
+
405
+ **Do NOT activate when:**
406
+ - The user invokes a specific skill by name or task mapping
407
+ - The user asks for a specific deliverable (PRD, wireframe, content, etc.)
408
+ - The request maps clearly to a skill in the table above
409
+
410
+ ### How to Use
411
+
412
+ 1. **Load context files:**
413
+ \`\`\`
414
+ context/core/identity.md
415
+ context/core/voice.md
416
+ context/extended/co-founder.md
417
+ \`\`\`
418
+ If \`co-founder.md\` does not exist, load only core context and proceed without the persona.
419
+
420
+ 2. **Adopt the persona.** Use the co-founder file to guide your thinking style, questions, and decision-making approach.
421
+
422
+ 3. **No workflow structure.** This is NOT a skill. No Plan/Clarify/Execute/Validate steps. No deliverables. No quality checks. Just strategic thinking partnership.
423
+
424
+ 4. **Ask probing questions.** Use the Default Questions and Assumptions to Challenge from the co-founder file to surface blind spots.
425
+
426
+ 5. **Reference principles when relevant.** When the conversation touches on strategic decisions, reference the Strategic Principles and Non-Negotiables from the co-founder file.
427
+
428
+ ### When to Exit
429
+
430
+ 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.
431
+
432
+ ---
433
+
324
434
  ## Session Management
325
435
 
326
436
  - Scope each session to one major task. Multi-task sessions degrade output quality.
327
437
  - After completing a major deliverable, recommend starting a fresh session.
328
438
  - If the conversation has gone through 3+ revision cycles, proactively suggest a session break.
439
+ - 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
440
 
330
441
  ---
331
442
 
@@ -339,3 +450,177 @@ If the user wants output delivered to an external tool, read the relevant script
339
450
  - **Overload the session** — One major task per session. Recommend fresh sessions after milestones.
340
451
  `;
341
452
  }
453
+ /** Generate CLAUDE.md — thin pointer to AGENTS.md for Claude Code */
454
+ function generateClaudeMdPointer() {
455
+ return `# Baseline System
456
+
457
+ 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.
458
+ `;
459
+ }
460
+ /** Generate .github/copilot-instructions.md — thin pointer to AGENTS.md for GitHub Copilot */
461
+ function generateCopilotInstructions() {
462
+ return `# Baseline System
463
+
464
+ 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.
465
+ `;
466
+ }
467
+ /** Generate README.md for client systems */
468
+ function generateReadme(clientName) {
469
+ return `# ${clientName} — Baseline System
470
+
471
+ > A complete AI system for product teams. Skills provide methodology. Context makes it yours. Frameworks give structure. Scripts deliver to your tools.
472
+
473
+ ## Getting Started
474
+
475
+ \`\`\`bash
476
+ npx baseline status # Check for updates
477
+ npx baseline update # Pull latest version
478
+ \`\`\`
479
+
480
+ ---
481
+
482
+ ## What This Is
483
+
484
+ 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.
485
+
486
+ It works with any AI coding tool by giving it structured knowledge about how to do product work and specific knowledge about your business.
487
+
488
+ **Four components:**
489
+
490
+ | Component | What It Does | Details |
491
+ |-----------|-------------|---------|
492
+ | **Skills** | Domain expertise modules that teach AI how to execute specific work | [\`skills/_README.md\`](skills/_README.md) |
493
+ | **Context** | Your business-specific knowledge — identity, voice, customers, product | \`context/\` |
494
+ | **Frameworks** | Reusable methodologies — prioritization, research, decision-making | [\`frameworks/_README.md\`](frameworks/_README.md) |
495
+ | **Scripts** | Delivery to external tools — Figma, Asana, Confluence, etc. | [\`scripts/_README.md\`](scripts/_README.md) |
496
+
497
+ 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.
498
+
499
+ ---
500
+
501
+ ## How It Works
502
+
503
+ 1. **You describe a task** — "Write a PRD for the new onboarding flow" or "Help me prioritize Q2 roadmap"
504
+ 2. **The system identifies the skill** — PRDs map to \`product-communications\`, prioritization maps to \`strategic-advisory\`
505
+ 3. **The skill loads its files** — The skill's \`manifest.yaml\` lists what to load: the skill file, frameworks, and your context
506
+ 4. **The system executes** — Plan, clarify, execute, validate
507
+
508
+ In AI coding tools, this is fully automated via the \`AGENTS.md\` file. Just describe what you need.
509
+
510
+ ### The 12 Skills
511
+
512
+ | Skill | What It Does |
513
+ |-------|-------------|
514
+ | **Strategic Advisory** | Roadmaps, prioritization, OKRs, strategic decisions |
515
+ | **Research Synthesis** | User interviews, research reports, validation testing |
516
+ | **Product Communications** | PRDs, specs, briefs, stakeholder updates |
517
+ | **UX Design** | Wireframes, user flows, UI copy, design critique |
518
+ | **Product Analytics** | Metrics frameworks, dashboards, A/B test plans |
519
+ | **Prototyping** | Coded prototypes, demos, proof-of-concepts |
520
+ | **Project Management** | Sprint planning, tracking, retrospectives |
521
+ | **Technical Documentation** | User guides, API docs, release notes, help content |
522
+ | **Brand Design** | Presentations, graphics, visual design direction |
523
+ | **Marketing** | LinkedIn posts, website copy, campaigns, case studies |
524
+ | **Sales** | Outreach emails, proposals, discovery call prep |
525
+ | **Skill Building** | Create new custom skills for your team |
526
+
527
+ See [\`skills/_README.md\`](skills/_README.md) for detailed documentation on each skill.
528
+
529
+ ---
530
+
531
+ ## Using the System
532
+
533
+ ### AI Coding Tools (Automated)
534
+
535
+ \`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:
536
+
537
+ | Tool | How It Works |
538
+ |------|-------------|
539
+ | **Codex, Cursor, Windsurf, JetBrains AI** | Reads \`AGENTS.md\` directly |
540
+ | **Claude Code** | Reads \`CLAUDE.md\`, which points to \`AGENTS.md\` |
541
+ | **GitHub Copilot Chat** | Reads \`.github/copilot-instructions.md\`, which points to \`AGENTS.md\` |
542
+
543
+ 1. Open this folder in your AI coding tool
544
+ 2. Describe what you need
545
+ 3. Done — the tool reads \`AGENTS.md\` (directly or via pointer) and handles the rest
546
+
547
+ ### ChatGPT / Gemini / Other Chat Tools
548
+
549
+ 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.
550
+
551
+ ---
552
+
553
+ ## Context
554
+
555
+ Context is what makes the system yours. The system's output quality is directly proportional to the quality of your context.
556
+
557
+ **Core context** (loaded by every skill):
558
+ - \`context/core/identity.md\` — Who you are, what you do, positioning, differentiators
559
+ - \`context/core/voice.md\` — How you sound, language rules, tone by channel
560
+
561
+ **Extended context** (loaded by relevant skills):
562
+ - \`context/extended/product.md\` — Product details, features, workflow
563
+ - \`context/extended/users.md\` — User personas, goals, pain points
564
+ - \`context/extended/icp.md\` — Ideal customer profile, buyer psychology
565
+ - \`context/extended/competitive.md\` — Competitors, positioning, alternatives
566
+ - \`context/extended/pricing.md\` — Pricing tiers, objection handling
567
+ - \`context/extended/technical.md\` — Tech stack, integrations, constraints
568
+ - \`context/extended/visual-identity.md\` — Colors, fonts, visual style
569
+ - \`context/extended/formatting.md\` — Document structure, heading rules
570
+ - \`context/extended/proof-points.md\` — Metrics, case studies, credibility
571
+
572
+ 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.
573
+
574
+ ---
575
+
576
+ ## CLI Reference
577
+
578
+ | Command | What It Does |
579
+ |---------|-------------|
580
+ | \`npx baseline status\` | Show current version, check for updates |
581
+ | \`npx baseline update\` | Pull latest skills, frameworks, scripts, and CLI |
582
+ | \`npx baseline context\` | Re-run context prompts to update existing files |
583
+ | \`npx baseline context add <name>\` | Create a new context file and wire it to skills |
584
+
585
+ ---
586
+
587
+ ## File Structure
588
+
589
+ \`\`\`
590
+ ${clientName.toLowerCase().replace(/\\s+/g, "-")}-system/
591
+ ├── AGENTS.md # AI instructions for all coding tools (don't edit)
592
+ ├── CLAUDE.md # Claude Code pointer to AGENTS.md
593
+ ├── .github/
594
+ │ └── copilot-instructions.md # GitHub Copilot pointer to AGENTS.md
595
+ ├── baseline.config.json # Version tracking and config
596
+ ├── skills/ # 12 domain expertise modules
597
+ ├── context/ # YOUR business knowledge (you own this)
598
+ │ ├── core/ # Identity and voice (loaded by every skill)
599
+ │ └── extended/ # Product, users, pricing, etc.
600
+ ├── frameworks/ # Reusable methodologies
601
+ ├── scripts/ # Delivery to external tools
602
+ └── cli/ # Bundled CLI for daily use
603
+ \`\`\`
604
+
605
+ **You own \`context/\`.** Everything else is managed by the system and updated via \`npx baseline update\`.
606
+
607
+ ---
608
+
609
+ ## FAQ
610
+
611
+ **Can I edit skill files?**
612
+ You can, but changes are overwritten on \`baseline update\`. Put custom behavior in context files instead.
613
+
614
+ **What if I don't have all the context files filled out?**
615
+ Skills work with whatever context is available. Missing context means more generic output, but nothing breaks.
616
+
617
+ **Can I add my own context files?**
618
+ Yes. Run \`npx baseline context add <name>\` to create a new file and wire it to skills.
619
+
620
+ **What AI tools does this work with?**
621
+ 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.
622
+
623
+ **How do I get help?**
624
+ Email trent@baselinestudio.design.
625
+ `;
626
+ }
@@ -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.0",
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"