@pleri/olam-cli 0.1.173 → 0.1.175

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.
Files changed (33) hide show
  1. package/dist/commands/auth.d.ts +22 -7
  2. package/dist/commands/auth.d.ts.map +1 -1
  3. package/dist/commands/auth.js +414 -46
  4. package/dist/commands/auth.js.map +1 -1
  5. package/dist/commands/create.d.ts.map +1 -1
  6. package/dist/commands/create.js +45 -1
  7. package/dist/commands/create.js.map +1 -1
  8. package/dist/commands/services.d.ts +39 -0
  9. package/dist/commands/services.d.ts.map +1 -1
  10. package/dist/commands/services.js +64 -9
  11. package/dist/commands/services.js.map +1 -1
  12. package/dist/from-manifest.d.ts +53 -0
  13. package/dist/from-manifest.d.ts.map +1 -0
  14. package/dist/from-manifest.js +95 -0
  15. package/dist/from-manifest.js.map +1 -0
  16. package/dist/image-digests.json +8 -8
  17. package/dist/index.js +907 -136
  18. package/dist/lib/auth-remote.d.ts +130 -0
  19. package/dist/lib/auth-remote.d.ts.map +1 -0
  20. package/dist/lib/auth-remote.js +307 -0
  21. package/dist/lib/auth-remote.js.map +1 -0
  22. package/dist/mcp-server.js +254 -57
  23. package/hermes-bundle/version.json +1 -1
  24. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  25. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  26. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  27. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  28. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  29. package/host-cp/src/boot-reconciler.mjs +238 -0
  30. package/host-cp/src/port-bridge-manager.mjs +116 -10
  31. package/host-cp/src/server.mjs +32 -0
  32. package/host-cp/src/world-activity-tracker.mjs +392 -0
  33. package/package.json +1 -1
