@pleri/olam-cli 0.1.144 → 0.1.145
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/doctor.d.ts +53 -23
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +117 -46
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/logs.d.ts +17 -3
- package/dist/commands/logs.d.ts.map +1 -1
- package/dist/commands/logs.js +38 -35
- package/dist/commands/logs.js.map +1 -1
- package/dist/commands/memory/bridge.d.ts +57 -0
- package/dist/commands/memory/bridge.d.ts.map +1 -0
- package/dist/commands/memory/bridge.js +156 -0
- package/dist/commands/memory/bridge.js.map +1 -0
- package/dist/commands/memory/index.d.ts +3 -0
- package/dist/commands/memory/index.d.ts.map +1 -1
- package/dist/commands/memory/index.js +10 -1
- package/dist/commands/memory/index.js.map +1 -1
- package/dist/commands/memory/reclassify.d.ts +56 -0
- package/dist/commands/memory/reclassify.d.ts.map +1 -0
- package/dist/commands/memory/reclassify.js +177 -0
- package/dist/commands/memory/reclassify.js.map +1 -0
- package/dist/commands/memory/stats.d.ts +69 -0
- package/dist/commands/memory/stats.d.ts.map +1 -0
- package/dist/commands/memory/stats.js +164 -0
- package/dist/commands/memory/stats.js.map +1 -0
- package/dist/commands/skills-source.d.ts +12 -0
- package/dist/commands/skills-source.d.ts.map +1 -0
- package/dist/commands/skills-source.js +133 -0
- package/dist/commands/skills-source.js.map +1 -0
- package/dist/commands/skills.d.ts +11 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +163 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/status.d.ts +27 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +102 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/image-digests.json +7 -7
- package/dist/index.js +2027 -529
- package/dist/index.js.map +1 -1
- package/dist/lib/health-probes.d.ts +72 -0
- package/dist/lib/health-probes.d.ts.map +1 -1
- package/dist/lib/health-probes.js +218 -0
- package/dist/lib/health-probes.js.map +1 -1
- package/dist/mcp-server.js +1246 -351
- package/host-cp/src/agent-runtime-trigger.mjs +74 -4
- package/host-cp/src/engine-identity.mjs +32 -0
- package/host-cp/src/server.mjs +188 -3
- package/package.json +1 -1
package/dist/mcp-server.js
CHANGED
|
@@ -445,8 +445,8 @@ var init_parseUtil = __esm({
|
|
|
445
445
|
init_errors();
|
|
446
446
|
init_en();
|
|
447
447
|
makeIssue = (params) => {
|
|
448
|
-
const { data, path:
|
|
449
|
-
const fullPath = [...
|
|
448
|
+
const { data, path: path37, errorMaps, issueData } = params;
|
|
449
|
+
const fullPath = [...path37, ...issueData.path || []];
|
|
450
450
|
const fullIssue = {
|
|
451
451
|
...issueData,
|
|
452
452
|
path: fullPath
|
|
@@ -754,11 +754,11 @@ var init_types = __esm({
|
|
|
754
754
|
init_parseUtil();
|
|
755
755
|
init_util();
|
|
756
756
|
ParseInputLazyPath = class {
|
|
757
|
-
constructor(parent, value,
|
|
757
|
+
constructor(parent, value, path37, key) {
|
|
758
758
|
this._cachedPath = [];
|
|
759
759
|
this.parent = parent;
|
|
760
760
|
this.data = value;
|
|
761
|
-
this._path =
|
|
761
|
+
this._path = path37;
|
|
762
762
|
this._key = key;
|
|
763
763
|
}
|
|
764
764
|
get path() {
|
|
@@ -7332,8 +7332,8 @@ var require_utils = __commonJS({
|
|
|
7332
7332
|
}
|
|
7333
7333
|
return ind;
|
|
7334
7334
|
}
|
|
7335
|
-
function removeDotSegments(
|
|
7336
|
-
let input =
|
|
7335
|
+
function removeDotSegments(path37) {
|
|
7336
|
+
let input = path37;
|
|
7337
7337
|
const output = [];
|
|
7338
7338
|
let nextSlash = -1;
|
|
7339
7339
|
let len = 0;
|
|
@@ -7532,8 +7532,8 @@ var require_schemes = __commonJS({
|
|
|
7532
7532
|
wsComponent.secure = void 0;
|
|
7533
7533
|
}
|
|
7534
7534
|
if (wsComponent.resourceName) {
|
|
7535
|
-
const [
|
|
7536
|
-
wsComponent.path =
|
|
7535
|
+
const [path37, query] = wsComponent.resourceName.split("?");
|
|
7536
|
+
wsComponent.path = path37 && path37 !== "/" ? path37 : void 0;
|
|
7537
7537
|
wsComponent.query = query;
|
|
7538
7538
|
wsComponent.resourceName = void 0;
|
|
7539
7539
|
}
|
|
@@ -10895,12 +10895,12 @@ var require_dist = __commonJS({
|
|
|
10895
10895
|
throw new Error(`Unknown format "${name}"`);
|
|
10896
10896
|
return f;
|
|
10897
10897
|
};
|
|
10898
|
-
function addFormats(ajv, list,
|
|
10898
|
+
function addFormats(ajv, list, fs34, exportName) {
|
|
10899
10899
|
var _a3;
|
|
10900
10900
|
var _b;
|
|
10901
10901
|
(_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
10902
10902
|
for (const f of list)
|
|
10903
|
-
ajv.addFormat(f,
|
|
10903
|
+
ajv.addFormat(f, fs34[f]);
|
|
10904
10904
|
}
|
|
10905
10905
|
module.exports = exports = formatsPlugin;
|
|
10906
10906
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -11008,7 +11008,7 @@ import YAML from "yaml";
|
|
|
11008
11008
|
function bootstrapStepCmd(entry) {
|
|
11009
11009
|
return typeof entry === "string" ? entry : entry.cmd;
|
|
11010
11010
|
}
|
|
11011
|
-
function refineForbiddenKeys(value,
|
|
11011
|
+
function refineForbiddenKeys(value, path37, ctx, rejectSource) {
|
|
11012
11012
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
11013
11013
|
return;
|
|
11014
11014
|
}
|
|
@@ -11016,12 +11016,12 @@ function refineForbiddenKeys(value, path31, ctx, rejectSource) {
|
|
|
11016
11016
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
11017
11017
|
ctx.addIssue({
|
|
11018
11018
|
code: external_exports.ZodIssueCode.custom,
|
|
11019
|
-
path: [...
|
|
11019
|
+
path: [...path37, key],
|
|
11020
11020
|
message: `forbidden key "${key}" (prototype-pollution surface)`
|
|
11021
11021
|
});
|
|
11022
11022
|
continue;
|
|
11023
11023
|
}
|
|
11024
|
-
if (rejectSource &&
|
|
11024
|
+
if (rejectSource && path37.length === 0 && key === "source") {
|
|
11025
11025
|
ctx.addIssue({
|
|
11026
11026
|
code: external_exports.ZodIssueCode.custom,
|
|
11027
11027
|
path: ["source"],
|
|
@@ -11029,21 +11029,21 @@ function refineForbiddenKeys(value, path31, ctx, rejectSource) {
|
|
|
11029
11029
|
});
|
|
11030
11030
|
continue;
|
|
11031
11031
|
}
|
|
11032
|
-
refineForbiddenKeys(value[key], [...
|
|
11032
|
+
refineForbiddenKeys(value[key], [...path37, key], ctx, false);
|
|
11033
11033
|
}
|
|
11034
11034
|
}
|
|
11035
|
-
function rejectForbiddenKeys(value,
|
|
11035
|
+
function rejectForbiddenKeys(value, path37, rejectSource) {
|
|
11036
11036
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
11037
11037
|
return;
|
|
11038
11038
|
}
|
|
11039
11039
|
for (const key of Object.keys(value)) {
|
|
11040
11040
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
11041
|
-
throw new Error(`[manifest] ${
|
|
11041
|
+
throw new Error(`[manifest] ${path37}: forbidden key "${key}" (prototype-pollution surface)`);
|
|
11042
11042
|
}
|
|
11043
11043
|
if (rejectSource && key === "source") {
|
|
11044
|
-
throw new Error(`[manifest] ${
|
|
11044
|
+
throw new Error(`[manifest] ${path37}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
|
|
11045
11045
|
}
|
|
11046
|
-
rejectForbiddenKeys(value[key], `${
|
|
11046
|
+
rejectForbiddenKeys(value[key], `${path37}.${key}`, false);
|
|
11047
11047
|
}
|
|
11048
11048
|
}
|
|
11049
11049
|
function unknownTopLevelKeys(parsed) {
|
|
@@ -12116,10 +12116,10 @@ function mergeDefs(...defs) {
|
|
|
12116
12116
|
function cloneDef(schema) {
|
|
12117
12117
|
return mergeDefs(schema._zod.def);
|
|
12118
12118
|
}
|
|
12119
|
-
function getElementAtPath(obj,
|
|
12120
|
-
if (!
|
|
12119
|
+
function getElementAtPath(obj, path37) {
|
|
12120
|
+
if (!path37)
|
|
12121
12121
|
return obj;
|
|
12122
|
-
return
|
|
12122
|
+
return path37.reduce((acc, key) => acc?.[key], obj);
|
|
12123
12123
|
}
|
|
12124
12124
|
function promiseAllObject(promisesObj) {
|
|
12125
12125
|
const keys = Object.keys(promisesObj);
|
|
@@ -12528,11 +12528,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
12528
12528
|
}
|
|
12529
12529
|
return false;
|
|
12530
12530
|
}
|
|
12531
|
-
function prefixIssues(
|
|
12531
|
+
function prefixIssues(path37, issues) {
|
|
12532
12532
|
return issues.map((iss) => {
|
|
12533
12533
|
var _a3;
|
|
12534
12534
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
12535
|
-
iss.path.unshift(
|
|
12535
|
+
iss.path.unshift(path37);
|
|
12536
12536
|
return iss;
|
|
12537
12537
|
});
|
|
12538
12538
|
}
|
|
@@ -12679,16 +12679,16 @@ function flattenError(error2, mapper = (issue2) => issue2.message) {
|
|
|
12679
12679
|
}
|
|
12680
12680
|
function formatError(error2, mapper = (issue2) => issue2.message) {
|
|
12681
12681
|
const fieldErrors = { _errors: [] };
|
|
12682
|
-
const processError = (error3,
|
|
12682
|
+
const processError = (error3, path37 = []) => {
|
|
12683
12683
|
for (const issue2 of error3.issues) {
|
|
12684
12684
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
12685
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
12685
|
+
issue2.errors.map((issues) => processError({ issues }, [...path37, ...issue2.path]));
|
|
12686
12686
|
} else if (issue2.code === "invalid_key") {
|
|
12687
|
-
processError({ issues: issue2.issues }, [...
|
|
12687
|
+
processError({ issues: issue2.issues }, [...path37, ...issue2.path]);
|
|
12688
12688
|
} else if (issue2.code === "invalid_element") {
|
|
12689
|
-
processError({ issues: issue2.issues }, [...
|
|
12689
|
+
processError({ issues: issue2.issues }, [...path37, ...issue2.path]);
|
|
12690
12690
|
} else {
|
|
12691
|
-
const fullpath = [...
|
|
12691
|
+
const fullpath = [...path37, ...issue2.path];
|
|
12692
12692
|
if (fullpath.length === 0) {
|
|
12693
12693
|
fieldErrors._errors.push(mapper(issue2));
|
|
12694
12694
|
} else {
|
|
@@ -23327,8 +23327,8 @@ var AuthClient = class {
|
|
|
23327
23327
|
throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
|
|
23328
23328
|
}
|
|
23329
23329
|
}
|
|
23330
|
-
async request(method,
|
|
23331
|
-
const url2 = `${this.baseUrl}${
|
|
23330
|
+
async request(method, path37, body, attempt = 0) {
|
|
23331
|
+
const url2 = `${this.baseUrl}${path37}`;
|
|
23332
23332
|
const controller = new AbortController();
|
|
23333
23333
|
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
23334
23334
|
const headers = {};
|
|
@@ -23346,7 +23346,7 @@ var AuthClient = class {
|
|
|
23346
23346
|
} catch (err) {
|
|
23347
23347
|
if (attempt < RETRY_COUNT && isTransient(err)) {
|
|
23348
23348
|
await sleep(RETRY_BACKOFF_MS * (attempt + 1));
|
|
23349
|
-
return this.request(method,
|
|
23349
|
+
return this.request(method, path37, body, attempt + 1);
|
|
23350
23350
|
}
|
|
23351
23351
|
throw err;
|
|
23352
23352
|
} finally {
|
|
@@ -24197,12 +24197,12 @@ function register3(server, _ctx, _initError) {
|
|
|
24197
24197
|
registry2.close();
|
|
24198
24198
|
}
|
|
24199
24199
|
try {
|
|
24200
|
-
const { default:
|
|
24201
|
-
const { default:
|
|
24202
|
-
const { default:
|
|
24203
|
-
const tokenPath =
|
|
24204
|
-
if (
|
|
24205
|
-
const token =
|
|
24200
|
+
const { default: fs34 } = await import("node:fs");
|
|
24201
|
+
const { default: os21 } = await import("node:os");
|
|
24202
|
+
const { default: path37 } = await import("node:path");
|
|
24203
|
+
const tokenPath = path37.join(os21.homedir(), ".olam", "host-cp.token");
|
|
24204
|
+
if (fs34.existsSync(tokenPath)) {
|
|
24205
|
+
const token = fs34.readFileSync(tokenPath, "utf-8").trim();
|
|
24206
24206
|
await fetch("http://127.0.0.1:19000/api/admin/world-pr", {
|
|
24207
24207
|
method: "POST",
|
|
24208
24208
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
|
|
@@ -24639,10 +24639,10 @@ function extractMcpConfig(claudeJsonPath) {
|
|
|
24639
24639
|
}
|
|
24640
24640
|
return { mcpServers, secrets };
|
|
24641
24641
|
}
|
|
24642
|
-
function readOptional(
|
|
24643
|
-
if (!existsSync6(
|
|
24642
|
+
function readOptional(path37) {
|
|
24643
|
+
if (!existsSync6(path37)) return null;
|
|
24644
24644
|
try {
|
|
24645
|
-
return readFileSync5(
|
|
24645
|
+
return readFileSync5(path37, "utf8");
|
|
24646
24646
|
} catch {
|
|
24647
24647
|
return null;
|
|
24648
24648
|
}
|
|
@@ -26058,8 +26058,8 @@ var CloudflareProvider = class extends ComputeProvider {
|
|
|
26058
26058
|
// -----------------------------------------------------------------------
|
|
26059
26059
|
// Internal fetch helper
|
|
26060
26060
|
// -----------------------------------------------------------------------
|
|
26061
|
-
async request(
|
|
26062
|
-
const url2 = `${this.config.workerUrl}${
|
|
26061
|
+
async request(path37, method, body) {
|
|
26062
|
+
const url2 = `${this.config.workerUrl}${path37}`;
|
|
26063
26063
|
const bearer = await this.config.mintToken();
|
|
26064
26064
|
const headers = {
|
|
26065
26065
|
Authorization: `Bearer ${bearer}`
|
|
@@ -28510,10 +28510,10 @@ async function writeManifest(args) {
|
|
|
28510
28510
|
capturedAt: args.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
28511
28511
|
shots: entries
|
|
28512
28512
|
};
|
|
28513
|
-
const
|
|
28514
|
-
await writeFile(
|
|
28513
|
+
const path37 = join13(args.outDir, "manifest.json");
|
|
28514
|
+
await writeFile(path37, `${JSON.stringify(manifest, null, 2)}
|
|
28515
28515
|
`, "utf8");
|
|
28516
|
-
return { path:
|
|
28516
|
+
return { path: path37, manifest };
|
|
28517
28517
|
}
|
|
28518
28518
|
|
|
28519
28519
|
// ../mcp-server/src/tools/_capture/proxy.ts
|
|
@@ -28767,9 +28767,9 @@ async function startProxy(opts) {
|
|
|
28767
28767
|
const liveCompiled = verified.allowedPaths.map(compileGlob);
|
|
28768
28768
|
const target = parseRequestTarget(req);
|
|
28769
28769
|
if (!target) return httpReject(400, "invalid_target");
|
|
28770
|
-
const
|
|
28771
|
-
if (!liveCompiled.some((re) => re.test(
|
|
28772
|
-
return httpReject(403, "outside_allow_list", { path:
|
|
28770
|
+
const path37 = target.pathname;
|
|
28771
|
+
if (!liveCompiled.some((re) => re.test(path37))) {
|
|
28772
|
+
return httpReject(403, "outside_allow_list", { path: path37 });
|
|
28773
28773
|
}
|
|
28774
28774
|
const headerWorld = req.headers[WORLD_ASSERT_HEADER];
|
|
28775
28775
|
const headerWorldStr = typeof headerWorld === "string" ? headerWorld : Array.isArray(headerWorld) && headerWorld.length > 0 ? headerWorld[0] : void 0;
|
|
@@ -29548,14 +29548,14 @@ async function runShot(browser, shot, outDir, format, jpegQuality, allowEval, as
|
|
|
29548
29548
|
await page.waitForTimeout(shot.afterLoadMs);
|
|
29549
29549
|
}
|
|
29550
29550
|
const ext = format === "jpeg" ? "jpg" : "png";
|
|
29551
|
-
const
|
|
29551
|
+
const path37 = join14(outDir, `${shot.name}.${ext}`);
|
|
29552
29552
|
await page.screenshot({
|
|
29553
|
-
path:
|
|
29553
|
+
path: path37,
|
|
29554
29554
|
type: format,
|
|
29555
29555
|
...format === "jpeg" ? { quality: jpegQuality } : {},
|
|
29556
29556
|
fullPage: false
|
|
29557
29557
|
});
|
|
29558
|
-
return { name: shot.name, path:
|
|
29558
|
+
return { name: shot.name, path: path37, urlRedacted: redactUrl(shot.url), viewport };
|
|
29559
29559
|
} finally {
|
|
29560
29560
|
await context.close();
|
|
29561
29561
|
}
|
|
@@ -29999,12 +29999,12 @@ function openUrl(url2) {
|
|
|
29999
29999
|
var HOST_CP_URL = "http://127.0.0.1:19000";
|
|
30000
30000
|
async function readHostCpToken2() {
|
|
30001
30001
|
try {
|
|
30002
|
-
const { default:
|
|
30003
|
-
const { default:
|
|
30004
|
-
const { default:
|
|
30005
|
-
const tp =
|
|
30006
|
-
if (!
|
|
30007
|
-
return { token:
|
|
30002
|
+
const { default: fs34 } = await import("node:fs");
|
|
30003
|
+
const { default: os21 } = await import("node:os");
|
|
30004
|
+
const { default: path37 } = await import("node:path");
|
|
30005
|
+
const tp = path37.join(os21.homedir(), ".olam", "host-cp.token");
|
|
30006
|
+
if (!fs34.existsSync(tp)) return { token: null };
|
|
30007
|
+
return { token: fs34.readFileSync(tp, "utf-8").trim() };
|
|
30008
30008
|
} catch {
|
|
30009
30009
|
return { token: null };
|
|
30010
30010
|
}
|
|
@@ -30240,6 +30240,22 @@ init_v3();
|
|
|
30240
30240
|
// ../core/dist/global-config/schema.js
|
|
30241
30241
|
init_v3();
|
|
30242
30242
|
init_schema();
|
|
30243
|
+
|
|
30244
|
+
// ../core/dist/skill-sources/schema.js
|
|
30245
|
+
init_v3();
|
|
30246
|
+
var SKILL_SOURCE_ID_LENGTH = 12;
|
|
30247
|
+
var NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;
|
|
30248
|
+
var URL_PATTERN = /^(?:https?:\/\/|git@|ssh:\/\/|file:\/\/|\/).+/;
|
|
30249
|
+
var SkillSourceSchema = external_exports.object({
|
|
30250
|
+
id: external_exports.string().length(SKILL_SOURCE_ID_LENGTH, `skill-source id must be exactly ${SKILL_SOURCE_ID_LENGTH} chars (sha256-of-url prefix)`).regex(/^[a-f0-9]+$/, "skill-source id must be lowercase hex"),
|
|
30251
|
+
name: external_exports.string().regex(NAME_PATTERN, "skill-source name must be ASCII lowercase + digits + dash (1-64 chars, no leading/trailing dash)"),
|
|
30252
|
+
gitUrl: external_exports.string().min(1, "gitUrl must not be empty").regex(URL_PATTERN, "gitUrl must look like a git URL (https://, git@, ssh://, file://, or absolute path)"),
|
|
30253
|
+
branch: external_exports.string().min(1, "branch must not be empty").default("main"),
|
|
30254
|
+
addedAt: external_exports.number().int().nonnegative(),
|
|
30255
|
+
lastPulledSha: external_exports.string().regex(/^[a-f0-9]{40}$/, "lastPulledSha must be a 40-char lowercase hex git SHA").optional()
|
|
30256
|
+
});
|
|
30257
|
+
|
|
30258
|
+
// ../core/dist/global-config/schema.js
|
|
30243
30259
|
function isAbsoluteOrTilde(p) {
|
|
30244
30260
|
return p.startsWith("/") || p === "~" || p.startsWith("~/");
|
|
30245
30261
|
}
|
|
@@ -30292,7 +30308,8 @@ var RunbookSchema = external_exports.object({
|
|
|
30292
30308
|
var GlobalConfigSchema = external_exports.object({
|
|
30293
30309
|
schemaVersion: external_exports.literal(1),
|
|
30294
30310
|
repos: external_exports.array(RepoEntrySchema).optional().default([]),
|
|
30295
|
-
runbooks: external_exports.array(RunbookSchema).optional().default([])
|
|
30311
|
+
runbooks: external_exports.array(RunbookSchema).optional().default([]),
|
|
30312
|
+
skillSources: external_exports.array(SkillSourceSchema).optional().default([])
|
|
30296
30313
|
}).strip().superRefine((val, ctx) => {
|
|
30297
30314
|
const repoNames = val.repos.map((r) => r.name);
|
|
30298
30315
|
const repoDupes = repoNames.filter((n, i) => repoNames.indexOf(n) !== i);
|
|
@@ -30304,11 +30321,22 @@ var GlobalConfigSchema = external_exports.object({
|
|
|
30304
30321
|
for (const d of rbDupes) {
|
|
30305
30322
|
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: `duplicate runbook name: "${d}"`, path: ["runbooks"] });
|
|
30306
30323
|
}
|
|
30324
|
+
const skillIds = val.skillSources.map((s) => s.id);
|
|
30325
|
+
const skillIdDupes = skillIds.filter((n, i) => skillIds.indexOf(n) !== i);
|
|
30326
|
+
for (const d of skillIdDupes) {
|
|
30327
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: `duplicate skill-source id: "${d}"`, path: ["skillSources"] });
|
|
30328
|
+
}
|
|
30329
|
+
const skillNames = val.skillSources.map((s) => s.name);
|
|
30330
|
+
const skillNameDupes = skillNames.filter((n, i) => skillNames.indexOf(n) !== i);
|
|
30331
|
+
for (const d of skillNameDupes) {
|
|
30332
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: `duplicate skill-source name: "${d}"`, path: ["skillSources"] });
|
|
30333
|
+
}
|
|
30307
30334
|
});
|
|
30308
30335
|
var DEFAULT_GLOBAL_CONFIG = {
|
|
30309
30336
|
schemaVersion: 1,
|
|
30310
30337
|
repos: [],
|
|
30311
|
-
runbooks: []
|
|
30338
|
+
runbooks: [],
|
|
30339
|
+
skillSources: []
|
|
30312
30340
|
};
|
|
30313
30341
|
|
|
30314
30342
|
// ../core/dist/global-config/store.js
|
|
@@ -30622,6 +30650,627 @@ function repoEntryToRepoConfig(entry) {
|
|
|
30622
30650
|
return config2;
|
|
30623
30651
|
}
|
|
30624
30652
|
|
|
30653
|
+
// ../core/dist/skill-sources/store.js
|
|
30654
|
+
import * as crypto3 from "node:crypto";
|
|
30655
|
+
function deriveSkillSourceId(gitUrl) {
|
|
30656
|
+
return crypto3.createHash("sha256").update(gitUrl).digest("hex").slice(0, SKILL_SOURCE_ID_LENGTH);
|
|
30657
|
+
}
|
|
30658
|
+
function listSkillSources() {
|
|
30659
|
+
return readGlobalConfig().skillSources;
|
|
30660
|
+
}
|
|
30661
|
+
function getSkillSource(id) {
|
|
30662
|
+
return readGlobalConfig().skillSources.find((s) => s.id === id);
|
|
30663
|
+
}
|
|
30664
|
+
function addSkillSource(entry) {
|
|
30665
|
+
const config2 = readGlobalConfig();
|
|
30666
|
+
const id = deriveSkillSourceId(entry.gitUrl);
|
|
30667
|
+
if (config2.skillSources.some((s) => s.id === id)) {
|
|
30668
|
+
throw new Error(`skill-source "${entry.gitUrl}" already registered (id "${id}"). Use "olam skills source list" to inspect.`);
|
|
30669
|
+
}
|
|
30670
|
+
if (config2.skillSources.some((s) => s.name === entry.name)) {
|
|
30671
|
+
throw new Error(`skill-source name "${entry.name}" already in use. Pick a different display name.`);
|
|
30672
|
+
}
|
|
30673
|
+
const now = Date.now();
|
|
30674
|
+
const newEntry = {
|
|
30675
|
+
id,
|
|
30676
|
+
name: entry.name,
|
|
30677
|
+
gitUrl: entry.gitUrl,
|
|
30678
|
+
branch: entry.branch ?? "main",
|
|
30679
|
+
addedAt: now
|
|
30680
|
+
};
|
|
30681
|
+
writeGlobalConfig({ ...config2, skillSources: [...config2.skillSources, newEntry] });
|
|
30682
|
+
return newEntry;
|
|
30683
|
+
}
|
|
30684
|
+
function removeSkillSource(id) {
|
|
30685
|
+
const config2 = readGlobalConfig();
|
|
30686
|
+
if (!config2.skillSources.some((s) => s.id === id)) {
|
|
30687
|
+
throw new Error(`skill-source "${id}" is not registered. Run "olam skills source list" to see registered sources.`);
|
|
30688
|
+
}
|
|
30689
|
+
writeGlobalConfig({
|
|
30690
|
+
...config2,
|
|
30691
|
+
skillSources: config2.skillSources.filter((s) => s.id !== id)
|
|
30692
|
+
});
|
|
30693
|
+
}
|
|
30694
|
+
function updateSkillSource(id, patch) {
|
|
30695
|
+
const config2 = readGlobalConfig();
|
|
30696
|
+
const idx = config2.skillSources.findIndex((s) => s.id === id);
|
|
30697
|
+
if (idx === -1) {
|
|
30698
|
+
throw new Error(`skill-source "${id}" is not registered. Run "olam skills source list" to see registered sources.`);
|
|
30699
|
+
}
|
|
30700
|
+
if (patch.name !== void 0) {
|
|
30701
|
+
const collision = config2.skillSources.find((s, i) => i !== idx && s.name === patch.name);
|
|
30702
|
+
if (collision !== void 0) {
|
|
30703
|
+
throw new Error(`skill-source name "${patch.name}" already in use by id "${collision.id}".`);
|
|
30704
|
+
}
|
|
30705
|
+
}
|
|
30706
|
+
const existing = config2.skillSources[idx];
|
|
30707
|
+
const updated = {
|
|
30708
|
+
...existing,
|
|
30709
|
+
...patch.name !== void 0 ? { name: patch.name } : {},
|
|
30710
|
+
...patch.branch !== void 0 ? { branch: patch.branch } : {},
|
|
30711
|
+
...patch.lastPulledSha !== void 0 ? { lastPulledSha: patch.lastPulledSha } : {}
|
|
30712
|
+
};
|
|
30713
|
+
const next = [...config2.skillSources];
|
|
30714
|
+
next[idx] = updated;
|
|
30715
|
+
writeGlobalConfig({ ...config2, skillSources: next });
|
|
30716
|
+
return updated;
|
|
30717
|
+
}
|
|
30718
|
+
|
|
30719
|
+
// ../core/dist/skill-sources/clone.js
|
|
30720
|
+
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
30721
|
+
import * as fs13 from "node:fs";
|
|
30722
|
+
import * as os9 from "node:os";
|
|
30723
|
+
import * as path15 from "node:path";
|
|
30724
|
+
function skillSourcesRootDir() {
|
|
30725
|
+
const override = process.env["OLAM_SKILL_SOURCES_DIR"];
|
|
30726
|
+
if (override && override.length > 0)
|
|
30727
|
+
return override;
|
|
30728
|
+
return path15.join(os9.homedir(), ".olam", "state", "skill-sources");
|
|
30729
|
+
}
|
|
30730
|
+
function skillSourceClonePath(id) {
|
|
30731
|
+
return path15.join(skillSourcesRootDir(), id);
|
|
30732
|
+
}
|
|
30733
|
+
var SkillSourceGitError = class extends Error {
|
|
30734
|
+
op;
|
|
30735
|
+
gitUrl;
|
|
30736
|
+
constructor(op, gitUrl, cause) {
|
|
30737
|
+
const msg = cause instanceof Error ? cause.message : String(cause);
|
|
30738
|
+
super(`git ${op} failed for "${gitUrl}": ${msg}`);
|
|
30739
|
+
this.op = op;
|
|
30740
|
+
this.gitUrl = gitUrl;
|
|
30741
|
+
this.name = "SkillSourceGitError";
|
|
30742
|
+
this.cause = cause;
|
|
30743
|
+
}
|
|
30744
|
+
};
|
|
30745
|
+
function runGit(args, cwd) {
|
|
30746
|
+
try {
|
|
30747
|
+
return execFileSync2("git", args, {
|
|
30748
|
+
cwd,
|
|
30749
|
+
encoding: "utf-8",
|
|
30750
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
30751
|
+
});
|
|
30752
|
+
} catch (err) {
|
|
30753
|
+
throw err;
|
|
30754
|
+
}
|
|
30755
|
+
}
|
|
30756
|
+
function cloneSkillSource(opts) {
|
|
30757
|
+
const clonePath = skillSourceClonePath(opts.id);
|
|
30758
|
+
if (fs13.existsSync(clonePath)) {
|
|
30759
|
+
throw new Error(`clone path "${clonePath}" already exists. Remove the existing skill-source first.`);
|
|
30760
|
+
}
|
|
30761
|
+
fs13.mkdirSync(skillSourcesRootDir(), { recursive: true });
|
|
30762
|
+
try {
|
|
30763
|
+
runGit(["clone", "--depth", "1", "--branch", opts.branch, opts.gitUrl, clonePath]);
|
|
30764
|
+
} catch (err) {
|
|
30765
|
+
if (fs13.existsSync(clonePath)) {
|
|
30766
|
+
fs13.rmSync(clonePath, { recursive: true, force: true });
|
|
30767
|
+
}
|
|
30768
|
+
throw new SkillSourceGitError("clone", opts.gitUrl, err);
|
|
30769
|
+
}
|
|
30770
|
+
let headSha;
|
|
30771
|
+
try {
|
|
30772
|
+
headSha = runGit(["rev-parse", "HEAD"], clonePath).trim();
|
|
30773
|
+
} catch (err) {
|
|
30774
|
+
throw new SkillSourceGitError("rev-parse", opts.gitUrl, err);
|
|
30775
|
+
}
|
|
30776
|
+
return { clonePath, headSha };
|
|
30777
|
+
}
|
|
30778
|
+
function pullSkillSource(opts) {
|
|
30779
|
+
const clonePath = skillSourceClonePath(opts.id);
|
|
30780
|
+
if (!fs13.existsSync(clonePath)) {
|
|
30781
|
+
throw new Error(`clone path "${clonePath}" does not exist. Run "olam skills source add" first.`);
|
|
30782
|
+
}
|
|
30783
|
+
try {
|
|
30784
|
+
runGit(["fetch", "origin", opts.branch], clonePath);
|
|
30785
|
+
runGit(["reset", "--hard", `origin/${opts.branch}`], clonePath);
|
|
30786
|
+
} catch (err) {
|
|
30787
|
+
throw new SkillSourceGitError("fetch/reset", opts.gitUrl, err);
|
|
30788
|
+
}
|
|
30789
|
+
try {
|
|
30790
|
+
const headSha = runGit(["rev-parse", "HEAD"], clonePath).trim();
|
|
30791
|
+
return { headSha };
|
|
30792
|
+
} catch (err) {
|
|
30793
|
+
throw new SkillSourceGitError("rev-parse", opts.gitUrl, err);
|
|
30794
|
+
}
|
|
30795
|
+
}
|
|
30796
|
+
function removeSkillSourceClone(id) {
|
|
30797
|
+
const clonePath = skillSourceClonePath(id);
|
|
30798
|
+
if (fs13.existsSync(clonePath)) {
|
|
30799
|
+
fs13.rmSync(clonePath, { recursive: true, force: true });
|
|
30800
|
+
}
|
|
30801
|
+
}
|
|
30802
|
+
|
|
30803
|
+
// ../core/dist/skill-sync/artifact-resolver.js
|
|
30804
|
+
import * as fs14 from "node:fs";
|
|
30805
|
+
import * as path16 from "node:path";
|
|
30806
|
+
function resolveSubscriptions(opts) {
|
|
30807
|
+
const { clonePath, atlasUser } = opts;
|
|
30808
|
+
if (atlasUser) {
|
|
30809
|
+
const subsPath = path16.join(clonePath, "members", atlasUser, "subscriptions.json");
|
|
30810
|
+
if (fs14.existsSync(subsPath)) {
|
|
30811
|
+
try {
|
|
30812
|
+
const parsed = JSON.parse(fs14.readFileSync(subsPath, "utf-8"));
|
|
30813
|
+
if (Array.isArray(parsed?.categories)) {
|
|
30814
|
+
return {
|
|
30815
|
+
categories: parsed.categories.filter((c) => typeof c === "string"),
|
|
30816
|
+
fromSubscriptionsFile: true,
|
|
30817
|
+
atlasUser
|
|
30818
|
+
};
|
|
30819
|
+
}
|
|
30820
|
+
} catch {
|
|
30821
|
+
}
|
|
30822
|
+
}
|
|
30823
|
+
}
|
|
30824
|
+
const catsPath = path16.join(clonePath, "shared", "categories.json");
|
|
30825
|
+
if (fs14.existsSync(catsPath)) {
|
|
30826
|
+
try {
|
|
30827
|
+
const parsed = JSON.parse(fs14.readFileSync(catsPath, "utf-8"));
|
|
30828
|
+
if (Array.isArray(parsed?.categories)) {
|
|
30829
|
+
return {
|
|
30830
|
+
categories: parsed.categories.map((c) => c.id).filter((id) => typeof id === "string"),
|
|
30831
|
+
fromSubscriptionsFile: false,
|
|
30832
|
+
atlasUser
|
|
30833
|
+
};
|
|
30834
|
+
}
|
|
30835
|
+
} catch {
|
|
30836
|
+
}
|
|
30837
|
+
}
|
|
30838
|
+
const sharedDir = path16.join(clonePath, "shared");
|
|
30839
|
+
const cats = [];
|
|
30840
|
+
if (fs14.existsSync(sharedDir)) {
|
|
30841
|
+
for (const name of fs14.readdirSync(sharedDir)) {
|
|
30842
|
+
const dir = path16.join(sharedDir, name);
|
|
30843
|
+
if (!fs14.statSync(dir).isDirectory())
|
|
30844
|
+
continue;
|
|
30845
|
+
if (fs14.existsSync(path16.join(dir, "skills")) || fs14.existsSync(path16.join(dir, "agents"))) {
|
|
30846
|
+
cats.push(name);
|
|
30847
|
+
}
|
|
30848
|
+
}
|
|
30849
|
+
}
|
|
30850
|
+
return { categories: cats, fromSubscriptionsFile: false, atlasUser };
|
|
30851
|
+
}
|
|
30852
|
+
function listDirSafe(dir) {
|
|
30853
|
+
if (!fs14.existsSync(dir))
|
|
30854
|
+
return [];
|
|
30855
|
+
return fs14.readdirSync(dir);
|
|
30856
|
+
}
|
|
30857
|
+
function resolveSkillsDir(opts) {
|
|
30858
|
+
const { sourceId, baseDir } = opts;
|
|
30859
|
+
const out = [];
|
|
30860
|
+
for (const name of listDirSafe(baseDir)) {
|
|
30861
|
+
const subdir = path16.join(baseDir, name);
|
|
30862
|
+
if (!fs14.statSync(subdir).isDirectory())
|
|
30863
|
+
continue;
|
|
30864
|
+
if (!fs14.existsSync(path16.join(subdir, "SKILL.md")))
|
|
30865
|
+
continue;
|
|
30866
|
+
out.push({ kind: "skill", sourceId, sourcePath: subdir, deployBasename: name });
|
|
30867
|
+
const subagentsDir = path16.join(subdir, "references", "agents");
|
|
30868
|
+
if (fs14.existsSync(subagentsDir) && fs14.statSync(subagentsDir).isDirectory()) {
|
|
30869
|
+
for (const f of listDirSafe(subagentsDir)) {
|
|
30870
|
+
if (!f.endsWith(".md"))
|
|
30871
|
+
continue;
|
|
30872
|
+
out.push({
|
|
30873
|
+
kind: "subagent",
|
|
30874
|
+
sourceId,
|
|
30875
|
+
sourcePath: path16.join(subagentsDir, f),
|
|
30876
|
+
deployBasename: f,
|
|
30877
|
+
parentSkill: name
|
|
30878
|
+
});
|
|
30879
|
+
}
|
|
30880
|
+
}
|
|
30881
|
+
}
|
|
30882
|
+
return out;
|
|
30883
|
+
}
|
|
30884
|
+
function resolveAgentsDir(opts) {
|
|
30885
|
+
const { sourceId, baseDir } = opts;
|
|
30886
|
+
const out = [];
|
|
30887
|
+
for (const name of listDirSafe(baseDir)) {
|
|
30888
|
+
const full = path16.join(baseDir, name);
|
|
30889
|
+
const stat = fs14.statSync(full);
|
|
30890
|
+
if (stat.isFile() && name.endsWith(".md")) {
|
|
30891
|
+
out.push({ kind: "agent", sourceId, sourcePath: full, deployBasename: name });
|
|
30892
|
+
} else if (stat.isDirectory()) {
|
|
30893
|
+
for (const f of listDirSafe(full)) {
|
|
30894
|
+
if (!f.endsWith(".md"))
|
|
30895
|
+
continue;
|
|
30896
|
+
out.push({
|
|
30897
|
+
kind: "agent",
|
|
30898
|
+
sourceId,
|
|
30899
|
+
sourcePath: path16.join(full, f),
|
|
30900
|
+
deployBasename: `${name}-${f}`
|
|
30901
|
+
});
|
|
30902
|
+
}
|
|
30903
|
+
}
|
|
30904
|
+
}
|
|
30905
|
+
return out;
|
|
30906
|
+
}
|
|
30907
|
+
function resolveScriptsDir(opts) {
|
|
30908
|
+
const { sourceId, baseDir } = opts;
|
|
30909
|
+
const out = [];
|
|
30910
|
+
for (const name of listDirSafe(baseDir)) {
|
|
30911
|
+
const full = path16.join(baseDir, name);
|
|
30912
|
+
const stat = fs14.statSync(full);
|
|
30913
|
+
if (stat.isFile() && name.endsWith(".sh")) {
|
|
30914
|
+
out.push({ kind: "script", sourceId, sourcePath: full, deployBasename: name });
|
|
30915
|
+
} else if (stat.isDirectory()) {
|
|
30916
|
+
out.push({ kind: "script", sourceId, sourcePath: full, deployBasename: name });
|
|
30917
|
+
}
|
|
30918
|
+
}
|
|
30919
|
+
return out;
|
|
30920
|
+
}
|
|
30921
|
+
function resolveRulesDir(opts) {
|
|
30922
|
+
const { sourceId, baseDir } = opts;
|
|
30923
|
+
const out = [];
|
|
30924
|
+
for (const name of listDirSafe(baseDir)) {
|
|
30925
|
+
if (!name.endsWith(".md"))
|
|
30926
|
+
continue;
|
|
30927
|
+
const full = path16.join(baseDir, name);
|
|
30928
|
+
if (!fs14.statSync(full).isFile())
|
|
30929
|
+
continue;
|
|
30930
|
+
out.push({ kind: "rule", sourceId, sourcePath: full, deployBasename: name });
|
|
30931
|
+
}
|
|
30932
|
+
return out;
|
|
30933
|
+
}
|
|
30934
|
+
function resolveJsonDir(opts) {
|
|
30935
|
+
const { sourceId, baseDir, kind } = opts;
|
|
30936
|
+
const out = [];
|
|
30937
|
+
for (const name of listDirSafe(baseDir)) {
|
|
30938
|
+
if (!name.endsWith(".json"))
|
|
30939
|
+
continue;
|
|
30940
|
+
const full = path16.join(baseDir, name);
|
|
30941
|
+
if (!fs14.statSync(full).isFile())
|
|
30942
|
+
continue;
|
|
30943
|
+
out.push({ kind, sourceId, sourcePath: full, deployBasename: name });
|
|
30944
|
+
}
|
|
30945
|
+
return out;
|
|
30946
|
+
}
|
|
30947
|
+
function resolveSourceArtifacts(opts) {
|
|
30948
|
+
const { sourceId, clonePath, atlasUser } = opts;
|
|
30949
|
+
const subscription = resolveSubscriptions({ clonePath, atlasUser });
|
|
30950
|
+
const artifacts = [];
|
|
30951
|
+
for (const cat of subscription.categories) {
|
|
30952
|
+
const catDir = path16.join(clonePath, "shared", cat);
|
|
30953
|
+
if (!fs14.existsSync(catDir))
|
|
30954
|
+
continue;
|
|
30955
|
+
artifacts.push(...resolveSkillsDir({ sourceId, baseDir: path16.join(catDir, "skills") }));
|
|
30956
|
+
artifacts.push(...resolveAgentsDir({ sourceId, baseDir: path16.join(catDir, "agents") }));
|
|
30957
|
+
artifacts.push(...resolveScriptsDir({ sourceId, baseDir: path16.join(catDir, "scripts") }));
|
|
30958
|
+
artifacts.push(...resolveRulesDir({ sourceId, baseDir: path16.join(catDir, "rules") }));
|
|
30959
|
+
artifacts.push(...resolveJsonDir({ sourceId, baseDir: path16.join(catDir, "hooks"), kind: "hook" }));
|
|
30960
|
+
artifacts.push(...resolveJsonDir({ sourceId, baseDir: path16.join(catDir, "permissions"), kind: "permission" }));
|
|
30961
|
+
}
|
|
30962
|
+
if (atlasUser) {
|
|
30963
|
+
const memberRoot = path16.join(clonePath, "members", atlasUser);
|
|
30964
|
+
if (fs14.existsSync(memberRoot)) {
|
|
30965
|
+
artifacts.push(...resolveSkillsDir({ sourceId, baseDir: path16.join(memberRoot, "skills") }));
|
|
30966
|
+
artifacts.push(...resolveAgentsDir({ sourceId, baseDir: path16.join(memberRoot, "agents") }));
|
|
30967
|
+
artifacts.push(...resolveScriptsDir({ sourceId, baseDir: path16.join(memberRoot, "scripts") }));
|
|
30968
|
+
artifacts.push(...resolveRulesDir({ sourceId, baseDir: path16.join(memberRoot, "rules") }));
|
|
30969
|
+
artifacts.push(...resolveJsonDir({ sourceId, baseDir: path16.join(memberRoot, "hooks"), kind: "hook" }));
|
|
30970
|
+
artifacts.push(...resolveJsonDir({ sourceId, baseDir: path16.join(memberRoot, "permissions"), kind: "permission" }));
|
|
30971
|
+
}
|
|
30972
|
+
}
|
|
30973
|
+
return { subscription, artifacts };
|
|
30974
|
+
}
|
|
30975
|
+
|
|
30976
|
+
// ../core/dist/skill-sync/symlink-deployer.js
|
|
30977
|
+
import * as fs15 from "node:fs";
|
|
30978
|
+
import * as os10 from "node:os";
|
|
30979
|
+
import * as path17 from "node:path";
|
|
30980
|
+
function claudeDir() {
|
|
30981
|
+
const override = process.env["OLAM_CLAUDE_DIR"];
|
|
30982
|
+
if (override && override.length > 0)
|
|
30983
|
+
return override;
|
|
30984
|
+
return path17.join(os10.homedir(), ".claude");
|
|
30985
|
+
}
|
|
30986
|
+
var BUCKETS = ["commands", "agents", "skills", "scripts", "rules"];
|
|
30987
|
+
function bucketFor(kind) {
|
|
30988
|
+
switch (kind) {
|
|
30989
|
+
case "skill":
|
|
30990
|
+
return "skills";
|
|
30991
|
+
case "agent":
|
|
30992
|
+
return "agents";
|
|
30993
|
+
case "subagent":
|
|
30994
|
+
return "agents";
|
|
30995
|
+
case "script":
|
|
30996
|
+
return "scripts";
|
|
30997
|
+
case "rule":
|
|
30998
|
+
return "rules";
|
|
30999
|
+
case "hook":
|
|
31000
|
+
case "permission":
|
|
31001
|
+
return void 0;
|
|
31002
|
+
}
|
|
31003
|
+
}
|
|
31004
|
+
function cleanManagedSymlinks(claude) {
|
|
31005
|
+
for (const bucket of BUCKETS) {
|
|
31006
|
+
const dir = path17.join(claude, bucket);
|
|
31007
|
+
if (!fs15.existsSync(dir))
|
|
31008
|
+
continue;
|
|
31009
|
+
for (const name of fs15.readdirSync(dir)) {
|
|
31010
|
+
const p = path17.join(dir, name);
|
|
31011
|
+
try {
|
|
31012
|
+
const stat = fs15.lstatSync(p);
|
|
31013
|
+
if (stat.isSymbolicLink()) {
|
|
31014
|
+
fs15.unlinkSync(p);
|
|
31015
|
+
}
|
|
31016
|
+
} catch {
|
|
31017
|
+
}
|
|
31018
|
+
}
|
|
31019
|
+
}
|
|
31020
|
+
}
|
|
31021
|
+
function shadowBackup(link) {
|
|
31022
|
+
const epoch = Math.floor(Date.now() / 1e3);
|
|
31023
|
+
const backup = `${link}.shadow-backup-${epoch}`;
|
|
31024
|
+
fs15.renameSync(link, backup);
|
|
31025
|
+
return backup;
|
|
31026
|
+
}
|
|
31027
|
+
function linkIfNeeded(target, link) {
|
|
31028
|
+
try {
|
|
31029
|
+
const existing = fs15.readlinkSync(link);
|
|
31030
|
+
if (existing === target)
|
|
31031
|
+
return { created: false };
|
|
31032
|
+
} catch {
|
|
31033
|
+
}
|
|
31034
|
+
let isLink = false;
|
|
31035
|
+
try {
|
|
31036
|
+
isLink = fs15.lstatSync(link).isSymbolicLink();
|
|
31037
|
+
} catch {
|
|
31038
|
+
}
|
|
31039
|
+
let backup;
|
|
31040
|
+
if (isLink) {
|
|
31041
|
+
fs15.unlinkSync(link);
|
|
31042
|
+
} else if (fs15.existsSync(link)) {
|
|
31043
|
+
backup = shadowBackup(link);
|
|
31044
|
+
}
|
|
31045
|
+
fs15.symlinkSync(target, link);
|
|
31046
|
+
return { created: true, shadowBackup: backup };
|
|
31047
|
+
}
|
|
31048
|
+
function deployArtifacts(artifacts) {
|
|
31049
|
+
const claude = claudeDir();
|
|
31050
|
+
for (const bucket of BUCKETS) {
|
|
31051
|
+
fs15.mkdirSync(path17.join(claude, bucket), { recursive: true });
|
|
31052
|
+
}
|
|
31053
|
+
cleanManagedSymlinks(claude);
|
|
31054
|
+
const result = { linked: 0, shadowBackups: [], subagentCollisions: [] };
|
|
31055
|
+
const seenAgentBasenames = /* @__PURE__ */ new Map();
|
|
31056
|
+
const collisionLosers = /* @__PURE__ */ new Map();
|
|
31057
|
+
for (const artifact of artifacts) {
|
|
31058
|
+
const bucket = bucketFor(artifact.kind);
|
|
31059
|
+
if (!bucket)
|
|
31060
|
+
continue;
|
|
31061
|
+
if (artifact.kind === "agent" || artifact.kind === "subagent") {
|
|
31062
|
+
const prior = seenAgentBasenames.get(artifact.deployBasename);
|
|
31063
|
+
if (prior) {
|
|
31064
|
+
const losers = collisionLosers.get(artifact.deployBasename) ?? [];
|
|
31065
|
+
losers.push(artifact.sourcePath);
|
|
31066
|
+
collisionLosers.set(artifact.deployBasename, losers);
|
|
31067
|
+
continue;
|
|
31068
|
+
}
|
|
31069
|
+
seenAgentBasenames.set(artifact.deployBasename, artifact.sourcePath);
|
|
31070
|
+
}
|
|
31071
|
+
const linkPath = path17.join(claude, bucket, artifact.deployBasename);
|
|
31072
|
+
const { created, shadowBackup: backup } = linkIfNeeded(artifact.sourcePath, linkPath);
|
|
31073
|
+
if (created)
|
|
31074
|
+
result.linked += 1;
|
|
31075
|
+
if (backup)
|
|
31076
|
+
result.shadowBackups.push(backup);
|
|
31077
|
+
}
|
|
31078
|
+
for (const [name, losers] of collisionLosers.entries()) {
|
|
31079
|
+
const winner = seenAgentBasenames.get(name);
|
|
31080
|
+
result.subagentCollisions.push({ name, winner, losers });
|
|
31081
|
+
}
|
|
31082
|
+
return result;
|
|
31083
|
+
}
|
|
31084
|
+
|
|
31085
|
+
// ../core/dist/skill-sync/settings-merger.js
|
|
31086
|
+
import * as fs16 from "node:fs";
|
|
31087
|
+
import * as os11 from "node:os";
|
|
31088
|
+
import * as path18 from "node:path";
|
|
31089
|
+
var OLAM_SKILLS_MARKER = "_olamSkillsManaged";
|
|
31090
|
+
var BACKUP_RETENTION = 30;
|
|
31091
|
+
function claudeSettingsPath() {
|
|
31092
|
+
const override = process.env["OLAM_CLAUDE_SETTINGS_PATH"];
|
|
31093
|
+
if (override && override.length > 0)
|
|
31094
|
+
return override;
|
|
31095
|
+
return path18.join(claudeDirInternal(), "settings.json");
|
|
31096
|
+
}
|
|
31097
|
+
function claudeDirInternal() {
|
|
31098
|
+
const override = process.env["OLAM_CLAUDE_DIR"];
|
|
31099
|
+
if (override && override.length > 0)
|
|
31100
|
+
return override;
|
|
31101
|
+
return path18.join(os11.homedir(), ".claude");
|
|
31102
|
+
}
|
|
31103
|
+
function settingsBackupDir() {
|
|
31104
|
+
const override = process.env["OLAM_SETTINGS_BACKUP_DIR"];
|
|
31105
|
+
if (override && override.length > 0)
|
|
31106
|
+
return override;
|
|
31107
|
+
return path18.join(os11.homedir(), ".olam", "state", "settings-backups");
|
|
31108
|
+
}
|
|
31109
|
+
function dedupeByMatcher(entries) {
|
|
31110
|
+
const map = /* @__PURE__ */ new Map();
|
|
31111
|
+
for (const e of entries) {
|
|
31112
|
+
map.set(e.matcher ?? "", e);
|
|
31113
|
+
}
|
|
31114
|
+
return [...map.values()];
|
|
31115
|
+
}
|
|
31116
|
+
function tagOlam(entry) {
|
|
31117
|
+
return { ...entry, [OLAM_SKILLS_MARKER]: true };
|
|
31118
|
+
}
|
|
31119
|
+
function readJson(file) {
|
|
31120
|
+
return JSON.parse(fs16.readFileSync(file, "utf-8"));
|
|
31121
|
+
}
|
|
31122
|
+
function rotateBackups(backupDir) {
|
|
31123
|
+
if (!fs16.existsSync(backupDir))
|
|
31124
|
+
return;
|
|
31125
|
+
const files = fs16.readdirSync(backupDir).filter((f) => f.endsWith(".json")).map((f) => ({ name: f, full: path18.join(backupDir, f), mtime: fs16.statSync(path18.join(backupDir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
31126
|
+
for (const f of files.slice(BACKUP_RETENTION)) {
|
|
31127
|
+
try {
|
|
31128
|
+
fs16.unlinkSync(f.full);
|
|
31129
|
+
} catch {
|
|
31130
|
+
}
|
|
31131
|
+
}
|
|
31132
|
+
}
|
|
31133
|
+
function backupSettings() {
|
|
31134
|
+
const src = claudeSettingsPath();
|
|
31135
|
+
if (!fs16.existsSync(src))
|
|
31136
|
+
return void 0;
|
|
31137
|
+
const dir = settingsBackupDir();
|
|
31138
|
+
fs16.mkdirSync(dir, { recursive: true });
|
|
31139
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
31140
|
+
const dest = path18.join(dir, `settings-${stamp}.json`);
|
|
31141
|
+
fs16.copyFileSync(src, dest);
|
|
31142
|
+
rotateBackups(dir);
|
|
31143
|
+
return dest;
|
|
31144
|
+
}
|
|
31145
|
+
function mergeSettings(input) {
|
|
31146
|
+
const settingsPath = claudeSettingsPath();
|
|
31147
|
+
const backupPath = backupSettings();
|
|
31148
|
+
let base = {};
|
|
31149
|
+
if (fs16.existsSync(settingsPath)) {
|
|
31150
|
+
try {
|
|
31151
|
+
base = readJson(settingsPath);
|
|
31152
|
+
} catch {
|
|
31153
|
+
base = {};
|
|
31154
|
+
}
|
|
31155
|
+
}
|
|
31156
|
+
const olamHooksByCategory = /* @__PURE__ */ new Map();
|
|
31157
|
+
for (const file of input.hookFiles) {
|
|
31158
|
+
let parsed;
|
|
31159
|
+
try {
|
|
31160
|
+
parsed = readJson(file);
|
|
31161
|
+
} catch {
|
|
31162
|
+
continue;
|
|
31163
|
+
}
|
|
31164
|
+
if (!parsed.hooks || typeof parsed.hooks !== "object")
|
|
31165
|
+
continue;
|
|
31166
|
+
for (const [category, entries] of Object.entries(parsed.hooks)) {
|
|
31167
|
+
if (!Array.isArray(entries))
|
|
31168
|
+
continue;
|
|
31169
|
+
const list = olamHooksByCategory.get(category) ?? [];
|
|
31170
|
+
list.push(...entries.map(tagOlam));
|
|
31171
|
+
olamHooksByCategory.set(category, list);
|
|
31172
|
+
}
|
|
31173
|
+
}
|
|
31174
|
+
const mergedHooks = {};
|
|
31175
|
+
const existingHooks = base.hooks && typeof base.hooks === "object" ? base.hooks : {};
|
|
31176
|
+
const categories = /* @__PURE__ */ new Set([
|
|
31177
|
+
...Object.keys(existingHooks),
|
|
31178
|
+
...olamHooksByCategory.keys()
|
|
31179
|
+
]);
|
|
31180
|
+
let hooksAdded = 0;
|
|
31181
|
+
for (const cat of categories) {
|
|
31182
|
+
const existing = Array.isArray(existingHooks[cat]) ? existingHooks[cat] : [];
|
|
31183
|
+
const preserved = existing.filter((e) => !e[OLAM_SKILLS_MARKER]);
|
|
31184
|
+
const olam = olamHooksByCategory.get(cat) ?? [];
|
|
31185
|
+
const combined = [...preserved, ...olam];
|
|
31186
|
+
mergedHooks[cat] = dedupeByMatcher(combined);
|
|
31187
|
+
hooksAdded += olam.length;
|
|
31188
|
+
}
|
|
31189
|
+
const permSet = /* @__PURE__ */ new Set();
|
|
31190
|
+
for (const file of input.permissionFiles) {
|
|
31191
|
+
let parsed;
|
|
31192
|
+
try {
|
|
31193
|
+
parsed = readJson(file);
|
|
31194
|
+
} catch {
|
|
31195
|
+
continue;
|
|
31196
|
+
}
|
|
31197
|
+
const allow = parsed.permissions?.allow;
|
|
31198
|
+
if (Array.isArray(allow)) {
|
|
31199
|
+
for (const p of allow)
|
|
31200
|
+
if (typeof p === "string")
|
|
31201
|
+
permSet.add(p);
|
|
31202
|
+
}
|
|
31203
|
+
}
|
|
31204
|
+
const next = {
|
|
31205
|
+
...base,
|
|
31206
|
+
hooks: mergedHooks,
|
|
31207
|
+
permissions: {
|
|
31208
|
+
...base.permissions ?? {},
|
|
31209
|
+
...input.permissionFiles.length > 0 ? { allow: [...permSet] } : {}
|
|
31210
|
+
}
|
|
31211
|
+
};
|
|
31212
|
+
fs16.mkdirSync(path18.dirname(settingsPath), { recursive: true });
|
|
31213
|
+
const tmp = `${settingsPath}.tmp-${process.pid}`;
|
|
31214
|
+
fs16.writeFileSync(tmp, JSON.stringify(next, null, 2) + "\n", { mode: 420 });
|
|
31215
|
+
fs16.renameSync(tmp, settingsPath);
|
|
31216
|
+
return { backupPath, hooksAdded, permissionsCount: permSet.size };
|
|
31217
|
+
}
|
|
31218
|
+
|
|
31219
|
+
// ../core/dist/skill-sync/engine.js
|
|
31220
|
+
import * as fs17 from "node:fs";
|
|
31221
|
+
import * as os12 from "node:os";
|
|
31222
|
+
import * as path19 from "node:path";
|
|
31223
|
+
function resolveAtlasUser(override) {
|
|
31224
|
+
if (override)
|
|
31225
|
+
return override;
|
|
31226
|
+
const claudeDir2 = process.env["OLAM_CLAUDE_DIR"] || path19.join(os12.homedir(), ".claude");
|
|
31227
|
+
const f = path19.join(claudeDir2, ".atlas-user");
|
|
31228
|
+
if (fs17.existsSync(f)) {
|
|
31229
|
+
return fs17.readFileSync(f, "utf-8").trim() || void 0;
|
|
31230
|
+
}
|
|
31231
|
+
return void 0;
|
|
31232
|
+
}
|
|
31233
|
+
async function syncSkills(opts = {}) {
|
|
31234
|
+
const atlasUser = resolveAtlasUser(opts.atlasUser);
|
|
31235
|
+
const sources = listSkillSources();
|
|
31236
|
+
const allArtifacts = [];
|
|
31237
|
+
const perSource = [];
|
|
31238
|
+
for (const source of sources) {
|
|
31239
|
+
const clonePath = skillSourceClonePath(source.id);
|
|
31240
|
+
if (!fs17.existsSync(clonePath))
|
|
31241
|
+
continue;
|
|
31242
|
+
const { artifacts, subscription } = resolveSourceArtifacts({
|
|
31243
|
+
sourceId: source.id,
|
|
31244
|
+
clonePath,
|
|
31245
|
+
atlasUser
|
|
31246
|
+
});
|
|
31247
|
+
allArtifacts.push(...artifacts);
|
|
31248
|
+
perSource.push({
|
|
31249
|
+
sourceId: source.id,
|
|
31250
|
+
name: source.name,
|
|
31251
|
+
artifactCount: artifacts.length,
|
|
31252
|
+
categories: subscription.categories,
|
|
31253
|
+
fromSubscriptionsFile: subscription.fromSubscriptionsFile
|
|
31254
|
+
});
|
|
31255
|
+
}
|
|
31256
|
+
const hookFiles = allArtifacts.filter((a) => a.kind === "hook").map((a) => a.sourcePath);
|
|
31257
|
+
const permissionFiles = allArtifacts.filter((a) => a.kind === "permission").map((a) => a.sourcePath);
|
|
31258
|
+
const summary = {
|
|
31259
|
+
sourceCount: sources.length,
|
|
31260
|
+
artifactCount: allArtifacts.length,
|
|
31261
|
+
hookFileCount: hookFiles.length,
|
|
31262
|
+
permissionFileCount: permissionFiles.length,
|
|
31263
|
+
deploy: void 0,
|
|
31264
|
+
merge: void 0,
|
|
31265
|
+
perSource
|
|
31266
|
+
};
|
|
31267
|
+
if (opts.dryRun)
|
|
31268
|
+
return summary;
|
|
31269
|
+
summary.deploy = deployArtifacts(allArtifacts);
|
|
31270
|
+
summary.merge = mergeSettings({ hookFiles, permissionFiles });
|
|
31271
|
+
return summary;
|
|
31272
|
+
}
|
|
31273
|
+
|
|
30625
31274
|
// ../mcp-server/src/tools/repo.ts
|
|
30626
31275
|
function asMessage4(err) {
|
|
30627
31276
|
return err instanceof Error ? err.message : String(err);
|
|
@@ -30650,9 +31299,9 @@ function register22(server, _ctx, _initError) {
|
|
|
30650
31299
|
description: external_exports.string().optional().describe("Optional human-readable description."),
|
|
30651
31300
|
defaultBranch: external_exports.string().optional().describe("Default branch name (e.g. main).")
|
|
30652
31301
|
},
|
|
30653
|
-
async ({ name, path:
|
|
31302
|
+
async ({ name, path: path37, description, defaultBranch }) => {
|
|
30654
31303
|
try {
|
|
30655
|
-
const entry = addRepo({ name, path:
|
|
31304
|
+
const entry = addRepo({ name, path: path37, description, defaultBranch });
|
|
30656
31305
|
return {
|
|
30657
31306
|
content: [{
|
|
30658
31307
|
type: "text",
|
|
@@ -30693,9 +31342,9 @@ function register22(server, _ctx, _initError) {
|
|
|
30693
31342
|
description: external_exports.string().optional().describe("New description."),
|
|
30694
31343
|
defaultBranch: external_exports.string().optional().describe("New default branch.")
|
|
30695
31344
|
},
|
|
30696
|
-
async ({ name, path:
|
|
31345
|
+
async ({ name, path: path37, description, defaultBranch }) => {
|
|
30697
31346
|
try {
|
|
30698
|
-
const entry = updateRepo(name, { path:
|
|
31347
|
+
const entry = updateRepo(name, { path: path37, description, defaultBranch });
|
|
30699
31348
|
return {
|
|
30700
31349
|
content: [{
|
|
30701
31350
|
type: "text",
|
|
@@ -30716,15 +31365,15 @@ __export(process_port_exports, {
|
|
|
30716
31365
|
resolveHostCpToken: () => resolveHostCpToken
|
|
30717
31366
|
});
|
|
30718
31367
|
init_v3();
|
|
30719
|
-
import
|
|
30720
|
-
import
|
|
30721
|
-
import
|
|
31368
|
+
import fs18 from "node:fs";
|
|
31369
|
+
import os13 from "node:os";
|
|
31370
|
+
import path20 from "node:path";
|
|
30722
31371
|
var HOST_CP_BASE = "http://127.0.0.1:19000";
|
|
30723
31372
|
function resolveHostCpToken() {
|
|
30724
31373
|
const envToken = process.env["OLAM_HOST_CP_TOKEN"];
|
|
30725
31374
|
if (envToken) return envToken;
|
|
30726
|
-
const tokenPath =
|
|
30727
|
-
if (
|
|
31375
|
+
const tokenPath = path20.join(os13.homedir(), ".olam", "host-cp.token");
|
|
31376
|
+
if (fs18.existsSync(tokenPath)) return fs18.readFileSync(tokenPath, "utf-8").trim();
|
|
30728
31377
|
return null;
|
|
30729
31378
|
}
|
|
30730
31379
|
function tokenMissingError() {
|
|
@@ -31004,10 +31653,254 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
|
|
|
31004
31653
|
);
|
|
31005
31654
|
}
|
|
31006
31655
|
|
|
31656
|
+
// ../mcp-server/src/tools/skill-source.ts
|
|
31657
|
+
var skill_source_exports = {};
|
|
31658
|
+
__export(skill_source_exports, {
|
|
31659
|
+
register: () => register25
|
|
31660
|
+
});
|
|
31661
|
+
init_v3();
|
|
31662
|
+
function asMessage7(err) {
|
|
31663
|
+
return err instanceof Error ? err.message : String(err);
|
|
31664
|
+
}
|
|
31665
|
+
function ok(data) {
|
|
31666
|
+
return {
|
|
31667
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
31668
|
+
};
|
|
31669
|
+
}
|
|
31670
|
+
function fail(err) {
|
|
31671
|
+
return {
|
|
31672
|
+
content: [{ type: "text", text: asMessage7(err) }],
|
|
31673
|
+
isError: true
|
|
31674
|
+
};
|
|
31675
|
+
}
|
|
31676
|
+
function register25(server, _ctx, _initError) {
|
|
31677
|
+
server.tool(
|
|
31678
|
+
"olam_skills_source_list",
|
|
31679
|
+
"List every registered skill source. Returns { skillSources: SkillSource[] }.",
|
|
31680
|
+
{},
|
|
31681
|
+
async () => {
|
|
31682
|
+
return ok({ skillSources: listSkillSources() });
|
|
31683
|
+
}
|
|
31684
|
+
);
|
|
31685
|
+
server.tool(
|
|
31686
|
+
"olam_skills_source_add",
|
|
31687
|
+
"Register and clone a skill source. Clones to ~/.olam/state/skill-sources/<id>/. Atomic: rolls back the state-store entry if the clone fails.",
|
|
31688
|
+
{
|
|
31689
|
+
name: external_exports.string().min(1).describe("Display name (lowercase, digits, dash; 1\u201364 chars)."),
|
|
31690
|
+
gitUrl: external_exports.string().min(1).describe("Git URL (https://, git@, ssh://, file://, or absolute path)."),
|
|
31691
|
+
branch: external_exports.string().min(1).optional().describe('Branch to track. Defaults to "main".')
|
|
31692
|
+
},
|
|
31693
|
+
async ({ name, gitUrl, branch }) => {
|
|
31694
|
+
let entry;
|
|
31695
|
+
try {
|
|
31696
|
+
entry = addSkillSource({ name, gitUrl, branch });
|
|
31697
|
+
} catch (err) {
|
|
31698
|
+
return fail(err);
|
|
31699
|
+
}
|
|
31700
|
+
try {
|
|
31701
|
+
const result = cloneSkillSource({
|
|
31702
|
+
gitUrl: entry.gitUrl,
|
|
31703
|
+
branch: entry.branch,
|
|
31704
|
+
id: entry.id
|
|
31705
|
+
});
|
|
31706
|
+
const updated = updateSkillSource(entry.id, { lastPulledSha: result.headSha });
|
|
31707
|
+
return ok({
|
|
31708
|
+
source: updated,
|
|
31709
|
+
clonePath: result.clonePath,
|
|
31710
|
+
message: `Registered skill source "${entry.name}" (${entry.id}) @ ${result.headSha.slice(0, 8)}.`
|
|
31711
|
+
});
|
|
31712
|
+
} catch (err) {
|
|
31713
|
+
try {
|
|
31714
|
+
removeSkillSource(entry.id);
|
|
31715
|
+
} catch {
|
|
31716
|
+
}
|
|
31717
|
+
return fail(err);
|
|
31718
|
+
}
|
|
31719
|
+
}
|
|
31720
|
+
);
|
|
31721
|
+
server.tool(
|
|
31722
|
+
"olam_skills_source_remove",
|
|
31723
|
+
"Remove a registered skill source. Deletes the clone directory and the state entry.",
|
|
31724
|
+
{
|
|
31725
|
+
id: external_exports.string().length(12).describe("Skill source id (from olam_skills_source_list).")
|
|
31726
|
+
},
|
|
31727
|
+
async ({ id }) => {
|
|
31728
|
+
try {
|
|
31729
|
+
removeSkillSourceClone(id);
|
|
31730
|
+
removeSkillSource(id);
|
|
31731
|
+
return ok({ id, message: `Removed skill source "${id}".` });
|
|
31732
|
+
} catch (err) {
|
|
31733
|
+
return fail(err);
|
|
31734
|
+
}
|
|
31735
|
+
}
|
|
31736
|
+
);
|
|
31737
|
+
server.tool(
|
|
31738
|
+
"olam_skills_source_pull",
|
|
31739
|
+
"Fetch + reset the clone to upstream HEAD. Updates lastPulledSha.",
|
|
31740
|
+
{
|
|
31741
|
+
id: external_exports.string().length(12).describe("Skill source id.")
|
|
31742
|
+
},
|
|
31743
|
+
async ({ id }) => {
|
|
31744
|
+
const entry = getSkillSource(id);
|
|
31745
|
+
if (!entry) {
|
|
31746
|
+
return fail(new Error(`skill source "${id}" is not registered`));
|
|
31747
|
+
}
|
|
31748
|
+
try {
|
|
31749
|
+
const result = pullSkillSource({
|
|
31750
|
+
gitUrl: entry.gitUrl,
|
|
31751
|
+
branch: entry.branch,
|
|
31752
|
+
id: entry.id
|
|
31753
|
+
});
|
|
31754
|
+
const updated = updateSkillSource(entry.id, { lastPulledSha: result.headSha });
|
|
31755
|
+
return ok({
|
|
31756
|
+
source: updated,
|
|
31757
|
+
message: `Pulled "${entry.name}" \u2192 ${result.headSha.slice(0, 8)}.`
|
|
31758
|
+
});
|
|
31759
|
+
} catch (err) {
|
|
31760
|
+
return fail(err);
|
|
31761
|
+
}
|
|
31762
|
+
}
|
|
31763
|
+
);
|
|
31764
|
+
server.tool(
|
|
31765
|
+
"olam_skills_source_show",
|
|
31766
|
+
"Show details for a single skill source (state-store entry + resolved clone path).",
|
|
31767
|
+
{
|
|
31768
|
+
id: external_exports.string().length(12).describe("Skill source id.")
|
|
31769
|
+
},
|
|
31770
|
+
async ({ id }) => {
|
|
31771
|
+
const entry = getSkillSource(id);
|
|
31772
|
+
if (!entry) {
|
|
31773
|
+
return fail(new Error(`skill source "${id}" is not registered`));
|
|
31774
|
+
}
|
|
31775
|
+
return ok({
|
|
31776
|
+
source: entry,
|
|
31777
|
+
clonePath: skillSourceClonePath(entry.id)
|
|
31778
|
+
});
|
|
31779
|
+
}
|
|
31780
|
+
);
|
|
31781
|
+
}
|
|
31782
|
+
|
|
31783
|
+
// ../mcp-server/src/tools/skills.ts
|
|
31784
|
+
var skills_exports = {};
|
|
31785
|
+
__export(skills_exports, {
|
|
31786
|
+
register: () => register26
|
|
31787
|
+
});
|
|
31788
|
+
init_v3();
|
|
31789
|
+
import * as fs19 from "node:fs";
|
|
31790
|
+
import * as path21 from "node:path";
|
|
31791
|
+
function asMessage8(err) {
|
|
31792
|
+
return err instanceof Error ? err.message : String(err);
|
|
31793
|
+
}
|
|
31794
|
+
function ok2(data) {
|
|
31795
|
+
return {
|
|
31796
|
+
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
31797
|
+
};
|
|
31798
|
+
}
|
|
31799
|
+
function fail2(err) {
|
|
31800
|
+
return {
|
|
31801
|
+
content: [{ type: "text", text: asMessage8(err) }],
|
|
31802
|
+
isError: true
|
|
31803
|
+
};
|
|
31804
|
+
}
|
|
31805
|
+
function listDeployed() {
|
|
31806
|
+
const dir = claudeDir();
|
|
31807
|
+
const sources = listSkillSources();
|
|
31808
|
+
const sourcePaths = new Map(
|
|
31809
|
+
sources.map((s) => [skillSourceClonePath(s.id), s.id])
|
|
31810
|
+
);
|
|
31811
|
+
const entries = [];
|
|
31812
|
+
for (const bucket of ["skills", "agents", "scripts", "rules", "commands"]) {
|
|
31813
|
+
const bucketDir = path21.join(dir, bucket);
|
|
31814
|
+
if (!fs19.existsSync(bucketDir)) continue;
|
|
31815
|
+
for (const name of fs19.readdirSync(bucketDir)) {
|
|
31816
|
+
const full = path21.join(bucketDir, name);
|
|
31817
|
+
try {
|
|
31818
|
+
const stat = fs19.lstatSync(full);
|
|
31819
|
+
if (!stat.isSymbolicLink()) continue;
|
|
31820
|
+
const target = fs19.readlinkSync(full);
|
|
31821
|
+
let sourceId;
|
|
31822
|
+
for (const [clonePath, id] of sourcePaths.entries()) {
|
|
31823
|
+
if (target.startsWith(clonePath)) {
|
|
31824
|
+
sourceId = id;
|
|
31825
|
+
break;
|
|
31826
|
+
}
|
|
31827
|
+
}
|
|
31828
|
+
entries.push({ bucket, name, target, sourceId });
|
|
31829
|
+
} catch {
|
|
31830
|
+
}
|
|
31831
|
+
}
|
|
31832
|
+
}
|
|
31833
|
+
return entries;
|
|
31834
|
+
}
|
|
31835
|
+
function register26(server, _ctx, _initError) {
|
|
31836
|
+
server.tool(
|
|
31837
|
+
"olam_skills_sync",
|
|
31838
|
+
"Sync all registered skill sources to ~/.claude/. Returns SyncSummary with per-source artifact breakdown, deploy result, and merge result.",
|
|
31839
|
+
{
|
|
31840
|
+
dryRun: external_exports.boolean().optional().describe("Resolve artifacts but do not deploy or merge. Returns the summary that sync would produce."),
|
|
31841
|
+
atlasUser: external_exports.string().optional().describe("Override atlas-user identifier (defaults to ~/.claude/.atlas-user).")
|
|
31842
|
+
},
|
|
31843
|
+
async ({ dryRun, atlasUser }) => {
|
|
31844
|
+
try {
|
|
31845
|
+
const summary = await syncSkills({ dryRun, atlasUser });
|
|
31846
|
+
return ok2(summary);
|
|
31847
|
+
} catch (err) {
|
|
31848
|
+
return fail2(err);
|
|
31849
|
+
}
|
|
31850
|
+
}
|
|
31851
|
+
);
|
|
31852
|
+
server.tool(
|
|
31853
|
+
"olam_skills_diff",
|
|
31854
|
+
"Show what `olam skills sync` would deploy without making on-disk changes. Equivalent to sync with dryRun=true.",
|
|
31855
|
+
{
|
|
31856
|
+
atlasUser: external_exports.string().optional().describe("Override atlas-user identifier.")
|
|
31857
|
+
},
|
|
31858
|
+
async ({ atlasUser }) => {
|
|
31859
|
+
try {
|
|
31860
|
+
const summary = await syncSkills({ dryRun: true, atlasUser });
|
|
31861
|
+
return ok2(summary);
|
|
31862
|
+
} catch (err) {
|
|
31863
|
+
return fail2(err);
|
|
31864
|
+
}
|
|
31865
|
+
}
|
|
31866
|
+
);
|
|
31867
|
+
server.tool(
|
|
31868
|
+
"olam_skills_list",
|
|
31869
|
+
"List artifacts currently deployed under ~/.claude/{skills,agents,scripts,rules,commands}/ along with their source-id (if from a registered olam source).",
|
|
31870
|
+
{},
|
|
31871
|
+
async () => {
|
|
31872
|
+
try {
|
|
31873
|
+
const entries = listDeployed();
|
|
31874
|
+
return ok2({ deployed: entries, count: entries.length });
|
|
31875
|
+
} catch (err) {
|
|
31876
|
+
return fail2(err);
|
|
31877
|
+
}
|
|
31878
|
+
}
|
|
31879
|
+
);
|
|
31880
|
+
server.tool(
|
|
31881
|
+
"olam_skills_show",
|
|
31882
|
+
'Show details for a deployed artifact by name (e.g. "plan-hard" or "codex-second-opinion.md"). Returns one or more matches across buckets.',
|
|
31883
|
+
{
|
|
31884
|
+
name: external_exports.string().min(1).describe("Artifact name (basename under any of the managed buckets).")
|
|
31885
|
+
},
|
|
31886
|
+
async ({ name }) => {
|
|
31887
|
+
try {
|
|
31888
|
+
const entries = listDeployed().filter((e) => e.name === name);
|
|
31889
|
+
if (entries.length === 0) {
|
|
31890
|
+
return fail2(new Error(`no deployed artifact matches "${name}"`));
|
|
31891
|
+
}
|
|
31892
|
+
return ok2({ matches: entries });
|
|
31893
|
+
} catch (err) {
|
|
31894
|
+
return fail2(err);
|
|
31895
|
+
}
|
|
31896
|
+
}
|
|
31897
|
+
);
|
|
31898
|
+
}
|
|
31899
|
+
|
|
31007
31900
|
// ../mcp-server/src/tools/kg-classify.ts
|
|
31008
31901
|
var kg_classify_exports = {};
|
|
31009
31902
|
__export(kg_classify_exports, {
|
|
31010
|
-
register: () =>
|
|
31903
|
+
register: () => register27
|
|
31011
31904
|
});
|
|
31012
31905
|
init_v3();
|
|
31013
31906
|
|
|
@@ -31020,8 +31913,8 @@ function port() {
|
|
|
31020
31913
|
const n = Number.parseInt(env, 10);
|
|
31021
31914
|
return Number.isFinite(n) && n > 0 ? n : KG_SERVICE_PORT_DEFAULT;
|
|
31022
31915
|
}
|
|
31023
|
-
function url(
|
|
31024
|
-
return `http://127.0.0.1:${port()}${
|
|
31916
|
+
function url(path37) {
|
|
31917
|
+
return `http://127.0.0.1:${port()}${path37}`;
|
|
31025
31918
|
}
|
|
31026
31919
|
function kgServiceHealthUrl() {
|
|
31027
31920
|
return url("/health");
|
|
@@ -31082,7 +31975,7 @@ async function status(opts = {}) {
|
|
|
31082
31975
|
}
|
|
31083
31976
|
|
|
31084
31977
|
// ../mcp-server/src/tools/kg-classify.ts
|
|
31085
|
-
function
|
|
31978
|
+
function register27(server, _ctx, _initError) {
|
|
31086
31979
|
server.tool(
|
|
31087
31980
|
"olam_kg_classify",
|
|
31088
31981
|
"Route a question to kg | grep | both via the 4-layer classifier (kg-service container). Returns route + layer + reason + matched exemplar. Requires olam-kg-service running (see `olam services up`).",
|
|
@@ -31130,7 +32023,7 @@ function register25(server, _ctx, _initError) {
|
|
|
31130
32023
|
// ../mcp-server/src/tools/kg-doctor.ts
|
|
31131
32024
|
var kg_doctor_exports = {};
|
|
31132
32025
|
__export(kg_doctor_exports, {
|
|
31133
|
-
register: () =>
|
|
32026
|
+
register: () => register28
|
|
31134
32027
|
});
|
|
31135
32028
|
async function runProbes() {
|
|
31136
32029
|
const results = [];
|
|
@@ -31180,7 +32073,7 @@ async function runProbes() {
|
|
|
31180
32073
|
}
|
|
31181
32074
|
return results;
|
|
31182
32075
|
}
|
|
31183
|
-
function
|
|
32076
|
+
function register28(server, _ctx, _initError) {
|
|
31184
32077
|
server.tool(
|
|
31185
32078
|
"olam_kg_doctor",
|
|
31186
32079
|
"Diagnostic report for olam-kg-service over HTTP: /health readiness, workspace inventory, and /classify round-trip. Returns a JSON `probes` array. If the container isn't running, all probes fail with a hint to run `olam services up`.",
|
|
@@ -31216,17 +32109,17 @@ function register26(server, _ctx, _initError) {
|
|
|
31216
32109
|
// ../mcp-server/src/tools/kg-install-hook.ts
|
|
31217
32110
|
var kg_install_hook_exports = {};
|
|
31218
32111
|
__export(kg_install_hook_exports, {
|
|
31219
|
-
register: () =>
|
|
32112
|
+
register: () => register29
|
|
31220
32113
|
});
|
|
31221
32114
|
init_v3();
|
|
31222
|
-
import * as
|
|
31223
|
-
import * as
|
|
31224
|
-
import * as
|
|
32115
|
+
import * as fs21 from "node:fs";
|
|
32116
|
+
import * as path23 from "node:path";
|
|
32117
|
+
import * as os14 from "node:os";
|
|
31225
32118
|
|
|
31226
32119
|
// ../core/dist/world/merge-settings.js
|
|
31227
|
-
import * as
|
|
31228
|
-
import * as
|
|
31229
|
-
import * as
|
|
32120
|
+
import * as fs20 from "node:fs";
|
|
32121
|
+
import * as path22 from "node:path";
|
|
32122
|
+
import * as crypto4 from "node:crypto";
|
|
31230
32123
|
function mergeHomeSettingsJson(filePath, options) {
|
|
31231
32124
|
let settings;
|
|
31232
32125
|
try {
|
|
@@ -31285,10 +32178,10 @@ function mergeHomeSettingsJson(filePath, options) {
|
|
|
31285
32178
|
return { status: "installed", message: `settings.json updated at ${filePath}` };
|
|
31286
32179
|
}
|
|
31287
32180
|
function readSettings(filePath) {
|
|
31288
|
-
if (!
|
|
32181
|
+
if (!fs20.existsSync(filePath)) {
|
|
31289
32182
|
return {};
|
|
31290
32183
|
}
|
|
31291
|
-
const raw =
|
|
32184
|
+
const raw = fs20.readFileSync(filePath, "utf-8");
|
|
31292
32185
|
if (!raw.trim())
|
|
31293
32186
|
return {};
|
|
31294
32187
|
return JSON.parse(raw);
|
|
@@ -31309,13 +32202,13 @@ function isHookSentinelPresent(matchers, sentinel) {
|
|
|
31309
32202
|
return false;
|
|
31310
32203
|
}
|
|
31311
32204
|
function atomicWriteJson(filePath, data) {
|
|
31312
|
-
const dir =
|
|
31313
|
-
|
|
31314
|
-
const rand =
|
|
32205
|
+
const dir = path22.dirname(filePath);
|
|
32206
|
+
fs20.mkdirSync(dir, { recursive: true });
|
|
32207
|
+
const rand = crypto4.randomBytes(6).toString("hex");
|
|
31315
32208
|
const tmp = `${filePath}.tmp.${process.pid}.${rand}`;
|
|
31316
32209
|
const json = JSON.stringify(data, null, 2) + "\n";
|
|
31317
|
-
|
|
31318
|
-
|
|
32210
|
+
fs20.writeFileSync(tmp, json, { mode: 420 });
|
|
32211
|
+
fs20.renameSync(tmp, filePath);
|
|
31319
32212
|
}
|
|
31320
32213
|
|
|
31321
32214
|
// ../core/dist/kg/hook-template.js
|
|
@@ -31366,12 +32259,12 @@ function buildHookMatcherEntry(opts) {
|
|
|
31366
32259
|
// ../mcp-server/src/tools/kg-install-hook.ts
|
|
31367
32260
|
function settingsPathFor(scope, projectPath) {
|
|
31368
32261
|
if (scope === "user") {
|
|
31369
|
-
return
|
|
32262
|
+
return path23.join(os14.homedir(), ".claude", "settings.json");
|
|
31370
32263
|
}
|
|
31371
32264
|
const root = projectPath ?? process.cwd();
|
|
31372
|
-
return
|
|
32265
|
+
return path23.join(root, ".claude", "settings.json");
|
|
31373
32266
|
}
|
|
31374
|
-
function
|
|
32267
|
+
function register29(server, _ctx, _initError) {
|
|
31375
32268
|
server.tool(
|
|
31376
32269
|
"olam_kg_install_hook",
|
|
31377
32270
|
"Install the kg-service PreToolUse hook into .claude/settings.json. Idempotent (sentinel-detected). Default scope=project (writes <cwd>/.claude/settings.json); scope=user writes ~/.claude/settings.json.",
|
|
@@ -31383,12 +32276,12 @@ function register27(server, _ctx, _initError) {
|
|
|
31383
32276
|
const scope = params.scope === "user" ? "user" : "project";
|
|
31384
32277
|
const filePath = settingsPathFor(scope, params.projectPath);
|
|
31385
32278
|
try {
|
|
31386
|
-
|
|
32279
|
+
fs21.mkdirSync(path23.dirname(filePath), { recursive: true });
|
|
31387
32280
|
let backupPath = null;
|
|
31388
|
-
if (
|
|
32281
|
+
if (fs21.existsSync(filePath)) {
|
|
31389
32282
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
31390
32283
|
backupPath = `${filePath}.olam-bak.${ts}`;
|
|
31391
|
-
|
|
32284
|
+
fs21.copyFileSync(filePath, backupPath);
|
|
31392
32285
|
}
|
|
31393
32286
|
const result = mergeHomeSettingsJson(filePath, {
|
|
31394
32287
|
ensureHook: {
|
|
@@ -31399,7 +32292,7 @@ function register27(server, _ctx, _initError) {
|
|
|
31399
32292
|
});
|
|
31400
32293
|
if (result.status === "already-present" && backupPath) {
|
|
31401
32294
|
try {
|
|
31402
|
-
|
|
32295
|
+
fs21.unlinkSync(backupPath);
|
|
31403
32296
|
} catch {
|
|
31404
32297
|
}
|
|
31405
32298
|
}
|
|
@@ -31440,18 +32333,18 @@ function register27(server, _ctx, _initError) {
|
|
|
31440
32333
|
// ../mcp-server/src/tools/kg-uninstall-hook.ts
|
|
31441
32334
|
var kg_uninstall_hook_exports = {};
|
|
31442
32335
|
__export(kg_uninstall_hook_exports, {
|
|
31443
|
-
register: () =>
|
|
32336
|
+
register: () => register30
|
|
31444
32337
|
});
|
|
31445
32338
|
init_v3();
|
|
31446
|
-
import * as
|
|
31447
|
-
import * as
|
|
31448
|
-
import * as
|
|
32339
|
+
import * as fs22 from "node:fs";
|
|
32340
|
+
import * as path24 from "node:path";
|
|
32341
|
+
import * as os15 from "node:os";
|
|
31449
32342
|
function settingsPathFor2(scope, projectPath) {
|
|
31450
32343
|
if (scope === "user") {
|
|
31451
|
-
return
|
|
32344
|
+
return path24.join(os15.homedir(), ".claude", "settings.json");
|
|
31452
32345
|
}
|
|
31453
32346
|
const root = projectPath ?? process.cwd();
|
|
31454
|
-
return
|
|
32347
|
+
return path24.join(root, ".claude", "settings.json");
|
|
31455
32348
|
}
|
|
31456
32349
|
function dropSentinel(matchers) {
|
|
31457
32350
|
let changed = false;
|
|
@@ -31473,7 +32366,7 @@ function dropSentinel(matchers) {
|
|
|
31473
32366
|
}
|
|
31474
32367
|
return { matchers: out, changed };
|
|
31475
32368
|
}
|
|
31476
|
-
function
|
|
32369
|
+
function register30(server, _ctx, _initError) {
|
|
31477
32370
|
server.tool(
|
|
31478
32371
|
"olam_kg_uninstall_hook",
|
|
31479
32372
|
"Remove the kg-service PreToolUse hook from .claude/settings.json. Sentinel-matched: only the olam entry is removed; other PreToolUse hooks are preserved.",
|
|
@@ -31485,7 +32378,7 @@ function register28(server, _ctx, _initError) {
|
|
|
31485
32378
|
const scope = params.scope === "user" ? "user" : "project";
|
|
31486
32379
|
const filePath = settingsPathFor2(scope, params.projectPath);
|
|
31487
32380
|
try {
|
|
31488
|
-
if (!
|
|
32381
|
+
if (!fs22.existsSync(filePath)) {
|
|
31489
32382
|
return {
|
|
31490
32383
|
content: [
|
|
31491
32384
|
{
|
|
@@ -31499,7 +32392,7 @@ function register28(server, _ctx, _initError) {
|
|
|
31499
32392
|
]
|
|
31500
32393
|
};
|
|
31501
32394
|
}
|
|
31502
|
-
const raw =
|
|
32395
|
+
const raw = fs22.readFileSync(filePath, "utf-8");
|
|
31503
32396
|
const settings = raw.trim() ? JSON.parse(raw) : {};
|
|
31504
32397
|
const preToolUse = settings.hooks?.PreToolUse;
|
|
31505
32398
|
if (!Array.isArray(preToolUse) || preToolUse.length === 0) {
|
|
@@ -31534,7 +32427,7 @@ function register28(server, _ctx, _initError) {
|
|
|
31534
32427
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
31535
32428
|
const backupPath = `${filePath}.olam-bak.${ts}`;
|
|
31536
32429
|
try {
|
|
31537
|
-
|
|
32430
|
+
fs22.copyFileSync(filePath, backupPath);
|
|
31538
32431
|
} catch {
|
|
31539
32432
|
}
|
|
31540
32433
|
const next = {
|
|
@@ -31546,7 +32439,7 @@ function register28(server, _ctx, _initError) {
|
|
|
31546
32439
|
if (otherStages.length === 0) delete next.hooks;
|
|
31547
32440
|
else delete next.hooks.PreToolUse;
|
|
31548
32441
|
}
|
|
31549
|
-
|
|
32442
|
+
fs22.writeFileSync(filePath, JSON.stringify(next, null, 2) + "\n");
|
|
31550
32443
|
return {
|
|
31551
32444
|
content: [
|
|
31552
32445
|
{
|
|
@@ -31606,6 +32499,8 @@ var toolModules = [
|
|
|
31606
32499
|
repo_exports,
|
|
31607
32500
|
process_port_exports,
|
|
31608
32501
|
runbook_exports,
|
|
32502
|
+
skill_source_exports,
|
|
32503
|
+
skills_exports,
|
|
31609
32504
|
kg_classify_exports,
|
|
31610
32505
|
kg_doctor_exports,
|
|
31611
32506
|
kg_install_hook_exports,
|
|
@@ -31757,11 +32652,11 @@ function assertBetterSqlite3Loadable(deps = {}) {
|
|
|
31757
32652
|
init_loader();
|
|
31758
32653
|
|
|
31759
32654
|
// ../core/dist/world/manager.js
|
|
31760
|
-
import * as
|
|
32655
|
+
import * as crypto7 from "node:crypto";
|
|
31761
32656
|
import { execSync as execSync5, spawnSync as spawnSync4 } from "node:child_process";
|
|
31762
|
-
import * as
|
|
31763
|
-
import * as
|
|
31764
|
-
import * as
|
|
32657
|
+
import * as fs31 from "node:fs";
|
|
32658
|
+
import * as os19 from "node:os";
|
|
32659
|
+
import * as path34 from "node:path";
|
|
31765
32660
|
|
|
31766
32661
|
// ../core/dist/world/state.js
|
|
31767
32662
|
var VALID_TRANSITIONS = {
|
|
@@ -31856,9 +32751,9 @@ function resolveDevboxImage(config2, tag) {
|
|
|
31856
32751
|
}
|
|
31857
32752
|
|
|
31858
32753
|
// ../core/dist/world/worktree.js
|
|
31859
|
-
import { execFileSync as
|
|
31860
|
-
import * as
|
|
31861
|
-
import * as
|
|
32754
|
+
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
32755
|
+
import * as fs23 from "node:fs";
|
|
32756
|
+
import * as path25 from "node:path";
|
|
31862
32757
|
function resolveGitDir(repo) {
|
|
31863
32758
|
if (repo.path) {
|
|
31864
32759
|
return repo.path;
|
|
@@ -31868,18 +32763,18 @@ function resolveGitDir(repo) {
|
|
|
31868
32763
|
async function createWorktrees(repos, worldId, workspacePath, branch) {
|
|
31869
32764
|
const created = [];
|
|
31870
32765
|
for (const repo of repos) {
|
|
31871
|
-
const worktreePath =
|
|
32766
|
+
const worktreePath = path25.join(workspacePath, repo.name);
|
|
31872
32767
|
const gitDir = resolveGitDir(repo);
|
|
31873
32768
|
const branchName = branch || `olam/${worldId}`;
|
|
31874
32769
|
try {
|
|
31875
|
-
|
|
31876
|
-
|
|
32770
|
+
fs23.mkdirSync(path25.dirname(worktreePath), { recursive: true });
|
|
32771
|
+
execFileSync3("git", ["worktree", "add", worktreePath, "-b", branchName], {
|
|
31877
32772
|
cwd: gitDir,
|
|
31878
32773
|
stdio: "pipe"
|
|
31879
32774
|
});
|
|
31880
32775
|
if (repo.submodules) {
|
|
31881
32776
|
try {
|
|
31882
|
-
|
|
32777
|
+
execFileSync3("git", ["submodule", "update", "--init", "--recursive"], {
|
|
31883
32778
|
cwd: worktreePath,
|
|
31884
32779
|
stdio: "pipe"
|
|
31885
32780
|
});
|
|
@@ -31891,7 +32786,7 @@ async function createWorktrees(repos, worldId, workspacePath, branch) {
|
|
|
31891
32786
|
for (const entry of created) {
|
|
31892
32787
|
try {
|
|
31893
32788
|
const entryGitDir = resolveGitDir(entry.repo);
|
|
31894
|
-
|
|
32789
|
+
execFileSync3("git", ["worktree", "remove", entry.worktreePath, "--force"], {
|
|
31895
32790
|
cwd: entryGitDir,
|
|
31896
32791
|
stdio: "pipe"
|
|
31897
32792
|
});
|
|
@@ -31905,7 +32800,7 @@ async function createWorktrees(repos, worldId, workspacePath, branch) {
|
|
|
31905
32800
|
}
|
|
31906
32801
|
async function removeWorktrees(repos, workspacePath) {
|
|
31907
32802
|
for (const repo of repos) {
|
|
31908
|
-
const worktreePath =
|
|
32803
|
+
const worktreePath = path25.join(workspacePath, repo.name);
|
|
31909
32804
|
let gitDir;
|
|
31910
32805
|
try {
|
|
31911
32806
|
gitDir = resolveGitDir(repo);
|
|
@@ -31914,7 +32809,7 @@ async function removeWorktrees(repos, workspacePath) {
|
|
|
31914
32809
|
}
|
|
31915
32810
|
let removed = false;
|
|
31916
32811
|
try {
|
|
31917
|
-
|
|
32812
|
+
execFileSync3("git", ["worktree", "remove", "--force", worktreePath], {
|
|
31918
32813
|
cwd: gitDir,
|
|
31919
32814
|
stdio: "pipe"
|
|
31920
32815
|
});
|
|
@@ -31923,7 +32818,7 @@ async function removeWorktrees(repos, workspacePath) {
|
|
|
31923
32818
|
}
|
|
31924
32819
|
if (!removed) {
|
|
31925
32820
|
try {
|
|
31926
|
-
|
|
32821
|
+
execFileSync3("git", ["worktree", "prune"], {
|
|
31927
32822
|
cwd: gitDir,
|
|
31928
32823
|
stdio: "pipe"
|
|
31929
32824
|
});
|
|
@@ -31940,7 +32835,7 @@ function removeBranch(repo, branch) {
|
|
|
31940
32835
|
return { branch, action: "not-found" };
|
|
31941
32836
|
}
|
|
31942
32837
|
try {
|
|
31943
|
-
|
|
32838
|
+
execFileSync3("git", ["show-ref", "--quiet", `refs/heads/${branch}`], {
|
|
31944
32839
|
cwd: gitDir,
|
|
31945
32840
|
stdio: "pipe"
|
|
31946
32841
|
});
|
|
@@ -31949,7 +32844,7 @@ function removeBranch(repo, branch) {
|
|
|
31949
32844
|
}
|
|
31950
32845
|
let hasUpstream = false;
|
|
31951
32846
|
try {
|
|
31952
|
-
|
|
32847
|
+
execFileSync3("git", ["rev-parse", "--abbrev-ref", `${branch}@{upstream}`], { cwd: gitDir, stdio: "pipe" });
|
|
31953
32848
|
hasUpstream = true;
|
|
31954
32849
|
} catch {
|
|
31955
32850
|
}
|
|
@@ -31958,14 +32853,14 @@ function removeBranch(repo, branch) {
|
|
|
31958
32853
|
}
|
|
31959
32854
|
let localCommitCount = 0;
|
|
31960
32855
|
try {
|
|
31961
|
-
const output =
|
|
32856
|
+
const output = execFileSync3("git", ["rev-list", "--count", branch, "--not", "--remotes"], { cwd: gitDir, stdio: "pipe" }).toString().trim();
|
|
31962
32857
|
localCommitCount = parseInt(output, 10) || 0;
|
|
31963
32858
|
} catch {
|
|
31964
32859
|
localCommitCount = 1;
|
|
31965
32860
|
}
|
|
31966
32861
|
if (localCommitCount === 0) {
|
|
31967
32862
|
try {
|
|
31968
|
-
|
|
32863
|
+
execFileSync3("git", ["branch", "-D", branch], {
|
|
31969
32864
|
cwd: gitDir,
|
|
31970
32865
|
stdio: "pipe"
|
|
31971
32866
|
});
|
|
@@ -31979,13 +32874,13 @@ function removeBranch(repo, branch) {
|
|
|
31979
32874
|
}
|
|
31980
32875
|
|
|
31981
32876
|
// ../core/dist/world/kg-overlay.js
|
|
31982
|
-
import { execFileSync as
|
|
31983
|
-
import * as
|
|
31984
|
-
import * as
|
|
32877
|
+
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
32878
|
+
import * as fs24 from "node:fs";
|
|
32879
|
+
import * as path26 from "node:path";
|
|
31985
32880
|
|
|
31986
32881
|
// ../core/dist/kg/storage-paths.js
|
|
31987
|
-
import { homedir as
|
|
31988
|
-
import { join as
|
|
32882
|
+
import { homedir as homedir16 } from "node:os";
|
|
32883
|
+
import { join as join26, resolve as resolve5 } from "node:path";
|
|
31989
32884
|
|
|
31990
32885
|
// ../core/dist/world/workspace-name.js
|
|
31991
32886
|
var InvalidWorkspaceNameError = class extends Error {
|
|
@@ -32006,25 +32901,25 @@ function validateWorkspaceName(name) {
|
|
|
32006
32901
|
|
|
32007
32902
|
// ../core/dist/kg/storage-paths.js
|
|
32008
32903
|
function olamHome() {
|
|
32009
|
-
return process.env.OLAM_HOME ??
|
|
32904
|
+
return process.env.OLAM_HOME ?? join26(homedir16(), ".olam");
|
|
32010
32905
|
}
|
|
32011
32906
|
function kgRoot() {
|
|
32012
|
-
return
|
|
32907
|
+
return join26(olamHome(), "kg");
|
|
32013
32908
|
}
|
|
32014
32909
|
function worldsRoot() {
|
|
32015
|
-
return
|
|
32910
|
+
return join26(olamHome(), "worlds");
|
|
32016
32911
|
}
|
|
32017
|
-
function assertWithinPrefix(
|
|
32018
|
-
if (!
|
|
32019
|
-
throw new Error(`${label} escape: ${
|
|
32912
|
+
function assertWithinPrefix(path37, prefix, label) {
|
|
32913
|
+
if (!path37.startsWith(prefix + "/")) {
|
|
32914
|
+
throw new Error(`${label} escape: ${path37} not under ${prefix}/`);
|
|
32020
32915
|
}
|
|
32021
32916
|
}
|
|
32022
32917
|
function kgPristinePath(workspace) {
|
|
32023
32918
|
validateWorkspaceName(workspace);
|
|
32024
32919
|
const root = kgRoot();
|
|
32025
|
-
const
|
|
32026
|
-
assertWithinPrefix(
|
|
32027
|
-
return
|
|
32920
|
+
const path37 = resolve5(join26(root, workspace));
|
|
32921
|
+
assertWithinPrefix(path37, root, "kgPristinePath");
|
|
32922
|
+
return path37;
|
|
32028
32923
|
}
|
|
32029
32924
|
var KG_PATHS_INTERNALS = Object.freeze({
|
|
32030
32925
|
olamHome,
|
|
@@ -32040,10 +32935,10 @@ var KgOverlayError = class extends Error {
|
|
|
32040
32935
|
}
|
|
32041
32936
|
};
|
|
32042
32937
|
function ensureGitignoreEntry(worldClonePath) {
|
|
32043
|
-
const gitignorePath =
|
|
32044
|
-
if (!
|
|
32938
|
+
const gitignorePath = path26.join(worldClonePath, ".gitignore");
|
|
32939
|
+
if (!fs24.existsSync(gitignorePath))
|
|
32045
32940
|
return "no-gitignore";
|
|
32046
|
-
const content =
|
|
32941
|
+
const content = fs24.readFileSync(gitignorePath, "utf-8");
|
|
32047
32942
|
const lines = content.split("\n").map((l) => l.trim());
|
|
32048
32943
|
const recognised = /* @__PURE__ */ new Set([
|
|
32049
32944
|
"graphify-out",
|
|
@@ -32058,31 +32953,31 @@ function ensureGitignoreEntry(worldClonePath) {
|
|
|
32058
32953
|
const eol = content.includes("\r\n") ? "\r\n" : "\n";
|
|
32059
32954
|
const needsLeadingNewline = content.length > 0 && !content.endsWith(eol);
|
|
32060
32955
|
const block = `${needsLeadingNewline ? eol : ""}${eol}# olam-kg-service: per-world KG overlay (Phase B1)${eol}graphify-out/${eol}`;
|
|
32061
|
-
|
|
32956
|
+
fs24.appendFileSync(gitignorePath, block, "utf-8");
|
|
32062
32957
|
return "appended";
|
|
32063
32958
|
}
|
|
32064
32959
|
function createWorldOverlay(opts) {
|
|
32065
32960
|
const pristineRoot = kgPristinePath(opts.workspace);
|
|
32066
|
-
const pristinePath =
|
|
32067
|
-
if (!
|
|
32961
|
+
const pristinePath = path26.join(pristineRoot, "graphify-out");
|
|
32962
|
+
if (!fs24.existsSync(pristinePath)) {
|
|
32068
32963
|
throw new KgOverlayError(`Pristine KG for workspace ${JSON.stringify(opts.workspace)} not found at ${pristinePath}. Run \`olam kg build ${opts.workspace}\` first.`);
|
|
32069
32964
|
}
|
|
32070
|
-
if (!
|
|
32965
|
+
if (!path26.isAbsolute(opts.worldClonePath)) {
|
|
32071
32966
|
throw new KgOverlayError(`worldClonePath must be absolute (got ${opts.worldClonePath})`);
|
|
32072
32967
|
}
|
|
32073
|
-
if (!
|
|
32968
|
+
if (!fs24.existsSync(opts.worldClonePath)) {
|
|
32074
32969
|
throw new KgOverlayError(`worldClonePath does not exist: ${opts.worldClonePath}. Create the clone before reflinking.`);
|
|
32075
32970
|
}
|
|
32076
|
-
const overlayPath =
|
|
32077
|
-
if (
|
|
32078
|
-
|
|
32971
|
+
const overlayPath = path26.join(opts.worldClonePath, "graphify-out");
|
|
32972
|
+
if (fs24.existsSync(overlayPath)) {
|
|
32973
|
+
fs24.rmSync(overlayPath, { recursive: true, force: true });
|
|
32079
32974
|
}
|
|
32080
32975
|
const useReflink = process.platform === "darwin";
|
|
32081
32976
|
let strategy;
|
|
32082
32977
|
let reflinkError;
|
|
32083
32978
|
if (useReflink) {
|
|
32084
32979
|
try {
|
|
32085
|
-
|
|
32980
|
+
execFileSync4("cp", ["-c", "-r", pristinePath, opts.worldClonePath], {
|
|
32086
32981
|
stdio: ["ignore", "ignore", "pipe"]
|
|
32087
32982
|
});
|
|
32088
32983
|
strategy = "cp-c-r-reflink";
|
|
@@ -32093,9 +32988,9 @@ function createWorldOverlay(opts) {
|
|
|
32093
32988
|
} else {
|
|
32094
32989
|
strategy = "cp-r";
|
|
32095
32990
|
}
|
|
32096
|
-
if (strategy === "cp-r" || !
|
|
32991
|
+
if (strategy === "cp-r" || !fs24.existsSync(overlayPath)) {
|
|
32097
32992
|
try {
|
|
32098
|
-
|
|
32993
|
+
execFileSync4("cp", ["-r", pristinePath, opts.worldClonePath], {
|
|
32099
32994
|
stdio: ["ignore", "ignore", "pipe"]
|
|
32100
32995
|
});
|
|
32101
32996
|
strategy = "cp-r";
|
|
@@ -32105,7 +33000,7 @@ function createWorldOverlay(opts) {
|
|
|
32105
33000
|
throw new KgOverlayError(`cp -r failed: ${msg}${reflinkMsg}`);
|
|
32106
33001
|
}
|
|
32107
33002
|
}
|
|
32108
|
-
if (!
|
|
33003
|
+
if (!fs24.existsSync(overlayPath)) {
|
|
32109
33004
|
throw new KgOverlayError(`Overlay creation produced no ${overlayPath} after cp \u2014 filesystem returned without error?`);
|
|
32110
33005
|
}
|
|
32111
33006
|
const gitignoreAction = ensureGitignoreEntry(opts.worldClonePath);
|
|
@@ -32118,13 +33013,13 @@ function createWorldOverlay(opts) {
|
|
|
32118
33013
|
}
|
|
32119
33014
|
|
|
32120
33015
|
// ../core/dist/world/baseline-diff.js
|
|
32121
|
-
import { execFileSync as
|
|
32122
|
-
import * as
|
|
32123
|
-
import * as
|
|
32124
|
-
import * as
|
|
33016
|
+
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
33017
|
+
import * as fs25 from "node:fs";
|
|
33018
|
+
import * as os16 from "node:os";
|
|
33019
|
+
import * as path27 from "node:path";
|
|
32125
33020
|
var DEFAULT_MAX_BUFFER_BYTES = 50 * 1024 * 1024;
|
|
32126
|
-
function expandHome2(p,
|
|
32127
|
-
return p.replace(/^~(?=$|\/|\\)/,
|
|
33021
|
+
function expandHome2(p, homedir22) {
|
|
33022
|
+
return p.replace(/^~(?=$|\/|\\)/, homedir22());
|
|
32128
33023
|
}
|
|
32129
33024
|
function sanitizeRepoFilename(name) {
|
|
32130
33025
|
const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
@@ -32146,11 +33041,11 @@ ${stderr}`;
|
|
|
32146
33041
|
return /unknown revision|bad revision|does not have any commits|HEAD'?: ambiguous|Needed a single revision/.test(blob);
|
|
32147
33042
|
}
|
|
32148
33043
|
function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
32149
|
-
const exec = deps.exec ?? ((cmd, args, opts) =>
|
|
32150
|
-
const
|
|
32151
|
-
const baselineDir =
|
|
33044
|
+
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync5(cmd, args, opts));
|
|
33045
|
+
const homedir22 = deps.homedir ?? (() => os16.homedir());
|
|
33046
|
+
const baselineDir = path27.join(workspacePath, ".olam", "baseline");
|
|
32152
33047
|
try {
|
|
32153
|
-
|
|
33048
|
+
fs25.mkdirSync(baselineDir, { recursive: true });
|
|
32154
33049
|
} catch (err) {
|
|
32155
33050
|
const msg = err instanceof Error ? err.message : String(err);
|
|
32156
33051
|
console.warn(`[baseline-diff] mkdir ${baselineDir} failed: ${msg}; reaper will see no baseline at all`);
|
|
@@ -32162,9 +33057,9 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
|
32162
33057
|
if (!repo.path)
|
|
32163
33058
|
continue;
|
|
32164
33059
|
const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
|
|
32165
|
-
const outPath =
|
|
32166
|
-
const repoPath = expandHome2(repo.path,
|
|
32167
|
-
if (!
|
|
33060
|
+
const outPath = path27.join(baselineDir, filename);
|
|
33061
|
+
const repoPath = expandHome2(repo.path, homedir22);
|
|
33062
|
+
if (!fs25.existsSync(repoPath)) {
|
|
32168
33063
|
writeBaselineFile(outPath, `# repo: ${repo.name}
|
|
32169
33064
|
# (skipped: path ${repoPath} does not exist)
|
|
32170
33065
|
`);
|
|
@@ -32231,7 +33126,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
|
32231
33126
|
}
|
|
32232
33127
|
function writeBaselineFile(outPath, content) {
|
|
32233
33128
|
try {
|
|
32234
|
-
|
|
33129
|
+
fs25.writeFileSync(outPath, content);
|
|
32235
33130
|
} catch (err) {
|
|
32236
33131
|
const msg = err instanceof Error ? err.message : String(err);
|
|
32237
33132
|
console.warn(`[baseline-diff] write to ${outPath} failed: ${msg}`);
|
|
@@ -32239,11 +33134,11 @@ function writeBaselineFile(outPath, content) {
|
|
|
32239
33134
|
}
|
|
32240
33135
|
function stripWorktreeEdits(repos, workspacePath) {
|
|
32241
33136
|
for (const repo of repos) {
|
|
32242
|
-
const worktreePath =
|
|
32243
|
-
if (!
|
|
33137
|
+
const worktreePath = path27.join(workspacePath, repo.name);
|
|
33138
|
+
if (!fs25.existsSync(worktreePath))
|
|
32244
33139
|
continue;
|
|
32245
33140
|
try {
|
|
32246
|
-
|
|
33141
|
+
execFileSync5("git", ["checkout", "--", "."], {
|
|
32247
33142
|
cwd: worktreePath,
|
|
32248
33143
|
stdio: "pipe"
|
|
32249
33144
|
});
|
|
@@ -32270,7 +33165,7 @@ ${stderr.trim()}` : "";
|
|
|
32270
33165
|
}
|
|
32271
33166
|
};
|
|
32272
33167
|
function captureOperatorDiff(repoPath, deps = {}) {
|
|
32273
|
-
const exec = deps.exec ?? ((cmd, args, opts) =>
|
|
33168
|
+
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync5(cmd, args, opts));
|
|
32274
33169
|
const unstaged = exec("git", ["diff"], {
|
|
32275
33170
|
cwd: repoPath,
|
|
32276
33171
|
encoding: "utf-8",
|
|
@@ -32298,22 +33193,22 @@ function extractStderr(err) {
|
|
|
32298
33193
|
return typeof raw === "string" ? raw : raw.toString("utf-8");
|
|
32299
33194
|
}
|
|
32300
33195
|
function carryUncommittedEdits(repos, workspacePath, deps = {}) {
|
|
32301
|
-
const exec = deps.exec ?? ((cmd, args, opts) =>
|
|
32302
|
-
const
|
|
32303
|
-
const
|
|
32304
|
-
const
|
|
32305
|
-
const
|
|
32306
|
-
|
|
33196
|
+
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync5(cmd, args, opts));
|
|
33197
|
+
const homedir22 = deps.homedir ?? (() => os16.homedir());
|
|
33198
|
+
const existsSync33 = deps.existsSync ?? ((p) => fs25.existsSync(p));
|
|
33199
|
+
const copyFileSync7 = deps.copyFileSync ?? ((src, dest) => fs25.copyFileSync(src, dest));
|
|
33200
|
+
const mkdirSync21 = deps.mkdirSync ?? ((dirPath, opts) => {
|
|
33201
|
+
fs25.mkdirSync(dirPath, opts);
|
|
32307
33202
|
});
|
|
32308
33203
|
const plans = [];
|
|
32309
33204
|
for (const repo of repos) {
|
|
32310
33205
|
if (!repo.path)
|
|
32311
33206
|
continue;
|
|
32312
|
-
const repoPath = expandHome2(repo.path,
|
|
32313
|
-
const worktreePath =
|
|
32314
|
-
if (!
|
|
33207
|
+
const repoPath = expandHome2(repo.path, homedir22);
|
|
33208
|
+
const worktreePath = path27.join(workspacePath, repo.name);
|
|
33209
|
+
if (!existsSync33(repoPath))
|
|
32315
33210
|
continue;
|
|
32316
|
-
if (!
|
|
33211
|
+
if (!existsSync33(worktreePath)) {
|
|
32317
33212
|
console.warn(`[carry] ${repo.name}: world worktree ${worktreePath} missing; skipping carry for this repo`);
|
|
32318
33213
|
continue;
|
|
32319
33214
|
}
|
|
@@ -32371,13 +33266,13 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
|
|
|
32371
33266
|
}
|
|
32372
33267
|
}
|
|
32373
33268
|
for (const rel of plan.diff.untracked) {
|
|
32374
|
-
const src =
|
|
32375
|
-
const dest =
|
|
32376
|
-
if (!
|
|
33269
|
+
const src = path27.join(plan.repoPath, rel);
|
|
33270
|
+
const dest = path27.join(plan.worktreePath, rel);
|
|
33271
|
+
if (!existsSync33(src))
|
|
32377
33272
|
continue;
|
|
32378
33273
|
try {
|
|
32379
|
-
|
|
32380
|
-
|
|
33274
|
+
mkdirSync21(path27.dirname(dest), { recursive: true });
|
|
33275
|
+
copyFileSync7(src, dest);
|
|
32381
33276
|
} catch (err) {
|
|
32382
33277
|
const msg = err instanceof Error ? err.message : String(err);
|
|
32383
33278
|
console.warn(`[carry] ${plan.name}: copy untracked ${rel} failed: ${msg}`);
|
|
@@ -32402,8 +33297,8 @@ function formatBaselineSummary(result) {
|
|
|
32402
33297
|
}
|
|
32403
33298
|
|
|
32404
33299
|
// ../core/dist/world/context-injection.js
|
|
32405
|
-
import * as
|
|
32406
|
-
import * as
|
|
33300
|
+
import * as fs26 from "node:fs";
|
|
33301
|
+
import * as path28 from "node:path";
|
|
32407
33302
|
|
|
32408
33303
|
// ../core/dist/world/templates/_generated.js
|
|
32409
33304
|
var GH_PR_CREATE = '# Creating PRs from inside an Olam world\n\n## The problem\n\nCalling `gh pr create` directly inside an Olam container **hangs forever** on a\nTTY confirmation prompt that the agent cannot answer. This is a known, reproduced issue.\n\n## The fix\n\nAlways use this exact pattern:\n\n```bash\necho y | timeout 30 gh pr create \\\n --base main \\\n --head <branch> \\\n --title "<title>" \\\n --body-file /tmp/pr-body.md\n```\n\n## Why each part matters\n\n- **`echo y |`** \u2014 answers the "Submit?" confirmation prompt up front so `gh` never pauses.\n- **`timeout 30`** \u2014 hard deadline. If `gh` hangs anyway, the command exits non-zero so the\n agent can react instead of stalling the world indefinitely.\n- **`--body-file /tmp/pr-body.md`** \u2014 write the PR body to a temp file first. Avoids\n shell-escaping bugs that occur with `--body "..."` for long or multi-line bodies.\n- **`--head` and `--base` explicitly** \u2014 removes all interactive prompts; `gh` has nothing to ask.\n\n## Troubleshooting\n\n**"no commits" or "branch not found" error:**\n\n```bash\ngit push -u origin <branch>\n# then retry:\necho y | timeout 30 gh pr create --base main --head <branch> --title "..." --body-file /tmp/pr-body.md\n```\n\n**Timeout exceeded (command exits 124):**\n\n- Check if the branch was pushed: `git log origin/<branch> --oneline -1`\n- Check GitHub CLI auth: `gh auth status`\n- Retry once; if it hangs again, open the PR via the GitHub web UI.\n';
|
|
@@ -32413,10 +33308,10 @@ var WORLD_CLAUDE_MD = '# Olam World: {{worldName}}\n\n{{taskBlock}}\n\n## Enviro
|
|
|
32413
33308
|
// ../core/dist/world/context-injection.js
|
|
32414
33309
|
function injectWorldContext(opts) {
|
|
32415
33310
|
const { world } = opts;
|
|
32416
|
-
const
|
|
32417
|
-
|
|
33311
|
+
const claudeDir2 = path28.join(world.workspacePath, ".claude");
|
|
33312
|
+
fs26.mkdirSync(claudeDir2, { recursive: true });
|
|
32418
33313
|
const content = WORLD_CLAUDE_MD.replace("{{worldName}}", world.name).replace("{{worldId}}", world.id).replace("{{branch}}", world.branch).replace("{{taskBlock}}", buildTaskBlock(opts)).replace("{{reposList}}", buildReposList(world)).replace("{{servicesLine}}", buildServicesLine(opts.services)).replace("{{pleriPlaneLine}}", buildPleriPlaneLine(opts.pleriPlaneUrl)).replace("{{planFileBlock}}", buildPlanFileBlock(world)).replace("{{extraContextBlock}}", buildExtraContextBlock(opts.claudeMdExtra));
|
|
32419
|
-
|
|
33314
|
+
fs26.writeFileSync(path28.join(claudeDir2, "CLAUDE.md"), content);
|
|
32420
33315
|
writeOlamDocs(world.workspacePath);
|
|
32421
33316
|
}
|
|
32422
33317
|
function buildTaskBlock(opts) {
|
|
@@ -32490,10 +33385,10 @@ function buildExtraContextBlock(extra) {
|
|
|
32490
33385
|
${extra}`;
|
|
32491
33386
|
}
|
|
32492
33387
|
function writeOlamDocs(workspacePath) {
|
|
32493
|
-
const docsDir =
|
|
32494
|
-
|
|
32495
|
-
|
|
32496
|
-
|
|
33388
|
+
const docsDir = path28.join(workspacePath, ".olam", "docs");
|
|
33389
|
+
fs26.mkdirSync(docsDir, { recursive: true });
|
|
33390
|
+
fs26.writeFileSync(path28.join(docsDir, "gh-pr-create.md"), GH_PR_CREATE);
|
|
33391
|
+
fs26.writeFileSync(path28.join(docsDir, "lane-orchestration.md"), LANE_ORCHESTRATION);
|
|
32497
33392
|
}
|
|
32498
33393
|
function formatTaskSource(ctx) {
|
|
32499
33394
|
if (ctx.source === "linear" && ctx.ticketId) {
|
|
@@ -32507,9 +33402,9 @@ function formatTaskSource(ctx) {
|
|
|
32507
33402
|
function hasPlanFile(world) {
|
|
32508
33403
|
if (world.repos.length === 0)
|
|
32509
33404
|
return false;
|
|
32510
|
-
const plansDir =
|
|
33405
|
+
const plansDir = path28.join(world.workspacePath, world.repos[0], "docs", "plans");
|
|
32511
33406
|
try {
|
|
32512
|
-
return
|
|
33407
|
+
return fs26.existsSync(plansDir) && fs26.readdirSync(plansDir).length > 0;
|
|
32513
33408
|
} catch {
|
|
32514
33409
|
return false;
|
|
32515
33410
|
}
|
|
@@ -32737,7 +33632,7 @@ async function installStack(exec, repos, stacks) {
|
|
|
32737
33632
|
|
|
32738
33633
|
// ../core/dist/world/stack-image.js
|
|
32739
33634
|
import { execSync as execSync3 } from "node:child_process";
|
|
32740
|
-
import * as
|
|
33635
|
+
import * as crypto5 from "node:crypto";
|
|
32741
33636
|
var BASE_IMAGE = "olam-devbox";
|
|
32742
33637
|
var LABEL_PREFIX = "olam.stack-image";
|
|
32743
33638
|
var MAX_TAG_LENGTH = 128;
|
|
@@ -32793,7 +33688,7 @@ function getImageDigest(imageRef) {
|
|
|
32793
33688
|
cachedImageDigests.set(imageRef, short);
|
|
32794
33689
|
return short;
|
|
32795
33690
|
} catch {
|
|
32796
|
-
const fallback =
|
|
33691
|
+
const fallback = crypto5.createHash("sha256").update(imageRef).digest("hex").slice(0, 16);
|
|
32797
33692
|
cachedImageDigests.set(imageRef, fallback);
|
|
32798
33693
|
return fallback;
|
|
32799
33694
|
}
|
|
@@ -32804,7 +33699,7 @@ function getBaseImageDigest() {
|
|
|
32804
33699
|
function sanitizeTag(raw) {
|
|
32805
33700
|
let tag = raw.toLowerCase().replace(/[^a-z0-9._-]/g, "-");
|
|
32806
33701
|
if (tag.length > MAX_TAG_LENGTH) {
|
|
32807
|
-
const hash =
|
|
33702
|
+
const hash = crypto5.createHash("sha256").update(raw).digest("hex").slice(0, 12);
|
|
32808
33703
|
tag = tag.slice(0, MAX_TAG_LENGTH - 13) + "_" + hash;
|
|
32809
33704
|
}
|
|
32810
33705
|
return tag;
|
|
@@ -33080,26 +33975,26 @@ function shellQuote(s) {
|
|
|
33080
33975
|
init_repo_manifest();
|
|
33081
33976
|
|
|
33082
33977
|
// ../core/dist/world/snapshot.js
|
|
33083
|
-
import * as
|
|
33084
|
-
import * as
|
|
33085
|
-
import * as
|
|
33086
|
-
import * as
|
|
33087
|
-
import { execFileSync as
|
|
33978
|
+
import * as crypto6 from "node:crypto";
|
|
33979
|
+
import * as fs27 from "node:fs";
|
|
33980
|
+
import * as os17 from "node:os";
|
|
33981
|
+
import * as path29 from "node:path";
|
|
33982
|
+
import { execFileSync as execFileSync6, spawn as spawn2 } from "node:child_process";
|
|
33088
33983
|
import { gunzipSync } from "node:zlib";
|
|
33089
33984
|
function snapshotsDir() {
|
|
33090
|
-
return process.env["OLAM_SNAPSHOTS_DIR"] ??
|
|
33985
|
+
return process.env["OLAM_SNAPSHOTS_DIR"] ?? path29.join(os17.homedir(), ".olam", "snapshots");
|
|
33091
33986
|
}
|
|
33092
33987
|
function snapshotKindDirByWorkspace(workspace, arch, kind) {
|
|
33093
|
-
return
|
|
33988
|
+
return path29.join(snapshotsDir(), "by-workspace", workspace, arch, kind);
|
|
33094
33989
|
}
|
|
33095
33990
|
function cleanupLegacyByWorldDir(worldId) {
|
|
33096
|
-
const legacyDir =
|
|
33991
|
+
const legacyDir = path29.join(snapshotsDir(), worldId);
|
|
33097
33992
|
if (worldId === "by-workspace")
|
|
33098
33993
|
return;
|
|
33099
|
-
if (!
|
|
33994
|
+
if (!fs27.existsSync(legacyDir))
|
|
33100
33995
|
return;
|
|
33101
33996
|
try {
|
|
33102
|
-
|
|
33997
|
+
fs27.rmSync(legacyDir, { recursive: true, force: true });
|
|
33103
33998
|
} catch {
|
|
33104
33999
|
}
|
|
33105
34000
|
}
|
|
@@ -33108,7 +34003,7 @@ function manifestPath(tarPath) {
|
|
|
33108
34003
|
}
|
|
33109
34004
|
function hashBuffers(entries) {
|
|
33110
34005
|
const sorted = [...entries].sort((a, b) => a.path.localeCompare(b.path));
|
|
33111
|
-
const hash =
|
|
34006
|
+
const hash = crypto6.createHash("sha256");
|
|
33112
34007
|
for (const entry of sorted) {
|
|
33113
34008
|
hash.update(entry.path);
|
|
33114
34009
|
hash.update("\0");
|
|
@@ -33118,11 +34013,11 @@ function hashBuffers(entries) {
|
|
|
33118
34013
|
return hash.digest("hex").slice(0, 12);
|
|
33119
34014
|
}
|
|
33120
34015
|
function computeGemsFingerprint(repoDir, imageDigest) {
|
|
33121
|
-
const lockfile =
|
|
33122
|
-
if (!
|
|
34016
|
+
const lockfile = path29.join(repoDir, "Gemfile.lock");
|
|
34017
|
+
if (!fs27.existsSync(lockfile))
|
|
33123
34018
|
return null;
|
|
33124
34019
|
const entries = [
|
|
33125
|
-
{ path: "Gemfile.lock", content:
|
|
34020
|
+
{ path: "Gemfile.lock", content: fs27.readFileSync(lockfile) }
|
|
33126
34021
|
];
|
|
33127
34022
|
if (imageDigest) {
|
|
33128
34023
|
entries.push({ path: "__image_digest__", content: Buffer.from(imageDigest, "utf-8") });
|
|
@@ -33132,10 +34027,10 @@ function computeGemsFingerprint(repoDir, imageDigest) {
|
|
|
33132
34027
|
function computeNodeFingerprint(repoDir, imageDigest) {
|
|
33133
34028
|
const candidates = ["yarn.lock", "pnpm-lock.yaml", "package-lock.json"];
|
|
33134
34029
|
for (const name of candidates) {
|
|
33135
|
-
const lockfile =
|
|
33136
|
-
if (
|
|
34030
|
+
const lockfile = path29.join(repoDir, name);
|
|
34031
|
+
if (fs27.existsSync(lockfile)) {
|
|
33137
34032
|
const entries = [
|
|
33138
|
-
{ path: name, content:
|
|
34033
|
+
{ path: name, content: fs27.readFileSync(lockfile) }
|
|
33139
34034
|
];
|
|
33140
34035
|
if (imageDigest) {
|
|
33141
34036
|
entries.push({ path: "__image_digest__", content: Buffer.from(imageDigest, "utf-8") });
|
|
@@ -33154,18 +34049,18 @@ function unpackTarballAtomic(srcPath, destDir) {
|
|
|
33154
34049
|
detail: validation.detail ?? `unsafe entry: ${validation.unsafePath}`
|
|
33155
34050
|
};
|
|
33156
34051
|
}
|
|
33157
|
-
const parent =
|
|
33158
|
-
|
|
33159
|
-
const tmpSuffix = `.tmp-${process.pid}-${
|
|
34052
|
+
const parent = path29.dirname(destDir);
|
|
34053
|
+
fs27.mkdirSync(parent, { recursive: true });
|
|
34054
|
+
const tmpSuffix = `.tmp-${process.pid}-${crypto6.randomBytes(4).toString("hex")}`;
|
|
33160
34055
|
const tmpDir = `${destDir}${tmpSuffix}`;
|
|
33161
34056
|
try {
|
|
33162
|
-
|
|
33163
|
-
|
|
33164
|
-
|
|
34057
|
+
fs27.mkdirSync(tmpDir, { recursive: true });
|
|
34058
|
+
execFileSync6("tar", ["-xzf", srcPath, "-C", tmpDir], { stdio: "pipe" });
|
|
34059
|
+
fs27.renameSync(tmpDir, destDir);
|
|
33165
34060
|
return { ok: true, entryCount: validation.entries.length };
|
|
33166
34061
|
} catch (err) {
|
|
33167
34062
|
try {
|
|
33168
|
-
|
|
34063
|
+
fs27.rmSync(tmpDir, { recursive: true, force: true });
|
|
33169
34064
|
} catch {
|
|
33170
34065
|
}
|
|
33171
34066
|
return {
|
|
@@ -33176,12 +34071,12 @@ function unpackTarballAtomic(srcPath, destDir) {
|
|
|
33176
34071
|
}
|
|
33177
34072
|
}
|
|
33178
34073
|
function resolvesWithin(base, target) {
|
|
33179
|
-
const resolved =
|
|
33180
|
-
const baseResolved =
|
|
33181
|
-
const rel =
|
|
34074
|
+
const resolved = path29.resolve(base, target);
|
|
34075
|
+
const baseResolved = path29.resolve(base);
|
|
34076
|
+
const rel = path29.relative(baseResolved, resolved);
|
|
33182
34077
|
if (rel === "")
|
|
33183
34078
|
return true;
|
|
33184
|
-
return !rel.startsWith("..") && !
|
|
34079
|
+
return !rel.startsWith("..") && !path29.isAbsolute(rel);
|
|
33185
34080
|
}
|
|
33186
34081
|
var TYPE_CHAR_TO_TYPE = {
|
|
33187
34082
|
"-": "file",
|
|
@@ -33231,7 +34126,7 @@ function parseTarListLine(line) {
|
|
|
33231
34126
|
function validateHardlinksBinary(tarPath, targetDir) {
|
|
33232
34127
|
let raw;
|
|
33233
34128
|
try {
|
|
33234
|
-
raw = gunzipSync(
|
|
34129
|
+
raw = gunzipSync(fs27.readFileSync(tarPath));
|
|
33235
34130
|
} catch {
|
|
33236
34131
|
return null;
|
|
33237
34132
|
}
|
|
@@ -33246,7 +34141,7 @@ function validateHardlinksBinary(tarPath, targetDir) {
|
|
|
33246
34141
|
const name = block.subarray(0, nameNull >= 0 && nameNull <= 99 ? nameNull : 100).toString("utf-8");
|
|
33247
34142
|
const linkNull = block.indexOf(0, 157);
|
|
33248
34143
|
const linkname = block.subarray(157, linkNull >= 157 && linkNull <= 256 ? linkNull : 257).toString("utf-8");
|
|
33249
|
-
if (linkname && (
|
|
34144
|
+
if (linkname && (path29.isAbsolute(linkname) || !resolvesWithin(targetDir, linkname))) {
|
|
33250
34145
|
return {
|
|
33251
34146
|
valid: false,
|
|
33252
34147
|
reason: "hardlink-escape",
|
|
@@ -33264,7 +34159,7 @@ function validateHardlinksBinary(tarPath, targetDir) {
|
|
|
33264
34159
|
function enumerateAndValidateTarballEntries(tarPath, targetDir) {
|
|
33265
34160
|
let raw;
|
|
33266
34161
|
try {
|
|
33267
|
-
raw =
|
|
34162
|
+
raw = execFileSync6("tar", ["-tvf", tarPath], {
|
|
33268
34163
|
stdio: ["ignore", "pipe", "pipe"],
|
|
33269
34164
|
env: { ...process.env, LC_ALL: "C", TZ: "UTC" },
|
|
33270
34165
|
encoding: "utf-8",
|
|
@@ -33284,7 +34179,7 @@ function enumerateAndValidateTarballEntries(tarPath, targetDir) {
|
|
|
33284
34179
|
const entry = parseTarListLine(line);
|
|
33285
34180
|
if (!entry)
|
|
33286
34181
|
continue;
|
|
33287
|
-
if (
|
|
34182
|
+
if (path29.isAbsolute(entry.name) || !resolvesWithin(targetDir, entry.name)) {
|
|
33288
34183
|
return {
|
|
33289
34184
|
valid: false,
|
|
33290
34185
|
reason: "path-traversal",
|
|
@@ -33292,8 +34187,8 @@ function enumerateAndValidateTarballEntries(tarPath, targetDir) {
|
|
|
33292
34187
|
};
|
|
33293
34188
|
}
|
|
33294
34189
|
if (entry.type === "symlink" && entry.linkname !== void 0) {
|
|
33295
|
-
const symlinkParent =
|
|
33296
|
-
if (
|
|
34190
|
+
const symlinkParent = path29.join(targetDir, path29.dirname(entry.name));
|
|
34191
|
+
if (path29.isAbsolute(entry.linkname) || !resolvesWithin(targetDir, path29.join(path29.dirname(entry.name), entry.linkname))) {
|
|
33297
34192
|
return {
|
|
33298
34193
|
valid: false,
|
|
33299
34194
|
reason: "symlink-escape",
|
|
@@ -33303,7 +34198,7 @@ function enumerateAndValidateTarballEntries(tarPath, targetDir) {
|
|
|
33303
34198
|
}
|
|
33304
34199
|
}
|
|
33305
34200
|
if (entry.type === "hardlink" && entry.linkname !== void 0) {
|
|
33306
|
-
if (
|
|
34201
|
+
if (path29.isAbsolute(entry.linkname) || !resolvesWithin(targetDir, entry.linkname)) {
|
|
33307
34202
|
return {
|
|
33308
34203
|
valid: false,
|
|
33309
34204
|
reason: "hardlink-escape",
|
|
@@ -33336,8 +34231,8 @@ function restoreSnapshotsForRepos(input) {
|
|
|
33336
34231
|
}
|
|
33337
34232
|
const archDir = snapshotKindDirByWorkspace(input.workspace, input.arch, kind);
|
|
33338
34233
|
const tarFilename = `${repo.name}-${input.arch}-${fingerprint}.tar.gz`;
|
|
33339
|
-
const tarPath =
|
|
33340
|
-
if (!
|
|
34234
|
+
const tarPath = path29.join(archDir, tarFilename);
|
|
34235
|
+
if (!fs27.existsSync(tarPath)) {
|
|
33341
34236
|
outcomes.push({ repo: repo.name, kind, outcome: "miss", reason: "no-tarball", fingerprint });
|
|
33342
34237
|
continue;
|
|
33343
34238
|
}
|
|
@@ -33352,9 +34247,9 @@ function restoreSnapshotsForRepos(input) {
|
|
|
33352
34247
|
});
|
|
33353
34248
|
continue;
|
|
33354
34249
|
}
|
|
33355
|
-
const targetDir =
|
|
34250
|
+
const targetDir = path29.join(repo.worktreeDir, targetSubpath);
|
|
33356
34251
|
try {
|
|
33357
|
-
|
|
34252
|
+
fs27.rmSync(targetDir, { recursive: true, force: true });
|
|
33358
34253
|
} catch {
|
|
33359
34254
|
}
|
|
33360
34255
|
const result = unpackTarballAtomic(tarPath, targetDir);
|
|
@@ -33367,8 +34262,8 @@ function restoreSnapshotsForRepos(input) {
|
|
|
33367
34262
|
fingerprint
|
|
33368
34263
|
});
|
|
33369
34264
|
try {
|
|
33370
|
-
|
|
33371
|
-
|
|
34265
|
+
fs27.rmSync(tarPath, { force: true });
|
|
34266
|
+
fs27.rmSync(manifestPath(tarPath), { force: true });
|
|
33372
34267
|
} catch {
|
|
33373
34268
|
}
|
|
33374
34269
|
continue;
|
|
@@ -33384,10 +34279,10 @@ function restoreSnapshotsForRepos(input) {
|
|
|
33384
34279
|
}
|
|
33385
34280
|
function readManifest(tarPath) {
|
|
33386
34281
|
const mPath = manifestPath(tarPath);
|
|
33387
|
-
if (!
|
|
34282
|
+
if (!fs27.existsSync(mPath))
|
|
33388
34283
|
return null;
|
|
33389
34284
|
try {
|
|
33390
|
-
return JSON.parse(
|
|
34285
|
+
return JSON.parse(fs27.readFileSync(mPath, "utf-8"));
|
|
33391
34286
|
} catch {
|
|
33392
34287
|
return null;
|
|
33393
34288
|
}
|
|
@@ -33402,17 +34297,17 @@ function isPidAlive(pid) {
|
|
|
33402
34297
|
}
|
|
33403
34298
|
}
|
|
33404
34299
|
function evictOldSnapshotsWithFlock(maxBytes, dir = snapshotsDir()) {
|
|
33405
|
-
|
|
33406
|
-
const lockPath =
|
|
34300
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
34301
|
+
const lockPath = path29.join(dir, EVICT_LOCK_FILENAME);
|
|
33407
34302
|
let fd;
|
|
33408
34303
|
try {
|
|
33409
|
-
fd =
|
|
34304
|
+
fd = fs27.openSync(lockPath, fs27.constants.O_WRONLY | fs27.constants.O_CREAT | fs27.constants.O_EXCL, 384);
|
|
33410
34305
|
} catch (err) {
|
|
33411
34306
|
if (err.code !== "EEXIST")
|
|
33412
34307
|
return 0;
|
|
33413
34308
|
let holderPid = null;
|
|
33414
34309
|
try {
|
|
33415
|
-
holderPid = parseInt(
|
|
34310
|
+
holderPid = parseInt(fs27.readFileSync(lockPath, "utf-8").trim(), 10);
|
|
33416
34311
|
} catch {
|
|
33417
34312
|
holderPid = null;
|
|
33418
34313
|
}
|
|
@@ -33420,23 +34315,23 @@ function evictOldSnapshotsWithFlock(maxBytes, dir = snapshotsDir()) {
|
|
|
33420
34315
|
return 0;
|
|
33421
34316
|
}
|
|
33422
34317
|
try {
|
|
33423
|
-
|
|
33424
|
-
fd =
|
|
34318
|
+
fs27.unlinkSync(lockPath);
|
|
34319
|
+
fd = fs27.openSync(lockPath, fs27.constants.O_WRONLY | fs27.constants.O_CREAT | fs27.constants.O_EXCL, 384);
|
|
33425
34320
|
} catch {
|
|
33426
34321
|
return 0;
|
|
33427
34322
|
}
|
|
33428
34323
|
}
|
|
33429
34324
|
try {
|
|
33430
|
-
|
|
34325
|
+
fs27.writeSync(fd, `${process.pid}
|
|
33431
34326
|
`);
|
|
33432
34327
|
} finally {
|
|
33433
|
-
|
|
34328
|
+
fs27.closeSync(fd);
|
|
33434
34329
|
}
|
|
33435
34330
|
try {
|
|
33436
34331
|
return evictOldSnapshots(maxBytes, dir);
|
|
33437
34332
|
} finally {
|
|
33438
34333
|
try {
|
|
33439
|
-
|
|
34334
|
+
fs27.unlinkSync(lockPath);
|
|
33440
34335
|
} catch {
|
|
33441
34336
|
}
|
|
33442
34337
|
}
|
|
@@ -33469,16 +34364,16 @@ function spawnAutoCapture(worldId, olamBin = "olam") {
|
|
|
33469
34364
|
}
|
|
33470
34365
|
}
|
|
33471
34366
|
function evictOldSnapshots(maxBytes, dir = snapshotsDir()) {
|
|
33472
|
-
if (!
|
|
34367
|
+
if (!fs27.existsSync(dir))
|
|
33473
34368
|
return 0;
|
|
33474
34369
|
const allTars = [];
|
|
33475
34370
|
const walk = (d) => {
|
|
33476
|
-
for (const entry of
|
|
33477
|
-
const full =
|
|
34371
|
+
for (const entry of fs27.readdirSync(d, { withFileTypes: true })) {
|
|
34372
|
+
const full = path29.join(d, entry.name);
|
|
33478
34373
|
if (entry.isDirectory()) {
|
|
33479
34374
|
walk(full);
|
|
33480
34375
|
} else if (entry.name.endsWith(".tar.gz")) {
|
|
33481
|
-
const stat =
|
|
34376
|
+
const stat = fs27.statSync(full);
|
|
33482
34377
|
allTars.push({ path: full, size: stat.size, mtime: stat.mtimeMs });
|
|
33483
34378
|
}
|
|
33484
34379
|
}
|
|
@@ -33493,8 +34388,8 @@ function evictOldSnapshots(maxBytes, dir = snapshotsDir()) {
|
|
|
33493
34388
|
for (const tar of allTars) {
|
|
33494
34389
|
if (remaining <= maxBytes)
|
|
33495
34390
|
break;
|
|
33496
|
-
|
|
33497
|
-
|
|
34391
|
+
fs27.rmSync(tar.path, { force: true });
|
|
34392
|
+
fs27.rmSync(manifestPath(tar.path), { force: true });
|
|
33498
34393
|
freed += tar.size;
|
|
33499
34394
|
remaining -= tar.size;
|
|
33500
34395
|
}
|
|
@@ -33611,14 +34506,14 @@ function gcloudAvailable(execFn = defaultExecFn) {
|
|
|
33611
34506
|
|
|
33612
34507
|
// ../core/dist/world/olam-yaml.js
|
|
33613
34508
|
init_repo_manifest();
|
|
33614
|
-
import * as
|
|
34509
|
+
import * as path30 from "node:path";
|
|
33615
34510
|
import YAML2 from "yaml";
|
|
33616
34511
|
function enrichReposWithManifests(repos, workspacePath) {
|
|
33617
34512
|
return repos.map((repo) => {
|
|
33618
34513
|
if (repo.manifest !== void 0 && repo.manifest !== null) {
|
|
33619
34514
|
return repo;
|
|
33620
34515
|
}
|
|
33621
|
-
const repoDir =
|
|
34516
|
+
const repoDir = path30.join(workspacePath, repo.name);
|
|
33622
34517
|
let manifest = null;
|
|
33623
34518
|
try {
|
|
33624
34519
|
manifest = loadRepoManifest(repoDir);
|
|
@@ -33633,8 +34528,8 @@ function enrichReposWithManifests(repos, workspacePath) {
|
|
|
33633
34528
|
}
|
|
33634
34529
|
|
|
33635
34530
|
// ../core/dist/policies/loader.js
|
|
33636
|
-
import * as
|
|
33637
|
-
import * as
|
|
34531
|
+
import * as fs28 from "node:fs";
|
|
34532
|
+
import * as path31 from "node:path";
|
|
33638
34533
|
import { parse as parseYaml3 } from "yaml";
|
|
33639
34534
|
function parseFrontmatter(content) {
|
|
33640
34535
|
const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/m.exec(content);
|
|
@@ -33654,20 +34549,20 @@ function toStringArray(v) {
|
|
|
33654
34549
|
return v.filter((x) => typeof x === "string");
|
|
33655
34550
|
}
|
|
33656
34551
|
function loadPolicies(workspaceRoot) {
|
|
33657
|
-
const policiesDir =
|
|
33658
|
-
if (!
|
|
34552
|
+
const policiesDir = path31.join(workspaceRoot, ".olam", "policies");
|
|
34553
|
+
if (!fs28.existsSync(policiesDir))
|
|
33659
34554
|
return [];
|
|
33660
34555
|
let files;
|
|
33661
34556
|
try {
|
|
33662
|
-
files =
|
|
34557
|
+
files = fs28.readdirSync(policiesDir).filter((f) => f.endsWith(".md")).sort();
|
|
33663
34558
|
} catch {
|
|
33664
34559
|
return [];
|
|
33665
34560
|
}
|
|
33666
34561
|
const policies = [];
|
|
33667
34562
|
for (const file of files) {
|
|
33668
|
-
const filePath =
|
|
34563
|
+
const filePath = path31.join(policiesDir, file);
|
|
33669
34564
|
try {
|
|
33670
|
-
const content =
|
|
34565
|
+
const content = fs28.readFileSync(filePath, "utf8");
|
|
33671
34566
|
const parsed = parseFrontmatter(content);
|
|
33672
34567
|
if (!parsed) {
|
|
33673
34568
|
console.warn(`[policies] skipping ${file}: no valid frontmatter block`);
|
|
@@ -33809,12 +34704,12 @@ async function autoDispatchTask(opts) {
|
|
|
33809
34704
|
}
|
|
33810
34705
|
|
|
33811
34706
|
// ../core/dist/global-config/runbook-resolver.js
|
|
33812
|
-
import * as
|
|
33813
|
-
import * as
|
|
33814
|
-
import * as
|
|
34707
|
+
import * as fs29 from "node:fs";
|
|
34708
|
+
import * as os18 from "node:os";
|
|
34709
|
+
import * as path32 from "node:path";
|
|
33815
34710
|
function expandTilde(p) {
|
|
33816
34711
|
if (p === "~" || p.startsWith("~/")) {
|
|
33817
|
-
return
|
|
34712
|
+
return path32.join(os18.homedir(), p.slice(1));
|
|
33818
34713
|
}
|
|
33819
34714
|
return p;
|
|
33820
34715
|
}
|
|
@@ -33826,7 +34721,7 @@ function resolveRunbookToWorldParams(runbook, repoRegistry) {
|
|
|
33826
34721
|
throw new Error(`repo "${repoName}" is referenced by runbook "${runbook.name}" but is not in the registry. Run "olam repos add ${repoName} --path <path>" to register it.`);
|
|
33827
34722
|
}
|
|
33828
34723
|
const resolvedPath = expandTilde(entry.path);
|
|
33829
|
-
if (!
|
|
34724
|
+
if (!fs29.existsSync(resolvedPath)) {
|
|
33830
34725
|
throw new Error(`repo "${repoName}" path "${resolvedPath}" no longer exists. Run "olam repos update ${repoName} --path <new-path>" to fix.`);
|
|
33831
34726
|
}
|
|
33832
34727
|
}
|
|
@@ -33839,19 +34734,19 @@ function resolveRunbookToWorldParams(runbook, repoRegistry) {
|
|
|
33839
34734
|
}
|
|
33840
34735
|
|
|
33841
34736
|
// ../core/dist/world/bootstrap-hooks.js
|
|
33842
|
-
import * as
|
|
33843
|
-
import * as
|
|
34737
|
+
import * as fs30 from "node:fs";
|
|
34738
|
+
import * as path33 from "node:path";
|
|
33844
34739
|
function runFixtureCopySeeds(seeds, workspacePath) {
|
|
33845
34740
|
if (!seeds)
|
|
33846
34741
|
return;
|
|
33847
34742
|
for (const seed of seeds) {
|
|
33848
34743
|
if (seed.type !== "fixture-copy")
|
|
33849
34744
|
continue;
|
|
33850
|
-
const srcAbs =
|
|
33851
|
-
const destAbs =
|
|
33852
|
-
const destDir =
|
|
33853
|
-
|
|
33854
|
-
|
|
34745
|
+
const srcAbs = path33.resolve(workspacePath, seed.repo, seed.src);
|
|
34746
|
+
const destAbs = path33.resolve(workspacePath, seed.repo, seed.dest);
|
|
34747
|
+
const destDir = path33.dirname(destAbs);
|
|
34748
|
+
fs30.mkdirSync(destDir, { recursive: true });
|
|
34749
|
+
fs30.cpSync(srcAbs, destAbs, { recursive: true, force: true });
|
|
33855
34750
|
}
|
|
33856
34751
|
}
|
|
33857
34752
|
async function runSeedHooks(seeds, containerName, servicePortMap, exec) {
|
|
@@ -34487,7 +35382,7 @@ ${detail}`);
|
|
|
34487
35382
|
runbookSeeds = resolved.seeds;
|
|
34488
35383
|
}
|
|
34489
35384
|
const worldId = generateWorldId();
|
|
34490
|
-
const workspacePath =
|
|
35385
|
+
const workspacePath = path34.join(os19.homedir(), ".olam", "worlds", worldId);
|
|
34491
35386
|
const portOffset = this.registry.getNextPortOffset();
|
|
34492
35387
|
const branch = opts.branchName ?? `olam/${worldId}`;
|
|
34493
35388
|
const repos = this.resolveReposWithWorkspace(opts);
|
|
@@ -34568,38 +35463,38 @@ ${detail}`);
|
|
|
34568
35463
|
for (const repo of repos) {
|
|
34569
35464
|
if (!repo.path)
|
|
34570
35465
|
continue;
|
|
34571
|
-
const sourceRoot = repo.path.replace(/^~/,
|
|
34572
|
-
const worktreeRoot =
|
|
34573
|
-
if (!
|
|
35466
|
+
const sourceRoot = repo.path.replace(/^~/, os19.homedir());
|
|
35467
|
+
const worktreeRoot = path34.join(workspacePath, repo.name);
|
|
35468
|
+
if (!fs31.existsSync(sourceRoot) || !fs31.existsSync(worktreeRoot))
|
|
34574
35469
|
continue;
|
|
34575
35470
|
let copied = 0;
|
|
34576
35471
|
for (const pattern of RUNTIME_FILE_PATTERNS) {
|
|
34577
35472
|
const matches2 = [];
|
|
34578
35473
|
if (pattern.includes("*")) {
|
|
34579
|
-
const [dir, glob] = [
|
|
34580
|
-
const sourceDir =
|
|
34581
|
-
if (
|
|
35474
|
+
const [dir, glob] = [path34.dirname(pattern), path34.basename(pattern)];
|
|
35475
|
+
const sourceDir = path34.join(sourceRoot, dir);
|
|
35476
|
+
if (fs31.existsSync(sourceDir)) {
|
|
34582
35477
|
const ext = glob.replace(/^\*+/, "");
|
|
34583
35478
|
try {
|
|
34584
|
-
for (const entry of
|
|
35479
|
+
for (const entry of fs31.readdirSync(sourceDir)) {
|
|
34585
35480
|
if (ext === "" || entry.endsWith(ext))
|
|
34586
|
-
matches2.push(
|
|
35481
|
+
matches2.push(path34.join(dir, entry));
|
|
34587
35482
|
}
|
|
34588
35483
|
} catch {
|
|
34589
35484
|
}
|
|
34590
35485
|
}
|
|
34591
|
-
} else if (
|
|
35486
|
+
} else if (fs31.existsSync(path34.join(sourceRoot, pattern))) {
|
|
34592
35487
|
matches2.push(pattern);
|
|
34593
35488
|
}
|
|
34594
35489
|
for (const rel of matches2) {
|
|
34595
|
-
const src =
|
|
34596
|
-
const dst =
|
|
35490
|
+
const src = path34.join(sourceRoot, rel);
|
|
35491
|
+
const dst = path34.join(worktreeRoot, rel);
|
|
34597
35492
|
try {
|
|
34598
|
-
const st =
|
|
35493
|
+
const st = fs31.statSync(src);
|
|
34599
35494
|
if (!st.isFile())
|
|
34600
35495
|
continue;
|
|
34601
|
-
|
|
34602
|
-
|
|
35496
|
+
fs31.mkdirSync(path34.dirname(dst), { recursive: true });
|
|
35497
|
+
fs31.copyFileSync(src, dst);
|
|
34603
35498
|
copied++;
|
|
34604
35499
|
} catch {
|
|
34605
35500
|
}
|
|
@@ -34685,7 +35580,7 @@ ${detail}`);
|
|
|
34685
35580
|
}
|
|
34686
35581
|
const overlayAttachments = [];
|
|
34687
35582
|
for (const repo of repos) {
|
|
34688
|
-
const worldClonePath =
|
|
35583
|
+
const worldClonePath = path34.join(workspacePath, repo.name);
|
|
34689
35584
|
try {
|
|
34690
35585
|
const result = createWorldOverlay({
|
|
34691
35586
|
workspace: repo.name,
|
|
@@ -34740,7 +35635,7 @@ ${detail}`);
|
|
|
34740
35635
|
try {
|
|
34741
35636
|
const hostExec = makeHostExecFn();
|
|
34742
35637
|
for (const repo of repos) {
|
|
34743
|
-
const repoDir =
|
|
35638
|
+
const repoDir = path34.join(workspacePath, repo.name);
|
|
34744
35639
|
if (repo.stack && Object.keys(repo.stack).length > 0) {
|
|
34745
35640
|
preDetectedStacks.set(repo.name, { repoName: repo.name, versions: repo.stack });
|
|
34746
35641
|
} else {
|
|
@@ -34784,10 +35679,10 @@ ${detail}`);
|
|
|
34784
35679
|
const worldEnv = {};
|
|
34785
35680
|
if (opts.task)
|
|
34786
35681
|
worldEnv.OLAM_TASK = opts.task;
|
|
34787
|
-
const r2CredsPath =
|
|
34788
|
-
if (
|
|
35682
|
+
const r2CredsPath = path34.join(os19.homedir(), ".olam", "r2-credentials.json");
|
|
35683
|
+
if (fs31.existsSync(r2CredsPath)) {
|
|
34789
35684
|
try {
|
|
34790
|
-
const r2Raw =
|
|
35685
|
+
const r2Raw = fs31.readFileSync(r2CredsPath, "utf-8").trim();
|
|
34791
35686
|
if (r2Raw.length > 0) {
|
|
34792
35687
|
const r2 = JSON.parse(r2Raw);
|
|
34793
35688
|
if (typeof r2.account_id === "string")
|
|
@@ -34804,10 +35699,10 @@ ${detail}`);
|
|
|
34804
35699
|
} catch {
|
|
34805
35700
|
}
|
|
34806
35701
|
}
|
|
34807
|
-
const keysYamlPath =
|
|
34808
|
-
if (
|
|
35702
|
+
const keysYamlPath = path34.join(os19.homedir(), ".olam", "keys.yaml");
|
|
35703
|
+
if (fs31.existsSync(keysYamlPath)) {
|
|
34809
35704
|
try {
|
|
34810
|
-
const keysRaw =
|
|
35705
|
+
const keysRaw = fs31.readFileSync(keysYamlPath, "utf-8").trim();
|
|
34811
35706
|
if (keysRaw.length > 0) {
|
|
34812
35707
|
const parsed = YAML3.parse(keysRaw);
|
|
34813
35708
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
@@ -34866,10 +35761,10 @@ ${detail}`);
|
|
|
34866
35761
|
worldEnv[k] = v;
|
|
34867
35762
|
}
|
|
34868
35763
|
for (const { repoName, relativePath, content } of fileWrites) {
|
|
34869
|
-
const absPath =
|
|
35764
|
+
const absPath = path34.join(workspacePath, repoName, relativePath);
|
|
34870
35765
|
try {
|
|
34871
|
-
|
|
34872
|
-
|
|
35766
|
+
fs31.mkdirSync(path34.dirname(absPath), { recursive: true });
|
|
35767
|
+
fs31.writeFileSync(absPath, content.endsWith("\n") ? content : content + "\n", {
|
|
34873
35768
|
mode: 384
|
|
34874
35769
|
});
|
|
34875
35770
|
console.log(`[secrets] ${repoName}: materialised ${relativePath} (${content.length} chars, mode 0600)`);
|
|
@@ -35040,7 +35935,7 @@ ${detail}`);
|
|
|
35040
35935
|
imageDigest: void 0,
|
|
35041
35936
|
repos: enrichedRepos.map((r) => ({
|
|
35042
35937
|
name: r.name,
|
|
35043
|
-
worktreeDir:
|
|
35938
|
+
worktreeDir: path34.join(workspacePath, r.name)
|
|
35044
35939
|
}))
|
|
35045
35940
|
});
|
|
35046
35941
|
for (const out of restoreResult.outcomes) {
|
|
@@ -35146,7 +36041,7 @@ ${detail}`);
|
|
|
35146
36041
|
}
|
|
35147
36042
|
if (opts.task) {
|
|
35148
36043
|
const allPolicies = repos.flatMap((repo) => {
|
|
35149
|
-
const repoWorktree =
|
|
36044
|
+
const repoWorktree = path34.join(workspacePath, repo.name);
|
|
35150
36045
|
try {
|
|
35151
36046
|
return loadPolicies(repoWorktree);
|
|
35152
36047
|
} catch (err) {
|
|
@@ -35159,8 +36054,8 @@ ${detail}`);
|
|
|
35159
36054
|
try {
|
|
35160
36055
|
execSync5(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
|
|
35161
36056
|
for (const repo of repos) {
|
|
35162
|
-
const policiesDir =
|
|
35163
|
-
if (
|
|
36057
|
+
const policiesDir = path34.join(workspacePath, repo.name, ".olam", "policies");
|
|
36058
|
+
if (fs31.existsSync(policiesDir)) {
|
|
35164
36059
|
execSync5(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
|
|
35165
36060
|
}
|
|
35166
36061
|
}
|
|
@@ -35268,8 +36163,8 @@ ${detail}`);
|
|
|
35268
36163
|
} catch {
|
|
35269
36164
|
}
|
|
35270
36165
|
try {
|
|
35271
|
-
|
|
35272
|
-
if (
|
|
36166
|
+
fs31.rmSync(world.workspacePath, { recursive: true, force: true });
|
|
36167
|
+
if (fs31.existsSync(world.workspacePath)) {
|
|
35273
36168
|
console.warn(`[WorldManager] destroyWorld(${worldId}): workspace dir ${world.workspacePath} still exists after rmSync. Run \`olam clean --apply\` to reap.`);
|
|
35274
36169
|
}
|
|
35275
36170
|
} catch (err) {
|
|
@@ -35378,14 +36273,14 @@ ${detail}`);
|
|
|
35378
36273
|
}).filter((r) => r !== void 0);
|
|
35379
36274
|
}
|
|
35380
36275
|
transportPlanFile(planFilePath, workspacePath, repoNames) {
|
|
35381
|
-
const planContent =
|
|
35382
|
-
const planFileName =
|
|
36276
|
+
const planContent = fs31.readFileSync(planFilePath, "utf-8");
|
|
36277
|
+
const planFileName = path34.basename(planFilePath);
|
|
35383
36278
|
const targetRepo = repoNames[0];
|
|
35384
36279
|
if (!targetRepo)
|
|
35385
36280
|
return;
|
|
35386
|
-
const plansDir =
|
|
35387
|
-
|
|
35388
|
-
|
|
36281
|
+
const plansDir = path34.join(workspacePath, targetRepo, "docs", "plans");
|
|
36282
|
+
fs31.mkdirSync(plansDir, { recursive: true });
|
|
36283
|
+
fs31.writeFileSync(path34.join(plansDir, planFileName), planContent);
|
|
35389
36284
|
}
|
|
35390
36285
|
resolveServices(repos) {
|
|
35391
36286
|
const services = [];
|
|
@@ -35688,7 +36583,7 @@ function applyPostgresWorldRole(worldId, worldDbNames, options = {}) {
|
|
|
35688
36583
|
return { worldRoleName, password };
|
|
35689
36584
|
}
|
|
35690
36585
|
function defaultPasswordGenerator() {
|
|
35691
|
-
return
|
|
36586
|
+
return crypto7.randomBytes(24).toString("base64url");
|
|
35692
36587
|
}
|
|
35693
36588
|
function escapeSqlLiteral(s) {
|
|
35694
36589
|
return s.replace(/'/g, "''");
|
|
@@ -35819,8 +36714,8 @@ import * as http2 from "node:http";
|
|
|
35819
36714
|
|
|
35820
36715
|
// ../core/dist/dashboard/server.js
|
|
35821
36716
|
import * as http from "node:http";
|
|
35822
|
-
import * as
|
|
35823
|
-
import * as
|
|
36717
|
+
import * as fs32 from "node:fs";
|
|
36718
|
+
import * as path35 from "node:path";
|
|
35824
36719
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
35825
36720
|
|
|
35826
36721
|
// ../core/dist/dashboard/serialize.js
|
|
@@ -36155,7 +37050,7 @@ function notFound(res) {
|
|
|
36155
37050
|
}
|
|
36156
37051
|
function openThoughtStore(workspacePath) {
|
|
36157
37052
|
const dbPath = getWorldDbPath(workspacePath);
|
|
36158
|
-
if (!
|
|
37053
|
+
if (!fs32.existsSync(dbPath))
|
|
36159
37054
|
return null;
|
|
36160
37055
|
return new ThoughtLocalStore(dbPath);
|
|
36161
37056
|
}
|
|
@@ -36326,13 +37221,13 @@ function findSessionInWorld(registry2, sessionId) {
|
|
|
36326
37221
|
}
|
|
36327
37222
|
function createDashboardServer(opts) {
|
|
36328
37223
|
const { port: port2, registry: registry2 } = opts;
|
|
36329
|
-
const thisDir =
|
|
36330
|
-
const defaultPublicDir =
|
|
37224
|
+
const thisDir = path35.dirname(fileURLToPath2(import.meta.url));
|
|
37225
|
+
const defaultPublicDir = path35.resolve(thisDir, "../../../control-plane/public");
|
|
36331
37226
|
const publicDir = opts.publicDir ?? defaultPublicDir;
|
|
36332
|
-
let hasPublicDir =
|
|
37227
|
+
let hasPublicDir = fs32.existsSync(publicDir);
|
|
36333
37228
|
const server = http.createServer((req, res) => {
|
|
36334
37229
|
if (!hasPublicDir) {
|
|
36335
|
-
hasPublicDir =
|
|
37230
|
+
hasPublicDir = fs32.existsSync(publicDir);
|
|
36336
37231
|
}
|
|
36337
37232
|
const host = req.headers.host ?? `localhost:${port2}`;
|
|
36338
37233
|
const url2 = new URL(req.url ?? "/", `http://${host}`);
|
|
@@ -36606,22 +37501,22 @@ function createDashboardServer(opts) {
|
|
|
36606
37501
|
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>`);
|
|
36607
37502
|
return;
|
|
36608
37503
|
}
|
|
36609
|
-
let filePath =
|
|
37504
|
+
let filePath = path35.join(publicDir, pathname === "/" ? "index.html" : pathname);
|
|
36610
37505
|
if (!filePath.startsWith(publicDir)) {
|
|
36611
37506
|
notFound(res);
|
|
36612
37507
|
return;
|
|
36613
37508
|
}
|
|
36614
|
-
if (
|
|
36615
|
-
const ext =
|
|
37509
|
+
if (fs32.existsSync(filePath) && fs32.statSync(filePath).isFile()) {
|
|
37510
|
+
const ext = path35.extname(filePath);
|
|
36616
37511
|
const contentType = MIME[ext] ?? "application/octet-stream";
|
|
36617
37512
|
res.writeHead(200, { "Content-Type": contentType });
|
|
36618
|
-
|
|
37513
|
+
fs32.createReadStream(filePath).pipe(res);
|
|
36619
37514
|
return;
|
|
36620
37515
|
}
|
|
36621
|
-
filePath =
|
|
36622
|
-
if (
|
|
37516
|
+
filePath = path35.join(publicDir, "index.html");
|
|
37517
|
+
if (fs32.existsSync(filePath)) {
|
|
36623
37518
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
36624
|
-
|
|
37519
|
+
fs32.createReadStream(filePath).pipe(res);
|
|
36625
37520
|
return;
|
|
36626
37521
|
}
|
|
36627
37522
|
notFound(res);
|
|
@@ -36631,17 +37526,17 @@ function createDashboardServer(opts) {
|
|
|
36631
37526
|
}
|
|
36632
37527
|
|
|
36633
37528
|
// ../core/dist/dashboard/state.js
|
|
36634
|
-
import * as
|
|
36635
|
-
import * as
|
|
36636
|
-
import * as
|
|
36637
|
-
var STATE_PATH =
|
|
37529
|
+
import * as fs33 from "node:fs";
|
|
37530
|
+
import * as os20 from "node:os";
|
|
37531
|
+
import * as path36 from "node:path";
|
|
37532
|
+
var STATE_PATH = path36.join(os20.homedir(), ".olam", "dashboard.json");
|
|
36638
37533
|
function saveDashboardState(state) {
|
|
36639
|
-
|
|
36640
|
-
|
|
37534
|
+
fs33.mkdirSync(path36.dirname(STATE_PATH), { recursive: true });
|
|
37535
|
+
fs33.writeFileSync(STATE_PATH, JSON.stringify(state, null, 2));
|
|
36641
37536
|
}
|
|
36642
37537
|
function loadDashboardState() {
|
|
36643
37538
|
try {
|
|
36644
|
-
const raw =
|
|
37539
|
+
const raw = fs33.readFileSync(STATE_PATH, "utf-8");
|
|
36645
37540
|
return JSON.parse(raw);
|
|
36646
37541
|
} catch {
|
|
36647
37542
|
return null;
|
|
@@ -36649,7 +37544,7 @@ function loadDashboardState() {
|
|
|
36649
37544
|
}
|
|
36650
37545
|
function clearDashboardState() {
|
|
36651
37546
|
try {
|
|
36652
|
-
|
|
37547
|
+
fs33.unlinkSync(STATE_PATH);
|
|
36653
37548
|
} catch {
|
|
36654
37549
|
}
|
|
36655
37550
|
}
|
|
@@ -36929,8 +37824,8 @@ var PleriClient = class {
|
|
|
36929
37824
|
};
|
|
36930
37825
|
|
|
36931
37826
|
// ../mcp-server/src/env-loader.ts
|
|
36932
|
-
import { readFileSync as
|
|
36933
|
-
import { join as
|
|
37827
|
+
import { readFileSync as readFileSync22, existsSync as existsSync32, statSync as statSync9 } from "node:fs";
|
|
37828
|
+
import { join as join37, dirname as dirname19, resolve as resolve9 } from "node:path";
|
|
36934
37829
|
var PROJECT_MARKERS = [
|
|
36935
37830
|
".olam/config.yaml",
|
|
36936
37831
|
".olam/config.yml",
|
|
@@ -36942,26 +37837,26 @@ function findProjectRoot2(startDir) {
|
|
|
36942
37837
|
const root = resolve9("/");
|
|
36943
37838
|
while (true) {
|
|
36944
37839
|
for (const marker of PROJECT_MARKERS) {
|
|
36945
|
-
if (
|
|
37840
|
+
if (existsSync32(join37(dir, marker))) return dir;
|
|
36946
37841
|
}
|
|
36947
|
-
const pkg =
|
|
36948
|
-
if (
|
|
37842
|
+
const pkg = join37(dir, "package.json");
|
|
37843
|
+
if (existsSync32(pkg)) {
|
|
36949
37844
|
try {
|
|
36950
|
-
const json = JSON.parse(
|
|
37845
|
+
const json = JSON.parse(readFileSync22(pkg, "utf8"));
|
|
36951
37846
|
const isOlamWorkspace = typeof json.name === "string" && json.name.startsWith("@olam/");
|
|
36952
37847
|
const hasOlamDep = json.dependencies && Object.keys(json.dependencies).some((k) => k.startsWith("@olam/")) || json.devDependencies && Object.keys(json.devDependencies).some((k) => k.startsWith("@olam/"));
|
|
36953
37848
|
if (isOlamWorkspace || hasOlamDep) return dir;
|
|
36954
37849
|
} catch {
|
|
36955
37850
|
}
|
|
36956
37851
|
}
|
|
36957
|
-
const parent =
|
|
37852
|
+
const parent = dirname19(dir);
|
|
36958
37853
|
if (parent === dir || parent === root) return null;
|
|
36959
37854
|
dir = parent;
|
|
36960
37855
|
}
|
|
36961
37856
|
}
|
|
36962
|
-
function parseEnvFile(
|
|
37857
|
+
function parseEnvFile(path37) {
|
|
36963
37858
|
const out = {};
|
|
36964
|
-
const raw =
|
|
37859
|
+
const raw = readFileSync22(path37, "utf8");
|
|
36965
37860
|
for (const line of raw.split(/\r?\n/)) {
|
|
36966
37861
|
const trimmed = line.trim();
|
|
36967
37862
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -36984,8 +37879,8 @@ function loadProjectEnv(startDir = process.cwd()) {
|
|
|
36984
37879
|
const filesRead = [];
|
|
36985
37880
|
const merged = {};
|
|
36986
37881
|
for (const name of [".env", ".env.local"]) {
|
|
36987
|
-
const p =
|
|
36988
|
-
if (
|
|
37882
|
+
const p = join37(root, name);
|
|
37883
|
+
if (existsSync32(p) && statSync9(p).isFile()) {
|
|
36989
37884
|
Object.assign(merged, parseEnvFile(p));
|
|
36990
37885
|
filesRead.push(p);
|
|
36991
37886
|
}
|