create-geonosis 1.3.0 → 2.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.
- package/README.md +30 -0
- package/dist/{chunk-3FX4T27X.js → chunk-PRX7MKFZ.js} +298 -61
- package/dist/create-geonosis-cli.js +35 -4
- package/dist/index.d.ts +77 -2
- package/dist/index.js +21 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -68,6 +68,36 @@ verify. It is done by hand because neither package manager can do it: pnpm resol
|
|
|
68
68
|
and bun refuses both `link:` and `file:` here, because it follows into the target and tries to
|
|
69
69
|
resolve the `workspace:*` specifiers the kit's own packages use.
|
|
70
70
|
|
|
71
|
+
## `--check` — what an existing repo never received
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npx create-geonosis . --check --runtime pnpm --backend medusa --ui tiered-shadcn
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
A repo is scaffolded once and the scaffold keeps learning, so the divergence is permanent and
|
|
78
|
+
one-way. `--check` closes the loop in the only direction that is safe: it says what is missing and
|
|
79
|
+
**writes nothing** — no file created, no file opened for writing, no `writeScaffold` on the path at
|
|
80
|
+
all. Exit 0 when nothing drifted, 1 with a line per drift.
|
|
81
|
+
|
|
82
|
+
Two things are compared and two are deliberately not:
|
|
83
|
+
|
|
84
|
+
- **a file the scaffold writes that the repo has never had** — drift;
|
|
85
|
+
- **a key inside a JSON file the repo does have** — drift, named as `file → a.b.c`;
|
|
86
|
+
- a file's **contents** — never. A repo that has been worked in has rewritten them and was entitled to;
|
|
87
|
+
- a **value** — never. `doctor.corpus` pointing somewhere else is that repo's answer, not a drift.
|
|
88
|
+
|
|
89
|
+
**The workspaces are out of the question.** `packages/core/src/money.ts` is a sample that makes a
|
|
90
|
+
new repo compile, not a shape a repo must hold. Measured over dielime: including them turned 24 real
|
|
91
|
+
findings into 52, thirty of which were about a `packages/ui` that repo does not have.
|
|
92
|
+
|
|
93
|
+
Over dielime — a repo scaffolded before D-054 moved the law — it reads 24, among them `LAW.md`,
|
|
94
|
+
`geonosis.json → law.file`, three architecture rules the plugin has since added, and
|
|
95
|
+
`gate-baseline.json`. `proofs/024-W31a-create-check/` has the whole run and the before/after hash.
|
|
96
|
+
|
|
97
|
+
A JSON file the repo has that is not plain JSON — dielime's `tsconfig.json` carries `//` comments,
|
|
98
|
+
legal JSONC — is reported rather than skipped. A check that could not read a file has not passed
|
|
99
|
+
over it.
|
|
100
|
+
|
|
71
101
|
## Proven, not claimed
|
|
72
102
|
|
|
73
103
|
A repo scaffolded on **both** runtimes passes its own `geonosis-verify full` in a temp directory —
|
|
@@ -1,3 +1,116 @@
|
|
|
1
|
+
// src/composition.ts
|
|
2
|
+
var PLATFORM_FILE = "src/platform.ts";
|
|
3
|
+
var SEARCH = {
|
|
4
|
+
at: "domains/search",
|
|
5
|
+
built: [
|
|
6
|
+
" search: pgFtsSearchIndex({",
|
|
7
|
+
" executor: tx,",
|
|
8
|
+
" nowMs: definitions.nowMs,",
|
|
9
|
+
" projections: SEARCH_PROJECTIONS,",
|
|
10
|
+
" }),"
|
|
11
|
+
],
|
|
12
|
+
declarations: [
|
|
13
|
+
"/** How each kind this repo indexes becomes searchable text \u2014 declared once, never per call. */",
|
|
14
|
+
"const SEARCH_PROJECTIONS: SearchProjections<'note'> = {",
|
|
15
|
+
" note: {",
|
|
16
|
+
" body: (fields) => fields.notes ?? '',",
|
|
17
|
+
" title: (fields) => fields.heading ?? '',",
|
|
18
|
+
" },",
|
|
19
|
+
"}"
|
|
20
|
+
],
|
|
21
|
+
field: "search",
|
|
22
|
+
fieldType: "SearchIndex<'note'>",
|
|
23
|
+
imports: [
|
|
24
|
+
"import { pgFtsSearchIndex, type SearchIndex, type SearchProjections } from '@geonosis/search'"
|
|
25
|
+
],
|
|
26
|
+
name: "@geonosis/search",
|
|
27
|
+
version: "0.1.1"
|
|
28
|
+
};
|
|
29
|
+
var DOMAINS = [SEARCH];
|
|
30
|
+
var DOMAIN_NAMES = DOMAINS.map((one) => one.field);
|
|
31
|
+
var FOUNDATIONS = [
|
|
32
|
+
{ at: "foundations/db", name: "@geonosis/db", version: "0.2.0" },
|
|
33
|
+
{ at: "foundations/events", name: "@geonosis/events", version: "1.5.0" }
|
|
34
|
+
];
|
|
35
|
+
var domainsNamed = (named) => named.map((one) => {
|
|
36
|
+
const found = DOMAINS.find((domain) => domain.field === one);
|
|
37
|
+
if (found === void 0) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
`--domains "${one}" is not a domain this kit ships \u2014 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.`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
return found;
|
|
43
|
+
});
|
|
44
|
+
var floorDependencies = (named) => named.length === 0 ? {} : Object.fromEntries(
|
|
45
|
+
[...FOUNDATIONS, ...domainsNamed(named)].map((one) => [one.name, `^${one.version}`]).toSorted(([a], [b]) => String(a).localeCompare(String(b)))
|
|
46
|
+
);
|
|
47
|
+
var floorDirectories = (named) => named.length === 0 ? [] : [...FOUNDATIONS, ...domainsNamed(named)].map((one) => one.at);
|
|
48
|
+
var platformSource = (named) => {
|
|
49
|
+
const domains = domainsNamed(named);
|
|
50
|
+
return [
|
|
51
|
+
"import { createSessionSeam, type Executor, type SessionSeam } from '@geonosis/db'",
|
|
52
|
+
"import { createEmitDoor, type EmitDoor, type Extensions } from '@geonosis/events'",
|
|
53
|
+
...domains.flatMap((one) => one.imports),
|
|
54
|
+
"",
|
|
55
|
+
"/** Every name a foundation cannot pick for this repo, answered here and only here. */",
|
|
56
|
+
"export type PlatformConfig = {",
|
|
57
|
+
" newId: () => string",
|
|
58
|
+
" nowMs: () => number",
|
|
59
|
+
" /** What maintenance sets to see every tenant, through a lever no request path reaches. */",
|
|
60
|
+
" opsSetting: string",
|
|
61
|
+
" /** The producer every envelope names (D-057) \u2014 spelled here, never at an emit call. */",
|
|
62
|
+
" source: string",
|
|
63
|
+
" /** What a transaction sets to name its tenant, and what the RLS policies read. */",
|
|
64
|
+
" tenantSetting: string",
|
|
65
|
+
"}",
|
|
66
|
+
"",
|
|
67
|
+
"export type Definitions = {",
|
|
68
|
+
" emit: EmitDoor<Extensions>",
|
|
69
|
+
" nowMs: () => number",
|
|
70
|
+
" session: SessionSeam",
|
|
71
|
+
"}",
|
|
72
|
+
"",
|
|
73
|
+
"/** Once per isolate: what this platform is, before anybody has asked it anything. */",
|
|
74
|
+
"export const definitionsOf = (config: PlatformConfig): Definitions => ({",
|
|
75
|
+
" emit: createEmitDoor({",
|
|
76
|
+
" extensions: [],",
|
|
77
|
+
" newId: config.newId,",
|
|
78
|
+
" now: config.nowMs,",
|
|
79
|
+
" source: config.source,",
|
|
80
|
+
" }),",
|
|
81
|
+
" nowMs: config.nowMs,",
|
|
82
|
+
" session: createSessionSeam({",
|
|
83
|
+
" settings: { opsSetting: config.opsSetting, tenantSetting: config.tenantSetting },",
|
|
84
|
+
" }),",
|
|
85
|
+
"})",
|
|
86
|
+
"",
|
|
87
|
+
...domains.flatMap((one) => [...one.declarations, ""]),
|
|
88
|
+
"/** Who is asking, and the connection they may ask on. */",
|
|
89
|
+
"export type Caller = { connection: Executor; tenantId: string }",
|
|
90
|
+
"",
|
|
91
|
+
"/** Every domain this repo composed, built for one caller. */",
|
|
92
|
+
"export type Scope = {",
|
|
93
|
+
...domains.map((one) => ` ${one.field}: ${one.fieldType}`),
|
|
94
|
+
"}",
|
|
95
|
+
"",
|
|
96
|
+
"/**",
|
|
97
|
+
" * Per request. The tenant session opens FIRST and the stores are built inside it, so a store",
|
|
98
|
+
" * that could run outside the transaction that named its tenant does not exist to be held.",
|
|
99
|
+
" */",
|
|
100
|
+
"export const inScope = async <Result>(",
|
|
101
|
+
" definitions: Definitions,",
|
|
102
|
+
" caller: Caller,",
|
|
103
|
+
" run: (scope: Scope) => Promise<Result>,",
|
|
104
|
+
"): Promise<Result> =>",
|
|
105
|
+
" definitions.session.inTenant(caller.connection, caller.tenantId, async (tx) =>",
|
|
106
|
+
" run({",
|
|
107
|
+
...domains.flatMap((one) => [...one.built]),
|
|
108
|
+
" }),",
|
|
109
|
+
" )",
|
|
110
|
+
""
|
|
111
|
+
].join("\n");
|
|
112
|
+
};
|
|
113
|
+
|
|
1
114
|
// src/answers.ts
|
|
2
115
|
import { basename, resolve } from "path";
|
|
3
116
|
var RUNTIMES = ["bun", "pnpm"];
|
|
@@ -6,13 +119,14 @@ var UIS = ["atoms-only", "none", "tiered-shadcn"];
|
|
|
6
119
|
var VALUED = /* @__PURE__ */ new Set([
|
|
7
120
|
"--backend",
|
|
8
121
|
"--brand",
|
|
122
|
+
"--domains",
|
|
9
123
|
"--kit",
|
|
10
124
|
"--marketplace",
|
|
11
125
|
"--runtime",
|
|
12
126
|
"--themekit",
|
|
13
127
|
"--ui"
|
|
14
128
|
]);
|
|
15
|
-
var SWITCHES = /* @__PURE__ */ new Set(["--help", "-h", "--no-install"]);
|
|
129
|
+
var SWITCHES = /* @__PURE__ */ new Set(["--check", "--help", "-h", "--no-install"]);
|
|
16
130
|
var read = (argv) => {
|
|
17
131
|
const flags = {};
|
|
18
132
|
let dir;
|
|
@@ -53,16 +167,23 @@ var choose = (flag, given, allowed) => {
|
|
|
53
167
|
return given;
|
|
54
168
|
};
|
|
55
169
|
var scopeOf = (name) => `@${name.toLowerCase().replaceAll(/[^a-z0-9-]/g, "-")}`;
|
|
170
|
+
var domainsFrom = (given) => {
|
|
171
|
+
const named = (given ?? "").split(",").map((one) => one.trim()).filter((one) => one !== "");
|
|
172
|
+
domainsNamed(named);
|
|
173
|
+
return named;
|
|
174
|
+
};
|
|
56
175
|
var parseAnswers = (argv, cwd) => {
|
|
57
176
|
const { dir, flags } = read(argv);
|
|
58
177
|
if (dir === void 0) {
|
|
59
178
|
throw new Error("create-geonosis needs a directory to write the repo into");
|
|
60
179
|
}
|
|
61
180
|
const name = basename(resolve(cwd, dir));
|
|
181
|
+
const domains = domainsFrom(flags["--domains"]);
|
|
62
182
|
return {
|
|
63
183
|
backend: choose("--backend", flags["--backend"], BACKENDS),
|
|
64
184
|
...flags["--brand"] === void 0 ? {} : { brand: flags["--brand"] },
|
|
65
185
|
dir: resolve(cwd, dir),
|
|
186
|
+
domains,
|
|
66
187
|
...flags["--kit"] === void 0 ? {} : { kit: resolve(cwd, flags["--kit"]) },
|
|
67
188
|
...flags["--marketplace"] === void 0 ? {} : { marketplace: flags["--marketplace"] },
|
|
68
189
|
name,
|
|
@@ -263,15 +384,20 @@ var workspacesOf = (answers) => {
|
|
|
263
384
|
dir: "apps/web",
|
|
264
385
|
mayDependOn: list.map((one) => one.tag),
|
|
265
386
|
name: `${scope}/web`,
|
|
266
|
-
|
|
387
|
+
packages: floorDependencies(answers.domains),
|
|
388
|
+
sources: {
|
|
389
|
+
"src/boot.ts": APP(scope, ui !== "none"),
|
|
390
|
+
"src/boot.test.ts": APP_TEST,
|
|
391
|
+
...answers.domains.length === 0 ? {} : { [PLATFORM_FILE]: platformSource(answers.domains) }
|
|
392
|
+
},
|
|
267
393
|
tag: "app"
|
|
268
394
|
});
|
|
269
395
|
return list;
|
|
270
396
|
};
|
|
271
397
|
|
|
272
398
|
// src/files.ts
|
|
273
|
-
import { countersFor, rulesFor } from "@geonosis/cli";
|
|
274
|
-
var VERSION = "
|
|
399
|
+
import { countersFor, LAW_SOURCE, rulesFor, tiersFor } from "@geonosis/cli";
|
|
400
|
+
var VERSION = "2.0.0";
|
|
275
401
|
var SCHEMA = "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json";
|
|
276
402
|
var CATALOG = {
|
|
277
403
|
"@types/node": "^24.3.0",
|
|
@@ -364,12 +490,17 @@ var workspaceManifest = (workspace, answers, workspaces) => {
|
|
|
364
490
|
typescript: "catalog:",
|
|
365
491
|
vitest: "catalog:"
|
|
366
492
|
},
|
|
367
|
-
dependencies:
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
493
|
+
dependencies: {
|
|
494
|
+
...Object.fromEntries(
|
|
495
|
+
workspace.mayDependOn.flatMap((tag) => {
|
|
496
|
+
const found = workspaces.find((one) => one.tag === tag);
|
|
497
|
+
return found === void 0 || found.name === workspace.name ? [] : [[found.name, "workspace:*"]];
|
|
498
|
+
})
|
|
499
|
+
),
|
|
500
|
+
// With --kit the floors are linked from a workspace AFTER the install, and the manifest is
|
|
501
|
+
// rewritten to say so — the same reason the root's kit versions are left out.
|
|
502
|
+
...answers.kit === void 0 ? workspace.packages : {}
|
|
503
|
+
}
|
|
373
504
|
});
|
|
374
505
|
};
|
|
375
506
|
var kitDependencies = (answers) => ({
|
|
@@ -381,6 +512,17 @@ var kitDependencies = (answers) => ({
|
|
|
381
512
|
"@geonosis/verify": `^${VERSION}`,
|
|
382
513
|
...answers.themekit === void 0 ? {} : { "@geonosis/themekit": `^${VERSION}` }
|
|
383
514
|
});
|
|
515
|
+
var rootScripts = ({ runtime }) => ({
|
|
516
|
+
doctor: "geonosis-doctor",
|
|
517
|
+
"format:check": "oxfmt --config .oxfmtrc.json --check .",
|
|
518
|
+
format: "oxfmt --config .oxfmtrc.json .",
|
|
519
|
+
lint: "oxlint --config .oxlintrc.json .",
|
|
520
|
+
ratchet: "geonosis-ratchet",
|
|
521
|
+
sync: "geonosis sync",
|
|
522
|
+
test: everyWorkspace(runtime, "test"),
|
|
523
|
+
typecheck: everyWorkspace(runtime, "typecheck"),
|
|
524
|
+
verify: "geonosis-verify"
|
|
525
|
+
});
|
|
384
526
|
var rootManifest = (answers) => {
|
|
385
527
|
const { runtime } = answers;
|
|
386
528
|
const globs = ["apps/*", "packages/*"];
|
|
@@ -395,17 +537,7 @@ var rootManifest = (answers) => {
|
|
|
395
537
|
packages: globs
|
|
396
538
|
}
|
|
397
539
|
} : {},
|
|
398
|
-
scripts:
|
|
399
|
-
doctor: "geonosis-doctor",
|
|
400
|
-
"format:check": "oxfmt --config .oxfmtrc.json --check .",
|
|
401
|
-
format: "oxfmt --config .oxfmtrc.json .",
|
|
402
|
-
lint: "oxlint --config .oxlintrc.json .",
|
|
403
|
-
ratchet: "geonosis-ratchet",
|
|
404
|
-
sync: "geonosis sync",
|
|
405
|
-
test: everyWorkspace(runtime, "test"),
|
|
406
|
-
typecheck: everyWorkspace(runtime, "typecheck"),
|
|
407
|
-
verify: "geonosis-verify"
|
|
408
|
-
},
|
|
540
|
+
scripts: rootScripts(answers),
|
|
409
541
|
devDependencies: {
|
|
410
542
|
// With --kit the kit is linked from a workspace AFTER the install, and the manifest is
|
|
411
543
|
// rewritten to say so. Declaring published versions here would make the install go looking
|
|
@@ -540,6 +672,9 @@ var ci = (answers) => [
|
|
|
540
672
|
"jobs:",
|
|
541
673
|
" verify:",
|
|
542
674
|
" runs-on: ubuntu-latest",
|
|
675
|
+
// #161: a job with no ceiling ran three hours before failing in a consumer. The runner's
|
|
676
|
+
// timeout is not the repo's budget — it is what stops a gate nobody can see from billing.
|
|
677
|
+
" timeout-minutes: 30",
|
|
543
678
|
" steps:",
|
|
544
679
|
" - uses: actions/checkout@v4",
|
|
545
680
|
...answers.runtime === "bun" ? [" - uses: oven-sh/setup-bun@v2", " - run: bun install --frozen-lockfile"] : [
|
|
@@ -587,12 +722,16 @@ var tsconfigBase = (answers) => json({
|
|
|
587
722
|
});
|
|
588
723
|
var filesFor = (answers) => {
|
|
589
724
|
const workspaces = workspacesOf(answers);
|
|
590
|
-
const counters = countersFor(answers.runtime);
|
|
725
|
+
const counters = countersFor(answers.runtime, LAW_SOURCE);
|
|
591
726
|
const { rules } = rulesFor(presetsFor(answers), answersForRules(answers));
|
|
592
727
|
const files = {
|
|
593
728
|
"package.json": rootManifest(answers),
|
|
594
729
|
...answers.runtime === "pnpm" ? { "pnpm-workspace.yaml": workspaceYaml(answers) } : {},
|
|
595
|
-
|
|
730
|
+
// D-054 from day one: the law is written once, CLAUDE.md imports it, and the three
|
|
731
|
+
// declarations below point at the same file — a repo with nothing to migrate later.
|
|
732
|
+
[LAW_SOURCE]: law(answers),
|
|
733
|
+
"CLAUDE.md": `@${LAW_SOURCE}
|
|
734
|
+
`,
|
|
596
735
|
"docs/architecture.md": architecture(answers, workspaces),
|
|
597
736
|
"docs/pipelines/order-placed.md": pipeline(answers),
|
|
598
737
|
".github/workflows/ci.yml": ci(answers),
|
|
@@ -628,19 +767,16 @@ var filesFor = (answers) => {
|
|
|
628
767
|
ignorePatterns: ["node_modules", "dist", "coverage", CORPUS_DIR]
|
|
629
768
|
}),
|
|
630
769
|
"geonosis.json": json({
|
|
631
|
-
verify: {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
)
|
|
635
|
-
|
|
636
|
-
"fast",
|
|
637
|
-
answers.runtime === "bun" ? "bun run format:check" : "pnpm format:check",
|
|
638
|
-
answers.runtime === "bun" ? "bun run ratchet" : "pnpm ratchet"
|
|
639
|
-
]
|
|
640
|
-
},
|
|
770
|
+
verify: tiersFor({
|
|
771
|
+
rules,
|
|
772
|
+
runtime: answers.runtime,
|
|
773
|
+
scripts: Object.keys(rootScripts(answers))
|
|
774
|
+
}),
|
|
641
775
|
doctor: { corpus: CORPUS_DIR },
|
|
776
|
+
law: { file: LAW_SOURCE },
|
|
642
777
|
ledger: {
|
|
643
778
|
architecture: "docs/architecture.md",
|
|
779
|
+
law: LAW_SOURCE,
|
|
644
780
|
plans: "plans",
|
|
645
781
|
progress: "plans/PROGRESS.md",
|
|
646
782
|
proofs: "proofs"
|
|
@@ -718,10 +854,62 @@ var filesFor = (answers) => {
|
|
|
718
854
|
};
|
|
719
855
|
var presetsChosenBy = presetsFor;
|
|
720
856
|
|
|
857
|
+
// src/check.ts
|
|
858
|
+
import { existsSync, readFileSync } from "fs";
|
|
859
|
+
import { join } from "path";
|
|
860
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
861
|
+
var pathsIn = (value, prefix = "") => {
|
|
862
|
+
if (!isRecord(value)) return [];
|
|
863
|
+
return Object.entries(value).flatMap(([key, child]) => {
|
|
864
|
+
const here = prefix === "" ? key : `${prefix}.${key}`;
|
|
865
|
+
return [here, ...pathsIn(child, here)];
|
|
866
|
+
});
|
|
867
|
+
};
|
|
868
|
+
var parsed = (body) => {
|
|
869
|
+
try {
|
|
870
|
+
const value = JSON.parse(body);
|
|
871
|
+
return isRecord(value) ? value : void 0;
|
|
872
|
+
} catch {
|
|
873
|
+
return void 0;
|
|
874
|
+
}
|
|
875
|
+
};
|
|
876
|
+
var missingPaths = (want, has) => {
|
|
877
|
+
const held = new Set(pathsIn(has));
|
|
878
|
+
return pathsIn(want).filter((path) => !held.has(path));
|
|
879
|
+
};
|
|
880
|
+
var isCompositionRoot = (file) => file.endsWith(`/${PLATFORM_FILE}`);
|
|
881
|
+
var checkScaffold = (answers) => {
|
|
882
|
+
const drift = [];
|
|
883
|
+
const seeded = workspacesOf(answers).map((one) => `${one.dir}/`);
|
|
884
|
+
for (const [file, body] of Object.entries(filesFor(answers))) {
|
|
885
|
+
if (!isCompositionRoot(file) && seeded.some((prefix) => file.startsWith(prefix))) continue;
|
|
886
|
+
const at = join(answers.dir, file);
|
|
887
|
+
if (!existsSync(at)) {
|
|
888
|
+
drift.push({ at: "", file, kind: "missing" });
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
const want = parsed(body);
|
|
892
|
+
if (want === void 0) continue;
|
|
893
|
+
const has = parsed(readFileSync(at, "utf8"));
|
|
894
|
+
if (has === void 0) {
|
|
895
|
+
drift.push({ at: "", file, kind: "unreadable" });
|
|
896
|
+
continue;
|
|
897
|
+
}
|
|
898
|
+
for (const path of missingPaths(want, has)) drift.push({ at: path, file, kind: "key" });
|
|
899
|
+
}
|
|
900
|
+
return drift;
|
|
901
|
+
};
|
|
902
|
+
var SAID = {
|
|
903
|
+
key: (one) => `${one.file} \u2192 ${one.at} \u2014 the scaffold writes this key and your file has none`,
|
|
904
|
+
missing: (one) => `${one.file} \u2014 the scaffold writes this file and your repo has none`,
|
|
905
|
+
unreadable: (one) => `${one.file} \u2014 the scaffold writes plain JSON here and yours is not (comments? trailing commas?), so this check could not read its keys`
|
|
906
|
+
};
|
|
907
|
+
var describeDrift = (drift) => drift.map((one) => SAID[one.kind](one));
|
|
908
|
+
|
|
721
909
|
// src/scaffold.ts
|
|
722
910
|
import { spawnSync } from "child_process";
|
|
723
|
-
import { chmodSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "fs";
|
|
724
|
-
import { dirname, join } from "path";
|
|
911
|
+
import { chmodSync, existsSync as existsSync2, mkdirSync, readdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
912
|
+
import { dirname, join as join2 } from "path";
|
|
725
913
|
var KIT_PACKAGES = [
|
|
726
914
|
"cli",
|
|
727
915
|
"doctor",
|
|
@@ -733,12 +921,12 @@ var KIT_PACKAGES = [
|
|
|
733
921
|
"verify"
|
|
734
922
|
];
|
|
735
923
|
var write = (dir, file, body) => {
|
|
736
|
-
const path =
|
|
924
|
+
const path = join2(dir, file);
|
|
737
925
|
mkdirSync(dirname(path), { recursive: true });
|
|
738
926
|
writeFileSync(path, body);
|
|
739
927
|
};
|
|
740
928
|
var writeScaffold = (answers) => {
|
|
741
|
-
if (
|
|
929
|
+
if (existsSync2(answers.dir) && readdirSync(answers.dir).length > 0) {
|
|
742
930
|
throw new Error(`${answers.dir} is not empty \u2014 nothing was written`);
|
|
743
931
|
}
|
|
744
932
|
const files = filesFor(answers);
|
|
@@ -755,38 +943,77 @@ var run = (what, dir, command, args) => {
|
|
|
755
943
|
};
|
|
756
944
|
};
|
|
757
945
|
var binsOf = (dir) => {
|
|
758
|
-
const manifest = JSON.parse(
|
|
946
|
+
const manifest = JSON.parse(readFileSync2(join2(dir, "package.json"), "utf8"));
|
|
759
947
|
if (typeof manifest.bin === "string") return [[manifest.name ?? "", manifest.bin]];
|
|
760
948
|
return Object.entries(manifest.bin ?? {});
|
|
761
949
|
};
|
|
950
|
+
var repoint = (path, at, owed) => {
|
|
951
|
+
if (!existsSync2(path)) return [];
|
|
952
|
+
const manifest = JSON.parse(readFileSync2(path, "utf8"));
|
|
953
|
+
const moved = [];
|
|
954
|
+
for (const block of ["dependencies", "devDependencies"]) {
|
|
955
|
+
const declared = manifest[block];
|
|
956
|
+
if (declared === void 0) continue;
|
|
957
|
+
for (const name of Object.keys(declared)) {
|
|
958
|
+
const from = at.get(name);
|
|
959
|
+
if (from === void 0) continue;
|
|
960
|
+
declared[name] = `link:${from}`;
|
|
961
|
+
moved.push(name);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
for (const name of owed) {
|
|
965
|
+
const from = at.get(name);
|
|
966
|
+
if (from === void 0 || moved.includes(name)) continue;
|
|
967
|
+
manifest.dependencies = { ...manifest.dependencies, [name]: `link:${from}` };
|
|
968
|
+
moved.push(name);
|
|
969
|
+
}
|
|
970
|
+
if (moved.length > 0) writeFileSync(path, `${JSON.stringify(manifest, void 0, 2)}
|
|
971
|
+
`);
|
|
972
|
+
return moved;
|
|
973
|
+
};
|
|
762
974
|
var linkKit = (answers, kit) => {
|
|
763
|
-
const modules =
|
|
764
|
-
const scope =
|
|
765
|
-
const bin =
|
|
975
|
+
const modules = join2(answers.dir, "node_modules");
|
|
976
|
+
const scope = join2(modules, "@geonosis");
|
|
977
|
+
const bin = join2(modules, ".bin");
|
|
766
978
|
mkdirSync(scope, { recursive: true });
|
|
767
979
|
mkdirSync(bin, { recursive: true });
|
|
768
980
|
const linked = [];
|
|
769
|
-
const
|
|
770
|
-
const
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
981
|
+
const at = /* @__PURE__ */ new Map();
|
|
982
|
+
const manifestPath = join2(answers.dir, "package.json");
|
|
983
|
+
const manifest = JSON.parse(readFileSync2(manifestPath, "utf8"));
|
|
984
|
+
for (const relative of [
|
|
985
|
+
...KIT_PACKAGES.map((name) => `packages/${name}`),
|
|
986
|
+
...floorDirectories(answers.domains)
|
|
987
|
+
]) {
|
|
988
|
+
const from = join2(kit, relative);
|
|
989
|
+
if (!existsSync2(from)) continue;
|
|
990
|
+
const declared = JSON.parse(readFileSync2(join2(from, "package.json"), "utf8"));
|
|
991
|
+
if (declared.name === void 0) continue;
|
|
992
|
+
const to = join2(scope, declared.name.replace("@geonosis/", ""));
|
|
993
|
+
if (!existsSync2(to)) spawnSync("ln", ["-s", from, to]);
|
|
994
|
+
for (const [called, entry] of binsOf(from)) {
|
|
995
|
+
const shim = join2(bin, called);
|
|
780
996
|
writeFileSync(shim, `#!/bin/sh
|
|
781
|
-
exec node "${
|
|
997
|
+
exec node "${join2(from, entry)}" "$@"
|
|
782
998
|
`);
|
|
783
999
|
chmodSync(shim, 493);
|
|
784
1000
|
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
1001
|
+
at.set(declared.name, from);
|
|
1002
|
+
linked.push(relative);
|
|
1003
|
+
}
|
|
1004
|
+
const owned = new Set(
|
|
1005
|
+
workspacesOf(answers).flatMap(
|
|
1006
|
+
(workspace) => repoint(
|
|
1007
|
+
join2(answers.dir, workspace.dir, "package.json"),
|
|
1008
|
+
at,
|
|
1009
|
+
Object.keys(workspace.packages ?? {})
|
|
1010
|
+
)
|
|
1011
|
+
)
|
|
1012
|
+
);
|
|
1013
|
+
for (const [name, from] of at) {
|
|
1014
|
+
if (!owned.has(name)) {
|
|
1015
|
+
manifest.devDependencies = { ...manifest.devDependencies, [name]: `link:${from}` };
|
|
788
1016
|
}
|
|
789
|
-
linked.push(name);
|
|
790
1017
|
}
|
|
791
1018
|
writeFileSync(manifestPath, `${JSON.stringify(manifest, void 0, 2)}
|
|
792
1019
|
`);
|
|
@@ -813,8 +1040,8 @@ var finish = ({ answers, install }) => {
|
|
|
813
1040
|
what: `link the kit from ${answers.kit}`
|
|
814
1041
|
});
|
|
815
1042
|
}
|
|
816
|
-
const ledger =
|
|
817
|
-
if (
|
|
1043
|
+
const ledger = join2(answers.dir, "node_modules/.bin/geonosis-ledger");
|
|
1044
|
+
if (existsSync2(ledger)) {
|
|
818
1045
|
steps.push(
|
|
819
1046
|
run("sync the edges table into turbo.json", answers.dir, ledger, [
|
|
820
1047
|
"sync",
|
|
@@ -832,14 +1059,22 @@ var finish = ({ answers, install }) => {
|
|
|
832
1059
|
])
|
|
833
1060
|
);
|
|
834
1061
|
}
|
|
835
|
-
const oxfmt =
|
|
836
|
-
if (
|
|
1062
|
+
const oxfmt = join2(answers.dir, "node_modules/.bin/oxfmt");
|
|
1063
|
+
if (existsSync2(oxfmt)) {
|
|
837
1064
|
steps.push(run("format", answers.dir, oxfmt, ["--config", ".oxfmtrc.json", "."]));
|
|
838
1065
|
}
|
|
839
1066
|
return steps;
|
|
840
1067
|
};
|
|
841
1068
|
|
|
842
1069
|
export {
|
|
1070
|
+
PLATFORM_FILE,
|
|
1071
|
+
DOMAINS,
|
|
1072
|
+
DOMAIN_NAMES,
|
|
1073
|
+
FOUNDATIONS,
|
|
1074
|
+
domainsNamed,
|
|
1075
|
+
floorDependencies,
|
|
1076
|
+
floorDirectories,
|
|
1077
|
+
platformSource,
|
|
843
1078
|
RUNTIMES,
|
|
844
1079
|
BACKENDS,
|
|
845
1080
|
UIS,
|
|
@@ -850,6 +1085,8 @@ export {
|
|
|
850
1085
|
workspacesOf,
|
|
851
1086
|
filesFor,
|
|
852
1087
|
presetsChosenBy,
|
|
1088
|
+
checkScaffold,
|
|
1089
|
+
describeDrift,
|
|
853
1090
|
KIT_PACKAGES,
|
|
854
1091
|
writeScaffold,
|
|
855
1092
|
linkKit,
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DOMAIN_NAMES,
|
|
3
|
+
PLATFORM_FILE,
|
|
4
|
+
checkScaffold,
|
|
5
|
+
describeDrift,
|
|
2
6
|
finish,
|
|
3
7
|
parseAnswers,
|
|
4
8
|
wantsInstall,
|
|
5
9
|
writeScaffold
|
|
6
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-PRX7MKFZ.js";
|
|
7
11
|
|
|
8
12
|
// src/create-geonosis-cli.ts
|
|
13
|
+
import { existsSync } from "fs";
|
|
9
14
|
var USAGE = `create-geonosis <dir> --runtime pnpm|bun --backend medusa|sagaflow-cf|none --ui tiered-shadcn|atoms-only|none
|
|
10
|
-
[--brand <name>] [--themekit <name>] [--marketplace <path>] [--kit <path>] [--no-install]
|
|
15
|
+
[--domains <a,b>] [--brand <name>] [--themekit <name>] [--marketplace <path>] [--kit <path>] [--no-install]
|
|
16
|
+
[--check]
|
|
11
17
|
|
|
12
18
|
Writes a repo that passes its own gates on day one: a workspace with one catalog of shared versions,
|
|
13
19
|
an exports map and no barrel in every package, typecheck + lint + test scripts in every workspace,
|
|
@@ -18,13 +24,20 @@ skills lock, and a reach corpus in this repo's own vocabulary so the doctor can
|
|
|
18
24
|
There is no default for --runtime, --backend or --ui. Each one decides the shape of the tree, and a
|
|
19
25
|
default borrowed from another repo would be that repo's stack hardcoded into this one.
|
|
20
26
|
|
|
27
|
+
--domains the domains this repo composes \u2014 ${DOMAIN_NAMES.join(", ")}. Each one writes its
|
|
28
|
+
store into the app's ${PLATFORM_FILE}: the composition root, in two lifetimes, with
|
|
29
|
+
the tenant session opened before any store is built. A name nothing ships is refused.
|
|
21
30
|
--kit <path> read the kit from a workspace instead of the registry. A proof aid: it symlinks the
|
|
22
31
|
packages after the install and rewrites the manifest to say so.
|
|
23
32
|
--no-install write the files and stop. The gates cannot run until the two "geonosis sync
|
|
24
33
|
--target" commands below have been run, and they are printed for you.
|
|
34
|
+
--check say what an EXISTING repo is missing of what the scaffold writes today, and WRITE
|
|
35
|
+
NOTHING. Files it has never had, and keys inside the JSON it has. Contents and
|
|
36
|
+
values are never compared: a repo that has been worked in has rewritten them, and
|
|
37
|
+
it was entitled to. Exit 1 when anything drifted.
|
|
25
38
|
|
|
26
|
-
Exit: 0 written \xB7 1 refused (a directory with something in it, an
|
|
27
|
-
that could not be made at all.`;
|
|
39
|
+
Exit: 0 written (or, under --check, no drift) \xB7 1 refused (a directory with something in it, an
|
|
40
|
+
answer that is not one) or drift found \xB7 2 a run that could not be made at all.`;
|
|
28
41
|
var CONFIG_SHAPE = `create-geonosis reads no configuration file.
|
|
29
42
|
|
|
30
43
|
It WRITES them: geonosis.json, .oxlintrc.json, geonosis.ratchet.json and gate-baseline.json, from
|
|
@@ -45,6 +58,24 @@ var main = () => {
|
|
|
45
58
|
return argv.length === 0 ? 2 : 0;
|
|
46
59
|
}
|
|
47
60
|
const answers = parseAnswers(argv, process.cwd());
|
|
61
|
+
if (argv.includes("--check")) {
|
|
62
|
+
if (!existsSync(answers.dir)) {
|
|
63
|
+
throw new Error(`${answers.dir} is not there \u2014 --check reads a repo, it never makes one`);
|
|
64
|
+
}
|
|
65
|
+
const drift = checkScaffold(answers);
|
|
66
|
+
if (drift.length === 0) {
|
|
67
|
+
process.stdout.write(`create-geonosis --check ${answers.dir} \u2014 no drift
|
|
68
|
+
`);
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
for (const line of describeDrift(drift)) process.stderr.write(` ${line}
|
|
72
|
+
`);
|
|
73
|
+
process.stderr.write(
|
|
74
|
+
`create-geonosis --check ${answers.dir} \u2014 ${drift.length} drift, nothing written
|
|
75
|
+
`
|
|
76
|
+
);
|
|
77
|
+
return 1;
|
|
78
|
+
}
|
|
48
79
|
const written = writeScaffold(answers);
|
|
49
80
|
process.stdout.write(`create-geonosis \u2014 ${written.length} file(s) into ${answers.dir}
|
|
50
81
|
`);
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ type Answers = {
|
|
|
8
8
|
backend: Backend;
|
|
9
9
|
brand?: string;
|
|
10
10
|
dir: string;
|
|
11
|
+
/** The domains this repo composes at its composition root. Empty until the flag names one. */
|
|
12
|
+
domains: string[];
|
|
11
13
|
/** The kit read from a workspace instead of the registry — a proof aid, never the default. */
|
|
12
14
|
kit?: string;
|
|
13
15
|
marketplace?: string;
|
|
@@ -20,11 +22,84 @@ type Answers = {
|
|
|
20
22
|
declare const parseAnswers: (argv: readonly string[], cwd: string) => Answers;
|
|
21
23
|
declare const wantsInstall: (argv: readonly string[]) => boolean;
|
|
22
24
|
|
|
25
|
+
/**
|
|
26
|
+
* What an existing repo never receives: whatever the scaffold has learned since it was run.
|
|
27
|
+
*
|
|
28
|
+
* The comparison is over SHAPE and not over content, because a repo that has been worked in has
|
|
29
|
+
* legitimately rewritten every file the scaffold gave it. What it cannot have legitimately done is
|
|
30
|
+
* lose a file the scaffold now writes, or miss a declaration a new gate reads — so a missing path is
|
|
31
|
+
* drift and a changed value never is.
|
|
32
|
+
*/
|
|
33
|
+
type DriftKind = 'key' | 'missing' | 'unreadable';
|
|
34
|
+
type Drift = {
|
|
35
|
+
/** The key path inside the file, or `''` when the fact is about the whole file. */
|
|
36
|
+
at: string;
|
|
37
|
+
file: string;
|
|
38
|
+
kind: DriftKind;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The drift between a tree and what the scaffold would write into it today. Reads only.
|
|
42
|
+
*
|
|
43
|
+
* Nothing in this module opens a file for writing, and nothing calls `writeScaffold`. That is the
|
|
44
|
+
* whole contract of `--check`: it is run against a repo somebody is working in.
|
|
45
|
+
*/
|
|
46
|
+
declare const checkScaffold: (answers: Answers) => Drift[];
|
|
47
|
+
declare const describeDrift: (drift: readonly Drift[]) => string[];
|
|
48
|
+
|
|
49
|
+
/** Where the composition root lives, relative to the workspace that composes: the app. */
|
|
50
|
+
declare const PLATFORM_FILE = "src/platform.ts";
|
|
51
|
+
/**
|
|
52
|
+
* A domain the kit ships, and the two lines composing it takes.
|
|
53
|
+
*
|
|
54
|
+
* A domain is added here and nowhere else: the flag's vocabulary, the app's dependencies and the
|
|
55
|
+
* generated file all read this table, so a domain that ships without a way to compose it cannot be
|
|
56
|
+
* offered by name. `version` is the floor package's OWN line — the method's number says nothing
|
|
57
|
+
* about it (D-053) — and `tooling/floor-scaffold-versions.test.ts` holds each against the workspace.
|
|
58
|
+
*/
|
|
59
|
+
type DomainScaffold = {
|
|
60
|
+
/** Where the package sits in the kit's tree, for `--kit`'s workspace links. */
|
|
61
|
+
at: string;
|
|
62
|
+
/** What the scope field is called, and the type it is annotated with. */
|
|
63
|
+
field: string;
|
|
64
|
+
/** Everything the generated file needs above the composition itself. */
|
|
65
|
+
declarations: readonly string[];
|
|
66
|
+
fieldType: string;
|
|
67
|
+
imports: readonly string[];
|
|
68
|
+
name: string;
|
|
69
|
+
/** How the store is built, once the tenant's transaction is already open. */
|
|
70
|
+
built: readonly string[];
|
|
71
|
+
version: string;
|
|
72
|
+
};
|
|
73
|
+
declare const DOMAINS: readonly DomainScaffold[];
|
|
74
|
+
declare const DOMAIN_NAMES: readonly string[];
|
|
75
|
+
/** The two foundations a composition root is built from, whichever domains it composes. */
|
|
76
|
+
declare const FOUNDATIONS: readonly {
|
|
77
|
+
at: string;
|
|
78
|
+
name: string;
|
|
79
|
+
version: string;
|
|
80
|
+
}[];
|
|
81
|
+
declare const domainsNamed: (named: readonly string[]) => DomainScaffold[];
|
|
82
|
+
/** What the composing workspace declares once a domain is named. */
|
|
83
|
+
declare const floorDependencies: (named: readonly string[]) => Record<string, string>;
|
|
84
|
+
/** Every kit directory a `--kit` link has to reach for the domains this repo named. */
|
|
85
|
+
declare const floorDirectories: (named: readonly string[]) => string[];
|
|
86
|
+
/**
|
|
87
|
+
* The composition root, in the two lifetimes it has.
|
|
88
|
+
*
|
|
89
|
+
* DEFINITIONS are what this deployment IS — wired once per isolate, before anybody has asked
|
|
90
|
+
* anything. SCOPE is who is asking, bound per request. Keeping them apart is what lets the session
|
|
91
|
+
* come first: the stores are built INSIDE the tenant's transaction, so a caller cannot hold one
|
|
92
|
+
* that was made without a session to run in (D-014 — structural, never an assertion).
|
|
93
|
+
*/
|
|
94
|
+
declare const platformSource: (named: readonly string[]) => string;
|
|
95
|
+
|
|
23
96
|
type Workspace = {
|
|
24
97
|
dir: string;
|
|
25
98
|
/** The files under this workspace, keyed by path relative to the workspace. */
|
|
26
99
|
sources: Record<string, string>;
|
|
27
100
|
name: string;
|
|
101
|
+
/** Packages outside the workspace this one declares, spec and all. */
|
|
102
|
+
packages?: Record<string, string>;
|
|
28
103
|
tag: string;
|
|
29
104
|
mayDependOn: string[];
|
|
30
105
|
};
|
|
@@ -74,7 +149,7 @@ type Step = {
|
|
|
74
149
|
* and tries to resolve the `workspace:*` specifiers the kit's own packages use. Symlinking the
|
|
75
150
|
* directories and writing the bin shims is the one form of the answer that is true on both.
|
|
76
151
|
*
|
|
77
|
-
* The
|
|
152
|
+
* The manifests are then told what is on disk, because `geonosis-doctor` FAILS a config whose plugin
|
|
78
153
|
* no manifest declares — and it should. A link is a declaration it accepts and can verify.
|
|
79
154
|
*/
|
|
80
155
|
declare const linkKit: (answers: Answers, kit: string) => string[];
|
|
@@ -90,4 +165,4 @@ declare const finish: ({ answers, install }: {
|
|
|
90
165
|
install: boolean;
|
|
91
166
|
}) => Step[];
|
|
92
167
|
|
|
93
|
-
export { type Answers, BACKENDS, type Backend, CORPUS_DIR, KIT_PACKAGES, RUNTIMES, type Runtime, type Step, UIS, type Ui, type Workspace, corpusFor, filesFor, finish, linkKit, parseAnswers, presetsChosenBy, wantsInstall, workspacesOf, writeScaffold };
|
|
168
|
+
export { type Answers, BACKENDS, type Backend, CORPUS_DIR, DOMAINS, DOMAIN_NAMES, type DomainScaffold, type Drift, type DriftKind, FOUNDATIONS, KIT_PACKAGES, PLATFORM_FILE, RUNTIMES, type Runtime, type Step, UIS, type Ui, type Workspace, checkScaffold, corpusFor, describeDrift, domainsNamed, filesFor, finish, floorDependencies, floorDirectories, linkKit, parseAnswers, platformSource, presetsChosenBy, wantsInstall, workspacesOf, writeScaffold };
|
package/dist/index.js
CHANGED
|
@@ -1,30 +1,50 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BACKENDS,
|
|
3
3
|
CORPUS_DIR,
|
|
4
|
+
DOMAINS,
|
|
5
|
+
DOMAIN_NAMES,
|
|
6
|
+
FOUNDATIONS,
|
|
4
7
|
KIT_PACKAGES,
|
|
8
|
+
PLATFORM_FILE,
|
|
5
9
|
RUNTIMES,
|
|
6
10
|
UIS,
|
|
11
|
+
checkScaffold,
|
|
7
12
|
corpusFor,
|
|
13
|
+
describeDrift,
|
|
14
|
+
domainsNamed,
|
|
8
15
|
filesFor,
|
|
9
16
|
finish,
|
|
17
|
+
floorDependencies,
|
|
18
|
+
floorDirectories,
|
|
10
19
|
linkKit,
|
|
11
20
|
parseAnswers,
|
|
21
|
+
platformSource,
|
|
12
22
|
presetsChosenBy,
|
|
13
23
|
wantsInstall,
|
|
14
24
|
workspacesOf,
|
|
15
25
|
writeScaffold
|
|
16
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-PRX7MKFZ.js";
|
|
17
27
|
export {
|
|
18
28
|
BACKENDS,
|
|
19
29
|
CORPUS_DIR,
|
|
30
|
+
DOMAINS,
|
|
31
|
+
DOMAIN_NAMES,
|
|
32
|
+
FOUNDATIONS,
|
|
20
33
|
KIT_PACKAGES,
|
|
34
|
+
PLATFORM_FILE,
|
|
21
35
|
RUNTIMES,
|
|
22
36
|
UIS,
|
|
37
|
+
checkScaffold,
|
|
23
38
|
corpusFor,
|
|
39
|
+
describeDrift,
|
|
40
|
+
domainsNamed,
|
|
24
41
|
filesFor,
|
|
25
42
|
finish,
|
|
43
|
+
floorDependencies,
|
|
44
|
+
floorDirectories,
|
|
26
45
|
linkKit,
|
|
27
46
|
parseAnswers,
|
|
47
|
+
platformSource,
|
|
28
48
|
presetsChosenBy,
|
|
29
49
|
wantsInstall,
|
|
30
50
|
workspacesOf,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-geonosis",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"types": "./dist/index.d.ts",
|
|
5
5
|
"description": "Scaffold a microcompany repo that passes its own geonosis gates on day one.",
|
|
6
6
|
"keywords": [
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"dist"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@geonosis/cli": "
|
|
37
|
+
"@geonosis/cli": "2.0.0"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
|
40
40
|
"node": ">=22"
|