@mrciphersmith/keryx 0.3.75 → 0.3.76

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 (3) hide show
  1. package/dist/cli.js +544 -437
  2. package/dist/core.js +6 -0
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -20145,7 +20145,7 @@ var package_default;
20145
20145
  var init_package = __esm(() => {
20146
20146
  package_default = {
20147
20147
  name: "@mrciphersmith/keryx",
20148
- version: "0.3.75",
20148
+ version: "0.3.76",
20149
20149
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
20150
20150
  private: false,
20151
20151
  publishConfig: {
@@ -97077,109 +97077,6 @@ function createSpawnSubagentTool(deps) {
97077
97077
  outcome
97078
97078
  });
97079
97079
  };
97080
- const parent = deps.getParentModel();
97081
- const detected = deps.getDetectedProviders();
97082
- const session = { providerId: parent.providerId, modelId: parent.modelId };
97083
- const catalog = detected.map((p) => ({
97084
- name: p.name,
97085
- models: p.models ?? []
97086
- }));
97087
- const requestedTier = parseModelTier(typeof input.model_tier === "string" ? input.model_tier : undefined);
97088
- let categoryModelRequest;
97089
- if (requestedTier === undefined) {
97090
- const routingLocation = { cwd: deps.cwd };
97091
- const [projectRouting, userRouting] = await Promise.all([
97092
- loadRoutingConfig("project", routingLocation),
97093
- loadRoutingConfig("user", routingLocation)
97094
- ]);
97095
- for (const layer of [projectRouting, userRouting]) {
97096
- if (layer.error !== undefined) {
97097
- emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "system", text: `routing: ${layer.error}` } });
97098
- }
97099
- }
97100
- const external = await resolveExternalSetting({ cwd: deps.cwd });
97101
- const { config: externalConfig } = loadExternalProvidersConfig();
97102
- const connected = externalAllowedConnectedPredicate(connectedPredicateFrom(catalog), external.value === "on", externalConfig);
97103
- const resolved = resolveCategoryDetailed("subagents", { project: projectRouting.table, user: userRouting.table }, connected);
97104
- if (resolved.rejected !== undefined) {
97105
- emitFleetEvent({
97106
- kind: "log",
97107
- id: workerId,
97108
- entry: { kind: "system", text: `routing: ${describeFallbackNotice(resolved.rejected.assignment, resolved.assignment)}` }
97109
- });
97110
- }
97111
- categoryModelRequest = categoryAssignmentToChildModelRequest(resolved.assignment);
97112
- }
97113
- const dispatchModelRequest = requestedTier !== undefined ? { kind: "tier", tier: requestedTier } : categoryModelRequest;
97114
- let tierMap = buildTierMap(session, catalog);
97115
- const tierPrices = deps.tierRank?.prices?.(session.providerId);
97116
- let tierResolution = requestedTier === undefined ? undefined : resolveTierModel(session, requestedTier, catalog, undefined, tierPrices);
97117
- if (requestedTier !== undefined && deps.tierRank !== undefined) {
97118
- tierResolution = await resolveTierWithAgent(session, requestedTier, rankDiscoveredModels(session, catalog), {
97119
- agent: deps.tierRank.agent,
97120
- ...deps.tierRank.cache !== undefined ? { cache: deps.tierRank.cache } : {},
97121
- ...tierPrices !== undefined ? { prices: tierPrices } : {},
97122
- ...parent.baseUrl !== undefined ? { baseUrl: parent.baseUrl } : {}
97123
- });
97124
- if (tierResolution.source === "agent-ranked") {
97125
- tierMap = applyTierResolution(tierMap, tierResolution);
97126
- }
97127
- }
97128
- const ctx = {
97129
- parentRunId,
97130
- parentSessionId,
97131
- parentProvenance,
97132
- contextManifestHash: sha2569(`${parentRunId}:${parentSessionId}`),
97133
- canonicalContractVersion: "1.0.0",
97134
- parentModel: session,
97135
- parentPolicy: parentShellPolicy(),
97136
- ledger,
97137
- detected: detected.length > 0 ? detected : [{ name: parent.providerId }],
97138
- config: {
97139
- maxTreeDepth: 2,
97140
- maxChildren: DEFAULT_MAX_CHILDREN,
97141
- tiers: tierMap
97142
- }
97143
- };
97144
- const attemptId = idSeq();
97145
- const branchId = idSeq();
97146
- const reservationId = idSeq();
97147
- const artifactHash = sha2569(task);
97148
- const spawned = spawnSubagent({
97149
- attempt: { attemptId, number: childSeq },
97150
- branchId,
97151
- budgetRequest: {
97152
- reservationId,
97153
- maxRuntimeMs: 5 * 60000
97154
- },
97155
- policyRequest: childReadOnlyPolicy(),
97156
- durableResultArtifact: {
97157
- artifactId: idSeq(),
97158
- kind: "final-report",
97159
- hash: artifactHash
97160
- },
97161
- ...dispatchModelRequest !== undefined ? { modelRequest: dispatchModelRequest } : {}
97162
- }, ctx, { idSeq, clock });
97163
- if (!spawned.ok) {
97164
- emitFleetEvent({
97165
- id: workerId,
97166
- kind: "upsert",
97167
- label,
97168
- status: "failed",
97169
- detail: "denied",
97170
- task
97171
- });
97172
- return {
97173
- status: "Denied",
97174
- output: `spawn_subagent denied by MAE: ${spawned.reason}`,
97175
- isError: true
97176
- };
97177
- }
97178
- const runModel = spawned.runModel ?? {
97179
- provider: parent.providerId,
97180
- model: parent.modelId
97181
- };
97182
- const tierRecord = tierResolution === undefined ? undefined : `model tier ${tierResolution.tier} \u2192 ${runModel.provider}/${runModel.model} ` + `[${tierResolution.source}] ${tierResolution.reason}` + (tierResolution.agent === undefined ? "" : ` (agent ${tierResolution.agent.trigger}, ran on ${tierResolution.agent.runOn.providerId}/${tierResolution.agent.runOn.modelId}, ` + `${tierResolution.agent.cacheHit ? "cache hit" : "asked"}${tierResolution.agent.failure === null ? "" : `, failed: ${tierResolution.agent.failure}`})`);
97183
97080
  const externalRuntime = readExternalRuntimeRequest(input);
97184
97081
  const externalAgentId = externalRuntime === undefined || typeof externalRuntime.agent !== "string" ? undefined : externalRuntime.agent;
97185
97082
  const externalMark = externalRuntime !== undefined && deps.runExternal !== undefined ? { runtime: "external", ...externalAgentId === undefined ? {} : { agentId: externalAgentId } } : {};
@@ -97188,29 +97085,190 @@ function createSpawnSubagentTool(deps) {
97188
97085
  id: workerId,
97189
97086
  label,
97190
97087
  status: "running",
97191
- detail: mode === "read_only" ? "read-only" : "general",
97192
- model: `${runModel.provider}/${runModel.model}`,
97088
+ detail: "preparing",
97193
97089
  task,
97194
97090
  ...externalMark
97195
97091
  });
