negotium 0.23.2 → 0.23.4

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 (30) hide show
  1. package/dist/agent-helpers.js +171 -12
  2. package/dist/agent-helpers.js.map +8 -7
  3. package/dist/{chunk-s34sv3d2.js → chunk-ggdwn8d5.js} +3 -3
  4. package/dist/{chunk-s34sv3d2.js.map → chunk-ggdwn8d5.js.map} +2 -2
  5. package/dist/{chunk-9zn0bkc9.js → chunk-jarf6nb2.js} +2 -2
  6. package/dist/{chunk-9zn0bkc9.js.map → chunk-jarf6nb2.js.map} +1 -1
  7. package/dist/{chunk-cez5m5hm.js → chunk-pwafy9bb.js} +1 -1
  8. package/dist/{chunk-q5djsg78.js → chunk-qekt5bnd.js} +1 -1
  9. package/dist/{chunk-6cnpkzkb.js → chunk-vtd5kn4n.js} +1 -1
  10. package/dist/{chunk-6cnpkzkb.js.map → chunk-vtd5kn4n.js.map} +3 -3
  11. package/dist/hosted-agent.js +166 -13
  12. package/dist/hosted-agent.js.map +8 -7
  13. package/dist/main.js +240 -21
  14. package/dist/main.js.map +11 -10
  15. package/dist/mcp-factories.js +171 -12
  16. package/dist/mcp-factories.js.map +8 -7
  17. package/dist/registry.js +3 -3
  18. package/dist/rollout.js +2 -2
  19. package/dist/runtime/src/agents/claude-notices.ts +130 -0
  20. package/dist/runtime/src/agents/claude-provider.ts +9 -11
  21. package/dist/runtime/src/agents/codex-provider.ts +51 -6
  22. package/dist/runtime/src/agents/rollout/codex.ts +58 -0
  23. package/dist/runtime/src/version.ts +1 -1
  24. package/dist/types/packages/core/src/agents/claude-notices.d.ts +15 -0
  25. package/dist/types/packages/core/src/agents/codex-provider.d.ts +6 -0
  26. package/dist/types/packages/core/src/agents/rollout/codex.d.ts +12 -0
  27. package/dist/types/packages/core/src/version.d.ts +1 -1
  28. package/package.json +1 -1
  29. /package/dist/{chunk-cez5m5hm.js.map → chunk-pwafy9bb.js.map} +0 -0
  30. /package/dist/{chunk-q5djsg78.js.map → chunk-qekt5bnd.js.map} +0 -0
package/dist/main.js CHANGED
@@ -6291,6 +6291,49 @@ function extractCodexForkedFromId(jsonl) {
6291
6291
  return;
6292
6292
  }
6293
6293
  }
6294
+ function extractLatestCodexSystemInstructionsTurn(jsonl) {
6295
+ const lines = jsonl.trimEnd().split(`
6296
+ `);
6297
+ for (let index = lines.length - 1;index >= 0; index -= 1) {
6298
+ const line = lines[index] ?? "";
6299
+ if (!line.includes("[System Instructions]"))
6300
+ continue;
6301
+ try {
6302
+ const entry = JSON.parse(line);
6303
+ if (entry.type !== "response_item")
6304
+ continue;
6305
+ if (entry.payload?.type !== "message" || entry.payload.role !== "user")
6306
+ continue;
6307
+ const text = (entry.payload.content ?? []).map((part) => typeof part.text === "string" ? part.text : "").join("");
6308
+ if (text.startsWith(`[System Instructions]
6309
+ `))
6310
+ return text;
6311
+ } catch {}
6312
+ }
6313
+ return;
6314
+ }
6315
+ function codexThreadHasSystemPrompt(threadId, systemPrompt, depth = 0) {
6316
+ const path = latestCodexRolloutPath(threadId);
6317
+ if (!path)
6318
+ return false;
6319
+ try {
6320
+ const jsonl = readFileSync4(path, "utf8");
6321
+ const latest = extractLatestCodexSystemInstructionsTurn(jsonl);
6322
+ if (latest !== undefined) {
6323
+ return latest.startsWith(`[System Instructions]
6324
+ ${systemPrompt}
6325
+
6326
+ `);
6327
+ }
6328
+ if (depth >= 8)
6329
+ return false;
6330
+ const parentId = extractCodexForkedFromId(jsonl);
6331
+ return parentId && parentId !== threadId ? codexThreadHasSystemPrompt(parentId, systemPrompt, depth + 1) : false;
6332
+ } catch (error) {
6333
+ logger.debug({ error, threadId }, "codex system prompt: rollout read failed");
6334
+ return false;
6335
+ }
6336
+ }
6294
6337
  function readLatestCodexTokenTotals(threadId, depth = 0) {
6295
6338
  const path = latestCodexRolloutPath(threadId);
6296
6339
  if (!path)
@@ -6564,7 +6607,7 @@ var exports_version = {};
6564
6607
  __export(exports_version, {
6565
6608
  NEGOTIUM_VERSION: () => NEGOTIUM_VERSION
6566
6609
  });
6567
- var NEGOTIUM_VERSION = "0.23.2";
6610
+ var NEGOTIUM_VERSION = "0.23.4";
6568
6611
 
6569
6612
  // ../../packages/core/src/agents/codex-native-multi-agent.ts
6570
6613
  import { spawn as spawn2 } from "child_process";
@@ -7653,6 +7696,97 @@ var init_conversations = __esm(async () => {
7653
7696
  };
7654
7697
  });
