@pleri/olam-cli 0.1.56 → 0.1.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/services.test.d.ts +8 -0
- package/dist/__tests__/services.test.d.ts.map +1 -0
- package/dist/__tests__/services.test.js +185 -0
- package/dist/__tests__/services.test.js.map +1 -0
- package/dist/commands/__tests__/__fixtures__/upgrade-helpers.d.ts +6 -0
- package/dist/commands/__tests__/__fixtures__/upgrade-helpers.d.ts.map +1 -0
- package/dist/commands/__tests__/__fixtures__/upgrade-helpers.js +26 -0
- package/dist/commands/__tests__/__fixtures__/upgrade-helpers.js.map +1 -0
- package/dist/commands/__tests__/upgrade.all-three.test.js +1 -13
- package/dist/commands/__tests__/upgrade.all-three.test.js.map +1 -1
- package/dist/commands/__tests__/upgrade.compose-path.test.js +1 -13
- package/dist/commands/__tests__/upgrade.compose-path.test.js.map +1 -1
- package/dist/commands/__tests__/upgrade.olam-tag.test.js +1 -14
- package/dist/commands/__tests__/upgrade.olam-tag.test.js.map +1 -1
- package/dist/commands/__tests__/upgrade.recreate.test.js +1 -13
- package/dist/commands/__tests__/upgrade.recreate.test.js.map +1 -1
- package/dist/commands/__tests__/upgrade.rollback.test.js +1 -21
- package/dist/commands/__tests__/upgrade.rollback.test.js.map +1 -1
- package/dist/commands/__tests__/upgrade.smoke.test.js +1 -21
- package/dist/commands/__tests__/upgrade.smoke.test.js.map +1 -1
- package/dist/commands/__tests__/upgrade.swap.test.js +1 -22
- package/dist/commands/__tests__/upgrade.swap.test.js.map +1 -1
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +15 -38
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/bootstrap.d.ts +2 -0
- package/dist/commands/bootstrap.d.ts.map +1 -1
- package/dist/commands/bootstrap.js +3 -3
- package/dist/commands/bootstrap.js.map +1 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +1 -9
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/services.d.ts +39 -0
- package/dist/commands/services.d.ts.map +1 -0
- package/dist/commands/services.js +220 -0
- package/dist/commands/services.js.map +1 -0
- package/dist/commands/upgrade.d.ts +11 -0
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +70 -6
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/image-digests.json +4 -3
- package/dist/index.js +953 -1023
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +258 -370
- package/host-cp/src/server.mjs +9 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -460,8 +460,8 @@ var init_parseUtil = __esm({
|
|
|
460
460
|
init_errors();
|
|
461
461
|
init_en();
|
|
462
462
|
makeIssue = (params) => {
|
|
463
|
-
const { data, path:
|
|
464
|
-
const fullPath = [...
|
|
463
|
+
const { data, path: path44, errorMaps, issueData } = params;
|
|
464
|
+
const fullPath = [...path44, ...issueData.path || []];
|
|
465
465
|
const fullIssue = {
|
|
466
466
|
...issueData,
|
|
467
467
|
path: fullPath
|
|
@@ -769,11 +769,11 @@ var init_types = __esm({
|
|
|
769
769
|
init_parseUtil();
|
|
770
770
|
init_util();
|
|
771
771
|
ParseInputLazyPath = class {
|
|
772
|
-
constructor(parent, value,
|
|
772
|
+
constructor(parent, value, path44, key) {
|
|
773
773
|
this._cachedPath = [];
|
|
774
774
|
this.parent = parent;
|
|
775
775
|
this.data = value;
|
|
776
|
-
this._path =
|
|
776
|
+
this._path = path44;
|
|
777
777
|
this._key = key;
|
|
778
778
|
}
|
|
779
779
|
get path() {
|
|
@@ -4254,7 +4254,7 @@ import YAML from "yaml";
|
|
|
4254
4254
|
function bootstrapStepCmd(entry) {
|
|
4255
4255
|
return typeof entry === "string" ? entry : entry.cmd;
|
|
4256
4256
|
}
|
|
4257
|
-
function refineForbiddenKeys(value,
|
|
4257
|
+
function refineForbiddenKeys(value, path44, ctx, rejectSource) {
|
|
4258
4258
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4259
4259
|
return;
|
|
4260
4260
|
}
|
|
@@ -4262,12 +4262,12 @@ function refineForbiddenKeys(value, path45, ctx, rejectSource) {
|
|
|
4262
4262
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
4263
4263
|
ctx.addIssue({
|
|
4264
4264
|
code: external_exports.ZodIssueCode.custom,
|
|
4265
|
-
path: [...
|
|
4265
|
+
path: [...path44, key],
|
|
4266
4266
|
message: `forbidden key "${key}" (prototype-pollution surface)`
|
|
4267
4267
|
});
|
|
4268
4268
|
continue;
|
|
4269
4269
|
}
|
|
4270
|
-
if (rejectSource &&
|
|
4270
|
+
if (rejectSource && path44.length === 0 && key === "source") {
|
|
4271
4271
|
ctx.addIssue({
|
|
4272
4272
|
code: external_exports.ZodIssueCode.custom,
|
|
4273
4273
|
path: ["source"],
|
|
@@ -4275,21 +4275,21 @@ function refineForbiddenKeys(value, path45, ctx, rejectSource) {
|
|
|
4275
4275
|
});
|
|
4276
4276
|
continue;
|
|
4277
4277
|
}
|
|
4278
|
-
refineForbiddenKeys(value[key], [...
|
|
4278
|
+
refineForbiddenKeys(value[key], [...path44, key], ctx, false);
|
|
4279
4279
|
}
|
|
4280
4280
|
}
|
|
4281
|
-
function rejectForbiddenKeys(value,
|
|
4281
|
+
function rejectForbiddenKeys(value, path44, rejectSource) {
|
|
4282
4282
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4283
4283
|
return;
|
|
4284
4284
|
}
|
|
4285
4285
|
for (const key of Object.keys(value)) {
|
|
4286
4286
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
4287
|
-
throw new Error(`[manifest] ${
|
|
4287
|
+
throw new Error(`[manifest] ${path44}: forbidden key "${key}" (prototype-pollution surface)`);
|
|
4288
4288
|
}
|
|
4289
4289
|
if (rejectSource && key === "source") {
|
|
4290
|
-
throw new Error(`[manifest] ${
|
|
4290
|
+
throw new Error(`[manifest] ${path44}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
|
|
4291
4291
|
}
|
|
4292
|
-
rejectForbiddenKeys(value[key], `${
|
|
4292
|
+
rejectForbiddenKeys(value[key], `${path44}.${key}`, false);
|
|
4293
4293
|
}
|
|
4294
4294
|
}
|
|
4295
4295
|
function unknownTopLevelKeys(parsed) {
|
|
@@ -5280,8 +5280,8 @@ var init_client = __esm({
|
|
|
5280
5280
|
throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
|
|
5281
5281
|
}
|
|
5282
5282
|
}
|
|
5283
|
-
async request(method,
|
|
5284
|
-
const url = `${this.baseUrl}${
|
|
5283
|
+
async request(method, path44, body, attempt = 0) {
|
|
5284
|
+
const url = `${this.baseUrl}${path44}`;
|
|
5285
5285
|
const controller = new AbortController();
|
|
5286
5286
|
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
5287
5287
|
const headers = {};
|
|
@@ -5299,7 +5299,7 @@ var init_client = __esm({
|
|
|
5299
5299
|
} catch (err) {
|
|
5300
5300
|
if (attempt < RETRY_COUNT && isTransient(err)) {
|
|
5301
5301
|
await sleep(RETRY_BACKOFF_MS * (attempt + 1));
|
|
5302
|
-
return this.request(method,
|
|
5302
|
+
return this.request(method, path44, body, attempt + 1);
|
|
5303
5303
|
}
|
|
5304
5304
|
throw err;
|
|
5305
5305
|
} finally {
|
|
@@ -6778,8 +6778,8 @@ var init_provider3 = __esm({
|
|
|
6778
6778
|
// -----------------------------------------------------------------------
|
|
6779
6779
|
// Internal fetch helper
|
|
6780
6780
|
// -----------------------------------------------------------------------
|
|
6781
|
-
async request(
|
|
6782
|
-
const url = `${this.config.workerUrl}${
|
|
6781
|
+
async request(path44, method, body) {
|
|
6782
|
+
const url = `${this.config.workerUrl}${path44}`;
|
|
6783
6783
|
const bearer = await this.config.mintToken();
|
|
6784
6784
|
const headers = {
|
|
6785
6785
|
Authorization: `Bearer ${bearer}`
|
|
@@ -7569,192 +7569,87 @@ var init_hooks_config = __esm({
|
|
|
7569
7569
|
}
|
|
7570
7570
|
});
|
|
7571
7571
|
|
|
7572
|
-
// ../core/dist/world/merge-settings.js
|
|
7573
|
-
import * as fs12 from "node:fs";
|
|
7574
|
-
import * as path13 from "node:path";
|
|
7575
|
-
import * as crypto2 from "node:crypto";
|
|
7576
|
-
function mergeHomeSettingsJson(filePath, options) {
|
|
7577
|
-
let settings;
|
|
7578
|
-
try {
|
|
7579
|
-
settings = readSettings(filePath);
|
|
7580
|
-
} catch (err) {
|
|
7581
|
-
throw new Error(`merge-settings: failed to parse existing settings.json: ${err?.message ?? err}`);
|
|
7582
|
-
}
|
|
7583
|
-
let changed = false;
|
|
7584
|
-
if (options.ensureHook) {
|
|
7585
|
-
const { stage, sentinel, entry } = options.ensureHook;
|
|
7586
|
-
if (!settings.hooks || typeof settings.hooks !== "object") {
|
|
7587
|
-
settings = { ...settings, hooks: {} };
|
|
7588
|
-
changed = true;
|
|
7589
|
-
}
|
|
7590
|
-
const hooks = settings.hooks;
|
|
7591
|
-
if (!Array.isArray(hooks[stage])) {
|
|
7592
|
-
settings = {
|
|
7593
|
-
...settings,
|
|
7594
|
-
hooks: { ...hooks, [stage]: [] }
|
|
7595
|
-
};
|
|
7596
|
-
changed = true;
|
|
7597
|
-
}
|
|
7598
|
-
const stageArr = settings.hooks[stage];
|
|
7599
|
-
if (isHookSentinelPresent(stageArr, sentinel)) {
|
|
7600
|
-
if (!changed) {
|
|
7601
|
-
return { status: "already-present", message: `hook already present at ${filePath}` };
|
|
7602
|
-
}
|
|
7603
|
-
} else {
|
|
7604
|
-
settings = {
|
|
7605
|
-
...settings,
|
|
7606
|
-
hooks: {
|
|
7607
|
-
...settings.hooks,
|
|
7608
|
-
[stage]: [...stageArr, entry]
|
|
7609
|
-
}
|
|
7610
|
-
};
|
|
7611
|
-
changed = true;
|
|
7612
|
-
}
|
|
7613
|
-
}
|
|
7614
|
-
if (options.env) {
|
|
7615
|
-
const existingEnv = settings.env && typeof settings.env === "object" ? settings.env : {};
|
|
7616
|
-
const mergedEnv = { ...existingEnv, ...options.env };
|
|
7617
|
-
const sameKeys = Object.keys(mergedEnv).length === Object.keys(existingEnv).length && Object.keys(mergedEnv).every((k) => existingEnv[k] === mergedEnv[k]);
|
|
7618
|
-
if (!sameKeys) {
|
|
7619
|
-
settings = { ...settings, env: mergedEnv };
|
|
7620
|
-
changed = true;
|
|
7621
|
-
}
|
|
7622
|
-
}
|
|
7623
|
-
if (!changed) {
|
|
7624
|
-
return { status: "no-op", message: `no change needed at ${filePath}` };
|
|
7625
|
-
}
|
|
7626
|
-
try {
|
|
7627
|
-
atomicWriteJson(filePath, settings);
|
|
7628
|
-
} catch (err) {
|
|
7629
|
-
throw new Error(`merge-settings: failed to write settings.json: ${err?.message ?? err}`);
|
|
7630
|
-
}
|
|
7631
|
-
return { status: "installed", message: `settings.json updated at ${filePath}` };
|
|
7632
|
-
}
|
|
7633
|
-
function readSettings(filePath) {
|
|
7634
|
-
if (!fs12.existsSync(filePath)) {
|
|
7635
|
-
return {};
|
|
7636
|
-
}
|
|
7637
|
-
const raw = fs12.readFileSync(filePath, "utf-8");
|
|
7638
|
-
if (!raw.trim())
|
|
7639
|
-
return {};
|
|
7640
|
-
return JSON.parse(raw);
|
|
7641
|
-
}
|
|
7642
|
-
function isHookSentinelPresent(matchers, sentinel) {
|
|
7643
|
-
for (const matcher of matchers) {
|
|
7644
|
-
if (typeof matcher?.command === "string" && matcher.command.includes(sentinel)) {
|
|
7645
|
-
return true;
|
|
7646
|
-
}
|
|
7647
|
-
if (Array.isArray(matcher?.hooks)) {
|
|
7648
|
-
for (const h of matcher.hooks) {
|
|
7649
|
-
if (typeof h?.command === "string" && h.command.includes(sentinel)) {
|
|
7650
|
-
return true;
|
|
7651
|
-
}
|
|
7652
|
-
}
|
|
7653
|
-
}
|
|
7654
|
-
}
|
|
7655
|
-
return false;
|
|
7656
|
-
}
|
|
7657
|
-
function atomicWriteJson(filePath, data) {
|
|
7658
|
-
const dir = path13.dirname(filePath);
|
|
7659
|
-
fs12.mkdirSync(dir, { recursive: true });
|
|
7660
|
-
const rand = crypto2.randomBytes(6).toString("hex");
|
|
7661
|
-
const tmp = `${filePath}.tmp.${process.pid}.${rand}`;
|
|
7662
|
-
const json = JSON.stringify(data, null, 2) + "\n";
|
|
7663
|
-
fs12.writeFileSync(tmp, json, { mode: 420 });
|
|
7664
|
-
fs12.renameSync(tmp, filePath);
|
|
7665
|
-
}
|
|
7666
|
-
var init_merge_settings = __esm({
|
|
7667
|
-
"../core/dist/world/merge-settings.js"() {
|
|
7668
|
-
"use strict";
|
|
7669
|
-
}
|
|
7670
|
-
});
|
|
7671
|
-
|
|
7672
7572
|
// ../core/dist/world/env-setup.js
|
|
7673
|
-
import * as
|
|
7674
|
-
import * as
|
|
7573
|
+
import * as crypto2 from "node:crypto";
|
|
7574
|
+
import * as fs12 from "node:fs";
|
|
7675
7575
|
import * as os8 from "node:os";
|
|
7676
|
-
import * as
|
|
7576
|
+
import * as path13 from "node:path";
|
|
7677
7577
|
import { globSync } from "node:fs";
|
|
7678
7578
|
function copyClaudeConfig(workspacePath, homeDir, configCtx) {
|
|
7679
|
-
const sourceClaudeDir =
|
|
7680
|
-
const destClaudeDir =
|
|
7579
|
+
const sourceClaudeDir = path13.join(homeDir ?? os8.homedir(), ".claude");
|
|
7580
|
+
const destClaudeDir = path13.join(workspacePath, ".claude-host-config");
|
|
7681
7581
|
void configCtx;
|
|
7682
|
-
if (!
|
|
7582
|
+
if (!fs12.existsSync(sourceClaudeDir))
|
|
7683
7583
|
return;
|
|
7684
|
-
|
|
7685
|
-
const settingsPath =
|
|
7584
|
+
fs12.mkdirSync(destClaudeDir, { recursive: true });
|
|
7585
|
+
const settingsPath = path13.join(sourceClaudeDir, "settings.json");
|
|
7686
7586
|
let settings = {};
|
|
7687
|
-
if (
|
|
7587
|
+
if (fs12.existsSync(settingsPath)) {
|
|
7688
7588
|
try {
|
|
7689
|
-
settings = JSON.parse(
|
|
7589
|
+
settings = JSON.parse(fs12.readFileSync(settingsPath, "utf-8"));
|
|
7690
7590
|
delete settings["hooks"];
|
|
7691
7591
|
} catch {
|
|
7692
7592
|
}
|
|
7693
7593
|
}
|
|
7694
7594
|
const hooksConfig = generateHooksConfig(DEFAULT_HOOK_SERVER_URL);
|
|
7695
7595
|
settings["hooks"] = hooksConfig["hooks"];
|
|
7696
|
-
|
|
7697
|
-
const claudeMdPath =
|
|
7698
|
-
if (
|
|
7699
|
-
|
|
7596
|
+
fs12.writeFileSync(path13.join(destClaudeDir, "settings.json"), JSON.stringify(settings, null, 2));
|
|
7597
|
+
const claudeMdPath = path13.join(sourceClaudeDir, "CLAUDE.md");
|
|
7598
|
+
if (fs12.existsSync(claudeMdPath)) {
|
|
7599
|
+
fs12.copyFileSync(claudeMdPath, path13.join(destClaudeDir, "CLAUDE.md"));
|
|
7700
7600
|
}
|
|
7701
|
-
const rulesDir =
|
|
7702
|
-
if (
|
|
7703
|
-
copyDirRecursive(rulesDir,
|
|
7601
|
+
const rulesDir = path13.join(sourceClaudeDir, "rules");
|
|
7602
|
+
if (fs12.existsSync(rulesDir)) {
|
|
7603
|
+
copyDirRecursive(rulesDir, path13.join(destClaudeDir, "rules"));
|
|
7704
7604
|
}
|
|
7705
|
-
const agentsDir =
|
|
7706
|
-
if (
|
|
7707
|
-
copyDirRecursive(agentsDir,
|
|
7605
|
+
const agentsDir = path13.join(sourceClaudeDir, "agents");
|
|
7606
|
+
if (fs12.existsSync(agentsDir)) {
|
|
7607
|
+
copyDirRecursive(agentsDir, path13.join(destClaudeDir, "agents"));
|
|
7708
7608
|
}
|
|
7709
|
-
const pluginsDir =
|
|
7710
|
-
if (
|
|
7711
|
-
copyDirRecursive(pluginsDir,
|
|
7609
|
+
const pluginsDir = path13.join(sourceClaudeDir, "plugins");
|
|
7610
|
+
if (fs12.existsSync(pluginsDir)) {
|
|
7611
|
+
copyDirRecursive(pluginsDir, path13.join(destClaudeDir, "plugins"), 0, SKIP_FILES);
|
|
7712
7612
|
}
|
|
7713
|
-
const skillsDir =
|
|
7714
|
-
if (
|
|
7715
|
-
copyDirRecursive(skillsDir,
|
|
7613
|
+
const skillsDir = path13.join(sourceClaudeDir, "skills");
|
|
7614
|
+
if (fs12.existsSync(skillsDir)) {
|
|
7615
|
+
copyDirRecursive(skillsDir, path13.join(destClaudeDir, "skills"));
|
|
7716
7616
|
}
|
|
7717
|
-
const scriptsDir =
|
|
7718
|
-
if (
|
|
7719
|
-
copyDirRecursive(scriptsDir,
|
|
7617
|
+
const scriptsDir = path13.join(sourceClaudeDir, "scripts");
|
|
7618
|
+
if (fs12.existsSync(scriptsDir)) {
|
|
7619
|
+
copyDirRecursive(scriptsDir, path13.join(destClaudeDir, "scripts"));
|
|
7720
7620
|
}
|
|
7721
7621
|
applyProjectClaudeOverlay(workspacePath, destClaudeDir);
|
|
7722
7622
|
writeStrippedMcpServersSnapshot(homeDir ?? os8.homedir(), workspacePath, destClaudeDir);
|
|
7723
|
-
if (configCtx != null && configCtx.worlds_default?.agent_teams_enabled !== false) {
|
|
7724
|
-
mergeHomeSettingsJson(path14.join(destClaudeDir, "settings.json"), {
|
|
7725
|
-
env: { CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS: "1" }
|
|
7726
|
-
});
|
|
7727
|
-
}
|
|
7728
7623
|
}
|
|
7729
7624
|
function applyProjectClaudeOverlay(workspacePath, destClaudeDir) {
|
|
7730
|
-
const projectClaudeDir =
|
|
7731
|
-
if (!
|
|
7625
|
+
const projectClaudeDir = path13.join(workspacePath, ".claude");
|
|
7626
|
+
if (!fs12.existsSync(projectClaudeDir))
|
|
7732
7627
|
return;
|
|
7733
|
-
const projectSettingsPath =
|
|
7734
|
-
const destSettingsPath =
|
|
7735
|
-
if (
|
|
7628
|
+
const projectSettingsPath = path13.join(projectClaudeDir, "settings.json");
|
|
7629
|
+
const destSettingsPath = path13.join(destClaudeDir, "settings.json");
|
|
7630
|
+
if (fs12.existsSync(projectSettingsPath)) {
|
|
7736
7631
|
try {
|
|
7737
|
-
const projectSettings = JSON.parse(
|
|
7632
|
+
const projectSettings = JSON.parse(fs12.readFileSync(projectSettingsPath, "utf-8"));
|
|
7738
7633
|
delete projectSettings["hooks"];
|
|
7739
|
-
const existing =
|
|
7634
|
+
const existing = fs12.existsSync(destSettingsPath) ? JSON.parse(fs12.readFileSync(destSettingsPath, "utf-8")) : {};
|
|
7740
7635
|
const merged = { ...existing, ...projectSettings, hooks: existing["hooks"] };
|
|
7741
|
-
|
|
7636
|
+
fs12.writeFileSync(destSettingsPath, JSON.stringify(merged, null, 2));
|
|
7742
7637
|
} catch {
|
|
7743
7638
|
}
|
|
7744
7639
|
}
|
|
7745
|
-
const projectClaudeMd =
|
|
7746
|
-
if (
|
|
7747
|
-
|
|
7640
|
+
const projectClaudeMd = path13.join(projectClaudeDir, "CLAUDE.md");
|
|
7641
|
+
if (fs12.existsSync(projectClaudeMd)) {
|
|
7642
|
+
fs12.copyFileSync(projectClaudeMd, path13.join(destClaudeDir, "CLAUDE.md"));
|
|
7748
7643
|
}
|
|
7749
|
-
const projectAgentsMd =
|
|
7750
|
-
if (
|
|
7751
|
-
|
|
7644
|
+
const projectAgentsMd = path13.join(projectClaudeDir, "AGENTS.md");
|
|
7645
|
+
if (fs12.existsSync(projectAgentsMd)) {
|
|
7646
|
+
fs12.copyFileSync(projectAgentsMd, path13.join(destClaudeDir, "AGENTS.md"));
|
|
7752
7647
|
}
|
|
7753
7648
|
for (const subdir of ["rules", "agents", "plugins", "skills", "scripts"]) {
|
|
7754
|
-
const projectSubdir =
|
|
7755
|
-
if (
|
|
7649
|
+
const projectSubdir = path13.join(projectClaudeDir, subdir);
|
|
7650
|
+
if (fs12.existsSync(projectSubdir)) {
|
|
7756
7651
|
const skip = subdir === "plugins" ? SKIP_FILES : /* @__PURE__ */ new Set();
|
|
7757
|
-
copyDirRecursive(projectSubdir,
|
|
7652
|
+
copyDirRecursive(projectSubdir, path13.join(destClaudeDir, subdir), 0, skip);
|
|
7758
7653
|
}
|
|
7759
7654
|
}
|
|
7760
7655
|
}
|
|
@@ -7784,8 +7679,8 @@ function stripMcpServers(mcpServers) {
|
|
|
7784
7679
|
return out;
|
|
7785
7680
|
}
|
|
7786
7681
|
function writeStrippedMcpServersSnapshot(homeDir, workspacePath, destClaudeDir) {
|
|
7787
|
-
const hostMcpServers = readMcpServersFromFile(
|
|
7788
|
-
const projectMcpServers = readMcpServersFromFile(
|
|
7682
|
+
const hostMcpServers = readMcpServersFromFile(path13.join(homeDir, ".claude.json"));
|
|
7683
|
+
const projectMcpServers = readMcpServersFromFile(path13.join(workspacePath, ".mcp.json"));
|
|
7789
7684
|
if (Object.keys(hostMcpServers).length === 0 && Object.keys(projectMcpServers).length === 0) {
|
|
7790
7685
|
return;
|
|
7791
7686
|
}
|
|
@@ -7794,11 +7689,11 @@ function writeStrippedMcpServersSnapshot(homeDir, workspacePath, destClaudeDir)
|
|
|
7794
7689
|
...stripMcpServers(projectMcpServers)
|
|
7795
7690
|
};
|
|
7796
7691
|
const output = { mcpServers: stripped };
|
|
7797
|
-
|
|
7692
|
+
fs12.writeFileSync(path13.join(destClaudeDir, ".claude.json"), JSON.stringify(output, null, 2), { mode: 384 });
|
|
7798
7693
|
}
|
|
7799
7694
|
function writeWorldEntitlementsJson(workspacePath, configCtx) {
|
|
7800
|
-
const olamDir =
|
|
7801
|
-
|
|
7695
|
+
const olamDir = path13.join(workspacePath, ".olam");
|
|
7696
|
+
fs12.mkdirSync(olamDir, { recursive: true });
|
|
7802
7697
|
const resolvedRepos = configCtx.repos.map((repo) => {
|
|
7803
7698
|
const repoEntitlement = repo;
|
|
7804
7699
|
return {
|
|
@@ -7812,14 +7707,14 @@ function writeWorldEntitlementsJson(workspacePath, configCtx) {
|
|
|
7812
7707
|
worlds_default: configCtx.worlds_default,
|
|
7813
7708
|
repos: resolvedRepos
|
|
7814
7709
|
};
|
|
7815
|
-
const filePath =
|
|
7816
|
-
|
|
7710
|
+
const filePath = path13.join(olamDir, "world-entitlements.json");
|
|
7711
|
+
fs12.writeFileSync(filePath, JSON.stringify(resolved, null, 2), { mode: 420 });
|
|
7817
7712
|
}
|
|
7818
7713
|
function readMcpServersFromFile(filePath) {
|
|
7819
|
-
if (!
|
|
7714
|
+
if (!fs12.existsSync(filePath))
|
|
7820
7715
|
return {};
|
|
7821
7716
|
try {
|
|
7822
|
-
const raw =
|
|
7717
|
+
const raw = fs12.readFileSync(filePath, "utf-8");
|
|
7823
7718
|
if (!raw.trim())
|
|
7824
7719
|
return {};
|
|
7825
7720
|
const parsed = JSON.parse(raw);
|
|
@@ -7834,8 +7729,8 @@ function readMcpServersFromFile(filePath) {
|
|
|
7834
7729
|
function copyDirRecursive(src, dest, depth = 0, skipFiles = /* @__PURE__ */ new Set()) {
|
|
7835
7730
|
if (depth > 10)
|
|
7836
7731
|
return;
|
|
7837
|
-
|
|
7838
|
-
for (const entry of
|
|
7732
|
+
fs12.mkdirSync(dest, { recursive: true });
|
|
7733
|
+
for (const entry of fs12.readdirSync(src, { withFileTypes: true })) {
|
|
7839
7734
|
const { name } = entry;
|
|
7840
7735
|
if (skipFiles.has(name))
|
|
7841
7736
|
continue;
|
|
@@ -7845,12 +7740,12 @@ function copyDirRecursive(src, dest, depth = 0, skipFiles = /* @__PURE__ */ new
|
|
|
7845
7740
|
continue;
|
|
7846
7741
|
if (entry.isDirectory() && SKIP_DIRS.has(name))
|
|
7847
7742
|
continue;
|
|
7848
|
-
const srcPath =
|
|
7849
|
-
const destPath =
|
|
7743
|
+
const srcPath = path13.join(src, name);
|
|
7744
|
+
const destPath = path13.join(dest, name);
|
|
7850
7745
|
if (entry.isSymbolicLink()) {
|
|
7851
7746
|
let stat;
|
|
7852
7747
|
try {
|
|
7853
|
-
stat =
|
|
7748
|
+
stat = fs12.statSync(srcPath);
|
|
7854
7749
|
} catch {
|
|
7855
7750
|
continue;
|
|
7856
7751
|
}
|
|
@@ -7859,12 +7754,12 @@ function copyDirRecursive(src, dest, depth = 0, skipFiles = /* @__PURE__ */ new
|
|
|
7859
7754
|
continue;
|
|
7860
7755
|
copyDirRecursive(srcPath, destPath, depth + 1, skipFiles);
|
|
7861
7756
|
} else if (stat.isFile()) {
|
|
7862
|
-
|
|
7757
|
+
fs12.copyFileSync(srcPath, destPath);
|
|
7863
7758
|
}
|
|
7864
7759
|
} else if (entry.isDirectory()) {
|
|
7865
7760
|
copyDirRecursive(srcPath, destPath, depth + 1, skipFiles);
|
|
7866
7761
|
} else {
|
|
7867
|
-
|
|
7762
|
+
fs12.copyFileSync(srcPath, destPath);
|
|
7868
7763
|
}
|
|
7869
7764
|
}
|
|
7870
7765
|
}
|
|
@@ -8002,9 +7897,9 @@ function setupWorldEnv(repos, workspacePath, serviceEnv, crossRepoEnv = {}, conf
|
|
|
8002
7897
|
}
|
|
8003
7898
|
}
|
|
8004
7899
|
for (const repo of repos) {
|
|
8005
|
-
const worktreePath =
|
|
7900
|
+
const worktreePath = path13.join(workspacePath, repo.name);
|
|
8006
7901
|
const sourcePath = repo.path;
|
|
8007
|
-
if (!sourcePath || !
|
|
7902
|
+
if (!sourcePath || !fs12.existsSync(worktreePath))
|
|
8008
7903
|
continue;
|
|
8009
7904
|
const envSetup = repo.env_setup;
|
|
8010
7905
|
if (!envSetup)
|
|
@@ -8023,23 +7918,23 @@ function setupWorldEnv(repos, workspacePath, serviceEnv, crossRepoEnv = {}, conf
|
|
|
8023
7918
|
}
|
|
8024
7919
|
}
|
|
8025
7920
|
function copyMatchingFiles(sourcePath, destPath, pattern) {
|
|
8026
|
-
const fullPattern =
|
|
7921
|
+
const fullPattern = path13.join(sourcePath, pattern);
|
|
8027
7922
|
if (!pattern.includes("*")) {
|
|
8028
|
-
const sourceFile =
|
|
8029
|
-
const destFile =
|
|
8030
|
-
if (
|
|
8031
|
-
|
|
8032
|
-
|
|
7923
|
+
const sourceFile = path13.join(sourcePath, pattern);
|
|
7924
|
+
const destFile = path13.join(destPath, pattern);
|
|
7925
|
+
if (fs12.existsSync(sourceFile)) {
|
|
7926
|
+
fs12.mkdirSync(path13.dirname(destFile), { recursive: true });
|
|
7927
|
+
fs12.copyFileSync(sourceFile, destFile);
|
|
8033
7928
|
}
|
|
8034
7929
|
return;
|
|
8035
7930
|
}
|
|
8036
7931
|
try {
|
|
8037
7932
|
const matches2 = globSync(fullPattern);
|
|
8038
7933
|
for (const match2 of matches2) {
|
|
8039
|
-
const relative2 =
|
|
8040
|
-
const dest =
|
|
8041
|
-
|
|
8042
|
-
|
|
7934
|
+
const relative2 = path13.relative(sourcePath, match2);
|
|
7935
|
+
const dest = path13.join(destPath, relative2);
|
|
7936
|
+
fs12.mkdirSync(path13.dirname(dest), { recursive: true });
|
|
7937
|
+
fs12.copyFileSync(match2, dest);
|
|
8043
7938
|
}
|
|
8044
7939
|
} catch {
|
|
8045
7940
|
}
|
|
@@ -8047,14 +7942,14 @@ function copyMatchingFiles(sourcePath, destPath, pattern) {
|
|
|
8047
7942
|
function generateEnvFromExample(repoPath, overrides) {
|
|
8048
7943
|
const exampleFiles = [".env.example", ".env.sample", ".env.local.example"];
|
|
8049
7944
|
for (const exampleName of exampleFiles) {
|
|
8050
|
-
const examplePath =
|
|
8051
|
-
if (!
|
|
7945
|
+
const examplePath = path13.join(repoPath, exampleName);
|
|
7946
|
+
if (!fs12.existsSync(examplePath))
|
|
8052
7947
|
continue;
|
|
8053
7948
|
const targetName = exampleName.replace(".example", "").replace(".sample", "");
|
|
8054
|
-
const targetPath =
|
|
8055
|
-
if (
|
|
7949
|
+
const targetPath = path13.join(repoPath, targetName);
|
|
7950
|
+
if (fs12.existsSync(targetPath))
|
|
8056
7951
|
continue;
|
|
8057
|
-
const template =
|
|
7952
|
+
const template = fs12.readFileSync(examplePath, "utf-8");
|
|
8058
7953
|
const generated = template.split("\n").map((line) => {
|
|
8059
7954
|
const match2 = /^([A-Z_][A-Z0-9_]*)=(.*)$/.exec(line);
|
|
8060
7955
|
if (match2) {
|
|
@@ -8065,13 +7960,13 @@ function generateEnvFromExample(repoPath, overrides) {
|
|
|
8065
7960
|
}
|
|
8066
7961
|
return line;
|
|
8067
7962
|
}).join("\n");
|
|
8068
|
-
|
|
7963
|
+
fs12.writeFileSync(targetPath, generated);
|
|
8069
7964
|
}
|
|
8070
7965
|
}
|
|
8071
7966
|
function applyEnvOverrides(repoPath, overrides) {
|
|
8072
|
-
const envPath =
|
|
8073
|
-
if (
|
|
8074
|
-
const existing =
|
|
7967
|
+
const envPath = path13.join(repoPath, ".env");
|
|
7968
|
+
if (fs12.existsSync(envPath)) {
|
|
7969
|
+
const existing = fs12.readFileSync(envPath, "utf-8");
|
|
8075
7970
|
const existingKeys = new Set(existing.split("\n").map((l) => l.split("=")[0]?.trim()).filter(Boolean));
|
|
8076
7971
|
const additions = [];
|
|
8077
7972
|
for (const [key, value] of Object.entries(overrides)) {
|
|
@@ -8080,7 +7975,7 @@ function applyEnvOverrides(repoPath, overrides) {
|
|
|
8080
7975
|
}
|
|
8081
7976
|
}
|
|
8082
7977
|
if (additions.length > 0) {
|
|
8083
|
-
|
|
7978
|
+
fs12.appendFileSync(envPath, "\n# Olam injected\n" + additions.join("\n") + "\n");
|
|
8084
7979
|
}
|
|
8085
7980
|
}
|
|
8086
7981
|
}
|
|
@@ -8089,7 +7984,6 @@ var init_env_setup = __esm({
|
|
|
8089
7984
|
"../core/dist/world/env-setup.js"() {
|
|
8090
7985
|
"use strict";
|
|
8091
7986
|
init_hooks_config();
|
|
8092
|
-
init_merge_settings();
|
|
8093
7987
|
MCP_SERVER_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
8094
7988
|
"command",
|
|
8095
7989
|
"args",
|
|
@@ -8153,9 +8047,9 @@ var init_env_setup = __esm({
|
|
|
8153
8047
|
|
|
8154
8048
|
// ../core/dist/world/baseline-diff.js
|
|
8155
8049
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
8156
|
-
import * as
|
|
8050
|
+
import * as fs13 from "node:fs";
|
|
8157
8051
|
import * as os9 from "node:os";
|
|
8158
|
-
import * as
|
|
8052
|
+
import * as path14 from "node:path";
|
|
8159
8053
|
function expandHome(p, homedir22) {
|
|
8160
8054
|
return p.replace(/^~(?=$|\/|\\)/, homedir22());
|
|
8161
8055
|
}
|
|
@@ -8181,9 +8075,9 @@ ${stderr}`;
|
|
|
8181
8075
|
function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
8182
8076
|
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync3(cmd, args, opts));
|
|
8183
8077
|
const homedir22 = deps.homedir ?? (() => os9.homedir());
|
|
8184
|
-
const baselineDir =
|
|
8078
|
+
const baselineDir = path14.join(workspacePath, ".olam", "baseline");
|
|
8185
8079
|
try {
|
|
8186
|
-
|
|
8080
|
+
fs13.mkdirSync(baselineDir, { recursive: true });
|
|
8187
8081
|
} catch (err) {
|
|
8188
8082
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8189
8083
|
console.warn(`[baseline-diff] mkdir ${baselineDir} failed: ${msg}; reaper will see no baseline at all`);
|
|
@@ -8195,9 +8089,9 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
|
8195
8089
|
if (!repo.path)
|
|
8196
8090
|
continue;
|
|
8197
8091
|
const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
|
|
8198
|
-
const outPath =
|
|
8092
|
+
const outPath = path14.join(baselineDir, filename);
|
|
8199
8093
|
const repoPath = expandHome(repo.path, homedir22);
|
|
8200
|
-
if (!
|
|
8094
|
+
if (!fs13.existsSync(repoPath)) {
|
|
8201
8095
|
writeBaselineFile(outPath, `# repo: ${repo.name}
|
|
8202
8096
|
# (skipped: path ${repoPath} does not exist)
|
|
8203
8097
|
`);
|
|
@@ -8264,7 +8158,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
|
8264
8158
|
}
|
|
8265
8159
|
function writeBaselineFile(outPath, content) {
|
|
8266
8160
|
try {
|
|
8267
|
-
|
|
8161
|
+
fs13.writeFileSync(outPath, content);
|
|
8268
8162
|
} catch (err) {
|
|
8269
8163
|
const msg = err instanceof Error ? err.message : String(err);
|
|
8270
8164
|
console.warn(`[baseline-diff] write to ${outPath} failed: ${msg}`);
|
|
@@ -8272,8 +8166,8 @@ function writeBaselineFile(outPath, content) {
|
|
|
8272
8166
|
}
|
|
8273
8167
|
function stripWorktreeEdits(repos, workspacePath) {
|
|
8274
8168
|
for (const repo of repos) {
|
|
8275
|
-
const worktreePath =
|
|
8276
|
-
if (!
|
|
8169
|
+
const worktreePath = path14.join(workspacePath, repo.name);
|
|
8170
|
+
if (!fs13.existsSync(worktreePath))
|
|
8277
8171
|
continue;
|
|
8278
8172
|
try {
|
|
8279
8173
|
execFileSync3("git", ["checkout", "--", "."], {
|
|
@@ -8310,12 +8204,12 @@ var init_baseline_diff = __esm({
|
|
|
8310
8204
|
});
|
|
8311
8205
|
|
|
8312
8206
|
// ../core/dist/world/context-injection.js
|
|
8313
|
-
import * as
|
|
8314
|
-
import * as
|
|
8207
|
+
import * as fs14 from "node:fs";
|
|
8208
|
+
import * as path15 from "node:path";
|
|
8315
8209
|
function injectWorldContext(opts) {
|
|
8316
8210
|
const { world, task, linearTicketId, claudeMdExtra, taskContext, services, pleriPlaneUrl } = opts;
|
|
8317
|
-
const claudeDir =
|
|
8318
|
-
|
|
8211
|
+
const claudeDir = path15.join(world.workspacePath, ".claude");
|
|
8212
|
+
fs14.mkdirSync(claudeDir, { recursive: true });
|
|
8319
8213
|
const sections = [];
|
|
8320
8214
|
sections.push(`# Olam World: ${world.name}`);
|
|
8321
8215
|
sections.push("");
|
|
@@ -8476,7 +8370,7 @@ function injectWorldContext(opts) {
|
|
|
8476
8370
|
sections.push("");
|
|
8477
8371
|
}
|
|
8478
8372
|
const content = sections.join("\n");
|
|
8479
|
-
|
|
8373
|
+
fs14.writeFileSync(path15.join(claudeDir, "CLAUDE.md"), content);
|
|
8480
8374
|
}
|
|
8481
8375
|
function formatTaskSource(ctx) {
|
|
8482
8376
|
if (ctx.source === "linear" && ctx.ticketId) {
|
|
@@ -8490,9 +8384,9 @@ function formatTaskSource(ctx) {
|
|
|
8490
8384
|
function hasPlanFile(world) {
|
|
8491
8385
|
if (world.repos.length === 0)
|
|
8492
8386
|
return false;
|
|
8493
|
-
const plansDir =
|
|
8387
|
+
const plansDir = path15.join(world.workspacePath, world.repos[0], "docs", "plans");
|
|
8494
8388
|
try {
|
|
8495
|
-
return
|
|
8389
|
+
return fs14.existsSync(plansDir) && fs14.readdirSync(plansDir).length > 0;
|
|
8496
8390
|
} catch {
|
|
8497
8391
|
return false;
|
|
8498
8392
|
}
|
|
@@ -8737,7 +8631,7 @@ var init_stack_install = __esm({
|
|
|
8737
8631
|
|
|
8738
8632
|
// ../core/dist/world/stack-image.js
|
|
8739
8633
|
import { execSync as execSync2 } from "node:child_process";
|
|
8740
|
-
import * as
|
|
8634
|
+
import * as crypto3 from "node:crypto";
|
|
8741
8635
|
function computeFingerprint(runtimes) {
|
|
8742
8636
|
const parts = [];
|
|
8743
8637
|
for (const [runtime, versions] of runtimes) {
|
|
@@ -8787,14 +8681,14 @@ function getBaseImageDigest() {
|
|
|
8787
8681
|
cachedBaseDigest = digest.replace("sha256:", "").slice(0, 16);
|
|
8788
8682
|
return cachedBaseDigest;
|
|
8789
8683
|
} catch {
|
|
8790
|
-
cachedBaseDigest =
|
|
8684
|
+
cachedBaseDigest = crypto3.createHash("sha256").update("unknown").digest("hex").slice(0, 16);
|
|
8791
8685
|
return cachedBaseDigest;
|
|
8792
8686
|
}
|
|
8793
8687
|
}
|
|
8794
8688
|
function sanitizeTag(raw) {
|
|
8795
8689
|
let tag = raw.toLowerCase().replace(/[^a-z0-9._-]/g, "-");
|
|
8796
8690
|
if (tag.length > MAX_TAG_LENGTH) {
|
|
8797
|
-
const hash =
|
|
8691
|
+
const hash = crypto3.createHash("sha256").update(raw).digest("hex").slice(0, 12);
|
|
8798
8692
|
tag = tag.slice(0, MAX_TAG_LENGTH - 13) + "_" + hash;
|
|
8799
8693
|
}
|
|
8800
8694
|
return tag;
|
|
@@ -9196,14 +9090,14 @@ var init_secrets_fetcher = __esm({
|
|
|
9196
9090
|
});
|
|
9197
9091
|
|
|
9198
9092
|
// ../core/dist/world/olam-yaml.js
|
|
9199
|
-
import * as
|
|
9093
|
+
import * as path16 from "node:path";
|
|
9200
9094
|
import YAML2 from "yaml";
|
|
9201
9095
|
function enrichReposWithManifests(repos, workspacePath) {
|
|
9202
9096
|
return repos.map((repo) => {
|
|
9203
9097
|
if (repo.manifest !== void 0 && repo.manifest !== null) {
|
|
9204
9098
|
return repo;
|
|
9205
9099
|
}
|
|
9206
|
-
const repoDir =
|
|
9100
|
+
const repoDir = path16.join(workspacePath, repo.name);
|
|
9207
9101
|
let manifest = null;
|
|
9208
9102
|
try {
|
|
9209
9103
|
manifest = loadRepoManifest(repoDir);
|
|
@@ -9224,8 +9118,8 @@ var init_olam_yaml = __esm({
|
|
|
9224
9118
|
});
|
|
9225
9119
|
|
|
9226
9120
|
// ../core/dist/policies/loader.js
|
|
9227
|
-
import * as
|
|
9228
|
-
import * as
|
|
9121
|
+
import * as fs15 from "node:fs";
|
|
9122
|
+
import * as path17 from "node:path";
|
|
9229
9123
|
import { parse as parseYaml3 } from "yaml";
|
|
9230
9124
|
function parseFrontmatter(content) {
|
|
9231
9125
|
const match2 = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/m.exec(content);
|
|
@@ -9245,20 +9139,20 @@ function toStringArray(v) {
|
|
|
9245
9139
|
return v.filter((x) => typeof x === "string");
|
|
9246
9140
|
}
|
|
9247
9141
|
function loadPolicies(workspaceRoot) {
|
|
9248
|
-
const policiesDir =
|
|
9249
|
-
if (!
|
|
9142
|
+
const policiesDir = path17.join(workspaceRoot, ".olam", "policies");
|
|
9143
|
+
if (!fs15.existsSync(policiesDir))
|
|
9250
9144
|
return [];
|
|
9251
9145
|
let files;
|
|
9252
9146
|
try {
|
|
9253
|
-
files =
|
|
9147
|
+
files = fs15.readdirSync(policiesDir).filter((f) => f.endsWith(".md")).sort();
|
|
9254
9148
|
} catch {
|
|
9255
9149
|
return [];
|
|
9256
9150
|
}
|
|
9257
9151
|
const policies = [];
|
|
9258
9152
|
for (const file of files) {
|
|
9259
|
-
const filePath =
|
|
9153
|
+
const filePath = path17.join(policiesDir, file);
|
|
9260
9154
|
try {
|
|
9261
|
-
const content =
|
|
9155
|
+
const content = fs15.readFileSync(filePath, "utf8");
|
|
9262
9156
|
const parsed = parseFrontmatter(content);
|
|
9263
9157
|
if (!parsed) {
|
|
9264
9158
|
console.warn(`[policies] skipping ${file}: no valid frontmatter block`);
|
|
@@ -9333,7 +9227,7 @@ async function startSupervisedApps(containerName, worldId, repos, exec, options
|
|
|
9333
9227
|
const probeTimeoutMs = options.probeTimeoutMs ?? 3e4;
|
|
9334
9228
|
const probeIntervalMs = options.probeIntervalMs ?? 1e3;
|
|
9335
9229
|
const clock = options.clock ?? Date.now;
|
|
9336
|
-
const
|
|
9230
|
+
const sleep4 = options.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
9337
9231
|
for (const repo of repos) {
|
|
9338
9232
|
if (isPortBound(exec, containerName, repo.hostPort)) {
|
|
9339
9233
|
throw new PortInUseError(repo.hostPort, repo.name, repo.manifestPath);
|
|
@@ -9358,7 +9252,7 @@ async function startSupervisedApps(containerName, worldId, repos, exec, options
|
|
|
9358
9252
|
probeTimeoutMs,
|
|
9359
9253
|
probeIntervalMs,
|
|
9360
9254
|
clock,
|
|
9361
|
-
sleep:
|
|
9255
|
+
sleep: sleep4
|
|
9362
9256
|
})));
|
|
9363
9257
|
return {
|
|
9364
9258
|
sessionName,
|
|
@@ -9422,7 +9316,6 @@ var manager_exports = {};
|
|
|
9422
9316
|
__export(manager_exports, {
|
|
9423
9317
|
AuthPreflightError: () => AuthPreflightError,
|
|
9424
9318
|
BotIdentityError: () => BotIdentityError,
|
|
9425
|
-
RepoSelectionRequiredError: () => RepoSelectionRequiredError,
|
|
9426
9319
|
WorkspaceNotFoundError: () => WorkspaceNotFoundError,
|
|
9427
9320
|
WorldManager: () => WorldManager,
|
|
9428
9321
|
buildManifestRuntimeForTest: () => buildManifestRuntime,
|
|
@@ -9431,11 +9324,11 @@ __export(manager_exports, {
|
|
|
9431
9324
|
planManifestPipeline: () => planManifestPipeline,
|
|
9432
9325
|
runManifestRuntime: () => runManifestRuntime
|
|
9433
9326
|
});
|
|
9434
|
-
import * as
|
|
9327
|
+
import * as crypto4 from "node:crypto";
|
|
9435
9328
|
import { execSync as execSync4 } from "node:child_process";
|
|
9436
|
-
import * as
|
|
9329
|
+
import * as fs16 from "node:fs";
|
|
9437
9330
|
import * as os10 from "node:os";
|
|
9438
|
-
import * as
|
|
9331
|
+
import * as path18 from "node:path";
|
|
9439
9332
|
import YAML3 from "yaml";
|
|
9440
9333
|
function getTokenScopes(ghToken, _exec = execSync4) {
|
|
9441
9334
|
try {
|
|
@@ -9774,7 +9667,7 @@ function buildManifestRuntime(worldId, repos) {
|
|
|
9774
9667
|
}
|
|
9775
9668
|
return { worldId, repos: runtimeRepos };
|
|
9776
9669
|
}
|
|
9777
|
-
var BotIdentityError, ADJECTIVES, NOUNS, AuthPreflightError, WorkspaceNotFoundError,
|
|
9670
|
+
var BotIdentityError, ADJECTIVES, NOUNS, AuthPreflightError, WorkspaceNotFoundError, WorldManager;
|
|
9778
9671
|
var init_manager = __esm({
|
|
9779
9672
|
"../core/dist/world/manager.js"() {
|
|
9780
9673
|
"use strict";
|
|
@@ -9823,15 +9716,6 @@ var init_manager = __esm({
|
|
|
9823
9716
|
this.name = "WorkspaceNotFoundError";
|
|
9824
9717
|
}
|
|
9825
9718
|
};
|
|
9826
|
-
RepoSelectionRequiredError = class extends Error {
|
|
9827
|
-
availableRepos;
|
|
9828
|
-
constructor(availableRepos) {
|
|
9829
|
-
const list = availableRepos.length > 0 ? availableRepos.join(", ") : "(none configured)";
|
|
9830
|
-
super(`--repos or --workspace is required. Available repos: ${list}. Pick the subset you actually want \u2014 implicit "all repos" was removed to prevent accidental multi-repo bootstraps.`);
|
|
9831
|
-
this.availableRepos = availableRepos;
|
|
9832
|
-
this.name = "RepoSelectionRequiredError";
|
|
9833
|
-
}
|
|
9834
|
-
};
|
|
9835
9719
|
WorldManager = class {
|
|
9836
9720
|
config;
|
|
9837
9721
|
provider;
|
|
@@ -9859,7 +9743,7 @@ var init_manager = __esm({
|
|
|
9859
9743
|
}
|
|
9860
9744
|
}
|
|
9861
9745
|
const worldId = generateWorldId();
|
|
9862
|
-
const workspacePath =
|
|
9746
|
+
const workspacePath = path18.join(os10.homedir(), ".olam", "worlds", worldId);
|
|
9863
9747
|
const portOffset = this.registry.getNextPortOffset();
|
|
9864
9748
|
const branch = opts.branchName ?? `olam/${worldId}`;
|
|
9865
9749
|
const repos = this.resolveReposWithWorkspace(opts);
|
|
@@ -9916,37 +9800,37 @@ var init_manager = __esm({
|
|
|
9916
9800
|
if (!repo.path)
|
|
9917
9801
|
continue;
|
|
9918
9802
|
const sourceRoot = repo.path.replace(/^~/, os10.homedir());
|
|
9919
|
-
const worktreeRoot =
|
|
9920
|
-
if (!
|
|
9803
|
+
const worktreeRoot = path18.join(workspacePath, repo.name);
|
|
9804
|
+
if (!fs16.existsSync(sourceRoot) || !fs16.existsSync(worktreeRoot))
|
|
9921
9805
|
continue;
|
|
9922
9806
|
let copied = 0;
|
|
9923
9807
|
for (const pattern of RUNTIME_FILE_PATTERNS) {
|
|
9924
9808
|
const matches2 = [];
|
|
9925
9809
|
if (pattern.includes("*")) {
|
|
9926
|
-
const [dir, glob] = [
|
|
9927
|
-
const sourceDir =
|
|
9928
|
-
if (
|
|
9810
|
+
const [dir, glob] = [path18.dirname(pattern), path18.basename(pattern)];
|
|
9811
|
+
const sourceDir = path18.join(sourceRoot, dir);
|
|
9812
|
+
if (fs16.existsSync(sourceDir)) {
|
|
9929
9813
|
const ext2 = glob.replace(/^\*+/, "");
|
|
9930
9814
|
try {
|
|
9931
|
-
for (const entry of
|
|
9815
|
+
for (const entry of fs16.readdirSync(sourceDir)) {
|
|
9932
9816
|
if (ext2 === "" || entry.endsWith(ext2))
|
|
9933
|
-
matches2.push(
|
|
9817
|
+
matches2.push(path18.join(dir, entry));
|
|
9934
9818
|
}
|
|
9935
9819
|
} catch {
|
|
9936
9820
|
}
|
|
9937
9821
|
}
|
|
9938
|
-
} else if (
|
|
9822
|
+
} else if (fs16.existsSync(path18.join(sourceRoot, pattern))) {
|
|
9939
9823
|
matches2.push(pattern);
|
|
9940
9824
|
}
|
|
9941
9825
|
for (const rel of matches2) {
|
|
9942
|
-
const src =
|
|
9943
|
-
const dst =
|
|
9826
|
+
const src = path18.join(sourceRoot, rel);
|
|
9827
|
+
const dst = path18.join(worktreeRoot, rel);
|
|
9944
9828
|
try {
|
|
9945
|
-
const st =
|
|
9829
|
+
const st = fs16.statSync(src);
|
|
9946
9830
|
if (!st.isFile())
|
|
9947
9831
|
continue;
|
|
9948
|
-
|
|
9949
|
-
|
|
9832
|
+
fs16.mkdirSync(path18.dirname(dst), { recursive: true });
|
|
9833
|
+
fs16.copyFileSync(src, dst);
|
|
9950
9834
|
copied++;
|
|
9951
9835
|
} catch {
|
|
9952
9836
|
}
|
|
@@ -10046,7 +9930,7 @@ var init_manager = __esm({
|
|
|
10046
9930
|
try {
|
|
10047
9931
|
const hostExec = makeHostExecFn();
|
|
10048
9932
|
for (const repo of repos) {
|
|
10049
|
-
const repoDir =
|
|
9933
|
+
const repoDir = path18.join(workspacePath, repo.name);
|
|
10050
9934
|
if (repo.stack && Object.keys(repo.stack).length > 0) {
|
|
10051
9935
|
preDetectedStacks.set(repo.name, { repoName: repo.name, versions: repo.stack });
|
|
10052
9936
|
} else {
|
|
@@ -10103,10 +9987,10 @@ var init_manager = __esm({
|
|
|
10103
9987
|
const worldEnv = {};
|
|
10104
9988
|
if (opts.task)
|
|
10105
9989
|
worldEnv.OLAM_TASK = opts.task;
|
|
10106
|
-
const r2CredsPath =
|
|
10107
|
-
if (
|
|
9990
|
+
const r2CredsPath = path18.join(os10.homedir(), ".olam", "r2-credentials.json");
|
|
9991
|
+
if (fs16.existsSync(r2CredsPath)) {
|
|
10108
9992
|
try {
|
|
10109
|
-
const r2Raw =
|
|
9993
|
+
const r2Raw = fs16.readFileSync(r2CredsPath, "utf-8").trim();
|
|
10110
9994
|
if (r2Raw.length > 0) {
|
|
10111
9995
|
const r2 = JSON.parse(r2Raw);
|
|
10112
9996
|
if (typeof r2.account_id === "string")
|
|
@@ -10123,10 +10007,10 @@ var init_manager = __esm({
|
|
|
10123
10007
|
} catch {
|
|
10124
10008
|
}
|
|
10125
10009
|
}
|
|
10126
|
-
const keysYamlPath =
|
|
10127
|
-
if (
|
|
10010
|
+
const keysYamlPath = path18.join(os10.homedir(), ".olam", "keys.yaml");
|
|
10011
|
+
if (fs16.existsSync(keysYamlPath)) {
|
|
10128
10012
|
try {
|
|
10129
|
-
const keysRaw =
|
|
10013
|
+
const keysRaw = fs16.readFileSync(keysYamlPath, "utf-8").trim();
|
|
10130
10014
|
if (keysRaw.length > 0) {
|
|
10131
10015
|
const parsed = YAML3.parse(keysRaw);
|
|
10132
10016
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
@@ -10173,10 +10057,10 @@ var init_manager = __esm({
|
|
|
10173
10057
|
worldEnv[k] = v;
|
|
10174
10058
|
}
|
|
10175
10059
|
for (const { repoName, relativePath, content } of fileWrites) {
|
|
10176
|
-
const absPath =
|
|
10060
|
+
const absPath = path18.join(workspacePath, repoName, relativePath);
|
|
10177
10061
|
try {
|
|
10178
|
-
|
|
10179
|
-
|
|
10062
|
+
fs16.mkdirSync(path18.dirname(absPath), { recursive: true });
|
|
10063
|
+
fs16.writeFileSync(absPath, content.endsWith("\n") ? content : content + "\n", {
|
|
10180
10064
|
mode: 384
|
|
10181
10065
|
});
|
|
10182
10066
|
console.log(`[secrets] ${repoName}: materialised ${relativePath} (${content.length} chars, mode 0600)`);
|
|
@@ -10328,7 +10212,7 @@ var init_manager = __esm({
|
|
|
10328
10212
|
let taskWithPolicies = opts.task;
|
|
10329
10213
|
try {
|
|
10330
10214
|
const allPolicies = repos.flatMap((repo) => {
|
|
10331
|
-
const repoWorktree =
|
|
10215
|
+
const repoWorktree = path18.join(workspacePath, repo.name);
|
|
10332
10216
|
return loadPolicies(repoWorktree);
|
|
10333
10217
|
});
|
|
10334
10218
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -10344,8 +10228,8 @@ var init_manager = __esm({
|
|
|
10344
10228
|
${opts.task}`;
|
|
10345
10229
|
execSync4(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
|
|
10346
10230
|
for (const repo of repos) {
|
|
10347
|
-
const policiesDir =
|
|
10348
|
-
if (
|
|
10231
|
+
const policiesDir = path18.join(workspacePath, repo.name, ".olam", "policies");
|
|
10232
|
+
if (fs16.existsSync(policiesDir)) {
|
|
10349
10233
|
execSync4(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
|
|
10350
10234
|
}
|
|
10351
10235
|
}
|
|
@@ -10424,8 +10308,8 @@ ${opts.task}`;
|
|
|
10424
10308
|
} catch {
|
|
10425
10309
|
}
|
|
10426
10310
|
try {
|
|
10427
|
-
|
|
10428
|
-
if (
|
|
10311
|
+
fs16.rmSync(world.workspacePath, { recursive: true, force: true });
|
|
10312
|
+
if (fs16.existsSync(world.workspacePath)) {
|
|
10429
10313
|
console.warn(`[WorldManager] destroyWorld(${worldId}): workspace dir ${world.workspacePath} still exists after rmSync. Run \`olam clean --apply\` to reap.`);
|
|
10430
10314
|
}
|
|
10431
10315
|
} catch (err) {
|
|
@@ -10480,10 +10364,7 @@ ${opts.task}`;
|
|
|
10480
10364
|
* Resolution precedence (matches the CF worker exactly):
|
|
10481
10365
|
* 1. inline `opts.repos` names → look up in `config.repos`
|
|
10482
10366
|
* 2. named `opts.workspace` → load catalog YAML, map via workspaceToRepoConfigs
|
|
10483
|
-
* 3.
|
|
10484
|
-
* "include every repo in config.yaml" fallback silently fanned a
|
|
10485
|
-
* single-repo audit into 7-repo bootstraps and steered
|
|
10486
|
-
* `image_selectors` to a wider tag than intended.
|
|
10367
|
+
* 3. fallback → every repo declared in the project's config.yaml
|
|
10487
10368
|
*/
|
|
10488
10369
|
resolveReposWithWorkspace(opts) {
|
|
10489
10370
|
if (opts.repos && opts.repos.length > 0) {
|
|
@@ -10495,7 +10376,7 @@ ${opts.task}`;
|
|
|
10495
10376
|
throw new WorkspaceNotFoundError(opts.workspace);
|
|
10496
10377
|
return workspaceToRepoConfigs(ws);
|
|
10497
10378
|
}
|
|
10498
|
-
|
|
10379
|
+
return this.resolveRepos(void 0);
|
|
10499
10380
|
}
|
|
10500
10381
|
resolveRepos(repoNames) {
|
|
10501
10382
|
if (!repoNames || repoNames.length === 0) {
|
|
@@ -10513,14 +10394,14 @@ ${opts.task}`;
|
|
|
10513
10394
|
return names.map((name) => this.config.repos.find((r) => r.name === name)).filter((r) => r !== void 0);
|
|
10514
10395
|
}
|
|
10515
10396
|
transportPlanFile(planFilePath, workspacePath, repoNames) {
|
|
10516
|
-
const planContent =
|
|
10517
|
-
const planFileName =
|
|
10397
|
+
const planContent = fs16.readFileSync(planFilePath, "utf-8");
|
|
10398
|
+
const planFileName = path18.basename(planFilePath);
|
|
10518
10399
|
const targetRepo = repoNames[0];
|
|
10519
10400
|
if (!targetRepo)
|
|
10520
10401
|
return;
|
|
10521
|
-
const plansDir =
|
|
10522
|
-
|
|
10523
|
-
|
|
10402
|
+
const plansDir = path18.join(workspacePath, targetRepo, "docs", "plans");
|
|
10403
|
+
fs16.mkdirSync(plansDir, { recursive: true });
|
|
10404
|
+
fs16.writeFileSync(path18.join(plansDir, planFileName), planContent);
|
|
10524
10405
|
}
|
|
10525
10406
|
resolveServices(repos) {
|
|
10526
10407
|
const services = [];
|
|
@@ -10613,9 +10494,9 @@ var init_tracker = __esm({
|
|
|
10613
10494
|
});
|
|
10614
10495
|
|
|
10615
10496
|
// ../core/dist/world-paths.js
|
|
10616
|
-
import * as
|
|
10497
|
+
import * as path19 from "node:path";
|
|
10617
10498
|
function getWorldDbPath(workspacePath) {
|
|
10618
|
-
return
|
|
10499
|
+
return path19.join(workspacePath, WORLD_DB_FILENAME);
|
|
10619
10500
|
}
|
|
10620
10501
|
var WORLD_DB_FILENAME;
|
|
10621
10502
|
var init_world_paths = __esm({
|
|
@@ -11233,8 +11114,8 @@ var init_session_aggregator = __esm({
|
|
|
11233
11114
|
|
|
11234
11115
|
// ../core/dist/dashboard/server.js
|
|
11235
11116
|
import * as http from "node:http";
|
|
11236
|
-
import * as
|
|
11237
|
-
import * as
|
|
11117
|
+
import * as fs17 from "node:fs";
|
|
11118
|
+
import * as path20 from "node:path";
|
|
11238
11119
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
11239
11120
|
function jsonResponse(res, data, status = 200) {
|
|
11240
11121
|
res.writeHead(status, { "Content-Type": "application/json; charset=utf-8" });
|
|
@@ -11245,7 +11126,7 @@ function notFound(res) {
|
|
|
11245
11126
|
}
|
|
11246
11127
|
function openThoughtStore(workspacePath) {
|
|
11247
11128
|
const dbPath = getWorldDbPath(workspacePath);
|
|
11248
|
-
if (!
|
|
11129
|
+
if (!fs17.existsSync(dbPath))
|
|
11249
11130
|
return null;
|
|
11250
11131
|
return new ThoughtLocalStore(dbPath);
|
|
11251
11132
|
}
|
|
@@ -11416,13 +11297,13 @@ function findSessionInWorld(registry, sessionId) {
|
|
|
11416
11297
|
}
|
|
11417
11298
|
function createDashboardServer(opts) {
|
|
11418
11299
|
const { port, registry } = opts;
|
|
11419
|
-
const thisDir =
|
|
11420
|
-
const defaultPublicDir =
|
|
11300
|
+
const thisDir = path20.dirname(fileURLToPath2(import.meta.url));
|
|
11301
|
+
const defaultPublicDir = path20.resolve(thisDir, "../../../control-plane/public");
|
|
11421
11302
|
const publicDir = opts.publicDir ?? defaultPublicDir;
|
|
11422
|
-
let hasPublicDir =
|
|
11303
|
+
let hasPublicDir = fs17.existsSync(publicDir);
|
|
11423
11304
|
const server = http.createServer((req, res) => {
|
|
11424
11305
|
if (!hasPublicDir) {
|
|
11425
|
-
hasPublicDir =
|
|
11306
|
+
hasPublicDir = fs17.existsSync(publicDir);
|
|
11426
11307
|
}
|
|
11427
11308
|
const host = req.headers.host ?? `localhost:${port}`;
|
|
11428
11309
|
const url = new URL(req.url ?? "/", `http://${host}`);
|
|
@@ -11696,22 +11577,22 @@ function createDashboardServer(opts) {
|
|
|
11696
11577
|
res.end(`<html><body style="font-family:system-ui;padding:2rem"><h1>Olam Dashboard</h1><p>The React app has not been built yet.</p><p>Run <code>npm run build:app</code> in <code>packages/control-plane</code> to build it.</p><p>API routes are available at <code>/api/*</code>.</p></body></html>`);
|
|
11697
11578
|
return;
|
|
11698
11579
|
}
|
|
11699
|
-
let filePath =
|
|
11580
|
+
let filePath = path20.join(publicDir, pathname === "/" ? "index.html" : pathname);
|
|
11700
11581
|
if (!filePath.startsWith(publicDir)) {
|
|
11701
11582
|
notFound(res);
|
|
11702
11583
|
return;
|
|
11703
11584
|
}
|
|
11704
|
-
if (
|
|
11705
|
-
const ext2 =
|
|
11585
|
+
if (fs17.existsSync(filePath) && fs17.statSync(filePath).isFile()) {
|
|
11586
|
+
const ext2 = path20.extname(filePath);
|
|
11706
11587
|
const contentType = MIME[ext2] ?? "application/octet-stream";
|
|
11707
11588
|
res.writeHead(200, { "Content-Type": contentType });
|
|
11708
|
-
|
|
11589
|
+
fs17.createReadStream(filePath).pipe(res);
|
|
11709
11590
|
return;
|
|
11710
11591
|
}
|
|
11711
|
-
filePath =
|
|
11712
|
-
if (
|
|
11592
|
+
filePath = path20.join(publicDir, "index.html");
|
|
11593
|
+
if (fs17.existsSync(filePath)) {
|
|
11713
11594
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
11714
|
-
|
|
11595
|
+
fs17.createReadStream(filePath).pipe(res);
|
|
11715
11596
|
return;
|
|
11716
11597
|
}
|
|
11717
11598
|
notFound(res);
|
|
@@ -11742,16 +11623,16 @@ var init_server = __esm({
|
|
|
11742
11623
|
});
|
|
11743
11624
|
|
|
11744
11625
|
// ../core/dist/dashboard/state.js
|
|
11745
|
-
import * as
|
|
11626
|
+
import * as fs18 from "node:fs";
|
|
11746
11627
|
import * as os11 from "node:os";
|
|
11747
|
-
import * as
|
|
11628
|
+
import * as path21 from "node:path";
|
|
11748
11629
|
function saveDashboardState(state) {
|
|
11749
|
-
|
|
11750
|
-
|
|
11630
|
+
fs18.mkdirSync(path21.dirname(STATE_PATH), { recursive: true });
|
|
11631
|
+
fs18.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2));
|
|
11751
11632
|
}
|
|
11752
11633
|
function loadDashboardState() {
|
|
11753
11634
|
try {
|
|
11754
|
-
const raw =
|
|
11635
|
+
const raw = fs18.readFileSync(STATE_PATH, "utf-8");
|
|
11755
11636
|
return JSON.parse(raw);
|
|
11756
11637
|
} catch {
|
|
11757
11638
|
return null;
|
|
@@ -11759,7 +11640,7 @@ function loadDashboardState() {
|
|
|
11759
11640
|
}
|
|
11760
11641
|
function clearDashboardState() {
|
|
11761
11642
|
try {
|
|
11762
|
-
|
|
11643
|
+
fs18.unlinkSync(STATE_PATH);
|
|
11763
11644
|
} catch {
|
|
11764
11645
|
}
|
|
11765
11646
|
}
|
|
@@ -11779,7 +11660,7 @@ var STATE_PATH;
|
|
|
11779
11660
|
var init_state2 = __esm({
|
|
11780
11661
|
"../core/dist/dashboard/state.js"() {
|
|
11781
11662
|
"use strict";
|
|
11782
|
-
STATE_PATH =
|
|
11663
|
+
STATE_PATH = path21.join(os11.homedir(), ".olam", "dashboard.json");
|
|
11783
11664
|
}
|
|
11784
11665
|
});
|
|
11785
11666
|
|
|
@@ -12173,51 +12054,51 @@ __export(host_cp_exports, {
|
|
|
12173
12054
|
writePid: () => writePid,
|
|
12174
12055
|
writeToken: () => writeToken
|
|
12175
12056
|
});
|
|
12176
|
-
import * as
|
|
12177
|
-
import * as
|
|
12057
|
+
import * as crypto5 from "node:crypto";
|
|
12058
|
+
import * as fs19 from "node:fs";
|
|
12178
12059
|
import * as os12 from "node:os";
|
|
12179
|
-
import * as
|
|
12060
|
+
import * as path22 from "node:path";
|
|
12180
12061
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
12181
12062
|
import Dockerode2 from "dockerode";
|
|
12182
12063
|
function findComposeFile() {
|
|
12183
12064
|
const candidates = [
|
|
12184
12065
|
// Bundled path: dist/index.js lives at <pkg>/dist/; host-cp/ is a sibling of dist/
|
|
12185
|
-
|
|
12066
|
+
path22.resolve(path22.dirname(new URL(import.meta.url).pathname), "../host-cp/compose.yaml"),
|
|
12186
12067
|
// Source-mode: cwd is monorepo root
|
|
12187
|
-
|
|
12068
|
+
path22.resolve(process.cwd(), "packages/host-cp/compose.yaml"),
|
|
12188
12069
|
// Source-mode: cwd is one level inside the monorepo
|
|
12189
|
-
|
|
12070
|
+
path22.resolve(process.cwd(), "../packages/host-cp/compose.yaml")
|
|
12190
12071
|
];
|
|
12191
12072
|
for (const c of candidates) {
|
|
12192
|
-
if (
|
|
12073
|
+
if (fs19.existsSync(c)) return c;
|
|
12193
12074
|
}
|
|
12194
|
-
return
|
|
12075
|
+
return path22.resolve(process.cwd(), "packages/host-cp/compose.yaml");
|
|
12195
12076
|
}
|
|
12196
12077
|
function olamHome() {
|
|
12197
|
-
return process.env.OLAM_HOME ??
|
|
12078
|
+
return process.env.OLAM_HOME ?? path22.join(os12.homedir(), ".olam");
|
|
12198
12079
|
}
|
|
12199
12080
|
function tokenPath() {
|
|
12200
|
-
return
|
|
12081
|
+
return path22.join(olamHome(), "host-cp.token");
|
|
12201
12082
|
}
|
|
12202
12083
|
function pidPath() {
|
|
12203
|
-
return
|
|
12084
|
+
return path22.join(olamHome(), "host-cp.pid");
|
|
12204
12085
|
}
|
|
12205
12086
|
function authSecretPath() {
|
|
12206
|
-
return
|
|
12087
|
+
return path22.join(olamHome(), "auth-secret");
|
|
12207
12088
|
}
|
|
12208
12089
|
function readAuthSecret2() {
|
|
12209
12090
|
const filePath = authSecretPath();
|
|
12210
|
-
if (!
|
|
12211
|
-
const raw =
|
|
12091
|
+
if (!fs19.existsSync(filePath)) return null;
|
|
12092
|
+
const raw = fs19.readFileSync(filePath, "utf-8").trim();
|
|
12212
12093
|
return raw.length > 0 ? raw : null;
|
|
12213
12094
|
}
|
|
12214
12095
|
function r2CredentialsPath() {
|
|
12215
|
-
return
|
|
12096
|
+
return path22.join(olamHome(), "r2-credentials.json");
|
|
12216
12097
|
}
|
|
12217
12098
|
function readR2Credentials() {
|
|
12218
12099
|
const filePath = r2CredentialsPath();
|
|
12219
|
-
if (!
|
|
12220
|
-
const raw =
|
|
12100
|
+
if (!fs19.existsSync(filePath)) return null;
|
|
12101
|
+
const raw = fs19.readFileSync(filePath, "utf-8").trim();
|
|
12221
12102
|
if (raw.length === 0) return null;
|
|
12222
12103
|
try {
|
|
12223
12104
|
const parsed = JSON.parse(raw);
|
|
@@ -12238,39 +12119,39 @@ function readR2Credentials() {
|
|
|
12238
12119
|
}
|
|
12239
12120
|
}
|
|
12240
12121
|
function writeToken() {
|
|
12241
|
-
const token =
|
|
12122
|
+
const token = crypto5.randomBytes(32).toString("hex");
|
|
12242
12123
|
const filePath = tokenPath();
|
|
12243
|
-
|
|
12244
|
-
|
|
12124
|
+
fs19.mkdirSync(path22.dirname(filePath), { recursive: true });
|
|
12125
|
+
fs19.writeFileSync(filePath, token, { mode: 384 });
|
|
12245
12126
|
return token;
|
|
12246
12127
|
}
|
|
12247
12128
|
function readToken() {
|
|
12248
12129
|
const filePath = tokenPath();
|
|
12249
|
-
if (!
|
|
12250
|
-
return
|
|
12130
|
+
if (!fs19.existsSync(filePath)) return null;
|
|
12131
|
+
return fs19.readFileSync(filePath, "utf-8").trim();
|
|
12251
12132
|
}
|
|
12252
12133
|
function removeToken() {
|
|
12253
12134
|
const filePath = tokenPath();
|
|
12254
|
-
if (!
|
|
12255
|
-
|
|
12135
|
+
if (!fs19.existsSync(filePath)) return false;
|
|
12136
|
+
fs19.unlinkSync(filePath);
|
|
12256
12137
|
return true;
|
|
12257
12138
|
}
|
|
12258
12139
|
function writePid(pid) {
|
|
12259
12140
|
const filePath = pidPath();
|
|
12260
|
-
|
|
12261
|
-
|
|
12141
|
+
fs19.mkdirSync(path22.dirname(filePath), { recursive: true });
|
|
12142
|
+
fs19.writeFileSync(filePath, String(pid), { mode: 420 });
|
|
12262
12143
|
}
|
|
12263
12144
|
function readPid() {
|
|
12264
12145
|
const filePath = pidPath();
|
|
12265
|
-
if (!
|
|
12266
|
-
const raw =
|
|
12146
|
+
if (!fs19.existsSync(filePath)) return null;
|
|
12147
|
+
const raw = fs19.readFileSync(filePath, "utf-8").trim();
|
|
12267
12148
|
const n = parseInt(raw, 10);
|
|
12268
12149
|
return Number.isFinite(n) ? n : null;
|
|
12269
12150
|
}
|
|
12270
12151
|
function removePid() {
|
|
12271
12152
|
const filePath = pidPath();
|
|
12272
|
-
if (!
|
|
12273
|
-
|
|
12153
|
+
if (!fs19.existsSync(filePath)) return false;
|
|
12154
|
+
fs19.unlinkSync(filePath);
|
|
12274
12155
|
return true;
|
|
12275
12156
|
}
|
|
12276
12157
|
async function findHostCpContainer() {
|
|
@@ -12429,7 +12310,7 @@ async function handleStart(opts) {
|
|
|
12429
12310
|
}
|
|
12430
12311
|
const token = writeToken();
|
|
12431
12312
|
const composeFile = findComposeFile();
|
|
12432
|
-
if (!
|
|
12313
|
+
if (!fs19.existsSync(composeFile)) {
|
|
12433
12314
|
printError(`compose.yaml not found at ${composeFile}. Run from the olam project root.`);
|
|
12434
12315
|
removeToken();
|
|
12435
12316
|
process.exitCode = 1;
|
|
@@ -12511,7 +12392,7 @@ async function stopHostCp() {
|
|
|
12511
12392
|
}
|
|
12512
12393
|
async function handleStop() {
|
|
12513
12394
|
const composeFile = findComposeFile();
|
|
12514
|
-
if (!
|
|
12395
|
+
if (!fs19.existsSync(composeFile)) {
|
|
12515
12396
|
printWarning(`compose.yaml not found at ${composeFile}. Cleaning up token + PID anyway.`);
|
|
12516
12397
|
removeToken();
|
|
12517
12398
|
removePid();
|
|
@@ -12539,13 +12420,13 @@ async function buildStatusReport() {
|
|
|
12539
12420
|
const container = await findHostCpContainer();
|
|
12540
12421
|
const health = await probeHealth();
|
|
12541
12422
|
const tokenFile = tokenPath();
|
|
12542
|
-
const tokenPresent =
|
|
12423
|
+
const tokenPresent = fs19.existsSync(tokenFile);
|
|
12543
12424
|
let tokenModeOk = false;
|
|
12544
12425
|
if (tokenPresent) {
|
|
12545
|
-
const mode =
|
|
12426
|
+
const mode = fs19.statSync(tokenFile).mode & 511;
|
|
12546
12427
|
tokenModeOk = mode === 384;
|
|
12547
12428
|
}
|
|
12548
|
-
const pidPresent =
|
|
12429
|
+
const pidPresent = fs19.existsSync(pidPath());
|
|
12549
12430
|
let stack;
|
|
12550
12431
|
if (!container) {
|
|
12551
12432
|
stack = "not_started";
|
|
@@ -12633,13 +12514,13 @@ async function discoverWorldPort(worldId) {
|
|
|
12633
12514
|
}
|
|
12634
12515
|
async function readHostCpToken2() {
|
|
12635
12516
|
const tp = tokenPath();
|
|
12636
|
-
if (!
|
|
12637
|
-
return
|
|
12517
|
+
if (!fs19.existsSync(tp)) return null;
|
|
12518
|
+
return fs19.readFileSync(tp, "utf-8").trim();
|
|
12638
12519
|
}
|
|
12639
|
-
async function callHostCpProxy(method, worldId,
|
|
12520
|
+
async function callHostCpProxy(method, worldId, path44, body) {
|
|
12640
12521
|
const token = await readHostCpToken2();
|
|
12641
12522
|
if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
|
|
12642
|
-
const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${
|
|
12523
|
+
const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path44}`;
|
|
12643
12524
|
try {
|
|
12644
12525
|
const headers = {
|
|
12645
12526
|
Authorization: `Bearer ${token}`
|
|
@@ -12764,17 +12645,17 @@ __export(install_root_exports, {
|
|
|
12764
12645
|
isDevMode: () => isDevMode,
|
|
12765
12646
|
resolveBuildScript: () => resolveBuildScript
|
|
12766
12647
|
});
|
|
12767
|
-
import { existsSync as
|
|
12768
|
-
import { dirname as
|
|
12648
|
+
import { existsSync as existsSync18 } from "node:fs";
|
|
12649
|
+
import { dirname as dirname13, join as join24, resolve as resolve6 } from "node:path";
|
|
12769
12650
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
12770
12651
|
function installRoot(metaUrl = import.meta.url) {
|
|
12771
12652
|
const here = fileURLToPath3(metaUrl);
|
|
12772
|
-
return resolve6(
|
|
12653
|
+
return resolve6(dirname13(here), "..");
|
|
12773
12654
|
}
|
|
12774
12655
|
function isDevMode(env = process.env, installRootDir = installRoot()) {
|
|
12775
12656
|
if (env.OLAM_DEV !== "1") return false;
|
|
12776
12657
|
const repoRoot = resolve6(installRootDir, "..", "..");
|
|
12777
|
-
return
|
|
12658
|
+
return existsSync18(join24(repoRoot, "packages")) && existsSync18(join24(repoRoot, "package.json"));
|
|
12778
12659
|
}
|
|
12779
12660
|
function resolveBuildScript(input) {
|
|
12780
12661
|
const { scriptRelPath, env = process.env, installRootDir = installRoot() } = input;
|
|
@@ -12953,20 +12834,20 @@ var init_registry_allowlist = __esm({
|
|
|
12953
12834
|
});
|
|
12954
12835
|
|
|
12955
12836
|
// ../core/dist/world/world-yaml.js
|
|
12956
|
-
import * as
|
|
12957
|
-
import * as
|
|
12837
|
+
import * as fs21 from "node:fs";
|
|
12838
|
+
import * as path24 from "node:path";
|
|
12958
12839
|
import { parse as parseYaml4, stringify as stringifyYaml4 } from "yaml";
|
|
12959
12840
|
function writeWorldYaml(worldPath, data) {
|
|
12960
|
-
const olamDir =
|
|
12961
|
-
|
|
12962
|
-
|
|
12841
|
+
const olamDir = path24.join(worldPath, ".olam");
|
|
12842
|
+
fs21.mkdirSync(olamDir, { recursive: true });
|
|
12843
|
+
fs21.writeFileSync(path24.join(olamDir, "world.yaml"), stringifyYaml4(data), "utf-8");
|
|
12963
12844
|
}
|
|
12964
12845
|
function readWorldYaml(worldPath) {
|
|
12965
|
-
const yamlPath =
|
|
12966
|
-
if (!
|
|
12846
|
+
const yamlPath = path24.join(worldPath, ".olam", "world.yaml");
|
|
12847
|
+
if (!fs21.existsSync(yamlPath))
|
|
12967
12848
|
return null;
|
|
12968
12849
|
try {
|
|
12969
|
-
const raw =
|
|
12850
|
+
const raw = fs21.readFileSync(yamlPath, "utf-8");
|
|
12970
12851
|
const parsed = parseYaml4(raw);
|
|
12971
12852
|
return WorldYamlSchema.parse(parsed);
|
|
12972
12853
|
} catch {
|
|
@@ -13097,16 +12978,16 @@ __export(machine_schema_exports, {
|
|
|
13097
12978
|
readMachineConfig: () => readMachineConfig,
|
|
13098
12979
|
writeMachineConfig: () => writeMachineConfig
|
|
13099
12980
|
});
|
|
13100
|
-
import * as
|
|
13101
|
-
import * as
|
|
12981
|
+
import * as fs35 from "node:fs";
|
|
12982
|
+
import * as path39 from "node:path";
|
|
13102
12983
|
import * as os21 from "node:os";
|
|
13103
12984
|
import { parse as parseYaml5, stringify as stringifyYaml5 } from "yaml";
|
|
13104
12985
|
function readMachineConfig(configPath) {
|
|
13105
12986
|
const p = configPath ?? DEFAULT_CONFIG_PATH;
|
|
13106
|
-
if (!
|
|
12987
|
+
if (!fs35.existsSync(p))
|
|
13107
12988
|
return null;
|
|
13108
12989
|
try {
|
|
13109
|
-
const raw =
|
|
12990
|
+
const raw = fs35.readFileSync(p, "utf-8");
|
|
13110
12991
|
const parsed = parseYaml5(raw);
|
|
13111
12992
|
return MachineConfigSchema.parse(parsed);
|
|
13112
12993
|
} catch {
|
|
@@ -13115,8 +12996,8 @@ function readMachineConfig(configPath) {
|
|
|
13115
12996
|
}
|
|
13116
12997
|
function writeMachineConfig(config, configPath) {
|
|
13117
12998
|
const p = configPath ?? DEFAULT_CONFIG_PATH;
|
|
13118
|
-
|
|
13119
|
-
|
|
12999
|
+
fs35.mkdirSync(path39.dirname(p), { recursive: true });
|
|
13000
|
+
fs35.writeFileSync(p, stringifyYaml5({ ...config }), { mode: 420 });
|
|
13120
13001
|
}
|
|
13121
13002
|
function initMachineConfig(opts = {}) {
|
|
13122
13003
|
const configPath = opts.configPath ?? DEFAULT_CONFIG_PATH;
|
|
@@ -13139,16 +13020,16 @@ var init_machine_schema = __esm({
|
|
|
13139
13020
|
channel: external_exports.enum(["stable", "beta", "edge"]).default("stable"),
|
|
13140
13021
|
auto_update: external_exports.boolean().default(true),
|
|
13141
13022
|
telemetry: external_exports.boolean().default(true),
|
|
13142
|
-
worlds_dir: external_exports.string().default(() =>
|
|
13023
|
+
worlds_dir: external_exports.string().default(() => path39.join(os21.homedir(), ".olam", "worlds"))
|
|
13143
13024
|
});
|
|
13144
|
-
DEFAULT_CONFIG_PATH =
|
|
13025
|
+
DEFAULT_CONFIG_PATH = path39.join(os21.homedir(), ".olam", "config.yaml");
|
|
13145
13026
|
}
|
|
13146
13027
|
});
|
|
13147
13028
|
|
|
13148
13029
|
// src/index.ts
|
|
13149
13030
|
import { Command } from "commander";
|
|
13150
|
-
import * as
|
|
13151
|
-
import * as
|
|
13031
|
+
import * as fs39 from "node:fs";
|
|
13032
|
+
import * as path43 from "node:path";
|
|
13152
13033
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
13153
13034
|
|
|
13154
13035
|
// src/commands/init.ts
|
|
@@ -13525,9 +13406,9 @@ var UnknownArchetypeError = class extends Error {
|
|
|
13525
13406
|
};
|
|
13526
13407
|
var ArchetypeCycleError = class extends Error {
|
|
13527
13408
|
path;
|
|
13528
|
-
constructor(
|
|
13529
|
-
super(`Archetype inheritance cycle detected: ${
|
|
13530
|
-
this.path =
|
|
13409
|
+
constructor(path44) {
|
|
13410
|
+
super(`Archetype inheritance cycle detected: ${path44.join(" \u2192 ")} \u2192 ${path44[0] ?? "?"}`);
|
|
13411
|
+
this.path = path44;
|
|
13531
13412
|
this.name = "ArchetypeCycleError";
|
|
13532
13413
|
}
|
|
13533
13414
|
};
|
|
@@ -13721,7 +13602,7 @@ function registerInstall(program2) {
|
|
|
13721
13602
|
// src/commands/auth.ts
|
|
13722
13603
|
init_auth();
|
|
13723
13604
|
init_output();
|
|
13724
|
-
import
|
|
13605
|
+
import pc9 from "picocolors";
|
|
13725
13606
|
import * as readline from "node:readline/promises";
|
|
13726
13607
|
import { spawn as spawn3 } from "node:child_process";
|
|
13727
13608
|
|
|
@@ -13730,174 +13611,17 @@ import * as fs8 from "node:fs";
|
|
|
13730
13611
|
import * as os5 from "node:os";
|
|
13731
13612
|
import * as path9 from "node:path";
|
|
13732
13613
|
import pc5 from "picocolors";
|
|
13733
|
-
|
|
13734
|
-
// ../auth-logic/dist/effective-state.js
|
|
13735
|
-
function effectiveState(account, now = Date.now()) {
|
|
13736
|
-
const persisted = account.state ?? (account.rateLimited ? "cooldown" : "active");
|
|
13737
|
-
if (persisted === "disabled")
|
|
13738
|
-
return "disabled";
|
|
13739
|
-
if (account.expiresAt != null && account.expiresAt <= now)
|
|
13740
|
-
return "expired";
|
|
13741
|
-
if (persisted === "cooldown" || persisted === "usage-capped") {
|
|
13742
|
-
const reset = account.rateLimitResetsAt ? new Date(account.rateLimitResetsAt).getTime() : 0;
|
|
13743
|
-
if (reset > 0 && reset <= now)
|
|
13744
|
-
return "active";
|
|
13745
|
-
return persisted;
|
|
13746
|
-
}
|
|
13747
|
-
return "active";
|
|
13748
|
-
}
|
|
13749
|
-
|
|
13750
|
-
// ../auth-logic/dist/pick-credential.js
|
|
13751
|
-
function pickCredential(accounts, now = Date.now()) {
|
|
13752
|
-
const active = accounts.filter((a) => effectiveState(a, now) === "active");
|
|
13753
|
-
if (active.length === 0)
|
|
13754
|
-
return null;
|
|
13755
|
-
return [...active].sort((a, b) => {
|
|
13756
|
-
const aCount = a.usage?.requestCount5h ?? 0;
|
|
13757
|
-
const bCount = b.usage?.requestCount5h ?? 0;
|
|
13758
|
-
if (aCount !== bCount)
|
|
13759
|
-
return aCount - bCount;
|
|
13760
|
-
const aLast = a.lastUsed ? new Date(a.lastUsed).getTime() : 0;
|
|
13761
|
-
const bLast = b.lastUsed ? new Date(b.lastUsed).getTime() : 0;
|
|
13762
|
-
return aLast - bLast;
|
|
13763
|
-
})[0] ?? null;
|
|
13764
|
-
}
|
|
13765
|
-
|
|
13766
|
-
// ../auth-logic/dist/next-cooldown-reset.js
|
|
13767
|
-
function nextCooldownReset(accounts, now = Date.now()) {
|
|
13768
|
-
const upcoming = accounts.filter((a) => effectiveState(a, now) === "cooldown").map((a) => a.rateLimitResetsAt ? new Date(a.rateLimitResetsAt).getTime() : 0).filter((ts) => ts > now).sort((a, b) => a - b);
|
|
13769
|
-
return upcoming.length > 0 ? new Date(upcoming[0]).toISOString() : null;
|
|
13770
|
-
}
|
|
13771
|
-
|
|
13772
|
-
// src/commands/auth-status.ts
|
|
13773
13614
|
init_auth();
|
|
13774
13615
|
init_output();
|
|
13775
13616
|
init_exit_codes();
|
|
13776
13617
|
var LOCAL_DATA_DIR = path9.join(os5.homedir(), ".olam", "auth-data");
|
|
13777
|
-
function localHHMM(isoStr) {
|
|
13778
|
-
const d = new Date(isoStr);
|
|
13779
|
-
return d.toLocaleTimeString(void 0, {
|
|
13780
|
-
hour: "2-digit",
|
|
13781
|
-
minute: "2-digit",
|
|
13782
|
-
hour12: false
|
|
13783
|
-
});
|
|
13784
|
-
}
|
|
13785
|
-
function daysAgoStr(expiresAt, now) {
|
|
13786
|
-
const diffDays = Math.floor((now - expiresAt) / (1e3 * 60 * 60 * 24));
|
|
13787
|
-
if (diffDays <= 0) return "expired today";
|
|
13788
|
-
return `expired ${diffDays} day${diffDays === 1 ? "" : "s"} ago`;
|
|
13789
|
-
}
|
|
13790
|
-
function trunc(s, maxLen) {
|
|
13791
|
-
return s.length > maxLen ? s.slice(0, maxLen) : s;
|
|
13792
|
-
}
|
|
13793
|
-
var STATE_PRIORITY = {
|
|
13794
|
-
active: 0,
|
|
13795
|
-
cooldown: 1,
|
|
13796
|
-
"usage-capped": 2,
|
|
13797
|
-
disabled: 3,
|
|
13798
|
-
expired: 4
|
|
13799
|
-
};
|
|
13800
|
-
function formatAuthStatus(accounts, now = Date.now()) {
|
|
13801
|
-
const picked = pickCredential(accounts, now);
|
|
13802
|
-
const rows = accounts.map((account) => {
|
|
13803
|
-
const state = effectiveState(account, now);
|
|
13804
|
-
const isPicked = picked != null && account.id === picked.id;
|
|
13805
|
-
const req5h = account.usage?.requestCount5h ?? 0;
|
|
13806
|
-
const last429 = account.usage?.last429At ? localHHMM(account.usage.last429At) : "never";
|
|
13807
|
-
let reason;
|
|
13808
|
-
if (isPicked) {
|
|
13809
|
-
reason = "\u2190 selected";
|
|
13810
|
-
} else if (state === "active") {
|
|
13811
|
-
reason = `req5h=${req5h} (higher than candidate)`;
|
|
13812
|
-
} else if (state === "cooldown") {
|
|
13813
|
-
const resetTime = account.rateLimitResetsAt ? localHHMM(account.rateLimitResetsAt) : "?";
|
|
13814
|
-
reason = `cooldown until ${resetTime}`;
|
|
13815
|
-
} else if (state === "expired") {
|
|
13816
|
-
reason = daysAgoStr(account.expiresAt ?? 0, now);
|
|
13817
|
-
} else {
|
|
13818
|
-
reason = "disabled";
|
|
13819
|
-
}
|
|
13820
|
-
return { id: account.id, label: account.accountLabel ?? account.id, state, reason, req5h, last429, isPicked };
|
|
13821
|
-
});
|
|
13822
|
-
rows.sort((a, b) => {
|
|
13823
|
-
if (a.isPicked !== b.isPicked) return a.isPicked ? -1 : 1;
|
|
13824
|
-
return STATE_PRIORITY[a.state] - STATE_PRIORITY[b.state];
|
|
13825
|
-
});
|
|
13826
|
-
const COL = { id: 17, label: 17, state: 11, reason: 28, req5h: 7 };
|
|
13827
|
-
const lines = [];
|
|
13828
|
-
const hdr = "id".padEnd(COL.id) + "label".padEnd(COL.label) + "state".padEnd(COL.state) + "reason".padEnd(COL.reason) + "req5h".padEnd(COL.req5h) + "last429";
|
|
13829
|
-
lines.push(pc5.dim(hdr));
|
|
13830
|
-
lines.push(pc5.dim("-".repeat(hdr.length)));
|
|
13831
|
-
for (const row of rows) {
|
|
13832
|
-
const id = trunc(row.id, 16).padEnd(COL.id);
|
|
13833
|
-
const label = trunc(row.label, 16).padEnd(COL.label);
|
|
13834
|
-
const stateRaw = row.state.padEnd(COL.state);
|
|
13835
|
-
const stateColored = row.state === "active" ? pc5.green(stateRaw) : row.state === "cooldown" ? pc5.yellow(stateRaw) : row.state === "expired" ? pc5.red(stateRaw) : pc5.dim(stateRaw);
|
|
13836
|
-
const reason = row.reason.padEnd(COL.reason);
|
|
13837
|
-
const req5h = String(row.req5h).padEnd(COL.req5h);
|
|
13838
|
-
if (row.isPicked) {
|
|
13839
|
-
lines.push(
|
|
13840
|
-
pc5.bold(id) + pc5.bold(label) + stateColored + pc5.green(reason) + pc5.dim(req5h) + pc5.dim(row.last429)
|
|
13841
|
-
);
|
|
13842
|
-
} else {
|
|
13843
|
-
lines.push(id + label + stateColored + reason + pc5.dim(req5h) + pc5.dim(row.last429));
|
|
13844
|
-
}
|
|
13845
|
-
}
|
|
13846
|
-
if (picked == null) {
|
|
13847
|
-
const resetIso = nextCooldownReset(accounts, now);
|
|
13848
|
-
lines.push("");
|
|
13849
|
-
lines.push(
|
|
13850
|
-
resetIso ? pc5.yellow(`Next reset: ${localHHMM(resetIso)}`) : pc5.dim("No reset scheduled")
|
|
13851
|
-
);
|
|
13852
|
-
return { output: lines.join("\n"), exitCode: EXIT_AUTH_NEEDS_ATTENTION };
|
|
13853
|
-
}
|
|
13854
|
-
return { output: lines.join("\n"), exitCode: 0 };
|
|
13855
|
-
}
|
|
13856
|
-
function toSafeAccount(a) {
|
|
13857
|
-
return {
|
|
13858
|
-
id: a.id,
|
|
13859
|
-
accountLabel: a.accountLabel,
|
|
13860
|
-
// expiresAt not exposed in summary — state is pre-computed server-side
|
|
13861
|
-
rateLimited: a.rateLimited,
|
|
13862
|
-
rateLimitResetsAt: a.rateLimitResetsAt,
|
|
13863
|
-
lastUsed: a.lastUsed,
|
|
13864
|
-
state: a.state,
|
|
13865
|
-
usage: a.usage ? { requestCount5h: a.usage.requestCount5h, last429At: a.usage.last429At } : void 0
|
|
13866
|
-
};
|
|
13867
|
-
}
|
|
13868
|
-
async function runAuthStatus(getStatus) {
|
|
13869
|
-
const fetchStatus = getStatus ?? (() => new AuthClient().status());
|
|
13870
|
-
let status;
|
|
13871
|
-
try {
|
|
13872
|
-
status = await fetchStatus();
|
|
13873
|
-
} catch {
|
|
13874
|
-
printError("Failed to contact auth service. Run `olam auth up` first.");
|
|
13875
|
-
process.exitCode = 1;
|
|
13876
|
-
return;
|
|
13877
|
-
}
|
|
13878
|
-
if (!status.reachable) {
|
|
13879
|
-
printError("Auth container is not reachable. Run `olam auth up` first.");
|
|
13880
|
-
process.exitCode = 1;
|
|
13881
|
-
return;
|
|
13882
|
-
}
|
|
13883
|
-
if (status.accounts.length === 0) {
|
|
13884
|
-
console.log(pc5.dim("No credentials found. Run: olam auth login"));
|
|
13885
|
-
return;
|
|
13886
|
-
}
|
|
13887
|
-
const accounts = status.accounts.map(toSafeAccount);
|
|
13888
|
-
const result = formatAuthStatus(accounts);
|
|
13889
|
-
console.log(result.output);
|
|
13890
|
-
if (result.exitCode !== 0) {
|
|
13891
|
-
process.exitCode = result.exitCode;
|
|
13892
|
-
}
|
|
13893
|
-
}
|
|
13894
13618
|
|
|
13895
13619
|
// src/commands/auth-upgrade.ts
|
|
13896
13620
|
init_output();
|
|
13897
13621
|
init_host_cp();
|
|
13898
13622
|
init_auth();
|
|
13899
|
-
import * as
|
|
13900
|
-
import * as
|
|
13623
|
+
import * as fs20 from "node:fs";
|
|
13624
|
+
import * as path23 from "node:path";
|
|
13901
13625
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
13902
13626
|
import ora2 from "ora";
|
|
13903
13627
|
import pc7 from "picocolors";
|
|
@@ -13908,20 +13632,20 @@ init_exit_codes();
|
|
|
13908
13632
|
init_protocol_version();
|
|
13909
13633
|
init_output();
|
|
13910
13634
|
import { spawn as spawn2, spawnSync as spawnSync6 } from "node:child_process";
|
|
13911
|
-
import { existsSync as
|
|
13635
|
+
import { existsSync as existsSync19, readFileSync as readFileSync15 } from "node:fs";
|
|
13912
13636
|
import { join as join25 } from "node:path";
|
|
13913
13637
|
import ora from "ora";
|
|
13914
13638
|
import pc6 from "picocolors";
|
|
13915
13639
|
function loadImageDigests(installRootDir = installRoot()) {
|
|
13916
13640
|
const digestsPath = join25(installRootDir, "dist", "image-digests.json");
|
|
13917
|
-
if (!
|
|
13641
|
+
if (!existsSync19(digestsPath)) {
|
|
13918
13642
|
throw new Error(
|
|
13919
13643
|
`image-digests.json missing at ${digestsPath}. Re-run \`npm install -g @pleri/olam-cli@<version>\` to refresh the tarball.`
|
|
13920
13644
|
);
|
|
13921
13645
|
}
|
|
13922
13646
|
let parsed;
|
|
13923
13647
|
try {
|
|
13924
|
-
parsed = JSON.parse(
|
|
13648
|
+
parsed = JSON.parse(readFileSync15(digestsPath, "utf8"));
|
|
13925
13649
|
} catch (err) {
|
|
13926
13650
|
throw new Error(`image-digests.json is not valid JSON: ${err.message}`);
|
|
13927
13651
|
}
|
|
@@ -14179,9 +13903,9 @@ async function runBootstrap2(opts, deps = {}) {
|
|
|
14179
13903
|
printSuccess("Smoke world created");
|
|
14180
13904
|
}
|
|
14181
13905
|
printHeader("Stack ready");
|
|
14182
|
-
printInfo("host-cp", `running (${digests["host-cp"].slice(0, 19)}\u2026)`);
|
|
14183
|
-
printInfo("auth", `running (${digests.auth.slice(0, 19)}\u2026)`);
|
|
14184
|
-
printInfo("devbox", `pulled (${digests.devbox.slice(0, 19)}\u2026)`);
|
|
13906
|
+
printInfo("olam-host-cp", `running (${digests["host-cp"].slice(0, 19)}\u2026)`);
|
|
13907
|
+
printInfo("olam-auth", `running (${digests.auth.slice(0, 19)}\u2026)`);
|
|
13908
|
+
printInfo("olam-devbox", `pulled (${digests.devbox.slice(0, 19)}\u2026)`);
|
|
14185
13909
|
printInfo("next", '`olam create --task "your task"` to spawn a world');
|
|
14186
13910
|
return { exitCode: 0, summary: "stack ready" };
|
|
14187
13911
|
}
|
|
@@ -14221,8 +13945,8 @@ function parseAuthUpgradeOpts(raw) {
|
|
|
14221
13945
|
};
|
|
14222
13946
|
}
|
|
14223
13947
|
function validateAuthRepoRoot(cwd) {
|
|
14224
|
-
const marker =
|
|
14225
|
-
if (!
|
|
13948
|
+
const marker = path23.join(cwd, "packages/auth-service/Dockerfile");
|
|
13949
|
+
if (!fs20.existsSync(marker)) {
|
|
14226
13950
|
return {
|
|
14227
13951
|
ok: false,
|
|
14228
13952
|
error: `Not an olam repo root (expected ${marker}).
|
|
@@ -14589,6 +14313,185 @@ function registerAuthUpgrade(auth) {
|
|
|
14589
14313
|
});
|
|
14590
14314
|
}
|
|
14591
14315
|
|
|
14316
|
+
// src/commands/services.ts
|
|
14317
|
+
init_auth();
|
|
14318
|
+
init_output();
|
|
14319
|
+
import { execFileSync as execFileSync4, spawnSync as spawnSync8 } from "node:child_process";
|
|
14320
|
+
import pc8 from "picocolors";
|
|
14321
|
+
var MCP_AUTH_PORT = 9998;
|
|
14322
|
+
var MCP_AUTH_VOLUME = "olam-mcp-auth-data";
|
|
14323
|
+
var MCP_AUTH_CONTAINER = "olam-mcp-auth";
|
|
14324
|
+
var MCP_AUTH_LOCAL_TAG = "olam-mcp-auth:local";
|
|
14325
|
+
var MCP_AUTH_PUBLISHED_TAG = "ghcr.io/pleri/olam-mcp-auth:latest";
|
|
14326
|
+
var MCP_AUTH_HEALTH_URL = `http://127.0.0.1:${MCP_AUTH_PORT}/health`;
|
|
14327
|
+
var MCP_AUTH_HEALTH_TIMEOUT_MS = 15e3;
|
|
14328
|
+
var McpAuthContainerController = class {
|
|
14329
|
+
imageTag = MCP_AUTH_LOCAL_TAG;
|
|
14330
|
+
status() {
|
|
14331
|
+
const r = spawnSync8(
|
|
14332
|
+
"docker",
|
|
14333
|
+
["inspect", "--format", "{{.State.Status}}|{{.Id}}", MCP_AUTH_CONTAINER],
|
|
14334
|
+
{ encoding: "utf-8" }
|
|
14335
|
+
);
|
|
14336
|
+
if (r.status === 0) {
|
|
14337
|
+
const [stateRaw, id] = r.stdout.trim().split("|");
|
|
14338
|
+
return {
|
|
14339
|
+
state: stateRaw === "running" ? "running" : "stopped",
|
|
14340
|
+
port: MCP_AUTH_PORT,
|
|
14341
|
+
containerId: id
|
|
14342
|
+
};
|
|
14343
|
+
}
|
|
14344
|
+
return { state: "missing", port: MCP_AUTH_PORT };
|
|
14345
|
+
}
|
|
14346
|
+
imageExists(tag = this.imageTag) {
|
|
14347
|
+
return spawnSync8("docker", ["image", "inspect", tag], { encoding: "utf-8" }).status === 0;
|
|
14348
|
+
}
|
|
14349
|
+
start() {
|
|
14350
|
+
const current = this.status();
|
|
14351
|
+
if (current.state === "running") return;
|
|
14352
|
+
if (current.state === "stopped") {
|
|
14353
|
+
execFileSync4("docker", ["start", MCP_AUTH_CONTAINER], { stdio: "pipe" });
|
|
14354
|
+
return;
|
|
14355
|
+
}
|
|
14356
|
+
if (!this.imageExists()) {
|
|
14357
|
+
if (this.imageTag !== MCP_AUTH_PUBLISHED_TAG && this.imageExists(MCP_AUTH_PUBLISHED_TAG)) {
|
|
14358
|
+
this.imageTag = MCP_AUTH_PUBLISHED_TAG;
|
|
14359
|
+
} else {
|
|
14360
|
+
throw new Error(
|
|
14361
|
+
`mcp-auth image '${this.imageTag}' not found locally. Run \`olam bootstrap\` to pull the published image.`
|
|
14362
|
+
);
|
|
14363
|
+
}
|
|
14364
|
+
}
|
|
14365
|
+
execFileSync4(
|
|
14366
|
+
"docker",
|
|
14367
|
+
[
|
|
14368
|
+
"run",
|
|
14369
|
+
"--detach",
|
|
14370
|
+
"--name",
|
|
14371
|
+
MCP_AUTH_CONTAINER,
|
|
14372
|
+
"--restart",
|
|
14373
|
+
"unless-stopped",
|
|
14374
|
+
"--publish",
|
|
14375
|
+
`${MCP_AUTH_PORT}:${MCP_AUTH_PORT}`,
|
|
14376
|
+
"--volume",
|
|
14377
|
+
`${MCP_AUTH_VOLUME}:/mcp-auth-data`,
|
|
14378
|
+
this.imageTag
|
|
14379
|
+
],
|
|
14380
|
+
{ stdio: "pipe" }
|
|
14381
|
+
);
|
|
14382
|
+
}
|
|
14383
|
+
stop() {
|
|
14384
|
+
const current = this.status();
|
|
14385
|
+
if (current.state !== "running") return;
|
|
14386
|
+
execFileSync4("docker", ["stop", MCP_AUTH_CONTAINER], { stdio: "pipe" });
|
|
14387
|
+
}
|
|
14388
|
+
remove() {
|
|
14389
|
+
spawnSync8("docker", ["rm", "-f", MCP_AUTH_CONTAINER], { stdio: "pipe" });
|
|
14390
|
+
}
|
|
14391
|
+
async waitForReady(timeoutMs = MCP_AUTH_HEALTH_TIMEOUT_MS) {
|
|
14392
|
+
const deadline = Date.now() + timeoutMs;
|
|
14393
|
+
while (Date.now() < deadline) {
|
|
14394
|
+
try {
|
|
14395
|
+
const res = await fetch(MCP_AUTH_HEALTH_URL, { signal: AbortSignal.timeout(1500) });
|
|
14396
|
+
if (res.ok) return true;
|
|
14397
|
+
} catch {
|
|
14398
|
+
}
|
|
14399
|
+
await sleep3(500);
|
|
14400
|
+
}
|
|
14401
|
+
return false;
|
|
14402
|
+
}
|
|
14403
|
+
};
|
|
14404
|
+
function sleep3(ms) {
|
|
14405
|
+
return new Promise((resolve8) => setTimeout(resolve8, ms));
|
|
14406
|
+
}
|
|
14407
|
+
async function servicesUp() {
|
|
14408
|
+
const auth = new AuthContainerController();
|
|
14409
|
+
const mcpAuth = new McpAuthContainerController();
|
|
14410
|
+
const authStatus = auth.status();
|
|
14411
|
+
if (authStatus.state === "running") {
|
|
14412
|
+
printSuccess(`olam-auth already running on :${authStatus.port}`);
|
|
14413
|
+
} else {
|
|
14414
|
+
try {
|
|
14415
|
+
auth.start();
|
|
14416
|
+
} catch (err) {
|
|
14417
|
+
printError(`olam-auth failed to start: ${err instanceof Error ? err.message : String(err)}`);
|
|
14418
|
+
return { exitCode: 1 };
|
|
14419
|
+
}
|
|
14420
|
+
const ready = await auth.waitForReady(15e3);
|
|
14421
|
+
if (!ready) {
|
|
14422
|
+
printWarning("olam-auth started but /health did not respond within 15s.");
|
|
14423
|
+
return { exitCode: 1 };
|
|
14424
|
+
}
|
|
14425
|
+
printSuccess("olam-auth started");
|
|
14426
|
+
}
|
|
14427
|
+
const mcpStatus = mcpAuth.status();
|
|
14428
|
+
if (mcpStatus.state === "running") {
|
|
14429
|
+
printSuccess(`olam-mcp-auth already running on :${mcpStatus.port}`);
|
|
14430
|
+
} else {
|
|
14431
|
+
try {
|
|
14432
|
+
mcpAuth.start();
|
|
14433
|
+
} catch (err) {
|
|
14434
|
+
printError(`olam-mcp-auth failed to start: ${err instanceof Error ? err.message : String(err)}`);
|
|
14435
|
+
return { exitCode: 1 };
|
|
14436
|
+
}
|
|
14437
|
+
const ready = await mcpAuth.waitForReady();
|
|
14438
|
+
if (!ready) {
|
|
14439
|
+
printWarning("olam-mcp-auth started but /health did not respond within 15s.");
|
|
14440
|
+
return { exitCode: 1 };
|
|
14441
|
+
}
|
|
14442
|
+
printSuccess("olam-mcp-auth started");
|
|
14443
|
+
}
|
|
14444
|
+
printHeader("Services up");
|
|
14445
|
+
printInfo("olam-auth", ":9999");
|
|
14446
|
+
printInfo("olam-mcp-auth", ":9998");
|
|
14447
|
+
return { exitCode: 0 };
|
|
14448
|
+
}
|
|
14449
|
+
function servicesDown() {
|
|
14450
|
+
const auth = new AuthContainerController();
|
|
14451
|
+
const mcpAuth = new McpAuthContainerController();
|
|
14452
|
+
let exitCode = 0;
|
|
14453
|
+
try {
|
|
14454
|
+
auth.stop();
|
|
14455
|
+
printSuccess("olam-auth stopped.");
|
|
14456
|
+
} catch (err) {
|
|
14457
|
+
printError(`olam-auth: ${err instanceof Error ? err.message : String(err)}`);
|
|
14458
|
+
exitCode = 1;
|
|
14459
|
+
}
|
|
14460
|
+
try {
|
|
14461
|
+
mcpAuth.stop();
|
|
14462
|
+
printSuccess("olam-mcp-auth stopped.");
|
|
14463
|
+
} catch (err) {
|
|
14464
|
+
printError(`olam-mcp-auth: ${err instanceof Error ? err.message : String(err)}`);
|
|
14465
|
+
exitCode = 1;
|
|
14466
|
+
}
|
|
14467
|
+
return { exitCode };
|
|
14468
|
+
}
|
|
14469
|
+
function servicesStatus() {
|
|
14470
|
+
const auth = new AuthContainerController();
|
|
14471
|
+
const mcpAuth = new McpAuthContainerController();
|
|
14472
|
+
printHeader("Services status");
|
|
14473
|
+
const authState = auth.status();
|
|
14474
|
+
const authStateStr = authState.state === "running" ? pc8.green("running") : authState.state === "stopped" ? pc8.yellow("stopped") : pc8.red("missing");
|
|
14475
|
+
printInfo("olam-auth", `${authStateStr} :${authState.port}`);
|
|
14476
|
+
const mcpState = mcpAuth.status();
|
|
14477
|
+
const mcpStateStr = mcpState.state === "running" ? pc8.green("running") : mcpState.state === "stopped" ? pc8.yellow("stopped") : pc8.red("missing");
|
|
14478
|
+
printInfo("olam-mcp-auth", `${mcpStateStr} :${mcpState.port}`);
|
|
14479
|
+
}
|
|
14480
|
+
function registerServices(program2) {
|
|
14481
|
+
const services = program2.command("services").description("Manage Olam service containers (olam-auth, olam-mcp-auth)");
|
|
14482
|
+
services.command("up").description("Start all service containers (idempotent)").action(async () => {
|
|
14483
|
+
const result = await servicesUp();
|
|
14484
|
+
if (result.exitCode !== 0) process.exitCode = result.exitCode;
|
|
14485
|
+
});
|
|
14486
|
+
services.command("down").description("Stop all service containers").action(() => {
|
|
14487
|
+
const result = servicesDown();
|
|
14488
|
+
if (result.exitCode !== 0) process.exitCode = result.exitCode;
|
|
14489
|
+
});
|
|
14490
|
+
services.command("status").description("Show state of all service containers").action(() => {
|
|
14491
|
+
servicesStatus();
|
|
14492
|
+
});
|
|
14493
|
+
}
|
|
14494
|
+
|
|
14592
14495
|
// src/commands/auth.ts
|
|
14593
14496
|
function openBrowser(url) {
|
|
14594
14497
|
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
@@ -14609,44 +14512,19 @@ async function promptLine(question) {
|
|
|
14609
14512
|
}
|
|
14610
14513
|
function registerAuth(program2) {
|
|
14611
14514
|
const auth = program2.command("auth").description("Manage the local Claude auth container");
|
|
14612
|
-
auth.command("up").description("Start the auth container
|
|
14613
|
-
|
|
14614
|
-
const
|
|
14615
|
-
if (
|
|
14616
|
-
printSuccess(`Auth container already running on :${initial.port}`);
|
|
14617
|
-
return;
|
|
14618
|
-
}
|
|
14619
|
-
try {
|
|
14620
|
-
controller.start();
|
|
14621
|
-
} catch (err) {
|
|
14622
|
-
printError(err instanceof Error ? err.message : "failed to start");
|
|
14623
|
-
process.exitCode = 1;
|
|
14624
|
-
return;
|
|
14625
|
-
}
|
|
14626
|
-
const ready = await controller.waitForReady(15e3);
|
|
14627
|
-
if (!ready) {
|
|
14628
|
-
printWarning("Container started but /health did not respond within 15s.");
|
|
14629
|
-
process.exitCode = 1;
|
|
14630
|
-
return;
|
|
14631
|
-
}
|
|
14632
|
-
printHeader("Auth container up");
|
|
14633
|
-
printInfo("Port", String(initial.port));
|
|
14634
|
-
printInfo("Volume", "olam-auth-data");
|
|
14635
|
-
console.log(`
|
|
14636
|
-
${pc8.dim("Next: olam auth login")}`);
|
|
14515
|
+
auth.command("up").description("[deprecated] Start the auth container \u2014 use `olam services up` instead").action(async () => {
|
|
14516
|
+
printWarning("`olam auth up` is deprecated. Use `olam services up` instead.");
|
|
14517
|
+
const result = await servicesUp();
|
|
14518
|
+
if (result.exitCode !== 0) process.exitCode = result.exitCode;
|
|
14637
14519
|
});
|
|
14638
|
-
auth.command("down").description("Stop the auth container
|
|
14639
|
-
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
printSuccess("Auth container stopped.");
|
|
14643
|
-
} catch (err) {
|
|
14644
|
-
printError(err instanceof Error ? err.message : "failed to stop");
|
|
14645
|
-
process.exitCode = 1;
|
|
14646
|
-
}
|
|
14520
|
+
auth.command("down").description("[deprecated] Stop the auth container \u2014 use `olam services down` instead").action(() => {
|
|
14521
|
+
printWarning("`olam auth down` is deprecated. Use `olam services down` instead.");
|
|
14522
|
+
const result = servicesDown();
|
|
14523
|
+
if (result.exitCode !== 0) process.exitCode = result.exitCode;
|
|
14647
14524
|
});
|
|
14648
|
-
auth.command("status").description("Show
|
|
14649
|
-
|
|
14525
|
+
auth.command("status").description("[deprecated] Show container state \u2014 use `olam services status` instead").action(() => {
|
|
14526
|
+
printWarning("`olam auth status` is deprecated. Use `olam services status` instead.");
|
|
14527
|
+
servicesStatus();
|
|
14650
14528
|
});
|
|
14651
14529
|
auth.command("list").description("List all stored credentials with state, usage, and rate-limit status").action(async () => {
|
|
14652
14530
|
const client = new AuthClient();
|
|
@@ -14658,15 +14536,15 @@ ${pc8.dim("Next: olam auth login")}`);
|
|
|
14658
14536
|
}
|
|
14659
14537
|
printHeader(`Credentials (${status.accounts.length})`);
|
|
14660
14538
|
if (status.accounts.length === 0) {
|
|
14661
|
-
console.log(` ${
|
|
14539
|
+
console.log(` ${pc9.dim("No credentials \u2014 run: olam auth login --label primary")}`);
|
|
14662
14540
|
return;
|
|
14663
14541
|
}
|
|
14664
14542
|
const stateColor = (s) => {
|
|
14665
|
-
if (s === "active") return
|
|
14666
|
-
if (s === "cooldown") return
|
|
14667
|
-
if (s === "expired") return
|
|
14668
|
-
if (s === "disabled") return
|
|
14669
|
-
return
|
|
14543
|
+
if (s === "active") return pc9.green("active");
|
|
14544
|
+
if (s === "cooldown") return pc9.yellow("cooldown");
|
|
14545
|
+
if (s === "expired") return pc9.red("expired");
|
|
14546
|
+
if (s === "disabled") return pc9.dim("disabled");
|
|
14547
|
+
return pc9.dim(s ?? "unknown");
|
|
14670
14548
|
};
|
|
14671
14549
|
for (const a of status.accounts) {
|
|
14672
14550
|
const label = a.accountLabel ?? a.id;
|
|
@@ -14674,7 +14552,7 @@ ${pc8.dim("Next: olam auth login")}`);
|
|
|
14674
14552
|
const last429 = a.usage?.last429At ? `last429=${a.usage.last429At}` : "last429=never";
|
|
14675
14553
|
const reset = a.rateLimitResetsAt ? `resets=${a.rateLimitResetsAt}` : "";
|
|
14676
14554
|
console.log(
|
|
14677
|
-
` ${
|
|
14555
|
+
` ${pc9.bold(label.padEnd(18))} ${stateColor(a.state).padEnd(18)} ${pc9.dim(`req5h=${reqs}`)} ${pc9.dim(`exp=${a.expiresIn}`)} ${pc9.dim(last429)} ${pc9.yellow(reset)}`
|
|
14678
14556
|
);
|
|
14679
14557
|
}
|
|
14680
14558
|
});
|
|
@@ -14712,7 +14590,7 @@ ${pc8.dim("Next: olam auth login")}`);
|
|
|
14712
14590
|
const preflight = await runAuthPreflight({ autoStart: true });
|
|
14713
14591
|
if (preflight.verdict !== "ok" && preflight.verdict !== "no-accounts") {
|
|
14714
14592
|
printError(preflight.message);
|
|
14715
|
-
console.log(` ${
|
|
14593
|
+
console.log(` ${pc9.dim(preflight.remedy)}`);
|
|
14716
14594
|
process.exitCode = 1;
|
|
14717
14595
|
return;
|
|
14718
14596
|
}
|
|
@@ -14745,14 +14623,14 @@ ${pc8.dim("Next: olam auth login")}`);
|
|
|
14745
14623
|
}
|
|
14746
14624
|
printHeader("Claude OAuth \u2014 PKCE flow");
|
|
14747
14625
|
console.log(`
|
|
14748
|
-
${
|
|
14749
|
-
console.log(` ${
|
|
14626
|
+
${pc9.bold("1.")} Opening Claude in your default browser\u2026`);
|
|
14627
|
+
console.log(` ${pc9.dim(pending.loginUrl)}`);
|
|
14750
14628
|
openBrowser(pending.loginUrl);
|
|
14751
14629
|
console.log(`
|
|
14752
|
-
${
|
|
14753
|
-
console.log(` ${
|
|
14630
|
+
${pc9.bold("2.")} After approving, paste the authorization code from the redirect page.`);
|
|
14631
|
+
console.log(` ${pc9.dim("(Format: <code>#<state> or just <code>.)")}
|
|
14754
14632
|
`);
|
|
14755
|
-
const raw = await promptLine(`${
|
|
14633
|
+
const raw = await promptLine(`${pc9.dim("code:")} `);
|
|
14756
14634
|
if (!raw) {
|
|
14757
14635
|
printError("No code provided.");
|
|
14758
14636
|
process.exitCode = 1;
|
|
@@ -14763,7 +14641,7 @@ ${pc8.dim("Next: olam auth login")}`);
|
|
|
14763
14641
|
const result = await client.completeLogin(statePart, codePart);
|
|
14764
14642
|
printSuccess(`Account stored: ${result.account} (${result.expiresIn})`);
|
|
14765
14643
|
console.log(`
|
|
14766
|
-
${
|
|
14644
|
+
${pc9.dim("Next: olam create --name my-world")}`);
|
|
14767
14645
|
} catch (err) {
|
|
14768
14646
|
printError(err instanceof Error ? err.message : "token exchange failed");
|
|
14769
14647
|
process.exitCode = 1;
|
|
@@ -14794,15 +14672,15 @@ ${pc8.dim("Next: olam create --name my-world")}`);
|
|
|
14794
14672
|
|
|
14795
14673
|
// src/commands/create.ts
|
|
14796
14674
|
init_manager();
|
|
14797
|
-
import { spawnSync as
|
|
14798
|
-
import { existsSync as
|
|
14799
|
-
import { dirname as
|
|
14675
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
14676
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
14677
|
+
import { dirname as dirname14, resolve as resolve7 } from "node:path";
|
|
14800
14678
|
import ora3 from "ora";
|
|
14801
|
-
import
|
|
14679
|
+
import pc10 from "picocolors";
|
|
14802
14680
|
|
|
14803
14681
|
// ../core/dist/world/devbox-freshness.js
|
|
14804
14682
|
import { execSync as execSync6 } from "node:child_process";
|
|
14805
|
-
import { existsSync as
|
|
14683
|
+
import { existsSync as existsSync21, statSync as statSync5 } from "node:fs";
|
|
14806
14684
|
import { join as join27 } from "node:path";
|
|
14807
14685
|
var DEFAULT_DEVBOX_IMAGE = "olam-devbox:latest";
|
|
14808
14686
|
var DEVBOX_BAKED_SOURCES = [
|
|
@@ -14871,9 +14749,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
|
|
|
14871
14749
|
"These source files have changed since the image was built; the",
|
|
14872
14750
|
"changes will NOT take effect in fresh worlds until you rebuild:"
|
|
14873
14751
|
];
|
|
14874
|
-
for (const { path:
|
|
14752
|
+
for (const { path: path44, mtimeMs } of result.newerSources) {
|
|
14875
14753
|
const when = new Date(mtimeMs).toISOString();
|
|
14876
|
-
lines.push(` \u2022 ${
|
|
14754
|
+
lines.push(` \u2022 ${path44} (modified ${when})`);
|
|
14877
14755
|
}
|
|
14878
14756
|
lines.push("");
|
|
14879
14757
|
lines.push("Rebuild with:");
|
|
@@ -14892,7 +14770,7 @@ function defaultDockerInspect(image) {
|
|
|
14892
14770
|
}
|
|
14893
14771
|
function defaultStatMtime(absPath) {
|
|
14894
14772
|
try {
|
|
14895
|
-
if (!
|
|
14773
|
+
if (!existsSync21(absPath))
|
|
14896
14774
|
return null;
|
|
14897
14775
|
return statSync5(absPath).mtimeMs;
|
|
14898
14776
|
} catch {
|
|
@@ -15032,15 +14910,15 @@ init_host_cp();
|
|
|
15032
14910
|
var HOST_CP_URL = "http://127.0.0.1:19000";
|
|
15033
14911
|
async function readHostCpTokenForCreate() {
|
|
15034
14912
|
try {
|
|
15035
|
-
const { default:
|
|
14913
|
+
const { default: fs40 } = await import("node:fs");
|
|
15036
14914
|
const { default: os24 } = await import("node:os");
|
|
15037
|
-
const { default:
|
|
15038
|
-
const tp =
|
|
15039
|
-
process.env.OLAM_HOME ??
|
|
14915
|
+
const { default: path44 } = await import("node:path");
|
|
14916
|
+
const tp = path44.join(
|
|
14917
|
+
process.env.OLAM_HOME ?? path44.join(os24.homedir(), ".olam"),
|
|
15040
14918
|
"host-cp.token"
|
|
15041
14919
|
);
|
|
15042
|
-
if (!
|
|
15043
|
-
return
|
|
14920
|
+
if (!fs40.existsSync(tp)) return null;
|
|
14921
|
+
return fs40.readFileSync(tp, "utf-8").trim();
|
|
15044
14922
|
} catch {
|
|
15045
14923
|
return null;
|
|
15046
14924
|
}
|
|
@@ -15065,7 +14943,7 @@ function registerCreate(program2) {
|
|
|
15065
14943
|
if (decision.stderrLine) {
|
|
15066
14944
|
process.stderr.write(decision.stderrLine + "\n");
|
|
15067
14945
|
}
|
|
15068
|
-
|
|
14946
|
+
spawnSync9("docker", ["pull", overrideRef], { stdio: "pipe" });
|
|
15069
14947
|
const { inspectImageProtocolVersions: inspectImageProtocolVersions2, checkProtocolOverlap: checkProtocolOverlap2 } = await Promise.resolve().then(() => (init_protocol_version(), protocol_version_exports));
|
|
15070
14948
|
const inspect = inspectImageProtocolVersions2(overrideRef);
|
|
15071
14949
|
if (inspect.inspectFailed) {
|
|
@@ -15114,9 +14992,9 @@ function registerCreate(program2) {
|
|
|
15114
14992
|
const reason = inferred.repos.length === 0 ? "no repo names extracted from prompt" : `inference confidence ${inferred.confidence.toFixed(2)} below ${PICKER_CONFIDENCE_THRESHOLD}`;
|
|
15115
14993
|
printError(`Picker needed: ${reason}`);
|
|
15116
14994
|
if (catalogRepos.length > 0) {
|
|
15117
|
-
console.log(
|
|
14995
|
+
console.log(pc10.dim(` available repos: ${catalogRepos.join(", ")}`));
|
|
15118
14996
|
}
|
|
15119
|
-
console.log(
|
|
14997
|
+
console.log(pc10.dim(" rerun with explicit --workspace <name> or --repos <a> <b> <c>"));
|
|
15120
14998
|
process.exitCode = 1;
|
|
15121
14999
|
return;
|
|
15122
15000
|
}
|
|
@@ -15134,7 +15012,7 @@ function registerCreate(program2) {
|
|
|
15134
15012
|
inferenceSpinner.fail(`Multiple workspaces match (${decision.result})`);
|
|
15135
15013
|
const cands = decision.result === "exact-N" ? decision.candidates.map((w) => w.name) : decision.candidates.map((c) => c.workspace.name);
|
|
15136
15014
|
printError(`Picker needed: ${cands.join(", ")}`);
|
|
15137
|
-
console.log(
|
|
15015
|
+
console.log(pc10.dim(" rerun with explicit --workspace <name>"));
|
|
15138
15016
|
process.exitCode = 1;
|
|
15139
15017
|
return;
|
|
15140
15018
|
} else {
|
|
@@ -15182,7 +15060,7 @@ function registerCreate(program2) {
|
|
|
15182
15060
|
throw err;
|
|
15183
15061
|
}
|
|
15184
15062
|
const spinner2 = ora3("Rebuilding olam-devbox:latest\u2026").start();
|
|
15185
|
-
const rebuild =
|
|
15063
|
+
const rebuild = spawnSync9(
|
|
15186
15064
|
"bash",
|
|
15187
15065
|
[buildScript],
|
|
15188
15066
|
{ cwd: repoRoot, stdio: "inherit" }
|
|
@@ -15248,10 +15126,10 @@ function registerCreate(program2) {
|
|
|
15248
15126
|
}
|
|
15249
15127
|
if (world.credentialsInjected?.claude) {
|
|
15250
15128
|
console.log(`
|
|
15251
|
-
${
|
|
15129
|
+
${pc10.green("Credentials injected. World is ready for dispatch.")}`);
|
|
15252
15130
|
} else if (world.dashboardUrl) {
|
|
15253
15131
|
console.log(`
|
|
15254
|
-
${
|
|
15132
|
+
${pc10.yellow("Authenticate at")} ${world.dashboardUrl}`);
|
|
15255
15133
|
}
|
|
15256
15134
|
if (opts.hostCp !== false) {
|
|
15257
15135
|
const probeResult = await probeHostCp().catch(() => null);
|
|
@@ -15263,14 +15141,14 @@ ${pc9.yellow("Authenticate at")} ${world.dashboardUrl}`);
|
|
|
15263
15141
|
process.stderr.write(
|
|
15264
15142
|
[
|
|
15265
15143
|
"",
|
|
15266
|
-
|
|
15144
|
+
pc10.red("Host CP probe failed."),
|
|
15267
15145
|
` tried: http://127.0.0.1:19000/api/bootstrap \u2192 ${diag.bootstrapStatus}`,
|
|
15268
15146
|
` tried: docker container "olam-host-cp" \u2192 ${diag.containerStatus}`,
|
|
15269
15147
|
"",
|
|
15270
|
-
|
|
15271
|
-
` ${
|
|
15272
|
-
` ${
|
|
15273
|
-
` OR pass ${
|
|
15148
|
+
pc10.yellow("World was created but the SPA inbox will not show it until you:"),
|
|
15149
|
+
` ${pc10.cyan("olam host-cp start")} (start the host CP)`,
|
|
15150
|
+
` ${pc10.cyan(`olam host-cp register --world ${world.id}`)} (register manually)`,
|
|
15151
|
+
` OR pass ${pc10.dim("--no-host-cp")} on next create to suppress this check.`,
|
|
15274
15152
|
""
|
|
15275
15153
|
].join("\n")
|
|
15276
15154
|
);
|
|
@@ -15302,13 +15180,13 @@ ${pc9.yellow("Authenticate at")} ${world.dashboardUrl}`);
|
|
|
15302
15180
|
process.stderr.write(
|
|
15303
15181
|
[
|
|
15304
15182
|
"",
|
|
15305
|
-
|
|
15183
|
+
pc10.red("Host CP registry POST failed."),
|
|
15306
15184
|
` url: ${hostCpUrl}/api/admin/registry`,
|
|
15307
15185
|
` status: ${reg.status}`,
|
|
15308
15186
|
` error: ${reg.error}`,
|
|
15309
15187
|
"",
|
|
15310
|
-
|
|
15311
|
-
` ${
|
|
15188
|
+
pc10.yellow("World was created but not registered. Run manually:"),
|
|
15189
|
+
` ${pc10.cyan(`olam host-cp register --world ${world.id}`)}`,
|
|
15312
15190
|
""
|
|
15313
15191
|
].join("\n")
|
|
15314
15192
|
);
|
|
@@ -15363,7 +15241,7 @@ ${pc9.yellow("Authenticate at")} ${world.dashboardUrl}`);
|
|
|
15363
15241
|
}
|
|
15364
15242
|
const worldUrl = `${hostCpUrl}/world/${encodeURIComponent(world.id)}`;
|
|
15365
15243
|
console.log(`
|
|
15366
|
-
${
|
|
15244
|
+
${pc10.cyan("Host CP UI:")} ${worldUrl}`);
|
|
15367
15245
|
if (opts.open !== false && reg.ok) {
|
|
15368
15246
|
const openResult = openUrl(worldUrl);
|
|
15369
15247
|
if (openResult.opened) {
|
|
@@ -15377,14 +15255,7 @@ ${pc9.cyan("Host CP UI:")} ${worldUrl}`);
|
|
|
15377
15255
|
spinner.fail("Failed to create world");
|
|
15378
15256
|
if (err instanceof AuthPreflightError) {
|
|
15379
15257
|
printError(err.message);
|
|
15380
|
-
if (err.remedy) console.log(` ${
|
|
15381
|
-
} else if (err instanceof RepoSelectionRequiredError) {
|
|
15382
|
-
printError(err.message);
|
|
15383
|
-
if (err.availableRepos.length > 0) {
|
|
15384
|
-
const example = err.availableRepos[0];
|
|
15385
|
-
console.log(` ${pc9.dim(`Example: olam create --name <name> --repos ${example} --task "<task>"`)}`);
|
|
15386
|
-
console.log(` ${pc9.dim('Or: olam create --name <name> --workspace <workspace> --task "<task>"')}`);
|
|
15387
|
-
}
|
|
15258
|
+
if (err.remedy) console.log(` ${pc10.dim(err.remedy)}`);
|
|
15388
15259
|
} else {
|
|
15389
15260
|
printError(err instanceof Error ? err.message : String(err));
|
|
15390
15261
|
}
|
|
@@ -15395,10 +15266,10 @@ ${pc9.cyan("Host CP UI:")} ${worldUrl}`);
|
|
|
15395
15266
|
function resolveRepoRoot(start) {
|
|
15396
15267
|
let cur = start;
|
|
15397
15268
|
while (true) {
|
|
15398
|
-
if (
|
|
15269
|
+
if (existsSync22(resolve7(cur, "packages")) && existsSync22(resolve7(cur, "package.json"))) {
|
|
15399
15270
|
return cur;
|
|
15400
15271
|
}
|
|
15401
|
-
const parent =
|
|
15272
|
+
const parent = dirname14(cur);
|
|
15402
15273
|
if (parent === cur) return start;
|
|
15403
15274
|
cur = parent;
|
|
15404
15275
|
}
|
|
@@ -15409,12 +15280,12 @@ function defaultNameFromPrompt(prompt) {
|
|
|
15409
15280
|
}
|
|
15410
15281
|
async function readHostCpToken3() {
|
|
15411
15282
|
try {
|
|
15412
|
-
const { default:
|
|
15283
|
+
const { default: fs40 } = await import("node:fs");
|
|
15413
15284
|
const { default: os24 } = await import("node:os");
|
|
15414
|
-
const { default:
|
|
15415
|
-
const tp =
|
|
15416
|
-
if (!
|
|
15417
|
-
const raw =
|
|
15285
|
+
const { default: path44 } = await import("node:path");
|
|
15286
|
+
const tp = path44.join(os24.homedir(), ".olam", "host-cp.token");
|
|
15287
|
+
if (!fs40.existsSync(tp)) return null;
|
|
15288
|
+
const raw = fs40.readFileSync(tp, "utf-8").trim();
|
|
15418
15289
|
return raw.length > 0 ? raw : null;
|
|
15419
15290
|
} catch {
|
|
15420
15291
|
return null;
|
|
@@ -15459,7 +15330,7 @@ async function fetchHostCpExactMatches(projects) {
|
|
|
15459
15330
|
init_context();
|
|
15460
15331
|
init_output();
|
|
15461
15332
|
import ora4 from "ora";
|
|
15462
|
-
import
|
|
15333
|
+
import pc11 from "picocolors";
|
|
15463
15334
|
|
|
15464
15335
|
// ../core/dist/orchestrator/dispatch.js
|
|
15465
15336
|
var DEEP_MODE_SUFFIX = "\n\nUltrathink and use sub-agents (the Agent tool) to parallelize independent work. Break complex tasks into focused sub-tasks.";
|
|
@@ -15546,7 +15417,7 @@ OLAM_EOF`
|
|
|
15546
15417
|
const containerName = `olam-${worldId}-devbox`;
|
|
15547
15418
|
console.log(
|
|
15548
15419
|
`
|
|
15549
|
-
${
|
|
15420
|
+
${pc11.dim(`Watch live: docker exec -it ${containerName} tmux attach -t claude-main -r`)}`
|
|
15550
15421
|
);
|
|
15551
15422
|
} catch (err) {
|
|
15552
15423
|
spinner.fail("Dispatch failed");
|
|
@@ -15559,7 +15430,7 @@ ${pc10.dim(`Watch live: docker exec -it ${containerName} tmux attach -t claude-m
|
|
|
15559
15430
|
// src/commands/observe.ts
|
|
15560
15431
|
init_context();
|
|
15561
15432
|
init_output();
|
|
15562
|
-
import
|
|
15433
|
+
import pc12 from "picocolors";
|
|
15563
15434
|
function registerObserve(program2) {
|
|
15564
15435
|
program2.command("observe").description("Stream thoughts from a world (coming soon)").argument("<world>", "World ID").action(async (worldId) => {
|
|
15565
15436
|
const { ctx, error } = await loadContext();
|
|
@@ -15579,15 +15450,15 @@ function registerObserve(program2) {
|
|
|
15579
15450
|
checkVersionPin2(worldId, world.workspacePath);
|
|
15580
15451
|
}
|
|
15581
15452
|
console.log(
|
|
15582
|
-
|
|
15453
|
+
pc12.yellow("Observation is coming in a future release.")
|
|
15583
15454
|
);
|
|
15584
15455
|
console.log(
|
|
15585
|
-
|
|
15456
|
+
pc12.dim("This will stream the world's reasoning in real-time.")
|
|
15586
15457
|
);
|
|
15587
15458
|
const containerName = `olam-${worldId}-devbox`;
|
|
15588
15459
|
console.log(
|
|
15589
15460
|
`
|
|
15590
|
-
${
|
|
15461
|
+
${pc12.dim(`For now: docker exec -it ${containerName} tmux attach -t claude-main -r`)}`
|
|
15591
15462
|
);
|
|
15592
15463
|
});
|
|
15593
15464
|
}
|
|
@@ -15595,7 +15466,7 @@ ${pc11.dim(`For now: docker exec -it ${containerName} tmux attach -t claude-main
|
|
|
15595
15466
|
// src/commands/list.ts
|
|
15596
15467
|
init_context();
|
|
15597
15468
|
init_output();
|
|
15598
|
-
import
|
|
15469
|
+
import pc13 from "picocolors";
|
|
15599
15470
|
function registerList(program2) {
|
|
15600
15471
|
program2.command("list").alias("ls").description("List active worlds").action(async () => {
|
|
15601
15472
|
const { ctx, error } = await loadContext();
|
|
@@ -15606,18 +15477,18 @@ function registerList(program2) {
|
|
|
15606
15477
|
}
|
|
15607
15478
|
const worlds = ctx.worldManager.listWorlds();
|
|
15608
15479
|
if (worlds.length === 0) {
|
|
15609
|
-
console.log(
|
|
15480
|
+
console.log(pc13.dim("No worlds. Create one with `olam create --name my-world`."));
|
|
15610
15481
|
return;
|
|
15611
15482
|
}
|
|
15612
|
-
console.log(`${
|
|
15483
|
+
console.log(`${pc13.bold(String(worlds.length))} world(s)
|
|
15613
15484
|
`);
|
|
15614
15485
|
for (const w of worlds) {
|
|
15615
|
-
const statusColor = w.status === "running" ?
|
|
15486
|
+
const statusColor = w.status === "running" ? pc13.green(w.status) : w.status === "error" ? pc13.red(w.status) : pc13.yellow(w.status);
|
|
15616
15487
|
const age = formatAge(w.createdAt);
|
|
15617
15488
|
const cost = `$${w.totalCostUsd.toFixed(2)}`;
|
|
15618
|
-
console.log(` ${
|
|
15489
|
+
console.log(` ${pc13.bold(w.name)} ${pc13.dim(`(${w.id})`)}`);
|
|
15619
15490
|
console.log(
|
|
15620
|
-
` ${statusColor} ${
|
|
15491
|
+
` ${statusColor} ${pc13.dim("|")} ${w.repos.join(", ")} ${pc13.dim("|")} ${cost} ${pc13.dim("|")} ${age}`
|
|
15621
15492
|
);
|
|
15622
15493
|
console.log();
|
|
15623
15494
|
}
|
|
@@ -15626,9 +15497,9 @@ function registerList(program2) {
|
|
|
15626
15497
|
|
|
15627
15498
|
// src/commands/status.ts
|
|
15628
15499
|
init_output();
|
|
15629
|
-
import * as
|
|
15500
|
+
import * as fs22 from "node:fs";
|
|
15630
15501
|
import * as os13 from "node:os";
|
|
15631
|
-
import * as
|
|
15502
|
+
import * as path25 from "node:path";
|
|
15632
15503
|
var CLI_VERSION2 = process.env["OLAM_CLI_VERSION"] ?? "0.0.0";
|
|
15633
15504
|
var HOST_CP_PORT2 = 19e3;
|
|
15634
15505
|
async function getMachineStatus(_probe, _loadCtx, _readToken) {
|
|
@@ -15658,14 +15529,14 @@ async function getMachineStatus(_probe, _loadCtx, _readToken) {
|
|
|
15658
15529
|
}
|
|
15659
15530
|
} catch {
|
|
15660
15531
|
}
|
|
15661
|
-
const manifestPath2 =
|
|
15532
|
+
const manifestPath2 = path25.join(os13.homedir(), ".olam", "cache", "manifest.json");
|
|
15662
15533
|
let updateAvailable = null;
|
|
15663
15534
|
let lastUpdateCheck = null;
|
|
15664
|
-
if (
|
|
15665
|
-
const mtime =
|
|
15535
|
+
if (fs22.existsSync(manifestPath2)) {
|
|
15536
|
+
const mtime = fs22.statSync(manifestPath2).mtime;
|
|
15666
15537
|
lastUpdateCheck = mtime.toISOString();
|
|
15667
15538
|
try {
|
|
15668
|
-
const manifest = JSON.parse(
|
|
15539
|
+
const manifest = JSON.parse(fs22.readFileSync(manifestPath2, "utf-8"));
|
|
15669
15540
|
const latest = manifest["version"];
|
|
15670
15541
|
updateAvailable = latest !== void 0 && latest !== CLI_VERSION2;
|
|
15671
15542
|
} catch {
|
|
@@ -15788,10 +15659,10 @@ function registerDestroy(program2) {
|
|
|
15788
15659
|
// src/commands/clean.ts
|
|
15789
15660
|
init_context();
|
|
15790
15661
|
init_output();
|
|
15791
|
-
import
|
|
15662
|
+
import fs23 from "node:fs";
|
|
15792
15663
|
import os14 from "node:os";
|
|
15793
|
-
import
|
|
15794
|
-
import { execFileSync as
|
|
15664
|
+
import path26 from "node:path";
|
|
15665
|
+
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
15795
15666
|
function registerClean(program2) {
|
|
15796
15667
|
program2.command("clean").description("Reap orphan world filesystem state under ~/.olam/worlds/").option("--apply", "Actually delete the orphans (default is dry-run)", false).option(
|
|
15797
15668
|
"--include-dirty",
|
|
@@ -15814,8 +15685,8 @@ async function runClean(opts) {
|
|
|
15814
15685
|
printError(error?.message ?? "Olam is not configured. Run `olam init` first.");
|
|
15815
15686
|
return 1;
|
|
15816
15687
|
}
|
|
15817
|
-
const worldsDir =
|
|
15818
|
-
if (!
|
|
15688
|
+
const worldsDir = path26.join(os14.homedir(), ".olam", "worlds");
|
|
15689
|
+
if (!fs23.existsSync(worldsDir)) {
|
|
15819
15690
|
if (opts.json) {
|
|
15820
15691
|
process.stdout.write(`${JSON.stringify({ worldsDir, entries: [] })}
|
|
15821
15692
|
`);
|
|
@@ -15830,8 +15701,8 @@ async function runClean(opts) {
|
|
|
15830
15701
|
}
|
|
15831
15702
|
const worktreeMap = collectWorktrees(worldsDir);
|
|
15832
15703
|
const entries = [];
|
|
15833
|
-
for (const id of
|
|
15834
|
-
const fullPath =
|
|
15704
|
+
for (const id of fs23.readdirSync(worldsDir).sort()) {
|
|
15705
|
+
const fullPath = path26.join(worldsDir, id);
|
|
15835
15706
|
const stat = safeStat(fullPath);
|
|
15836
15707
|
if (!stat || !stat.isDirectory()) continue;
|
|
15837
15708
|
entries.push(classifyWorld({ id, fullPath, liveIds, worktreeMap }));
|
|
@@ -15897,7 +15768,7 @@ function classifyWorld(args) {
|
|
|
15897
15768
|
if (liveIds.has(id)) {
|
|
15898
15769
|
return { id, path: fullPath, bytes, category: "active", note: "in registry" };
|
|
15899
15770
|
}
|
|
15900
|
-
const worktreeChild =
|
|
15771
|
+
const worktreeChild = path26.join(fullPath, "olam");
|
|
15901
15772
|
const worktreeInfo = worktreeMap.get(worktreeChild);
|
|
15902
15773
|
if (worktreeInfo) {
|
|
15903
15774
|
if (worktreeInfo.dirty > 0 || worktreeInfo.unpushed > 0) {
|
|
@@ -15934,7 +15805,7 @@ function reapEntry(entry) {
|
|
|
15934
15805
|
try {
|
|
15935
15806
|
const gitDir = resolveGitDirForWorktree(entry.worktreePath);
|
|
15936
15807
|
if (gitDir) {
|
|
15937
|
-
|
|
15808
|
+
execFileSync5("git", ["worktree", "remove", "--force", entry.worktreePath], {
|
|
15938
15809
|
cwd: gitDir,
|
|
15939
15810
|
stdio: "pipe"
|
|
15940
15811
|
});
|
|
@@ -15943,20 +15814,20 @@ function reapEntry(entry) {
|
|
|
15943
15814
|
}
|
|
15944
15815
|
}
|
|
15945
15816
|
try {
|
|
15946
|
-
|
|
15817
|
+
fs23.rmSync(entry.path, { recursive: true, force: true });
|
|
15947
15818
|
} catch (err) {
|
|
15948
15819
|
process.stderr.write(` ! rm ${entry.path}: ${err instanceof Error ? err.message : String(err)}
|
|
15949
15820
|
`);
|
|
15950
15821
|
return false;
|
|
15951
15822
|
}
|
|
15952
|
-
return !
|
|
15823
|
+
return !fs23.existsSync(entry.path);
|
|
15953
15824
|
}
|
|
15954
15825
|
function collectWorktrees(worldsDir) {
|
|
15955
15826
|
const out = /* @__PURE__ */ new Map();
|
|
15956
|
-
for (const id of
|
|
15957
|
-
const child =
|
|
15958
|
-
const gitMarker =
|
|
15959
|
-
if (!
|
|
15827
|
+
for (const id of fs23.readdirSync(worldsDir)) {
|
|
15828
|
+
const child = path26.join(worldsDir, id, "olam");
|
|
15829
|
+
const gitMarker = path26.join(child, ".git");
|
|
15830
|
+
if (!fs23.existsSync(gitMarker)) continue;
|
|
15960
15831
|
const gitDir = resolveGitDirForWorktree(child);
|
|
15961
15832
|
if (!gitDir) continue;
|
|
15962
15833
|
const branch = readBranch(child);
|
|
@@ -15967,21 +15838,21 @@ function collectWorktrees(worldsDir) {
|
|
|
15967
15838
|
return out;
|
|
15968
15839
|
}
|
|
15969
15840
|
function resolveGitDirForWorktree(worktreePath) {
|
|
15970
|
-
const gitMarker =
|
|
15841
|
+
const gitMarker = path26.join(worktreePath, ".git");
|
|
15971
15842
|
try {
|
|
15972
|
-
const top =
|
|
15843
|
+
const top = execFileSync5("git", ["rev-parse", "--show-toplevel"], {
|
|
15973
15844
|
cwd: worktreePath,
|
|
15974
15845
|
encoding: "utf-8",
|
|
15975
15846
|
stdio: "pipe"
|
|
15976
15847
|
}).trim();
|
|
15977
15848
|
if (!top) return null;
|
|
15978
|
-
const common =
|
|
15849
|
+
const common = execFileSync5("git", ["rev-parse", "--git-common-dir"], {
|
|
15979
15850
|
cwd: worktreePath,
|
|
15980
15851
|
encoding: "utf-8",
|
|
15981
15852
|
stdio: "pipe"
|
|
15982
15853
|
}).trim();
|
|
15983
15854
|
if (!common) return top;
|
|
15984
|
-
return
|
|
15855
|
+
return path26.dirname(path26.resolve(worktreePath, common));
|
|
15985
15856
|
} catch {
|
|
15986
15857
|
return null;
|
|
15987
15858
|
}
|
|
@@ -15989,7 +15860,7 @@ function resolveGitDirForWorktree(worktreePath) {
|
|
|
15989
15860
|
}
|
|
15990
15861
|
function readBranch(worktreePath) {
|
|
15991
15862
|
try {
|
|
15992
|
-
return
|
|
15863
|
+
return execFileSync5("git", ["branch", "--show-current"], {
|
|
15993
15864
|
cwd: worktreePath,
|
|
15994
15865
|
encoding: "utf-8",
|
|
15995
15866
|
stdio: "pipe"
|
|
@@ -16000,7 +15871,7 @@ function readBranch(worktreePath) {
|
|
|
16000
15871
|
}
|
|
16001
15872
|
function countDirty(worktreePath) {
|
|
16002
15873
|
try {
|
|
16003
|
-
const out =
|
|
15874
|
+
const out = execFileSync5("git", ["status", "--porcelain"], {
|
|
16004
15875
|
cwd: worktreePath,
|
|
16005
15876
|
encoding: "utf-8",
|
|
16006
15877
|
stdio: "pipe"
|
|
@@ -16012,7 +15883,7 @@ function countDirty(worktreePath) {
|
|
|
16012
15883
|
}
|
|
16013
15884
|
function countUnpushed(worktreePath) {
|
|
16014
15885
|
try {
|
|
16015
|
-
const out =
|
|
15886
|
+
const out = execFileSync5("git", ["log", "@{u}..HEAD", "--oneline"], {
|
|
16016
15887
|
cwd: worktreePath,
|
|
16017
15888
|
encoding: "utf-8",
|
|
16018
15889
|
stdio: "pipe"
|
|
@@ -16024,7 +15895,7 @@ function countUnpushed(worktreePath) {
|
|
|
16024
15895
|
}
|
|
16025
15896
|
function safeStat(p) {
|
|
16026
15897
|
try {
|
|
16027
|
-
return
|
|
15898
|
+
return fs23.statSync(p);
|
|
16028
15899
|
} catch {
|
|
16029
15900
|
return null;
|
|
16030
15901
|
}
|
|
@@ -16036,7 +15907,7 @@ function computeBytes(p) {
|
|
|
16036
15907
|
const cur = stack.pop();
|
|
16037
15908
|
let st;
|
|
16038
15909
|
try {
|
|
16039
|
-
st =
|
|
15910
|
+
st = fs23.lstatSync(cur);
|
|
16040
15911
|
} catch {
|
|
16041
15912
|
continue;
|
|
16042
15913
|
}
|
|
@@ -16044,11 +15915,11 @@ function computeBytes(p) {
|
|
|
16044
15915
|
if (st.isDirectory()) {
|
|
16045
15916
|
let entries;
|
|
16046
15917
|
try {
|
|
16047
|
-
entries =
|
|
15918
|
+
entries = fs23.readdirSync(cur);
|
|
16048
15919
|
} catch {
|
|
16049
15920
|
continue;
|
|
16050
15921
|
}
|
|
16051
|
-
for (const name of entries) stack.push(
|
|
15922
|
+
for (const name of entries) stack.push(path26.join(cur, name));
|
|
16052
15923
|
} else {
|
|
16053
15924
|
total += st.size;
|
|
16054
15925
|
}
|
|
@@ -16101,7 +15972,7 @@ async function confirmInteractive() {
|
|
|
16101
15972
|
init_context();
|
|
16102
15973
|
init_output();
|
|
16103
15974
|
import { execSync as execSync7 } from "node:child_process";
|
|
16104
|
-
import
|
|
15975
|
+
import pc14 from "picocolors";
|
|
16105
15976
|
var SAFE_IDENT3 = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
16106
15977
|
function buildStartClaudeCommands(containerName, sessionName, task) {
|
|
16107
15978
|
if (!SAFE_IDENT3.test(containerName)) {
|
|
@@ -16208,7 +16079,7 @@ function registerEnter(program2) {
|
|
|
16208
16079
|
}
|
|
16209
16080
|
console.log("Run these commands in order to enter the world:\n");
|
|
16210
16081
|
for (const step of steps) {
|
|
16211
|
-
console.log(` ${
|
|
16082
|
+
console.log(` ${pc14.dim(`# ${step.description}`)}`);
|
|
16212
16083
|
if (step.stdin !== void 0) {
|
|
16213
16084
|
const escaped = step.stdin.replace(/'/g, "'\\''");
|
|
16214
16085
|
console.log(` printf '%s' '${escaped}' | ${step.command}`);
|
|
@@ -16242,11 +16113,11 @@ function registerEnter(program2) {
|
|
|
16242
16113
|
return;
|
|
16243
16114
|
}
|
|
16244
16115
|
console.log("Run this command to enter the world:\n");
|
|
16245
|
-
console.log(` ${
|
|
16116
|
+
console.log(` ${pc14.bold(result.command)}`);
|
|
16246
16117
|
const containerName = `olam-${worldId}-devbox`;
|
|
16247
16118
|
console.log(
|
|
16248
16119
|
`
|
|
16249
|
-
${
|
|
16120
|
+
${pc14.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t olam-dispatch -r`)}`
|
|
16250
16121
|
);
|
|
16251
16122
|
});
|
|
16252
16123
|
}
|
|
@@ -16256,7 +16127,7 @@ init_context();
|
|
|
16256
16127
|
init_output();
|
|
16257
16128
|
init_exit_codes();
|
|
16258
16129
|
init_world_paths();
|
|
16259
|
-
import * as
|
|
16130
|
+
import * as fs24 from "node:fs";
|
|
16260
16131
|
import "node:path";
|
|
16261
16132
|
import ora6 from "ora";
|
|
16262
16133
|
function registerCrystallize(program2, options = {}) {
|
|
@@ -16288,7 +16159,7 @@ function registerCrystallize(program2, options = {}) {
|
|
|
16288
16159
|
return;
|
|
16289
16160
|
}
|
|
16290
16161
|
const thoughtDbPath = getWorldDbPath(world.workspacePath);
|
|
16291
|
-
if (!
|
|
16162
|
+
if (!fs24.existsSync(thoughtDbPath)) {
|
|
16292
16163
|
printError(`No thoughts captured yet for "${worldId}". Run a dispatch first.`);
|
|
16293
16164
|
process.exitCode = EXIT_GENERIC_ERROR;
|
|
16294
16165
|
return;
|
|
@@ -16358,7 +16229,7 @@ function registerCrystallize(program2, options = {}) {
|
|
|
16358
16229
|
|
|
16359
16230
|
// src/commands/pr.ts
|
|
16360
16231
|
init_registry();
|
|
16361
|
-
import
|
|
16232
|
+
import pc15 from "picocolors";
|
|
16362
16233
|
|
|
16363
16234
|
// ../core/dist/pr-gate/client.js
|
|
16364
16235
|
var HOST_CONTROL_PLANE_BASE2 = 19080;
|
|
@@ -16439,26 +16310,26 @@ async function findGate(id) {
|
|
|
16439
16310
|
return null;
|
|
16440
16311
|
}
|
|
16441
16312
|
function formatStateBadge(state) {
|
|
16442
|
-
if (state === "approve") return
|
|
16443
|
-
if (state === "block") return
|
|
16444
|
-
if (state === "denied") return
|
|
16445
|
-
return
|
|
16313
|
+
if (state === "approve") return pc15.green("approve");
|
|
16314
|
+
if (state === "block") return pc15.red("block");
|
|
16315
|
+
if (state === "denied") return pc15.gray("denied");
|
|
16316
|
+
return pc15.yellow("pending");
|
|
16446
16317
|
}
|
|
16447
16318
|
function registerPr(program2) {
|
|
16448
16319
|
const pr = program2.command("pr").description("Review and decide PR-gate requests from running worlds");
|
|
16449
16320
|
pr.command("list").description("List all PR-gate requests across every running world").action(async () => {
|
|
16450
16321
|
const all = await fanoutList();
|
|
16451
16322
|
if (all.length === 0) {
|
|
16452
|
-
console.log(
|
|
16323
|
+
console.log(pc15.dim("No gates open."));
|
|
16453
16324
|
return;
|
|
16454
16325
|
}
|
|
16455
16326
|
printHeader(`${all.length} gate(s)`);
|
|
16456
16327
|
for (const { world, gate } of all) {
|
|
16457
16328
|
const badge = formatStateBadge(gate.state);
|
|
16458
16329
|
console.log(
|
|
16459
|
-
` ${
|
|
16330
|
+
` ${pc15.bold(gate.id.slice(0, 8))} ${badge.padEnd(20)} ${pc15.dim(world.name)} ${pc15.dim(gate.branch)}`
|
|
16460
16331
|
);
|
|
16461
|
-
console.log(` ${
|
|
16332
|
+
console.log(` ${pc15.dim(gate.command.slice(0, 100))}`);
|
|
16462
16333
|
}
|
|
16463
16334
|
});
|
|
16464
16335
|
pr.command("show").description("Show full gate detail (diff, command, commits)").argument("<id>", "Gate id (prefix match ok)").action(async (id) => {
|
|
@@ -16481,9 +16352,9 @@ function registerPr(program2) {
|
|
|
16481
16352
|
if (gate.reason) printInfo("Reason", gate.reason);
|
|
16482
16353
|
}
|
|
16483
16354
|
printHeader("Commits");
|
|
16484
|
-
console.log(gate.commitLog ||
|
|
16355
|
+
console.log(gate.commitLog || pc15.dim(" (empty)"));
|
|
16485
16356
|
printHeader("Diff stat");
|
|
16486
|
-
console.log(gate.diffStat ||
|
|
16357
|
+
console.log(gate.diffStat || pc15.dim(" (empty)"));
|
|
16487
16358
|
});
|
|
16488
16359
|
function decideCommand(verb, decision) {
|
|
16489
16360
|
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) => {
|
|
@@ -16608,7 +16479,7 @@ function registerLanes(program2) {
|
|
|
16608
16479
|
// src/commands/policy-check.ts
|
|
16609
16480
|
init_loader2();
|
|
16610
16481
|
import { execSync as execSync8 } from "node:child_process";
|
|
16611
|
-
import
|
|
16482
|
+
import pc16 from "picocolors";
|
|
16612
16483
|
|
|
16613
16484
|
// ../../node_modules/balanced-match/dist/esm/index.js
|
|
16614
16485
|
var balanced = (a, b, str) => {
|
|
@@ -17662,11 +17533,11 @@ var qmarksTestNoExtDot = ([$0]) => {
|
|
|
17662
17533
|
return (f) => f.length === len && f !== "." && f !== "..";
|
|
17663
17534
|
};
|
|
17664
17535
|
var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
|
|
17665
|
-
var
|
|
17536
|
+
var path28 = {
|
|
17666
17537
|
win32: { sep: "\\" },
|
|
17667
17538
|
posix: { sep: "/" }
|
|
17668
17539
|
};
|
|
17669
|
-
var sep = defaultPlatform === "win32" ?
|
|
17540
|
+
var sep = defaultPlatform === "win32" ? path28.win32.sep : path28.posix.sep;
|
|
17670
17541
|
minimatch.sep = sep;
|
|
17671
17542
|
var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
|
|
17672
17543
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
@@ -18468,7 +18339,7 @@ function registerPolicyCheck(program2) {
|
|
|
18468
18339
|
const workspaceRoot = opts.workspace ?? process.cwd();
|
|
18469
18340
|
const policies = loadPolicies(workspaceRoot);
|
|
18470
18341
|
if (policies.length === 0) {
|
|
18471
|
-
console.log(
|
|
18342
|
+
console.log(pc16.dim("policy-check: no policies found in .olam/policies/ \u2014 nothing to enforce"));
|
|
18472
18343
|
return;
|
|
18473
18344
|
}
|
|
18474
18345
|
const diff = getDiff(opts.base, workspaceRoot);
|
|
@@ -18477,11 +18348,11 @@ function registerPolicyCheck(program2) {
|
|
|
18477
18348
|
for (const result of results) {
|
|
18478
18349
|
if (result.passed) continue;
|
|
18479
18350
|
if (result.severity === "error") {
|
|
18480
|
-
console.error(`${
|
|
18351
|
+
console.error(`${pc16.red("policy error")} [${result.policyId}]`);
|
|
18481
18352
|
console.error(result.message);
|
|
18482
18353
|
hasErrorFailure = true;
|
|
18483
18354
|
} else {
|
|
18484
|
-
console.warn(`${
|
|
18355
|
+
console.warn(`${pc16.yellow("policy warn")} [${result.policyId}]`);
|
|
18485
18356
|
console.warn(result.message);
|
|
18486
18357
|
}
|
|
18487
18358
|
}
|
|
@@ -18494,23 +18365,23 @@ function registerPolicyCheck(program2) {
|
|
|
18494
18365
|
// src/commands/upgrade.ts
|
|
18495
18366
|
init_output();
|
|
18496
18367
|
init_host_cp();
|
|
18497
|
-
import * as
|
|
18498
|
-
import * as
|
|
18499
|
-
import { spawnSync as
|
|
18368
|
+
import * as fs27 from "node:fs";
|
|
18369
|
+
import * as path31 from "node:path";
|
|
18370
|
+
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
18500
18371
|
import ora7 from "ora";
|
|
18501
|
-
import
|
|
18372
|
+
import pc17 from "picocolors";
|
|
18502
18373
|
|
|
18503
18374
|
// src/commands/upgrade-lock.ts
|
|
18504
|
-
import * as
|
|
18375
|
+
import * as fs25 from "node:fs";
|
|
18505
18376
|
import * as os15 from "node:os";
|
|
18506
|
-
import * as
|
|
18507
|
-
import { spawnSync as
|
|
18508
|
-
var LOCK_FILE_PATH =
|
|
18377
|
+
import * as path29 from "node:path";
|
|
18378
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
18379
|
+
var LOCK_FILE_PATH = path29.join(os15.homedir(), ".olam", ".upgrade.lock");
|
|
18509
18380
|
var STALE_LOCK_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
18510
18381
|
function readLockFile(lockPath) {
|
|
18511
18382
|
try {
|
|
18512
|
-
if (!
|
|
18513
|
-
const raw =
|
|
18383
|
+
if (!fs25.existsSync(lockPath)) return null;
|
|
18384
|
+
const raw = fs25.readFileSync(lockPath, "utf-8").trim();
|
|
18514
18385
|
if (raw.length === 0) return null;
|
|
18515
18386
|
const parsed = JSON.parse(raw);
|
|
18516
18387
|
if (typeof parsed.pid !== "number" || typeof parsed.startTs !== "number") return null;
|
|
@@ -18529,7 +18400,7 @@ function isPidAlive(pid) {
|
|
|
18529
18400
|
}
|
|
18530
18401
|
var PS_UNAVAILABLE = "__ps_unavailable__";
|
|
18531
18402
|
function getPidCommand(pid) {
|
|
18532
|
-
const result =
|
|
18403
|
+
const result = spawnSync10("ps", ["-p", String(pid), "-o", "comm="], {
|
|
18533
18404
|
encoding: "utf-8",
|
|
18534
18405
|
stdio: ["ignore", "pipe", "ignore"]
|
|
18535
18406
|
});
|
|
@@ -18555,16 +18426,16 @@ function isStaleLock(content, nowMs = Date.now()) {
|
|
|
18555
18426
|
return false;
|
|
18556
18427
|
}
|
|
18557
18428
|
function acquireLock(lockPath = LOCK_FILE_PATH, nowMs = Date.now()) {
|
|
18558
|
-
const dir =
|
|
18559
|
-
|
|
18429
|
+
const dir = path29.dirname(lockPath);
|
|
18430
|
+
fs25.mkdirSync(dir, { recursive: true });
|
|
18560
18431
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
18561
18432
|
try {
|
|
18562
|
-
const fd =
|
|
18433
|
+
const fd = fs25.openSync(lockPath, "wx", 420);
|
|
18563
18434
|
try {
|
|
18564
18435
|
const content = { pid: process.pid, startTs: nowMs };
|
|
18565
|
-
|
|
18436
|
+
fs25.writeSync(fd, JSON.stringify(content));
|
|
18566
18437
|
} finally {
|
|
18567
|
-
|
|
18438
|
+
fs25.closeSync(fd);
|
|
18568
18439
|
}
|
|
18569
18440
|
return { acquired: true, lockPath };
|
|
18570
18441
|
} catch (err) {
|
|
@@ -18573,7 +18444,7 @@ function acquireLock(lockPath = LOCK_FILE_PATH, nowMs = Date.now()) {
|
|
|
18573
18444
|
const existing2 = readLockFile(lockPath);
|
|
18574
18445
|
if (isStaleLock(existing2, nowMs)) {
|
|
18575
18446
|
try {
|
|
18576
|
-
|
|
18447
|
+
fs25.unlinkSync(lockPath);
|
|
18577
18448
|
} catch (unlinkErr) {
|
|
18578
18449
|
const ucode = unlinkErr.code;
|
|
18579
18450
|
if (ucode !== "ENOENT") throw unlinkErr;
|
|
@@ -18598,7 +18469,7 @@ function acquireLock(lockPath = LOCK_FILE_PATH, nowMs = Date.now()) {
|
|
|
18598
18469
|
}
|
|
18599
18470
|
function releaseLock(lockPath = LOCK_FILE_PATH) {
|
|
18600
18471
|
try {
|
|
18601
|
-
|
|
18472
|
+
fs25.unlinkSync(lockPath);
|
|
18602
18473
|
} catch (err) {
|
|
18603
18474
|
const code = err.code;
|
|
18604
18475
|
if (code !== "ENOENT") throw err;
|
|
@@ -18616,19 +18487,19 @@ function formatRefusalMessage(result, lockPath = LOCK_FILE_PATH) {
|
|
|
18616
18487
|
}
|
|
18617
18488
|
|
|
18618
18489
|
// src/commands/upgrade-log.ts
|
|
18619
|
-
import * as
|
|
18490
|
+
import * as fs26 from "node:fs";
|
|
18620
18491
|
import * as os16 from "node:os";
|
|
18621
|
-
import * as
|
|
18492
|
+
import * as path30 from "node:path";
|
|
18622
18493
|
function getUpgradeLogPath() {
|
|
18623
18494
|
const home = process.env["HOME"] ?? os16.homedir();
|
|
18624
|
-
return
|
|
18495
|
+
return path30.join(home, ".olam", "upgrade.log");
|
|
18625
18496
|
}
|
|
18626
18497
|
var UPGRADE_LOG_PATH = getUpgradeLogPath();
|
|
18627
18498
|
function appendUpgradeLog(row, logPath = getUpgradeLogPath()) {
|
|
18628
18499
|
try {
|
|
18629
|
-
|
|
18500
|
+
fs26.mkdirSync(path30.dirname(logPath), { recursive: true });
|
|
18630
18501
|
const line = JSON.stringify(row) + "\n";
|
|
18631
|
-
|
|
18502
|
+
fs26.appendFileSync(logPath, line, { mode: 420 });
|
|
18632
18503
|
} catch (err) {
|
|
18633
18504
|
process.stderr.write(
|
|
18634
18505
|
`[upgrade-log] failed to append: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -18637,10 +18508,10 @@ function appendUpgradeLog(row, logPath = getUpgradeLogPath()) {
|
|
|
18637
18508
|
}
|
|
18638
18509
|
}
|
|
18639
18510
|
function readUpgradeLog(limit = 10, logPath = getUpgradeLogPath()) {
|
|
18640
|
-
if (!
|
|
18511
|
+
if (!fs26.existsSync(logPath)) return [];
|
|
18641
18512
|
let raw;
|
|
18642
18513
|
try {
|
|
18643
|
-
raw =
|
|
18514
|
+
raw = fs26.readFileSync(logPath, "utf-8");
|
|
18644
18515
|
} catch (err) {
|
|
18645
18516
|
process.stderr.write(
|
|
18646
18517
|
`[upgrade-log] failed to read: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -18733,12 +18604,12 @@ init_protocol_version();
|
|
|
18733
18604
|
init_install_root();
|
|
18734
18605
|
var AUTH_HEALTH_URL2 = "http://127.0.0.1:9999/health";
|
|
18735
18606
|
function isNodeModulesInSync(cwd) {
|
|
18736
|
-
const lockPath =
|
|
18737
|
-
const markerPath =
|
|
18738
|
-
if (!
|
|
18607
|
+
const lockPath = path31.join(cwd, "package-lock.json");
|
|
18608
|
+
const markerPath = path31.join(cwd, "node_modules", ".package-lock.json");
|
|
18609
|
+
if (!fs27.existsSync(lockPath) || !fs27.existsSync(markerPath)) return false;
|
|
18739
18610
|
try {
|
|
18740
|
-
const lockStat =
|
|
18741
|
-
const markerStat =
|
|
18611
|
+
const lockStat = fs27.statSync(lockPath);
|
|
18612
|
+
const markerStat = fs27.statSync(markerPath);
|
|
18742
18613
|
return markerStat.mtimeMs >= lockStat.mtimeMs;
|
|
18743
18614
|
} catch {
|
|
18744
18615
|
return false;
|
|
@@ -18754,8 +18625,8 @@ function shouldSkipInstall(opts, cwd) {
|
|
|
18754
18625
|
return { skip: false };
|
|
18755
18626
|
}
|
|
18756
18627
|
function validateRepoRoot(cwd) {
|
|
18757
|
-
const marker =
|
|
18758
|
-
if (!
|
|
18628
|
+
const marker = path31.join(cwd, "packages/host-cp/compose.yaml");
|
|
18629
|
+
if (!fs27.existsSync(marker)) {
|
|
18759
18630
|
return {
|
|
18760
18631
|
ok: false,
|
|
18761
18632
|
error: `Not an olam repo root (expected ${marker}).
|
|
@@ -18787,8 +18658,8 @@ function extractBundleHash(indexHtml) {
|
|
|
18787
18658
|
}
|
|
18788
18659
|
function runStep2(label, cmd, args, opts = {}) {
|
|
18789
18660
|
const start = Date.now();
|
|
18790
|
-
process.stdout.write(` ${
|
|
18791
|
-
const result =
|
|
18661
|
+
process.stdout.write(` ${pc17.dim(label.padEnd(34))}`);
|
|
18662
|
+
const result = spawnSync11(cmd, [...args], {
|
|
18792
18663
|
encoding: "utf-8",
|
|
18793
18664
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18794
18665
|
cwd: opts.cwd ?? process.cwd(),
|
|
@@ -18797,7 +18668,7 @@ function runStep2(label, cmd, args, opts = {}) {
|
|
|
18797
18668
|
const durationMs = Date.now() - start;
|
|
18798
18669
|
const ok = result.status === 0 && result.error === void 0;
|
|
18799
18670
|
const dur = `${(durationMs / 1e3).toFixed(1)}s`;
|
|
18800
|
-
process.stdout.write(`${ok ?
|
|
18671
|
+
process.stdout.write(`${ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${dur}
|
|
18801
18672
|
`);
|
|
18802
18673
|
return {
|
|
18803
18674
|
ok,
|
|
@@ -18807,7 +18678,7 @@ function runStep2(label, cmd, args, opts = {}) {
|
|
|
18807
18678
|
};
|
|
18808
18679
|
}
|
|
18809
18680
|
function isGitDirty(cwd) {
|
|
18810
|
-
const result =
|
|
18681
|
+
const result = spawnSync11("git", ["status", "--porcelain"], {
|
|
18811
18682
|
encoding: "utf-8",
|
|
18812
18683
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18813
18684
|
cwd
|
|
@@ -18815,7 +18686,7 @@ function isGitDirty(cwd) {
|
|
|
18815
18686
|
return (result.stdout ?? "").trim().length > 0;
|
|
18816
18687
|
}
|
|
18817
18688
|
function hasGitUpstream(cwd) {
|
|
18818
|
-
const result =
|
|
18689
|
+
const result = spawnSync11("git", ["rev-parse", "--abbrev-ref", "@{u}"], {
|
|
18819
18690
|
encoding: "utf-8",
|
|
18820
18691
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18821
18692
|
cwd
|
|
@@ -18823,7 +18694,7 @@ function hasGitUpstream(cwd) {
|
|
|
18823
18694
|
return result.status === 0;
|
|
18824
18695
|
}
|
|
18825
18696
|
function captureHeadSha(cwd) {
|
|
18826
|
-
const result =
|
|
18697
|
+
const result = spawnSync11("git", ["rev-parse", "HEAD"], {
|
|
18827
18698
|
encoding: "utf-8",
|
|
18828
18699
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18829
18700
|
cwd
|
|
@@ -18838,7 +18709,7 @@ function abbreviateSha(sha) {
|
|
|
18838
18709
|
}
|
|
18839
18710
|
function imageExists(tag) {
|
|
18840
18711
|
try {
|
|
18841
|
-
const result =
|
|
18712
|
+
const result = spawnSync11("docker", ["image", "inspect", "--format", "{{.Id}}", tag], {
|
|
18842
18713
|
encoding: "utf-8",
|
|
18843
18714
|
stdio: ["ignore", "pipe", "ignore"]
|
|
18844
18715
|
});
|
|
@@ -18854,7 +18725,7 @@ function checkRollbackSetExists(plan) {
|
|
|
18854
18725
|
}
|
|
18855
18726
|
var SMOKE_DOCKER_TIMEOUT_MS = 3e4;
|
|
18856
18727
|
function smokeImage(image, targetSha) {
|
|
18857
|
-
const createResult =
|
|
18728
|
+
const createResult = spawnSync11("docker", ["create", "--name", `olam-smoke-${Date.now()}`, image], {
|
|
18858
18729
|
encoding: "utf-8",
|
|
18859
18730
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18860
18731
|
timeout: SMOKE_DOCKER_TIMEOUT_MS
|
|
@@ -18868,7 +18739,7 @@ function smokeImage(image, targetSha) {
|
|
|
18868
18739
|
};
|
|
18869
18740
|
}
|
|
18870
18741
|
const containerId = (createResult.stdout ?? "").trim();
|
|
18871
|
-
const inspectResult =
|
|
18742
|
+
const inspectResult = spawnSync11(
|
|
18872
18743
|
"docker",
|
|
18873
18744
|
["inspect", "--format", '{{index .Config.Labels "olam.build.sha"}}', image],
|
|
18874
18745
|
{
|
|
@@ -18878,7 +18749,7 @@ function smokeImage(image, targetSha) {
|
|
|
18878
18749
|
}
|
|
18879
18750
|
);
|
|
18880
18751
|
if (containerId.length > 0) {
|
|
18881
|
-
|
|
18752
|
+
spawnSync11("docker", ["rm", "-f", containerId], {
|
|
18882
18753
|
encoding: "utf-8",
|
|
18883
18754
|
stdio: ["ignore", "ignore", "ignore"],
|
|
18884
18755
|
timeout: SMOKE_DOCKER_TIMEOUT_MS
|
|
@@ -18918,7 +18789,7 @@ var PRODUCTION_SWAP_PLAN = [
|
|
|
18918
18789
|
];
|
|
18919
18790
|
function dockerTag(source, dest) {
|
|
18920
18791
|
try {
|
|
18921
|
-
const result =
|
|
18792
|
+
const result = spawnSync11("docker", ["tag", source, dest], {
|
|
18922
18793
|
encoding: "utf-8",
|
|
18923
18794
|
stdio: ["ignore", "ignore", "pipe"]
|
|
18924
18795
|
});
|
|
@@ -19082,11 +18953,11 @@ async function waitForAuthHealthLocal(timeoutMs = AUTH_HEALTH_TIMEOUT_MS) {
|
|
|
19082
18953
|
async function recreateAuthService() {
|
|
19083
18954
|
const start = Date.now();
|
|
19084
18955
|
try {
|
|
19085
|
-
|
|
18956
|
+
spawnSync11("docker", ["stop", "olam-auth"], {
|
|
19086
18957
|
encoding: "utf-8",
|
|
19087
18958
|
stdio: ["ignore", "ignore", "ignore"]
|
|
19088
18959
|
});
|
|
19089
|
-
|
|
18960
|
+
spawnSync11("docker", ["rm", "olam-auth"], {
|
|
19090
18961
|
encoding: "utf-8",
|
|
19091
18962
|
stdio: ["ignore", "ignore", "ignore"]
|
|
19092
18963
|
});
|
|
@@ -19111,9 +18982,9 @@ async function recreateAuthService() {
|
|
|
19111
18982
|
}
|
|
19112
18983
|
}
|
|
19113
18984
|
function readBundleHash(cwd) {
|
|
19114
|
-
const indexPath =
|
|
19115
|
-
if (!
|
|
19116
|
-
return extractBundleHash(
|
|
18985
|
+
const indexPath = path31.join(cwd, "packages/control-plane/public/index.html");
|
|
18986
|
+
if (!fs27.existsSync(indexPath)) return null;
|
|
18987
|
+
return extractBundleHash(fs27.readFileSync(indexPath, "utf-8"));
|
|
19117
18988
|
}
|
|
19118
18989
|
async function runUpgradePullByDigest(deps = {}) {
|
|
19119
18990
|
const docker2 = deps.docker ?? realDocker;
|
|
@@ -19125,19 +18996,27 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
19125
18996
|
if (info.exitCode !== 0) {
|
|
19126
18997
|
infoSpinner.fail("docker daemon not reachable");
|
|
19127
18998
|
process.stderr.write(
|
|
19128
|
-
`${
|
|
18999
|
+
`${pc17.red("error")} docker info exited with ${info.exitCode}.
|
|
19129
19000
|
Ensure Docker Desktop / Colima / Rancher is running, then retry.
|
|
19130
19001
|
`
|
|
19131
19002
|
);
|
|
19132
19003
|
return { exitCode: EXIT_GENERIC_ERROR, summary: "docker daemon not reachable" };
|
|
19133
19004
|
}
|
|
19134
19005
|
infoSpinner.succeed("docker daemon reachable");
|
|
19135
|
-
const
|
|
19006
|
+
const hasMcpAuthDigest = typeof digests["mcp-auth"] === "string" && digests["mcp-auth"].length > 0;
|
|
19007
|
+
const baseRefs = [
|
|
19136
19008
|
{ name: "host-cp", ref: `${registry}/olam-host-cp@${digests["host-cp"]}` },
|
|
19137
19009
|
{ name: "auth", ref: `${registry}/olam-auth@${digests.auth}` },
|
|
19138
19010
|
{ name: "devbox", ref: `${registry}/olam-devbox@${digests.devbox}` }
|
|
19139
19011
|
];
|
|
19140
|
-
|
|
19012
|
+
if (hasMcpAuthDigest) {
|
|
19013
|
+
baseRefs.push({
|
|
19014
|
+
name: "mcp-auth",
|
|
19015
|
+
ref: `${registry}/olam-mcp-auth@${digests["mcp-auth"]}`
|
|
19016
|
+
});
|
|
19017
|
+
}
|
|
19018
|
+
const imageRefs = baseRefs;
|
|
19019
|
+
const pullSpinner = ora7(`Pulling images (${imageRefs.length} parallel)`).start();
|
|
19141
19020
|
const pullStart = Date.now();
|
|
19142
19021
|
const pullResults = await Promise.all(
|
|
19143
19022
|
imageRefs.map(async ({ name, ref }) => ({
|
|
@@ -19152,7 +19031,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
19152
19031
|
pullSpinner.fail(`Pull failed for ${failed.map((r) => r.name).join(", ")}`);
|
|
19153
19032
|
for (const f of failed) {
|
|
19154
19033
|
process.stderr.write(
|
|
19155
|
-
` ${
|
|
19034
|
+
` ${pc17.red(f.name)} (${f.ref}):
|
|
19156
19035
|
exit=${f.result.exitCode}
|
|
19157
19036
|
stderr: ${f.result.stderr.split("\n")[0] ?? "(empty)"}
|
|
19158
19037
|
`
|
|
@@ -19166,14 +19045,14 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
19166
19045
|
summary: `pull failed: ${failed.map((r) => r.name).join(", ")}`
|
|
19167
19046
|
};
|
|
19168
19047
|
}
|
|
19169
|
-
pullSpinner.succeed(`Pulled
|
|
19048
|
+
pullSpinner.succeed(`Pulled ${imageRefs.length} images in ${pullElapsed}s`);
|
|
19170
19049
|
const handshakeSpinner = ora7("Verifying olam.protocol.versions handshake").start();
|
|
19171
19050
|
for (const { name, ref } of imageRefs) {
|
|
19172
19051
|
const inspect = await docker2.inspectLabel(ref, "olam.protocol.versions");
|
|
19173
19052
|
if (inspect.exitCode !== 0) {
|
|
19174
19053
|
handshakeSpinner.fail(`Could not inspect ${name}`);
|
|
19175
19054
|
process.stderr.write(
|
|
19176
|
-
`${
|
|
19055
|
+
`${pc17.red("error")} docker inspect ${ref} failed: ${inspect.stderr}
|
|
19177
19056
|
`
|
|
19178
19057
|
);
|
|
19179
19058
|
return { exitCode: EXIT_GENERIC_ERROR, summary: `inspect failed: ${name}` };
|
|
@@ -19185,7 +19064,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
19185
19064
|
const decision = checkProtocolOverlap(versions);
|
|
19186
19065
|
if (!decision.compatible) {
|
|
19187
19066
|
handshakeSpinner.fail(`Protocol mismatch on ${name}`);
|
|
19188
|
-
process.stderr.write(`${
|
|
19067
|
+
process.stderr.write(`${pc17.red("error")} ${decision.remedy}
|
|
19189
19068
|
`);
|
|
19190
19069
|
return {
|
|
19191
19070
|
exitCode: EXIT_PROTOCOL_MISMATCH,
|
|
@@ -19193,8 +19072,8 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
19193
19072
|
};
|
|
19194
19073
|
}
|
|
19195
19074
|
}
|
|
19196
|
-
handshakeSpinner.succeed(
|
|
19197
|
-
const
|
|
19075
|
+
handshakeSpinner.succeed(`Protocol handshake passed (all ${imageRefs.length} images)`);
|
|
19076
|
+
const tagPlanBase = [
|
|
19198
19077
|
{ from: imageRefs[0].ref, to: "olam-host-cp:latest", name: "host-cp (bare)" },
|
|
19199
19078
|
{ from: imageRefs[0].ref, to: `${registry}/olam-host-cp:latest`, name: "host-cp (registry)" },
|
|
19200
19079
|
{ from: imageRefs[1].ref, to: "olam-auth:local", name: "auth (bare)" },
|
|
@@ -19202,13 +19081,20 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
19202
19081
|
{ from: imageRefs[2].ref, to: "olam-devbox:latest", name: "devbox (bare)" },
|
|
19203
19082
|
{ from: imageRefs[2].ref, to: `${registry}/olam-devbox:latest`, name: "devbox (registry)" }
|
|
19204
19083
|
];
|
|
19084
|
+
if (hasMcpAuthDigest && imageRefs[3]) {
|
|
19085
|
+
tagPlanBase.push(
|
|
19086
|
+
{ from: imageRefs[3].ref, to: "olam-mcp-auth:local", name: "mcp-auth (bare)" },
|
|
19087
|
+
{ from: imageRefs[3].ref, to: `${registry}/olam-mcp-auth:latest`, name: "mcp-auth (registry)" }
|
|
19088
|
+
);
|
|
19089
|
+
}
|
|
19090
|
+
const tagPlan = tagPlanBase;
|
|
19205
19091
|
const tagSpinner = ora7("Tagging digests \u2192 canonical local refs").start();
|
|
19206
19092
|
const tagger = deps.tagImpl ?? dockerTag;
|
|
19207
19093
|
for (const t of tagPlan) {
|
|
19208
19094
|
const r = tagger(t.from, t.to);
|
|
19209
19095
|
if (!r.ok) {
|
|
19210
19096
|
tagSpinner.fail(`docker tag failed for ${t.name}`);
|
|
19211
|
-
process.stderr.write(`${
|
|
19097
|
+
process.stderr.write(`${pc17.red("error")} ${r.error ?? "docker tag failed"}
|
|
19212
19098
|
`);
|
|
19213
19099
|
return { exitCode: EXIT_GENERIC_ERROR, summary: `tag failed: ${t.name}` };
|
|
19214
19100
|
}
|
|
@@ -19226,7 +19112,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
19226
19112
|
if (!composeResult.ok) {
|
|
19227
19113
|
composeSpinner.fail("compose recreate failed");
|
|
19228
19114
|
process.stderr.write(
|
|
19229
|
-
`${
|
|
19115
|
+
`${pc17.red("error")} docker compose up --force-recreate host-cp failed:
|
|
19230
19116
|
${composeResult.stderr.split("\n").slice(0, 3).join("\n ")}
|
|
19231
19117
|
`
|
|
19232
19118
|
);
|
|
@@ -19239,25 +19125,68 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
19239
19125
|
if (!authResult.ok) {
|
|
19240
19126
|
authSpinner.fail("auth-service recreate failed");
|
|
19241
19127
|
process.stderr.write(
|
|
19242
|
-
`${
|
|
19128
|
+
`${pc17.red("error")} ${authResult.error ?? "unknown failure"}
|
|
19243
19129
|
`
|
|
19244
19130
|
);
|
|
19245
19131
|
return { exitCode: EXIT_GENERIC_ERROR, summary: "auth recreate failed" };
|
|
19246
19132
|
}
|
|
19247
19133
|
authSpinner.succeed("auth-service running on new image");
|
|
19134
|
+
if (hasMcpAuthDigest) {
|
|
19135
|
+
const mcpSpinner = ora7("recreate mcp-auth-service").start();
|
|
19136
|
+
const mcpRecreate = deps.recreateMcpAuth ?? defaultRecreateMcpAuthForUpgrade;
|
|
19137
|
+
const mcpResult = await mcpRecreate();
|
|
19138
|
+
if (!mcpResult.ok) {
|
|
19139
|
+
mcpSpinner.fail("mcp-auth-service recreate failed");
|
|
19140
|
+
process.stderr.write(
|
|
19141
|
+
`${pc17.red("error")} ${mcpResult.error ?? "unknown failure"}
|
|
19142
|
+
`
|
|
19143
|
+
);
|
|
19144
|
+
return { exitCode: EXIT_GENERIC_ERROR, summary: "mcp-auth recreate failed" };
|
|
19145
|
+
}
|
|
19146
|
+
mcpSpinner.succeed("mcp-auth-service running on new image");
|
|
19147
|
+
}
|
|
19248
19148
|
printSuccess("Upgrade complete (pull-by-digest)");
|
|
19249
19149
|
printInfo("host-cp", `running (${digests["host-cp"].slice(0, 19)}\u2026)`);
|
|
19250
19150
|
printInfo("auth", `running (${digests.auth.slice(0, 19)}\u2026)`);
|
|
19251
19151
|
printInfo("devbox", `pulled (${digests.devbox.slice(0, 19)}\u2026)`);
|
|
19152
|
+
if (hasMcpAuthDigest) {
|
|
19153
|
+
printInfo("mcp-auth", `running (${digests["mcp-auth"].slice(0, 19)}\u2026)`);
|
|
19154
|
+
}
|
|
19252
19155
|
return { exitCode: 0, summary: "stack upgraded" };
|
|
19253
19156
|
}
|
|
19157
|
+
async function defaultRecreateMcpAuthForUpgrade() {
|
|
19158
|
+
try {
|
|
19159
|
+
const { spawnSync: ss } = await import("node:child_process");
|
|
19160
|
+
ss("docker", ["stop", "olam-mcp-auth"], { stdio: "ignore" });
|
|
19161
|
+
ss("docker", ["rm", "-f", "olam-mcp-auth"], { stdio: "ignore" });
|
|
19162
|
+
const startResult = ss("docker", [
|
|
19163
|
+
"run",
|
|
19164
|
+
"-d",
|
|
19165
|
+
"--name",
|
|
19166
|
+
"olam-mcp-auth",
|
|
19167
|
+
"-p",
|
|
19168
|
+
"9998:9998",
|
|
19169
|
+
"-v",
|
|
19170
|
+
"olam-mcp-auth-data:/mcp-auth-data",
|
|
19171
|
+
"--restart",
|
|
19172
|
+
"unless-stopped",
|
|
19173
|
+
"olam-mcp-auth:local"
|
|
19174
|
+
], { stdio: "pipe" });
|
|
19175
|
+
if (startResult.status !== 0) {
|
|
19176
|
+
return { ok: false, error: `docker run failed: ${startResult.stderr?.toString() ?? "unknown"}` };
|
|
19177
|
+
}
|
|
19178
|
+
return { ok: true };
|
|
19179
|
+
} catch (err) {
|
|
19180
|
+
return { ok: false, error: err instanceof Error ? err.message : String(err) };
|
|
19181
|
+
}
|
|
19182
|
+
}
|
|
19254
19183
|
async function defaultRecreateAuthForUpgrade() {
|
|
19255
19184
|
try {
|
|
19256
|
-
|
|
19185
|
+
spawnSync11("docker", ["stop", "olam-auth"], {
|
|
19257
19186
|
encoding: "utf-8",
|
|
19258
19187
|
stdio: ["ignore", "ignore", "ignore"]
|
|
19259
19188
|
});
|
|
19260
|
-
|
|
19189
|
+
spawnSync11("docker", ["rm", "olam-auth"], {
|
|
19261
19190
|
encoding: "utf-8",
|
|
19262
19191
|
stdio: ["ignore", "ignore", "ignore"]
|
|
19263
19192
|
});
|
|
@@ -19402,11 +19331,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
|
|
|
19402
19331
|
process.once("SIGINT", releaseOnSignal);
|
|
19403
19332
|
process.once("SIGTERM", releaseOnSignal);
|
|
19404
19333
|
try {
|
|
19405
|
-
process.stdout.write(` ${
|
|
19334
|
+
process.stdout.write(` ${pc17.dim("rollback retag (3 ops)".padEnd(34))}`);
|
|
19406
19335
|
const swapStart = Date.now();
|
|
19407
19336
|
const swapResult = performRollbackSwap(PRODUCTION_SWAP_PLAN);
|
|
19408
19337
|
const swapDur = `${((Date.now() - swapStart) / 1e3).toFixed(1)}s`;
|
|
19409
|
-
process.stdout.write(`${swapResult.ok ?
|
|
19338
|
+
process.stdout.write(`${swapResult.ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${swapDur}
|
|
19410
19339
|
`);
|
|
19411
19340
|
if (!swapResult.ok) {
|
|
19412
19341
|
printError(`Rollback retag failed: ${swapResult.summary}`);
|
|
@@ -19416,11 +19345,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
|
|
|
19416
19345
|
printInfo("Rollback", swapResult.summary);
|
|
19417
19346
|
const composeFile = findComposeFile();
|
|
19418
19347
|
const authSecret = readAuthSecret2();
|
|
19419
|
-
process.stdout.write(` ${
|
|
19348
|
+
process.stdout.write(` ${pc17.dim("docker compose recreate host-cp".padEnd(34))}`);
|
|
19420
19349
|
const composeStart = Date.now();
|
|
19421
19350
|
const composeResult = runCompose(["up", "-d", "--force-recreate", "--no-deps", "host-cp"], composeFile, buildComposeEnv(authSecret));
|
|
19422
19351
|
const composeDur = `${((Date.now() - composeStart) / 1e3).toFixed(1)}s`;
|
|
19423
|
-
process.stdout.write(`${composeResult.ok ?
|
|
19352
|
+
process.stdout.write(`${composeResult.ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${composeDur}
|
|
19424
19353
|
`);
|
|
19425
19354
|
if (!composeResult.ok) {
|
|
19426
19355
|
printError(
|
|
@@ -19431,10 +19360,10 @@ Canonical tags are at :olam-rollback (good); container restart pending. Manually
|
|
|
19431
19360
|
process.exitCode = 1;
|
|
19432
19361
|
return;
|
|
19433
19362
|
}
|
|
19434
|
-
process.stdout.write(` ${
|
|
19363
|
+
process.stdout.write(` ${pc17.dim("recreate auth-service".padEnd(34))}`);
|
|
19435
19364
|
const authResult = await recreateAuthService();
|
|
19436
19365
|
const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
|
|
19437
|
-
process.stdout.write(`${authResult.ok ?
|
|
19366
|
+
process.stdout.write(`${authResult.ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${authDur}
|
|
19438
19367
|
`);
|
|
19439
19368
|
if (!authResult.ok) {
|
|
19440
19369
|
printError(`Auth-service recreate failed: ${authResult.error ?? "unknown"}`);
|
|
@@ -19555,7 +19484,7 @@ ${buildResult.stderr}`);
|
|
|
19555
19484
|
return;
|
|
19556
19485
|
}
|
|
19557
19486
|
const authSecret = readAuthSecret2();
|
|
19558
|
-
const spaDir =
|
|
19487
|
+
const spaDir = path31.join(cwd, "packages/control-plane/app");
|
|
19559
19488
|
const spaResult = runStep2(
|
|
19560
19489
|
"vite build (SPA)",
|
|
19561
19490
|
"npx",
|
|
@@ -19600,10 +19529,10 @@ ${spaResult.stderr}`);
|
|
|
19600
19529
|
throw err;
|
|
19601
19530
|
}
|
|
19602
19531
|
if (step.tee) {
|
|
19603
|
-
process.stdout.write(` ${
|
|
19532
|
+
process.stdout.write(` ${pc17.dim(step.label.padEnd(34))}
|
|
19604
19533
|
`);
|
|
19605
19534
|
const start = Date.now();
|
|
19606
|
-
const result =
|
|
19535
|
+
const result = spawnSync11("bash", [scriptPath], {
|
|
19607
19536
|
stdio: "inherit",
|
|
19608
19537
|
cwd,
|
|
19609
19538
|
env: { ...process.env, ...olamTagEnv }
|
|
@@ -19611,7 +19540,7 @@ ${spaResult.stderr}`);
|
|
|
19611
19540
|
const durationMs = Date.now() - start;
|
|
19612
19541
|
const ok = result.status === 0 && result.error === void 0;
|
|
19613
19542
|
const dur = `${(durationMs / 1e3).toFixed(1)}s`;
|
|
19614
|
-
process.stdout.write(` ${
|
|
19543
|
+
process.stdout.write(` ${pc17.dim(step.label.padEnd(34))}${ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${dur}
|
|
19615
19544
|
`);
|
|
19616
19545
|
timings.push({ label: step.label, durationMs });
|
|
19617
19546
|
if (!ok) {
|
|
@@ -19637,7 +19566,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
|
|
|
19637
19566
|
}
|
|
19638
19567
|
for (const t of timings) logRow.durations_ms[t.label] = t.durationMs;
|
|
19639
19568
|
const smokeStart = Date.now();
|
|
19640
|
-
process.stdout.write(` ${
|
|
19569
|
+
process.stdout.write(` ${pc17.dim("smoke (docker create + inspect)".padEnd(34))}`);
|
|
19641
19570
|
const smokeImages = [
|
|
19642
19571
|
"olam-auth:olam-next",
|
|
19643
19572
|
"olam-devbox:olam-next",
|
|
@@ -19647,7 +19576,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
|
|
|
19647
19576
|
const smokeFailures = smokeResults.filter((r) => !r.ok);
|
|
19648
19577
|
const smokeDurationMs = Date.now() - smokeStart;
|
|
19649
19578
|
const smokeDur = `${(smokeDurationMs / 1e3).toFixed(1)}s`;
|
|
19650
|
-
process.stdout.write(`${smokeFailures.length === 0 ?
|
|
19579
|
+
process.stdout.write(`${smokeFailures.length === 0 ? pc17.green("\u2713") : pc17.red("\u2717")} ${smokeDur}
|
|
19651
19580
|
`);
|
|
19652
19581
|
timings.push({ label: "smoke", durationMs: smokeDurationMs });
|
|
19653
19582
|
if (smokeFailures.length > 0) {
|
|
@@ -19674,12 +19603,12 @@ Recovery options:
|
|
|
19674
19603
|
process.exitCode = 1;
|
|
19675
19604
|
return;
|
|
19676
19605
|
}
|
|
19677
|
-
process.stdout.write(` ${
|
|
19606
|
+
process.stdout.write(` ${pc17.dim("atomic 6-tag swap".padEnd(34))}`);
|
|
19678
19607
|
const swapStart = Date.now();
|
|
19679
19608
|
const swapResult = performAtomicSwap(PRODUCTION_SWAP_PLAN);
|
|
19680
19609
|
const swapDurationMs = Date.now() - swapStart;
|
|
19681
19610
|
const swapDur = `${(swapDurationMs / 1e3).toFixed(1)}s`;
|
|
19682
|
-
process.stdout.write(`${swapResult.ok ?
|
|
19611
|
+
process.stdout.write(`${swapResult.ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${swapDur}
|
|
19683
19612
|
`);
|
|
19684
19613
|
timings.push({ label: "atomic swap", durationMs: swapDurationMs });
|
|
19685
19614
|
if (!swapResult.ok) {
|
|
@@ -19689,7 +19618,7 @@ Recovery options:
|
|
|
19689
19618
|
}
|
|
19690
19619
|
printInfo("Swap", swapResult.summary);
|
|
19691
19620
|
const composeFile = findComposeFile();
|
|
19692
|
-
process.stdout.write(` ${
|
|
19621
|
+
process.stdout.write(` ${pc17.dim("docker compose recreate".padEnd(34))}`);
|
|
19693
19622
|
const composeStart = Date.now();
|
|
19694
19623
|
const composeResult = runCompose(
|
|
19695
19624
|
["up", "-d", "--force-recreate"],
|
|
@@ -19699,7 +19628,7 @@ Recovery options:
|
|
|
19699
19628
|
const composeDurationMs = Date.now() - composeStart;
|
|
19700
19629
|
const composeOk = composeResult.ok;
|
|
19701
19630
|
const composeDur = `${(composeDurationMs / 1e3).toFixed(1)}s`;
|
|
19702
|
-
process.stdout.write(`${composeOk ?
|
|
19631
|
+
process.stdout.write(`${composeOk ? pc17.green("\u2713") : pc17.red("\u2717")} ${composeDur}
|
|
19703
19632
|
`);
|
|
19704
19633
|
timings.push({ label: "container recreate", durationMs: composeDurationMs });
|
|
19705
19634
|
if (!composeOk) {
|
|
@@ -19715,10 +19644,10 @@ Recovery options:
|
|
|
19715
19644
|
process.exitCode = 1;
|
|
19716
19645
|
return;
|
|
19717
19646
|
}
|
|
19718
|
-
process.stdout.write(` ${
|
|
19647
|
+
process.stdout.write(` ${pc17.dim("recreate auth-service".padEnd(34))}`);
|
|
19719
19648
|
const authResult = await recreateAuthService();
|
|
19720
19649
|
const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
|
|
19721
|
-
process.stdout.write(`${authResult.ok ?
|
|
19650
|
+
process.stdout.write(`${authResult.ok ? pc17.green("\u2713") : pc17.red("\u2717")} ${authDur}
|
|
19722
19651
|
`);
|
|
19723
19652
|
timings.push({ label: "auth recreate", durationMs: authResult.durationMs });
|
|
19724
19653
|
if (!authResult.ok) {
|
|
@@ -19733,12 +19662,12 @@ Recovery options:
|
|
|
19733
19662
|
process.exitCode = 1;
|
|
19734
19663
|
return;
|
|
19735
19664
|
}
|
|
19736
|
-
process.stdout.write(` ${
|
|
19665
|
+
process.stdout.write(` ${pc17.dim("waiting for /health".padEnd(34))}`);
|
|
19737
19666
|
const healthStart = Date.now();
|
|
19738
19667
|
const healthy = await waitForHealth(1e4);
|
|
19739
19668
|
const healthDurationMs = Date.now() - healthStart;
|
|
19740
19669
|
const healthDur = `${(healthDurationMs / 1e3).toFixed(1)}s`;
|
|
19741
|
-
process.stdout.write(`${healthy ?
|
|
19670
|
+
process.stdout.write(`${healthy ? pc17.green("\u2713") : pc17.yellow("?")} ${healthDur}
|
|
19742
19671
|
`);
|
|
19743
19672
|
timings.push({ label: "/health", durationMs: healthDurationMs });
|
|
19744
19673
|
if (!healthy) {
|
|
@@ -19746,12 +19675,12 @@ Recovery options:
|
|
|
19746
19675
|
"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."
|
|
19747
19676
|
);
|
|
19748
19677
|
}
|
|
19749
|
-
process.stdout.write(` ${
|
|
19678
|
+
process.stdout.write(` ${pc17.dim("verify /version/status round-trip".padEnd(34))}`);
|
|
19750
19679
|
const versionStart = Date.now();
|
|
19751
19680
|
const versionMatch = await waitForVersionMatch(_targetSha, 9e4);
|
|
19752
19681
|
const versionDurationMs = Date.now() - versionStart;
|
|
19753
19682
|
const versionDur = `${(versionDurationMs / 1e3).toFixed(1)}s`;
|
|
19754
|
-
process.stdout.write(`${versionMatch.matched ?
|
|
19683
|
+
process.stdout.write(`${versionMatch.matched ? pc17.green("\u2713") : pc17.yellow("?")} ${versionDur}
|
|
19755
19684
|
`);
|
|
19756
19685
|
timings.push({ label: "/version/status round-trip", durationMs: versionDurationMs });
|
|
19757
19686
|
if (!versionMatch.matched) {
|
|
@@ -19825,16 +19754,16 @@ init_host_cp();
|
|
|
19825
19754
|
init_context();
|
|
19826
19755
|
init_output();
|
|
19827
19756
|
import * as http3 from "node:http";
|
|
19828
|
-
import
|
|
19757
|
+
import pc18 from "picocolors";
|
|
19829
19758
|
var HOST_CP_PORT3 = 19e3;
|
|
19830
19759
|
function colorLine(line) {
|
|
19831
|
-
if (/\bERROR\b/.test(line)) return
|
|
19832
|
-
if (/\bWARN\b/.test(line)) return
|
|
19833
|
-
if (/\bINFO\b/.test(line)) return
|
|
19760
|
+
if (/\bERROR\b/.test(line)) return pc18.red(line);
|
|
19761
|
+
if (/\bWARN\b/.test(line)) return pc18.yellow(line);
|
|
19762
|
+
if (/\bINFO\b/.test(line)) return pc18.dim(line);
|
|
19834
19763
|
return line;
|
|
19835
19764
|
}
|
|
19836
19765
|
function formatLine(line, service, showService) {
|
|
19837
|
-
const prefix = showService && service ? `${
|
|
19766
|
+
const prefix = showService && service ? `${pc18.cyan(`[${service}]`)} ` : "";
|
|
19838
19767
|
return prefix + colorLine(line);
|
|
19839
19768
|
}
|
|
19840
19769
|
function parseSseEvent(raw) {
|
|
@@ -19951,8 +19880,8 @@ function registerLogs(program2) {
|
|
|
19951
19880
|
// src/commands/ps.ts
|
|
19952
19881
|
init_context();
|
|
19953
19882
|
init_output();
|
|
19954
|
-
import
|
|
19955
|
-
import { spawnSync as
|
|
19883
|
+
import pc19 from "picocolors";
|
|
19884
|
+
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
19956
19885
|
var SAFE_IDENT4 = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
19957
19886
|
function parseDockerTop(stdout) {
|
|
19958
19887
|
const trimmed = stdout.trim();
|
|
@@ -20012,18 +19941,18 @@ function printTable2(rows) {
|
|
|
20012
19941
|
const fixedWidth = 5 + 1 + 8 + 1 + 6 + 1 + 6 + 1 + 10 + 1 + 6 + 1;
|
|
20013
19942
|
const cmdWidth = Math.max(20, cols - fixedWidth);
|
|
20014
19943
|
const header = [
|
|
20015
|
-
|
|
20016
|
-
|
|
20017
|
-
|
|
20018
|
-
|
|
20019
|
-
|
|
20020
|
-
|
|
20021
|
-
|
|
19944
|
+
pc19.bold(pc19.dim("PID".padEnd(5))),
|
|
19945
|
+
pc19.bold(pc19.dim("USER".padEnd(8))),
|
|
19946
|
+
pc19.bold(pc19.dim("%CPU".padEnd(6))),
|
|
19947
|
+
pc19.bold(pc19.dim("%MEM".padEnd(6))),
|
|
19948
|
+
pc19.bold(pc19.dim("STARTED".padEnd(10))),
|
|
19949
|
+
pc19.bold(pc19.dim("STATE".padEnd(6))),
|
|
19950
|
+
pc19.bold(pc19.dim("COMMAND"))
|
|
20022
19951
|
].join(" ");
|
|
20023
19952
|
console.log(header);
|
|
20024
19953
|
for (const row of rows) {
|
|
20025
19954
|
const cmd = row.command.length > cmdWidth ? row.command.slice(0, cmdWidth - 1) + "\u2026" : row.command;
|
|
20026
|
-
const stateFn = row.state.startsWith("R") ?
|
|
19955
|
+
const stateFn = row.state.startsWith("R") ? pc19.green : row.state.startsWith("Z") ? pc19.red : pc19.dim;
|
|
20027
19956
|
console.log([
|
|
20028
19957
|
row.pid.padEnd(5),
|
|
20029
19958
|
row.user.slice(0, 8).padEnd(8),
|
|
@@ -20052,7 +19981,7 @@ function registerPs(program2) {
|
|
|
20052
19981
|
const containerName = `olam-${worldId}-devbox`;
|
|
20053
19982
|
let watchInterval;
|
|
20054
19983
|
function fetchAndPrint() {
|
|
20055
|
-
const result =
|
|
19984
|
+
const result = spawnSync12(
|
|
20056
19985
|
"docker",
|
|
20057
19986
|
["top", containerName, "pid", "user", "pcpu", "pmem", "stime", "stat", "cmd"],
|
|
20058
19987
|
{ encoding: "utf-8", timeout: 3e3 }
|
|
@@ -20072,7 +20001,7 @@ function registerPs(program2) {
|
|
|
20072
20001
|
printTable2(rows);
|
|
20073
20002
|
if (opts.watch) {
|
|
20074
20003
|
process.stdout.write(`
|
|
20075
|
-
${
|
|
20004
|
+
${pc19.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
|
|
20076
20005
|
`);
|
|
20077
20006
|
}
|
|
20078
20007
|
}
|
|
@@ -20089,20 +20018,20 @@ ${pc18.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
|
|
|
20089
20018
|
|
|
20090
20019
|
// src/commands/keys.ts
|
|
20091
20020
|
init_output();
|
|
20092
|
-
import * as
|
|
20021
|
+
import * as fs28 from "node:fs";
|
|
20093
20022
|
import * as os17 from "node:os";
|
|
20094
|
-
import * as
|
|
20023
|
+
import * as path32 from "node:path";
|
|
20095
20024
|
import YAML4 from "yaml";
|
|
20096
20025
|
function olamHome2() {
|
|
20097
|
-
return process.env.OLAM_HOME ??
|
|
20026
|
+
return process.env.OLAM_HOME ?? path32.join(os17.homedir(), ".olam");
|
|
20098
20027
|
}
|
|
20099
20028
|
function keysFilePath() {
|
|
20100
|
-
return
|
|
20029
|
+
return path32.join(olamHome2(), "keys.yaml");
|
|
20101
20030
|
}
|
|
20102
20031
|
function readKeysFile() {
|
|
20103
20032
|
const filePath = keysFilePath();
|
|
20104
|
-
if (!
|
|
20105
|
-
const raw =
|
|
20033
|
+
if (!fs28.existsSync(filePath)) return null;
|
|
20034
|
+
const raw = fs28.readFileSync(filePath, "utf-8").trim();
|
|
20106
20035
|
if (raw.length === 0) return null;
|
|
20107
20036
|
try {
|
|
20108
20037
|
const parsed = YAML4.parse(raw);
|
|
@@ -20118,13 +20047,13 @@ function readKeysFile() {
|
|
|
20118
20047
|
}
|
|
20119
20048
|
function writeKeysFile(keys) {
|
|
20120
20049
|
const dir = olamHome2();
|
|
20121
|
-
if (!
|
|
20122
|
-
|
|
20050
|
+
if (!fs28.existsSync(dir)) {
|
|
20051
|
+
fs28.mkdirSync(dir, { recursive: true });
|
|
20123
20052
|
}
|
|
20124
20053
|
const filePath = keysFilePath();
|
|
20125
20054
|
const content = YAML4.stringify(keys);
|
|
20126
|
-
|
|
20127
|
-
|
|
20055
|
+
fs28.writeFileSync(filePath, content, { encoding: "utf-8", mode: 384 });
|
|
20056
|
+
fs28.chmodSync(filePath, 384);
|
|
20128
20057
|
}
|
|
20129
20058
|
function redact(value) {
|
|
20130
20059
|
if (value.length <= 8) return value + "...";
|
|
@@ -20167,7 +20096,7 @@ function registerKeys(program2) {
|
|
|
20167
20096
|
}
|
|
20168
20097
|
const { [key]: _removed, ...rest } = existing;
|
|
20169
20098
|
if (Object.keys(rest).length === 0) {
|
|
20170
|
-
|
|
20099
|
+
fs28.unlinkSync(keysFilePath());
|
|
20171
20100
|
} else {
|
|
20172
20101
|
writeKeysFile(rest);
|
|
20173
20102
|
}
|
|
@@ -20190,33 +20119,33 @@ function registerKeys(program2) {
|
|
|
20190
20119
|
}
|
|
20191
20120
|
|
|
20192
20121
|
// src/commands/world-snapshot.ts
|
|
20193
|
-
import * as
|
|
20194
|
-
import * as
|
|
20122
|
+
import * as fs30 from "node:fs";
|
|
20123
|
+
import * as path34 from "node:path";
|
|
20195
20124
|
import { execSync as execSync9 } from "node:child_process";
|
|
20196
|
-
import
|
|
20125
|
+
import pc20 from "picocolors";
|
|
20197
20126
|
|
|
20198
20127
|
// ../core/dist/world/snapshot.js
|
|
20199
|
-
import * as
|
|
20200
|
-
import * as
|
|
20128
|
+
import * as crypto6 from "node:crypto";
|
|
20129
|
+
import * as fs29 from "node:fs";
|
|
20201
20130
|
import * as os18 from "node:os";
|
|
20202
|
-
import * as
|
|
20203
|
-
import { execFileSync as
|
|
20131
|
+
import * as path33 from "node:path";
|
|
20132
|
+
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
20204
20133
|
function snapshotsDir() {
|
|
20205
|
-
return process.env["OLAM_SNAPSHOTS_DIR"] ??
|
|
20134
|
+
return process.env["OLAM_SNAPSHOTS_DIR"] ?? path33.join(os18.homedir(), ".olam", "snapshots");
|
|
20206
20135
|
}
|
|
20207
20136
|
function snapshotKindDir(worldId, kind) {
|
|
20208
|
-
return
|
|
20137
|
+
return path33.join(snapshotsDir(), worldId, kind);
|
|
20209
20138
|
}
|
|
20210
20139
|
function snapshotTarPath(worldId, kind, repoName, hash) {
|
|
20211
20140
|
const base = repoName ? `${repoName}-${hash}` : hash;
|
|
20212
|
-
return
|
|
20141
|
+
return path33.join(snapshotKindDir(worldId, kind), `${base}.tar.gz`);
|
|
20213
20142
|
}
|
|
20214
20143
|
function manifestPath(tarPath) {
|
|
20215
20144
|
return tarPath.replace(/\.tar\.gz$/, ".manifest.json");
|
|
20216
20145
|
}
|
|
20217
20146
|
function hashBuffers(entries) {
|
|
20218
20147
|
const sorted = [...entries].sort((a, b) => a.path.localeCompare(b.path));
|
|
20219
|
-
const hash =
|
|
20148
|
+
const hash = crypto6.createHash("sha256");
|
|
20220
20149
|
for (const entry of sorted) {
|
|
20221
20150
|
hash.update(entry.path);
|
|
20222
20151
|
hash.update("\0");
|
|
@@ -20226,17 +20155,17 @@ function hashBuffers(entries) {
|
|
|
20226
20155
|
return hash.digest("hex").slice(0, 12);
|
|
20227
20156
|
}
|
|
20228
20157
|
function computeGemsFingerprint(repoDir) {
|
|
20229
|
-
const lockfile =
|
|
20230
|
-
if (!
|
|
20158
|
+
const lockfile = path33.join(repoDir, "Gemfile.lock");
|
|
20159
|
+
if (!fs29.existsSync(lockfile))
|
|
20231
20160
|
return null;
|
|
20232
|
-
return hashBuffers([{ path: "Gemfile.lock", content:
|
|
20161
|
+
return hashBuffers([{ path: "Gemfile.lock", content: fs29.readFileSync(lockfile) }]);
|
|
20233
20162
|
}
|
|
20234
20163
|
function computeNodeFingerprint(repoDir) {
|
|
20235
20164
|
const candidates = ["yarn.lock", "pnpm-lock.yaml", "package-lock.json"];
|
|
20236
20165
|
for (const name of candidates) {
|
|
20237
|
-
const lockfile =
|
|
20238
|
-
if (
|
|
20239
|
-
return hashBuffers([{ path: name, content:
|
|
20166
|
+
const lockfile = path33.join(repoDir, name);
|
|
20167
|
+
if (fs29.existsSync(lockfile)) {
|
|
20168
|
+
return hashBuffers([{ path: name, content: fs29.readFileSync(lockfile) }]);
|
|
20240
20169
|
}
|
|
20241
20170
|
}
|
|
20242
20171
|
return null;
|
|
@@ -20246,64 +20175,64 @@ function computePgFingerprint(repoDirs) {
|
|
|
20246
20175
|
const entries = [];
|
|
20247
20176
|
for (const repoDir of repoDirs) {
|
|
20248
20177
|
for (const pattern of patterns) {
|
|
20249
|
-
const filePath =
|
|
20250
|
-
if (
|
|
20251
|
-
entries.push({ path: filePath, content:
|
|
20178
|
+
const filePath = path33.join(repoDir, pattern);
|
|
20179
|
+
if (fs29.existsSync(filePath)) {
|
|
20180
|
+
entries.push({ path: filePath, content: fs29.readFileSync(filePath) });
|
|
20252
20181
|
}
|
|
20253
20182
|
}
|
|
20254
20183
|
}
|
|
20255
20184
|
return entries.length > 0 ? hashBuffers(entries) : null;
|
|
20256
20185
|
}
|
|
20257
20186
|
function packTarball(srcDir, destPath, opts = {}) {
|
|
20258
|
-
|
|
20187
|
+
fs29.mkdirSync(path33.dirname(destPath), { recursive: true });
|
|
20259
20188
|
const tmp = `${destPath}.tmp`;
|
|
20260
20189
|
const args = [];
|
|
20261
20190
|
if (opts.followSymlinks)
|
|
20262
20191
|
args.push("-h");
|
|
20263
20192
|
args.push("-czf", tmp, "-C", srcDir, ".");
|
|
20264
20193
|
try {
|
|
20265
|
-
|
|
20266
|
-
|
|
20194
|
+
execFileSync6("tar", args, { stdio: "pipe" });
|
|
20195
|
+
fs29.renameSync(tmp, destPath);
|
|
20267
20196
|
} catch (err) {
|
|
20268
20197
|
try {
|
|
20269
|
-
|
|
20198
|
+
fs29.rmSync(tmp, { force: true });
|
|
20270
20199
|
} catch {
|
|
20271
20200
|
}
|
|
20272
20201
|
throw err;
|
|
20273
20202
|
}
|
|
20274
20203
|
}
|
|
20275
20204
|
function writeManifest(manifest, tarPath) {
|
|
20276
|
-
|
|
20205
|
+
fs29.writeFileSync(manifestPath(tarPath), JSON.stringify(manifest, null, 2), "utf-8");
|
|
20277
20206
|
}
|
|
20278
20207
|
function readManifest(tarPath) {
|
|
20279
20208
|
const mPath = manifestPath(tarPath);
|
|
20280
|
-
if (!
|
|
20209
|
+
if (!fs29.existsSync(mPath))
|
|
20281
20210
|
return null;
|
|
20282
20211
|
try {
|
|
20283
|
-
return JSON.parse(
|
|
20212
|
+
return JSON.parse(fs29.readFileSync(mPath, "utf-8"));
|
|
20284
20213
|
} catch {
|
|
20285
20214
|
return null;
|
|
20286
20215
|
}
|
|
20287
20216
|
}
|
|
20288
20217
|
function listSnapshots(worldIdFilter) {
|
|
20289
20218
|
const root = snapshotsDir();
|
|
20290
|
-
if (!
|
|
20219
|
+
if (!fs29.existsSync(root))
|
|
20291
20220
|
return [];
|
|
20292
20221
|
const now = Date.now();
|
|
20293
20222
|
const results = [];
|
|
20294
|
-
const worlds = worldIdFilter ? [worldIdFilter] :
|
|
20223
|
+
const worlds = worldIdFilter ? [worldIdFilter] : fs29.readdirSync(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
20295
20224
|
for (const worldId of worlds) {
|
|
20296
|
-
const worldDir =
|
|
20297
|
-
if (!
|
|
20225
|
+
const worldDir = path33.join(root, worldId);
|
|
20226
|
+
if (!fs29.existsSync(worldDir) || !fs29.statSync(worldDir).isDirectory())
|
|
20298
20227
|
continue;
|
|
20299
20228
|
for (const kind of ["gems", "node", "pg"]) {
|
|
20300
|
-
const kindDir =
|
|
20301
|
-
if (!
|
|
20229
|
+
const kindDir = path33.join(worldDir, kind);
|
|
20230
|
+
if (!fs29.existsSync(kindDir))
|
|
20302
20231
|
continue;
|
|
20303
|
-
const tarballs =
|
|
20232
|
+
const tarballs = fs29.readdirSync(kindDir).filter((f) => f.endsWith(".tar.gz"));
|
|
20304
20233
|
for (const tarFile of tarballs) {
|
|
20305
|
-
const tarPath =
|
|
20306
|
-
const stat =
|
|
20234
|
+
const tarPath = path33.join(kindDir, tarFile);
|
|
20235
|
+
const stat = fs29.statSync(tarPath);
|
|
20307
20236
|
const manifest = readManifest(tarPath);
|
|
20308
20237
|
if (!manifest)
|
|
20309
20238
|
continue;
|
|
@@ -20379,7 +20308,7 @@ async function handleCreate2(worldId, kindArg) {
|
|
|
20379
20308
|
const label = r.repo ? `${r.kind}/${r.repo}` : r.kind;
|
|
20380
20309
|
if (r.ok) {
|
|
20381
20310
|
printSuccess(`${label}`);
|
|
20382
|
-
console.log(` ${
|
|
20311
|
+
console.log(` ${pc20.dim(r.tarPath)}`);
|
|
20383
20312
|
} else {
|
|
20384
20313
|
printWarning(`${label}: ${r.msg ?? "skipped"}`);
|
|
20385
20314
|
}
|
|
@@ -20393,17 +20322,17 @@ function resolveKinds(arg) {
|
|
|
20393
20322
|
return [];
|
|
20394
20323
|
}
|
|
20395
20324
|
async function captureGems(worldId, workspacePath, repo) {
|
|
20396
|
-
const repoDir =
|
|
20325
|
+
const repoDir = path34.join(workspacePath, repo);
|
|
20397
20326
|
const fingerprint = computeGemsFingerprint(repoDir);
|
|
20398
20327
|
if (!fingerprint) {
|
|
20399
20328
|
return { ok: false, tarPath: "", msg: "no Gemfile.lock \u2014 layer does not apply" };
|
|
20400
20329
|
}
|
|
20401
20330
|
const tarPath = snapshotTarPath(worldId, "gems", repo, fingerprint);
|
|
20402
|
-
const vendorBundle =
|
|
20403
|
-
if (
|
|
20331
|
+
const vendorBundle = path34.join(repoDir, "vendor", "bundle");
|
|
20332
|
+
if (fs30.existsSync(vendorBundle)) {
|
|
20404
20333
|
try {
|
|
20405
20334
|
packTarball(vendorBundle, tarPath);
|
|
20406
|
-
const stat =
|
|
20335
|
+
const stat = fs30.statSync(tarPath);
|
|
20407
20336
|
const manifest = {
|
|
20408
20337
|
kind: "gems",
|
|
20409
20338
|
worldId,
|
|
@@ -20436,10 +20365,10 @@ async function captureGems(worldId, workspacePath, repo) {
|
|
|
20436
20365
|
`docker exec ${containerName} sh -c 'mkdir -p "$(dirname ${tmpTar})" && tar -czf ${tmpTar}.tmp -C ${bundlePath} . && mv ${tmpTar}.tmp ${tmpTar}'`,
|
|
20437
20366
|
{ stdio: "pipe", timeout: 12e4 }
|
|
20438
20367
|
);
|
|
20439
|
-
|
|
20368
|
+
fs30.mkdirSync(path34.dirname(tarPath), { recursive: true });
|
|
20440
20369
|
execSync9(`docker cp ${containerName}:${tmpTar} "${tarPath}"`, { stdio: "pipe", timeout: 12e4 });
|
|
20441
20370
|
execSync9(`docker exec ${containerName} rm -f ${tmpTar}`, { stdio: "pipe" });
|
|
20442
|
-
const stat =
|
|
20371
|
+
const stat = fs30.statSync(tarPath);
|
|
20443
20372
|
const manifest = {
|
|
20444
20373
|
kind: "gems",
|
|
20445
20374
|
worldId,
|
|
@@ -20456,19 +20385,19 @@ async function captureGems(worldId, workspacePath, repo) {
|
|
|
20456
20385
|
}
|
|
20457
20386
|
}
|
|
20458
20387
|
async function captureNode(worldId, workspacePath, repo) {
|
|
20459
|
-
const repoDir =
|
|
20388
|
+
const repoDir = path34.join(workspacePath, repo);
|
|
20460
20389
|
const fingerprint = computeNodeFingerprint(repoDir);
|
|
20461
20390
|
if (!fingerprint) {
|
|
20462
20391
|
return { ok: false, tarPath: "", msg: "no lockfile \u2014 layer does not apply" };
|
|
20463
20392
|
}
|
|
20464
|
-
const nodeModules =
|
|
20465
|
-
if (!
|
|
20393
|
+
const nodeModules = path34.join(repoDir, "node_modules");
|
|
20394
|
+
if (!fs30.existsSync(nodeModules)) {
|
|
20466
20395
|
return { ok: false, tarPath: "", msg: "node_modules not installed yet" };
|
|
20467
20396
|
}
|
|
20468
20397
|
const tarPath = snapshotTarPath(worldId, "node", repo, fingerprint);
|
|
20469
20398
|
try {
|
|
20470
20399
|
packTarball(nodeModules, tarPath);
|
|
20471
|
-
const stat =
|
|
20400
|
+
const stat = fs30.statSync(tarPath);
|
|
20472
20401
|
const manifest = {
|
|
20473
20402
|
kind: "node",
|
|
20474
20403
|
worldId,
|
|
@@ -20485,7 +20414,7 @@ async function captureNode(worldId, workspacePath, repo) {
|
|
|
20485
20414
|
}
|
|
20486
20415
|
}
|
|
20487
20416
|
async function capturePg(worldId, workspacePath, repoNames) {
|
|
20488
|
-
const repoDirs = repoNames.map((r) =>
|
|
20417
|
+
const repoDirs = repoNames.map((r) => path34.join(workspacePath, r));
|
|
20489
20418
|
const fingerprint = computePgFingerprint(repoDirs);
|
|
20490
20419
|
if (!fingerprint) {
|
|
20491
20420
|
return { ok: false, tarPath: "", msg: "no Gemfile.lock / schema.rb \u2014 layer does not apply" };
|
|
@@ -20500,13 +20429,13 @@ async function capturePg(worldId, workspacePath, repoNames) {
|
|
|
20500
20429
|
}
|
|
20501
20430
|
try {
|
|
20502
20431
|
execSync9(`docker stop ${containerName}`, { stdio: "pipe", timeout: 3e4 });
|
|
20503
|
-
|
|
20432
|
+
fs30.mkdirSync(path34.dirname(tarPath), { recursive: true });
|
|
20504
20433
|
execSync9(
|
|
20505
|
-
`docker run --rm -v "${volumeName2}:/pgdata:ro" -v "${
|
|
20434
|
+
`docker run --rm -v "${volumeName2}:/pgdata:ro" -v "${path34.dirname(tarPath)}:/dest" alpine sh -c 'tar -czf /dest/${path34.basename(tarPath)}.tmp -C /pgdata . && mv /dest/${path34.basename(tarPath)}.tmp /dest/${path34.basename(tarPath)}'`,
|
|
20506
20435
|
{ stdio: "pipe", timeout: 18e4 }
|
|
20507
20436
|
);
|
|
20508
20437
|
execSync9(`docker start ${containerName}`, { stdio: "pipe", timeout: 3e4 });
|
|
20509
|
-
const stat =
|
|
20438
|
+
const stat = fs30.statSync(tarPath);
|
|
20510
20439
|
const manifest = {
|
|
20511
20440
|
kind: "pg",
|
|
20512
20441
|
worldId,
|
|
@@ -20529,7 +20458,7 @@ function handleList2(worldIdFilter) {
|
|
|
20529
20458
|
const entries = listSnapshots(worldIdFilter);
|
|
20530
20459
|
if (entries.length === 0) {
|
|
20531
20460
|
const where = worldIdFilter ? ` for world "${worldIdFilter}"` : "";
|
|
20532
|
-
console.log(
|
|
20461
|
+
console.log(pc20.dim(`No snapshots found${where}. Run \`olam world snapshot create <worldId>\` first.`));
|
|
20533
20462
|
return;
|
|
20534
20463
|
}
|
|
20535
20464
|
printHeader(`${entries.length} snapshot(s)`);
|
|
@@ -20538,15 +20467,15 @@ function handleList2(worldIdFilter) {
|
|
|
20538
20467
|
for (const entry of entries) {
|
|
20539
20468
|
const { manifest } = entry;
|
|
20540
20469
|
if (manifest.worldId !== lastWorldId) {
|
|
20541
|
-
console.log(
|
|
20470
|
+
console.log(pc20.bold(manifest.worldId));
|
|
20542
20471
|
lastWorldId = manifest.worldId;
|
|
20543
20472
|
}
|
|
20544
20473
|
const repo = manifest.repo ?? "(all repos)";
|
|
20545
20474
|
const size = formatBytes2(manifest.sizeBytes);
|
|
20546
20475
|
const age = formatAge2(entry.ageMs);
|
|
20547
|
-
const kindColor = manifest.kind === "gems" ?
|
|
20476
|
+
const kindColor = manifest.kind === "gems" ? pc20.magenta(manifest.kind) : manifest.kind === "node" ? pc20.cyan(manifest.kind) : pc20.yellow(manifest.kind);
|
|
20548
20477
|
console.log(
|
|
20549
|
-
` ${kindColor.padEnd(6)} ${
|
|
20478
|
+
` ${kindColor.padEnd(6)} ${pc20.dim(repo.padEnd(24))} ${manifest.fingerprint} ${size.padStart(8)} ${age}`
|
|
20550
20479
|
);
|
|
20551
20480
|
}
|
|
20552
20481
|
console.log();
|
|
@@ -20581,35 +20510,35 @@ function formatAge2(ms) {
|
|
|
20581
20510
|
// src/commands/refresh.ts
|
|
20582
20511
|
init_context();
|
|
20583
20512
|
init_output();
|
|
20584
|
-
import * as
|
|
20513
|
+
import * as fs32 from "node:fs";
|
|
20585
20514
|
import * as os19 from "node:os";
|
|
20586
|
-
import * as
|
|
20587
|
-
import { spawnSync as
|
|
20515
|
+
import * as path36 from "node:path";
|
|
20516
|
+
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
20588
20517
|
import ora8 from "ora";
|
|
20589
20518
|
|
|
20590
20519
|
// src/commands/refresh-helpers.ts
|
|
20591
|
-
import * as
|
|
20592
|
-
import * as
|
|
20520
|
+
import * as fs31 from "node:fs";
|
|
20521
|
+
import * as path35 from "node:path";
|
|
20593
20522
|
function collectCpSourceFiles(standaloneDir) {
|
|
20594
|
-
if (!
|
|
20523
|
+
if (!fs31.existsSync(standaloneDir)) {
|
|
20595
20524
|
throw new Error(`CP standalone dir not found: ${standaloneDir}`);
|
|
20596
20525
|
}
|
|
20597
20526
|
const entries = [];
|
|
20598
|
-
const topLevel =
|
|
20599
|
-
const stat =
|
|
20527
|
+
const topLevel = fs31.readdirSync(standaloneDir).filter((f) => {
|
|
20528
|
+
const stat = fs31.statSync(path35.join(standaloneDir, f));
|
|
20600
20529
|
return stat.isFile() && f.endsWith(".mjs") && !f.endsWith(".test.mjs");
|
|
20601
20530
|
}).sort();
|
|
20602
20531
|
for (const f of topLevel) {
|
|
20603
|
-
entries.push({ srcPath:
|
|
20532
|
+
entries.push({ srcPath: path35.join(standaloneDir, f), destRelPath: f });
|
|
20604
20533
|
}
|
|
20605
|
-
const libDir =
|
|
20606
|
-
if (
|
|
20607
|
-
const libFiles =
|
|
20608
|
-
const stat =
|
|
20534
|
+
const libDir = path35.join(standaloneDir, "lib");
|
|
20535
|
+
if (fs31.existsSync(libDir) && fs31.statSync(libDir).isDirectory()) {
|
|
20536
|
+
const libFiles = fs31.readdirSync(libDir).filter((f) => {
|
|
20537
|
+
const stat = fs31.statSync(path35.join(libDir, f));
|
|
20609
20538
|
return stat.isFile() && f.endsWith(".mjs") && !f.endsWith(".test.mjs");
|
|
20610
20539
|
}).sort();
|
|
20611
20540
|
for (const f of libFiles) {
|
|
20612
|
-
entries.push({ srcPath:
|
|
20541
|
+
entries.push({ srcPath: path35.join(libDir, f), destRelPath: `lib/${f}` });
|
|
20613
20542
|
}
|
|
20614
20543
|
}
|
|
20615
20544
|
return entries;
|
|
@@ -20628,7 +20557,7 @@ var RESTART_TIMEOUT_S = 30;
|
|
|
20628
20557
|
var HEALTH_POLL_MS = 500;
|
|
20629
20558
|
var HEALTH_TIMEOUT_MS = 3e4;
|
|
20630
20559
|
function docker(args) {
|
|
20631
|
-
const result =
|
|
20560
|
+
const result = spawnSync13("docker", args, {
|
|
20632
20561
|
encoding: "utf-8",
|
|
20633
20562
|
stdio: ["ignore", "pipe", "pipe"]
|
|
20634
20563
|
});
|
|
@@ -20667,16 +20596,16 @@ async function refreshWorld(worldId, portOffset, standaloneDir, opts) {
|
|
|
20667
20596
|
error: err instanceof Error ? err.message : String(err)
|
|
20668
20597
|
};
|
|
20669
20598
|
}
|
|
20670
|
-
const stagingDir =
|
|
20671
|
-
|
|
20599
|
+
const stagingDir = fs32.mkdtempSync(
|
|
20600
|
+
path36.join(os19.tmpdir(), `olam-refresh-${worldId}-`)
|
|
20672
20601
|
);
|
|
20673
20602
|
try {
|
|
20674
20603
|
const hasLib = entries.some((e) => e.destRelPath.startsWith("lib/"));
|
|
20675
20604
|
if (hasLib) {
|
|
20676
|
-
|
|
20605
|
+
fs32.mkdirSync(path36.join(stagingDir, "lib"), { recursive: true });
|
|
20677
20606
|
}
|
|
20678
20607
|
for (const { srcPath, destRelPath } of entries) {
|
|
20679
|
-
|
|
20608
|
+
fs32.copyFileSync(srcPath, path36.join(stagingDir, destRelPath));
|
|
20680
20609
|
}
|
|
20681
20610
|
const cpResult = docker([
|
|
20682
20611
|
"cp",
|
|
@@ -20691,7 +20620,7 @@ async function refreshWorld(worldId, portOffset, standaloneDir, opts) {
|
|
|
20691
20620
|
};
|
|
20692
20621
|
}
|
|
20693
20622
|
} finally {
|
|
20694
|
-
|
|
20623
|
+
fs32.rmSync(stagingDir, { recursive: true, force: true });
|
|
20695
20624
|
}
|
|
20696
20625
|
if (opts.restart) {
|
|
20697
20626
|
const restartResult = docker([
|
|
@@ -20728,11 +20657,11 @@ function registerRefresh(program2) {
|
|
|
20728
20657
|
process.exitCode = 1;
|
|
20729
20658
|
return;
|
|
20730
20659
|
}
|
|
20731
|
-
const standaloneDir =
|
|
20660
|
+
const standaloneDir = path36.join(
|
|
20732
20661
|
process.cwd(),
|
|
20733
20662
|
"packages/control-plane/standalone"
|
|
20734
20663
|
);
|
|
20735
|
-
if (!
|
|
20664
|
+
if (!fs32.existsSync(standaloneDir)) {
|
|
20736
20665
|
printError(
|
|
20737
20666
|
`CP standalone source not found at ${standaloneDir}.
|
|
20738
20667
|
Run \`olam refresh\` from the olam repo root.`
|
|
@@ -20811,11 +20740,11 @@ Run \`olam refresh\` from the olam repo root.`
|
|
|
20811
20740
|
}
|
|
20812
20741
|
|
|
20813
20742
|
// src/commands/diagnose.ts
|
|
20814
|
-
import * as
|
|
20743
|
+
import * as fs33 from "node:fs";
|
|
20815
20744
|
import * as os20 from "node:os";
|
|
20816
|
-
import * as
|
|
20817
|
-
import { execFileSync as
|
|
20818
|
-
import
|
|
20745
|
+
import * as path37 from "node:path";
|
|
20746
|
+
import { execFileSync as execFileSync7, execSync as execSync10 } from "node:child_process";
|
|
20747
|
+
import pc21 from "picocolors";
|
|
20819
20748
|
|
|
20820
20749
|
// ../core/dist/diagnose/secret-stripper.js
|
|
20821
20750
|
var SECRET_PATTERNS = [
|
|
@@ -20848,9 +20777,9 @@ function stripSecrets(input) {
|
|
|
20848
20777
|
}
|
|
20849
20778
|
|
|
20850
20779
|
// src/commands/diagnose.ts
|
|
20851
|
-
var DIAGNOSTICS_DIR =
|
|
20852
|
-
var LOG_DIR =
|
|
20853
|
-
var CACHE_DIR =
|
|
20780
|
+
var DIAGNOSTICS_DIR = path37.join(os20.homedir(), ".olam", "diagnostics");
|
|
20781
|
+
var LOG_DIR = path37.join(os20.homedir(), ".olam", "log");
|
|
20782
|
+
var CACHE_DIR = path37.join(os20.homedir(), ".olam", "cache");
|
|
20854
20783
|
var LOG_TAIL_LINES = 200;
|
|
20855
20784
|
function safeExec(cmd) {
|
|
20856
20785
|
try {
|
|
@@ -20860,14 +20789,14 @@ function safeExec(cmd) {
|
|
|
20860
20789
|
}
|
|
20861
20790
|
}
|
|
20862
20791
|
function defaultZip(zipPath, files) {
|
|
20863
|
-
|
|
20792
|
+
execFileSync7("zip", ["-j", zipPath, ...files]);
|
|
20864
20793
|
}
|
|
20865
20794
|
async function buildDiagnosticsZip(_exec = (cmd) => safeExec(cmd), _outDir = DIAGNOSTICS_DIR, _logDir = LOG_DIR, _zip = defaultZip) {
|
|
20866
20795
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 23);
|
|
20867
|
-
const zipPath =
|
|
20868
|
-
const tmpDir =
|
|
20796
|
+
const zipPath = path37.join(_outDir, `olam-diag-${ts}.zip`);
|
|
20797
|
+
const tmpDir = fs33.mkdtempSync(path37.join(os20.tmpdir(), "olam-diag-"));
|
|
20869
20798
|
try {
|
|
20870
|
-
|
|
20799
|
+
fs33.mkdirSync(_outDir, { recursive: true });
|
|
20871
20800
|
const entries = [];
|
|
20872
20801
|
const version = process.env["OLAM_CLI_VERSION"] ?? "unknown";
|
|
20873
20802
|
const nodeVersion = process.version;
|
|
@@ -20883,14 +20812,14 @@ platform: ${platform}
|
|
|
20883
20812
|
`uptime: ${os20.uptime()}s`
|
|
20884
20813
|
].join("\n") + "\n";
|
|
20885
20814
|
_writeEntry(tmpDir, "os-info.txt", stripSecrets(osContent), entries);
|
|
20886
|
-
const depsFile =
|
|
20887
|
-
if (
|
|
20888
|
-
const deps =
|
|
20815
|
+
const depsFile = path37.join(CACHE_DIR, "deps.json");
|
|
20816
|
+
if (fs33.existsSync(depsFile)) {
|
|
20817
|
+
const deps = fs33.readFileSync(depsFile, "utf-8");
|
|
20889
20818
|
_writeEntry(tmpDir, "deps.json", stripSecrets(deps), entries);
|
|
20890
20819
|
}
|
|
20891
20820
|
const latestLog = _latestLog(_logDir);
|
|
20892
20821
|
if (latestLog) {
|
|
20893
|
-
const lines =
|
|
20822
|
+
const lines = fs33.readFileSync(latestLog, "utf-8").split("\n");
|
|
20894
20823
|
const tail = lines.slice(-LOG_TAIL_LINES).join("\n");
|
|
20895
20824
|
_writeEntry(tmpDir, "log-tail.txt", stripSecrets(tail), entries);
|
|
20896
20825
|
}
|
|
@@ -20902,38 +20831,38 @@ platform: ${platform}
|
|
|
20902
20831
|
if (authAudit) {
|
|
20903
20832
|
_writeEntry(tmpDir, "audit-auth-callers.txt", stripSecrets(authAudit), entries);
|
|
20904
20833
|
}
|
|
20905
|
-
const fileArgs = entries.map((e) =>
|
|
20834
|
+
const fileArgs = entries.map((e) => path37.join(tmpDir, e));
|
|
20906
20835
|
try {
|
|
20907
20836
|
_zip(zipPath, fileArgs);
|
|
20908
20837
|
} catch (err) {
|
|
20909
20838
|
throw new Error(`zip command produced no output file. zip stderr: ${err.message}`);
|
|
20910
20839
|
}
|
|
20911
|
-
if (!
|
|
20840
|
+
if (!fs33.existsSync(zipPath)) {
|
|
20912
20841
|
throw new Error("zip command produced no output file.");
|
|
20913
20842
|
}
|
|
20914
20843
|
return { zipPath, entries };
|
|
20915
20844
|
} finally {
|
|
20916
20845
|
try {
|
|
20917
|
-
|
|
20846
|
+
fs33.rmSync(tmpDir, { recursive: true, force: true });
|
|
20918
20847
|
} catch {
|
|
20919
20848
|
}
|
|
20920
20849
|
}
|
|
20921
20850
|
}
|
|
20922
20851
|
function _writeEntry(dir, name, content, entries) {
|
|
20923
|
-
|
|
20852
|
+
fs33.writeFileSync(path37.join(dir, name), content, { mode: 420 });
|
|
20924
20853
|
entries.push(name);
|
|
20925
20854
|
}
|
|
20926
20855
|
function _latestLog(logDir) {
|
|
20927
|
-
if (!
|
|
20928
|
-
const files =
|
|
20929
|
-
return files.length > 0 ?
|
|
20856
|
+
if (!fs33.existsSync(logDir)) return null;
|
|
20857
|
+
const files = fs33.readdirSync(logDir).filter((f) => f.startsWith("host-")).sort().reverse();
|
|
20858
|
+
return files.length > 0 ? path37.join(logDir, files[0]) : null;
|
|
20930
20859
|
}
|
|
20931
20860
|
async function buildTelemetryPayload() {
|
|
20932
20861
|
const channel = "stable";
|
|
20933
|
-
const manifestFile =
|
|
20862
|
+
const manifestFile = path37.join(CACHE_DIR, "manifest.json");
|
|
20934
20863
|
let manifestAgeHours = null;
|
|
20935
|
-
if (
|
|
20936
|
-
const mtime =
|
|
20864
|
+
if (fs33.existsSync(manifestFile)) {
|
|
20865
|
+
const mtime = fs33.statSync(manifestFile).mtime.getTime();
|
|
20937
20866
|
manifestAgeHours = Math.round((Date.now() - mtime) / 36e5);
|
|
20938
20867
|
}
|
|
20939
20868
|
return {
|
|
@@ -20953,47 +20882,47 @@ function registerDiagnose(program2) {
|
|
|
20953
20882
|
return;
|
|
20954
20883
|
}
|
|
20955
20884
|
if (!opts.quiet) {
|
|
20956
|
-
console.log(
|
|
20885
|
+
console.log(pc21.cyan("Building diagnostics zip\u2026"));
|
|
20957
20886
|
}
|
|
20958
20887
|
try {
|
|
20959
20888
|
const { zipPath, entries } = await buildDiagnosticsZip();
|
|
20960
20889
|
if (!opts.quiet) {
|
|
20961
|
-
console.log(
|
|
20962
|
-
console.log(
|
|
20890
|
+
console.log(pc21.green(`Done: ${zipPath}`));
|
|
20891
|
+
console.log(pc21.dim(`Contents: ${entries.join(", ")}`));
|
|
20963
20892
|
}
|
|
20964
20893
|
if (opts.upload) {
|
|
20965
|
-
console.log(
|
|
20894
|
+
console.log(pc21.yellow(
|
|
20966
20895
|
`Telemetry endpoint not yet provisioned. Share the zip manually:
|
|
20967
20896
|
File: ${zipPath}
|
|
20968
20897
|
See docs/runbooks/share-diagnostics.md for instructions.`
|
|
20969
20898
|
));
|
|
20970
20899
|
}
|
|
20971
20900
|
} catch (err) {
|
|
20972
|
-
console.error(
|
|
20901
|
+
console.error(pc21.red(`Diagnose failed: ${err.message}`));
|
|
20973
20902
|
process.exitCode = 1;
|
|
20974
20903
|
}
|
|
20975
20904
|
});
|
|
20976
20905
|
}
|
|
20977
20906
|
|
|
20978
20907
|
// src/commands/update.ts
|
|
20979
|
-
import * as
|
|
20908
|
+
import * as fs36 from "node:fs";
|
|
20980
20909
|
import * as os22 from "node:os";
|
|
20981
|
-
import * as
|
|
20910
|
+
import * as path40 from "node:path";
|
|
20982
20911
|
import { execSync as execSync11 } from "node:child_process";
|
|
20983
|
-
import
|
|
20912
|
+
import pc22 from "picocolors";
|
|
20984
20913
|
|
|
20985
20914
|
// src/lib/symlink-reconcile.ts
|
|
20986
|
-
import * as
|
|
20987
|
-
import * as
|
|
20915
|
+
import * as fs34 from "node:fs";
|
|
20916
|
+
import * as path38 from "node:path";
|
|
20988
20917
|
var realFs = {
|
|
20989
|
-
readdirSync: (p) =>
|
|
20990
|
-
existsSync: (p) =>
|
|
20991
|
-
lstatSync: (p) =>
|
|
20992
|
-
readlinkSync: (p) =>
|
|
20993
|
-
symlinkSync: (t, l) =>
|
|
20994
|
-
unlinkSync: (p) =>
|
|
20918
|
+
readdirSync: (p) => fs34.readdirSync(p),
|
|
20919
|
+
existsSync: (p) => fs34.existsSync(p),
|
|
20920
|
+
lstatSync: (p) => fs34.lstatSync(p),
|
|
20921
|
+
readlinkSync: (p) => fs34.readlinkSync(p),
|
|
20922
|
+
symlinkSync: (t, l) => fs34.symlinkSync(t, l),
|
|
20923
|
+
unlinkSync: (p) => fs34.unlinkSync(p),
|
|
20995
20924
|
mkdirSync: (p, o) => {
|
|
20996
|
-
|
|
20925
|
+
fs34.mkdirSync(p, o);
|
|
20997
20926
|
}
|
|
20998
20927
|
};
|
|
20999
20928
|
function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
|
|
@@ -21003,8 +20932,8 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
|
|
|
21003
20932
|
_fs.mkdirSync(claudeSkillsDir, { recursive: true });
|
|
21004
20933
|
const sourceSkills = _fs.existsSync(npmSkillsDir) ? _fs.readdirSync(npmSkillsDir).filter((d) => d.startsWith("olam-")) : [];
|
|
21005
20934
|
for (const skill of sourceSkills) {
|
|
21006
|
-
const linkPath =
|
|
21007
|
-
const target =
|
|
20935
|
+
const linkPath = path38.join(claudeSkillsDir, skill);
|
|
20936
|
+
const target = path38.join(npmSkillsDir, skill);
|
|
21008
20937
|
if (!_fs.existsSync(linkPath)) {
|
|
21009
20938
|
try {
|
|
21010
20939
|
_fs.symlinkSync(target, linkPath);
|
|
@@ -21017,7 +20946,7 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
|
|
|
21017
20946
|
}
|
|
21018
20947
|
const deployedEntries = _fs.existsSync(claudeSkillsDir) ? _fs.readdirSync(claudeSkillsDir).filter((d) => d.startsWith("olam-")) : [];
|
|
21019
20948
|
for (const entry of deployedEntries) {
|
|
21020
|
-
const linkPath =
|
|
20949
|
+
const linkPath = path38.join(claudeSkillsDir, entry);
|
|
21021
20950
|
let isSymlink = false;
|
|
21022
20951
|
try {
|
|
21023
20952
|
isSymlink = _fs.lstatSync(linkPath).isSymbolicLink();
|
|
@@ -21042,9 +20971,9 @@ function reconcileSkillSymlinks(npmSkillsDir, claudeSkillsDir, _fs = realFs) {
|
|
|
21042
20971
|
|
|
21043
20972
|
// src/commands/update.ts
|
|
21044
20973
|
var PACKAGE_NAME = "@pleri/olam-cli";
|
|
21045
|
-
var CACHE_DIR2 =
|
|
21046
|
-
var LOG_DIR2 =
|
|
21047
|
-
var LAST_STABLE_FILE =
|
|
20974
|
+
var CACHE_DIR2 = path40.join(os22.homedir(), ".olam", "cache");
|
|
20975
|
+
var LOG_DIR2 = path40.join(os22.homedir(), ".olam", "log");
|
|
20976
|
+
var LAST_STABLE_FILE = path40.join(CACHE_DIR2, "last-stable.txt");
|
|
21048
20977
|
function defaultExec(cmd) {
|
|
21049
20978
|
try {
|
|
21050
20979
|
const stdout = execSync11(cmd, { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
|
|
@@ -21066,22 +20995,22 @@ function getCurrentVersion(_exec = defaultExec) {
|
|
|
21066
20995
|
}
|
|
21067
20996
|
function readLastStable(file = LAST_STABLE_FILE) {
|
|
21068
20997
|
try {
|
|
21069
|
-
const v =
|
|
20998
|
+
const v = fs36.readFileSync(file, "utf-8").trim();
|
|
21070
20999
|
return v || null;
|
|
21071
21000
|
} catch {
|
|
21072
21001
|
return null;
|
|
21073
21002
|
}
|
|
21074
21003
|
}
|
|
21075
21004
|
function writeLastStable(version, file = LAST_STABLE_FILE) {
|
|
21076
|
-
|
|
21077
|
-
|
|
21005
|
+
fs36.mkdirSync(path40.dirname(file), { recursive: true });
|
|
21006
|
+
fs36.writeFileSync(file, version, { mode: 420 });
|
|
21078
21007
|
}
|
|
21079
21008
|
function logUpdateFailure(stderr) {
|
|
21080
21009
|
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
21081
|
-
const logFile =
|
|
21010
|
+
const logFile = path40.join(LOG_DIR2, `update-${ts}.log`);
|
|
21082
21011
|
try {
|
|
21083
|
-
|
|
21084
|
-
|
|
21012
|
+
fs36.mkdirSync(LOG_DIR2, { recursive: true });
|
|
21013
|
+
fs36.appendFileSync(logFile, `[update-failure ${(/* @__PURE__ */ new Date()).toISOString()}]
|
|
21085
21014
|
${stderr}
|
|
21086
21015
|
`, "utf-8");
|
|
21087
21016
|
} catch {
|
|
@@ -21132,52 +21061,52 @@ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSy
|
|
|
21132
21061
|
writeLastStable(prevVersion);
|
|
21133
21062
|
}
|
|
21134
21063
|
if (!quiet) {
|
|
21135
|
-
console.log(
|
|
21064
|
+
console.log(pc22.cyan(`Installing ${PACKAGE_NAME}@${channel}\u2026`));
|
|
21136
21065
|
}
|
|
21137
21066
|
const installResult = _exec(`npm install -g ${PACKAGE_NAME}@${channel}`);
|
|
21138
21067
|
if (installResult.exitCode !== 0) {
|
|
21139
21068
|
logUpdateFailure(installResult.stderr);
|
|
21140
21069
|
if (!quiet) {
|
|
21141
|
-
console.error(
|
|
21070
|
+
console.error(pc22.red("Update failed."));
|
|
21142
21071
|
}
|
|
21143
21072
|
const prev = readLastStable();
|
|
21144
21073
|
if (prev) {
|
|
21145
21074
|
if (!quiet) {
|
|
21146
|
-
console.log(
|
|
21075
|
+
console.log(pc22.yellow(`Restoring to ${prev}\u2026`));
|
|
21147
21076
|
}
|
|
21148
21077
|
const restoreResult = _exec(`npm install -g ${PACKAGE_NAME}@${prev}`);
|
|
21149
21078
|
if (restoreResult.exitCode !== 0) {
|
|
21150
21079
|
if (!quiet) {
|
|
21151
|
-
console.error(
|
|
21080
|
+
console.error(pc22.red(
|
|
21152
21081
|
`Restore also failed. Run: npm install -g ${PACKAGE_NAME}@${prev} manually.`
|
|
21153
21082
|
));
|
|
21154
21083
|
}
|
|
21155
21084
|
} else if (!quiet) {
|
|
21156
|
-
console.log(
|
|
21085
|
+
console.log(pc22.yellow(`Restored to ${prev}.`));
|
|
21157
21086
|
}
|
|
21158
21087
|
} else if (!quiet) {
|
|
21159
|
-
console.error(
|
|
21088
|
+
console.error(pc22.red("No previous version cached; cannot auto-restore."));
|
|
21160
21089
|
}
|
|
21161
21090
|
return { action: "restored", prevVersion: prev ?? void 0, exitCode: 11 };
|
|
21162
21091
|
}
|
|
21163
21092
|
const newVersion = getCurrentVersion(_exec) ?? void 0;
|
|
21164
21093
|
if (!quiet && newVersion) {
|
|
21165
|
-
console.log(
|
|
21094
|
+
console.log(pc22.green(`Updated to ${newVersion}.`));
|
|
21166
21095
|
}
|
|
21167
21096
|
const npmRootResult = _getNpmRoot("npm root -g");
|
|
21168
21097
|
let symlinkResult = { added: [], removed: [] };
|
|
21169
21098
|
if (npmRootResult.exitCode === 0) {
|
|
21170
21099
|
const npmRoot = npmRootResult.stdout.trim();
|
|
21171
|
-
const npmSkillsDir =
|
|
21172
|
-
const claudeSkillsDir =
|
|
21100
|
+
const npmSkillsDir = path40.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills");
|
|
21101
|
+
const claudeSkillsDir = path40.join(os22.homedir(), ".claude", "skills");
|
|
21173
21102
|
const rec = _reconcile(npmSkillsDir, claudeSkillsDir);
|
|
21174
21103
|
symlinkResult = { added: rec.added, removed: rec.removed };
|
|
21175
21104
|
if (!quiet && (rec.added.length > 0 || rec.removed.length > 0)) {
|
|
21176
21105
|
if (rec.added.length > 0) {
|
|
21177
|
-
console.log(
|
|
21106
|
+
console.log(pc22.dim(`Skills added: ${rec.added.join(", ")}`));
|
|
21178
21107
|
}
|
|
21179
21108
|
if (rec.removed.length > 0) {
|
|
21180
|
-
console.log(
|
|
21109
|
+
console.log(pc22.dim(`Skills removed (dangling): ${rec.removed.join(", ")}`));
|
|
21181
21110
|
}
|
|
21182
21111
|
}
|
|
21183
21112
|
}
|
|
@@ -21215,8 +21144,8 @@ async function doRollback(_exec = defaultExec, _reconcile = reconcileSkillSymlin
|
|
|
21215
21144
|
if (npmRootResult.exitCode === 0) {
|
|
21216
21145
|
const npmRoot = npmRootResult.stdout.trim();
|
|
21217
21146
|
_reconcile(
|
|
21218
|
-
|
|
21219
|
-
|
|
21147
|
+
path40.join(npmRoot, "@pleri", "olam-cli", "plugin", "skills"),
|
|
21148
|
+
path40.join(os22.homedir(), ".claude", "skills")
|
|
21220
21149
|
);
|
|
21221
21150
|
}
|
|
21222
21151
|
return { action: "rolled-back", restoredVersion: prev, exitCode: 0 };
|
|
@@ -21271,7 +21200,7 @@ function registerUpdate(program2) {
|
|
|
21271
21200
|
// src/commands/begin.ts
|
|
21272
21201
|
init_host_cp();
|
|
21273
21202
|
init_open_url();
|
|
21274
|
-
import
|
|
21203
|
+
import pc23 from "picocolors";
|
|
21275
21204
|
async function doBegin(opts, _startFn = startHostCp, _openFn = openUrl) {
|
|
21276
21205
|
const prevExitCode = process.exitCode;
|
|
21277
21206
|
await _startFn({ showToken: opts.showToken });
|
|
@@ -21281,7 +21210,7 @@ async function doBegin(opts, _startFn = startHostCp, _openFn = openUrl) {
|
|
|
21281
21210
|
const token = readToken();
|
|
21282
21211
|
if (token) {
|
|
21283
21212
|
const base = `http://127.0.0.1:${HOST_CP_PORT}/`;
|
|
21284
|
-
console.log(
|
|
21213
|
+
console.log(pc23.dim(`Opening ${base}`));
|
|
21285
21214
|
_openFn(`${base}?token=${token}`);
|
|
21286
21215
|
}
|
|
21287
21216
|
}
|
|
@@ -21377,8 +21306,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
|
|
|
21377
21306
|
function authHeaders() {
|
|
21378
21307
|
return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
|
|
21379
21308
|
}
|
|
21380
|
-
async function apiFetch(
|
|
21381
|
-
const res = await fetch(`${BASE_URL}${
|
|
21309
|
+
async function apiFetch(path44, init = {}) {
|
|
21310
|
+
const res = await fetch(`${BASE_URL}${path44}`, {
|
|
21382
21311
|
...init,
|
|
21383
21312
|
headers: {
|
|
21384
21313
|
"Content-Type": "application/json",
|
|
@@ -21530,7 +21459,7 @@ function registerMcpAdd(cmd) {
|
|
|
21530
21459
|
|
|
21531
21460
|
// src/commands/mcp/list.ts
|
|
21532
21461
|
init_output();
|
|
21533
|
-
import
|
|
21462
|
+
import pc24 from "picocolors";
|
|
21534
21463
|
function registerMcpList(cmd) {
|
|
21535
21464
|
cmd.command("list").description("List all registered MCP credentials").action(async () => {
|
|
21536
21465
|
const client = getMcpAuthClient();
|
|
@@ -21545,8 +21474,8 @@ function registerMcpList(cmd) {
|
|
|
21545
21474
|
}
|
|
21546
21475
|
const mcps = data.mcps ?? [];
|
|
21547
21476
|
if (mcps.length === 0) {
|
|
21548
|
-
console.log(
|
|
21549
|
-
console.log(
|
|
21477
|
+
console.log(pc24.dim("No MCP credentials registered."));
|
|
21478
|
+
console.log(pc24.dim("Add one with: olam mcp add <service>"));
|
|
21550
21479
|
return;
|
|
21551
21480
|
}
|
|
21552
21481
|
const [c0, c1, c2, c3] = [16, 20, 10, 24];
|
|
@@ -21557,12 +21486,12 @@ function registerMcpList(cmd) {
|
|
|
21557
21486
|
"ENV VAR".padEnd(c3),
|
|
21558
21487
|
"STATUS"
|
|
21559
21488
|
].join(" ");
|
|
21560
|
-
console.log(
|
|
21561
|
-
console.log(
|
|
21489
|
+
console.log(pc24.dim(header));
|
|
21490
|
+
console.log(pc24.dim("\u2500".repeat(header.length)));
|
|
21562
21491
|
for (const m of mcps) {
|
|
21563
|
-
const status = !m.validated ?
|
|
21492
|
+
const status = !m.validated ? pc24.yellow("unvalidated") : m.expired ? pc24.red("expired") : pc24.green("active");
|
|
21564
21493
|
const row = [
|
|
21565
|
-
|
|
21494
|
+
pc24.cyan(m.service.padEnd(c0)),
|
|
21566
21495
|
m.label.padEnd(c1).slice(0, c1),
|
|
21567
21496
|
m.type.padEnd(c2),
|
|
21568
21497
|
(m.envName ?? "\u2014").padEnd(c3).slice(0, c3),
|
|
@@ -21590,13 +21519,13 @@ function registerMcpRemove(cmd) {
|
|
|
21590
21519
|
|
|
21591
21520
|
// src/commands/mcp/status.ts
|
|
21592
21521
|
init_output();
|
|
21593
|
-
import
|
|
21522
|
+
import pc25 from "picocolors";
|
|
21594
21523
|
function formatExpiry(expiresAt) {
|
|
21595
21524
|
if (!expiresAt) return "\u2014";
|
|
21596
21525
|
const ms = expiresAt - Date.now();
|
|
21597
|
-
if (ms <= 0) return
|
|
21526
|
+
if (ms <= 0) return pc25.red("expired");
|
|
21598
21527
|
const hours = ms / (1e3 * 60 * 60);
|
|
21599
|
-
if (hours < 1) return
|
|
21528
|
+
if (hours < 1) return pc25.yellow(`${Math.ceil(ms / 6e4)}m`);
|
|
21600
21529
|
return `${hours.toFixed(1)}h`;
|
|
21601
21530
|
}
|
|
21602
21531
|
function registerMcpStatus(cmd) {
|
|
@@ -21613,14 +21542,14 @@ function registerMcpStatus(cmd) {
|
|
|
21613
21542
|
const mcps = data.mcps ?? [];
|
|
21614
21543
|
printHeader(`MCP Credentials (${mcps.length})`);
|
|
21615
21544
|
if (mcps.length === 0) {
|
|
21616
|
-
console.log(
|
|
21545
|
+
console.log(pc25.dim("No credentials registered."));
|
|
21617
21546
|
return;
|
|
21618
21547
|
}
|
|
21619
21548
|
for (const m of mcps) {
|
|
21620
|
-
const stateColor = !m.validated ?
|
|
21549
|
+
const stateColor = !m.validated ? pc25.yellow : m.expired ? pc25.red : pc25.green;
|
|
21621
21550
|
const stateLabel = !m.validated ? "unvalidated" : m.expired ? "expired" : "active";
|
|
21622
21551
|
console.log(`
|
|
21623
|
-
${
|
|
21552
|
+
${pc25.cyan(m.service)} ${stateColor(`[${stateLabel}]`)}`);
|
|
21624
21553
|
console.log(` label: ${m.label}`);
|
|
21625
21554
|
console.log(` type: ${m.type}`);
|
|
21626
21555
|
if (m.envName) console.log(` env var: ${m.envName}`);
|
|
@@ -21635,15 +21564,15 @@ function registerMcpStatus(cmd) {
|
|
|
21635
21564
|
// src/commands/mcp/import.ts
|
|
21636
21565
|
init_output();
|
|
21637
21566
|
import * as readline3 from "node:readline";
|
|
21638
|
-
import
|
|
21567
|
+
import pc26 from "picocolors";
|
|
21639
21568
|
|
|
21640
21569
|
// src/commands/mcp/import-discovery.ts
|
|
21641
|
-
import * as
|
|
21570
|
+
import * as fs37 from "node:fs";
|
|
21642
21571
|
import * as os23 from "node:os";
|
|
21643
|
-
import * as
|
|
21572
|
+
import * as path41 from "node:path";
|
|
21644
21573
|
function readJsonFile(filePath) {
|
|
21645
21574
|
try {
|
|
21646
|
-
const raw =
|
|
21575
|
+
const raw = fs37.readFileSync(filePath, "utf-8");
|
|
21647
21576
|
return JSON.parse(raw);
|
|
21648
21577
|
} catch {
|
|
21649
21578
|
return null;
|
|
@@ -21672,24 +21601,24 @@ function extractMcpServers(obj, source, sourceLabel) {
|
|
|
21672
21601
|
}
|
|
21673
21602
|
function getClaudeDesktopPath() {
|
|
21674
21603
|
if (process.platform === "darwin") {
|
|
21675
|
-
return
|
|
21604
|
+
return path41.join(os23.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
21676
21605
|
}
|
|
21677
21606
|
if (process.platform === "win32") {
|
|
21678
|
-
const appData = process.env["APPDATA"] ??
|
|
21679
|
-
return
|
|
21607
|
+
const appData = process.env["APPDATA"] ?? path41.join(os23.homedir(), "AppData", "Roaming");
|
|
21608
|
+
return path41.join(appData, "Claude", "claude_desktop_config.json");
|
|
21680
21609
|
}
|
|
21681
|
-
return
|
|
21610
|
+
return path41.join(os23.homedir(), ".config", "Claude", "claude_desktop_config.json");
|
|
21682
21611
|
}
|
|
21683
21612
|
function getOlamRepoPaths() {
|
|
21684
21613
|
const configPaths = [
|
|
21685
|
-
|
|
21686
|
-
|
|
21614
|
+
path41.join(os23.homedir(), ".olam", "config.yaml"),
|
|
21615
|
+
path41.join(process.cwd(), ".olam", "config.yaml")
|
|
21687
21616
|
];
|
|
21688
21617
|
const paths = [];
|
|
21689
21618
|
for (const configPath of configPaths) {
|
|
21690
|
-
if (!
|
|
21619
|
+
if (!fs37.existsSync(configPath)) continue;
|
|
21691
21620
|
try {
|
|
21692
|
-
const raw =
|
|
21621
|
+
const raw = fs37.readFileSync(configPath, "utf-8");
|
|
21693
21622
|
const repoMatches = [...raw.matchAll(/path:\s*["']?([^\s"'\n]+)/g)];
|
|
21694
21623
|
for (const m of repoMatches) {
|
|
21695
21624
|
if (m[1]) paths.push(m[1]);
|
|
@@ -21705,7 +21634,7 @@ async function discoverMcpSources(repoPaths) {
|
|
|
21705
21634
|
const sources = [];
|
|
21706
21635
|
const sourceDefs = [
|
|
21707
21636
|
{
|
|
21708
|
-
path:
|
|
21637
|
+
path: path41.join(os23.homedir(), ".claude.json"),
|
|
21709
21638
|
label: "Claude Code (~/.claude.json)"
|
|
21710
21639
|
},
|
|
21711
21640
|
{
|
|
@@ -21713,19 +21642,19 @@ async function discoverMcpSources(repoPaths) {
|
|
|
21713
21642
|
label: "Claude Desktop"
|
|
21714
21643
|
},
|
|
21715
21644
|
{
|
|
21716
|
-
path:
|
|
21645
|
+
path: path41.join(os23.homedir(), ".cursor", "mcp.json"),
|
|
21717
21646
|
label: "Cursor (~/.cursor/mcp.json)"
|
|
21718
21647
|
},
|
|
21719
21648
|
{
|
|
21720
|
-
path:
|
|
21649
|
+
path: path41.join(os23.homedir(), ".codeium", "windsurf", "mcp_config.json"),
|
|
21721
21650
|
label: "Windsurf (~/.codeium/windsurf/mcp_config.json)"
|
|
21722
21651
|
}
|
|
21723
21652
|
];
|
|
21724
21653
|
const resolvedRepoPaths = repoPaths ?? getOlamRepoPaths();
|
|
21725
21654
|
for (const repoPath of resolvedRepoPaths) {
|
|
21726
21655
|
sourceDefs.push({
|
|
21727
|
-
path:
|
|
21728
|
-
label: `.mcp.json (${
|
|
21656
|
+
path: path41.join(repoPath, ".mcp.json"),
|
|
21657
|
+
label: `.mcp.json (${path41.basename(repoPath)})`
|
|
21729
21658
|
});
|
|
21730
21659
|
}
|
|
21731
21660
|
const reads = await Promise.all(
|
|
@@ -21805,13 +21734,13 @@ async function validateMcpEntry(entry) {
|
|
|
21805
21734
|
// src/commands/mcp/import.ts
|
|
21806
21735
|
async function multiSelectPicker(entries) {
|
|
21807
21736
|
if (entries.length === 0) return [];
|
|
21808
|
-
console.log("\n" +
|
|
21737
|
+
console.log("\n" + pc26.bold("Discovered MCP servers:"));
|
|
21809
21738
|
entries.forEach((e, i) => {
|
|
21810
21739
|
console.log(
|
|
21811
|
-
` ${
|
|
21740
|
+
` ${pc26.dim(`[${i + 1}]`)} ${pc26.cyan(e.name.padEnd(20))} ${pc26.dim(e.sourceLabel)}`
|
|
21812
21741
|
);
|
|
21813
21742
|
});
|
|
21814
|
-
console.log("\n" +
|
|
21743
|
+
console.log("\n" + pc26.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
|
|
21815
21744
|
const answer = await new Promise((resolve8) => {
|
|
21816
21745
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
21817
21746
|
rl.question("> ", (ans) => {
|
|
@@ -21838,7 +21767,7 @@ function registerMcpImport(cmd) {
|
|
|
21838
21767
|
const repoPaths = opts.repoPaths ? opts.repoPaths.split(",").map((s) => s.trim()) : void 0;
|
|
21839
21768
|
const { entries, sources, durationMs } = await discoverMcpSources(repoPaths);
|
|
21840
21769
|
if (entries.length === 0) {
|
|
21841
|
-
console.log(
|
|
21770
|
+
console.log(pc26.dim("No MCP servers found in any source path."));
|
|
21842
21771
|
return;
|
|
21843
21772
|
}
|
|
21844
21773
|
printInfo("Sources", sources.length > 0 ? sources.join(", ") : "none");
|
|
@@ -21851,15 +21780,15 @@ function registerMcpImport(cmd) {
|
|
|
21851
21780
|
candidates = filtered;
|
|
21852
21781
|
}
|
|
21853
21782
|
if (skippedCount > 0) {
|
|
21854
|
-
console.log(
|
|
21783
|
+
console.log(pc26.dim(`skipped: ${skippedCount} already registered`));
|
|
21855
21784
|
}
|
|
21856
21785
|
if (candidates.length === 0) {
|
|
21857
|
-
console.log(
|
|
21786
|
+
console.log(pc26.dim("Nothing new to import. Use --reimport to force."));
|
|
21858
21787
|
return;
|
|
21859
21788
|
}
|
|
21860
21789
|
const selected = await multiSelectPicker(candidates);
|
|
21861
21790
|
if (selected.length === 0) {
|
|
21862
|
-
console.log(
|
|
21791
|
+
console.log(pc26.dim("No servers selected."));
|
|
21863
21792
|
return;
|
|
21864
21793
|
}
|
|
21865
21794
|
console.log(`
|
|
@@ -21870,16 +21799,16 @@ Importing ${selected.length} server(s)\u2026`);
|
|
|
21870
21799
|
let validated = false;
|
|
21871
21800
|
let validationReason = "skipped";
|
|
21872
21801
|
if (opts.validate !== false) {
|
|
21873
|
-
process.stdout.write(` ${
|
|
21802
|
+
process.stdout.write(` ${pc26.dim("\u2192")} ${entry.name} validating\u2026 `);
|
|
21874
21803
|
const vr = await validateMcpEntry(entry);
|
|
21875
21804
|
validated = vr.validated;
|
|
21876
21805
|
validationReason = vr.reason;
|
|
21877
21806
|
process.stdout.write(
|
|
21878
|
-
validated ?
|
|
21807
|
+
validated ? pc26.green("ok\n") : pc26.yellow(`unvalidated (${vr.reason})
|
|
21879
21808
|
`)
|
|
21880
21809
|
);
|
|
21881
21810
|
} else {
|
|
21882
|
-
console.log(` ${
|
|
21811
|
+
console.log(` ${pc26.dim("\u2192")} ${entry.name} ${pc26.dim("(validation skipped)")}`);
|
|
21883
21812
|
}
|
|
21884
21813
|
if (validated) validatedCount++;
|
|
21885
21814
|
const result = await client.staticAdd({
|
|
@@ -21894,21 +21823,21 @@ Importing ${selected.length} server(s)\u2026`);
|
|
|
21894
21823
|
}
|
|
21895
21824
|
}
|
|
21896
21825
|
console.log("");
|
|
21897
|
-
console.log(
|
|
21826
|
+
console.log(pc26.green(`\u2713 Imported ${importedCount}/${selected.length}`));
|
|
21898
21827
|
if (validatedCount > 0) {
|
|
21899
|
-
console.log(
|
|
21828
|
+
console.log(pc26.dim(` ${validatedCount} validated, ${importedCount - validatedCount} unvalidated`));
|
|
21900
21829
|
}
|
|
21901
21830
|
});
|
|
21902
21831
|
}
|
|
21903
21832
|
|
|
21904
21833
|
// src/commands/mcp/revoke.ts
|
|
21905
21834
|
init_output();
|
|
21906
|
-
import
|
|
21835
|
+
import pc27 from "picocolors";
|
|
21907
21836
|
function registerMcpRevoke(cmd) {
|
|
21908
21837
|
cmd.command("revoke <user> <world> <service>").description("Revoke a user's MCP service entitlement (multi-tenant mode only)").action(async (user, world, service) => {
|
|
21909
21838
|
const multiTenant = (process.env["OLAM_MCP_MULTI_TENANT"] ?? "").toLowerCase() === "true";
|
|
21910
21839
|
if (!multiTenant) {
|
|
21911
|
-
console.warn(
|
|
21840
|
+
console.warn(pc27.yellow("\u26A0 revocation only meaningful in multi_tenant mode \u2014 no-op"));
|
|
21912
21841
|
return;
|
|
21913
21842
|
}
|
|
21914
21843
|
const baseUrl = process.env["OLAM_MCP_AUTH_SERVICE_URL"] ?? "http://127.0.0.1:9998";
|
|
@@ -21937,8 +21866,8 @@ function registerMcpRevoke(cmd) {
|
|
|
21937
21866
|
process.exitCode = 1;
|
|
21938
21867
|
return;
|
|
21939
21868
|
}
|
|
21940
|
-
console.log(
|
|
21941
|
-
console.log(
|
|
21869
|
+
console.log(pc27.green(`\u2713 Revoked: ${user} / ${world} / ${service}`));
|
|
21870
|
+
console.log(pc27.dim(" Next fetch-creds call returns 403; token cleared on next merge."));
|
|
21942
21871
|
});
|
|
21943
21872
|
}
|
|
21944
21873
|
|
|
@@ -21955,18 +21884,18 @@ function registerMcp(program2) {
|
|
|
21955
21884
|
}
|
|
21956
21885
|
|
|
21957
21886
|
// src/pleri-config.ts
|
|
21958
|
-
import * as
|
|
21959
|
-
import * as
|
|
21887
|
+
import * as fs38 from "node:fs";
|
|
21888
|
+
import * as path42 from "node:path";
|
|
21960
21889
|
function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
|
|
21961
21890
|
if (process.env.PLERI_BASE_URL) {
|
|
21962
21891
|
return true;
|
|
21963
21892
|
}
|
|
21964
|
-
const configPath =
|
|
21965
|
-
if (!
|
|
21893
|
+
const configPath = path42.join(configDir, "config.yaml");
|
|
21894
|
+
if (!fs38.existsSync(configPath)) {
|
|
21966
21895
|
return false;
|
|
21967
21896
|
}
|
|
21968
21897
|
try {
|
|
21969
|
-
const contents =
|
|
21898
|
+
const contents = fs38.readFileSync(configPath, "utf8");
|
|
21970
21899
|
return /^[^#\n]*\bpleri:/m.test(contents);
|
|
21971
21900
|
} catch {
|
|
21972
21901
|
return false;
|
|
@@ -21977,14 +21906,14 @@ function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
|
|
|
21977
21906
|
var program = new Command();
|
|
21978
21907
|
function readCliVersion() {
|
|
21979
21908
|
try {
|
|
21980
|
-
const here =
|
|
21909
|
+
const here = path43.dirname(fileURLToPath4(import.meta.url));
|
|
21981
21910
|
for (const candidate of [
|
|
21982
|
-
|
|
21983
|
-
|
|
21984
|
-
|
|
21911
|
+
path43.join(here, "package.json"),
|
|
21912
|
+
path43.join(here, "..", "package.json"),
|
|
21913
|
+
path43.join(here, "..", "..", "package.json")
|
|
21985
21914
|
]) {
|
|
21986
|
-
if (
|
|
21987
|
-
const pkg = JSON.parse(
|
|
21915
|
+
if (fs39.existsSync(candidate)) {
|
|
21916
|
+
const pkg = JSON.parse(fs39.readFileSync(candidate, "utf-8"));
|
|
21988
21917
|
if (typeof pkg.version === "string" && pkg.version.length > 0) return pkg.version;
|
|
21989
21918
|
}
|
|
21990
21919
|
}
|
|
@@ -22023,4 +21952,5 @@ registerBegin(program);
|
|
|
22023
21952
|
registerStop(program);
|
|
22024
21953
|
registerWorldUpgrade(program);
|
|
22025
21954
|
registerMcp(program);
|
|
21955
|
+
registerServices(program);
|
|
22026
21956
|
program.parse();
|