@leing2021/super-pi 0.22.0 → 0.23.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.
Files changed (101) hide show
  1. package/README.md +38 -209
  2. package/extensions/ce-core/index.ts +190 -7
  3. package/extensions/ce-core/tools/parallel-subagent.ts +3 -3
  4. package/extensions/ce-core/tools/subagent.ts +2 -2
  5. package/package.json +4 -18
  6. package/rules/common/naming.md +154 -0
  7. package/skills/02-plan/SKILL.md +3 -2
  8. package/skills/03-work/SKILL.md +9 -6
  9. package/skills/04-review/SKILL.md +3 -2
  10. package/skills/06-next/SKILL.md +38 -10
  11. package/skills/06-next/references/recommendation-logic.md +2 -2
  12. package/skills/07-worktree/SKILL.md +9 -8
  13. package/skills/{09-help → 08-help}/SKILL.md +3 -3
  14. package/skills/{09-help → 08-help}/references/workflow-sequence.md +2 -1
  15. package/skills/references/language-detection.md +44 -0
  16. package/extensions/subagent/agent-management.ts +0 -595
  17. package/extensions/subagent/agent-manager-chain-detail.ts +0 -162
  18. package/extensions/subagent/agent-manager-detail.ts +0 -231
  19. package/extensions/subagent/agent-manager-edit.ts +0 -390
  20. package/extensions/subagent/agent-manager-list.ts +0 -278
  21. package/extensions/subagent/agent-manager-parallel.ts +0 -304
  22. package/extensions/subagent/agent-manager.ts +0 -705
  23. package/extensions/subagent/agent-scope.ts +0 -8
  24. package/extensions/subagent/agent-selection.ts +0 -25
  25. package/extensions/subagent/agent-serializer.ts +0 -123
  26. package/extensions/subagent/agent-templates.ts +0 -62
  27. package/extensions/subagent/agents/context-builder.md +0 -37
  28. package/extensions/subagent/agents/delegate.md +0 -9
  29. package/extensions/subagent/agents/oracle.md +0 -73
  30. package/extensions/subagent/agents/planner.md +0 -52
  31. package/extensions/subagent/agents/researcher.md +0 -50
  32. package/extensions/subagent/agents/reviewer.md +0 -38
  33. package/extensions/subagent/agents/scout.md +0 -48
  34. package/extensions/subagent/agents/worker.md +0 -52
  35. package/extensions/subagent/agents.ts +0 -761
  36. package/extensions/subagent/artifacts.ts +0 -100
  37. package/extensions/subagent/async-execution.ts +0 -520
  38. package/extensions/subagent/async-job-tracker.ts +0 -216
  39. package/extensions/subagent/async-status.ts +0 -241
  40. package/extensions/subagent/chain-clarify.ts +0 -1364
  41. package/extensions/subagent/chain-execution.ts +0 -853
  42. package/extensions/subagent/chain-serializer.ts +0 -126
  43. package/extensions/subagent/completion-dedupe.ts +0 -65
  44. package/extensions/subagent/doctor.ts +0 -200
  45. package/extensions/subagent/execution.ts +0 -738
  46. package/extensions/subagent/file-coalescer.ts +0 -42
  47. package/extensions/subagent/fork-context.ts +0 -63
  48. package/extensions/subagent/formatters.ts +0 -122
  49. package/extensions/subagent/frontmatter.ts +0 -31
  50. package/extensions/subagent/index.ts +0 -585
  51. package/extensions/subagent/intercom-bridge.ts +0 -240
  52. package/extensions/subagent/jsonl-writer.ts +0 -83
  53. package/extensions/subagent/model-fallback.ts +0 -108
  54. package/extensions/subagent/notify.ts +0 -110
  55. package/extensions/subagent/parallel-utils.ts +0 -108
  56. package/extensions/subagent/pi-args.ts +0 -138
  57. package/extensions/subagent/pi-spawn.ts +0 -100
  58. package/extensions/subagent/post-exit-stdio-guard.ts +0 -87
  59. package/extensions/subagent/prompt-template-bridge.ts +0 -399
  60. package/extensions/subagent/prompts/gather-context-and-clarify.md +0 -13
  61. package/extensions/subagent/prompts/parallel-cleanup.md +0 -42
  62. package/extensions/subagent/prompts/parallel-research.md +0 -50
  63. package/extensions/subagent/prompts/parallel-review.md +0 -40
  64. package/extensions/subagent/render-helpers.ts +0 -82
  65. package/extensions/subagent/render.ts +0 -836
  66. package/extensions/subagent/result-intercom.ts +0 -237
  67. package/extensions/subagent/result-watcher.ts +0 -171
  68. package/extensions/subagent/run-history.ts +0 -57
  69. package/extensions/subagent/run-status.ts +0 -136
  70. package/extensions/subagent/schemas.ts +0 -164
  71. package/extensions/subagent/session-tokens.ts +0 -50
  72. package/extensions/subagent/settings.ts +0 -367
  73. package/extensions/subagent/single-output.ts +0 -97
  74. package/extensions/subagent/skills.ts +0 -626
  75. package/extensions/subagent/slash-bridge.ts +0 -176
  76. package/extensions/subagent/slash-commands.ts +0 -303
  77. package/extensions/subagent/slash-live-state.ts +0 -294
  78. package/extensions/subagent/subagent-control.ts +0 -150
  79. package/extensions/subagent/subagent-executor.ts +0 -1899
  80. package/extensions/subagent/subagent-prompt-runtime.ts +0 -75
  81. package/extensions/subagent/subagent-runner.ts +0 -1470
  82. package/extensions/subagent/subagents-status.ts +0 -472
  83. package/extensions/subagent/text-editor.ts +0 -272
  84. package/extensions/subagent/top-level-async.ts +0 -15
  85. package/extensions/subagent/types.ts +0 -623
  86. package/extensions/subagent/utils.ts +0 -456
  87. package/extensions/subagent/worktree.ts +0 -579
  88. package/extensions/super-pi-extension/agents/ce-oracle.md +0 -109
  89. package/extensions/super-pi-extension/agents/ce-planner.md +0 -116
  90. package/extensions/super-pi-extension/agents/ce-reviewer.md +0 -99
  91. package/extensions/super-pi-extension/agents/ce-scout.md +0 -80
  92. package/extensions/super-pi-extension/agents/ce-worker.md +0 -78
  93. package/extensions/super-pi-extension/chains/ce-parallel-review.chain.md +0 -34
  94. package/extensions/super-pi-extension/chains/ce-review-only.chain.md +0 -12
  95. package/extensions/super-pi-extension/chains/ce-standard.chain.md +0 -28
  96. package/extensions/super-pi-extension/index.ts +0 -129
  97. package/extensions/super-pi-extension/model-sync.ts +0 -204
  98. package/skills/08-status/SKILL.md +0 -41
  99. package/skills/08-status/references/artifact-locations.md +0 -10
  100. package/skills/10-rules/SKILL.md +0 -76
  101. package/skills/pi-subagents/SKILL.md +0 -566
