prdforge-cli 0.1.0 → 0.2.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/package.json +2 -2
- package/src/api/client.js +35 -9
- package/src/api/stream.js +97 -0
- package/src/commands/auth.js +132 -1
- package/src/commands/dashboard.js +2 -74
- package/src/hooks/useScroll.js +20 -0
- package/src/hooks/useStream.js +144 -0
- package/src/hooks/useTerminalSize.js +24 -0
- package/src/index.js +10 -5
- package/src/ui/LeftPane.js +215 -0
- package/src/ui/PrdCreation.js +1 -1
- package/src/ui/PreviewPanel.js +148 -0
- package/src/ui/REPLDashboard.js +418 -0
- package/src/ui/ReplPanel.js +227 -0
- package/src/ui/RightPane.js +66 -0
- package/src/ui/StageIndicator.js +51 -20
- package/src/ui/theme.js +4 -2
- package/src/utils/debug.js +7 -0
- package/src/utils/logo.js +18 -0
package/src/ui/StageIndicator.js
CHANGED
|
@@ -1,40 +1,71 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { Text } from "ink";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
3
|
import Spinner from "ink-spinner";
|
|
4
4
|
import { theme } from "./theme.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Renders a single stage row with a status indicator.
|
|
7
|
+
* Renders a single stage row with a status indicator and optional content preview.
|
|
8
8
|
*
|
|
9
|
-
* @param {{ label: string, status: "pending"|"active"|"done"|"stale" }} props
|
|
9
|
+
* @param {{ label: string, status: "pending"|"active"|"streaming"|"done"|"stale", preview?: string }} props
|
|
10
10
|
*/
|
|
11
|
-
export function StageIndicator({ label, status }) {
|
|
11
|
+
export function StageIndicator({ label, status, preview }) {
|
|
12
|
+
let indicator;
|
|
13
|
+
|
|
12
14
|
if (status === "active") {
|
|
13
|
-
|
|
15
|
+
indicator = React.createElement(
|
|
14
16
|
Text,
|
|
15
17
|
null,
|
|
16
18
|
React.createElement(Spinner, { type: "dots" }),
|
|
17
19
|
" ",
|
|
18
20
|
React.createElement(Text, { color: theme.white }, label)
|
|
19
21
|
);
|
|
22
|
+
} else if (status === "streaming") {
|
|
23
|
+
indicator = React.createElement(
|
|
24
|
+
Text,
|
|
25
|
+
null,
|
|
26
|
+
React.createElement(Spinner, { type: "dots", color: theme.streaming }),
|
|
27
|
+
" ",
|
|
28
|
+
React.createElement(Text, { color: theme.streaming }, label)
|
|
29
|
+
);
|
|
30
|
+
} else {
|
|
31
|
+
const dot = status === "done" ? "✓"
|
|
32
|
+
: status === "stale" ? "⚠"
|
|
33
|
+
: "●";
|
|
34
|
+
const color = status === "done" ? theme.success
|
|
35
|
+
: status === "stale" ? theme.warning
|
|
36
|
+
: theme.dim;
|
|
37
|
+
|
|
38
|
+
indicator = React.createElement(
|
|
39
|
+
Text,
|
|
40
|
+
null,
|
|
41
|
+
React.createElement(Text, { color }, dot),
|
|
42
|
+
" ",
|
|
43
|
+
React.createElement(
|
|
44
|
+
Text,
|
|
45
|
+
{ color: status === "pending" ? theme.dim : theme.white },
|
|
46
|
+
label
|
|
47
|
+
)
|
|
48
|
+
);
|
|
20
49
|
}
|
|
21
50
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
51
|
+
if (!preview || status === "pending" || status === "done") {
|
|
52
|
+
return indicator;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Show first line of preview text below the stage label while streaming
|
|
56
|
+
const firstLine = preview.split("\n").find((l) => l.trim()) ?? "";
|
|
57
|
+
const clipped = firstLine.length > 72 ? firstLine.slice(0, 72) + "…" : firstLine;
|
|
28
58
|
|
|
29
59
|
return React.createElement(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
60
|
+
Box,
|
|
61
|
+
{ flexDirection: "column" },
|
|
62
|
+
indicator,
|
|
63
|
+
clipped
|
|
64
|
+
? React.createElement(
|
|
65
|
+
Box,
|
|
66
|
+
{ marginLeft: 3 },
|
|
67
|
+
React.createElement(Text, { color: theme.dim }, clipped)
|
|
68
|
+
)
|
|
69
|
+
: null
|
|
39
70
|
);
|
|
40
71
|
}
|
package/src/ui/theme.js
CHANGED
|
@@ -4,8 +4,10 @@ export const theme = {
|
|
|
4
4
|
success: "#22C55E", // green checkmark / done
|
|
5
5
|
warning: "#F97316", // orange stale
|
|
6
6
|
error: "#EF4444", // red
|
|
7
|
-
dim:
|
|
8
|
-
white:
|
|
7
|
+
dim: "#6B7280", // grey inactive
|
|
8
|
+
white: "#F1F5F9", // near-white text
|
|
9
|
+
streaming: "#818CF8", // indigo — active SSE streaming stage
|
|
10
|
+
accent: "#38BDF8", // sky blue — REPL input bar border
|
|
9
11
|
|
|
10
12
|
// The 8 completion stages (overview + versions not counted)
|
|
11
13
|
stages: [
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const isDebug = () => !!process.env.PRDFORGE_DEBUG || !!global.__prdforgeDebug;
|
|
2
|
+
|
|
3
|
+
export const debugLog = (label, data) => {
|
|
4
|
+
if (!isDebug()) return;
|
|
5
|
+
const msg = typeof data === "object" ? JSON.stringify(data) : data;
|
|
6
|
+
process.stderr.write(`[DEBUG ${label}] ${msg}\n`);
|
|
7
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import figlet from "figlet";
|
|
2
|
+
|
|
3
|
+
export function printWelcome() {
|
|
4
|
+
const narrow = !process.stdout.columns || process.stdout.columns < 60;
|
|
5
|
+
|
|
6
|
+
if (!narrow) {
|
|
7
|
+
const art = figlet.textSync("PRDForge", { font: "Slant" });
|
|
8
|
+
process.stdout.write(`\n\x1b[1m\x1b[36m${art}\x1b[0m\n`);
|
|
9
|
+
} else {
|
|
10
|
+
process.stdout.write(`\n\x1b[1m\x1b[36m PRDForge CLI\x1b[0m\n`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
process.stdout.write(` \x1b[90mThe planning layer for AI-first development\x1b[0m\n\n`);
|
|
14
|
+
process.stdout.write(` \x1b[2mGet started:\x1b[0m\n`);
|
|
15
|
+
process.stdout.write(` \x1b[36mprdforge auth signup\x1b[0m — create a free account\n`);
|
|
16
|
+
process.stdout.write(` \x1b[36mprdforge auth login\x1b[0m — sign in to an existing account\n`);
|
|
17
|
+
process.stdout.write(` \x1b[36mprdforge --help\x1b[0m — see all commands\n\n`);
|
|
18
|
+
}
|