@pleri/olam-cli 0.1.166 → 0.1.167
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/README.md +4 -2
- package/dist/commands/bootstrap.d.ts +6 -0
- package/dist/commands/bootstrap.d.ts.map +1 -1
- package/dist/commands/bootstrap.js +15 -0
- package/dist/commands/bootstrap.js.map +1 -1
- package/dist/commands/doctor.js +4 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts +4 -3
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +103 -81
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/memory-service-container.d.ts +8 -0
- package/dist/commands/memory-service-container.d.ts.map +1 -1
- package/dist/commands/memory-service-container.js +16 -1
- package/dist/commands/memory-service-container.js.map +1 -1
- package/dist/commands/setup.d.ts +62 -14
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +373 -42
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/skills-source.d.ts.map +1 -1
- package/dist/commands/skills-source.js +89 -4
- package/dist/commands/skills-source.js.map +1 -1
- package/dist/image-digests.json +8 -7
- package/dist/index.js +672 -168
- package/dist/lib/bootstrap-kubernetes.d.ts.map +1 -1
- package/dist/lib/bootstrap-kubernetes.js +163 -106
- package/dist/lib/bootstrap-kubernetes.js.map +1 -1
- package/dist/lib/health-probes.d.ts +16 -0
- package/dist/lib/health-probes.d.ts.map +1 -1
- package/dist/lib/health-probes.js +49 -0
- package/dist/lib/health-probes.js.map +1 -1
- package/dist/lib/peripheral-registry.d.ts +9 -3
- package/dist/lib/peripheral-registry.d.ts.map +1 -1
- package/dist/lib/peripheral-registry.js +4 -4
- package/dist/lib/peripheral-registry.js.map +1 -1
- package/dist/lib/port-forward.js +1 -1
- package/dist/lib/port-forward.js.map +1 -1
- package/dist/lib/upgrade-kubernetes.d.ts +1 -1
- package/dist/lib/upgrade-kubernetes.d.ts.map +1 -1
- package/dist/lib/upgrade-kubernetes.js +35 -21
- package/dist/lib/upgrade-kubernetes.js.map +1 -1
- package/dist/mcp-server.js +990 -331
- package/hermes-bundle/version.json +1 -1
- package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
- package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
- package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
- package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
- package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5397,7 +5397,7 @@ var init_client = __esm({
|
|
|
5397
5397
|
"use strict";
|
|
5398
5398
|
init_secret();
|
|
5399
5399
|
DEFAULT_BASE_URL = "http://127.0.0.1:9999";
|
|
5400
|
-
DEFAULT_TIMEOUT_MS =
|
|
5400
|
+
DEFAULT_TIMEOUT_MS = 1e4;
|
|
5401
5401
|
RETRY_COUNT = 2;
|
|
5402
5402
|
RETRY_BACKOFF_MS = 250;
|
|
5403
5403
|
AuthClient = class {
|
|
@@ -7884,6 +7884,38 @@ function hasImageRef(present, ref) {
|
|
|
7884
7884
|
const variants = [`docker.io/library/${ref}`, `docker.io/${ref}`];
|
|
7885
7885
|
return variants.some((v) => present.has(v));
|
|
7886
7886
|
}
|
|
7887
|
+
async function probeKubectl(exec = defaultDockerExec) {
|
|
7888
|
+
const r = exec("kubectl", ["version", "--client", "--output=json"]);
|
|
7889
|
+
if (r.status === 0 && r.stdout.length > 0) {
|
|
7890
|
+
let clientVersion = "unknown";
|
|
7891
|
+
try {
|
|
7892
|
+
const parsed = JSON.parse(r.stdout);
|
|
7893
|
+
const clientInfo = parsed.clientVersion;
|
|
7894
|
+
if (typeof clientInfo?.gitVersion === "string") {
|
|
7895
|
+
clientVersion = clientInfo.gitVersion;
|
|
7896
|
+
}
|
|
7897
|
+
} catch {
|
|
7898
|
+
}
|
|
7899
|
+
return { ok: true, message: `kubectl ${clientVersion} on PATH` };
|
|
7900
|
+
}
|
|
7901
|
+
return {
|
|
7902
|
+
ok: false,
|
|
7903
|
+
message: "kubectl not found on PATH",
|
|
7904
|
+
remedy: "Install kubectl: macOS: `brew install kubectl`; Linux: https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/"
|
|
7905
|
+
};
|
|
7906
|
+
}
|
|
7907
|
+
async function probeK3d(exec = defaultDockerExec) {
|
|
7908
|
+
const r = exec("k3d", ["version"]);
|
|
7909
|
+
if (r.status === 0 && r.stdout.length > 0) {
|
|
7910
|
+
const versionLine = r.stdout.trim().split("\n")[0] ?? "";
|
|
7911
|
+
return { ok: true, message: `k3d ${versionLine} on PATH` };
|
|
7912
|
+
}
|
|
7913
|
+
return {
|
|
7914
|
+
ok: false,
|
|
7915
|
+
message: "k3d not found on PATH",
|
|
7916
|
+
remedy: "Install k3d: `brew install k3d` (macOS) or curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash"
|
|
7917
|
+
};
|
|
7918
|
+
}
|
|
7887
7919
|
var HEALTH_TIMEOUT_MS, COLIMA_010_WARN_TEXT, COLIMA_010_RANGE, defaultDockerExec, defaultFetch;
|
|
7888
7920
|
var init_health_probes = __esm({
|
|
7889
7921
|
"src/lib/health-probes.ts"() {
|
|
@@ -11067,7 +11099,19 @@ var init_schema3 = __esm({
|
|
|
11067
11099
|
* use canonical names; `olam flywheel migrate-overlays --push` enforces
|
|
11068
11100
|
* this via the reverse validator.
|
|
11069
11101
|
*/
|
|
11070
|
-
prefix: external_exports.string().regex(PREFIX_PATTERN, "skill-source prefix must be ASCII lowercase + digits + dash/underscore (1-39 chars, no leading/trailing dash)").optional()
|
|
11102
|
+
prefix: external_exports.string().regex(PREFIX_PATTERN, "skill-source prefix must be ASCII lowercase + digits + dash/underscore (1-39 chars, no leading/trailing dash)").optional(),
|
|
11103
|
+
/**
|
|
11104
|
+
* Which artifact kinds get renamed when `prefix` is set. Optional; defaults
|
|
11105
|
+
* to `['skill', 'agent']` for back-compat with the original Phase A semantic
|
|
11106
|
+
* (Decision 6 in docs/decisions/019-skill-prefix-rules.md). Operators who
|
|
11107
|
+
* want to rebrand ONLY skills (keeping `@architect` etc. canonical) set
|
|
11108
|
+
* `['skill']`; ones who want only agents set `['agent']`.
|
|
11109
|
+
*
|
|
11110
|
+
* Empty array `[]` = same as omitting `prefix` entirely (no renaming).
|
|
11111
|
+
*
|
|
11112
|
+
* NOT applicable when `prefix` is undefined.
|
|
11113
|
+
*/
|
|
11114
|
+
prefixScope: external_exports.array(external_exports.enum(["skill", "agent"])).optional()
|
|
11071
11115
|
});
|
|
11072
11116
|
}
|
|
11073
11117
|
});
|
|
@@ -16413,29 +16457,26 @@ function updateSkillSource(id, patch) {
|
|
|
16413
16457
|
}
|
|
16414
16458
|
}
|
|
16415
16459
|
const existing = config.skillSources[idx];
|
|
16416
|
-
let
|
|
16460
|
+
let working = { ...existing };
|
|
16417
16461
|
if (patch.prefix === null) {
|
|
16418
|
-
const { prefix:
|
|
16419
|
-
void
|
|
16420
|
-
|
|
16421
|
-
...rest,
|
|
16422
|
-
...patch.name !== void 0 ? { name: patch.name } : {},
|
|
16423
|
-
...patch.branch !== void 0 ? { branch: patch.branch } : {},
|
|
16424
|
-
...patch.lastPulledSha !== void 0 ? { lastPulledSha: patch.lastPulledSha } : {}
|
|
16425
|
-
};
|
|
16426
|
-
const next2 = [...config.skillSources];
|
|
16427
|
-
next2[idx] = updated2;
|
|
16428
|
-
writeGlobalConfig({ ...config, skillSources: next2 });
|
|
16429
|
-
return updated2;
|
|
16462
|
+
const { prefix: _p, ...rest } = working;
|
|
16463
|
+
void _p;
|
|
16464
|
+
working = rest;
|
|
16430
16465
|
} else if (patch.prefix !== void 0) {
|
|
16431
|
-
|
|
16466
|
+
working = { ...working, prefix: patch.prefix };
|
|
16467
|
+
}
|
|
16468
|
+
if (patch.prefixScope === null) {
|
|
16469
|
+
const { prefixScope: _s, ...rest } = working;
|
|
16470
|
+
void _s;
|
|
16471
|
+
working = rest;
|
|
16472
|
+
} else if (patch.prefixScope !== void 0) {
|
|
16473
|
+
working = { ...working, prefixScope: [...patch.prefixScope] };
|
|
16432
16474
|
}
|
|
16433
16475
|
const updated = {
|
|
16434
|
-
...
|
|
16476
|
+
...working,
|
|
16435
16477
|
...patch.name !== void 0 ? { name: patch.name } : {},
|
|
16436
16478
|
...patch.branch !== void 0 ? { branch: patch.branch } : {},
|
|
16437
|
-
...patch.lastPulledSha !== void 0 ? { lastPulledSha: patch.lastPulledSha } : {}
|
|
16438
|
-
...prefixUpdate
|
|
16479
|
+
...patch.lastPulledSha !== void 0 ? { lastPulledSha: patch.lastPulledSha } : {}
|
|
16439
16480
|
};
|
|
16440
16481
|
const next = [...config.skillSources];
|
|
16441
16482
|
next[idx] = updated;
|
|
@@ -17249,7 +17290,7 @@ function detectCollisions(artifacts) {
|
|
|
17249
17290
|
}
|
|
17250
17291
|
return { winners, collisions };
|
|
17251
17292
|
}
|
|
17252
|
-
function cleanManagedSymlinks(claude, installedOlamVersion, overlayReferences) {
|
|
17293
|
+
function cleanManagedSymlinks(claude, installedOlamVersion, overlayReferences, expectedAgentWinnerNames) {
|
|
17253
17294
|
const shadowBackups = [];
|
|
17254
17295
|
for (const bucket of BUCKETS) {
|
|
17255
17296
|
const dir = path59.join(claude, bucket);
|
|
@@ -17283,8 +17324,11 @@ function cleanManagedSymlinks(claude, installedOlamVersion, overlayReferences) {
|
|
|
17283
17324
|
}
|
|
17284
17325
|
fs58.unlinkSync(p);
|
|
17285
17326
|
} else if (bucket === "agents" && stat.isFile() && !name.includes(".shadow-backup-")) {
|
|
17286
|
-
const
|
|
17287
|
-
|
|
17327
|
+
const hasWinner = expectedAgentWinnerNames !== void 0 ? expectedAgentWinnerNames.has(name) : true;
|
|
17328
|
+
if (hasWinner) {
|
|
17329
|
+
const backup3 = shadowBackup(p);
|
|
17330
|
+
shadowBackups.push(backup3);
|
|
17331
|
+
}
|
|
17288
17332
|
}
|
|
17289
17333
|
} catch {
|
|
17290
17334
|
}
|
|
@@ -17324,8 +17368,9 @@ function deployArtifacts(artifacts, opts) {
|
|
|
17324
17368
|
for (const bucket of BUCKETS) {
|
|
17325
17369
|
fs58.mkdirSync(path59.join(claude, bucket), { recursive: true });
|
|
17326
17370
|
}
|
|
17327
|
-
const sweepShadowBackups = cleanManagedSymlinks(claude, opts?.installedOlamVersion, opts?.overlayReferences);
|
|
17328
17371
|
const { winners, collisions } = detectCollisions(artifacts);
|
|
17372
|
+
const expectedAgentWinnerNames = new Set(winners.filter((a) => a.kind === "agent").map((a) => a.deployBasename));
|
|
17373
|
+
const sweepShadowBackups = cleanManagedSymlinks(claude, opts?.installedOlamVersion, opts?.overlayReferences, expectedAgentWinnerNames);
|
|
17329
17374
|
const result = { linked: 0, shadowBackups: [...sweepShadowBackups], collisions };
|
|
17330
17375
|
for (const artifact of winners) {
|
|
17331
17376
|
const bucket = bucketFor(artifact.kind);
|
|
@@ -18860,15 +18905,18 @@ import * as fs68 from "node:fs";
|
|
|
18860
18905
|
import * as path67 from "node:path";
|
|
18861
18906
|
function buildSourcePrefixMap(sources) {
|
|
18862
18907
|
const byId = /* @__PURE__ */ new Map();
|
|
18908
|
+
const scopeById = /* @__PURE__ */ new Map();
|
|
18863
18909
|
const prefixes = /* @__PURE__ */ new Set();
|
|
18864
18910
|
for (const s of sources) {
|
|
18865
18911
|
if (s.prefix !== void 0 && s.prefix.length > 0) {
|
|
18866
18912
|
byId.set(s.id, s.prefix);
|
|
18913
|
+
scopeById.set(s.id, s.prefixScope ?? DEFAULT_SCOPE);
|
|
18867
18914
|
prefixes.add(s.prefix);
|
|
18868
18915
|
}
|
|
18869
18916
|
}
|
|
18870
18917
|
return {
|
|
18871
18918
|
get: (sourceId) => byId.get(sourceId),
|
|
18919
|
+
getScope: (sourceId) => scopeById.get(sourceId) ?? DEFAULT_SCOPE,
|
|
18872
18920
|
registeredPrefixes: Array.from(prefixes)
|
|
18873
18921
|
};
|
|
18874
18922
|
}
|
|
@@ -18880,6 +18928,9 @@ function applyPrefixRewrites(baseArtifacts, sourceMap, claudeDir2, dryRun) {
|
|
|
18880
18928
|
const prefix = sourceMap.get(artifact.sourceId);
|
|
18881
18929
|
if (prefix === void 0)
|
|
18882
18930
|
continue;
|
|
18931
|
+
const scope = sourceMap.getScope(artifact.sourceId);
|
|
18932
|
+
if (!scope.includes(artifact.kind))
|
|
18933
|
+
continue;
|
|
18883
18934
|
const canonical = artifact.deployBasename;
|
|
18884
18935
|
const otherPrefixes = sourceMap.registeredPrefixes.filter((p) => p !== prefix);
|
|
18885
18936
|
const renamed = applyPrefix(canonical, prefix, otherPrefixes);
|
|
@@ -18946,11 +18997,13 @@ function detectPrefixCollisions(sources) {
|
|
|
18946
18997
|
}
|
|
18947
18998
|
return collisions;
|
|
18948
18999
|
}
|
|
19000
|
+
var DEFAULT_SCOPE;
|
|
18949
19001
|
var init_prefix_deploy = __esm({
|
|
18950
19002
|
"../core/dist/skill-sync/prefix-deploy.js"() {
|
|
18951
19003
|
"use strict";
|
|
18952
19004
|
init_prefix_rules();
|
|
18953
19005
|
init_managed_merge();
|
|
19006
|
+
DEFAULT_SCOPE = ["skill", "agent"];
|
|
18954
19007
|
}
|
|
18955
19008
|
});
|
|
18956
19009
|
|
|
@@ -19940,7 +19993,7 @@ __export(project_sweep_exports, {
|
|
|
19940
19993
|
walkProjectRoot: () => walkProjectRoot
|
|
19941
19994
|
});
|
|
19942
19995
|
import * as path72 from "node:path";
|
|
19943
|
-
import { readdirSync as
|
|
19996
|
+
import { readdirSync as readdirSync25, lstatSync as lstatSync6, statSync as statSync25, existsSync as existsSync81 } from "node:fs";
|
|
19944
19997
|
function isSkipped(basename16, extra) {
|
|
19945
19998
|
if (DEFAULT_SKIP.has(basename16))
|
|
19946
19999
|
return true;
|
|
@@ -20004,7 +20057,7 @@ function walk2(currentPath, depth, maxDepth, extraExclude, fsAdapter, results) {
|
|
|
20004
20057
|
}
|
|
20005
20058
|
function makeRealFsAdapter() {
|
|
20006
20059
|
return {
|
|
20007
|
-
readdirSync: (p) =>
|
|
20060
|
+
readdirSync: (p) => readdirSync25(p, { encoding: "utf-8" }),
|
|
20008
20061
|
// lstatSync does NOT follow symlinks — used for descent decisions.
|
|
20009
20062
|
lstatSync: (p) => {
|
|
20010
20063
|
const s = lstatSync6(p, { throwIfNoEntry: true });
|
|
@@ -20188,6 +20241,7 @@ init_output();
|
|
|
20188
20241
|
import * as fs6 from "node:fs";
|
|
20189
20242
|
import * as path6 from "node:path";
|
|
20190
20243
|
import { execSync } from "node:child_process";
|
|
20244
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
20191
20245
|
import pc3 from "picocolors";
|
|
20192
20246
|
|
|
20193
20247
|
// src/commands/workspace.ts
|
|
@@ -20442,9 +20496,11 @@ function writeConfig(updates, opts = {}) {
|
|
|
20442
20496
|
|
|
20443
20497
|
// src/commands/init.ts
|
|
20444
20498
|
function detectProjectType(root) {
|
|
20445
|
-
if (fs6.existsSync(path6.join(root, "Gemfile")) || fs6.existsSync(path6.join(root, "config", "routes.rb")))
|
|
20499
|
+
if (fs6.existsSync(path6.join(root, "Gemfile")) || fs6.existsSync(path6.join(root, "config", "routes.rb")))
|
|
20500
|
+
return "rails";
|
|
20446
20501
|
if (fs6.existsSync(path6.join(root, "package.json"))) return "node";
|
|
20447
|
-
if (fs6.existsSync(path6.join(root, "pyproject.toml")) || fs6.existsSync(path6.join(root, "requirements.txt")))
|
|
20502
|
+
if (fs6.existsSync(path6.join(root, "pyproject.toml")) || fs6.existsSync(path6.join(root, "requirements.txt")))
|
|
20503
|
+
return "python";
|
|
20448
20504
|
return "generic";
|
|
20449
20505
|
}
|
|
20450
20506
|
function getRepoName(root) {
|
|
@@ -20461,7 +20517,9 @@ function getRepoName(root) {
|
|
|
20461
20517
|
}
|
|
20462
20518
|
function detectK3dOlamContexts(execFn = (cmd, opts) => execSync(cmd, opts)) {
|
|
20463
20519
|
try {
|
|
20464
|
-
const raw = execFn("kubectl config get-contexts -o name", {
|
|
20520
|
+
const raw = execFn("kubectl config get-contexts -o name", {
|
|
20521
|
+
encoding: "utf-8"
|
|
20522
|
+
});
|
|
20465
20523
|
const contexts = raw.split("\n").map((l) => l.trim()).filter((l) => /^k3d-olam-/.test(l));
|
|
20466
20524
|
return { contexts };
|
|
20467
20525
|
} catch {
|
|
@@ -20472,11 +20530,14 @@ function applyKubectlContextPin(contexts, opts = {}) {
|
|
|
20472
20530
|
const configPath = opts.configPath ?? OLAM_CONFIG_PATH;
|
|
20473
20531
|
const readFn = opts.readFileSyncFn ?? fs6.readFileSync;
|
|
20474
20532
|
const writeFn = opts.writeFileSyncFn ?? fs6.writeFileSync;
|
|
20533
|
+
const mkdirFn = opts.mkdirSyncFn ?? fs6.mkdirSync;
|
|
20475
20534
|
if (contexts.length === 0) {
|
|
20476
20535
|
return { skipped: "no ^k3d-olam- contexts found" };
|
|
20477
20536
|
}
|
|
20478
20537
|
if (contexts.length > 1) {
|
|
20479
|
-
return {
|
|
20538
|
+
return {
|
|
20539
|
+
refused: `multiple ^k3d-olam- contexts found: ${contexts.join(", ")} \u2014 set host.kubectl_context_pinned manually`
|
|
20540
|
+
};
|
|
20480
20541
|
}
|
|
20481
20542
|
const context = contexts[0];
|
|
20482
20543
|
let parsed = {};
|
|
@@ -20484,17 +20545,26 @@ function applyKubectlContextPin(contexts, opts = {}) {
|
|
|
20484
20545
|
const raw = readFn(configPath, "utf8");
|
|
20485
20546
|
parsed = JSON.parse(raw);
|
|
20486
20547
|
} catch {
|
|
20487
|
-
parsed = {
|
|
20548
|
+
parsed = {
|
|
20549
|
+
"config.schema": 1,
|
|
20550
|
+
host: { substrate: "kubernetes" },
|
|
20551
|
+
install_id: randomUUID2()
|
|
20552
|
+
};
|
|
20488
20553
|
}
|
|
20489
20554
|
const host = typeof parsed.host === "object" && parsed.host !== null ? parsed.host : {};
|
|
20490
20555
|
if (typeof host["kubectl_context_pinned"] === "string" && host["kubectl_context_pinned"].length > 0) {
|
|
20491
|
-
return {
|
|
20556
|
+
return {
|
|
20557
|
+
skipped: `kubectl_context_pinned already set to ${host["kubectl_context_pinned"]}`
|
|
20558
|
+
};
|
|
20492
20559
|
}
|
|
20493
20560
|
const next = {
|
|
20494
20561
|
...parsed,
|
|
20495
20562
|
host: { ...host, kubectl_context_pinned: context }
|
|
20496
20563
|
};
|
|
20497
|
-
|
|
20564
|
+
mkdirFn(path6.dirname(configPath), { recursive: true });
|
|
20565
|
+
writeFn(configPath, JSON.stringify(next, null, 2) + "\n", {
|
|
20566
|
+
encoding: "utf8"
|
|
20567
|
+
});
|
|
20498
20568
|
return { pinned: context };
|
|
20499
20569
|
}
|
|
20500
20570
|
function findProjectRoot(startDir) {
|
|
@@ -20570,14 +20640,19 @@ function registerInit(program2) {
|
|
|
20570
20640
|
printInfo("Project", `${projectType} (detected)`);
|
|
20571
20641
|
printInfo("Repo", repoName);
|
|
20572
20642
|
try {
|
|
20573
|
-
const result = ensureProjectWorkspaceFromConfig(
|
|
20643
|
+
const result = ensureProjectWorkspaceFromConfig(
|
|
20644
|
+
projectRoot,
|
|
20645
|
+
repoName
|
|
20646
|
+
);
|
|
20574
20647
|
if (result.created) {
|
|
20575
20648
|
printInfo("Workspace", `${repoName} \u2192 ${result.file}`);
|
|
20576
20649
|
} else {
|
|
20577
20650
|
printInfo("Workspace", `${repoName} (already registered)`);
|
|
20578
20651
|
}
|
|
20579
20652
|
} catch (err) {
|
|
20580
|
-
printError(
|
|
20653
|
+
printError(
|
|
20654
|
+
`Workspace auto-register failed: ${err instanceof Error ? err.message : String(err)}`
|
|
20655
|
+
);
|
|
20581
20656
|
}
|
|
20582
20657
|
const { contexts } = detectK3dOlamContexts();
|
|
20583
20658
|
if (contexts !== null) {
|
|
@@ -20585,12 +20660,16 @@ function registerInit(program2) {
|
|
|
20585
20660
|
if ("pinned" in pinResult) {
|
|
20586
20661
|
printInfo("kubectl context", `${pinResult.pinned} (auto-pinned)`);
|
|
20587
20662
|
} else if ("refused" in pinResult) {
|
|
20588
|
-
process.stderr.write(
|
|
20589
|
-
|
|
20663
|
+
process.stderr.write(
|
|
20664
|
+
`${pc3.yellow("warn:")} ${pinResult.refused}
|
|
20665
|
+
`
|
|
20666
|
+
);
|
|
20590
20667
|
}
|
|
20591
20668
|
}
|
|
20592
|
-
console.log(
|
|
20593
|
-
|
|
20669
|
+
console.log(
|
|
20670
|
+
`
|
|
20671
|
+
${pc3.dim(`Next: olam create --name my-world --workspace ${repoName} --task "..."`)}`
|
|
20672
|
+
);
|
|
20594
20673
|
} catch (err) {
|
|
20595
20674
|
printError(err instanceof Error ? err.message : String(err));
|
|
20596
20675
|
process.exitCode = 1;
|
|
@@ -20950,7 +21029,13 @@ import pc7 from "picocolors";
|
|
|
20950
21029
|
init_output();
|
|
20951
21030
|
init_install_root();
|
|
20952
21031
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
20953
|
-
import {
|
|
21032
|
+
import {
|
|
21033
|
+
existsSync as existsSync29,
|
|
21034
|
+
mkdirSync as mkdirSync19,
|
|
21035
|
+
readdirSync as readdirSync9,
|
|
21036
|
+
writeFileSync as writeFileSync15,
|
|
21037
|
+
chmodSync as chmodSync4
|
|
21038
|
+
} from "node:fs";
|
|
20954
21039
|
import { join as join34 } from "node:path";
|
|
20955
21040
|
import { homedir as homedir19, platform } from "node:os";
|
|
20956
21041
|
import { randomBytes as randomBytes7 } from "node:crypto";
|
|
@@ -21394,8 +21479,14 @@ var REQUIRED_TOOLS = [
|
|
|
21394
21479
|
{ name: "kubectl", brew: "kubectl" },
|
|
21395
21480
|
{ name: "helm", brew: "helm" },
|
|
21396
21481
|
{ name: "jq", brew: "jq" },
|
|
21397
|
-
{
|
|
21398
|
-
|
|
21482
|
+
{
|
|
21483
|
+
name: "curl",
|
|
21484
|
+
hint: "expected on macOS by default; `apt install curl` on linux"
|
|
21485
|
+
},
|
|
21486
|
+
{
|
|
21487
|
+
name: "openssl",
|
|
21488
|
+
hint: "expected on macOS by default; `apt install openssl` on linux"
|
|
21489
|
+
},
|
|
21399
21490
|
{ name: "gh", brew: "gh", hint: "after install: `gh auth login`" },
|
|
21400
21491
|
{ name: "docker", hint: "Docker Desktop, or colima on macOS" }
|
|
21401
21492
|
];
|
|
@@ -21413,7 +21504,10 @@ var OBSERVABILITY_SCRIPTS = [
|
|
|
21413
21504
|
"kyverno-cardinality-mutate.sh"
|
|
21414
21505
|
];
|
|
21415
21506
|
function hasTool(tool) {
|
|
21416
|
-
const result = spawnSync10("command", ["-v", tool], {
|
|
21507
|
+
const result = spawnSync10("command", ["-v", tool], {
|
|
21508
|
+
shell: true,
|
|
21509
|
+
stdio: "pipe"
|
|
21510
|
+
});
|
|
21417
21511
|
return result.status === 0;
|
|
21418
21512
|
}
|
|
21419
21513
|
function detectMissingTools() {
|
|
@@ -21445,8 +21539,15 @@ function preflight(opts) {
|
|
|
21445
21539
|
} else if (opts.autoInstall && platform() === "darwin") {
|
|
21446
21540
|
const brewable = missing.filter((t) => t.brew);
|
|
21447
21541
|
if (brewable.length > 0) {
|
|
21448
|
-
printInfo(
|
|
21449
|
-
|
|
21542
|
+
printInfo(
|
|
21543
|
+
"auto-install",
|
|
21544
|
+
`${brewable.length} brew formula(s): ${brewable.map((t) => t.brew).join(", ")}`
|
|
21545
|
+
);
|
|
21546
|
+
runOrFail(
|
|
21547
|
+
"brew",
|
|
21548
|
+
["install", ...brewable.map((t) => t.brew)],
|
|
21549
|
+
"brew install"
|
|
21550
|
+
);
|
|
21450
21551
|
}
|
|
21451
21552
|
const stillMissing = detectMissingTools();
|
|
21452
21553
|
if (stillMissing.length > 0) {
|
|
@@ -21465,7 +21566,9 @@ function preflight(opts) {
|
|
|
21465
21566
|
process.stderr.write(` - ${pc6.bold(t.name)}: ${hint}
|
|
21466
21567
|
`);
|
|
21467
21568
|
}
|
|
21468
|
-
process.stderr.write(
|
|
21569
|
+
process.stderr.write(
|
|
21570
|
+
"\nRe-run with --auto-install on macOS to install brew-formulae automatically.\n"
|
|
21571
|
+
);
|
|
21469
21572
|
process.exit(1);
|
|
21470
21573
|
}
|
|
21471
21574
|
if (!runCapture("gh", ["auth", "status"]).ok) {
|
|
@@ -21501,16 +21604,33 @@ function ensureColima() {
|
|
|
21501
21604
|
printWarning("colima not running \u2014 starting");
|
|
21502
21605
|
runOrFail(
|
|
21503
21606
|
"colima",
|
|
21504
|
-
[
|
|
21607
|
+
[
|
|
21608
|
+
"start",
|
|
21609
|
+
"--cpu",
|
|
21610
|
+
"4",
|
|
21611
|
+
"--memory",
|
|
21612
|
+
"8",
|
|
21613
|
+
"--vm-type=vz",
|
|
21614
|
+
"--mount-type=virtiofs"
|
|
21615
|
+
],
|
|
21505
21616
|
"colima start"
|
|
21506
21617
|
);
|
|
21507
21618
|
}
|
|
21508
21619
|
printSuccess("colima running");
|
|
21509
|
-
const chmod = runCapture("colima", [
|
|
21620
|
+
const chmod = runCapture("colima", [
|
|
21621
|
+
"ssh",
|
|
21622
|
+
"--",
|
|
21623
|
+
"sudo",
|
|
21624
|
+
"chmod",
|
|
21625
|
+
"666",
|
|
21626
|
+
"/var/run/docker.sock"
|
|
21627
|
+
]);
|
|
21510
21628
|
if (chmod.ok) {
|
|
21511
21629
|
printSuccess("docker.sock chmod applied inside colima VM");
|
|
21512
21630
|
} else {
|
|
21513
|
-
printWarning(
|
|
21631
|
+
printWarning(
|
|
21632
|
+
"colima ssh chmod failed \u2014 k3d cluster create may still succeed"
|
|
21633
|
+
);
|
|
21514
21634
|
}
|
|
21515
21635
|
}
|
|
21516
21636
|
function ensureCluster(opts) {
|
|
@@ -21526,14 +21646,25 @@ function ensureCluster(opts) {
|
|
|
21526
21646
|
const ghConfigBind = `${homedir19()}/.config/gh:/host/.config/gh`;
|
|
21527
21647
|
runOrFail(
|
|
21528
21648
|
"k3d",
|
|
21529
|
-
[
|
|
21649
|
+
[
|
|
21650
|
+
"cluster",
|
|
21651
|
+
"create",
|
|
21652
|
+
opts.cluster,
|
|
21653
|
+
"--volume",
|
|
21654
|
+
ghConfigBind,
|
|
21655
|
+
"--wait",
|
|
21656
|
+
"--timeout",
|
|
21657
|
+
"90s"
|
|
21658
|
+
],
|
|
21530
21659
|
`k3d cluster create ${opts.cluster}`
|
|
21531
21660
|
);
|
|
21532
21661
|
if (!runCapture("kubectl", ["cluster-info"]).ok) {
|
|
21533
21662
|
printError("kubectl cannot reach the cluster \u2014 check kubeconfig context");
|
|
21534
21663
|
process.exit(1);
|
|
21535
21664
|
}
|
|
21536
|
-
printSuccess(
|
|
21665
|
+
printSuccess(
|
|
21666
|
+
`cluster ready (${runCapture("kubectl", ["config", "current-context"]).stdout.trim()})`
|
|
21667
|
+
);
|
|
21537
21668
|
}
|
|
21538
21669
|
function resolveObservabilityScriptsDir() {
|
|
21539
21670
|
const installed = join34(installRoot(), "host-cp", "observability");
|
|
@@ -21570,12 +21701,14 @@ function installObservability(opts) {
|
|
|
21570
21701
|
step("4/6 \u2014 observability (skipped via --skip-observability)");
|
|
21571
21702
|
return;
|
|
21572
21703
|
}
|
|
21573
|
-
step(
|
|
21704
|
+
step(
|
|
21705
|
+
"4/6 \u2014 observability stack (Loki + Promtail + Grafana + Prometheus + Kyverno)"
|
|
21706
|
+
);
|
|
21574
21707
|
const observabilityDir = resolveObservabilityScriptsDir();
|
|
21575
21708
|
if (!observabilityDir) {
|
|
21576
|
-
|
|
21577
|
-
|
|
21578
|
-
|
|
21709
|
+
throw new Error(
|
|
21710
|
+
`Bundled observability assets missing. This indicates a corrupt or incomplete @pleri/olam-cli installation. Remediation: reinstall with 'npm install -g @pleri/olam-cli@latest', or open an issue at https://github.com/pleri/olam/issues with this error.`
|
|
21711
|
+
);
|
|
21579
21712
|
}
|
|
21580
21713
|
const bundleRoot = resolveBundleRoot();
|
|
21581
21714
|
const scriptEnv = { ...process.env };
|
|
@@ -21589,10 +21722,15 @@ function installObservability(opts) {
|
|
|
21589
21722
|
continue;
|
|
21590
21723
|
}
|
|
21591
21724
|
printInfo("run", script);
|
|
21592
|
-
const result = spawnSync10("bash", [path94], {
|
|
21725
|
+
const result = spawnSync10("bash", [path94], {
|
|
21726
|
+
stdio: "inherit",
|
|
21727
|
+
env: scriptEnv
|
|
21728
|
+
});
|
|
21593
21729
|
if (result.status !== 0) {
|
|
21594
21730
|
if (script === "loki-ingest.sh") {
|
|
21595
|
-
printWarning(
|
|
21731
|
+
printWarning(
|
|
21732
|
+
"loki-ingest non-zero \u2014 likely Promtail scrub-wait flake; continuing"
|
|
21733
|
+
);
|
|
21596
21734
|
} else {
|
|
21597
21735
|
printError(`${script} failed \u2014 observability stack not ready`);
|
|
21598
21736
|
process.exit(1);
|
|
@@ -21603,7 +21741,9 @@ function installObservability(opts) {
|
|
|
21603
21741
|
}
|
|
21604
21742
|
}
|
|
21605
21743
|
function applyPeripheralServicesManifests() {
|
|
21606
|
-
step(
|
|
21744
|
+
step(
|
|
21745
|
+
"5/6 \u2014 peripheral-services manifests (IngressRoutes + ServiceMonitors + recording rules + dashboards + Kyverno)"
|
|
21746
|
+
);
|
|
21607
21747
|
const dir = resolvePeripheralServicesDir();
|
|
21608
21748
|
if (!dir) {
|
|
21609
21749
|
printWarning("bundled peripheral-services manifests not found \u2014 skipping");
|
|
@@ -21611,21 +21751,38 @@ function applyPeripheralServicesManifests() {
|
|
|
21611
21751
|
}
|
|
21612
21752
|
const manifestsDir = join34(dir, "manifests");
|
|
21613
21753
|
if (!existsSync29(manifestsDir)) {
|
|
21614
|
-
printWarning(
|
|
21754
|
+
printWarning(
|
|
21755
|
+
`peripheral-services/manifests not found at ${manifestsDir} \u2014 skipping`
|
|
21756
|
+
);
|
|
21615
21757
|
return;
|
|
21616
21758
|
}
|
|
21617
|
-
|
|
21618
|
-
|
|
21619
|
-
|
|
21620
|
-
|
|
21621
|
-
|
|
21759
|
+
const manifestFiles = readdirSync9(manifestsDir).filter(
|
|
21760
|
+
(f) => (f.endsWith(".yaml") || f.endsWith(".yml")) && !/deploy/i.test(f)
|
|
21761
|
+
).map((f) => join34(manifestsDir, f));
|
|
21762
|
+
if (manifestFiles.length === 0) {
|
|
21763
|
+
printWarning(
|
|
21764
|
+
"no non-deployment peripheral-services manifests found \u2014 skipping"
|
|
21765
|
+
);
|
|
21766
|
+
return;
|
|
21767
|
+
}
|
|
21768
|
+
for (const manifest of manifestFiles) {
|
|
21769
|
+
printInfo("apply", manifest.replace(manifestsDir + "/", ""));
|
|
21770
|
+
const r = spawnSync10("kubectl", ["apply", "-f", manifest], {
|
|
21771
|
+
stdio: "inherit"
|
|
21772
|
+
});
|
|
21773
|
+
if (r.status !== 0) {
|
|
21774
|
+
printError(`kubectl apply failed for ${manifest}`);
|
|
21775
|
+
process.exit(r.status ?? 1);
|
|
21776
|
+
}
|
|
21622
21777
|
}
|
|
21623
21778
|
printSuccess("peripheral-services manifests applied");
|
|
21624
21779
|
}
|
|
21625
21780
|
function delegateToUpgrade() {
|
|
21626
21781
|
step("6/6 \u2014 apply host-cp + peripherals + rollout (olam upgrade)");
|
|
21627
21782
|
const olamBin = process.argv[1] ?? "olam";
|
|
21628
|
-
const result = spawnSync10(process.execPath, [olamBin, "upgrade", "-y"], {
|
|
21783
|
+
const result = spawnSync10(process.execPath, [olamBin, "upgrade", "-y"], {
|
|
21784
|
+
stdio: "inherit"
|
|
21785
|
+
});
|
|
21629
21786
|
if (result.status !== 0) {
|
|
21630
21787
|
printError("olam upgrade failed \u2014 see output above");
|
|
21631
21788
|
process.exit(result.status ?? 1);
|
|
@@ -21657,7 +21814,10 @@ async function runBootstrapKubernetes(rawOpts) {
|
|
|
21657
21814
|
skipClusterCreate: rawOpts.skipClusterCreate ?? false
|
|
21658
21815
|
};
|
|
21659
21816
|
printHeader("olam setup \u2014 k3s mode");
|
|
21660
|
-
printInfo(
|
|
21817
|
+
printInfo(
|
|
21818
|
+
"mode",
|
|
21819
|
+
"one-command bring-up of olam peripherals + observability on a local k3d cluster"
|
|
21820
|
+
);
|
|
21661
21821
|
preflight(opts);
|
|
21662
21822
|
ensureSecrets();
|
|
21663
21823
|
ensureColima();
|
|
@@ -21750,6 +21910,9 @@ async function runBootstrap2(opts, deps = {}) {
|
|
|
21750
21910
|
if (digests["kg-service"] && !opts.skipKgService) {
|
|
21751
21911
|
imageRefs.push({ name: "kg-service", ref: `${registry}/olam-kg-service@${digests["kg-service"]}` });
|
|
21752
21912
|
}
|
|
21913
|
+
if (digests["memory-service"] && !opts.skipMemory) {
|
|
21914
|
+
imageRefs.push({ name: "memory-service", ref: `${registry}/olam-memory-service@${digests["memory-service"]}` });
|
|
21915
|
+
}
|
|
21753
21916
|
if (digests["devbox-base"]) {
|
|
21754
21917
|
imageRefs.push({
|
|
21755
21918
|
name: "devbox-base",
|
|
@@ -21827,6 +21990,10 @@ async function runBootstrap2(opts, deps = {}) {
|
|
|
21827
21990
|
if (kgServiceRef) {
|
|
21828
21991
|
tagPlan.push({ name: "kg-service", from: kgServiceRef.ref, to: "olam-kg-service:local" });
|
|
21829
21992
|
}
|
|
21993
|
+
const memoryServiceRef = imageRefs.find((r) => r.name === "memory-service");
|
|
21994
|
+
if (memoryServiceRef) {
|
|
21995
|
+
tagPlan.push({ name: "memory-service", from: memoryServiceRef.ref, to: "olam-memory-service:local" });
|
|
21996
|
+
}
|
|
21830
21997
|
const devboxBaseRef = imageRefs.find((r) => r.name === "devbox-base");
|
|
21831
21998
|
if (devboxBaseRef) {
|
|
21832
21999
|
tagPlan.push({ name: "devbox-base (bare)", from: devboxBaseRef.ref, to: "olam-devbox:base" });
|
|
@@ -22617,6 +22784,7 @@ function writeCloudMemorySecret(value, path94 = CLOUD_MEMORY_SECRET_PATH) {
|
|
|
22617
22784
|
}
|
|
22618
22785
|
|
|
22619
22786
|
// src/commands/memory-service-container.ts
|
|
22787
|
+
init_output();
|
|
22620
22788
|
var MEMORY_SERVICE_PORT = 3111;
|
|
22621
22789
|
var MEMORY_SERVICE_CONTAINER = "olam-memory-service";
|
|
22622
22790
|
var MEMORY_SERVICE_LOCAL_TAG = "olam-memory-service:local";
|
|
@@ -22651,13 +22819,27 @@ var MemoryServiceContainerController = class {
|
|
|
22651
22819
|
}
|
|
22652
22820
|
/**
|
|
22653
22821
|
* Resolve the first available image tag: local → dev → published.
|
|
22822
|
+
*
|
|
22823
|
+
* The preferred path is :local (populated by `olam bootstrap` pulling the
|
|
22824
|
+
* digest-pinned image and tagging it). The :published fallback is `:latest`
|
|
22825
|
+
* which is NOT digest-pinned — Docker will pull whatever tag-head is on
|
|
22826
|
+
* the registry at pull time. This is the degraded-mode path for operators
|
|
22827
|
+
* whose image-digests.json predates the G1 memory-service digest fix; it
|
|
22828
|
+
* is intentionally loud so they know they are not on the pinned path.
|
|
22829
|
+
*
|
|
22654
22830
|
* Throws if none exist (operator should run `olam bootstrap` to pull, or
|
|
22655
22831
|
* `node packages/cli/scripts/build-memory-service-image.mjs` to build locally).
|
|
22656
22832
|
*/
|
|
22657
22833
|
resolveImage() {
|
|
22658
|
-
for (const tag of [MEMORY_SERVICE_LOCAL_TAG, MEMORY_SERVICE_DEV_TAG
|
|
22834
|
+
for (const tag of [MEMORY_SERVICE_LOCAL_TAG, MEMORY_SERVICE_DEV_TAG]) {
|
|
22659
22835
|
if (this.imageExists(tag)) return tag;
|
|
22660
22836
|
}
|
|
22837
|
+
if (this.imageExists(MEMORY_SERVICE_PUBLISHED_TAG)) {
|
|
22838
|
+
printWarning(
|
|
22839
|
+
`memory-service: using tag-pulled fallback image (${MEMORY_SERVICE_PUBLISHED_TAG}). This image was NOT pulled by digest. Run \`olam bootstrap\` to pull the digest-pinned image and eliminate this warning.`
|
|
22840
|
+
);
|
|
22841
|
+
return MEMORY_SERVICE_PUBLISHED_TAG;
|
|
22842
|
+
}
|
|
22661
22843
|
throw new Error(
|
|
22662
22844
|
`memory-service image not found. Tried: ${MEMORY_SERVICE_LOCAL_TAG}, ${MEMORY_SERVICE_DEV_TAG}, ${MEMORY_SERVICE_PUBLISHED_TAG}. Run \`olam bootstrap\` to pull the published image, or \`node packages/cli/scripts/build-memory-service-image.mjs\` to build locally.`
|
|
22663
22845
|
);
|
|
@@ -22773,7 +22955,7 @@ var PERIPHERALS = [
|
|
|
22773
22955
|
{
|
|
22774
22956
|
name: "auth-service",
|
|
22775
22957
|
port: 9999,
|
|
22776
|
-
|
|
22958
|
+
k8sResourceName: "olam-auth-service",
|
|
22777
22959
|
composeContainerName: "olam-auth-service",
|
|
22778
22960
|
configMapKeyInHostCp: "OLAM_AUTH_SERVICE_URL",
|
|
22779
22961
|
healthPath: "/health"
|
|
@@ -22781,7 +22963,7 @@ var PERIPHERALS = [
|
|
|
22781
22963
|
{
|
|
22782
22964
|
name: "mcp-auth-service",
|
|
22783
22965
|
port: 9998,
|
|
22784
|
-
|
|
22966
|
+
k8sResourceName: "olam-mcp-auth-service",
|
|
22785
22967
|
composeContainerName: "olam-mcp-auth-service",
|
|
22786
22968
|
configMapKeyInHostCp: "OLAM_MCP_AUTH_SERVICE_URL",
|
|
22787
22969
|
healthPath: "/health"
|
|
@@ -22789,7 +22971,7 @@ var PERIPHERALS = [
|
|
|
22789
22971
|
{
|
|
22790
22972
|
name: "kg-service",
|
|
22791
22973
|
port: 9997,
|
|
22792
|
-
|
|
22974
|
+
k8sResourceName: "olam-kg-service",
|
|
22793
22975
|
composeContainerName: "olam-kg-service",
|
|
22794
22976
|
configMapKeyInHostCp: "OLAM_KG_SERVICE_URL",
|
|
22795
22977
|
healthPath: "/health"
|
|
@@ -22797,7 +22979,7 @@ var PERIPHERALS = [
|
|
|
22797
22979
|
{
|
|
22798
22980
|
name: "memory-service",
|
|
22799
22981
|
port: 3111,
|
|
22800
|
-
|
|
22982
|
+
k8sResourceName: "olam-memory-service",
|
|
22801
22983
|
composeContainerName: "olam-memory-service",
|
|
22802
22984
|
configMapKeyInHostCp: "OLAM_MEMORY_SERVICE_URL",
|
|
22803
22985
|
healthPath: "/agentmemory/livez"
|
|
@@ -23455,7 +23637,7 @@ async function spawnPeripheralPortForward(peripheral, context, namespace, deps =
|
|
|
23455
23637
|
"port-forward",
|
|
23456
23638
|
"-n",
|
|
23457
23639
|
namespace,
|
|
23458
|
-
`service/${peripheral.
|
|
23640
|
+
`service/${peripheral.k8sResourceName}`,
|
|
23459
23641
|
`${peripheral.port}:${peripheral.port}`
|
|
23460
23642
|
],
|
|
23461
23643
|
{
|
|
@@ -23654,8 +23836,8 @@ function appendAuditEntry(entry, auditLogPath, writeFileSyncImpl) {
|
|
|
23654
23836
|
}
|
|
23655
23837
|
async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, peripheral) {
|
|
23656
23838
|
const auditLogPath = deps.auditLogPath ?? MANIFEST_REFRESH_AUDIT_LOG;
|
|
23657
|
-
const
|
|
23658
|
-
const
|
|
23839
|
+
const readdirSync33 = deps.readdirSync ?? fs31.readdirSync;
|
|
23840
|
+
const readFileSync93 = deps.readFileSync ?? fs31.readFileSync;
|
|
23659
23841
|
const writeFileSyncImpl = deps.writeFileSync ?? fs31.writeFileSync;
|
|
23660
23842
|
const existsSync112 = deps.existsSync ?? fs31.existsSync;
|
|
23661
23843
|
const now = deps.now ? deps.now() : /* @__PURE__ */ new Date();
|
|
@@ -23668,7 +23850,7 @@ async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, per
|
|
|
23668
23850
|
}
|
|
23669
23851
|
let files;
|
|
23670
23852
|
try {
|
|
23671
|
-
const entries =
|
|
23853
|
+
const entries = readdirSync33(targetDir, { withFileTypes: true });
|
|
23672
23854
|
files = entries.filter((e) => e.isFile() && (e.name.endsWith(".yaml") || e.name.endsWith(".json"))).map((e) => e.name);
|
|
23673
23855
|
} catch (err) {
|
|
23674
23856
|
return {
|
|
@@ -23681,7 +23863,7 @@ async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, per
|
|
|
23681
23863
|
const filePath = path32.join(targetDir, file);
|
|
23682
23864
|
let content;
|
|
23683
23865
|
try {
|
|
23684
|
-
content =
|
|
23866
|
+
content = readFileSync93(filePath, "utf8");
|
|
23685
23867
|
} catch {
|
|
23686
23868
|
continue;
|
|
23687
23869
|
}
|
|
@@ -23831,9 +24013,8 @@ var PERIPHERAL_SECRETS = [
|
|
|
23831
24013
|
{ name: "memory-service", secretName: "olam-memory-service-secret", keys: ["OLAM_MEMORY_BEARER_SECRET"] }
|
|
23832
24014
|
];
|
|
23833
24015
|
var K8S_DNS_SUFFIX = "olam.svc.cluster.local";
|
|
23834
|
-
function buildK8sDnsUrl(
|
|
23835
|
-
|
|
23836
|
-
return `http://${prefixed}.${K8S_DNS_SUFFIX}:${port2}`;
|
|
24016
|
+
function buildK8sDnsUrl(k8sResourceName, port2) {
|
|
24017
|
+
return `http://${k8sResourceName}.${K8S_DNS_SUFFIX}:${port2}`;
|
|
23837
24018
|
}
|
|
23838
24019
|
function appendSubstrateAuditEntry(entry, stderr) {
|
|
23839
24020
|
try {
|
|
@@ -23933,11 +24114,11 @@ async function checkSecretPreCondition(context, deps) {
|
|
|
23933
24114
|
}
|
|
23934
24115
|
async function applyConfigMapSubstitution(context, manifestsDir, deps) {
|
|
23935
24116
|
const wrap = deps.kubectlWrapImpl ?? kubectlWrap;
|
|
23936
|
-
const
|
|
24117
|
+
const readFileSync93 = deps.readFileSyncImpl ?? fs32.readFileSync;
|
|
23937
24118
|
const configMapPath = path33.join(manifestsDir, "30-configmap.yaml");
|
|
23938
24119
|
let rawYaml;
|
|
23939
24120
|
try {
|
|
23940
|
-
rawYaml =
|
|
24121
|
+
rawYaml = readFileSync93(configMapPath, "utf8");
|
|
23941
24122
|
} catch (err) {
|
|
23942
24123
|
return `Failed to read ConfigMap at ${configMapPath}: ${err instanceof Error ? err.message : String(err)}`;
|
|
23943
24124
|
}
|
|
@@ -23949,7 +24130,7 @@ async function applyConfigMapSubstitution(context, manifestsDir, deps) {
|
|
|
23949
24130
|
}
|
|
23950
24131
|
const data = parsed["data"] ?? {};
|
|
23951
24132
|
for (const peripheral of PERIPHERALS) {
|
|
23952
|
-
data[peripheral.configMapKeyInHostCp] = buildK8sDnsUrl(peripheral.
|
|
24133
|
+
data[peripheral.configMapKeyInHostCp] = buildK8sDnsUrl(peripheral.k8sResourceName, peripheral.port);
|
|
23953
24134
|
}
|
|
23954
24135
|
parsed["data"] = data;
|
|
23955
24136
|
const patchedYaml = yamlStringify(parsed);
|
|
@@ -24302,10 +24483,10 @@ async function runUpgradeKubernetes(opts = {}, deps = {}) {
|
|
|
24302
24483
|
return { exitCode: 1, summary: "configmap substitution failed" };
|
|
24303
24484
|
}
|
|
24304
24485
|
step35Spinner.succeed("ConfigMap patched with K8s DNS URLs (survives bulk apply)");
|
|
24305
|
-
const step4Spinner = ora3("Waiting for rollout (all 5 deployments,
|
|
24486
|
+
const step4Spinner = ora3("Waiting for rollout (all 5 deployments, 300s each)").start();
|
|
24306
24487
|
const deploymentNames = [
|
|
24307
24488
|
HOST_CP_DEPLOYMENT_NAME,
|
|
24308
|
-
...PERIPHERALS.map((p) => p.
|
|
24489
|
+
...PERIPHERALS.map((p) => p.k8sResourceName)
|
|
24309
24490
|
];
|
|
24310
24491
|
const rolloutResults = await Promise.all(
|
|
24311
24492
|
deploymentNames.map(
|
|
@@ -24318,18 +24499,28 @@ async function runUpgradeKubernetes(opts = {}, deps = {}) {
|
|
|
24318
24499
|
`deployment/${deploymentName}`,
|
|
24319
24500
|
"-n",
|
|
24320
24501
|
K8S_NAMESPACE3,
|
|
24321
|
-
"--timeout=
|
|
24502
|
+
"--timeout=300s"
|
|
24322
24503
|
],
|
|
24323
|
-
{ timeout:
|
|
24504
|
+
{ timeout: 305e3 }
|
|
24324
24505
|
)
|
|
24325
24506
|
)
|
|
24326
24507
|
);
|
|
24327
24508
|
const failedDeployments = deploymentNames.filter((_, i) => !rolloutResults[i]?.ok);
|
|
24328
24509
|
if (failedDeployments.length > 0) {
|
|
24329
24510
|
step4Spinner.fail(`Rollout failed for: ${failedDeployments.join(", ")}`);
|
|
24330
|
-
for (const name of failedDeployments) {
|
|
24511
|
+
for (const [i, name] of failedDeployments.entries()) {
|
|
24512
|
+
const result = rolloutResults[deploymentNames.indexOf(name)];
|
|
24331
24513
|
stderr.write(`${pc10.red("error:")} rollout status failed for deployment/${name}.
|
|
24332
24514
|
`);
|
|
24515
|
+
if (result && (result.stdout || result.stderr)) {
|
|
24516
|
+
stderr.write(`${pc10.dim("--- kubectl rollout status output ---")}
|
|
24517
|
+
`);
|
|
24518
|
+
if (result.stdout) stderr.write(result.stdout + "\n");
|
|
24519
|
+
if (result.stderr) stderr.write(result.stderr + "\n");
|
|
24520
|
+
stderr.write(`${pc10.dim(`exit code: ${result.exitCode ?? "(none)"}, reason: ${"reason" in result ? result.reason : "ok"}`)}
|
|
24521
|
+
`);
|
|
24522
|
+
}
|
|
24523
|
+
void i;
|
|
24333
24524
|
stderr.write(`${pc10.dim(`--- kubectl get pods -n ${K8S_NAMESPACE3} -o wide ---`)}
|
|
24334
24525
|
`);
|
|
24335
24526
|
const podsResult = await wrap(
|
|
@@ -34550,7 +34741,7 @@ async function runPeripheralProbes(peripheral, startPosition, kubectlContext, wr
|
|
|
34550
34741
|
[
|
|
34551
34742
|
...ctxArgs,
|
|
34552
34743
|
"exec",
|
|
34553
|
-
`deploy/${peripheral.
|
|
34744
|
+
`deploy/${peripheral.k8sResourceName}`,
|
|
34554
34745
|
"-n",
|
|
34555
34746
|
K8S_NAMESPACE5,
|
|
34556
34747
|
"--",
|
|
@@ -34567,7 +34758,7 @@ async function runPeripheralProbes(peripheral, startPosition, kubectlContext, wr
|
|
|
34567
34758
|
return {
|
|
34568
34759
|
ok: false,
|
|
34569
34760
|
message: `${peripheral.name} pod not reachable`,
|
|
34570
|
-
remedy: `Check pod logs: kubectl logs deploy/${peripheral.
|
|
34761
|
+
remedy: `Check pod logs: kubectl logs deploy/${peripheral.k8sResourceName} -n ${K8S_NAMESPACE5}. stderr: ${errLine}`
|
|
34571
34762
|
};
|
|
34572
34763
|
})();
|
|
34573
34764
|
rows.push({ name: `${peripheral.name} reachable`, result: reachableResult, position: startPosition });
|
|
@@ -34612,7 +34803,7 @@ async function runPeripheralProbes(peripheral, startPosition, kubectlContext, wr
|
|
|
34612
34803
|
"-n",
|
|
34613
34804
|
K8S_NAMESPACE5,
|
|
34614
34805
|
"-l",
|
|
34615
|
-
`app=${peripheral.
|
|
34806
|
+
`app=${peripheral.k8sResourceName}`,
|
|
34616
34807
|
"-o",
|
|
34617
34808
|
`jsonpath={.items[0].status.containerStatuses[0].image}`
|
|
34618
34809
|
],
|
|
@@ -34626,7 +34817,7 @@ async function runPeripheralProbes(peripheral, startPosition, kubectlContext, wr
|
|
|
34626
34817
|
ok: true,
|
|
34627
34818
|
warn: true,
|
|
34628
34819
|
message: `${peripheral.name} image not detected`,
|
|
34629
|
-
remedy: `Verify pod is running: kubectl get pods -n ${K8S_NAMESPACE5} -l app=${peripheral.
|
|
34820
|
+
remedy: `Verify pod is running: kubectl get pods -n ${K8S_NAMESPACE5} -l app=${peripheral.k8sResourceName}`
|
|
34630
34821
|
};
|
|
34631
34822
|
})();
|
|
34632
34823
|
rows.push({ name: `${peripheral.name} image`, result: imagePresentResult, position: startPosition + 2 });
|
|
@@ -35314,10 +35505,10 @@ function parseTracker(path94) {
|
|
|
35314
35505
|
}
|
|
35315
35506
|
|
|
35316
35507
|
// ../cli-plugin-tasks/dist/commands/workers.js
|
|
35317
|
-
import { randomUUID as
|
|
35508
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
35318
35509
|
var SUBSTRATES = ["mac-mini", "cloudflare-container", "gcp-vm"];
|
|
35319
35510
|
function generateProvisionPlan(opts) {
|
|
35320
|
-
const workerId = opts.workerId ?? `worker-${
|
|
35511
|
+
const workerId = opts.workerId ?? `worker-${randomUUID3().slice(0, 8)}`;
|
|
35321
35512
|
const hostCpUrl = opts.hostCpUrl ?? "http://localhost:19000";
|
|
35322
35513
|
const nodeId = opts.olamNodeId ?? `<OLAM_NODE_ID>`;
|
|
35323
35514
|
const sessionId = opts.sessionId ?? `<OLAM_SESSION_ID>`;
|
|
@@ -35667,8 +35858,8 @@ function registerCompletion(program2) {
|
|
|
35667
35858
|
// src/commands/setup.ts
|
|
35668
35859
|
init_cli_version();
|
|
35669
35860
|
init_health_probes();
|
|
35670
|
-
import { spawn as spawn7 } from "node:child_process";
|
|
35671
|
-
import { existsSync as existsSync84 } from "node:fs";
|
|
35861
|
+
import { spawn as spawn7, spawnSync as spawnSync26 } from "node:child_process";
|
|
35862
|
+
import { existsSync as existsSync84, readFileSync as readFileSync68 } from "node:fs";
|
|
35672
35863
|
import { homedir as homedir43 } from "node:os";
|
|
35673
35864
|
import path75 from "node:path";
|
|
35674
35865
|
import { createInterface as createInterface3 } from "node:readline";
|
|
@@ -35996,10 +36187,17 @@ async function runProjectSweepPhase(opts, deps, sweepDeps = {}) {
|
|
|
35996
36187
|
|
|
35997
36188
|
// src/commands/setup.ts
|
|
35998
36189
|
var REQUIRED_NODE_MAJOR = 20;
|
|
35999
|
-
var
|
|
36000
|
-
|
|
36001
|
-
"docs/architecture/
|
|
36002
|
-
"docs/architecture/
|
|
36190
|
+
var SETUP_K3D_CLUSTER_NAME = "olam-dev";
|
|
36191
|
+
var NEXT_STEPS_DOCS_DOCKER = [
|
|
36192
|
+
"https://github.com/pleri/olam/blob/main/docs/architecture/devbox-contract.md \u2014 image contract",
|
|
36193
|
+
"https://github.com/pleri/olam/blob/main/docs/architecture/manifest-spec.md \u2014 per-repo .adb.yaml schema",
|
|
36194
|
+
"https://github.com/pleri/olam/blob/main/docs/architecture/config-spec.md \u2014 workspace .olam/config.yaml schema"
|
|
36195
|
+
];
|
|
36196
|
+
var NEXT_STEPS_DOCS_KUBERNETES = [
|
|
36197
|
+
"https://github.com/pleri/olam/blob/main/docs/architecture/devbox-contract.md \u2014 image contract",
|
|
36198
|
+
"https://github.com/pleri/olam/blob/main/docs/architecture/manifest-spec.md \u2014 per-repo .adb.yaml schema",
|
|
36199
|
+
"https://github.com/pleri/olam/blob/main/docs/architecture/config-spec.md \u2014 workspace .olam/config.yaml schema",
|
|
36200
|
+
"https://github.com/pleri/olam/blob/main/docs/k8s/SETUP.md \u2014 k3d operator guide"
|
|
36003
36201
|
];
|
|
36004
36202
|
var defaultSpawn = (cmd, args) => new Promise((resolve27) => {
|
|
36005
36203
|
const child = spawn7(cmd, [...args], { stdio: "inherit" });
|
|
@@ -36028,14 +36226,61 @@ var defaultPrompt = (question, defaultYes) => {
|
|
|
36028
36226
|
rl.on("close", () => resolve27(defaultYes));
|
|
36029
36227
|
});
|
|
36030
36228
|
};
|
|
36031
|
-
|
|
36229
|
+
var DOCKER_MIGRATION_HINT = "olam: detected existing docker stack \u2014 continuing on docker. To migrate to k3d, run: olam upgrade --substrate=kubernetes (available in a future release).";
|
|
36230
|
+
function resolveSubstrate(opts, deps) {
|
|
36231
|
+
if (opts.substrate === "kubernetes") return "kubernetes";
|
|
36232
|
+
if (opts.substrate === "docker") return "docker";
|
|
36233
|
+
const configPath = deps.configPath ?? OLAM_CONFIG_PATH;
|
|
36234
|
+
if (existsSync84(configPath)) {
|
|
36235
|
+
try {
|
|
36236
|
+
const raw = readFileSync68(configPath, "utf8");
|
|
36237
|
+
const parsed = JSON.parse(raw);
|
|
36238
|
+
const host = parsed.host;
|
|
36239
|
+
if (host?.substrate === "kubernetes") return "kubernetes";
|
|
36240
|
+
if (host?.substrate === "compose") {
|
|
36241
|
+
process.stderr.write(DOCKER_MIGRATION_HINT + "\n");
|
|
36242
|
+
return "docker";
|
|
36243
|
+
}
|
|
36244
|
+
} catch {
|
|
36245
|
+
}
|
|
36246
|
+
}
|
|
36247
|
+
return "kubernetes";
|
|
36248
|
+
}
|
|
36249
|
+
async function phase1SystemCheck(substrate, deps) {
|
|
36250
|
+
const nodeVersion = deps.nodeVersion ?? process.version;
|
|
36251
|
+
const nodeMajor = parseNodeMajor(nodeVersion);
|
|
36252
|
+
const nodeOk = nodeMajor !== null && nodeMajor >= REQUIRED_NODE_MAJOR;
|
|
36253
|
+
if (substrate === "kubernetes") {
|
|
36254
|
+
const kubectlProbe = await probeKubectl(deps.dockerExec);
|
|
36255
|
+
if (!kubectlProbe.ok) {
|
|
36256
|
+
return phaseFromProbe(kubectlProbe);
|
|
36257
|
+
}
|
|
36258
|
+
const dockerProbe2 = await probeDockerDaemon(deps.dockerExec);
|
|
36259
|
+
if (!dockerProbe2.ok) {
|
|
36260
|
+
return {
|
|
36261
|
+
ok: false,
|
|
36262
|
+
message: "docker daemon required for k3d: " + dockerProbe2.message,
|
|
36263
|
+
remedy: dockerProbe2.remedy
|
|
36264
|
+
};
|
|
36265
|
+
}
|
|
36266
|
+
if (!nodeOk) {
|
|
36267
|
+
return {
|
|
36268
|
+
ok: false,
|
|
36269
|
+
message: `Node.js ${nodeVersion} is too old (need \u2265${REQUIRED_NODE_MAJOR})`,
|
|
36270
|
+
remedy: `Install Node.js ${REQUIRED_NODE_MAJOR}+ LTS via nvm/fnm/asdf and re-run \`olam setup\`.`
|
|
36271
|
+
};
|
|
36272
|
+
}
|
|
36273
|
+
return { ok: true, message: `kubectl on PATH; docker ready; node ${nodeVersion}` };
|
|
36274
|
+
}
|
|
36032
36275
|
const dockerProbe = await probeDockerDaemon(deps.dockerExec);
|
|
36033
36276
|
if (!dockerProbe.ok) {
|
|
36034
36277
|
return phaseFromProbe(dockerProbe);
|
|
36035
36278
|
}
|
|
36036
|
-
const
|
|
36037
|
-
|
|
36038
|
-
|
|
36279
|
+
const composeProbe = await probeComposePlugin(deps.dockerExec);
|
|
36280
|
+
if (!composeProbe.ok) {
|
|
36281
|
+
return phaseFromProbe(composeProbe);
|
|
36282
|
+
}
|
|
36283
|
+
if (!nodeOk) {
|
|
36039
36284
|
return {
|
|
36040
36285
|
ok: false,
|
|
36041
36286
|
message: `Node.js ${nodeVersion} is too old (need \u2265${REQUIRED_NODE_MAJOR})`,
|
|
@@ -36044,9 +36289,68 @@ async function phase1SystemCheck(deps) {
|
|
|
36044
36289
|
}
|
|
36045
36290
|
return {
|
|
36046
36291
|
ok: true,
|
|
36047
|
-
message: `${dockerProbe.message}; node ${nodeVersion}`
|
|
36292
|
+
message: `${dockerProbe.message}; ${composeProbe.message}; node ${nodeVersion}`
|
|
36048
36293
|
};
|
|
36049
36294
|
}
|
|
36295
|
+
async function phase1_5InstallSubstrate(substrate, opts, deps) {
|
|
36296
|
+
if (substrate === "docker") {
|
|
36297
|
+
return { ok: true, skipped: true, message: "no-op for docker substrate" };
|
|
36298
|
+
}
|
|
36299
|
+
const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
|
|
36300
|
+
const promptFn = deps.prompt ?? defaultPrompt;
|
|
36301
|
+
const k3dProbe = await probeK3d(deps.dockerExec);
|
|
36302
|
+
if (k3dProbe.ok) {
|
|
36303
|
+
return { ok: true, message: `k3d already present: ${k3dProbe.message}` };
|
|
36304
|
+
}
|
|
36305
|
+
const hasBrew = spawnSync26("command", ["-v", "brew"], { shell: true, stdio: "pipe" }).status === 0;
|
|
36306
|
+
const useBrewMsg = hasBrew ? "Homebrew" : "upstream install script";
|
|
36307
|
+
if (!opts.yes) {
|
|
36308
|
+
const confirmed = await promptFn(
|
|
36309
|
+
`k3d is not installed. Install via ${useBrewMsg}?`,
|
|
36310
|
+
true
|
|
36311
|
+
);
|
|
36312
|
+
if (!confirmed) {
|
|
36313
|
+
return {
|
|
36314
|
+
ok: false,
|
|
36315
|
+
message: "k3d install declined; required for kubernetes substrate",
|
|
36316
|
+
remedy: "Install manually: `brew install k3d` or curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash, then re-run `olam setup --substrate=kubernetes`."
|
|
36317
|
+
};
|
|
36318
|
+
}
|
|
36319
|
+
}
|
|
36320
|
+
if (hasBrew) {
|
|
36321
|
+
process.stdout.write("Installing k3d via Homebrew...\n");
|
|
36322
|
+
const r = await spawnFn("brew", ["install", "k3d"]);
|
|
36323
|
+
if (r.status !== 0) {
|
|
36324
|
+
return {
|
|
36325
|
+
ok: false,
|
|
36326
|
+
message: `brew install k3d failed (exit ${r.status ?? "signal"})`,
|
|
36327
|
+
remedy: "Try manually: `brew install k3d` or curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash"
|
|
36328
|
+
};
|
|
36329
|
+
}
|
|
36330
|
+
} else {
|
|
36331
|
+
process.stdout.write("Installing k3d via upstream install script...\n");
|
|
36332
|
+
const r = await spawnFn("bash", [
|
|
36333
|
+
"-c",
|
|
36334
|
+
"curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh | bash"
|
|
36335
|
+
]);
|
|
36336
|
+
if (r.status !== 0) {
|
|
36337
|
+
return {
|
|
36338
|
+
ok: false,
|
|
36339
|
+
message: `k3d upstream install failed (exit ${r.status ?? "signal"})`,
|
|
36340
|
+
remedy: "Install manually: https://k3d.io/v5.x/installation/"
|
|
36341
|
+
};
|
|
36342
|
+
}
|
|
36343
|
+
}
|
|
36344
|
+
const k3dCheck = await probeK3d(deps.dockerExec);
|
|
36345
|
+
if (!k3dCheck.ok) {
|
|
36346
|
+
return {
|
|
36347
|
+
ok: false,
|
|
36348
|
+
message: "k3d still not on PATH after install \u2014 shell PATH may need updating",
|
|
36349
|
+
remedy: "Close and re-open your terminal, then re-run `olam setup --substrate=kubernetes`."
|
|
36350
|
+
};
|
|
36351
|
+
}
|
|
36352
|
+
return { ok: true, message: `k3d installed: ${k3dCheck.message}` };
|
|
36353
|
+
}
|
|
36050
36354
|
function parseNodeMajor(version) {
|
|
36051
36355
|
const m = version.match(/^v?(\d+)\./);
|
|
36052
36356
|
if (!m) return null;
|
|
@@ -36057,6 +36361,65 @@ function phaseFromProbe(probe2) {
|
|
|
36057
36361
|
if (probe2.ok) return { ok: true, message: probe2.message };
|
|
36058
36362
|
return { ok: false, message: probe2.message, remedy: probe2.remedy };
|
|
36059
36363
|
}
|
|
36364
|
+
async function phase2_5ProvisionCluster(substrate, opts, deps) {
|
|
36365
|
+
if (substrate === "docker") {
|
|
36366
|
+
return { ok: true, skipped: true, message: "no-op for docker substrate" };
|
|
36367
|
+
}
|
|
36368
|
+
const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
|
|
36369
|
+
const listResult = await captureSpawn("k3d", ["cluster", "list", "--output", "json"], deps.dockerExec);
|
|
36370
|
+
if (listResult.ok) {
|
|
36371
|
+
const exists = clusterExistsInList(listResult.stdout, SETUP_K3D_CLUSTER_NAME);
|
|
36372
|
+
if (exists) {
|
|
36373
|
+
return {
|
|
36374
|
+
ok: true,
|
|
36375
|
+
message: `cluster ${SETUP_K3D_CLUSTER_NAME} already exists; skipping create`
|
|
36376
|
+
};
|
|
36377
|
+
}
|
|
36378
|
+
}
|
|
36379
|
+
process.stdout.write(`Creating k3d cluster ${SETUP_K3D_CLUSTER_NAME}...
|
|
36380
|
+
`);
|
|
36381
|
+
const ghConfigBind = `${homedir43()}/.config/gh:/host/.config/gh`;
|
|
36382
|
+
const createResult = await spawnFn("k3d", [
|
|
36383
|
+
"cluster",
|
|
36384
|
+
"create",
|
|
36385
|
+
SETUP_K3D_CLUSTER_NAME,
|
|
36386
|
+
"--volume",
|
|
36387
|
+
ghConfigBind,
|
|
36388
|
+
"--wait",
|
|
36389
|
+
"--timeout",
|
|
36390
|
+
"90s"
|
|
36391
|
+
]);
|
|
36392
|
+
if (createResult.status !== 0) {
|
|
36393
|
+
return {
|
|
36394
|
+
ok: false,
|
|
36395
|
+
message: `k3d cluster create ${SETUP_K3D_CLUSTER_NAME} failed (exit ${createResult.status ?? "signal"})`,
|
|
36396
|
+
remedy: `Run manually: k3d cluster create ${SETUP_K3D_CLUSTER_NAME} --wait --timeout 90s`
|
|
36397
|
+
};
|
|
36398
|
+
}
|
|
36399
|
+
const ctxResult = captureSpawnSync("kubectl", ["config", "current-context"]);
|
|
36400
|
+
const ctx = ctxResult.ok ? ctxResult.stdout.trim() : "(unknown)";
|
|
36401
|
+
return { ok: true, message: `cluster ${SETUP_K3D_CLUSTER_NAME} created; context: ${ctx}` };
|
|
36402
|
+
}
|
|
36403
|
+
async function captureSpawn(cmd, args, dockerExec) {
|
|
36404
|
+
const exec = dockerExec ?? ((c, a) => {
|
|
36405
|
+
const r2 = spawnSync26(c, [...a], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
|
|
36406
|
+
return { status: r2.status, stdout: r2.stdout ?? "", stderr: r2.stderr ?? "" };
|
|
36407
|
+
});
|
|
36408
|
+
const r = exec(cmd, args);
|
|
36409
|
+
return { ok: r.status === 0, stdout: r.stdout, stderr: r.stderr };
|
|
36410
|
+
}
|
|
36411
|
+
function captureSpawnSync(cmd, args) {
|
|
36412
|
+
const r = spawnSync26(cmd, [...args], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] });
|
|
36413
|
+
return { ok: r.status === 0, stdout: r.stdout ?? "" };
|
|
36414
|
+
}
|
|
36415
|
+
function clusterExistsInList(json, clusterName) {
|
|
36416
|
+
try {
|
|
36417
|
+
const parsed = JSON.parse(json);
|
|
36418
|
+
return Array.isArray(parsed) && parsed.some((c) => c.name === clusterName);
|
|
36419
|
+
} catch {
|
|
36420
|
+
return false;
|
|
36421
|
+
}
|
|
36422
|
+
}
|
|
36060
36423
|
async function phase2CliSanity(deps) {
|
|
36061
36424
|
const version = deps.olamCliVersion ?? safeReadCliVersion();
|
|
36062
36425
|
if (!version || version === "unknown") {
|
|
@@ -36075,11 +36438,36 @@ function safeReadCliVersion() {
|
|
|
36075
36438
|
return null;
|
|
36076
36439
|
}
|
|
36077
36440
|
}
|
|
36078
|
-
async function
|
|
36441
|
+
async function phase2_6PinKubectlContext(substrate, deps) {
|
|
36442
|
+
if (substrate !== "kubernetes") {
|
|
36443
|
+
return { ok: true, skipped: true, message: "no-op for docker substrate" };
|
|
36444
|
+
}
|
|
36445
|
+
const expectedContext = `k3d-${SETUP_K3D_CLUSTER_NAME}`;
|
|
36446
|
+
writeConfig({ host: { substrate: "kubernetes" } }, { configPath: deps.configPath });
|
|
36447
|
+
const result = applyKubectlContextPin([expectedContext], {
|
|
36448
|
+
configPath: deps.configPath
|
|
36449
|
+
});
|
|
36450
|
+
if ("pinned" in result) {
|
|
36451
|
+
return { ok: true, message: `kubectl context pinned: ${result.pinned}` };
|
|
36452
|
+
}
|
|
36453
|
+
if ("skipped" in result) {
|
|
36454
|
+
return { ok: true, message: `kubectl context already pinned (${result.skipped})` };
|
|
36455
|
+
}
|
|
36456
|
+
return {
|
|
36457
|
+
ok: false,
|
|
36458
|
+
message: `kubectl context pin refused: ${result.refused}`,
|
|
36459
|
+
remedy: `Set host.kubectl_context_pinned = ${expectedContext} in ~/.olam/config.json and re-run.`
|
|
36460
|
+
};
|
|
36461
|
+
}
|
|
36462
|
+
async function phase3Bootstrap(substrate, deps) {
|
|
36079
36463
|
const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
|
|
36080
|
-
const
|
|
36464
|
+
const bootstrapArgs = ["bootstrap", "--skip-auth-login"];
|
|
36465
|
+
if (substrate === "kubernetes") {
|
|
36466
|
+
bootstrapArgs.push("--skip-cluster-create");
|
|
36467
|
+
}
|
|
36468
|
+
const r = await spawnFn("olam", bootstrapArgs);
|
|
36081
36469
|
if (r.status === 0) {
|
|
36082
|
-
return { ok: true, message:
|
|
36470
|
+
return { ok: true, message: `olam bootstrap succeeded (substrate: ${substrate})` };
|
|
36083
36471
|
}
|
|
36084
36472
|
return {
|
|
36085
36473
|
ok: false,
|
|
@@ -36191,7 +36579,10 @@ async function phase6Auth(opts, deps) {
|
|
|
36191
36579
|
message: `olam auth login exited ${r.status}; re-run \`olam auth login\` after resolving`
|
|
36192
36580
|
};
|
|
36193
36581
|
}
|
|
36194
|
-
async function phase7Verify(deps) {
|
|
36582
|
+
async function phase7Verify(opts, deps) {
|
|
36583
|
+
if (opts.skipDoctor) {
|
|
36584
|
+
return { ok: true, skipped: true, message: "skipped via --skip-doctor" };
|
|
36585
|
+
}
|
|
36195
36586
|
const spawnFn = deps.spawnSubprocess ?? defaultSpawn;
|
|
36196
36587
|
const r = await spawnFn("olam", ["doctor"]);
|
|
36197
36588
|
if (r.status === 0) {
|
|
@@ -36203,9 +36594,12 @@ async function phase7Verify(deps) {
|
|
|
36203
36594
|
remedy: "Inspect doctor output above; the specific failing probe names its remedy."
|
|
36204
36595
|
};
|
|
36205
36596
|
}
|
|
36206
|
-
var
|
|
36597
|
+
var PHASE_TITLES_DOCKER = [
|
|
36207
36598
|
"Phase 1: System check",
|
|
36599
|
+
"Phase 1.5: Substrate tools install",
|
|
36208
36600
|
"Phase 2: olam CLI sanity",
|
|
36601
|
+
"Phase 2.5: Cluster provision",
|
|
36602
|
+
"Phase 2.6: Pin kubectl context",
|
|
36209
36603
|
"Phase 3: Bootstrap",
|
|
36210
36604
|
"Phase 4: Shell init",
|
|
36211
36605
|
"Phase 5: Init project",
|
|
@@ -36215,22 +36609,29 @@ var PHASE_TITLES = [
|
|
|
36215
36609
|
"Phase 7: Final verification"
|
|
36216
36610
|
];
|
|
36217
36611
|
async function runSetup(opts, deps = {}) {
|
|
36218
|
-
|
|
36612
|
+
const substrate = resolveSubstrate(opts, deps);
|
|
36613
|
+
const bannerSubstrate = substrate === "kubernetes" ? "Kubernetes (k3d)" : "Docker Compose";
|
|
36614
|
+
printHeader(`olam setup \u2014 Olam local stack on ${bannerSubstrate}`);
|
|
36615
|
+
process.stdout.write(`substrate: ${substrate}
|
|
36616
|
+
`);
|
|
36219
36617
|
const phaseFns = [
|
|
36220
|
-
() => phase1SystemCheck(deps),
|
|
36618
|
+
() => phase1SystemCheck(substrate, deps),
|
|
36619
|
+
() => phase1_5InstallSubstrate(substrate, opts, deps),
|
|
36221
36620
|
() => phase2CliSanity(deps),
|
|
36222
|
-
() =>
|
|
36621
|
+
() => phase2_5ProvisionCluster(substrate, opts, deps),
|
|
36622
|
+
() => phase2_6PinKubectlContext(substrate, deps),
|
|
36623
|
+
() => phase3Bootstrap(substrate, deps),
|
|
36223
36624
|
() => phase4ShellInit(opts, deps),
|
|
36224
36625
|
() => phase5InitProject(opts, deps),
|
|
36225
36626
|
() => phase5aSkillSource(opts, deps),
|
|
36226
36627
|
() => phase5bProjectSweep(opts, deps),
|
|
36227
36628
|
() => phase6Auth(opts, deps),
|
|
36228
|
-
() => phase7Verify(deps)
|
|
36629
|
+
() => phase7Verify(opts, deps)
|
|
36229
36630
|
];
|
|
36230
36631
|
const results = [];
|
|
36231
36632
|
let failureAt = null;
|
|
36232
36633
|
for (let i = 0; i < phaseFns.length; i += 1) {
|
|
36233
|
-
const name =
|
|
36634
|
+
const name = PHASE_TITLES_DOCKER[i];
|
|
36234
36635
|
process.stdout.write(`
|
|
36235
36636
|
${name}
|
|
36236
36637
|
`);
|
|
@@ -36254,7 +36655,8 @@ ${name}
|
|
|
36254
36655
|
}
|
|
36255
36656
|
printSuccess("Setup complete.");
|
|
36256
36657
|
process.stdout.write("\nNext steps \u2014 read these in order for the 3-contract pattern:\n");
|
|
36257
|
-
|
|
36658
|
+
const nextStepsDocs = substrate === "kubernetes" ? NEXT_STEPS_DOCS_KUBERNETES : NEXT_STEPS_DOCS_DOCKER;
|
|
36659
|
+
for (const line of nextStepsDocs) {
|
|
36258
36660
|
printInfo("docs", line);
|
|
36259
36661
|
}
|
|
36260
36662
|
process.stdout.write("\n");
|
|
@@ -36262,9 +36664,31 @@ ${name}
|
|
|
36262
36664
|
}
|
|
36263
36665
|
function registerSetup(program2) {
|
|
36264
36666
|
program2.command("setup").description(
|
|
36265
|
-
"Fresh-host onboarding wizard.
|
|
36266
|
-
).option(
|
|
36267
|
-
|
|
36667
|
+
"Fresh-host onboarding wizard. Default substrate=kubernetes (k3d on all platforms): installs k3d (no sudo needed \u2014 only requires docker), provisions the olam-dev cluster, then runs bootstrap end-to-end. Existing docker/compose installs are protected \u2014 they continue on docker with a migration hint. Idempotent; safe to re-run."
|
|
36668
|
+
).option(
|
|
36669
|
+
"--substrate <substrate>",
|
|
36670
|
+
"Target substrate: kubernetes (default, alias: k3s) or docker. Auto-detected from ~/.olam/config.json when not specified."
|
|
36671
|
+
).option("--skip-shell-init", "Skip Phase 4 (do not append to ~/.zshrc / ~/.bashrc)").option("--skip-auth", "Skip Phase 6 (do not prompt for `olam auth login`)").option("--skip-skill-source", "Skip Phase 5a (do not pick a skill source; run `olam skills source add` later)").option("--skill-source <id-or-url>", "Non-interactive Phase 5a: curated name (e.g. atlas-toolbox) or git URL").option("--skip-project-sweep", "Skip Phase 5b (do not walk projects directory for repo discovery)").option("--projects <path>", "Phase 5b: project root path to walk (default: ~/Projects)").option("--dry-run", "Phase 5b: print matches without registering or building (no side effects)").option("--exclude <glob...>", "Phase 5b: additional skip patterns for project sweep").option("--skip-kg", "Phase 5b: skip KG eager-build sub-step (sources still registered)").option(
|
|
36672
|
+
"--skip-doctor",
|
|
36673
|
+
"Skip Phase 7 final `olam doctor` verification (for CI or minimal setups)"
|
|
36674
|
+
).option("-y, --yes", "Auto-affirm every prompt (non-interactive)").action(async (rawOpts) => {
|
|
36675
|
+
let substrate;
|
|
36676
|
+
const rawSubstrate = rawOpts.substrate;
|
|
36677
|
+
if (rawSubstrate === "k3s" || rawSubstrate === "kubernetes") {
|
|
36678
|
+
substrate = "kubernetes";
|
|
36679
|
+
} else if (rawSubstrate === "docker") {
|
|
36680
|
+
substrate = "docker";
|
|
36681
|
+
} else if (rawSubstrate !== void 0) {
|
|
36682
|
+
process.stderr.write(
|
|
36683
|
+
`[olam setup] Unknown --substrate value '${rawSubstrate}'. Valid values: docker, kubernetes (alias: k3s).
|
|
36684
|
+
`
|
|
36685
|
+
);
|
|
36686
|
+
process.exitCode = 1;
|
|
36687
|
+
return;
|
|
36688
|
+
}
|
|
36689
|
+
const { substrate: _drop, ...restOpts } = rawOpts;
|
|
36690
|
+
void _drop;
|
|
36691
|
+
const report = await runSetup({ ...restOpts, substrate });
|
|
36268
36692
|
if (report.exitCode !== 0) process.exitCode = report.exitCode;
|
|
36269
36693
|
});
|
|
36270
36694
|
}
|
|
@@ -37036,7 +37460,7 @@ import * as readline2 from "node:readline";
|
|
|
37036
37460
|
import pc32 from "picocolors";
|
|
37037
37461
|
|
|
37038
37462
|
// src/commands/flywheel/install-shims.ts
|
|
37039
|
-
import { copyFileSync as copyFileSync9, existsSync as existsSync88, mkdirSync as mkdirSync53, readFileSync as
|
|
37463
|
+
import { copyFileSync as copyFileSync9, existsSync as existsSync88, mkdirSync as mkdirSync53, readFileSync as readFileSync72, writeFileSync as writeFileSync44 } from "node:fs";
|
|
37040
37464
|
import { homedir as homedir46 } from "node:os";
|
|
37041
37465
|
import { dirname as dirname48, join as join85 } from "node:path";
|
|
37042
37466
|
|
|
@@ -37140,7 +37564,7 @@ function installOne(spec, targetDir, opts) {
|
|
|
37140
37564
|
}
|
|
37141
37565
|
return { basename: spec.basename, action: "written", targetPath };
|
|
37142
37566
|
}
|
|
37143
|
-
const existing =
|
|
37567
|
+
const existing = readFileSync72(targetPath, "utf8");
|
|
37144
37568
|
if (existing === newContent) {
|
|
37145
37569
|
return { basename: spec.basename, action: "unchanged", targetPath };
|
|
37146
37570
|
}
|
|
@@ -37252,6 +37676,15 @@ ${pc32.bold("Sync now?")} ${pc32.dim("[Y/n] ")}`);
|
|
|
37252
37676
|
});
|
|
37253
37677
|
});
|
|
37254
37678
|
}
|
|
37679
|
+
function parsePrefixScope(raw) {
|
|
37680
|
+
const tokens = raw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
37681
|
+
if (tokens.length === 0) return [];
|
|
37682
|
+
const valid = /* @__PURE__ */ new Set(["skill", "agent"]);
|
|
37683
|
+
for (const t of tokens) {
|
|
37684
|
+
if (!valid.has(t)) return null;
|
|
37685
|
+
}
|
|
37686
|
+
return [...new Set(tokens)];
|
|
37687
|
+
}
|
|
37255
37688
|
function registerSkillsSource(program2) {
|
|
37256
37689
|
const skills = program2.command("skills").description("Manage skill sources and synchronization");
|
|
37257
37690
|
const source = skills.command("source").description("Manage registered skill sources");
|
|
@@ -37264,20 +37697,29 @@ function registerSkillsSource(program2) {
|
|
|
37264
37697
|
return;
|
|
37265
37698
|
}
|
|
37266
37699
|
printHeader(`${all.length} skill source(s)`);
|
|
37700
|
+
const DEFAULT_SCOPE_REPR = "skill,agent";
|
|
37701
|
+
const showScopeCol = all.some(
|
|
37702
|
+
(s) => s.prefixScope !== void 0 && s.prefixScope.slice().sort().join(",") !== "agent,skill"
|
|
37703
|
+
);
|
|
37267
37704
|
for (let i = 0; i < all.length; i += 1) {
|
|
37268
37705
|
const s = all[i];
|
|
37269
37706
|
const when = new Date(s.addedAt).toISOString().slice(0, 10);
|
|
37270
37707
|
const sha = s.lastPulledSha ? s.lastPulledSha.slice(0, 8) : pc32.dim("(unpulled)");
|
|
37271
37708
|
const ord = pc32.dim(`[${i + 1}]`);
|
|
37272
37709
|
const prefixCol = s.prefix ? pc32.cyan(s.prefix.padEnd(12)) : pc32.dim("\u2014".padEnd(12));
|
|
37710
|
+
const scopeDisplay = s.prefixScope !== void 0 ? s.prefixScope.join(",") : DEFAULT_SCOPE_REPR;
|
|
37711
|
+
const scopeCol = showScopeCol ? ` ${pc32.yellow(scopeDisplay.padEnd(12))}` : "";
|
|
37273
37712
|
console.log(
|
|
37274
|
-
` ${ord} ${pc32.bold(s.id.padEnd(14))} ${s.name.padEnd(24)} ${s.branch.padEnd(12)} ${sha.padEnd(12)} ${prefixCol} ${pc32.dim(when)} ${pc32.dim(s.gitUrl)}`
|
|
37713
|
+
` ${ord} ${pc32.bold(s.id.padEnd(14))} ${s.name.padEnd(24)} ${s.branch.padEnd(12)} ${sha.padEnd(12)} ${prefixCol}${scopeCol} ${pc32.dim(when)} ${pc32.dim(s.gitUrl)}`
|
|
37275
37714
|
);
|
|
37276
37715
|
}
|
|
37277
37716
|
});
|
|
37278
37717
|
source.command("add").description("Register and clone a skill source (T6 capability-class: requires --trust OR interactive ack)").requiredOption("--name <name>", "Display name (lowercase, digits, dash)").requiredOption("--git-url <url>", "git URL (https://, git@, ssh://, file://, or absolute path)").option("--branch <branch>", "Branch to track", "main").option(
|
|
37279
37718
|
"--prefix <prefix>",
|
|
37280
37719
|
'Deploy prefix: skills+agents from this source deploy as <prefix>:<canonical-name> (e.g. "atl", "pln"). Must match /^[a-z0-9][a-z0-9_-]{0,38}$/'
|
|
37720
|
+
).option(
|
|
37721
|
+
"--prefix-scope <scope>",
|
|
37722
|
+
'Comma-separated list of artifact kinds to rename when prefix is set. Valid values: skill, agent. Default: skill,agent. E.g. "--prefix-scope=skill" to rename only skills.'
|
|
37281
37723
|
).option("--trust", "Acknowledge that registering grants symlink-into-~/.claude permission (skips interactive picker)").option("--sync-now", "Run `olam skills sync` immediately after add (skips interactive prompt)").option("--no-sync-now", "Skip the post-add sync (skips interactive prompt)").option("--install-hook", "Install the SessionStart hook after add (skips interactive prompt)").option("--no-install-hook", "Skip installing the SessionStart hook (skips interactive prompt)").option(
|
|
37282
37724
|
"--hook-scope <scope>",
|
|
37283
37725
|
"When installing the hook (post-add): project (<cwd>/.claude) or user (~/.claude)",
|
|
@@ -37291,6 +37733,18 @@ function registerSkillsSource(program2) {
|
|
|
37291
37733
|
process.exitCode = 1;
|
|
37292
37734
|
return;
|
|
37293
37735
|
}
|
|
37736
|
+
let parsedPrefixScope;
|
|
37737
|
+
if (opts.prefixScope !== void 0) {
|
|
37738
|
+
const parsed = parsePrefixScope(opts.prefixScope);
|
|
37739
|
+
if (parsed === null) {
|
|
37740
|
+
printError(
|
|
37741
|
+
`--prefix-scope must be a comma-separated list of "skill" and/or "agent" \u2014 got "${opts.prefixScope}"`
|
|
37742
|
+
);
|
|
37743
|
+
process.exitCode = 1;
|
|
37744
|
+
return;
|
|
37745
|
+
}
|
|
37746
|
+
parsedPrefixScope = parsed;
|
|
37747
|
+
}
|
|
37294
37748
|
const isTTY = Boolean(process.stdout.isTTY);
|
|
37295
37749
|
const testPromptFn = globalThis.__olamTestTrustPrompt;
|
|
37296
37750
|
let decision;
|
|
@@ -37328,8 +37782,11 @@ function registerSkillsSource(program2) {
|
|
|
37328
37782
|
branch: opts.branch,
|
|
37329
37783
|
trustMethod: decision.method
|
|
37330
37784
|
});
|
|
37331
|
-
if (opts.prefix !== void 0) {
|
|
37332
|
-
updateSkillSource(entry.id, {
|
|
37785
|
+
if (opts.prefix !== void 0 || parsedPrefixScope !== void 0) {
|
|
37786
|
+
updateSkillSource(entry.id, {
|
|
37787
|
+
...opts.prefix !== void 0 ? { prefix: opts.prefix } : {},
|
|
37788
|
+
...parsedPrefixScope !== void 0 ? { prefixScope: parsedPrefixScope } : {}
|
|
37789
|
+
});
|
|
37333
37790
|
}
|
|
37334
37791
|
} catch (err) {
|
|
37335
37792
|
try {
|
|
@@ -37576,6 +38033,53 @@ function registerSkillsSource(program2) {
|
|
|
37576
38033
|
process.exitCode = 1;
|
|
37577
38034
|
}
|
|
37578
38035
|
});
|
|
38036
|
+
source.command("set-prefix-scope").description(
|
|
38037
|
+
"Set which artifact kinds are renamed by the prefix (comma-separated: skill, agent, or skill,agent)"
|
|
38038
|
+
).argument("<name>", 'Display name of the skill source (from "olam skills source list")').argument("<scope>", 'Comma-separated artifact kinds: "skill", "agent", or "skill,agent". Empty string = no renaming.').action((name, scopeRaw) => {
|
|
38039
|
+
const entry = getSkillSourceByName(name);
|
|
38040
|
+
if (entry === null) {
|
|
38041
|
+
printError(
|
|
38042
|
+
`skill source "${name}" is not registered. Run "olam skills source list" to see registered sources.`
|
|
38043
|
+
);
|
|
38044
|
+
process.exitCode = 1;
|
|
38045
|
+
return;
|
|
38046
|
+
}
|
|
38047
|
+
const parsed = parsePrefixScope(scopeRaw);
|
|
38048
|
+
if (parsed === null) {
|
|
38049
|
+
printError(
|
|
38050
|
+
`scope must be a comma-separated list of "skill" and/or "agent" \u2014 got "${scopeRaw}"`
|
|
38051
|
+
);
|
|
38052
|
+
process.exitCode = 1;
|
|
38053
|
+
return;
|
|
38054
|
+
}
|
|
38055
|
+
try {
|
|
38056
|
+
updateSkillSource(entry.id, { prefixScope: parsed });
|
|
38057
|
+
const display = parsed.length === 0 ? "(none \u2014 prefix disabled)" : parsed.join(",");
|
|
38058
|
+
printSuccess(`set prefix-scope "${display}" on source "${name}" (${entry.id})`);
|
|
38059
|
+
} catch (err) {
|
|
38060
|
+
printError(asMessage3(err));
|
|
38061
|
+
process.exitCode = 1;
|
|
38062
|
+
}
|
|
38063
|
+
});
|
|
38064
|
+
source.command("unset-prefix-scope").description(
|
|
38065
|
+
"Remove the prefix-scope override from a registered skill source (reverts to default: both skill and agent are renamed)"
|
|
38066
|
+
).argument("<name>", 'Display name of the skill source (from "olam skills source list")').action((name) => {
|
|
38067
|
+
const entry = getSkillSourceByName(name);
|
|
38068
|
+
if (entry === null) {
|
|
38069
|
+
printError(
|
|
38070
|
+
`skill source "${name}" is not registered. Run "olam skills source list" to see registered sources.`
|
|
38071
|
+
);
|
|
38072
|
+
process.exitCode = 1;
|
|
38073
|
+
return;
|
|
38074
|
+
}
|
|
38075
|
+
try {
|
|
38076
|
+
updateSkillSource(entry.id, { prefixScope: null });
|
|
38077
|
+
printSuccess(`unset prefix-scope on source "${name}" (${entry.id}) \u2014 reverted to default (skill,agent)`);
|
|
38078
|
+
} catch (err) {
|
|
38079
|
+
printError(asMessage3(err));
|
|
38080
|
+
process.exitCode = 1;
|
|
38081
|
+
}
|
|
38082
|
+
});
|
|
37579
38083
|
}
|
|
37580
38084
|
|
|
37581
38085
|
// src/commands/skills.ts
|
|
@@ -37595,8 +38099,8 @@ import {
|
|
|
37595
38099
|
existsSync as existsSync89,
|
|
37596
38100
|
lstatSync as lstatSync8,
|
|
37597
38101
|
mkdirSync as mkdirSync54,
|
|
37598
|
-
readdirSync as
|
|
37599
|
-
readFileSync as
|
|
38102
|
+
readdirSync as readdirSync27,
|
|
38103
|
+
readFileSync as readFileSync73,
|
|
37600
38104
|
readlinkSync as readlinkSync4,
|
|
37601
38105
|
rmSync as rmSync9,
|
|
37602
38106
|
statSync as statSync27,
|
|
@@ -37679,7 +38183,7 @@ function ensureRealDir(p) {
|
|
|
37679
38183
|
rmSync9(p);
|
|
37680
38184
|
mkdirSync54(p, { recursive: true });
|
|
37681
38185
|
if (existsSync89(target) && statSync27(target).isDirectory()) {
|
|
37682
|
-
for (const entry of
|
|
38186
|
+
for (const entry of readdirSync27(target)) {
|
|
37683
38187
|
const src = join86(target, entry);
|
|
37684
38188
|
const dest = join86(p, entry);
|
|
37685
38189
|
const srcStat = lstatSync8(src);
|
|
@@ -37703,8 +38207,8 @@ function postMergeSanitize(mergedText, label) {
|
|
|
37703
38207
|
return { ok: false, reason: `[post-merge-sanitize] ${label} merged output failed sanitizer: ${result.reason}` };
|
|
37704
38208
|
}
|
|
37705
38209
|
function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages) {
|
|
37706
|
-
const upstreamText =
|
|
37707
|
-
const overlayText =
|
|
38210
|
+
const upstreamText = readFileSync73(upstreamPath, "utf8");
|
|
38211
|
+
const overlayText = readFileSync73(overlayPath, "utf8");
|
|
37708
38212
|
const result = mergeMarkdown(upstreamText, overlayText, label, upstreamPath, overlayPath);
|
|
37709
38213
|
if ("error" in result) {
|
|
37710
38214
|
messages.push(`ERROR ${result.error.reason}`);
|
|
@@ -37724,7 +38228,7 @@ function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages)
|
|
|
37724
38228
|
}
|
|
37725
38229
|
function isNewAgentOverlay(overlayPath) {
|
|
37726
38230
|
try {
|
|
37727
|
-
const text =
|
|
38231
|
+
const text = readFileSync73(overlayPath, "utf8");
|
|
37728
38232
|
const { fm } = parseFrontmatter3(text);
|
|
37729
38233
|
return fm["overlay-intent"] === "new-agent";
|
|
37730
38234
|
} catch {
|
|
@@ -37740,7 +38244,7 @@ function copyNewAgent(overlayPath, destPath2, label, dryRun, messages) {
|
|
|
37740
38244
|
}
|
|
37741
38245
|
function walkSkillsOverlays(skillsOverridesDir, skillsDir, opts, result) {
|
|
37742
38246
|
if (!existsSync89(skillsOverridesDir)) return;
|
|
37743
|
-
for (const skillName of
|
|
38247
|
+
for (const skillName of readdirSync27(skillsOverridesDir)) {
|
|
37744
38248
|
const overlaySkillDir = join86(skillsOverridesDir, skillName);
|
|
37745
38249
|
if (!statSync27(overlaySkillDir).isDirectory()) continue;
|
|
37746
38250
|
const upstreamSkillDir = join86(skillsDir, skillName);
|
|
@@ -37756,7 +38260,7 @@ function walkOverlayTree(overlayRoot, upstreamRoot, labelPrefix, opts, result, i
|
|
|
37756
38260
|
const stack = [overlayRoot];
|
|
37757
38261
|
while (stack.length > 0) {
|
|
37758
38262
|
const current = stack.pop();
|
|
37759
|
-
for (const entry of
|
|
38263
|
+
for (const entry of readdirSync27(current)) {
|
|
37760
38264
|
const overlayPath = join86(current, entry);
|
|
37761
38265
|
const stat = lstatSync8(overlayPath);
|
|
37762
38266
|
if (stat.isDirectory()) {
|
|
@@ -39743,9 +40247,9 @@ function registerMcpServe(cmd) {
|
|
|
39743
40247
|
init_output();
|
|
39744
40248
|
|
|
39745
40249
|
// src/commands/mcp/install-shared.ts
|
|
39746
|
-
import { spawnSync as
|
|
40250
|
+
import { spawnSync as spawnSync28 } from "node:child_process";
|
|
39747
40251
|
var DEFAULT_CLAUDE_SHELL_DEPS = {
|
|
39748
|
-
spawn:
|
|
40252
|
+
spawn: spawnSync28,
|
|
39749
40253
|
log: (msg) => console.log(msg)
|
|
39750
40254
|
};
|
|
39751
40255
|
function isOnPath(deps, bin) {
|
|
@@ -40462,8 +40966,8 @@ function registerMcp(program2) {
|
|
|
40462
40966
|
init_output();
|
|
40463
40967
|
|
|
40464
40968
|
// src/lib/memory-host-process-migration.ts
|
|
40465
|
-
import { existsSync as existsSync100, readFileSync as
|
|
40466
|
-
import { spawnSync as
|
|
40969
|
+
import { existsSync as existsSync100, readFileSync as readFileSync81, unlinkSync as unlinkSync23 } from "node:fs";
|
|
40970
|
+
import { spawnSync as spawnSync29 } from "node:child_process";
|
|
40467
40971
|
|
|
40468
40972
|
// src/commands/memory/_paths.ts
|
|
40469
40973
|
import { homedir as homedir51 } from "node:os";
|
|
@@ -40531,7 +41035,7 @@ function migrateFromHostProcess(opts = {}) {
|
|
|
40531
41035
|
}
|
|
40532
41036
|
function readPidFromFile(pidPath2) {
|
|
40533
41037
|
try {
|
|
40534
|
-
const raw =
|
|
41038
|
+
const raw = readFileSync81(pidPath2, "utf8").trim();
|
|
40535
41039
|
const pid = parseInt(raw, 10);
|
|
40536
41040
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
40537
41041
|
return pid;
|
|
@@ -40548,7 +41052,7 @@ function isProcessAlive(pid) {
|
|
|
40548
41052
|
}
|
|
40549
41053
|
}
|
|
40550
41054
|
function processCommName(pid) {
|
|
40551
|
-
const r =
|
|
41055
|
+
const r = spawnSync29("ps", ["-p", String(pid), "-o", "comm="], { encoding: "utf-8" });
|
|
40552
41056
|
if (r.status !== 0) return null;
|
|
40553
41057
|
const comm = r.stdout.trim();
|
|
40554
41058
|
return comm.split("/").pop() ?? null;
|
|
@@ -40562,7 +41066,7 @@ function terminateProcess(pid) {
|
|
|
40562
41066
|
const deadline = Date.now() + KILL_TIMEOUT_MS;
|
|
40563
41067
|
while (Date.now() < deadline) {
|
|
40564
41068
|
if (!isProcessAlive(pid)) return true;
|
|
40565
|
-
|
|
41069
|
+
spawnSync29("sleep", ["0.1"]);
|
|
40566
41070
|
}
|
|
40567
41071
|
try {
|
|
40568
41072
|
process.kill(pid, "SIGKILL");
|
|
@@ -40964,7 +41468,7 @@ function registerMemoryUninstall(cmd) {
|
|
|
40964
41468
|
// src/commands/memory/mode.ts
|
|
40965
41469
|
init_schema2();
|
|
40966
41470
|
init_output();
|
|
40967
|
-
import { existsSync as existsSync103, readFileSync as
|
|
41471
|
+
import { existsSync as existsSync103, readFileSync as readFileSync82, writeFileSync as writeFileSync51 } from "node:fs";
|
|
40968
41472
|
import { join as join94 } from "node:path";
|
|
40969
41473
|
import * as readline7 from "node:readline/promises";
|
|
40970
41474
|
import { parse as parseYaml7, stringify as stringifyYaml6 } from "yaml";
|
|
@@ -40979,7 +41483,7 @@ function locateConfig(cwd) {
|
|
|
40979
41483
|
return { absPath };
|
|
40980
41484
|
}
|
|
40981
41485
|
function readConfigYaml(absPath) {
|
|
40982
|
-
const raw =
|
|
41486
|
+
const raw = readFileSync82(absPath, "utf-8");
|
|
40983
41487
|
const parsed = parseYaml7(raw) ?? {};
|
|
40984
41488
|
if (typeof parsed !== "object" || parsed === null) {
|
|
40985
41489
|
throw new Error(`${absPath} is not a YAML object`);
|
|
@@ -41466,7 +41970,7 @@ function registerMemoryStats(cmd) {
|
|
|
41466
41970
|
}
|
|
41467
41971
|
|
|
41468
41972
|
// src/commands/memory/install-hooks.ts
|
|
41469
|
-
import { copyFileSync as copyFileSync12, existsSync as existsSync105, mkdirSync as mkdirSync60, readFileSync as
|
|
41973
|
+
import { copyFileSync as copyFileSync12, existsSync as existsSync105, mkdirSync as mkdirSync60, readFileSync as readFileSync83, writeFileSync as writeFileSync52 } from "node:fs";
|
|
41470
41974
|
import { homedir as homedir52 } from "node:os";
|
|
41471
41975
|
import { dirname as dirname56, join as join96, resolve as resolve25 } from "node:path";
|
|
41472
41976
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
@@ -41489,7 +41993,7 @@ function installOne2(basename16, sourceDir, targetDir, opts) {
|
|
|
41489
41993
|
if (!existsSync105(sourcePath)) {
|
|
41490
41994
|
throw new Error(`canonical hook source missing at ${sourcePath} \u2014 olam install corrupt or sourceDir is wrong`);
|
|
41491
41995
|
}
|
|
41492
|
-
const newContent =
|
|
41996
|
+
const newContent = readFileSync83(sourcePath, "utf8");
|
|
41493
41997
|
if (!existsSync105(targetPath)) {
|
|
41494
41998
|
if (opts.dryRun !== true) {
|
|
41495
41999
|
mkdirSync60(dirname56(targetPath), { recursive: true });
|
|
@@ -41497,7 +42001,7 @@ function installOne2(basename16, sourceDir, targetDir, opts) {
|
|
|
41497
42001
|
}
|
|
41498
42002
|
return { basename: basename16, action: "written", targetPath };
|
|
41499
42003
|
}
|
|
41500
|
-
const existing =
|
|
42004
|
+
const existing = readFileSync83(targetPath, "utf8");
|
|
41501
42005
|
if (existing === newContent) {
|
|
41502
42006
|
return { basename: basename16, action: "unchanged", targetPath };
|
|
41503
42007
|
}
|
|
@@ -42824,14 +43328,14 @@ init_file_lock();
|
|
|
42824
43328
|
import { mkdirSync as mkdirSync63, appendFileSync as appendFileSync6 } from "node:fs";
|
|
42825
43329
|
import { homedir as homedir57 } from "node:os";
|
|
42826
43330
|
import { dirname as dirname59, join as join100 } from "node:path";
|
|
42827
|
-
import { randomUUID as
|
|
43331
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
42828
43332
|
var VALID_SEVERITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "low", "info", "warn"]);
|
|
42829
43333
|
var PROMPT_FEEDING_FIELDS = ["extracted_pattern", "severity", "affected_persona", "proposed_edit"];
|
|
42830
43334
|
var BREADCRUMBS_BASE = join100(homedir57(), ".local", "share", "claude", "breadcrumbs");
|
|
42831
43335
|
var LOCK_FILENAME = ".flywheel-emit.lock";
|
|
42832
43336
|
function buildRecord(opts) {
|
|
42833
43337
|
const rec = {
|
|
42834
|
-
breadcrumb_id:
|
|
43338
|
+
breadcrumb_id: randomUUID4().replace(/-/g, ""),
|
|
42835
43339
|
emitted_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
42836
43340
|
emitted_by_skill: opts.skill,
|
|
42837
43341
|
pass_number: opts.pass !== void 0 ? Number.parseInt(opts.pass, 10) : 0,
|
|
@@ -42975,7 +43479,7 @@ function registerFlywheelK5Score(parent) {
|
|
|
42975
43479
|
}
|
|
42976
43480
|
|
|
42977
43481
|
// src/commands/flywheel/k5-validate.ts
|
|
42978
|
-
import { readFileSync as
|
|
43482
|
+
import { readFileSync as readFileSync87, statSync as statSync30 } from "node:fs";
|
|
42979
43483
|
import { parse as parseYAML } from "yaml";
|
|
42980
43484
|
var K5_DIMS = ["direction", "approach", "open_questions", "constraints", "reuse"];
|
|
42981
43485
|
var MAX_PLAN_BYTES = 1048576;
|
|
@@ -43045,7 +43549,7 @@ function validatePlan(path94) {
|
|
|
43045
43549
|
}
|
|
43046
43550
|
let text;
|
|
43047
43551
|
try {
|
|
43048
|
-
text =
|
|
43552
|
+
text = readFileSync87(path94, "utf8");
|
|
43049
43553
|
} catch (err) {
|
|
43050
43554
|
return { ok: false, message: `FAIL cannot read ${path94}: ${err instanceof Error ? err.message : "unknown"}` };
|
|
43051
43555
|
}
|
|
@@ -43127,7 +43631,7 @@ function registerFlywheelK5Validate(parent) {
|
|
|
43127
43631
|
}
|
|
43128
43632
|
|
|
43129
43633
|
// src/commands/flywheel/k10-measure.ts
|
|
43130
|
-
import { readFileSync as
|
|
43634
|
+
import { readFileSync as readFileSync88 } from "node:fs";
|
|
43131
43635
|
|
|
43132
43636
|
// ../core/dist/lib/k10-budget.js
|
|
43133
43637
|
var K10_TOKEN_CAP = 5500;
|
|
@@ -43184,7 +43688,7 @@ function registerFlywheelK10Measure(parent) {
|
|
|
43184
43688
|
parent.command("k10-measure").description("Measure K10 token budget for upstream + optional overlay; emit PASS/REJECT verdict").requiredOption("--upstream <path>", "path to upstream file (e.g. persona prompt)").option("--overlay <path>", "path to overlay file (omit if none \u2014 PASS without enforcement)").option("--json", "emit verdict as JSON instead of human-readable").action((opts) => {
|
|
43185
43689
|
let upstreamText;
|
|
43186
43690
|
try {
|
|
43187
|
-
upstreamText =
|
|
43691
|
+
upstreamText = readFileSync88(opts.upstream, "utf8");
|
|
43188
43692
|
} catch (err) {
|
|
43189
43693
|
process.stderr.write(
|
|
43190
43694
|
`[k10-measure-error] cannot read upstream ${opts.upstream}: ${err instanceof Error ? err.message : "unknown"}
|
|
@@ -43196,7 +43700,7 @@ function registerFlywheelK10Measure(parent) {
|
|
|
43196
43700
|
let overlayTokens = null;
|
|
43197
43701
|
if (opts.overlay !== void 0) {
|
|
43198
43702
|
try {
|
|
43199
|
-
const overlayText =
|
|
43703
|
+
const overlayText = readFileSync88(opts.overlay, "utf8");
|
|
43200
43704
|
overlayTokens = tokensFromText(overlayText);
|
|
43201
43705
|
} catch (err) {
|
|
43202
43706
|
process.stderr.write(
|
|
@@ -43230,7 +43734,7 @@ function registerFlywheelK10Measure(parent) {
|
|
|
43230
43734
|
}
|
|
43231
43735
|
|
|
43232
43736
|
// src/commands/flywheel/check-persona-skeleton.ts
|
|
43233
|
-
import { existsSync as existsSync109, readFileSync as
|
|
43737
|
+
import { existsSync as existsSync109, readFileSync as readFileSync89, statSync as statSync31 } from "node:fs";
|
|
43234
43738
|
import { homedir as homedir58 } from "node:os";
|
|
43235
43739
|
import { basename as basename14, join as join101 } from "node:path";
|
|
43236
43740
|
import { parse as parseYAML2 } from "yaml";
|
|
@@ -43279,7 +43783,7 @@ function checkFile(filepath) {
|
|
|
43279
43783
|
if (!existsSync109(filepath) || !statSync31(filepath).isFile()) {
|
|
43280
43784
|
return { passed: false, failures: [`file not found: ${filepath}`], tokens: 0, mergedSkipped: false };
|
|
43281
43785
|
}
|
|
43282
|
-
const text =
|
|
43786
|
+
const text = readFileSync89(filepath, "utf8");
|
|
43283
43787
|
const { fm, body } = parseFile(text);
|
|
43284
43788
|
const failures = [];
|
|
43285
43789
|
for (const key of REQUIRED_FRONTMATTER_KEYS) {
|
|
@@ -43345,7 +43849,7 @@ Results: ${passCount} passed, ${failCount} failed
|
|
|
43345
43849
|
}
|
|
43346
43850
|
|
|
43347
43851
|
// src/commands/flywheel/diversity-check.ts
|
|
43348
|
-
import { readFileSync as
|
|
43852
|
+
import { readFileSync as readFileSync90 } from "node:fs";
|
|
43349
43853
|
import { basename as basename15 } from "node:path";
|
|
43350
43854
|
import { globSync as globSync2 } from "node:fs";
|
|
43351
43855
|
|
|
@@ -43454,7 +43958,7 @@ function registerFlywheelDiversityCheck(parent) {
|
|
|
43454
43958
|
const personas = /* @__PURE__ */ new Map();
|
|
43455
43959
|
for (const filepath of files) {
|
|
43456
43960
|
try {
|
|
43457
|
-
const body =
|
|
43961
|
+
const body = readFileSync90(filepath, "utf8");
|
|
43458
43962
|
if (body.trim().length > 0) {
|
|
43459
43963
|
personas.set(basename15(filepath, ".md"), body);
|
|
43460
43964
|
}
|
|
@@ -43547,12 +44051,12 @@ import {
|
|
|
43547
44051
|
copyFileSync as copyFileSync15,
|
|
43548
44052
|
existsSync as existsSync110,
|
|
43549
44053
|
mkdirSync as mkdirSync65,
|
|
43550
|
-
readFileSync as
|
|
43551
|
-
readdirSync as
|
|
44054
|
+
readFileSync as readFileSync91,
|
|
44055
|
+
readdirSync as readdirSync32,
|
|
43552
44056
|
statSync as statSync32,
|
|
43553
44057
|
writeFileSync as writeFileSync57
|
|
43554
44058
|
} from "node:fs";
|
|
43555
|
-
import { spawnSync as
|
|
44059
|
+
import { spawnSync as spawnSync30 } from "node:child_process";
|
|
43556
44060
|
import { homedir as homedir60 } from "node:os";
|
|
43557
44061
|
import { dirname as dirname61, join as join103, relative as relative7 } from "node:path";
|
|
43558
44062
|
function escapeRegex(s) {
|
|
@@ -43586,7 +44090,7 @@ function walkOverlayFiles(dir) {
|
|
|
43586
44090
|
const found = [];
|
|
43587
44091
|
let entries;
|
|
43588
44092
|
try {
|
|
43589
|
-
entries =
|
|
44093
|
+
entries = readdirSync32(dir);
|
|
43590
44094
|
} catch {
|
|
43591
44095
|
return [];
|
|
43592
44096
|
}
|
|
@@ -43633,7 +44137,7 @@ function resolveAtlasUser2(opts) {
|
|
|
43633
44137
|
const claudeDir2 = opts._testClaudeDir ?? process.env["OLAM_CLAUDE_DIR"] ?? join103(homedir60(), ".claude");
|
|
43634
44138
|
const f = join103(claudeDir2, ".atlas-user");
|
|
43635
44139
|
if (existsSync110(f)) {
|
|
43636
|
-
const v =
|
|
44140
|
+
const v = readFileSync91(f, "utf-8").trim();
|
|
43637
44141
|
if (v.length === 0) return null;
|
|
43638
44142
|
assertValidAtlasUser(v);
|
|
43639
44143
|
return v;
|
|
@@ -43641,7 +44145,7 @@ function resolveAtlasUser2(opts) {
|
|
|
43641
44145
|
return null;
|
|
43642
44146
|
}
|
|
43643
44147
|
function runGit2(args, cwd) {
|
|
43644
|
-
const result =
|
|
44148
|
+
const result = spawnSync30("git", args, {
|
|
43645
44149
|
cwd,
|
|
43646
44150
|
encoding: "utf-8",
|
|
43647
44151
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -43775,7 +44279,7 @@ function pushOverlays(opts) {
|
|
|
43775
44279
|
const basename16 = relPath.split("/").pop() ?? relPath;
|
|
43776
44280
|
let content;
|
|
43777
44281
|
try {
|
|
43778
|
-
content =
|
|
44282
|
+
content = readFileSync91(srcFile);
|
|
43779
44283
|
} catch {
|
|
43780
44284
|
continue;
|
|
43781
44285
|
}
|
|
@@ -43823,12 +44327,12 @@ function pushOverlays(opts) {
|
|
|
43823
44327
|
const targetFile = join103(targetDir, relPath);
|
|
43824
44328
|
let srcBuf;
|
|
43825
44329
|
try {
|
|
43826
|
-
srcBuf =
|
|
44330
|
+
srcBuf = readFileSync91(srcFile);
|
|
43827
44331
|
} catch {
|
|
43828
44332
|
continue;
|
|
43829
44333
|
}
|
|
43830
44334
|
if (existsSync110(targetFile)) {
|
|
43831
|
-
const dstBuf =
|
|
44335
|
+
const dstBuf = readFileSync91(targetFile);
|
|
43832
44336
|
if (srcBuf.equals(dstBuf)) {
|
|
43833
44337
|
wouldUnchange += 1;
|
|
43834
44338
|
process.stdout.write(` [skip] ${overlayKind}.overrides/${relPath} (unchanged)
|
|
@@ -43879,13 +44383,13 @@ function pushOverlays(opts) {
|
|
|
43879
44383
|
const targetFile = join103(membersBase, `${overlayKind}.overrides`, relPath);
|
|
43880
44384
|
let srcBuf;
|
|
43881
44385
|
try {
|
|
43882
|
-
srcBuf =
|
|
44386
|
+
srcBuf = readFileSync91(srcFile);
|
|
43883
44387
|
} catch {
|
|
43884
44388
|
continue;
|
|
43885
44389
|
}
|
|
43886
44390
|
const targetExists = existsSync110(targetFile);
|
|
43887
44391
|
if (targetExists) {
|
|
43888
|
-
const dstBuf =
|
|
44392
|
+
const dstBuf = readFileSync91(targetFile);
|
|
43889
44393
|
if (srcBuf.equals(dstBuf)) {
|
|
43890
44394
|
filesUnchanged += 1;
|
|
43891
44395
|
continue;
|
|
@@ -44094,7 +44598,7 @@ function migrateOverlays(opts = {}) {
|
|
|
44094
44598
|
for (const filePath of allFiles) {
|
|
44095
44599
|
let original;
|
|
44096
44600
|
try {
|
|
44097
|
-
original =
|
|
44601
|
+
original = readFileSync91(filePath, "utf8");
|
|
44098
44602
|
} catch {
|
|
44099
44603
|
continue;
|
|
44100
44604
|
}
|
|
@@ -44254,7 +44758,7 @@ function registerFlywheel(program2) {
|
|
|
44254
44758
|
|
|
44255
44759
|
// src/commands/seed.ts
|
|
44256
44760
|
init_output();
|
|
44257
|
-
import { spawnSync as
|
|
44761
|
+
import { spawnSync as spawnSync31, spawn as spawnAsync2 } from "node:child_process";
|
|
44258
44762
|
var DEFAULT_SINGLETON_CONTAINER = "olam-postgres";
|
|
44259
44763
|
var DEFAULT_SINGLETON_USER = "development";
|
|
44260
44764
|
function assertValidSeedName(name) {
|
|
@@ -44265,7 +44769,7 @@ function assertValidSeedName(name) {
|
|
|
44265
44769
|
}
|
|
44266
44770
|
}
|
|
44267
44771
|
function singletonDocker(container, user, args, stdin) {
|
|
44268
|
-
return
|
|
44772
|
+
return spawnSync31(
|
|
44269
44773
|
"docker",
|
|
44270
44774
|
["exec", "-i", container, "psql", "-U", user, ...args],
|
|
44271
44775
|
{ encoding: "utf-8", input: stdin }
|
|
@@ -44320,7 +44824,7 @@ async function handleBake(opts) {
|
|
|
44320
44824
|
if (sources.length > 1) {
|
|
44321
44825
|
throw new Error("multiple sources specified \u2014 pass exactly one of --source-container, --source-url, --source-local");
|
|
44322
44826
|
}
|
|
44323
|
-
const ping =
|
|
44827
|
+
const ping = spawnSync31("docker", ["inspect", "--format", "{{.State.Status}}", singleton], { encoding: "utf-8" });
|
|
44324
44828
|
if (ping.status !== 0 || (ping.stdout || "").trim() !== "running") {
|
|
44325
44829
|
throw new Error(`singleton container "${singleton}" not running \u2014 run \`olam bootstrap\` first`);
|
|
44326
44830
|
}
|