@selesai/code 0.4.0 → 0.5.1

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 (60) hide show
  1. package/dist/core/agent-session-auto-handoff.test.d.ts +2 -0
  2. package/dist/core/agent-session-auto-handoff.test.d.ts.map +1 -0
  3. package/dist/core/agent-session-auto-handoff.test.js +161 -0
  4. package/dist/core/agent-session-auto-handoff.test.js.map +1 -0
  5. package/dist/core/agent-session.d.ts +4 -0
  6. package/dist/core/agent-session.d.ts.map +1 -1
  7. package/dist/core/agent-session.js +43 -0
  8. package/dist/core/agent-session.js.map +1 -1
  9. package/dist/core/settings-manager-auto-handoff.test.d.ts +2 -0
  10. package/dist/core/settings-manager-auto-handoff.test.d.ts.map +1 -0
  11. package/dist/core/settings-manager-auto-handoff.test.js +29 -0
  12. package/dist/core/settings-manager-auto-handoff.test.js.map +1 -0
  13. package/dist/core/settings-manager.d.ts +9 -0
  14. package/dist/core/settings-manager.d.ts.map +1 -1
  15. package/dist/core/settings-manager.js +22 -0
  16. package/dist/core/settings-manager.js.map +1 -1
  17. package/dist/extensions/context-compaction-reminder.ts +1 -1
  18. package/dist/extensions/pi-powerline-footer/index.ts +43 -2
  19. package/dist/extensions/pi-powerline-footer/session-usage.ts +44 -0
  20. package/dist/extensions/pi-powerline-footer/tests/session-usage.test.ts +47 -0
  21. package/dist/extensions/pi-subagents/README.md +1 -1
  22. package/dist/extensions/pi-subagents/agents/architect.md +150 -22
  23. package/dist/extensions/pi-subagents/agents/builder.md +1 -1
  24. package/dist/extensions/pi-subagents/agents/commentator.md +2 -2
  25. package/dist/extensions/pi-subagents/agents/explorer.md +2 -3
  26. package/dist/extensions/pi-subagents/agents/recapper.md +2 -2
  27. package/dist/extensions/pi-subagents/agents/researcher.md +2 -2
  28. package/dist/extensions/pi-subagents/src/agents/agents.ts +46 -0
  29. package/dist/extensions/pi-subagents/src/extension/index.ts +2 -1
  30. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +2 -0
  31. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +24 -0
  32. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +25 -1
  33. package/dist/extensions/workflow/adapter.ts +34 -174
  34. package/dist/extensions/workflow/modes/prototype.ts +12 -14
  35. package/dist/extensions/workflow/modes/quick.ts +12 -14
  36. package/dist/extensions/workflow/modes/task.ts +8 -5
  37. package/dist/extensions/workflow/state-machine.ts +3 -0
  38. package/dist/extensions/workflow/task-validators.ts +69 -0
  39. package/dist/index.d.ts +1 -1
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js.map +1 -1
  42. package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
  43. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  44. package/dist/modes/interactive/components/settings-selector.js +20 -0
  45. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  46. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  47. package/dist/modes/interactive/interactive-mode.js +8 -0
  48. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  49. package/dist/modes/rpc/rpc-client.d.ts +8 -0
  50. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  51. package/dist/modes/rpc/rpc-client.js +12 -0
  52. package/dist/modes/rpc/rpc-client.js.map +1 -1
  53. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  54. package/dist/modes/rpc/rpc-mode.js +14 -0
  55. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  56. package/dist/modes/rpc/rpc-types.d.ts +20 -0
  57. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  58. package/dist/modes/rpc/rpc-types.js.map +1 -1
  59. package/docs/workflows.md +9 -4
  60. package/package.json +1 -1
@@ -5,36 +5,164 @@ tools: read, grep, find, ls
5
5
  systemPromptMode: replace
6
6
  inheritProjectContext: true
7
7
  inheritSkills: false
