@mrciphersmith/keryx 0.3.75 → 0.3.77

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 +629 -449
  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.77",
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>",
@@ -126890,13 +126919,75 @@ var init_proxy = __esm(() => {
126890
126919
  init_guard();
126891
126920
  });
126892
126921
 
126922
+ // src/commands/granted-json-ids.ts
126923
+ function letters(index) {
126924
+ return String(index).replace(/\d/g, (d) => String.fromCharCode(97 + Number(d)));
126925
+ }
126926
+ function protectJsonIds(text) {
126927
+ const head = text.trim();
126928
+ if (head.length === 0 || head[0] !== "[" && head[0] !== "{")
126929
+ return;
126930
+ if (text.includes(PLACEHOLDER))
126931
+ return;
126932
+ try {
126933
+ JSON.parse(head);
126934
+ } catch {
126935
+ return;
126936
+ }
126937
+ const hidden = [];
126938
+ const hide = (value) => {
126939
+ hidden.push(value);
126940
+ return `${PLACEHOLDER}${letters(hidden.length - 1)}x`;
126941
+ };
126942
+ let out = "";
126943
+ let i = 0;
126944
+ while (i < text.length) {
126945
+ const ch = text[i];
126946
+ if (ch === '"') {
126947
+ let j = i + 1;
126948
+ while (j < text.length && text[j] !== '"')
126949
+ j += text[j] === "\\" ? 2 : 1;
126950
+ const literal = text.slice(i, j + 1);
126951
+ const inner = literal.slice(1, -1);
126952
+ const prefix = GITHUB_URL_PREFIX.exec(inner);
126953
+ const rest = prefix === null ? "" : inner.slice(prefix[0].length);
126954
+ out += prefix !== null && GITHUB_URL_REST.test(rest) ? `"${prefix[0]}${rest.replace(/\d+/g, hide)}"` : literal;
126955
+ i = j + 1;
126956
+ continue;
126957
+ }
126958
+ const number = ch === "-" || ch >= "0" && ch <= "9" ? NUMBER2.exec(text.slice(i, i + 40)) : null;
126959
+ if (number !== null) {
126960
+ const key = /"((?:[^"\\]|\\.)*)"\s*:\s*$/.exec(out.slice(-120))?.[1] ?? "";
126961
+ out += SENSITIVE_KEY.test(key) ? number[0] : hide(number[0]);
126962
+ i += number[0].length;
126963
+ continue;
126964
+ }
126965
+ out += ch;
126966
+ i += 1;
126967
+ }
126968
+ return {
126969
+ text: out,
126970
+ restore: (scrubbed) => scrubbed.replace(new RegExp(`${PLACEHOLDER}([a-j]+)x`, "g"), (whole, index) => {
126971
+ const at = Number(index.replace(/[a-j]/g, (c) => String(c.charCodeAt(0) - 97)));
126972
+ return hidden[at] ?? whole;
126973
+ })
126974
+ };
126975
+ }
126976
+ var PLACEHOLDER = "kxjsonid", GITHUB_URL_PREFIX, GITHUB_URL_REST, SENSITIVE_KEY, NUMBER2;
126977
+ var init_granted_json_ids = __esm(() => {
126978
+ GITHUB_URL_PREFIX = /^https:\/\/(?:api\.)?github\.com\/(?:repos\/)?[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+\//;
126979
+ GITHUB_URL_REST = /^(?:actions\/runs|pull|issues)\/\d+(?:\/[A-Za-z0-9_-]+)*(?:#[A-Za-z_-]+-?\d+)?$/;
126980
+ SENSITIVE_KEY = /token|secret|pass|key|auth|credential|private|ssn|phone|card|account|iban|pin|otp/i;
126981
+ NUMBER2 = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?/;
126982
+ });
126983
+
126893
126984
  // src/commands/trigger-agent-task.ts
126894
126985
  import { execFile as execFile11 } from "child_process";
126895
126986
  import { randomUUID as randomUUID35 } from "crypto";
126896
126987
  import { mkdtemp as mkdtemp5, mkdir as mkdir60, readdir as readdir42, rm as rm19, writeFile as writeFile37 } from "fs/promises";
126897
126988
  import { homedir as homedir12, tmpdir as tmpdir11 } from "os";
126898
126989
  import path266 from "path";
126899
- function scrubGrantedOutput(text, env, secrets = []) {
126990
+ function scrubGrantedOutput(text, env, secrets = [], json = false) {
126900
126991
  let out = text;
126901
126992
  for (const value of secrets) {
126902
126993
  if (value.length >= 8)
@@ -126909,10 +127000,18 @@ function scrubGrantedOutput(text, env, secrets = []) {
126909
127000
  }
126910
127001
  for (const [shape, mask] of TOKEN_SHAPES)
126911
127002
  out = out.replace(shape, mask);
127003
+ if (json) {
127004
+ const at = out.indexOf(STDERR_MARK);
127005
+ const protectedJson = protectJsonIds(at === -1 ? out : out.slice(0, at));
127006
+ if (protectedJson !== undefined) {
127007
+ const tail = at === -1 ? "" : redactSensitiveText(out.slice(at));
127008
+ return protectedJson.restore(redactSensitiveText(protectedJson.text)) + tail;
127009
+ }
127010
+ }
126912
127011
  return redactSensitiveText(out);
126913
127012
  }
126914
- function scrubThenCap(raw, env, secrets, max = GRANTED_MAX_BYTES) {
126915
- const scrubbed = scrubGrantedOutput(raw, env, secrets);
127013
+ function scrubThenCap(raw, env, secrets, max = GRANTED_MAX_BYTES, json = false) {
127014
+ const scrubbed = scrubGrantedOutput(raw, env, secrets, json);
126916
127015
  if (scrubbed.length <= max)
126917
127016
  return scrubbed;
126918
127017
  const head = scrubbed.slice(0, max);
@@ -126930,7 +127029,7 @@ ${stderr}` : ""}`;
126930
127029
  const code = error === null ? 0 : typeof error.code === "number" ? error.code : null;
126931
127030
  const reason = error === null ? "" : `
126932
127031
  [exit: ${code ?? error.message}]`;
126933
- resolve({ output: `${scrubThenCap(raw, env, secrets)}${scrubGrantedOutput(reason, env, secrets)}`, exitCode: code, ok: error === null });
127032
+ resolve({ output: `${scrubThenCap(raw, env, secrets, GRANTED_MAX_BYTES, true)}${scrubGrantedOutput(reason, env, secrets)}`, exitCode: code, ok: error === null });
126934
127033
  });
126935
127034
  });
126936
127035
  }
@@ -127297,7 +127396,9 @@ function defaultArmTimeout2(ms, fire) {
127297
127396
  timer.unref?.();
127298
127397
  return () => clearTimeout(timer);
127299
127398
  }
127300
- var GRANTED_TIMEOUT_MS = 30000, GRANTED_MAX_BYTES, SECRET_ENV_NAME, TOKEN_SHAPES;
127399
+ var GRANTED_TIMEOUT_MS = 30000, GRANTED_MAX_BYTES, STDERR_MARK = `
127400
+ [stderr]
127401
+ `, SECRET_ENV_NAME, TOKEN_SHAPES;
127301
127402
  var init_trigger_agent_task = __esm(() => {
127302
127403
  init_agent();
127303
127404
  init_agent_hooks();
@@ -127309,6 +127410,7 @@ var init_trigger_agent_task = __esm(() => {
127309
127410
  init_fs();
127310
127411
  init_maintenance_lock();
127311
127412
  init_service2();
127413
+ init_granted_json_ids();
127312
127414
  init_granted_binary();
127313
127415
  init_schedule_verify();
127314
127416
  init_granted_tools();
@@ -127359,9 +127461,9 @@ function ghEnvForProject(projectRoot, base = process.env) {
127359
127461
  function parseGrantedOutput(output, ok, exitCode) {
127360
127462
  const exit = EXIT_MARK.exec(output);
127361
127463
  const withoutExit = exit === null ? output : output.slice(0, exit.index);
127362
- const stderrAt = withoutExit.indexOf(STDERR_MARK);
127464
+ const stderrAt = withoutExit.indexOf(STDERR_MARK2);
127363
127465
  const stdout = stderrAt === -1 ? withoutExit : withoutExit.slice(0, stderrAt);
127364
- const stderr = stderrAt === -1 ? "" : withoutExit.slice(stderrAt + STDERR_MARK.length).trim();
127466
+ const stderr = stderrAt === -1 ? "" : withoutExit.slice(stderrAt + STDERR_MARK2.length).trim();
127365
127467
  if (!ok) {
127366
127468
  const why = stderr.length > 0 ? stderr : exit !== null ? exit[0].trim() : "gh failed";
127367
127469
  return { ok: false, stdout: "", detail: `${why.replace(/\s+/g, " ").slice(0, 300)}`, exitCode };
@@ -127371,7 +127473,7 @@ function parseGrantedOutput(output, ok, exitCode) {
127371
127473
  }
127372
127474
  return { ok: true, stdout, detail: "", exitCode };
127373
127475
  }
127374
- var GH_ENV_ALLOWED, STDERR_MARK = `
127476
+ var GH_ENV_ALLOWED, STDERR_MARK2 = `
127375
127477
  [stderr]
127376
127478
  `, TRUNCATED, EXIT_MARK, defaultGhRunner = async (call) => {
127377
127479
  const result = await runGrantedCommand(call.bin, call.argv, call.cwd, call.env, call.signal, call.secrets);
@@ -144030,15 +144132,18 @@ function classifyDeterministic(line) {
144030
144132
  return;
144031
144133
  if (REVIEW_RE.test(trimmed))
144032
144134
  return "review";
144135
+ if (RUSSIAN_CHITCHAT_RE.test(trimmed))
144136
+ return "quick";
144033
144137
  const words = trimmed.split(/\s+/).filter((w) => w.length > 0);
144034
144138
  if (trimmed.length <= CHITCHAT_MAX_CHARS && words.length <= CHITCHAT_MAX_WORDS && CHITCHAT_RE.test(trimmed)) {
144035
144139
  return "quick";
144036
144140
  }
144037
144141
  return;
144038
144142
  }
144039
- var CHITCHAT_RE, CHITCHAT_MAX_CHARS = 24, CHITCHAT_MAX_WORDS = 4, REVIEW_RE;
144143
+ var CHITCHAT_RE, CHITCHAT_MAX_CHARS = 24, CHITCHAT_MAX_WORDS = 4, RUSSIAN_CHITCHAT_RE, REVIEW_RE;
144040
144144
  var init_deterministic_shortcuts = __esm(() => {
144041
144145
  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;
144146
+ 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
144147
  REVIEW_RE = /\b(?:code\s+review|review(?:s|ed|ing)?|PRs?|pull\s+requests?)\b/i;
144043
144148
  });
144044
144149
 
@@ -144298,6 +144403,11 @@ async function runRoutingClassifierForTurn(line, opts) {
144298
144403
  }
144299
144404
  return { classification, category, assignment: resolved.assignment };
144300
144405
  }
144406
+ function renderRoutingFallbackLine(result) {
144407
+ if (result === undefined)
144408
+ return "[route fallback: no classifier category; using session model]";
144409
+ return `[route fallback: ${result.category} -> ${describeAssignment(result.assignment)}; using session model]`;
144410
+ }
144301
144411
  function pct6(n) {
144302
144412
  return `${Math.round(n * 100)}%`;
144303
144413
  }
@@ -147101,6 +147211,71 @@ var init_help_first_run = __esm(() => {
147101
147211
  init_config_dir();
147102
147212
  });
147103
147213
 
147214
+ // src/tui/tasks-command.ts
147215
+ async function runTasksCommand(args, registry) {
147216
+ const parts = args.trim().split(/\s+/).filter(Boolean);
147217
+ const usage = `Usage: /tasks [output <task_id> [cursor] | kill <task_id>]
147218
+ `;
147219
+ if (registry === undefined)
147220
+ return `This session tracks no shell tasks.
147221
+ `;
147222
+ if (parts.length === 0) {
147223
+ const tasks = registry.list();
147224
+ return tasks.length === 0 ? `No shell tasks.
147225
+ ` : tasks.map((task) => `${task.jobId} \xB7 ${task.status} \xB7 ${task.phase} \xB7 ${task.description ?? task.command}`).join(`
147226
+ `) + `
147227
+ `;
147228
+ }
147229
+ const [action, id, rawCursor] = parts;
147230
+ if (id === undefined)
147231
+ return usage;
147232
+ if (action === "output" && parts.length <= 3) {
147233
+ if (rawCursor !== undefined && !/^\d+$/.test(rawCursor))
147234
+ return usage;
147235
+ const cursor = Number(rawCursor ?? 0);
147236
+ if (!Number.isSafeInteger(cursor))
147237
+ return usage;
147238
+ const result = registry.readOutputSince(id, cursor);
147239
+ if (!result.ok)
147240
+ return `${result.error}
147241
+ `;
147242
+ return `${id} \xB7 ${result.status} \xB7 next_cursor=${result.nextCursor}${result.missed > 0 ? ` \xB7 missed=${result.missed}` : ""}
147243
+ ${result.output}
147244
+ `;
147245
+ }
147246
+ if (action === "kill" && parts.length === 2) {
147247
+ const result = await registry.kill(id, "operator");
147248
+ if (!result.ok)
147249
+ return `${result.error}
147250
+ `;
147251
+ return `${id} \xB7 ${registry.get(id)?.status ?? "unknown"}
147252
+ `;
147253
+ }
147254
+ return usage;
147255
+ }
147256
+
147257
+ // src/tui/usage-format.ts
147258
+ function formatUsageLine(usage) {
147259
+ const parts = [];
147260
+ if (usage.inputTokens !== undefined)
147261
+ parts.push(`\u2191${usage.inputTokens}`);
147262
+ if (usage.outputTokens !== undefined)
147263
+ parts.push(`\u2193${usage.outputTokens}`);
147264
+ if (parts.length === 0)
147265
+ return;
147266
+ const cache = [];
147267
+ if (usage.cacheReadTokens !== undefined)
147268
+ cache.push(`cache-read ${usage.cacheReadTokens}`);
147269
+ if (usage.cacheWriteTokens !== undefined)
147270
+ cache.push(`cache-write ${usage.cacheWriteTokens}`);
147271
+ if (usage.inputTokens !== undefined && usage.cacheReadTokens !== undefined && usage.cacheWriteTokens !== undefined) {
147272
+ const uncached = usage.inputTokens - usage.cacheReadTokens - usage.cacheWriteTokens;
147273
+ if (uncached >= 0)
147274
+ cache.push(`uncached ${uncached}`);
147275
+ }
147276
+ return `${parts.join(" ")} tokens${cache.length > 0 ? ` \xB7 ${cache.join(" \xB7 ")}` : " \xB7 cache not reported"}`;
147277
+ }
147278
+
147104
147279
  // src/tui/settings-actions.ts
147105
147280
  async function runSettingsCommand(command, handlers) {
147106
147281
  const [name = "", ...rest] = command.trim().split(/\s+/);
@@ -157575,16 +157750,9 @@ function createTuiAgentIo(otui, renderer, transcript) {
157575
157750
  }))}`);
157576
157751
  },
157577
157752
  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
- }
157753
+ const line = formatUsageLine(usage);
157754
+ if (line !== undefined)
157755
+ append(otui.t`${dimChunk(otui, line)}`);
157588
157756
  },
157589
157757
  onToolCall: (name, input) => {
157590
157758
  const args = summarizeToolArgs(input);
@@ -162453,6 +162621,10 @@ ${formatThemeList(getThemeId())}`);
162453
162621
  }
162454
162622
  return;
162455
162623
  }
162624
+ if (command.name === "/tasks") {
162625
+ trackCommandWork(() => runTasksCommand(line.slice(command.name.length), deps.jobRegistry).then((text) => io.onSystem?.(text)));
162626
+ return;
162627
+ }
162456
162628
  if (command.name === "/clear" || command.name === "/new") {
162457
162629
  (async () => {
162458
162630
  await closeSlateSession(slateSession, mintTimestampAttemptId);
@@ -163022,6 +163194,15 @@ ${formatThemeList(getThemeId())}`);
163022
163194
  if (line.startsWith("/")) {
163023
163195
  io.onSystem?.(describeUnavailableCommand(line, "agent") ?? `Unknown command: ${line}
163024
163196
  `);
163197
+ const help = renderCommandHelp("agent");
163198
+ addBlock({ kind: "output", fullText: help, summary: "Available commands", lineCount: help.trimEnd().split(`
163199
+ `).length }, {
163200
+ hint: "ctrl+o \xB7 Enter to expand",
163201
+ collapsedPreview: help.trimEnd().split(`
163202
+ `).slice(0, 8).join(`
163203
+ `),
163204
+ maxLines: 500
163205
+ });
163025
163206
  io.onSystem?.(helpText());
163026
163207
  return;
163027
163208
  }
@@ -163258,6 +163439,10 @@ ${formatThemeList(getThemeId())}`);
163258
163439
  (async () => {
163259
163440
  let deps = sessionDeps;
163260
163441
  let routingOutcome;
163442
+ if (routingEnabled && sessionModelExplicit && origin === "operator") {
163443
+ io.onSystem?.(`[route skipped: manual /model selection pins this session]
163444
+ `);
163445
+ }
163261
163446
  if (routingEnabled && !sessionModelExplicit && origin === "operator" && line.trim().length > 0) {
163262
163447
  try {
163263
163448
  routingOutcome = await runRoutingClassifierForTurn(line, {
@@ -163287,7 +163472,12 @@ ${formatThemeList(getThemeId())}`);
163287
163472
  `);
163288
163473
  } catch {
163289
163474
  deps = sessionDeps;
163475
+ io.onSystem?.(`[route fallback: selected model could not be prepared; check availability and external policy; using session model]
163476
+ `);
163290
163477
  }
163478
+ } else {
163479
+ io.onSystem?.(`${renderRoutingFallbackLine(routingOutcome)}
163480
+ `);
163291
163481
  }
163292
163482
  }
163293
163483
  const turnCategory = routingOutcome?.category;
@@ -165563,20 +165753,8 @@ ${rows.length > 0 ? rows.join(`
165563
165753
  `;
165564
165754
  }
165565
165755
  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`);
165756
+ const line = usage === undefined ? undefined : formatUsageLine(usage);
165757
+ return line === undefined ? "" : style.dim(line);
165580
165758
  }
