@tintinweb/pi-subagents 0.2.6 → 0.3.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/src/prompts.ts CHANGED
@@ -1,53 +1,16 @@
1
1
  /**
2
- * prompts.ts — System prompts per agent type.
2
+ * prompts.ts — System prompt builder for agents.
3
3
  */
4
4
 
5
- import type { EnvInfo } from "./types.js";
5
+ import type { AgentConfig, EnvInfo } from "./types.js";
6
6
 
7
- // ---- Reusable prompt blocks ----
8
-
9
- const READ_ONLY_PROHIBITION = `You are STRICTLY PROHIBITED from:
10
- - Creating new files
11
- - Modifying existing files
12
- - Deleting files
13
- - Moving or copying files
14
- - Creating temporary files anywhere, including /tmp
15
- - Using redirect operators (>, >>, |) or heredocs to write to files
16
- - Running ANY commands that change system state`;
17
-
18
- const READ_ONLY_TOOLS = `# Tool Usage
19
- - Use the find tool for file pattern matching (NOT the bash find command)
20
- - Use the grep tool for content search (NOT bash grep/rg command)
21
- - Use the read tool for reading files (NOT bash cat/head/tail)
22
- - Use Bash ONLY for read-only operations`;
23
-
24
- const FULL_TOOL_USAGE = `# Tool Usage
25
- - Use the read tool instead of cat/head/tail
26
- - Use the edit tool instead of sed/awk
27
- - Use the write tool instead of echo/heredoc
28
- - Use the find tool instead of bash find/ls for file search
29
- - Use the grep tool instead of bash grep/rg for content search
30
- - Make independent tool calls in parallel`;
31
-
32
- const GIT_SAFETY = `# Git Safety
33
- - NEVER update git config
34
- - NEVER run destructive git commands (push --force, reset --hard, checkout ., restore ., clean -f, branch -D) without explicit request
35
- - NEVER skip hooks (--no-verify, --no-gpg-sign) unless explicitly asked
36
- - NEVER force push to main/master — warn the user if they request it
37
- - Always create NEW commits, never amend existing ones. When a pre-commit hook fails, the commit did NOT happen — so --amend would modify the PREVIOUS commit. Fix the issue, re-stage, and create a NEW commit
38
- - Stage specific files by name, not git add -A or git add .
39
- - NEVER commit changes unless the user explicitly asks
40
- - NEVER push unless the user explicitly asks
41
- - NEVER use git commands with the -i flag (like git rebase -i or git add -i) — they require interactive input
42
- - Do not use --no-edit with git rebase commands
43
- - Do not commit files that likely contain secrets (.env, credentials.json, etc); warn the user if they request it`;
44
-
45
- const OUTPUT_RULES = `# Output
46
- - Use absolute file paths
47
- - Do not use emojis
48
- - Be concise but complete`;
49
-
50
- export function buildSystemPrompt(type: string, cwd: string, env: EnvInfo): string {
7
+ /**
8
+ * Build the system prompt for an agent from its config.
9
+ *
10
+ * - "replace" mode: common header + config.systemPrompt
11
+ * - "append" mode: common header + generic base + config.systemPrompt
12
+ */
13
+ export function buildAgentPrompt(config: AgentConfig, cwd: string, env: EnvInfo): string {
51
14
  const commonHeader = `You are a pi coding agent sub-agent.
52
15
  You have been invoked to handle a specific task autonomously.
53
16
 
@@ -56,108 +19,30 @@ Working directory: ${cwd}
56
19
  ${env.isGitRepo ? `Git repository: yes\nBranch: ${env.branch}` : "Not a git repository"}
57
20
  Platform: ${env.platform}`;
58
21
 
59
- switch (type) {
60
- case "Explore":
61
- return `${commonHeader}
62
-
63
- # CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS
64
- You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
65
- Your role is EXCLUSIVELY to search and analyze existing code. You do NOT have access to file editing tools.
66
-
67
- ${READ_ONLY_PROHIBITION}
68
-
69
- Use Bash ONLY for read-only operations: ls, git status, git log, git diff, find, cat, head, tail.
70
-
71
- ${READ_ONLY_TOOLS}
72
- - Make independent tool calls in parallel for efficiency
73
- - Adapt search approach based on thoroughness level specified
74
-
75
- # Output
76
- - Use absolute file paths in all references
77
- - Report findings as regular messages
78
- - Do not use emojis
79
- - Be thorough and precise`;
80
-
81
- case "Plan":
82
- return `${commonHeader}
83
-
84
- # CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS
85
- You are a software architect and planning specialist.
86
- Your role is EXCLUSIVELY to explore the codebase and design implementation plans.
87
- You do NOT have access to file editing tools — attempting to edit files will fail.
88
-
89
- ${READ_ONLY_PROHIBITION}
90
-
91
- # Planning Process
92
- 1. Understand requirements
93
- 2. Explore thoroughly (read files, find patterns, understand architecture)
94
- 3. Design solution based on your assigned perspective
95
- 4. Detail the plan with step-by-step implementation strategy
96
-
97
- # Requirements
98
- - Consider trade-offs and architectural decisions
99
- - Identify dependencies and sequencing
100
- - Anticipate potential challenges
101
- - Follow existing patterns where appropriate
102
-
103
- ${READ_ONLY_TOOLS}
104
-
105
- # Output Format
106
- - Use absolute file paths
107
- - Do not use emojis
108
- - End your response with:
109
-
110
- ### Critical Files for Implementation
111
- List 3-5 files most critical for implementing this plan:
112
- - /absolute/path/to/file.ts - [Brief reason]`;
113
-
114
- case "general-purpose":
115
- return `${commonHeader}
22
+ if (config.promptMode === "append") {
23
+ const genericBase = `
116
24
 
117
25
  # Role
118
26
  You are a general-purpose coding agent for complex, multi-step tasks.
119
27
  You have full access to read, write, edit files, and execute commands.
120
28
  Do what has been asked; nothing more, nothing less.
121
29
 
122
- ${FULL_TOOL_USAGE}
123
-
124
- # File Operations
125
- - NEVER create files unless absolutely necessary
126
- - Prefer editing existing files over creating new ones
127
- - NEVER create documentation files unless explicitly requested
128
-
129
- ${GIT_SAFETY}
130
-
131
- ${OUTPUT_RULES}`;
132
-
133
- case "statusline-setup":
134
- return `${commonHeader}
135
-
136
- # Role
137
- You configure settings. You can read and edit files only.
138
- Focus on the specific configuration task requested.
139
- Use absolute file paths.`;
140
-
141
- case "claude-code-guide":
142
- return `${commonHeader}
143
-
144
- # Role
145
- You help answer questions about the tool, its features, and capabilities.
146
- Search documentation, read config files, and provide accurate answers.
147
- You have read-only access to the codebase for reference.
148
- Use absolute file paths.`;
149
-
150
- default:
151
- // Custom agents or unknown: general-purpose base without git safety / file ops
152
- return `${commonHeader}
153
-
154
- # Role
155
- You are a general-purpose coding agent for complex, multi-step tasks.
156
- You have full access to read, write, edit files, and execute commands.
157
- Do what has been asked; nothing more, nothing less.
30
+ # Tool Usage
31
+ - Use the read tool instead of cat/head/tail
32
+ - Use the edit tool instead of sed/awk
33
+ - Use the write tool instead of echo/heredoc
34
+ - Use the find tool instead of bash find/ls for file search
35
+ - Use the grep tool instead of bash grep/rg for content search
36
+ - Make independent tool calls in parallel
158
37
 
159
- ${FULL_TOOL_USAGE}
38
+ # Output
39
+ - Use absolute file paths
40
+ - Do not use emojis
41
+ - Be concise but complete`;
160
42
 
161
- ${OUTPUT_RULES}`;
43
+ return commonHeader + genericBase + "\n\n" + config.systemPrompt;
162
44
  }
45
+
46
+ // "replace" mode — header + the config's full system prompt
47
+ return commonHeader + "\n\n" + config.systemPrompt;
163
48
  }
package/src/types.ts CHANGED
@@ -7,44 +7,18 @@ import type { ThinkingLevel } from "@mariozechner/pi-agent-core";
7
7
 
8
8
  export type { ThinkingLevel };
9
9
 
10
- /** Built-in agent types. Custom agents use arbitrary string names. */
11
- export type BuiltinSubagentType = "general-purpose" | "Explore" | "Plan" | "statusline-setup" | "claude-code-guide";
10
+ /** Agent type: any string name (built-in defaults or user-defined). */
11
+ export type SubagentType = string;
12
12
 
13
- /** Agent type: built-in or custom (any string). */
14
- export type SubagentType = BuiltinSubagentType | (string & {});
13
+ /** Names of the three embedded default agents. */
14
+ export const DEFAULT_AGENT_NAMES = ["general-purpose", "Explore", "Plan"] as const;
15
15
 
16
- /** Display name mapping for built-in types. */
17
- export const DISPLAY_NAMES: Record<BuiltinSubagentType, string> = {
18
- "general-purpose": "Agent",
19
- "Explore": "Explore",
20
- "Plan": "Plan",
21
- "statusline-setup": "Config",
22
- "claude-code-guide": "Guide",
23
- };
24
-
25
- export const SUBAGENT_TYPES: BuiltinSubagentType[] = [
26
- "general-purpose",
27
- "Explore",
28
- "Plan",
29
- "statusline-setup",
30
- "claude-code-guide",
31
- ];
32
-
33
- export interface SubagentTypeConfig {
34
- displayName: string;
35
- description: string;
36
- builtinToolNames: string[];
37
- /** true = inherit all, string[] = only listed, false = none */
38
- extensions: true | string[] | false;
39
- /** true = inherit all, string[] = only listed, false = none */
40
- skills: true | string[] | false;
41
- }
42
-
43
- /** Configuration for a custom agent loaded from .pi/agents/<name>.md */
44
- export interface CustomAgentConfig {
16
+ /** Unified agent configuration — used for both default and user-defined agents. */
17
+ export interface AgentConfig {
45
18
  name: string;
19
+ displayName?: string;
46
20
  description: string;
47
- builtinToolNames: string[];
21
+ builtinToolNames?: string[];
48
22
  /** true = inherit all, string[] = only listed, false = none */
49
23
  extensions: true | string[] | false;
50
24
  /** true = inherit all, string[] = only listed, false = none */
@@ -60,6 +34,12 @@ export interface CustomAgentConfig {
60
34
  runInBackground: boolean;
61
35
  /** Default for spawn: no extension tools */
62
36
  isolated: boolean;
37
+ /** true = this is an embedded default agent (informational) */
38
+ isDefault?: boolean;
39
+ /** false = agent is hidden from the registry */
40
+ enabled?: boolean;
41
+ /** Where this agent was loaded from */
42
+ source?: "default" | "project" | "global";
63
43
  }
64
44
 
65
45
  export type JoinMode = 'async' | 'group' | 'smart';
@@ -5,6 +5,7 @@
5
5
  * Uses the callback form of setWidget for themed rendering.
6
6
  */
7
7
 
8
+ import { truncateToWidth } from "@mariozechner/pi-tui";
8
9
  import type { AgentManager } from "../agent-manager.js";
9
10
  import type { SubagentType } from "../types.js";
10
11
  import { getConfig } from "../agent-types.js";
@@ -262,17 +263,19 @@ export class AgentWidget {
262
263
  this.widgetFrame++;
263
264
  const frame = SPINNER[this.widgetFrame % SPINNER.length];
264
265
 
265
- this.uiCtx.setWidget("agents", (_tui, theme) => {
266
+ this.uiCtx.setWidget("agents", (tui, theme) => {
267
+ const w = tui.terminal.columns;
268
+ const truncate = (line: string) => truncateToWidth(line, w);
266
269
  const headingColor = hasActive ? "accent" : "dim";
267
270
  const headingIcon = hasActive ? "●" : "○";
268
- const lines: string[] = [theme.fg(headingColor, headingIcon) + " " + theme.fg(headingColor, "Agents")];
271
+ const lines: string[] = [truncate(theme.fg(headingColor, headingIcon) + " " + theme.fg(headingColor, "Agents"))];
269
272
 
270
273
  // --- Finished agents (shown first, dimmed) ---
271
274
  for (let i = 0; i < finished.length; i++) {
272
275
  const a = finished[i];
273
276
  const isLast = !hasActive && i === finished.length - 1;
274
277
  const connector = isLast ? "└─" : "├─";
275
- lines.push(theme.fg("dim", connector) + " " + this.renderFinishedLine(a, theme));
278
+ lines.push(truncate(theme.fg("dim", connector) + " " + this.renderFinishedLine(a, theme)));
276
279
  }
277
280
 
278
281
  // --- Running agents ---
@@ -299,14 +302,14 @@ export class AgentWidget {
299
302
 
300
303
  const activity = bg ? describeActivity(bg.activeTools, bg.responseText) : "thinking…";
301
304
 
302
- lines.push(theme.fg("dim", connector) + ` ${theme.fg("accent", frame)} ${theme.bold(name)} ${theme.fg("muted", a.description)} ${theme.fg("dim", "·")} ${theme.fg("dim", statsText)}`);
305
+ lines.push(truncate(theme.fg("dim", connector) + ` ${theme.fg("accent", frame)} ${theme.bold(name)} ${theme.fg("muted", a.description)} ${theme.fg("dim", "·")} ${theme.fg("dim", statsText)}`));
303
306
  const indent = isLast ? " " : "│ ";
304
- lines.push(theme.fg("dim", indent) + theme.fg("dim", ` ⎿ ${activity}`));
307
+ lines.push(truncate(theme.fg("dim", indent) + theme.fg("dim", ` ⎿ ${activity}`)));
305
308
  }
306
309
 
307
310
  // --- Queued agents (collapsed) ---
308
311
  if (queued.length > 0) {
309
- lines.push(theme.fg("dim", "└─") + ` ${theme.fg("muted", "◦")} ${theme.fg("dim", `${queued.length} queued`)}`);
312
+ lines.push(truncate(theme.fg("dim", "└─") + ` ${theme.fg("muted", "◦")} ${theme.fg("dim", `${queued.length} queued`)}`));
310
313
  }
311
314
 
312
315
  return { render: () => lines, invalidate: () => {} };