create-geonosis 2.13.0 → 3.0.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.
@@ -1,199 +1,15 @@
1
- import {
2
- BACKENDS,
3
- DOMAIN_NAMES,
4
- MEDUSA_RANGE,
5
- PLATFORM_FILE,
6
- UIS,
7
- checkScaffold,
8
- describeDrift,
9
- finish,
10
- parseAnswers,
11
- parseArgs,
12
- scopeOf,
13
- wantsInstall,
14
- writeScaffold
15
- } from "./chunk-LUUI74BB.js";
16
-
17
- // src/create-geonosis-cli.ts
18
- import { existsSync as existsSync2 } from "fs";
19
-
20
- // src/adopt.ts
21
- import { existsSync, readdirSync, readFileSync } from "fs";
22
- import { basename, join, resolve } from "path";
23
- import { countersFor, rulesFor, runtimeOf, tiersFor } from "@geonosis/cli";
24
- var ADOPT_USAGE = "create-geonosis --plan <dir> [--presets <a,b>] [--runtime pnpm|bun] [--backend medusa|sagaflow-cf|none] [--ui tiered-shadcn|atoms-only|none] \u2014 what adopting this repo would take, computed off the tree. Writes nothing.";
25
- var LOCKFILES = ["bun.lock", "bun.lockb", "pnpm-lock.yaml"];
26
- var MEDUSA = "@medusajs/";
27
- var WORKERS = ["wrangler", "@cloudflare/workers-types", "sagaflow-js"];
28
- var readJson = (at) => {
29
- if (!existsSync(at)) return void 0;
30
- try {
31
- return JSON.parse(readFileSync(at, "utf8"));
32
- } catch {
33
- return void 0;
34
- }
35
- };
36
- var manifestsIn = (dir) => {
37
- const found = [readJson(join(dir, "package.json"))];
38
- for (const group of ["apps", "packages"]) {
39
- const at = join(dir, group);
40
- if (!existsSync(at)) continue;
41
- for (const entry of readdirSync(at, { withFileTypes: true })) {
42
- if (entry.isDirectory()) found.push(readJson(join(at, entry.name, "package.json")));
43
- }
44
- }
45
- return found.filter((one) => one !== void 0);
46
- };
47
- var dependencyNames = (manifests) => manifests.flatMap((one) => [
48
- ...Object.keys(one.dependencies ?? {}),
49
- ...Object.keys(one.devDependencies ?? {})
50
- ]);
51
- var backendOf = (manifests) => {
52
- const names = dependencyNames(manifests);
53
- if (names.some((one) => one.startsWith(MEDUSA))) return "medusa";
54
- if (names.some((one) => WORKERS.includes(one))) return "sagaflow-cf";
55
- return "none";
56
- };
57
- var chosen = (flag, given, allowed) => {
58
- if (given === void 0) return void 0;
59
- if (!allowed.includes(given)) {
60
- throw new Error(`${flag} "${given}" is not one of ${allowed.join(", ")}`);
61
- }
62
- return given;
63
- };
64
- var uiOf = (dir, given) => {
65
- if (given !== void 0) return given;
66
- if (!existsSync(join(dir, "packages/ui"))) return "none";
67
- throw new Error(
68
- `${dir} has a packages/ui and no --ui was given \u2014 the tier decides which rules the plan proposes, and a directory listing cannot say which tier it is. Name --ui ${UIS.join("|")}.`
69
- );
70
- };
71
- var doorFor = (block) => `@geonosis/${block}`;
72
- var KIT_OWNED_BLOCKS = ["ledger", "review", "testbed", "verify", "walk"];
73
- var planAdoption = ({ backend, dir, presets, runtime, ui }) => {
74
- const at = resolve(dir);
75
- if (!existsSync(at))
76
- throw new Error(`${at} is not there \u2014 --plan reads a repo, it never makes one`);
77
- const manifests = manifestsIn(at);
78
- const chosenRuntime = chosen("--runtime", runtime, ["bun", "pnpm"]) ?? runtimeOf(at);
79
- if (chosenRuntime === void 0) {
80
- throw new Error(
81
- `${at} has none of ${LOCKFILES.join(", ")}, so nothing there says which package manager it runs \u2014 name --runtime pnpm|bun.`
82
- );
83
- }
84
- const answers = {
85
- backend: chosen("--backend", backend, BACKENDS) ?? backendOf(manifests),
86
- dir: at,
87
- domains: [],
88
- name: basename(at),
89
- runtime: chosenRuntime,
90
- scope: scopeOf(basename(at)),
91
- ui: uiOf(at, chosen("--ui", ui, UIS))
92
- };
93
- const drift = checkScaffold(answers);
94
- const enabled = new Set(
95
- Object.keys(
96
- readJson(join(at, ".oxlintrc.json"))?.rules ?? {}
97
- )
98
- );
99
- const config = readJson(join(at, "geonosis.json")) ?? {};
100
- const declaredTiers = config["verify"] ?? {};
101
- const declaredCounters = new Set(
102
- (readJson(
103
- join(at, "geonosis.ratchet.json")
104
- )?.counters ?? []).map((one) => one.key ?? one.counter ?? "")
105
- );
106
- const declaredPackages = new Set(dependencyNames(manifests));
107
- const { unanswered } = rulesFor(presets);
108
- const tiers = tiersFor({
109
- rules: {},
110
- runtime: chosenRuntime,
111
- scripts: Object.keys(
112
- readJson(join(at, "package.json"))?.scripts ?? {}
113
- )
114
- });
115
- return {
116
- backend: answers.backend,
117
- counters: countersFor(chosenRuntime, "LAW.md").map((one) => {
118
- const key = typeof one["key"] === "string" ? one["key"] : String(one["counter"]);
119
- return { declared: declaredCounters.has(key), key };
120
- }),
121
- dir: at,
122
- doors: KIT_OWNED_BLOCKS.map((block) => ({
123
- block,
124
- declared: declaredPackages.has(doorFor(block)),
125
- package: doorFor(block)
126
- })),
127
- files: drift.filter((one) => one.kind === "missing"),
128
- keys: drift.filter((one) => one.kind === "key"),
129
- presets: presets.map((name) => {
130
- const brings = Object.keys(rulesFor([name]).rules);
131
- return {
132
- brings: brings.length,
133
- enabled: brings.filter((id) => enabled.has(id)),
134
- name
135
- };
136
- }),
137
- runtime: chosenRuntime,
138
- tiers: Object.entries(tiers).map(([name, steps]) => ({
139
- declared: Object.hasOwn(declaredTiers, name),
140
- name,
141
- steps
142
- })),
143
- ui: answers.ui,
144
- unanswered,
145
- unreadable: drift.filter((one) => one.kind === "unreadable")
146
- };
147
- };
148
- var section = (title, lines) => lines.length === 0 ? [`${title} \u2014 none`, ""] : [`${title} (${lines.length})`, ...lines, ""];
149
- var formatPlan = (plan) => [
150
- `adoption plan for ${plan.dir}`,
151
- ` runtime ${plan.runtime} \xB7 backend ${plan.backend} \xB7 ui ${plan.ui}`,
152
- "",
153
- ...section(
154
- "FILES the scaffold writes and this repo has none of",
155
- plan.files.map((one) => ` ${one.file}`)
156
- ),
157
- ...section(
158
- "KEYS the scaffold declares inside a file this repo has",
159
- plan.keys.map((one) => ` ${one.file} \u2192 ${one.at}`)
160
- ),
161
- ...section(
162
- "RULES the presets bring",
163
- plan.presets.map(
164
- (one) => ` ${one.name}: ${one.brings} rules, ${one.enabled.length} already enabled here`
165
- )
166
- ),
167
- ...section(
168
- "RULES left out until somebody answers their option",
169
- plan.unanswered.map(([rule, option]) => ` ${rule} needs \`${option}\``)
170
- ),
171
- ...section(
172
- "COUNTERS the ratchet would run",
173
- plan.counters.map((one) => ` ${one.key}${one.declared ? " \u2014 declared" : ""}`)
174
- ),
175
- ...section(
176
- "TIERS",
177
- plan.tiers.map((one) => ` ${one.name}${one.declared ? " \u2014 declared" : ""}`)
178
- ),
179
- ...section(
180
- "DOORS a block needs declared",
181
- plan.doors.map(
182
- (one) => ` ${one.package} for "${one.block}"${one.declared ? " \u2014 declared" : ""}`
183
- )
184
- ),
185
- ...plan.unreadable.length === 0 ? [] : section(
186
- "FILES this check could not read as JSON",
187
- plan.unreadable.map((one) => ` ${one.file}`)
188
- )
189
- ].join("\n");
190
-
191
1
  // src/create-geonosis-cli.ts
