@compilr-dev/cli 0.4.0 → 0.5.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/README.md +30 -12
- package/dist/agent.d.ts +74 -1
- package/dist/agent.js +259 -76
- package/dist/anchors/index.d.ts +9 -0
- package/dist/anchors/index.js +9 -0
- package/dist/anchors/project-anchors.d.ts +79 -0
- package/dist/anchors/project-anchors.js +202 -0
- package/dist/commands/handler-types.d.ts +68 -0
- package/dist/commands/handler-types.js +8 -0
- package/dist/commands/handlers/agent-commands.d.ts +13 -0
- package/dist/commands/handlers/agent-commands.js +305 -0
- package/dist/commands/handlers/design-commands.d.ts +15 -0
- package/dist/commands/handlers/design-commands.js +334 -0
- package/dist/commands/handlers/index.d.ts +20 -0
- package/dist/commands/handlers/index.js +43 -0
- package/dist/commands/handlers/overlay-commands.d.ts +21 -0
- package/dist/commands/handlers/overlay-commands.js +287 -0
- package/dist/commands/handlers/project-commands.d.ts +11 -0
- package/dist/commands/handlers/project-commands.js +167 -0
- package/dist/commands/handlers/simple-commands.d.ts +19 -0
- package/dist/commands/handlers/simple-commands.js +144 -0
- package/dist/commands/index.d.ts +2 -1
- package/dist/commands/registry.d.ts +50 -0
- package/dist/commands/registry.js +75 -0
- package/dist/commands-v2/handlers/context.d.ts +13 -0
- package/dist/commands-v2/handlers/context.js +348 -0
- package/dist/commands-v2/handlers/core.d.ts +13 -0
- package/dist/commands-v2/handlers/core.js +165 -0
- package/dist/commands-v2/handlers/debug.d.ts +11 -0
- package/dist/commands-v2/handlers/debug.js +159 -0
- package/dist/commands-v2/handlers/index.d.ts +12 -0
- package/dist/commands-v2/handlers/index.js +24 -0
- package/dist/commands-v2/handlers/project.d.ts +22 -0
- package/dist/commands-v2/handlers/project.js +814 -0
- package/dist/commands-v2/handlers/settings.d.ts +15 -0
- package/dist/commands-v2/handlers/settings.js +235 -0
- package/dist/commands-v2/index.d.ts +13 -0
- package/dist/commands-v2/index.js +15 -0
- package/dist/commands-v2/registry.d.ts +37 -0
- package/dist/commands-v2/registry.js +80 -0
- package/dist/commands-v2/types.d.ts +75 -0
- package/dist/commands-v2/types.js +7 -0
- package/dist/commands.js +110 -7
- package/dist/index.js +288 -29
- package/dist/input-handlers/index.d.ts +7 -0
- package/dist/input-handlers/index.js +7 -0
- package/dist/input-handlers/memory-handler.d.ts +26 -0
- package/dist/input-handlers/memory-handler.js +68 -0
- package/dist/repl-helpers.d.ts +63 -0
- package/dist/repl-helpers.js +318 -0
- package/dist/repl-v2.d.ts +155 -0
- package/dist/repl-v2.js +774 -0
- package/dist/repl.d.ts +32 -4
- package/dist/repl.js +250 -977
- package/dist/settings/index.d.ts +23 -0
- package/dist/settings/index.js +48 -0
- package/dist/settings/paths.d.ts +110 -0
- package/dist/settings/paths.js +264 -0
- package/dist/templates/compilr-md.js +7 -4
- package/dist/templates/index.js +3 -4
- package/dist/themes/colors.js +3 -1
- package/dist/themes/registry.d.ts +5 -36
- package/dist/themes/registry.js +11 -95
- package/dist/themes/types.d.ts +3 -38
- package/dist/themes/types.js +2 -2
- package/dist/tools/anchor-tools.d.ts +31 -0
- package/dist/tools/anchor-tools.js +255 -0
- package/dist/tools/backlog-wrappers.d.ts +54 -0
- package/dist/tools/backlog-wrappers.js +338 -0
- package/dist/tools/backlog.js +1 -1
- package/dist/tools/db-tools.d.ts +65 -0
- package/dist/tools/db-tools.js +19 -0
- package/dist/tools/document-db.d.ts +43 -0
- package/dist/tools/document-db.js +220 -0
- package/dist/tools/project-db.d.ts +102 -0
- package/dist/tools/project-db.js +370 -0
- package/dist/tools/workitem-db.d.ts +103 -0
- package/dist/tools/workitem-db.js +549 -0
- package/dist/tools.js +13 -3
- package/dist/ui/agents-overlay-v2.d.ts +43 -0
- package/dist/ui/agents-overlay-v2.js +809 -0
- package/dist/ui/agents-overlay.d.ts +5 -5
- package/dist/ui/agents-overlay.js +782 -420
- package/dist/ui/anchors-overlay.d.ts +12 -0
- package/dist/ui/anchors-overlay.js +775 -0
- package/dist/ui/arch-type-overlay.d.ts +1 -6
- package/dist/ui/arch-type-overlay.js +175 -203
- package/dist/ui/ask-user-overlay-v2.d.ts +26 -0
- package/dist/ui/ask-user-overlay-v2.js +555 -0
- package/dist/ui/ask-user-overlay.d.ts +2 -2
- package/dist/ui/ask-user-overlay.js +443 -535
- package/dist/ui/ask-user-simple-overlay-v2.d.ts +25 -0
- package/dist/ui/ask-user-simple-overlay-v2.js +215 -0
- package/dist/ui/ask-user-simple-overlay.d.ts +2 -2
- package/dist/ui/ask-user-simple-overlay.js +182 -209
- package/dist/ui/backlog-overlay.d.ts +16 -1
- package/dist/ui/backlog-overlay.js +525 -659
- package/dist/ui/base/index.d.ts +26 -0
- package/dist/ui/base/index.js +33 -0
- package/dist/ui/base/inline-overlay-utils.d.ts +217 -0
- package/dist/ui/base/inline-overlay-utils.js +320 -0
- package/dist/ui/base/inline-overlay.d.ts +159 -0
- package/dist/ui/base/inline-overlay.js +257 -0
- package/dist/ui/base/key-utils.d.ts +15 -0
- package/dist/ui/base/key-utils.js +30 -0
- package/dist/ui/base/overlay-base-v2.d.ts +193 -0
- package/dist/ui/base/overlay-base-v2.js +246 -0
- package/dist/ui/base/overlay-base.d.ts +156 -0
- package/dist/ui/base/overlay-base.js +238 -0
- package/dist/ui/base/overlay-lifecycle.d.ts +65 -0
- package/dist/ui/base/overlay-lifecycle.js +159 -0
- package/dist/ui/base/overlay-types.d.ts +185 -0
- package/dist/ui/base/overlay-types.js +7 -0
- package/dist/ui/base/render-utils.d.ts +8 -0
- package/dist/ui/base/render-utils.js +11 -0
- package/dist/ui/base/screen-stack.d.ts +148 -0
- package/dist/ui/base/screen-stack.js +184 -0
- package/dist/ui/base/tabbed-list-overlay-v2.d.ts +103 -0
- package/dist/ui/base/tabbed-list-overlay-v2.js +317 -0
- package/dist/ui/base/tabbed-list-overlay.d.ts +153 -0
- package/dist/ui/base/tabbed-list-overlay.js +369 -0
- package/dist/ui/commands-overlay-v2.d.ts +33 -0
- package/dist/ui/commands-overlay-v2.js +441 -0
- package/dist/ui/commands-overlay.d.ts +7 -2
- package/dist/ui/commands-overlay.js +384 -355
- package/dist/ui/config-overlay.d.ts +5 -4
- package/dist/ui/config-overlay.js +243 -513
- package/dist/ui/conversation.d.ts +75 -4
- package/dist/ui/conversation.js +374 -161
- package/dist/ui/docs-overlay.d.ts +17 -0
- package/dist/ui/docs-overlay.js +303 -0
- package/dist/ui/ephemeral.d.ts +1 -1
- package/dist/ui/ephemeral.js +1 -1
- package/dist/ui/features/index.d.ts +34 -0
- package/dist/ui/features/index.js +34 -0
- package/dist/ui/features/input-feature.d.ts +85 -0
- package/dist/ui/features/input-feature.js +238 -0
- package/dist/ui/features/list-feature.d.ts +155 -0
- package/dist/ui/features/list-feature.js +244 -0
- package/dist/ui/features/pagination-feature.d.ts +154 -0
- package/dist/ui/features/pagination-feature.js +238 -0
- package/dist/ui/features/search-feature.d.ts +148 -0
- package/dist/ui/features/search-feature.js +185 -0
- package/dist/ui/features/tab-feature.d.ts +194 -0
- package/dist/ui/features/tab-feature.js +307 -0
- package/dist/ui/footer-v2.d.ts +222 -0
- package/dist/ui/footer-v2.js +1349 -0
- package/dist/ui/footer.d.ts +107 -0
- package/dist/ui/footer.js +359 -67
- package/dist/ui/guardrail-overlay.d.ts +29 -0
- package/dist/ui/guardrail-overlay.js +145 -0
- package/dist/ui/help-overlay-v2.d.ts +34 -0
- package/dist/ui/help-overlay-v2.js +309 -0
- package/dist/ui/help-overlay.d.ts +16 -0
- package/dist/ui/help-overlay.js +316 -0
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +1 -3
- package/dist/ui/init-overlay-v2.d.ts +34 -0
- package/dist/ui/init-overlay-v2.js +600 -0
- package/dist/ui/init-overlay.d.ts +12 -2
- package/dist/ui/init-overlay.js +349 -270
- package/dist/ui/input-prompt-v2.d.ts +1 -0
- package/dist/ui/input-prompt-v2.js +14 -6
- package/dist/ui/input-prompt.d.ts +116 -33
- package/dist/ui/input-prompt.js +536 -337
- package/dist/ui/iteration-limit-overlay-v2.d.ts +21 -0
- package/dist/ui/iteration-limit-overlay-v2.js +114 -0
- package/dist/ui/iteration-limit-overlay.d.ts +2 -2
- package/dist/ui/iteration-limit-overlay.js +92 -128
- package/dist/ui/keys-overlay-v2.d.ts +41 -0
- package/dist/ui/keys-overlay-v2.js +248 -0
- package/dist/ui/keys-overlay.d.ts +1 -0
- package/dist/ui/keys-overlay.js +203 -141
- package/dist/ui/line-utils.d.ts +88 -0
- package/dist/ui/line-utils.js +150 -0
- package/dist/ui/live-region.d.ts +161 -0
- package/dist/ui/live-region.js +387 -0
- package/dist/ui/mascot/expressions.d.ts +32 -0
- package/dist/ui/mascot/expressions.js +213 -0
- package/dist/ui/mascot/index.d.ts +8 -0
- package/dist/ui/mascot/index.js +8 -0
- package/dist/ui/mascot/renderer.d.ts +19 -0
- package/dist/ui/mascot/renderer.js +97 -0
- package/dist/ui/mascot-overlay-v2.d.ts +41 -0
- package/dist/ui/mascot-overlay-v2.js +138 -0
- package/dist/ui/mascot-overlay.d.ts +21 -0
- package/dist/ui/mascot-overlay.js +146 -0
- package/dist/ui/model-overlay-v2.d.ts +49 -0
- package/dist/ui/model-overlay-v2.js +118 -0
- package/dist/ui/model-overlay.d.ts +27 -0
- package/dist/ui/model-overlay.js +221 -0
- package/dist/ui/model-warning-overlay.js +3 -5
- package/dist/ui/new-overlay.d.ts +34 -0
- package/dist/ui/new-overlay.js +604 -0
- package/dist/ui/overlay/impl/agents-overlay-v2.d.ts +45 -0
- package/dist/ui/overlay/impl/agents-overlay-v2.js +825 -0
- package/dist/ui/overlay/impl/anchors-overlay-v2.d.ts +47 -0
- package/dist/ui/overlay/impl/anchors-overlay-v2.js +783 -0
- package/dist/ui/overlay/impl/arch-type-overlay-v2.d.ts +37 -0
- package/dist/ui/overlay/impl/arch-type-overlay-v2.js +240 -0
- package/dist/ui/overlay/impl/ask-user-overlay-v2.d.ts +72 -0
- package/dist/ui/overlay/impl/ask-user-overlay-v2.js +584 -0
- package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.d.ts +46 -0
- package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.js +204 -0
- package/dist/ui/overlay/impl/backlog-overlay-v2.d.ts +49 -0
- package/dist/ui/overlay/impl/backlog-overlay-v2.js +642 -0
- package/dist/ui/overlay/impl/commands-overlay-v2.d.ts +33 -0
- package/dist/ui/overlay/impl/commands-overlay-v2.js +441 -0
- package/dist/ui/overlay/impl/config-overlay-v2.d.ts +100 -0
- package/dist/ui/overlay/impl/config-overlay-v2.js +654 -0
- package/dist/ui/overlay/impl/dashboard-overlay-v2.d.ts +55 -0
- package/dist/ui/overlay/impl/dashboard-overlay-v2.js +359 -0
- package/dist/ui/overlay/impl/docs-overlay-v2.d.ts +45 -0
- package/dist/ui/overlay/impl/docs-overlay-v2.js +114 -0
- package/dist/ui/overlay/impl/document-detail-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/document-detail-overlay-v2.js +1071 -0
- package/dist/ui/overlay/impl/guardrail-overlay-v2.d.ts +43 -0
- package/dist/ui/overlay/impl/guardrail-overlay-v2.js +114 -0
- package/dist/ui/overlay/impl/help-overlay-v2.d.ts +34 -0
- package/dist/ui/overlay/impl/help-overlay-v2.js +309 -0
- package/dist/ui/overlay/impl/init-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/init-overlay-v2.js +593 -0
- package/dist/ui/overlay/impl/init-setup-overlay-v2.d.ts +25 -0
- package/dist/ui/overlay/impl/init-setup-overlay-v2.js +97 -0
- package/dist/ui/overlay/impl/iteration-limit-overlay-v2.d.ts +35 -0
- package/dist/ui/overlay/impl/iteration-limit-overlay-v2.js +105 -0
- package/dist/ui/overlay/impl/keys-overlay-v2.d.ts +41 -0
- package/dist/ui/overlay/impl/keys-overlay-v2.js +248 -0
- package/dist/ui/overlay/impl/mascot-overlay-v2.d.ts +41 -0
- package/dist/ui/overlay/impl/mascot-overlay-v2.js +138 -0
- package/dist/ui/overlay/impl/model-overlay-v2.d.ts +49 -0
- package/dist/ui/overlay/impl/model-overlay-v2.js +118 -0
- package/dist/ui/overlay/impl/model-warning-overlay-v2.d.ts +46 -0
- package/dist/ui/overlay/impl/model-warning-overlay-v2.js +132 -0
- package/dist/ui/overlay/impl/new-overlay-v2.d.ts +77 -0
- package/dist/ui/overlay/impl/new-overlay-v2.js +593 -0
- package/dist/ui/overlay/impl/permission-overlay-v2.d.ts +36 -0
- package/dist/ui/overlay/impl/permission-overlay-v2.js +380 -0
- package/dist/ui/overlay/impl/projects-overlay-v2.d.ts +36 -0
- package/dist/ui/overlay/impl/projects-overlay-v2.js +499 -0
- package/dist/ui/overlay/impl/theme-overlay-v2.d.ts +42 -0
- package/dist/ui/overlay/impl/theme-overlay-v2.js +135 -0
- package/dist/ui/overlay/impl/tools-overlay-v2.d.ts +47 -0
- package/dist/ui/overlay/impl/tools-overlay-v2.js +218 -0
- package/dist/ui/overlay/impl/tutorial-overlay-v2.d.ts +31 -0
- package/dist/ui/overlay/impl/tutorial-overlay-v2.js +1035 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.d.ts +80 -0
- package/dist/ui/overlay/impl/workflow-overlay-v2.js +637 -0
- package/dist/ui/overlay/index.d.ts +33 -0
- package/dist/ui/overlay/index.js +35 -0
- package/dist/ui/overlay/key-utils.d.ts +6 -0
- package/dist/ui/overlay/key-utils.js +6 -0
- package/dist/ui/overlay/overlay-types.d.ts +128 -0
- package/dist/ui/overlay/overlay-types.js +22 -0
- package/dist/ui/overlay/types.d.ts +135 -0
- package/dist/ui/overlay/types.js +22 -0
- package/dist/ui/overlays/help-overlay-v2.d.ts +28 -0
- package/dist/ui/overlays/help-overlay-v2.js +198 -0
- package/dist/ui/overlays/index.d.ts +11 -0
- package/dist/ui/overlays/index.js +11 -0
- package/dist/ui/overlays.d.ts +0 -4
- package/dist/ui/overlays.js +0 -444
- package/dist/ui/permission-overlay-v2.d.ts +36 -0
- package/dist/ui/permission-overlay-v2.js +380 -0
- package/dist/ui/permission-overlay.d.ts +1 -1
- package/dist/ui/permission-overlay.js +186 -298
- package/dist/ui/projects-overlay.d.ts +19 -0
- package/dist/ui/projects-overlay.js +484 -0
- package/dist/ui/providers/types.d.ts +178 -0
- package/dist/ui/providers/types.js +9 -0
- package/dist/ui/render-modes.d.ts +36 -0
- package/dist/ui/render-modes.js +44 -0
- package/dist/ui/startup-menu.d.ts +36 -0
- package/dist/ui/startup-menu.js +236 -0
- package/dist/ui/subagent-renderer.d.ts +117 -0
- package/dist/ui/subagent-renderer.js +334 -0
- package/dist/ui/terminal-codes.d.ts +94 -0
- package/dist/ui/terminal-codes.js +124 -0
- package/dist/ui/terminal-renderer.d.ts +221 -0
- package/dist/ui/terminal-renderer.js +751 -0
- package/dist/ui/terminal-ui.d.ts +463 -0
- package/dist/ui/terminal-ui.js +2296 -0
- package/dist/ui/terminal.d.ts +20 -0
- package/dist/ui/terminal.js +72 -0
- package/dist/ui/theme-overlay-v2.d.ts +42 -0
- package/dist/ui/theme-overlay-v2.js +135 -0
- package/dist/ui/theme-overlay.d.ts +24 -0
- package/dist/ui/theme-overlay.js +127 -0
- package/dist/ui/todo-zone.js +53 -25
- package/dist/ui/tool-formatters.d.ts +16 -0
- package/dist/ui/tool-formatters.js +516 -0
- package/dist/ui/tools-overlay-v2.d.ts +47 -0
- package/dist/ui/tools-overlay-v2.js +218 -0
- package/dist/ui/tools-overlay.d.ts +10 -2
- package/dist/ui/tools-overlay.js +172 -220
- package/dist/ui/tutorial-overlay-v2.d.ts +31 -0
- package/dist/ui/tutorial-overlay-v2.js +1035 -0
- package/dist/ui/tutorial-overlay.d.ts +1 -0
- package/dist/ui/tutorial-overlay.js +400 -302
- package/dist/ui/workflow-overlay.d.ts +22 -0
- package/dist/ui/workflow-overlay.js +636 -0
- package/dist/utils/debug-log.d.ts +28 -0
- package/dist/utils/debug-log.js +57 -0
- package/dist/utils/model-tiers.js +1 -1
- package/dist/utils/path-safety.d.ts +56 -0
- package/dist/utils/path-safety.js +239 -0
- package/dist/workflow/guided-mode-injector.d.ts +42 -0
- package/dist/workflow/guided-mode-injector.js +191 -0
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.js +8 -0
- package/dist/workflow/step-criteria.d.ts +62 -0
- package/dist/workflow/step-criteria.js +150 -0
- package/dist/workflow/step-tracker.d.ts +92 -0
- package/dist/workflow/step-tracker.js +141 -0
- package/package.json +12 -5
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard Overlay V2
|
|
3
|
+
*
|
|
4
|
+
* Main entry point for the CLI when startup mode is 'dashboard'.
|
|
5
|
+
* Shows current project info, recent projects, and quick actions.
|
|
6
|
+
*
|
|
7
|
+
* Two tabs:
|
|
8
|
+
* - Dashboard: Current project, recent projects, actions
|
|
9
|
+
* - More: Help links, about information
|
|
10
|
+
*/
|
|
11
|
+
import { BaseOverlayV2 } from '../../base/index.js';
|
|
12
|
+
import type { RenderContext, OverlayAction, KeyEvent } from '../types.js';
|
|
13
|
+
import { type Project } from '../../../db/repositories/index.js';
|
|
14
|
+
type DashboardTab = 'dashboard' | 'more';
|
|
15
|
+
type DashboardAction = 'continue' | 'new' | 'projects' | 'chat' | 'workflow' | 'exit' | 'help' | 'config' | 'about';
|
|
16
|
+
interface DashboardState {
|
|
17
|
+
currentTab: DashboardTab;
|
|
18
|
+
selectedIndex: number;
|
|
19
|
+
currentProject: {
|
|
20
|
+
id: number;
|
|
21
|
+
name: string;
|
|
22
|
+
displayName: string;
|
|
23
|
+
path: string;
|
|
24
|
+
} | null;
|
|
25
|
+
recentProjects: Project[];
|
|
26
|
+
progress: {
|
|
27
|
+
completed: number;
|
|
28
|
+
total: number;
|
|
29
|
+
} | null;
|
|
30
|
+
}
|
|
31
|
+
export interface DashboardOverlayV2Result {
|
|
32
|
+
/** The action to take after closing the overlay */
|
|
33
|
+
action: DashboardAction;
|
|
34
|
+
/** The selected project ID (for 'continue' action) */
|
|
35
|
+
projectId?: number;
|
|
36
|
+
}
|
|
37
|
+
export declare class DashboardOverlayV2 extends BaseOverlayV2<DashboardState, DashboardOverlayV2Result> {
|
|
38
|
+
readonly type: "inline";
|
|
39
|
+
readonly id = "dashboard-overlay-v2";
|
|
40
|
+
protected minHeight: number;
|
|
41
|
+
constructor();
|
|
42
|
+
private getDashboardItems;
|
|
43
|
+
private getMoreItems;
|
|
44
|
+
private getItems;
|
|
45
|
+
private formatProjectStatus;
|
|
46
|
+
private formatTimeAgo;
|
|
47
|
+
protected renderContent(context: RenderContext): string[];
|
|
48
|
+
private renderTabBar;
|
|
49
|
+
private renderDashboardTab;
|
|
50
|
+
private renderMoreTab;
|
|
51
|
+
private renderDashboardFooter;
|
|
52
|
+
private shortenPath;
|
|
53
|
+
handleKey(key: KeyEvent): OverlayAction<DashboardOverlayV2Result>;
|
|
54
|
+
}
|
|
55
|
+
export {};
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard Overlay V2
|
|
3
|
+
*
|
|
4
|
+
* Main entry point for the CLI when startup mode is 'dashboard'.
|
|
5
|
+
* Shows current project info, recent projects, and quick actions.
|
|
6
|
+
*
|
|
7
|
+
* Two tabs:
|
|
8
|
+
* - Dashboard: Current project, recent projects, actions
|
|
9
|
+
* - More: Help links, about information
|
|
10
|
+
*/
|
|
11
|
+
import { BaseOverlayV2, isEscape, isEnter, isNavigateUp, isNavigateDown, isNavigateLeft, isNavigateRight, isTab, isShiftTab, isCtrlC, renderBorder, } from '../../base/index.js';
|
|
12
|
+
import { getCurrentProject } from '../../../tools/project-db.js';
|
|
13
|
+
import { projectRepository } from '../../../db/repositories/index.js';
|
|
14
|
+
import { workItemRepository } from '../../../db/repositories/work-item-repository.js';
|
|
15
|
+
// =============================================================================
|
|
16
|
+
// Constants
|
|
17
|
+
// =============================================================================
|
|
18
|
+
const VERSION = '0.4.0';
|
|
19
|
+
const TARGET_HEIGHT = 20; // Without logo (logo is printed to scrolling area)
|
|
20
|
+
const MAX_RECENT_PROJECTS = 3;
|
|
21
|
+
// =============================================================================
|
|
22
|
+
// Dashboard Overlay V2
|
|
23
|
+
// =============================================================================
|
|
24
|
+
export class DashboardOverlayV2 extends BaseOverlayV2 {
|
|
25
|
+
type = 'inline';
|
|
26
|
+
id = 'dashboard-overlay-v2';
|
|
27
|
+
minHeight = TARGET_HEIGHT;
|
|
28
|
+
constructor() {
|
|
29
|
+
// Load current project and recent projects
|
|
30
|
+
const current = getCurrentProject();
|
|
31
|
+
const { projects: recentProjects } = projectRepository.list({
|
|
32
|
+
status: 'all',
|
|
33
|
+
limit: MAX_RECENT_PROJECTS + 1, // Get one extra to exclude current
|
|
34
|
+
});
|
|
35
|
+
// Filter out current project from recent list
|
|
36
|
+
const filteredRecent = current
|
|
37
|
+
? recentProjects.filter(p => p.id !== current.id).slice(0, MAX_RECENT_PROJECTS)
|
|
38
|
+
: recentProjects.slice(0, MAX_RECENT_PROJECTS);
|
|
39
|
+
// Get progress for current project
|
|
40
|
+
let progress = null;
|
|
41
|
+
if (current) {
|
|
42
|
+
const allItems = workItemRepository.query({ project_id: current.id });
|
|
43
|
+
const completedItems = workItemRepository.query({ project_id: current.id, status: 'completed' });
|
|
44
|
+
progress = {
|
|
45
|
+
completed: completedItems.total,
|
|
46
|
+
total: allItems.total,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
super({
|
|
50
|
+
currentTab: 'dashboard',
|
|
51
|
+
selectedIndex: 0,
|
|
52
|
+
currentProject: current,
|
|
53
|
+
recentProjects: filteredRecent,
|
|
54
|
+
progress,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
// ===========================================================================
|
|
58
|
+
// Get Items for Current Tab
|
|
59
|
+
// ===========================================================================
|
|
60
|
+
getDashboardItems() {
|
|
61
|
+
const items = [];
|
|
62
|
+
if (this.state.currentProject) {
|
|
63
|
+
// First item: Continue with current project
|
|
64
|
+
items.push({
|
|
65
|
+
key: '',
|
|
66
|
+
label: `Continue with ${this.state.currentProject.displayName}`,
|
|
67
|
+
description: 'Resume working on current project',
|
|
68
|
+
action: 'continue',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Show recent projects as switch options (always, if any exist)
|
|
72
|
+
for (const project of this.state.recentProjects) {
|
|
73
|
+
items.push({
|
|
74
|
+
key: '',
|
|
75
|
+
label: `Switch to ${project.displayName}`,
|
|
76
|
+
description: this.formatProjectStatus(project),
|
|
77
|
+
action: 'continue',
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
// If no projects at all, show create/chat options
|
|
81
|
+
if (items.length === 0) {
|
|
82
|
+
items.push({
|
|
83
|
+
key: 'n',
|
|
84
|
+
label: '/new Project',
|
|
85
|
+
description: 'Create new or import existing project',
|
|
86
|
+
action: 'new',
|
|
87
|
+
});
|
|
88
|
+
items.push({
|
|
89
|
+
key: 'c',
|
|
90
|
+
label: 'Quick Chat',
|
|
91
|
+
description: 'Chat without project context',
|
|
92
|
+
action: 'chat',
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return items;
|
|
96
|
+
}
|
|
97
|
+
getMoreItems() {
|
|
98
|
+
return [
|
|
99
|
+
{ key: '?', label: 'Help', description: 'Show help and available commands', action: 'help' },
|
|
100
|
+
{ key: '', label: 'Settings', description: 'Open configuration panel', action: 'config' },
|
|
101
|
+
{ key: '', label: 'About', description: `compilr-dev-cli v${VERSION}`, action: 'about' },
|
|
102
|
+
];
|
|
103
|
+
}
|
|
104
|
+
getItems() {
|
|
105
|
+
return this.state.currentTab === 'dashboard' ? this.getDashboardItems() : this.getMoreItems();
|
|
106
|
+
}
|
|
107
|
+
formatProjectStatus(project) {
|
|
108
|
+
const status = project.status.charAt(0).toUpperCase() + project.status.slice(1);
|
|
109
|
+
const ago = this.formatTimeAgo(project.lastActivityAt ?? project.updatedAt);
|
|
110
|
+
return `${status} • ${ago}`;
|
|
111
|
+
}
|
|
112
|
+
formatTimeAgo(date) {
|
|
113
|
+
const now = new Date();
|
|
114
|
+
const diffMs = now.getTime() - date.getTime();
|
|
115
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
116
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
117
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
118
|
+
const diffWeeks = Math.floor(diffDays / 7);
|
|
119
|
+
if (diffMins < 1)
|
|
120
|
+
return 'just now';
|
|
121
|
+
if (diffMins < 60)
|
|
122
|
+
return `${String(diffMins)}m ago`;
|
|
123
|
+
if (diffHours < 24)
|
|
124
|
+
return `${String(diffHours)}h ago`;
|
|
125
|
+
if (diffDays === 1)
|
|
126
|
+
return 'yesterday';
|
|
127
|
+
if (diffDays < 7)
|
|
128
|
+
return `${String(diffDays)} days ago`;
|
|
129
|
+
if (diffWeeks === 1)
|
|
130
|
+
return '1 week ago';
|
|
131
|
+
return `${String(diffWeeks)} weeks ago`;
|
|
132
|
+
}
|
|
133
|
+
// ===========================================================================
|
|
134
|
+
// Rendering
|
|
135
|
+
// ===========================================================================
|
|
136
|
+
renderContent(context) {
|
|
137
|
+
const lines = [];
|
|
138
|
+
const s = context.styles;
|
|
139
|
+
const cols = context.width;
|
|
140
|
+
// 1. Tab bar (logo is printed to scrolling area by menuCommand)
|
|
141
|
+
lines.push(renderBorder(cols, s));
|
|
142
|
+
lines.push(this.renderTabBar(s));
|
|
143
|
+
lines.push(renderBorder(cols, s));
|
|
144
|
+
lines.push('');
|
|
145
|
+
// 3. Content based on current tab
|
|
146
|
+
if (this.state.currentTab === 'dashboard') {
|
|
147
|
+
lines.push(...this.renderDashboardTab(context));
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
lines.push(...this.renderMoreTab(context));
|
|
151
|
+
}
|
|
152
|
+
// 4. Footer with keyboard hints
|
|
153
|
+
lines.push('');
|
|
154
|
+
lines.push(...this.renderDashboardFooter(context));
|
|
155
|
+
// Pad to target height
|
|
156
|
+
while (lines.length < TARGET_HEIGHT) {
|
|
157
|
+
lines.push('');
|
|
158
|
+
}
|
|
159
|
+
return lines;
|
|
160
|
+
}
|
|
161
|
+
renderTabBar(s) {
|
|
162
|
+
const dashLabel = this.state.currentTab === 'dashboard' ? s.selected(' Dashboard ') : s.muted(' Dashboard ');
|
|
163
|
+
const moreLabel = this.state.currentTab === 'more' ? s.selected(' More ') : s.muted(' More ');
|
|
164
|
+
const hint = s.muted('(Tab Switch · 1-2 Jump)');
|
|
165
|
+
return ` ${dashLabel} │ ${moreLabel} ${hint}`;
|
|
166
|
+
}
|
|
167
|
+
renderDashboardTab(context) {
|
|
168
|
+
const lines = [];
|
|
169
|
+
const s = context.styles;
|
|
170
|
+
const items = this.getDashboardItems();
|
|
171
|
+
const hasProjects = this.state.currentProject || this.state.recentProjects.length > 0;
|
|
172
|
+
if (this.state.currentProject) {
|
|
173
|
+
// Current project section (display info)
|
|
174
|
+
lines.push(` ${s.primaryBold('CURRENT PROJECT')}`);
|
|
175
|
+
lines.push(` ${s.primary('★')} ${s.primaryBold(this.state.currentProject.displayName)}`);
|
|
176
|
+
// Path, status, mode
|
|
177
|
+
const project = projectRepository.getById(this.state.currentProject.id);
|
|
178
|
+
if (project) {
|
|
179
|
+
const pathShort = this.shortenPath(project.path);
|
|
180
|
+
lines.push(` ${s.muted(pathShort)} │ ${s.muted(project.status)} │ ${s.muted(project.workflowMode)}`);
|
|
181
|
+
}
|
|
182
|
+
// Progress bar
|
|
183
|
+
if (this.state.progress && this.state.progress.total > 0) {
|
|
184
|
+
const pct = Math.round((this.state.progress.completed / this.state.progress.total) * 100);
|
|
185
|
+
const barWidth = 20;
|
|
186
|
+
const filled = Math.round((pct / 100) * barWidth);
|
|
187
|
+
const empty = barWidth - filled;
|
|
188
|
+
const bar = s.success('█'.repeat(filled)) + s.muted('░'.repeat(empty));
|
|
189
|
+
lines.push(` Progress: ${bar} ${String(pct)}% (${String(this.state.progress.completed)}/${String(this.state.progress.total)} items)`);
|
|
190
|
+
}
|
|
191
|
+
lines.push('');
|
|
192
|
+
}
|
|
193
|
+
else if (hasProjects) {
|
|
194
|
+
// No current project but have recent projects - show select prompt
|
|
195
|
+
lines.push(` ${s.primaryBold('SELECT A PROJECT')}`);
|
|
196
|
+
lines.push(` ${s.muted('No project currently selected. Choose a project to continue.')}`);
|
|
197
|
+
lines.push('');
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
// No projects at all - welcome screen
|
|
201
|
+
lines.push(` ${s.primaryBold('WELCOME TO COMPILR DEV CLI')}`);
|
|
202
|
+
lines.push('');
|
|
203
|
+
lines.push(` ${s.muted('Get started by creating a new project or importing an existing')}`);
|
|
204
|
+
lines.push(` ${s.muted('repository. Or use Quick Chat for general assistance.')}`);
|
|
205
|
+
lines.push('');
|
|
206
|
+
}
|
|
207
|
+
// Actions list
|
|
208
|
+
lines.push(` ${s.secondary('ACTIONS')}`);
|
|
209
|
+
for (let i = 0; i < items.length; i++) {
|
|
210
|
+
const item = items[i];
|
|
211
|
+
const isSelected = i === this.state.selectedIndex;
|
|
212
|
+
const prefix = isSelected ? s.primary(' ❯ ') : ' ';
|
|
213
|
+
const label = isSelected ? s.primary(item.label.padEnd(35)) : item.label.padEnd(35);
|
|
214
|
+
lines.push(`${prefix}${label}${s.muted(item.description)}`);
|
|
215
|
+
}
|
|
216
|
+
// Shortcut hints (only if we have projects)
|
|
217
|
+
if (hasProjects) {
|
|
218
|
+
lines.push('');
|
|
219
|
+
lines.push(` ${s.muted('[n] /new [p] Projects [c] Chat [w] Workflow')}`);
|
|
220
|
+
}
|
|
221
|
+
return lines;
|
|
222
|
+
}
|
|
223
|
+
renderMoreTab(context) {
|
|
224
|
+
const lines = [];
|
|
225
|
+
const s = context.styles;
|
|
226
|
+
lines.push(` ${s.primaryBold('HELP & DOCUMENTATION')}`);
|
|
227
|
+
lines.push('');
|
|
228
|
+
const items = this.getMoreItems();
|
|
229
|
+
for (let i = 0; i < items.length; i++) {
|
|
230
|
+
const item = items[i];
|
|
231
|
+
const isSelected = i === this.state.selectedIndex;
|
|
232
|
+
const prefix = isSelected ? s.primary(' ❯ ') : ' ';
|
|
233
|
+
const label = isSelected ? s.primary(item.label.padEnd(25)) : item.label.padEnd(25);
|
|
234
|
+
lines.push(`${prefix}${label}${s.muted(item.description)}`);
|
|
235
|
+
}
|
|
236
|
+
lines.push('');
|
|
237
|
+
lines.push(` ${s.muted('For more options, use /config to open settings.')}`);
|
|
238
|
+
return lines;
|
|
239
|
+
}
|
|
240
|
+
renderDashboardFooter(context) {
|
|
241
|
+
const s = context.styles;
|
|
242
|
+
return [
|
|
243
|
+
s.muted(' ↑↓/jk Navigate Enter Select q Quit'),
|
|
244
|
+
];
|
|
245
|
+
}
|
|
246
|
+
shortenPath(fullPath) {
|
|
247
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
248
|
+
if (home && fullPath.startsWith(home)) {
|
|
249
|
+
return '~' + fullPath.slice(home.length);
|
|
250
|
+
}
|
|
251
|
+
return fullPath;
|
|
252
|
+
}
|
|
253
|
+
// ===========================================================================
|
|
254
|
+
// Key Handling
|
|
255
|
+
// ===========================================================================
|
|
256
|
+
handleKey(key) {
|
|
257
|
+
const data = key.raw;
|
|
258
|
+
const char = data.toString();
|
|
259
|
+
const items = this.getItems();
|
|
260
|
+
// Only q exits - Escape does nothing on dashboard (it's the home screen)
|
|
261
|
+
if (char === 'q') {
|
|
262
|
+
return this.close({ action: 'exit' });
|
|
263
|
+
}
|
|
264
|
+
// Escape and Ctrl+C just do nothing on dashboard
|
|
265
|
+
if (isEscape(data) || isCtrlC(data)) {
|
|
266
|
+
return this.noAction();
|
|
267
|
+
}
|
|
268
|
+
// Tab switching
|
|
269
|
+
if (isTab(data) || isNavigateRight(data) || char === 'l') {
|
|
270
|
+
this.state.currentTab = this.state.currentTab === 'dashboard' ? 'more' : 'dashboard';
|
|
271
|
+
this.state.selectedIndex = 0;
|
|
272
|
+
return this.rerender();
|
|
273
|
+
}
|
|
274
|
+
if (isShiftTab(data) || isNavigateLeft(data) || char === 'h') {
|
|
275
|
+
this.state.currentTab = this.state.currentTab === 'dashboard' ? 'more' : 'dashboard';
|
|
276
|
+
this.state.selectedIndex = 0;
|
|
277
|
+
return this.rerender();
|
|
278
|
+
}
|
|
279
|
+
// Number keys for tab jump (1 = Dashboard, 2 = More)
|
|
280
|
+
if (char === '1') {
|
|
281
|
+
this.state.currentTab = 'dashboard';
|
|
282
|
+
this.state.selectedIndex = 0;
|
|
283
|
+
return this.rerender();
|
|
284
|
+
}
|
|
285
|
+
if (char === '2') {
|
|
286
|
+
this.state.currentTab = 'more';
|
|
287
|
+
this.state.selectedIndex = 0;
|
|
288
|
+
return this.rerender();
|
|
289
|
+
}
|
|
290
|
+
// Navigation
|
|
291
|
+
if (isNavigateUp(data) || char === 'k') {
|
|
292
|
+
if (this.state.selectedIndex > 0) {
|
|
293
|
+
this.state.selectedIndex--;
|
|
294
|
+
return this.rerender();
|
|
295
|
+
}
|
|
296
|
+
return this.noAction();
|
|
297
|
+
}
|
|
298
|
+
if (isNavigateDown(data) || char === 'j') {
|
|
299
|
+
if (this.state.selectedIndex < items.length - 1) {
|
|
300
|
+
this.state.selectedIndex++;
|
|
301
|
+
return this.rerender();
|
|
302
|
+
}
|
|
303
|
+
return this.noAction();
|
|
304
|
+
}
|
|
305
|
+
// Enter selects current item
|
|
306
|
+
if (isEnter(data)) {
|
|
307
|
+
const selectedItem = items[this.state.selectedIndex];
|
|
308
|
+
if (selectedItem) {
|
|
309
|
+
if (selectedItem.action === 'continue') {
|
|
310
|
+
// For continue action, determine which project
|
|
311
|
+
if (this.state.currentProject && this.state.selectedIndex === 0) {
|
|
312
|
+
// First item = current project (only if we have a current project)
|
|
313
|
+
return this.close({
|
|
314
|
+
action: 'continue',
|
|
315
|
+
projectId: this.state.currentProject.id,
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
else {
|
|
319
|
+
// Recent projects - offset by 1 if we have a current project
|
|
320
|
+
const recentIndex = this.state.currentProject
|
|
321
|
+
? this.state.selectedIndex - 1
|
|
322
|
+
: this.state.selectedIndex;
|
|
323
|
+
const recentProject = this.state.recentProjects[recentIndex];
|
|
324
|
+
if (recentProject) {
|
|
325
|
+
return this.close({
|
|
326
|
+
action: 'continue',
|
|
327
|
+
projectId: recentProject.id,
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
// For other actions (new, chat, help, config, about)
|
|
333
|
+
return this.close({ action: selectedItem.action });
|
|
334
|
+
}
|
|
335
|
+
return this.noAction();
|
|
336
|
+
}
|
|
337
|
+
// Quick action shortcuts (Dashboard tab only)
|
|
338
|
+
if (this.state.currentTab === 'dashboard') {
|
|
339
|
+
switch (char) {
|
|
340
|
+
case 'n':
|
|
341
|
+
return this.close({ action: 'new' });
|
|
342
|
+
case 'p':
|
|
343
|
+
return this.close({ action: 'projects' });
|
|
344
|
+
case 'c':
|
|
345
|
+
return this.close({ action: 'chat' });
|
|
346
|
+
case 'w':
|
|
347
|
+
if (this.state.currentProject) {
|
|
348
|
+
return this.close({ action: 'workflow' });
|
|
349
|
+
}
|
|
350
|
+
return this.noAction();
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// More tab shortcuts
|
|
354
|
+
if (this.state.currentTab === 'more' && char === '?') {
|
|
355
|
+
return this.close({ action: 'help' });
|
|
356
|
+
}
|
|
357
|
+
return this.noAction();
|
|
358
|
+
}
|
|
359
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docs Overlay V2
|
|
3
|
+
*
|
|
4
|
+
* Document browser for project documents (PRD, architecture, design, notes).
|
|
5
|
+
* Uses TabbedListOverlayV2 for consistent list/tab/search behavior.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Tabbed filtering by document type
|
|
9
|
+
* - Search with / toggle
|
|
10
|
+
* - Paginated list
|
|
11
|
+
* - Returns selected document for viewing in separate fullscreen overlay
|
|
12
|
+
*/
|
|
13
|
+
import { TabbedListOverlayV2 } from '../../base/tabbed-list-overlay-v2.js';
|
|
14
|
+
import type { OverlayAction, KeyEvent } from '../types.js';
|
|
15
|
+
import { type ProjectDocument } from '../../../db/repositories/document-repository.js';
|
|
16
|
+
export interface DocsOverlayV2Result {
|
|
17
|
+
/** Selected document to view (if any) */
|
|
18
|
+
selectedDocument?: ProjectDocument;
|
|
19
|
+
/** Whether user cancelled (Ctrl+C or Esc) */
|
|
20
|
+
cancelled: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare class DocsOverlayV2 extends TabbedListOverlayV2<ProjectDocument, DocsOverlayV2Result> {
|
|
23
|
+
readonly type: "inline";
|
|
24
|
+
readonly id = "docs-overlay-v2";
|
|
25
|
+
private readonly projectName;
|
|
26
|
+
/**
|
|
27
|
+
* @param projectId - Optional project ID to view documents for.
|
|
28
|
+
* If not provided, uses the active project.
|
|
29
|
+
* Pass this when opening from workflow overlay for a specific project.
|
|
30
|
+
*/
|
|
31
|
+
constructor(projectId?: number);
|
|
32
|
+
/**
|
|
33
|
+
* Override to render project name in header
|
|
34
|
+
*/
|
|
35
|
+
protected renderHeader(title: string, subtitle?: string): string[];
|
|
36
|
+
/**
|
|
37
|
+
* Override to handle item selection.
|
|
38
|
+
* Returns the selected document so the command handler can show it in a fullscreen overlay.
|
|
39
|
+
*/
|
|
40
|
+
protected onItemSelected(doc: ProjectDocument): DocsOverlayV2Result | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Override to return result on close
|
|
43
|
+
*/
|
|
44
|
+
handleKey(key: KeyEvent): OverlayAction<DocsOverlayV2Result>;
|
|
45
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Docs Overlay V2
|
|
3
|
+
*
|
|
4
|
+
* Document browser for project documents (PRD, architecture, design, notes).
|
|
5
|
+
* Uses TabbedListOverlayV2 for consistent list/tab/search behavior.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Tabbed filtering by document type
|
|
9
|
+
* - Search with / toggle
|
|
10
|
+
* - Paginated list
|
|
11
|
+
* - Returns selected document for viewing in separate fullscreen overlay
|
|
12
|
+
*/
|
|
13
|
+
import { TabbedListOverlayV2 } from '../../base/tabbed-list-overlay-v2.js';
|
|
14
|
+
import { documentRepository } from '../../../db/repositories/document-repository.js';
|
|
15
|
+
import { getActiveProject } from '../../../tools/project-db.js';
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Constants
|
|
18
|
+
// =============================================================================
|
|
19
|
+
const PAGE_SIZE = 10;
|
|
20
|
+
const DOC_TYPE_LABELS = {
|
|
21
|
+
'prd': 'PRD',
|
|
22
|
+
'architecture': 'ARCH',
|
|
23
|
+
'design': 'DESIGN',
|
|
24
|
+
'notes': 'NOTES',
|
|
25
|
+
};
|
|
26
|
+
const TABS = [
|
|
27
|
+
{ id: 'all', label: 'All' },
|
|
28
|
+
{ id: 'prd', label: 'PRD' },
|
|
29
|
+
{ id: 'architecture', label: 'ARCH' },
|
|
30
|
+
{ id: 'design', label: 'DESIGN' },
|
|
31
|
+
{ id: 'notes', label: 'NOTES' },
|
|
32
|
+
];
|
|
33
|
+
// =============================================================================
|
|
34
|
+
// Docs Overlay V2
|
|
35
|
+
// =============================================================================
|
|
36
|
+
export class DocsOverlayV2 extends TabbedListOverlayV2 {
|
|
37
|
+
type = 'inline';
|
|
38
|
+
id = 'docs-overlay-v2';
|
|
39
|
+
projectName;
|
|
40
|
+
/**
|
|
41
|
+
* @param projectId - Optional project ID to view documents for.
|
|
42
|
+
* If not provided, uses the active project.
|
|
43
|
+
* Pass this when opening from workflow overlay for a specific project.
|
|
44
|
+
*/
|
|
45
|
+
constructor(projectId) {
|
|
46
|
+
// Use provided projectId, or fall back to active project
|
|
47
|
+
const activeProject = getActiveProject();
|
|
48
|
+
const resolvedProjectId = projectId ?? activeProject?.id ?? null;
|
|
49
|
+
const projectName = projectId
|
|
50
|
+
? null // Will be loaded if needed, but we don't have it here
|
|
51
|
+
: activeProject?.displayName ?? null;
|
|
52
|
+
// Load documents
|
|
53
|
+
const documents = resolvedProjectId !== null
|
|
54
|
+
? documentRepository.listByProject(resolvedProjectId)
|
|
55
|
+
: [];
|
|
56
|
+
super({
|
|
57
|
+
title: 'Documents',
|
|
58
|
+
tabs: TABS,
|
|
59
|
+
items: documents,
|
|
60
|
+
pageSize: PAGE_SIZE,
|
|
61
|
+
filterByTab: (doc, tabId) => {
|
|
62
|
+
if (tabId === 'all')
|
|
63
|
+
return true;
|
|
64
|
+
return doc.docType === tabId;
|
|
65
|
+
},
|
|
66
|
+
getSearchText: (doc) => `${doc.title} ${doc.docType}`,
|
|
67
|
+
renderItem: (doc, isSelected, styles) => {
|
|
68
|
+
const prefix = isSelected ? styles.primary('❯ ') : ' ';
|
|
69
|
+
const typeLabel = (DOC_TYPE_LABELS[doc.docType] || doc.docType).padEnd(8);
|
|
70
|
+
const title = doc.title.slice(0, 50);
|
|
71
|
+
if (isSelected) {
|
|
72
|
+
return `${prefix}${styles.primaryBold(typeLabel)} ${styles.primary(title)}`;
|
|
73
|
+
}
|
|
74
|
+
return `${prefix}${styles.muted(typeLabel)} ${styles.secondary(title)}`;
|
|
75
|
+
},
|
|
76
|
+
showCount: true,
|
|
77
|
+
emptyMessage: resolvedProjectId === null
|
|
78
|
+
? 'No active project. Use /projects to select one.'
|
|
79
|
+
: 'No documents found. Use /design or /arch to create documents.',
|
|
80
|
+
noResultsMessage: 'No documents match the search.',
|
|
81
|
+
});
|
|
82
|
+
this.projectName = projectName;
|
|
83
|
+
this.minHeight = 20;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Override to render project name in header
|
|
87
|
+
*/
|
|
88
|
+
renderHeader(title, subtitle) {
|
|
89
|
+
const displaySubtitle = this.projectName || subtitle;
|
|
90
|
+
return super.renderHeader(title, displaySubtitle);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Override to handle item selection.
|
|
94
|
+
* Returns the selected document so the command handler can show it in a fullscreen overlay.
|
|
95
|
+
*/
|
|
96
|
+
onItemSelected(doc) {
|
|
97
|
+
return { selectedDocument: doc, cancelled: false };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Override to return result on close
|
|
101
|
+
*/
|
|
102
|
+
handleKey(key) {
|
|
103
|
+
// Check for close keys first
|
|
104
|
+
if (this.isInterruptKey(key)) {
|
|
105
|
+
return this.close({ cancelled: true });
|
|
106
|
+
}
|
|
107
|
+
if (this.isCloseKey(key) && !this.state.searchMode) {
|
|
108
|
+
return this.close({ cancelled: true });
|
|
109
|
+
}
|
|
110
|
+
// Let parent handle everything else (including Enter → onItemSelected)
|
|
111
|
+
// Parent will return the result from onItemSelected, so pass it through
|
|
112
|
+
return super.handleKey(key);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document Detail Overlay V2
|
|
3
|
+
*
|
|
4
|
+
* Fullscreen markdown document viewer AND editor with vim-style navigation.
|
|
5
|
+
* Separate from DocsOverlayV2 (inline list) to allow proper fullscreen rendering.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Full-screen document viewing with markdown rendering
|
|
9
|
+
* - Vim-style navigation (j/k, g/G, PgUp/PgDn)
|
|
10
|
+
* - Edit mode with raw markdown editing
|
|
11
|
+
* - Save to database (Ctrl+S)
|
|
12
|
+
* - Dirty check with save prompt on exit
|
|
13
|
+
*/
|
|
14
|
+
import { BaseOverlayV2 } from '../../base/overlay-base-v2.js';
|
|
15
|
+
import type { RenderContext, OverlayAction, KeyEvent } from '../types.js';
|
|
16
|
+
import { type ProjectDocument } from '../../../db/repositories/document-repository.js';
|
|
17
|
+
export interface DocumentDetailResult {
|
|
18
|
+
/** Whether to go back to the document list */
|
|
19
|
+
goBack: boolean;
|
|
20
|
+
}
|
|
21
|
+
interface DocumentDetailState {
|
|
22
|
+
contentLines: string[];
|
|
23
|
+
scrollOffset: number;
|
|
24
|
+
isEditMode: boolean;
|
|
25
|
+
rawLines: string[];
|
|
26
|
+
cursorLine: number;
|
|
27
|
+
cursorColumn: number;
|
|
28
|
+
editScrollOffset: number;
|
|
29
|
+
isDirty: boolean;
|
|
30
|
+
originalContent: string;
|
|
31
|
+
showSavePrompt: boolean;
|
|
32
|
+
saveMessage: string | null;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Fullscreen document viewer and editor overlay.
|
|
36
|
+
* Shows a single document with vim-style scrolling navigation.
|
|
37
|
+
* Supports edit mode for modifying raw markdown content.
|
|
38
|
+
*/
|
|
39
|
+
export declare class DocumentDetailOverlayV2 extends BaseOverlayV2<DocumentDetailState, DocumentDetailResult> {
|
|
40
|
+
private readonly document;
|
|
41
|
+
readonly type: "inline";
|
|
42
|
+
readonly id = "document-detail-overlay-v2";
|
|
43
|
+
readonly usesAlternateScreen = true;
|
|
44
|
+
constructor(document: ProjectDocument);
|
|
45
|
+
/**
|
|
46
|
+
* Enter alternate screen buffer when overlay mounts.
|
|
47
|
+
* This preserves the main screen content.
|
|
48
|
+
*/
|
|
49
|
+
onMount(): void;
|
|
50
|
+
/**
|
|
51
|
+
* Exit alternate screen buffer when overlay unmounts.
|
|
52
|
+
* This restores the main screen content.
|
|
53
|
+
*/
|
|
54
|
+
onUnmount(): void;
|
|
55
|
+
protected renderContent(context: RenderContext): string[];
|
|
56
|
+
private renderViewMode;
|
|
57
|
+
private renderEditMode;
|
|
58
|
+
private renderLineWithCursor;
|
|
59
|
+
private ensureCursorVisible;
|
|
60
|
+
handleKey(key: KeyEvent): OverlayAction<DocumentDetailResult>;
|
|
61
|
+
private handleViewModeKey;
|
|
62
|
+
private handleEditModeKey;
|
|
63
|
+
private handleSavePromptKey;
|
|
64
|
+
private moveCursorUp;
|
|
65
|
+
private moveCursorDown;
|
|
66
|
+
private moveCursorLeft;
|
|
67
|
+
private moveCursorRight;
|
|
68
|
+
private clampCursorColumn;
|
|
69
|
+
private getCurrentLine;
|
|
70
|
+
private insertText;
|
|
71
|
+
private handleBackspace;
|
|
72
|
+
private handleDelete;
|
|
73
|
+
private handleEnter;
|
|
74
|
+
private saveDocument;
|
|
75
|
+
private exitEditMode;
|
|
76
|
+
}
|
|
77
|
+
export {};
|