vyriy 0.3.2 → 0.3.4

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.
Files changed (53) hide show
  1. package/AGENTS.md +59 -22
  2. package/README.md +38 -7
  3. package/cli/args/args.js +21 -10
  4. package/cli/args/types.d.ts +11 -1
  5. package/cli/cli.js +16 -2
  6. package/commands/doctor/doctor.js +5 -16
  7. package/commands/doctor/types.d.ts +2 -2
  8. package/commands/new/new.d.ts +2 -1
  9. package/commands/new/new.js +104 -18
  10. package/commands/new/types.d.ts +6 -0
  11. package/doctor/checkCorepack.d.ts +2 -0
  12. package/doctor/checkCorepack.js +24 -0
  13. package/doctor/checkGit.d.ts +2 -0
  14. package/doctor/checkGit.js +23 -0
  15. package/doctor/checkNodeVersion.d.ts +5 -0
  16. package/doctor/checkNodeVersion.js +24 -0
  17. package/doctor/checkYarn.d.ts +10 -0
  18. package/doctor/checkYarn.js +45 -0
  19. package/doctor/createDoctorReport.d.ts +2 -0
  20. package/doctor/createDoctorReport.js +17 -0
  21. package/doctor/index.d.ts +7 -0
  22. package/doctor/index.js +6 -0
  23. package/doctor/printDoctorReport.d.ts +2 -0
  24. package/doctor/printDoctorReport.js +42 -0
  25. package/doctor/types.d.ts +25 -0
  26. package/file-plan/createFilePlan.d.ts +4 -0
  27. package/file-plan/createFilePlan.js +29 -0
  28. package/file-plan/index.d.ts +4 -0
  29. package/file-plan/index.js +3 -0
  30. package/file-plan/printFilePlan.d.ts +2 -0
  31. package/file-plan/printFilePlan.js +44 -0
  32. package/file-plan/types.d.ts +12 -0
  33. package/file-plan/writeFilePlan.d.ts +2 -0
  34. package/file-plan/writeFilePlan.js +12 -0
  35. package/index.d.ts +4 -1
  36. package/index.js +4 -1
  37. package/package.json +181 -1
  38. package/presets/createProjectFiles.d.ts +2 -0
  39. package/presets/createProjectFiles.js +52 -0
  40. package/presets/index.d.ts +2 -0
  41. package/presets/index.js +1 -0
  42. package/presets/types.d.ts +3 -0
  43. package/shared/commandExists.d.ts +2 -0
  44. package/shared/commandExists.js +10 -0
  45. package/shared/execCommand.d.ts +2 -0
  46. package/shared/execCommand.js +7 -0
  47. package/shared/fileExists.d.ts +2 -0
  48. package/shared/fileExists.js +10 -0
  49. package/shared/index.d.ts +5 -0
  50. package/shared/index.js +4 -0
  51. package/shared/semver.d.ts +1 -0
  52. package/shared/semver.js +4 -0
  53. package/shared/types.d.ts +5 -0
