@growthub/create-growthub-local 0.2.2 → 0.2.4
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 +43 -17
- package/bin/create-growthub-local.mjs +191 -45
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,46 +2,72 @@
|
|
|
2
2
|
|
|
3
3
|
`create-growthub-local` is the guided installer for Growthub Local.
|
|
4
4
|
|
|
5
|
+
It now handles three lanes in one command, so a fresh user can get either the
|
|
6
|
+
Paperclip Local App or a Custom Workspace Starter workspace in a single step —
|
|
7
|
+
no second `growthub starter init` call required.
|
|
8
|
+
|
|
5
9
|
## Quickstart
|
|
6
10
|
|
|
7
11
|
```bash
|
|
8
|
-
# Interactive (
|
|
12
|
+
# Interactive discovery hub (kits / templates / workflows / agent harness / settings)
|
|
9
13
|
npm create growthub-local@latest
|
|
10
14
|
|
|
11
|
-
#
|
|
15
|
+
# Paperclip Local App profiles
|
|
12
16
|
npm create growthub-local@latest -- --profile gtm
|
|
13
17
|
npm create growthub-local@latest -- --profile dx
|
|
18
|
+
|
|
19
|
+
# Custom Workspace Starter (zero second step — scaffolds + registers as a fork)
|
|
20
|
+
npm create growthub-local@latest -- --profile workspace --out ./my-workspace
|
|
14
21
|
```
|
|
15
22
|
|
|
16
23
|
## Installer Paths
|
|
17
24
|
|
|
18
|
-
- **
|
|
19
|
-
- runs
|
|
25
|
+
- **Paperclip Local App** (`--profile gtm|dx`)
|
|
26
|
+
- runs `growthub onboard --yes` for the selected surface profile
|
|
27
|
+
- **Custom Workspace Starter** (`--profile workspace`)
|
|
28
|
+
- runs `growthub starter init --out <path>` against the bundled
|
|
29
|
+
`growthub-custom-workspace-starter-v1` kit
|
|
30
|
+
- composes the already-shipping primitives — `copyBundledKitSource`,
|
|
31
|
+
`registerKitFork`, `writeKitForkPolicy`, `appendKitForkTraceEvent`,
|
|
32
|
+
and (optionally) `createFork` via the first-party GitHub integration
|
|
33
|
+
- no cross-package coupling beyond the existing `@growthub/cli` dep pin
|
|
20
34
|
- **Discovery mode** (no profile)
|
|
21
|
-
- opens `growthub discover` so users can
|
|
22
|
-
|
|
23
|
-
- Worker Kits
|
|
24
|
-
- Templates
|
|
35
|
+
- opens `growthub discover` so users can pick Worker Kits, Templates,
|
|
36
|
+
Workflows, Local Intelligence, Agent Harness, Settings, or Help
|
|
25
37
|
|
|
26
38
|
## Options
|
|
27
39
|
|
|
28
|
-
| Flag | Description |
|
|
29
|
-
|
|
30
|
-
| `--profile gtm\|dx` |
|
|
31
|
-
| `--run` | Start
|
|
32
|
-
| `--data-dir <path>` | Override install directory (default: `./growthub-local`) |
|
|
33
|
-
| `--config <path>` | Use a custom config path |
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
| Flag | Applies to | Description |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `--profile gtm\|dx\|workspace` | all | Pick an install lane |
|
|
43
|
+
| `--run` | `dx`, `gtm`, discovery | Start Growthub immediately after saving config |
|
|
44
|
+
| `--data-dir <path>` | `dx`, `gtm`, discovery | Override install directory (default: `./growthub-local`) |
|
|
45
|
+
| `--config <path>` | `dx`, `gtm`, discovery | Use a custom config path |
|
|
46
|
+
| `--out <path>` | `workspace` | Destination directory for the new workspace |
|
|
47
|
+
| `--kit <kit-id>` | `workspace` | Source kit id (default: `growthub-custom-workspace-starter-v1`) |
|
|
48
|
+
| `--name <label>` | `workspace` | Human label for the fork |
|
|
49
|
+
| `--upstream <owner/repo>` | `workspace` | When set, also creates a remote GitHub fork |
|
|
50
|
+
| `--destination-org <org>` | `workspace` | Create the GitHub fork under an org |
|
|
51
|
+
| `--fork-name <name>` | `workspace` | Override the GitHub fork name |
|
|
52
|
+
| `--remote-sync-mode <mode>` | `workspace` | Initial `policy.remoteSyncMode` — `off` (default), `branch`, `pr` |
|
|
53
|
+
| `--json` | `workspace` | Emit machine-readable output from `growthub starter init` |
|
|
54
|
+
|
|
55
|
+
## After install — Paperclip Local App
|
|
36
56
|
|
|
37
57
|
```bash
|
|
38
58
|
cd growthub-local
|
|
39
59
|
npx growthub run
|
|
40
60
|
```
|
|
41
61
|
|
|
42
|
-
|
|
62
|
+
## After install — Custom Workspace Starter
|
|
43
63
|
|
|
44
64
|
```bash
|
|
65
|
+
cd my-workspace
|
|
66
|
+
|
|
67
|
+
# Inspect your new fork (registration + policy + trace)
|
|
68
|
+
npx growthub kit fork status <fork-id>
|
|
69
|
+
|
|
70
|
+
# Re-open the discovery hub any time
|
|
45
71
|
npx growthub
|
|
46
72
|
```
|
|
47
73
|
|
|
@@ -9,50 +9,157 @@ import { fileURLToPath } from "node:url";
|
|
|
9
9
|
const require = createRequire(import.meta.url);
|
|
10
10
|
const __filename = fileURLToPath(import.meta.url);
|
|
11
11
|
|
|
12
|
+
const VALID_PROFILES = new Set(["dx", "gtm", "workspace"]);
|
|
13
|
+
const VALID_REMOTE_SYNC_MODES = new Set(["off", "branch", "pr"]);
|
|
14
|
+
|
|
12
15
|
function printUsage() {
|
|
13
|
-
console.log(
|
|
16
|
+
console.log(
|
|
17
|
+
[
|
|
18
|
+
"Usage:",
|
|
19
|
+
" create-growthub-local [--profile <dx|gtm|workspace>] [--out <path>]",
|
|
20
|
+
" [--data-dir <path>] [--config <path>]",
|
|
21
|
+
" [--run]",
|
|
22
|
+
"",
|
|
23
|
+
"Paperclip Local App profiles (dx | gtm):",
|
|
24
|
+
" create-growthub-local --profile gtm",
|
|
25
|
+
" create-growthub-local --profile dx --data-dir ./my-growthub",
|
|
26
|
+
"",
|
|
27
|
+
"Custom Workspace Starter profile (workspace):",
|
|
28
|
+
" create-growthub-local --profile workspace --out ./my-workspace",
|
|
29
|
+
" create-growthub-local --profile workspace --out ./my-workspace --name \"My Workspace\"",
|
|
30
|
+
" create-growthub-local --profile workspace --out ./my-workspace \\",
|
|
31
|
+
" --upstream Growthub-ai/growthub-custom-workspace-starter-v1 --remote-sync-mode off",
|
|
32
|
+
"",
|
|
33
|
+
"Discovery mode (no profile):",
|
|
34
|
+
" create-growthub-local # opens `growthub discover` picker",
|
|
35
|
+
].join("\n"),
|
|
36
|
+
);
|
|
14
37
|
}
|
|
15
38
|
|
|
16
39
|
function parseArgs(argv) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
40
|
+
const opts = {
|
|
41
|
+
profile: null,
|
|
42
|
+
run: false,
|
|
43
|
+
dataDir: null,
|
|
44
|
+
config: null,
|
|
45
|
+
out: null,
|
|
46
|
+
kit: null,
|
|
47
|
+
name: null,
|
|
48
|
+
upstream: null,
|
|
49
|
+
destinationOrg: null,
|
|
50
|
+
forkName: null,
|
|
51
|
+
remoteSyncMode: null,
|
|
52
|
+
json: false,
|
|
53
|
+
};
|
|
21
54
|
|
|
22
55
|
for (let index = 0; index < argv.length; index += 1) {
|
|
23
56
|
const value = argv[index];
|
|
57
|
+
|
|
24
58
|
if (value === "--profile" && argv[index + 1]) {
|
|
25
|
-
profile = argv[index + 1];
|
|
59
|
+
opts.profile = String(argv[index + 1]).trim();
|
|
26
60
|
index += 1;
|
|
27
61
|
continue;
|
|
28
62
|
}
|
|
29
63
|
if (value === "--run") {
|
|
30
|
-
run = true;
|
|
64
|
+
opts.run = true;
|
|
31
65
|
continue;
|
|
32
66
|
}
|
|
33
67
|
if ((value === "-d" || value === "--data-dir") && argv[index + 1]) {
|
|
34
|
-
dataDir = argv[index + 1];
|
|
68
|
+
opts.dataDir = argv[index + 1];
|
|
35
69
|
index += 1;
|
|
36
70
|
continue;
|
|
37
71
|
}
|
|
38
72
|
if ((value === "-c" || value === "--config") && argv[index + 1]) {
|
|
39
|
-
config = argv[index + 1];
|
|
73
|
+
opts.config = argv[index + 1];
|
|
74
|
+
index += 1;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (value === "--out" && argv[index + 1]) {
|
|
78
|
+
opts.out = argv[index + 1];
|
|
79
|
+
index += 1;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (value === "--kit" && argv[index + 1]) {
|
|
83
|
+
opts.kit = argv[index + 1];
|
|
84
|
+
index += 1;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (value === "--name" && argv[index + 1]) {
|
|
88
|
+
opts.name = argv[index + 1];
|
|
89
|
+
index += 1;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (value === "--upstream" && argv[index + 1]) {
|
|
93
|
+
opts.upstream = argv[index + 1];
|
|
40
94
|
index += 1;
|
|
41
95
|
continue;
|
|
42
96
|
}
|
|
97
|
+
if (value === "--destination-org" && argv[index + 1]) {
|
|
98
|
+
opts.destinationOrg = argv[index + 1];
|
|
99
|
+
index += 1;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (value === "--fork-name" && argv[index + 1]) {
|
|
103
|
+
opts.forkName = argv[index + 1];
|
|
104
|
+
index += 1;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
if (value === "--remote-sync-mode" && argv[index + 1]) {
|
|
108
|
+
opts.remoteSyncMode = String(argv[index + 1]).trim();
|
|
109
|
+
index += 1;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (value === "--json") {
|
|
113
|
+
opts.json = true;
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
43
116
|
if (value === "-h" || value === "--help") {
|
|
44
117
|
printUsage();
|
|
45
118
|
process.exit(0);
|
|
46
119
|
}
|
|
47
120
|
}
|
|
48
121
|
|
|
49
|
-
if (profile !== null && profile
|
|
122
|
+
if (opts.profile !== null && !VALID_PROFILES.has(opts.profile)) {
|
|
123
|
+
printUsage();
|
|
124
|
+
console.error(
|
|
125
|
+
`create-growthub-local only accepts --profile dx | gtm | workspace (got: ${opts.profile})`,
|
|
126
|
+
);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (
|
|
131
|
+
opts.remoteSyncMode !== null
|
|
132
|
+
&& !VALID_REMOTE_SYNC_MODES.has(opts.remoteSyncMode)
|
|
133
|
+
) {
|
|
50
134
|
printUsage();
|
|
51
|
-
console.error(
|
|
135
|
+
console.error(
|
|
136
|
+
`--remote-sync-mode must be one of off | branch | pr (got: ${opts.remoteSyncMode})`,
|
|
137
|
+
);
|
|
52
138
|
process.exit(1);
|
|
53
139
|
}
|
|
54
140
|
|
|
55
|
-
|
|
141
|
+
const workspaceOnlyFlags = [
|
|
142
|
+
["--out", opts.out],
|
|
143
|
+
["--kit", opts.kit],
|
|
144
|
+
["--name", opts.name],
|
|
145
|
+
["--upstream", opts.upstream],
|
|
146
|
+
["--destination-org", opts.destinationOrg],
|
|
147
|
+
["--fork-name", opts.forkName],
|
|
148
|
+
["--remote-sync-mode", opts.remoteSyncMode],
|
|
149
|
+
];
|
|
150
|
+
if (opts.profile !== "workspace") {
|
|
151
|
+
for (const [flag, value] of workspaceOnlyFlags) {
|
|
152
|
+
if (value !== null) {
|
|
153
|
+
printUsage();
|
|
154
|
+
console.error(
|
|
155
|
+
`${flag} is only valid with --profile workspace (the Custom Workspace Starter path).`,
|
|
156
|
+
);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return opts;
|
|
56
163
|
}
|
|
57
164
|
|
|
58
165
|
function resolveGrowthubCliEntrypoint() {
|
|
@@ -78,10 +185,71 @@ function resolveGrowthubCliEntrypoint() {
|
|
|
78
185
|
return path.resolve(cliPackageDir, growthubBin);
|
|
79
186
|
}
|
|
80
187
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
188
|
+
function buildCliArgs(opts, effectiveDataDir, growthubCli) {
|
|
189
|
+
// --profile workspace → forward into `growthub starter init`
|
|
190
|
+
// (the Custom Workspace Starter surface, which composes
|
|
191
|
+
// copyBundledKitSource + registerKitFork + writeKitForkPolicy
|
|
192
|
+
// + appendKitForkTraceEvent and, optionally, createFork).
|
|
193
|
+
if (opts.profile === "workspace") {
|
|
194
|
+
const outArg = opts.out ?? "./my-workspace";
|
|
195
|
+
const absOut = path.resolve(process.cwd(), outArg);
|
|
196
|
+
const args = [growthubCli, "starter", "init", "--out", absOut];
|
|
197
|
+
if (opts.kit) args.push("--kit", opts.kit);
|
|
198
|
+
if (opts.name) args.push("--name", opts.name);
|
|
199
|
+
if (opts.upstream) args.push("--upstream", opts.upstream);
|
|
200
|
+
if (opts.destinationOrg) args.push("--destination-org", opts.destinationOrg);
|
|
201
|
+
if (opts.forkName) args.push("--fork-name", opts.forkName);
|
|
202
|
+
if (opts.remoteSyncMode) args.push("--remote-sync-mode", opts.remoteSyncMode);
|
|
203
|
+
if (opts.json) args.push("--json");
|
|
204
|
+
return args;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// --profile dx | gtm → existing Paperclip Local App onboarding flow.
|
|
208
|
+
if (opts.profile) {
|
|
209
|
+
return [
|
|
210
|
+
growthubCli,
|
|
211
|
+
"onboard",
|
|
212
|
+
"--yes",
|
|
213
|
+
...(opts.run ? ["--run"] : []),
|
|
214
|
+
"--data-dir",
|
|
215
|
+
effectiveDataDir,
|
|
216
|
+
...(opts.config ? ["--config", opts.config] : []),
|
|
217
|
+
];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// No profile → open the shared discovery hub (kits / templates /
|
|
221
|
+
// workflows / agent harness / settings).
|
|
222
|
+
return [
|
|
223
|
+
growthubCli,
|
|
224
|
+
"discover",
|
|
225
|
+
...(opts.run ? ["--run"] : []),
|
|
226
|
+
"--data-dir",
|
|
227
|
+
effectiveDataDir,
|
|
228
|
+
...(opts.config ? ["--config", opts.config] : []),
|
|
229
|
+
];
|
|
230
|
+
}
|
|
84
231
|
|
|
232
|
+
function buildCliEnv(opts) {
|
|
233
|
+
const env = {
|
|
234
|
+
...process.env,
|
|
235
|
+
GROWTHUB_INSTALLER_MODE: "true",
|
|
236
|
+
};
|
|
237
|
+
// PAPERCLIP_SURFACE_PROFILE is only meaningful for the Paperclip
|
|
238
|
+
// Local App lanes (dx | gtm). The workspace profile scaffolds a
|
|
239
|
+
// Self-Healing Fork Sync workspace that has nothing to do with
|
|
240
|
+
// Paperclip surface selection, so we intentionally do not set it.
|
|
241
|
+
if (opts.profile === "dx" || opts.profile === "gtm") {
|
|
242
|
+
env.PAPERCLIP_SURFACE_PROFILE = opts.profile;
|
|
243
|
+
}
|
|
244
|
+
return env;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const opts = parseArgs(process.argv.slice(2));
|
|
248
|
+
const effectiveDataDir = opts.dataDir
|
|
249
|
+
? path.resolve(process.cwd(), opts.dataDir)
|
|
250
|
+
: path.resolve(process.cwd(), "growthub-local");
|
|
251
|
+
|
|
252
|
+
let growthubCli;
|
|
85
253
|
try {
|
|
86
254
|
growthubCli = resolveGrowthubCliEntrypoint();
|
|
87
255
|
} catch (error) {
|
|
@@ -93,35 +261,13 @@ try {
|
|
|
93
261
|
process.exit(1);
|
|
94
262
|
}
|
|
95
263
|
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
"--data-dir",
|
|
105
|
-
effectiveDataDir,
|
|
106
|
-
...(config ? ["--config", config] : []),
|
|
107
|
-
]
|
|
108
|
-
: [
|
|
109
|
-
growthubCli,
|
|
110
|
-
"discover",
|
|
111
|
-
...(run ? ["--run"] : []),
|
|
112
|
-
"--data-dir",
|
|
113
|
-
effectiveDataDir,
|
|
114
|
-
...(config ? ["--config", config] : []),
|
|
115
|
-
],
|
|
116
|
-
{
|
|
117
|
-
cwd: process.cwd(),
|
|
118
|
-
stdio: "inherit",
|
|
119
|
-
env: {
|
|
120
|
-
...process.env,
|
|
121
|
-
GROWTHUB_INSTALLER_MODE: "true",
|
|
122
|
-
...(profile ? { PAPERCLIP_SURFACE_PROFILE: profile } : {}),
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
);
|
|
264
|
+
const cliArgs = buildCliArgs(opts, effectiveDataDir, growthubCli);
|
|
265
|
+
const cliEnv = buildCliEnv(opts);
|
|
266
|
+
|
|
267
|
+
const result = spawnSync(process.execPath, cliArgs, {
|
|
268
|
+
cwd: process.cwd(),
|
|
269
|
+
stdio: "inherit",
|
|
270
|
+
env: cliEnv,
|
|
271
|
+
});
|
|
126
272
|
|
|
127
273
|
process.exit(result.status ?? 1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@growthub/create-growthub-local",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "Growthub local installer for DX and GTM profiles",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"node": ">=20"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@growthub/cli": "0.
|
|
26
|
+
"@growthub/cli": "0.5.0"
|
|
27
27
|
},
|
|
28
28
|
"keywords": [
|
|
29
29
|
"growthub",
|