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.
- package/.allhands/README.md +75 -0
- package/.allhands/agents/compounder.yaml +15 -0
- package/.allhands/agents/coordinator.yaml +17 -0
- package/.allhands/agents/documentor.yaml +15 -0
- package/.allhands/agents/e2e-test-planner.yaml +17 -0
- package/.allhands/agents/emergent.yaml +22 -0
- package/.allhands/agents/executor.yaml +14 -0
- package/.allhands/agents/ideation.yaml +11 -0
- package/.allhands/agents/initiative-steering.yaml +19 -0
- package/.allhands/agents/judge.yaml +13 -0
- package/.allhands/agents/planner.yaml +19 -0
- package/.allhands/agents/pr-reviewer.yaml +15 -0
- package/.allhands/docs.json +5 -0
- package/.allhands/docs.local.json +26 -0
- package/.allhands/flows/COMPOUNDING.md +203 -0
- package/.allhands/flows/COORDINATION.md +89 -0
- package/.allhands/flows/CORE.md +87 -0
- package/.allhands/flows/DOCUMENTATION.md +218 -0
- package/.allhands/flows/E2E_TEST_PLAN_BUILDING.md +140 -0
- package/.allhands/flows/EMERGENT_PLANNING.md +57 -0
- package/.allhands/flows/IDEATION_SCOPING.md +154 -0
- package/.allhands/flows/INITIATIVE_STEERING.md +110 -0
- package/.allhands/flows/JUDGE_REVIEWING.md +79 -0
- package/.allhands/flows/PROMPT_TASK_EXECUTION.md +68 -0
- package/.allhands/flows/PR_REVIEWING.md +43 -0
- package/.allhands/flows/SPEC_PLANNING.md +216 -0
- package/.allhands/flows/harness/WRITING_HARNESS_FLOWS.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_KNOWLEDGE.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_ORCHESTRATION.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_SKILLS.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_TOOLS.md +27 -0
- package/.allhands/flows/harness/WRITING_HARNESS_VALIDATION_TOOLING.md +27 -0
- package/.allhands/flows/shared/CODEBASE_UNDERSTANDING.md +72 -0
- package/.allhands/flows/shared/CREATE_HARNESS_SPEC.md +48 -0
- package/.allhands/flows/shared/CREATE_SPEC.md +41 -0
- package/.allhands/flows/shared/CREATE_VALIDATION_TOOLING_SPEC.md +70 -0
- package/.allhands/flows/shared/DOCUMENTATION_DISCOVERY.md +123 -0
- package/.allhands/flows/shared/DOCUMENTATION_WRITER.md +101 -0
- package/.allhands/flows/shared/EMERGENT_REFINEMENT_ANALYSIS.md +76 -0
- package/.allhands/flows/shared/EXTERNAL_TECH_GUIDANCE.md +97 -0
- package/.allhands/flows/shared/IDEATION_CODEBASE_GROUNDING.md +49 -0
- package/.allhands/flows/shared/PLAN_DEEPENING.md +152 -0
- package/.allhands/flows/shared/PROMPT_TASKS_CURATION.md +113 -0
- package/.allhands/flows/shared/PROMPT_VALIDATION_REVIEW.MD +99 -0
- package/.allhands/flows/shared/QUICK_PREMORTEM.md +70 -0
- package/.allhands/flows/shared/RESEARCH_GUIDANCE.md +38 -0
- package/.allhands/flows/shared/REVIEW_OPTIONS_BREAKDOWN.md +68 -0
- package/.allhands/flows/shared/SKILL_EXTRACTION.md +84 -0
- package/.allhands/flows/shared/SPEC_FLOW_ANALYSIS.md +119 -0
- package/.allhands/flows/shared/TDD_WORKFLOW.md +109 -0
- package/.allhands/flows/shared/UTILIZE_VALIDATION_TOOLING.md +84 -0
- package/.allhands/flows/shared/WRITING_HARNESS_FLOWS.md +11 -0
- package/.allhands/flows/shared/WRITING_HARNESS_MCP_TOOLS.md +84 -0
- package/.allhands/flows/shared/jury/ARCHITECTURE_REVIEW.md +91 -0
- package/.allhands/flows/shared/jury/BEST_PRACTICES_REVIEW.md +80 -0
- package/.allhands/flows/shared/jury/CLAIM_VERIFICATION_REVIEW.md +101 -0
- package/.allhands/flows/shared/jury/EXPECTATIONS_FIT_REVIEW.md +78 -0
- package/.allhands/flows/shared/jury/MAINTAINABILITY_REVIEW.md +110 -0
- package/.allhands/flows/shared/jury/PROMPTS_EXPECTATIONS_FIT.md +74 -0
- package/.allhands/flows/shared/jury/PROMPTS_FLOW_ANALYSIS.md +92 -0
- package/.allhands/flows/shared/jury/PROMPTS_YAGNI.md +78 -0
- package/.allhands/flows/shared/jury/PROMPT_PREMORTEM.md +125 -0
- package/.allhands/flows/shared/jury/SECURITY_REVIEW.md +86 -0
- package/.allhands/flows/shared/jury/YAGNI_REVIEW.md +82 -0
- package/.allhands/flows/wip/DEBUG_INVESTIGATION.md +162 -0
- package/.allhands/flows/wip/MEMORY_RECALL.md +62 -0
- package/.allhands/harness/ah +131 -0
- package/.allhands/harness/package-lock.json +5292 -0
- package/.allhands/harness/package.json +52 -0
- package/.allhands/harness/src/__tests__/e2e/commands.test.ts +307 -0
- package/.allhands/harness/src/__tests__/e2e/event-loop.test.ts +539 -0
- package/.allhands/harness/src/__tests__/e2e/hooks.test.ts +427 -0
- package/.allhands/harness/src/__tests__/e2e/new-initiative-routing.test.ts +137 -0
- package/.allhands/harness/src/__tests__/e2e/run-e2e.ts +109 -0
- package/.allhands/harness/src/__tests__/e2e/specs-type.test.ts +210 -0
- package/.allhands/harness/src/__tests__/e2e/validation-hooks.test.ts +669 -0
- package/.allhands/harness/src/__tests__/e2e/validation-path-consistency.test.ts +354 -0
- package/.allhands/harness/src/__tests__/e2e/validation.test.ts +528 -0
- package/.allhands/harness/src/__tests__/harness/assertions.ts +318 -0
- package/.allhands/harness/src/__tests__/harness/cli-runner.ts +359 -0
- package/.allhands/harness/src/__tests__/harness/fixture.ts +384 -0
- package/.allhands/harness/src/__tests__/harness/hook-runner.ts +411 -0
- package/.allhands/harness/src/__tests__/harness/index.ts +122 -0
- package/.allhands/harness/src/cli.ts +36 -0
- package/.allhands/harness/src/commands/complexity.ts +177 -0
- package/.allhands/harness/src/commands/context7.ts +202 -0
- package/.allhands/harness/src/commands/docs.ts +557 -0
- package/.allhands/harness/src/commands/hooks.ts +24 -0
- package/.allhands/harness/src/commands/index.ts +51 -0
- package/.allhands/harness/src/commands/knowledge.ts +382 -0
- package/.allhands/harness/src/commands/memories.ts +302 -0
- package/.allhands/harness/src/commands/notify.ts +61 -0
- package/.allhands/harness/src/commands/oracle.ts +158 -0
- package/.allhands/harness/src/commands/perplexity.ts +220 -0
- package/.allhands/harness/src/commands/planning.ts +245 -0
- package/.allhands/harness/src/commands/schema.ts +73 -0
- package/.allhands/harness/src/commands/skills.ts +128 -0
- package/.allhands/harness/src/commands/solutions.ts +353 -0
- package/.allhands/harness/src/commands/spawn.ts +158 -0
- package/.allhands/harness/src/commands/specs.ts +532 -0
- package/.allhands/harness/src/commands/tavily.ts +226 -0
- package/.allhands/harness/src/commands/tools.ts +579 -0
- package/.allhands/harness/src/commands/trace.ts +327 -0
- package/.allhands/harness/src/commands/tui.ts +960 -0
- package/.allhands/harness/src/commands/validate.ts +143 -0
- package/.allhands/harness/src/commands/validation-tools.ts +108 -0
- package/.allhands/harness/src/hooks/context.ts +1442 -0
- package/.allhands/harness/src/hooks/enforcement.ts +170 -0
- package/.allhands/harness/src/hooks/index.ts +54 -0
- package/.allhands/harness/src/hooks/lifecycle.ts +229 -0
- package/.allhands/harness/src/hooks/notification.ts +104 -0
- package/.allhands/harness/src/hooks/observability.ts +551 -0
- package/.allhands/harness/src/hooks/session.ts +88 -0
- package/.allhands/harness/src/hooks/shared.ts +815 -0
- package/.allhands/harness/src/hooks/transcript-parser.ts +208 -0
- package/.allhands/harness/src/hooks/validation.ts +617 -0
- package/.allhands/harness/src/lib/__tests__/ctags.test.ts +244 -0
- package/.allhands/harness/src/lib/__tests__/docs-validation.test.ts +344 -0
- package/.allhands/harness/src/lib/__tests__/mcp-runtime.test.ts +190 -0
- package/.allhands/harness/src/lib/__tests__/schema.test.ts +861 -0
- package/.allhands/harness/src/lib/base-command.ts +198 -0
- package/.allhands/harness/src/lib/cli-daemon.ts +343 -0
- package/.allhands/harness/src/lib/compaction.ts +313 -0
- package/.allhands/harness/src/lib/ctags.ts +497 -0
- package/.allhands/harness/src/lib/docs-validation.ts +907 -0
- package/.allhands/harness/src/lib/event-loop.ts +662 -0
- package/.allhands/harness/src/lib/flows.ts +155 -0
- package/.allhands/harness/src/lib/git.ts +276 -0
- package/.allhands/harness/src/lib/knowledge-worker.ts +72 -0
- package/.allhands/harness/src/lib/knowledge.ts +810 -0
- package/.allhands/harness/src/lib/llm.ts +255 -0
- package/.allhands/harness/src/lib/mcp-client.ts +432 -0
- package/.allhands/harness/src/lib/mcp-daemon.ts +486 -0
- package/.allhands/harness/src/lib/mcp-runtime.ts +418 -0
- package/.allhands/harness/src/lib/notification.ts +115 -0
- package/.allhands/harness/src/lib/opencode/index.ts +70 -0
- package/.allhands/harness/src/lib/opencode/profiles.ts +300 -0
- package/.allhands/harness/src/lib/opencode/prompts/codesearch.md +98 -0
- package/.allhands/harness/src/lib/opencode/prompts/knowledge-aggregator.md +67 -0
- package/.allhands/harness/src/lib/opencode/runner.ts +281 -0
- package/.allhands/harness/src/lib/oracle.ts +926 -0
- package/.allhands/harness/src/lib/planning-utils.ts +150 -0
- package/.allhands/harness/src/lib/planning.ts +605 -0
- package/.allhands/harness/src/lib/pr-review.ts +225 -0
- package/.allhands/harness/src/lib/prompts.ts +522 -0
- package/.allhands/harness/src/lib/schema.ts +418 -0
- package/.allhands/harness/src/lib/schemas/agent-profile.ts +141 -0
- package/.allhands/harness/src/lib/schemas/template-vars.ts +138 -0
- package/.allhands/harness/src/lib/session.ts +164 -0
- package/.allhands/harness/src/lib/specs.ts +348 -0
- package/.allhands/harness/src/lib/tldr.ts +829 -0
- package/.allhands/harness/src/lib/tmux.ts +1051 -0
- package/.allhands/harness/src/lib/trace-store.ts +714 -0
- package/.allhands/harness/src/mcp/__tests__/index.test.ts +46 -0
- package/.allhands/harness/src/mcp/_template.ts +47 -0
- package/.allhands/harness/src/mcp/filesystem.ts +33 -0
- package/.allhands/harness/src/mcp/index.ts +69 -0
- package/.allhands/harness/src/mcp/playwright.ts +34 -0
- package/.allhands/harness/src/mcp/xcodebuild.ts +29 -0
- package/.allhands/harness/src/schemas/docs.schema.json +44 -0
- package/.allhands/harness/src/schemas/settings.schema.json +214 -0
- package/.allhands/harness/src/tui/actions.ts +227 -0
- package/.allhands/harness/src/tui/file-viewer-modal.ts +270 -0
- package/.allhands/harness/src/tui/index.ts +1574 -0
- package/.allhands/harness/src/tui/modal.ts +232 -0
- package/.allhands/harness/src/tui/prompts-pane.ts +186 -0
- package/.allhands/harness/src/tui/status-pane.ts +434 -0
- package/.allhands/harness/tsconfig.json +22 -0
- package/.allhands/harness/vitest.config.ts +13 -0
- package/.allhands/pillars.md +33 -0
- package/.allhands/principles.md +88 -0
- package/.allhands/schemas/alignment.yaml +51 -0
- package/.allhands/schemas/documentation.yaml +10 -0
- package/.allhands/schemas/prompt.yaml +92 -0
- package/.allhands/schemas/skill.yaml +34 -0
- package/.allhands/schemas/solution.yaml +131 -0
- package/.allhands/schemas/spec.yaml +67 -0
- package/.allhands/schemas/validation-suite.yaml +49 -0
- package/.allhands/schemas/workflow.yaml +51 -0
- package/.allhands/settings.json +57 -0
- package/.allhands/skills/claude-code-patterns/SKILL.md +60 -0
- package/.allhands/skills/claude-code-patterns/docs/context-hygiene.md +19 -0
- package/.allhands/skills/harness-maintenance/SKILL.md +449 -0
- package/.allhands/skills/harness-maintenance/references/core-architecture.md +187 -0
- package/.allhands/skills/harness-maintenance/references/harness-skills.md +87 -0
- package/.allhands/skills/harness-maintenance/references/knowledge-compounding.md +78 -0
- package/.allhands/skills/harness-maintenance/references/tools-commands-mcp-hooks.md +115 -0
- package/.allhands/skills/harness-maintenance/references/validation-tooling.md +77 -0
- package/.allhands/skills/harness-maintenance/references/writing-flows.md +84 -0
- package/.allhands/validation/browser-automation.md +109 -0
- package/.allhands/validation/xcode-automation.md +195 -0
- package/.allhands/workflows/documentation.md +86 -0
- package/.allhands/workflows/investigation.md +81 -0
- package/.allhands/workflows/milestone.md +91 -0
- package/.allhands/workflows/optimization.md +85 -0
- package/.allhands/workflows/refactor.md +99 -0
- package/.allhands/workflows/triage.md +81 -0
- package/.claude/README.md +1 -0
- package/.claude/agents/explorer.md +10 -0
- package/.claude/agents/researcher.md +11 -0
- package/.claude/agents/task-runner.md +8 -0
- package/.claude/settings.json +231 -0
- package/.env.ai.example +7 -0
- package/.github/workflows/npm-publish.yml +69 -0
- package/.internal.json +45 -0
- package/.tldr/config.json +11 -0
- package/.tldrignore +90 -0
- package/CLAUDE.md +6 -0
- package/README.md +98 -0
- package/bin/sync-cli.js +7552 -0
- package/concerns.md +7 -0
- package/docs/README.md +41 -0
- package/docs/agents/README.md +24 -0
- package/docs/agents/agent-configuration-system.md +86 -0
- package/docs/agents/execution-agents.md +50 -0
- package/docs/agents/knowledge-agents.md +61 -0
- package/docs/agents/orchestration-agent.md +57 -0
- package/docs/agents/planning-agents.md +84 -0
- package/docs/agents/quality-review-agents.md +67 -0
- package/docs/agents/workflow-agent-orchestration.md +69 -0
- package/docs/flows/README.md +44 -0
- package/docs/flows/compounding.md +126 -0
- package/docs/flows/coordination.md +72 -0
- package/docs/flows/core-harness-integration.md +63 -0
- package/docs/flows/documentation-orchestration.md +98 -0
- package/docs/flows/e2e-test-plan-building.md +83 -0
- package/docs/flows/emergent-refinement.md +104 -0
- package/docs/flows/flow-authoring-and-mcp-tools.md +89 -0
- package/docs/flows/judge-reviewing.md +112 -0
- package/docs/flows/plan-deepening-and-research.md +107 -0
- package/docs/flows/plan-review-jury.md +114 -0
- package/docs/flows/pr-reviewing.md +54 -0
- package/docs/flows/prompt-task-execution.md +119 -0
- package/docs/flows/spec-planning.md +162 -0
- package/docs/flows/type-specific-scoping-flows.md +49 -0
- package/docs/flows/validation-and-skills-integration.md +145 -0
- package/docs/flows/wip/wip-flows.md +102 -0
- package/docs/harness/README.md +23 -0
- package/docs/harness/agent-profiles.md +84 -0
- package/docs/harness/cli/README.md +24 -0
- package/docs/harness/cli/cli-entry-and-command-discovery.md +91 -0
- package/docs/harness/cli/docs-command.md +87 -0
- package/docs/harness/cli/knowledge-command.md +91 -0
- package/docs/harness/cli/minor-cli-commands.md +65 -0
- package/docs/harness/cli/oracle-command.md +113 -0
- package/docs/harness/cli/planning-command.md +95 -0
- package/docs/harness/cli/schema-and-validation-commands.md +154 -0
- package/docs/harness/cli/search-commands.md +97 -0
- package/docs/harness/cli/spawn-command.md +136 -0
- package/docs/harness/cli/specs-command.md +102 -0
- package/docs/harness/cli/tools-command.md +122 -0
- package/docs/harness/cli/trace-command.md +122 -0
- package/docs/harness/cli-daemon.md +92 -0
- package/docs/harness/event-loop.md +184 -0
- package/docs/harness/hooks/README.md +15 -0
- package/docs/harness/hooks/context-hooks.md +96 -0
- package/docs/harness/hooks/lifecycle-and-observability-hooks.md +135 -0
- package/docs/harness/hooks/validation-hooks.md +97 -0
- package/docs/harness/test-harness.md +149 -0
- package/docs/harness/tui.md +176 -0
- package/docs/memories.md +20 -0
- package/docs/solutions/agentic-issues/premature-agent-deletion-tui-action-dependency-20260130.md +49 -0
- package/docs/solutions/agentic-issues/ref-anchor-scope-mismatch-skill-references-20260131.md +55 -0
- package/docs/solutions/agentic-issues/tautological-tests-routing-20260131.md +52 -0
- package/docs/solutions/integration_issue/blocktool-output-format-mismatch-hook-runner-20260130.md +52 -0
- package/docs/solutions/integration_issue/dual-validation-path-divergence-schema-20260130.md +66 -0
- package/docs/solutions/security-issues/unsanitized-domain-path-join-20260131.md +52 -0
- package/docs/solutions/test-failures/event-loop-mock-ordering-checkAgentWindows-20260130.md +63 -0
- package/docs/sync-cli/README.md +19 -0
- package/docs/sync-cli/cli-entrypoint-and-commands.md +39 -0
- package/docs/sync-cli/commands/README.md +11 -0
- package/docs/sync-cli/commands/pull-manifest-command.md +36 -0
- package/docs/sync-cli/commands/push-command.md +84 -0
- package/docs/sync-cli/commands/sync-command.md +71 -0
- package/docs/sync-cli/systems/README.md +14 -0
- package/docs/sync-cli/systems/git-and-github-integration.md +49 -0
- package/docs/sync-cli/systems/interactive-ui.md +43 -0
- package/docs/sync-cli/systems/manifest-and-distribution.md +51 -0
- package/docs/sync-cli/systems/path-resolution.md +42 -0
- package/package.json +46 -0
- package/scripts/install-shim.sh +40 -0
- package/scripts/pre-pack.sh +25 -0
- package/specs/harness-maintenance-skill.spec.md +138 -0
- package/specs/roadmap/git-spec-lifecycle-management.spec.md +113 -0
- package/specs/sync-init-flag.spec.md +117 -0
- package/specs/unified-workflow-orchestration.spec.md +250 -0
- package/specs/validation-tooling-practice.spec.md +98 -0
- package/specs/workflow-domain-configuration.spec.md +265 -0
- package/src/commands/pull-manifest.ts +31 -0
- package/src/commands/push.ts +344 -0
- package/src/commands/sync.ts +289 -0
- package/src/lib/constants.ts +10 -0
- package/src/lib/dotfiles.ts +36 -0
- package/src/lib/fs-utils.ts +18 -0
- package/src/lib/gh.ts +40 -0
- package/src/lib/git.ts +63 -0
- package/src/lib/gitignore.ts +167 -0
- package/src/lib/manifest.ts +121 -0
- package/src/lib/marker-sync.ts +39 -0
- package/src/lib/paths.ts +38 -0
- package/src/lib/target-lines.ts +66 -0
- package/src/lib/ui.ts +78 -0
- package/src/sync-cli.ts +120 -0
- package/target-lines.json +23 -0
- 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
|
+
}
|