@@ -0,0 +1,45 @@
1
+ import { execCommand as execCommandDefault, getMajorVersion } from '../shared/index.js';
2
+ export const yarnStableFix = {
3
+ label: 'Enable Yarn using Corepack',
4
+ command: 'corepack enable\ncorepack prepare yarn@stable --activate',
5
+ safeToRun: true,
6
+ };
7
+ export const checkYarn = async ({ execCommand = execCommandDefault, minimumMajor = 4, version, } = {}) => {
8
+ let currentVersion = version;
9
+ try {
10
+ currentVersion ??= await execCommand('yarn', ['--version']);
11
+ }
12
+ catch {
13
+ return {
14
+ name: 'yarn',
15
+ label: 'Yarn',
16
+ group: 'Package manager',
17
+ level: 'warning',
18
+ message: 'Yarn was not found',
19
+ detail: 'Vyriy uses Yarn 4 for generated projects.',
20
+ fix: yarnStableFix,
21
+ };
22
+ }
23
+ const normalizedVersion = currentVersion.trim();
24
+ const majorVersion = getMajorVersion(normalizedVersion);
25
+ if (majorVersion !== undefined && majorVersion >= minimumMajor) {
26
+ return {
27
+ name: 'yarn',
28
+ label: 'Yarn',
29
+ group: 'Package manager',
30
+ level: 'ok',
31
+ version: normalizedVersion,
32
+ message: `Yarn ${normalizedVersion}`,
33
+ };
34
+ }
35
+ return {
36
+ name: 'yarn',
37
+ label: 'Yarn',
38
+ group: 'Package manager',
39
+ level: 'warning',
40
+ version: normalizedVersion,
41
+ message: `Yarn ${normalizedVersion} detected`,
42
+ detail: `Vyriy recommends Yarn ${minimumMajor}.`,
43
+ fix: yarnStableFix,
44
+ };
45
+ };
@@ -0,0 +1,2 @@
1
+ import { DoctorCheckOptions, DoctorReport } from './types.js';
2
+ export declare const createDoctorReport: (options?: DoctorCheckOptions) => Promise<DoctorReport>;
@@ -0,0 +1,17 @@
1
+ import { checkCorepack } from './checkCorepack.js';
2
+ import { checkGit } from './checkGit.js';
3
+ import { checkNodeVersion } from './checkNodeVersion.js';
4
+ import { checkYarn } from './checkYarn.js';
5
+ export const createDoctorReport = async (options = {}) => {
6
+ const checks = [
7
+ checkNodeVersion(),
8
+ await checkCorepack(options),
9
+ await checkYarn(options),
10
+ await checkGit(options),
11
+ ];
12
+ return {
13
+ checks,
14
+ hasErrors: checks.some((check) => check.level === 'error'),
15
+ hasWarnings: checks.some((check) => check.level === 'warning'),
16
+ };
17
+ };
@@ -0,0 +1,7 @@
1
+ export * from './checkCorepack.js';
2
+ export * from './checkGit.js';
3
+ export * from './checkNodeVersion.js';
4
+ export * from './checkYarn.js';
5
+ export * from './createDoctorReport.js';
6
+ export * from './printDoctorReport.js';
7
+ export type * from './types.js';
@@ -0,0 +1,6 @@
1
+ export * from './checkCorepack.js';
2
+ export * from './checkGit.js';
3
+ export * from './checkNodeVersion.js';
4
+ export * from './checkYarn.js';
5
+ export * from './createDoctorReport.js';
6
+ export * from './printDoctorReport.js';
@@ -0,0 +1,2 @@
1
+ import { DoctorReport } from './types.js';
2
+ export declare const printDoctorReport: (report: DoctorReport) => string;
@@ -0,0 +1,42 @@
1
+ const statusMark = {
2
+ ok: '✓',
3
+ warning: '!',
4
+ error: '✘',
5
+ };
6
+ const groups = ['Runtime', 'Package manager', 'Git'];
7
+ export const printDoctorReport = (report) => {
8
+ const lines = ['Vyriy Doctor', ''];
9
+ for (const group of groups) {
10
+ const checks = report.checks.filter((check) => check.group === group);
11
+ if (checks.length === 0) {
12
+ continue;
13
+ }
14
+ lines.push(`${group}:`);
15
+ for (const check of checks) {
16
+ lines.push(` ${statusMark[check.level]} ${check.message}`);
17
+ if (check.detail) {
18
+ lines.push(` ${check.detail}`);
19
+ }
20
+ }
21
+ lines.push('');
22
+ }
23
+ const fixes = report.checks.flatMap((check) => (check.fix ? [check.fix] : []));
24
+ if (fixes.length > 0) {
25
+ lines.push('Suggested fix:');
26
+ for (const fix of fixes) {
27
+ lines.push(` ${fix.command.replaceAll('\n', '\n ')}`);
28
+ }
29
+ lines.push('');
30
+ }
31
+ lines.push('Result:');
32
+ if (report.hasErrors) {
33
+ lines.push(' Environment is not usable.');
34
+ }
35
+ else if (report.hasWarnings) {
36
+ lines.push(' Environment is usable, but warnings should be reviewed.');
37
+ }
38
+ else {
39
+ lines.push(' Environment is usable.');
40
+ }
41
+ return lines.join('\n');
42
+ };
@@ -0,0 +1,25 @@
1
+ import { ExecCommand } from '../shared/index.js';
2
+ export type DoctorCheckLevel = 'ok' | 'warning' | 'error';
3
+ export type DoctorFix = {
4
+ readonly label: string;
5
+ readonly command: string;
6
+ readonly safeToRun: boolean;
7
+ };
8
+ export type DoctorCheck = {
9
+ readonly name: 'node' | 'corepack' | 'yarn' | 'git';
10
+ readonly label: string;
11
+ readonly group: 'Runtime' | 'Package manager' | 'Git';
12
+ readonly level: DoctorCheckLevel;
13
+ readonly message: string;
14
+ readonly detail?: string;
15
+ readonly version?: string;
16
+ readonly fix?: DoctorFix;
17
+ };
18
+ export type DoctorReport = {
19
+ readonly checks: readonly DoctorCheck[];
20
+ readonly hasErrors: boolean;
21
+ readonly hasWarnings: boolean;
22
+ };
23
+ export type DoctorCheckOptions = {
24
+ readonly execCommand?: ExecCommand;
25
+ };
@@ -0,0 +1,4 @@
1
+ import { FilePlanItem, FilePlanOptions, ProjectFile } from './types.js';
2
+ export declare const createFilePlan: (targetDirectory: string, files: readonly ProjectFile[], options?: FilePlanOptions & {
3
+ readonly fileExists?: (filePath: string) => Promise<boolean>;
4
+ }) => Promise<FilePlanItem[]>;
@@ -0,0 +1,29 @@
1
+ import path from 'node:path';
2
+ import { fileExists as fileExistsDefault } from '../shared/index.js';
3
+ const getFilePlanStatus = (exists, { overwrite, skipExisting, }) => {
4
+ if (!exists) {
5
+ return 'create';
6
+ }
7
+ if (overwrite) {
8
+ return 'overwrite';
9
+ }
10
+ if (skipExisting) {
11
+ return 'skip';
12
+ }
13
+ return 'conflict';
14
+ };
15
+ export const createFilePlan = async (targetDirectory, files, options = {}) => {
16
+ const { fileExists = fileExistsDefault, overwrite = false, skipExisting = false } = options;
17
+ if (overwrite && skipExisting) {
18
+ throw new Error('Cannot use overwrite and skipExisting together.');
19
+ }
20
+ const plan = [];
21
+ for (const file of files) {
22
+ const exists = await fileExists(path.join(targetDirectory, file.path));
23
+ plan.push({
24
+ ...file,
25
+ status: getFilePlanStatus(exists, { overwrite, skipExisting }),
26
+ });
27
+ }
28
+ return plan;
29
+ };
@@ -0,0 +1,4 @@
1
+ export * from './createFilePlan.js';
2
+ export * from './printFilePlan.js';
3
+ export * from './writeFilePlan.js';
4
+ export type * from './types.js';
@@ -0,0 +1,3 @@
1
+ export * from './createFilePlan.js';
2
+ export * from './printFilePlan.js';
3
+ export * from './writeFilePlan.js';
@@ -0,0 +1,2 @@
1
+ import { FilePlanItem } from './types.js';
2
+ export declare const printFilePlan: (plan: readonly FilePlanItem[]) => string;
@@ -0,0 +1,44 @@
1
+ const sections = [
2
+ [
3
+ 'create',
4
+ 'CREATE',
5
+ '+',
6
+ 'to create',
7
+ ],
8
+ [
9
+ 'overwrite',
10
+ 'OVERWRITE',
11
+ '~',
12
+ 'to overwrite',
13
+ ],
14
+ [
15
+ 'skip',
16
+ 'SKIP',
17
+ '-',
18
+ 'to skip',
19
+ ],
20
+ [
21
+ 'conflict',
22
+ 'CONFLICT',
23
+ '!',
24
+ 'conflict',
25
+ ],
26
+ ];
27
+ export const printFilePlan = (plan) => {
28
+ const lines = ['File plan:', ''];
29
+ for (const [status, title, marker] of sections) {
30
+ const items = plan.filter((item) => item.status === status);
31
+ if (items.length === 0) {
32
+ continue;
33
+ }
34
+ lines.push(title, ...items.map((item) => ` ${marker} ${item.path}`), '');
35
+ }
36
+ lines.push('Summary:');
37
+ for (const [status, , , label,] of sections) {
38
+ const count = plan.filter((item) => item.status === status).length;
39
+ if (count > 0) {
40
+ lines.push(` ${count} ${label}${status === 'conflict' && count !== 1 ? 's' : ''}`);
41
+ }
42
+ }
43
+ return lines.join('\n');
44
+ };
@@ -0,0 +1,12 @@
1
+ export type FilePlanItemStatus = 'create' | 'overwrite' | 'skip' | 'conflict';
2
+ export type ProjectFile = {
3
+ readonly path: string;
4
+ readonly content: string;
5
+ };
6
+ export type FilePlanItem = ProjectFile & {
7
+ readonly status: FilePlanItemStatus;
8
+ };
9
+ export type FilePlanOptions = {
10
+ readonly overwrite?: boolean;
11
+ readonly skipExisting?: boolean;
12
+ };
@@ -0,0 +1,2 @@
1
+ import { FilePlanItem } from './types.js';
2
+ export declare const writeFilePlan: (targetDirectory: string, plan: readonly FilePlanItem[]) => Promise<void>;
@@ -0,0 +1,12 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ export const writeFilePlan = async (targetDirectory, plan) => {
4
+ for (const item of plan) {
5
+ if (item.status === 'skip' || item.status === 'conflict') {
6
+ continue;
7
+ }
8
+ const absolutePath = path.join(targetDirectory, item.path);
9
+ await fs.mkdir(path.dirname(absolutePath), { recursive: true });
10
+ await fs.writeFile(absolutePath, item.content, 'utf8');
11
+ }
12
+ };
package/index.d.ts CHANGED
@@ -2,7 +2,10 @@ export * from './cli/index.js';
2
2
  export * from './commands/doctor/index.js';
