@wrongstack/core 0.280.0 → 0.281.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.
Files changed (95) hide show
  1. package/dist/{agent-subagent-runner-PoqNKiR4.d.ts → agent-subagent-runner-DyOSK2Wy.d.ts} +39 -8
  2. package/dist/{compactor-U3agvUIG.d.ts → compactor-BxddyCFu.d.ts} +1 -1
  3. package/dist/{config-Cr3312zc.d.ts → config-CN-vdDEI.d.ts} +82 -2
  4. package/dist/coordination/index.d.ts +203 -20
  5. package/dist/coordination/index.js +981 -52
  6. package/dist/coordination/index.js.map +1 -1
  7. package/dist/defaults/index.d.ts +26 -30
  8. package/dist/defaults/index.js +382 -30
  9. package/dist/defaults/index.js.map +1 -1
  10. package/dist/{events-Bs2fmldo.d.ts → events-C5hLU0AT.d.ts} +38 -2
  11. package/dist/execution/index.d.ts +16 -16
  12. package/dist/execution/index.js +161 -18
  13. package/dist/execution/index.js.map +1 -1
  14. package/dist/execution/prompt-enhancer.d.ts +1 -1
  15. package/dist/execution/prompt-enhancer.js +12 -3
  16. package/dist/execution/prompt-enhancer.js.map +1 -1
  17. package/dist/extension/index.d.ts +6 -6
  18. package/dist/{global-mailbox-Ct7IorLJ.d.ts → global-mailbox-CHM1QkCi.d.ts} +5 -2
  19. package/dist/{goal-store-C4F6DjC0.d.ts → goal-store-BLGZq16t.d.ts} +1 -1
  20. package/dist/hq/index.d.ts +6 -6
  21. package/dist/hq/index.js +35 -13
  22. package/dist/hq/index.js.map +1 -1
  23. package/dist/{index-nP09-oP2.d.ts → index-BEFWNZYs.d.ts} +1 -2
  24. package/dist/{index-kidebiDh.d.ts → index-C1E-_71T.d.ts} +6 -6
  25. package/dist/index.d.ts +44 -48
  26. package/dist/index.js +14855 -13944
  27. package/dist/index.js.map +1 -1
  28. package/dist/infrastructure/index.d.ts +60 -8
  29. package/dist/infrastructure/index.js.map +1 -1
  30. package/dist/kernel/index.d.ts +11 -11
  31. package/dist/kernel/index.js.map +1 -1
  32. package/dist/{mcp-servers-D910X5_r.d.ts → mcp-servers-EKRAcJDi.d.ts} +97 -4
  33. package/dist/models/index.d.ts +4 -5
  34. package/dist/models/index.js +22 -5
  35. package/dist/models/index.js.map +1 -1
  36. package/dist/{multi-agent-coordinator-CieyUoEL.d.ts → multi-agent-coordinator-IpHCuHUa.d.ts} +29 -1
  37. package/dist/{null-fleet-bus-DkdmZJ_W.d.ts → null-fleet-bus-ZBkKGR9j.d.ts} +105 -7
  38. package/dist/observability/index.d.ts +3 -3
  39. package/dist/{tool-executor-SiE1wlZo.d.ts → parallel-eternal-engine-Cc2CNgmv.d.ts} +6 -202
  40. package/dist/path-resolver-CMS5307d.d.ts +13 -0
  41. package/dist/{permission-Dx6dIqS2.d.ts → permission-B6YAtNFz.d.ts} +1 -1
  42. package/dist/{pipeline-BwAP21_4.d.ts → pipeline-E7_jqGyV.d.ts} +2 -2
  43. package/dist/{provider-model-resolve-CwQNZWt_.d.ts → provider-model-resolve-KgIdiEQ6.d.ts} +118 -5
  44. package/dist/{provider-runner-CYHFImzV.d.ts → provider-runner-DxWXNHL1.d.ts} +3 -3
  45. package/dist/{retry-policy-D4feSLk3.d.ts → retry-policy-V67lBOJz.d.ts} +2 -2
  46. package/dist/sdd/index.d.ts +9 -9
  47. package/dist/sdd/index.js +94 -10
  48. package/dist/sdd/index.js.map +1 -1
  49. package/dist/{permission-policy-C8vJcnX5.d.ts → secret-vault-D7jeyXUQ.d.ts} +119 -3
  50. package/dist/security/index.d.ts +5 -6
  51. package/dist/security/index.js +4 -1
  52. package/dist/security/index.js.map +1 -1
  53. package/dist/{selector-Dy-MzKp1.d.ts → selector-Bx2HgUkU.d.ts} +1 -1
  54. package/dist/{session-event-bridge-CqdiGnfU.d.ts → session-event-bridge-vA2fLV58.d.ts} +1 -1
  55. package/dist/{session-reader-Hk0WbNm9.d.ts → session-reader-B-Fi9L6I.d.ts} +1 -1
  56. package/dist/session-registry-Dvg7i_IA.d.ts +129 -0
  57. package/dist/storage/index.d.ts +71 -142
  58. package/dist/storage/index.js +161 -13
  59. package/dist/storage/index.js.map +1 -1
  60. package/dist/{todos-checkpoint-Bk2uP7Ex.d.ts → todos-checkpoint-B1QVkoa8.d.ts} +23 -5
  61. package/dist/{tool-BkOgs_KL.d.ts → tool-LVSLiE1s.d.ts} +18 -4
  62. package/dist/{strategy-compactor-CQwhbErd.d.ts → tool-executor-BWtYwuPI.d.ts} +210 -12
  63. package/dist/tools/index.d.ts +2 -2
  64. package/dist/tools/index.js.map +1 -1
  65. package/dist/types/index.d.ts +17 -41
  66. package/dist/types/index.js +182 -5085
  67. package/dist/types/index.js.map +1 -1
  68. package/dist/utils/index.d.ts +3 -3
  69. package/dist/utils/index.js +6 -1
  70. package/dist/utils/index.js.map +1 -1
  71. package/dist/{worktree-manager-BjOFF6bt.d.ts → worktree-manager-C6CIilTT.d.ts} +1 -1
  72. package/dist/{wstack-paths-CMl_cYgq.d.ts → wstack-paths-C3K40Qst.d.ts} +2 -0
  73. package/instructions/agents/shadow-agent.md +23 -84
  74. package/instructions/coordination/director-preamble.md +12 -3
  75. package/instructions/coordination/subagent-baseline.md +39 -46
  76. package/instructions/leader-after-task.md +10 -28
  77. package/instructions/llm/llm-selector.md +1 -2
  78. package/instructions/modes/brief-system.md +7 -33
  79. package/instructions/modes/brief.md +5 -20
  80. package/instructions/modes/teach-system.md +12 -72
  81. package/instructions/modes/teach.md +12 -49
  82. package/instructions/sections/tool/commit-hygiene.md +5 -5
  83. package/instructions/sections/tool/context-management-full.md +6 -6
  84. package/instructions/sections/tool/delegation-compact.md +1 -1
  85. package/instructions/sections/tool/delegation-full.md +19 -23
  86. package/instructions/sections/tool/mailbox-full.md +11 -31
  87. package/instructions/sections/tool/mcp-full-control.md +5 -7
  88. package/instructions/sections/tool/mcp-full-use.md +7 -7
  89. package/instructions/system.md +22 -38
  90. package/package.json +1 -29
  91. package/dist/agent-bridge-DXC6QDJ4.d.ts +0 -35
  92. package/dist/logger-D3lV0cUZ.d.ts +0 -101
  93. package/dist/models-registry-CLkoOcHk.d.ts +0 -108
  94. package/dist/path-resolver-XfZ9eLxG.d.ts +0 -67
  95. package/dist/secret-vault-CImt2XrR.d.ts +0 -118
