@pleri/olam-cli 0.1.175 → 0.1.180

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 (41) hide show
  1. package/README.md +19 -0
  2. package/bin/olam.cjs +22 -0
  3. package/dist/commands/flywheel/index.d.ts.map +1 -1
  4. package/dist/commands/flywheel/index.js +4 -0
  5. package/dist/commands/flywheel/index.js.map +1 -1
  6. package/dist/commands/flywheel/install-sessionstart-hook.d.ts +64 -0
  7. package/dist/commands/flywheel/install-sessionstart-hook.d.ts.map +1 -0
  8. package/dist/commands/flywheel/install-sessionstart-hook.js +197 -0
  9. package/dist/commands/flywheel/install-sessionstart-hook.js.map +1 -0
  10. package/dist/commands/flywheel/session-start.d.ts +26 -0
  11. package/dist/commands/flywheel/session-start.d.ts.map +1 -0
  12. package/dist/commands/flywheel/session-start.js +119 -0
  13. package/dist/commands/flywheel/session-start.js.map +1 -0
  14. package/dist/commands/host-cp.d.ts +0 -3
  15. package/dist/commands/host-cp.d.ts.map +1 -1
  16. package/dist/commands/host-cp.js +27 -2
  17. package/dist/commands/host-cp.js.map +1 -1
  18. package/dist/commands/yolo.d.ts +99 -0
  19. package/dist/commands/yolo.d.ts.map +1 -0
  20. package/dist/commands/yolo.js +377 -0
  21. package/dist/commands/yolo.js.map +1 -0
  22. package/dist/image-digests.json +8 -8
  23. package/dist/index.js +808 -207
  24. package/dist/index.js.map +1 -1
  25. package/dist/lib/auth-remote.d.ts +0 -17
  26. package/dist/lib/auth-remote.d.ts.map +1 -1
  27. package/dist/lib/auth-remote.js +6 -16
  28. package/dist/lib/auth-remote.js.map +1 -1
  29. package/dist/mcp-server.js +26 -0
  30. package/hermes-bundle/version.json +1 -1
  31. package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
  32. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  33. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  34. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  35. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  36. package/host-cp/src/bootstrap-selective.mjs +56 -0
  37. package/host-cp/src/plan-chat-service.mjs +51 -0
  38. package/host-cp/src/redirect.mjs +152 -0
  39. package/host-cp/src/resolver.mjs +121 -0
  40. package/host-cp/src/server.mjs +57 -16
  41. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -492,8 +492,8 @@ var init_parseUtil = __esm({
492
492
  init_errors();
493
493
  init_en();
494
494
  makeIssue = (params) => {
495
- const { data, path: path96, errorMaps, issueData } = params;
496
- const fullPath = [...path96, ...issueData.path || []];
495
+ const { data, path: path97, errorMaps, issueData } = params;
496
+ const fullPath = [...path97, ...issueData.path || []];
497
497
  const fullIssue = {
498
498
  ...issueData,
499
499
  path: fullPath
@@ -801,11 +801,11 @@ var init_types = __esm({
801
801
  init_parseUtil();
802
802
  init_util();
803
803
  ParseInputLazyPath = class {
804
- constructor(parent, value, path96, key) {
804
+ constructor(parent, value, path97, key) {
805
805
  this._cachedPath = [];
806
806
  this.parent = parent;
807
807
  this.data = value;
808
- this._path = path96;
808
+ this._path = path97;
809
809
  this._key = key;
810
810
  }
811
811
  get path() {
@@ -4286,7 +4286,7 @@ import YAML from "yaml";
4286
4286
  function bootstrapStepCmd(entry) {
4287
4287
  return typeof entry === "string" ? entry : entry.cmd;
4288
4288
  }
4289
- function refineForbiddenKeys(value, path96, ctx, rejectSource) {
4289
+ function refineForbiddenKeys(value, path97, ctx, rejectSource) {
4290
4290
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
4291
4291
  return;
4292
4292
  }
@@ -4294,12 +4294,12 @@ function refineForbiddenKeys(value, path96, ctx, rejectSource) {
4294
4294
  if (FORBIDDEN_KEYS.has(key)) {
4295
4295
  ctx.addIssue({
4296
4296
  code: external_exports.ZodIssueCode.custom,
4297
- path: [...path96, key],
4297
+ path: [...path97, key],
4298
4298
  message: `forbidden key "${key}" (prototype-pollution surface)`
4299
4299
  });
4300
4300
  continue;
4301
4301
  }
4302
- if (rejectSource && path96.length === 0 && key === "source") {
4302
+ if (rejectSource && path97.length === 0 && key === "source") {
4303
4303
  ctx.addIssue({
4304
4304
  code: external_exports.ZodIssueCode.custom,
4305
4305
  path: ["source"],
@@ -4307,21 +4307,21 @@ function refineForbiddenKeys(value, path96, ctx, rejectSource) {
4307
4307
  });
4308
4308
  continue;
4309
4309
  }
4310
- refineForbiddenKeys(value[key], [...path96, key], ctx, false);
4310
+ refineForbiddenKeys(value[key], [...path97, key], ctx, false);
4311
4311
  }
4312
4312
  }
4313
- function rejectForbiddenKeys(value, path96, rejectSource) {
4313
+ function rejectForbiddenKeys(value, path97, rejectSource) {
4314
4314
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
4315
4315
  return;
4316
4316
  }
4317
4317
  for (const key of Object.keys(value)) {
4318
4318
  if (FORBIDDEN_KEYS.has(key)) {
4319
- throw new Error(`[manifest] ${path96}: forbidden key "${key}" (prototype-pollution surface)`);
4319
+ throw new Error(`[manifest] ${path97}: forbidden key "${key}" (prototype-pollution surface)`);
4320
4320
  }
4321
4321
  if (rejectSource && key === "source") {
4322
- throw new Error(`[manifest] ${path96}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4322
+ throw new Error(`[manifest] ${path97}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
4323
4323
  }
4324
- rejectForbiddenKeys(value[key], `${path96}.${key}`, false);
4324
+ rejectForbiddenKeys(value[key], `${path97}.${key}`, false);
4325
4325
  }
4326
4326
  }
4327
4327
  function unknownTopLevelKeys(parsed) {
@@ -5515,8 +5515,8 @@ var init_client = __esm({
5515
5515
  throw new Error(`failed to report rate-limit for ${accountId} (HTTP ${res.status})`);
5516
5516
  }
5517
5517
  }
5518
- async request(method, path96, body, attempt = 0) {
5519
- const url2 = `${this.baseUrl}${path96}`;
5518
+ async request(method, path97, body, attempt = 0) {
5519
+ const url2 = `${this.baseUrl}${path97}`;
5520
5520
  const controller = new AbortController();
5521
5521
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
5522
5522
  const headers = {};
@@ -5534,7 +5534,7 @@ var init_client = __esm({
5534
5534
  } catch (err) {
5535
5535
  if (attempt < RETRY_COUNT && isTransient(err)) {
5536
5536
  await sleep(RETRY_BACKOFF_MS * (attempt + 1));
5537
- return this.request(method, path96, body, attempt + 1);
5537
+ return this.request(method, path97, body, attempt + 1);
5538
5538
  }
5539
5539
  throw err;
5540
5540
  } finally {
@@ -5977,6 +5977,22 @@ function readAuthSecret() {
5977
5977
  return "";
5978
5978
  }
5979
5979
  }
5980
+ function readAnthropicBaseUrl() {
5981
+ const fromOlamEnv = process.env["OLAM_ANTHROPIC_BASE_URL"];
5982
+ if (fromOlamEnv && fromOlamEnv.length > 0)
5983
+ return fromOlamEnv.trim();
5984
+ const file = path11.join(os6.homedir(), ".olam", "anthropic-base-url");
5985
+ try {
5986
+ const content = fs10.readFileSync(file, "utf-8").trim();
5987
+ if (content.length > 0)
5988
+ return content;
5989
+ } catch {
5990
+ }
5991
+ const fromShellEnv = process.env["ANTHROPIC_BASE_URL"];
5992
+ if (fromShellEnv && fromShellEnv.length > 0)
5993
+ return fromShellEnv.trim();
5994
+ return "";
5995
+ }
5980
5996
  function readHostCpToken() {
5981
5997
  const fromEnv = process.env["OLAM_HOST_CP_TOKEN"];
5982
5998
  if (fromEnv && fromEnv.length > 0)
@@ -6196,6 +6212,7 @@ var init_container2 = __esm({
6196
6212
  const labels = olamLabels(worldId, worldName);
6197
6213
  const authSecret = readAuthSecret();
6198
6214
  const hostCpToken = readHostCpToken();
6215
+ const anthropicBaseUrl = readAnthropicBaseUrl();
6199
6216
  const memoryEnv = resolveMemoryEnv();
6200
6217
  const worldEnv = {
6201
6218
  OLAM_WORLD_ID: worldId,
@@ -6219,6 +6236,15 @@ var init_container2 = __esm({
6219
6236
  ...isKubernetesServiceSubstrate() ? { OLAM_KG_SERVICE_URL: TRAEFIK_INGRESS_KG_URL } : {},
6220
6237
  ...authSecret ? { OLAM_AUTH_SECRET: authSecret } : {},
6221
6238
  ...hostCpToken ? { OLAM_HOST_CP_TOKEN: hostCpToken } : {},
6239
+ // Cloud-mode Anthropic proxy: when an auth-worker bearer URL is configured
6240
+ // (~/.olam/anthropic-base-url file OR OLAM_ANTHROPIC_BASE_URL env), every
6241
+ // outbound Claude call from inside the world is routed through it via
6242
+ // URL-userinfo Basic auth. The container's Claude Code + Anthropic SDK
6243
+ // respect ANTHROPIC_BASE_URL natively; no per-caller change required.
6244
+ // When unset, the in-world fetch-creds.mjs helper still pulls from the
6245
+ // local OLAM_AUTH_SERVICE_URL (host.docker.internal:9999) — zero
6246
+ // regression for existing local-mode operators.
6247
+ ...anthropicBaseUrl ? { ANTHROPIC_BASE_URL: anthropicBaseUrl } : {},
6222
6248
  // Phase B1 + C4 — agent-memory wiring. URL + secret resolved together
6223
6249
  // by resolveMemoryEnv() above:
6224
6250
  // - local mode (or no config): URL = host.docker.internal:3111,
@@ -7337,8 +7363,8 @@ var init_provider3 = __esm({
7337
7363
  // -----------------------------------------------------------------------
7338
7364
  // Internal fetch helper
7339
7365
  // -----------------------------------------------------------------------
7340
- async request(path96, method, body) {
7341
- const url2 = `${this.config.workerUrl}${path96}`;
7366
+ async request(path97, method, body) {
7367
+ const url2 = `${this.config.workerUrl}${path97}`;
7342
7368
  const bearer = await this.config.mintToken();
7343
7369
  const headers = {
7344
7370
  Authorization: `Bearer ${bearer}`
@@ -9202,17 +9228,17 @@ function kgRoot() {
9202
9228
  function worldsRoot() {
9203
9229
  return join17(olamHome(), "worlds");
9204
9230
  }
9205
- function assertWithinPrefix(path96, prefix, label) {
9206
- if (!path96.startsWith(prefix + "/")) {
9207
- throw new Error(`${label} escape: ${path96} not under ${prefix}/`);
9231
+ function assertWithinPrefix(path97, prefix, label) {
9232
+ if (!path97.startsWith(prefix + "/")) {
9233
+ throw new Error(`${label} escape: ${path97} not under ${prefix}/`);
9208
9234
  }
9209
9235
  }
9210
9236
  function kgPristinePath(workspace) {
9211
9237
  validateWorkspaceName(workspace);
9212
9238
  const root = kgRoot();
9213
- const path96 = resolve6(join17(root, workspace));
9214
- assertWithinPrefix(path96, root, "kgPristinePath");
9215
- return path96;
9239
+ const path97 = resolve6(join17(root, workspace));
9240
+ assertWithinPrefix(path97, root, "kgPristinePath");
9241
+ return path97;
9216
9242
  }
9217
9243
  var KG_PATHS_INTERNALS;
9218
9244
  var init_storage_paths = __esm({
@@ -9327,8 +9353,8 @@ import { execFileSync as execFileSync4 } from "node:child_process";
9327
9353
  import * as fs15 from "node:fs";
9328
9354
  import * as os9 from "node:os";
9329
9355
  import * as path17 from "node:path";
9330
- function expandHome2(p, homedir64) {
9331
- return p.replace(/^~(?=$|\/|\\)/, homedir64());
9356
+ function expandHome2(p, homedir67) {
9357
+ return p.replace(/^~(?=$|\/|\\)/, homedir67());
9332
9358
  }
9333
9359
  function sanitizeRepoFilename(name) {
9334
9360
  const sanitized = name.replace(/[^A-Za-z0-9._-]/g, "_");
@@ -9351,7 +9377,7 @@ ${stderr}`;
9351
9377
  }
9352
9378
  function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
9353
9379
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
9354
- const homedir64 = deps.homedir ?? (() => os9.homedir());
9380
+ const homedir67 = deps.homedir ?? (() => os9.homedir());
9355
9381
  const baselineDir = path17.join(workspacePath, ".olam", "baseline");
9356
9382
  try {
9357
9383
  fs15.mkdirSync(baselineDir, { recursive: true });
@@ -9367,7 +9393,7 @@ function snapshotBaselineDiff(repos, workspacePath, deps = {}) {
9367
9393
  continue;
9368
9394
  const filename = `${sanitizeRepoFilename(repo.name)}.diff`;
9369
9395
  const outPath = path17.join(baselineDir, filename);
9370
- const repoPath = expandHome2(repo.path, homedir64);
9396
+ const repoPath = expandHome2(repo.path, homedir67);
9371
9397
  if (!fs15.existsSync(repoPath)) {
9372
9398
  writeBaselineFile(outPath, `# repo: ${repo.name}
9373
9399
  # (skipped: path ${repoPath} does not exist)
@@ -9487,21 +9513,21 @@ function extractStderr(err) {
9487
9513
  }
9488
9514
  function carryUncommittedEdits(repos, workspacePath, deps = {}) {
9489
9515
  const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
9490
- const homedir64 = deps.homedir ?? (() => os9.homedir());
9491
- const existsSync113 = deps.existsSync ?? ((p) => fs15.existsSync(p));
9492
- const copyFileSync16 = deps.copyFileSync ?? ((src, dest) => fs15.copyFileSync(src, dest));
9493
- const mkdirSync67 = deps.mkdirSync ?? ((dirPath, opts) => {
9516
+ const homedir67 = deps.homedir ?? (() => os9.homedir());
9517
+ const existsSync115 = deps.existsSync ?? ((p) => fs15.existsSync(p));
9518
+ const copyFileSync17 = deps.copyFileSync ?? ((src, dest) => fs15.copyFileSync(src, dest));
9519
+ const mkdirSync68 = deps.mkdirSync ?? ((dirPath, opts) => {
9494
9520
  fs15.mkdirSync(dirPath, opts);
9495
9521
  });
9496
9522
  const plans = [];
9497
9523
  for (const repo of repos) {
9498
9524
  if (!repo.path)
9499
9525
  continue;
9500
- const repoPath = expandHome2(repo.path, homedir64);
9526
+ const repoPath = expandHome2(repo.path, homedir67);
9501
9527
  const worktreePath = path17.join(workspacePath, repo.name);
9502
- if (!existsSync113(repoPath))
9528
+ if (!existsSync115(repoPath))
9503
9529
  continue;
9504
- if (!existsSync113(worktreePath)) {
9530
+ if (!existsSync115(worktreePath)) {
9505
9531
  console.warn(`[carry] ${repo.name}: world worktree ${worktreePath} missing; skipping carry for this repo`);
9506
9532
  continue;
9507
9533
  }
@@ -9561,11 +9587,11 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
9561
9587
  for (const rel of plan.diff.untracked) {
9562
9588
  const src = path17.join(plan.repoPath, rel);
9563
9589
  const dest = path17.join(plan.worktreePath, rel);
9564
- if (!existsSync113(src))
9590
+ if (!existsSync115(src))
9565
9591
  continue;
9566
9592
  try {
9567
- mkdirSync67(path17.dirname(dest), { recursive: true });
9568
- copyFileSync16(src, dest);
9593
+ mkdirSync68(path17.dirname(dest), { recursive: true });
9594
+ copyFileSync17(src, dest);
9569
9595
  } catch (err) {
9570
9596
  const msg = err instanceof Error ? err.message : String(err);
9571
9597
  console.warn(`[carry] ${plan.name}: copy untracked ${rel} failed: ${msg}`);
@@ -15485,7 +15511,20 @@ function removePid() {
15485
15511
  }
15486
15512
  async function findHostCpContainer() {
15487
15513
  const docker3 = new Dockerode2(resolveDockerHostOptions());
15488
- const containers = await docker3.listContainers({ all: true });
15514
+ let timer = null;
15515
+ const listing = docker3.listContainers({ all: true }).then((cs) => cs);
15516
+ const timeout = new Promise((resolve27) => {
15517
+ timer = setTimeout(() => resolve27(null), DOCKER_PROBE_TIMEOUT_MS);
15518
+ });
15519
+ let containers;
15520
+ try {
15521
+ containers = await Promise.race([listing, timeout]);
15522
+ } catch {
15523
+ containers = null;
15524
+ } finally {
15525
+ if (timer !== null) clearTimeout(timer);
15526
+ }
15527
+ if (containers === null) return null;
15489
15528
  for (const c of containers) {
15490
15529
  const names = (c.Names ?? []).map((n) => n.replace(/^\//, ""));
15491
15530
  if (names.includes("olam-host-cp")) {
@@ -15859,10 +15898,10 @@ async function readHostCpToken2() {
15859
15898
  if (!fs26.existsSync(tp)) return null;
15860
15899
  return fs26.readFileSync(tp, "utf-8").trim();
15861
15900
  }
15862
- async function callHostCpProxy(method, worldId, path96, body) {
15901
+ async function callHostCpProxy(method, worldId, path97, body) {
15863
15902
  const token = await readHostCpToken2();
15864
15903
  if (!token) return { ok: false, status: 0, error: "no token (host CP not started)" };
15865
- const url2 = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path96}`;
15904
+ const url2 = `http://127.0.0.1:${HOST_CP_PORT}/api/world/${encodeURIComponent(worldId)}${path97}`;
15866
15905
  try {
15867
15906
  const headers = {
15868
15907
  Authorization: `Bearer ${token}`
@@ -15966,7 +16005,7 @@ async function handleDeregister(opts) {
15966
16005
  }
15967
16006
  printSuccess(`Deregistered ${opts.world}`);
15968
16007
  }
15969
- var HOST_CP_PORT, SIDECAR_PULL_SERVICE;
16008
+ var HOST_CP_PORT, DOCKER_PROBE_TIMEOUT_MS, SIDECAR_PULL_SERVICE;
15970
16009
  var init_host_cp = __esm({
15971
16010
  "src/commands/host-cp.ts"() {
15972
16011
  "use strict";
@@ -15977,6 +16016,7 @@ var init_host_cp = __esm({
15977
16016
  init_cli_version();
15978
16017
  init_open_url();
15979
16018
  HOST_CP_PORT = 19e3;
16019
+ DOCKER_PROBE_TIMEOUT_MS = 2e3;
15980
16020
  SIDECAR_PULL_SERVICE = "docker-socket-proxy";
15981
16021
  }
15982
16022
  });
@@ -16337,31 +16377,31 @@ __export(from_manifest_exports, {
16337
16377
  provenanceLine: () => provenanceLine
16338
16378
  });
16339
16379
  import { readFileSync as readFileSync30 } from "node:fs";
16340
- function parseForkManifest(path96) {
16380
+ function parseForkManifest(path97) {
16341
16381
  let raw;
16342
16382
  try {
16343
- raw = readFileSync30(path96, "utf8");
16383
+ raw = readFileSync30(path97, "utf8");
16344
16384
  } catch (err) {
16345
16385
  const reason = err?.code === "ENOENT" ? "file does not exist" : err.message;
16346
- throw new Error(`--from-manifest: cannot read ${path96} (${reason})`);
16386
+ throw new Error(`--from-manifest: cannot read ${path97} (${reason})`);
16347
16387
  }
16348
16388
  let json;
16349
16389
  try {
16350
16390
  json = JSON.parse(raw);
16351
16391
  } catch (err) {
16352
- throw new Error(`--from-manifest: ${path96} is not valid JSON (${err.message})`);
16392
+ throw new Error(`--from-manifest: ${path97} is not valid JSON (${err.message})`);
16353
16393
  }
16354
16394
  if (!isPlainObject2(json)) {
16355
- throw new Error(`--from-manifest: ${path96} root must be a JSON object`);
16395
+ throw new Error(`--from-manifest: ${path97} root must be a JSON object`);
16356
16396
  }
16357
16397
  const originalWorldId = json.originalWorldId;
16358
16398
  if (typeof originalWorldId !== "string" || originalWorldId.trim().length === 0) {
16359
- throw new Error(`--from-manifest: ${path96} missing required string "originalWorldId"`);
16399
+ throw new Error(`--from-manifest: ${path97} missing required string "originalWorldId"`);
16360
16400
  }
16361
16401
  const newPrompt = json.newPrompt;
16362
16402
  if (typeof newPrompt !== "string" || newPrompt.trim().length === 0) {
16363
16403
  throw new Error(
16364
- `--from-manifest: ${path96} has no "newPrompt" \u2014 re-run trace-replay with --with-prompt "<alternate dispatch>"`
16404
+ `--from-manifest: ${path97} has no "newPrompt" \u2014 re-run trace-replay with --with-prompt "<alternate dispatch>"`
16365
16405
  );
16366
16406
  }
16367
16407
  const fp = isPlainObject2(json.forkPoint) ? json.forkPoint : {};
@@ -16372,7 +16412,7 @@ function parseForkManifest(path96) {
16372
16412
  originalWorldId: originalWorldId.trim(),
16373
16413
  forkPoint: { resolvedPhase, resolvedSpanId, resolvedAt },
16374
16414
  newPrompt,
16375
- manifestPath: path96
16415
+ manifestPath: path97
16376
16416
  };
16377
16417
  }
16378
16418
  function defaultNameFromManifest(manifest) {
@@ -17498,8 +17538,8 @@ var init_artifact_resolver = __esm({
17498
17538
  });
17499
17539
 
17500
17540
  // ../core/dist/lib/shim-targets.js
17501
- function lookupShimTarget(basename16) {
17502
- return SHIM_TARGETS.find((t) => t.basename === basename16);
17541
+ function lookupShimTarget(basename17) {
17542
+ return SHIM_TARGETS.find((t) => t.basename === basename17);
17503
17543
  }
17504
17544
  function compareSemver(installed, required) {
17505
17545
  const norm = (s) => {
@@ -17518,8 +17558,8 @@ function compareSemver(installed, required) {
17518
17558
  }
17519
17559
  return 0;
17520
17560
  }
17521
- function checkShimRemoval(basename16, installedOlamVersion) {
17522
- const target = lookupShimTarget(basename16);
17561
+ function checkShimRemoval(basename17, installedOlamVersion) {
17562
+ const target = lookupShimTarget(basename17);
17523
17563
  if (target === void 0)
17524
17564
  return null;
17525
17565
  return {
@@ -17600,11 +17640,11 @@ function detectCollisions(artifacts) {
17600
17640
  }
17601
17641
  const collisions = [];
17602
17642
  for (const [key, loserList] of losersByKey.entries()) {
17603
- const [bucket, basename16] = key.split("\0");
17643
+ const [bucket, basename17] = key.split("\0");
17604
17644
  const winner = seen.get(key);
17605
17645
  collisions.push({
17606
17646
  bucket,
17607
- basename: basename16,
17647
+ basename: basename17,
17608
17648
  winnerSourceId: winner.sourceId,
17609
17649
  winnerSourcePath: winner.sourcePath,
17610
17650
  loserSourceIds: loserList.map((l) => l.sourceId),
@@ -17649,8 +17689,8 @@ function cleanManagedSymlinks(claude, installedOlamVersion, overlayReferences, e
17649
17689
  } else if (bucket === "agents" && stat.isFile() && !name.includes(".shadow-backup-")) {
17650
17690
  const hasWinner = expectedAgentWinnerNames !== void 0 ? expectedAgentWinnerNames.has(name) : true;
17651
17691
  if (hasWinner) {
17652
- const backup3 = shadowBackup(p);
17653
- shadowBackups.push(backup3);
17692
+ const backup4 = shadowBackup(p);
17693
+ shadowBackups.push(backup4);
17654
17694
  }
17655
17695
  }
17656
17696
  } catch {
@@ -17661,9 +17701,9 @@ function cleanManagedSymlinks(claude, installedOlamVersion, overlayReferences, e
17661
17701
  }
17662
17702
  function shadowBackup(link) {
17663
17703
  const epoch = Math.floor(Date.now() / 1e3);
17664
- const backup3 = `${link}.shadow-backup-${epoch}`;
17665
- fs59.renameSync(link, backup3);
17666
- return backup3;
17704
+ const backup4 = `${link}.shadow-backup-${epoch}`;
17705
+ fs59.renameSync(link, backup4);
17706
+ return backup4;
17667
17707
  }
17668
17708
  function linkIfNeeded(target, link) {
17669
17709
  try {
@@ -17677,14 +17717,14 @@ function linkIfNeeded(target, link) {
17677
17717
  isLink = fs59.lstatSync(link).isSymbolicLink();
17678
17718
  } catch {
17679
17719
  }
17680
- let backup3;
17720
+ let backup4;
17681
17721
  if (isLink) {
17682
17722
  fs59.unlinkSync(link);
17683
17723
  } else if (fs59.existsSync(link)) {
17684
- backup3 = shadowBackup(link);
17724
+ backup4 = shadowBackup(link);
17685
17725
  }
17686
17726
  fs59.symlinkSync(target, link);
17687
- return { created: true, shadowBackup: backup3 };
17727
+ return { created: true, shadowBackup: backup4 };
17688
17728
  }
17689
17729
  function deployArtifacts(artifacts, opts) {
17690
17730
  const claude = claudeDir();
@@ -17707,11 +17747,11 @@ function deployArtifacts(artifacts, opts) {
17707
17747
  result.linked += 1;
17708
17748
  continue;
17709
17749
  }
17710
- const { created, shadowBackup: backup3 } = linkIfNeeded(artifact.sourcePath, linkPath);
17750
+ const { created, shadowBackup: backup4 } = linkIfNeeded(artifact.sourcePath, linkPath);
17711
17751
  if (created)
17712
17752
  result.linked += 1;
17713
- if (backup3)
17714
- result.shadowBackups.push(backup3);
17753
+ if (backup4)
17754
+ result.shadowBackups.push(backup4);
17715
17755
  }
17716
17756
  return result;
17717
17757
  }
@@ -18421,11 +18461,11 @@ function scanOverlayReferences(overlayRoot, basenames, caps = DEFAULT_CAPS) {
18421
18461
  throw err;
18422
18462
  }
18423
18463
  const relpath = path65.relative(overlayRoot, filepath).split(path65.sep).join("/");
18424
- for (const basename16 of basenames) {
18425
- if (content.includes(basename16)) {
18426
- const list = result.get(basename16) ?? [];
18464
+ for (const basename17 of basenames) {
18465
+ if (content.includes(basename17)) {
18466
+ const list = result.get(basename17) ?? [];
18427
18467
  list.push(relpath);
18428
- result.set(basename16, list);
18468
+ result.set(basename17, list);
18429
18469
  }
18430
18470
  }
18431
18471
  }
@@ -19338,12 +19378,12 @@ function sourceConfigPath(clonePath) {
19338
19378
  return join76(clonePath, "shared", "source-config.yaml");
19339
19379
  }
19340
19380
  function readSourceConfig(clonePath, sourceId) {
19341
- const path96 = sourceConfigPath(clonePath);
19342
- if (!existsSync77(path96))
19381
+ const path97 = sourceConfigPath(clonePath);
19382
+ if (!existsSync77(path97))
19343
19383
  return void 0;
19344
19384
  let raw;
19345
19385
  try {
19346
- raw = readFileSync67(path96, "utf-8");
19386
+ raw = readFileSync67(path97, "utf-8");
19347
19387
  } catch (err) {
19348
19388
  emitMalformedWarning(sourceId, `read failed: ${errToMsg(err)}`);
19349
19389
  return void 0;
@@ -19882,12 +19922,12 @@ function restoreShadowBackup(opts) {
19882
19922
  if (!fs71.existsSync(abs)) {
19883
19923
  throw new Error(`backup file not found: ${abs}`);
19884
19924
  }
19885
- const basename16 = path71.basename(abs);
19886
- const match2 = SHADOW_BACKUP_SUFFIX_RE.exec(basename16);
19925
+ const basename17 = path71.basename(abs);
19926
+ const match2 = SHADOW_BACKUP_SUFFIX_RE.exec(basename17);
19887
19927
  if (!match2) {
19888
- throw new Error(`not a shadow-backup file (basename "${basename16}" does not match \`.shadow-backup-<epoch>\`): ${abs}`);
19928
+ throw new Error(`not a shadow-backup file (basename "${basename17}" does not match \`.shadow-backup-<epoch>\`): ${abs}`);
19889
19929
  }
19890
- const originalBasename = basename16.slice(0, basename16.length - match2[0].length);
19930
+ const originalBasename = basename17.slice(0, basename17.length - match2[0].length);
19891
19931
  const originalPath = path71.join(path71.dirname(abs), originalBasename);
19892
19932
  if (fs71.existsSync(originalPath) && !opts.force) {
19893
19933
  throw new Error(`original path already occupied: ${originalPath}. Move/rename it first OR re-run with --force.`);
@@ -20507,11 +20547,11 @@ __export(project_sweep_exports, {
20507
20547
  });
20508
20548
  import * as path74 from "node:path";
20509
20549
  import { readdirSync as readdirSync25, lstatSync as lstatSync6, statSync as statSync25, existsSync as existsSync82 } from "node:fs";
20510
- function isSkipped(basename16, extra) {
20511
- if (DEFAULT_SKIP.has(basename16))
20550
+ function isSkipped(basename17, extra) {
20551
+ if (DEFAULT_SKIP.has(basename17))
20512
20552
  return true;
20513
20553
  for (const pattern of extra) {
20514
- if (basename16 === pattern)
20554
+ if (basename17 === pattern)
20515
20555
  return true;
20516
20556
  }
20517
20557
  return false;
@@ -20936,16 +20976,16 @@ function isValidConfig(value) {
20936
20976
  if (typeof v.install_id !== "string" || v.install_id.length === 0) return false;
20937
20977
  return true;
20938
20978
  }
20939
- function atomicWriteJSON(path96, value, stderr = process.stderr) {
20979
+ function atomicWriteJSON(path97, value, stderr = process.stderr) {
20940
20980
  ensureStateDir();
20941
- const dir = dirname3(path96);
20981
+ const dir = dirname3(path97);
20942
20982
  if (!existsSync6(dir)) {
20943
20983
  mkdirSync2(dir, { recursive: true });
20944
20984
  }
20945
- const tmp = `${path96}.tmp.${process.pid}`;
20985
+ const tmp = `${path97}.tmp.${process.pid}`;
20946
20986
  try {
20947
20987
  writeFileSync2(tmp, JSON.stringify(value, null, 2) + "\n", { encoding: "utf8" });
20948
- renameSync2(tmp, path96);
20988
+ renameSync2(tmp, path97);
20949
20989
  } catch (err) {
20950
20990
  if (existsSync6(tmp)) {
20951
20991
  try {
@@ -21306,9 +21346,9 @@ var UnknownArchetypeError = class extends Error {
21306
21346
  };
21307
21347
  var ArchetypeCycleError = class extends Error {
21308
21348
  path;
21309
- constructor(path96) {
21310
- super(`Archetype inheritance cycle detected: ${path96.join(" \u2192 ")} \u2192 ${path96[0] ?? "?"}`);
21311
- this.path = path96;
21349
+ constructor(path97) {
21350
+ super(`Archetype inheritance cycle detected: ${path97.join(" \u2192 ")} \u2192 ${path97[0] ?? "?"}`);
21351
+ this.path = path97;
21312
21352
  this.name = "ArchetypeCycleError";
21313
21353
  }
21314
21354
  };
@@ -22107,14 +22147,14 @@ function ensureSecrets() {
22107
22147
  step("1/6 \u2014 operator secrets");
22108
22148
  mkdirSync19(OLAM_HOME3, { recursive: true });
22109
22149
  for (const name of SECRET_FILES) {
22110
- const path96 = join34(OLAM_HOME3, name);
22111
- if (existsSync29(path96)) {
22150
+ const path97 = join34(OLAM_HOME3, name);
22151
+ if (existsSync29(path97)) {
22112
22152
  printInfo("skip", `~/.olam/${name} already exists`);
22113
22153
  continue;
22114
22154
  }
22115
22155
  const hex = randomBytes7(32).toString("hex");
22116
- writeFileSync15(path96, hex + "\n", { encoding: "utf8", mode: 384 });
22117
- chmodSync4(path96, 384);
22156
+ writeFileSync15(path97, hex + "\n", { encoding: "utf8", mode: 384 });
22157
+ chmodSync4(path97, 384);
22118
22158
  printSuccess(`generated ~/.olam/${name}`);
22119
22159
  }
22120
22160
  }
@@ -22237,13 +22277,13 @@ function installObservability(opts) {
22237
22277
  scriptEnv.OLAM_BUNDLE_ROOT = bundleRoot;
22238
22278
  }
22239
22279
  for (const script of OBSERVABILITY_SCRIPTS) {
22240
- const path96 = join34(observabilityDir, script);
22241
- if (!existsSync29(path96)) {
22280
+ const path97 = join34(observabilityDir, script);
22281
+ if (!existsSync29(path97)) {
22242
22282
  printWarning(`observability script missing: ${script} \u2014 skipping`);
22243
22283
  continue;
22244
22284
  }
22245
22285
  printInfo("run", script);
22246
- const result = spawnSync10("bash", [path96], {
22286
+ const result = spawnSync10("bash", [path97], {
22247
22287
  stdio: "inherit",
22248
22288
  env: scriptEnv
22249
22289
  });
@@ -23252,56 +23292,56 @@ var SECRET_LEN_BYTES = 32;
23252
23292
  function generateSecret() {
23253
23293
  return randomBytes8(SECRET_LEN_BYTES).toString("hex");
23254
23294
  }
23255
- function writeSecretAtPath(path96, value) {
23256
- mkdirSync21(dirname22(path96), { recursive: true });
23257
- const tmp = `${path96}.tmp.${process.pid}`;
23295
+ function writeSecretAtPath(path97, value) {
23296
+ mkdirSync21(dirname22(path97), { recursive: true });
23297
+ const tmp = `${path97}.tmp.${process.pid}`;
23258
23298
  writeFileSync16(tmp, value, { mode: 384 });
23259
23299
  chmodSync5(tmp, 384);
23260
- renameSync6(tmp, path96);
23300
+ renameSync6(tmp, path97);
23261
23301
  }
23262
- function readSecretAtPathOrNull(path96) {
23263
- if (!existsSync32(path96)) return null;
23264
- const mode = statSync8(path96).mode & 511;
23302
+ function readSecretAtPathOrNull(path97) {
23303
+ if (!existsSync32(path97)) return null;
23304
+ const mode = statSync8(path97).mode & 511;
23265
23305
  if (mode !== 384) {
23266
23306
  process.stderr.write(
23267
- `warn: ${path96} has mode 0${mode.toString(8)}; expected 0600. Run 'olam memory secret rotate' to regenerate.
23307
+ `warn: ${path97} has mode 0${mode.toString(8)}; expected 0600. Run 'olam memory secret rotate' to regenerate.
23268
23308
  `
23269
23309
  );
23270
23310
  }
23271
- return readFileSync25(path96, "utf8").trim();
23311
+ return readFileSync25(path97, "utf8").trim();
23272
23312
  }
23273
- function readSecretAtPath(path96) {
23274
- const v = readSecretAtPathOrNull(path96);
23313
+ function readSecretAtPath(path97) {
23314
+ const v = readSecretAtPathOrNull(path97);
23275
23315
  if (v === null) {
23276
23316
  throw new Error(
23277
- `Secret not found at ${path96}. Run 'olam memory start' to generate it.`
23317
+ `Secret not found at ${path97}. Run 'olam memory start' to generate it.`
23278
23318
  );
23279
23319
  }
23280
23320
  return v;
23281
23321
  }
23282
- function ensureMemorySecret(path96 = MEMORY_SECRET_PATH) {
23283
- const existing = readSecretAtPathOrNull(path96);
23322
+ function ensureMemorySecret(path97 = MEMORY_SECRET_PATH) {
23323
+ const existing = readSecretAtPathOrNull(path97);
23284
23324
  if (existing) return existing;
23285
23325
  const fresh = generateSecret();
23286
- writeSecretAtPath(path96, fresh);
23326
+ writeSecretAtPath(path97, fresh);
23287
23327
  return fresh;
23288
23328
  }
23289
- function readMemorySecretOrNull(path96 = MEMORY_SECRET_PATH) {
23290
- return readSecretAtPathOrNull(path96);
23329
+ function readMemorySecretOrNull(path97 = MEMORY_SECRET_PATH) {
23330
+ return readSecretAtPathOrNull(path97);
23291
23331
  }
23292
- function readMemorySecret(path96 = MEMORY_SECRET_PATH) {
23293
- return readSecretAtPath(path96);
23332
+ function readMemorySecret(path97 = MEMORY_SECRET_PATH) {
23333
+ return readSecretAtPath(path97);
23294
23334
  }
23295
- function rotateMemorySecret(path96 = MEMORY_SECRET_PATH) {
23335
+ function rotateMemorySecret(path97 = MEMORY_SECRET_PATH) {
23296
23336
  const fresh = generateSecret();
23297
- writeSecretAtPath(path96, fresh);
23337
+ writeSecretAtPath(path97, fresh);
23298
23338
  return fresh;
23299
23339
  }
23300
- function hasMemorySecret(path96 = MEMORY_SECRET_PATH) {
23301
- return existsSync32(path96);
23340
+ function hasMemorySecret(path97 = MEMORY_SECRET_PATH) {
23341
+ return existsSync32(path97);
23302
23342
  }
23303
- function writeCloudMemorySecret(value, path96 = CLOUD_MEMORY_SECRET_PATH) {
23304
- writeSecretAtPath(path96, value);
23343
+ function writeCloudMemorySecret(value, path97 = CLOUD_MEMORY_SECRET_PATH) {
23344
+ writeSecretAtPath(path97, value);
23305
23345
  }
23306
23346
 
23307
23347
  // src/commands/memory-service-container.ts
@@ -24408,12 +24448,12 @@ function appendAuditEntry(entry, auditLogPath, writeFileSyncImpl) {
24408
24448
  async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, peripheral) {
24409
24449
  const auditLogPath = deps.auditLogPath ?? MANIFEST_REFRESH_AUDIT_LOG;
24410
24450
  const readdirSync33 = deps.readdirSync ?? fs31.readdirSync;
24411
- const readFileSync96 = deps.readFileSync ?? fs31.readFileSync;
24451
+ const readFileSync99 = deps.readFileSync ?? fs31.readFileSync;
24412
24452
  const writeFileSyncImpl = deps.writeFileSync ?? fs31.writeFileSync;
24413
- const existsSync113 = deps.existsSync ?? fs31.existsSync;
24453
+ const existsSync115 = deps.existsSync ?? fs31.existsSync;
24414
24454
  const now = deps.now ? deps.now() : /* @__PURE__ */ new Date();
24415
24455
  const targetDir = peripheral ? path32.join(manifestsDir, peripheral) : manifestsDir;
24416
- if (!existsSync113(targetDir)) {
24456
+ if (!existsSync115(targetDir)) {
24417
24457
  return {
24418
24458
  ok: false,
24419
24459
  message: peripheral ? `peripheral manifests directory not found: ${targetDir}` : `manifests directory not found: ${targetDir}`
@@ -24434,7 +24474,7 @@ async function runManifestRefresh(manifestsDir, acceptRegression, deps = {}, per
24434
24474
  const filePath = path32.join(targetDir, file);
24435
24475
  let content;
24436
24476
  try {
24437
- content = readFileSync96(filePath, "utf8");
24477
+ content = readFileSync99(filePath, "utf8");
24438
24478
  } catch {
24439
24479
  continue;
24440
24480
  }
@@ -24685,11 +24725,11 @@ async function checkSecretPreCondition(context, deps) {
24685
24725
  }
24686
24726
  async function applyConfigMapSubstitution(context, manifestsDir, deps) {
24687
24727
  const wrap = deps.kubectlWrapImpl ?? kubectlWrap;
24688
- const readFileSync96 = deps.readFileSyncImpl ?? fs32.readFileSync;
24728
+ const readFileSync99 = deps.readFileSyncImpl ?? fs32.readFileSync;
24689
24729
  const configMapPath = path33.join(manifestsDir, "30-configmap.yaml");
24690
24730
  let rawYaml;
24691
24731
  try {
24692
- rawYaml = readFileSync96(configMapPath, "utf8");
24732
+ rawYaml = readFileSync99(configMapPath, "utf8");
24693
24733
  } catch (err) {
24694
24734
  return `Failed to read ConfigMap at ${configMapPath}: ${err instanceof Error ? err.message : String(err)}`;
24695
24735
  }
@@ -26059,9 +26099,9 @@ function formatFreshnessWarning(result, image = DEFAULT_DEVBOX_IMAGE) {
26059
26099
  "These source files have changed since the image was built; the",
26060
26100
  "changes will NOT take effect in fresh worlds until you rebuild:"
26061
26101
  ];
26062
- for (const { path: path96, mtimeMs } of result.newerSources) {
26102
+ for (const { path: path97, mtimeMs } of result.newerSources) {
26063
26103
  const when = new Date(mtimeMs).toISOString();
26064
- lines.push(` \u2022 ${path96} (modified ${when})`);
26104
+ lines.push(` \u2022 ${path97} (modified ${when})`);
26065
26105
  }
26066
26106
  lines.push("");
26067
26107
  lines.push("Rebuild with:");
@@ -26440,15 +26480,15 @@ var AGENTMEMORY_LOCAL_URL = "http://host.docker.internal:3111";
26440
26480
  var HOST_CP_URL = "http://127.0.0.1:19000";
26441
26481
  async function readHostCpTokenForCreate() {
26442
26482
  try {
26443
- const { default: fs96 } = await import("node:fs");
26444
- const { default: os50 } = await import("node:os");
26445
- const { default: path96 } = await import("node:path");
26446
- const tp = path96.join(
26447
- process.env.OLAM_HOME ?? path96.join(os50.homedir(), ".olam"),
26483
+ const { default: fs97 } = await import("node:fs");
26484
+ const { default: os51 } = await import("node:os");
26485
+ const { default: path97 } = await import("node:path");
26486
+ const tp = path97.join(
26487
+ process.env.OLAM_HOME ?? path97.join(os51.homedir(), ".olam"),
26448
26488
  "host-cp.token"
26449
26489
  );
26450
- if (!fs96.existsSync(tp)) return null;
26451
- return fs96.readFileSync(tp, "utf-8").trim();
26490
+ if (!fs97.existsSync(tp)) return null;
26491
+ return fs97.readFileSync(tp, "utf-8").trim();
26452
26492
  } catch {
26453
26493
  return null;
26454
26494
  }
@@ -26936,12 +26976,12 @@ function defaultNameFromPrompt(prompt) {
26936
26976
  }
26937
26977
  async function readHostCpToken3() {
26938
26978
  try {
26939
- const { default: fs96 } = await import("node:fs");
26940
- const { default: os50 } = await import("node:os");
26941
- const { default: path96 } = await import("node:path");
26942
- const tp = path96.join(os50.homedir(), ".olam", "host-cp.token");
26943
- if (!fs96.existsSync(tp)) return null;
26944
- const raw = fs96.readFileSync(tp, "utf-8").trim();
26979
+ const { default: fs97 } = await import("node:fs");
26980
+ const { default: os51 } = await import("node:os");
26981
+ const { default: path97 } = await import("node:path");
26982
+ const tp = path97.join(os51.homedir(), ".olam", "host-cp.token");
26983
+ if (!fs97.existsSync(tp)) return null;
26984
+ const raw = fs97.readFileSync(tp, "utf-8").trim();
26945
26985
  return raw.length > 0 ? raw : null;
26946
26986
  } catch {
26947
26987
  return null;
@@ -28662,13 +28702,13 @@ var PlansClient = class {
28662
28702
  const credentials = Buffer.from(`operator:${this.cfg.bearer}`).toString("base64");
28663
28703
  return `Basic ${credentials}`;
28664
28704
  }
28665
- async request(path96, init) {
28705
+ async request(path97, init) {
28666
28706
  const headers = {
28667
28707
  Authorization: this.authHeader()
28668
28708
  };
28669
28709
  if (init.body) headers["content-type"] = "application/json";
28670
28710
  if (init.adminSecret) headers["X-Admin-Secret"] = init.adminSecret;
28671
- return fetch(`${this.cfg.cloudUrl}${path96}`, {
28711
+ return fetch(`${this.cfg.cloudUrl}${path97}`, {
28672
28712
  method: init.method,
28673
28713
  headers,
28674
28714
  body: init.body ? JSON.stringify(init.body) : void 0
@@ -31153,11 +31193,11 @@ function zodIssueToError(issue, doc, lineCounter) {
31153
31193
  suggestion: deriveSuggestion(issue)
31154
31194
  };
31155
31195
  }
31156
- function formatJsonPath(path96) {
31157
- if (path96.length === 0)
31196
+ function formatJsonPath(path97) {
31197
+ if (path97.length === 0)
31158
31198
  return "<root>";
31159
31199
  let out = "";
31160
- for (const seg of path96) {
31200
+ for (const seg of path97) {
31161
31201
  if (typeof seg === "number") {
31162
31202
  out += `[${seg}]`;
31163
31203
  } else {
@@ -31166,11 +31206,11 @@ function formatJsonPath(path96) {
31166
31206
  }
31167
31207
  return out;
31168
31208
  }
31169
- function resolveYamlLocation(path96, doc, lineCounter) {
31209
+ function resolveYamlLocation(path97, doc, lineCounter) {
31170
31210
  let bestLine = 0;
31171
31211
  let bestColumn = 0;
31172
- for (let depth = path96.length; depth >= 0; depth -= 1) {
31173
- const segment = path96.slice(0, depth);
31212
+ for (let depth = path97.length; depth >= 0; depth -= 1) {
31213
+ const segment = path97.slice(0, depth);
31174
31214
  try {
31175
31215
  const node = doc.getIn(segment, true);
31176
31216
  if (node && typeof node === "object" && "range" in node) {
@@ -31388,11 +31428,11 @@ function topoSort(nodes) {
31388
31428
  }
31389
31429
  function traceCycle(start, byId) {
31390
31430
  const seen = /* @__PURE__ */ new Set();
31391
- const path96 = [];
31431
+ const path97 = [];
31392
31432
  let current = start;
31393
31433
  while (current && !seen.has(current)) {
31394
31434
  seen.add(current);
31395
- path96.push(current);
31435
+ path97.push(current);
31396
31436
  const node = byId.get(current);
31397
31437
  const next = node?.dependsOn[0];
31398
31438
  if (next === void 0)
@@ -31400,10 +31440,10 @@ function traceCycle(start, byId) {
31400
31440
  current = next;
31401
31441
  }
31402
31442
  if (current && seen.has(current)) {
31403
- const idx = path96.indexOf(current);
31404
- return [...path96.slice(idx), current];
31443
+ const idx = path97.indexOf(current);
31444
+ return [...path97.slice(idx), current];
31405
31445
  }
31406
- return path96;
31446
+ return path97;
31407
31447
  }
31408
31448
 
31409
31449
  // ../core/dist/executor/types.js
@@ -36110,8 +36150,8 @@ function checkWorld(container, hostShas, dockerExec) {
36110
36150
  const m = shaLine.match(/^([a-f0-9]{64})\s+(.+)$/);
36111
36151
  if (!m) continue;
36112
36152
  const sha = m[1];
36113
- const path96 = m[2];
36114
- const filename = path96?.split("/").pop();
36153
+ const path97 = m[2];
36154
+ const filename = path97?.split("/").pop();
36115
36155
  if (!filename) continue;
36116
36156
  const mtimeSecs = parseInt(mtimeLine.trim(), 10);
36117
36157
  if (Number.isNaN(mtimeSecs) || !sha) continue;
@@ -36978,9 +37018,9 @@ var TasksClient = class {
36978
37018
  this.olamNodeId = opts.olamNodeId;
36979
37019
  this.sessionId = opts.sessionId;
36980
37020
  }
36981
- async call(method, path96, scopes, body, query) {
37021
+ async call(method, path97, scopes, body, query) {
36982
37022
  const qs = query ? "?" + new URLSearchParams(Object.entries(query).filter(([, v]) => v !== void 0)).toString() : "";
36983
- const url2 = `${this.baseUrl}${path96}${qs}`;
37023
+ const url2 = `${this.baseUrl}${path97}${qs}`;
36984
37024
  const res = await fetch(url2, {
36985
37025
  method,
36986
37026
  headers: {
@@ -37031,8 +37071,8 @@ function parseFrontmatter2(raw) {
37031
37071
  }
37032
37072
  return { frontmatter: fm, body };
37033
37073
  }
37034
- function parseTracker(path96) {
37035
- const raw = readFileSync48(path96, "utf8");
37074
+ function parseTracker(path97) {
37075
+ const raw = readFileSync48(path97, "utf8");
37036
37076
  const { frontmatter, body } = parseFrontmatter2(raw);
37037
37077
  const lines = body.split("\n");
37038
37078
  const tasks = [];
@@ -37269,8 +37309,8 @@ function registerTasks(program2) {
37269
37309
  `);
37270
37310
  }
37271
37311
  });
37272
- tasks.command("sync-tracker <path>").description("Parse /10x:commit-plan tracker.md + upsert each task via POST /api/tasks (B2.4; dual-emit pattern, olam-side per cross-ownership decoupling)").option("--node-id <uuid>", "Olam node ID").option("--session-id <uuid>", "Session ID").option("--dry-run", "Parse + print task records; do not POST").option("--json", "Output raw JSON envelope").action(async (path96, opts) => {
37273
- const parsed = parseTracker(path96);
37312
+ tasks.command("sync-tracker <path>").description("Parse /10x:commit-plan tracker.md + upsert each task via POST /api/tasks (B2.4; dual-emit pattern, olam-side per cross-ownership decoupling)").option("--node-id <uuid>", "Olam node ID").option("--session-id <uuid>", "Session ID").option("--dry-run", "Parse + print task records; do not POST").option("--json", "Output raw JSON envelope").action(async (path97, opts) => {
37313
+ const parsed = parseTracker(path97);
37274
37314
  if (opts.dryRun) {
37275
37315
  process.stdout.write(JSON.stringify(parsed, null, 2) + "\n");
37276
37316
  return;
@@ -37516,9 +37556,9 @@ function appendIdempotent(opts) {
37516
37556
  }
37517
37557
  function resolveShellRc(home, shellEnv) {
37518
37558
  if (!shellEnv) return null;
37519
- const basename16 = path54.basename(shellEnv);
37520
- if (basename16 === "zsh") return path54.join(home, ".zshrc");
37521
- if (basename16 === "bash") return path54.join(home, ".bashrc");
37559
+ const basename17 = path54.basename(shellEnv);
37560
+ if (basename17 === "zsh") return path54.join(home, ".zshrc");
37561
+ if (basename17 === "bash") return path54.join(home, ".bashrc");
37522
37562
  return null;
37523
37563
  }
37524
37564
 
@@ -41319,10 +41359,10 @@ function registerSkillsMigrateHooksBack(program2) {
41319
41359
  process.exitCode = 1;
41320
41360
  return;
41321
41361
  }
41322
- const basename16 = path85.basename(resolved);
41323
- if (!basename16.startsWith(META_HOOKS_SNAPSHOT_PREFIX)) {
41362
+ const basename17 = path85.basename(resolved);
41363
+ if (!basename17.startsWith(META_HOOKS_SNAPSHOT_PREFIX)) {
41324
41364
  printError(
41325
- `--snapshot filename must start with "${META_HOOKS_SNAPSHOT_PREFIX}" (got "${basename16}"). Cross-namespace snapshots (atlas-toolbox-*) are not valid restore targets for olam-meta hooks.`
41365
+ `--snapshot filename must start with "${META_HOOKS_SNAPSHOT_PREFIX}" (got "${basename17}"). Cross-namespace snapshots (atlas-toolbox-*) are not valid restore targets for olam-meta hooks.`
41326
41366
  );
41327
41367
  process.exitCode = 1;
41328
41368
  return;
@@ -42310,8 +42350,8 @@ var SECRET = process.env["OLAM_MCP_AUTH_SECRET"] ?? "";
42310
42350
  function authHeaders() {
42311
42351
  return SECRET ? { "X-Olam-Mcp-Secret": SECRET } : {};
42312
42352
  }
42313
- async function apiFetch(path96, init = {}) {
42314
- const res = await fetch(`${BASE_URL}${path96}`, {
42353
+ async function apiFetch(path97, init = {}) {
42354
+ const res = await fetch(`${BASE_URL}${path97}`, {
42315
42355
  ...init,
42316
42356
  headers: {
42317
42357
  "Content-Type": "application/json",
@@ -43551,13 +43591,13 @@ function resolveMemoryServiceDir() {
43551
43591
  );
43552
43592
  }
43553
43593
  function resolveLocalBridgeScript(serviceDir) {
43554
- const path96 = join97(serviceDir, "scripts", "local-bridge-server.mjs");
43555
- if (!existsSync105(path96)) {
43594
+ const path97 = join97(serviceDir, "scripts", "local-bridge-server.mjs");
43595
+ if (!existsSync105(path97)) {
43556
43596
  throw new Error(
43557
- `Could not find local-bridge-server.mjs at ${path96}. Verify packages/memory-service ships the scripts/ directory.`
43597
+ `Could not find local-bridge-server.mjs at ${path97}. Verify packages/memory-service ships the scripts/ directory.`
43558
43598
  );
43559
43599
  }
43560
- return path96;
43600
+ return path97;
43561
43601
  }
43562
43602
  function validateBridgeOpts(opts) {
43563
43603
  const local = opts.local ?? false;
@@ -43915,9 +43955,9 @@ function defaultSourceDir() {
43915
43955
  if (existsSync106(srcCandidate)) return srcCandidate;
43916
43956
  return candidate;
43917
43957
  }
43918
- function installOne2(basename16, sourceDir, targetDir, opts) {
43919
- const sourcePath = join98(sourceDir, basename16);
43920
- const targetPath = join98(targetDir, basename16);
43958
+ function installOne2(basename17, sourceDir, targetDir, opts) {
43959
+ const sourcePath = join98(sourceDir, basename17);
43960
+ const targetPath = join98(targetDir, basename17);
43921
43961
  if (!existsSync106(sourcePath)) {
43922
43962
  throw new Error(`canonical hook source missing at ${sourcePath} \u2014 olam install corrupt or sourceDir is wrong`);
43923
43963
  }
@@ -43927,11 +43967,11 @@ function installOne2(basename16, sourceDir, targetDir, opts) {
43927
43967
  mkdirSync60(dirname56(targetPath), { recursive: true });
43928
43968
  writeFileSync52(targetPath, newContent, { mode: 493 });
43929
43969
  }
43930
- return { basename: basename16, action: "written", targetPath };
43970
+ return { basename: basename17, action: "written", targetPath };
43931
43971
  }
43932
43972
  const existing = readFileSync86(targetPath, "utf8");
43933
43973
  if (existing === newContent) {
43934
- return { basename: basename16, action: "unchanged", targetPath };
43974
+ return { basename: basename17, action: "unchanged", targetPath };
43935
43975
  }
43936
43976
  if (opts.force === true) {
43937
43977
  const backupPath = `${targetPath}.agentmemory-hook-backup-${Math.floor(Date.now() / 1e3)}`;
@@ -43939,9 +43979,9 @@ function installOne2(basename16, sourceDir, targetDir, opts) {
43939
43979
  copyFileSync12(targetPath, backupPath);
43940
43980
  writeFileSync52(targetPath, newContent, { mode: 493 });
43941
43981
  }
43942
- return { basename: basename16, action: "force-overwritten", targetPath, backupPath };
43982
+ return { basename: basename17, action: "force-overwritten", targetPath, backupPath };
43943
43983
  }
43944
- return { basename: basename16, action: "preserved-existing", targetPath };
43984
+ return { basename: basename17, action: "preserved-existing", targetPath };
43945
43985
  }
43946
43986
  function emitSettingsHint(targetDir) {
43947
43987
  return `
@@ -43977,8 +44017,8 @@ function registerMemoryInstallHooks(parent) {
43977
44017
  const lines = [];
43978
44018
  const backups = [];
43979
44019
  try {
43980
- for (const basename16 of HOOK_BASENAMES) {
43981
- const result = installOne2(basename16, sourceDir, targetDir, opts);
44020
+ for (const basename17 of HOOK_BASENAMES) {
44021
+ const result = installOne2(basename17, sourceDir, targetDir, opts);
43982
44022
  const dryRunSuffix = opts.dryRun === true ? " (dry-run)" : "";
43983
44023
  switch (result.action) {
43984
44024
  case "written":
@@ -44059,8 +44099,8 @@ function port() {
44059
44099
  const n = Number.parseInt(env, 10);
44060
44100
  return Number.isFinite(n) && n > 0 ? n : KG_SERVICE_PORT_DEFAULT;
44061
44101
  }
44062
- function url(path96) {
44063
- return `http://127.0.0.1:${port()}${path96}`;
44102
+ function url(path97) {
44103
+ return `http://127.0.0.1:${port()}${path97}`;
44064
44104
  }
44065
44105
  function kgServiceHealthUrl() {
44066
44106
  return url("/health");
@@ -45325,14 +45365,14 @@ async function emitBreadcrumb(opts) {
45325
45365
  );
45326
45366
  process.exit(2);
45327
45367
  }
45328
- const path96 = destPath(rec.project_slug);
45329
- const lockDir = dirname59(path96);
45368
+ const path97 = destPath(rec.project_slug);
45369
+ const lockDir = dirname59(path97);
45330
45370
  mkdirSync63(lockDir, { recursive: true });
45331
45371
  const line = JSON.stringify(rec) + "\n";
45332
45372
  await withFileLock(
45333
45373
  lockDir,
45334
45374
  () => {
45335
- appendFileSync6(path96, line, "utf8");
45375
+ appendFileSync6(path97, line, "utf8");
45336
45376
  },
45337
45377
  {
45338
45378
  lockFilename: LOCK_FILENAME,
@@ -45342,7 +45382,7 @@ async function emitBreadcrumb(opts) {
45342
45382
  acquireTimeoutMs: 5e3
45343
45383
  }
45344
45384
  );
45345
- process.stdout.write(`[K7-emit] ${path96}: ${rec.extracted_pattern} (${rec.severity})
45385
+ process.stdout.write(`[K7-emit] ${path97}: ${rec.extracted_pattern} (${rec.severity})
45346
45386
  `);
45347
45387
  }
45348
45388
  function registerFlywheelEmitBreadcrumb(parent) {
@@ -45465,38 +45505,38 @@ function validateK5ScoredAt(scoredAt) {
45465
45505
  }
45466
45506
  return null;
45467
45507
  }
45468
- function validatePlan(path96) {
45508
+ function validatePlan(path97) {
45469
45509
  let stat;
45470
45510
  try {
45471
- stat = statSync30(path96);
45511
+ stat = statSync30(path97);
45472
45512
  } catch (err) {
45473
- return { ok: false, message: `FAIL cannot stat ${path96}: ${err instanceof Error ? err.message : "unknown"}` };
45513
+ return { ok: false, message: `FAIL cannot stat ${path97}: ${err instanceof Error ? err.message : "unknown"}` };
45474
45514
  }
45475
45515
  if (stat.size > MAX_PLAN_BYTES) {
45476
- return { ok: false, message: `FAIL ${path96}: plan file exceeds 1MB (${stat.size} bytes); refusing to parse` };
45516
+ return { ok: false, message: `FAIL ${path97}: plan file exceeds 1MB (${stat.size} bytes); refusing to parse` };
45477
45517
  }
45478
45518
  let text;
45479
45519
  try {
45480
- text = readFileSync90(path96, "utf8");
45520
+ text = readFileSync90(path97, "utf8");
45481
45521
  } catch (err) {
45482
- return { ok: false, message: `FAIL cannot read ${path96}: ${err instanceof Error ? err.message : "unknown"}` };
45522
+ return { ok: false, message: `FAIL cannot read ${path97}: ${err instanceof Error ? err.message : "unknown"}` };
45483
45523
  }
45484
45524
  if (!text.replace(/^/, "").startsWith("---")) {
45485
- return { ok: false, message: `FAIL ${path96}: no YAML frontmatter (missing opening --- marker)` };
45525
+ return { ok: false, message: `FAIL ${path97}: no YAML frontmatter (missing opening --- marker)` };
45486
45526
  }
45487
45527
  if (!text.includes("\n---", 3)) {
45488
- return { ok: false, message: `FAIL ${path96}: frontmatter block never closed (missing closing --- marker)` };
45528
+ return { ok: false, message: `FAIL ${path97}: frontmatter block never closed (missing closing --- marker)` };
45489
45529
  }
45490
45530
  const fm = extractFrontmatter(text);
45491
45531
  if (fm === null) {
45492
- return { ok: false, message: `FAIL ${path96}: frontmatter could not be parsed as YAML` };
45532
+ return { ok: false, message: `FAIL ${path97}: frontmatter could not be parsed as YAML` };
45493
45533
  }
45494
45534
  const hasScores = "k5_scores" in fm;
45495
45535
  const hasBoost = "k5_boost" in fm;
45496
45536
  const hasComposite = "k5_composite" in fm;
45497
45537
  const hasScoredAt = "k5_scored_at" in fm;
45498
45538
  if (!hasScores && !hasBoost && !hasComposite && !hasScoredAt) {
45499
- return { ok: true, message: `PASS ${path96}: k5_scores absent (acceptable \u2014 legacy plan)` };
45539
+ return { ok: true, message: `PASS ${path97}: k5_scores absent (acceptable \u2014 legacy plan)` };
45500
45540
  }
45501
45541
  const errors = [];
45502
45542
  if (hasScores) {
@@ -45516,9 +45556,9 @@ function validatePlan(path96) {
45516
45556
  if (err !== null) errors.push(err);
45517
45557
  }
45518
45558
  if (errors.length > 0) {
45519
- return { ok: false, message: `FAIL ${path96}: ${errors.join("; ")}` };
45559
+ return { ok: false, message: `FAIL ${path97}: ${errors.join("; ")}` };
45520
45560
  }
45521
- const lines = [`PASS ${path96}: k5_scores valid`];
45561
+ const lines = [`PASS ${path97}: k5_scores valid`];
45522
45562
  if (hasScores && typeof fm.k5_scores === "object" && fm.k5_scores !== null) {
45523
45563
  const scoresObj = fm.k5_scores;
45524
45564
  const vals = [];
@@ -46204,14 +46244,14 @@ function pushOverlays(opts) {
46204
46244
  const registeredPrefixes = (opts._testSkillSources ?? listSkillSources()).map((s) => s.prefix).filter((p) => typeof p === "string" && p.length > 0);
46205
46245
  if (registeredPrefixes.length > 0) {
46206
46246
  for (const { srcFile, relPath } of sourceFiles) {
46207
- const basename16 = relPath.split("/").pop() ?? relPath;
46247
+ const basename17 = relPath.split("/").pop() ?? relPath;
46208
46248
  let content;
46209
46249
  try {
46210
46250
  content = readFileSync94(srcFile);
46211
46251
  } catch {
46212
46252
  continue;
46213
46253
  }
46214
- const validation = validateCanonical(basename16, content, registeredPrefixes);
46254
+ const validation = validateCanonical(basename17, content, registeredPrefixes);
46215
46255
  if (!validation.ok && validation.violation !== void 0) {
46216
46256
  throw new PushError(
46217
46257
  1,
@@ -46667,6 +46707,261 @@ Per-file changes:
46667
46707
  });
46668
46708
  }
46669
46709
 
46710
+ // src/commands/flywheel/session-start.ts
46711
+ import { readFileSync as readFileSync95, statSync as statSync33 } from "node:fs";
46712
+ import { homedir as homedir63 } from "node:os";
46713
+ import { join as join106 } from "node:path";
46714
+ var SESSIONSTART_HOOK_SENTINEL = "olam-sessionstart-context-hook-v1";
46715
+ var MAX_WAKE_BRIEF_BYTES = 8 * 1024;
46716
+ var MAX_ACTIVE_WORLD_BYTES = 4 * 1024;
46717
+ var MAX_CONFIG_BYTES = 8 * 1024;
46718
+ function tryReadCapped(path97, maxBytes) {
46719
+ try {
46720
+ const stat = statSync33(path97);
46721
+ if (!stat.isFile() || stat.size === 0) return null;
46722
+ if (stat.size > maxBytes) {
46723
+ process.stderr.write(
46724
+ `[${SESSIONSTART_HOOK_SENTINEL}] skipping ${path97}: ${stat.size} bytes > ${maxBytes} cap
46725
+ `
46726
+ );
46727
+ return null;
46728
+ }
46729
+ return readFileSync95(path97, "utf-8");
46730
+ } catch (err) {
46731
+ const code = err?.code;
46732
+ if (code === "ENOENT") return null;
46733
+ process.stderr.write(
46734
+ `[${SESSIONSTART_HOOK_SENTINEL}] read failed for ${path97}: ${err?.message ?? err}
46735
+ `
46736
+ );
46737
+ return null;
46738
+ }
46739
+ }
46740
+ function tryParseJson(raw, label) {
46741
+ if (raw === null) return null;
46742
+ try {
46743
+ return JSON.parse(raw);
46744
+ } catch (err) {
46745
+ process.stderr.write(
46746
+ `[${SESSIONSTART_HOOK_SENTINEL}] ${label} JSON parse failed: ${err?.message ?? err}
46747
+ `
46748
+ );
46749
+ return null;
46750
+ }
46751
+ }
46752
+ function buildContextBlock(olamHome5) {
46753
+ const config = tryParseJson(
46754
+ tryReadCapped(join106(olamHome5, "config.json"), MAX_CONFIG_BYTES),
46755
+ "config.json"
46756
+ );
46757
+ const activeWorld = tryParseJson(
46758
+ tryReadCapped(join106(olamHome5, "state", "active-world.json"), MAX_ACTIVE_WORLD_BYTES),
46759
+ "active-world.json"
46760
+ );
46761
+ const wakeBrief = tryReadCapped(
46762
+ join106(olamHome5, "state", "wake-brief.md"),
46763
+ MAX_WAKE_BRIEF_BYTES
46764
+ );
46765
+ const sections = [];
46766
+ if (config && typeof config.activeWorkspace === "string") {
46767
+ sections.push(`Active workspace: ${config.activeWorkspace}`);
46768
+ }
46769
+ if (activeWorld && typeof activeWorld === "object") {
46770
+ const parts = [];
46771
+ if (typeof activeWorld.worldId === "string") parts.push(`worldId=${activeWorld.worldId}`);
46772
+ if (typeof activeWorld.branch === "string") parts.push(`branch=${activeWorld.branch}`);
46773
+ if (typeof activeWorld.repo === "string") parts.push(`repo=${activeWorld.repo}`);
46774
+ if (typeof activeWorld.tier === "string") parts.push(`tier=${activeWorld.tier}`);
46775
+ if (typeof activeWorld.enteredAt === "string") parts.push(`enteredAt=${activeWorld.enteredAt}`);
46776
+ if (parts.length > 0) sections.push(`Active world: ${parts.join(", ")}`);
46777
+ }
46778
+ if (wakeBrief && wakeBrief.trim().length > 0) {
46779
+ sections.push("Most recent wake brief:\n\n" + wakeBrief.trimEnd());
46780
+ }
46781
+ if (sections.length === 0) return null;
46782
+ const body = sections.join("\n\n");
46783
+ return `Olam SessionStart context (${Buffer.byteLength(body, "utf-8")} bytes):
46784
+
46785
+ ${body}`;
46786
+ }
46787
+ function emitSessionStartContext(olamHome5) {
46788
+ try {
46789
+ const context = buildContextBlock(olamHome5);
46790
+ if (context === null) {
46791
+ process.stdout.write("{}\n");
46792
+ return;
46793
+ }
46794
+ process.stdout.write(
46795
+ JSON.stringify({
46796
+ hookSpecificOutput: {
46797
+ hookEventName: "SessionStart",
46798
+ additionalContext: context
46799
+ }
46800
+ }) + "\n"
46801
+ );
46802
+ } catch (err) {
46803
+ process.stderr.write(
46804
+ `[${SESSIONSTART_HOOK_SENTINEL}] unexpected error: ${err?.message ?? err}
46805
+ `
46806
+ );
46807
+ process.stdout.write("{}\n");
46808
+ }
46809
+ }
46810
+ function registerFlywheelSessionStart(parent) {
46811
+ parent.command("session-start").description(
46812
+ "Emit operator-state context for the SessionStart hook (4th defense layer). Reads ~/.olam/state/* and writes the additionalContext JSON to stdout. Fail-soft: always exits 0."
46813
+ ).action(() => {
46814
+ const olamHome5 = process.env.OLAM_HOME ?? join106(homedir63(), ".olam");
46815
+ emitSessionStartContext(olamHome5);
46816
+ process.exit(0);
46817
+ });
46818
+ }
46819
+
46820
+ // src/commands/flywheel/install-sessionstart-hook.ts
46821
+ init_merge_settings();
46822
+ init_output();
46823
+ import { existsSync as existsSync112, copyFileSync as copyFileSync16, mkdirSync as mkdirSync66, readFileSync as readFileSync96, unlinkSync as unlinkSync25, writeFileSync as writeFileSync58 } from "node:fs";
46824
+ import { homedir as homedir64 } from "node:os";
46825
+ import { dirname as dirname62, join as join107 } from "node:path";
46826
+ var SESSIONSTART_HOOK_STAGE = "SessionStart";
46827
+ var SESSIONSTART_HOOK_TIMEOUT_MS = 5e3;
46828
+ var NOOP_GUARD = "command -v olam >/dev/null 2>&1 || exit 0;";
46829
+ function buildSessionStartHookEntry() {
46830
+ return {
46831
+ matcher: "",
46832
+ hooks: [
46833
+ {
46834
+ type: "command",
46835
+ command: `OLAM_SESSIONSTART_SENTINEL=${SESSIONSTART_HOOK_SENTINEL}; ${NOOP_GUARD} olam flywheel session-start`,
46836
+ timeout: SESSIONSTART_HOOK_TIMEOUT_MS
46837
+ }
46838
+ ]
46839
+ };
46840
+ }
46841
+ function settingsPathFor4(scope, cwd) {
46842
+ if (scope === "user") return join107(homedir64(), ".claude", "settings.json");
46843
+ return join107(cwd ?? process.cwd(), ".claude", "settings.json");
46844
+ }
46845
+ function backup3(filePath) {
46846
+ if (!existsSync112(filePath)) return null;
46847
+ const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
46848
+ const backupPath = `${filePath}.olam-bak.${ts}`;
46849
+ copyFileSync16(filePath, backupPath);
46850
+ return backupPath;
46851
+ }
46852
+ function installSessionStartHook(filePath) {
46853
+ mkdirSync66(dirname62(filePath), { recursive: true });
46854
+ const backupPath = backup3(filePath);
46855
+ const result = mergeHomeSettingsJson(filePath, {
46856
+ ensureHook: {
46857
+ stage: SESSIONSTART_HOOK_STAGE,
46858
+ sentinel: SESSIONSTART_HOOK_SENTINEL,
46859
+ entry: buildSessionStartHookEntry()
46860
+ }
46861
+ });
46862
+ if (result.status === "already-present" && backupPath) {
46863
+ try {
46864
+ unlinkSync25(backupPath);
46865
+ } catch {
46866
+ }
46867
+ return { status: "already-present", filePath, backupPath: null };
46868
+ }
46869
+ return { status: result.status, filePath, backupPath };
46870
+ }
46871
+ function uninstallSessionStartHook(filePath) {
46872
+ if (!existsSync112(filePath)) return { status: "no-settings", filePath };
46873
+ const raw = readFileSync96(filePath, "utf-8");
46874
+ const settings = raw.trim() ? JSON.parse(raw) : {};
46875
+ const matchers = settings.hooks?.SessionStart;
46876
+ if (!Array.isArray(matchers) || matchers.length === 0) {
46877
+ return { status: "not-found", filePath };
46878
+ }
46879
+ let changed = false;
46880
+ const kept = [];
46881
+ for (const matcher of matchers) {
46882
+ const inner = matcher.hooks ?? [];
46883
+ const keptInner = inner.filter((h) => {
46884
+ if (typeof h.command === "string" && h.command.includes(SESSIONSTART_HOOK_SENTINEL)) {
46885
+ changed = true;
46886
+ return false;
46887
+ }
46888
+ return true;
46889
+ });
46890
+ if (keptInner.length === 0 && inner.length > 0) {
46891
+ changed = true;
46892
+ continue;
46893
+ }
46894
+ if (keptInner.length === inner.length) {
46895
+ kept.push(matcher);
46896
+ } else {
46897
+ kept.push({ ...matcher, hooks: keptInner });
46898
+ }
46899
+ }
46900
+ if (!changed) return { status: "not-found", filePath };
46901
+ const next = {
46902
+ ...settings,
46903
+ hooks: { ...settings.hooks, SessionStart: kept }
46904
+ };
46905
+ if (kept.length === 0) {
46906
+ const otherStages = Object.keys(next.hooks ?? {}).filter((k) => k !== "SessionStart");
46907
+ if (otherStages.length === 0) {
46908
+ delete next.hooks;
46909
+ } else {
46910
+ delete next.hooks.SessionStart;
46911
+ }
46912
+ }
46913
+ writeFileSync58(filePath, JSON.stringify(next, null, 2) + "\n");
46914
+ return { status: "removed", filePath };
46915
+ }
46916
+ function registerFlywheelInstallSessionStartHook(parent) {
46917
+ parent.command("install-sessionstart-hook").description(
46918
+ "Install (or --uninstall) the SessionStart context hook into .claude/settings.json. Idempotent. 4th defense layer \u2014 preloads operator state before the first prompt."
46919
+ ).option("--scope <scope>", "project (default; <cwd>/.claude/settings.json) or user (~/.claude/settings.json)", "project").option("--uninstall", "Remove the hook instead of installing it").action((opts) => {
46920
+ const scope = opts.scope === "user" ? "user" : "project";
46921
+ const filePath = settingsPathFor4(scope);
46922
+ if (opts.uninstall) {
46923
+ try {
46924
+ const r = uninstallSessionStartHook(filePath);
46925
+ switch (r.status) {
46926
+ case "removed":
46927
+ printSuccess(`SessionStart context hook removed from ${filePath}`);
46928
+ return;
46929
+ case "not-found":
46930
+ printInfo("sessionstart hook", `not found in ${filePath} \u2014 already uninstalled`);
46931
+ return;
46932
+ case "no-settings":
46933
+ printInfo("sessionstart hook", `no settings.json at ${filePath} \u2014 nothing to remove`);
46934
+ return;
46935
+ }
46936
+ } catch (err) {
46937
+ printError(`uninstall failed: ${err instanceof Error ? err.message : String(err)}`);
46938
+ process.exitCode = 1;
46939
+ }
46940
+ return;
46941
+ }
46942
+ try {
46943
+ const r = installSessionStartHook(filePath);
46944
+ switch (r.status) {
46945
+ case "installed":
46946
+ printSuccess(`SessionStart context hook installed (${scope} scope)`);
46947
+ printInfo("settings", r.filePath);
46948
+ if (r.backupPath) printInfo("backup", r.backupPath);
46949
+ printInfo("next", "open a new Claude Code session \u2014 Olam state will preload via additionalContext");
46950
+ return;
46951
+ case "already-present":
46952
+ printInfo("sessionstart hook", `already installed at ${r.filePath}`);
46953
+ return;
46954
+ case "no-op":
46955
+ printWarning(`no change made to ${r.filePath}`);
46956
+ return;
46957
+ }
46958
+ } catch (err) {
46959
+ printError(`install failed: ${err instanceof Error ? err.message : String(err)}`);
46960
+ process.exitCode = 1;
46961
+ }
46962
+ });
46963
+ }
46964
+
46670
46965
  // src/commands/flywheel/index.ts
46671
46966
  function registerFlywheel(program2) {
46672
46967
  const flywheel = program2.command("flywheel").description(
@@ -46682,6 +46977,8 @@ function registerFlywheel(program2) {
46682
46977
  registerFlywheelPing(flywheel);
46683
46978
  registerFlywheelInstallShims(flywheel);
46684
46979
  registerFlywheelMigrateOverlays(flywheel);
46980
+ registerFlywheelSessionStart(flywheel);
46981
+ registerFlywheelInstallSessionStartHook(flywheel);
46685
46982
  }
46686
46983
 
46687
46984
  // src/commands/seed.ts
@@ -47074,19 +47371,321 @@ function registerRekey(program2) {
47074
47371
  });
47075
47372
  }
47076
47373
 
47077
- // src/pleri-config.ts
47374
+ // src/commands/yolo.ts
47375
+ init_output();
47376
+ import * as childProcess2 from "node:child_process";
47078
47377
  import * as fs95 from "node:fs";
47378
+ import * as os50 from "node:os";
47079
47379
  import * as path95 from "node:path";
47380
+ import pc44 from "picocolors";
47381
+ var YOLO_BOOT_DELAY_MS = 8e3;
47382
+ var CAPTURE_DELAY_MS = 4e3;
47383
+ var TMUX_PROBE_PATHS = [
47384
+ "/opt/homebrew/Cellar/tmux/3.6a/bin/tmux",
47385
+ "/opt/homebrew/bin/tmux",
47386
+ "/usr/local/bin/tmux",
47387
+ "/usr/bin/tmux"
47388
+ ];
47389
+ var TMUX_SHIM_MARKERS = [".oh-my-zsh", ".zsh", ".bash", "nvm", "asdf"];
47390
+ function defaultRunner(cmd, args, opts) {
47391
+ const result = childProcess2.spawnSync(cmd, args, {
47392
+ encoding: "utf-8",
47393
+ cwd: opts?.cwd
47394
+ });
47395
+ return {
47396
+ status: result.status,
47397
+ stdout: typeof result.stdout === "string" ? result.stdout.trim() : "",
47398
+ stderr: typeof result.stderr === "string" ? result.stderr.trim() : ""
47399
+ };
47400
+ }
47401
+ function defaultSleeper(ms) {
47402
+ return new Promise((resolve27) => setTimeout(resolve27, ms));
47403
+ }
47404
+ function detectTmuxBinary(runner = defaultRunner) {
47405
+ for (const p of TMUX_PROBE_PATHS) {
47406
+ if (TMUX_SHIM_MARKERS.some((m) => p.includes(m))) continue;
47407
+ if (fs95.existsSync(p)) return p;
47408
+ }
47409
+ const result = runner("which", ["tmux"]);
47410
+ if (result.status === 0 && result.stdout) {
47411
+ const p = result.stdout.trim();
47412
+ if (TMUX_SHIM_MARKERS.some((m) => p.includes(m))) return null;
47413
+ return p;
47414
+ }
47415
+ return null;
47416
+ }
47417
+ function resolveWorktreeRoot(runner = defaultRunner, cwd = process.cwd()) {
47418
+ if (process.env["OLAM_TMUX_YOLO_ROOT"]) {
47419
+ return process.env["OLAM_TMUX_YOLO_ROOT"];
47420
+ }
47421
+ const rootFile = path95.join(os50.homedir(), ".olam-tmux-yolo-root");
47422
+ if (fs95.existsSync(rootFile)) {
47423
+ const line = fs95.readFileSync(rootFile, "utf-8").trim();
47424
+ if (line) return line;
47425
+ }
47426
+ const gitResult = runner("git", ["rev-parse", "--show-toplevel"], { cwd });
47427
+ if (gitResult.status !== 0 || !gitResult.stdout) {
47428
+ return path95.join(cwd, "..", path95.basename(cwd) + "-wt");
47429
+ }
47430
+ const repoRoot = gitResult.stdout.trim();
47431
+ return path95.join(path95.dirname(repoRoot), path95.basename(repoRoot) + "-wt");
47432
+ }
47433
+ function resolveYoloCommand(runner = defaultRunner) {
47434
+ const result = runner("bash", ["-lc", "command -v yolo"]);
47435
+ if (result.status === 0 && result.stdout) {
47436
+ const p = result.stdout.trim();
47437
+ if (p && !TMUX_SHIM_MARKERS.some((m) => p.includes(m))) {
47438
+ return { cmd: "yolo", usingFallback: false };
47439
+ }
47440
+ }
47441
+ return {
47442
+ cmd: "~/.local/bin/claude --dangerously-skip-permissions",
47443
+ usingFallback: true
47444
+ };
47445
+ }
47446
+ async function spawnYolo(opts) {
47447
+ const runner = opts.runner ?? defaultRunner;
47448
+ const sleeper = opts.sleeper ?? defaultSleeper;
47449
+ const cwd = opts.cwd ?? process.cwd();
47450
+ const tmux = detectTmuxBinary(runner);
47451
+ if (!tmux) {
47452
+ throw new Error(
47453
+ "tmux binary not found. Checked: " + TMUX_PROBE_PATHS.join(", ") + " and PATH. Ensure tmux is installed and not shadowed by a shell plugin."
47454
+ );
47455
+ }
47456
+ try {
47457
+ fs95.accessSync(opts.promptFile, fs95.constants.R_OK);
47458
+ } catch {
47459
+ throw new Error(
47460
+ `Prompt file not found or not readable: ${opts.promptFile}
47461
+ Create the file with your task description and try again.`
47462
+ );
47463
+ }
47464
+ const worktreeRoot = resolveWorktreeRoot(runner, cwd);
47465
+ const worktreePath = path95.join(worktreeRoot, opts.name);
47466
+ const branchCheck = runner("git", ["show-ref", "--verify", "--quiet", `refs/heads/${opts.branch}`], { cwd });
47467
+ if (branchCheck.status === 0) {
47468
+ throw new Error(
47469
+ `Branch "${opts.branch}" already exists.
47470
+ Run: olam yolo --cleanup ${opts.name} (or use --force to bypass the merged check)`
47471
+ );
47472
+ }
47473
+ if (fs95.existsSync(worktreePath)) {
47474
+ throw new Error(
47475
+ `Worktree directory already exists: ${worktreePath}
47476
+ Run: olam yolo --cleanup ${opts.name} to remove it first.`
47477
+ );
47478
+ }
47479
+ const base = opts.base ?? (() => {
47480
+ const r = runner("git", ["rev-parse", "--abbrev-ref", "HEAD"], { cwd });
47481
+ return r.status === 0 ? r.stdout.trim() : "main";
47482
+ })();
47483
+ const worktreeAdd = runner(
47484
+ "git",
47485
+ ["worktree", "add", "-b", opts.branch, worktreePath, base],
47486
+ { cwd }
47487
+ );
47488
+ if (worktreeAdd.status !== 0) {
47489
+ throw new Error(
47490
+ `git worktree add failed:
47491
+ ${worktreeAdd.stderr || worktreeAdd.stdout}`
47492
+ );
47493
+ }
47494
+ const newWindow = runner(tmux, ["new-window", "-t", "0:", "-n", opts.name, "-c", worktreePath]);
47495
+ if (newWindow.status !== 0) {
47496
+ throw new Error(
47497
+ `tmux new-window failed:
47498
+ ${newWindow.stderr}
47499
+ Is tmux running? Start a session with: tmux new-session -d -s 0`
47500
+ );
47501
+ }
47502
+ const { cmd: yoloCmd, usingFallback } = resolveYoloCommand(runner);
47503
+ await sleeper(YOLO_BOOT_DELAY_MS);
47504
+ const sendKeysArg = `${yoloCmd} "$(cat ${opts.promptFile})"`;
47505
+ const sendKeys = runner(tmux, ["send-keys", "-t", `0:${opts.name}`, sendKeysArg, "Enter"]);
47506
+ if (sendKeys.status !== 0) {
47507
+ throw new Error(`tmux send-keys failed:
47508
+ ${sendKeys.stderr}`);
47509
+ }
47510
+ await sleeper(CAPTURE_DELAY_MS);
47511
+ const capture = runner(tmux, ["capture-pane", "-t", `0:${opts.name}`, "-p"]);
47512
+ const captureText = capture.stdout ?? "";
47513
+ let captureWarning;
47514
+ const YOLO_STARTED_MARKERS = ["Cogitating", "Welcome to Claude Code", "Claude Code", "Human:", "> "];
47515
+ const started = YOLO_STARTED_MARKERS.some((m) => captureText.includes(m));
47516
+ if (!started) {
47517
+ captureWarning = "yolo may not have started \u2014 pane output does not contain expected markers. Attach to verify: tmux select-window -t 0:" + opts.name;
47518
+ }
47519
+ return {
47520
+ worktreePath,
47521
+ branch: opts.branch,
47522
+ windowName: opts.name,
47523
+ attachHint: `tmux select-window -t 0:${opts.name}`,
47524
+ captureWarning,
47525
+ yoloFallbackUsed: usingFallback
47526
+ };
47527
+ }
47528
+ function listYoloWindows(opts = {}) {
47529
+ const runner = opts.runner ?? defaultRunner;
47530
+ const cwd = opts.cwd ?? process.cwd();
47531
+ const tmux = detectTmuxBinary(runner);
47532
+ if (!tmux) return [];
47533
+ const listResult = runner(tmux, ["list-windows", "-t", "0", "-F", "#{window_name}"]);
47534
+ if (listResult.status !== 0) return [];
47535
+ const windowNames = listResult.stdout.split("\n").map((n) => n.trim()).filter(Boolean);
47536
+ const worktreeRoot = resolveWorktreeRoot(runner, cwd);
47537
+ return windowNames.map((name) => {
47538
+ const worktreePath = path95.join(worktreeRoot, name);
47539
+ return {
47540
+ name,
47541
+ worktreePath: fs95.existsSync(worktreePath) ? worktreePath : void 0
47542
+ };
47543
+ });
47544
+ }
47545
+ async function cleanupYolo(opts) {
47546
+ const runner = opts.runner ?? defaultRunner;
47547
+ const cwd = opts.cwd ?? process.cwd();
47548
+ const mainBranch = opts.mainBranch ?? "main";
47549
+ const worktreeRoot = resolveWorktreeRoot(runner, cwd);
47550
+ const worktreePath = path95.join(worktreeRoot, opts.name);
47551
+ const worktreeList = runner("git", ["worktree", "list", "--porcelain"], { cwd });
47552
+ let branch;
47553
+ if (worktreeList.status === 0) {
47554
+ const lines = worktreeList.stdout.split("\n");
47555
+ let inTarget = false;
47556
+ for (const line of lines) {
47557
+ if (line.startsWith("worktree ")) {
47558
+ inTarget = line.slice("worktree ".length).trim() === worktreePath;
47559
+ }
47560
+ if (inTarget && line.startsWith("branch ")) {
47561
+ branch = line.replace("branch refs/heads/", "").trim();
47562
+ break;
47563
+ }
47564
+ }
47565
+ }
47566
+ if (branch && !opts.force) {
47567
+ const mergedCheck = runner(
47568
+ "git",
47569
+ ["branch", "--merged", mainBranch],
47570
+ { cwd }
47571
+ );
47572
+ const mergedBranches = mergedCheck.stdout.split("\n").map((b) => b.replace(/^\*?\s*/, "").trim());
47573
+ if (!mergedBranches.includes(branch)) {
47574
+ throw new Error(
47575
+ `Branch "${branch}" is not merged into ${mainBranch}.
47576
+ Run: olam yolo --cleanup ${opts.name} --force to remove anyway.`
47577
+ );
47578
+ }
47579
+ }
47580
+ const tmux = detectTmuxBinary(runner);
47581
+ if (tmux) {
47582
+ runner(tmux, ["kill-window", "-t", `0:${opts.name}`]);
47583
+ }
47584
+ const removeArgs = opts.force ? ["worktree", "remove", "--force", worktreePath] : ["worktree", "remove", worktreePath];
47585
+ const worktreeRemove = runner("git", removeArgs, { cwd });
47586
+ if (worktreeRemove.status !== 0) {
47587
+ if (!worktreeRemove.stderr.includes("is not a worktree")) {
47588
+ printWarning(`git worktree remove: ${worktreeRemove.stderr}`);
47589
+ }
47590
+ }
47591
+ if (branch) {
47592
+ const branchDeleteArgs = opts.force ? ["branch", "-D", branch] : ["branch", "-d", branch];
47593
+ const branchDelete = runner("git", branchDeleteArgs, { cwd });
47594
+ if (branchDelete.status !== 0) {
47595
+ printWarning(`git branch delete: ${branchDelete.stderr}`);
47596
+ }
47597
+ }
47598
+ }
47599
+ function registerYolo(program2) {
47600
+ const cmd = program2.command("yolo").description(
47601
+ "Dispatch a parallel Claude Code session in a new tmux window + isolated git worktree"
47602
+ ).argument("[name]", "Short identifier for the yolo session (kebab-case)").option("--branch <branch>", "Branch to create in the worktree").option("--base <base>", "Base branch to fork from (default: current branch)").option("--prompt-file <path>", "Path to a file containing the task prompt").option("--list", "List active yolo tmux windows and matched worktree paths").option("--cleanup <name>", "Remove worktree + kill tmux window + delete branch").option("--force", "With --cleanup: bypass merged-branch check").action(
47603
+ async (name, opts) => {
47604
+ if (opts.list) {
47605
+ const windows = listYoloWindows();
47606
+ if (windows.length === 0) {
47607
+ console.log(pc44.dim("No active yolo windows found (tmux session 0)."));
47608
+ return;
47609
+ }
47610
+ printHeader(`${windows.length} yolo window(s)`);
47611
+ for (const w of windows) {
47612
+ const wt = w.worktreePath ? pc44.dim(w.worktreePath) : pc44.dim("(no worktree)");
47613
+ console.log(` ${pc44.bold(w.name.padEnd(24))} ${wt}`);
47614
+ }
47615
+ return;
47616
+ }
47617
+ if (opts.cleanup) {
47618
+ try {
47619
+ await cleanupYolo({
47620
+ name: opts.cleanup,
47621
+ force: opts.force
47622
+ });
47623
+ printSuccess(`cleaned up yolo "${opts.cleanup}"`);
47624
+ } catch (err) {
47625
+ printError(err instanceof Error ? err.message : String(err));
47626
+ process.exitCode = 1;
47627
+ }
47628
+ return;
47629
+ }
47630
+ if (!name) {
47631
+ cmd.help();
47632
+ return;
47633
+ }
47634
+ if (!opts.branch) {
47635
+ printError("--branch is required for spawn. Example: --branch feat/my-task");
47636
+ process.exitCode = 1;
47637
+ return;
47638
+ }
47639
+ if (!opts.promptFile) {
47640
+ printError(
47641
+ "--prompt-file is required for spawn. Create a file with your task description."
47642
+ );
47643
+ process.exitCode = 1;
47644
+ return;
47645
+ }
47646
+ try {
47647
+ const result = await spawnYolo({
47648
+ name,
47649
+ branch: opts.branch,
47650
+ base: opts.base,
47651
+ promptFile: opts.promptFile
47652
+ });
47653
+ printHeader("yolo dispatched");
47654
+ printInfo("Worktree", result.worktreePath);
47655
+ printInfo("Branch", result.branch);
47656
+ printInfo("Window", result.windowName);
47657
+ printInfo("Attach", result.attachHint);
47658
+ if (result.yoloFallbackUsed) {
47659
+ console.log(
47660
+ pc44.dim(
47661
+ " [note] yolo alias not found on PATH \u2014 used ~/.local/bin/claude --dangerously-skip-permissions"
47662
+ )
47663
+ );
47664
+ }
47665
+ if (result.captureWarning) {
47666
+ printWarning(result.captureWarning);
47667
+ }
47668
+ } catch (err) {
47669
+ printError(err instanceof Error ? err.message : String(err));
47670
+ process.exitCode = 1;
47671
+ }
47672
+ }
47673
+ );
47674
+ }
47675
+
47676
+ // src/pleri-config.ts
47677
+ import * as fs96 from "node:fs";
47678
+ import * as path96 from "node:path";
47080
47679
  function isPleriConfigured(configDir = process.env.OLAM_CONFIG_DIR ?? ".olam") {
47081
47680
  if (process.env.PLERI_BASE_URL) {
47082
47681
  return true;
47083
47682
  }
47084
- const configPath = path95.join(configDir, "config.yaml");
47085
- if (!fs95.existsSync(configPath)) {
47683
+ const configPath = path96.join(configDir, "config.yaml");
47684
+ if (!fs96.existsSync(configPath)) {
47086
47685
  return false;
47087
47686
  }
47088
47687
  try {
47089
- const contents = fs95.readFileSync(configPath, "utf8");
47688
+ const contents = fs96.readFileSync(configPath, "utf8");
47090
47689
  return /^[^#\n]*\bpleri:/m.test(contents);
47091
47690
  } catch {
47092
47691
  return false;
@@ -47129,6 +47728,7 @@ registerPlans(program);
47129
47728
  registerServices(program);
47130
47729
  registerSeed(program);
47131
47730
  registerRekey(program);
47731
+ registerYolo(program);
47132
47732
  registerLanes(program);
47133
47733
  registerPolicyCheck(program);
47134
47734
  registerWorldspec(program);
@@ -47172,4 +47772,5 @@ registerSkillsShadowBackups(program);
47172
47772
  registerSkillsDoctor(program);
47173
47773
  registerSkills10x(program);
47174
47774
  registerHermes(program);
47175
- program.parse();
47775
+ await program.parseAsync();
47776
+ process.exit(process.exitCode ?? 0);