@wrongstack/core 0.299.0 → 0.301.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/chronicle/index.d.ts +2 -0
- package/dist/chronicle/index.js +297 -10
- package/dist/chronicle/project-server.js +253 -15
- package/dist/chronicle/sqlite-compaction.d.ts +20 -0
- package/dist/chronicle/sqlite-journal.d.ts +57 -0
- package/dist/coordination/agents/capability-manifest.d.ts +7 -0
- package/dist/coordination/agents/index.d.ts +3 -2
- package/dist/coordination/agents/index.js +818 -570
- package/dist/coordination/agents/project-agent-identity.d.ts +6 -6
- package/dist/coordination/agents/role-skills.d.ts +1 -1
- package/dist/coordination/agents/types.d.ts +6 -0
- package/dist/coordination/director.d.ts +10 -2
- package/dist/coordination/fleet-manager.d.ts +48 -3
- package/dist/coordination/ifleet-manager.d.ts +2 -0
- package/dist/coordination/index.js +6880 -6440
- package/dist/coordination/mail-tools.d.ts +3 -3
- package/dist/coordination/mailbox-project-server.js +3 -4
- package/dist/coordination/mailbox-types.d.ts +6 -0
- package/dist/coordination/multi-agent-coordinator.d.ts +1 -0
- package/dist/core/agent-response.d.ts +5 -1
- package/dist/core/agent-tools.d.ts +3 -0
- package/dist/core/context.d.ts +20 -0
- package/dist/core/fallback-model.d.ts +48 -0
- package/dist/core/index.d.ts +11 -9
- package/dist/core/index.js +1119 -310
- package/dist/core/instruction-template.d.ts +83 -0
- package/dist/core/next-steps-slot.d.ts +88 -0
- package/dist/core/system-prompt-blocks.d.ts +10 -1
- package/dist/core/system-prompt-builder.d.ts +40 -4
- package/dist/core/system-prompt-memory-skills.d.ts +1 -0
- package/dist/core/system-prompt-skill-bodies.d.ts +3 -3
- package/dist/defaults/index.js +9805 -8767
- package/dist/design/index.js +11 -3
- package/dist/execution/auto-compaction-middleware.d.ts +17 -0
- package/dist/execution/autonomy-brain.d.ts +15 -2
- package/dist/execution/brain-runtime.d.ts +3 -1
- package/dist/execution/compaction-core.d.ts +41 -2
- package/dist/execution/council-brain.d.ts +47 -1
- package/dist/execution/council-orchestrator.d.ts +25 -6
- package/dist/execution/council-prompts.d.ts +12 -1
- package/dist/execution/index.d.ts +11 -10
- package/dist/execution/index.js +10507 -9189
- package/dist/execution/tool-executor.d.ts +4 -1
- package/dist/execution/topic-shift-advisor.d.ts +53 -0
- package/dist/extension/index.js +8 -2
- package/dist/extension/registry.d.ts +8 -1
- package/dist/fleet-notifier.d.ts +9 -2
- package/dist/goal/index.js +11 -3
- package/dist/hooks/index.js +50 -13
- package/dist/hooks/runner.d.ts +12 -1
- package/dist/hq/index.js +59 -21
- package/dist/hq/protocol/fleet.d.ts +20 -0
- package/dist/hq/protocol.js +10 -0
- package/dist/hq/publisher.d.ts +21 -3
- package/dist/index.d.ts +22 -20
- package/dist/index.js +12211 -8572
- package/dist/infrastructure/index.js +108 -21
- package/dist/kernel/events/brain-events.d.ts +9 -0
- package/dist/kernel/events/provider-events.d.ts +42 -1
- package/dist/kernel/events/session-events.d.ts +13 -0
- package/dist/kernel/events/tool-events.d.ts +3 -3
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +18 -1
- package/dist/models/provider-credentials.d.ts +54 -0
- package/dist/plugin/api.d.ts +6 -0
- package/dist/plugin/config.d.ts +55 -0
- package/dist/plugin/index.d.ts +2 -1
- package/dist/plugin/index.js +2179 -544
- package/dist/plugins/auto-review-plugin.d.ts +3 -0
- package/dist/plugins/cloud-config-sync-plugin.d.ts +22 -0
- package/dist/plugins/review-claim-registry.d.ts +23 -8
- package/dist/plugins/review-types.d.ts +2 -0
- package/dist/registry/index.js +109 -74
- package/dist/registry/tool-registry.d.ts +15 -0
- package/dist/security/capabilities.d.ts +2 -0
- package/dist/security/index.d.ts +2 -2
- package/dist/security/index.js +166 -44
- package/dist/security/permission-helpers.d.ts +23 -6
- package/dist/security/permission-policy.d.ts +16 -0
- package/dist/security/readonly-permission-policy.d.ts +20 -0
- package/dist/security/totp.d.ts +14 -0
- package/dist/session-registry-atomic-file.d.ts +32 -5
- package/dist/skills/frontmatter.d.ts +6 -0
- package/dist/skills/index.js +22 -5
- package/dist/storage/cloud-config-sync/sanitize.d.ts +54 -0
- package/dist/storage/cloud-config-sync.d.ts +87 -0
- package/dist/storage/director-state.d.ts +7 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +887 -74
- package/dist/tools/fallback-system-config-view-tool.d.ts +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/index.js +898 -335
- package/dist/tools/one-shot-llm-tool.d.ts +1 -0
- package/dist/tools/plugin-manager.d.ts +27 -0
- package/dist/types/config/mcp-features.d.ts +18 -11
- package/dist/types/config/root.d.ts +8 -1
- package/dist/types/config/runtime.d.ts +20 -6
- package/dist/types/config/skills-fleet-brain.d.ts +12 -4
- package/dist/types/config/tools.d.ts +16 -0
- package/dist/types/context-window.d.ts +1 -0
- package/dist/types/council.d.ts +11 -0
- package/dist/types/hooks.d.ts +14 -0
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.js +1 -0
- package/dist/types/multi-agent.d.ts +12 -0
- package/dist/types/one-shot-llm.d.ts +25 -0
- package/dist/types/plugin.d.ts +28 -0
- package/dist/types/provider.d.ts +16 -0
- package/dist/types/runtime-capability-manifest.d.ts +168 -0
- package/dist/types/skill.d.ts +5 -0
- package/dist/types/system-prompt.d.ts +3 -1
- package/dist/types/tool-executor.d.ts +8 -1
- package/dist/utils/context-breakdown.d.ts +8 -2
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js +141 -31
- package/dist/utils/regex-guard.d.ts +16 -2
- package/dist/utils/sage-output-block.d.ts +7 -10
- package/dist/utils/wstack-paths.d.ts +11 -3
- package/dist/worktree/index.js +4 -4
- package/instructions/agents/browser.md +1 -4
- package/instructions/agents/e2e.md +17 -15
- package/instructions/agents/ios.md +3 -3
- package/instructions/agents/search.md +1 -1
- package/instructions/autonomy/goal-preamble.md +4 -4
- package/instructions/coordination/director-preamble.md +2 -3
- package/instructions/coordination/subagent-baseline.md +3 -1
- package/instructions/leader-after-task.md +12 -0
- package/instructions/llm/chimera-review.md +1 -1
- package/instructions/modes/audit-lite.md +1 -1
- package/instructions/sections/tool/common-patterns.md +18 -2
- package/instructions/sections/tool/mailbox-compact.md +1 -1
- package/instructions/sections/tool/mailbox-full.md +1 -1
- package/instructions/system-lite.md +91 -3
- package/instructions/system-pro.md +296 -102
- package/instructions/system.md +248 -92
- package/package.json +3 -3
- package/skills/api-design/SKILL.md +3 -0
- package/skills/audit-log/SKILL.md +2 -0
- package/skills/auto-review/SKILL.md +6 -1
- package/skills/bug-hunter/SKILL.md +4 -1
- package/skills/chimera/SKILL.md +3 -0
- package/skills/data-governance/SKILL.md +3 -0
- package/skills/design-system/SKILL.md +5 -2
- package/skills/docker-deploy/SKILL.md +2 -0
- package/skills/git-flow/SKILL.md +2 -0
- package/skills/mailbox-bridge/SKILL.md +3 -0
- package/skills/mnemosyne/SKILL.md +2 -0
- package/skills/multi-agent/SKILL.md +4 -1
- package/skills/node-modern/SKILL.md +4 -1
- package/skills/observability/SKILL.md +3 -0
- package/skills/output-standards/SKILL.md +2 -0
- package/skills/plugin-author/SKILL.md +4 -1
- package/skills/prompt-engineering/SKILL.md +3 -1
- package/skills/react-modern/SKILL.md +6 -3
- package/skills/refactor-planner/SKILL.md +2 -0
- package/skills/research-web/SKILL.md +3 -0
- package/skills/sdd/SKILL.md +3 -1
- package/skills/security-scanner/SKILL.md +3 -0
- package/skills/skill-creator/SKILL.md +2 -0
- package/skills/tech-stack/SKILL.md +3 -0
- package/skills/testing/SKILL.md +4 -1
- package/skills/typescript-strict/SKILL.md +4 -1
- package/skills/wrongstack-kanban/SKILL.md +6 -3
- package/skills/wrongstack-mailbox/SKILL.md +4 -1
- package/skills/wrongstack-mailbox-mcp/SKILL.md +10 -8
package/dist/types/skill.d.ts
CHANGED
|
@@ -19,6 +19,11 @@ export interface SkillManifest {
|
|
|
19
19
|
* grants nor restricts any tool.
|
|
20
20
|
*/
|
|
21
21
|
allowedTools?: string[] | undefined;
|
|
22
|
+
/** Stable WrongStack runtime capabilities required to activate this skill. */
|
|
23
|
+
requiredCapabilities?: string[] | undefined;
|
|
24
|
+
requiredTools?: string[] | undefined;
|
|
25
|
+
/** Optional capabilities; the skill must remain useful when these are absent. */
|
|
26
|
+
optionalCapabilities?: string[] | undefined;
|
|
22
27
|
path: string;
|
|
23
28
|
/**
|
|
24
29
|
* Discovery layer the skill came from. `claude-*`, `foreign`, and `extra` are
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import type { MailboxAgentStatus } from '../coordination/mailbox-types.js';
|
|
1
2
|
import type { TextBlock } from './blocks.js';
|
|
2
3
|
import type { Tool } from './tool.js';
|
|
3
|
-
import type { MailboxAgentStatus } from '../coordination/mailbox-types.js';
|
|
4
4
|
/** Model capabilities relevant to prompt composition. */
|
|
5
5
|
export interface ModelCapabilities {
|
|
6
6
|
maxContextTokens: number;
|
|
@@ -12,6 +12,8 @@ export interface BuildContext {
|
|
|
12
12
|
cwd: string;
|
|
13
13
|
projectRoot: string;
|
|
14
14
|
tools: Tool[];
|
|
15
|
+
/** Complete enabled catalog, including tools reachable only through lazy gateways. */
|
|
16
|
+
catalogTools?: Tool[] | undefined;
|
|
15
17
|
/** Provider id (e.g. "anthropic", "minimax-coding-plan"). */
|
|
16
18
|
provider?: string | undefined;
|
|
17
19
|
/** Model id (e.g. "configured-model", "MiniMax-M2.7"). */
|
|
@@ -102,6 +102,10 @@ export interface ToolConfirmPendingResult {
|
|
|
102
102
|
toolUseId: string;
|
|
103
103
|
toolName: string;
|
|
104
104
|
input: unknown;
|
|
105
|
+
preToolContext?: {
|
|
106
|
+
text: string;
|
|
107
|
+
contextAs: 'inline' | 'separate';
|
|
108
|
+
} | undefined;
|
|
105
109
|
suggestedPattern: string;
|
|
106
110
|
decisionSource?: import('./permission.js').PermissionDecision['source'] | undefined;
|
|
107
111
|
riskTier?: import('./tool.js').RiskTier | undefined;
|
|
@@ -139,7 +143,10 @@ export interface ToolExecutorLike {
|
|
|
139
143
|
* `bytes` from the running budget — no second `Buffer.byteLength`
|
|
140
144
|
* walk, and no `JSON.stringify` fallback for structured results.
|
|
141
145
|
*/
|
|
142
|
-
executeTool(tool: Tool, use: ToolUseBlock, ctx: import('../core/context.js').Context, budget: number
|
|
146
|
+
executeTool(tool: Tool, use: ToolUseBlock, ctx: import('../core/context.js').Context, budget: number, preToolContext?: {
|
|
147
|
+
text: string;
|
|
148
|
+
contextAs: 'inline' | 'separate';
|
|
149
|
+
}): Promise<{
|
|
143
150
|
block: ToolResultBlock;
|
|
144
151
|
bytes: number;
|
|
145
152
|
}>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type SystemBlockSource } from '../core/system-prompt-builder.js';
|
|
2
1
|
import type { Context } from '../core/context.js';
|
|
2
|
+
import { type SystemBlockSource } from '../core/system-prompt-builder.js';
|
|
3
3
|
/**
|
|
4
4
|
* Real, per-category token accounting for the live context window — the data
|
|
5
5
|
* behind an honest `/context` display. Every number is measured from the actual
|
|
@@ -25,10 +25,16 @@ export interface ContextBreakdown {
|
|
|
25
25
|
};
|
|
26
26
|
history: {
|
|
27
27
|
total: number;
|
|
28
|
-
/** User/assistant text
|
|
28
|
+
/** User/assistant/system text only. */
|
|
29
29
|
text: number;
|
|
30
|
+
/** Serialized tool_use arguments. Optional for backward-compatible UI snapshots. */
|
|
31
|
+
toolInputs?: number | undefined;
|
|
30
32
|
/** tool_result output content. */
|
|
31
33
|
toolResults: number;
|
|
34
|
+
/** Preserved provider reasoning/thinking blocks. */
|
|
35
|
+
thinking?: number | undefined;
|
|
36
|
+
/** Images and future/unknown content block kinds. */
|
|
37
|
+
other?: number | undefined;
|
|
32
38
|
messageCount: number;
|
|
33
39
|
};
|
|
34
40
|
volatile: {
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export { getPerfProfile, indexParallelBatchSize, isFrugalPerf, type PerfProfile,
|
|
|
32
32
|
export { isPidAlive } from './pid.js';
|
|
33
33
|
export * from './project-identity.js';
|
|
34
34
|
export { type ProjectWatchEvent, type ProjectWatchSubscription, watchProjectTree, } from './project-watch.js';
|
|
35
|
-
export { type CompileFail, type CompileResult, compileUserRegex } from './regex-guard.js';
|
|
35
|
+
export { capSubject, type CompileFail, type CompileResult, compileUserRegex, MAX_SUBJECT_LEN, } from './regex-guard.js';
|
|
36
36
|
export * from './safe-json.js';
|
|
37
37
|
export { sessionScopedPath } from './session-scoped-path.js';
|
|
38
38
|
export * from './sleep.js';
|
package/dist/utils/index.js
CHANGED
|
@@ -1655,6 +1655,25 @@ function resetCalibration(calibrationKey) {
|
|
|
1655
1655
|
_cals.delete(calibrationKey);
|
|
1656
1656
|
}
|
|
1657
1657
|
|
|
1658
|
+
// src/utils/todos-format.ts
|
|
1659
|
+
function formatTodosList(todos) {
|
|
1660
|
+
if (todos.length === 0) return "No todos.";
|
|
1661
|
+
const lines = [];
|
|
1662
|
+
const done = todos.filter((t) => t.status === "completed").length;
|
|
1663
|
+
lines.push(color.dim(`Todos (${done}/${todos.length} done):`));
|
|
1664
|
+
todos.forEach((t, i) => {
|
|
1665
|
+
const mark = t.status === "completed" ? color.green("[x]") : t.status === "in_progress" ? color.yellow("[~]") : color.dim("[ ]");
|
|
1666
|
+
const text = t.status === "in_progress" && t.activeForm ? t.activeForm : t.content;
|
|
1667
|
+
const label = t.status === "completed" ? color.dim(text) : text;
|
|
1668
|
+
lines.push(` ${color.dim(String(i + 1).padStart(2))}. ${mark} ${label}`);
|
|
1669
|
+
});
|
|
1670
|
+
return lines.join("\n");
|
|
1671
|
+
}
|
|
1672
|
+
function hasOpenTodos(todos) {
|
|
1673
|
+
if (!Array.isArray(todos) || todos.length === 0) return false;
|
|
1674
|
+
return todos.some((t) => t.status === "pending" || t.status === "in_progress");
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1658
1677
|
// src/core/agent-response.ts
|
|
1659
1678
|
var MAX_TODO_SNAPSHOT_ITEMS = 10;
|
|
1660
1679
|
var MAX_TODO_SNAPSHOT_CONTENT = 180;
|
|
@@ -1664,6 +1683,9 @@ function buildLiveNextStepsGateBlock(ctx) {
|
|
|
1664
1683
|
(todo) => todo.status === "pending" || todo.status === "in_progress"
|
|
1665
1684
|
);
|
|
1666
1685
|
if (openTodos.length === 0) {
|
|
1686
|
+
const toolRoute = ctx.tools?.some((t) => t.name === "nextsteps") ? [
|
|
1687
|
+
"Calling the `nextsteps` tool with the same items satisfies branch 1 as well; if you both call it and write the block, the block wins."
|
|
1688
|
+
] : [];
|
|
1667
1689
|
return {
|
|
1668
1690
|
type: "text",
|
|
1669
1691
|
text: [
|
|
@@ -1672,6 +1694,7 @@ function buildLiveNextStepsGateBlock(ctx) {
|
|
|
1672
1694
|
"On the final response, you MUST take exactly one branch:",
|
|
1673
1695
|
"1. If at least one genuinely useful follow-on action exists, include a balanced <nextsteps> block containing 1-4 exact prompt messages that can be submitted back to you through the current TUI or WebUI input.",
|
|
1674
1696
|
"Every item must ask the agent to perform work. Never put a human-only chore or an instruction addressed to the user inside <nextsteps>; natural-language agent-directed imperatives are valid and need not be shell commands.",
|
|
1697
|
+
...toolRoute,
|
|
1675
1698
|
"2. If no useful follow-on action truly exists, omit <nextsteps> and explicitly tell the user in normal prose that no further steps are needed for this task.",
|
|
1676
1699
|
"Silently omitting both is invalid. Do not decide by chance, tone, or response length, and do not invent filler suggestions.",
|
|
1677
1700
|
"[/nextsteps_gate]"
|
|
@@ -1765,7 +1788,10 @@ function getContextBreakdown(ctx) {
|
|
|
1765
1788
|
}
|
|
1766
1789
|
}
|
|
1767
1790
|
let histText = 0;
|
|
1791
|
+
let histToolInputs = 0;
|
|
1768
1792
|
let histToolResults = 0;
|
|
1793
|
+
let histThinking = 0;
|
|
1794
|
+
let histOther = 0;
|
|
1769
1795
|
for (const msg of ctx.messages) {
|
|
1770
1796
|
if (typeof msg.content === "string") {
|
|
1771
1797
|
histText += estimateTextTokens(msg.content);
|
|
@@ -1777,16 +1803,16 @@ function getContextBreakdown(ctx) {
|
|
|
1777
1803
|
histText += estimateTextTokens(b.text);
|
|
1778
1804
|
break;
|
|
1779
1805
|
case "tool_use":
|
|
1780
|
-
|
|
1806
|
+
histToolInputs += estimateToolInputTokens(b.input);
|
|
1781
1807
|
break;
|
|
1782
1808
|
case "tool_result":
|
|
1783
1809
|
histToolResults += estimateToolResultTokens(b.content);
|
|
1784
1810
|
break;
|
|
1785
1811
|
case "thinking":
|
|
1786
|
-
|
|
1812
|
+
histThinking += estimateTextTokens(JSON.stringify(b));
|
|
1787
1813
|
break;
|
|
1788
1814
|
default:
|
|
1789
|
-
|
|
1815
|
+
histOther += estimateTextTokens(JSON.stringify(b));
|
|
1790
1816
|
}
|
|
1791
1817
|
}
|
|
1792
1818
|
}
|
|
@@ -1800,7 +1826,7 @@ function getContextBreakdown(ctx) {
|
|
|
1800
1826
|
const ledger = ledgerBlock ? estimateTextTokens(ledgerBlock.text) : 0;
|
|
1801
1827
|
const nextsteps = nextstepsBlock ? estimateTextTokens(nextstepsBlock.text) : 0;
|
|
1802
1828
|
const toolsTotal = toolsBuiltin + toolsMcp;
|
|
1803
|
-
const historyTotal = histText + histToolResults;
|
|
1829
|
+
const historyTotal = histText + histToolInputs + histToolResults + histThinking + histOther;
|
|
1804
1830
|
const volatileTotal = ledger + nextsteps;
|
|
1805
1831
|
const total = systemTotal + toolsTotal + historyTotal + volatileTotal;
|
|
1806
1832
|
const effectiveMaxContext = resolveEffectiveMaxContext(ctx);
|
|
@@ -1816,7 +1842,10 @@ function getContextBreakdown(ctx) {
|
|
|
1816
1842
|
history: {
|
|
1817
1843
|
total: historyTotal,
|
|
1818
1844
|
text: histText,
|
|
1845
|
+
toolInputs: histToolInputs,
|
|
1819
1846
|
toolResults: histToolResults,
|
|
1847
|
+
thinking: histThinking,
|
|
1848
|
+
other: histOther,
|
|
1820
1849
|
messageCount: ctx.messages.length
|
|
1821
1850
|
},
|
|
1822
1851
|
volatile: { ledger, nextsteps, total: volatileTotal },
|
|
@@ -2453,6 +2482,9 @@ function canonicalProjectRoot(absRoot) {
|
|
|
2453
2482
|
const commonDirFile = path3.join(gitDir, "commondir");
|
|
2454
2483
|
if (!fs3.statSync(commonDirFile).isFile()) return checkoutRoot;
|
|
2455
2484
|
const commonDir = path3.resolve(gitDir, fs3.readFileSync(commonDirFile, "utf8").trim());
|
|
2485
|
+
const worktreesDir = path3.dirname(gitDir);
|
|
2486
|
+
if (path3.basename(worktreesDir).toLowerCase() !== "worktrees") return checkoutRoot;
|
|
2487
|
+
if (path3.resolve(worktreesDir, "..") !== commonDir) return checkoutRoot;
|
|
2456
2488
|
if (path3.basename(commonDir).toLowerCase() !== ".git") return checkoutRoot;
|
|
2457
2489
|
return path3.dirname(commonDir);
|
|
2458
2490
|
} catch {
|
|
@@ -2475,7 +2507,7 @@ function safeProfileName(name) {
|
|
|
2475
2507
|
const safe = (name ?? "").replace(/[/\\:]/g, "_").replace(/\.\./g, "_").trim();
|
|
2476
2508
|
return safe || "default";
|
|
2477
2509
|
}
|
|
2478
|
-
function
|
|
2510
|
+
function bootstrapProfileName(globalRoot) {
|
|
2479
2511
|
try {
|
|
2480
2512
|
const parsed = JSON.parse(fs3.readFileSync(path3.join(globalRoot, "config.json"), "utf8"));
|
|
2481
2513
|
return safeProfileName(
|
|
@@ -2493,7 +2525,7 @@ function wstackGlobalRoot() {
|
|
|
2493
2525
|
function resolveWstackPaths(opts) {
|
|
2494
2526
|
const globalRoot = opts.globalRoot ?? (opts.userHome ? path3.join(opts.userHome, ".wrongstack") : wstackGlobalRoot());
|
|
2495
2527
|
const homeDir = opts.userHome ?? os.homedir();
|
|
2496
|
-
const profileName = safeProfileName(opts.profileName ??
|
|
2528
|
+
const profileName = safeProfileName(opts.profileName ?? bootstrapProfileName(globalRoot));
|
|
2497
2529
|
const profileDir = path3.join(globalRoot, "profiles", profileName);
|
|
2498
2530
|
const hash = projectHash(opts.projectRoot);
|
|
2499
2531
|
const slug = projectSlug(opts.projectRoot);
|
|
@@ -2563,7 +2595,12 @@ function resolveWstackPaths(opts) {
|
|
|
2563
2595
|
projectRequirementIntakes: path3.join(projectDir, "requirement-intakes"),
|
|
2564
2596
|
syncConfig: path3.join(profileDir, "sync.json"),
|
|
2565
2597
|
configHistoryDir: path3.join(globalRoot, "config-history"),
|
|
2566
|
-
projectStatus: (
|
|
2598
|
+
projectStatus: (statusProjectSlug) => {
|
|
2599
|
+
if (!/^[a-z0-9](?:[a-z0-9-]{0,39})-[a-f0-9]{6}$/.test(statusProjectSlug)) {
|
|
2600
|
+
throw new Error(`Invalid project slug: ${statusProjectSlug}`);
|
|
2601
|
+
}
|
|
2602
|
+
return path3.join(globalRoot, "projects", statusProjectSlug, "status.json");
|
|
2603
|
+
}
|
|
2567
2604
|
};
|
|
2568
2605
|
}
|
|
2569
2606
|
|
|
@@ -4068,13 +4105,93 @@ function watchProjectTree(root, listener, opts) {
|
|
|
4068
4105
|
}
|
|
4069
4106
|
|
|
4070
4107
|
// src/utils/regex-guard.ts
|
|
4071
|
-
var MAX_PATTERN_LEN =
|
|
4108
|
+
var MAX_PATTERN_LEN = 256;
|
|
4072
4109
|
var DANGEROUS_PATTERNS = [
|
|
4110
|
+
// (a+)+, (.*)+, etc — nested quantifier on a group with internal quantifier
|
|
4073
4111
|
/(\([^)]*[+*][^)]*\))[+*]/,
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4112
|
+
/(\(\?:[^)]*[+*][^)]*\))[+*]/,
|
|
4113
|
+
// Adjacent quantifiers: a++ a*+
|
|
4114
|
+
/[+*]{2,}/,
|
|
4115
|
+
// Quantifier on alternation with length 2+
|
|
4116
|
+
/\([^|)]+\|[^)]+\)[+*][+*]/,
|
|
4117
|
+
// Greedy quantifier inside lookahead/lookbehind — (?!.*a+)
|
|
4118
|
+
/[([][^)\]]*[+*][^)\]]*[)\]][^)]*\?\??/
|
|
4077
4119
|
];
|
|
4120
|
+
function hasAmbiguousQuantifiedAlternation(pattern) {
|
|
4121
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
4122
|
+
if (pattern[i] !== "(") continue;
|
|
4123
|
+
if (i > 0 && pattern[i - 1] === "\\") continue;
|
|
4124
|
+
let depth = 0;
|
|
4125
|
+
let inClass = false;
|
|
4126
|
+
let j = i;
|
|
4127
|
+
for (; j < pattern.length; j++) {
|
|
4128
|
+
const ch = pattern[j];
|
|
4129
|
+
if (ch === "\\") {
|
|
4130
|
+
j++;
|
|
4131
|
+
continue;
|
|
4132
|
+
}
|
|
4133
|
+
if (inClass) {
|
|
4134
|
+
if (ch === "]") inClass = false;
|
|
4135
|
+
continue;
|
|
4136
|
+
}
|
|
4137
|
+
if (ch === "[") {
|
|
4138
|
+
inClass = true;
|
|
4139
|
+
continue;
|
|
4140
|
+
}
|
|
4141
|
+
if (ch === "(") depth++;
|
|
4142
|
+
else if (ch === ")") {
|
|
4143
|
+
depth--;
|
|
4144
|
+
if (depth === 0) break;
|
|
4145
|
+
}
|
|
4146
|
+
}
|
|
4147
|
+
if (j >= pattern.length) return false;
|
|
4148
|
+
const next = pattern[j + 1];
|
|
4149
|
+
if (next !== "+" && next !== "*" && next !== "{") continue;
|
|
4150
|
+
let inner = pattern.slice(i + 1, j);
|
|
4151
|
+
inner = inner.replace(/^\?(?::|<?[=!])/u, "");
|
|
4152
|
+
const branches = [];
|
|
4153
|
+
let current = "";
|
|
4154
|
+
let d = 0;
|
|
4155
|
+
let cls = false;
|
|
4156
|
+
for (let k = 0; k < inner.length; k++) {
|
|
4157
|
+
const ch = inner[k];
|
|
4158
|
+
if (ch === "\\") {
|
|
4159
|
+
current += ch + (inner[k + 1] ?? "");
|
|
4160
|
+
k++;
|
|
4161
|
+
continue;
|
|
4162
|
+
}
|
|
4163
|
+
if (cls) {
|
|
4164
|
+
if (ch === "]") cls = false;
|
|
4165
|
+
current += ch;
|
|
4166
|
+
continue;
|
|
4167
|
+
}
|
|
4168
|
+
if (ch === "[") {
|
|
4169
|
+
cls = true;
|
|
4170
|
+
current += ch;
|
|
4171
|
+
continue;
|
|
4172
|
+
}
|
|
4173
|
+
if (ch === "(") d++;
|
|
4174
|
+
if (ch === ")") d--;
|
|
4175
|
+
if (ch === "|" && d === 0) {
|
|
4176
|
+
branches.push(current);
|
|
4177
|
+
current = "";
|
|
4178
|
+
continue;
|
|
4179
|
+
}
|
|
4180
|
+
current += ch;
|
|
4181
|
+
}
|
|
4182
|
+
branches.push(current);
|
|
4183
|
+
if (branches.length < 2) continue;
|
|
4184
|
+
for (let a = 0; a < branches.length; a++) {
|
|
4185
|
+
for (let b = a + 1; b < branches.length; b++) {
|
|
4186
|
+
const x = branches[a];
|
|
4187
|
+
const y = branches[b];
|
|
4188
|
+
if (x === "" || y === "") return true;
|
|
4189
|
+
if (x === y || x.startsWith(y) || y.startsWith(x)) return true;
|
|
4190
|
+
}
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
return false;
|
|
4194
|
+
}
|
|
4078
4195
|
function compileUserRegex(pattern, flags) {
|
|
4079
4196
|
if (typeof pattern !== "string") {
|
|
4080
4197
|
return { ok: false, reason: "pattern must be a string" };
|
|
@@ -4093,6 +4210,12 @@ function compileUserRegex(pattern, flags) {
|
|
|
4093
4210
|
};
|
|
4094
4211
|
}
|
|
4095
4212
|
}
|
|
4213
|
+
if (hasAmbiguousQuantifiedAlternation(pattern)) {
|
|
4214
|
+
return {
|
|
4215
|
+
ok: false,
|
|
4216
|
+
reason: "pattern quantifies an alternation with overlapping branches \u2014 rewrite so no two branches can match the same text"
|
|
4217
|
+
};
|
|
4218
|
+
}
|
|
4096
4219
|
try {
|
|
4097
4220
|
return { ok: true, regex: new RegExp(pattern, flags) };
|
|
4098
4221
|
} catch (err) {
|
|
@@ -4102,6 +4225,10 @@ function compileUserRegex(pattern, flags) {
|
|
|
4102
4225
|
};
|
|
4103
4226
|
}
|
|
4104
4227
|
}
|
|
4228
|
+
var MAX_SUBJECT_LEN = 64 * 1024;
|
|
4229
|
+
function capSubject(line) {
|
|
4230
|
+
return line.length > MAX_SUBJECT_LEN ? line.slice(0, MAX_SUBJECT_LEN) : line;
|
|
4231
|
+
}
|
|
4105
4232
|
|
|
4106
4233
|
// src/utils/safe-json.ts
|
|
4107
4234
|
function safeParse(input, maxBytes = 5e6) {
|
|
@@ -4418,25 +4545,6 @@ function formatTaskList(tasks) {
|
|
|
4418
4545
|
return lines.join("\n");
|
|
4419
4546
|
}
|
|
4420
4547
|
|
|
4421
|
-
// src/utils/todos-format.ts
|
|
4422
|
-
function formatTodosList(todos) {
|
|
4423
|
-
if (todos.length === 0) return "No todos.";
|
|
4424
|
-
const lines = [];
|
|
4425
|
-
const done = todos.filter((t) => t.status === "completed").length;
|
|
4426
|
-
lines.push(color.dim(`Todos (${done}/${todos.length} done):`));
|
|
4427
|
-
todos.forEach((t, i) => {
|
|
4428
|
-
const mark = t.status === "completed" ? color.green("[x]") : t.status === "in_progress" ? color.yellow("[~]") : color.dim("[ ]");
|
|
4429
|
-
const text = t.status === "in_progress" && t.activeForm ? t.activeForm : t.content;
|
|
4430
|
-
const label = t.status === "completed" ? color.dim(text) : text;
|
|
4431
|
-
lines.push(` ${color.dim(String(i + 1).padStart(2))}. ${mark} ${label}`);
|
|
4432
|
-
});
|
|
4433
|
-
return lines.join("\n");
|
|
4434
|
-
}
|
|
4435
|
-
function hasOpenTodos(todos) {
|
|
4436
|
-
if (!Array.isArray(todos) || todos.length === 0) return false;
|
|
4437
|
-
return todos.some((t) => t.status === "pending" || t.status === "in_progress");
|
|
4438
|
-
}
|
|
4439
|
-
|
|
4440
4548
|
// src/utils/tool-description-mode.ts
|
|
4441
4549
|
var DEFAULT_TOOL_DESCRIPTION_MODE = "extend";
|
|
4442
4550
|
var ORIGINAL_TOOL_DESCRIPTION = /* @__PURE__ */ Symbol.for("wrongstack.tool.originalDescription");
|
|
@@ -5455,6 +5563,7 @@ export {
|
|
|
5455
5563
|
MAX_INCOMING_IMAGES,
|
|
5456
5564
|
MAX_INCOMING_IMAGE_BYTES,
|
|
5457
5565
|
MAX_PATH_SEGMENT_LENGTH,
|
|
5566
|
+
MAX_SUBJECT_LEN,
|
|
5458
5567
|
PROJECT_IDENTITY_RELATIVE_PATH,
|
|
5459
5568
|
PROJECT_IDENTITY_VERSION,
|
|
5460
5569
|
PROJECT_ID_PREFIX,
|
|
@@ -5463,7 +5572,6 @@ export {
|
|
|
5463
5572
|
TerminalLifecycle,
|
|
5464
5573
|
WIRE_TOOL_NAME_MAX_LENGTH,
|
|
5465
5574
|
WIRE_TOOL_NAME_PATTERN,
|
|
5466
|
-
activeProfileName,
|
|
5467
5575
|
applyToolDescriptionModeToTool,
|
|
5468
5576
|
applyToolDescriptionModes,
|
|
5469
5577
|
applyToolResultRenderModes,
|
|
@@ -5474,6 +5582,7 @@ export {
|
|
|
5474
5582
|
atomicWrite,
|
|
5475
5583
|
backupConfigFile,
|
|
5476
5584
|
base64DecodedBytes,
|
|
5585
|
+
bootstrapProfileName,
|
|
5477
5586
|
buildChildEnv,
|
|
5478
5587
|
buildCompletedWorkLedgerBlock,
|
|
5479
5588
|
buildContextEvidenceDigest,
|
|
@@ -5483,6 +5592,7 @@ export {
|
|
|
5483
5592
|
buildWin32CmdShimInvocation,
|
|
5484
5593
|
canonicalProjectRoot,
|
|
5485
5594
|
capSageLines,
|
|
5595
|
+
capSubject,
|
|
5486
5596
|
checkConnectivity,
|
|
5487
5597
|
checkUnixSocketPath,
|
|
5488
5598
|
coerceAgainstSchema,
|
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
* Compile a user-supplied regex with conservative bounds against ReDoS.
|
|
3
3
|
*
|
|
4
4
|
* Duplicated from @wrongstack/tools/_regex.ts to avoid a circular
|
|
5
|
-
* dependency (tools depends on core, not vice versa).
|
|
6
|
-
*
|
|
5
|
+
* dependency (tools depends on core, not vice versa). There is a THIRD copy —
|
|
6
|
+
* `@wrongstack/kanban/src/verification/safe-regex.ts` — which sits below both
|
|
7
|
+
* in the workspace DAG for the same reason. This header used to say "keep
|
|
8
|
+
* both copies in sync", unaware of the third, and this copy had drifted the
|
|
9
|
+
* furthest: 2 of the 5 heuristics, a 512-character cap instead of 256, and no
|
|
10
|
+
* subject cap at all. `packages/tools/tests/regex-guard-parity.test.ts` now
|
|
11
|
+
* holds all three to the same verdicts — change one, change all three.
|
|
7
12
|
*
|
|
8
13
|
* V8's regex engine is backtracking-based and cannot interrupt a
|
|
9
14
|
* synchronous match — a pattern like `(a+)+$` against a sufficiently
|
|
@@ -18,4 +23,13 @@ export interface CompileFail {
|
|
|
18
23
|
reason: string;
|
|
19
24
|
}
|
|
20
25
|
export declare function compileUserRegex(pattern: string, flags: string): CompileResult | CompileFail;
|
|
26
|
+
/**
|
|
27
|
+
* Truncate a subject line to a safe length for synchronous regex eval.
|
|
28
|
+
*
|
|
29
|
+
* The canonical copy has always shipped this; this one did not, so callers
|
|
30
|
+
* here bounded the pattern but never the SUBJECT — and a linear-time pattern
|
|
31
|
+
* over a multi-megabyte line is still a stall.
|
|
32
|
+
*/
|
|
33
|
+
export declare const MAX_SUBJECT_LEN: number;
|
|
34
|
+
export declare function capSubject(line: string): string;
|
|
21
35
|
//# sourceMappingURL=regex-guard.d.ts.map
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* sage-output-block —
|
|
2
|
+
* sage-output-block — legacy replay support for inline SAGE tool-result suffixes.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* `SageMemoryCard`).
|
|
4
|
+
* Current SAGE middleware stores retrievals in Context.memoryEvidence and the
|
|
5
|
+
* provider receives them as separate ephemeral system blocks. Older session
|
|
6
|
+
* logs may still contain a `--- SAGE: … (Memory Injector) ---` suffix inside a
|
|
7
|
+
* tool result, so replay surfaces retain this parser for compatibility.
|
|
9
8
|
*
|
|
10
9
|
* Surfaces used to recover the block by re-parsing the `tool.executed` event
|
|
11
10
|
* `output` string — which is a ~400-char preview. When a tool's own output was
|
|
@@ -14,7 +13,7 @@
|
|
|
14
13
|
* candidate, and the whole block fell through to the plain tool-output
|
|
15
14
|
* renderer. The result was raw `--- SAGE: … ---` text dumped into the chat.
|
|
16
15
|
*
|
|
17
|
-
*
|
|
16
|
+
* For those legacy payloads the split happens HERE, before any truncation:
|
|
18
17
|
* `tool.executed.output` carries tool text only and the block travels
|
|
19
18
|
* separately in `tool.executed.sage`. Surfaces that don't know about SAGE show
|
|
20
19
|
* clean tool output instead of leaking the block, and surfaces that do render
|
|
@@ -22,9 +21,7 @@
|
|
|
22
21
|
*
|
|
23
22
|
* The headings and the memory-line shape mirror
|
|
24
23
|
* `packages/tui/src/components/history/sage-output-format.ts` and
|
|
25
|
-
* `packages/webui/src/lib/sage-block.ts`.
|
|
26
|
-
* because they also parse *replayed* sessions, where the block is still inline
|
|
27
|
-
* in the persisted `tool_result` content. All three must agree.
|
|
24
|
+
* `packages/webui/src/lib/sage-block.ts`. All three must agree for old logs.
|
|
28
25
|
*/
|
|
29
26
|
export interface SageOutputSplit {
|
|
30
27
|
/** Tool result text with the SAGE block removed (trailing whitespace trimmed). */
|
|
@@ -130,8 +130,8 @@ export interface WstackPaths {
|
|
|
130
130
|
syncConfig: string;
|
|
131
131
|
/** ~/.wrongstack/config-history — timestamped backups on every config write */
|
|
132
132
|
configHistoryDir: string;
|
|
133
|
-
/** Function to get the status.json path for a project
|
|
134
|
-
projectStatus: (
|
|
133
|
+
/** Function to get the status.json path for a validated project slug. */
|
|
134
|
+
projectStatus: (projectSlug: string) => string;
|
|
135
135
|
}
|
|
136
136
|
/**
|
|
137
137
|
* Resolve the stable project identity root used by global WrongStack state.
|
|
@@ -167,8 +167,16 @@ export declare function safeProfileName(name: string | undefined): string;
|
|
|
167
167
|
/**
|
|
168
168
|
* Resolve the selected profile from ~/.wrongstack/config.json. The root file
|
|
169
169
|
* is bootstrap metadata only; a missing/corrupt bootstrap selects `default`.
|
|
170
|
+
*
|
|
171
|
+
* Named for its SOURCE, not its meaning. This used to be `activeProfileName`,
|
|
172
|
+
* the same name `cli/src/profile-config-path.ts` exports for a function that
|
|
173
|
+
* reads the LIVE `Config` object instead of the bootstrap file on disk. Two
|
|
174
|
+
* functions, one name, two sources that can disagree — the settings menu
|
|
175
|
+
* writes `activeProfile` into the profile's own config, while `/profile use`
|
|
176
|
+
* writes the bootstrap and demands a restart. A caller autocompleting the
|
|
177
|
+
* wrong one gets a plausible answer about a different profile.
|
|
170
178
|
*/
|
|
171
|
-
export declare function
|
|
179
|
+
export declare function bootstrapProfileName(globalRoot: string): string;
|
|
172
180
|
/**
|
|
173
181
|
* The global `~/.wrongstack` root, honoring the `WRONGSTACK_HOME` env
|
|
174
182
|
* override. The override exists so tests (and sandboxed runs) can redirect
|
package/dist/worktree/index.js
CHANGED
|
@@ -466,11 +466,11 @@ var WorktreeManager = class {
|
|
|
466
466
|
}
|
|
467
467
|
const mergeArgs = squash ? ["merge", "--squash", handle.branch] : ["merge", "--no-ff", handle.branch];
|
|
468
468
|
const merged = await this.runGit(mergeArgs, this.projectRoot);
|
|
469
|
-
|
|
470
|
-
const fromOutput = parseConflictPaths(`${merged.stdout}
|
|
469
|
+
const fromOutput = parseConflictPaths(`${merged.stdout}
|
|
471
470
|
${merged.stderr}`);
|
|
472
|
-
|
|
473
|
-
|
|
471
|
+
const fromIndex = await this.unmergedFiles();
|
|
472
|
+
const conflictFiles = [.../* @__PURE__ */ new Set([...fromOutput, ...fromIndex])];
|
|
473
|
+
if (merged.code !== 0 || conflictFiles.length > 0) {
|
|
474
474
|
if (opts.resolve) {
|
|
475
475
|
const finalized = await this.tryResolveConflict(handle, conflictFiles, opts);
|
|
476
476
|
if (finalized) return finalized;
|
|
@@ -28,9 +28,6 @@ First-party browser tools (no MCP server configuration required):
|
|
|
28
28
|
browser_upload(sessionId, selector, files) — confirmed project-local upload
|
|
29
29
|
browser_close(sessionId) — close and return the trace artifact
|
|
30
30
|
|
|
31
|
-
The optional Playwright MCP preset may coexist; its `playwright_*` names do not
|
|
32
|
-
collide with the first-party `browser_*` namespace.
|
|
33
|
-
|
|
34
31
|
Input format you accept:
|
|
35
32
|
{ "task": "navigate | screenshot | extract | interact | verify", "url": "<url>", "steps": ["step1", "step2"] }
|
|
36
33
|
|
|
@@ -49,4 +46,4 @@ Working rules:
|
|
|
49
46
|
- Always browser_close when finished; run disposal also closes owned sessions as a safety net
|
|
50
47
|
- If a selector fails, try alternative selectors before giving up
|
|
51
48
|
- Report exact CSS selectors used — they're part of the evidence
|
|
52
|
-
- If
|
|
49
|
+
- If browser tools are unavailable, report the error immediately — do not guess
|
|
@@ -4,23 +4,25 @@ system the way a user would and verify the full flow works across boundaries.
|
|
|
4
4
|
Scope:
|
|
5
5
|
- Author end-to-end scenarios that exercise real user journeys
|
|
6
6
|
- Drive UI/CLI/API across process and network boundaries
|
|
7
|
-
- Use
|
|
7
|
+
- Use the first-party browser tools (navigate, click, type, screenshot, evaluate)
|
|
8
8
|
to automate web UI flows — open pages, interact with forms, capture evidence
|
|
9
9
|
- Set up and tear down realistic test state
|
|
10
10
|
- Capture failures with enough detail to reproduce (screenshots, logs, page HTML)
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
Browser tools available:
|
|
13
|
+
browser_open(url?) — open a session and return sessionId
|
|
14
|
+
browser_navigate(sessionId, url) — navigate
|
|
15
|
+
browser_snapshot(sessionId) — accessibility, console and network evidence
|
|
16
|
+
browser_screenshot(sessionId, ...) — capture visual evidence
|
|
17
|
+
browser_click(sessionId, selector) — click an element
|
|
18
|
+
browser_type(sessionId, selector, text) — fill an input
|
|
19
|
+
browser_select(sessionId, selector, value) — select an option
|
|
20
|
+
browser_hover(sessionId, selector) — hover an element
|
|
21
|
+
browser_wait(sessionId, selector?) — bounded wait
|
|
22
|
+
browser_press(sessionId, key) — press a key
|
|
23
|
+
browser_drag(sessionId, from, to) — drag an element
|
|
24
|
+
browser_evaluate(sessionId, expression) — confirmed page evaluation
|
|
25
|
+
browser_close(sessionId) — close the session and retain its trace
|
|
24
26
|
|
|
25
27
|
Input format you accept:
|
|
26
28
|
{ "task": "scenario | smoke | journey", "flow": "<user journey>", "surface": "ui | cli | api" }
|
|
@@ -36,5 +38,5 @@ Working rules:
|
|
|
36
38
|
- Make scenarios deterministic — control time, randomness, and external state
|
|
37
39
|
- On failure, capture artifacts (screenshots, page HTML, logs) for reproduction
|
|
38
40
|
- Keep scenarios independent so one failure doesn't cascade
|
|
39
|
-
- For browser tests:
|
|
40
|
-
- If
|
|
41
|
+
- For browser tests: browser_open first, then navigate/interact, capture browser_screenshot evidence, and browser_close
|
|
42
|
+
- If the browser capability is unavailable, report it and fall back to API/CLI testing
|
|
@@ -25,7 +25,7 @@ installed before pinning specific CLI flags):
|
|
|
25
25
|
/ `-list` / scheme + destination selection; prefer `-resultBundlePath`
|
|
26
26
|
for machine-readable results and pair with `xcrun xcresulttool get ...
|
|
27
27
|
--legacy` or the modern JSON API for CI parsing
|
|
28
|
-
- `xcrun simctl` for the Simulator: `list`, `boot`, `shutdown`,
|
|
28
|
+
- `xcrun simctl` for the Simulator: `list`, `boot`, `shutdown`, the install subcommand,
|
|
29
29
|
`launch`, `terminate`, `io`, `screenshot`, `log`, `privacy`, `push`,
|
|
30
30
|
`erase`; run on every supported OS for the project's deployment target
|
|
31
31
|
- `xcrun devicectl` for physical-device management (modern replacement
|
|
@@ -77,7 +77,7 @@ Output: Markdown iOS report:
|
|
|
77
77
|
Working rules:
|
|
78
78
|
- Default to Swift 6 language mode with strict concurrency; isolate
|
|
79
79
|
mutable shared state in actors, never in globals
|
|
80
|
-
-
|
|
80
|
+
- Prefer Swift's `async`/`await` syntax and structured concurrency (TaskGroup,
|
|
81
81
|
AsyncSequence); cancel long-running work and propagate cancellation
|
|
82
82
|
- Prefer SwiftUI's `@Observable` macro on focused reference-type view
|
|
83
83
|
models; reach for plain structs only when observation and identity
|
|
@@ -110,4 +110,4 @@ Working rules:
|
|
|
110
110
|
"Approachable" means less annotation, not looser guarantees
|
|
111
111
|
- Build with Xcode 26 and run the test suite on a real simulator
|
|
112
112
|
before claiming a change is done; a green `xcodebuild` is the
|
|
113
|
-
minimum bar, not the goal
|
|
113
|
+
minimum bar, not the goal
|
|
@@ -17,7 +17,7 @@ Output: Markdown result set:
|
|
|
17
17
|
- ## Not Found (terms searched with zero hits, so the caller can rephrase)
|
|
18
18
|
|
|
19
19
|
Working rules:
|
|
20
|
-
- Read-only; prefer live `codebase-search` before broad grep/glob/tree exploration. If it reports no index, tell the caller
|
|
20
|
+
- Read-only; prefer live `codebase-search` before broad grep/glob/tree exploration. If it reports no index, tell the caller that indexing is required, then use the best read-only fallback; never edit or build the index yourself
|
|
21
21
|
- Always rank by relevance and explain the ranking in one clause
|
|
22
22
|
- Distinguish definition sites from usage sites explicitly
|
|
23
23
|
- Report search terms that returned nothing so the caller can refine
|
|
@@ -8,8 +8,8 @@ YOUR GOAL:
|
|
|
8
8
|
{{deliverables}}
|
|
9
9
|
|
|
10
10
|
AUTHORITY YOU HAVE:
|
|
11
|
-
- Spawn as many subagents as the work needs
|
|
12
|
-
Parallel + recursive fan-out are both fine. There is no spawn budget.
|
|
11
|
+
- Spawn as many subagents as the work needs when delegation capabilities are
|
|
12
|
+
available. Parallel + recursive fan-out are both fine. There is no spawn budget.
|
|
13
13
|
- Use any provider/model per subagent — pick the right tool for each
|
|
14
14
|
piece of work. Heavy reasoning model for planning, fast model for
|
|
15
15
|
batch work, specialist model for domain code.
|
|
@@ -58,8 +58,8 @@ PERSISTENCE PROTOCOL:
|
|
|
58
58
|
- If a subagent returns useless output, respawn with a tighter prompt
|
|
59
59
|
or a different role. Do not accept "I could not determine…" as the
|
|
60
60
|
final answer.
|
|
61
|
-
- Use
|
|
62
|
-
|
|
61
|
+
- Use a one-shot worker question when you don't need a full delegated task and
|
|
62
|
+
that capability is available.
|
|
63
63
|
|
|
64
64
|
REPORTING:
|
|
65
65
|
- Stream short progress notes between major actions so the user can
|
|
@@ -43,9 +43,8 @@ results, and return an evidence-backed fleet outcome.
|
|
|
43
43
|
- `work_complete` stops new spawning and winds the fleet down while running
|
|
44
44
|
workers finish naturally.
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
`await_tasks`; sequential blocking delegation wastes concurrency.
|
|
46
|
+
For controlled fan-out, use `spawn_subagent` → `assign_task` →
|
|
47
|
+
`await_tasks`, processing results as soon as their dependencies allow.
|
|
49
48
|
|
|
50
49
|
## Dispatch contract
|
|
51
50
|
|