negotium 0.2.10 → 0.2.12

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 (35) hide show
  1. package/dist/agent-helpers.js +335 -92
  2. package/dist/agent-helpers.js.map +8 -6
  3. package/dist/background-bash.js +2 -2
  4. package/dist/background-bash.js.map +2 -2
  5. package/dist/browser-runtime.js +2 -2
  6. package/dist/browser-runtime.js.map +2 -2
  7. package/dist/{chunk-dcfmsrnb.js → chunk-8asy22vc.js} +2 -2
  8. package/dist/{chunk-dcfmsrnb.js.map → chunk-8asy22vc.js.map} +2 -2
  9. package/dist/hosted-agent.js +3 -3
  10. package/dist/hosted-agent.js.map +3 -3
  11. package/dist/main.js +3 -3
  12. package/dist/main.js.map +3 -3
  13. package/dist/mcp-factories.js +3 -3
  14. package/dist/mcp-factories.js.map +3 -3
  15. package/dist/prompts.js +2 -2
  16. package/dist/prompts.js.map +2 -2
  17. package/dist/query-runtime.js +2 -2
  18. package/dist/query-runtime.js.map +2 -2
  19. package/dist/registry.js +3 -3
  20. package/dist/registry.js.map +2 -2
  21. package/dist/rollout.js +1 -1
  22. package/dist/runtime/src/agents/public-helpers.ts +4 -0
  23. package/dist/runtime/src/platform/config.ts +1 -1
  24. package/dist/runtime/src/version.ts +1 -1
  25. package/dist/runtime-helpers.js +2 -2
  26. package/dist/runtime-helpers.js.map +2 -2
  27. package/dist/types/packages/core/src/agents/mcp-tools/inline-assets.d.ts +24 -0
  28. package/dist/types/packages/core/src/agents/mcp-tools/publish-html.d.ts +18 -0
  29. package/dist/types/packages/core/src/agents/public-helpers.d.ts +1 -0
  30. package/dist/types/packages/core/src/platform/config.d.ts +1 -1
  31. package/dist/types/packages/core/src/version.d.ts +1 -1
  32. package/dist/vault.js +2 -2
  33. package/dist/vault.js.map +2 -2
  34. package/install-browser-rs.mjs +3 -3
  35. package/package.json +1 -1
