@mrciphersmith/keryx 0.2.36 → 0.2.37

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 +583 -92
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -41726,7 +41726,7 @@ function harnessWave(args, deps) {
41726
41726
  // src/commands/shell.ts
41727
41727
  init_make_provider();
41728
41728
  init_orient();
41729
- import { randomUUID as randomUUID17 } from "crypto";
41729
+ import { randomUUID as randomUUID18 } from "crypto";
41730
41730
  import * as readline2 from "readline";
41731
41731
 
41732
41732
  // src/harness/tool/builtin/ask-user-tool.ts
@@ -44799,7 +44799,7 @@ import { spawnSync as spawnSync2 } from "child_process";
44799
44799
  // package.json
44800
44800
  var package_default = {
44801
44801
  name: "@mrciphersmith/keryx",
44802
- version: "0.2.36",
44802
+ version: "0.2.37",
44803
44803
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
44804
44804
  private: false,
44805
44805
  publishConfig: {
@@ -44881,6 +44881,17 @@ function onKeypress(r, handler) {
44881
44881
  var BACKDROP_ID = "modal-backdrop";
44882
44882
  var PANEL_ID = "modal-panel";
44883
44883
  var BACKDROP_OPACITY = 0.45;
44884
+ var MODAL_PANEL_WIDTH = 72;
44885
+ var MODAL_PANEL_HEIGHT = 18;
44886
+ var MODAL_PANEL_INNER_WIDTH = MODAL_PANEL_WIDTH - 4;
44887
+ var CLOSE_HINT = "[x] esc";
44888
+ var DEFAULT_FOOTER = [
44889
+ { key: "\u2190/\u2192", label: "tabs" },
44890
+ { key: "esc", label: "close" }
44891
+ ];
44892
+ function formatModalFooter(actions) {
44893
+ return actions.map((action) => `${action.key} ${action.label}`).join(" \xB7 ");
44894
+ }
44884
44895
  var hosts = new WeakMap;
44885
44896
  function clearChildren(box) {
44886
44897
  for (const child of [...box.getChildren()]) {
@@ -44916,6 +44927,14 @@ function paintTabs(state) {
44916
44927
  content: state.otui.t`${state.otui.dim(labels)}`
44917
44928
  }));
44918
44929
  }
44930
+ function paintHeader(state, title) {
44931
+ state.titleText.content = state.otui.t`${state.otui.bold(title)}`;
44932
+ state.closeText.content = state.otui.t`${state.otui.dim(CLOSE_HINT)}`;
44933
+ }
44934
+ function paintFooter(state, actions) {
44935
+ const items = actions !== undefined && actions.length > 0 ? actions : DEFAULT_FOOTER;
44936
+ state.footerText.content = state.otui.t`${state.otui.dim(formatModalFooter(items))}`;
44937
+ }
44919
44938
  function unmountActiveTab(state) {
44920
44939
  const cleanup = state.tabCleanup;
44921
44940
  state.tabCleanup = undefined;
@@ -44975,10 +44994,10 @@ function ensureHost(otui, chrome) {
44975
44994
  });
44976
44995
  const panel = new otui.BoxRenderable(r, {
44977
44996
  id: PANEL_ID,
44978
- width: "80%",
44979
- maxWidth: 72,
44980
- maxHeight: "80%",
44997
+ width: MODAL_PANEL_WIDTH,
44998
+ height: MODAL_PANEL_HEIGHT,
44981
44999
  flexShrink: 0,
45000
+ flexGrow: 0,
44982
45001
  flexDirection: "column",
44983
45002
  borderStyle: "rounded",
44984
45003
  border: true,
@@ -44988,26 +45007,57 @@ function ensureHost(otui, chrome) {
44988
45007
  paddingRight: 1,
44989
45008
  zIndex: 101
44990
45009
  });
45010
+ const header3 = new otui.BoxRenderable(r, {
45011
+ id: "modal-header",
45012
+ width: "100%",
45013
+ height: 1,
45014
+ flexShrink: 0,
45015
+ flexDirection: "row",
45016
+ justifyContent: "space-between"
45017
+ });
44991
45018
  const titleText = new otui.TextRenderable(r, {
44992
45019
  id: "modal-title",
44993
- content: ""
45020
+ content: "",
45021
+ flexGrow: 1
44994
45022
  });
45023
+ const closeText = new otui.TextRenderable(r, {
45024
+ id: "modal-close",
45025
+ content: "",
45026
+ flexShrink: 0
45027
+ });
45028
+ header3.add(titleText);
45029
+ header3.add(closeText);
44995
45030
  const tabStrip = new otui.BoxRenderable(r, {
44996
45031
  id: "modal-tab-strip",
44997
45032
  flexShrink: 0,
44998
45033
  width: "100%",
45034
+ height: 1,
44999
45035
  flexDirection: "row",
45000
45036
  focusable: true
45001
45037
  });
45002
45038
  const body = new otui.BoxRenderable(r, {
45003
45039
  id: "modal-body",
45004
45040
  width: "100%",
45041
+ flexGrow: 1,
45005
45042
  minHeight: 1,
45006
45043
  flexDirection: "column"
45007
45044
  });
45008
- panel.add(titleText);
45045
+ const footer = new otui.BoxRenderable(r, {
45046
+ id: "modal-footer",
45047
+ width: "100%",
45048
+ height: 1,
45049
+ flexShrink: 0,
45050
+ flexDirection: "row"
45051
+ });
45052
+ const footerText = new otui.TextRenderable(r, {
45053
+ id: "modal-footer-text",
45054
+ content: ""
45055
+ });
45056
+ footer.add(footerText);
45057
+ panel.add(header3);
45009
45058
  panel.add(tabStrip);
45010
45059
  panel.add(body);
45060
+ panel.add(footer);
45011
45061
  backdrop.add(panel);
45012
45062
  r.root.add(backdrop);
45013
45063
  const state = {
@@ -45015,9 +45065,13 @@ function ensureHost(otui, chrome) {
45015
45065
  chrome,
45016
45066
  backdrop,
45017
45067
  panel,
45068
+ header: header3,
45018
45069
  titleText,
45070
+ closeText,
45019
45071
  tabStrip,
45020
45072
  body,
45073
+ footer,
45074
+ footerText,
45021
45075
  open: false,
45022
45076
  generation: 0,
45023
45077
  tabs: [],
@@ -45034,7 +45088,7 @@ function ensureHost(otui, chrome) {
45034
45088
  if (!state.open || state.input === undefined) {
45035
45089
  return;
45036
45090
  }
45037
- if (key.name === "escape") {
45091
+ if (key.name === "escape" || key.name === "x" || key.sequence === "x") {
45038
45092
  closeHost(state, { restoreFocus: true, runOnClose: true });
45039
45093
  key.preventDefault();
45040
45094
  key.stopPropagation();
@@ -45121,15 +45175,323 @@ function openModal(otui, chrome, input2) {
45121
45175
  state.input = input2;
45122
45176
  state.tabs = input2.tabs;
45123
45177
  state.onClose = input2.onClose;
45124
- state.titleText.content = otui.t`${otui.bold(input2.title)}`;
45178
+ paintHeader(state, input2.title);
45179
+ paintFooter(state, input2.footer);
45125
45180
  mountTab(state, input2, resolveInitialTab(input2.tabs, input2.initialTab));
45126
45181
  state.tabStrip.focus();
45127
45182
  return makeHandle(state, generation);
45128
45183
  }
45129
45184
 
45185
+ // src/tui/flow-inspector.ts
45186
+ var FLOWS_COMMAND = "/flows";
45187
+ var FLOWS_FOOTER = [
45188
+ { key: "\u2191/\u2193", label: "select" },
45189
+ { key: "\u2190/\u2192", label: "tabs" },
45190
+ { key: "esc", label: "close" }
45191
+ ];
45192
+ function isFlowsCommand(line) {
45193
+ const token = line.trim().split(/\s+/)[0] ?? "";
45194
+ return token === FLOWS_COMMAND;
45195
+ }
45196
+ function findFlowItem(items, query) {
45197
+ const needle = query.trim();
45198
+ if (needle.length === 0) {
45199
+ return;
45200
+ }
45201
+ const padded = /^\d+$/.test(needle) ? needle.padStart(3, "0") : needle;
45202
+ return items.find((item) => item.id === needle || item.id === padded || item.dir === needle || item.dir.endsWith(`/${needle}`)) ?? items.find((item) => item.slug === needle);
45203
+ }
45204
+ function formatFlowListLines(items, selected) {
45205
+ if (items.length === 0) {
45206
+ return ["No flows in this project."];
45207
+ }
45208
+ return items.map((item, index) => {
45209
+ const mark = index === selected ? ">" : " ";
45210
+ return `${mark} ${item.id} ${item.status} ${item.tasksDone}/${item.tasksTotal} ${item.title}`;
45211
+ });
45212
+ }
45213
+ function formatFlowDetailLines(item) {
45214
+ const taskLines = item.tasks.length === 0 ? [" (no tasks)"] : item.tasks.map((task) => ` ${task.id} ${task.status} ${task.title}`);
45215
+ return [
45216
+ `${item.id} ${item.title}`,
45217
+ `Status ${item.status}`,
45218
+ `Dir ${item.dir}`,
45219
+ `Tasks ${item.tasksDone}/${item.tasksTotal}`,
45220
+ `PR ${item.prUrl ?? "\u2014"}`,
45221
+ `Source ${item.source}`,
45222
+ `Created ${item.createdAt}`,
45223
+ `Updated ${item.updatedAt}`,
45224
+ "",
45225
+ "Tasks",
45226
+ ...taskLines
45227
+ ];
45228
+ }
45229
+ function formatFlowListText(items) {
45230
+ if (items.length === 0) {
45231
+ return `Flows
45232
+ No flows in this project.
45233
+ `;
45234
+ }
45235
+ return [
45236
+ "Flows",
45237
+ ...items.map((item) => ` ${item.id} ${item.status} ${item.tasksDone}/${item.tasksTotal} ${item.title}`),
45238
+ ""
45239
+ ].join(`
45240
+ `);
45241
+ }
45242
+ function formatFlowDetailText(item) {
45243
+ return `${formatFlowDetailLines(item).join(`
45244
+ `)}
45245
+ `;
45246
+ }
45247
+ function paintLines(otui, renderer, body, lines) {
45248
+ if (otui === undefined || otui === null || body === undefined || body === null) {
45249
+ return;
45250
+ }
45251
+ const parent = body;
45252
+ const ctor = otui.TextRenderable;
45253
+ if (parent.add === undefined || ctor === undefined) {
45254
+ return;
45255
+ }
45256
+ const node = new ctor(renderer, { id: "flows-body", content: lines.join(`
45257
+ `) });
45258
+ parent.add(node);
45259
+ return node;
45260
+ }
45261
+ function presentFlows(openModal2, otui, chrome, options) {
45262
+ const items = options.items;
45263
+ let selected = 0;
45264
+ let listNode;
45265
+ let detailNode;
45266
+ let unsubscribeKey;
45267
+ const paintSelection = () => {
45268
+ if (listNode !== undefined) {
45269
+ listNode.content = formatFlowListLines(items, selected).join(`
45270
+ `);
45271
+ }
45272
+ if (detailNode !== undefined) {
45273
+ const item = items[selected];
45274
+ detailNode.content = item !== undefined ? formatFlowDetailLines(item).join(`
45275
+ `) : "No flow selected.";
45276
+ }
45277
+ };
45278
+ const handle = openModal2(otui, chrome, {
45279
+ title: "/flows",
45280
+ tabs: [
45281
+ { id: "list", label: "Flows" },
45282
+ { id: "detail", label: "Detail" }
45283
+ ],
45284
+ initialTab: "list",
45285
+ footer: FLOWS_FOOTER,
45286
+ renderTab: (tabId, body) => {
45287
+ const renderer = options.renderer ?? chrome?.renderer;
45288
+ if (tabId === "list") {
45289
+ listNode = paintLines(otui, renderer, body, formatFlowListLines(items, selected));
45290
+ return;
45291
+ }
45292
+ const item = items[selected];
45293
+ detailNode = paintLines(otui, renderer, body, item !== undefined ? formatFlowDetailLines(item) : ["No flow selected."]);
45294
+ },
45295
+ onClose: () => {
45296
+ unsubscribeKey?.();
45297
+ }
45298
+ });
45299
+ if (handle === undefined) {
45300
+ return;
45301
+ }
45302
+ if (options.onKeypress !== undefined) {
45303
+ unsubscribeKey = options.onKeypress((key) => {
45304
+ const token = key.name || key.sequence;
45305
+ if (items.length === 0) {
45306
+ return;
45307
+ }
45308
+ if (token === "up" || token === "k") {
45309
+ selected = selected > 0 ? selected - 1 : 0;
45310
+ paintSelection();
45311
+ } else if (token === "down" || token === "j") {
45312
+ selected = selected < items.length - 1 ? selected + 1 : selected;
45313
+ paintSelection();
45314
+ } else if (token === "return" || token === "enter") {
45315
+ handle.setTab("detail");
45316
+ }
45317
+ });
45318
+ }
45319
+ return handle;
45320
+ }
45321
+ function openFlows(otui, chrome, options) {
45322
+ return presentFlows((hostOtui, hostChrome, input2) => openModal(hostOtui, hostChrome, input2), otui, chrome, options);
45323
+ }
45324
+
45325
+ // src/tui/inspector-sources.ts
45326
+ init_store2();
45327
+ import { randomUUID as randomUUID17 } from "crypto";
45328
+ function workspaceFromManifest(manifest) {
45329
+ return {
45330
+ id: manifest.id,
45331
+ title: manifest.title,
45332
+ status: manifest.status,
45333
+ resources: manifest.resources.map((resource) => ({ kind: resource.kind, uri: resource.uri }))
45334
+ };
45335
+ }
45336
+ function workspacesInSession(workspaces, opts) {
45337
+ const text = opts.sessionText ?? "";
45338
+ const sessionId = opts.sessionId ?? "";
45339
+ return workspaces.filter((workspace) => {
45340
+ if (text.includes(workspace.id)) {
45341
+ return true;
45342
+ }
45343
+ return workspace.resources.some((resource) => resource.kind === "session" && sessionId.length > 0 && resource.uri.includes(sessionId));
45344
+ });
45345
+ }
45346
+ function explicitFlowMention(item, text) {
45347
+ if (text.length === 0) {
45348
+ return false;
45349
+ }
45350
+ const id = item.id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
45351
+ const slug2 = item.slug.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
45352
+ const pattern = new RegExp(`(?:flow\\s+#?|/flows\\s+|\\.metaproject/flows/)${id}\\b` + (slug2.length > 0 ? `|(?:flow\\s+)${slug2}\\b` : ""), "i");
45353
+ return pattern.test(text);
45354
+ }
45355
+ function flowsInSession(flows, opts) {
45356
+ const sessionId = opts.sessionId ?? "";
45357
+ const text = opts.sessionText ?? "";
45358
+ return flows.filter((flow) => {
45359
+ if (sessionId.length > 0 && flow.sessionIds.includes(sessionId)) {
45360
+ return true;
45361
+ }
45362
+ return explicitFlowMention(flow, text);
45363
+ });
45364
+ }
45365
+ function flowItemFromState(flow, dir) {
45366
+ const sessionIds = [
45367
+ ...new Set(flow.tasks.map((task) => task.runLink?.sessionId).filter((id) => typeof id === "string" && id.length > 0))
45368
+ ];
45369
+ return {
45370
+ id: flow.id,
45371
+ slug: flow.slug,
45372
+ title: flow.title,
45373
+ status: flow.status,
45374
+ dir: `.metaproject/flows/${dir}`,
45375
+ tasksDone: flow.tasks.filter((task) => task.status === "done").length,
45376
+ tasksTotal: flow.tasks.length,
45377
+ sessionIds,
45378
+ prUrl: flow.pr.url,
45379
+ createdAt: flow.createdAt,
45380
+ updatedAt: flow.updatedAt,
45381
+ source: flow.source.ref ?? flow.source.type,
45382
+ tasks: flow.tasks.map((task) => ({ id: task.id, title: task.title, status: task.status }))
45383
+ };
45384
+ }
45385
+ async function loadInspectorWorkspaces(cwd) {
45386
+ try {
45387
+ const service4 = new WorkspaceService({
45388
+ workspaceRoot: cwd,
45389
+ authorizationServer: localWorkspaceAuthorizationServer(),
45390
+ strictGuard: {
45391
+ mode: "strict",
45392
+ availability: "available",
45393
+ decision: "pass",
45394
+ policyRevision: "local-offline-v1"
45395
+ }
45396
+ });
45397
+ const listed = await service4.list({ request: undefined, requestCorrelationId: randomUUID17() });
45398
+ return listed.map(workspaceFromManifest);
45399
+ } catch {
45400
+ return [];
45401
+ }
45402
+ }
45403
+ async function loadInspectorFlows(cwd) {
45404
+ try {
45405
+ const dirs = await listFlowDirs(cwd);
45406
+ const items = [];
45407
+ for (const dir of dirs) {
45408
+ try {
45409
+ items.push(flowItemFromState(await readFlow(cwd, dir), dir));
45410
+ } catch {}
45411
+ }
45412
+ return items;
45413
+ } catch {
45414
+ return [];
45415
+ }
45416
+ }
45417
+ function formatWorkspaceLines(workspaces) {
45418
+ if (workspaces.length === 0) {
45419
+ return ["No workspaces recorded in this session."];
45420
+ }
45421
+ const width = workspaces.reduce((max, workspace) => Math.max(max, workspace.id.length), 0);
45422
+ return workspaces.map((workspace) => `${workspace.id.padEnd(width)} ${workspace.status} ${workspace.title}`);
45423
+ }
45424
+ function formatSessionFlowLines(flows) {
45425
+ if (flows.length === 0) {
45426
+ return ["No flows recorded in this session."];
45427
+ }
45428
+ return flows.map((flow) => `${flow.id} ${flow.status} ${flow.tasksDone}/${flow.tasksTotal} ${flow.title}`);
45429
+ }
45430
+
45431
+ // src/tui/context-usage.ts
45432
+ var CONTEXT_BAR_WIDTH = 28;
45433
+ function lastTurnUsed(usage) {
45434
+ if (usage === undefined) {
45435
+ return;
45436
+ }
45437
+ if (usage.totalTokens !== undefined) {
45438
+ return usage.totalTokens;
45439
+ }
45440
+ if (usage.inputTokens === undefined && usage.outputTokens === undefined) {
45441
+ return;
45442
+ }
45443
+ return (usage.inputTokens ?? 0) + (usage.outputTokens ?? 0);
45444
+ }
45445
+ function renderUsageBar(filled, width = CONTEXT_BAR_WIDTH) {
45446
+ const n = Math.max(0, Math.min(width, filled > 0 ? width : 0));
45447
+ return `[${"\u2588".repeat(n)}${"\u2591".repeat(width - n)}]`;
45448
+ }
45449
+ function buildContextUsage(source) {
45450
+ const lastIn = source.usage?.inputTokens;
45451
+ const lastOut = source.usage?.outputTokens;
45452
+ const last = lastTurnUsed(source.usage);
45453
+ const hasEstimate = source.estimateTokens !== undefined;
45454
+ const total = hasEstimate ? source.estimateTokens ?? 0 : last ?? 0;
45455
+ const estimated = hasEstimate || last === undefined;
45456
+ const segments2 = [];
45457
+ if (hasEstimate) {
45458
+ segments2.push({ id: "history", label: "history (est.)", tokens: source.estimateTokens ?? 0 });
45459
+ }
45460
+ if (lastIn !== undefined) {
45461
+ segments2.push({ id: "last-in", label: "last in", tokens: lastIn });
45462
+ }
45463
+ if (lastOut !== undefined) {
45464
+ segments2.push({ id: "last-out", label: "last out", tokens: lastOut });
45465
+ }
45466
+ return {
45467
+ total,
45468
+ estimated,
45469
+ segments: segments2,
45470
+ bar: renderUsageBar(total),
45471
+ note: total === 0 ? "No context usage yet." : "No model context window is known. The bar is relative to used tokens, not a billed limit."
45472
+ };
45473
+ }
45474
+ function formatContextUsageText(view) {
45475
+ if (view.total === 0 && view.segments.every((segment) => segment.tokens === 0)) {
45476
+ return `Context
45477
+ ${view.note}
45478
+ `;
45479
+ }
45480
+ const kind = view.estimated ? "tokens (estimate)" : "tokens";
45481
+ const width = view.segments.reduce((max, segment) => Math.max(max, segment.label.length), 0);
45482
+ const rows = view.segments.map((segment) => ` ${segment.label.padEnd(width)} ${segment.tokens}`);
45483
+ return [`Context`, ` Used ${view.total} ${kind}`, ` ${view.bar}`, ...rows, "", ` ${view.note}`, ""].join(`
45484
+ `);
45485
+ }
45486
+
45130
45487
  // src/tui/session-info.ts
45131
- var SESSION_INFO_COMMANDS = ["/session-info", "/status", "/info"];
45488
+ var SESSION_INFO_COMMANDS = ["/status"];
45132
45489
  var MISSING = "\u2014";
45490
+ var SESSION_INFO_FOOTER = [
45491
+ { key: "c", label: "copy id" },
45492
+ { key: "\u2190/\u2192", label: "tabs" },
45493
+ { key: "esc", label: "close" }
45494
+ ];
45133
45495
  function isSessionInfoCommand(line) {
45134
45496
  const token = line.trim().split(/\s+/)[0] ?? "";
45135
45497
  return SESSION_INFO_COMMANDS.includes(token);
@@ -45201,7 +45563,28 @@ function buildSessionInfoSnapshot(source) {
45201
45563
  },
45202
45564
  { label: "Context estimate", value: estimate }
45203
45565
  ];
45204
- return { sessionId: id, sessionRows, usageRows };
45566
+ const context = buildContextUsage({
45567
+ estimateTokens: source.estimateTokens,
45568
+ usage: source.usage
45569
+ });
45570
+ const sessionWorkspaces = workspacesInSession(source.workspaces ?? [], {
45571
+ sessionId: id,
45572
+ ...source.sessionText !== undefined ? { sessionText: source.sessionText } : {}
45573
+ });
45574
+ const sessionFlows = flowsInSession(source.flows ?? [], {
45575
+ sessionId: id,
45576
+ ...source.sessionText !== undefined ? { sessionText: source.sessionText } : {}
45577
+ });
45578
+ return {
45579
+ sessionId: id,
45580
+ sessionRows,
45581
+ usageRows,
45582
+ context,
45583
+ workspaceLines: formatWorkspaceLines(sessionWorkspaces),
45584
+ flowLines: formatSessionFlowLines(sessionFlows),
45585
+ hasWorkspaces: sessionWorkspaces.length > 0,
45586
+ hasFlows: sessionFlows.length > 0
45587
+ };
45205
45588
  }
45206
45589
  function formatSection(title, rows) {
45207
45590
  const width = rows.reduce((max, row) => Math.max(max, row.label.length), 0);
@@ -45209,18 +45592,40 @@ function formatSection(title, rows) {
45209
45592
  `);
45210
45593
  }
45211
45594
  function formatSessionInfoText(snapshot) {
45595
+ const extra = [];
45596
+ extra.push(formatContextUsageText(snapshot.context));
45597
+ if (snapshot.hasWorkspaces) {
45598
+ extra.push(["Workspaces", ...snapshot.workspaceLines.map((line) => ` ${line}`), ""].join(`
45599
+ `));
45600
+ }
45601
+ if (snapshot.hasFlows) {
45602
+ extra.push(["Flow", ...snapshot.flowLines.map((line) => ` ${line}`), ""].join(`
45603
+ `));
45604
+ }
45212
45605
  return `${formatSection("Session", snapshot.sessionRows)}
45213
45606
 
45214
45607
  ${formatSection("Usage", snapshot.usageRows)}
45215
- `;
45608
+
45609
+ ${extra.join(`
45610
+ `)}`;
45216
45611
  }
45217
45612
  function sessionIdCopyText(snapshot) {
45218
45613
  return snapshot.sessionId;
45219
45614
  }
45220
- function sessionBlockCopyText(snapshot) {
45221
- return formatSessionInfoText(snapshot);
45615
+ function statusModalTabs(snapshot) {
45616
+ const tabs = [
45617
+ { id: "status", label: "Status" },
45618
+ { id: "context", label: "Context" }
45619
+ ];
45620
+ if (snapshot.hasWorkspaces) {
45621
+ tabs.push({ id: "workspaces", label: "Workspaces" });
45622
+ }
45623
+ if (snapshot.hasFlows) {
45624
+ tabs.push({ id: "flow", label: "Flow" });
45625
+ }
45626
+ return tabs;
45222
45627
  }
45223
- function paintRows(otui, renderer, body, rows) {
45628
+ function paintContent(otui, renderer, body, content) {
45224
45629
  if (otui === undefined || otui === null || body === undefined || body === null) {
45225
45630
  return;
45226
45631
  }
@@ -45229,12 +45634,12 @@ function paintRows(otui, renderer, body, rows) {
45229
45634
  if (parent.add === undefined || ctor === undefined) {
45230
45635
  return;
45231
45636
  }
45637
+ parent.add(new ctor(renderer, { id: "session-info-body", content }));
45638
+ }
45639
+ function paintRows(otui, renderer, body, rows) {
45232
45640
  const width = rows.reduce((max, row) => Math.max(max, row.label.length), 0);
45233
- parent.add(new ctor(renderer, {
45234
- id: "session-info-body",
45235
- content: rows.map((row) => `${row.label.padEnd(width)} ${row.value}`).join(`
45236
- `)
45237
- }));
45641
+ paintContent(otui, renderer, body, rows.map((row) => `${row.label.padEnd(width)} ${row.value}`).join(`
45642
+ `));
45238
45643
  }
45239
45644
  function presentSessionInfo(openModal2, otui, chrome, options) {
45240
45645
  const { snapshot, toast } = options;
@@ -45249,16 +45654,27 @@ function presentSessionInfo(openModal2, otui, chrome, options) {
45249
45654
  };
45250
45655
  let unsubscribeKey;
45251
45656
  const handle = openModal2(otui, chrome, {
45252
- title: "Session",
45253
- tabs: [
45254
- { id: "session", label: "Session" },
45255
- { id: "usage", label: "Usage" }
45256
- ],
45257
- initialTab: "session",
45657
+ title: "/status",
45658
+ tabs: statusModalTabs(snapshot),
45659
+ initialTab: "status",
45660
+ footer: SESSION_INFO_FOOTER,
45258
45661
  renderTab: (tabId, body) => {
45259
- const rows = tabId === "usage" ? snapshot.usageRows : snapshot.sessionRows;
45260
45662
  const renderer = options.renderer ?? chrome?.renderer;
45261
- paintRows(otui, renderer, body, rows);
45663
+ if (tabId === "context") {
45664
+ paintContent(otui, renderer, body, formatContextUsageText(snapshot.context).trimEnd());
45665
+ return;
45666
+ }
45667
+ if (tabId === "workspaces") {
45668
+ paintContent(otui, renderer, body, snapshot.workspaceLines.join(`
45669
+ `));
45670
+ return;
45671
+ }
45672
+ if (tabId === "flow") {
45673
+ paintContent(otui, renderer, body, snapshot.flowLines.join(`
45674
+ `));
45675
+ return;
45676
+ }
45677
+ paintRows(otui, renderer, body, snapshot.sessionRows);
45262
45678
  },
45263
45679
  onClose: () => {
45264
45680
  unsubscribeKey?.();
@@ -45272,8 +45688,6 @@ function presentSessionInfo(openModal2, otui, chrome, options) {
45272
45688
  const token = key.name || key.sequence;
45273
45689
  if (token === "c") {
45274
45690
  copy(sessionIdCopyText(snapshot));
45275
- } else if (token === "y") {
45276
- copy(sessionBlockCopyText(snapshot));
45277
45691
  }
45278
45692
  });
45279
45693
  }
@@ -45341,12 +45755,11 @@ var AGENT_SLASH_COMMANDS = [
45341
45755
  { name: "/resume", description: "Resume a prior session in this project", modes: AGENT_ONLY },
45342
45756
  { name: "/sessions", description: "Open the session list and switch to one", modes: AGENT_ONLY },
45343
45757
  {
45344
- name: "/session-info",
45345
- description: "Show session identity and context usage",
45758
+ name: "/status",
45759
+ description: "Show session identity, context, workspaces, and flows",
45346
45760
  modes: BOTH
45347
45761
  },
45348
- { name: "/status", description: "Alias of /session-info", modes: BOTH },
45349
- { name: "/info", description: "Alias of /session-info", modes: BOTH },
45762
+ { name: "/flows", description: "Browse project flows and inspect one", modes: BOTH },
45350
45763
  {
45351
45764
  name: "/compact",
45352
45765
  description: "Compact model context \u2014 /compact [focus] (archive kept)",
@@ -47451,7 +47864,7 @@ function createBlockView(otui, renderer, parent, block, options = {}) {
47451
47864
  let body;
47452
47865
  let bodyText;
47453
47866
  let painted;
47454
- const paintHeader = (state, focused) => {
47867
+ const paintHeader2 = (state, focused) => {
47455
47868
  const hint = state.collapsed ? options.hint : options.expandedHint ?? options.hint;
47456
47869
  const label = blockLabel({
47457
47870
  kind: state.kind,
@@ -47512,7 +47925,7 @@ function createBlockView(otui, renderer, parent, block, options = {}) {
47512
47925
  return {
47513
47926
  id: block.id,
47514
47927
  render: (state, opts = {}) => {
47515
- paintHeader(state, opts.focused === true);
47928
+ paintHeader2(state, opts.focused === true);
47516
47929
  if (state.collapsed) {
47517
47930
  dropBody();
47518
47931
  return;
@@ -49012,21 +49425,41 @@ Staying in the current session.
49012
49425
  `);
49013
49426
  };
49014
49427
  paintSessionHeader();
49428
+ const inspectorKeys = { onKeypress: (handler) => onKeypress4(r, (key) => handler(key)) };
49429
+ const inspectorCwd = () => opts.session?.cwd ?? liveSession.summary.projectPath;
49015
49430
  const showSessionInfo = () => {
49016
- const snapshot = buildSessionInfoSnapshot({
49017
- summary: liveSession.summary,
49018
- selection: currentSel,
49019
- version: package_default.version,
49020
- usage: lastUsage,
49021
- estimateTokens: estimateContextTokens(history)
49022
- });
49023
- openSessionInfo(otui, chrome, {
49024
- snapshot,
49025
- copyText: (text) => r.copyToClipboardOSC52(text),
49026
- toast: (message2) => chrome.showToast(message2),
49027
- renderer: r,
49028
- onKeypress: (handler) => onKeypress4(r, (key) => handler(key))
49029
- });
49431
+ (async () => {
49432
+ const cwd = inspectorCwd();
49433
+ const [workspaces, flows] = await Promise.all([loadInspectorWorkspaces(cwd), loadInspectorFlows(cwd)]);
49434
+ const snapshot = buildSessionInfoSnapshot({
49435
+ summary: liveSession.summary,
49436
+ selection: currentSel,
49437
+ version: package_default.version,
49438
+ usage: lastUsage,
49439
+ estimateTokens: estimateContextTokens(history),
49440
+ sessionText: history.map((message2) => message2.content).join(`
49441
+ `),
49442
+ workspaces,
49443
+ flows
49444
+ });
49445
+ openSessionInfo(otui, chrome, {
49446
+ snapshot,
49447
+ copyText: (text) => r.copyToClipboardOSC52(text),
49448
+ toast: (message2) => chrome.showToast(message2),
49449
+ renderer: r,
49450
+ ...inspectorKeys
49451
+ });
49452
+ })();
49453
+ };
49454
+ const showFlows = () => {
49455
+ (async () => {
49456
+ const items = await loadInspectorFlows(inspectorCwd());
49457
+ openFlows(otui, chrome, {
49458
+ items,
49459
+ renderer: r,
49460
+ ...inspectorKeys
49461
+ });
49462
+ })();
49030
49463
  };
49031
49464
  const updateModelLabels = () => {
49032
49465
  paintSessionHeader();
@@ -49237,6 +49670,10 @@ Staying in the current session.
49237
49670
  showSessionInfo();
49238
49671
  return;
49239
49672
  }
49673
+ if (command2 !== undefined && isFlowsCommand(command2.name)) {
49674
+ showFlows();
49675
+ return;
49676
+ }
49240
49677
  if (command2 !== undefined || line.startsWith("/")) {
49241
49678
  transcript.add(new otui.TextRenderable(r, {
49242
49679
  id: `c${uid++}`,
@@ -49382,6 +49819,10 @@ Staying in the current session.
49382
49819
  showSessionInfo();
49383
49820
  return;
49384
49821
  }
49822
+ if (isFlowsCommand(command.name)) {
49823
+ showFlows();
49824
+ return;
49825
+ }
49385
49826
  if (command.name === "/copy") {
49386
49827
  const target = newestBlock();
49387
49828
  if (target === undefined || !copyBlock(target.id)) {
@@ -49727,7 +50168,7 @@ function createChatBridge(hooks = {}) {
49727
50168
  close();
49728
50169
  return "exit";
49729
50170
  }
49730
- if (isSessionInfoCommand(value)) {
50171
+ if (isSessionInfoCommand(value) || isFlowsCommand(value)) {
49731
50172
  return "local";
49732
50173
  }
49733
50174
  if ((turn || queue.length > 0) && value.startsWith("/")) {
@@ -49854,19 +50295,33 @@ async function mountChatShell(otui, renderer, opts) {
49854
50295
  return;
49855
50296
  }
49856
50297
  if (result === "local") {
49857
- const snapshot = buildSessionInfoSnapshot({
49858
- summary: opts.deps.session !== undefined ? latestSession(opts.deps.session.cwd) : undefined,
49859
- selection,
49860
- version: package_default.version,
49861
- estimateTokens: estimateContextTokens(seen)
49862
- });
49863
- openSessionInfo(otui, chrome, {
49864
- snapshot,
49865
- copyText: (text) => r.copyToClipboardOSC52(text),
49866
- toast: (message2) => chrome.showToast(message2),
49867
- renderer: r,
49868
- onKeypress: (handler) => onKeypress4(r, (key) => handler(key))
49869
- });
50298
+ const cwd = opts.deps.session?.cwd;
50299
+ const keys = { onKeypress: (handler) => onKeypress4(r, (key) => handler(key)) };
50300
+ (async () => {
50301
+ const [workspaces, flows] = cwd === undefined ? [[], []] : await Promise.all([loadInspectorWorkspaces(cwd), loadInspectorFlows(cwd)]);
50302
+ if (isFlowsCommand(line)) {
50303
+ openFlows(otui, chrome, { items: flows, renderer: r, ...keys });
50304
+ return;
50305
+ }
50306
+ const summary = cwd !== undefined ? latestSession(cwd) : undefined;
50307
+ const snapshot = buildSessionInfoSnapshot({
50308
+ summary,
50309
+ selection,
50310
+ version: package_default.version,
50311
+ estimateTokens: estimateContextTokens(seen),
50312
+ sessionText: seen.map((message2) => message2.content).join(`
50313
+ `),
50314
+ workspaces,
50315
+ flows
50316
+ });
50317
+ openSessionInfo(otui, chrome, {
50318
+ snapshot,
50319
+ copyText: (text) => r.copyToClipboardOSC52(text),
50320
+ toast: (message2) => chrome.showToast(message2),
50321
+ renderer: r,
50322
+ ...keys
50323
+ });
50324
+ })();
49870
50325
  return;
49871
50326
  }
49872
50327
  if (result === "deferred") {
@@ -50193,9 +50648,8 @@ var READLINE_AGENT_COMMANDS = [
50193
50648
  "/new",
50194
50649
  "/clear",
50195
50650
  "/compact",
50196
- "/session-info",
50197
50651
  "/status",
50198
- "/info",
50652
+ "/flows",
50199
50653
  "/exit"
50200
50654
  ];
50201
50655
  function readlineAgentHelpText() {
@@ -50285,14 +50739,33 @@ Starting a new session.
50285
50739
  continue;
50286
50740
  }
50287
50741
  if (isSessionInfoCommand(command)) {
50742
+ const cwd = deps.session?.cwd;
50743
+ const [workspaces, flows] = cwd === undefined ? [[], []] : await Promise.all([loadInspectorWorkspaces(cwd), loadInspectorFlows(cwd)]);
50288
50744
  system(formatSessionInfoText(buildSessionInfoSnapshot({
50289
50745
  summary: live?.summary,
50290
50746
  selection: { provider: providerName, model: modelName },
50291
50747
  version: package_default.version,
50292
- estimateTokens: estimateContextTokens(history)
50748
+ estimateTokens: estimateContextTokens(history),
50749
+ sessionText: history.map((message2) => message2.content).join(`
50750
+ `),
50751
+ workspaces,
50752
+ flows
50293
50753
  })));
50294
50754
  continue;
50295
50755
  }
50756
+ if (isFlowsCommand(command)) {
50757
+ const cwd = deps.session?.cwd;
50758
+ const items = cwd === undefined ? [] : await loadInspectorFlows(cwd);
50759
+ const query = argument.trim();
50760
+ if (query.length > 0) {
50761
+ const found = findFlowItem(items, query);
50762
+ system(found !== undefined ? formatFlowDetailText(found) : `No flow matching '${query}'.
50763
+ `);
50764
+ continue;
50765
+ }
50766
+ system(formatFlowListText(items));
50767
+ continue;
50768
+ }
50296
50769
  if (command === "/clear" || command === "/new") {
50297
50770
  if (sessionsOn) {
50298
50771
  live = createSession({ cwd: sessionCwd, provider: providerName, model: modelName });
@@ -50941,13 +51414,31 @@ New session ${shortSessionId(live.summary.id)}.
50941
51414
  if (command === "/help") {
50942
51415
  agentIo.onSystem?.(readlineAgentHelpText());
50943
51416
  } else if (isSessionInfoCommand(command)) {
51417
+ const cwd = sessionCwd;
51418
+ const [workspaces, flows] = await Promise.all([
51419
+ loadInspectorWorkspaces(cwd),
51420
+ loadInspectorFlows(cwd)
51421
+ ]);
50944
51422
  agentIo.onSystem?.(formatSessionInfoText(buildSessionInfoSnapshot({
50945
51423
  summary: live?.summary,
50946
51424
  selection: { provider: deps.providerId, model: deps.modelId },
50947
51425
  version: package_default.version,
50948
51426
  usage: lastUsage,
50949
- estimateTokens: estimateContextTokens(history)
51427
+ estimateTokens: estimateContextTokens(history),
51428
+ sessionText: history.map((message2) => message2.content).join(`
51429
+ `),
51430
+ workspaces,
51431
+ flows
50950
51432
  })));
51433
+ } else if (isFlowsCommand(command)) {
51434
+ const items = await loadInspectorFlows(sessionCwd);
51435
+ if (rest.length > 0) {
51436
+ const found = findFlowItem(items, rest);
51437
+ agentIo.onSystem?.(found !== undefined ? formatFlowDetailText(found) : `No flow matching '${rest}'.
51438
+ `);
51439
+ } else {
51440
+ agentIo.onSystem?.(formatFlowListText(items));
51441
+ }
50951
51442
  } else if (command === "/expand") {
50952
51443
  const expanded = expandedToolOutput(lastToolName, lastToolOutput);
50953
51444
  if (expanded !== undefined) {
@@ -51234,7 +51725,7 @@ async function shellCommand(args2, runtime = {}) {
51234
51725
  modelId: sel.model
51235
51726
  }),
51236
51727
  maxToolCalls: resolveAgentMaxToolCalls(),
51237
- idSeq: () => randomUUID17()
51728
+ idSeq: () => randomUUID18()
51238
51729
  };
51239
51730
  };
51240
51731
  const redetect = () => detectProviders({
@@ -51265,7 +51756,7 @@ async function shellCommand(args2, runtime = {}) {
51265
51756
  makeShellDeps: (sel) => ({
51266
51757
  makeProvider: chatFactory,
51267
51758
  clock: () => new Date().toISOString(),
51268
- idSeq: () => randomUUID17(),
51759
+ idSeq: () => randomUUID18(),
51269
51760
  initial: sel,
51270
51761
  session: {
51271
51762
  cwd,
@@ -51335,7 +51826,7 @@ async function shellCommand(args2, runtime = {}) {
51335
51826
  const deps = {
51336
51827
  makeProvider: baseFactory,
51337
51828
  clock: () => new Date().toISOString(),
51338
- idSeq: () => randomUUID17(),
51829
+ idSeq: () => randomUUID18(),
51339
51830
  initial: baseUrl2 === undefined ? { provider, model } : { provider, model, baseUrl: baseUrl2 },
51340
51831
  selectProviderModel: realSelectProviderModel(baseUrl2)
51341
51832
  };
@@ -51383,7 +51874,7 @@ async function shellCommand(args2, runtime = {}) {
51383
51874
  modelId: model
51384
51875
  }),
51385
51876
  maxToolCalls: resolveAgentMaxToolCalls(),
51386
- idSeq: () => randomUUID17()
51877
+ idSeq: () => randomUUID18()
51387
51878
  };
51388
51879
  let resumeId = flags.resumeId;
51389
51880
  if (flags.resumePick === true && resumeId === undefined) {
@@ -51715,7 +52206,7 @@ function printHelp16() {
51715
52206
  }
51716
52207
 
51717
52208
  // src/commands/serve.ts
51718
- import { randomUUID as randomUUID20 } from "crypto";
52209
+ import { randomUUID as randomUUID21 } from "crypto";
51719
52210
 
51720
52211
  // src/lib/serve-config.ts
51721
52212
  init_config_dir();
@@ -52042,7 +52533,7 @@ function saveServeConfig(config, dir, onWarn) {
52042
52533
 
52043
52534
  // src/lib/serve-credential.ts
52044
52535
  init_config_dir();
52045
- import { createHash as createHash29, randomBytes as randomBytes2, randomUUID as randomUUID18 } from "crypto";
52536
+ import { createHash as createHash29, randomBytes as randomBytes2, randomUUID as randomUUID19 } from "crypto";
52046
52537
  import {
52047
52538
  chmodSync as chmodSync4,
52048
52539
  closeSync as closeSync3,
@@ -52126,7 +52617,7 @@ function readServeCredential(dir) {
52126
52617
  }
52127
52618
  function writeStore(store, dir) {
52128
52619
  const file = serveCredentialPath(dir);
52129
- const temp = `${file}.${randomUUID18()}.tmp`;
52620
+ const temp = `${file}.${randomUUID19()}.tmp`;
52130
52621
  try {
52131
52622
  ensureKeryxConfigDir(dir);
52132
52623
  const handle = openSync3(temp, "wx", 384);
@@ -52166,7 +52657,7 @@ function mintRecord(now) {
52166
52657
  const salt = randomBytes2(32).toString("hex");
52167
52658
  return {
52168
52659
  token,
52169
- record: { id: randomUUID18(), algorithm: "sha256", salt, hash: hashToken(salt, token), createdAt: now }
52660
+ record: { id: randomUUID19(), algorithm: "sha256", salt, hash: hashToken(salt, token), createdAt: now }
52170
52661
  };
52171
52662
  }
52172
52663
  function issueServeToken(dir, now = () => new Date().toISOString(), onWaiting) {
@@ -52480,7 +52971,7 @@ function releaseIdempotencyKey(project, idempotencyKey, turnId, dir) {
52480
52971
  }
52481
52972
 
52482
52973
  // src/lib/serve-turn.ts
52483
- import { randomUUID as randomUUID19 } from "crypto";
52974
+ import { randomUUID as randomUUID20 } from "crypto";
52484
52975
  import path140 from "path";
52485
52976
  init_service();
52486
52977
  var REMOTE_ORIGIN = "remote:http";
@@ -52599,7 +53090,7 @@ async function redactOut(security, text) {
52599
53090
  async function runRemoteTurn(input2) {
52600
53091
  const scanRoot = input2.scanRoot;
52601
53092
  const security = createSecurityService(scanRoot);
52602
- const newId = input2.newId ?? (() => randomUUID19());
53093
+ const newId = input2.newId ?? (() => randomUUID20());
52603
53094
  const clock = input2.clock ?? (() => new Date().toISOString());
52604
53095
  const turnId = input2.turnId ?? newId();
52605
53096
  const sessionId = input2.request.sessionId ?? newId();
@@ -52742,7 +53233,7 @@ function outcomeOf(status, gate, unresolvedBlockerIds) {
52742
53233
  }
52743
53234
  function createSubmitTurn(deps) {
52744
53235
  return async (request, project) => {
52745
- const turnId = (deps.newId ?? (() => randomUUID19()))();
53236
+ const turnId = (deps.newId ?? (() => randomUUID20()))();
52746
53237
  const scanned = await scanPrompt(deps.dir, request.prompt);
52747
53238
  if (scanned.rejected) {
52748
53239
  return { kind: "rejected" };
@@ -53429,7 +53920,7 @@ function runConfig(args2) {
53429
53920
  return;
53430
53921
  }
53431
53922
  const credential2 = readServeCredential();
53432
- const credentialId = credential2.status === "ok" ? credential2.record.id : randomUUID20();
53923
+ const credentialId = credential2.status === "ok" ? credential2.record.id : randomUUID21();
53433
53924
  const config = defaultServeConfig(credentialId, {
53434
53925
  address: parsed.parsed.values.get("--bind") ?? DEFAULT_SERVE_BIND_ADDRESS,
53435
53926
  port: port ?? DEFAULT_SERVE_PORT,
@@ -57128,7 +57619,7 @@ async function versionCommand(args2, deps = {}) {
57128
57619
 
57129
57620
  // src/commands/workspace.ts
57130
57621
  init_args();
57131
- import { randomUUID as randomUUID21 } from "crypto";
57622
+ import { randomUUID as randomUUID22 } from "crypto";
57132
57623
  import { writeFile as writeFile50 } from "fs/promises";
57133
57624
 
57134
57625
  // src/sac/fwk-explain.ts
@@ -57196,13 +57687,13 @@ async function workspaceCommand(args2) {
57196
57687
  const component = optionValue(args2, "--component");
57197
57688
  if (!title)
57198
57689
  throw new Error("Usage: keryx workspace create --title <title> [--component <workspace-relative-ref>]");
57199
- const workspace = await service4().create({ request: undefined, requestCorrelationId: randomUUID21(), id: newWorkspaceId(), title, ...component ? { component: { kind: "component", uri: component } } : {} });
57690
+ const workspace = await service4().create({ request: undefined, requestCorrelationId: randomUUID22(), id: newWorkspaceId(), title, ...component ? { component: { kind: "component", uri: component } } : {} });
57200
57691
  console.log(JSON.stringify(workspace, null, 2));
57201
57692
  return;
57202
57693
  }
57203
57694
  if (subcommand === "list") {
57204
57695
  rejectUnknownOptions(args2.slice(1), new Set);
57205
- console.log(JSON.stringify(await service4().list({ request: undefined, requestCorrelationId: randomUUID21() }), null, 2));
57696
+ console.log(JSON.stringify(await service4().list({ request: undefined, requestCorrelationId: randomUUID22() }), null, 2));
57206
57697
  return;
57207
57698
  }
57208
57699
  if (subcommand === "show") {
@@ -57210,7 +57701,7 @@ async function workspaceCommand(args2) {
57210
57701
  const id = args2[1];
57211
57702
  if (!id)
57212
57703
  throw new Error("Usage: keryx workspace show <workspace-id>");
57213
- console.log(JSON.stringify(await service4().show({ request: undefined, requestCorrelationId: randomUUID21(), workspaceId: id }), null, 2));
57704
+ console.log(JSON.stringify(await service4().show({ request: undefined, requestCorrelationId: randomUUID22(), workspaceId: id }), null, 2));
57214
57705
  return;
57215
57706
  }
57216
57707
  if (subcommand === "add-resource") {
@@ -57221,7 +57712,7 @@ async function workspaceCommand(args2) {
57221
57712
  const revision = optionValue(args2, "--revision");
57222
57713
  if (!workspaceId || !kind || !uri)
57223
57714
  throw new Error("Usage: keryx workspace add-resource <workspace-id> --kind <kind> --uri <workspace-relative-ref> [--revision <revision>]");
57224
- console.log(JSON.stringify(await service4().addResource({ request: undefined, requestCorrelationId: randomUUID21(), workspaceId, resource: { kind, uri, ...revision ? { revision } : {} } }), null, 2));
57715
+ console.log(JSON.stringify(await service4().addResource({ request: undefined, requestCorrelationId: randomUUID22(), workspaceId, resource: { kind, uri, ...revision ? { revision } : {} } }), null, 2));
57225
57716
  return;
57226
57717
  }
57227
57718
  if (subcommand === "overview") {
@@ -57233,7 +57724,7 @@ async function workspaceCommand(args2) {
57233
57724
  const maxTokens = Number(optionValue(args2, "--max-tokens") ?? "4096");
57234
57725
  if (!Number.isInteger(maxItems) || !Number.isInteger(maxTokens) || maxItems < 0 || maxTokens < 0)
57235
57726
  throw new Error("--max-items and --max-tokens must be non-negative integers");
57236
- const result = await createLocalFwkReadService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID21(), budget: { maxItems, maxTokens } });
57727
+ const result = await createLocalFwkReadService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID22(), budget: { maxItems, maxTokens } });
57237
57728
  const normalized = normalizeFwkResult(result);
57238
57729
  console.log(JSON.stringify(normalized, null, 2));
57239
57730
  if (args2.includes("--explain"))
@@ -57250,7 +57741,7 @@ async function workspaceCommand(args2) {
57250
57741
  const maxTokens = Number(optionValue(args2, "--max-tokens") ?? "4096");
57251
57742
  if (!Number.isInteger(maxItems) || !Number.isInteger(maxTokens) || maxItems < 0 || maxTokens < 0)
57252
57743
  throw new Error("--max-items and --max-tokens must be non-negative integers");
57253
- const result = await createLocalFwkReadService(process.cwd()).read({ workspaceId, itemId, request: undefined, requestCorrelationId: randomUUID21(), budget: { maxItems, maxTokens } });
57744
+ const result = await createLocalFwkReadService(process.cwd()).read({ workspaceId, itemId, request: undefined, requestCorrelationId: randomUUID22(), budget: { maxItems, maxTokens } });
57254
57745
  const normalized = normalizeFwkResult(result);
57255
57746
  console.log(JSON.stringify(normalized, null, 2));
57256
57747
  if (args2.includes("--explain"))
@@ -57273,12 +57764,12 @@ async function workspaceCommand(args2) {
57273
57764
  if (!session)
57274
57765
  throw new Error(`no session matching "${sessionRef}" in this project \u2014 use \`keryx sessions list\``);
57275
57766
  const { service: service5, wrapUpAuthority, authorizationServer } = createHarnessProposalLifecycleService(cwd, { workspaceId, ...note2 ? { note: note2 } : {} });
57276
- const requestCorrelationId = randomUUID21();
57767
+ const requestCorrelationId = randomUUID22();
57277
57768
  const actor = await authorizationServer.actorContextFor(undefined, requestCorrelationId);
57278
57769
  if (!actor)
57279
57770
  throw new Error("trusted ActorContext is required");
57280
57771
  const wrapUp = await wrapUpAuthority.issue({ actor, source: "session", sourceRef: sessionEvidenceRef(workspaceId, session.id) });
57281
- const proposal = await service5.create({ request: undefined, requestCorrelationId, workspaceId, id: `proposal-${randomUUID21().replace(/-/g, "").slice(0, 16)}`, proposalRevision, kind, wrapUp });
57772
+ const proposal = await service5.create({ request: undefined, requestCorrelationId, workspaceId, id: `proposal-${randomUUID22().replace(/-/g, "").slice(0, 16)}`, proposalRevision, kind, wrapUp });
57282
57773
  if (note2)
57283
57774
  await writeFile50(proposalNotePath(cwd, workspaceId, proposal.id), note2, "utf8");
57284
57775
  console.log(JSON.stringify(normalizeProposalLifecycleResult(proposal), null, 2));
@@ -57290,10 +57781,10 @@ async function workspaceCommand(args2) {
57290
57781
  const proposalId = args2[2];
57291
57782
  const decision = optionValue(args2, "--decision");
57292
57783
  const reason = optionValue(args2, "--reason");
57293
- const idempotencyKey = optionValue(args2, "--idempotency-key") ?? randomUUID21();
57784
+ const idempotencyKey = optionValue(args2, "--idempotency-key") ?? randomUUID22();
57294
57785
  if (!workspaceId || !proposalId || !decision)
57295
57786
  throw new Error("Usage: keryx workspace review <workspace-id> <proposal-id> --decision <accepted|rejected|dismissed> [--reason <reason>] [--idempotency-key <key>]");
57296
- const result = await createHarnessProposalLifecycleService(process.cwd(), { workspaceId }).service.review({ request: undefined, requestCorrelationId: randomUUID21(), workspaceId, proposalId, decision, idempotencyKey, ...reason ? { reason } : {} });
57787
+ const result = await createHarnessProposalLifecycleService(process.cwd(), { workspaceId }).service.review({ request: undefined, requestCorrelationId: randomUUID22(), workspaceId, proposalId, decision, idempotencyKey, ...reason ? { reason } : {} });
57297
57788
  console.log(JSON.stringify(normalizeProposalLifecycleResult(result), null, 2));
57298
57789
  return;
57299
57790
  }
@@ -57302,7 +57793,7 @@ async function workspaceCommand(args2) {
57302
57793
  const workspaceId = args2[1];
57303
57794
  if (!workspaceId)
57304
57795
  throw new Error("Usage: keryx workspace collaboration <workspace-id>");
57305
- console.log(JSON.stringify(await createLocalCollaborationService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID21() }), null, 2));
57796
+ console.log(JSON.stringify(await createLocalCollaborationService(process.cwd()).overview({ workspaceId, request: undefined, requestCorrelationId: randomUUID22() }), null, 2));
57306
57797
  return;
57307
57798
  }
57308
57799
  if (subcommand === "policy-readiness") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.2.36",
3
+ "version": "0.2.37",
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": {