neko-harness 0.4.3 → 0.4.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.
package/dist/neko.js CHANGED
@@ -80,7 +80,7 @@ function updateAction(input) {
80
80
  return "install";
81
81
  return "none";
82
82
  }
83
- var RUNNING_VERSION = "0.4.3", APPLICATION_PROTOCOL = 6, ApplicationProtocolError;
83
+ var RUNNING_VERSION = "0.4.4", APPLICATION_PROTOCOL = 6, ApplicationProtocolError;
84
84
  var init_application_version = __esm(() => {
85
85
  ApplicationProtocolError = class ApplicationProtocolError extends Error {
86
86
  constructor() {
@@ -1060,6 +1060,52 @@ var init_input = __esm(() => {
1060
1060
  NekoInput = defineEntry("app.neko.input");
1061
1061
  });
1062
1062
 
1063
+ // packages/core/src/queued.ts
1064
+ function queuedUserInput(raw) {
1065
+ const item = raw;
1066
+ if (item.mode !== "steer" && item.mode !== "followUp")
1067
+ return;
1068
+ if (item.entry?.kind !== NekoInput.kind)
1069
+ return;
1070
+ const data = item.entry.data;
1071
+ if (!data || data.jobReport || data.subagentRoundId)
1072
+ return;
1073
+ const defaultPrompt = Array.isArray(item.content) ? savedDefaultImagePrompt(item.content, data.defaultImagePrompt) : undefined;
1074
+ const content = defaultPrompt && Array.isArray(item.content) ? item.content.slice(1) : item.content;
1075
+ const skill = data.skill ? { name: data.skill.name, args: data.skill.args } : undefined;
1076
+ return {
1077
+ id: item.id,
1078
+ mode: item.mode,
1079
+ text: skill ? `/skill:${skill.name}${skill.args ? ` ${skill.args}` : ""}` : textOf(content),
1080
+ images: data.images?.length ?? 0,
1081
+ ...skill ? { skill } : {}
1082
+ };
1083
+ }
1084
+ function projectQueued(view) {
1085
+ const items = view.docs["pi.inbox"]?.items ?? [];
1086
+ return items.flatMap((raw) => {
1087
+ const input = queuedUserInput(raw);
1088
+ if (!input)
1089
+ return [];
1090
+ const { text, ...rest } = input;
1091
+ return [{ ...rest, preview: clip(text) }];
1092
+ });
1093
+ }
1094
+ var QUEUED_PREVIEW_CHARS = 300, textOf = (content) => {
1095
+ if (typeof content === "string")
1096
+ return content;
1097
+ if (!Array.isArray(content))
1098
+ return "";
1099
+ return content.flatMap((b) => b && b.type === "text" && typeof b.text === "string" ? [b.text] : []).join("");
1100
+ }, clip = (text) => {
1101
+ const chars = [...text.replace(/\s+/g, " ").trim()];
1102
+ return chars.length > QUEUED_PREVIEW_CHARS ? `${chars.slice(0, QUEUED_PREVIEW_CHARS - 1).join("")}\u2026` : chars.join("");
1103
+ };
1104
+ var init_queued = __esm(() => {
1105
+ init_image_prompt();
1106
+ init_input();
1107
+ });
1108
+
1063
1109
  // packages/core/src/workspace.ts
1064
1110
  import { accessSync, constants, realpathSync, statSync } from "fs";
1065
1111
  import { isAbsolute, resolve as resolve2 } from "path";
@@ -1379,6 +1425,7 @@ function projectChatView(view, modelLabel, options = {}) {
1379
1425
  },
1380
1426
  cwd: savedWorkspace(agent?.cwd),
1381
1427
  busy: live.run !== undefined,
1428
+ queued: projectQueued(view),
1382
1429
  status,
1383
1430
  usage: {
1384
1431
  input: usage.input,
@@ -1491,6 +1538,7 @@ var WRITE_DIFF_MAX_LINES = 2000, WRITE_DIFF_MAX_BYTES;
1491
1538
  var init_projection = __esm(() => {
1492
1539
  init_image_prompt();
1493
1540
  init_input();
1541
+ init_queued();
1494
1542
  init_workspace();
1495
1543
  WRITE_DIFF_MAX_BYTES = 64 * 1024;
1496
1544
  });
@@ -3207,6 +3255,14 @@ var createResourceSnapshots = (load, submission) => {
3207
3255
  discard(id, requestId) {
3208
3256
  conversations.get(id)?.pending.delete(requestId);
3209
3257
  },
3258
+ move(id, from, to) {
3259
+ const pending = conversations.get(id)?.pending;
3260
+ const snapshot = pending?.get(from);
3261
+ if (!pending || !snapshot)
3262
+ return;
3263
+ pending.delete(from);
3264
+ pending.set(to, snapshot);
3265
+ },
3210
3266
  forget(id) {
3211
3267
  conversations.delete(id);
3212
3268
  }
@@ -4495,6 +4551,7 @@ import {
4495
4551
  createRegistry,
4496
4552
  defineDoc as defineDoc5,
4497
4553
  Harness,
4554
+ InboxDoc as InboxDoc2,
4498
4555
  LiveDoc as importLiveDoc,
4499
4556
  MemoryStorage,
4500
4557
  UsageDoc as UsageDoc2,
@@ -4843,6 +4900,57 @@ async function createNekoRuntime(options = {}) {
4843
4900
  },
4844
4901
  abort() {
4845
4902
  return target.abort(context);
4903
+ },
4904
+ async withdraw(submissionId) {
4905
+ const id = submissionId;
4906
+ const inbox = await harness.snapshot(InboxDoc2, target.id, context);
4907
+ const item = inbox?.items.find((i) => i.id === id);
4908
+ const input = item ? queuedUserInput(item) : undefined;
4909
+ if (item && !input)
4910
+ return { result: "unknown" };
4911
+ const requestId = (await (await harness.submission(id, context))?.status(context))?.requestId;
4912
+ const outcome = await harness.abortSubmission(id, context, target.id);
4913
+ if (outcome !== "aborted") {
4914
+ return { result: outcome === "already_placed" ? "placed" : outcome === "settled" ? "settled" : "unknown" };
4915
+ }
4916
+ if (requestId !== undefined)
4917
+ resourceSnapshots.discard(target.id, requestId);
4918
+ await metadata.reconcile(target.id);
4919
+ return { result: "withdrawn", ...input ? { text: input.text, images: input.images } : {} };
4920
+ },
4921
+ async steer(submissionId) {
4922
+ const id = submissionId;
4923
+ const inbox = await harness.snapshot(InboxDoc2, target.id, context);
4924
+ const item = inbox?.items.find((i) => i.id === id);
4925
+ const input = item ? queuedUserInput(item) : undefined;
4926
+ if (item && (!input || item.mode === "write"))
4927
+ return { result: "unknown" };
4928
+ if (item && input?.mode === "steer")
4929
+ return { result: "steered", id: submissionId };
4930
+ const requestId = (await (await harness.submission(id, context))?.status(context))?.requestId;
4931
+ const outcome = await harness.abortSubmission(id, context, target.id);
4932
+ if (outcome !== "aborted" || !item || !input) {
4933
+ return { result: outcome === "already_placed" ? "placed" : outcome === "settled" ? "settled" : "unknown" };
4934
+ }
4935
+ const steerRequestId = requestId !== undefined ? `steer:${requestId}` : crypto.randomUUID();
4936
+ try {
4937
+ const next = await target.submit({
4938
+ type: "input",
4939
+ content: item.content,
4940
+ ...item.entry ? { entry: item.entry } : {},
4941
+ requestId: steerRequestId,
4942
+ whenBusy: "steer"
4943
+ }, context);
4944
+ if (requestId !== undefined)
4945
+ resourceSnapshots.move(target.id, requestId, steerRequestId);
4946
+ await metadata.reconcile(target.id);
4947
+ return { result: "steered", id: next.id };
4948
+ } catch {
4949
+ if (requestId !== undefined)
4950
+ resourceSnapshots.discard(target.id, requestId);
4951
+ await metadata.reconcile(target.id);
4952
+ return { result: "withdrawn", text: input.text, images: input.images };
4953
+ }
4846
4954
  }
4847
4955
  });
4848
4956
  const rootSession = makeSession(conversation);
@@ -5163,6 +5271,7 @@ var init_runtime = __esm(() => {
5163
5271
  init_invoke();
5164
5272
  init_prompt();
5165
5273
  init_resources();
5274
+ init_queued();
5166
5275
  init_search_providers();
5167
5276
  init_session_metadata();
5168
5277
  init_subagent_usage();
@@ -5238,6 +5347,7 @@ var init_src = __esm(() => {
5238
5347
  init_jobs();
5239
5348
  init_projection();
5240
5349
  init_frontmatter();
5350
+ init_queued();
5241
5351
  init_runtime();
5242
5352
  init_search_providers();
5243
5353
  init_session_metadata();
@@ -5368,7 +5478,7 @@ function contract(name, def) {
5368
5478
  ]));
5369
5479
  return remote(name, { ...def, host: hostNamed(GATEWAY_HOST), variants });
5370
5480
  }
5371
- var GATEWAY_HOST = "neko", rpc = (args, result) => [args, result], str, num, bool, nil, integer, nullableString, phase, level, thinking, model, change, usage, image, skill, call, DelegationSchema, SubagentSummarySchema, jobStatus, JobSummarySchema, JobOutputSchema, ChatViewSchema, SessionSummarySchema, DirectoryStateSchema, WorkspaceSummarySchema, WorkspaceStateSchema, credentialStatus, CredentialStateSchema, AttachmentSchema, chatInput, NekoSessionDirectory, NekoSessionManagement, resize, inputLimits, modelInfo, NekoModels, imageChunk, NekoSubagent, NekoChat, browse, page, NekoWorkspaces, provider, NekoCredentials, SearchSettingsStateSchema, NekoSearchSettings, contextSource, ContextSettingsStateSchema, nullable = (schema) => Type5.Union([schema, nil]), ContextSettingsPatchSchema, NekoContextSettings, FileCandidatesSchema, NekoWorkspaceFiles, marketSkill, preview, scope, installResult, NekoSkillMarket, ApplicationInfoSchema, NekoApplicationInfo;
5481
+ var GATEWAY_HOST = "neko", rpc = (args, result) => [args, result], str, num, bool, nil, integer, nullableString, phase, level, thinking, model, change, usage, image, skill, call, DelegationSchema, SubagentSummarySchema, jobStatus, JobSummarySchema, JobOutputSchema, QueuedInputSchema, WithdrawResultSchema, SteerResultSchema, ChatViewSchema, SessionSummarySchema, DirectoryStateSchema, WorkspaceSummarySchema, WorkspaceStateSchema, credentialStatus, CredentialStateSchema, AttachmentSchema, chatInput, NekoSessionDirectory, NekoSessionManagement, resize, inputLimits, modelInfo, NekoModels, imageChunk, NekoSubagent, NekoChat, browse, page, NekoWorkspaces, provider, NekoCredentials, SearchSettingsStateSchema, NekoSearchSettings, contextSource, ContextSettingsStateSchema, nullable = (schema) => Type5.Union([schema, nil]), ContextSettingsPatchSchema, NekoContextSettings, FileCandidatesSchema, NekoWorkspaceFiles, marketSkill, preview, scope, installResult, NekoSkillMarket, ApplicationInfoSchema, NekoApplicationInfo;
5372
5482
  var init_contract = __esm(() => {
5373
5483
  str = Type5.String();
5374
5484
  num = Type5.Number();
@@ -5464,10 +5574,29 @@ var init_contract = __esm(() => {
5464
5574
  truncated: bool,
5465
5575
  dropped: integer
5466
5576
  });
5577
+ QueuedInputSchema = Type5.Object({
5578
+ id: integer,
5579
+ mode: Type5.Enum(["steer", "followUp"]),
5580
+ preview: str,
5581
+ images: integer,
5582
+ skill: Type5.Optional(Type5.Object({ name: str, args: str }))
5583
+ });
5584
+ WithdrawResultSchema = Type5.Object({
5585
+ result: Type5.Enum(["withdrawn", "placed", "settled", "unknown"]),
5586
+ text: Type5.Optional(str),
5587
+ images: Type5.Optional(integer)
5588
+ });
5589
+ SteerResultSchema = Type5.Object({
5590
+ result: Type5.Enum(["steered", "withdrawn", "placed", "settled", "unknown"]),
5591
+ id: Type5.Optional(integer),
5592
+ text: Type5.Optional(str),
5593
+ images: Type5.Optional(integer)
5594
+ });
5467
5595
  ChatViewSchema = Type5.Object({
5468
5596
  historyBefore: Type5.Optional(Type5.Union([integer, nil])),
5469
5597
  agents: Type5.Optional(Type5.Array(SubagentSummarySchema)),
5470
5598
  jobs: Type5.Optional(Type5.Array(JobSummarySchema)),
5599
+ queued: Type5.Optional(Type5.Array(QueuedInputSchema)),
5471
5600
  rounds: Type5.Optional(Type5.Array(DelegationSchema)),
5472
5601
  subagents: Type5.Optional(Type5.Array(DelegationSchema)),
5473
5602
  taskUsage: Type5.Optional(usage),
@@ -5672,6 +5801,8 @@ var init_contract = __esm(() => {
5672
5801
  whenBusy: Type5.Optional(Type5.Enum(["steer", "followUp"]))
5673
5802
  }, { additionalProperties: false }), nil),
5674
5803
  abort: rpc(nil, nil),
5804
+ withdraw: rpc(Type5.Object({ id: integer }, { additionalProperties: false }), WithdrawResultSchema),
5805
+ steer: rpc(Type5.Object({ id: integer }, { additionalProperties: false }), SteerResultSchema),
5675
5806
  usage: rpc(nil, usage),
5676
5807
  skills: rpc(nil, Type5.Array(Type5.Object({ name: str, description: str, location: str, level }))),
5677
5808
  jobOutput: rpc(Type5.Object({ jobId: str, since: Type5.Optional(integer) }, { additionalProperties: false }), JobOutputSchema),
@@ -6168,6 +6299,25 @@ function jobsClient(chat) {
6168
6299
  }
6169
6300
  };
6170
6301
  }
6302
+ function queueClient(chat) {
6303
+ const supported = () => chat.view.value?.queued !== undefined;
6304
+ return {
6305
+ get supported() {
6306
+ return supported();
6307
+ },
6308
+ list: () => chat.view.value?.queued ?? [],
6309
+ async steer(id) {
6310
+ if (!supported())
6311
+ throw new Error(QUEUE_UNSUPPORTED);
6312
+ return chat.steer({ id });
6313
+ },
6314
+ async withdraw(id) {
6315
+ if (!supported())
6316
+ throw new Error(QUEUE_UNSUPPORTED);
6317
+ return chat.withdraw({ id });
6318
+ }
6319
+ };
6320
+ }
6171
6321
  function createGatewayConnection(link, serverId) {
6172
6322
  let protocolMismatch = false;
6173
6323
  const linkClosed = new AbortController;
@@ -6364,7 +6514,7 @@ function deadline(work, signal) {
6364
6514
  signal?.removeEventListener("abort", abort);
6365
6515
  });
6366
6516
  }
6367
- var GatewayIdentityError, JOBS_UNSUPPORTED = "This gateway does not support background jobs. Restart the gateway to enable them.";
6517
+ var GatewayIdentityError, JOBS_UNSUPPORTED = "This gateway does not support background jobs. Restart the gateway to enable them.", QUEUE_UNSUPPORTED = "This gateway does not support queued message controls. Restart the gateway to enable them.";
6368
6518
  var init_client_session = __esm(() => {
6369
6519
  init_application_version();
6370
6520
  init_contract();
@@ -18578,9 +18728,9 @@ var init_labels = __esm(() => {
18578
18728
  return shortcutHints(["\u2191\u2193", "Select"], ["Enter", "Open"], ["Esc", "Close"]);
18579
18729
  },
18580
18730
  idleHints: "Enter Send \xB7 /help Keys",
18581
- busyHints: "Enter Steer \xB7 Esc Stop",
18731
+ busyHints: "Enter Queue \xB7 Esc Stop",
18582
18732
  idleCompact: "Enter Send \xB7 /help Keys",
18583
- busyCompact: "Enter Steer \xB7 Esc Stop"
18733
+ busyCompact: "Enter Queue \xB7 Esc Stop"
18584
18734
  };
18585
18735
  });
18586
18736
 
@@ -21294,7 +21444,7 @@ function buildHelloResultSchema() {
21294
21444
  })
21295
21445
  });
21296
21446
  }
21297
- var MOBILE_LIMITS, MOBILE_API_VERSIONS, MOBILE_CAPABILITIES, MOBILE_CLOSE_REVOKED = 4401, MOBILE_CLOSE_INCOMPATIBLE = 4402, MOBILE_CLOSE_SLOW_CONSUMER = 4408, MobileHelloParams, opt, str2, int, nullable2 = (schema) => Type7.Union([schema, Type7.Null()]), MobileContentRefSchema, MobileImageRefSchema, MobileToolItemSchema, MobileChatItemSchema, MobileStreamingSchema, MobileUsageSchema, MobileSubagentRoundSchema, MobileAgentSchema, MobileChatStatusSchema, MobileChatSnapshotSchema, MobileWorkspaceSchema, MobileSessionSummarySchema, MobileApprovalSchema, sessionListParams, sessionListResult, subscription, pageResult, pageParams, chunkResult, MOBILE_API_V1_METHODS, patchBody, MOBILE_API_V1_NOTIFICATIONS;
21447
+ var MOBILE_LIMITS, MOBILE_API_VERSIONS, MOBILE_CAPABILITIES, MOBILE_CLOSE_REVOKED = 4401, MOBILE_CLOSE_INCOMPATIBLE = 4402, MOBILE_CLOSE_SLOW_CONSUMER = 4408, MobileHelloParams, opt, str2, int, nullable2 = (schema) => Type7.Union([schema, Type7.Null()]), MobileContentRefSchema, MobileImageRefSchema, MobileToolItemSchema, MobileChatItemSchema, MobileStreamingSchema, MobileUsageSchema, MobileSubagentRoundSchema, MobileAgentSchema, MobileQueuedSchema, MobileChatStatusSchema, MobileChatSnapshotSchema, MobileWorkspaceSchema, MobileSessionSummarySchema, MobileApprovalSchema, sessionListParams, sessionListResult, subscription, pageResult, pageParams, chunkResult, MOBILE_API_V1_METHODS, patchBody, MOBILE_API_V1_NOTIFICATIONS;
21298
21448
  var init_protocol = __esm(() => {
21299
21449
  init_application_version();
21300
21450
  MOBILE_LIMITS = {
@@ -21426,8 +21576,15 @@ var init_protocol = __esm(() => {
21426
21576
  roundCount: int,
21427
21577
  approvalCount: int
21428
21578
  });
21579
+ MobileQueuedSchema = Type7.Object({
21580
+ id: int,
21581
+ mode: Type7.Union([Type7.Literal("steer"), Type7.Literal("followUp")]),
21582
+ preview: Type7.String(),
21583
+ images: int
21584
+ });
21429
21585
  MobileChatStatusSchema = Type7.Object({
21430
21586
  busy: Type7.Boolean(),
21587
+ queued: opt(Type7.Array(MobileQueuedSchema)),
21431
21588
  status: nullable2(str2),
21432
21589
  usage: MobileUsageSchema,
21433
21590
  taskUsage: opt(MobileUsageSchema),
@@ -21511,6 +21668,34 @@ var init_protocol = __esm(() => {
21511
21668
  params: Type7.Object({ ...subscription, requestId: Type7.String({ minLength: 1, maxLength: 128 }) }),
21512
21669
  result: Type7.Object({ status: Type7.Union([Type7.Literal("accepted"), Type7.Literal("unknown")]) })
21513
21670
  },
21671
+ "chat.steer": {
21672
+ params: Type7.Object({ ...subscription, id: int }),
21673
+ result: Type7.Object({
21674
+ result: Type7.Union([
21675
+ Type7.Literal("steered"),
21676
+ Type7.Literal("withdrawn"),
21677
+ Type7.Literal("placed"),
21678
+ Type7.Literal("settled"),
21679
+ Type7.Literal("unknown")
21680
+ ]),
21681
+ id: opt(int),
21682
+ text: opt(Type7.String()),
21683
+ images: opt(int)
21684
+ })
21685
+ },
21686
+ "chat.withdraw": {
21687
+ params: Type7.Object({ ...subscription, id: int }),
21688
+ result: Type7.Object({
21689
+ result: Type7.Union([
21690
+ Type7.Literal("withdrawn"),
21691
+ Type7.Literal("placed"),
21692
+ Type7.Literal("settled"),
21693
+ Type7.Literal("unknown")
21694
+ ]),
21695
+ text: opt(Type7.String()),
21696
+ images: opt(int)
21697
+ })
21698
+ },
21514
21699
  "chat.abort": { params: Type7.Object(subscription), result: Type7.Object({ accepted: Type7.Boolean() }) },
21515
21700
  "subagents.open": {
21516
21701
  params: Type7.Object({ ...subscription, agentId: opt(Type7.String({ minLength: 1 })), taskId: opt(int) }),
@@ -21770,6 +21955,9 @@ function mapStatus(view, options = {}) {
21770
21955
  const latest = view.compaction?.latest;
21771
21956
  return {
21772
21957
  busy: view.busy,
21958
+ ...view.queued === undefined ? {} : {
21959
+ queued: view.queued.map(({ id, mode, preview, images }) => ({ id, mode, preview, images }))
21960
+ },
21773
21961
  status: view.status,
21774
21962
  usage: mapUsage(view.usage),
21775
21963
  ...view.taskUsage === undefined ? {} : { taskUsage: mapUsage(view.taskUsage) },
@@ -22258,6 +22446,10 @@ class MobileAdapter {
22258
22446
  return this.chatSubmit(params);
22259
22447
  case "chat.submissionStatus":
22260
22448
  return this.chatSubmissionStatus(params);
22449
+ case "chat.steer":
22450
+ return this.chatSteer(params);
22451
+ case "chat.withdraw":
22452
+ return this.chatWithdraw(params);
22261
22453
  case "chat.abort":
22262
22454
  return this.chatAbort(params);
22263
22455
  case "subagents.open":
@@ -22487,6 +22679,16 @@ class MobileAdapter {
22487
22679
  const accepted = await this.runtime.submissionAccepted(state.sessionId, params.requestId);
22488
22680
  return { status: accepted ? "accepted" : "unknown" };
22489
22681
  }
22682
+ async chatSteer(params) {
22683
+ const state = this.requireChat(params);
22684
+ this.assertAuthorized();
22685
+ return remote2(() => state.chat.steer({ id: params.id }), "rejected");
22686
+ }
22687
+ async chatWithdraw(params) {
22688
+ const state = this.requireChat(params);
22689
+ this.assertAuthorized();
22690
+ return remote2(() => state.chat.withdraw({ id: params.id }), "rejected");
22691
+ }
22490
22692
  async chatAbort(params) {
22491
22693
  const state = this.requireChat(params);
22492
22694
  this.assertAuthorized();
@@ -41339,6 +41541,8 @@ function serveSessions(host, runtime, context) {
41339
41541
  await projection.value.session.abort();
41340
41542
  return null;
41341
41543
  },
41544
+ withdraw: ({ id }) => projection.value.session.withdraw(id),
41545
+ steer: ({ id }) => projection.value.session.steer(id),
41342
41546
  skills: () => runtime.listSkills(projection.value.session.id),
41343
41547
  jobOutput: async ({ jobId, since }) => {
41344
41548
  try {
@@ -41416,6 +41620,7 @@ var init_session_host = __esm(() => {
41416
41620
  agent: { model: null, thinkingLevel: null },
41417
41621
  cwd: "",
41418
41622
  busy: false,
41623
+ queued: [],
41419
41624
  status: null,
41420
41625
  usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 },
41421
41626
  items: [],
@@ -42939,8 +43144,7 @@ function helpLines(platform = process.platform) {
42939
43144
  rows.push(theme.accent(title), ...hints.map(([key, description]) => shortcutHints([key, description])), "");
42940
43145
  };
42941
43146
  section("Chat", [
42942
- ["Enter", "Send; steer while running"],
42943
- ["Alt+Enter", "Queue while running"],
43147
+ ["Enter", "Send; queue while running"],
42944
43148
  ["Esc", "Stop a running task or blocking compaction"],
42945
43149
  ["Esc Esc", "Clear draft when idle (press twice quickly)"],
42946
43150
  ["Up / Down", "Browse previous inputs in this session"],
@@ -42977,6 +43181,12 @@ function helpLines(platform = process.platform) {
42977
43181
  ["End", "Jump to the newest output"],
42978
43182
  ["\u2190", "Back"]
42979
43183
  ]);
43184
+ section("Queue", [
43185
+ ["Alt+\u2191", "Select queued messages above the editor"],
43186
+ ["\u2191 / \u2193", "Move between queued messages"],
43187
+ ["Enter", "Steer the selected message (joins the run after the current tool round)"],
43188
+ ["Esc", "Withdraw the selected message into the editor; the run keeps going"]
43189
+ ]);
42980
43190
  section("Web search", [
42981
43191
  ["/search", "Choose the web search provider"],
42982
43192
  ["Enter", "Apply the highlighted provider"]
@@ -43180,7 +43390,7 @@ function createAppLayout(parts) {
43180
43390
  parts.approval.height = Math.min(10, Math.max(7, Math.floor(v.height / 2)));
43181
43391
  parts.footer.panelOpen = parts.panelOpen();
43182
43392
  parts.editor.maxRows = parts.panelOpen() ? 3 : v.height >= 24 ? 7 : 5;
43183
- parts.panel.height = Math.max(1, v.height - (parts.approvalVisible?.() ? parts.approval?.height ?? 0 : 0) - Math.min(7, Math.max(3, parts.editor.render(v.width).length)) - 2 - Math.min(1, parts.notices.render(v.width).length) - (parts.busyVisible?.() ? Math.min(2, parts.busy?.render(v.width).length ?? 0) : 0));
43393
+ parts.panel.height = Math.max(1, v.height - (parts.approvalVisible?.() ? parts.approval?.height ?? 0 : 0) - Math.min(7, Math.max(3, parts.editor.render(v.width).length)) - 2 - Math.min(1, parts.notices.render(v.width).length) - (parts.busyVisible?.() ? Math.min(2, parts.busy?.render(v.width).length ?? 0) : 0) - (parts.queueVisible?.() ? Math.min(3, parts.queue?.render(v.width).length ?? 0) : 0));
43184
43394
  return usableSize(v.width, v.height);
43185
43395
  };
43186
43396
  return new VStack([
@@ -43198,6 +43408,12 @@ function createAppLayout(parts) {
43198
43408
  shrink: 0,
43199
43409
  visible: (v) => normal(v) && (parts.busyVisible?.() ?? false)
43200
43410
  },
43411
+ {
43412
+ component: parts.queue ?? new Text8("", 0, 0),
43413
+ maxSize: 3,
43414
+ shrink: 0,
43415
+ visible: (v) => normal(v) && (parts.queueVisible?.() ?? false)
43416
+ },
43201
43417
  {
43202
43418
  component: parts.approval ?? new Text8("", 0, 0),
43203
43419
  shrink: 0,
@@ -43210,6 +43426,105 @@ function createAppLayout(parts) {
43210
43426
  var usableSize = (width, height) => width >= 40 && height >= 10;
43211
43427
  var init_layout = () => {};
43212
43428
 
43429
+ // packages/tui/src/queue-ui.ts
43430
+ import { matchesKey as matchesKey10, truncateToWidth as truncateToWidth6 } from "@earendil-works/pi-tui";
43431
+
43432
+ class QueueRow {
43433
+ #items = [];
43434
+ #selected;
43435
+ setItems(items) {
43436
+ this.#items = items;
43437
+ if (items.length === 0)
43438
+ this.#selected = undefined;
43439
+ else if (this.#selected !== undefined)
43440
+ this.#selected = Math.min(this.#selected, items.length - 1);
43441
+ }
43442
+ get visible() {
43443
+ return this.#items.length > 0;
43444
+ }
43445
+ get selecting() {
43446
+ return this.#selected !== undefined;
43447
+ }
43448
+ get current() {
43449
+ return this.#selected === undefined ? undefined : this.#items[this.#selected];
43450
+ }
43451
+ select() {
43452
+ if (this.#items.length === 0)
43453
+ return false;
43454
+ this.#selected = this.#items.length - 1;
43455
+ return true;
43456
+ }
43457
+ clear() {
43458
+ this.#selected = undefined;
43459
+ }
43460
+ move(delta) {
43461
+ if (this.#selected === undefined)
43462
+ return;
43463
+ const next = this.#selected + delta;
43464
+ if (next >= this.#items.length)
43465
+ this.#selected = undefined;
43466
+ else
43467
+ this.#selected = Math.max(0, next);
43468
+ }
43469
+ render(width) {
43470
+ const total = this.#items.length;
43471
+ if (total === 0)
43472
+ return [];
43473
+ const end = this.#selected === undefined ? total : Math.max(this.#selected + 1, Math.min(total, QUEUE_ROWS));
43474
+ const start = Math.max(0, end - QUEUE_ROWS);
43475
+ const rows = this.#items.slice(start, end).map((item, offset) => {
43476
+ const picked = start + offset === this.#selected;
43477
+ const text = `${modeLabel(item.mode)} \xB7 ${content2(item)}`;
43478
+ return truncateToWidth6(picked ? ` ${theme.accent(`\u203A ${text}`)}` : ` ${theme.muted(text)}`, width);
43479
+ });
43480
+ const earlier = start > 0 ? `${start} earlier \xB7 ` : "";
43481
+ const later = end < total ? `${total - end} newer \xB7 ` : "";
43482
+ const hint = this.#selected === undefined ? shortcutHints(["Alt+\u2191", "Select queued"]) : shortcutHints(["Enter", "Steer"], ["Esc", "Withdraw"], ["\u2191/\u2193", "Move"]);
43483
+ rows.push(truncateToWidth6(theme.dim(` ${earlier}${later}${hint}`), width));
43484
+ return rows;
43485
+ }
43486
+ invalidate() {}
43487
+ }
43488
+ function queueKeyAction(row, data, autocompleteOpen) {
43489
+ if (!row.selecting)
43490
+ return matchesKey10(data, "alt+up") && row.visible && !autocompleteOpen ? "select" : undefined;
43491
+ if (matchesKey10(data, "up"))
43492
+ return "up";
43493
+ if (matchesKey10(data, "down"))
43494
+ return "down";
43495
+ if (matchesKey10(data, "enter"))
43496
+ return "steer";
43497
+ if (matchesKey10(data, "escape"))
43498
+ return "withdraw";
43499
+ return "leave";
43500
+ }
43501
+ function restoreText(existing, text) {
43502
+ return existing.trim() ? `${existing}
43503
+ ${text}` : text;
43504
+ }
43505
+ function steerNotice(outcome) {
43506
+ if (outcome.result === "steered")
43507
+ return { message: "Message will steer the current run.", level: "info" };
43508
+ if (outcome.result === "withdrawn")
43509
+ return { message: "Could not steer; the message was withdrawn into the editor.", level: "warning" };
43510
+ if (outcome.result === "unknown")
43511
+ return { message: "That message is no longer queued.", level: "warning" };
43512
+ return { message: "That message was already sent and cannot be steered.", level: "warning" };
43513
+ }
43514
+ function withdrawNotice(outcome) {
43515
+ if (outcome.result === "withdrawn")
43516
+ return outcome.images ? { message: "Message withdrawn into the editor. Images are not restored; attach them again.", level: "warning" } : { message: "Message withdrawn into the editor.", level: "info" };
43517
+ if (outcome.result === "unknown")
43518
+ return { message: "That message is no longer queued.", level: "warning" };
43519
+ return { message: "That message was already sent and cannot be withdrawn.", level: "warning" };
43520
+ }
43521
+ var QUEUE_ROWS = 2, QUEUE_BLOCK_LINES, modeLabel = (mode) => mode === "steer" ? "Steer" : "Queued", oneLine3 = (text) => text.replace(/\s+/g, " ").trim(), content2 = (item) => oneLine3(item.preview) || (item.images > 0 ? `[${item.images} image${item.images > 1 ? "s" : ""}]` : "");
43522
+ var init_queue_ui = __esm(() => {
43523
+ init_shortcut_hints();
43524
+ init_theme();
43525
+ QUEUE_BLOCK_LINES = QUEUE_ROWS + 1;
43526
+ });
43527
+
43213
43528
  // packages/tui/src/search-ui.ts
43214
43529
  function searchItems(settings, credentials) {
43215
43530
  if (!settings)
@@ -43258,7 +43573,7 @@ var init_search_ui = __esm(() => {
43258
43573
 
43259
43574
  // packages/tui/src/skill-market-ui.ts
43260
43575
  import { ChordError as ChordError6 } from "@earendil-works/chord";
43261
- import { Markdown as Markdown3, matchesKey as matchesKey10, wrapTextWithAnsi as wrapTextWithAnsi5 } from "@earendil-works/pi-tui";
43576
+ import { Markdown as Markdown3, matchesKey as matchesKey11, wrapTextWithAnsi as wrapTextWithAnsi5 } from "@earendil-works/pi-tui";
43262
43577
 
43263
43578
  class SkillDetailView {
43264
43579
  #skill = null;
@@ -43297,11 +43612,11 @@ class SkillDetailView {
43297
43612
  }
43298
43613
  handleKey(data) {
43299
43614
  if (this.#confirm) {
43300
- if (matchesKey10(data, "y")) {
43615
+ if (matchesKey11(data, "y")) {
43301
43616
  const pending = this.#confirm;
43302
43617
  this.#confirm = null;
43303
43618
  this.run(pending.run);
43304
- } else if (matchesKey10(data, "n")) {
43619
+ } else if (matchesKey11(data, "n")) {
43305
43620
  this.#confirm = null;
43306
43621
  }
43307
43622
  return true;
@@ -43310,17 +43625,17 @@ class SkillDetailView {
43310
43625
  return true;
43311
43626
  const skill = this.#skill;
43312
43627
  const builtinOnly = skill.installed.builtin && !skill.installed.user && !skill.installed.project;
43313
- if (matchesKey10(data, "v")) {
43628
+ if (matchesKey11(data, "v")) {
43314
43629
  this.#openPreview(this.#name);
43315
43630
  return true;
43316
43631
  }
43317
43632
  if (builtinOnly)
43318
43633
  return true;
43319
- if (matchesKey10(data, "u"))
43634
+ if (matchesKey11(data, "u"))
43320
43635
  this.askInstall("user", skill);
43321
- else if (matchesKey10(data, "p"))
43636
+ else if (matchesKey11(data, "p"))
43322
43637
  this.askInstall("project", skill);
43323
- else if (matchesKey10(data, "d"))
43638
+ else if (matchesKey11(data, "d"))
43324
43639
  this.askUninstall(skill);
43325
43640
  else
43326
43641
  return false;
@@ -43445,13 +43760,13 @@ class SkillPreviewView {
43445
43760
  this.#offset = Math.max(0, Math.min(this.#maxOffset, this.#offset + delta));
43446
43761
  }
43447
43762
  handleKey(data) {
43448
- if (matchesKey10(data, "up"))
43763
+ if (matchesKey11(data, "up"))
43449
43764
  this.scroll(-1);
43450
- else if (matchesKey10(data, "down"))
43765
+ else if (matchesKey11(data, "down"))
43451
43766
  this.scroll(1);
43452
- else if (matchesKey10(data, "pageUp"))
43767
+ else if (matchesKey11(data, "pageUp"))
43453
43768
  this.scroll(-this.#pageSize);
43454
- else if (matchesKey10(data, "pageDown"))
43769
+ else if (matchesKey11(data, "pageDown"))
43455
43770
  this.scroll(this.#pageSize);
43456
43771
  else
43457
43772
  return false;
@@ -43503,7 +43818,7 @@ var init_skill_market_ui = __esm(() => {
43503
43818
  });
43504
43819
 
43505
43820
  // packages/tui/src/subagents-ui.ts
43506
- import { matchesKey as matchesKey11 } from "@earendil-works/pi-tui";
43821
+ import { matchesKey as matchesKey12 } from "@earendil-works/pi-tui";
43507
43822
 
43508
43823
  class SubagentDetail {
43509
43824
  get help() {
@@ -43623,13 +43938,13 @@ class SubagentDetail {
43623
43938
  this.history();
43624
43939
  }
43625
43940
  handleKey(data) {
43626
- if (matchesKey11(data, "up")) {
43941
+ if (matchesKey12(data, "up")) {
43627
43942
  this.scroll(-1);
43628
- } else if (matchesKey11(data, "down")) {
43943
+ } else if (matchesKey12(data, "down")) {
43629
43944
  this.scroll(1);
43630
- } else if (matchesKey11(data, "pageUp")) {
43945
+ } else if (matchesKey12(data, "pageUp")) {
43631
43946
  this.scroll(-this.#pageSize);
43632
- } else if (matchesKey11(data, "pageDown")) {
43947
+ } else if (matchesKey12(data, "pageDown")) {
43633
43948
  this.scroll(this.#pageSize);
43634
43949
  } else if (data.toLowerCase() === "e") {
43635
43950
  this.#expanded = !this.#expanded;
@@ -43645,7 +43960,7 @@ class SubagentDetail {
43645
43960
  help: shortcutHints(["Enter", "Stop"], ["Esc", "Back"]),
43646
43961
  lines: () => [theme.warning("Stop this task? Existing changes will be kept.")],
43647
43962
  handleKey: (key) => {
43648
- if (!matchesKey11(key, "enter"))
43963
+ if (!matchesKey12(key, "enter"))
43649
43964
  return false;
43650
43965
  this.#service.stop(stopTaskId === undefined ? null : { taskId: stopTaskId }).catch((e) => {
43651
43966
  this.#error = String(e);
@@ -43776,7 +44091,7 @@ var init_subagents_ui = __esm(() => {
43776
44091
  });
43777
44092
 
43778
44093
  // packages/tui/src/version-ui.ts
43779
- import { matchesKey as matchesKey12, Text as Text9 } from "@earendil-works/pi-tui";
44094
+ import { matchesKey as matchesKey13, Text as Text9 } from "@earendil-works/pi-tui";
43780
44095
  function actionFor(state, installed, runningVersion) {
43781
44096
  const action = updateAction({ gateway: state, frontend: runningVersion, installed });
43782
44097
  return action === "install" && !newer(state?.latestVersion, runningVersion) ? "none" : action;
@@ -43854,9 +44169,9 @@ class VersionDetail {
43854
44169
  return lines.slice(this.#offset, this.#offset + height);
43855
44170
  }
43856
44171
  handleKey(data) {
43857
- if (matchesKey12(data, "up"))
44172
+ if (matchesKey13(data, "up"))
43858
44173
  this.#offset = Math.max(0, this.#offset - 1);
43859
- else if (matchesKey12(data, "down"))
44174
+ else if (matchesKey13(data, "down"))
43860
44175
  this.#offset++;
43861
44176
  else
43862
44177
  return false;
@@ -43921,7 +44236,7 @@ import {
43921
44236
  Container as Container6,
43922
44237
  isKeyRelease as isKeyRelease5,
43923
44238
  Loader,
43924
- matchesKey as matchesKey13,
44239
+ matchesKey as matchesKey14,
43925
44240
  ProcessTerminal,
43926
44241
  ScrollView,
43927
44242
  TuiAltScreen
@@ -43957,6 +44272,8 @@ class NekoTuiApp {
43957
44272
  #chat;
43958
44273
  #agentsPanel = false;
43959
44274
  #jobsPanel = false;
44275
+ #queueBusy = false;
44276
+ #queueRow = new QueueRow;
43960
44277
  #searchStop;
43961
44278
  #contextStop;
43962
44279
  #agentDetails = new Map;
@@ -44064,10 +44381,10 @@ class NekoTuiApp {
44064
44381
  this.#ui.addInputListener((data) => {
44065
44382
  if (isKeyRelease5(data))
44066
44383
  return { consume: true };
44067
- if (!matchesKey13(data, "escape") || this.#panel.open || this.#login.open || this.#busyText !== undefined || this.#lastView?.compaction?.active.length)
44384
+ if (!matchesKey14(data, "escape") || this.#panel.open || this.#login.open || this.#busyText !== undefined || this.#lastView?.compaction?.active.length)
44068
44385
  this.#editor.resetEscapeSequence();
44069
44386
  if (!usableSize(this.#terminal.columns, this.#terminal.rows)) {
44070
- if (matchesKey13(data, "ctrl+c"))
44387
+ if (matchesKey14(data, "ctrl+c"))
44071
44388
  this.exit();
44072
44389
  return { consume: true };
44073
44390
  }
@@ -44078,11 +44395,14 @@ class NekoTuiApp {
44078
44395
  }
44079
44396
  if (this.#sessionOperation)
44080
44397
  return { consume: true };
44081
- if (matchesKey13(data, "right") && this.#lastView?.subagents?.length && this.#editor.getText() === "" && !this.#editor.isShowingAutocomplete()) {
44398
+ const queueKey = this.#queueKey(data);
44399
+ if (queueKey)
44400
+ return queueKey;
44401
+ if (matchesKey14(data, "right") && this.#lastView?.subagents?.length && this.#editor.getText() === "" && !this.#editor.isShowingAutocomplete()) {
44082
44402
  this.#showAgents();
44083
44403
  return { consume: true };
44084
44404
  }
44085
- if (matchesKey13(data, process.platform === "win32" ? "alt+v" : "ctrl+v")) {
44405
+ if (matchesKey14(data, process.platform === "win32" ? "alt+v" : "ctrl+v")) {
44086
44406
  if (isClipboardShortcut(data))
44087
44407
  this.pasteClipboard();
44088
44408
  return { consume: true };
@@ -44099,29 +44419,25 @@ class NekoTuiApp {
44099
44419
  return { consume: true };
44100
44420
  }
44101
44421
  }
44102
- if (matchesKey13(data, "escape") && this.#editor.isShowingAutocomplete()) {
44422
+ if (matchesKey14(data, "escape") && this.#editor.isShowingAutocomplete()) {
44103
44423
  this.#editor.resetEscapeSequence();
44104
44424
  return;
44105
44425
  }
44106
- if (matchesKey13(data, "ctrl+c")) {
44426
+ if (matchesKey14(data, "ctrl+c")) {
44107
44427
  if (this.#busyText !== undefined)
44108
44428
  this.abort();
44109
44429
  else
44110
44430
  this.exit();
44111
44431
  return { consume: true };
44112
44432
  }
44113
- if (matchesKey13(data, "escape") && (this.#busyText !== undefined || this.#lastView?.compaction?.active.some((c) => c.reason === "manual" || c.blocking))) {
44433
+ if (matchesKey14(data, "escape") && (this.#busyText !== undefined || this.#lastView?.compaction?.active.some((c) => c.reason === "manual" || c.blocking))) {
44114
44434
  this.abort();
44115
44435
  return { consume: true };
44116
44436
  }
44117
- if (matchesKey13(data, "ctrl+s")) {
44437
+ if (matchesKey14(data, "ctrl+s")) {
44118
44438
  this.openSessionsOverlay();
44119
44439
  return { consume: true };
44120
44440
  }
44121
- if (this.#busyText !== undefined && matchesKey13(data, "alt+enter")) {
44122
- this.submitFollowUp();
44123
- return { consume: true };
44124
- }
44125
44441
  return;
44126
44442
  });
44127
44443
  }
@@ -44165,6 +44481,8 @@ class NekoTuiApp {
44165
44481
  notices,
44166
44482
  busy: this.#busyLoader,
44167
44483
  busyVisible: () => this.#busyText !== undefined,
44484
+ queue: this.#queueRow,
44485
+ queueVisible: () => this.#queueRow.visible,
44168
44486
  panelOpen: () => this.#panel.open || this.#login.open
44169
44487
  }));
44170
44488
  this.#ui.setFocus(this.#editor);
@@ -44323,12 +44641,7 @@ class NekoTuiApp {
44323
44641
  this.addNotice("Configure DeepSeek with /login before sending.", "warning");
44324
44642
  return;
44325
44643
  }
44326
- this.sendImages(text, this.#busyText !== undefined ? "steer" : undefined);
44327
- }
44328
- submitFollowUp() {
44329
- const text = this.#editor.getText();
44330
- if (text.trim())
44331
- this.sendImages(text, "followUp");
44644
+ this.sendImages(text);
44332
44645
  }
44333
44646
  async addImagePaths(paths) {
44334
44647
  return paths.map((path) => this.addImage(readImageFile(path, this.#options.cwd ?? process.cwd()), path.split(/[\\/]/).at(-1) ?? "Image")).join(" ");
@@ -44363,7 +44676,7 @@ class NekoTuiApp {
44363
44676
  this.#clipboardPending = false;
44364
44677
  }
44365
44678
  }
44366
- async sendImages(text, whenBusy) {
44679
+ async sendImages(text) {
44367
44680
  const chat = this.#chat;
44368
44681
  const session = this.#sessionId;
44369
44682
  if (!chat || this.#sending.has(session))
@@ -44395,7 +44708,7 @@ class NekoTuiApp {
44395
44708
  }));
44396
44709
  content = content.replaceAll(ref, "");
44397
44710
  }
44398
- await chat.submit({ content: content.trim(), images: ids, requestId, ...whenBusy ? { whenBusy } : {} });
44711
+ await chat.submit({ content: content.trim(), images: ids, requestId });
44399
44712
  if (session === this.#sessionId && this.#editor.getText() === before)
44400
44713
  this.#editor.setText("");
44401
44714
  if (this.#texts.get(session) === before)
@@ -44471,6 +44784,7 @@ class NekoTuiApp {
44471
44784
  async switchSession(id) {
44472
44785
  this.#approval.close();
44473
44786
  this.#chat = undefined;
44787
+ this.#queueRow.setItems([]);
44474
44788
  if (this.#jobsPanel && this.#panel.open)
44475
44789
  this.#panel.close();
44476
44790
  if (this.#sessionId)
@@ -44675,7 +44989,7 @@ class NekoTuiApp {
44675
44989
  this.#panel.pointerSelection = true;
44676
44990
  this.#panel.emptyText = JOBS_EMPTY;
44677
44991
  this.#panel.listKey = (data, value) => {
44678
- if (matchesKey13(data, "left")) {
44992
+ if (matchesKey14(data, "left")) {
44679
44993
  this.#panel.close();
44680
44994
  return true;
44681
44995
  }
@@ -44689,6 +45003,64 @@ class NekoTuiApp {
44689
45003
  this.#panel.show("Jobs", async () => jobItems(jobs.list()), async (value) => new JobDetail(jobs, value, this.#panel, changed).open());
44690
45004
  this.#ui.setFocus(this.#panel);
44691
45005
  }
45006
+ #queueKey(data) {
45007
+ const row = this.#queueRow;
45008
+ if (this.#queueBusy && row.selecting)
45009
+ return { consume: true };
45010
+ const action = queueKeyAction(row, data, this.#editor.isShowingAutocomplete());
45011
+ if (action === undefined)
45012
+ return;
45013
+ if (action === "steer" || action === "withdraw")
45014
+ return this.#queueAct(action);
45015
+ if (action === "select")
45016
+ row.select();
45017
+ else if (action === "up")
45018
+ row.move(-1);
45019
+ else if (action === "down")
45020
+ row.move(1);
45021
+ else {
45022
+ row.clear();
45023
+ this.#ui.requestRender();
45024
+ return;
45025
+ }
45026
+ this.#ui.requestRender();
45027
+ return { consume: true };
45028
+ }
45029
+ #queueAct(action) {
45030
+ const chat = this.#chat;
45031
+ const item = this.#queueRow.current;
45032
+ if (!chat || !item)
45033
+ return { consume: true };
45034
+ if (action === "steer" && item.mode === "steer") {
45035
+ this.addNotice("That message already steers the current run.", "info");
45036
+ return { consume: true };
45037
+ }
45038
+ const queue = queueClient(chat);
45039
+ const session = this.#sessionId;
45040
+ this.#queueBusy = true;
45041
+ const restore = (outcome) => {
45042
+ if (outcome.result === "withdrawn")
45043
+ this.#editor.setText(restoreText(this.#editor.getText(), outcome.text ?? ""));
45044
+ };
45045
+ const run = action === "steer" ? queue.steer(item.id).then((outcome) => {
45046
+ if (session !== this.#sessionId)
45047
+ return;
45048
+ restore(outcome);
45049
+ const notice = steerNotice(outcome);
45050
+ this.addNotice(notice.message, notice.level);
45051
+ }) : queue.withdraw(item.id).then((outcome) => {
45052
+ if (session !== this.#sessionId)
45053
+ return;
45054
+ restore(outcome);
45055
+ const notice = withdrawNotice(outcome);
45056
+ this.addNotice(notice.message, notice.level);
45057
+ });
45058
+ run.catch((error) => this.addNotice(messageOf(error), "error")).finally(() => {
45059
+ this.#queueBusy = false;
45060
+ this.#ui.requestRender();
45061
+ });
45062
+ return { consume: true };
45063
+ }
44692
45064
  #showSearch() {
44693
45065
  if (this.#exitStarted || this.#panel.open || this.#login.open)
44694
45066
  return;
@@ -44767,6 +45139,7 @@ class NekoTuiApp {
44767
45139
  this.#panel.update(subagentItems(view.subagents ?? [], view.agents));
44768
45140
  if (this.#jobsPanel)
44769
45141
  this.#panel.update(jobItems(view.jobs ?? []));
45142
+ this.#queueRow.setItems(view.queued ?? []);
44770
45143
  for (const identity of view.agents ?? []) {
44771
45144
  const detail = this.#agentDetails.get(identity.agentId);
44772
45145
  if (detail) {
@@ -45122,6 +45495,7 @@ var init_tui = __esm(() => {
45122
45495
  init_jobs_ui();
45123
45496
  init_labels();
45124
45497
  init_layout();
45498
+ init_queue_ui();
45125
45499
  init_search_ui();
45126
45500
  init_skill_market_ui();
45127
45501
  init_subagents_ui();