@pleri/olam-cli 0.1.66 → 0.1.68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__tests__/config.test.d.ts +2 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +95 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +53 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/repos.d.ts +11 -0
- package/dist/commands/repos.d.ts.map +1 -0
- package/dist/commands/repos.js +92 -0
- package/dist/commands/repos.js.map +1 -0
- package/dist/image-digests.json +3 -3
- package/dist/index.js +407 -118
- package/dist/index.js.map +1 -1
- package/dist/mcp-server.js +453 -172
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -460,8 +460,8 @@ var init_parseUtil = __esm({
|
|
|
460
460
|
init_errors();
|
|
461
461
|
init_en();
|
|
462
462
|
makeIssue = (params) => {
|
|
463
|
-
const { data, path:
|
|
464
|
-
const fullPath = [...
|
|
463
|
+
const { data, path: path46, errorMaps, issueData } = params;
|
|
464
|
+
const fullPath = [...path46, ...issueData.path || []];
|
|
465
465
|
const fullIssue = {
|
|
466
466
|
...issueData,
|
|
467
467
|
path: fullPath
|
|
@@ -769,11 +769,11 @@ var init_types = __esm({
|
|
|
769
769
|
init_parseUtil();
|
|
770
770
|
init_util();
|
|
771
771
|
ParseInputLazyPath = class {
|
|
772
|
-
constructor(parent, value,
|
|
772
|
+
constructor(parent, value, path46, key) {
|
|
773
773
|
this._cachedPath = [];
|
|
774
774
|
this.parent = parent;
|
|
775
775
|
this.data = value;
|
|
776
|
-
this._path =
|
|
776
|
+
this._path = path46;
|
|
777
777
|
this._key = key;
|
|
778
778
|
}
|
|
779
779
|
get path() {
|
|
@@ -4254,7 +4254,7 @@ import YAML from "yaml";
|
|
|
4254
4254
|
function bootstrapStepCmd(entry) {
|
|
4255
4255
|
return typeof entry === "string" ? entry : entry.cmd;
|
|
4256
4256
|
}
|
|
4257
|
-
function refineForbiddenKeys(value,
|
|
4257
|
+
function refineForbiddenKeys(value, path46, ctx, rejectSource) {
|
|
4258
4258
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4259
4259
|
return;
|
|
4260
4260
|
}
|
|
@@ -4262,12 +4262,12 @@ function refineForbiddenKeys(value, path44, ctx, rejectSource) {
|
|
|
4262
4262
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
4263
4263
|
ctx.addIssue({
|
|
4264
4264
|
code: external_exports.ZodIssueCode.custom,
|
|
4265
|
-
path: [...
|
|
4265
|
+
path: [...path46, key],
|
|
4266
4266
|
message: `forbidden key "${key}" (prototype-pollution surface)`
|
|
4267
4267
|
});
|
|
4268
4268
|
continue;
|
|
4269
4269
|
}
|
|
4270
|
-
if (rejectSource &&
|
|
4270
|
+
if (rejectSource && path46.length === 0 && key === "source") {
|
|
4271
4271
|
ctx.addIssue({
|
|
4272
4272
|
code: external_exports.ZodIssueCode.custom,
|
|
4273
4273
|
path: ["source"],
|
|
@@ -4275,21 +4275,21 @@ function refineForbiddenKeys(value, path44, ctx, rejectSource) {
|
|
|
4275
4275
|
});
|
|
4276
4276
|
continue;
|
|
4277
4277
|
}
|
|
4278
|
-
refineForbiddenKeys(value[key], [...
|
|
4278
|
+
refineForbiddenKeys(value[key], [...path46, key], ctx, false);
|
|
4279
4279
|
}
|
|
4280
4280
|
}
|
|
4281
|
-
function rejectForbiddenKeys(value,
|
|
4281
|
+
function rejectForbiddenKeys(value, path46, rejectSource) {
|
|
4282
4282
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
4283
4283
|
return;
|
|
4284
4284
|
}
|
|
4285
4285
|
for (const key of Object.keys(value)) {
|
|
4286
4286
|
if (FORBIDDEN_KEYS.has(key)) {
|
|
4287
|
-
throw new Error(`[manifest] ${
|
|
4287
|
+
throw new Error(`[manifest] ${path46}: forbidden key "${key}" (prototype-pollution surface)`);
|
|
4288
4288
|
}
|
|
4289
4289
|
if (rejectSource && key === "source") {
|
|
4290
|
-
throw new Error(`[manifest] ${
|
|
4290
|
+
throw new Error(`[manifest] ${path46}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
|
|
4291
4291
|
}
|
|
4292
|
-
rejectForbiddenKeys(value[key], `${
|
|
4292
|
+
rejectForbiddenKeys(value[key], `${path46}.${key}`, false);
|
|
4293
4293
|
}
|
|
4294
4294
|
}
|
|
4295
4295
|
function unknownTopLevelKeys(parsed) {
|
|
@@ -5280,8 +5280,8 @@ var init_client = __esm({
|
|
|
5280
5280
|
throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
|
|
5281
5281
|
}
|
|
5282
5282
|
}
|
|
5283
|
-
async request(method,
|
|
5284
|
-
const url = `${this.baseUrl}${
|
|
5283
|
+
async request(method, path46, body, attempt = 0) {
|
|
5284
|
+
const url = `${this.baseUrl}${path46}`;
|
|
5285
5285
|
const controller = new AbortController();
|
|
5286
5286
|
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
5287
5287
|
const headers = {};
|
|
@@ -5299,7 +5299,7 @@ var init_client = __esm({
|
|
|
5299
5299
|
} catch (err) {
|
|
5300
5300
|
if (attempt < RETRY_COUNT && isTransient(err)) {
|
|
5301
5301
|
await sleep(RETRY_BACKOFF_MS * (attempt + 1));
|
|
5302
|
-
return this.request(method,
|
|
5302
|
+
return this.request(method, path46, body, attempt + 1);
|
|
5303
5303
|
}
|
|
5304
5304
|
throw err;
|
|
5305
5305
|
} finally {
|
|
@@ -6778,8 +6778,8 @@ var init_provider3 = __esm({
|
|
|
6778
6778
|
// -----------------------------------------------------------------------
|
|
6779
6779
|
// Internal fetch helper
|
|
6780
6780
|
// -----------------------------------------------------------------------
|
|
6781
|
-
async request(
|
|
6782
|
-
const url = `${this.config.workerUrl}${
|
|
6781
|
+
async request(path46, method, body) {
|
|
6782
|
+
const url = `${this.config.workerUrl}${path46}`;
|
|
6783
6783
|
const bearer = await this.config.mintToken();
|
|
6784
6784
|
const headers = {
|
|
6785
6785
|
Authorization: `Bearer ${bearer}`
|
|
@@ -8056,8 +8056,8 @@ import { execFileSync as execFileSync3 } from "node:child_process";
|
|
|
8056
8056
|
import * as fs13 from "node:fs";
|
|
8057
8057
|
import * as os9 from "node:os";
|
|
8058
8058
|
import * as path14 from "node:path";
|
|
8059
|
-
function expandHome(p,
|
|
8060
|
-
return p.replace(/^~(?=$|\/|\\)/,
|
|
8059
|
+
function expandHome(p, homedir24) {
|
|
8060
|
+
return p.replace(/^~(?=$|\/|\\)/, homedir24());
|
|
8061
8061
|
}
|
|
8062
8062
|
function sanitizeRepoFilename(name) {
|
|
8063
8063
|
const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
@@ -8080,7 +8080,7 @@ ${stderr}`;
|
|
|
8080
8080
|
}
|
|
8081
8081
|
function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
8082
8082
|
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync3(cmd, args, opts));
|
|
8083
|
-
const
|
|
8083
|
+
const homedir24 = deps.homedir ?? (() => os9.homedir());
|
|
8084
8084
|
const baselineDir = path14.join(workspacePath, ".olam", "baseline");
|
|
8085
8085
|
try {
|
|
8086
8086
|
fs13.mkdirSync(baselineDir, { recursive: true });
|
|
@@ -8096,7 +8096,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
|
8096
8096
|
continue;
|
|
8097
8097
|
const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
|
|
8098
8098
|
const outPath = path14.join(baselineDir, filename);
|
|
8099
|
-
const repoPath = expandHome(repo.path,
|
|
8099
|
+
const repoPath = expandHome(repo.path, homedir24);
|
|
8100
8100
|
if (!fs13.existsSync(repoPath)) {
|
|
8101
8101
|
writeBaselineFile(outPath, `# repo: ${repo.name}
|
|
8102
8102
|
# (skipped: path ${repoPath} does not exist)
|
|
@@ -12523,10 +12523,10 @@ async function readHostCpToken2() {
|
|
|
12523
12523
|
if (!fs19.existsSync(tp)) return null;
|
|
12524
12524
|
return fs19.readFileSync(tp, "utf-8").trim();
|
|
12525
12525
|
}
|
|
12526
|
-
async function callHostCpProxy(method, worldId,
|
|
12526
|
+
async function callHostCpProxy(method, worldId, path46, body) {
|
|
12527
12527
|
const token = await readHostCpToken2();
|
|
12528
12528
|
if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
|
|
12529
|
-
const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${
|
|
12529
|
+
const url = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path46}`;
|
|
12530
12530
|
try {
|
|
12531
12531
|
const headers = {
|
|
12532
12532
|
Authorization: `Bearer ${token}`
|
|
@@ -13034,8 +13034,8 @@ var init_machine_schema = __esm({
|
|
|
13034
13034
|
|
|
13035
13035
|
// src/index.ts
|
|
13036
13036
|
import { Command } from "commander";
|
|
13037
|
-
import * as
|
|
13038
|
-
import * as
|
|
13037
|
+
import * as fs42 from "node:fs";
|
|
13038
|
+
import * as path45 from "node:path";
|
|
13039
13039
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
13040
13040
|
|
|
13041
13041
|
// src/commands/init.ts
|
|
@@ -13412,9 +13412,9 @@ var UnknownArchetypeError = class extends Error {
|
|
|
13412
13412
|
};
|
|
13413
13413
|
var ArchetypeCycleError = class extends Error {
|
|
13414
13414
|
path;
|
|
13415
|
-
constructor(
|
|
13416
|
-
super(`Archetype inheritance cycle detected: ${
|
|
13417
|
-
this.path =
|
|
13415
|
+
constructor(path46) {
|
|
13416
|
+
super(`Archetype inheritance cycle detected: ${path46.join(" \u2192 ")} \u2192 ${path46[0] ?? "?"}`);
|
|
13417
|
+
this.path = path46;
|
|
13418
13418
|
this.name = "ArchetypeCycleError";
|
|
13419
13419
|
}
|
|
13420
13420
|
};
|
|
@@ -14521,20 +14521,6 @@ function servicesStatus() {
|
|
|
14521
14521
|
const mcpStateStr = mcpState.state === "running" ? pc8.green("running") : mcpState.state === "stopped" ? pc8.yellow("stopped") : pc8.red("missing");
|
|
14522
14522
|
printInfo("olam-mcp-auth", `${mcpStateStr} :${mcpState.port}`);
|
|
14523
14523
|
}
|
|
14524
|
-
function registerServices(program2) {
|
|
14525
|
-
const services = program2.command("services").description("Manage Olam service containers (olam-auth, olam-mcp-auth)");
|
|
14526
|
-
services.command("up").description("Start all service containers (idempotent)").action(async () => {
|
|
14527
|
-
const result = await servicesUp();
|
|
14528
|
-
if (result.exitCode !== 0) process.exitCode = result.exitCode;
|
|
14529
|
-
});
|
|
14530
|
-
services.command("down").description("Stop all service containers").action(() => {
|
|
14531
|
-
const result = servicesDown();
|
|
14532
|
-
if (result.exitCode !== 0) process.exitCode = result.exitCode;
|
|
14533
|
-
});
|
|
14534
|
-
services.command("status").description("Show state of all service containers").action(() => {
|
|
14535
|
-
servicesStatus();
|
|
14536
|
-
});
|
|
14537
|
-
}
|
|
14538
14524
|
|
|
14539
14525
|
// src/commands/auth.ts
|
|
14540
14526
|
function openBrowser(url) {
|
|
@@ -14793,9 +14779,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
|
|
|
14793
14779
|
"These source files have changed since the image was built; the",
|
|
14794
14780
|
"changes will NOT take effect in fresh worlds until you rebuild:"
|
|
14795
14781
|
];
|
|
14796
|
-
for (const { path:
|
|
14782
|
+
for (const { path: path46, mtimeMs } of result.newerSources) {
|
|
14797
14783
|
const when = new Date(mtimeMs).toISOString();
|
|
14798
|
-
lines.push(` \u2022 ${
|
|
14784
|
+
lines.push(` \u2022 ${path46} (modified ${when})`);
|
|
14799
14785
|
}
|
|
14800
14786
|
lines.push("");
|
|
14801
14787
|
lines.push("Rebuild with:");
|
|
@@ -14954,15 +14940,15 @@ init_host_cp();
|
|
|
14954
14940
|
var HOST_CP_URL = "http://127.0.0.1:19000";
|
|
14955
14941
|
async function readHostCpTokenForCreate() {
|
|
14956
14942
|
try {
|
|
14957
|
-
const { default:
|
|
14958
|
-
const { default:
|
|
14959
|
-
const { default:
|
|
14960
|
-
const tp =
|
|
14961
|
-
process.env.OLAM_HOME ??
|
|
14943
|
+
const { default: fs43 } = await import("node:fs");
|
|
14944
|
+
const { default: os26 } = await import("node:os");
|
|
14945
|
+
const { default: path46 } = await import("node:path");
|
|
14946
|
+
const tp = path46.join(
|
|
14947
|
+
process.env.OLAM_HOME ?? path46.join(os26.homedir(), ".olam"),
|
|
14962
14948
|
"host-cp.token"
|
|
14963
14949
|
);
|
|
14964
|
-
if (!
|
|
14965
|
-
return
|
|
14950
|
+
if (!fs43.existsSync(tp)) return null;
|
|
14951
|
+
return fs43.readFileSync(tp, "utf-8").trim();
|
|
14966
14952
|
} catch {
|
|
14967
14953
|
return null;
|
|
14968
14954
|
}
|
|
@@ -15324,12 +15310,12 @@ function defaultNameFromPrompt(prompt) {
|
|
|
15324
15310
|
}
|
|
15325
15311
|
async function readHostCpToken3() {
|
|
15326
15312
|
try {
|
|
15327
|
-
const { default:
|
|
15328
|
-
const { default:
|
|
15329
|
-
const { default:
|
|
15330
|
-
const tp =
|
|
15331
|
-
if (!
|
|
15332
|
-
const raw =
|
|
15313
|
+
const { default: fs43 } = await import("node:fs");
|
|
15314
|
+
const { default: os26 } = await import("node:os");
|
|
15315
|
+
const { default: path46 } = await import("node:path");
|
|
15316
|
+
const tp = path46.join(os26.homedir(), ".olam", "host-cp.token");
|
|
15317
|
+
if (!fs43.existsSync(tp)) return null;
|
|
15318
|
+
const raw = fs43.readFileSync(tp, "utf-8").trim();
|
|
15333
15319
|
return raw.length > 0 ? raw : null;
|
|
15334
15320
|
} catch {
|
|
15335
15321
|
return null;
|
|
@@ -21269,6 +21255,308 @@ function registerBegin(program2) {
|
|
|
21269
21255
|
});
|
|
21270
21256
|
}
|
|
21271
21257
|
|
|
21258
|
+
// src/commands/config.ts
|
|
21259
|
+
import * as fs39 from "node:fs";
|
|
21260
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
21261
|
+
|
|
21262
|
+
// ../core/dist/global-config/schema.js
|
|
21263
|
+
init_zod();
|
|
21264
|
+
init_schema();
|
|
21265
|
+
function isAbsoluteOrTilde(p) {
|
|
21266
|
+
return p.startsWith("/") || p === "~" || p.startsWith("~/");
|
|
21267
|
+
}
|
|
21268
|
+
function hasNoTraversalComponents(p) {
|
|
21269
|
+
return !p.split("/").some((seg) => seg === "..");
|
|
21270
|
+
}
|
|
21271
|
+
var RepoEntrySchema = external_exports.object({
|
|
21272
|
+
name: external_exports.string().regex(REPO_NAME_PATTERN, "repo name must be ASCII lowercase + digits + dash (1-64 chars, no leading/trailing dash)"),
|
|
21273
|
+
path: external_exports.string().min(1, "path must not be empty").refine(isAbsoluteOrTilde, {
|
|
21274
|
+
message: `path must be absolute (e.g. "/home/user/atlas-core") or "~/..." for the operator's home directory`
|
|
21275
|
+
}).refine(hasNoTraversalComponents, { message: 'path must not contain ".." components' }),
|
|
21276
|
+
description: external_exports.string().optional(),
|
|
21277
|
+
defaultBranch: external_exports.string().optional(),
|
|
21278
|
+
addedAt: external_exports.number().int().nonnegative(),
|
|
21279
|
+
updatedAt: external_exports.number().int().nonnegative()
|
|
21280
|
+
});
|
|
21281
|
+
var PortMapSchema = external_exports.record(external_exports.string().min(1), external_exports.number().int().min(1024).max(65535));
|
|
21282
|
+
var SeedSqlFileSchema = external_exports.object({
|
|
21283
|
+
type: external_exports.literal("sql-file"),
|
|
21284
|
+
repo: external_exports.string().min(1),
|
|
21285
|
+
service: external_exports.string().min(1),
|
|
21286
|
+
path: external_exports.string().min(1)
|
|
21287
|
+
});
|
|
21288
|
+
var SeedCommandSchema = external_exports.object({
|
|
21289
|
+
type: external_exports.literal("command"),
|
|
21290
|
+
repo: external_exports.string().min(1),
|
|
21291
|
+
run: external_exports.string().min(1)
|
|
21292
|
+
});
|
|
21293
|
+
var SeedFixtureCopySchema = external_exports.object({
|
|
21294
|
+
type: external_exports.literal("fixture-copy"),
|
|
21295
|
+
repo: external_exports.string().min(1),
|
|
21296
|
+
src: external_exports.string().min(1),
|
|
21297
|
+
dest: external_exports.string().min(1)
|
|
21298
|
+
});
|
|
21299
|
+
var SeedSchema = external_exports.discriminatedUnion("type", [
|
|
21300
|
+
SeedSqlFileSchema,
|
|
21301
|
+
SeedCommandSchema,
|
|
21302
|
+
SeedFixtureCopySchema
|
|
21303
|
+
]);
|
|
21304
|
+
var RunbookSchema = external_exports.object({
|
|
21305
|
+
name: external_exports.string().regex(WORKSPACE_NAME_PATTERN, "runbook name must be ASCII lowercase + digits + dash (1-64 chars, no leading/trailing dash)"),
|
|
21306
|
+
description: external_exports.string().optional(),
|
|
21307
|
+
repos: external_exports.array(external_exports.string().min(1)).min(1, "runbook must reference at least one repo"),
|
|
21308
|
+
portMap: external_exports.record(external_exports.string().min(1), PortMapSchema).optional(),
|
|
21309
|
+
seeds: external_exports.array(SeedSchema).optional(),
|
|
21310
|
+
env: external_exports.record(external_exports.string().min(1), external_exports.record(external_exports.string().min(1), external_exports.string())).optional(),
|
|
21311
|
+
updatedAt: external_exports.number().int().nonnegative()
|
|
21312
|
+
});
|
|
21313
|
+
var GlobalConfigSchema = external_exports.object({
|
|
21314
|
+
schemaVersion: external_exports.literal(1),
|
|
21315
|
+
repos: external_exports.array(RepoEntrySchema).optional().default([]),
|
|
21316
|
+
runbooks: external_exports.array(RunbookSchema).optional().default([])
|
|
21317
|
+
}).strip().superRefine((val, ctx) => {
|
|
21318
|
+
const repoNames = val.repos.map((r) => r.name);
|
|
21319
|
+
const repoDupes = repoNames.filter((n, i) => repoNames.indexOf(n) !== i);
|
|
21320
|
+
for (const d of repoDupes) {
|
|
21321
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: `duplicate repo name: "${d}"`, path: ["repos"] });
|
|
21322
|
+
}
|
|
21323
|
+
const rbNames = val.runbooks.map((r) => r.name);
|
|
21324
|
+
const rbDupes = rbNames.filter((n, i) => rbNames.indexOf(n) !== i);
|
|
21325
|
+
for (const d of rbDupes) {
|
|
21326
|
+
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, message: `duplicate runbook name: "${d}"`, path: ["runbooks"] });
|
|
21327
|
+
}
|
|
21328
|
+
});
|
|
21329
|
+
var DEFAULT_GLOBAL_CONFIG = {
|
|
21330
|
+
schemaVersion: 1,
|
|
21331
|
+
repos: [],
|
|
21332
|
+
runbooks: []
|
|
21333
|
+
};
|
|
21334
|
+
|
|
21335
|
+
// ../core/dist/global-config/store.js
|
|
21336
|
+
import * as fs37 from "node:fs";
|
|
21337
|
+
import * as os23 from "node:os";
|
|
21338
|
+
import * as path41 from "node:path";
|
|
21339
|
+
var GlobalConfigReadError = class extends Error {
|
|
21340
|
+
constructor(configPath, cause) {
|
|
21341
|
+
const msg = cause instanceof Error ? cause.message : String(cause);
|
|
21342
|
+
super(`Failed to read global config at ${configPath}: ${msg}. Run "olam config validate" to diagnose the issue.`);
|
|
21343
|
+
this.name = "GlobalConfigReadError";
|
|
21344
|
+
this.cause = cause;
|
|
21345
|
+
}
|
|
21346
|
+
};
|
|
21347
|
+
function globalConfigPath() {
|
|
21348
|
+
const override = process.env["OLAM_GLOBAL_CONFIG_PATH"];
|
|
21349
|
+
if (override && override.length > 0)
|
|
21350
|
+
return override;
|
|
21351
|
+
return path41.join(os23.homedir(), ".olam", "config.json");
|
|
21352
|
+
}
|
|
21353
|
+
function readGlobalConfig() {
|
|
21354
|
+
const configPath = globalConfigPath();
|
|
21355
|
+
if (!fs37.existsSync(configPath)) {
|
|
21356
|
+
return { ...DEFAULT_GLOBAL_CONFIG };
|
|
21357
|
+
}
|
|
21358
|
+
let raw;
|
|
21359
|
+
try {
|
|
21360
|
+
raw = fs37.readFileSync(configPath, "utf-8");
|
|
21361
|
+
} catch (err) {
|
|
21362
|
+
throw new GlobalConfigReadError(configPath, err);
|
|
21363
|
+
}
|
|
21364
|
+
let parsed;
|
|
21365
|
+
try {
|
|
21366
|
+
parsed = JSON.parse(raw);
|
|
21367
|
+
} catch (err) {
|
|
21368
|
+
throw new GlobalConfigReadError(configPath, err);
|
|
21369
|
+
}
|
|
21370
|
+
try {
|
|
21371
|
+
return GlobalConfigSchema.parse(parsed);
|
|
21372
|
+
} catch (err) {
|
|
21373
|
+
throw new GlobalConfigReadError(configPath, err);
|
|
21374
|
+
}
|
|
21375
|
+
}
|
|
21376
|
+
function writeGlobalConfig(config) {
|
|
21377
|
+
const configPath = globalConfigPath();
|
|
21378
|
+
const validated = GlobalConfigSchema.parse(config);
|
|
21379
|
+
const dir = path41.dirname(configPath);
|
|
21380
|
+
fs37.mkdirSync(dir, { recursive: true });
|
|
21381
|
+
const tmp = `${configPath}.tmp-${process.pid}`;
|
|
21382
|
+
fs37.writeFileSync(tmp, JSON.stringify(validated, null, 2) + "\n", { mode: 420 });
|
|
21383
|
+
fs37.renameSync(tmp, configPath);
|
|
21384
|
+
}
|
|
21385
|
+
|
|
21386
|
+
// ../core/dist/global-config/repos.js
|
|
21387
|
+
import * as fs38 from "node:fs";
|
|
21388
|
+
import * as os24 from "node:os";
|
|
21389
|
+
import * as path42 from "node:path";
|
|
21390
|
+
function expandPath(p) {
|
|
21391
|
+
if (p === "~" || p.startsWith("~/")) {
|
|
21392
|
+
return path42.join(os24.homedir(), p.slice(1));
|
|
21393
|
+
}
|
|
21394
|
+
return p;
|
|
21395
|
+
}
|
|
21396
|
+
function listRepos() {
|
|
21397
|
+
return readGlobalConfig().repos;
|
|
21398
|
+
}
|
|
21399
|
+
function addRepo(entry) {
|
|
21400
|
+
const config = readGlobalConfig();
|
|
21401
|
+
if (config.repos.some((r) => r.name === entry.name)) {
|
|
21402
|
+
throw new Error(`repo "${entry.name}" already registered. Use "olam repos update" to change its path.`);
|
|
21403
|
+
}
|
|
21404
|
+
const resolvedPath = expandPath(entry.path);
|
|
21405
|
+
if (!fs38.existsSync(resolvedPath)) {
|
|
21406
|
+
throw new Error(`path "${entry.path}" does not exist. Verify the path is correct.`);
|
|
21407
|
+
}
|
|
21408
|
+
const now = Date.now();
|
|
21409
|
+
const newEntry = {
|
|
21410
|
+
name: entry.name,
|
|
21411
|
+
path: resolvedPath,
|
|
21412
|
+
addedAt: now,
|
|
21413
|
+
updatedAt: now,
|
|
21414
|
+
...entry.description !== void 0 ? { description: entry.description } : {},
|
|
21415
|
+
...entry.defaultBranch !== void 0 ? { defaultBranch: entry.defaultBranch } : {}
|
|
21416
|
+
};
|
|
21417
|
+
writeGlobalConfig({ ...config, repos: [...config.repos, newEntry] });
|
|
21418
|
+
return newEntry;
|
|
21419
|
+
}
|
|
21420
|
+
function removeRepo(name) {
|
|
21421
|
+
const config = readGlobalConfig();
|
|
21422
|
+
if (!config.repos.some((r) => r.name === name)) {
|
|
21423
|
+
throw new Error(`repo "${name}" is not registered. Run "olam repos list" to see registered repos.`);
|
|
21424
|
+
}
|
|
21425
|
+
writeGlobalConfig({ ...config, repos: config.repos.filter((r) => r.name !== name) });
|
|
21426
|
+
}
|
|
21427
|
+
function updateRepo(name, updates) {
|
|
21428
|
+
const config = readGlobalConfig();
|
|
21429
|
+
const idx = config.repos.findIndex((r) => r.name === name);
|
|
21430
|
+
if (idx === -1) {
|
|
21431
|
+
throw new Error(`repo "${name}" is not registered. Run "olam repos list" to see registered repos.`);
|
|
21432
|
+
}
|
|
21433
|
+
const resolvedUpdatePath = updates.path !== void 0 ? expandPath(updates.path) : void 0;
|
|
21434
|
+
if (resolvedUpdatePath !== void 0 && !fs38.existsSync(resolvedUpdatePath)) {
|
|
21435
|
+
throw new Error(`path "${updates.path}" does not exist. Verify the path is correct.`);
|
|
21436
|
+
}
|
|
21437
|
+
const existing = config.repos[idx];
|
|
21438
|
+
const updated = {
|
|
21439
|
+
...existing,
|
|
21440
|
+
...resolvedUpdatePath !== void 0 ? { path: resolvedUpdatePath } : {},
|
|
21441
|
+
...updates.description !== void 0 ? { description: updates.description } : {},
|
|
21442
|
+
...updates.defaultBranch !== void 0 ? { defaultBranch: updates.defaultBranch } : {},
|
|
21443
|
+
updatedAt: Date.now()
|
|
21444
|
+
};
|
|
21445
|
+
const newRepos = [...config.repos];
|
|
21446
|
+
newRepos[idx] = updated;
|
|
21447
|
+
writeGlobalConfig({ ...config, repos: newRepos });
|
|
21448
|
+
return updated;
|
|
21449
|
+
}
|
|
21450
|
+
|
|
21451
|
+
// src/commands/config.ts
|
|
21452
|
+
var _require3 = createRequire3(import.meta.url);
|
|
21453
|
+
var { parse: parseWithMap } = _require3("json-source-map");
|
|
21454
|
+
function registerConfig(program2) {
|
|
21455
|
+
const config = program2.command("config").description("Manage global olam configuration");
|
|
21456
|
+
config.command("validate [path]").description("Validate ~/.olam/config.json (or a custom path) against the schema").action((filePath) => {
|
|
21457
|
+
const resolvedPath = filePath ?? globalConfigPath();
|
|
21458
|
+
if (!fs39.existsSync(resolvedPath)) {
|
|
21459
|
+
process.stderr.write(`config file not found: ${resolvedPath}
|
|
21460
|
+
`);
|
|
21461
|
+
process.exit(1);
|
|
21462
|
+
}
|
|
21463
|
+
let raw;
|
|
21464
|
+
try {
|
|
21465
|
+
raw = fs39.readFileSync(resolvedPath, "utf-8");
|
|
21466
|
+
} catch (err) {
|
|
21467
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
21468
|
+
process.stderr.write(`cannot read ${resolvedPath}: ${msg}
|
|
21469
|
+
`);
|
|
21470
|
+
process.exit(1);
|
|
21471
|
+
}
|
|
21472
|
+
let parsed;
|
|
21473
|
+
let pointers;
|
|
21474
|
+
try {
|
|
21475
|
+
const result2 = parseWithMap(raw);
|
|
21476
|
+
parsed = result2.data;
|
|
21477
|
+
pointers = result2.pointers;
|
|
21478
|
+
} catch (err) {
|
|
21479
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
21480
|
+
process.stderr.write(`${resolvedPath}: invalid JSON \u2014 ${msg}
|
|
21481
|
+
`);
|
|
21482
|
+
process.exit(1);
|
|
21483
|
+
}
|
|
21484
|
+
const result = GlobalConfigSchema.safeParse(parsed);
|
|
21485
|
+
if (result.success) {
|
|
21486
|
+
process.exit(0);
|
|
21487
|
+
}
|
|
21488
|
+
for (const issue of result.error.issues) {
|
|
21489
|
+
const pointer = "/" + issue.path.join("/");
|
|
21490
|
+
const entry = pointers[pointer];
|
|
21491
|
+
const rawLine = entry?.value?.line ?? entry?.key?.line ?? -1;
|
|
21492
|
+
const lineStr = rawLine >= 0 ? `Line ${rawLine + 1}: ` : "";
|
|
21493
|
+
process.stderr.write(`${lineStr}${pointer}: ${issue.message}
|
|
21494
|
+
`);
|
|
21495
|
+
}
|
|
21496
|
+
process.exit(1);
|
|
21497
|
+
});
|
|
21498
|
+
}
|
|
21499
|
+
|
|
21500
|
+
// src/commands/repos.ts
|
|
21501
|
+
import pc24 from "picocolors";
|
|
21502
|
+
init_output();
|
|
21503
|
+
function asMessage(err) {
|
|
21504
|
+
return err instanceof Error ? err.message : String(err);
|
|
21505
|
+
}
|
|
21506
|
+
function registerRepos(program2) {
|
|
21507
|
+
const repos = program2.command("repos").description("Manage the global repo registry");
|
|
21508
|
+
repos.command("list").description("List all registered repos").action(() => {
|
|
21509
|
+
const all = listRepos();
|
|
21510
|
+
if (all.length === 0) {
|
|
21511
|
+
console.log(pc24.dim("0 repo(s) registered. Add one with: olam repos add --name <n> --path <p>"));
|
|
21512
|
+
return;
|
|
21513
|
+
}
|
|
21514
|
+
printHeader(`${all.length} repo(s)`);
|
|
21515
|
+
for (const r of all) {
|
|
21516
|
+
const when = new Date(r.addedAt).toISOString().slice(0, 10);
|
|
21517
|
+
console.log(
|
|
21518
|
+
` ${pc24.bold(r.name.padEnd(24))} ${r.path.padEnd(48)} ${pc24.dim(when)}`
|
|
21519
|
+
);
|
|
21520
|
+
}
|
|
21521
|
+
});
|
|
21522
|
+
repos.command("add").description("Register a local repo path").requiredOption("--name <name>", "Repo name (lowercase, digits, dash)").requiredOption("--path <path>", "Absolute or ~/... path to the local repo").option("--description <desc>", "Optional human-readable description").option("--default-branch <branch>", "Default branch name (e.g. main)").action((opts) => {
|
|
21523
|
+
try {
|
|
21524
|
+
const entry = addRepo({
|
|
21525
|
+
name: opts.name,
|
|
21526
|
+
path: opts.path,
|
|
21527
|
+
description: opts.description,
|
|
21528
|
+
defaultBranch: opts.defaultBranch
|
|
21529
|
+
});
|
|
21530
|
+
printSuccess(`registered repo "${entry.name}" at ${entry.path}`);
|
|
21531
|
+
} catch (err) {
|
|
21532
|
+
printError(asMessage(err));
|
|
21533
|
+
process.exitCode = 1;
|
|
21534
|
+
}
|
|
21535
|
+
});
|
|
21536
|
+
repos.command("remove").description("Remove a repo from the registry").argument("<name>", "Repo name to remove").action((name) => {
|
|
21537
|
+
try {
|
|
21538
|
+
removeRepo(name);
|
|
21539
|
+
printSuccess(`removed repo "${name}"`);
|
|
21540
|
+
} catch (err) {
|
|
21541
|
+
printError(asMessage(err));
|
|
21542
|
+
process.exitCode = 1;
|
|
21543
|
+
}
|
|
21544
|
+
});
|
|
21545
|
+
repos.command("update").description("Update a registered repo").argument("<name>", "Repo name to update").option("--path <path>", "New path").option("--description <desc>", "New description").option("--default-branch <branch>", "New default branch").action((name, opts) => {
|
|
21546
|
+
try {
|
|
21547
|
+
const entry = updateRepo(name, {
|
|
21548
|
+
path: opts.path,
|
|
21549
|
+
description: opts.description,
|
|
21550
|
+
defaultBranch: opts.defaultBranch
|
|
21551
|
+
});
|
|
21552
|
+
printSuccess(`updated repo "${entry.name}"`);
|
|
21553
|
+
} catch (err) {
|
|
21554
|
+
printError(asMessage(err));
|
|
21555
|
+
process.exitCode = 1;
|
|
21556
|
+
}
|
|
21557
|
+
});
|
|
21558
|
+
}
|
|
21559
|
+
|
|
21272
21560
|
// src/commands/stop.ts
|
|
21273
21561
|
init_host_cp();
|
|
21274
21562
|
async function doStop(_stopFn = stopHostCp) {
|
|
@@ -21350,8 +21638,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
|
|
|
21350
21638
|
function authHeaders() {
|
|
21351
21639
|
return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
|
|
21352
21640
|
}
|
|
21353
|
-
async function apiFetch(
|
|
21354
|
-
const res = await fetch(`${BASE_URL}${
|
|
21641
|
+
async function apiFetch(path46, init = {}) {
|
|
21642
|
+
const res = await fetch(`${BASE_URL}${path46}`, {
|
|
21355
21643
|
...init,
|
|
21356
21644
|
headers: {
|
|
21357
21645
|
"Content-Type": "application/json",
|
|
@@ -21503,7 +21791,7 @@ function registerMcpAdd(cmd) {
|
|
|
21503
21791
|
|
|
21504
21792
|
// src/commands/mcp/list.ts
|
|
21505
21793
|
init_output();
|
|
21506
|
-
import
|
|
21794
|
+
import pc25 from "picocolors";
|
|
21507
21795
|
function registerMcpList(cmd) {
|
|
21508
21796
|
cmd.command("list").description("List all registered MCP credentials").action(async () => {
|
|
21509
21797
|
const client = getMcpAuthClient();
|
|
@@ -21518,8 +21806,8 @@ function registerMcpList(cmd) {
|
|
|
21518
21806
|
}
|
|
21519
21807
|
const mcps = data.mcps ?? [];
|
|
21520
21808
|
if (mcps.length === 0) {
|
|
21521
|
-
console.log(
|
|
21522
|
-
console.log(
|
|
21809
|
+
console.log(pc25.dim("No MCP credentials registered."));
|
|
21810
|
+
console.log(pc25.dim("Add one with: olam mcp add <service>"));
|
|
21523
21811
|
return;
|
|
21524
21812
|
}
|
|
21525
21813
|
const [c0, c1, c2, c3] = [16, 20, 10, 24];
|
|
@@ -21530,12 +21818,12 @@ function registerMcpList(cmd) {
|
|
|
21530
21818
|
"ENV VAR".padEnd(c3),
|
|
21531
21819
|
"STATUS"
|
|
21532
21820
|
].join(" ");
|
|
21533
|
-
console.log(
|
|
21534
|
-
console.log(
|
|
21821
|
+
console.log(pc25.dim(header));
|
|
21822
|
+
console.log(pc25.dim("\u2500".repeat(header.length)));
|
|
21535
21823
|
for (const m of mcps) {
|
|
21536
|
-
const status = !m.validated ?
|
|
21824
|
+
const status = !m.validated ? pc25.yellow("unvalidated") : m.expired ? pc25.red("expired") : pc25.green("active");
|
|
21537
21825
|
const row = [
|
|
21538
|
-
|
|
21826
|
+
pc25.cyan(m.service.padEnd(c0)),
|
|
21539
21827
|
m.label.padEnd(c1).slice(0, c1),
|
|
21540
21828
|
m.type.padEnd(c2),
|
|
21541
21829
|
(m.envName ?? "\u2014").padEnd(c3).slice(0, c3),
|
|
@@ -21563,13 +21851,13 @@ function registerMcpRemove(cmd) {
|
|
|
21563
21851
|
|
|
21564
21852
|
// src/commands/mcp/status.ts
|
|
21565
21853
|
init_output();
|
|
21566
|
-
import
|
|
21854
|
+
import pc26 from "picocolors";
|
|
21567
21855
|
function formatExpiry(expiresAt) {
|
|
21568
21856
|
if (!expiresAt) return "\u2014";
|
|
21569
21857
|
const ms = expiresAt - Date.now();
|
|
21570
|
-
if (ms <= 0) return
|
|
21858
|
+
if (ms <= 0) return pc26.red("expired");
|
|
21571
21859
|
const hours = ms / (1e3 * 60 * 60);
|
|
21572
|
-
if (hours < 1) return
|
|
21860
|
+
if (hours < 1) return pc26.yellow(`${Math.ceil(ms / 6e4)}m`);
|
|
21573
21861
|
return `${hours.toFixed(1)}h`;
|
|
21574
21862
|
}
|
|
21575
21863
|
function registerMcpStatus(cmd) {
|
|
@@ -21586,14 +21874,14 @@ function registerMcpStatus(cmd) {
|
|
|
21586
21874
|
const mcps = data.mcps ?? [];
|
|
21587
21875
|
printHeader(`MCP Credentials (${mcps.length})`);
|
|
21588
21876
|
if (mcps.length === 0) {
|
|
21589
|
-
console.log(
|
|
21877
|
+
console.log(pc26.dim("No credentials registered."));
|
|
21590
21878
|
return;
|
|
21591
21879
|
}
|
|
21592
21880
|
for (const m of mcps) {
|
|
21593
|
-
const stateColor = !m.validated ?
|
|
21881
|
+
const stateColor = !m.validated ? pc26.yellow : m.expired ? pc26.red : pc26.green;
|
|
21594
21882
|
const stateLabel = !m.validated ? "unvalidated" : m.expired ? "expired" : "active";
|
|
21595
21883
|
console.log(`
|
|
21596
|
-
${
|
|
21884
|
+
${pc26.cyan(m.service)} ${stateColor(`[${stateLabel}]`)}`);
|
|
21597
21885
|
console.log(` label: ${m.label}`);
|
|
21598
21886
|
console.log(` type: ${m.type}`);
|
|
21599
21887
|
if (m.envName) console.log(` env var: ${m.envName}`);
|
|
@@ -21608,15 +21896,15 @@ function registerMcpStatus(cmd) {
|
|
|
21608
21896
|
// src/commands/mcp/import.ts
|
|
21609
21897
|
init_output();
|
|
21610
21898
|
import * as readline3 from "node:readline";
|
|
21611
|
-
import
|
|
21899
|
+
import pc27 from "picocolors";
|
|
21612
21900
|
|
|
21613
21901
|
// src/commands/mcp/import-discovery.ts
|
|
21614
|
-
import * as
|
|
21615
|
-
import * as
|
|
21616
|
-
import * as
|
|
21902
|
+
import * as fs40 from "node:fs";
|
|
21903
|
+
import * as os25 from "node:os";
|
|
21904
|
+
import * as path43 from "node:path";
|
|
21617
21905
|
function readJsonFile(filePath) {
|
|
21618
21906
|
try {
|
|
21619
|
-
const raw =
|
|
21907
|
+
const raw = fs40.readFileSync(filePath, "utf-8");
|
|
21620
21908
|
return JSON.parse(raw);
|
|
21621
21909
|
} catch {
|
|
21622
21910
|
return null;
|
|
@@ -21645,24 +21933,24 @@ function extractMcpServers(obj, source, sourceLabel) {
|
|
|
21645
21933
|
}
|
|
21646
21934
|
function getClaudeDesktopPath() {
|
|
21647
21935
|
if (process.platform === "darwin") {
|
|
21648
|
-
return
|
|
21936
|
+
return path43.join(os25.homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
21649
21937
|
}
|
|
21650
21938
|
if (process.platform === "win32") {
|
|
21651
|
-
const appData = process.env["APPDATA"] ??
|
|
21652
|
-
return
|
|
21939
|
+
const appData = process.env["APPDATA"] ?? path43.join(os25.homedir(), "AppData", "Roaming");
|
|
21940
|
+
return path43.join(appData, "Claude", "claude_desktop_config.json");
|
|
21653
21941
|
}
|
|
21654
|
-
return
|
|
21942
|
+
return path43.join(os25.homedir(), ".config", "Claude", "claude_desktop_config.json");
|
|
21655
21943
|
}
|
|
21656
21944
|
function getOlamRepoPaths() {
|
|
21657
21945
|
const configPaths = [
|
|
21658
|
-
|
|
21659
|
-
|
|
21946
|
+
path43.join(os25.homedir(), ".olam", "config.yaml"),
|
|
21947
|
+
path43.join(process.cwd(), ".olam", "config.yaml")
|
|
21660
21948
|
];
|
|
21661
21949
|
const paths = [];
|
|
21662
21950
|
for (const configPath of configPaths) {
|
|
21663
|
-
if (!
|
|
21951
|
+
if (!fs40.existsSync(configPath)) continue;
|
|
21664
21952
|
try {
|
|
21665
|
-
const raw =
|
|
21953
|
+
const raw = fs40.readFileSync(configPath, "utf-8");
|
|
21666
21954
|
const repoMatches = [...raw.matchAll(/path:\s*["']?([^\s"'\n]+)/g)];
|
|
21667
21955
|
for (const m of repoMatches) {
|
|
21668
21956
|
if (m[1]) paths.push(m[1]);
|
|
@@ -21678,7 +21966,7 @@ async function discoverMcpSources(repoPaths) {
|
|
|
21678
21966
|
const sources = [];
|
|
21679
21967
|
const sourceDefs = [
|
|
21680
21968
|
{
|
|
21681
|
-
path:
|
|
21969
|
+
path: path43.join(os25.homedir(), ".claude.json"),
|
|
21682
21970
|
label: "Claude Code (~/.claude.json)"
|
|
21683
21971
|
},
|
|
21684
21972
|
{
|
|
@@ -21686,19 +21974,19 @@ async function discoverMcpSources(repoPaths) {
|
|
|
21686
21974
|
label: "Claude Desktop"
|
|
21687
21975
|
},
|
|
21688
21976
|
{
|
|
21689
|
-
path:
|
|
21977
|
+
path: path43.join(os25.homedir(), ".cursor", "mcp.json"),
|
|
21690
21978
|
label: "Cursor (~/.cursor/mcp.json)"
|
|
21691
21979
|
},
|
|
21692
21980
|
{
|
|
21693
|
-
path:
|
|
21981
|
+
path: path43.join(os25.homedir(), ".codeium", "windsurf", "mcp_config.json"),
|
|
21694
21982
|
label: "Windsurf (~/.codeium/windsurf/mcp_config.json)"
|
|
21695
21983
|
}
|
|
21696
21984
|
];
|
|
21697
21985
|
const resolvedRepoPaths = repoPaths ?? getOlamRepoPaths();
|
|
21698
21986
|
for (const repoPath of resolvedRepoPaths) {
|
|
21699
21987
|
sourceDefs.push({
|
|
21700
|
-
path:
|
|
21701
|
-
label: `.mcp.json (${
|
|
21988
|
+
path: path43.join(repoPath, ".mcp.json"),
|
|
21989
|
+
label: `.mcp.json (${path43.basename(repoPath)})`
|
|
21702
21990
|
});
|
|
21703
21991
|
}
|
|
21704
21992
|
const reads = await Promise.all(
|
|
@@ -21778,13 +22066,13 @@ async function validateMcpEntry(entry) {
|
|
|
21778
22066
|
// src/commands/mcp/import.ts
|
|
21779
22067
|
async function multiSelectPicker(entries) {
|
|
21780
22068
|
if (entries.length === 0) return [];
|
|
21781
|
-
console.log("\n" +
|
|
22069
|
+
console.log("\n" + pc27.bold("Discovered MCP servers:"));
|
|
21782
22070
|
entries.forEach((e, i) => {
|
|
21783
22071
|
console.log(
|
|
21784
|
-
` ${
|
|
22072
|
+
` ${pc27.dim(`[${i + 1}]`)} ${pc27.cyan(e.name.padEnd(20))} ${pc27.dim(e.sourceLabel)}`
|
|
21785
22073
|
);
|
|
21786
22074
|
});
|
|
21787
|
-
console.log("\n" +
|
|
22075
|
+
console.log("\n" + pc27.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
|
|
21788
22076
|
const answer = await new Promise((resolve8) => {
|
|
21789
22077
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
21790
22078
|
rl.question("> ", (ans) => {
|
|
@@ -21811,7 +22099,7 @@ function registerMcpImport(cmd) {
|
|
|
21811
22099
|
const repoPaths = opts.repoPaths ? opts.repoPaths.split(",").map((s) => s.trim()) : void 0;
|
|
21812
22100
|
const { entries, sources, durationMs } = await discoverMcpSources(repoPaths);
|
|
21813
22101
|
if (entries.length === 0) {
|
|
21814
|
-
console.log(
|
|
22102
|
+
console.log(pc27.dim("No MCP servers found in any source path."));
|
|
21815
22103
|
return;
|
|
21816
22104
|
}
|
|
21817
22105
|
printInfo("Sources", sources.length > 0 ? sources.join(", ") : "none");
|
|
@@ -21824,15 +22112,15 @@ function registerMcpImport(cmd) {
|
|
|
21824
22112
|
candidates = filtered;
|
|
21825
22113
|
}
|
|
21826
22114
|
if (skippedCount > 0) {
|
|
21827
|
-
console.log(
|
|
22115
|
+
console.log(pc27.dim(`skipped: ${skippedCount} already registered`));
|
|
21828
22116
|
}
|
|
21829
22117
|
if (candidates.length === 0) {
|
|
21830
|
-
console.log(
|
|
22118
|
+
console.log(pc27.dim("Nothing new to import. Use --reimport to force."));
|
|
21831
22119
|
return;
|
|
21832
22120
|
}
|
|
21833
22121
|
const selected = await multiSelectPicker(candidates);
|
|
21834
22122
|
if (selected.length === 0) {
|
|
21835
|
-
console.log(
|
|
22123
|
+
console.log(pc27.dim("No servers selected."));
|
|
21836
22124
|
return;
|
|
21837
22125
|
}
|
|
21838
22126
|
console.log(`
|
|
@@ -21843,16 +22131,16 @@ Importing ${selected.length} server(s)\u2026`);
|
|
|
21843
22131
|
let validated = false;
|
|
21844
22132
|
let validationReason = "skipped";
|
|
21845
22133
|
if (opts.validate !== false) {
|
|
21846
|
-
process.stdout.write(` ${
|
|
22134
|
+
process.stdout.write(` ${pc27.dim("\u2192")} ${entry.name} validating\u2026 `);
|
|
21847
22135
|
const vr = await validateMcpEntry(entry);
|
|
21848
22136
|
validated = vr.validated;
|
|
21849
22137
|
validationReason = vr.reason;
|
|
21850
22138
|
process.stdout.write(
|
|
21851
|
-
validated ?
|
|
22139
|
+
validated ? pc27.green("ok\n") : pc27.yellow(`unvalidated (${vr.reason})
|
|
21852
22140
|
`)
|
|
21853
22141
|
);
|
|
21854
22142
|
} else {
|
|
21855
|
-
console.log(` ${
|
|
22143
|
+
console.log(` ${pc27.dim("\u2192")} ${entry.name} ${pc27.dim("(validation skipped)")}`);
|
|
21856
22144
|
}
|
|
21857
22145
|
if (validated) validatedCount++;
|
|
21858
22146
|
const result = await client.staticAdd({
|
|
@@ -21867,21 +22155,21 @@ Importing ${selected.length} server(s)\u2026`);
|
|
|
21867
22155
|
}
|
|
21868
22156
|
}
|
|
21869
22157
|
console.log("");
|
|
21870
|
-
console.log(
|
|
22158
|
+
console.log(pc27.green(`\u2713 Imported ${importedCount}/${selected.length}`));
|
|
21871
22159
|
if (validatedCount > 0) {
|
|
21872
|
-
console.log(
|
|
22160
|
+
console.log(pc27.dim(` ${validatedCount} validated, ${importedCount - validatedCount} unvalidated`));
|
|
21873
22161
|
}
|
|
21874
22162
|
});
|
|
21875
22163
|
}
|
|
21876
22164
|
|
|
21877
22165
|
// src/commands/mcp/revoke.ts
|
|
21878
22166
|
init_output();
|
|
21879
|
-
import
|
|
22167
|
+
import pc28 from "picocolors";
|
|
21880
22168
|
function registerMcpRevoke(cmd) {
|
|
21881
22169
|
cmd.command("revoke <user> <world> <service>").description("Revoke a user's MCP service entitlement (multi-tenant mode only)").action(async (user, world, service) => {
|
|
21882
22170
|
const multiTenant = (process.env["OLAM_MCP_MULTI_TENANT"] ?? "").toLowerCase() === "true";
|
|
21883
22171
|
if (!multiTenant) {
|
|
21884
|
-
console.warn(
|
|
22172
|
+
console.warn(pc28.yellow("\u26A0 revocation only meaningful in multi_tenant mode \u2014 no-op"));
|
|
21885
22173
|
return;
|
|
21886
22174
|
}
|
|
21887
22175
|
const baseUrl = process.env["OLAM_MCP_AUTH_SERVICE_URL"] ?? "http://127.0.0.1:9998";
|
|
@@ -21910,8 +22198,8 @@ function registerMcpRevoke(cmd) {
|
|
|
21910
22198
|
process.exitCode = 1;
|
|
21911
22199
|
return;
|
|
21912
22200
|
}
|
|
21913
|
-
console.log(
|
|
21914
|
-
console.log(
|
|
22201
|
+
console.log(pc28.green(`\u2713 Revoked: ${user} / ${world} / ${service}`));
|
|
22202
|
+
console.log(pc28.dim(" Next fetch-creds call returns 403; token cleared on next merge."));
|
|
21915
22203
|
});
|
|
21916
22204
|
}
|
|
21917
22205
|
|
|
@@ -21928,18 +22216,18 @@ function registerMcp(program2) {
|
|
|
21928
22216
|
}
|
|
21929
22217
|
|
|
21930
22218
|
// src/pleri-config.ts
|
|
21931
|
-
import * as
|
|
21932
|
-
import * as
|
|
22219
|
+
import * as fs41 from "node:fs";
|
|
22220
|
+
import * as path44 from "node:path";
|
|
21933
22221
|
function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
|
|
21934
22222
|
if (process.env.PLERI_BASE_URL) {
|
|
21935
22223
|
return true;
|
|
21936
22224
|
}
|
|
21937
|
-
const configPath =
|
|
21938
|
-
if (!
|
|
22225
|
+
const configPath = path44.join(configDir, "config.yaml");
|
|
22226
|
+
if (!fs41.existsSync(configPath)) {
|
|
21939
22227
|
return false;
|
|
21940
22228
|
}
|
|
21941
22229
|
try {
|
|
21942
|
-
const contents =
|
|
22230
|
+
const contents = fs41.readFileSync(configPath, "utf8");
|
|
21943
22231
|
return /^[^#\n]*\bpleri:/m.test(contents);
|
|
21944
22232
|
} catch {
|
|
21945
22233
|
return false;
|
|
@@ -21950,14 +22238,14 @@ function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
|
|
|
21950
22238
|
var program = new Command();
|
|
21951
22239
|
function readCliVersion() {
|
|
21952
22240
|
try {
|
|
21953
|
-
const here =
|
|
22241
|
+
const here = path45.dirname(fileURLToPath4(import.meta.url));
|
|
21954
22242
|
for (const candidate of [
|
|
21955
|
-
|
|
21956
|
-
|
|
21957
|
-
|
|
22243
|
+
path45.join(here, "package.json"),
|
|
22244
|
+
path45.join(here, "..", "package.json"),
|
|
22245
|
+
path45.join(here, "..", "..", "package.json")
|
|
21958
22246
|
]) {
|
|
21959
|
-
if (
|
|
21960
|
-
const pkg = JSON.parse(
|
|
22247
|
+
if (fs42.existsSync(candidate)) {
|
|
22248
|
+
const pkg = JSON.parse(fs42.readFileSync(candidate, "utf-8"));
|
|
21961
22249
|
if (typeof pkg.version === "string" && pkg.version.length > 0) return pkg.version;
|
|
21962
22250
|
}
|
|
21963
22251
|
}
|
|
@@ -21996,5 +22284,6 @@ registerBegin(program);
|
|
|
21996
22284
|
registerStop(program);
|
|
21997
22285
|
registerWorldUpgrade(program);
|
|
21998
22286
|
registerMcp(program);
|
|
21999
|
-
|
|
22287
|
+
registerConfig(program);
|
|
22288
|
+
registerRepos(program);
|
|
22000
22289
|
program.parse();
|