create-geonosis 2.12.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.
@@ -0,0 +1,46 @@
1
+ /** Where the composition root lives, relative to the workspace that composes: the app. */
2
+ export declare const PLATFORM_FILE = "src/platform.ts";
3
+ /**
4
+ * A domain the kit ships, and the two lines composing it takes.
5
+ *
6
+ * A domain is added here and nowhere else: the flag's vocabulary, the app's dependencies and the
7
+ * generated file all read this table, so a domain that ships without a way to compose it cannot be
8
+ * offered by name. `version` is the floor package's OWN line — the method's number says nothing
9
+ * about it (D-053) — and `tooling/floor-scaffold-versions.test.ts` holds each against the workspace.
10
+ */
11
+ export type DomainScaffold = {
12
+ /** Where the package sits in the kit's tree, for `--kit`'s workspace links. */
13
+ at: string;
14
+ /** What the scope field is called, and the type it is annotated with. */
15
+ field: string;
16
+ /** Everything the generated file needs above the composition itself. */
17
+ declarations: readonly string[];
18
+ fieldType: string;
19
+ imports: readonly string[];
20
+ name: string;
21
+ /** How the store is built, once the tenant's transaction is already open. */
22
+ built: readonly string[];
23
+ version: string;
24
+ };
25
+ export declare const DOMAINS: readonly DomainScaffold[];
26
+ export declare const DOMAIN_NAMES: readonly string[];
27
+ /** The two foundations a composition root is built from, whichever domains it composes. */
28
+ export declare const FOUNDATIONS: readonly {
29
+ at: string;
30
+ name: string;
31
+ version: string;
32
+ }[];
33
+ export declare const domainsNamed: (named: readonly string[]) => DomainScaffold[];
34
+ /** What the composing workspace declares once a domain is named. */
35
+ export declare const floorDependencies: (named: readonly string[]) => Record<string, string>;
36
+ /** Every kit directory a `--kit` link has to reach for the domains this repo named. */
37
+ export declare const floorDirectories: (named: readonly string[]) => string[];
38
+ /**
39
+ * The composition root, in the two lifetimes it has.
40
+ *
41
+ * DEFINITIONS are what this deployment IS — wired once per isolate, before anybody has asked
42
+ * anything. SCOPE is who is asking, bound per request. Keeping them apart is what lets the session
43
+ * come first: the stores are built INSIDE the tenant's transaction, so a caller cannot hold one
44
+ * that was made without a session to run in (D-014 — structural, never an assertion).
45
+ */
46
+ export declare const platformSource: (named: readonly string[]) => string;
@@ -0,0 +1,137 @@
1
+ // src/composition.ts
2
+ import { FLOOR_VERSIONS } from "./floor-versions.js";
3
+ var PLATFORM_FILE = "src/platform.ts";
4
+ var SEARCH = {
5
+ at: "domains/search",
6
+ built: [
7
+ " search: pgFtsSearchIndex({",
8
+ " executor: tx,",
9
+ " nowMs: definitions.nowMs,",
10
+ " projections: SEARCH_PROJECTIONS,",
11
+ " }),"
12
+ ],
13
+ declarations: [
14
+ "/** How each kind this repo indexes becomes searchable text — declared once, never per call. */",
15
+ "const SEARCH_PROJECTIONS: SearchProjections<'note'> = {",
16
+ " note: {",
17
+ " body: (fields) => fields.notes ?? '',",
18
+ " title: (fields) => fields.heading ?? '',",
19
+ " },",
20
+ "}"
21
+ ],
22
+ field: "search",
23
+ fieldType: "SearchIndex<'note'>",
24
+ imports: [
25
+ "import { pgFtsSearchIndex, type SearchIndex, type SearchProjections } from '@geonosis/search'"
26
+ ],
27
+ name: "@geonosis/search",
28
+ version: FLOOR_VERSIONS["@geonosis/search"]
29
+ };
30
+ var DOCUMENT = {
31
+ at: "domains/document",
32
+ built: [" document: DOCUMENT_ENTITIES,"],
33
+ declarations: [
34
+ "/** Every `Document.extend` this repo declares, by the name its rows carry — grow this map. */",
35
+ "const DOCUMENT_ENTITIES = documentEntities({})"
36
+ ],
37
+ field: "document",
38
+ fieldType: "typeof DOCUMENT_ENTITIES",
39
+ imports: ["import { documentEntities } from '@geonosis/document'"],
40
+ name: "@geonosis/document",
41
+ version: FLOOR_VERSIONS["@geonosis/document"]
42
+ };
43
+ var DOMAINS = [SEARCH, DOCUMENT];
44
+ var DOMAIN_NAMES = DOMAINS.map((one) => one.field);
45
+ var FOUNDATIONS = [
46
+ { at: "foundations/db", name: "@geonosis/db", version: FLOOR_VERSIONS["@geonosis/db"] },
47
+ {
48
+ at: "foundations/events",
49
+ name: "@geonosis/events",
50
+ version: FLOOR_VERSIONS["@geonosis/events"]
51
+ }
52
+ ];
53
+ var domainsNamed = (named) => named.map((one) => {
54
+ const found = DOMAINS.find((domain) => domain.field === one);
55
+ if (found === undefined) {
56
+ throw new Error(`--domains "${one}" is not a domain this kit ships — it ships ${DOMAIN_NAMES.join(", ")}. A domain nothing publishes cannot be composed, and a scaffold that wrote the import anyway would leave a repo that does not install.`);
57
+ }
58
+ return found;
59
+ });
60
+ var floorDependencies = (named) => named.length === 0 ? {} : Object.fromEntries([...FOUNDATIONS, ...domainsNamed(named)].map((one) => [one.name, `^${one.version}`]).toSorted(([a], [b]) => String(a).localeCompare(String(b), "en-US")));
61
+ var floorDirectories = (named) => named.length === 0 ? [] : [...FOUNDATIONS, ...domainsNamed(named)].map((one) => one.at);
62
+ var platformSource = (named) => {
63
+ const domains = domainsNamed(named);
64
+ return [
65
+ "import { createSessionSeam, type Executor, type SessionSeam } from '@geonosis/db'",
66
+ "import { createEmitDoor, type EmitDoor, type Extensions } from '@geonosis/events'",
67
+ ...domains.flatMap((one) => one.imports),
68
+ "",
69
+ "/** Every name a foundation cannot pick for this repo, answered here and only here. */",
70
+ "export type PlatformConfig = {",
71
+ " newId: () => string",
72
+ " nowMs: () => number",
73
+ " /** What maintenance sets to see every tenant, through a lever no request path reaches. */",
74
+ " opsSetting: string",
75
+ " /** The producer every envelope names (D-057) — spelled here, never at an emit call. */",
76
+ " source: string",
77
+ " /** What a transaction sets to name its tenant, and what the RLS policies read. */",
78
+ " tenantSetting: string",
79
+ "}",
80
+ "",
81
+ "export type Definitions = {",
82
+ " emit: EmitDoor<Extensions>",
83
+ " nowMs: () => number",
84
+ " session: SessionSeam",
85
+ "}",
86
+ "",
87
+ "/** Once per isolate: what this platform is, before anybody has asked it anything. */",
88
+ "export const definitionsOf = (config: PlatformConfig): Definitions => ({",
89
+ " emit: createEmitDoor({",
90
+ " extensions: [],",
91
+ " newId: config.newId,",
92
+ " now: config.nowMs,",
93
+ " source: config.source,",
94
+ " }),",
95
+ " nowMs: config.nowMs,",
96
+ " session: createSessionSeam({",
97
+ " settings: { opsSetting: config.opsSetting, tenantSetting: config.tenantSetting },",
98
+ " }),",
99
+ "})",
100
+ "",
101
+ ...domains.flatMap((one) => [...one.declarations, ""]),
102
+ "/** Who is asking, and the connection they may ask on. */",
103
+ "export type Caller = { connection: Executor; tenantId: string }",
104
+ "",
105
+ "/** Every domain this repo composed, built for one caller. */",
106
+ "export type Scope = {",
107
+ ...domains.map((one) => ` ${one.field}: ${one.fieldType}`),
108
+ "}",
109
+ "",
110
+ "/**",
111
+ " * Per request. The tenant session opens FIRST and the stores are built inside it, so a store",
112
+ " * that could run outside the transaction that named its tenant does not exist to be held.",
113
+ " */",
114
+ "export const inScope = async <Result>(",
115
+ " definitions: Definitions,",
116
+ " caller: Caller,",
117
+ " run: (scope: Scope) => Promise<Result>,",
118
+ "): Promise<Result> =>",
119
+ " definitions.session.inTenant(caller.connection, caller.tenantId, async (tx) =>",
120
+ " run({",
121
+ ...domains.flatMap((one) => [...one.built]),
122
+ " }),",
123
+ " )",
124
+ ""
125
+ ].join(`
126
+ `);
127
+ };
128
+ export {
129
+ DOMAINS,
130
+ DOMAIN_NAMES,
131
+ FOUNDATIONS,
132
+ PLATFORM_FILE,
133
+ domainsNamed,
134
+ floorDependencies,
135
+ floorDirectories,
136
+ platformSource
137
+ };
@@ -0,0 +1,16 @@
1
+ import type { Answers } from './answers.js';
2
+ import type { Workspace } from './layout.js';
3
+ export declare const CORPUS_DIR = "lint-corpus";
4
+ /**
5
+ * A reach corpus a shipped one cannot be.
6
+ *
7
+ * `geonosis-doctor` asks whether every enabled rule can fire at all, and it asks the corpus the
8
+ * PLUGIN ships. That cannot answer for a rule whose reach is the repo's own vocabulary: its layer
9
+ * names, its brand, its plugin package root, the `within` its sagas live in. The plugin's corpus
10
+ * says "acme" and `layers/core`, so it is no evidence either way about a repo that says anything
11
+ * else — and those rules would read as firing nowhere.
12
+ *
13
+ * So the repo ships its own, in ITS vocabulary. The corpus is copied to a temp root and linted with
14
+ * `--no-ignore`, so the fixture paths mirror the repo's real ones and the layer patterns match.
15
+ */
16
+ export declare const corpusFor: (answers: Answers, workspaces: Workspace[]) => Record<string, string>;
package/dist/corpus.js ADDED
@@ -0,0 +1,46 @@
1
+ // src/corpus.ts
2
+ var CORPUS_DIR = "lint-corpus";
3
+ var PREFIX = "biological-architecture";
4
+ var corpusFor = (answers, workspaces) => {
5
+ const files = {};
6
+ const rules = [];
7
+ const walled = workspaces.find((one) => one.mayDependOn.length === 0);
8
+ const forbidden = workspaces.find((one) => one.tag === "app");
9
+ if (walled !== undefined && forbidden !== undefined) {
10
+ rules.push(`${PREFIX}/layer-walls`);
11
+ files[`${CORPUS_DIR}/${walled.dir}/src/bad-reaches-up.ts`] = `// BREACH: the ${walled.tag} layer may import nothing, and this reaches ${forbidden.tag}.
12
+ import { boot } from '${forbidden.name}/boot'
13
+
14
+ export const reachesUp = () => boot
15
+ `;
16
+ }
17
+ if (answers.brand !== undefined) {
18
+ rules.push(`${PREFIX}/no-brand-names`);
19
+ files[`${CORPUS_DIR}/brand/bad-brand.ts`] = `// BREACH: the brand name spelled into source, which is what the rule is configured to find.
20
+ export const FOOTER_NOTE = 'Powered by ${answers.brand}'
21
+ `;
22
+ }
23
+ if (answers.backend === "medusa") {
24
+ rules.push(`${PREFIX}/plugin-route-namespaced`);
25
+ files[`${CORPUS_DIR}/packages/medusa-plugins/example/src/api/store/route.ts`] = `// BREACH: a store route with no namespace under it, in a plugin package.
26
+ export async function GET(req: unknown, res: { json: (body: unknown) => void }) {
27
+ res.json({ ok: true, req })
28
+ }
29
+ `;
30
+ }
31
+ if (answers.backend === "sagaflow-cf") {
32
+ rules.push(`${PREFIX}/step-opens-its-own-cell`);
33
+ files[`${CORPUS_DIR}/packages/backend/src/workflows/bad-engine-step.ts`] = `// BREACH: a saga inside the configured \`within\` reaching the engine's own step.
34
+ import { step } from 'sagaflow-js'
35
+
36
+ export const issue = step('issue', async () => ({ ok: true }))
37
+ `;
38
+ }
39
+ files[`${CORPUS_DIR}/manifest.json`] = `${JSON.stringify({ plugin: PREFIX, rules }, undefined, 2)}
40
+ `;
41
+ return files;
42
+ };
43
+ export {
44
+ CORPUS_DIR,
45
+ corpusFor
46
+ };
@@ -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-4IX6PJ7R.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 {};