@pleri/olam-cli 0.1.182 → 0.1.186

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/dist/agent-stream/agent-sdk-to-chunks.js +44 -30
  2. package/dist/ask/checkout.d.ts +19 -0
  3. package/dist/ask/checkout.d.ts.map +1 -0
  4. package/dist/ask/checkout.js +40 -0
  5. package/dist/ask/checkout.js.map +1 -0
  6. package/dist/ask/knowledge-pack-builder.d.ts +72 -0
  7. package/dist/ask/knowledge-pack-builder.d.ts.map +1 -0
  8. package/dist/ask/knowledge-pack-builder.js +91 -0
  9. package/dist/ask/knowledge-pack-builder.js.map +1 -0
  10. package/dist/ask/knowledge-pack.generated.d.ts +8 -0
  11. package/dist/ask/knowledge-pack.generated.d.ts.map +1 -0
  12. package/dist/ask/knowledge-pack.generated.js +1947 -0
  13. package/dist/ask/knowledge-pack.generated.js.map +1 -0
  14. package/dist/ask/one-shot.d.ts +21 -0
  15. package/dist/ask/one-shot.d.ts.map +1 -0
  16. package/dist/ask/one-shot.js +50 -0
  17. package/dist/ask/one-shot.js.map +1 -0
  18. package/dist/ask/repl.d.ts +30 -0
  19. package/dist/ask/repl.d.ts.map +1 -0
  20. package/dist/ask/repl.js +109 -0
  21. package/dist/ask/repl.js.map +1 -0
  22. package/dist/ask/sdk-client.d.ts +87 -0
  23. package/dist/ask/sdk-client.d.ts.map +1 -0
  24. package/dist/ask/sdk-client.js +118 -0
  25. package/dist/ask/sdk-client.js.map +1 -0
  26. package/dist/ask/system-prompt.d.ts +30 -0
  27. package/dist/ask/system-prompt.d.ts.map +1 -0
  28. package/dist/ask/system-prompt.js +31 -0
  29. package/dist/ask/system-prompt.js.map +1 -0
  30. package/dist/commands/ask.d.ts +27 -0
  31. package/dist/commands/ask.d.ts.map +1 -0
  32. package/dist/commands/ask.js +63 -0
  33. package/dist/commands/ask.js.map +1 -0
  34. package/dist/commands/auth-list-json.d.ts +53 -0
  35. package/dist/commands/auth-list-json.d.ts.map +1 -0
  36. package/dist/commands/auth-list-json.js +47 -0
  37. package/dist/commands/auth-list-json.js.map +1 -0
  38. package/dist/commands/auth.d.ts.map +1 -1
  39. package/dist/commands/auth.js +13 -0
  40. package/dist/commands/auth.js.map +1 -1
  41. package/dist/commands/doctor.js +11 -11
  42. package/dist/commands/doctor.js.map +1 -1
  43. package/dist/commands/keys-list-json.d.ts +55 -0
  44. package/dist/commands/keys-list-json.d.ts.map +1 -0
  45. package/dist/commands/keys-list-json.js +54 -0
  46. package/dist/commands/keys-list-json.js.map +1 -0
  47. package/dist/commands/keys.d.ts.map +1 -1
  48. package/dist/commands/keys.js +6 -0
  49. package/dist/commands/keys.js.map +1 -1
  50. package/dist/commands/lanes-list-json.d.ts +69 -0
  51. package/dist/commands/lanes-list-json.d.ts.map +1 -0
  52. package/dist/commands/lanes-list-json.js +42 -0
  53. package/dist/commands/lanes-list-json.js.map +1 -0
  54. package/dist/commands/lanes.d.ts.map +1 -1
  55. package/dist/commands/lanes.js +18 -7
  56. package/dist/commands/lanes.js.map +1 -1
  57. package/dist/commands/plans-list-json.d.ts +77 -0
  58. package/dist/commands/plans-list-json.d.ts.map +1 -0
  59. package/dist/commands/plans-list-json.js +61 -0
  60. package/dist/commands/plans-list-json.js.map +1 -0
  61. package/dist/commands/plans.d.ts.map +1 -1
  62. package/dist/commands/plans.js +10 -0
  63. package/dist/commands/plans.js.map +1 -1
  64. package/dist/commands/repos-list-json.d.ts +58 -0
  65. package/dist/commands/repos-list-json.d.ts.map +1 -0
  66. package/dist/commands/repos-list-json.js +45 -0
  67. package/dist/commands/repos-list-json.js.map +1 -0
  68. package/dist/commands/repos.d.ts +1 -1
  69. package/dist/commands/repos.d.ts.map +1 -1
  70. package/dist/commands/repos.js +12 -2
  71. package/dist/commands/repos.js.map +1 -1
  72. package/dist/commands/services.d.ts +47 -1
  73. package/dist/commands/services.d.ts.map +1 -1
  74. package/dist/commands/services.js +59 -33
  75. package/dist/commands/services.js.map +1 -1
  76. package/dist/commands/skills.d.ts +27 -0
  77. package/dist/commands/skills.d.ts.map +1 -1
  78. package/dist/commands/skills.js +17 -2
  79. package/dist/commands/skills.js.map +1 -1
  80. package/dist/commands/workspace-list-json.d.ts +73 -0
  81. package/dist/commands/workspace-list-json.d.ts.map +1 -0
  82. package/dist/commands/workspace-list-json.js +59 -0
  83. package/dist/commands/workspace-list-json.js.map +1 -0
  84. package/dist/commands/workspace.d.ts.map +1 -1
  85. package/dist/commands/workspace.js +7 -1
  86. package/dist/commands/workspace.js.map +1 -1
  87. package/dist/image-digests.json +8 -8
  88. package/dist/index.js +3170 -580
  89. package/dist/index.js.map +1 -1
  90. package/dist/lib/k8s-bootstrap.d.ts.map +1 -1
  91. package/dist/lib/k8s-bootstrap.js +13 -1
  92. package/dist/lib/k8s-bootstrap.js.map +1 -1
  93. package/dist/lib/k8s-secret-render.d.ts +2 -0
  94. package/dist/lib/k8s-secret-render.d.ts.map +1 -1
  95. package/dist/lib/k8s-secret-render.js +27 -0
  96. package/dist/lib/k8s-secret-render.js.map +1 -1
  97. package/dist/lib/peripheral-registry.d.ts +1 -1
  98. package/dist/lib/peripheral-registry.d.ts.map +1 -1
  99. package/dist/lib/peripheral-registry.js +13 -0
  100. package/dist/lib/peripheral-registry.js.map +1 -1
  101. package/dist/lib/upgrade-kubernetes.d.ts +6 -0
  102. package/dist/lib/upgrade-kubernetes.d.ts.map +1 -1
  103. package/dist/lib/upgrade-kubernetes.js +7 -1
  104. package/dist/lib/upgrade-kubernetes.js.map +1 -1
  105. package/dist/mcp-server.js +1167 -37
  106. package/hermes-bundle/version.json +1 -1
  107. package/host-cp/k8s/manifests/30-configmap.yaml +11 -6
  108. package/host-cp/k8s/manifests/50-deployment.yaml +15 -1
  109. package/host-cp/k8s/manifests/auth-service/50-deployment.yaml +1 -1
  110. package/host-cp/k8s/manifests/kg-service/50-deployment.yaml +1 -1
  111. package/host-cp/k8s/manifests/mcp-auth-service/50-deployment.yaml +1 -1
  112. package/host-cp/k8s/manifests/memory-service/50-deployment.yaml +1 -1
  113. package/host-cp/k8s/templates/chunks-postgres-secret-template.yaml +24 -0
  114. package/host-cp/k8s/templates/plan-chat-service-secret-template.yaml +35 -0
  115. package/host-cp/src/plan-chat-service.mjs +99 -74
  116. package/host-cp/src/server.mjs +141 -5
  117. package/package.json +4 -2
