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