2
+ import { existsSync } from "node:fs";
3
+ import { ADOPT_USAGE, formatPlan, planAdoption } from "./adopt.js";
4
+ import { MEDUSA_RANGE, parseAnswers, parseArgs, wantsInstall } from "./answers.js";
5
+ import { checkScaffold, describeDrift } from "./check.js";
6
+ import { DOMAIN_NAMES, PLATFORM_FILE } from "./composition.js";
7
+ import { finish, writeScaffold } from "./scaffold.js";
192
8
  var USAGE = `create-geonosis <dir> --runtime pnpm|bun --backend medusa|sagaflow-cf|none --ui tiered-shadcn|atoms-only|none
193
9
  [--medusa <range>]
194
10
  [--domains <a,b>] [--brand <name>] [--themekit <name>] [--marketplace <path>] [--kit <path>] [--no-install]
195
11
  [--check]
196
- create-geonosis --plan <dir> [--presets <a,b>] [--runtime \u2026] [--backend \u2026] [--ui \u2026]
12
+ create-geonosis --plan <dir> [--presets <a,b>] [--runtime …] [--backend …] [--ui …]
197
13
 
198
14
  Writes a repo that passes its own gates on day one: a workspace with one catalog of shared versions,
199
15
  an exports map and no barrel in every package, typecheck + lint + test scripts in every workspace,
@@ -204,7 +20,7 @@ skills lock, and a reach corpus in this repo's own vocabulary so the doctor can
204
20
  There is no default for --runtime, --backend or --ui. Each one decides the shape of the tree, and a
205
21
  default borrowed from another repo would be that repo's stack hardcoded into this one.
206
22
 
207
- --domains the domains this repo composes \u2014 ${DOMAIN_NAMES.join(", ")}. Each one writes its
23
+ --domains the domains this repo composes — ${DOMAIN_NAMES.join(", ")}. Each one writes its
208
24
  store into the app's ${PLATFORM_FILE}: the composition root, in two lifetimes, with
209
25
  the tenant session opened before any store is built. A name nothing ships is refused.
210
26
  --medusa <range>
@@ -221,19 +37,19 @@ default borrowed from another repo would be that repo's stack hardcoded into thi
221
37
  preset brings against the ones already enabled, the rules left out until somebody
222
38
  answers their option, the counters, the tiers and the doors a block needs
223
39
  declared. The runtime and the backend are read off the lockfile and the manifests;
224
- a flag overrides one. Exit 0 \u2014 it is a report.
40
+ a flag overrides one. Exit 0 — it is a report.
225
41
  --check say what an EXISTING repo is missing of what the scaffold writes today, and WRITE
226
42
  NOTHING. Files it has never had, and keys inside the JSON it has. Contents and
227
43
  values are never compared: a repo that has been worked in has rewritten them, and
228
44
  it was entitled to. Exit 1 when anything drifted.
229
45
 
230
- Exit: 0 written (or, under --check, no drift) \xB7 1 refused (a directory with something in it, an
231
- answer that is not one) or drift found \xB7 2 a run that could not be made at all.`;
46
+ Exit: 0 written (or, under --check, no drift) · 1 refused (a directory with something in it, an
47
+ answer that is not one) or drift found · 2 a run that could not be made at all.`;
232
48
  var CONFIG_SHAPE = `create-geonosis reads no configuration file.
