agent-afk 5.166.0 → 5.167.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.
@@ -2,6 +2,7 @@ export interface PluginSkillMetadata {
2
2
  name?: string;
3
3
  description?: string;
4
4
  argumentHint?: string;
5
+ whenToUse?: string;
5
6
  origin?: 'command';
6
7
  allowedTools?: string[];
7
8
  context?: string;
@@ -1,4 +1,4 @@
1
- export declare const ROUTING_DIRECTIVE = "[skill-routing: active]\n\nRoute recurring work through registered skills instead of rolling ad-hoc solutions:\n\n- Before non-trivial implementation (multi-file edits, new features, config/build changes \u2014 anything that writes) \u2192 `/ground-state` first. Do NOT substitute inline `git status`/`get_runtime_state` \u2014 the skill triangulates git + infra + prior-session memory in parallel, which the inline checks miss. If `/ground-state` dispatch fails (depth limit, unavailable), fall back to inline checks AND note the coverage gap.\n- Bugs, failing tests, or regressions \u2192 `/diagnose`\n- High-stakes sub-agent output that will drive edits or commits \u2192 `/shadow-verify` before acting\n- Refactor needing parallel waves \u2192 `/parallelize`\n- Parallel or dependent multi-task work \u2192 `compose` tool (DAG of subagent nodes)\n- Greenfield feature where a written spec would genuinely help (novel scope, multi-day work, or external stakeholders involved) \u2192 `/mint`\n\nDo NOT reach for `/mint` for: bug fixes (use `/diagnose`), refactors with known shape, single-feature edits, work already spec'd in chat, or anything where the spec/approve pause would feel like ceremony. Implement directly in those cases.\n\nCommon composed sequences \u2014 reach for these when the task shape matches:\n\n- Bug with failing test and non-trivial fix \u2192 `/diagnose` \u2192 `/shadow-verify` on the proposed fix\n- Refactor needing parallel waves \u2192 plan \u2192 `/parallelize` \u2192 build waves\n- Diagnose + fix in parallel \u2192 `compose` with two independent nodes\n- Research \u2192 implement \u2192 verify pipeline \u2192 `compose` with edges: research\u2192implement\u2192verify\n- Multiple independent investigations \u2192 `compose` with N nodes, no edges\n\nReach for context-isolated investigators when the task is exploratory:\n\n- Map an unfamiliar module before editing \u2192 `/gather` or `/research`\n- Re-derive a load-bearing claim independently \u2192 `/shadow-verify`\n- Audit a diff before merge \u2192 `/review`\n- Generate alternatives before committing to a plan \u2192 `/devils-advocate`\n\nOr dispatch a raw `agent` call when no skill matches but the work is parallelizable, verification-heavy, or would otherwise consume substantial inline context.\n\nSkip orchestration for: single-line edits, trivial Q&A, and direct tool calls the user explicitly requested. The goal is leverage, not ceremony. If a skill would add overhead without adding value, don't invoke it.\n\nDefault to acting autonomously. `ask_question` is a last resort, not a first move \u2014 every question blocks on the operator, who is often away from keyboard.\n\nBefore you ask, you MUST exhaust the tools you have: read the files, check git, search the codebase and docs, inspect runtime state. If any tool can get you the answer, use the tool \u2014 never ask the operator for something you can discover yourself. When a wrong guess would be cheap or reversible, make a reasonable assumption, proceed, and state the assumption instead of asking.\n\n**Answerability \u2014 a question only helps if a human will actually answer it:**\n\n`surface` (from `get_runtime_state`, view `\"self\"`) is a partial signal, not a guarantee:\n- `daemon`, or any session started by a scheduler, cron job, or another agent, has no human watching \u2014 never block on `ask_question` here.\n- `cli` is ambiguous: the interactive REPL and the Telegram bot can reach a human, but one-shot `chat` runs and sub-agent forks report the same `cli` and have no elicitation handler \u2014 there `ask_question` returns `{ action: 'decline' }` instantly.\n- Even when a handler exists, the operator is usually away, so a blocking question can stall until the turn aborts.\n\nSo treat `ask_question` as best-effort: a `decline` or `cancel` result means \"no answer is coming,\" not a failure to abort the task on. When you cannot be sure a human will answer, instead of asking:\n1. **Proceed on a stated assumption** \u2014 pick the most reasonable interpretation, act on it, and record the assumption in your Done/Blocked terminal state for async review.\n2. **Emit a Blocked artifact** \u2014 if no safe assumption exists and proceeding would be irreversible, end the turn with a **Blocked** terminal state naming exactly what the operator must supply before the next run.\n\nReserve `ask_question` for the narrow set of things no tool can resolve: a genuinely ambiguous requirement whose readings lead to materially different work, a decision with significant or irreversible consequences, or context that lives only in the operator's head (a preference, a secret, an external constraint):\n\n- Question types: `text` (open-ended), `confirm` (yes/no), `choice` (single pick from list), `multi_choice` (multi-pick), `number` (numeric with optional bounds). When `allow_custom: true`, the result may include `custom_value` instead of `value` \u2014 check `content.custom_value !== undefined` to detect a free-form answer.\n- Ask one focused question at a time. Do NOT ask multiple questions in a single call, and do NOT stack several ask_question calls across a turn \u2014 fold the genuine unknowns into the single most decision-relevant question.\n- Do NOT use when the user has already provided sufficient context \u2014 infer and proceed instead.\n- The result `action` will be `accept` (answered), `cancel` (user interrupted), `decline` (no handler), or `skip` (optional question skipped).\n- `allow_custom` (choice/multi_choice only): opt-in to a free-form entry affordance. On accept, `content` has `{ value: null, custom_value: \"<text>\" }` rather than `{ value: \"<listed-string>\" }`.\n- After a `cancel` or `decline`, stop and tell the user what information you need \u2014 do not loop and re-ask.";
1
+ export declare const ROUTING_DIRECTIVE = "[skill-routing: active]\n\nRoute recurring work through registered skills instead of rolling ad-hoc solutions:\n\n- Before non-trivial implementation (multi-file edits, new features, config/build changes \u2014 anything that writes) \u2192 `/ground-state` first. Do NOT substitute inline `git status`/`get_runtime_state` \u2014 the skill triangulates git + infra + prior-session memory in parallel, which the inline checks miss. If `/ground-state` dispatch fails (depth limit, unavailable), fall back to inline checks AND note the coverage gap.\n- Bugs, failing tests, or regressions \u2192 `/diagnose`\n- High-stakes sub-agent output that will drive edits or commits \u2192 `/shadow-verify` before acting\n- Refactor needing parallel waves \u2192 `/parallelize`\n- Parallel or dependent multi-task work \u2192 `compose` tool (DAG of subagent nodes)\n- Greenfield feature where a written spec would genuinely help (novel scope, multi-day work, or external stakeholders involved) \u2192 `/mint`\n\nDo NOT reach for `/mint` for: bug fixes (use `/diagnose`), refactors with known shape, single-feature edits, work already spec'd in chat, or anything where the spec/approve pause would feel like ceremony. Implement directly in those cases.\n\nCommon composed sequences \u2014 reach for these when the task shape matches:\n\n- Bug with failing test and non-trivial fix \u2192 `/diagnose` \u2192 `/shadow-verify` on the proposed fix\n- Refactor needing parallel waves \u2192 plan \u2192 `/parallelize` \u2192 build waves\n- Diagnose + fix in parallel \u2192 `compose` with two independent nodes\n- Research \u2192 implement \u2192 verify pipeline \u2192 `compose` with edges: research\u2192implement\u2192verify\n- Multiple independent investigations \u2192 `compose` with N nodes, no edges\n\nReach for context-isolated investigators when the task is exploratory:\n\n- Map an unfamiliar module before editing \u2192 `/gather` or `/research`\n- Re-derive a load-bearing claim independently \u2192 `/shadow-verify`\n- Audit a diff before merge \u2192 `/review`\n- Generate alternatives before committing to a plan \u2192 `/devils-advocate`\n\nOr dispatch a raw `agent` call when no skill matches but the work is parallelizable, verification-heavy, or would otherwise consume substantial inline context.\n\nAfter local work is ready to push and PR \u2192 `/ship`; to fix PR review feedback or red CI \u2192 `/fix-pr`; to clean up complexity or dead code \u2192 `/simplify`; large-scope structural refactors \u2192 `/refactor`.\n\nSkip orchestration for: single-line edits, trivial Q&A, and direct tool calls the user explicitly requested. The goal is leverage, not ceremony. If a skill would add overhead without adding value, don't invoke it.\n\nDefault to acting autonomously. `ask_question` is a last resort, not a first move \u2014 every question blocks on the operator, who is often away from keyboard.\n\nBefore you ask, you MUST exhaust the tools you have: read the files, check git, search the codebase and docs, inspect runtime state. If any tool can get you the answer, use the tool \u2014 never ask the operator for something you can discover yourself. When a wrong guess would be cheap or reversible, make a reasonable assumption, proceed, and state the assumption instead of asking.\n\n**Answerability \u2014 a question only helps if a human will actually answer it:**\n\n`surface` (from `get_runtime_state`, view `\"self\"`) is a partial signal, not a guarantee:\n- `daemon`, or any session started by a scheduler, cron job, or another agent, has no human watching \u2014 never block on `ask_question` here.\n- `cli` is ambiguous: the interactive REPL and the Telegram bot can reach a human, but one-shot `chat` runs and sub-agent forks report the same `cli` and have no elicitation handler \u2014 there `ask_question` returns `{ action: 'decline' }` instantly.\n- Even when a handler exists, the operator is usually away, so a blocking question can stall until the turn aborts.\n\nSo treat `ask_question` as best-effort: a `decline` or `cancel` result means \"no answer is coming,\" not a failure to abort the task on. When you cannot be sure a human will answer, instead of asking:\n1. **Proceed on a stated assumption** \u2014 pick the most reasonable interpretation, act on it, and record the assumption in your Done/Blocked terminal state for async review.\n2. **Emit a Blocked artifact** \u2014 if no safe assumption exists and proceeding would be irreversible, end the turn with a **Blocked** terminal state naming exactly what the operator must supply before the next run.\n\nReserve `ask_question` for the narrow set of things no tool can resolve: a genuinely ambiguous requirement whose readings lead to materially different work, a decision with significant or irreversible consequences, or context that lives only in the operator's head (a preference, a secret, an external constraint):\n\n- Question types: `text` (open-ended), `confirm` (yes/no), `choice` (single pick from list), `multi_choice` (multi-pick), `number` (numeric with optional bounds). When `allow_custom: true`, the result may include `custom_value` instead of `value` \u2014 check `content.custom_value !== undefined` to detect a free-form answer.\n- Ask one focused question at a time. Do NOT ask multiple questions in a single call, and do NOT stack several ask_question calls across a turn \u2014 fold the genuine unknowns into the single most decision-relevant question.\n- Do NOT use when the user has already provided sufficient context \u2014 infer and proceed instead.\n- The result `action` will be `accept` (answered), `cancel` (user interrupted), `decline` (no handler), or `skip` (optional question skipped).\n- `allow_custom` (choice/multi_choice only): opt-in to a free-form entry affordance. On accept, `content` has `{ value: null, custom_value: \"<text>\" }` rather than `{ value: \"<listed-string>\" }`.\n- After a `cancel` or `decline`, stop and tell the user what information you need \u2014 do not loop and re-ask.";
2
2
  export declare const END_OF_TURN_DIRECTIVE = "[end-of-turn protocol]\n\nEvery turn must end in one externally identifiable terminal state. AFK users need inspectable artifacts, not ceremony. Write each bullet as a single sentence.\n\n**Done**\n- What was done: <one-sentence summary>\n- Evidence: <durable location \u2014 file path, commit SHA, trace path, test output, or memory key; never transcript-only>\n- What changed: <world-state delta>\n- Deferred: <anything still pending, with why; or \"none\">\n- If files were written or edited but no `git commit` ran, say so explicitly \u2014 name the uncommitted paths and why (e.g. awaiting review); do not imply clean completion while the work sits uncommitted in the worktree.\n\n**Blocked**\n- What blocks: <the blocker>\n- What must change to unblock: <the unblock condition>\n- What has already been done: <progress so far>\n\n**Asking**\n- Question: <one precise question>\n- Assumption it resolves: <what answering clarifies>\n- Once answered: <what you will do>\n\n**Interrupted**\n- What you were doing: <the in-progress task>\n- Where state was saved: <location>\n- What resumption requires: <prerequisites>\n\nNever end a turn mid-loop without one of these. The terminal-state heading must be the last block of the response, with no trailing prose after it.";
3
3
  export type PromptSurface = 'repl' | 'telegram' | 'one-shot' | 'subagent';
4
4
  export declare function assembleSystemPrompt(base: string | undefined, autoRouting: boolean, surface?: PromptSurface): string | undefined;
@@ -59,6 +59,7 @@ export declare class AgentSession implements IAgentSession {
59
59
  setModel(model?: AgentModelInput): Promise<void>;
60
60
  setPermissionMode(mode: PermissionMode): Promise<void>;
61
61
  getPrePlanMode(): PermissionMode | undefined;
62
+ setPlanExitQueueCheck(fn: () => boolean): void;
62
63
  takePendingPlanExitSeed(): Promise<{
63
64
  message: string;
64
65
  mode: PermissionMode;
@@ -465,6 +465,11 @@ export declare const BrowserEventPayloadSchema: z.ZodObject<{
465
465
  wait_for: "wait_for";
466
466
  }>>;
467
467
  toolUseId: z.ZodString;
468
+ backend: z.ZodOptional<z.ZodEnum<{
469
+ "agent-browser": "agent-browser";
470
+ playwright: "playwright";
471
+ }>>;
472
+ backendReason: z.ZodOptional<z.ZodString>;
468
473
  target: z.ZodOptional<z.ZodObject<{
469
474
  kind: z.ZodEnum<{
470
475
  semantic: "semantic";
@@ -835,6 +840,11 @@ export declare const TraceEventInputSchema: z.ZodDiscriminatedUnion<[z.ZodObject
835
840
  wait_for: "wait_for";
836
841
  }>>;
837
842
  toolUseId: z.ZodString;
843
+ backend: z.ZodOptional<z.ZodEnum<{
844
+ "agent-browser": "agent-browser";
845
+ playwright: "playwright";
846
+ }>>;
847
+ backendReason: z.ZodOptional<z.ZodString>;
838
848
  target: z.ZodOptional<z.ZodObject<{
839
849
  kind: z.ZodEnum<{
840
850
  semantic: "semantic";
@@ -1195,6 +1205,11 @@ export declare const TraceEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
1195
1205
  wait_for: "wait_for";
1196
1206
  }>>;
1197
1207
  toolUseId: z.ZodString;
1208
+ backend: z.ZodOptional<z.ZodEnum<{
1209
+ "agent-browser": "agent-browser";
1210
+ playwright: "playwright";
1211
+ }>>;
1212
+ backendReason: z.ZodOptional<z.ZodString>;
1198
1213
  target: z.ZodOptional<z.ZodObject<{
1199
1214
  kind: z.ZodEnum<{
1200
1215
  semantic: "semantic";
@@ -161,6 +161,8 @@ export interface BrowserEventPayload {
161
161
  tool: BrowserEventTool;
162
162
  action?: BrowserActAction;
163
163
  toolUseId: string;
164
+ backend?: 'playwright' | 'agent-browser';
165
+ backendReason?: string;
164
166
  target?: BrowserEventTarget;
165
167
  urlBefore: string | null;
166
168
  urlAfter: string | null;
@@ -19,6 +19,7 @@ export interface PlanExitControls {
19
19
  setPermissionMode(mode: PermissionMode): Promise<void>;
20
20
  requestImplementSeed(message: string, mode: PermissionMode): void;
21
21
  getPrePlanMode(): PermissionMode | undefined;
22
+ hasPendingUserMessage?: () => boolean;
22
23
  }
23
24
  export interface AgentConfig {
24
25
  model: AgentModelInput;
@@ -35,3 +35,4 @@ export declare class WorkspaceStore {
35
35
  close(): void;
36
36
  private nextSeq;
37
37
  }
38
+ export declare function buildFtsQuery(prompt: string): string;
@@ -0,0 +1,15 @@
1
+ import type { ActOutcome } from '../provider.js';
2
+ import type { ActInput, InteractiveElement, Target } from '../types.js';
3
+ import type { BrowserConfig } from '../types.js';
4
+ import type { AgentBrowserClient, InspectElement } from './client.js';
5
+ export declare function mapElement(el: InspectElement): InteractiveElement;
6
+ export declare function resolveElementId(knownElements: Map<string, InteractiveElement>, target: Target): string | null;
7
+ export declare function executeAction(client: AgentBrowserClient, tabId: string, action: string, elementId: string, value?: string, timeoutMs?: number): Promise<void>;
8
+ export interface SemanticResolveContext {
9
+ client: AgentBrowserClient;
10
+ config: BrowserConfig;
11
+ tabId: string;
12
+ }
13
+ export declare function resolveSemanticAndAct(ctx: SemanticResolveContext, input: ActInput): Promise<{
14
+ elementId: string;
15
+ } | ActOutcome>;
@@ -0,0 +1,68 @@
1
+ import type { AgentBrowserConnection } from './connection.js';
2
+ export interface AgentBrowserTab {
3
+ id: string;
4
+ title: string;
5
+ url: string;
6
+ loading: boolean;
7
+ }
8
+ export interface InspectElement {
9
+ id: string;
10
+ tag: string;
11
+ role: string;
12
+ label: string;
13
+ kind: string | null;
14
+ value: string | null;
15
+ placeholder: string | null;
16
+ disabled: boolean;
17
+ checked?: boolean;
18
+ selected?: boolean;
19
+ expanded?: boolean;
20
+ bbox: {
21
+ x: number;
22
+ y: number;
23
+ w: number;
24
+ h: number;
25
+ };
26
+ selector?: string;
27
+ }
28
+ export interface ReadResult {
29
+ content: string;
30
+ url: string;
31
+ title: string;
32
+ wordCount: number;
33
+ }
34
+ export declare class AgentBrowserClient {
35
+ private readonly baseUrl;
36
+ private readonly token;
37
+ constructor(connection: AgentBrowserConnection);
38
+ private call;
39
+ listTabs(): Promise<AgentBrowserTab[]>;
40
+ openTab(url: string): Promise<{
41
+ tabId: string;
42
+ }>;
43
+ closeTab(tabId: string): Promise<void>;
44
+ read(tabId: string, opts?: {
45
+ mode?: string;
46
+ query?: string;
47
+ budget?: number;
48
+ }): Promise<ReadResult>;
49
+ inspect(tabId: string, opts?: {
50
+ mode?: string;
51
+ query?: string;
52
+ limit?: number;
53
+ }): Promise<{
54
+ elements: InspectElement[];
55
+ }>;
56
+ click(tabId: string, elementId: string): Promise<void>;
57
+ fill(tabId: string, elementId: string, value: string): Promise<void>;
58
+ press(tabId: string, key: string, elementId?: string): Promise<void>;
59
+ select(tabId: string, elementId: string, value: string): Promise<void>;
60
+ waitFor(tabId: string, condition: string, opts?: {
61
+ value?: string;
62
+ timeout?: number;
63
+ }): Promise<void>;
64
+ evalScript(tabId: string, script: string): Promise<unknown>;
65
+ screenshot(tabId: string): Promise<{
66
+ data: string;
67
+ }>;
68
+ }
@@ -0,0 +1,15 @@
1
+ export interface AgentBrowserConnection {
2
+ url: string;
3
+ token: string;
4
+ pid: number;
5
+ version: string;
6
+ }
7
+ export declare function readConnectionFile(path?: string): AgentBrowserConnection | null;
8
+ export declare function isPidAlive(pid: number): boolean;
9
+ export declare function probeHealth(baseUrl: string, token: string, timeoutMs?: number): Promise<boolean>;
10
+ export interface AvailabilityResult {
11
+ available: boolean;
12
+ connection: AgentBrowserConnection | null;
13
+ reason: string | null;
14
+ }
15
+ export declare function checkAvailability(connectionPath?: string): Promise<AvailabilityResult>;
@@ -0,0 +1,30 @@
1
+ import type { BrowserProvider, OpenOutcome, ActOutcome } from '../provider.js';
2
+ import type { ActInput, BrowserConfig, BrowserObservation, BrowserProviderState, CloseInput, ExtractInput, ExtractResult, InteractiveElement, ObserveInput, OpenInput, RenderInput, RenderResult, ScreenshotInput, ScreenshotResult } from '../types.js';
3
+ import { AgentBrowserClient } from './client.js';
4
+ import type { AgentBrowserConnection } from './connection.js';
5
+ export interface SessionState {
6
+ tabId: string;
7
+ observationCounter: number;
8
+ knownElements: Map<string, InteractiveElement>;
9
+ lastAction: string | null;
10
+ lastActionAt: string | null;
11
+ currentUrl: string | null;
12
+ currentTitle: string | null;
13
+ }
14
+ export declare class AgentBrowserProvider implements BrowserProvider {
15
+ readonly name = "agent-browser";
16
+ private readonly config;
17
+ readonly client: AgentBrowserClient;
18
+ private readonly sessions;
19
+ constructor(config: BrowserConfig, connection: AgentBrowserConnection);
20
+ open(input: OpenInput): Promise<OpenOutcome>;
21
+ observe(input: ObserveInput): Promise<BrowserObservation>;
22
+ act(input: ActInput): Promise<ActOutcome>;
23
+ render(_input: RenderInput): Promise<RenderResult>;
24
+ screenshot(input: ScreenshotInput): Promise<ScreenshotResult>;
25
+ extract(_input: ExtractInput): Promise<ExtractResult>;
26
+ close(input: CloseInput): Promise<void>;
27
+ describe(sessionId: string): BrowserProviderState | null;
28
+ shutdown(): Promise<void>;
29
+ private buildObservation;
30
+ }
@@ -1,7 +1,9 @@
1
1
  import type { BrowserProvider } from './provider.js';
2
2
  import type { LoadBrowserConfigOptions } from './config.js';
3
+ import { type RoutingDecision } from './routing.js';
3
4
  export declare function getBrowserProvider(opts?: LoadBrowserConfigOptions): Promise<BrowserProvider>;
4
5
  export declare function closeBrowserProvider(): Promise<void>;
5
6
  export declare function browserProviderActive(): boolean;
6
7
  export declare function peekBrowserProvider(): BrowserProvider | null;
8
+ export declare function getLastRoutingDecision(): RoutingDecision | null;
7
9
  export declare function __resetBrowserRegistryForTests(): void;
@@ -0,0 +1,14 @@
1
+ import type { BrowserConfig } from './types.js';
2
+ import { type AvailabilityResult } from './agent-browser/connection.js';
3
+ export type RoutingBackend = 'playwright' | 'agent-browser';
4
+ export interface RoutingDecision {
5
+ backend: RoutingBackend;
6
+ reason: string;
7
+ probeMs: number;
8
+ availability: AvailabilityResult | null;
9
+ }
10
+ export interface RoutingContext {
11
+ config: BrowserConfig;
12
+ surface?: string;
13
+ }
14
+ export declare function selectBackend(ctx: RoutingContext): Promise<RoutingDecision>;
@@ -135,7 +135,7 @@ export interface BrowserConfig {
135
135
  allowedDomains: readonly string[];
136
136
  blockedDomains: readonly string[];
137
137
  domSnapshots: boolean;
138
- backend: 'playwright';
138
+ backend: 'playwright' | 'agent-browser' | 'auto';
139
139
  configPath: string | null;
140
140
  defaultProfile: string;
141
141
  }
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: fix-pr
3
3
  description: "One-verb pipeline for the operator's highest-frequency manual loop: fetch a PR's unresolved reviewer feedback (inline review comments, review-summary bodies, and issue-level conversation comments) and failing CI checks, fix them in an isolated managed worktree via a budget-bounded subagent, verify with the project's test gates, and push the fix back to the PR branch. Replaces the retyped recipe 'send a subagent in a worktree to fix <PR feedback>, then push.' Use when a PR has review comments or red CI that needs addressing — e.g. 'fix pr 286', 'address the review on #215', 'CI is red on the worktree-sweep PR'. Never force-pushes, never touches main, fails closed on missing gh auth or un-pushable fork PRs."
4
+ when-to-use: "A PR has review feedback or red CI that needs fixing."
4
5
  argument-hint: "<PR-number-or-URL> [--repo <path>] [--no-push] [--re-review]"
5
6
  surface: "afk"
6
7
  failure_modes:
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: refactor
3
3
  description: "Orchestrates safe, large-scale structural changes across a codebase — symbol renames, API migrations, pattern standardizations, layer restructurings. Enumerates all affected sites, groups them into dependency layers via the DAG executor, applies changes in parallel per layer with worktree isolation, and verifies behavioral preservation at each layer boundary before proceeding. Exits immediately on first regression, surfacing the exact site, diff, and behavioral delta before any commit."
4
+ when-to-use: "Large-scope structural refactors across multiple files or layers."
4
5
  argument-hint: "<refactor goal> [--scope <glob-or-path>]"
5
6
  failure_modes:
6
7
  - bad decomposition
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: ship
3
3
  description: "Release pipeline for already-done local work. Dispatches /ground-state pre-flight, runs the project test suite, drafts a commit message, pushes, and opens a PR with a structured verification summary. Use when local changes are ready to hand off to review — e.g. 'ship this', 'push and open a PR', 'release this work'. Add --verify to trigger an adversarial verifier wave on the diff before a human reads the PR."
4
+ when-to-use: "Local changes are ready to push and open a PR."
4
5
  context: fork
5
6
  ---
6
7
 
@@ -1,6 +1,7 @@
1
1
  ---
2
2
  name: simplify
3
3
  description: "Discovers incidental complexity, duplication, and dead code in a codebase and produces a ranked, behavior-preserving reduction plan — optionally applying safe changes. Dispatches four parallel read-only discovery lenses (clone detection, dead code, complexity hotspots, wrong abstraction), synthesizes into a prioritized reduction plan, and gates apply mode behind /refactor and a hard test check."
4
+ when-to-use: "Reduce complexity, find duplicates, or remove dead code."
4
5
  argument-hint: "[target] [--apply] [--all]"
5
6
  context: load
6
7
  ---
@@ -78,6 +78,7 @@ export interface InteractiveCtx {
78
78
  viewingTaskId?: string;
79
79
  hookRegistry?: HookRegistry;
80
80
  addPreviewDiffRef?: PreviewDiffRef;
81
+ hasPendingUserMessage?: () => boolean;
81
82
  }
82
83
  export interface CompletionWriter {
83
84
  fn: (line: string) => void;