@@ -331,7 +331,7 @@ function resolveDefaultModel(agent, registryDefaultModel) {
331
331
  function codexAuthFilePath() {
332
332
  return process.env.NEGOTIUM_CODEX_AUTH_FILE || join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
333
333
  }
334
- var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.17", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", SNIPPETS_API_URL, BROWSER_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, BROWSER_MCP_SSE_PROXY_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, BACKGROUND_BASH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
334
+ var HOME, PROJECT_ROOT, STATE_DIR_ENV, STATE_DIR, WORKSPACE_DIR, TOPIC_WORKSPACE_DIR, SHARED_WIKI_DIR, CRON_WORKSPACE_DIR, BROWSER_DIR, BROWSER_PROFILES_DIR, BINARIES_DIR, SECRETS_DIR, DM_WORKSPACE_DIR, SESSION_WORKSPACE_DIR, CLAUDE_EXECUTABLE_ENV, CLAUDE_EXECUTABLE, DEFAULT_OUTPUT_LANGUAGE = "English", BROWSER_RS_VERSION = "v0.1.19", BROWSER_RS_MIN_SECURE_VERSION = "0.1.15", SNIPPETS_API_URL, BROWSER_RS_BIN, PLAYWRIGHT_MCP_BIN, TSX_BIN, TSX_LOADER, TSCONFIG_PATH, SESSION_COMM_SERVER, TASK_SERVER, BROWSER_MCP_SSE_PROXY_SERVER, CANONICAL_MCP_PROXY_SERVER, WIKI_SERVER, TOKEN_STATS_SERVER, COMPACTION_LOG_SERVER, SYSTEM_HEALTH_SERVER, AGENT_HEALTH_SERVER, BACKGROUND_BASH_SERVER, VAULT_SERVER, BG_BASH_BASE_PORT, BG_BASH_MAX_PORT, RUNTIME_MCP_SECRET, NODE_CONTROL_TOKEN, VAULT_MASTER_KEY, NEGOTIUM_PORT, hostname, DATA_DIR, LOG_DIR, UPLOADS_DIR, VAULT_DIR, SESSIONS_DB, DEBUG_FILE, USERS_LOG_DIR, RUN_DIR, PROGRESS_DIR, DM_CMD_DIR, DM_RESP_DIR, SESSION_INBOX_DIR, SESSION_ASKS_DIR, PLAYWRIGHT_BASE_PORT, PLAYWRIGHT_MAX_PORT, PLAYWRIGHT_PORTS_DIR, ACTIVE_QUERY_STALE_MS, AGENTS_PROMPTS_DIR, RESOURCES_DIR, FILE_TAG_REGEX, MODEL_SONNET = "claude-sonnet-5", MODEL_OPUS = "claude-opus-5", MODEL_FABLE = "claude-fable-5", FALLBACK_AGENT, SESSION_AGENT, GATEWAY_AGENT, FALLBACK_MODEL, SESSION_MODEL, GATEWAY_MODEL, FFMPEG_BIN, FFPROBE_BIN, PYTHON_BIN, FASTER_WHISPER_WRAPPER, WHISPER_MODEL, TESSERACT_BIN, PDFTOTEXT_BIN, _envMaxTellDepth, MAX_TELL_DEPTH;
335
335
  var init_config = __esm(() => {
336
336
  init_config_helpers();
337
337
  init_logger();
@@ -2148,7 +2148,7 @@ var init_claude_registry = __esm(() => {
2148
2148
  });
2149
2149
 
2150
2150
  // ../../packages/core/src/version.ts
2151
- var NEGOTIUM_VERSION = "0.2.10";
2151
+ var NEGOTIUM_VERSION = "0.2.12";
2152
2152
 
2153
2153
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
2154
2154
  import { spawn as spawn2 } from "child_process";
@@ -10228,7 +10228,7 @@ var init_manager_utils = () => {};
10228
10228
  import { execFileSync as execFileSync6 } from "child_process";
10229
10229
  import { readdirSync as readdirSync3, unlinkSync as unlinkSync10 } from "fs";
10230
10230
  import { createServer } from "net";
10231
- import { resolve as resolve11, sep } from "path";
10231
+ import { resolve as resolve12, sep } from "path";
10232
10232
  function isPortInUse(port) {
10233
10233
  return new Promise((resolveProbe) => {
10234
10234
  const server = createServer();
@@ -10261,8 +10261,8 @@ async function reserveAvailableLoopbackPort(minPort, maxPort, reservedPorts, pro
10261
10261
  return null;
10262
10262
  }
10263
10263
  function killBrowserProcsForUserDataDir(userDataDir) {
10264
- const target = resolve11(userDataDir);
10265
- const profileRoot = resolve11(BROWSER_PROFILES_DIR);
10264
+ const target = resolve12(userDataDir);
10265
+ const profileRoot = resolve12(BROWSER_PROFILES_DIR);
10266
10266
  if (target !== profileRoot && !target.startsWith(`${profileRoot}${sep}`))
10267
10267
  return;
10268
10268
  let pids;
@@ -10283,7 +10283,7 @@ function killBrowserProcsForUserDataDir(userDataDir) {
10283
10283
  stdio: "pipe"
10284
10284
  }).toString().trim();
10285
10285
  const argDir = extractUserDataDirArg(cmdline);
10286
- if (!argDir || resolve11(argDir) !== target)
10286
+ if (!argDir || resolve12(argDir) !== target)
10287
10287
  continue;
10288
10288
  killProcessTreeChildren(pidNum);
10289
10289
  process.kill(pidNum, "SIGKILL");
@@ -10294,13 +10294,13 @@ function killBrowserProcsForUserDataDir(userDataDir) {
10294
10294
  }
10295
10295
  }
10296
10296
  function selectOrphanBrowserPids(procs, liveUserDataDirs, profileRoot, selfPid) {
10297
- const root = resolve11(profileRoot);
10298
- const live = new Set([...liveUserDataDirs].map((d) => resolve11(d)));
10297
+ const root = resolve12(profileRoot);
10298
+ const live = new Set([...liveUserDataDirs].map((d) => resolve12(d)));
10299
10299
  const out = [];
10300
10300
  for (const { pid, userDataDir } of procs) {
10301
10301
  if (pid === selfPid || !userDataDir)
10302
10302
  continue;
10303
- const dir = resolve11(userDataDir);
10303
+ const dir = resolve12(userDataDir);
10304
10304
  if (dir !== root && !dir.startsWith(`${root}${sep}`))
10305
10305
  continue;
10306
10306
  if (live.has(dir))
@@ -10316,7 +10316,7 @@ function reapOrphanBrowsers(liveUserDataDirs) {
10316
10316
  const daemonLease = getRuntimeProcessLease("node-daemon", Date.now(), Number.POSITIVE_INFINITY);
10317
10317
  if (!isBrowserJanitorOwner(daemonLease?.pid ?? null, process.pid))
10318
10318
  return;
10319
- const profileRoot = resolve11(BROWSER_PROFILES_DIR);
10319
+ const profileRoot = resolve12(BROWSER_PROFILES_DIR);
10320
10320
  let pids;
10321
10321
  try {
10322
10322
  pids = execFileSync6("pgrep", ["-f", "--", profileRoot], { stdio: "pipe" }).toString().trim();
@@ -10355,7 +10355,7 @@ function cleanSingletonFiles(userDataDir) {
10355
10355
  for (const f of files) {
10356
10356
  if (f.startsWith("Singleton")) {
10357
10357
  try {
10358
- unlinkSync10(resolve11(userDataDir, f));
10358
+ unlinkSync10(resolve12(userDataDir, f));
10359
10359
  logger.info({ file: f, userDataDir }, "Removed stale Singleton file");
10360
10360
  } catch (e) {
10361
10361
  logger.warn({ err: e, file: f }, "Failed to remove stale Chrome Singleton file");
@@ -10395,9 +10395,9 @@ var init_browser_processes = __esm(async () => {
10395
10395
 
10396
10396
  // ../../packages/core/src/platform/playwright/headed-launch.ts
10397
10397
  import { accessSync as accessSync2, constants as constants2 } from "fs";
10398
- import { delimiter, isAbsolute as isAbsolute3, resolve as resolve12 } from "path";
10398
+ import { delimiter, isAbsolute as isAbsolute4, resolve as resolve13 } from "path";
10399
10399
  function findExecutableOnPath(command, environment = process.env) {
10400
- const candidates = isAbsolute3(command) ? [command] : (environment.PATH ?? "").split(delimiter).filter(Boolean).map((directory) => resolve12(directory, command));
10400
+ const candidates = isAbsolute4(command) ? [command] : (environment.PATH ?? "").split(delimiter).filter(Boolean).map((directory) => resolve13(directory, command));
10401
10401
  for (const candidate of candidates) {
10402
10402
  try {
10403
10403
  accessSync2(candidate, constants2.X_OK);
@@ -10785,21 +10785,21 @@ import { execFileSync as execFileSync7, spawn as spawn5 } from "child_process";
10785
10785
  import { createHash as createHash3, randomBytes as randomBytes6, timingSafeEqual as timingSafeEqual3 } from "crypto";
10786
10786
  import {
10787
10787
  cpSync,
10788
- existsSync as existsSync16,
10788
+ existsSync as existsSync17,
10789
10789
  mkdirSync as mkdirSync11,
10790
- readFileSync as readFileSync14,
10790
+ readFileSync as readFileSync15,
10791
10791
  rmSync as rmSync3,
10792
10792
  unlinkSync as unlinkSync11,
10793
10793
  writeFileSync as writeFileSync9
10794
10794
  } from "fs";
10795
- import { dirname as dirname11, join as join19, resolve as resolve13 } from "path";
10795
+ import { dirname as dirname11, join as join19, resolve as resolve14 } from "path";
10796
10796
  function removeDefaultProfileDataDir(userDataDir) {
10797
- const root = resolve13(BROWSER_PROFILES_DIR);
10798
- const target = resolve13(userDataDir);
10797
+ const root = resolve14(BROWSER_PROFILES_DIR);
10798
+ const target = resolve14(userDataDir);
10799
10799
  if (dirname11(target) !== root) {
10800
10800
  throw new Error(`Refusing to delete browser profile outside managed root: ${target}`);
10801
10801
  }
10802
- const existed = existsSync16(target);
10802
+ const existed = existsSync17(target);
10803
10803
  rmSync3(target, { recursive: true, force: true });
10804
10804
  return existed;
10805
10805
  }
@@ -11013,7 +11013,7 @@ function releasePort(port) {
11013
11013
  usedPorts.delete(port);
11014
11014
  }
11015
11015
  function defaultProfileDir(_ownerId, profile) {
11016
- return resolve13(BROWSER_PROFILES_DIR, profile);
11016
+ return resolve14(BROWSER_PROFILES_DIR, profile);
11017
11017
  }
11018
11018
  function resolveUserDataDir(instanceKey) {
11019
11019
  return managerHost.resolveInstanceDataDir(instanceKey);
@@ -11374,11 +11374,11 @@ async function cloneProfileForChild(opts) {
11374
11374
  killInstance(dstKey);
11375
11375
  await delay(500);
11376
11376
  }
11377
- if (!existsSync16(srcDir)) {
11377
+ if (!existsSync17(srcDir)) {
11378
11378
  return { copied: false, srcDir, dstDir, reason: "src-missing" };
11379
11379
  }
11380
11380
  try {
11381
- if (existsSync16(dstDir)) {
11381
+ if (existsSync17(dstDir)) {
11382
11382
  rmSync3(dstDir, { recursive: true, force: true });
11383
11383
  }
11384
11384
  mkdirSync11(dirname11(dstDir), { recursive: true });
@@ -11399,7 +11399,7 @@ async function cloneProfileForChild(opts) {
11399
11399
  cleanSingletonFiles(dstDir);
11400
11400
  for (const f of ["DevToolsActivePort", "LOCK"]) {
11401
11401
  try {
11402
- unlinkSync11(resolve13(dstDir, f));
11402
+ unlinkSync11(resolve14(dstDir, f));
11403
11403
  } catch {}
11404
11404
  }
11405
11405
  logger.info({ srcKey, dstKey, srcDir, dstDir }, "Cloned Playwright profile for child topic");
@@ -13035,8 +13035,8 @@ import {
13035
13035
  mkdirSync as mkdirSync15,
13036
13036
  openSync as openSync2,
13037
13037
  readdirSync as readdirSync4,
13038
- readFileSync as readFileSync15,
13039
- statSync as statSync7,
13038
+ readFileSync as readFileSync16,
13039
+ statSync as statSync8,
13040
13040
  unlinkSync as unlinkSync16,
13041
13041
  writeFileSync as writeFileSync13
13042
13042
  } from "fs";
@@ -13084,11 +13084,11 @@ function parsePendingAskFilename(fileName) {
13084
13084
  }
13085
13085
  function readPendingAskFile(path, fallback) {
13086
13086
  try {
13087
- const raw = readFileSync15(path, "utf8").trim();
13087
+ const raw = readFileSync16(path, "utf8").trim();
13088
13088
  if (!raw)
13089
13089
  return null;
13090
13090
  if (!raw.startsWith("{")) {
13091
- const ts = new Date(statSync7(path).mtimeMs).toISOString();
13091
+ const ts = new Date(statSync8(path).mtimeMs).toISOString();
13092
13092
  return {
13093
13093
  userId: fallback.userId,
13094
13094
  from: fallback.from,
@@ -13128,7 +13128,7 @@ function isStale(record, path) {
13128
13128
  if (Number.isFinite(ts))
13129
13129
  return Date.now() - ts > PENDING_ASK_TTL_MS;
13130
13130
  try {
13131
- return Date.now() - statSync7(path).mtimeMs > PENDING_ASK_TTL_MS;
13131
+ return Date.now() - statSync8(path).mtimeMs > PENDING_ASK_TTL_MS;
13132
13132
  } catch {
13133
13133
  return false;
13134
13134
  }
@@ -14215,12 +14215,12 @@ var init_errors = __esm(() => {
14215
14215
 
14216
14216
  // ../../packages/core/src/runtime/event-heartbeat.ts
14217
14217
  function nextOrHeartbeat(pending, intervalMs) {
14218
- return new Promise((resolve14, reject) => {
14219
- const timer = setTimeout(() => resolve14({ kind: "heartbeat" }), intervalMs);
14218
+ return new Promise((resolve15, reject) => {
14219
+ const timer = setTimeout(() => resolve15({ kind: "heartbeat" }), intervalMs);
14220
14220
  timer.unref?.();
14221
14221
  pending.then((result) => {
14222
14222
  clearTimeout(timer);
14223
- resolve14({ kind: "event", result });
14223
+ resolve15({ kind: "event", result });
14224
14224
  }, (error) => {
14225
14225
  clearTimeout(timer);
14226
14226
  reject(error);
@@ -14477,7 +14477,7 @@ var init_visual_html = __esm(() => {
14477
14477
 
14478
14478
  // ../../packages/core/src/runtime/visuals.ts
14479
14479
  import { realpathSync as realpathSync4 } from "fs";
14480
- import { isAbsolute as isAbsolute4, resolve as resolve14 } from "path";
14480
+ import { isAbsolute as isAbsolute5, resolve as resolve15 } from "path";
14481
14481
  function activeVisualHtmlForPrompt(html) {
14482
14482
  if (html.length <= ACTIVE_VISUAL_PROMPT_MAX_CHARS) {
14483
14483
  return { html, omittedChars: 0 };
@@ -14528,8 +14528,8 @@ function topicAllowsVisualFileId(topicId, fileId) {
14528
14528
  return topicHasAttachmentFileId(topicId, fileId) || topicHasVisualFileId(topicId, fileId);
14529
14529
  }
14530
14530
  function isPathInside(baseDir, filePath) {
14531
- const base = resolve14(baseDir);
14532
- const normalized = resolve14(filePath);
14531
+ const base = resolve15(baseDir);
14532
+ const normalized = resolve15(filePath);
14533
14533
  try {
14534
14534
  const realBase = realpathSync4(base);
14535
14535
  const real = realpathSync4(normalized);
@@ -14591,7 +14591,7 @@ function resolveVisualMediaInput(topicId, input) {
14591
14591
  }
14592
14592
  const rawPath = input.file_path.trim();
14593
14593
  const cwd = workspaceCwdFor(topicId);
14594
- const candidate = isAbsolute4(rawPath) ? rawPath : resolve14(cwd, rawPath);
14594
+ const candidate = isAbsolute5(rawPath) ? rawPath : resolve15(cwd, rawPath);
14595
14595
  if (!isPathInside(cwd, candidate)) {
14596
14596
  return { error: "file_path must be inside the topic workspace" };
14597
14597
  }
@@ -14665,8 +14665,8 @@ var init_token_stats = __esm(async () => {
14665
14665
 
14666
14666
  // ../../packages/core/src/runtime/turn-event-stream.ts
14667
14667
  import { randomUUID as randomUUID15 } from "crypto";
14668
- import { realpathSync as realpathSync5, statSync as statSync8 } from "fs";
14669
- import { isAbsolute as isAbsolute5, resolve as resolve15 } from "path";
14668
+ import { realpathSync as realpathSync5, statSync as statSync9 } from "fs";
14669
+ import { isAbsolute as isAbsolute6, resolve as resolve16 } from "path";
14670
14670
  function sessionEventMatchesCurrentExecution(topicId, queryId, agent, model) {
14671
14671
  if (getRoomQuery(topicId)?.queryId !== queryId)
14672
14672
  return false;
@@ -14981,7 +14981,7 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
14981
14981
  case "file":
14982
14982
  if (!silent && peerBridge) {
14983
14983
  const cwd = workspaceCwdFor(topicId);
14984
- const path = isAbsolute5(event.path) ? event.path : resolve15(cwd, event.path);
14984
+ const path = isAbsolute6(event.path) ? event.path : resolve16(cwd, event.path);
14985
14985
  if (!isPathInside(cwd, path)) {
14986
14986
  logger.warn({ topicId, path }, "peer output file is outside the topic workspace");
14987
14987
  break;
@@ -14989,7 +14989,7 @@ async function runTurnEventStream(topicId, topicTitle, queryId, events, control,
14989
14989
  let safePath;
14990
14990
  try {
14991
14991
  safePath = realpathSync5(path);
14992
- if (!statSync8(safePath).isFile()) {
14992
+ if (!statSync9(safePath).isFile()) {
14993
14993
  logger.warn({ topicId, path }, "peer output path is not a regular file");
14994
14994
  break;
14995
14995
  }
@@ -15265,7 +15265,7 @@ var init_turn_session = __esm(async () => {
15265
15265
  });
15266
15266
 
15267
15267
  // ../../packages/core/src/storage/app-settings.ts
15268
- import { existsSync as existsSync17, mkdirSync as mkdirSync18, readFileSync as readFileSync16, writeFileSync as writeFileSync15 } from "fs";
15268
+ import { existsSync as existsSync18, mkdirSync as mkdirSync18, readFileSync as readFileSync17, writeFileSync as writeFileSync15 } from "fs";
15269
15269
  import { dirname as dirname14, join as join27 } from "path";
15270
15270
  function settingsFile() {
15271
15271
  return join27(resolveStorageDataDir(), "otium-settings.json");
@@ -15277,8 +15277,8 @@ function ensureSettingsLoaded() {
15277
15277
  loadedSettingsFile = path;
15278
15278
  aiName = DEFAULT_AI_NAME;
15279
15279
  try {
15280
- if (existsSync17(path)) {
15281
- const data = JSON.parse(readFileSync16(path, "utf8"));
15280
+ if (existsSync18(path)) {
15281
+ const data = JSON.parse(readFileSync17(path, "utf8"));
15282
15282
  if (typeof data.aiName === "string" && data.aiName.trim()) {
15283
15283
  aiName = data.aiName.trim();
15284
15284
  }
@@ -15370,7 +15370,7 @@ __export(exports_turn_runner, {
15370
15370
  AGENT_DISPLAY_NAME: () => AGENT_DISPLAY_NAME
15371
15371
  });
15372
15372
  import { randomUUID as randomUUID16 } from "crypto";
15373
- import { existsSync as existsSync18, mkdirSync as mkdirSync19, readdirSync as readdirSync5, statSync as statSync9 } from "fs";
15373
+ import { existsSync as existsSync19, mkdirSync as mkdirSync19, readdirSync as readdirSync5, statSync as statSync10 } from "fs";
15374
15374
  import { join as join28 } from "path";
15375
15375
  function withDefaultPlaywright(configuredMcp, isManager) {
15376
15376
  if (isManager)
@@ -15415,7 +15415,7 @@ function appendAskReplyMessage(topicId, text2, agentType) {
15415
15415
  }
15416
15416
  function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, matchesTitle, preferExact = true) {
15417
15417
  const preferred = join28(directory, preferredFilename);
15418
- if (preferExact && existsSync18(preferred))
15418
+ if (preferExact && existsSync19(preferred))
15419
15419
  return preferred;
15420
15420
  let newestLegacyId = null;
15421
15421
  let newestTitle = null;
@@ -15426,7 +15426,7 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
15426
15426
  if (!titleMatch && !legacyIdMatch)
15427
15427
  continue;
15428
15428
  const path = join28(directory, filename);
15429
- const mtimeMs = statSync9(path).mtimeMs;
15429
+ const mtimeMs = statSync10(path).mtimeMs;
15430
15430
  if (titleMatch) {
15431
15431
  if (!newestTitle || mtimeMs > newestTitle.mtimeMs) {
15432
15432
  newestTitle = { path, mtimeMs };
@@ -15440,9 +15440,9 @@ function resolveWikiMirrorPath(directory, preferredFilename, matchesLegacyId, ma
15440
15440
  }
15441
15441
  function resolveWikiMemoryMirror(wikiDir, topicId, topicTitle) {
15442
15442
  const briefFile = resolveWikiMirrorPath(join28(wikiDir, "topic"), `${wikiBriefStorageKey(topicTitle, topicId)}.md`, (filename) => isTopicBriefFile(filename, topicId), (filename) => isTopicBriefFile(filename, topicId, topicTitle));
15443
- const hasBriefFile = existsSync18(briefFile) && statSync9(briefFile).isFile();
15443
+ const hasBriefFile = existsSync19(briefFile) && statSync10(briefFile).isFile();
15444
15444
  const latestSummaryCandidate = resolveWikiMirrorPath(join28(wikiDir, "summaries"), `__missing__-${wikiSummaryFilename("0000-00-00", topicTitle, topicId)}`, (filename) => isTopicSummaryFile(filename, topicId), (filename) => isTopicSummaryFile(filename, topicId, topicTitle), false);
15445
- const latestSummaryFile = existsSync18(latestSummaryCandidate) && statSync9(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
15445
+ const latestSummaryFile = existsSync19(latestSummaryCandidate) && statSync10(latestSummaryCandidate).isFile() ? latestSummaryCandidate : null;
15446
15446
  return { briefFile, hasBriefFile, latestSummaryFile };
15447
15447
  }
15448
15448
  async function streamAgentEvents(topicId, topicTitle, queryId, events, control, agentType, model, effort, userId, retryableSessionExpired = true, onSessionId, execution) {
@@ -16636,7 +16636,7 @@ var init_turn_runner = __esm(async () => {
16636
16636
  });
16637
16637
 
16638
16638
  // ../../packages/core/src/agents/mcp-tools/spawn-subagent.ts
16639
- import { z as z3 } from "zod";
16639
+ import { z as z4 } from "zod";
16640
16640
  function createSubagentLifecycle(host) {
16641
16641
  const runtimeOwnerId = host.runtime.ownerId;
16642
16642
  const limits = Object.freeze({
@@ -17171,7 +17171,7 @@ ${card.task}${reportInstruction}`;
17171
17171
  name: "start_subagent",
17172
17172
  description: "Start a prepared descendant subagent task.",
17173
17173
  schema: {
17174
- topic_id: z3.string().describe("Prepared subagent room id.")
17174
+ topic_id: z4.string().describe("Prepared subagent room id.")
17175
17175
  },
17176
17176
  async handler(input) {
17177
17177
  const result = ownedSubagentTree(ctx);
@@ -17191,7 +17191,7 @@ ${card.task}${reportInstruction}`;
17191
17191
  name: "delete_subagent",
17192
17192
  description: "Permanently delete one descendant subagent room managed by the current room. " + "This removes its conversation, workspace, runtime state, and topic. Keep it when follow-up work is likely.",
17193
17193
  schema: {
17194
- topic_id: z3.string().describe("Exact subagent room id returned by list_subagents; names are not accepted.")
17194
+ topic_id: z4.string().describe("Exact subagent room id returned by list_subagents; names are not accepted.")
17195
17195
  },
17196
17196
  async handler(input) {
17197
17197
  const result = ownedSubagentTree(ctx);
@@ -17215,8 +17215,8 @@ ${card.task}${reportInstruction}`;
17215
17215
  name: "grant_subagent_tell",
17216
17216
  description: "Allow one descendant subagent to tell_session another topic in this managed subagent tree. " + "Direct-parent reporting is always allowed and does not need a grant.",
17217
17217
  schema: {
17218
- subagent_topic_id: z3.string().describe("Source descendant subagent topic id."),
17219
- target_topic_id: z3.string().describe("Target topic id: this manager room or another descendant in its tree.")
17218
+ subagent_topic_id: z4.string().describe("Source descendant subagent topic id."),
17219
+ target_topic_id: z4.string().describe("Target topic id: this manager room or another descendant in its tree.")
17220
17220
  },
17221
17221
  async handler(input) {
17222
17222
  const result = ownedSubagentTree(ctx);
@@ -17242,8 +17242,8 @@ ${card.task}${reportInstruction}`;
17242
17242
  name: "revoke_subagent_tell",
17243
17243
  description: "Remove an extra tell_session connection previously granted to a descendant subagent.",
17244
17244
  schema: {
17245
- subagent_topic_id: z3.string().describe("Source descendant subagent topic id."),
17246
- target_topic_id: z3.string().describe("Granted target topic id.")
17245
+ subagent_topic_id: z4.string().describe("Source descendant subagent topic id."),
17246
+ target_topic_id: z4.string().describe("Granted target topic id.")
17247
17247
  },
17248
17248
  async handler(input) {
17249
17249
  const result = ownedSubagentTree(ctx);
@@ -17269,12 +17269,12 @@ ${card.task}${reportInstruction}`;
17269
17269
  name: "spawn_subagent",
17270
17270
  description: "Delegate a self-contained task to a subagent that works in its own new agent room. " + "Returns immediately; the subagent runs in the background and reports according to report_mode. " + "The fresh room has no parent conversation history; it receives the task plus the selected or inherited topic memory. " + "Use for parallelizable or long-running side work. Do not use provider built-in Task/Agent subagents.",
17271
17271
  schema: {
17272
- task: z3.string().describe("Self-contained task brief. The worker has topic memory but no parent conversation history, so include all task-specific context."),
17273
- name: z3.string().optional().describe("Short name for the subagent room. Auto-generated when omitted."),
17274
- agent: z3.enum(["claude", "codex", "maestro"]).optional().describe("Agent backend override. Defaults to this room's agent."),
17275
- model: z3.string().optional().describe(`Best-fit model override from the system prompt catalog. Omit agent+model to inherit ${ctx.agent}/${ctx.model ?? "default"}; overriding agent without model uses that agent's default.`),
17276
- memory_topic: z3.string().optional().describe("Optional knowledge source: an accessible topic id/title or topic/*.md brief. Defaults to the parent room's effective topic brief."),
17277
- report_mode: z3.enum(["auto", "tell", "status-only"]).optional().describe("Completion reporting: auto injects the final result, tell requires tell_session, status-only updates only the lifecycle card.")
17272
+ task: z4.string().describe("Self-contained task brief. The worker has topic memory but no parent conversation history, so include all task-specific context."),
17273
+ name: z4.string().optional().describe("Short name for the subagent room. Auto-generated when omitted."),
17274
+ agent: z4.enum(["claude", "codex", "maestro"]).optional().describe("Agent backend override. Defaults to this room's agent."),
17275
+ model: z4.string().optional().describe(`Best-fit model override from the system prompt catalog. Omit agent+model to inherit ${ctx.agent}/${ctx.model ?? "default"}; overriding agent without model uses that agent's default.`),
17276
+ memory_topic: z4.string().optional().describe("Optional knowledge source: an accessible topic id/title or topic/*.md brief. Defaults to the parent room's effective topic brief."),
17277
+ report_mode: z4.enum(["auto", "tell", "status-only"]).optional().describe("Completion reporting: auto injects the final result, tell requires tell_session, status-only updates only the lifecycle card.")
17278
17278
  },
17279
17279
  async handler(input) {
17280
17280
  return createSubagent(ctx, input, true);
@@ -17286,12 +17286,12 @@ ${card.task}${reportInstruction}`;
17286
17286
  name: "create_subagent",
17287
17287
  description: "Create a prepared subagent room and task definition without starting its AI turn. " + "Use start_subagent when the team is ready to run it.",
17288
17288
  schema: {
17289
- task: z3.string().describe("Self-contained task brief for the subagent."),
17290
- name: z3.string().optional().describe("Short room name. Auto-generated when omitted."),
17291
- agent: z3.enum(["claude", "codex", "maestro"]).optional(),
17292
- model: z3.string().optional(),
17293
- memory_topic: z3.string().optional().describe("Optional accessible topic id/title or topic/*.md brief to use as this worker's knowledge source. Defaults to the parent."),
17294
- report_mode: z3.enum(["auto", "tell", "status-only"]).optional()
17289
+ task: z4.string().describe("Self-contained task brief for the subagent."),
17290
+ name: z4.string().optional().describe("Short room name. Auto-generated when omitted."),
17291
+ agent: z4.enum(["claude", "codex", "maestro"]).optional(),
17292
+ model: z4.string().optional(),
17293
+ memory_topic: z4.string().optional().describe("Optional accessible topic id/title or topic/*.md brief to use as this worker's knowledge source. Defaults to the parent."),
17294
+ report_mode: z4.enum(["auto", "tell", "status-only"]).optional()
17295
17295
  },
17296
17296
  async handler(input) {
17297
17297
  return createSubagent(ctx, input, false);
@@ -17479,10 +17479,252 @@ await __promiseAll([
17479
17479
  init_ask_user()
17480
17480
  ]);
17481
17481
 
17482
- // ../../packages/core/src/agents/mcp-tools/self-config.ts
17482
+ // ../../packages/core/src/agents/mcp-tools/publish-html.ts
17483
17483
  init_common();
17484
17484
  import { z as z2 } from "zod";
17485
17485
 
17486
+ // ../../packages/core/src/agents/mcp-tools/inline-assets.ts
17487
+ import { existsSync as existsSync16, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
17488
+ import { extname, isAbsolute as isAbsolute3, resolve as resolve11 } from "path";
17489
+ var MIME_BY_EXT = {
17490
+ ".apng": "image/apng",
17491
+ ".avif": "image/avif",
17492
+ ".bmp": "image/bmp",
17493
+ ".css": "text/css",
17494
+ ".gif": "image/gif",
17495
+ ".ico": "image/x-icon",
17496
+ ".jpeg": "image/jpeg",
17497
+ ".jpg": "image/jpeg",
17498
+ ".mp3": "audio/mpeg",
17499
+ ".mp4": "video/mp4",
17500
+ ".otf": "font/otf",
17501
+ ".png": "image/png",
17502
+ ".svg": "image/svg+xml",
17503
+ ".ttf": "font/ttf",
17504
+ ".wav": "audio/wav",
17505
+ ".webm": "video/webm",
17506
+ ".webp": "image/webp",
17507
+ ".woff": "font/woff",
17508
+ ".woff2": "font/woff2"
17509
+ };
17510
+ function isNonLocal(ref) {
17511
+ return /^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i.test(ref.trim());
17512
+ }
17513
+ function stripSuffix(ref) {
17514
+ return ref.replace(/[?#].*$/, "");
17515
+ }
17516
+ function inlineLocalAssets(html, options) {
17517
+ const { baseDir, maxAssetBytes, maxTotalBytes } = options;
17518
+ const inlined = [];
17519
+ const unresolved = [];
17520
+ const skipped = [];
17521
+ const cache = new Map;
17522
+ let budget = maxTotalBytes - Buffer.byteLength(html, "utf-8");
17523
+ function toDataUri(rawRef) {
17524
+ const ref = rawRef.trim();
17525
+ if (!ref || isNonLocal(ref))
17526
+ return null;
17527
+ const cached = cache.get(ref);
17528
+ if (cached !== undefined)
17529
+ return cached;
17530
+ const relPath = stripSuffix(ref);
17531
+ if (!relPath)
17532
+ return null;
17533
+ const abs = isAbsolute3(relPath) ? relPath : resolve11(baseDir, relPath);
17534
+ let bytes;
17535
+ try {
17536
+ if (!existsSync16(abs) || !statSync7(abs).isFile()) {
17537
+ unresolved.push(ref);
17538
+ cache.set(ref, null);
17539
+ return null;
17540
+ }
17541
+ bytes = statSync7(abs).size;
17542
+ } catch {
17543
+ unresolved.push(ref);
17544
+ cache.set(ref, null);
17545
+ return null;
17546
+ }
17547
+ if (bytes > maxAssetBytes) {
17548
+ skipped.push({ ref, bytes, reason: "asset-too-large" });
17549
+ cache.set(ref, null);
17550
+ return null;
17551
+ }
17552
+ const encodedCost = Math.ceil(bytes / 3) * 4;
17553
+ if (encodedCost > budget) {
17554
+ skipped.push({ ref, bytes, reason: "document-too-large" });
17555
+ cache.set(ref, null);
17556
+ return null;
17557
+ }
17558
+ let uri;
17559
+ try {
17560
+ const mime = MIME_BY_EXT[extname(abs).toLowerCase()] ?? "application/octet-stream";
17561
+ uri = `data:${mime};base64,${readFileSync14(abs).toString("base64")}`;
17562
+ } catch {
17563
+ unresolved.push(ref);
17564
+ cache.set(ref, null);
17565
+ return null;
17566
+ }
17567
+ budget -= uri.length;
17568
+ inlined.push({ ref, bytes });
17569
+ cache.set(ref, uri);
17570
+ return uri;
17571
+ }
17572
+ function rewriteSrcset(value) {
17573
+ return value.split(",").map((candidate) => {
17574
+ const trimmed = candidate.trim();
17575
+ if (!trimmed)
17576
+ return candidate;
17577
+ const [url, ...descriptor] = trimmed.split(/\s+/);
17578
+ const uri = url ? toDataUri(url) : null;
17579
+ if (!uri)
17580
+ return candidate;
17581
+ return [uri, ...descriptor].join(" ");
17582
+ }).join(", ");
17583
+ }
17584
+ let out = html;
17585
+ out = out.replace(/(\b(?:src|poster)\s*=\s*)(["'])([^"']*)\2/gi, (match, prefix, quote, ref) => {
17586
+ const uri = toDataUri(ref);
17587
+ return uri ? `${prefix}${quote}${uri}${quote}` : match;
17588
+ });
17589
+ out = out.replace(/(\bsrcset\s*=\s*)(["'])([^"']*)\2/gi, (match, prefix, quote, value) => {
17590
+ const rewritten = rewriteSrcset(value);
17591
+ return rewritten === value ? match : `${prefix}${quote}${rewritten}${quote}`;
17592
+ });
17593
+ out = out.replace(/<link\b[^>]*>/gi, (tag) => tag.replace(/(\bhref\s*=\s*)(["'])([^"']*)\2/i, (match, prefix, quote, ref) => {
17594
+ const uri = toDataUri(ref);
17595
+ return uri ? `${prefix}${quote}${uri}${quote}` : match;
17596
+ }));
17597
+ out = out.replace(/url\(\s*(["']?)([^"')]+)\1\s*\)/gi, (match, quote, ref) => {
17598
+ const uri = toDataUri(ref);
17599
+ return uri ? `url(${quote}${uri}${quote})` : match;
17600
+ });
17601
+ return { html: out, inlined, unresolved, skipped };
17602
+ }
17603
+
17604
+ // ../../packages/core/src/agents/mcp-tools/publish-html.ts
17605
+ init_config();
17606
+ var REQUEST_TIMEOUT_MS = 30000;
17607
+ var MAX_PUBLISHED_BYTES = 10 * 1024 * 1024;
17608
+ var MAX_PUBLISHED_ASSET_BYTES = 5 * 1024 * 1024;
17609
+ function formatPublishBytes(bytes) {
17610
+ if (bytes < 1024)
17611
+ return `${bytes}B`;
17612
+ if (bytes < 1024 * 1024)
17613
+ return `${(bytes / 1024).toFixed(0)}KB`;
17614
+ return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
17615
+ }
17616
+ function parseSnippetId(input) {
17617
+ const trimmed = input.trim();
17618
+ const fromUrl = trimmed.match(/\/snippets\/([A-Za-z0-9-]+)/)?.[1];
17619
+ const id = fromUrl ?? trimmed;
17620
+ return /^[A-Za-z0-9-]+$/.test(id) ? id : null;
17621
+ }
17622
+ async function snippetRequest(baseUrl, path, init = {}) {
17623
+ try {
17624
+ const response = await fetch(`${baseUrl}${path}`, {
17625
+ ...init,
17626
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
17627
+ });
17628
+ const body = await response.json().catch(() => null);
17629
+ if (body)
17630
+ return body;
17631
+ return { ok: false, error: `snippet service returned ${response.status}` };
17632
+ } catch (error) {
17633
+ const message = error instanceof Error ? error.message : "snippet service unreachable";
17634
+ return { ok: false, error: message };
17635
+ }
17636
+ }
17637
+ function createPublishHtmlToolDefinitions(ctx, options = {}) {
17638
+ const apiUrl = (options.apiUrl ?? SNIPPETS_API_URL)?.replace(/\/+$/, "");
17639
+ if (!apiUrl)
17640
+ return [];
17641
+ const getCtx = typeof ctx === "function" ? ctx : () => ctx;
17642
+ return [
17643
+ {
17644
+ name: "publish_html",
17645
+ description: [
17646
+ "Publish an HTML document and return a public, shareable https link that",
17647
+ "stays live for 72 hours. Use this when the user should be able to open,",
17648
+ "keep, or send the result \u2014 a report, dashboard, or styled table \u2014 rather",
17649
+ "than only glance at it in the side panel.",
17650
+ "Pass a complete standalone document and inline the CSS and JS.",
17651
+ "For charts and diagrams prefer inline <svg>: it stays sharp at any zoom",
17652
+ "and is far smaller than an image file.",
17653
+ "Images may be remote URLs, data: URIs, or paths to local files you",
17654
+ "created \u2014 local files are embedded automatically, so the page keeps",
17655
+ "working after your workspace is gone."
17656
+ ].join(" "),
17657
+ schema: {
17658
+ html: z2.string().describe("Complete standalone HTML document to publish. Inline the CSS and JS."),
17659
+ base_dir: z2.string().optional().describe("Directory that relative image paths resolve against. Defaults to the working directory.")
17660
+ },
17661
+ async handler(input) {
17662
+ const html = input?.html ?? "";
17663
+ if (!html.trim())
17664
+ return errorResult("html is empty \u2014 provide an HTML document.");
17665
+ const baseDir = input.base_dir?.trim() || getCtx().cwd || process.cwd();
17666
+ const report = inlineLocalAssets(html, {
17667
+ baseDir,
17668
+ maxAssetBytes: MAX_PUBLISHED_ASSET_BYTES,
17669
+ maxTotalBytes: MAX_PUBLISHED_BYTES
17670
+ });
17671
+ const bytes = Buffer.byteLength(report.html, "utf-8");
17672
+ if (bytes > MAX_PUBLISHED_BYTES) {
17673
+ return errorResult(`Document is ${formatPublishBytes(bytes)} after embedding images, over the ${formatPublishBytes(MAX_PUBLISHED_BYTES)} limit. Use fewer or smaller images, or switch charts to inline <svg>.`);
17674
+ }
17675
+ const result = await snippetRequest(apiUrl, "/snippets", {
17676
+ method: "POST",
17677
+ headers: { "content-type": "text/html; charset=utf-8" },
17678
+ body: report.html
17679
+ });
17680
+ if (!result.ok || !result.url) {
17681
+ return errorResult(result.error ?? "Failed to publish.");
17682
+ }
17683
+ const notes = [];
17684
+ if (report.inlined.length > 0) {
17685
+ const total = report.inlined.reduce((sum, a) => sum + a.bytes, 0);
17686
+ notes.push(`Embedded ${report.inlined.length} local file(s), ${formatPublishBytes(total)}.`);
17687
+ }
17688
+ if (report.unresolved.length > 0) {
17689
+ notes.push(`WARNING \u2014 these look like local files but were not found, so they will render broken: ${report.unresolved.join(", ")}. Check the paths (relative to ${baseDir}) and republish.`);
17690
+ }
17691
+ for (const s of report.skipped) {
17692
+ notes.push(s.reason === "asset-too-large" ? `WARNING \u2014 ${s.ref} is ${formatPublishBytes(s.bytes)}, over the ${formatPublishBytes(MAX_PUBLISHED_ASSET_BYTES)} per-file limit, and was left as a broken link.` : `WARNING \u2014 ${s.ref} was left out because the document hit the ${formatPublishBytes(MAX_PUBLISHED_BYTES)} limit.`);
17693
+ }
17694
+ const payload = {
17695
+ url: result.url,
17696
+ snippetId: result.snippetId,
17697
+ expiresAt: result.expiresAt,
17698
+ sizeBytes: bytes,
17699
+ ...report.inlined.length > 0 ? { embeddedFiles: report.inlined.length } : {}
17700
+ };
17701
+ return textResult([JSON.stringify(payload, null, 2), ...notes].join(`
17702
+
17703
+ `));
17704
+ }
17705
+ },
17706
+ {
17707
+ name: "unpublish_html",
17708
+ description: "Delete a previously published HTML document before its 72-hour expiry. Accepts the URL returned by publish_html, or its id.",
17709
+ schema: {
17710
+ snippet: z2.string().describe("URL returned by publish_html, or the bare id.")
17711
+ },
17712
+ async handler(input) {
17713
+ const id = parseSnippetId(input?.snippet ?? "");
17714
+ if (!id)
17715
+ return errorResult("Could not read a published document id from that value.");
17716
+ const result = await snippetRequest(apiUrl, `/snippets/${id}`, { method: "DELETE" });
17717
+ if (!result.ok)
17718
+ return errorResult(result.error ?? "Failed to delete.");
17719
+ return textResult(`Published document ${id} deleted.`);
17720
+ }
17721
+ }
17722
+ ];
17723
+ }
17724
+ // ../../packages/core/src/agents/mcp-tools/self-config.ts
17725
+ init_common();
17726
+ import { z as z3 } from "zod";
17727
+
17486
17728
  // ../../packages/core/src/agents/api-topic-agent-switch.ts
17487
17729
  init_model_catalog();
17488
17730
  init_logger();
@@ -18028,7 +18270,7 @@ function createSelfConfigToolDefinitionsForCore(core, ctx) {
18028
18270
  {
18029
18271
  name: "set_model",
18030
18272
  description: toolDescription(core, "set_model", "Set the model for THIS topic; it persists and applies from the NEXT turn. Use a model from the system prompt's same-agent catalog. Cross-agent changes require an explicit user-requested set_agent first. Fails if the user locked this setting. NEVER use 'fable' unless explicitly requested."),
18031
- schema: { model: z2.string().describe("Model id valid for the topic's current agent.") },
18273
+ schema: { model: z3.string().describe("Model id valid for the topic's current agent.") },
18032
18274
  async handler({ model }) {
18033
18275
  return mcpResult(core.setModel(getCtx(), model));
18034
18276
  }
@@ -18044,7 +18286,7 @@ function createSelfConfigToolDefinitionsForCore(core, ctx) {
18044
18286
  {
18045
18287
  name: "set_agent",
18046
18288
  description: toolDescription(core, "set_agent", "Switch the agent backend for THIS topic between 'claude', 'codex', and 'maestro'. Clears the topic's model/effort override so the new agent starts at its defaults. Fails if the user locked this setting. Use only when the user explicitly asks to switch the runtime itself."),
18047
- schema: { agent: z2.enum(AGENT_VALUES) },
18289
+ schema: { agent: z3.enum(AGENT_VALUES) },
18048
18290
  async handler({ agent }) {
18049
18291
  return mcpResult(core.setAgent(getCtx(), agent));
18050
18292
  }
@@ -18061,7 +18303,7 @@ function createSelfConfigToolDefinitionsForCore(core, ctx) {
18061
18303
  name: "set_effort",
18062
18304
  description: toolDescription(core, "set_effort", "Set the reasoning effort for THIS topic. Claude: low/medium/high/xhigh/max. Codex: low/medium/high/xhigh. Maestro: low/medium/high/xhigh/max. Higher effort costs more and is slower. Fails if the user locked this setting."),
18063
18305
  schema: {
18064
- effort: z2.enum(EFFORT_VALUES).describe("Reasoning effort level valid for the topic's current agent.")
18306
+ effort: z3.enum(EFFORT_VALUES).describe("Reasoning effort level valid for the topic's current agent.")
18065
18307
  },
18066
18308
  async handler({ effort }) {
18067
18309
  return mcpResult(core.setEffort(getCtx(), effort));
@@ -18081,8 +18323,8 @@ function createSelfConfigToolDefinitionsForCore(core, ctx) {
18081
18323
  name: "schedule_self",
18082
18324
  description: toolDescription(core, "schedule_self", "Create the one pending durable delayed continuation allowed for THIS topic without blocking the current turn. Use it to check a long-running operation or resume work later. The future message must be self-contained. If one already exists, use get_self_schedule then update_self_schedule or cancel_self_schedule. For recurring or longer-lived schedules, use cron-manager instead."),
18083
18325
  schema: {
18084
- delay_seconds: z2.number().int().min(1).max(core.product.scheduleMaxDelaySeconds).describe(`Seconds before this topic resumes, from 1 through ${core.product.scheduleMaxDelaySeconds}${core.product.scheduleMaxDelaySeconds === 86400 ? " (24 hours)" : ""}.`),
18085
- message: z2.string().min(1).max(core.product.scheduleMaxMessageLength).describe("Self-contained instruction delivered to your future turn.")
18326
+ delay_seconds: z3.number().int().min(1).max(core.product.scheduleMaxDelaySeconds).describe(`Seconds before this topic resumes, from 1 through ${core.product.scheduleMaxDelaySeconds}${core.product.scheduleMaxDelaySeconds === 86400 ? " (24 hours)" : ""}.`),
18327
+ message: z3.string().min(1).max(core.product.scheduleMaxMessageLength).describe("Self-contained instruction delivered to your future turn.")
18086
18328
  },
18087
18329
  async handler({ delay_seconds, message }) {
18088
18330
  return mcpResult(core.scheduleContinue(getCtx(), delay_seconds, message));
@@ -18100,9 +18342,9 @@ function createSelfConfigToolDefinitionsForCore(core, ctx) {
18100
18342
  name: "update_self_schedule",
18101
18343
  description: toolDescription(core, "update_self_schedule", "Edit THIS topic's pending self-schedule. Provide its schedule_id from schedule_self/get_self_schedule and change delay_seconds, message, or both. delay_seconds is measured from this update. A schedule that already started cannot be edited."),
18102
18344
  schema: {
18103
- schedule_id: z2.string().min(1).describe("Exact ID of the pending self-schedule."),
18104
- delay_seconds: z2.number().int().min(1).max(core.product.scheduleMaxDelaySeconds).optional().describe(`New delay from now, from 1 through ${core.product.scheduleMaxDelaySeconds} seconds.`),
18105
- message: z2.string().min(1).max(core.product.scheduleMaxMessageLength).optional().describe("Replacement self-contained future instruction.")
18345
+ schedule_id: z3.string().min(1).describe("Exact ID of the pending self-schedule."),
18346
+ delay_seconds: z3.number().int().min(1).max(core.product.scheduleMaxDelaySeconds).optional().describe(`New delay from now, from 1 through ${core.product.scheduleMaxDelaySeconds} seconds.`),
18347
+ message: z3.string().min(1).max(core.product.scheduleMaxMessageLength).optional().describe("Replacement self-contained future instruction.")
18106
18348
  },
18107
18349
  async handler({
18108
18350
  schedule_id,
@@ -18119,7 +18361,7 @@ function createSelfConfigToolDefinitionsForCore(core, ctx) {
18119
18361
  name: "cancel_self_schedule",
18120
18362
  description: toolDescription(core, "cancel_self_schedule", "Cancel THIS topic's pending self-schedule by its exact schedule_id. A schedule that already started cannot be cancelled with this tool."),
18121
18363
  schema: {
18122
- schedule_id: z2.string().min(1).describe("Exact ID of the pending self-schedule.")
18364
+ schedule_id: z3.string().min(1).describe("Exact ID of the pending self-schedule.")
18123
18365
  },
18124
18366
  async handler({ schedule_id }) {
18125
18367
  return mcpResult(core.cancelSchedule(getCtx(), schedule_id));
@@ -18131,7 +18373,7 @@ function createSelfConfigToolDefinitionsForCore(core, ctx) {
18131
18373
  name: "spawn_topic",
18132
18374
  description: toolDescription(core, "spawn_topic", `Create a new forum topic that inherits all settings from THIS topic but starts with a fresh session. Limited to ${core.product.derivedTopicLimit} calls per conversation turn.`),
18133
18375
  schema: {
18134
- name: z2.string().optional().describe("New topic name. Auto-generated if omitted.")
18376
+ name: z3.string().optional().describe("New topic name. Auto-generated if omitted.")
18135
18377
  },
18136
18378
  async handler({ name }) {
18137
18379
  if (derivedCount >= core.product.derivedTopicLimit) {
@@ -18148,7 +18390,7 @@ function createSelfConfigToolDefinitionsForCore(core, ctx) {
18148
18390
  name: "fork_topic",
18149
18391
  description: toolDescription(core, "fork_topic", `Fork THIS topic by creating a new topic that inherits both settings AND conversation history. Limited to ${core.product.derivedTopicLimit} calls per conversation turn.`),
18150
18392
  schema: {
18151
- name: z2.string().optional().describe("New topic name. Auto-generated if omitted.")
18393
+ name: z3.string().optional().describe("New topic name. Auto-generated if omitted.")
18152
18394
  },
18153
18395
  async handler({ name }) {
18154
18396
  if (derivedCount >= core.product.derivedTopicLimit) {
@@ -18170,14 +18412,14 @@ await init_spawn_subagent();
18170
18412
 
18171
18413
  // ../../packages/core/src/agents/mcp-tools/visuals.ts
18172
18414
  init_common();
18173
- import { z as z4 } from "zod";
18415
+ import { z as z5 } from "zod";
18174
18416
  var VISUALS_MCP_KEY = "visuals";
18175
18417
  var showHtmlTool = {
18176
18418
  name: "show_html",
18177
18419
  description: "Display charts, tables, or interactive HTML to the user in a sandboxed WebView side panel. Pass a complete, self-contained HTML string with inline CSS/JS. Local DOM interactions are supported. Links (<a href> to http/https URLs) are safe to include: a click opens the URL in the user's system browser. Network requests, external scripts, form posts, popups, and parent-window access are blocked.",
18178
18420
  schema: {
18179
- html: z4.string().describe("Complete, self-contained HTML document or fragment to render."),
18180
- title: z4.string().optional().describe("Optional title shown above the rendered card.")
18421
+ html: z5.string().describe("Complete, self-contained HTML document or fragment to render."),
18422
+ title: z5.string().optional().describe("Optional title shown above the rendered card.")
18181
18423
  },
18182
18424
  async handler() {
18183
18425
  return textResult("HTML card displayed to the user.");
@@ -18187,9 +18429,9 @@ var showMermaidTool = {
18187
18429
  name: "show_mermaid",
18188
18430
  description: "Render a Mermaid diagram in the user's visual side panel. Pass Mermaid DSL only, not markdown fences. Use this for flowcharts, sequence diagrams, class diagrams, state diagrams, ER diagrams, timelines, and architecture diagrams.",
18189
18431
  schema: {
18190
- code: z4.string().describe("Mermaid diagram source without markdown code fences."),
18191
- title: z4.string().optional().describe("Optional title shown above the rendered card."),
18192
- theme: z4.enum(["default", "neutral", "dark", "forest"]).optional().describe("Optional Mermaid theme. Defaults to neutral.")
18432
+ code: z5.string().describe("Mermaid diagram source without markdown code fences."),
18433
+ title: z5.string().optional().describe("Optional title shown above the rendered card."),
18434
+ theme: z5.enum(["default", "neutral", "dark", "forest"]).optional().describe("Optional Mermaid theme. Defaults to neutral.")
18193
18435
  },
18194
18436
  async handler() {
18195
18437
  return textResult("Mermaid diagram displayed to the user.");
@@ -18199,10 +18441,10 @@ var showImageTool = {
18199
18441
  name: "show_image",
18200
18442
  description: "Display an image in the user's visual side panel. Provide either file_path for an image in the topic workspace, or file_id for an uploaded file already attached in this topic.",
18201
18443
  schema: {
18202
- file_path: z4.string().optional().describe("Absolute or workspace-relative path to an image file."),
18203
- file_id: z4.string().optional().describe("Full Otium uploaded file UUID for an image attached in this topic."),
18204
- title: z4.string().optional().describe("Optional title shown above the rendered card."),
18205
- alt: z4.string().optional().describe("Optional alt text for the image.")
18444
+ file_path: z5.string().optional().describe("Absolute or workspace-relative path to an image file."),
18445
+ file_id: z5.string().optional().describe("Full Otium uploaded file UUID for an image attached in this topic."),
18446
+ title: z5.string().optional().describe("Optional title shown above the rendered card."),
18447
+ alt: z5.string().optional().describe("Optional alt text for the image.")
18206
18448
  },
18207
18449
  async handler(input) {
18208
18450
  if (!input?.file_path && !input?.file_id) {
@@ -18215,9 +18457,9 @@ var showVideoTool = {
18215
18457
  name: "show_video",
18216
18458
  description: "Display a playable video in the user's visual side panel. Provide either file_path for a video in the topic workspace, or file_id for an uploaded file already attached in this topic.",
18217
18459
  schema: {
18218
- file_path: z4.string().optional().describe("Absolute or workspace-relative path to a video file."),
18219
- file_id: z4.string().optional().describe("Full Otium uploaded file UUID for a video attached in this topic."),
18220
- title: z4.string().optional().describe("Optional title shown above the rendered card.")
18460
+ file_path: z5.string().optional().describe("Absolute or workspace-relative path to a video file."),
18461
+ file_id: z5.string().optional().describe("Full Otium uploaded file UUID for a video attached in this topic."),
18462
+ title: z5.string().optional().describe("Optional title shown above the rendered card.")
18221
18463
  },
18222
18464
  async handler(input) {
18223
18465
  if (!input?.file_path && !input?.file_id) {
@@ -18291,6 +18533,7 @@ export {
18291
18533
  createSelfConfigToolDefinitionsForCore,
18292
18534
  createSelfConfigRuntime,
18293
18535
  createSelfConfigCore,
18536
+ createPublishHtmlToolDefinitions,
18294
18537
  createCodexTreeManager,
18295
18538
  createAskUserRuntime,
18296
18539
  createArchiverRuntime,
@@ -18310,4 +18553,4 @@ export {
18310
18553
  DEFAULT_SELF_CONFIG_PRODUCT
18311
18554
  };
18312
18555
 
18313
- //# debugId=9D7DFE7928DB7C4D64756E2164756E21
18556
+ //# debugId=A750A8503E5A9A9064756E2164756E21