unoverse 0.1.31 → 0.1.33
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/bin/unoverse.mjs +22 -12
- package/operator/lib/init.sh +27 -3
- package/operator/lib/start.sh +27 -0
- package/operator/operator.sh +16 -0
- package/package.json +1 -1
package/bin/unoverse.mjs
CHANGED
|
@@ -103,26 +103,36 @@ switch (cmd) {
|
|
|
103
103
|
break;
|
|
104
104
|
|
|
105
105
|
case "update": {
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
//
|
|
106
|
+
// ONE update: the CLI from npm, then everything the CLI is responsible for keeping
|
|
107
|
+
// current — the repo-local authoring skill and, in a universe, the platform images.
|
|
108
|
+
// Those two steps run via `_postupdate` in the NEWLY installed binary, not this
|
|
109
|
+
// process: this file is being replaced mid-command, and copying the skill from the
|
|
110
|
+
// old install would pin it one release behind forever.
|
|
111
|
+
const r = spawnSync("npm", ["install", "-g", "unoverse@latest"], { stdio: "inherit" });
|
|
112
|
+
if (r.status === 0) {
|
|
113
|
+
const v = spawnSync("unoverse", ["-v"], { encoding: "utf8" }).stdout?.trim();
|
|
114
|
+
console.log(`\n ✓ unoverse is now ${v || "up to date"}`);
|
|
115
|
+
spawnSync("unoverse", ["_postupdate"], { stdio: "inherit" });
|
|
116
|
+
} else {
|
|
117
|
+
console.log(`\n ✗ global install failed (permissions?). Try:\n\n sudo npm install -g unoverse@latest\n npx unoverse@latest # or skip the global install entirely\n`);
|
|
118
|
+
}
|
|
119
|
+
process.exit(r.status ?? 0);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
case "_postupdate": {
|
|
123
|
+
// Runs AS the new version, in the developer's cwd. Outside a universe there is
|
|
124
|
+
// nothing to refresh, and silence is the right answer.
|
|
109
125
|
if (UNIVERSE) {
|
|
110
126
|
const skillSrc = join(dirname(fileURLToPath(import.meta.url)), "../operator/skills/unoverse-create");
|
|
111
127
|
if (existsSync(skillSrc)) {
|
|
112
128
|
const { cpSync, mkdirSync } = await import("node:fs");
|
|
113
129
|
mkdirSync(join(UNIVERSE.root, ".claude/skills"), { recursive: true });
|
|
114
130
|
cpSync(skillSrc, join(UNIVERSE.root, ".claude/skills/unoverse-create"), { recursive: true });
|
|
115
|
-
console.log(" ✓ authoring skill refreshed
|
|
131
|
+
console.log(" ✓ authoring skill refreshed");
|
|
116
132
|
}
|
|
133
|
+
operator(UNIVERSE, ["refresh-images"]);
|
|
117
134
|
}
|
|
118
|
-
|
|
119
|
-
if (r.status === 0) {
|
|
120
|
-
const v = spawnSync("unoverse", ["-v"], { encoding: "utf8" }).stdout?.trim();
|
|
121
|
-
console.log(`\n ✓ unoverse is now ${v || "up to date"}\n`);
|
|
122
|
-
} else {
|
|
123
|
-
console.log(`\n ✗ global install failed (permissions?). Try:\n\n sudo npm install -g unoverse@latest\n npx unoverse@latest # or skip the global install entirely\n`);
|
|
124
|
-
}
|
|
125
|
-
process.exit(r.status ?? 0);
|
|
135
|
+
process.exit(0);
|
|
126
136
|
}
|
|
127
137
|
|
|
128
138
|
// `urls` stays as an alias: it shipped in 0.1.4/0.1.5 and is in people's fingers.
|
package/operator/lib/init.sh
CHANGED
|
@@ -256,6 +256,24 @@ cmd_init() {
|
|
|
256
256
|
[ -z "$OPENAI_API_KEY" ] && warn "No OpenAI key: the universe starts, but agents, embeddings and memory will not work until one is in .env"
|
|
257
257
|
fi
|
|
258
258
|
|
|
259
|
+
# Node vendor keys, OPTIONAL: only the matching nodes need them, nothing platform-level
|
|
260
|
+
# does. Asked so compose stops warning about them and so they land in .env with names.
|
|
261
|
+
local cur_hb cur_sa
|
|
262
|
+
cur_hb=$(_env_cur HYPERBROWSER_API_KEY)
|
|
263
|
+
if [ -n "$cur_hb" ]; then
|
|
264
|
+
read -p " HYPERBROWSER_API_KEY [keep current]: " HYPERBROWSER_API_KEY
|
|
265
|
+
HYPERBROWSER_API_KEY="${HYPERBROWSER_API_KEY:-$cur_hb}"
|
|
266
|
+
else
|
|
267
|
+
read -p " HYPERBROWSER_API_KEY (browser nodes, blank to skip): " HYPERBROWSER_API_KEY
|
|
268
|
+
fi
|
|
269
|
+
cur_sa=$(_env_cur SEARCHAPI_KEY)
|
|
270
|
+
if [ -n "$cur_sa" ]; then
|
|
271
|
+
read -p " SEARCHAPI_KEY [keep current]: " SEARCHAPI_KEY
|
|
272
|
+
SEARCHAPI_KEY="${SEARCHAPI_KEY:-$cur_sa}"
|
|
273
|
+
else
|
|
274
|
+
read -p " SEARCHAPI_KEY (web-search nodes, blank to skip): " SEARCHAPI_KEY
|
|
275
|
+
fi
|
|
276
|
+
|
|
259
277
|
# Write .env
|
|
260
278
|
cat > "$ROOT/.env" << ENVEOF
|
|
261
279
|
# Generated by unoverse init
|
|
@@ -272,6 +290,8 @@ AUTH_CLIENT_ID=${AUTH_CLIENT_ID}
|
|
|
272
290
|
AUTH_AUDIENCE=${AUTH_AUDIENCE}
|
|
273
291
|
API_URL=${API_URL}
|
|
274
292
|
OPENAI_API_KEY=${OPENAI_API_KEY}
|
|
293
|
+
HYPERBROWSER_API_KEY=${HYPERBROWSER_API_KEY}
|
|
294
|
+
SEARCHAPI_KEY=${SEARCHAPI_KEY}
|
|
275
295
|
DOMAIN=
|
|
276
296
|
ENVEOF
|
|
277
297
|
|
|
@@ -288,7 +308,7 @@ ENVEOF
|
|
|
288
308
|
fail "DOCR login failed. Check your token"
|
|
289
309
|
exit 1
|
|
290
310
|
fi
|
|
291
|
-
|
|
311
|
+
pull_missing_images
|
|
292
312
|
else
|
|
293
313
|
echo ""
|
|
294
314
|
info "Skipped the registry login and image pull. ${BOLD}unoverse start${NC} does both once Docker is up"
|
|
@@ -306,11 +326,14 @@ ENVEOF
|
|
|
306
326
|
# A database that is not reachable yet is not a failed setup — .env is written and
|
|
307
327
|
# correct, so say so and move on rather than unwinding everything.
|
|
308
328
|
echo ""
|
|
329
|
+
# SUBSHELL, deliberately: cmd_db_setup exits on "services not up yet", and an exit in a
|
|
330
|
+
# sourced function would take all of init with it — setup then reported failure for a
|
|
331
|
+
# situation that just means "migrations run on start". Which they now do (start.sh).
|
|
309
332
|
if grep -q '^DATABASE_URL=' "$ROOT/.env" 2>/dev/null; then
|
|
310
|
-
if cmd_db_setup; then
|
|
333
|
+
if (cmd_db_setup); then
|
|
311
334
|
ok "Database schema is up to date"
|
|
312
335
|
else
|
|
313
|
-
|
|
336
|
+
info "Migrations wait for the platform: ${BOLD}unoverse start${NC} applies them once services are up"
|
|
314
337
|
fi
|
|
315
338
|
fi
|
|
316
339
|
|
|
@@ -326,5 +349,6 @@ ENVEOF
|
|
|
326
349
|
echo -e " ${GREEN}unoverse where${NC} Its addresses, once it is up"
|
|
327
350
|
echo ""
|
|
328
351
|
info "Run ${BOLD}unoverse check${NC} anytime to see if it is healthy"
|
|
352
|
+
info "Change a setting any time: edit ${BOLD}.env${NC} directly, or re-run ${BOLD}unoverse create${NC} (Enter keeps each current value)"
|
|
329
353
|
echo ""
|
|
330
354
|
}
|
package/operator/lib/start.sh
CHANGED
|
@@ -33,6 +33,24 @@ check_docker_file_sharing() {
|
|
|
33
33
|
return 0
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
# Pull whatever images are missing, VISIBLY. docker's own per-layer progress bars are the
|
|
37
|
+
# loading indication — a developer staring at a silent screen while gigabytes download
|
|
38
|
+
# assumes the tool is hung. Exists because init used to call cmd_pull (deleted with
|
|
39
|
+
# update.sh), so nothing pulled and nothing printed, and start buried compose's pull
|
|
40
|
+
# inside a log file.
|
|
41
|
+
pull_missing_images() {
|
|
42
|
+
local img missing=""
|
|
43
|
+
for img in $(docker compose -f "$ROOT/docker-compose.yml" config --images 2>/dev/null | sort -u); do
|
|
44
|
+
docker image inspect "$img" >/dev/null 2>&1 || missing="$missing $img"
|
|
45
|
+
done
|
|
46
|
+
[ -n "$missing" ] || return 0
|
|
47
|
+
echo ""
|
|
48
|
+
info "Pulling platform images (first run — a few minutes, progress below)..."
|
|
49
|
+
echo ""
|
|
50
|
+
docker compose -f "$ROOT/docker-compose.yml" --env-file "$ROOT/.env" pull || { fail "Image pull failed. Check the registry token (re-run unoverse create to change it)"; exit 1; }
|
|
51
|
+
echo ""
|
|
52
|
+
}
|
|
53
|
+
|
|
36
54
|
cmd_start() {
|
|
37
55
|
# Login to registry if DOCR_TOKEN is set
|
|
38
56
|
local docr_token
|
|
@@ -44,6 +62,8 @@ cmd_start() {
|
|
|
44
62
|
# `start --pull` refreshes the images first. This is where refreshing a LOCAL universe
|
|
45
63
|
# lives now: `update` is the CLI's word and means only the CLI, wherever you type it.
|
|
46
64
|
# A server is refreshed by `unoverse deploy` from your machine, not on the box.
|
|
65
|
+
pull_missing_images
|
|
66
|
+
|
|
47
67
|
if [ "${1:-}" = "--pull" ]; then
|
|
48
68
|
info "Pulling the latest images..."
|
|
49
69
|
docker compose -f "$ROOT/docker-compose.yml" pull || { fail "Image pull failed"; exit 1; }
|
|
@@ -137,6 +157,13 @@ cmd_start() {
|
|
|
137
157
|
# Generates + tsc-builds nodes/components, then reloads unoverse so they load.
|
|
138
158
|
# Non-fatal: build_component_nodes returns (doesn't exit) if it can't run, so start still finishes.
|
|
139
159
|
build_component_nodes
|
|
160
|
+
# Migrations, now that the unoverse service is up (they run from inside its
|
|
161
|
+
# container). This is what makes start the resume point after any interrupted
|
|
162
|
+
# setup: pull, boot, migrate, no third command to know. Subshell for the same
|
|
163
|
+
# reason init uses one: cmd_db_setup exits rather than returns on failure.
|
|
164
|
+
if ! (cmd_db_setup) >/dev/null 2>&1; then
|
|
165
|
+
warn "Migrations did not apply. Run ${BOLD}unoverse check${NC} to see why"
|
|
166
|
+
fi
|
|
140
167
|
print_access_urls
|
|
141
168
|
echo ""
|
|
142
169
|
info "Run ${BOLD}unoverse open${NC} to open Canvas in your browser"
|
package/operator/operator.sh
CHANGED
|
@@ -64,6 +64,22 @@ case "${1:-}" in
|
|
|
64
64
|
check) cmd_check && cmd_db_verify && cmd_doctor ;;
|
|
65
65
|
dev) cmd_dev ;;
|
|
66
66
|
ground) shift; cmd_ground "$@" ;;
|
|
67
|
+
refresh-images)
|
|
68
|
+
# internal: `unoverse update` runs this after updating the CLI. Pull newer images
|
|
69
|
+
# if the registry has them, and recreate only what is already running — an update
|
|
70
|
+
# never boots a stopped universe.
|
|
71
|
+
if [ ! -f "$ROOT/.env" ]; then
|
|
72
|
+
: # unconfigured: nothing to refresh
|
|
73
|
+
elif ! docker info >/dev/null 2>&1; then
|
|
74
|
+
info "Docker is not running. Images refresh on the next unoverse start"
|
|
75
|
+
else
|
|
76
|
+
info "Checking for newer platform images..."
|
|
77
|
+
docker compose -f "$ROOT/docker-compose.yml" --env-file "$ROOT/.env" pull || warn "image check failed (network/registry?)"
|
|
78
|
+
if [ -n "$(docker compose -f "$ROOT/docker-compose.yml" ps -q 2>/dev/null)" ]; then
|
|
79
|
+
docker compose -f "$ROOT/docker-compose.yml" --env-file "$ROOT/.env" up -d --remove-orphans >/dev/null 2>&1 \
|
|
80
|
+
&& ok "Running services moved to the new images"
|
|
81
|
+
fi
|
|
82
|
+
fi ;;
|
|
67
83
|
deploy)
|
|
68
84
|
# `deploy marketplace` is PLATFORM-OWNER only: it publishes the marketplace package
|
|
69
85
|
# to npm, which a starter developer never does (they INSTALL from the marketplace).
|
package/package.json
CHANGED