@pleri/olam-cli 0.1.7
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/dist/__tests__/auth-status.test.d.ts +2 -0
- package/dist/__tests__/auth-status.test.d.ts.map +1 -0
- package/dist/__tests__/auth-status.test.js +290 -0
- package/dist/__tests__/auth-status.test.js.map +1 -0
- package/dist/__tests__/auth-upgrade.test.d.ts +9 -0
- package/dist/__tests__/auth-upgrade.test.d.ts.map +1 -0
- package/dist/__tests__/auth-upgrade.test.js +161 -0
- package/dist/__tests__/auth-upgrade.test.js.map +1 -0
- package/dist/__tests__/create-app-urls.test.d.ts +2 -0
- package/dist/__tests__/create-app-urls.test.d.ts.map +1 -0
- package/dist/__tests__/create-app-urls.test.js +102 -0
- package/dist/__tests__/create-app-urls.test.js.map +1 -0
- package/dist/__tests__/enter.test.d.ts +2 -0
- package/dist/__tests__/enter.test.d.ts.map +1 -0
- package/dist/__tests__/enter.test.js +90 -0
- package/dist/__tests__/enter.test.js.map +1 -0
- package/dist/__tests__/host-cp-gh-token.test.d.ts +9 -0
- package/dist/__tests__/host-cp-gh-token.test.d.ts.map +1 -0
- package/dist/__tests__/host-cp-gh-token.test.js +119 -0
- package/dist/__tests__/host-cp-gh-token.test.js.map +1 -0
- package/dist/__tests__/host-cp.test.d.ts +9 -0
- package/dist/__tests__/host-cp.test.d.ts.map +1 -0
- package/dist/__tests__/host-cp.test.js +254 -0
- package/dist/__tests__/host-cp.test.js.map +1 -0
- package/dist/__tests__/keys.test.d.ts +9 -0
- package/dist/__tests__/keys.test.d.ts.map +1 -0
- package/dist/__tests__/keys.test.js +145 -0
- package/dist/__tests__/keys.test.js.map +1 -0
- package/dist/__tests__/logs.test.d.ts +9 -0
- package/dist/__tests__/logs.test.d.ts.map +1 -0
- package/dist/__tests__/logs.test.js +124 -0
- package/dist/__tests__/logs.test.js.map +1 -0
- package/dist/__tests__/ps.test.d.ts +2 -0
- package/dist/__tests__/ps.test.d.ts.map +1 -0
- package/dist/__tests__/ps.test.js +172 -0
- package/dist/__tests__/ps.test.js.map +1 -0
- package/dist/__tests__/status-app-urls.test.d.ts +2 -0
- package/dist/__tests__/status-app-urls.test.d.ts.map +1 -0
- package/dist/__tests__/status-app-urls.test.js +125 -0
- package/dist/__tests__/status-app-urls.test.js.map +1 -0
- package/dist/__tests__/upgrade.test.d.ts +9 -0
- package/dist/__tests__/upgrade.test.d.ts.map +1 -0
- package/dist/__tests__/upgrade.test.js +262 -0
- package/dist/__tests__/upgrade.test.js.map +1 -0
- package/dist/commands/__tests__/carry-uncommitted.test.d.ts +14 -0
- package/dist/commands/__tests__/carry-uncommitted.test.d.ts.map +1 -0
- package/dist/commands/__tests__/carry-uncommitted.test.js +83 -0
- package/dist/commands/__tests__/carry-uncommitted.test.js.map +1 -0
- package/dist/commands/__tests__/openHostCpUrl.test.d.ts +2 -0
- package/dist/commands/__tests__/openHostCpUrl.test.d.ts.map +1 -0
- package/dist/commands/__tests__/openHostCpUrl.test.js +63 -0
- package/dist/commands/__tests__/openHostCpUrl.test.js.map +1 -0
- package/dist/commands/__tests__/refresh.test.d.ts +13 -0
- package/dist/commands/__tests__/refresh.test.d.ts.map +1 -0
- package/dist/commands/__tests__/refresh.test.js +170 -0
- package/dist/commands/__tests__/refresh.test.js.map +1 -0
- package/dist/commands/auth-status.d.ts +43 -0
- package/dist/commands/auth-status.d.ts.map +1 -0
- package/dist/commands/auth-status.js +208 -0
- package/dist/commands/auth-status.js.map +1 -0
- package/dist/commands/auth-upgrade.d.ts +47 -0
- package/dist/commands/auth-upgrade.d.ts.map +1 -0
- package/dist/commands/auth-upgrade.js +277 -0
- package/dist/commands/auth-upgrade.js.map +1 -0
- package/dist/commands/auth.d.ts +16 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +283 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/create.d.ts +8 -0
- package/dist/commands/create.d.ts.map +1 -0
- package/dist/commands/create.js +512 -0
- package/dist/commands/create.js.map +1 -0
- package/dist/commands/crystallize.d.ts +8 -0
- package/dist/commands/crystallize.d.ts.map +1 -0
- package/dist/commands/crystallize.js +101 -0
- package/dist/commands/crystallize.js.map +1 -0
- package/dist/commands/destroy.d.ts +6 -0
- package/dist/commands/destroy.d.ts.map +1 -0
- package/dist/commands/destroy.js +54 -0
- package/dist/commands/destroy.js.map +1 -0
- package/dist/commands/dispatch.d.ts +9 -0
- package/dist/commands/dispatch.d.ts.map +1 -0
- package/dist/commands/dispatch.js +94 -0
- package/dist/commands/dispatch.js.map +1 -0
- package/dist/commands/enter.d.ts +63 -0
- package/dist/commands/enter.d.ts.map +1 -0
- package/dist/commands/enter.js +206 -0
- package/dist/commands/enter.js.map +1 -0
- package/dist/commands/host-cp.d.ts +191 -0
- package/dist/commands/host-cp.d.ts.map +1 -0
- package/dist/commands/host-cp.js +797 -0
- package/dist/commands/host-cp.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +143 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install.d.ts +22 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +203 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/keys.d.ts +26 -0
- package/dist/commands/keys.d.ts.map +1 -0
- package/dist/commands/keys.js +151 -0
- package/dist/commands/keys.js.map +1 -0
- package/dist/commands/lanes.d.ts +18 -0
- package/dist/commands/lanes.d.ts.map +1 -0
- package/dist/commands/lanes.js +122 -0
- package/dist/commands/lanes.js.map +1 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +39 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/logs.d.ts +38 -0
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/commands/logs.js +177 -0
- package/dist/commands/logs.js.map +1 -0
- package/dist/commands/observe.d.ts +9 -0
- package/dist/commands/observe.d.ts.map +1 -0
- package/dist/commands/observe.js +34 -0
- package/dist/commands/observe.js.map +1 -0
- package/dist/commands/policy-check.d.ts +14 -0
- package/dist/commands/policy-check.d.ts.map +1 -0
- package/dist/commands/policy-check.js +76 -0
- package/dist/commands/policy-check.js.map +1 -0
- package/dist/commands/pr.d.ts +17 -0
- package/dist/commands/pr.d.ts.map +1 -0
- package/dist/commands/pr.js +148 -0
- package/dist/commands/pr.js.map +1 -0
- package/dist/commands/ps.d.ts +25 -0
- package/dist/commands/ps.d.ts.map +1 -0
- package/dist/commands/ps.js +164 -0
- package/dist/commands/ps.js.map +1 -0
- package/dist/commands/refresh-helpers.d.ts +25 -0
- package/dist/commands/refresh-helpers.d.ts.map +1 -0
- package/dist/commands/refresh-helpers.js +56 -0
- package/dist/commands/refresh-helpers.js.map +1 -0
- package/dist/commands/refresh.d.ts +23 -0
- package/dist/commands/refresh.d.ts.map +1 -0
- package/dist/commands/refresh.js +237 -0
- package/dist/commands/refresh.js.map +1 -0
- package/dist/commands/status.d.ts +6 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +51 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/upgrade.d.ts +67 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +358 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/workspace.d.ts +23 -0
- package/dist/commands/workspace.d.ts.map +1 -0
- package/dist/commands/workspace.js +198 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/commands/world-snapshot.d.ts +18 -0
- package/dist/commands/world-snapshot.d.ts.map +1 -0
- package/dist/commands/world-snapshot.js +327 -0
- package/dist/commands/world-snapshot.js.map +1 -0
- package/dist/context.d.ts +26 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +51 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18007 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.js +32236 -0
- package/dist/output.d.ts +10 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +31 -0
- package/dist/output.js.map +1 -0
- package/host-cp/compose.yaml +126 -0
- package/host-cp/src/auth-secret-hint.mjs +45 -0
- package/host-cp/src/auth.mjs +155 -0
- package/host-cp/src/compose-worlds-sources.mjs +170 -0
- package/host-cp/src/container-secret-fetcher.mjs +163 -0
- package/host-cp/src/docker-events.mjs +184 -0
- package/host-cp/src/local-worlds-source.mjs +83 -0
- package/host-cp/src/plan-orchestrator.mjs +829 -0
- package/host-cp/src/plan-progress.mjs +282 -0
- package/host-cp/src/pr-cache.mjs +201 -0
- package/host-cp/src/pr-merge-poller.mjs +154 -0
- package/host-cp/src/process-poller.mjs +250 -0
- package/host-cp/src/proxy.mjs +245 -0
- package/host-cp/src/pylon-worlds-source.mjs +68 -0
- package/host-cp/src/redact.mjs +67 -0
- package/host-cp/src/secret-cache.mjs +104 -0
- package/host-cp/src/server.mjs +2215 -0
- package/host-cp/src/sse-gate.mjs +117 -0
- package/host-cp/src/version-status.mjs +209 -0
- package/host-cp/src/workspace-catalog.mjs +149 -0
- package/host-cp/src/world-names-store.mjs +176 -0
- package/host-cp/src/world-pr-state.mjs +97 -0
- package/host-cp/src/world-progress.mjs +322 -0
- package/host-cp/src/world-tunnel-manager.mjs +288 -0
- package/host-cp/src/worlds-db-source.mjs +191 -0
- package/host-cp/src/worlds-source.mjs +59 -0
- package/package.json +38 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorldsDbSource — reconcile loop that reads ~/.olam/worlds.db and
|
|
3
|
+
* auto-registers running worlds into host-cp's in-memory registry.
|
|
4
|
+
*
|
|
5
|
+
* Two triggers (belt-and-suspenders):
|
|
6
|
+
* 1. fs.watch on the worlds.db file — fires within ~100ms of a write
|
|
7
|
+
* 2. 30s setInterval backstop — catches cases where fs.watch silently
|
|
8
|
+
* misses events (network filesystems, some Linux kernels)
|
|
9
|
+
*
|
|
10
|
+
* Uses better-sqlite3 for synchronous, lightweight reads. If the module
|
|
11
|
+
* is not installed (e.g., no native build in the container), the module
|
|
12
|
+
* logs a warning and exits without crashing the server.
|
|
13
|
+
*
|
|
14
|
+
* DB handle: deliberately NOT cached across reconcile calls. A long-lived
|
|
15
|
+
* readonly connection with the DB bind-mounted across the docker boundary
|
|
16
|
+
* does not reliably pick up writes committed on the host side — the host
|
|
17
|
+
* writer appends to the WAL, but the container reader's snapshot is stuck
|
|
18
|
+
* at the point the handle was first opened. Closing and reopening on every
|
|
19
|
+
* reconcile forces a new read transaction that sees all committed WAL
|
|
20
|
+
* frames. Cost: ~1 ms per call at a 30 s interval — negligible. This
|
|
21
|
+
* eliminates the entire class of "olam create world vanishes within 30 s"
|
|
22
|
+
* bugs (regression confirmed: ember-elk-9191 removed by reconciler despite
|
|
23
|
+
* being present in worlds.db with status=running).
|
|
24
|
+
*
|
|
25
|
+
* Interface: thin wrapper so a future "remote" source (cloud orchestrator)
|
|
26
|
+
* can drop in via the same WorldsSource interface in worlds-source.mjs.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import fs from 'node:fs';
|
|
30
|
+
import { createRequire } from 'node:module';
|
|
31
|
+
|
|
32
|
+
const require = createRequire(import.meta.url);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @typedef {object} WorldsDbSourceDeps
|
|
36
|
+
* @property {string} dbPath Path to worlds.db (OLAM_WORLDS_DB or ~/.olam/worlds.db)
|
|
37
|
+
* @property {string} dockerHost Docker API base URL (tcp://host:port)
|
|
38
|
+
* @property {string} worldHost Host used to reach world CPs (127.0.0.1 or host.docker.internal)
|
|
39
|
+
* @property {() => Record<string, number>} getRegistry Current WORLDS map
|
|
40
|
+
* @property {(id: string, port: number) => void} onWorldAdded Called when a new running world is found
|
|
41
|
+
* @property {(id: string) => void} onWorldRemoved Called when a running world disappears
|
|
42
|
+
* @property {(msg: string) => void} [log]
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Derive the per-world CP host port from docker inspect.
|
|
47
|
+
*
|
|
48
|
+
* @param {string} worldId
|
|
49
|
+
* @param {string} dockerHost e.g. 'tcp://docker-socket-proxy:2375'
|
|
50
|
+
* @returns {Promise<number | null>}
|
|
51
|
+
*/
|
|
52
|
+
async function getWorldPortFromDocker(worldId, dockerHost) {
|
|
53
|
+
const apiBase = dockerHost.replace(/^tcp:\/\//, 'http://');
|
|
54
|
+
const containerName = `olam-${worldId}-devbox`;
|
|
55
|
+
try {
|
|
56
|
+
const res = await fetch(`${apiBase}/containers/${encodeURIComponent(containerName)}/json`, {
|
|
57
|
+
signal: AbortSignal.timeout(3000),
|
|
58
|
+
});
|
|
59
|
+
if (!res.ok) return null;
|
|
60
|
+
const data = await res.json();
|
|
61
|
+
// Per-world CP runs on internal port 8080; host port is the published binding.
|
|
62
|
+
const ports = data?.NetworkSettings?.Ports ?? {};
|
|
63
|
+
const binding = ports['8080/tcp'];
|
|
64
|
+
if (!Array.isArray(binding) || binding.length === 0) return null;
|
|
65
|
+
const hostPort = parseInt(binding[0].HostPort, 10);
|
|
66
|
+
return Number.isFinite(hostPort) ? hostPort : null;
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Start the worlds-db reconcile loop. Returns a stop function.
|
|
74
|
+
*
|
|
75
|
+
* @param {WorldsDbSourceDeps} deps
|
|
76
|
+
* @returns {{ stop: () => void }}
|
|
77
|
+
*/
|
|
78
|
+
export function startWorldsDbReconciler(deps) {
|
|
79
|
+
const { dbPath, dockerHost, getRegistry, onWorldAdded, onWorldRemoved, log = console.log } = deps;
|
|
80
|
+
|
|
81
|
+
let db = null;
|
|
82
|
+
let stopped = false;
|
|
83
|
+
let watcher = null;
|
|
84
|
+
|
|
85
|
+
function tryOpenDb() {
|
|
86
|
+
if (db) return db;
|
|
87
|
+
try {
|
|
88
|
+
// Dynamic require — gracefully degrade if better-sqlite3 is not installed.
|
|
89
|
+
// better-sqlite3 is CommonJS-only; createRequire enables sync dynamic loading in ESM.
|
|
90
|
+
const Database = require('better-sqlite3');
|
|
91
|
+
db = new Database(dbPath, { readonly: true, fileMustExist: true });
|
|
92
|
+
log(`[worlds-db] opened ${dbPath}`);
|
|
93
|
+
return db;
|
|
94
|
+
} catch (err) {
|
|
95
|
+
if (err.code === 'MODULE_NOT_FOUND') {
|
|
96
|
+
log('[worlds-db] better-sqlite3 not available; skipping DB reconciler');
|
|
97
|
+
} else if (err.code !== 'SQLITE_CANTOPEN') {
|
|
98
|
+
log(`[worlds-db] failed to open ${dbPath}: ${err.message}`);
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function reconcile() {
|
|
105
|
+
if (stopped) return;
|
|
106
|
+
|
|
107
|
+
// Close any cached handle so tryOpenDb() opens a fresh connection below.
|
|
108
|
+
// A long-lived readonly handle under cross-bind-mount WAL mode has its
|
|
109
|
+
// read snapshot frozen at open time; closing and reopening starts a new
|
|
110
|
+
// read transaction that includes all WAL frames committed by the host.
|
|
111
|
+
if (db) {
|
|
112
|
+
try { db.close(); } catch { /* ignore */ }
|
|
113
|
+
db = null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const database = tryOpenDb();
|
|
117
|
+
if (!database) return;
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
let runningIds;
|
|
121
|
+
try {
|
|
122
|
+
const rows = database.prepare("SELECT id FROM worlds WHERE status = 'running'").all();
|
|
123
|
+
runningIds = new Set(rows.map((r) => r.id));
|
|
124
|
+
} catch (err) {
|
|
125
|
+
log(`[worlds-db] query failed: ${err.message}`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const registry = getRegistry();
|
|
130
|
+
|
|
131
|
+
// Add worlds that are running in DB but missing from registry.
|
|
132
|
+
for (const id of runningIds) {
|
|
133
|
+
if (id in registry) continue;
|
|
134
|
+
const port = await getWorldPortFromDocker(id, dockerHost);
|
|
135
|
+
if (port === null) {
|
|
136
|
+
log(`[worlds-db] world ${id} running in DB but no docker port found; skipping`);
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
log(`[worlds-db] reconcile: adding ${id} → :${port}`);
|
|
140
|
+
onWorldAdded(id, port);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Remove worlds that are registered but no longer 'running' in DB.
|
|
144
|
+
for (const id of Object.keys(registry)) {
|
|
145
|
+
if (runningIds.has(id)) continue;
|
|
146
|
+
log(`[worlds-db] reconcile: removing ${id} (not running in DB)`);
|
|
147
|
+
onWorldRemoved(id);
|
|
148
|
+
}
|
|
149
|
+
} finally {
|
|
150
|
+
// Always close — no need to hold the handle between reconciles.
|
|
151
|
+
try { db.close(); } catch { /* ignore */ }
|
|
152
|
+
db = null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Watch the DB file for changes (fast path).
|
|
157
|
+
if (fs.existsSync(dbPath)) {
|
|
158
|
+
try {
|
|
159
|
+
watcher = fs.watch(dbPath, { persistent: false }, () => {
|
|
160
|
+
void reconcile();
|
|
161
|
+
});
|
|
162
|
+
} catch (err) {
|
|
163
|
+
log(`[worlds-db] fs.watch failed: ${err.message}; relying on 30s poll`);
|
|
164
|
+
}
|
|
165
|
+
// Initial reconcile on startup.
|
|
166
|
+
void reconcile();
|
|
167
|
+
} else {
|
|
168
|
+
log(`[worlds-db] ${dbPath} not found; will poll every 30s`);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// 30s backstop poll. Also watches for the file to appear.
|
|
172
|
+
const interval = setInterval(async () => {
|
|
173
|
+
if (!watcher && fs.existsSync(dbPath)) {
|
|
174
|
+
// File appeared since startup — set up watcher now.
|
|
175
|
+
try {
|
|
176
|
+
watcher = fs.watch(dbPath, { persistent: false }, () => { void reconcile(); });
|
|
177
|
+
log(`[worlds-db] ${dbPath} appeared; watcher started`);
|
|
178
|
+
} catch { /* fs.watch failure is non-fatal */ }
|
|
179
|
+
}
|
|
180
|
+
await reconcile();
|
|
181
|
+
}, 30_000);
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
stop() {
|
|
185
|
+
stopped = true;
|
|
186
|
+
clearInterval(interval);
|
|
187
|
+
if (watcher) { try { watcher.close(); } catch { /* ignore */ } }
|
|
188
|
+
if (db) { try { db.close(); } catch { /* ignore */ } }
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase E1 (olam-dogfood-vision): WorldsSource interface.
|
|
3
|
+
*
|
|
4
|
+
* Single narrow boundary that both LocalWorldsSource (today's
|
|
5
|
+
* dockerode-driven enumeration) and PylonWorldsSource (future cloud
|
|
6
|
+
* worlds) implement. The interface is the entire contract — there is
|
|
7
|
+
* no shared abstract class, no shared base, no shared utility module.
|
|
8
|
+
*
|
|
9
|
+
* Per Phase E plan (S1 contract carried through C-phase): the wire
|
|
10
|
+
* shape IS the abstraction. Sources implementing this interface are
|
|
11
|
+
* free to pick any backend (dockerode, Pylon SDK, mock, sqlite cache
|
|
12
|
+
* — anything) as long as `list()` returns the WorldSummary shape.
|
|
13
|
+
*
|
|
14
|
+
* Deliberately narrow:
|
|
15
|
+
* - `name` — discriminator for the source. SPA uses this to render
|
|
16
|
+
* the per-world `source` chip (E5).
|
|
17
|
+
* - `list()` — read-only enumeration. NO mutations. Mutations stay
|
|
18
|
+
* on host-cp's existing endpoints (POST /api/worlds delegation,
|
|
19
|
+
* DELETE via per-world CP, etc.). T5 mitigation: keeping the
|
|
20
|
+
* surface narrow lets the future Pylon SDK integration extend
|
|
21
|
+
* `list()`'s implementation without forcing a contract change
|
|
22
|
+
* across consumers.
|
|
23
|
+
*
|
|
24
|
+
* This is a `.mjs` file (matches host-cp's existing module style).
|
|
25
|
+
* Type information is conveyed via JSDoc; consumers reading via
|
|
26
|
+
* TypeScript get the shape via `// @ts-check` + JSDoc inference.
|
|
27
|
+
*
|
|
28
|
+
* @typedef {object} ServiceInfo
|
|
29
|
+
* @property {string} name
|
|
30
|
+
* @property {number} host_port
|
|
31
|
+
* @property {number} internal_port
|
|
32
|
+
* @property {string} url
|
|
33
|
+
* @property {boolean} live
|
|
34
|
+
*
|
|
35
|
+
* @typedef {object} WorldSummary
|
|
36
|
+
* @property {string} id
|
|
37
|
+
* @property {string | null} name
|
|
38
|
+
* @property {'running' | 'starting' | 'unknown' | 'failed'} status
|
|
39
|
+
* @property {ServiceInfo[]} services
|
|
40
|
+
* @property {'local' | 'pylon-cloud'} source
|
|
41
|
+
*
|
|
42
|
+
* @typedef {object} WorldsSource
|
|
43
|
+
* @property {'local' | 'pylon-cloud'} name
|
|
44
|
+
* @property {() => Promise<WorldSummary[]>} list
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
// Re-export the source-name discriminator so consumers don't repeat
|
|
48
|
+
// the literal string. Both implementations + E4's composition layer
|
|
49
|
+
// + E5's SPA badge logic reference this.
|
|
50
|
+
export const SOURCE_NAMES = /** @type {const} */ (['local', 'pylon-cloud']);
|
|
51
|
+
|
|
52
|
+
// `WorldsSource` is a TYPE export — no runtime symbol. Consumers
|
|
53
|
+
// import it via JSDoc references:
|
|
54
|
+
// /** @type {import('./worlds-source.mjs').WorldsSource} */
|
|
55
|
+
// or in TypeScript:
|
|
56
|
+
// import type { WorldsSource } from './worlds-source.mjs';
|
|
57
|
+
//
|
|
58
|
+
// Test files exercising the interface treat it as duck-typed: any
|
|
59
|
+
// object with the right shape passes structural compatibility.
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pleri/olam-cli",
|
|
3
|
+
"version": "0.1.7",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"bin": {
|
|
6
|
+
"olam": "./dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"host-cp",
|
|
11
|
+
"plugin",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/pleri/olam.git",
|
|
17
|
+
"directory": "packages/cli"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"registry": "https://registry.npmjs.org",
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"dev": "tsx src/index.ts",
|
|
26
|
+
"test": "vitest run --passWithNoTests",
|
|
27
|
+
"test:ci": "vitest run --reporter=basic --passWithNoTests"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"better-sqlite3": "^12.0.0",
|
|
31
|
+
"commander": "^13.0.0",
|
|
32
|
+
"dockerode": "^4.0.0",
|
|
33
|
+
"ora": "^8.0.0",
|
|
34
|
+
"picocolors": "^1.1.0",
|
|
35
|
+
"ssh2": "^1.16.0",
|
|
36
|
+
"yaml": "^2.7.0"
|
|
37
|
+
}
|
|
38
|
+
}
|