@@ -1,162 +0,0 @@
1
- // Based on pi-subagents by Nico Bailon (https://github.com/nicobailon/pi-subagents)
2
- // MIT License
3
- import type { Theme } from "@mariozechner/pi-coding-agent";
4
- import { matchesKey, truncateToWidth } from "@mariozechner/pi-tui";
5
- import type { ChainConfig, ChainStepConfig } from "./agents.ts";
6
- import { row, renderFooter, renderHeader, formatPath, formatScrollInfo } from "./render-helpers.ts";
7
- import { isParallelStep, type ChainStep } from "./settings.ts";
8
-
9
- export interface ChainDetailState {
10
- scrollOffset: number;
11
- }
12
-
13
- export type ChainDetailAction =
14
- | { type: "back" }
15
- | { type: "launch" }
16
- | { type: "edit" };
17
-
18
- const CHAIN_DETAIL_VIEWPORT_HEIGHT = 12;
19
-
20
- type DetailChainStep = ChainStepConfig | ChainStep;
21
-
22
- export function buildDependencyMap(steps: DetailChainStep[]): Map<number, number[]> {
23
- const outputMap = new Map<string, number>();
24
- const deps = new Map<number, number[]>();
25
- for (let i = 0; i < steps.length; i++) {
26
- const step = steps[i]!;
27
- if (isParallelStep(step as ChainStep)) {
28
- const reads = step.parallel.flatMap((task) => Array.isArray(task.reads) ? task.reads : []);
29
- const sources = reads
30
- .map((file) => outputMap.get(file))
31
- .filter((idx): idx is number => idx !== undefined);
32
- if (sources.length > 0) deps.set(i, [...new Set(sources)]);
33
- for (const task of step.parallel) {
34
- if (typeof task.output === "string" && task.output.length > 0) outputMap.set(task.output, i);
35
- }
36
- continue;
37
- }
38
- if (typeof step.output === "string" && step.output.length > 0) outputMap.set(step.output, i);
39
- if (Array.isArray(step.reads) && step.reads.length > 0) {
40
- const sources = step.reads
41
- .map((file) => outputMap.get(file))
42
- .filter((idx): idx is number => idx !== undefined);
43
- if (sources.length > 0) deps.set(i, sources);
44
- }
45
- }
46
- return deps;
47
- }
48
-
49
- function buildChainDetailLines(chain: ChainConfig, width: number): string[] {
50
- const contentWidth = width - 3;
51
- const lines: string[] = [];
52
- const steps = chain.steps as DetailChainStep[];
53
- const dependencyMap = buildDependencyMap(steps);
54
- lines.push(truncateToWidth(chain.description, contentWidth));
55
- lines.push("");
56
- lines.push(truncateToWidth(`File: ${formatPath(chain.filePath)}`, contentWidth));
57
- lines.push("");
58
- lines.push(truncateToWidth("── Flow ──", contentWidth));
59
-
60
- for (let i = 0; i < steps.length; i++) {
61
- const step = steps[i]!;
62
- const sources = dependencyMap.get(i);
63
- const fromText = sources && sources.length > 0 ? ` (from ${sources.map((s) => s + 1).join(", ")})` : "";
64
- if (isParallelStep(step as ChainStep)) {
65
- lines.push(truncateToWidth(` ${i + 1} Parallel: ${step.parallel.map((task) => task.agent).join(" + ")}`, contentWidth));
66
- if (step.concurrency !== undefined) lines.push(truncateToWidth(` concurrency: ${step.concurrency}`, contentWidth));
67
- if (step.failFast !== undefined) lines.push(truncateToWidth(` fail fast: ${step.failFast ? "on" : "off"}`, contentWidth));
68
- if (step.worktree !== undefined) lines.push(truncateToWidth(` worktree: ${step.worktree ? "on" : "off"}`, contentWidth));
69
- for (let taskIndex = 0; taskIndex < step.parallel.length; taskIndex++) {
70
- const task = step.parallel[taskIndex]!;
71
- lines.push(truncateToWidth(` ${taskIndex + 1}. ${task.agent}`, contentWidth));
72
- const taskPreview = (task.task ?? "").split("\n")[0] ?? "";
73
- if (taskPreview) lines.push(truncateToWidth(` task: ${taskPreview}`, contentWidth));
74
- if (Array.isArray(task.reads) && task.reads.length > 0) lines.push(truncateToWidth(` ← reads: ${task.reads.join(", ")}${fromText}`, contentWidth));
75
- else if (task.reads === false) lines.push(truncateToWidth(" ← reads: (disabled)", contentWidth));
76
- if (typeof task.output === "string" && task.output.length > 0) lines.push(truncateToWidth(` → output: ${task.output}`, contentWidth));
77
- else if (task.output === false) lines.push(truncateToWidth(" → output: (disabled)", contentWidth));
78
- if (task.model) lines.push(truncateToWidth(` model: ${task.model}`, contentWidth));
79
- if (task.skill !== undefined) {
80
- const skillsText =
81
- task.skill === false
82
- ? "(disabled)"
83
- : Array.isArray(task.skill)
84
- ? (task.skill.length > 0 ? task.skill.join(", ") : "(none)")
85
- : task.skill;
86
- lines.push(truncateToWidth(` skills: ${skillsText}`, contentWidth));
87
- }
88
- if (task.progress !== undefined) lines.push(truncateToWidth(` progress: ${task.progress ? "on" : "off"}`, contentWidth));
89
- }
90
- lines.push("");
91
- continue;
92
- }
93
- lines.push(truncateToWidth(` ${i + 1} ${step.agent}`, contentWidth));
94
- const taskPreview = step.task.split("\n")[0] ?? "";
95
- lines.push(truncateToWidth(` task: ${taskPreview || "(none)"}`, contentWidth));
96
- if (Array.isArray(step.reads) && step.reads.length > 0) {
97
- lines.push(truncateToWidth(` ← reads: ${step.reads.join(", ")}${fromText}`, contentWidth));
98
- } else if (step.reads === false) {
99
- lines.push(truncateToWidth(" ← reads: (disabled)", contentWidth));
100
- }
101
- if (typeof step.output === "string" && step.output.length > 0) {
102
- lines.push(truncateToWidth(` → output: ${step.output}`, contentWidth));
103
- } else if (step.output === false) {
104
- lines.push(truncateToWidth(" → output: (disabled)", contentWidth));
105
- }
106
- if (step.model) lines.push(truncateToWidth(` model: ${step.model}`, contentWidth));
107
- if (step.skills !== undefined) {
108
- const skillsText =
109
- step.skills === false
110
- ? "(disabled)"
111
- : step.skills.length > 0
112
- ? step.skills.join(", ")
113
- : "(none)";
114
- lines.push(truncateToWidth(` skills: ${skillsText}`, contentWidth));
115
- }
116
- if (step.progress !== undefined) {
117
- lines.push(truncateToWidth(` progress: ${step.progress ? "on" : "off"}`, contentWidth));
118
- }
119
- lines.push("");
120
- }
121
-
122
- if (chain.steps.length === 0) {
123
- lines.push(truncateToWidth("(no steps)", contentWidth));
124
- }
125
-
126
- return lines;
127
- }
128
-
129
- export function handleChainDetailInput(state: ChainDetailState, data: string): ChainDetailAction | undefined {
130
- if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) return { type: "back" };
131
- if (data === "l") return { type: "launch" };
132
- if (data === "e") return { type: "edit" };
133
- if (matchesKey(data, "up")) { state.scrollOffset--; return; }
134
- if (matchesKey(data, "down")) { state.scrollOffset++; return; }
135
- if (matchesKey(data, "pageup") || matchesKey(data, "shift+up")) { state.scrollOffset -= CHAIN_DETAIL_VIEWPORT_HEIGHT; return; }
136
- if (matchesKey(data, "pagedown") || matchesKey(data, "shift+down")) { state.scrollOffset += CHAIN_DETAIL_VIEWPORT_HEIGHT; return; }
137
- return;
138
- }
139
-
140
- export function renderChainDetail(
141
- state: ChainDetailState,
142
- chain: ChainConfig,
143
- width: number,
144
- theme: Theme,
145
- ): string[] {
146
- const lines: string[] = [];
147
- const scopeBadge = chain.source === "user" ? "[user]" : "[proj]";
148
- lines.push(renderHeader(` ${chain.name} [chain] ${scopeBadge} `, width, theme));
149
- lines.push(row("", width, theme));
150
-
151
- const contentLines = buildChainDetailLines(chain, width);
152
- const maxOffset = Math.max(0, contentLines.length - CHAIN_DETAIL_VIEWPORT_HEIGHT);
153
- state.scrollOffset = Math.max(0, Math.min(state.scrollOffset, maxOffset));
154
- const visible = contentLines.slice(state.scrollOffset, state.scrollOffset + CHAIN_DETAIL_VIEWPORT_HEIGHT);
155
- for (const line of visible) lines.push(row(` ${line}`, width, theme));
156
- for (let i = visible.length; i < CHAIN_DETAIL_VIEWPORT_HEIGHT; i++) lines.push(row("", width, theme));
157
-
158
- const scrollInfo = formatScrollInfo(state.scrollOffset, Math.max(0, contentLines.length - (state.scrollOffset + CHAIN_DETAIL_VIEWPORT_HEIGHT)));
159
- lines.push(row(scrollInfo ? ` ${theme.fg("dim", scrollInfo)}` : "", width, theme));
160
- lines.push(renderFooter(" [l]aunch [e]dit [↑↓] scroll [esc] back ", width, theme));
161
- return lines;
162
- }
@@ -1,231 +0,0 @@
1
- // Based on pi-subagents by Nico Bailon (https://github.com/nicobailon/pi-subagents)
2
- // MIT License
3
- import type { Theme } from "@mariozechner/pi-coding-agent";
4
- import { matchesKey, truncateToWidth } from "@mariozechner/pi-tui";
5
- import type { AgentConfig } from "./agents.ts";
6
- import { formatDuration } from "./formatters.ts";
7
- import type { RunEntry } from "./run-history.ts";
8
- import { buildSkillInjection, resolveSkills } from "./skills.ts";
9
- import { ensureCursorVisible, getCursorDisplayPos, renderEditor, wrapText } from "./text-editor.ts";
10
- import type { TextEditorState } from "./text-editor.ts";
11
- import { pad, row, renderHeader, renderFooter, formatPath, formatScrollInfo } from "./render-helpers.ts";
12
-
13
- export interface DetailState {
14
- resolved: boolean;
15
- scrollOffset: number;
16
- recentRuns?: RunEntry[];
17
- }
18
-
19
- export type DetailAction =
20
- | { type: "back" }
21
- | { type: "edit" }
22
- | { type: "launch" };
23
-
24
- const DETAIL_VIEWPORT_HEIGHT = 12;
25
-
26
- function renderFieldLine(
27
- label: string,
28
- value: string,
29
- width: number,
30
- theme: Theme,
31
- ): string {
32
- const labelWidth = 12;
33
- const labelText = theme.fg("dim", pad(label, labelWidth));
34
- const available = Math.max(0, width - labelWidth);
35
- return `${labelText}${truncateToWidth(value, available)}`;
36
- }
37
-
38
- function formatRelativeTime(ts: number): string {
39
- const diff = Math.max(0, Math.floor(Date.now() / 1000) - ts);
40
- if (diff < 60) return `${diff}s ago`;
41
- if (diff < 3600) return `${Math.floor(diff / 60)}m ago`;
42
- if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`;
43
- return `${Math.floor(diff / 86400)}d ago`;
44
- }
45
-
46
- function buildDetailLines(
47
- agent: AgentConfig,
48
- resolved: boolean,
49
- recentRuns: RunEntry[] | undefined,
50
- cwd: string,
51
- width: number,
52
- theme: Theme,
53
- ): string[] {
54
- const contentWidth = width - 3;
55
- const lines: string[] = [];
56
-
57
- const tools = agent.tools && agent.tools.length > 0 ? agent.tools.join(", ") : "(none)";
58
- const mcp = agent.mcpDirectTools && agent.mcpDirectTools.length > 0 ? agent.mcpDirectTools.join(", ") : "(none)";
59
- const skillsList = agent.skills && agent.skills.length > 0 ? agent.skills.join(", ") : "(none)";
60
- const output = agent.output ?? "(none)";
61
- const reads = agent.defaultReads && agent.defaultReads.length > 0 ? agent.defaultReads.join(", ") : "(none)";
62
- const progress = agent.defaultProgress ? "on" : "off";
63
- const maxSubagentDepth = agent.maxSubagentDepth !== undefined ? String(agent.maxSubagentDepth) : "(default)";
64
-
65
- lines.push(renderFieldLine("Model:", agent.model ?? "default", contentWidth, theme));
66
- lines.push(renderFieldLine("Prompt mode:", agent.systemPromptMode, contentWidth, theme));
67
- lines.push(renderFieldLine("Project ctx:", agent.inheritProjectContext ? "on" : "off", contentWidth, theme));
68
- lines.push(renderFieldLine("Skills ctx:", agent.inheritSkills ? "on" : "off", contentWidth, theme));
69
- if (agent.source === "builtin") {
70
- lines.push(renderFieldLine("Disabled:", agent.disabled ? "on" : "off", contentWidth, theme));
71
- }
72
- if (agent.override) {
73
- const overrideLabel = `${agent.override.scope} · ${formatPath(agent.override.path)}`;
74
- lines.push(renderFieldLine("Override:", overrideLabel, contentWidth, theme));
75
- }
76
- lines.push(renderFieldLine("Thinking:", agent.thinking ?? "off", contentWidth, theme));
77
- lines.push(renderFieldLine("Tools:", tools, contentWidth, theme));
78
- lines.push(renderFieldLine("MCP:", mcp, contentWidth, theme));
79
- lines.push(renderFieldLine("Skills:", skillsList, contentWidth, theme));
80
- const extensionsList = agent.extensions !== undefined
81
- ? (agent.extensions.length > 0 ? agent.extensions.join(", ") : "(none)")
82
- : "(all)";
83
- lines.push(renderFieldLine("Extensions:", extensionsList, contentWidth, theme));
84
- lines.push(renderFieldLine("Output:", output, contentWidth, theme));
85
- lines.push(renderFieldLine("Reads:", reads, contentWidth, theme));
86
- lines.push(renderFieldLine("Progress:", progress, contentWidth, theme));
87
- lines.push(renderFieldLine("Max depth:", maxSubagentDepth, contentWidth, theme));
88
-
89
- if (agent.extraFields) {
90
- for (const [key, value] of Object.entries(agent.extraFields)) {
91
- lines.push(truncateToWidth(`${key}: ${value}`, contentWidth));
92
- }
93
- }
94
-
95
- lines.push("");
96
- const sectionTitle = `── System Prompt (${resolved ? "resolved" : "raw"}) ──`;
97
- lines.push(truncateToWidth(sectionTitle, contentWidth));
98
-
99
- let prompt = agent.systemPrompt ?? "";
100
- if (resolved) {
101
- const { resolved: resolvedSkills } = resolveSkills(agent.skills ?? [], cwd);
102
- const injection = buildSkillInjection(resolvedSkills);
103
- if (injection) prompt = `${prompt}\n\n${injection}`;
104
- }
105
-
106
- const wrapped = wrapText(prompt, contentWidth);
107
- lines.push(...wrapped.lines);
108
- lines.push("");
109
- lines.push(truncateToWidth("── Recent Runs ──", contentWidth));
110
- if (!recentRuns || recentRuns.length === 0) {
111
- lines.push(truncateToWidth(" (none)", contentWidth));
112
- return lines;
113
- }
114
-
115
- for (const run of recentRuns) {
116
- const when = pad(formatRelativeTime(run.ts), 8);
117
- const status = run.status;
118
- const task = truncateToWidth(`"${run.task}"`, 34);
119
- const tail = run.status === "ok" ? formatDuration(run.duration) : `exit ${run.exit ?? 1}`;
120
- lines.push(truncateToWidth(` ${when} ${status} ${task} ${tail}`, contentWidth));
121
- }
122
-
123
- return lines;
124
- }
125
-
126
- export function handleDetailInput(state: DetailState, data: string): DetailAction | undefined {
127
- if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) return { type: "back" };
128
- if (data === "e") return { type: "edit" };
129
- if (data === "l") return { type: "launch" };
130
- if (data === "v") { state.resolved = !state.resolved; state.scrollOffset = 0; return; }
131
- if (matchesKey(data, "up")) { state.scrollOffset--; return; }
132
- if (matchesKey(data, "down")) { state.scrollOffset++; return; }
133
- if (matchesKey(data, "pageup") || matchesKey(data, "shift+up")) { state.scrollOffset -= DETAIL_VIEWPORT_HEIGHT; return; }
134
- if (matchesKey(data, "pagedown") || matchesKey(data, "shift+down")) { state.scrollOffset += DETAIL_VIEWPORT_HEIGHT; return; }
135
- return;
136
- }
137
-
138
- export function renderDetail(
139
- state: DetailState,
140
- agent: AgentConfig,
141
- cwd: string,
142
- width: number,
143
- theme: Theme,
144
- ): string[] {
145
- const lines: string[] = [];
146
- const scopeBadge = agent.source === "builtin"
147
- ? (agent.disabled
148
- ? (agent.override ? `[builtin off+${agent.override.scope}]` : "[builtin off]")
149
- : (agent.override ? `[builtin+${agent.override.scope}]` : "[builtin]"))
150
- : agent.source === "project"
151
- ? "[proj]"
152
- : "[user]";
153
- const headerText = ` ${agent.name} ${scopeBadge} ${formatPath(agent.filePath)} `;
154
- lines.push(renderHeader(headerText, width, theme));
155
- lines.push(row("", width, theme));
156
-
157
- const contentLines = buildDetailLines(agent, state.resolved, state.recentRuns, cwd, width, theme);
158
- const maxOffset = Math.max(0, contentLines.length - DETAIL_VIEWPORT_HEIGHT);
159
- state.scrollOffset = Math.max(0, Math.min(state.scrollOffset, maxOffset));
160
-
161
- const visible = contentLines.slice(state.scrollOffset, state.scrollOffset + DETAIL_VIEWPORT_HEIGHT);
162
- for (const line of visible) {
163
- lines.push(row(` ${line}`, width, theme));
164
- }
165
- for (let i = visible.length; i < DETAIL_VIEWPORT_HEIGHT; i++) {
166
- lines.push(row("", width, theme));
167
- }
168
-
169
- const scrollInfo = formatScrollInfo(state.scrollOffset, Math.max(0, contentLines.length - (state.scrollOffset + DETAIL_VIEWPORT_HEIGHT)));
170
- lines.push(row(scrollInfo ? ` ${theme.fg("dim", scrollInfo)}` : "", width, theme));
171
-
172
- const footer = agent.source === "builtin"
173
- ? agent.override
174
- ? (agent.disabled
175
- ? " [e]dit override [v] raw/resolved [↑↓] scroll [esc] back "
176
- : " [l]aunch [e]dit override [v] raw/resolved [↑↓] scroll [esc] back ")
177
- : (agent.disabled
178
- ? " [e]create override [v] raw/resolved [↑↓] scroll [esc] back "
179
- : " [l]aunch [e]create override [v] raw/resolved [↑↓] scroll [esc] back ")
180
- : " [l]aunch [e]dit [v] raw/resolved [↑↓] scroll [esc] back ";
181
- lines.push(renderFooter(footer, width, theme));
182
- return lines;
183
- }
184
-
185
- export interface LaunchToggleState {
186
- fork: boolean;
187
- background: boolean;
188
- worktree?: boolean;
189
- }
190
-
191
- export function renderTaskInput(
192
- title: string,
193
- editor: TextEditorState,
194
- skipClarify: boolean,
195
- width: number,
196
- theme: Theme,
197
- launchToggles?: LaunchToggleState,
198
- ): string[] {
199
- const lines: string[] = [];
200
- lines.push(renderHeader(` ${title} `, width, theme));
201
- lines.push(row("", width, theme));
202
- lines.push(row(` ${theme.fg("dim", "Task:")}`, width, theme));
203
-
204
- const innerW = width - 2;
205
- const boxInnerWidth = Math.max(10, innerW - 4);
206
- const top = `┌${"─".repeat(boxInnerWidth)}┐`;
207
- const bottom = `└${"─".repeat(boxInnerWidth)}┘`;
208
-
209
- lines.push(row(` ${top}`, width, theme));
210
- const editorState = { ...editor };
211
- const { starts } = wrapText(editorState.buffer, boxInnerWidth);
212
- const cursorPos = getCursorDisplayPos(editorState.cursor, starts);
213
- editorState.viewportOffset = ensureCursorVisible(cursorPos.line, 2, editorState.viewportOffset);
214
- const editorLines = renderEditor(editorState, boxInnerWidth, 2);
215
- for (const line of editorLines) {
216
- lines.push(row(` │${pad(line, boxInnerWidth)}│`, width, theme));
217
- }
218
- lines.push(row(` ${bottom}`, width, theme));
219
-
220
- lines.push(row("", width, theme));
221
- const quickLabel = skipClarify ? "on" : "off";
222
- const footerParts = ["[enter] run", `[tab] quick:${quickLabel}`];
223
- if (launchToggles) {
224
- footerParts.push(`[ctrl+f] fork:${launchToggles.fork ? "on" : "off"}`);
225
- footerParts.push(`[ctrl+b] bg:${launchToggles.background ? "on" : "off"}`);
226
- if (launchToggles.worktree !== undefined) footerParts.push(`[ctrl+w] worktree:${launchToggles.worktree ? "on" : "off"}`);
227
- }
228
- footerParts.push("[esc]");
229
- lines.push(renderFooter(` ${footerParts.join(" ")} `, width, theme));
230
- return lines;
231
- }