create-doop 0.1.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/index.mjs +148 -0
- package/package.json +28 -0
package/index.mjs
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execSync, spawnSync } from "node:child_process";
|
|
3
|
+
import { existsSync, cpSync, readFileSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { resolve, basename } from "node:path";
|
|
5
|
+
import { randomBytes } from "node:crypto";
|
|
6
|
+
|
|
7
|
+
const REPO = "https://github.com/idanbier999/doop-os.git";
|
|
8
|
+
const BOLD = "\x1b[1m";
|
|
9
|
+
const GREEN = "\x1b[32m";
|
|
10
|
+
const CYAN = "\x1b[36m";
|
|
11
|
+
const DIM = "\x1b[2m";
|
|
12
|
+
const RESET = "\x1b[0m";
|
|
13
|
+
|
|
14
|
+
function log(msg) {
|
|
15
|
+
console.log(`${GREEN}==>${RESET} ${msg}`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function dim(msg) {
|
|
19
|
+
console.log(`${DIM} ${msg}${RESET}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function run(cmd, opts = {}) {
|
|
23
|
+
return execSync(cmd, { stdio: "inherit", ...opts });
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function hasCommand(cmd) {
|
|
27
|
+
const { status } = spawnSync("which", [cmd], { stdio: "ignore" });
|
|
28
|
+
return status === 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Parse args
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
const args = process.argv.slice(2).filter((a) => !a.startsWith("-"));
|
|
35
|
+
const flags = process.argv.slice(2).filter((a) => a.startsWith("-"));
|
|
36
|
+
|
|
37
|
+
if (flags.includes("--help") || flags.includes("-h")) {
|
|
38
|
+
console.log(`
|
|
39
|
+
${BOLD}create-doop${RESET} — scaffold the Doop operating system for your AI workforce
|
|
40
|
+
|
|
41
|
+
${BOLD}Usage${RESET}
|
|
42
|
+
npx create-doop [directory]
|
|
43
|
+
|
|
44
|
+
${BOLD}Options${RESET}
|
|
45
|
+
--help, -h Show this help message
|
|
46
|
+
|
|
47
|
+
If no directory is given, defaults to ${CYAN}doop-dashboard${RESET}.
|
|
48
|
+
`);
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const dir = args[0] || "doop-dashboard";
|
|
53
|
+
const dest = resolve(process.cwd(), dir);
|
|
54
|
+
|
|
55
|
+
if (existsSync(dest)) {
|
|
56
|
+
console.error(
|
|
57
|
+
`\n Directory ${CYAN}${dir}${RESET} already exists. Pick a different name or remove it.\n`
|
|
58
|
+
);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// 1. Clone
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
console.log();
|
|
66
|
+
log(`Cloning Doop into ${CYAN}${dir}${RESET} ...`);
|
|
67
|
+
run(`git clone --depth 1 ${REPO} "${dest}"`);
|
|
68
|
+
// Remove .git so the user starts with a clean history
|
|
69
|
+
execSync(`rm -rf "${dest}/.git"`);
|
|
70
|
+
run(`git init`, { cwd: dest });
|
|
71
|
+
|
|
72
|
+
// ---------------------------------------------------------------------------
|
|
73
|
+
// 2. Install
|
|
74
|
+
// ---------------------------------------------------------------------------
|
|
75
|
+
log("Installing dependencies ...");
|
|
76
|
+
run("npm install", { cwd: dest });
|
|
77
|
+
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// 3. Environment
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
const envExample = resolve(dest, ".env.example");
|
|
82
|
+
const envLocal = resolve(dest, ".env.local");
|
|
83
|
+
|
|
84
|
+
if (existsSync(envExample) && !existsSync(envLocal)) {
|
|
85
|
+
log("Creating .env.local ...");
|
|
86
|
+
cpSync(envExample, envLocal);
|
|
87
|
+
|
|
88
|
+
// Generate a random BETTER_AUTH_SECRET
|
|
89
|
+
let env = readFileSync(envLocal, "utf-8");
|
|
90
|
+
const secret = randomBytes(32).toString("hex");
|
|
91
|
+
env = env.replace(/BETTER_AUTH_SECRET=.*/, `BETTER_AUTH_SECRET=${secret}`);
|
|
92
|
+
writeFileSync(envLocal, env);
|
|
93
|
+
dim("Generated random BETTER_AUTH_SECRET");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
// 4. Local Supabase (if available)
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
const hasSupabase = hasCommand("supabase");
|
|
100
|
+
const hasDocker =
|
|
101
|
+
hasCommand("docker") && spawnSync("docker", ["info"], { stdio: "ignore" }).status === 0;
|
|
102
|
+
|
|
103
|
+
if (hasSupabase && hasDocker) {
|
|
104
|
+
log("Starting local Supabase ...");
|
|
105
|
+
try {
|
|
106
|
+
run("supabase start", { cwd: dest });
|
|
107
|
+
|
|
108
|
+
// Read status and inject credentials
|
|
109
|
+
const status = execSync("supabase status --output json", {
|
|
110
|
+
cwd: dest,
|
|
111
|
+
encoding: "utf-8",
|
|
112
|
+
});
|
|
113
|
+
const info = JSON.parse(status);
|
|
114
|
+
|
|
115
|
+
let env = readFileSync(envLocal, "utf-8");
|
|
116
|
+
const replacements = {
|
|
117
|
+
NEXT_PUBLIC_SUPABASE_URL: info["API URL"],
|
|
118
|
+
NEXT_PUBLIC_SUPABASE_ANON_KEY: info["anon key"],
|
|
119
|
+
SUPABASE_SERVICE_ROLE_KEY: info["service_role key"],
|
|
120
|
+
SUPABASE_JWT_SECRET: info["JWT secret"],
|
|
121
|
+
DATABASE_URL: info["DB URL"],
|
|
122
|
+
};
|
|
123
|
+
for (const [key, value] of Object.entries(replacements)) {
|
|
124
|
+
if (value) {
|
|
125
|
+
env = env.replace(new RegExp(`${key}=.*`), `${key}=${value}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
writeFileSync(envLocal, env);
|
|
129
|
+
dim("Local Supabase credentials written to .env.local");
|
|
130
|
+
} catch {
|
|
131
|
+
dim("Supabase start failed — fill in .env.local manually.");
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
dim("Supabase CLI or Docker not detected — skipping local database.");
|
|
135
|
+
dim("Fill in .env.local manually (see .env.example).");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// Done
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
console.log(`
|
|
142
|
+
${GREEN}${BOLD} Done!${RESET} Your Doop AI workforce OS is ready.
|
|
143
|
+
|
|
144
|
+
${BOLD}cd ${dir}${RESET}
|
|
145
|
+
${BOLD}npm run dev${RESET}
|
|
146
|
+
|
|
147
|
+
Then open ${CYAN}http://localhost:3000${RESET}
|
|
148
|
+
`);
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-doop",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Scaffold the Doop operating system for your AI workforce",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"bin": {
|
|
7
|
+
"create-doop": "./index.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.mjs"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"doop",
|
|
14
|
+
"ai-agents",
|
|
15
|
+
"ai-workforce",
|
|
16
|
+
"operating-system",
|
|
17
|
+
"scaffold",
|
|
18
|
+
"create"
|
|
19
|
+
],
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/idanbier999/doop-os",
|
|
23
|
+
"directory": "packages/create-doop"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=20"
|
|
27
|
+
}
|
|
28
|
+
}
|