@mrciphersmith/keryx 0.2.42 → 0.2.43

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 +597 -18
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -48582,7 +48582,7 @@ import { spawnSync as spawnSync2 } from "child_process";
48582
48582
  // package.json
48583
48583
  var package_default = {
48584
48584
  name: "@mrciphersmith/keryx",
48585
- version: "0.2.42",
48585
+ version: "0.2.43",
48586
48586
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
48587
48587
  private: false,
48588
48588
  publishConfig: {
@@ -49460,6 +49460,12 @@ function onKeypress(r, handler) {
49460
49460
  }
49461
49461
  var BACKDROP_ID = "modal-backdrop";
49462
49462
  var PANEL_ID = "modal-panel";
49463
+ var BACKDROP_ALPHA = 0.85;
49464
+ function backdropFillColor(otui) {
49465
+ const color = otui.RGBA.fromHex(getTheme().bg);
49466
+ color.a = BACKDROP_ALPHA;
49467
+ return color;
49468
+ }
49463
49469
  var MODAL_PANEL_MARGIN = 1;
49464
49470
  var MODAL_PANEL_CHROME_X = 4;
49465
49471
  var MODAL_PANEL_MIN_WIDTH = 72;
@@ -49600,7 +49606,7 @@ function ensureHost(otui, chrome) {
49600
49606
  left: 0,
49601
49607
  width: "100%",
49602
49608
  height: "100%",
49603
- backgroundColor: getTheme().bg,
49609
+ backgroundColor: backdropFillColor(otui),
49604
49610
  zIndex: 100,
49605
49611
  flexDirection: "column",
49606
49612
  justifyContent: "center",
@@ -49826,7 +49832,14 @@ function openModal(otui, chrome, input2) {
49826
49832
  // src/tui/inspector-sources.ts
49827
49833
  init_store2();
49828
49834
  init_workspace_service();
49835
+ init_slate();
49829
49836
  import { randomUUID as randomUUID22 } from "crypto";
49837
+
49838
+ // src/session/index.ts
49839
+ init_paths();
49840
+ init_store3();
49841
+
49842
+ // src/tui/inspector-sources.ts
49830
49843
  function workspaceFromManifest(manifest) {
49831
49844
  return {
49832
49845
  id: manifest.id,
@@ -49884,17 +49897,20 @@ function flowItemFromState(flow, dir) {
49884
49897
  tasks: flow.tasks.map((task) => ({ id: task.id, title: task.title, status: task.status }))
49885
49898
  };
49886
49899
  }
49900
+ function localSacGuard() {
49901
+ return {
49902
+ mode: "strict",
49903
+ availability: "available",
49904
+ decision: "pass",
49905
+ policyRevision: "local-offline-v1"
49906
+ };
49907
+ }
49887
49908
  async function loadInspectorWorkspaces(cwd) {
49888
49909
  try {
49889
49910
  const service5 = new WorkspaceService({
49890
49911
  workspaceRoot: cwd,
49891
49912
  authorizationServer: localWorkspaceAuthorizationServer(),
49892
- strictGuard: {
49893
- mode: "strict",
49894
- availability: "available",
49895
- decision: "pass",
49896
- policyRevision: "local-offline-v1"
49897
- }
49913
+ strictGuard: localSacGuard()
49898
49914
  });
49899
49915
  const listed = await service5.list({ request: undefined, requestCorrelationId: randomUUID22() });
49900
49916
  return listed.map(workspaceFromManifest);
@@ -49902,6 +49918,19 @@ async function loadInspectorWorkspaces(cwd) {
49902
49918
  return [];
49903
49919
  }
49904
49920
  }
49921
+ async function loadInspectorWorkspace(cwd, workspaceId) {
49922
+ try {
49923
+ const service5 = new WorkspaceService({
49924
+ workspaceRoot: cwd,
49925
+ authorizationServer: localWorkspaceAuthorizationServer(),
49926
+ strictGuard: localSacGuard()
49927
+ });
49928
+ const manifest = await service5.show({ request: undefined, requestCorrelationId: randomUUID22(), workspaceId });
49929
+ return workspaceFromManifest(manifest);
49930
+ } catch {
49931
+ return;
49932
+ }
49933
+ }
49905
49934
  function sortFlowsNewestFirst(items) {
49906
49935
  return [...items].sort((left, right) => {
49907
49936
  const byId = Number(right.id) - Number(left.id);
@@ -49928,6 +49957,40 @@ async function loadInspectorFlows(cwd) {
49928
49957
  return [];
49929
49958
  }
49930
49959
  }
49960
+ function sortSlatesNewestFirst(items) {
49961
+ return [...items].sort((left, right) => left.updatedAt < right.updatedAt ? 1 : left.updatedAt > right.updatedAt ? -1 : 0);
49962
+ }
49963
+ async function loadInspectorSlates(cwd, workspaceId) {
49964
+ try {
49965
+ const sessions = listSessions(cwd);
49966
+ const items = [];
49967
+ for (const session of sessions) {
49968
+ const dir = sessionDir(session.projectPath, session.id);
49969
+ let slate;
49970
+ try {
49971
+ slate = await readSlate(dir);
49972
+ } catch {
49973
+ continue;
49974
+ }
49975
+ if (slate === undefined || slate.workspaceId !== workspaceId) {
49976
+ continue;
49977
+ }
49978
+ items.push({
49979
+ sessionId: session.id,
49980
+ sessionTitle: session.title,
49981
+ updatedAt: session.updatedAt,
49982
+ courseStatus: session.courseStatus ?? "unbound",
49983
+ ...slate.course.flowRef !== undefined ? { flowRef: slate.course.flowRef } : {},
49984
+ seedCount: slate.seeds.length,
49985
+ touchedFiles: slate.anchors.touched,
49986
+ seeds: slate.seeds
49987
+ });
49988
+ }
49989
+ return sortSlatesNewestFirst(items);
49990
+ } catch {
49991
+ return [];
49992
+ }
49993
+ }
49931
49994
  function formatWorkspaceLines(workspaces) {
49932
49995
  if (workspaces.length === 0) {
49933
49996
  return ["No workspaces recorded in this session."];
@@ -50177,6 +50240,259 @@ function openFlows(otui, chrome, options) {
50177
50240
  return presentFlows((hostOtui, hostChrome, input2) => openModal(hostOtui, hostChrome, input2), otui, chrome, options);
50178
50241
  }
50179
50242
 
50243
+ // src/tui/workspace-inspector.ts
50244
+ var WORKSPACE_COMMAND = "/workspace";
50245
+ var WORKSPACE_FOOTER = [
50246
+ { key: "[/]", label: "slate" },
50247
+ { key: "\u2191/\u2193", label: "scroll" },
50248
+ { key: "\u2190/\u2192", label: "tabs" },
50249
+ { key: "esc", label: "close" }
50250
+ ];
50251
+ function isWorkspaceCommand(line) {
50252
+ const token = line.trim().split(/\s+/)[0] ?? "";
50253
+ return token === WORKSPACE_COMMAND;
50254
+ }
50255
+ function formatWorkspaceOverviewLines(workspace, slateCount) {
50256
+ const resourceLines = workspace.resources.length === 0 ? [" (no resources)"] : workspace.resources.map((resource) => ` ${resource.kind.padEnd(10)} ${resource.uri}`);
50257
+ return [
50258
+ `${workspace.id} ${workspace.title}`,
50259
+ `Status ${workspace.status}`,
50260
+ `Slates ${slateCount}`,
50261
+ "",
50262
+ "Resources",
50263
+ ...resourceLines
50264
+ ];
50265
+ }
50266
+ function formatSlateListLines(items, selected) {
50267
+ if (items.length === 0) {
50268
+ return ["No slates bound to this workspace yet."];
50269
+ }
50270
+ return items.map((item, index) => {
50271
+ const mark = index === selected ? ">" : " ";
50272
+ const flow = item.flowRef !== undefined ? `flow ${item.flowRef}` : "no flow";
50273
+ return `${mark} ${item.sessionId.slice(0, 8)} ${item.courseStatus.padEnd(8)} ${item.seedCount} seeds ${flow} ${item.sessionTitle}`;
50274
+ });
50275
+ }
50276
+ function formatSlateDetailLines(item) {
50277
+ if (item === undefined) {
50278
+ return ["No slate selected.", "", "Press Enter (or click a row) on the Slates tab to view one."];
50279
+ }
50280
+ const touchedLines = item.touchedFiles.length === 0 ? [" (none)"] : item.touchedFiles.map((file) => ` ${file}`);
50281
+ const seedLines = item.seeds.length === 0 ? [" (no seeds)"] : item.seeds.map((seed) => ` ${seed.ts} ${(seed.kind ?? "note").padEnd(14)} ${seed.text}`);
50282
+ return [
50283
+ `${item.sessionId} ${item.sessionTitle}`,
50284
+ `Course ${item.courseStatus}`,
50285
+ `Flow ${item.flowRef ?? "\u2014"}`,
50286
+ `Updated ${item.updatedAt}`,
50287
+ "",
50288
+ "Touched files",
50289
+ ...touchedLines,
50290
+ "",
50291
+ "Seeds",
50292
+ ...seedLines
50293
+ ];
50294
+ }
50295
+ function clampScroll2(offset, lineCount, height) {
50296
+ const max = Math.max(0, lineCount - height);
50297
+ return Math.min(max, Math.max(0, offset));
50298
+ }
50299
+ function windowLines2(lines, offset, height) {
50300
+ if (height < 1) {
50301
+ return [];
50302
+ }
50303
+ const start = clampScroll2(offset, lines.length, height);
50304
+ return lines.slice(start, start + height);
50305
+ }
50306
+ function scrollToReveal2(index, offset, height) {
50307
+ if (index < offset) {
50308
+ return index;
50309
+ }
50310
+ if (index >= offset + height) {
50311
+ return index - height + 1;
50312
+ }
50313
+ return offset;
50314
+ }
50315
+ function wrapLines2(text, width) {
50316
+ if (width === undefined || width < 8) {
50317
+ return text;
50318
+ }
50319
+ return text.split(`
50320
+ `).flatMap((line) => {
50321
+ if (line.length <= width) {
50322
+ return [line];
50323
+ }
50324
+ const chunks = [];
50325
+ for (let i = 0;i < line.length; i += width) {
50326
+ chunks.push(line.slice(i, i + width));
50327
+ }
50328
+ return chunks;
50329
+ }).join(`
50330
+ `);
50331
+ }
50332
+ function paintLines2(otui, renderer, body, lines, width, idPrefix = "workspace") {
50333
+ if (otui === undefined || otui === null || body === undefined || body === null) {
50334
+ return;
50335
+ }
50336
+ const parent = body;
50337
+ const ctor = otui.TextRenderable;
50338
+ if (parent.add === undefined || ctor === undefined) {
50339
+ return;
50340
+ }
50341
+ const node = new ctor(renderer, { id: `${idPrefix}-body`, content: wrapLines2(lines.join(`
50342
+ `), width) });
50343
+ parent.add(node);
50344
+ return node;
50345
+ }
50346
+ function presentWorkspace(openModal2, otui, chrome, options) {
50347
+ const items = sortSlatesNewestFirst(options.slates);
50348
+ let selected = 0;
50349
+ let openIndex;
50350
+ let overviewScroll = 0;
50351
+ let listScroll = 0;
50352
+ let detailScroll = 0;
50353
+ let overviewNode;
50354
+ let listNode;
50355
+ let detailNode;
50356
+ let unsubscribeKey;
50357
+ const rendererHint = options.renderer ?? chrome?.renderer;
50358
+ const bodyRows = options.visibleRows ?? (typeof rendererHint?.width === "number" && typeof rendererHint.height === "number" ? modalBodyRows(resolveModalPanelSize(rendererHint.width, rendererHint.height).height) : 13);
50359
+ let tabWidth;
50360
+ const overviewLines = () => wrapLines2(formatWorkspaceOverviewLines(options.workspace, items.length).join(`
50361
+ `), tabWidth).split(`
50362
+ `);
50363
+ const listLines = () => formatSlateListLines(items, selected);
50364
+ const detailLines = () => {
50365
+ const item = openIndex !== undefined ? items[openIndex] : undefined;
50366
+ return wrapLines2(formatSlateDetailLines(item).join(`
50367
+ `), tabWidth).split(`
50368
+ `);
50369
+ };
50370
+ const paintSelection = () => {
50371
+ listScroll = scrollToReveal2(selected, listScroll, bodyRows);
50372
+ listScroll = clampScroll2(listScroll, items.length, bodyRows);
50373
+ detailScroll = clampScroll2(detailScroll, detailLines().length, bodyRows);
50374
+ overviewScroll = clampScroll2(overviewScroll, overviewLines().length, bodyRows);
50375
+ if (overviewNode !== undefined) {
50376
+ overviewNode.content = windowLines2(overviewLines(), overviewScroll, bodyRows).join(`
50377
+ `);
50378
+ }
50379
+ if (listNode !== undefined) {
50380
+ listNode.content = windowLines2(listLines(), listScroll, bodyRows).join(`
50381
+ `);
50382
+ }
50383
+ if (detailNode !== undefined) {
50384
+ detailNode.content = windowLines2(detailLines(), detailScroll, bodyRows).join(`
50385
+ `);
50386
+ }
50387
+ };
50388
+ const moveSelection = (next) => {
50389
+ if (items.length === 0) {
50390
+ return;
50391
+ }
50392
+ const clamped = Math.min(items.length - 1, Math.max(0, next));
50393
+ if (clamped === selected) {
50394
+ return;
50395
+ }
50396
+ selected = clamped;
50397
+ paintSelection();
50398
+ };
50399
+ const openSelected = () => {
50400
+ if (items.length === 0) {
50401
+ return;
50402
+ }
50403
+ openIndex = selected;
50404
+ detailScroll = 0;
50405
+ handle?.setTab("detail");
50406
+ paintSelection();
50407
+ };
50408
+ const handle = openModal2(otui, chrome, {
50409
+ title: WORKSPACE_COMMAND,
50410
+ tabs: [
50411
+ { id: "overview", label: "Workspace" },
50412
+ { id: "slates", label: "Slates" },
50413
+ { id: "detail", label: "Slate" }
50414
+ ],
50415
+ initialTab: "overview",
50416
+ footer: WORKSPACE_FOOTER,
50417
+ renderTab: (tabId, body, ctx) => {
50418
+ const renderer = options.renderer ?? chrome?.renderer;
50419
+ tabWidth = ctx?.width;
50420
+ if (tabId === "overview") {
50421
+ overviewScroll = clampScroll2(overviewScroll, overviewLines().length, bodyRows);
50422
+ overviewNode = paintLines2(otui, renderer, body, windowLines2(overviewLines(), overviewScroll, bodyRows), undefined, "workspace-overview");
50423
+ return;
50424
+ }
50425
+ if (tabId === "slates") {
50426
+ listScroll = scrollToReveal2(selected, listScroll, bodyRows);
50427
+ listNode = paintLines2(otui, renderer, body, windowLines2(listLines(), listScroll, bodyRows), undefined, "workspace-slates");
50428
+ return;
50429
+ }
50430
+ detailScroll = clampScroll2(detailScroll, detailLines().length, bodyRows);
50431
+ detailNode = paintLines2(otui, renderer, body, windowLines2(detailLines(), detailScroll, bodyRows), tabWidth, "workspace-detail");
50432
+ return () => {
50433
+ openIndex = undefined;
50434
+ };
50435
+ },
50436
+ onClose: () => {
50437
+ unsubscribeKey?.();
50438
+ }
50439
+ });
50440
+ if (handle === undefined) {
50441
+ return;
50442
+ }
50443
+ if (options.onKeypress !== undefined) {
50444
+ unsubscribeKey = options.onKeypress((key) => {
50445
+ const token = key.name || key.sequence;
50446
+ const active = handle.activeTab();
50447
+ if (active === "slates") {
50448
+ if (token === "[" || token === "p" || token === "up" || token === "k") {
50449
+ moveSelection(selected - 1);
50450
+ return;
50451
+ }
50452
+ if (token === "]" || token === "n" || token === "down" || token === "j") {
50453
+ moveSelection(selected + 1);
50454
+ return;
50455
+ }
50456
+ if (token === "return" || token === "enter") {
50457
+ openSelected();
50458
+ }
50459
+ return;
50460
+ }
50461
+ const scrollable = active === "detail" ? detailLines : overviewLines;
50462
+ const setScroll = (value) => {
50463
+ if (active === "detail") {
50464
+ detailScroll = value;
50465
+ } else {
50466
+ overviewScroll = value;
50467
+ }
50468
+ };
50469
+ const current = active === "detail" ? detailScroll : overviewScroll;
50470
+ if (token === "up" || token === "k") {
50471
+ setScroll(clampScroll2(current - 1, scrollable().length, bodyRows));
50472
+ paintSelection();
50473
+ return;
50474
+ }
50475
+ if (token === "down" || token === "j") {
50476
+ setScroll(clampScroll2(current + 1, scrollable().length, bodyRows));
50477
+ paintSelection();
50478
+ return;
50479
+ }
50480
+ if (token === "pageup" || token === "pagedown") {
50481
+ const step = token === "pageup" ? -bodyRows : bodyRows;
50482
+ setScroll(clampScroll2(current + step, scrollable().length, bodyRows));
50483
+ paintSelection();
50484
+ }
50485
+ });
50486
+ }
50487
+ return handle;
50488
+ }
50489
+ function openWorkspace(otui, chrome, options) {
50490
+ return presentWorkspace((hostOtui, hostChrome, input2) => openModal(hostOtui, hostChrome, input2), otui, chrome, options);
50491
+ }
50492
+
50493
+ // src/tui/tui-shell.ts
50494
+ init_slate();
50495
+
50180
50496
  // src/tui/context-usage.ts
50181
50497
  var CONTEXT_BAR_WIDTH = 28;
50182
50498
  function lastTurnUsed(usage) {
@@ -50533,6 +50849,11 @@ var AGENT_SLASH_COMMANDS = [
50533
50849
  modes: BOTH
50534
50850
  },
50535
50851
  { name: "/flows", description: "Browse project flows and inspect one", modes: BOTH },
50852
+ {
50853
+ name: "/workspace",
50854
+ description: "Show this session's SAC workspace and its slates",
50855
+ modes: AGENT_ONLY
50856
+ },
50536
50857
  {
50537
50858
  name: "/compact",
50538
50859
  description: "Compact model context \u2014 /compact [focus] (archive kept)",
@@ -50965,10 +51286,6 @@ function setProjectPermissionMode(projectPath, mode, dir) {
50965
51286
  init_permission_mode();
50966
51287
  init_enrich2();
50967
51288
 
50968
- // src/session/index.ts
50969
- init_paths();
50970
- init_store3();
50971
-
50972
51289
  // src/tui/herdr-report.ts
50973
51290
  import net from "net";
50974
51291
  var SOURCE = "herdr:keryx";
@@ -51681,6 +51998,21 @@ async function createShellChrome(otui, renderer, opts) {
51681
51998
  });
51682
51999
  main.add(scroll);
51683
52000
  const transcript = scroll.content;
52001
+ const queueDock = new otui.BoxRenderable(r, {
52002
+ id: "queue-dock",
52003
+ flexShrink: 0,
52004
+ flexDirection: "column",
52005
+ visible: false,
52006
+ backgroundColor: getTheme().panel,
52007
+ borderStyle: "rounded",
52008
+ border: true,
52009
+ borderColor: getTheme().border,
52010
+ paddingLeft: 1,
52011
+ paddingRight: 1,
52012
+ paddingTop: 0,
52013
+ paddingBottom: 0
52014
+ });
52015
+ main.add(queueDock);
51684
52016
  const dock = new otui.BoxRenderable(r, {
51685
52017
  id: "choice-dock",
51686
52018
  flexShrink: 0,
@@ -51817,6 +52149,16 @@ async function createShellChrome(otui, renderer, opts) {
51817
52149
  textarea.focus();
51818
52150
  }
51819
52151
  };
52152
+ scroll.onMouseDown = (event) => {
52153
+ if (overlayActive())
52154
+ return;
52155
+ input2.focus();
52156
+ event.preventDefault();
52157
+ };
52158
+ sidebar.onMouseDown = () => {
52159
+ if (overlayActive())
52160
+ return;
52161
+ };
51820
52162
  const footer = new otui.BoxRenderable(r, {
51821
52163
  id: "footer",
51822
52164
  flexShrink: 0,
@@ -51983,6 +52325,8 @@ async function createShellChrome(otui, renderer, opts) {
51983
52325
  sidebar.borderColor = theme.highlight;
51984
52326
  dock.backgroundColor = theme.panel;
51985
52327
  dock.borderColor = theme.border;
52328
+ queueDock.backgroundColor = theme.panel;
52329
+ queueDock.borderColor = theme.border;
51986
52330
  composer.borderColor = theme.border;
51987
52331
  menu.backgroundColor = theme.panel;
51988
52332
  menu.focusedBackgroundColor = theme.panel;
@@ -52004,6 +52348,7 @@ async function createShellChrome(otui, renderer, opts) {
52004
52348
  scroll,
52005
52349
  transcript,
52006
52350
  dock,
52351
+ queueDock,
52007
52352
  menu,
52008
52353
  composer,
52009
52354
  textarea,
@@ -52150,6 +52495,28 @@ function reinsertMainQueueItem(items, at, item) {
52150
52495
  return next;
52151
52496
  }
52152
52497
 
52498
+ // src/tui/queue-nav.ts
52499
+ var QUEUE_NAV_ACTIONS = ["force", "edit", "delete"];
52500
+ function stepQueueNavIndex(selected, count, direction) {
52501
+ if (count <= 0)
52502
+ return 0;
52503
+ if (direction === "up") {
52504
+ return selected > 0 ? selected - 1 : count - 1;
52505
+ }
52506
+ return selected < count - 1 ? selected + 1 : 0;
52507
+ }
52508
+ function clampQueueNavIndex(selected, count) {
52509
+ if (count <= 0)
52510
+ return 0;
52511
+ return Math.min(Math.max(selected, 0), count - 1);
52512
+ }
52513
+ function stepQueueNavAction(selected, direction) {
52514
+ const idx = QUEUE_NAV_ACTIONS.indexOf(selected);
52515
+ const count = QUEUE_NAV_ACTIONS.length;
52516
+ const nextIdx = direction === "left" ? idx > 0 ? idx - 1 : count - 1 : idx < count - 1 ? idx + 1 : 0;
52517
+ return QUEUE_NAV_ACTIONS[nextIdx];
52518
+ }
52519
+
52153
52520
  // src/tui/worker-fleet.ts
52154
52521
  var STATUS_GLYPH = {
52155
52522
  queued: "\u25CB",
@@ -53528,6 +53895,7 @@ async function launchTuiAgentShell(opts) {
53528
53895
  ...opts.versionCheck !== undefined ? { versionCheck: opts.versionCheck } : {}
53529
53896
  });
53530
53897
  mountedChrome = chrome;
53898
+ chrome.input.focus();
53531
53899
  const transcript = chrome.transcript;
53532
53900
  const input2 = chrome.input;
53533
53901
  let busyPhase = "waiting for model";
@@ -53551,6 +53919,37 @@ async function launchTuiAgentShell(opts) {
53551
53919
  const sbModelV = new otui.TextRenderable(r, { id: "sb-model-v", content: otui.t`${otui.dim(`${sel.provider}/${sel.model}`)}` });
53552
53920
  sidebar.add(sbModelV);
53553
53921
  mountCwdPanel(otui, r, sidebar, opts.session?.cwd ?? process.cwd());
53922
+ sidebar.add(new otui.TextRenderable(r, { id: "sb-workspace-k", content: otui.t`${otui.dim("Workspace")}`, marginTop: 1 }));
53923
+ const sbWorkspaceV = new otui.TextRenderable(r, {
53924
+ id: "sb-workspace-v",
53925
+ content: otui.t`${otui.dim("\u2014")}`,
53926
+ onMouseDown: () => {
53927
+ showWorkspace();
53928
+ }
53929
+ });
53930
+ sidebar.add(sbWorkspaceV);
53931
+ let currentWorkspace;
53932
+ let currentSlates = [];
53933
+ const refreshWorkspaceSidebar = async () => {
53934
+ const dir = slateSession?.dir;
53935
+ const workspaceId = dir !== undefined ? (await readSlate(dir).catch(() => {
53936
+ return;
53937
+ }))?.workspaceId : undefined;
53938
+ if (workspaceId === undefined) {
53939
+ currentWorkspace = undefined;
53940
+ currentSlates = [];
53941
+ sbWorkspaceV.content = otui.t`${otui.dim("\u2014")}`;
53942
+ return;
53943
+ }
53944
+ const cwd = opts.session?.cwd ?? process.cwd();
53945
+ const [workspace, slates] = await Promise.all([
53946
+ loadInspectorWorkspace(cwd, workspaceId),
53947
+ loadInspectorSlates(cwd, workspaceId)
53948
+ ]);
53949
+ currentWorkspace = workspace;
53950
+ currentSlates = slates;
53951
+ sbWorkspaceV.content = workspace === undefined ? otui.t`${otui.dim("\u2014")}` : otui.t`${otui.dim(`${shortenCwd(workspace.title, SIDEBAR_TEXT_WIDTH)} \xB7 ${workspace.status} \xB7 ${slates.length} slate${slates.length === 1 ? "" : "s"}`)}`;
53952
+ };
53554
53953
  sidebar.add(new otui.TextRenderable(r, { id: "sb-ctx-k", content: otui.t`${otui.dim("Context")}`, marginTop: 1 }));
53555
53954
  const sbContext = new otui.TextRenderable(r, { id: "sb-ctx-v", content: otui.t`${otui.dim("0 tokens")}` });
53556
53955
  sidebar.add(sbContext);
@@ -53990,6 +54389,7 @@ async function launchTuiAgentShell(opts) {
53990
54389
  }));
53991
54390
  }
53992
54391
  slateSession = { dir: liveSession.dir, cwd: sessionCwd, opened: false };
54392
+ refreshWorkspaceSidebar();
53993
54393
  const paintSessionHeader = () => {
53994
54394
  const label = `${currentSel.provider}/${currentSel.model}`;
53995
54395
  const sid = shortSessionId(liveSession.summary.id);
@@ -54130,6 +54530,35 @@ Staying in the current session.
54130
54530
  });
54131
54531
  })();
54132
54532
  };
54533
+ const showWorkspace = () => {
54534
+ (async () => {
54535
+ const dir = slateSession?.dir;
54536
+ const workspaceId = dir !== undefined ? (await readSlate(dir).catch(() => {
54537
+ return;
54538
+ }))?.workspaceId : undefined;
54539
+ if (workspaceId === undefined) {
54540
+ io.onSystem?.(`No workspace bound to this session yet \u2014 the agent binds one automatically on its first real task.
54541
+ `);
54542
+ return;
54543
+ }
54544
+ const cwd = inspectorCwd();
54545
+ const [workspace, slates] = await Promise.all([
54546
+ loadInspectorWorkspace(cwd, workspaceId),
54547
+ loadInspectorSlates(cwd, workspaceId)
54548
+ ]);
54549
+ if (workspace === undefined) {
54550
+ io.onSystem?.(`Workspace ${workspaceId} could not be loaded.
54551
+ `);
54552
+ return;
54553
+ }
54554
+ openWorkspace(otui, chrome, {
54555
+ workspace,
54556
+ slates,
54557
+ renderer: r,
54558
+ ...inspectorKeys
54559
+ });
54560
+ })();
54561
+ };
54133
54562
  const updateModelLabels = () => {
54134
54563
  paintSessionHeader();
54135
54564
  const label = `${currentSel.provider}/${currentSel.model}`;
@@ -54168,26 +54597,110 @@ Staying in the current session.
54168
54597
  detail: `queued \xD7${sideQueue.length}`
54169
54598
  });
54170
54599
  };
54600
+ let queueNavActive = false;
54601
+ let selectedQueueIndex = 0;
54602
+ let selectedQueueAction = "force";
54603
+ chrome.addOverlaySource(() => queueNavActive);
54171
54604
  let mainQueueBlocks = [];
54605
+ const mainQueueButton = (label, id, color, onMouseDown) => {
54606
+ const box = new otui.BoxRenderable(r, {
54607
+ id,
54608
+ flexShrink: 0,
54609
+ marginLeft: 1,
54610
+ paddingLeft: 1,
54611
+ paddingRight: 1,
54612
+ onMouseDown: (event) => {
54613
+ event.stopPropagation();
54614
+ onMouseDown();
54615
+ }
54616
+ });
54617
+ const text = new otui.TextRenderable(r, { id: `${id}-t`, content: `[${label}]` });
54618
+ text.fg = color;
54619
+ box.add(text);
54620
+ const setActive = (active) => {
54621
+ box.backgroundColor = active ? getTheme().highlight : undefined;
54622
+ text.content = active ? otui.t`${otui.bold(`[${label}]`)}` : `[${label}]`;
54623
+ text.fg = color;
54624
+ };
54625
+ return { box, setActive };
54626
+ };
54627
+ const applyQueueNavHighlight = () => {
54628
+ for (let i = 0;i < mainQueueBlocks.length; i++) {
54629
+ const entry = mainQueueBlocks[i];
54630
+ if (entry === undefined)
54631
+ continue;
54632
+ const rowActive = queueNavActive && i === selectedQueueIndex;
54633
+ entry.setRowActive(rowActive);
54634
+ entry.buttons.force.setActive(rowActive && selectedQueueAction === "force");
54635
+ entry.buttons.edit.setActive(rowActive && selectedQueueAction === "edit");
54636
+ entry.buttons.delete.setActive(rowActive && selectedQueueAction === "delete");
54637
+ }
54638
+ };
54639
+ const exitQueueNav = () => {
54640
+ if (!queueNavActive)
54641
+ return;
54642
+ queueNavActive = false;
54643
+ applyQueueNavHighlight();
54644
+ };
54645
+ const enterQueueNav = () => {
54646
+ if (mainQueue.length === 0)
54647
+ return;
54648
+ queueNavActive = true;
54649
+ selectedQueueIndex = clampQueueNavIndex(selectedQueueIndex, mainQueue.length);
54650
+ applyQueueNavHighlight();
54651
+ };
54652
+ chrome.queueDock.onMouseDown = () => {
54653
+ if (chrome.overlayActive())
54654
+ return;
54655
+ enterQueueNav();
54656
+ };
54172
54657
  const paintMainQueue = () => {
54173
54658
  for (const entry of mainQueueBlocks) {
54174
54659
  try {
54175
- transcript.remove(entry.box);
54660
+ chrome.queueDock.remove(entry.box);
54176
54661
  } catch {}
54177
54662
  }
54178
54663
  mainQueueBlocks = [];
54664
+ selectedQueueIndex = clampQueueNavIndex(selectedQueueIndex, mainQueue.length);
54665
+ if (mainQueue.length === 0) {
54666
+ exitQueueNav();
54667
+ }
54668
+ const theme = getTheme();
54179
54669
  for (let i = 0;i < mainQueue.length; i++) {
54180
54670
  const item = mainQueue[i];
54181
54671
  if (item === undefined)
54182
54672
  continue;
54183
- const box = appendUserEcho(otui, r, transcript, {
54673
+ const index = i;
54674
+ const row = new otui.BoxRenderable(r, {
54184
54675
  id: `mq-${item.id}`,
54185
- line: `${formatMainQueueMarker(i, mainQueue.length)} ${item.displayQuestion}`,
54186
- borderColor: getTheme().highlight,
54187
- marginTop: 0
54676
+ width: "100%",
54677
+ flexDirection: "row"
54678
+ });
54679
+ const label = new otui.TextRenderable(r, {
54680
+ id: `mq-${item.id}-t`,
54681
+ flexGrow: 1,
54682
+ minWidth: 0,
54683
+ content: otui.t`${otui.dim(`${formatMainQueueMarker(index, mainQueue.length)} ${item.displayQuestion}`)}`
54684
+ });
54685
+ row.add(label);
54686
+ const force = mainQueueButton("Force", `mq-force-${item.id}`, theme.focus, () => forceMainQueue(index));
54687
+ const edit = mainQueueButton("Edit", `mq-edit-${item.id}`, theme.text, () => editMainQueue(index));
54688
+ const del = mainQueueButton("Delete", `mq-del-${item.id}`, theme.error, () => removeMainQueue(index));
54689
+ row.add(force.box);
54690
+ row.add(edit.box);
54691
+ row.add(del.box);
54692
+ chrome.queueDock.add(row);
54693
+ mainQueueBlocks.push({
54694
+ id: item.id,
54695
+ box: row,
54696
+ setRowActive: (active) => {
54697
+ row.backgroundColor = active ? theme.highlight : undefined;
54698
+ },
54699
+ buttons: { force, edit, delete: del }
54188
54700
  });
54189
- mainQueueBlocks.push({ id: item.id, box });
54190
54701
  }
54702
+ chrome.queueDock.visible = mainQueue.length > 0;
54703
+ applyQueueNavHighlight();
54191
54704
  if (mainQueue.length > 0) {
54192
54705
  fleet.upsert({ id: "agent:queue", label: "mainQ", status: "queued", detail: `queued \xD7${mainQueue.length}` });
54193
54706
  } else {
@@ -54226,6 +54739,63 @@ Staying in the current session.
54226
54739
  }
54227
54740
  runLine(item.question);
54228
54741
  };
54742
+ const handleQueueNavKey = (key) => {
54743
+ if (!queueNavActive) {
54744
+ if (key.ctrl && key.name === "q" && mainQueue.length > 0 && !chrome.overlayActive() && !chrome.menuActive() && !nav.active()) {
54745
+ enterQueueNav();
54746
+ key.preventDefault();
54747
+ key.stopPropagation();
54748
+ }
54749
+ return;
54750
+ }
54751
+ if (key.name === "escape") {
54752
+ exitQueueNav();
54753
+ key.preventDefault();
54754
+ key.stopPropagation();
54755
+ return;
54756
+ }
54757
+ if (key.name === "up") {
54758
+ selectedQueueIndex = stepQueueNavIndex(selectedQueueIndex, mainQueue.length, "up");
54759
+ applyQueueNavHighlight();
54760
+ key.preventDefault();
54761
+ key.stopPropagation();
54762
+ return;
54763
+ }
54764
+ if (key.name === "down") {
54765
+ selectedQueueIndex = stepQueueNavIndex(selectedQueueIndex, mainQueue.length, "down");
54766
+ applyQueueNavHighlight();
54767
+ key.preventDefault();
54768
+ key.stopPropagation();
54769
+ return;
54770
+ }
54771
+ if (key.name === "left") {
54772
+ selectedQueueAction = stepQueueNavAction(selectedQueueAction, "left");
54773
+ applyQueueNavHighlight();
54774
+ key.preventDefault();
54775
+ key.stopPropagation();
54776
+ return;
54777
+ }
54778
+ if (key.name === "right") {
54779
+ selectedQueueAction = stepQueueNavAction(selectedQueueAction, "right");
54780
+ applyQueueNavHighlight();
54781
+ key.preventDefault();
54782
+ key.stopPropagation();
54783
+ return;
54784
+ }
54785
+ if (key.name === "return" || key.name === "linefeed" || key.name === "kpenter") {
54786
+ const index = selectedQueueIndex;
54787
+ const action = selectedQueueAction;
54788
+ exitQueueNav();
54789
+ if (action === "force")
54790
+ forceMainQueue(index);
54791
+ else if (action === "edit")
54792
+ editMainQueue(index);
54793
+ else
54794
+ removeMainQueue(index);
54795
+ key.preventDefault();
54796
+ key.stopPropagation();
54797
+ }
54798
+ };
54229
54799
  const clearSideWorkerSlot = () => {
54230
54800
  if (sideClearTimeout !== undefined) {
54231
54801
  clearTimeout(sideClearTimeout);
@@ -54507,6 +55077,7 @@ Staying in the current session.
54507
55077
  await closeSlateSession(slateSession, mintTimestampAttemptId);
54508
55078
  startNewSession();
54509
55079
  slateSession = { dir: liveSession.dir, cwd: sessionCwd, opened: false };
55080
+ refreshWorkspaceSidebar();
54510
55081
  sessions.clear();
54511
55082
  deps.resetSubagentBudget?.();
54512
55083
  io.onSystem?.(`New session ${shortSessionId(liveSession.summary.id)} (previous kept on disk \xB7 /resume)
@@ -54641,6 +55212,10 @@ Staying in the current session.
54641
55212
  showFlows();
54642
55213
  return;
54643
55214
  }
55215
+ if (isWorkspaceCommand(command.name)) {
55216
+ showWorkspace();
55217
+ return;
55218
+ }
54644
55219
  if (command.name === "/copy") {
54645
55220
  const target = newestBlock();
54646
55221
  if (target === undefined || !copyBlock(target.id)) {
@@ -54959,6 +55534,7 @@ ${formatThemeList(getThemeId())}`);
54959
55534
  mainTurnAbortController = undefined;
54960
55535
  const secs = ((Date.now() - startedAt) / 1000).toFixed(1);
54961
55536
  stopBusy();
55537
+ refreshWorkspaceSidebar();
54962
55538
  setMainAgent(turnFailed ? "failed" : "done", turnFailed ? "error" : "idle");
54963
55539
  try {
54964
55540
  flushSessionCheckpoint();
@@ -54985,6 +55561,9 @@ ${formatThemeList(getThemeId())}`);
54985
55561
  onKeypress4(r, (key) => {
54986
55562
  nav.handleKey(key);
54987
55563
  });
55564
+ onKeypress4(r, (key) => {
55565
+ handleQueueNavKey(key);
55566
+ });
54988
55567
  chrome.onSubmit((line) => {
54989
55568
  runLine(line);
54990
55569
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.2.42",
3
+ "version": "0.2.43",
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": {