165581
165759
  async function runAgentRepl(lines, rich, deps, metaprojectPort, sessionOpts, initialPermissionMode, slateSessionBox = { current: undefined }, events, configDir, orient) {
165582
165760
  const out = rich.write ?? ((s) => {
@@ -166413,6 +166591,8 @@ ${GUTTER}${turnSeparator()}
166413
166591
  `);
166414
166592
  }
166415
166593
  }
166594
+ } else if (command === "/tasks") {
166595
+ agentIo.onSystem?.(await runTasksCommand(rest, deps.jobRegistry));
166416
166596
  } else if (command === "/demote") {
166417
166597
  const parsed = parseDemoteCommand(rest);
166418
166598
  if (!parsed.ok) {
@@ -185161,10 +185341,10 @@ function codeOf(text) {
185161
185341
  return stripTrailingComment2(text).trimEnd();
185162
185342
  }
185163
185343
  function numericSkeleton(text) {
185164
- return text.replace(NUMBER2, "\x00");
185344
+ return text.replace(NUMBER3, "\x00");
185165
185345
  }
185166
185346
  function numbersOf(text) {
185167
- return [...text.matchAll(NUMBER2)].map((match) => ({ value: Number(match[0]), index: match.index ?? 0 }));
185347
+ return [...text.matchAll(NUMBER3)].map((match) => ({ value: Number(match[0]), index: match.index ?? 0 }));
185168
185348
  }
185169
185349
  function enclosingNames(code, index) {
185170
185350
  const names = [];
@@ -185427,7 +185607,7 @@ function renderFloorMarkdown(report) {
185427
185607
  return lines.join(`
185428
185608
  `);
185429
185609
  }
185430
- var FLOOR_FINDING_KINDS, COMMENT_OPENER, FLOOR_WORDS, CEILING_WORDS, CAPACITY_WORDS, NUMBER2, KEY_SEPARATORS, TRAILING_IDENTIFIER, TRAILING_INDEX, OPENS_CONTAINER, TYPE_KEYWORDS, COMMENTED_LINE, MODIFIER_SEGMENT, DISABLED_CALL, DISABLED_ANNOTATION, OTHER_TEST_PATHS, ASSERTION_HEAD, SUPPRESSION_MARKERS, ANNOTATION_MARKERS;
185610
+ var FLOOR_FINDING_KINDS, COMMENT_OPENER, FLOOR_WORDS, CEILING_WORDS, CAPACITY_WORDS, NUMBER3, KEY_SEPARATORS, TRAILING_IDENTIFIER, TRAILING_INDEX, OPENS_CONTAINER, TYPE_KEYWORDS, COMMENTED_LINE, MODIFIER_SEGMENT, DISABLED_CALL, DISABLED_ANNOTATION, OTHER_TEST_PATHS, ASSERTION_HEAD, SUPPRESSION_MARKERS, ANNOTATION_MARKERS;
185431
185611
  var init_floor = __esm(() => {
185432
185612
  init_selection();
185433
185613
  FLOOR_FINDING_KINDS = [
@@ -185517,7 +185697,7 @@ var init_floor = __esm(() => {
185517
185697
  "parallel",
185518
185698
  "batch"
185519
185699
  ]);
185520
- NUMBER2 = /[0-9]+(?:\.[0-9]+)?/g;
185700
+ NUMBER3 = /[0-9]+(?:\.[0-9]+)?/g;
185521
185701
  KEY_SEPARATORS = /[\s:=(["'`{<]*$/;
185522
185702
  TRAILING_IDENTIFIER = /[A-Za-z0-9_$.-]+$/;
185523
185703
  TRAILING_INDEX = /\[\s*[0-9]*\s*\]$/;