97196
- if (tierRecord !== undefined) {
97197
- emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "system", text: tierRecord } });
97198
- }
97199
- if (externalRuntime !== undefined && deps.runExternal !== undefined) {
97200
- const externalStartedAt = performance.now();
97201
- const startOutcome = await fireSubagentStart("external");
97202
- if (startOutcome === "deny" || startOutcome === "ask") {
97092
+ try {
97093
+ const parent = deps.getParentModel();
97094
+ const detected = deps.getDetectedProviders();
97095
+ const session = { providerId: parent.providerId, modelId: parent.modelId };
97096
+ const catalog = detected.map((p) => ({
97097
+ name: p.name,
97098
+ models: p.models ?? []
97099
+ }));
97100
+ const requestedTier = parseModelTier(typeof input.model_tier === "string" ? input.model_tier : undefined);
97101
+ let categoryModelRequest;
97102
+ if (requestedTier === undefined) {
97103
+ const routingLocation = { cwd: deps.cwd };
97104
+ const [projectRouting, userRouting] = await Promise.all([
97105
+ loadRoutingConfig("project", routingLocation),
97106
+ loadRoutingConfig("user", routingLocation)
97107
+ ]);
97108
+ for (const layer of [projectRouting, userRouting]) {
97109
+ if (layer.error !== undefined) {
97110
+ emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "system", text: `routing: ${layer.error}` } });
97111
+ }
97112
+ }
97113
+ const external = await resolveExternalSetting({ cwd: deps.cwd });
97114
+ const { config: externalConfig } = loadExternalProvidersConfig();
97115
+ const connected = externalAllowedConnectedPredicate(connectedPredicateFrom(catalog), external.value === "on", externalConfig);
97116
+ const resolved = resolveCategoryDetailed("subagents", { project: projectRouting.table, user: userRouting.table }, connected);
97117
+ if (resolved.rejected !== undefined) {
97118
+ emitFleetEvent({
97119
+ kind: "log",
97120
+ id: workerId,
97121
+ entry: { kind: "system", text: `routing: ${describeFallbackNotice(resolved.rejected.assignment, resolved.assignment)}` }
97122
+ });
97123
+ }
97124
+ categoryModelRequest = categoryAssignmentToChildModelRequest(resolved.assignment);
97125
+ }
97126
+ const dispatchModelRequest = requestedTier !== undefined ? { kind: "tier", tier: requestedTier } : categoryModelRequest;
97127
+ let tierMap = buildTierMap(session, catalog);
97128
+ const tierPrices = deps.tierRank?.prices?.(session.providerId);
97129
+ let tierResolution = requestedTier === undefined ? undefined : resolveTierModel(session, requestedTier, catalog, undefined, tierPrices);
97130
+ if (requestedTier !== undefined && deps.tierRank !== undefined) {
97131
+ tierResolution = await resolveTierWithAgent(session, requestedTier, rankDiscoveredModels(session, catalog), {
97132
+ agent: deps.tierRank.agent,
97133
+ ...deps.tierRank.cache !== undefined ? { cache: deps.tierRank.cache } : {},
97134
+ ...tierPrices !== undefined ? { prices: tierPrices } : {},
97135
+ ...parent.baseUrl !== undefined ? { baseUrl: parent.baseUrl } : {}
97136
+ });
97137
+ if (tierResolution.source === "agent-ranked") {
97138
+ tierMap = applyTierResolution(tierMap, tierResolution);
97139
+ }
97140
+ }
97141
+ const ctx = {
97142
+ parentRunId,
97143
+ parentSessionId,
97144
+ parentProvenance,
97145
+ contextManifestHash: sha2569(`${parentRunId}:${parentSessionId}`),
97146
+ canonicalContractVersion: "1.0.0",
97147
+ parentModel: session,
97148
+ parentPolicy: parentShellPolicy(),
97149
+ ledger,
97150
+ detected: detected.length > 0 ? detected : [{ name: parent.providerId }],
97151
+ config: {
97152
+ maxTreeDepth: 2,
97153
+ maxChildren: DEFAULT_MAX_CHILDREN,
97154
+ tiers: tierMap
97155
+ }
97156
+ };
97157
+ const attemptId = idSeq();
97158
+ const branchId = idSeq();
97159
+ const reservationId = idSeq();
97160
+ const artifactHash = sha2569(task);
97161
+ const spawned = spawnSubagent({
97162
+ attempt: { attemptId, number: childSeq },
97163
+ branchId,
97164
+ budgetRequest: {
97165
+ reservationId,
97166
+ maxRuntimeMs: 5 * 60000
97167
+ },
97168
+ policyRequest: childReadOnlyPolicy(),
97169
+ durableResultArtifact: {
97170
+ artifactId: idSeq(),
97171
+ kind: "final-report",
97172
+ hash: artifactHash
97173
+ },
97174
+ ...dispatchModelRequest !== undefined ? { modelRequest: dispatchModelRequest } : {}
97175
+ }, ctx, { idSeq, clock });
97176
+ if (!spawned.ok) {
97203
97177
  emitFleetEvent({
97204
- kind: "upsert",
97205
97178
  id: workerId,
97179
+ kind: "upsert",
97206
97180
  label,
97207
97181
  status: "failed",
97208
- detail: "hook-denied",
97209
- task,
97210
- ...externalMark
97182
+ detail: "denied",
97183
+ task
97211
97184
  });
97185
+ return {
97186
+ status: "Denied",
97187
+ output: `spawn_subagent denied by MAE: ${spawned.reason}`,
97188
+ isError: true
97189
+ };
97190
+ }
97191
+ const runModel = spawned.runModel ?? {
97192
+ provider: parent.providerId,
97193
+ model: parent.modelId
97194
+ };
97195
+ const tierRecord = tierResolution === undefined ? undefined : `model tier ${tierResolution.tier} \u2192 ${runModel.provider}/${runModel.model} ` + `[${tierResolution.source}] ${tierResolution.reason}` + (tierResolution.agent === undefined ? "" : ` (agent ${tierResolution.agent.trigger}, ran on ${tierResolution.agent.runOn.providerId}/${tierResolution.agent.runOn.modelId}, ` + `${tierResolution.agent.cacheHit ? "cache hit" : "asked"}${tierResolution.agent.failure === null ? "" : `, failed: ${tierResolution.agent.failure}`})`);
97196
+ emitFleetEvent({
97197
+ kind: "upsert",
97198
+ id: workerId,
97199
+ label,
97200
+ status: "running",
97201
+ detail: mode === "read_only" ? "read-only" : "general",
97202
+ model: `${runModel.provider}/${runModel.model}`,
97203
+ task,
97204
+ ...externalMark
97205
+ });
97206
+ if (tierRecord !== undefined) {
97207
+ emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "system", text: tierRecord } });
97208
+ }
97209
+ if (externalRuntime !== undefined && deps.runExternal !== undefined) {
97210
+ const externalStartedAt = performance.now();
97211
+ const startOutcome = await fireSubagentStart("external");
97212
+ if (startOutcome === "deny" || startOutcome === "ask") {
97213
+ emitFleetEvent({
97214
+ kind: "upsert",
97215
+ id: workerId,
97216
+ label,
97217
+ status: "failed",
97218
+ detail: "hook-denied",
97219
+ task,
97220
+ ...externalMark
97221
+ });
97222
+ ledger.release(spawned.reservation.reservationId, {
97223
+ maxRuntimeMs: Math.round(performance.now() - externalStartedAt)
97224
+ });
97225
+ return {
97226
+ status: "Denied",
97227
+ output: `spawn_subagent denied by a SubagentStart hook for ${workerId}`,
97228
+ isError: true
97229
+ };
97230
+ }
97231
+ try {
97232
+ const external = await deps.runExternal({ runtime: externalRuntime, task, mode, workerId, label });
97233
+ emitFleetEvent({
97234
+ kind: "upsert",
97235
+ id: workerId,
97236
+ label,
97237
+ status: external.isError ? "failed" : "done",
97238
+ detail: external.status,
97239
+ task,
97240
+ ...externalMark
97241
+ });
97242
+ await fireSubagentStop(external.status);
97243
+ return external;
97244
+ } catch (err) {
97245
+ emitFleetEvent({
97246
+ kind: "upsert",
97247
+ id: workerId,
97248
+ label,
97249
+ status: "failed",
97250
+ detail: "error",
97251
+ task,
97252
+ ...externalMark
97253
+ });
97254
+ await fireSubagentStop("Error");
97255
+ return {
97256
+ status: "Error",
97257
+ output: `external runtime failed before the agent could report: ${err.message}`,
97258
+ isError: true
97259
+ };
97260
+ } finally {
97261
+ ledger.release(spawned.reservation.reservationId, {
97262
+ maxRuntimeMs: Math.round(performance.now() - externalStartedAt)
97263
+ });
97264
+ }
97265
+ }
97266
+ const nativeStartedAt = performance.now();
97267
+ const nativeStartOutcome = await fireSubagentStart("internal");
97268
+ if (nativeStartOutcome === "deny" || nativeStartOutcome === "ask") {
97269
+ emitFleetEvent({ kind: "upsert", id: workerId, label, status: "failed", detail: "hook-denied", task });
97212
97270
  ledger.release(spawned.reservation.reservationId, {
97213
- maxRuntimeMs: Math.round(performance.now() - externalStartedAt)
97271
+ maxRuntimeMs: Math.round(performance.now() - nativeStartedAt)
97214
97272
  });
97215
97273
  return {
97216
97274
  status: "Denied",
@@ -97218,333 +97276,289 @@ function createSpawnSubagentTool(deps) {
97218
97276
  isError: true
97219
97277
  };
97220
97278
  }
97279
+ const cwd = childCwd;
97280
+ const tools = mode === "read_only" ? [
97281
+ ...builtinReadOnlyTools(cwd),
97282
+ ...builtinMetaprojectTools(cwd, makeKeryxRunner(cwd), createMetaprojectAdapter(cwd))
97283
+ ] : [
97284
+ ...builtinReadOnlyTools(cwd),
97285
+ ...builtinMetaprojectTools(cwd, makeKeryxRunner(cwd), createMetaprojectAdapter(cwd))
97286
+ ];
97287
+ let ephemeralDir;
97288
+ let openedChildSlate;
97289
+ let dispatchId = "";
97290
+ let closing = false;
97221
97291
  try {
97222
- const external = await deps.runExternal({ runtime: externalRuntime, task, mode, workerId, label });
97223
- emitFleetEvent({
97224
- kind: "upsert",
97225
- id: workerId,
97226
- label,
97227
- status: external.isError ? "failed" : "done",
97228
- detail: external.status,
97229
- task,
97230
- ...externalMark
97292
+ ephemeralDir = await mkdtemp2(path220.join(tmpdir6(), "keryx-subagent-slate-"));
97293
+ dispatchId = path220.basename(ephemeralDir);
97294
+ openedChildSlate = await openSlate({
97295
+ dir: ephemeralDir,
97296
+ cwd,
97297
+ mintAttemptId: () => idSeq(),
97298
+ runtime: { provider: runModel.provider, model: runModel.model }
97231
97299
  });
97232
- await fireSubagentStop(external.status);
97233
- return external;
97234
- } catch (err) {
97235
- emitFleetEvent({
97236
- kind: "upsert",
97237
- id: workerId,
97238
- label,
97239
- status: "failed",
97240
- detail: "error",
97241
- task,
97242
- ...externalMark
97243
- });
97244
- await fireSubagentStop("Error");
97245
- return {
97246
- status: "Error",
97247
- output: `external runtime failed before the agent could report: ${err.message}`,
97248
- isError: true
97249
- };
97250
- } finally {
97300
+ tools.push(slateWriteSeedTool(() => closing ? undefined : ephemeralDir, idSeq, clock));
97301
+ } catch {
97302
+ openedChildSlate = undefined;
97303
+ }
97304
+ let provider;
97305
+ try {
97306
+ provider = deps.makeProvider(runModel.provider, runModel.model, parent.baseUrl);
97307
+ } catch (cause) {
97308
+ if (ephemeralDir !== undefined) {
97309
+ await rm15(ephemeralDir, { recursive: true, force: true }).catch(() => {});
97310
+ }
97311
+ await fireSubagentStop("Error").catch(() => {});
97251
97312
  ledger.release(spawned.reservation.reservationId, {
97252
- maxRuntimeMs: Math.round(performance.now() - externalStartedAt)
97313
+ maxRuntimeMs: Math.round(performance.now() - nativeStartedAt)
97253
97314
  });
97315
+ throw cause;
97254
97316
  }
97255
- }
97256
- const nativeStartedAt = performance.now();
97257
- const nativeStartOutcome = await fireSubagentStart("internal");
97258
- if (nativeStartOutcome === "deny" || nativeStartOutcome === "ask") {
97259
- emitFleetEvent({ kind: "upsert", id: workerId, label, status: "failed", detail: "hook-denied", task });
97260
- ledger.release(spawned.reservation.reservationId, {
97261
- maxRuntimeMs: Math.round(performance.now() - nativeStartedAt)
97262
- });
97263
- return {
97264
- status: "Denied",
97265
- output: `spawn_subagent denied by a SubagentStart hook for ${workerId}`,
97266
- isError: true
97317
+ const childHooks = deps.hooks === undefined ? undefined : (() => {
97318
+ const childRunId = idSeq();
97319
+ return { runtime: deps.hooks.forChild({ sessionId: workerId, runId: childRunId }), sessionId: workerId, runId: childRunId };
97320
+ })();
97321
+ const childDeps = {
97322
+ provider,
97323
+ providerId: runModel.provider,
97324
+ modelId: runModel.model,
97325
+ tools,
97326
+ ...childHooks !== undefined ? { hooks: childHooks } : {},
97327
+ systemInstruction: "You are a keryx subagent. Complete ONLY the assigned task. " + "Be concise. Use tools when needed. Do not spawn further subagents. " + (configuredMaxToolCalls === undefined ? "" : `You may invoke at most ${configuredMaxToolCalls} tools in total (a hard limit). `) + (advisoryToolCalls === undefined ? "" : `Aim to finish within about ${advisoryToolCalls} tool calls \u2014 a target, not a hard stop; ` + "tool results will tell you when you are close. ") + `You have up to ${maxRounds} model turns (rounds) to complete this task \u2014 each round ` + "may include several tool calls; an identical call repeated does not start a new round " + "but is still capped at a few attempts, so do not retry the same query hoping for a " + "different answer. If a graph/symbol/wiki lookup returns empty or 'not found', that tool " + "has no index for this \u2014 do not re-run it with a slightly reworded query; switch tool " + "(e.g. a direct file read or a plain text/code search) or report the gap instead of " + "spending rounds probing the same dead end. When a tool result says your budget is nearly " + "spent, stop exploring and return your result. If a limit is reached you get one final round " + "in which the only tool is submit_result \u2014 use it to hand back a partial result. " + "End with a short factual summary the parent can use.",
97328
+ idSeq: () => idSeq(),
97329
+ controlNonce: generateControlNonce(),
97330
+ maxRounds,
97331
+ ...configuredMaxToolCalls === undefined ? {} : { maxToolCalls: configuredMaxToolCalls },
97332
+ subagentBudget: advisoryToolCalls === undefined ? {} : { advisoryToolCalls }
97267
97333
  };
97268
- }
97269
- const cwd = childCwd;
97270
- const tools = mode === "read_only" ? [
97271
- ...builtinReadOnlyTools(cwd),
97272
- ...builtinMetaprojectTools(cwd, makeKeryxRunner(cwd), createMetaprojectAdapter(cwd))
97273
- ] : [
97274
- ...builtinReadOnlyTools(cwd),
97275
- ...builtinMetaprojectTools(cwd, makeKeryxRunner(cwd), createMetaprojectAdapter(cwd))
97276
- ];
97277
- let ephemeralDir;
97278
- let openedChildSlate;
97279
- let dispatchId = "";
97280
- let closing = false;
97281
- try {
97282
- ephemeralDir = await mkdtemp2(path220.join(tmpdir6(), "keryx-subagent-slate-"));
97283
- dispatchId = path220.basename(ephemeralDir);
97284
- openedChildSlate = await openSlate({
97285
- dir: ephemeralDir,
97286
- cwd,
97287
- mintAttemptId: () => idSeq(),
97288
- runtime: { provider: runModel.provider, model: runModel.model }
97289
- });
97290
- tools.push(slateWriteSeedTool(() => closing ? undefined : ephemeralDir, idSeq, clock));
97291
- } catch {
97292
- openedChildSlate = undefined;
97293
- }
97294
- let provider;
97295
- try {
97296
- provider = deps.makeProvider(runModel.provider, runModel.model, parent.baseUrl);
97297
- } catch (cause) {
97298
- if (ephemeralDir !== undefined) {
97299
- await rm15(ephemeralDir, { recursive: true, force: true }).catch(() => {});
97300
- }
97301
- await fireSubagentStop("Error").catch(() => {});
97302
- ledger.release(spawned.reservation.reservationId, {
97303
- maxRuntimeMs: Math.round(performance.now() - nativeStartedAt)
97304
- });
97305
- throw cause;
97306
- }
97307
- const childHooks = deps.hooks === undefined ? undefined : (() => {
97308
- const childRunId = idSeq();
97309
- return { runtime: deps.hooks.forChild({ sessionId: workerId, runId: childRunId }), sessionId: workerId, runId: childRunId };
97310
- })();
97311
- const childDeps = {
97312
- provider,
97313
- providerId: runModel.provider,
97314
- modelId: runModel.model,
97315
- tools,
97316
- ...childHooks !== undefined ? { hooks: childHooks } : {},
97317
- systemInstruction: "You are a keryx subagent. Complete ONLY the assigned task. " + "Be concise. Use tools when needed. Do not spawn further subagents. " + (configuredMaxToolCalls === undefined ? "" : `You may invoke at most ${configuredMaxToolCalls} tools in total (a hard limit). `) + (advisoryToolCalls === undefined ? "" : `Aim to finish within about ${advisoryToolCalls} tool calls \u2014 a target, not a hard stop; ` + "tool results will tell you when you are close. ") + `You have up to ${maxRounds} model turns (rounds) to complete this task \u2014 each round ` + "may include several tool calls; an identical call repeated does not start a new round " + "but is still capped at a few attempts, so do not retry the same query hoping for a " + "different answer. If a graph/symbol/wiki lookup returns empty or 'not found', that tool " + "has no index for this \u2014 do not re-run it with a slightly reworded query; switch tool " + "(e.g. a direct file read or a plain text/code search) or report the gap instead of " + "spending rounds probing the same dead end. When a tool result says your budget is nearly " + "spent, stop exploring and return your result. If a limit is reached you get one final round " + "in which the only tool is submit_result \u2014 use it to hand back a partial result. " + "End with a short factual summary the parent can use.",
97318
- idSeq: () => idSeq(),
97319
- controlNonce: generateControlNonce(),
97320
- maxRounds,
97321
- ...configuredMaxToolCalls === undefined ? {} : { maxToolCalls: configuredMaxToolCalls },
97322
- subagentBudget: advisoryToolCalls === undefined ? {} : { advisoryToolCalls }
97323
- };
97324
- let assistant = "";
97325
- let closed = false;
97326
- const internalAbort = new AbortController;
97327
- const composed = composeAbortSignals(toolCtx?.signal, internalAbort.signal);
97328
- const io = {
97329
- write: (s) => {
97330
- assistant += s;
97331
- },
97332
- onAssistantText: (text) => {
97333
- assistant = text;
97334
- if (closed) {
97335
- return;
97336
- }
97337
- emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "text", text } });
97338
- },
97339
- onReasoning: (text) => {
97340
- if (closed) {
97341
- return;
97342
- }
97343
- emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "reasoning", text } });
97344
- },
97345
- onToolCall: (name) => {
97346
- if (closed) {
97347
- return;
97348
- }
97349
- emitFleetEvent({
97350
- kind: "upsert",
97351
- id: workerId,
97352
- label,
97353
- status: "running",
97354
- detail: name.length > 14 ? `${name.slice(0, 12)}\u2026` : name,
97355
- model: `${runModel.provider}/${runModel.model}`,
97356
- task
97357
- });
97358
- emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "tool", text: name } });
97359
- },
97360
- onToolResult: (name, result) => {
97361
- if (closed) {
97362
- return;
97363
- }
97364
- const preview = result.output.trim().slice(0, 400);
97365
- emitFleetEvent({
97366
- kind: "log",
97367
- id: workerId,
97368
- entry: { kind: "result", text: `${name}${result.isError ? " (error)" : ""} ${preview}` }
97334
+ let assistant = "";
97335
+ let closed = false;
97336
+ const internalAbort = new AbortController;
97337
+ const composed = composeAbortSignals(toolCtx?.signal, internalAbort.signal);
97338
+ const io = {
97339
+ write: (s) => {
97340
+ assistant += s;
97341
+ },
97342
+ onAssistantText: (text) => {
97343
+ assistant = text;
97344
+ if (closed) {
97345
+ return;
97346
+ }
97347
+ emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "text", text } });
97348
+ },
97349
+ onReasoning: (text) => {
97350
+ if (closed) {
97351
+ return;
97352
+ }
97353
+ emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "reasoning", text } });
97354
+ },
97355
+ onToolCall: (name) => {
97356
+ if (closed) {
97357
+ return;
97358
+ }
97359
+ emitFleetEvent({
97360
+ kind: "upsert",
97361
+ id: workerId,
97362
+ label,
97363
+ status: "running",
97364
+ detail: name.length > 14 ? `${name.slice(0, 12)}\u2026` : name,
97365
+ model: `${runModel.provider}/${runModel.model}`,
97366
+ task
97367
+ });
97368
+ emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "tool", text: name } });
97369
+ },
97370
+ onToolResult: (name, result) => {
97371
+ if (closed) {
97372
+ return;
97373
+ }
97374
+ const preview = result.output.trim().slice(0, 400);
97375
+ emitFleetEvent({
97376
+ kind: "log",
97377
+ id: workerId,
97378
+ entry: { kind: "result", text: `${name}${result.isError ? " (error)" : ""} ${preview}` }
97379
+ });
97380
+ },
97381
+ onSystem: (text) => {
97382
+ if (closed) {
97383
+ return;
97384
+ }
97385
+ emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "system", text } });
97386
+ },
97387
+ requestApproval: async () => false
97388
+ };
97389
+ const deadlineMs = resolveSubagentTimeoutMs(spawned.reservation.maxRuntimeMs);
97390
+ const startedAt = performance.now();
97391
+ const releaseBudget = () => {
97392
+ ledger.release(spawned.reservation.reservationId, {
97393
+ maxRuntimeMs: Math.round(performance.now() - startedAt)
97369
97394
  });
97370
- },
97371
- onSystem: (text) => {
97372
- if (closed) {
97395
+ };
97396
+ const foldChildSlateAndCleanup = async (status) => {
97397
+ closing = true;
97398
+ if (ephemeralDir === undefined) {
97373
97399
  return;
97374
97400
  }
97375
- emitFleetEvent({ kind: "log", id: workerId, entry: { kind: "system", text } });
97376
- },
97377
- requestApproval: async () => false
97378
- };
97379
- const deadlineMs = resolveSubagentTimeoutMs(spawned.reservation.maxRuntimeMs);
97380
- const startedAt = performance.now();
97381
- const releaseBudget = () => {
97382
- ledger.release(spawned.reservation.reservationId, {
97383
- maxRuntimeMs: Math.round(performance.now() - startedAt)
97384
- });
97385
- };
97386
- const foldChildSlateAndCleanup = async (status) => {
97387
- closing = true;
97388
- if (ephemeralDir === undefined) {
97389
- return;
97390
- }
97391
- const dirToClean = ephemeralDir;
97392
- try {
97393
- await withFileLock(slateLockPath(dirToClean), async () => {
97394
- try {
97395
- const slateSession = deps.getSlateSession?.();
97396
- if (openedChildSlate !== undefined && slateSession !== undefined) {
97397
- try {
97398
- const childSlate = await readSlate(dirToClean);
97399
- const dispatch = {
97400
- anchors: childSlate?.anchors ?? openedChildSlate.anchors,
97401
- course: childSlate?.course ?? openedChildSlate.course,
97402
- seeds: childSlate?.seeds ?? [],
97403
- status
97404
- };
97405
- const parentDir = slateSession.dir;
97406
- await writeSlate(parentDir, (prev) => {
97407
- if (prev === undefined) {
97408
- throw new Error(`foldChildSlateAndCleanup: no open parent slate in ${parentDir}`);
97409
- }
97410
- return {
97411
- ...prev,
97412
- childDispatches: { ...prev.childDispatches ?? {}, [dispatchId]: dispatch }
97401
+ const dirToClean = ephemeralDir;
97402
+ try {
97403
+ await withFileLock(slateLockPath(dirToClean), async () => {
97404
+ try {
97405
+ const slateSession = deps.getSlateSession?.();
97406
+ if (openedChildSlate !== undefined && slateSession !== undefined) {
97407
+ try {
97408
+ const childSlate = await readSlate(dirToClean);
97409
+ const dispatch = {
97410
+ anchors: childSlate?.anchors ?? openedChildSlate.anchors,
97411
+ course: childSlate?.course ?? openedChildSlate.course,
97412
+ seeds: childSlate?.seeds ?? [],
97413
+ status
97413
97414
  };
97414
- });
97415
- } catch (foldCause) {
97416
- const foldMsg = foldCause instanceof Error ? foldCause.message : String(foldCause);
97417
- emitFleetEvent({
97418
- kind: "log",
97419
- id: workerId,
97420
- entry: { kind: "system", text: `slate fold failed (ignored): ${foldMsg}` }
97421
- });
97415
+ const parentDir = slateSession.dir;
97416
+ await writeSlate(parentDir, (prev) => {
97417
+ if (prev === undefined) {
97418
+ throw new Error(`foldChildSlateAndCleanup: no open parent slate in ${parentDir}`);
97419
+ }
97420
+ return {
97421
+ ...prev,
97422
+ childDispatches: { ...prev.childDispatches ?? {}, [dispatchId]: dispatch }
97423
+ };
97424
+ });
97425
+ } catch (foldCause) {
97426
+ const foldMsg = foldCause instanceof Error ? foldCause.message : String(foldCause);
97427
+ emitFleetEvent({
97428
+ kind: "log",
97429
+ id: workerId,
97430
+ entry: { kind: "system", text: `slate fold failed (ignored): ${foldMsg}` }
97431
+ });
97432
+ }
97422
97433
  }
97434
+ } finally {
97435
+ await rm15(dirToClean, { recursive: true, force: true }).catch(() => {});
97423
97436
  }
97424
- } finally {
97425
- await rm15(dirToClean, { recursive: true, force: true }).catch(() => {});
97426
- }
97427
- });
97428
- } catch (lockCause) {
97429
- const lockMsg = lockCause instanceof Error ? lockCause.message : String(lockCause);
97430
- emitFleetEvent({
97431
- kind: "log",
97432
- id: workerId,
97433
- entry: { kind: "system", text: `slate cleanup lock failed (ignored): ${lockMsg}` }
97434
- });
97435
- await rm15(dirToClean, { recursive: true, force: true }).catch(() => {});
97436
- }
97437
- };
97438
- try {
97439
- const history = [];
97440
- if (openedChildSlate !== undefined) {
97441
- history.push({ role: "user", content: renderAnchorsBlock(openedChildSlate.anchors), provenance: "project", injected: true });
97442
- }
97443
- const userLine = `## Subagent task (${mode})
97437
+ });
97438
+ } catch (lockCause) {
97439
+ const lockMsg = lockCause instanceof Error ? lockCause.message : String(lockCause);
97440
+ emitFleetEvent({
97441
+ kind: "log",
97442
+ id: workerId,
97443
+ entry: { kind: "system", text: `slate cleanup lock failed (ignored): ${lockMsg}` }
97444
+ });
97445
+ await rm15(dirToClean, { recursive: true, force: true }).catch(() => {});
97446
+ }
97447
+ };
97448
+ try {
97449
+ const history = [];
97450
+ if (openedChildSlate !== undefined) {
97451
+ history.push({ role: "user", content: renderAnchorsBlock(openedChildSlate.anchors), provenance: "project", injected: true });
97452
+ }
97453
+ const userLine = `## Subagent task (${mode})
97444
97454
  ` + `${task}
97445
97455
 
97446
97456
  ` + `Project root: ${childCwd}
97447
97457
  ` + `Round budget: ${maxRounds} rounds \u2014 plan which tools to try before spending them; prefer a ` + "direct, targeted lookup (exact file path, exact symbol) over a broad/guessed one, and fall " + `back to a different tool rather than repeating a failed call.
97448
97458
 
97449
97459
  ` + "Return a concise summary of findings and any recommended next steps for the parent agent.";
97450
- const turn = runAgentTurn(io, childDeps, history, userLine, { signal: composed.signal });
97451
- let turnResult;
97452
- if (deadlineMs > 0) {
97453
- let timer;
97454
- const expired = new Promise((resolve) => {
97455
- timer = setTimeout(() => resolve("timeout"), deadlineMs);
97456
- });
97457
- let outcome;
97458
- try {
97459
- outcome = await Promise.race([turn.then(() => "done"), expired]);
97460
- } finally {
97461
- if (timer !== undefined)
97462
- clearTimeout(timer);
97463
- }
97464
- if (outcome === "timeout") {
97465
- closed = true;
97466
- internalAbort.abort();
97467
- turn.catch(() => {});
97468
- composed.dispose();
97469
- releaseBudget();
97470
- emitFleetEvent({ kind: "upsert", id: workerId, label, status: "failed", detail: "timeout", task });
97471
- await foldChildSlateAndCleanup("incomplete");
97472
- await fireSubagentStop("Timeout");
97473
- const partial = assistant.trim();
97474
- const foldedPartial = partial.length > 0 ? foldChildSummary(partial).text : "";
97475
- return {
97476
- status: "Timeout",
97477
- output: `subagent ${label} (${workerId}) timed out after ${deadlineMs}ms and was abandoned ` + `(tighten or disable with ${ENV_SUBAGENT_TIMEOUT_MS})` + (foldedPartial.length > 0 ? `
97460
+ const turn = runAgentTurn(io, childDeps, history, userLine, { signal: composed.signal });
97461
+ let turnResult;
97462
+ if (deadlineMs > 0) {
97463
+ let timer;
97464
+ const expired = new Promise((resolve) => {
97465
+ timer = setTimeout(() => resolve("timeout"), deadlineMs);
97466
+ });
97467
+ let outcome;
97468
+ try {
97469
+ outcome = await Promise.race([turn.then(() => "done"), expired]);
97470
+ } finally {
97471
+ if (timer !== undefined)
97472
+ clearTimeout(timer);
97473
+ }
97474
+ if (outcome === "timeout") {
97475
+ closed = true;
97476
+ internalAbort.abort();
97477
+ turn.catch(() => {});
97478
+ composed.dispose();
97479
+ releaseBudget();
97480
+ emitFleetEvent({ kind: "upsert", id: workerId, label, status: "failed", detail: "timeout", task });
97481
+ await foldChildSlateAndCleanup("incomplete");
97482
+ await fireSubagentStop("Timeout");
97483
+ const partial = assistant.trim();
97484
+ const foldedPartial = partial.length > 0 ? foldChildSummary(partial).text : "";
97485
+ return {
97486
+ status: "Timeout",
97487
+ output: `subagent ${label} (${workerId}) timed out after ${deadlineMs}ms and was abandoned ` + `(tighten or disable with ${ENV_SUBAGENT_TIMEOUT_MS})` + (foldedPartial.length > 0 ? `
97478
97488
  --- partial output ---
97479
97489
  ${boundSummary(foldedPartial)}` : ""),
97480
- isError: true,
97481
- ...foldedPartial.length > 0 ? { partial: boundSummary(foldedPartial) } : {}
97482
- };
97490
+ isError: true,
97491
+ ...foldedPartial.length > 0 ? { partial: boundSummary(foldedPartial) } : {}
97492
+ };
97493
+ }
97494
+ turnResult = await turn;
97495
+ } else {
97496
+ turnResult = await turn;
97483
97497
  }
97484
- turnResult = await turn;
97485
- } else {
97486
- turnResult = await turn;
97487
- }
97488
- closed = true;
97489
- composed.dispose();
97490
- releaseBudget();
97491
- const raw = assistant.trim().length > 0 ? assistant.trim() : history.filter((m) => m.role === "assistant").map((m) => m.content).join(`
97498
+ closed = true;
97499
+ composed.dispose();
97500
+ releaseBudget();
97501
+ const raw = assistant.trim().length > 0 ? assistant.trim() : history.filter((m) => m.role === "assistant").map((m) => m.content).join(`
97492
97502
  `).trim() || "(subagent produced no text)";
97493
- const folded = foldChildSummary(raw);
97494
- const status = subagentStatusForFinishReason(turnResult?.finishReason);
97495
- const isError = status !== "Completed";
97496
- emitFleetEvent({
97497
- kind: "upsert",
97498
- id: workerId,
97499
- label,
97500
- status: isError ? "failed" : "done",
97501
- detail: subagentFleetDetail(status),
97502
- model: `${runModel.provider}/${runModel.model}`,
97503
- task
97504
- });
97505
- await foldChildSlateAndCleanup(isError ? "incomplete" : "completed");
97506
- await fireSubagentStop(status);
97507
- const header = `subagent ${label} (${workerId}) ${mode} via ${runModel.provider}/${runModel.model}
97503
+ const folded = foldChildSummary(raw);
97504
+ const status = subagentStatusForFinishReason(turnResult?.finishReason);
97505
+ const isError = status !== "Completed";
97506
+ emitFleetEvent({
97507
+ kind: "upsert",
97508
+ id: workerId,
97509
+ label,
97510
+ status: isError ? "failed" : "done",
97511
+ detail: subagentFleetDetail(status),
97512
+ model: `${runModel.provider}/${runModel.model}`,
97513
+ task
97514
+ });
97515
+ await foldChildSlateAndCleanup(isError ? "incomplete" : "completed");
97516
+ await fireSubagentStop(status);
97517
+ const header = `subagent ${label} (${workerId}) ${mode} via ${runModel.provider}/${runModel.model}
97508
97518
  ` + `MAE reservation: rounds\u2264${maxRounds} ` + (configuredMaxToolCalls === undefined ? "" : `calls\u2264${configuredMaxToolCalls} `) + (advisoryToolCalls === undefined ? "" : `calls~${advisoryToolCalls}(advisory) `) + `runtime\u2264${spawned.reservation.maxRuntimeMs}ms children=${ledger.childCount}
97509
97519
  ` + (tierRecord === undefined ? "" : `${tierRecord}
97510
97520
  `);
97511
- if (status === "Completed") {
97512
- return { status, isError, output: `${header}--- summary ---
97521
+ if (status === "Completed") {
97522
+ return { status, isError, output: `${header}--- summary ---
97513
97523
  ${boundSummary(folded.text)}` };
97514
- }
97515
- const statusLine = formatStoppedStatusLine(status, turnResult);
97516
- const submitted = turnResult?.submittedResult;
97517
- const resultBlock = submitted !== undefined ? foldChildSummary(`--- submitted result (${submitted.status}) ---
97524
+ }
97525
+ const statusLine = formatStoppedStatusLine(status, turnResult);
97526
+ const submitted = turnResult?.submittedResult;
97527
+ const resultBlock = submitted !== undefined ? foldChildSummary(`--- submitted result (${submitted.status}) ---
97518
97528
  ` + `summary: ${submitted.summary}
97519
97529
  ` + `result:
97520
97530
  ${typeof submitted.result === "string" ? submitted.result : JSON.stringify(submitted.result, null, 2)}`).text : foldChildSummary(`no result submitted${turnResult?.submitResultError !== undefined ? ` (${turnResult.submitResultError})` : ""}
97521
97531
  ` + `--- last output ---
97522
97532
  ${raw}`).text;
97523
- const boundedResult = boundSummary(resultBlock);
97524
- return {
97525
- status,
97526
- isError,
97527
- output: `${statusLine}
97533
+ const boundedResult = boundSummary(resultBlock);
97534
+ return {
97535
+ status,
97536
+ isError,
97537
+ output: `${statusLine}
97528
97538
  ${header}${boundedResult}`,
97529
- partial: boundedResult
97530
- };
97539
+ partial: boundedResult
97540
+ };
97541
+ } catch (cause) {
97542
+ closed = true;
97543
+ internalAbort.abort();
97544
+ composed.dispose();
97545
+ releaseBudget();
97546
+ const msg = cause instanceof Error ? cause.message : String(cause);
97547
+ emitFleetEvent({
97548
+ kind: "upsert",
97549
+ id: workerId,
97550
+ label,
97551
+ status: "failed",
97552
+ detail: "error",
97553
+ task
97554
+ });
97555
+ await foldChildSlateAndCleanup("incomplete");
97556
+ await fireSubagentStop("Error");
97557
+ return { status: "Error", output: `subagent ${label} failed: ${msg}`, isError: true };
97558
+ }
97531
97559
  } catch (cause) {
97532
- closed = true;
97533
- internalAbort.abort();
97534
- composed.dispose();
97535
- releaseBudget();
97536
- const msg = cause instanceof Error ? cause.message : String(cause);
97537
- emitFleetEvent({
97538
- kind: "upsert",
97539
- id: workerId,
97540
- label,
97541
- status: "failed",
97542
- detail: "error",
97543
- task
97544
- });
97545
- await foldChildSlateAndCleanup("incomplete");
97546
- await fireSubagentStop("Error");
97547
- return { status: "Error", output: `subagent ${label} failed: ${msg}`, isError: true };
97560
+ emitFleetEvent({ kind: "upsert", id: workerId, label, status: "failed", detail: "setup-error", task });
97561
+ throw cause;
97548
97562
  }
97549
97563
  }
97550
97564
  };
@@ -107425,6 +107439,12 @@ var init_help_groups = __esm(() => {
107425
107439
  group: "Working in keryx shell",
107426
107440
  summary: "Manage the main queue \u2014 /queue <remove|edit|force> [N] (N = qN position, default 1)."
107427
107441
  },
107442
+ {
107443
+ kind: "slash",
107444
+ name: "/tasks",
107445
+ group: "Working in keryx shell",
107446
+ summary: "List supervised shell tasks \u2014 /tasks [output <task_id> [cursor] | kill <task_id>]."
107447
+ },
107428
107448
  {
107429
107449
  kind: "slash",
107430
107450
  name: "/interrupt",
@@ -109761,6 +109781,10 @@ function createBlockView(otui, renderer, parent, block, options = {}) {
109761
109781
  render: (state, opts = {}) => {
109762
109782
  paintHeader(state, opts.focused === true);
109763
109783
  if (state.collapsed) {
109784
+ if (options.collapsedPreview !== undefined) {
109785
+ showBody(options.collapsedPreview);
109786
+ return;
109787
+ }
109764
109788
  dropBody();
109765
109789
  return;
109766
109790
  }
@@ -123085,6 +123109,11 @@ var init_agent_commands = __esm(() => {
123085
123109
  description: "Hand a task to an external agent CLI \u2014 /delegate <agent> <task>",
123086
123110
  modes: AGENT_ONLY
123087
123111
  },
123112
+ {
123113
+ name: "/tasks",
123114
+ description: "Shell tasks \u2014 /tasks, /tasks output <task_id> [cursor], /tasks kill <task_id>",
123115
+ modes: AGENT_ONLY
123116
+ },
123088
123117
  {
123089
123118
  name: "/demote",
123090
123119
  description: "Move a running foreground task to the background \u2014 /demote <task_id>",
@@ -144030,15 +144059,18 @@ function classifyDeterministic(line) {
144030
144059
  return;
144031
144060
  if (REVIEW_RE.test(trimmed))
144032
144061
  return "review";
144062
+ if (RUSSIAN_CHITCHAT_RE.test(trimmed))
144063
+ return "quick";
144033
144064
  const words = trimmed.split(/\s+/).filter((w) => w.length > 0);
144034
144065
  if (trimmed.length <= CHITCHAT_MAX_CHARS && words.length <= CHITCHAT_MAX_WORDS && CHITCHAT_RE.test(trimmed)) {
144035
144066
  return "quick";
144036
144067
  }
144037
144068
  return;
144038
144069
  }
144039
- var CHITCHAT_RE, CHITCHAT_MAX_CHARS = 24, CHITCHAT_MAX_WORDS = 4, REVIEW_RE;
144070
+ var CHITCHAT_RE, CHITCHAT_MAX_CHARS = 24, CHITCHAT_MAX_WORDS = 4, RUSSIAN_CHITCHAT_RE, REVIEW_RE;
144040
144071
  var init_deterministic_shortcuts = __esm(() => {
144041
144072
  CHITCHAT_RE = /^(?:hi|hello|hey|yo|thanks|thank you|thx|ty|ok|okay|k|cool|nice|great|awesome|sounds good|got it|sure|yes|no|yep|yup|nope|nah|good morning|good night|gm|lol|haha|np|no problem|welcome|you're welcome)[.!?]*$/i;
144073
+ RUSSIAN_CHITCHAT_RE = /^(?:\u043F\u0440\u0438\u0432\u0435\u0442|\u0437\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439|\u0437\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435|\u0441\u043F\u0430\u0441\u0438\u0431\u043E|\u043E\u043A|\u0434\u0430|\u043D\u0435\u0442)[.!?]*(?:\s+\u043E\u0442\u0432\u0435\u0442\u044C \u043E\u0434\u043D\u0438\u043C \u0441\u043B\u043E\u0432\u043E\u043C[.!?]*)?$/i;
144042
144074
  REVIEW_RE = /\b(?:code\s+review|review(?:s|ed|ing)?|PRs?|pull\s+requests?)\b/i;
144043
144075
  });
144044
144076
 
@@ -144298,6 +144330,11 @@ async function runRoutingClassifierForTurn(line, opts) {
144298
144330
  }
144299
144331
  return { classification, category, assignment: resolved.assignment };
144300
144332
  }
144333
+ function renderRoutingFallbackLine(result) {
144334
+ if (result === undefined)
144335
+ return "[route fallback: no classifier category; using session model]";
144336
+ return `[route fallback: ${result.category} -> ${describeAssignment(result.assignment)}; using session model]`;
144337
+ }
144301
144338
  function pct6(n) {
144302
144339
  return `${Math.round(n * 100)}%`;
144303
144340
  }
@@ -147101,6 +147138,71 @@ var init_help_first_run = __esm(() => {
147101
147138
  init_config_dir();
147102
147139
  });
147103
147140
 
147141
+ // src/tui/tasks-command.ts
147142
+ async function runTasksCommand(args, registry) {
147143
+ const parts = args.trim().split(/\s+/).filter(Boolean);
147144
+ const usage = `Usage: /tasks [output <task_id> [cursor] | kill <task_id>]
147145
+ `;
147146
+ if (registry === undefined)
147147
+ return `This session tracks no shell tasks.
147148
+ `;
147149
+ if (parts.length === 0) {
147150
+ const tasks = registry.list();
147151
+ return tasks.length === 0 ? `No shell tasks.
147152
+ ` : tasks.map((task) => `${task.jobId} \xB7 ${task.status} \xB7 ${task.phase} \xB7 ${task.description ?? task.command}`).join(`
147153
+ `) + `
147154
+ `;
147155
+ }
147156
+ const [action, id, rawCursor] = parts;
147157
+ if (id === undefined)
147158
+ return usage;
147159
+ if (action === "output" && parts.length <= 3) {
147160
+ if (rawCursor !== undefined && !/^\d+$/.test(rawCursor))
147161
+ return usage;
147162
+ const cursor = Number(rawCursor ?? 0);
147163
+ if (!Number.isSafeInteger(cursor))
147164
+ return usage;
147165
+ const result = registry.readOutputSince(id, cursor);
147166
+ if (!result.ok)
147167
+ return `${result.error}
147168
+ `;
147169
+ return `${id} \xB7 ${result.status} \xB7 next_cursor=${result.nextCursor}${result.missed > 0 ? ` \xB7 missed=${result.missed}` : ""}
147170
+ ${result.output}
147171
+ `;
147172
+ }
147173
+ if (action === "kill" && parts.length === 2) {
147174
+ const result = await registry.kill(id, "operator");
147175
+ if (!result.ok)
147176
+ return `${result.error}
147177
+ `;
147178
+ return `${id} \xB7 ${registry.get(id)?.status ?? "unknown"}
147179
+ `;
147180
+ }
147181
+ return usage;
147182
+ }
147183
+
147184
+ // src/tui/usage-format.ts
147185
+ function formatUsageLine(usage) {
147186
+ const parts = [];
147187
+ if (usage.inputTokens !== undefined)
147188
+ parts.push(`\u2191${usage.inputTokens}`);
147189
+ if (usage.outputTokens !== undefined)
147190
+ parts.push(`\u2193${usage.outputTokens}`);
147191
+ if (parts.length === 0)
147192
+ return;
147193
+ const cache = [];
147194
+ if (usage.cacheReadTokens !== undefined)
147195
+ cache.push(`cache-read ${usage.cacheReadTokens}`);
147196
+ if (usage.cacheWriteTokens !== undefined)
147197
+ cache.push(`cache-write ${usage.cacheWriteTokens}`);
147198
+ if (usage.inputTokens !== undefined && usage.cacheReadTokens !== undefined && usage.cacheWriteTokens !== undefined) {
147199
+ const uncached = usage.inputTokens - usage.cacheReadTokens - usage.cacheWriteTokens;
147200
+ if (uncached >= 0)
147201
+ cache.push(`uncached ${uncached}`);
147202
+ }
147203
+ return `${parts.join(" ")} tokens${cache.length > 0 ? ` \xB7 ${cache.join(" \xB7 ")}` : " \xB7 cache not reported"}`;
147204
+ }
147205
+
147104
147206
  // src/tui/settings-actions.ts
147105
147207
  async function runSettingsCommand(command, handlers) {
147106
147208
  const [name = "", ...rest] = command.trim().split(/\s+/);
@@ -157575,16 +157677,9 @@ function createTuiAgentIo(otui, renderer, transcript) {
157575
157677
  }))}`);
157576
157678
  },
157577
157679
  onUsage: (usage) => {
157578
- const parts = [];
157579
- if (usage.inputTokens !== undefined) {
157580
- parts.push(`\u2191${usage.inputTokens}`);
157581
- }
157582
- if (usage.outputTokens !== undefined) {
157583
- parts.push(`\u2193${usage.outputTokens}`);
157584
- }
157585
- if (parts.length > 0) {
157586
- append(otui.t`${dimChunk(otui, `${parts.join(" ")} tokens`)}`);
157587
- }
157680
+ const line = formatUsageLine(usage);
157681
+ if (line !== undefined)
157682
+ append(otui.t`${dimChunk(otui, line)}`);
157588
157683
  },
157589
157684
  onToolCall: (name, input) => {
157590
157685
  const args = summarizeToolArgs(input);
@@ -162453,6 +162548,10 @@ ${formatThemeList(getThemeId())}`);
162453
162548
  }
162454
162549
  return;
162455
162550
  }
162551
+ if (command.name === "/tasks") {
162552
+ trackCommandWork(() => runTasksCommand(line.slice(command.name.length), deps.jobRegistry).then((text) => io.onSystem?.(text)));
162553
+ return;
162554
+ }
162456
162555
  if (command.name === "/clear" || command.name === "/new") {
162457
162556
  (async () => {
162458
162557
  await closeSlateSession(slateSession, mintTimestampAttemptId);
@@ -163022,6 +163121,15 @@ ${formatThemeList(getThemeId())}`);
163022
163121
  if (line.startsWith("/")) {
163023
163122
  io.onSystem?.(describeUnavailableCommand(line, "agent") ?? `Unknown command: ${line}
163024
163123
  `);
163124
+ const help = renderCommandHelp("agent");
163125
+ addBlock({ kind: "output", fullText: help, summary: "Available commands", lineCount: help.trimEnd().split(`
163126
+ `).length }, {
163127
+ hint: "ctrl+o \xB7 Enter to expand",
163128
+ collapsedPreview: help.trimEnd().split(`
163129
+ `).slice(0, 8).join(`
163130
+ `),
163131
+ maxLines: 500
163132
+ });
163025
163133
  io.onSystem?.(helpText());
163026
163134
  return;
163027
163135
  }
@@ -163258,6 +163366,10 @@ ${formatThemeList(getThemeId())}`);
163258
163366
  (async () => {
163259
163367
  let deps = sessionDeps;
163260
163368
  let routingOutcome;
163369
+ if (routingEnabled && sessionModelExplicit && origin === "operator") {
163370
+ io.onSystem?.(`[route skipped: manual /model selection pins this session]
163371
+ `);
163372
+ }
163261
163373
  if (routingEnabled && !sessionModelExplicit && origin === "operator" && line.trim().length > 0) {
163262
163374
  try {
163263
163375
  routingOutcome = await runRoutingClassifierForTurn(line, {
@@ -163287,7 +163399,12 @@ ${formatThemeList(getThemeId())}`);
163287
163399
  `);
163288
163400
  } catch {
163289
163401
  deps = sessionDeps;
163402
+ io.onSystem?.(`[route fallback: selected model could not be prepared; check availability and external policy; using session model]
163403
+ `);
163290
163404
  }
163405
+ } else {
163406
+ io.onSystem?.(`${renderRoutingFallbackLine(routingOutcome)}
163407
+ `);
163291
163408
  }
163292
163409
  }
163293
163410
  const turnCategory = routingOutcome?.category;
@@ -165563,20 +165680,8 @@ ${rows.length > 0 ? rows.join(`
165563
165680
  `;
165564
165681
  }
165565
165682
  function formatUsage(usage) {
165566
- if (usage === undefined) {
165567
- return "";
165568
- }
165569
- const parts = [];
165570
- if (usage.inputTokens !== undefined) {
165571
- parts.push(`\u2191${usage.inputTokens}`);
165572
- }
165573
- if (usage.outputTokens !== undefined) {
165574
- parts.push(`\u2193${usage.outputTokens}`);
165575
- }
165576
- if (parts.length === 0) {
165577
- return "";
165578
- }
165579
- return style.dim(`${parts.join(" ")} tokens`);
165683
+ const line = usage === undefined ? undefined : formatUsageLine(usage);
165684
+ return line === undefined ? "" : style.dim(line);
165580
165685
  }
165581
165686
  async function runAgentRepl(lines, rich, deps, metaprojectPort, sessionOpts, initialPermissionMode, slateSessionBox = { current: undefined }, events, configDir, orient) {
165582
165687
  const out = rich.write ?? ((s) => {
@@ -166413,6 +166518,8 @@ ${GUTTER}${turnSeparator()}
166413
166518
  `);
166414
166519
  }
166415
166520
  }
166521
+ } else if (command === "/tasks") {
166522
+ agentIo.onSystem?.(await runTasksCommand(rest, deps.jobRegistry));
166416
166523
  } else if (command === "/demote") {
166417
166524
  const parsed = parseDemoteCommand(rest);
166418
166525
  if (!parsed.ok) {
package/dist/core.js CHANGED
@@ -41212,6 +41212,12 @@ var HELP_GROUPS = [
41212
41212
  group: "Working in keryx shell",
41213
41213
  summary: "Manage the main queue \u2014 /queue <remove|edit|force> [N] (N = qN position, default 1)."
41214
41214
  },
41215
+ {
41216
+ kind: "slash",
41217
+ name: "/tasks",
41218
+ group: "Working in keryx shell",
41219
+ summary: "List supervised shell tasks \u2014 /tasks [output <task_id> [cursor] | kill <task_id>]."
41220
+ },
41215
41221
  {
41216
41222
  kind: "slash",
41217
41223
  name: "/interrupt",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.3.75",
3
+ "version": "0.3.76",
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": {