@pleri/olam-cli 0.1.186 → 0.1.188
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ask/knowledge-pack-builder.d.ts.map +1 -1
- package/dist/ask/knowledge-pack-builder.js +5 -0
- package/dist/ask/knowledge-pack-builder.js.map +1 -1
- package/dist/ask/knowledge-pack.generated.d.ts.map +1 -1
- package/dist/ask/knowledge-pack.generated.js +406 -22
- package/dist/ask/knowledge-pack.generated.js.map +1 -1
- package/dist/commands/auth-status.js +2 -2
- package/dist/commands/auth-status.js.map +1 -1
- package/dist/commands/auth.js +1 -1
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/create.d.ts.map +1 -1
- package/dist/commands/create.js +4 -0
- package/dist/commands/create.js.map +1 -1
- package/dist/commands/install.js +2 -2
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/services.d.ts.map +1 -1
- package/dist/commands/services.js +12 -0
- package/dist/commands/services.js.map +1 -1
- package/dist/commands/setup.js +1 -1
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +4 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/image-digests.json +8 -8
- package/dist/index.js +788 -368
- package/dist/lib/health-probes.d.ts +14 -0
- package/dist/lib/health-probes.d.ts.map +1 -1
- package/dist/lib/health-probes.js +41 -3
- package/dist/lib/health-probes.js.map +1 -1
- package/dist/mcp-server.js +95 -27
- 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/chunks-electric/10-serviceaccount.yaml +8 -0
- package/host-cp/k8s/manifests/chunks-electric/20-rbac.yaml +27 -0
- package/host-cp/k8s/manifests/chunks-electric/30-configmap.yaml +23 -0
- package/host-cp/k8s/manifests/chunks-electric/45-pvc.yaml +19 -0
- package/host-cp/k8s/manifests/chunks-electric/50-deployment.yaml +84 -0
- package/host-cp/k8s/manifests/chunks-electric/60-service.yaml +17 -0
- package/host-cp/k8s/manifests/chunks-postgres/10-serviceaccount.yaml +8 -0
- package/host-cp/k8s/manifests/chunks-postgres/20-rbac.yaml +29 -0
- package/host-cp/k8s/manifests/chunks-postgres/30-configmap.yaml +185 -0
- package/host-cp/k8s/manifests/chunks-postgres/45-pvc.yaml +24 -0
- package/host-cp/k8s/manifests/chunks-postgres/50-deployment.yaml +101 -0
- package/host-cp/k8s/manifests/chunks-postgres/60-service.yaml +24 -0
- 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/k8s/manifests/plan-chat-service/10-serviceaccount.yaml +8 -0
- package/host-cp/k8s/manifests/plan-chat-service/20-rbac.yaml +29 -0
- package/host-cp/k8s/manifests/plan-chat-service/30-configmap.yaml +36 -0
- package/host-cp/k8s/manifests/plan-chat-service/45-pvc.yaml +24 -0
- package/host-cp/k8s/manifests/plan-chat-service/50-deployment.yaml +135 -0
- package/host-cp/k8s/manifests/plan-chat-service/60-service.yaml +17 -0
- package/host-cp/src/plan-chat-service.mjs +216 -0
- package/host-cp/src/pr-cache.mjs +11 -2
- package/host-cp/src/server.mjs +36 -20
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5581,7 +5581,8 @@ var init_client = __esm({
|
|
|
5581
5581
|
|
|
5582
5582
|
// ../core/dist/auth/container.js
|
|
5583
5583
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
5584
|
-
import { existsSync as existsSync10 } from "node:fs";
|
|
5584
|
+
import { chmodSync as chmodSync2, existsSync as existsSync10, mkdtempSync, rmSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
5585
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
5585
5586
|
import * as path9 from "node:path";
|
|
5586
5587
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
5587
5588
|
function resolveAuthServicePath() {
|
|
@@ -5671,28 +5672,41 @@ var init_container = __esm({
|
|
|
5671
5672
|
/**
|
|
5672
5673
|
* `docker run` the auth container. Injects the shared secret so every
|
|
5673
5674
|
* /credentials* request must present X-Olam-Secret to succeed.
|
|
5675
|
+
*
|
|
5676
|
+
* The secret is written to a 0600-permissioned temp file and passed via
|
|
5677
|
+
* `--env-file` so it never appears in `ps aux` / `/proc/<pid>/cmdline`
|
|
5678
|
+
* during the spawn window.
|
|
5674
5679
|
*/
|
|
5675
5680
|
runContainer() {
|
|
5676
5681
|
const secret = getOrCreateSecret();
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
"
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5682
|
+
const tmpDir = mkdtempSync(path9.join(tmpdir2(), "olam-auth-"));
|
|
5683
|
+
const envFilePath = path9.join(tmpDir, "env");
|
|
5684
|
+
writeFileSync6(envFilePath, `OLAM_AUTH_SECRET=${secret}
|
|
5685
|
+
`, { mode: 384 });
|
|
5686
|
+
chmodSync2(envFilePath, 384);
|
|
5687
|
+
try {
|
|
5688
|
+
execFileSync("docker", [
|
|
5689
|
+
"run",
|
|
5690
|
+
"--detach",
|
|
5691
|
+
"--name",
|
|
5692
|
+
this.containerName,
|
|
5693
|
+
"--restart",
|
|
5694
|
+
"unless-stopped",
|
|
5695
|
+
"--publish",
|
|
5696
|
+
`${this.port}:9999`,
|
|
5697
|
+
"--volume",
|
|
5698
|
+
`${this.volume}:/auth-data`,
|
|
5699
|
+
"--env",
|
|
5700
|
+
`AUTH_BIND=0.0.0.0`,
|
|
5701
|
+
"--env",
|
|
5702
|
+
`AUTH_DATA_DIR=/auth-data`,
|
|
5703
|
+
"--env-file",
|
|
5704
|
+
envFilePath,
|
|
5705
|
+
this.imageTag
|
|
5706
|
+
], { stdio: "pipe" });
|
|
5707
|
+
} finally {
|
|
5708
|
+
rmSync(tmpDir, { recursive: true, force: true });
|
|
5709
|
+
}
|
|
5696
5710
|
}
|
|
5697
5711
|
stop() {
|
|
5698
5712
|
const current = this.status();
|
|
@@ -7701,7 +7715,7 @@ async function probeAuthVault(olamHomeOverride) {
|
|
|
7701
7715
|
return {
|
|
7702
7716
|
ok: false,
|
|
7703
7717
|
message: `auth vault missing at ${vaultPath}`,
|
|
7704
|
-
remedy: "Run `olam
|
|
7718
|
+
remedy: "Run `olam services up && olam auth login` to provision the vault."
|
|
7705
7719
|
};
|
|
7706
7720
|
}
|
|
7707
7721
|
let parsed;
|
|
@@ -7711,14 +7725,14 @@ async function probeAuthVault(olamHomeOverride) {
|
|
|
7711
7725
|
return {
|
|
7712
7726
|
ok: false,
|
|
7713
7727
|
message: `auth vault malformed: ${err.message}`,
|
|
7714
|
-
remedy: "Inspect the accounts.json file; restore from backup or re-run `olam
|
|
7728
|
+
remedy: "Inspect the accounts.json file; restore from backup or re-run `olam services up`."
|
|
7715
7729
|
};
|
|
7716
7730
|
}
|
|
7717
7731
|
if (!Array.isArray(parsed)) {
|
|
7718
7732
|
return {
|
|
7719
7733
|
ok: false,
|
|
7720
7734
|
message: "auth vault malformed: expected JSON array at top level",
|
|
7721
|
-
remedy: "Restore the vault from backup or re-run `olam
|
|
7735
|
+
remedy: "Restore the vault from backup or re-run `olam services up && olam auth login`."
|
|
7722
7736
|
};
|
|
7723
7737
|
}
|
|
7724
7738
|
const accounts = parsed.filter((a) => a !== null && typeof a === "object");
|
|
@@ -7766,7 +7780,8 @@ async function probeKgStorage(olamHomeOverride) {
|
|
|
7766
7780
|
if (totalBytes >= SOFT_CAP_BYTES) {
|
|
7767
7781
|
return {
|
|
7768
7782
|
ok: true,
|
|
7769
|
-
message: `KG storage ${formatBytes(totalBytes)} (soft-warn \u2014 exceeds 1.5 GB; consider pruning)
|
|
7783
|
+
message: `KG storage ${formatBytes(totalBytes)} (soft-warn \u2014 exceeds 1.5 GB; consider pruning)`,
|
|
7784
|
+
remedy: "Prune stale pristines: `rm -rf ~/.olam/kg/<workspace>` or raise OLAM_KG_SOFT_CAP."
|
|
7770
7785
|
};
|
|
7771
7786
|
}
|
|
7772
7787
|
return { ok: true, message: `KG storage ${formatBytes(totalBytes)} (under cap)` };
|
|
@@ -21693,12 +21708,12 @@ function nextStepsFor(archetype) {
|
|
|
21693
21708
|
];
|
|
21694
21709
|
case "bootstrapper":
|
|
21695
21710
|
return [
|
|
21696
|
-
"Start the auth container: `olam
|
|
21711
|
+
"Start the auth container: `olam services up`, then `olam auth login`.",
|
|
21697
21712
|
"For Cloudflare deployments: `cd packages/cloudflare-worker && pnpm wrangler deploy`."
|
|
21698
21713
|
];
|
|
21699
21714
|
case "admin":
|
|
21700
21715
|
return [
|
|
21701
|
-
"Start the auth container: `olam
|
|
21716
|
+
"Start the auth container: `olam services up`, then `olam auth login`.",
|
|
21702
21717
|
"Curate workspaces: `olam workspace add <name> --from-config`.",
|
|
21703
21718
|
"Assign narrower archetypes to teammates (CF side, once slice C lands): use `role.manage`."
|
|
21704
21719
|
];
|
|
@@ -21893,8 +21908,8 @@ import {
|
|
|
21893
21908
|
existsSync as existsSync30,
|
|
21894
21909
|
mkdirSync as mkdirSync19,
|
|
21895
21910
|
readdirSync as readdirSync9,
|
|
21896
|
-
writeFileSync as
|
|
21897
|
-
chmodSync as
|
|
21911
|
+
writeFileSync as writeFileSync16,
|
|
21912
|
+
chmodSync as chmodSync5
|
|
21898
21913
|
} from "node:fs";
|
|
21899
21914
|
import { join as join36 } from "node:path";
|
|
21900
21915
|
import { homedir as homedir21, platform } from "node:os";
|
|
@@ -22010,7 +22025,7 @@ init_install_root();
|
|
|
22010
22025
|
|
|
22011
22026
|
// src/lib/k8s-secret-render.ts
|
|
22012
22027
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
22013
|
-
import { existsSync as existsSync28, readFileSync as readFileSync24, writeFileSync as
|
|
22028
|
+
import { existsSync as existsSync28, readFileSync as readFileSync24, writeFileSync as writeFileSync15, mkdirSync as mkdirSync18, chmodSync as chmodSync4, renameSync as renameSync5 } from "node:fs";
|
|
22014
22029
|
import { join as join34, dirname as dirname21 } from "node:path";
|
|
22015
22030
|
import { randomBytes as randomBytes6 } from "node:crypto";
|
|
22016
22031
|
var K8S_SECRETS_STATE_PATH = join34(OLAM_HOME, "k8s-secrets-state.json");
|
|
@@ -22110,8 +22125,8 @@ var defaultRunGhTokenCmd = () => {
|
|
|
22110
22125
|
var defaultReadFile = (p, enc) => readFileSync24(p, enc);
|
|
22111
22126
|
var defaultWriteFile = (p, data, mode) => {
|
|
22112
22127
|
mkdirSync18(dirname21(p), { recursive: true });
|
|
22113
|
-
|
|
22114
|
-
|
|
22128
|
+
writeFileSync15(p, data, { encoding: "utf8", mode });
|
|
22129
|
+
chmodSync4(p, mode);
|
|
22115
22130
|
};
|
|
22116
22131
|
var defaultFileExists = (p) => existsSync28(p);
|
|
22117
22132
|
function readSecretsState(statePath = K8S_SECRETS_STATE_PATH) {
|
|
@@ -22128,8 +22143,8 @@ function readSecretsState(statePath = K8S_SECRETS_STATE_PATH) {
|
|
|
22128
22143
|
function writeSecretsState(state, statePath = K8S_SECRETS_STATE_PATH) {
|
|
22129
22144
|
mkdirSync18(dirname21(statePath), { recursive: true });
|
|
22130
22145
|
const tmp = `${statePath}.tmp.${process.pid}`;
|
|
22131
|
-
|
|
22132
|
-
|
|
22146
|
+
writeFileSync15(tmp, JSON.stringify(state, null, 2) + "\n", { encoding: "utf8", mode: 384 });
|
|
22147
|
+
chmodSync4(tmp, 384);
|
|
22133
22148
|
renameSync5(tmp, statePath);
|
|
22134
22149
|
}
|
|
22135
22150
|
function resolveSourceValue(source, olamHome5, reuseFromState, rotate, deps) {
|
|
@@ -22497,8 +22512,8 @@ function ensureSecrets() {
|
|
|
22497
22512
|
continue;
|
|
22498
22513
|
}
|
|
22499
22514
|
const hex = randomBytes7(32).toString("hex");
|
|
22500
|
-
|
|
22501
|
-
|
|
22515
|
+
writeFileSync16(path101, hex + "\n", { encoding: "utf8", mode: 384 });
|
|
22516
|
+
chmodSync5(path101, 384);
|
|
22502
22517
|
printSuccess(`generated ~/.olam/${name}`);
|
|
22503
22518
|
}
|
|
22504
22519
|
}
|
|
@@ -23647,7 +23662,7 @@ import { homedir as homedir24 } from "node:os";
|
|
|
23647
23662
|
import { join as join41 } from "node:path";
|
|
23648
23663
|
|
|
23649
23664
|
// src/lib/memory-secret.ts
|
|
23650
|
-
import { existsSync as existsSync33, mkdirSync as mkdirSync22, readFileSync as readFileSync27, statSync as statSync8, writeFileSync as
|
|
23665
|
+
import { existsSync as existsSync33, mkdirSync as mkdirSync22, readFileSync as readFileSync27, statSync as statSync8, writeFileSync as writeFileSync18, renameSync as renameSync6, chmodSync as chmodSync7 } from "node:fs";
|
|
23651
23666
|
import { homedir as homedir23 } from "node:os";
|
|
23652
23667
|
import { join as join40, dirname as dirname23 } from "node:path";
|
|
23653
23668
|
import { randomBytes as randomBytes8 } from "node:crypto";
|
|
@@ -23660,8 +23675,8 @@ function generateSecret() {
|
|
|
23660
23675
|
function writeSecretAtPath(path101, value) {
|
|
23661
23676
|
mkdirSync22(dirname23(path101), { recursive: true });
|
|
23662
23677
|
const tmp = `${path101}.tmp.${process.pid}`;
|
|
23663
|
-
|
|
23664
|
-
|
|
23678
|
+
writeFileSync18(tmp, value, { mode: 384 });
|
|
23679
|
+
chmodSync7(tmp, 384);
|
|
23665
23680
|
renameSync6(tmp, path101);
|
|
23666
23681
|
}
|
|
23667
23682
|
function readSecretAtPathOrNull(path101) {
|
|
@@ -24404,6 +24419,10 @@ async function servicesUp() {
|
|
|
24404
24419
|
if (!ready) {
|
|
24405
24420
|
printError(`olam-auth started but /health did not respond within ${MCP_AUTH_HEALTH_TIMEOUT_MS / 1e3}s.`);
|
|
24406
24421
|
dumpContainerLogs("olam-auth");
|
|
24422
|
+
printError("\nTry:");
|
|
24423
|
+
printError(" - olam doctor # check service prereqs");
|
|
24424
|
+
printError(" - docker logs olam-auth # full logs");
|
|
24425
|
+
printError(" - docker restart olam-auth # restart");
|
|
24407
24426
|
return { exitCode: 1 };
|
|
24408
24427
|
}
|
|
24409
24428
|
printSuccess("olam-auth started");
|
|
@@ -24422,6 +24441,10 @@ async function servicesUp() {
|
|
|
24422
24441
|
if (!ready) {
|
|
24423
24442
|
printError(`olam-mcp-auth started but /health did not respond within ${MCP_AUTH_HEALTH_TIMEOUT_MS / 1e3}s.`);
|
|
24424
24443
|
dumpContainerLogs("olam-mcp-auth");
|
|
24444
|
+
printError("\nTry:");
|
|
24445
|
+
printError(" - olam doctor # check service prereqs");
|
|
24446
|
+
printError(" - docker logs olam-mcp-auth # full logs");
|
|
24447
|
+
printError(" - docker restart olam-mcp-auth # restart");
|
|
24425
24448
|
return { exitCode: 1 };
|
|
24426
24449
|
}
|
|
24427
24450
|
printSuccess("olam-mcp-auth started");
|
|
@@ -24488,6 +24511,10 @@ async function servicesUp() {
|
|
|
24488
24511
|
`olam-memory-service started but /agentmemory/livez did not respond within ${MEMORY_SERVICE_HEALTH_TIMEOUT_MS / 1e3}s.`
|
|
24489
24512
|
);
|
|
24490
24513
|
dumpContainerLogs("olam-memory-service");
|
|
24514
|
+
printError("\nTry:");
|
|
24515
|
+
printError(" - olam doctor # check service prereqs");
|
|
24516
|
+
printError(" - docker logs olam-memory-service # full logs");
|
|
24517
|
+
printError(" - docker restart olam-memory-service # restart");
|
|
24491
24518
|
return { exitCode: 1 };
|
|
24492
24519
|
}
|
|
24493
24520
|
printSuccess("olam-memory-service started");
|
|
@@ -26449,7 +26476,7 @@ ${pc12.dim("Tip: set ANTHROPIC_BASE_URL=" + baseUrl.replace(/\/+$/, "") + "/v1/p
|
|
|
26449
26476
|
process.exitCode = 1;
|
|
26450
26477
|
return;
|
|
26451
26478
|
}
|
|
26452
|
-
printError("Auth container is not reachable. Run `olam
|
|
26479
|
+
printError("Auth container is not reachable. Run `olam services up` first.");
|
|
26453
26480
|
process.exitCode = 1;
|
|
26454
26481
|
return;
|
|
26455
26482
|
}
|
|
@@ -26865,20 +26892,16 @@ codes are explicit: \`3\` = pull failed, \`4\` = protocol mismatch.
|
|
|
26865
26892
|
|
|
26866
26893
|
## Quick start
|
|
26867
26894
|
|
|
26895
|
+
**Two paths: Kubernetes (default, full-featured) or Docker Compose (lighter, for CI).**
|
|
26896
|
+
|
|
26897
|
+
### Kubernetes (recommended)
|
|
26898
|
+
|
|
26868
26899
|
\`\`\`bash
|
|
26869
26900
|
curl -fsSL https://olam.bar.dev/install | sh
|
|
26870
26901
|
olam setup
|
|
26871
26902
|
\`\`\`
|
|
26872
26903
|
|
|
26873
|
-
|
|
26874
|
-
|
|
26875
|
-
The setup wizard is **idempotent** \u2014 re-running skips steps that are already complete.
|
|
26876
|
-
|
|
26877
|
-
After setup, every world is one call:
|
|
26878
|
-
|
|
26879
|
-
\`\`\`bash
|
|
26880
|
-
olam create --name my-world --task "audit the auth module for SSRF"
|
|
26881
|
-
\`\`\`
|
|
26904
|
+
The installer puts \`@pleri/olam-cli\` on your PATH (requires Node.js \u2265 20 and npm). \`olam setup\` installs k3d (if absent), creates a local Kubernetes cluster named \`olam-dev\`, and brings up the full peripheral stack (host-cp, auth-service, mcp-auth-service, kg-service, memory-service). Works on macOS and Linux. No source checkout required. The setup wizard is **idempotent** \u2014 re-running skips steps that are already complete.
|
|
26882
26905
|
|
|
26883
26906
|
Full setup guide (prereqs, observability, troubleshooting):
|
|
26884
26907
|
[\`docs/onboarding/k3s-mode-setup.md\`](./docs/onboarding/k3s-mode-setup.md).
|
|
@@ -26896,6 +26919,16 @@ This runs three host containers (auth, mcp-auth, kg-service) via docker compose
|
|
|
26896
26919
|
|
|
26897
26920
|
Full setup guide for compose mode: [\`docs/onboarding/fresh-machine-setup.md\`](./docs/onboarding/fresh-machine-setup.md).
|
|
26898
26921
|
|
|
26922
|
+
### Create your first world
|
|
26923
|
+
|
|
26924
|
+
After setup completes, every world is one call:
|
|
26925
|
+
|
|
26926
|
+
\`\`\`bash
|
|
26927
|
+
olam create --name my-world --task "audit the auth module for SSRF"
|
|
26928
|
+
\`\`\`
|
|
26929
|
+
|
|
26930
|
+
Open the dashboard URL in your browser \u2014 you'll see the world provisioning, credentials flowing in from the vault, and your task dispatching to an in-world Claude session.
|
|
26931
|
+
|
|
26899
26932
|
---
|
|
26900
26933
|
|
|
26901
26934
|
## Setup
|
|
@@ -27475,6 +27508,7 @@ Source: \`docs/ONBOARDING.md\`
|
|
|
27475
27508
|
|
|
27476
27509
|
- **Docker daemon** running (Docker Desktop, or colima on macOS)
|
|
27477
27510
|
- **Node.js \u2265 20** (\`node --version\`)
|
|
27511
|
+
- **GitHub CLI authenticated** (\`gh auth login\`) \u2014 \`olam setup\` uses \`gh auth token\` to create a GHCR pull secret; skipping this fails on first image pull
|
|
27478
27512
|
- **Claude Code** (\`claude --version\`) \u2014 authenticated via \`claude auth login\`
|
|
27479
27513
|
- **Git** with SSH key configured for your repos
|
|
27480
27514
|
|
|
@@ -27485,7 +27519,7 @@ Source: \`docs/ONBOARDING.md\`
|
|
|
27485
27519
|
No source checkout required \u2014 the CLI publishes to npm:
|
|
27486
27520
|
|
|
27487
27521
|
\`\`\`bash
|
|
27488
|
-
curl -fsSL https://olam.bar.dev/install | sh # installs @pleri/olam-cli on PATH
|
|
27522
|
+
curl -fsSL https://olam.bar.dev/install | sh # installs @pleri/olam-cli on PATH (PLERI is the GitHub org & npm scope)
|
|
27489
27523
|
olam setup # k3d cluster + full peripheral stack
|
|
27490
27524
|
\`\`\`
|
|
27491
27525
|
|
|
@@ -27496,7 +27530,15 @@ mcp-auth-service, kg-service, and memory-service. Pass
|
|
|
27496
27530
|
no cluster). Full guide:
|
|
27497
27531
|
[\`docs/onboarding/k3s-mode-setup.md\`](onboarding/k3s-mode-setup.md).
|
|
27498
27532
|
|
|
27499
|
-
## 2.
|
|
27533
|
+
## 2. Verify your setup (1 minute)
|
|
27534
|
+
|
|
27535
|
+
\`\`\`bash
|
|
27536
|
+
olam doctor # runs 8\u201323 checks: auth, services, vault, network
|
|
27537
|
+
\`\`\`
|
|
27538
|
+
|
|
27539
|
+
This diagnoses common issues (Docker daemon, images, credentials, etc.). Any FAIL row shows an actionable remedy \u2014 fix and re-run until all rows PASS.
|
|
27540
|
+
|
|
27541
|
+
## 3. Register the MCP server (1 minute)
|
|
27500
27542
|
|
|
27501
27543
|
\`\`\`bash
|
|
27502
27544
|
olam mcp install # default --scope=user
|
|
@@ -27509,7 +27551,7 @@ worlds directly. Core tools: \`olam_create\`, \`olam_dispatch\`,
|
|
|
27509
27551
|
\`olam_enter\`, \`olam_crystallize\`, \`olam_pr_*\`. Restart Claude Code and
|
|
27510
27552
|
verify with \`claude mcp list\` (look for \`olam\`).
|
|
27511
27553
|
|
|
27512
|
-
##
|
|
27554
|
+
## 4. Configure your repos (2 minutes)
|
|
27513
27555
|
|
|
27514
27556
|
Point Olam at the repos a world should clone. Use the interactive
|
|
27515
27557
|
wizard:
|
|
@@ -27524,7 +27566,7 @@ world-runner tier (\`docker\` | \`cloudflare\` | \`cloudflare-isolate\`). See
|
|
|
27524
27566
|
[\`docs/architecture/config-spec.md\`](architecture/config-spec.md) for
|
|
27525
27567
|
the full schema.
|
|
27526
27568
|
|
|
27527
|
-
##
|
|
27569
|
+
## 5. Create your first world (2 minutes)
|
|
27528
27570
|
|
|
27529
27571
|
In Claude Code, say:
|
|
27530
27572
|
|
|
@@ -27536,9 +27578,9 @@ Claude will:
|
|
|
27536
27578
|
1. Create a Docker container (or CF Sandbox) with your repo cloned
|
|
27537
27579
|
2. Set up git worktrees for isolation
|
|
27538
27580
|
3. Boot the in-world Claude session and auto-dispatch the task
|
|
27539
|
-
4. Return the Host CP dashboard URL (\`http://127.0.0.1:
|
|
27581
|
+
4. Return the Host CP dashboard URL (\`http://127.0.0.1:19001\`)
|
|
27540
27582
|
|
|
27541
|
-
##
|
|
27583
|
+
## 6. Dispatch a task (1 minute)
|
|
27542
27584
|
|
|
27543
27585
|
\`\`\`
|
|
27544
27586
|
Dispatch to the world: investigate and fix the session timeout issue
|
|
@@ -27546,7 +27588,7 @@ Dispatch to the world: investigate and fix the session timeout issue
|
|
|
27546
27588
|
|
|
27547
27589
|
Claude Code runs autonomously inside the world. Every tool call, every decision, every exploration is captured as a thought node.
|
|
27548
27590
|
|
|
27549
|
-
##
|
|
27591
|
+
## 7. Watch it work (ongoing)
|
|
27550
27592
|
|
|
27551
27593
|
**Dashboard:** Open the Host CP URL from step 4. You'll see:
|
|
27552
27594
|
- the **seed of thought** pinned at the top (the immutable task)
|
|
@@ -27561,7 +27603,7 @@ Claude Code runs autonomously inside the world. Every tool call, every decision,
|
|
|
27561
27603
|
What is the world thinking right now?
|
|
27562
27604
|
\`\`\`
|
|
27563
27605
|
|
|
27564
|
-
##
|
|
27606
|
+
## 8. Clean up
|
|
27565
27607
|
|
|
27566
27608
|
\`\`\`
|
|
27567
27609
|
Crystallize and destroy the world
|
|
@@ -27583,7 +27625,7 @@ after \`olam setup\`):
|
|
|
27583
27625
|
\`\`\`bash
|
|
27584
27626
|
olam create --name login-fix --repos my-project --task "Fix session timeout"
|
|
27585
27627
|
olam dispatch login-fix "investigate and fix the session timeout"
|
|
27586
|
-
olam observe login-fix #
|
|
27628
|
+
olam observe login-fix # Alternative: \`olam enter login-fix\` for a shell inside the world (until \`olam observe\` ships)
|
|
27587
27629
|
olam status login-fix
|
|
27588
27630
|
olam crystallize login-fix # requires PLERI; otherwise no-op (exit 2)
|
|
27589
27631
|
olam destroy login-fix # accepts the world ID or name
|
|
@@ -27621,11 +27663,38 @@ refresh token never leaves the service.
|
|
|
27621
27663
|
|
|
27622
27664
|
| Problem | Fix |
|
|
27623
27665
|
|---------|-----|
|
|
27666
|
+
| Something not working | Run \`olam doctor\` \u2014 it diagnoses the setup and shows remedies for each issue |
|
|
27624
27667
|
| "Docker not running" | Start Docker Desktop |
|
|
27625
27668
|
| "No Claude credentials" | Run \`claude auth login\` on the host |
|
|
27669
|
+
| "GHCR pull secret failed" or "401 unauthorized" on first \`olam setup\` | Run \`gh auth login\` and verify with \`gh auth status\` |
|
|
27626
27670
|
| Dashboard shows empty | Wait for the first dispatch to generate thoughts |
|
|
27627
27671
|
| "Port already in use" | Another world is running. Use \`olam list\` to check |
|
|
27628
27672
|
| Session seems stuck | Use \`olam enter <world>\` to open the terminal and check |
|
|
27673
|
+
| **Blank white page at \`localhost:19001\`** | SPA dist not built. Run \`cd packages/host-cp && npm run build:spa\` from the repo root (or just \`npm start\` \u2014 the \`prestart\` hook does it automatically). |
|
|
27674
|
+
| Cloud toggle missing in SPA | Both \`OLAM_CLOUD_URL\` and \`OLAM_SHOWCASE_PASSWORD\` must be set. If only one is set the server logs a \`[cloud]\` warning at startup. |
|
|
27675
|
+
|
|
27676
|
+
## Bare-node / source-checkout mode
|
|
27677
|
+
|
|
27678
|
+
If you are running host-cp directly from source (not via \`olam setup\`
|
|
27679
|
+
or a pulled Docker image), you need to build the SPA before first boot:
|
|
27680
|
+
|
|
27681
|
+
\`\`\`bash
|
|
27682
|
+
# From the repo root:
|
|
27683
|
+
cd packages/host-cp
|
|
27684
|
+
npm run build:spa # builds plan-chat-spa and stages it into packages/host-cp/dist/
|
|
27685
|
+
npm start # prestart hook runs check:spa first; rebuilds if dist is stale
|
|
27686
|
+
\`\`\`
|
|
27687
|
+
|
|
27688
|
+
\`npm start\` runs \`check:spa\` first. If \`dist/\` is already populated and
|
|
27689
|
+
self-consistent (every asset in \`index.html\` is present on disk) it skips
|
|
27690
|
+
the build and starts immediately. If not, it calls \`build:spa\` to rebuild.
|
|
27691
|
+
|
|
27692
|
+
The \`build:spa\` script triggers a full \`npm run build:ci\` + \`vite build\`
|
|
27693
|
+
chain on a cold checkout (takes ~60s the first time; subsequent runs skip
|
|
27694
|
+
the vite build if \`packages/plan-chat-spa/dist/client/\` is already populated).
|
|
27695
|
+
|
|
27696
|
+
**This is not required when using \`olam setup\`** \u2014 the Docker image has the
|
|
27697
|
+
SPA baked in and host-cp never touches the local \`dist/\` directory.
|
|
27629
27698
|
|
|
27630
27699
|
## Architecture
|
|
27631
27700
|
|
|
@@ -27780,16 +27849,18 @@ olam skills source list
|
|
|
27780
27849
|
|
|
27781
27850
|
---
|
|
27782
27851
|
|
|
27783
|
-
## 5. Start the memory
|
|
27852
|
+
## 5. Start the memory service (Docker container)
|
|
27784
27853
|
|
|
27785
|
-
The memory-
|
|
27854
|
+
The memory-service is a Docker container (managed by \`olam services\`) that serves \`127.0.0.1:3111/agentmemory/livez\`. When it's running, \`olam skills sync\` will inject the olam-meta-memory-recall + olam-meta-memory-classify hook blocks into \`~/.claude/settings.json\`. When it's NOT running, the strip half of the auto-migration still fires but no olam-meta blocks land \u2014 meaning operator gets no recall/classify behavior.
|
|
27786
27855
|
|
|
27787
27856
|
\`\`\`bash
|
|
27788
27857
|
olam memory secret # \u2192 shows the bearer at ~/.olam/memory-secret (auto-generated on first run)
|
|
27789
|
-
olam memory start # \u2192 starts the
|
|
27790
|
-
olam memory status # \u2192
|
|
27858
|
+
olam memory start # \u2192 starts the olam-memory-service container; polls livez until ready
|
|
27859
|
+
olam memory status # \u2192 container state + livez + secret-set check
|
|
27791
27860
|
\`\`\`
|
|
27792
27861
|
|
|
27862
|
+
**Note:** \`~/.olam/memory-secret\` is used with the Docker Compose substrate (this guide). For Kubernetes, the file is \`~/.olam/memory-bearer-secret\`. They are the same logical service in different deployment substrates.
|
|
27863
|
+
|
|
27793
27864
|
Sanity check the live probe:
|
|
27794
27865
|
|
|
27795
27866
|
\`\`\`bash
|
|
@@ -27917,6 +27988,7 @@ If the recall hook doesn't fire, run \`olam memory status\` to confirm the bridg
|
|
|
27917
27988
|
## What's NOT in this doc
|
|
27918
27989
|
|
|
27919
27990
|
- Setting up Cloudflare-substrate worlds (separate doc: \`docs/architecture/cf-worlds-spec.md\`).
|
|
27991
|
+
- **Cloud-mode (optional)**: if you want dispatches to run on Cloudflare Sandboxes instead of local Docker, follow [plan-cloud-mode-setup.md](../runbooks/plan-cloud-mode-setup.md) to set \`OLAM_CLOUD_URL\` + \`OLAM_SHOWCASE_PASSWORD\` on host-cp.
|
|
27920
27992
|
- PLERI thought-graph integration (separate setup; skip-pleri is fine for most operators).
|
|
27921
27993
|
- Per-project skill overrides (advanced; see Phase B B2 + \`docs/architecture/skill-source-contract.md\`).
|
|
27922
27994
|
- Cutting an olam release (developer flow, not operator flow; see \`~/.claude/skills/olam-cut-release/SKILL.md\`).
|
|
@@ -27943,6 +28015,345 @@ npm uninstall -g @pleri/olam-cli
|
|
|
27943
28015
|
|
|
27944
28016
|
---
|
|
27945
28017
|
|
|
28018
|
+
## Setup \u2014 k3d/k3s mode (default substrate, port 19001)
|
|
28019
|
+
|
|
28020
|
+
Source: \`docs/onboarding/k3s-mode-setup.md\`
|
|
28021
|
+
|
|
28022
|
+
# Olam in k3d mode \u2014 definitive setup guide
|
|
28023
|
+
|
|
28024
|
+
> **Audience**: an operator setting up olam on their workstation. k3d mode runs olam's full peripheral stack (host-cp, auth-service, mcp-auth-service, kg-service, memory-service) as a real Kubernetes deployment on a local k3d cluster, with Prometheus + Grafana + Loki + Kyverno for observability.
|
|
28025
|
+
>
|
|
28026
|
+
> **End state**: a local k3d cluster \`olam-dev\`, five peripheral pods at \`1/1 Running\` in the \`olam\` namespace, a \`monitoring\` namespace with kube-prometheus-stack + Grafana, the \`olam\` CLI talking to host-cp inside the cluster.
|
|
28027
|
+
>
|
|
28028
|
+
> **Time**: ~5 minutes warm, ~10 minutes cold (image pulls).
|
|
28029
|
+
>
|
|
28030
|
+
> **k3d on all platforms**: olam uses k3d (k3s wrapped in Docker) on both macOS and Linux. No sudo needed \u2014 k3d only requires a Docker daemon. Same substrate, same mental model, same teardown on every machine.
|
|
28031
|
+
|
|
28032
|
+
k3d is the **default mode** for olam. For the lighter docker-compose mode (3 containers, no cluster), see [fresh-machine-setup.md](fresh-machine-setup.md).
|
|
28033
|
+
|
|
28034
|
+
---
|
|
28035
|
+
|
|
28036
|
+
## 0. Prerequisites
|
|
28037
|
+
|
|
28038
|
+
You need these tools installed. \`olam setup\` will prompt to install missing brew-formulae for you on macOS (answer y); on Linux it uses the upstream k3d install script (no sudo needed). Pass \`-y\` to skip all prompts.
|
|
28039
|
+
|
|
28040
|
+
| Tool | Why | Install |
|
|
28041
|
+
|---|---|---|
|
|
28042
|
+
| **Node.js \u2265 20** | The olam CLI runs on Node | \`nvm install 20\` |
|
|
28043
|
+
| **Docker daemon** | k3d runs k3s nodes as Docker containers (required on all platforms) | Docker Desktop (macOS/Windows) or \`sudo apt install docker.io\` (Linux); colima works too |
|
|
28044
|
+
| **colima** (macOS, optional) | Lightweight Docker runtime for macOS | \`brew install colima && colima start --cpu 4 --memory 8 --vm-type=vz --mount-type=virtiofs\` |
|
|
28045
|
+
| **k3d** | Wraps k3s in Docker for local clusters \u2014 works on macOS and Linux, no sudo | \`brew install k3d\` (macOS/Linux with brew) or \`curl -s https://raw.githubusercontent.com/k3d-io/k3d/main/install.sh \\| bash\` |
|
|
28046
|
+
| **kubectl** | Cluster operations | \`brew install kubectl\` |
|
|
28047
|
+
| **helm** | Installs Loki + Promtail + Grafana + Prometheus + Kyverno | \`brew install helm\` |
|
|
28048
|
+
| **gh** | ghcr-pull secret + \`gh auth token\` | \`brew install gh && gh auth login\` |
|
|
28049
|
+
| **docker** + \`docker compose\` plugin | Hosts the docker-socket-proxy sibling container | Docker Desktop, or colima ships it |
|
|
28050
|
+
| **jq, curl, openssl** | Shell helpers | macOS defaults |
|
|
28051
|
+
| **Claude Code subscription** | The \`claude\` CLI inside each world consumes your local subscription | \`npm install -g @anthropic-ai/claude-code\` |
|
|
28052
|
+
|
|
28053
|
+
---
|
|
28054
|
+
|
|
28055
|
+
## 1. Install the olam CLI
|
|
28056
|
+
|
|
28057
|
+
\`\`\`bash
|
|
28058
|
+
# One-line installer (recommended)
|
|
28059
|
+
curl -fsSL https://olam.bar.dev/install | sh
|
|
28060
|
+
|
|
28061
|
+
# Or via npm directly
|
|
28062
|
+
npm install -g @pleri/olam-cli
|
|
28063
|
+
\`\`\`
|
|
28064
|
+
|
|
28065
|
+
Verify:
|
|
28066
|
+
|
|
28067
|
+
\`\`\`bash
|
|
28068
|
+
olam --version
|
|
28069
|
+
\`\`\`
|
|
28070
|
+
|
|
28071
|
+
The CLI ships every manifest, secret template, and observability install script it needs inside the npm tarball \u2014 no \`git clone\` required.
|
|
28072
|
+
|
|
28073
|
+
---
|
|
28074
|
+
|
|
28075
|
+
## 2. Authenticate \`gh\`
|
|
28076
|
+
|
|
28077
|
+
\`\`\`bash
|
|
28078
|
+
gh auth login
|
|
28079
|
+
\`\`\`
|
|
28080
|
+
|
|
28081
|
+
The bootstrap creates a \`ghcr-pull\` Kubernetes Secret from \`gh auth token\` so pulls of \`ghcr.io/pleri/olam-*\` images don't hit anonymous rate limits.
|
|
28082
|
+
|
|
28083
|
+
---
|
|
28084
|
+
|
|
28085
|
+
## 3. Bootstrap
|
|
28086
|
+
|
|
28087
|
+
Single command, end-to-end:
|
|
28088
|
+
|
|
28089
|
+
\`\`\`bash
|
|
28090
|
+
olam setup
|
|
28091
|
+
\`\`\`
|
|
28092
|
+
|
|
28093
|
+
Pass \`-y\` to skip all prompts (non-interactive, auto-affirm every step):
|
|
28094
|
+
|
|
28095
|
+
\`\`\`bash
|
|
28096
|
+
olam setup -y
|
|
28097
|
+
\`\`\`
|
|
28098
|
+
|
|
28099
|
+
The command is **idempotent** \u2014 re-running against an existing cluster only does work for incomplete steps. It runs five ordered phases:
|
|
28100
|
+
|
|
28101
|
+
| # | Phase | What it does |
|
|
28102
|
+
|---|---|---|
|
|
28103
|
+
| 0 | **Preflight** | Detects missing tools and prints actionable install commands. Verifies \`gh\` is authenticated and the docker daemon is reachable. |
|
|
28104
|
+
| 1 | **Secrets** | Generates \`~/.olam/{auth-secret,kg-bearer-token,auth-db-secret,mcp-auth-jwt-secret,memory-bearer-secret}\` if absent (32-byte hex, mode 0600). |
|
|
28105
|
+
| 2 | **Colima** (macOS only) | Ensures colima is running; if not, starts it with sensible defaults. Applies \`chmod 666 /var/run/docker.sock\` inside the colima VM (virtiofs mitigation). |
|
|
28106
|
+
| 3 | **Cluster** | \`k3d cluster create olam-dev\` with the gh-config bind. Skipped if cluster exists. (Override the name with \`--cluster-name\`.) |
|
|
28107
|
+
| 4 | **Observability** | Chains the bundled install scripts: Loki + Promtail, Grafana with port-forward + admin secret, kube-prometheus-stack with recording rules, Kyverno admission policy. |
|
|
28108
|
+
| 5 | **Apply manifests + rollout** | Delegates to the existing \`olam upgrade\` flow: namespace, RBAC, secrets, ghcr-pull, host-side docker-socket-proxy, manifest apply, rollout status (per-deployment, 90s timeout), port-forward, \`/health\` verify, audit log. |
|
|
28109
|
+
|
|
28110
|
+
Flag reference:
|
|
28111
|
+
|
|
28112
|
+
\`\`\`bash
|
|
28113
|
+
olam setup --help
|
|
28114
|
+
\`\`\`
|
|
28115
|
+
|
|
28116
|
+
Common overrides:
|
|
28117
|
+
|
|
28118
|
+
- \`-y, --yes\` \u2014 auto-affirm every prompt (non-interactive).
|
|
28119
|
+
- \`--substrate <docker|kubernetes>\` \u2014 force a substrate instead of auto-detecting.
|
|
28120
|
+
- \`--cluster-name <name>\` \u2014 k3d cluster name to create/use (default: \`olam-dev\`).
|
|
28121
|
+
- \`--reuse-cluster <name>\` \u2014 reuse an existing reachable kube context instead of provisioning.
|
|
28122
|
+
- \`--skip-cluster-create\` \u2014 cluster already exists; skip cluster provisioning.
|
|
28123
|
+
- \`--skip-doctor\` \u2014 skip final health check (useful in CI).
|
|
28124
|
+
|
|
28125
|
+
---
|
|
28126
|
+
|
|
28127
|
+
## 4. Verify the cluster is healthy
|
|
28128
|
+
|
|
28129
|
+
\`\`\`bash
|
|
28130
|
+
kubectl get pods -n olam
|
|
28131
|
+
\`\`\`
|
|
28132
|
+
|
|
28133
|
+
Expected \u2014 all five \`1/1 Running\`:
|
|
28134
|
+
|
|
28135
|
+
\`\`\`
|
|
28136
|
+
NAME READY STATUS RESTARTS AGE
|
|
28137
|
+
olam-auth-service-... 1/1 Running 0 ~5m
|
|
28138
|
+
olam-host-cp-... 1/1 Running 0 ~5m
|
|
28139
|
+
olam-kg-service-... 1/1 Running 0 ~5m
|
|
28140
|
+
olam-mcp-auth-service-... 1/1 Running 0 ~5m
|
|
28141
|
+
olam-memory-service-... 1/1 Running 0 ~5m
|
|
28142
|
+
\`\`\`
|
|
28143
|
+
|
|
28144
|
+
If something's off:
|
|
28145
|
+
|
|
28146
|
+
\`\`\`bash
|
|
28147
|
+
olam doctor # checks substrate, cluster, pods, secrets
|
|
28148
|
+
olam services status # k8s-aware status table
|
|
28149
|
+
\`\`\`
|
|
28150
|
+
|
|
28151
|
+
---
|
|
28152
|
+
|
|
28153
|
+
## 5. Open Grafana
|
|
28154
|
+
|
|
28155
|
+
\`\`\`bash
|
|
28156
|
+
kubectl port-forward -n monitoring svc/olam-grafana 3000:80
|
|
28157
|
+
open http://localhost:3000
|
|
28158
|
+
\`\`\`
|
|
28159
|
+
|
|
28160
|
+
User \`admin\`, password from:
|
|
28161
|
+
|
|
28162
|
+
\`\`\`bash
|
|
28163
|
+
kubectl get secret olam-grafana-admin -n monitoring \\
|
|
28164
|
+
-o jsonpath='{.data.admin-password}' | base64 -d
|
|
28165
|
+
\`\`\`
|
|
28166
|
+
|
|
28167
|
+
Pre-installed dashboards (under "Olam"):
|
|
28168
|
+
|
|
28169
|
+
- **olam-home** \u2014 at-a-glance status across all peripherals.
|
|
28170
|
+
- **host-cp** \u2014 request rate, p50/p95/p99 latency, world counts.
|
|
28171
|
+
- **kg-service** \u2014 classifier hit rate, classify latency, hook traffic.
|
|
28172
|
+
- **request-rate** \u2014 per-route HTTP request rate (uses recording rule \`olam:http_requests:rate5m_by_service_route\`).
|
|
28173
|
+
|
|
28174
|
+
---
|
|
28175
|
+
|
|
28176
|
+
## 6. Day-to-day operations
|
|
28177
|
+
|
|
28178
|
+
\`\`\`bash
|
|
28179
|
+
olam doctor # health check across substrate
|
|
28180
|
+
olam services status # peripherals status table (k8s-aware)
|
|
28181
|
+
olam services restart <name> # kubectl rollout restart for one peripheral
|
|
28182
|
+
olam services down # scale all peripherals to 0 replicas
|
|
28183
|
+
olam services up # scale them back to 1
|
|
28184
|
+
\`\`\`
|
|
28185
|
+
|
|
28186
|
+
To pick up a new release after \`npm install -g @pleri/olam-cli@latest\`:
|
|
28187
|
+
|
|
28188
|
+
\`\`\`bash
|
|
28189
|
+
olam upgrade
|
|
28190
|
+
\`\`\`
|
|
28191
|
+
|
|
28192
|
+
The upgrade flow re-applies all manifests (Kubernetes rolls the deployments to the new image digests); persistent volumes survive.
|
|
28193
|
+
|
|
28194
|
+
---
|
|
28195
|
+
|
|
28196
|
+
## 7. Tear down
|
|
28197
|
+
|
|
28198
|
+
\`\`\`bash
|
|
28199
|
+
olam implode --dry-run # preview what will be removed
|
|
28200
|
+
olam implode # confirmed: cluster + secrets + state
|
|
28201
|
+
\`\`\`
|
|
28202
|
+
|
|
28203
|
+
\`olam implode\` removes the k3d cluster, the host-side docker-socket-proxy sibling, every container, every secret in \`~/.olam/\`, and the global config. Use it when you want to start completely fresh; otherwise prefer \`olam services down\` or scale to 0.
|
|
28204
|
+
|
|
28205
|
+
---
|
|
28206
|
+
|
|
28207
|
+
## Choosing compose mode instead
|
|
28208
|
+
|
|
28209
|
+
To use the lighter 3-container compose path instead:
|
|
28210
|
+
|
|
28211
|
+
\`\`\`bash
|
|
28212
|
+
curl -fsSL https://olam.bar.dev/install | sh
|
|
28213
|
+
olam setup --substrate=docker
|
|
28214
|
+
\`\`\`
|
|
28215
|
+
|
|
28216
|
+
The CLI is substrate-aware: \`olam setup\`, \`olam services up|down|status|restart\`, \`olam upgrade\`, and \`olam doctor\` all route to the correct backend based on \`~/.olam/config.json\`'s \`host.substrate\` value.
|
|
28217
|
+
|
|
28218
|
+
Full compose guide: [\`fresh-machine-setup.md\`](./fresh-machine-setup.md).
|
|
28219
|
+
|
|
28220
|
+
---
|
|
28221
|
+
|
|
28222
|
+
## Architecture quick-ref
|
|
28223
|
+
|
|
28224
|
+
\`\`\`
|
|
28225
|
+
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
28226
|
+
\u2502 operator's machine \u2502
|
|
28227
|
+
\u2502 \u2502
|
|
28228
|
+
\u2502 ~/.olam/*-secret \u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u25B6 Kubernetes Secrets
|
|
28229
|
+
\u2502 ~/.config/gh \u2500\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u25B6 k3d --volume bind
|
|
28230
|
+
\u2502 \u2502
|
|
28231
|
+
\u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502
|
|
28232
|
+
\u2502 \u2502 docker daemon \u2502 \u2502
|
|
28233
|
+
\u2502 \u2502 \u2502 \u2502
|
|
28234
|
+
\u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u2502 \u2502
|
|
28235
|
+
\u2502 \u2502 \u2502 k3d node \u2502 \u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
28236
|
+
\u2502 \u2502 \u2502 cluster \u2502\u25C0\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u253C\u2500\u2500\u2500\u2500\u2500\u2502 ghcr.io/pleri/olam-* \u2502
|
|
28237
|
+
\u2502 \u2502 \u2502 olam-dev \u2502 \u2502 \u2502 \u2502 (pulled with gh token) \u2502
|
|
28238
|
+
\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u252C\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
28239
|
+
\u2502 \u2502 \u2502 TCP \u2502 \u2502
|
|
28240
|
+
\u2502 \u2502 \u25BC :2375 \u2502 \u2502
|
|
28241
|
+
\u2502 \u2502 \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2534\u2510 \u2502
|
|
28242
|
+
\u2502 \u2502 \u2502 docker-socket \u2502 \u2502
|
|
28243
|
+
\u2502 \u2502 \u2502 proxy \u2502 \u2502
|
|
28244
|
+
\u2502 \u2502 \u2502 (sibling \u2502 \u2502
|
|
28245
|
+
\u2502 \u2502 \u2502 container) \u2502 \u2502
|
|
28246
|
+
\u2502 \u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502
|
|
28247
|
+
\u2502 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
28248
|
+
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
28249
|
+
\u2502
|
|
28250
|
+
\u25BC k3d nodes via host.k3d.internal:2375
|
|
28251
|
+
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
28252
|
+
\u2502 cluster: olam-dev \u2502
|
|
28253
|
+
\u2502 \u2502
|
|
28254
|
+
\u2502 namespace: olam \u2502
|
|
28255
|
+
\u2502 olam-host-cp (1/1 Running) \u2502
|
|
28256
|
+
\u2502 olam-auth-service (1/1 Running) \u2502
|
|
28257
|
+
\u2502 olam-mcp-auth-svc (1/1 Running) \u2502
|
|
28258
|
+
\u2502 olam-kg-service (1/1 Running) \u2502
|
|
28259
|
+
\u2502 olam-memory-service (1/1 Running) \u2502
|
|
28260
|
+
\u2502 \u2502
|
|
28261
|
+
\u2502 namespace: monitoring \u2502
|
|
28262
|
+
\u2502 olam-grafana \u2502
|
|
28263
|
+
\u2502 prometheus-operated \u2502
|
|
28264
|
+
\u2502 loki + promtail \u2502
|
|
28265
|
+
\u2502 kyverno (admission) \u2502
|
|
28266
|
+
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
28267
|
+
\`\`\`
|
|
28268
|
+
|
|
28269
|
+
Why the sibling docker-socket-proxy? On macOS, colima exposes \`/var/run/docker.sock\` via virtiofs, which blocks unix-socket bind-mounts into k3d pods. The proxy runs as a normal Docker container on the operator's daemon and exposes the same socket over TCP \`:2375\`. Pods reach it through an ExternalName Service. See [\`docs/test-reports/olam-k3d-on-mac-substrate-decision-eli5.md\`](../test-reports/olam-k3d-on-mac-substrate-decision-eli5.md).
|
|
28270
|
+
|
|
28271
|
+
---
|
|
28272
|
+
|
|
28273
|
+
## Common issues
|
|
28274
|
+
|
|
28275
|
+
| Symptom | Fix |
|
|
28276
|
+
|---|---|
|
|
28277
|
+
| \`colima not running\` | \`colima start --cpu 4 --memory 8 --vm-type=vz --mount-type=virtiofs\` |
|
|
28278
|
+
| \`permission denied\` on docker socket | \`colima ssh -- sudo chmod 666 /var/run/docker.sock\` |
|
|
28279
|
+
| Missing tool errors at preflight | Install manually per the prereq table, then re-run \`olam setup\` |
|
|
28280
|
+
| \`helm install\` timeout during observability bootstrap | Set \`OLAM_HELM_TIMEOUT=600s\` (or higher on loaded machines). See [Tuning](#tuning-helm-timeouts-on-resource-constrained-machines) for details. |
|
|
28281
|
+
| \`host-cp\` \`CrashLoopBackOff\` with \`inClusterContext is not in the allowlist\` | Image pre-dates v0.1.161 \u2014 \`npm install -g @pleri/olam-cli@latest && olam upgrade\` |
|
|
28282
|
+
| \`memory-service\` \`CrashLoopBackOff\` with \`port 3111 is already in use\` | Image pre-dates v0.1.163 \u2014 \`npm install -g @pleri/olam-cli@latest && olam upgrade\` |
|
|
28283
|
+
| \`imagePullBackOff\` from \`ghcr.io/pleri/olam-*\` | The bootstrap creates \`ghcr-pull\` from \`gh auth token\`; re-run \`olam setup\` after \`gh auth login\` |
|
|
28284
|
+
| Grafana dashboards missing | \`kubectl rollout restart deploy/olam-grafana -n monitoring\` |
|
|
28285
|
+
| host-cp can't reach docker | \`docker ps \\| grep docker-socket-proxy\` \u2014 restart with \`olam setup --skip-cluster-create\` to re-run only the proxy + manifest-apply steps |
|
|
28286
|
+
| \`helm install\` fails with \`Error: context deadline exceeded\` during observability bootstrap (grafana / loki / kube-prometheus-stack / kyverno) | The Colima VM is sharing CPU/memory with too many other containers. Bump the helm timeout via \`OLAM_HELM_TIMEOUT=900s olam setup\` (default is \`600s\`). On very loaded machines, \`1200s\` is reasonable. Applies to every \`helm install\` step in the observability chain. |
|
|
28287
|
+
|
|
28288
|
+
### Tuning helm timeouts on resource-constrained machines
|
|
28289
|
+
|
|
28290
|
+
Every observability \`helm install\` (grafana, loki, promtail, kube-prometheus-stack, kyverno) reads \`OLAM_HELM_TIMEOUT\` (default \`600s\`). When the Colima VM is sharing resources with a heavy local workload, charts can take longer than the default to converge \u2014 bump the env var instead of editing scripts:
|
|
28291
|
+
|
|
28292
|
+
\`\`\`bash
|
|
28293
|
+
OLAM_HELM_TIMEOUT=900s olam setup # bootstrap with longer timeout
|
|
28294
|
+
OLAM_HELM_TIMEOUT=1200s olam setup # very loaded machines
|
|
28295
|
+
\`\`\`
|
|
28296
|
+
|
|
28297
|
+
CI Linux runners run unmodified at \`600s\` (dedicated resources). The knob exists for macOS-Colima hosts that share a VM with other docker workloads.
|
|
28298
|
+
|
|
28299
|
+
### Tuning Prometheus scrape/discovery waits
|
|
28300
|
+
|
|
28301
|
+
The Phase C E2E scripts in \`scripts/e2e/\` poll Prometheus for synthetic-target discovery (\`TARGET_DISCOVERY_TIMEOUT\`, default 240s \u2014 \`cardinality-drop.sh\`, \`kyverno-cardinality-mutate.sh\`, \`dashboards-have-data.sh\`) and then sleep for recording-rule evaluation (\`SCRAPE_WAIT\`, default 70s \u2014 \`dashboards-have-data.sh\`). Both default values cover \u22652 rule-evaluation cycles at the 30s rule interval against a 15s scrape interval. Override on very slow runners:
|
|
28302
|
+
|
|
28303
|
+
\`\`\`bash
|
|
28304
|
+
OLAM_PROM_DISCOVERY_TIMEOUT=300 OLAM_PROM_SCRAPE_WAIT=120 npm run test:ingress-integration
|
|
28305
|
+
\`\`\`
|
|
28306
|
+
|
|
28307
|
+
### Troubleshooting port-forwards
|
|
28308
|
+
|
|
28309
|
+
**Problem:** connections to a port-forward (e.g. \`localhost:19001\` for host-cp, \`localhost:3000\` for Grafana) suddenly fail with "connection refused".
|
|
28310
|
+
|
|
28311
|
+
**Why:** kubectl port-forwards die when:
|
|
28312
|
+
- The terminal that started them exits
|
|
28313
|
+
- k3d restarts or the cluster reboots
|
|
28314
|
+
- The underlying pod crashes or is redeployed
|
|
28315
|
+
- The local kube context changes
|
|
28316
|
+
|
|
28317
|
+
**Diagnose:**
|
|
28318
|
+
\`\`\`bash
|
|
28319
|
+
ps aux | grep "kubectl port-forward"
|
|
28320
|
+
\`\`\`
|
|
28321
|
+
|
|
28322
|
+
If nothing shows up, the port-forward is dead and needs to be re-established.
|
|
28323
|
+
|
|
28324
|
+
**Fix:**
|
|
28325
|
+
|
|
28326
|
+
Option 1 \u2014 re-establish all port-forwards at once:
|
|
28327
|
+
\`\`\`bash
|
|
28328
|
+
olam services up
|
|
28329
|
+
\`\`\`
|
|
28330
|
+
|
|
28331
|
+
Option 2 \u2014 manually restart the port-forward (canonical command from the setup doc):
|
|
28332
|
+
\`\`\`bash
|
|
28333
|
+
kubectl port-forward -n olam svc/host-cp 19001:19001
|
|
28334
|
+
\`\`\`
|
|
28335
|
+
|
|
28336
|
+
Use \`olam services status\` to see which services are running and which port each binds to locally.
|
|
28337
|
+
|
|
28338
|
+
When everything else fails, tear down and re-create:
|
|
28339
|
+
|
|
28340
|
+
\`\`\`bash
|
|
28341
|
+
olam implode
|
|
28342
|
+
olam setup
|
|
28343
|
+
\`\`\`
|
|
28344
|
+
|
|
28345
|
+
\`olam implode\` removes everything; \`olam setup\` re-creates from scratch.
|
|
28346
|
+
|
|
28347
|
+
---
|
|
28348
|
+
|
|
28349
|
+
## What to read next
|
|
28350
|
+
|
|
28351
|
+
- \`olam --help\`, \`olam setup --help\` \u2014 the canonical CLI surface.
|
|
28352
|
+
- [\`docs/architecture/peripheral-services-on-k3s.md\`](../architecture/peripheral-services-on-k3s.md) \u2014 design doc for the k3s peripheral architecture.
|
|
28353
|
+
- [\`docs/test-reports/olam-k3d-on-mac-substrate-decision-eli5.md\`](../test-reports/olam-k3d-on-mac-substrate-decision-eli5.md) \u2014 why the docker-socket-proxy sits where it sits.
|
|
28354
|
+
|
|
28355
|
+
---
|
|
28356
|
+
|
|
27946
28357
|
## Architecture \u2014 the problem olam solves
|
|
27947
28358
|
|
|
27948
28359
|
Source: \`docs/architecture/01-problem.md\`
|
|
@@ -29691,6 +30102,11 @@ function registerCreate(program2) {
|
|
|
29691
30102
|
if (resolvedTask) {
|
|
29692
30103
|
printInfo("Task", resolvedTask);
|
|
29693
30104
|
}
|
|
30105
|
+
if (!opts.json) {
|
|
30106
|
+
console.log(`
|
|
30107
|
+
${pc14.cyan("Dashboard:")} ${HOST_CP_URL}/plan/${encodeURIComponent(world.id)}`);
|
|
30108
|
+
console.log(`${pc14.cyan("Enter world:")} ${pc14.dim(`olam enter ${world.name}`)}`);
|
|
30109
|
+
}
|
|
29694
30110
|
if (world.credentialsInjected?.claude) {
|
|
29695
30111
|
console.log(`
|
|
29696
30112
|
${pc14.green("Credentials injected. World is ready for dispatch.")}`);
|
|
@@ -30208,6 +30624,7 @@ import * as fs40 from "node:fs";
|
|
|
30208
30624
|
import * as http3 from "node:http";
|
|
30209
30625
|
import * as os22 from "node:os";
|
|
30210
30626
|
import * as path42 from "node:path";
|
|
30627
|
+
import pc18 from "picocolors";
|
|
30211
30628
|
var CLI_VERSION2 = process.env["OLAM_CLI_VERSION"] ?? "0.0.0";
|
|
30212
30629
|
var HOST_CP_PORT2 = 19e3;
|
|
30213
30630
|
var STATE_ENUM = [
|
|
@@ -30334,6 +30751,9 @@ function registerStatus(program2) {
|
|
|
30334
30751
|
printHeader("Olam Status");
|
|
30335
30752
|
printInfo("CLI version", `@pleri/olam-cli@${ms.version}`);
|
|
30336
30753
|
printInfo("Host CP", ms.host_cp === "running" ? `running on port ${ms.port}` : "stopped");
|
|
30754
|
+
if (ms.host_cp === "stopped") {
|
|
30755
|
+
console.log(pc18.dim(" \u2192 run `olam doctor` to diagnose"));
|
|
30756
|
+
}
|
|
30337
30757
|
printInfo("Worlds", String(ms.worlds));
|
|
30338
30758
|
printInfo("Token", ms.token_present ? "present" : "absent");
|
|
30339
30759
|
if (ms.last_update_check) {
|
|
@@ -30404,7 +30824,7 @@ init_context();
|
|
|
30404
30824
|
init_output();
|
|
30405
30825
|
init_host_cp();
|
|
30406
30826
|
import ora7 from "ora";
|
|
30407
|
-
import
|
|
30827
|
+
import pc19 from "picocolors";
|
|
30408
30828
|
async function runDestroy(worldArg, opts, deps) {
|
|
30409
30829
|
const worlds = deps.listWorlds();
|
|
30410
30830
|
const world = resolveWorld(worlds, worldArg);
|
|
@@ -30412,12 +30832,12 @@ async function runDestroy(worldArg, opts, deps) {
|
|
|
30412
30832
|
deps.stderr(`World "${worldArg}" not found.`);
|
|
30413
30833
|
const suggestions = suggestWorlds(worlds, worldArg);
|
|
30414
30834
|
if (suggestions.length > 0) {
|
|
30415
|
-
deps.stdout(
|
|
30835
|
+
deps.stdout(pc19.dim("\n Did you mean:"));
|
|
30416
30836
|
for (const s of suggestions) {
|
|
30417
|
-
deps.stdout(` ${
|
|
30837
|
+
deps.stdout(` ${pc19.bold(s.name)} ${pc19.dim(`(${s.id})`)} ${pc19.dim(s.status)}`);
|
|
30418
30838
|
}
|
|
30419
30839
|
}
|
|
30420
|
-
deps.stdout(
|
|
30840
|
+
deps.stdout(pc19.dim("\n Run `olam list` to see all worlds."));
|
|
30421
30841
|
return 1;
|
|
30422
30842
|
}
|
|
30423
30843
|
const worldId = world.id;
|
|
@@ -30796,7 +31216,7 @@ import * as fs42 from "node:fs";
|
|
|
30796
31216
|
import * as os24 from "node:os";
|
|
30797
31217
|
import * as path44 from "node:path";
|
|
30798
31218
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
30799
|
-
import
|
|
31219
|
+
import pc20 from "picocolors";
|
|
30800
31220
|
var NPM_PACKAGE = "@pleri/olam-cli";
|
|
30801
31221
|
var realExec = (cmd, args) => {
|
|
30802
31222
|
try {
|
|
@@ -30953,7 +31373,7 @@ function renderSurvey(survey, opts) {
|
|
|
30953
31373
|
const dirtyWorlds = survey.worlds.filter((w) => w.dirty);
|
|
30954
31374
|
const cleanWorlds = survey.worlds.filter((w) => !w.dirty);
|
|
30955
31375
|
const worldBytes = survey.worlds.reduce((acc, w) => acc + w.bytes, 0);
|
|
30956
|
-
lines.push(
|
|
31376
|
+
lines.push(pc20.bold(pc20.red("\u2014 olam implode survey \u2014")));
|
|
30957
31377
|
lines.push("");
|
|
30958
31378
|
lines.push(` containers (olam-*): ${survey.containers.length}`);
|
|
30959
31379
|
lines.push(` images: ${survey.images.length}`);
|
|
@@ -30969,13 +31389,13 @@ function renderSurvey(survey, opts) {
|
|
|
30969
31389
|
);
|
|
30970
31390
|
if (dirtyWorlds.length > 0) {
|
|
30971
31391
|
lines.push("");
|
|
30972
|
-
lines.push(
|
|
31392
|
+
lines.push(pc20.yellow(` \u26A0 dirty worlds (${dirtyWorlds.length}) \u2014 pass --include-dirty to destroy:`));
|
|
30973
31393
|
for (const w of dirtyWorlds) {
|
|
30974
31394
|
lines.push(` - ${w.id} ${formatBytes3(w.bytes)} (${w.note})`);
|
|
30975
31395
|
}
|
|
30976
31396
|
}
|
|
30977
31397
|
lines.push("");
|
|
30978
|
-
lines.push(
|
|
31398
|
+
lines.push(pc20.dim(" Run with --yes to actually destroy. Default is dry-run."));
|
|
30979
31399
|
return lines.join("\n");
|
|
30980
31400
|
}
|
|
30981
31401
|
function formatBytes3(n) {
|
|
@@ -31150,11 +31570,11 @@ async function runImplode(opts) {
|
|
|
31150
31570
|
process.stdout.write("\n");
|
|
31151
31571
|
process.stdout.write(`To reinstall a fresh copy:
|
|
31152
31572
|
`);
|
|
31153
|
-
process.stdout.write(` ${
|
|
31573
|
+
process.stdout.write(` ${pc20.cyan(`npm install -g ${NPM_PACKAGE}`)}
|
|
31154
31574
|
`);
|
|
31155
|
-
process.stdout.write(` ${
|
|
31575
|
+
process.stdout.write(` ${pc20.cyan("olam init")}
|
|
31156
31576
|
`);
|
|
31157
|
-
process.stdout.write(` ${
|
|
31577
|
+
process.stdout.write(` ${pc20.cyan("olam auth login")}
|
|
31158
31578
|
`);
|
|
31159
31579
|
return result.errors.length > 0 ? 1 : 0;
|
|
31160
31580
|
}
|
|
@@ -31163,7 +31583,7 @@ async function runImplode(opts) {
|
|
|
31163
31583
|
init_context();
|
|
31164
31584
|
init_output();
|
|
31165
31585
|
import { execSync as execSync9 } from "node:child_process";
|
|
31166
|
-
import
|
|
31586
|
+
import pc21 from "picocolors";
|
|
31167
31587
|
var SAFE_IDENT3 = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
31168
31588
|
function buildStartClaudeCommands(containerName, sessionName, task) {
|
|
31169
31589
|
if (!SAFE_IDENT3.test(containerName)) {
|
|
@@ -31227,7 +31647,7 @@ function registerEnter(program2) {
|
|
|
31227
31647
|
checkVersionPin2(worldId, worldMeta.workspacePath);
|
|
31228
31648
|
if (worldMeta.claudeHome) {
|
|
31229
31649
|
console.log(
|
|
31230
|
-
|
|
31650
|
+
pc21.dim(`# claude-home: ${worldMeta.claudeHome} (per-world Claude Code instance, ADR 045)`)
|
|
31231
31651
|
);
|
|
31232
31652
|
}
|
|
31233
31653
|
}
|
|
@@ -31275,7 +31695,7 @@ function registerEnter(program2) {
|
|
|
31275
31695
|
}
|
|
31276
31696
|
console.log("Run these commands in order to enter the world:\n");
|
|
31277
31697
|
for (const step2 of steps) {
|
|
31278
|
-
console.log(` ${
|
|
31698
|
+
console.log(` ${pc21.dim(`# ${step2.description}`)}`);
|
|
31279
31699
|
if (step2.stdin !== void 0) {
|
|
31280
31700
|
const escaped = step2.stdin.replace(/'/g, "'\\''");
|
|
31281
31701
|
console.log(` printf '%s' '${escaped}' | ${step2.command}`);
|
|
@@ -31309,11 +31729,11 @@ function registerEnter(program2) {
|
|
|
31309
31729
|
return;
|
|
31310
31730
|
}
|
|
31311
31731
|
console.log("Run this command to enter the world:\n");
|
|
31312
|
-
console.log(` ${
|
|
31732
|
+
console.log(` ${pc21.bold(result.command)}`);
|
|
31313
31733
|
const containerName = `olam-${worldId}-devbox`;
|
|
31314
31734
|
console.log(
|
|
31315
31735
|
`
|
|
31316
|
-
${
|
|
31736
|
+
${pc21.dim(`Observe dispatch: docker exec -it ${containerName} tmux attach -t olam-dispatch -r`)}`
|
|
31317
31737
|
);
|
|
31318
31738
|
});
|
|
31319
31739
|
}
|
|
@@ -31557,7 +31977,7 @@ function registerCrystallize(program2, options = {}) {
|
|
|
31557
31977
|
|
|
31558
31978
|
// src/commands/pr.ts
|
|
31559
31979
|
init_registry();
|
|
31560
|
-
import
|
|
31980
|
+
import pc22 from "picocolors";
|
|
31561
31981
|
|
|
31562
31982
|
// ../core/dist/pr-gate/client.js
|
|
31563
31983
|
var HOST_CONTROL_PLANE_BASE2 = 19080;
|
|
@@ -31638,26 +32058,26 @@ async function findGate(id) {
|
|
|
31638
32058
|
return null;
|
|
31639
32059
|
}
|
|
31640
32060
|
function formatStateBadge(state) {
|
|
31641
|
-
if (state === "approve") return
|
|
31642
|
-
if (state === "block") return
|
|
31643
|
-
if (state === "denied") return
|
|
31644
|
-
return
|
|
32061
|
+
if (state === "approve") return pc22.green("approve");
|
|
32062
|
+
if (state === "block") return pc22.red("block");
|
|
32063
|
+
if (state === "denied") return pc22.gray("denied");
|
|
32064
|
+
return pc22.yellow("pending");
|
|
31645
32065
|
}
|
|
31646
32066
|
function registerPr(program2) {
|
|
31647
32067
|
const pr = program2.command("pr").description("Review and decide PR-gate requests from running worlds");
|
|
31648
32068
|
pr.command("list").description("List all PR-gate requests across every running world").action(async () => {
|
|
31649
32069
|
const all = await fanoutList();
|
|
31650
32070
|
if (all.length === 0) {
|
|
31651
|
-
console.log(
|
|
32071
|
+
console.log(pc22.dim("No gates open."));
|
|
31652
32072
|
return;
|
|
31653
32073
|
}
|
|
31654
32074
|
printHeader(`${all.length} gate(s)`);
|
|
31655
32075
|
for (const { world, gate } of all) {
|
|
31656
32076
|
const badge = formatStateBadge(gate.state);
|
|
31657
32077
|
console.log(
|
|
31658
|
-
` ${
|
|
32078
|
+
` ${pc22.bold(gate.id.slice(0, 8))} ${badge.padEnd(20)} ${pc22.dim(world.name)} ${pc22.dim(gate.branch)}`
|
|
31659
32079
|
);
|
|
31660
|
-
console.log(` ${
|
|
32080
|
+
console.log(` ${pc22.dim(gate.command.slice(0, 100))}`);
|
|
31661
32081
|
}
|
|
31662
32082
|
});
|
|
31663
32083
|
pr.command("show").description("Show full gate detail (diff, command, commits)").argument("<id>", "Gate id (prefix match ok)").action(async (id) => {
|
|
@@ -31680,9 +32100,9 @@ function registerPr(program2) {
|
|
|
31680
32100
|
if (gate.reason) printInfo("Reason", gate.reason);
|
|
31681
32101
|
}
|
|
31682
32102
|
printHeader("Commits");
|
|
31683
|
-
console.log(gate.commitLog ||
|
|
32103
|
+
console.log(gate.commitLog || pc22.dim(" (empty)"));
|
|
31684
32104
|
printHeader("Diff stat");
|
|
31685
|
-
console.log(gate.diffStat ||
|
|
32105
|
+
console.log(gate.diffStat || pc22.dim(" (empty)"));
|
|
31686
32106
|
});
|
|
31687
32107
|
function decideCommand(verb, decision) {
|
|
31688
32108
|
pr.command(verb).description(`${verb[0].toUpperCase()}${verb.slice(1)} a pending gate`).argument("<id>", "Gate id").option("--reason <reason>", "Short free-text reason").option("--by <name>", "Deciding identity (defaults to $USER)", process.env["USER"] ?? "human").action(async (id, opts) => {
|
|
@@ -32135,7 +32555,7 @@ function registerLanes(program2) {
|
|
|
32135
32555
|
// src/commands/policy-check.ts
|
|
32136
32556
|
init_loader2();
|
|
32137
32557
|
import { execSync as execSync10 } from "node:child_process";
|
|
32138
|
-
import
|
|
32558
|
+
import pc23 from "picocolors";
|
|
32139
32559
|
|
|
32140
32560
|
// ../../node_modules/balanced-match/dist/esm/index.js
|
|
32141
32561
|
var balanced = (a, b, str) => {
|
|
@@ -33995,7 +34415,7 @@ function registerPolicyCheck(program2) {
|
|
|
33995
34415
|
const workspaceRoot = opts.workspace ?? process.cwd();
|
|
33996
34416
|
const policies = loadPolicies(workspaceRoot);
|
|
33997
34417
|
if (policies.length === 0) {
|
|
33998
|
-
console.log(
|
|
34418
|
+
console.log(pc23.dim("policy-check: no policies found in .olam/policies/ \u2014 nothing to enforce"));
|
|
33999
34419
|
return;
|
|
34000
34420
|
}
|
|
34001
34421
|
const diff = getDiff(opts.base, workspaceRoot);
|
|
@@ -34004,11 +34424,11 @@ function registerPolicyCheck(program2) {
|
|
|
34004
34424
|
for (const result of results) {
|
|
34005
34425
|
if (result.passed) continue;
|
|
34006
34426
|
if (result.severity === "error") {
|
|
34007
|
-
console.error(`${
|
|
34427
|
+
console.error(`${pc23.red("policy error")} [${result.policyId}]`);
|
|
34008
34428
|
console.error(result.message);
|
|
34009
34429
|
hasErrorFailure = true;
|
|
34010
34430
|
} else {
|
|
34011
|
-
console.warn(`${
|
|
34431
|
+
console.warn(`${pc23.yellow("policy warn")} [${result.policyId}]`);
|
|
34012
34432
|
console.warn(result.message);
|
|
34013
34433
|
}
|
|
34014
34434
|
}
|
|
@@ -34019,7 +34439,7 @@ function registerPolicyCheck(program2) {
|
|
|
34019
34439
|
}
|
|
34020
34440
|
|
|
34021
34441
|
// src/commands/worldspec/compile.ts
|
|
34022
|
-
import { existsSync as existsSync46, mkdirSync as mkdirSync29, readFileSync as readFileSync37, writeFileSync as
|
|
34442
|
+
import { existsSync as existsSync46, mkdirSync as mkdirSync29, readFileSync as readFileSync37, writeFileSync as writeFileSync24 } from "node:fs";
|
|
34023
34443
|
import { resolve as resolvePath } from "node:path";
|
|
34024
34444
|
import YAML5 from "yaml";
|
|
34025
34445
|
|
|
@@ -34885,12 +35305,12 @@ Resolutions:
|
|
|
34885
35305
|
const outDir = resolvePath(process.cwd(), opts.out);
|
|
34886
35306
|
try {
|
|
34887
35307
|
mkdirSync29(outDir, { recursive: true });
|
|
34888
|
-
|
|
35308
|
+
writeFileSync24(
|
|
34889
35309
|
resolvePath(outDir, "execution-graph.json"),
|
|
34890
35310
|
graphJson,
|
|
34891
35311
|
"utf8"
|
|
34892
35312
|
);
|
|
34893
|
-
|
|
35313
|
+
writeFileSync24(
|
|
34894
35314
|
resolvePath(outDir, "lockfile.json"),
|
|
34895
35315
|
lockfileJson,
|
|
34896
35316
|
"utf8"
|
|
@@ -34913,7 +35333,7 @@ function getPkgVersion() {
|
|
|
34913
35333
|
// src/commands/worldspec/init.ts
|
|
34914
35334
|
init_exit_codes();
|
|
34915
35335
|
init_output();
|
|
34916
|
-
import { existsSync as existsSync47, mkdirSync as mkdirSync30, readFileSync as readFileSync38, writeFileSync as
|
|
35336
|
+
import { existsSync as existsSync47, mkdirSync as mkdirSync30, readFileSync as readFileSync38, writeFileSync as writeFileSync25 } from "node:fs";
|
|
34917
35337
|
import { execSync as execSync11 } from "node:child_process";
|
|
34918
35338
|
import { basename as basename3, resolve as resolvePath2 } from "node:path";
|
|
34919
35339
|
function registerWorldspecInit(parent) {
|
|
@@ -34947,7 +35367,7 @@ function registerWorldspecInit(parent) {
|
|
|
34947
35367
|
const yaml = renderWorldspecYaml(shape);
|
|
34948
35368
|
try {
|
|
34949
35369
|
mkdirSync30(targetDir, { recursive: true });
|
|
34950
|
-
|
|
35370
|
+
writeFileSync25(targetFile, yaml, {
|
|
34951
35371
|
encoding: "utf8",
|
|
34952
35372
|
flag: opts.force ? "w" : "wx"
|
|
34953
35373
|
});
|
|
@@ -35044,7 +35464,7 @@ function relativeFromCwd(absPath, cwd) {
|
|
|
35044
35464
|
}
|
|
35045
35465
|
|
|
35046
35466
|
// src/commands/worldspec/schema.ts
|
|
35047
|
-
import { writeFileSync as
|
|
35467
|
+
import { writeFileSync as writeFileSync26 } from "node:fs";
|
|
35048
35468
|
import { resolve as resolvePath3 } from "node:path";
|
|
35049
35469
|
|
|
35050
35470
|
// ../../node_modules/zod-to-json-schema/dist/esm/Options.js
|
|
@@ -36366,7 +36786,7 @@ function registerWorldspecSchema(parent) {
|
|
|
36366
36786
|
if (opts.out) {
|
|
36367
36787
|
const absPath = resolvePath3(process.cwd(), opts.out);
|
|
36368
36788
|
try {
|
|
36369
|
-
|
|
36789
|
+
writeFileSync26(absPath, json + "\n", "utf8");
|
|
36370
36790
|
} catch (err) {
|
|
36371
36791
|
printError(
|
|
36372
36792
|
`failed to write ${absPath}: ${err.message}`
|
|
@@ -36455,7 +36875,7 @@ import * as fs47 from "node:fs";
|
|
|
36455
36875
|
import * as path50 from "node:path";
|
|
36456
36876
|
import { spawnSync as spawnSync23 } from "node:child_process";
|
|
36457
36877
|
import ora9 from "ora";
|
|
36458
|
-
import
|
|
36878
|
+
import pc24 from "picocolors";
|
|
36459
36879
|
|
|
36460
36880
|
// src/commands/upgrade-lock.ts
|
|
36461
36881
|
import * as fs45 from "node:fs";
|
|
@@ -36746,7 +37166,7 @@ function extractBundleHash(indexHtml) {
|
|
|
36746
37166
|
}
|
|
36747
37167
|
function runStep2(label, cmd, args, opts = {}) {
|
|
36748
37168
|
const start = Date.now();
|
|
36749
|
-
process.stdout.write(` ${
|
|
37169
|
+
process.stdout.write(` ${pc24.dim(label.padEnd(34))}`);
|
|
36750
37170
|
const result = spawnSync23(cmd, [...args], {
|
|
36751
37171
|
encoding: "utf-8",
|
|
36752
37172
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -36756,7 +37176,7 @@ function runStep2(label, cmd, args, opts = {}) {
|
|
|
36756
37176
|
const durationMs = Date.now() - start;
|
|
36757
37177
|
const ok = result.status === 0 && result.error === void 0;
|
|
36758
37178
|
const dur = `${(durationMs / 1e3).toFixed(1)}s`;
|
|
36759
|
-
process.stdout.write(`${ok ?
|
|
37179
|
+
process.stdout.write(`${ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${dur}
|
|
36760
37180
|
`);
|
|
36761
37181
|
return {
|
|
36762
37182
|
ok,
|
|
@@ -37086,7 +37506,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
37086
37506
|
if (info.exitCode !== 0) {
|
|
37087
37507
|
infoSpinner.fail("docker daemon not reachable");
|
|
37088
37508
|
process.stderr.write(
|
|
37089
|
-
`${
|
|
37509
|
+
`${pc24.red("error")} docker info exited with ${info.exitCode}.
|
|
37090
37510
|
Ensure Docker Desktop / Colima / Rancher is running, then retry.
|
|
37091
37511
|
`
|
|
37092
37512
|
);
|
|
@@ -37135,7 +37555,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
37135
37555
|
pullSpinner.fail(`Pull failed for ${failed.map((r) => r.name).join(", ")}`);
|
|
37136
37556
|
for (const f of failed) {
|
|
37137
37557
|
process.stderr.write(
|
|
37138
|
-
` ${
|
|
37558
|
+
` ${pc24.red(f.name)} (${f.ref}):
|
|
37139
37559
|
exit=${f.result.exitCode}
|
|
37140
37560
|
stderr: ${f.result.stderr.split("\n")[0] ?? "(empty)"}
|
|
37141
37561
|
`
|
|
@@ -37156,7 +37576,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
37156
37576
|
if (inspect.exitCode !== 0) {
|
|
37157
37577
|
handshakeSpinner.fail(`Could not inspect ${name}`);
|
|
37158
37578
|
process.stderr.write(
|
|
37159
|
-
`${
|
|
37579
|
+
`${pc24.red("error")} docker inspect ${ref} failed: ${inspect.stderr}
|
|
37160
37580
|
`
|
|
37161
37581
|
);
|
|
37162
37582
|
return { exitCode: EXIT_GENERIC_ERROR, summary: `inspect failed: ${name}` };
|
|
@@ -37168,7 +37588,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
37168
37588
|
const decision = checkProtocolOverlap(versions);
|
|
37169
37589
|
if (!decision.compatible) {
|
|
37170
37590
|
handshakeSpinner.fail(`Protocol mismatch on ${name}`);
|
|
37171
|
-
process.stderr.write(`${
|
|
37591
|
+
process.stderr.write(`${pc24.red("error")} ${decision.remedy}
|
|
37172
37592
|
`);
|
|
37173
37593
|
return {
|
|
37174
37594
|
exitCode: EXIT_PROTOCOL_MISMATCH,
|
|
@@ -37215,7 +37635,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
37215
37635
|
const r = tagger(t.from, t.to);
|
|
37216
37636
|
if (!r.ok) {
|
|
37217
37637
|
tagSpinner.fail(`docker tag failed for ${t.name}`);
|
|
37218
|
-
process.stderr.write(`${
|
|
37638
|
+
process.stderr.write(`${pc24.red("error")} ${r.error ?? "docker tag failed"}
|
|
37219
37639
|
`);
|
|
37220
37640
|
return { exitCode: EXIT_GENERIC_ERROR, summary: `tag failed: ${t.name}` };
|
|
37221
37641
|
}
|
|
@@ -37233,7 +37653,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
37233
37653
|
if (!proxyResult.ok) {
|
|
37234
37654
|
proxySpinner.fail("docker-socket-proxy recreate failed");
|
|
37235
37655
|
process.stderr.write(
|
|
37236
|
-
`${
|
|
37656
|
+
`${pc24.red("error")} docker compose up --force-recreate docker-socket-proxy failed:
|
|
37237
37657
|
${proxyResult.stderr.split("\n").slice(0, 3).join("\n ")}
|
|
37238
37658
|
`
|
|
37239
37659
|
);
|
|
@@ -37245,7 +37665,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
37245
37665
|
const orphanCheck = inspectContainer("olam-host-cp");
|
|
37246
37666
|
if (!orphanCheck.ok) {
|
|
37247
37667
|
process.stderr.write(
|
|
37248
|
-
`${
|
|
37668
|
+
`${pc24.red("error")} docker inspect olam-host-cp failed:
|
|
37249
37669
|
${orphanCheck.stderr.split("\n").slice(0, 3).join("\n ")}
|
|
37250
37670
|
`
|
|
37251
37671
|
);
|
|
@@ -37253,13 +37673,13 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
37253
37673
|
}
|
|
37254
37674
|
if (orphanCheck.exists && orphanCheck.service !== "olam-host-cp") {
|
|
37255
37675
|
process.stderr.write(
|
|
37256
|
-
`${
|
|
37676
|
+
`${pc24.yellow("info")} Removing pre-rename orphan container olam-host-cp (old project=${orphanCheck.project || "<none>"}, old service=${orphanCheck.service || "<none>"})
|
|
37257
37677
|
`
|
|
37258
37678
|
);
|
|
37259
37679
|
const rm = removeContainer("olam-host-cp");
|
|
37260
37680
|
if (!rm.ok) {
|
|
37261
37681
|
process.stderr.write(
|
|
37262
|
-
`${
|
|
37682
|
+
`${pc24.red("error")} docker rm -f olam-host-cp failed:
|
|
37263
37683
|
${rm.stderr.split("\n").slice(0, 3).join("\n ")}
|
|
37264
37684
|
`
|
|
37265
37685
|
);
|
|
@@ -37275,7 +37695,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
37275
37695
|
if (!composeResult.ok) {
|
|
37276
37696
|
composeSpinner.fail("compose recreate failed");
|
|
37277
37697
|
process.stderr.write(
|
|
37278
|
-
`${
|
|
37698
|
+
`${pc24.red("error")} docker compose up --force-recreate olam-host-cp failed:
|
|
37279
37699
|
${composeResult.stderr.split("\n").slice(0, 3).join("\n ")}
|
|
37280
37700
|
`
|
|
37281
37701
|
);
|
|
@@ -37288,7 +37708,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
37288
37708
|
if (!authResult.ok) {
|
|
37289
37709
|
authSpinner.fail("auth-service recreate failed");
|
|
37290
37710
|
process.stderr.write(
|
|
37291
|
-
`${
|
|
37711
|
+
`${pc24.red("error")} ${authResult.error ?? "unknown failure"}
|
|
37292
37712
|
`
|
|
37293
37713
|
);
|
|
37294
37714
|
return { exitCode: EXIT_GENERIC_ERROR, summary: "auth recreate failed" };
|
|
@@ -37301,7 +37721,7 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
37301
37721
|
if (!mcpResult.ok) {
|
|
37302
37722
|
mcpSpinner.fail("mcp-auth-service recreate failed");
|
|
37303
37723
|
process.stderr.write(
|
|
37304
|
-
`${
|
|
37724
|
+
`${pc24.red("error")} ${mcpResult.error ?? "unknown failure"}
|
|
37305
37725
|
`
|
|
37306
37726
|
);
|
|
37307
37727
|
return { exitCode: EXIT_GENERIC_ERROR, summary: "mcp-auth recreate failed" };
|
|
@@ -37525,11 +37945,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
|
|
|
37525
37945
|
process.once("SIGINT", releaseOnSignal);
|
|
37526
37946
|
process.once("SIGTERM", releaseOnSignal);
|
|
37527
37947
|
try {
|
|
37528
|
-
process.stdout.write(` ${
|
|
37948
|
+
process.stdout.write(` ${pc24.dim("rollback retag (3 ops)".padEnd(34))}`);
|
|
37529
37949
|
const swapStart = Date.now();
|
|
37530
37950
|
const swapResult = performRollbackSwap(PRODUCTION_SWAP_PLAN);
|
|
37531
37951
|
const swapDur = `${((Date.now() - swapStart) / 1e3).toFixed(1)}s`;
|
|
37532
|
-
process.stdout.write(`${swapResult.ok ?
|
|
37952
|
+
process.stdout.write(`${swapResult.ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${swapDur}
|
|
37533
37953
|
`);
|
|
37534
37954
|
if (!swapResult.ok) {
|
|
37535
37955
|
printError(`Rollback retag failed: ${swapResult.summary}`);
|
|
@@ -37539,11 +37959,11 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
|
|
|
37539
37959
|
printInfo("Rollback", swapResult.summary);
|
|
37540
37960
|
const composeFile = findComposeFile();
|
|
37541
37961
|
const authSecret = readAuthSecret2();
|
|
37542
|
-
process.stdout.write(` ${
|
|
37962
|
+
process.stdout.write(` ${pc24.dim("docker compose recreate olam-host-cp".padEnd(34))}`);
|
|
37543
37963
|
const composeStart = Date.now();
|
|
37544
37964
|
const composeResult = runCompose(["up", "-d", "--force-recreate", "--no-deps", "olam-host-cp"], composeFile, buildComposeEnv(authSecret, captureGhToken()));
|
|
37545
37965
|
const composeDur = `${((Date.now() - composeStart) / 1e3).toFixed(1)}s`;
|
|
37546
|
-
process.stdout.write(`${composeResult.ok ?
|
|
37966
|
+
process.stdout.write(`${composeResult.ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${composeDur}
|
|
37547
37967
|
`);
|
|
37548
37968
|
if (!composeResult.ok) {
|
|
37549
37969
|
printError(
|
|
@@ -37554,10 +37974,10 @@ Canonical tags are at :olam-rollback (good); container restart pending. Manually
|
|
|
37554
37974
|
process.exitCode = 1;
|
|
37555
37975
|
return;
|
|
37556
37976
|
}
|
|
37557
|
-
process.stdout.write(` ${
|
|
37977
|
+
process.stdout.write(` ${pc24.dim("recreate auth-service".padEnd(34))}`);
|
|
37558
37978
|
const authResult = await recreateAuthService();
|
|
37559
37979
|
const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
|
|
37560
|
-
process.stdout.write(`${authResult.ok ?
|
|
37980
|
+
process.stdout.write(`${authResult.ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${authDur}
|
|
37561
37981
|
`);
|
|
37562
37982
|
if (!authResult.ok) {
|
|
37563
37983
|
printError(`Auth-service recreate failed: ${authResult.error ?? "unknown"}`);
|
|
@@ -37723,7 +38143,7 @@ ${spaResult.stderr}`);
|
|
|
37723
38143
|
throw err;
|
|
37724
38144
|
}
|
|
37725
38145
|
if (step2.tee) {
|
|
37726
|
-
process.stdout.write(` ${
|
|
38146
|
+
process.stdout.write(` ${pc24.dim(step2.label.padEnd(34))}
|
|
37727
38147
|
`);
|
|
37728
38148
|
const start = Date.now();
|
|
37729
38149
|
const result = spawnSync23("bash", [scriptPath], {
|
|
@@ -37734,7 +38154,7 @@ ${spaResult.stderr}`);
|
|
|
37734
38154
|
const durationMs = Date.now() - start;
|
|
37735
38155
|
const ok = result.status === 0 && result.error === void 0;
|
|
37736
38156
|
const dur = `${(durationMs / 1e3).toFixed(1)}s`;
|
|
37737
|
-
process.stdout.write(` ${
|
|
38157
|
+
process.stdout.write(` ${pc24.dim(step2.label.padEnd(34))}${ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${dur}
|
|
37738
38158
|
`);
|
|
37739
38159
|
timings.push({ label: step2.label, durationMs });
|
|
37740
38160
|
if (!ok) {
|
|
@@ -37760,7 +38180,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
|
|
|
37760
38180
|
}
|
|
37761
38181
|
for (const t of timings) logRow.durations_ms[t.label] = t.durationMs;
|
|
37762
38182
|
const smokeStart = Date.now();
|
|
37763
|
-
process.stdout.write(` ${
|
|
38183
|
+
process.stdout.write(` ${pc24.dim("smoke (docker create + inspect)".padEnd(34))}`);
|
|
37764
38184
|
const smokeImages = [
|
|
37765
38185
|
"olam-auth:olam-next",
|
|
37766
38186
|
"olam-devbox:olam-next",
|
|
@@ -37770,7 +38190,7 @@ ${result.stderr.split("\n").slice(-3).join("\n")}`);
|
|
|
37770
38190
|
const smokeFailures = smokeResults.filter((r) => !r.ok);
|
|
37771
38191
|
const smokeDurationMs = Date.now() - smokeStart;
|
|
37772
38192
|
const smokeDur = `${(smokeDurationMs / 1e3).toFixed(1)}s`;
|
|
37773
|
-
process.stdout.write(`${smokeFailures.length === 0 ?
|
|
38193
|
+
process.stdout.write(`${smokeFailures.length === 0 ? pc24.green("\u2713") : pc24.red("\u2717")} ${smokeDur}
|
|
37774
38194
|
`);
|
|
37775
38195
|
timings.push({ label: "smoke", durationMs: smokeDurationMs });
|
|
37776
38196
|
if (smokeFailures.length > 0) {
|
|
@@ -37797,12 +38217,12 @@ Recovery options:
|
|
|
37797
38217
|
process.exitCode = 1;
|
|
37798
38218
|
return;
|
|
37799
38219
|
}
|
|
37800
|
-
process.stdout.write(` ${
|
|
38220
|
+
process.stdout.write(` ${pc24.dim("atomic 6-tag swap".padEnd(34))}`);
|
|
37801
38221
|
const swapStart = Date.now();
|
|
37802
38222
|
const swapResult = performAtomicSwap(PRODUCTION_SWAP_PLAN);
|
|
37803
38223
|
const swapDurationMs = Date.now() - swapStart;
|
|
37804
38224
|
const swapDur = `${(swapDurationMs / 1e3).toFixed(1)}s`;
|
|
37805
|
-
process.stdout.write(`${swapResult.ok ?
|
|
38225
|
+
process.stdout.write(`${swapResult.ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${swapDur}
|
|
37806
38226
|
`);
|
|
37807
38227
|
timings.push({ label: "atomic swap", durationMs: swapDurationMs });
|
|
37808
38228
|
if (!swapResult.ok) {
|
|
@@ -37812,7 +38232,7 @@ Recovery options:
|
|
|
37812
38232
|
}
|
|
37813
38233
|
printInfo("Swap", swapResult.summary);
|
|
37814
38234
|
const composeFile = findComposeFile();
|
|
37815
|
-
process.stdout.write(` ${
|
|
38235
|
+
process.stdout.write(` ${pc24.dim("docker compose recreate".padEnd(34))}`);
|
|
37816
38236
|
const composeStart = Date.now();
|
|
37817
38237
|
const composeResult = runCompose(
|
|
37818
38238
|
["up", "-d", "--force-recreate"],
|
|
@@ -37822,7 +38242,7 @@ Recovery options:
|
|
|
37822
38242
|
const composeDurationMs = Date.now() - composeStart;
|
|
37823
38243
|
const composeOk = composeResult.ok;
|
|
37824
38244
|
const composeDur = `${(composeDurationMs / 1e3).toFixed(1)}s`;
|
|
37825
|
-
process.stdout.write(`${composeOk ?
|
|
38245
|
+
process.stdout.write(`${composeOk ? pc24.green("\u2713") : pc24.red("\u2717")} ${composeDur}
|
|
37826
38246
|
`);
|
|
37827
38247
|
timings.push({ label: "container recreate", durationMs: composeDurationMs });
|
|
37828
38248
|
if (!composeOk) {
|
|
@@ -37838,10 +38258,10 @@ Recovery options:
|
|
|
37838
38258
|
process.exitCode = 1;
|
|
37839
38259
|
return;
|
|
37840
38260
|
}
|
|
37841
|
-
process.stdout.write(` ${
|
|
38261
|
+
process.stdout.write(` ${pc24.dim("recreate auth-service".padEnd(34))}`);
|
|
37842
38262
|
const authResult = await recreateAuthService();
|
|
37843
38263
|
const authDur = `${(authResult.durationMs / 1e3).toFixed(1)}s`;
|
|
37844
|
-
process.stdout.write(`${authResult.ok ?
|
|
38264
|
+
process.stdout.write(`${authResult.ok ? pc24.green("\u2713") : pc24.red("\u2717")} ${authDur}
|
|
37845
38265
|
`);
|
|
37846
38266
|
timings.push({ label: "auth recreate", durationMs: authResult.durationMs });
|
|
37847
38267
|
if (!authResult.ok) {
|
|
@@ -37856,12 +38276,12 @@ Recovery options:
|
|
|
37856
38276
|
process.exitCode = 1;
|
|
37857
38277
|
return;
|
|
37858
38278
|
}
|
|
37859
|
-
process.stdout.write(` ${
|
|
38279
|
+
process.stdout.write(` ${pc24.dim("waiting for /health".padEnd(34))}`);
|
|
37860
38280
|
const healthStart = Date.now();
|
|
37861
38281
|
const healthy = await waitForHealth(1e4);
|
|
37862
38282
|
const healthDurationMs = Date.now() - healthStart;
|
|
37863
38283
|
const healthDur = `${(healthDurationMs / 1e3).toFixed(1)}s`;
|
|
37864
|
-
process.stdout.write(`${healthy ?
|
|
38284
|
+
process.stdout.write(`${healthy ? pc24.green("\u2713") : pc24.yellow("?")} ${healthDur}
|
|
37865
38285
|
`);
|
|
37866
38286
|
timings.push({ label: "/health", durationMs: healthDurationMs });
|
|
37867
38287
|
if (!healthy) {
|
|
@@ -37869,12 +38289,12 @@ Recovery options:
|
|
|
37869
38289
|
"Host CP started but /health did not respond within 10s.\n \u2022 Check: docker logs olam-host-cp\n \u2022 If the new SHA is broken: `olam upgrade --rollback` restores the prior set in <30s."
|
|
37870
38290
|
);
|
|
37871
38291
|
}
|
|
37872
|
-
process.stdout.write(` ${
|
|
38292
|
+
process.stdout.write(` ${pc24.dim("verify /version/status round-trip".padEnd(34))}`);
|
|
37873
38293
|
const versionStart = Date.now();
|
|
37874
38294
|
const versionMatch = await waitForVersionMatch(_targetSha, 9e4);
|
|
37875
38295
|
const versionDurationMs = Date.now() - versionStart;
|
|
37876
38296
|
const versionDur = `${(versionDurationMs / 1e3).toFixed(1)}s`;
|
|
37877
|
-
process.stdout.write(`${versionMatch.matched ?
|
|
38297
|
+
process.stdout.write(`${versionMatch.matched ? pc24.green("\u2713") : pc24.yellow("?")} ${versionDur}
|
|
37878
38298
|
`);
|
|
37879
38299
|
timings.push({ label: "/version/status round-trip", durationMs: versionDurationMs });
|
|
37880
38300
|
if (!versionMatch.matched) {
|
|
@@ -37979,12 +38399,12 @@ init_host_cp();
|
|
|
37979
38399
|
init_context();
|
|
37980
38400
|
init_output();
|
|
37981
38401
|
import * as http4 from "node:http";
|
|
37982
|
-
import
|
|
38402
|
+
import pc25 from "picocolors";
|
|
37983
38403
|
var HOST_CP_PORT3 = 19e3;
|
|
37984
38404
|
function colorLine(line) {
|
|
37985
|
-
if (/\bERROR\b/.test(line)) return
|
|
37986
|
-
if (/\bWARN\b/.test(line)) return
|
|
37987
|
-
if (/\bINFO\b/.test(line)) return
|
|
38405
|
+
if (/\bERROR\b/.test(line)) return pc25.red(line);
|
|
38406
|
+
if (/\bWARN\b/.test(line)) return pc25.yellow(line);
|
|
38407
|
+
if (/\bINFO\b/.test(line)) return pc25.dim(line);
|
|
37988
38408
|
return line;
|
|
37989
38409
|
}
|
|
37990
38410
|
function buildLogsUrl(worldId, opts, port2 = HOST_CP_PORT3) {
|
|
@@ -38081,7 +38501,7 @@ function registerLogs(program2) {
|
|
|
38081
38501
|
// src/commands/ps.ts
|
|
38082
38502
|
init_context();
|
|
38083
38503
|
init_output();
|
|
38084
|
-
import
|
|
38504
|
+
import pc26 from "picocolors";
|
|
38085
38505
|
import { spawnSync as spawnSync24 } from "node:child_process";
|
|
38086
38506
|
var SAFE_IDENT4 = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
38087
38507
|
function parseDockerTop(stdout) {
|
|
@@ -38164,18 +38584,18 @@ function printTable2(rows) {
|
|
|
38164
38584
|
const fixedWidth = 5 + 1 + 8 + 1 + 6 + 1 + 6 + 1 + 10 + 1 + 6 + 1;
|
|
38165
38585
|
const cmdWidth = Math.max(20, cols - fixedWidth);
|
|
38166
38586
|
const header = [
|
|
38167
|
-
|
|
38168
|
-
|
|
38169
|
-
|
|
38170
|
-
|
|
38171
|
-
|
|
38172
|
-
|
|
38173
|
-
|
|
38587
|
+
pc26.bold(pc26.dim("PID".padEnd(5))),
|
|
38588
|
+
pc26.bold(pc26.dim("USER".padEnd(8))),
|
|
38589
|
+
pc26.bold(pc26.dim("%CPU".padEnd(6))),
|
|
38590
|
+
pc26.bold(pc26.dim("%MEM".padEnd(6))),
|
|
38591
|
+
pc26.bold(pc26.dim("STARTED".padEnd(10))),
|
|
38592
|
+
pc26.bold(pc26.dim("STATE".padEnd(6))),
|
|
38593
|
+
pc26.bold(pc26.dim("COMMAND"))
|
|
38174
38594
|
].join(" ");
|
|
38175
38595
|
console.log(header);
|
|
38176
38596
|
for (const row of rows) {
|
|
38177
38597
|
const cmd = row.command.length > cmdWidth ? row.command.slice(0, cmdWidth - 1) + "\u2026" : row.command;
|
|
38178
|
-
const stateFn = row.state.startsWith("R") ?
|
|
38598
|
+
const stateFn = row.state.startsWith("R") ? pc26.green : row.state.startsWith("Z") ? pc26.red : pc26.dim;
|
|
38179
38599
|
console.log([
|
|
38180
38600
|
row.pid.padEnd(5),
|
|
38181
38601
|
row.user.slice(0, 8).padEnd(8),
|
|
@@ -38229,7 +38649,7 @@ function registerPs(program2) {
|
|
|
38229
38649
|
printTable2(rows);
|
|
38230
38650
|
if (opts.watch) {
|
|
38231
38651
|
process.stdout.write(`
|
|
38232
|
-
${
|
|
38652
|
+
${pc26.dim(`world: ${worldId} sort: ${sortKey} refresh: 5s Ctrl-C to exit`)}
|
|
38233
38653
|
`);
|
|
38234
38654
|
}
|
|
38235
38655
|
}
|
|
@@ -38379,7 +38799,7 @@ init_output();
|
|
|
38379
38799
|
import * as fs49 from "node:fs";
|
|
38380
38800
|
import * as path52 from "node:path";
|
|
38381
38801
|
import { execSync as execSync12 } from "node:child_process";
|
|
38382
|
-
import
|
|
38802
|
+
import pc27 from "picocolors";
|
|
38383
38803
|
|
|
38384
38804
|
// src/commands/world.ts
|
|
38385
38805
|
function getOrCreateWorldCommand(program2) {
|
|
@@ -38489,7 +38909,7 @@ async function handleCreate2(worldId, kindArg) {
|
|
|
38489
38909
|
const label = r.repo ? `${r.kind}/${r.repo}` : r.kind;
|
|
38490
38910
|
if (r.ok) {
|
|
38491
38911
|
printSuccess(`${label}`);
|
|
38492
|
-
console.log(` ${
|
|
38912
|
+
console.log(` ${pc27.dim(r.tarPath)}`);
|
|
38493
38913
|
} else {
|
|
38494
38914
|
printWarning(`${label}: ${r.msg ?? "skipped"}`);
|
|
38495
38915
|
}
|
|
@@ -38679,18 +39099,18 @@ function handleInspect(opts) {
|
|
|
38679
39099
|
const label = `${out.kind}/${out.repo}`;
|
|
38680
39100
|
if (out.outcome === "hit") {
|
|
38681
39101
|
const size = out.sizeBytes !== void 0 ? ` (${formatBytes4(out.sizeBytes)})` : "";
|
|
38682
|
-
printSuccess(`${label.padEnd(24)} HIT ${
|
|
39102
|
+
printSuccess(`${label.padEnd(24)} HIT ${pc27.dim(out.fingerprint ?? "")}${size}`);
|
|
38683
39103
|
} else {
|
|
38684
39104
|
printWarning(`${label.padEnd(24)} MISS ${explainInspectReason(out)}`);
|
|
38685
39105
|
if (out.expectedTarPath) {
|
|
38686
|
-
console.log(` ${
|
|
39106
|
+
console.log(` ${pc27.dim("expected: " + out.expectedTarPath)}`);
|
|
38687
39107
|
}
|
|
38688
39108
|
}
|
|
38689
39109
|
}
|
|
38690
39110
|
console.log();
|
|
38691
39111
|
if (hits === 0) {
|
|
38692
39112
|
console.log(
|
|
38693
|
-
|
|
39113
|
+
pc27.dim(
|
|
38694
39114
|
"No warm snapshot would be restored \u2014 the next `olam create` takes the cold path. See docs/architecture/snapshot-restore.md \xA7 FAQ."
|
|
38695
39115
|
)
|
|
38696
39116
|
);
|
|
@@ -38702,7 +39122,7 @@ async function handleEvict(opts) {
|
|
|
38702
39122
|
if (opts.dryRun) {
|
|
38703
39123
|
const root = snapshotsDir();
|
|
38704
39124
|
if (!fs49.existsSync(root)) {
|
|
38705
|
-
console.log(
|
|
39125
|
+
console.log(pc27.dim("No snapshot dir; nothing to evict."));
|
|
38706
39126
|
return;
|
|
38707
39127
|
}
|
|
38708
39128
|
const allTars = [];
|
|
@@ -38735,17 +39155,17 @@ async function handleEvict(opts) {
|
|
|
38735
39155
|
console.log();
|
|
38736
39156
|
for (const t of toEvict) {
|
|
38737
39157
|
const age = formatAge2(Date.now() - t.mtime);
|
|
38738
|
-
console.log(` ${
|
|
39158
|
+
console.log(` ${pc27.dim(formatBytes4(t.size).padStart(8))} ${age.padStart(10)} ${t.path}`);
|
|
38739
39159
|
}
|
|
38740
39160
|
console.log();
|
|
38741
|
-
console.log(
|
|
39161
|
+
console.log(pc27.dim(`Total after eviction: ${formatBytes4(remaining)} (cap: ${formatBytes4(maxBytes)})`));
|
|
38742
39162
|
return;
|
|
38743
39163
|
}
|
|
38744
39164
|
const freed = evictOldSnapshotsWithFlock(maxBytes);
|
|
38745
39165
|
if (freed > 0) {
|
|
38746
39166
|
printSuccess(`Evicted ${formatBytes4(freed)} (cap: ${formatBytes4(maxBytes)})`);
|
|
38747
39167
|
} else {
|
|
38748
|
-
console.log(
|
|
39168
|
+
console.log(pc27.dim("No eviction needed (or another process held the lock)."));
|
|
38749
39169
|
}
|
|
38750
39170
|
}
|
|
38751
39171
|
function handleList2(worldIdFilter) {
|
|
@@ -38753,7 +39173,7 @@ function handleList2(worldIdFilter) {
|
|
|
38753
39173
|
const entries = listSnapshots(worldIdFilter);
|
|
38754
39174
|
if (entries.length === 0) {
|
|
38755
39175
|
const where = worldIdFilter ? ` for world "${worldIdFilter}"` : "";
|
|
38756
|
-
console.log(
|
|
39176
|
+
console.log(pc27.dim(`No snapshots found${where}. Run \`olam world snapshot create <worldId>\` first.`));
|
|
38757
39177
|
return;
|
|
38758
39178
|
}
|
|
38759
39179
|
printHeader(`${entries.length} snapshot(s)`);
|
|
@@ -38762,15 +39182,15 @@ function handleList2(worldIdFilter) {
|
|
|
38762
39182
|
for (const entry of entries) {
|
|
38763
39183
|
const { manifest } = entry;
|
|
38764
39184
|
if (manifest.worldId !== lastWorldId) {
|
|
38765
|
-
console.log(
|
|
39185
|
+
console.log(pc27.bold(manifest.worldId));
|
|
38766
39186
|
lastWorldId = manifest.worldId;
|
|
38767
39187
|
}
|
|
38768
39188
|
const repo = manifest.repo ?? "(all repos)";
|
|
38769
39189
|
const size = formatBytes4(manifest.sizeBytes);
|
|
38770
39190
|
const age = formatAge2(entry.ageMs);
|
|
38771
|
-
const kindColor = manifest.kind === "gems" ?
|
|
39191
|
+
const kindColor = manifest.kind === "gems" ? pc27.magenta(manifest.kind) : manifest.kind === "node" ? pc27.cyan(manifest.kind) : pc27.yellow(manifest.kind);
|
|
38772
39192
|
console.log(
|
|
38773
|
-
` ${kindColor.padEnd(6)} ${
|
|
39193
|
+
` ${kindColor.padEnd(6)} ${pc27.dim(repo.padEnd(24))} ${manifest.fingerprint} ${size.padStart(8)} ${age}`
|
|
38774
39194
|
);
|
|
38775
39195
|
}
|
|
38776
39196
|
console.log();
|
|
@@ -39122,7 +39542,7 @@ import * as fs52 from "node:fs";
|
|
|
39122
39542
|
import * as os30 from "node:os";
|
|
39123
39543
|
import * as path55 from "node:path";
|
|
39124
39544
|
import { execFileSync as execFileSync13, execSync as execSync13 } from "node:child_process";
|
|
39125
|
-
import
|
|
39545
|
+
import pc28 from "picocolors";
|
|
39126
39546
|
|
|
39127
39547
|
// ../core/dist/diagnose/secret-stripper.js
|
|
39128
39548
|
var SECRET_PATTERNS = [
|
|
@@ -39260,23 +39680,23 @@ function registerDiagnose(program2) {
|
|
|
39260
39680
|
return;
|
|
39261
39681
|
}
|
|
39262
39682
|
if (!opts.quiet) {
|
|
39263
|
-
console.log(
|
|
39683
|
+
console.log(pc28.cyan("Building diagnostics zip\u2026"));
|
|
39264
39684
|
}
|
|
39265
39685
|
try {
|
|
39266
39686
|
const { zipPath, entries } = await buildDiagnosticsZip();
|
|
39267
39687
|
if (!opts.quiet) {
|
|
39268
|
-
console.log(
|
|
39269
|
-
console.log(
|
|
39688
|
+
console.log(pc28.green(`Done: ${zipPath}`));
|
|
39689
|
+
console.log(pc28.dim(`Contents: ${entries.join(", ")}`));
|
|
39270
39690
|
}
|
|
39271
39691
|
if (opts.upload) {
|
|
39272
|
-
console.log(
|
|
39692
|
+
console.log(pc28.yellow(
|
|
39273
39693
|
`Telemetry endpoint not yet provisioned. Share the zip manually:
|
|
39274
39694
|
File: ${zipPath}
|
|
39275
39695
|
See docs/runbooks/share-diagnostics.md for instructions.`
|
|
39276
39696
|
));
|
|
39277
39697
|
}
|
|
39278
39698
|
} catch (err) {
|
|
39279
|
-
console.error(
|
|
39699
|
+
console.error(pc28.red(`Diagnose failed: ${err.message}`));
|
|
39280
39700
|
process.exitCode = 1;
|
|
39281
39701
|
}
|
|
39282
39702
|
});
|
|
@@ -39979,13 +40399,13 @@ function registerDoctor(program2) {
|
|
|
39979
40399
|
}
|
|
39980
40400
|
|
|
39981
40401
|
// src/commands/substrate.ts
|
|
39982
|
-
import
|
|
40402
|
+
import pc30 from "picocolors";
|
|
39983
40403
|
init_context();
|
|
39984
40404
|
init_output();
|
|
39985
40405
|
|
|
39986
40406
|
// src/commands/substrate-audit-log.ts
|
|
39987
40407
|
import * as fs55 from "node:fs";
|
|
39988
|
-
import
|
|
40408
|
+
import pc29 from "picocolors";
|
|
39989
40409
|
var VALID_PERIPHERAL_NAMES = PERIPHERALS.map((p) => p.name).sort();
|
|
39990
40410
|
var DEFAULT_LIMIT = 50;
|
|
39991
40411
|
function parseAuditLog(raw) {
|
|
@@ -40002,8 +40422,8 @@ function parseAuditLog(raw) {
|
|
|
40002
40422
|
}
|
|
40003
40423
|
function formatEntryRow(entry, index) {
|
|
40004
40424
|
const ts = entry.ts ?? "(no timestamp)";
|
|
40005
|
-
const regression = entry.security_regression ?
|
|
40006
|
-
const accepted = entry.accepted ?
|
|
40425
|
+
const regression = entry.security_regression ? pc29.red("yes") : pc29.green("no");
|
|
40426
|
+
const accepted = entry.accepted ? pc29.yellow("yes") : "\u2014";
|
|
40007
40427
|
const fields = (entry.changed_fields ?? []).join(", ") || "\u2014";
|
|
40008
40428
|
return ` ${String(index + 1).padStart(3)} ${ts} regression=${regression} accepted=${accepted} fields=[${fields}]`;
|
|
40009
40429
|
}
|
|
@@ -40029,7 +40449,7 @@ function handleAuditLog(opts, deps = {}) {
|
|
|
40029
40449
|
raw = readFileSyncImpl(auditLogPath, "utf8");
|
|
40030
40450
|
} catch (err) {
|
|
40031
40451
|
stderr.write(
|
|
40032
|
-
`${
|
|
40452
|
+
`${pc29.red("error:")} could not read audit log at ${auditLogPath}: ${err instanceof Error ? err.message : String(err)}
|
|
40033
40453
|
`
|
|
40034
40454
|
);
|
|
40035
40455
|
return 1;
|
|
@@ -40038,7 +40458,7 @@ function handleAuditLog(opts, deps = {}) {
|
|
|
40038
40458
|
if (opts.peripheral) {
|
|
40039
40459
|
if (!VALID_PERIPHERAL_NAMES.includes(opts.peripheral)) {
|
|
40040
40460
|
stderr.write(
|
|
40041
|
-
`${
|
|
40461
|
+
`${pc29.red("error:")} unknown peripheral "${opts.peripheral}". Valid names: ${VALID_PERIPHERAL_NAMES.join(", ")}
|
|
40042
40462
|
`
|
|
40043
40463
|
);
|
|
40044
40464
|
return 1;
|
|
@@ -40049,7 +40469,7 @@ function handleAuditLog(opts, deps = {}) {
|
|
|
40049
40469
|
const sinceMs = Date.parse(opts.since);
|
|
40050
40470
|
if (Number.isNaN(sinceMs)) {
|
|
40051
40471
|
stderr.write(
|
|
40052
|
-
`${
|
|
40472
|
+
`${pc29.red("error:")} invalid --since date "${opts.since}". Expected ISO-8601 (e.g. 2026-05-20T00:00:00Z).
|
|
40053
40473
|
`
|
|
40054
40474
|
);
|
|
40055
40475
|
return 1;
|
|
@@ -40104,9 +40524,9 @@ async function defaultCountWorlds() {
|
|
|
40104
40524
|
}
|
|
40105
40525
|
function formatBetaLine(cfg) {
|
|
40106
40526
|
if (cfg.host.substrate === "compose") {
|
|
40107
|
-
return `Substrate: ${
|
|
40527
|
+
return `Substrate: ${pc30.bold("compose")}`;
|
|
40108
40528
|
}
|
|
40109
|
-
return `Substrate: ${
|
|
40529
|
+
return `Substrate: ${pc30.bold("kubernetes")} (beta until ${BETA_EXPIRY_DATE}, flavor=k3s)`;
|
|
40110
40530
|
}
|
|
40111
40531
|
async function handleGet(deps = {}) {
|
|
40112
40532
|
const read = deps.readConfig ?? readConfig;
|
|
@@ -40128,7 +40548,7 @@ async function handleSet(target, deps = {}) {
|
|
|
40128
40548
|
void runDoctorFn;
|
|
40129
40549
|
if (target !== "compose" && target !== "kubernetes") {
|
|
40130
40550
|
stderr.write(
|
|
40131
|
-
`${
|
|
40551
|
+
`${pc30.red("error:")} unsupported substrate "${target}". Expected: compose | kubernetes.
|
|
40132
40552
|
`
|
|
40133
40553
|
);
|
|
40134
40554
|
return 1;
|
|
@@ -40137,7 +40557,7 @@ async function handleSet(target, deps = {}) {
|
|
|
40137
40557
|
const current = read();
|
|
40138
40558
|
if (current.host.substrate === targetSubstrate) {
|
|
40139
40559
|
stdout.write(
|
|
40140
|
-
`Substrate already set to ${
|
|
40560
|
+
`Substrate already set to ${pc30.bold(targetSubstrate)}. No change.
|
|
40141
40561
|
`
|
|
40142
40562
|
);
|
|
40143
40563
|
return 0;
|
|
@@ -40147,23 +40567,23 @@ async function handleSet(target, deps = {}) {
|
|
|
40147
40567
|
worldsCount = await countWorlds();
|
|
40148
40568
|
} catch (err) {
|
|
40149
40569
|
stderr.write(
|
|
40150
|
-
`${
|
|
40570
|
+
`${pc30.yellow("warn:")} could not list worlds (${err instanceof Error ? err.message : String(err)}); assuming none exist and proceeding.
|
|
40151
40571
|
`
|
|
40152
40572
|
);
|
|
40153
40573
|
worldsCount = 0;
|
|
40154
40574
|
}
|
|
40155
40575
|
if (worldsCount > 0) {
|
|
40156
40576
|
stderr.write(
|
|
40157
|
-
`${
|
|
40577
|
+
`${pc30.red("error:")} ${worldsCount} world(s) exist on the current substrate (${pc30.bold(
|
|
40158
40578
|
current.host.substrate
|
|
40159
40579
|
)}). Switching substrates abandons their state.
|
|
40160
40580
|
`
|
|
40161
40581
|
);
|
|
40162
|
-
stderr.write(` Run ${
|
|
40582
|
+
stderr.write(` Run ${pc30.bold("olam destroy --all")} first, then re-run this command.
|
|
40163
40583
|
`);
|
|
40164
40584
|
return 1;
|
|
40165
40585
|
}
|
|
40166
|
-
stdout.write(`Running pre-flight for ${
|
|
40586
|
+
stdout.write(`Running pre-flight for ${pc30.bold(targetSubstrate)} substrate\u2026
|
|
40167
40587
|
`);
|
|
40168
40588
|
let doctorResult;
|
|
40169
40589
|
try {
|
|
@@ -40174,18 +40594,18 @@ async function handleSet(target, deps = {}) {
|
|
|
40174
40594
|
}
|
|
40175
40595
|
} catch (err) {
|
|
40176
40596
|
stderr.write(
|
|
40177
|
-
`${
|
|
40597
|
+
`${pc30.red("error:")} pre-flight crashed: ${err instanceof Error ? err.message : String(err)}
|
|
40178
40598
|
`
|
|
40179
40599
|
);
|
|
40180
40600
|
return 1;
|
|
40181
40601
|
}
|
|
40182
40602
|
if (doctorResult.exitCode !== 0) {
|
|
40183
40603
|
stderr.write(
|
|
40184
|
-
`${
|
|
40604
|
+
`${pc30.red("error:")} pre-flight failed for ${pc30.bold(targetSubstrate)} substrate.
|
|
40185
40605
|
`
|
|
40186
40606
|
);
|
|
40187
40607
|
stderr.write(
|
|
40188
|
-
` Run ${
|
|
40608
|
+
` Run ${pc30.bold(
|
|
40189
40609
|
`olam doctor${targetSubstrate === "kubernetes" ? " --substrate=kubernetes" : ""}`
|
|
40190
40610
|
)} to see what's missing, fix the named prereqs, then re-run.
|
|
40191
40611
|
`
|
|
@@ -40202,14 +40622,14 @@ async function handleSet(target, deps = {}) {
|
|
|
40202
40622
|
stdout.write(
|
|
40203
40623
|
`
|
|
40204
40624
|
Kubernetes substrate is in beta until ${BETA_EXPIRY_DATE}.
|
|
40205
|
-
Rollback: ${
|
|
40206
|
-
Next: ${
|
|
40625
|
+
Rollback: ${pc30.bold("olam substrate set compose")} (preserves compose worlds you create after this).
|
|
40626
|
+
Next: ${pc30.bold("olam upgrade")} to deploy host-cp to your kubectl context.
|
|
40207
40627
|
`
|
|
40208
40628
|
);
|
|
40209
40629
|
} else {
|
|
40210
40630
|
stdout.write(
|
|
40211
40631
|
`
|
|
40212
|
-
Next: ${
|
|
40632
|
+
Next: ${pc30.bold("olam upgrade")} to redeploy host-cp on the compose substrate.
|
|
40213
40633
|
`
|
|
40214
40634
|
);
|
|
40215
40635
|
}
|
|
@@ -40713,7 +41133,7 @@ import path81 from "node:path";
|
|
|
40713
41133
|
import { createInterface as createInterface4 } from "node:readline";
|
|
40714
41134
|
|
|
40715
41135
|
// src/lib/shell-rc.ts
|
|
40716
|
-
import { copyFileSync as copyFileSync5, existsSync as existsSync62, readFileSync as readFileSync52, renameSync as renameSync8, writeFileSync as
|
|
41136
|
+
import { copyFileSync as copyFileSync5, existsSync as existsSync62, readFileSync as readFileSync52, renameSync as renameSync8, writeFileSync as writeFileSync31 } from "node:fs";
|
|
40717
41137
|
import path58 from "node:path";
|
|
40718
41138
|
function appendIdempotent(opts) {
|
|
40719
41139
|
const { rcPath, marker, contentLine, clock = () => /* @__PURE__ */ new Date() } = opts;
|
|
@@ -40731,7 +41151,7 @@ function appendIdempotent(opts) {
|
|
|
40731
41151
|
const trailing = contentLine.endsWith("\n") ? "" : "\n";
|
|
40732
41152
|
const nextContent = `${content}${separator}${contentLine}${trailing}`;
|
|
40733
41153
|
const tmpPath = `${rcPath}.olam-tmp.${process.pid}`;
|
|
40734
|
-
|
|
41154
|
+
writeFileSync31(tmpPath, nextContent, { encoding: "utf-8" });
|
|
40735
41155
|
renameSync8(tmpPath, rcPath);
|
|
40736
41156
|
return { status: "appended", backupPath };
|
|
40737
41157
|
}
|
|
@@ -41335,7 +41755,7 @@ async function phase2_5ProvisionCluster(substrate, clusterName, opts, deps, reus
|
|
|
41335
41755
|
return {
|
|
41336
41756
|
ok: false,
|
|
41337
41757
|
message: `k3d cluster create ${clusterName} failed (exit ${createResult.status ?? "signal"})`,
|
|
41338
|
-
remedy: `Run manually: k3d cluster create ${clusterName} --wait --timeout 90s`
|
|
41758
|
+
remedy: `Run manually: k3d cluster create ${clusterName} --volume ~/.config/gh:/host/.config/gh --wait --timeout 90s`
|
|
41339
41759
|
};
|
|
41340
41760
|
}
|
|
41341
41761
|
const ctxResult = captureSpawnSync("kubectl", ["config", "current-context"]);
|
|
@@ -41853,7 +42273,7 @@ import * as fs82 from "node:fs";
|
|
|
41853
42273
|
import * as os46 from "node:os";
|
|
41854
42274
|
import * as path84 from "node:path";
|
|
41855
42275
|
import { execSync as execSync15 } from "node:child_process";
|
|
41856
|
-
import
|
|
42276
|
+
import pc31 from "picocolors";
|
|
41857
42277
|
|
|
41858
42278
|
// src/lib/symlink-reconcile.ts
|
|
41859
42279
|
import * as fs80 from "node:fs";
|
|
@@ -42005,37 +42425,37 @@ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSy
|
|
|
42005
42425
|
writeLastStable(prevVersion);
|
|
42006
42426
|
}
|
|
42007
42427
|
if (!quiet) {
|
|
42008
|
-
console.log(
|
|
42428
|
+
console.log(pc31.cyan(`Installing ${PACKAGE_NAME}@${channel}\u2026`));
|
|
42009
42429
|
}
|
|
42010
42430
|
const installResult = _exec(`npm install -g ${PACKAGE_NAME}@${channel}`);
|
|
42011
42431
|
if (installResult.exitCode !== 0) {
|
|
42012
42432
|
logUpdateFailure(installResult.stderr);
|
|
42013
42433
|
if (!quiet) {
|
|
42014
|
-
console.error(
|
|
42434
|
+
console.error(pc31.red("Update failed."));
|
|
42015
42435
|
}
|
|
42016
42436
|
const prev = readLastStable();
|
|
42017
42437
|
if (prev) {
|
|
42018
42438
|
if (!quiet) {
|
|
42019
|
-
console.log(
|
|
42439
|
+
console.log(pc31.yellow(`Restoring to ${prev}\u2026`));
|
|
42020
42440
|
}
|
|
42021
42441
|
const restoreResult = _exec(`npm install -g ${PACKAGE_NAME}@${prev}`);
|
|
42022
42442
|
if (restoreResult.exitCode !== 0) {
|
|
42023
42443
|
if (!quiet) {
|
|
42024
|
-
console.error(
|
|
42444
|
+
console.error(pc31.red(
|
|
42025
42445
|
`Restore also failed. Run: npm install -g ${PACKAGE_NAME}@${prev} manually.`
|
|
42026
42446
|
));
|
|
42027
42447
|
}
|
|
42028
42448
|
} else if (!quiet) {
|
|
42029
|
-
console.log(
|
|
42449
|
+
console.log(pc31.yellow(`Restored to ${prev}.`));
|
|
42030
42450
|
}
|
|
42031
42451
|
} else if (!quiet) {
|
|
42032
|
-
console.error(
|
|
42452
|
+
console.error(pc31.red("No previous version cached; cannot auto-restore."));
|
|
42033
42453
|
}
|
|
42034
42454
|
return { action: "restored", prevVersion: prev ?? void 0, exitCode: 11 };
|
|
42035
42455
|
}
|
|
42036
42456
|
const newVersion = getCurrentVersion(_exec) ?? void 0;
|
|
42037
42457
|
if (!quiet && newVersion) {
|
|
42038
|
-
console.log(
|
|
42458
|
+
console.log(pc31.green(`Updated to ${newVersion}.`));
|
|
42039
42459
|
}
|
|
42040
42460
|
const npmRootResult = _getNpmRoot("npm root -g");
|
|
42041
42461
|
let symlinkResult = { added: [], removed: [] };
|
|
@@ -42047,10 +42467,10 @@ async function doUpdate(opts, _exec = defaultExec, _reconcile = reconcileSkillSy
|
|
|
42047
42467
|
symlinkResult = { added: rec.added, removed: rec.removed };
|
|
42048
42468
|
if (!quiet && (rec.added.length > 0 || rec.removed.length > 0)) {
|
|
42049
42469
|
if (rec.added.length > 0) {
|
|
42050
|
-
console.log(
|
|
42470
|
+
console.log(pc31.dim(`Skills added: ${rec.added.join(", ")}`));
|
|
42051
42471
|
}
|
|
42052
42472
|
if (rec.removed.length > 0) {
|
|
42053
|
-
console.log(
|
|
42473
|
+
console.log(pc31.dim(`Skills removed (dangling): ${rec.removed.join(", ")}`));
|
|
42054
42474
|
}
|
|
42055
42475
|
}
|
|
42056
42476
|
}
|
|
@@ -42144,7 +42564,7 @@ function registerUpdate(program2) {
|
|
|
42144
42564
|
// src/commands/begin.ts
|
|
42145
42565
|
init_host_cp();
|
|
42146
42566
|
init_open_url();
|
|
42147
|
-
import
|
|
42567
|
+
import pc32 from "picocolors";
|
|
42148
42568
|
async function doBegin(opts, _startFn = startHostCp, _openFn = openUrl) {
|
|
42149
42569
|
const prevExitCode = process.exitCode;
|
|
42150
42570
|
await _startFn({ showToken: opts.showToken });
|
|
@@ -42154,7 +42574,7 @@ async function doBegin(opts, _startFn = startHostCp, _openFn = openUrl) {
|
|
|
42154
42574
|
const token = readToken();
|
|
42155
42575
|
if (token) {
|
|
42156
42576
|
const base = `http://127.0.0.1:${HOST_CP_PORT}/`;
|
|
42157
|
-
console.log(
|
|
42577
|
+
console.log(pc32.dim(`Opening ${base}`));
|
|
42158
42578
|
_openFn(`${base}?token=${token}`);
|
|
42159
42579
|
}
|
|
42160
42580
|
}
|
|
@@ -42302,7 +42722,7 @@ function registerConfig(program2) {
|
|
|
42302
42722
|
// src/commands/repos.ts
|
|
42303
42723
|
init_global_config();
|
|
42304
42724
|
init_output();
|
|
42305
|
-
import
|
|
42725
|
+
import pc33 from "picocolors";
|
|
42306
42726
|
|
|
42307
42727
|
// src/commands/repos-list-json.ts
|
|
42308
42728
|
init_skill_sources();
|
|
@@ -42337,14 +42757,14 @@ function registerRepos(program2) {
|
|
|
42337
42757
|
return;
|
|
42338
42758
|
}
|
|
42339
42759
|
if (all.length === 0) {
|
|
42340
|
-
console.log(
|
|
42760
|
+
console.log(pc33.dim("0 repo(s) registered. Add one with: olam repos add --name <n> --path <p>"));
|
|
42341
42761
|
return;
|
|
42342
42762
|
}
|
|
42343
42763
|
printHeader(`${all.length} repo(s)`);
|
|
42344
42764
|
for (const r of all) {
|
|
42345
42765
|
const when = new Date(r.addedAt).toISOString().slice(0, 10);
|
|
42346
42766
|
console.log(
|
|
42347
|
-
` ${
|
|
42767
|
+
` ${pc33.bold(r.name.padEnd(24))} ${r.path.padEnd(48)} ${pc33.dim(when)}`
|
|
42348
42768
|
);
|
|
42349
42769
|
}
|
|
42350
42770
|
});
|
|
@@ -42389,7 +42809,7 @@ function registerRepos(program2) {
|
|
|
42389
42809
|
// src/commands/runbooks.ts
|
|
42390
42810
|
init_global_config();
|
|
42391
42811
|
init_output();
|
|
42392
|
-
import
|
|
42812
|
+
import pc34 from "picocolors";
|
|
42393
42813
|
function asMessage2(err) {
|
|
42394
42814
|
return err instanceof Error ? err.message : String(err);
|
|
42395
42815
|
}
|
|
@@ -42408,13 +42828,13 @@ function renderRunbookList(runbooks, opts) {
|
|
|
42408
42828
|
);
|
|
42409
42829
|
}
|
|
42410
42830
|
if (runbooks.length === 0) {
|
|
42411
|
-
return
|
|
42831
|
+
return pc34.dim("0 runbook(s). Add one with: olam runbooks add <name> --repos <repo>");
|
|
42412
42832
|
}
|
|
42413
|
-
const lines = [
|
|
42833
|
+
const lines = [pc34.bold(`${runbooks.length} runbook(s)`)];
|
|
42414
42834
|
for (const rb of runbooks) {
|
|
42415
42835
|
const when = new Date(rb.updatedAt).toISOString().slice(0, 10);
|
|
42416
42836
|
const repoList = rb.repos.join(", ");
|
|
42417
|
-
lines.push(` ${
|
|
42837
|
+
lines.push(` ${pc34.bold(rb.name.padEnd(24))} ${repoList.padEnd(40)} ${pc34.dim(when)}`);
|
|
42418
42838
|
}
|
|
42419
42839
|
return lines.join("\n");
|
|
42420
42840
|
}
|
|
@@ -42463,7 +42883,7 @@ function parsePortFlags(ports) {
|
|
|
42463
42883
|
}
|
|
42464
42884
|
function formatConflict(c) {
|
|
42465
42885
|
const occupantStr = c.occupant.type === "olam-world" ? `in use by world "${c.occupant.worldId}" (olam)` : `in use by PID ${c.occupant.pid ?? "unknown"} (non-olam process)`;
|
|
42466
|
-
return ` ${
|
|
42886
|
+
return ` ${pc34.red("\u2717")} ${c.repoName}.${c.serviceName}:${c.port} \u2014 ${occupantStr}`;
|
|
42467
42887
|
}
|
|
42468
42888
|
function registerRunbooks(program2) {
|
|
42469
42889
|
const runbooks = program2.command("runbooks").description("Manage runbooks in the global config");
|
|
@@ -42523,17 +42943,17 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
|
|
|
42523
42943
|
return;
|
|
42524
42944
|
}
|
|
42525
42945
|
console.log(
|
|
42526
|
-
|
|
42946
|
+
pc34.dim(
|
|
42527
42947
|
`olam runbooks apply: port validation passed for "${name}" (repos: ${rb.repos.join(", ")}).`
|
|
42528
42948
|
)
|
|
42529
42949
|
);
|
|
42530
42950
|
console.log(
|
|
42531
|
-
|
|
42951
|
+
pc34.dim(
|
|
42532
42952
|
`Hint: use "olam create --repos ${rb.repos.join(" ")}${opts.task ? ` --task "${opts.task}"` : ""}${opts.name ? ` --name ${opts.name}` : ""}" to create the world.`
|
|
42533
42953
|
)
|
|
42534
42954
|
);
|
|
42535
42955
|
console.log(
|
|
42536
|
-
|
|
42956
|
+
pc34.yellow('Phase D will wire --runbook directly. For now, use "olam create --repos ..." above.')
|
|
42537
42957
|
);
|
|
42538
42958
|
} catch (err) {
|
|
42539
42959
|
printError(asMessage2(err));
|
|
@@ -42551,7 +42971,7 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
|
|
|
42551
42971
|
return;
|
|
42552
42972
|
}
|
|
42553
42973
|
if (rows.length === 0) {
|
|
42554
|
-
console.log(
|
|
42974
|
+
console.log(pc34.dim(`runbook "${name}" declares no ports.`));
|
|
42555
42975
|
return;
|
|
42556
42976
|
}
|
|
42557
42977
|
for (const row of rows) {
|
|
@@ -42559,7 +42979,7 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
|
|
|
42559
42979
|
const conflict = conflicts.find((c) => c.port === row.port);
|
|
42560
42980
|
if (conflict) console.log(formatConflict(conflict));
|
|
42561
42981
|
} else {
|
|
42562
|
-
console.log(` ${
|
|
42982
|
+
console.log(` ${pc34.green("\u2713")} ${row.repoName}.${row.serviceName}:${row.port} \u2014 free`);
|
|
42563
42983
|
}
|
|
42564
42984
|
}
|
|
42565
42985
|
if (conflicts.length > 0) {
|
|
@@ -42569,7 +42989,7 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
|
|
|
42569
42989
|
);
|
|
42570
42990
|
process.exitCode = 1;
|
|
42571
42991
|
} else {
|
|
42572
|
-
console.log(
|
|
42992
|
+
console.log(pc34.green("\n\u2713 all ports free"));
|
|
42573
42993
|
}
|
|
42574
42994
|
} catch (err) {
|
|
42575
42995
|
printError(asMessage2(err));
|
|
@@ -42582,10 +43002,10 @@ ${conflicts.length} port conflict(s). Stop the conflicting processes or update p
|
|
|
42582
43002
|
init_skill_sources();
|
|
42583
43003
|
init_output();
|
|
42584
43004
|
import * as readline2 from "node:readline";
|
|
42585
|
-
import
|
|
43005
|
+
import pc35 from "picocolors";
|
|
42586
43006
|
|
|
42587
43007
|
// src/commands/flywheel/install-shims.ts
|
|
42588
|
-
import { copyFileSync as copyFileSync9, existsSync as existsSync91, mkdirSync as mkdirSync54, readFileSync as readFileSync78, writeFileSync as
|
|
43008
|
+
import { copyFileSync as copyFileSync9, existsSync as existsSync91, mkdirSync as mkdirSync54, readFileSync as readFileSync78, writeFileSync as writeFileSync46 } from "node:fs";
|
|
42589
43009
|
import { homedir as homedir52 } from "node:os";
|
|
42590
43010
|
import { dirname as dirname50, join as join92 } from "node:path";
|
|
42591
43011
|
|
|
@@ -42685,7 +43105,7 @@ function installOne(spec, targetDir, opts) {
|
|
|
42685
43105
|
if (!existsSync91(targetPath)) {
|
|
42686
43106
|
if (opts.dryRun !== true) {
|
|
42687
43107
|
mkdirSync54(dirname50(targetPath), { recursive: true });
|
|
42688
|
-
|
|
43108
|
+
writeFileSync46(targetPath, newContent, { mode: 493 });
|
|
42689
43109
|
}
|
|
42690
43110
|
return { basename: spec.basename, action: "written", targetPath };
|
|
42691
43111
|
}
|
|
@@ -42695,7 +43115,7 @@ function installOne(spec, targetDir, opts) {
|
|
|
42695
43115
|
}
|
|
42696
43116
|
if (isOlamGeneratedShim(existing)) {
|
|
42697
43117
|
if (opts.dryRun !== true) {
|
|
42698
|
-
|
|
43118
|
+
writeFileSync46(targetPath, newContent, { mode: 493 });
|
|
42699
43119
|
}
|
|
42700
43120
|
return { basename: spec.basename, action: "overwritten", targetPath };
|
|
42701
43121
|
}
|
|
@@ -42703,7 +43123,7 @@ function installOne(spec, targetDir, opts) {
|
|
|
42703
43123
|
const backupPath = `${targetPath}.shim-backup-${Math.floor(Date.now() / 1e3)}`;
|
|
42704
43124
|
if (opts.dryRun !== true) {
|
|
42705
43125
|
copyFileSync9(targetPath, backupPath);
|
|
42706
|
-
|
|
43126
|
+
writeFileSync46(targetPath, newContent, { mode: 493 });
|
|
42707
43127
|
}
|
|
42708
43128
|
return { basename: spec.basename, action: "overwritten", targetPath, backupPath };
|
|
42709
43129
|
}
|
|
@@ -42767,10 +43187,10 @@ function defaultTrustPrompt(gitUrl) {
|
|
|
42767
43187
|
return new Promise((resolve28) => {
|
|
42768
43188
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
42769
43189
|
process.stdout.write(
|
|
42770
|
-
`${
|
|
43190
|
+
`${pc35.yellow("Trust gate:")} register "${gitUrl}" as a skill source?
|
|
42771
43191
|
This grants the source permission to symlink artifacts into
|
|
42772
43192
|
~/.claude/ on every \`olam skills sync\`.
|
|
42773
|
-
Type ${
|
|
43193
|
+
Type ${pc35.bold("y")} to add + trust, anything else to cancel: `
|
|
42774
43194
|
);
|
|
42775
43195
|
rl.question("", (a) => {
|
|
42776
43196
|
rl.close();
|
|
@@ -42786,8 +43206,8 @@ function defaultSourcePrefixPrompt(input2) {
|
|
|
42786
43206
|
const scopeLabel = cfg.prefixScope !== void 0 && cfg.prefixScope.length > 0 ? ` (scope: ${cfg.prefixScope.join(",")})` : "";
|
|
42787
43207
|
process.stdout.write(
|
|
42788
43208
|
`
|
|
42789
|
-
${
|
|
42790
|
-
Adopt for this host? ${
|
|
43209
|
+
${pc35.cyan("Source-config:")} ${input2.sourceName} suggests prefix ${pc35.bold(prefixLabel)}${scopeLabel}.
|
|
43210
|
+
Adopt for this host? ${pc35.dim("[Y/n] ")}`
|
|
42791
43211
|
);
|
|
42792
43212
|
rl.question("", (a) => {
|
|
42793
43213
|
rl.close();
|
|
@@ -42799,7 +43219,7 @@ function defaultPostAddPrompt(input2) {
|
|
|
42799
43219
|
return new Promise((resolve28) => {
|
|
42800
43220
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
42801
43221
|
process.stdout.write(`
|
|
42802
|
-
${
|
|
43222
|
+
${pc35.bold("Sync now?")} ${pc35.dim("[Y/n] ")}`);
|
|
42803
43223
|
rl.question("", (syncAnswer) => {
|
|
42804
43224
|
const sync = !/^n(o)?$/i.test(syncAnswer.trim());
|
|
42805
43225
|
if (input2.hookAlreadyInstalled) {
|
|
@@ -42808,7 +43228,7 @@ ${pc34.bold("Sync now?")} ${pc34.dim("[Y/n] ")}`);
|
|
|
42808
43228
|
return;
|
|
42809
43229
|
}
|
|
42810
43230
|
process.stdout.write(
|
|
42811
|
-
`${
|
|
43231
|
+
`${pc35.bold("Install SessionStart hook so future sessions auto-sync?")} ${pc35.dim("[Y/n] ")}`
|
|
42812
43232
|
);
|
|
42813
43233
|
rl.question("", (hookAnswer) => {
|
|
42814
43234
|
rl.close();
|
|
@@ -42865,7 +43285,7 @@ function registerSkillsSource(program2) {
|
|
|
42865
43285
|
}
|
|
42866
43286
|
if (all.length === 0) {
|
|
42867
43287
|
console.log(
|
|
42868
|
-
|
|
43288
|
+
pc35.dim("0 skill source(s) registered. Add one with: olam skills source add --name <n> --git-url <url>")
|
|
42869
43289
|
);
|
|
42870
43290
|
return;
|
|
42871
43291
|
}
|
|
@@ -42886,19 +43306,19 @@ function registerSkillsSource(program2) {
|
|
|
42886
43306
|
for (let i = 0; i < all.length; i += 1) {
|
|
42887
43307
|
const s = all[i];
|
|
42888
43308
|
const when = new Date(s.addedAt).toISOString().slice(0, 10);
|
|
42889
|
-
const sha = s.lastPulledSha ? s.lastPulledSha.slice(0, 8) :
|
|
42890
|
-
const ord =
|
|
42891
|
-
const prefixCol = s.prefix ?
|
|
43309
|
+
const sha = s.lastPulledSha ? s.lastPulledSha.slice(0, 8) : pc35.dim("(unpulled)");
|
|
43310
|
+
const ord = pc35.dim(`[${i + 1}]`);
|
|
43311
|
+
const prefixCol = s.prefix ? pc35.cyan(s.prefix.padEnd(12)) : pc35.dim("\u2014".padEnd(12));
|
|
42892
43312
|
const scopeDisplay = s.prefixScope !== void 0 ? s.prefixScope.join(",") : DEFAULT_SCOPE_REPR;
|
|
42893
|
-
const scopeCol = showScopeCol ? ` ${
|
|
43313
|
+
const scopeCol = showScopeCol ? ` ${pc35.yellow(scopeDisplay.padEnd(12))}` : "";
|
|
42894
43314
|
let originCol = "";
|
|
42895
43315
|
if (showOriginCol) {
|
|
42896
43316
|
const eff = resolveEffectivePrefix(s, sourceConfigs[i]);
|
|
42897
|
-
const tag = eff.origin === "operator" ?
|
|
43317
|
+
const tag = eff.origin === "operator" ? pc35.dim("(operator)") : eff.origin === "source" ? pc35.dim("(source)") : "";
|
|
42898
43318
|
originCol = ` ${tag.padEnd(10)}`;
|
|
42899
43319
|
}
|
|
42900
43320
|
console.log(
|
|
42901
|
-
` ${ord} ${
|
|
43321
|
+
` ${ord} ${pc35.bold(s.id.padEnd(14))} ${s.name.padEnd(24)} ${s.branch.padEnd(12)} ${sha.padEnd(12)} ${prefixCol}${originCol}${scopeCol} ${pc35.dim(when)} ${pc35.dim(s.gitUrl)}`
|
|
42902
43322
|
);
|
|
42903
43323
|
}
|
|
42904
43324
|
});
|
|
@@ -43280,35 +43700,35 @@ function registerSkillsSource(program2) {
|
|
|
43280
43700
|
console.log(JSON.stringify(payload, null, 2));
|
|
43281
43701
|
return;
|
|
43282
43702
|
}
|
|
43283
|
-
console.log(
|
|
43284
|
-
console.log(` ${
|
|
43285
|
-
console.log(` ${
|
|
43286
|
-
console.log(` ${
|
|
43287
|
-
console.log(` ${
|
|
43288
|
-
console.log(` ${
|
|
43289
|
-
console.log(` ${
|
|
43290
|
-
console.log(` ${
|
|
43703
|
+
console.log(pc35.bold("\u25B8 registered"));
|
|
43704
|
+
console.log(` ${pc35.bold("id:")} ${entry.id}`);
|
|
43705
|
+
console.log(` ${pc35.bold("name:")} ${entry.name}`);
|
|
43706
|
+
console.log(` ${pc35.bold("gitUrl:")} ${entry.gitUrl}`);
|
|
43707
|
+
console.log(` ${pc35.bold("branch:")} ${entry.branch}`);
|
|
43708
|
+
console.log(` ${pc35.bold("addedAt:")} ${when}`);
|
|
43709
|
+
console.log(` ${pc35.bold("lastPulledSha:")} ${entry.lastPulledSha ?? pc35.dim("(unpulled)")}`);
|
|
43710
|
+
console.log(` ${pc35.bold("clonePath:")} ${clonePath}`);
|
|
43291
43711
|
let sourceConfig;
|
|
43292
43712
|
try {
|
|
43293
43713
|
sourceConfig = readSourceConfig(clonePath, entry.id);
|
|
43294
43714
|
} catch {
|
|
43295
43715
|
sourceConfig = void 0;
|
|
43296
43716
|
}
|
|
43297
|
-
console.log(
|
|
43717
|
+
console.log(pc35.bold("\u25B8 source-config (from clone)"));
|
|
43298
43718
|
if (sourceConfig === void 0) {
|
|
43299
|
-
console.log(` ${
|
|
43719
|
+
console.log(` ${pc35.dim("(no shared/source-config.yaml in clone)")}`);
|
|
43300
43720
|
} else {
|
|
43301
|
-
console.log(` ${
|
|
43302
|
-
console.log(` ${
|
|
43721
|
+
console.log(` ${pc35.bold("prefix:")} ${sourceConfig.prefix ?? pc35.dim("\u2014")}`);
|
|
43722
|
+
console.log(` ${pc35.bold("prefixScope:")} ${sourceConfig.prefixScope?.join(",") ?? pc35.dim("\u2014")}`);
|
|
43303
43723
|
}
|
|
43304
|
-
console.log(
|
|
43305
|
-
console.log(` ${
|
|
43306
|
-
console.log(` ${
|
|
43307
|
-
console.log(` ${
|
|
43724
|
+
console.log(pc35.bold("\u25B8 operator overrides"));
|
|
43725
|
+
console.log(` ${pc35.bold("prefix:")} ${entry.prefix ?? pc35.dim("\u2014")}`);
|
|
43726
|
+
console.log(` ${pc35.bold("prefixScope:")} ${entry.prefixScope?.join(",") ?? pc35.dim("\u2014")}`);
|
|
43727
|
+
console.log(` ${pc35.bold("lastSeen:")} ${entry.lastSeenSourcePrefix ? JSON.stringify(entry.lastSeenSourcePrefix) : pc35.dim("\u2014")}`);
|
|
43308
43728
|
const eff = resolveEffectivePrefix(entry, sourceConfig);
|
|
43309
|
-
console.log(
|
|
43310
|
-
console.log(` ${
|
|
43311
|
-
console.log(` ${
|
|
43729
|
+
console.log(pc35.bold(`\u25B8 effective ${pc35.dim(`(origin: ${eff.origin})`)}`));
|
|
43730
|
+
console.log(` ${pc35.bold("prefix:")} ${eff.prefix ?? pc35.dim("\u2014")}`);
|
|
43731
|
+
console.log(` ${pc35.bold("prefixScope:")} ${eff.prefixScope?.join(",") ?? pc35.dim("\u2014")}`);
|
|
43312
43732
|
});
|
|
43313
43733
|
source.command("set-prefix").description(
|
|
43314
43734
|
"Set the deploy prefix for a registered skill source (skills+agents deploy as <prefix>:<canonical-name>)"
|
|
@@ -43402,7 +43822,7 @@ import * as fs84 from "node:fs";
|
|
|
43402
43822
|
import * as os47 from "node:os";
|
|
43403
43823
|
import * as path85 from "node:path";
|
|
43404
43824
|
import * as readline3 from "node:readline";
|
|
43405
|
-
import
|
|
43825
|
+
import pc36 from "picocolors";
|
|
43406
43826
|
|
|
43407
43827
|
// src/lib/skills-apply-overlays.ts
|
|
43408
43828
|
init_markdown_merger();
|
|
@@ -43415,9 +43835,9 @@ import {
|
|
|
43415
43835
|
readdirSync as readdirSync27,
|
|
43416
43836
|
readFileSync as readFileSync79,
|
|
43417
43837
|
readlinkSync as readlinkSync4,
|
|
43418
|
-
rmSync as
|
|
43838
|
+
rmSync as rmSync10,
|
|
43419
43839
|
statSync as statSync27,
|
|
43420
|
-
writeFileSync as
|
|
43840
|
+
writeFileSync as writeFileSync47
|
|
43421
43841
|
} from "node:fs";
|
|
43422
43842
|
import { homedir as homedir53 } from "node:os";
|
|
43423
43843
|
import { basename as basename8, dirname as dirname51, isAbsolute as isAbsolute4, join as join93, relative as relative5, resolve as resolve22 } from "node:path";
|
|
@@ -43493,7 +43913,7 @@ function ensureRealDir(p) {
|
|
|
43493
43913
|
if (stat.isSymbolicLink()) {
|
|
43494
43914
|
const targetRaw = readlinkSync4(p);
|
|
43495
43915
|
const target = isAbsolute4(targetRaw) ? targetRaw : resolve22(dirname51(p), targetRaw);
|
|
43496
|
-
|
|
43916
|
+
rmSync10(p);
|
|
43497
43917
|
mkdirSync55(p, { recursive: true });
|
|
43498
43918
|
if (existsSync92(target) && statSync27(target).isDirectory()) {
|
|
43499
43919
|
for (const entry of readdirSync27(target)) {
|
|
@@ -43534,7 +43954,7 @@ function mergeOne(upstreamPath, overlayPath, destPath2, label, dryRun, messages)
|
|
|
43534
43954
|
}
|
|
43535
43955
|
if (!dryRun) {
|
|
43536
43956
|
mkdirSync55(dirname51(destPath2), { recursive: true });
|
|
43537
|
-
|
|
43957
|
+
writeFileSync47(destPath2, result.merged, "utf8");
|
|
43538
43958
|
}
|
|
43539
43959
|
messages.push(`MERGED ${label} \u2192 ${destPath2}${dryRun ? " (dry-run)" : ""}`);
|
|
43540
43960
|
return { ok: true };
|
|
@@ -43706,13 +44126,13 @@ function defaultSourcePrefixSyncPrompt(input2) {
|
|
|
43706
44126
|
let line;
|
|
43707
44127
|
if (input2.kind === "first-time") {
|
|
43708
44128
|
line = `
|
|
43709
|
-
${
|
|
43710
|
-
Adopt for this host? ${
|
|
44129
|
+
${pc36.cyan("Source-config:")} ${input2.sourceName} suggests prefix ${pc36.bold(newLabel)}.
|
|
44130
|
+
Adopt for this host? ${pc36.dim("[Y/n] ")}`;
|
|
43711
44131
|
} else {
|
|
43712
44132
|
const oldLabel = formatSourcePrefix(input2.priorConfig);
|
|
43713
44133
|
line = `
|
|
43714
|
-
${
|
|
43715
|
-
Accept change? ${
|
|
44134
|
+
${pc36.cyan("Source-config CHANGED:")} ${input2.sourceName} changed from ${pc36.bold(oldLabel)} to ${pc36.bold(newLabel)}.
|
|
44135
|
+
Accept change? ${pc36.dim("[Y/n] ")}`;
|
|
43716
44136
|
}
|
|
43717
44137
|
process.stdout.write(line);
|
|
43718
44138
|
rl.question("", (a) => {
|
|
@@ -43761,9 +44181,9 @@ async function resolveAtlasUserWithPicker(cliOverride, opts) {
|
|
|
43761
44181
|
const OTHER_OPTION = "[Other (type a new name)]";
|
|
43762
44182
|
const choices = [...members, OTHER_OPTION];
|
|
43763
44183
|
process.stdout.write("\n");
|
|
43764
|
-
process.stdout.write(
|
|
44184
|
+
process.stdout.write(pc36.bold("First sync detected \u2014 pick your member name:\n"));
|
|
43765
44185
|
choices.forEach((choice, i) => {
|
|
43766
|
-
process.stdout.write(` ${
|
|
44186
|
+
process.stdout.write(` ${pc36.dim(String(i + 1) + ".")} ${choice}
|
|
43767
44187
|
`);
|
|
43768
44188
|
});
|
|
43769
44189
|
process.stdout.write("\n");
|
|
@@ -43798,7 +44218,7 @@ async function resolveAtlasUserWithPicker(cliOverride, opts) {
|
|
|
43798
44218
|
const claudeDirPath = opts?._testClaudeDir ?? (process.env["OLAM_CLAUDE_DIR"] ?? path85.join(os47.homedir(), ".claude"));
|
|
43799
44219
|
fs84.mkdirSync(claudeDirPath, { recursive: true });
|
|
43800
44220
|
fs84.writeFileSync(path85.join(claudeDirPath, ".atlas-user"), picked + "\n", "utf8");
|
|
43801
|
-
process.stdout.write(
|
|
44221
|
+
process.stdout.write(pc36.green(`\u2713 atlas-user set to "${picked}" (written to ${path85.join(claudeDirPath, ".atlas-user")})
|
|
43802
44222
|
`));
|
|
43803
44223
|
return picked;
|
|
43804
44224
|
}
|
|
@@ -43841,21 +44261,21 @@ function printSyncSummary(summary2, dryRun) {
|
|
|
43841
44261
|
if (summary2.deploy) {
|
|
43842
44262
|
console.log(` symlinks made: ${summary2.deploy.linked}`);
|
|
43843
44263
|
if (summary2.deploy.shadowBackups.length > 0) {
|
|
43844
|
-
console.log(` ${
|
|
43845
|
-
for (const p of summary2.deploy.shadowBackups) console.log(` ${
|
|
44264
|
+
console.log(` ${pc36.yellow("shadow backups:")} ${summary2.deploy.shadowBackups.length}`);
|
|
44265
|
+
for (const p of summary2.deploy.shadowBackups) console.log(` ${pc36.dim(p)}`);
|
|
43846
44266
|
}
|
|
43847
44267
|
}
|
|
43848
44268
|
if (summary2.collisions.length > 0) {
|
|
43849
|
-
console.log(` ${
|
|
44269
|
+
console.log(` ${pc36.yellow("[conflict] name collisions:")} ${summary2.collisions.length}`);
|
|
43850
44270
|
for (const c of summary2.collisions) {
|
|
43851
44271
|
const winnerIdShort = c.winnerSourceId.slice(0, 8);
|
|
43852
44272
|
console.log(
|
|
43853
|
-
` ${
|
|
44273
|
+
` ${pc36.bold(`${c.bucket}/${c.basename}`)}: ${c.loserSourceIds.length + 1} sources export \u2014 using source [${winnerIdShort}]`
|
|
43854
44274
|
);
|
|
43855
|
-
console.log(` ${
|
|
44275
|
+
console.log(` ${pc36.dim("(winner)")} ${c.winnerSourcePath}`);
|
|
43856
44276
|
for (let i = 0; i < c.loserSourcePaths.length; i += 1) {
|
|
43857
44277
|
const loserIdShort = c.loserSourceIds[i].slice(0, 8);
|
|
43858
|
-
console.log(` ${
|
|
44278
|
+
console.log(` ${pc36.dim(`(skipped, source ${loserIdShort})`)} ${c.loserSourcePaths[i]}`);
|
|
43859
44279
|
}
|
|
43860
44280
|
}
|
|
43861
44281
|
}
|
|
@@ -43863,33 +44283,33 @@ function printSyncSummary(summary2, dryRun) {
|
|
|
43863
44283
|
console.log(` hooks added: ${summary2.merge.hooksAdded}`);
|
|
43864
44284
|
console.log(` permissions: ${summary2.merge.permissionsCount}`);
|
|
43865
44285
|
if (summary2.merge.backupPath) {
|
|
43866
|
-
console.log(` settings backup: ${
|
|
44286
|
+
console.log(` settings backup: ${pc36.dim(summary2.merge.backupPath)}`);
|
|
43867
44287
|
}
|
|
43868
44288
|
if (summary2.merge.dualWriteDeduped > 0) {
|
|
43869
|
-
console.log(` ${
|
|
44289
|
+
console.log(` ${pc36.dim(`dual-write deduped: ${summary2.merge.dualWriteDeduped} (atlas-shipped hook redundant with olam-meta block)`)}`);
|
|
43870
44290
|
for (const cmd of summary2.merge.dualWriteDroppedCommands) {
|
|
43871
|
-
console.log(` ${
|
|
44291
|
+
console.log(` ${pc36.dim("(dropped)")} ${cmd.slice(0, 120)}${cmd.length > 120 ? "\u2026" : ""}`);
|
|
43872
44292
|
}
|
|
43873
44293
|
}
|
|
43874
44294
|
}
|
|
43875
44295
|
if (summary2.metaHooks) {
|
|
43876
44296
|
const mh = summary2.metaHooks;
|
|
43877
|
-
const memLabel = mh.servicesStatus.memory ?
|
|
43878
|
-
console.log(` meta-hooks: mode=${mh.mode} \xB7 memory=${memLabel}${mh.servicesStatus.memoryDetail ?
|
|
44297
|
+
const memLabel = mh.servicesStatus.memory ? pc36.green("up") : pc36.dim("down");
|
|
44298
|
+
console.log(` meta-hooks: mode=${mh.mode} \xB7 memory=${memLabel}${mh.servicesStatus.memoryDetail ? pc36.dim(` (${mh.servicesStatus.memoryDetail})`) : ""}`);
|
|
43879
44299
|
if (mh.autoMigrated && mh.autoMigrated.strippedCount > 0) {
|
|
43880
44300
|
console.log(
|
|
43881
|
-
` ${
|
|
44301
|
+
` ${pc36.cyan("~ auto-migrated:")} stripped ${mh.autoMigrated.strippedCount} atlas-toolbox-shipped agentmemory hook entry(ies); replaced by olam-injected blocks`
|
|
43882
44302
|
);
|
|
43883
44303
|
}
|
|
43884
44304
|
if (mh.blocksAdded.length > 0) {
|
|
43885
|
-
console.log(` ${
|
|
44305
|
+
console.log(` ${pc36.green("+ injected:")} ${mh.blocksAdded.join(", ")}`);
|
|
43886
44306
|
}
|
|
43887
44307
|
if (mh.blocksRemoved.length > 0) {
|
|
43888
|
-
console.log(` ${
|
|
44308
|
+
console.log(` ${pc36.yellow("- stripped:")} ${mh.blocksRemoved.join(", ")}`);
|
|
43889
44309
|
}
|
|
43890
44310
|
if (mh.snapshotError) {
|
|
43891
|
-
console.log(` ${
|
|
43892
|
-
console.log(` ${
|
|
44311
|
+
console.log(` ${pc36.red("! snapshot FAILED:")} ${mh.snapshotError}`);
|
|
44312
|
+
console.log(` ${pc36.red(" (migrate-hooks-back will not be able to undo this sync)")}`);
|
|
43893
44313
|
}
|
|
43894
44314
|
}
|
|
43895
44315
|
if (summary2.prefixRewrites.length > 0) {
|
|
@@ -43901,14 +44321,14 @@ function printSyncSummary(summary2, dryRun) {
|
|
|
43901
44321
|
const winnerName = allSources.find((s) => s.sourceId === col.winnerSourceId)?.name ?? col.winnerSourceId.slice(0, 8);
|
|
43902
44322
|
const loserNames = col.loserSourceIds.map((id) => allSources.find((s) => s.sourceId === id)?.name ?? id.slice(0, 8)).join(", ");
|
|
43903
44323
|
console.log(
|
|
43904
|
-
` ${
|
|
44324
|
+
` ${pc36.yellow(`\u26A0 prefix collision: '${col.prefix}' used by ${winnerName} (winner) + ${loserNames}; first-registered wins`)}`
|
|
43905
44325
|
);
|
|
43906
44326
|
}
|
|
43907
44327
|
}
|
|
43908
44328
|
console.log();
|
|
43909
44329
|
for (const s of summary2.perSource) {
|
|
43910
44330
|
const sub = s.fromSubscriptionsFile ? "(subscribed)" : "(all categories)";
|
|
43911
|
-
console.log(` ${
|
|
44331
|
+
console.log(` ${pc36.bold(s.name.padEnd(24))} ${s.artifactCount} artifacts \xB7 ${s.categories.join(", ") || "(none)"} ${pc36.dim(sub)}`);
|
|
43912
44332
|
}
|
|
43913
44333
|
}
|
|
43914
44334
|
function registerSkills(program2) {
|
|
@@ -43986,7 +44406,7 @@ function registerSkills(program2) {
|
|
|
43986
44406
|
return;
|
|
43987
44407
|
}
|
|
43988
44408
|
if (entries.length === 0) {
|
|
43989
|
-
console.log(
|
|
44409
|
+
console.log(pc36.dim('0 deployed artifact(s). Run "olam skills sync" first.'));
|
|
43990
44410
|
return;
|
|
43991
44411
|
}
|
|
43992
44412
|
const byBucket = /* @__PURE__ */ new Map();
|
|
@@ -43997,10 +44417,10 @@ function registerSkills(program2) {
|
|
|
43997
44417
|
}
|
|
43998
44418
|
printHeader(`${entries.length} deployed artifact(s)`);
|
|
43999
44419
|
for (const [bucket, list] of byBucket.entries()) {
|
|
44000
|
-
console.log(` ${
|
|
44420
|
+
console.log(` ${pc36.bold(bucket)} (${list.length})`);
|
|
44001
44421
|
for (const e of list) {
|
|
44002
|
-
const src = e.sourceId ? `[${e.sourceId}]` :
|
|
44003
|
-
console.log(` ${e.name.padEnd(40)} ${
|
|
44422
|
+
const src = e.sourceId ? `[${e.sourceId}]` : pc36.yellow("[unknown]");
|
|
44423
|
+
console.log(` ${e.name.padEnd(40)} ${pc36.dim(src)} \u2192 ${pc36.dim(e.target)}`);
|
|
44004
44424
|
}
|
|
44005
44425
|
}
|
|
44006
44426
|
});
|
|
@@ -44013,10 +44433,10 @@ function registerSkills(program2) {
|
|
|
44013
44433
|
return;
|
|
44014
44434
|
}
|
|
44015
44435
|
for (const e of matches2) {
|
|
44016
|
-
console.log(`${
|
|
44017
|
-
console.log(`${
|
|
44018
|
-
console.log(`${
|
|
44019
|
-
console.log(`${
|
|
44436
|
+
console.log(`${pc36.bold("bucket:")} ${e.bucket}`);
|
|
44437
|
+
console.log(`${pc36.bold("name:")} ${e.name}`);
|
|
44438
|
+
console.log(`${pc36.bold("target:")} ${e.target}`);
|
|
44439
|
+
console.log(`${pc36.bold("source:")} ${e.sourceId ?? pc36.dim("(unknown \u2014 not from a registered olam source)")}`);
|
|
44020
44440
|
console.log();
|
|
44021
44441
|
}
|
|
44022
44442
|
});
|
|
@@ -44111,7 +44531,7 @@ function registerSkillsHook(program2) {
|
|
|
44111
44531
|
// src/commands/skills-onboard.ts
|
|
44112
44532
|
init_skill_sources();
|
|
44113
44533
|
init_output();
|
|
44114
|
-
import
|
|
44534
|
+
import pc37 from "picocolors";
|
|
44115
44535
|
function asMessage5(err) {
|
|
44116
44536
|
return err instanceof Error ? err.message : String(err);
|
|
44117
44537
|
}
|
|
@@ -44264,7 +44684,7 @@ function registerSkillsOnboard(program2) {
|
|
|
44264
44684
|
}
|
|
44265
44685
|
printInfo("sync", `${syncedArtifacts} artifact(s) deployed`);
|
|
44266
44686
|
console.log();
|
|
44267
|
-
console.log(
|
|
44687
|
+
console.log(pc37.dim(" Open a new Claude Code session to pick up the deployed skills."));
|
|
44268
44688
|
});
|
|
44269
44689
|
}
|
|
44270
44690
|
|
|
@@ -44619,7 +45039,7 @@ init_atlas_hook_strip();
|
|
|
44619
45039
|
init_output();
|
|
44620
45040
|
import * as fs88 from "node:fs";
|
|
44621
45041
|
import * as path88 from "node:path";
|
|
44622
|
-
import
|
|
45042
|
+
import pc38 from "picocolors";
|
|
44623
45043
|
var MIGRATE_HOOKS_COMMAND = "migrate-hooks";
|
|
44624
45044
|
function settingsHasOlamMetaSentinel(settings) {
|
|
44625
45045
|
for (const stage of ["PreToolUse", "PostToolUse"]) {
|
|
@@ -44656,12 +45076,12 @@ function printSummary(candidates2, opts) {
|
|
|
44656
45076
|
return;
|
|
44657
45077
|
}
|
|
44658
45078
|
const verb = opts.dryRun ? "would strip" : "stripped";
|
|
44659
|
-
console.log(
|
|
45079
|
+
console.log(pc38.bold(`${verb} ${candidates2.length} atlas-toolbox-shipped agentmemory hook entry(ies):`));
|
|
44660
45080
|
for (const c of candidates2) {
|
|
44661
45081
|
const matcher = c.matcher ?? "*";
|
|
44662
45082
|
const cmdPreview = c.command.length > 120 ? `${c.command.slice(0, 117)}...` : c.command;
|
|
44663
|
-
console.log(` ${
|
|
44664
|
-
console.log(` ${
|
|
45083
|
+
console.log(` ${pc38.dim(`[${c.stage}]`)} matcher=${pc38.cyan(matcher)} pattern=${pc38.yellow(c.matchedPattern)}`);
|
|
45084
|
+
console.log(` ${pc38.dim(cmdPreview)}`);
|
|
44665
45085
|
}
|
|
44666
45086
|
if (opts.snapshotPath) {
|
|
44667
45087
|
console.log();
|
|
@@ -44784,7 +45204,7 @@ function registerSkillsMigrateHooksBack(program2) {
|
|
|
44784
45204
|
init_skill_sources();
|
|
44785
45205
|
init_output();
|
|
44786
45206
|
import * as fs89 from "node:fs";
|
|
44787
|
-
import
|
|
45207
|
+
import pc39 from "picocolors";
|
|
44788
45208
|
function asMessage10(err) {
|
|
44789
45209
|
return err instanceof Error ? err.message : String(err);
|
|
44790
45210
|
}
|
|
@@ -44808,7 +45228,7 @@ function printBackupRows(backups) {
|
|
|
44808
45228
|
for (const b of backups) {
|
|
44809
45229
|
const when = new Date(b.epochSeconds * 1e3).toISOString().slice(0, 10);
|
|
44810
45230
|
console.log(
|
|
44811
|
-
` ${
|
|
45231
|
+
` ${pc39.dim(formatAge3(b.ageMs).padStart(6))} ${formatSize(b.sizeBytes).padStart(7)} ${pc39.dim(when)} ${b.bucket}/${pc39.bold(b.basename)}`
|
|
44812
45232
|
);
|
|
44813
45233
|
}
|
|
44814
45234
|
}
|
|
@@ -44818,11 +45238,11 @@ function registerSkillsShadowBackups(program2) {
|
|
|
44818
45238
|
sb.command("list").description("List all shadow-backup files under ~/.claude/").action(() => {
|
|
44819
45239
|
const all = listShadowBackups();
|
|
44820
45240
|
if (all.length === 0) {
|
|
44821
|
-
console.log(
|
|
45241
|
+
console.log(pc39.dim("No shadow-backup files under ~/.claude/."));
|
|
44822
45242
|
return;
|
|
44823
45243
|
}
|
|
44824
45244
|
printHeader(`${all.length} shadow backup(s)`);
|
|
44825
|
-
console.log(
|
|
45245
|
+
console.log(pc39.dim(" age size created bucket/basename"));
|
|
44826
45246
|
printBackupRows(all);
|
|
44827
45247
|
});
|
|
44828
45248
|
sb.command("prune").description("Delete shadow-backup files older than a duration (e.g. 30d) OR all of them with --all --force").option("--older-than <duration>", "Delete backups older than this duration (e.g. 30d, 7d, 24h, 2w)", "30d").option("--all", "Delete every shadow-backup file (requires --force)").option("--force", "Confirm deletion when --all is used").option("--dry-run", "Show what would be deleted without deleting").action((opts) => {
|
|
@@ -44849,13 +45269,13 @@ function registerSkillsShadowBackups(program2) {
|
|
|
44849
45269
|
const result = pruneShadowBackups(pruneOpts);
|
|
44850
45270
|
const action = opts.dryRun ? "would delete" : "deleted";
|
|
44851
45271
|
if (result.deleted.length === 0) {
|
|
44852
|
-
console.log(
|
|
45272
|
+
console.log(pc39.dim(`No shadow-backups match \u2014 ${result.skipped.length} kept`));
|
|
44853
45273
|
return;
|
|
44854
45274
|
}
|
|
44855
45275
|
printHeader(`${action} ${result.deleted.length} shadow backup(s) (${result.skipped.length} kept)`);
|
|
44856
45276
|
printBackupRows(result.deleted);
|
|
44857
45277
|
if (opts.dryRun) {
|
|
44858
|
-
console.log(
|
|
45278
|
+
console.log(pc39.dim("\n(dry-run \u2014 re-run without --dry-run to delete)"));
|
|
44859
45279
|
} else {
|
|
44860
45280
|
printSuccess(`pruned ${result.deleted.length} backup(s)`);
|
|
44861
45281
|
}
|
|
@@ -44884,7 +45304,7 @@ function registerSkillsShadowBackups(program2) {
|
|
|
44884
45304
|
init_skill_sources();
|
|
44885
45305
|
init_output();
|
|
44886
45306
|
import * as readline4 from "node:readline";
|
|
44887
|
-
import
|
|
45307
|
+
import pc40 from "picocolors";
|
|
44888
45308
|
function asMessage11(err) {
|
|
44889
45309
|
return err instanceof Error ? err.message : String(err);
|
|
44890
45310
|
}
|
|
@@ -44907,16 +45327,16 @@ async function confirmRepair(check) {
|
|
|
44907
45327
|
}
|
|
44908
45328
|
function printCheck(check) {
|
|
44909
45329
|
if (check.healthy) {
|
|
44910
|
-
console.log(` ${
|
|
45330
|
+
console.log(` ${pc40.green("\u2713")} ${pc40.bold(check.name.padEnd(22))} ${pc40.dim(check.description)}`);
|
|
44911
45331
|
if (check.details && check.details.length > 0) {
|
|
44912
|
-
for (const d of check.details) console.log(` ${
|
|
45332
|
+
for (const d of check.details) console.log(` ${pc40.dim(d)}`);
|
|
44913
45333
|
}
|
|
44914
45334
|
} else {
|
|
44915
|
-
console.log(` ${
|
|
44916
|
-
console.log(` ${
|
|
45335
|
+
console.log(` ${pc40.red("\u2717")} ${pc40.bold(check.name.padEnd(22))} ${pc40.yellow(check.issue ?? "unhealthy")}`);
|
|
45336
|
+
console.log(` ${pc40.dim(check.description)}`);
|
|
44917
45337
|
if (check.details) {
|
|
44918
|
-
for (const d of check.details.slice(0, 10)) console.log(` ${
|
|
44919
|
-
if (check.details.length > 10) console.log(` ${
|
|
45338
|
+
for (const d of check.details.slice(0, 10)) console.log(` ${pc40.dim("\xB7 " + d)}`);
|
|
45339
|
+
if (check.details.length > 10) console.log(` ${pc40.dim(`\u2026 and ${check.details.length - 10} more`)}`);
|
|
44920
45340
|
}
|
|
44921
45341
|
}
|
|
44922
45342
|
}
|
|
@@ -44947,7 +45367,7 @@ function registerSkillsDoctor(program2) {
|
|
|
44947
45367
|
console.log();
|
|
44948
45368
|
printWarning(`${unhealthy.length} of ${checks.length} check(s) report issues`);
|
|
44949
45369
|
if (opts.checkOnly) {
|
|
44950
|
-
console.log(
|
|
45370
|
+
console.log(pc40.dim("(--check-only \u2014 exiting without repair)"));
|
|
44951
45371
|
process.exitCode = 1;
|
|
44952
45372
|
return;
|
|
44953
45373
|
}
|
|
@@ -44955,19 +45375,19 @@ function registerSkillsDoctor(program2) {
|
|
|
44955
45375
|
let skipped = 0;
|
|
44956
45376
|
for (const check of unhealthy) {
|
|
44957
45377
|
if (!check.repair) {
|
|
44958
|
-
console.log(
|
|
45378
|
+
console.log(pc40.dim(` (no auto-repair for ${check.name} \u2014 operator-attention required)`));
|
|
44959
45379
|
skipped += 1;
|
|
44960
45380
|
continue;
|
|
44961
45381
|
}
|
|
44962
45382
|
const shouldRepair = opts.autoFix ? true : await confirmRepair(check);
|
|
44963
45383
|
if (!shouldRepair) {
|
|
44964
|
-
console.log(
|
|
45384
|
+
console.log(pc40.dim(` skipped: ${check.name}`));
|
|
44965
45385
|
skipped += 1;
|
|
44966
45386
|
continue;
|
|
44967
45387
|
}
|
|
44968
45388
|
try {
|
|
44969
45389
|
await check.repair();
|
|
44970
|
-
console.log(
|
|
45390
|
+
console.log(pc40.green(` repaired: ${check.name}`));
|
|
44971
45391
|
repaired += 1;
|
|
44972
45392
|
} catch (err) {
|
|
44973
45393
|
printError(` repair failed for ${check.name}: ${asMessage11(err)}`);
|
|
@@ -45898,7 +46318,7 @@ function registerMcpAdd(cmd) {
|
|
|
45898
46318
|
|
|
45899
46319
|
// src/commands/mcp/list.ts
|
|
45900
46320
|
init_output();
|
|
45901
|
-
import
|
|
46321
|
+
import pc41 from "picocolors";
|
|
45902
46322
|
function registerMcpList(cmd) {
|
|
45903
46323
|
cmd.command("list").description("List all registered MCP credentials").action(async () => {
|
|
45904
46324
|
const client = getMcpAuthClient();
|
|
@@ -45913,8 +46333,8 @@ function registerMcpList(cmd) {
|
|
|
45913
46333
|
}
|
|
45914
46334
|
const mcps = data.mcps ?? [];
|
|
45915
46335
|
if (mcps.length === 0) {
|
|
45916
|
-
console.log(
|
|
45917
|
-
console.log(
|
|
46336
|
+
console.log(pc41.dim("No MCP credentials registered."));
|
|
46337
|
+
console.log(pc41.dim("Add one with: olam mcp add <service>"));
|
|
45918
46338
|
return;
|
|
45919
46339
|
}
|
|
45920
46340
|
const [c0, c1, c2, c3] = [16, 20, 10, 24];
|
|
@@ -45925,12 +46345,12 @@ function registerMcpList(cmd) {
|
|
|
45925
46345
|
"ENV VAR".padEnd(c3),
|
|
45926
46346
|
"STATUS"
|
|
45927
46347
|
].join(" ");
|
|
45928
|
-
console.log(
|
|
45929
|
-
console.log(
|
|
46348
|
+
console.log(pc41.dim(header));
|
|
46349
|
+
console.log(pc41.dim("\u2500".repeat(header.length)));
|
|
45930
46350
|
for (const m of mcps) {
|
|
45931
|
-
const status2 = !m.validated ?
|
|
46351
|
+
const status2 = !m.validated ? pc41.yellow("unvalidated") : m.expired ? pc41.red("expired") : pc41.green("active");
|
|
45932
46352
|
const row = [
|
|
45933
|
-
|
|
46353
|
+
pc41.cyan(m.service.padEnd(c0)),
|
|
45934
46354
|
m.label.padEnd(c1).slice(0, c1),
|
|
45935
46355
|
m.type.padEnd(c2),
|
|
45936
46356
|
(m.envName ?? "\u2014").padEnd(c3).slice(0, c3),
|
|
@@ -45958,13 +46378,13 @@ function registerMcpRemove(cmd) {
|
|
|
45958
46378
|
|
|
45959
46379
|
// src/commands/mcp/status.ts
|
|
45960
46380
|
init_output();
|
|
45961
|
-
import
|
|
46381
|
+
import pc42 from "picocolors";
|
|
45962
46382
|
function formatExpiry(expiresAt) {
|
|
45963
46383
|
if (!expiresAt) return "\u2014";
|
|
45964
46384
|
const ms = expiresAt - Date.now();
|
|
45965
|
-
if (ms <= 0) return
|
|
46385
|
+
if (ms <= 0) return pc42.red("expired");
|
|
45966
46386
|
const hours = ms / (1e3 * 60 * 60);
|
|
45967
|
-
if (hours < 1) return
|
|
46387
|
+
if (hours < 1) return pc42.yellow(`${Math.ceil(ms / 6e4)}m`);
|
|
45968
46388
|
return `${hours.toFixed(1)}h`;
|
|
45969
46389
|
}
|
|
45970
46390
|
function registerMcpStatus(cmd) {
|
|
@@ -45981,14 +46401,14 @@ function registerMcpStatus(cmd) {
|
|
|
45981
46401
|
const mcps = data.mcps ?? [];
|
|
45982
46402
|
printHeader(`MCP Credentials (${mcps.length})`);
|
|
45983
46403
|
if (mcps.length === 0) {
|
|
45984
|
-
console.log(
|
|
46404
|
+
console.log(pc42.dim("No credentials registered."));
|
|
45985
46405
|
return;
|
|
45986
46406
|
}
|
|
45987
46407
|
for (const m of mcps) {
|
|
45988
|
-
const stateColor = !m.validated ?
|
|
46408
|
+
const stateColor = !m.validated ? pc42.yellow : m.expired ? pc42.red : pc42.green;
|
|
45989
46409
|
const stateLabel = !m.validated ? "unvalidated" : m.expired ? "expired" : "active";
|
|
45990
46410
|
console.log(`
|
|
45991
|
-
${
|
|
46411
|
+
${pc42.cyan(m.service)} ${stateColor(`[${stateLabel}]`)}`);
|
|
45992
46412
|
console.log(` label: ${m.label}`);
|
|
45993
46413
|
console.log(` type: ${m.type}`);
|
|
45994
46414
|
if (m.envName) console.log(` env var: ${m.envName}`);
|
|
@@ -46003,7 +46423,7 @@ function registerMcpStatus(cmd) {
|
|
|
46003
46423
|
// src/commands/mcp/import.ts
|
|
46004
46424
|
init_output();
|
|
46005
46425
|
import * as readline6 from "node:readline";
|
|
46006
|
-
import
|
|
46426
|
+
import pc43 from "picocolors";
|
|
46007
46427
|
|
|
46008
46428
|
// src/commands/mcp/import-discovery.ts
|
|
46009
46429
|
import * as fs92 from "node:fs";
|
|
@@ -46173,13 +46593,13 @@ async function validateMcpEntry(entry) {
|
|
|
46173
46593
|
// src/commands/mcp/import.ts
|
|
46174
46594
|
async function multiSelectPicker(entries) {
|
|
46175
46595
|
if (entries.length === 0) return [];
|
|
46176
|
-
console.log("\n" +
|
|
46596
|
+
console.log("\n" + pc43.bold("Discovered MCP servers:"));
|
|
46177
46597
|
entries.forEach((e, i) => {
|
|
46178
46598
|
console.log(
|
|
46179
|
-
` ${
|
|
46599
|
+
` ${pc43.dim(`[${i + 1}]`)} ${pc43.cyan(e.name.padEnd(20))} ${pc43.dim(e.sourceLabel)}`
|
|
46180
46600
|
);
|
|
46181
46601
|
});
|
|
46182
|
-
console.log("\n" +
|
|
46602
|
+
console.log("\n" + pc43.dim('Enter numbers to import (e.g. 1,2,3 or "all" or Enter to skip):'));
|
|
46183
46603
|
const answer = await new Promise((resolve28) => {
|
|
46184
46604
|
const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
|
|
46185
46605
|
rl.question("> ", (ans) => {
|
|
@@ -46206,7 +46626,7 @@ function registerMcpImport(cmd) {
|
|
|
46206
46626
|
const repoPaths = opts.repoPaths ? opts.repoPaths.split(",").map((s) => s.trim()) : void 0;
|
|
46207
46627
|
const { entries, sources, durationMs } = await discoverMcpSources(repoPaths);
|
|
46208
46628
|
if (entries.length === 0) {
|
|
46209
|
-
console.log(
|
|
46629
|
+
console.log(pc43.dim("No MCP servers found in any source path."));
|
|
46210
46630
|
return;
|
|
46211
46631
|
}
|
|
46212
46632
|
printInfo("Sources", sources.length > 0 ? sources.join(", ") : "none");
|
|
@@ -46219,15 +46639,15 @@ function registerMcpImport(cmd) {
|
|
|
46219
46639
|
candidates2 = filtered;
|
|
46220
46640
|
}
|
|
46221
46641
|
if (skippedCount > 0) {
|
|
46222
|
-
console.log(
|
|
46642
|
+
console.log(pc43.dim(`skipped: ${skippedCount} already registered`));
|
|
46223
46643
|
}
|
|
46224
46644
|
if (candidates2.length === 0) {
|
|
46225
|
-
console.log(
|
|
46645
|
+
console.log(pc43.dim("Nothing new to import. Use --reimport to force."));
|
|
46226
46646
|
return;
|
|
46227
46647
|
}
|
|
46228
46648
|
const selected = await multiSelectPicker(candidates2);
|
|
46229
46649
|
if (selected.length === 0) {
|
|
46230
|
-
console.log(
|
|
46650
|
+
console.log(pc43.dim("No servers selected."));
|
|
46231
46651
|
return;
|
|
46232
46652
|
}
|
|
46233
46653
|
console.log(`
|
|
@@ -46238,16 +46658,16 @@ Importing ${selected.length} server(s)\u2026`);
|
|
|
46238
46658
|
let validated = false;
|
|
46239
46659
|
let validationReason = "skipped";
|
|
46240
46660
|
if (opts.validate !== false) {
|
|
46241
|
-
process.stdout.write(` ${
|
|
46661
|
+
process.stdout.write(` ${pc43.dim("\u2192")} ${entry.name} validating\u2026 `);
|
|
46242
46662
|
const vr = await validateMcpEntry(entry);
|
|
46243
46663
|
validated = vr.validated;
|
|
46244
46664
|
validationReason = vr.reason;
|
|
46245
46665
|
process.stdout.write(
|
|
46246
|
-
validated ?
|
|
46666
|
+
validated ? pc43.green("ok\n") : pc43.yellow(`unvalidated (${vr.reason})
|
|
46247
46667
|
`)
|
|
46248
46668
|
);
|
|
46249
46669
|
} else {
|
|
46250
|
-
console.log(` ${
|
|
46670
|
+
console.log(` ${pc43.dim("\u2192")} ${entry.name} ${pc43.dim("(validation skipped)")}`);
|
|
46251
46671
|
}
|
|
46252
46672
|
if (validated) validatedCount++;
|
|
46253
46673
|
const result = await client.staticAdd({
|
|
@@ -46262,21 +46682,21 @@ Importing ${selected.length} server(s)\u2026`);
|
|
|
46262
46682
|
}
|
|
46263
46683
|
}
|
|
46264
46684
|
console.log("");
|
|
46265
|
-
console.log(
|
|
46685
|
+
console.log(pc43.green(`\u2713 Imported ${importedCount}/${selected.length}`));
|
|
46266
46686
|
if (validatedCount > 0) {
|
|
46267
|
-
console.log(
|
|
46687
|
+
console.log(pc43.dim(` ${validatedCount} validated, ${importedCount - validatedCount} unvalidated`));
|
|
46268
46688
|
}
|
|
46269
46689
|
});
|
|
46270
46690
|
}
|
|
46271
46691
|
|
|
46272
46692
|
// src/commands/mcp/revoke.ts
|
|
46273
46693
|
init_output();
|
|
46274
|
-
import
|
|
46694
|
+
import pc44 from "picocolors";
|
|
46275
46695
|
function registerMcpRevoke(cmd) {
|
|
46276
46696
|
cmd.command("revoke <user> <world> <service>").description("Revoke a user's MCP service entitlement (multi-tenant mode only)").action(async (user, world, service) => {
|
|
46277
46697
|
const multiTenant = (process.env["OLAM_MCP_MULTI_TENANT"] ?? "").toLowerCase() === "true";
|
|
46278
46698
|
if (!multiTenant) {
|
|
46279
|
-
console.warn(
|
|
46699
|
+
console.warn(pc44.yellow("\u26A0 revocation only meaningful in multi_tenant mode \u2014 no-op"));
|
|
46280
46700
|
return;
|
|
46281
46701
|
}
|
|
46282
46702
|
const baseUrl = process.env["OLAM_MCP_AUTH_SERVICE_URL"] ?? "http://127.0.0.1:9998";
|
|
@@ -46305,8 +46725,8 @@ function registerMcpRevoke(cmd) {
|
|
|
46305
46725
|
process.exitCode = 1;
|
|
46306
46726
|
return;
|
|
46307
46727
|
}
|
|
46308
|
-
console.log(
|
|
46309
|
-
console.log(
|
|
46728
|
+
console.log(pc44.green(`\u2713 Revoked: ${user} / ${world} / ${service}`));
|
|
46729
|
+
console.log(pc44.dim(" Next fetch-creds call returns 403; token cleared on next merge."));
|
|
46310
46730
|
});
|
|
46311
46731
|
}
|
|
46312
46732
|
|
|
@@ -46849,7 +47269,7 @@ function registerMemoryUninstall(cmd) {
|
|
|
46849
47269
|
// src/commands/memory/mode.ts
|
|
46850
47270
|
init_schema2();
|
|
46851
47271
|
init_output();
|
|
46852
|
-
import { existsSync as existsSync106, readFileSync as readFileSync88, writeFileSync as
|
|
47272
|
+
import { existsSync as existsSync106, readFileSync as readFileSync88, writeFileSync as writeFileSync53 } from "node:fs";
|
|
46853
47273
|
import { join as join101 } from "node:path";
|
|
46854
47274
|
import * as readline7 from "node:readline/promises";
|
|
46855
47275
|
import { parse as parseYaml8, stringify as stringifyYaml6 } from "yaml";
|
|
@@ -46873,7 +47293,7 @@ function readConfigYaml(absPath) {
|
|
|
46873
47293
|
}
|
|
46874
47294
|
function writeConfigYaml(absPath, parsed) {
|
|
46875
47295
|
const out = stringifyYaml6(parsed, { aliasDuplicateObjects: false });
|
|
46876
|
-
|
|
47296
|
+
writeFileSync53(absPath, out, "utf-8");
|
|
46877
47297
|
}
|
|
46878
47298
|
async function defaultPromptText(question) {
|
|
46879
47299
|
const rl = readline7.createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -47351,7 +47771,7 @@ function registerMemoryStats(cmd) {
|
|
|
47351
47771
|
}
|
|
47352
47772
|
|
|
47353
47773
|
// src/commands/memory/install-hooks.ts
|
|
47354
|
-
import { copyFileSync as copyFileSync12, existsSync as existsSync108, mkdirSync as mkdirSync61, readFileSync as readFileSync89, writeFileSync as
|
|
47774
|
+
import { copyFileSync as copyFileSync12, existsSync as existsSync108, mkdirSync as mkdirSync61, readFileSync as readFileSync89, writeFileSync as writeFileSync54 } from "node:fs";
|
|
47355
47775
|
import { homedir as homedir58 } from "node:os";
|
|
47356
47776
|
import { dirname as dirname58, join as join103, resolve as resolve26 } from "node:path";
|
|
47357
47777
|
import { fileURLToPath as fileURLToPath9 } from "node:url";
|
|
@@ -47378,7 +47798,7 @@ function installOne2(basename17, sourceDir, targetDir, opts) {
|
|
|
47378
47798
|
if (!existsSync108(targetPath)) {
|
|
47379
47799
|
if (opts.dryRun !== true) {
|
|
47380
47800
|
mkdirSync61(dirname58(targetPath), { recursive: true });
|
|
47381
|
-
|
|
47801
|
+
writeFileSync54(targetPath, newContent, { mode: 493 });
|
|
47382
47802
|
}
|
|
47383
47803
|
return { basename: basename17, action: "written", targetPath };
|
|
47384
47804
|
}
|
|
@@ -47390,7 +47810,7 @@ function installOne2(basename17, sourceDir, targetDir, opts) {
|
|
|
47390
47810
|
const backupPath = `${targetPath}.agentmemory-hook-backup-${Math.floor(Date.now() / 1e3)}`;
|
|
47391
47811
|
if (opts.dryRun !== true) {
|
|
47392
47812
|
copyFileSync12(targetPath, backupPath);
|
|
47393
|
-
|
|
47813
|
+
writeFileSync54(targetPath, newContent, { mode: 493 });
|
|
47394
47814
|
}
|
|
47395
47815
|
return { basename: basename17, action: "force-overwritten", targetPath, backupPath };
|
|
47396
47816
|
}
|
|
@@ -47974,7 +48394,7 @@ function registerKgWatchCommand(kg) {
|
|
|
47974
48394
|
}
|
|
47975
48395
|
|
|
47976
48396
|
// src/commands/kg-classify.ts
|
|
47977
|
-
import
|
|
48397
|
+
import pc45 from "picocolors";
|
|
47978
48398
|
init_output();
|
|
47979
48399
|
function formatSavedTokens(n) {
|
|
47980
48400
|
if (n >= 1e6) return `~${(n / 1e6).toFixed(1)}M`;
|
|
@@ -47989,7 +48409,7 @@ function registerKgClassifyCommand(kg) {
|
|
|
47989
48409
|
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
47990
48410
|
return;
|
|
47991
48411
|
}
|
|
47992
|
-
const routeStr = result.route === "kg" ?
|
|
48412
|
+
const routeStr = result.route === "kg" ? pc45.cyan("kg") : result.route === "grep" ? pc45.magenta("grep") : pc45.yellow("both");
|
|
47993
48413
|
printInfo("route", `${routeStr} (layer ${result.layer}, took ${result.took_ms}ms)`);
|
|
47994
48414
|
printInfo("confidence", String(result.confidence));
|
|
47995
48415
|
printInfo("reason", result.reason);
|
|
@@ -48019,7 +48439,7 @@ function registerKgClassifyCommand(kg) {
|
|
|
48019
48439
|
}
|
|
48020
48440
|
|
|
48021
48441
|
// src/commands/kg-doctor.ts
|
|
48022
|
-
import
|
|
48442
|
+
import pc46 from "picocolors";
|
|
48023
48443
|
init_output();
|
|
48024
48444
|
function formatUptime(seconds) {
|
|
48025
48445
|
if (!Number.isFinite(seconds) || seconds < 0) return "?";
|
|
@@ -48181,12 +48601,12 @@ async function runKgDoctor(opts, deps = {}) {
|
|
|
48181
48601
|
} else {
|
|
48182
48602
|
printHeader("kg-service doctor");
|
|
48183
48603
|
for (const p of probes) {
|
|
48184
|
-
const badge = p.status === "ok" ?
|
|
48604
|
+
const badge = p.status === "ok" ? pc46.green("\u2713") : p.status === "warn" ? pc46.yellow("\u2298") : pc46.red("\u2717");
|
|
48185
48605
|
const label = `${badge} ${p.name}`;
|
|
48186
48606
|
const detail = p.detail ?? "";
|
|
48187
48607
|
printInfo(label, detail);
|
|
48188
48608
|
if (p.remedy) {
|
|
48189
|
-
process.stderr.write(` ${
|
|
48609
|
+
process.stderr.write(` ${pc46.dim("remedy:")} ${p.remedy}
|
|
48190
48610
|
`);
|
|
48191
48611
|
}
|
|
48192
48612
|
}
|
|
@@ -49490,7 +49910,7 @@ ${formatRedivergencePrompt(persona_a, persona_b, score, void 0, void 0, threshol
|
|
|
49490
49910
|
}
|
|
49491
49911
|
|
|
49492
49912
|
// src/commands/flywheel/ping.ts
|
|
49493
|
-
import { mkdirSync as mkdirSync65, writeFileSync as
|
|
49913
|
+
import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync58 } from "node:fs";
|
|
49494
49914
|
import { homedir as homedir65 } from "node:os";
|
|
49495
49915
|
import { dirname as dirname62, join as join109 } from "node:path";
|
|
49496
49916
|
var COLD_START_BUDGET_GOOD_MS = 200;
|
|
@@ -49510,7 +49930,7 @@ function readOlamVersion() {
|
|
|
49510
49930
|
function writeBaseline(record) {
|
|
49511
49931
|
const baselinePath = join109(homedir65(), ".local", "share", "olam", "flywheel-baseline.json");
|
|
49512
49932
|
mkdirSync65(dirname62(baselinePath), { recursive: true });
|
|
49513
|
-
|
|
49933
|
+
writeFileSync58(baselinePath, JSON.stringify(record, null, 2) + "\n", "utf8");
|
|
49514
49934
|
return baselinePath;
|
|
49515
49935
|
}
|
|
49516
49936
|
function registerFlywheelPing(parent) {
|
|
@@ -49555,7 +49975,7 @@ import {
|
|
|
49555
49975
|
readFileSync as readFileSync97,
|
|
49556
49976
|
readdirSync as readdirSync32,
|
|
49557
49977
|
statSync as statSync32,
|
|
49558
|
-
writeFileSync as
|
|
49978
|
+
writeFileSync as writeFileSync59
|
|
49559
49979
|
} from "node:fs";
|
|
49560
49980
|
import { spawnSync as spawnSync31 } from "node:child_process";
|
|
49561
49981
|
import { homedir as homedir66 } from "node:os";
|
|
@@ -50035,10 +50455,10 @@ function initMember(opts) {
|
|
|
50035
50455
|
}
|
|
50036
50456
|
try {
|
|
50037
50457
|
mkdirSync66(join110(memberDir, "skills.overrides"), { recursive: true });
|
|
50038
|
-
|
|
50458
|
+
writeFileSync59(join110(memberDir, "skills.overrides", ".gitkeep"), "");
|
|
50039
50459
|
mkdirSync66(join110(memberDir, "agents.overrides"), { recursive: true });
|
|
50040
|
-
|
|
50041
|
-
|
|
50460
|
+
writeFileSync59(join110(memberDir, "agents.overrides", ".gitkeep"), "");
|
|
50461
|
+
writeFileSync59(
|
|
50042
50462
|
join110(memberDir, "README.md"),
|
|
50043
50463
|
`# Member overlays for \`${memberName}\`
|
|
50044
50464
|
|
|
@@ -50110,7 +50530,7 @@ function migrateOverlays(opts = {}) {
|
|
|
50110
50530
|
continue;
|
|
50111
50531
|
}
|
|
50112
50532
|
if (opts.dryRun !== true) {
|
|
50113
|
-
|
|
50533
|
+
writeFileSync59(filePath, newContent, "utf8");
|
|
50114
50534
|
}
|
|
50115
50535
|
summary2.modified += 1;
|
|
50116
50536
|
summary2.totalReplacements += totalReplacements;
|
|
@@ -50353,7 +50773,7 @@ function registerFlywheelSessionStart(parent) {
|
|
|
50353
50773
|
// src/commands/flywheel/install-sessionstart-hook.ts
|
|
50354
50774
|
init_merge_settings();
|
|
50355
50775
|
init_output();
|
|
50356
|
-
import { existsSync as existsSync114, copyFileSync as copyFileSync16, mkdirSync as mkdirSync67, readFileSync as readFileSync99, unlinkSync as unlinkSync25, writeFileSync as
|
|
50776
|
+
import { existsSync as existsSync114, copyFileSync as copyFileSync16, mkdirSync as mkdirSync67, readFileSync as readFileSync99, unlinkSync as unlinkSync25, writeFileSync as writeFileSync60 } from "node:fs";
|
|
50357
50777
|
import { homedir as homedir68 } from "node:os";
|
|
50358
50778
|
import { dirname as dirname64, join as join112 } from "node:path";
|
|
50359
50779
|
var SESSIONSTART_HOOK_STAGE = "SessionStart";
|
|
@@ -50443,7 +50863,7 @@ function uninstallSessionStartHook(filePath) {
|
|
|
50443
50863
|
delete next.hooks.SessionStart;
|
|
50444
50864
|
}
|
|
50445
50865
|
}
|
|
50446
|
-
|
|
50866
|
+
writeFileSync60(filePath, JSON.stringify(next, null, 2) + "\n");
|
|
50447
50867
|
return { status: "removed", filePath };
|
|
50448
50868
|
}
|
|
50449
50869
|
function registerFlywheelInstallSessionStartHook(parent) {
|
|
@@ -50910,7 +51330,7 @@ import * as childProcess2 from "node:child_process";
|
|
|
50910
51330
|
import * as fs99 from "node:fs";
|
|
50911
51331
|
import * as os54 from "node:os";
|
|
50912
51332
|
import * as path99 from "node:path";
|
|
50913
|
-
import
|
|
51333
|
+
import pc47 from "picocolors";
|
|
50914
51334
|
var YOLO_BOOT_DELAY_MS = 8e3;
|
|
50915
51335
|
var CAPTURE_DELAY_MS = 4e3;
|
|
50916
51336
|
var TMUX_PROBE_PATHS = [
|
|
@@ -51137,13 +51557,13 @@ function registerYolo(program2) {
|
|
|
51137
51557
|
if (opts.list) {
|
|
51138
51558
|
const windows = listYoloWindows();
|
|
51139
51559
|
if (windows.length === 0) {
|
|
51140
|
-
console.log(
|
|
51560
|
+
console.log(pc47.dim("No active yolo windows found (tmux session 0)."));
|
|
51141
51561
|
return;
|
|
51142
51562
|
}
|
|
51143
51563
|
printHeader(`${windows.length} yolo window(s)`);
|
|
51144
51564
|
for (const w of windows) {
|
|
51145
|
-
const wt = w.worktreePath ?
|
|
51146
|
-
console.log(` ${
|
|
51565
|
+
const wt = w.worktreePath ? pc47.dim(w.worktreePath) : pc47.dim("(no worktree)");
|
|
51566
|
+
console.log(` ${pc47.bold(w.name.padEnd(24))} ${wt}`);
|
|
51147
51567
|
}
|
|
51148
51568
|
return;
|
|
51149
51569
|
}
|
|
@@ -51190,7 +51610,7 @@ function registerYolo(program2) {
|
|
|
51190
51610
|
printInfo("Attach", result.attachHint);
|
|
51191
51611
|
if (result.yoloFallbackUsed) {
|
|
51192
51612
|
console.log(
|
|
51193
|
-
|
|
51613
|
+
pc47.dim(
|
|
51194
51614
|
" [note] yolo alias not found on PATH \u2014 used ~/.local/bin/claude --dangerously-skip-permissions"
|
|
51195
51615
|
)
|
|
51196
51616
|
);
|