fecode-cli 1.0.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 (74) hide show
  1. package/dist/App.d.ts +33 -0
  2. package/dist/App.js +2224 -0
  3. package/dist/approvalResolver.d.ts +12 -0
  4. package/dist/approvalResolver.js +112 -0
  5. package/dist/commands.d.ts +11 -0
  6. package/dist/commands.js +33 -0
  7. package/dist/index.d.ts +3 -0
  8. package/dist/index.js +15175 -0
  9. package/dist/ui/AppShell.d.ts +14 -0
  10. package/dist/ui/AppShell.js +25 -0
  11. package/dist/ui/ApprovalPrompt.d.ts +31 -0
  12. package/dist/ui/ApprovalPrompt.js +55 -0
  13. package/dist/ui/BlockedView.d.ts +13 -0
  14. package/dist/ui/BlockedView.js +7 -0
  15. package/dist/ui/CommandPalette.d.ts +8 -0
  16. package/dist/ui/CommandPalette.js +18 -0
  17. package/dist/ui/CurrentStepView.d.ts +16 -0
  18. package/dist/ui/CurrentStepView.js +28 -0
  19. package/dist/ui/DiagnosticsView.d.ts +45 -0
  20. package/dist/ui/DiagnosticsView.js +23 -0
  21. package/dist/ui/ExecutionTimeline.d.ts +15 -0
  22. package/dist/ui/ExecutionTimeline.js +51 -0
  23. package/dist/ui/ExecutionView.d.ts +42 -0
  24. package/dist/ui/ExecutionView.js +20 -0
  25. package/dist/ui/Header.d.ts +15 -0
  26. package/dist/ui/Header.js +47 -0
  27. package/dist/ui/HelpView.d.ts +3 -0
  28. package/dist/ui/HelpView.js +35 -0
  29. package/dist/ui/MessageBubble.d.ts +9 -0
  30. package/dist/ui/MessageBubble.js +58 -0
  31. package/dist/ui/PlanStep.d.ts +16 -0
  32. package/dist/ui/PlanStep.js +71 -0
  33. package/dist/ui/PlanView.d.ts +26 -0
  34. package/dist/ui/PlanView.js +24 -0
  35. package/dist/ui/ProgressBar.d.ts +10 -0
  36. package/dist/ui/ProgressBar.js +14 -0
  37. package/dist/ui/RecoveryView.d.ts +20 -0
  38. package/dist/ui/RecoveryView.js +19 -0
  39. package/dist/ui/ReplanView.d.ts +16 -0
  40. package/dist/ui/ReplanView.js +21 -0
  41. package/dist/ui/ResumeView.d.ts +15 -0
  42. package/dist/ui/ResumeView.js +25 -0
  43. package/dist/ui/RiskNotice.d.ts +10 -0
  44. package/dist/ui/RiskNotice.js +21 -0
  45. package/dist/ui/RunHistoryView.d.ts +15 -0
  46. package/dist/ui/RunHistoryView.js +39 -0
  47. package/dist/ui/StatusBar.d.ts +16 -0
  48. package/dist/ui/StatusBar.js +104 -0
  49. package/dist/ui/TaskInput.d.ts +15 -0
  50. package/dist/ui/TaskInput.js +8 -0
  51. package/dist/ui/ThinkingBlock.d.ts +8 -0
  52. package/dist/ui/ThinkingBlock.js +13 -0
  53. package/dist/ui/ThinkingIndicator.d.ts +7 -0
  54. package/dist/ui/ThinkingIndicator.js +20 -0
  55. package/dist/ui/TurnView.d.ts +13 -0
  56. package/dist/ui/TurnView.js +11 -0
  57. package/dist/ui/WorkspaceStatus.d.ts +20 -0
  58. package/dist/ui/WorkspaceStatus.js +23 -0
  59. package/dist/ui/index.d.ts +26 -0
  60. package/dist/ui/index.js +26 -0
  61. package/package.json +42 -0
  62. package/skills/accessibility/SKILL.md +98 -0
  63. package/skills/css/SKILL.md +90 -0
  64. package/skills/frontend-debugging/SKILL.md +201 -0
  65. package/skills/frontend-design/SKILL.md +358 -0
  66. package/skills/frontend-performance/SKILL.md +89 -0
  67. package/skills/frontend-testing/SKILL.md +87 -0
  68. package/skills/nextjs/SKILL.md +75 -0
  69. package/skills/react/SKILL.md +213 -0
  70. package/skills/responsive-design/SKILL.md +190 -0
  71. package/skills/svelte/SKILL.md +86 -0
  72. package/skills/tailwind/SKILL.md +74 -0
  73. package/skills/ui-review/SKILL.md +245 -0
  74. package/skills/vue/SKILL.md +72 -0