3
3
  export * from './commands/init/index.js';
4
4
  export * from './commands/new/index.js';
5
- export * from './checks/node/index.js';
6
5
  export * from './checks/yarn/index.js';
6
+ export * from './doctor/index.js';
7
+ export * from './file-plan/index.js';
8
+ export * from './presets/index.js';
7
9
  export * from './project-plan/index.js';
8
10
  export * from './prompts/project-plan/index.js';
11
+ export * from './shared/index.js';
package/index.js CHANGED
@@ -2,7 +2,10 @@ export * from './cli/index.js';
2
2
  export * from './commands/doctor/index.js';
3
3
  export * from './commands/init/index.js';
4
4
  export * from './commands/new/index.js';
5
- export * from './checks/node/index.js';
6
5
  export * from './checks/yarn/index.js';
6
+ export * from './doctor/index.js';
7
+ export * from './file-plan/index.js';
8
+ export * from './presets/index.js';
7
9
  export * from './project-plan/index.js';
8
10
  export * from './prompts/project-plan/index.js';
11
+ export * from './shared/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vyriy",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "Interactive project master for calm cloud-ready applications.",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -169,6 +169,116 @@
169
169
  "import": "./commands/new/new.js",
170
170
  "default": "./commands/new/new.js"
171
171
  },
