@mrciphersmith/keryx 0.3.15 → 0.3.16

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 +222 -208
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -17637,7 +17637,7 @@ var package_default;
17637
17637
  var init_package = __esm(() => {
17638
17638
  package_default = {
17639
17639
  name: "@mrciphersmith/keryx",
17640
- version: "0.3.15",
17640
+ version: "0.3.16",
17641
17641
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
17642
17642
  private: false,
17643
17643
  publishConfig: {
@@ -58996,7 +58996,13 @@ ${hint}
58996
58996
  }
58997
58997
  if (roundState.round < roundState.maxRounds) {
58998
58998
  roundState.round += 1;
58999
- await finishWithBudgetSummary(io, deps, history, parentRunId, { maxAttempts, toolLog }, signal);
58999
+ const wrapUp = await finishWithBudgetSummary(io, deps, history, parentRunId, { maxAttempts, toolLog }, signal);
59000
+ if (wrapUp.aborted) {
59001
+ system(`
59002
+ [stopped] Model turn interrupted by user.
59003
+ `);
59004
+ return { finishReason: "interrupted" };
59005
+ }
59000
59006
  } else {
59001
59007
  system(`
59002
59008
  [budget] Stopping tools: no progress (only repeated/exhausted tool signatures; ` + `max ${maxAttempts} attempts each). No model rounds remain for a wrap-up.
@@ -59208,6 +59214,9 @@ ${logBlock}
59208
59214
  };
59209
59215
  const request = signal === undefined ? { ...baseRequest } : { ...baseRequest, signal };
59210
59216
  const round = await streamWrapUpRound(io, deps, request, signal, system);
59217
+ if (round.aborted || signal?.aborted === true) {
59218
+ return { aborted: true };
59219
+ }
59211
59220
  if (round.thrownError !== undefined) {
59212
59221
  system(`
59213
59222
  [error] wrap-up failed: ${round.thrownError}
@@ -59226,6 +59235,7 @@ ${logBlock}
59226
59235
  system(`
59227
59236
  [budget] No wrap-up text from the model. Re-run your request, or call the ` + "needed `keryx \u2026` command directly (e.g. `keryx wiki enrich --all`).\n");
59228
59237
  }
59238
+ return { aborted: false };
59229
59239
  }
59230
59240
  async function finishWithSubmitResult(io, deps, history, parentRunId, why, signal) {
59231
59241
  const system = (text) => {
@@ -68912,6 +68922,7 @@ async function enrichPageDeep(input) {
68912
68922
  if (input.signal?.aborted) {
68913
68923
  return { fallback: true, reason: "deep enrich cancelled", toolCalls };
68914
68924
  }
68925
+ let disposeComposed;
68915
68926
  try {
68916
68927
  const env = envWithSavedApiKeys(input.env ?? process.env);
68917
68928
  const credentialAvailable = hasCredential(input.provider, env);
@@ -68988,6 +68999,7 @@ async function enrichPageDeep(input) {
68988
68999
  let pending;
68989
69000
  const abort = new AbortController;
68990
69001
  const composed = composeAbortSignals(input.signal, abort.signal);
69002
+ disposeComposed = composed.dispose;
68991
69003
  const io = {
68992
69004
  write: (s) => {
68993
69005
  assistant += s;
@@ -69086,6 +69098,7 @@ async function enrichPageDeep(input) {
69086
69098
  }
69087
69099
  return { enriched: raw, toolCalls };
69088
69100
  } catch (cause) {
69101
+ disposeComposed?.();
69089
69102
  return { fallback: true, reason: `deep enrich failed: ${errorMessage2(cause)}`, toolCalls };
69090
69103
  }
69091
69104
  }
@@ -160994,256 +161007,257 @@ Kept the current session.
160994
161007
  `);
160995
161008
  }
160996
161009
  };
160997
- for await (const line of io.lines) {
160998
- io.onSafeBoundary?.();
160999
- if (line.startsWith("/")) {
161000
- const parts = line.trim().split(/\s+/);
161001
- const command = parts[0] ?? "";
161002
- const argument = parts.slice(1).join(" ");
161003
- if (command === "/exit" || command === "/quit") {
161004
- leaveBus();
161005
- releaseLease();
161006
- return;
161007
- }
161008
- if (command === "/bus") {
161009
- await runBusSlashCommand(bus, argument, system);
161010
- continue;
161011
- }
161012
- if (command === "/help") {
161013
- system(HELP_TEXT);
161014
- continue;
161015
- }
161016
- if (isSessionInfoCommand(command)) {
161017
- const cwd = deps.session?.cwd;
161018
- const [workspaces, flows] = cwd === undefined ? [[], []] : await Promise.all([loadInspectorWorkspaces(cwd), loadInspectorFlows(cwd)]);
161019
- system(formatSessionInfoText(buildSessionInfoSnapshot({
161020
- summary: live?.summary,
161021
- selection: { provider: providerName, model: modelName },
161022
- version: package_default.version,
161023
- estimateTokens: estimateContextTokens(history),
161024
- limits: await loadSessionLimits({
161025
- provider: providerName,
161026
- model: modelName,
161027
- ...baseUrl !== undefined ? { baseUrl } : {}
161028
- }),
161029
- sessionText: history.map((message) => message.content).join(`
161030
- `),
161031
- workspaces,
161032
- flows
161033
- })));
161034
- continue;
161035
- }
161036
- if (isFlowsCommand(command)) {
161037
- const cwd = deps.session?.cwd;
161038
- const items = cwd === undefined ? [] : await loadInspectorFlows(cwd);
161039
- const query = argument.trim();
161040
- if (query.length > 0) {
161041
- const found = findFlowItem(items, query);
161042
- system(found !== undefined ? formatFlowDetailText(found) : `No flow matching '${query}'.
161043
- `);
161010
+ try {
161011
+ for await (const line of io.lines) {
161012
+ io.onSafeBoundary?.();
161013
+ if (line.startsWith("/")) {
161014
+ const parts = line.trim().split(/\s+/);
161015
+ const command = parts[0] ?? "";
161016
+ const argument = parts.slice(1).join(" ");
161017
+ if (command === "/exit" || command === "/quit") {
161018
+ return;
161019
+ }
161020
+ if (command === "/bus") {
161021
+ await runBusSlashCommand(bus, argument, system);
161044
161022
  continue;
161045
161023
  }
161046
- system(formatFlowListText(items));
161047
- continue;
161048
- }
161049
- if (command === "/theme") {
161050
- const wanted = argument.trim();
161051
- if (wanted.length === 0) {
161052
- system(formatThemeList(getThemeId()));
161024
+ if (command === "/help") {
161025
+ system(HELP_TEXT);
161053
161026
  continue;
161054
161027
  }
161055
- const next = parseThemeId(wanted);
161056
- if (next === undefined) {
161057
- system(`Unknown theme '${wanted}'.
161058
- ${formatThemeList(getThemeId())}`);
161028
+ if (isSessionInfoCommand(command)) {
161029
+ const cwd = deps.session?.cwd;
161030
+ const [workspaces, flows] = cwd === undefined ? [[], []] : await Promise.all([loadInspectorWorkspaces(cwd), loadInspectorFlows(cwd)]);
161031
+ system(formatSessionInfoText(buildSessionInfoSnapshot({
161032
+ summary: live?.summary,
161033
+ selection: { provider: providerName, model: modelName },
161034
+ version: package_default.version,
161035
+ estimateTokens: estimateContextTokens(history),
161036
+ limits: await loadSessionLimits({
161037
+ provider: providerName,
161038
+ model: modelName,
161039
+ ...baseUrl !== undefined ? { baseUrl } : {}
161040
+ }),
161041
+ sessionText: history.map((message) => message.content).join(`
161042
+ `),
161043
+ workspaces,
161044
+ flows
161045
+ })));
161059
161046
  continue;
161060
161047
  }
161061
- applyThemeId(next);
161062
- persistThemeId(next);
161063
- system(`Theme: ${themeLabel(next)}
161064
- `);
161065
- continue;
161066
- }
161067
- if (command === "/clear" || command === "/new") {
161068
- if (sessionsOn) {
161069
- try {
161070
- const next = switchLeasedSession(lease, () => openLeased({ cwd: sessionCwd, provider: providerName, model: modelName }));
161071
- holdLease(next.lease);
161072
- live = next.handle;
161073
- } catch (cause) {
161074
- system(`${cause instanceof Error ? cause.message : String(cause)}
161075
- Kept the current session.
161048
+ if (isFlowsCommand(command)) {
161049
+ const cwd = deps.session?.cwd;
161050
+ const items = cwd === undefined ? [] : await loadInspectorFlows(cwd);
161051
+ const query = argument.trim();
161052
+ if (query.length > 0) {
161053
+ const found = findFlowItem(items, query);
161054
+ system(found !== undefined ? formatFlowDetailText(found) : `No flow matching '${query}'.
161076
161055
  `);
161077
161056
  continue;
161078
161057
  }
161079
- history = [];
161080
- archive = [];
161081
- try {
161082
- await bus?.setSession(live.summary.id);
161083
- } catch (cause) {
161084
- system(busErrorLine(cause));
161085
- }
161086
- system(`New session ${shortSessionId(live.summary.id)} (previous kept on disk)
161087
- `);
161088
- } else {
161089
- history.length = 0;
161058
+ system(formatFlowListText(items));
161059
+ continue;
161090
161060
  }
161091
- continue;
161092
- }
161093
- if (command === "/compact") {
161094
- if (live === undefined) {
161095
- system(`No persistent session in this mode.
161061
+ if (command === "/theme") {
161062
+ const wanted = argument.trim();
161063
+ if (wanted.length === 0) {
161064
+ system(formatThemeList(getThemeId()));
161065
+ continue;
161066
+ }
161067
+ const next = parseThemeId(wanted);
161068
+ if (next === undefined) {
161069
+ system(`Unknown theme '${wanted}'.
161070
+ ${formatThemeList(getThemeId())}`);
161071
+ continue;
161072
+ }
161073
+ applyThemeId(next);
161074
+ persistThemeId(next);
161075
+ system(`Theme: ${themeLabel(next)}
161096
161076
  `);
161097
161077
  continue;
161098
161078
  }
161099
- if (!leaseWatch.canPersist()) {
161100
- system(LOST_LEASE_COMPACT_REFUSAL);
161079
+ if (command === "/clear" || command === "/new") {
161080
+ if (sessionsOn) {
161081
+ try {
161082
+ const next = switchLeasedSession(lease, () => openLeased({ cwd: sessionCwd, provider: providerName, model: modelName }));
161083
+ holdLease(next.lease);
161084
+ live = next.handle;
161085
+ } catch (cause) {
161086
+ system(`${cause instanceof Error ? cause.message : String(cause)}
161087
+ Kept the current session.
161088
+ `);
161089
+ continue;
161090
+ }
161091
+ history = [];
161092
+ archive = [];
161093
+ try {
161094
+ await bus?.setSession(live.summary.id);
161095
+ } catch (cause) {
161096
+ system(busErrorLine(cause));
161097
+ }
161098
+ system(`New session ${shortSessionId(live.summary.id)} (previous kept on disk)
161099
+ `);
161100
+ } else {
161101
+ history.length = 0;
161102
+ }
161101
161103
  continue;
161102
161104
  }
161103
- const focus = argument.trim();
161104
- const packed = compactSession(live, history, archive, {
161105
- keepLastUserTurns: 3,
161106
- ...focus.length > 0 ? { focus } : {},
161107
- provider: providerName,
161108
- model: modelName
161109
- });
161110
- live = packed.handle;
161111
- history = packed.context;
161112
- if (packed.result.noop) {
161113
- system(`Nothing to compact (context already small).
161105
+ if (command === "/compact") {
161106
+ if (live === undefined) {
161107
+ system(`No persistent session in this mode.
161114
161108
  `);
161115
- } else {
161116
- system(`Compacted: removed ${packed.result.removed} msgs from context \xB7 archive ${live.summary.archiveMessageCount} \xB7 compact\xD7${live.summary.compactCount}
161109
+ continue;
161110
+ }
161111
+ if (!leaseWatch.canPersist()) {
161112
+ system(LOST_LEASE_COMPACT_REFUSAL);
161113
+ continue;
161114
+ }
161115
+ const focus = argument.trim();
161116
+ const packed = compactSession(live, history, archive, {
161117
+ keepLastUserTurns: 3,
161118
+ ...focus.length > 0 ? { focus } : {},
161119
+ provider: providerName,
161120
+ model: modelName
161121
+ });
161122
+ live = packed.handle;
161123
+ history = packed.context;
161124
+ if (packed.result.noop) {
161125
+ system(`Nothing to compact (context already small).
161117
161126
  `);
161127
+ } else {
161128
+ system(`Compacted: removed ${packed.result.removed} msgs from context \xB7 archive ${live.summary.archiveMessageCount} \xB7 compact\xD7${live.summary.compactCount}
161129
+ `);
161130
+ }
161131
+ continue;
161118
161132
  }
161119
- continue;
161120
- }
161121
- if (command === "/model") {
161122
- if (argument.length > 0) {
161123
- modelName = argument;
161124
- provider = makeActive();
161133
+ if (command === "/model") {
161134
+ if (argument.length > 0) {
161135
+ modelName = argument;
161136
+ provider = makeActive();
161137
+ }
161138
+ continue;
161125
161139
  }
161126
- continue;
161127
- }
161128
- if (command === "/models") {
161129
- if (deps.selectProviderModel === undefined) {
161130
- system(`Interactive model selection is not available in this session.
161140
+ if (command === "/models") {
161141
+ if (deps.selectProviderModel === undefined) {
161142
+ system(`Interactive model selection is not available in this session.
161131
161143
  `);
161144
+ continue;
161145
+ }
161146
+ await selectAndApply({ onlyProvider: providerName });
161132
161147
  continue;
161133
161148
  }
161134
- await selectAndApply({ onlyProvider: providerName });
161135
- continue;
161136
- }
161137
- if (command === "/provider") {
161138
- if (argument.length > 0) {
161139
- if (argument === "openai-codex") {
161140
- if (deps.selectProviderModel === undefined) {
161141
- system("Interactive subscription selection is not available. Run `keryx auth login openai-codex` and select an authorized model.\n");
161142
- } else {
161143
- await selectAndApply({ onlyProvider: "openai-codex" });
161149
+ if (command === "/provider") {
161150
+ if (argument.length > 0) {
161151
+ if (argument === "openai-codex") {
161152
+ if (deps.selectProviderModel === undefined) {
161153
+ system("Interactive subscription selection is not available. Run `keryx auth login openai-codex` and select an authorized model.\n");
161154
+ } else {
161155
+ await selectAndApply({ onlyProvider: "openai-codex" });
161156
+ }
161157
+ continue;
161144
161158
  }
161159
+ providerName = argument;
161160
+ provider = makeActive();
161145
161161
  continue;
161146
161162
  }
161147
- providerName = argument;
161148
- provider = makeActive();
161163
+ if (deps.selectProviderModel === undefined) {
161164
+ system(`Interactive provider selection is not available in this session.
161165
+ `);
161166
+ continue;
161167
+ }
161168
+ await selectAndApply({});
161149
161169
  continue;
161150
161170
  }
161151
- if (deps.selectProviderModel === undefined) {
161152
- system(`Interactive provider selection is not available in this session.
161153
- `);
161171
+ if (command === "/connect") {
161172
+ if (deps.selectProviderModel === undefined) {
161173
+ system(CONNECT_GUIDANCE);
161174
+ continue;
161175
+ }
161176
+ await selectAndApply({ onlyConnected: true });
161154
161177
  continue;
161155
161178
  }
161156
- await selectAndApply({});
161157
- continue;
161158
- }
161159
- if (command === "/connect") {
161160
- if (deps.selectProviderModel === undefined) {
161161
- system(CONNECT_GUIDANCE);
161179
+ const wrongMode = describeUnavailableCommand(command, "chat");
161180
+ if (wrongMode !== undefined) {
161181
+ system(wrongMode);
161162
161182
  continue;
161163
161183
  }
161164
- await selectAndApply({ onlyConnected: true });
161184
+ system(`Unknown command: ${command}. Type /help for commands.
161185
+ `);
161165
161186
  continue;
161166
161187
  }
161167
- const wrongMode = describeUnavailableCommand(command, "chat");
161168
- if (wrongMode !== undefined) {
161169
- system(wrongMode);
161188
+ if (line.trim().length === 0) {
161170
161189
  continue;
161171
161190
  }
161172
- system(`Unknown command: ${command}. Type /help for commands.
161173
- `);
161174
- continue;
161175
- }
161176
- if (line.trim().length === 0) {
161177
- continue;
161178
- }
161179
- history.push({ role: "user", content: line, provenance: "project" });
161180
- const resolvedMaxOutputTokens = modelParams.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS;
161181
- const request = {
161182
- providerId: providerName,
161183
- modelId: modelName,
161184
- systemInstruction: SYSTEM_INSTRUCTION,
161185
- messages: [...history],
161186
- budget: { maxOutputTokens: resolvedMaxOutputTokens, runReservation: resolvedMaxOutputTokens },
161187
- ...modelParams.temperature !== undefined ? { options: { temperature: modelParams.temperature } } : {},
161188
- stream: true,
161189
- requestId: deps.idSeq(),
161190
- parentRunId
161191
- };
161192
- let accumulated = "";
161193
- let errored = false;
161194
- busWorking = true;
161195
- io.onTurnStart?.();
161196
- try {
161197
- const streamOptions = {
161198
- attemptId: deps.idSeq(),
161199
- ...modelParams.timeoutMs !== undefined ? { timeoutMs: modelParams.timeoutMs } : {}
161191
+ history.push({ role: "user", content: line, provenance: "project" });
161192
+ const resolvedMaxOutputTokens = modelParams.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS;
161193
+ const request = {
161194
+ providerId: providerName,
161195
+ modelId: modelName,
161196
+ systemInstruction: SYSTEM_INSTRUCTION,
161197
+ messages: [...history],
161198
+ budget: { maxOutputTokens: resolvedMaxOutputTokens, runReservation: resolvedMaxOutputTokens },
161199
+ ...modelParams.temperature !== undefined ? { options: { temperature: modelParams.temperature } } : {},
161200
+ stream: true,
161201
+ requestId: deps.idSeq(),
161202
+ parentRunId
161200
161203
  };
161201
- for await (const event of provider.stream(request, streamOptions)) {
161202
- if (event.kind === "text_delta") {
161203
- const text = event.text ?? "";
161204
- io.write(text);
161205
- accumulated += text;
161206
- } else if (event.kind === "provider_error") {
161207
- const detail = event.error?.message ?? event.error?.kind ?? "provider error";
161208
- system(`
161204
+ let accumulated = "";
161205
+ let errored = false;
161206
+ busWorking = true;
161207
+ io.onTurnStart?.();
161208
+ try {
161209
+ const streamOptions = {
161210
+ attemptId: deps.idSeq(),
161211
+ ...modelParams.timeoutMs !== undefined ? { timeoutMs: modelParams.timeoutMs } : {}
161212
+ };
161213
+ for await (const event of provider.stream(request, streamOptions)) {
161214
+ if (event.kind === "text_delta") {
161215
+ const text = event.text ?? "";
161216
+ io.write(text);
161217
+ accumulated += text;
161218
+ } else if (event.kind === "provider_error") {
161219
+ const detail = event.error?.message ?? event.error?.kind ?? "provider error";
161220
+ system(`
161209
161221
  [error] ${detail}
161210
161222
  `);
161211
- errored = true;
161212
- break;
161213
- } else if (event.kind === "model_end") {
161214
- break;
161223
+ errored = true;
161224
+ break;
161225
+ } else if (event.kind === "model_end") {
161226
+ break;
161227
+ }
161215
161228
  }
161216
- }
161217
- } catch (cause) {
161218
- system(`
161229
+ } catch (cause) {
161230
+ system(`
161219
161231
  [error] ${cause instanceof Error ? cause.message : String(cause)}
161220
161232
  `);
161221
- errored = true;
161222
- }
161223
- if (accumulated.length > 0) {
161224
- io.onTurnEnd?.(accumulated);
161225
- }
161226
- if (!errored) {
161227
- history.push({ role: "assistant", content: accumulated, provenance: "model" });
161228
- archive.push({ role: "user", content: line, provenance: "project" });
161229
- archive.push({ role: "assistant", content: accumulated, provenance: "model" });
161230
- save();
161231
- } else if (accumulated.length > 0) {
161232
- history.push({ role: "assistant", content: accumulated, provenance: "model" });
161233
- archive.push({ role: "user", content: line, provenance: "project" });
161234
- archive.push({ role: "assistant", content: accumulated, provenance: "model" });
161235
- save();
161236
- } else {
161237
- history.pop();
161238
- }
161239
- busWorking = false;
161240
- io.onSafeBoundary?.();
161241
- io.write(`
161233
+ errored = true;
161234
+ }
161235
+ if (accumulated.length > 0) {
161236
+ io.onTurnEnd?.(accumulated);
161237
+ }
161238
+ if (!errored) {
161239
+ history.push({ role: "assistant", content: accumulated, provenance: "model" });
161240
+ archive.push({ role: "user", content: line, provenance: "project" });
161241
+ archive.push({ role: "assistant", content: accumulated, provenance: "model" });
161242
+ save();
161243
+ } else if (accumulated.length > 0) {
161244
+ history.push({ role: "assistant", content: accumulated, provenance: "model" });
161245
+ archive.push({ role: "user", content: line, provenance: "project" });
161246
+ archive.push({ role: "assistant", content: accumulated, provenance: "model" });
161247
+ save();
161248
+ } else {
161249
+ history.pop();
161250
+ }
161251
+ busWorking = false;
161252
+ io.onSafeBoundary?.();
161253
+ io.write(`
161242
161254
 
161243
161255
  `);
161256
+ }
161257
+ } finally {
161258
+ leaveBus();
161259
+ releaseLease();
161244
161260
  }
161245
- leaveBus();
161246
- releaseLease();
161247
161261
  }
161248
161262
  function realMakeProvider(write) {
161249
161263
  return (name, model, baseUrl) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.3.15",
3
+ "version": "0.3.16",
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": {