@arvorco/relentless 0.1.18 → 0.1.20
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/.claude/skills/constitution/SKILL.md +118 -13
- package/README.md +4 -1
- package/package.json +1 -1
- package/src/init/scaffolder.ts +38 -38
- package/src/tui/App.tsx +18 -3
- package/src/tui/components/StoryGrid.tsx +32 -3
|
@@ -12,9 +12,10 @@ Create a personalized project constitution that defines your team's coding princ
|
|
|
12
12
|
## The Job
|
|
13
13
|
|
|
14
14
|
1. Ask the user about their project's coding philosophy and standards
|
|
15
|
-
2.
|
|
16
|
-
3.
|
|
17
|
-
4.
|
|
15
|
+
2. Analyze the project structure and documentation
|
|
16
|
+
3. Generate personalized constitution based on their answers → `relentless/constitution.md`
|
|
17
|
+
4. Generate personalized agent prompt based on the same analysis → `relentless/prompt.md`
|
|
18
|
+
5. Ensure consistency with project templates and documentation
|
|
18
19
|
|
|
19
20
|
**Important:** The constitution is the foundation for all feature work - create this before generating features.
|
|
20
21
|
|
|
@@ -67,31 +68,126 @@ Load the template from `templates/constitution-template.md` and:
|
|
|
67
68
|
|
|
68
69
|
---
|
|
69
70
|
|
|
70
|
-
## Step 3:
|
|
71
|
+
## Step 3: Analyze Project Structure
|
|
72
|
+
|
|
73
|
+
Read and analyze project documentation:
|
|
74
|
+
|
|
75
|
+
**Core Files:**
|
|
76
|
+
- `README.md` - Project overview, setup instructions
|
|
77
|
+
- `AGENTS.md` or `CLAUDE.md` - Developer guidelines
|
|
78
|
+
- `package.json` - Scripts, dependencies, tech stack
|
|
79
|
+
- `CONTRIBUTING.md` - Contribution workflow (if exists)
|
|
80
|
+
|
|
81
|
+
**Extract:**
|
|
82
|
+
- Tech stack (TypeScript, React, Node, etc.)
|
|
83
|
+
- Testing framework (vitest, jest, playwright)
|
|
84
|
+
- Quality commands (`typecheck`, `lint`, `test`)
|
|
85
|
+
- Build system (bun, npm, turbo, vite)
|
|
86
|
+
- Linting setup (eslint, biome)
|
|
87
|
+
- File structure patterns
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Step 4: Generate Personalized Prompt
|
|
92
|
+
|
|
93
|
+
Using the generic template from relentless, create a personalized `prompt.md` with:
|
|
94
|
+
|
|
95
|
+
**Section 1: Quality Gates**
|
|
96
|
+
```markdown
|
|
97
|
+
## CRITICAL: Quality Gates (Non-Negotiable)
|
|
98
|
+
|
|
99
|
+
Before marking ANY story as complete:
|
|
100
|
+
|
|
101
|
+
\`\`\`bash
|
|
102
|
+
# TypeScript (detected from package.json)
|
|
103
|
+
[actual typecheck command from package.json scripts]
|
|
104
|
+
|
|
105
|
+
# Linting (detected from package.json)
|
|
106
|
+
[actual lint command from package.json scripts]
|
|
107
|
+
|
|
108
|
+
# Tests (detected from package.json)
|
|
109
|
+
[actual test command from package.json scripts]
|
|
110
|
+
\`\`\`
|
|
111
|
+
|
|
112
|
+
**If ANY check fails, DO NOT mark the story as complete.**
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Section 2: Project-Specific Patterns** (from README/AGENTS.md)
|
|
116
|
+
- Monorepo structure (if applicable)
|
|
117
|
+
- Component locations
|
|
118
|
+
- Test file patterns
|
|
119
|
+
- Database/backend info
|
|
120
|
+
- Styling approach
|
|
121
|
+
|
|
122
|
+
**Section 3: TDD Workflow** (if tests exist)
|
|
123
|
+
- Test-first workflow
|
|
124
|
+
- Test location patterns
|
|
125
|
+
- Test commands
|
|
126
|
+
|
|
127
|
+
**Section 4: Common Pitfalls** (from AGENTS.md/docs)
|
|
128
|
+
- Project-specific gotchas
|
|
129
|
+
- Known issues
|
|
130
|
+
- Best practices
|
|
131
|
+
|
|
132
|
+
**Footer:**
|
|
133
|
+
```markdown
|
|
134
|
+
---
|
|
135
|
+
**Personalized for [Project Name]**
|
|
136
|
+
**Generated:** [date]
|
|
137
|
+
**Re-generate:** /relentless.constitution
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Save to: `relentless/prompt.md`
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Step 5: Validate & Save
|
|
71
145
|
|
|
72
146
|
Before saving:
|
|
73
|
-
|
|
147
|
+
|
|
148
|
+
**Constitution:**
|
|
149
|
+
- No `[PLACEHOLDER]` tokens remain
|
|
74
150
|
- All dates in ISO format (YYYY-MM-DD)
|
|
75
151
|
- Principles are declarative and testable
|
|
76
152
|
- Version format is semantic (X.Y.Z)
|
|
77
153
|
|
|
78
|
-
|
|
154
|
+
**Prompt:**
|
|
155
|
+
- All quality commands are actual commands from package.json
|
|
156
|
+
- File patterns match project structure
|
|
157
|
+
- No generic placeholders remain
|
|
158
|
+
|
|
159
|
+
Save both files:
|
|
160
|
+
- `relentless/constitution.md`
|
|
161
|
+
- `relentless/prompt.md`
|
|
79
162
|
|
|
80
163
|
---
|
|
81
164
|
|
|
82
|
-
## Step
|
|
165
|
+
## Step 6: Report
|
|
83
166
|
|
|
84
167
|
Output summary:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
-
|
|
88
|
-
-
|
|
168
|
+
```
|
|
169
|
+
✓ Created constitution.md
|
|
170
|
+
- Version: 1.0.0
|
|
171
|
+
- Principles: [count]
|
|
172
|
+
- Key rules: [summary]
|
|
173
|
+
|
|
174
|
+
✓ Created prompt.md
|
|
175
|
+
- Quality gates: [count]
|
|
176
|
+
- Tech stack: [detected stack]
|
|
177
|
+
- Test framework: [detected]
|
|
178
|
+
|
|
179
|
+
Next steps:
|
|
180
|
+
1. Review both files
|
|
181
|
+
2. Create your first feature: /relentless.specify "feature description"
|
|
182
|
+
```
|
|
89
183
|
|
|
90
184
|
---
|
|
91
185
|
|
|
92
|
-
## Updating Existing
|
|
186
|
+
## Updating Existing Files
|
|
187
|
+
|
|
188
|
+
If `relentless/constitution.md` or `relentless/prompt.md` exist:
|
|
93
189
|
|
|
94
|
-
|
|
190
|
+
**For Constitution Updates:**
|
|
95
191
|
1. Load current version
|
|
96
192
|
2. Ask what needs to change
|
|
97
193
|
3. Increment version appropriately:
|
|
@@ -101,6 +197,15 @@ If `relentless/constitution.md` exists:
|
|
|
101
197
|
4. Update `LAST_AMENDED_DATE` to today
|
|
102
198
|
5. Add amendment notes at top
|
|
103
199
|
|
|
200
|
+
**For Prompt Updates:**
|
|
201
|
+
1. Re-analyze project structure (package.json, docs)
|
|
202
|
+
2. Detect any new quality commands or patterns
|
|
203
|
+
3. Regenerate personalized sections
|
|
204
|
+
4. Preserve any manual customizations in comments
|
|
205
|
+
5. Update "Generated" date
|
|
206
|
+
|
|
207
|
+
**Both files can be regenerated at any time by running `/relentless.constitution` again.**
|
|
208
|
+
|
|
104
209
|
---
|
|
105
210
|
|
|
106
211
|
## Example Constitution Structure
|
package/README.md
CHANGED
|
@@ -30,8 +30,11 @@ bun install -g github:ArvorCo/Relentless
|
|
|
30
30
|
cd your-project
|
|
31
31
|
relentless init
|
|
32
32
|
|
|
33
|
-
# 3. Create constitution (personalized governance)
|
|
33
|
+
# 3. Create constitution and prompt (personalized governance + agent instructions)
|
|
34
34
|
/relentless.constitution
|
|
35
|
+
# This creates BOTH:
|
|
36
|
+
# - relentless/constitution.md (project principles)
|
|
37
|
+
# - relentless/prompt.md (personalized agent instructions)
|
|
35
38
|
|
|
36
39
|
# 4. Create feature specification
|
|
37
40
|
/relentless.specify Add user authentication with OAuth2
|
package/package.json
CHANGED
package/src/init/scaffolder.ts
CHANGED
|
@@ -57,64 +57,64 @@ const RELENTLESS_FILES: Record<string, () => string> = {
|
|
|
57
57
|
|
|
58
58
|
const PROMPT_TEMPLATE = `# Relentless Agent Instructions
|
|
59
59
|
|
|
60
|
-
You are an autonomous coding agent
|
|
60
|
+
You are an autonomous coding agent. Follow these instructions exactly.
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
**⚠️ This is a generic template. Personalize it for your project using:**
|
|
63
|
+
\`\`\`bash
|
|
64
|
+
/relentless.prompt
|
|
65
|
+
\`\`\`
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Your Task (Per Iteration)
|
|
63
70
|
|
|
64
|
-
1.
|
|
65
|
-
2.
|
|
66
|
-
3.
|
|
71
|
+
1. Read \`relentless/features/<feature>/prd.json\`
|
|
72
|
+
2. Read \`relentless/features/<feature>/progress.txt\`
|
|
73
|
+
3. Check you're on the correct branch from PRD \`branchName\`
|
|
74
|
+
4. Pick the **highest priority** story where \`passes: false\`
|
|
75
|
+
5. Review existing code to understand patterns
|
|
76
|
+
6. Implement the story
|
|
77
|
+
7. Run quality checks (typecheck, lint, test)
|
|
78
|
+
8. If ALL checks pass, commit: \`feat: [Story ID] - [Story Title]\`
|
|
79
|
+
9. Update PRD: set \`passes: true\`
|
|
80
|
+
10. Append progress to \`progress.txt\`
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Quality Requirements
|
|
67
85
|
|
|
68
|
-
|
|
86
|
+
Before marking a story complete:
|
|
87
|
+
- [ ] All quality checks pass (typecheck, lint, test)
|
|
88
|
+
- [ ] Zero errors and zero warnings
|
|
89
|
+
- [ ] No debug code (console.log, debugger)
|
|
90
|
+
- [ ] No unused imports or variables
|
|
91
|
+
- [ ] Follows existing patterns
|
|
69
92
|
|
|
70
|
-
|
|
71
|
-
2. Read the progress log at \`relentless/features/<feature>/progress.txt\`
|
|
72
|
-
3. Check you're on the correct branch from PRD \`branchName\`. If not, check it out or create from main.
|
|
73
|
-
4. Pick the **highest priority** user story where \`passes: false\`
|
|
74
|
-
5. **Review relevant code** before implementing - understand existing patterns
|
|
75
|
-
6. Implement that single user story
|
|
76
|
-
7. Run quality checks (typecheck, lint, test - whatever your project requires)
|
|
77
|
-
8. If checks pass, commit ALL changes with message: \`feat: [Story ID] - [Story Title]\`
|
|
78
|
-
9. Update the PRD to set \`passes: true\` for the completed story
|
|
79
|
-
10. Append your progress to \`relentless/features/<feature>/progress.txt\`
|
|
93
|
+
---
|
|
80
94
|
|
|
81
95
|
## Progress Report Format
|
|
82
96
|
|
|
83
|
-
APPEND to progress.txt
|
|
97
|
+
APPEND to progress.txt:
|
|
84
98
|
\`\`\`
|
|
85
99
|
## [Date/Time] - [Story ID]
|
|
86
100
|
- What was implemented
|
|
87
101
|
- Files changed
|
|
88
|
-
-
|
|
89
|
-
- Patterns discovered
|
|
90
|
-
- Gotchas encountered
|
|
91
|
-
- Useful context
|
|
102
|
+
- Learnings for future iterations
|
|
92
103
|
---
|
|
93
104
|
\`\`\`
|
|
94
105
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
- ALL commits must pass your project's quality checks (typecheck, lint, test)
|
|
98
|
-
- Do NOT commit broken code
|
|
99
|
-
- Keep changes focused and minimal
|
|
100
|
-
- Follow existing code patterns
|
|
101
|
-
- Review code before modifying it
|
|
106
|
+
---
|
|
102
107
|
|
|
103
108
|
## Stop Condition
|
|
104
109
|
|
|
105
|
-
After completing a
|
|
110
|
+
After completing a story, check if ALL stories have \`passes: true\`.
|
|
106
111
|
|
|
107
|
-
If ALL
|
|
112
|
+
If ALL complete:
|
|
113
|
+
\`\`\`
|
|
108
114
|
<promise>COMPLETE</promise>
|
|
115
|
+
\`\`\`
|
|
109
116
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
## Important
|
|
113
|
-
|
|
114
|
-
- Work on ONE story per iteration
|
|
115
|
-
- Review existing code before implementing
|
|
116
|
-
- Commit frequently
|
|
117
|
-
- Keep CI green
|
|
117
|
+
Otherwise, end normally (next iteration continues).
|
|
118
118
|
`;
|
|
119
119
|
|
|
120
120
|
/**
|
package/src/tui/App.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import React from "react";
|
|
8
|
-
import { Box, Text } from "ink";
|
|
8
|
+
import { Box, Text, useStdout } from "ink";
|
|
9
9
|
import { Header } from "./components/Header.js";
|
|
10
10
|
import { ProgressBar } from "./components/ProgressBar.js";
|
|
11
11
|
import { CurrentStory } from "./components/CurrentStory.js";
|
|
@@ -20,8 +20,23 @@ interface AppProps {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export function App({ state }: AppProps): React.ReactElement {
|
|
23
|
+
const { stdout } = useStdout();
|
|
24
|
+
const terminalRows = stdout.rows ?? 24;
|
|
25
|
+
|
|
23
26
|
const completedCount = state.stories.filter((s) => s.passes).length;
|
|
24
27
|
const totalCount = state.stories.length;
|
|
28
|
+
|
|
29
|
+
// Calculate available rows for stories based on terminal height
|
|
30
|
+
// Chrome: Header(2) + Feature/Progress(2) + CurrentStory(2) + AgentOutputHeader(1) + AgentStatusFooter(2) + Padding(2) = ~11 lines
|
|
31
|
+
// AgentOutput: 6 lines
|
|
32
|
+
// Remaining space for stories
|
|
33
|
+
const chromeHeight = 11;
|
|
34
|
+
const agentOutputLines = 6;
|
|
35
|
+
const availableForStories = Math.max(8, terminalRows - chromeHeight - agentOutputLines);
|
|
36
|
+
|
|
37
|
+
// Calculate story rows needed for 2-column layout
|
|
38
|
+
const storyRows = Math.ceil(totalCount / 2);
|
|
39
|
+
const maxStoryRows = Math.min(storyRows, availableForStories);
|
|
25
40
|
|
|
26
41
|
return (
|
|
27
42
|
<Box flexDirection="column" width="100%">
|
|
@@ -50,13 +65,13 @@ export function App({ state }: AppProps): React.ReactElement {
|
|
|
50
65
|
</Box>
|
|
51
66
|
|
|
52
67
|
{/* Agent output */}
|
|
53
|
-
<AgentOutput lines={state.outputLines} maxLines={
|
|
68
|
+
<AgentOutput lines={state.outputLines} maxLines={agentOutputLines} />
|
|
54
69
|
|
|
55
70
|
{/* Story grid */}
|
|
56
71
|
<StoryGrid
|
|
57
72
|
stories={state.stories}
|
|
58
73
|
currentStoryId={state.currentStory?.id}
|
|
59
|
-
maxRows={
|
|
74
|
+
maxRows={maxStoryRows}
|
|
60
75
|
/>
|
|
61
76
|
|
|
62
77
|
{/* Agent status footer */}
|
|
@@ -37,14 +37,43 @@ export function StoryGrid({
|
|
|
37
37
|
rows.push(row);
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
//
|
|
41
|
-
|
|
40
|
+
// Window around current story to show context
|
|
41
|
+
let visibleRows = rows;
|
|
42
|
+
let startRow = 0;
|
|
43
|
+
let endRow = rows.length;
|
|
44
|
+
|
|
45
|
+
if (maxRows && rows.length > maxRows) {
|
|
46
|
+
// Find the row containing the current story
|
|
47
|
+
const currentRowIdx = currentStoryId
|
|
48
|
+
? rows.findIndex((row) => row.some((story) => story.id === currentStoryId))
|
|
49
|
+
: -1;
|
|
50
|
+
|
|
51
|
+
if (currentRowIdx >= 0) {
|
|
52
|
+
// Center the window around the current story
|
|
53
|
+
const half = Math.floor(maxRows / 2);
|
|
54
|
+
startRow = Math.max(0, currentRowIdx - half);
|
|
55
|
+
|
|
56
|
+
// Adjust if window goes past the end
|
|
57
|
+
if (startRow + maxRows > rows.length) {
|
|
58
|
+
startRow = Math.max(0, rows.length - maxRows);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
endRow = Math.min(rows.length, startRow + maxRows);
|
|
62
|
+
visibleRows = rows.slice(startRow, endRow);
|
|
63
|
+
} else {
|
|
64
|
+
// No current story, just show first N rows
|
|
65
|
+
visibleRows = rows.slice(0, maxRows);
|
|
66
|
+
endRow = Math.min(rows.length, maxRows);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
42
69
|
|
|
43
70
|
return (
|
|
44
71
|
<Box flexDirection="column" paddingY={1}>
|
|
45
72
|
<Box paddingX={1}>
|
|
46
73
|
<Text color={colors.dim} bold>
|
|
47
|
-
|
|
74
|
+
{visibleRows.length < rows.length
|
|
75
|
+
? `── Stories (rows ${startRow + 1}-${endRow} of ${rows.length}, ${stories.length} total) ──`
|
|
76
|
+
: `── Stories (${stories.length}) ──`}
|
|
48
77
|
</Text>
|
|
49
78
|
</Box>
|
|
50
79
|
<Box flexDirection="column" paddingX={1}>
|