@take-out/cli 0.0.39
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/LICENSE +21 -0
- package/README.md +274 -0
- package/cli.mjs +3 -0
- package/dist/cjs/cli.cjs +71 -0
- package/dist/cjs/cli.js +70 -0
- package/dist/cjs/cli.js.map +6 -0
- package/dist/cjs/cli.native.js +79 -0
- package/dist/cjs/cli.native.js.map +6 -0
- package/dist/cjs/commands/changed.cjs +212 -0
- package/dist/cjs/commands/changed.js +214 -0
- package/dist/cjs/commands/changed.js.map +6 -0
- package/dist/cjs/commands/changed.native.js +289 -0
- package/dist/cjs/commands/changed.native.js.map +6 -0
- package/dist/cjs/commands/docs.cjs +388 -0
- package/dist/cjs/commands/docs.js +313 -0
- package/dist/cjs/commands/docs.js.map +6 -0
- package/dist/cjs/commands/docs.native.js +476 -0
- package/dist/cjs/commands/docs.native.js.map +6 -0
- package/dist/cjs/commands/env-setup.cjs +90 -0
- package/dist/cjs/commands/env-setup.js +78 -0
- package/dist/cjs/commands/env-setup.js.map +6 -0
- package/dist/cjs/commands/env-setup.native.js +85 -0
- package/dist/cjs/commands/env-setup.native.js.map +6 -0
- package/dist/cjs/commands/onboard.cjs +479 -0
- package/dist/cjs/commands/onboard.js +631 -0
- package/dist/cjs/commands/onboard.js.map +6 -0
- package/dist/cjs/commands/onboard.native.js +608 -0
- package/dist/cjs/commands/onboard.native.js.map +6 -0
- package/dist/cjs/commands/run.cjs +148 -0
- package/dist/cjs/commands/run.js +116 -0
- package/dist/cjs/commands/run.js.map +6 -0
- package/dist/cjs/commands/run.native.js +140 -0
- package/dist/cjs/commands/run.native.js.map +6 -0
- package/dist/cjs/commands/script.cjs +379 -0
- package/dist/cjs/commands/script.js +339 -0
- package/dist/cjs/commands/script.js.map +6 -0
- package/dist/cjs/commands/script.native.js +449 -0
- package/dist/cjs/commands/script.native.js.map +6 -0
- package/dist/cjs/commands/sync.cjs +190 -0
- package/dist/cjs/commands/sync.js +168 -0
- package/dist/cjs/commands/sync.js.map +6 -0
- package/dist/cjs/commands/sync.native.js +211 -0
- package/dist/cjs/commands/sync.native.js.map +6 -0
- package/dist/cjs/constants/ascii.cjs +36 -0
- package/dist/cjs/constants/ascii.js +30 -0
- package/dist/cjs/constants/ascii.js.map +6 -0
- package/dist/cjs/constants/ascii.native.js +36 -0
- package/dist/cjs/constants/ascii.native.js.map +6 -0
- package/dist/cjs/index.cjs +64 -0
- package/dist/cjs/index.js +55 -0
- package/dist/cjs/index.js.map +6 -0
- package/dist/cjs/index.native.js +94 -0
- package/dist/cjs/index.native.js.map +6 -0
- package/dist/cjs/types.cjs +16 -0
- package/dist/cjs/types.js +14 -0
- package/dist/cjs/types.js.map +6 -0
- package/dist/cjs/types.native.js +15 -0
- package/dist/cjs/types.native.js.map +6 -0
- package/dist/cjs/utils/env-categories.cjs +272 -0
- package/dist/cjs/utils/env-categories.js +296 -0
- package/dist/cjs/utils/env-categories.js.map +6 -0
- package/dist/cjs/utils/env-categories.native.js +317 -0
- package/dist/cjs/utils/env-categories.native.js.map +6 -0
- package/dist/cjs/utils/env-setup.cjs +181 -0
- package/dist/cjs/utils/env-setup.js +190 -0
- package/dist/cjs/utils/env-setup.js.map +6 -0
- package/dist/cjs/utils/env-setup.native.js +264 -0
- package/dist/cjs/utils/env-setup.native.js.map +6 -0
- package/dist/cjs/utils/env.cjs +118 -0
- package/dist/cjs/utils/env.js +97 -0
- package/dist/cjs/utils/env.js.map +6 -0
- package/dist/cjs/utils/env.native.js +128 -0
- package/dist/cjs/utils/env.native.js.map +6 -0
- package/dist/cjs/utils/files.cjs +215 -0
- package/dist/cjs/utils/files.js +164 -0
- package/dist/cjs/utils/files.js.map +6 -0
- package/dist/cjs/utils/files.native.js +266 -0
- package/dist/cjs/utils/files.native.js.map +6 -0
- package/dist/cjs/utils/parallel-runner.cjs +99 -0
- package/dist/cjs/utils/parallel-runner.js +84 -0
- package/dist/cjs/utils/parallel-runner.js.map +6 -0
- package/dist/cjs/utils/parallel-runner.native.js +123 -0
- package/dist/cjs/utils/parallel-runner.native.js.map +6 -0
- package/dist/cjs/utils/ports.cjs +101 -0
- package/dist/cjs/utils/ports.js +81 -0
- package/dist/cjs/utils/ports.js.map +6 -0
- package/dist/cjs/utils/ports.native.js +130 -0
- package/dist/cjs/utils/ports.native.js.map +6 -0
- package/dist/cjs/utils/prerequisites.cjs +119 -0
- package/dist/cjs/utils/prerequisites.js +107 -0
- package/dist/cjs/utils/prerequisites.js.map +6 -0
- package/dist/cjs/utils/prerequisites.native.js +127 -0
- package/dist/cjs/utils/prerequisites.native.js.map +6 -0
- package/dist/cjs/utils/prompts.cjs +161 -0
- package/dist/cjs/utils/prompts.js +162 -0
- package/dist/cjs/utils/prompts.js.map +6 -0
- package/dist/cjs/utils/prompts.native.js +179 -0
- package/dist/cjs/utils/prompts.native.js.map +6 -0
- package/dist/cjs/utils/script-listing.cjs +113 -0
- package/dist/cjs/utils/script-listing.js +108 -0
- package/dist/cjs/utils/script-listing.js.map +6 -0
- package/dist/cjs/utils/script-listing.native.js +174 -0
- package/dist/cjs/utils/script-listing.native.js.map +6 -0
- package/dist/cjs/utils/sync.cjs +85 -0
- package/dist/cjs/utils/sync.js +70 -0
- package/dist/cjs/utils/sync.js.map +6 -0
- package/dist/cjs/utils/sync.native.js +84 -0
- package/dist/cjs/utils/sync.native.js.map +6 -0
- package/dist/cjs/utils/welcome.cjs +50 -0
- package/dist/cjs/utils/welcome.js +42 -0
- package/dist/cjs/utils/welcome.js.map +6 -0
- package/dist/cjs/utils/welcome.native.js +47 -0
- package/dist/cjs/utils/welcome.native.js.map +6 -0
- package/dist/esm/cli.js +79 -0
- package/dist/esm/cli.js.map +6 -0
- package/dist/esm/cli.mjs +71 -0
- package/dist/esm/cli.mjs.map +1 -0
- package/dist/esm/cli.native.js +69 -0
- package/dist/esm/cli.native.js.map +1 -0
- package/dist/esm/commands/changed.js +194 -0
- package/dist/esm/commands/changed.js.map +6 -0
- package/dist/esm/commands/changed.mjs +178 -0
- package/dist/esm/commands/changed.mjs.map +1 -0
- package/dist/esm/commands/changed.native.js +273 -0
- package/dist/esm/commands/changed.native.js.map +1 -0
- package/dist/esm/commands/docs.js +306 -0
- package/dist/esm/commands/docs.js.map +6 -0
- package/dist/esm/commands/docs.mjs +353 -0
- package/dist/esm/commands/docs.mjs.map +1 -0
- package/dist/esm/commands/docs.native.js +516 -0
- package/dist/esm/commands/docs.native.js.map +1 -0
- package/dist/esm/commands/env-setup.js +56 -0
- package/dist/esm/commands/env-setup.js.map +6 -0
- package/dist/esm/commands/env-setup.mjs +56 -0
- package/dist/esm/commands/env-setup.mjs.map +1 -0
- package/dist/esm/commands/env-setup.native.js +59 -0
- package/dist/esm/commands/env-setup.native.js.map +1 -0
- package/dist/esm/commands/onboard.js +645 -0
- package/dist/esm/commands/onboard.js.map +6 -0
- package/dist/esm/commands/onboard.mjs +445 -0
- package/dist/esm/commands/onboard.mjs.map +1 -0
- package/dist/esm/commands/onboard.native.js +584 -0
- package/dist/esm/commands/onboard.native.js.map +1 -0
- package/dist/esm/commands/run.js +95 -0
- package/dist/esm/commands/run.js.map +6 -0
- package/dist/esm/commands/run.mjs +114 -0
- package/dist/esm/commands/run.mjs.map +1 -0
- package/dist/esm/commands/run.native.js +133 -0
- package/dist/esm/commands/run.native.js.map +1 -0
- package/dist/esm/commands/script.js +338 -0
- package/dist/esm/commands/script.js.map +6 -0
- package/dist/esm/commands/script.mjs +336 -0
- package/dist/esm/commands/script.mjs.map +1 -0
- package/dist/esm/commands/script.native.js +445 -0
- package/dist/esm/commands/script.native.js.map +1 -0
- package/dist/esm/commands/sync.js +158 -0
- package/dist/esm/commands/sync.js.map +6 -0
- package/dist/esm/commands/sync.mjs +155 -0
- package/dist/esm/commands/sync.mjs.map +1 -0
- package/dist/esm/commands/sync.native.js +173 -0
- package/dist/esm/commands/sync.native.js.map +1 -0
- package/dist/esm/constants/ascii.js +14 -0
- package/dist/esm/constants/ascii.js.map +6 -0
- package/dist/esm/constants/ascii.mjs +12 -0
- package/dist/esm/constants/ascii.mjs.map +1 -0
- package/dist/esm/constants/ascii.native.js +12 -0
- package/dist/esm/constants/ascii.native.js.map +1 -0
- package/dist/esm/index.js +83 -0
- package/dist/esm/index.js.map +6 -0
- package/dist/esm/index.mjs +7 -0
- package/dist/esm/index.mjs.map +1 -0
- package/dist/esm/index.native.js +7 -0
- package/dist/esm/index.native.js.map +1 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/types.js.map +6 -0
- package/dist/esm/types.mjs +2 -0
- package/dist/esm/types.mjs.map +1 -0
- package/dist/esm/types.native.js +2 -0
- package/dist/esm/types.native.js.map +1 -0
- package/dist/esm/utils/env-categories.js +272 -0
- package/dist/esm/utils/env-categories.js.map +6 -0
- package/dist/esm/utils/env-categories.mjs +233 -0
- package/dist/esm/utils/env-categories.mjs.map +1 -0
- package/dist/esm/utils/env-categories.native.js +246 -0
- package/dist/esm/utils/env-categories.native.js.map +1 -0
- package/dist/esm/utils/env-setup.js +173 -0
- package/dist/esm/utils/env-setup.js.map +6 -0
- package/dist/esm/utils/env-setup.mjs +146 -0
- package/dist/esm/utils/env-setup.mjs.map +1 -0
- package/dist/esm/utils/env-setup.native.js +243 -0
- package/dist/esm/utils/env-setup.native.js.map +1 -0
- package/dist/esm/utils/env.js +83 -0
- package/dist/esm/utils/env.js.map +6 -0
- package/dist/esm/utils/env.mjs +90 -0
- package/dist/esm/utils/env.mjs.map +1 -0
- package/dist/esm/utils/env.native.js +99 -0
- package/dist/esm/utils/env.native.js.map +1 -0
- package/dist/esm/utils/files.js +150 -0
- package/dist/esm/utils/files.js.map +6 -0
- package/dist/esm/utils/files.mjs +187 -0
- package/dist/esm/utils/files.mjs.map +1 -0
- package/dist/esm/utils/files.native.js +247 -0
- package/dist/esm/utils/files.native.js.map +1 -0
- package/dist/esm/utils/parallel-runner.js +69 -0
- package/dist/esm/utils/parallel-runner.js.map +6 -0
- package/dist/esm/utils/parallel-runner.mjs +76 -0
- package/dist/esm/utils/parallel-runner.mjs.map +1 -0
- package/dist/esm/utils/parallel-runner.native.js +109 -0
- package/dist/esm/utils/parallel-runner.native.js.map +1 -0
- package/dist/esm/utils/ports.js +65 -0
- package/dist/esm/utils/ports.js.map +6 -0
- package/dist/esm/utils/ports.mjs +74 -0
- package/dist/esm/utils/ports.mjs.map +1 -0
- package/dist/esm/utils/ports.native.js +93 -0
- package/dist/esm/utils/ports.native.js.map +1 -0
- package/dist/esm/utils/prerequisites.js +91 -0
- package/dist/esm/utils/prerequisites.js.map +6 -0
- package/dist/esm/utils/prerequisites.mjs +91 -0
- package/dist/esm/utils/prerequisites.mjs.map +1 -0
- package/dist/esm/utils/prerequisites.native.js +97 -0
- package/dist/esm/utils/prerequisites.native.js.map +1 -0
- package/dist/esm/utils/prompts.js +139 -0
- package/dist/esm/utils/prompts.js.map +6 -0
- package/dist/esm/utils/prompts.mjs +112 -0
- package/dist/esm/utils/prompts.mjs.map +1 -0
- package/dist/esm/utils/prompts.native.js +115 -0
- package/dist/esm/utils/prompts.native.js.map +1 -0
- package/dist/esm/utils/script-listing.js +91 -0
- package/dist/esm/utils/script-listing.js.map +6 -0
- package/dist/esm/utils/script-listing.mjs +76 -0
- package/dist/esm/utils/script-listing.mjs.map +1 -0
- package/dist/esm/utils/script-listing.native.js +151 -0
- package/dist/esm/utils/script-listing.native.js.map +1 -0
- package/dist/esm/utils/sync.js +50 -0
- package/dist/esm/utils/sync.js.map +6 -0
- package/dist/esm/utils/sync.mjs +48 -0
- package/dist/esm/utils/sync.mjs.map +1 -0
- package/dist/esm/utils/sync.native.js +53 -0
- package/dist/esm/utils/sync.native.js.map +1 -0
- package/dist/esm/utils/welcome.js +21 -0
- package/dist/esm/utils/welcome.js.map +6 -0
- package/dist/esm/utils/welcome.mjs +15 -0
- package/dist/esm/utils/welcome.mjs.map +1 -0
- package/dist/esm/utils/welcome.native.js +18 -0
- package/dist/esm/utils/welcome.native.js.map +1 -0
- package/docs/aggregates.md +579 -0
- package/docs/cloudflare-dev-tunnel.md +41 -0
- package/docs/database.md +203 -0
- package/docs/docs.md +8 -0
- package/docs/emitters.md +562 -0
- package/docs/hot-updater.md +223 -0
- package/docs/native-hot-update.md +252 -0
- package/docs/one-components.md +234 -0
- package/docs/one-hooks.md +570 -0
- package/docs/one-routes.md +660 -0
- package/docs/package-json.md +115 -0
- package/docs/react-native-navigation-flow.md +184 -0
- package/docs/scripts.md +147 -0
- package/docs/sync-prompt.md +208 -0
- package/docs/tamagui.md +478 -0
- package/docs/testing-integration.md +564 -0
- package/docs/triggers.md +450 -0
- package/docs/zero.md +719 -0
- package/package.json +76 -0
- package/scripts/seed.ts +209 -0
- package/src/cli.ts +147 -0
- package/src/commands/changed.ts +313 -0
- package/src/commands/docs.ts +582 -0
- package/src/commands/env-setup.ts +69 -0
- package/src/commands/onboard.ts +1391 -0
- package/src/commands/run.ts +173 -0
- package/src/commands/script.ts +587 -0
- package/src/commands/sync.ts +305 -0
- package/src/constants/ascii.ts +17 -0
- package/src/index.ts +63 -0
- package/src/types.ts +59 -0
- package/src/utils/env-categories.ts +245 -0
- package/src/utils/env-setup.ts +338 -0
- package/src/utils/env.ts +127 -0
- package/src/utils/files.ts +302 -0
- package/src/utils/parallel-runner.ts +129 -0
- package/src/utils/ports.ts +77 -0
- package/src/utils/prerequisites.ts +137 -0
- package/src/utils/prompts.ts +197 -0
- package/src/utils/script-listing.ts +214 -0
- package/src/utils/sync.ts +101 -0
- package/src/withOpSqliteStatic.cjs +51 -0
- package/types/cli.d.ts +7 -0
- package/types/cli.d.ts.map +1 -0
- package/types/commands/changed.d.ts +14 -0
- package/types/commands/changed.d.ts.map +1 -0
- package/types/commands/docs.d.ts +5 -0
- package/types/commands/docs.d.ts.map +1 -0
- package/types/commands/env-setup.d.ts +25 -0
- package/types/commands/env-setup.d.ts.map +1 -0
- package/types/commands/onboard.d.ts +16 -0
- package/types/commands/onboard.d.ts.map +1 -0
- package/types/commands/run.d.ts +8 -0
- package/types/commands/run.d.ts.map +1 -0
- package/types/commands/script.d.ts +28 -0
- package/types/commands/script.d.ts.map +1 -0
- package/types/commands/sync.d.ts +5 -0
- package/types/commands/sync.d.ts.map +1 -0
- package/types/constants/ascii.d.ts +6 -0
- package/types/constants/ascii.d.ts.map +1 -0
- package/types/index.d.ts +12 -0
- package/types/index.d.ts.map +1 -0
- package/types/types.d.ts +54 -0
- package/types/types.d.ts.map +1 -0
- package/types/utils/env-categories.d.ts +8 -0
- package/types/utils/env-categories.d.ts.map +1 -0
- package/types/utils/env-setup.d.ts +10 -0
- package/types/utils/env-setup.d.ts.map +1 -0
- package/types/utils/env.d.ts +19 -0
- package/types/utils/env.d.ts.map +1 -0
- package/types/utils/files.d.ts +47 -0
- package/types/utils/files.d.ts.map +1 -0
- package/types/utils/parallel-runner.d.ts +15 -0
- package/types/utils/parallel-runner.d.ts.map +1 -0
- package/types/utils/ports.d.ts +16 -0
- package/types/utils/ports.d.ts.map +1 -0
- package/types/utils/prerequisites.d.ts +11 -0
- package/types/utils/prerequisites.d.ts.map +1 -0
- package/types/utils/prompts.d.ts +30 -0
- package/types/utils/prompts.d.ts.map +1 -0
- package/types/utils/script-listing.d.ts +7 -0
- package/types/utils/script-listing.d.ts.map +1 -0
- package/types/utils/sync.d.ts +16 -0
- package/types/utils/sync.d.ts.map +1 -0
- package/types/utils/welcome.d.ts +6 -0
- package/types/utils/welcome.d.ts.map +1 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File operations for updating project configuration
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { execSync } from 'node:child_process'
|
|
6
|
+
import { existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
7
|
+
import { join } from 'node:path'
|
|
8
|
+
|
|
9
|
+
export function updatePackageJson(
|
|
10
|
+
cwd: string,
|
|
11
|
+
updates: { name?: string; description?: string }
|
|
12
|
+
): { success: boolean; error?: string } {
|
|
13
|
+
const packagePath = join(cwd, 'package.json')
|
|
14
|
+
|
|
15
|
+
if (!existsSync(packagePath)) {
|
|
16
|
+
return { success: false, error: 'package.json not found' }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const content = readFileSync(packagePath, 'utf-8')
|
|
21
|
+
const pkg = JSON.parse(content)
|
|
22
|
+
|
|
23
|
+
if (updates.name) pkg.name = updates.name
|
|
24
|
+
if (updates.description) pkg.description = updates.description
|
|
25
|
+
|
|
26
|
+
writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8')
|
|
27
|
+
return { success: true }
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function updateAppConfig(
|
|
37
|
+
cwd: string,
|
|
38
|
+
updates: { name?: string; slug?: string; bundleId?: string }
|
|
39
|
+
): { success: boolean; error?: string } {
|
|
40
|
+
const configPath = join(cwd, 'app.config.ts')
|
|
41
|
+
|
|
42
|
+
if (!existsSync(configPath)) {
|
|
43
|
+
return { success: false, error: 'app.config.ts not found' }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
let content = readFileSync(configPath, 'utf-8')
|
|
48
|
+
|
|
49
|
+
if (updates.name) {
|
|
50
|
+
// Update name field
|
|
51
|
+
content = content.replace(/(name:\s*['"])([^'"]+)(['"])/, `$1${updates.name}$3`)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (updates.slug) {
|
|
55
|
+
// Update slug field
|
|
56
|
+
content = content.replace(/(slug:\s*['"])([^'"]+)(['"])/, `$1${updates.slug}$3`)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (updates.bundleId) {
|
|
60
|
+
// Update iOS bundle identifier
|
|
61
|
+
content = content.replace(
|
|
62
|
+
/(bundleIdentifier:\s*['"])([^'"]+)(['"])/,
|
|
63
|
+
`$1${updates.bundleId}$3`
|
|
64
|
+
)
|
|
65
|
+
// Update Android package
|
|
66
|
+
content = content.replace(
|
|
67
|
+
/(package:\s*['"])([^'"]+)(['"])/,
|
|
68
|
+
`$1${updates.bundleId}$3`
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
writeFileSync(configPath, content, 'utf-8')
|
|
73
|
+
return { success: true }
|
|
74
|
+
} catch (error) {
|
|
75
|
+
return {
|
|
76
|
+
success: false,
|
|
77
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function checkOnboarded(cwd: string): boolean {
|
|
83
|
+
const packagePath = join(cwd, 'package.json')
|
|
84
|
+
if (!existsSync(packagePath)) return false
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const pkg = JSON.parse(readFileSync(packagePath, 'utf-8'))
|
|
88
|
+
return pkg.takeout?.onboarded === true
|
|
89
|
+
} catch {
|
|
90
|
+
return false
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function markOnboarded(cwd: string): { success: boolean; error?: string } {
|
|
95
|
+
const packagePath = join(cwd, 'package.json')
|
|
96
|
+
|
|
97
|
+
if (!existsSync(packagePath)) {
|
|
98
|
+
return { success: false, error: 'package.json not found' }
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const content = readFileSync(packagePath, 'utf-8')
|
|
103
|
+
const pkg = JSON.parse(content)
|
|
104
|
+
|
|
105
|
+
if (!pkg.takeout) {
|
|
106
|
+
pkg.takeout = {}
|
|
107
|
+
}
|
|
108
|
+
pkg.takeout.onboarded = true
|
|
109
|
+
|
|
110
|
+
writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8')
|
|
111
|
+
return { success: true }
|
|
112
|
+
} catch (error) {
|
|
113
|
+
return {
|
|
114
|
+
success: false,
|
|
115
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Updates the env section in package.json to remove platform-specific variables
|
|
122
|
+
*/
|
|
123
|
+
export function updatePackageJsonEnv(
|
|
124
|
+
cwd: string,
|
|
125
|
+
platform: 'sst' | 'uncloud'
|
|
126
|
+
): { success: boolean; error?: string } {
|
|
127
|
+
const packagePath = join(cwd, 'package.json')
|
|
128
|
+
|
|
129
|
+
if (!existsSync(packagePath)) {
|
|
130
|
+
return { success: false, error: 'package.json not found' }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const content = readFileSync(packagePath, 'utf-8')
|
|
135
|
+
const pkg = JSON.parse(content)
|
|
136
|
+
|
|
137
|
+
if (!pkg.env) {
|
|
138
|
+
return { success: false, error: 'env section not found in package.json' }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (platform === 'sst') {
|
|
142
|
+
// remove uncloud-specific vars, keep sst vars
|
|
143
|
+
delete pkg.env.DEPLOY_HOST
|
|
144
|
+
delete pkg.env.DEPLOY_USER
|
|
145
|
+
delete pkg.env.DEPLOY_SSH_KEY
|
|
146
|
+
} else if (platform === 'uncloud') {
|
|
147
|
+
// remove sst-specific vars, keep uncloud vars
|
|
148
|
+
delete pkg.env.CLOUDFLARE_API_TOKEN
|
|
149
|
+
delete pkg.env.AWS_ACCESS_KEY_ID
|
|
150
|
+
delete pkg.env.AWS_SECRET_ACCESS_KEY
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8')
|
|
154
|
+
return { success: true }
|
|
155
|
+
} catch (error) {
|
|
156
|
+
return {
|
|
157
|
+
success: false,
|
|
158
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface EjectOptions {
|
|
164
|
+
dryRun?: boolean
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface EjectResult {
|
|
168
|
+
success: boolean
|
|
169
|
+
error?: string
|
|
170
|
+
packages?: { name: string; version: string }[]
|
|
171
|
+
warnings?: string[]
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Ejects from monorepo setup by removing ./packages and updating workspace:* versions
|
|
176
|
+
*/
|
|
177
|
+
export async function ejectFromMonorepo(
|
|
178
|
+
cwd: string,
|
|
179
|
+
options: EjectOptions = {}
|
|
180
|
+
): Promise<EjectResult> {
|
|
181
|
+
const { dryRun = false } = options
|
|
182
|
+
const packagePath = join(cwd, 'package.json')
|
|
183
|
+
const packagesDir = join(cwd, 'packages')
|
|
184
|
+
const warnings: string[] = []
|
|
185
|
+
|
|
186
|
+
if (!existsSync(packagePath)) {
|
|
187
|
+
return { success: false, error: 'package.json not found' }
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
try {
|
|
191
|
+
// read package.json
|
|
192
|
+
const content = readFileSync(packagePath, 'utf-8')
|
|
193
|
+
const pkg = JSON.parse(content)
|
|
194
|
+
|
|
195
|
+
// check if already ejected
|
|
196
|
+
if (!existsSync(packagesDir)) {
|
|
197
|
+
return { success: false, error: 'packages directory not found - already ejected?' }
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (!pkg.workspaces) {
|
|
201
|
+
return { success: false, error: 'no workspaces field found - already ejected?' }
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// dynamically discover workspace packages from ./packages directory
|
|
205
|
+
const workspacePackages: { name: string; version: string }[] = []
|
|
206
|
+
|
|
207
|
+
const entries = readdirSync(packagesDir, { withFileTypes: true })
|
|
208
|
+
for (const entry of entries) {
|
|
209
|
+
if (!entry.isDirectory()) continue
|
|
210
|
+
const pkgJsonPath = join(packagesDir, entry.name, 'package.json')
|
|
211
|
+
if (existsSync(pkgJsonPath)) {
|
|
212
|
+
try {
|
|
213
|
+
const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'))
|
|
214
|
+
if (pkgJson.name && pkgJson.version) {
|
|
215
|
+
workspacePackages.push({ name: pkgJson.name, version: pkgJson.version })
|
|
216
|
+
} else {
|
|
217
|
+
warnings.push(`skipped ${entry.name}: missing name or version`)
|
|
218
|
+
}
|
|
219
|
+
} catch (e) {
|
|
220
|
+
warnings.push(`skipped ${entry.name}: invalid package.json`)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (workspacePackages.length === 0) {
|
|
226
|
+
return { success: false, error: 'no valid workspace packages found' }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// check for workspace:* references that won't be resolved
|
|
230
|
+
const unresolvedDeps: string[] = []
|
|
231
|
+
const allDeps = { ...pkg.dependencies, ...pkg.devDependencies }
|
|
232
|
+
for (const [name, version] of Object.entries(allDeps)) {
|
|
233
|
+
if (version === 'workspace:*') {
|
|
234
|
+
const found = workspacePackages.find((p) => p.name === name)
|
|
235
|
+
if (!found) {
|
|
236
|
+
unresolvedDeps.push(name)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (unresolvedDeps.length > 0) {
|
|
242
|
+
return {
|
|
243
|
+
success: false,
|
|
244
|
+
error: `unresolved workspace dependencies: ${unresolvedDeps.join(', ')}`,
|
|
245
|
+
packages: workspacePackages,
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// dry run returns here without making changes
|
|
250
|
+
if (dryRun) {
|
|
251
|
+
return {
|
|
252
|
+
success: true,
|
|
253
|
+
packages: workspacePackages,
|
|
254
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// replace workspace:* with actual versions
|
|
259
|
+
for (const { name, version } of workspacePackages) {
|
|
260
|
+
if (pkg.dependencies?.[name] === 'workspace:*') {
|
|
261
|
+
pkg.dependencies[name] = `^${version}`
|
|
262
|
+
}
|
|
263
|
+
if (pkg.devDependencies?.[name] === 'workspace:*') {
|
|
264
|
+
pkg.devDependencies[name] = `^${version}`
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// remove workspaces field
|
|
269
|
+
delete pkg.workspaces
|
|
270
|
+
|
|
271
|
+
// write updated package.json
|
|
272
|
+
writeFileSync(packagePath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8')
|
|
273
|
+
|
|
274
|
+
// remove packages directory
|
|
275
|
+
rmSync(packagesDir, { recursive: true, force: true })
|
|
276
|
+
|
|
277
|
+
// install the published packages
|
|
278
|
+
try {
|
|
279
|
+
execSync('bun install', { cwd, stdio: 'inherit' })
|
|
280
|
+
} catch {
|
|
281
|
+
// restore packages directory hint in error
|
|
282
|
+
return {
|
|
283
|
+
success: false,
|
|
284
|
+
error:
|
|
285
|
+
'failed to install published packages. package.json was modified but install failed. ' +
|
|
286
|
+
'try running "bun install" manually, or restore from git.',
|
|
287
|
+
packages: workspacePackages,
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return {
|
|
292
|
+
success: true,
|
|
293
|
+
packages: workspacePackages,
|
|
294
|
+
warnings: warnings.length > 0 ? warnings : undefined,
|
|
295
|
+
}
|
|
296
|
+
} catch (error) {
|
|
297
|
+
return {
|
|
298
|
+
success: false,
|
|
299
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility for running scripts in parallel with color-coded output
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { spawn } from 'node:child_process'
|
|
6
|
+
import { cpus } from 'node:os'
|
|
7
|
+
|
|
8
|
+
const colors = [
|
|
9
|
+
'\x1b[36m', // Cyan
|
|
10
|
+
'\x1b[35m', // Magenta
|
|
11
|
+
'\x1b[33m', // Yellow
|
|
12
|
+
'\x1b[32m', // Green
|
|
13
|
+
'\x1b[34m', // Blue
|
|
14
|
+
'\x1b[31m', // Red
|
|
15
|
+
'\x1b[90m', // Gray
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
const reset = '\x1b[0m'
|
|
19
|
+
|
|
20
|
+
interface ScriptToRun {
|
|
21
|
+
name: string
|
|
22
|
+
path: string
|
|
23
|
+
args?: string[]
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function runScriptsInParallel(
|
|
27
|
+
scripts: ScriptToRun[],
|
|
28
|
+
options: {
|
|
29
|
+
title?: string
|
|
30
|
+
onError?: 'continue' | 'exit'
|
|
31
|
+
maxParallelism?: number
|
|
32
|
+
} = {}
|
|
33
|
+
): Promise<void> {
|
|
34
|
+
const { title, onError = 'exit', maxParallelism = cpus().length } = options
|
|
35
|
+
|
|
36
|
+
if (title) {
|
|
37
|
+
console.info()
|
|
38
|
+
console.info(title)
|
|
39
|
+
console.info()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const allPromises: Promise<void>[] = []
|
|
43
|
+
const executing: Set<Promise<void>> = new Set()
|
|
44
|
+
|
|
45
|
+
for (let i = 0; i < scripts.length; i++) {
|
|
46
|
+
const script = scripts[i]!
|
|
47
|
+
const scriptPromise = runSingleScript(script, i).finally(() => {
|
|
48
|
+
executing.delete(scriptPromise)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
allPromises.push(scriptPromise)
|
|
52
|
+
executing.add(scriptPromise)
|
|
53
|
+
|
|
54
|
+
if (executing.size >= maxParallelism) {
|
|
55
|
+
await Promise.race(executing)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const settledResults = await Promise.allSettled(allPromises)
|
|
60
|
+
|
|
61
|
+
// Check for failures
|
|
62
|
+
const failures = settledResults.filter((r) => r.status === 'rejected')
|
|
63
|
+
|
|
64
|
+
if (failures.length > 0) {
|
|
65
|
+
console.error(`\n${reset}\x1b[31m✗ ${failures.length} script(s) failed${reset}\n`)
|
|
66
|
+
if (onError === 'exit') {
|
|
67
|
+
process.exit(1)
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
console.info(`\n${reset}\x1b[32m✓ All scripts completed successfully${reset}\n`)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function runSingleScript(script: ScriptToRun, colorIndex: number): Promise<void> {
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
const color = colors[colorIndex % colors.length]
|
|
77
|
+
const prefixLabel = script.name
|
|
78
|
+
|
|
79
|
+
const proc = spawn('bun', [script.path, ...(script.args || [])], {
|
|
80
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
81
|
+
shell: false,
|
|
82
|
+
env: { ...process.env, FORCE_COLOR: '3' } as any,
|
|
83
|
+
detached: true,
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
let stderrBuffer = ''
|
|
87
|
+
|
|
88
|
+
proc.stdout.on('data', (data) => {
|
|
89
|
+
const lines = data.toString().split('\n')
|
|
90
|
+
for (const line of lines) {
|
|
91
|
+
if (line) console.info(`${color}${prefixLabel}${reset} ${line}`)
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
proc.stderr.on('data', (data) => {
|
|
96
|
+
const dataStr = data.toString()
|
|
97
|
+
stderrBuffer += dataStr
|
|
98
|
+
|
|
99
|
+
const lines = dataStr.split('\n')
|
|
100
|
+
for (const line of lines) {
|
|
101
|
+
if (line) console.error(`${color}${prefixLabel}${reset} ${line}`)
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
proc.on('error', (error) => {
|
|
106
|
+
console.error(`${color}${prefixLabel}${reset} Failed to start: ${error.message}`)
|
|
107
|
+
reject(error)
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
proc.on('close', (code) => {
|
|
111
|
+
if (code && code !== 0) {
|
|
112
|
+
console.error(`${color}${prefixLabel}${reset} Process exited with code ${code}`)
|
|
113
|
+
|
|
114
|
+
// Show error details
|
|
115
|
+
if (stderrBuffer.trim()) {
|
|
116
|
+
console.error(`\n${color}${prefixLabel}${reset} Error output:`)
|
|
117
|
+
console.error('\x1b[90m' + '─'.repeat(80) + '\x1b[0m')
|
|
118
|
+
console.error(stderrBuffer)
|
|
119
|
+
console.error('\x1b[90m' + '─'.repeat(80) + '\x1b[0m\n')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
reject(new Error(`Script ${prefixLabel} failed with code ${code}`))
|
|
123
|
+
} else {
|
|
124
|
+
console.info(`${color}${prefixLabel}${reset} \x1b[32m✓ completed${reset}`)
|
|
125
|
+
resolve()
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
})
|
|
129
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Port conflict detection for Takeout services
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { execSync } from 'node:child_process'
|
|
6
|
+
|
|
7
|
+
import type { PortCheck } from '../types'
|
|
8
|
+
|
|
9
|
+
function isPortInUse(port: number): { inUse: boolean; pid?: number } {
|
|
10
|
+
try {
|
|
11
|
+
if (process.platform === 'win32') {
|
|
12
|
+
// windows: use netstat to find processes on the port
|
|
13
|
+
const output = execSync(`netstat -ano | findstr :${port}`, {
|
|
14
|
+
encoding: 'utf-8',
|
|
15
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
16
|
+
}).trim()
|
|
17
|
+
|
|
18
|
+
if (!output) return { inUse: false }
|
|
19
|
+
|
|
20
|
+
// extract pid from last column of netstat output
|
|
21
|
+
const lines = output.split('\n')
|
|
22
|
+
for (const line of lines) {
|
|
23
|
+
const parts = line.trim().split(/\s+/)
|
|
24
|
+
// check if this is a LISTENING state on the exact port
|
|
25
|
+
if (parts[1]?.includes(`:${port}`) && parts[3] === 'LISTENING') {
|
|
26
|
+
const pid = Number.parseInt(parts[4] || '', 10)
|
|
27
|
+
return { inUse: true, pid: Number.isNaN(pid) ? undefined : pid }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return { inUse: false }
|
|
31
|
+
} else {
|
|
32
|
+
// unix: use lsof
|
|
33
|
+
const output = execSync(`lsof -i :${port} -t`, {
|
|
34
|
+
encoding: 'utf-8',
|
|
35
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
36
|
+
}).trim()
|
|
37
|
+
|
|
38
|
+
const pid = output ? Number.parseInt(output.split('\n')[0] || '', 10) : undefined
|
|
39
|
+
|
|
40
|
+
return { inUse: !!output, pid: Number.isNaN(pid) ? undefined : pid }
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
// if command fails, port is likely free
|
|
44
|
+
return { inUse: false }
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const TAKEOUT_PORTS = {
|
|
49
|
+
postgres: 5432,
|
|
50
|
+
zero: 4848,
|
|
51
|
+
web: 8081,
|
|
52
|
+
minio: 9090,
|
|
53
|
+
minioConsole: 9091,
|
|
54
|
+
} as const
|
|
55
|
+
|
|
56
|
+
export function checkPort(port: number, name: string): PortCheck {
|
|
57
|
+
const { inUse, pid } = isPortInUse(port)
|
|
58
|
+
return { port, name, inUse, pid }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function checkAllPorts(): PortCheck[] {
|
|
62
|
+
return [
|
|
63
|
+
checkPort(TAKEOUT_PORTS.postgres, 'PostgreSQL'),
|
|
64
|
+
checkPort(TAKEOUT_PORTS.zero, 'Zero Sync'),
|
|
65
|
+
checkPort(TAKEOUT_PORTS.web, 'Web Server'),
|
|
66
|
+
checkPort(TAKEOUT_PORTS.minio, 'MinIO (S3)'),
|
|
67
|
+
checkPort(TAKEOUT_PORTS.minioConsole, 'MinIO Console'),
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function hasPortConflicts(checks: PortCheck[]): boolean {
|
|
72
|
+
return checks.some((c) => c.inUse)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function getConflictingPorts(checks: PortCheck[]): PortCheck[] {
|
|
76
|
+
return checks.filter((c) => c.inUse)
|
|
77
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check for required prerequisites (Bun, Node, Docker, Git)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { execSync } from 'node:child_process'
|
|
6
|
+
|
|
7
|
+
import type { PrerequisiteCheck } from '../types'
|
|
8
|
+
|
|
9
|
+
function execCommand(command: string): string | null {
|
|
10
|
+
try {
|
|
11
|
+
return execSync(command, {
|
|
12
|
+
encoding: 'utf-8',
|
|
13
|
+
stdio: ['pipe', 'pipe', 'ignore'],
|
|
14
|
+
}).trim()
|
|
15
|
+
} catch {
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getVersion(command: string): string | null {
|
|
21
|
+
const output = execCommand(command)
|
|
22
|
+
if (!output) return null
|
|
23
|
+
|
|
24
|
+
// Extract version number (e.g., "v1.2.3" or "1.2.3")
|
|
25
|
+
const match = output.match(/\d+\.\d+\.\d+/)
|
|
26
|
+
return match ? match[0] : output
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function compareVersions(current: string, required: string): boolean {
|
|
30
|
+
const parseCurrent = current.replace(/^v/, '').split('.').map(Number)
|
|
31
|
+
const parseRequired = required.replace(/^v/, '').split('.').map(Number)
|
|
32
|
+
|
|
33
|
+
for (let i = 0; i < 3; i++) {
|
|
34
|
+
const curr = parseCurrent[i] || 0
|
|
35
|
+
const req = parseRequired[i] || 0
|
|
36
|
+
if (curr > req) return true
|
|
37
|
+
if (curr < req) return false
|
|
38
|
+
}
|
|
39
|
+
return true
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function checkBun(): PrerequisiteCheck {
|
|
43
|
+
const version = getVersion('bun --version') ?? undefined
|
|
44
|
+
const requiredVersion = '1.0.0'
|
|
45
|
+
const hasBunv = !!execCommand('bunv --version')
|
|
46
|
+
|
|
47
|
+
let message = version
|
|
48
|
+
? compareVersions(version, requiredVersion)
|
|
49
|
+
? `Bun ${version} installed`
|
|
50
|
+
: `Bun ${version} installed (${requiredVersion}+ recommended)`
|
|
51
|
+
: 'Bun not found'
|
|
52
|
+
|
|
53
|
+
if (version && !hasBunv) {
|
|
54
|
+
message += ' (consider installing bunv for auto version switching)'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
name: 'Bun',
|
|
59
|
+
required: true,
|
|
60
|
+
installed: !!version,
|
|
61
|
+
version,
|
|
62
|
+
requiredVersion,
|
|
63
|
+
message,
|
|
64
|
+
installUrl: 'https://bun.sh',
|
|
65
|
+
recommendation: !hasBunv
|
|
66
|
+
? 'Install bunv to automatically switch bun versions: https://github.com/aklinker1/bunv'
|
|
67
|
+
: undefined,
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function checkNode(): PrerequisiteCheck {
|
|
72
|
+
const version = getVersion('node --version') ?? undefined
|
|
73
|
+
const requiredVersion = '20.0.0'
|
|
74
|
+
const hasFnm = !!execCommand('fnm --version')
|
|
75
|
+
|
|
76
|
+
let message = version
|
|
77
|
+
? compareVersions(version, requiredVersion)
|
|
78
|
+
? `Node.js ${version} installed`
|
|
79
|
+
: `Node.js ${version} installed (${requiredVersion}+ recommended)`
|
|
80
|
+
: 'Node.js not found (optional)'
|
|
81
|
+
|
|
82
|
+
if (version && !hasFnm) {
|
|
83
|
+
message += ' (consider installing fnm for auto version switching)'
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
name: 'Node.js',
|
|
88
|
+
required: false,
|
|
89
|
+
installed: !!version,
|
|
90
|
+
version,
|
|
91
|
+
requiredVersion,
|
|
92
|
+
message,
|
|
93
|
+
installUrl: 'https://nodejs.org',
|
|
94
|
+
recommendation: !hasFnm
|
|
95
|
+
? 'Install fnm to automatically switch node versions: https://github.com/Schniz/fnm'
|
|
96
|
+
: undefined,
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function checkDocker(): PrerequisiteCheck {
|
|
101
|
+
const version = getVersion('docker --version') ?? undefined
|
|
102
|
+
const isRunning = !!execCommand('docker ps')
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
name: 'Docker',
|
|
106
|
+
required: true,
|
|
107
|
+
installed: !!version,
|
|
108
|
+
version,
|
|
109
|
+
message: !version
|
|
110
|
+
? 'Docker not found'
|
|
111
|
+
: !isRunning
|
|
112
|
+
? 'Docker installed but not running'
|
|
113
|
+
: `Docker ${version} running`,
|
|
114
|
+
installUrl: 'https://docs.docker.com/get-docker/',
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function checkGit(): PrerequisiteCheck {
|
|
119
|
+
const version = getVersion('git --version') ?? undefined
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
name: 'Git',
|
|
123
|
+
required: true,
|
|
124
|
+
installed: !!version,
|
|
125
|
+
version,
|
|
126
|
+
message: version ? `Git ${version} installed` : 'Git not found',
|
|
127
|
+
installUrl: 'https://git-scm.com',
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function checkAllPrerequisites(): PrerequisiteCheck[] {
|
|
132
|
+
return [checkBun(), checkNode(), checkDocker(), checkGit()]
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function hasRequiredPrerequisites(checks: PrerequisiteCheck[]): boolean {
|
|
136
|
+
return checks.filter((c) => c.required).every((c) => c.installed)
|
|
137
|
+
}
|