create-flow-os 0.0.1-dev.1771614697
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 +4 -0
- package/config.json +54 -0
- package/flow.config.client.ts +3 -0
- package/gen.ts +163 -0
- package/index.ts +175 -0
- package/package.json +29 -0
- package/profiles/client/.dockerignore +12 -0
- package/profiles/client/.oxfmtrc.json +7 -0
- package/profiles/client/.oxlintrc.json +13 -0
- package/profiles/client/.vscode/settings.json +12 -0
- package/profiles/client/Dockerfile +26 -0
- package/profiles/client/bun.lock +334 -0
- package/profiles/client/client/root.css +9 -0
- package/profiles/client/client/root.tsx +17 -0
- package/profiles/client/client/routes/about.tsx +22 -0
- package/profiles/client/client/routes/index.tsx +48 -0
- package/profiles/client/flow.config.ts +3 -0
- package/profiles/client/index.html +5 -0
- package/profiles/client/package.json +32 -0
- package/profiles/client/packages/client/config.ts +68 -0
- package/profiles/client/packages/client/dom.ts +5 -0
- package/profiles/client/packages/client/features/attrs.ts +32 -0
- package/profiles/client/packages/client/features/class-flow.ts +116 -0
- package/profiles/client/packages/client/features/index.ts +8 -0
- package/profiles/client/packages/client/features/pseudo-injector.ts +40 -0
- package/profiles/client/packages/client/features/style-flow.ts +106 -0
- package/profiles/client/packages/client/features/style.ts +27 -0
- package/profiles/client/packages/client/features/utils.ts +4 -0
- package/profiles/client/packages/client/features/viewport.ts +20 -0
- package/profiles/client/packages/client/index.ts +4 -0
- package/profiles/client/packages/client/jsx-dev-runtime.ts +1 -0
- package/profiles/client/packages/client/jsx-runtime.ts +1 -0
- package/profiles/client/packages/client/jsx-types.d.ts +64 -0
- package/profiles/client/packages/client/jsx.ts +99 -0
- package/profiles/client/packages/client/package.json +42 -0
- package/profiles/client/packages/client/vite.ts +42 -0
- package/profiles/client/tsconfig.json +30 -0
- package/utils.ts +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
# create-flow
|
|
2
|
+
|
|
3
|
+
**Uso:** `bun create flow-os [nome-progetto]` (o `bunx create-flow-os [nome-progetto]`).
|
|
4
|
+
**Dev (framework):** da `packages/create-flow`: `bun run gen`, poi `bun run publish:dev`; crea progetti con `bun create flow-os mio-app --dev` per usare le versioni da npm@dev.
|
package/config.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"profiles": {
|
|
3
|
+
"client": {
|
|
4
|
+
"exclude": [
|
|
5
|
+
"packages",
|
|
6
|
+
"node_modules",
|
|
7
|
+
".git",
|
|
8
|
+
".cursor",
|
|
9
|
+
"agent-transcripts",
|
|
10
|
+
"server"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"server": {
|
|
14
|
+
"exclude": [
|
|
15
|
+
"packages",
|
|
16
|
+
"node_modules",
|
|
17
|
+
".git",
|
|
18
|
+
".cursor",
|
|
19
|
+
"agent-transcripts",
|
|
20
|
+
"client"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"full": {
|
|
24
|
+
"exclude": [
|
|
25
|
+
"packages",
|
|
26
|
+
"node_modules",
|
|
27
|
+
".git",
|
|
28
|
+
".cursor",
|
|
29
|
+
"agent-transcripts"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"packages": {
|
|
34
|
+
"core": {
|
|
35
|
+
"package": "@flow-os/core",
|
|
36
|
+
"includeIn": [
|
|
37
|
+
"client"
|
|
38
|
+
],
|
|
39
|
+
"deps": [
|
|
40
|
+
"@flow-os/core"
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"router": {
|
|
44
|
+
"package": "@flow-os/router",
|
|
45
|
+
"includeIn": [
|
|
46
|
+
"client"
|
|
47
|
+
],
|
|
48
|
+
"deps": [
|
|
49
|
+
"@flow-os/core",
|
|
50
|
+
"@flow-os/router"
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
package/gen.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Scan repo: tag // @flow-package: <id> (id = chiave in config.packages). Genera profiles/, packages/.
|
|
4
|
+
* Valida includeIn in base ai path (solo client → client, solo server → server, entrambi → full) e aggiorna config.
|
|
5
|
+
* Legge import → deps. Scrive tutto in config.json (niente manifest).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readdir, mkdir } from "node:fs/promises";
|
|
9
|
+
import { join, dirname, basename } from "node:path";
|
|
10
|
+
import { rm } from "node:fs/promises";
|
|
11
|
+
import { copyWithExclude, transformPackageJson, findPackageDir } from "./utils.ts";
|
|
12
|
+
|
|
13
|
+
const CREATE_FLOW_DIR = import.meta.dir;
|
|
14
|
+
const REPO_ROOT = (process.env.FLOW_FRAMEWORK_ROOT ?? join(CREATE_FLOW_DIR, "..", "..")).replace(/\\/g, "/");
|
|
15
|
+
|
|
16
|
+
const TAG = /^\s*\/\/\s*@flow-package\s*:\s*(\w+)\s*$/m;
|
|
17
|
+
const IMPORT_SPEC = /from\s+['"]([^'"]+)['"]|require\s*\(\s*['"]([^'"]+)['"]\)/g;
|
|
18
|
+
const EXCLUDE = new Set(["node_modules", ".git", "dist", ".cursor", "agent-transcripts"].map((s) => s.toLowerCase()));
|
|
19
|
+
const SCAN_EXT = new Set([".ts", ".tsx", ".js", ".jsx"]);
|
|
20
|
+
|
|
21
|
+
type PackageEntry = { package: string; includeIn: string[]; deps?: string[] };
|
|
22
|
+
type Config = { profiles: Record<string, { exclude: string[] }>; packages: Record<string, PackageEntry> };
|
|
23
|
+
|
|
24
|
+
function getPackageFromHead(content: string): string | null {
|
|
25
|
+
const m = content.slice(0, 500).match(TAG);
|
|
26
|
+
return m ? m[1]! : null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function stripTag(content: string): string {
|
|
30
|
+
const first = content.split(/\r?\n/)[0] ?? "";
|
|
31
|
+
if (TAG.test(first.trim())) return content.replace(/^[^\n]+\n?/, "");
|
|
32
|
+
return content;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getFlowImports(content: string): string[] {
|
|
36
|
+
const out: string[] = [];
|
|
37
|
+
let m: RegExpExecArray | null;
|
|
38
|
+
IMPORT_SPEC.lastIndex = 0;
|
|
39
|
+
while ((m = IMPORT_SPEC.exec(content)) !== null) {
|
|
40
|
+
const spec = (m[1] ?? m[2])!.trim();
|
|
41
|
+
if (spec.startsWith("@flow-os/") && !out.includes(spec)) out.push(spec);
|
|
42
|
+
}
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function walk(dir: string, rel: string, filesByPkg: Record<string, string[]>) {
|
|
47
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
48
|
+
for (const ent of entries) {
|
|
49
|
+
const name = ent.name;
|
|
50
|
+
if (EXCLUDE.has(name.toLowerCase())) continue;
|
|
51
|
+
const relPath = rel ? `${rel}/${name}` : name;
|
|
52
|
+
if (rel === "packages" && name === "create-flow") continue;
|
|
53
|
+
const full = join(dir, name);
|
|
54
|
+
if (ent.isDirectory()) {
|
|
55
|
+
await walk(full, relPath, filesByPkg);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
const ext = name.replace(/^.*\./, ".");
|
|
59
|
+
if (!SCAN_EXT.has(ext)) continue;
|
|
60
|
+
const content = await Bun.file(full).text();
|
|
61
|
+
const pkg = getPackageFromHead(content);
|
|
62
|
+
if (!pkg) continue;
|
|
63
|
+
const norm = relPath.replace(/\\/g, "/");
|
|
64
|
+
if (!filesByPkg[pkg]) filesByPkg[pkg] = [];
|
|
65
|
+
if (!filesByPkg[pkg]!.includes(norm)) filesByPkg[pkg]!.push(norm);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function main() {
|
|
70
|
+
const configPath = join(CREATE_FLOW_DIR, "config.json");
|
|
71
|
+
const config: Config = (await Bun.file(configPath).json()) as Config;
|
|
72
|
+
|
|
73
|
+
const filesByPkg: Record<string, string[]> = {};
|
|
74
|
+
await walk(REPO_ROOT, "", filesByPkg);
|
|
75
|
+
|
|
76
|
+
for (const pkgId of Object.keys(config.packages)) {
|
|
77
|
+
const entry = config.packages[pkgId]!;
|
|
78
|
+
const paths = filesByPkg[pkgId] ?? [];
|
|
79
|
+
const hasServer = paths.some((p) => p.startsWith("server/"));
|
|
80
|
+
const hasClient = paths.some((p) => p.startsWith("client/"));
|
|
81
|
+
let includeIn = entry.includeIn ?? [];
|
|
82
|
+
if (paths.length > 0) {
|
|
83
|
+
// Solo valori minimali: full = solo full; client/server = disponibili anche per full
|
|
84
|
+
if (hasServer && hasClient) includeIn = ["full"];
|
|
85
|
+
else if (hasServer) includeIn = ["server"];
|
|
86
|
+
else if (hasClient) includeIn = ["client"];
|
|
87
|
+
else includeIn = ["full"];
|
|
88
|
+
entry.includeIn = includeIn;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const profilesDir = join(CREATE_FLOW_DIR, "profiles");
|
|
93
|
+
const packagesDir = join(CREATE_FLOW_DIR, "packages");
|
|
94
|
+
await rm(profilesDir, { recursive: true, force: true });
|
|
95
|
+
await rm(packagesDir, { recursive: true, force: true });
|
|
96
|
+
|
|
97
|
+
const rootPkg = (await Bun.file(join(REPO_ROOT, "package.json")).json()) as { dependencies?: Record<string, string> };
|
|
98
|
+
const flowDepNames = Object.keys(rootPkg.dependencies ?? {}).filter((k) => k === "@flow-os" || k.startsWith("@flow-os/"));
|
|
99
|
+
|
|
100
|
+
for (const [id, profile] of Object.entries(config.profiles)) {
|
|
101
|
+
const dest = join(profilesDir, id);
|
|
102
|
+
await copyWithExclude(REPO_ROOT, dest, profile.exclude ?? []);
|
|
103
|
+
if (id === "client") {
|
|
104
|
+
const override = join(CREATE_FLOW_DIR, "flow.config.client.ts");
|
|
105
|
+
try {
|
|
106
|
+
await Bun.write(join(dest, "flow.config.ts"), Bun.file(override));
|
|
107
|
+
} catch {}
|
|
108
|
+
}
|
|
109
|
+
const pkgPath = join(dest, "package.json");
|
|
110
|
+
let pkg = (await Bun.file(pkgPath).json()) as Record<string, unknown>;
|
|
111
|
+
pkg = transformPackageJson(pkg, "placeholder", {}, false) as Record<string, unknown>;
|
|
112
|
+
const deps = (pkg.dependencies as Record<string, string>) ?? {};
|
|
113
|
+
const exclude = new Set((profile.exclude ?? []).map((s) => s.toLowerCase()));
|
|
114
|
+
const profilePackagesDir = join(dest, "packages");
|
|
115
|
+
await mkdir(profilePackagesDir, { recursive: true });
|
|
116
|
+
for (const pkgName of flowDepNames) {
|
|
117
|
+
if (exclude.has("server") && (pkgName === "@flow-os/server")) continue;
|
|
118
|
+
if (exclude.has("client") && (pkgName === "@flow-os/client")) continue;
|
|
119
|
+
const dir = await findPackageDir(REPO_ROOT, pkgName);
|
|
120
|
+
if (!dir) continue;
|
|
121
|
+
const folderName = basename(dir);
|
|
122
|
+
const destPkg = join(profilePackagesDir, folderName);
|
|
123
|
+
await copyWithExclude(dir, destPkg, ["node_modules", ".git", "dist"]);
|
|
124
|
+
deps[pkgName] = "file:./packages/" + folderName;
|
|
125
|
+
}
|
|
126
|
+
pkg.dependencies = deps;
|
|
127
|
+
delete (pkg as Record<string, unknown>).workspaces;
|
|
128
|
+
await Bun.write(pkgPath, JSON.stringify(pkg, null, 2));
|
|
129
|
+
console.log("profiles/" + id);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
for (const pkgId of Object.keys(config.packages)) {
|
|
133
|
+
const entry = config.packages[pkgId]!;
|
|
134
|
+
const paths = filesByPkg[pkgId] ?? [];
|
|
135
|
+
const dest = join(packagesDir, pkgId);
|
|
136
|
+
await mkdir(dest, { recursive: true });
|
|
137
|
+
const depsSet = new Set<string>([entry.package]);
|
|
138
|
+
const prefix = new RegExp(`^packages/${pkgId}(/scaffold)?/`);
|
|
139
|
+
for (const rel of paths) {
|
|
140
|
+
const src = join(REPO_ROOT, rel);
|
|
141
|
+
try {
|
|
142
|
+
const content = await Bun.file(src).text();
|
|
143
|
+
for (const d of getFlowImports(content)) depsSet.add(d);
|
|
144
|
+
const destRel = rel.replace(prefix, "") || rel;
|
|
145
|
+
const destFile = join(dest, destRel);
|
|
146
|
+
await mkdir(dirname(destFile), { recursive: true });
|
|
147
|
+
await Bun.write(destFile, stripTag(content));
|
|
148
|
+
} catch (e) {
|
|
149
|
+
console.warn("Skip", rel, e);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
entry.deps = [...depsSet].sort();
|
|
153
|
+
console.log("packages/" + pkgId);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
await Bun.write(configPath, JSON.stringify(config, null, 2));
|
|
157
|
+
console.log("config.json scritto (deps aggiornati).");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
main().catch((e) => {
|
|
161
|
+
console.error(e);
|
|
162
|
+
process.exit(1);
|
|
163
|
+
});
|
package/index.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* create-flow: scegli profile (full/client/server) → librerie filtrate → copia profiles/ + packages/, install.
|
|
4
|
+
* Dev: REPO_ROOT disponibile → deps con file:. Prod: bun install normale.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { rm, stat } from "node:fs/promises";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import * as p from "@clack/prompts";
|
|
10
|
+
import pc from "picocolors";
|
|
11
|
+
import { copyWithExclude, transformPackageJson } from "./utils.ts";
|
|
12
|
+
|
|
13
|
+
const argv = process.argv.slice(2);
|
|
14
|
+
const noInstall = argv.includes("--no-install");
|
|
15
|
+
const noGit = argv.includes("--no-git");
|
|
16
|
+
const force = argv.includes("--force");
|
|
17
|
+
const yes = argv.includes("--yes") || argv.includes("-y");
|
|
18
|
+
const useDevTag = argv.includes("--dev");
|
|
19
|
+
const nameArg = argv.find((a) => !a.startsWith("--"));
|
|
20
|
+
|
|
21
|
+
const DIR = import.meta.dir;
|
|
22
|
+
const REPO_ROOT = (process.env.FLOW_FRAMEWORK_ROOT ?? join(DIR, "..", "..")).replace(/\\/g, "/");
|
|
23
|
+
|
|
24
|
+
type PackageEntry = { package: string; includeIn: string[]; deps?: string[] };
|
|
25
|
+
type Config = { profiles: Record<string, { exclude?: string[] }>; packages: Record<string, PackageEntry> };
|
|
26
|
+
|
|
27
|
+
async function main() {
|
|
28
|
+
p.intro(pc.cyan(" Flow – create project\n"));
|
|
29
|
+
|
|
30
|
+
const config: Config = (await Bun.file(join(DIR, "config.json")).json()) as Config;
|
|
31
|
+
const hasDeps = Object.values(config.packages).every((e) => Array.isArray(e.deps));
|
|
32
|
+
if (!hasDeps) {
|
|
33
|
+
p.cancel("Esegui prima " + pc.cyan("bun run gen") + " dalla cartella create-flow.");
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const projectName = nameArg?.trim() || (yes ? "my-flow-app" : null);
|
|
38
|
+
let name = projectName;
|
|
39
|
+
if (!name && !yes) {
|
|
40
|
+
const r = await p.text({ message: "Project name", initialValue: "my-flow-app", validate: (v) => (!v?.trim() ? "Obbligatorio" : undefined) });
|
|
41
|
+
if (p.isCancel(r)) process.exit(0);
|
|
42
|
+
name = (r as string).trim() || "my-flow-app";
|
|
43
|
+
}
|
|
44
|
+
if (!name) name = "my-flow-app";
|
|
45
|
+
|
|
46
|
+
function optsForProfile(profileId: string) {
|
|
47
|
+
return Object.entries(config.packages).filter(([, e]) => {
|
|
48
|
+
const inc = e.includeIn ?? [];
|
|
49
|
+
if (inc.includes(profileId)) return true;
|
|
50
|
+
if (profileId === "full" && (inc.includes("client") || inc.includes("server"))) return true;
|
|
51
|
+
return false;
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
let profileId: string;
|
|
55
|
+
let selected: string[] = [];
|
|
56
|
+
const optsForFull = optsForProfile("full");
|
|
57
|
+
|
|
58
|
+
if (yes) {
|
|
59
|
+
profileId = "full";
|
|
60
|
+
selected = optsForFull.map(([id]) => id);
|
|
61
|
+
} else {
|
|
62
|
+
const complete = await p.select({
|
|
63
|
+
message: "Vuoi installare tutto completo? (tutti i package)",
|
|
64
|
+
options: [
|
|
65
|
+
{ value: "yes", label: "Sì, tutto completo" },
|
|
66
|
+
{ value: "no", label: "No, scelgo profile e package" },
|
|
67
|
+
],
|
|
68
|
+
});
|
|
69
|
+
if (p.isCancel(complete)) process.exit(0);
|
|
70
|
+
if (complete === "yes") {
|
|
71
|
+
profileId = "full";
|
|
72
|
+
selected = optsForFull.map(([id]) => id);
|
|
73
|
+
} else {
|
|
74
|
+
const profile = await p.select({
|
|
75
|
+
message: "Client, Server o Client+Server?",
|
|
76
|
+
options: [
|
|
77
|
+
{ value: "client", label: "Client" },
|
|
78
|
+
{ value: "server", label: "Server" },
|
|
79
|
+
{ value: "full", label: "Client + Server" },
|
|
80
|
+
],
|
|
81
|
+
});
|
|
82
|
+
if (p.isCancel(profile)) process.exit(0);
|
|
83
|
+
profileId = profile as string;
|
|
84
|
+
const opts = optsForProfile(profileId);
|
|
85
|
+
if (opts.length > 0) {
|
|
86
|
+
const r = await p.multiselect({
|
|
87
|
+
message: "Scegli i package",
|
|
88
|
+
options: opts.map(([id]) => ({ value: id, label: id })),
|
|
89
|
+
required: false,
|
|
90
|
+
});
|
|
91
|
+
if (!p.isCancel(r)) selected = (r as string[]) ?? [];
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const projectPath = join(process.cwd(), name);
|
|
97
|
+
const exists = await stat(projectPath).then(() => true).catch(() => false);
|
|
98
|
+
if (exists && !force) {
|
|
99
|
+
p.cancel("Esiste già: " + name + ". Usa " + pc.cyan("--force") + ".");
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
if (exists) await rm(projectPath, { recursive: true, force: true });
|
|
103
|
+
|
|
104
|
+
const profileDir = join(DIR, "profiles", profileId);
|
|
105
|
+
try {
|
|
106
|
+
await stat(profileDir);
|
|
107
|
+
} catch {
|
|
108
|
+
p.cancel("Profile " + profileId + " non trovato. Esegui " + pc.cyan("bun run gen") + ".");
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const scaffoldSpinner = p.spinner();
|
|
113
|
+
scaffoldSpinner.start("Scaffold");
|
|
114
|
+
await copyWithExclude(profileDir, projectPath, ["node_modules", ".git"]);
|
|
115
|
+
for (const id of selected) {
|
|
116
|
+
const pkgDir = join(DIR, "packages", id);
|
|
117
|
+
try {
|
|
118
|
+
await copyWithExclude(pkgDir, projectPath, []);
|
|
119
|
+
} catch {}
|
|
120
|
+
}
|
|
121
|
+
scaffoldSpinner.stop("Scaffold");
|
|
122
|
+
|
|
123
|
+
const extraDeps: Record<string, string> = {};
|
|
124
|
+
for (const id of selected) {
|
|
125
|
+
const deps = config.packages[id]?.deps;
|
|
126
|
+
if (deps) for (const d of deps) extraDeps[d] = "^0.0.1";
|
|
127
|
+
}
|
|
128
|
+
const pkgPath = join(projectPath, "package.json");
|
|
129
|
+
const pkg = (await Bun.file(pkgPath).json()) as Record<string, unknown>;
|
|
130
|
+
await Bun.write(pkgPath, JSON.stringify(transformPackageJson(pkg, name, extraDeps, false), null, 2));
|
|
131
|
+
|
|
132
|
+
if (!noGit) {
|
|
133
|
+
try {
|
|
134
|
+
await Bun.$`git init ${projectPath}`.quiet();
|
|
135
|
+
await Bun.$`git -C ${projectPath} add -A`.quiet();
|
|
136
|
+
await Bun.$`git -C ${projectPath} commit -m "Initial commit (Flow)"`.quiet();
|
|
137
|
+
} catch {}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const finalPkg = (await Bun.file(pkgPath).json()) as { workspaces?: string[]; dependencies?: Record<string, string> };
|
|
141
|
+
delete finalPkg.workspaces;
|
|
142
|
+
if (finalPkg.dependencies) {
|
|
143
|
+
for (const k of Object.keys(finalPkg.dependencies)) {
|
|
144
|
+
if (finalPkg.dependencies[k] === "workspace:*") finalPkg.dependencies[k] = "^0.0.1";
|
|
145
|
+
if (useDevTag && (k === "@flow-os" || k.startsWith("@flow-os/"))) finalPkg.dependencies[k] = "dev";
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
await Bun.write(pkgPath, JSON.stringify(finalPkg, null, 2));
|
|
149
|
+
|
|
150
|
+
if (useDevTag) {
|
|
151
|
+
const projectPackagesDir = join(projectPath, "packages");
|
|
152
|
+
try {
|
|
153
|
+
await rm(projectPackagesDir, { recursive: true, force: true });
|
|
154
|
+
} catch {}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!noInstall) {
|
|
158
|
+
const s = p.spinner();
|
|
159
|
+
s.start("Install");
|
|
160
|
+
const proc = Bun.spawn(["bun", "install"], { cwd: projectPath, stdout: "pipe", stderr: "pipe" });
|
|
161
|
+
const code = await proc.exited;
|
|
162
|
+
s.stop(code === 0 ? "Install ok" : "Install failed");
|
|
163
|
+
if (code !== 0) {
|
|
164
|
+
const err = await new Response(proc.stderr).text();
|
|
165
|
+
p.log.error(err || "bun install exit " + code);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
p.outro([pc.green("Ok."), "", " " + pc.cyan("cd " + name), " " + pc.cyan("bun run dev")].join("\n"));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
main().catch((e) => {
|
|
173
|
+
p.log.error(String(e));
|
|
174
|
+
process.exit(1);
|
|
175
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-flow-os",
|
|
3
|
+
"version": "0.0.1-dev.1771614697",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"create-flow-os": "./index.ts"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"index.ts",
|
|
10
|
+
"utils.ts",
|
|
11
|
+
"gen.ts",
|
|
12
|
+
"config.json",
|
|
13
|
+
"flow.config.client.ts",
|
|
14
|
+
"profiles",
|
|
15
|
+
"packages"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"gen": "bun gen.ts",
|
|
19
|
+
"create": "bun index.ts",
|
|
20
|
+
"publish:dev": "bun publish-dev.ts"
|
|
21
|
+
},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@clack/prompts": "^0.8.2",
|
|
24
|
+
"picocolors": "^1.1.1"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"bun-types": "~1.2.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# DEV: packages/flow-os → workaround Bun workspace (doppio install).
|
|
2
|
+
# PROD: install → build → start (PORT da env)
|
|
3
|
+
|
|
4
|
+
FROM oven/bun:1 AS builder
|
|
5
|
+
WORKDIR /app
|
|
6
|
+
COPY . .
|
|
7
|
+
RUN if [ -d packages ] && [ -f packages/flow-os/package.json ]; then \
|
|
8
|
+
bun install || true && bun install; \
|
|
9
|
+
else \
|
|
10
|
+
bun install --frozen-lockfile; \
|
|
11
|
+
fi
|
|
12
|
+
RUN bun run build
|
|
13
|
+
RUN mkdir -p out && cp package.json bun.lock* out/ && cp -r dist server out/ && ([ -d packages ] && cp -r packages out/ || true)
|
|
14
|
+
|
|
15
|
+
FROM oven/bun:1
|
|
16
|
+
WORKDIR /app
|
|
17
|
+
ENV NODE_ENV=production
|
|
18
|
+
ENV PORT=3000
|
|
19
|
+
COPY --from=builder /app/out/ ./
|
|
20
|
+
RUN if [ -d packages ] && [ -f packages/flow-os/package.json ]; then \
|
|
21
|
+
bun install --frozen-lockfile --production || true && bun install --frozen-lockfile --production; \
|
|
22
|
+
else \
|
|
23
|
+
bun install --frozen-lockfile --production; \
|
|
24
|
+
fi
|
|
25
|
+
EXPOSE 3000
|
|
26
|
+
CMD ["bun", "run", "start"]
|