172
+ "./doctor/checkCorepack": {
173
+ "types": "./doctor/checkCorepack.d.ts",
174
+ "import": "./doctor/checkCorepack.js",
175
+ "default": "./doctor/checkCorepack.js"
176
+ },
177
+ "./doctor/checkCorepack.js": {
178
+ "types": "./doctor/checkCorepack.d.ts",
179
+ "import": "./doctor/checkCorepack.js",
180
+ "default": "./doctor/checkCorepack.js"
181
+ },
182
+ "./doctor/checkGit": {
183
+ "types": "./doctor/checkGit.d.ts",
184
+ "import": "./doctor/checkGit.js",
185
+ "default": "./doctor/checkGit.js"
186
+ },
187
+ "./doctor/checkGit.js": {
188
+ "types": "./doctor/checkGit.d.ts",
189
+ "import": "./doctor/checkGit.js",
190
+ "default": "./doctor/checkGit.js"
191
+ },
192
+ "./doctor/checkNodeVersion": {
193
+ "types": "./doctor/checkNodeVersion.d.ts",
194
+ "import": "./doctor/checkNodeVersion.js",
195
+ "default": "./doctor/checkNodeVersion.js"
196
+ },
197
+ "./doctor/checkNodeVersion.js": {
198
+ "types": "./doctor/checkNodeVersion.d.ts",
199
+ "import": "./doctor/checkNodeVersion.js",
200
+ "default": "./doctor/checkNodeVersion.js"
201
+ },
202
+ "./doctor/checkYarn": {
203
+ "types": "./doctor/checkYarn.d.ts",
204
+ "import": "./doctor/checkYarn.js",
205
+ "default": "./doctor/checkYarn.js"
206
+ },
207
+ "./doctor/checkYarn.js": {
208
+ "types": "./doctor/checkYarn.d.ts",
209
+ "import": "./doctor/checkYarn.js",
210
+ "default": "./doctor/checkYarn.js"
211
+ },
212
+ "./doctor/createDoctorReport": {
213
+ "types": "./doctor/createDoctorReport.d.ts",
214
+ "import": "./doctor/createDoctorReport.js",
215
+ "default": "./doctor/createDoctorReport.js"
216
+ },
217
+ "./doctor/createDoctorReport.js": {
218
+ "types": "./doctor/createDoctorReport.d.ts",
219
+ "import": "./doctor/createDoctorReport.js",
220
+ "default": "./doctor/createDoctorReport.js"
221
+ },
222
+ "./doctor/index": {
223
+ "types": "./doctor/index.d.ts",
224
+ "import": "./doctor/index.js",
225
+ "default": "./doctor/index.js"
226
+ },
227
+ "./doctor/index.js": {
228
+ "types": "./doctor/index.d.ts",
229
+ "import": "./doctor/index.js",
230
+ "default": "./doctor/index.js"
231
+ },
232
+ "./doctor/printDoctorReport": {
233
+ "types": "./doctor/printDoctorReport.d.ts",
234
+ "import": "./doctor/printDoctorReport.js",
235
+ "default": "./doctor/printDoctorReport.js"
236
+ },
237
+ "./doctor/printDoctorReport.js": {
238
+ "types": "./doctor/printDoctorReport.d.ts",
239
+ "import": "./doctor/printDoctorReport.js",
240
+ "default": "./doctor/printDoctorReport.js"
241
+ },
242
+ "./file-plan/createFilePlan": {
243
+ "types": "./file-plan/createFilePlan.d.ts",
244
+ "import": "./file-plan/createFilePlan.js",
245
+ "default": "./file-plan/createFilePlan.js"
246
+ },
247
+ "./file-plan/createFilePlan.js": {
248
+ "types": "./file-plan/createFilePlan.d.ts",
249
+ "import": "./file-plan/createFilePlan.js",
250
+ "default": "./file-plan/createFilePlan.js"
251
+ },
252
+ "./file-plan/index": {
253
+ "types": "./file-plan/index.d.ts",
254
+ "import": "./file-plan/index.js",
255
+ "default": "./file-plan/index.js"
256
+ },
257
+ "./file-plan/index.js": {
258
+ "types": "./file-plan/index.d.ts",
259
+ "import": "./file-plan/index.js",
260
+ "default": "./file-plan/index.js"
261
+ },
262
+ "./file-plan/printFilePlan": {
263
+ "types": "./file-plan/printFilePlan.d.ts",
264
+ "import": "./file-plan/printFilePlan.js",
265
+ "default": "./file-plan/printFilePlan.js"
266
+ },
267
+ "./file-plan/printFilePlan.js": {
268
+ "types": "./file-plan/printFilePlan.d.ts",
269
+ "import": "./file-plan/printFilePlan.js",
270
+ "default": "./file-plan/printFilePlan.js"
271
+ },
272
+ "./file-plan/writeFilePlan": {
273
+ "types": "./file-plan/writeFilePlan.d.ts",
274
+ "import": "./file-plan/writeFilePlan.js",
275
+ "default": "./file-plan/writeFilePlan.js"
276
+ },
277
+ "./file-plan/writeFilePlan.js": {
278
+ "types": "./file-plan/writeFilePlan.d.ts",
279
+ "import": "./file-plan/writeFilePlan.js",
280
+ "default": "./file-plan/writeFilePlan.js"
281
+ },
172
282
  "./index": {
173
283
  "types": "./index.d.ts",
174
284
  "import": "./index.js",
@@ -179,6 +289,26 @@
179
289
  "import": "./index.js",
180
290
  "default": "./index.js"
181
291
  },