@@ -2,8 +2,8 @@
2
2
 
3
3
  Another coding agent, a separate wrongstack process, or a human may be editing this same working tree while you run. Before you commit:
4
4
 
5
- - **Never blind-stage the whole tree** (`git add .` / a bare `git commit` of all staged changes) unless you are certain you are the only writer. That sweep captures other agents' unfinished work into your commit.
6
- - **Scope to what you changed**: pass an explicit `files` list to the `git` tool so the commit contains only the files you edited this session.
7
- - **Read `git status` first**. If you see changes you did not make, leave them uncommitted; do not commit code you did not write or work that is half-done.
8
- - **Heed the `warning` field** on a commit result: it flags files authored by another agent/session. If it fires, narrow your `files` list or coordinate via the mailbox before committing.
9
- - A failed or aborted commit beats a commit that mixes your work with someone else's. When in doubt, commit a smaller, self-contained slice.
5
+ - **Never blind-stage the whole tree** (`git add .` / a bare commit of everything staged) unless you are certain you are the only writer it sweeps other agents' unfinished work into your commit.
6
+ - **Scope to what you changed**: pass an explicit `files` list to the `git` tool so the commit contains only files you edited this session.
7
+ - **Read `git status` first.** Changes you did not make stay uncommitted never commit code you didn't write or work that is half-done.
8
+ - **Heed the `warning` field** on a commit result: it flags files authored by another agent/session. If it fires, narrow your `files` list or coordinate via the mailbox first.
9
+ - When in doubt, commit a smaller, self-contained slice — a failed commit beats one that mixes your work with someone else's.
@@ -1,10 +1,10 @@
1
1
  ## Context management
2
2
 
3
- When the conversation grows long and context window usage exceeds what you can track, use the context_manager tool proactively. Do not wait to be told:
3
+ When the conversation grows long, use the `context_manager` tool proactively do not wait to be told:
4
4
 
5
- - Call `context_manager` with `{"action":"check"}` to see current token budget and message counts.
6
- - When the conversation exceeds ~{{threshold}}% of your context window, call `{"action":"summary"}` or `{"action":"compact"}` to reclaim space.
7
- - Use `{"action":"prune"}` to surgically remove specific irrelevant message ranges, such as old debug output.
8
- - Use `{"action":"add_note"}` to inject a summary note at a specific point after a complex operation.
5
+ - `{"action":"check"}` current token budget and message counts.
6
+ - Past ~{{threshold}}% of the context window: `{"action":"summary"}` or `{"action":"compact"}` to reclaim space.
7
+ - `{"action":"prune"}` surgically remove irrelevant message ranges (e.g. old debug output).
8
+ - `{"action":"add_note"}` inject a summary note after a complex operation.
9
9
 
10
- Never stuff redundant information into a tool result. If you summarize a file, do not paste its full content; summarize it, and let the tool result hold only the summary.
10
+ Never restate bulk content: when you summarize a file, keep the summary and let go of the full text.
@@ -1,3 +1,3 @@
1
1
  ## Delegation
2
2
 
3
- Use `delegate` to hand work to a subagent (roles: {{roleList}}).
3
+ Use `delegate` to hand work to a subagent (roles: {{roleList}}). Provider/model/budget default sensibly when omitted; override per call only with a concrete reason.
@@ -1,39 +1,35 @@
1
1
  ## Delegation
2
2
 
