start-jibril 1.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/index.js +258 -0
- package/package.json +22 -0
package/index.js
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { execSync, spawnSync } = require("child_process");
|
|
5
|
+
const readline = require("readline");
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const os = require("os");
|
|
9
|
+
|
|
10
|
+
const REPO = "https://github.com/dancinglightning/Jibril.git";
|
|
11
|
+
|
|
12
|
+
// ── Terminal colours ──────────────────────────────────────────────────────────
|
|
13
|
+
const isTTY = process.stdout.isTTY;
|
|
14
|
+
const G = isTTY ? "\x1b[32m" : ""; // green
|
|
15
|
+
const Y = isTTY ? "\x1b[33m" : ""; // yellow
|
|
16
|
+
const R = isTTY ? "\x1b[31m" : ""; // red
|
|
17
|
+
const B = isTTY ? "\x1b[1m" : ""; // bold
|
|
18
|
+
const D = isTTY ? "\x1b[2m" : ""; // dim
|
|
19
|
+
const X = isTTY ? "\x1b[0m" : ""; // reset
|
|
20
|
+
|
|
21
|
+
const log = (m = "") => process.stdout.write(m + "\n");
|
|
22
|
+
const ok = (m) => log(` ${G}✓${X} ${m}`);
|
|
23
|
+
const warn = (m) => log(` ${Y}!${X} ${m}`);
|
|
24
|
+
const fail = (m) => { log(` ${R}✗${X} ${m}`); process.exit(1); };
|
|
25
|
+
const h = (m) => log(`\n ${B}${m}${X}`);
|
|
26
|
+
|
|
27
|
+
function run(cmd, opts = {}) {
|
|
28
|
+
return execSync(cmd, { encoding: "utf8", stdio: opts.quiet ? "pipe" : "inherit", cwd: opts.cwd });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function ask(rl, prompt) {
|
|
32
|
+
return new Promise((res) => rl.question(prompt, res));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ── Prerequisites ─────────────────────────────────────────────────────────────
|
|
36
|
+
function checkPrereqs() {
|
|
37
|
+
h("Checking prerequisites...");
|
|
38
|
+
log();
|
|
39
|
+
|
|
40
|
+
// Node 20+ (we're already running, so just version check)
|
|
41
|
+
const major = parseInt(process.version.slice(1));
|
|
42
|
+
if (major < 20) fail(`Node.js ${process.version} is too old — need 20+. https://nodejs.org`);
|
|
43
|
+
ok(`Node.js ${process.version}`);
|
|
44
|
+
|
|
45
|
+
// git
|
|
46
|
+
try { run("git --version", { quiet: true }); ok("git"); }
|
|
47
|
+
catch { fail("git not found — install from https://git-scm.com"); }
|
|
48
|
+
|
|
49
|
+
// Claude Code CLI
|
|
50
|
+
try { run("claude --version", { quiet: true }); ok("Claude Code CLI"); }
|
|
51
|
+
catch {
|
|
52
|
+
log();
|
|
53
|
+
log(" Claude Code CLI is required but not installed.");
|
|
54
|
+
log();
|
|
55
|
+
log(` Install: ${B}npm install -g @anthropic-ai/claude-code${X}`);
|
|
56
|
+
log(` Authenticate: ${B}claude auth${X}`);
|
|
57
|
+
log(` Then re-run: ${B}npx start-jibril${X}`);
|
|
58
|
+
log();
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Claude auth
|
|
63
|
+
const creds = path.join(os.homedir(), ".claude", ".credentials.json");
|
|
64
|
+
if (!fs.existsSync(creds)) {
|
|
65
|
+
log();
|
|
66
|
+
log(` Claude Code is installed but not authenticated.`);
|
|
67
|
+
log(` Run ${B}claude auth${X} first, then re-run ${B}npx start-jibril${X}.`);
|
|
68
|
+
log();
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
ok("Claude Code authenticated");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ── Resume if already installed ───────────────────────────────────────────────
|
|
75
|
+
function tryResume() {
|
|
76
|
+
// Check if `jibril` command is already on PATH
|
|
77
|
+
try {
|
|
78
|
+
execSync("which jibril", { stdio: "pipe" });
|
|
79
|
+
} catch {
|
|
80
|
+
try {
|
|
81
|
+
execSync("where jibril", { stdio: "pipe" }); // Windows
|
|
82
|
+
} catch {
|
|
83
|
+
return false; // not installed
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
log();
|
|
88
|
+
log(` ${B}Jibril is already set up.${X} Resuming your session...`);
|
|
89
|
+
log();
|
|
90
|
+
const result = spawnSync("jibril", [], { stdio: "inherit" });
|
|
91
|
+
process.exit(result.status ?? 0);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
95
|
+
async function main() {
|
|
96
|
+
// If already installed, just start the session — no setup needed
|
|
97
|
+
tryResume();
|
|
98
|
+
|
|
99
|
+
log();
|
|
100
|
+
log(` ${B}╔══════════════════════════════════════╗${X}`);
|
|
101
|
+
log(` ${B}║ Start Jibril ║${X}`);
|
|
102
|
+
log(` ${B}║ self-evolving AI assistant ║${X}`);
|
|
103
|
+
log(` ${B}╚══════════════════════════════════════╝${X}`);
|
|
104
|
+
log();
|
|
105
|
+
|
|
106
|
+
checkPrereqs();
|
|
107
|
+
|
|
108
|
+
// ── Target directory ────────────────────────────────────────────────────────
|
|
109
|
+
const arg = process.argv[2];
|
|
110
|
+
const targetName = arg || "jibril";
|
|
111
|
+
const targetDir = path.resolve(process.cwd(), targetName);
|
|
112
|
+
|
|
113
|
+
if (fs.existsSync(targetDir)) {
|
|
114
|
+
fail(
|
|
115
|
+
`Directory already exists: ${targetDir}\n\n` +
|
|
116
|
+
` If Jibril is installed there, add it to PATH and run: jibril\n` +
|
|
117
|
+
` Or pick a new directory: npx start-jibril my-jibril`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ── Clone ───────────────────────────────────────────────────────────────────
|
|
122
|
+
h("Cloning Jibril...");
|
|
123
|
+
log();
|
|
124
|
+
run(`git clone "${REPO}" "${targetDir}"`);
|
|
125
|
+
ok(`Cloned to ${targetDir}`);
|
|
126
|
+
|
|
127
|
+
// ── Install deps ────────────────────────────────────────────────────────────
|
|
128
|
+
h("Installing dependencies...");
|
|
129
|
+
log();
|
|
130
|
+
|
|
131
|
+
const webDir = path.join(targetDir, "web");
|
|
132
|
+
const channelsDir = path.join(targetDir, "channels");
|
|
133
|
+
|
|
134
|
+
if (fs.existsSync(webDir)) {
|
|
135
|
+
log(" Installing web UI dependencies...");
|
|
136
|
+
run("npm install --silent", { cwd: webDir });
|
|
137
|
+
ok("web/ ready");
|
|
138
|
+
}
|
|
139
|
+
if (fs.existsSync(channelsDir)) {
|
|
140
|
+
log(" Installing channel server dependencies...");
|
|
141
|
+
run("npm install --silent", { cwd: channelsDir });
|
|
142
|
+
ok("channels/ ready");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ── Personalise ─────────────────────────────────────────────────────────────
|
|
146
|
+
h("Personalize Jibril");
|
|
147
|
+
log();
|
|
148
|
+
|
|
149
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
150
|
+
const rawName = (await ask(rl, " Your name (e.g. Alex): ")).trim();
|
|
151
|
+
const name = rawName || "User";
|
|
152
|
+
const rawShort = (await ask(rl, ` Nickname (Enter = "${name}"): `)).trim();
|
|
153
|
+
const short = rawShort || name;
|
|
154
|
+
rl.close();
|
|
155
|
+
|
|
156
|
+
// Write memory files
|
|
157
|
+
const memDir = path.join(targetDir, "memory");
|
|
158
|
+
const stateDir = path.join(memDir, "state");
|
|
159
|
+
for (const d of [
|
|
160
|
+
stateDir,
|
|
161
|
+
path.join(memDir, "self_model"),
|
|
162
|
+
path.join(memDir, "evolution_log"),
|
|
163
|
+
path.join(memDir, "snapshots"),
|
|
164
|
+
path.join(memDir, "feedback"),
|
|
165
|
+
path.join(memDir, "tasks"),
|
|
166
|
+
]) fs.mkdirSync(d, { recursive: true });
|
|
167
|
+
|
|
168
|
+
fs.writeFileSync(
|
|
169
|
+
path.join(memDir, "user_profile.json"),
|
|
170
|
+
JSON.stringify({ name, short_name: short, preferences: { theme: "dark" }, updated_at: new Date().toISOString().slice(0, 10) }, null, 2)
|
|
171
|
+
);
|
|
172
|
+
ok(`Profile saved — welcome, ${name}!`);
|
|
173
|
+
|
|
174
|
+
const write = (file, content) => {
|
|
175
|
+
if (!fs.existsSync(file)) fs.writeFileSync(file, content);
|
|
176
|
+
};
|
|
177
|
+
write(path.join(memDir, "journal.md"), "# Jibril Journal\n\nThis journal grows as Jibril learns from your sessions.\n");
|
|
178
|
+
write(path.join(memDir, "proactive.json"), JSON.stringify({ version: 1, reminders: [], thought_seeds: [], follow_ups: [] }, null, 2));
|
|
179
|
+
write(
|
|
180
|
+
path.join(memDir, "schedules.json"),
|
|
181
|
+
JSON.stringify({
|
|
182
|
+
schedules: [
|
|
183
|
+
{ name: "proactive-pulse", cron: "*/5 * * * *", prompt: "Proactive Pulse -- think proactively, check proactive.json, surface due reminders", enabled: true },
|
|
184
|
+
{ name: "end-of-day-nudge", cron: "47 17 * * *", prompt: "End of Day -- suggest wrap-up, summarize accomplishments, offer /session-end", enabled: true },
|
|
185
|
+
],
|
|
186
|
+
}, null, 2)
|
|
187
|
+
);
|
|
188
|
+
write(path.join(memDir, "feedback", "pending.json"), JSON.stringify({ pending: [] }));
|
|
189
|
+
write(path.join(stateDir, "first_run.json"), JSON.stringify({ first_run_completed: false, onboarding_version: 1 }, null, 2));
|
|
190
|
+
|
|
191
|
+
// ── MCP config ──────────────────────────────────────────────────────────────
|
|
192
|
+
h("Configuring MCP server...");
|
|
193
|
+
log();
|
|
194
|
+
|
|
195
|
+
const claudeDir = path.join(targetDir, ".claude");
|
|
196
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
197
|
+
fs.writeFileSync(
|
|
198
|
+
path.join(claudeDir, "mcp_config.json"),
|
|
199
|
+
JSON.stringify(
|
|
200
|
+
{ mcpServers: { "web-chat": { command: "npx", args: ["tsx", "web-chat.ts"], cwd: channelsDir } } },
|
|
201
|
+
null, 2
|
|
202
|
+
)
|
|
203
|
+
);
|
|
204
|
+
ok("MCP config written");
|
|
205
|
+
|
|
206
|
+
// ── Make scripts executable ─────────────────────────────────────────────────
|
|
207
|
+
try { run(`chmod +x "${path.join(targetDir, "jibril.sh")}"`, { quiet: true }); } catch {}
|
|
208
|
+
try { run(`chmod +x "${path.join(targetDir, "jibril-start-web.sh")}"`, { quiet: true }); } catch {}
|
|
209
|
+
|
|
210
|
+
// ── Global command ───────────────────────────────────────────────────────────
|
|
211
|
+
h("Installing global 'jibril' command...");
|
|
212
|
+
log();
|
|
213
|
+
|
|
214
|
+
const jibrilScript = path.join(targetDir, "jibril.sh");
|
|
215
|
+
const globalBin = "/usr/local/bin/jibril";
|
|
216
|
+
let globalInstalled = false;
|
|
217
|
+
|
|
218
|
+
// Try direct, then sudo
|
|
219
|
+
for (const usesSudo of [false, true]) {
|
|
220
|
+
const result = spawnSync(
|
|
221
|
+
usesSudo ? "sudo" : "ln",
|
|
222
|
+
usesSudo ? ["ln", "-sf", jibrilScript, globalBin] : ["-sf", jibrilScript, globalBin],
|
|
223
|
+
{ stdio: usesSudo ? "inherit" : "pipe" }
|
|
224
|
+
);
|
|
225
|
+
if (result.status === 0) {
|
|
226
|
+
ok(`Installed: ${globalBin}`);
|
|
227
|
+
globalInstalled = true;
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (!globalInstalled) {
|
|
233
|
+
warn(`Could not install to ${globalBin}.`);
|
|
234
|
+
warn(`Add this to your shell profile to use 'jibril' anywhere:`);
|
|
235
|
+
log(` export PATH="${targetDir}:$PATH"`);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ── Done ────────────────────────────────────────────────────────────────────
|
|
239
|
+
log();
|
|
240
|
+
log(` ${B}${G}╔══════════════════════════════════════╗${X}`);
|
|
241
|
+
log(` ${B}${G}║ Jibril is ready! ║${X}`);
|
|
242
|
+
log(` ${B}${G}╚══════════════════════════════════════╝${X}`);
|
|
243
|
+
log();
|
|
244
|
+
log(` ${B}Start a session:${X}`);
|
|
245
|
+
log(` ${G}jibril${X}`);
|
|
246
|
+
log();
|
|
247
|
+
log(` ${B}Web UI + mobile:${X}`);
|
|
248
|
+
log(` ${D}cd ${targetDir}${X}`);
|
|
249
|
+
log(` ${G}./jibril-start-web.sh${X} ${D}# opens http://localhost:3333${X}`);
|
|
250
|
+
log();
|
|
251
|
+
log(` ${D}On first launch Jibril will introduce itself.${X}`);
|
|
252
|
+
log();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
main().catch((e) => {
|
|
256
|
+
process.stderr.write(`\nError: ${e.message}\n`);
|
|
257
|
+
process.exit(1);
|
|
258
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "start-jibril",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Set up and start Jibril — the self-evolving AI assistant — in one command",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"jibril",
|
|
7
|
+
"ai",
|
|
8
|
+
"claude",
|
|
9
|
+
"assistant"
|
|
10
|
+
],
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"bin": {
|
|
13
|
+
"start-jibril": "index.js"
|
|
14
|
+
},
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=20"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/dancinglightning/Jibril.git"
|
|
21
|
+
}
|
|
22
|
+
}
|