@arvorco/relentless 0.1.16 → 0.1.18

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arvorco/relentless",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Universal AI agent orchestrator - works with Claude Code, Amp, OpenCode, Codex, Droid, and Gemini",
5
5
  "type": "module",
6
6
  "publishConfig": {
package/src/tui/App.tsx CHANGED
@@ -29,12 +29,12 @@ export function App({ state }: AppProps): React.ReactElement {
29
29
  <Header agent={state.currentAgent} />
30
30
 
31
31
  {/* Feature info and progress */}
32
- <Box flexDirection="column" paddingX={1} paddingY={1}>
32
+ <Box flexDirection="column" paddingX={1} paddingY={0}>
33
33
  <Box>
34
34
  <Text color={colors.dim}>Feature: </Text>
35
35
  <Text bold>{state.feature}</Text>
36
36
  </Box>
37
- <Box marginTop={1}>
37
+ <Box>
38
38
  <Text color={colors.dim}>Progress: </Text>
39
39
  <ProgressBar completed={completedCount} total={totalCount} />
40
40
  </Box>
@@ -50,12 +50,13 @@ export function App({ state }: AppProps): React.ReactElement {
50
50
  </Box>
51
51
 
52
52
  {/* Agent output */}
53
- <AgentOutput lines={state.outputLines} />
53
+ <AgentOutput lines={state.outputLines} maxLines={8} />
54
54
 
55
55
  {/* Story grid */}
56
56
  <StoryGrid
57
57
  stories={state.stories}
58
58
  currentStoryId={state.currentStory?.id}
59
+ maxRows={8}
59
60
  />
60
61
 
61
62
  {/* Agent status footer */}
@@ -113,6 +113,10 @@ function TUIRunnerComponent({
113
113
  id: s.id,
114
114
  title: s.title,
115
115
  passes: s.passes,
116
+ priority: s.priority,
117
+ criteriaCount: s.acceptanceCriteria.length,
118
+ research: s.research,
119
+ phase: s.phase,
116
120
  })),
117
121
  agents: agentStates,
118
122
  }));
@@ -153,7 +157,15 @@ function TUIRunnerComponent({
153
157
  // Update current story
154
158
  setState((prev) => ({
155
159
  ...prev,
156
- currentStory: { id: story.id, title: story.title, passes: story.passes },
160
+ currentStory: {
161
+ id: story.id,
162
+ title: story.title,
163
+ passes: story.passes,
164
+ priority: story.priority,
165
+ criteriaCount: story.acceptanceCriteria.length,
166
+ research: story.research,
167
+ phase: story.phase,
168
+ },
157
169
  elapsedSeconds: 0,
158
170
  }));
159
171
 
@@ -334,6 +346,10 @@ function TUIRunnerComponent({
334
346
  id: s.id,
335
347
  title: s.title,
336
348
  passes: s.passes,
349
+ priority: s.priority,
350
+ criteriaCount: s.acceptanceCriteria.length,
351
+ research: s.research,
352
+ phase: s.phase,
337
353
  })),
338
354
  }));
339
355
 
@@ -6,7 +6,7 @@
6
6
 
7
7
  import React from "react";
8
8
  import { Box, Text } from "ink";
9
- import { colors, borders } from "../theme.js";
9
+ import { colors } from "../theme.js";
10
10
 
