@wrongstack/core 0.308.0 → 0.308.2

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 (61) hide show
  1. package/dist/coordination/agents/index.js +4 -4
  2. package/dist/coordination/index.d.ts +1 -0
  3. package/dist/coordination/index.js +113 -15
  4. package/dist/coordination/task-boundary.d.ts +64 -0
  5. package/dist/core/index.js +1 -1
  6. package/dist/defaults/index.js +116 -19
  7. package/dist/execution/index.js +11 -8
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.js +127 -20
  10. package/dist/infrastructure/index.js +1 -1
  11. package/dist/storage/index.js +2 -1
  12. package/dist/tools/index.js +4 -4
  13. package/dist/types/config/ui.d.ts +1 -1
  14. package/dist/types/context-window.d.ts +18 -1
  15. package/dist/types/index.d.ts +1 -1
  16. package/dist/types/index.js +11 -4
  17. package/dist/types/runtime-capability-manifest.d.ts +1 -1
  18. package/instructions/agents/backend.md +3 -0
  19. package/instructions/agents/bug-hunter.md +3 -0
  20. package/instructions/agents/code-reviewer.md +1 -0
  21. package/instructions/agents/frontend.md +2 -0
  22. package/instructions/agents/test.md +2 -0
  23. package/instructions/coordination/director-preamble.md +9 -1
  24. package/instructions/coordination/subagent-baseline.md +4 -0
  25. package/instructions/modes/code-reviewer.md +1 -1
  26. package/instructions/modes/debugger.md +2 -2
  27. package/instructions/modes/refactorer.md +2 -2
  28. package/instructions/modes/tester.md +2 -2
  29. package/instructions/system-lite.md +37 -33
  30. package/instructions/system-pro.md +23 -7
  31. package/instructions/system.md +33 -11
  32. package/package.json +6 -4
  33. package/skills/api-design/SKILL.md +26 -1
  34. package/skills/audit-log/SKILL.md +22 -1
  35. package/skills/auto-review/SKILL.md +21 -1
  36. package/skills/bug-hunter/SKILL.md +8 -0
  37. package/skills/chimera/SKILL.md +9 -0
  38. package/skills/data-governance/SKILL.md +25 -1
  39. package/skills/design-system/SKILL.md +19 -1
  40. package/skills/docker-deploy/SKILL.md +26 -1
  41. package/skills/git-flow/SKILL.md +26 -1
  42. package/skills/mailbox-bridge/SKILL.md +25 -1
  43. package/skills/mnemosyne/SKILL.md +25 -2
  44. package/skills/multi-agent/SKILL.md +12 -0
  45. package/skills/node-modern/SKILL.md +28 -1
  46. package/skills/observability/SKILL.md +25 -1
  47. package/skills/output-standards/SKILL.md +28 -1
  48. package/skills/plugin-author/SKILL.md +31 -1
  49. package/skills/prompt-engineering/SKILL.md +27 -1
  50. package/skills/react-modern/SKILL.md +29 -1
  51. package/skills/refactor-planner/SKILL.md +10 -0
  52. package/skills/research-web/SKILL.md +28 -1
  53. package/skills/sdd/SKILL.md +18 -0
  54. package/skills/security-scanner/SKILL.md +25 -1
  55. package/skills/skill-creator/SKILL.md +25 -1
  56. package/skills/tech-stack/SKILL.md +25 -1
  57. package/skills/testing/SKILL.md +25 -1
  58. package/skills/typescript-strict/SKILL.md +30 -1
  59. package/skills/wrongstack-kanban/SKILL.md +24 -0
  60. package/skills/wrongstack-mailbox/SKILL.md +29 -1
  61. package/skills/wrongstack-mailbox-mcp/SKILL.md +30 -3
@@ -1378,7 +1378,7 @@ var RUNTIME_CAPABILITY_MANIFEST = [
1378
1378
  id: "execution.shell",
1379
1379
  pack: "development",
1380
1380
  exposure: "direct",
1381
- tools: ["bash", "exec", "language", "language_info", "language_package"]
1381
+ tools: ["bash", "exec", "pwsh", "language", "language_info", "language_package"]
1382
1382
  },
