Skip to content

Commit 299aa91

Browse files
Merge pull request #1030 from corbitsdev/cl-7949-tui-micro-inlines
Inline TUI and agent micro-modules and merge the delivery queue trio
2 parents 94bcc4d + 9ff99c9 commit 299aa91

79 files changed

Lines changed: 572 additions & 563 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎docs/ARCHITECTURE.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ In TUI chat mode there is no completion gate — the session stays open across t
8282
- Wires `ask_operator` to an operator-gate event resolved by a modal
8383
- Mounts the OpenTUI host via `mountRunnerHost` (`src/tui/runner/host.ts`), which mounts `mountProductHost` (`src/tui/product-host.ts`) over the shell (`src/tui/shell/`)
8484
- Bridges reactor events to the OpenTUI host via a plain `EventEmitter`
85-
- **Mid-run injection** — Shell `session-queue` items drain at the parent
85+
- **Mid-run injection** — Shell `delivery-queue` items drain at the parent
8686
`tool.boundary` through `SessionPort.deliver`. Production `routeQueuedDelivery`
8787
live-injects in-flight parent-boundary steers via `agentProxy.deliver`
8888
(`Agent.deliver`) into one captured agent identity — never re-reading
@@ -220,7 +220,7 @@ The **`spawn_agent`** tool starts a fleet agent on a separate inference source (
220220

221221
Workers ask the spawning parent with **`ask_director`** (not the human). That parks a question while the worker stays `running`. On the TUI primary that arrives as an idle-send wake. On a nested orchestrator the question arrives as mailbox mail with an `awaiting_director` status — that is not terminal. Once a parked ask is surfaced (TUI wake, nested mailbox mail, or a successful `list_agents`), further `list_agents` calls fail closed until **`send_input`** answers or the ask is dropped — `list_agents` is not a poll. The parent answers with **`send_input`**, then continues. Escalate to the human with **`ask_operator`** only when the parent cannot resolve it.
222222

223-
When the parent TUI is not blocked in an in-flight tool call, the runner publishes an authoritative snapshot of currently pending top-level questions on each store notification, including empty snapshots before fleet-count updates. During synchronous session rotation, a runner-owned barrier suppresses both publications before delivery-generation invalidation, transcript clearing, and worker cancellation; successful reset reconciles a fresh snapshot before resuming asynchronous backend rebuild. The bridge drops resolved, cancelled, replaced, terminal, and removed asks and delivers each session/question identity once while pending. A coalesced wake starts only when the parent is not processing and every operator gate is closed, including parent-idle fleet holds where the shell stays busy. Worker gates do not manufacture parent processing. Replies use `send_input`'s `target` field with the worker session ID, never its shared catalog ID. Synthetic wakes use `SessionPort.deliver` through queued-delivery's idle-send path without entering the user follow-up queue or composer `/feedback` capture.
223+
When the parent TUI is not blocked in an in-flight tool call, the runner publishes an authoritative snapshot of currently pending top-level questions on each store notification, including empty snapshots before fleet-count updates. During synchronous session rotation, a runner-owned barrier suppresses both publications before delivery-generation invalidation, transcript clearing, and worker cancellation; successful reset reconciles a fresh snapshot before resuming asynchronous backend rebuild. The bridge drops resolved, cancelled, replaced, terminal, and removed asks and delivers each session/question identity once while pending. A coalesced wake starts only when the parent is not processing and every operator gate is closed, including parent-idle fleet holds where the shell stays busy. Worker gates do not manufacture parent processing. Replies use `send_input`'s `target` field with the worker session ID, never its shared catalog ID. Synthetic wakes use `SessionPort.deliver` through delivery-queue's idle-send path without entering the user follow-up queue or composer `/feedback` capture.
224224

225225
When profiles exist (local `.agents/agents/` and/or enabled **`kind: "agent"`** plugins, including **data-only** markdown plugins with no `index.ts`), the chat model also receives **`search_agents`** — a lexical index over profile id, description, and role text so the model can discover ids before calling `spawn_agent(agent=...)`. Default results are id, description, and spawn metadata (orchestrator flag, source). Pass `include_body=true` to include each match's loaded system prompt / body (truncated) so the parent can inspect plugin or Claude marketplace agents without `read_file` on paths outside the session cwd (path-escape blocks those roots by design; writes remain blocked). `spawn_agent` and `search_agents` are core tools on the primary session.
226226

‎docs/IMPLEMENTATION.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ the directors guard on; the full set of reactor and stream event types is
463463
treat that as canonical rather than this section or any other doc's partial
464464
list.
465465

466-
Mid-run queue/steer/interrupt state is a pure state machine in `src/tui/session-queue.ts` (interaction contract §3): `enqueue` (kind `"queue"`) and `enqueueSteer` (kind `"steer"`) share one pending pool, drained steer-first, then queue, both FIFO within their class. Mid-run gestures: Enter soft-steers (drain at the next **parent** `tool.boundary` — the parent tool finishing, not a child; parent-busy holds steers), Alt+Enter queues a follow-up (drain on **session-idle**: parent-idle and no live fleet lanes), Ctrl+C stops. Idle-with-fleet is shipped: with live fleet lanes the bridge holds the run busy after the parent turn settles (`fleet` events carry the live count), mid-hold Enter upgrades to an immediate new turn, and the last lane terminalizing releases the hold and drains follow-ups.
466+
Mid-run queue/steer/interrupt state is a pure state machine in `src/tui/delivery-queue.ts` (interaction contract §3): `enqueue` (kind `"queue"`) and `enqueueSteer` (kind `"steer"`) share one pending pool, drained steer-first, then queue, both FIFO within their class. Mid-run gestures: Enter soft-steers (drain at the next **parent** `tool.boundary` — the parent tool finishing, not a child; parent-busy holds steers), Alt+Enter queues a follow-up (drain on **session-idle**: parent-idle and no live fleet lanes), Ctrl+C stops. Idle-with-fleet is shipped: with live fleet lanes the bridge holds the run busy after the parent turn settles (`fleet` events carry the live count), mid-hold Enter upgrades to an immediate new turn, and the last lane terminalizing releases the hold and drains follow-ups.
467467

468468
### Lifecycle Hooks
469469

‎docs/TUI.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ row at a time down to its 3-row base — never the transcript
3434
(`COLLAPSE_ORDER` in `zones.ts`).
3535

3636
Horizontally, every surface sits inside one shared gutter
37-
(`resolveSideMargin`, `src/tui/geometry/margins.ts`) so the shell reads
37+
(`resolveSideMargin`, `src/tui/geometry/zones.ts`) so the shell reads
3838
as a single column of content rather than stacked panes.
3939
`resolveGeometry` always returns `layoutMode: "stack"` — full-width
4040
y-stack, no dual-column rail. Live workers paint in the agents strip
@@ -711,7 +711,7 @@ thing they were trying to deliver. It now reports `interrupt — N pending
711711
kept`: the run stops, the queue survives, and those messages are handed over
712712
at the interrupt itself (`doInterrupt` drains after `port.interrupt()`), not
713713
left waiting on an idle event the stop may never produce (`interrupt` in
714-
`session-queue.ts` no longer clears `items`).
714+
`delivery-queue.ts` no longer clears `items`).
715715