3
- You have a `delegate` tool that hands a discrete piece of work to a dedicated subagent (its own context, its own LLM call, its own budget cap) and waits for the result. Use it proactively when:
3
+ The `delegate` tool hands a discrete piece of work to a subagent (own context, own LLM call, own budget) and waits for the result. The roster has tuned prompts and budgets for: {{roleList}} — reach for a role when it matches the subtask; otherwise pass `name` + `task` for a general-purpose coding subagent. Use it proactively when:
4
4
 
5
- - **The task fans out naturally**: for example, "audit these 5 files for security issues" splits cleanly into 5 parallel `delegate` calls, one per file or per role. Fire them through the provider's parallel-tool-call surface in the same turn.
6
- - **A specialized role exists**: the roster has tuned prompts and budgets for: {{roleList}}. Reach for a role when the description matches your subtask; otherwise pass `name` + `provider` + `model`.
5
+ - **The task fans out naturally**: "audit these 5 files" splits into 5 parallel `delegate` calls fire them in the same turn via parallel tool calls.
7
6
  - **A subtask would blow up your context**: long log analyses, large diff reviews, multi-file refactor plans. The subagent absorbs the reading cost and hands back a summary.
8
- - **You'd otherwise switch hats mid-turn**: instead of stopping a code fix to do a security pass, delegate the security pass.
7
+ - **You'd switch hats mid-turn**: delegate the security pass instead of stopping a code fix.
9
8
 
10
- ### Scope it tight
9
+ Stay in-process when the task is trivial or atomic, the information is already in your context, or the user expects an immediate reply rather than a research detour.
11
10
 
12
- A subagent has a finite iteration / tool-call budget, typically 50-80 iterations and 200-300 tool calls. Tasks that mention "ALL files" or "the entire codebase" reliably exhaust that budget without producing a clean answer. The delegate returns with `stopReason: budget_exhausted` and no useful output.
11
+ ### Provider & model
12
+
13
+ When you omit `provider`/`model`, the system resolves them for you: the user's model matrix (`/setmodel`; exact role → role's phase → `*` default) and finally your own host model. That default is usually right — override per call only when you have a concrete reason: a heavy-reasoning model for planning/architecture, a fast cheap model for mechanical batch work, a domain specialist for niche code. Switch a subagent's provider when the current one is rate-limited.
14
+
15
+ ### Scope it tight, size the budget
16
+
17
+ There is no hidden budget cap — YOU size it: `timeoutMs` (default 30 min), `maxIterations`, `maxToolCalls`, set to what the work realistically needs. But a broad task is still a bad task: "ALL files" / "the entire codebase" produces shallow, unfocused answers regardless of budget.
13
18
 
14
- - BAD: `"Analyze ALL .ts files in src/ for bugs"`
15
19
  - BAD: `"Audit the codebase for security issues"`
16
- - BAD: `"Plan a refactor of the whole project"`
17
20
  - GOOD: `"Audit src/auth/session.ts for null-deref bugs in the login flow"`
18
21
  - GOOD: `"Check packages/core/src/storage/*.ts for unhandled promise rejections (~6 files)"`
19
- - GOOD: `"Plan a phased refactor of the InMemoryBridge transport (3 files in coordination/)"`
20
22
 
21
- If you need fleet-wide coverage, fan out: list the target files yourself first with one quick `glob` call, then fire one `delegate` per chunk of 5-10 files in parallel.
23
+ For fleet-wide coverage, fan out: `glob` the target files yourself first, then fire one `delegate` per chunk of 510 files in parallel.
22
24
 
23
25
  ### Reading the result
24
26
 
25
- `delegate` returns a structured object. Look at `stopReason`:
26
-
27
- - `end_turn`: subagent finished cleanly, `result` has the answer.
28
- - `budget_exhausted`: task was too broad; `partial.lastAssistantText` has whatever it managed. Narrow the next try.
29
- - `subagent_timeout` / `host_timeout`: likewise partial; raise `timeoutMs` only if you have a reason to believe more time would help.
30
- - `aborted`: the user or another tool stopped this worker; don't retry silently.
31
- - `error`: infrastructure problem; surface it.
32
-
33
- Stay in-process, without `delegate`, when:
27
+ Check `stopReason` on the returned object:
34
28
 
35
- - The task is trivial or atomic.
36
- - The information needed is already in your context.
37
- - The user is mid-conversation and expects an immediate reply from you, not a research detour through a subagent.
29
+ - `end_turn` finished cleanly; `result` has the answer.
30
+ - `budget_exhausted` `partial.lastAssistantText` has what it managed. Raise the matching `max*` field (e.g. `maxToolCalls: 600`) on the retry, or split the task.
31
+ - `subagent_timeout` / `host_timeout` likewise partial; raise `timeoutMs` if more time would plausibly help.
32
+ - `aborted` — the user or another tool stopped it; don't retry silently.
33
+ - `error` — infrastructure problem; surface it.
38
34
 
39
- `delegate` auto-promotes the host into director mode the first time it's called; you do not need to call any setup tool. For fine-grained control over a long-running fleet, use `spawn_subagent` + `assign_task` + `await_tasks` directly; `delegate` is the one-call shortcut.
35
+ `delegate` auto-promotes you into director mode on first call no setup tool needed. For fine-grained control over a long-running fleet, use `spawn_subagent` + `assign_task` + `await_tasks` directly. Fire-and-forget assigns report back automatically: a completed non-awaited task posts its result to your mailbox, injected before your next step.
@@ -1,45 +1,25 @@
1
1
  ## Inter-agent mailbox{{onlineAgentsInfo}}
2
2
 
3
- You share a persistent project mailbox with every other agent working on this project, including other terminals, TUIs and WebUIs. You are expected to use it: announce what you do, hand work off, ask questions, and answer mail addressed to you. Coordination is part of the job, not an optional extra.
3
+ You share a persistent project mailbox with every other agent working on this project, including other terminals, TUIs and WebUIs. Coordination is part of the job: announce what you do, hand work off, and answer mail addressed to you.
4
4
 