1383
1383
  {
1384
1384
  id: "verification.run",
@@ -3337,7 +3337,7 @@ ${identity}`);
3337
3337
  splitLearnedEntries(rawLearned)
3338
3338
  );
3339
3339
  const rawBytes = Buffer.byteLength(rawLearned, "utf8");
3340
- const freshEntries = meta === void 0 ? [] : rawEntries.filter((entry) => entry.capturedAt > meta.consolidatedAt);
3340
+ const freshEntries = meta === void 0 ? [] : rawEntries.filter((entry) => entry.capturedAt >= meta.consolidatedAt);
3341
3341
  const stale = meta === void 0 || freshEntries.length > 0 || rawEntries.length > meta.sourceEntryCount || rawBytes > meta.sourceBytes;
3342
3342
  if (!stale) {
3343
3343
  learnedContent = consolidated;
@@ -4934,7 +4934,7 @@ var VERIFY_AGENTS = [
4934
4934
  id: "bug-hunter",
4935
4935
  name: "Bug Hunter",
4936
4936
  role: "bug-hunter",
4937
- tools: [...TOOLS.inspect],
4937
+ tools: [...TOOLS.inspect, "dead-code-scan"],
4938
4938
  prompt: agentPrompt("bug-hunter")
4939
4939
  },
4940
4940
  budget: HEAVY_BUDGET,
@@ -5024,7 +5024,7 @@ var REVIEW_AGENTS = [
5024
5024
  id: "code-reviewer",
5025
5025
  name: "Code Reviewer",
5026
5026
  role: "code-reviewer",
5027
- tools: [...TOOLS.inspect, "git"],
5027
+ tools: [...TOOLS.inspect, "git", "codebase-impact-analysis", "codebase-invariant-check"],
5028
5028
  prompt: agentPrompt("code-reviewer")
5029
5029
  },
5030
5030
  budget: MEDIUM_BUDGET,
@@ -69,6 +69,7 @@ TIMEOUT_PREEMPT_FRACTION, } from './subagent-budget.js';
69
69
  export { assignNickname } from './subagent-nicknames.js';
70
70
  export { formatSubagentStructuredReport, MAX_SUBAGENT_STRUCTURED_REPORT_CHARS, makeSubagentResultTool, normalizeSubagentStructuredReport, readSubagentStructuredReport, SUBAGENT_STRUCTURED_REPORT_META_KEY, } from './subagent-result-tool.js';
71
71
  export { startTechStackConsumer, type TechStackConsumerOptions, } from './techstack-mailbox-consumer.js';
72
+ export { composeBoundedTaskDescription, type TaskBoundary, parseTaskBoundary, renderTaskBoundaryBlock, taskBoundarySchemaProperties, } from './task-boundary.js';
72
73
  export { type FleetWorktreePolicy, resolveSubagentWorktreeDecision, subagentNeedsWorktree, WorktreeIntegrationError, type WorktreeIsolationDecision, type WorktreeTaskRunnerOptions, type WorktreeTaskStateUpdate, wrapSubagentRunnerWithWorktrees, } from './worktree-task-runner.js';
73
74
  export { collabInjectMiddleware, collabPauseMiddleware, } from '../middleware/collab-pause.js';
74
75
  export { AdaptiveConcurrencyController, type AdaptiveConcurrencyState, } from './adaptive-concurrency.js';
@@ -2643,7 +2643,7 @@ var RUNTIME_CAPABILITY_MANIFEST = [
2643
2643
  id: "execution.shell",
2644
2644
  pack: "development",
2645
2645
  exposure: "direct",
2646
- tools: ["bash", "exec", "language", "language_info", "language_package"]
2646
+ tools: ["bash", "exec", "pwsh", "language", "language_info", "language_package"]
2647
2647
  },
2648
2648
  {
2649
2649
  id: "verification.run",
@@ -4435,7 +4435,7 @@ ${identity}`);
4435
4435
  splitLearnedEntries(rawLearned)
4436
4436
  );
4437
4437
  const rawBytes = Buffer.byteLength(rawLearned, "utf8");
4438
- const freshEntries = meta === void 0 ? [] : rawEntries.filter((entry) => entry.capturedAt > meta.consolidatedAt);
4438
+ const freshEntries = meta === void 0 ? [] : rawEntries.filter((entry) => entry.capturedAt >= meta.consolidatedAt);
4439
4439
  const stale = meta === void 0 || freshEntries.length > 0 || rawEntries.length > meta.sourceEntryCount || rawBytes > meta.sourceBytes;