8
- skill: ponytail
9
- output: plan.md
8
+ skill: ponytail, caveman, planger
10
9
  defaultContext: fork
11
10
  ---
12
11
 
13
- You are a planning subagent. Turn the supplied requirements and code context into a concrete implementation plan. Do not edit project files and do not delegate to other subagents; inspect the code yourself.
12
+ ## Goal
14
13
 
15
- Working rules:
16
- - Read supplied artifacts and relevant code before planning. Follow callers and tests when needed.
17
- - Name exact files, symbols, and validation commands whenever evidence permits.
18
- - Prefer the smallest maintainable change. Reuse existing code and avoid speculative abstractions or dependencies.
19
- - Surface unresolved requirements or risks instead of inventing product decisions.
20
- - The configured output artifact is allowed; do not write any other file.
14
+ Create implementation plans that can be executed by a small coding model with:
21
15
 
22
- Output:
16
+ - Limited context window
17
+ - No project knowledge
18
+ - No memory of previous conversation
19
+ - Weak architectural understanding
20
+ - No ability to infer missing steps
23
21
 
24
- # Implementation Plan
22
+ Assume the executor only knows what is written in the plan. Return the complete plan in your final response; do not write an output file.
25
23
 
26
- ## Goal
24
+ # Core Principles
25
+
26
+ ## Discovery First
27
+
28
+ Never assume:
29
+
30
+ - File names
31
+ - File locations
32
+ - Ownership of behavior
33
+ - Existing abstractions
34
+ - Existing utilities
35
+
36
+ If the code has not been inspected, the plan must begin with discovery.
37
+ You research the codebase (using explore agent) → clarify with the user (using questions tool) → capture findings and decisions into a comprehensive plan. This iterative approach catches edge cases and non-obvious requirements BEFORE implementation begins.
38
+
39
+ ## Simplicity First
40
+
41
+ Prefer the smallest maintainable solution that satisfies the requirement.
42
+
43
+ Avoid:
44
+
45
+ - New abstractions
46
+ - New services
47
+ - New dependencies
48
+ - Large refactors
49
+ - Generic frameworks
50
+ - Future-proofing for hypothetical requirements
51
+
52
+ Choose the lowest-complexity solution that works.
53
+
54
+ ## Reuse Before Build
55
+
56
+ Before creating anything new (use explorer agent):
57
+
58
+ - Search for existing implementations
59
+ - Search for existing utilities
60
+ - Search for existing patterns
61
+ - Search for existing tests
62
+
63
+ Reuse existing code when reasonable.
64
+
65
+ Do not duplicate behavior unless duplication is clearly preferable.
66
+
67
+ ## Scope Discipline
68
+
69
+ Only modify code required for the task.
70
+
71
+ Allowed:
72
+
73
+ - Small cleanup in touched files
74
+ - Remove unused imports
75
+ - Remove obvious dead code
76
+ - Improve nearby naming
77
+
78
+ Not allowed:
79
+
80
+ - Unrelated refactors
81
+ - Architecture changes
82
+ - Broad cleanup efforts
83
+ - Dependency migrations
84
+
85
+ # Task Structure
86
+
87
+ Every implementation task must contain:
88
+
89
+ ## 1. Discovery
90
+
91
+ Describe:
92
+
93
+ - What to search for
94
+ - Where to search
95
+ - How to identify relevant code
96
+
97
+ Example:
98
+
99
+ Search for:
100
+
101
+ - Authorization
102
+ - Bearer
103
+ - Interceptor
104
+ - Refresh token
105
+
106
+ Inspect matching files and identify where authentication headers are attached.
107
+
108
+ ## 2. Identification
109
+
110
+ Describe:
111
+
112
+ - Exact file(s) to modify
113
+ - Why those files own the behavior
114
+ - Why other files should not be modified
115
+
116
+ ## 3. Change
117
+
118
+ Describe:
119
+
120
+ - Exact modification required
121
+ - Functions/classes affected
122
+ - Existing code to reuse
123
+ - New code to add
124
+ - Code explicitly not to add
125
+
126
+ The executor should know exactly what to implement.
127
+
128
+ ## 4. Verification
129
+
130
+ Include:
131
+
132
+ ### Success Cases
133
+
134
+ Expected working behavior.
135
+
136
+ ### Failure Cases
137
+
138
+ Expected error behavior.
139
+
140
+ ### Regression Checks
141
+
142
+ Existing behavior that must remain unchanged.
143
+
144
+ # Granularity Rule
145
+
146
+ A task is too large if it can be split into smaller independently verifiable work.
147
+
148
+ Keep decomposing until each task:
149
+
150
+ - Has one objective
151
+ - Has clear ownership
152
+ - Can be implemented independently
153
+ - Can be verified independently
27
154
 
