@pleri/olam-cli 0.1.134 → 0.1.136
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +23 -1
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/kg-build.d.ts +29 -31
- package/dist/commands/kg-build.d.ts.map +1 -1
- package/dist/commands/kg-build.js +102 -190
- package/dist/commands/kg-build.js.map +1 -1
- package/dist/commands/kg-service-container.d.ts.map +1 -1
- package/dist/commands/kg-service-container.js +10 -0
- package/dist/commands/kg-service-container.js.map +1 -1
- package/dist/commands/memory/start.d.ts.map +1 -1
- package/dist/commands/memory/start.js +6 -0
- package/dist/commands/memory/start.js.map +1 -1
- package/dist/image-digests.json +6 -6
- package/dist/index.js +447 -344
- package/dist/mcp-server.js +303 -86
- package/host-cp/src/plan-chat-secret.mjs +92 -0
- package/host-cp/src/plan-chat-service.mjs +271 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4420,7 +4420,7 @@ function loadRepoManifest(repoDir) {
|
|
|
4420
4420
|
}
|
|
4421
4421
|
return { ...body, source };
|
|
4422
4422
|
}
|
|
4423
|
-
var runtimeSchema, appSchema, serviceSchema, deploySchema, BootstrapKindSchema, BootstrapStepSchema, RepoManifestSchema, KNOWN_TOP_LEVEL_KEYS, FORBIDDEN_KEYS;
|
|
4423
|
+
var runtimeSchema, appSchema, serviceSchema, deploySchema, planChatSchema, BootstrapKindSchema, BootstrapStepSchema, RepoManifestSchema, KNOWN_TOP_LEVEL_KEYS, FORBIDDEN_KEYS;
|
|
4424
4424
|
var init_repo_manifest = __esm({
|
|
4425
4425
|
"../core/dist/world/repo-manifest.js"() {
|
|
4426
4426
|
"use strict";
|
|
@@ -4526,6 +4526,9 @@ var init_repo_manifest = __esm({
|
|
|
4526
4526
|
deploySchema = external_exports.object({
|
|
4527
4527
|
tags: external_exports.array(external_exports.string()).optional()
|
|
4528
4528
|
}).passthrough();
|
|
4529
|
+
planChatSchema = external_exports.object({
|
|
4530
|
+
enabled: external_exports.boolean()
|
|
4531
|
+
}).strict();
|
|
4529
4532
|
BootstrapKindSchema = external_exports.enum(["gems", "node", "pg"]);
|
|
4530
4533
|
BootstrapStepSchema = external_exports.union([
|
|
4531
4534
|
external_exports.string(),
|
|
@@ -4548,7 +4551,8 @@ var init_repo_manifest = __esm({
|
|
|
4548
4551
|
secrets: external_exports.string().optional(),
|
|
4549
4552
|
bootstrap: external_exports.array(BootstrapStepSchema).optional(),
|
|
4550
4553
|
start: external_exports.string().optional(),
|
|
4551
|
-
deploy: deploySchema.optional()
|
|
4554
|
+
deploy: deploySchema.optional(),
|
|
4555
|
+
plan_chat: planChatSchema.optional()
|
|
4552
4556
|
// TODO(phase-C): runtime field consumed by stack-install.ts (T16).
|
|
4553
4557
|
// TODO(phase-D): app.fixed (sticky port) consumed by port-allocation.
|
|
4554
4558
|
// TODO(phase-D): idempotent_check on bootstrap steps in bootstrap-runner.
|
|
@@ -4556,11 +4560,11 @@ var init_repo_manifest = __esm({
|
|
|
4556
4560
|
}).passthrough().superRefine((val, ctx) => {
|
|
4557
4561
|
refineForbiddenKeys(val, [], ctx, true);
|
|
4558
4562
|
}).superRefine((val, ctx) => {
|
|
4559
|
-
const hasContent = val.version !== void 0 || val.runtime !== void 0 || val.app !== void 0 || val.services !== void 0 || val.env !== void 0 || val.secrets !== void 0 || val.bootstrap !== void 0 || val.start !== void 0 || val.deploy !== void 0;
|
|
4563
|
+
const hasContent = val.version !== void 0 || val.runtime !== void 0 || val.app !== void 0 || val.services !== void 0 || val.env !== void 0 || val.secrets !== void 0 || val.bootstrap !== void 0 || val.start !== void 0 || val.deploy !== void 0 || val.plan_chat !== void 0;
|
|
4560
4564
|
if (!hasContent) {
|
|
4561
4565
|
ctx.addIssue({
|
|
4562
4566
|
code: external_exports.ZodIssueCode.custom,
|
|
4563
|
-
message: "Manifest must declare at least one of: version, runtime, app, services, env, secrets, bootstrap, start, deploy"
|
|
4567
|
+
message: "Manifest must declare at least one of: version, runtime, app, services, env, secrets, bootstrap, start, deploy, plan_chat"
|
|
4564
4568
|
});
|
|
4565
4569
|
}
|
|
4566
4570
|
});
|
|
@@ -4574,6 +4578,10 @@ var init_repo_manifest = __esm({
|
|
|
4574
4578
|
"bootstrap",
|
|
4575
4579
|
"start",
|
|
4576
4580
|
"deploy",
|
|
4581
|
+
// olam-plan-chat-chunks-substrate Phase A task A4: opt-in for the chunks
|
|
4582
|
+
// thought substrate. Read by `resolveThoughtSubstrate` in
|
|
4583
|
+
// `packages/core/src/thought/substrate-router.ts`.
|
|
4584
|
+
"plan_chat",
|
|
4577
4585
|
// F-7 (olam-hybrid-shared-postgres dogfood finding): native inheritance —
|
|
4578
4586
|
// `.olam.yaml` may declare `inherits: .adb.yaml` to deep-merge an adb-shaped
|
|
4579
4587
|
// base manifest into itself. Retires the atlas-one `bin/olam-create-wrap.sh`
|
|
@@ -5025,7 +5033,24 @@ var init_schema2 = __esm({
|
|
|
5025
5033
|
* (B1/C4) reads this file and forwards the value as
|
|
5026
5034
|
* `AGENTMEMORY_SECRET` into worlds.
|
|
5027
5035
|
*/
|
|
5028
|
-
secret_ref: external_exports.string().min(1).optional().default("~/.olam/cloud-memory-secret")
|
|
5036
|
+
secret_ref: external_exports.string().min(1).optional().default("~/.olam/cloud-memory-secret"),
|
|
5037
|
+
/**
|
|
5038
|
+
* DO SQLite write-through bridge toggle. Defaults to `true` (bridge
|
|
5039
|
+
* active — every state-mutating call captures the engine's export to
|
|
5040
|
+
* a DO snapshot, restored on cold-start).
|
|
5041
|
+
*
|
|
5042
|
+
* Operators set `bridge: false` to bisect bridge vs engine bugs:
|
|
5043
|
+
* the CLI threads this into the Worker as `OLAM_BRIDGE_DISABLED=1`,
|
|
5044
|
+
* which makes `AgentMemoryContainer.fetch` a plain pass-through
|
|
5045
|
+
* (no capture, no restore). The next deploy with `bridge: true`
|
|
5046
|
+
* resumes captures automatically.
|
|
5047
|
+
*
|
|
5048
|
+
* See `docs/design/olam-agent-memory-do-bridge-schema.md` for the
|
|
5049
|
+
* full storage contract; the bridge is OFF only as a diagnosis aid.
|
|
5050
|
+
*
|
|
5051
|
+
* Plan reference: docs/plans/olam-agent-memory-do-sqlite-bridge/phase-c-tasks.md C3
|
|
5052
|
+
*/
|
|
5053
|
+
bridge: external_exports.boolean().optional().default(true)
|
|
5029
5054
|
});
|
|
5030
5055
|
MemorySchema = external_exports.object({
|
|
5031
5056
|
mode: external_exports.enum(["local", "cloud"]).optional().default("local"),
|
|
@@ -5370,7 +5395,7 @@ async function safeText(res) {
|
|
|
5370
5395
|
}
|
|
5371
5396
|
}
|
|
5372
5397
|
function sleep(ms) {
|
|
5373
|
-
return new Promise((
|
|
5398
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
5374
5399
|
}
|
|
5375
5400
|
var DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS, RETRY_COUNT, RETRY_BACKOFF_MS, AuthClient;
|
|
5376
5401
|
var init_client = __esm({
|
|
@@ -5522,7 +5547,7 @@ function resolveAuthServicePath() {
|
|
|
5522
5547
|
return path9.join(pkgsDir, "auth-service");
|
|
5523
5548
|
}
|
|
5524
5549
|
function sleep2(ms) {
|
|
5525
|
-
return new Promise((
|
|
5550
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
5526
5551
|
}
|
|
5527
5552
|
var DEFAULT_PORT, DEFAULT_VOLUME, DEFAULT_CONTAINER, DEFAULT_IMAGE, AuthContainerController;
|
|
5528
5553
|
var init_container = __esm({
|
|
@@ -5820,7 +5845,7 @@ var init_network = __esm({
|
|
|
5820
5845
|
// ../adapters/dist/docker/pull.js
|
|
5821
5846
|
import { spawn } from "node:child_process";
|
|
5822
5847
|
function spawnAsync(cmd, args, opts = {}) {
|
|
5823
|
-
return new Promise((
|
|
5848
|
+
return new Promise((resolve15) => {
|
|
5824
5849
|
const child = spawn(cmd, [...args], {
|
|
5825
5850
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5826
5851
|
signal: opts.signal
|
|
@@ -5834,10 +5859,10 @@ function spawnAsync(cmd, args, opts = {}) {
|
|
|
5834
5859
|
stderr += chunk.toString();
|
|
5835
5860
|
});
|
|
5836
5861
|
child.on("error", (err) => {
|
|
5837
|
-
|
|
5862
|
+
resolve15({ exitCode: -1, stdout, stderr: stderr + err.message });
|
|
5838
5863
|
});
|
|
5839
5864
|
child.on("close", (code) => {
|
|
5840
|
-
|
|
5865
|
+
resolve15({ exitCode: code ?? -1, stdout, stderr });
|
|
5841
5866
|
});
|
|
5842
5867
|
});
|
|
5843
5868
|
}
|
|
@@ -6272,6 +6297,10 @@ var init_container2 = __esm({
|
|
|
6272
6297
|
opts.push(`size=${m.size}`);
|
|
6273
6298
|
if (m.mode !== void 0)
|
|
6274
6299
|
opts.push(`mode=${m.mode.toString(8).padStart(4, "0")}`);
|
|
6300
|
+
if (m.uid !== void 0)
|
|
6301
|
+
opts.push(`uid=${m.uid}`);
|
|
6302
|
+
if (m.gid !== void 0)
|
|
6303
|
+
opts.push(`gid=${m.gid}`);
|
|
6275
6304
|
acc[m.target] = opts.join(",");
|
|
6276
6305
|
return acc;
|
|
6277
6306
|
}, {})
|
|
@@ -6307,7 +6336,7 @@ var demuxStream, execInContainer;
|
|
|
6307
6336
|
var init_exec = __esm({
|
|
6308
6337
|
"../adapters/dist/docker/exec.js"() {
|
|
6309
6338
|
"use strict";
|
|
6310
|
-
demuxStream = (stream) => new Promise((
|
|
6339
|
+
demuxStream = (stream) => new Promise((resolve15, reject) => {
|
|
6311
6340
|
const stdoutChunks = [];
|
|
6312
6341
|
const stderrChunks = [];
|
|
6313
6342
|
const stdout = new PassThrough();
|
|
@@ -6321,7 +6350,7 @@ var init_exec = __esm({
|
|
|
6321
6350
|
stream.pipe(stdout);
|
|
6322
6351
|
}
|
|
6323
6352
|
stream.on("end", () => {
|
|
6324
|
-
|
|
6353
|
+
resolve15({
|
|
6325
6354
|
stdout: Buffer.concat(stdoutChunks).toString("utf-8"),
|
|
6326
6355
|
stderr: Buffer.concat(stderrChunks).toString("utf-8")
|
|
6327
6356
|
});
|
|
@@ -6781,7 +6810,7 @@ var init_connection = __esm({
|
|
|
6781
6810
|
// -----------------------------------------------------------------------
|
|
6782
6811
|
async exec(host, command) {
|
|
6783
6812
|
const client = await this.getConnection(host);
|
|
6784
|
-
return new Promise((
|
|
6813
|
+
return new Promise((resolve15, reject) => {
|
|
6785
6814
|
client.exec(command, (err, stream) => {
|
|
6786
6815
|
if (err) {
|
|
6787
6816
|
reject(new Error(`SSH exec failed on ${host}: ${err.message}`));
|
|
@@ -6796,7 +6825,7 @@ var init_connection = __esm({
|
|
|
6796
6825
|
stderr += data.toString();
|
|
6797
6826
|
});
|
|
6798
6827
|
stream.on("close", (code) => {
|
|
6799
|
-
|
|
6828
|
+
resolve15({
|
|
6800
6829
|
exitCode: code ?? 0,
|
|
6801
6830
|
stdout: stdout.trimEnd(),
|
|
6802
6831
|
stderr: stderr.trimEnd()
|
|
@@ -6827,10 +6856,10 @@ var init_connection = __esm({
|
|
|
6827
6856
|
throw new Error(`No SSH configuration found for host: ${host}`);
|
|
6828
6857
|
}
|
|
6829
6858
|
const client = new SSHClient();
|
|
6830
|
-
return new Promise((
|
|
6859
|
+
return new Promise((resolve15, reject) => {
|
|
6831
6860
|
client.on("ready", () => {
|
|
6832
6861
|
this.connections.set(host, client);
|
|
6833
|
-
|
|
6862
|
+
resolve15(client);
|
|
6834
6863
|
}).on("error", (err) => {
|
|
6835
6864
|
this.connections.delete(host);
|
|
6836
6865
|
reject(new Error(`SSH connection to ${host} failed: ${err.message}`));
|
|
@@ -8461,8 +8490,8 @@ function copyMatchingFiles(sourcePath, destPath, pattern) {
|
|
|
8461
8490
|
try {
|
|
8462
8491
|
const matches2 = globSync(fullPattern);
|
|
8463
8492
|
for (const match2 of matches2) {
|
|
8464
|
-
const
|
|
8465
|
-
const dest = path14.join(destPath,
|
|
8493
|
+
const relative4 = path14.relative(sourcePath, match2);
|
|
8494
|
+
const dest = path14.join(destPath, relative4);
|
|
8466
8495
|
fs13.mkdirSync(path14.dirname(dest), { recursive: true });
|
|
8467
8496
|
fs13.copyFileSync(match2, dest);
|
|
8468
8497
|
}
|
|
@@ -8742,8 +8771,8 @@ import { execFileSync as execFileSync4 } from "node:child_process";
|
|
|
8742
8771
|
import * as fs15 from "node:fs";
|
|
8743
8772
|
import * as os9 from "node:os";
|
|
8744
8773
|
import * as path16 from "node:path";
|
|
8745
|
-
function expandHome2(p,
|
|
8746
|
-
return p.replace(/^~(?=$|\/|\\)/,
|
|
8774
|
+
function expandHome2(p, homedir36) {
|
|
8775
|
+
return p.replace(/^~(?=$|\/|\\)/, homedir36());
|
|
8747
8776
|
}
|
|
8748
8777
|
function sanitizeRepoFilename(name) {
|
|
8749
8778
|
const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
@@ -8766,7 +8795,7 @@ ${stderr}`;
|
|
|
8766
8795
|
}
|
|
8767
8796
|
function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
8768
8797
|
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
|
|
8769
|
-
const
|
|
8798
|
+
const homedir36 = deps.homedir ?? (() => os9.homedir());
|
|
8770
8799
|
const baselineDir = path16.join(workspacePath, ".olam", "baseline");
|
|
8771
8800
|
try {
|
|
8772
8801
|
fs15.mkdirSync(baselineDir, { recursive: true });
|
|
@@ -8782,7 +8811,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
|
|
|
8782
8811
|
continue;
|
|
8783
8812
|
const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
|
|
8784
8813
|
const outPath = path16.join(baselineDir, filename);
|
|
8785
|
-
const repoPath = expandHome2(repo.path,
|
|
8814
|
+
const repoPath = expandHome2(repo.path, homedir36);
|
|
8786
8815
|
if (!fs15.existsSync(repoPath)) {
|
|
8787
8816
|
writeBaselineFile(outPath, `# repo: ${repo.name}
|
|
8788
8817
|
# (skipped: path ${repoPath} does not exist)
|
|
@@ -8902,17 +8931,17 @@ function extractStderr(err) {
|
|
|
8902
8931
|
}
|
|
8903
8932
|
function carryUncommittedEdits(repos, workspacePath, deps = {}) {
|
|
8904
8933
|
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
|
|
8905
|
-
const
|
|
8934
|
+
const homedir36 = deps.homedir ?? (() => os9.homedir());
|
|
8906
8935
|
const existsSync64 = deps.existsSync ?? ((p) => fs15.existsSync(p));
|
|
8907
8936
|
const copyFileSync9 = deps.copyFileSync ?? ((src, dest) => fs15.copyFileSync(src, dest));
|
|
8908
|
-
const
|
|
8937
|
+
const mkdirSync36 = deps.mkdirSync ?? ((dirPath, opts) => {
|
|
8909
8938
|
fs15.mkdirSync(dirPath, opts);
|
|
8910
8939
|
});
|
|
8911
8940
|
const plans = [];
|
|
8912
8941
|
for (const repo of repos) {
|
|
8913
8942
|
if (!repo.path)
|
|
8914
8943
|
continue;
|
|
8915
|
-
const repoPath = expandHome2(repo.path,
|
|
8944
|
+
const repoPath = expandHome2(repo.path, homedir36);
|
|
8916
8945
|
const worktreePath = path16.join(workspacePath, repo.name);
|
|
8917
8946
|
if (!existsSync64(repoPath))
|
|
8918
8947
|
continue;
|
|
@@ -8979,7 +9008,7 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
|
|
|
8979
9008
|
if (!existsSync64(src))
|
|
8980
9009
|
continue;
|
|
8981
9010
|
try {
|
|
8982
|
-
|
|
9011
|
+
mkdirSync36(path16.dirname(dest), { recursive: true });
|
|
8983
9012
|
copyFileSync9(src, dest);
|
|
8984
9013
|
} catch (err) {
|
|
8985
9014
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -9422,18 +9451,18 @@ function computeFingerprint(runtimes) {
|
|
|
9422
9451
|
const joined = parts.join("_");
|
|
9423
9452
|
return sanitizeTag(joined);
|
|
9424
9453
|
}
|
|
9425
|
-
function computeImageTag(runtimes) {
|
|
9426
|
-
const baseDigest =
|
|
9454
|
+
function computeImageTag(runtimes, baseImageRef = `${BASE_IMAGE}:latest`) {
|
|
9455
|
+
const baseDigest = getImageDigest(baseImageRef);
|
|
9427
9456
|
const prefix = baseDigest.slice(0, 8);
|
|
9428
9457
|
const fingerprint = computeFingerprint(runtimes);
|
|
9429
9458
|
const tag = `${prefix}_${fingerprint}`;
|
|
9430
9459
|
return sanitizeTag(tag);
|
|
9431
9460
|
}
|
|
9432
|
-
function computeImageName(runtimes) {
|
|
9433
|
-
return `${BASE_IMAGE}:${computeImageTag(runtimes)}`;
|
|
9461
|
+
function computeImageName(runtimes, baseImageRef = `${BASE_IMAGE}:latest`) {
|
|
9462
|
+
return `${BASE_IMAGE}:${computeImageTag(runtimes, baseImageRef)}`;
|
|
9434
9463
|
}
|
|
9435
|
-
function lookupCachedImage(runtimes) {
|
|
9436
|
-
const tag = computeImageTag(runtimes);
|
|
9464
|
+
function lookupCachedImage(runtimes, baseImageRef = `${BASE_IMAGE}:latest`) {
|
|
9465
|
+
const tag = computeImageTag(runtimes, baseImageRef);
|
|
9437
9466
|
const imageName = `${BASE_IMAGE}:${tag}`;
|
|
9438
9467
|
try {
|
|
9439
9468
|
execSync2(`docker image inspect ${imageName} > /dev/null 2>&1`, {
|
|
@@ -9450,18 +9479,24 @@ function commitAsImage(containerName, imageName) {
|
|
|
9450
9479
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9451
9480
|
execSync2(`docker commit --change 'LABEL ${LABEL_PREFIX}=true' --change 'LABEL ${LABEL_PREFIX}.created-at=${now}' --change 'LABEL ${LABEL_PREFIX}.base-digest=${baseDigest}' ${containerName} ${imageName}`, { stdio: "pipe", timeout: 12e4 });
|
|
9452
9481
|
}
|
|
9453
|
-
function
|
|
9454
|
-
|
|
9455
|
-
|
|
9482
|
+
function getImageDigest(imageRef) {
|
|
9483
|
+
const memo = cachedImageDigests.get(imageRef);
|
|
9484
|
+
if (memo)
|
|
9485
|
+
return memo;
|
|
9456
9486
|
try {
|
|
9457
|
-
const digest = execSync2(`docker inspect ${
|
|
9458
|
-
|
|
9459
|
-
|
|
9487
|
+
const digest = execSync2(`docker inspect ${imageRef} --format '{{.Id}}'`, { encoding: "utf-8", timeout: 5e3 }).trim();
|
|
9488
|
+
const short = digest.replace("sha256:", "").slice(0, 16);
|
|
9489
|
+
cachedImageDigests.set(imageRef, short);
|
|
9490
|
+
return short;
|
|
9460
9491
|
} catch {
|
|
9461
|
-
|
|
9462
|
-
|
|
9492
|
+
const fallback = crypto3.createHash("sha256").update(imageRef).digest("hex").slice(0, 16);
|
|
9493
|
+
cachedImageDigests.set(imageRef, fallback);
|
|
9494
|
+
return fallback;
|
|
9463
9495
|
}
|
|
9464
9496
|
}
|
|
9497
|
+
function getBaseImageDigest() {
|
|
9498
|
+
return getImageDigest(`${BASE_IMAGE}:latest`);
|
|
9499
|
+
}
|
|
9465
9500
|
function sanitizeTag(raw) {
|
|
9466
9501
|
let tag = raw.toLowerCase().replace(/[^a-z0-9._-]/g, "-");
|
|
9467
9502
|
if (tag.length > MAX_TAG_LENGTH) {
|
|
@@ -9470,13 +9505,14 @@ function sanitizeTag(raw) {
|
|
|
9470
9505
|
}
|
|
9471
9506
|
return tag;
|
|
9472
9507
|
}
|
|
9473
|
-
var BASE_IMAGE, LABEL_PREFIX, MAX_TAG_LENGTH,
|
|
9508
|
+
var BASE_IMAGE, LABEL_PREFIX, MAX_TAG_LENGTH, cachedImageDigests;
|
|
9474
9509
|
var init_stack_image = __esm({
|
|
9475
9510
|
"../core/dist/world/stack-image.js"() {
|
|
9476
9511
|
"use strict";
|
|
9477
9512
|
BASE_IMAGE = "olam-devbox";
|
|
9478
9513
|
LABEL_PREFIX = "olam.stack-image";
|
|
9479
9514
|
MAX_TAG_LENGTH = 128;
|
|
9515
|
+
cachedImageDigests = /* @__PURE__ */ new Map();
|
|
9480
9516
|
}
|
|
9481
9517
|
});
|
|
9482
9518
|
|
|
@@ -10485,6 +10521,81 @@ var init_loader2 = __esm({
|
|
|
10485
10521
|
}
|
|
10486
10522
|
});
|
|
10487
10523
|
|
|
10524
|
+
// ../core/dist/world/auto-dispatch-task.js
|
|
10525
|
+
async function probeHealth(containerName, dockerExec, budgetMs, sleep6) {
|
|
10526
|
+
const deadline = Date.now() + budgetMs;
|
|
10527
|
+
const cadenceMs = 100;
|
|
10528
|
+
let lastErr = "";
|
|
10529
|
+
while (Date.now() < deadline) {
|
|
10530
|
+
try {
|
|
10531
|
+
const out = dockerExec(containerName, `curl -s -o /dev/null -w '%{http_code}' http://localhost:8080/health`).trim();
|
|
10532
|
+
if (out === "200")
|
|
10533
|
+
return;
|
|
10534
|
+
lastErr = `HTTP ${out || "(no response)"}`;
|
|
10535
|
+
} catch (err) {
|
|
10536
|
+
lastErr = err instanceof Error ? err.message.slice(0, 200) : String(err).slice(0, 200);
|
|
10537
|
+
}
|
|
10538
|
+
await sleep6(cadenceMs);
|
|
10539
|
+
}
|
|
10540
|
+
throw new TaskDispatchError(`container-cp /health did not return 200 within ${budgetMs}ms`, "health-probe", lastErr || "no response");
|
|
10541
|
+
}
|
|
10542
|
+
function startAgent(containerName, dockerExec) {
|
|
10543
|
+
const out = dockerExec(containerName, `curl -s -o /dev/null -w '%{http_code}' -X POST http://localhost:8080/session/start-agent`).trim();
|
|
10544
|
+
if (out !== "200" && out !== "202") {
|
|
10545
|
+
throw new TaskDispatchError(`/session/start-agent returned HTTP ${out || "(no response)"}`, "start-agent", `out=${out}`);
|
|
10546
|
+
}
|
|
10547
|
+
}
|
|
10548
|
+
function dispatch(containerName, prompt, dockerExec) {
|
|
10549
|
+
const body = JSON.stringify({ prompt });
|
|
10550
|
+
const b64 = Buffer.from(body, "utf8").toString("base64");
|
|
10551
|
+
const tmpFile = "/tmp/olam-auto-dispatch.json";
|
|
10552
|
+
dockerExec(containerName, `echo '${b64}' | base64 -d > ${tmpFile}`);
|
|
10553
|
+
const out = dockerExec(containerName, `curl -s -o /dev/null -w '%{http_code}' -X POST -H 'Content-Type: application/json' -d @${tmpFile} http://localhost:8080/dispatch`).trim();
|
|
10554
|
+
if (out !== "202" && out !== "200") {
|
|
10555
|
+
throw new TaskDispatchError(`/dispatch returned HTTP ${out || "(no response)"}`, "dispatch-post", `out=${out}`);
|
|
10556
|
+
}
|
|
10557
|
+
}
|
|
10558
|
+
function composeTaskPrompt(task, policies, formatPoliciesBrief2) {
|
|
10559
|
+
if (policies.length === 0 || !formatPoliciesBrief2)
|
|
10560
|
+
return task;
|
|
10561
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10562
|
+
const unique = policies.filter((p) => {
|
|
10563
|
+
if (seen.has(p.id))
|
|
10564
|
+
return false;
|
|
10565
|
+
seen.add(p.id);
|
|
10566
|
+
return true;
|
|
10567
|
+
});
|
|
10568
|
+
if (unique.length === 0)
|
|
10569
|
+
return task;
|
|
10570
|
+
return `${formatPoliciesBrief2(unique)}## Your task
|
|
10571
|
+
${task}`;
|
|
10572
|
+
}
|
|
10573
|
+
async function autoDispatchTask(opts) {
|
|
10574
|
+
const { containerName, task, policies, dockerExec, healthBudgetMs = 15e3, sleep: sleep6 = DEFAULT_SLEEP, logger = console, formatPoliciesBrief: formatPoliciesBrief2 } = opts;
|
|
10575
|
+
const finalPrompt = composeTaskPrompt(task, policies, formatPoliciesBrief2);
|
|
10576
|
+
await probeHealth(containerName, dockerExec, healthBudgetMs, sleep6);
|
|
10577
|
+
startAgent(containerName, dockerExec);
|
|
10578
|
+
dispatch(containerName, finalPrompt, dockerExec);
|
|
10579
|
+
logger.log(`[world] Task auto-dispatched (${finalPrompt.length} chars)`);
|
|
10580
|
+
}
|
|
10581
|
+
var TaskDispatchError, DEFAULT_SLEEP;
|
|
10582
|
+
var init_auto_dispatch_task = __esm({
|
|
10583
|
+
"../core/dist/world/auto-dispatch-task.js"() {
|
|
10584
|
+
"use strict";
|
|
10585
|
+
TaskDispatchError = class extends Error {
|
|
10586
|
+
kind;
|
|
10587
|
+
detail;
|
|
10588
|
+
constructor(message, kind, detail) {
|
|
10589
|
+
super(message);
|
|
10590
|
+
this.kind = kind;
|
|
10591
|
+
this.detail = detail;
|
|
10592
|
+
this.name = "TaskDispatchError";
|
|
10593
|
+
}
|
|
10594
|
+
};
|
|
10595
|
+
DEFAULT_SLEEP = (ms) => new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
10596
|
+
}
|
|
10597
|
+
});
|
|
10598
|
+
|
|
10488
10599
|
// ../core/dist/global-config/schema.js
|
|
10489
10600
|
function isAbsoluteOrTilde(p) {
|
|
10490
10601
|
return p.startsWith("/") || p === "~" || p.startsWith("~/");
|
|
@@ -11058,6 +11169,7 @@ var manager_exports = {};
|
|
|
11058
11169
|
__export(manager_exports, {
|
|
11059
11170
|
AuthPreflightError: () => AuthPreflightError,
|
|
11060
11171
|
BotIdentityError: () => BotIdentityError,
|
|
11172
|
+
TaskDispatchError: () => TaskDispatchError,
|
|
11061
11173
|
WorkspaceNotFoundError: () => WorkspaceNotFoundError,
|
|
11062
11174
|
WorldManager: () => WorldManager,
|
|
11063
11175
|
applyPostgresNetworkOverrides: () => applyPostgresNetworkOverrides,
|
|
@@ -11858,6 +11970,8 @@ var init_manager = __esm({
|
|
|
11858
11970
|
init_secrets_fetcher();
|
|
11859
11971
|
init_olam_yaml();
|
|
11860
11972
|
init_loader2();
|
|
11973
|
+
init_auto_dispatch_task();
|
|
11974
|
+
init_auto_dispatch_task();
|
|
11861
11975
|
init_runbooks();
|
|
11862
11976
|
init_store2();
|
|
11863
11977
|
init_bridge();
|
|
@@ -12161,9 +12275,32 @@ ${detail}`);
|
|
|
12161
12275
|
}
|
|
12162
12276
|
}
|
|
12163
12277
|
const repoSecretUrls = enrichedRepos.filter((r) => typeof r.manifest?.secrets === "string" && r.manifest.secrets.length > 0).map((r) => ({ repoName: r.name, secretsUrl: r.manifest.secrets }));
|
|
12164
|
-
let stackCacheHit = false;
|
|
12165
12278
|
let selectedImage;
|
|
12279
|
+
let cacheArchOverride;
|
|
12280
|
+
const selected = selectDevboxImageForWorld({
|
|
12281
|
+
config: this.config,
|
|
12282
|
+
repos,
|
|
12283
|
+
worldspec: opts.worldspec
|
|
12284
|
+
});
|
|
12285
|
+
if (selected) {
|
|
12286
|
+
selectedImage = selected.image;
|
|
12287
|
+
cacheArchOverride = selected.cacheArch;
|
|
12288
|
+
if (selected.source === "worldspec") {
|
|
12289
|
+
console.log(`[WorldManager] worldspec override \u2014 using ${selected.image} (tag=${selected.tag})`);
|
|
12290
|
+
} else {
|
|
12291
|
+
console.log(`[WorldManager] image_selector matched \u2014 using ${selected.image} (tag=${selected.tag}${selected.cacheArch ? `, cache_arch=${selected.cacheArch}` : ""})`);
|
|
12292
|
+
}
|
|
12293
|
+
} else {
|
|
12294
|
+
const hasRailsRepo = repos.some((r) => r.type === "rails");
|
|
12295
|
+
if (hasRailsRepo) {
|
|
12296
|
+
selectedImage = resolveDevboxImage(this.config, "amd64");
|
|
12297
|
+
cacheArchOverride = "x64";
|
|
12298
|
+
console.log(`[WorldManager] Rails repo detected \u2014 using ${selectedImage} + x64 mise-cache (Rosetta path)`);
|
|
12299
|
+
}
|
|
12300
|
+
}
|
|
12301
|
+
let stackCacheHit = false;
|
|
12166
12302
|
const preDetectedStacks = /* @__PURE__ */ new Map();
|
|
12303
|
+
const cacheBaseRef = selectedImage ?? "olam-devbox:latest";
|
|
12167
12304
|
if (this.provider.capabilities.supportsCustomImages) {
|
|
12168
12305
|
try {
|
|
12169
12306
|
const hostExec = makeHostExecFn();
|
|
@@ -12178,7 +12315,7 @@ ${detail}`);
|
|
|
12178
12315
|
}
|
|
12179
12316
|
const runtimes = collectUniqueRuntimes(Array.from(preDetectedStacks.values()));
|
|
12180
12317
|
if (runtimes.size > 0) {
|
|
12181
|
-
const cacheResult = lookupCachedImage(runtimes);
|
|
12318
|
+
const cacheResult = lookupCachedImage(runtimes, cacheBaseRef);
|
|
12182
12319
|
if (cacheResult.hit) {
|
|
12183
12320
|
selectedImage = cacheResult.imageName;
|
|
12184
12321
|
stackCacheHit = true;
|
|
@@ -12192,30 +12329,6 @@ ${detail}`);
|
|
|
12192
12329
|
console.warn(`[WorldManager] host-side stack detection failed: ${msg}`);
|
|
12193
12330
|
}
|
|
12194
12331
|
}
|
|
12195
|
-
let cacheArchOverride;
|
|
12196
|
-
if (!stackCacheHit) {
|
|
12197
|
-
const selected = selectDevboxImageForWorld({
|
|
12198
|
-
config: this.config,
|
|
12199
|
-
repos,
|
|
12200
|
-
worldspec: opts.worldspec
|
|
12201
|
-
});
|
|
12202
|
-
if (selected) {
|
|
12203
|
-
selectedImage = selected.image;
|
|
12204
|
-
cacheArchOverride = selected.cacheArch;
|
|
12205
|
-
if (selected.source === "worldspec") {
|
|
12206
|
-
console.log(`[WorldManager] worldspec override \u2014 using ${selected.image} (tag=${selected.tag})`);
|
|
12207
|
-
} else {
|
|
12208
|
-
console.log(`[WorldManager] image_selector matched \u2014 using ${selected.image} (tag=${selected.tag}${selected.cacheArch ? `, cache_arch=${selected.cacheArch}` : ""})`);
|
|
12209
|
-
}
|
|
12210
|
-
} else {
|
|
12211
|
-
const hasRailsRepo = repos.some((r) => r.type === "rails");
|
|
12212
|
-
if (hasRailsRepo) {
|
|
12213
|
-
selectedImage = resolveDevboxImage(this.config, "amd64");
|
|
12214
|
-
cacheArchOverride = "x64";
|
|
12215
|
-
console.log(`[WorldManager] Rails repo detected \u2014 using ${selectedImage} + x64 mise-cache (Rosetta path)`);
|
|
12216
|
-
}
|
|
12217
|
-
}
|
|
12218
|
-
}
|
|
12219
12332
|
const appPorts = [];
|
|
12220
12333
|
for (const repo of enrichedRepos) {
|
|
12221
12334
|
const manifestPort = repo.manifest?.app?.port;
|
|
@@ -12369,12 +12482,22 @@ ${detail}`);
|
|
|
12369
12482
|
...extraNetworks ? { extraNetworks } : {},
|
|
12370
12483
|
// Closes SEC-002 residual: hybrid worlds get a tmpfs mount at
|
|
12371
12484
|
// /run/olam to receive the per-world postgres credentials. Size
|
|
12372
|
-
// 256K is generous for a few env files; mode 0700
|
|
12373
|
-
//
|
|
12374
|
-
//
|
|
12375
|
-
//
|
|
12485
|
+
// 256K is generous for a few env files; mode 0700 keeps the dir
|
|
12486
|
+
// owner-only. uid/gid 999 matches the `olam` user from the Phase
|
|
12487
|
+
// E E4 base image contract — without setting these, the tmpfs is
|
|
12488
|
+
// root-owned and `docker exec` (which runs as the image's USER,
|
|
12489
|
+
// i.e. olam) hits EACCES on credential writes. Non-hybrid worlds
|
|
12490
|
+
// skip the mount entirely — no behavior change.
|
|
12376
12491
|
...tmpfsPostgresCredContent ? {
|
|
12377
|
-
tmpfsMounts: [
|
|
12492
|
+
tmpfsMounts: [
|
|
12493
|
+
{
|
|
12494
|
+
target: "/run/olam",
|
|
12495
|
+
size: 256 * 1024,
|
|
12496
|
+
mode: 448,
|
|
12497
|
+
uid: 999,
|
|
12498
|
+
gid: 999
|
|
12499
|
+
}
|
|
12500
|
+
],
|
|
12378
12501
|
tmpfsCredentialWrites: [
|
|
12379
12502
|
{ path: "/run/olam/postgres.env", content: tmpfsPostgresCredContent }
|
|
12380
12503
|
]
|
|
@@ -12586,48 +12709,38 @@ ${detail}`);
|
|
|
12586
12709
|
}
|
|
12587
12710
|
}
|
|
12588
12711
|
}
|
|
12589
|
-
if (
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
} catch {
|
|
12593
|
-
}
|
|
12594
|
-
if (opts.task) {
|
|
12595
|
-
let taskWithPolicies = opts.task;
|
|
12712
|
+
if (opts.task) {
|
|
12713
|
+
const allPolicies = repos.flatMap((repo) => {
|
|
12714
|
+
const repoWorktree = path24.join(workspacePath, repo.name);
|
|
12596
12715
|
try {
|
|
12597
|
-
|
|
12598
|
-
const repoWorktree = path24.join(workspacePath, repo.name);
|
|
12599
|
-
return loadPolicies(repoWorktree);
|
|
12600
|
-
});
|
|
12601
|
-
const seen = /* @__PURE__ */ new Set();
|
|
12602
|
-
const uniquePolicies = allPolicies.filter((p) => {
|
|
12603
|
-
if (seen.has(p.id))
|
|
12604
|
-
return false;
|
|
12605
|
-
seen.add(p.id);
|
|
12606
|
-
return true;
|
|
12607
|
-
});
|
|
12608
|
-
if (uniquePolicies.length > 0) {
|
|
12609
|
-
const brief = formatPoliciesBrief(uniquePolicies);
|
|
12610
|
-
taskWithPolicies = `${brief}## Your task
|
|
12611
|
-
${opts.task}`;
|
|
12612
|
-
execSync5(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
|
|
12613
|
-
for (const repo of repos) {
|
|
12614
|
-
const policiesDir = path24.join(workspacePath, repo.name, ".olam", "policies");
|
|
12615
|
-
if (fs23.existsSync(policiesDir)) {
|
|
12616
|
-
execSync5(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
|
|
12617
|
-
}
|
|
12618
|
-
}
|
|
12619
|
-
}
|
|
12716
|
+
return loadPolicies(repoWorktree);
|
|
12620
12717
|
} catch (err) {
|
|
12621
12718
|
const msg = err instanceof Error ? err.message : String(err);
|
|
12622
|
-
console.warn(`[world] policy
|
|
12719
|
+
console.warn(`[world] policy load failed for ${repo.name} (non-fatal): ${msg}`);
|
|
12720
|
+
return [];
|
|
12623
12721
|
}
|
|
12722
|
+
});
|
|
12723
|
+
if (allPolicies.length > 0) {
|
|
12624
12724
|
try {
|
|
12625
|
-
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
|
|
12725
|
+
execSync5(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
|
|
12726
|
+
for (const repo of repos) {
|
|
12727
|
+
const policiesDir = path24.join(workspacePath, repo.name, ".olam", "policies");
|
|
12728
|
+
if (fs23.existsSync(policiesDir)) {
|
|
12729
|
+
execSync5(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
|
|
12730
|
+
}
|
|
12731
|
+
}
|
|
12732
|
+
} catch (err) {
|
|
12733
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12734
|
+
console.warn(`[world] policy copy failed (non-fatal): ${msg}`);
|
|
12629
12735
|
}
|
|
12630
12736
|
}
|
|
12737
|
+
await autoDispatchTask({
|
|
12738
|
+
containerName,
|
|
12739
|
+
task: opts.task,
|
|
12740
|
+
policies: allPolicies,
|
|
12741
|
+
dockerExec: this.dockerExec,
|
|
12742
|
+
formatPoliciesBrief
|
|
12743
|
+
});
|
|
12631
12744
|
}
|
|
12632
12745
|
const controlPlanePort = 19080 + portOffset;
|
|
12633
12746
|
const dashboardPort = controlPlanePort;
|
|
@@ -14111,7 +14224,7 @@ function isCloudflaredAvailable() {
|
|
|
14111
14224
|
}
|
|
14112
14225
|
}
|
|
14113
14226
|
function startTunnel(port2) {
|
|
14114
|
-
return new Promise((
|
|
14227
|
+
return new Promise((resolve15, reject) => {
|
|
14115
14228
|
const child = spawn3("cloudflared", ["tunnel", "--url", `http://localhost:${port2}`], {
|
|
14116
14229
|
stdio: ["ignore", "pipe", "pipe"],
|
|
14117
14230
|
detached: false
|
|
@@ -14133,7 +14246,7 @@ function startTunnel(port2) {
|
|
|
14133
14246
|
if (match2) {
|
|
14134
14247
|
resolved = true;
|
|
14135
14248
|
clearTimeout(timeout);
|
|
14136
|
-
|
|
14249
|
+
resolve15(match2[0]);
|
|
14137
14250
|
}
|
|
14138
14251
|
}
|
|
14139
14252
|
child.stdout?.on("data", scan);
|
|
@@ -14220,8 +14333,8 @@ var init_dashboard = __esm({
|
|
|
14220
14333
|
}
|
|
14221
14334
|
throw err;
|
|
14222
14335
|
}
|
|
14223
|
-
await new Promise((
|
|
14224
|
-
this.server.on("listening",
|
|
14336
|
+
await new Promise((resolve15, reject) => {
|
|
14337
|
+
this.server.on("listening", resolve15);
|
|
14225
14338
|
this.server.on("error", reject);
|
|
14226
14339
|
});
|
|
14227
14340
|
this.info = { localUrl: `http://localhost:${port2}` };
|
|
@@ -14267,8 +14380,8 @@ var init_dashboard = __esm({
|
|
|
14267
14380
|
async stop() {
|
|
14268
14381
|
stopTunnel();
|
|
14269
14382
|
if (this.server) {
|
|
14270
|
-
await new Promise((
|
|
14271
|
-
this.server.close(() =>
|
|
14383
|
+
await new Promise((resolve15) => {
|
|
14384
|
+
this.server.close(() => resolve15());
|
|
14272
14385
|
});
|
|
14273
14386
|
this.server = null;
|
|
14274
14387
|
}
|
|
@@ -14668,7 +14781,7 @@ async function gatherProbeFailureDiagnostics() {
|
|
|
14668
14781
|
}
|
|
14669
14782
|
return { bootstrapStatus, containerStatus };
|
|
14670
14783
|
}
|
|
14671
|
-
async function
|
|
14784
|
+
async function probeHealth2() {
|
|
14672
14785
|
try {
|
|
14673
14786
|
const res = await fetch(`http://127.0.0.1:${HOST_CP_PORT}/health`, {
|
|
14674
14787
|
signal: AbortSignal.timeout(2e3)
|
|
@@ -14726,7 +14839,7 @@ async function startHostCp(opts) {
|
|
|
14726
14839
|
async function handleStart(opts) {
|
|
14727
14840
|
const existing = await findHostCpContainer();
|
|
14728
14841
|
if (existing && existing.state === "running") {
|
|
14729
|
-
const health2 = await
|
|
14842
|
+
const health2 = await probeHealth2();
|
|
14730
14843
|
if (health2) {
|
|
14731
14844
|
printSuccess(`Host CP already running at http://127.0.0.1:${HOST_CP_PORT}`);
|
|
14732
14845
|
printInfo("Container", existing.id);
|
|
@@ -14805,7 +14918,7 @@ async function handleStart(opts) {
|
|
|
14805
14918
|
const deadline = Date.now() + 1e4;
|
|
14806
14919
|
let healthy = false;
|
|
14807
14920
|
while (Date.now() < deadline) {
|
|
14808
|
-
const h = await
|
|
14921
|
+
const h = await probeHealth2();
|
|
14809
14922
|
if (h) {
|
|
14810
14923
|
healthy = true;
|
|
14811
14924
|
break;
|
|
@@ -14858,7 +14971,7 @@ async function handleStop() {
|
|
|
14858
14971
|
}
|
|
14859
14972
|
async function buildStatusReport() {
|
|
14860
14973
|
const container = await findHostCpContainer();
|
|
14861
|
-
const health2 = await
|
|
14974
|
+
const health2 = await probeHealth2();
|
|
14862
14975
|
const tokenFile = tokenPath();
|
|
14863
14976
|
const tokenPresent = fs26.existsSync(tokenFile);
|
|
14864
14977
|
let tokenModeOk = false;
|
|
@@ -15354,7 +15467,7 @@ async function ensureOlamPostgresSingleton(options = {}) {
|
|
|
15354
15467
|
};
|
|
15355
15468
|
}
|
|
15356
15469
|
function sleep3(ms) {
|
|
15357
|
-
return new Promise((
|
|
15470
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
15358
15471
|
}
|
|
15359
15472
|
var DEFAULT_POSTGRES_NETWORK, DEFAULT_POSTGRES_CONTAINER, DEFAULT_POSTGRES_HOST_PORT, DEFAULT_POSTGRES_IMAGE, DEFAULT_POSTGRES_USER, DEFAULT_POSTGRES_PASSWORD, DEFAULT_POSTGRES_DB, DEFAULT_POSTGRES_READY_TIMEOUT_MS;
|
|
15360
15473
|
var init_postgres_init_helpers = __esm({
|
|
@@ -16627,10 +16740,10 @@ async function confirm(message) {
|
|
|
16627
16740
|
if (!process.stdin.isTTY) return true;
|
|
16628
16741
|
const { createInterface: createInterface7 } = await import("node:readline");
|
|
16629
16742
|
const rl = createInterface7({ input: process.stdin, output: process.stdout });
|
|
16630
|
-
return new Promise((
|
|
16743
|
+
return new Promise((resolve15) => {
|
|
16631
16744
|
rl.question(`${message} [y/N] `, (answer) => {
|
|
16632
16745
|
rl.close();
|
|
16633
|
-
|
|
16746
|
+
resolve15(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
16634
16747
|
});
|
|
16635
16748
|
});
|
|
16636
16749
|
}
|
|
@@ -17008,6 +17121,17 @@ var KgServiceContainerController = class {
|
|
|
17008
17121
|
// Mount the operator's KG root (OLAM_HOME-aware) so /build can persist graphs.
|
|
17009
17122
|
"--volume",
|
|
17010
17123
|
`${kgData}:${KG_SERVICE_VOLUME_TARGET}`,
|
|
17124
|
+
// kg-service-container-v2 Phase F: read-only mount of $HOME so /build
|
|
17125
|
+
// can ingest any project under the operator's home as the source repo.
|
|
17126
|
+
// Read-only is sufficient: server-side scratch in /tmp/ holds the
|
|
17127
|
+
// working copy + receives graphify's output before persisting to
|
|
17128
|
+
// /kg-data. Operator's source tree is never written. Mount path
|
|
17129
|
+
// `/host-home` is referenced by kg-build.ts when translating cwd
|
|
17130
|
+
// → container-side path. Closes Samuel's multi-submodule cp-r bug
|
|
17131
|
+
// by construction: copy runs INSIDE the container as root, not on
|
|
17132
|
+
// the host with the operator's UID hitting locked .git/objects/pack/*.
|
|
17133
|
+
"--volume",
|
|
17134
|
+
`${process.env.HOME ?? "/root"}:/host-home:ro`,
|
|
17011
17135
|
this.imageTag
|
|
17012
17136
|
],
|
|
17013
17137
|
{ stdio: "pipe" }
|
|
@@ -17070,7 +17194,7 @@ var KgServiceContainerController = class {
|
|
|
17070
17194
|
}
|
|
17071
17195
|
};
|
|
17072
17196
|
function sleep4(ms) {
|
|
17073
|
-
return new Promise((
|
|
17197
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
17074
17198
|
}
|
|
17075
17199
|
|
|
17076
17200
|
// src/commands/services.ts
|
|
@@ -17158,7 +17282,7 @@ var McpAuthContainerController = class {
|
|
|
17158
17282
|
}
|
|
17159
17283
|
};
|
|
17160
17284
|
function sleep5(ms) {
|
|
17161
|
-
return new Promise((
|
|
17285
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
17162
17286
|
}
|
|
17163
17287
|
function dumpContainerLogs(container, tail = 40) {
|
|
17164
17288
|
try {
|
|
@@ -17854,10 +17978,10 @@ var HOST_CP_URL = "http://127.0.0.1:19000";
|
|
|
17854
17978
|
async function readHostCpTokenForCreate() {
|
|
17855
17979
|
try {
|
|
17856
17980
|
const { default: fs56 } = await import("node:fs");
|
|
17857
|
-
const { default:
|
|
17981
|
+
const { default: os32 } = await import("node:os");
|
|
17858
17982
|
const { default: path60 } = await import("node:path");
|
|
17859
17983
|
const tp = path60.join(
|
|
17860
|
-
process.env.OLAM_HOME ?? path60.join(
|
|
17984
|
+
process.env.OLAM_HOME ?? path60.join(os32.homedir(), ".olam"),
|
|
17861
17985
|
"host-cp.token"
|
|
17862
17986
|
);
|
|
17863
17987
|
if (!fs56.existsSync(tp)) return null;
|
|
@@ -18224,6 +18348,23 @@ ${pc10.cyan("Host CP UI:")} ${worldUrl}`);
|
|
|
18224
18348
|
}
|
|
18225
18349
|
}
|
|
18226
18350
|
} catch (err) {
|
|
18351
|
+
if (err instanceof TaskDispatchError) {
|
|
18352
|
+
spinner.fail("Auto-dispatch failed (world exists but task was not sent)");
|
|
18353
|
+
printError(
|
|
18354
|
+
`Task auto-dispatch failed (${err.kind}): ${err.message}`
|
|
18355
|
+
);
|
|
18356
|
+
console.log(
|
|
18357
|
+
` ${pc10.yellow("Remedy:")} ${pc10.cyan(`olam dispatch ${resolvedName} '<your task>'`)}`
|
|
18358
|
+
);
|
|
18359
|
+
console.log(
|
|
18360
|
+
` ${pc10.dim(`(or use 'olam list' to find the world ID if the name is ambiguous)`)}`
|
|
18361
|
+
);
|
|
18362
|
+
if (err.detail) {
|
|
18363
|
+
console.log(` ${pc10.dim(`detail: ${err.detail}`)}`);
|
|
18364
|
+
}
|
|
18365
|
+
process.exitCode = 1;
|
|
18366
|
+
return;
|
|
18367
|
+
}
|
|
18227
18368
|
spinner.fail("Failed to create world");
|
|
18228
18369
|
if (err instanceof AuthPreflightError) {
|
|
18229
18370
|
printError(err.message);
|
|
@@ -18253,9 +18394,9 @@ function defaultNameFromPrompt(prompt) {
|
|
|
18253
18394
|
async function readHostCpToken3() {
|
|
18254
18395
|
try {
|
|
18255
18396
|
const { default: fs56 } = await import("node:fs");
|
|
18256
|
-
const { default:
|
|
18397
|
+
const { default: os32 } = await import("node:os");
|
|
18257
18398
|
const { default: path60 } = await import("node:path");
|
|
18258
|
-
const tp = path60.join(
|
|
18399
|
+
const tp = path60.join(os32.homedir(), ".olam", "host-cp.token");
|
|
18259
18400
|
if (!fs56.existsSync(tp)) return null;
|
|
18260
18401
|
const raw = fs56.readFileSync(tp, "utf-8").trim();
|
|
18261
18402
|
return raw.length > 0 ? raw : null;
|
|
@@ -18925,14 +19066,14 @@ function printTable(entries) {
|
|
|
18925
19066
|
async function confirmInteractive() {
|
|
18926
19067
|
process.stdout.write(" Type `yes` to proceed: ");
|
|
18927
19068
|
const buf = [];
|
|
18928
|
-
return new Promise((
|
|
19069
|
+
return new Promise((resolve15) => {
|
|
18929
19070
|
const onData = (chunk) => {
|
|
18930
19071
|
buf.push(chunk);
|
|
18931
19072
|
if (Buffer.concat(buf).toString("utf-8").includes("\n")) {
|
|
18932
19073
|
process.stdin.removeListener("data", onData);
|
|
18933
19074
|
process.stdin.pause();
|
|
18934
19075
|
const answer = Buffer.concat(buf).toString("utf-8").trim();
|
|
18935
|
-
|
|
19076
|
+
resolve15(answer.toLowerCase() === "yes");
|
|
18936
19077
|
}
|
|
18937
19078
|
};
|
|
18938
19079
|
process.stdin.resume();
|
|
@@ -24647,10 +24788,10 @@ async function confirm2(message) {
|
|
|
24647
24788
|
if (!process.stdin.isTTY) return true;
|
|
24648
24789
|
const { createInterface: createInterface7 } = await import("node:readline");
|
|
24649
24790
|
const rl = createInterface7({ input: process.stdin, output: process.stdout });
|
|
24650
|
-
return new Promise((
|
|
24791
|
+
return new Promise((resolve15) => {
|
|
24651
24792
|
rl.question(`${message} [y/N] `, (answer) => {
|
|
24652
24793
|
rl.close();
|
|
24653
|
-
|
|
24794
|
+
resolve15(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
|
|
24654
24795
|
});
|
|
24655
24796
|
});
|
|
24656
24797
|
}
|
|
@@ -27153,9 +27294,9 @@ function appendIdempotent(opts) {
|
|
|
27153
27294
|
}
|
|
27154
27295
|
function resolveShellRc(home, shellEnv) {
|
|
27155
27296
|
if (!shellEnv) return null;
|
|
27156
|
-
const
|
|
27157
|
-
if (
|
|
27158
|
-
if (
|
|
27297
|
+
const basename7 = path45.basename(shellEnv);
|
|
27298
|
+
if (basename7 === "zsh") return path45.join(home, ".zshrc");
|
|
27299
|
+
if (basename7 === "bash") return path45.join(home, ".bashrc");
|
|
27159
27300
|
return null;
|
|
27160
27301
|
}
|
|
27161
27302
|
|
|
@@ -27167,10 +27308,10 @@ var NEXT_STEPS_DOCS = [
|
|
|
27167
27308
|
"docs/architecture/manifest-spec.md \u2014 per-repo .adb.yaml schema",
|
|
27168
27309
|
"docs/architecture/config-spec.md \u2014 workspace .olam/config.yaml schema"
|
|
27169
27310
|
];
|
|
27170
|
-
var defaultSpawn = (cmd, args) => new Promise((
|
|
27311
|
+
var defaultSpawn = (cmd, args) => new Promise((resolve15) => {
|
|
27171
27312
|
const child = spawn5(cmd, [...args], { stdio: "inherit" });
|
|
27172
|
-
child.on("exit", (code) =>
|
|
27173
|
-
child.on("error", () =>
|
|
27313
|
+
child.on("exit", (code) => resolve15({ status: code }));
|
|
27314
|
+
child.on("error", () => resolve15({ status: 1 }));
|
|
27174
27315
|
});
|
|
27175
27316
|
var defaultPrompt = (question, defaultYes) => {
|
|
27176
27317
|
if (!process.stdin.isTTY) {
|
|
@@ -27180,18 +27321,18 @@ var defaultPrompt = (question, defaultYes) => {
|
|
|
27180
27321
|
);
|
|
27181
27322
|
return Promise.resolve(defaultYes);
|
|
27182
27323
|
}
|
|
27183
|
-
return new Promise((
|
|
27324
|
+
return new Promise((resolve15) => {
|
|
27184
27325
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
27185
27326
|
const suffix = defaultYes ? " [Y/n]: " : " [y/N]: ";
|
|
27186
27327
|
rl.question(`${question}${suffix}`, (answer) => {
|
|
27187
27328
|
rl.close();
|
|
27188
27329
|
const t = answer.trim().toLowerCase();
|
|
27189
|
-
if (t === "")
|
|
27190
|
-
else if (t === "y" || t === "yes")
|
|
27191
|
-
else if (t === "n" || t === "no")
|
|
27192
|
-
else
|
|
27330
|
+
if (t === "") resolve15(defaultYes);
|
|
27331
|
+
else if (t === "y" || t === "yes") resolve15(true);
|
|
27332
|
+
else if (t === "n" || t === "no") resolve15(false);
|
|
27333
|
+
else resolve15(defaultYes);
|
|
27193
27334
|
});
|
|
27194
|
-
rl.on("close", () =>
|
|
27335
|
+
rl.on("close", () => resolve15(defaultYes));
|
|
27195
27336
|
});
|
|
27196
27337
|
};
|
|
27197
27338
|
async function phase1SystemCheck(deps) {
|
|
@@ -28415,7 +28556,7 @@ function registerMcpLogin(cmd) {
|
|
|
28415
28556
|
init_output();
|
|
28416
28557
|
import * as readline2 from "node:readline";
|
|
28417
28558
|
async function readTokenSilent(prompt) {
|
|
28418
|
-
return new Promise((
|
|
28559
|
+
return new Promise((resolve15, reject) => {
|
|
28419
28560
|
const rl = readline2.createInterface({
|
|
28420
28561
|
input: process.stdin,
|
|
28421
28562
|
output: process.stdout,
|
|
@@ -28433,7 +28574,7 @@ async function readTokenSilent(prompt) {
|
|
|
28433
28574
|
process.stdin.removeListener("data", onData);
|
|
28434
28575
|
process.stdout.write("\n");
|
|
28435
28576
|
rl.close();
|
|
28436
|
-
|
|
28577
|
+
resolve15(token);
|
|
28437
28578
|
} else if (char === "") {
|
|
28438
28579
|
if (process.stdin.isTTY) process.stdin.setRawMode(false);
|
|
28439
28580
|
process.stdin.removeListener("data", onData);
|
|
@@ -28708,7 +28849,7 @@ async function discoverMcpSources(repoPaths) {
|
|
|
28708
28849
|
import { spawn as spawn7 } from "node:child_process";
|
|
28709
28850
|
var VALIDATION_TIMEOUT_MS = 5e3;
|
|
28710
28851
|
async function validateMcpEntry(entry) {
|
|
28711
|
-
return new Promise((
|
|
28852
|
+
return new Promise((resolve15) => {
|
|
28712
28853
|
let stdout = "";
|
|
28713
28854
|
let timedOut = false;
|
|
28714
28855
|
let child;
|
|
@@ -28718,7 +28859,7 @@ async function validateMcpEntry(entry) {
|
|
|
28718
28859
|
env: { ...process.env, ...entry.env ?? {} }
|
|
28719
28860
|
});
|
|
28720
28861
|
} catch (err) {
|
|
28721
|
-
|
|
28862
|
+
resolve15({
|
|
28722
28863
|
name: entry.name,
|
|
28723
28864
|
validated: false,
|
|
28724
28865
|
reason: err instanceof Error ? err.message : "spawn failed"
|
|
@@ -28735,11 +28876,11 @@ async function validateMcpEntry(entry) {
|
|
|
28735
28876
|
child.on("close", (code) => {
|
|
28736
28877
|
clearTimeout(timer);
|
|
28737
28878
|
if (timedOut) {
|
|
28738
|
-
|
|
28879
|
+
resolve15({ name: entry.name, validated: false, reason: "timeout (5s)" });
|
|
28739
28880
|
return;
|
|
28740
28881
|
}
|
|
28741
28882
|
const validated = code === 0 && stdout.trim().length > 0;
|
|
28742
|
-
|
|
28883
|
+
resolve15({
|
|
28743
28884
|
name: entry.name,
|
|
28744
28885
|
validated,
|
|
28745
28886
|
reason: validated ? "ok" : `exit code ${code ?? "null"}`
|
|
@@ -28747,7 +28888,7 @@ async function validateMcpEntry(entry) {
|
|
|
28747
28888
|
});
|
|
28748
28889
|
child.on("error", (err) => {
|
|
28749
28890
|
clearTimeout(timer);
|
|
28750
|
-
|
|
28891
|
+
resolve15({ name: entry.name, validated: false, reason: err.message });
|
|
28751
28892
|
});
|
|
28752
28893
|
});
|
|
28753
28894
|
}
|
|
@@ -28762,11 +28903,11 @@ async function multiSelectPicker(entries) {
|
|
|
28762
28903
|
);
|
|
28763
28904
|
});
|
|
28764
28905
|
console.log("\n" + pc29.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
|
|
28765
|
-
const answer = await new Promise((
|
|
28906
|
+
const answer = await new Promise((resolve15) => {
|
|
28766
28907
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
28767
28908
|
rl.question("> ", (ans) => {
|
|
28768
28909
|
rl.close();
|
|
28769
|
-
|
|
28910
|
+
resolve15(ans.trim());
|
|
28770
28911
|
});
|
|
28771
28912
|
});
|
|
28772
28913
|
if (!answer || answer === "") return [];
|
|
@@ -29051,6 +29192,12 @@ async function runMemoryStart() {
|
|
|
29051
29192
|
env: {
|
|
29052
29193
|
...process.env,
|
|
29053
29194
|
AGENTMEMORY_SECRET: secret,
|
|
29195
|
+
// Bind 0.0.0.0 so worlds inside Docker can reach the host service
|
|
29196
|
+
// via `host.docker.internal:3111`. Defaults to 127.0.0.1 in the
|
|
29197
|
+
// upstream iii-config, which would make the service host-only.
|
|
29198
|
+
// The bearer-secret gate above prevents non-authed access from
|
|
29199
|
+
// any other LAN host that can route to this machine.
|
|
29200
|
+
AGENTMEMORY_HOST: "0.0.0.0",
|
|
29054
29201
|
PATH: `${OLAM_BIN_DIR}:${process.env.PATH ?? ""}`
|
|
29055
29202
|
},
|
|
29056
29203
|
stdio: ["ignore", logFd, logFd],
|
|
@@ -29244,8 +29391,8 @@ async function runMemoryLogs(opts) {
|
|
|
29244
29391
|
args.push(MEMORY_LOG_PATH);
|
|
29245
29392
|
printHeader(`olam memory logs (${opts.follow ? "follow" : `tail -n ${tailN}`})`);
|
|
29246
29393
|
const child = spawn9("tail", args, { stdio: "inherit" });
|
|
29247
|
-
return new Promise((
|
|
29248
|
-
child.on("exit", (code) =>
|
|
29394
|
+
return new Promise((resolve15) => {
|
|
29395
|
+
child.on("exit", (code) => resolve15(code ?? 0));
|
|
29249
29396
|
});
|
|
29250
29397
|
}
|
|
29251
29398
|
function registerMemoryLogs(cmd) {
|
|
@@ -29611,10 +29758,88 @@ function registerMemory(program2) {
|
|
|
29611
29758
|
// src/commands/kg-build.ts
|
|
29612
29759
|
init_storage_paths();
|
|
29613
29760
|
init_workspace_name();
|
|
29761
|
+
import * as fs53 from "node:fs";
|
|
29762
|
+
import * as os30 from "node:os";
|
|
29763
|
+
import * as path57 from "node:path";
|
|
29764
|
+
|
|
29765
|
+
// ../core/dist/kg/kg-service-client.js
|
|
29766
|
+
var KG_SERVICE_PORT_DEFAULT = 9997;
|
|
29767
|
+
function port() {
|
|
29768
|
+
const env = process.env.OLAM_KG_SERVICE_PORT;
|
|
29769
|
+
if (!env)
|
|
29770
|
+
return KG_SERVICE_PORT_DEFAULT;
|
|
29771
|
+
const n = Number.parseInt(env, 10);
|
|
29772
|
+
return Number.isFinite(n) && n > 0 ? n : KG_SERVICE_PORT_DEFAULT;
|
|
29773
|
+
}
|
|
29774
|
+
function url(path60) {
|
|
29775
|
+
return `http://127.0.0.1:${port()}${path60}`;
|
|
29776
|
+
}
|
|
29777
|
+
function kgServiceHealthUrl() {
|
|
29778
|
+
return url("/health");
|
|
29779
|
+
}
|
|
29780
|
+
function kgServiceClassifyUrl() {
|
|
29781
|
+
return url("/classify");
|
|
29782
|
+
}
|
|
29783
|
+
function kgServiceStatusUrl() {
|
|
29784
|
+
return url("/status");
|
|
29785
|
+
}
|
|
29786
|
+
function kgServiceBuildUrl() {
|
|
29787
|
+
return url("/build");
|
|
29788
|
+
}
|
|
29789
|
+
var KgServiceUnreachableError = class extends Error {
|
|
29790
|
+
cause;
|
|
29791
|
+
constructor(message, cause) {
|
|
29792
|
+
super(message);
|
|
29793
|
+
this.cause = cause;
|
|
29794
|
+
this.name = "KgServiceUnreachableError";
|
|
29795
|
+
}
|
|
29796
|
+
};
|
|
29797
|
+
var DEFAULT_TIMEOUT_MS3 = 5e3;
|
|
29798
|
+
async function postJson(endpointUrl, body, timeoutMs = DEFAULT_TIMEOUT_MS3) {
|
|
29799
|
+
let res;
|
|
29800
|
+
try {
|
|
29801
|
+
res = await fetch(endpointUrl, {
|
|
29802
|
+
method: "POST",
|
|
29803
|
+
headers: { "Content-Type": "application/json" },
|
|
29804
|
+
body: JSON.stringify(body),
|
|
29805
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
29806
|
+
});
|
|
29807
|
+
} catch (err) {
|
|
29808
|
+
throw new KgServiceUnreachableError(`kg-service not reachable at ${endpointUrl} \u2014 run \`olam services up\` to start it.`, err);
|
|
29809
|
+
}
|
|
29810
|
+
if (!res.ok) {
|
|
29811
|
+
const errBody = await res.text().catch(() => "");
|
|
29812
|
+
throw new Error(`${endpointUrl} returned ${res.status}: ${errBody.slice(0, 500)}`);
|
|
29813
|
+
}
|
|
29814
|
+
return await res.json();
|
|
29815
|
+
}
|
|
29816
|
+
async function getJson(endpointUrl, timeoutMs = DEFAULT_TIMEOUT_MS3) {
|
|
29817
|
+
let res;
|
|
29818
|
+
try {
|
|
29819
|
+
res = await fetch(endpointUrl, { signal: AbortSignal.timeout(timeoutMs) });
|
|
29820
|
+
} catch (err) {
|
|
29821
|
+
throw new KgServiceUnreachableError(`kg-service not reachable at ${endpointUrl} \u2014 run \`olam services up\` to start it.`, err);
|
|
29822
|
+
}
|
|
29823
|
+
if (!res.ok) {
|
|
29824
|
+
throw new Error(`${endpointUrl} returned ${res.status}`);
|
|
29825
|
+
}
|
|
29826
|
+
return await res.json();
|
|
29827
|
+
}
|
|
29828
|
+
async function classify(req, opts = {}) {
|
|
29829
|
+
return postJson(kgServiceClassifyUrl(), req, opts.timeoutMs);
|
|
29830
|
+
}
|
|
29831
|
+
async function health(opts = {}) {
|
|
29832
|
+
return getJson(kgServiceHealthUrl(), opts.timeoutMs ?? 2e3);
|
|
29833
|
+
}
|
|
29834
|
+
async function status(opts = {}) {
|
|
29835
|
+
return getJson(kgServiceStatusUrl(), opts.timeoutMs);
|
|
29836
|
+
}
|
|
29837
|
+
async function build(req, opts = {}) {
|
|
29838
|
+
return postJson(kgServiceBuildUrl(), req, opts.timeoutMs ?? 9e5);
|
|
29839
|
+
}
|
|
29840
|
+
|
|
29841
|
+
// src/commands/kg-build.ts
|
|
29614
29842
|
init_output();
|
|
29615
|
-
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
29616
|
-
import fs53 from "node:fs";
|
|
29617
|
-
import path57 from "node:path";
|
|
29618
29843
|
|
|
29619
29844
|
// src/commands/kg-status.ts
|
|
29620
29845
|
init_storage_paths();
|
|
@@ -29978,16 +30203,16 @@ async function runKgWatch(workspaceArg, opts, deps = {}) {
|
|
|
29978
30203
|
process.on("SIGINT", () => forward("SIGINT"));
|
|
29979
30204
|
process.on("SIGTERM", () => forward("SIGTERM"));
|
|
29980
30205
|
}
|
|
29981
|
-
return new Promise((
|
|
30206
|
+
return new Promise((resolve15) => {
|
|
29982
30207
|
child.on("exit", (code, signal) => {
|
|
29983
30208
|
removePidFile(name);
|
|
29984
30209
|
const exitCode = typeof code === "number" ? code : signal === "SIGINT" || signal === "SIGTERM" ? 0 : 1;
|
|
29985
|
-
|
|
30210
|
+
resolve15({ exitCode, pidWritten: true });
|
|
29986
30211
|
});
|
|
29987
30212
|
child.on("error", (err) => {
|
|
29988
30213
|
removePidFile(name);
|
|
29989
30214
|
printError(`graphify subprocess error: ${err.message}`);
|
|
29990
|
-
|
|
30215
|
+
resolve15({ exitCode: 1, pidWritten: true });
|
|
29991
30216
|
});
|
|
29992
30217
|
});
|
|
29993
30218
|
}
|
|
@@ -30002,78 +30227,6 @@ function registerKgWatchCommand(kg) {
|
|
|
30002
30227
|
|
|
30003
30228
|
// src/commands/kg-classify.ts
|
|
30004
30229
|
import pc31 from "picocolors";
|
|
30005
|
-
|
|
30006
|
-
// ../core/dist/kg/kg-service-client.js
|
|
30007
|
-
var KG_SERVICE_PORT_DEFAULT = 9997;
|
|
30008
|
-
function port() {
|
|
30009
|
-
const env = process.env.OLAM_KG_SERVICE_PORT;
|
|
30010
|
-
if (!env)
|
|
30011
|
-
return KG_SERVICE_PORT_DEFAULT;
|
|
30012
|
-
const n = Number.parseInt(env, 10);
|
|
30013
|
-
return Number.isFinite(n) && n > 0 ? n : KG_SERVICE_PORT_DEFAULT;
|
|
30014
|
-
}
|
|
30015
|
-
function url(path60) {
|
|
30016
|
-
return `http://127.0.0.1:${port()}${path60}`;
|
|
30017
|
-
}
|
|
30018
|
-
function kgServiceHealthUrl() {
|
|
30019
|
-
return url("/health");
|
|
30020
|
-
}
|
|
30021
|
-
function kgServiceClassifyUrl() {
|
|
30022
|
-
return url("/classify");
|
|
30023
|
-
}
|
|
30024
|
-
function kgServiceStatusUrl() {
|
|
30025
|
-
return url("/status");
|
|
30026
|
-
}
|
|
30027
|
-
var KgServiceUnreachableError = class extends Error {
|
|
30028
|
-
cause;
|
|
30029
|
-
constructor(message, cause) {
|
|
30030
|
-
super(message);
|
|
30031
|
-
this.cause = cause;
|
|
30032
|
-
this.name = "KgServiceUnreachableError";
|
|
30033
|
-
}
|
|
30034
|
-
};
|
|
30035
|
-
var DEFAULT_TIMEOUT_MS3 = 5e3;
|
|
30036
|
-
async function postJson(endpointUrl, body, timeoutMs = DEFAULT_TIMEOUT_MS3) {
|
|
30037
|
-
let res;
|
|
30038
|
-
try {
|
|
30039
|
-
res = await fetch(endpointUrl, {
|
|
30040
|
-
method: "POST",
|
|
30041
|
-
headers: { "Content-Type": "application/json" },
|
|
30042
|
-
body: JSON.stringify(body),
|
|
30043
|
-
signal: AbortSignal.timeout(timeoutMs)
|
|
30044
|
-
});
|
|
30045
|
-
} catch (err) {
|
|
30046
|
-
throw new KgServiceUnreachableError(`kg-service not reachable at ${endpointUrl} \u2014 run \`olam services up\` to start it.`, err);
|
|
30047
|
-
}
|
|
30048
|
-
if (!res.ok) {
|
|
30049
|
-
const errBody = await res.text().catch(() => "");
|
|
30050
|
-
throw new Error(`${endpointUrl} returned ${res.status}: ${errBody.slice(0, 500)}`);
|
|
30051
|
-
}
|
|
30052
|
-
return await res.json();
|
|
30053
|
-
}
|
|
30054
|
-
async function getJson(endpointUrl, timeoutMs = DEFAULT_TIMEOUT_MS3) {
|
|
30055
|
-
let res;
|
|
30056
|
-
try {
|
|
30057
|
-
res = await fetch(endpointUrl, { signal: AbortSignal.timeout(timeoutMs) });
|
|
30058
|
-
} catch (err) {
|
|
30059
|
-
throw new KgServiceUnreachableError(`kg-service not reachable at ${endpointUrl} \u2014 run \`olam services up\` to start it.`, err);
|
|
30060
|
-
}
|
|
30061
|
-
if (!res.ok) {
|
|
30062
|
-
throw new Error(`${endpointUrl} returned ${res.status}`);
|
|
30063
|
-
}
|
|
30064
|
-
return await res.json();
|
|
30065
|
-
}
|
|
30066
|
-
async function classify(req, opts = {}) {
|
|
30067
|
-
return postJson(kgServiceClassifyUrl(), req, opts.timeoutMs);
|
|
30068
|
-
}
|
|
30069
|
-
async function health(opts = {}) {
|
|
30070
|
-
return getJson(kgServiceHealthUrl(), opts.timeoutMs ?? 2e3);
|
|
30071
|
-
}
|
|
30072
|
-
async function status(opts = {}) {
|
|
30073
|
-
return getJson(kgServiceStatusUrl(), opts.timeoutMs);
|
|
30074
|
-
}
|
|
30075
|
-
|
|
30076
|
-
// src/commands/kg-classify.ts
|
|
30077
30230
|
init_output();
|
|
30078
30231
|
function registerKgClassifyCommand(kg) {
|
|
30079
30232
|
kg.command("classify <question>").description("Route a question to kg | grep | both via the 4-layer classifier (kg-service required)").option("--workspace <name>", "Scope the L2 probe gate to a specific workspace graph").option("--json", "Emit raw JSON instead of the formatted summary").action(async (question, opts) => {
|
|
@@ -30542,60 +30695,24 @@ function registerKgUninstallHookCommand(kg) {
|
|
|
30542
30695
|
}
|
|
30543
30696
|
|
|
30544
30697
|
// src/commands/kg-build.ts
|
|
30545
|
-
var DEFAULT_DEVBOX_IMAGE2 = "olam-devbox:latest";
|
|
30546
30698
|
function resolveWorkspace(arg) {
|
|
30547
30699
|
const cwd = process.cwd();
|
|
30548
30700
|
const name = arg ?? path57.basename(cwd).toLowerCase();
|
|
30549
30701
|
validateWorkspaceName(name);
|
|
30550
30702
|
return { name, sourcePath: cwd };
|
|
30551
30703
|
}
|
|
30552
|
-
function
|
|
30553
|
-
|
|
30554
|
-
|
|
30555
|
-
|
|
30556
|
-
|
|
30557
|
-
|
|
30558
|
-
|
|
30559
|
-
}
|
|
30560
|
-
const r = spawnSync20("cp", ["-r", source + "/.", scratch], {
|
|
30561
|
-
stdio: ["ignore", "ignore", "pipe"],
|
|
30562
|
-
encoding: "utf-8"
|
|
30563
|
-
});
|
|
30564
|
-
if (r.status !== 0) {
|
|
30565
|
-
throw new Error(`cp -r failed: ${(r.stderr ?? "").trim() || r.error?.message}`);
|
|
30566
|
-
}
|
|
30567
|
-
return "cp-r";
|
|
30568
|
-
}
|
|
30569
|
-
function parseNodeCount(graphifyOutDir) {
|
|
30570
|
-
const graphPath = path57.join(graphifyOutDir, "graph.json");
|
|
30571
|
-
if (!fs53.existsSync(graphPath)) return null;
|
|
30572
|
-
try {
|
|
30573
|
-
const content = fs53.readFileSync(graphPath, "utf-8");
|
|
30574
|
-
const data = JSON.parse(content);
|
|
30575
|
-
return Array.isArray(data.nodes) ? data.nodes.length : null;
|
|
30576
|
-
} catch {
|
|
30577
|
-
return null;
|
|
30704
|
+
function toContainerPath(hostPath) {
|
|
30705
|
+
const home = os30.homedir();
|
|
30706
|
+
const resolved = path57.resolve(hostPath);
|
|
30707
|
+
if (!resolved.startsWith(home + path57.sep) && resolved !== home) {
|
|
30708
|
+
throw new Error(
|
|
30709
|
+
`source path "${resolved}" is not under $HOME (${home}). kg-service can only build repos that live under your home dir (it bind-mounts $HOME:/host-home:ro at start). Move the repo or set OLAM_HOME if you need a different root.`
|
|
30710
|
+
);
|
|
30578
30711
|
}
|
|
30579
|
-
|
|
30580
|
-
|
|
30581
|
-
const r = spawnSync20(
|
|
30582
|
-
"docker",
|
|
30583
|
-
[
|
|
30584
|
-
"run",
|
|
30585
|
-
"--rm",
|
|
30586
|
-
"--entrypoint=/opt/graphify-venv/bin/pip",
|
|
30587
|
-
image,
|
|
30588
|
-
"show",
|
|
30589
|
-
"graphifyy"
|
|
30590
|
-
],
|
|
30591
|
-
{ encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"] }
|
|
30592
|
-
);
|
|
30593
|
-
if (r.status !== 0) return "unknown";
|
|
30594
|
-
const m = (r.stdout ?? "").match(/^Version:\s*(\S+)/m);
|
|
30595
|
-
return m?.[1] ?? "unknown";
|
|
30712
|
+
const rel = path57.relative(home, resolved);
|
|
30713
|
+
return rel === "" ? "/host-home" : path57.posix.join("/host-home", rel.split(path57.sep).join("/"));
|
|
30596
30714
|
}
|
|
30597
30715
|
async function runKgBuild(workspaceArg, options = {}) {
|
|
30598
|
-
const image = options.image ?? DEFAULT_DEVBOX_IMAGE2;
|
|
30599
30716
|
let workspace;
|
|
30600
30717
|
try {
|
|
30601
30718
|
workspace = resolveWorkspace(workspaceArg);
|
|
@@ -30603,82 +30720,68 @@ async function runKgBuild(workspaceArg, options = {}) {
|
|
|
30603
30720
|
printError(err instanceof Error ? err.message : String(err));
|
|
30604
30721
|
return { exitCode: 2 };
|
|
30605
30722
|
}
|
|
30723
|
+
let containerRepoPath;
|
|
30724
|
+
try {
|
|
30725
|
+
containerRepoPath = toContainerPath(workspace.sourcePath);
|
|
30726
|
+
} catch (err) {
|
|
30727
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
30728
|
+
return { exitCode: 2 };
|
|
30729
|
+
}
|
|
30606
30730
|
const outDir = kgPristinePath(workspace.name);
|
|
30607
|
-
const scratchDir = path57.join(outDir, "scratch");
|
|
30608
30731
|
fs53.mkdirSync(outDir, { recursive: true });
|
|
30609
|
-
if (fs53.existsSync(scratchDir)) fs53.rmSync(scratchDir, { recursive: true, force: true });
|
|
30610
|
-
fs53.mkdirSync(scratchDir);
|
|
30611
30732
|
const human = !options.json;
|
|
30612
30733
|
if (human) {
|
|
30613
30734
|
printInfo("kg build", `workspace=${workspace.name} source=${workspace.sourcePath}`);
|
|
30614
|
-
printInfo("kg build",
|
|
30735
|
+
printInfo("kg build", `\u2192 kg-service /build (container path ${containerRepoPath}) \u2192 ${outDir}/graphify-out/`);
|
|
30615
30736
|
}
|
|
30616
|
-
|
|
30617
|
-
let scratchStrategy;
|
|
30737
|
+
let resp;
|
|
30618
30738
|
try {
|
|
30619
|
-
|
|
30620
|
-
if (human) printInfo("kg build", `copied via ${scratchStrategy}`);
|
|
30621
|
-
const dockerArgs = [
|
|
30622
|
-
"run",
|
|
30623
|
-
"--rm",
|
|
30624
|
-
"-v",
|
|
30625
|
-
`${scratchDir}:/work`,
|
|
30626
|
-
"-w",
|
|
30627
|
-
"/work",
|
|
30628
|
-
"--entrypoint=graphify",
|
|
30629
|
-
image,
|
|
30630
|
-
"update",
|
|
30631
|
-
"."
|
|
30632
|
-
];
|
|
30633
|
-
const r = human ? spawnSync20("docker", dockerArgs, { stdio: "inherit" }) : spawnSync20("docker", dockerArgs, { stdio: ["ignore", "ignore", "pipe"] });
|
|
30634
|
-
if (r.status !== 0) {
|
|
30635
|
-
printError(`graphify update failed (exit ${r.status})`);
|
|
30636
|
-
return { exitCode: r.status ?? 1 };
|
|
30637
|
-
}
|
|
30638
|
-
const scratchOut = path57.join(scratchDir, "graphify-out");
|
|
30639
|
-
const finalOut = path57.join(outDir, "graphify-out");
|
|
30640
|
-
if (!fs53.existsSync(scratchOut)) {
|
|
30641
|
-
printError(`graphify produced no graphify-out/ in scratch (${scratchOut})`);
|
|
30642
|
-
return { exitCode: 1 };
|
|
30643
|
-
}
|
|
30644
|
-
if (fs53.existsSync(finalOut)) fs53.rmSync(finalOut, { recursive: true, force: true });
|
|
30645
|
-
fs53.renameSync(scratchOut, finalOut);
|
|
30646
|
-
const durationMs = Date.now() - started;
|
|
30647
|
-
const nodeCount = parseNodeCount(finalOut);
|
|
30648
|
-
const version = readGraphifyVersion(image);
|
|
30649
|
-
const freshness = {
|
|
30650
|
-
built_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30651
|
-
duration_ms: durationMs,
|
|
30652
|
-
node_count: nodeCount,
|
|
30653
|
-
graphify_version: version,
|
|
30739
|
+
resp = await build({
|
|
30654
30740
|
workspace: workspace.name,
|
|
30655
|
-
|
|
30656
|
-
};
|
|
30657
|
-
|
|
30658
|
-
|
|
30659
|
-
|
|
30660
|
-
"
|
|
30741
|
+
repo_path: containerRepoPath
|
|
30742
|
+
});
|
|
30743
|
+
} catch (err) {
|
|
30744
|
+
if (err instanceof KgServiceUnreachableError) {
|
|
30745
|
+
printError(err.message);
|
|
30746
|
+
printInfo("remedy", "run `olam services up` to start kg-service, then re-run `olam kg build`.");
|
|
30747
|
+
return { exitCode: 3 };
|
|
30748
|
+
}
|
|
30749
|
+
printError(`kg-service /build failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
30750
|
+
return { exitCode: 1 };
|
|
30751
|
+
}
|
|
30752
|
+
if (!resp.ok) {
|
|
30753
|
+
printError(`kg-service /build returned error: ${resp.error ?? "unknown"}`);
|
|
30754
|
+
return { exitCode: 1 };
|
|
30755
|
+
}
|
|
30756
|
+
const freshness = {
|
|
30757
|
+
built_at: resp.built_at ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
30758
|
+
duration_ms: resp.duration_ms ?? 0,
|
|
30759
|
+
node_count: resp.nodes ?? null,
|
|
30760
|
+
edge_count: resp.edges ?? null,
|
|
30761
|
+
workspace: workspace.name,
|
|
30762
|
+
graphify_path: "container"
|
|
30763
|
+
};
|
|
30764
|
+
fs53.writeFileSync(
|
|
30765
|
+
path57.join(outDir, "freshness.json"),
|
|
30766
|
+
JSON.stringify(freshness, null, 2) + "\n",
|
|
30767
|
+
"utf-8"
|
|
30768
|
+
);
|
|
30769
|
+
const finalOut = path57.join(outDir, "graphify-out");
|
|
30770
|
+
if (options.json) {
|
|
30771
|
+
process.stdout.write(JSON.stringify(freshness) + "\n");
|
|
30772
|
+
} else {
|
|
30773
|
+
printSuccess(
|
|
30774
|
+
`kg build ${workspace.name} \u2014 ${resp.nodes ?? "?"} nodes / ${resp.edges ?? "?"} edges in ${((resp.duration_ms ?? 0) / 1e3).toFixed(1)}s (via kg-service container)`
|
|
30661
30775
|
);
|
|
30662
|
-
|
|
30663
|
-
process.stdout.write(JSON.stringify(freshness) + "\n");
|
|
30664
|
-
} else {
|
|
30665
|
-
printSuccess(
|
|
30666
|
-
`kg build ${workspace.name} \u2014 ${nodeCount ?? "?"} nodes in ${(durationMs / 1e3).toFixed(1)}s (graphify ${version})`
|
|
30667
|
-
);
|
|
30668
|
-
printInfo("output", `${finalOut}/graph.json`);
|
|
30669
|
-
}
|
|
30670
|
-
return { exitCode: 0, freshness, outputDir: finalOut };
|
|
30671
|
-
} finally {
|
|
30672
|
-
if (fs53.existsSync(scratchDir)) {
|
|
30673
|
-
fs53.rmSync(scratchDir, { recursive: true, force: true });
|
|
30674
|
-
}
|
|
30776
|
+
printInfo("output", `${finalOut}/graph.json`);
|
|
30675
30777
|
}
|
|
30778
|
+
return { exitCode: 0, freshness, outputDir: finalOut };
|
|
30676
30779
|
}
|
|
30677
30780
|
function registerKg(program2) {
|
|
30678
|
-
const kg = program2.command("kg").description("Knowledge-graph operations (
|
|
30781
|
+
const kg = program2.command("kg").description("Knowledge-graph operations (kg-service container)");
|
|
30679
30782
|
kg.command("build").description(
|
|
30680
|
-
"Build pristine KG for a workspace (default: current dir).
|
|
30681
|
-
).argument("[workspace]", "workspace name (lowercase alphanumeric + hyphens/underscores)").option("--
|
|
30783
|
+
"Build pristine KG for a workspace (default: current dir). Routes through olam-kg-service /build endpoint."
|
|
30784
|
+
).argument("[workspace]", "workspace name (lowercase alphanumeric + hyphens/underscores)").option("--json", "emit freshness record as JSON instead of human-readable status").action(async (workspaceArg, opts) => {
|
|
30682
30785
|
const r = await runKgBuild(workspaceArg, opts);
|
|
30683
30786
|
if (r.exitCode !== 0) process.exitCode = r.exitCode;
|
|
30684
30787
|
});
|
|
@@ -30692,7 +30795,7 @@ function registerKg(program2) {
|
|
|
30692
30795
|
|
|
30693
30796
|
// src/commands/seed.ts
|
|
30694
30797
|
init_output();
|
|
30695
|
-
import { spawnSync as
|
|
30798
|
+
import { spawnSync as spawnSync20, spawn as spawnAsync2 } from "node:child_process";
|
|
30696
30799
|
var DEFAULT_SINGLETON_CONTAINER = "olam-postgres";
|
|
30697
30800
|
var DEFAULT_SINGLETON_USER = "development";
|
|
30698
30801
|
function assertValidSeedName(name) {
|
|
@@ -30703,7 +30806,7 @@ function assertValidSeedName(name) {
|
|
|
30703
30806
|
}
|
|
30704
30807
|
}
|
|
30705
30808
|
function singletonDocker(container, user, args, stdin) {
|
|
30706
|
-
return
|
|
30809
|
+
return spawnSync20(
|
|
30707
30810
|
"docker",
|
|
30708
30811
|
["exec", "-i", container, "psql", "-U", user, ...args],
|
|
30709
30812
|
{ encoding: "utf-8", input: stdin }
|
|
@@ -30758,7 +30861,7 @@ async function handleBake(opts) {
|
|
|
30758
30861
|
if (sources.length > 1) {
|
|
30759
30862
|
throw new Error("multiple sources specified \u2014 pass exactly one of --source-container, --source-url, --source-local");
|
|
30760
30863
|
}
|
|
30761
|
-
const ping =
|
|
30864
|
+
const ping = spawnSync20("docker", ["inspect", "--format", "{{.State.Status}}", singleton], { encoding: "utf-8" });
|
|
30762
30865
|
if (ping.status !== 0 || (ping.stdout || "").trim() !== "running") {
|
|
30763
30866
|
throw new Error(`singleton container "${singleton}" not running \u2014 run \`olam bootstrap\` first`);
|
|
30764
30867
|
}
|
|
@@ -30940,13 +31043,13 @@ init_context();
|
|
|
30940
31043
|
init_output();
|
|
30941
31044
|
import { spawnSync as defaultSpawnSync } from "node:child_process";
|
|
30942
31045
|
import * as fs54 from "node:fs";
|
|
30943
|
-
import * as
|
|
31046
|
+
import * as os31 from "node:os";
|
|
30944
31047
|
import * as path58 from "node:path";
|
|
30945
31048
|
function devboxContainerName(worldId) {
|
|
30946
31049
|
return `olam-${worldId}-devbox`;
|
|
30947
31050
|
}
|
|
30948
31051
|
function olamHomeDir() {
|
|
30949
|
-
return process.env["OLAM_HOME"] ?? path58.join(
|
|
31052
|
+
return process.env["OLAM_HOME"] ?? path58.join(os31.homedir(), ".olam");
|
|
30950
31053
|
}
|
|
30951
31054
|
function defaultRestartContainer(name, spawn11 = defaultSpawnSync) {
|
|
30952
31055
|
const r = spawn11("docker", ["restart", "--time", "30", name], {
|