mikoshi-construct 0.1.1 → 0.1.3
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 +52 -3
- package/dist/cli.js +103 -59
- package/package.json +18 -20
package/README.md
CHANGED
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
Bootstrap for AI-native software projects. Start with a proven engineering workflow instead of an
|
|
4
4
|
empty repository.
|
|
5
5
|
|
|
6
|
-
```
|
|
7
|
-
|
|
6
|
+
```bash
|
|
7
|
+
mkdir my-service && cd my-service
|
|
8
|
+
npx mikoshi-construct init # interactive: preset, agent, project name
|
|
9
|
+
pnpm install && pnpm run quality # green before you write a line
|
|
8
10
|
```
|
|
9
11
|
|
|
10
12
|
> **v0.1.** Presets `node-backend`, `node-frontend`, `node-library` and `monorepo`. Claude Code gets
|
|
@@ -34,6 +36,52 @@ An existing repository gets the policy, the harness tooling and the agent files,
|
|
|
34
36
|
code; its own `AGENTS.md`, `CLAUDE.md`, `package.json` and configs are merged or left alone, and
|
|
35
37
|
`init` says what still has to be wired by hand.
|
|
36
38
|
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
**A new project.** Name a preset and it writes everything:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
mkdir my-service && cd my-service
|
|
45
|
+
npx mikoshi-construct init --yes --preset node-backend
|
|
46
|
+
pnpm install && pnpm run quality
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**An existing repository.** Look before you write:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx mikoshi-construct init --preset monorepo --dry-run
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
~ package.json (merge)
|
|
57
|
+
= eslint.config.mjs — exists, review manually
|
|
58
|
+
+ architecture/principles.md
|
|
59
|
+
+ .claude/commands/construct-discover.md
|
|
60
|
+
|
|
61
|
+
Sample sources omitted: the directory is not empty. Discovery maps what is already here.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`+` creates a file that is not there. `~` merges into one that is, inside a
|
|
65
|
+
`construct:begin … construct:end` block or as a JSON merge where your values win. `=` leaves the file
|
|
66
|
+
alone and reports it. No example code lands in a repository that already has some, and there is no
|
|
67
|
+
`--force`.
|
|
68
|
+
|
|
69
|
+
**Cursor, or both agents.** The rules are written once and rendered for each:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx mikoshi-construct init --yes --preset node-frontend --ai both
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**Check a repository at any time.**
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx mikoshi-construct doctor # baseline intact, harness intact, markers filled
|
|
79
|
+
npx mikoshi-construct soulkill # what the detector sees; writes nothing
|
|
80
|
+
npx mikoshi-construct cost --last
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Every command, flag and exit code: [docs/cli.md](https://github.com/E1i/mikoshi-construct/blob/main/docs/cli.md).
|
|
84
|
+
|
|
37
85
|
## Three principles
|
|
38
86
|
|
|
39
87
|
1. **CLI detects facts. Agent interprets the system.** Everything that needs understanding of the
|
|
@@ -82,7 +130,8 @@ with a named check, not a second fix.
|
|
|
82
130
|
| `construct soulkill` | Print what the detector sees, write nothing (`--json`; aliases `inspect`, `capture`) |
|
|
83
131
|
| `construct cost` | Token usage of the `/implement` runs in this directory, per agent, billable and price-weighted (`--last`, `--json`) |
|
|
84
132
|
|
|
85
|
-
`--plain` turns off colours and lore for CI. `--johnny` — wake up, Netrunner.
|
|
133
|
+
`--plain` turns off colours and lore for CI. `--johnny` — wake up, Netrunner. The full reference,
|
|
134
|
+
with examples and exit codes, is in [docs/cli.md](https://github.com/E1i/mikoshi-construct/blob/main/docs/cli.md).
|
|
86
135
|
|
|
87
136
|
> If you already keep a user-level `implement` skill in `~/.claude/skills/`, it shadows the one the
|
|
88
137
|
> construct puts in `.claude/skills/implement/`; move yours aside to run the repository's ladder.
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import
|
|
4
|
+
import path14 from "path";
|
|
5
5
|
import process4 from "process";
|
|
6
6
|
import { isTTY } from "@clack/prompts";
|
|
7
7
|
import { defineCommand, runMain } from "citty";
|
|
@@ -269,11 +269,11 @@ function printDoctor(ui2, result) {
|
|
|
269
269
|
|
|
270
270
|
// src/commands/init.ts
|
|
271
271
|
import { mkdirSync as mkdirSync2 } from "fs";
|
|
272
|
-
import
|
|
272
|
+
import path13 from "path";
|
|
273
273
|
|
|
274
274
|
// src/detect/index.ts
|
|
275
|
-
import { existsSync as
|
|
276
|
-
import
|
|
275
|
+
import { existsSync as existsSync8 } from "fs";
|
|
276
|
+
import path8 from "path";
|
|
277
277
|
import process from "process";
|
|
278
278
|
|
|
279
279
|
// src/detect/existing.ts
|
|
@@ -314,65 +314,109 @@ function detectExisting(dir) {
|
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
// src/detect/layout.ts
|
|
317
|
-
import { existsSync as
|
|
317
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
|
|
318
|
+
import path6 from "path";
|
|
319
|
+
|
|
320
|
+
// src/detect/workspaces.ts
|
|
321
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
|
|
318
322
|
import path5 from "path";
|
|
319
|
-
var
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
323
|
+
var TOP_LEVEL_PACKAGES_KEY = /^packages:(.*)$/m;
|
|
324
|
+
var EMPTY_FLOW_SEQUENCE = /^\[\s*\]$/;
|
|
325
|
+
var BLOCK_SEQUENCE_ENTRY = /^[ \t]+-[ \t]*\S/;
|
|
326
|
+
function readIfPresent(file) {
|
|
327
|
+
if (!existsSync5(file))
|
|
328
|
+
return null;
|
|
329
|
+
try {
|
|
330
|
+
return readFileSync4(file, "utf8");
|
|
331
|
+
} catch {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function startsBlockSequence(rest) {
|
|
336
|
+
for (const line of rest.split("\n")) {
|
|
337
|
+
if (line.trim() === "" || line.trimStart().startsWith("#"))
|
|
338
|
+
continue;
|
|
339
|
+
return BLOCK_SEQUENCE_ENTRY.test(line);
|
|
340
|
+
}
|
|
341
|
+
return false;
|
|
342
|
+
}
|
|
343
|
+
function declaresPnpmPackages(dir) {
|
|
344
|
+
const content = readIfPresent(path5.join(dir, "pnpm-workspace.yaml"));
|
|
345
|
+
if (content == null)
|
|
346
|
+
return false;
|
|
347
|
+
const match = TOP_LEVEL_PACKAGES_KEY.exec(content);
|
|
348
|
+
if (match == null)
|
|
349
|
+
return false;
|
|
350
|
+
const inline = match[1].trim();
|
|
351
|
+
if (inline.startsWith("["))
|
|
352
|
+
return !EMPTY_FLOW_SEQUENCE.test(inline);
|
|
353
|
+
if (inline !== "")
|
|
354
|
+
return false;
|
|
355
|
+
return startsBlockSequence(content.slice(match.index + match[0].length));
|
|
324
356
|
}
|
|
325
|
-
function
|
|
326
|
-
const
|
|
327
|
-
if (
|
|
357
|
+
function declaresNpmWorkspaces(dir) {
|
|
358
|
+
const content = readIfPresent(path5.join(dir, "package.json"));
|
|
359
|
+
if (content == null)
|
|
328
360
|
return false;
|
|
361
|
+
let workspaces;
|
|
329
362
|
try {
|
|
330
|
-
|
|
331
|
-
return parsed.workspaces != null;
|
|
363
|
+
({ workspaces } = JSON.parse(content));
|
|
332
364
|
} catch {
|
|
333
365
|
return false;
|
|
334
366
|
}
|
|
367
|
+
if (Array.isArray(workspaces))
|
|
368
|
+
return workspaces.length > 0;
|
|
369
|
+
const packages = workspaces?.packages;
|
|
370
|
+
return Array.isArray(packages) && packages.length > 0;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/detect/layout.ts
|
|
374
|
+
var IGNORED_ENTRIES = /* @__PURE__ */ new Set([".git", ".DS_Store", ".gitignore", ".gitattributes", "LICENSE", "README.md", ".idea", ".vscode"]);
|
|
375
|
+
function isEmptyDir(dir) {
|
|
376
|
+
if (!existsSync6(dir))
|
|
377
|
+
return true;
|
|
378
|
+
return readdirSync4(dir).every((entry) => IGNORED_ENTRIES.has(entry));
|
|
335
379
|
}
|
|
336
380
|
function detectMonorepoTools(dir) {
|
|
337
381
|
const tools = [];
|
|
338
|
-
if (
|
|
382
|
+
if (declaresPnpmPackages(dir))
|
|
339
383
|
tools.push("pnpm-workspace");
|
|
340
|
-
if (
|
|
384
|
+
if (declaresNpmWorkspaces(dir))
|
|
341
385
|
tools.push("npm-workspaces");
|
|
342
|
-
if (
|
|
386
|
+
if (existsSync6(path6.join(dir, "turbo.json")))
|
|
343
387
|
tools.push("turbo");
|
|
344
|
-
if (
|
|
388
|
+
if (existsSync6(path6.join(dir, "nx.json")))
|
|
345
389
|
tools.push("nx");
|
|
346
390
|
return tools;
|
|
347
391
|
}
|
|
348
392
|
function detectWorkspaceDirs(dir) {
|
|
349
|
-
return ["apps", "packages", "libs", "services"].filter((name) =>
|
|
393
|
+
return ["apps", "packages", "libs", "services"].filter((name) => existsSync6(path6.join(dir, name)) && statSync2(path6.join(dir, name)).isDirectory());
|
|
350
394
|
}
|
|
351
395
|
function packageName(dir) {
|
|
352
396
|
try {
|
|
353
|
-
const parsed = JSON.parse(
|
|
397
|
+
const parsed = JSON.parse(readFileSync5(path6.join(dir, "package.json"), "utf8"));
|
|
354
398
|
return typeof parsed.name === "string" && parsed.name !== "" ? parsed.name : null;
|
|
355
399
|
} catch {
|
|
356
400
|
return null;
|
|
357
401
|
}
|
|
358
402
|
}
|
|
359
403
|
function detectWorkspacePackages(root, workspaceDirs) {
|
|
360
|
-
return workspaceDirs.flatMap((parent) => readdirSync4(
|
|
404
|
+
return workspaceDirs.flatMap((parent) => readdirSync4(path6.join(root, parent)).sort().map((entry) => `${parent}/${entry}`).filter((dir) => existsSync6(path6.join(root, dir, "package.json"))).map((dir) => ({ dir, name: packageName(path6.join(root, dir)) ?? dir.split("/").at(-1) ?? dir })));
|
|
361
405
|
}
|
|
362
406
|
function detectLayout(dir, monorepoTools, workspaceDirs, hasSrc) {
|
|
363
407
|
if (isEmptyDir(dir))
|
|
364
408
|
return "empty";
|
|
365
409
|
if (monorepoTools.length > 0 || workspaceDirs.length > 0)
|
|
366
410
|
return "monorepo";
|
|
367
|
-
if (hasSrc ||
|
|
411
|
+
if (hasSrc || existsSync6(path6.join(dir, "package.json")))
|
|
368
412
|
return "single";
|
|
369
413
|
return "unknown";
|
|
370
414
|
}
|
|
371
415
|
|
|
372
416
|
// src/detect/package-manager.ts
|
|
373
417
|
import { execFileSync } from "child_process";
|
|
374
|
-
import { existsSync as
|
|
375
|
-
import
|
|
418
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
|
|
419
|
+
import path7 from "path";
|
|
376
420
|
var LOCKFILES = [
|
|
377
421
|
["pnpm-lock.yaml", "pnpm"],
|
|
378
422
|
["bun.lockb", "bun"],
|
|
@@ -381,11 +425,11 @@ var LOCKFILES = [
|
|
|
381
425
|
["package-lock.json", "npm"]
|
|
382
426
|
];
|
|
383
427
|
function fromPackageManagerField(dir) {
|
|
384
|
-
const manifest =
|
|
385
|
-
if (!
|
|
428
|
+
const manifest = path7.join(dir, "package.json");
|
|
429
|
+
if (!existsSync7(manifest))
|
|
386
430
|
return null;
|
|
387
431
|
try {
|
|
388
|
-
const parsed = JSON.parse(
|
|
432
|
+
const parsed = JSON.parse(readFileSync6(manifest, "utf8"));
|
|
389
433
|
const name = parsed.packageManager?.split("@")[0];
|
|
390
434
|
return name === "pnpm" || name === "npm" || name === "yarn" || name === "bun" ? name : null;
|
|
391
435
|
} catch {
|
|
@@ -397,10 +441,10 @@ function detectPackageManager(dir) {
|
|
|
397
441
|
if (declared != null)
|
|
398
442
|
return declared;
|
|
399
443
|
for (const [lockfile, manager] of LOCKFILES) {
|
|
400
|
-
if (
|
|
444
|
+
if (existsSync7(path7.join(dir, lockfile)))
|
|
401
445
|
return manager;
|
|
402
446
|
}
|
|
403
|
-
return
|
|
447
|
+
return existsSync7(path7.join(dir, "package.json")) ? "npm" : "none";
|
|
404
448
|
}
|
|
405
449
|
var pnpmVersionCache;
|
|
406
450
|
function detectPnpmVersion() {
|
|
@@ -416,10 +460,10 @@ function detectPnpmVersion() {
|
|
|
416
460
|
|
|
417
461
|
// src/detect/index.ts
|
|
418
462
|
function detect(dir) {
|
|
419
|
-
const root =
|
|
463
|
+
const root = path8.resolve(dir);
|
|
420
464
|
const monorepoTools = detectMonorepoTools(root);
|
|
421
465
|
const workspaceDirs = detectWorkspaceDirs(root);
|
|
422
|
-
const hasSrc =
|
|
466
|
+
const hasSrc = existsSync8(path8.join(root, "src"));
|
|
423
467
|
return {
|
|
424
468
|
dir: root,
|
|
425
469
|
packageManager: detectPackageManager(root),
|
|
@@ -436,14 +480,14 @@ function detect(dir) {
|
|
|
436
480
|
|
|
437
481
|
// src/materialize/apply.ts
|
|
438
482
|
import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
|
|
439
|
-
import
|
|
483
|
+
import path9 from "path";
|
|
440
484
|
function applyPlan(root, ops) {
|
|
441
485
|
const written = [];
|
|
442
486
|
for (const op of ops) {
|
|
443
487
|
if (op.action === "skip")
|
|
444
488
|
continue;
|
|
445
|
-
const absolute =
|
|
446
|
-
mkdirSync(
|
|
489
|
+
const absolute = path9.join(root, op.target);
|
|
490
|
+
mkdirSync(path9.dirname(absolute), { recursive: true });
|
|
447
491
|
writeFileSync2(absolute, op.content);
|
|
448
492
|
written.push(op);
|
|
449
493
|
}
|
|
@@ -451,8 +495,8 @@ function applyPlan(root, ops) {
|
|
|
451
495
|
}
|
|
452
496
|
|
|
453
497
|
// src/materialize/plan.ts
|
|
454
|
-
import { existsSync as
|
|
455
|
-
import
|
|
498
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
|
|
499
|
+
import path11 from "path";
|
|
456
500
|
|
|
457
501
|
// src/materialize/rules.ts
|
|
458
502
|
var CLAUDE_RULES_DIR = ".claude/rules/";
|
|
@@ -614,20 +658,20 @@ ${end}
|
|
|
614
658
|
}
|
|
615
659
|
|
|
616
660
|
// src/materialize/templates.ts
|
|
617
|
-
import { existsSync as
|
|
618
|
-
import
|
|
661
|
+
import { existsSync as existsSync9, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
|
|
662
|
+
import path10 from "path";
|
|
619
663
|
import { fileURLToPath } from "url";
|
|
620
|
-
var HERE =
|
|
664
|
+
var HERE = path10.dirname(fileURLToPath(import.meta.url));
|
|
621
665
|
function templatesRoot() {
|
|
622
|
-
const candidates = [
|
|
623
|
-
const found = candidates.find((candidate) =>
|
|
666
|
+
const candidates = [path10.resolve(HERE, "../templates"), path10.resolve(HERE, "../../templates")];
|
|
667
|
+
const found = candidates.find((candidate) => existsSync9(candidate));
|
|
624
668
|
if (found == null)
|
|
625
669
|
throw new Error(`templates directory not found next to ${HERE}`);
|
|
626
670
|
return found;
|
|
627
671
|
}
|
|
628
672
|
var EXISTING_SUFFIX = ".existing.eta";
|
|
629
673
|
function toTargetPath(relative) {
|
|
630
|
-
const segments = relative.split(
|
|
674
|
+
const segments = relative.split(path10.sep).map((segment) => segment.startsWith("_") ? `.${segment.slice(1)}` : segment);
|
|
631
675
|
const joined = segments.join("/");
|
|
632
676
|
if (joined.endsWith(EXISTING_SUFFIX))
|
|
633
677
|
return { target: joined.slice(0, -EXISTING_SUFFIX.length), rendered: true, variant: "existing" };
|
|
@@ -635,22 +679,22 @@ function toTargetPath(relative) {
|
|
|
635
679
|
}
|
|
636
680
|
function walk(root, current, files) {
|
|
637
681
|
for (const entry of readdirSync5(current).sort()) {
|
|
638
|
-
const absolute =
|
|
682
|
+
const absolute = path10.join(current, entry);
|
|
639
683
|
if (statSync3(absolute).isDirectory())
|
|
640
684
|
walk(root, absolute, files);
|
|
641
685
|
else if (entry !== ".DS_Store")
|
|
642
|
-
files.push(
|
|
686
|
+
files.push(path10.relative(root, absolute));
|
|
643
687
|
}
|
|
644
688
|
}
|
|
645
689
|
function listTemplateFiles(group) {
|
|
646
|
-
const root =
|
|
647
|
-
if (!
|
|
690
|
+
const root = path10.join(templatesRoot(), group);
|
|
691
|
+
if (!existsSync9(root))
|
|
648
692
|
throw new Error(`template group "${group}" does not exist`);
|
|
649
693
|
const files = [];
|
|
650
694
|
walk(root, root, files);
|
|
651
695
|
return files.map((relative) => {
|
|
652
696
|
const { target, rendered, variant } = toTargetPath(relative);
|
|
653
|
-
return { group, source:
|
|
697
|
+
return { group, source: path10.join(root, relative), target, rendered, variant };
|
|
654
698
|
});
|
|
655
699
|
}
|
|
656
700
|
var BLOCK = /^[ \t]*\{\{#(if|unless) (\w+)\}\}[ \t]*\n([\s\S]*?)^[ \t]*\{\{\/\1\}\}[ \t]*\n/gm;
|
|
@@ -677,7 +721,7 @@ function mountTarget(mount, target) {
|
|
|
677
721
|
return mount.into == null || mount.into === "." ? target : `${mount.into.replace(/\/$/, "")}/${target}`;
|
|
678
722
|
}
|
|
679
723
|
function readTemplate(source, rendered, vars) {
|
|
680
|
-
const raw =
|
|
724
|
+
const raw = readFileSync7(source, "utf8");
|
|
681
725
|
return rendered ? render(raw, vars) : raw;
|
|
682
726
|
}
|
|
683
727
|
var SORTED_SECTIONS = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
|
@@ -735,12 +779,12 @@ function layerJson(earlier, later) {
|
|
|
735
779
|
var NOT_ADDED_TO_EXISTING_MANIFEST = ["version"];
|
|
736
780
|
function planOne(root, target, content, conflicts, existingVariant) {
|
|
737
781
|
const strategy = strategyFor(target);
|
|
738
|
-
const absolute =
|
|
739
|
-
const exists =
|
|
782
|
+
const absolute = path11.join(root, target);
|
|
783
|
+
const exists = existsSync10(absolute);
|
|
740
784
|
if (!exists)
|
|
741
785
|
return { target, strategy, action: "create", content: strategy === "append-block" ? appendBlock("", content, target) : content };
|
|
742
786
|
if (strategy === "merge-json") {
|
|
743
|
-
const existing = JSON.parse(
|
|
787
|
+
const existing = JSON.parse(readFileSync7(absolute, "utf8"));
|
|
744
788
|
const incoming = JSON.parse(content);
|
|
745
789
|
for (const key of NOT_ADDED_TO_EXISTING_MANIFEST)
|
|
746
790
|
delete incoming[key];
|
|
@@ -751,7 +795,7 @@ function planOne(root, target, content, conflicts, existingVariant) {
|
|
|
751
795
|
` };
|
|
752
796
|
}
|
|
753
797
|
if (strategy === "append-block") {
|
|
754
|
-
const existing =
|
|
798
|
+
const existing = readFileSync7(absolute, "utf8");
|
|
755
799
|
return { target, strategy, action: "append", content: appendBlock(existing, existingVariant ?? content, target) };
|
|
756
800
|
}
|
|
757
801
|
return { target, strategy, action: "skip", content, note: "exists, review manually" };
|
|
@@ -987,14 +1031,14 @@ function createClackPrompter(lore, streams = {}) {
|
|
|
987
1031
|
}
|
|
988
1032
|
|
|
989
1033
|
// src/version.ts
|
|
990
|
-
import { readFileSync as
|
|
991
|
-
import
|
|
1034
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
1035
|
+
import path12 from "path";
|
|
992
1036
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
993
|
-
var HERE2 =
|
|
1037
|
+
var HERE2 = path12.dirname(fileURLToPath2(import.meta.url));
|
|
994
1038
|
function readVersion() {
|
|
995
1039
|
for (const candidate of ["../package.json", "../../package.json"]) {
|
|
996
1040
|
try {
|
|
997
|
-
const parsed = JSON.parse(
|
|
1041
|
+
const parsed = JSON.parse(readFileSync8(path12.resolve(HERE2, candidate), "utf8"));
|
|
998
1042
|
if (parsed.name === "mikoshi-construct" && parsed.version != null)
|
|
999
1043
|
return parsed.version;
|
|
1000
1044
|
} catch {
|
|
@@ -1094,7 +1138,7 @@ async function askChoices(ui2, options, report, root, prompter) {
|
|
|
1094
1138
|
return { presetId, ai, projectName, review };
|
|
1095
1139
|
}
|
|
1096
1140
|
async function runInit(ui2, options, prompter) {
|
|
1097
|
-
const root =
|
|
1141
|
+
const root = path13.resolve(options.dir);
|
|
1098
1142
|
mkdirSync2(root, { recursive: true });
|
|
1099
1143
|
if (!options.yes && prompter == null) {
|
|
1100
1144
|
ui2.glitch(ui2.lore.needsTerminal);
|
|
@@ -1462,7 +1506,7 @@ var cost = defineCommand({
|
|
|
1462
1506
|
json: { type: "boolean", description: "Machine-readable report", default: false }
|
|
1463
1507
|
},
|
|
1464
1508
|
run({ args }) {
|
|
1465
|
-
const runs = collectWorkflowRuns(
|
|
1509
|
+
const runs = collectWorkflowRuns(path14.resolve(args.dir));
|
|
1466
1510
|
if (args.json) {
|
|
1467
1511
|
const selected = runs == null ? null : args.last ? runs.slice(-1) : runs;
|
|
1468
1512
|
process4.stdout.write(`${JSON.stringify(selected, null, 2)}
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mikoshi-construct",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
5
|
-
"packageManager": "pnpm@12.4.2",
|
|
4
|
+
"version": "0.1.3",
|
|
6
5
|
"description": "Bootstrap for AI-native software projects. Start with a proven engineering workflow instead of an empty repository.",
|
|
7
6
|
"author": "Eli Tabrisov",
|
|
8
7
|
"license": "MIT",
|
|
@@ -36,23 +35,6 @@
|
|
|
36
35
|
"engines": {
|
|
37
36
|
"node": ">=20"
|
|
38
37
|
},
|
|
39
|
-
"scripts": {
|
|
40
|
-
"build": "tsup",
|
|
41
|
-
"dev": "tsx src/cli.ts",
|
|
42
|
-
"lint": "eslint .",
|
|
43
|
-
"lint:fix": "eslint --fix .",
|
|
44
|
-
"typecheck": "tsc --noEmit",
|
|
45
|
-
"test": "vitest run",
|
|
46
|
-
"test:watch": "vitest",
|
|
47
|
-
"quality": "pnpm composition:check && pnpm lint && pnpm typecheck && pnpm test",
|
|
48
|
-
"prepublishOnly": "pnpm build",
|
|
49
|
-
"composition:render": "tsx scripts/composition/sync-docs.ts",
|
|
50
|
-
"composition:check": "tsx scripts/composition/check.ts",
|
|
51
|
-
"ci": "pnpm run quality",
|
|
52
|
-
"changeset": "changeset",
|
|
53
|
-
"version-packages": "changeset version",
|
|
54
|
-
"release": "pnpm build && npm publish --provenance --access public"
|
|
55
|
-
},
|
|
56
38
|
"dependencies": {
|
|
57
39
|
"@clack/prompts": "^1.8.0",
|
|
58
40
|
"citty": "^0.2.2",
|
|
@@ -69,5 +51,21 @@
|
|
|
69
51
|
"typescript": "^5.9.3",
|
|
70
52
|
"vitest": "^5.0.0",
|
|
71
53
|
"yaml": "^2.9.1"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsup",
|
|
57
|
+
"dev": "tsx src/cli.ts",
|
|
58
|
+
"lint": "eslint .",
|
|
59
|
+
"lint:fix": "eslint --fix .",
|
|
60
|
+
"typecheck": "tsc --noEmit",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"test:watch": "vitest",
|
|
63
|
+
"quality": "pnpm composition:check && pnpm lint && pnpm typecheck && pnpm test",
|
|
64
|
+
"composition:render": "tsx scripts/composition/sync-docs.ts",
|
|
65
|
+
"composition:check": "tsx scripts/composition/check.ts",
|
|
66
|
+
"ci": "pnpm run quality",
|
|
67
|
+
"changeset": "changeset",
|
|
68
|
+
"version-packages": "changeset version",
|
|
69
|
+
"release": "pnpm build && changeset publish"
|
|
72
70
|
}
|
|
73
|
-
}
|
|
71
|
+
}
|