@pleri/olam-cli 0.1.141 → 0.1.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/kg-build.d.ts.map +1 -1
- package/dist/commands/kg-build.js +3 -0
- package/dist/commands/kg-build.js.map +1 -1
- package/dist/commands/kg-savings.d.ts +20 -0
- package/dist/commands/kg-savings.d.ts.map +1 -0
- package/dist/commands/kg-savings.js +77 -0
- package/dist/commands/kg-savings.js.map +1 -0
- package/dist/commands/memory/_paths.d.ts.map +1 -1
- package/dist/commands/memory/_paths.js +27 -7
- package/dist/commands/memory/_paths.js.map +1 -1
- package/dist/commands/upgrade.js +8 -8
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/image-digests.json +7 -7
- package/dist/index.js +186 -138
- package/dist/mcp-server.js +91 -118
- package/host-cp/compose.yaml +1 -1
- package/host-cp/src/server.mjs +14 -0
- package/memory-service-bundle/scripts/ensure-iii-engine.mjs +179 -0
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -3,12 +3,6 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
7
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
8
|
-
}) : x)(function(x) {
|
|
9
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
10
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
11
|
-
});
|
|
12
6
|
var __esm = (fn, res) => function __init() {
|
|
13
7
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
14
8
|
};
|
|
@@ -8933,7 +8927,7 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
|
|
|
8933
8927
|
const exec = deps.exec ?? ((cmd, args, opts) => execFileSync4(cmd, args, opts));
|
|
8934
8928
|
const homedir36 = deps.homedir ?? (() => os9.homedir());
|
|
8935
8929
|
const existsSync64 = deps.existsSync ?? ((p) => fs15.existsSync(p));
|
|
8936
|
-
const
|
|
8930
|
+
const copyFileSync8 = deps.copyFileSync ?? ((src, dest) => fs15.copyFileSync(src, dest));
|
|
8937
8931
|
const mkdirSync36 = deps.mkdirSync ?? ((dirPath, opts) => {
|
|
8938
8932
|
fs15.mkdirSync(dirPath, opts);
|
|
8939
8933
|
});
|
|
@@ -9009,7 +9003,7 @@ function carryUncommittedEdits(repos, workspacePath, deps = {}) {
|
|
|
9009
9003
|
continue;
|
|
9010
9004
|
try {
|
|
9011
9005
|
mkdirSync36(path16.dirname(dest), { recursive: true });
|
|
9012
|
-
|
|
9006
|
+
copyFileSync8(src, dest);
|
|
9013
9007
|
} catch (err) {
|
|
9014
9008
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9015
9009
|
console.warn(`[carry] ${plan.name}: copy untracked ${rel} failed: ${msg}`);
|
|
@@ -9056,125 +9050,103 @@ ${stderr.trim()}` : "";
|
|
|
9056
9050
|
}
|
|
9057
9051
|
});
|
|
9058
9052
|
|
|
9053
|
+
// ../core/dist/world/templates/_generated.js
|
|
9054
|
+
var GH_PR_CREATE, LANE_ORCHESTRATION, WORLD_CLAUDE_MD;
|
|
9055
|
+
var init_generated = __esm({
|
|
9056
|
+
"../core/dist/world/templates/_generated.js"() {
|
|
9057
|
+
"use strict";
|
|
9058
|
+
GH_PR_CREATE = '# Creating PRs from inside an Olam world\n\n## The problem\n\nCalling `gh pr create` directly inside an Olam container **hangs forever** on a\nTTY confirmation prompt that the agent cannot answer. This is a known, reproduced issue.\n\n## The fix\n\nAlways use this exact pattern:\n\n```bash\necho y | timeout 30 gh pr create \\\n --base main \\\n --head <branch> \\\n --title "<title>" \\\n --body-file /tmp/pr-body.md\n```\n\n## Why each part matters\n\n- **`echo y |`** \u2014 answers the "Submit?" confirmation prompt up front so `gh` never pauses.\n- **`timeout 30`** \u2014 hard deadline. If `gh` hangs anyway, the command exits non-zero so the\n agent can react instead of stalling the world indefinitely.\n- **`--body-file /tmp/pr-body.md`** \u2014 write the PR body to a temp file first. Avoids\n shell-escaping bugs that occur with `--body "..."` for long or multi-line bodies.\n- **`--head` and `--base` explicitly** \u2014 removes all interactive prompts; `gh` has nothing to ask.\n\n## Troubleshooting\n\n**"no commits" or "branch not found" error:**\n\n```bash\ngit push -u origin <branch>\n# then retry:\necho y | timeout 30 gh pr create --base main --head <branch> --title "..." --body-file /tmp/pr-body.md\n```\n\n**Timeout exceeded (command exits 124):**\n\n- Check if the branch was pushed: `git log origin/<branch> --oneline -1`\n- Check GitHub CLI auth: `gh auth status`\n- Retry once; if it hangs again, open the PR via the GitHub web UI.\n';
|
|
9059
|
+
LANE_ORCHESTRATION = '# Lane Orchestration\n\nOlam worlds support parallel work via **lanes** \u2014 independent Claude Code sessions\nrunning in isolated git worktrees inside the same container.\n\nUse lanes when a task has 2+ independent scopes that can work simultaneously\nwithout file conflicts.\n\n## Container API\n\nBase URL: `http://localhost:8080`\n\n### Create a lane\n\n```bash\ncurl -s -X POST \\\n -H \'Content-Type: application/json\' \\\n -d \'{"name":"auth-fix","task":"Fix auth bugs","scope":["src/auth/**"],"avoids":["tests/**"]}\' \\\n http://localhost:8080/lanes/create\n```\n\n### List lanes\n\n```bash\ncurl -s http://localhost:8080/lanes\n```\n\n### Dispatch a prompt to a lane\n\n```bash\ncurl -s -X POST \\\n -H \'Content-Type: application/json\' \\\n -d \'{"prompt":"Start by reviewing..."}\' \\\n http://localhost:8080/lanes/auth-fix/dispatch\n```\n\n### Check lane status\n\n```bash\ncurl -s http://localhost:8080/lanes/auth-fix\n```\n\n### Merge a lane\n\n```bash\ncurl -s -X POST http://localhost:8080/lanes/auth-fix/merge\n```\n\n### Destroy a lane\n\n```bash\ncurl -s -X DELETE http://localhost:8080/lanes/auth-fix\n```\n\n## When to use lanes\n\n- Task has 2+ independent scopes (different directories/modules)\n- Work can be done simultaneously without file conflicts\n- Estimated effort > ~30 tool calls per scope\n\n## When NOT to use lanes\n\n- Simple tasks touching few files\n- Sequential work where each step depends on the previous\n- Everything is in one directory\n\n## Orchestration workflow\n\n1. Analyze the task \u2014 identify independent work streams\n2. Create lanes with non-overlapping scope globs\n3. Dispatch initial prompts to each lane\n4. **Monitor progress** \u2014 poll lane status every 30 seconds:\n ```bash\n while true; do\n STATUS=$(curl -s http://localhost:8080/lanes)\n RUNNING=$(echo "$STATUS" | jq \'[.lanes[] | select(.status == "running")] | length\')\n echo "Running lanes: $RUNNING"\n if [ "$RUNNING" = "0" ]; then echo "All lanes complete!"; break; fi\n sleep 30\n done\n ```\n5. **When a lane completes** (status is "completed" or no longer "running"):\n - Check its output: `curl -s http://localhost:8080/lanes/<name>`\n - If satisfactory, merge it: `curl -s -X POST http://localhost:8080/lanes/<name>/merge`\n - The merge automatically triggers a Codex adversarial review\n6. **After ALL lanes are merged**:\n - Run tests: `npm test` or equivalent\n - Review combined changes: `git diff main...HEAD --stat`\n - Create a PR: see `~/.olam/docs/gh-pr-create.md`\n7. Clean up: `curl -s -X DELETE http://localhost:8080/lanes/<name>`\n\n## Act on completion immediately\n\nWhen all lanes are done, immediately start merging and creating the PR.\nDo not wait for the user to tell you to merge. The workflow is:\n**lanes complete \u2192 merge each \u2192 run tests \u2192 create PR \u2192 report to user.**\n';
|
|
9060
|
+
WORLD_CLAUDE_MD = '# Olam World: {{worldName}}\n\n{{taskBlock}}\n\n## Environment\n- World ID: {{worldId}}\n- Branch: {{branch}}{{servicesLine}}{{pleriPlaneLine}}\n\n## Repos in this World\n{{reposList}}\n\n{{planFileBlock}}## Instructions\n1. Work on the task described above\n2. Write tests first (TDD)\n3. Commit frequently to the world branch\n4. When done, push and the work will be available for review\n5. Your `AskUserQuestion` calls are intercepted and surfaced to the operator\'s host CP automatically. The operator answers in the SPA; claude resumes when keys are injected.\n\n## Sandbox & network \u2014 what is actually true\n\nThe olam-devbox container has FULL outbound internet. Confirm any time:\n\n```bash\ncurl -sI https://registry.npmjs.org/ # \u2192 HTTP 200\ncurl -sI https://github.com/ # \u2192 HTTP 200\n```\n\nRules:\n\n- **Never claim "the sandbox blocks X" without proving it.** Capture the actual `npm install` / `curl` error verbatim. A flaky postinstall is not a network block.\n- **Retry transient failures at least once** before falling back to a manual workaround. `npm install <pkg>` flakes happen; one retry catches >90%.\n- **If you genuinely need a workaround**, say so explicitly with the error message and the retry count, NOT "sandbox network blocked it." Truthful attribution = trustable telemetry.\n- **Playwright `chromium` downloads ~140 MB** from playwright.azureedge.net. Disk-space failures (not network) are the usual cause. Check `df -h` before blaming the network.\n\n## Halt semantics \u2014 when to stop and surface\n\nStop and call `AskUserQuestion` (which surfaces in the host CP) when you hit:\n\n- **Halt-N (new pattern)**: a new dep family, framework, or architectural pattern not in the existing codebase. Don\'t silently adopt it \u2014 surface the choice.\n- **Halt-B (business deal-breaker)**: a breaking constraint that makes the task\'s goal unsatisfiable as stated. Surface the conflict; let the operator re-scope.\n- **Halt-C (complexity blowup)**: the diff is exceeding 1.5x of what the task implied. Surface for re-scoping before continuing.\n\nDon\'t halt on every uncertainty \u2014 only on these three classes. Style/naming/error-handling choices are non-load-bearing; pick the simplest option that works and continue.\n\n## Lane Orchestration (advanced \u2014 read on demand)\n\nThis world supports parallel work lanes via the container API at http://localhost:8080.\nUse only when the task has 2+ independent scopes that can run simultaneously.\n\n**Full lane API + workflow**: see `~/.olam/docs/lane-orchestration.md` (mounted into the world).\n\n## Creating PRs from inside this world\n\n`gh pr create` hangs on a TTY prompt inside the container. Always use:\n\n```bash\necho y | timeout 30 gh pr create --base main --head <branch> --title "..." --body-file /tmp/pr-body.md\n```\n\n**Why + full troubleshooting**: see `~/.olam/docs/gh-pr-create.md`.\n\n## Available Skills & Plugins\n\nYour Claude Code session includes the invoker\'s plugins, rules, and skills.\nThese are copied from the host at world creation time.\nUse `/codex:review` or `/codex:adversarial-review` for code reviews.\nUse `/codex:rescue` to delegate tasks to Codex.\n{{extraContextBlock}}';
|
|
9061
|
+
}
|
|
9062
|
+
});
|
|
9063
|
+
|
|
9059
9064
|
// ../core/dist/world/context-injection.js
|
|
9060
9065
|
import * as fs16 from "node:fs";
|
|
9061
9066
|
import * as path17 from "node:path";
|
|
9062
|
-
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
9063
9067
|
function injectWorldContext(opts) {
|
|
9064
|
-
const { world
|
|
9068
|
+
const { world } = opts;
|
|
9065
9069
|
const claudeDir = path17.join(world.workspacePath, ".claude");
|
|
9066
9070
|
fs16.mkdirSync(claudeDir, { recursive: true });
|
|
9067
|
-
const
|
|
9068
|
-
|
|
9069
|
-
|
|
9071
|
+
const content = WORLD_CLAUDE_MD.replace("{{worldName}}", world.name).replace("{{worldId}}", world.id).replace("{{branch}}", world.branch).replace("{{taskBlock}}", buildTaskBlock(opts)).replace("{{reposList}}", buildReposList(world)).replace("{{servicesLine}}", buildServicesLine(opts.services)).replace("{{pleriPlaneLine}}", buildPleriPlaneLine(opts.pleriPlaneUrl)).replace("{{planFileBlock}}", buildPlanFileBlock(world)).replace("{{extraContextBlock}}", buildExtraContextBlock(opts.claudeMdExtra));
|
|
9072
|
+
fs16.writeFileSync(path17.join(claudeDir, "CLAUDE.md"), content);
|
|
9073
|
+
writeOlamDocs(world.workspacePath);
|
|
9074
|
+
}
|
|
9075
|
+
function buildTaskBlock(opts) {
|
|
9076
|
+
const { task, linearTicketId, taskContext, world } = opts;
|
|
9070
9077
|
if (taskContext) {
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
if (taskContext.title)
|
|
9074
|
-
|
|
9075
|
-
}
|
|
9076
|
-
|
|
9077
|
-
sections.push("");
|
|
9078
|
+
const lines = ["## Task"];
|
|
9079
|
+
lines.push(`**Source:** ${formatTaskSource(taskContext)}`);
|
|
9080
|
+
if (taskContext.title)
|
|
9081
|
+
lines.push(`**Title:** ${taskContext.title}`);
|
|
9082
|
+
lines.push(`**Branch:** ${world.branch}`);
|
|
9083
|
+
lines.push("");
|
|
9078
9084
|
if (taskContext.description) {
|
|
9079
|
-
|
|
9080
|
-
sections.push(taskContext.description);
|
|
9081
|
-
sections.push("");
|
|
9085
|
+
lines.push("### Description", taskContext.description, "");
|
|
9082
9086
|
}
|
|
9083
9087
|
if (taskContext.acceptanceCriteria) {
|
|
9084
|
-
|
|
9085
|
-
sections.push(taskContext.acceptanceCriteria);
|
|
9086
|
-
sections.push("");
|
|
9088
|
+
lines.push("### Acceptance Criteria", taskContext.acceptanceCriteria, "");
|
|
9087
9089
|
}
|
|
9088
9090
|
if (taskContext.labels && taskContext.labels.length > 0) {
|
|
9089
|
-
|
|
9090
|
-
sections.push(taskContext.labels.join(", "));
|
|
9091
|
-
sections.push("");
|
|
9091
|
+
lines.push("### Labels", taskContext.labels.join(", "), "");
|
|
9092
9092
|
}
|
|
9093
9093
|
if (taskContext.assignee) {
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9098
|
-
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
}
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
|
|
9138
|
-
|
|
9139
|
-
|
|
9140
|
-
|
|
9141
|
-
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
sections.push("## Creating PRs from inside this world");
|
|
9145
|
-
sections.push("");
|
|
9146
|
-
sections.push("`gh pr create` hangs on a TTY prompt inside the container. Always use:");
|
|
9147
|
-
sections.push("");
|
|
9148
|
-
sections.push("```bash");
|
|
9149
|
-
sections.push('echo y | timeout 30 gh pr create --base main --head <branch> --title "..." --body-file /tmp/pr-body.md');
|
|
9150
|
-
sections.push("```");
|
|
9151
|
-
sections.push("");
|
|
9152
|
-
sections.push("**Why + full troubleshooting**: see `~/.olam/docs/gh-pr-create.md`.");
|
|
9153
|
-
sections.push("");
|
|
9154
|
-
sections.push("## Available Skills & Plugins");
|
|
9155
|
-
sections.push("");
|
|
9156
|
-
sections.push("Your Claude Code session includes the invoker's plugins, rules, and skills.");
|
|
9157
|
-
sections.push("These are copied from the host at world creation time.");
|
|
9158
|
-
sections.push("Use `/codex:review` or `/codex:adversarial-review` for code reviews.");
|
|
9159
|
-
sections.push("Use `/codex:rescue` to delegate tasks to Codex.");
|
|
9160
|
-
sections.push("");
|
|
9161
|
-
if (claudeMdExtra) {
|
|
9162
|
-
sections.push("## Additional Context");
|
|
9163
|
-
sections.push(claudeMdExtra);
|
|
9164
|
-
sections.push("");
|
|
9165
|
-
}
|
|
9166
|
-
const content = sections.join("\n");
|
|
9167
|
-
fs16.writeFileSync(path17.join(claudeDir, "CLAUDE.md"), content);
|
|
9168
|
-
writeOlamDocs(world.workspacePath);
|
|
9094
|
+
lines.push("### Assignee", taskContext.assignee, "");
|
|
9095
|
+
}
|
|
9096
|
+
return lines.join("\n").trimEnd();
|
|
9097
|
+
}
|
|
9098
|
+
if (task) {
|
|
9099
|
+
return `## Task
|
|
9100
|
+
${task}`;
|
|
9101
|
+
}
|
|
9102
|
+
if (linearTicketId) {
|
|
9103
|
+
return [
|
|
9104
|
+
"## Linear Ticket",
|
|
9105
|
+
`- ID: ${linearTicketId}`,
|
|
9106
|
+
"- (Fetch full details with Linear MCP tools)"
|
|
9107
|
+
].join("\n");
|
|
9108
|
+
}
|
|
9109
|
+
return "## Task\n_(no task description provided)_";
|
|
9110
|
+
}
|
|
9111
|
+
function buildReposList(world) {
|
|
9112
|
+
return world.repos.map((repoName) => `- \`${repoName}\` \u2192 \`/home/olam/workspace/${repoName}\``).join("\n");
|
|
9113
|
+
}
|
|
9114
|
+
function buildServicesLine(services) {
|
|
9115
|
+
if (!services || services.length === 0)
|
|
9116
|
+
return "";
|
|
9117
|
+
const svcList = services.map((s) => `${s.name} (${s.port})`).join(", ");
|
|
9118
|
+
return `
|
|
9119
|
+
- Services: ${svcList}`;
|
|
9120
|
+
}
|
|
9121
|
+
function buildPleriPlaneLine(pleriPlaneUrl) {
|
|
9122
|
+
if (!pleriPlaneUrl)
|
|
9123
|
+
return "";
|
|
9124
|
+
return `
|
|
9125
|
+
- Pleri Plane: ${pleriPlaneUrl}`;
|
|
9126
|
+
}
|
|
9127
|
+
function buildPlanFileBlock(world) {
|
|
9128
|
+
if (!hasPlanFile(world))
|
|
9129
|
+
return "";
|
|
9130
|
+
return [
|
|
9131
|
+
"## Plan",
|
|
9132
|
+
"A plan file has been provided at `docs/plans/`. Review it before starting work.",
|
|
9133
|
+
"",
|
|
9134
|
+
""
|
|
9135
|
+
].join("\n");
|
|
9136
|
+
}
|
|
9137
|
+
function buildExtraContextBlock(extra) {
|
|
9138
|
+
if (!extra)
|
|
9139
|
+
return "";
|
|
9140
|
+
return `
|
|
9141
|
+
|
|
9142
|
+
## Additional Context
|
|
9143
|
+
${extra}`;
|
|
9169
9144
|
}
|
|
9170
9145
|
function writeOlamDocs(workspacePath) {
|
|
9171
9146
|
const docsDir = path17.join(workspacePath, ".olam", "docs");
|
|
9172
9147
|
fs16.mkdirSync(docsDir, { recursive: true });
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
const dest = path17.join(docsDir, filename);
|
|
9176
|
-
fs16.copyFileSync(src, dest);
|
|
9177
|
-
}
|
|
9148
|
+
fs16.writeFileSync(path17.join(docsDir, "gh-pr-create.md"), GH_PR_CREATE);
|
|
9149
|
+
fs16.writeFileSync(path17.join(docsDir, "lane-orchestration.md"), LANE_ORCHESTRATION);
|
|
9178
9150
|
}
|
|
9179
9151
|
function formatTaskSource(ctx) {
|
|
9180
9152
|
if (ctx.source === "linear" && ctx.ticketId) {
|
|
@@ -9195,11 +9167,10 @@ function hasPlanFile(world) {
|
|
|
9195
9167
|
return false;
|
|
9196
9168
|
}
|
|
9197
9169
|
}
|
|
9198
|
-
var TEMPLATES_DIR;
|
|
9199
9170
|
var init_context_injection = __esm({
|
|
9200
9171
|
"../core/dist/world/context-injection.js"() {
|
|
9201
9172
|
"use strict";
|
|
9202
|
-
|
|
9173
|
+
init_generated();
|
|
9203
9174
|
}
|
|
9204
9175
|
});
|
|
9205
9176
|
|
|
@@ -11306,8 +11277,7 @@ ${stderr.split("\n").slice(0, 3).join(" ")}`);
|
|
|
11306
11277
|
if (!olamUserPresent) {
|
|
11307
11278
|
const imageName = (() => {
|
|
11308
11279
|
try {
|
|
11309
|
-
|
|
11310
|
-
return execSync14(`docker inspect ${containerName} --format '{{.Config.Image}}'`, {
|
|
11280
|
+
return execSync5(`docker inspect ${containerName} --format '{{.Config.Image}}'`, {
|
|
11311
11281
|
encoding: "utf8",
|
|
11312
11282
|
timeout: 5e3
|
|
11313
11283
|
}).trim() || "(unknown)";
|
|
@@ -13687,7 +13657,7 @@ var init_session_aggregator = __esm({
|
|
|
13687
13657
|
import * as http from "node:http";
|
|
13688
13658
|
import * as fs24 from "node:fs";
|
|
13689
13659
|
import * as path26 from "node:path";
|
|
13690
|
-
import { fileURLToPath as
|
|
13660
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
13691
13661
|
function jsonResponse(res, data, status2 = 200) {
|
|
13692
13662
|
res.writeHead(status2, { "Content-Type": "application/json; charset=utf-8" });
|
|
13693
13663
|
res.end(JSON.stringify(data));
|
|
@@ -13868,7 +13838,7 @@ function findSessionInWorld(registry, sessionId) {
|
|
|
13868
13838
|
}
|
|
13869
13839
|
function createDashboardServer(opts) {
|
|
13870
13840
|
const { port: port2, registry } = opts;
|
|
13871
|
-
const thisDir = path26.dirname(
|
|
13841
|
+
const thisDir = path26.dirname(fileURLToPath3(import.meta.url));
|
|
13872
13842
|
const defaultPublicDir = path26.resolve(thisDir, "../../../control-plane/public");
|
|
13873
13843
|
const publicDir = opts.publicDir ?? defaultPublicDir;
|
|
13874
13844
|
let hasPublicDir = fs24.existsSync(publicDir);
|
|
@@ -15223,9 +15193,9 @@ __export(install_root_exports, {
|
|
|
15223
15193
|
});
|
|
15224
15194
|
import { existsSync as existsSync24 } from "node:fs";
|
|
15225
15195
|
import { dirname as dirname18, join as join30, resolve as resolve10 } from "node:path";
|
|
15226
|
-
import { fileURLToPath as
|
|
15196
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
15227
15197
|
function installRoot(metaUrl = import.meta.url) {
|
|
15228
|
-
const here3 =
|
|
15198
|
+
const here3 = fileURLToPath4(metaUrl);
|
|
15229
15199
|
return resolve10(dirname18(here3), "..");
|
|
15230
15200
|
}
|
|
15231
15201
|
function isDevMode(env = process.env, installRootDir = installRoot()) {
|
|
@@ -25101,22 +25071,22 @@ async function runUpgradePullByDigest(deps = {}) {
|
|
|
25101
25071
|
return { exitCode: EXIT_GENERIC_ERROR, summary: "socket-proxy recreate failed" };
|
|
25102
25072
|
}
|
|
25103
25073
|
proxySpinner.succeed("docker-socket-proxy recreated");
|
|
25104
|
-
const composeSpinner = ora7("docker compose recreate host-cp").start();
|
|
25074
|
+
const composeSpinner = ora7("docker compose recreate olam-host-cp").start();
|
|
25105
25075
|
const composeResult = composeRunner(
|
|
25106
|
-
["up", "-d", "--force-recreate", "--no-deps", "host-cp"],
|
|
25076
|
+
["up", "-d", "--force-recreate", "--no-deps", "olam-host-cp"],
|
|
25107
25077
|
composeFile,
|
|
25108
25078
|
buildComposeEnv(authSecret, captureGhToken())
|
|
25109
25079
|
);
|
|
25110
25080
|
if (!composeResult.ok) {
|
|
25111
25081
|
composeSpinner.fail("compose recreate failed");
|
|
25112
25082
|
process.stderr.write(
|
|
25113
|
-
`${pc18.red("error")} docker compose up --force-recreate host-cp failed:
|
|
25083
|
+
`${pc18.red("error")} docker compose up --force-recreate olam-host-cp failed:
|
|
25114
25084
|
${composeResult.stderr.split("\n").slice(0, 3).join("\n ")}
|
|
25115
25085
|
`
|
|
25116
25086
|
);
|
|
25117
25087
|
return { exitCode: EXIT_GENERIC_ERROR, summary: "compose recreate failed" };
|
|
25118
25088
|
}
|
|
25119
|
-
composeSpinner.succeed("host-cp recreated");
|
|
25089
|
+
composeSpinner.succeed("olam-host-cp recreated");
|
|
25120
25090
|
const authSpinner = ora7("recreate auth-service").start();
|
|
25121
25091
|
const authRecreate = deps.recreateAuth ?? defaultRecreateAuthForUpgrade;
|
|
25122
25092
|
const authResult = await authRecreate();
|
|
@@ -25230,7 +25200,7 @@ async function handleUpgrade(opts) {
|
|
|
25230
25200
|
"bash build-host-cp.sh (host-cp image)",
|
|
25231
25201
|
"smoke (docker create + inspect)",
|
|
25232
25202
|
"atomic 6-tag swap (canonical -> :olam-rollback; :olam-next -> canonical)",
|
|
25233
|
-
"docker compose --force-recreate host-cp + AuthContainerController.start auth",
|
|
25203
|
+
"docker compose --force-recreate olam-host-cp + AuthContainerController.start auth",
|
|
25234
25204
|
"poll /api/version/status until SHAs match"
|
|
25235
25205
|
]
|
|
25236
25206
|
];
|
|
@@ -25343,9 +25313,9 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
|
|
|
25343
25313
|
printInfo("Rollback", swapResult.summary);
|
|
25344
25314
|
const composeFile = findComposeFile();
|
|
25345
25315
|
const authSecret = readAuthSecret2();
|
|
25346
|
-
process.stdout.write(` ${pc18.dim("docker compose recreate host-cp".padEnd(34))}`);
|
|
25316
|
+
process.stdout.write(` ${pc18.dim("docker compose recreate olam-host-cp".padEnd(34))}`);
|
|
25347
25317
|
const composeStart = Date.now();
|
|
25348
|
-
const composeResult = runCompose(["up", "-d", "--force-recreate", "--no-deps", "host-cp"], composeFile, buildComposeEnv(authSecret, captureGhToken()));
|
|
25318
|
+
const composeResult = runCompose(["up", "-d", "--force-recreate", "--no-deps", "olam-host-cp"], composeFile, buildComposeEnv(authSecret, captureGhToken()));
|
|
25349
25319
|
const composeDur = `${((Date.now() - composeStart) / 1e3).toFixed(1)}s`;
|
|
25350
25320
|
process.stdout.write(`${composeResult.ok ? pc18.green("\u2713") : pc18.red("\u2717")} ${composeDur}
|
|
25351
25321
|
`);
|
|
@@ -25353,7 +25323,7 @@ manually inspect images with \`docker images olam-*:olam-rollback\`.`
|
|
|
25353
25323
|
printError(
|
|
25354
25324
|
`Rollback compose recreate failed:
|
|
25355
25325
|
${composeResult.stderr}
|
|
25356
|
-
Canonical tags are at :olam-rollback (good); container restart pending. Manually: \`docker compose -f packages/host-cp/compose.yaml up -d --force-recreate host-cp\`.`
|
|
25326
|
+
Canonical tags are at :olam-rollback (good); container restart pending. Manually: \`docker compose -f packages/host-cp/compose.yaml up -d --force-recreate olam-host-cp\`.`
|
|
25357
25327
|
);
|
|
25358
25328
|
process.exitCode = 1;
|
|
25359
25329
|
return;
|
|
@@ -27328,7 +27298,7 @@ import path46 from "node:path";
|
|
|
27328
27298
|
import { createInterface as createInterface3 } from "node:readline";
|
|
27329
27299
|
|
|
27330
27300
|
// src/lib/shell-rc.ts
|
|
27331
|
-
import { copyFileSync as
|
|
27301
|
+
import { copyFileSync as copyFileSync5, existsSync as existsSync46, readFileSync as readFileSync33, renameSync as renameSync5, writeFileSync as writeFileSync21 } from "node:fs";
|
|
27332
27302
|
import path45 from "node:path";
|
|
27333
27303
|
function appendIdempotent(opts) {
|
|
27334
27304
|
const { rcPath, marker, contentLine, clock = () => /* @__PURE__ */ new Date() } = opts;
|
|
@@ -27341,7 +27311,7 @@ function appendIdempotent(opts) {
|
|
|
27341
27311
|
}
|
|
27342
27312
|
const timestamp = clock().toISOString().replace(/[:.]/g, "-");
|
|
27343
27313
|
const backupPath = `${rcPath}.olam-bak.${timestamp}`;
|
|
27344
|
-
|
|
27314
|
+
copyFileSync5(rcPath, backupPath);
|
|
27345
27315
|
const separator = content.length === 0 || content.endsWith("\n") ? "" : "\n";
|
|
27346
27316
|
const trailing = contentLine.endsWith("\n") ? "" : "\n";
|
|
27347
27317
|
const nextContent = `${content}${separator}${contentLine}${trailing}`;
|
|
@@ -28361,8 +28331,8 @@ function registerWorldUpgrade(program2) {
|
|
|
28361
28331
|
init_output();
|
|
28362
28332
|
import { existsSync as existsSync52 } from "node:fs";
|
|
28363
28333
|
import { dirname as dirname27, resolve as resolve13 } from "node:path";
|
|
28364
|
-
import { fileURLToPath as
|
|
28365
|
-
var here = dirname27(
|
|
28334
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
28335
|
+
var here = dirname27(fileURLToPath5(import.meta.url));
|
|
28366
28336
|
var BUNDLE_PATH_CANDIDATES = [
|
|
28367
28337
|
// bundled (`dist/index.js` after bundle-cli.mjs) — sibling
|
|
28368
28338
|
resolve13(here, "mcp-server.js"),
|
|
@@ -29116,7 +29086,7 @@ import { pathToFileURL } from "node:url";
|
|
|
29116
29086
|
// src/commands/memory/_paths.ts
|
|
29117
29087
|
import { homedir as homedir30 } from "node:os";
|
|
29118
29088
|
import { join as join51, dirname as dirname28 } from "node:path";
|
|
29119
|
-
import { fileURLToPath as
|
|
29089
|
+
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
29120
29090
|
var OLAM_HOME = join51(homedir30(), ".olam");
|
|
29121
29091
|
var OLAM_BIN_DIR = join51(OLAM_HOME, "bin");
|
|
29122
29092
|
var III_BINARY_PATH = join51(OLAM_BIN_DIR, "iii");
|
|
@@ -29125,14 +29095,17 @@ var MEMORY_LOG_PATH = join51(OLAM_HOME, "memory-service.log");
|
|
|
29125
29095
|
var MEMORY_DATA_DIR = join51(OLAM_HOME, "memory-data");
|
|
29126
29096
|
var MEMORY_REST_PORT = 3111;
|
|
29127
29097
|
var MEMORY_LIVEZ_URL = `http://localhost:${MEMORY_REST_PORT}/agentmemory/livez`;
|
|
29128
|
-
var here2 = dirname28(
|
|
29098
|
+
var here2 = dirname28(fileURLToPath6(import.meta.url));
|
|
29129
29099
|
var candidates = [
|
|
29130
|
-
// Workspace dev: packages/cli/
|
|
29131
|
-
// Workspace built: packages/cli/dist/commands/memory/_paths.js → packages/cli → packages/memory-service
|
|
29100
|
+
// 1. Workspace dev (built): packages/cli/dist/commands/memory/_paths.js → packages/cli → packages/memory-service
|
|
29132
29101
|
join51(here2, "..", "..", "..", "..", "memory-service"),
|
|
29133
|
-
//
|
|
29102
|
+
// 2a. Workspace bundled: packages/cli/dist/index.js → packages/cli → packages/memory-service
|
|
29134
29103
|
join51(here2, "..", "..", "memory-service"),
|
|
29135
|
-
//
|
|
29104
|
+
// 2b. Published tarball: <prefix>/node_modules/@pleri/olam-cli/dist/index.js
|
|
29105
|
+
// → <prefix>/node_modules/@pleri/olam-cli/memory-service-bundle
|
|
29106
|
+
// (copied at publish time by bundle-cli.mjs)
|
|
29107
|
+
join51(here2, "..", "memory-service-bundle"),
|
|
29108
|
+
// 3. CWD fallback
|
|
29136
29109
|
join51(process.cwd(), "packages", "memory-service")
|
|
29137
29110
|
];
|
|
29138
29111
|
var MEMORY_SERVICE_CANDIDATES = candidates;
|
|
@@ -29844,6 +29817,9 @@ function kgServiceStatusUrl() {
|
|
|
29844
29817
|
function kgServiceBuildUrl() {
|
|
29845
29818
|
return url("/build");
|
|
29846
29819
|
}
|
|
29820
|
+
function kgServiceSavingsUrl() {
|
|
29821
|
+
return url("/savings");
|
|
29822
|
+
}
|
|
29847
29823
|
var KgServiceUnreachableError = class extends Error {
|
|
29848
29824
|
cause;
|
|
29849
29825
|
constructor(message, cause) {
|
|
@@ -29895,6 +29871,9 @@ async function status(opts = {}) {
|
|
|
29895
29871
|
async function build(req, opts = {}) {
|
|
29896
29872
|
return postJson(kgServiceBuildUrl(), req, opts.timeoutMs ?? 9e5);
|
|
29897
29873
|
}
|
|
29874
|
+
async function savings(opts = {}) {
|
|
29875
|
+
return getJson(kgServiceSavingsUrl(), opts.timeoutMs);
|
|
29876
|
+
}
|
|
29898
29877
|
|
|
29899
29878
|
// src/commands/kg-build.ts
|
|
29900
29879
|
init_output();
|
|
@@ -30567,19 +30546,26 @@ function defaultUrl(flavor) {
|
|
|
30567
30546
|
function buildHookCommand(opts) {
|
|
30568
30547
|
const url2 = opts.url ?? defaultUrl(opts.flavor);
|
|
30569
30548
|
const extractCmd = `python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('tool_input',d).get('command',''))" 2>/dev/null`;
|
|
30570
|
-
const emitContext = `python3 -c 'import json,sys
|
|
30549
|
+
const emitContext = `python3 -c 'import json,sys,os
|
|
30571
30550
|
try:
|
|
30572
30551
|
d=json.loads(sys.stdin.read())
|
|
30573
30552
|
if d.get("route") and d["route"] != "grep":
|
|
30574
30553
|
label=d.get("top_match") or d.get("reason","")
|
|
30575
|
-
|
|
30554
|
+
layer=d.get("layer","?")
|
|
30555
|
+
route=d["route"]
|
|
30556
|
+
nodes=d.get("nodes_matched",0)
|
|
30557
|
+
saved=(d.get("savings") or {}).get("saved_tokens_est",0)
|
|
30558
|
+
saved_k=round(saved/1000)
|
|
30559
|
+
q=os.environ.get("KG_QUERY","")[:60]
|
|
30560
|
+
sys.stderr.write(f"\\x1b[32m\\u2713 KG hit\\x1b[0m \\"{q}\\" \\u2192 L{layer}/{route} \\u00b7 {nodes} nodes \\u00b7 ~{saved_k}k tokens saved\\n")
|
|
30561
|
+
print(json.dumps({"hookSpecificOutput":{"hookEventName":"PreToolUse","additionalContext":f"[kg-classifier L{layer}|{route}] {label[:160]}"}}))
|
|
30576
30562
|
except Exception: pass' 2>/dev/null`;
|
|
30577
30563
|
return [
|
|
30578
30564
|
`KG_SENTINEL=${KG_HOOK_SENTINEL}`,
|
|
30579
30565
|
`CMD=$(${extractCmd})`,
|
|
30580
30566
|
`case "$CMD" in *grep*|*rg\\ *|*ripgrep*|*find\\ *|*fd\\ *|*ack\\ *|*ag\\ *)`,
|
|
30581
30567
|
`RESP=$(curl -s --max-time 1 -X POST -H 'Content-Type: application/json' -d "{\\"q\\":\\"$(echo \\"$CMD\\" | head -c 200 | tr '\\"' ' ')\\"}" ${url2} 2>/dev/null)`,
|
|
30582
|
-
`echo "$RESP" | ${emitContext}`,
|
|
30568
|
+
`KG_QUERY="$(echo \\"$CMD\\" | head -c 60 | tr '\\"' ' ')" echo "$RESP" | ${emitContext}`,
|
|
30583
30569
|
`;; esac`
|
|
30584
30570
|
].join("; ");
|
|
30585
30571
|
}
|
|
@@ -30752,6 +30738,67 @@ function registerKgUninstallHookCommand(kg) {
|
|
|
30752
30738
|
});
|
|
30753
30739
|
}
|
|
30754
30740
|
|
|
30741
|
+
// src/commands/kg-savings.ts
|
|
30742
|
+
init_output();
|
|
30743
|
+
function formatTokens(n) {
|
|
30744
|
+
if (n >= 1e6) return `~${(n / 1e6).toFixed(1)}M`;
|
|
30745
|
+
if (n >= 1e3) return `~${Math.round(n / 1e3)}k`;
|
|
30746
|
+
return `~${n}`;
|
|
30747
|
+
}
|
|
30748
|
+
function renderHumanReadable(stats) {
|
|
30749
|
+
if (stats.total_hits === 0) {
|
|
30750
|
+
printInfo("savings", "no KG hits logged yet \u2014 run some grep/find Bash invocations to populate /kg-data/savings.jsonl");
|
|
30751
|
+
return;
|
|
30752
|
+
}
|
|
30753
|
+
printSuccess(`KG hits: ${stats.total_hits} \xB7 estimated savings: ${formatTokens(stats.total_saved_tokens_est)} tokens`);
|
|
30754
|
+
printInfo("first hit", stats.first_hit_at ?? "(unknown)");
|
|
30755
|
+
printInfo("last hit", stats.last_hit_at ?? "(unknown)");
|
|
30756
|
+
const layerPairs = Object.entries(stats.by_layer).map(
|
|
30757
|
+
([k, v]) => [k, v ?? 0]
|
|
30758
|
+
);
|
|
30759
|
+
const layers = [...layerPairs].sort((a, b) => a[0].localeCompare(b[0]));
|
|
30760
|
+
if (layers.length > 0) {
|
|
30761
|
+
printInfo("by layer", layers.map(([k, v]) => `L${k}=${formatTokens(v)}`).join(" \xB7 "));
|
|
30762
|
+
}
|
|
30763
|
+
const workspacePairs = Object.entries(
|
|
30764
|
+
stats.by_workspace
|
|
30765
|
+
).map(([k, v]) => [k, v ?? 0]);
|
|
30766
|
+
const workspaces = [...workspacePairs].sort((a, b) => b[1] - a[1]).slice(0, 5);
|
|
30767
|
+
if (workspaces.length > 0) {
|
|
30768
|
+
printInfo(
|
|
30769
|
+
"top workspaces",
|
|
30770
|
+
workspaces.map(([k, v]) => `${k || "(none)"}=${formatTokens(v)}`).join(" \xB7 ")
|
|
30771
|
+
);
|
|
30772
|
+
}
|
|
30773
|
+
if (stats.parse_errors > 0) {
|
|
30774
|
+
printWarning(`savings.jsonl had ${stats.parse_errors} unparseable lines (skipped)`);
|
|
30775
|
+
}
|
|
30776
|
+
printInfo("note", "savings are a heuristic, not a measurement. See SAVINGS_HEURISTIC in server.py for the per-layer model.");
|
|
30777
|
+
}
|
|
30778
|
+
function registerKgSavingsCommand(kg) {
|
|
30779
|
+
kg.command("savings").description("Show cumulative KG-hit savings tallied by the kg-service container").option("--json", "emit raw response JSON instead of human-readable summary").action(async (opts) => {
|
|
30780
|
+
let stats;
|
|
30781
|
+
try {
|
|
30782
|
+
stats = await savings();
|
|
30783
|
+
} catch (err) {
|
|
30784
|
+
if (err instanceof KgServiceUnreachableError) {
|
|
30785
|
+
printError(err.message);
|
|
30786
|
+
printInfo("remedy", "`olam services up` to start kg-service, then re-run");
|
|
30787
|
+
process.exitCode = 3;
|
|
30788
|
+
return;
|
|
30789
|
+
}
|
|
30790
|
+
printError(`kg-service /savings failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
30791
|
+
process.exitCode = 1;
|
|
30792
|
+
return;
|
|
30793
|
+
}
|
|
30794
|
+
if (opts.json) {
|
|
30795
|
+
process.stdout.write(JSON.stringify(stats, null, 2) + "\n");
|
|
30796
|
+
return;
|
|
30797
|
+
}
|
|
30798
|
+
renderHumanReadable(stats);
|
|
30799
|
+
});
|
|
30800
|
+
}
|
|
30801
|
+
|
|
30755
30802
|
// src/commands/kg-build.ts
|
|
30756
30803
|
function resolveWorkspace(arg) {
|
|
30757
30804
|
const cwd = process.cwd();
|
|
@@ -30849,6 +30896,7 @@ function registerKg(program2) {
|
|
|
30849
30896
|
registerKgDoctorCommand(kg);
|
|
30850
30897
|
registerKgInstallHookCommand(kg);
|
|
30851
30898
|
registerKgUninstallHookCommand(kg);
|
|
30899
|
+
registerKgSavingsCommand(kg);
|
|
30852
30900
|
}
|
|
30853
30901
|
|
|
30854
30902
|
// src/commands/seed.ts
|