@pleri/olam-cli 0.1.174 → 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.
- package/README.md +19 -0
- package/bin/olam.cjs +22 -0
- package/dist/commands/flywheel/index.d.ts.map +1 -1
- package/dist/commands/flywheel/index.js +4 -0
- package/dist/commands/flywheel/index.js.map +1 -1
- package/dist/commands/flywheel/install-sessionstart-hook.d.ts +64 -0
- package/dist/commands/flywheel/install-sessionstart-hook.d.ts.map +1 -0
- package/dist/commands/flywheel/install-sessionstart-hook.js +197 -0
- package/dist/commands/flywheel/install-sessionstart-hook.js.map +1 -0
- package/dist/commands/flywheel/session-start.d.ts +26 -0
- package/dist/commands/flywheel/session-start.d.ts.map +1 -0
- package/dist/commands/flywheel/session-start.js +119 -0
- package/dist/commands/flywheel/session-start.js.map +1 -0
- package/dist/commands/host-cp.d.ts +0 -3
- package/dist/commands/host-cp.d.ts.map +1 -1
- package/dist/commands/host-cp.js +27 -2
- package/dist/commands/host-cp.js.map +1 -1
- package/dist/commands/yolo.d.ts +99 -0
- package/dist/commands/yolo.d.ts.map +1 -0
- package/dist/commands/yolo.js +377 -0
- package/dist/commands/yolo.js.map +1 -0
- package/dist/image-digests.json +8 -8
- package/dist/index.js +808 -207
- package/dist/index.js.map +1 -1
- package/dist/lib/auth-remote.d.ts +0 -17
- package/dist/lib/auth-remote.d.ts.map +1 -1
- package/dist/lib/auth-remote.js +6 -16
- package/dist/lib/auth-remote.js.map +1 -1
- package/dist/mcp-server.js +26 -0
- package/hermes-bundle/version.json +1 -1
- package/host-cp/k8s/manifests/50-deployment.yaml +1 -1
- package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
- package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
- package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
- package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
- package/host-cp/src/bootstrap-selective.mjs +56 -0
- package/host-cp/src/plan-chat-service.mjs +51 -0
- package/host-cp/src/redirect.mjs +152 -0
- package/host-cp/src/resolver.mjs +121 -0
- package/host-cp/src/server.mjs +57 -16
- 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:
|
|
496
|
-
const fullPath = [...
|
|
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,
|
|
804
|
+
constructor(parent, value, path97, key) {
|
|
805
805
|
this._cachedPath = [];
|
|
806
806
|
this.parent = parent;
|
|
807
807
|
this.data = value;
|
|
808
|
-
this._path =
|
|
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,
|
|
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: [...
|
|
4297
|
+
path: [...path97, key],
|
|
4298
4298
|
message: `forbidden key "${key}" (prototype-pollution surface)`
|
|
4299
4299
|
});
|
|
4300
4300
|
continue;
|
|
4301
4301
|
}
|
|
4302
|
-
if (rejectSource &&
|
|
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], [...
|
|
4310
|
+
refineForbiddenKeys(value[key], [...path97, key], ctx, false);
|
|
4311
4311
|
}
|
|
4312
4312
|
}
|
|
4313
|
-
function rejectForbiddenKeys(value,
|
|
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] ${
|
|
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] ${
|
|
4322
|
+
throw new Error(`[manifest] ${path97}: top-level "source" is loader-stamped \u2014 manifests must not author it`);
|
|
4323
4323
|
}
|
|
4324
|
-
rejectForbiddenKeys(value[key], `${
|
|
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,
|
|
5519
|
-
const url2 = `${this.baseUrl}${
|
|
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,
|
|
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(
|
|
7341
|
-
const url2 = `${this.config.workerUrl}${
|
|
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(
|
|
9206
|
-
if (!
|
|
9207
|
-
throw new Error(`${label} escape: ${
|
|
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
|
|
9214
|
-
assertWithinPrefix(
|
|
9215
|
-
return
|
|
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,
|
|
9331
|
-
return p.replace(/^~(?=$|\/|\\)/,
|
|
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
|
|
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,
|
|
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
|
|
9491
|
-
const
|
|
9492
|
-
const
|
|
9493
|
-
const
|
|
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,
|
|
9526
|
+
const repoPath = expandHome2(repo.path, homedir67);
|
|
9501
9527
|
const worktreePath = path17.join(workspacePath, repo.name);
|
|
9502
|
-
if (!
|
|
9528
|
+
if (!existsSync115(repoPath))
|
|
9503
9529
|
continue;
|
|
9504
|
-
if (!
|
|
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 (!
|
|
9590
|
+
if (!existsSync115(src))
|
|
9565
9591
|
continue;
|
|
9566
9592
|
try {
|
|
9567
|
-
|
|
9568
|
-
|
|
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
|
-
|
|
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,
|
|
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)}${
|
|
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(
|
|
16380
|
+
function parseForkManifest(path97) {
|
|
16341
16381
|
let raw;
|
|
16342
16382
|
try {
|
|
16343
|
-
raw = readFileSync30(
|
|
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 ${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
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:
|
|
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(
|
|
17502
|
-
return SHIM_TARGETS.find((t) => t.basename ===
|
|
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(
|
|
17522
|
-
const target = lookupShimTarget(
|
|
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,
|
|
17643
|
+
const [bucket, basename17] = key.split("\0");
|
|
17604
17644
|
const winner = seen.get(key);
|
|
17605
17645
|
collisions.push({
|
|
17606
17646
|
bucket,
|
|
17607
|
-
basename:
|
|
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
|
|
17653
|
-
shadowBackups.push(
|
|
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
|
|
17665
|
-
fs59.renameSync(link,
|
|
17666
|
-
return
|
|
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
|
|
17720
|
+
let backup4;
|
|
17681
17721
|
if (isLink) {
|
|
17682
17722
|
fs59.unlinkSync(link);
|
|
17683
17723
|
} else if (fs59.existsSync(link)) {
|
|
17684
|
-
|
|
17724
|
+
backup4 = shadowBackup(link);
|
|
17685
17725
|
}
|
|
17686
17726
|
fs59.symlinkSync(target, link);
|
|
17687
|
-
return { created: true, shadowBackup:
|
|
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:
|
|
17750
|
+
const { created, shadowBackup: backup4 } = linkIfNeeded(artifact.sourcePath, linkPath);
|
|
17711
17751
|
if (created)
|
|
17712
17752
|
result.linked += 1;
|
|
17713
|
-
if (
|
|
17714
|
-
result.shadowBackups.push(
|
|
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
|
|
18425
|
-
if (content.includes(
|
|
18426
|
-
const list = result.get(
|
|
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(
|
|
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
|
|
19342
|
-
if (!existsSync77(
|
|
19381
|
+
const path97 = sourceConfigPath(clonePath);
|
|
19382
|
+
if (!existsSync77(path97))
|
|
19343
19383
|
return void 0;
|
|
19344
19384
|
let raw;
|
|
19345
19385
|
try {
|
|
19346
|
-
raw = readFileSync67(
|
|
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
|
|
19886
|
-
const match2 = SHADOW_BACKUP_SUFFIX_RE.exec(
|
|
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 "${
|
|
19928
|
+
throw new Error(`not a shadow-backup file (basename "${basename17}" does not match \`.shadow-backup-<epoch>\`): ${abs}`);
|
|
19889
19929
|
}
|
|
19890
|
-
const originalBasename =
|
|
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(
|
|
20511
|
-
if (DEFAULT_SKIP.has(
|
|
20550
|
+
function isSkipped(basename17, extra) {
|
|
20551
|
+
if (DEFAULT_SKIP.has(basename17))
|
|
20512
20552
|
return true;
|
|
20513
20553
|
for (const pattern of extra) {
|
|
20514
|
-
if (
|
|
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(
|
|
20979
|
+
function atomicWriteJSON(path97, value, stderr = process.stderr) {
|
|
20940
20980
|
ensureStateDir();
|
|
20941
|
-
const dir = dirname3(
|
|
20981
|
+
const dir = dirname3(path97);
|
|
20942
20982
|
if (!existsSync6(dir)) {
|
|
20943
20983
|
mkdirSync2(dir, { recursive: true });
|
|
20944
20984
|
}
|
|
20945
|
-
const tmp = `${
|
|
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,
|
|
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(
|
|
21310
|
-
super(`Archetype inheritance cycle detected: ${
|
|
21311
|
-
this.path =
|
|
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
|
|
22111
|
-
if (existsSync29(
|
|
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(
|
|
22117
|
-
chmodSync4(
|
|
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
|
|
22241
|
-
if (!existsSync29(
|
|
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", [
|
|
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(
|
|
23256
|
-
mkdirSync21(dirname22(
|
|
23257
|
-
const tmp = `${
|
|
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,
|
|
23300
|
+
renameSync6(tmp, path97);
|
|
23261
23301
|
}
|
|
23262
|
-
function readSecretAtPathOrNull(
|
|
23263
|
-
if (!existsSync32(
|
|
23264
|
-
const mode = statSync8(
|
|
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: ${
|
|
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(
|
|
23311
|
+
return readFileSync25(path97, "utf8").trim();
|
|
23272
23312
|
}
|
|
23273
|
-
function readSecretAtPath(
|
|
23274
|
-
const v = readSecretAtPathOrNull(
|
|
23313
|
+
function readSecretAtPath(path97) {
|
|
23314
|
+
const v = readSecretAtPathOrNull(path97);
|
|
23275
23315
|
if (v === null) {
|
|
23276
23316
|
throw new Error(
|
|
23277
|
-
`Secret not found at ${
|
|
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(
|
|
23283
|
-
const existing = readSecretAtPathOrNull(
|
|
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(
|
|
23326
|
+
writeSecretAtPath(path97, fresh);
|
|
23287
23327
|
return fresh;
|
|
23288
23328
|
}
|
|
23289
|
-
function readMemorySecretOrNull(
|
|
23290
|
-
return readSecretAtPathOrNull(
|
|
23329
|
+
function readMemorySecretOrNull(path97 = MEMORY_SECRET_PATH) {
|
|
23330
|
+
return readSecretAtPathOrNull(path97);
|
|
23291
23331
|
}
|
|
23292
|
-
function readMemorySecret(
|
|
23293
|
-
return readSecretAtPath(
|
|
23332
|
+
function readMemorySecret(path97 = MEMORY_SECRET_PATH) {
|
|
23333
|
+
return readSecretAtPath(path97);
|
|
23294
23334
|
}
|
|
23295
|
-
function rotateMemorySecret(
|
|
23335
|
+
function rotateMemorySecret(path97 = MEMORY_SECRET_PATH) {
|
|
23296
23336
|
const fresh = generateSecret();
|
|
23297
|
-
writeSecretAtPath(
|
|
23337
|
+
writeSecretAtPath(path97, fresh);
|
|
23298
23338
|
return fresh;
|
|
23299
23339
|
}
|
|
23300
|
-
function hasMemorySecret(
|
|
23301
|
-
return existsSync32(
|
|
23340
|
+
function hasMemorySecret(path97 = MEMORY_SECRET_PATH) {
|
|
23341
|
+
return existsSync32(path97);
|
|
23302
23342
|
}
|
|
23303
|
-
function writeCloudMemorySecret(value,
|
|
23304
|
-
writeSecretAtPath(
|
|
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
|
|
24451
|
+
const readFileSync99 = deps.readFileSync ?? fs31.readFileSync;
|
|
24412
24452
|
const writeFileSyncImpl = deps.writeFileSync ?? fs31.writeFileSync;
|
|
24413
|
-
const
|
|
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 (!
|
|
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 =
|
|
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
|
|
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 =
|
|
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:
|
|
26102
|
+
for (const { path: path97, mtimeMs } of result.newerSources) {
|
|
26063
26103
|
const when = new Date(mtimeMs).toISOString();
|
|
26064
|
-
lines.push(` \u2022 ${
|
|
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:
|
|
26444
|
-
const { default:
|
|
26445
|
-
const { default:
|
|
26446
|
-
const tp =
|
|
26447
|
-
process.env.OLAM_HOME ??
|
|
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 (!
|
|
26451
|
-
return
|
|
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:
|
|
26940
|
-
const { default:
|
|
26941
|
-
const { default:
|
|
26942
|
-
const tp =
|
|
26943
|
-
if (!
|
|
26944
|
-
const raw =
|
|
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(
|
|
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}${
|
|
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(
|
|
31157
|
-
if (
|
|
31196
|
+
function formatJsonPath(path97) {
|
|
31197
|
+
if (path97.length === 0)
|
|
31158
31198
|
return "<root>";
|
|
31159
31199
|
let out = "";
|
|
31160
|
-
for (const seg of
|
|
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(
|
|
31209
|
+
function resolveYamlLocation(path97, doc, lineCounter) {
|
|
31170
31210
|
let bestLine = 0;
|
|
31171
31211
|
let bestColumn = 0;
|
|
31172
|
-
for (let depth =
|
|
31173
|
-
const segment =
|
|
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
|
|
31431
|
+
const path97 = [];
|
|
31392
31432
|
let current = start;
|
|
31393
31433
|
while (current && !seen.has(current)) {
|
|
31394
31434
|
seen.add(current);
|
|
31395
|
-
|
|
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 =
|
|
31404
|
-
return [...
|
|
31443
|
+
const idx = path97.indexOf(current);
|
|
31444
|
+
return [...path97.slice(idx), current];
|
|
31405
31445
|
}
|
|
31406
|
-
return
|
|
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
|
|
36114
|
-
const filename =
|
|
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,
|
|
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}${
|
|
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(
|
|
37035
|
-
const raw = readFileSync48(
|
|
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 (
|
|
37273
|
-
const parsed = parseTracker(
|
|
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
|
|
37520
|
-
if (
|
|
37521
|
-
if (
|
|
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
|
|
41323
|
-
if (!
|
|
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 "${
|
|
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(
|
|
42314
|
-
const res = await fetch(`${BASE_URL}${
|
|
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
|
|
43555
|
-
if (!existsSync105(
|
|
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 ${
|
|
43597
|
+
`Could not find local-bridge-server.mjs at ${path97}. Verify packages/memory-service ships the scripts/ directory.`
|
|
43558
43598
|
);
|
|
43559
43599
|
}
|
|
43560
|
-
return
|
|
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(
|
|
43919
|
-
const sourcePath = join98(sourceDir,
|
|
43920
|
-
const targetPath = join98(targetDir,
|
|
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:
|
|
43970
|
+
return { basename: basename17, action: "written", targetPath };
|
|
43931
43971
|
}
|
|
43932
43972
|
const existing = readFileSync86(targetPath, "utf8");
|
|
43933
43973
|
if (existing === newContent) {
|
|
43934
|
-
return { basename:
|
|
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:
|
|
43982
|
+
return { basename: basename17, action: "force-overwritten", targetPath, backupPath };
|
|
43943
43983
|
}
|
|
43944
|
-
return { basename:
|
|
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
|
|
43981
|
-
const result = installOne2(
|
|
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(
|
|
44063
|
-
return `http://127.0.0.1:${port()}${
|
|
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
|
|
45329
|
-
const lockDir = dirname59(
|
|
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(
|
|
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] ${
|
|
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(
|
|
45508
|
+
function validatePlan(path97) {
|
|
45469
45509
|
let stat;
|
|
45470
45510
|
try {
|
|
45471
|
-
stat = statSync30(
|
|
45511
|
+
stat = statSync30(path97);
|
|
45472
45512
|
} catch (err) {
|
|
45473
|
-
return { ok: false, message: `FAIL cannot stat ${
|
|
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 ${
|
|
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(
|
|
45520
|
+
text = readFileSync90(path97, "utf8");
|
|
45481
45521
|
} catch (err) {
|
|
45482
|
-
return { ok: false, message: `FAIL cannot read ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
45559
|
+
return { ok: false, message: `FAIL ${path97}: ${errors.join("; ")}` };
|
|
45520
45560
|
}
|
|
45521
|
-
const lines = [`PASS ${
|
|
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
|
|
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(
|
|
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/
|
|
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 =
|
|
47085
|
-
if (!
|
|
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 =
|
|
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.
|
|
47775
|
+
await program.parseAsync();
|
|
47776
|
+
process.exit(process.exitCode ?? 0);
|