@pleri/olam-cli 0.1.65 → 0.1.68
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__/config.test.d.ts +2 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +95 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +53 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/repos.d.ts +11 -0
- package/dist/commands/repos.d.ts.map +1 -0
- package/dist/commands/repos.js +92 -0
- package/dist/commands/repos.js.map +1 -0
- package/dist/image-digests.json +3 -3
- package/dist/index.js +407 -118
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +453 -172
- package/host-cp/src/pr-nanny.mjs +284 -0
- package/host-cp/src/server.mjs +67 -0
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -3228,8 +3228,8 @@ var require_utils = __commonJS({
|
|
|
3228
3228
|
}
|
|
3229
3229
|
return ind;
|
|
3230
3230
|
}
|
|
3231
|
-
function removeDotSegments(
|
|
3232
|
-
let input =
|
|
3231
|
+
function removeDotSegments(path23) {
|
|
3232
|
+
let input = path23;
|
|
3233
3233
|
const output = [];
|
|
3234
3234
|
let nextSlash = -1;
|
|
3235
3235
|
let len = 0;
|
|
@@ -3428,8 +3428,8 @@ var require_schemes = __commonJS({
|
|
|
3428
3428
|
wsComponent.secure = void 0;
|
|
3429
3429
|
}
|
|
3430
3430
|
if (wsComponent.resourceName) {
|
|
3431
|
-
const [
|
|
3432
|
-
wsComponent.path =
|
|
3431
|
+
const [path23, query] = wsComponent.resourceName.split("?");
|
|
3432
|
+
wsComponent.path = path23 && path23 !== "/" ? path23 : void 0;
|
|
3433
3433
|
wsComponent.query = query;
|
|
3434
3434
|
wsComponent.resourceName = void 0;
|
|
3435
3435
|
}
|
|
@@ -6791,12 +6791,12 @@ var require_dist = __commonJS({
|
|
|
6791
6791
|
throw new Error(`Unknown format "${name}"`);
|
|
6792
6792
|
return f;
|
|
6793
6793
|
};
|
|
6794
|
-
function addFormats(ajv, list,
|
|
6794
|
+
function addFormats(ajv, list, fs19, exportName) {
|
|
6795
6795
|
var _a;
|
|
6796
6796
|
var _b;
|
|
6797
6797
|
(_a = (_b = ajv.opts.code).formats) !== null && _a !== void 0 ? _a : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
6798
6798
|
for (const f of list)
|
|
6799
|
-
ajv.addFormat(f,
|
|
6799
|
+
ajv.addFormat(f, fs19[f]);
|
|
6800
6800
|
}
|
|
6801
6801
|
module.exports = exports = formatsPlugin;
|
|
6802
6802
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -7002,10 +7002,10 @@ function assignProp(target, prop, value) {
|
|
|
7002
7002
|
configurable: true
|
|
7003
7003
|
});
|
|
7004
7004
|
}
|
|
7005
|
-
function getElementAtPath(obj,
|
|
7006
|
-
if (!
|
|
7005
|
+
function getElementAtPath(obj, path23) {
|
|
7006
|
+
if (!path23)
|
|
7007
7007
|
return obj;
|
|
7008
|
-
return
|
|
7008
|
+
return path23.reduce((acc, key) => acc?.[key], obj);
|
|
7009
7009
|
}
|
|
7010
7010
|
function promiseAllObject(promisesObj) {
|
|
7011
7011
|
const keys = Object.keys(promisesObj);
|
|
@@ -7325,11 +7325,11 @@ function aborted(x, startIndex = 0) {
|
|
|
7325
7325
|
}
|
|
7326
7326
|
return false;
|
|
7327
7327
|
}
|
|
7328
|
-
function prefixIssues(
|
|
7328
|
+
function prefixIssues(path23, issues) {
|
|
7329
7329
|
return issues.map((iss) => {
|
|
7330
7330
|
var _a;
|
|
7331
7331
|
(_a = iss).path ?? (_a.path = []);
|
|
7332
|
-
iss.path.unshift(
|
|
7332
|
+
iss.path.unshift(path23);
|
|
7333
7333
|
return iss;
|
|
7334
7334
|
});
|
|
7335
7335
|
}
|
|
@@ -13403,8 +13403,8 @@ function getErrorMap() {
|
|
|
13403
13403
|
|
|
13404
13404
|
// ../../node_modules/zod/v3/helpers/parseUtil.js
|
|
13405
13405
|
var makeIssue = (params) => {
|
|
13406
|
-
const { data, path:
|
|
13407
|
-
const fullPath = [...
|
|
13406
|
+
const { data, path: path23, errorMaps, issueData } = params;
|
|
13407
|
+
const fullPath = [...path23, ...issueData.path || []];
|
|
13408
13408
|
const fullIssue = {
|
|
13409
13409
|
...issueData,
|
|
13410
13410
|
path: fullPath
|
|
@@ -13520,11 +13520,11 @@ var errorUtil;
|
|
|
13520
13520
|
|
|
13521
13521
|
// ../../node_modules/zod/v3/types.js
|
|
13522
13522
|
var ParseInputLazyPath = class {
|
|
13523
|
-
constructor(parent, value,
|
|
13523
|
+
constructor(parent, value, path23, key) {
|
|
13524
13524
|
this._cachedPath = [];
|
|
13525
13525
|
this.parent = parent;
|
|
13526
13526
|
this.data = value;
|
|
13527
|
-
this._path =
|
|
13527
|
+
this._path = path23;
|
|
13528
13528
|
this._key = key;
|
|
13529
13529
|
}
|
|
13530
13530
|
get path() {
|
|
@@ -21365,8 +21365,8 @@ var AuthClient = class {
|
|
|
21365
21365
|
throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
|
|
21366
21366
|
}
|
|
21367
21367
|
}
|
|
21368
|
-
async request(method,
|
|
21369
|
-
const url = `${this.baseUrl}${
|
|
21368
|
+
async request(method, path23, body, attempt = 0) {
|
|
21369
|
+
const url = `${this.baseUrl}${path23}`;
|
|
21370
21370
|
const controller = new AbortController();
|
|
21371
21371
|
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
21372
21372
|
const headers = {};
|
|
@@ -21384,7 +21384,7 @@ var AuthClient = class {
|
|
|
21384
21384
|
} catch (err) {
|
|
21385
21385
|
if (attempt < RETRY_COUNT && isTransient(err)) {
|
|
21386
21386
|
await sleep(RETRY_BACKOFF_MS * (attempt + 1));
|
|
21387
|
-
return this.request(method,
|
|
21387
|
+
return this.request(method, path23, body, attempt + 1);
|
|
21388
21388
|
}
|
|
21389
21389
|
throw err;
|
|
21390
21390
|
} finally {
|
|
@@ -22191,12 +22191,12 @@ function register3(server, _ctx, _initError) {
|
|
|
22191
22191
|
registry2.close();
|
|
22192
22192
|
}
|
|
22193
22193
|
try {
|
|
22194
|
-
const { default:
|
|
22195
|
-
const { default:
|
|
22196
|
-
const { default:
|
|
22197
|
-
const tokenPath =
|
|
22198
|
-
if (
|
|
22199
|
-
const token =
|
|
22194
|
+
const { default: fs19 } = await import("node:fs");
|
|
22195
|
+
const { default: os12 } = await import("node:os");
|
|
22196
|
+
const { default: path23 } = await import("node:path");
|
|
22197
|
+
const tokenPath = path23.join(os12.homedir(), ".olam", "host-cp.token");
|
|
22198
|
+
if (fs19.existsSync(tokenPath)) {
|
|
22199
|
+
const token = fs19.readFileSync(tokenPath, "utf-8").trim();
|
|
22200
22200
|
await fetch("http://127.0.0.1:19000/api/admin/world-pr", {
|
|
22201
22201
|
method: "POST",
|
|
22202
22202
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
|
|
@@ -22389,7 +22389,7 @@ var KNOWN_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
22389
22389
|
"deploy"
|
|
22390
22390
|
]);
|
|
22391
22391
|
var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
22392
|
-
function refineForbiddenKeys(value,
|
|
22392
|
+
function refineForbiddenKeys(value, path23, ctx, rejectSource) {
|
|
22393
22393
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
22394
22394
|
return;
|
|
22395
22395
|
}
|
|
@@ -22397,12 +22397,12 @@ function refineForbiddenKeys(value, path21, ctx, rejectSource) {
|
|
|
22397
22397
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
22398
22398
|
ctx.addIssue({
|
|
22399
22399
|
code: external_exports.ZodIssueCode.custom,
|
|
22400
|
-
path: [...
|
|
22400
|
+
path: [...path23, key],
|
|
22401
22401
|
message: `forbidden key "${key}" (prototype-pollution surface)`
|
|
22402
22402
|
});
|
|
22403
22403
|
continue;
|
|
22404
22404
|
}
|
|
22405
|
-
if (rejectSource &&
|
|
22405
|
+
if (rejectSource && path23.length === 0 && key === "source") {
|
|
22406
22406
|
ctx.addIssue({
|
|
22407
22407
|
code: external_exports.ZodIssueCode.custom,
|
|
22408
22408
|
path: ["source"],
|
|
@@ -22410,21 +22410,21 @@ function refineForbiddenKeys(value, path21, ctx, rejectSource) {
|
|
|
22410
22410
|
});
|
|
22411
22411
|
continue;
|
|
22412
22412
|
}
|
|
22413
|
-
refineForbiddenKeys(value[key], [...
|
|
22413
|
+
refineForbiddenKeys(value[key], [...path23, key], ctx, false);
|
|
22414
22414
|
}
|
|
22415
22415
|
}
|
|
22416
|
-
function rejectForbiddenKeys(value,
|
|
22416
|
+
function rejectForbiddenKeys(value, path23, rejectSource) {
|
|
22417
22417
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
22418
22418
|
return;
|
|
22419
22419
|
}
|
|
22420
22420
|
for (const key of Object.keys(value)) {
|
|
22421
22421
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
22422
|
-
throw new Error(`[manifest] ${
|
|
22422
|
+
throw new Error(`[manifest] ${path23}: forbidden key "${key}" (prototype-pollution surface)`);
|
|
22423
22423
|
}
|
|
22424
22424
|
if (rejectSource && key === "source") {
|
|
22425
|
-
throw new Error(`[manifest] ${
|
|
22425
|
+
throw new Error(`[manifest] ${path23}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
|
|
22426
22426
|
}
|
|
22427
|
-
rejectForbiddenKeys(value[key], `${
|
|
22427
|
+
rejectForbiddenKeys(value[key], `${path23}.${key}`, false);
|
|
22428
22428
|
}
|
|
22429
22429
|
}
|
|
22430
22430
|
function unknownTopLevelKeys(parsed) {
|
|
@@ -22862,10 +22862,10 @@ function extractMcpConfig(claudeJsonPath) {
|
|
|
22862
22862
|
}
|
|
22863
22863
|
return { mcpServers, secrets };
|
|
22864
22864
|
}
|
|
22865
|
-
function readOptional(
|
|
22866
|
-
if (!existsSync6(
|
|
22865
|
+
function readOptional(path23) {
|
|
22866
|
+
if (!existsSync6(path23)) return null;
|
|
22867
22867
|
try {
|
|
22868
|
-
return readFileSync5(
|
|
22868
|
+
return readFileSync5(path23, "utf8");
|
|
22869
22869
|
} catch {
|
|
22870
22870
|
return null;
|
|
22871
22871
|
}
|
|
@@ -24008,8 +24008,8 @@ var CloudflareProvider = class extends ComputeProvider {
|
|
|
24008
24008
|
// -----------------------------------------------------------------------
|
|
24009
24009
|
// Internal fetch helper
|
|
24010
24010
|
// -----------------------------------------------------------------------
|
|
24011
|
-
async request(
|
|
24012
|
-
const url = `${this.config.workerUrl}${
|
|
24011
|
+
async request(path23, method, body) {
|
|
24012
|
+
const url = `${this.config.workerUrl}${path23}`;
|
|
24013
24013
|
const bearer = await this.config.mintToken();
|
|
24014
24014
|
const headers = {
|
|
24015
24015
|
Authorization: `Bearer ${bearer}`
|
|
@@ -26442,10 +26442,10 @@ async function writeManifest(args) {
|
|
|
26442
26442
|
capturedAt: args.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
26443
26443
|
shots: entries
|
|
26444
26444
|
};
|
|
26445
|
-
const
|
|
26446
|
-
await writeFile(
|
|
26445
|
+
const path23 = join12(args.outDir, "manifest.json");
|
|
26446
|
+
await writeFile(path23, `${JSON.stringify(manifest, null, 2)}
|
|
26447
26447
|
`, "utf8");
|
|
26448
|
-
return { path:
|
|
26448
|
+
return { path: path23, manifest };
|
|
26449
26449
|
}
|
|
26450
26450
|
|
|
26451
26451
|
// ../mcp-server/src/tools/_capture/proxy.ts
|
|
@@ -26699,9 +26699,9 @@ async function startProxy(opts) {
|
|
|
26699
26699
|
const liveCompiled = verified.allowedPaths.map(compileGlob);
|
|
26700
26700
|
const target = parseRequestTarget(req);
|
|
26701
26701
|
if (!target) return httpReject(400, "invalid_target");
|
|
26702
|
-
const
|
|
26703
|
-
if (!liveCompiled.some((re) => re.test(
|
|
26704
|
-
return httpReject(403, "outside_allow_list", { path:
|
|
26702
|
+
const path23 = target.pathname;
|
|
26703
|
+
if (!liveCompiled.some((re) => re.test(path23))) {
|
|
26704
|
+
return httpReject(403, "outside_allow_list", { path: path23 });
|
|
26705
26705
|
}
|
|
26706
26706
|
const headerWorld = req.headers[WORLD_ASSERT_HEADER];
|
|
26707
26707
|
const headerWorldStr = typeof headerWorld === "string" ? headerWorld : Array.isArray(headerWorld) && headerWorld.length > 0 ? headerWorld[0] : void 0;
|
|
@@ -27480,14 +27480,14 @@ async function runShot(browser, shot, outDir, format, jpegQuality, allowEval, as
|
|
|
27480
27480
|
await page.waitForTimeout(shot.afterLoadMs);
|
|
27481
27481
|
}
|
|
27482
27482
|
const ext = format === "jpeg" ? "jpg" : "png";
|
|
27483
|
-
const
|
|
27483
|
+
const path23 = join13(outDir, `${shot.name}.${ext}`);
|
|
27484
27484
|
await page.screenshot({
|
|
27485
|
-
path:
|
|
27485
|
+
path: path23,
|
|
27486
27486
|
type: format,
|
|
27487
27487
|
...format === "jpeg" ? { quality: jpegQuality } : {},
|
|
27488
27488
|
fullPage: false
|
|
27489
27489
|
});
|
|
27490
|
-
return { name: shot.name, path:
|
|
27490
|
+
return { name: shot.name, path: path23, urlRedacted: redactUrl(shot.url), viewport };
|
|
27491
27491
|
} finally {
|
|
27492
27492
|
await context.close();
|
|
27493
27493
|
}
|
|
@@ -27930,12 +27930,12 @@ function openUrl(url) {
|
|
|
27930
27930
|
var HOST_CP_URL = "http://127.0.0.1:19000";
|
|
27931
27931
|
async function readHostCpToken2() {
|
|
27932
27932
|
try {
|
|
27933
|
-
const { default:
|
|
27934
|
-
const { default:
|
|
27935
|
-
const { default:
|
|
27936
|
-
const tp =
|
|
27937
|
-
if (!
|
|
27938
|
-
return { token:
|
|
27933
|
+
const { default: fs19 } = await import("node:fs");
|
|
27934
|
+
const { default: os12 } = await import("node:os");
|
|
27935
|
+
const { default: path23 } = await import("node:path");
|
|
27936
|
+
const tp = path23.join(os12.homedir(), ".olam", "host-cp.token");
|
|
27937
|
+
if (!fs19.existsSync(tp)) return { token: null };
|
|
27938
|
+
return { token: fs19.readFileSync(tp, "utf-8").trim() };
|
|
27939
27939
|
} catch {
|
|
27940
27940
|
return { token: null };
|
|
27941
27941
|
}
|
|
@@ -28161,6 +28161,286 @@ function register21(server, ctx, initError) {
|
|
|
28161
28161
|
);
|
|
28162
28162
|
}
|
|
28163
28163
|
|
|
28164
|
+
// ../mcp-server/src/tools/repo.ts
|
|
28165
|
+
var repo_exports = {};
|
|
28166
|
+
__export(repo_exports, {
|
|
28167
|
+
register: () => register22
|
|
28168
|
+
});
|
|
28169
|
+
|
|
28170
|
+
// ../core/dist/global-config/schema.js
|
|
28171
|
+
function isAbsoluteOrTilde(p) {
|
|
28172
|
+
return p.startsWith("/") || p === "~" || p.startsWith("~/");
|
|
28173
|
+
}
|
|
28174
|
+
function hasNoTraversalComponents(p) {
|
|
28175
|
+
return !p.split("/").some((seg) => seg === "..");
|
|
28176
|
+
}
|
|
28177
|
+
var RepoEntrySchema = external_exports.object({
|
|
28178
|
+
name: external_exports.string().regex(REPO_NAME_PATTERN, "repo name must be ASCII lowercase + digits + dash (1-64 chars, no leading/trailing dash)"),
|
|
28179
|
+
path: external_exports.string().min(1, "path must not be empty").refine(isAbsoluteOrTilde, {
|
|
28180
|
+
message: `path must be absolute (e.g. "/home/user/atlas-core") or "~/..." for the operator's home directory`
|
|
28181
|
+
}).refine(hasNoTraversalComponents, { message: 'path must not contain ".." components' }),
|
|
28182
|
+
description: external_exports.string().optional(),
|
|
28183
|
+
defaultBranch: external_exports.string().optional(),
|
|
28184
|
+
addedAt: external_exports.number().int().nonnegative(),
|
|
28185
|
+
updatedAt: external_exports.number().int().nonnegative()
|
|
28186
|
+
});
|
|
28187
|
+
var PortMapSchema = external_exports.record(external_exports.string().min(1), external_exports.number().int().min(1024).max(65535));
|
|
28188
|
+
var SeedSqlFileSchema = external_exports.object({
|
|
28189
|
+
type: external_exports.literal("sql-file"),
|
|
28190
|
+
repo: external_exports.string().min(1),
|
|
28191
|
+
service: external_exports.string().min(1),
|
|
28192
|
+
path: external_exports.string().min(1)
|
|
28193
|
+
});
|
|
28194
|
+
var SeedCommandSchema = external_exports.object({
|
|
28195
|
+
type: external_exports.literal("command"),
|
|
28196
|
+
repo: external_exports.string().min(1),
|
|
28197
|
+
run: external_exports.string().min(1)
|
|
28198
|
+
});
|
|
28199
|
+
var SeedFixtureCopySchema = external_exports.object({
|
|
28200
|
+
type: external_exports.literal("fixture-copy"),
|
|
28201
|
+
repo: external_exports.string().min(1),
|
|
28202
|
+
src: external_exports.string().min(1),
|
|
28203
|
+
dest: external_exports.string().min(1)
|
|
28204
|
+
});
|
|
28205
|
+
var SeedSchema = external_exports.discriminatedUnion("type", [
|
|
28206
|
+
SeedSqlFileSchema,
|
|
28207
|
+
SeedCommandSchema,
|
|
28208
|
+
SeedFixtureCopySchema
|
|
28209
|
+
]);
|
|
28210
|
+
var RunbookSchema = external_exports.object({
|
|
28211
|
+
name: external_exports.string().regex(WORKSPACE_NAME_PATTERN, "runbook name must be ASCII lowercase + digits + dash (1-64 chars, no leading/trailing dash)"),
|
|
28212
|
+
description: external_exports.string().optional(),
|
|
28213
|
+
repos: external_exports.array(external_exports.string().min(1)).min(1, "runbook must reference at least one repo"),
|
|
28214
|
+
portMap: external_exports.record(external_exports.string().min(1), PortMapSchema).optional(),
|
|
28215
|
+
seeds: external_exports.array(SeedSchema).optional(),
|
|
28216
|
+
env: external_exports.record(external_exports.string().min(1), external_exports.record(external_exports.string().min(1), external_exports.string())).optional(),
|
|
28217
|
+
updatedAt: external_exports.number().int().nonnegative()
|
|
28218
|
+
});
|
|
28219
|
+
var GlobalConfigSchema = external_exports.object({
|
|
28220
|
+
schemaVersion: external_exports.literal(1),
|
|
28221
|
+
repos: external_exports.array(RepoEntrySchema).optional().default([]),
|
|
28222
|
+
runbooks: external_exports.array(RunbookSchema).optional().default([])
|
|
28223
|
+
}).strip().superRefine((val, ctx) => {
|
|
28224
|
+
const repoNames = val.repos.map((r) => r.name);
|
|
28225
|
+
const repoDupes = repoNames.filter((n, i) => repoNames.indexOf(n) !== i);
|
|
28226
|
+
for (const d of repoDupes) {
|
|
28227
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: `duplicate repo name: "${d}"`, path: ["repos"] });
|
|
28228
|
+
}
|
|
28229
|
+
const rbNames = val.runbooks.map((r) => r.name);
|
|
28230
|
+
const rbDupes = rbNames.filter((n, i) => rbNames.indexOf(n) !== i);
|
|
28231
|
+
for (const d of rbDupes) {
|
|
28232
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: `duplicate runbook name: "${d}"`, path: ["runbooks"] });
|
|
28233
|
+
}
|
|
28234
|
+
});
|
|
28235
|
+
var DEFAULT_GLOBAL_CONFIG = {
|
|
28236
|
+
schemaVersion: 1,
|
|
28237
|
+
repos: [],
|
|
28238
|
+
runbooks: []
|
|
28239
|
+
};
|
|
28240
|
+
|
|
28241
|
+
// ../core/dist/global-config/store.js
|
|
28242
|
+
import * as fs8 from "node:fs";
|
|
28243
|
+
import * as os7 from "node:os";
|
|
28244
|
+
import * as path12 from "node:path";
|
|
28245
|
+
var GlobalConfigReadError = class extends Error {
|
|
28246
|
+
constructor(configPath, cause) {
|
|
28247
|
+
const msg = cause instanceof Error ? cause.message : String(cause);
|
|
28248
|
+
super(`Failed to read global config at ${configPath}: ${msg}. Run "olam config validate" to diagnose the issue.`);
|
|
28249
|
+
this.name = "GlobalConfigReadError";
|
|
28250
|
+
this.cause = cause;
|
|
28251
|
+
}
|
|
28252
|
+
};
|
|
28253
|
+
function globalConfigPath() {
|
|
28254
|
+
const override = process.env["OLAM_GLOBAL_CONFIG_PATH"];
|
|
28255
|
+
if (override && override.length > 0)
|
|
28256
|
+
return override;
|
|
28257
|
+
return path12.join(os7.homedir(), ".olam", "config.json");
|
|
28258
|
+
}
|
|
28259
|
+
function readGlobalConfig() {
|
|
28260
|
+
const configPath = globalConfigPath();
|
|
28261
|
+
if (!fs8.existsSync(configPath)) {
|
|
28262
|
+
return { ...DEFAULT_GLOBAL_CONFIG };
|
|
28263
|
+
}
|
|
28264
|
+
let raw;
|
|
28265
|
+
try {
|
|
28266
|
+
raw = fs8.readFileSync(configPath, "utf-8");
|
|
28267
|
+
} catch (err) {
|
|
28268
|
+
throw new GlobalConfigReadError(configPath, err);
|
|
28269
|
+
}
|
|
28270
|
+
let parsed;
|
|
28271
|
+
try {
|
|
28272
|
+
parsed = JSON.parse(raw);
|
|
28273
|
+
} catch (err) {
|
|
28274
|
+
throw new GlobalConfigReadError(configPath, err);
|
|
28275
|
+
}
|
|
28276
|
+
try {
|
|
28277
|
+
return GlobalConfigSchema.parse(parsed);
|
|
28278
|
+
} catch (err) {
|
|
28279
|
+
throw new GlobalConfigReadError(configPath, err);
|
|
28280
|
+
}
|
|
28281
|
+
}
|
|
28282
|
+
function writeGlobalConfig(config2) {
|
|
28283
|
+
const configPath = globalConfigPath();
|
|
28284
|
+
const validated = GlobalConfigSchema.parse(config2);
|
|
28285
|
+
const dir = path12.dirname(configPath);
|
|
28286
|
+
fs8.mkdirSync(dir, { recursive: true });
|
|
28287
|
+
const tmp = `${configPath}.tmp-${process.pid}`;
|
|
28288
|
+
fs8.writeFileSync(tmp, JSON.stringify(validated, null, 2) + "\n", { mode: 420 });
|
|
28289
|
+
fs8.renameSync(tmp, configPath);
|
|
28290
|
+
}
|
|
28291
|
+
|
|
28292
|
+
// ../core/dist/global-config/repos.js
|
|
28293
|
+
import * as fs9 from "node:fs";
|
|
28294
|
+
import * as os8 from "node:os";
|
|
28295
|
+
import * as path13 from "node:path";
|
|
28296
|
+
function expandPath(p) {
|
|
28297
|
+
if (p === "~" || p.startsWith("~/")) {
|
|
28298
|
+
return path13.join(os8.homedir(), p.slice(1));
|
|
28299
|
+
}
|
|
28300
|
+
return p;
|
|
28301
|
+
}
|
|
28302
|
+
function listRepos() {
|
|
28303
|
+
return readGlobalConfig().repos;
|
|
28304
|
+
}
|
|
28305
|
+
function addRepo(entry) {
|
|
28306
|
+
const config2 = readGlobalConfig();
|
|
28307
|
+
if (config2.repos.some((r) => r.name === entry.name)) {
|
|
28308
|
+
throw new Error(`repo "${entry.name}" already registered. Use "olam repos update" to change its path.`);
|
|
28309
|
+
}
|
|
28310
|
+
const resolvedPath = expandPath(entry.path);
|
|
28311
|
+
if (!fs9.existsSync(resolvedPath)) {
|
|
28312
|
+
throw new Error(`path "${entry.path}" does not exist. Verify the path is correct.`);
|
|
28313
|
+
}
|
|
28314
|
+
const now = Date.now();
|
|
28315
|
+
const newEntry = {
|
|
28316
|
+
name: entry.name,
|
|
28317
|
+
path: resolvedPath,
|
|
28318
|
+
addedAt: now,
|
|
28319
|
+
updatedAt: now,
|
|
28320
|
+
...entry.description !== void 0 ? { description: entry.description } : {},
|
|
28321
|
+
...entry.defaultBranch !== void 0 ? { defaultBranch: entry.defaultBranch } : {}
|
|
28322
|
+
};
|
|
28323
|
+
writeGlobalConfig({ ...config2, repos: [...config2.repos, newEntry] });
|
|
28324
|
+
return newEntry;
|
|
28325
|
+
}
|
|
28326
|
+
function removeRepo(name) {
|
|
28327
|
+
const config2 = readGlobalConfig();
|
|
28328
|
+
if (!config2.repos.some((r) => r.name === name)) {
|
|
28329
|
+
throw new Error(`repo "${name}" is not registered. Run "olam repos list" to see registered repos.`);
|
|
28330
|
+
}
|
|
28331
|
+
writeGlobalConfig({ ...config2, repos: config2.repos.filter((r) => r.name !== name) });
|
|
28332
|
+
}
|
|
28333
|
+
function updateRepo(name, updates) {
|
|
28334
|
+
const config2 = readGlobalConfig();
|
|
28335
|
+
const idx = config2.repos.findIndex((r) => r.name === name);
|
|
28336
|
+
if (idx === -1) {
|
|
28337
|
+
throw new Error(`repo "${name}" is not registered. Run "olam repos list" to see registered repos.`);
|
|
28338
|
+
}
|
|
28339
|
+
const resolvedUpdatePath = updates.path !== void 0 ? expandPath(updates.path) : void 0;
|
|
28340
|
+
if (resolvedUpdatePath !== void 0 && !fs9.existsSync(resolvedUpdatePath)) {
|
|
28341
|
+
throw new Error(`path "${updates.path}" does not exist. Verify the path is correct.`);
|
|
28342
|
+
}
|
|
28343
|
+
const existing = config2.repos[idx];
|
|
28344
|
+
const updated = {
|
|
28345
|
+
...existing,
|
|
28346
|
+
...resolvedUpdatePath !== void 0 ? { path: resolvedUpdatePath } : {},
|
|
28347
|
+
...updates.description !== void 0 ? { description: updates.description } : {},
|
|
28348
|
+
...updates.defaultBranch !== void 0 ? { defaultBranch: updates.defaultBranch } : {},
|
|
28349
|
+
updatedAt: Date.now()
|
|
28350
|
+
};
|
|
28351
|
+
const newRepos = [...config2.repos];
|
|
28352
|
+
newRepos[idx] = updated;
|
|
28353
|
+
writeGlobalConfig({ ...config2, repos: newRepos });
|
|
28354
|
+
return updated;
|
|
28355
|
+
}
|
|
28356
|
+
|
|
28357
|
+
// ../mcp-server/src/tools/repo.ts
|
|
28358
|
+
function asMessage4(err) {
|
|
28359
|
+
return err instanceof Error ? err.message : String(err);
|
|
28360
|
+
}
|
|
28361
|
+
function register22(server, _ctx, _initError) {
|
|
28362
|
+
server.tool(
|
|
28363
|
+
"olam_repo_list",
|
|
28364
|
+
"List every repo registered in ~/.olam/config.json. Returns { repos: RepoEntry[] }.",
|
|
28365
|
+
{},
|
|
28366
|
+
async () => {
|
|
28367
|
+
const repos = listRepos();
|
|
28368
|
+
return {
|
|
28369
|
+
content: [{
|
|
28370
|
+
type: "text",
|
|
28371
|
+
text: JSON.stringify({ repos }, null, 2)
|
|
28372
|
+
}]
|
|
28373
|
+
};
|
|
28374
|
+
}
|
|
28375
|
+
);
|
|
28376
|
+
server.tool(
|
|
28377
|
+
"olam_repo_add",
|
|
28378
|
+
"Register a local repo path in the global registry. The path must exist on disk. Rejects duplicate names.",
|
|
28379
|
+
{
|
|
28380
|
+
name: external_exports.string().min(1).describe("Repo name (lowercase, digits, dash; 1\u201364 chars)."),
|
|
28381
|
+
path: external_exports.string().min(1).describe("Absolute or ~/... path to the local repo directory."),
|
|
28382
|
+
description: external_exports.string().optional().describe("Optional human-readable description."),
|
|
28383
|
+
defaultBranch: external_exports.string().optional().describe("Default branch name (e.g. main).")
|
|
28384
|
+
},
|
|
28385
|
+
async ({ name, path: path23, description, defaultBranch }) => {
|
|
28386
|
+
try {
|
|
28387
|
+
const entry = addRepo({ name, path: path23, description, defaultBranch });
|
|
28388
|
+
return {
|
|
28389
|
+
content: [{
|
|
28390
|
+
type: "text",
|
|
28391
|
+
text: JSON.stringify({ name: entry.name, path: entry.path, message: `Registered repo "${entry.name}".` })
|
|
28392
|
+
}]
|
|
28393
|
+
};
|
|
28394
|
+
} catch (err) {
|
|
28395
|
+
return { content: [{ type: "text", text: asMessage4(err) }], isError: true };
|
|
28396
|
+
}
|
|
28397
|
+
}
|
|
28398
|
+
);
|
|
28399
|
+
server.tool(
|
|
28400
|
+
"olam_repo_remove",
|
|
28401
|
+
"Remove a repo from the global registry. Does not delete any files on disk.",
|
|
28402
|
+
{
|
|
28403
|
+
name: external_exports.string().min(1).describe("Repo name to remove.")
|
|
28404
|
+
},
|
|
28405
|
+
async ({ name }) => {
|
|
28406
|
+
try {
|
|
28407
|
+
removeRepo(name);
|
|
28408
|
+
return {
|
|
28409
|
+
content: [{
|
|
28410
|
+
type: "text",
|
|
28411
|
+
text: JSON.stringify({ name, message: `Removed repo "${name}".` })
|
|
28412
|
+
}]
|
|
28413
|
+
};
|
|
28414
|
+
} catch (err) {
|
|
28415
|
+
return { content: [{ type: "text", text: asMessage4(err) }], isError: true };
|
|
28416
|
+
}
|
|
28417
|
+
}
|
|
28418
|
+
);
|
|
28419
|
+
server.tool(
|
|
28420
|
+
"olam_repo_update",
|
|
28421
|
+
"Update a registered repo's path, description, or default branch.",
|
|
28422
|
+
{
|
|
28423
|
+
name: external_exports.string().min(1).describe("Repo name to update."),
|
|
28424
|
+
path: external_exports.string().optional().describe("New local path."),
|
|
28425
|
+
description: external_exports.string().optional().describe("New description."),
|
|
28426
|
+
defaultBranch: external_exports.string().optional().describe("New default branch.")
|
|
28427
|
+
},
|
|
28428
|
+
async ({ name, path: path23, description, defaultBranch }) => {
|
|
28429
|
+
try {
|
|
28430
|
+
const entry = updateRepo(name, { path: path23, description, defaultBranch });
|
|
28431
|
+
return {
|
|
28432
|
+
content: [{
|
|
28433
|
+
type: "text",
|
|
28434
|
+
text: JSON.stringify({ name: entry.name, path: entry.path, message: `Updated repo "${entry.name}".` })
|
|
28435
|
+
}]
|
|
28436
|
+
};
|
|
28437
|
+
} catch (err) {
|
|
28438
|
+
return { content: [{ type: "text", text: asMessage4(err) }], isError: true };
|
|
28439
|
+
}
|
|
28440
|
+
}
|
|
28441
|
+
);
|
|
28442
|
+
}
|
|
28443
|
+
|
|
28164
28444
|
// ../mcp-server/src/tools/index.ts
|
|
28165
28445
|
var toolModules = [
|
|
28166
28446
|
init_exports,
|
|
@@ -28183,7 +28463,8 @@ var toolModules = [
|
|
|
28183
28463
|
lane_destroy_exports,
|
|
28184
28464
|
lane_merge_exports,
|
|
28185
28465
|
capture_view_exports,
|
|
28186
|
-
create_from_prompt_exports
|
|
28466
|
+
create_from_prompt_exports,
|
|
28467
|
+
repo_exports
|
|
28187
28468
|
];
|
|
28188
28469
|
function registerAllTools(server, ctx, initError) {
|
|
28189
28470
|
for (const mod of toolModules) {
|
|
@@ -28215,8 +28496,8 @@ function createServer3(ctx, initError) {
|
|
|
28215
28496
|
}
|
|
28216
28497
|
|
|
28217
28498
|
// ../core/dist/config/loader.js
|
|
28218
|
-
import * as
|
|
28219
|
-
import * as
|
|
28499
|
+
import * as fs11 from "node:fs";
|
|
28500
|
+
import * as path14 from "node:path";
|
|
28220
28501
|
import { parse as parseYaml2 } from "yaml";
|
|
28221
28502
|
|
|
28222
28503
|
// ../core/dist/config/schema.js
|
|
@@ -28596,11 +28877,11 @@ function substituteEnvVars(obj) {
|
|
|
28596
28877
|
}
|
|
28597
28878
|
|
|
28598
28879
|
// ../core/dist/config/dotenv.js
|
|
28599
|
-
import * as
|
|
28880
|
+
import * as fs10 from "node:fs";
|
|
28600
28881
|
function loadDotEnv(envPath) {
|
|
28601
|
-
if (!
|
|
28882
|
+
if (!fs10.existsSync(envPath))
|
|
28602
28883
|
return;
|
|
28603
|
-
const content =
|
|
28884
|
+
const content = fs10.readFileSync(envPath, "utf-8");
|
|
28604
28885
|
for (const line of content.split("\n")) {
|
|
28605
28886
|
const trimmed = line.trim();
|
|
28606
28887
|
if (!trimmed || trimmed.startsWith("#"))
|
|
@@ -28619,18 +28900,18 @@ function loadDotEnv(envPath) {
|
|
|
28619
28900
|
// ../core/dist/config/loader.js
|
|
28620
28901
|
function findConfigFile(startDir) {
|
|
28621
28902
|
const searched = [];
|
|
28622
|
-
let current =
|
|
28903
|
+
let current = path14.resolve(startDir);
|
|
28623
28904
|
while (true) {
|
|
28624
|
-
const newLayout =
|
|
28625
|
-
const legacyLayout =
|
|
28905
|
+
const newLayout = path14.join(current, CONFIG_DIR_NAME, CONFIG_FILENAME);
|
|
28906
|
+
const legacyLayout = path14.join(current, LEGACY_CONFIG_FILENAME);
|
|
28626
28907
|
searched.push(newLayout, legacyLayout);
|
|
28627
|
-
if (
|
|
28908
|
+
if (fs11.existsSync(newLayout)) {
|
|
28628
28909
|
return { path: newLayout, isLegacy: false };
|
|
28629
28910
|
}
|
|
28630
|
-
if (
|
|
28911
|
+
if (fs11.existsSync(legacyLayout)) {
|
|
28631
28912
|
return { path: legacyLayout, isLegacy: true };
|
|
28632
28913
|
}
|
|
28633
|
-
const parent =
|
|
28914
|
+
const parent = path14.dirname(current);
|
|
28634
28915
|
if (parent === current)
|
|
28635
28916
|
break;
|
|
28636
28917
|
current = parent;
|
|
@@ -28645,12 +28926,12 @@ function loadConfig(startDir) {
|
|
|
28645
28926
|
Run /olam:init to migrate to .olam/config.yaml
|
|
28646
28927
|
`);
|
|
28647
28928
|
} else {
|
|
28648
|
-
const envPath =
|
|
28929
|
+
const envPath = path14.join(path14.dirname(found.path), ".env");
|
|
28649
28930
|
loadDotEnv(envPath);
|
|
28650
28931
|
}
|
|
28651
28932
|
let rawContent;
|
|
28652
28933
|
try {
|
|
28653
|
-
rawContent =
|
|
28934
|
+
rawContent = fs11.readFileSync(found.path, "utf-8");
|
|
28654
28935
|
} catch (err) {
|
|
28655
28936
|
throw new Error(`Failed to read ${found.path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
28656
28937
|
}
|
|
@@ -28682,9 +28963,9 @@ function loadConfig(startDir) {
|
|
|
28682
28963
|
// ../core/dist/world/manager.js
|
|
28683
28964
|
import * as crypto4 from "node:crypto";
|
|
28684
28965
|
import { execSync as execSync4 } from "node:child_process";
|
|
28685
|
-
import * as
|
|
28686
|
-
import * as
|
|
28687
|
-
import * as
|
|
28966
|
+
import * as fs16 from "node:fs";
|
|
28967
|
+
import * as os10 from "node:os";
|
|
28968
|
+
import * as path20 from "node:path";
|
|
28688
28969
|
|
|
28689
28970
|
// ../core/dist/world/state.js
|
|
28690
28971
|
var VALID_TRANSITIONS = {
|
|
@@ -28766,8 +29047,8 @@ function resolveDevboxImage(config2, tag) {
|
|
|
28766
29047
|
|
|
28767
29048
|
// ../core/dist/world/worktree.js
|
|
28768
29049
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
28769
|
-
import * as
|
|
28770
|
-
import * as
|
|
29050
|
+
import * as fs12 from "node:fs";
|
|
29051
|
+
import * as path15 from "node:path";
|
|
28771
29052
|
function resolveGitDir(repo) {
|
|
28772
29053
|
if (repo.path) {
|
|
28773
29054
|
return repo.path;
|
|
@@ -28777,11 +29058,11 @@ function resolveGitDir(repo) {
|
|
|
28777
29058
|
async function createWorktrees(repos, worldId, workspacePath, branch) {
|
|
28778
29059
|
const created = [];
|
|
28779
29060
|
for (const repo of repos) {
|
|
28780
|
-
const worktreePath =
|
|
29061
|
+
const worktreePath = path15.join(workspacePath, repo.name);
|
|
28781
29062
|
const gitDir = resolveGitDir(repo);
|
|
28782
29063
|
const branchName = branch || `olam/${worldId}`;
|
|
28783
29064
|
try {
|
|
28784
|
-
|
|
29065
|
+
fs12.mkdirSync(path15.dirname(worktreePath), { recursive: true });
|
|
28785
29066
|
execFileSync2("git", ["worktree", "add", worktreePath, "-b", branchName], {
|
|
28786
29067
|
cwd: gitDir,
|
|
28787
29068
|
stdio: "pipe"
|
|
@@ -28814,7 +29095,7 @@ async function createWorktrees(repos, worldId, workspacePath, branch) {
|
|
|
28814
29095
|
}
|
|
28815
29096
|
async function removeWorktrees(repos, workspacePath) {
|
|
28816
29097
|
for (const repo of repos) {
|
|
28817
|
-
const worktreePath =
|
|
29098
|
+
const worktreePath = path15.join(workspacePath, repo.name);
|
|
28818
29099
|
let gitDir;
|
|
28819
29100
|
try {
|
|
28820
29101
|
gitDir = resolveGitDir(repo);
|
|
@@ -28889,12 +29170,12 @@ function removeBranch(repo, branch) {
|
|
|
28889
29170
|
|
|
28890
29171
|
// ../core/dist/world/baseline-diff.js
|
|
28891
29172
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
28892
|
-
import * as
|
|
28893
|
-
import * as
|
|
28894
|
-
import * as
|
|
29173
|
+
import * as fs13 from "node:fs";
|
|
29174
|
+
import * as os9 from "node:os";
|
|
29175
|
+
import * as path16 from "node:path";
|
|
28895
29176
|
var DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
28896
|
-
function expandHome(p,
|
|
28897
|
-
return p.replace(/^~(?=$|\/|\\)/,
|
|
29177
|
+
function expandHome(p, homedir13) {
|
|
29178
|
+
return p.replace(/^~(?=$|\/|\\)/, homedir13());
|
|
28898
29179
|
}
|
|
28899
29180
|
function sanitizeRepoFilename(name) {
|
|
28900
29181
|
const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
@@ -28917,10 +29198,10 @@ ${stderr}`;
|
|
|
28917
29198
|
}
|
|
28918
29199
|
function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
28919
29200
|
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync3(cmd, args, opts));
|
|
28920
|
-
const
|
|
28921
|
-
const baselineDir =
|
|
29201
|
+
const homedir13 = deps.homedir ?? (() => os9.homedir());
|
|
29202
|
+
const baselineDir = path16.join(workspacePath, ".olam", "baseline");
|
|
28922
29203
|
try {
|
|
28923
|
-
|
|
29204
|
+
fs13.mkdirSync(baselineDir, { recursive: true });
|
|
28924
29205
|
} catch (err) {
|
|
28925
29206
|
const msg = err instanceof Error ? err.message : String(err);
|
|
28926
29207
|
console.warn(`[baseline-diff] mkdir ${baselineDir} failed: ${msg}; reaper will see no baseline at all`);
|
|
@@ -28932,9 +29213,9 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
|
28932
29213
|
if (!repo.path)
|
|
28933
29214
|
continue;
|
|
28934
29215
|
const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
|
|
28935
|
-
const outPath =
|
|
28936
|
-
const repoPath = expandHome(repo.path,
|
|
28937
|
-
if (!
|
|
29216
|
+
const outPath = path16.join(baselineDir, filename);
|
|
29217
|
+
const repoPath = expandHome(repo.path, homedir13);
|
|
29218
|
+
if (!fs13.existsSync(repoPath)) {
|
|
28938
29219
|
writeBaselineFile(outPath, `# repo: ${repo.name}
|
|
28939
29220
|
# (skipped: path ${repoPath} does not exist)
|
|
28940
29221
|
`);
|
|
@@ -29001,7 +29282,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
|
29001
29282
|
}
|
|
29002
29283
|
function writeBaselineFile(outPath, content) {
|
|
29003
29284
|
try {
|
|
29004
|
-
|
|
29285
|
+
fs13.writeFileSync(outPath, content);
|
|
29005
29286
|
} catch (err) {
|
|
29006
29287
|
const msg = err instanceof Error ? err.message : String(err);
|
|
29007
29288
|
console.warn(`[baseline-diff] write to ${outPath} failed: ${msg}`);
|
|
@@ -29009,8 +29290,8 @@ function writeBaselineFile(outPath, content) {
|
|
|
29009
29290
|
}
|
|
29010
29291
|
function stripWorktreeEdits(repos, workspacePath) {
|
|
29011
29292
|
for (const repo of repos) {
|
|
29012
|
-
const worktreePath =
|
|
29013
|
-
if (!
|
|
29293
|
+
const worktreePath = path16.join(workspacePath, repo.name);
|
|
29294
|
+
if (!fs13.existsSync(worktreePath))
|
|
29014
29295
|
continue;
|
|
29015
29296
|
try {
|
|
29016
29297
|
execFileSync3("git", ["checkout", "--", "."], {
|
|
@@ -29040,12 +29321,12 @@ function formatBaselineSummary(result) {
|
|
|
29040
29321
|
}
|
|
29041
29322
|
|
|
29042
29323
|
// ../core/dist/world/context-injection.js
|
|
29043
|
-
import * as
|
|
29044
|
-
import * as
|
|
29324
|
+
import * as fs14 from "node:fs";
|
|
29325
|
+
import * as path17 from "node:path";
|
|
29045
29326
|
function injectWorldContext(opts) {
|
|
29046
29327
|
const { world, task, linearTicketId, claudeMdExtra, taskContext, services, pleriPlaneUrl } = opts;
|
|
29047
|
-
const claudeDir =
|
|
29048
|
-
|
|
29328
|
+
const claudeDir = path17.join(world.workspacePath, ".claude");
|
|
29329
|
+
fs14.mkdirSync(claudeDir, { recursive: true });
|
|
29049
29330
|
const sections = [];
|
|
29050
29331
|
sections.push(`# Olam World: ${world.name}`);
|
|
29051
29332
|
sections.push("");
|
|
@@ -29206,7 +29487,7 @@ function injectWorldContext(opts) {
|
|
|
29206
29487
|
sections.push("");
|
|
29207
29488
|
}
|
|
29208
29489
|
const content = sections.join("\n");
|
|
29209
|
-
|
|
29490
|
+
fs14.writeFileSync(path17.join(claudeDir, "CLAUDE.md"), content);
|
|
29210
29491
|
}
|
|
29211
29492
|
function formatTaskSource(ctx) {
|
|
29212
29493
|
if (ctx.source === "linear" && ctx.ticketId) {
|
|
@@ -29220,9 +29501,9 @@ function formatTaskSource(ctx) {
|
|
|
29220
29501
|
function hasPlanFile(world) {
|
|
29221
29502
|
if (world.repos.length === 0)
|
|
29222
29503
|
return false;
|
|
29223
|
-
const plansDir =
|
|
29504
|
+
const plansDir = path17.join(world.workspacePath, world.repos[0], "docs", "plans");
|
|
29224
29505
|
try {
|
|
29225
|
-
return
|
|
29506
|
+
return fs14.existsSync(plansDir) && fs14.readdirSync(plansDir).length > 0;
|
|
29226
29507
|
} catch {
|
|
29227
29508
|
return false;
|
|
29228
29509
|
}
|
|
@@ -29888,14 +30169,14 @@ function gcloudAvailable(execFn = defaultExecFn) {
|
|
|
29888
30169
|
}
|
|
29889
30170
|
|
|
29890
30171
|
// ../core/dist/world/olam-yaml.js
|
|
29891
|
-
import * as
|
|
30172
|
+
import * as path18 from "node:path";
|
|
29892
30173
|
import YAML2 from "yaml";
|
|
29893
30174
|
function enrichReposWithManifests(repos, workspacePath) {
|
|
29894
30175
|
return repos.map((repo) => {
|
|
29895
30176
|
if (repo.manifest !== void 0 && repo.manifest !== null) {
|
|
29896
30177
|
return repo;
|
|
29897
30178
|
}
|
|
29898
|
-
const repoDir =
|
|
30179
|
+
const repoDir = path18.join(workspacePath, repo.name);
|
|
29899
30180
|
let manifest = null;
|
|
29900
30181
|
try {
|
|
29901
30182
|
manifest = loadRepoManifest(repoDir);
|
|
@@ -29910,8 +30191,8 @@ function enrichReposWithManifests(repos, workspacePath) {
|
|
|
29910
30191
|
}
|
|
29911
30192
|
|
|
29912
30193
|
// ../core/dist/policies/loader.js
|
|
29913
|
-
import * as
|
|
29914
|
-
import * as
|
|
30194
|
+
import * as fs15 from "node:fs";
|
|
30195
|
+
import * as path19 from "node:path";
|
|
29915
30196
|
import { parse as parseYaml3 } from "yaml";
|
|
29916
30197
|
function parseFrontmatter(content) {
|
|
29917
30198
|
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/m.exec(content);
|
|
@@ -29931,20 +30212,20 @@ function toStringArray(v) {
|
|
|
29931
30212
|
return v.filter((x) => typeof x === "string");
|
|
29932
30213
|
}
|
|
29933
30214
|
function loadPolicies(workspaceRoot) {
|
|
29934
|
-
const policiesDir =
|
|
29935
|
-
if (!
|
|
30215
|
+
const policiesDir = path19.join(workspaceRoot, ".olam", "policies");
|
|
30216
|
+
if (!fs15.existsSync(policiesDir))
|
|
29936
30217
|
return [];
|
|
29937
30218
|
let files;
|
|
29938
30219
|
try {
|
|
29939
|
-
files =
|
|
30220
|
+
files = fs15.readdirSync(policiesDir).filter((f) => f.endsWith(".md")).sort();
|
|
29940
30221
|
} catch {
|
|
29941
30222
|
return [];
|
|
29942
30223
|
}
|
|
29943
30224
|
const policies = [];
|
|
29944
30225
|
for (const file of files) {
|
|
29945
|
-
const filePath =
|
|
30226
|
+
const filePath = path19.join(policiesDir, file);
|
|
29946
30227
|
try {
|
|
29947
|
-
const content =
|
|
30228
|
+
const content = fs15.readFileSync(filePath, "utf8");
|
|
29948
30229
|
const parsed = parseFrontmatter(content);
|
|
29949
30230
|
if (!parsed) {
|
|
29950
30231
|
console.warn(`[policies] skipping ${file}: no valid frontmatter block`);
|
|
@@ -30483,7 +30764,7 @@ var WorldManager = class {
|
|
|
30483
30764
|
}
|
|
30484
30765
|
}
|
|
30485
30766
|
const worldId = generateWorldId();
|
|
30486
|
-
const workspacePath =
|
|
30767
|
+
const workspacePath = path20.join(os10.homedir(), ".olam", "worlds", worldId);
|
|
30487
30768
|
const portOffset = this.registry.getNextPortOffset();
|
|
30488
30769
|
const branch = opts.branchName ?? `olam/${worldId}`;
|
|
30489
30770
|
const repos = this.resolveReposWithWorkspace(opts);
|
|
@@ -30539,38 +30820,38 @@ var WorldManager = class {
|
|
|
30539
30820
|
for (const repo of repos) {
|
|
30540
30821
|
if (!repo.path)
|
|
30541
30822
|
continue;
|
|
30542
|
-
const sourceRoot = repo.path.replace(/^~/,
|
|
30543
|
-
const worktreeRoot =
|
|
30544
|
-
if (!
|
|
30823
|
+
const sourceRoot = repo.path.replace(/^~/, os10.homedir());
|
|
30824
|
+
const worktreeRoot = path20.join(workspacePath, repo.name);
|
|
30825
|
+
if (!fs16.existsSync(sourceRoot) || !fs16.existsSync(worktreeRoot))
|
|
30545
30826
|
continue;
|
|
30546
30827
|
let copied = 0;
|
|
30547
30828
|
for (const pattern of RUNTIME_FILE_PATTERNS) {
|
|
30548
30829
|
const matches2 = [];
|
|
30549
30830
|
if (pattern.includes("*")) {
|
|
30550
|
-
const [dir, glob] = [
|
|
30551
|
-
const sourceDir =
|
|
30552
|
-
if (
|
|
30831
|
+
const [dir, glob] = [path20.dirname(pattern), path20.basename(pattern)];
|
|
30832
|
+
const sourceDir = path20.join(sourceRoot, dir);
|
|
30833
|
+
if (fs16.existsSync(sourceDir)) {
|
|
30553
30834
|
const ext = glob.replace(/^\*+/, "");
|
|
30554
30835
|
try {
|
|
30555
|
-
for (const entry of
|
|
30836
|
+
for (const entry of fs16.readdirSync(sourceDir)) {
|
|
30556
30837
|
if (ext === "" || entry.endsWith(ext))
|
|
30557
|
-
matches2.push(
|
|
30838
|
+
matches2.push(path20.join(dir, entry));
|
|
30558
30839
|
}
|
|
30559
30840
|
} catch {
|
|
30560
30841
|
}
|
|
30561
30842
|
}
|
|
30562
|
-
} else if (
|
|
30843
|
+
} else if (fs16.existsSync(path20.join(sourceRoot, pattern))) {
|
|
30563
30844
|
matches2.push(pattern);
|
|
30564
30845
|
}
|
|
30565
30846
|
for (const rel of matches2) {
|
|
30566
|
-
const src =
|
|
30567
|
-
const dst =
|
|
30847
|
+
const src = path20.join(sourceRoot, rel);
|
|
30848
|
+
const dst = path20.join(worktreeRoot, rel);
|
|
30568
30849
|
try {
|
|
30569
|
-
const st =
|
|
30850
|
+
const st = fs16.statSync(src);
|
|
30570
30851
|
if (!st.isFile())
|
|
30571
30852
|
continue;
|
|
30572
|
-
|
|
30573
|
-
|
|
30853
|
+
fs16.mkdirSync(path20.dirname(dst), { recursive: true });
|
|
30854
|
+
fs16.copyFileSync(src, dst);
|
|
30574
30855
|
copied++;
|
|
30575
30856
|
} catch {
|
|
30576
30857
|
}
|
|
@@ -30670,7 +30951,7 @@ var WorldManager = class {
|
|
|
30670
30951
|
try {
|
|
30671
30952
|
const hostExec = makeHostExecFn();
|
|
30672
30953
|
for (const repo of repos) {
|
|
30673
|
-
const repoDir =
|
|
30954
|
+
const repoDir = path20.join(workspacePath, repo.name);
|
|
30674
30955
|
if (repo.stack && Object.keys(repo.stack).length > 0) {
|
|
30675
30956
|
preDetectedStacks.set(repo.name, { repoName: repo.name, versions: repo.stack });
|
|
30676
30957
|
} else {
|
|
@@ -30727,10 +31008,10 @@ var WorldManager = class {
|
|
|
30727
31008
|
const worldEnv = {};
|
|
30728
31009
|
if (opts.task)
|
|
30729
31010
|
worldEnv.OLAM_TASK = opts.task;
|
|
30730
|
-
const r2CredsPath =
|
|
30731
|
-
if (
|
|
31011
|
+
const r2CredsPath = path20.join(os10.homedir(), ".olam", "r2-credentials.json");
|
|
31012
|
+
if (fs16.existsSync(r2CredsPath)) {
|
|
30732
31013
|
try {
|
|
30733
|
-
const r2Raw =
|
|
31014
|
+
const r2Raw = fs16.readFileSync(r2CredsPath, "utf-8").trim();
|
|
30734
31015
|
if (r2Raw.length > 0) {
|
|
30735
31016
|
const r2 = JSON.parse(r2Raw);
|
|
30736
31017
|
if (typeof r2.account_id === "string")
|
|
@@ -30747,10 +31028,10 @@ var WorldManager = class {
|
|
|
30747
31028
|
} catch {
|
|
30748
31029
|
}
|
|
30749
31030
|
}
|
|
30750
|
-
const keysYamlPath =
|
|
30751
|
-
if (
|
|
31031
|
+
const keysYamlPath = path20.join(os10.homedir(), ".olam", "keys.yaml");
|
|
31032
|
+
if (fs16.existsSync(keysYamlPath)) {
|
|
30752
31033
|
try {
|
|
30753
|
-
const keysRaw =
|
|
31034
|
+
const keysRaw = fs16.readFileSync(keysYamlPath, "utf-8").trim();
|
|
30754
31035
|
if (keysRaw.length > 0) {
|
|
30755
31036
|
const parsed = YAML3.parse(keysRaw);
|
|
30756
31037
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
@@ -30797,10 +31078,10 @@ var WorldManager = class {
|
|
|
30797
31078
|
worldEnv[k] = v;
|
|
30798
31079
|
}
|
|
30799
31080
|
for (const { repoName, relativePath, content } of fileWrites) {
|
|
30800
|
-
const absPath =
|
|
31081
|
+
const absPath = path20.join(workspacePath, repoName, relativePath);
|
|
30801
31082
|
try {
|
|
30802
|
-
|
|
30803
|
-
|
|
31083
|
+
fs16.mkdirSync(path20.dirname(absPath), { recursive: true });
|
|
31084
|
+
fs16.writeFileSync(absPath, content.endsWith("\n") ? content : content + "\n", {
|
|
30804
31085
|
mode: 384
|
|
30805
31086
|
});
|
|
30806
31087
|
console.log(`[secrets] ${repoName}: materialised ${relativePath} (${content.length} chars, mode 0600)`);
|
|
@@ -30952,7 +31233,7 @@ var WorldManager = class {
|
|
|
30952
31233
|
let taskWithPolicies = opts.task;
|
|
30953
31234
|
try {
|
|
30954
31235
|
const allPolicies = repos.flatMap((repo) => {
|
|
30955
|
-
const repoWorktree =
|
|
31236
|
+
const repoWorktree = path20.join(workspacePath, repo.name);
|
|
30956
31237
|
return loadPolicies(repoWorktree);
|
|
30957
31238
|
});
|
|
30958
31239
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -30968,8 +31249,8 @@ var WorldManager = class {
|
|
|
30968
31249
|
${opts.task}`;
|
|
30969
31250
|
execSync4(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
|
|
30970
31251
|
for (const repo of repos) {
|
|
30971
|
-
const policiesDir =
|
|
30972
|
-
if (
|
|
31252
|
+
const policiesDir = path20.join(workspacePath, repo.name, ".olam", "policies");
|
|
31253
|
+
if (fs16.existsSync(policiesDir)) {
|
|
30973
31254
|
execSync4(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
|
|
30974
31255
|
}
|
|
30975
31256
|
}
|
|
@@ -31048,8 +31329,8 @@ ${opts.task}`;
|
|
|
31048
31329
|
} catch {
|
|
31049
31330
|
}
|
|
31050
31331
|
try {
|
|
31051
|
-
|
|
31052
|
-
if (
|
|
31332
|
+
fs16.rmSync(world.workspacePath, { recursive: true, force: true });
|
|
31333
|
+
if (fs16.existsSync(world.workspacePath)) {
|
|
31053
31334
|
console.warn(`[WorldManager] destroyWorld(${worldId}): workspace dir ${world.workspacePath} still exists after rmSync. Run \`olam clean --apply\` to reap.`);
|
|
31054
31335
|
}
|
|
31055
31336
|
} catch (err) {
|
|
@@ -31134,14 +31415,14 @@ ${opts.task}`;
|
|
|
31134
31415
|
return names.map((name) => this.config.repos.find((r) => r.name === name)).filter((r) => r !== void 0);
|
|
31135
31416
|
}
|
|
31136
31417
|
transportPlanFile(planFilePath, workspacePath, repoNames) {
|
|
31137
|
-
const planContent =
|
|
31138
|
-
const planFileName =
|
|
31418
|
+
const planContent = fs16.readFileSync(planFilePath, "utf-8");
|
|
31419
|
+
const planFileName = path20.basename(planFilePath);
|
|
31139
31420
|
const targetRepo = repoNames[0];
|
|
31140
31421
|
if (!targetRepo)
|
|
31141
31422
|
return;
|
|
31142
|
-
const plansDir =
|
|
31143
|
-
|
|
31144
|
-
|
|
31423
|
+
const plansDir = path20.join(workspacePath, targetRepo, "docs", "plans");
|
|
31424
|
+
fs16.mkdirSync(plansDir, { recursive: true });
|
|
31425
|
+
fs16.writeFileSync(path20.join(plansDir, planFileName), planContent);
|
|
31145
31426
|
}
|
|
31146
31427
|
resolveServices(repos) {
|
|
31147
31428
|
const services = [];
|
|
@@ -31226,8 +31507,8 @@ import * as http2 from "node:http";
|
|
|
31226
31507
|
|
|
31227
31508
|
// ../core/dist/dashboard/server.js
|
|
31228
31509
|
import * as http from "node:http";
|
|
31229
|
-
import * as
|
|
31230
|
-
import * as
|
|
31510
|
+
import * as fs17 from "node:fs";
|
|
31511
|
+
import * as path21 from "node:path";
|
|
31231
31512
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
31232
31513
|
|
|
31233
31514
|
// ../core/dist/dashboard/serialize.js
|
|
@@ -31562,7 +31843,7 @@ function notFound(res) {
|
|
|
31562
31843
|
}
|
|
31563
31844
|
function openThoughtStore(workspacePath) {
|
|
31564
31845
|
const dbPath = getWorldDbPath(workspacePath);
|
|
31565
|
-
if (!
|
|
31846
|
+
if (!fs17.existsSync(dbPath))
|
|
31566
31847
|
return null;
|
|
31567
31848
|
return new ThoughtLocalStore(dbPath);
|
|
31568
31849
|
}
|
|
@@ -31733,13 +32014,13 @@ function findSessionInWorld(registry2, sessionId) {
|
|
|
31733
32014
|
}
|
|
31734
32015
|
function createDashboardServer(opts) {
|
|
31735
32016
|
const { port, registry: registry2 } = opts;
|
|
31736
|
-
const thisDir =
|
|
31737
|
-
const defaultPublicDir =
|
|
32017
|
+
const thisDir = path21.dirname(fileURLToPath2(import.meta.url));
|
|
32018
|
+
const defaultPublicDir = path21.resolve(thisDir, "../../../control-plane/public");
|
|
31738
32019
|
const publicDir = opts.publicDir ?? defaultPublicDir;
|
|
31739
|
-
let hasPublicDir =
|
|
32020
|
+
let hasPublicDir = fs17.existsSync(publicDir);
|
|
31740
32021
|
const server = http.createServer((req, res) => {
|
|
31741
32022
|
if (!hasPublicDir) {
|
|
31742
|
-
hasPublicDir =
|
|
32023
|
+
hasPublicDir = fs17.existsSync(publicDir);
|
|
31743
32024
|
}
|
|
31744
32025
|
const host = req.headers.host ?? `localhost:${port}`;
|
|
31745
32026
|
const url = new URL(req.url ?? "/", `http://${host}`);
|
|
@@ -32013,22 +32294,22 @@ function createDashboardServer(opts) {
|
|
|
32013
32294
|
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>`);
|
|
32014
32295
|
return;
|
|
32015
32296
|
}
|
|
32016
|
-
let filePath =
|
|
32297
|
+
let filePath = path21.join(publicDir, pathname === "/" ? "index.html" : pathname);
|
|
32017
32298
|
if (!filePath.startsWith(publicDir)) {
|
|
32018
32299
|
notFound(res);
|
|
32019
32300
|
return;
|
|
32020
32301
|
}
|
|
32021
|
-
if (
|
|
32022
|
-
const ext =
|
|
32302
|
+
if (fs17.existsSync(filePath) && fs17.statSync(filePath).isFile()) {
|
|
32303
|
+
const ext = path21.extname(filePath);
|
|
32023
32304
|
const contentType = MIME[ext] ?? "application/octet-stream";
|
|
32024
32305
|
res.writeHead(200, { "Content-Type": contentType });
|
|
32025
|
-
|
|
32306
|
+
fs17.createReadStream(filePath).pipe(res);
|
|
32026
32307
|
return;
|
|
32027
32308
|
}
|
|
32028
|
-
filePath =
|
|
32029
|
-
if (
|
|
32309
|
+
filePath = path21.join(publicDir, "index.html");
|
|
32310
|
+
if (fs17.existsSync(filePath)) {
|
|
32030
32311
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
32031
|
-
|
|
32312
|
+
fs17.createReadStream(filePath).pipe(res);
|
|
32032
32313
|
return;
|
|
32033
32314
|
}
|
|
32034
32315
|
notFound(res);
|
|
@@ -32038,17 +32319,17 @@ function createDashboardServer(opts) {
|
|
|
32038
32319
|
}
|
|
32039
32320
|
|
|
32040
32321
|
// ../core/dist/dashboard/state.js
|
|
32041
|
-
import * as
|
|
32042
|
-
import * as
|
|
32043
|
-
import * as
|
|
32044
|
-
var STATE_PATH =
|
|
32322
|
+
import * as fs18 from "node:fs";
|
|
32323
|
+
import * as os11 from "node:os";
|
|
32324
|
+
import * as path22 from "node:path";
|
|
32325
|
+
var STATE_PATH = path22.join(os11.homedir(), ".olam", "dashboard.json");
|
|
32045
32326
|
function saveDashboardState(state) {
|
|
32046
|
-
|
|
32047
|
-
|
|
32327
|
+
fs18.mkdirSync(path22.dirname(STATE_PATH), { recursive: true });
|
|
32328
|
+
fs18.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2));
|
|
32048
32329
|
}
|
|
32049
32330
|
function loadDashboardState() {
|
|
32050
32331
|
try {
|
|
32051
|
-
const raw =
|
|
32332
|
+
const raw = fs18.readFileSync(STATE_PATH, "utf-8");
|
|
32052
32333
|
return JSON.parse(raw);
|
|
32053
32334
|
} catch {
|
|
32054
32335
|
return null;
|
|
@@ -32056,7 +32337,7 @@ function loadDashboardState() {
|
|
|
32056
32337
|
}
|
|
32057
32338
|
function clearDashboardState() {
|
|
32058
32339
|
try {
|
|
32059
|
-
|
|
32340
|
+
fs18.unlinkSync(STATE_PATH);
|
|
32060
32341
|
} catch {
|
|
32061
32342
|
}
|
|
32062
32343
|
}
|
|
@@ -32336,8 +32617,8 @@ var PleriClient = class {
|
|
|
32336
32617
|
};
|
|
32337
32618
|
|
|
32338
32619
|
// ../mcp-server/src/env-loader.ts
|
|
32339
|
-
import { readFileSync as
|
|
32340
|
-
import { join as
|
|
32620
|
+
import { readFileSync as readFileSync15, existsSync as existsSync19, statSync as statSync6 } from "node:fs";
|
|
32621
|
+
import { join as join25, dirname as dirname13, resolve as resolve5 } from "node:path";
|
|
32341
32622
|
var PROJECT_MARKERS = [
|
|
32342
32623
|
".olam/config.yaml",
|
|
32343
32624
|
".olam/config.yml",
|
|
@@ -32349,26 +32630,26 @@ function findProjectRoot2(startDir) {
|
|
|
32349
32630
|
const root = resolve5("/");
|
|
32350
32631
|
while (true) {
|
|
32351
32632
|
for (const marker of PROJECT_MARKERS) {
|
|
32352
|
-
if (
|
|
32633
|
+
if (existsSync19(join25(dir, marker))) return dir;
|
|
32353
32634
|
}
|
|
32354
|
-
const pkg =
|
|
32355
|
-
if (
|
|
32635
|
+
const pkg = join25(dir, "package.json");
|
|
32636
|
+
if (existsSync19(pkg)) {
|
|
32356
32637
|
try {
|
|
32357
|
-
const json = JSON.parse(
|
|
32638
|
+
const json = JSON.parse(readFileSync15(pkg, "utf8"));
|
|
32358
32639
|
const isOlamWorkspace = typeof json.name === "string" && json.name.startsWith("@olam/");
|
|
32359
32640
|
const hasOlamDep = json.dependencies && Object.keys(json.dependencies).some((k) => k.startsWith("@olam/")) || json.devDependencies && Object.keys(json.devDependencies).some((k) => k.startsWith("@olam/"));
|
|
32360
32641
|
if (isOlamWorkspace || hasOlamDep) return dir;
|
|
32361
32642
|
} catch {
|
|
32362
32643
|
}
|
|
32363
32644
|
}
|
|
32364
|
-
const parent =
|
|
32645
|
+
const parent = dirname13(dir);
|
|
32365
32646
|
if (parent === dir || parent === root) return null;
|
|
32366
32647
|
dir = parent;
|
|
32367
32648
|
}
|
|
32368
32649
|
}
|
|
32369
|
-
function parseEnvFile(
|
|
32650
|
+
function parseEnvFile(path23) {
|
|
32370
32651
|
const out = {};
|
|
32371
|
-
const raw =
|
|
32652
|
+
const raw = readFileSync15(path23, "utf8");
|
|
32372
32653
|
for (const line of raw.split(/\r?\n/)) {
|
|
32373
32654
|
const trimmed = line.trim();
|
|
32374
32655
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -32391,8 +32672,8 @@ function loadProjectEnv(startDir = process.cwd()) {
|
|
|
32391
32672
|
const filesRead = [];
|
|
32392
32673
|
const merged = {};
|
|
32393
32674
|
for (const name of [".env", ".env.local"]) {
|
|
32394
|
-
const p =
|
|
32395
|
-
if (
|
|
32675
|
+
const p = join25(root, name);
|
|
32676
|
+
if (existsSync19(p) && statSync6(p).isFile()) {
|
|
32396
32677
|
Object.assign(merged, parseEnvFile(p));
|
|
32397
32678
|
filesRead.push(p);
|
|
32398
32679
|
}
|