28
- ## Findings
29
- - Relevant files, existing behavior, and constraints.
155
+ Prefer 5 small tasks over 1 large task.
30
156
 
31
- ## Steps
32
- 1. Exact file and change.
33
- 2. Exact file and change.
157
+ # Final Review
34
158
 
35
- ## Verification
36
- - Success cases
37
- - Failure/regression cases
38
- - Commands or manual checks
159
+ Before returning a plan verify:
39
160
 
40
- ## Risks / Open Questions
161
+ - Discovery exists
162
+ - Ownership is justified
163
+ - Solution is the simplest acceptable approach
164
+ - Existing code is reused when possible
165
+ - No unnecessary abstractions are introduced
166
+ - Scope remains limited
167
+ - Verification is included
168
+ - Every step is executable without additional assumptions
@@ -5,7 +5,7 @@ thinking: high
5
5
  systemPromptMode: replace
6
6
  tools: read, grep, find, ls, bash, edit, write, contact_supervisor
7
7
  inheritSkills: false
8
- skill: ponytail, implanger
8
+ skill: ponytail, caveman, implanger
9
9
  inheritProjectContext: true
10
10
  defaultContext: fresh
11
11
  ---
@@ -7,11 +7,11 @@ systemPromptMode: replace
7
7
  inheritProjectContext: true
8
8
  inheritSkills: false
9
9
  defaultContext: fresh
10
- output: review.md
10
+ skill: ponytail, caveman, planger
11
11
  completionGuard: false
12
12
  ---
13
13
 
14
- You are a review-only subagent. Inspect and report evidence-backed findings; do not edit project files, do not use shell commands that mutate state, and do not launch subagents. The configured output artifact is allowed.
14
+ You are a review-only subagent. Inspect and report evidence-backed findings; do not edit project files, write output files, use shell commands that mutate state, or launch subagents.
15
15
 
16
16
  Review the supplied target directly. For code, inspect the actual diff, callers, relevant tests, and requirements—not just another agent's summary. Use `bash` only for read-only inspection or test commands.
17
17
 
@@ -5,12 +5,11 @@ tools: read, grep, find, ls
5
5
  systemPromptMode: replace
6
6
  inheritProjectContext: true
7
7
  inheritSkills: false
8
- skill: caveman
9
- output: context.md
8
+ skill: ponytail, caveman
10
9
  defaultContext: fresh
11
10
  ---
12
11
 
13
- You are a codebase reconnaissance subagent. Inspect the repository and return only the minimum verified context another agent needs to act. Do not edit project files and do not launch subagents. The configured output artifact is allowed.
12
+ You are a codebase reconnaissance subagent. Inspect the repository and return only the minimum verified context another agent needs to act. Do not edit project files, write output files, or launch subagents.
14
13
 
15
14
  Use targeted `grep`, `find`, `ls`, and `read`. Follow imports, callers, tests, and configuration far enough to establish the real behavior. Do not guess.
16
15
 
@@ -5,11 +5,11 @@ tools: read, grep, find, ls
5
5
  systemPromptMode: replace
6
6
  inheritProjectContext: true
7
7
  inheritSkills: false
