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.
@@ -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
- return React.createElement(
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
- const dot = status === "done" ? ""
23
- : status === "stale" ? "⚠"
24
- : "●";
25
- const color = status === "done" ? theme.success
26
- : status === "stale" ? theme.warning
27
- : theme.dim;
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
- Text,
31
- null,
32
- React.createElement(Text, { color }, dot),
33
- " ",
34
- React.createElement(
35
- Text,
36
- { color: status === "pending" ? theme.dim : theme.white },
37
- label
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: "#6B7280", // grey inactive
8
- white: "#F1F5F9", // near-white text
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
+ }