4440
4440
  if (!stale) {
4441
4441
  learnedContent = consolidated;
@@ -6032,7 +6032,7 @@ var VERIFY_AGENTS = [
6032
6032
  id: "bug-hunter",
6033
6033
  name: "Bug Hunter",
6034
6034
  role: "bug-hunter",
6035
- tools: [...TOOLS.inspect],
6035
+ tools: [...TOOLS.inspect, "dead-code-scan"],
6036
6036
  prompt: agentPrompt("bug-hunter")
6037
6037
  },
6038
6038
  budget: HEAVY_BUDGET,
@@ -6122,7 +6122,7 @@ var REVIEW_AGENTS = [
6122
6122
  id: "code-reviewer",
6123
6123
  name: "Code Reviewer",
6124
6124
  role: "code-reviewer",
6125
- tools: [...TOOLS.inspect, "git"],
6125
+ tools: [...TOOLS.inspect, "git", "codebase-impact-analysis", "codebase-invariant-check"],
6126
6126
  prompt: agentPrompt("code-reviewer")
6127
6127
  },
6128
6128
  budget: MEDIUM_BUDGET,
@@ -10481,6 +10481,80 @@ var FLEET_ROSTER_WITHACP = {
10481
10481
  ...Object.fromEntries(ACP_AGENTS.map((a) => [a.role, a]))
10482
10482
  };
10483
10483
 
10484
+ // src/coordination/task-boundary.ts
10485
+ var PLACEHOLDER_VALUES = /* @__PURE__ */ new Set([
10486
+ "n/a",
10487
+ "na",
10488
+ "none",
10489
+ "nothing",
10490
+ "tbd",
10491
+ "todo",
10492
+ "unknown",
10493
+ "unspecified",
10494
+ "-",
10495
+ "\u2014",
10496
+ ".",
10497
+ "as above",
10498
+ "same as above",
10499
+ "see above",
10500
+ "see task",
10501
+ "same as task"
10502
+ ]);
10503
+ var isPlaceholder = (value) => PLACEHOLDER_VALUES.has(value.trim().toLowerCase());
10504
+ var MIN_SCOPE_CHARS = 8;
10505
+ var MIN_NON_GOAL_CHARS = 3;
10506
+ function parseTaskBoundary(raw) {
10507
+ const scope = typeof raw.scope === "string" ? raw.scope.trim() : "";
10508
+ if (scope.length < MIN_SCOPE_CHARS) {
10509
+ return {
10510
+ ok: false,
10511
+ error: `\`scope\` is missing or too vague \u2014 state in one concrete sentence what work this task covers (files, components, or commands in-bounds).`,
10512
+ hint: 'Example \u2014 scope: "Audit packages/core/src/parser/*.ts for unhandled token errors and report findings."'
10513
+ };
10514
+ }
10515
+ if (!Array.isArray(raw.outOfScope) || raw.outOfScope.length === 0) {
10516
+ return {
10517
+ ok: false,
10518
+ error: "`outOfScope` must be an array with at least one explicit non-goal \u2014 things the worker must NOT do.",
10519
+ hint: 'Example \u2014 outOfScope: ["Do not modify files outside packages/core", "Do not fix the bugs you find, only report them"].'
10520
+ };
10521
+ }
10522
+ const concrete = raw.outOfScope.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length >= MIN_NON_GOAL_CHARS && !isPlaceholder(item));
10523
+ if (concrete.length === 0) {
10524
+ return {
10525
+ ok: false,
10526
+ error: 'Every `outOfScope` entry was a placeholder ("none", "n/a", \u2026). Name at least one concrete non-goal: files or areas not to touch, changes not to make, features not to add.',
10527
+ hint: 'There is always an edge worth stating \u2014 "read-only, no edits", "no dependency changes", "do not touch other packages". If truly nothing comes to mind, the task is not decomposed enough yet.'
10528
+ };
10529
+ }
10530
+ return { ok: true, boundary: { scope, outOfScope: concrete } };
10531
+ }
10532
+ function renderTaskBoundaryBlock(boundary) {
10533
+ return [
10534
+ "\u2500\u2500 TASK BOUNDARY (hard contract \u2014 these lines define your edges) \u2500\u2500",
10535
+ `Scope (what this task covers):
10536
+ ${boundary.scope}`,
10537
+ `Out of scope (explicit non-goals \u2014 do NOT do any of these):
10538
+ ${boundary.outOfScope.map((item) => `- ${item}`).join("\n")}`
10539
+ ].join("\n");
10540
+ }
10541
+ function composeBoundedTaskDescription(objective, boundary) {
10542
+ return `${objective.trim()}
10543
+
10544
+ ${renderTaskBoundaryBlock(boundary)}`;
10545
+ }
10546
+ var taskBoundarySchemaProperties = {
10547
+ scope: {
10548
+ type: "string",
10549
+ description: "REQUIRED. One concrete sentence stating what work this task covers \u2014 the in-bounds. The call is rejected without it."
10550
+ },
10551
+ outOfScope: {
10552
+ type: "array",
10553
+ items: { type: "string", minLength: 1 },
10554
+ description: 'REQUIRED. At least one explicit non-goal the worker must NOT do (files/areas not to touch, changes not to make, features not to add). Placeholders like "none" are rejected.'
10555
+ }
10556
+ };
10557
+
10484
10558
  // src/coordination/delegate-tool.ts