8
+ skill: ponytail, caveman
8
9
  defaultContext: fork
9
- output: handoff.md
10
10
  ---
11
11
 
12
- Create a concise, self-contained handoff for a fresh agent. Use the inherited conversation, supplied artifacts, and relevant repository evidence. Do not edit project files or launch subagents. The configured output artifact is allowed.
12
+ Create a concise, self-contained handoff for a fresh agent. Use the inherited conversation, supplied artifacts, and relevant repository evidence. Do not edit project files, write output files, or launch subagents.
13
13
 
14
14
  Do not duplicate plans, ADRs, issues, commits, diffs, or other artifacts: reference them by exact path or URL. Redact secrets and personal data. If the task names a next focus, tailor the handoff to it.
15
15
 
@@ -6,11 +6,11 @@ thinking: medium
6
6
  systemPromptMode: replace
7
7
  inheritProjectContext: false
8
8
  inheritSkills: false
9
- output: research.md
10
9
  defaultContext: fresh
10
+ skill: ponytail, caveman
11
11
  ---
12
12
 
13
- You are a web research subagent. Answer the supplied question with a concise, well-sourced brief. Do not edit project files or launch subagents. The configured output artifact is allowed.
13
+ You are a web research subagent. Answer the supplied question with a concise, well-sourced brief. Do not edit project files, write output files, or launch subagents.
14
14
 
15
15
  Use `web_explore` for focused search/fetch/source ranking. Start with 2–4 distinct angles, prioritize primary and official sources, then narrow follow-ups only for material gaps. Do not fetch URLs through shell commands.
16
16
 
@@ -543,6 +543,52 @@ function getUserAgentSettingsPath(): string {
543
543
  return path.join(getAgentDir(), "settings.json");
544
544
  }
545
545
 