233
49
 
234
50
  It WRITES them: geonosis.json, .oxlintrc.json, geonosis.ratchet.json and gate-baseline.json, from
235
51
  the answers given on the command line. Every answer is a flag, and there is no default for the three
236
- that decide the shape of the tree \u2014 see create-geonosis --help.
52
+ that decide the shape of the tree — see create-geonosis --help.
237
53
 
238
54
  For the shape of what it wrote, ask the bin that reads it: geonosis-<tool> --print-config-shape.`;
239
55
  var main = () => {
@@ -250,61 +66,57 @@ var main = () => {
250
66
  }
251
67
  if (argv.includes("--plan")) {
252
68
  const { dir, flags } = parseArgs(argv);
253
- if (dir === void 0) throw new Error(`--plan needs a directory \u2014 ${ADOPT_USAGE}`);
254
- process.stdout.write(
255
- `${formatPlan(
256
- planAdoption({
257
- ...flags["--backend"] === void 0 ? {} : { backend: flags["--backend"] },
258
- dir,
259
- presets: (flags["--presets"] ?? "frontend,tooling").split(",").map((one) => one.trim()).filter((one) => one !== ""),
260
- ...flags["--runtime"] === void 0 ? {} : { runtime: flags["--runtime"] },
261
- ...flags["--ui"] === void 0 ? {} : { ui: flags["--ui"] }
262
- })
263
- )}
264
- `
265
- );
69
+ if (dir === undefined)
70
+ throw new Error(`--plan needs a directory — ${ADOPT_USAGE}`);
71
+ process.stdout.write(`${formatPlan(planAdoption({
72
+ ...flags["--backend"] === undefined ? {} : { backend: flags["--backend"] },
73
+ dir,
74
+ presets: (flags["--presets"] ?? "frontend,tooling").split(",").map((one) => one.trim()).filter((one) => one !== ""),
75
+ ...flags["--runtime"] === undefined ? {} : { runtime: flags["--runtime"] },
76
+ ...flags["--ui"] === undefined ? {} : { ui: flags["--ui"] }
77
+ }))}
78
+ `);
266
79
  return 0;
267
80
  }
268
81
  const answers = parseAnswers(argv, process.cwd());
269
82
  if (argv.includes("--check")) {
270
- if (!existsSync2(answers.dir)) {
271
- throw new Error(`${answers.dir} is not there \u2014 --check reads a repo, it never makes one`);
83
+ if (!existsSync(answers.dir)) {
84
+ throw new Error(`${answers.dir} is not there — --check reads a repo, it never makes one`);
272
85
  }
273
86
  const drift = checkScaffold(answers);
274
87
  if (drift.length === 0) {
275
- process.stdout.write(`create-geonosis --check ${answers.dir} \u2014 no drift
88
+ process.stdout.write(`create-geonosis --check ${answers.dir} — no drift
276
89
  `);
