@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.
- package/dist/{agent-subagent-runner-PoqNKiR4.d.ts → agent-subagent-runner-DyOSK2Wy.d.ts} +39 -8
- package/dist/{compactor-U3agvUIG.d.ts → compactor-BxddyCFu.d.ts} +1 -1
- package/dist/{config-Cr3312zc.d.ts → config-CN-vdDEI.d.ts} +82 -2
- package/dist/coordination/index.d.ts +203 -20
- package/dist/coordination/index.js +981 -52
- package/dist/coordination/index.js.map +1 -1
- package/dist/defaults/index.d.ts +26 -30
- package/dist/defaults/index.js +382 -30
- package/dist/defaults/index.js.map +1 -1
- package/dist/{events-Bs2fmldo.d.ts → events-C5hLU0AT.d.ts} +38 -2
- package/dist/execution/index.d.ts +16 -16
- package/dist/execution/index.js +161 -18
- package/dist/execution/index.js.map +1 -1
- package/dist/execution/prompt-enhancer.d.ts +1 -1
- package/dist/execution/prompt-enhancer.js +12 -3
- package/dist/execution/prompt-enhancer.js.map +1 -1
- package/dist/extension/index.d.ts +6 -6
- package/dist/{global-mailbox-Ct7IorLJ.d.ts → global-mailbox-CHM1QkCi.d.ts} +5 -2
- package/dist/{goal-store-C4F6DjC0.d.ts → goal-store-BLGZq16t.d.ts} +1 -1
- package/dist/hq/index.d.ts +6 -6
- package/dist/hq/index.js +35 -13
- package/dist/hq/index.js.map +1 -1
- package/dist/{index-nP09-oP2.d.ts → index-BEFWNZYs.d.ts} +1 -2
- package/dist/{index-kidebiDh.d.ts → index-C1E-_71T.d.ts} +6 -6
- package/dist/index.d.ts +44 -48
- package/dist/index.js +14855 -13944
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/index.d.ts +60 -8
- package/dist/infrastructure/index.js.map +1 -1
- package/dist/kernel/index.d.ts +11 -11
- package/dist/kernel/index.js.map +1 -1
- package/dist/{mcp-servers-D910X5_r.d.ts → mcp-servers-EKRAcJDi.d.ts} +97 -4
- package/dist/models/index.d.ts +4 -5
- package/dist/models/index.js +22 -5
- package/dist/models/index.js.map +1 -1
- package/dist/{multi-agent-coordinator-CieyUoEL.d.ts → multi-agent-coordinator-IpHCuHUa.d.ts} +29 -1
- package/dist/{null-fleet-bus-DkdmZJ_W.d.ts → null-fleet-bus-ZBkKGR9j.d.ts} +105 -7
- package/dist/observability/index.d.ts +3 -3
- package/dist/{tool-executor-SiE1wlZo.d.ts → parallel-eternal-engine-Cc2CNgmv.d.ts} +6 -202
- package/dist/path-resolver-CMS5307d.d.ts +13 -0
- package/dist/{permission-Dx6dIqS2.d.ts → permission-B6YAtNFz.d.ts} +1 -1
- package/dist/{pipeline-BwAP21_4.d.ts → pipeline-E7_jqGyV.d.ts} +2 -2
- package/dist/{provider-model-resolve-CwQNZWt_.d.ts → provider-model-resolve-KgIdiEQ6.d.ts} +118 -5
- package/dist/{provider-runner-CYHFImzV.d.ts → provider-runner-DxWXNHL1.d.ts} +3 -3
- package/dist/{retry-policy-D4feSLk3.d.ts → retry-policy-V67lBOJz.d.ts} +2 -2
- package/dist/sdd/index.d.ts +9 -9
- package/dist/sdd/index.js +94 -10
- package/dist/sdd/index.js.map +1 -1
- package/dist/{permission-policy-C8vJcnX5.d.ts → secret-vault-D7jeyXUQ.d.ts} +119 -3
- package/dist/security/index.d.ts +5 -6
- package/dist/security/index.js +4 -1
- package/dist/security/index.js.map +1 -1
- package/dist/{selector-Dy-MzKp1.d.ts → selector-Bx2HgUkU.d.ts} +1 -1
- package/dist/{session-event-bridge-CqdiGnfU.d.ts → session-event-bridge-vA2fLV58.d.ts} +1 -1
- package/dist/{session-reader-Hk0WbNm9.d.ts → session-reader-B-Fi9L6I.d.ts} +1 -1
- package/dist/session-registry-Dvg7i_IA.d.ts +129 -0
- package/dist/storage/index.d.ts +71 -142
- package/dist/storage/index.js +161 -13
- package/dist/storage/index.js.map +1 -1
- package/dist/{todos-checkpoint-Bk2uP7Ex.d.ts → todos-checkpoint-B1QVkoa8.d.ts} +23 -5
- package/dist/{tool-BkOgs_KL.d.ts → tool-LVSLiE1s.d.ts} +18 -4
- package/dist/{strategy-compactor-CQwhbErd.d.ts → tool-executor-BWtYwuPI.d.ts} +210 -12
- package/dist/tools/index.d.ts +2 -2
- package/dist/tools/index.js.map +1 -1
- package/dist/types/index.d.ts +17 -41
- package/dist/types/index.js +182 -5085
- package/dist/types/index.js.map +1 -1
- package/dist/utils/index.d.ts +3 -3
- package/dist/utils/index.js +6 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/{worktree-manager-BjOFF6bt.d.ts → worktree-manager-C6CIilTT.d.ts} +1 -1
- package/dist/{wstack-paths-CMl_cYgq.d.ts → wstack-paths-C3K40Qst.d.ts} +2 -0
- package/instructions/agents/shadow-agent.md +23 -84
- package/instructions/coordination/director-preamble.md +12 -3
- package/instructions/coordination/subagent-baseline.md +39 -46
- package/instructions/leader-after-task.md +10 -28
- package/instructions/llm/llm-selector.md +1 -2
- package/instructions/modes/brief-system.md +7 -33
- package/instructions/modes/brief.md +5 -20
- package/instructions/modes/teach-system.md +12 -72
- package/instructions/modes/teach.md +12 -49
- package/instructions/sections/tool/commit-hygiene.md +5 -5
- package/instructions/sections/tool/context-management-full.md +6 -6
- package/instructions/sections/tool/delegation-compact.md +1 -1
- package/instructions/sections/tool/delegation-full.md +19 -23
- package/instructions/sections/tool/mailbox-full.md +11 -31
- package/instructions/sections/tool/mcp-full-control.md +5 -7
- package/instructions/sections/tool/mcp-full-use.md +7 -7
- package/instructions/system.md +22 -38
- package/package.json +1 -29
- package/dist/agent-bridge-DXC6QDJ4.d.ts +0 -35
- package/dist/logger-D3lV0cUZ.d.ts +0 -101
- package/dist/models-registry-CLkoOcHk.d.ts +0 -108
- package/dist/path-resolver-XfZ9eLxG.d.ts +0 -67
- 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
|
|
6
|
-
- **Scope to what you changed**: pass an explicit `files` list to the `git` tool so the commit contains only
|
|
7
|
-
- **Read `git status` first
|
|
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
|
|
9
|
-
-
|
|
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
|
|
3
|
+
When the conversation grows long, use the `context_manager` tool proactively — do not wait to be told:
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
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
|
|
10
|
+
Never restate bulk content: when you summarize a file, keep the summary and let go of the full text.
|
|
@@ -1,39 +1,35 @@
|
|
|
1
1
|
## Delegation
|
|
2
2
|
|
|
3
|
-
|
|
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**:
|
|
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
|
|
7
|
+
- **You'd switch hats mid-turn**: delegate the security pass instead of stopping a code fix.
|
|
9
8
|
|
|
10
|
-
|
|
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
|
-
|
|
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
|
-
|
|
23
|
+
For fleet-wide coverage, fan out: `glob` the target files yourself first, then fire one `delegate` per chunk of 5–10 files in parallel.
|
|
22
24
|
|
|
23
25
|
### Reading the result
|
|
24
26
|
|
|
25
|
-
`
|
|
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
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
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
|
|
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.
|
|
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>` (
|
|
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.
|
|
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
|
-
|
|
13
|
+
### Sending & discovery
|
|
14
14
|
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
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**:
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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>" })
|
|
8
|
+
4. `mcp_control({ action: "deactivate", server: "<name>" })` — unregister when done
|
|
11
9
|
|
|
12
|
-
Activation/deactivation is ephemeral (no config writes) and
|
|
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
|
|
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
|
|
5
|
+
**Preferred approach** — one-shot meta-tool:
|
|
6
6
|
|
|
7
7
|
`mcp_use({ server: "<name>", tool: "<bare-tool>", input: { ... } })`
|
|
8
8
|
|
|
9
|
-
|
|
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" })
|
|
14
|
-
2. `mcp_control({ action: "activate", server: "<name>" })
|
|
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>" })
|
|
16
|
+
4. `mcp_control({ action: "deactivate", server: "<name>" })` — clean up
|
|
17
17
|
|
|
18
|
-
Activation/deactivation is ephemeral (no config writes) and
|
|
18
|
+
Activation/deactivation is ephemeral (no config writes) and affects only tool visibility, not the server connection.
|
package/instructions/system.md
CHANGED
|
@@ -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
|
|
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
|
|
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.**
|
|
10
|
-
2. **Prefer surgical edits over rewrites.**
|
|
11
|
-
3. **
|
|
12
|
-
4. **Be honest about limits.** If you don't know, say so.
|
|
13
|
-
5. **Be concise
|
|
14
|
-
6. **
|
|
15
|
-
7. **
|
|
16
|
-
8. **
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
- **
|
|
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.
|
|
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 };
|