546
+ /**
547
+ * Seed the user-visible subagent configuration on first session startup.
548
+ *
549
+ * Builtin agents normally inherit the parent session model. Recording that
550
+ * model as `subagents.defaultModel` makes the default explicit. Each bundled
551
+ * role is also written to `agentOverrides`, so users can see and edit its
552
+ * effective model without changing unrelated user settings.
553
+ */
554
+ export function ensureDefaultUserSubagentSettings(currentModel: { provider: string; id: string } | undefined): boolean {
555
+ if (!currentModel?.provider || !currentModel.id) return false;
556
+
557
+ const filePath = getUserAgentSettingsPath();
558
+ const settings = readSettingsFileStrict(filePath);
559
+ const existing = settings.subagents;
560
+ if (existing !== undefined && (!existing || typeof existing !== "object" || Array.isArray(existing))) return false;
561
+
562
+ const subagents = (existing ?? {}) as Record<string, unknown>;
563
+ const currentModelId = `${currentModel.provider}/${currentModel.id}`;
564
+ if ("defaultModel" in subagents && (typeof subagents.defaultModel !== "string" || !subagents.defaultModel.trim())) return false;
565
+
566
+ let changed = false;
567
+ if (!("defaultModel" in subagents)) {
568
+ subagents.defaultModel = currentModelId;
569
+ changed = true;
570
+ }
571
+
572
+ const defaultModel = subagents.defaultModel as string;
573
+ const overrides = subagents.agentOverrides;
574
+ const shouldSeedOverrides = overrides === undefined
575
+ || (overrides !== null && typeof overrides === "object" && !Array.isArray(overrides) && Object.keys(overrides).length === 0);
576
+ if (shouldSeedOverrides) {
577
+ subagents.agentOverrides = Object.fromEntries(
578
+ loadAgentsFromDir(BUILTIN_AGENTS_DIR, "builtin").map((agent) => [
579
+ agent.name,
580
+ { model: agent.model ?? defaultModel },
581
+ ]),
582
+ );
583
+ changed = true;
584
+ }
585
+ if (!changed) return false;
586
+
587
+ settings.subagents = subagents;
588
+ writeSettingsFile(filePath, settings);
589
+ return true;
590
+ }
591
+
546
592
  function getProjectAgentSettingsPath(cwd: string): string | null {
547
593
  const projectRoot = findNearestProjectRoot(cwd);
548
594
  return projectRoot ? path.join(getProjectConfigDir(projectRoot), "settings.json") : null;
@@ -19,7 +19,7 @@ import * as path from "node:path";
19
19
  import type { AgentToolResult } from "@earendil-works/pi-agent-core";
20
20
  import { keyText, type ExtensionAPI, type ExtensionContext, type ToolDefinition } from "@selesai/code";
21
21
  import { Box, Container, Spacer, Text, truncateToWidth, visibleWidth, wrapTextWithAnsi, type Component } from "@earendil-works/pi-tui";
22
- import { discoverAgents } from "../agents/agents.ts";
22
+ import { discoverAgents, ensureDefaultUserSubagentSettings } from "../agents/agents.ts";
23
23
  import { cleanupAllArtifactDirs, cleanupOldArtifacts, getArtifactsDir } from "../shared/artifacts.ts";
24
24
  import { resolveCurrentSessionId } from "../shared/session-identity.ts";
25
25
  import { cleanupOldChainDirs } from "../shared/settings.ts";
@@ -584,6 +584,7 @@ wait also returns when a run needs attention (a child that went idle or blocked
584
584
  };
585
585
 
586
586
  const resetSessionState = (ctx: ExtensionContext) => {
587
+ ensureDefaultUserSubagentSettings(ctx.model);
587
588
  state.baseCwd = ctx.cwd;
588
589
  state.currentSessionId = resolveCurrentSessionId(ctx.sessionManager);
589
590
  state.subagentSpawns = { sessionId: state.currentSessionId, count: 0 };
@@ -5,6 +5,7 @@ import { createFileCoalescer } from "../../shared/file-coalescer.ts";
5
5
  import {
6
6
  SUBAGENT_ASYNC_COMPLETE_EVENT,
7
7
  type IntercomEventBus,
8
+ type Usage,
8
9
  type NestedRunSummary,
9
10
  type SubagentResultIntercomChild,
10
11
  type SubagentState,
@@ -61,6 +62,7 @@ type ResultFileData = {
61
62
  sessionFile?: string;
62
63
  asyncDir?: string;
63
64
  intercomTarget?: string;
65
+ totalChildUsage?: Usage;
64
66
  };
65
67
 
66
68
  function sanitizeNestedResultChildren(value: unknown, resultPath: string, label: string): NestedRunSummary[] | undefined {
@@ -254,6 +254,19 @@ function emptyUsage(): Usage {
254
254
  return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, turns: 0 };
255
255
  }
256
256
 
257
+ function usageFromAttempts(attempts: ModelAttempt[] | undefined): Usage {
258
+ const usage = emptyUsage();
259
+ for (const attempt of attempts ?? []) {
260
+ usage.input += attempt.usage?.input ?? 0;
261
+ usage.output += attempt.usage?.output ?? 0;
262
+ usage.cacheRead += attempt.usage?.cacheRead ?? 0;
263
+ usage.cacheWrite += attempt.usage?.cacheWrite ?? 0;
264
+ usage.cost += attempt.usage?.cost ?? 0;
265
+ usage.turns += attempt.usage?.turns ?? 0;
266
+ }
267
+ return usage;
268
+ }
269
+
257
270
  function tokenUsageFromAttempts(attempts: ModelAttempt[] | undefined): TokenUsage | null {
258
271
  if (!attempts || attempts.length === 0) return null;
259
272
  let input = 0;
@@ -2959,6 +2972,16 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
2959
2972
  costUsd: sum.costUsd + (result.totalCost?.costUsd ?? 0),
2960
2973
  }), { inputTokens: 0, outputTokens: 0, costUsd: 0 });
2961
2974
  const finalTotalCost = totalCost.inputTokens > 0 || totalCost.outputTokens > 0 || totalCost.costUsd > 0 ? totalCost : undefined;
2975
+ const totalChildUsage = results.reduce<Usage>((sum, result) => {
2976
+ const usage = usageFromAttempts(result.modelAttempts);
2977
+ sum.input += usage.input;
2978
+ sum.output += usage.output;
2979
+ sum.cacheRead += usage.cacheRead;
2980
+ sum.cacheWrite += usage.cacheWrite;
2981
+ sum.cost += usage.cost;
2982
+ sum.turns += usage.turns;
2983
+ return sum;
2984
+ }, emptyUsage());
2962
2985
  const finalFlatAgents = statusPayload.steps.map((step) => step.agent);
2963
2986
  const agentName = finalFlatAgents.length === 1
2964
2987
  ? finalFlatAgents[0]!
@@ -3113,6 +3136,7 @@ async function runSubagent(config: SubagentRunConfig): Promise<void> {
3113
3136
  timestamp: runEndedAt,
3114
3137
  durationMs: runEndedAt - overallStartTime,
3115
3138
  totalTokens: statusPayload.totalTokens,
3139
+ totalChildUsage,
3116
3140
  totalCost: finalTotalCost,
3117
3141
  truncated,
3118
3142
  artifactsDir,
@@ -3,7 +3,7 @@ import * as fs from "node:fs";
3
3
  import * as os from "node:os";
4
4
  import * as path from "node:path";
5
5
  import { afterEach, beforeEach, describe, it } from "node:test";
6
- import { discoverAgentsAll } from "../../src/agents/agents.ts";
6
+ import { discoverAgentsAll, ensureDefaultUserSubagentSettings } from "../../src/agents/agents.ts";
7
7
  import { handleCreate } from "../../src/agents/agent-management.ts";
8
8
  import { clearSkillCache, discoverAvailableSkills, resolveSkillPath } from "../../src/agents/skills.ts";
9
9
  import { loadConfig } from "../../src/extension/config.ts";
@@ -86,6 +86,30 @@ describe("SELESAI_CODING_AGENT_DIR runtime paths", () => {
86
86
  assert.equal(config.maxSubagentDepth, 3);
87
87
  });
88
88
 
89
+ it("seeds an editable user subagent model default without replacing existing settings", () => {
90
+ const settingsPath = path.join(agentDir, "settings.json");
91
+ writeFile(settingsPath, JSON.stringify({ defaultModel: "openai/gpt-5", packages: ["npm:example"] }, null, 2));
92
+
93
+ assert.equal(ensureDefaultUserSubagentSettings({ provider: "anthropic", id: "claude-sonnet-4" }), true);
94
+ assert.deepEqual(JSON.parse(fs.readFileSync(settingsPath, "utf-8")), {
95
+ defaultModel: "openai/gpt-5",
96
+ packages: ["npm:example"],
97
+ subagents: {
98
+ defaultModel: "anthropic/claude-sonnet-4",
99
+ agentOverrides: {
100
+ architect: { model: "anthropic/claude-sonnet-4" },
101
+ builder: { model: "anthropic/claude-sonnet-4" },
102
+ commentator: { model: "anthropic/claude-sonnet-4" },
103
+ explorer: { model: "anthropic/claude-sonnet-4" },
104
+ recapper: { model: "anthropic/claude-sonnet-4" },
105
+ researcher: { model: "anthropic/claude-sonnet-4" },
106
+ },
107
+ },
108
+ });
109
+ assert.equal(ensureDefaultUserSubagentSettings({ provider: "openai", id: "gpt-5-mini" }), false);
110
+ assert.equal(ensureDefaultUserSubagentSettings(undefined), false);
111
+ });
112
+
89
113
  it("discovers user agents, chains, and settings under the configured agent dir", () => {
90
114
  const settingsPath = path.join(agentDir, "settings.json");
91
115
  writeFile(path.join(agentDir, "agents", "env-agent.md"), `---