@readme/cli 0.1.0 → 0.2.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/bin/readme.js +1 -1
- package/package.json +33 -24
- package/src/bootstrap.js +9 -13
- package/src/cli.js +17 -11
- package/src/commands/components.js +35 -18
- package/src/commands/dev.js +12 -8
- package/src/commands/eyes.js +12 -8
- package/src/commands/import.js +2190 -2048
- package/src/commands/lint.js +33 -29
- package/src/commands/oas-bundle.js +6 -2
- package/src/commands/oas-sync.js +96 -93
- package/src/commands/oas-validate.js +10 -7
- package/src/commands/pretty.js +177 -164
- package/src/commands/setup.js +24 -26
- package/src/commands/versions.js +6 -2
- package/src/dev/app/[...slug]/page.js +1 -0
- package/src/dev/app/layout.js +18 -11
- package/src/dev/app/page.js +1 -0
- package/src/dev/lib/docs.js +27 -19
- package/src/dev/next.config.mjs +2 -2
- package/src/gha.js +7 -7
- package/src/prompts/index.js +16 -6
- package/src/utils/eyes.js +143 -51
- package/src/utils/git.js +3 -3
- package/src/utils/lint.js +39 -38
- package/src/utils/llms.js +94 -91
- package/src/utils/markdown.js +256 -0
- package/src/utils/marketplace.js +12 -5
- package/src/utils/multi-spinner.js +5 -7
- package/src/utils/promise-pool.js +7 -5
- package/src/utils/reporter.js +88 -91
- package/src/utils/setup-templates.js +12 -6
- package/src/utils/styles.js +2 -1
- package/src/utils/tamagotchi.js +257 -91
- package/src/utils/tips.js +18 -9
- package/src/utils/url-segs.js +46 -41
- package/src/validators/components.js +55 -63
- package/src/validators/content.js +5 -10
- package/src/validators/duplicates.js +6 -2
- package/src/validators/frontmatter.js +19 -21
- package/src/validators/links.js +4 -8
- package/src/validators/oas-reference.js +7 -14
- package/src/validators/oas-schema.js +2 -0
- package/src/validators/ordering.js +5 -5
- package/src/validators/recipes.js +4 -12
- package/src/commands/import-oas.test.js +0 -277
- package/src/commands/import.classify.test.js +0 -172
- package/src/commands/import.landing.test.js +0 -217
- package/src/commands/import.slug-planner.test.js +0 -86
- package/src/commands/import.staging.test.js +0 -230
- package/src/commands/import.test.js +0 -382
- package/src/utils/llms.test.js +0 -302
- package/src/utils/url-segs.test.js +0 -239
package/bin/readme.js
CHANGED
package/package.json
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@readme/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "The ReadMe CLI",
|
|
5
|
-
"
|
|
5
|
+
"keywords": [
|
|
6
|
+
"cli",
|
|
7
|
+
"docs",
|
|
8
|
+
"readme"
|
|
9
|
+
],
|
|
10
|
+
"license": "ISC",
|
|
6
11
|
"bin": {
|
|
7
12
|
"readme": "./bin/readme.js",
|
|
8
13
|
"readme_": "./bin/readme.js"
|
|
9
14
|
},
|
|
15
|
+
"files": [
|
|
16
|
+
"bin",
|
|
17
|
+
"src",
|
|
18
|
+
"vendor",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
10
22
|
"exports": {
|
|
11
23
|
".": "./src/index.js",
|
|
12
24
|
"./commands/lint": "./src/commands/lint.js",
|
|
@@ -17,30 +29,18 @@
|
|
|
17
29
|
"./prompts": "./src/prompts/index.js",
|
|
18
30
|
"./package.json": "./package.json"
|
|
19
31
|
},
|
|
20
|
-
"files": [
|
|
21
|
-
"bin",
|
|
22
|
-
"src",
|
|
23
|
-
"vendor",
|
|
24
|
-
"README.md"
|
|
25
|
-
],
|
|
26
|
-
"scripts": {
|
|
27
|
-
"start": "node bin/readme.js",
|
|
28
|
-
"test": "node --test src/**/*.test.js test/*.test.js",
|
|
29
|
-
"build:gha": "ncc build src/gha.js -o dist-gha --external @readme/markdown"
|
|
30
|
-
},
|
|
31
|
-
"engines": {
|
|
32
|
-
"node": ">=22"
|
|
33
|
-
},
|
|
34
|
-
"keywords": [
|
|
35
|
-
"readme",
|
|
36
|
-
"cli",
|
|
37
|
-
"docs"
|
|
38
|
-
],
|
|
39
|
-
"license": "ISC",
|
|
40
32
|
"publishConfig": {
|
|
41
33
|
"access": "public",
|
|
42
34
|
"registry": "https://registry.npmjs.org"
|
|
43
35
|
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build:gha": "ncc build src/gha.js -o dist-gha --external @readme/markdown",
|
|
38
|
+
"format": "npx oxlint --fix && npx oxfmt --write",
|
|
39
|
+
"lint": "npx oxlint && npx oxfmt --check .",
|
|
40
|
+
"pretest": "npm run lint",
|
|
41
|
+
"start": "node bin/readme.js",
|
|
42
|
+
"test": "vitest run"
|
|
43
|
+
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@anthropic-ai/claude-agent-sdk": "^0.3.207",
|
|
46
46
|
"@readme/markdown": "^13.3.0",
|
|
@@ -50,16 +50,25 @@
|
|
|
50
50
|
"chalk": "^5.4.1",
|
|
51
51
|
"cli-spinners": "^3.4.0",
|
|
52
52
|
"commander": "^13.1.0",
|
|
53
|
-
"
|
|
53
|
+
"js-yaml": "^5.5.0",
|
|
54
54
|
"log-update": "^8.0.0",
|
|
55
55
|
"next": "^15.0.0",
|
|
56
56
|
"oas-normalize": "^15.7.1",
|
|
57
57
|
"ora": "^9.3.0",
|
|
58
58
|
"react": "^18.3.1",
|
|
59
59
|
"react-dom": "^18.3.1",
|
|
60
|
+
"remove-undefined-objects": "^9.0.0",
|
|
60
61
|
"update-notifier": "^7.3.1"
|
|
61
62
|
},
|
|
62
63
|
"devDependencies": {
|
|
63
|
-
"@
|
|
64
|
+
"@readme/oxlint-config": "^1.9.0",
|
|
65
|
+
"@vercel/ncc": "^0.45.0",
|
|
66
|
+
"@vitest/coverage-v8": "^5.0.5",
|
|
67
|
+
"oxfmt": "^0.74.0",
|
|
68
|
+
"oxlint": "^1.89.0",
|
|
69
|
+
"vitest": "^5.0.5"
|
|
70
|
+
},
|
|
71
|
+
"engines": {
|
|
72
|
+
"node": ">=22"
|
|
64
73
|
}
|
|
65
74
|
}
|
package/src/bootstrap.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
3
|
import { createRequire } from 'node:module';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
5
6
|
import updateNotifier from 'update-notifier';
|
|
7
|
+
|
|
6
8
|
import * as styles from './utils/styles.js';
|
|
7
9
|
|
|
8
10
|
const require = createRequire(import.meta.url);
|
|
@@ -22,7 +24,7 @@ export default async function bootstrap({ skipValidation = false } = {}) {
|
|
|
22
24
|
// 3. Make sure this is a ReadMe project repo
|
|
23
25
|
if (!skipValidation) {
|
|
24
26
|
if (!findGitRoot()) {
|
|
25
|
-
styles.error(
|
|
27
|
+
styles.error("This doesn't appear to be a git repository.");
|
|
26
28
|
styles.info('Run this command from inside a git repo to get started.');
|
|
27
29
|
styles.info(`You can skip this check with ${styles.bold(`${styles.binName()} --no-check`)}.`);
|
|
28
30
|
process.exit(1);
|
|
@@ -67,30 +69,24 @@ function validateReadMeRepo(gitRoot) {
|
|
|
67
69
|
branches = '';
|
|
68
70
|
}
|
|
69
71
|
|
|
70
|
-
const hasVersionBranch = branches
|
|
71
|
-
.split('\n')
|
|
72
|
-
.some((b) => /^(origin\/)?v[0-9]/.test(b.trim()));
|
|
72
|
+
const hasVersionBranch = branches.split('\n').some(b => /^(origin\/)?v[0-9]/.test(b.trim()));
|
|
73
73
|
|
|
74
74
|
// Check for /docs or /reference at the repo root
|
|
75
75
|
const hasDocs = fs.existsSync(path.join(gitRoot, 'docs'));
|
|
76
76
|
const hasReference = fs.existsSync(path.join(gitRoot, 'reference'));
|
|
77
77
|
|
|
78
78
|
if (!hasVersionBranch || (!hasDocs && !hasReference)) {
|
|
79
|
-
styles.error(
|
|
79
|
+
styles.error("This doesn't look like a ReadMe docs repo.");
|
|
80
80
|
|
|
81
81
|
if (!hasVersionBranch) {
|
|
82
|
-
styles.info(
|
|
83
|
-
`We couldn't find a version branch (e.g. ${styles.bold('v1')}, ${styles.bold('v2')}).`
|
|
84
|
-
);
|
|
82
|
+
styles.info(`We couldn't find a version branch (e.g. ${styles.bold('v1')}, ${styles.bold('v2')}).`);
|
|
85
83
|
}
|
|
86
84
|
if (!hasDocs && !hasReference) {
|
|
87
|
-
styles.info(
|
|
88
|
-
`We couldn't find a ${styles.bold('/docs')} or ${styles.bold('/reference')} folder.`
|
|
89
|
-
);
|
|
85
|
+
styles.info(`We couldn't find a ${styles.bold('/docs')} or ${styles.bold('/reference')} folder.`);
|
|
90
86
|
}
|
|
91
87
|
|
|
92
88
|
console.log();
|
|
93
|
-
styles.info(
|
|
89
|
+
styles.info("Make sure you're running this inside a ReadMe docs project.");
|
|
94
90
|
styles.info(`You can skip this check with ${styles.bold(`${styles.binName()} --no-check`)}.`);
|
|
95
91
|
process.exit(1);
|
|
96
92
|
}
|
package/src/cli.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
4
6
|
import { Command } from 'commander';
|
|
5
|
-
import { createRequire } from 'node:module';
|
|
6
7
|
import updateNotifier from 'update-notifier';
|
|
8
|
+
|
|
7
9
|
import bootstrap from './bootstrap.js';
|
|
8
|
-
import * as styles from './utils/styles.js';
|
|
9
10
|
import { header, setPalette, isAgenticCli } from './utils/eyes.js';
|
|
11
|
+
import * as styles from './utils/styles.js';
|
|
10
12
|
import { loadPet, applyDecay, getPetHeader } from './utils/tamagotchi.js';
|
|
11
13
|
import { getRandomTip } from './utils/tips.js';
|
|
12
14
|
|
|
@@ -46,18 +48,20 @@ export async function main() {
|
|
|
46
48
|
|
|
47
49
|
if (!isRunningInClaude) {
|
|
48
50
|
program.addHelpText('beforeAll', () => {
|
|
49
|
-
return
|
|
51
|
+
return `\n${header({
|
|
50
52
|
version: pkg.version,
|
|
51
53
|
binName: styles.binName(),
|
|
52
54
|
greeting: petGreeting,
|
|
53
55
|
expression: petExpression,
|
|
54
|
-
})
|
|
56
|
+
})
|
|
57
|
+
.map(l => ` ${l}`)
|
|
58
|
+
.join('\n')}\n`;
|
|
55
59
|
});
|
|
56
60
|
}
|
|
57
61
|
|
|
58
62
|
// Auto-discover and register every command in src/commands/
|
|
59
63
|
const commandsDir = path.join(path.dirname(fileURLToPath(import.meta.url)), 'commands');
|
|
60
|
-
const files = fs.readdirSync(commandsDir).filter(
|
|
64
|
+
const files = fs.readdirSync(commandsDir).filter(f => f.endsWith('.js') && !f.endsWith('.test.js'));
|
|
61
65
|
|
|
62
66
|
// Load all modules, then sort by order (default 0)
|
|
63
67
|
const mods = [];
|
|
@@ -111,7 +115,7 @@ export async function main() {
|
|
|
111
115
|
program.addHelpText('after', () => {
|
|
112
116
|
// Group registered commands by category. The built-in `help` command
|
|
113
117
|
// doesn't go through the loop above, so we add it manually.
|
|
114
|
-
const groups = {
|
|
118
|
+
const groups = { Linting: [], 'OAS Tooling': [], Other: [] };
|
|
115
119
|
for (const [cmd, category] of commandCategories.entries()) {
|
|
116
120
|
if (cmd._hidden) continue;
|
|
117
121
|
if (!groups[category]) groups[category] = [];
|
|
@@ -123,12 +127,12 @@ export async function main() {
|
|
|
123
127
|
|
|
124
128
|
const allCmds = Object.values(groups).flat();
|
|
125
129
|
if (allCmds.length === 0) return '';
|
|
126
|
-
const nameWidth = Math.max(...allCmds.map(
|
|
130
|
+
const nameWidth = Math.max(...allCmds.map(c => c.name().length));
|
|
127
131
|
|
|
128
132
|
// Map cmd → its source module so we can pull optional helpHint.
|
|
129
133
|
const cmdToMod = new Map();
|
|
130
134
|
for (const mod of mods) {
|
|
131
|
-
const cmd = program.commands.find(
|
|
135
|
+
const cmd = program.commands.find(c => c.name() === mod.command);
|
|
132
136
|
if (cmd) cmdToMod.set(cmd, mod);
|
|
133
137
|
}
|
|
134
138
|
|
|
@@ -158,10 +162,12 @@ export async function main() {
|
|
|
158
162
|
if (tip) {
|
|
159
163
|
let output = '';
|
|
160
164
|
const origLog = console.log;
|
|
161
|
-
console.log = (...args) => {
|
|
165
|
+
console.log = (...args) => {
|
|
166
|
+
output += `${args.join(' ')}\n`;
|
|
167
|
+
};
|
|
162
168
|
tip.render();
|
|
163
169
|
console.log = origLog;
|
|
164
|
-
return
|
|
170
|
+
return `\n${output}`;
|
|
165
171
|
}
|
|
166
172
|
return '';
|
|
167
173
|
});
|
|
@@ -185,7 +191,7 @@ export async function main() {
|
|
|
185
191
|
let cmdIdx = 2;
|
|
186
192
|
while (cmdIdx < argv.length && argv[cmdIdx].startsWith('-')) cmdIdx++;
|
|
187
193
|
const cmdArg = argv[cmdIdx];
|
|
188
|
-
if (cmdArg && cmdArg.includes(':') && !program.commands.some(
|
|
194
|
+
if (cmdArg && cmdArg.includes(':') && !program.commands.some(c => c.name() === cmdArg)) {
|
|
189
195
|
const [base, ...rest] = cmdArg.split(':');
|
|
190
196
|
argv.splice(cmdIdx, 1, base, rest.join(':'));
|
|
191
197
|
}
|
|
@@ -13,9 +13,11 @@
|
|
|
13
13
|
import fs from 'node:fs';
|
|
14
14
|
import path from 'node:path';
|
|
15
15
|
import readline from 'node:readline';
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
import { query } from '@anthropic-ai/claude-agent-sdk';
|
|
18
|
-
import
|
|
18
|
+
import ora from 'ora';
|
|
19
|
+
|
|
20
|
+
import { stripCodeFences } from '../prompts/index.js';
|
|
19
21
|
import {
|
|
20
22
|
listMarketplaceComponents,
|
|
21
23
|
fetchMarketplaceComponent,
|
|
@@ -23,7 +25,7 @@ import {
|
|
|
23
25
|
localComponentsDir,
|
|
24
26
|
listLocalComponents,
|
|
25
27
|
} from '../utils/marketplace.js';
|
|
26
|
-
import
|
|
28
|
+
import * as styles from '../utils/styles.js';
|
|
27
29
|
|
|
28
30
|
export const command = 'components [action] [name...]';
|
|
29
31
|
export const order = 3;
|
|
@@ -33,7 +35,7 @@ export const beta = true;
|
|
|
33
35
|
export const helpHint = [
|
|
34
36
|
'readme components # list marketplace + installed',
|
|
35
37
|
'readme components add <Name> # copy a marketplace component into ./components/',
|
|
36
|
-
|
|
38
|
+
"readme components show <Name> # print the component's source",
|
|
37
39
|
'readme components new "<idea>" # ask Claude to generate a new component',
|
|
38
40
|
].join('\n');
|
|
39
41
|
|
|
@@ -46,7 +48,7 @@ export function args(cmd) {
|
|
|
46
48
|
export async function run(action, names, options, _cmd, ctx) {
|
|
47
49
|
const { gitRoot } = ctx;
|
|
48
50
|
const sub = (action || 'list').toLowerCase();
|
|
49
|
-
const arg =
|
|
51
|
+
const arg = names && names.length ? names.join(' ') : null;
|
|
50
52
|
|
|
51
53
|
switch (sub) {
|
|
52
54
|
case 'list':
|
|
@@ -107,9 +109,9 @@ async function runList(gitRoot, options) {
|
|
|
107
109
|
}
|
|
108
110
|
spinner.stop();
|
|
109
111
|
|
|
110
|
-
const local = new Set(listLocalComponents(gitRoot).map(
|
|
112
|
+
const local = new Set(listLocalComponents(gitRoot).map(c => c.name.toLowerCase()));
|
|
111
113
|
|
|
112
|
-
const nameWidth = Math.max(...marketplace.map(
|
|
114
|
+
const nameWidth = Math.max(...marketplace.map(c => c.name.length));
|
|
113
115
|
for (const c of marketplace) {
|
|
114
116
|
const installed = local.has(c.name.toLowerCase());
|
|
115
117
|
const marker = installed ? styles.success('●') : styles.dim('○');
|
|
@@ -118,7 +120,7 @@ async function runList(gitRoot, options) {
|
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
console.log();
|
|
121
|
-
const installedCount = [...local].filter(
|
|
123
|
+
const installedCount = [...local].filter(n => marketplace.some(c => c.name.toLowerCase() === n)).length;
|
|
122
124
|
styles.info(`${marketplace.length} components in the marketplace · ${installedCount} already installed.`);
|
|
123
125
|
styles.info(`Run ${styles.bold('readme components add <Name>')} to copy one into ./components/.`);
|
|
124
126
|
}
|
|
@@ -173,12 +175,22 @@ async function runShow(name, options) {
|
|
|
173
175
|
console.log(` ${styles.heading(comp.name)} ${styles.dim(comp.htmlUrl)}`);
|
|
174
176
|
if (comp.readme) {
|
|
175
177
|
console.log();
|
|
176
|
-
console.log(
|
|
178
|
+
console.log(
|
|
179
|
+
comp.readme
|
|
180
|
+
.split('\n')
|
|
181
|
+
.map(l => ` ${l}`)
|
|
182
|
+
.join('\n'),
|
|
183
|
+
);
|
|
177
184
|
}
|
|
178
185
|
console.log();
|
|
179
186
|
console.log(` ${styles.bold('Source')} ${styles.dim(`(${comp.name}.mdx)`)}`);
|
|
180
187
|
console.log();
|
|
181
|
-
console.log(
|
|
188
|
+
console.log(
|
|
189
|
+
comp.mdx
|
|
190
|
+
.split('\n')
|
|
191
|
+
.map(l => ` ${l}`)
|
|
192
|
+
.join('\n'),
|
|
193
|
+
);
|
|
182
194
|
console.log();
|
|
183
195
|
}
|
|
184
196
|
|
|
@@ -198,7 +210,9 @@ async function runNew(gitRoot, description, options) {
|
|
|
198
210
|
try {
|
|
199
211
|
const c = await fetchMarketplaceComponent(n);
|
|
200
212
|
exemplars.push({ name: c.name, mdx: c.mdx });
|
|
201
|
-
} catch {
|
|
213
|
+
} catch {
|
|
214
|
+
/* skip */
|
|
215
|
+
}
|
|
202
216
|
}
|
|
203
217
|
|
|
204
218
|
const systemPrompt = [
|
|
@@ -221,7 +235,7 @@ async function runNew(gitRoot, description, options) {
|
|
|
221
235
|
'',
|
|
222
236
|
'For style and conventions, follow these existing components (do NOT copy them — match their structure):',
|
|
223
237
|
'',
|
|
224
|
-
...exemplars.map(
|
|
238
|
+
...exemplars.map(e => `### ${e.name}\n\`\`\`mdx\n${e.mdx}\n\`\`\``),
|
|
225
239
|
'',
|
|
226
240
|
'Now write the new component .mdx. Pick a good PascalCase name that matches the brief.',
|
|
227
241
|
].join('\n');
|
|
@@ -243,7 +257,7 @@ async function runNew(gitRoot, description, options) {
|
|
|
243
257
|
}
|
|
244
258
|
} else if (message.type === 'result') {
|
|
245
259
|
if (message.subtype && message.subtype !== 'success') {
|
|
246
|
-
throw new Error(`${message.subtype}${message.error?.message ?
|
|
260
|
+
throw new Error(`${message.subtype}${message.error?.message ? ` — ${message.error.message}` : ''}`);
|
|
247
261
|
}
|
|
248
262
|
break;
|
|
249
263
|
}
|
|
@@ -258,7 +272,7 @@ async function runNew(gitRoot, description, options) {
|
|
|
258
272
|
const mdx = stripCodeFences(text).trim();
|
|
259
273
|
const nameMatch = mdx.match(/export\s+const\s+([A-Z][A-Za-z0-9]+)\s*=/);
|
|
260
274
|
if (!nameMatch) {
|
|
261
|
-
styles.error(
|
|
275
|
+
styles.error("Claude's response did not include `export const <Name> = ...`. Try again.");
|
|
262
276
|
process.exit(1);
|
|
263
277
|
}
|
|
264
278
|
|
|
@@ -266,10 +280,13 @@ async function runNew(gitRoot, description, options) {
|
|
|
266
280
|
const file = path.join(dest, `${name}.mdx`);
|
|
267
281
|
if (fs.existsSync(file) && !options.yes) {
|
|
268
282
|
const ok = await confirm(`${styles.bold(name)}.mdx already exists. Overwrite?`);
|
|
269
|
-
if (!ok) {
|
|
283
|
+
if (!ok) {
|
|
284
|
+
styles.info('Aborted.');
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
270
287
|
}
|
|
271
288
|
|
|
272
|
-
fs.writeFileSync(file, mdx
|
|
289
|
+
fs.writeFileSync(file, `${mdx}\n`, 'utf-8');
|
|
273
290
|
console.log();
|
|
274
291
|
styles.ok(`Created ${styles.bold(name)} → ${styles.dim(path.relative(gitRoot, file))}`);
|
|
275
292
|
styles.info(`Use it in any docs page as ${styles.bold(`<${name} ... />`)}.`);
|
|
@@ -278,9 +295,9 @@ async function runNew(gitRoot, description, options) {
|
|
|
278
295
|
// ─── tiny readline confirm ───────────────────────────────────────────────────
|
|
279
296
|
|
|
280
297
|
function confirm(message) {
|
|
281
|
-
return new Promise(
|
|
298
|
+
return new Promise(resolve => {
|
|
282
299
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
283
|
-
rl.question(`${styles.warn('?')} ${message} ${styles.dim('[y/N]')} `,
|
|
300
|
+
rl.question(`${styles.warn('?')} ${message} ${styles.dim('[y/N]')} `, ans => {
|
|
284
301
|
rl.close();
|
|
285
302
|
resolve(/^y(es)?$/i.test(ans.trim()));
|
|
286
303
|
});
|
package/src/commands/dev.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
2
|
import { createServer } from 'http';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
3
|
import { createRequire } from 'node:module';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
|
|
6
7
|
import chalk from 'chalk';
|
|
7
|
-
|
|
8
|
+
|
|
8
9
|
import { header, setPalette, isAgenticCli } from '../utils/eyes.js';
|
|
10
|
+
import { binName } from '../utils/styles.js';
|
|
9
11
|
import { loadPet } from '../utils/tamagotchi.js';
|
|
10
12
|
|
|
11
13
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -35,15 +37,17 @@ export async function run(options, _cmd, ctx) {
|
|
|
35
37
|
try {
|
|
36
38
|
const pet = loadPet();
|
|
37
39
|
if (pet?.color) setPalette(pet.color);
|
|
38
|
-
} catch {
|
|
40
|
+
} catch {
|
|
41
|
+
// no-op
|
|
42
|
+
}
|
|
39
43
|
|
|
40
44
|
// Suppress Next.js noisy compile/request logging
|
|
41
45
|
for (const stream of [process.stdout, process.stderr]) {
|
|
42
46
|
const original = stream.write.bind(stream);
|
|
43
|
-
stream.write = (chunk, ...
|
|
47
|
+
stream.write = (chunk, ...streamAgs) => {
|
|
44
48
|
const str = typeof chunk === 'string' ? chunk : chunk.toString();
|
|
45
49
|
if (/^ [○✓⨯▲ ]*(Compiled|Compiling|GET |POST |⚠|Warning:)/.test(str)) return true;
|
|
46
|
-
return original(chunk, ...
|
|
50
|
+
return original(chunk, ...streamAgs);
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
53
|
|
|
@@ -84,7 +88,7 @@ export async function run(options, _cmd, ctx) {
|
|
|
84
88
|
|
|
85
89
|
function listen(port) {
|
|
86
90
|
return new Promise((resolve, reject) => {
|
|
87
|
-
const onError =
|
|
91
|
+
const onError = err => {
|
|
88
92
|
if (err.code === 'EADDRINUSE') {
|
|
89
93
|
resolve(listen(port + 1));
|
|
90
94
|
} else {
|
|
@@ -108,7 +112,7 @@ export async function run(options, _cmd, ctx) {
|
|
|
108
112
|
binName: `${binName()} dev`,
|
|
109
113
|
});
|
|
110
114
|
for (const line of headerLines) {
|
|
111
|
-
console.log(
|
|
115
|
+
console.log(` ${line}`);
|
|
112
116
|
}
|
|
113
117
|
console.log();
|
|
114
118
|
}
|
package/src/commands/eyes.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createRequire } from 'node:module';
|
|
2
|
+
|
|
2
3
|
import { printEyes, animate, expressions, animations } from '../utils/eyes.js';
|
|
3
4
|
import { binName } from '../utils/styles.js';
|
|
4
5
|
|
|
@@ -11,14 +12,12 @@ export const skipBootstrap = true;
|
|
|
11
12
|
|
|
12
13
|
export async function run(variant) {
|
|
13
14
|
if (!variant) {
|
|
14
|
-
// Show all expressions side by side
|
|
15
|
-
const chalk = (await import('chalk')).default;
|
|
16
|
-
const names = Object.keys(expressions);
|
|
17
|
-
const rendered = Object.fromEntries(names.map(n => [n, expressions[n] ? require : null]));
|
|
18
|
-
|
|
19
15
|
console.log('');
|
|
20
16
|
const ctrl = animate('all', { indent: ' ', version: pkg.version, binName: binName() });
|
|
21
|
-
process.on('SIGINT', () => {
|
|
17
|
+
process.on('SIGINT', () => {
|
|
18
|
+
ctrl.stop();
|
|
19
|
+
process.exit();
|
|
20
|
+
});
|
|
22
21
|
return;
|
|
23
22
|
}
|
|
24
23
|
|
|
@@ -29,9 +28,14 @@ export async function run(variant) {
|
|
|
29
28
|
} else if (animations[variant]) {
|
|
30
29
|
console.log('');
|
|
31
30
|
const ctrl = animate(variant, { indent: ' ', version: pkg.version, binName: binName() });
|
|
32
|
-
process.on('SIGINT', () => {
|
|
31
|
+
process.on('SIGINT', () => {
|
|
32
|
+
ctrl.stop();
|
|
33
|
+
process.exit();
|
|
34
|
+
});
|
|
33
35
|
} else {
|
|
34
|
-
console.error(
|
|
36
|
+
console.error(
|
|
37
|
+
`Unknown: "${variant}". Try: ${[...Object.keys(expressions), ...Object.keys(animations)].join(', ')}`,
|
|
38
|
+
);
|
|
35
39
|
process.exit(1);
|
|
36
40
|
}
|
|
37
41
|
}
|