11
11
  interface AgentOutputProps {
12
12
  lines: string[];
@@ -17,19 +17,19 @@ export function AgentOutput({
17
17
  lines,
18
18
  maxLines = 8,
19
19
  }: AgentOutputProps): React.ReactElement {
20
- // Take last N lines for display
21
- const displayLines = lines.slice(-maxLines);
20
+ const clampedMaxLines = Math.max(0, maxLines);
21
+ const displayLines = clampedMaxLines > 0 ? lines.slice(-clampedMaxLines) : [];
22
22
 
23
23
  return (
24
- <Box flexDirection="column" borderStyle="single" borderColor={colors.dim}>
25
- <Box paddingX={1} borderBottom borderColor={colors.dim}>
24
+ <Box flexDirection="column" paddingY={1}>
25
+ <Box paddingX={1}>
26
26
  <Text color={colors.dim} bold>
27
- Agent Output
27
+ ── Agent Output ──
28
28
  </Text>
29
29
  </Box>
30
- <Box flexDirection="column" paddingX={1} height={maxLines}>
30
+ <Box flexDirection="column" paddingX={1}>
31
31
  {displayLines.length > 0 ? (
32
- displayLines.map((line, i) => (
32
+ displayLines.slice(0, clampedMaxLines).map((line, i) => (
33
33
  <Text key={i} color={colors.dim} wrap="truncate">
34
34
  {line}
35
35
  </Text>
@@ -31,9 +31,8 @@ export function AgentStatus({
31
31
 
32
32
  return (
33
33
  <Box
34
- borderStyle="single"
35
- borderColor={colors.dim}
36
34
  paddingX={1}
35
+ paddingY={1}
37
36
  flexDirection="row"
38
37
  justifyContent="space-between"
39
38
  >
@@ -32,14 +32,14 @@ export function CurrentStory({
32
32
  }: CurrentStoryProps): React.ReactElement {
33
33
  if (!story) {
34
34
  return (
35
- <Box paddingY={1}>
35
+ <Box>
36
36
  <Text color={colors.dim}>No story in progress</Text>
37
37
  </Box>
38
38
  );
39
39
  }
40
40
 
41
41
  return (
42
- <Box flexDirection="column" paddingY={1}>
42
+ <Box flexDirection="column">
43
43
  <Box>
44
44
  <Text color={colors.dim}>Current Story: </Text>
45
45
  <Text color={colors.warning} bold>
@@ -16,9 +16,8 @@ interface HeaderProps {
16
16
  export function Header({ agent }: HeaderProps): React.ReactElement {
17
17
  return (
18
18
  <Box
19
- borderStyle="single"
20
- borderColor={colors.primary}
21
19
  paddingX={1}
20
+ paddingY={1}
22
21
  flexDirection="row"
23
22
  justifyContent="space-between"
24
23
  >
@@ -13,12 +13,14 @@ interface StoryGridProps {
13
13
  stories: Story[];
14
14
  currentStoryId?: string;
15
15
  columns?: number;
16
+ maxRows?: number;
16
17
  }
17
18
 
18
19
  export function StoryGrid({
19
20
  stories,
20
21
  currentStoryId,
21
22
  columns = 2,
23
+ maxRows,
22
24
  }: StoryGridProps): React.ReactElement {
23
25
  // Split stories into columns
24
26
  const rows: Story[][] = [];
@@ -35,15 +37,18 @@ export function StoryGrid({
35
37
  rows.push(row);
36
38
  }
37
39
 
40
+ // Constrain to maxRows
41
+ const visibleRows = maxRows ? rows.slice(0, maxRows) : rows;
42
+
38
43
  return (
39
- <Box flexDirection="column" borderStyle="single" borderColor={colors.dim}>
40
- <Box paddingX={1} borderBottom borderColor={colors.dim}>
44
+ <Box flexDirection="column" paddingY={1}>
45
+ <Box paddingX={1}>
41
46
  <Text color={colors.dim} bold>
42
- Stories
47
+ ── Stories ({stories.length}) ──
43
48
  </Text>
44
49
  </Box>
45
- <Box flexDirection="column" paddingX={1} paddingY={0}>
46
- {rows.map((row, rowIdx) => (
50
+ <Box flexDirection="column" paddingX={1}>
51
+ {visibleRows.map((row, rowIdx) => (
47
52
  <Box key={rowIdx} flexDirection="row">
48
53
  {row.map((story, colIdx) => {
49
54
  const isCurrent = story.id === currentStoryId;
@@ -58,23 +63,55 @@ export function StoryGrid({
58
63
  ? colors.success
59
64
  : colors.dim;
60
65
 
66
+ const priorityColor =
67
+ story.priority <= 2 ? colors.error : story.priority <= 5 ? colors.warning : colors.dim;
68
+
61
69
  return (
62
70
  <Box key={colIdx} width="50%">
71
+ {/* Status symbol */}
63
72
  <Text color={symbolColor}>{symbol} </Text>
73
+
74
+ {/* Story ID */}
64
75
  <Text
65
76
  color={story.passes ? colors.success : isCurrent ? colors.warning : undefined}
66
77
  dimColor={story.passes}
67
78
  >
68
- {story.id.padEnd(8)}
79
+ {story.id.padEnd(9)}
80
+ </Text>
81
+
82
+ {/* Priority badge */}
83
+ <Text color={priorityColor} bold={story.priority <= 3}>
84
+ P{story.priority}{" "}
69
85
  </Text>
86
+
87
+ {/* Title (longer) */}
70
88
  <Text
71
- color={colors.dim}
89
+ color={story.passes ? colors.dim : undefined}
72
90
  dimColor={story.passes}
73
91
  strikethrough={story.passes}
74
92
  wrap="truncate"
75
93
  >
76
- {story.title.substring(0, 25)}
94
+ {story.title.substring(0, 40)}
95
+ </Text>
96
+
97
+ {/* Acceptance criteria count */}
98
+ <Text color={colors.dim} dimColor>
99
+ {" "}
100
+ ({story.criteriaCount}c)
77
101
  </Text>
102
+
103
+ {/* Research indicator */}
104
+ {story.research && (
105
+ <Text color={colors.dim}> 🔍</Text>
106
+ )}
107
+
108
+ {/* Phase badge */}
109
+ {story.phase && (
110
+ <Text color={colors.dim} dimColor>
111
+ {" "}
112
+ [{story.phase}]
113
+ </Text>
114
+ )}
78
115
  </Box>
79
116
  );
80
117
  })}
package/src/tui/types.ts CHANGED
@@ -10,6 +10,10 @@ export interface Story {
10
10
  id: string;
11
11
  title: string;
12
12
  passes: boolean;
13
+ priority: number;
14
+ criteriaCount: number;
15
+ research?: boolean;
16
+ phase?: string;
13
17
  }
14
18
 
15
19
  export interface AgentState {