@@ -12331,10 +12331,10 @@ var init_runbooks = __esm({
12331
12331
  // ../core/dist/global-config/port-validator.js
12332
12332
  import * as net2 from "node:net";
12333
12333
  import * as childProcess from "node:child_process";
12334
- import { createRequire as createRequire3 } from "node:module";
12334
+ import { createRequire as createRequire4 } from "node:module";
12335
12335
  function getRequire() {
12336
12336
  if (!_require3) {
12337
- _require3 = createRequire3(import.meta.url);
12337
+ _require3 = createRequire4(import.meta.url);
12338
12338
  }
12339
12339
  return _require3;
12340
12340
  }
@@ -14165,9 +14165,9 @@ var init_file_lock = __esm({
14165
14165
  });
14166
14166
 
14167
14167
  // ../core/dist/lib/min-version-filter.js
14168
- import { existsSync as existsSync27, readFileSync as readFileSync23 } from "node:fs";
14168
+ import { existsSync as existsSync28, readFileSync as readFileSync23 } from "node:fs";
14169
14169
  function readOlamMinVersion(filepath) {
14170
- if (!existsSync27(filepath))
14170
+ if (!existsSync28(filepath))
14171
14171
  return void 0;
14172
14172
  let text;
14173
14173
  try {
@@ -14790,7 +14790,7 @@ var init_meta_hook_injector = __esm({
14790
14790
 
14791
14791
  // ../core/dist/lib/markdown-merger.js
14792
14792
  import { createHash as createHash5 } from "node:crypto";
14793
- import { readFileSync as readFileSync27, existsSync as existsSync30, statSync as statSync8 } from "node:fs";
14793
+ import { readFileSync as readFileSync27, existsSync as existsSync31, statSync as statSync8 } from "node:fs";
14794
14794
  function parseFrontmatter(text) {
14795
14795
  const match = FM_RE2.exec(text);
14796
14796
  if (match === null)
@@ -14910,7 +14910,7 @@ function mergeMarkdown(upstreamText, overlayText, labelForError, upstreamPath, o
14910
14910
  return { merged: fmBlock !== "" ? fmBlock + mergedBody : mergedBody };
14911
14911
  }
14912
14912
  function sha256OfPath(p) {
14913
- if (!existsSync30(p) || !statSync8(p).isFile())
14913
+ if (!existsSync31(p) || !statSync8(p).isFile())
14914
14914
  return "MISSING";
14915
14915
  return createHash5("sha256").update(readFileSync27(p)).digest("hex");
14916
14916
  }
@@ -15123,7 +15123,7 @@ var init_prefix_deploy = __esm({
15123
15123
  });
15124
15124
 
15125
15125
  // ../core/dist/skill-sync/resolve-source-config.js
15126
- import { readFileSync as readFileSync29, existsSync as existsSync31 } from "node:fs";
15126
+ import { readFileSync as readFileSync29, existsSync as existsSync32 } from "node:fs";
15127
15127
  import { join as join31 } from "node:path";
15128
15128
  import { parse as parseYaml4 } from "yaml";
15129
15129
  function sourceConfigPath(clonePath) {
@@ -15131,7 +15131,7 @@ function sourceConfigPath(clonePath) {
15131
15131
  }
15132
15132
  function readSourceConfig(clonePath, sourceId) {
15133
15133
  const path53 = sourceConfigPath(clonePath);
15134
- if (!existsSync31(path53))
15134
+ if (!existsSync32(path53))
15135
15135
  return void 0;
15136
15136
  let raw;
15137
15137
  try {
@@ -28718,6 +28718,21 @@ var WorldRegistry = class {
28718
28718
  const row = this.db.prepare("SELECT * FROM worlds WHERE id = ?").get(worldId);
28719
28719
  return row ? rowToMetadata(row) : void 0;
28720
28720
  }
28721
+ /**
28722
+ * Find all worlds with a given `name`. Returns rows of every lifecycle
28723
+ * status — callers filter as needed (e.g. active-only for dedup, error-
28724
+ * only for cleanup).
28725
+ *
28726
+ * The schema has UNIQUE on `id` but NOT on `name`, so a single name can
28727
+ * legitimately have multiple rows (e.g. one destroyed + one new). Issue
28728
+ * #962: `olam create <name>` was generating fresh ids without checking
28729
+ * for an existing row, accumulating orphan error rows under the same
28730
+ * name. This is the registry-level primitive the manager's dedup uses.
28731
+ */
28732
+ findByName(name) {
28733
+ const rows = this.db.prepare("SELECT * FROM worlds WHERE name = ? ORDER BY created_at DESC").all(name);
28734
+ return rows.map(rowToMetadata);
28735
+ }
28721
28736
  list(filter) {
28722
28737
  if (filter?.status) {
28723
28738
  const rows2 = this.db.prepare("SELECT * FROM worlds WHERE status = ? ORDER BY created_at DESC").all(filter.status);
@@ -32349,8 +32364,8 @@ function copyDirRecursive(src, dest, depth = 0, skipFiles = /* @__PURE__ */ new
32349
32364
  }
32350
32365
  }
32351
32366
  async function copyClaudeConfigIntoContainer(containerName) {
32352
- const { execSync: execSync7 } = await import("node:child_process");
32353
- const dockerExec = (cmd) => execSync7(`docker exec ${containerName} sh -c '${cmd}'`, { stdio: "pipe" });
32367
+ const { execSync: execSync8 } = await import("node:child_process");
32368
+ const dockerExec = (cmd) => execSync8(`docker exec ${containerName} sh -c '${cmd}'`, { stdio: "pipe" });
32354
32369
  dockerExec("mkdir -p $HOME/.claude");
32355
32370
  dockerExec("test -f /home/olam/workspace/.claude-host-config/settings.json && cp /home/olam/workspace/.claude-host-config/settings.json $HOME/.claude/settings.json || true");
32356
32371
  dockerExec("test -f /home/olam/workspace/.claude-host-config/CLAUDE.md && cp /home/olam/workspace/.claude-host-config/CLAUDE.md $HOME/.claude/CLAUDE.md || true");
@@ -32366,7 +32381,7 @@ async function copyClaudeConfigIntoContainer(containerName) {
32366
32381
  await sanitizeContainerClaudeHooks(containerName);
32367
32382
  }
32368
32383
  async function sanitizeContainerClaudeHooks(containerName) {
32369
- const { execSync: execSync7 } = await import("node:child_process");
32384
+ const { execSync: execSync8 } = await import("node:child_process");
32370
32385
  const script = `
32371
32386
  const fs = require('fs');
32372
32387
  const p = (process.env.HOME || '/home/olam') + '/.claude/settings.json';
@@ -32410,7 +32425,7 @@ if (changed) {
32410
32425
  }
32411
32426
  `;
32412
32427
  try {
32413
- execSync7(`docker exec ${containerName} /usr/local/bin/node -e ${shQuote(script)}`, { stdio: "pipe" });
32428
+ execSync8(`docker exec ${containerName} /usr/local/bin/node -e ${shQuote(script)}`, { stdio: "pipe" });
32414
32429
  } catch {
32415
32430
  }
32416
32431
  }
@@ -33039,29 +33054,116 @@ function register9(server, ctx, initError, deps) {
33039
33054
  // ../mcp-server/src/tools/world-observe.ts
33040
33055
  var world_observe_exports = {};
33041
33056
  __export(world_observe_exports, {
33057
+ readWorldChunks: () => readWorldChunks,
33042
33058
  register: () => register10
33043
33059
  });
33060
+ import { createRequire as createRequire3 } from "node:module";
33061
+ import { existsSync as existsSync11 } from "node:fs";
33044
33062
 
33045
33063
  // ../skill-runtime/dist/skills/world-observe.js
33046
33064
  init_v3();
33047
33065
  var worldObserveInputSchema = external_exports.object({
33048
- worldId: external_exports.string()
33066
+ worldId: external_exports.string(),
33067
+ sessionId: external_exports.string().optional(),
33068
+ sinceChunkId: external_exports.string().optional(),
33069
+ limit: external_exports.number().int().min(1).max(1e3).optional()
33049
33070
  });
33050
33071
  var worldObserveSkill = defineSkill({
33051
33072
  name: "world-observe",
33052
- description: "Watch a world's reasoning process and retrieve its current thought stream.",
33073
+ description: "Stream a world's reasoning chunks (thought_nodes feed). Returns JSON `{ chunks: [{ chunkId, sessionId, role, content, createdAt, nodeType }], metadata: { pane_state, count } }`, most-recent-last. Supports pagination via `sinceChunkId` (returns only chunks newer than the given id) and `limit` (default 100, max 1000). Use `olam_list` first to discover worldIds.",
33053
33074
  inputSchema: worldObserveInputSchema,
33054
- handler: (_input) => "Observation is coming in a future release. This feature will stream a world's reasoning in real-time."
33075
+ handler: (_input) => "World observation requires an active OlamContext. Use the MCP tool surface to read a world's chunks."
33055
33076
  });
33056
33077
 
33057
33078
  // ../mcp-server/src/tools/world-observe.ts
33079
+ var require2 = createRequire3(import.meta.url);
33080
+ var SYSTEM_NODE_TYPES = /* @__PURE__ */ new Set(["lifecycle", "dispatch_error"]);
33081
+ var DEFAULT_LIMIT = 100;
33082
+ var BUSY_WINDOW_MS = 3e4;
33083
+ function roleFor(nodeType) {
33084
+ return SYSTEM_NODE_TYPES.has(nodeType) ? "system" : "assistant";
33085
+ }
33086
+ function rowToChunk(row) {
33087
+ return {
33088
+ chunkId: row.id,
33089
+ sessionId: row.session_id,
33090
+ role: roleFor(row.node_type),
33091
+ content: row.content,
33092
+ summary: row.summary,
33093
+ createdAt: row.created_at,
33094
+ nodeType: row.node_type,
33095
+ sequenceNum: row.sequence_num
33096
+ };
33097
+ }
33098
+ function readWorldChunks(dbPath, params) {
33099
+ const limit = params.limit ?? DEFAULT_LIMIT;
33100
+ const now = params.now ?? Date.now();
33101
+ const empty = () => ({
33102
+ worldId: params.worldId,
33103
+ chunks: [],
33104
+ metadata: {
33105
+ count: 0,
33106
+ pane_state: "idle",
33107
+ sessionFilter: params.sessionId ?? null,
33108
+ sinceChunkId: params.sinceChunkId ?? null,
33109
+ limit
33110
+ }
33111
+ });
33112
+ if (!existsSync11(dbPath)) return empty();
33113
+ const Sqlite = require2("better-sqlite3");
33114
+ const db = new Sqlite(dbPath, { readonly: true, fileMustExist: true });
33115
+ try {
33116
+ let minSeq = -1;
33117
+ if (params.sinceChunkId) {
33118
+ const seqRow = db.prepare("SELECT sequence_num FROM thought_nodes WHERE id = ?").get(params.sinceChunkId);
33119
+ if (!seqRow) {
33120
+ return empty();
33121
+ }
33122
+ minSeq = seqRow.sequence_num;
33123
+ }
33124
+ const where = ["sequence_num > ?"];
33125
+ const bind = [minSeq];
33126
+ if (params.sessionId !== void 0) {
33127
+ where.push("session_id = ?");
33128
+ bind.push(params.sessionId);
33129
+ }
33130
+ const sql = `SELECT id, node_type, summary, content, source_ref, sequence_num, created_at, session_id, hook_event_name, turn_index, token_usage, duration_ms FROM thought_nodes WHERE ${where.join(" AND ")} ORDER BY sequence_num DESC LIMIT ?`;
33131
+ const rows = db.prepare(sql).all(...bind, limit);
33132
+ rows.reverse();
33133
+ const lastRow = rows[rows.length - 1];
33134
+ let paneState = "idle";
33135
+ if (lastRow) {
33136
+ const ageMs = now - new Date(lastRow.created_at).getTime();
33137
+ paneState = ageMs <= BUSY_WINDOW_MS ? "busy" : "idle";
33138
+ } else {
33139
+ const maxRow = db.prepare("SELECT MAX(created_at) AS max_at FROM thought_nodes").get();
33140
+ if (maxRow?.max_at) {
33141
+ const ageMs = now - new Date(maxRow.max_at).getTime();
33142
+ paneState = ageMs <= BUSY_WINDOW_MS ? "busy" : "idle";
33143
+ }
33144
+ }
33145
+ return {
33146
+ worldId: params.worldId,
33147
+ chunks: rows.map(rowToChunk),
33148
+ metadata: {
33149
+ count: rows.length,
33150
+ pane_state: paneState,
33151
+ sessionFilter: params.sessionId ?? null,
33152
+ sinceChunkId: params.sinceChunkId ?? null,
33153
+ limit
33154
+ }
33155
+ };
33156
+ } finally {
33157
+ db.close();
33158
+ }
33159
+ }
33058
33160
  function register10(server, ctx, initError) {
33059
33161
  const { description, inputSchema } = worldObserveSkill.asMcpTool();
33060
33162
  server.tool(
33061
33163
  "olam_observe",
33062
33164
  description,
33063
33165
  inputSchema,
33064
- async (_params) => {
33166
+ async (params) => {
33065
33167
  if (!ctx) {
33066
33168
  const errorMsg = initError?.message ?? "Olam is not configured. Run /olam:init to set up.";
33067
33169
  return {
@@ -33069,10 +33171,34 @@ function register10(server, ctx, initError) {
33069
33171
  isError: true
33070
33172
  };
33071
33173
  }
33072
- return {
33073
- content: [{ type: "text", text: "Observation is coming in a future release. This feature will stream a world's reasoning in real-time." }],
33074
- isError: true
33075
- };
33174
+ const { worldId, sessionId, sinceChunkId, limit } = params;
33175
+ const world = ctx.worldManager.getWorld(worldId);
33176
+ if (!world) {
33177
+ return {
33178
+ content: [
33179
+ {
33180
+ type: "text",
33181
+ text: `World "${worldId}" not found. Use olam_list to discover available worlds.`
33182
+ }
33183
+ ],
33184
+ isError: true
33185
+ };
33186
+ }
33187
+ try {
33188
+ const dbPath = getWorldDbPath(world.workspacePath);
33189
+ const output = readWorldChunks(dbPath, { worldId, sessionId, sinceChunkId, limit });
33190
+ return {
33191
+ content: [{ type: "text", text: JSON.stringify(output, null, 2) }]
33192
+ };
33193
+ } catch (err) {
33194
+ const message = err instanceof Error ? err.message : String(err);
33195
+ return {
33196
+ content: [
33197
+ { type: "text", text: `Failed to read chunks for world "${worldId}": ${message}` }
33198
+ ],
33199
+ isError: true
33200
+ };
33201
+ }
33076
33202
  }
33077
33203
  );
33078
33204
  }
@@ -36070,16 +36196,20 @@ function register23(server, _ctx, _initError) {
36070
36196
  };
36071
36197
  }
36072
36198
  const data = JSON.parse(body);
36199
+ const payload = {
36200
+ url: `http://localhost:${data.hostPort}`,
36201
+ host_port: data.hostPort,
36202
+ sidecar_container_id: data.containerId,
36203
+ container_port: data.containerPort,
36204
+ container_name: data.containerName
36205
+ };
36206
+ if (data.pulledImage === true) {
36207
+ payload["pulled_image"] = "alpine/socat:latest (first-call fallback)";
36208
+ }
36073
36209
  return {
36074
36210
  content: [{
36075
36211
  type: "text",
36076
- text: JSON.stringify({
36077
- url: `http://localhost:${data.hostPort}`,
36078
- host_port: data.hostPort,
36079
- sidecar_container_id: data.containerId,
36080
- container_port: data.containerPort,
36081
- container_name: data.containerName
36082
- }, null, 2)
36212
+ text: JSON.stringify(payload, null, 2)
36083
36213
  }]
36084
36214
  };
36085
36215
  } catch (err) {
@@ -36719,14 +36849,14 @@ import * as path37 from "node:path";
36719
36849
  import * as os22 from "node:os";
36720
36850
 
36721
36851
  // ../mcp-server/src/lib/skills-index.mjs
36722
- import { createRequire as createRequire4 } from "node:module";
36852
+ import { createRequire as createRequire5 } from "node:module";
36723
36853
  import * as fs37 from "node:fs";
36724
36854
  import * as path36 from "node:path";
36725
36855
  import * as os21 from "node:os";
36726
36856
  var VECTOR_DIM = 256;
36727
36857
  var SCHEMA_VERSION3 = "1";
36728
36858
  var SCHEMA_KEY = "skills_index_schema_version";
36729
- var _require4 = createRequire4(import.meta.url);
36859
+ var _require4 = createRequire5(import.meta.url);
36730
36860
  var _Database3 = null;
36731
36861
  function getDatabase3() {
36732
36862
  if (_Database3 === null) {
@@ -37738,8 +37868,8 @@ function createServer4(ctx, initError) {
37738
37868
  }
37739
37869
 
37740
37870
  // ../mcp-server/src/utils/native-probe.ts
37741
- import { createRequire as createRequire5 } from "node:module";
37742
- var PROBE_REQUIRE = createRequire5(import.meta.url);
37871
+ import { createRequire as createRequire6 } from "node:module";
37872
+ var PROBE_REQUIRE = createRequire6(import.meta.url);
37743
37873
  function runtimeModuleVersion() {
37744
37874
  return Number.parseInt(process.versions.modules, 10);
37745
37875
  }
@@ -37855,7 +37985,7 @@ init_loader();
37855
37985
 
37856
37986
  // ../core/dist/world/manager.js
37857
37987
  import * as crypto8 from "node:crypto";
37858
- import { execSync as execSync5, spawnSync as spawnSync4 } from "node:child_process";
37988
+ import { execSync as execSync6, spawnSync as spawnSync4 } from "node:child_process";
37859
37989
  import * as fs49 from "node:fs";
37860
37990
  import * as os29 from "node:os";
37861
37991
  import * as path50 from "node:path";
@@ -38397,7 +38527,7 @@ function extractStderr(err) {
38397
38527
  function carryUncommittedEdits(repos, workspacePath, deps = {}) {
38398
38528
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync6(cmd, args, opts));
38399
38529
  const homedir30 = deps.homedir ?? (() => os26.homedir());
38400
- const existsSync48 = deps.existsSync ?? ((p) => fs43.existsSync(p));
38530
+ const existsSync49 = deps.existsSync ?? ((p) => fs43.existsSync(p));
38401
38531
  const copyFileSync9 = deps.copyFileSync ?? ((src, dest) => fs43.copyFileSync(src, dest));
38402
38532
  const mkdirSync30 = deps.mkdirSync ?? ((dirPath, opts) => {
38403
38533
  fs43.mkdirSync(dirPath, opts);
@@ -38408,9 +38538,9 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
38408
38538
  continue;
38409
38539
  const repoPath = expandHome2(repo.path, homedir30);
38410
38540
  const worktreePath = path43.join(workspacePath, repo.name);
38411
- if (!existsSync48(repoPath))
38541
+ if (!existsSync49(repoPath))
38412
38542
  continue;
38413
- if (!existsSync48(worktreePath)) {
38543
+ if (!existsSync49(worktreePath)) {
38414
38544
  console.warn(`[carry] ${repo.name}: world worktree ${worktreePath} missing; skipping carry for this repo`);
38415
38545
  continue;
38416
38546
  }
@@ -38470,7 +38600,7 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
38470
38600
  for (const rel of plan.diff.untracked) {
38471
38601
  const src = path43.join(plan.repoPath, rel);
38472
38602
  const dest = path43.join(plan.worktreePath, rel);
38473
- if (!existsSync48(src))
38603
+ if (!existsSync49(src))
38474
38604
  continue;
38475
38605
  try {
38476
38606
  mkdirSync30(path43.dirname(dest), { recursive: true });
@@ -39989,6 +40119,54 @@ async function runSeedHooks(seeds, containerName, servicePortMap, exec) {
39989
40119
  }
39990
40120
  }
39991
40121
 
40122
+ // ../core/dist/world/create-dedup.js
40123
+ import { execSync as execSync5 } from "node:child_process";
40124
+ var ACTIVE_STATUSES = /* @__PURE__ */ new Set([
40125
+ "creating",
40126
+ "running",
40127
+ "paused",
40128
+ "crystallizing"
40129
+ ]);
40130
+ var defaultContainerProbe = (containerName) => {
40131
+ try {
40132
+ const out = execSync5(`docker ps --filter name=^/${containerName}$ --format '{{.Names}}'`, { stdio: ["pipe", "pipe", "pipe"], timeout: 5e3 }).toString().trim();
40133
+ return out.length > 0;
40134
+ } catch {
40135
+ return false;
40136
+ }
40137
+ };
40138
+ function resolveCreateDedup(opts) {
40139
+ const { registry: registry2, name } = opts;
40140
+ const probe = opts.probeContainer ?? defaultContainerProbe;
40141
+ const containerName = `olam-${name}-devbox`;
40142
+ const existing = registry2.findByName(name);
40143
+ const active = existing.find((w) => ACTIVE_STATUSES.has(w.status));
40144
+ if (active) {
40145
+ return { action: "reuse", world: active };
40146
+ }
40147
+ const errorRows = existing.filter((w) => w.status === "error");
40148
+ for (const er of errorRows) {
40149
+ registry2.remove(er.id);
40150
+ }
40151
+ if (probe(containerName)) {
40152
+ return {
40153
+ action: "container-orphan",
40154
+ containerName,
40155
+ remediation: `A container '${containerName}' is running on this host but no worlds.db row exists for it. Either destroy the orphan with 'docker rm -f ${containerName}' and re-run, or wait for the reconciler (issue #963) to insert a row.`
40156
+ };
40157
+ }
40158
+ return { action: "fresh", cleanedErrorRows: errorRows.length };
40159
+ }
40160
+ var ContainerOrphanError = class extends Error {
40161
+ containerName;
40162
+ kind = "container-orphan";
40163
+ constructor(message, containerName) {
40164
+ super(message);
40165
+ this.containerName = containerName;
40166
+ this.name = "ContainerOrphanError";
40167
+ }
40168
+ };
40169
+
39992
40170
  // ../core/dist/world/tmux-supervisor.js
39993
40171
  function injectBindAll(start) {
39994
40172
  let result = start;
@@ -40122,7 +40300,7 @@ var BotIdentityError = class extends Error {
40122
40300
  this.name = "BotIdentityError";
40123
40301
  }
40124
40302
  };
40125
- function getTokenScopes(ghToken, _exec = execSync5) {
40303
+ function getTokenScopes(ghToken, _exec = execSync6) {
40126
40304
  try {
40127
40305
  const out = _exec("gh auth status 2>&1", {
40128
40306
  encoding: "utf-8",
@@ -40139,13 +40317,13 @@ function getTokenScopes(ghToken, _exec = execSync5) {
40139
40317
  }
40140
40318
  }
40141
40319
  async function setupContainerGit(containerName, repos, branch) {
40142
- const dockerExec = (cmd) => execSync5(`docker exec ${containerName} sh -c '${cmd.replace(/'/g, "'\\''")}'`, {
40320
+ const dockerExec = (cmd) => execSync6(`docker exec ${containerName} sh -c '${cmd.replace(/'/g, "'\\''")}'`, {
40143
40321
  stdio: "pipe",
40144
40322
  timeout: 6e4
40145
40323
  }).toString();
40146
40324
  let ghToken = "";
40147
40325
  try {
40148
- ghToken = execSync5("gh auth token 2>/dev/null", { encoding: "utf-8", timeout: 5e3 }).trim();
40326
+ ghToken = execSync6("gh auth token 2>/dev/null", { encoding: "utf-8", timeout: 5e3 }).trim();
40149
40327
  } catch {
40150
40328
  }
40151
40329
  const actorName = process.env.OLAM_BOT_NAME ?? "Claude Code (olam)";
@@ -40165,7 +40343,7 @@ async function setupContainerGit(containerName, repos, branch) {
40165
40343
  continue;
40166
40344
  const ownerRepo = ghMatch[1];
40167
40345
  try {
40168
- execSync5(`gh api repos/${ownerRepo} --silent`, {
40346
+ execSync6(`gh api repos/${ownerRepo} --silent`, {
40169
40347
  stdio: "pipe",
40170
40348
  timeout: 5e3,
40171
40349
  env: { ...process.env, GH_TOKEN: ghToken }
@@ -40213,7 +40391,7 @@ ${stderr.split("\n").slice(0, 3).join(" ")}`);
40213
40391
  if (!olamUserPresent) {
40214
40392
  const imageName = (() => {
40215
40393
  try {
40216
- return execSync5(`docker inspect ${containerName} --format '{{.Config.Image}}'`, {
40394
+ return execSync6(`docker inspect ${containerName} --format '{{.Config.Image}}'`, {
40217
40395
  encoding: "utf8",
40218
40396
  timeout: 5e3
40219
40397
  }).trim() || "(unknown)";
@@ -40256,7 +40434,7 @@ ${stderr.split("\n").slice(0, 3).join(" ")}`);
40256
40434
  function makeHostExecFn() {
40257
40435
  return async (cmd) => {
40258
40436
  try {
40259
- const stdout = execSync5(cmd, { encoding: "utf-8", timeout: 5e3 });
40437
+ const stdout = execSync6(cmd, { encoding: "utf-8", timeout: 5e3 });
40260
40438
  return { stdout, stderr: "", exitCode: 0 };
40261
40439
  } catch {
40262
40440
  return { stdout: "", stderr: "", exitCode: 1 };
@@ -40266,7 +40444,7 @@ function makeHostExecFn() {
40266
40444
  function makeContainerExecFn(containerName) {
40267
40445
  return async (cmd) => {
40268
40446
  try {
40269
- const result = execSync5(`docker exec ${containerName} sh -c '${cmd.replace(/'/g, "'\\''")}'`, { stdio: "pipe", timeout: 6e5 });
40447
+ const result = execSync6(`docker exec ${containerName} sh -c '${cmd.replace(/'/g, "'\\''")}'`, { stdio: "pipe", timeout: 6e5 });
40270
40448
  return { stdout: result.toString(), stderr: "", exitCode: 0 };
40271
40449
  } catch (err) {
40272
40450
  const execErr = err;
@@ -40280,7 +40458,7 @@ function makeContainerExecFn(containerName) {
40280
40458
  }
40281
40459
  function defaultDockerExec() {
40282
40460
  return (containerName, cmd) => {
40283
- const result = execSync5(
40461
+ const result = execSync6(
40284
40462
  `docker exec ${containerName} sh -c '${cmd.replace(/'/g, "'\\''")}'`,
40285
40463
  // Phase E E5 raise: 10min was too tight on cold-boot for atlas-core's
40286
40464
  // `rails db:create` chain (Rails 7 boot + initializer load + first
@@ -40480,7 +40658,7 @@ function buildManifestRuntime(worldId, repos) {
40480
40658
  }
40481
40659
  return { worldId, repos: runtimeRepos };
40482
40660
  }
40483
- function exposeWorldOverTailscale(appPortUrls, worldId, registry2, _exec = execSync5) {
40661
+ function exposeWorldOverTailscale(appPortUrls, worldId, registry2, _exec = execSync6) {
40484
40662
  if (process.env["OLAM_TAILSCALE_SERVE"] !== "true")
40485
40663
  return;
40486
40664
  if (appPortUrls.length === 0)
@@ -40508,7 +40686,7 @@ function exposeWorldOverTailscale(appPortUrls, worldId, registry2, _exec = execS
40508
40686
  registry2.storeTailscalePaths(worldId, registeredPaths);
40509
40687
  }
40510
40688
  }
40511
- function cleanupWorldTailscale(worldId, registry2, _exec = execSync5) {
40689
+ function cleanupWorldTailscale(worldId, registry2, _exec = execSync6) {
40512
40690
  const paths = registry2.loadTailscalePaths(worldId);
40513
40691
  if (paths.length === 0)
40514
40692
  return;
@@ -40527,7 +40705,7 @@ function cleanupWorldTailscale(worldId, registry2, _exec = execSync5) {
40527
40705
  }
40528
40706
  }
40529
40707
  }
40530
- function resolveTailscaleBin(_exec = execSync5) {
40708
+ function resolveTailscaleBin(_exec = execSync6) {
40531
40709
  const candidates = [
40532
40710
  process.env["TAILSCALE_BIN"],
40533
40711
  "/Applications/Tailscale.app/Contents/MacOS/Tailscale",
@@ -40552,19 +40730,38 @@ var WorldManager = class {
40552
40730
  dashboardManager;
40553
40731
  pleriClient;
40554
40732
  dockerExec;
40733
+ containerProbe;
40555
40734
  manifestRuntimes = /* @__PURE__ */ new Map();
40556
- constructor(config2, provider, registry2, dashboardManager, pleriClient, dockerExec) {
40735
+ constructor(config2, provider, registry2, dashboardManager, pleriClient, dockerExec, containerProbe) {
40557
40736
  this.config = config2;
40558
40737
  this.provider = provider;
40559
40738
  this.registry = registry2;
40560
40739
  this.dashboardManager = dashboardManager;
40561
40740
  this.pleriClient = pleriClient;
40562
40741
  this.dockerExec = dockerExec ?? defaultDockerExec();
40742
+ this.containerProbe = containerProbe;
40563
40743
  }
40564
40744
  // -----------------------------------------------------------------------
40565
40745
  // createWorld
40566
40746
  // -----------------------------------------------------------------------
40567
40747
  async createWorld(opts) {
40748
+ {
40749
+ const dedupOpts = {
40750
+ registry: this.registry,
40751
+ name: opts.name,
40752
+ ...this.containerProbe ? { probeContainer: this.containerProbe } : {}
40753
+ };
40754
+ const dedup = resolveCreateDedup(dedupOpts);
40755
+ if (dedup.action === "reuse") {
40756
+ return dedup.world;
40757
+ }
40758
+ if (dedup.action === "container-orphan") {
40759
+ throw new ContainerOrphanError(dedup.remediation, dedup.containerName);
40760
+ }
40761
+ if (dedup.cleanedErrorRows > 0) {
40762
+ console.log(`[manager] removed ${dedup.cleanedErrorRows} stale error row(s) for world name "${opts.name}" before fresh create (issue #962)`);
40763
+ }
40764
+ }
40568
40765
  if (!opts.noAuth) {
40569
40766
  const preflight = await runAuthPreflight({ autoStart: true });
40570
40767
  if (preflight.verdict !== "ok") {
@@ -41248,7 +41445,7 @@ ${detail}`);
41248
41445
  const escapedDir = `/home/olam/workspace/${repo.name.replace(/["$`\\]/g, "\\$&")}`;
41249
41446
  for (const cmd of repo.setup_commands) {
41250
41447
  try {
41251
- execSync5(`docker exec ${containerName} sh -c 'cd "${escapedDir}" && ${cmd.replace(/'/g, "'\\''")}'`, { stdio: "pipe", timeout: 6e5 });
41448
+ execSync6(`docker exec ${containerName} sh -c 'cd "${escapedDir}" && ${cmd.replace(/'/g, "'\\''")}'`, { stdio: "pipe", timeout: 6e5 });
41252
41449
  } catch (err) {
41253
41450
  const msg = err instanceof Error ? err.message : String(err);
41254
41451
  console.warn(`[WorldManager] setup command failed for ${repo.name}: ${msg}`);
@@ -41269,11 +41466,11 @@ ${detail}`);
41269
41466
  });
41270
41467
  if (allPolicies.length > 0) {
41271
41468
  try {
41272
- execSync5(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
41469
+ execSync6(`docker exec ${containerName} mkdir -p /home/olam/.olam/policies`, { stdio: "pipe", timeout: 1e4 });
41273
41470
  for (const repo of repos) {
41274
41471
  const policiesDir = path50.join(workspacePath, repo.name, ".olam", "policies");
41275
41472
  if (fs49.existsSync(policiesDir)) {
41276
- execSync5(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
41473
+ execSync6(`docker cp "${policiesDir}/." "${containerName}:/home/olam/.olam/policies/"`, { stdio: "pipe", timeout: 15e3 });
41277
41474
  }
41278
41475
  }
41279
41476
  } catch (err) {
@@ -42779,11 +42976,11 @@ function isDashboardRunning() {
42779
42976
  }
42780
42977
 
42781
42978
  // ../core/dist/dashboard/tunnel.js
42782
- import { spawn as spawn4, execSync as execSync6 } from "node:child_process";
42979
+ import { spawn as spawn4, execSync as execSync7 } from "node:child_process";
42783
42980
  var tunnelProcess = null;
42784
42981
  function isCloudflaredAvailable() {
42785
42982
  try {
42786
- execSync6("which cloudflared", { stdio: "ignore" });
42983
+ execSync7("which cloudflared", { stdio: "ignore" });
42787
42984
  return true;
42788
42985
  } catch {
42789
42986
  return false;
@@ -43041,7 +43238,7 @@ var PleriClient = class {
43041
43238
  };
43042
43239
 
43043
43240
  // ../mcp-server/src/env-loader.ts
43044
- import { readFileSync as readFileSync39, existsSync as existsSync47, statSync as statSync14 } from "node:fs";
43241
+ import { readFileSync as readFileSync39, existsSync as existsSync48, statSync as statSync14 } from "node:fs";
43045
43242
  import { join as join52, dirname as dirname29, resolve as resolve14 } from "node:path";
43046
43243
  var PROJECT_MARKERS = [
43047
43244
  ".olam/config.yaml",
@@ -43054,10 +43251,10 @@ function findProjectRoot2(startDir) {
43054
43251
  const root = resolve14("/");
43055
43252
  while (true) {
43056
43253
  for (const marker of PROJECT_MARKERS) {
43057
- if (existsSync47(join52(dir, marker))) return dir;
43254
+ if (existsSync48(join52(dir, marker))) return dir;
43058
43255
  }
43059
43256
  const pkg = join52(dir, "package.json");
43060
- if (existsSync47(pkg)) {
43257
+ if (existsSync48(pkg)) {
43061
43258
  try {
43062
43259
  const json = JSON.parse(readFileSync39(pkg, "utf8"));
43063
43260
  const isOlamWorkspace = typeof json.name === "string" && json.name.startsWith("@olam/");
@@ -43097,7 +43294,7 @@ function loadProjectEnv(startDir = process.cwd()) {
43097
43294
  const merged = {};
43098
43295
  for (const name of [".env", ".env.local"]) {
43099
43296
  const p = join52(root, name);
43100
- if (existsSync47(p) && statSync14(p).isFile()) {
43297
+ if (existsSync48(p) && statSync14(p).isFile()) {
43101
43298
  Object.assign(merged, parseEnvFile(p));
43102
43299
  filesRead.push(p);
43103
43300
  }
@@ -1,4 +1,4 @@
1
1
  {
2
- "bundledAt": "2026-05-24T11:22:38.644Z",
2
+ "bundledAt": "2026-05-24T13:03:21.307Z",
3
3
  "kgFirstSha": "29a9ccce1b115d049e375c4a90eb5cf7c123e610e2d0590270a4db2cdbc64a28"
4
4
  }
@@ -118,7 +118,7 @@ spec:
118
118
  # k3d), started by `olam upgrade` Step 0.7 — not inside this Pod.
119
119
  containers:
120
120
  - name: olam-host-cp
121
- image: ghcr.io/pleri/olam-host-cp@sha256:3043df80469fa58319de53688991c81575522beba48b7a1b6956d0e3f2d03b45
121
+ image: ghcr.io/pleri/olam-host-cp@sha256:71e376df97d498e76c51f35698464b26413bcfe4efe926b85e12248422ae1a54
122
122
  imagePullPolicy: IfNotPresent
123
123
  securityContext:
124
124
  runAsNonRoot: true
@@ -70,7 +70,7 @@ spec:
70
70
  mountPath: /data
71
71
  containers:
72
72
  - name: olam-auth-service
73
- image: ghcr.io/pleri/olam-auth@sha256:2e40e0c1f0469331dfa98a2e194c922c710149d8d5d3816bc660e530be6a9b97
73
+ image: ghcr.io/pleri/olam-auth@sha256:fe6e1ff20ee99aa2ce74e144d33ebf07411855fc2080ec046ee8a82a6144fb54
74
74
  imagePullPolicy: IfNotPresent
75
75
  securityContext:
76
76
  runAsNonRoot: true
@@ -61,7 +61,7 @@ spec:
61
61
  mountPath: /data
62
62
  containers:
63
63
  - name: olam-kg-service
64
- image: ghcr.io/pleri/olam-kg-service@sha256:225dd3460bce1f2572e6076e55a875ff526a5217a2d8f311d14b6dee591e8a38
64
+ image: ghcr.io/pleri/olam-kg-service@sha256:0300a3140a25510703df52ebeae8a1783e620b93aae7115ef0b3577208eb9b1f
65
65
  imagePullPolicy: IfNotPresent
66
66
  securityContext:
67
67
  runAsNonRoot: true
@@ -68,7 +68,7 @@ spec:
68
68
  mountPath: /data
69
69
  containers:
70
70
  - name: olam-mcp-auth-service
71
- image: ghcr.io/pleri/olam-mcp-auth@sha256:f61bf653ada702d59aca0a309b224b01e0f151a89e01583a76f94d8604101d20
71
+ image: ghcr.io/pleri/olam-mcp-auth@sha256:2a442b17f372eb60b2e1444bb16092157df10ad76b4e87cf6cc8975d386e5be4
72
72
  imagePullPolicy: IfNotPresent
73
73
  securityContext:
74
74
  runAsNonRoot: true
@@ -70,7 +70,7 @@ spec:
70
70
  # bootstrap-placeholder comment + run `npm run refresh:manifest-digests`
71
71
  # once ghcr.io/pleri/olam-memory-service has a real published digest.
72
72
  # bootstrap-placeholder: pre-publish; refresh after first release
73
- image: ghcr.io/pleri/olam-memory-service@sha256:86ce43a8bfec3edf0a9ac1aea63bf3ecd922209a7ab2a0f589ae9e1cedc0134a
73
+ image: ghcr.io/pleri/olam-memory-service@sha256:320298284431afbeebc947a55701f486bc1df0d5642817f68a61147056da9056
74
74
  imagePullPolicy: IfNotPresent
75
75
  securityContext:
76
76
  runAsNonRoot: true