292
+ "./presets/createProjectFiles": {
293
+ "types": "./presets/createProjectFiles.d.ts",
294
+ "import": "./presets/createProjectFiles.js",
295
+ "default": "./presets/createProjectFiles.js"
296
+ },
297
+ "./presets/createProjectFiles.js": {
298
+ "types": "./presets/createProjectFiles.d.ts",
299
+ "import": "./presets/createProjectFiles.js",
300
+ "default": "./presets/createProjectFiles.js"
301
+ },
302
+ "./presets/index": {
303
+ "types": "./presets/index.d.ts",
304
+ "import": "./presets/index.js",
305
+ "default": "./presets/index.js"
306
+ },
307
+ "./presets/index.js": {
308
+ "types": "./presets/index.d.ts",
309
+ "import": "./presets/index.js",
310
+ "default": "./presets/index.js"
311
+ },
182
312
  "./project-plan/api/api": {
183
313
  "types": "./project-plan/api/api.d.ts",
184
314
  "import": "./project-plan/api/api.js",
@@ -308,6 +438,56 @@
308
438
  "types": "./prompts/project-plan/project-plan.d.ts",
309
439
  "import": "./prompts/project-plan/project-plan.js",
310
440
  "default": "./prompts/project-plan/project-plan.js"
441
+ },
442
+ "./shared/commandExists": {
443
+ "types": "./shared/commandExists.d.ts",
444
+ "import": "./shared/commandExists.js",
445
+ "default": "./shared/commandExists.js"
446
+ },
447
+ "./shared/commandExists.js": {
448
+ "types": "./shared/commandExists.d.ts",
449
+ "import": "./shared/commandExists.js",
450
+ "default": "./shared/commandExists.js"
451
+ },
452
+ "./shared/execCommand": {
453
+ "types": "./shared/execCommand.d.ts",
454
+ "import": "./shared/execCommand.js",
455
+ "default": "./shared/execCommand.js"
456
+ },
457
+ "./shared/execCommand.js": {
458
+ "types": "./shared/execCommand.d.ts",
459
+ "import": "./shared/execCommand.js",
460
+ "default": "./shared/execCommand.js"
461
+ },
462
+ "./shared/fileExists": {
463
+ "types": "./shared/fileExists.d.ts",
464
+ "import": "./shared/fileExists.js",
465
+ "default": "./shared/fileExists.js"
466
+ },
467
+ "./shared/fileExists.js": {
468
+ "types": "./shared/fileExists.d.ts",
469
+ "import": "./shared/fileExists.js",
470
+ "default": "./shared/fileExists.js"
471
+ },
472
+ "./shared/index": {
473
+ "types": "./shared/index.d.ts",
474
+ "import": "./shared/index.js",
475
+ "default": "./shared/index.js"
476
+ },
477
+ "./shared/index.js": {
478
+ "types": "./shared/index.d.ts",
479
+ "import": "./shared/index.js",
480
+ "default": "./shared/index.js"
481
+ },
482
+ "./shared/semver": {
483
+ "types": "./shared/semver.d.ts",
484
+ "import": "./shared/semver.js",
485
+ "default": "./shared/semver.js"
486
+ },
487
+ "./shared/semver.js": {
488
+ "types": "./shared/semver.d.ts",
489
+ "import": "./shared/semver.js",
490
+ "default": "./shared/semver.js"
311
491
  }