10485
10559
  function createDelegateTool(opts) {
10486
10560
  const defaultTimeoutMs = opts.defaultTimeoutMs ?? 4 * 60 * 60 * 1e3;
@@ -10490,8 +10564,9 @@ function createDelegateTool(opts) {
10490
10564
  properties: {
10491
10565
  task: {
10492
10566
  type: "string",
10493
- description: "What the subagent should do \u2014 natural language, complete sentence(s)."
10567
+ description: "The objective \u2014 what the subagent should do, natural language, complete sentence(s). Pair it with the required `scope` and `outOfScope` boundary fields."
10494
10568
  },
10569
+ ...taskBoundarySchemaProperties,
10495
10570
  role: {
10496
10571
  type: "string",
10497
10572
  description: rosterIds.length > 0 ? "Roster role id. Common: bug-hunter, security-scanner, refactor-planner, critic, audit-log, executor, shadow-agent, architect." : "No roster configured \u2014 pass `name` instead."
@@ -10549,12 +10624,12 @@ function createDelegateTool(opts) {
10549
10624
  description: "Max fresh-worker continuations after budget exhaustion. Default 1. Each gets the prior partial report."
10550
10625
  }
10551
10626
  },
10552
- required: ["task"]
10627
+ required: ["task", "scope", "outOfScope"]
10553
10628
  };
10554
10629
  return {
10555
10630
  name: "delegate",
10556
10631
  description: "Hand a piece of work to a subagent and block until it returns. This call is synchronous: the leader's iteration pauses for the full duration of the subagent's run. (Multiple `delegate` calls fired in the same assistant turn still parallelize through the provider's parallel-tool-call surface, but each one eats wall-clock time \u2014 so for fan-out you actually control, reach for the async path below.) Use `delegate` when your next step genuinely needs the subagent's verdict \u2014 a review, a fact-check, a sign-off. Has own context, own LLM call, auto-extending budget, and a partial-completion handoff path (maxHandoffs, default 1). Workers cannot recursively spawn.\n\n**Do NOT use `delegate` for long-running work.** While `delegate` is in flight, the leader is fully blocked \u2014 it cannot act on other tools, read mail, or react to the user. If the work might run for tens of minutes or hours (multi-file refactor, monorepo audit, long-running build/test, sweeping migration), the blocking call wastes the leader's time. Use the async tool family instead: `spawn_subagent` to create each worker (returns a `subagentId` immediately), `assign_task` to queue work on it (returns a `taskId` immediately), then `await_tasks` to retrieve results later. The leader keeps doing other work while the worker churns, and a worker that realizes its task will run long can mail the leader (type `steer` or `ask` via `mail_send`) saying *\"my task is going to run long, please spawn a subagent instead\"* so the leader re-dispatches asynchronously instead of waiting.\n\n**Do NOT use `delegate` for fan-out you control.** Multiple sequential `delegate` calls each block the leader, wasting wall-clock time. For independent investigations you want to run in parallel \u2014 security scan + bug hunt + perf review on the same PR \u2014 use the async tool family: `spawn_subagent` to create each worker (returns a `subagentId` immediately), `assign_task` to queue work on it (returns a `taskId` immediately), then the `await_tasks` tool with `{mode: 'any'}` to fold the first useful result into the next decision while the rest keep churning. Reach for `delegate` only when the result gates your next move AND the work is short enough that blocking the leader is acceptable.",
10557
- usageHint: "Set `task` to a complete instruction. Pick `role` from roster or pass `name` for free-form. Reach for `delegate` only when the result gates your next move AND the work is short enough that blocking the leader is acceptable (minutes, not hours). For long-running work or fan-out you control, use `spawn_subagent` + `assign_task` + `await_tasks` instead. Raise `maxHandoffs` (default 1, cap 8) for multi-day or multi-refactor tasks; pass larger `timeoutMs`/`maxIterations`/`maxToolCalls` only when needed.",
10632
+ usageHint: "Set `task` to the objective, then make the edges explicit: `scope` (what the work covers) and `outOfScope` (at least one concrete non-goal) are REQUIRED \u2014 the call is rejected without them, and the worker treats the rendered boundary block as a hard contract. Pick `role` from roster or pass `name` for free-form. Reach for `delegate` only when the result gates your next move AND the work is short enough that blocking the leader is acceptable (minutes, not hours). For long-running work or fan-out you control, use `spawn_subagent` + `assign_task` + `await_tasks` instead. Raise `maxHandoffs` (default 1, cap 8) for multi-day or multi-refactor tasks; pass larger `timeoutMs`/`maxIterations`/`maxToolCalls` only when needed.",
10558
10633
  permission: "auto",
10559
10634
  mutating: false,
10560
10635
  managesOwnTimeout: true,
@@ -10574,6 +10649,14 @@ function createDelegateTool(opts) {
10574
10649
  error: "Delegation cancelled before spawn \u2014 the run was interrupted."
10575
10650
  };
10576
10651
  }
10652
+ const boundary = parseTaskBoundary(i);
10653
+ if (!boundary.ok) {
10654
+ return {
10655
+ ok: false,
10656
+ error: `delegate rejected \u2014 task boundary incomplete: ${boundary.error}`,
10657
+ hint: boundary.hint
10658
+ };
10659
+ }
10577
10660
  const target = i.role ?? i.name ?? "subagent";
10578
10661
  const launchModePreface = [
10579
10662
  "Launch-mode guidance (delegate): you were launched via the synchronous `delegate` tool, so the leader is blocked on this call for the full duration of your run.",
@@ -10644,7 +10727,8 @@ function createDelegateTool(opts) {
10644
10727
  const dir = director;
10645
10728
  const maxHandoffs = Math.min(8, Math.max(0, Math.floor(i.maxHandoffs ?? 1)));
10646
10729
  const handoffs = [];
10647
- let delegatedTask = i.task;
10730
+ const baseBrief = composeBoundedTaskDescription(i.task, boundary.boundary);
10731
+ let delegatedTask = baseBrief;
10648
10732
  let handoffCount = 0;
10649
10733
  for (; ; ) {
10650
10734
  const attemptConfig = (() => {
@@ -10784,7 +10868,7 @@ function createDelegateTool(opts) {
10784
10868
  remainingWork: continuation.remainingWork
10785
10869
  });
10786
10870
  handoffCount += 1;
10787
- delegatedTask = buildHandoffTask(i.task, continuation, handoffCount, maxHandoffs);
10871
+ delegatedTask = buildHandoffTask(baseBrief, continuation, handoffCount, maxHandoffs);
10788
10872
  continue;
10789
10873
  }
10790
10874
  const incomplete = result.report?.completion === "partial";
@@ -12688,8 +12772,9 @@ function makeAssignTool(director) {
12688
12772
  description: {
12689
12773
  type: "string",
12690
12774
  minLength: 1,
12691
- description: "The task in natural language \u2014 what you want this subagent to do."
12775
+ description: "The objective in natural language \u2014 what you want this subagent to do. Pair it with the required `scope` and `outOfScope` boundary fields."
12692
12776
  },
12777
+ ...taskBoundarySchemaProperties,
12693
12778
  maxToolCalls: {
12694
12779
  type: "number",
12695
12780
  minimum: 1,
@@ -12697,20 +12782,28 @@ function makeAssignTool(director) {
12697
12782
  },
12698
12783
  timeoutMs: { type: "number", minimum: 1, description: "Optional per-task timeout in ms." }
12699
12784
  },
12700
- required: ["subagentId", "description"]
12785
+ required: ["subagentId", "description", "scope", "outOfScope"]
12701
12786
  };
12702
12787
  return {
12703
12788
  name: "assign_task",
12704
- description: "Queue a task on a previously spawned subagent. NON-BLOCKING: returns a `taskId` IMMEDIATELY \u2014 the subagent processes the task on its next iteration with its own LLM budget. The `taskId` is the durable handle for retrieving the result later via `await_tasks`, `roll_up`, or `ask_result`. Many `assign_task` calls can be in flight in parallel against the same or different subagents. This is the primary tool for fan-out work; do NOT use `delegate` to spawn multiple investigations sequentially.",
12789
+ description: "Queue a task on a previously spawned subagent. NON-BLOCKING: returns a `taskId` IMMEDIATELY \u2014 the subagent processes the task on its next iteration with its own LLM budget. The `taskId` is the durable handle for retrieving the result later via `await_tasks`, `roll_up`, or `ask_result`. Every assignment MUST carry an explicit boundary: `scope` (what the work covers) and `outOfScope` (at least one concrete non-goal) \u2014 the call is rejected without them, and the worker treats the rendered boundary block as a hard contract. Many `assign_task` calls can be in flight in parallel against the same or different subagents. This is the primary tool for fan-out work; do NOT use `delegate` to spawn multiple investigations sequentially.",
12705
12790
  permission: "auto",
12706
12791
  mutating: false,
12707
12792
  capabilities: [ToolCapabilities.SUBAGENT_SPAWN],
12708
12793
  inputSchema,
12709
12794
  async execute(input) {
12710
12795
  const i = input;
12796
+ const boundary = parseTaskBoundary(i);
12797
+ if (!boundary.ok) {
12798
+ return {
12799
+ ok: false,
12800
+ error: `assign_task rejected \u2014 task boundary incomplete: ${boundary.error}`,
12801
+ hint: boundary.hint
12802
+ };
12803
+ }
12711
12804
  const task = {
12712
12805
  id: randomUUID8(),
12713
- description: i.description,
12806
+ description: composeBoundedTaskDescription(i.description, boundary.boundary),
12714
12807
  subagentId: i.subagentId,
12715
12808
  maxToolCalls: i.maxToolCalls,
12716
12809
  timeoutMs: i.timeoutMs
@@ -18543,6 +18636,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
18543
18636
  sessionPath: (sid, ext) => this.sessionPath(sid, ext)
18544
18637
  });
18545
18638
  this.clearLoadCache(canonical);
18639
+ if (id !== canonical) this.clearLoadCache(id);
18546
18640
  }
18547
18641
  async summarize(id, mtime) {
18548
18642
  return summarizeSessionFile({
@@ -20502,8 +20596,8 @@ var DefaultMultiAgentCoordinator = class _DefaultMultiAgentCoordinator extends E
20502
20596
  withNickname(subagent, subagentId) {
20503
20597
  const role = subagent.role ?? "subagent";
20504
20598
  const name = subagent.name?.trim() ?? "";
20505
- const isPlaceholder = name === "" || name.toLowerCase() === role.toLowerCase() || name === "subagent" || name === "adhoc" || name === "generic" || /^slot-/.test(name);
20506
- if (!isPlaceholder) return subagent;
20599
+ const isPlaceholder2 = name === "" || name.toLowerCase() === role.toLowerCase() || name === "subagent" || name === "adhoc" || name === "generic" || /^slot-/.test(name);
20600
+ if (!isPlaceholder2) return subagent;
20507
20601
  const { key, display } = assignNickname(role, this.usedNicknames);
20508
20602
  this.usedNicknames.add(key);
20509
20603
  this.subagentNicknames.set(subagentId, key);
@@ -31366,6 +31460,7 @@ export {
31366
31460
  clearProjectSkillAugmentation,
31367
31461
  collabInjectMiddleware,
31368
31462
  collabPauseMiddleware,
31463
+ composeBoundedTaskDescription,
31369
31464
  composeDirectorPrompt,
31370
31465
  composeSubagentPrompt,
31371
31466
  consolidatedDocumentPath,
@@ -31450,6 +31545,7 @@ export {
31450
31545
  parseMailboxAckInput,
31451
31546
  parseMailboxQueryInput,
31452
31547
  parseMailboxSendInput,
31548
+ parseTaskBoundary,
31453
31549
  phaseForRole,
31454
31550
  quarantinePath,
31455
31551
  rankRoleSkills,
@@ -31466,6 +31562,7 @@ export {
31466
31562
  refreshProjectAgentIdentity,
31467
31563
  release,
31468
31564
  renderSkillAugmentation,
31565
+ renderTaskBoundaryBlock,
31469
31566
  resetCaptureWindow,
31470
31567
  resetCaptureWindows,
31471
31568
  resetProjectAgentIdentity,
@@ -31496,6 +31593,7 @@ export {
31496
31593
  startPackageOutdatedWatcher,
31497
31594
  startTechStackConsumer,
31498
31595
  subagentNeedsWorktree,
31596
+ taskBoundarySchemaProperties,
31499
31597
  terminalPolicyDecision,
31500
31598
  unwrapWholeDocumentFence,
31501
31599
  updatePackageOutdatedStatus,
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Hard task-boundary contract for leader → subagent assignment tools.
3
+ *
4
+ * `delegate` and `assign_task` reject any assignment that does not carry an
5
+ * explicit in-bounds `scope` and at least one concrete out-of-scope non-goal.
6
+ * Prompt-only guidance ("state the scope and non-goals") degrades under
7
+ * pressure: a rushed leader writes "fix it", the worker guesses the edges, and
8
+ * the drift only surfaces at review time — the most expensive place to find
9
+ * it. Forcing the boundary into structured fields makes the edges
10
+ * machine-checkable at assignment time and lets the tool return a teaching
11
+ * error that names exactly what is missing, so the leader self-corrects on
12
+ * the next call instead of shipping a vague brief.
13
+ *
14
+ * The parsed boundary is composed into `TaskSpec.description` as a clearly
15
+ * delimited block. That is deliberate: the description is the canonical brief
16
+ * every runner, transcript, handoff continuation, and roll-up already
17
+ * consumes, so the boundary travels with the task everywhere without new
18
+ * plumbing (and `buildHandoffTask`'s "Original task:" carry-over preserves it
19
+ * into fresh workers for free).
20
+ */
21
+ import type { JSONSchema } from '../types/tool.js';
22
+ export interface TaskBoundary {
23
+ /** What the work covers — the in-bounds statement. */
24
+ scope: string;
25
+ /** Explicit non-goals: things the worker must NOT do. */
26
+ outOfScope: string[];
27
+ }
28
+ export type TaskBoundaryParseResult = {
29
+ ok: true;
30
+ boundary: TaskBoundary;
31
+ } | {
32
+ ok: false;
33
+ error: string;
34
+ hint: string;
35
+ };
36
+ /**
37
+ * Validate and normalize the `scope` / `outOfScope` pair from a tool input.
38
+ * Returns the cleaned boundary, or an error + hint pair worded so the calling
39
+ * leader can fix the call in one retry.
40
+ */
41
+ export declare function parseTaskBoundary(raw: {
42
+ scope?: unknown;
43
+ outOfScope?: unknown;
44
+ }): TaskBoundaryParseResult;
45
+ /**
46
+ * Render the boundary as the block appended to `TaskSpec.description`. The
47
+ * heading is loud on purpose: the worker treats these lines as hard edges,
48
+ * and review-time drift checks quote them verbatim.
49
+ */
50
+ export declare function renderTaskBoundaryBlock(boundary: TaskBoundary): string;
51
+ /**
52
+ * Compose the leader's objective with its boundary into the canonical brief
53
+ * delivered to the runner. The objective stays verbatim and first; the
54
+ * boundary block follows so handoffs, transcripts, and roll-ups that quote
55
+ * the description carry the edges with them.
56
+ */
57
+ export declare function composeBoundedTaskDescription(objective: string, boundary: TaskBoundary): string;
58
+ /**
59
+ * Shared schema property definitions so `delegate` and `assign_task` state
60
+ * the identical contract. Declaring the fields here (rather than inline per
61
+ * tool) keeps the required-field teaching text single-sourced.
62
+ */
63
+ export declare const taskBoundarySchemaProperties: Record<string, JSONSchema>;
64
+ //# sourceMappingURL=task-boundary.d.ts.map
@@ -7920,7 +7920,7 @@ var RUNTIME_CAPABILITY_MANIFEST = [
7920
7920
  id: "execution.shell",
7921
7921
  pack: "development",
7922
7922
  exposure: "direct",
7923
- tools: ["bash", "exec", "language", "language_info", "language_package"]
7923
+ tools: ["bash", "exec", "pwsh", "language", "language_info", "language_package"]
7924
7924
  },
7925
7925
  {
7926
7926
  id: "verification.run",