create-chanom-app 0.4.3 → 0.5.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 +9 -3
- package/dist/index.js +220 -14
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -29,10 +29,11 @@ pnpm create chanom-app .
|
|
|
29
29
|
Run with no flags, the CLI walks you through:
|
|
30
30
|
|
|
31
31
|
1. **Project name** - the target directory (kebab-cased). Defaults to `my-chanom-app`.
|
|
32
|
-
2. **Initialize a git repository?** - `git init` plus an initial commit.
|
|
32
|
+
2. **Initialize a git repository?** - `git init` plus an initial commit (made after the install, so it includes the lockfile).
|
|
33
33
|
3. **Add commit hooks?** - husky + lint-staged + commitlint (only asked when git is enabled).
|
|
34
34
|
4. **Add agent coding standards?** - the `coding-standards` skill in `.agents/skills`, linked into `.claude/skills`.
|
|
35
|
-
5. **
|
|
35
|
+
5. **Add a GitHub Actions CI workflow?** - `.github/workflows/ci.yml`; if yes, pick its jobs from `lint`, `build`, `typecheck`, `test` (all checked by default).
|
|
36
|
+
6. **Install dependencies now?** - runs `<pm> install` after scaffolding.
|
|
36
37
|
|
|
37
38
|
Every prompt has a matching flag so you can pre-answer any of them (or all, with `--yes`).
|
|
38
39
|
|
|
@@ -46,13 +47,16 @@ Every prompt has a matching flag so you can pre-answer any of them (or all, with
|
|
|
46
47
|
| `--no-commit-hooks` | Skip the commit-hooks topping |
|
|
47
48
|
| `--agent-skills` | Add the coding-standards skill (default: yes) |
|
|
48
49
|
| `--no-agent-skills` | Skip the agent-skills topping |
|
|
50
|
+
| `--github-actions` | Add a GitHub Actions CI workflow (default: yes) |
|
|
51
|
+
| `--no-github-actions` | Skip the github-actions topping |
|
|
52
|
+
| `--ci-jobs <jobs>` | Comma-separated CI jobs, e.g. `lint,test` (default: all) |
|
|
49
53
|
| `--install` / `--no-install` | Install dependencies after scaffolding (default: install) |
|
|
50
54
|
| `--pm <pnpm\|npm\|yarn\|bun>` | Package manager to record (default: detected) |
|
|
51
55
|
| `-y`, `--yes` | Accept all defaults, no prompts (CI-friendly) |
|
|
52
56
|
| `--help` | Show help |
|
|
53
57
|
| `--version` | Show the version |
|
|
54
58
|
|
|
55
|
-
`--no-git --commit-hooks` is rejected: husky needs a repo to install into.
|
|
59
|
+
`--no-git --commit-hooks` is rejected: husky needs a repo to install into. `--no-github-actions --ci-jobs` is rejected too. `--ci-jobs` on its own turns the topping on.
|
|
56
60
|
|
|
57
61
|
The package manager is detected from the invoking user agent (falling back to `pnpm`); `--pm` overrides it and is recorded in the generated `package.json` `packageManager` field.
|
|
58
62
|
|
|
@@ -81,6 +85,8 @@ With the **commit-hooks** topping, it also adds husky, lint-staged, and commitli
|
|
|
81
85
|
|
|
82
86
|
With the **agent-skills** topping, it adds the `coding-standards` agent skill - a router `SKILL.md` plus TypeScript, React, and Vitest references written for exactly the stack scaffolded here. The real files land in `.agents/skills/coding-standards/` so any agent tool can read them, and `.claude/skills/coding-standards` is a relative symlink pointing at that directory rather than a second copy. It contributes no packages and no scripts, so skipping it leaves both directories out entirely.
|
|
83
87
|
|
|
88
|
+
With the **github-actions** topping, it adds `.github/workflows/ci.yml` - the same workflow `chanom brew` writes. It runs on every pull request with one independent job per check you picked. Each job sets up your package manager and the latest LTS Node, runs `<pm> install` with a frozen lockfile, then `<pm> run <job>`. The generated app ships all four scripts, so every job works as generated. When dependencies are installed during scaffolding, the lockfile lands in the initial commit; with `--no-install`, commit it after your first install - the frozen install fails without it.
|
|
89
|
+
|
|
84
90
|
## Development
|
|
85
91
|
|
|
86
92
|
```sh
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,134 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { Document, isMap, isNode, isScalar, isSeq, stringify } from "yaml";
|
|
2
3
|
import { Command, CommandExecutor, FileSystem, Path } from "@effect/platform";
|
|
3
4
|
import { Data, Effect, Layer, LogLevel, Logger, Option, Stream } from "effect";
|
|
4
5
|
import * as clack from "@clack/prompts";
|
|
5
6
|
import pc from "picocolors";
|
|
6
7
|
import { NodeContext, NodeRuntime } from "@effect/platform-node";
|
|
7
8
|
import { join } from "node:path";
|
|
9
|
+
// ../internal/src/domain/yaml.ts
|
|
10
|
+
/** Stringify options shared by every YAML file chanom generates, so they all read alike. */
|
|
11
|
+
const YAML_OPTIONS = {
|
|
12
|
+
singleQuote: true,
|
|
13
|
+
lineWidth: 0,
|
|
14
|
+
flowCollectionPadding: false
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Puts a blank line before every entry of a map or sequence node except the
|
|
18
|
+
* first. Mutates the node, so only call it on a `Document` built for output.
|
|
19
|
+
*/
|
|
20
|
+
function spaceItems(node) {
|
|
21
|
+
if (isMap(node)) {
|
|
22
|
+
for (const pair of node.items.slice(1)) if (isScalar(pair.key)) pair.key.spaceBefore = true;
|
|
23
|
+
} else if (isSeq(node)) {
|
|
24
|
+
for (const item of node.items.slice(1)) if (isNode(item)) item.spaceBefore = true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// ../internal/src/domain/github-actions.ts
|
|
28
|
+
/** Every job the workflow can contain, in the order they appear in the file. */
|
|
29
|
+
const CI_JOBS = [
|
|
30
|
+
"lint",
|
|
31
|
+
"build",
|
|
32
|
+
"typecheck",
|
|
33
|
+
"test"
|
|
34
|
+
];
|
|
35
|
+
const WORKFLOW_PATH = ".github/workflows/ci.yml";
|
|
36
|
+
const INSTALL_COMMAND = {
|
|
37
|
+
pnpm: "pnpm install --frozen-lockfile",
|
|
38
|
+
npm: "npm ci",
|
|
39
|
+
yarn: "yarn install --frozen-lockfile",
|
|
40
|
+
bun: "bun install --frozen-lockfile"
|
|
41
|
+
};
|
|
42
|
+
const JOB_STEP_NAME = {
|
|
43
|
+
lint: "Lint",
|
|
44
|
+
build: "Build",
|
|
45
|
+
typecheck: "Typecheck",
|
|
46
|
+
test: "Test"
|
|
47
|
+
};
|
|
48
|
+
function setupNode(cache, hasNvmrc) {
|
|
49
|
+
return {
|
|
50
|
+
uses: "actions/setup-node@v6",
|
|
51
|
+
with: {
|
|
52
|
+
...hasNvmrc ? { "node-version-file": ".nvmrc" } : { "node-version": "lts/*" },
|
|
53
|
+
cache
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** Steps that bring a job up to "dependencies installed". */
|
|
58
|
+
function setupSteps(options) {
|
|
59
|
+
const checkout = { uses: "actions/checkout@v7" };
|
|
60
|
+
const install = {
|
|
61
|
+
name: "Install dependencies",
|
|
62
|
+
run: INSTALL_COMMAND[options.pm]
|
|
63
|
+
};
|
|
64
|
+
switch (options.pm) {
|
|
65
|
+
case "pnpm": return [
|
|
66
|
+
checkout,
|
|
67
|
+
options.hasPackageManagerField ? { uses: "pnpm/action-setup@v6" } : {
|
|
68
|
+
uses: "pnpm/action-setup@v6",
|
|
69
|
+
with: { version: "latest" }
|
|
70
|
+
},
|
|
71
|
+
setupNode("pnpm", options.hasNvmrc),
|
|
72
|
+
install
|
|
73
|
+
];
|
|
74
|
+
case "npm": return [
|
|
75
|
+
checkout,
|
|
76
|
+
setupNode("npm", options.hasNvmrc),
|
|
77
|
+
install
|
|
78
|
+
];
|
|
79
|
+
case "yarn": return [
|
|
80
|
+
checkout,
|
|
81
|
+
{ run: "corepack enable" },
|
|
82
|
+
setupNode("yarn", options.hasNvmrc),
|
|
83
|
+
install
|
|
84
|
+
];
|
|
85
|
+
case "bun": return [
|
|
86
|
+
checkout,
|
|
87
|
+
{ uses: "oven-sh/setup-bun@v2" },
|
|
88
|
+
install
|
|
89
|
+
];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/** Selected jobs deduplicated and put in workflow order. */
|
|
93
|
+
function orderJobs(jobs) {
|
|
94
|
+
return CI_JOBS.filter((job) => jobs.includes(job));
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* `.github/workflows/ci.yml` contents: one independent job per selected check,
|
|
98
|
+
* each running `<pm> run <job>`. Shared so `chanom brew` and
|
|
99
|
+
* `create-chanom-app` emit byte-identical workflows.
|
|
100
|
+
*/
|
|
101
|
+
function workflowFile(options) {
|
|
102
|
+
const jobs = Object.fromEntries(orderJobs(options.jobs).map((job) => [job, {
|
|
103
|
+
"runs-on": "ubuntu-latest",
|
|
104
|
+
steps: [...setupSteps(options), {
|
|
105
|
+
name: JOB_STEP_NAME[job],
|
|
106
|
+
run: `${options.pm} run ${job}`
|
|
107
|
+
}]
|
|
108
|
+
}]));
|
|
109
|
+
const doc = new Document({
|
|
110
|
+
name: "CI",
|
|
111
|
+
on: { pull_request: { branches: ["*"] } },
|
|
112
|
+
concurrency: {
|
|
113
|
+
group: "${{ github.workflow }}-${{ github.ref }}",
|
|
114
|
+
"cancel-in-progress": true
|
|
115
|
+
},
|
|
116
|
+
jobs
|
|
117
|
+
});
|
|
118
|
+
spaceItems(doc.contents);
|
|
119
|
+
const branches = doc.getIn([
|
|
120
|
+
"on",
|
|
121
|
+
"pull_request",
|
|
122
|
+
"branches"
|
|
123
|
+
], true);
|
|
124
|
+
if (isSeq(branches)) branches.flow = true;
|
|
125
|
+
const jobNodes = doc.get("jobs", true);
|
|
126
|
+
spaceItems(jobNodes);
|
|
127
|
+
if (isMap(jobNodes)) {
|
|
128
|
+
for (const pair of jobNodes.items) if (isMap(pair.value)) spaceItems(pair.value.get("steps", true));
|
|
129
|
+
}
|
|
130
|
+
return doc.toString(YAML_OPTIONS);
|
|
131
|
+
}
|
|
8
132
|
// ../internal/src/domain/package-manager.ts
|
|
9
133
|
/** How to run a locally installed binary with each package manager. */
|
|
10
134
|
const PM_EXEC = {
|
|
@@ -193,7 +317,8 @@ var Prompter = class extends Effect.Service()("internal/Prompter", { succeed: {
|
|
|
193
317
|
multiselect: (params) => guardCancel(() => clack.multiselect({
|
|
194
318
|
message: params.message,
|
|
195
319
|
options: [...params.options],
|
|
196
|
-
required: params.required ?? false
|
|
320
|
+
required: params.required ?? false,
|
|
321
|
+
initialValues: params.initialValues && [...params.initialValues]
|
|
197
322
|
})),
|
|
198
323
|
spinner: (message) => Effect.sync(() => {
|
|
199
324
|
const s = clack.spinner();
|
|
@@ -278,7 +403,7 @@ const depVersions = {
|
|
|
278
403
|
"@chanom/vite-config": "0.1.2"
|
|
279
404
|
};
|
|
280
405
|
/** This package's own version, for `--version`. */
|
|
281
|
-
const pkgVersion = "0.
|
|
406
|
+
const pkgVersion = "0.5.0";
|
|
282
407
|
// src/domain/args.ts
|
|
283
408
|
const PACKAGE_MANAGERS = [
|
|
284
409
|
"pnpm",
|
|
@@ -287,11 +412,12 @@ const PACKAGE_MANAGERS = [
|
|
|
287
412
|
"bun"
|
|
288
413
|
];
|
|
289
414
|
const isPackageManager = (value) => PACKAGE_MANAGERS.includes(value);
|
|
415
|
+
const isCiJob = (value) => CI_JOBS.includes(value);
|
|
290
416
|
/**
|
|
291
417
|
* Parses the CLI arguments, returning either the resolved flags or a
|
|
292
418
|
* user-facing error message. Every flag mirrors an interactive prompt; the
|
|
293
|
-
* contradictory `--no-git --commit-hooks`
|
|
294
|
-
*
|
|
419
|
+
* contradictory `--no-git --commit-hooks` and `--no-github-actions --ci-jobs`
|
|
420
|
+
* pairs are rejected here rather than silently reconciled.
|
|
295
421
|
*/
|
|
296
422
|
function parseArgs(argv) {
|
|
297
423
|
const args = {
|
|
@@ -331,6 +457,27 @@ function parseArgs(argv) {
|
|
|
331
457
|
case "--no-agent-skills":
|
|
332
458
|
args.agentSkills = false;
|
|
333
459
|
break;
|
|
460
|
+
case "--github-actions":
|
|
461
|
+
args.githubActions = true;
|
|
462
|
+
break;
|
|
463
|
+
case "--no-github-actions":
|
|
464
|
+
args.githubActions = false;
|
|
465
|
+
break;
|
|
466
|
+
case "--ci-jobs": {
|
|
467
|
+
const value = argv[++i];
|
|
468
|
+
if (value === void 0) return {
|
|
469
|
+
ok: false,
|
|
470
|
+
message: "--ci-jobs requires a value."
|
|
471
|
+
};
|
|
472
|
+
const jobs = value.split(",").map((job) => job.trim());
|
|
473
|
+
const unknown = jobs.find((job) => !isCiJob(job));
|
|
474
|
+
if (unknown !== void 0) return {
|
|
475
|
+
ok: false,
|
|
476
|
+
message: `Unknown CI job "${unknown}". Use any of: ${CI_JOBS.join(", ")}.`
|
|
477
|
+
};
|
|
478
|
+
args.ciJobs = jobs.filter(isCiJob);
|
|
479
|
+
break;
|
|
480
|
+
}
|
|
334
481
|
case "--install":
|
|
335
482
|
args.install = true;
|
|
336
483
|
break;
|
|
@@ -366,6 +513,10 @@ function parseArgs(argv) {
|
|
|
366
513
|
ok: false,
|
|
367
514
|
message: "--commit-hooks requires a git repo. Remove --no-git or --commit-hooks."
|
|
368
515
|
};
|
|
516
|
+
if (args.githubActions === false && args.ciJobs !== void 0) return {
|
|
517
|
+
ok: false,
|
|
518
|
+
message: "--ci-jobs needs the github-actions topping. Remove --no-github-actions or --ci-jobs."
|
|
519
|
+
};
|
|
369
520
|
return {
|
|
370
521
|
ok: true,
|
|
371
522
|
args
|
|
@@ -511,12 +662,10 @@ const onlyBuiltDependencies = ["esbuild"];
|
|
|
511
662
|
const allowBuilds = ["esbuild"];
|
|
512
663
|
/** Renders the generated `pnpm-workspace.yaml` as a string. */
|
|
513
664
|
function buildPnpmWorkspace() {
|
|
514
|
-
return
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
...allowBuilds.map((name) => ` ${name}: true`)
|
|
519
|
-
].join("\n") + "\n";
|
|
665
|
+
return stringify({
|
|
666
|
+
onlyBuiltDependencies,
|
|
667
|
+
allowBuilds: Object.fromEntries(allowBuilds.map((name) => [name, true]))
|
|
668
|
+
}, YAML_OPTIONS);
|
|
520
669
|
}
|
|
521
670
|
// src/generate/readme.ts
|
|
522
671
|
/**
|
|
@@ -713,11 +862,32 @@ const agentSkills = {
|
|
|
713
862
|
files: skillFiles(codingStandardsSkill),
|
|
714
863
|
links: [skillLink(codingStandardsSkill)]
|
|
715
864
|
};
|
|
865
|
+
/**
|
|
866
|
+
* The `github-actions` topping: a CI workflow with one job per chosen check,
|
|
867
|
+
* identical to what `chanom brew` writes. The baseline ships every script the
|
|
868
|
+
* jobs run, so each job works out of the box. The generated app has no
|
|
869
|
+
* `.nvmrc`, so setup-node uses the latest LTS.
|
|
870
|
+
*/
|
|
871
|
+
function githubActions(pm, jobs, hasPackageManagerField) {
|
|
872
|
+
return {
|
|
873
|
+
...emptyContribution,
|
|
874
|
+
files: [{
|
|
875
|
+
path: WORKFLOW_PATH,
|
|
876
|
+
contents: workflowFile({
|
|
877
|
+
pm,
|
|
878
|
+
jobs,
|
|
879
|
+
hasNvmrc: false,
|
|
880
|
+
hasPackageManagerField
|
|
881
|
+
})
|
|
882
|
+
}]
|
|
883
|
+
};
|
|
884
|
+
}
|
|
716
885
|
/** The baseline plus whichever toppings the resolved options select, in fold order. */
|
|
717
886
|
function selectContributions(selection) {
|
|
718
887
|
const contributions = [baseline];
|
|
719
888
|
if (selection.commitHooks) contributions.push(commitHooks(selection.pm));
|
|
720
889
|
if (selection.agentSkills) contributions.push(agentSkills);
|
|
890
|
+
if (selection.ciJobs.length > 0) contributions.push(githubActions(selection.pm, selection.ciJobs, selection.hasPackageManagerField));
|
|
721
891
|
return contributions;
|
|
722
892
|
}
|
|
723
893
|
// src/scaffold.ts
|
|
@@ -777,10 +947,15 @@ const initGit = Effect.fn("scaffold.initGit")(function* (plan) {
|
|
|
777
947
|
const git = yield* Git;
|
|
778
948
|
const s = yield* (yield* Prompter).spinner("Initializing git repository...");
|
|
779
949
|
yield* git.init(plan.targetDir);
|
|
950
|
+
yield* s.stop("Git repository initialized");
|
|
951
|
+
});
|
|
952
|
+
const commitScaffold = Effect.fn("scaffold.commitScaffold")(function* (plan) {
|
|
953
|
+
const git = yield* Git;
|
|
954
|
+
const s = yield* (yield* Prompter).spinner("Creating the initial commit...");
|
|
780
955
|
if (!(yield* git.hasIdentity(plan.targetDir))) yield* git.setLocalIdentity(plan.targetDir, "create-chanom-app", "create-chanom-app@users.noreply.github.com");
|
|
781
956
|
yield* git.stageAll(plan.targetDir);
|
|
782
957
|
const result = yield* git.commit(plan.targetDir, "chore: scaffold with create-chanom-app");
|
|
783
|
-
yield* s.stop(result.ok ? "
|
|
958
|
+
yield* s.stop(result.ok ? "Initial commit created" : pc.yellow("Could not create the initial commit"));
|
|
784
959
|
});
|
|
785
960
|
const installDependencies = Effect.fn("scaffold.installDependencies")(function* (plan) {
|
|
786
961
|
const prompter = yield* Prompter;
|
|
@@ -796,19 +971,22 @@ const installDependencies = Effect.fn("scaffold.installDependencies")(function*
|
|
|
796
971
|
}
|
|
797
972
|
yield* s.stop("Dependencies installed");
|
|
798
973
|
});
|
|
799
|
-
/** Writes the generated app, then optionally initializes git
|
|
974
|
+
/** Writes the generated app, then optionally initializes git, installs deps, and commits. */
|
|
800
975
|
const scaffold = Effect.fn("scaffold")(function* (plan) {
|
|
801
976
|
const fs = yield* FileSystem.FileSystem;
|
|
802
977
|
const folded = mergeContributions(selectContributions({
|
|
803
978
|
pm: plan.pm,
|
|
804
979
|
commitHooks: plan.commitHooks,
|
|
805
|
-
agentSkills: plan.agentSkills
|
|
980
|
+
agentSkills: plan.agentSkills,
|
|
981
|
+
ciJobs: plan.ciJobs,
|
|
982
|
+
hasPackageManagerField: plan.packageManagerField !== void 0
|
|
806
983
|
}));
|
|
807
984
|
yield* fs.makeDirectory(plan.targetDir, { recursive: true });
|
|
808
985
|
yield* copyTemplates(plan);
|
|
809
986
|
yield* writeGeneratedFiles(plan, folded);
|
|
810
987
|
if (plan.git) yield* initGit(plan);
|
|
811
|
-
if (plan.install) yield* installDependencies(plan);
|
|
988
|
+
if (plan.install) yield* installDependencies(plan).pipe(Effect.tapError(() => plan.git ? commitScaffold(plan) : Effect.void));
|
|
989
|
+
if (plan.git) yield* commitScaffold(plan);
|
|
812
990
|
});
|
|
813
991
|
// src/cli.ts
|
|
814
992
|
const DEFAULT_NAME = "my-chanom-app";
|
|
@@ -825,6 +1003,9 @@ ${pc.bold("Options")}
|
|
|
825
1003
|
${pc.cyan("--no-commit-hooks")} Skip the commit-hooks topping
|
|
826
1004
|
${pc.cyan("--agent-skills")} Add the coding-standards skill to .claude/skills
|
|
827
1005
|
${pc.cyan("--no-agent-skills")} Skip the agent-skills topping
|
|
1006
|
+
${pc.cyan("--github-actions")} Add a GitHub Actions CI workflow
|
|
1007
|
+
${pc.cyan("--no-github-actions")} Skip the github-actions topping
|
|
1008
|
+
${pc.cyan("--ci-jobs <jobs>")} Comma-separated CI jobs: ${CI_JOBS.join(", ")} (default: all)
|
|
828
1009
|
${pc.cyan("--install / --no-install")} Install dependencies after scaffolding (default: install)
|
|
829
1010
|
${pc.cyan("--pm <pnpm|npm|yarn|bun>")} Package manager to record (default: detected)
|
|
830
1011
|
${pc.cyan("-y, --yes")} Accept all defaults, no prompts (CI-friendly)
|
|
@@ -845,6 +1026,28 @@ function resolveConfirm(flag, yes, ask) {
|
|
|
845
1026
|
if (flag !== void 0) return Effect.succeed(flag);
|
|
846
1027
|
return yes ? Effect.succeed(true) : ask;
|
|
847
1028
|
}
|
|
1029
|
+
/**
|
|
1030
|
+
* `--ci-jobs` implies the topping and wins over the jobs prompt; `--yes` takes
|
|
1031
|
+
* every job. Returns no jobs when the topping is declined.
|
|
1032
|
+
*/
|
|
1033
|
+
const resolveCiJobs = Effect.fn("cli.resolveCiJobs")(function* (flag, jobs, yes) {
|
|
1034
|
+
const prompter = yield* Prompter;
|
|
1035
|
+
if (!(yield* resolveConfirm(jobs === void 0 ? flag : true, yes, prompter.confirm({
|
|
1036
|
+
message: "Add a GitHub Actions CI workflow?",
|
|
1037
|
+
initialValue: true
|
|
1038
|
+
})))) return [];
|
|
1039
|
+
if (jobs !== void 0) return jobs;
|
|
1040
|
+
if (yes) return CI_JOBS;
|
|
1041
|
+
return yield* prompter.multiselect({
|
|
1042
|
+
message: "Which GitHub Actions jobs would you like?",
|
|
1043
|
+
options: CI_JOBS.map((job) => ({
|
|
1044
|
+
value: job,
|
|
1045
|
+
label: job
|
|
1046
|
+
})),
|
|
1047
|
+
initialValues: CI_JOBS,
|
|
1048
|
+
required: true
|
|
1049
|
+
});
|
|
1050
|
+
});
|
|
848
1051
|
const isEmptyDir = Effect.fn("cli.isEmptyDir")(function* (dir) {
|
|
849
1052
|
const fs = yield* FileSystem.FileSystem;
|
|
850
1053
|
if (!(yield* fs.exists(dir))) return true;
|
|
@@ -900,6 +1103,7 @@ const program$1 = (argv, cwd, options) => Effect.gen(function* () {
|
|
|
900
1103
|
message: "Add agent coding standards (.agents/skills)?",
|
|
901
1104
|
initialValue: true
|
|
902
1105
|
}));
|
|
1106
|
+
const ciJobs = yield* resolveCiJobs(args.githubActions, args.ciJobs, args.yes);
|
|
903
1107
|
const install = yield* resolveConfirm(args.install, args.yes, prompter.confirm({
|
|
904
1108
|
message: "Install dependencies now?",
|
|
905
1109
|
initialValue: true
|
|
@@ -914,6 +1118,7 @@ const program$1 = (argv, cwd, options) => Effect.gen(function* () {
|
|
|
914
1118
|
`${pc.dim("git")} ${git ? "yes" : "no"}`,
|
|
915
1119
|
`${pc.dim("commit hooks")} ${git ? commitHooks ? "yes" : "no" : pc.dim("n/a")}`,
|
|
916
1120
|
`${pc.dim("agent skills")} ${agentSkills ? "yes" : "no"}`,
|
|
1121
|
+
`${pc.dim("ci jobs")} ${ciJobs.length > 0 ? ciJobs.join(", ") : "no"}`,
|
|
917
1122
|
`${pc.dim("install")} ${install ? "yes" : "no"}`
|
|
918
1123
|
].join("\n"));
|
|
919
1124
|
yield* scaffold({
|
|
@@ -924,6 +1129,7 @@ const program$1 = (argv, cwd, options) => Effect.gen(function* () {
|
|
|
924
1129
|
git,
|
|
925
1130
|
commitHooks,
|
|
926
1131
|
agentSkills,
|
|
1132
|
+
ciJobs,
|
|
927
1133
|
install,
|
|
928
1134
|
templatesRoot: options.templatesRoot
|
|
929
1135
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-chanom-app",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Scaffold a Vite + React + TypeScript app, wired to the chanom shared configs.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"create",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"@effect/platform": "0.96.2",
|
|
31
31
|
"@effect/platform-node": "0.107.0",
|
|
32
32
|
"effect": "3.22.4",
|
|
33
|
-
"picocolors": "1.1.1"
|
|
33
|
+
"picocolors": "1.1.1",
|
|
34
|
+
"yaml": "2.9.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@effect/language-service": "0.86.4",
|