5
5
  ### Your identity
6
6
 
7
- You are addressable as `<your-name>@<session-tag>` (your session-unique id, visible in the online list). Every session has its own tag, so two sessions running under the same name never mix. Mail sent to your bare base name, such as `leader`, reaches every live session running under that name; mail to your exact id reaches only you. When replying, use the sender's exact `from` id.
7
+ You are addressable as `<your-name>@<session-tag>` (session-unique, visible in the online list). Mail to your bare base name (e.g. `leader`) reaches every live session under that name; mail to your exact id reaches only you. When replying, use the sender's exact `from` id.
8
8
 
9
9
  ### Receiving
10
10
 
11
- Unread mail (direct, base-name, and `*` broadcasts) is injected into your conversation automatically before each step. All message types (steer, btw, ask, assign, result, note) appear inline with a call to action. You do not need to manually check the mailbox; subagent results and questions reach you even while you are mid-task.
11
+ Unread mail (direct, base-name, and `*` broadcasts) is injected into your conversation automatically before each step — you never need to poll; results and questions reach you even mid-task. How to react by type: **steer** adjust course at the next stopping point; **ask** → reply to the sender; **assign** act on it when your current operation allows; **result** factor it into your next decision; **review** → inspect the referenced code/doc when convenient; **note**/**btw**/**status** absorb the info, no reply needed don't derail your current task. To catch up explicitly: `mail_inbox` (read unread + mark read) or `mailbox action=query from=<agent> type=result`.
12
12
 
13
- When a message includes a call to action:
13
+ ### Sending & discovery
14
14
 
15
- - **ask**: reply to the agent directly or use `mail_send` to respond
16
- - **assign**: act on the task when your current operation allows
17
- - **result**: factor the outcome into your next decision
18
-
19
- To catch up explicitly:
20
-
21
- - `mail_inbox`: read your unread mail and mark it read
22
- - `mailbox action=query from=<agent> type=result`: find specific results
23
-
24
- ### Sending
25
-
26
- - `mail_send to=<agentId> subject="..." body="..."`: direct message
27
- - `mail_send to="*" subject="..." body="..."`: broadcast to everyone (`to="all"` works too)
28
- - Message types: `note` (info), `ask` (question), `assign` (task handoff), `steer` (change approach), `btw` (non-urgent info), `status` (your current task), `result` (task outcome)
29
-
30
- ### Agent discovery
31
-
32
- - `mailbox action=online`: who is live right now (ids to address)
33
- - `mailbox action=status`: all agents and their current tasks. Use this to find who to ask for help or who can pick up a broadcast task.
15
+ - `mail_send to=<agentId> subject="..." body="..."` direct; `to="*"` broadcasts to everyone.
16
+ - Message types: `note`, `ask`, `assign` (task handoff), `steer` (change approach), `btw` (non-urgent FYI), `status`, `result`, `review`, `broadcast`. Match the type to the intent an `ask` demands a reply from the receiver, a `btw` explicitly doesn't; don't send `ask` for information that needs no answer.
17
+ - `mailbox action=online` who is live (ids to address); `mailbox action=status` — all agents and their current tasks.
18
+ - `mailbox action=ack messageId=<id> completed=true outcome="..."` — mark an assignment complete (reading auto-marks messages as read; `ack` marks them done).
34
19
 
35
20
  ### Etiquette
36
21
 
37
- - **Broadcast milestones**: when you finish a significant change, `mail_send to="*"` so parallel agents do not collide with or duplicate your work.
38
- - **Hand off matching work**: if another agent's role fits a task better, send it to them instead of doing everything yourself.
39
- - **Answer your mail**: when an `ask` arrives, reply to the sender's exact id with a `result` or `note`; silence stalls the other agent.
22
+ - **Broadcast milestones**: after a significant change, `mail_send to="*"` so parallel agents don't collide with or duplicate your work.
40
23
  - Post a `status` when you start something significant; post a `result` when someone is waiting on you.
41
-
42
- ### Acknowledging
43
-
44
- - `mailbox action=ack messageId=<id> completed=true outcome="What you did"`
45
- - Messages you `check` are auto-marked as read; use `ack` to mark complete.
24
+ - **Hand off matching work** to the agent whose role fits it better instead of doing everything yourself.
25
+ - **Answer every `ask`** — reply to the sender's exact id with a `result` or `note`; silence stalls the other agent.
@@ -1,12 +1,10 @@
1
1
  ## MCP tools (lazy-loaded)
2
2
 
3
- MCP server tools are not registered by default in token-saving mode to keep the prompt compact. Each server's process is running in the background; only tool registration is deferred.
3
+ MCP servers are running in the background, but their tools are not registered in token-saving mode only registration is deferred. When you need a server's tools:
4
4
 
5
- When you need a specific MCP server's tools:
6
-
7
- 1. `mcp_control({ action: "list" })`: see which servers are connected
8
- 2. `mcp_control({ action: "activate", server: "<name>" })`: register its tools
5
+ 1. `mcp_control({ action: "list" })` see connected servers
6
+ 2. `mcp_control({ action: "activate", server: "<name>" })` — register its tools
9
7
  3. Use the tools as needed
10
- 4. `mcp_control({ action: "deactivate", server: "<name>" })`: unregister when done
8
+ 4. `mcp_control({ action: "deactivate", server: "<name>" })` unregister when done
11
9
 
12
- Activation/deactivation is ephemeral (no config writes) and does not affect the server connection, only tool visibility.
10
+ Activation/deactivation is ephemeral (no config writes) and affects only tool visibility, not the server connection.
@@ -1,18 +1,18 @@
1
1
  ## MCP tools (lazy-loaded)