277
90
  return 0;
278
91
  }
279
- for (const line of describeDrift(drift)) process.stderr.write(` ${line}
92
+ for (const line of describeDrift(drift))
93
+ process.stderr.write(` ${line}
94
+ `);
95
+ process.stderr.write(`create-geonosis --check ${answers.dir} — ${drift.length} drift, nothing written
280
96
  `);
281
- process.stderr.write(
282
- `create-geonosis --check ${answers.dir} \u2014 ${drift.length} drift, nothing written
283
- `
284
- );
285
97
  return 1;
286
98
  }
287
99
  const written = writeScaffold(answers);
288
- process.stdout.write(`create-geonosis \u2014 ${written.length} file(s) into ${answers.dir}
100
+ process.stdout.write(`create-geonosis — ${written.length} file(s) into ${answers.dir}
289
101
  `);
290
102
  const install = wantsInstall(argv);
291
103
  for (const step of finish({ answers, install })) {
292
104
  process.stdout.write(` ${step.code === 0 ? "ok " : "FAIL"} ${step.what}
293
105
  `);
294
- if (step.code !== 0) process.stdout.write(`${step.output}
106
+ if (step.code !== 0)
107
+ process.stdout.write(`${step.output}
295
108
  `);
296
109
  }
297
110
  if (!install) {
298
- process.stdout.write(
299
- [
300
- "",
301
- " Nothing was installed, so the edges table has not reached the gates yet. Run:",
302
- ` cd ${answers.dir} && ${answers.runtime} install`,
303
- " geonosis sync --target turbo --into turbo.json",
304
- " geonosis sync --target layer-walls --into .oxlintrc.json",
305
- ""
306
- ].join("\n")
307
- );
111
+ process.stdout.write([
112
+ "",
113
+ " Nothing was installed, so the edges table has not reached the gates yet. Run:",
114
+ ` cd ${answers.dir} && ${answers.runtime} install`,
115
+ " geonosis sync --target turbo --into turbo.json",
116
+ " geonosis sync --target layer-walls --into .oxlintrc.json",
117
+ ""
118
+ ].join(`
119
+ `));
308
120
  }
309
121
  return 0;
310
122
  };
@@ -0,0 +1,18 @@
1
+ import type { Answers } from './answers.js';
2
+ declare const presetsFor: (answers: Answers) => string[];
3
+ /** The kit a scaffolded repo runs on, at the version this scaffold was published at. */
4
+ export declare const kitDependencies: (answers: Answers) => Record<string, string>;
5
+ /**
6
+ * The two files the edges table generates, named once. `scaffold` runs them when it makes the tree
7
+ * and the `sync:graph` script runs them when the table changes; a second spelling of the pair is a
8
+ * second answer to where the graph comes from.
9
+ */
10
+ export declare const GRAPH_SYNCS: {
11
+ target: string;
12
+ write: string;
13
+ }[];
14
+ /** What the root can be asked to run — and therefore what a verify tier may name (`tiersFor`). */
15
+ export declare const HOOK_INSTALLER = "scripts/install-hooks.mjs";
16
+ export declare const filesFor: (answers: Answers) => Record<string, string>;
17
+ export declare const presetsChosenBy: typeof presetsFor;
18
+ export {};