@@ -13373,7 +13373,7 @@ var init_artifact_resolver = __esm({
13373
13373
 
13374
13374
  // ../core/dist/lib/shim-targets.js
13375
13375
  function lookupShimTarget(basename6) {
13376
- return SHIM_TARGETS.find((t) => t.basename === basename6);
13376
+ return SHIM_TARGETS_BY_BASENAME.get(basename6);
13377
13377
  }
13378
13378
  function compareSemver(installed, required2) {
13379
13379
  const norm = (s) => {
@@ -13404,7 +13404,7 @@ function checkShimRemoval(basename6, installedOlamVersion) {
13404
13404
  safeToRemove: compareSemver(installedOlamVersion, target.minOlamVersion) >= 0
13405
13405
  };
13406
13406
  }
13407
- var SHIM_TARGETS;
13407
+ var SHIM_TARGETS, SHIM_TARGETS_BY_BASENAME;
13408
13408
  var init_shim_targets = __esm({
13409
13409
  "../core/dist/lib/shim-targets.js"() {
13410
13410
  "use strict";
@@ -13419,6 +13419,7 @@ var init_shim_targets = __esm({
13419
13419
  { basename: "apply-overlays.py", minOlamVersion: "0.2.0", replacedBy: "olam skills apply-overlays" },
13420
13420
  { basename: "sync-with-overlays.sh", minOlamVersion: "0.2.0", replacedBy: "olam skills sync --with-overlays" }
13421
13421
  ]);
13422
+ SHIM_TARGETS_BY_BASENAME = new Map(SHIM_TARGETS.map((t) => [t.basename, t]));
13422
13423
  }
13423
13424
  });
13424
13425
 
@@ -14845,19 +14846,28 @@ function parseSections(body) {
14845
14846
  return sections;
14846
14847
  }
14847
14848
  function sectionsToBody(sections) {
14849
+ let tail = "";
14848
14850
  const out = [];
14851
+ function trackPush(s) {
14852
+ out.push(s);
14853
+ if (s.length >= 2) {
14854
+ tail = s.slice(-2);
14855
+ } else if (s.length === 1) {
14856
+ tail = (tail.length > 0 ? tail.slice(-1) : "") + s;
14857
+ }
14858
+ }
14849
14859
  for (const [heading, content] of sections) {
14850
14860
  if (heading === null) {
14851
- out.push(content);
14861
+ trackPush(content);
14852
14862
  } else {
14853
- const current = out.join("");
14854
- if (current !== "" && !current.endsWith("\n\n")) {
14855
- if (current.endsWith("\n"))
14856
- out.push("\n");
14863
+ const hasOutput = out.length > 0 && (out.length > 1 || out[0] !== "");
14864
+ if (hasOutput && tail !== "\n\n") {
14865
+ if (tail.endsWith("\n"))
14866
+ trackPush("\n");
14857
14867
  else
14858
- out.push("\n\n");
14868
+ trackPush("\n\n");
14859
14869
  }
14860
- out.push(heading + content);
14870
+ trackPush(heading + content);
14861
14871
  }
14862
14872
  }
14863
14873
  return out.join("");
@@ -32042,12 +32052,28 @@ function rowToEdge(row) {
32042
32052
  var SCHEMA_VERSION2 = "2";
32043
32053
  var ThoughtLocalStore = class {
32044
32054
  db;
32055
+ // Prepared statements cached at construction time so insertNode / insertEdge
32056
+ // never re-compile the same SQL on every call in a hot insertBatch loop.
32057
+ stmtInsertNode;
32058
+ stmtInsertEdge;
32045
32059
  constructor(dbPath) {
32046
32060
  const Database = getDatabase2();
32047
32061
  this.db = new Database(dbPath);
32048
32062
  this.db.pragma("journal_mode = WAL");
32049
32063
  this.db.pragma("foreign_keys = ON");
32050
32064
  this.initSchema();
32065
+ this.stmtInsertNode = this.db.prepare(`
32066
+ INSERT INTO thought_nodes (id, node_type, summary, content, source_ref, sequence_num, created_at,
32067
+ session_id, hook_event_name, turn_index, token_usage, duration_ms)
32068
+ VALUES (@id, @nodeType, @summary, @content, @sourceRef, @sequenceNum, @createdAt,
32069
+ @sessionId, @hookEventName, @turnIndex, @tokenUsage, @durationMs)
32070
+ ON CONFLICT (id) DO NOTHING
32071
+ `);
32072
+ this.stmtInsertEdge = this.db.prepare(`
32073
+ INSERT INTO thought_edges (id, source_id, target_id, edge_type, metadata, created_at)
32074
+ VALUES (@id, @sourceId, @targetId, @edgeType, @metadata, @createdAt)
32075
+ ON CONFLICT (id) DO NOTHING
32076
+ `);
32051
32077
  }
32052
32078
  initSchema() {
32053
32079
  this.db.exec(`
@@ -32145,14 +32171,7 @@ var ThoughtLocalStore = class {
32145
32171
  migrate();
32146
32172
  }
32147
32173
  insertNode(node) {
32148
- const stmt = this.db.prepare(`
32149
- INSERT INTO thought_nodes (id, node_type, summary, content, source_ref, sequence_num, created_at,
32150
- session_id, hook_event_name, turn_index, token_usage, duration_ms)
32151
- VALUES (@id, @nodeType, @summary, @content, @sourceRef, @sequenceNum, @createdAt,
32152
- @sessionId, @hookEventName, @turnIndex, @tokenUsage, @durationMs)
32153
- ON CONFLICT (id) DO NOTHING
32154
- `);
32155
- stmt.run({
32174
+ this.stmtInsertNode.run({
32156
32175
  id: node.id,
32157
32176
  nodeType: node.nodeType,
32158
32177
  summary: node.summary,
@@ -32168,12 +32187,7 @@ var ThoughtLocalStore = class {
32168
32187
  });
32169
32188
  }
32170
32189
  insertEdge(edge) {
32171
- const stmt = this.db.prepare(`
32172
- INSERT INTO thought_edges (id, source_id, target_id, edge_type, metadata, created_at)
32173
- VALUES (@id, @sourceId, @targetId, @edgeType, @metadata, @createdAt)
32174
- ON CONFLICT (id) DO NOTHING
32175
- `);
32176
- stmt.run({
32190
+ this.stmtInsertEdge.run({
32177
32191
  id: edge.id,
32178
32192
  sourceId: edge.sourceId,
32179
32193
  targetId: edge.targetId,
@@ -37832,6 +37846,152 @@ function register31(server, _ctx, _initError) {
37832
37846
  );
37833
37847
  }
37834
37848
 
37849
+ // ../mcp-server/src/tools/pr-apply-review-comments.ts
37850
+ var pr_apply_review_comments_exports = {};
37851
+ __export(pr_apply_review_comments_exports, {
37852
+ register: () => register32
37853
+ });
37854
+ import { execFile as execFile2 } from "node:child_process";
37855
+ import { promisify as promisify2 } from "node:util";
37856
+
37857
+ // ../skill-runtime/dist/skills/pr-apply-review-comments.js
37858
+ init_v3();
37859
+ var prApplyReviewCommentsInputSchema = external_exports.object({
37860
+ prNumber: external_exports.number().int().positive().describe("GitHub PR number to fetch unresolved review threads from"),
37861
+ dryRun: external_exports.boolean().optional().describe("When true (default), return what would be dispatched without firing. v1 always dry-runs regardless of this flag \u2014 dispatch wiring is Phase 2."),
37862
+ repo: external_exports.string().optional().describe("Repository slug (owner/repo). Defaults to the current repo detected via git remote.")
37863
+ });
37864
+ var prApplyReviewCommentsSkill = defineSkill({
37865
+ name: "pr-apply-review-comments",
37866
+ description: "Fetch unresolved review-comment threads for a GitHub PR and package them as an Olam dispatch payload. Returns the PR metadata, a structured comment list, and the synthesised prompt that would be dispatched. v1 stub \u2014 dispatch is NOT wired (Phase 2). Safe to call from any agent; nothing is mutated or fired.",
37867
+ inputSchema: prApplyReviewCommentsInputSchema,
37868
+ handler: (input) => {
37869
+ return {
37870
+ pr: {
37871
+ number: input.prNumber,
37872
+ title: "(skill-runtime stub \u2014 no gh context)",
37873
+ headRefName: "stub-branch"
37874
+ },
37875
+ comments: [],
37876
+ dispatchPayload: {
37877
+ worldId: null,
37878
+ prompt: `Apply review comments on PR #${input.prNumber}.
37879
+ (No comments resolved \u2014 skill-runtime stub context.)`
37880
+ },
37881
+ status: "dry-run",
37882
+ stubNote: "v1 stub: skill-runtime handler has no gh context. Register this skill via @olam/mcp-server for a live response."
37883
+ };
37884
+ }
37885
+ });
37886
+
37887
+ // ../mcp-server/src/tools/pr-apply-review-comments.ts
37888
+ var execFileAsync = promisify2(execFile2);
37889
+ function resolveWorldId(_prNumber) {
37890
+ return null;
37891
+ }
37892
+ function synthesisePrompt(prNumber, comments) {
37893
+ if (comments.length === 0) {
37894
+ return `No unresolved review comments found on PR #${prNumber}. Nothing to apply.`;
37895
+ }
37896
+ const lines = [
37897
+ `Apply all unresolved reviewer comments on PR #${prNumber}.`,
37898
+ ``,
37899
+ `Unresolved review comments (${comments.length}):`
37900
+ ];
37901
+ for (const c of comments) {
37902
+ const location = c.line != null ? `${c.path}:${c.line}` : c.path;
37903
+ lines.push(`- [${location}] @${c.author}: ${c.body.replace(/\n/g, " ").slice(0, 200)}`);
37904
+ }
37905
+ lines.push(
37906
+ ``,
37907
+ `For each comment: understand the reviewer's intent, make the minimal change`,
37908
+ `that addresses it, then move on. Do not introduce scope beyond what each`,
37909
+ `comment requests. Push when all comments are addressed.`
37910
+ );
37911
+ return lines.join("\n");
37912
+ }
37913
+ async function fetchPrData(prNumber, repo) {
37914
+ const args = [
37915
+ "pr",
37916
+ "view",
37917
+ String(prNumber),
37918
+ "--json",
37919
+ "number,title,headRefName,reviewThreads"
37920
+ ];
37921
+ if (repo) {
37922
+ args.push("--repo", repo);
37923
+ }
37924
+ const { stdout } = await execFileAsync("gh", args, {
37925
+ timeout: 15e3
37926
+ });
37927
+ return JSON.parse(stdout);
37928
+ }
37929
+ function register32(server, _ctx, _initError, deps) {
37930
+ const fetcher = deps?.fetchPr ?? fetchPrData;
37931
+ const { description, inputSchema } = prApplyReviewCommentsSkill.asMcpTool();
37932
+ server.tool(
37933
+ "olam_pr_apply_review_comments",
37934
+ description,
37935
+ inputSchema,
37936
+ async (params) => {
37937
+ const { prNumber, repo } = params;
37938
+ let prData;
37939
+ try {
37940
+ prData = await fetcher(prNumber, repo);
37941
+ } catch (err) {
37942
+ const msg = err instanceof Error ? err.message : String(err);
37943
+ return {
37944
+ content: [
37945
+ {
37946
+ type: "text",
37947
+ text: `Failed to fetch PR #${prNumber}: ${msg}
37948
+
37949
+ Ensure gh CLI is authenticated and the PR exists.`
37950
+ }
37951
+ ],
37952
+ isError: true
37953
+ };
37954
+ }
37955
+ const unresolvedThreads = (prData.reviewThreads ?? []).filter(
37956
+ (t) => !t.isResolved && !t.isOutdated
37957
+ );
37958
+ const comments = unresolvedThreads.flatMap(
37959
+ (thread) => (thread.comments.nodes ?? []).map((node) => ({
37960
+ author: node.author?.login ?? "unknown",
37961
+ body: node.body,
37962
+ path: node.path,
37963
+ line: node.line ?? node.originalLine ?? null,
37964
+ threadId: thread.id
37965
+ }))
37966
+ );
37967
+ const worldId = resolveWorldId(prNumber);
37968
+ const prompt = synthesisePrompt(prNumber, comments);
37969
+ const result = {
37970
+ pr: {
37971
+ number: prData.number,
37972
+ title: prData.title,
37973
+ headRefName: prData.headRefName
37974
+ },
37975
+ comments,
37976
+ dispatchPayload: {
37977
+ worldId,
37978
+ prompt
37979
+ },
37980
+ status: "dry-run",
37981
+ stubNote: "v1 stub: dispatch is not wired. Phase 2 will wire worldId resolution + actual olam_dispatch call. See docs/research/2026-05-27-pr-comment-reply-prior-art.md for the shaping brief."
37982
+ };
37983
+ return {
37984
+ content: [
37985
+ {
37986
+ type: "text",
37987
+ text: JSON.stringify(result, null, 2)
37988
+ }
37989
+ ]
37990
+ };
37991
+ }
37992
+ );
37993
+ }
37994
+
37835
37995
  // ../mcp-server/src/tools/index.ts
37836
37996
  var toolModules = [
37837
37997
  init_exports,
@@ -37864,7 +38024,8 @@ var toolModules = [
37864
38024
  kg_classify_exports,
37865
38025
  kg_doctor_exports,
37866
38026
  kg_install_hook_exports,
37867
- kg_uninstall_hook_exports
38027
+ kg_uninstall_hook_exports,
38028
+ pr_apply_review_comments_exports
37868
38029
  ];
37869
38030
  function registerAllTools(server, ctx, initError) {
37870
38031
  const filterContext = getToolFilterContextFromEnv();
@@ -38202,6 +38363,374 @@ function createChunksResource(deps = {}) {
38202
38363
  };
38203
38364
  }
38204
38365
 
38366
+ // ../mcp-server/src/resources/capabilities.ts
38367
+ var CAPABILITIES_URI = "olam://capabilities";
38368
+ var CHUNKS_ERROR_CODES = [
38369
+ {
38370
+ code: "invalid_uri",
38371
+ jsonRpcCode: -32602,
38372
+ jsonRpcClass: "InvalidParams",
38373
+ when: "URI scheme/host/path does not match olam://worlds/<id>/chunks."
38374
+ },
38375
+ {
38376
+ code: "missing_session_id",
38377
+ jsonRpcCode: -32602,
38378
+ jsonRpcClass: "InvalidParams",
38379
+ when: "URI lacks ?sessionId=... \u2014 the Electric shape proxy requires it."
38380
+ },
38381
+ {
38382
+ code: "missing_bearer",
38383
+ jsonRpcCode: -32602,
38384
+ jsonRpcClass: "InvalidParams",
38385
+ when: "Neither OLAM_PLAN_CHAT_BEARER nor the on-disk secret is readable."
38386
+ },
38387
+ {
38388
+ code: "upstream_unavailable",
38389
+ jsonRpcCode: -32603,
38390
+ jsonRpcClass: "InternalError",
38391
+ when: "host-cp /api/plan-chat/v1/shape unreachable (fetch threw)."
38392
+ },
38393
+ {
38394
+ code: "upstream_error",
38395
+ jsonRpcCode: -32603,
38396
+ jsonRpcClass: "InternalError",
38397
+ when: "host-cp returned a non-2xx or non-JSON body."
38398
+ }
38399
+ ];
38400
+ function buildCapabilitiesPayload(chunks) {
38401
+ return {
38402
+ schemaVersion: 1,
38403
+ server: "olam",
38404
+ capabilities: { resources: true, tools: true },
38405
+ resources: [
38406
+ {
38407
+ name: chunks.name,
38408
+ uriTemplate: chunks.uriTemplate,
38409
+ templated: true,
38410
+ mimeType: chunks.mimeType,
38411
+ description: chunks.description,
38412
+ params: [
38413
+ {
38414
+ name: "sessionId",
38415
+ required: true,
38416
+ description: "Scopes the read to a single planning session. Electric SQL enforces per-(world_id,session_id) scope server-side, so this is required at read time despite being optional in the template."
38417
+ },
38418
+ {
38419
+ name: "limit",
38420
+ required: false,
38421
+ description: "Advisory cap on returned row count. Parsed from the URL; not part of the matched RFC 6570 template."
38422
+ }
38423
+ ],
38424
+ errorCodes: [...CHUNKS_ERROR_CODES]
38425
+ }
38426
+ ]
38427
+ };
38428
+ }
38429
+ function createCapabilitiesResource() {
38430
+ return {
38431
+ name: "olam-capabilities",
38432
+ uri: CAPABILITIES_URI,
38433
+ description: "Machine-readable catalog of the Olam MCP server's Resources surface: every resource URI template, its query params, and the structured error-code taxonomy a failed resources/read can return. Read this once to discover the contract programmatically instead of parsing prose.",
38434
+ mimeType: "application/json",
38435
+ read(chunks) {
38436
+ return buildCapabilitiesPayload(chunks);
38437
+ }
38438
+ };
38439
+ }
38440
+
38441
+ // ../mcp-server/src/tool-catalog.ts
38442
+ function unwrap(schema) {
38443
+ let current = schema;
38444
+ let optional2 = false;
38445
+ let hasDefault = false;
38446
+ for (let depth = 0; depth < 16; depth += 1) {
38447
+ const typeName = current._def?.typeName;
38448
+ if (typeName === "ZodOptional") {
38449
+ optional2 = true;
38450
+ const inner = current._def?.innerType;
38451
+ if (!inner) break;
38452
+ current = inner;
38453
+ continue;
38454
+ }
38455
+ if (typeName === "ZodDefault") {
38456
+ optional2 = true;
38457
+ hasDefault = true;
38458
+ const inner = current._def?.innerType;
38459
+ if (!inner) break;
38460
+ current = inner;
38461
+ continue;
38462
+ }
38463
+ if (typeName === "ZodNullable") {
38464
+ const inner = current._def?.innerType;
38465
+ if (!inner) break;
38466
+ current = inner;
38467
+ continue;
38468
+ }
38469
+ if (typeName === "ZodEffects") {
38470
+ const inner = current._def?.schema;
38471
+ if (!inner) break;
38472
+ current = inner;
38473
+ continue;
38474
+ }
38475
+ break;
38476
+ }
38477
+ return { base: current, optional: optional2, hasDefault };
38478
+ }
38479
+ function extractDescription(schema) {
38480
+ let current = schema;
38481
+ for (let depth = 0; depth < 16 && current; depth += 1) {
38482
+ const d = current._def?.description ?? current.description;
38483
+ if (typeof d === "string" && d.length > 0) return d;
38484
+ current = current._def?.innerType ?? current._def?.schema;
38485
+ }
38486
+ return null;
38487
+ }
38488
+ function canonicalType(base) {
38489
+ const typeName = base._def?.typeName;
38490
+ switch (typeName) {
38491
+ case "ZodString":
38492
+ return "string";
38493
+ case "ZodNumber":
38494
+ return "number";
38495
+ case "ZodBoolean":
38496
+ return "boolean";
38497
+ case "ZodArray":
38498
+ return "array";
38499
+ case "ZodObject":
38500
+ return "object";
38501
+ case "ZodEnum":
38502
+ case "ZodNativeEnum":
38503
+ return "enum";
38504
+ case "ZodEffects":
38505
+ return "effect";
38506
+ case "ZodLiteral":
38507
+ return "literal";
38508
+ default:
38509
+ return typeName ? typeName.replace(/^Zod/, "").toLowerCase() : "unknown";
38510
+ }
38511
+ }
38512
+ function readEnumValues(base) {
38513
+ if (base._def?.typeName !== "ZodEnum" && base._def?.typeName !== "ZodNativeEnum") {
38514
+ return null;
38515
+ }
38516
+ const values = base._def?.values;
38517
+ if (Array.isArray(values)) {
38518
+ return [...values.map((v) => String(v))].sort();
38519
+ }
38520
+ if (values && typeof values === "object") {
38521
+ return Object.values(values).map((v) => String(v)).sort();
38522
+ }
38523
+ return null;
38524
+ }
38525
+ function isConstrained(base) {
38526
+ const typeName = base._def?.typeName;
38527
+ if (typeName === "ZodEnum" || typeName === "ZodNativeEnum" || typeName === "ZodNumber" || typeName === "ZodBoolean" || typeName === "ZodLiteral" || typeName === "ZodArray" || typeName === "ZodObject" || typeName === "ZodEffects") {
38528
+ return true;
38529
+ }
38530
+ if (typeName === "ZodString") {
38531
+ const checks = base._def?.checks;
38532
+ return Array.isArray(checks) && checks.length > 0;
38533
+ }
38534
+ return false;
38535
+ }
38536
+ function describeParam(schema) {
38537
+ const { base, optional: optional2, hasDefault } = unwrap(schema);
38538
+ return {
38539
+ type: canonicalType(base),
38540
+ optional: optional2,
38541
+ hasDefault,
38542
+ description: extractDescription(schema),
38543
+ enumValues: readEnumValues(base),
38544
+ constrained: isConstrained(base)
38545
+ };
38546
+ }
38547
+ function extractToolCatalog() {
38548
+ const captured = [];
38549
+ const recordingServer = {
38550
+ tool(name, description, inputSchema, _handler) {
38551
+ const params = {};
38552
+ if (inputSchema && typeof inputSchema === "object") {
38553
+ for (const [key, fieldSchema] of Object.entries(inputSchema)) {
38554
+ params[key] = describeParam(fieldSchema);
38555
+ }
38556
+ }
38557
+ captured.push({ name, description: description ?? "", params });
38558
+ }
38559
+ };
38560
+ registerAllTools(recordingServer, void 0, void 0);
38561
+ return [...captured].sort((a, b) => a.name.localeCompare(b.name));
38562
+ }
38563
+
38564
+ // ../mcp-server/src/resources/tools-catalog.ts
38565
+ var TOOLS_CATALOG_URI = "olam://tools";
38566
+ function buildToolsCatalogPayload(catalog) {
38567
+ const tools = catalog.map((tool) => ({
38568
+ name: tool.name,
38569
+ description: tool.description,
38570
+ params: Object.entries(tool.params).map(([name, p]) => ({
38571
+ name,
38572
+ type: p.type,
38573
+ optional: p.optional,
38574
+ hasDefault: p.hasDefault,
38575
+ constrained: p.constrained,
38576
+ enumValues: p.enumValues,
38577
+ description: p.description
38578
+ }))
38579
+ }));
38580
+ return {
38581
+ schemaVersion: 1,
38582
+ server: "olam",
38583
+ toolCount: tools.length,
38584
+ tools
38585
+ };
38586
+ }
38587
+ function createToolsCatalogResource(deps = {}) {
38588
+ const extract = deps.extract ?? extractToolCatalog;
38589
+ let cachedPayload = null;
38590
+ return {
38591
+ name: "olam-tools",
38592
+ uri: TOOLS_CATALOG_URI,
38593
+ description: "Machine-readable catalog of the Olam MCP server's Tools surface: every tool name, its description, and per-param metadata (type, required/optional, default, enum members, and whether the value space is constrained vs free-form). Read this once to discover which tool params are closed enum sets and which are required, so an autonomous client can build valid tool calls on the first attempt instead of inferring the contract from raw JSON Schema or hitting validation errors.",
38594
+ mimeType: "application/json",
38595
+ read() {
38596
+ if (cachedPayload === null) {
38597
+ cachedPayload = buildToolsCatalogPayload(extract());
38598
+ }
38599
+ return cachedPayload;
38600
+ }
38601
+ };
38602
+ }
38603
+
38604
+ // ../mcp-server/src/server-identity.ts
38605
+ var SERVER_NAME = "olam";
38606
+ var SERVER_VERSION = "0.1.0";
38607
+ var SERVER_INSTRUCTIONS = [
38608
+ "Olam manages isolated development worlds. Use olam_list_worlds to see available worlds.",
38609
+ "Use olam_create_world to provision a new world. Use olam_dispatch to send tasks.",
38610
+ "Use olam_observe to watch a world's reasoning. Use olam_crystallize to save thoughts.",
38611
+ "Always olam_destroy_world when done to clean up resources."
38612
+ ].join("\n");
38613
+
38614
+ // ../mcp-server/src/resources/server-info.ts
38615
+ var SERVER_INFO_URI = "olam://server-info";
38616
+ function buildServerInfoPayload(sources) {
38617
+ const baseEntries = [
38618
+ {
38619
+ name: sources.chunks.name,
38620
+ uri: sources.chunks.uriTemplate,
38621
+ templated: true,
38622
+ mimeType: sources.chunks.mimeType
38623
+ },
38624
+ {
38625
+ name: sources.capabilities.name,
38626
+ uri: sources.capabilities.uri,
38627
+ templated: false,
38628
+ mimeType: sources.capabilities.mimeType
38629
+ },
38630
+ {
38631
+ name: sources.toolsCatalog.name,
38632
+ uri: sources.toolsCatalog.uri,
38633
+ templated: false,
38634
+ mimeType: sources.toolsCatalog.mimeType
38635
+ },
38636
+ {
38637
+ name: SERVER_INFO_NAME,
38638
+ uri: SERVER_INFO_URI,
38639
+ templated: false,
38640
+ mimeType: SERVER_INFO_MIME_TYPE
38641
+ }
38642
+ ];
38643
+ if (sources.runbookManifest) {
38644
+ baseEntries.push({
38645
+ name: sources.runbookManifest.name,
38646
+ uri: sources.runbookManifest.uriTemplate,
38647
+ templated: true,
38648
+ mimeType: sources.runbookManifest.mimeType
38649
+ });
38650
+ }
38651
+ const entries = baseEntries.sort((a, b) => a.name.localeCompare(b.name));
38652
+ return {
38653
+ schemaVersion: 1,
38654
+ name: SERVER_NAME,
38655
+ version: SERVER_VERSION,
38656
+ instructions: SERVER_INSTRUCTIONS,
38657
+ capabilities: { resources: true, tools: true },
38658
+ resources: entries
38659
+ };
38660
+ }
38661
+ var SERVER_INFO_NAME = "olam-server-info";
38662
+ var SERVER_INFO_MIME_TYPE = "application/json";
38663
+ function createServerInfoResource() {
38664
+ return {
38665
+ name: SERVER_INFO_NAME,
38666
+ uri: SERVER_INFO_URI,
38667
+ description: "Machine-readable identity of the Olam MCP server: its name, version, the operator instructions advertised in the initialize handshake (re-readable here mid-session), the MCP capability flags, and a flat index of EVERY registered resource URI (templated and static, including the introspection resources). Read this first to learn what version you are talking to and the complete set of resource URIs you can read next.",
38668
+ mimeType: SERVER_INFO_MIME_TYPE,
38669
+ read(sources) {
38670
+ return buildServerInfoPayload(sources);
38671
+ }
38672
+ };
38673
+ }
38674
+
38675
+ // ../mcp-server/src/resources/runbook-manifest.ts
38676
+ init_global_config();
38677
+ var RUNBOOK_MANIFEST_URI_TEMPLATE = "olam://runbooks/{name}";
38678
+ var RUNBOOK_MANIFEST_NAME = "olam-runbook-manifest";
38679
+ var RUNBOOK_MANIFEST_MIME_TYPE = "application/json";
38680
+ function parseRunbookManifestUri(uri) {
38681
+ let parsed;
38682
+ try {
38683
+ parsed = new URL(uri);
38684
+ } catch {
38685
+ return null;
38686
+ }
38687
+ if (parsed.protocol !== "olam:") return null;
38688
+ if (parsed.hostname !== "runbooks") return null;
38689
+ const name = parsed.pathname.slice(1);
38690
+ if (!name || name.includes("/")) return null;
38691
+ return decodeURIComponent(name);
38692
+ }
38693
+ function createRunbookManifestResource(deps = {}) {
38694
+ const listFn = deps.listFn ?? listRunbooks;
38695
+ const getFn = deps.getFn ?? ((name) => {
38696
+ return getRunbook(name);
38697
+ });
38698
+ return {
38699
+ name: RUNBOOK_MANIFEST_NAME,
38700
+ uriTemplate: RUNBOOK_MANIFEST_URI_TEMPLATE,
38701
+ description: "Machine-readable manifest of a registered Olam runbook: its repos, portMap, seeds, env, and description. URI: olam://runbooks/{name}. Substitute {name} with an exact runbook name (use olam_runbook_list or the resources/list snapshot to discover names). Read this to inspect a runbook before applying it \u2014 equivalent to olam_runbook_show but accessible as a Resource for context-injection workflows.",
38702
+ mimeType: RUNBOOK_MANIFEST_MIME_TYPE,
38703
+ read(uri) {
38704
+ const name = parseRunbookManifestUri(uri);
38705
+ if (!name) {
38706
+ return {
38707
+ ok: false,
38708
+ code: "invalid_uri",
38709
+ message: `Invalid runbook manifest URI "${uri}". Expected format: olam://runbooks/<name> (e.g. olam://runbooks/node-devbox).`
38710
+ };
38711
+ }
38712
+ try {
38713
+ const manifest = getFn(name);
38714
+ return { ok: true, uri, manifest };
38715
+ } catch (err) {
38716
+ const detail = err instanceof Error ? err.message : String(err);
38717
+ return {
38718
+ ok: false,
38719
+ code: "runbook_not_found",
38720
+ message: `Runbook "${name}" not found: ${detail}`
38721
+ };
38722
+ }
38723
+ },
38724
+ list() {
38725
+ try {
38726
+ return listFn().map((r) => r.name);
38727
+ } catch {
38728
+ return [];
38729
+ }
38730
+ }
38731
+ };
38732
+ }
38733
+
38205
38734
  // ../mcp-server/src/resources/index.ts
38206
38735
  var JSON_RPC_CODE_FOR = {
38207
38736
  invalid_uri: ErrorCode.InvalidParams,
@@ -38212,6 +38741,10 @@ var JSON_RPC_CODE_FOR = {
38212
38741
  };
38213
38742
  function registerAllResources(server, deps = {}) {
38214
38743
  const chunks = deps.chunks ?? createChunksResource();
38744
+ const capabilities = deps.capabilities ?? createCapabilitiesResource();
38745
+ const toolsCatalog = deps.toolsCatalog ?? createToolsCatalogResource();
38746
+ const serverInfo = deps.serverInfo ?? createServerInfoResource();
38747
+ const runbookManifest = deps.runbookManifest ?? createRunbookManifestResource();
38215
38748
  server.registerResource(
38216
38749
  chunks.name,
38217
38750
  new ResourceTemplate(chunks.uriTemplate, {
@@ -38256,21 +38789,587 @@ function registerAllResources(server, deps = {}) {
38256
38789
  };
38257
38790
  }
38258
38791
  );
38792
+ server.registerResource(
38793
+ capabilities.name,
38794
+ capabilities.uri,
38795
+ {
38796
+ description: capabilities.description,
38797
+ mimeType: capabilities.mimeType
38798
+ },
38799
+ async (uri) => {
38800
+ const payload = capabilities.read(chunks);
38801
+ return {
38802
+ contents: [
38803
+ {
38804
+ uri: uri.toString(),
38805
+ mimeType: capabilities.mimeType,
38806
+ text: JSON.stringify(payload, null, 2)
38807
+ }
38808
+ ]
38809
+ };
38810
+ }
38811
+ );
38812
+ server.registerResource(
38813
+ toolsCatalog.name,
38814
+ toolsCatalog.uri,
38815
+ {
38816
+ description: toolsCatalog.description,
38817
+ mimeType: toolsCatalog.mimeType
38818
+ },
38819
+ async (uri) => {
38820
+ const payload = toolsCatalog.read();
38821
+ return {
38822
+ contents: [
38823
+ {
38824
+ uri: uri.toString(),
38825
+ mimeType: toolsCatalog.mimeType,
38826
+ text: JSON.stringify(payload, null, 2)
38827
+ }
38828
+ ]
38829
+ };
38830
+ }
38831
+ );
38832
+ server.registerResource(
38833
+ serverInfo.name,
38834
+ serverInfo.uri,
38835
+ {
38836
+ description: serverInfo.description,
38837
+ mimeType: serverInfo.mimeType
38838
+ },
38839
+ async (uri) => {
38840
+ const payload = serverInfo.read({
38841
+ chunks,
38842
+ capabilities,
38843
+ toolsCatalog,
38844
+ runbookManifest
38845
+ });
38846
+ return {
38847
+ contents: [
38848
+ {
38849
+ uri: uri.toString(),
38850
+ mimeType: serverInfo.mimeType,
38851
+ text: JSON.stringify(payload, null, 2)
38852
+ }
38853
+ ]
38854
+ };
38855
+ }
38856
+ );
38857
+ server.registerResource(
38858
+ runbookManifest.name,
38859
+ new ResourceTemplate(runbookManifest.uriTemplate, {
38860
+ list: void 0
38861
+ }),
38862
+ {
38863
+ description: runbookManifest.description,
38864
+ mimeType: runbookManifest.mimeType
38865
+ },
38866
+ async (uri) => {
38867
+ const result = runbookManifest.read(uri.toString());
38868
+ if (!result.ok) {
38869
+ const rpcCode = result.code === "invalid_uri" ? ErrorCode.InvalidParams : ErrorCode.InternalError;
38870
+ throw new McpError(rpcCode, result.message, { code: result.code });
38871
+ }
38872
+ return {
38873
+ contents: [
38874
+ {
38875
+ uri: result.uri,
38876
+ mimeType: RUNBOOK_MANIFEST_MIME_TYPE,
38877
+ text: JSON.stringify(result.manifest, null, 2)
38878
+ }
38879
+ ]
38880
+ };
38881
+ }
38882
+ );
38259
38883
  logger.info("Olam MCP resources registered", {
38260
- resources: [chunks.name],
38261
- uriTemplate: chunks.uriTemplate
38884
+ resources: [
38885
+ chunks.name,
38886
+ capabilities.name,
38887
+ toolsCatalog.name,
38888
+ serverInfo.name,
38889
+ runbookManifest.name
38890
+ ],
38891
+ uriTemplate: chunks.uriTemplate,
38892
+ runbookManifestUriTemplate: runbookManifest.uriTemplate,
38893
+ capabilitiesUri: capabilities.uri,
38894
+ toolsCatalogUri: toolsCatalog.uri,
38895
+ serverInfoUri: serverInfo.uri
38896
+ });
38897
+ }
38898
+
38899
+ // ../mcp-server/src/prompts/index.ts
38900
+ init_v3();
38901
+
38902
+ // ../mcp-server/src/prompts/workflows.ts
38903
+ var INSPECT_REASONING_PROMPT_NAME = "olam-inspect-reasoning";
38904
+ var DISPATCH_FROM_RUNBOOK_PROMPT_NAME = "olam-dispatch-from-runbook";
38905
+ var DESTROY_WORLD_PROMPT_NAME = "olam-destroy-world";
38906
+ var ROTATE_AUTH_PROMPT_NAME = "olam-rotate-auth";
38907
+ var SCAFFOLD_RUNBOOK_PROMPT_NAME = "olam-scaffold-runbook";
38908
+ var TRIAGE_FAILING_WORLD_PROMPT_NAME = "olam-triage-failing-world";
38909
+ var CREATE_WORLD_FOR_LINEAR_ISSUE_PROMPT_NAME = "olam-create-world-for-linear-issue";
38910
+ var REVIEW_PR_GATE_PROMPT_NAME = "olam-review-pr-gate";
38911
+ var PROMOTE_TO_LANE_PROMPT_NAME = "olam-promote-to-lane";
38912
+ function buildInspectReasoningPrompt(args) {
38913
+ const { worldId, sessionId } = args;
38914
+ const chunksUri = sessionId ? `olam://worlds/${worldId}/chunks?sessionId=${sessionId}` : `olam://worlds/${worldId}/chunks?sessionId=<SESSION_ID>`;
38915
+ const sessionGuidance = sessionId ? `The session is "${sessionId}", so read \`${chunksUri}\` directly.` : `No session was supplied. The chunks Resource REQUIRES a sessionId at read time (the Electric shape proxy enforces per-(world,session) scope and returns the \`missing_session_id\` error code otherwise). Discover the active session via olam_status or olam_observe first, then read \`${chunksUri}\` with the real id.`;
38916
+ const text = [
38917
+ `Inspect the reasoning stream of Olam world "${worldId}".`,
38918
+ "",
38919
+ "Follow this sequence:",
38920
+ `1. Confirm the world exists and is live: call olam_status with worldId="${worldId}" (use olam_list if you need to discover worldIds \u2014 do not guess).`,
38921
+ `2. Read the substrate-grade chunk stream via the MCP Resource \`olam://worlds/${worldId}/chunks{?sessionId}\`. ${sessionGuidance}`,
38922
+ "3. For an incremental live tail rather than a snapshot, call olam_observe with the same worldId; pass sinceChunkId as a cursor to page forward without re-reading earlier chunks.",
38923
+ "",
38924
+ "Then summarise what the world is currently reasoning about, any blockers it has surfaced, and whether it appears to be making progress."
38925
+ ].join("\n");
38926
+ return {
38927
+ description: `Inspect the reasoning stream of Olam world "${worldId}".`,
38928
+ messages: [{ role: "user", content: { type: "text", text } }]
38929
+ };
38930
+ }
38931
+ function buildDispatchFromRunbookPrompt(args) {
38932
+ const { worldId, runbookName, task } = args;
38933
+ const text = [
38934
+ `Dispatch a task into Olam world "${worldId}" after preparing it with the "${runbookName}" runbook.`,
38935
+ "",
38936
+ "Follow this sequence:",
38937
+ `1. Inspect the runbook so you know what it sets up: call olam_runbook_show with name="${runbookName}". If it does not exist, list options with olam_runbook_list and stop \u2014 do not invent a runbook.`,
38938
+ `2. Confirm the target world is live: olam_status with worldId="${worldId}" (discover worldIds with olam_list if needed).`,
38939
+ `3. Apply the runbook to the world: olam_runbook_apply with name="${runbookName}" and worldId="${worldId}".`,
38940
+ `4. Dispatch the task: olam_dispatch with worldId="${worldId}" and prompt="${task}".`,
38941
+ "5. Confirm the agent picked the task up: olam_observe with the same worldId and report the first few reasoning chunks.",
38942
+ "",
38943
+ "If any step fails, stop and report which step failed and the error \u2014 do not proceed to a later step on a failed precondition."
38944
+ ].join("\n");
38945
+ return {
38946
+ description: `Prepare world "${worldId}" with runbook "${runbookName}", then dispatch a task.`,
38947
+ messages: [{ role: "user", content: { type: "text", text } }]
38948
+ };
38949
+ }
38950
+ function buildDestroyWorldPrompt(args) {
38951
+ const { worldName } = args;
38952
+ const text = [
38953
+ `Safely destroy the Olam world whose human-readable name matches "${worldName}".`,
38954
+ "",
38955
+ "Follow this sequence:",
38956
+ `1. Discover the worldId: call olam_list and find the entry whose name contains "${worldName}". If multiple worlds match, list them and ask which to destroy \u2014 do not guess.`,
38957
+ `2. Confirm current state: call olam_status with the matched worldId. If the world is still "running" with active work (thoughtCount recently incremented or status is "dispatching"), warn that it is mid-task before proceeding.`,
38958
+ `3. Destroy the world: call olam_destroy with the resolved worldId.`,
38959
+ `4. Confirm destruction: report the world's name and id, and note that all its resources have been cleaned up.`,
38960
+ "",
38961
+ "If no world matches the name, report that clearly \u2014 do not fabricate a worldId.",
38962
+ "If the destroy call fails, report the error verbatim and stop."
38963
+ ].join("\n");
38964
+ return {
38965
+ description: `Discover and safely destroy the Olam world named "${worldName}".`,
38966
+ messages: [{ role: "user", content: { type: "text", text } }]
38967
+ };
38968
+ }
38969
+ function buildRotateAuthPrompt(args) {
38970
+ const { accountLabel, provider } = args;
38971
+ const labelText = accountLabel ?? "a new account";
38972
+ const labelArg = accountLabel ?? "<label>";
38973
+ const providerText = provider ?? "claude";
38974
+ const text = [
38975
+ `Rotate (or add) a Claude credential for ${labelText} using the "${providerText}" provider.`,
38976
+ "",
38977
+ "Follow this sequence:",
38978
+ "1. Check current auth state: call olam_auth_status.",
38979
+ ` - If the container is not running, continue to step 2.`,
38980
+ ` - If an account labelled "${labelArg}" already shows "valid", confirm with the operator before replacing it.`,
38981
+ "2. Ensure the auth container is up: call olam_auth_up. It is idempotent \u2014 safe to call even if already running.",
38982
+ `3. Start the PKCE login: call olam_auth_login with label="${labelArg}" and provider="${providerText}".`,
38983
+ ` The response contains a loginUrl and a state token. IMPORTANT: surface the loginUrl to the operator and capture the state token \u2014 you will need it in the next step.`,
38984
+ "4. Wait for the operator to complete the browser flow and provide the authorization code.",
38985
+ `5. Complete the exchange: call olam_auth_complete with the state token from step 3 and the code the operator just provided.`,
38986
+ `6. Confirm: call olam_auth_status again and report the new account's flag (should be "valid") and expiry.`,
38987
+ "",
38988
+ "If any step fails, report the error verbatim and stop \u2014 do not proceed with a missing or invalid state token."
38989
+ ].join("\n");
38990
+ return {
38991
+ description: `Rotate or add a Claude credential for ${labelText}.`,
38992
+ messages: [{ role: "user", content: { type: "text", text } }]
38993
+ };
38994
+ }
38995
+ function buildScaffoldRunbookPrompt(args) {
38996
+ const { runbookName, repos, description, templateWorldId } = args;
38997
+ const repoList = repos.join(", ");
38998
+ const descText = description ?? `Runbook for ${repoList}`;
38999
+ const templateClause = templateWorldId ? `Before calling olam_runbook_add, inspect the live world "${templateWorldId}" with olam_status to borrow its portOffset as a portMap baseline: use portOffset as the base and assign service ports relative to it (e.g. portOffset + 0 for the primary service, + 1 for the secondary). ` : `If you have a reference world whose port layout matches what this runbook needs, consult its portOffset first. Otherwise omit portMap and rely on Olam's automatic assignment. `;
39000
+ const text = [
39001
+ `Scaffold a new Olam runbook named "${runbookName}" covering repos: ${repoList}.`,
39002
+ "",
39003
+ "Follow this sequence:",
39004
+ `1. Check for a name collision: call olam_runbook_list. If "${runbookName}" already exists, stop and report it \u2014 do not overwrite without explicit operator confirmation.`,
39005
+ `2. ${templateClause}`,
39006
+ `3. Call olam_runbook_add with this payload shape:`,
39007
+ ` - name: "${runbookName}"`,
39008
+ ` - repos: [${repos.map((r) => `"${r}"`).join(", ")}]`,
39009
+ ` - description: "${descText}"`,
39010
+ ` - portMap: (from step 2, or omit for auto-assignment)`,
39011
+ ` - seeds: [] (add startup commands if the operator supplied them)`,
39012
+ ` - env: {} (add env vars if the operator supplied them)`,
39013
+ `4. Confirm: call olam_runbook_show with name="${runbookName}" and display the stored runbook so the operator can verify it.`,
39014
+ "",
39015
+ "If olam_runbook_add fails with a validation error, surface the error verbatim \u2014 do not retry with a guessed payload."
39016
+ ].join("\n");
39017
+ return {
39018
+ description: `Scaffold a new runbook named "${runbookName}" for repos: ${repoList}.`,
39019
+ messages: [{ role: "user", content: { type: "text", text } }]
39020
+ };
39021
+ }
39022
+ function buildTriageFailingWorldPrompt(args) {
39023
+ const { worldId, sessionId, expectedBehaviour } = args;
39024
+ const chunksUri = sessionId ? `olam://worlds/${worldId}/chunks?sessionId=${sessionId}` : `olam://worlds/${worldId}/chunks?sessionId=<SESSION_ID>`;
39025
+ const chunksGuidance = sessionId ? `Read \`${chunksUri}\` for the reasoning snapshot.` : `The chunks Resource requires a sessionId \u2014 discover the active session from olam_status or olam_observe output, then read \`${chunksUri}\` with the real id to get the full reasoning snapshot.`;
39026
+ const expectationText = expectedBehaviour ? `
39027
+ The operator described the expected behaviour as: "${expectedBehaviour}". Use this to anchor your diagnosis \u2014 look for divergence from that description.` : "";
39028
+ const text = [
39029
+ `Triage the failing or stuck Olam world "${worldId}" and determine whether it can be recovered.${expectationText}`,
39030
+ "",
39031
+ "Follow this sequence:",
39032
+ `1. Confirm the world exists: call olam_status with worldId="${worldId}" (use olam_list if you need to discover worldIds \u2014 do not guess). Note the current status, thoughtCount, and any error field.`,
39033
+ `2. Read the latest reasoning to understand the failure: ${chunksGuidance} Alternatively tail live with olam_observe. Look for the last meaningful reasoning step and any error or block the agent reported.`,
39034
+ `3. Diagnose:`,
39035
+ ` a. If the agent is blocked by a missing tool or credential, the world cannot self-recover \u2014 crystallise its work (olam_crystallize with worldId="${worldId}") and report the block to the operator.`,
39036
+ ` b. If the agent looped or drifted from the task, form a corrective dispatch prompt that names the deviation and the expected outcome, then call olam_dispatch with worldId="${worldId}" and the corrective prompt.`,
39037
+ ` c. If the agent appears to have completed its task but did not report success, call olam_status again and report the final thoughtCount and any completion signal.`,
39038
+ ` d. If the world is in a terminal error state with no recoverable path, call olam_destroy with worldId="${worldId}" and report what was lost.`,
39039
+ "",
39040
+ "Report which branch (a/b/c/d) was taken, why, and the outcome. Do not retry with a vague re-dispatch if you cannot identify the specific failure cause \u2014 crystallise and report instead."
39041
+ ].join("\n");
39042
+ return {
39043
+ description: `Triage and recover the failing Olam world "${worldId}".`,
39044
+ messages: [{ role: "user", content: { type: "text", text } }]
39045
+ };
39046
+ }
39047
+ function buildCreateWorldForLinearIssuePrompt(args) {
39048
+ const { linearTicketId, runbookName, task } = args;
39049
+ const runbookStep = runbookName ? [
39050
+ `1. Inspect the runbook so you know what it sets up: call olam_runbook_show with name="${runbookName}". If it does not exist, list options with olam_runbook_list \u2014 do not invent a runbook name.`,
39051
+ `2. Create the world with the Linear ticket wired in: call olam_create with linearTicketId="${linearTicketId}" and runbookName="${runbookName}". ${task ? `Set task="${task}".` : `Omit task \u2014 the ticket drives context.`} Do not guess the worldId; it is returned by olam_create.`
39052
+ ] : [
39053
+ `1. Create the world with the Linear ticket wired in: call olam_create with linearTicketId="${linearTicketId}". ${task ? `Set task="${task}".` : `Omit task \u2014 the ticket drives context.`} Do not guess the worldId; it is returned by olam_create.`
39054
+ ];
39055
+ const observeStep = runbookName ? `3. Confirm the agent picked up the ticket: call olam_observe with the worldId returned in step 2 and report the first few reasoning chunks.` : `2. Confirm the agent picked up the ticket: call olam_observe with the worldId returned in step 1 and report the first few reasoning chunks.`;
39056
+ const text = [
39057
+ `Create an Olam world pre-wired to Linear issue "${linearTicketId}"${runbookName ? ` using runbook "${runbookName}"` : ""}.`,
39058
+ "",
39059
+ "Follow this sequence:",
39060
+ ...runbookStep,
39061
+ observeStep,
39062
+ "",
39063
+ "The linearTicketId param passes the ticket's title, description, and metadata into the world's context automatically \u2014 this is the correct integration point for Linear-agent flows. Do not manually copy ticket text into a task string.",
39064
+ "If olam_create fails with a context or auth error, stop and report the error verbatim \u2014 do not retry with a guessed worldId."
39065
+ ].join("\n");
39066
+ return {
39067
+ description: `Create a world for Linear issue "${linearTicketId}"${runbookName ? ` with runbook "${runbookName}"` : ""}.`,
39068
+ messages: [{ role: "user", content: { type: "text", text } }]
39069
+ };
39070
+ }
39071
+ function buildReviewPrGatePrompt(args) {
39072
+ const { gateId, worldName, by } = args;
39073
+ const byClause = by ?? "mcp";
39074
+ const discoveryClause = gateId ? `The gate id is "${gateId}", so you can call olam_pr_show with id="${gateId}" directly.` : worldName ? `No gate id was given. List open gates via olam_pr_list and find the gate whose world name contains "${worldName}". If multiple gates match, list them and ask the operator which to act on \u2014 do not guess.` : `No gate id or world name was given. Call olam_pr_list to see all open gates across every running world. Pick the gate the operator intends or list them and ask \u2014 do not fabricate an id.`;
39075
+ const text = [
39076
+ `Review a PR gate and decide whether to approve or block it.`,
39077
+ "",
39078
+ "Follow this sequence:",
39079
+ `1. Discover the gate: ${discoveryClause}`,
39080
+ `2. Inspect the gate in detail: call olam_pr_show with the resolved gate id. Read the diff-stat and commit log it returns carefully. Do NOT approve or reject until you have read this output.`,
39081
+ `3. Form a decision based on what the diff-stat and commit log show:`,
39082
+ ` a. If the changes look correct and complete for their stated goal, call olam_pr_approve with id=<gate-id> and by="${byClause}". Add a reason arg summarising what you verified.`,
39083
+ ` b. If the changes have issues (missing tests, logic errors, wrong files changed, unrelated modifications), call olam_pr_reject with id=<gate-id>, by="${byClause}", and a reason arg that names the specific problem(s). The reason arg is REQUIRED by olam_pr_reject \u2014 do not omit it.`,
39084
+ `4. Report the gate id, the world name, your decision, and a one-sentence summary of the reason.`,
39085
+ "",
39086
+ "Do not approve a gate you have not inspected. The diff-stat from step 2 is the minimum evidence required for a non-trivial approve.",
39087
+ "If the gate is already in a decided state (approved or blocked), report that and stop \u2014 do not re-decide a closed gate."
39088
+ ].join("\n");
39089
+ return {
39090
+ description: gateId ? `Review PR gate "${gateId}" and approve or block it.` : worldName ? `Review the open PR gate for world "${worldName}" and approve or block it.` : "Review open PR gates and decide approve or block.",
39091
+ messages: [{ role: "user", content: { type: "text", text } }]
39092
+ };
39093
+ }
39094
+ function buildPromoteToLanePrompt(args) {
39095
+ const { worldId, task, laneName, existingLaneId } = args;
39096
+ const laneLabel = laneName ?? "the experiment";
39097
+ const createBlock = existingLaneId ? [
39098
+ `Lane "${existingLaneId}" was supplied \u2014 skip creation and go to step 3.`
39099
+ ] : [
39100
+ `2. Check for a lane name collision: call olam_list_lanes with worldId="${worldId}". If a lane named "${laneLabel}" already exists, stop and ask the operator whether to reuse it or pick a different name.`,
39101
+ `3. Create the lane: call olam_create_lane with worldId="${worldId}"` + (laneName ? ` and name="${laneName}".` : ".") + ` The returned laneId is required for the next step \u2014 capture it.`
39102
+ ];
39103
+ const laneIdRef = existingLaneId ? `"${existingLaneId}"` : "the laneId from step 3";
39104
+ const dispatchStep = existingLaneId ? "2" : "4";
39105
+ const observeStep = existingLaneId ? "3" : "5";
39106
+ const text = [
39107
+ `Promote work from Olam world "${worldId}" to a lane for parallel experimentation.`,
39108
+ "",
39109
+ "Follow this sequence:",
39110
+ `1. Confirm the source world is running: call olam_status with worldId="${worldId}" (use olam_list if you need to discover worldIds \u2014 do not guess). If the world is not in "running" status, stop and report it \u2014 lane creation requires a live running world.`,
39111
+ ...createBlock,
39112
+ `${dispatchStep}. Dispatch the experiment into the LANE (not the world): call olam_dispatch_lane with worldId="${worldId}", laneId=${laneIdRef}, and prompt="${task}". IMPORTANT: use olam_dispatch_lane, not olam_dispatch \u2014 they are different tools. olam_dispatch sends work to the world itself; olam_dispatch_lane sends it to an isolated lane branch.`,
39113
+ `${observeStep}. Confirm the lane picked up the task: call olam_observe with worldId="${worldId}" and laneId=${laneIdRef}. Report the first few reasoning chunks from the lane.`,
39114
+ "",
39115
+ "If any step fails, stop and report which step failed and the error. Do not proceed to a later step on a failed precondition.",
39116
+ "When the experiment is complete, the operator can call olam_merge_lane to fold the lane's work back into the world, or olam_destroy_lane to discard it."
39117
+ ].join("\n");
39118
+ return {
39119
+ description: existingLaneId ? `Dispatch task into existing lane "${existingLaneId}" of world "${worldId}".` : `Create a lane from world "${worldId}" and dispatch: ${task.slice(0, 60)}${task.length > 60 ? "\u2026" : ""}`,
39120
+ messages: [{ role: "user", content: { type: "text", text } }]
39121
+ };
39122
+ }
39123
+
39124
+ // ../mcp-server/src/prompts/index.ts
39125
+ function registerAllPrompts(server) {
39126
+ server.registerPrompt(
39127
+ INSPECT_REASONING_PROMPT_NAME,
39128
+ {
39129
+ title: "Inspect a world's reasoning stream",
39130
+ description: "Guided workflow to inspect what an Olam world is currently reasoning about: resolve the world, read its chunk substrate via the MCP Resource (scoped to a session), and tail it live with olam_observe.",
39131
+ argsSchema: {
39132
+ worldId: external_exports.string().describe(
39133
+ 'Slug-style world identifier, e.g. "amber-fox-42". Call olam_list first to discover live worldIds \u2014 do not guess.'
39134
+ ),
39135
+ sessionId: external_exports.string().optional().describe(
39136
+ "Optional planning-session id. The chunks Resource requires it at read time; if omitted the prompt instructs the agent to discover it first."
39137
+ )
39138
+ }
39139
+ },
39140
+ (args) => {
39141
+ const result = buildInspectReasoningPrompt({
39142
+ worldId: args.worldId,
39143
+ sessionId: args.sessionId
39144
+ });
39145
+ return {
39146
+ description: result.description,
39147
+ messages: result.messages
39148
+ };
39149
+ }
39150
+ );
39151
+ server.registerPrompt(
39152
+ DISPATCH_FROM_RUNBOOK_PROMPT_NAME,
39153
+ {
39154
+ title: "Dispatch a task from a runbook",
39155
+ description: "Guided workflow to prepare an Olam world with a named runbook and then dispatch a task into it: inspect the runbook, apply it to the world, dispatch the task, and confirm pickup via olam_observe.",
39156
+ argsSchema: {
39157
+ worldId: external_exports.string().describe(
39158
+ 'Slug-style world identifier, e.g. "amber-fox-42". Call olam_list first to discover live worldIds \u2014 do not guess.'
39159
+ ),
39160
+ runbookName: external_exports.string().describe(
39161
+ "Name of a registered runbook to apply before dispatch. Use olam_runbook_list to discover available runbooks."
39162
+ ),
39163
+ task: external_exports.string().describe(
39164
+ "The task prompt to dispatch into the world once the runbook is applied."
39165
+ )
39166
+ }
39167
+ },
39168
+ (args) => {
39169
+ const result = buildDispatchFromRunbookPrompt({
39170
+ worldId: args.worldId,
39171
+ runbookName: args.runbookName,
39172
+ task: args.task
39173
+ });
39174
+ return {
39175
+ description: result.description,
39176
+ messages: result.messages
39177
+ };
39178
+ }
39179
+ );
39180
+ server.registerPrompt(
39181
+ DESTROY_WORLD_PROMPT_NAME,
39182
+ {
39183
+ title: "Destroy a world by name",
39184
+ description: "Guided workflow to safely destroy an Olam world: discover the worldId from the human-readable name via olam_list, confirm it is idle via olam_status, then call olam_destroy. Guards against destroying the wrong world when multiple worlds have similar names.",
39185
+ argsSchema: {
39186
+ worldName: external_exports.string().describe(
39187
+ 'Human-readable world name or partial name to search for, e.g. "feature/auth-refactor". The prompt discovers the worldId for you via olam_list \u2014 do not guess the slug id.'
39188
+ )
39189
+ }
39190
+ },
39191
+ (args) => {
39192
+ const result = buildDestroyWorldPrompt({ worldName: args.worldName });
39193
+ return { description: result.description, messages: result.messages };
39194
+ }
39195
+ );
39196
+ server.registerPrompt(
39197
+ ROTATE_AUTH_PROMPT_NAME,
39198
+ {
39199
+ title: "Rotate a Claude credential",
39200
+ description: "Guided workflow to rotate or add a Claude credential: check auth container status, start it if needed, initiate PKCE login, surface the browser URL to the operator, then complete the exchange. Encodes the state-token handoff between olam_auth_login and olam_auth_complete so the agent does not call complete with a missing or stale token.",
39201
+ argsSchema: {
39202
+ accountLabel: external_exports.string().optional().describe(
39203
+ 'Label for the credential, e.g. "work" or "personal". If omitted the prompt uses a placeholder and asks the operator to supply one.'
39204
+ ),
39205
+ provider: external_exports.string().optional().describe(
39206
+ 'OAuth provider \u2014 defaults to "claude". Pass a different value only when the operator has a non-standard provider configured.'
39207
+ )
39208
+ }
39209
+ },
39210
+ (args) => {
39211
+ const result = buildRotateAuthPrompt({
39212
+ accountLabel: args.accountLabel,
39213
+ provider: args.provider
39214
+ });
39215
+ return { description: result.description, messages: result.messages };
39216
+ }
39217
+ );
39218
+ server.registerPrompt(
39219
+ SCAFFOLD_RUNBOOK_PROMPT_NAME,
39220
+ {
39221
+ title: "Scaffold a new runbook",
39222
+ description: "Guided workflow to scaffold a new Olam runbook: check for name collisions via olam_runbook_list, optionally derive a portMap from a live world via olam_status, then call olam_runbook_add with a well- formed payload and confirm the result via olam_runbook_show. Prevents the common mistake of calling add with a malformed portMap or a duplicate name.",
39223
+ argsSchema: {
39224
+ runbookName: external_exports.string().describe(
39225
+ 'Name for the new runbook, e.g. "node-devbox". Must be unique \u2014 this prompt checks for collisions first.'
39226
+ ),
39227
+ repos: external_exports.string().describe(
39228
+ 'Comma-separated repo slugs to include, e.g. "my-org/my-api,my-org/my-frontend". At least one required. MCP prompt arguments are string-valued; split on commas.'
39229
+ ),
39230
+ description: external_exports.string().optional().describe(
39231
+ 'Human-readable description stored with the runbook. Defaults to "Runbook for <repos>" when omitted.'
39232
+ ),
39233
+ templateWorldId: external_exports.string().optional().describe(
39234
+ "Optional worldId of a live world whose portOffset to use as a portMap baseline. When supplied the prompt calls olam_status on that world before building the add payload."
39235
+ )
39236
+ }
39237
+ },
39238
+ (args) => {
39239
+ const repos = args.repos.split(",").map((r) => r.trim()).filter(Boolean);
39240
+ const result = buildScaffoldRunbookPrompt({
39241
+ runbookName: args.runbookName,
39242
+ repos,
39243
+ description: args.description,
39244
+ templateWorldId: args.templateWorldId
39245
+ });
39246
+ return { description: result.description, messages: result.messages };
39247
+ }
39248
+ );
39249
+ server.registerPrompt(
39250
+ TRIAGE_FAILING_WORLD_PROMPT_NAME,
39251
+ {
39252
+ title: "Triage a failing or stuck world",
39253
+ description: "Guided workflow to diagnose and recover a world that is stuck or has failed mid-task: confirm the world exists, read its latest reasoning via the chunks Resource or olam_observe to identify the failure cause, then choose the right recovery action \u2014 corrective re-dispatch, crystallise, or destroy. Prevents vague re-dispatches that loop.",
39254
+ argsSchema: {
39255
+ worldId: external_exports.string().describe(
39256
+ 'Slug-style world identifier, e.g. "amber-fox-42". Call olam_list first to discover live worldIds \u2014 do not guess.'
39257
+ ),
39258
+ sessionId: external_exports.string().optional().describe(
39259
+ "Optional planning-session id. Supplying it lets the prompt build a ready-to-read chunks URI directly, avoiding a missing_session_id round-trip."
39260
+ ),
39261
+ expectedBehaviour: external_exports.string().optional().describe(
39262
+ "Optional description of what the world was supposed to do. Anchors the diagnosis by naming the deviation from expected behaviour."
39263
+ )
39264
+ }
39265
+ },
39266
+ (args) => {
39267
+ const result = buildTriageFailingWorldPrompt({
39268
+ worldId: args.worldId,
39269
+ sessionId: args.sessionId,
39270
+ expectedBehaviour: args.expectedBehaviour
39271
+ });
39272
+ return { description: result.description, messages: result.messages };
39273
+ }
39274
+ );
39275
+ server.registerPrompt(
39276
+ CREATE_WORLD_FOR_LINEAR_ISSUE_PROMPT_NAME,
39277
+ {
39278
+ title: "Create a world for a Linear issue",
39279
+ description: "Guided workflow to create an Olam world pre-wired to a Linear ticket: optionally inspect a named runbook, call olam_create with linearTicketId so the world inherits the ticket's title and description automatically, then confirm pickup via olam_observe. The correct integration point for Linear-agent flows \u2014 prevents manually threading ticket text into the task string.",
39280
+ argsSchema: {
39281
+ linearTicketId: external_exports.string().describe(
39282
+ `Linear issue identifier, e.g. "ENG-1234". Passed directly to olam_create as linearTicketId so the world's context includes the ticket's title and description.`
39283
+ ),
39284
+ runbookName: external_exports.string().optional().describe(
39285
+ "Optional name of a registered runbook to apply when creating the world. Use olam_runbook_list to discover available runbooks."
39286
+ ),
39287
+ task: external_exports.string().optional().describe(
39288
+ "Optional initial task prompt. When omitted the ticket's own description drives the world's first dispatch."
39289
+ )
39290
+ }
39291
+ },
39292
+ (args) => {
39293
+ const result = buildCreateWorldForLinearIssuePrompt({
39294
+ linearTicketId: args.linearTicketId,
39295
+ runbookName: args.runbookName,
39296
+ task: args.task
39297
+ });
39298
+ return { description: result.description, messages: result.messages };
39299
+ }
39300
+ );
39301
+ server.registerPrompt(
39302
+ REVIEW_PR_GATE_PROMPT_NAME,
39303
+ {
39304
+ title: "Review a PR gate and decide approve or block",
39305
+ description: "Guided workflow to review a PR gate opened by a running world: discover the gate via olam_pr_list (or accept a known gateId), inspect the diff-stat and commit log via olam_pr_show BEFORE deciding, then call olam_pr_approve or olam_pr_reject with a reason. Encodes the inspect-first safety contract and surfaces that olam_pr_reject requires a reason arg.",
39306
+ argsSchema: {
39307
+ gateId: external_exports.string().optional().describe(
39308
+ 'Short or full PR gate id, e.g. "a1b2c3d4". When supplied the prompt skips the discovery step and calls olam_pr_show directly. Omit to have the prompt discover open gates via olam_pr_list.'
39309
+ ),
39310
+ worldName: external_exports.string().optional().describe(
39311
+ 'Human-readable world name or partial name to filter gates by, e.g. "feature/auth-refactor". Used when gateId is unknown but you know which world opened the gate.'
39312
+ ),
39313
+ by: external_exports.string().optional().describe(
39314
+ 'Deciding identity recorded in the gate audit trail, e.g. "codex" or "human:ernest". Defaults to "mcp". Use a meaningful label so the audit trail shows who (or what automation) decided.'
39315
+ )
39316
+ }
39317
+ },
39318
+ (args) => {
39319
+ const result = buildReviewPrGatePrompt({
39320
+ gateId: args.gateId,
39321
+ worldName: args.worldName,
39322
+ by: args.by
39323
+ });
39324
+ return { description: result.description, messages: result.messages };
39325
+ }
39326
+ );
39327
+ server.registerPrompt(
39328
+ PROMOTE_TO_LANE_PROMPT_NAME,
39329
+ {
39330
+ title: "Promote world work to a lane for parallel experimentation",
39331
+ description: "Guided workflow to create a lane off a running world and dispatch an experiment task into it: confirm the world is running via olam_status, check for lane name collisions via olam_list_lanes, create the lane via olam_create_lane, dispatch into the lane via olam_dispatch_lane (NOT olam_dispatch \u2014 different tool), and confirm pickup via olam_observe. Prevents the common mistake of dispatching to the world instead of the lane.",
39332
+ argsSchema: {
39333
+ worldId: external_exports.string().describe(
39334
+ 'Slug-style world identifier, e.g. "amber-fox-42". Call olam_list first to discover live worldIds \u2014 do not guess.'
39335
+ ),
39336
+ task: external_exports.string().describe(
39337
+ "The experiment task prompt to dispatch into the lane. This is the same prompt you would pass to olam_dispatch_lane."
39338
+ ),
39339
+ laneName: external_exports.string().optional().describe(
39340
+ 'Optional name for the new lane, e.g. "try-new-cache-strategy". When omitted the prompt lets olam assign a name automatically.'
39341
+ ),
39342
+ existingLaneId: external_exports.string().optional().describe(
39343
+ "Optional id of an already-created lane to dispatch into. When supplied the prompt skips the creation steps and goes straight to olam_dispatch_lane."
39344
+ )
39345
+ }
39346
+ },
39347
+ (args) => {
39348
+ const result = buildPromoteToLanePrompt({
39349
+ worldId: args.worldId,
39350
+ task: args.task,
39351
+ laneName: args.laneName,
39352
+ existingLaneId: args.existingLaneId
39353
+ });
39354
+ return { description: result.description, messages: result.messages };
39355
+ }
39356
+ );
39357
+ logger.info("Olam MCP prompts registered", {
39358
+ prompts: [
39359
+ INSPECT_REASONING_PROMPT_NAME,
39360
+ DISPATCH_FROM_RUNBOOK_PROMPT_NAME,
39361
+ DESTROY_WORLD_PROMPT_NAME,
39362
+ ROTATE_AUTH_PROMPT_NAME,
39363
+ SCAFFOLD_RUNBOOK_PROMPT_NAME,
39364
+ TRIAGE_FAILING_WORLD_PROMPT_NAME,
39365
+ CREATE_WORLD_FOR_LINEAR_ISSUE_PROMPT_NAME,
39366
+ REVIEW_PR_GATE_PROMPT_NAME,
39367
+ PROMOTE_TO_LANE_PROMPT_NAME
39368
+ ]
38262
39369
  });
38263
39370
  }
38264
39371
 
38265
39372
  // ../mcp-server/src/server.ts
38266
- var SERVER_NAME = "olam";
38267
- var SERVER_VERSION = "0.1.0";
38268
- var SERVER_INSTRUCTIONS = [
38269
- "Olam manages isolated development worlds. Use olam_list_worlds to see available worlds.",
38270
- "Use olam_create_world to provision a new world. Use olam_dispatch to send tasks.",
38271
- "Use olam_observe to watch a world's reasoning. Use olam_crystallize to save thoughts.",
38272
- "Always olam_destroy_world when done to clean up resources."
38273
- ].join("\n");
38274
39373
  function createServer4(ctx, initError) {
38275
39374
  const server = new McpServer(
38276
39375
  { name: SERVER_NAME, version: SERVER_VERSION },
@@ -38278,6 +39377,7 @@ function createServer4(ctx, initError) {
38278
39377
  );
38279
39378
  registerAllTools(server, ctx, initError);
38280
39379
  registerAllResources(server);
39380
+ registerAllPrompts(server);
38281
39381
  logger.info("Olam MCP server created", {
38282
39382
  name: SERVER_NAME,
38283
39383
  version: SERVER_VERSION,
@@ -42547,23 +43647,53 @@ function deriveWorldDbName(seed, worldId) {
42547
43647
  var CostTracker = class {
42548
43648
  budgetConfig;
42549
43649
  records = [];
43650
+ /** Per-world running total (USD). Updated on every record(). */
43651
+ perWorldCost = /* @__PURE__ */ new Map();
43652
+ /** Running total for the current calendar day (UTC, USD). */
43653
+ dailyAccumulator = 0;
43654
+ /** The YYYY-MM-DD string for the day dailyAccumulator covers. */
43655
+ dailyDate = todayIsoPrefix();
42550
43656
  constructor(budgetConfig) {
42551
43657
  this.budgetConfig = budgetConfig;
42552
43658
  }
42553
43659
  // ── Mutations ────────────────────────────────────────────────────────────
42554
43660
  record(entry) {
42555
43661
  this.records.push(entry);
43662
+ const prev = this.perWorldCost.get(entry.worldId) ?? 0;
43663
+ this.perWorldCost.set(entry.worldId, prev + entry.costUsd);
43664
+ const entryDay = entry.timestamp.slice(0, 10);
43665
+ const today = todayIsoPrefix();
43666
+ if (today !== this.dailyDate) {
43667
+ this.dailyDate = today;
43668
+ this.dailyAccumulator = 0;
43669
+ for (const r of this.records) {
43670
+ if (r.timestamp.startsWith(today)) {
43671
+ this.dailyAccumulator += r.costUsd;
43672
+ }
43673
+ }
43674
+ } else if (entryDay === today) {
43675
+ this.dailyAccumulator += entry.costUsd;
43676
+ }
42556
43677
  }
42557
43678
  // ── Queries ──────────────────────────────────────────────────────────────
42558
43679
  getWorldCost(worldId) {
42559
- return this.records.filter((r) => r.worldId === worldId).reduce((sum, r) => sum + r.costUsd, 0);
43680
+ return this.perWorldCost.get(worldId) ?? 0;
42560
43681
  }
42561
43682
  getWorldRecords(worldId) {
42562
43683
  return this.records.filter((r) => r.worldId === worldId);
42563
43684
  }
42564
43685
  getDailyCost() {
42565
- const todayPrefix = todayIsoPrefix();
42566
- return this.records.filter((r) => r.timestamp.startsWith(todayPrefix)).reduce((sum, r) => sum + r.costUsd, 0);
43686
+ const today = todayIsoPrefix();
43687
+ if (today !== this.dailyDate) {
43688
+ this.dailyDate = today;
43689
+ this.dailyAccumulator = 0;
43690
+ for (const r of this.records) {
43691
+ if (r.timestamp.startsWith(today)) {
43692
+ this.dailyAccumulator += r.costUsd;
43693
+ }
43694
+ }
43695
+ }
43696
+ return this.dailyAccumulator;
42567
43697
  }
42568
43698
  // ── Budget checks ────────────────────────────────────────────────────────
42569
43699
  checkBudget(worldId) {