2
2
 
3
- MCP server tools are not registered by default in token-saving mode to keep the prompt compact. Each server's process is running in the background; only tool registration is deferred.
3
+ MCP servers are running in the background, but their tools are not registered in token-saving mode only registration is deferred.
4
4
 
5
- **Preferred approach**: one-shot meta-tool:
5
+ **Preferred approach** one-shot meta-tool:
6
6
 
7
7
  `mcp_use({ server: "<name>", tool: "<bare-tool>", input: { ... } })`
8
8
 
9
- This activates the server, calls the tool, returns the result, and deactivates, all in one call. No need to track activate/deactivate state.
9
+ Activates the server, calls the tool, returns the result, and deactivates no state to track.
10
10
 
11
11
  **Manual approach** for exploration:
12
12
 
13
- 1. `mcp_control({ action: "list" })`: see which servers are connected
14
- 2. `mcp_control({ action: "activate", server: "<name>" })`: register tools
13
+ 1. `mcp_control({ action: "list" })` see connected servers
14
+ 2. `mcp_control({ action: "activate", server: "<name>" })` register tools
15
15
  3. Use the tools normally
16
- 4. `mcp_control({ action: "deactivate", server: "<name>" })`: clean up
16
+ 4. `mcp_control({ action: "deactivate", server: "<name>" })` clean up
17
17
 
18
- Activation/deactivation is ephemeral (no config writes) and does not affect the server connection, only tool visibility.
18
+ Activation/deactivation is ephemeral (no config writes) and affects only tool visibility, not the server connection.
@@ -1,47 +1,31 @@
1
1
  You are WrongStack, a command-line AI coding agent.
2
2
 
3
- You 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 — your job is to accelerate them, not to second-guess them.
3
+ You operate inside the user's terminal with direct read/write access to their working directory, shell execution, and web access. You assist a developer who knows what they're doing — accelerate them, don't second-guess them.
4
4
 
5
- These 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 — the mode layer always wins on conflict.
5
+ These 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.
6
6
 
7
7
  ## Core principles
8
8
 
9
- 1. **Read before you write.** Always inspect the relevant files before proposing changes. Assumptions about code you haven't read are bugs in waiting.
10
- 2. **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.
11
- 3. **Show your work.** Before non-trivial changes, briefly state what you're about to do — one sentence, not a wall of text. After tool calls, summarize what happened, not what you did mechanically.
12
- 4. **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.
13
- 5. **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 follow the mode's guidance on depth.)
14
- 6. **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.
15
- 7. **Trust the tools.** If a permission prompt is shown, the user will answer. Do not preemptively explain that you "would like to" do something call the tool, let the permission flow decide.
16
- 8. **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.
17
- 9. **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.
18
- 10. **Recover explicitly.** When a tool fails, distinguish the failure type and respond accordingly:
9
+ 1. **Read before you write.** Inspect the relevant files before proposing changes assumptions about code you haven't read are bugs in waiting. When unsure about a file's current state, read it rather than guessing.
10
+ 2. **Prefer surgical edits over rewrites.** Modify existing files with the `edit` tool (`old_string`/`new_string`); use `write` only for new files or explicitly requested full replacements.
11
+ 3. **Announce, then act.** Before a non-trivial change, one sentence on what you're about to do — not a wall of text. Afterwards, summarize the outcome, not the mechanics.
12
+ 4. **Be honest about limits.** If you don't know, say so. Never fabricate file contents, command output, or test results. Never call work "production-ready" or "fully tested" the user makes that call.
13
+ 5. **Be concise and scannable.** No marketing language, no filler. If a one-liner answers, a one-liner is the answer. Code blocks for code, backticks for paths, bold for key terms; paragraphs max 3 sentences. (Active modes may override verbosity.)
14
+ 6. **Match the user's language.** Reply in the language the user writes in; if they mix, follow the dominant one.
15
+ 7. **Ask when blocked, proceed when not.** If ambiguity meaningfully changes the approach (unclear file, conflicting requirements), ask. Otherwise pick a reasonable default, state the assumption, and proceed.
16
+ 8. **Stay focused.** Fix only what was asked no refactoring or reformatting of neighboring code. Comment only to explain *why*, not *what*. Don't lecture about engineering principles unless asked.
19
17
 
20
- | Failure type | Examples | Strategy |
21
- |---|---|---|
22
- | **Transient** | Timeout, rate limit, network hiccup | Retry once with adjusted params, then report |
23
- | **Permanent** | Syntax error, missing file, type error, permission denied | Do NOT retry — diagnose and report the root cause |
24
- | **Validation** | Invalid argument, out-of-range value, schema mismatch | State what was rejected and what range/format is accepted |
25
-
26
- Never silently skip a failure — always report it, even when you choose not to retry.
27
-
28
- **Empty results are not failures.** When a tool returns an empty result (no lines, no matches, no output), this means the operation completed successfully but found nothing. Do NOT retry the same call with the same parameters — interpret the empty result and adjust your approach. For example, an empty file read at a given offset means you've reached the end of the file; an empty grep means no matches exist.
18
+ ## Tool use and failures
29
19
 
30
- ## Decision heuristics
20
+ Call tools directly and let the permission flow decide — don't pre-announce that you "would like to" do something. When a tool fails, classify the failure and respond accordingly; never silently skip one:
31
21
 
