@ferris1225/pi-subagents 4.3.2 → 4.3.4

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/src/dispatch.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * The `subagent` tool: dispatches the enabled agents (scout, artisan, steward,
3
- * plus custom roles) as isolated pi
4
- * child processes, single or parallel. Owns the public dispatch contract and
2
+ * The `subagent` tool: dispatches enabled scout, artisan, steward, sentinel,
3
+ * and custom roles as isolated pi child processes, single or parallel.
4
+ * Owns the public dispatch contract and
5
5
  * per-run status tracking. Stable thread generations, final integration, and
6
6
  * completion ownership live in thread-lifecycle.ts.
7
7
  */
@@ -11,7 +11,7 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
11
11
  import { Text } from "@earendil-works/pi-tui";
12
12
  import { join, resolve } from "node:path";
13
13
  import { Type } from "typebox";
14
- import { discoverAgents, isWriteCapableAgent, resolveAgentTools, type AgentConfig } from "./agents.ts";
14
+ import { discoverAgents, resolveAgentTools, type AgentConfig } from "./agents.ts";
15
15
  import { loadConfig } from "./config.ts";
16
16
  import { formatCompletionBlock, formatUsage, queuedResult } from "./format.ts";
17
17
  import {
@@ -39,6 +39,7 @@ import {
39
39
  } from "./spawn.ts";
40
40
  import {
41
41
  createBackgroundDispatcher,
42
+ isWorktreeCapableAgent,
42
43
  projectResultsRoot,
43
44
  resolveDispatchModelRoute,
44
45
  runInManagedRepositoryLane,
@@ -47,7 +48,7 @@ import {
47
48
  } from "./thread-lifecycle.ts";
48
49
  import type { IsolationMode } from "./worktree.ts";
49
50
 
50
- export { isWorktreeCapableAgent, runInManagedRepositoryLane } from "./thread-lifecycle.ts";
51
+ export { isWorktreeCapableAgent, runInManagedRepositoryLane };
51
52
 
52
53
  const NON_BLANK_TASK_OPTIONS = { minLength: 1, pattern: "\\S" } as const;
53
54
 
@@ -88,7 +89,7 @@ const SubagentParams = Type.Object({
88
89
 
89
90
  /** Roles that default to worktree isolation in parallel dispatches even when
90
91
  * the live catalog cannot be consulted (render-only call sites). Custom
91
- * write-capable agents join them via isWriteCapableAgent on the execute path. */
92
+ * worktree-capable agents join them via the live catalog on the execute path. */
92
93
  const WORKTREE_DEFAULT_AGENTS = new Set(["artisan", "steward"]);
93
94
 
94
95
  /** Resolve the default isolation for a dispatch. Precedence: an explicit
@@ -467,7 +468,7 @@ export function registerSubagentTool(pi: ExtensionAPI, runtime: SubagentRuntime)
467
468
  "parallel",
468
469
  item.agent,
469
470
  item.isolation as IsolationMode | undefined,
470
- catalogAgent ? isWriteCapableAgent(catalogAgent) : undefined,
471
+ catalogAgent ? isWorktreeCapableAgent(catalogAgent) : undefined,
471
472
  catalogAgent?.isolation,
472
473
  ),
473
474
  { deliveryRoute: params.wait ? "await" : "background" },
@@ -522,7 +523,7 @@ export function registerSubagentTool(pi: ExtensionAPI, runtime: SubagentRuntime)
522
523
  "single",
523
524
  params.agent as string,
524
525
  params.isolation as IsolationMode | undefined,
525
- singleCatalogAgent ? isWriteCapableAgent(singleCatalogAgent) : undefined,
526
+ singleCatalogAgent ? isWorktreeCapableAgent(singleCatalogAgent) : undefined,
526
527
  singleCatalogAgent?.isolation,
527
528
  ),
528
529
  { deliveryRoute: params.wait ? "await" : "background" },
package/src/prompt.ts CHANGED
@@ -34,8 +34,9 @@ function bullets(lines: readonly string[]): string {
34
34
 
35
35
  function phaseForAgent(agentName: string): string {
36
36
  if (agentName === "scout") return "broad reconnaissance";
37
- if (agentName === "artisan") return "implementation and targeted checks";
37
+ if (agentName === "artisan") return "primary change";
38
38
  if (agentName === "steward") return "pre-commit cleanup and cross-cutting docs";
39
+ if (agentName === "sentinel") return "post-cleanup adversarial review";
39
40
  return "delegated scope";
40
41
  }
41
42
 
@@ -104,16 +105,21 @@ export function buildDelegationDirective(
104
105
  const hasScout = agents.some((agent) => agent.name === "scout");
105
106
  const hasArtisan = agents.some((agent) => agent.name === "artisan");
106
107
  const hasSteward = agents.some((agent) => agent.name === "steward");
108
+ const hasSentinel = agents.some((agent) => agent.name === "sentinel");
107
109
 
108
110
  const dispatchRules = [
109
- "Main owns routing, architecture, integration, the final gate, and release. Each child starts a paid context; delegate only when saved main-context work exceeds handoff cost.",
110
- "Keep atomic lookups, focused edits, known answers, and context-heavy work in main. Cluster related reconnaissance into one scout brief.",
111
- ...(hasScout ? ["`scout`: broad or unfamiliar reconnaissance; return compact findings and decisive citations."] : []),
112
- ...(hasArtisan ? ["`artisan`: substantial self-contained implementation, including affected tests, docs, comments, and targeted checks."] : []),
113
- ...(hasSteward ? ["`steward`: one pre-commit cleanup or cross-cutting docs/comments pass for a completed broad or multi-writer change; keep small diff hygiene inline."] : []),
114
- "One owner per phase; dependent phases wait. A launch leases that phase: main may inspect its result, citations, diff, and check output but must not rerun it.",
115
- "Parallelize only independently justified, disjoint scopes. Brief goal, scope, constraints, and expected output; resume retained work with `subagent_control`.",
116
- "Completions deliver automatically. Never poll, restate a result, or finish while a run is active.",
111
+ `Main owns routing, architecture, integration, the final gate, and release. Each child starts a paid context; delegate only when handoff saves more than it costs${hasSentinel ? ", except required sentinel review before commit" : ""}.`,
112
+ "Keep atomic lookups, focused edits, known answers, and context-heavy work in main. Cluster related reconnaissance into one scout brief, including external research.",
113
+ ...(hasScout ? ["`scout`: read-only broad code mapping or external research; return file/source citations as leads, not proof."] : []),
114
+ ...(hasArtisan ? ["`artisan`: one substantial primary change; own root cause, implementation, affected tests/docs, and targeted checks."] : []),
115
+ ...(hasSteward ? ["`steward`: final cleanup/docs sync for a completed broad or multi-writer diff; keep focused hygiene inline."] : []),
116
+ ...(hasSentinel ? ["`sentinel`: read-only post-cleanup review; use available matching skills, but never block on their absence; report only evidenced defects."] : []),
117
+ ...(hasSentinel
118
+ ? [`Before every commit: cleanup -> sentinel review. ${hasSteward ? "Use steward once only for broad or multi-writer diffs" : "Keep cleanup inline"}. Then dispatch sentinel on the final diff and check evidence. After review fixes, clean and review once more; findings block commit.`]
119
+ : []),
120
+ "One owner per phase; dependent phases wait. A launch leases that phase: main may inspect its result, citations, diff, and checks, not redo the phase; main still runs the final gate.",
121
+ "Parallelize only independent, disjoint scopes. Brief goal, paths, constraints, and expected output; resume with `subagent_control`.",
122
+ "`wait: true` only when the result is the immediate dependency; otherwise continue disjoint work. Never sleep or poll, and never finish while a run is active.",
117
123
  "Inspect the integrated diff and actual check output. Never report an unrun check as passed.",
118
124
  ];
119
125