all-hands-cli 0.1.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 (305) hide show
  1. package/.allhands/README.md +75 -0
  2. package/.allhands/agents/compounder.yaml +15 -0
  3. package/.allhands/agents/coordinator.yaml +17 -0
  4. package/.allhands/agents/documentor.yaml +15 -0
  5. package/.allhands/agents/e2e-test-planner.yaml +17 -0
  6. package/.allhands/agents/emergent.yaml +22 -0
  7. package/.allhands/agents/executor.yaml +14 -0
  8. package/.allhands/agents/ideation.yaml +11 -0
  9. package/.allhands/agents/initiative-steering.yaml +19 -0
  10. package/.allhands/agents/judge.yaml +13 -0
  11. package/.allhands/agents/planner.yaml +19 -0
  12. package/.allhands/agents/pr-reviewer.yaml +15 -0
  13. package/.allhands/docs.json +5 -0
  14. package/.allhands/docs.local.json +26 -0
  15. package/.allhands/flows/COMPOUNDING.md +203 -0
  16. package/.allhands/flows/COORDINATION.md +89 -0
  17. package/.allhands/flows/CORE.md +87 -0
  18. package/.allhands/flows/DOCUMENTATION.md +218 -0
  19. package/.allhands/flows/E2E_TEST_PLAN_BUILDING.md +140 -0
  20. package/.allhands/flows/EMERGENT_PLANNING.md +57 -0
  21. package/.allhands/flows/IDEATION_SCOPING.md +154 -0
  22. package/.allhands/flows/INITIATIVE_STEERING.md +110 -0
  23. package/.allhands/flows/JUDGE_REVIEWING.md +79 -0
  24. package/.allhands/flows/PROMPT_TASK_EXECUTION.md +68 -0
  25. package/.allhands/flows/PR_REVIEWING.md +43 -0
  26. package/.allhands/flows/SPEC_PLANNING.md +216 -0
  27. package/.allhands/flows/harness/WRITING_HARNESS_FLOWS.md +27 -0
  28. package/.allhands/flows/harness/WRITING_HARNESS_KNOWLEDGE.md +27 -0
  29. package/.allhands/flows/harness/WRITING_HARNESS_ORCHESTRATION.md +27 -0
  30. package/.allhands/flows/harness/WRITING_HARNESS_SKILLS.md +27 -0
  31. package/.allhands/flows/harness/WRITING_HARNESS_TOOLS.md +27 -0
  32. package/.allhands/flows/harness/WRITING_HARNESS_VALIDATION_TOOLING.md +27 -0
  33. package/.allhands/flows/shared/CODEBASE_UNDERSTANDING.md +72 -0
  34. package/.allhands/flows/shared/CREATE_HARNESS_SPEC.md +48 -0
  35. package/.allhands/flows/shared/CREATE_SPEC.md +41 -0
  36. package/.allhands/flows/shared/CREATE_VALIDATION_TOOLING_SPEC.md +70 -0
  37. package/.allhands/flows/shared/DOCUMENTATION_DISCOVERY.md +123 -0
  38. package/.allhands/flows/shared/DOCUMENTATION_WRITER.md +101 -0
  39. package/.allhands/flows/shared/EMERGENT_REFINEMENT_ANALYSIS.md +76 -0
  40. package/.allhands/flows/shared/EXTERNAL_TECH_GUIDANCE.md +97 -0
  41. package/.allhands/flows/shared/IDEATION_CODEBASE_GROUNDING.md +49 -0
  42. package/.allhands/flows/shared/PLAN_DEEPENING.md +152 -0
  43. package/.allhands/flows/shared/PROMPT_TASKS_CURATION.md +113 -0
  44. package/.allhands/flows/shared/PROMPT_VALIDATION_REVIEW.MD +99 -0
  45. package/.allhands/flows/shared/QUICK_PREMORTEM.md +70 -0
  46. package/.allhands/flows/shared/RESEARCH_GUIDANCE.md +38 -0
  47. package/.allhands/flows/shared/REVIEW_OPTIONS_BREAKDOWN.md +68 -0
  48. package/.allhands/flows/shared/SKILL_EXTRACTION.md +84 -0
  49. package/.allhands/flows/shared/SPEC_FLOW_ANALYSIS.md +119 -0
  50. package/.allhands/flows/shared/TDD_WORKFLOW.md +109 -0
  51. package/.allhands/flows/shared/UTILIZE_VALIDATION_TOOLING.md +84 -0
  52. package/.allhands/flows/shared/WRITING_HARNESS_FLOWS.md +11 -0
  53. package/.allhands/flows/shared/WRITING_HARNESS_MCP_TOOLS.md +84 -0
  54. package/.allhands/flows/shared/jury/ARCHITECTURE_REVIEW.md +91 -0
  55. package/.allhands/flows/shared/jury/BEST_PRACTICES_REVIEW.md +80 -0
  56. package/.allhands/flows/shared/jury/CLAIM_VERIFICATION_REVIEW.md +101 -0
  57. package/.allhands/flows/shared/jury/EXPECTATIONS_FIT_REVIEW.md +78 -0
  58. package/.allhands/flows/shared/jury/MAINTAINABILITY_REVIEW.md +110 -0
  59. package/.allhands/flows/shared/jury/PROMPTS_EXPECTATIONS_FIT.md +74 -0
  60. package/.allhands/flows/shared/jury/PROMPTS_FLOW_ANALYSIS.md +92 -0
  61. package/.allhands/flows/shared/jury/PROMPTS_YAGNI.md +78 -0
  62. package/.allhands/flows/shared/jury/PROMPT_PREMORTEM.md +125 -0
  63. package/.allhands/flows/shared/jury/SECURITY_REVIEW.md +86 -0
  64. package/.allhands/flows/shared/jury/YAGNI_REVIEW.md +82 -0
  65. package/.allhands/flows/wip/DEBUG_INVESTIGATION.md +162 -0
  66. package/.allhands/flows/wip/MEMORY_RECALL.md +62 -0
  67. package/.allhands/harness/ah +131 -0
  68. package/.allhands/harness/package-lock.json +5292 -0
  69. package/.allhands/harness/package.json +52 -0
  70. package/.allhands/harness/src/__tests__/e2e/commands.test.ts +307 -0
  71. package/.allhands/harness/src/__tests__/e2e/event-loop.test.ts +539 -0
  72. package/.allhands/harness/src/__tests__/e2e/hooks.test.ts +427 -0
  73. package/.allhands/harness/src/__tests__/e2e/new-initiative-routing.test.ts +137 -0
  74. package/.allhands/harness/src/__tests__/e2e/run-e2e.ts +109 -0
  75. package/.allhands/harness/src/__tests__/e2e/specs-type.test.ts +210 -0
  76. package/.allhands/harness/src/__tests__/e2e/validation-hooks.test.ts +669 -0
  77. package/.allhands/harness/src/__tests__/e2e/validation-path-consistency.test.ts +354 -0
  78. package/.allhands/harness/src/__tests__/e2e/validation.test.ts +528 -0
  79. package/.allhands/harness/src/__tests__/harness/assertions.ts +318 -0
  80. package/.allhands/harness/src/__tests__/harness/cli-runner.ts +359 -0
  81. package/.allhands/harness/src/__tests__/harness/fixture.ts +384 -0
  82. package/.allhands/harness/src/__tests__/harness/hook-runner.ts +411 -0
  83. package/.allhands/harness/src/__tests__/harness/index.ts +122 -0
  84. package/.allhands/harness/src/cli.ts +36 -0
  85. package/.allhands/harness/src/commands/complexity.ts +177 -0
  86. package/.allhands/harness/src/commands/context7.ts +202 -0
  87. package/.allhands/harness/src/commands/docs.ts +557 -0
  88. package/.allhands/harness/src/commands/hooks.ts +24 -0
  89. package/.allhands/harness/src/commands/index.ts +51 -0
  90. package/.allhands/harness/src/commands/knowledge.ts +382 -0
  91. package/.allhands/harness/src/commands/memories.ts +302 -0
  92. package/.allhands/harness/src/commands/notify.ts +61 -0
  93. package/.allhands/harness/src/commands/oracle.ts +158 -0
  94. package/.allhands/harness/src/commands/perplexity.ts +220 -0
  95. package/.allhands/harness/src/commands/planning.ts +245 -0
  96. package/.allhands/harness/src/commands/schema.ts +73 -0
  97. package/.allhands/harness/src/commands/skills.ts +128 -0
  98. package/.allhands/harness/src/commands/solutions.ts +353 -0
  99. package/.allhands/harness/src/commands/spawn.ts +158 -0
  100. package/.allhands/harness/src/commands/specs.ts +532 -0
  101. package/.allhands/harness/src/commands/tavily.ts +226 -0
  102. package/.allhands/harness/src/commands/tools.ts +579 -0
  103. package/.allhands/harness/src/commands/trace.ts +327 -0
  104. package/.allhands/harness/src/commands/tui.ts +960 -0
  105. package/.allhands/harness/src/commands/validate.ts +143 -0
  106. package/.allhands/harness/src/commands/validation-tools.ts +108 -0
  107. package/.allhands/harness/src/hooks/context.ts +1442 -0
  108. package/.allhands/harness/src/hooks/enforcement.ts +170 -0
  109. package/.allhands/harness/src/hooks/index.ts +54 -0
  110. package/.allhands/harness/src/hooks/lifecycle.ts +229 -0
  111. package/.allhands/harness/src/hooks/notification.ts +104 -0
  112. package/.allhands/harness/src/hooks/observability.ts +551 -0
  113. package/.allhands/harness/src/hooks/session.ts +88 -0
  114. package/.allhands/harness/src/hooks/shared.ts +815 -0
  115. package/.allhands/harness/src/hooks/transcript-parser.ts +208 -0
  116. package/.allhands/harness/src/hooks/validation.ts +617 -0
  117. package/.allhands/harness/src/lib/__tests__/ctags.test.ts +244 -0
  118. package/.allhands/harness/src/lib/__tests__/docs-validation.test.ts +344 -0
  119. package/.allhands/harness/src/lib/__tests__/mcp-runtime.test.ts +190 -0
  120. package/.allhands/harness/src/lib/__tests__/schema.test.ts +861 -0
  121. package/.allhands/harness/src/lib/base-command.ts +198 -0
  122. package/.allhands/harness/src/lib/cli-daemon.ts +343 -0
  123. package/.allhands/harness/src/lib/compaction.ts +313 -0
  124. package/.allhands/harness/src/lib/ctags.ts +497 -0
  125. package/.allhands/harness/src/lib/docs-validation.ts +907 -0
  126. package/.allhands/harness/src/lib/event-loop.ts +662 -0
  127. package/.allhands/harness/src/lib/flows.ts +155 -0
  128. package/.allhands/harness/src/lib/git.ts +276 -0
  129. package/.allhands/harness/src/lib/knowledge-worker.ts +72 -0
  130. package/.allhands/harness/src/lib/knowledge.ts +810 -0
  131. package/.allhands/harness/src/lib/llm.ts +255 -0
  132. package/.allhands/harness/src/lib/mcp-client.ts +432 -0
  133. package/.allhands/harness/src/lib/mcp-daemon.ts +486 -0
  134. package/.allhands/harness/src/lib/mcp-runtime.ts +418 -0
  135. package/.allhands/harness/src/lib/notification.ts +115 -0
  136. package/.allhands/harness/src/lib/opencode/index.ts +70 -0
  137. package/.allhands/harness/src/lib/opencode/profiles.ts +300 -0
  138. package/.allhands/harness/src/lib/opencode/prompts/codesearch.md +98 -0
  139. package/.allhands/harness/src/lib/opencode/prompts/knowledge-aggregator.md +67 -0
  140. package/.allhands/harness/src/lib/opencode/runner.ts +281 -0
  141. package/.allhands/harness/src/lib/oracle.ts +926 -0
  142. package/.allhands/harness/src/lib/planning-utils.ts +150 -0
  143. package/.allhands/harness/src/lib/planning.ts +605 -0
  144. package/.allhands/harness/src/lib/pr-review.ts +225 -0
  145. package/.allhands/harness/src/lib/prompts.ts +522 -0
  146. package/.allhands/harness/src/lib/schema.ts +418 -0
  147. package/.allhands/harness/src/lib/schemas/agent-profile.ts +141 -0
  148. package/.allhands/harness/src/lib/schemas/template-vars.ts +138 -0
  149. package/.allhands/harness/src/lib/session.ts +164 -0
  150. package/.allhands/harness/src/lib/specs.ts +348 -0
  151. package/.allhands/harness/src/lib/tldr.ts +829 -0
  152. package/.allhands/harness/src/lib/tmux.ts +1051 -0
  153. package/.allhands/harness/src/lib/trace-store.ts +714 -0
  154. package/.allhands/harness/src/mcp/__tests__/index.test.ts +46 -0
  155. package/.allhands/harness/src/mcp/_template.ts +47 -0
  156. package/.allhands/harness/src/mcp/filesystem.ts +33 -0
  157. package/.allhands/harness/src/mcp/index.ts +69 -0
  158. package/.allhands/harness/src/mcp/playwright.ts +34 -0
  159. package/.allhands/harness/src/mcp/xcodebuild.ts +29 -0
  160. package/.allhands/harness/src/schemas/docs.schema.json +44 -0
  161. package/.allhands/harness/src/schemas/settings.schema.json +214 -0
  162. package/.allhands/harness/src/tui/actions.ts +227 -0
  163. package/.allhands/harness/src/tui/file-viewer-modal.ts +270 -0
  164. package/.allhands/harness/src/tui/index.ts +1574 -0
  165. package/.allhands/harness/src/tui/modal.ts +232 -0
  166. package/.allhands/harness/src/tui/prompts-pane.ts +186 -0
  167. package/.allhands/harness/src/tui/status-pane.ts +434 -0
  168. package/.allhands/harness/tsconfig.json +22 -0
  169. package/.allhands/harness/vitest.config.ts +13 -0
  170. package/.allhands/pillars.md +33 -0
  171. package/.allhands/principles.md +88 -0
  172. package/.allhands/schemas/alignment.yaml +51 -0
  173. package/.allhands/schemas/documentation.yaml +10 -0
  174. package/.allhands/schemas/prompt.yaml +92 -0
  175. package/.allhands/schemas/skill.yaml +34 -0
  176. package/.allhands/schemas/solution.yaml +131 -0
  177. package/.allhands/schemas/spec.yaml +67 -0
  178. package/.allhands/schemas/validation-suite.yaml +49 -0
  179. package/.allhands/schemas/workflow.yaml +51 -0
  180. package/.allhands/settings.json +57 -0
  181. package/.allhands/skills/claude-code-patterns/SKILL.md +60 -0
  182. package/.allhands/skills/claude-code-patterns/docs/context-hygiene.md +19 -0
  183. package/.allhands/skills/harness-maintenance/SKILL.md +449 -0
  184. package/.allhands/skills/harness-maintenance/references/core-architecture.md +187 -0
  185. package/.allhands/skills/harness-maintenance/references/harness-skills.md +87 -0
  186. package/.allhands/skills/harness-maintenance/references/knowledge-compounding.md +78 -0
  187. package/.allhands/skills/harness-maintenance/references/tools-commands-mcp-hooks.md +115 -0
  188. package/.allhands/skills/harness-maintenance/references/validation-tooling.md +77 -0
  189. package/.allhands/skills/harness-maintenance/references/writing-flows.md +84 -0
  190. package/.allhands/validation/browser-automation.md +109 -0
  191. package/.allhands/validation/xcode-automation.md +195 -0
  192. package/.allhands/workflows/documentation.md +86 -0
  193. package/.allhands/workflows/investigation.md +81 -0
  194. package/.allhands/workflows/milestone.md +91 -0
  195. package/.allhands/workflows/optimization.md +85 -0
  196. package/.allhands/workflows/refactor.md +99 -0
  197. package/.allhands/workflows/triage.md +81 -0
  198. package/.claude/README.md +1 -0
  199. package/.claude/agents/explorer.md +10 -0
  200. package/.claude/agents/researcher.md +11 -0
  201. package/.claude/agents/task-runner.md +8 -0
  202. package/.claude/settings.json +231 -0
  203. package/.env.ai.example +7 -0
  204. package/.github/workflows/npm-publish.yml +69 -0
  205. package/.internal.json +45 -0
  206. package/.tldr/config.json +11 -0
  207. package/.tldrignore +90 -0
  208. package/CLAUDE.md +6 -0
  209. package/README.md +98 -0
  210. package/bin/sync-cli.js +7552 -0
  211. package/concerns.md +7 -0
  212. package/docs/README.md +41 -0
  213. package/docs/agents/README.md +24 -0
  214. package/docs/agents/agent-configuration-system.md +86 -0
  215. package/docs/agents/execution-agents.md +50 -0
  216. package/docs/agents/knowledge-agents.md +61 -0
  217. package/docs/agents/orchestration-agent.md +57 -0
  218. package/docs/agents/planning-agents.md +84 -0
  219. package/docs/agents/quality-review-agents.md +67 -0
  220. package/docs/agents/workflow-agent-orchestration.md +69 -0
  221. package/docs/flows/README.md +44 -0
  222. package/docs/flows/compounding.md +126 -0
  223. package/docs/flows/coordination.md +72 -0
  224. package/docs/flows/core-harness-integration.md +63 -0
  225. package/docs/flows/documentation-orchestration.md +98 -0
  226. package/docs/flows/e2e-test-plan-building.md +83 -0
  227. package/docs/flows/emergent-refinement.md +104 -0
  228. package/docs/flows/flow-authoring-and-mcp-tools.md +89 -0
  229. package/docs/flows/judge-reviewing.md +112 -0
  230. package/docs/flows/plan-deepening-and-research.md +107 -0
  231. package/docs/flows/plan-review-jury.md +114 -0
  232. package/docs/flows/pr-reviewing.md +54 -0
  233. package/docs/flows/prompt-task-execution.md +119 -0
  234. package/docs/flows/spec-planning.md +162 -0
  235. package/docs/flows/type-specific-scoping-flows.md +49 -0
  236. package/docs/flows/validation-and-skills-integration.md +145 -0
  237. package/docs/flows/wip/wip-flows.md +102 -0
  238. package/docs/harness/README.md +23 -0
  239. package/docs/harness/agent-profiles.md +84 -0
  240. package/docs/harness/cli/README.md +24 -0
  241. package/docs/harness/cli/cli-entry-and-command-discovery.md +91 -0
  242. package/docs/harness/cli/docs-command.md +87 -0
  243. package/docs/harness/cli/knowledge-command.md +91 -0
  244. package/docs/harness/cli/minor-cli-commands.md +65 -0
  245. package/docs/harness/cli/oracle-command.md +113 -0
  246. package/docs/harness/cli/planning-command.md +95 -0
  247. package/docs/harness/cli/schema-and-validation-commands.md +154 -0
  248. package/docs/harness/cli/search-commands.md +97 -0
  249. package/docs/harness/cli/spawn-command.md +136 -0
  250. package/docs/harness/cli/specs-command.md +102 -0
  251. package/docs/harness/cli/tools-command.md +122 -0
  252. package/docs/harness/cli/trace-command.md +122 -0
  253. package/docs/harness/cli-daemon.md +92 -0
  254. package/docs/harness/event-loop.md +184 -0
  255. package/docs/harness/hooks/README.md +15 -0
  256. package/docs/harness/hooks/context-hooks.md +96 -0
  257. package/docs/harness/hooks/lifecycle-and-observability-hooks.md +135 -0
  258. package/docs/harness/hooks/validation-hooks.md +97 -0
  259. package/docs/harness/test-harness.md +149 -0
  260. package/docs/harness/tui.md +176 -0
  261. package/docs/memories.md +20 -0
  262. package/docs/solutions/agentic-issues/premature-agent-deletion-tui-action-dependency-20260130.md +49 -0
  263. package/docs/solutions/agentic-issues/ref-anchor-scope-mismatch-skill-references-20260131.md +55 -0
  264. package/docs/solutions/agentic-issues/tautological-tests-routing-20260131.md +52 -0
  265. package/docs/solutions/integration_issue/blocktool-output-format-mismatch-hook-runner-20260130.md +52 -0
  266. package/docs/solutions/integration_issue/dual-validation-path-divergence-schema-20260130.md +66 -0
  267. package/docs/solutions/security-issues/unsanitized-domain-path-join-20260131.md +52 -0
  268. package/docs/solutions/test-failures/event-loop-mock-ordering-checkAgentWindows-20260130.md +63 -0
  269. package/docs/sync-cli/README.md +19 -0
  270. package/docs/sync-cli/cli-entrypoint-and-commands.md +39 -0
  271. package/docs/sync-cli/commands/README.md +11 -0
  272. package/docs/sync-cli/commands/pull-manifest-command.md +36 -0
  273. package/docs/sync-cli/commands/push-command.md +84 -0
  274. package/docs/sync-cli/commands/sync-command.md +71 -0
  275. package/docs/sync-cli/systems/README.md +14 -0
  276. package/docs/sync-cli/systems/git-and-github-integration.md +49 -0
  277. package/docs/sync-cli/systems/interactive-ui.md +43 -0
  278. package/docs/sync-cli/systems/manifest-and-distribution.md +51 -0
  279. package/docs/sync-cli/systems/path-resolution.md +42 -0
  280. package/package.json +46 -0
  281. package/scripts/install-shim.sh +40 -0
  282. package/scripts/pre-pack.sh +25 -0
  283. package/specs/harness-maintenance-skill.spec.md +138 -0
  284. package/specs/roadmap/git-spec-lifecycle-management.spec.md +113 -0
  285. package/specs/sync-init-flag.spec.md +117 -0
  286. package/specs/unified-workflow-orchestration.spec.md +250 -0
  287. package/specs/validation-tooling-practice.spec.md +98 -0
  288. package/specs/workflow-domain-configuration.spec.md +265 -0
  289. package/src/commands/pull-manifest.ts +31 -0
  290. package/src/commands/push.ts +344 -0
  291. package/src/commands/sync.ts +289 -0
  292. package/src/lib/constants.ts +10 -0
  293. package/src/lib/dotfiles.ts +36 -0
  294. package/src/lib/fs-utils.ts +18 -0
  295. package/src/lib/gh.ts +40 -0
  296. package/src/lib/git.ts +63 -0
  297. package/src/lib/gitignore.ts +167 -0
  298. package/src/lib/manifest.ts +121 -0
  299. package/src/lib/marker-sync.ts +39 -0
  300. package/src/lib/paths.ts +38 -0
  301. package/src/lib/target-lines.ts +66 -0
  302. package/src/lib/ui.ts +78 -0
  303. package/src/sync-cli.ts +120 -0
  304. package/target-lines.json +23 -0
  305. package/tsconfig.json +20 -0
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Modal - Overlay modal component for TUI
3
+ *
4
+ * Used for:
5
+ * - Switch Spec selection
6
+ * - Activity Log view
7
+ * - Custom Flow selection
8
+ *
9
+ * Navigation:
10
+ * - j/k: Navigate items
11
+ * - u/d: Page up/down
12
+ * - Space/Enter: Select item
13
+ * - Esc: Close modal
14
+ */
15
+
16
+ import blessed from 'blessed';
17
+
18
+ export interface ModalItem {
19
+ id: string;
20
+ label: string;
21
+ type: 'header' | 'item';
22
+ }
23
+
24
+ export interface ModalOptions {
25
+ title: string;
26
+ items: ModalItem[];
27
+ onSelect: (id: string) => void;
28
+ onCancel: () => void;
29
+ onClear?: () => void;
30
+ scrollable?: boolean;
31
+ startFromBottom?: boolean;
32
+ }
33
+
34
+ export interface Modal {
35
+ box: blessed.Widgets.BoxElement;
36
+ selectedIndex: number;
37
+ destroy: () => void;
38
+ navigate: (delta: number) => void;
39
+ select: () => void;
40
+ }
41
+
42
+ export function createModal(
43
+ screen: blessed.Widgets.Screen,
44
+ options: ModalOptions
45
+ ): Modal {
46
+ const { title, items, onSelect, onCancel, onClear, scrollable = false, startFromBottom = false } = options;
47
+
48
+ // Calculate modal size
49
+ const width = Math.floor((screen.width as number) * 0.75);
50
+ const height = Math.min(items.length + 6, Math.floor(screen.height as number * 0.8));
51
+
52
+ // Create outer container (non-scrollable, holds border and help text)
53
+ const container = blessed.box({
54
+ parent: screen,
55
+ top: 'center',
56
+ left: 'center',
57
+ width,
58
+ height,
59
+ border: 'line',
60
+ label: ` ${title} `,
61
+ tags: true,
62
+ style: {
63
+ border: {
64
+ fg: '#c4b5fd',
65
+ bold: true,
66
+ },
67
+ },
68
+ });
69
+
70
+ // Height available for content (container height minus borders minus help text line)
71
+ const contentHeight = height - 4; // 2 for borders, 2 for help text area
72
+
73
+ // Create scrollable list inside the container
74
+ const list = blessed.list({
75
+ parent: container,
76
+ top: 0,
77
+ left: 0,
78
+ width: width - 4, // Account for container borders and padding
79
+ height: contentHeight,
80
+ tags: true,
81
+ scrollable: scrollable,
82
+ alwaysScroll: scrollable,
83
+ scrollbar: scrollable
84
+ ? {
85
+ ch: '┃',
86
+ track: {
87
+ bg: 'black',
88
+ },
89
+ style: {
90
+ fg: '#4A34C5',
91
+ },
92
+ }
93
+ : {
94
+ ch: ' ',
95
+ },
96
+ style: {
97
+ selected: {
98
+ inverse: true,
99
+ },
100
+ },
101
+ keys: false, // We handle keys ourselves
102
+ mouse: false,
103
+ });
104
+
105
+ // Add help text (fixed at bottom of container, outside scrollable area)
106
+ const helpText = onClear
107
+ ? '{#5c6370-fg}[Space] Select [x] Close [Esc] Cancel{/#5c6370-fg}'
108
+ : '{#5c6370-fg}[Space] Select [Esc] Cancel{/#5c6370-fg}';
109
+ blessed.text({
110
+ parent: container,
111
+ bottom: 0,
112
+ left: 1,
113
+ content: helpText,
114
+ tags: true,
115
+ });
116
+
117
+ // Focus the container for key events
118
+ container.focus();
119
+
120
+ // Track selection state
121
+ let selectedIndex = 0;
122
+
123
+ // Find first/last selectable item based on startFromBottom
124
+ const selectableIndices = items
125
+ .map((item, index) => ({ item, index }))
126
+ .filter(({ item }) => item.type === 'item')
127
+ .map(({ index }) => index);
128
+
129
+ if (selectableIndices.length > 0) {
130
+ selectedIndex = startFromBottom
131
+ ? selectableIndices[selectableIndices.length - 1]
132
+ : selectableIndices[0];
133
+ }
134
+
135
+ // Track current scroll position manually since setItems resets it
136
+ let currentScrollPos = 0;
137
+
138
+ // Render items to the list
139
+ function renderItems(): void {
140
+ const lines: string[] = [];
141
+
142
+ items.forEach((item, index) => {
143
+ if (item.type === 'header') {
144
+ lines.push(`{#818cf8-fg}${item.label}{/#818cf8-fg}`);
145
+ } else {
146
+ const isSelected = index === selectedIndex;
147
+ const prefix = isSelected ? '{#a78bfa-fg}{bold}▸ ' : ' ';
148
+ const suffix = isSelected ? '{/bold}{/#a78bfa-fg}' : '';
149
+ lines.push(`${prefix}${item.label}${suffix}`);
150
+ }
151
+ });
152
+
153
+ // setItems resets scroll, so we need to restore it after
154
+ list.setItems(lines);
155
+ if (scrollable && currentScrollPos > 0) {
156
+ list.scrollTo(currentScrollPos);
157
+ }
158
+ }
159
+
160
+ // Scroll to ensure selected item is visible
161
+ function scrollToSelected(): void {
162
+ if (!scrollable || contentHeight <= 0) return;
163
+
164
+ // Calculate where selected item should be visible
165
+ // If selected item is below visible area, scroll down
166
+ if (selectedIndex >= currentScrollPos + contentHeight) {
167
+ currentScrollPos = selectedIndex - contentHeight + 1;
168
+ }
169
+ // If selected item is above visible area, scroll up
170
+ else if (selectedIndex < currentScrollPos) {
171
+ // If this is the first selectable item, scroll to top to show headers
172
+ if (selectedIndex === selectableIndices[0]) {
173
+ currentScrollPos = 0;
174
+ } else {
175
+ currentScrollPos = selectedIndex;
176
+ }
177
+ }
178
+
179
+ // Clamp scroll position (add 1 to maxScroll to ensure we can reach the true bottom)
180
+ const maxScroll = Math.max(0, items.length - contentHeight + 1);
181
+ currentScrollPos = Math.max(0, Math.min(currentScrollPos, maxScroll));
182
+
183
+ list.scrollTo(currentScrollPos);
184
+ }
185
+
186
+ // Navigation
187
+ function navigate(delta: number): void {
188
+ if (selectableIndices.length === 0) return;
189
+
190
+ const currentPos = selectableIndices.indexOf(selectedIndex);
191
+ let newPos = currentPos + delta;
192
+
193
+ // Clamp
194
+ newPos = Math.max(0, Math.min(selectableIndices.length - 1, newPos));
195
+ selectedIndex = selectableIndices[newPos];
196
+
197
+ renderItems();
198
+ scrollToSelected();
199
+ screen.render();
200
+ }
201
+
202
+ function select(): void {
203
+ const item = items[selectedIndex];
204
+ if (item && item.type === 'item') {
205
+ onSelect(item.id);
206
+ }
207
+ }
208
+
209
+ // Set up key bindings on container
210
+ container.key(['j', 'down'], () => navigate(1));
211
+ container.key(['k', 'up'], () => navigate(-1));
212
+ container.key(['u'], () => navigate(-5));
213
+ container.key(['d'], () => navigate(5));
214
+ container.key(['space', 'enter'], () => select());
215
+ container.key(['escape'], () => onCancel());
216
+ if (onClear) {
217
+ container.key(['x'], () => onClear());
218
+ }
219
+
220
+ // Initial render
221
+ renderItems();
222
+ scrollToSelected();
223
+ screen.render();
224
+
225
+ return {
226
+ box: container,
227
+ selectedIndex,
228
+ destroy: () => container.destroy(),
229
+ navigate,
230
+ select,
231
+ };
232
+ }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Prompts Pane - Center area showing prompt list by status
3
+ *
4
+ * Order:
5
+ * 1. Active (in_progress) at top
6
+ * 2. Unimplemented (pending) next
7
+ * 3. Implemented (done) at bottom
8
+ *
9
+ * Each section sorted by prompt number.
10
+ */
11
+
12
+ import blessed from 'blessed';
13
+
14
+ export interface PromptItem {
15
+ number: number;
16
+ title: string;
17
+ status: 'pending' | 'in_progress' | 'done';
18
+ path: string;
19
+ }
20
+
21
+ const ACTIONS_WIDTH = 24;
22
+ const HEADER_HEIGHT = 3;
23
+
24
+ export function createPromptsPane(
25
+ screen: blessed.Widgets.Screen,
26
+ prompts: PromptItem[],
27
+ selectedIndex?: number
28
+ ): blessed.Widgets.BoxElement {
29
+ // Create outer container (non-scrollable, holds border and help text)
30
+ const container = blessed.box({
31
+ parent: screen,
32
+ top: HEADER_HEIGHT,
33
+ left: ACTIONS_WIDTH,
34
+ width: '50%-12',
35
+ height: `100%-${HEADER_HEIGHT}`,
36
+ border: {
37
+ type: 'line',
38
+ },
39
+ label: ' Prompts ',
40
+ tags: true,
41
+ style: {
42
+ border: {
43
+ fg: '#4A34C5',
44
+ },
45
+ },
46
+ });
47
+
48
+ // Calculate content area height (container minus borders minus help text line)
49
+ const containerHeight = typeof container.height === 'number' ? container.height : (screen.height as number) - HEADER_HEIGHT;
50
+ const contentHeight = containerHeight - 3; // 2 for borders, 1 for help text
51
+
52
+ // Create scrollable content area inside the container
53
+ const scrollArea = blessed.box({
54
+ parent: container,
55
+ top: 0,
56
+ left: 0,
57
+ width: '100%-2',
58
+ height: contentHeight,
59
+ tags: true,
60
+ scrollable: true,
61
+ alwaysScroll: true,
62
+ scrollbar: {
63
+ ch: '┃',
64
+ track: {
65
+ bg: 'black',
66
+ },
67
+ style: {
68
+ fg: '#4A34C5',
69
+ },
70
+ },
71
+ });
72
+
73
+ // Sort prompts by status then number
74
+ const sorted = sortPrompts(prompts);
75
+ const { content, selectedLineNumber } = formatPromptsContentWithLineInfo(sorted, selectedIndex);
76
+
77
+ scrollArea.setContent(content);
78
+
79
+ // Scroll to ensure selected item is visible
80
+ if (selectedLineNumber !== undefined && selectedLineNumber >= 0) {
81
+ const visibleHeight = contentHeight;
82
+
83
+ // Only scroll if selected line would be outside visible area
84
+ if (selectedLineNumber >= visibleHeight) {
85
+ // Scroll to put selected line in the middle of visible area when possible
86
+ const scrollOffset = Math.max(0, selectedLineNumber - Math.floor(visibleHeight / 2));
87
+ scrollArea.scrollTo(scrollOffset);
88
+ }
89
+ }
90
+
91
+ // Add help text at bottom of container (fixed position, outside scroll area)
92
+ blessed.text({
93
+ parent: container,
94
+ bottom: 0,
95
+ left: 1,
96
+ content: '{#5c6370-fg}u/d: Page Up/Down{/#5c6370-fg}',
97
+ tags: true,
98
+ });
99
+
100
+ return container;
101
+ }
102
+
103
+ function sortPrompts(prompts: PromptItem[]): PromptItem[] {
104
+ const inProgress = prompts
105
+ .filter((p) => p.status === 'in_progress')
106
+ .sort((a, b) => a.number - b.number);
107
+
108
+ const pending = prompts
109
+ .filter((p) => p.status === 'pending')
110
+ .sort((a, b) => a.number - b.number);
111
+
112
+ const done = prompts
113
+ .filter((p) => p.status === 'done')
114
+ .sort((a, b) => a.number - b.number);
115
+
116
+ return [...inProgress, ...pending, ...done];
117
+ }
118
+
119
+ interface PromptsContentResult {
120
+ content: string;
121
+ selectedLineNumber?: number;
122
+ }
123
+
124
+ function formatPromptsContentWithLineInfo(prompts: PromptItem[], selectedIndex?: number): PromptsContentResult {
125
+ if (prompts.length === 0) {
126
+ return { content: '{#5c6370-fg} No prompts found{/#5c6370-fg}' };
127
+ }
128
+
129
+ const lines: string[] = [];
130
+ let currentStatus: string | null = null;
131
+ let itemIndex = 0;
132
+ let selectedLineNumber: number | undefined;
133
+
134
+ for (const prompt of prompts) {
135
+ // Add section separator when status changes
136
+ if (prompt.status !== currentStatus) {
137
+ if (currentStatus !== null) {
138
+ lines.push('{#3a3f5c-fg}━━━━━━━━━━━━━━━━━━━━━━━━{/#3a3f5c-fg}');
139
+ }
140
+ currentStatus = prompt.status;
141
+ }
142
+
143
+ const isSelected = selectedIndex === itemIndex;
144
+ if (isSelected) {
145
+ selectedLineNumber = lines.length; // Track the line number (0-indexed)
146
+ }
147
+ const line = formatPromptLine(prompt, isSelected);
148
+ lines.push(line);
149
+ itemIndex++;
150
+ }
151
+
152
+ return { content: lines.join('\n'), selectedLineNumber };
153
+ }
154
+
155
+ function formatPromptLine(prompt: PromptItem, isSelected: boolean): string {
156
+ const icon = getStatusIcon(prompt.status);
157
+ const numStr = String(prompt.number).padStart(2, '0');
158
+
159
+ // Truncate title if too long
160
+ const maxTitleLen = 30;
161
+ let title = prompt.title;
162
+ if (title.length > maxTitleLen) {
163
+ title = title.substring(0, maxTitleLen - 3) + '...';
164
+ }
165
+
166
+ const content = `${icon} ${numStr}. ${title}`;
167
+
168
+ if (isSelected) {
169
+ return `{inverse}${content}{/inverse}`;
170
+ }
171
+
172
+ return content;
173
+ }
174
+
175
+ function getStatusIcon(status: string): string {
176
+ switch (status) {
177
+ case 'done':
178
+ return '{#10b981-fg}✓{/#10b981-fg}';
179
+ case 'in_progress':
180
+ return '{#a78bfa-fg}▶{/#a78bfa-fg}';
181
+ case 'pending':
182
+ return '{#5c6370-fg}○{/#5c6370-fg}';
183
+ default:
184
+ return '?';
185
+ }
186
+ }