32
- - **Task is ambiguous** (unclear which file, conflicting requirements) → ask before proceeding
33
- - **Task is clear, approach is unknown** → try one approach, report what happened
34
- - **Tool fails** classify the failure (transient/permanent/validation), then apply the appropriate recovery
35
- - **Permission prompt shown** wait for user, do not act unilaterally
36
- - **Tool denied by user** 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 — acknowledge it and ask if they'd like to clarify what they actually want.
37
- - **Context window filling up** → use context_manager proactively; don't wait to be told
38
-
39
- ## How you work
40
-
41
- - **Stay focused.** When fixing a bug, fix only the bug — don't refactor neighboring code unless the user asks.
42
- - **Comment with purpose.** Add comments only when they explain why, not what. The code already says what.
43
- - **Own your output.** Never call work "production-ready" or "fully tested" — the user makes that call.
44
- - **Move on from mistakes.** When something fails, report what happened and what you'll do next. No apologies, no hand-wringing.
45
- - **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.
46
- - **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?"
47
- - **Stay in your lane.** Don't lecture about software engineering principles unless explicitly asked — the user is the expert on their codebase.
22
+ | Failure type | Examples | Strategy |
23
+ |---|---|---|
24
+ | **Transient** | timeout, rate limit, network hiccup | Retry once with adjusted params, then report |
25
+ | **Permanent** | syntax error, missing file, permission denied | Do NOT retry — diagnose and report the root cause |
26
+ | **Validation** | invalid argument, out-of-range value, schema mismatch | State what was rejected and what format is accepted |
27
+
28
+ - **Empty results are successes, not failures.** No matches / no lines / no output means the call worked and found nothing. Never repeat the identical call — interpret the result (empty read at offset = end of file; empty grep = no matches) and adjust.
29
+ - **A denial is final.** If the user denies a tool call via the permission prompt, do not retry it and do not work around it with another tool. Acknowledge the denial and ask: "What would you like me to do instead?"
30
+ - **Context filling up** → use `context_manager` proactively; don't wait to be told.
31
+ - **Move on from mistakes.** Report what failed and what you'll try next. No apologies, no hand-wringing.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wrongstack/core",
3
- "version": "0.280.0",
3
+ "version": "0.281.0",
4
4
  "license": "MIT",
5
5
  "description": "WrongStack core: kernel, types, defaults, and shared utilities for the WrongStack CLI agent.",
6
6
  "repository": {
@@ -36,10 +36,6 @@
36
36
  "types": "./dist/utils/index.d.ts",
37
37
  "import": "./dist/utils/index.js"
38
38
  },
39
- "./utils/expect-defined": {
40
- "types": "./dist/utils/expect-defined.d.ts",
41
- "import": "./dist/utils/expect-defined.js"
42
- },
43
39
  "./utils/error": {
44
40
  "types": "./dist/utils/error.d.ts",
45
41
  "import": "./dist/utils/error.js"
@@ -48,10 +44,6 @@
48
44
  "types": "./dist/execution/index.d.ts",
49
45
  "import": "./dist/execution/index.js"
50
46
  },
51
- "./execution/prompt-enhancer": {
52
- "types": "./dist/execution/prompt-enhancer.d.ts",
53
- "import": "./dist/execution/prompt-enhancer.js"
54
- },
55
47
  "./coordination": {
56
48
  "types": "./dist/coordination/index.d.ts",
57
49
  "import": "./dist/coordination/index.js"
@@ -60,38 +52,18 @@
60
52
  "types": "./dist/storage/index.d.ts",
61
53
  "import": "./dist/storage/index.js"
62
54
  },
63
- "./hq": {
64
- "types": "./dist/hq/index.d.ts",
65
- "import": "./dist/hq/index.js"
66
- },
67
55
  "./security": {
68
56
  "types": "./dist/security/index.d.ts",
69
57
  "import": "./dist/security/index.js"
70
58
  },
71
- "./sdd": {
72
- "types": "./dist/sdd/index.d.ts",
73
- "import": "./dist/sdd/index.js"
74
- },
75
- "./models": {
76
- "types": "./dist/models/index.d.ts",
77
- "import": "./dist/models/index.js"
78
- },
79
59
  "./infrastructure": {
80
60
  "types": "./dist/infrastructure/index.d.ts",
81
61
  "import": "./dist/infrastructure/index.js"
82
62
  },
83
- "./observability": {
84
- "types": "./dist/observability/index.d.ts",
85
- "import": "./dist/observability/index.js"
86
- },
87
63
  "./tools": {
88
64
  "types": "./dist/tools/index.d.ts",
89
65
  "import": "./dist/tools/index.js"
90
66
  },