716716
**Fleet agent lanes on redirect.** Soft steer (Enter mid-run) and follow-up
717717
(queued drain) leave running workers alone — they never call

‎src/agent/agent-search.ts‎

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ import type { AgentTool } from "@intx/agent";
33
import type { ToolDefinition } from "@intx/types/runtime";
44
import { type } from "arktype";
55
import { scrubSecretShapedContent } from "../plugins/tool-result-secret-scrub.js";
6+
import {
7+
lexicalFields,
8+
scoreLexical,
9+
tokenizeLexical,
10+
} from "./lexical-rank.js";
611
import type { AgentProfile } from "./profiles.js";
712

8-
function tokenize(text: string): string[] {
9-
return text.toLowerCase().match(/[a-z0-9]+/g) ?? [];
10-
}
11-
1213
function profileSearchText(profile: AgentProfile): string {
1314
const parts = [
1415
profile.id,
@@ -30,27 +31,18 @@ export function createAgentIndex(
3031
profile: AgentProfile,
3132
queryTokens: string[],
3233
rawQuery: string,
33-
): number => {
34-
const idTokens = tokenize(profile.id);
35-
const blob = profileSearchText(profile).toLowerCase();
36-
const blobTokens = new Set(tokenize(blob));
37-
let total = 0;
38-
for (const token of queryTokens) {
39-
if (idTokens.includes(token)) total += 3;
40-
else if (blobTokens.has(token)) total += 1;
41-
else if (profile.id.toLowerCase().includes(token)) total += 0.75;
42-
else if (blob.includes(token)) total += 0.25;
43-
}
44-
if (profile.id.toLowerCase().includes(rawQuery)) total += 1;
45-
if ((profile.description ?? "").toLowerCase().includes(rawQuery))
46-
total += 0.5;
47-
return total;
48-
};
34+
): number =>
35+
scoreLexical(
36+
lexicalFields(profile.id, profileSearchText(profile)),
37+
queryTokens,
38+
rawQuery,
39+
) +
40+
((profile.description ?? "").toLowerCase().includes(rawQuery) ? 0.5 : 0);
4941

5042
return {
5143
search(query: string, limit = 12): AgentProfile[] {
5244
const rawQuery = query.toLowerCase().trim();
53-
const queryTokens = tokenize(query);
45+
const queryTokens = tokenizeLexical(query);
5446
const profiles = getProfiles();
5547
if (queryTokens.length === 0) return profiles.slice(0, limit);
5648
return profiles

‎src/agent/directors/bruckheimer/index.ts‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎src/agent/directors/builder/index.ts‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎src/agent/directors/counsel/index.ts‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎src/agent/directors/critic/index.ts‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎src/agent/directors/draper/index.ts‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

‎src/agent/directors/emil/index.ts‎

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)