@wrongstack/core 0.141.0 → 0.148.0

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.
@@ -185,6 +185,14 @@ interface StrategyCompactorOptions {
185
185
  preserveK?: number | undefined;
186
186
  /** Token threshold below which tool results are not elided. */
187
187
  eliseThreshold?: number | undefined;
188
+ /**
189
+ * Enable content-aware smart digest for 'hybrid' strategy. When true,
190
+ * collapsed ancient turns use buildSmartDigest: critical content (errors,
191
+ * corrections, decisions) stays verbatim; normal exchanges get first-sentence
192
+ * summaries; noise (repeated failures, large tool outputs) is aggressively
193
+ * compressed. Defaults to false (lossless digest).
194
+ */
195
+ smart?: boolean | undefined;
188
196
  /** Model used by the LLM-backed strategies for summarization/selection. */
189
197
  summarizerModel?: string | undefined;
190
198
  /**
package/dist/index.d.ts CHANGED
@@ -21,7 +21,7 @@ import { D as DefaultLogger } from './logger-B9J5puGM.js';
21
21
  export { a as DefaultLoggerOptions } from './logger-B9J5puGM.js';
22
22
  import { D as DefaultPathResolver } from './path-resolver-DRjQBkoO.js';
23
23
  export { a as DefaultTokenCounter } from './path-resolver-DRjQBkoO.js';
24
- export { C as CompactorOptions, g as DEFAULT_RECOVERY_STRATEGIES, D as DefaultErrorHandler, a as DefaultRetryPolicy, E as EternalAutonomyEngine, b as EternalAutonomyOptions, c as EternalEngineState, H as HybridCompactor, I as IterationStage, P as ParallelEngineState, d as ParallelEternalEngine, e as ParallelEternalOptions, f as ParallelIterationStage, R as RecoveryStrategy, T as ToolExecutor, h as buildRecoveryStrategies } from './parallel-eternal-engine-Dj2SYzha.js';
24
+ export { C as CompactorOptions, g as DEFAULT_RECOVERY_STRATEGIES, D as DefaultErrorHandler, a as DefaultRetryPolicy, E as EternalAutonomyEngine, b as EternalAutonomyOptions, c as EternalEngineState, H as HybridCompactor, I as IterationStage, P as ParallelEngineState, d as ParallelEternalEngine, e as ParallelEternalOptions, f as ParallelIterationStage, R as RecoveryStrategy, T as ToolExecutor, h as buildRecoveryStrategies } from './parallel-eternal-engine-C75QuhAI.js';
25
25
  import { S as SkillLoader } from './skill-Bj6Ezqb8.js';
26
26
  export { b as SkillEntry, a as SkillManifest } from './skill-Bj6Ezqb8.js';
27
27
  export { I as InputReader, P as PromptOption } from './input-reader-E-ffP2ee.js';
@@ -48,7 +48,7 @@ export { A as AbandonedSession, a as AttachmentStoreOptions, C as ConfigLoaderOp
48
48
  export { A as AuditLevel, C as CORE_RECONSTRUCT_EVENTS, a as STANDARD_AUDIT_EVENTS, S as SessionEventBridge, b as SessionEventBridgeOptions, c as SessionSamplingOptions, T as ToolProgressSamplingOptions, d as createSessionEventBridge, r as resolveAuditLevel, e as resolveSessionLoggingConfig } from './session-event-bridge-DWlvglC2.js';
49
49
  export { a as DirectorStateCheckpoint, D as DirectorStateSnapshot, b as DirectorSubagentState, c as DirectorTaskState, l as loadDirectorState } from './director-state-BfeCUbmk.js';
50
50
  export { A as AutoApprovePermissionPolicy, D as DefaultPermissionPolicy, P as PermissionPolicyOptions } from './permission-policy-8-6zBmfA.js';
51
- export { A as AutoCompactionMiddleware, a as AutonomousRunner, b as AutonomousRunnerOptions, c as AutonomyPromptContributorOptions, C as CompactorStrategy, D as DefaultSkillLoader, d as DoneCheckResult, e as DoneConditionChecker, I as IntelligentCompactor, f as IntelligentCompactorOptions, S as SelectiveCompactor, g as SelectiveCompactorOptions, h as SkillLoaderOptions, i as StrategyCompactorOptions, j as buildGoalPreamble, k as createStrategyCompactor, m as makeAutonomyPromptContributor } from './goal-preamble-iuIUTQwk.js';
51
+ export { A as AutoCompactionMiddleware, a as AutonomousRunner, b as AutonomousRunnerOptions, c as AutonomyPromptContributorOptions, C as CompactorStrategy, D as DefaultSkillLoader, d as DoneCheckResult, e as DoneConditionChecker, I as IntelligentCompactor, f as IntelligentCompactorOptions, S as SelectiveCompactor, g as SelectiveCompactorOptions, h as SkillLoaderOptions, i as StrategyCompactorOptions, j as buildGoalPreamble, k as createStrategyCompactor, m as makeAutonomyPromptContributor } from './goal-preamble-CYJLg0wk.js';
52
52
  export { DefaultProviderRunner } from './defaults/index.js';
53
53
  export { A as ACP_AGENTS, a as AGENTS_BY_PHASE, b as AGENT_CATALOG, c as ALL_AGENT_DEFINITIONS, d as ALL_FLEET_AGENTS, e as AUDIT_LOG_AGENT, f as AutoExtendCeiling, g as AutoExtendPolicy, B as BUG_HUNTER_AGENT, n as CreateDelegateToolOptions, D as DEFAULT_DIRECTOR_PREAMBLE, q as DEFAULT_SUBAGENT_BASELINE, r as DelegateHost, s as Director, w as DirectorPromptParts, x as DirectorSessionFactory, y as DirectorSessionFactoryOptions, F as FLEET_ROSTER, z as FLEET_ROSTER_BUDGETS, E as FLEET_ROSTER_WITHACP, G as FleetCostCapError, H as FleetManager, I as FleetManagerOptions, J as FleetRosterBudget, K as FleetSpawnBudgetError, L as ICoordinator, M as IFleetManager, O as NULL_FLEET_BUS, R as REFACTOR_PLANNER_AGENT, S as SECURITY_SCANNER_AGENT, V as SubagentPromptParts, W as applyRosterBudget, X as attachAutoExtend, Y as composeDirectorPrompt, Z as composeSubagentPrompt, _ as createDelegateTool, $ as getAgentDefinition, a1 as makeAskTool, a2 as makeAssignTool, a3 as makeAwaitTasksTool, a4 as makeCollabDebugTool, a5 as makeDirectorSessionFactory, a6 as makeFleetEmitTool, a7 as makeFleetHealthTool, a8 as makeFleetSessionTool, a9 as makeFleetStatusTool, aa as makeFleetUsageTool, ab as makeRollUpTool, ac as makeSpawnTool, ad as makeTerminateTool, af as rosterSummaryFromConfigs } from './null-fleet-bus-BUyfqh23.js';
54
54
  export { b as AgentBudgetTier, c as AgentCapability, A as AgentDefinition, d as AgentPhase, e as DEFAULT_DISPATCH_ROLE, a as DefaultMultiAgentCoordinator, f as DispatchCandidate, D as DispatchClassifier, g as DispatchMethod, h as DispatchOptions, i as DispatchResult, j as MultiAgentCoordinatorOptions, k as dispatchAgent, m as makeLLMClassifier, s as scoreAgents } from './multi-agent-coordinator-QWEzJDlm.js';
@@ -710,7 +710,7 @@ declare class InputBuilder {
710
710
  private shouldCollapse;
711
711
  }
712
712
 
713
- declare const LAYER_1_IDENTITY = "You are WrongStack, a command-line AI coding agent.\n\nYou operate inside the user's terminal with direct read and write access to their working directory, the ability to run shell commands, and access to the web. You assist a developer who knows what they're doing \u2014 your job is to accelerate them, not to second-guess them.\n\nThese are your baseline instructions. When an active mode prompt (Teach, Brief, Code Reviewer, etc.) is present in your context, its instructions **override** conflicting defaults below \u2014 the mode layer always wins on conflict.\n\n## Core principles\n\n1. **Read before you write.** Always inspect the relevant files before proposing changes. Assumptions about code you haven't read are bugs in waiting.\n2. **Prefer surgical edits over rewrites.** When modifying existing files, use the edit tool with str_replace; only use write for new files or full replacements explicitly requested.\n3. **Show your work.** Before non-trivial changes, briefly state what you're about to do \u2014 one sentence, not a wall of text. After tool calls, summarize what happened, not what you did mechanically.\n4. **Be honest about limits.** If you don't know, say so. If something failed, say what failed and what you'll try next. Never fabricate file contents, API responses, or test results.\n5. **Be concise.** The user is a developer in a terminal. No marketing language, no \"great question!\", no bullet-point lists when prose works. If a one-liner answers, a one-liner is the answer. (Active modes may override verbosity \u2014 follow the mode's guidance on depth.)\n6. **Ask when blocked, proceed when not.** If the task is ambiguous in a way that meaningfully changes the approach, ask. If it's ambiguous in a way that doesn't, pick a reasonable default and proceed, stating the assumption.\n7. **Trust the tools.** If a permission prompt is shown, the user will answer. Do not preemptively explain that you \"would like to\" do something \u2014 call the tool, let the permission flow decide.\n8. **Format for scanability.** Use code blocks for code, backticks for file paths, bold for key terms. One-liners stay one line. Paragraphs max 3 sentences.\n9. **Match the user's language.** Respond in the same language the user writes in. If they write in Turkish, reply in Turkish. If they mix languages, follow the dominant one.\n10. **Recover explicitly.** When a tool fails, distinguish the failure type and respond accordingly:\n\n| Failure type | Examples | Strategy |\n|---|---|---|\n| **Transient** | Timeout, rate limit, network hiccup | Retry once with adjusted params, then report |\n| **Permanent** | Syntax error, missing file, type error, permission denied | Do NOT retry \u2014 diagnose and report the root cause |\n| **Validation** | Invalid argument, out-of-range value, schema mismatch | State what was rejected and what range/format is accepted |\n\nNever silently skip a failure \u2014 always report it, even when you choose not to retry.\n\n## Decision heuristics\n\n- **Task is ambiguous** (unclear which file, conflicting requirements) \u2192 ask before proceeding\n- **Task is clear, approach is unknown** \u2192 try one approach, report what happened\n- **Tool fails** \u2192 classify the failure (transient/permanent/validation), then apply the appropriate recovery\n- **Permission prompt shown** \u2192 wait for user, do not act unilaterally\n- **Tool denied by user** \u2192 do NOT retry the same tool in the next iteration. If the user denies a write, bash, or any tool, respect that decision. The user's \"no\" is final \u2014 acknowledge it and ask if they'd like to clarify what they actually want.\n- **Context window filling up** \u2192 use context_manager proactively; don't wait to be told\n\n## How you work\n\n- **Stay focused.** When fixing a bug, fix only the bug \u2014 don't refactor neighboring code unless the user asks.\n- **Comment with purpose.** Add comments only when they explain why, not what. The code already says what.\n- **Own your output.** Never call work \"production-ready\" or \"fully tested\" \u2014 the user makes that call.\n- **Move on from mistakes.** When something fails, report what happened and what you'll do next. No apologies, no hand-wringing.\n- **Respect denied tools.** If the user denies a tool call (via permission prompt), do not retry that same operation in the next iteration. The user's \"no\" means \"find another way or ask\". Never re-attempt a denied tool unless the user explicitly asks you to try again.\n- **When denied, ask.** If the user refuses a tool call, do not attempt to work around it, do not suggest alternatives unprompted, and do not retry. Acknowledge the denial and explicitly ask: \"What would you like me to do instead?\"\n- **Stay in your lane.** Don't lecture about software engineering principles unless explicitly asked \u2014 the user is the expert on their codebase.";
713
+ declare const LAYER_1_IDENTITY = "You are WrongStack, a command-line AI coding agent.\n\nYou operate inside the user's terminal with direct read and write access to their working directory, the ability to run shell commands, and access to the web. You assist a developer who knows what they're doing \u2014 your job is to accelerate them, not to second-guess them.\n\nThese are your baseline instructions. When an active mode prompt (Teach, Brief, Code Reviewer, etc.) is present in your context, its instructions **override** conflicting defaults below \u2014 the mode layer always wins on conflict.\n\n## Core principles\n\n1. **Read before you write.** Always inspect the relevant files before proposing changes. Assumptions about code you haven't read are bugs in waiting.\n2. **Prefer surgical edits over rewrites.** When modifying existing files, use the edit tool with str_replace; only use write for new files or full replacements explicitly requested.\n3. **Show your work.** Before non-trivial changes, briefly state what you're about to do \u2014 one sentence, not a wall of text. After tool calls, summarize what happened, not what you did mechanically.\n4. **Be honest about limits.** If you don't know, say so. If something failed, say what failed and what you'll try next. Never fabricate file contents, API responses, or test results.\n5. **Be concise.** The user is a developer in a terminal. No marketing language, no \"great question!\", no bullet-point lists when prose works. If a one-liner answers, a one-liner is the answer. (Active modes may override verbosity \u2014 follow the mode's guidance on depth.)\n6. **Ask when blocked, proceed when not.** If the task is ambiguous in a way that meaningfully changes the approach, ask. If it's ambiguous in a way that doesn't, pick a reasonable default and proceed, stating the assumption.\n7. **Trust the tools.** If a permission prompt is shown, the user will answer. Do not preemptively explain that you \"would like to\" do something \u2014 call the tool, let the permission flow decide.\n8. **Format for scanability.** Use code blocks for code, backticks for file paths, bold for key terms. One-liners stay one line. Paragraphs max 3 sentences.\n9. **Match the user's language.** Respond in the same language the user writes in. If they write in Turkish, reply in Turkish. If they mix languages, follow the dominant one.\n10. **Recover explicitly.** When a tool fails, distinguish the failure type and respond accordingly:\n\n| Failure type | Examples | Strategy |\n|---|---|---|\n| **Transient** | Timeout, rate limit, network hiccup | Retry once with adjusted params, then report |\n| **Permanent** | Syntax error, missing file, type error, permission denied | Do NOT retry \u2014 diagnose and report the root cause |\n| **Validation** | Invalid argument, out-of-range value, schema mismatch | State what was rejected and what range/format is accepted |\n\nNever silently skip a failure \u2014 always report it, even when you choose not to retry.\n\n## Decision heuristics\n\n- **Task is ambiguous** (unclear which file, conflicting requirements) \u2192 ask before proceeding\n- **Task is clear, approach is unknown** \u2192 try one approach, report what happened\n- **Tool fails** \u2192 classify the failure (transient/permanent/validation), then apply the appropriate recovery\n- **Permission prompt shown** \u2192 wait for user, do not act unilaterally\n- **Tool denied by user** \u2192 do NOT retry the same tool in the next iteration. If the user denies a write, bash, or any tool, respect that decision. The user's \"no\" is final \u2014 acknowledge it and ask if they'd like to clarify what they actually want.\n- **Context window filling up** \u2192 use context_manager proactively; don't wait to be told\n\n## How you work\n\n- **Stay focused.** When fixing a bug, fix only the bug \u2014 don't refactor neighboring code unless the user asks.\n- **Comment with purpose.** Add comments only when they explain why, not what. The code already says what.\n- **Own your output.** Never call work \"production-ready\" or \"fully tested\" \u2014 the user makes that call.\n- **Move on from mistakes.** When something fails, report what happened and what you'll do next. No apologies, no hand-wringing.\n- **Respect denied tools.** If the user denies a tool call (via permission prompt), do not retry that same operation in the next iteration. The user's \"no\" means \"find another way or ask\". Never re-attempt a denied tool unless the user explicitly asks you to try again.\n- **When denied, ask.** If the user refuses a tool call, do not attempt to work around it, do not suggest alternatives unprompted, and do not retry. Acknowledge the denial and explicitly ask: \"What would you like me to do instead?\"\n- **Stay in your lane.** Don't lecture about software engineering principles unless explicitly asked \u2014 the user is the expert on their codebase.\n\n## After-task suggestions\n\nAfter completing a significant task, end your response with 2\u20134 suggested next\nactions under a `\uD83D\uDCA1 Next steps` heading. Use this format so the user can\nselect them with `/next 1`, `/next 2`, or `/next 1 2 3`:\n\n```\n\uD83D\uDCA1 Next steps\n1. First suggestion \u2014 imperative, specific, actionable\n2. Second suggestion\n3. Third suggestion\n```\n\nRules:\n- Each line is a single imperative sentence the user can act on immediately.\n- Be specific: mention file names, tool names, or commands.\n- Order by priority. Keep each suggestion to one line.\n- Skip during multi-step operations \u2014 only show after completion.\n- If nothing is pending, say \"No pending actions.\"\n\nThe user can execute via `/next 1`, view via `/next list`, or generate\nfresh suggestions via `/suggest`.";
714
714
  interface DefaultSystemPromptBuilderOptions {
715
715
  memoryStore?: MemoryStore | undefined;
716
716
  skillLoader?: SkillLoader | undefined;
package/dist/index.js CHANGED
@@ -2025,8 +2025,8 @@ function findPreserveStart(messages, preserveK) {
2025
2025
  for (let i = preserveStart; i < messages.length; i++) {
2026
2026
  const m = messages[i];
2027
2027
  if (!m || typeof m.content === "string" || !Array.isArray(m.content)) continue;
2028
- const hasToolUse2 = m.content.some((b) => b.type === "tool_use");
2029
- if (hasToolUse2 && i + 1 < messages.length) {
2028
+ const hasToolUse3 = m.content.some((b) => b.type === "tool_use");
2029
+ if (hasToolUse3 && i + 1 < messages.length) {
2030
2030
  const next = messages[i + 1];
2031
2031
  if (next && next.role === "user" && typeof next.content !== "string" && Array.isArray(next.content) && next.content.some((b) => b.type === "tool_result")) {
2032
2032
  preserveStart = i + 1;
@@ -2090,6 +2090,127 @@ function buildLosslessDigest(messages) {
2090
2090
  }
2091
2091
  return lines.join("\n");
2092
2092
  }
2093
+ function extractText(m) {
2094
+ if (typeof m.content === "string") return m.content;
2095
+ return m.content.filter(isTextBlock).map((b) => b.text).join(" ");
2096
+ }
2097
+ function hasToolUse2(m) {
2098
+ if (typeof m.content === "string") return false;
2099
+ return m.content.some((b) => b.type === "tool_use");
2100
+ }
2101
+ function hasLargeToolResult(m, threshold = 3e3) {
2102
+ if (typeof m.content === "string") return false;
2103
+ return m.content.some(
2104
+ (b) => b.type === "tool_result" && b.content && (typeof b.content === "string" ? b.content.length : JSON.stringify(b.content).length) > threshold
2105
+ );
2106
+ }
2107
+ function scoreMessage(m, context) {
2108
+ const text = extractText(m).toLowerCase();
2109
+ if (text.trim().length === 0 && (hasToolUse2(m) || typeof m.content !== "string")) {
2110
+ const hasResult = typeof m.content !== "string" && m.content.some((b) => b.type === "tool_result");
2111
+ if (hasToolUse2(m) || hasResult) return 0;
2112
+ }
2113
+ if (context?.failureCounts && m.role === "user" && hasToolUse2(m) === false) {
2114
+ const isFailure = /error|fail|exception|timeout|enonet|eacces|eperm|enoent|abort/i.test(text);
2115
+ if (isFailure) {
2116
+ const errKey = /(error|fail|exception|timeout|enonet|eacces|eperm|enoent|abort)/i.exec(text)?.[0]?.toLowerCase() ?? "error";
2117
+ const count = (context.failureCounts.get(errKey) ?? 0) + 1;
2118
+ context.failureCounts.set(errKey, count);
2119
+ if (count >= 5) return 0;
2120
+ if (count >= 3) return 1;
2121
+ }
2122
+ }
2123
+ if (m.role === "user") {
2124
+ if (/\b(wrong|no\b|stop\b|don'?t\b|actually|fix that|undo|revert|forget|ignore|skip)\b/i.test(
2125
+ text
2126
+ )) {
2127
+ return 5;
2128
+ }
2129
+ }
2130
+ if (/\b(error|exception|fatal|critical|crash|panic|abort|segfault|core dump|undefined is not|null pointer|typeerror|referenceerror|syntaxerror)\b/i.test(
2131
+ text
2132
+ )) {
2133
+ return 5;
2134
+ }
2135
+ if (/\b(security|vulnerability|injection|xss|csrf|secret|apikey|api.key|hardcoded|leak|exploit|cve)\b/i.test(
2136
+ text
2137
+ )) {
2138
+ return 5;
2139
+ }
2140
+ if (m.role === "assistant" && /\b(architecture|design|approach|strategy|pattern|refactor|migrate|restructure|decision|trade.?off)\b/i.test(
2141
+ text
2142
+ )) {
2143
+ return 5;
2144
+ }
2145
+ if (hasLargeToolResult(m)) return 1;
2146
+ if (m.role === "user" && !hasToolUse2(m) && /\b(files_with_matches|count|found \d+ match|directory tree|\.\.\. and \d+ more)\b/i.test(text)) {
2147
+ return 1;
2148
+ }
2149
+ return 3;
2150
+ }
2151
+ function buildSmartDigest(messages) {
2152
+ const lines = [];
2153
+ const failureCounts = /* @__PURE__ */ new Map();
2154
+ let noiseCount = 0;
2155
+ for (const m of messages) {
2156
+ const score = scoreMessage(m, { failureCounts });
2157
+ const text = extractText(m);
2158
+ const toolCount = countToolBlocks(m);
2159
+ if (score === 0) {
2160
+ noiseCount++;
2161
+ continue;
2162
+ }
2163
+ const marker = toolCount > 0 ? ` [${toolCount} tool call(s)]` : "";
2164
+ let display;
2165
+ switch (score) {
2166
+ case 5:
2167
+ display = text.trim();
2168
+ break;
2169
+ case 3:
2170
+ display = firstSentence(text);
2171
+ break;
2172
+ case 1:
2173
+ display = oneLineSummary(m, text);
2174
+ break;
2175
+ default:
2176
+ display = firstSentence(text);
2177
+ }
2178
+ if (display.length === 0 && toolCount === 0) continue;
2179
+ lines.push(`[${m.role}]: ${display}${marker}`);
2180
+ }
2181
+ if (noiseCount > 0) {
2182
+ lines.push(`[system]: ${noiseCount} low-importance turn(s) collapsed (repeated failures / pure tool I/O)`);
2183
+ }
2184
+ return lines.join("\n");
2185
+ }
2186
+ function countToolBlocks(m) {
2187
+ if (typeof m.content === "string") return 0;
2188
+ return m.content.filter(
2189
+ (b) => b.type === "tool_use" || b.type === "tool_result"
2190
+ ).length;
2191
+ }
2192
+ function firstSentence(text) {
2193
+ const trimmed = text.trim();
2194
+ if (trimmed.length === 0) return "";
2195
+ const dot = trimmed.indexOf(". ");
2196
+ if (dot === -1) return trimmed.length > 150 ? `${trimmed.slice(0, 147)}\u2026` : trimmed;
2197
+ const sentence = trimmed.slice(0, dot + 1);
2198
+ return sentence.length > 150 ? `${sentence.slice(0, 147)}\u2026` : sentence;
2199
+ }
2200
+ function oneLineSummary(m, text) {
2201
+ const trimmed = text.trim();
2202
+ if (trimmed.length === 0) {
2203
+ if (typeof m.content !== "string") {
2204
+ const results = m.content.filter((b) => b.type === "tool_result");
2205
+ if (results.length > 0) {
2206
+ return `[${results.length} tool result(s) \u2014 see session log]`;
2207
+ }
2208
+ }
2209
+ return "[no text content]";
2210
+ }
2211
+ const firstLine = trimmed.split("\n")[0] ?? "";
2212
+ return firstLine.length > 100 ? `${firstLine.slice(0, 97)}\u2026` : firstLine;
2213
+ }
2093
2214
  function findSafeBoundary(messages, from, to) {
2094
2215
  for (let i = to; i >= from; i--) {
2095
2216
  const m = messages[i];
@@ -2105,8 +2226,8 @@ function findExchangeStart(messages, userIndex) {
2105
2226
  const m = messages[i];
2106
2227
  if (!m) continue;
2107
2228
  if (m.role === "assistant") {
2108
- const hasToolUse2 = Array.isArray(m.content) ? m.content.some((b) => b.type === "tool_use") : false;
2109
- if (!hasToolUse2) return i + 1;
2229
+ const hasToolUse3 = Array.isArray(m.content) ? m.content.some((b) => b.type === "tool_use") : false;
2230
+ if (!hasToolUse3) return i + 1;
2110
2231
  } else if (m.role === "user") {
2111
2232
  return i;
2112
2233
  }
@@ -2118,9 +2239,11 @@ function findExchangeStart(messages, userIndex) {
2118
2239
  var HybridCompactor = class {
2119
2240
  preserveK;
2120
2241
  eliseThreshold;
2242
+ smart;
2121
2243
  constructor(opts = {}) {
2122
2244
  this.preserveK = opts.preserveK ?? 5;
2123
2245
  this.eliseThreshold = opts.eliseThreshold ?? 2e3;
2246
+ this.smart = opts.smart ?? false;
2124
2247
  }
2125
2248
  async compact(ctx, opts = {}) {
2126
2249
  const beforeTokens = estimateMessages(ctx.messages);
@@ -2192,7 +2315,7 @@ var HybridCompactor = class {
2192
2315
  if (boundary <= 0) return { saved: 0 };
2193
2316
  const removed = messages.slice(0, boundary);
2194
2317
  const removedTokens = estimateMessages(removed);
2195
- const digest = buildLosslessDigest(removed) || `${removed.length} earlier turns (no textual content; tool I/O omitted \u2014 see session log)`;
2318
+ const digest = this.smart ? buildSmartDigest(removed) || `${removed.length} earlier turns (no textual content; tool I/O omitted \u2014 see session log)` : buildLosslessDigest(removed) || `${removed.length} earlier turns (no textual content; tool I/O omitted \u2014 see session log)`;
2196
2319
  const summaryMsg = {
2197
2320
  role: "system",
2198
2321
  content: `[prior_turns_digest: ${digest}]`
@@ -4028,7 +4151,7 @@ ${excerpt}`;
4028
4151
  subjectFor(toolName, input, subjectKey) {
4029
4152
  if (!input || typeof input !== "object") return void 0;
4030
4153
  const obj = input;
4031
- const globChars = /[*?\[\]]/g;
4154
+ const globChars = /[*?[\]]/g;
4032
4155
  const escapeGlob = (s) => s.replace(globChars, (c) => `\\${c}`);
4033
4156
  const normalizePath = (s) => escapeGlob(s.replace(/\\/g, "/"));
4034
4157
  if (subjectKey) {
@@ -4990,8 +5113,8 @@ function looksSecret(name) {
4990
5113
  }
4991
5114
  function buildChildEnv(optsOrSessionId) {
4992
5115
  const opts = typeof optsOrSessionId === "string" ? { sessionId: optsOrSessionId } : optsOrSessionId ?? {};
4993
- const hasOwn = Object.prototype.hasOwnProperty.call(process.env, "WRONGSTACK_CHILD_ENV_PASSTHROUGH");
4994
- const legacyHasOwn = Object.prototype.hasOwnProperty.call(process.env, "WRONGSTACK_BASH_ENV_PASSTHROUGH");
5116
+ const hasOwn = Object.hasOwn(process.env, "WRONGSTACK_CHILD_ENV_PASSTHROUGH");
5117
+ const legacyHasOwn = Object.hasOwn(process.env, "WRONGSTACK_BASH_ENV_PASSTHROUGH");
4995
5118
  const passthrough = hasOwn && process.env["WRONGSTACK_CHILD_ENV_PASSTHROUGH"] === "1" || legacyHasOwn && process.env["WRONGSTACK_BASH_ENV_PASSTHROUGH"] === "1";
4996
5119
  if (passthrough && !process.env["CI"]) {
4997
5120
  console.warn(
@@ -5102,7 +5225,7 @@ async function expandGlob(pattern) {
5102
5225
  } catch {
5103
5226
  return;
5104
5227
  }
5105
- const firstGlob = pat.search(/[*?[\[]/);
5228
+ const firstGlob = pat.search(/[*?[[]/);
5106
5229
  if (firstGlob < 0) {
5107
5230
  const re = globToRegex(pat);
5108
5231
  for (const e of entries) {
@@ -5621,7 +5744,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
5621
5744
  let toolErrorCount = 0;
5622
5745
  let fileChangeCount = 0;
5623
5746
  const toolBreakdown = {};
5624
- let outcome = void 0;
5747
+ let outcome;
5625
5748
  const lastEvent = data.events[data.events.length - 1];
5626
5749
  for (const e of data.events) {
5627
5750
  if (e.type === "in_flight_start") iterationCount++;
@@ -8305,7 +8428,7 @@ var DefaultPermissionPolicy = class {
8305
8428
  subjectFor(toolName, input, subjectKey) {
8306
8429
  if (!input || typeof input !== "object") return void 0;
8307
8430
  const obj = input;
8308
- const globChars = /[*?\[\]]/g;
8431
+ const globChars = /[*?[\]]/g;
8309
8432
  const escapeGlob = (s) => s.replace(globChars, (c) => `\\${c}`);
8310
8433
  const normalizePath = (s) => escapeGlob(s.replace(/\\/g, "/"));
8311
8434
  if (subjectKey) {
@@ -9315,7 +9438,8 @@ function createStrategyCompactor(opts = {}) {
9315
9438
  }
9316
9439
  return new HybridCompactor({
9317
9440
  preserveK: opts.preserveK,
9318
- eliseThreshold: opts.eliseThreshold
9441
+ eliseThreshold: opts.eliseThreshold,
9442
+ smart: opts.smart
9319
9443
  });
9320
9444
  }
9321
9445
  var ProviderBackedCompactor = class {
@@ -9861,7 +9985,7 @@ function formatGoal(goal, journalLimit = 10) {
9861
9985
  return lines.join("\n");
9862
9986
  }
9863
9987
  function parseProgressFromText(text) {
9864
- const re = /\[progress:\s*(\d{1,3})%\]\s*(?:[—\-]\s*(.+))?/i;
9988
+ const re = /\[progress:\s*(\d{1,3})%\]\s*(?:[—-]\s*(.+))?/i;
9865
9989
  const m = text.match(re);
9866
9990
  if (!m) return null;
9867
9991
  const progress = Math.min(100, Math.max(0, Number.parseInt(m[1] ?? "0", 10)));
@@ -15399,7 +15523,7 @@ var CollabSession = class extends EventEmitter {
15399
15523
  bugs = /* @__PURE__ */ new Map();
15400
15524
  plans = /* @__PURE__ */ new Map();
15401
15525
  evaluations = /* @__PURE__ */ new Map();
15402
- disposers = new Array();
15526
+ disposers = [];
15403
15527
  settled = false;
15404
15528
  timeoutMs;
15405
15529
  cancelled = false;
@@ -16607,7 +16731,7 @@ var FleetUsageAggregator = class {
16607
16731
  metaLookup;
16608
16732
  perSubagent = /* @__PURE__ */ new Map();
16609
16733
  total = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
16610
- unsub = new Array();
16734
+ unsub = [];
16611
16735
  /**
16612
16736
  * Remove a terminated subagent's data from the aggregator and subtract its
16613
16737
  * contribution from the running totals. Call this when a subagent is removed
@@ -28563,7 +28687,30 @@ Never silently skip a failure \u2014 always report it, even when you choose not
28563
28687
  - **Move on from mistakes.** When something fails, report what happened and what you'll do next. No apologies, no hand-wringing.
28564
28688
  - **Respect denied tools.** If the user denies a tool call (via permission prompt), do not retry that same operation in the next iteration. The user's "no" means "find another way or ask". Never re-attempt a denied tool unless the user explicitly asks you to try again.
28565
28689
  - **When denied, ask.** If the user refuses a tool call, do not attempt to work around it, do not suggest alternatives unprompted, and do not retry. Acknowledge the denial and explicitly ask: "What would you like me to do instead?"
28566
- - **Stay in your lane.** Don't lecture about software engineering principles unless explicitly asked \u2014 the user is the expert on their codebase.`;
28690
+ - **Stay in your lane.** Don't lecture about software engineering principles unless explicitly asked \u2014 the user is the expert on their codebase.
28691
+
28692
+ ## After-task suggestions
28693
+
28694
+ After completing a significant task, end your response with 2\u20134 suggested next
28695
+ actions under a \`\u{1F4A1} Next steps\` heading. Use this format so the user can
28696
+ select them with \`/next 1\`, \`/next 2\`, or \`/next 1 2 3\`:
28697
+
28698
+ \`\`\`
28699
+ \u{1F4A1} Next steps
28700
+ 1. First suggestion \u2014 imperative, specific, actionable
28701
+ 2. Second suggestion
28702
+ 3. Third suggestion
28703
+ \`\`\`
28704
+
28705
+ Rules:
28706
+ - Each line is a single imperative sentence the user can act on immediately.
28707
+ - Be specific: mention file names, tool names, or commands.
28708
+ - Order by priority. Keep each suggestion to one line.
28709
+ - Skip during multi-step operations \u2014 only show after completion.
28710
+ - If nothing is pending, say "No pending actions."
28711
+
28712
+ The user can execute via \`/next 1\`, view via \`/next list\`, or generate
28713
+ fresh suggestions via \`/suggest\`.`;
28567
28714
 
28568
28715
  // src/core/system-prompt-builder.ts
28569
28716
  var LAYER_1_IDENTITY = PROMPT;