7655
7698
 
7699
+ // ../../packages/core/src/agents/claude-notices.ts
7700
+ function modelLabel(id) {
7701
+ const match = /^claude-([a-z]+)-(\d+)-(\d+)/.exec(id);
7702
+ if (!match)
7703
+ return id;
7704
+ const [, family = "", major, minor] = match;
7705
+ return `${family.charAt(0).toUpperCase()}${family.slice(1)} ${major}.${minor}`;
7706
+ }
7707
+ function rateLimitNotice(m) {
7708
+ const { status, rateLimitType } = m.rate_limit_info;
7709
+ const limit = rateLimitType ? `${RATE_LIMIT_TEXT[rateLimitType] ?? ""} `.trimStart() : "";
7710
+ if (status === "allowed_warning")
7711
+ return `Nearing your ${limit}Claude usage limit`;
7712
+ if (status === "rejected")
7713
+ return `Reached your ${limit}Claude usage limit`;
7714
+ return;
7715
+ }
7716
+ function claudeNoticeStatus(message) {
7717
+ try {
7718
+ if (message.type === "rate_limit_event")
7719
+ return rateLimitNotice(message);
7720
+ if (message.type !== "system")
7721
+ return;
7722
+ const handler = SYSTEM_NOTICES[message.subtype];
7723
+ if (!handler) {
7724
+ logger.debug({ subtype: message.subtype, msg: message }, "claudeProvider: system message (unhandled subtype)");
7725
+ return;
7726
+ }
7727
+ const status = handler(message);
7728
+ if (status)
7729
+ logger.warn({ subtype: message.subtype, status }, "claudeProvider: notice");
7730
+ return status;
7731
+ } catch (err) {
7732
+ logger.debug({ err, msg: message }, "claudeProvider: notice mapping failed");
7733
+ return;
7734
+ }
7735
+ }
7736
+ var API_ERROR_TEXT, RATE_LIMIT_TEXT, DENIAL_TEXT, SYSTEM_NOTICES;
7737
+ var init_claude_notices = __esm(() => {
7738
+ init_logger();
7739
+ API_ERROR_TEXT = {
7740
+ overloaded: "Claude is overloaded",
7741
+ rate_limit: "Claude rate limit hit",
7742
+ server_error: "Claude API error",
7743
+ unknown: "Claude request failed",
7744
+ authentication_failed: "Claude sign-in failed",
7745
+ oauth_org_not_allowed: "Organization not allowed for Claude",
7746
+ account_on_hold: "Claude account is on hold",
7747
+ verification_required: "Claude account needs verification",
7748
+ billing_error: "Claude billing issue",
7749
+ invalid_request: "Claude rejected the request",
7750
+ model_not_found: "Claude model not found",
7751
+ max_output_tokens: "Claude reply hit the length limit",
7752
+ cloud_credential_error: "Cloud credentials failed"
7753
+ };
7754
+ RATE_LIMIT_TEXT = {
7755
+ five_hour: "5-hour",
7756
+ seven_day: "weekly",
7757
+ seven_day_opus: "weekly Opus",
7758
+ seven_day_sonnet: "weekly Sonnet",
7759
+ seven_day_overage_included: "weekly",
7760
+ overage: "extra usage"
7761
+ };
7762
+ DENIAL_TEXT = {
7763
+ rule: "by a permission rule",
7764
+ mode: "by the permission mode",
7765
+ classifier: "by the safety check",
7766
+ asyncAgent: "for a background agent"
7767
+ };
7768
+ SYSTEM_NOTICES = {
7769
+ api_retry: (m) => {
7770
+ const reason = m.error_status === null ? "Lost connection to Claude" : API_ERROR_TEXT[m.error] ?? "Claude request failed";
7771
+ const delay2 = Math.round(m.retry_delay_ms / 1000);
7772
+ const when = delay2 > 0 ? `in ${delay2}s` : "now";
7773
+ return `${reason} \xB7 retrying ${when} (${m.attempt}/${m.max_retries})`;
7774
+ },
7775
+ model_refusal_fallback: (m) => m.direction === "retry" ? `${modelLabel(m.original_model)} declined \xB7 ${modelLabel(m.fallback_model)} is answering instead` : m.content || undefined,
7776
+ model_refusal_no_fallback: (m) => `${modelLabel(m.original_model)} declined this request`,
7777
+ permission_denied: (m) => {
7778
+ const tool = m.tool_name.split("__").at(-1) || m.tool_name;
7779
+ const why = m.decision_reason ? `: ${m.decision_reason}` : ` ${DENIAL_TEXT[m.decision_reason_type ?? ""] ?? ""}`.trimEnd();
7780
+ return `${tool} was blocked${why}`;
7781
+ },
7782
+ informational: (m) => m.prevent_continuation || m.level === "warning" || m.level === "suggestion" ? m.content : undefined,
7783
+ mirror_error: (m) => {
7784
+ logger.warn({ error: m.error }, "claudeProvider: transcript mirror batch dropped");
7785
+ return;
7786
+ }
7787
+ };
7788
+ });
7789
+
7656
7790
  // ../../packages/core/src/agents/deep-map.ts