312
492
  }
313
493
  }
@@ -0,0 +1,2 @@
1
+ import { CreateProjectFiles } from './types.js';
2
+ export declare const createProjectFiles: CreateProjectFiles;
@@ -0,0 +1,52 @@
1
+ const json = (value) => `${JSON.stringify(value, null, 2)}\n`;
2
+ const createPackageJson = ({ description, packageScope, projectName, }) => ({
3
+ path: 'package.json',
4
+ content: json({
5
+ name: `${packageScope}/${projectName}`,
6
+ version: '0.1.0',
7
+ description,
8
+ private: true,
9
+ type: 'module',
10
+ packageManager: 'yarn@4.14.1',
11
+ engines: {
12
+ node: '>=24.0.0',
13
+ },
14
+ scripts: {
15
+ build: 'tsc --pretty false',
16
+ test: 'jest --coverage=false',
17
+ lint: 'eslint .',
18
+ },
19
+ devDependencies: {},
20
+ }),
21
+ });
22
+ export const createProjectFiles = (plan) => [
23
+ createPackageJson(plan),
24
+ {
25
+ path: 'README.md',
26
+ content: `# ${plan.projectName}\n\n${plan.description}\n`,
27
+ },
28
+ {
29
+ path: 'AGENTS.md',
30
+ content: `# ${plan.projectName} Agent Context\n\nKeep changes scoped, explicit, and easy to validate.\n`,
31
+ },
32
+ {
33
+ path: '.editorconfig',
34
+ content: 'root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 2\n',
35
+ },
36
+ {
37
+ path: '.gitignore',
38
+ content: 'node_modules/\ndist/\ncoverage/\n.yarn/cache/\n.env\n',
39
+ },
40
+ {
41
+ path: 'src/index.ts',
42
+ content: "export type * from './types.js';\n",
43
+ },
44
+ {
45
+ path: 'src/index.test.ts',
46
+ content: "import { describe, expect, it } from '@jest/globals';\n\ndescribe('project', () => {\n it('has a test harness', () => {\n expect(true).toBe(true);\n });\n});\n",
47
+ },
48
+ {
49
+ path: 'src/types.ts',
50
+ content: 'export type ProjectName = string;\n',
51
+ },
52
+ ];
@@ -0,0 +1,2 @@
1
+ export * from './createProjectFiles.js';
2
+ export type * from './types.js';
@@ -0,0 +1 @@
1
+ export * from './createProjectFiles.js';
@@ -0,0 +1,3 @@
1
+ import { ProjectFile } from '../file-plan/index.js';
2
+ import { VyriyProjectPlan } from '../project-plan/index.js';
3
+ export type CreateProjectFiles = (plan: VyriyProjectPlan) => ProjectFile[];
@@ -0,0 +1,2 @@
1
+ import { CommandExists } from './types.js';
2
+ export declare const commandExists: CommandExists;
@@ -0,0 +1,10 @@
1
+ import { execCommand as execCommandDefault } from './execCommand.js';
2
+ export const commandExists = async (command, { execCommand = execCommandDefault } = {}) => {
3
+ try {
4
+ await execCommand(command, ['--version']);
5
+ return true;
6
+ }
7
+ catch {
8
+ return false;
9
+ }
10
+ };
@@ -0,0 +1,2 @@
1
+ import { ExecCommand } from './types.js';
2
+ export declare const execCommand: ExecCommand;
@@ -0,0 +1,7 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execFileAsync = promisify(execFile);
4
+ export const execCommand = async (command, args = []) => {
5
+ const { stdout } = await execFileAsync(command, args);
6
+ return stdout.trim();
7
+ };
@@ -0,0 +1,2 @@
1
+ import { FileExists } from './types.js';
2
+ export declare const fileExists: FileExists;
@@ -0,0 +1,10 @@
1
+ import fs from 'node:fs/promises';
2
+ export const fileExists = async (filePath) => {
3
+ try {
4
+ await fs.access(filePath);
5
+ return true;
6
+ }
7
+ catch {
8
+ return false;
9
+ }
10
+ };
@@ -0,0 +1,5 @@
1
+ export * from './commandExists.js';
2
+ export * from './execCommand.js';
3
+ export * from './fileExists.js';
4
+ export * from './semver.js';
5
+ export type * from './types.js';
@@ -0,0 +1,4 @@
1
+ export * from './commandExists.js';
2
+ export * from './execCommand.js';
3
+ export * from './fileExists.js';
4
+ export * from './semver.js';
@@ -0,0 +1 @@
1
+ export declare const getMajorVersion: (version: string) => number | undefined;
@@ -0,0 +1,4 @@
1
+ export const getMajorVersion = (version) => {
2
+ const majorVersion = /^v?(\d+)/.exec(version.trim())?.[1];
3
+ return majorVersion ? Number.parseInt(majorVersion, 10) : undefined;
4
+ };