@mrciphersmith/keryx 0.2.119 → 0.2.121

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 (2) hide show
  1. package/dist/cli.js +131 -29
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -29500,6 +29500,7 @@ async function runAgentTurnCore(io, deps, history, userLine, options = {}) {
29500
29500
  const spawnConcurrencyCandidates = calls.filter((call) => call.name === "spawn_subagent" && reservationByCallId.get(call.id)?.ok === true);
29501
29501
  const untrustedGateBlocksSpawns = untrustedContentSeen || batchContainsUntrustedWeb;
29502
29502
  const concurrentSpawnResults = spawnConcurrencyCandidates.length >= 2 && !untrustedGateBlocksSpawns && maxToolCalls === undefined ? await runConcurrentSpawnBatch(spawnConcurrencyCandidates, toolByName, io, deps, hasInvocationCapacity, reserveInvocation) : undefined;
29503
+ const answeredToolIds = new Set;
29503
29504
  let anchorsToAnnounce;
29504
29505
  let repeatedFailureHint;
29505
29506
  for (const call of calls) {
@@ -29507,6 +29508,26 @@ async function runAgentTurnCore(io, deps, history, userLine, options = {}) {
29507
29508
  system(`
29508
29509
  [stopped] Model turn interrupted by user.
29509
29510
  `);
29511
+ if (concurrentSpawnResults !== undefined) {
29512
+ for (const spawnCall of spawnConcurrencyCandidates) {
29513
+ if (answeredToolIds.has(spawnCall.id)) {
29514
+ continue;
29515
+ }
29516
+ const settled = concurrentSpawnResults.get(spawnCall.id);
29517
+ if (settled === undefined) {
29518
+ continue;
29519
+ }
29520
+ io.onToolResult?.(spawnCall.name, settled);
29521
+ history.push({
29522
+ role: "tool",
29523
+ content: redactSensitiveText(settled.output),
29524
+ provenance: "tool",
29525
+ toolCallId: spawnCall.id,
29526
+ ts: now()
29527
+ });
29528
+ io.onHistoryChange?.("tool");
29529
+ }
29530
+ }
29510
29531
  return {};
29511
29532
  }
29512
29533
  if (deps.unattended === true && call.name === "ask_user") {
@@ -29549,6 +29570,7 @@ ${modelOutput}` : modelOutput,
29549
29570
  ts: now()
29550
29571
  });
29551
29572
  io.onHistoryChange?.("tool");
29573
+ answeredToolIds.add(call.id);
29552
29574
  if (untrusted) {
29553
29575
  untrustedContentSeen = true;
29554
29576
  }
@@ -50252,7 +50274,7 @@ import path47 from "path";
50252
50274
  // package.json
50253
50275
  var package_default = {
50254
50276
  name: "@mrciphersmith/keryx",
50255
- version: "0.2.119",
50277
+ version: "0.2.121",
50256
50278
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
50257
50279
  private: false,
50258
50280
  publishConfig: {
@@ -85105,13 +85127,14 @@ function createSearchProviderRegistry(transport, resolveCredential = () => {
85105
85127
  return normalize2("searxng", query, parsed === undefined ? [] : resultsFrom(parsed), { title: "title", url: "url", snippet: "content", date: "publishedDate" });
85106
85128
  }
85107
85129
  };
85130
+ const apiKeyLabel = (displayName) => /\bAPI$/.test(displayName) ? `${displayName} key` : `${displayName} API key`;
85108
85131
  const remote = (id, displayName, endpoint, injection, name, mapping) => ({
85109
85132
  id,
85110
85133
  displayName,
85111
85134
  kind: "remote",
85112
85135
  fields: [],
85113
85136
  defaults: {},
85114
- credentialSchema: { required: true, label: `${displayName} API key`, secret: true },
85137
+ credentialSchema: { required: true, label: apiKeyLabel(displayName), secret: true },
85115
85138
  documentationUrl: id === "brave" ? "https://api.search.brave.com/app/documentation" : id === "tavily" ? "https://docs.tavily.com/" : "https://docs.exa.ai/",
85116
85139
  capabilities: { localLoopback: false, supportsPublicationDate: Boolean(mapping.date) },
85117
85140
  async testConnection(_fields) {
@@ -91637,11 +91660,13 @@ function presentMcpTools(openModal, otui, chrome, options) {
91637
91660
  bodyWidth = ctx?.width;
91638
91661
  if (tabId === "tools") {
91639
91662
  toolsBody = target;
91663
+ mcpBody = undefined;
91640
91664
  toolsScroll = Math.max(0, toolsScroll);
91641
91665
  paintToolsRows();
91642
91666
  return;
91643
91667
  }
91644
91668
  mcpBody = target;
91669
+ toolsBody = undefined;
91645
91670
  mcpScroll = scrollToReveal3(mcpSelected, mcpScroll, bodyRows);
91646
91671
  paintMcpRows();
91647
91672
  },
@@ -94355,7 +94380,48 @@ function onKeypress2(r, handler) {
94355
94380
  r._internalKeyInput.onInternal("keypress", handler);
94356
94381
  return () => r._internalKeyInput.offInternal("keypress", handler);
94357
94382
  }
94358
- function showComposerChoice(otui, r, dock, request) {
94383
+ var dockChain = new WeakMap;
94384
+ var dockDepth = new WeakMap;
94385
+ function dockBusy(dock) {
94386
+ return (dockDepth.get(dock) ?? 0) > 0;
94387
+ }
94388
+ function lockDock(dock) {
94389
+ dockDepth.set(dock, (dockDepth.get(dock) ?? 0) + 1);
94390
+ const prev = dockChain.get(dock) ?? Promise.resolve();
94391
+ let release;
94392
+ const mine = new Promise((resolve) => {
94393
+ release = resolve;
94394
+ });
94395
+ dockChain.set(dock, prev.then(() => mine));
94396
+ return prev.then(() => {
94397
+ return () => {
94398
+ const n = (dockDepth.get(dock) ?? 1) - 1;
94399
+ if (n <= 0) {
94400
+ dockDepth.delete(dock);
94401
+ } else {
94402
+ dockDepth.set(dock, n);
94403
+ }
94404
+ release();
94405
+ };
94406
+ });
94407
+ }
94408
+ async function showComposerChoice(otui, r, dock, request) {
94409
+ const enqueue = request.enqueue !== false;
94410
+ if (!enqueue && dockBusy(dock)) {
94411
+ request.onBusy?.();
94412
+ return request.cancelId;
94413
+ }
94414
+ const unlock = await lockDock(dock);
94415
+ try {
94416
+ if (request.signal?.aborted === true) {
94417
+ return request.cancelId;
94418
+ }
94419
+ return await presentComposerChoice(otui, r, dock, request);
94420
+ } finally {
94421
+ unlock();
94422
+ }
94423
+ }
94424
+ function presentComposerChoice(otui, r, dock, request) {
94359
94425
  if (dock.visible === true) {
94360
94426
  request.onBusy?.();
94361
94427
  return Promise.resolve(request.cancelId);
@@ -94368,6 +94434,7 @@ function showComposerChoice(otui, r, dock, request) {
94368
94434
  const recommendedIdx = options.findIndex((o) => o.recommended === true);
94369
94435
  let selected = recommendedIdx >= 0 ? recommendedIdx : 0;
94370
94436
  dock.visible = true;
94437
+ request.onOpen?.();
94371
94438
  const theme = getTheme();
94372
94439
  const rawSubtitle = request.subtitle !== undefined && request.subtitle.length > 0 ? request.subtitle : undefined;
94373
94440
  const subtitleText = rawSubtitle !== undefined && rawSubtitle.length > MAX_SUBTITLE_CHARS ? `${rawSubtitle.slice(0, MAX_SUBTITLE_CHARS)}
@@ -94432,7 +94499,15 @@ function showComposerChoice(otui, r, dock, request) {
94432
94499
  }
94433
94500
  }
94434
94501
  };
94502
+ let settled = false;
94503
+ const onAbort = () => {
94504
+ finish(request.cancelId);
94505
+ };
94435
94506
  const finish = (id) => {
94507
+ if (settled) {
94508
+ return;
94509
+ }
94510
+ settled = true;
94436
94511
  cleanup();
94437
94512
  resolve(id);
94438
94513
  };
@@ -94484,6 +94559,7 @@ function showComposerChoice(otui, r, dock, request) {
94484
94559
  function cleanup() {
94485
94560
  closed = true;
94486
94561
  unsub();
94562
+ request.signal?.removeEventListener("abort", onAbort);
94487
94563
  try {
94488
94564
  dock.remove(title);
94489
94565
  if (subtitleScroll !== undefined) {
@@ -94520,7 +94596,7 @@ function showComposerChoice(otui, r, dock, request) {
94520
94596
  }
94521
94597
  const focused = r.currentFocusedRenderable;
94522
94598
  const inScroll = subtitleScroll !== undefined && focused !== null && containsNode(subtitleScroll, focused);
94523
- if (inScroll) {
94599
+ if (inScroll && key.name !== "return" && key.name !== "linefeed" && key.name !== "kpenter") {
94524
94600
  return;
94525
94601
  }
94526
94602
  if (key.name === "up") {
@@ -94547,6 +94623,9 @@ function showComposerChoice(otui, r, dock, request) {
94547
94623
  }
94548
94624
  };
94549
94625
  const unsub = onKeypress2(r, onKey);
94626
+ if (request.signal !== undefined) {
94627
+ request.signal.addEventListener("abort", onAbort, { once: true });
94628
+ }
94550
94629
  optionsScroll.focus();
94551
94630
  });
94552
94631
  }
@@ -95350,6 +95429,9 @@ async function createShellChrome(otui, renderer, opts) {
95350
95429
  }
95351
95430
  });
95352
95431
  textarea.onSubmit = () => {
95432
+ if (overlayActive()) {
95433
+ return;
95434
+ }
95353
95435
  const line = input.value.trim();
95354
95436
  input.value = "";
95355
95437
  hideMenu();
@@ -98145,7 +98227,7 @@ function createApprovalContextLoader(cwd) {
98145
98227
  return buildApprovalContext(port, command);
98146
98228
  };
98147
98229
  }
98148
- async function pickShellApproval(otui, r, dock, command, loadContext, destructive = false, credentials = false) {
98230
+ async function pickShellApproval(otui, r, dock, command, loadContext, destructive = false, credentials = false, ui = {}) {
98149
98231
  let context;
98150
98232
  try {
98151
98233
  context = loadContext(command);
@@ -98185,7 +98267,9 @@ async function pickShellApproval(otui, r, dock, command, loadContext, destructiv
98185
98267
  subtitle: command,
98186
98268
  ...context !== undefined ? { context } : {},
98187
98269
  cancelId: "deny",
98188
- options
98270
+ options,
98271
+ ...ui.onOpen !== undefined ? { onOpen: ui.onOpen } : {},
98272
+ ...ui.signal !== undefined ? { signal: ui.signal } : {}
98189
98273
  });
98190
98274
  if (id === "once" || id === "always-exact" || id === "always-prefix" || id === "deny") {
98191
98275
  return id;
@@ -99530,10 +99614,12 @@ async function launchTuiAgentShell(opts) {
99530
99614
  chrome.hideMenu();
99531
99615
  setMainAgent("blocked", "approval");
99532
99616
  const preview = request.task.length > 80 ? `${request.task.slice(0, 77)}\u2026` : request.task;
99533
- const id = await showComposerChoice(otui, r, chrome.dock, {
99617
+ const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99534
99618
  title: `Run the external agent ${request.agentId}?`,
99535
99619
  subtitle: preview,
99536
99620
  cancelId: "deny",
99621
+ onOpen: () => chrome.blurComposer(),
99622
+ signal: foregroundOperation.signal,
99537
99623
  options: [
99538
99624
  {
99539
99625
  id: "allow",
@@ -99542,7 +99628,7 @@ async function launchTuiAgentShell(opts) {
99542
99628
  },
99543
99629
  { id: "deny", label: "Deny", description: "Do not start the external agent" }
99544
99630
  ]
99545
- });
99631
+ }));
99546
99632
  input.focus();
99547
99633
  setMainAgent("running", id === "allow" ? "external" : "denied");
99548
99634
  return id === "allow" ? { ok: true } : { ok: false, reason: `you declined the external spawn of ${request.agentId}` };
@@ -99713,10 +99799,12 @@ async function launchTuiAgentShell(opts) {
99713
99799
  }
99714
99800
  chrome.hideMenu();
99715
99801
  setMainAgent("blocked", "approval");
99716
- const id = await showComposerChoice(otui, r, chrome.dock, {
99802
+ const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99717
99803
  title: "Spawn general subagent?",
99718
99804
  subtitle: taskPreview,
99719
99805
  cancelId: "deny",
99806
+ onOpen: () => chrome.blurComposer(),
99807
+ signal: foregroundOperation.signal,
99720
99808
  options: [
99721
99809
  {
99722
99810
  id: "allow",
@@ -99726,7 +99814,7 @@ async function launchTuiAgentShell(opts) {
99726
99814
  },
99727
99815
  { id: "deny", label: "Deny", description: "Do not spawn" }
99728
99816
  ]
99729
- });
99817
+ }));
99730
99818
  input.focus();
99731
99819
  setMainAgent("running", id === "allow" ? "subagent" : "denied");
99732
99820
  transcript.add(new otui.TextRenderable(r, {
@@ -99755,15 +99843,17 @@ async function launchTuiAgentShell(opts) {
99755
99843
  }
99756
99844
  chrome.hideMenu();
99757
99845
  setMainAgent("blocked", "approval");
99758
- const id = await showComposerChoice(otui, r, chrome.dock, {
99846
+ const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99759
99847
  title: "Approve apply_patch?",
99760
99848
  subtitle: "Diff shown above \xB7 Esc denies",
99761
99849
  cancelId: "deny",
99850
+ onOpen: () => chrome.blurComposer(),
99851
+ signal: foregroundOperation.signal,
99762
99852
  options: [
99763
99853
  { id: "allow", label: "Approve", description: "Write the patch to disk", recommended: true },
99764
99854
  { id: "deny", label: "Deny", description: "Do not write anything" }
99765
99855
  ]
99766
- });
99856
+ }));
99767
99857
  input.focus();
99768
99858
  setMainAgent("running", id === "allow" ? "write" : "denied");
99769
99859
  transcript.add(new otui.TextRenderable(r, {
@@ -99789,15 +99879,17 @@ async function launchTuiAgentShell(opts) {
99789
99879
  }
99790
99880
  chrome.hideMenu();
99791
99881
  setMainAgent("blocked", "approval");
99792
- const id = await showComposerChoice(otui, r, chrome.dock, {
99882
+ const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99793
99883
  title: described.title,
99794
99884
  subtitle: summariseUseToolApproval(described),
99795
99885
  cancelId: "deny",
99886
+ onOpen: () => chrome.blurComposer(),
99887
+ signal: foregroundOperation.signal,
99796
99888
  options: [
99797
99889
  { id: APPROVAL_ALLOW_ID, label: "Approve", description: `run ${described.tool} on ${described.server}` },
99798
99890
  { id: "deny", label: "Deny", description: "the tool call is refused", recommended: true }
99799
99891
  ]
99800
- });
99892
+ }));
99801
99893
  input.focus();
99802
99894
  const allowed = isDockApproval(id);
99803
99895
  setMainAgent("running", allowed ? "write" : "denied");
@@ -99835,15 +99927,17 @@ async function launchTuiAgentShell(opts) {
99835
99927
  chrome.hideMenu();
99836
99928
  setMainAgent("blocked", "approval");
99837
99929
  const elicitationSubtitle = described.message.length > 80 ? `${described.message.slice(0, 77)}\u2026` : described.message;
99838
- const id = await showComposerChoice(otui, r, chrome.dock, {
99930
+ const id = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99839
99931
  title: "Approve codex elicitation?",
99840
99932
  subtitle: elicitationSubtitle,
99841
99933
  cancelId: "deny",
99934
+ onOpen: () => chrome.blurComposer(),
99935
+ signal: foregroundOperation.signal,
99842
99936
  options: [
99843
99937
  { id: "allow", label: "Approve", description: "codex proceeds with this action", recommended: true },
99844
99938
  { id: "deny", label: "Deny", description: "codex's action is refused" }
99845
99939
  ]
99846
- });
99940
+ }));
99847
99941
  input.focus();