7657
7791
  function deepMapStrings(value, fn) {
7658
7792
  if (typeof value === "string")
@@ -8169,12 +8303,13 @@ async function* claudeProvider(opts) {
8169
8303
  yield { type: "tool_use_summary", summary: m.summary };
8170
8304
  continue;
8171
8305
  }
8172
- if (message.type === "system") {
8173
- const m = message;
8174
- if (m.subtype === "init") {
8175
- yield { type: "session", sessionId: m.session_id };
8306
+ if (message.type === "system" || message.type === "rate_limit_event") {
8307
+ if (message.type === "system" && message.subtype === "init") {
8308
+ yield { type: "session", sessionId: message.session_id };
8176
8309
  } else {
8177
- logger.debug({ subtype: m.subtype, msg: m }, "claudeProvider: system message (unhandled subtype)");
8310
+ const status = claudeNoticeStatus(message);
8311
+ if (status)
8312
+ yield { type: "status", content: status };
8178
8313
  }
8179
8314
  continue;
8180
8315
  }
@@ -8285,6 +8420,7 @@ async function* claudeProvider(opts) {
8285
8420
  }
8286
8421
  var CLAUDE_DEFAULT_DISALLOWED_TOOLS, CLAUDE_NATIVE_AGENT_TOOLS, CLAUDE_IMAGE_MAX_BYTES, CLAUDE_IMAGE_MIME_TYPES, CLAUDE_ABORT_SIGKILL_DELAY_MS = 2500, claudeProcessExitListeners;
8287
8422
  var init_claude_provider = __esm(async () => {
8423
+ init_claude_notices();
8288
8424
  init_claude_registry();
8289
8425
  init_vault_tool_policy();
8290
8426
  init_file_events();
@@ -9241,13 +9377,22 @@ var exports_codex_provider = {};
9241
9377
  __export(exports_codex_provider, {
9242
9378
  toCodexMcpServers: () => toCodexMcpServers,
9243
9379
  normalizeCodexTurnUsage: () => normalizeCodexTurnUsage,
9244
- codexProvider: () => codexProvider
9380
+ codexProvider: () => codexProvider,
9381
+ codexNoticeStatus: () => codexNoticeStatus
9245
9382
  });
9246
9383
  import { execFileSync as execFileSync5 } from "child_process";
9247
9384
  import { existsSync as existsSync16, readFileSync as readFileSync11, realpathSync as realpathSync4, statSync as statSync5 } from "fs";
9248
9385
  import { homedir as homedir8 } from "os";
9249
9386
  import { dirname as dirname11, isAbsolute as isAbsolute3, join as join16, relative as relative2, resolve as resolve10 } from "path";
9250
9387
  import { Codex } from "@openai/codex-sdk";
9388
+ function codexNoticeStatus(message) {
9389
+ const firstLine = message.trim().split(`
9390
+ `)[0]?.trim() ?? "";
9391
+ const sentence = /^.*?[.!?](?=\s|$)/.exec(firstLine)?.[0] ?? firstLine;
9392
+ if (!sentence)
9393
+ return "Codex notice";
9394
+ return /^codex\b/i.test(sentence) ? sentence : `Codex: ${sentence}`;
9395
+ }
9251
9396
  function sameCodexUsage(usage, total) {
9252
9397
  return usage.input_tokens === total.inputTokens && usage.output_tokens === total.outputTokens && (usage.cached_input_tokens ?? 0) === total.cachedInputTokens && (usage.cache_write_input_tokens ?? 0) === total.cacheWriteInputTokens;
9253
9398
  }
@@ -9665,8 +9810,7 @@ async function* codexProvider(opts) {
9665
9810
  },
9666
9811
  hooks: vaultHook.hooks,
9667
9812
  model_catalog_json: codexModelCatalogPath,
9668
- mcp_servers: codexMcpServers,
9669
- ...opts.toolPolicy ? { sandbox_permissions: [] } : {}
9813
+ mcp_servers: codexMcpServers
9670
9814
  }
9671
9815
  });
9672
9816
  const threadOptions = {
@@ -9687,7 +9831,7 @@ async function* codexProvider(opts) {
9687
9831
  let currentSessionId = opts.sessionId;
9688
9832
  let usageBaseline = currentSessionId ? readLatestCodexTokenTotals(currentSessionId) : undefined;
9689
9833
  let thread = currentSessionId ? codex.resumeThread(currentSessionId, threadOptions) : codex.startThread(threadOptions);
9690
- let prompt = promptForThread(opts, true);
9834
+ let prompt = promptForThread(opts, !currentSessionId || !opts.systemPrompt || !codexThreadHasSystemPrompt(currentSessionId, opts.systemPrompt));
9691
9835
  let agentTextSoFar = "";
9692
9836
  let currentAgentMessageId;
9693
9837
  let finalText = "";
@@ -9715,6 +9859,8 @@ async function* codexProvider(opts) {
9715
9859
  trackedPids.pids = [];
9716
9860
  let heartbeatTriggered = false;
9717
9861
  let attemptCompleted = false;
9862
+ let turnFailed = false;
9863
+ let streamError;
9718
9864
  let heartbeatTimer = null;
9719
9865
  const scheduleHeartbeat = () => {
9720
9866
  if (heartbeatTimer !== null)
@@ -9843,7 +9989,8 @@ async function* codexProvider(opts) {
9843
9989
  } else if (item.type === "error") {
9844
9990
  const message = String(item.message ?? "");
9845
9991
  if (message !== CODEX_HOOK_TRUST_BYPASS_NOTICE) {
9846
- yield { type: "error", content: message };
9992
+ logger.warn({ message }, "codexProvider: codex non-fatal error item");
9993
+ yield { type: "status", content: codexNoticeStatus(message) };
9847
9994
  }
9848
9995
  }
9849
9996
  break;
@@ -9871,7 +10018,15 @@ async function* codexProvider(opts) {
9871
10018
  yield* extractFileEvents(finalText, "result");
9872
10019
  break;
9873
10020
  }
10021
+ case "error": {
10022
+ const message = event.message || "Codex stream error";
10023
+ logger.warn({ message }, "codexProvider: codex stream error event");
10024
+ streamError = message;
10025
+ yield { type: "status", content: codexNoticeStatus(message) };
10026
+ break;
10027
+ }
9874
10028
  case "turn.failed": {
10029
+ turnFailed = true;
9875
10030
  stopReason = "error";
9876
10031
  yield {
9877
10032
  type: "error",
@@ -9883,6 +10038,10 @@ async function* codexProvider(opts) {
9883
10038
  break;
9884
10039
  }
9885
10040
  }
10041
+ if (!attemptCompleted && !turnFailed && streamError) {
10042
+ stopReason = "error";
10043
+ yield { type: "error", content: streamError };
10044
+ }
9886
10045
  } catch (err) {
9887
10046
  if (abortSignal?.aborted)
9888
10047
  return;
@@ -42027,6 +42186,7 @@ function createInitialState(userId) {
42027
42186
  topicUsage: {},
42028
42187
  messageHistory: {},
42029
42188
  activity: {},
42189
+ unread: {},
42030
42190
  input: "",
42031
42191
  inputCursor: { row: 0, col: 0 },
42032
42192
  suggestionIndex: 0,
@@ -42263,11 +42423,12 @@ function sortedTopicEntries(state, entries) {
42263
42423
  function topicPickerItems(state) {
42264
42424
  const visible = visibleTopicPickerIds(state);
42265
42425
  const indexedTopics = state.topics.map((topic, index) => ({ topic, index })).filter(({ topic }) => visible.has(topic.id));
42266
- const managerEntries = sortedTopicEntries(state, indexedTopics.filter(({ topic }) => topic.kind === "manager"));
42267
- const regularEntries = sortedTopicEntries(state, indexedTopics.filter(({ topic }) => topic.kind !== "manager"));
42268
42426
  return [
42269
- ...managerEntries.map(({ topic, index }) => ({ kind: "topic", id: topic.id, index })),
42270
- ...regularEntries.map(({ topic, index }) => ({ kind: "topic", id: topic.id, index })),
42427
+ ...managerFirstTopicEntries(state, indexedTopics).map(({ topic, index }) => ({
42428
+ kind: "topic",
42429
+ id: topic.id,
42430
+ index
42431
+ })),
42271
42432
  ...visibleBackgroundSessions(state).map((session) => ({
42272
42433
  kind: "background",
42273
42434
  id: session.id
@@ -42343,6 +42504,7 @@ function setTopics(state, topics, preferredTitle) {
42343
42504
  ...state,
42344
42505
  topics: orderedTopics,
42345
42506
  activity,
42507
+ unread: withoutUnread(state.unread, nextActive),
42346
42508
  activeTopicId: nextActive,
42347
42509
  scrollOffset: nextActive === state.activeTopicId ? state.scrollOffset : 0,
42348
42510
  askChoiceIndex: nextActive === state.activeTopicId ? state.askChoiceIndex : 0,
@@ -42350,11 +42512,32 @@ function setTopics(state, topics, preferredTitle) {
42350
42512
  topicPickerBackgroundId: state.topicPickerBackgroundId
42351
42513
  });
42352
42514
  }
42515
+ function withoutUnread(unread, topicId) {
42516
+ if (topicId === null || !unread[topicId])
42517
+ return unread;
42518
+ const next = { ...unread };
42519
+ delete next[topicId];
42520
+ return next;
42521
+ }
42522
+ function managerFirstTopicEntries(state, entries) {
42523
+ return [
42524
+ ...sortedTopicEntries(state, entries.filter(({ topic }) => topic.kind === "manager")),
42525
+ ...sortedTopicEntries(state, entries.filter(({ topic }) => topic.kind !== "manager"))
42526
+ ];
42527
+ }
42528
+ function adjacentTopicId(state, delta) {
42529
+ const order = managerFirstTopicEntries(state, state.topics.map((topic) => ({ topic }))).map(({ topic }) => topic.id);
42530
+ const current3 = order.indexOf(state.activeTopicId ?? "");
42531
+ if (current3 < 0 || order.length < 2)
42532
+ return null;
42533
+ return order[(current3 + delta + order.length) % order.length] ?? null;
42534
+ }
42353
42535
  function selectTopic(state, topicId) {
42354
42536
  if (!state.topics.some((topic) => topic.id === topicId))
42355
42537
  return state;
42356
42538
  return {
42357
42539
  ...state,
42540
+ unread: withoutUnread(state.unread, topicId),
42358
42541
  activeTopicId: topicId,
42359
42542
  scrollOffset: 0,
42360
42543
  askChoiceIndex: 0,
@@ -42442,6 +42625,11 @@ function removeMessage(state, topicId, messageId) {
42442
42625
  return state;
42443
42626
  return { ...state, messages: { ...state.messages, [topicId]: next } };
42444
42627
  }
42628
+ function flagUnreadReply(state, topicId, wasRunning) {
42629
+ if (!wasRunning || topicId === state.activeTopicId)
42630
+ return state;
42631
+ return { ...state, unread: { ...state.unread, [topicId]: true } };
42632
+ }
42445
42633
  function activityFor(state, topicId) {
42446
42634
  return state.activity[topicId] ?? { running: false, tools: [] };
42447
42635
  }
@@ -42610,11 +42798,11 @@ function applyAiStatus(state, topicId, raw, createdAt) {
42610
42798
  if (kind === "ai_done") {
42611
42799
  if (isStaleTerminalStatus(current3, status))
42612
42800
  return state;
42613
- return setActivity(state, topicId, {
42801
+ return flagUnreadReply(setActivity(state, topicId, {
42614
42802
  ...liveCurrent,
42615
42803
  running: false,
42616
42804
  status: "Done"
42617
- });
42805
+ }), topicId, current3.running);
42618
42806
  }
42619
42807
  if (kind === "ai_aborted") {
42620
42808
  if (isStaleTerminalStatus(current3, status))
@@ -42628,12 +42816,12 @@ function applyAiStatus(state, topicId, raw, createdAt) {
42628
42816
  if (kind === "ai_error") {
42629
42817
  if (isStaleTerminalStatus(current3, status))
42630
42818
  return state;
42631
- return setActivity(state, topicId, {
42819
+ return flagUnreadReply(setActivity(state, topicId, {
42632
42820
  ...liveCurrent,
42633
42821
  running: false,
42634
42822
  status: "Error",
42635
42823
  error: String(status.error ?? "Unknown error")
42636
- });
42824
+ }), topicId, current3.running);
42637
42825
  }
42638
42826
  if (kind === "tool_call") {
42639
42827
  if (isStaleTerminalStatus(current3, status))
@@ -44001,6 +44189,8 @@ function topicStatusIndicator(state, topic, animationFrame) {
44001
44189
  if (state.activity[topic.id]?.running) {
44002
44190
  return { icon: workingFrame(animationFrame), fg: theme.green };
44003
44191
  }
44192
+ if (state.unread[topic.id])
44193
+ return { icon: "\u25CF", fg: theme.blue };
44004
44194
  return { icon: "\u25CB", fg: theme.muted };
44005
44195
  }
44006
44196
  function topicPanelRowLines(state, topic, topicIndex, animationFrame) {
@@ -44239,6 +44429,7 @@ function helpLines() {
44239
44429
  line(" Ctrl-R sort topics panel (activity / name) \xB7 drag a \u2502 divider to resize"),
44240
44430
  line(" Ctrl-T open/close a shell on the right (closing ends it) \xB7 click it to type"),
44241
44431
  line(" Ctrl-O topics \xB7 Ctrl-G subagents \xB7 Ctrl-D decisions \xB7 Ctrl-X abort"),
44432
+ line(" Ctrl/Alt-\u2191 \u2193 step through topics \xB7 a blue \u25CF marks an unread reply"),
44242
44433
  line(" In topics: type to filter \xB7 Ctrl-N new \xB7 Ctrl-D delete"),
44243
44434
  line(" Esc/Ctrl-C stop active turn \xB7 Ctrl-C twice when idle to quit"),
44244
44435
  line(""),
@@ -45449,6 +45640,7 @@ var init_render = __esm(async () => {
45449
45640
  cyan: [87, 205, 220],
45450
45641
  tool: [196, 181, 253],
45451
45642
  green: [94, 211, 142],
45643
+ blue: [96, 165, 250],
45452
45644
  diffAddBg: [18, 43, 32],
45453
45645
  amber: [241, 190, 91],
45454
45646
  red: [245, 116, 128],
@@ -48582,6 +48774,12 @@ class TerminalApp {
48582
48774
  this.#openNewTopicComposer();
48583
48775
  return;
48584
48776
  }
48777
+ if (this.#state.overlay === null && (PREVIOUS_TOPIC_KEYS.has(chunk) || NEXT_TOPIC_KEYS.has(chunk))) {
48778
+ const topicId = adjacentTopicId(this.#state, PREVIOUS_TOPIC_KEYS.has(chunk) ? -1 : 1);
48779
+ if (topicId !== null)
48780
+ this.#activateTopic(topicId);
48781
+ return;
48782
+ }
48585
48783
  if (chunk === "\x10") {
48586
48784
  if (editingVaultSecret)
48587
48785
  return;
@@ -48903,6 +49101,17 @@ class TerminalApp {
48903
49101
  return;
48904
49102
  }
48905
49103
  if (chunk === "\r") {
49104
+ const commands = this.#shownCommands();
49105
+ if (commands.length > 0) {
49106
+ const selected = commands[Math.min(this.#state.suggestionIndex, commands.length - 1)];
49107
+ if (selected) {
49108
+ if (selected.usage.includes("<")) {
49109
+ this.#replaceInput(`/${selected.name} `);
49110
+ return;
49111
+ }
49112
+ this.#replaceInput(`/${selected.name}`);
49113
+ }
49114
+ }
48906
49115
  if (this.#state.overlay !== "vault" && !activeQuestion(this.#state) && commandSuggestions(this.#input.text).length === 0 && this.#pathItems().length > 0 && this.#applyPathCompletion(true)) {
48907
49116
  return;
48908
49117
  }
@@ -49619,6 +49828,14 @@ class TerminalApp {
49619
49828
  `)[cursor.row] ?? "";
49620
49829
  return pathSuggestions(lineText, cursor.col)?.items ?? [];
49621
49830
  }
49831
+ #shownCommands() {
49832
+ const state2 = this.#state;
49833
+ if (state2.creatingTopic || state2.overlay === "vault" || composerHoldsSecret(state2))
49834
+ return [];
49835
+ if (activeQuestion(state2))
49836
+ return [];
49837
+ return commandSuggestions(this.#input.text);
49838
+ }
49622
49839
  #suggestionCount() {
49623
49840
  const commands = commandSuggestions(this.#input.text).length;
49624
49841
  return commands > 0 ? commands : this.#pathItems().length;
@@ -50290,7 +50507,7 @@ class TerminalApp {
50290
50507
  await this.#client.stop();
50291
50508
  }
50292
50509
  }
50293
- var KITTY_KEYBOARD_PUSH = "\x1B[>1u", KITTY_KEYBOARD_POP = "\x1B[<u", CANVAS_RGB, ENTER_ALT_SCREEN, EXIT_ALT_SCREEN, ABORT_ENTER_ALT_SCREEN, NEW_TOPIC_KEY = "\x0E", DELETE_TOPIC_KEY = "\x04", TERMINAL_PANE_KEY = "\x14", FILTER_BACKSPACE_KEYS, CONFIRM_KEYS, CANCEL_KEYS, INPUT_CARRY_FLUSH_MS = 15;
50510
+ var KITTY_KEYBOARD_PUSH = "\x1B[>1u", KITTY_KEYBOARD_POP = "\x1B[<u", CANVAS_RGB, ENTER_ALT_SCREEN, EXIT_ALT_SCREEN, ABORT_ENTER_ALT_SCREEN, NEW_TOPIC_KEY = "\x0E", DELETE_TOPIC_KEY = "\x04", TERMINAL_PANE_KEY = "\x14", PREVIOUS_TOPIC_KEYS, NEXT_TOPIC_KEYS, FILTER_BACKSPACE_KEYS, CONFIRM_KEYS, CANCEL_KEYS, INPUT_CARRY_FLUSH_MS = 15;
50294
50511
  var init_app = __esm(async () => {
50295
50512
  init_color_depth();
50296
50513
  init_commands();
@@ -50314,6 +50531,8 @@ var init_app = __esm(async () => {
50314
50531
  ENTER_ALT_SCREEN = altScreenSequences().enter;
50315
50532
  EXIT_ALT_SCREEN = altScreenSequences().exit;
50316
50533
  ABORT_ENTER_ALT_SCREEN = altScreenSequences().abortEnter;
50534
+ PREVIOUS_TOPIC_KEYS = new Set(["\x1B[1;5A", "\x1B[1;3A", "\x1B\x1B[A"]);
50535
+ NEXT_TOPIC_KEYS = new Set(["\x1B[1;5B", "\x1B[1;3B", "\x1B\x1B[B"]);
50317
50536
  FILTER_BACKSPACE_KEYS = new Set(["\x7F", "\b"]);
50318
50537
  CONFIRM_KEYS = new Set(["y", "\u315B"]);
50319
50538
  CANCEL_KEYS = new Set(["n", "\u315C"]);
@@ -60355,4 +60574,4 @@ switch (command) {
60355
60574
  }
60356
60575
  }
60357
60576
 
60358
- //# debugId=3FFA808EE892362C64756E2164756E21
60577
+ //# debugId=7009B5CBB966BCAA64756E2164756E21