@arvorco/relentless 0.1.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/.claude/commands/relentless.analyze.md +20 -0
- package/.claude/commands/relentless.checklist.md +15 -0
- package/.claude/commands/relentless.clarify.md +19 -0
- package/.claude/commands/relentless.constitution.md +78 -0
- package/.claude/commands/relentless.implement.md +15 -0
- package/.claude/commands/relentless.plan.md +22 -0
- package/.claude/commands/relentless.plan.old.md +89 -0
- package/.claude/commands/relentless.specify.md +254 -0
- package/.claude/commands/relentless.tasks.md +25 -0
- package/.claude/commands/relentless.taskstoissues.md +15 -0
- package/.claude/settings.local.json +23 -0
- package/.claude/skills/analyze/SKILL.md +149 -0
- package/.claude/skills/checklist/SKILL.md +173 -0
- package/.claude/skills/checklist/templates/checklist-template.md +40 -0
- package/.claude/skills/clarify/SKILL.md +174 -0
- package/.claude/skills/constitution/SKILL.md +150 -0
- package/.claude/skills/constitution/templates/constitution-template.md +228 -0
- package/.claude/skills/implement/SKILL.md +141 -0
- package/.claude/skills/plan/SKILL.md +179 -0
- package/.claude/skills/plan/templates/plan-template.md +104 -0
- package/.claude/skills/prd/SKILL.md +242 -0
- package/.claude/skills/relentless/SKILL.md +265 -0
- package/.claude/skills/specify/SKILL.md +220 -0
- package/.claude/skills/specify/scripts/bash/check-prerequisites.sh +166 -0
- package/.claude/skills/specify/scripts/bash/common.sh +156 -0
- package/.claude/skills/specify/scripts/bash/create-new-feature.sh +305 -0
- package/.claude/skills/specify/scripts/bash/setup-plan.sh +61 -0
- package/.claude/skills/specify/scripts/bash/update-agent-context.sh +799 -0
- package/.claude/skills/specify/templates/spec-template.md +115 -0
- package/.claude/skills/tasks/SKILL.md +202 -0
- package/.claude/skills/tasks/templates/tasks-template.md +251 -0
- package/.claude/skills/taskstoissues/SKILL.md +97 -0
- package/.specify/memory/constitution.md +50 -0
- package/.specify/scripts/bash/check-prerequisites.sh +166 -0
- package/.specify/scripts/bash/common.sh +156 -0
- package/.specify/scripts/bash/create-new-feature.sh +297 -0
- package/.specify/scripts/bash/setup-plan.sh +61 -0
- package/.specify/scripts/bash/update-agent-context.sh +799 -0
- package/.specify/templates/agent-file-template.md +28 -0
- package/.specify/templates/checklist-template.md +40 -0
- package/.specify/templates/plan-template.md +104 -0
- package/.specify/templates/spec-template.md +115 -0
- package/.specify/templates/tasks-template.md +251 -0
- package/CHANGES_SUMMARY.md +255 -0
- package/CLAUDE.md +92 -0
- package/GEMINI_SETUP.md +256 -0
- package/LICENSE +21 -0
- package/README.md +1171 -0
- package/REFACTOR_SUMMARY.md +267 -0
- package/bin/relentless.ts +536 -0
- package/bun.lock +352 -0
- package/eslint.config.js +37 -0
- package/package.json +61 -0
- package/prd.json.example +64 -0
- package/prompt.md +108 -0
- package/ralph.sh +80 -0
- package/relentless/config.json +38 -0
- package/relentless/features/.gitkeep +0 -0
- package/relentless/features/ghsk-ideas/prd.json +229 -0
- package/relentless/features/ghsk-ideas/prd.md +191 -0
- package/relentless/features/ghsk-ideas/progress.txt +408 -0
- package/relentless/prompt.md +79 -0
- package/skills/checklist/SKILL.md +349 -0
- package/skills/clarify/SKILL.md +476 -0
- package/skills/prd/SKILL.md +242 -0
- package/skills/relentless/SKILL.md +268 -0
- package/skills/tasks/SKILL.md +577 -0
- package/src/agents/amp.ts +115 -0
- package/src/agents/claude.ts +185 -0
- package/src/agents/codex.ts +89 -0
- package/src/agents/droid.ts +90 -0
- package/src/agents/gemini.ts +109 -0
- package/src/agents/index.ts +16 -0
- package/src/agents/opencode.ts +88 -0
- package/src/agents/registry.ts +95 -0
- package/src/agents/types.ts +101 -0
- package/src/config/index.ts +8 -0
- package/src/config/loader.ts +237 -0
- package/src/config/schema.ts +115 -0
- package/src/execution/index.ts +8 -0
- package/src/execution/router.ts +49 -0
- package/src/execution/runner.ts +512 -0
- package/src/index.ts +11 -0
- package/src/init/index.ts +7 -0
- package/src/init/scaffolder.ts +377 -0
- package/src/prd/analyzer.ts +512 -0
- package/src/prd/index.ts +11 -0
- package/src/prd/issues.ts +249 -0
- package/src/prd/parser.ts +281 -0
- package/src/prd/progress.ts +198 -0
- package/src/prd/types.ts +170 -0
- package/src/tui/App.tsx +85 -0
- package/src/tui/TUIRunner.tsx +400 -0
- package/src/tui/components/AgentOutput.tsx +45 -0
- package/src/tui/components/AgentStatus.tsx +64 -0
- package/src/tui/components/CurrentStory.tsx +66 -0
- package/src/tui/components/Header.tsx +49 -0
- package/src/tui/components/ProgressBar.tsx +39 -0
- package/src/tui/components/StoryGrid.tsx +86 -0
- package/src/tui/hooks/useTUI.ts +147 -0
- package/src/tui/hooks/useTimer.ts +51 -0
- package/src/tui/index.tsx +17 -0
- package/src/tui/theme.ts +41 -0
- package/src/tui/types.ts +77 -0
- package/templates/constitution.md +228 -0
- package/templates/plan.md +273 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StoryGrid Component
|
|
3
|
+
*
|
|
4
|
+
* Visual grid showing all stories with status
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from "react";
|
|
8
|
+
import { Box, Text } from "ink";
|
|
9
|
+
import { colors, symbols } from "../theme.js";
|
|
10
|
+
import type { Story } from "../types.js";
|
|
11
|
+
|
|
12
|
+
interface StoryGridProps {
|
|
13
|
+
stories: Story[];
|
|
14
|
+
currentStoryId?: string;
|
|
15
|
+
columns?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function StoryGrid({
|
|
19
|
+
stories,
|
|
20
|
+
currentStoryId,
|
|
21
|
+
columns = 2,
|
|
22
|
+
}: StoryGridProps): React.ReactElement {
|
|
23
|
+
// Split stories into columns
|
|
24
|
+
const rows: Story[][] = [];
|
|
25
|
+
const storiesPerColumn = Math.ceil(stories.length / columns);
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < storiesPerColumn; i++) {
|
|
28
|
+
const row: Story[] = [];
|
|
29
|
+
for (let col = 0; col < columns; col++) {
|
|
30
|
+
const idx = col * storiesPerColumn + i;
|
|
31
|
+
if (idx < stories.length) {
|
|
32
|
+
row.push(stories[idx]);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
rows.push(row);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<Box flexDirection="column" borderStyle="single" borderColor={colors.dim}>
|
|
40
|
+
<Box paddingX={1} borderBottom borderColor={colors.dim}>
|
|
41
|
+
<Text color={colors.dim} bold>
|
|
42
|
+
Stories
|
|
43
|
+
</Text>
|
|
44
|
+
</Box>
|
|
45
|
+
<Box flexDirection="column" paddingX={1} paddingY={0}>
|
|
46
|
+
{rows.map((row, rowIdx) => (
|
|
47
|
+
<Box key={rowIdx} flexDirection="row">
|
|
48
|
+
{row.map((story, colIdx) => {
|
|
49
|
+
const isCurrent = story.id === currentStoryId;
|
|
50
|
+
const symbol = isCurrent
|
|
51
|
+
? symbols.inProgress
|
|
52
|
+
: story.passes
|
|
53
|
+
? symbols.complete
|
|
54
|
+
: symbols.pending;
|
|
55
|
+
const symbolColor = isCurrent
|
|
56
|
+
? colors.warning
|
|
57
|
+
: story.passes
|
|
58
|
+
? colors.success
|
|
59
|
+
: colors.dim;
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<Box key={colIdx} width="50%">
|
|
63
|
+
<Text color={symbolColor}>{symbol} </Text>
|
|
64
|
+
<Text
|
|
65
|
+
color={story.passes ? colors.success : isCurrent ? colors.warning : undefined}
|
|
66
|
+
dimColor={story.passes}
|
|
67
|
+
>
|
|
68
|
+
{story.id.padEnd(8)}
|
|
69
|
+
</Text>
|
|
70
|
+
<Text
|
|
71
|
+
color={colors.dim}
|
|
72
|
+
dimColor={story.passes}
|
|
73
|
+
strikethrough={story.passes}
|
|
74
|
+
wrap="truncate"
|
|
75
|
+
>
|
|
76
|
+
{story.title.substring(0, 25)}
|
|
77
|
+
</Text>
|
|
78
|
+
</Box>
|
|
79
|
+
);
|
|
80
|
+
})}
|
|
81
|
+
</Box>
|
|
82
|
+
))}
|
|
83
|
+
</Box>
|
|
84
|
+
</Box>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useTUI Hook
|
|
3
|
+
*
|
|
4
|
+
* Main state management hook for the TUI
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useState, useCallback } from "react";
|
|
8
|
+
import type { TUIState, TUIActions, Story, AgentState } from "../types.js";
|
|
9
|
+
import type { AgentName } from "../../agents/types.js";
|
|
10
|
+
|
|
11
|
+
interface UseTUIOptions {
|
|
12
|
+
feature: string;
|
|
13
|
+
project: string;
|
|
14
|
+
branchName: string;
|
|
15
|
+
stories: Story[];
|
|
16
|
+
maxIterations: number;
|
|
17
|
+
agents: AgentState[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface UseTUIReturn {
|
|
21
|
+
state: TUIState;
|
|
22
|
+
actions: TUIActions;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function useTUI(options: UseTUIOptions): UseTUIReturn {
|
|
26
|
+
const [state, setState] = useState<TUIState>({
|
|
27
|
+
feature: options.feature,
|
|
28
|
+
project: options.project,
|
|
29
|
+
branchName: options.branchName,
|
|
30
|
+
stories: options.stories,
|
|
31
|
+
iteration: 0,
|
|
32
|
+
maxIterations: options.maxIterations,
|
|
33
|
+
currentStory: null,
|
|
34
|
+
currentAgent: null,
|
|
35
|
+
agents: options.agents,
|
|
36
|
+
outputLines: [],
|
|
37
|
+
elapsedSeconds: 0,
|
|
38
|
+
isRunning: false,
|
|
39
|
+
isComplete: false,
|
|
40
|
+
error: undefined,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
const addOutput = useCallback((line: string) => {
|
|
44
|
+
setState((prev) => ({
|
|
45
|
+
...prev,
|
|
46
|
+
outputLines: [...prev.outputLines, line],
|
|
47
|
+
}));
|
|
48
|
+
}, []);
|
|
49
|
+
|
|
50
|
+
const clearOutput = useCallback(() => {
|
|
51
|
+
setState((prev) => ({
|
|
52
|
+
...prev,
|
|
53
|
+
outputLines: [],
|
|
54
|
+
}));
|
|
55
|
+
}, []);
|
|
56
|
+
|
|
57
|
+
const setCurrentStory = useCallback((story: Story | null) => {
|
|
58
|
+
setState((prev) => ({
|
|
59
|
+
...prev,
|
|
60
|
+
currentStory: story,
|
|
61
|
+
}));
|
|
62
|
+
}, []);
|
|
63
|
+
|
|
64
|
+
const setCurrentAgent = useCallback((agent: AgentState | null) => {
|
|
65
|
+
setState((prev) => ({
|
|
66
|
+
...prev,
|
|
67
|
+
currentAgent: agent,
|
|
68
|
+
agents: prev.agents.map((a) => ({
|
|
69
|
+
...a,
|
|
70
|
+
active: agent ? a.name === agent.name : false,
|
|
71
|
+
})),
|
|
72
|
+
}));
|
|
73
|
+
}, []);
|
|
74
|
+
|
|
75
|
+
const markAgentLimited = useCallback((name: AgentName, resetTime?: Date) => {
|
|
76
|
+
setState((prev) => ({
|
|
77
|
+
...prev,
|
|
78
|
+
agents: prev.agents.map((a) =>
|
|
79
|
+
a.name === name ? { ...a, rateLimited: true, resetTime, active: false } : a
|
|
80
|
+
),
|
|
81
|
+
currentAgent:
|
|
82
|
+
prev.currentAgent?.name === name
|
|
83
|
+
? { ...prev.currentAgent, rateLimited: true, resetTime }
|
|
84
|
+
: prev.currentAgent,
|
|
85
|
+
}));
|
|
86
|
+
}, []);
|
|
87
|
+
|
|
88
|
+
const clearAgentLimit = useCallback((name: AgentName) => {
|
|
89
|
+
setState((prev) => ({
|
|
90
|
+
...prev,
|
|
91
|
+
agents: prev.agents.map((a) =>
|
|
92
|
+
a.name === name ? { ...a, rateLimited: false, resetTime: undefined } : a
|
|
93
|
+
),
|
|
94
|
+
}));
|
|
95
|
+
}, []);
|
|
96
|
+
|
|
97
|
+
const updateStory = useCallback((id: string, passes: boolean) => {
|
|
98
|
+
setState((prev) => ({
|
|
99
|
+
...prev,
|
|
100
|
+
stories: prev.stories.map((s) => (s.id === id ? { ...s, passes } : s)),
|
|
101
|
+
}));
|
|
102
|
+
}, []);
|
|
103
|
+
|
|
104
|
+
const setIteration = useCallback((iteration: number) => {
|
|
105
|
+
setState((prev) => ({
|
|
106
|
+
...prev,
|
|
107
|
+
iteration,
|
|
108
|
+
}));
|
|
109
|
+
}, []);
|
|
110
|
+
|
|
111
|
+
const setRunning = useCallback((isRunning: boolean) => {
|
|
112
|
+
setState((prev) => ({
|
|
113
|
+
...prev,
|
|
114
|
+
isRunning,
|
|
115
|
+
}));
|
|
116
|
+
}, []);
|
|
117
|
+
|
|
118
|
+
const setComplete = useCallback((isComplete: boolean) => {
|
|
119
|
+
setState((prev) => ({
|
|
120
|
+
...prev,
|
|
121
|
+
isComplete,
|
|
122
|
+
}));
|
|
123
|
+
}, []);
|
|
124
|
+
|
|
125
|
+
const setError = useCallback((error: string | undefined) => {
|
|
126
|
+
setState((prev) => ({
|
|
127
|
+
...prev,
|
|
128
|
+
error,
|
|
129
|
+
}));
|
|
130
|
+
}, []);
|
|
131
|
+
|
|
132
|
+
const actions: TUIActions = {
|
|
133
|
+
addOutput,
|
|
134
|
+
clearOutput,
|
|
135
|
+
setCurrentStory,
|
|
136
|
+
setCurrentAgent,
|
|
137
|
+
markAgentLimited,
|
|
138
|
+
clearAgentLimit,
|
|
139
|
+
updateStory,
|
|
140
|
+
setIteration,
|
|
141
|
+
setRunning,
|
|
142
|
+
setComplete,
|
|
143
|
+
setError,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return { state, actions };
|
|
147
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useTimer Hook
|
|
3
|
+
*
|
|
4
|
+
* Tracks elapsed time for the current operation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useState, useEffect, useCallback, useRef } from "react";
|
|
8
|
+
|
|
9
|
+
interface UseTimerReturn {
|
|
10
|
+
seconds: number;
|
|
11
|
+
start: () => void;
|
|
12
|
+
stop: () => void;
|
|
13
|
+
reset: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function useTimer(): UseTimerReturn {
|
|
17
|
+
const [seconds, setSeconds] = useState(0);
|
|
18
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
19
|
+
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (isRunning) {
|
|
23
|
+
intervalRef.current = setInterval(() => {
|
|
24
|
+
setSeconds((s) => s + 1);
|
|
25
|
+
}, 1000);
|
|
26
|
+
} else if (intervalRef.current) {
|
|
27
|
+
clearInterval(intervalRef.current);
|
|
28
|
+
intervalRef.current = null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return () => {
|
|
32
|
+
if (intervalRef.current) {
|
|
33
|
+
clearInterval(intervalRef.current);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}, [isRunning]);
|
|
37
|
+
|
|
38
|
+
const start = useCallback(() => {
|
|
39
|
+
setIsRunning(true);
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
const stop = useCallback(() => {
|
|
43
|
+
setIsRunning(false);
|
|
44
|
+
}, []);
|
|
45
|
+
|
|
46
|
+
const reset = useCallback(() => {
|
|
47
|
+
setSeconds(0);
|
|
48
|
+
}, []);
|
|
49
|
+
|
|
50
|
+
return { seconds, start, stop, reset };
|
|
51
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI Module
|
|
3
|
+
*
|
|
4
|
+
* Beautiful terminal interface for Relentless
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { App } from "./App.js";
|
|
8
|
+
export { Header } from "./components/Header.js";
|
|
9
|
+
export { ProgressBar } from "./components/ProgressBar.js";
|
|
10
|
+
export { CurrentStory } from "./components/CurrentStory.js";
|
|
11
|
+
export { AgentOutput } from "./components/AgentOutput.js";
|
|
12
|
+
export { StoryGrid } from "./components/StoryGrid.js";
|
|
13
|
+
export { AgentStatus } from "./components/AgentStatus.js";
|
|
14
|
+
export { useTUI } from "./hooks/useTUI.js";
|
|
15
|
+
export { useTimer } from "./hooks/useTimer.js";
|
|
16
|
+
export * from "./types.js";
|
|
17
|
+
export * from "./theme.js";
|
package/src/tui/theme.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI Theme
|
|
3
|
+
*
|
|
4
|
+
* Colors, borders, and styling constants
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const colors = {
|
|
8
|
+
primary: "cyan",
|
|
9
|
+
success: "green",
|
|
10
|
+
warning: "yellow",
|
|
11
|
+
error: "red",
|
|
12
|
+
dim: "gray",
|
|
13
|
+
accent: "magenta",
|
|
14
|
+
} as const;
|
|
15
|
+
|
|
16
|
+
export const symbols = {
|
|
17
|
+
complete: "✓",
|
|
18
|
+
pending: "○",
|
|
19
|
+
inProgress: "◉",
|
|
20
|
+
arrow: "→",
|
|
21
|
+
bullet: "•",
|
|
22
|
+
lightning: "⚡",
|
|
23
|
+
rocket: "🚀",
|
|
24
|
+
party: "🎉",
|
|
25
|
+
warning: "⚠️",
|
|
26
|
+
error: "❌",
|
|
27
|
+
clock: "⏳",
|
|
28
|
+
} as const;
|
|
29
|
+
|
|
30
|
+
export const borders = {
|
|
31
|
+
horizontal: "─",
|
|
32
|
+
vertical: "│",
|
|
33
|
+
topLeft: "┌",
|
|
34
|
+
topRight: "┐",
|
|
35
|
+
bottomLeft: "└",
|
|
36
|
+
bottomRight: "┘",
|
|
37
|
+
teeLeft: "├",
|
|
38
|
+
teeRight: "┤",
|
|
39
|
+
cross: "┼",
|
|
40
|
+
doubleLine: "═",
|
|
41
|
+
} as const;
|
package/src/tui/types.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TUI Types
|
|
3
|
+
*
|
|
4
|
+
* State and props types for the TUI components
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { AgentName } from "../agents/types";
|
|
8
|
+
|
|
9
|
+
export interface Story {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
passes: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface AgentState {
|
|
16
|
+
name: AgentName;
|
|
17
|
+
displayName: string;
|
|
18
|
+
active: boolean;
|
|
19
|
+
rateLimited: boolean;
|
|
20
|
+
resetTime?: Date;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TUIState {
|
|
24
|
+
/** Feature name */
|
|
25
|
+
feature: string;
|
|
26
|
+
/** Project name */
|
|
27
|
+
project: string;
|
|
28
|
+
/** Branch name */
|
|
29
|
+
branchName: string;
|
|
30
|
+
/** All stories */
|
|
31
|
+
stories: Story[];
|
|
32
|
+
/** Current iteration */
|
|
33
|
+
iteration: number;
|
|
34
|
+
/** Maximum iterations */
|
|
35
|
+
maxIterations: number;
|
|
36
|
+
/** Current story being worked on */
|
|
37
|
+
currentStory: Story | null;
|
|
38
|
+
/** Current agent */
|
|
39
|
+
currentAgent: AgentState | null;
|
|
40
|
+
/** All agents with their states */
|
|
41
|
+
agents: AgentState[];
|
|
42
|
+
/** Agent output lines */
|
|
43
|
+
outputLines: string[];
|
|
44
|
+
/** Elapsed time in seconds */
|
|
45
|
+
elapsedSeconds: number;
|
|
46
|
+
/** Is running */
|
|
47
|
+
isRunning: boolean;
|
|
48
|
+
/** Is complete */
|
|
49
|
+
isComplete: boolean;
|
|
50
|
+
/** Error message if any */
|
|
51
|
+
error?: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export interface TUIActions {
|
|
55
|
+
/** Add output line */
|
|
56
|
+
addOutput: (line: string) => void;
|
|
57
|
+
/** Clear output */
|
|
58
|
+
clearOutput: () => void;
|
|
59
|
+
/** Set current story */
|
|
60
|
+
setCurrentStory: (story: Story | null) => void;
|
|
61
|
+
/** Set current agent */
|
|
62
|
+
setCurrentAgent: (agent: AgentState | null) => void;
|
|
63
|
+
/** Mark agent as rate limited */
|
|
64
|
+
markAgentLimited: (name: AgentName, resetTime?: Date) => void;
|
|
65
|
+
/** Clear agent rate limit */
|
|
66
|
+
clearAgentLimit: (name: AgentName) => void;
|
|
67
|
+
/** Update story status */
|
|
68
|
+
updateStory: (id: string, passes: boolean) => void;
|
|
69
|
+
/** Set iteration */
|
|
70
|
+
setIteration: (iteration: number) => void;
|
|
71
|
+
/** Set running state */
|
|
72
|
+
setRunning: (running: boolean) => void;
|
|
73
|
+
/** Set complete */
|
|
74
|
+
setComplete: (complete: boolean) => void;
|
|
75
|
+
/** Set error */
|
|
76
|
+
setError: (error: string | undefined) => void;
|
|
77
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Project Constitution
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This document defines the governing principles, patterns, and constraints for this project. All agents and developers MUST follow these guidelines when working on the codebase.
|
|
6
|
+
|
|
7
|
+
## Core Principles
|
|
8
|
+
|
|
9
|
+
### Architecture
|
|
10
|
+
|
|
11
|
+
**MUST** follow these architectural patterns:
|
|
12
|
+
- Follow existing code structure and organization patterns
|
|
13
|
+
- Keep modules focused and single-purpose
|
|
14
|
+
- Use dependency injection where appropriate
|
|
15
|
+
|
|
16
|
+
**SHOULD** consider these best practices:
|
|
17
|
+
- Prefer composition over inheritance
|
|
18
|
+
- Keep functions small and focused
|
|
19
|
+
- Write self-documenting code
|
|
20
|
+
|
|
21
|
+
### Code Quality
|
|
22
|
+
|
|
23
|
+
**MUST** maintain these quality standards:
|
|
24
|
+
- All commits MUST pass typecheck with 0 errors
|
|
25
|
+
- All commits MUST pass lint with 0 warnings
|
|
26
|
+
- All new features MUST include appropriate tests
|
|
27
|
+
- All code MUST be formatted consistently
|
|
28
|
+
|
|
29
|
+
**SHOULD** strive for:
|
|
30
|
+
- High test coverage (aim for >80%)
|
|
31
|
+
- Clear, descriptive variable and function names
|
|
32
|
+
- Comprehensive error handling
|
|
33
|
+
|
|
34
|
+
### Version Control
|
|
35
|
+
|
|
36
|
+
**MUST** follow these Git practices:
|
|
37
|
+
- Write clear, descriptive commit messages
|
|
38
|
+
- Reference user story IDs in commits: `feat: [US-XXX] - Description`
|
|
39
|
+
- Keep commits focused and atomic
|
|
40
|
+
- Do not commit broken code
|
|
41
|
+
|
|
42
|
+
**SHOULD** maintain:
|
|
43
|
+
- Clean commit history
|
|
44
|
+
- Meaningful branch names
|
|
45
|
+
- Updated documentation with code changes
|
|
46
|
+
|
|
47
|
+
## Technology Stack
|
|
48
|
+
|
|
49
|
+
### Language & Runtime
|
|
50
|
+
|
|
51
|
+
- **TypeScript** - Primary language
|
|
52
|
+
- **Bun** - Runtime environment (not Node.js)
|
|
53
|
+
- **Zod** - Schema validation
|
|
54
|
+
|
|
55
|
+
### Key Libraries
|
|
56
|
+
|
|
57
|
+
- Commander - CLI parsing
|
|
58
|
+
- Chalk - Terminal formatting
|
|
59
|
+
- Execa - Process execution
|
|
60
|
+
|
|
61
|
+
## File Organization
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
project/
|
|
65
|
+
├── bin/ # CLI entry points
|
|
66
|
+
├── src/ # Source code
|
|
67
|
+
│ ├── agents/ # Agent adapters
|
|
68
|
+
│ ├── config/ # Configuration
|
|
69
|
+
│ ├── execution/ # Orchestration
|
|
70
|
+
│ ├── init/ # Project scaffolding
|
|
71
|
+
│ └── prd/ # PRD handling
|
|
72
|
+
├── templates/ # Template files
|
|
73
|
+
├── skills/ # Agent skills
|
|
74
|
+
└── relentless/ # Relentless workspace
|
|
75
|
+
├── config.json
|
|
76
|
+
├── prompt.md
|
|
77
|
+
└── features/
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Coding Standards
|
|
81
|
+
|
|
82
|
+
### TypeScript
|
|
83
|
+
|
|
84
|
+
**MUST** follow:
|
|
85
|
+
- Use strict TypeScript mode
|
|
86
|
+
- Avoid `any` type - use `unknown` or proper types
|
|
87
|
+
- Export types alongside implementations
|
|
88
|
+
- Use Zod schemas for runtime validation
|
|
89
|
+
|
|
90
|
+
**SHOULD** prefer:
|
|
91
|
+
- Interface for public APIs
|
|
92
|
+
- Type for unions and intersections
|
|
93
|
+
- Explicit return types on public functions
|
|
94
|
+
|
|
95
|
+
### Error Handling
|
|
96
|
+
|
|
97
|
+
**MUST** implement:
|
|
98
|
+
- Descriptive error messages
|
|
99
|
+
- Proper error types
|
|
100
|
+
- Validation at system boundaries
|
|
101
|
+
- Graceful degradation where appropriate
|
|
102
|
+
|
|
103
|
+
**SHOULD** include:
|
|
104
|
+
- Context in error messages
|
|
105
|
+
- Recovery suggestions
|
|
106
|
+
- Logging for debugging
|
|
107
|
+
|
|
108
|
+
### Testing
|
|
109
|
+
|
|
110
|
+
**MUST** test:
|
|
111
|
+
- Core business logic
|
|
112
|
+
- Edge cases and error conditions
|
|
113
|
+
- Integration points
|
|
114
|
+
- CLI commands
|
|
115
|
+
|
|
116
|
+
**SHOULD** test:
|
|
117
|
+
- Helper functions
|
|
118
|
+
- Utilities
|
|
119
|
+
- Type guards
|
|
120
|
+
|
|
121
|
+
## Documentation
|
|
122
|
+
|
|
123
|
+
**MUST** document:
|
|
124
|
+
- Public APIs and interfaces
|
|
125
|
+
- Complex algorithms or logic
|
|
126
|
+
- Breaking changes in commits
|
|
127
|
+
- Setup and installation steps
|
|
128
|
+
|
|
129
|
+
**SHOULD** document:
|
|
130
|
+
- Configuration options
|
|
131
|
+
- Architecture decisions
|
|
132
|
+
- Common workflows
|
|
133
|
+
- Troubleshooting steps
|
|
134
|
+
|
|
135
|
+
## Security
|
|
136
|
+
|
|
137
|
+
**MUST** ensure:
|
|
138
|
+
- No secrets committed to git
|
|
139
|
+
- Proper input validation
|
|
140
|
+
- Safe file system operations
|
|
141
|
+
- Minimal permissions required
|
|
142
|
+
|
|
143
|
+
**SHOULD** consider:
|
|
144
|
+
- Rate limiting where appropriate
|
|
145
|
+
- Audit logs for sensitive operations
|
|
146
|
+
- Security updates for dependencies
|
|
147
|
+
|
|
148
|
+
## Performance
|
|
149
|
+
|
|
150
|
+
**MUST** maintain:
|
|
151
|
+
- Fast startup time (<1s)
|
|
152
|
+
- Responsive CLI commands
|
|
153
|
+
- Efficient file operations
|
|
154
|
+
- Minimal memory footprint
|
|
155
|
+
|
|
156
|
+
**SHOULD** optimize:
|
|
157
|
+
- Parallel operations where safe
|
|
158
|
+
- Caching for repeated operations
|
|
159
|
+
- Lazy loading of heavy modules
|
|
160
|
+
|
|
161
|
+
## Constraints
|
|
162
|
+
|
|
163
|
+
### Dependencies
|
|
164
|
+
|
|
165
|
+
**MUST NOT**:
|
|
166
|
+
- Add dependencies without justification
|
|
167
|
+
- Include deprecated packages
|
|
168
|
+
- Use packages with known security issues
|
|
169
|
+
|
|
170
|
+
**SHOULD**:
|
|
171
|
+
- Prefer built-in solutions over dependencies
|
|
172
|
+
- Keep dependencies minimal and focused
|
|
173
|
+
- Regularly update dependencies
|
|
174
|
+
|
|
175
|
+
### Backwards Compatibility
|
|
176
|
+
|
|
177
|
+
**MUST**:
|
|
178
|
+
- Maintain compatibility with existing PRDs
|
|
179
|
+
- Provide migration paths for breaking changes
|
|
180
|
+
- Version configuration formats
|
|
181
|
+
|
|
182
|
+
**SHOULD**:
|
|
183
|
+
- Deprecate features before removal
|
|
184
|
+
- Provide clear upgrade documentation
|
|
185
|
+
- Support at least 2 major versions
|
|
186
|
+
|
|
187
|
+
## Agent-Specific Guidelines
|
|
188
|
+
|
|
189
|
+
### For All Agents
|
|
190
|
+
|
|
191
|
+
**MUST**:
|
|
192
|
+
- Read progress.txt before starting work
|
|
193
|
+
- Work on ONE story per iteration
|
|
194
|
+
- Update PRD after completing a story
|
|
195
|
+
- Append learnings to progress.txt
|
|
196
|
+
- Run all quality checks before committing
|
|
197
|
+
|
|
198
|
+
**SHOULD**:
|
|
199
|
+
- Review existing code before modifying
|
|
200
|
+
- Follow established patterns
|
|
201
|
+
- Ask questions when unclear
|
|
202
|
+
- Document non-obvious decisions
|
|
203
|
+
|
|
204
|
+
### Iteration Workflow
|
|
205
|
+
|
|
206
|
+
1. Read PRD to find next incomplete story
|
|
207
|
+
2. Read progress.txt for context and patterns
|
|
208
|
+
3. Review relevant existing code
|
|
209
|
+
4. Implement the single story
|
|
210
|
+
5. Run typecheck and lint
|
|
211
|
+
6. Run tests if applicable
|
|
212
|
+
7. Commit with proper message format
|
|
213
|
+
8. Update PRD passes: true
|
|
214
|
+
9. Append to progress.txt
|
|
215
|
+
10. Check if all stories complete
|
|
216
|
+
|
|
217
|
+
## Review and Updates
|
|
218
|
+
|
|
219
|
+
This constitution should be:
|
|
220
|
+
- **Reviewed** at project milestones
|
|
221
|
+
- **Updated** when patterns emerge
|
|
222
|
+
- **Referenced** in code reviews
|
|
223
|
+
- **Enforced** in CI/CD pipelines
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
Last Updated: YYYY-MM-DD
|
|
228
|
+
Version: 1.0.0
|