@pleri/olam-cli 0.1.101 → 0.1.103
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/commands/bootstrap.d.ts +8 -0
- package/dist/commands/bootstrap.d.ts.map +1 -1
- package/dist/commands/bootstrap.js.map +1 -1
- package/dist/commands/kg-build.d.ts +59 -0
- package/dist/commands/kg-build.d.ts.map +1 -0
- package/dist/commands/kg-build.js +247 -0
- package/dist/commands/kg-build.js.map +1 -0
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +35 -8
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/docker-host.d.ts +13 -34
- package/dist/docker-host.d.ts.map +1 -1
- package/dist/docker-host.js +12 -62
- package/dist/docker-host.js.map +1 -1
- package/dist/image-digests.json +6 -5
- package/dist/index.js +505 -138
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +175 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -487,8 +487,8 @@ var init_parseUtil = __esm({
|
|
|
487
487
|
init_errors();
|
|
488
488
|
init_en();
|
|
489
489
|
makeIssue = (params) => {
|
|
490
|
-
const { data, path:
|
|
491
|
-
const fullPath = [...
|
|
490
|
+
const { data, path: path50, errorMaps, issueData } = params;
|
|
491
|
+
const fullPath = [...path50, ...issueData.path || []];
|
|
492
492
|
const fullIssue = {
|
|
493
493
|
...issueData,
|
|
494
494
|
path: fullPath
|
|
@@ -796,11 +796,11 @@ var init_types = __esm({
|
|
|
796
796
|
init_parseUtil();
|
|
797
797
|
init_util();
|
|
798
798
|
ParseInputLazyPath = class {
|
|
799
|
-
constructor(parent, value,
|
|
799
|
+
constructor(parent, value, path50, key) {
|
|
800
800
|
this._cachedPath = [];
|
|
801
801
|
this.parent = parent;
|
|
802
802
|
this.data = value;
|
|
803
|
-
this._path =
|
|
803
|
+
this._path = path50;
|
|
804
804
|
this._key = key;
|
|
805
805
|
}
|
|
806
806
|
get path() {
|
|
@@ -4281,7 +4281,7 @@ import YAML from "yaml";
|
|
|
4281
4281
|
function bootstrapStepCmd(entry) {
|
|
4282
4282
|
return typeof entry === "string" ? entry : entry.cmd;
|
|
4283
4283
|
}
|
|
4284
|
-
function refineForbiddenKeys(value,
|
|
4284
|
+
function refineForbiddenKeys(value, path50, ctx, rejectSource) {
|
|
4285
4285
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4286
4286
|
return;
|
|
4287
4287
|
}
|
|
@@ -4289,12 +4289,12 @@ function refineForbiddenKeys(value, path49, ctx, rejectSource) {
|
|
|
4289
4289
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
4290
4290
|
ctx.addIssue({
|
|
4291
4291
|
code: external_exports.ZodIssueCode.custom,
|
|
4292
|
-
path: [...
|
|
4292
|
+
path: [...path50, key],
|
|
4293
4293
|
message: `forbidden key "${key}" (prototype-pollution surface)`
|
|
4294
4294
|
});
|
|
4295
4295
|
continue;
|
|
4296
4296
|
}
|
|
4297
|
-
if (rejectSource &&
|
|
4297
|
+
if (rejectSource && path50.length === 0 && key === "source") {
|
|
4298
4298
|
ctx.addIssue({
|
|
4299
4299
|
code: external_exports.ZodIssueCode.custom,
|
|
4300
4300
|
path: ["source"],
|
|
@@ -4302,21 +4302,21 @@ function refineForbiddenKeys(value, path49, ctx, rejectSource) {
|
|
|
4302
4302
|
});
|
|
4303
4303
|
continue;
|
|
4304
4304
|
}
|
|
4305
|
-
refineForbiddenKeys(value[key], [...
|
|
4305
|
+
refineForbiddenKeys(value[key], [...path50, key], ctx, false);
|
|
4306
4306
|
}
|
|
4307
4307
|
}
|
|
4308
|
-
function rejectForbiddenKeys(value,
|
|
4308
|
+
function rejectForbiddenKeys(value, path50, rejectSource) {
|
|
4309
4309
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4310
4310
|
return;
|
|
4311
4311
|
}
|
|
4312
4312
|
for (const key of Object.keys(value)) {
|
|
4313
4313
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
4314
|
-
throw new Error(`[manifest] ${
|
|
4314
|
+
throw new Error(`[manifest] ${path50}: forbidden key "${key}" (prototype-pollution surface)`);
|
|
4315
4315
|
}
|
|
4316
4316
|
if (rejectSource && key === "source") {
|
|
4317
|
-
throw new Error(`[manifest] ${
|
|
4317
|
+
throw new Error(`[manifest] ${path50}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
|
|
4318
4318
|
}
|
|
4319
|
-
rejectForbiddenKeys(value[key], `${
|
|
4319
|
+
rejectForbiddenKeys(value[key], `${path50}.${key}`, false);
|
|
4320
4320
|
}
|
|
4321
4321
|
}
|
|
4322
4322
|
function unknownTopLevelKeys(parsed) {
|
|
@@ -5198,7 +5198,7 @@ async function safeText(res) {
|
|
|
5198
5198
|
}
|
|
5199
5199
|
}
|
|
5200
5200
|
function sleep(ms) {
|
|
5201
|
-
return new Promise((
|
|
5201
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
5202
5202
|
}
|
|
5203
5203
|
var DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, RETRY_COUNT, RETRY_BACKOFF_MS, AuthClient;
|
|
5204
5204
|
var init_client = __esm({
|
|
@@ -5309,8 +5309,8 @@ var init_client = __esm({
|
|
|
5309
5309
|
throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
|
|
5310
5310
|
}
|
|
5311
5311
|
}
|
|
5312
|
-
async request(method,
|
|
5313
|
-
const url = `${this.baseUrl}${
|
|
5312
|
+
async request(method, path50, body, attempt = 0) {
|
|
5313
|
+
const url = `${this.baseUrl}${path50}`;
|
|
5314
5314
|
const controller = new AbortController();
|
|
5315
5315
|
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
5316
5316
|
const headers = {};
|
|
@@ -5328,7 +5328,7 @@ var init_client = __esm({
|
|
|
5328
5328
|
} catch (err) {
|
|
5329
5329
|
if (attempt < RETRY_COUNT && isTransient(err)) {
|
|
5330
5330
|
await sleep(RETRY_BACKOFF_MS * (attempt + 1));
|
|
5331
|
-
return this.request(method,
|
|
5331
|
+
return this.request(method, path50, body, attempt + 1);
|
|
5332
5332
|
}
|
|
5333
5333
|
throw err;
|
|
5334
5334
|
} finally {
|
|
@@ -5350,7 +5350,7 @@ function resolveAuthServicePath() {
|
|
|
5350
5350
|
return path9.join(pkgsDir, "auth-service");
|
|
5351
5351
|
}
|
|
5352
5352
|
function sleep2(ms) {
|
|
5353
|
-
return new Promise((
|
|
5353
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
5354
5354
|
}
|
|
5355
5355
|
var DEFAULT_PORT, DEFAULT_VOLUME, DEFAULT_CONTAINER, DEFAULT_IMAGE, AuthContainerController;
|
|
5356
5356
|
var init_container = __esm({
|
|
@@ -5798,7 +5798,7 @@ var init_container2 = __esm({
|
|
|
5798
5798
|
await container.start();
|
|
5799
5799
|
return container;
|
|
5800
5800
|
};
|
|
5801
|
-
DEFAULT_IMAGE2 = "olam-devbox:
|
|
5801
|
+
DEFAULT_IMAGE2 = "olam-devbox:base";
|
|
5802
5802
|
CONTROL_PLANE_PORT = 8080;
|
|
5803
5803
|
HOST_CONTROL_PLANE_BASE = 19080;
|
|
5804
5804
|
HOST_APP_PORT_BASE_DELTA = 1e4;
|
|
@@ -5951,7 +5951,7 @@ var demuxStream, execInContainer;
|
|
|
5951
5951
|
var init_exec = __esm({
|
|
5952
5952
|
"../adapters/dist/docker/exec.js"() {
|
|
5953
5953
|
"use strict";
|
|
5954
|
-
demuxStream = (stream) => new Promise((
|
|
5954
|
+
demuxStream = (stream) => new Promise((resolve11, reject) => {
|
|
5955
5955
|
const stdoutChunks = [];
|
|
5956
5956
|
const stderrChunks = [];
|
|
5957
5957
|
const stdout = new PassThrough();
|
|
@@ -5965,7 +5965,7 @@ var init_exec = __esm({
|
|
|
5965
5965
|
stream.pipe(stdout);
|
|
5966
5966
|
}
|
|
5967
5967
|
stream.on("end", () => {
|
|
5968
|
-
|
|
5968
|
+
resolve11({
|
|
5969
5969
|
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
5970
5970
|
stderr: Buffer.concat(stderrChunks).toString("utf-8")
|
|
5971
5971
|
});
|
|
@@ -6003,6 +6003,51 @@ var init_exec = __esm({
|
|
|
6003
6003
|
}
|
|
6004
6004
|
});
|
|
6005
6005
|
|
|
6006
|
+
// ../adapters/dist/docker/host.js
|
|
6007
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
6008
|
+
function resolveDockerHostOptions(spawnImpl = spawnSync2) {
|
|
6009
|
+
if (process.env.DOCKER_HOST && process.env.DOCKER_HOST.length > 0) {
|
|
6010
|
+
return {};
|
|
6011
|
+
}
|
|
6012
|
+
try {
|
|
6013
|
+
const result = spawnImpl("docker", ["context", "inspect", "--format", "{{.Endpoints.docker.Host}}"], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
|
|
6014
|
+
if (result.status === 0) {
|
|
6015
|
+
const host = (result.stdout ?? "").trim();
|
|
6016
|
+
if (host.startsWith("unix://")) {
|
|
6017
|
+
return { socketPath: host.slice("unix://".length) };
|
|
6018
|
+
}
|
|
6019
|
+
if (host.startsWith("npipe://")) {
|
|
6020
|
+
return { socketPath: host.slice("npipe://".length) };
|
|
6021
|
+
}
|
|
6022
|
+
if (host.startsWith("tcp://") || host.startsWith("http://") || host.startsWith("https://")) {
|
|
6023
|
+
const url = new URL(host.startsWith("tcp://") ? host.replace("tcp://", "http://") : host);
|
|
6024
|
+
const protocol = host.startsWith("https://") ? "https" : "http";
|
|
6025
|
+
const port = url.port ? parseInt(url.port, 10) : protocol === "https" ? 2376 : 2375;
|
|
6026
|
+
return { host: url.hostname, port, protocol };
|
|
6027
|
+
}
|
|
6028
|
+
}
|
|
6029
|
+
} catch {
|
|
6030
|
+
}
|
|
6031
|
+
return { socketPath: "/var/run/docker.sock" };
|
|
6032
|
+
}
|
|
6033
|
+
function describeDockerEndpoint(opts) {
|
|
6034
|
+
if (!opts || Object.keys(opts).length === 0) {
|
|
6035
|
+
return process.env.DOCKER_HOST ? `DOCKER_HOST=${process.env.DOCKER_HOST}` : "/var/run/docker.sock (default)";
|
|
6036
|
+
}
|
|
6037
|
+
if (opts.socketPath) {
|
|
6038
|
+
return `socketPath=${opts.socketPath}`;
|
|
6039
|
+
}
|
|
6040
|
+
if (opts.host) {
|
|
6041
|
+
return `${opts.protocol ?? "http"}://${opts.host}:${opts.port ?? "?"}`;
|
|
6042
|
+
}
|
|
6043
|
+
return JSON.stringify(opts);
|
|
6044
|
+
}
|
|
6045
|
+
var init_host = __esm({
|
|
6046
|
+
"../adapters/dist/docker/host.js"() {
|
|
6047
|
+
"use strict";
|
|
6048
|
+
}
|
|
6049
|
+
});
|
|
6050
|
+
|
|
6006
6051
|
// ../adapters/dist/docker/provider.js
|
|
6007
6052
|
import Dockerode from "dockerode";
|
|
6008
6053
|
var DockerWorld, DockerProvider, dockerStateToWorldStatus;
|
|
@@ -6012,6 +6057,7 @@ var init_provider = __esm({
|
|
|
6012
6057
|
init_types2();
|
|
6013
6058
|
init_container2();
|
|
6014
6059
|
init_exec();
|
|
6060
|
+
init_host();
|
|
6015
6061
|
init_network();
|
|
6016
6062
|
init_volume();
|
|
6017
6063
|
DockerWorld = class {
|
|
@@ -6065,9 +6111,11 @@ var init_provider = __esm({
|
|
|
6065
6111
|
maxLifetimeMinutes: null
|
|
6066
6112
|
};
|
|
6067
6113
|
docker;
|
|
6114
|
+
dockerOptions;
|
|
6068
6115
|
constructor(dockerOptions) {
|
|
6069
6116
|
super();
|
|
6070
6117
|
this.docker = new Dockerode(dockerOptions);
|
|
6118
|
+
this.dockerOptions = dockerOptions;
|
|
6071
6119
|
}
|
|
6072
6120
|
// -----------------------------------------------------------------------
|
|
6073
6121
|
// createWorld
|
|
@@ -6076,8 +6124,10 @@ var init_provider = __esm({
|
|
|
6076
6124
|
const { id, name, services = [], portOffset = 0 } = config;
|
|
6077
6125
|
try {
|
|
6078
6126
|
await this.docker.ping();
|
|
6079
|
-
} catch {
|
|
6080
|
-
|
|
6127
|
+
} catch (err) {
|
|
6128
|
+
const where = describeDockerEndpoint(this.dockerOptions);
|
|
6129
|
+
const cause = err instanceof Error ? err.message : String(err);
|
|
6130
|
+
throw new Error(`Docker daemon is not available at ${where}. Ensure Docker is running and the resolved endpoint is correct. (underlying: ${cause})`);
|
|
6081
6131
|
}
|
|
6082
6132
|
await createNetwork(this.docker, id, name);
|
|
6083
6133
|
for (const svc of services) {
|
|
@@ -6339,7 +6389,7 @@ var init_connection = __esm({
|
|
|
6339
6389
|
// -----------------------------------------------------------------------
|
|
6340
6390
|
async exec(host, command) {
|
|
6341
6391
|
const client = await this.getConnection(host);
|
|
6342
|
-
return new Promise((
|
|
6392
|
+
return new Promise((resolve11, reject) => {
|
|
6343
6393
|
client.exec(command, (err, stream) => {
|
|
6344
6394
|
if (err) {
|
|
6345
6395
|
reject(new Error(`SSH exec failed on ${host}: ${err.message}`));
|
|
@@ -6354,7 +6404,7 @@ var init_connection = __esm({
|
|
|
6354
6404
|
stderr += data.toString();
|
|
6355
6405
|
});
|
|
6356
6406
|
stream.on("close", (code) => {
|
|
6357
|
-
|
|
6407
|
+
resolve11({
|
|
6358
6408
|
exitCode: code ?? 0,
|
|
6359
6409
|
stdout: stdout.trimEnd(),
|
|
6360
6410
|
stderr: stderr.trimEnd()
|
|
@@ -6385,10 +6435,10 @@ var init_connection = __esm({
|
|
|
6385
6435
|
throw new Error(`No SSH configuration found for host: ${host}`);
|
|
6386
6436
|
}
|
|
6387
6437
|
const client = new SSHClient();
|
|
6388
|
-
return new Promise((
|
|
6438
|
+
return new Promise((resolve11, reject) => {
|
|
6389
6439
|
client.on("ready", () => {
|
|
6390
6440
|
this.connections.set(host, client);
|
|
6391
|
-
|
|
6441
|
+
resolve11(client);
|
|
6392
6442
|
}).on("error", (err) => {
|
|
6393
6443
|
this.connections.delete(host);
|
|
6394
6444
|
reject(new Error(`SSH connection to ${host} failed: ${err.message}`));
|
|
@@ -6827,8 +6877,8 @@ var init_provider3 = __esm({
|
|
|
6827
6877
|
// -----------------------------------------------------------------------
|
|
6828
6878
|
// Internal fetch helper
|
|
6829
6879
|
// -----------------------------------------------------------------------
|
|
6830
|
-
async request(
|
|
6831
|
-
const url = `${this.config.workerUrl}${
|
|
6880
|
+
async request(path50, method, body) {
|
|
6881
|
+
const url = `${this.config.workerUrl}${path50}`;
|
|
6832
6882
|
const bearer = await this.config.mintToken();
|
|
6833
6883
|
const headers = {
|
|
6834
6884
|
Authorization: `Bearer ${bearer}`
|
|
@@ -6960,7 +7010,9 @@ __export(dist_exports, {
|
|
|
6960
7010
|
SSHProvider: () => SSHProvider,
|
|
6961
7011
|
auditPortsForZombies: () => auditPortsForZombies,
|
|
6962
7012
|
buildPackageManagerCacheBinds: () => buildPackageManagerCacheBinds,
|
|
6963
|
-
cleanupOrphanedResources: () => cleanupOrphanedResources
|
|
7013
|
+
cleanupOrphanedResources: () => cleanupOrphanedResources,
|
|
7014
|
+
describeDockerEndpoint: () => describeDockerEndpoint,
|
|
7015
|
+
resolveDockerHostOptions: () => resolveDockerHostOptions
|
|
6964
7016
|
});
|
|
6965
7017
|
var init_dist = __esm({
|
|
6966
7018
|
"../adapters/dist/index.js"() {
|
|
@@ -6968,6 +7020,7 @@ var init_dist = __esm({
|
|
|
6968
7020
|
init_types2();
|
|
6969
7021
|
init_provider();
|
|
6970
7022
|
init_cleanup();
|
|
7023
|
+
init_host();
|
|
6971
7024
|
init_container2();
|
|
6972
7025
|
init_container2();
|
|
6973
7026
|
init_provider2();
|
|
@@ -6978,41 +7031,13 @@ var init_dist = __esm({
|
|
|
6978
7031
|
// src/docker-host.ts
|
|
6979
7032
|
var docker_host_exports = {};
|
|
6980
7033
|
__export(docker_host_exports, {
|
|
7034
|
+
describeDockerEndpoint: () => describeDockerEndpoint,
|
|
6981
7035
|
resolveDockerHostOptions: () => resolveDockerHostOptions
|
|
6982
7036
|
});
|
|
6983
|
-
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
6984
|
-
function resolveDockerHostOptions(spawnImpl = spawnSync2) {
|
|
6985
|
-
if (process.env.DOCKER_HOST && process.env.DOCKER_HOST.length > 0) {
|
|
6986
|
-
return {};
|
|
6987
|
-
}
|
|
6988
|
-
try {
|
|
6989
|
-
const result = spawnImpl(
|
|
6990
|
-
"docker",
|
|
6991
|
-
["context", "inspect", "--format", "{{.Endpoints.docker.Host}}"],
|
|
6992
|
-
{ encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
|
|
6993
|
-
);
|
|
6994
|
-
if (result.status === 0) {
|
|
6995
|
-
const host = (result.stdout ?? "").trim();
|
|
6996
|
-
if (host.startsWith("unix://")) {
|
|
6997
|
-
return { socketPath: host.slice("unix://".length) };
|
|
6998
|
-
}
|
|
6999
|
-
if (host.startsWith("npipe://")) {
|
|
7000
|
-
return { socketPath: host.slice("npipe://".length) };
|
|
7001
|
-
}
|
|
7002
|
-
if (host.startsWith("tcp://") || host.startsWith("http://") || host.startsWith("https://")) {
|
|
7003
|
-
const url = new URL(host.startsWith("tcp://") ? host.replace("tcp://", "http://") : host);
|
|
7004
|
-
const protocol = host.startsWith("https://") ? "https" : "http";
|
|
7005
|
-
const port = url.port ? parseInt(url.port, 10) : protocol === "https" ? 2376 : 2375;
|
|
7006
|
-
return { host: url.hostname, port, protocol };
|
|
7007
|
-
}
|
|
7008
|
-
}
|
|
7009
|
-
} catch {
|
|
7010
|
-
}
|
|
7011
|
-
return { socketPath: "/var/run/docker.sock" };
|
|
7012
|
-
}
|
|
7013
7037
|
var init_docker_host = __esm({
|
|
7014
7038
|
"src/docker-host.ts"() {
|
|
7015
7039
|
"use strict";
|
|
7040
|
+
init_dist();
|
|
7016
7041
|
}
|
|
7017
7042
|
});
|
|
7018
7043
|
|
|
@@ -7224,7 +7249,7 @@ CREATE TABLE IF NOT EXISTS meta (
|
|
|
7224
7249
|
this.db.pragma("foreign_keys = ON");
|
|
7225
7250
|
this.db.exec(CREATE_TABLE);
|
|
7226
7251
|
this.db.exec(CREATE_META);
|
|
7227
|
-
for (const col of ["readiness_chain TEXT", "expected_services TEXT", "app_port_urls TEXT"]) {
|
|
7252
|
+
for (const col of ["readiness_chain TEXT", "expected_services TEXT", "app_port_urls TEXT", "tailscale_paths TEXT"]) {
|
|
7228
7253
|
try {
|
|
7229
7254
|
this.db.exec(`ALTER TABLE worlds ADD COLUMN ${col}`);
|
|
7230
7255
|
} catch {
|
|
@@ -7342,6 +7367,27 @@ CREATE TABLE IF NOT EXISTS meta (
|
|
|
7342
7367
|
const max = rows.length > 0 ? rows[rows.length - 1].port_offset : -100;
|
|
7343
7368
|
return max + 100;
|
|
7344
7369
|
}
|
|
7370
|
+
/**
|
|
7371
|
+
* Persist tailscale serve paths registered for a world.
|
|
7372
|
+
* Paths are stored as a JSON array in the tailscale_paths column.
|
|
7373
|
+
*/
|
|
7374
|
+
storeTailscalePaths(worldId, paths) {
|
|
7375
|
+
this.db.prepare("UPDATE worlds SET tailscale_paths = ?, updated_at = ? WHERE id = ?").run(JSON.stringify(paths), (/* @__PURE__ */ new Date()).toISOString(), worldId);
|
|
7376
|
+
}
|
|
7377
|
+
/**
|
|
7378
|
+
* Load tailscale serve paths for a world. Returns [] when none stored or
|
|
7379
|
+
* column absent (pre-migration rows).
|
|
7380
|
+
*/
|
|
7381
|
+
loadTailscalePaths(worldId) {
|
|
7382
|
+
const row = this.db.prepare("SELECT tailscale_paths FROM worlds WHERE id = ?").get(worldId);
|
|
7383
|
+
if (!row?.tailscale_paths)
|
|
7384
|
+
return [];
|
|
7385
|
+
try {
|
|
7386
|
+
return JSON.parse(row.tailscale_paths);
|
|
7387
|
+
} catch {
|
|
7388
|
+
return [];
|
|
7389
|
+
}
|
|
7390
|
+
}
|
|
7345
7391
|
close() {
|
|
7346
7392
|
this.db.close();
|
|
7347
7393
|
}
|
|
@@ -8124,8 +8170,8 @@ import { execFileSync as execFileSync3 } from "node:child_process";
|
|
|
8124
8170
|
import * as fs14 from "node:fs";
|
|
8125
8171
|
import * as os9 from "node:os";
|
|
8126
8172
|
import * as path15 from "node:path";
|
|
8127
|
-
function expandHome(p,
|
|
8128
|
-
return p.replace(/^~(?=$|\/|\\)/,
|
|
8173
|
+
function expandHome(p, homedir27) {
|
|
8174
|
+
return p.replace(/^~(?=$|\/|\\)/, homedir27());
|
|
8129
8175
|
}
|
|
8130
8176
|
function sanitizeRepoFilename(name) {
|
|
8131
8177
|
const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
@@ -8148,7 +8194,7 @@ ${stderr}`;
|
|
|
8148
8194
|
}
|
|
8149
8195
|
function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
8150
8196
|
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync3(cmd, args, opts));
|
|
8151
|
-
const
|
|
8197
|
+
const homedir27 = deps.homedir ?? (() => os9.homedir());
|
|
8152
8198
|
const baselineDir = path15.join(workspacePath, ".olam", "baseline");
|
|
8153
8199
|
try {
|
|
8154
8200
|
fs14.mkdirSync(baselineDir, { recursive: true });
|
|
@@ -8164,7 +8210,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
|
8164
8210
|
continue;
|
|
8165
8211
|
const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
|
|
8166
8212
|
const outPath = path15.join(baselineDir, filename);
|
|
8167
|
-
const repoPath = expandHome(repo.path,
|
|
8213
|
+
const repoPath = expandHome(repo.path, homedir27);
|
|
8168
8214
|
if (!fs14.existsSync(repoPath)) {
|
|
8169
8215
|
writeBaselineFile(outPath, `# repo: ${repo.name}
|
|
8170
8216
|
# (skipped: path ${repoPath} does not exist)
|
|
@@ -10172,6 +10218,34 @@ var init_bootstrap_hooks = __esm({
|
|
|
10172
10218
|
});
|
|
10173
10219
|
|
|
10174
10220
|
// ../core/dist/world/tmux-supervisor.js
|
|
10221
|
+
function injectBindAll(start) {
|
|
10222
|
+
let result = start;
|
|
10223
|
+
const userBoundRails = /(^|\s)(-b|--binding)(\s+|=)\S+/.test(start);
|
|
10224
|
+
const userBoundNext = /(^|\s)(-H|--hostname)(\s+|=)\S+/.test(start);
|
|
10225
|
+
const userBoundVite = /(^|\s)--host(\s+\S+|=\S+)/.test(start);
|
|
10226
|
+
const userBoundGunicorn = /(^|\s)(-h|--bind)(\s+|=)\S+/.test(start);
|
|
10227
|
+
const userHostEnv = /(^|\s)HOST=\S+/.test(start);
|
|
10228
|
+
const anyUserBound = userBoundRails || userBoundNext || userBoundVite || userBoundGunicorn;
|
|
10229
|
+
if (!userHostEnv && !anyUserBound) {
|
|
10230
|
+
result = `HOST=0.0.0.0 ${result}`;
|
|
10231
|
+
}
|
|
10232
|
+
if (!userBoundRails && /\brails\s+s(?:erver)?\b/.test(start)) {
|
|
10233
|
+
result = `${result} -b 0.0.0.0`;
|
|
10234
|
+
}
|
|
10235
|
+
if (!userBoundNext && /\bnext\s+dev\b/.test(start)) {
|
|
10236
|
+
result = `${result} -H 0.0.0.0`;
|
|
10237
|
+
}
|
|
10238
|
+
if (!userBoundVite && /\b(?:^|\s|=)vite\b/.test(start)) {
|
|
10239
|
+
result = `${result} --host 0.0.0.0`;
|
|
10240
|
+
}
|
|
10241
|
+
if (!userBoundVite && /\b(?:flask\s+run|uvicorn|hypercorn)\b/.test(start)) {
|
|
10242
|
+
result = `${result} --host 0.0.0.0`;
|
|
10243
|
+
}
|
|
10244
|
+
if (!userBoundGunicorn && /\bgunicorn\b/.test(start)) {
|
|
10245
|
+
result = `${result} --bind 0.0.0.0`;
|
|
10246
|
+
}
|
|
10247
|
+
return result;
|
|
10248
|
+
}
|
|
10175
10249
|
async function startSupervisedApps(containerName, worldId, repos, exec, options = {}) {
|
|
10176
10250
|
if (!SAFE_IDENT2.test(containerName)) {
|
|
10177
10251
|
throw new Error(`containerName "${containerName}" must match ${SAFE_IDENT2} (defensive guard)`);
|
|
@@ -10207,7 +10281,7 @@ async function startSupervisedApps(containerName, worldId, repos, exec, options
|
|
|
10207
10281
|
windowsExisting.push(repo.name);
|
|
10208
10282
|
continue;
|
|
10209
10283
|
}
|
|
10210
|
-
const expandedStart = repo.start.replace(/\$\{?PORT\}?/g, String(repo.hostPort));
|
|
10284
|
+
const expandedStart = injectBindAll(repo.start).replace(/\$\{?PORT\}?/g, String(repo.hostPort));
|
|
10211
10285
|
const startCmd = `cd ${shellQuote2(repo.dir)} && exec ${expandedStart}`;
|
|
10212
10286
|
exec(containerName, `tmux new-window -t ${sessionName} -n ${repo.name} -d ${shellQuote2(startCmd)}`);
|
|
10213
10287
|
windowsCreated.push(repo.name);
|
|
@@ -10284,7 +10358,9 @@ __export(manager_exports, {
|
|
|
10284
10358
|
WorldManager: () => WorldManager,
|
|
10285
10359
|
applyPostgresNetworkOverrides: () => applyPostgresNetworkOverrides,
|
|
10286
10360
|
buildManifestRuntimeForTest: () => buildManifestRuntime,
|
|
10361
|
+
cleanupWorldTailscale: () => cleanupWorldTailscale,
|
|
10287
10362
|
deriveReadinessChain: () => deriveReadinessChain,
|
|
10363
|
+
exposeWorldOverTailscale: () => exposeWorldOverTailscale,
|
|
10288
10364
|
getTokenScopes: () => getTokenScopes,
|
|
10289
10365
|
planManifestPipeline: () => planManifestPipeline,
|
|
10290
10366
|
runManifestRuntime: () => runManifestRuntime
|
|
@@ -10400,7 +10476,7 @@ ${stderr.split("\n").slice(0, 3).join(" ")}`);
|
|
|
10400
10476
|
Likely cause: corrupt local image, a custom devbox image without
|
|
10401
10477
|
the olam user (line 10 of devbox.Dockerfile), or NSS resolver
|
|
10402
10478
|
failure under cross-arch QEMU emulation.
|
|
10403
|
-
Remedy: docker rmi olam-devbox:
|
|
10479
|
+
Remedy: docker rmi olam-devbox:base && olam upgrade -y
|
|
10404
10480
|
(or set OLAM_DEVBOX_IMAGE to a known-good ref before \`olam create\`).
|
|
10405
10481
|
PR push from inside the world will not work until this is resolved.`);
|
|
10406
10482
|
return;
|
|
@@ -10634,6 +10710,71 @@ function buildManifestRuntime(worldId, repos) {
|
|
|
10634
10710
|
}
|
|
10635
10711
|
return { worldId, repos: runtimeRepos };
|
|
10636
10712
|
}
|
|
10713
|
+
function exposeWorldOverTailscale(appPortUrls, worldId, registry, _exec = execSync5) {
|
|
10714
|
+
if (process.env["OLAM_TAILSCALE_SERVE"] !== "true")
|
|
10715
|
+
return;
|
|
10716
|
+
if (appPortUrls.length === 0)
|
|
10717
|
+
return;
|
|
10718
|
+
const bin = resolveTailscaleBin(_exec);
|
|
10719
|
+
if (!bin) {
|
|
10720
|
+
console.warn("[tailscale] WARN: OLAM_TAILSCALE_SERVE=true but no tailscale binary found. Set TAILSCALE_BIN or install tailscale. Skipping serve mapping.");
|
|
10721
|
+
return;
|
|
10722
|
+
}
|
|
10723
|
+
const registeredPaths = [];
|
|
10724
|
+
for (const { repoName, hostPort } of appPortUrls) {
|
|
10725
|
+
const servePath = `/world/${worldId}/${repoName}`;
|
|
10726
|
+
try {
|
|
10727
|
+
_exec(`"${bin}" serve --bg --set-path=${servePath} http://localhost:${hostPort}`, {
|
|
10728
|
+
timeout: 1e4
|
|
10729
|
+
});
|
|
10730
|
+
console.log(`[tailscale] exposed ${worldId}/${repoName} at https://<machine>.<tailnet>/world/${worldId}/${repoName}`);
|
|
10731
|
+
registeredPaths.push(servePath);
|
|
10732
|
+
} catch (err) {
|
|
10733
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10734
|
+
console.warn(`[tailscale] WARN: serve failed for ${repoName} (port ${hostPort}): ${msg}`);
|
|
10735
|
+
}
|
|
10736
|
+
}
|
|
10737
|
+
if (registeredPaths.length > 0) {
|
|
10738
|
+
registry.storeTailscalePaths(worldId, registeredPaths);
|
|
10739
|
+
}
|
|
10740
|
+
}
|
|
10741
|
+
function cleanupWorldTailscale(worldId, registry, _exec = execSync5) {
|
|
10742
|
+
const paths = registry.loadTailscalePaths(worldId);
|
|
10743
|
+
if (paths.length === 0)
|
|
10744
|
+
return;
|
|
10745
|
+
const bin = resolveTailscaleBin(_exec);
|
|
10746
|
+
if (!bin) {
|
|
10747
|
+
console.warn("[tailscale] WARN: Cannot cleanup tailscale serve paths \u2014 binary not found.");
|
|
10748
|
+
return;
|
|
10749
|
+
}
|
|
10750
|
+
for (const servePath of paths) {
|
|
10751
|
+
try {
|
|
10752
|
+
_exec(`"${bin}" serve --bg --set-path=${servePath} off`, { timeout: 1e4 });
|
|
10753
|
+
console.log(`[tailscale] cleaned up serve path ${servePath}`);
|
|
10754
|
+
} catch (err) {
|
|
10755
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
10756
|
+
console.warn(`[tailscale] WARN: cleanup failed for ${servePath}: ${msg}`);
|
|
10757
|
+
}
|
|
10758
|
+
}
|
|
10759
|
+
}
|
|
10760
|
+
function resolveTailscaleBin(_exec = execSync5) {
|
|
10761
|
+
const candidates = [
|
|
10762
|
+
process.env["TAILSCALE_BIN"],
|
|
10763
|
+
"/Applications/Tailscale.app/Contents/MacOS/Tailscale",
|
|
10764
|
+
"/usr/local/bin/tailscale",
|
|
10765
|
+
"/opt/homebrew/bin/tailscale"
|
|
10766
|
+
];
|
|
10767
|
+
for (const c of candidates) {
|
|
10768
|
+
if (!c)
|
|
10769
|
+
continue;
|
|
10770
|
+
try {
|
|
10771
|
+
_exec(`test -x "${c}"`, { timeout: 2e3 });
|
|
10772
|
+
return c;
|
|
10773
|
+
} catch {
|
|
10774
|
+
}
|
|
10775
|
+
}
|
|
10776
|
+
return void 0;
|
|
10777
|
+
}
|
|
10637
10778
|
function applyPostgresNetworkOverrides(worldEnv, enrichedRepos) {
|
|
10638
10779
|
const hasPostgres = enrichedRepos.some((r) => r.manifest?.services?.["postgres"] !== void 0);
|
|
10639
10780
|
if (!hasPostgres)
|
|
@@ -11379,6 +11520,10 @@ ${opts.task}`;
|
|
|
11379
11520
|
}
|
|
11380
11521
|
} catch {
|
|
11381
11522
|
}
|
|
11523
|
+
try {
|
|
11524
|
+
exposeWorldOverTailscale(appPortUrls, worldId, this.registry);
|
|
11525
|
+
} catch {
|
|
11526
|
+
}
|
|
11382
11527
|
return {
|
|
11383
11528
|
...metadata,
|
|
11384
11529
|
status: "running",
|
|
@@ -11426,6 +11571,10 @@ ${opts.task}`;
|
|
|
11426
11571
|
} catch {
|
|
11427
11572
|
}
|
|
11428
11573
|
}
|
|
11574
|
+
try {
|
|
11575
|
+
cleanupWorldTailscale(worldId, this.registry);
|
|
11576
|
+
} catch {
|
|
11577
|
+
}
|
|
11429
11578
|
try {
|
|
11430
11579
|
await this.provider.destroyWorld(worldId);
|
|
11431
11580
|
} catch {
|
|
@@ -12827,7 +12976,7 @@ function isCloudflaredAvailable() {
|
|
|
12827
12976
|
}
|
|
12828
12977
|
}
|
|
12829
12978
|
function startTunnel(port) {
|
|
12830
|
-
return new Promise((
|
|
12979
|
+
return new Promise((resolve11, reject) => {
|
|
12831
12980
|
const child = spawn2("cloudflared", ["tunnel", "--url", `http://localhost:${port}`], {
|
|
12832
12981
|
stdio: ["ignore", "pipe", "pipe"],
|
|
12833
12982
|
detached: false
|
|
@@ -12849,7 +12998,7 @@ function startTunnel(port) {
|
|
|
12849
12998
|
if (match2) {
|
|
12850
12999
|
resolved = true;
|
|
12851
13000
|
clearTimeout(timeout);
|
|
12852
|
-
|
|
13001
|
+
resolve11(match2[0]);
|
|
12853
13002
|
}
|
|
12854
13003
|
}
|
|
12855
13004
|
child.stdout?.on("data", scan);
|
|
@@ -12936,8 +13085,8 @@ var init_dashboard = __esm({
|
|
|
12936
13085
|
}
|
|
12937
13086
|
throw err;
|
|
12938
13087
|
}
|
|
12939
|
-
await new Promise((
|
|
12940
|
-
this.server.on("listening",
|
|
13088
|
+
await new Promise((resolve11, reject) => {
|
|
13089
|
+
this.server.on("listening", resolve11);
|
|
12941
13090
|
this.server.on("error", reject);
|
|
12942
13091
|
});
|
|
12943
13092
|
this.info = { localUrl: `http://localhost:${port}` };
|
|
@@ -12983,8 +13132,8 @@ var init_dashboard = __esm({
|
|
|
12983
13132
|
async stop() {
|
|
12984
13133
|
stopTunnel();
|
|
12985
13134
|
if (this.server) {
|
|
12986
|
-
await new Promise((
|
|
12987
|
-
this.server.close(() =>
|
|
13135
|
+
await new Promise((resolve11) => {
|
|
13136
|
+
this.server.close(() => resolve11());
|
|
12988
13137
|
});
|
|
12989
13138
|
this.server = null;
|
|
12990
13139
|
}
|
|
@@ -13673,10 +13822,10 @@ async function readHostCpToken2() {
|
|
|
13673
13822
|
if (!fs25.existsSync(tp)) return null;
|
|
13674
13823
|
return fs25.readFileSync(tp, "utf-8").trim();
|
|
13675
13824
|
}
|
|
13676
|
-
async function callHostCpProxy(method, worldId,
|
|
13825
|
+
async function callHostCpProxy(method, worldId, path50, body) {
|
|
13677
13826
|
const token = await readHostCpToken2();
|
|
13678
13827
|
if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
|
|
13679
|
-
const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${
|
|
13828
|
+
const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path50}`;
|
|
13680
13829
|
try {
|
|
13681
13830
|
const headers = {
|
|
13682
13831
|
Authorization: `Bearer ${token}`
|
|
@@ -14561,9 +14710,9 @@ var UnknownArchetypeError = class extends Error {
|
|
|
14561
14710
|
};
|
|
14562
14711
|
var ArchetypeCycleError = class extends Error {
|
|
14563
14712
|
path;
|
|
14564
|
-
constructor(
|
|
14565
|
-
super(`Archetype inheritance cycle detected: ${
|
|
14566
|
-
this.path =
|
|
14713
|
+
constructor(path50) {
|
|
14714
|
+
super(`Archetype inheritance cycle detected: ${path50.join(" \u2192 ")} \u2192 ${path50[0] ?? "?"}`);
|
|
14715
|
+
this.path = path50;
|
|
14567
14716
|
this.name = "ArchetypeCycleError";
|
|
14568
14717
|
}
|
|
14569
14718
|
};
|
|
@@ -14837,7 +14986,7 @@ var realDocker = {
|
|
|
14837
14986
|
}
|
|
14838
14987
|
};
|
|
14839
14988
|
function spawnAsync(cmd, args, opts = {}) {
|
|
14840
|
-
return new Promise((
|
|
14989
|
+
return new Promise((resolve11) => {
|
|
14841
14990
|
const child = spawn3(cmd, [...args], {
|
|
14842
14991
|
stdio: ["ignore", "pipe", "pipe"],
|
|
14843
14992
|
signal: opts.signal
|
|
@@ -14851,10 +15000,10 @@ function spawnAsync(cmd, args, opts = {}) {
|
|
|
14851
15000
|
stderr += chunk.toString();
|
|
14852
15001
|
});
|
|
14853
15002
|
child.on("error", (err) => {
|
|
14854
|
-
|
|
15003
|
+
resolve11({ exitCode: -1, stdout, stderr: stderr + err.message });
|
|
14855
15004
|
});
|
|
14856
15005
|
child.on("close", (code) => {
|
|
14857
|
-
|
|
15006
|
+
resolve11({ exitCode: code ?? -1, stdout, stderr });
|
|
14858
15007
|
});
|
|
14859
15008
|
});
|
|
14860
15009
|
}
|
|
@@ -15197,10 +15346,10 @@ async function confirm(message) {
|
|
|
15197
15346
|
if (!process.stdin.isTTY) return true;
|
|
15198
15347
|
const { createInterface: createInterface5 } = await import("node:readline");
|
|
15199
15348
|
const rl = createInterface5({ input: process.stdin, output: process.stdout });
|
|
15200
|
-
return new Promise((
|
|
15349
|
+
return new Promise((resolve11) => {
|
|
15201
15350
|
rl.question(`${message} [y/N] `, (answer) => {
|
|
15202
15351
|
rl.close();
|
|
15203
|
-
|
|
15352
|
+
resolve11(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
15204
15353
|
});
|
|
15205
15354
|
});
|
|
15206
15355
|
}
|
|
@@ -15574,7 +15723,7 @@ var McpAuthContainerController = class {
|
|
|
15574
15723
|
}
|
|
15575
15724
|
};
|
|
15576
15725
|
function sleep3(ms) {
|
|
15577
|
-
return new Promise((
|
|
15726
|
+
return new Promise((resolve11) => setTimeout(resolve11, ms));
|
|
15578
15727
|
}
|
|
15579
15728
|
function dumpContainerLogs(container, tail = 40) {
|
|
15580
15729
|
try {
|
|
@@ -15861,9 +16010,10 @@ import pc10 from "picocolors";
|
|
|
15861
16010
|
import { execSync as execSync7 } from "node:child_process";
|
|
15862
16011
|
import { existsSync as existsSync26, statSync as statSync6 } from "node:fs";
|
|
15863
16012
|
import { join as join31 } from "node:path";
|
|
15864
|
-
var DEFAULT_DEVBOX_IMAGE = "olam-devbox:
|
|
16013
|
+
var DEFAULT_DEVBOX_IMAGE = "olam-devbox:base";
|
|
15865
16014
|
var DEVBOX_BAKED_SOURCES = [
|
|
15866
|
-
"packages/adapters/src/docker/devbox.Dockerfile",
|
|
16015
|
+
"packages/adapters/src/docker/devbox.base.Dockerfile",
|
|
16016
|
+
"packages/adapters/src/docker/devbox.browser.Dockerfile",
|
|
15867
16017
|
"packages/control-plane/standalone/server.mjs",
|
|
15868
16018
|
"packages/control-plane/standalone/intelligence-bridge.mjs",
|
|
15869
16019
|
"packages/control-plane/standalone/d1-sqlite-adapter.mjs",
|
|
@@ -15928,9 +16078,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
|
|
|
15928
16078
|
"These source files have changed since the image was built; the",
|
|
15929
16079
|
"changes will NOT take effect in fresh worlds until you rebuild:"
|
|
15930
16080
|
];
|
|
15931
|
-
for (const { path:
|
|
16081
|
+
for (const { path: path50, mtimeMs } of result.newerSources) {
|
|
15932
16082
|
const when = new Date(mtimeMs).toISOString();
|
|
15933
|
-
lines.push(` \u2022 ${
|
|
16083
|
+
lines.push(` \u2022 ${path50} (modified ${when})`);
|
|
15934
16084
|
}
|
|
15935
16085
|
lines.push("");
|
|
15936
16086
|
lines.push("Rebuild with:");
|
|
@@ -16089,15 +16239,15 @@ init_host_cp();
|
|
|
16089
16239
|
var HOST_CP_URL = "http://127.0.0.1:19000";
|
|
16090
16240
|
async function readHostCpTokenForCreate() {
|
|
16091
16241
|
try {
|
|
16092
|
-
const { default:
|
|
16242
|
+
const { default: fs48 } = await import("node:fs");
|
|
16093
16243
|
const { default: os28 } = await import("node:os");
|
|
16094
|
-
const { default:
|
|
16095
|
-
const tp =
|
|
16096
|
-
process.env.OLAM_HOME ??
|
|
16244
|
+
const { default: path50 } = await import("node:path");
|
|
16245
|
+
const tp = path50.join(
|
|
16246
|
+
process.env.OLAM_HOME ?? path50.join(os28.homedir(), ".olam"),
|
|
16097
16247
|
"host-cp.token"
|
|
16098
16248
|
);
|
|
16099
|
-
if (!
|
|
16100
|
-
return
|
|
16249
|
+
if (!fs48.existsSync(tp)) return null;
|
|
16250
|
+
return fs48.readFileSync(tp, "utf-8").trim();
|
|
16101
16251
|
} catch {
|
|
16102
16252
|
return null;
|
|
16103
16253
|
}
|
|
@@ -16460,12 +16610,12 @@ function defaultNameFromPrompt(prompt) {
|
|
|
16460
16610
|
}
|
|
16461
16611
|
async function readHostCpToken3() {
|
|
16462
16612
|
try {
|
|
16463
|
-
const { default:
|
|
16613
|
+
const { default: fs48 } = await import("node:fs");
|
|
16464
16614
|
const { default: os28 } = await import("node:os");
|
|
16465
|
-
const { default:
|
|
16466
|
-
const tp =
|
|
16467
|
-
if (!
|
|
16468
|
-
const raw =
|
|
16615
|
+
const { default: path50 } = await import("node:path");
|
|
16616
|
+
const tp = path50.join(os28.homedir(), ".olam", "host-cp.token");
|
|
16617
|
+
if (!fs48.existsSync(tp)) return null;
|
|
16618
|
+
const raw = fs48.readFileSync(tp, "utf-8").trim();
|
|
16469
16619
|
return raw.length > 0 ? raw : null;
|
|
16470
16620
|
} catch {
|
|
16471
16621
|
return null;
|
|
@@ -17133,14 +17283,14 @@ function printTable(entries) {
|
|
|
17133
17283
|
async function confirmInteractive() {
|
|
17134
17284
|
process.stdout.write(" Type `yes` to proceed: ");
|
|
17135
17285
|
const buf = [];
|
|
17136
|
-
return new Promise((
|
|
17286
|
+
return new Promise((resolve11) => {
|
|
17137
17287
|
const onData = (chunk) => {
|
|
17138
17288
|
buf.push(chunk);
|
|
17139
17289
|
if (Buffer.concat(buf).toString("utf-8").includes("\n")) {
|
|
17140
17290
|
process.stdin.removeListener("data", onData);
|
|
17141
17291
|
process.stdin.pause();
|
|
17142
17292
|
const answer = Buffer.concat(buf).toString("utf-8").trim();
|
|
17143
|
-
|
|
17293
|
+
resolve11(answer.toLowerCase() === "yes");
|
|
17144
17294
|
}
|
|
17145
17295
|
};
|
|
17146
17296
|
process.stdin.resume();
|
|
@@ -20196,11 +20346,11 @@ function zodIssueToError(issue, doc, lineCounter) {
|
|
|
20196
20346
|
suggestion: deriveSuggestion(issue)
|
|
20197
20347
|
};
|
|
20198
20348
|
}
|
|
20199
|
-
function formatJsonPath(
|
|
20200
|
-
if (
|
|
20349
|
+
function formatJsonPath(path50) {
|
|
20350
|
+
if (path50.length === 0)
|
|
20201
20351
|
return "<root>";
|
|
20202
20352
|
let out = "";
|
|
20203
|
-
for (const seg of
|
|
20353
|
+
for (const seg of path50) {
|
|
20204
20354
|
if (typeof seg === "number") {
|
|
20205
20355
|
out += `[${seg}]`;
|
|
20206
20356
|
} else {
|
|
@@ -20209,11 +20359,11 @@ function formatJsonPath(path49) {
|
|
|
20209
20359
|
}
|
|
20210
20360
|
return out;
|
|
20211
20361
|
}
|
|
20212
|
-
function resolveYamlLocation(
|
|
20362
|
+
function resolveYamlLocation(path50, doc, lineCounter) {
|
|
20213
20363
|
let bestLine = 0;
|
|
20214
20364
|
let bestColumn = 0;
|
|
20215
|
-
for (let depth =
|
|
20216
|
-
const segment =
|
|
20365
|
+
for (let depth = path50.length; depth >= 0; depth -= 1) {
|
|
20366
|
+
const segment = path50.slice(0, depth);
|
|
20217
20367
|
try {
|
|
20218
20368
|
const node = doc.getIn(segment, true);
|
|
20219
20369
|
if (node && typeof node === "object" && "range" in node) {
|
|
@@ -20431,11 +20581,11 @@ function topoSort(nodes) {
|
|
|
20431
20581
|
}
|
|
20432
20582
|
function traceCycle(start, byId) {
|
|
20433
20583
|
const seen = /* @__PURE__ */ new Set();
|
|
20434
|
-
const
|
|
20584
|
+
const path50 = [];
|
|
20435
20585
|
let current = start;
|
|
20436
20586
|
while (current && !seen.has(current)) {
|
|
20437
20587
|
seen.add(current);
|
|
20438
|
-
|
|
20588
|
+
path50.push(current);
|
|
20439
20589
|
const node = byId.get(current);
|
|
20440
20590
|
const next = node?.dependsOn[0];
|
|
20441
20591
|
if (next === void 0)
|
|
@@ -20443,10 +20593,10 @@ function traceCycle(start, byId) {
|
|
|
20443
20593
|
current = next;
|
|
20444
20594
|
}
|
|
20445
20595
|
if (current && seen.has(current)) {
|
|
20446
|
-
const idx =
|
|
20447
|
-
return [...
|
|
20596
|
+
const idx = path50.indexOf(current);
|
|
20597
|
+
return [...path50.slice(idx), current];
|
|
20448
20598
|
}
|
|
20449
|
-
return
|
|
20599
|
+
return path50;
|
|
20450
20600
|
}
|
|
20451
20601
|
|
|
20452
20602
|
// ../core/dist/executor/types.js
|
|
@@ -22855,10 +23005,10 @@ async function confirm2(message) {
|
|
|
22855
23005
|
if (!process.stdin.isTTY) return true;
|
|
22856
23006
|
const { createInterface: createInterface5 } = await import("node:readline");
|
|
22857
23007
|
const rl = createInterface5({ input: process.stdin, output: process.stdout });
|
|
22858
|
-
return new Promise((
|
|
23008
|
+
return new Promise((resolve11) => {
|
|
22859
23009
|
rl.question(`${message} [y/N] `, (answer) => {
|
|
22860
23010
|
rl.close();
|
|
22861
|
-
|
|
23011
|
+
resolve11(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
22862
23012
|
});
|
|
22863
23013
|
});
|
|
22864
23014
|
}
|
|
@@ -22977,11 +23127,18 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
22977
23127
|
}
|
|
22978
23128
|
infoSpinner.succeed("docker daemon reachable");
|
|
22979
23129
|
const hasMcpAuthDigest = typeof digests["mcp-auth"] === "string" && digests["mcp-auth"].length > 0;
|
|
23130
|
+
const hasDevboxBaseDigest = typeof digests["devbox-base"] === "string" && digests["devbox-base"].length > 0;
|
|
22980
23131
|
const baseRefs = [
|
|
22981
23132
|
{ name: "host-cp", ref: `${registry}/olam-host-cp@${digests["host-cp"]}` },
|
|
22982
23133
|
{ name: "auth", ref: `${registry}/olam-auth@${digests.auth}` },
|
|
22983
23134
|
{ name: "devbox", ref: `${registry}/olam-devbox@${digests.devbox}` }
|
|
22984
23135
|
];
|
|
23136
|
+
if (hasDevboxBaseDigest) {
|
|
23137
|
+
baseRefs.push({
|
|
23138
|
+
name: "devbox-base",
|
|
23139
|
+
ref: `${registry}/olam-devbox@${digests["devbox-base"]}`
|
|
23140
|
+
});
|
|
23141
|
+
}
|
|
22985
23142
|
if (hasMcpAuthDigest) {
|
|
22986
23143
|
baseRefs.push({
|
|
22987
23144
|
name: "mcp-auth",
|
|
@@ -23046,18 +23203,29 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
23046
23203
|
}
|
|
23047
23204
|
}
|
|
23048
23205
|
handshakeSpinner.succeed(`Protocol handshake passed (all ${imageRefs.length} images)`);
|
|
23206
|
+
const refByName = (n) => {
|
|
23207
|
+
const found = imageRefs.find((r) => r.name === n);
|
|
23208
|
+
if (!found) throw new Error(`upgrade: missing imageRefs entry for "${n}"`);
|
|
23209
|
+
return found.ref;
|
|
23210
|
+
};
|
|
23049
23211
|
const tagPlanBase = [
|
|
23050
|
-
{ from:
|
|
23051
|
-
{ from:
|
|
23052
|
-
{ from:
|
|
23053
|
-
{ from:
|
|
23054
|
-
{ from:
|
|
23055
|
-
{ from:
|
|
23212
|
+
{ from: refByName("host-cp"), to: "olam-host-cp:latest", name: "host-cp (bare)" },
|
|
23213
|
+
{ from: refByName("host-cp"), to: `${registry}/olam-host-cp:latest`, name: "host-cp (registry)" },
|
|
23214
|
+
{ from: refByName("auth"), to: "olam-auth:local", name: "auth (bare)" },
|
|
23215
|
+
{ from: refByName("auth"), to: `${registry}/olam-auth:latest`, name: "auth (registry)" },
|
|
23216
|
+
{ from: refByName("devbox"), to: "olam-devbox:latest", name: "devbox (bare)" },
|
|
23217
|
+
{ from: refByName("devbox"), to: `${registry}/olam-devbox:latest`, name: "devbox (registry)" }
|
|
23056
23218
|
];
|
|
23057
|
-
if (
|
|
23219
|
+
if (hasDevboxBaseDigest) {
|
|
23058
23220
|
tagPlanBase.push(
|
|
23059
|
-
{ from:
|
|
23060
|
-
{ from:
|
|
23221
|
+
{ from: refByName("devbox-base"), to: "olam-devbox:base", name: "devbox-base (bare)" },
|
|
23222
|
+
{ from: refByName("devbox-base"), to: `${registry}/olam-devbox:base`, name: "devbox-base (registry)" }
|
|
23223
|
+
);
|
|
23224
|
+
}
|
|
23225
|
+
if (hasMcpAuthDigest) {
|
|
23226
|
+
tagPlanBase.push(
|
|
23227
|
+
{ from: refByName("mcp-auth"), to: "olam-mcp-auth:local", name: "mcp-auth (bare)" },
|
|
23228
|
+
{ from: refByName("mcp-auth"), to: `${registry}/olam-mcp-auth:latest`, name: "mcp-auth (registry)" }
|
|
23061
23229
|
);
|
|
23062
23230
|
}
|
|
23063
23231
|
const tagPlan = tagPlanBase;
|
|
@@ -25599,8 +25767,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
|
|
|
25599
25767
|
function authHeaders() {
|
|
25600
25768
|
return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
|
|
25601
25769
|
}
|
|
25602
|
-
async function apiFetch(
|
|
25603
|
-
const res = await fetch(`${BASE_URL}${
|
|
25770
|
+
async function apiFetch(path50, init = {}) {
|
|
25771
|
+
const res = await fetch(`${BASE_URL}${path50}`, {
|
|
25604
25772
|
...init,
|
|
25605
25773
|
headers: {
|
|
25606
25774
|
"Content-Type": "application/json",
|
|
@@ -25687,7 +25855,7 @@ function registerMcpLogin(cmd) {
|
|
|
25687
25855
|
init_output();
|
|
25688
25856
|
import * as readline2 from "node:readline";
|
|
25689
25857
|
async function readTokenSilent(prompt) {
|
|
25690
|
-
return new Promise((
|
|
25858
|
+
return new Promise((resolve11, reject) => {
|
|
25691
25859
|
const rl = readline2.createInterface({
|
|
25692
25860
|
input: process.stdin,
|
|
25693
25861
|
output: process.stdout,
|
|
@@ -25705,7 +25873,7 @@ async function readTokenSilent(prompt) {
|
|
|
25705
25873
|
process.stdin.removeListener("data", onData);
|
|
25706
25874
|
process.stdout.write("\n");
|
|
25707
25875
|
rl.close();
|
|
25708
|
-
|
|
25876
|
+
resolve11(token);
|
|
25709
25877
|
} else if (char === "") {
|
|
25710
25878
|
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
25711
25879
|
process.stdin.removeListener("data", onData);
|
|
@@ -25980,7 +26148,7 @@ async function discoverMcpSources(repoPaths) {
|
|
|
25980
26148
|
import { spawn as spawn6 } from "node:child_process";
|
|
25981
26149
|
var VALIDATION_TIMEOUT_MS = 5e3;
|
|
25982
26150
|
async function validateMcpEntry(entry) {
|
|
25983
|
-
return new Promise((
|
|
26151
|
+
return new Promise((resolve11) => {
|
|
25984
26152
|
let stdout = "";
|
|
25985
26153
|
let timedOut = false;
|
|
25986
26154
|
let child;
|
|
@@ -25990,7 +26158,7 @@ async function validateMcpEntry(entry) {
|
|
|
25990
26158
|
env: { ...process.env, ...entry.env ?? {} }
|
|
25991
26159
|
});
|
|
25992
26160
|
} catch (err) {
|
|
25993
|
-
|
|
26161
|
+
resolve11({
|
|
25994
26162
|
name: entry.name,
|
|
25995
26163
|
validated: false,
|
|
25996
26164
|
reason: err instanceof Error ? err.message : "spawn failed"
|
|
@@ -26007,11 +26175,11 @@ async function validateMcpEntry(entry) {
|
|
|
26007
26175
|
child.on("close", (code) => {
|
|
26008
26176
|
clearTimeout(timer);
|
|
26009
26177
|
if (timedOut) {
|
|
26010
|
-
|
|
26178
|
+
resolve11({ name: entry.name, validated: false, reason: "timeout (5s)" });
|
|
26011
26179
|
return;
|
|
26012
26180
|
}
|
|
26013
26181
|
const validated = code === 0 && stdout.trim().length > 0;
|
|
26014
|
-
|
|
26182
|
+
resolve11({
|
|
26015
26183
|
name: entry.name,
|
|
26016
26184
|
validated,
|
|
26017
26185
|
reason: validated ? "ok" : `exit code ${code ?? "null"}`
|
|
@@ -26019,7 +26187,7 @@ async function validateMcpEntry(entry) {
|
|
|
26019
26187
|
});
|
|
26020
26188
|
child.on("error", (err) => {
|
|
26021
26189
|
clearTimeout(timer);
|
|
26022
|
-
|
|
26190
|
+
resolve11({ name: entry.name, validated: false, reason: err.message });
|
|
26023
26191
|
});
|
|
26024
26192
|
});
|
|
26025
26193
|
}
|
|
@@ -26034,11 +26202,11 @@ async function multiSelectPicker(entries) {
|
|
|
26034
26202
|
);
|
|
26035
26203
|
});
|
|
26036
26204
|
console.log("\n" + pc29.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
|
|
26037
|
-
const answer = await new Promise((
|
|
26205
|
+
const answer = await new Promise((resolve11) => {
|
|
26038
26206
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
26039
26207
|
rl.question("> ", (ans) => {
|
|
26040
26208
|
rl.close();
|
|
26041
|
-
|
|
26209
|
+
resolve11(ans.trim());
|
|
26042
26210
|
});
|
|
26043
26211
|
});
|
|
26044
26212
|
if (!answer || answer === "") return [];
|
|
@@ -26176,19 +26344,217 @@ function registerMcp(program2) {
|
|
|
26176
26344
|
registerMcpRevoke(mcp);
|
|
26177
26345
|
}
|
|
26178
26346
|
|
|
26347
|
+
// src/commands/kg-build.ts
|
|
26348
|
+
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
26349
|
+
import fs46 from "node:fs";
|
|
26350
|
+
import path48 from "node:path";
|
|
26351
|
+
|
|
26352
|
+
// ../core/dist/kg/storage-paths.js
|
|
26353
|
+
import { homedir as homedir26 } from "node:os";
|
|
26354
|
+
import { join as join48, resolve as resolve10 } from "node:path";
|
|
26355
|
+
|
|
26356
|
+
// ../core/dist/world/workspace-name.js
|
|
26357
|
+
var InvalidWorkspaceNameError = class extends Error {
|
|
26358
|
+
constructor(name, reason) {
|
|
26359
|
+
super(`invalid workspace name ${JSON.stringify(name)}: ${reason}`);
|
|
26360
|
+
this.name = "InvalidWorkspaceNameError";
|
|
26361
|
+
}
|
|
26362
|
+
};
|
|
26363
|
+
var WORKSPACE_NAME_RE = /^[a-z0-9][a-z0-9_-]*$/;
|
|
26364
|
+
function validateWorkspaceName(name) {
|
|
26365
|
+
if (typeof name !== "string" || name.length === 0) {
|
|
26366
|
+
throw new InvalidWorkspaceNameError(String(name), "must be a non-empty string");
|
|
26367
|
+
}
|
|
26368
|
+
if (!WORKSPACE_NAME_RE.test(name)) {
|
|
26369
|
+
throw new InvalidWorkspaceNameError(name, "must match ^[a-z0-9][a-z0-9_-]*$ (lowercase letters, digits, hyphens, underscores; must start with letter or digit)");
|
|
26370
|
+
}
|
|
26371
|
+
}
|
|
26372
|
+
|
|
26373
|
+
// ../core/dist/kg/storage-paths.js
|
|
26374
|
+
function olamHome3() {
|
|
26375
|
+
return process.env.OLAM_HOME ?? join48(homedir26(), ".olam");
|
|
26376
|
+
}
|
|
26377
|
+
function kgRoot() {
|
|
26378
|
+
return join48(olamHome3(), "kg");
|
|
26379
|
+
}
|
|
26380
|
+
function worldsRoot() {
|
|
26381
|
+
return join48(olamHome3(), "worlds");
|
|
26382
|
+
}
|
|
26383
|
+
function assertWithinPrefix(path50, prefix, label) {
|
|
26384
|
+
if (!path50.startsWith(prefix + "/")) {
|
|
26385
|
+
throw new Error(`${label} escape: ${path50} not under ${prefix}/`);
|
|
26386
|
+
}
|
|
26387
|
+
}
|
|
26388
|
+
function kgPristinePath(workspace) {
|
|
26389
|
+
validateWorkspaceName(workspace);
|
|
26390
|
+
const root = kgRoot();
|
|
26391
|
+
const path50 = resolve10(join48(root, workspace));
|
|
26392
|
+
assertWithinPrefix(path50, root, "kgPristinePath");
|
|
26393
|
+
return path50;
|
|
26394
|
+
}
|
|
26395
|
+
var KG_PATHS_INTERNALS = Object.freeze({
|
|
26396
|
+
olamHome: olamHome3,
|
|
26397
|
+
kgRoot,
|
|
26398
|
+
worldsRoot
|
|
26399
|
+
});
|
|
26400
|
+
|
|
26401
|
+
// src/commands/kg-build.ts
|
|
26402
|
+
init_output();
|
|
26403
|
+
var DEFAULT_DEVBOX_IMAGE2 = "olam-devbox:latest";
|
|
26404
|
+
function resolveWorkspace(arg) {
|
|
26405
|
+
const cwd = process.cwd();
|
|
26406
|
+
const name = arg ?? path48.basename(cwd).toLowerCase();
|
|
26407
|
+
validateWorkspaceName(name);
|
|
26408
|
+
return { name, sourcePath: cwd };
|
|
26409
|
+
}
|
|
26410
|
+
function copyWorkspaceToScratch(source, scratch) {
|
|
26411
|
+
if (process.platform === "darwin") {
|
|
26412
|
+
const r2 = spawnSync14("cp", ["-c", "-r", source + "/.", scratch], {
|
|
26413
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
26414
|
+
encoding: "utf-8"
|
|
26415
|
+
});
|
|
26416
|
+
if (r2.status === 0) return "cp-c-r-reflink";
|
|
26417
|
+
}
|
|
26418
|
+
const r = spawnSync14("cp", ["-r", source + "/.", scratch], {
|
|
26419
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
26420
|
+
encoding: "utf-8"
|
|
26421
|
+
});
|
|
26422
|
+
if (r.status !== 0) {
|
|
26423
|
+
throw new Error(`cp -r failed: ${(r.stderr ?? "").trim() || r.error?.message}`);
|
|
26424
|
+
}
|
|
26425
|
+
return "cp-r";
|
|
26426
|
+
}
|
|
26427
|
+
function parseNodeCount(graphifyOutDir) {
|
|
26428
|
+
const graphPath = path48.join(graphifyOutDir, "graph.json");
|
|
26429
|
+
if (!fs46.existsSync(graphPath)) return null;
|
|
26430
|
+
try {
|
|
26431
|
+
const content = fs46.readFileSync(graphPath, "utf-8");
|
|
26432
|
+
const data = JSON.parse(content);
|
|
26433
|
+
return Array.isArray(data.nodes) ? data.nodes.length : null;
|
|
26434
|
+
} catch {
|
|
26435
|
+
return null;
|
|
26436
|
+
}
|
|
26437
|
+
}
|
|
26438
|
+
function readGraphifyVersion(image) {
|
|
26439
|
+
const r = spawnSync14(
|
|
26440
|
+
"docker",
|
|
26441
|
+
[
|
|
26442
|
+
"run",
|
|
26443
|
+
"--rm",
|
|
26444
|
+
"--entrypoint=/opt/graphify-venv/bin/pip",
|
|
26445
|
+
image,
|
|
26446
|
+
"show",
|
|
26447
|
+
"graphifyy"
|
|
26448
|
+
],
|
|
26449
|
+
{ encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
|
|
26450
|
+
);
|
|
26451
|
+
if (r.status !== 0) return "unknown";
|
|
26452
|
+
const m = (r.stdout ?? "").match(/^Version:\s*(\S+)/m);
|
|
26453
|
+
return m?.[1] ?? "unknown";
|
|
26454
|
+
}
|
|
26455
|
+
async function runKgBuild(workspaceArg, options = {}) {
|
|
26456
|
+
const image = options.image ?? DEFAULT_DEVBOX_IMAGE2;
|
|
26457
|
+
let workspace;
|
|
26458
|
+
try {
|
|
26459
|
+
workspace = resolveWorkspace(workspaceArg);
|
|
26460
|
+
} catch (err) {
|
|
26461
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
26462
|
+
return { exitCode: 2 };
|
|
26463
|
+
}
|
|
26464
|
+
const outDir = kgPristinePath(workspace.name);
|
|
26465
|
+
const scratchDir = path48.join(outDir, "scratch");
|
|
26466
|
+
fs46.mkdirSync(outDir, { recursive: true });
|
|
26467
|
+
if (fs46.existsSync(scratchDir)) fs46.rmSync(scratchDir, { recursive: true, force: true });
|
|
26468
|
+
fs46.mkdirSync(scratchDir);
|
|
26469
|
+
const human = !options.json;
|
|
26470
|
+
if (human) {
|
|
26471
|
+
printInfo("kg build", `workspace=${workspace.name} source=${workspace.sourcePath}`);
|
|
26472
|
+
printInfo("kg build", `scratch=${scratchDir} \u2192 out=${outDir}/graphify-out/`);
|
|
26473
|
+
}
|
|
26474
|
+
const started = Date.now();
|
|
26475
|
+
let scratchStrategy;
|
|
26476
|
+
try {
|
|
26477
|
+
scratchStrategy = copyWorkspaceToScratch(workspace.sourcePath, scratchDir);
|
|
26478
|
+
if (human) printInfo("kg build", `copied via ${scratchStrategy}`);
|
|
26479
|
+
const dockerArgs = [
|
|
26480
|
+
"run",
|
|
26481
|
+
"--rm",
|
|
26482
|
+
"-v",
|
|
26483
|
+
`${scratchDir}:/work`,
|
|
26484
|
+
"-w",
|
|
26485
|
+
"/work",
|
|
26486
|
+
"--entrypoint=graphify",
|
|
26487
|
+
image,
|
|
26488
|
+
"update",
|
|
26489
|
+
"."
|
|
26490
|
+
];
|
|
26491
|
+
const r = human ? spawnSync14("docker", dockerArgs, { stdio: "inherit" }) : spawnSync14("docker", dockerArgs, { stdio: ["ignore", "ignore", "pipe"] });
|
|
26492
|
+
if (r.status !== 0) {
|
|
26493
|
+
printError(`graphify update failed (exit ${r.status})`);
|
|
26494
|
+
return { exitCode: r.status ?? 1 };
|
|
26495
|
+
}
|
|
26496
|
+
const scratchOut = path48.join(scratchDir, "graphify-out");
|
|
26497
|
+
const finalOut = path48.join(outDir, "graphify-out");
|
|
26498
|
+
if (!fs46.existsSync(scratchOut)) {
|
|
26499
|
+
printError(`graphify produced no graphify-out/ in scratch (${scratchOut})`);
|
|
26500
|
+
return { exitCode: 1 };
|
|
26501
|
+
}
|
|
26502
|
+
if (fs46.existsSync(finalOut)) fs46.rmSync(finalOut, { recursive: true, force: true });
|
|
26503
|
+
fs46.renameSync(scratchOut, finalOut);
|
|
26504
|
+
const durationMs = Date.now() - started;
|
|
26505
|
+
const nodeCount = parseNodeCount(finalOut);
|
|
26506
|
+
const version = readGraphifyVersion(image);
|
|
26507
|
+
const freshness = {
|
|
26508
|
+
built_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
26509
|
+
duration_ms: durationMs,
|
|
26510
|
+
node_count: nodeCount,
|
|
26511
|
+
graphify_version: version,
|
|
26512
|
+
workspace: workspace.name,
|
|
26513
|
+
scratch_strategy: scratchStrategy
|
|
26514
|
+
};
|
|
26515
|
+
fs46.writeFileSync(
|
|
26516
|
+
path48.join(outDir, "freshness.json"),
|
|
26517
|
+
JSON.stringify(freshness, null, 2) + "\n",
|
|
26518
|
+
"utf-8"
|
|
26519
|
+
);
|
|
26520
|
+
if (options.json) {
|
|
26521
|
+
process.stdout.write(JSON.stringify(freshness) + "\n");
|
|
26522
|
+
} else {
|
|
26523
|
+
printSuccess(
|
|
26524
|
+
`kg build ${workspace.name} \u2014 ${nodeCount ?? "?"} nodes in ${(durationMs / 1e3).toFixed(1)}s (graphify ${version})`
|
|
26525
|
+
);
|
|
26526
|
+
printInfo("output", `${finalOut}/graph.json`);
|
|
26527
|
+
}
|
|
26528
|
+
return { exitCode: 0, freshness, outputDir: finalOut };
|
|
26529
|
+
} finally {
|
|
26530
|
+
if (fs46.existsSync(scratchDir)) {
|
|
26531
|
+
fs46.rmSync(scratchDir, { recursive: true, force: true });
|
|
26532
|
+
}
|
|
26533
|
+
}
|
|
26534
|
+
}
|
|
26535
|
+
function registerKg(program2) {
|
|
26536
|
+
const kg = program2.command("kg").description("Knowledge-graph operations (graphify-backed)");
|
|
26537
|
+
kg.command("build").description(
|
|
26538
|
+
"Build pristine KG for a workspace (default: current dir). Scratch-dir pattern; ~/.olam/kg/<ws>/graphify-out/"
|
|
26539
|
+
).argument("[workspace]", "workspace name (lowercase alphanumeric + hyphens/underscores)").option("--image <ref>", `devbox image to invoke (default: ${DEFAULT_DEVBOX_IMAGE2})`).option("--json", "emit freshness record as JSON instead of human-readable status").action(async (workspaceArg, opts) => {
|
|
26540
|
+
const r = await runKgBuild(workspaceArg, opts);
|
|
26541
|
+
if (r.exitCode !== 0) process.exitCode = r.exitCode;
|
|
26542
|
+
});
|
|
26543
|
+
}
|
|
26544
|
+
|
|
26179
26545
|
// src/pleri-config.ts
|
|
26180
|
-
import * as
|
|
26181
|
-
import * as
|
|
26546
|
+
import * as fs47 from "node:fs";
|
|
26547
|
+
import * as path49 from "node:path";
|
|
26182
26548
|
function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
|
|
26183
26549
|
if (process.env.PLERI_BASE_URL) {
|
|
26184
26550
|
return true;
|
|
26185
26551
|
}
|
|
26186
|
-
const configPath =
|
|
26187
|
-
if (!
|
|
26552
|
+
const configPath = path49.join(configDir, "config.yaml");
|
|
26553
|
+
if (!fs47.existsSync(configPath)) {
|
|
26188
26554
|
return false;
|
|
26189
26555
|
}
|
|
26190
26556
|
try {
|
|
26191
|
-
const contents =
|
|
26557
|
+
const contents = fs47.readFileSync(configPath, "utf8");
|
|
26192
26558
|
return /^[^#\n]*\bpleri:/m.test(contents);
|
|
26193
26559
|
} catch {
|
|
26194
26560
|
return false;
|
|
@@ -26230,6 +26596,7 @@ registerBegin(program);
|
|
|
26230
26596
|
registerStop(program);
|
|
26231
26597
|
registerWorldUpgrade(program);
|
|
26232
26598
|
registerMcp(program);
|
|
26599
|
+
registerKg(program);
|
|
26233
26600
|
registerConfig(program);
|
|
26234
26601
|
registerRepos(program);
|
|
26235
26602
|
registerRunbooks(program);
|