@baseline-studio/cli 2.2.4 → 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 +4 -1
- package/dist/commands/context.js +73 -26
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.js +316 -45
- package/dist/commands/status.js +48 -11
- package/dist/commands/update.js +108 -28
- package/dist/index.js +4 -1
- package/dist/ui.d.ts +25 -0
- package/dist/ui.js +179 -0
- package/package.json +8 -2
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
|
-
├──
|
|
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)
|
package/dist/commands/context.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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(
|
|
45
|
-
|
|
46
|
-
console.log(
|
|
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
|
-
|
|
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
|
-
|
|
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 ?
|
|
58
|
-
const answer = await ask(rl,
|
|
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
|
-
|
|
76
|
-
|
|
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
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
console.log(
|
|
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,
|
|
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(
|
|
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}
|
|
160
|
+
console.log(` ${ui.dim(`${i + 1}.`)} ${skills[i]}`);
|
|
116
161
|
}
|
|
117
162
|
console.log();
|
|
118
|
-
const selection = await ask(rl, `
|
|
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
|
|
154
|
-
for (const [file, skillList] of
|
|
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(
|
|
163
|
-
|
|
207
|
+
console.log();
|
|
208
|
+
ui.divider();
|
|
209
|
+
ui.success(`Created context/extended/${fileName}`);
|
|
164
210
|
if (selectedSkills.length > 0) {
|
|
165
|
-
|
|
211
|
+
ui.info(`Wired to: ${selectedSkills.join(", ")}`);
|
|
166
212
|
}
|
|
167
|
-
|
|
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) {
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -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;
|
package/dist/commands/init.js
CHANGED
|
@@ -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,33 +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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
//
|
|
33
|
-
const
|
|
34
|
-
const npxArtifacts = new Set(["node_modules", "package-lock.json", "package.json"]);
|
|
35
|
-
const cwdEntries = (0, fs_1.readdirSync)(cwd).filter((f) => !f.startsWith(".") && !npxArtifacts.has(f));
|
|
36
|
-
const destDir = cwdEntries.length === 0
|
|
37
|
-
? cwd
|
|
38
|
-
: (0, path_1.join)(cwd, `${clientName.toLowerCase().replace(/\s+/g, "-")}-system`);
|
|
39
|
-
if (destDir !== cwd && (0, fs_1.existsSync)(destDir)) {
|
|
40
|
-
console.error(`\n Error: ${destDir} already exists.\n`);
|
|
41
|
-
rl.close();
|
|
42
|
-
process.exit(1);
|
|
43
|
-
}
|
|
69
|
+
// Always scaffold in the current directory
|
|
70
|
+
const destDir = process.cwd();
|
|
44
71
|
// 2. Fetch latest from core
|
|
45
|
-
console.log(
|
|
72
|
+
console.log();
|
|
73
|
+
const spin1 = ui.spinner("Fetching latest version...");
|
|
46
74
|
const latest = (0, git_js_1.getLatestTag)(repo);
|
|
47
75
|
if (!latest) {
|
|
48
|
-
|
|
76
|
+
spin1.stop();
|
|
77
|
+
ui.error("Could not determine latest version.");
|
|
78
|
+
console.log();
|
|
49
79
|
rl.close();
|
|
50
80
|
process.exit(1);
|
|
51
81
|
}
|
|
52
|
-
|
|
82
|
+
spin1.stop(`Using v${latest}`);
|
|
83
|
+
const spin2 = ui.spinner("Downloading system files...");
|
|
53
84
|
const tmpDir = (0, git_js_1.cloneAtTag)(repo, latest);
|
|
85
|
+
spin2.stop("System files downloaded");
|
|
54
86
|
// 3. Create folder structure
|
|
55
87
|
(0, fs_1.mkdirSync)((0, path_1.join)(destDir, "context", "core"), { recursive: true });
|
|
56
88
|
(0, fs_1.mkdirSync)((0, path_1.join)(destDir, "context", "extended"), { recursive: true });
|
|
@@ -77,8 +109,12 @@ async function init() {
|
|
|
77
109
|
prompts = (0, js_yaml_1.load)((0, fs_1.readFileSync)(promptsPath, "utf-8"));
|
|
78
110
|
}
|
|
79
111
|
// 7. Ask questions and write context files
|
|
80
|
-
console.log(
|
|
81
|
-
|
|
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;
|
|
82
118
|
for (const ctxFile of contextFiles) {
|
|
83
119
|
const prompt = prompts[ctxFile];
|
|
84
120
|
if (!prompt) {
|
|
@@ -88,16 +124,20 @@ async function init() {
|
|
|
88
124
|
(0, fs_1.writeFileSync)(fullPath, `# ${ctxFile}\n\n<!-- Add your content here -->\n`);
|
|
89
125
|
continue;
|
|
90
126
|
}
|
|
91
|
-
|
|
127
|
+
sectionIndex++;
|
|
128
|
+
ui.sectionHeader(prompt.title, sectionIndex, promptSections.length);
|
|
92
129
|
const answers = [];
|
|
130
|
+
let answeredCount = 0;
|
|
93
131
|
// Pre-fill company name into identity file
|
|
94
132
|
if (ctxFile === "core/identity.md") {
|
|
95
133
|
answers.push(`**What is your company name?**\n${clientName}`);
|
|
96
134
|
}
|
|
97
|
-
for (
|
|
98
|
-
const
|
|
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));
|
|
99
138
|
if (answer.trim()) {
|
|
100
139
|
answers.push(`**${q}**\n${answer.trim()}`);
|
|
140
|
+
answeredCount++;
|
|
101
141
|
}
|
|
102
142
|
console.log();
|
|
103
143
|
}
|
|
@@ -109,6 +149,7 @@ async function init() {
|
|
|
109
149
|
else {
|
|
110
150
|
(0, fs_1.writeFileSync)(fullPath, `# ${prompt.title}\n\n<!-- Add your content here -->\n`);
|
|
111
151
|
}
|
|
152
|
+
ui.sectionComplete(prompt.title, answeredCount, prompt.questions.length);
|
|
112
153
|
}
|
|
113
154
|
// 8. Create context.yaml
|
|
114
155
|
const contextYaml = buildContextYaml(tmpDir, contextFiles);
|
|
@@ -124,16 +165,24 @@ async function init() {
|
|
|
124
165
|
},
|
|
125
166
|
};
|
|
126
167
|
(0, fs_1.writeFileSync)((0, path_1.join)(destDir, "baseline.config.json"), JSON.stringify(config, null, 2) + "\n");
|
|
127
|
-
// 10. Create
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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");
|
|
131
173
|
template = template.replace(/\{client_name\}/g, clientName);
|
|
132
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(destDir, "
|
|
174
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(destDir, "AGENTS.md"), template);
|
|
133
175
|
}
|
|
134
176
|
else {
|
|
135
|
-
(0, fs_1.writeFileSync)((0, path_1.join)(destDir, "
|
|
177
|
+
(0, fs_1.writeFileSync)((0, path_1.join)(destDir, "AGENTS.md"), generateAgentsMd(clientName));
|
|
136
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));
|
|
137
186
|
// 11. Create root package.json for local CLI access
|
|
138
187
|
const rootPkg = {
|
|
139
188
|
name: `${clientName.toLowerCase().replace(/\s+/g, "-")}-system`,
|
|
@@ -146,31 +195,33 @@ async function init() {
|
|
|
146
195
|
};
|
|
147
196
|
(0, fs_1.writeFileSync)((0, path_1.join)(destDir, "package.json"), JSON.stringify(rootPkg, null, 2) + "\n");
|
|
148
197
|
// 12. Install CLI locally so npx baseline works
|
|
149
|
-
|
|
198
|
+
const spin3 = ui.spinner("Installing CLI...");
|
|
150
199
|
(0, child_process_1.execSync)("npm install --silent", { cwd: destDir, stdio: "pipe" });
|
|
200
|
+
spin3.stop("CLI installed");
|
|
151
201
|
// 13. Create .gitignore
|
|
152
202
|
(0, fs_1.writeFileSync)((0, path_1.join)(destDir, ".gitignore"), "node_modules/\n.DS_Store\n");
|
|
153
203
|
// 14. Initialize git repo
|
|
204
|
+
const spin4 = ui.spinner("Initializing repository...");
|
|
154
205
|
(0, child_process_1.execSync)("git init", { cwd: destDir, stdio: "pipe" });
|
|
155
206
|
(0, child_process_1.execSync)("git add -A", { cwd: destDir, stdio: "pipe" });
|
|
156
207
|
(0, child_process_1.execSync)(`git commit -m "Initialize ${clientName} Baseline System (v${latest})"`, { cwd: destDir, stdio: "pipe" });
|
|
208
|
+
spin4.stop("Repository initialized");
|
|
157
209
|
// Clean up
|
|
158
210
|
(0, fs_1.rmSync)(tmpDir, { recursive: true });
|
|
159
211
|
rl.close();
|
|
160
|
-
const displayPath = destDir === cwd ? "." : `./${clientName.toLowerCase().replace(/\s+/g, "-")}-system`;
|
|
161
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;
|
|
162
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;
|
|
163
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;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
+
]);
|
|
174
225
|
}
|
|
175
226
|
/** Scan all skill manifests and return unique context file paths (relative to context/) */
|
|
176
227
|
function collectContextPaths(coreDir) {
|
|
@@ -181,6 +232,8 @@ function collectContextPaths(coreDir) {
|
|
|
181
232
|
// Always include core files
|
|
182
233
|
paths.add("core/identity.md");
|
|
183
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");
|
|
184
237
|
for (const skill of (0, fs_1.readdirSync)(skillsDir)) {
|
|
185
238
|
const manifestPath = (0, path_1.join)(skillsDir, skill, "manifest.yaml");
|
|
186
239
|
if (!(0, fs_1.existsSync)(manifestPath))
|
|
@@ -246,6 +299,8 @@ function buildContextYaml(coreDir, contextFiles) {
|
|
|
246
299
|
yaml += " - identity.md # loaded by all skills\n";
|
|
247
300
|
yaml += " - voice.md # loaded by all skills\n";
|
|
248
301
|
yaml += "extended:\n";
|
|
302
|
+
yaml += " co-founder.md:\n";
|
|
303
|
+
yaml += " - co-founder-mode # loaded by Co-Founder Mode (not a skill)\n";
|
|
249
304
|
for (const [file, skills] of [...extendedMap.entries()].sort()) {
|
|
250
305
|
yaml += ` ${file}:\n`;
|
|
251
306
|
for (const s of skills.sort()) {
|
|
@@ -254,11 +309,11 @@ function buildContextYaml(coreDir, contextFiles) {
|
|
|
254
309
|
}
|
|
255
310
|
return yaml;
|
|
256
311
|
}
|
|
257
|
-
/** Generate
|
|
258
|
-
function
|
|
312
|
+
/** Generate AGENTS.md — canonical AI instructions for all tools */
|
|
313
|
+
function generateAgentsMd(clientName) {
|
|
259
314
|
return `# ${clientName} — Baseline System
|
|
260
315
|
|
|
261
|
-
> This file
|
|
316
|
+
> This file provides instructions for AI coding agents. It enforces consistent skill execution across all AI tools.
|
|
262
317
|
|
|
263
318
|
---
|
|
264
319
|
|
|
@@ -335,11 +390,53 @@ If the user wants output delivered to an external tool, read the relevant script
|
|
|
335
390
|
|
|
336
391
|
---
|
|
337
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
|
+
|
|
338
434
|
## Session Management
|
|
339
435
|
|
|
340
436
|
- Scope each session to one major task. Multi-task sessions degrade output quality.
|
|
341
437
|
- After completing a major deliverable, recommend starting a fresh session.
|
|
342
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.
|
|
343
440
|
|
|
344
441
|
---
|
|
345
442
|
|
|
@@ -353,3 +450,177 @@ If the user wants output delivered to an external tool, read the relevant script
|
|
|
353
450
|
- **Overload the session** — One major task per session. Recommend fresh sessions after milestones.
|
|
354
451
|
`;
|
|
355
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
|
+
}
|
package/dist/commands/status.js
CHANGED
|
@@ -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
|
-
|
|
9
|
-
console.log(`
|
|
10
|
-
console.log(`
|
|
11
|
-
console.log(`
|
|
12
|
-
console.log(`
|
|
13
|
-
console.log(
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
|
|
22
|
-
console.log(`
|
|
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
|
-
|
|
61
|
+
ui.success(`Up to date (v${config.version})`);
|
|
62
|
+
console.log();
|
|
26
63
|
}
|
|
27
64
|
}
|
package/dist/commands/update.js
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
61
|
+
spin1.stop(`Already up to date (v${config.version})`);
|
|
62
|
+
console.log();
|
|
22
63
|
return;
|
|
23
64
|
}
|
|
24
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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.
|
|
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
|
-
"
|
|
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"
|