91
- "./extension": {
92
- "types": "./dist/extension/index.d.ts",
93
- "import": "./dist/extension/index.js"
94
- },
95
67
  "./skills": {
96
68
  "types": "./dist/skills/index.d.ts",
97
69
  "import": "./dist/skills/index.js"
@@ -1,35 +0,0 @@
1
- import { B as BridgeTransport, a as BridgeMessage, A as AgentBridge, b as AgentBridgeConfig } from './agent-subagent-runner-PoqNKiR4.js';
2
-
3
- /**
4
- * In-memory pub/sub transport for agent-to-agent messaging.
5
- * Subscribers register by agentId and receive messages via callback.
6
- */
7
- declare class InMemoryBridgeTransport implements BridgeTransport {
8
- private readonly subs;
9
- send(msg: BridgeMessage, to: string): Promise<void>;
10
- subscribe(agentId: string, handler: (msg: BridgeMessage) => void): () => void;
11
- close(agentId: string): Promise<void>;
12
- }
13
-
14
- declare class InMemoryAgentBridge implements AgentBridge {
15
- readonly agentId: string;
16
- readonly coordinatorId: string;
17
- private readonly transport;
18
- private readonly subscriptions;
19
- private readonly pendingRequests;
20
- private stopped;
21
- private timeoutMs;
22
- /** Guards request() so concurrent calls on the same id can't silently overwrite. */
23
- private readonly inflightGuards;
24
- /** Stores the transport unsubscribe function so it can be called on stop(). */
25
- private _transportUnsubscribe?;
26
- constructor(config: AgentBridgeConfig, transport: BridgeTransport);
27
- send(msg: BridgeMessage): Promise<void>;
28
- broadcast(msg: BridgeMessage): Promise<void>;
29
- subscribe(handler: (msg: BridgeMessage) => void | Promise<void>): () => void;
30
- request<T>(msg: BridgeMessage, timeoutMs?: number): Promise<BridgeMessage<T>>;
31
- stop(): Promise<void>;
32
- }
33
- declare function createMessage<T = unknown>(type: BridgeMessage['type'], from: string, payload: T, to?: string | undefined): BridgeMessage<T>;
34
-
35
- export { InMemoryAgentBridge as I, InMemoryBridgeTransport as a, createMessage as c };
@@ -1,101 +0,0 @@
1
- import { L as Logger, a as LogLevel } from './logger-B63L5bTg.js';
2
-
3
- type LogFormat = 'pretty' | 'json';
4
- interface DefaultLoggerOptions {
5
- level?: LogLevel | undefined;
6
- file?: string | undefined;
7
- /**
8
- * @deprecated Use `format: 'json'` instead. Kept for backward compat
9
- * with existing callers but has no effect on output — the `format`
10
- * option controls whether stderr receives pretty-printed or JSON lines.
11
- */
12
- pretty?: boolean | undefined;
13
- /** Output format for stderr. `pretty` (colored, human-readable) or `json` (machine-parseable). Defaults to `WRONGSTACK_LOG_FORMAT` env var, falling back to `pretty`. */
14
- format?: LogFormat | undefined;
15
- bindings?: Record<string, unknown>;
16
- /**
17
- * When false, suppress stderr output entirely — only write to the log
18
- * file (if configured). Use this in TUI mode so plugin/library log
19
- * messages don't interleave with Ink's terminal rendering.
20
- * Default: true (stderr output is enabled).
21
- */
22
- stderr?: boolean | undefined;
23
- /**
24
- * Rotate the log file once it exceeds this many bytes: the current file is
25
- * renamed to `<file>.1` (replacing any previous one) and a fresh file
26
- * starts. Bounds total disk to ~2× this value. Default 10 MB.
27
- */
28
- maxFileBytes?: number | undefined;
29
- }
30
- declare class DefaultLogger implements Logger {
31
- /** How many file writes between rotation size checks (statSync is not free). */
32
- private static readonly ROTATE_CHECK_EVERY;
33
- level: LogLevel;
34
- private file?;
35
- private bindings;
36
- private format;
37
- private stderr;
38
- private maxFileBytes;
39
- private writesSinceRotateCheck;
40
- /**
41
- * Serialized async tail for file writes. Every appendFile (and any
42
- * chained rotation) is awaited through this promise so file I/O
43
- * never overlaps itself — preserving the per-line ordering the
44
- * sync version had, but without blocking the caller thread. Any
45
- * rejection is swallowed (`catch(() => {})`) because logging must
46
- * never crash the host.
47
- *
48
- * Children share the parent's tail: `child.tail === parent.tail`
49
- * for the lifetime of the chain. Read/write access goes through
50
- * `_tail` so that, when a child has been wired to a parent, both
51
- * `enqueueRotate` and `log` always observe the parent's current tail
52
- * rather than a stale snapshot taken at `child()` time.
53
- */
54
- private tail;
55
- private parent;
56
- /**
57
- * Resolve the current tail. For the root logger this is the field;
58
- * for a child logger we always read through the parent so that a
59
- * child's appends land on the parent's most recent tail, and a
60
- * parent's `flush()` waits for everything the child chained.
61
- */
62
- private get _tail();
63
- private set _tail(value);
64
- constructor(opts?: DefaultLoggerOptions);
65
- error(msg: string, ctx?: unknown): void;
66
- warn(msg: string, ctx?: unknown): void;
67
- info(msg: string, ctx?: unknown): void;
68
- debug(msg: string, ctx?: unknown): void;
69
- trace(msg: string, ctx?: unknown): void;
70
- child(bindings: Record<string, unknown>): Logger;
71
- /**
72
- * Wait until all queued file writes (and any pending rotation) have
73
- * completed. `log()` is fire-and-forget by design — the caller never
74
- * blocks on disk — so tests, shutdown handlers, and processes that
75
- * need a deterministic "everything is on disk now" guarantee should
76
- * `await logger.flush()` before reading the file or exiting.
77
- */
78
- flush(): Promise<void>;
79
- /**
80
- * Size-based rotation: when the file outgrows `maxFileBytes`, rename it to
81
- * `<file>.1` (dropping the previous `.1`) so the live file restarts empty.
82
- * Checked on the first write and every ROTATE_CHECK_EVERY writes after.
83
- * Best-effort: a rename can fail on Windows while another process holds
84
- * the file — the next check retries. Multiple processes appending to the
85
- * same log all run this check; whoever crosses the threshold first wins.
86
- *
87
- * Async: the rotation runs on the file-write tail (so its writes don't
88
- * interleave with the next append), and the caller never blocks on a
89
- * statSync / renameSync syscall on the hot log path.
90
- */
91
- private enqueueRotate;
92
- private log;
93
- }
94
- /**
95
- * A logger that silently discards all messages. Used during boot before
96
- * the real logger is configured, and in test contexts where logging
97
- * would be noise.
98
- */
99
- declare const noOpLogger: Logger;
100
-
101
- export { DefaultLogger as D, type LogFormat as L, type DefaultLoggerOptions as a, noOpLogger as n };
@@ -1,108 +0,0 @@
1
- import { M as ModelsRegistry, a as ModelsDevPayload, R as ResolvedProvider, b as ResolvedModel, W as WireFamily } from './config-Cr3312zc.js';
2
-
3
- interface DefaultModelsRegistryOptions {
4
- cacheFile: string;
5
- url?: string | undefined;
6
- ttlSeconds?: number | undefined;
7
- fetchImpl?: typeof fetch | undefined;
8
- /** Pre-seeded payload — useful for offline scenarios and tests. */
9
- seed?: ModelsDevPayload | undefined;
10
- /**
11
- * Maximum age in seconds for stale cache fallback when network fails.
12
- * Defaults to 7 days. Set to `Infinity` for full offline resilience
13
- * (risk: deprecated models, wrong pricing). Set to `0` to disable
14
- * stale fallback entirely.
15
- */
16
- maxStaleAgeSeconds?: number | undefined;
17
- /**
18
- * Timeout in milliseconds for the models.dev network fetch. When exceeded,
19
- * the fetch is aborted and cache/stale fallback is used instead.
20
- * Defaults to 15 seconds. Set to `0` to disable (infinite wait).
21
- */
22
- refreshTimeoutMs?: number | undefined;
23
- /**
24
- * Curated override payload deep-merged ON TOP of the models.dev base via
25
- * `mergeModelsPayload` — adds providers/models the base lacks and overrides
26
- * fields it gets wrong. Resolution order (first non-empty wins): this
27
- * in-memory `overlay` → `overlayUrl` (fetched, cached) → `overlayFile`
28
- * (bundled, read from disk). A missing/broken overlay degrades to `{}` and
29
- * never throws, so the base alone still works.
30
- */
31
- overlay?: ModelsDevPayload | undefined;
32
- /** GitHub-raw (or any) URL serving the curated overlay `providers.json`. */
33
- overlayUrl?: string | undefined;
34
- /** Path to the bundled overlay `providers.json` (offline floor). */
35
- overlayFile?: string | undefined;
36
- /** Cache file for the fetched `overlayUrl`. Defaults next to `cacheFile`. */
37
- overlayCacheFile?: string | undefined;
38
- }
39
- declare function classifyFamily(npm: string | undefined): WireFamily;
40
- declare class DefaultModelsRegistry implements ModelsRegistry {
41
- /** Merged (base + overlay) payload — what every reader sees. */
42
- private payload?;
43
- /** Memoised overlay payload (in-memory / fetched / file). */
44
- private overlayPayload?;
45
- /**
46
- * Extra providers injected at runtime via `mergeOverlay()` — e.g. an
47
- * openai-compatible server (omniroute, LiteLLM, …) auto-discovered from its
48
- * `/v1/models` endpoint at boot. Applied LAST (on top of base + curated
49
- * overlay) and re-applied across `refresh()` so the discovered catalog
50
- * survives a models.dev refetch.
51
- */
52
- private extraOverlay?;
53
- private fetchedAt?;
54
- private readonly cacheFile;
55
- private readonly url;
56
- private readonly ttlMs;
57
- private readonly fetchImpl;
58
- private readonly seed?;
59
- private readonly maxStaleAgeMs;
60
- private readonly refreshTimeoutMs;
61
- private readonly overlay?;
62
- private readonly overlayUrl?;
63
- private readonly overlayFile?;
64
- private readonly overlayCacheFile?;
65
- constructor(opts: DefaultModelsRegistryOptions);
66
- load(opts?: {
67
- force?: boolean | undefined;
68
- }): Promise<ModelsDevPayload>;
69
- /**
70
- * Merge an additional provider payload on top of the resolved catalog. Used
71
- * for runtime-discovered openai-compatible providers. Remembered so it is
72
- * re-applied across `refresh()`. A no-op for an empty payload.
73
- */
74
- mergeOverlay(payload: ModelsDevPayload): void;
75
- private withExtraOverlay;
76
- /**
77
- * Load the models.dev base payload: fresh cache → network → stale cache.
78
- * On total failure, degrade to `{}` (so a non-empty overlay still drives
79
- * the catalog) rather than throwing — unless there's no curated overlay to
80
- * fall back on, in which case the original error propagates so pure-
81
- * models.dev setups still surface the problem.
82
- */
83
- private loadBase;
84
- /** Fetch + cache the models.dev base. Throws on failure (used by `refresh`). */
85
- private refreshBase;
86
- /**
87
- * Resolve the curated overlay, memoised. Order: in-memory `overlay` →
88
- * fetched `overlayUrl` (cached, same TTL/stale rules) → `overlayFile` on
89
- * disk. Never throws — a missing/broken overlay yields `{}`.
90
- */
91
- private loadOverlay;
92
- private loadOverlayFromUrl;
93
- private readOverlayFile;
94
- refresh(): Promise<ModelsDevPayload>;
95
- listProviders(): Promise<ResolvedProvider[]>;
96
- getProvider(id: string): Promise<ResolvedProvider | undefined>;
97
- getModel(providerId: string, modelId: string): Promise<ResolvedModel | undefined>;
98
- suggestModel(providerId: string): Promise<string | undefined>;
99
- ageSeconds(): Promise<number>;
100
- private resolveProvider;
101
- private isFresh;
102
- private isWithinMaxStaleAge;
103
- private readCacheAt;
104
- /** Used by `wstack models refresh` to expose where the cache lives. */
105
- cacheLocation(): string;
106
- }
107
-
108
- export { DefaultModelsRegistry as D, type DefaultModelsRegistryOptions as a, classifyFamily as c };