99848
99942
  setMainAgent("running", id === "allow" ? "write" : "denied");
99849
99943
  transcript.add(new otui.TextRenderable(r, {
@@ -99898,7 +99992,10 @@ async function launchTuiAgentShell(opts) {
99898
99992
  setMainAgent("blocked", "approval");
99899
99993
  setBusyPhase("waiting for your approval (menu above input)");
99900
99994
  chrome.hideMenu();
99901
- const choice = await pickShellApproval(otui, r, chrome.dock, cmd, approvalContext, destructive, meta?.credentials === true);
99995
+ const choice = await chrome.withOverlay(() => pickShellApproval(otui, r, chrome.dock, cmd, approvalContext, destructive, meta?.credentials === true, {
99996
+ onOpen: () => chrome.blurComposer(),
99997
+ signal: foregroundOperation.signal
99998
+ }));
99902
99999
  input.focus();
99903
100000
  if (choice === "deny") {
99904
100001
  transcript.add(new otui.TextRenderable(r, {
@@ -99942,17 +100039,19 @@ async function launchTuiAgentShell(opts) {
99942
100039
  id: `ask${uid++}`,
99943
100040
  content: otui.t`${otui.yellow("? ")} ${otui.dim(qShort)}`
99944
100041
  }));
99945
- const chosen = await showComposerChoice(otui, r, chrome.dock, {
100042
+ const chosen = await chrome.withOverlay(() => showComposerChoice(otui, r, chrome.dock, {
99946
100043
  title: req.question.length > 72 ? `${req.question.slice(0, 69)}\u2026` : req.question,
99947
100044
  subtitle: "Pick an option \xB7 Esc cancels",
99948
100045
  cancelId: "__cancel__",
100046
+ onOpen: () => chrome.blurComposer(),
100047
+ signal: foregroundOperation.signal,
99949
100048
  options: req.options.map((o) => ({
99950
100049
  id: o.id,
99951
100050
  label: o.label,
99952
100051
  description: o.description.length > 0 ? o.description : " ",
99953
100052
  ...o.recommended === true ? { recommended: true } : {}
99954
100053
  }))
99955
- });
100054
+ }));
99956
100055
  input.focus();
99957
100056
  if (chosen !== "__cancel__") {
99958
100057
  const picked = req.options.find((o) => o.id === chosen);
@@ -100414,14 +100513,15 @@ Staying in the current session.
100414
100513
  title: "Switch to auto mode?",
100415
100514
  subtitle: "Skips confirmation for EVERY action, including destructive commands. Only credential-touching commands still ask.",
100416
100515
  cancelId: "cancel",
100417
- options: [
100418
- { id: "confirm", label: "Confirm", description: "I understand the risk" },
100419
- { id: "cancel", label: "Cancel", description: "Keep the current mode", recommended: true }
100420
- ],
100516
+ enqueue: false,
100421
100517
  onBusy: () => {
100422
100518
  blockedByOpenDialog = true;
100423
100519
  chrome.showToast("Answer the open approval first, then retry /mode.");
100424
- }
100520
+ },
100521
+ options: [
100522
+ { id: "confirm", label: "Confirm", description: "I understand the risk" },
100523
+ { id: "cancel", label: "Cancel", description: "Keep the current mode", recommended: true }
100524
+ ]
100425
100525
  }));
100426
100526
  input.focus();
100427
100527
  if (blockedByOpenDialog) {
@@ -100462,16 +100562,17 @@ Staying in the current session.
100462
100562
  title: `Permission mode (current: ${permissionMode})`,
100463
100563
  subtitle: stored !== undefined ? `Project default: ${stored}` : "No project default set.",
100464
100564
  cancelId: permissionMode,
100565
+ enqueue: false,
100566
+ onBusy: () => {
100567
+ blockedByOpenDialog = true;
100568
+ chrome.showToast("Answer the open approval first, then retry /mode.");
100569
+ },
100465
100570
  options: PERMISSION_MODES.map((m) => ({
100466
100571
  id: m,
100467
100572
  label: m,
100468
100573
  description: MODE_PICKER_DESCRIPTIONS[m],
100469
100574
  recommended: m === permissionMode
100470
- })),
100471
- onBusy: () => {
100472
- blockedByOpenDialog = true;
100473
- chrome.showToast("Answer the open approval first, then retry /mode.");
100474
- }
100575
+ }))
100475
100576
  }));
100476
100577
  input.focus();
100477
100578
  if (blockedByOpenDialog) {
@@ -101064,6 +101165,7 @@ Staying in the current session.
101064
101165
  { id: "side", label: "Side-1", description: "read-only answer, outside main history (as before)" }
101065
101166
  ],
101066
101167
  cancelId: "side",
101168
+ enqueue: false,
101067
101169
  onBusy: () => {
101068
101170
  blockedByOpenDialog = true;
101069
101171
  chrome.showToast("Answer the open approval first, then resend.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.2.119",
3
+ "version": "0.2.121",
4
4
  "description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
5
5
  "private": false,
6
6
  "publishConfig": {