@mrciphersmith/keryx 0.2.21 → 0.2.22

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 +88 -18
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -39576,6 +39576,7 @@ function reserveToolAttempt(state, name, input2, risk) {
39576
39576
  }
39577
39577
  async function runAgentTurn(io, deps, history, userLine, options = {}) {
39578
39578
  history.push({ role: "user", content: userLine, provenance: "project" });
39579
+ io.onHistoryChange?.("user");
39579
39580
  const signal = options.signal;
39580
39581
  const isAborted = () => signal?.aborted === true;
39581
39582
  if (isAborted()) {
@@ -39628,6 +39629,7 @@ async function runAgentTurn(io, deps, history, userLine, options = {}) {
39628
39629
  };
39629
39630
  const request = signal === undefined ? { ...baseRequest } : { ...baseRequest, signal };
39630
39631
  let assistantText = "";
39632
+ let assistantMessage;
39631
39633
  let reasoningText = "";
39632
39634
  let reasoningFlushed = false;
39633
39635
  const flushReasoning = () => {
@@ -39655,6 +39657,13 @@ async function runAgentTurn(io, deps, history, userLine, options = {}) {
39655
39657
  const text = event.text ?? "";
39656
39658
  io.write(text);
39657
39659
  assistantText += text;
39660
+ if (assistantMessage === undefined) {
39661
+ assistantMessage = { role: "assistant", content: text, provenance: "model" };
39662
+ history.push(assistantMessage);
39663
+ } else {
39664
+ assistantMessage.content += text;
39665
+ }
39666
+ io.onHistoryChange?.("assistant_delta");
39658
39667
  } else if (event.kind === "tool_call_start") {
39659
39668
  if (event.toolCallId !== undefined && event.toolName !== undefined) {
39660
39669
  nameById.set(event.toolCallId, event.toolName);
@@ -39695,8 +39704,8 @@ async function runAgentTurn(io, deps, history, userLine, options = {}) {
39695
39704
  }
39696
39705
  flushReasoning();
39697
39706
  if (assistantText.length > 0) {
39698
- history.push({ role: "assistant", content: assistantText, provenance: "model" });
39699
39707
  io.onAssistantText?.(assistantText);
39708
+ io.onHistoryChange?.("assistant_final");
39700
39709
  }
39701
39710
  if (isAborted()) {
39702
39711
  system(`
@@ -39719,6 +39728,7 @@ async function runAgentTurn(io, deps, history, userLine, options = {}) {
39719
39728
  content: "[system] You were asked to execute or inspect, but you replied with text and no tool call. " + "Resend a single compliant tool call now (with fully populated required arguments).",
39720
39729
  provenance: "project"
39721
39730
  });
39731
+ io.onHistoryChange?.("tool");
39722
39732
  continue;
39723
39733
  }
39724
39734
  if (shouldReprompt) {
@@ -39749,6 +39759,7 @@ async function runAgentTurn(io, deps, history, userLine, options = {}) {
39749
39759
  const result2 = { output: reservation.reason, isError: true };
39750
39760
  io.onToolResult?.(call.name, result2);
39751
39761
  history.push({ role: "tool", content: result2.output, provenance: "tool" });
39762
+ io.onHistoryChange?.("tool");
39752
39763
  toolLog.push(`${call.name}: skipped (${reservation.reason.split(";")[0] ?? "budget"})`);
39753
39764
  if (reservation.kind === "total_budget") {
39754
39765
  exhaustedBudget = "total";
@@ -39763,6 +39774,7 @@ async function runAgentTurn(io, deps, history, userLine, options = {}) {
39763
39774
  const result = await executeCall(call, toolByName, io.requestApproval);
39764
39775
  io.onToolResult?.(call.name, result);
39765
39776
  history.push({ role: "tool", content: redactSensitiveText(result.output), provenance: "tool" });
39777
+ io.onHistoryChange?.("tool");
39766
39778
  const shortIn = call.input.length > 80 ? `${call.input.slice(0, 77)}\u2026` : call.input;
39767
39779
  const riskUsage = risk === "read" ? `, read ${readBudgetUsed(budget)}/${maxReadToolCalls}` : `, non-read ${nonReadBudgetUsed(budget)}/${maxNonReadToolCalls}`;
39768
39780
  toolLog.push(`${call.name}(${shortIn}) \u2192 ${result.isError ? "error" : "ok"} [attempt ${reservation.attempt}/${maxAttempts}, unique ${budgetUsed(budget)}/${maxToolCalls}${riskUsage}]`);
@@ -39778,6 +39790,7 @@ async function runAgentTurn(io, deps, history, userLine, options = {}) {
39778
39790
  ${hint}
39779
39791
  `);
39780
39792
  history.push({ role: "user", content: hint, provenance: "project" });
39793
+ io.onHistoryChange?.("tool");
39781
39794
  }
39782
39795
  } else {
39783
39796
  lastErrorByHash.delete(reservation.hash);
@@ -44131,10 +44144,13 @@ async function launchTuiAgentShell(opts) {
44131
44144
  let liveSession;
44132
44145
  let history = [];
44133
44146
  let archive = [];
44147
+ let nextArchiveIndex = 0;
44148
+ let sessionPersistTimer;
44134
44149
  const applyOpened = (opened, previewHistory) => {
44135
44150
  liveSession = opened.handle;
44136
44151
  history = previewHistory === true ? opened.history.slice(-SESSION_PREVIEW_MESSAGE_COUNT) : opened.history;
44137
44152
  archive = opened.archive.length > 0 ? [...opened.archive] : [...opened.history];
44153
+ nextArchiveIndex = history.length;
44138
44154
  };
44139
44155
  const pickRecentSession = async () => {
44140
44156
  const rows = listSessions(sessionCwd);
@@ -44260,6 +44276,36 @@ async function launchTuiAgentShell(opts) {
44260
44276
  });
44261
44277
  paintSessionHeader();
44262
44278
  };
44279
+ const syncArchive = () => {
44280
+ while (nextArchiveIndex < history.length) {
44281
+ const message2 = history[nextArchiveIndex];
44282
+ if (message2 !== undefined) {
44283
+ archive.push(message2);
44284
+ }
44285
+ nextArchiveIndex += 1;
44286
+ }
44287
+ };
44288
+ const flushSessionCheckpoint = () => {
44289
+ if (sessionPersistTimer !== undefined) {
44290
+ clearTimeout(sessionPersistTimer);
44291
+ sessionPersistTimer = undefined;
44292
+ }
44293
+ syncArchive();
44294
+ saveSession();
44295
+ };
44296
+ io.onHistoryChange = (kind) => {
44297
+ syncArchive();
44298
+ if (kind === "assistant_delta") {
44299
+ if (sessionPersistTimer === undefined) {
44300
+ sessionPersistTimer = setTimeout(() => {
44301
+ sessionPersistTimer = undefined;
44302
+ saveSession();
44303
+ }, 300);
44304
+ }
44305
+ return;
44306
+ }
44307
+ flushSessionCheckpoint();
44308
+ };
44263
44309
  const startNewSession = (note2) => {
44264
44310
  liveSession = createSession({
44265
44311
  cwd: sessionCwd,
@@ -44268,6 +44314,7 @@ async function launchTuiAgentShell(opts) {
44268
44314
  });
44269
44315
  history = [];
44270
44316
  archive = [];
44317
+ nextArchiveIndex = 0;
44271
44318
  paintSessionHeader();
44272
44319
  if (note2 !== undefined && note2.length > 0) {
44273
44320
  io.onSystem?.(`${note2}
@@ -44558,6 +44605,7 @@ Staying in the current session.
44558
44605
  });
44559
44606
  liveSession = packed.handle;
44560
44607
  history = packed.context;
44608
+ nextArchiveIndex = history.length;
44561
44609
  paintSessionHeader();
44562
44610
  if (packed.result.noop) {
44563
44611
  io.onSystem?.(`Nothing to compact (context already small).
@@ -44779,7 +44827,6 @@ Staying in the current session.
44779
44827
  }
44780
44828
  prevOnSystem?.(text);
44781
44829
  };
44782
- const beforeLen = history.length;
44783
44830
  const controller = new AbortController;
44784
44831
  mainTurnAbortController = controller;
44785
44832
  runAgentTurn(io, deps, history, line, { signal: controller.signal }).finally(() => {
@@ -44787,14 +44834,8 @@ Staying in the current session.
44787
44834
  const secs = ((Date.now() - startedAt) / 1000).toFixed(1);
44788
44835
  stopBusy();
44789
44836
  setMainAgent(turnFailed ? "failed" : "done", turnFailed ? "error" : "idle");
44790
- for (let i = beforeLen;i < history.length; i++) {
44791
- const m = history[i];
44792
- if (m !== undefined) {
44793
- archive.push(m);
44794
- }
44795
- }
44796
44837
  try {
44797
- saveSession();
44838
+ flushSessionCheckpoint();
44798
44839
  } catch {}
44799
44840
  transcript.add(new otui.TextRenderable(r, { id: `w${uid++}`, content: otui.t`${otui.dim(`worked for ${secs}s`)}`, marginTop: 1 }));
44800
44841
  if (!hasExactUsage) {
@@ -45137,7 +45178,7 @@ init_shell_config();
45137
45178
  // package.json
45138
45179
  var package_default = {
45139
45180
  name: "@mrciphersmith/keryx",
45140
- version: "0.2.21",
45181
+ version: "0.2.22",
45141
45182
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
45142
45183
  private: false,
45143
45184
  publishConfig: {
@@ -46048,6 +46089,8 @@ ${GUTTER}${style.cyan(`\u2699 ${call}`)}
46048
46089
  let live;
46049
46090
  let history = [];
46050
46091
  let archive = [];
46092
+ let nextArchiveIndex = 0;
46093
+ let sessionPersistTimer;
46051
46094
  if (sessionsOn) {
46052
46095
  try {
46053
46096
  let resumeId = sessionOpts?.resumeId;
@@ -46062,6 +46105,7 @@ ${GUTTER}${style.cyan(`\u2699 ${call}`)}
46062
46105
  live = opened.handle;
46063
46106
  history = opened.history;
46064
46107
  archive = opened.archive.length > 0 ? [...opened.archive] : [...opened.history];
46108
+ nextArchiveIndex = history.length;
46065
46109
  if (opened.resumed) {
46066
46110
  agentIo.onSystem?.(`Resumed session ${shortSessionId(live.summary.id)} \xB7 ${live.summary.title} (${history.length} context \xB7 archive ${archive.length})
46067
46111
  `);
@@ -46077,6 +46121,7 @@ ${GUTTER}${style.cyan(`\u2699 ${call}`)}
46077
46121
  });
46078
46122
  history = [];
46079
46123
  archive = [];
46124
+ nextArchiveIndex = 0;
46080
46125
  agentIo.onSystem?.(`${cause instanceof Error ? cause.message : String(cause)}
46081
46126
  New session ${shortSessionId(live.summary.id)}.
46082
46127
  `);
@@ -46094,6 +46139,36 @@ New session ${shortSessionId(live.summary.id)}.
46094
46139
  });
46095
46140
  } catch {}
46096
46141
  };
46142
+ const syncArchive = () => {
46143
+ while (nextArchiveIndex < history.length) {
46144
+ const message2 = history[nextArchiveIndex];
46145
+ if (message2 !== undefined) {
46146
+ archive.push(message2);
46147
+ }
46148
+ nextArchiveIndex += 1;
46149
+ }
46150
+ };
46151
+ const flushSessionCheckpoint = () => {
46152
+ if (sessionPersistTimer !== undefined) {
46153
+ clearTimeout(sessionPersistTimer);
46154
+ sessionPersistTimer = undefined;
46155
+ }
46156
+ syncArchive();
46157
+ save();
46158
+ };
46159
+ agentIo.onHistoryChange = (kind) => {
46160
+ syncArchive();
46161
+ if (kind === "assistant_delta") {
46162
+ if (sessionPersistTimer === undefined) {
46163
+ sessionPersistTimer = setTimeout(() => {
46164
+ sessionPersistTimer = undefined;
46165
+ save();
46166
+ }, 300);
46167
+ }
46168
+ return;
46169
+ }
46170
+ flushSessionCheckpoint();
46171
+ };
46097
46172
  for (;; ) {
46098
46173
  const line = await readLine();
46099
46174
  if (line === undefined) {
@@ -46127,6 +46202,7 @@ New session ${shortSessionId(live.summary.id)}.
46127
46202
  });
46128
46203
  history = [];
46129
46204
  archive = [];
46205
+ nextArchiveIndex = 0;
46130
46206
  agentIo.onSystem?.(`New session ${shortSessionId(live.summary.id)} (previous kept on disk)
46131
46207
  `);
46132
46208
  } else {
@@ -46148,6 +46224,7 @@ New session ${shortSessionId(live.summary.id)}.
46148
46224
  });
46149
46225
  live = packed.handle;
46150
46226
  history = packed.context;
46227
+ nextArchiveIndex = history.length;
46151
46228
  if (packed.result.noop) {
46152
46229
  agentIo.onSystem?.(`Nothing to compact (context already small).
46153
46230
  `);
@@ -46171,7 +46248,6 @@ New session ${shortSessionId(live.summary.id)}.
46171
46248
  ${GUTTER}${style.cyan("\u25CF")} ${style.bold("keryx")}
46172
46249
  `);
46173
46250
  lastUsage = undefined;
46174
- const before = history.length;
46175
46251
  startSpinner();
46176
46252
  try {
46177
46253
  await runAgentTurn(agentIo, deps, history, line);
@@ -46179,13 +46255,7 @@ ${GUTTER}${style.cyan("\u25CF")} ${style.bold("keryx")}
46179
46255
  endBlock();
46180
46256
  stopSpinner();
46181
46257
  }
46182
- for (let i = before;i < history.length; i++) {
46183
- const m = history[i];
46184
- if (m !== undefined) {
46185
- archive.push(m);
46186
- }
46187
- }
46188
- save();
46258
+ flushSessionCheckpoint();
46189
46259
  const usageLine = formatUsage(lastUsage);
46190
46260
  if (usageLine.length > 0) {
46191
46261
  out(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.2.21",
3
+ "version": "0.2.22",
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": {