@@ -0,0 +1,14 @@
1
+ import React from "react";
2
+ export type TerminalLayoutMode = "wide" | "medium" | "narrow" | "very_narrow";
3
+ export declare function getTerminalLayout(columns?: number): TerminalLayoutMode;
4
+ export declare function truncateText(str: string, maxLength: number): string;
5
+ export interface AppShellProps {
6
+ header?: React.ReactNode;
7
+ children?: React.ReactNode;
8
+ sidebar?: React.ReactNode;
9
+ modal?: React.ReactNode;
10
+ footer?: React.ReactNode;
11
+ columns?: number;
12
+ }
13
+ export declare const AppShell: React.FC<AppShellProps>;
14
+ //# sourceMappingURL=AppShell.d.ts.map
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, useStdout } from "ink";
3
+ export function getTerminalLayout(columns = 80) {
4
+ if (columns >= 100)
5
+ return "wide";
6
+ if (columns >= 70)
7
+ return "medium";
8
+ if (columns >= 50)
9
+ return "narrow";
10
+ return "very_narrow";
11
+ }
12
+ export function truncateText(str, maxLength) {
13
+ if (!str)
14
+ return "";
15
+ if (str.length <= maxLength)
16
+ return str;
17
+ return str.slice(0, Math.max(0, maxLength - 3)) + "...";
18
+ }
19
+ export const AppShell = ({ header, children, sidebar, modal, footer, columns: explicitColumns }) => {
20
+ const { stdout } = useStdout();
21
+ const columns = explicitColumns ?? stdout?.columns ?? 80;
22
+ const layout = getTerminalLayout(columns);
23
+ return (_jsxs(Box, { flexDirection: "column", padding: 0, width: "100%", children: [header, sidebar && layout === "wide" ? (_jsxs(Box, { flexDirection: "row", width: "100%", children: [_jsx(Box, { width: "65%", flexDirection: "column", paddingRight: 1, children: children }), _jsx(Box, { width: "35%", flexDirection: "column", paddingLeft: 1, children: sidebar })] })) : (_jsxs(Box, { flexDirection: "column", width: "100%", children: [children, sidebar && _jsx(Box, { flexDirection: "column", marginTop: 1, children: sidebar })] })), modal, footer] }));
24
+ };
25
+ //# sourceMappingURL=AppShell.js.map
@@ -0,0 +1,31 @@
1
+ import React from "react";
2
+ export interface ChangeReviewItem {
3
+ path: string;
4
+ operation?: string;
5
+ additions?: number;
6
+ deletions?: number;
7
+ diff?: string;
8
+ }
9
+ export interface ApprovalPromptProps {
10
+ approvalType?: "plan" | "step_checkpoint" | "tool_permission" | "recovery" | "continuation" | "replan" | string;
11
+ title?: string;
12
+ stepTitle?: string;
13
+ stepOrder?: number;
14
+ totalSteps?: number;
15
+ toolName?: string;
16
+ reason?: string;
17
+ riskLevel?: string;
18
+ affectedTargets?: string[];
19
+ checkpointId?: string;
20
+ diff?: string;
21
+ changeReview?: {
22
+ files?: ChangeReviewItem[];
23
+ totalAddedLines?: number;
24
+ totalRemovedLines?: number;
25
+ };
26
+ value: string;
27
+ onChange: (val: string) => void;
28
+ onSubmit: (val: string) => void;
29
+ }
30
+ export declare const ApprovalPrompt: React.FC<ApprovalPromptProps>;
31
+ //# sourceMappingURL=ApprovalPrompt.d.ts.map
@@ -0,0 +1,55 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import TextInput from "ink-text-input";
4
+ export const ApprovalPrompt = ({ approvalType = "tool_permission", title, stepTitle, stepOrder, totalSteps, toolName, reason, riskLevel = "elevated", affectedTargets = [], checkpointId, diff, changeReview, value, onChange, onSubmit }) => {
5
+ const isFileEdit = toolName === "edit_file" ||
6
+ toolName === "write_file" ||
7
+ (changeReview?.files && changeReview.files.length > 0);
8
+ const getHeaderTitle = () => {
9
+ if (title)
10
+ return title;
11
+ if (isFileEdit)
12
+ return "⚠ FeCode wants to modify a file";
13
+ switch (approvalType) {
14
+ case "plan":
15
+ return "⚠ PLAN APPROVAL REQUIRED";
16
+ case "step_checkpoint":
17
+ return "⚠ STEP CHECKPOINT APPROVAL REQUIRED";
18
+ case "recovery":
19
+ return "⚠ RECOVERY APPROVAL REQUIRED";
20
+ case "continuation":
21
+ return "⚠ CONTINUATION APPROVAL REQUIRED";
22
+ case "replan":
23
+ return "⚠ REPLAN APPROVAL REQUIRED";
24
+ case "tool_permission":
25
+ default:
26
+ return "⚠ FeCode wants to use a tool";
27
+ }
28
+ };
29
+ const getRiskColor = (risk) => {
30
+ switch (risk.toLowerCase()) {
31
+ case "critical":
32
+ return "red";
33
+ case "elevated":
34
+ case "high":
35
+ return "yellow";
36
+ case "low":
37
+ return "green";
38
+ case "normal":
39
+ default:
40
+ return "cyan";
41
+ }
42
+ };
43
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "double", borderColor: "yellow", paddingX: 1, marginY: 1, children: [_jsx(Box, { marginBottom: 0, children: _jsx(Text, { bold: true, color: "yellow", children: getHeaderTitle() }) }), stepTitle && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Step: " }), _jsx(Text, { bold: true, color: "white", children: stepOrder !== undefined && totalSteps !== undefined
44
+ ? `[${stepOrder}/${totalSteps}] ${stepTitle}`
45
+ : stepTitle })] })), _jsxs(Box, { marginTop: 0, justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { color: "gray", children: "Risk: " }), _jsx(Text, { bold: true, color: getRiskColor(riskLevel), children: riskLevel.toUpperCase() })] }), _jsxs(Box, { children: [_jsx(Text, { color: "gray", children: "Checkpoint: " }), _jsx(Text, { color: checkpointId || riskLevel.toLowerCase() === "elevated" || riskLevel.toLowerCase() === "critical" ? "yellow" : "gray", children: checkpointId ? `REQUIRED (${checkpointId.slice(0, 18)})` : "REQUIRED" })] })] }), toolName && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Tool: " }), _jsx(Text, { bold: true, color: "magenta", children: toolName })] })), reason && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Reason: " }), _jsx(Text, { color: "white", children: reason })] })), affectedTargets.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Files / Resources:" }), affectedTargets.map((t, i) => (_jsxs(Text, { color: "cyan", children: [" ", "\u2022 ", t] }, `target-${i}`)))] })), changeReview && changeReview.files && changeReview.files.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { bold: true, color: "gray", children: "Change Review:" }), changeReview.files.map((cf, idx) => (_jsxs(Box, { flexDirection: "column", marginLeft: 1, children: [_jsxs(Box, { children: [_jsx(Text, { color: "white", children: cf.path }), cf.additions !== undefined && cf.deletions !== undefined && (_jsxs(Text, { color: "gray", children: [" ", "Change: +", cf.additions, " -", cf.deletions] }))] }), cf.diff && (_jsxs(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, marginY: 0, flexDirection: "column", children: [cf.diff.split("\n").slice(0, 15).map((line, lIdx) => {
46
+ const isAdd = line.startsWith("+") && !line.startsWith("+++");
47
+ const isDel = line.startsWith("-") && !line.startsWith("---");
48
+ return (_jsx(Text, { color: isAdd ? "green" : isDel ? "red" : "gray", children: line }, `diff-${lIdx}`));
49
+ }), cf.diff.split("\n").length > 15 && (_jsxs(Text, { color: "gray", children: ["... (", cf.diff.split("\n").length - 15, " lines omitted)"] }))] }))] }, `cf-${idx}`)))] })), diff && !changeReview && (_jsx(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, marginY: 1, flexDirection: "column", children: diff.split("\n").slice(0, 15).map((line, lIdx) => {
50
+ const isAdd = line.startsWith("+") && !line.startsWith("+++");
51
+ const isDel = line.startsWith("-") && !line.startsWith("---");
52
+ return (_jsx(Text, { color: isAdd ? "green" : isDel ? "red" : "gray", children: line }, `diff-raw-${lIdx}`));
53
+ }) })), _jsxs(Box, { marginTop: 1, children: [_jsxs(Text, { color: "yellow", bold: true, children: ["Allow? [y/N]:", " "] }), _jsx(TextInput, { value: value, onChange: onChange, onSubmit: onSubmit, placeholder: "n" })] })] }));
54
+ };
55
+ //# sourceMappingURL=ApprovalPrompt.js.map
@@ -0,0 +1,13 @@
1
+ import React from "react";
2
+ export interface BlockedViewProps {
3
+ planId?: string;
4
+ stepInfo?: string;
5
+ reason?: string;
6
+ affectedSteps?: string[];
7
+ isReconciliation?: boolean;
8
+ value: string;
9
+ onChange: (val: string) => void;
10
+ onSubmit: (val: string) => void;
11
+ }
12
+ export declare const BlockedView: React.FC<BlockedViewProps>;
13
+ //# sourceMappingURL=BlockedView.d.ts.map
@@ -0,0 +1,7 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import TextInput from "ink-text-input";
4
+ export const BlockedView = ({ planId, stepInfo, reason = "Workspace changed since approval.", affectedSteps = [], isReconciliation = false, value, onChange, onSubmit }) => {
5
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "double", borderColor: "red", paddingX: 1, marginY: 1, children: [_jsx(Box, { marginBottom: 0, children: _jsx(Text, { bold: true, color: "red", children: "\u26A0 PLAN EXECUTION BLOCKED" }) }), planId && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Plan: " }), _jsx(Text, { color: "white", bold: true, children: planId })] })), stepInfo && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Step: " }), _jsx(Text, { color: "white", children: stepInfo })] })), _jsxs(Box, { marginTop: 0, flexDirection: "column", children: [_jsx(Text, { color: "gray", children: "Reason:" }), _jsx(Text, { color: "red", children: reason })] }), affectedSteps.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Affected steps:" }), affectedSteps.map((s, i) => (_jsxs(Text, { color: "white", children: [" ", "\u2022 ", s] }, `aff-${i}`)))] })), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: "gray", children: "What action would you like to take?" }), isReconciliation ? (_jsxs(Box, { flexDirection: "row", marginY: 0, children: [_jsx(Text, { bold: true, color: "yellow", children: "[r]" }), _jsx(Text, { color: "white", children: " Recover from checkpoint " }), _jsx(Text, { bold: true, color: "cyan", children: "[p]" }), _jsx(Text, { color: "white", children: " Replan " }), _jsx(Text, { bold: true, color: "gray", children: "[x]" }), _jsx(Text, { color: "white", children: " Cancel (Default)" })] })) : (_jsxs(Box, { flexDirection: "row", marginY: 0, children: [_jsx(Text, { bold: true, color: "green", children: "[c]" }), _jsx(Text, { color: "white", children: " Continue " }), _jsx(Text, { bold: true, color: "cyan", children: "[r]" }), _jsx(Text, { color: "white", children: " Replan " }), _jsx(Text, { bold: true, color: "gray", children: "[x]" }), _jsx(Text, { color: "white", children: " Cancel (Default)" })] }))] }), _jsxs(Box, { marginTop: 0, children: [_jsxs(Text, { color: "yellow", bold: true, children: ["Choice [x]:", " "] }), _jsx(TextInput, { value: value, onChange: onChange, onSubmit: onSubmit, placeholder: "x" })] })] }));
6
+ };
7
+ //# sourceMappingURL=BlockedView.js.map
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ import type { CommandDef } from "../commands.js";
3
+ export interface CommandPaletteProps {
4
+ suggestions: CommandDef[];
5
+ selectedIndex: number;
6
+ }
7
+ export declare const CommandPalette: React.FC<CommandPaletteProps>;
8
+ //# sourceMappingURL=CommandPalette.d.ts.map
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ const MAX_VISIBLE = 8;
4
+ export const CommandPalette = ({ suggestions, selectedIndex }) => {
5
+ if (suggestions.length === 0)
6
+ return null;
7
+ const clampedIndex = Math.max(0, Math.min(selectedIndex, suggestions.length - 1));
8
+ const startIndex = clampedIndex >= MAX_VISIBLE
9
+ ? Math.min(clampedIndex - MAX_VISIBLE + 1, Math.max(0, suggestions.length - MAX_VISIBLE))
10
+ : 0;
11
+ const visible = suggestions.slice(startIndex, startIndex + MAX_VISIBLE);
12
+ const remaining = suggestions.length - (startIndex + visible.length);
13
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, marginBottom: 0, children: [visible.map((cmd, idx) => {
14
+ const isSelected = startIndex + idx === clampedIndex;
15
+ return (_jsxs(Box, { children: [_jsx(Text, { color: "cyan", bold: true, children: isSelected ? "› " : " " }), _jsx(Box, { width: 16, children: _jsx(Text, { color: isSelected ? "whiteBright" : "white", bold: isSelected, children: cmd.command }) }), _jsx(Text, { color: "gray", children: cmd.description })] }, cmd.command));
16
+ }), remaining > 0 && (_jsx(Box, { children: _jsxs(Text, { color: "gray", dimColor: true, children: [" \u2026", remaining, " more"] }) }))] }));
17
+ };
18
+ //# sourceMappingURL=CommandPalette.js.map
@@ -0,0 +1,16 @@
1
+ import React from "react";
2
+ export interface CurrentStepViewProps {
3
+ stepOrder?: number;
4
+ totalSteps?: number;
5
+ title?: string;
6
+ objective?: string;
7
+ riskLevel?: string;
8
+ checkpointRequired?: boolean;
9
+ verificationRequired?: boolean;
10
+ toolName?: string;
11
+ target?: string;
12
+ command?: string;
13
+ durationMs?: number;
14
+ }
15
+ export declare const CurrentStepView: React.FC<CurrentStepViewProps>;
16
+ //# sourceMappingURL=CurrentStepView.d.ts.map
@@ -0,0 +1,28 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ export const CurrentStepView = ({ stepOrder, totalSteps, title, objective, riskLevel = "normal", checkpointRequired = false, verificationRequired = false, toolName, target, command, durationMs }) => {
4
+ if (!title && !toolName && !command) {
5
+ return null;
6
+ }
7
+ const getRiskColor = (risk) => {
8
+ switch (risk.toLowerCase()) {
9
+ case "critical":
10
+ return "red";
11
+ case "elevated":
12
+ case "high":
13
+ return "yellow";
14
+ case "low":
15
+ return "green";
16
+ case "normal":
17
+ default:
18
+ return "cyan";
19
+ }
20
+ };
21
+ const stepPrefix = stepOrder !== undefined && totalSteps !== undefined
22
+ ? `Step ${stepOrder}/${totalSteps}:`
23
+ : "Current Operation:";
24
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", paddingX: 1, marginY: 0, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Box, { children: _jsxs(Text, { children: [_jsxs(Text, { bold: true, color: "cyan", children: ["\u25B6 ", stepPrefix, " "] }), _jsx(Text, { bold: true, color: "white", children: title || toolName || command })] }) }), _jsxs(Box, { children: [_jsx(Text, { color: "gray", children: "Risk: " }), _jsx(Text, { bold: true, color: getRiskColor(riskLevel), children: riskLevel.toUpperCase() })] })] }), objective && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Goal: " }), _jsx(Text, { color: "white", children: objective })] })), _jsxs(Box, { marginTop: 0, flexWrap: "wrap", children: [toolName && (_jsxs(Box, { marginRight: 2, children: [_jsx(Text, { color: "gray", children: "Tool: " }), _jsx(Text, { bold: true, color: "magenta", children: toolName })] })), target && (_jsxs(Box, { marginRight: 2, children: [_jsx(Text, { color: "gray", children: "Target: " }), _jsx(Text, { color: "cyan", children: target })] })), command && (_jsxs(Box, { marginRight: 2, children: [_jsx(Text, { color: "gray", children: "Command: " }), _jsx(Text, { color: "yellow", children: command })] })), checkpointRequired && (_jsx(Box, { marginRight: 2, children: _jsx(Text, { color: "yellow", children: "[Checkpoint Required]" }) })), verificationRequired && (_jsx(Box, { marginRight: 2, children: _jsx(Text, { color: "cyan", children: "[Verification Required]" }) })), durationMs !== undefined && durationMs > 0 && (_jsx(Box, { children: _jsxs(Text, { color: "gray", children: ["Elapsed:", " ", durationMs >= 1000
25
+ ? `${(durationMs / 1000).toFixed(1)}s`
26
+ : `${durationMs}ms`] }) }))] })] }));
27
+ };
28
+ //# sourceMappingURL=CurrentStepView.js.map
@@ -0,0 +1,45 @@
1
+ import React from "react";
2
+ export interface DiagnosticsViewProps {
3
+ summary?: {
4
+ runId: string;
5
+ startedAt: number;
6
+ completedAt?: number;
7
+ durationMs?: number;
8
+ finalStatus?: string;
9
+ cwd?: string;
10
+ userRequestSummary?: string;
11
+ activeSkills?: string[];
12
+ initialRiskLevel?: string;
13
+ riskReasons?: string[];
14
+ requiresCheckpoint?: boolean;
15
+ requiresExplicitApproval?: boolean;
16
+ verificationAttempts?: number;
17
+ maxVerificationAttempts?: number;
18
+ recoveryAttempts?: number;
19
+ maxRecoveryAttempts?: number;
20
+ totalPlanSteps?: number;
21
+ completedPlanSteps?: number;
22
+ tools?: Array<{
23
+ toolName: string;
24
+ count?: number;
25
+ calls?: number;
26
+ }>;
27
+ commands?: Array<{
28
+ command: string;
29
+ exitCode?: number | null;
30
+ }>;
31
+ files?: {
32
+ modified?: string[];
33
+ created?: string[];
34
+ deleted?: string[];
35
+ };
36
+ lifecycleTransitions?: Array<{
37
+ from: string;
38
+ to: string;
39
+ reason: string;
40
+ }>;
41
+ };
42
+ formattedOutput?: string;
43
+ }
44
+ export declare const DiagnosticsView: React.FC<DiagnosticsViewProps>;
45
+ //# sourceMappingURL=DiagnosticsView.d.ts.map
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ export const DiagnosticsView = ({ summary, formattedOutput }) => {
4
+ if (formattedOutput) {
5
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "magenta", paddingX: 1, marginY: 1, children: [_jsx(Box, { marginBottom: 0, children: _jsx(Text, { bold: true, color: "magenta", children: "Diagnostics & Debug Info" }) }), _jsx(Text, { color: "white", children: formattedOutput })] }));
6
+ }
7
+ if (!summary) {
8
+ return (_jsx(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, marginY: 1, children: _jsx(Text, { color: "gray", children: "No diagnostic information available for current run." }) }));
9
+ }
10
+ const duration = summary.durationMs !== undefined
11
+ ? summary.durationMs
12
+ : summary.completedAt && summary.startedAt
13
+ ? summary.completedAt - summary.startedAt
14
+ : undefined;
15
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "magenta", paddingX: 1, marginY: 1, children: [_jsxs(Box, { marginBottom: 0, children: [_jsx(Text, { bold: true, color: "magenta", children: "Diagnostics: " }), _jsxs(Text, { bold: true, color: "white", children: ["Run: ", summary.runId] })] }), _jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Status: " }), _jsx(Text, { bold: true, color: summary.finalStatus === "completed"
16
+ ? "green"
17
+ : summary.finalStatus === "failed"
18
+ ? "red"
19
+ : "yellow", children: summary.finalStatus || "running" }), duration !== undefined && (_jsxs(Text, { color: "gray", children: [" | Duration: ", Math.max(0, Math.round(duration / 1000)), "s"] }))] }), summary.totalPlanSteps !== undefined && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Plan Steps: " }), _jsxs(Text, { color: "white", children: [summary.completedPlanSteps ?? 0, "/", summary.totalPlanSteps, " completed"] })] })), summary.userRequestSummary && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Request: " }), _jsx(Text, { color: "white", children: summary.userRequestSummary
20
+ .replace(/(?:sk-|key-|AIza)[a-zA-Z0-9_-]{8,}/g, "[REDACTED]")
21
+ .replace(/(?:api[_-]?key|secret|token)[\s:=]+([a-zA-Z0-9_.-]+)/gi, "[REDACTED]") })] })), summary.initialRiskLevel && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Initial Risk: " }), _jsx(Text, { color: "yellow", children: summary.initialRiskLevel.toUpperCase() })] })), summary.activeSkills && summary.activeSkills.length > 0 && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Active Skills: " }), _jsx(Text, { color: "cyan", children: summary.activeSkills.join(", ") })] })), summary.verificationAttempts !== undefined && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Verification Attempts: " }), _jsxs(Text, { color: "white", children: [summary.verificationAttempts, "/", summary.maxVerificationAttempts || 3] })] })), summary.recoveryAttempts !== undefined && (_jsxs(Box, { marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Recovery Attempts: " }), _jsxs(Text, { color: "white", children: [summary.recoveryAttempts, "/", summary.maxRecoveryAttempts || 1] })] })), summary.tools && summary.tools.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Tool Invocations:" }), summary.tools.map((t, idx) => (_jsxs(Text, { color: "white", children: [" ", "\u2022 ", t.toolName, " (", t.count || t.calls || 1, ")"] }, `diag-tool-${idx}`)))] })), summary.files && (_jsxs(Box, { flexDirection: "column", marginTop: 0, children: [_jsx(Text, { color: "gray", children: "File Operations:" }), summary.files.modified && summary.files.modified.length > 0 && (_jsxs(Text, { color: "white", children: [" ", "\u2022 Modified: ", summary.files.modified.join(", ")] })), summary.files.created && summary.files.created.length > 0 && (_jsxs(Text, { color: "white", children: [" ", "\u2022 Created: ", summary.files.created.join(", ")] })), summary.files.deleted && summary.files.deleted.length > 0 && (_jsxs(Text, { color: "white", children: [" ", "\u2022 Deleted: ", summary.files.deleted.join(", ")] }))] }))] }));
22
+ };
23
+ //# sourceMappingURL=DiagnosticsView.js.map
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ export interface TimelineItemData {
3
+ id: string;
4
+ type: string;
5
+ timestamp: number;
6
+ title: string;
7
+ description?: string;
8
+ status?: string;
9
+ }
10
+ export interface ExecutionTimelineProps {
11
+ items?: TimelineItemData[];
12
+ maxItems?: number;
13
+ }
14
+ export declare const ExecutionTimeline: React.FC<ExecutionTimelineProps>;
15
+ //# sourceMappingURL=ExecutionTimeline.d.ts.map
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ export const ExecutionTimeline = ({ items = [], maxItems = 8 }) => {
4
+ if (items.length === 0) {
5
+ return null;
6
+ }
7
+ // Keep history bounded to avoid terminal buffer overflow
8
+ const recentItems = items.slice(-maxItems);
9
+ const formatTimestamp = (ts) => {
10
+ const d = new Date(ts);
11
+ const h = String(d.getHours()).padStart(2, "0");
12
+ const m = String(d.getMinutes()).padStart(2, "0");
13
+ const s = String(d.getSeconds()).padStart(2, "0");
14
+ return `${h}:${m}:${s}`;
15
+ };
16
+ const getStatusIcon = (type, status) => {
17
+ if (type === "tool_call" || type === "tool") {
18
+ return _jsx(Text, { color: "magenta", children: "\u2699" });
19
+ }
20
+ if (type === "verification") {
21
+ return _jsx(Text, { color: "cyan", children: "\u25CC" });
22
+ }
23
+ if (type === "approval") {
24
+ return _jsx(Text, { color: "yellow", children: "\u26A0" });
25
+ }
26
+ if (type === "run_event") {
27
+ return _jsx(Text, { color: "blue", children: "\u25C9" });
28
+ }
29
+ switch (status?.toLowerCase()) {
30
+ case "completed":
31
+ case "approved":
32
+ return _jsx(Text, { color: "green", children: "\u2713" });
33
+ case "running":
34
+ case "in_progress":
35
+ case "pending":
36
+ return _jsx(Text, { color: "yellow", children: "\u25B8" });
37
+ case "failed":
38
+ case "rejected":
39
+ return _jsx(Text, { color: "red", children: "\u2717" });
40
+ case "skipped":
41
+ case "cancelled":
42
+ return _jsx(Text, { color: "gray", children: "\u2298" });
43
+ case "blocked":
44
+ return _jsx(Text, { color: "red", children: "\u26A0" });
45
+ default:
46
+ return _jsx(Text, { color: "gray", children: "\u2022" });
47
+ }
48
+ };
49
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "gray", paddingX: 1, marginY: 1, children: [_jsx(Box, { marginBottom: 0, children: _jsxs(Text, { bold: true, color: "gray", children: ["Timeline (last ", recentItems.length, " events)"] }) }), recentItems.map((item) => (_jsxs(Box, { children: [_jsxs(Text, { color: "gray", children: [formatTimestamp(item.timestamp), " "] }), getStatusIcon(item.type, item.status), _jsx(Text, { color: "gray", children: " " }), _jsx(Text, { color: "white", children: item.title }), item.description && (_jsxs(Text, { color: "gray", children: [" \u2014 ", item.description] }))] }, item.id || `tl-${item.timestamp}`)))] }));
50
+ };
51
+ //# sourceMappingURL=ExecutionTimeline.js.map
@@ -0,0 +1,42 @@
1
+ import React from "react";
2
+ import { type PlanStepItem } from "./PlanView.js";
3
+ export interface ExecutionViewProps {
4
+ runId?: string;
5
+ status?: string;
6
+ userRequest?: string;
7
+ activePlan?: {
8
+ planId?: string;
9
+ objective?: string;
10
+ summary?: string;
11
+ status?: string;
12
+ riskLevel?: string;
13
+ steps?: PlanStepItem[];
14
+ completedStepsCount?: number;
15
+ totalStepsCount?: number;
16
+ };
17
+ activeTool?: {
18
+ toolName: string;
19
+ target?: string;
20
+ callId?: string;
21
+ };
22
+ activeVerification?: {
23
+ command: string;
24
+ attempt?: number;
25
+ };
26
+ activeRecovery?: {
27
+ strategy: string;
28
+ recoveryId?: string;
29
+ };
30
+ streamedOutput?: string;
31
+ completionSummary?: {
32
+ status?: string;
33
+ completedFiles?: string[];
34
+ verifiedCommands?: string[];
35
+ completedRequirements?: string[];
36
+ remainingRequirements?: string[];
37
+ blockedReason?: string;
38
+ };
39
+ error?: string;
40
+ }
41
+ export declare const ExecutionView: React.FC<ExecutionViewProps>;
42
+ //# sourceMappingURL=ExecutionView.d.ts.map
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ import { PlanView } from "./PlanView.js";
4
+ export const ExecutionView = ({ runId, status = "idle", userRequest, activePlan, activeTool, activeVerification, activeRecovery, streamedOutput, completionSummary, error }) => {
5
+ return (_jsxs(Box, { flexDirection: "column", marginY: 0, children: [runId && (_jsxs(Box, { marginBottom: 0, children: [_jsx(Text, { color: "gray", children: "Run: " }), _jsx(Text, { color: "white", bold: true, children: runId }), _jsx(Text, { color: "gray", children: " | Status: " }), _jsx(Text, { bold: true, color: status === "executing"
6
+ ? "green"
7
+ : status === "completed"
8
+ ? "green"
9
+ : status === "failed"
10
+ ? "red"
11
+ : status === "blocked"
12
+ ? "red"
13
+ : "cyan", children: status.toUpperCase() })] })), userRequest && (_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { color: "gray", children: "Task: " }), _jsx(Text, { color: "white", children: userRequest })] })), activePlan && activePlan.steps && activePlan.steps.length > 0 && (_jsx(PlanView, { planId: activePlan.planId, objective: activePlan.objective, summary: activePlan.summary, status: activePlan.status, riskLevel: activePlan.riskLevel, steps: activePlan.steps, completedCount: activePlan.completedStepsCount, totalCount: activePlan.totalStepsCount })), activeTool && (_jsxs(Box, { borderStyle: "single", borderColor: "magenta", paddingX: 1, marginY: 0, flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "magenta", children: "Tool: " }), _jsx(Text, { bold: true, color: "white", children: activeTool.toolName })] }), activeTool.target && (_jsxs(Box, { children: [_jsx(Text, { color: "gray", children: "Target: " }), _jsx(Text, { color: "cyan", children: activeTool.target })] }))] })), activeVerification && (_jsx(Box, { borderStyle: "single", borderColor: "cyan", paddingX: 1, marginY: 0, flexDirection: "column", children: _jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: "Verification: " }), _jsx(Text, { bold: true, color: "white", children: activeVerification.command }), activeVerification.attempt !== undefined && (_jsxs(Text, { color: "gray", children: [" (Attempt ", activeVerification.attempt, ")"] }))] }) })), activeRecovery && (_jsx(Box, { borderStyle: "single", borderColor: "yellow", paddingX: 1, marginY: 0, flexDirection: "column", children: _jsxs(Box, { children: [_jsx(Text, { bold: true, color: "yellow", children: "Recovery: " }), _jsx(Text, { bold: true, color: "white", children: activeRecovery.strategy }), activeRecovery.recoveryId && (_jsxs(Text, { color: "gray", children: [" (", activeRecovery.recoveryId, ")"] }))] }) })), streamedOutput && (_jsx(Box, { borderStyle: "single", borderColor: "gray", paddingX: 1, marginY: 1, flexDirection: "column", children: _jsx(Text, { color: "white", children: streamedOutput }) })), completionSummary && (_jsxs(Box, { borderStyle: "single", borderColor: completionSummary.status === "completed" ? "green" : "red", paddingX: 1, marginY: 1, flexDirection: "column", children: [_jsx(Box, { children: _jsx(Text, { bold: true, color: completionSummary.status === "completed" ? "green" : "red", children: completionSummary.status === "completed"
14
+ ? "✓ Task completed"
15
+ : "⚠ Task blocked" }) }), completionSummary.completedFiles &&
16
+ completionSummary.completedFiles.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Changed:" }), completionSummary.completedFiles.map((f, i) => (_jsxs(Text, { color: "white", children: [" ", "\u2022 ", f] }, `cf-${i}`)))] })), completionSummary.verifiedCommands &&
17
+ completionSummary.verifiedCommands.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 0, children: [_jsx(Text, { color: "gray", children: "Verified:" }), completionSummary.verifiedCommands.map((c, i) => (_jsxs(Text, { color: "white", children: [" ", "\u2022 ", c] }, `vc-${i}`)))] })), completionSummary.blockedReason && (_jsx(Box, { marginTop: 0, children: _jsxs(Text, { color: "red", children: ["Reason: ", completionSummary.blockedReason] }) })), completionSummary.remainingRequirements &&
18
+ completionSummary.remainingRequirements.length > 0 && (_jsxs(Box, { flexDirection: "column", marginTop: 0, children: [_jsx(Text, { color: "yellow", children: "Remaining:" }), completionSummary.remainingRequirements.map((r, i) => (_jsxs(Text, { color: "white", children: [" ", "\u2022 ", r] }, `rr-${i}`)))] }))] })), error && (_jsx(Box, { borderStyle: "single", borderColor: "red", paddingX: 1, marginY: 1, flexDirection: "column", children: _jsxs(Text, { bold: true, color: "red", children: ["\u2717 Error: ", error] }) }))] }));
19
+ };
20
+ //# sourceMappingURL=ExecutionView.js.map
@@ -0,0 +1,15 @@
1
+ import React from "react";
2
+ export interface HeaderProps {
3
+ projectName?: string;
4
+ providerName?: string;
5
+ modelName?: string;
6
+ cwd?: string;
7
+ status?: string;
8
+ gitBranch?: string | null;
9
+ isGitClean?: boolean;
10
+ runId?: string;
11
+ elapsedMs?: number;
12
+ sessionId?: string;
13
+ }
14
+ export declare const Header: React.FC<HeaderProps>;
15
+ //# sourceMappingURL=Header.d.ts.map
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ export const Header = ({ projectName = "fecode", providerName, modelName, cwd = process.cwd(), status = "idle", gitBranch, isGitClean = true, runId, elapsedMs }) => {
4
+ const getStatusBadge = () => {
5
+ switch (status.toLowerCase()) {
6
+ case "in_progress":
7
+ case "generating":
8
+ case "executing":
9
+ case "running":
10
+ return _jsx(Text, { bold: true, color: "green", children: "\u25CF LIVE (EXECUTING)" });
11
+ case "planning":
12
+ return _jsx(Text, { bold: true, color: "cyan", children: "\u25CC PLANNING" });
13
+ case "verifying":
14
+ return _jsx(Text, { bold: true, color: "cyan", children: "\u25CC VERIFYING" });
15
+ case "awaiting_plan_approval":
16
+ case "awaiting_step_approval":
17
+ return _jsx(Text, { bold: true, color: "yellow", children: "\u26A0 APPROVAL REQUIRED" });
18
+ case "blocked":
19
+ return _jsx(Text, { bold: true, color: "red", children: "! BLOCKED" });
20
+ case "recovering":
21
+ return _jsx(Text, { bold: true, color: "yellow", children: "\u25CC RECOVERING" });
22
+ case "completed":
23
+ return _jsx(Text, { bold: true, color: "green", children: "\u2713 COMPLETED" });
24
+ case "failed":
25
+ return _jsx(Text, { bold: true, color: "red", children: "\u2717 FAILED" });
26
+ case "cancelled":
27
+ return _jsx(Text, { bold: true, color: "gray", children: "\u2298 CANCELLED" });
28
+ case "idle":
29
+ default:
30
+ return _jsx(Text, { color: "gray", children: "\u25CB IDLE" });
31
+ }
32
+ };
33
+ const modelInfo = providerName && modelName ? `${providerName}:${modelName}` : undefined;
34
+ const formatElapsed = (ms) => {
35
+ if (ms === undefined || ms <= 0)
36
+ return "";
37
+ const sec = Math.round(ms / 1000);
38
+ if (sec < 60)
39
+ return `${sec}s`;
40
+ const min = Math.floor(sec / 60);
41
+ const rem = sec % 60;
42
+ return `${min}m ${rem}s`;
43
+ };
44
+ const branchDisplay = gitBranch ? (_jsxs(Text, { children: [_jsx(Text, { color: "gray", children: " \u2502 \u2387 " }), _jsx(Text, { color: "cyan", children: gitBranch }), _jsx(Text, { color: "gray", children: " \u25CF " }), _jsx(Text, { color: isGitClean ? "green" : "yellow", children: isGitClean ? "clean" : "modified" })] })) : null;
45
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", paddingX: 1, marginBottom: 1, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsxs(Box, { children: [_jsx(Text, { bold: true, color: "cyan", children: "FeCode" }), _jsx(Text, { color: "gray", children: " project: " }), _jsx(Text, { bold: true, color: "white", children: projectName }), modelInfo && _jsxs(Text, { color: "gray", children: [" (", modelInfo, ")"] }), branchDisplay] }), _jsxs(Box, { children: [elapsedMs !== undefined && elapsedMs > 0 && (_jsxs(Text, { color: "gray", children: [formatElapsed(elapsedMs), " "] })), getStatusBadge()] })] }), (cwd || runId) && (_jsxs(Box, { justifyContent: "space-between", marginTop: 0, children: [_jsxs(Box, { children: [_jsx(Text, { color: "gray", children: "Working directory: " }), _jsx(Text, { color: "white", children: cwd })] }), runId && (_jsxs(Box, { children: [_jsx(Text, { color: "gray", children: "Run: " }), _jsx(Text, { color: "cyan", children: runId.slice(0, 16) })] }))] }))] }));
46
+ };
47
+ //# sourceMappingURL=Header.js.map
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ export declare const HelpView: React.FC;
3
+ //# sourceMappingURL=HelpView.d.ts.map
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Box, Text } from "ink";
3
+ export const HelpView = () => {
4
+ const commands = [
5
+ { cmd: "/help", desc: "Show available commands & keyboard shortcuts" },
6
+ { cmd: "/status", desc: "Show current session, model, and project context" },
7
+ { cmd: "/plan", desc: "Display current active task plan" },
8
+ { cmd: "/plan <id>", desc: "Display specific task plan" },
9
+ { cmd: "/runs", desc: "List recent durable historical runs" },
10
+ { cmd: "/run <id>", desc: "Inspect specific historical run" },
11
+ { cmd: "/resume <id>", desc: "Prepare and resume task from previous run" },
12
+ { cmd: "/replan", desc: "Request replanning for current task" },
13
+ { cmd: "/debug", desc: "Show diagnostics summary for current run" },
14
+ { cmd: "/diagnostics", desc: "Show complete diagnostic telemetry" },
15
+ { cmd: "/history", desc: "Show completed tasks in current session" },
16
+ { cmd: "/tasks", desc: "List session task summaries" },
17
+ { cmd: "/task <num>", desc: "View task details by index" },
18
+ { cmd: "/git", desc: "Inspect git repository status and branch" },
19
+ { cmd: "/checkpoints", desc: "List available rollback checkpoints" },
20
+ { cmd: "/checkpoint", desc: "Create a new manual checkpoint" },
21
+ { cmd: "/recover", desc: "Inspect or initiate checkpoint recovery" },
22
+ { cmd: "/clear", desc: "Clear current terminal conversation history" },
23
+ { cmd: "/exit", desc: "Persist session and exit FeCode" }
24
+ ];
25
+ const shortcuts = [
26
+ { key: "Ctrl+C", desc: "Cancel active generation / approval or exit" },
27
+ { key: "[p]", desc: "Toggle Plan View (in view navigation)" },
28
+ { key: "[r]", desc: "Toggle Run History View (in view navigation)" },
29
+ { key: "[d]", desc: "Toggle Diagnostics View (in view navigation)" },
30
+ { key: "[?]", desc: "Toggle Help View (or '?' on empty prompt)" },
31
+ { key: "Esc", desc: "Return to Main Execution View / dismiss modal" }
32
+ ];
33
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "single", borderColor: "cyan", paddingX: 1, marginY: 1, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: "cyan", children: "Available Commands:" }) }), commands.map((c, i) => (_jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { bold: true, color: "white", children: c.cmd }) }), _jsx(Text, { color: "gray", children: c.desc })] }, `cmd-${i}`))), _jsx(Box, { marginTop: 1, marginBottom: 0, children: _jsx(Text, { bold: true, color: "yellow", children: "Keyboard Shortcuts:" }) }), shortcuts.map((s, i) => (_jsxs(Box, { children: [_jsx(Box, { width: 18, children: _jsx(Text, { bold: true, color: "yellow", children: s.key }) }), _jsx(Text, { color: "gray", children: s.desc })] }, `sc-${i}`)))] }));
34
+ };
35
+ //# sourceMappingURL=HelpView.js.map
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ export interface MessageBubbleProps {
3
+ role: "user" | "agent";
4
+ content: string;
5
+ isStreaming?: boolean;
6
+ error?: string;
7
+ }
8
+ export declare const MessageBubble: React.FC<MessageBubbleProps>;
9
+ //# sourceMappingURL=MessageBubble.d.ts.map