@pleri/olam-cli 0.1.80 → 0.1.82
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/implode.d.ts +86 -0
- package/dist/commands/implode.d.ts.map +1 -0
- package/dist/commands/implode.js +468 -0
- package/dist/commands/implode.js.map +1 -0
- package/dist/image-digests.json +3 -3
- package/dist/index.js +775 -404
- package/dist/index.js.map +1 -1
- package/host-cp/src/plan-orchestrator.mjs +71 -40
- package/host-cp/src/server.mjs +4 -43
- 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: path49, errorMaps, issueData } = params;
|
|
491
|
+
const fullPath = [...path49, ...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, path49, key) {
|
|
800
800
|
this._cachedPath = [];
|
|
801
801
|
this.parent = parent;
|
|
802
802
|
this.data = value;
|
|
803
|
-
this._path =
|
|
803
|
+
this._path = path49;
|
|
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, path49, 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, path48, ctx, rejectSource) {
|
|
|
4289
4289
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
4290
4290
|
ctx.addIssue({
|
|
4291
4291
|
code: external_exports.ZodIssueCode.custom,
|
|
4292
|
-
path: [...
|
|
4292
|
+
path: [...path49, key],
|
|
4293
4293
|
message: `forbidden key "${key}" (prototype-pollution surface)`
|
|
4294
4294
|
});
|
|
4295
4295
|
continue;
|
|
4296
4296
|
}
|
|
4297
|
-
if (rejectSource &&
|
|
4297
|
+
if (rejectSource && path49.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, path48, ctx, rejectSource) {
|
|
|
4302
4302
|
});
|
|
4303
4303
|
continue;
|
|
4304
4304
|
}
|
|
4305
|
-
refineForbiddenKeys(value[key], [...
|
|
4305
|
+
refineForbiddenKeys(value[key], [...path49, key], ctx, false);
|
|
4306
4306
|
}
|
|
4307
4307
|
}
|
|
4308
|
-
function rejectForbiddenKeys(value,
|
|
4308
|
+
function rejectForbiddenKeys(value, path49, 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] ${path49}: forbidden key "${key}" (prototype-pollution surface)`);
|
|
4315
4315
|
}
|
|
4316
4316
|
if (rejectSource && key === "source") {
|
|
4317
|
-
throw new Error(`[manifest] ${
|
|
4317
|
+
throw new Error(`[manifest] ${path49}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
|
|
4318
4318
|
}
|
|
4319
|
-
rejectForbiddenKeys(value[key], `${
|
|
4319
|
+
rejectForbiddenKeys(value[key], `${path49}.${key}`, false);
|
|
4320
4320
|
}
|
|
4321
4321
|
}
|
|
4322
4322
|
function unknownTopLevelKeys(parsed) {
|
|
@@ -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, path49, body, attempt = 0) {
|
|
5313
|
+
const url = `${this.baseUrl}${path49}`;
|
|
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, path49, body, attempt + 1);
|
|
5332
5332
|
}
|
|
5333
5333
|
throw err;
|
|
5334
5334
|
} finally {
|
|
@@ -6819,8 +6819,8 @@ var init_provider3 = __esm({
|
|
|
6819
6819
|
// -----------------------------------------------------------------------
|
|
6820
6820
|
// Internal fetch helper
|
|
6821
6821
|
// -----------------------------------------------------------------------
|
|
6822
|
-
async request(
|
|
6823
|
-
const url = `${this.config.workerUrl}${
|
|
6822
|
+
async request(path49, method, body) {
|
|
6823
|
+
const url = `${this.config.workerUrl}${path49}`;
|
|
6824
6824
|
const bearer = await this.config.mintToken();
|
|
6825
6825
|
const headers = {
|
|
6826
6826
|
Authorization: `Bearer ${bearer}`
|
|
@@ -8112,8 +8112,8 @@ import { execFileSync as execFileSync3 } from "node:child_process";
|
|
|
8112
8112
|
import * as fs14 from "node:fs";
|
|
8113
8113
|
import * as os9 from "node:os";
|
|
8114
8114
|
import * as path15 from "node:path";
|
|
8115
|
-
function expandHome(p,
|
|
8116
|
-
return p.replace(/^~(?=$|\/|\\)/,
|
|
8115
|
+
function expandHome(p, homedir26) {
|
|
8116
|
+
return p.replace(/^~(?=$|\/|\\)/, homedir26());
|
|
8117
8117
|
}
|
|
8118
8118
|
function sanitizeRepoFilename(name) {
|
|
8119
8119
|
const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
@@ -8136,7 +8136,7 @@ ${stderr}`;
|
|
|
8136
8136
|
}
|
|
8137
8137
|
function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
8138
8138
|
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync3(cmd, args, opts));
|
|
8139
|
-
const
|
|
8139
|
+
const homedir26 = deps.homedir ?? (() => os9.homedir());
|
|
8140
8140
|
const baselineDir = path15.join(workspacePath, ".olam", "baseline");
|
|
8141
8141
|
try {
|
|
8142
8142
|
fs14.mkdirSync(baselineDir, { recursive: true });
|
|
@@ -8152,7 +8152,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
|
8152
8152
|
continue;
|
|
8153
8153
|
const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
|
|
8154
8154
|
const outPath = path15.join(baselineDir, filename);
|
|
8155
|
-
const repoPath = expandHome(repo.path,
|
|
8155
|
+
const repoPath = expandHome(repo.path, homedir26);
|
|
8156
8156
|
if (!fs14.existsSync(repoPath)) {
|
|
8157
8157
|
writeBaselineFile(outPath, `# repo: ${repo.name}
|
|
8158
8158
|
# (skipped: path ${repoPath} does not exist)
|
|
@@ -13674,10 +13674,10 @@ async function readHostCpToken2() {
|
|
|
13674
13674
|
if (!fs25.existsSync(tp)) return null;
|
|
13675
13675
|
return fs25.readFileSync(tp, "utf-8").trim();
|
|
13676
13676
|
}
|
|
13677
|
-
async function callHostCpProxy(method, worldId,
|
|
13677
|
+
async function callHostCpProxy(method, worldId, path49, body) {
|
|
13678
13678
|
const token = await readHostCpToken2();
|
|
13679
13679
|
if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
|
|
13680
|
-
const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${
|
|
13680
|
+
const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path49}`;
|
|
13681
13681
|
try {
|
|
13682
13682
|
const headers = {
|
|
13683
13683
|
Authorization: `Bearer ${token}`
|
|
@@ -14136,16 +14136,16 @@ __export(machine_schema_exports, {
|
|
|
14136
14136
|
readMachineConfig: () => readMachineConfig,
|
|
14137
14137
|
writeMachineConfig: () => writeMachineConfig
|
|
14138
14138
|
});
|
|
14139
|
-
import * as
|
|
14140
|
-
import * as
|
|
14141
|
-
import * as
|
|
14139
|
+
import * as fs41 from "node:fs";
|
|
14140
|
+
import * as path44 from "node:path";
|
|
14141
|
+
import * as os24 from "node:os";
|
|
14142
14142
|
import { parse as parseYaml5, stringify as stringifyYaml5 } from "yaml";
|
|
14143
14143
|
function readMachineConfig(configPath) {
|
|
14144
14144
|
const p = configPath ?? DEFAULT_CONFIG_PATH;
|
|
14145
|
-
if (!
|
|
14145
|
+
if (!fs41.existsSync(p))
|
|
14146
14146
|
return null;
|
|
14147
14147
|
try {
|
|
14148
|
-
const raw =
|
|
14148
|
+
const raw = fs41.readFileSync(p, "utf-8");
|
|
14149
14149
|
const parsed = parseYaml5(raw);
|
|
14150
14150
|
return MachineConfigSchema.parse(parsed);
|
|
14151
14151
|
} catch {
|
|
@@ -14154,8 +14154,8 @@ function readMachineConfig(configPath) {
|
|
|
14154
14154
|
}
|
|
14155
14155
|
function writeMachineConfig(config, configPath) {
|
|
14156
14156
|
const p = configPath ?? DEFAULT_CONFIG_PATH;
|
|
14157
|
-
|
|
14158
|
-
|
|
14157
|
+
fs41.mkdirSync(path44.dirname(p), { recursive: true });
|
|
14158
|
+
fs41.writeFileSync(p, stringifyYaml5({ ...config }), { mode: 420 });
|
|
14159
14159
|
}
|
|
14160
14160
|
function initMachineConfig(opts = {}) {
|
|
14161
14161
|
const configPath = opts.configPath ?? DEFAULT_CONFIG_PATH;
|
|
@@ -14178,9 +14178,9 @@ var init_machine_schema = __esm({
|
|
|
14178
14178
|
channel: external_exports.enum(["stable", "beta", "edge"]).default("stable"),
|
|
14179
14179
|
auto_update: external_exports.boolean().default(true),
|
|
14180
14180
|
telemetry: external_exports.boolean().default(true),
|
|
14181
|
-
worlds_dir: external_exports.string().default(() =>
|
|
14181
|
+
worlds_dir: external_exports.string().default(() => path44.join(os24.homedir(), ".olam", "worlds"))
|
|
14182
14182
|
});
|
|
14183
|
-
DEFAULT_CONFIG_PATH =
|
|
14183
|
+
DEFAULT_CONFIG_PATH = path44.join(os24.homedir(), ".olam", "config.yaml");
|
|
14184
14184
|
}
|
|
14185
14185
|
});
|
|
14186
14186
|
|
|
@@ -14562,9 +14562,9 @@ var UnknownArchetypeError = class extends Error {
|
|
|
14562
14562
|
};
|
|
14563
14563
|
var ArchetypeCycleError = class extends Error {
|
|
14564
14564
|
path;
|
|
14565
|
-
constructor(
|
|
14566
|
-
super(`Archetype inheritance cycle detected: ${
|
|
14567
|
-
this.path =
|
|
14565
|
+
constructor(path49) {
|
|
14566
|
+
super(`Archetype inheritance cycle detected: ${path49.join(" \u2192 ")} \u2192 ${path49[0] ?? "?"}`);
|
|
14567
|
+
this.path = path49;
|
|
14568
14568
|
this.name = "ArchetypeCycleError";
|
|
14569
14569
|
}
|
|
14570
14570
|
};
|
|
@@ -15196,8 +15196,8 @@ function runStep(label, cmd, args, opts = {}) {
|
|
|
15196
15196
|
}
|
|
15197
15197
|
async function confirm(message) {
|
|
15198
15198
|
if (!process.stdin.isTTY) return true;
|
|
15199
|
-
const { createInterface:
|
|
15200
|
-
const rl =
|
|
15199
|
+
const { createInterface: createInterface5 } = await import("node:readline");
|
|
15200
|
+
const rl = createInterface5({ input: process.stdin, output: process.stdout });
|
|
15201
15201
|
return new Promise((resolve10) => {
|
|
15202
15202
|
rl.question(`${message} [y/N] `, (answer) => {
|
|
15203
15203
|
rl.close();
|
|
@@ -15929,9 +15929,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
|
|
|
15929
15929
|
"These source files have changed since the image was built; the",
|
|
15930
15930
|
"changes will NOT take effect in fresh worlds until you rebuild:"
|
|
15931
15931
|
];
|
|
15932
|
-
for (const { path:
|
|
15932
|
+
for (const { path: path49, mtimeMs } of result.newerSources) {
|
|
15933
15933
|
const when = new Date(mtimeMs).toISOString();
|
|
15934
|
-
lines.push(` \u2022 ${
|
|
15934
|
+
lines.push(` \u2022 ${path49} (modified ${when})`);
|
|
15935
15935
|
}
|
|
15936
15936
|
lines.push("");
|
|
15937
15937
|
lines.push("Rebuild with:");
|
|
@@ -16090,15 +16090,15 @@ init_host_cp();
|
|
|
16090
16090
|
var HOST_CP_URL = "http://127.0.0.1:19000";
|
|
16091
16091
|
async function readHostCpTokenForCreate() {
|
|
16092
16092
|
try {
|
|
16093
|
-
const { default:
|
|
16094
|
-
const { default:
|
|
16095
|
-
const { default:
|
|
16096
|
-
const tp =
|
|
16097
|
-
process.env.OLAM_HOME ??
|
|
16093
|
+
const { default: fs47 } = await import("node:fs");
|
|
16094
|
+
const { default: os28 } = await import("node:os");
|
|
16095
|
+
const { default: path49 } = await import("node:path");
|
|
16096
|
+
const tp = path49.join(
|
|
16097
|
+
process.env.OLAM_HOME ?? path49.join(os28.homedir(), ".olam"),
|
|
16098
16098
|
"host-cp.token"
|
|
16099
16099
|
);
|
|
16100
|
-
if (!
|
|
16101
|
-
return
|
|
16100
|
+
if (!fs47.existsSync(tp)) return null;
|
|
16101
|
+
return fs47.readFileSync(tp, "utf-8").trim();
|
|
16102
16102
|
} catch {
|
|
16103
16103
|
return null;
|
|
16104
16104
|
}
|
|
@@ -16461,12 +16461,12 @@ function defaultNameFromPrompt(prompt) {
|
|
|
16461
16461
|
}
|
|
16462
16462
|
async function readHostCpToken3() {
|
|
16463
16463
|
try {
|
|
16464
|
-
const { default:
|
|
16465
|
-
const { default:
|
|
16466
|
-
const { default:
|
|
16467
|
-
const tp =
|
|
16468
|
-
if (!
|
|
16469
|
-
const raw =
|
|
16464
|
+
const { default: fs47 } = await import("node:fs");
|
|
16465
|
+
const { default: os28 } = await import("node:os");
|
|
16466
|
+
const { default: path49 } = await import("node:path");
|
|
16467
|
+
const tp = path49.join(os28.homedir(), ".olam", "host-cp.token");
|
|
16468
|
+
if (!fs47.existsSync(tp)) return null;
|
|
16469
|
+
const raw = fs47.readFileSync(tp, "utf-8").trim();
|
|
16470
16470
|
return raw.length > 0 ? raw : null;
|
|
16471
16471
|
} catch {
|
|
16472
16472
|
return null;
|
|
@@ -17149,11 +17149,381 @@ async function confirmInteractive() {
|
|
|
17149
17149
|
});
|
|
17150
17150
|
}
|
|
17151
17151
|
|
|
17152
|
+
// src/commands/implode.ts
|
|
17153
|
+
init_output();
|
|
17154
|
+
import { execFileSync as execFileSync7 } from "node:child_process";
|
|
17155
|
+
import * as fs30 from "node:fs";
|
|
17156
|
+
import * as os18 from "node:os";
|
|
17157
|
+
import * as path32 from "node:path";
|
|
17158
|
+
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
17159
|
+
import pc14 from "picocolors";
|
|
17160
|
+
var NPM_PACKAGE = "@pleri/olam-cli";
|
|
17161
|
+
var realExec = (cmd, args) => {
|
|
17162
|
+
try {
|
|
17163
|
+
const stdout = execFileSync7(cmd, [...args], {
|
|
17164
|
+
encoding: "utf-8",
|
|
17165
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
17166
|
+
});
|
|
17167
|
+
return { exitCode: 0, stdout, stderr: "" };
|
|
17168
|
+
} catch (err) {
|
|
17169
|
+
const e = err;
|
|
17170
|
+
return {
|
|
17171
|
+
exitCode: e.status ?? 1,
|
|
17172
|
+
stdout: typeof e.stdout === "string" ? e.stdout : e.stdout?.toString("utf-8") ?? "",
|
|
17173
|
+
stderr: typeof e.stderr === "string" ? e.stderr : e.stderr?.toString("utf-8") ?? ""
|
|
17174
|
+
};
|
|
17175
|
+
}
|
|
17176
|
+
};
|
|
17177
|
+
function surveyOlam(opts = {}) {
|
|
17178
|
+
const exec = opts.exec ?? realExec;
|
|
17179
|
+
const home = opts.olamHome ?? path32.join(os18.homedir(), ".olam");
|
|
17180
|
+
const containers = listDocker(exec, ["ps", "-a", "--format", "{{.Names}}"]).filter(
|
|
17181
|
+
(n) => n.startsWith("olam-")
|
|
17182
|
+
);
|
|
17183
|
+
const images = listDocker(exec, ["images", "--format", "{{.Repository}}:{{.Tag}}"]).filter(
|
|
17184
|
+
(ref) => ref.startsWith("olam-") || ref.startsWith("ghcr.io/pleri/olam-") || ref.startsWith("ghcr.io/pleri/olam")
|
|
17185
|
+
);
|
|
17186
|
+
const volumes = listDocker(exec, ["volume", "ls", "--format", "{{.Name}}"]).filter(
|
|
17187
|
+
(n) => n.startsWith("olam-")
|
|
17188
|
+
);
|
|
17189
|
+
const networks = listDocker(exec, ["network", "ls", "--format", "{{.Name}}"]).filter(
|
|
17190
|
+
(n) => n.startsWith("olam-") && n !== "olam-host-cp-internal-default"
|
|
17191
|
+
);
|
|
17192
|
+
const worlds = [];
|
|
17193
|
+
const worldsDir = path32.join(home, "worlds");
|
|
17194
|
+
if (fs30.existsSync(worldsDir)) {
|
|
17195
|
+
for (const entry of fs30.readdirSync(worldsDir, { withFileTypes: true })) {
|
|
17196
|
+
if (!entry.isDirectory()) continue;
|
|
17197
|
+
const wPath = path32.join(worldsDir, entry.name);
|
|
17198
|
+
const bytes = dirSize(wPath);
|
|
17199
|
+
const { dirty, note } = inspectWorldGitState(wPath);
|
|
17200
|
+
worlds.push({ id: entry.name, bytes, dirty, note, path: wPath });
|
|
17201
|
+
}
|
|
17202
|
+
}
|
|
17203
|
+
const homeBytesNonWorld = fs30.existsSync(home) ? Math.max(0, dirSize(home) - worlds.reduce((acc, w) => acc + w.bytes, 0)) : 0;
|
|
17204
|
+
const npmRoot = exec("npm", ["root", "-g"]);
|
|
17205
|
+
const npmGlobalRoot = npmRoot.exitCode === 0 ? npmRoot.stdout.trim() : null;
|
|
17206
|
+
const npmInstalled = npmGlobalRoot !== null && fs30.existsSync(path32.join(npmGlobalRoot, NPM_PACKAGE));
|
|
17207
|
+
return {
|
|
17208
|
+
containers,
|
|
17209
|
+
images,
|
|
17210
|
+
volumes,
|
|
17211
|
+
networks,
|
|
17212
|
+
worlds,
|
|
17213
|
+
homeBytesNonWorld,
|
|
17214
|
+
npmInstalled,
|
|
17215
|
+
npmGlobalRoot
|
|
17216
|
+
};
|
|
17217
|
+
}
|
|
17218
|
+
function listDocker(exec, args) {
|
|
17219
|
+
const r = exec("docker", args);
|
|
17220
|
+
if (r.exitCode !== 0) return [];
|
|
17221
|
+
return r.stdout.split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
17222
|
+
}
|
|
17223
|
+
function dirSize(p) {
|
|
17224
|
+
let total = 0;
|
|
17225
|
+
try {
|
|
17226
|
+
const stack = [p];
|
|
17227
|
+
while (stack.length > 0) {
|
|
17228
|
+
const cur = stack.pop();
|
|
17229
|
+
let entries;
|
|
17230
|
+
try {
|
|
17231
|
+
entries = fs30.readdirSync(cur, { withFileTypes: true });
|
|
17232
|
+
} catch {
|
|
17233
|
+
continue;
|
|
17234
|
+
}
|
|
17235
|
+
for (const e of entries) {
|
|
17236
|
+
const full = path32.join(cur, e.name);
|
|
17237
|
+
try {
|
|
17238
|
+
if (e.isDirectory()) stack.push(full);
|
|
17239
|
+
else if (e.isFile()) total += fs30.statSync(full).size;
|
|
17240
|
+
} catch {
|
|
17241
|
+
}
|
|
17242
|
+
}
|
|
17243
|
+
}
|
|
17244
|
+
} catch {
|
|
17245
|
+
}
|
|
17246
|
+
return total;
|
|
17247
|
+
}
|
|
17248
|
+
function inspectWorldGitState(worldPath) {
|
|
17249
|
+
const repoNotes = [];
|
|
17250
|
+
let dirty = false;
|
|
17251
|
+
try {
|
|
17252
|
+
for (const entry of fs30.readdirSync(worldPath, { withFileTypes: true })) {
|
|
17253
|
+
if (!entry.isDirectory()) continue;
|
|
17254
|
+
const repo = path32.join(worldPath, entry.name);
|
|
17255
|
+
const gitDir = path32.join(repo, ".git");
|
|
17256
|
+
if (!fs30.existsSync(gitDir)) continue;
|
|
17257
|
+
try {
|
|
17258
|
+
const status = execFileSync7("git", ["status", "--porcelain"], {
|
|
17259
|
+
cwd: repo,
|
|
17260
|
+
encoding: "utf-8",
|
|
17261
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
17262
|
+
}).trim();
|
|
17263
|
+
if (status.length > 0) {
|
|
17264
|
+
dirty = true;
|
|
17265
|
+
repoNotes.push(`${entry.name}: uncommitted`);
|
|
17266
|
+
continue;
|
|
17267
|
+
}
|
|
17268
|
+
} catch {
|
|
17269
|
+
continue;
|
|
17270
|
+
}
|
|
17271
|
+
try {
|
|
17272
|
+
const ahead = execFileSync7(
|
|
17273
|
+
"git",
|
|
17274
|
+
["rev-list", "--count", "@{upstream}..HEAD"],
|
|
17275
|
+
{ cwd: repo, encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
17276
|
+
).trim();
|
|
17277
|
+
if (ahead && ahead !== "0") {
|
|
17278
|
+
dirty = true;
|
|
17279
|
+
repoNotes.push(`${entry.name}: ${ahead} unpushed`);
|
|
17280
|
+
}
|
|
17281
|
+
} catch {
|
|
17282
|
+
dirty = true;
|
|
17283
|
+
repoNotes.push(`${entry.name}: no-upstream`);
|
|
17284
|
+
}
|
|
17285
|
+
}
|
|
17286
|
+
} catch {
|
|
17287
|
+
}
|
|
17288
|
+
return { dirty, note: repoNotes.join("; ") };
|
|
17289
|
+
}
|
|
17290
|
+
function renderSurvey(survey, opts) {
|
|
17291
|
+
if (opts.json) {
|
|
17292
|
+
return JSON.stringify(
|
|
17293
|
+
{
|
|
17294
|
+
containers: survey.containers,
|
|
17295
|
+
images: survey.images,
|
|
17296
|
+
volumes: survey.volumes,
|
|
17297
|
+
networks: survey.networks,
|
|
17298
|
+
worlds: survey.worlds.map((w) => ({
|
|
17299
|
+
id: w.id,
|
|
17300
|
+
bytes: w.bytes,
|
|
17301
|
+
dirty: w.dirty,
|
|
17302
|
+
note: w.note
|
|
17303
|
+
})),
|
|
17304
|
+
homeBytesNonWorld: survey.homeBytesNonWorld,
|
|
17305
|
+
npmInstalled: survey.npmInstalled,
|
|
17306
|
+
npmGlobalRoot: survey.npmGlobalRoot
|
|
17307
|
+
},
|
|
17308
|
+
null,
|
|
17309
|
+
2
|
|
17310
|
+
);
|
|
17311
|
+
}
|
|
17312
|
+
const lines = [];
|
|
17313
|
+
const dirtyWorlds = survey.worlds.filter((w) => w.dirty);
|
|
17314
|
+
const cleanWorlds = survey.worlds.filter((w) => !w.dirty);
|
|
17315
|
+
const worldBytes = survey.worlds.reduce((acc, w) => acc + w.bytes, 0);
|
|
17316
|
+
lines.push(pc14.bold(pc14.red("\u2014 olam implode survey \u2014")));
|
|
17317
|
+
lines.push("");
|
|
17318
|
+
lines.push(` containers (olam-*): ${survey.containers.length}`);
|
|
17319
|
+
lines.push(` images: ${survey.images.length}`);
|
|
17320
|
+
lines.push(` volumes: ${survey.volumes.length}`);
|
|
17321
|
+
lines.push(` networks: ${survey.networks.length}`);
|
|
17322
|
+
lines.push(
|
|
17323
|
+
` worlds: ${survey.worlds.length} (${dirtyWorlds.length} dirty, ${cleanWorlds.length} clean)`
|
|
17324
|
+
);
|
|
17325
|
+
lines.push(` ~/.olam/* (non-world): ${formatBytes2(survey.homeBytesNonWorld)}`);
|
|
17326
|
+
lines.push(` worlds total: ${formatBytes2(worldBytes)}`);
|
|
17327
|
+
lines.push(
|
|
17328
|
+
` npm package installed: ${survey.npmInstalled ? `yes (at ${survey.npmGlobalRoot}/${NPM_PACKAGE})` : "no"}`
|
|
17329
|
+
);
|
|
17330
|
+
if (dirtyWorlds.length > 0) {
|
|
17331
|
+
lines.push("");
|
|
17332
|
+
lines.push(pc14.yellow(` \u26A0 dirty worlds (${dirtyWorlds.length}) \u2014 pass --include-dirty to destroy:`));
|
|
17333
|
+
for (const w of dirtyWorlds) {
|
|
17334
|
+
lines.push(` - ${w.id} ${formatBytes2(w.bytes)} (${w.note})`);
|
|
17335
|
+
}
|
|
17336
|
+
}
|
|
17337
|
+
lines.push("");
|
|
17338
|
+
lines.push(pc14.dim(" Run with --yes to actually destroy. Default is dry-run."));
|
|
17339
|
+
return lines.join("\n");
|
|
17340
|
+
}
|
|
17341
|
+
function formatBytes2(n) {
|
|
17342
|
+
if (n < 1024) return `${n} B`;
|
|
17343
|
+
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
|
|
17344
|
+
if (n < 1024 * 1024 * 1024) return `${(n / 1024 / 1024).toFixed(1)} MB`;
|
|
17345
|
+
return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;
|
|
17346
|
+
}
|
|
17347
|
+
async function executeImplode(survey, opts) {
|
|
17348
|
+
const exec = opts.exec ?? realExec;
|
|
17349
|
+
const home = opts.olamHome ?? path32.join(os18.homedir(), ".olam");
|
|
17350
|
+
const removed = [];
|
|
17351
|
+
const skipped = [];
|
|
17352
|
+
const errors = [];
|
|
17353
|
+
if (!opts.keepWorlds) {
|
|
17354
|
+
const sortedContainers = [...survey.containers].sort((a, b) => {
|
|
17355
|
+
const aWorld = isWorldContainer(a);
|
|
17356
|
+
const bWorld = isWorldContainer(b);
|
|
17357
|
+
if (aWorld && !bWorld) return -1;
|
|
17358
|
+
if (!aWorld && bWorld) return 1;
|
|
17359
|
+
return 0;
|
|
17360
|
+
});
|
|
17361
|
+
for (const name of sortedContainers) {
|
|
17362
|
+
const r = exec("docker", ["rm", "-f", name]);
|
|
17363
|
+
if (r.exitCode === 0) removed.push(`container:${name}`);
|
|
17364
|
+
else errors.push(`container:${name}: ${r.stderr.trim()}`);
|
|
17365
|
+
}
|
|
17366
|
+
} else {
|
|
17367
|
+
for (const c of survey.containers) skipped.push(`container:${c}`);
|
|
17368
|
+
}
|
|
17369
|
+
if (!opts.keepImages) {
|
|
17370
|
+
for (const ref of survey.images) {
|
|
17371
|
+
const r = exec("docker", ["rmi", "-f", ref]);
|
|
17372
|
+
if (r.exitCode === 0) removed.push(`image:${ref}`);
|
|
17373
|
+
else errors.push(`image:${ref}: ${r.stderr.trim()}`);
|
|
17374
|
+
}
|
|
17375
|
+
} else {
|
|
17376
|
+
for (const i of survey.images) skipped.push(`image:${i}`);
|
|
17377
|
+
}
|
|
17378
|
+
if (!opts.keepVolumes && !opts.keepVault) {
|
|
17379
|
+
for (const v of survey.volumes) {
|
|
17380
|
+
const r = exec("docker", ["volume", "rm", "-f", v]);
|
|
17381
|
+
if (r.exitCode === 0) removed.push(`volume:${v}`);
|
|
17382
|
+
else errors.push(`volume:${v}: ${r.stderr.trim()}`);
|
|
17383
|
+
}
|
|
17384
|
+
} else if (opts.keepVault) {
|
|
17385
|
+
for (const v of survey.volumes) {
|
|
17386
|
+
if (v === "olam-auth-data" || v === "olam-mcp-auth-data") {
|
|
17387
|
+
skipped.push(`volume:${v} (--keep-vault)`);
|
|
17388
|
+
continue;
|
|
17389
|
+
}
|
|
17390
|
+
const r = exec("docker", ["volume", "rm", "-f", v]);
|
|
17391
|
+
if (r.exitCode === 0) removed.push(`volume:${v}`);
|
|
17392
|
+
else errors.push(`volume:${v}: ${r.stderr.trim()}`);
|
|
17393
|
+
}
|
|
17394
|
+
} else {
|
|
17395
|
+
for (const v of survey.volumes) skipped.push(`volume:${v}`);
|
|
17396
|
+
}
|
|
17397
|
+
if (!opts.keepNetworks) {
|
|
17398
|
+
for (const n of survey.networks) {
|
|
17399
|
+
const r = exec("docker", ["network", "rm", n]);
|
|
17400
|
+
if (r.exitCode === 0) removed.push(`network:${n}`);
|
|
17401
|
+
else errors.push(`network:${n}: ${r.stderr.trim()}`);
|
|
17402
|
+
}
|
|
17403
|
+
} else {
|
|
17404
|
+
for (const n of survey.networks) skipped.push(`network:${n}`);
|
|
17405
|
+
}
|
|
17406
|
+
if (fs30.existsSync(home)) {
|
|
17407
|
+
if (opts.keepVault) {
|
|
17408
|
+
for (const entry of fs30.readdirSync(home, { withFileTypes: true })) {
|
|
17409
|
+
if (entry.name === "auth-data") {
|
|
17410
|
+
skipped.push(`fs:~/.olam/auth-data (--keep-vault)`);
|
|
17411
|
+
continue;
|
|
17412
|
+
}
|
|
17413
|
+
const target = path32.join(home, entry.name);
|
|
17414
|
+
try {
|
|
17415
|
+
fs30.rmSync(target, { recursive: true, force: true });
|
|
17416
|
+
removed.push(`fs:${target}`);
|
|
17417
|
+
} catch (err) {
|
|
17418
|
+
errors.push(`fs:${target}: ${err.message}`);
|
|
17419
|
+
}
|
|
17420
|
+
}
|
|
17421
|
+
} else {
|
|
17422
|
+
try {
|
|
17423
|
+
fs30.rmSync(home, { recursive: true, force: true });
|
|
17424
|
+
removed.push(`fs:${home}`);
|
|
17425
|
+
} catch (err) {
|
|
17426
|
+
errors.push(`fs:${home}: ${err.message}`);
|
|
17427
|
+
}
|
|
17428
|
+
}
|
|
17429
|
+
}
|
|
17430
|
+
if (!opts.keepNpm && survey.npmInstalled) {
|
|
17431
|
+
const r = exec("npm", ["uninstall", "-g", NPM_PACKAGE]);
|
|
17432
|
+
if (r.exitCode === 0) removed.push(`npm:${NPM_PACKAGE}`);
|
|
17433
|
+
else errors.push(`npm:${NPM_PACKAGE}: ${r.stderr.trim()}`);
|
|
17434
|
+
} else if (opts.keepNpm) {
|
|
17435
|
+
skipped.push(`npm:${NPM_PACKAGE}`);
|
|
17436
|
+
}
|
|
17437
|
+
return { removed, skipped, errors };
|
|
17438
|
+
}
|
|
17439
|
+
function isWorldContainer(name) {
|
|
17440
|
+
const stack = /* @__PURE__ */ new Set(["olam-host-cp", "olam-auth", "olam-mcp-auth", "olam-docker-socket-proxy"]);
|
|
17441
|
+
return !stack.has(name);
|
|
17442
|
+
}
|
|
17443
|
+
async function readConfirmation() {
|
|
17444
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
17445
|
+
const answer = await rl.question('Type "implode" to proceed: ');
|
|
17446
|
+
rl.close();
|
|
17447
|
+
return answer.trim();
|
|
17448
|
+
}
|
|
17449
|
+
function registerImplode(program2) {
|
|
17450
|
+
program2.command("implode").description(
|
|
17451
|
+
"Destroy ALL local olam install + configs (containers, images, volumes, ~/.olam/, npm package). Default is dry-run."
|
|
17452
|
+
).option("-y, --yes", "Actually destroy (default is dry-run)", false).option(
|
|
17453
|
+
"--include-dirty",
|
|
17454
|
+
"Also destroy worlds with uncommitted/unpushed work",
|
|
17455
|
+
false
|
|
17456
|
+
).option("--keep-worlds", "Skip world container destruction", false).option("--keep-images", "Skip docker image removal", false).option("--keep-vault", "Preserve auth-service credentials (~/.olam/auth-data + olam-*-data volumes)", false).option("--keep-npm", "Skip global npm package uninstall", false).option("--keep-volumes", "Skip docker volume removal", false).option("--keep-networks", "Skip docker network removal", false).option("--json", "Emit machine-readable JSON survey", false).action(async (raw) => {
|
|
17457
|
+
const opts = {
|
|
17458
|
+
yes: raw.yes === true,
|
|
17459
|
+
includeDirty: raw.includeDirty === true,
|
|
17460
|
+
keepWorlds: raw.keepWorlds === true,
|
|
17461
|
+
keepImages: raw.keepImages === true,
|
|
17462
|
+
keepVault: raw.keepVault === true,
|
|
17463
|
+
keepNpm: raw.keepNpm === true,
|
|
17464
|
+
keepVolumes: raw.keepVolumes === true,
|
|
17465
|
+
keepNetworks: raw.keepNetworks === true,
|
|
17466
|
+
json: raw.json === true
|
|
17467
|
+
};
|
|
17468
|
+
const exitCode = await runImplode(opts);
|
|
17469
|
+
process.exitCode = exitCode;
|
|
17470
|
+
});
|
|
17471
|
+
}
|
|
17472
|
+
async function runImplode(opts) {
|
|
17473
|
+
const survey = surveyOlam({ exec: opts.exec, olamHome: opts.olamHome });
|
|
17474
|
+
if (opts.json && !opts.yes) {
|
|
17475
|
+
process.stdout.write(renderSurvey(survey, opts) + "\n");
|
|
17476
|
+
return 0;
|
|
17477
|
+
}
|
|
17478
|
+
if (!opts.yes) {
|
|
17479
|
+
process.stdout.write(renderSurvey(survey, opts) + "\n");
|
|
17480
|
+
return 0;
|
|
17481
|
+
}
|
|
17482
|
+
const dirty = survey.worlds.filter((w) => w.dirty);
|
|
17483
|
+
if (dirty.length > 0 && !opts.includeDirty && !opts.keepWorlds) {
|
|
17484
|
+
printError(
|
|
17485
|
+
`Refusing to destroy ${dirty.length} world(s) with uncommitted/unpushed work. Pass --include-dirty to override or --keep-worlds to skip world destruction.`
|
|
17486
|
+
);
|
|
17487
|
+
for (const w of dirty) {
|
|
17488
|
+
process.stderr.write(` - ${w.id} (${w.note})
|
|
17489
|
+
`);
|
|
17490
|
+
}
|
|
17491
|
+
return 2;
|
|
17492
|
+
}
|
|
17493
|
+
process.stdout.write(renderSurvey(survey, opts) + "\n");
|
|
17494
|
+
printWarning("This will permanently destroy the resources listed above.");
|
|
17495
|
+
printInfo("Project files", "~/Projects/* and ~/.claude/ are NOT touched.");
|
|
17496
|
+
const answer = opts.confirmAnswer ?? await readConfirmation();
|
|
17497
|
+
if (answer !== "implode") {
|
|
17498
|
+
printError(`Confirmation failed (got "${answer}", expected "implode"). Aborting.`);
|
|
17499
|
+
return 3;
|
|
17500
|
+
}
|
|
17501
|
+
printHeader("Imploding olam");
|
|
17502
|
+
const result = await executeImplode(survey, opts);
|
|
17503
|
+
for (const r of result.removed) printSuccess(`removed ${r}`);
|
|
17504
|
+
for (const s of result.skipped) printInfo("skipped", s);
|
|
17505
|
+
for (const e of result.errors) printError(e);
|
|
17506
|
+
printHeader("Implode complete");
|
|
17507
|
+
printInfo("Removed", String(result.removed.length));
|
|
17508
|
+
printInfo("Skipped", String(result.skipped.length));
|
|
17509
|
+
printInfo("Errors", String(result.errors.length));
|
|
17510
|
+
process.stdout.write("\n");
|
|
17511
|
+
process.stdout.write(`To reinstall a fresh copy:
|
|
17512
|
+
`);
|
|
17513
|
+
process.stdout.write(` ${pc14.cyan(`npm install -g ${NPM_PACKAGE}`)}
|
|
17514
|
+
`);
|
|
17515
|
+
process.stdout.write(` ${pc14.cyan("olam init")}
|
|
17516
|
+
`);
|
|
17517
|
+
process.stdout.write(` ${pc14.cyan("olam auth login")}
|
|
17518
|
+
`);
|
|
17519
|
+
return result.errors.length > 0 ? 1 : 0;
|
|
17520
|
+
}
|
|
17521
|
+
|
|
17152
17522
|
// src/commands/enter.ts
|
|
17153
17523
|
init_context();
|
|
17154
17524
|
init_output();
|
|
17155
17525
|
import { execSync as execSync8 } from "node:child_process";
|
|
17156
|
-
import
|
|
17526
|
+
import pc15 from "picocolors";
|
|
17157
17527
|
var SAFE_IDENT3 = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
17158
17528
|
function buildStartClaudeCommands(containerName, sessionName, task) {
|
|
17159
17529
|
if (!SAFE_IDENT3.test(containerName)) {
|
|
@@ -17260,7 +17630,7 @@ function registerEnter(program2) {
|
|
|
17260
17630
|
}
|
|
17261
17631
|
console.log("Run these commands in order to enter the world:\n");
|
|
17262
17632
|
for (const step of steps) {
|
|
17263
|
-
console.log(` ${
|
|
17633
|
+
console.log(` ${pc15.dim(`# ${step.description}`)}`);
|
|
17264
17634
|
if (step.stdin !== void 0) {
|
|
17265
17635
|
const escaped = step.stdin.replace(/'/g, "'\\''");
|
|
17266
17636
|
console.log(` printf '%s' '${escaped}' | ${step.command}`);
|
|
@@ -17294,11 +17664,11 @@ function registerEnter(program2) {
|
|
|
17294
17664
|
return;
|
|
17295
17665
|
}
|
|
17296
17666
|
console.log("Run this command to enter the world:\n");
|
|
17297
|
-
console.log(` ${
|
|
17667
|
+
console.log(` ${pc15.bold(result.command)}`);
|
|
17298
17668
|
const containerName = `olam-${worldId}-devbox`;
|
|
17299
17669
|
console.log(
|
|
17300
17670
|
`
|
|
17301
|
-
${
|
|
17671
|
+
${pc15.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t olam-dispatch -r`)}`
|
|
17302
17672
|
);
|
|
17303
17673
|
});
|
|
17304
17674
|
}
|
|
@@ -17308,7 +17678,7 @@ init_context();
|
|
|
17308
17678
|
init_output();
|
|
17309
17679
|
init_exit_codes();
|
|
17310
17680
|
init_world_paths();
|
|
17311
|
-
import * as
|
|
17681
|
+
import * as fs31 from "node:fs";
|
|
17312
17682
|
import "node:path";
|
|
17313
17683
|
import ora6 from "ora";
|
|
17314
17684
|
function registerCrystallize(program2, options = {}) {
|
|
@@ -17340,7 +17710,7 @@ function registerCrystallize(program2, options = {}) {
|
|
|
17340
17710
|
return;
|
|
17341
17711
|
}
|
|
17342
17712
|
const thoughtDbPath = getWorldDbPath(world.workspacePath);
|
|
17343
|
-
if (!
|
|
17713
|
+
if (!fs31.existsSync(thoughtDbPath)) {
|
|
17344
17714
|
printError(`No thoughts captured yet for "${worldId}". Run a dispatch first.`);
|
|
17345
17715
|
process.exitCode = EXIT_GENERIC_ERROR;
|
|
17346
17716
|
return;
|
|
@@ -17410,7 +17780,7 @@ function registerCrystallize(program2, options = {}) {
|
|
|
17410
17780
|
|
|
17411
17781
|
// src/commands/pr.ts
|
|
17412
17782
|
init_registry();
|
|
17413
|
-
import
|
|
17783
|
+
import pc16 from "picocolors";
|
|
17414
17784
|
|
|
17415
17785
|
// ../core/dist/pr-gate/client.js
|
|
17416
17786
|
var HOST_CONTROL_PLANE_BASE2 = 19080;
|
|
@@ -17491,26 +17861,26 @@ async function findGate(id) {
|
|
|
17491
17861
|
return null;
|
|
17492
17862
|
}
|
|
17493
17863
|
function formatStateBadge(state) {
|
|
17494
|
-
if (state === "approve") return
|
|
17495
|
-
if (state === "block") return
|
|
17496
|
-
if (state === "denied") return
|
|
17497
|
-
return
|
|
17864
|
+
if (state === "approve") return pc16.green("approve");
|
|
17865
|
+
if (state === "block") return pc16.red("block");
|
|
17866
|
+
if (state === "denied") return pc16.gray("denied");
|
|
17867
|
+
return pc16.yellow("pending");
|
|
17498
17868
|
}
|
|
17499
17869
|
function registerPr(program2) {
|
|
17500
17870
|
const pr = program2.command("pr").description("Review and decide PR-gate requests from running worlds");
|
|
17501
17871
|
pr.command("list").description("List all PR-gate requests across every running world").action(async () => {
|
|
17502
17872
|
const all = await fanoutList();
|
|
17503
17873
|
if (all.length === 0) {
|
|
17504
|
-
console.log(
|
|
17874
|
+
console.log(pc16.dim("No gates open."));
|
|
17505
17875
|
return;
|
|
17506
17876
|
}
|
|
17507
17877
|
printHeader(`${all.length} gate(s)`);
|
|
17508
17878
|
for (const { world, gate } of all) {
|
|
17509
17879
|
const badge = formatStateBadge(gate.state);
|
|
17510
17880
|
console.log(
|
|
17511
|
-
` ${
|
|
17881
|
+
` ${pc16.bold(gate.id.slice(0, 8))} ${badge.padEnd(20)} ${pc16.dim(world.name)} ${pc16.dim(gate.branch)}`
|
|
17512
17882
|
);
|
|
17513
|
-
console.log(` ${
|
|
17883
|
+
console.log(` ${pc16.dim(gate.command.slice(0, 100))}`);
|
|
17514
17884
|
}
|
|
17515
17885
|
});
|
|
17516
17886
|
pr.command("show").description("Show full gate detail (diff, command, commits)").argument("<id>", "Gate id (prefix match ok)").action(async (id) => {
|
|
@@ -17533,9 +17903,9 @@ function registerPr(program2) {
|
|
|
17533
17903
|
if (gate.reason) printInfo("Reason", gate.reason);
|
|
17534
17904
|
}
|
|
17535
17905
|
printHeader("Commits");
|
|
17536
|
-
console.log(gate.commitLog ||
|
|
17906
|
+
console.log(gate.commitLog || pc16.dim(" (empty)"));
|
|
17537
17907
|
printHeader("Diff stat");
|
|
17538
|
-
console.log(gate.diffStat ||
|
|
17908
|
+
console.log(gate.diffStat || pc16.dim(" (empty)"));
|
|
17539
17909
|
});
|
|
17540
17910
|
function decideCommand(verb, decision) {
|
|
17541
17911
|
pr.command(verb).description(`${verb[0].toUpperCase()}${verb.slice(1)} a pending gate`).argument("<id>", "Gate id").option("--reason <reason>", "Short free-text reason").option("--by <name>", "Deciding identity (defaults to $USER)", process.env["USER"] ?? "human").action(async (id, opts) => {
|
|
@@ -17660,7 +18030,7 @@ function registerLanes(program2) {
|
|
|
17660
18030
|
// src/commands/policy-check.ts
|
|
17661
18031
|
init_loader2();
|
|
17662
18032
|
import { execSync as execSync9 } from "node:child_process";
|
|
17663
|
-
import
|
|
18033
|
+
import pc17 from "picocolors";
|
|
17664
18034
|
|
|
17665
18035
|
// ../../node_modules/balanced-match/dist/esm/index.js
|
|
17666
18036
|
var balanced = (a, b, str) => {
|
|
@@ -18714,11 +19084,11 @@ var qmarksTestNoExtDot = ([$0]) => {
|
|
|
18714
19084
|
return (f) => f.length === len && f !== "." && f !== "..";
|
|
18715
19085
|
};
|
|
18716
19086
|
var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
|
|
18717
|
-
var
|
|
19087
|
+
var path34 = {
|
|
18718
19088
|
win32: { sep: "\\" },
|
|
18719
19089
|
posix: { sep: "/" }
|
|
18720
19090
|
};
|
|
18721
|
-
var sep = defaultPlatform === "win32" ?
|
|
19091
|
+
var sep = defaultPlatform === "win32" ? path34.win32.sep : path34.posix.sep;
|
|
18722
19092
|
minimatch.sep = sep;
|
|
18723
19093
|
var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
|
|
18724
19094
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
@@ -19520,7 +19890,7 @@ function registerPolicyCheck(program2) {
|
|
|
19520
19890
|
const workspaceRoot = opts.workspace ?? process.cwd();
|
|
19521
19891
|
const policies = loadPolicies(workspaceRoot);
|
|
19522
19892
|
if (policies.length === 0) {
|
|
19523
|
-
console.log(
|
|
19893
|
+
console.log(pc17.dim("policy-check: no policies found in .olam/policies/ \u2014 nothing to enforce"));
|
|
19524
19894
|
return;
|
|
19525
19895
|
}
|
|
19526
19896
|
const diff = getDiff(opts.base, workspaceRoot);
|
|
@@ -19529,11 +19899,11 @@ function registerPolicyCheck(program2) {
|
|
|
19529
19899
|
for (const result of results) {
|
|
19530
19900
|
if (result.passed) continue;
|
|
19531
19901
|
if (result.severity === "error") {
|
|
19532
|
-
console.error(`${
|
|
19902
|
+
console.error(`${pc17.red("policy error")} [${result.policyId}]`);
|
|
19533
19903
|
console.error(result.message);
|
|
19534
19904
|
hasErrorFailure = true;
|
|
19535
19905
|
} else {
|
|
19536
|
-
console.warn(`${
|
|
19906
|
+
console.warn(`${pc17.yellow("policy warn")} [${result.policyId}]`);
|
|
19537
19907
|
console.warn(result.message);
|
|
19538
19908
|
}
|
|
19539
19909
|
}
|
|
@@ -19544,7 +19914,7 @@ function registerPolicyCheck(program2) {
|
|
|
19544
19914
|
}
|
|
19545
19915
|
|
|
19546
19916
|
// src/commands/worldspec/compile.ts
|
|
19547
|
-
import { existsSync as
|
|
19917
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync18, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "node:fs";
|
|
19548
19918
|
import { resolve as resolvePath } from "node:path";
|
|
19549
19919
|
import YAML5 from "yaml";
|
|
19550
19920
|
|
|
@@ -19827,11 +20197,11 @@ function zodIssueToError(issue, doc, lineCounter) {
|
|
|
19827
20197
|
suggestion: deriveSuggestion(issue)
|
|
19828
20198
|
};
|
|
19829
20199
|
}
|
|
19830
|
-
function formatJsonPath(
|
|
19831
|
-
if (
|
|
20200
|
+
function formatJsonPath(path49) {
|
|
20201
|
+
if (path49.length === 0)
|
|
19832
20202
|
return "<root>";
|
|
19833
20203
|
let out = "";
|
|
19834
|
-
for (const seg of
|
|
20204
|
+
for (const seg of path49) {
|
|
19835
20205
|
if (typeof seg === "number") {
|
|
19836
20206
|
out += `[${seg}]`;
|
|
19837
20207
|
} else {
|
|
@@ -19840,11 +20210,11 @@ function formatJsonPath(path48) {
|
|
|
19840
20210
|
}
|
|
19841
20211
|
return out;
|
|
19842
20212
|
}
|
|
19843
|
-
function resolveYamlLocation(
|
|
20213
|
+
function resolveYamlLocation(path49, doc, lineCounter) {
|
|
19844
20214
|
let bestLine = 0;
|
|
19845
20215
|
let bestColumn = 0;
|
|
19846
|
-
for (let depth =
|
|
19847
|
-
const segment =
|
|
20216
|
+
for (let depth = path49.length; depth >= 0; depth -= 1) {
|
|
20217
|
+
const segment = path49.slice(0, depth);
|
|
19848
20218
|
try {
|
|
19849
20219
|
const node = doc.getIn(segment, true);
|
|
19850
20220
|
if (node && typeof node === "object" && "range" in node) {
|
|
@@ -20062,11 +20432,11 @@ function topoSort(nodes) {
|
|
|
20062
20432
|
}
|
|
20063
20433
|
function traceCycle(start, byId) {
|
|
20064
20434
|
const seen = /* @__PURE__ */ new Set();
|
|
20065
|
-
const
|
|
20435
|
+
const path49 = [];
|
|
20066
20436
|
let current = start;
|
|
20067
20437
|
while (current && !seen.has(current)) {
|
|
20068
20438
|
seen.add(current);
|
|
20069
|
-
|
|
20439
|
+
path49.push(current);
|
|
20070
20440
|
const node = byId.get(current);
|
|
20071
20441
|
const next = node?.dependsOn[0];
|
|
20072
20442
|
if (next === void 0)
|
|
@@ -20074,10 +20444,10 @@ function traceCycle(start, byId) {
|
|
|
20074
20444
|
current = next;
|
|
20075
20445
|
}
|
|
20076
20446
|
if (current && seen.has(current)) {
|
|
20077
|
-
const idx =
|
|
20078
|
-
return [...
|
|
20447
|
+
const idx = path49.indexOf(current);
|
|
20448
|
+
return [...path49.slice(idx), current];
|
|
20079
20449
|
}
|
|
20080
|
-
return
|
|
20450
|
+
return path49;
|
|
20081
20451
|
}
|
|
20082
20452
|
|
|
20083
20453
|
// ../core/dist/executor/types.js
|
|
@@ -20301,11 +20671,11 @@ async function resolveDigests(lockfile, resolver) {
|
|
|
20301
20671
|
}
|
|
20302
20672
|
|
|
20303
20673
|
// ../core/dist/worldspec/image-digest.js
|
|
20304
|
-
import { execFileSync as
|
|
20674
|
+
import { execFileSync as execFileSync8 } from "node:child_process";
|
|
20305
20675
|
var DOCKER_SUBPROCESS_TIMEOUT_MS = 3e4;
|
|
20306
20676
|
var dockerDigestResolver = async (image, source) => {
|
|
20307
20677
|
if (source === "local") {
|
|
20308
|
-
const out =
|
|
20678
|
+
const out = execFileSync8("docker", ["inspect", image, "--format", "{{.Id}}"], {
|
|
20309
20679
|
encoding: "utf8",
|
|
20310
20680
|
stdio: ["ignore", "pipe", "pipe"],
|
|
20311
20681
|
timeout: DOCKER_SUBPROCESS_TIMEOUT_MS,
|
|
@@ -20316,7 +20686,7 @@ var dockerDigestResolver = async (image, source) => {
|
|
|
20316
20686
|
}
|
|
20317
20687
|
return out;
|
|
20318
20688
|
}
|
|
20319
|
-
const raw =
|
|
20689
|
+
const raw = execFileSync8("docker", ["buildx", "imagetools", "inspect", image], {
|
|
20320
20690
|
encoding: "utf8",
|
|
20321
20691
|
stdio: ["ignore", "pipe", "pipe"],
|
|
20322
20692
|
timeout: DOCKER_SUBPROCESS_TIMEOUT_MS,
|
|
@@ -20347,7 +20717,7 @@ function registerWorldspecCompile(parent) {
|
|
|
20347
20717
|
const sourcePolicies = [];
|
|
20348
20718
|
for (const p of paths) {
|
|
20349
20719
|
const abs = resolvePath(process.cwd(), p);
|
|
20350
|
-
if (!
|
|
20720
|
+
if (!existsSync32(abs)) {
|
|
20351
20721
|
printError(`worldspec not found at ${abs}`);
|
|
20352
20722
|
process.exit(EXIT_WORLDSPEC_FILE_NOT_FOUND);
|
|
20353
20723
|
}
|
|
@@ -20438,7 +20808,7 @@ function getPkgVersion() {
|
|
|
20438
20808
|
// src/commands/worldspec/init.ts
|
|
20439
20809
|
init_exit_codes();
|
|
20440
20810
|
init_output();
|
|
20441
|
-
import { existsSync as
|
|
20811
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync19, readFileSync as readFileSync22, writeFileSync as writeFileSync15 } from "node:fs";
|
|
20442
20812
|
import { execSync as execSync10 } from "node:child_process";
|
|
20443
20813
|
import { basename as basename3, resolve as resolvePath2 } from "node:path";
|
|
20444
20814
|
function registerWorldspecInit(parent) {
|
|
@@ -20456,7 +20826,7 @@ function registerWorldspecInit(parent) {
|
|
|
20456
20826
|
const cwd = process.cwd();
|
|
20457
20827
|
const targetDir = resolvePath2(cwd, ".olam/worldspecs");
|
|
20458
20828
|
const targetFile = resolvePath2(targetDir, "default.yaml");
|
|
20459
|
-
if (
|
|
20829
|
+
if (existsSync33(targetFile) && !opts.force) {
|
|
20460
20830
|
printError(
|
|
20461
20831
|
`${targetFile} already exists; pass --force to overwrite`
|
|
20462
20832
|
);
|
|
@@ -20490,12 +20860,12 @@ function registerWorldspecInit(parent) {
|
|
|
20490
20860
|
});
|
|
20491
20861
|
}
|
|
20492
20862
|
function detectProjectShape(root, useAdbYaml) {
|
|
20493
|
-
const hasGemfile =
|
|
20494
|
-
const hasNodePackageJson =
|
|
20495
|
-
const hasAdbYaml =
|
|
20863
|
+
const hasGemfile = existsSync33(resolvePath2(root, "Gemfile"));
|
|
20864
|
+
const hasNodePackageJson = existsSync33(resolvePath2(root, "package.json"));
|
|
20865
|
+
const hasAdbYaml = existsSync33(resolvePath2(root, ".adb.yaml"));
|
|
20496
20866
|
let rubyVersion = null;
|
|
20497
20867
|
const rubyVersionPath = resolvePath2(root, ".ruby-version");
|
|
20498
|
-
if (
|
|
20868
|
+
if (existsSync33(rubyVersionPath)) {
|
|
20499
20869
|
try {
|
|
20500
20870
|
const raw = readFileSync22(rubyVersionPath, "utf8").trim();
|
|
20501
20871
|
const match2 = raw.match(/(\d+\.\d+\.\d+)/);
|
|
@@ -21900,7 +22270,7 @@ function registerWorldspecSchema(parent) {
|
|
|
21900
22270
|
}
|
|
21901
22271
|
|
|
21902
22272
|
// src/commands/worldspec/validate.ts
|
|
21903
|
-
import { existsSync as
|
|
22273
|
+
import { existsSync as existsSync34, readFileSync as readFileSync23 } from "node:fs";
|
|
21904
22274
|
import { resolve as resolvePath4 } from "node:path";
|
|
21905
22275
|
init_exit_codes();
|
|
21906
22276
|
init_output();
|
|
@@ -21917,7 +22287,7 @@ function registerWorldspecValidate(parent) {
|
|
|
21917
22287
|
"human"
|
|
21918
22288
|
).action(async (pathArg, opts) => {
|
|
21919
22289
|
const absPath = resolvePath4(process.cwd(), pathArg);
|
|
21920
|
-
if (!
|
|
22290
|
+
if (!existsSync34(absPath)) {
|
|
21921
22291
|
printError(`worldspec not found at ${absPath}`);
|
|
21922
22292
|
process.exit(EXIT_WORLDSPEC_FILE_NOT_FOUND);
|
|
21923
22293
|
}
|
|
@@ -21969,23 +22339,23 @@ function registerWorldspec(program2) {
|
|
|
21969
22339
|
// src/commands/upgrade.ts
|
|
21970
22340
|
init_output();
|
|
21971
22341
|
init_host_cp();
|
|
21972
|
-
import * as
|
|
21973
|
-
import * as
|
|
22342
|
+
import * as fs34 from "node:fs";
|
|
22343
|
+
import * as path37 from "node:path";
|
|
21974
22344
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
21975
22345
|
import ora7 from "ora";
|
|
21976
|
-
import
|
|
22346
|
+
import pc18 from "picocolors";
|
|
21977
22347
|
|
|
21978
22348
|
// src/commands/upgrade-lock.ts
|
|
21979
|
-
import * as
|
|
21980
|
-
import * as
|
|
21981
|
-
import * as
|
|
22349
|
+
import * as fs32 from "node:fs";
|
|
22350
|
+
import * as os19 from "node:os";
|
|
22351
|
+
import * as path35 from "node:path";
|
|
21982
22352
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
21983
|
-
var LOCK_FILE_PATH =
|
|
22353
|
+
var LOCK_FILE_PATH = path35.join(os19.homedir(), ".olam", ".upgrade.lock");
|
|
21984
22354
|
var STALE_LOCK_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
21985
22355
|
function readLockFile(lockPath) {
|
|
21986
22356
|
try {
|
|
21987
|
-
if (!
|
|
21988
|
-
const raw =
|
|
22357
|
+
if (!fs32.existsSync(lockPath)) return null;
|
|
22358
|
+
const raw = fs32.readFileSync(lockPath, "utf-8").trim();
|
|
21989
22359
|
if (raw.length === 0) return null;
|
|
21990
22360
|
const parsed = JSON.parse(raw);
|
|
21991
22361
|
if (typeof parsed.pid !== "number" || typeof parsed.startTs !== "number") return null;
|
|
@@ -22030,16 +22400,16 @@ function isStaleLock(content, nowMs = Date.now()) {
|
|
|
22030
22400
|
return false;
|
|
22031
22401
|
}
|
|
22032
22402
|
function acquireLock(lockPath = LOCK_FILE_PATH, nowMs = Date.now()) {
|
|
22033
|
-
const dir =
|
|
22034
|
-
|
|
22403
|
+
const dir = path35.dirname(lockPath);
|
|
22404
|
+
fs32.mkdirSync(dir, { recursive: true });
|
|
22035
22405
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
22036
22406
|
try {
|
|
22037
|
-
const fd =
|
|
22407
|
+
const fd = fs32.openSync(lockPath, "wx", 420);
|
|
22038
22408
|
try {
|
|
22039
22409
|
const content = { pid: process.pid, startTs: nowMs };
|
|
22040
|
-
|
|
22410
|
+
fs32.writeSync(fd, JSON.stringify(content));
|
|
22041
22411
|
} finally {
|
|
22042
|
-
|
|
22412
|
+
fs32.closeSync(fd);
|
|
22043
22413
|
}
|
|
22044
22414
|
return { acquired: true, lockPath };
|
|
22045
22415
|
} catch (err) {
|
|
@@ -22048,7 +22418,7 @@ function acquireLock(lockPath = LOCK_FILE_PATH, nowMs = Date.now()) {
|
|
|
22048
22418
|
const existing2 = readLockFile(lockPath);
|
|
22049
22419
|
if (isStaleLock(existing2, nowMs)) {
|
|
22050
22420
|
try {
|
|
22051
|
-
|
|
22421
|
+
fs32.unlinkSync(lockPath);
|
|
22052
22422
|
} catch (unlinkErr) {
|
|
22053
22423
|
const ucode = unlinkErr.code;
|
|
22054
22424
|
if (ucode !== "ENOENT") throw unlinkErr;
|
|
@@ -22073,7 +22443,7 @@ function acquireLock(lockPath = LOCK_FILE_PATH, nowMs = Date.now()) {
|
|
|
22073
22443
|
}
|
|
22074
22444
|
function releaseLock(lockPath = LOCK_FILE_PATH) {
|
|
22075
22445
|
try {
|
|
22076
|
-
|
|
22446
|
+
fs32.unlinkSync(lockPath);
|
|
22077
22447
|
} catch (err) {
|
|
22078
22448
|
const code = err.code;
|
|
22079
22449
|
if (code !== "ENOENT") throw err;
|
|
@@ -22091,19 +22461,19 @@ function formatRefusalMessage(result, lockPath = LOCK_FILE_PATH) {
|
|
|
22091
22461
|
}
|
|
22092
22462
|
|
|
22093
22463
|
// src/commands/upgrade-log.ts
|
|
22094
|
-
import * as
|
|
22095
|
-
import * as
|
|
22096
|
-
import * as
|
|
22464
|
+
import * as fs33 from "node:fs";
|
|
22465
|
+
import * as os20 from "node:os";
|
|
22466
|
+
import * as path36 from "node:path";
|
|
22097
22467
|
function getUpgradeLogPath() {
|
|
22098
|
-
const home = process.env["HOME"] ??
|
|
22099
|
-
return
|
|
22468
|
+
const home = process.env["HOME"] ?? os20.homedir();
|
|
22469
|
+
return path36.join(home, ".olam", "upgrade.log");
|
|
22100
22470
|
}
|
|
22101
22471
|
var UPGRADE_LOG_PATH = getUpgradeLogPath();
|
|
22102
22472
|
function appendUpgradeLog(row, logPath = getUpgradeLogPath()) {
|
|
22103
22473
|
try {
|
|
22104
|
-
|
|
22474
|
+
fs33.mkdirSync(path36.dirname(logPath), { recursive: true });
|
|
22105
22475
|
const line = JSON.stringify(row) + "\n";
|
|
22106
|
-
|
|
22476
|
+
fs33.appendFileSync(logPath, line, { mode: 420 });
|
|
22107
22477
|
} catch (err) {
|
|
22108
22478
|
process.stderr.write(
|
|
22109
22479
|
`[upgrade-log] failed to append: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -22112,10 +22482,10 @@ function appendUpgradeLog(row, logPath = getUpgradeLogPath()) {
|
|
|
22112
22482
|
}
|
|
22113
22483
|
}
|
|
22114
22484
|
function readUpgradeLog(limit = 10, logPath = getUpgradeLogPath()) {
|
|
22115
|
-
if (!
|
|
22485
|
+
if (!fs33.existsSync(logPath)) return [];
|
|
22116
22486
|
let raw;
|
|
22117
22487
|
try {
|
|
22118
|
-
raw =
|
|
22488
|
+
raw = fs33.readFileSync(logPath, "utf-8");
|
|
22119
22489
|
} catch (err) {
|
|
22120
22490
|
process.stderr.write(
|
|
22121
22491
|
`[upgrade-log] failed to read: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -22208,12 +22578,12 @@ init_protocol_version();
|
|
|
22208
22578
|
init_install_root();
|
|
22209
22579
|
var AUTH_HEALTH_URL2 = "http://127.0.0.1:9999/health";
|
|
22210
22580
|
function isNodeModulesInSync(cwd) {
|
|
22211
|
-
const lockPath =
|
|
22212
|
-
const markerPath =
|
|
22213
|
-
if (!
|
|
22581
|
+
const lockPath = path37.join(cwd, "package-lock.json");
|
|
22582
|
+
const markerPath = path37.join(cwd, "node_modules", ".package-lock.json");
|
|
22583
|
+
if (!fs34.existsSync(lockPath) || !fs34.existsSync(markerPath)) return false;
|
|
22214
22584
|
try {
|
|
22215
|
-
const lockStat =
|
|
22216
|
-
const markerStat =
|
|
22585
|
+
const lockStat = fs34.statSync(lockPath);
|
|
22586
|
+
const markerStat = fs34.statSync(markerPath);
|
|
22217
22587
|
return markerStat.mtimeMs >= lockStat.mtimeMs;
|
|
22218
22588
|
} catch {
|
|
22219
22589
|
return false;
|
|
@@ -22229,8 +22599,8 @@ function shouldSkipInstall(opts, cwd) {
|
|
|
22229
22599
|
return { skip: false };
|
|
22230
22600
|
}
|
|
22231
22601
|
function validateRepoRoot(cwd) {
|
|
22232
|
-
const marker =
|
|
22233
|
-
if (!
|
|
22602
|
+
const marker = path37.join(cwd, "packages/host-cp/compose.yaml");
|
|
22603
|
+
if (!fs34.existsSync(marker)) {
|
|
22234
22604
|
return {
|
|
22235
22605
|
ok: false,
|
|
22236
22606
|
error: `Not an olam repo root (expected ${marker}).
|
|
@@ -22262,7 +22632,7 @@ function extractBundleHash(indexHtml) {
|
|
|
22262
22632
|
}
|
|
22263
22633
|
function runStep2(label, cmd, args, opts = {}) {
|
|
22264
22634
|
const start = Date.now();
|
|
22265
|
-
process.stdout.write(` ${
|
|
22635
|
+
process.stdout.write(` ${pc18.dim(label.padEnd(34))}`);
|
|
22266
22636
|
const result = spawnSync11(cmd, [...args], {
|
|
22267
22637
|
encoding: "utf-8",
|
|
22268
22638
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -22272,7 +22642,7 @@ function runStep2(label, cmd, args, opts = {}) {
|
|
|
22272
22642
|
const durationMs = Date.now() - start;
|
|
22273
22643
|
const ok = result.status === 0 && result.error === void 0;
|
|
22274
22644
|
const dur = `${(durationMs / 1e3).toFixed(1)}s`;
|
|
22275
|
-
process.stdout.write(`${ok ?
|
|
22645
|
+
process.stdout.write(`${ok ? pc18.green("\u2713") : pc18.red("\u2717")} ${dur}
|
|
22276
22646
|
`);
|
|
22277
22647
|
return {
|
|
22278
22648
|
ok,
|
|
@@ -22484,8 +22854,8 @@ function performRollbackSwap(plan) {
|
|
|
22484
22854
|
}
|
|
22485
22855
|
async function confirm2(message) {
|
|
22486
22856
|
if (!process.stdin.isTTY) return true;
|
|
22487
|
-
const { createInterface:
|
|
22488
|
-
const rl =
|
|
22857
|
+
const { createInterface: createInterface5 } = await import("node:readline");
|
|
22858
|
+
const rl = createInterface5({ input: process.stdin, output: process.stdout });
|
|
22489
22859
|
return new Promise((resolve10) => {
|
|
22490
22860
|
rl.question(`${message} [y/N] `, (answer) => {
|
|
22491
22861
|
rl.close();
|
|
@@ -22586,9 +22956,9 @@ async function recreateAuthService() {
|
|
|
22586
22956
|
}
|
|
22587
22957
|
}
|
|
22588
22958
|
function readBundleHash(cwd) {
|
|
22589
|
-
const indexPath =
|
|
22590
|
-
if (!
|
|
22591
|
-
return extractBundleHash(
|
|
22959
|
+
const indexPath = path37.join(cwd, "packages/control-plane/public/index.html");
|
|
22960
|
+
if (!fs34.existsSync(indexPath)) return null;
|
|
22961
|
+
return extractBundleHash(fs34.readFileSync(indexPath, "utf-8"));
|
|
22592
22962
|
}
|
|
22593
22963
|
async function runUpgradePullByDigest(deps = {}) {
|
|
22594
22964
|
const docker2 = deps.docker ?? realDocker;
|
|
@@ -22600,7 +22970,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
22600
22970
|
if (info.exitCode !== 0) {
|
|
22601
22971
|
infoSpinner.fail("docker daemon not reachable");
|
|
22602
22972
|
process.stderr.write(
|
|
22603
|
-
`${
|
|
22973
|
+
`${pc18.red("error")} docker info exited with ${info.exitCode}.
|
|
22604
22974
|
Ensure Docker Desktop / Colima / Rancher is running, then retry.
|
|
22605
22975
|
`
|
|
22606
22976
|
);
|
|
@@ -22635,7 +23005,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
22635
23005
|
pullSpinner.fail(`Pull failed for ${failed.map((r) => r.name).join(", ")}`);
|
|
22636
23006
|
for (const f of failed) {
|
|
22637
23007
|
process.stderr.write(
|
|
22638
|
-
` ${
|
|
23008
|
+
` ${pc18.red(f.name)} (${f.ref}):
|
|
22639
23009
|
exit=${f.result.exitCode}
|
|
22640
23010
|
stderr: ${f.result.stderr.split("\n")[0] ?? "(empty)"}
|
|
22641
23011
|
`
|
|
@@ -22656,7 +23026,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
22656
23026
|
if (inspect.exitCode !== 0) {
|
|
22657
23027
|
handshakeSpinner.fail(`Could not inspect ${name}`);
|
|
22658
23028
|
process.stderr.write(
|
|
22659
|
-
`${
|
|
23029
|
+
`${pc18.red("error")} docker inspect ${ref} failed: ${inspect.stderr}
|
|
22660
23030
|
`
|
|
22661
23031
|
);
|
|
22662
23032
|
return { exitCode: EXIT_GENERIC_ERROR, summary: `inspect failed: ${name}` };
|
|
@@ -22668,7 +23038,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
22668
23038
|
const decision = checkProtocolOverlap(versions);
|
|
22669
23039
|
if (!decision.compatible) {
|
|
22670
23040
|
handshakeSpinner.fail(`Protocol mismatch on ${name}`);
|
|
22671
|
-
process.stderr.write(`${
|
|
23041
|
+
process.stderr.write(`${pc18.red("error")} ${decision.remedy}
|
|
22672
23042
|
`);
|
|
22673
23043
|
return {
|
|
22674
23044
|
exitCode: EXIT_PROTOCOL_MISMATCH,
|
|
@@ -22698,7 +23068,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
22698
23068
|
const r = tagger(t.from, t.to);
|
|
22699
23069
|
if (!r.ok) {
|
|
22700
23070
|
tagSpinner.fail(`docker tag failed for ${t.name}`);
|
|
22701
|
-
process.stderr.write(`${
|
|
23071
|
+
process.stderr.write(`${pc18.red("error")} ${r.error ?? "docker tag failed"}
|
|
22702
23072
|
`);
|
|
22703
23073
|
return { exitCode: EXIT_GENERIC_ERROR, summary: `tag failed: ${t.name}` };
|
|
22704
23074
|
}
|
|
@@ -22716,7 +23086,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
22716
23086
|
if (!composeResult.ok) {
|
|
22717
23087
|
composeSpinner.fail("compose recreate failed");
|
|
22718
23088
|
process.stderr.write(
|
|
22719
|
-
`${
|
|
23089
|
+
`${pc18.red("error")} docker compose up --force-recreate host-cp failed:
|
|
22720
23090
|
${composeResult.stderr.split("\n").slice(0, 3).join("\n ")}
|
|
22721
23091
|
`
|
|
22722
23092
|
);
|
|
@@ -22729,7 +23099,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
22729
23099
|
if (!authResult.ok) {
|
|
22730
23100
|
authSpinner.fail("auth-service recreate failed");
|
|
22731
23101
|
process.stderr.write(
|
|
22732
|
-
`${
|
|
23102
|
+
`${pc18.red("error")} ${authResult.error ?? "unknown failure"}
|
|
22733
23103
|
`
|
|
22734
23104
|
);
|
|
22735
23105
|
return { exitCode: EXIT_GENERIC_ERROR, summary: "auth recreate failed" };
|
|
@@ -22742,7 +23112,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
22742
23112
|
if (!mcpResult.ok) {
|
|
22743
23113
|
mcpSpinner.fail("mcp-auth-service recreate failed");
|
|
22744
23114
|
process.stderr.write(
|
|
22745
|
-
`${
|
|
23115
|
+
`${pc18.red("error")} ${mcpResult.error ?? "unknown failure"}
|
|
22746
23116
|
`
|
|
22747
23117
|
);
|
|
22748
23118
|
return { exitCode: EXIT_GENERIC_ERROR, summary: "mcp-auth recreate failed" };
|
|
@@ -22935,11 +23305,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
|
|
|
22935
23305
|
process.once("SIGINT", releaseOnSignal);
|
|
22936
23306
|
process.once("SIGTERM", releaseOnSignal);
|
|
22937
23307
|
try {
|
|
22938
|
-
process.stdout.write(` ${
|
|
23308
|
+
process.stdout.write(` ${pc18.dim("rollback retag (3 ops)".padEnd(34))}`);
|
|
22939
23309
|
const swapStart = Date.now();
|
|
22940
23310
|
const swapResult = performRollbackSwap(PRODUCTION_SWAP_PLAN);
|
|
22941
23311
|
const swapDur = `${((Date.now() - swapStart) / 1e3).toFixed(1)}s`;
|
|
22942
|
-
process.stdout.write(`${swapResult.ok ?
|
|
23312
|
+
process.stdout.write(`${swapResult.ok ? pc18.green("\u2713") : pc18.red("\u2717")} ${swapDur}
|
|
22943
23313
|
`);
|
|
22944
23314
|
if (!swapResult.ok) {
|
|
22945
23315
|
printError(`Rollback retag failed: ${swapResult.summary}`);
|
|
@@ -22949,11 +23319,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
|
|
|
22949
23319
|
printInfo("Rollback", swapResult.summary);
|
|
22950
23320
|
const composeFile = findComposeFile();
|
|
22951
23321
|
const authSecret = readAuthSecret2();
|
|
22952
|
-
process.stdout.write(` ${
|
|
23322
|
+
process.stdout.write(` ${pc18.dim("docker compose recreate host-cp".padEnd(34))}`);
|
|
22953
23323
|
const composeStart = Date.now();
|
|
22954
23324
|
const composeResult = runCompose(["up", "-d", "--force-recreate", "--no-deps", "host-cp"], composeFile, buildComposeEnv(authSecret, captureGhToken()));
|
|
22955
23325
|
const composeDur = `${((Date.now() - composeStart) / 1e3).toFixed(1)}s`;
|
|
22956
|
-
process.stdout.write(`${composeResult.ok ?
|
|
23326
|
+
process.stdout.write(`${composeResult.ok ? pc18.green("\u2713") : pc18.red("\u2717")} ${composeDur}
|
|
22957
23327
|
`);
|
|
22958
23328
|
if (!composeResult.ok) {
|
|
22959
23329
|
printError(
|
|
@@ -22964,10 +23334,10 @@ Canonical tags are at :olam-rollback (good); container restart pending. Manually
|
|
|
22964
23334
|
process.exitCode = 1;
|
|
22965
23335
|
return;
|
|
22966
23336
|
}
|
|
22967
|
-
process.stdout.write(` ${
|
|
23337
|
+
process.stdout.write(` ${pc18.dim("recreate auth-service".padEnd(34))}`);
|
|
22968
23338
|
const authResult = await recreateAuthService();
|
|
22969
23339
|
const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
|
|
22970
|
-
process.stdout.write(`${authResult.ok ?
|
|
23340
|
+
process.stdout.write(`${authResult.ok ? pc18.green("\u2713") : pc18.red("\u2717")} ${authDur}
|
|
22971
23341
|
`);
|
|
22972
23342
|
if (!authResult.ok) {
|
|
22973
23343
|
printError(`Auth-service recreate failed: ${authResult.error ?? "unknown"}`);
|
|
@@ -23088,7 +23458,7 @@ ${buildResult.stderr}`);
|
|
|
23088
23458
|
return;
|
|
23089
23459
|
}
|
|
23090
23460
|
const authSecret = readAuthSecret2();
|
|
23091
|
-
const spaDir =
|
|
23461
|
+
const spaDir = path37.join(cwd, "packages/control-plane/app");
|
|
23092
23462
|
const spaResult = runStep2(
|
|
23093
23463
|
"vite build (SPA)",
|
|
23094
23464
|
"npx",
|
|
@@ -23133,7 +23503,7 @@ ${spaResult.stderr}`);
|
|
|
23133
23503
|
throw err;
|
|
23134
23504
|
}
|
|
23135
23505
|
if (step.tee) {
|
|
23136
|
-
process.stdout.write(` ${
|
|
23506
|
+
process.stdout.write(` ${pc18.dim(step.label.padEnd(34))}
|
|
23137
23507
|
`);
|
|
23138
23508
|
const start = Date.now();
|
|
23139
23509
|
const result = spawnSync11("bash", [scriptPath], {
|
|
@@ -23144,7 +23514,7 @@ ${spaResult.stderr}`);
|
|
|
23144
23514
|
const durationMs = Date.now() - start;
|
|
23145
23515
|
const ok = result.status === 0 && result.error === void 0;
|
|
23146
23516
|
const dur = `${(durationMs / 1e3).toFixed(1)}s`;
|
|
23147
|
-
process.stdout.write(` ${
|
|
23517
|
+
process.stdout.write(` ${pc18.dim(step.label.padEnd(34))}${ok ? pc18.green("\u2713") : pc18.red("\u2717")} ${dur}
|
|
23148
23518
|
`);
|
|
23149
23519
|
timings.push({ label: step.label, durationMs });
|
|
23150
23520
|
if (!ok) {
|
|
@@ -23170,7 +23540,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
|
|
|
23170
23540
|
}
|
|
23171
23541
|
for (const t of timings) logRow.durations_ms[t.label] = t.durationMs;
|
|
23172
23542
|
const smokeStart = Date.now();
|
|
23173
|
-
process.stdout.write(` ${
|
|
23543
|
+
process.stdout.write(` ${pc18.dim("smoke (docker create + inspect)".padEnd(34))}`);
|
|
23174
23544
|
const smokeImages = [
|
|
23175
23545
|
"olam-auth:olam-next",
|
|
23176
23546
|
"olam-devbox:olam-next",
|
|
@@ -23180,7 +23550,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
|
|
|
23180
23550
|
const smokeFailures = smokeResults.filter((r) => !r.ok);
|
|
23181
23551
|
const smokeDurationMs = Date.now() - smokeStart;
|
|
23182
23552
|
const smokeDur = `${(smokeDurationMs / 1e3).toFixed(1)}s`;
|
|
23183
|
-
process.stdout.write(`${smokeFailures.length === 0 ?
|
|
23553
|
+
process.stdout.write(`${smokeFailures.length === 0 ? pc18.green("\u2713") : pc18.red("\u2717")} ${smokeDur}
|
|
23184
23554
|
`);
|
|
23185
23555
|
timings.push({ label: "smoke", durationMs: smokeDurationMs });
|
|
23186
23556
|
if (smokeFailures.length > 0) {
|
|
@@ -23207,12 +23577,12 @@ Recovery options:
|
|
|
23207
23577
|
process.exitCode = 1;
|
|
23208
23578
|
return;
|
|
23209
23579
|
}
|
|
23210
|
-
process.stdout.write(` ${
|
|
23580
|
+
process.stdout.write(` ${pc18.dim("atomic 6-tag swap".padEnd(34))}`);
|
|
23211
23581
|
const swapStart = Date.now();
|
|
23212
23582
|
const swapResult = performAtomicSwap(PRODUCTION_SWAP_PLAN);
|
|
23213
23583
|
const swapDurationMs = Date.now() - swapStart;
|
|
23214
23584
|
const swapDur = `${(swapDurationMs / 1e3).toFixed(1)}s`;
|
|
23215
|
-
process.stdout.write(`${swapResult.ok ?
|
|
23585
|
+
process.stdout.write(`${swapResult.ok ? pc18.green("\u2713") : pc18.red("\u2717")} ${swapDur}
|
|
23216
23586
|
`);
|
|
23217
23587
|
timings.push({ label: "atomic swap", durationMs: swapDurationMs });
|
|
23218
23588
|
if (!swapResult.ok) {
|
|
@@ -23222,7 +23592,7 @@ Recovery options:
|
|
|
23222
23592
|
}
|
|
23223
23593
|
printInfo("Swap", swapResult.summary);
|
|
23224
23594
|
const composeFile = findComposeFile();
|
|
23225
|
-
process.stdout.write(` ${
|
|
23595
|
+
process.stdout.write(` ${pc18.dim("docker compose recreate".padEnd(34))}`);
|
|
23226
23596
|
const composeStart = Date.now();
|
|
23227
23597
|
const composeResult = runCompose(
|
|
23228
23598
|
["up", "-d", "--force-recreate"],
|
|
@@ -23232,7 +23602,7 @@ Recovery options:
|
|
|
23232
23602
|
const composeDurationMs = Date.now() - composeStart;
|
|
23233
23603
|
const composeOk = composeResult.ok;
|
|
23234
23604
|
const composeDur = `${(composeDurationMs / 1e3).toFixed(1)}s`;
|
|
23235
|
-
process.stdout.write(`${composeOk ?
|
|
23605
|
+
process.stdout.write(`${composeOk ? pc18.green("\u2713") : pc18.red("\u2717")} ${composeDur}
|
|
23236
23606
|
`);
|
|
23237
23607
|
timings.push({ label: "container recreate", durationMs: composeDurationMs });
|
|
23238
23608
|
if (!composeOk) {
|
|
@@ -23248,10 +23618,10 @@ Recovery options:
|
|
|
23248
23618
|
process.exitCode = 1;
|
|
23249
23619
|
return;
|
|
23250
23620
|
}
|
|
23251
|
-
process.stdout.write(` ${
|
|
23621
|
+
process.stdout.write(` ${pc18.dim("recreate auth-service".padEnd(34))}`);
|
|
23252
23622
|
const authResult = await recreateAuthService();
|
|
23253
23623
|
const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
|
|
23254
|
-
process.stdout.write(`${authResult.ok ?
|
|
23624
|
+
process.stdout.write(`${authResult.ok ? pc18.green("\u2713") : pc18.red("\u2717")} ${authDur}
|
|
23255
23625
|
`);
|
|
23256
23626
|
timings.push({ label: "auth recreate", durationMs: authResult.durationMs });
|
|
23257
23627
|
if (!authResult.ok) {
|
|
@@ -23266,12 +23636,12 @@ Recovery options:
|
|
|
23266
23636
|
process.exitCode = 1;
|
|
23267
23637
|
return;
|
|
23268
23638
|
}
|
|
23269
|
-
process.stdout.write(` ${
|
|
23639
|
+
process.stdout.write(` ${pc18.dim("waiting for /health".padEnd(34))}`);
|
|
23270
23640
|
const healthStart = Date.now();
|
|
23271
23641
|
const healthy = await waitForHealth(1e4);
|
|
23272
23642
|
const healthDurationMs = Date.now() - healthStart;
|
|
23273
23643
|
const healthDur = `${(healthDurationMs / 1e3).toFixed(1)}s`;
|
|
23274
|
-
process.stdout.write(`${healthy ?
|
|
23644
|
+
process.stdout.write(`${healthy ? pc18.green("\u2713") : pc18.yellow("?")} ${healthDur}
|
|
23275
23645
|
`);
|
|
23276
23646
|
timings.push({ label: "/health", durationMs: healthDurationMs });
|
|
23277
23647
|
if (!healthy) {
|
|
@@ -23279,12 +23649,12 @@ Recovery options:
|
|
|
23279
23649
|
"Host CP started but /health did not respond within 10s.\n \u2022 Check: docker logs olam-host-cp\n \u2022 If the new SHA is broken: `olam upgrade --rollback` restores the prior set in <30s."
|
|
23280
23650
|
);
|
|
23281
23651
|
}
|
|
23282
|
-
process.stdout.write(` ${
|
|
23652
|
+
process.stdout.write(` ${pc18.dim("verify /version/status round-trip".padEnd(34))}`);
|
|
23283
23653
|
const versionStart = Date.now();
|
|
23284
23654
|
const versionMatch = await waitForVersionMatch(_targetSha, 9e4);
|
|
23285
23655
|
const versionDurationMs = Date.now() - versionStart;
|
|
23286
23656
|
const versionDur = `${(versionDurationMs / 1e3).toFixed(1)}s`;
|
|
23287
|
-
process.stdout.write(`${versionMatch.matched ?
|
|
23657
|
+
process.stdout.write(`${versionMatch.matched ? pc18.green("\u2713") : pc18.yellow("?")} ${versionDur}
|
|
23288
23658
|
`);
|
|
23289
23659
|
timings.push({ label: "/version/status round-trip", durationMs: versionDurationMs });
|
|
23290
23660
|
if (!versionMatch.matched) {
|
|
@@ -23358,16 +23728,16 @@ init_host_cp();
|
|
|
23358
23728
|
init_context();
|
|
23359
23729
|
init_output();
|
|
23360
23730
|
import * as http3 from "node:http";
|
|
23361
|
-
import
|
|
23731
|
+
import pc19 from "picocolors";
|
|
23362
23732
|
var HOST_CP_PORT3 = 19e3;
|
|
23363
23733
|
function colorLine(line) {
|
|
23364
|
-
if (/\bERROR\b/.test(line)) return
|
|
23365
|
-
if (/\bWARN\b/.test(line)) return
|
|
23366
|
-
if (/\bINFO\b/.test(line)) return
|
|
23734
|
+
if (/\bERROR\b/.test(line)) return pc19.red(line);
|
|
23735
|
+
if (/\bWARN\b/.test(line)) return pc19.yellow(line);
|
|
23736
|
+
if (/\bINFO\b/.test(line)) return pc19.dim(line);
|
|
23367
23737
|
return line;
|
|
23368
23738
|
}
|
|
23369
23739
|
function formatLine(line, service, showService) {
|
|
23370
|
-
const prefix = showService && service ? `${
|
|
23740
|
+
const prefix = showService && service ? `${pc19.cyan(`[${service}]`)} ` : "";
|
|
23371
23741
|
return prefix + colorLine(line);
|
|
23372
23742
|
}
|
|
23373
23743
|
function parseSseEvent(raw) {
|
|
@@ -23484,7 +23854,7 @@ function registerLogs(program2) {
|
|
|
23484
23854
|
// src/commands/ps.ts
|
|
23485
23855
|
init_context();
|
|
23486
23856
|
init_output();
|
|
23487
|
-
import
|
|
23857
|
+
import pc20 from "picocolors";
|
|
23488
23858
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
23489
23859
|
var SAFE_IDENT4 = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
23490
23860
|
function parseDockerTop(stdout) {
|
|
@@ -23545,18 +23915,18 @@ function printTable2(rows) {
|
|
|
23545
23915
|
const fixedWidth = 5 + 1 + 8 + 1 + 6 + 1 + 6 + 1 + 10 + 1 + 6 + 1;
|
|
23546
23916
|
const cmdWidth = Math.max(20, cols - fixedWidth);
|
|
23547
23917
|
const header = [
|
|
23548
|
-
|
|
23549
|
-
|
|
23550
|
-
|
|
23551
|
-
|
|
23552
|
-
|
|
23553
|
-
|
|
23554
|
-
|
|
23918
|
+
pc20.bold(pc20.dim("PID".padEnd(5))),
|
|
23919
|
+
pc20.bold(pc20.dim("USER".padEnd(8))),
|
|
23920
|
+
pc20.bold(pc20.dim("%CPU".padEnd(6))),
|
|
23921
|
+
pc20.bold(pc20.dim("%MEM".padEnd(6))),
|
|
23922
|
+
pc20.bold(pc20.dim("STARTED".padEnd(10))),
|
|
23923
|
+
pc20.bold(pc20.dim("STATE".padEnd(6))),
|
|
23924
|
+
pc20.bold(pc20.dim("COMMAND"))
|
|
23555
23925
|
].join(" ");
|
|
23556
23926
|
console.log(header);
|
|
23557
23927
|
for (const row of rows) {
|
|
23558
23928
|
const cmd = row.command.length > cmdWidth ? row.command.slice(0, cmdWidth - 1) + "\u2026" : row.command;
|
|
23559
|
-
const stateFn = row.state.startsWith("R") ?
|
|
23929
|
+
const stateFn = row.state.startsWith("R") ? pc20.green : row.state.startsWith("Z") ? pc20.red : pc20.dim;
|
|
23560
23930
|
console.log([
|
|
23561
23931
|
row.pid.padEnd(5),
|
|
23562
23932
|
row.user.slice(0, 8).padEnd(8),
|
|
@@ -23605,7 +23975,7 @@ function registerPs(program2) {
|
|
|
23605
23975
|
printTable2(rows);
|
|
23606
23976
|
if (opts.watch) {
|
|
23607
23977
|
process.stdout.write(`
|
|
23608
|
-
${
|
|
23978
|
+
${pc20.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
|
|
23609
23979
|
`);
|
|
23610
23980
|
}
|
|
23611
23981
|
}
|
|
@@ -23622,20 +23992,20 @@ ${pc19.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
|
|
|
23622
23992
|
|
|
23623
23993
|
// src/commands/keys.ts
|
|
23624
23994
|
init_output();
|
|
23625
|
-
import * as
|
|
23626
|
-
import * as
|
|
23627
|
-
import * as
|
|
23995
|
+
import * as fs35 from "node:fs";
|
|
23996
|
+
import * as os21 from "node:os";
|
|
23997
|
+
import * as path38 from "node:path";
|
|
23628
23998
|
import YAML6 from "yaml";
|
|
23629
23999
|
function olamHome2() {
|
|
23630
|
-
return process.env.OLAM_HOME ??
|
|
24000
|
+
return process.env.OLAM_HOME ?? path38.join(os21.homedir(), ".olam");
|
|
23631
24001
|
}
|
|
23632
24002
|
function keysFilePath() {
|
|
23633
|
-
return
|
|
24003
|
+
return path38.join(olamHome2(), "keys.yaml");
|
|
23634
24004
|
}
|
|
23635
24005
|
function readKeysFile() {
|
|
23636
24006
|
const filePath = keysFilePath();
|
|
23637
|
-
if (!
|
|
23638
|
-
const raw =
|
|
24007
|
+
if (!fs35.existsSync(filePath)) return null;
|
|
24008
|
+
const raw = fs35.readFileSync(filePath, "utf-8").trim();
|
|
23639
24009
|
if (raw.length === 0) return null;
|
|
23640
24010
|
try {
|
|
23641
24011
|
const parsed = YAML6.parse(raw);
|
|
@@ -23651,13 +24021,13 @@ function readKeysFile() {
|
|
|
23651
24021
|
}
|
|
23652
24022
|
function writeKeysFile(keys) {
|
|
23653
24023
|
const dir = olamHome2();
|
|
23654
|
-
if (!
|
|
23655
|
-
|
|
24024
|
+
if (!fs35.existsSync(dir)) {
|
|
24025
|
+
fs35.mkdirSync(dir, { recursive: true });
|
|
23656
24026
|
}
|
|
23657
24027
|
const filePath = keysFilePath();
|
|
23658
24028
|
const content = YAML6.stringify(keys);
|
|
23659
|
-
|
|
23660
|
-
|
|
24029
|
+
fs35.writeFileSync(filePath, content, { encoding: "utf-8", mode: 384 });
|
|
24030
|
+
fs35.chmodSync(filePath, 384);
|
|
23661
24031
|
}
|
|
23662
24032
|
function redact(value) {
|
|
23663
24033
|
if (value.length <= 8) return value + "...";
|
|
@@ -23700,7 +24070,7 @@ function registerKeys(program2) {
|
|
|
23700
24070
|
}
|
|
23701
24071
|
const { [key]: _removed, ...rest } = existing;
|
|
23702
24072
|
if (Object.keys(rest).length === 0) {
|
|
23703
|
-
|
|
24073
|
+
fs35.unlinkSync(keysFilePath());
|
|
23704
24074
|
} else {
|
|
23705
24075
|
writeKeysFile(rest);
|
|
23706
24076
|
}
|
|
@@ -23725,10 +24095,10 @@ function registerKeys(program2) {
|
|
|
23725
24095
|
// src/commands/world-snapshot.ts
|
|
23726
24096
|
init_snapshot();
|
|
23727
24097
|
init_output();
|
|
23728
|
-
import * as
|
|
23729
|
-
import * as
|
|
24098
|
+
import * as fs36 from "node:fs";
|
|
24099
|
+
import * as path39 from "node:path";
|
|
23730
24100
|
import { execSync as execSync11 } from "node:child_process";
|
|
23731
|
-
import
|
|
24101
|
+
import pc21 from "picocolors";
|
|
23732
24102
|
|
|
23733
24103
|
// src/commands/world.ts
|
|
23734
24104
|
function getOrCreateWorldCommand(program2) {
|
|
@@ -23749,16 +24119,16 @@ function emitDeprecationWarning(subcommand) {
|
|
|
23749
24119
|
}
|
|
23750
24120
|
function bumpDeprecationCounter() {
|
|
23751
24121
|
if (process.env[INTERNAL_SENTINEL_ENV] === "1") return;
|
|
23752
|
-
const counterPath =
|
|
24122
|
+
const counterPath = path39.join(snapshotsDir(), ".deprecation-counter");
|
|
23753
24123
|
try {
|
|
23754
|
-
|
|
24124
|
+
fs36.mkdirSync(path39.dirname(counterPath), { recursive: true });
|
|
23755
24125
|
let current = 0;
|
|
23756
|
-
if (
|
|
23757
|
-
const raw =
|
|
24126
|
+
if (fs36.existsSync(counterPath)) {
|
|
24127
|
+
const raw = fs36.readFileSync(counterPath, "utf-8").trim();
|
|
23758
24128
|
const parsed = parseInt(raw, 10);
|
|
23759
24129
|
if (Number.isInteger(parsed) && parsed >= 0) current = parsed;
|
|
23760
24130
|
}
|
|
23761
|
-
|
|
24131
|
+
fs36.writeFileSync(counterPath, String(current + 1), { mode: 384 });
|
|
23762
24132
|
} catch {
|
|
23763
24133
|
}
|
|
23764
24134
|
}
|
|
@@ -23820,7 +24190,7 @@ async function handleCreate2(worldId, kindArg) {
|
|
|
23820
24190
|
const label = r.repo ? `${r.kind}/${r.repo}` : r.kind;
|
|
23821
24191
|
if (r.ok) {
|
|
23822
24192
|
printSuccess(`${label}`);
|
|
23823
|
-
console.log(` ${
|
|
24193
|
+
console.log(` ${pc21.dim(r.tarPath)}`);
|
|
23824
24194
|
} else {
|
|
23825
24195
|
printWarning(`${label}: ${r.msg ?? "skipped"}`);
|
|
23826
24196
|
}
|
|
@@ -23834,17 +24204,17 @@ function resolveKinds(arg) {
|
|
|
23834
24204
|
return [];
|
|
23835
24205
|
}
|
|
23836
24206
|
async function captureGems(worldId, workspacePath, repo) {
|
|
23837
|
-
const repoDir =
|
|
24207
|
+
const repoDir = path39.join(workspacePath, repo);
|
|
23838
24208
|
const fingerprint = computeGemsFingerprint(repoDir);
|
|
23839
24209
|
if (!fingerprint) {
|
|
23840
24210
|
return { ok: false, tarPath: "", msg: "no Gemfile.lock \u2014 layer does not apply" };
|
|
23841
24211
|
}
|
|
23842
24212
|
const tarPath = snapshotTarPath(worldId, "gems", repo, fingerprint);
|
|
23843
|
-
const vendorBundle =
|
|
23844
|
-
if (
|
|
24213
|
+
const vendorBundle = path39.join(repoDir, "vendor", "bundle");
|
|
24214
|
+
if (fs36.existsSync(vendorBundle)) {
|
|
23845
24215
|
try {
|
|
23846
24216
|
packTarball(vendorBundle, tarPath);
|
|
23847
|
-
const stat =
|
|
24217
|
+
const stat = fs36.statSync(tarPath);
|
|
23848
24218
|
const manifest = {
|
|
23849
24219
|
kind: "gems",
|
|
23850
24220
|
worldId,
|
|
@@ -23877,10 +24247,10 @@ async function captureGems(worldId, workspacePath, repo) {
|
|
|
23877
24247
|
`docker exec ${containerName} sh -c 'mkdir -p "$(dirname ${tmpTar})" && tar -czf ${tmpTar}.tmp -C ${bundlePath} . && mv ${tmpTar}.tmp ${tmpTar}'`,
|
|
23878
24248
|
{ stdio: "pipe", timeout: 12e4 }
|
|
23879
24249
|
);
|
|
23880
|
-
|
|
24250
|
+
fs36.mkdirSync(path39.dirname(tarPath), { recursive: true });
|
|
23881
24251
|
execSync11(`docker cp ${containerName}:${tmpTar} "${tarPath}"`, { stdio: "pipe", timeout: 12e4 });
|
|
23882
24252
|
execSync11(`docker exec ${containerName} rm -f ${tmpTar}`, { stdio: "pipe" });
|
|
23883
|
-
const stat =
|
|
24253
|
+
const stat = fs36.statSync(tarPath);
|
|
23884
24254
|
const manifest = {
|
|
23885
24255
|
kind: "gems",
|
|
23886
24256
|
worldId,
|
|
@@ -23897,19 +24267,19 @@ async function captureGems(worldId, workspacePath, repo) {
|
|
|
23897
24267
|
}
|
|
23898
24268
|
}
|
|
23899
24269
|
async function captureNode(worldId, workspacePath, repo) {
|
|
23900
|
-
const repoDir =
|
|
24270
|
+
const repoDir = path39.join(workspacePath, repo);
|
|
23901
24271
|
const fingerprint = computeNodeFingerprint(repoDir);
|
|
23902
24272
|
if (!fingerprint) {
|
|
23903
24273
|
return { ok: false, tarPath: "", msg: "no lockfile \u2014 layer does not apply" };
|
|
23904
24274
|
}
|
|
23905
|
-
const nodeModules =
|
|
23906
|
-
if (!
|
|
24275
|
+
const nodeModules = path39.join(repoDir, "node_modules");
|
|
24276
|
+
if (!fs36.existsSync(nodeModules)) {
|
|
23907
24277
|
return { ok: false, tarPath: "", msg: "node_modules not installed yet" };
|
|
23908
24278
|
}
|
|
23909
24279
|
const tarPath = snapshotTarPath(worldId, "node", repo, fingerprint);
|
|
23910
24280
|
try {
|
|
23911
24281
|
packTarball(nodeModules, tarPath);
|
|
23912
|
-
const stat =
|
|
24282
|
+
const stat = fs36.statSync(tarPath);
|
|
23913
24283
|
const manifest = {
|
|
23914
24284
|
kind: "node",
|
|
23915
24285
|
worldId,
|
|
@@ -23926,7 +24296,7 @@ async function captureNode(worldId, workspacePath, repo) {
|
|
|
23926
24296
|
}
|
|
23927
24297
|
}
|
|
23928
24298
|
async function capturePg(worldId, workspacePath, repoNames) {
|
|
23929
|
-
const repoDirs = repoNames.map((r) =>
|
|
24299
|
+
const repoDirs = repoNames.map((r) => path39.join(workspacePath, r));
|
|
23930
24300
|
const fingerprint = computePgFingerprint(repoDirs);
|
|
23931
24301
|
if (!fingerprint) {
|
|
23932
24302
|
return { ok: false, tarPath: "", msg: "no Gemfile.lock / schema.rb \u2014 layer does not apply" };
|
|
@@ -23941,13 +24311,13 @@ async function capturePg(worldId, workspacePath, repoNames) {
|
|
|
23941
24311
|
}
|
|
23942
24312
|
try {
|
|
23943
24313
|
execSync11(`docker stop ${containerName}`, { stdio: "pipe", timeout: 3e4 });
|
|
23944
|
-
|
|
24314
|
+
fs36.mkdirSync(path39.dirname(tarPath), { recursive: true });
|
|
23945
24315
|
execSync11(
|
|
23946
|
-
`docker run --rm -v "${volumeName2}:/pgdata:ro" -v "${
|
|
24316
|
+
`docker run --rm -v "${volumeName2}:/pgdata:ro" -v "${path39.dirname(tarPath)}:/dest" alpine sh -c 'tar -czf /dest/${path39.basename(tarPath)}.tmp -C /pgdata . && mv /dest/${path39.basename(tarPath)}.tmp /dest/${path39.basename(tarPath)}'`,
|
|
23947
24317
|
{ stdio: "pipe", timeout: 18e4 }
|
|
23948
24318
|
);
|
|
23949
24319
|
execSync11(`docker start ${containerName}`, { stdio: "pipe", timeout: 3e4 });
|
|
23950
|
-
const stat =
|
|
24320
|
+
const stat = fs36.statSync(tarPath);
|
|
23951
24321
|
const manifest = {
|
|
23952
24322
|
kind: "pg",
|
|
23953
24323
|
worldId,
|
|
@@ -23971,18 +24341,18 @@ async function handleEvict(opts) {
|
|
|
23971
24341
|
const maxBytes = Number.isInteger(cap) && cap > 0 ? cap : 5 * 1024 * 1024 * 1024;
|
|
23972
24342
|
if (opts.dryRun) {
|
|
23973
24343
|
const root = snapshotsDir();
|
|
23974
|
-
if (!
|
|
23975
|
-
console.log(
|
|
24344
|
+
if (!fs36.existsSync(root)) {
|
|
24345
|
+
console.log(pc21.dim("No snapshot dir; nothing to evict."));
|
|
23976
24346
|
return;
|
|
23977
24347
|
}
|
|
23978
24348
|
const allTars = [];
|
|
23979
24349
|
const walk2 = (d) => {
|
|
23980
|
-
for (const entry of
|
|
23981
|
-
const full =
|
|
24350
|
+
for (const entry of fs36.readdirSync(d, { withFileTypes: true })) {
|
|
24351
|
+
const full = path39.join(d, entry.name);
|
|
23982
24352
|
if (entry.isDirectory()) {
|
|
23983
24353
|
walk2(full);
|
|
23984
24354
|
} else if (entry.name.endsWith(".tar.gz")) {
|
|
23985
|
-
const stat =
|
|
24355
|
+
const stat = fs36.statSync(full);
|
|
23986
24356
|
allTars.push({ path: full, size: stat.size, mtime: stat.mtimeMs });
|
|
23987
24357
|
}
|
|
23988
24358
|
}
|
|
@@ -23990,7 +24360,7 @@ async function handleEvict(opts) {
|
|
|
23990
24360
|
walk2(root);
|
|
23991
24361
|
const total = allTars.reduce((a, t) => a + t.size, 0);
|
|
23992
24362
|
if (total <= maxBytes) {
|
|
23993
|
-
console.log(`${
|
|
24363
|
+
console.log(`${formatBytes3(total)} total \u2264 ${formatBytes3(maxBytes)} cap; nothing to evict.`);
|
|
23994
24364
|
return;
|
|
23995
24365
|
}
|
|
23996
24366
|
allTars.sort((a, b) => a.mtime - b.mtime);
|
|
@@ -24001,21 +24371,21 @@ async function handleEvict(opts) {
|
|
|
24001
24371
|
toEvict.push(t);
|
|
24002
24372
|
remaining -= t.size;
|
|
24003
24373
|
}
|
|
24004
|
-
printHeader(`Would evict ${toEvict.length} snapshot(s) (${
|
|
24374
|
+
printHeader(`Would evict ${toEvict.length} snapshot(s) (${formatBytes3(total - remaining)})`);
|
|
24005
24375
|
console.log();
|
|
24006
24376
|
for (const t of toEvict) {
|
|
24007
24377
|
const age = formatAge2(Date.now() - t.mtime);
|
|
24008
|
-
console.log(` ${
|
|
24378
|
+
console.log(` ${pc21.dim(formatBytes3(t.size).padStart(8))} ${age.padStart(10)} ${t.path}`);
|
|
24009
24379
|
}
|
|
24010
24380
|
console.log();
|
|
24011
|
-
console.log(
|
|
24381
|
+
console.log(pc21.dim(`Total after eviction: ${formatBytes3(remaining)} (cap: ${formatBytes3(maxBytes)})`));
|
|
24012
24382
|
return;
|
|
24013
24383
|
}
|
|
24014
24384
|
const freed = evictOldSnapshotsWithFlock(maxBytes);
|
|
24015
24385
|
if (freed > 0) {
|
|
24016
|
-
printSuccess(`Evicted ${
|
|
24386
|
+
printSuccess(`Evicted ${formatBytes3(freed)} (cap: ${formatBytes3(maxBytes)})`);
|
|
24017
24387
|
} else {
|
|
24018
|
-
console.log(
|
|
24388
|
+
console.log(pc21.dim("No eviction needed (or another process held the lock)."));
|
|
24019
24389
|
}
|
|
24020
24390
|
}
|
|
24021
24391
|
function handleList2(worldIdFilter) {
|
|
@@ -24023,7 +24393,7 @@ function handleList2(worldIdFilter) {
|
|
|
24023
24393
|
const entries = listSnapshots(worldIdFilter);
|
|
24024
24394
|
if (entries.length === 0) {
|
|
24025
24395
|
const where = worldIdFilter ? ` for world "${worldIdFilter}"` : "";
|
|
24026
|
-
console.log(
|
|
24396
|
+
console.log(pc21.dim(`No snapshots found${where}. Run \`olam world snapshot create <worldId>\` first.`));
|
|
24027
24397
|
return;
|
|
24028
24398
|
}
|
|
24029
24399
|
printHeader(`${entries.length} snapshot(s)`);
|
|
@@ -24032,15 +24402,15 @@ function handleList2(worldIdFilter) {
|
|
|
24032
24402
|
for (const entry of entries) {
|
|
24033
24403
|
const { manifest } = entry;
|
|
24034
24404
|
if (manifest.worldId !== lastWorldId) {
|
|
24035
|
-
console.log(
|
|
24405
|
+
console.log(pc21.bold(manifest.worldId));
|
|
24036
24406
|
lastWorldId = manifest.worldId;
|
|
24037
24407
|
}
|
|
24038
24408
|
const repo = manifest.repo ?? "(all repos)";
|
|
24039
|
-
const size =
|
|
24409
|
+
const size = formatBytes3(manifest.sizeBytes);
|
|
24040
24410
|
const age = formatAge2(entry.ageMs);
|
|
24041
|
-
const kindColor = manifest.kind === "gems" ?
|
|
24411
|
+
const kindColor = manifest.kind === "gems" ? pc21.magenta(manifest.kind) : manifest.kind === "node" ? pc21.cyan(manifest.kind) : pc21.yellow(manifest.kind);
|
|
24042
24412
|
console.log(
|
|
24043
|
-
` ${kindColor.padEnd(6)} ${
|
|
24413
|
+
` ${kindColor.padEnd(6)} ${pc21.dim(repo.padEnd(24))} ${manifest.fingerprint} ${size.padStart(8)} ${age}`
|
|
24044
24414
|
);
|
|
24045
24415
|
}
|
|
24046
24416
|
console.log();
|
|
@@ -24057,7 +24427,7 @@ async function loadWorldMeta(worldId) {
|
|
|
24057
24427
|
}
|
|
24058
24428
|
return { workspacePath: world.workspacePath, repoNames: [...world.repos] };
|
|
24059
24429
|
}
|
|
24060
|
-
function
|
|
24430
|
+
function formatBytes3(bytes) {
|
|
24061
24431
|
if (bytes < 1024) return `${bytes}B`;
|
|
24062
24432
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
24063
24433
|
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
|
|
@@ -24075,35 +24445,35 @@ function formatAge2(ms) {
|
|
|
24075
24445
|
// src/commands/refresh.ts
|
|
24076
24446
|
init_context();
|
|
24077
24447
|
init_output();
|
|
24078
|
-
import * as
|
|
24079
|
-
import * as
|
|
24080
|
-
import * as
|
|
24448
|
+
import * as fs38 from "node:fs";
|
|
24449
|
+
import * as os22 from "node:os";
|
|
24450
|
+
import * as path41 from "node:path";
|
|
24081
24451
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
24082
24452
|
import ora8 from "ora";
|
|
24083
24453
|
|
|
24084
24454
|
// src/commands/refresh-helpers.ts
|
|
24085
|
-
import * as
|
|
24086
|
-
import * as
|
|
24455
|
+
import * as fs37 from "node:fs";
|
|
24456
|
+
import * as path40 from "node:path";
|
|
24087
24457
|
function collectCpSourceFiles(standaloneDir) {
|
|
24088
|
-
if (!
|
|
24458
|
+
if (!fs37.existsSync(standaloneDir)) {
|
|
24089
24459
|
throw new Error(`CP standalone dir not found: ${standaloneDir}`);
|
|
24090
24460
|
}
|
|
24091
24461
|
const entries = [];
|
|
24092
|
-
const topLevel =
|
|
24093
|
-
const stat =
|
|
24462
|
+
const topLevel = fs37.readdirSync(standaloneDir).filter((f) => {
|
|
24463
|
+
const stat = fs37.statSync(path40.join(standaloneDir, f));
|
|
24094
24464
|
return stat.isFile() && f.endsWith(".mjs") && !f.endsWith(".test.mjs");
|
|
24095
24465
|
}).sort();
|
|
24096
24466
|
for (const f of topLevel) {
|
|
24097
|
-
entries.push({ srcPath:
|
|
24467
|
+
entries.push({ srcPath: path40.join(standaloneDir, f), destRelPath: f });
|
|
24098
24468
|
}
|
|
24099
|
-
const libDir =
|
|
24100
|
-
if (
|
|
24101
|
-
const libFiles =
|
|
24102
|
-
const stat =
|
|
24469
|
+
const libDir = path40.join(standaloneDir, "lib");
|
|
24470
|
+
if (fs37.existsSync(libDir) && fs37.statSync(libDir).isDirectory()) {
|
|
24471
|
+
const libFiles = fs37.readdirSync(libDir).filter((f) => {
|
|
24472
|
+
const stat = fs37.statSync(path40.join(libDir, f));
|
|
24103
24473
|
return stat.isFile() && f.endsWith(".mjs") && !f.endsWith(".test.mjs");
|
|
24104
24474
|
}).sort();
|
|
24105
24475
|
for (const f of libFiles) {
|
|
24106
|
-
entries.push({ srcPath:
|
|
24476
|
+
entries.push({ srcPath: path40.join(libDir, f), destRelPath: `lib/${f}` });
|
|
24107
24477
|
}
|
|
24108
24478
|
}
|
|
24109
24479
|
return entries;
|
|
@@ -24161,16 +24531,16 @@ async function refreshWorld(worldId, portOffset, standaloneDir, opts) {
|
|
|
24161
24531
|
error: err instanceof Error ? err.message : String(err)
|
|
24162
24532
|
};
|
|
24163
24533
|
}
|
|
24164
|
-
const stagingDir =
|
|
24165
|
-
|
|
24534
|
+
const stagingDir = fs38.mkdtempSync(
|
|
24535
|
+
path41.join(os22.tmpdir(), `olam-refresh-${worldId}-`)
|
|
24166
24536
|
);
|
|
24167
24537
|
try {
|
|
24168
24538
|
const hasLib = entries.some((e) => e.destRelPath.startsWith("lib/"));
|
|
24169
24539
|
if (hasLib) {
|
|
24170
|
-
|
|
24540
|
+
fs38.mkdirSync(path41.join(stagingDir, "lib"), { recursive: true });
|
|
24171
24541
|
}
|
|
24172
24542
|
for (const { srcPath, destRelPath } of entries) {
|
|
24173
|
-
|
|
24543
|
+
fs38.copyFileSync(srcPath, path41.join(stagingDir, destRelPath));
|
|
24174
24544
|
}
|
|
24175
24545
|
const cpResult = docker([
|
|
24176
24546
|
"cp",
|
|
@@ -24185,7 +24555,7 @@ async function refreshWorld(worldId, portOffset, standaloneDir, opts) {
|
|
|
24185
24555
|
};
|
|
24186
24556
|
}
|
|
24187
24557
|
} finally {
|
|
24188
|
-
|
|
24558
|
+
fs38.rmSync(stagingDir, { recursive: true, force: true });
|
|
24189
24559
|
}
|
|
24190
24560
|
if (opts.restart) {
|
|
24191
24561
|
const restartResult = docker([
|
|
@@ -24222,11 +24592,11 @@ function registerRefresh(program2) {
|
|
|
24222
24592
|
process.exitCode = 1;
|
|
24223
24593
|
return;
|
|
24224
24594
|
}
|
|
24225
|
-
const standaloneDir =
|
|
24595
|
+
const standaloneDir = path41.join(
|
|
24226
24596
|
process.cwd(),
|
|
24227
24597
|
"packages/control-plane/standalone"
|
|
24228
24598
|
);
|
|
24229
|
-
if (!
|
|
24599
|
+
if (!fs38.existsSync(standaloneDir)) {
|
|
24230
24600
|
printError(
|
|
24231
24601
|
`CP standalone source not found at ${standaloneDir}.
|
|
24232
24602
|
Run \`olam refresh\` from the olam repo root.`
|
|
@@ -24305,11 +24675,11 @@ Run \`olam refresh\` from the olam repo root.`
|
|
|
24305
24675
|
}
|
|
24306
24676
|
|
|
24307
24677
|
// src/commands/diagnose.ts
|
|
24308
|
-
import * as
|
|
24309
|
-
import * as
|
|
24310
|
-
import * as
|
|
24311
|
-
import { execFileSync as
|
|
24312
|
-
import
|
|
24678
|
+
import * as fs39 from "node:fs";
|
|
24679
|
+
import * as os23 from "node:os";
|
|
24680
|
+
import * as path42 from "node:path";
|
|
24681
|
+
import { execFileSync as execFileSync9, execSync as execSync12 } from "node:child_process";
|
|
24682
|
+
import pc22 from "picocolors";
|
|
24313
24683
|
|
|
24314
24684
|
// ../core/dist/diagnose/secret-stripper.js
|
|
24315
24685
|
var SECRET_PATTERNS = [
|
|
@@ -24342,9 +24712,9 @@ function stripSecrets(input) {
|
|
|
24342
24712
|
}
|
|
24343
24713
|
|
|
24344
24714
|
// src/commands/diagnose.ts
|
|
24345
|
-
var DIAGNOSTICS_DIR =
|
|
24346
|
-
var LOG_DIR =
|
|
24347
|
-
var CACHE_DIR =
|
|
24715
|
+
var DIAGNOSTICS_DIR = path42.join(os23.homedir(), ".olam", "diagnostics");
|
|
24716
|
+
var LOG_DIR = path42.join(os23.homedir(), ".olam", "log");
|
|
24717
|
+
var CACHE_DIR = path42.join(os23.homedir(), ".olam", "cache");
|
|
24348
24718
|
var LOG_TAIL_LINES = 200;
|
|
24349
24719
|
function safeExec(cmd) {
|
|
24350
24720
|
try {
|
|
@@ -24354,14 +24724,14 @@ function safeExec(cmd) {
|
|
|
24354
24724
|
}
|
|
24355
24725
|
}
|
|
24356
24726
|
function defaultZip(zipPath, files) {
|
|
24357
|
-
|
|
24727
|
+
execFileSync9("zip", ["-j", zipPath, ...files]);
|
|
24358
24728
|
}
|
|
24359
24729
|
async function buildDiagnosticsZip(_exec = (cmd) => safeExec(cmd), _outDir = DIAGNOSTICS_DIR, _logDir = LOG_DIR, _zip = defaultZip) {
|
|
24360
24730
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 23);
|
|
24361
|
-
const zipPath =
|
|
24362
|
-
const tmpDir =
|
|
24731
|
+
const zipPath = path42.join(_outDir, `olam-diag-${ts}.zip`);
|
|
24732
|
+
const tmpDir = fs39.mkdtempSync(path42.join(os23.tmpdir(), "olam-diag-"));
|
|
24363
24733
|
try {
|
|
24364
|
-
|
|
24734
|
+
fs39.mkdirSync(_outDir, { recursive: true });
|
|
24365
24735
|
const entries = [];
|
|
24366
24736
|
const version = process.env["OLAM_CLI_VERSION"] ?? "unknown";
|
|
24367
24737
|
const nodeVersion = process.version;
|
|
@@ -24372,19 +24742,19 @@ platform: ${platform}
|
|
|
24372
24742
|
`;
|
|
24373
24743
|
_writeEntry(tmpDir, "version.txt", stripSecrets(versionContent), entries);
|
|
24374
24744
|
const osContent = [
|
|
24375
|
-
`os: ${
|
|
24376
|
-
`arch: ${
|
|
24377
|
-
`uptime: ${
|
|
24745
|
+
`os: ${os23.type()} ${os23.release()}`,
|
|
24746
|
+
`arch: ${os23.arch()}`,
|
|
24747
|
+
`uptime: ${os23.uptime()}s`
|
|
24378
24748
|
].join("\n") + "\n";
|
|
24379
24749
|
_writeEntry(tmpDir, "os-info.txt", stripSecrets(osContent), entries);
|
|
24380
|
-
const depsFile =
|
|
24381
|
-
if (
|
|
24382
|
-
const deps =
|
|
24750
|
+
const depsFile = path42.join(CACHE_DIR, "deps.json");
|
|
24751
|
+
if (fs39.existsSync(depsFile)) {
|
|
24752
|
+
const deps = fs39.readFileSync(depsFile, "utf-8");
|
|
24383
24753
|
_writeEntry(tmpDir, "deps.json", stripSecrets(deps), entries);
|
|
24384
24754
|
}
|
|
24385
24755
|
const latestLog = _latestLog(_logDir);
|
|
24386
24756
|
if (latestLog) {
|
|
24387
|
-
const lines =
|
|
24757
|
+
const lines = fs39.readFileSync(latestLog, "utf-8").split("\n");
|
|
24388
24758
|
const tail = lines.slice(-LOG_TAIL_LINES).join("\n");
|
|
24389
24759
|
_writeEntry(tmpDir, "log-tail.txt", stripSecrets(tail), entries);
|
|
24390
24760
|
}
|
|
@@ -24396,38 +24766,38 @@ platform: ${platform}
|
|
|
24396
24766
|
if (authAudit) {
|
|
24397
24767
|
_writeEntry(tmpDir, "audit-auth-callers.txt", stripSecrets(authAudit), entries);
|
|
24398
24768
|
}
|
|
24399
|
-
const fileArgs = entries.map((e) =>
|
|
24769
|
+
const fileArgs = entries.map((e) => path42.join(tmpDir, e));
|
|
24400
24770
|
try {
|
|
24401
24771
|
_zip(zipPath, fileArgs);
|
|
24402
24772
|
} catch (err) {
|
|
24403
24773
|
throw new Error(`zip command produced no output file. zip stderr: ${err.message}`);
|
|
24404
24774
|
}
|
|
24405
|
-
if (!
|
|
24775
|
+
if (!fs39.existsSync(zipPath)) {
|
|
24406
24776
|
throw new Error("zip command produced no output file.");
|
|
24407
24777
|
}
|
|
24408
24778
|
return { zipPath, entries };
|
|
24409
24779
|
} finally {
|
|
24410
24780
|
try {
|
|
24411
|
-
|
|
24781
|
+
fs39.rmSync(tmpDir, { recursive: true, force: true });
|
|
24412
24782
|
} catch {
|
|
24413
24783
|
}
|
|
24414
24784
|
}
|
|
24415
24785
|
}
|
|
24416
24786
|
function _writeEntry(dir, name, content, entries) {
|
|
24417
|
-
|
|
24787
|
+
fs39.writeFileSync(path42.join(dir, name), content, { mode: 420 });
|
|
24418
24788
|
entries.push(name);
|
|
24419
24789
|
}
|
|
24420
24790
|
function _latestLog(logDir) {
|
|
24421
|
-
if (!
|
|
24422
|
-
const files =
|
|
24423
|
-
return files.length > 0 ?
|
|
24791
|
+
if (!fs39.existsSync(logDir)) return null;
|
|
24792
|
+
const files = fs39.readdirSync(logDir).filter((f) => f.startsWith("host-")).sort().reverse();
|
|
24793
|
+
return files.length > 0 ? path42.join(logDir, files[0]) : null;
|
|
24424
24794
|
}
|
|
24425
24795
|
async function buildTelemetryPayload() {
|
|
24426
24796
|
const channel = "stable";
|
|
24427
|
-
const manifestFile =
|
|
24797
|
+
const manifestFile = path42.join(CACHE_DIR, "manifest.json");
|
|
24428
24798
|
let manifestAgeHours = null;
|
|
24429
|
-
if (
|
|
24430
|
-
const mtime =
|
|
24799
|
+
if (fs39.existsSync(manifestFile)) {
|
|
24800
|
+
const mtime = fs39.statSync(manifestFile).mtime.getTime();
|
|
24431
24801
|
manifestAgeHours = Math.round((Date.now() - mtime) / 36e5);
|
|
24432
24802
|
}
|
|
24433
24803
|
return {
|
|
@@ -24447,47 +24817,47 @@ function registerDiagnose(program2) {
|
|
|
24447
24817
|
return;
|
|
24448
24818
|
}
|
|
24449
24819
|
if (!opts.quiet) {
|
|
24450
|
-
console.log(
|
|
24820
|
+
console.log(pc22.cyan("Building diagnostics zip\u2026"));
|
|
24451
24821
|
}
|
|
24452
24822
|
try {
|
|
24453
24823
|
const { zipPath, entries } = await buildDiagnosticsZip();
|
|
24454
24824
|
if (!opts.quiet) {
|
|
24455
|
-
console.log(
|
|
24456
|
-
console.log(
|
|
24825
|
+
console.log(pc22.green(`Done: ${zipPath}`));
|
|
24826
|
+
console.log(pc22.dim(`Contents: ${entries.join(", ")}`));
|
|
24457
24827
|
}
|
|
24458
24828
|
if (opts.upload) {
|
|
24459
|
-
console.log(
|
|
24829
|
+
console.log(pc22.yellow(
|
|
24460
24830
|
`Telemetry endpoint not yet provisioned. Share the zip manually:
|
|
24461
24831
|
File: ${zipPath}
|
|
24462
24832
|
See docs/runbooks/share-diagnostics.md for instructions.`
|
|
24463
24833
|
));
|
|
24464
24834
|
}
|
|
24465
24835
|
} catch (err) {
|
|
24466
|
-
console.error(
|
|
24836
|
+
console.error(pc22.red(`Diagnose failed: ${err.message}`));
|
|
24467
24837
|
process.exitCode = 1;
|
|
24468
24838
|
}
|
|
24469
24839
|
});
|
|
24470
24840
|
}
|
|
24471
24841
|
|
|
24472
24842
|
// src/commands/update.ts
|
|
24473
|
-
import * as
|
|
24474
|
-
import * as
|
|
24475
|
-
import * as
|
|
24843
|
+
import * as fs42 from "node:fs";
|
|
24844
|
+
import * as os25 from "node:os";
|
|
24845
|
+
import * as path45 from "node:path";
|
|
24476
24846
|
import { execSync as execSync13 } from "node:child_process";
|
|
24477
|
-
import
|
|
24847
|
+
import pc23 from "picocolors";
|
|
24478
24848
|
|
|
24479
24849
|
// src/lib/symlink-reconcile.ts
|
|
24480
|
-
import * as
|
|
24481
|
-
import * as
|
|
24850
|
+
import * as fs40 from "node:fs";
|
|
24851
|
+
import * as path43 from "node:path";
|
|
24482
24852
|
var realFs = {
|
|
24483
|
-
readdirSync: (p) =>
|
|
24484
|
-
existsSync: (p) =>
|
|
24485
|
-
lstatSync: (p) =>
|
|
24486
|
-
readlinkSync: (p) =>
|
|
24487
|
-
symlinkSync: (t, l) =>
|
|
24488
|
-
unlinkSync: (p) =>
|
|
24853
|
+
readdirSync: (p) => fs40.readdirSync(p),
|
|
24854
|
+
existsSync: (p) => fs40.existsSync(p),
|
|
24855
|
+
lstatSync: (p) => fs40.lstatSync(p),
|
|
24856
|
+
readlinkSync: (p) => fs40.readlinkSync(p),
|
|
24857
|
+
symlinkSync: (t, l) => fs40.symlinkSync(t, l),
|
|
24858
|
+
unlinkSync: (p) => fs40.unlinkSync(p),
|
|
24489
24859
|
mkdirSync: (p, o) => {
|
|
24490
|
-
|
|
24860
|
+
fs40.mkdirSync(p, o);
|
|
24491
24861
|
}
|
|
24492
24862
|
};
|
|
24493
24863
|
function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
|
|
@@ -24497,8 +24867,8 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
|
|
|
24497
24867
|
_fs.mkdirSync(claudeSkillsDir, { recursive: true });
|
|
24498
24868
|
const sourceSkills = _fs.existsSync(npmSkillsDir) ? _fs.readdirSync(npmSkillsDir).filter((d) => d.startsWith("olam-")) : [];
|
|
24499
24869
|
for (const skill of sourceSkills) {
|
|
24500
|
-
const linkPath =
|
|
24501
|
-
const target =
|
|
24870
|
+
const linkPath = path43.join(claudeSkillsDir, skill);
|
|
24871
|
+
const target = path43.join(npmSkillsDir, skill);
|
|
24502
24872
|
if (!_fs.existsSync(linkPath)) {
|
|
24503
24873
|
try {
|
|
24504
24874
|
_fs.symlinkSync(target, linkPath);
|
|
@@ -24511,7 +24881,7 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
|
|
|
24511
24881
|
}
|
|
24512
24882
|
const deployedEntries = _fs.existsSync(claudeSkillsDir) ? _fs.readdirSync(claudeSkillsDir).filter((d) => d.startsWith("olam-")) : [];
|
|
24513
24883
|
for (const entry of deployedEntries) {
|
|
24514
|
-
const linkPath =
|
|
24884
|
+
const linkPath = path43.join(claudeSkillsDir, entry);
|
|
24515
24885
|
let isSymlink = false;
|
|
24516
24886
|
try {
|
|
24517
24887
|
isSymlink = _fs.lstatSync(linkPath).isSymbolicLink();
|
|
@@ -24536,9 +24906,9 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
|
|
|
24536
24906
|
|
|
24537
24907
|
// src/commands/update.ts
|
|
24538
24908
|
var PACKAGE_NAME = "@pleri/olam-cli";
|
|
24539
|
-
var CACHE_DIR2 =
|
|
24540
|
-
var LOG_DIR2 =
|
|
24541
|
-
var LAST_STABLE_FILE =
|
|
24909
|
+
var CACHE_DIR2 = path45.join(os25.homedir(), ".olam", "cache");
|
|
24910
|
+
var LOG_DIR2 = path45.join(os25.homedir(), ".olam", "log");
|
|
24911
|
+
var LAST_STABLE_FILE = path45.join(CACHE_DIR2, "last-stable.txt");
|
|
24542
24912
|
function defaultExec(cmd) {
|
|
24543
24913
|
try {
|
|
24544
24914
|
const stdout = execSync13(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -24560,22 +24930,22 @@ function getCurrentVersion(_exec = defaultExec) {
|
|
|
24560
24930
|
}
|
|
24561
24931
|
function readLastStable(file = LAST_STABLE_FILE) {
|
|
24562
24932
|
try {
|
|
24563
|
-
const v =
|
|
24933
|
+
const v = fs42.readFileSync(file, "utf-8").trim();
|
|
24564
24934
|
return v || null;
|
|
24565
24935
|
} catch {
|
|
24566
24936
|
return null;
|
|
24567
24937
|
}
|
|
24568
24938
|
}
|
|
24569
24939
|
function writeLastStable(version, file = LAST_STABLE_FILE) {
|
|
24570
|
-
|
|
24571
|
-
|
|
24940
|
+
fs42.mkdirSync(path45.dirname(file), { recursive: true });
|
|
24941
|
+
fs42.writeFileSync(file, version, { mode: 420 });
|
|
24572
24942
|
}
|
|
24573
24943
|
function logUpdateFailure(stderr) {
|
|
24574
24944
|
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
24575
|
-
const logFile =
|
|
24945
|
+
const logFile = path45.join(LOG_DIR2, `update-${ts}.log`);
|
|
24576
24946
|
try {
|
|
24577
|
-
|
|
24578
|
-
|
|
24947
|
+
fs42.mkdirSync(LOG_DIR2, { recursive: true });
|
|
24948
|
+
fs42.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
|
|
24579
24949
|
${stderr}
|
|
24580
24950
|
`, "utf-8");
|
|
24581
24951
|
} catch {
|
|
@@ -24626,52 +24996,52 @@ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSy
|
|
|
24626
24996
|
writeLastStable(prevVersion);
|
|
24627
24997
|
}
|
|
24628
24998
|
if (!quiet) {
|
|
24629
|
-
console.log(
|
|
24999
|
+
console.log(pc23.cyan(`Installing ${PACKAGE_NAME}@${channel}\u2026`));
|
|
24630
25000
|
}
|
|
24631
25001
|
const installResult = _exec(`npm install -g ${PACKAGE_NAME}@${channel}`);
|
|
24632
25002
|
if (installResult.exitCode !== 0) {
|
|
24633
25003
|
logUpdateFailure(installResult.stderr);
|
|
24634
25004
|
if (!quiet) {
|
|
24635
|
-
console.error(
|
|
25005
|
+
console.error(pc23.red("Update failed."));
|
|
24636
25006
|
}
|
|
24637
25007
|
const prev = readLastStable();
|
|
24638
25008
|
if (prev) {
|
|
24639
25009
|
if (!quiet) {
|
|
24640
|
-
console.log(
|
|
25010
|
+
console.log(pc23.yellow(`Restoring to ${prev}\u2026`));
|
|
24641
25011
|
}
|
|
24642
25012
|
const restoreResult = _exec(`npm install -g ${PACKAGE_NAME}@${prev}`);
|
|
24643
25013
|
if (restoreResult.exitCode !== 0) {
|
|
24644
25014
|
if (!quiet) {
|
|
24645
|
-
console.error(
|
|
25015
|
+
console.error(pc23.red(
|
|
24646
25016
|
`Restore also failed. Run: npm install -g ${PACKAGE_NAME}@${prev} manually.`
|
|
24647
25017
|
));
|
|
24648
25018
|
}
|
|
24649
25019
|
} else if (!quiet) {
|
|
24650
|
-
console.log(
|
|
25020
|
+
console.log(pc23.yellow(`Restored to ${prev}.`));
|
|
24651
25021
|
}
|
|
24652
25022
|
} else if (!quiet) {
|
|
24653
|
-
console.error(
|
|
25023
|
+
console.error(pc23.red("No previous version cached; cannot auto-restore."));
|
|
24654
25024
|
}
|
|
24655
25025
|
return { action: "restored", prevVersion: prev ?? void 0, exitCode: 11 };
|
|
24656
25026
|
}
|
|
24657
25027
|
const newVersion = getCurrentVersion(_exec) ?? void 0;
|
|
24658
25028
|
if (!quiet && newVersion) {
|
|
24659
|
-
console.log(
|
|
25029
|
+
console.log(pc23.green(`Updated to ${newVersion}.`));
|
|
24660
25030
|
}
|
|
24661
25031
|
const npmRootResult = _getNpmRoot("npm root -g");
|
|
24662
25032
|
let symlinkResult = { added: [], removed: [] };
|
|
24663
25033
|
if (npmRootResult.exitCode === 0) {
|
|
24664
25034
|
const npmRoot = npmRootResult.stdout.trim();
|
|
24665
|
-
const npmSkillsDir =
|
|
24666
|
-
const claudeSkillsDir =
|
|
25035
|
+
const npmSkillsDir = path45.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
|
|
25036
|
+
const claudeSkillsDir = path45.join(os25.homedir(), ".claude", "skills");
|
|
24667
25037
|
const rec = _reconcile(npmSkillsDir, claudeSkillsDir);
|
|
24668
25038
|
symlinkResult = { added: rec.added, removed: rec.removed };
|
|
24669
25039
|
if (!quiet && (rec.added.length > 0 || rec.removed.length > 0)) {
|
|
24670
25040
|
if (rec.added.length > 0) {
|
|
24671
|
-
console.log(
|
|
25041
|
+
console.log(pc23.dim(`Skills added: ${rec.added.join(", ")}`));
|
|
24672
25042
|
}
|
|
24673
25043
|
if (rec.removed.length > 0) {
|
|
24674
|
-
console.log(
|
|
25044
|
+
console.log(pc23.dim(`Skills removed (dangling): ${rec.removed.join(", ")}`));
|
|
24675
25045
|
}
|
|
24676
25046
|
}
|
|
24677
25047
|
}
|
|
@@ -24709,8 +25079,8 @@ async function doRollback(_exec = defaultExec, _reconcile = reconcileSkillSymlin
|
|
|
24709
25079
|
if (npmRootResult.exitCode === 0) {
|
|
24710
25080
|
const npmRoot = npmRootResult.stdout.trim();
|
|
24711
25081
|
_reconcile(
|
|
24712
|
-
|
|
24713
|
-
|
|
25082
|
+
path45.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
|
|
25083
|
+
path45.join(os25.homedir(), ".claude", "skills")
|
|
24714
25084
|
);
|
|
24715
25085
|
}
|
|
24716
25086
|
return { action: "rolled-back", restoredVersion: prev, exitCode: 0 };
|
|
@@ -24765,7 +25135,7 @@ function registerUpdate(program2) {
|
|
|
24765
25135
|
// src/commands/begin.ts
|
|
24766
25136
|
init_host_cp();
|
|
24767
25137
|
init_open_url();
|
|
24768
|
-
import
|
|
25138
|
+
import pc24 from "picocolors";
|
|
24769
25139
|
async function doBegin(opts, _startFn = startHostCp, _openFn = openUrl) {
|
|
24770
25140
|
const prevExitCode = process.exitCode;
|
|
24771
25141
|
await _startFn({ showToken: opts.showToken });
|
|
@@ -24775,7 +25145,7 @@ async function doBegin(opts, _startFn = startHostCp, _openFn = openUrl) {
|
|
|
24775
25145
|
const token = readToken();
|
|
24776
25146
|
if (token) {
|
|
24777
25147
|
const base = `http://127.0.0.1:${HOST_CP_PORT}/`;
|
|
24778
|
-
console.log(
|
|
25148
|
+
console.log(pc24.dim(`Opening ${base}`));
|
|
24779
25149
|
_openFn(`${base}?token=${token}`);
|
|
24780
25150
|
}
|
|
24781
25151
|
}
|
|
@@ -24791,7 +25161,7 @@ function registerBegin(program2) {
|
|
|
24791
25161
|
}
|
|
24792
25162
|
|
|
24793
25163
|
// src/commands/config.ts
|
|
24794
|
-
import * as
|
|
25164
|
+
import * as fs44 from "node:fs";
|
|
24795
25165
|
import { createRequire as createRequire4 } from "node:module";
|
|
24796
25166
|
|
|
24797
25167
|
// ../core/dist/global-config/index.js
|
|
@@ -24800,12 +25170,12 @@ init_store2();
|
|
|
24800
25170
|
|
|
24801
25171
|
// ../core/dist/global-config/repos.js
|
|
24802
25172
|
init_store2();
|
|
24803
|
-
import * as
|
|
24804
|
-
import * as
|
|
24805
|
-
import * as
|
|
25173
|
+
import * as fs43 from "node:fs";
|
|
25174
|
+
import * as os26 from "node:os";
|
|
25175
|
+
import * as path46 from "node:path";
|
|
24806
25176
|
function expandPath(p) {
|
|
24807
25177
|
if (p === "~" || p.startsWith("~/")) {
|
|
24808
|
-
return
|
|
25178
|
+
return path46.join(os26.homedir(), p.slice(1));
|
|
24809
25179
|
}
|
|
24810
25180
|
return p;
|
|
24811
25181
|
}
|
|
@@ -24818,7 +25188,7 @@ function addRepo(entry) {
|
|
|
24818
25188
|
throw new Error(`repo "${entry.name}" already registered. Use "olam repos update" to change its path.`);
|
|
24819
25189
|
}
|
|
24820
25190
|
const resolvedPath = expandPath(entry.path);
|
|
24821
|
-
if (!
|
|
25191
|
+
if (!fs43.existsSync(resolvedPath)) {
|
|
24822
25192
|
throw new Error(`path "${entry.path}" does not exist. Verify the path is correct.`);
|
|
24823
25193
|
}
|
|
24824
25194
|
const now = Date.now();
|
|
@@ -24847,7 +25217,7 @@ function updateRepo(name, updates) {
|
|
|
24847
25217
|
throw new Error(`repo "${name}" is not registered. Run "olam repos list" to see registered repos.`);
|
|
24848
25218
|
}
|
|
24849
25219
|
const resolvedUpdatePath = updates.path !== void 0 ? expandPath(updates.path) : void 0;
|
|
24850
|
-
if (resolvedUpdatePath !== void 0 && !
|
|
25220
|
+
if (resolvedUpdatePath !== void 0 && !fs43.existsSync(resolvedUpdatePath)) {
|
|
24851
25221
|
throw new Error(`path "${updates.path}" does not exist. Verify the path is correct.`);
|
|
24852
25222
|
}
|
|
24853
25223
|
const existing = config.repos[idx];
|
|
@@ -24877,14 +25247,14 @@ function registerConfig(program2) {
|
|
|
24877
25247
|
const config = program2.command("config").description("Manage global olam configuration");
|
|
24878
25248
|
config.command("validate [path]").description("Validate ~/.olam/config.json (or a custom path) against the schema").action((filePath) => {
|
|
24879
25249
|
const resolvedPath = filePath ?? globalConfigPath();
|
|
24880
|
-
if (!
|
|
25250
|
+
if (!fs44.existsSync(resolvedPath)) {
|
|
24881
25251
|
process.stderr.write(`config file not found: ${resolvedPath}
|
|
24882
25252
|
`);
|
|
24883
25253
|
process.exit(1);
|
|
24884
25254
|
}
|
|
24885
25255
|
let raw;
|
|
24886
25256
|
try {
|
|
24887
|
-
raw =
|
|
25257
|
+
raw = fs44.readFileSync(resolvedPath, "utf-8");
|
|
24888
25258
|
} catch (err) {
|
|
24889
25259
|
const msg = err instanceof Error ? err.message : String(err);
|
|
24890
25260
|
process.stderr.write(`cannot read ${resolvedPath}: ${msg}
|
|
@@ -24920,7 +25290,7 @@ function registerConfig(program2) {
|
|
|
24920
25290
|
}
|
|
24921
25291
|
|
|
24922
25292
|
// src/commands/repos.ts
|
|
24923
|
-
import
|
|
25293
|
+
import pc25 from "picocolors";
|
|
24924
25294
|
init_output();
|
|
24925
25295
|
function asMessage(err) {
|
|
24926
25296
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -24930,14 +25300,14 @@ function registerRepos(program2) {
|
|
|
24930
25300
|
repos.command("list").description("List all registered repos").action(() => {
|
|
24931
25301
|
const all = listRepos();
|
|
24932
25302
|
if (all.length === 0) {
|
|
24933
|
-
console.log(
|
|
25303
|
+
console.log(pc25.dim("0 repo(s) registered. Add one with: olam repos add --name <n> --path <p>"));
|
|
24934
25304
|
return;
|
|
24935
25305
|
}
|
|
24936
25306
|
printHeader(`${all.length} repo(s)`);
|
|
24937
25307
|
for (const r of all) {
|
|
24938
25308
|
const when = new Date(r.addedAt).toISOString().slice(0, 10);
|
|
24939
25309
|
console.log(
|
|
24940
|
-
` ${
|
|
25310
|
+
` ${pc25.bold(r.name.padEnd(24))} ${r.path.padEnd(48)} ${pc25.dim(when)}`
|
|
24941
25311
|
);
|
|
24942
25312
|
}
|
|
24943
25313
|
});
|
|
@@ -24980,7 +25350,7 @@ function registerRepos(program2) {
|
|
|
24980
25350
|
}
|
|
24981
25351
|
|
|
24982
25352
|
// src/commands/runbooks.ts
|
|
24983
|
-
import
|
|
25353
|
+
import pc26 from "picocolors";
|
|
24984
25354
|
init_output();
|
|
24985
25355
|
function asMessage2(err) {
|
|
24986
25356
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -25011,14 +25381,14 @@ function parsePortFlags(ports) {
|
|
|
25011
25381
|
}
|
|
25012
25382
|
function formatConflict(c) {
|
|
25013
25383
|
const occupantStr = c.occupant.type === "olam-world" ? `in use by world "${c.occupant.worldId}" (olam)` : `in use by PID ${c.occupant.pid ?? "unknown"} (non-olam process)`;
|
|
25014
|
-
return ` ${
|
|
25384
|
+
return ` ${pc26.red("\u2717")} ${c.repoName}.${c.serviceName}:${c.port} \u2014 ${occupantStr}`;
|
|
25015
25385
|
}
|
|
25016
25386
|
function registerRunbooks(program2) {
|
|
25017
25387
|
const runbooks = program2.command("runbooks").description("Manage runbooks in the global config");
|
|
25018
25388
|
runbooks.command("list").description("List all runbooks").action(() => {
|
|
25019
25389
|
const all = listRunbooks();
|
|
25020
25390
|
if (all.length === 0) {
|
|
25021
|
-
console.log(
|
|
25391
|
+
console.log(pc26.dim("0 runbook(s). Add one with: olam runbooks add <name> --repos <repo>"));
|
|
25022
25392
|
return;
|
|
25023
25393
|
}
|
|
25024
25394
|
printHeader(`${all.length} runbook(s)`);
|
|
@@ -25026,7 +25396,7 @@ function registerRunbooks(program2) {
|
|
|
25026
25396
|
const when = new Date(rb.updatedAt).toISOString().slice(0, 10);
|
|
25027
25397
|
const repoList = rb.repos.join(", ");
|
|
25028
25398
|
console.log(
|
|
25029
|
-
` ${
|
|
25399
|
+
` ${pc26.bold(rb.name.padEnd(24))} ${repoList.padEnd(40)} ${pc26.dim(when)}`
|
|
25030
25400
|
);
|
|
25031
25401
|
}
|
|
25032
25402
|
});
|
|
@@ -25082,17 +25452,17 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
|
|
|
25082
25452
|
return;
|
|
25083
25453
|
}
|
|
25084
25454
|
console.log(
|
|
25085
|
-
|
|
25455
|
+
pc26.dim(
|
|
25086
25456
|
`olam runbooks apply: port validation passed for "${name}" (repos: ${rb.repos.join(", ")}).`
|
|
25087
25457
|
)
|
|
25088
25458
|
);
|
|
25089
25459
|
console.log(
|
|
25090
|
-
|
|
25460
|
+
pc26.dim(
|
|
25091
25461
|
`Hint: use "olam create --repos ${rb.repos.join(" ")}${opts.task ? ` --task "${opts.task}"` : ""}${opts.name ? ` --name ${opts.name}` : ""}" to create the world.`
|
|
25092
25462
|
)
|
|
25093
25463
|
);
|
|
25094
25464
|
console.log(
|
|
25095
|
-
|
|
25465
|
+
pc26.yellow('Phase D will wire --runbook directly. For now, use "olam create --repos ..." above.')
|
|
25096
25466
|
);
|
|
25097
25467
|
} catch (err) {
|
|
25098
25468
|
printError(asMessage2(err));
|
|
@@ -25104,7 +25474,7 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
|
|
|
25104
25474
|
const rb = getRunbook(name);
|
|
25105
25475
|
const { conflicts } = validateRunbookPorts(rb);
|
|
25106
25476
|
if (!rb.portMap || Object.keys(rb.portMap).length === 0) {
|
|
25107
|
-
console.log(
|
|
25477
|
+
console.log(pc26.dim(`runbook "${name}" declares no ports.`));
|
|
25108
25478
|
return;
|
|
25109
25479
|
}
|
|
25110
25480
|
for (const [repoName, svcMap] of Object.entries(rb.portMap ?? {})) {
|
|
@@ -25113,7 +25483,7 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
|
|
|
25113
25483
|
if (conflict) {
|
|
25114
25484
|
console.log(formatConflict(conflict));
|
|
25115
25485
|
} else {
|
|
25116
|
-
console.log(` ${
|
|
25486
|
+
console.log(` ${pc26.green("\u2713")} ${repoName}.${svcName}:${port} \u2014 free`);
|
|
25117
25487
|
}
|
|
25118
25488
|
}
|
|
25119
25489
|
}
|
|
@@ -25124,7 +25494,7 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
|
|
|
25124
25494
|
);
|
|
25125
25495
|
process.exitCode = 1;
|
|
25126
25496
|
} else {
|
|
25127
|
-
console.log(
|
|
25497
|
+
console.log(pc26.green("\n\u2713 all ports free"));
|
|
25128
25498
|
}
|
|
25129
25499
|
} catch (err) {
|
|
25130
25500
|
printError(asMessage2(err));
|
|
@@ -25214,8 +25584,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
|
|
|
25214
25584
|
function authHeaders() {
|
|
25215
25585
|
return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
|
|
25216
25586
|
}
|
|
25217
|
-
async function apiFetch(
|
|
25218
|
-
const res = await fetch(`${BASE_URL}${
|
|
25587
|
+
async function apiFetch(path49, init = {}) {
|
|
25588
|
+
const res = await fetch(`${BASE_URL}${path49}`, {
|
|
25219
25589
|
...init,
|
|
25220
25590
|
headers: {
|
|
25221
25591
|
"Content-Type": "application/json",
|
|
@@ -25367,7 +25737,7 @@ function registerMcpAdd(cmd) {
|
|
|
25367
25737
|
|
|
25368
25738
|
// src/commands/mcp/list.ts
|
|
25369
25739
|
init_output();
|
|
25370
|
-
import
|
|
25740
|
+
import pc27 from "picocolors";
|
|
25371
25741
|
function registerMcpList(cmd) {
|
|
25372
25742
|
cmd.command("list").description("List all registered MCP credentials").action(async () => {
|
|
25373
25743
|
const client = getMcpAuthClient();
|
|
@@ -25382,8 +25752,8 @@ function registerMcpList(cmd) {
|
|
|
25382
25752
|
}
|
|
25383
25753
|
const mcps = data.mcps ?? [];
|
|
25384
25754
|
if (mcps.length === 0) {
|
|
25385
|
-
console.log(
|
|
25386
|
-
console.log(
|
|
25755
|
+
console.log(pc27.dim("No MCP credentials registered."));
|
|
25756
|
+
console.log(pc27.dim("Add one with: olam mcp add <service>"));
|
|
25387
25757
|
return;
|
|
25388
25758
|
}
|
|
25389
25759
|
const [c0, c1, c2, c3] = [16, 20, 10, 24];
|
|
@@ -25394,12 +25764,12 @@ function registerMcpList(cmd) {
|
|
|
25394
25764
|
"ENV VAR".padEnd(c3),
|
|
25395
25765
|
"STATUS"
|
|
25396
25766
|
].join(" ");
|
|
25397
|
-
console.log(
|
|
25398
|
-
console.log(
|
|
25767
|
+
console.log(pc27.dim(header));
|
|
25768
|
+
console.log(pc27.dim("\u2500".repeat(header.length)));
|
|
25399
25769
|
for (const m of mcps) {
|
|
25400
|
-
const status = !m.validated ?
|
|
25770
|
+
const status = !m.validated ? pc27.yellow("unvalidated") : m.expired ? pc27.red("expired") : pc27.green("active");
|
|
25401
25771
|
const row = [
|
|
25402
|
-
|
|
25772
|
+
pc27.cyan(m.service.padEnd(c0)),
|
|
25403
25773
|
m.label.padEnd(c1).slice(0, c1),
|
|
25404
25774
|
m.type.padEnd(c2),
|
|
25405
25775
|
(m.envName ?? "\u2014").padEnd(c3).slice(0, c3),
|
|
@@ -25427,13 +25797,13 @@ function registerMcpRemove(cmd) {
|
|
|
25427
25797
|
|
|
25428
25798
|
// src/commands/mcp/status.ts
|
|
25429
25799
|
init_output();
|
|
25430
|
-
import
|
|
25800
|
+
import pc28 from "picocolors";
|
|
25431
25801
|
function formatExpiry(expiresAt) {
|
|
25432
25802
|
if (!expiresAt) return "\u2014";
|
|
25433
25803
|
const ms = expiresAt - Date.now();
|
|
25434
|
-
if (ms <= 0) return
|
|
25804
|
+
if (ms <= 0) return pc28.red("expired");
|
|
25435
25805
|
const hours = ms / (1e3 * 60 * 60);
|
|
25436
|
-
if (hours < 1) return
|
|
25806
|
+
if (hours < 1) return pc28.yellow(`${Math.ceil(ms / 6e4)}m`);
|
|
25437
25807
|
return `${hours.toFixed(1)}h`;
|
|
25438
25808
|
}
|
|
25439
25809
|
function registerMcpStatus(cmd) {
|
|
@@ -25450,14 +25820,14 @@ function registerMcpStatus(cmd) {
|
|
|
25450
25820
|
const mcps = data.mcps ?? [];
|
|
25451
25821
|
printHeader(`MCP Credentials (${mcps.length})`);
|
|
25452
25822
|
if (mcps.length === 0) {
|
|
25453
|
-
console.log(
|
|
25823
|
+
console.log(pc28.dim("No credentials registered."));
|
|
25454
25824
|
return;
|
|
25455
25825
|
}
|
|
25456
25826
|
for (const m of mcps) {
|
|
25457
|
-
const stateColor = !m.validated ?
|
|
25827
|
+
const stateColor = !m.validated ? pc28.yellow : m.expired ? pc28.red : pc28.green;
|
|
25458
25828
|
const stateLabel = !m.validated ? "unvalidated" : m.expired ? "expired" : "active";
|
|
25459
25829
|
console.log(`
|
|
25460
|
-
${
|
|
25830
|
+
${pc28.cyan(m.service)} ${stateColor(`[${stateLabel}]`)}`);
|
|
25461
25831
|
console.log(` label: ${m.label}`);
|
|
25462
25832
|
console.log(` type: ${m.type}`);
|
|
25463
25833
|
if (m.envName) console.log(` env var: ${m.envName}`);
|
|
@@ -25472,15 +25842,15 @@ function registerMcpStatus(cmd) {
|
|
|
25472
25842
|
// src/commands/mcp/import.ts
|
|
25473
25843
|
init_output();
|
|
25474
25844
|
import * as readline3 from "node:readline";
|
|
25475
|
-
import
|
|
25845
|
+
import pc29 from "picocolors";
|
|
25476
25846
|
|
|
25477
25847
|
// src/commands/mcp/import-discovery.ts
|
|
25478
|
-
import * as
|
|
25479
|
-
import * as
|
|
25480
|
-
import * as
|
|
25848
|
+
import * as fs45 from "node:fs";
|
|
25849
|
+
import * as os27 from "node:os";
|
|
25850
|
+
import * as path47 from "node:path";
|
|
25481
25851
|
function readJsonFile(filePath) {
|
|
25482
25852
|
try {
|
|
25483
|
-
const raw =
|
|
25853
|
+
const raw = fs45.readFileSync(filePath, "utf-8");
|
|
25484
25854
|
return JSON.parse(raw);
|
|
25485
25855
|
} catch {
|
|
25486
25856
|
return null;
|
|
@@ -25509,24 +25879,24 @@ function extractMcpServers(obj, source, sourceLabel) {
|
|
|
25509
25879
|
}
|
|
25510
25880
|
function getClaudeDesktopPath() {
|
|
25511
25881
|
if (process.platform === "darwin") {
|
|
25512
|
-
return
|
|
25882
|
+
return path47.join(os27.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
25513
25883
|
}
|
|
25514
25884
|
if (process.platform === "win32") {
|
|
25515
|
-
const appData = process.env["APPDATA"] ??
|
|
25516
|
-
return
|
|
25885
|
+
const appData = process.env["APPDATA"] ?? path47.join(os27.homedir(), "AppData", "Roaming");
|
|
25886
|
+
return path47.join(appData, "Claude", "claude_desktop_config.json");
|
|
25517
25887
|
}
|
|
25518
|
-
return
|
|
25888
|
+
return path47.join(os27.homedir(), ".config", "Claude", "claude_desktop_config.json");
|
|
25519
25889
|
}
|
|
25520
25890
|
function getOlamRepoPaths() {
|
|
25521
25891
|
const configPaths = [
|
|
25522
|
-
|
|
25523
|
-
|
|
25892
|
+
path47.join(os27.homedir(), ".olam", "config.yaml"),
|
|
25893
|
+
path47.join(process.cwd(), ".olam", "config.yaml")
|
|
25524
25894
|
];
|
|
25525
25895
|
const paths = [];
|
|
25526
25896
|
for (const configPath of configPaths) {
|
|
25527
|
-
if (!
|
|
25897
|
+
if (!fs45.existsSync(configPath)) continue;
|
|
25528
25898
|
try {
|
|
25529
|
-
const raw =
|
|
25899
|
+
const raw = fs45.readFileSync(configPath, "utf-8");
|
|
25530
25900
|
const repoMatches = [...raw.matchAll(/path:\s*["']?([^\s"'\n]+)/g)];
|
|
25531
25901
|
for (const m of repoMatches) {
|
|
25532
25902
|
if (m[1]) paths.push(m[1]);
|
|
@@ -25542,7 +25912,7 @@ async function discoverMcpSources(repoPaths) {
|
|
|
25542
25912
|
const sources = [];
|
|
25543
25913
|
const sourceDefs = [
|
|
25544
25914
|
{
|
|
25545
|
-
path:
|
|
25915
|
+
path: path47.join(os27.homedir(), ".claude.json"),
|
|
25546
25916
|
label: "Claude Code (~/.claude.json)"
|
|
25547
25917
|
},
|
|
25548
25918
|
{
|
|
@@ -25550,19 +25920,19 @@ async function discoverMcpSources(repoPaths) {
|
|
|
25550
25920
|
label: "Claude Desktop"
|
|
25551
25921
|
},
|
|
25552
25922
|
{
|
|
25553
|
-
path:
|
|
25923
|
+
path: path47.join(os27.homedir(), ".cursor", "mcp.json"),
|
|
25554
25924
|
label: "Cursor (~/.cursor/mcp.json)"
|
|
25555
25925
|
},
|
|
25556
25926
|
{
|
|
25557
|
-
path:
|
|
25927
|
+
path: path47.join(os27.homedir(), ".codeium", "windsurf", "mcp_config.json"),
|
|
25558
25928
|
label: "Windsurf (~/.codeium/windsurf/mcp_config.json)"
|
|
25559
25929
|
}
|
|
25560
25930
|
];
|
|
25561
25931
|
const resolvedRepoPaths = repoPaths ?? getOlamRepoPaths();
|
|
25562
25932
|
for (const repoPath of resolvedRepoPaths) {
|
|
25563
25933
|
sourceDefs.push({
|
|
25564
|
-
path:
|
|
25565
|
-
label: `.mcp.json (${
|
|
25934
|
+
path: path47.join(repoPath, ".mcp.json"),
|
|
25935
|
+
label: `.mcp.json (${path47.basename(repoPath)})`
|
|
25566
25936
|
});
|
|
25567
25937
|
}
|
|
25568
25938
|
const reads = await Promise.all(
|
|
@@ -25642,13 +26012,13 @@ async function validateMcpEntry(entry) {
|
|
|
25642
26012
|
// src/commands/mcp/import.ts
|
|
25643
26013
|
async function multiSelectPicker(entries) {
|
|
25644
26014
|
if (entries.length === 0) return [];
|
|
25645
|
-
console.log("\n" +
|
|
26015
|
+
console.log("\n" + pc29.bold("Discovered MCP servers:"));
|
|
25646
26016
|
entries.forEach((e, i) => {
|
|
25647
26017
|
console.log(
|
|
25648
|
-
` ${
|
|
26018
|
+
` ${pc29.dim(`[${i + 1}]`)} ${pc29.cyan(e.name.padEnd(20))} ${pc29.dim(e.sourceLabel)}`
|
|
25649
26019
|
);
|
|
25650
26020
|
});
|
|
25651
|
-
console.log("\n" +
|
|
26021
|
+
console.log("\n" + pc29.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
|
|
25652
26022
|
const answer = await new Promise((resolve10) => {
|
|
25653
26023
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
25654
26024
|
rl.question("> ", (ans) => {
|
|
@@ -25675,7 +26045,7 @@ function registerMcpImport(cmd) {
|
|
|
25675
26045
|
const repoPaths = opts.repoPaths ? opts.repoPaths.split(",").map((s) => s.trim()) : void 0;
|
|
25676
26046
|
const { entries, sources, durationMs } = await discoverMcpSources(repoPaths);
|
|
25677
26047
|
if (entries.length === 0) {
|
|
25678
|
-
console.log(
|
|
26048
|
+
console.log(pc29.dim("No MCP servers found in any source path."));
|
|
25679
26049
|
return;
|
|
25680
26050
|
}
|
|
25681
26051
|
printInfo("Sources", sources.length > 0 ? sources.join(", ") : "none");
|
|
@@ -25688,15 +26058,15 @@ function registerMcpImport(cmd) {
|
|
|
25688
26058
|
candidates = filtered;
|
|
25689
26059
|
}
|
|
25690
26060
|
if (skippedCount > 0) {
|
|
25691
|
-
console.log(
|
|
26061
|
+
console.log(pc29.dim(`skipped: ${skippedCount} already registered`));
|
|
25692
26062
|
}
|
|
25693
26063
|
if (candidates.length === 0) {
|
|
25694
|
-
console.log(
|
|
26064
|
+
console.log(pc29.dim("Nothing new to import. Use --reimport to force."));
|
|
25695
26065
|
return;
|
|
25696
26066
|
}
|
|
25697
26067
|
const selected = await multiSelectPicker(candidates);
|
|
25698
26068
|
if (selected.length === 0) {
|
|
25699
|
-
console.log(
|
|
26069
|
+
console.log(pc29.dim("No servers selected."));
|
|
25700
26070
|
return;
|
|
25701
26071
|
}
|
|
25702
26072
|
console.log(`
|
|
@@ -25707,16 +26077,16 @@ Importing ${selected.length} server(s)\u2026`);
|
|
|
25707
26077
|
let validated = false;
|
|
25708
26078
|
let validationReason = "skipped";
|
|
25709
26079
|
if (opts.validate !== false) {
|
|
25710
|
-
process.stdout.write(` ${
|
|
26080
|
+
process.stdout.write(` ${pc29.dim("\u2192")} ${entry.name} validating\u2026 `);
|
|
25711
26081
|
const vr = await validateMcpEntry(entry);
|
|
25712
26082
|
validated = vr.validated;
|
|
25713
26083
|
validationReason = vr.reason;
|
|
25714
26084
|
process.stdout.write(
|
|
25715
|
-
validated ?
|
|
26085
|
+
validated ? pc29.green("ok\n") : pc29.yellow(`unvalidated (${vr.reason})
|
|
25716
26086
|
`)
|
|
25717
26087
|
);
|
|
25718
26088
|
} else {
|
|
25719
|
-
console.log(` ${
|
|
26089
|
+
console.log(` ${pc29.dim("\u2192")} ${entry.name} ${pc29.dim("(validation skipped)")}`);
|
|
25720
26090
|
}
|
|
25721
26091
|
if (validated) validatedCount++;
|
|
25722
26092
|
const result = await client.staticAdd({
|
|
@@ -25731,21 +26101,21 @@ Importing ${selected.length} server(s)\u2026`);
|
|
|
25731
26101
|
}
|
|
25732
26102
|
}
|
|
25733
26103
|
console.log("");
|
|
25734
|
-
console.log(
|
|
26104
|
+
console.log(pc29.green(`\u2713 Imported ${importedCount}/${selected.length}`));
|
|
25735
26105
|
if (validatedCount > 0) {
|
|
25736
|
-
console.log(
|
|
26106
|
+
console.log(pc29.dim(` ${validatedCount} validated, ${importedCount - validatedCount} unvalidated`));
|
|
25737
26107
|
}
|
|
25738
26108
|
});
|
|
25739
26109
|
}
|
|
25740
26110
|
|
|
25741
26111
|
// src/commands/mcp/revoke.ts
|
|
25742
26112
|
init_output();
|
|
25743
|
-
import
|
|
26113
|
+
import pc30 from "picocolors";
|
|
25744
26114
|
function registerMcpRevoke(cmd) {
|
|
25745
26115
|
cmd.command("revoke <user> <world> <service>").description("Revoke a user's MCP service entitlement (multi-tenant mode only)").action(async (user, world, service) => {
|
|
25746
26116
|
const multiTenant = (process.env["OLAM_MCP_MULTI_TENANT"] ?? "").toLowerCase() === "true";
|
|
25747
26117
|
if (!multiTenant) {
|
|
25748
|
-
console.warn(
|
|
26118
|
+
console.warn(pc30.yellow("\u26A0 revocation only meaningful in multi_tenant mode \u2014 no-op"));
|
|
25749
26119
|
return;
|
|
25750
26120
|
}
|
|
25751
26121
|
const baseUrl = process.env["OLAM_MCP_AUTH_SERVICE_URL"] ?? "http://127.0.0.1:9998";
|
|
@@ -25774,8 +26144,8 @@ function registerMcpRevoke(cmd) {
|
|
|
25774
26144
|
process.exitCode = 1;
|
|
25775
26145
|
return;
|
|
25776
26146
|
}
|
|
25777
|
-
console.log(
|
|
25778
|
-
console.log(
|
|
26147
|
+
console.log(pc30.green(`\u2713 Revoked: ${user} / ${world} / ${service}`));
|
|
26148
|
+
console.log(pc30.dim(" Next fetch-creds call returns 403; token cleared on next merge."));
|
|
25779
26149
|
});
|
|
25780
26150
|
}
|
|
25781
26151
|
|
|
@@ -25792,18 +26162,18 @@ function registerMcp(program2) {
|
|
|
25792
26162
|
}
|
|
25793
26163
|
|
|
25794
26164
|
// src/pleri-config.ts
|
|
25795
|
-
import * as
|
|
25796
|
-
import * as
|
|
26165
|
+
import * as fs46 from "node:fs";
|
|
26166
|
+
import * as path48 from "node:path";
|
|
25797
26167
|
function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
|
|
25798
26168
|
if (process.env.PLERI_BASE_URL) {
|
|
25799
26169
|
return true;
|
|
25800
26170
|
}
|
|
25801
|
-
const configPath =
|
|
25802
|
-
if (!
|
|
26171
|
+
const configPath = path48.join(configDir, "config.yaml");
|
|
26172
|
+
if (!fs46.existsSync(configPath)) {
|
|
25803
26173
|
return false;
|
|
25804
26174
|
}
|
|
25805
26175
|
try {
|
|
25806
|
-
const contents =
|
|
26176
|
+
const contents = fs46.readFileSync(configPath, "utf8");
|
|
25807
26177
|
return /^[^#\n]*\bpleri:/m.test(contents);
|
|
25808
26178
|
} catch {
|
|
25809
26179
|
return false;
|
|
@@ -25823,6 +26193,7 @@ registerList(program);
|
|
|
25823
26193
|
registerStatus(program);
|
|
25824
26194
|
registerDestroy(program);
|
|
25825
26195
|
registerClean(program);
|
|
26196
|
+
registerImplode(program);
|
|
25826
26197
|
registerEnter(program);
|
|
25827
26198
|
registerCrystallize(program, { hidden: !isPleriConfigured() });
|
|
25828
26199
|
registerPr(program);
|