@mindfoldhq/trellis 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/LICENSE +110 -0
- package/README.md +149 -0
- package/bin/trellis.js +3 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +42 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +236 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/configurators/claude.d.ts +35 -0
- package/dist/configurators/claude.d.ts.map +1 -0
- package/dist/configurators/claude.js +83 -0
- package/dist/configurators/claude.js.map +1 -0
- package/dist/configurators/cursor.d.ts +8 -0
- package/dist/configurators/cursor.d.ts.map +1 -0
- package/dist/configurators/cursor.js +22 -0
- package/dist/configurators/cursor.js.map +1 -0
- package/dist/configurators/templates.d.ts +40 -0
- package/dist/configurators/templates.d.ts.map +1 -0
- package/dist/configurators/templates.js +67 -0
- package/dist/configurators/templates.js.map +1 -0
- package/dist/configurators/workflow.d.ts +16 -0
- package/dist/configurators/workflow.d.ts.map +1 -0
- package/dist/configurators/workflow.js +169 -0
- package/dist/configurators/workflow.js.map +1 -0
- package/dist/constants/paths.d.ts +69 -0
- package/dist/constants/paths.d.ts.map +1 -0
- package/dist/constants/paths.js +80 -0
- package/dist/constants/paths.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/templates/agents/check.txt +120 -0
- package/dist/templates/agents/debug.txt +121 -0
- package/dist/templates/agents/dispatch.txt +201 -0
- package/dist/templates/agents/implement.txt +114 -0
- package/dist/templates/agents/index.d.ts +35 -0
- package/dist/templates/agents/index.d.ts.map +1 -0
- package/dist/templates/agents/index.js +71 -0
- package/dist/templates/agents/index.js.map +1 -0
- package/dist/templates/agents/research.txt +258 -0
- package/dist/templates/commands/claude/start.md.txt +127 -0
- package/dist/templates/commands/common/before-backend-dev.txt +13 -0
- package/dist/templates/commands/common/before-frontend-dev.txt +13 -0
- package/dist/templates/commands/common/break-loop.txt +107 -0
- package/dist/templates/commands/common/check-backend.txt +13 -0
- package/dist/templates/commands/common/check-cross-layer.txt +153 -0
- package/dist/templates/commands/common/check-frontend.txt +13 -0
- package/dist/templates/commands/common/create-command.txt +154 -0
- package/dist/templates/commands/common/finish-work.txt +129 -0
- package/dist/templates/commands/common/integrate-skill.txt +219 -0
- package/dist/templates/commands/common/onboard-developer.txt +355 -0
- package/dist/templates/commands/common/record-agent-flow.txt +62 -0
- package/dist/templates/commands/cursor/start.md.txt +94 -0
- package/dist/templates/commands/index.d.ts +46 -0
- package/dist/templates/commands/index.d.ts.map +1 -0
- package/dist/templates/commands/index.js +151 -0
- package/dist/templates/commands/index.js.map +1 -0
- package/dist/templates/extract.d.ts +22 -0
- package/dist/templates/extract.d.ts.map +1 -0
- package/dist/templates/extract.js +34 -0
- package/dist/templates/extract.js.map +1 -0
- package/dist/templates/hooks/index.d.ts +33 -0
- package/dist/templates/hooks/index.d.ts.map +1 -0
- package/dist/templates/hooks/index.js +53 -0
- package/dist/templates/hooks/index.js.map +1 -0
- package/dist/templates/hooks/inject-subagent-context.py +620 -0
- package/dist/templates/hooks/settings.json +16 -0
- package/dist/templates/markdown/agent-traces-index.md.txt +124 -0
- package/dist/templates/markdown/agents.md.txt +18 -0
- package/dist/templates/markdown/gitignore.txt +3 -0
- package/dist/templates/markdown/index.d.ts +26 -0
- package/dist/templates/markdown/index.d.ts.map +1 -0
- package/dist/templates/markdown/index.js +33 -0
- package/dist/templates/markdown/index.js.map +1 -0
- package/dist/templates/markdown/init-agent.md.txt +315 -0
- package/dist/templates/markdown/structure/backend/database-guidelines.md.txt +51 -0
- package/dist/templates/markdown/structure/backend/directory-structure.md.txt +54 -0
- package/dist/templates/markdown/structure/backend/error-handling.md.txt +51 -0
- package/dist/templates/markdown/structure/backend/index.md.txt +38 -0
- package/dist/templates/markdown/structure/backend/logging-guidelines.md.txt +51 -0
- package/dist/templates/markdown/structure/backend/quality-guidelines.md.txt +51 -0
- package/dist/templates/markdown/structure/frontend/component-guidelines.md.txt +59 -0
- package/dist/templates/markdown/structure/frontend/directory-structure.md.txt +54 -0
- package/dist/templates/markdown/structure/frontend/hook-guidelines.md.txt +51 -0
- package/dist/templates/markdown/structure/frontend/index.md.txt +39 -0
- package/dist/templates/markdown/structure/frontend/quality-guidelines.md.txt +51 -0
- package/dist/templates/markdown/structure/frontend/state-management.md.txt +51 -0
- package/dist/templates/markdown/structure/frontend/type-safety.md.txt +51 -0
- package/dist/templates/markdown/structure/guides/code-reuse-thinking-guide.md.txt +92 -0
- package/dist/templates/markdown/structure/guides/cross-layer-thinking-guide.md.txt +94 -0
- package/dist/templates/markdown/structure/guides/index.md.txt +79 -0
- package/dist/templates/markdown/workflow.md.txt +335 -0
- package/dist/templates/scripts/add-session.sh.txt +384 -0
- package/dist/templates/scripts/common/developer.sh.txt +130 -0
- package/dist/templates/scripts/common/git-context.sh.txt +237 -0
- package/dist/templates/scripts/common/paths.sh.txt +201 -0
- package/dist/templates/scripts/create-bootstrap.sh.txt +298 -0
- package/dist/templates/scripts/feature.sh.txt +700 -0
- package/dist/templates/scripts/get-context.sh.txt +7 -0
- package/dist/templates/scripts/get-developer.sh.txt +15 -0
- package/dist/templates/scripts/index.d.ts +25 -0
- package/dist/templates/scripts/index.d.ts.map +1 -0
- package/dist/templates/scripts/index.js +28 -0
- package/dist/templates/scripts/index.js.map +1 -0
- package/dist/templates/scripts/init-developer.sh.txt +34 -0
- package/dist/types/ai-tools.d.ts +35 -0
- package/dist/types/ai-tools.d.ts.map +1 -0
- package/dist/types/ai-tools.js +31 -0
- package/dist/types/ai-tools.js.map +1 -0
- package/dist/utils/file-writer.d.ts +23 -0
- package/dist/utils/file-writer.d.ts.map +1 -0
- package/dist/utils/file-writer.js +140 -0
- package/dist/utils/file-writer.js.map +1 -0
- package/dist/utils/project-detector.d.ts +16 -0
- package/dist/utils/project-detector.d.ts.map +1 -0
- package/dist/utils/project-detector.js +186 -0
- package/dist/utils/project-detector.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,700 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Feature Management Script for Multi-Agent Pipeline
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# ./.trellis/scripts/feature.sh create <feature-name> # Create new feature
|
|
6
|
+
# ./.trellis/scripts/feature.sh init-context <dir> <type> # Initialize jsonl files
|
|
7
|
+
# ./.trellis/scripts/feature.sh add-context <dir> <file> <path> [reason] # Add jsonl entry
|
|
8
|
+
# ./.trellis/scripts/feature.sh validate <dir> # Validate jsonl files
|
|
9
|
+
# ./.trellis/scripts/feature.sh list-context <dir> # List jsonl entries
|
|
10
|
+
# ./.trellis/scripts/feature.sh start <dir> # Set as current feature
|
|
11
|
+
# ./.trellis/scripts/feature.sh finish # Clear current feature
|
|
12
|
+
# ./.trellis/scripts/feature.sh archive <feature-name> # Archive completed feature
|
|
13
|
+
# ./.trellis/scripts/feature.sh list # List active features
|
|
14
|
+
# ./.trellis/scripts/feature.sh list-archive [month] # List archived features
|
|
15
|
+
#
|
|
16
|
+
# Feature Directory Structure:
|
|
17
|
+
# features/
|
|
18
|
+
# ├── 13-my-feature/
|
|
19
|
+
# │ ├── feature.json # Metadata
|
|
20
|
+
# │ ├── prd.md # Requirements
|
|
21
|
+
# │ ├── info.md # Technical design (optional)
|
|
22
|
+
# │ ├── implement.jsonl # Implement agent context
|
|
23
|
+
# │ ├── check.jsonl # Check agent context
|
|
24
|
+
# │ └── debug.jsonl # Debug agent context
|
|
25
|
+
# └── archive/
|
|
26
|
+
# └── 2026-01/
|
|
27
|
+
# └── 13-old-feature/
|
|
28
|
+
|
|
29
|
+
set -e
|
|
30
|
+
|
|
31
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
32
|
+
source "$SCRIPT_DIR/common/paths.sh"
|
|
33
|
+
source "$SCRIPT_DIR/common/developer.sh"
|
|
34
|
+
|
|
35
|
+
# Colors
|
|
36
|
+
RED='\033[0;31m'
|
|
37
|
+
GREEN='\033[0;32m'
|
|
38
|
+
YELLOW='\033[1;33m'
|
|
39
|
+
BLUE='\033[0;34m'
|
|
40
|
+
CYAN='\033[0;36m'
|
|
41
|
+
NC='\033[0m'
|
|
42
|
+
|
|
43
|
+
REPO_ROOT=$(get_repo_root)
|
|
44
|
+
|
|
45
|
+
# =============================================================================
|
|
46
|
+
# jsonl Default Content Generators
|
|
47
|
+
# =============================================================================
|
|
48
|
+
|
|
49
|
+
get_implement_base() {
|
|
50
|
+
cat << EOF
|
|
51
|
+
{"file": "$DIR_WORKFLOW/workflow.md", "reason": "Project workflow and conventions"}
|
|
52
|
+
{"file": "$DIR_WORKFLOW/$DIR_STRUCTURE/shared/index.md", "reason": "Shared coding standards"}
|
|
53
|
+
EOF
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get_implement_backend() {
|
|
57
|
+
cat << EOF
|
|
58
|
+
{"file": "$DIR_WORKFLOW/$DIR_STRUCTURE/backend/index.md", "reason": "Backend development guide"}
|
|
59
|
+
{"file": "$DIR_WORKFLOW/$DIR_STRUCTURE/backend/api-module.md", "reason": "API module conventions"}
|
|
60
|
+
{"file": "$DIR_WORKFLOW/$DIR_STRUCTURE/backend/quality.md", "reason": "Code quality requirements"}
|
|
61
|
+
EOF
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
get_implement_frontend() {
|
|
65
|
+
cat << EOF
|
|
66
|
+
{"file": "$DIR_WORKFLOW/$DIR_STRUCTURE/frontend/index.md", "reason": "Frontend development guide"}
|
|
67
|
+
{"file": "$DIR_WORKFLOW/$DIR_STRUCTURE/frontend/components.md", "reason": "Component conventions"}
|
|
68
|
+
EOF
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get_check_context() {
|
|
72
|
+
local dev_type="$1"
|
|
73
|
+
|
|
74
|
+
cat << EOF
|
|
75
|
+
{"file": ".claude/commands/finish-work.md", "reason": "Finish work checklist"}
|
|
76
|
+
{"file": "$DIR_WORKFLOW/$DIR_STRUCTURE/shared/index.md", "reason": "Shared coding standards"}
|
|
77
|
+
EOF
|
|
78
|
+
|
|
79
|
+
if [[ "$dev_type" == "backend" ]] || [[ "$dev_type" == "fullstack" ]]; then
|
|
80
|
+
echo '{"file": ".claude/commands/check-backend.md", "reason": "Backend check spec"}'
|
|
81
|
+
fi
|
|
82
|
+
if [[ "$dev_type" == "frontend" ]] || [[ "$dev_type" == "fullstack" ]]; then
|
|
83
|
+
echo '{"file": ".claude/commands/check-frontend.md", "reason": "Frontend check spec"}'
|
|
84
|
+
fi
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get_debug_context() {
|
|
88
|
+
local dev_type="$1"
|
|
89
|
+
|
|
90
|
+
echo "{\"file\": \"$DIR_WORKFLOW/$DIR_STRUCTURE/shared/index.md\", \"reason\": \"Shared coding standards\"}"
|
|
91
|
+
|
|
92
|
+
if [[ "$dev_type" == "backend" ]] || [[ "$dev_type" == "fullstack" ]]; then
|
|
93
|
+
echo '{"file": ".claude/commands/check-backend.md", "reason": "Backend check spec"}'
|
|
94
|
+
fi
|
|
95
|
+
if [[ "$dev_type" == "frontend" ]] || [[ "$dev_type" == "fullstack" ]]; then
|
|
96
|
+
echo '{"file": ".claude/commands/check-frontend.md", "reason": "Frontend check spec"}'
|
|
97
|
+
fi
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# =============================================================================
|
|
101
|
+
# Feature Operations
|
|
102
|
+
# =============================================================================
|
|
103
|
+
|
|
104
|
+
ensure_features_dir() {
|
|
105
|
+
local features_dir=$(get_features_dir)
|
|
106
|
+
local archive_dir="$features_dir/archive"
|
|
107
|
+
|
|
108
|
+
if [[ ! -d "$features_dir" ]]; then
|
|
109
|
+
mkdir -p "$features_dir"
|
|
110
|
+
echo -e "${GREEN}Created features directory: $features_dir${NC}" >&2
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
if [[ ! -d "$archive_dir" ]]; then
|
|
114
|
+
mkdir -p "$archive_dir"
|
|
115
|
+
fi
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
# =============================================================================
|
|
119
|
+
# Command: create
|
|
120
|
+
# =============================================================================
|
|
121
|
+
|
|
122
|
+
cmd_create() {
|
|
123
|
+
local feature_name="$1"
|
|
124
|
+
|
|
125
|
+
if [[ -z "$feature_name" ]]; then
|
|
126
|
+
echo -e "${RED}Error: Feature name is required${NC}" >&2
|
|
127
|
+
echo "Usage: $0 create <feature-name>" >&2
|
|
128
|
+
exit 1
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
ensure_developer
|
|
132
|
+
ensure_features_dir
|
|
133
|
+
|
|
134
|
+
local features_dir=$(get_features_dir)
|
|
135
|
+
local day=$(date +%d)
|
|
136
|
+
local dir_name="${day}-${feature_name}"
|
|
137
|
+
local feature_dir="$features_dir/$dir_name"
|
|
138
|
+
local feature_json="$feature_dir/feature.json"
|
|
139
|
+
|
|
140
|
+
if [[ -d "$feature_dir" ]]; then
|
|
141
|
+
echo -e "${YELLOW}Warning: Feature already exists: $feature_dir${NC}" >&2
|
|
142
|
+
echo "$DIR_WORKFLOW/$DIR_PROGRESS/$(get_developer)/$DIR_FEATURES/$dir_name"
|
|
143
|
+
exit 0
|
|
144
|
+
fi
|
|
145
|
+
|
|
146
|
+
mkdir -p "$feature_dir"
|
|
147
|
+
|
|
148
|
+
local today=$(date +%Y-%m-%d)
|
|
149
|
+
local developer=$(get_developer)
|
|
150
|
+
|
|
151
|
+
cat > "$feature_json" << EOF
|
|
152
|
+
{
|
|
153
|
+
"id": "$feature_name",
|
|
154
|
+
"name": "$feature_name",
|
|
155
|
+
"description": "",
|
|
156
|
+
"status": "planning",
|
|
157
|
+
"dev_type": null,
|
|
158
|
+
"priority": "medium",
|
|
159
|
+
"developer": "$developer",
|
|
160
|
+
"createdAt": "$today",
|
|
161
|
+
"completedAt": null,
|
|
162
|
+
"commit": null,
|
|
163
|
+
"subtasks": [],
|
|
164
|
+
"relatedFiles": [],
|
|
165
|
+
"notes": ""
|
|
166
|
+
}
|
|
167
|
+
EOF
|
|
168
|
+
|
|
169
|
+
echo -e "${GREEN}Created feature: $dir_name${NC}" >&2
|
|
170
|
+
echo -e "" >&2
|
|
171
|
+
echo -e "${BLUE}Next steps:${NC}" >&2
|
|
172
|
+
echo -e " 1. Create prd.md with requirements" >&2
|
|
173
|
+
echo -e " 2. Run: $0 init-context <dir> <dev_type>" >&2
|
|
174
|
+
echo -e " 3. Run: $0 start <dir>" >&2
|
|
175
|
+
echo "" >&2
|
|
176
|
+
|
|
177
|
+
# Output relative path for script chaining
|
|
178
|
+
echo "$DIR_WORKFLOW/$DIR_PROGRESS/$developer/$DIR_FEATURES/$dir_name"
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
# =============================================================================
|
|
182
|
+
# Command: init-context
|
|
183
|
+
# =============================================================================
|
|
184
|
+
|
|
185
|
+
cmd_init_context() {
|
|
186
|
+
local target_dir="$1"
|
|
187
|
+
local dev_type="$2"
|
|
188
|
+
|
|
189
|
+
if [[ -z "$target_dir" ]] || [[ -z "$dev_type" ]]; then
|
|
190
|
+
echo -e "${RED}Error: Missing arguments${NC}"
|
|
191
|
+
echo "Usage: $0 init-context <feature-dir> <dev_type>"
|
|
192
|
+
echo " dev_type: backend | frontend | fullstack | test | docs"
|
|
193
|
+
exit 1
|
|
194
|
+
fi
|
|
195
|
+
|
|
196
|
+
# Support relative paths
|
|
197
|
+
if [[ ! "$target_dir" = /* ]]; then
|
|
198
|
+
target_dir="$REPO_ROOT/$target_dir"
|
|
199
|
+
fi
|
|
200
|
+
|
|
201
|
+
if [[ ! -d "$target_dir" ]]; then
|
|
202
|
+
echo -e "${RED}Error: Directory not found: $target_dir${NC}"
|
|
203
|
+
exit 1
|
|
204
|
+
fi
|
|
205
|
+
|
|
206
|
+
echo -e "${BLUE}=== Initializing Agent Context Files ===${NC}"
|
|
207
|
+
echo -e "Target dir: $target_dir"
|
|
208
|
+
echo -e "Dev type: $dev_type"
|
|
209
|
+
echo ""
|
|
210
|
+
|
|
211
|
+
# implement.jsonl
|
|
212
|
+
echo -e "${CYAN}Creating implement.jsonl...${NC}"
|
|
213
|
+
local implement_file="$target_dir/implement.jsonl"
|
|
214
|
+
{
|
|
215
|
+
get_implement_base
|
|
216
|
+
case "$dev_type" in
|
|
217
|
+
backend|test) get_implement_backend ;;
|
|
218
|
+
frontend) get_implement_frontend ;;
|
|
219
|
+
fullstack)
|
|
220
|
+
get_implement_backend
|
|
221
|
+
get_implement_frontend
|
|
222
|
+
;;
|
|
223
|
+
esac
|
|
224
|
+
} > "$implement_file"
|
|
225
|
+
echo -e " ${GREEN}✓${NC} $(wc -l < "$implement_file" | tr -d ' ') entries"
|
|
226
|
+
|
|
227
|
+
# check.jsonl
|
|
228
|
+
echo -e "${CYAN}Creating check.jsonl...${NC}"
|
|
229
|
+
local check_file="$target_dir/check.jsonl"
|
|
230
|
+
get_check_context "$dev_type" > "$check_file"
|
|
231
|
+
echo -e " ${GREEN}✓${NC} $(wc -l < "$check_file" | tr -d ' ') entries"
|
|
232
|
+
|
|
233
|
+
# debug.jsonl
|
|
234
|
+
echo -e "${CYAN}Creating debug.jsonl...${NC}"
|
|
235
|
+
local debug_file="$target_dir/debug.jsonl"
|
|
236
|
+
get_debug_context "$dev_type" > "$debug_file"
|
|
237
|
+
echo -e " ${GREEN}✓${NC} $(wc -l < "$debug_file" | tr -d ' ') entries"
|
|
238
|
+
|
|
239
|
+
echo ""
|
|
240
|
+
echo -e "${GREEN}✓ All context files created${NC}"
|
|
241
|
+
echo -e ""
|
|
242
|
+
echo -e "${BLUE}Next steps:${NC}"
|
|
243
|
+
echo -e " 1. Add task-specific specs: $0 add-context <dir> <jsonl> <path>"
|
|
244
|
+
echo -e " 2. Set as current: $0 start <dir>"
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
# =============================================================================
|
|
248
|
+
# Command: add-context
|
|
249
|
+
# =============================================================================
|
|
250
|
+
|
|
251
|
+
cmd_add_context() {
|
|
252
|
+
local target_dir="$1"
|
|
253
|
+
local jsonl_name="$2"
|
|
254
|
+
local path="$3"
|
|
255
|
+
local reason="${4:-Added manually}"
|
|
256
|
+
|
|
257
|
+
if [[ -z "$target_dir" ]] || [[ -z "$jsonl_name" ]] || [[ -z "$path" ]]; then
|
|
258
|
+
echo -e "${RED}Error: Missing arguments${NC}"
|
|
259
|
+
echo "Usage: $0 add-context <feature-dir> <jsonl-file> <path> [reason]"
|
|
260
|
+
echo " jsonl-file: implement | check | debug (or full filename)"
|
|
261
|
+
exit 1
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
# Support relative paths
|
|
265
|
+
if [[ ! "$target_dir" = /* ]]; then
|
|
266
|
+
target_dir="$REPO_ROOT/$target_dir"
|
|
267
|
+
fi
|
|
268
|
+
|
|
269
|
+
# Support shorthand
|
|
270
|
+
if [[ "$jsonl_name" != *.jsonl ]]; then
|
|
271
|
+
jsonl_name="${jsonl_name}.jsonl"
|
|
272
|
+
fi
|
|
273
|
+
|
|
274
|
+
local jsonl_file="$target_dir/$jsonl_name"
|
|
275
|
+
local full_path="$REPO_ROOT/$path"
|
|
276
|
+
local entry_type="file"
|
|
277
|
+
|
|
278
|
+
if [[ -d "$full_path" ]]; then
|
|
279
|
+
entry_type="directory"
|
|
280
|
+
[[ "$path" != */ ]] && path="$path/"
|
|
281
|
+
elif [[ ! -f "$full_path" ]]; then
|
|
282
|
+
echo -e "${RED}Error: Path not found: $path${NC}"
|
|
283
|
+
exit 1
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
# Check if already exists
|
|
287
|
+
if [[ -f "$jsonl_file" ]] && grep -q "\"$path\"" "$jsonl_file" 2>/dev/null; then
|
|
288
|
+
echo -e "${YELLOW}Warning: Entry already exists for $path${NC}"
|
|
289
|
+
exit 0
|
|
290
|
+
fi
|
|
291
|
+
|
|
292
|
+
# Add entry
|
|
293
|
+
if [[ "$entry_type" == "directory" ]]; then
|
|
294
|
+
echo "{\"file\": \"$path\", \"type\": \"directory\", \"reason\": \"$reason\"}" >> "$jsonl_file"
|
|
295
|
+
else
|
|
296
|
+
echo "{\"file\": \"$path\", \"reason\": \"$reason\"}" >> "$jsonl_file"
|
|
297
|
+
fi
|
|
298
|
+
|
|
299
|
+
echo -e "${GREEN}Added $entry_type: $path${NC}"
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
# =============================================================================
|
|
303
|
+
# Command: validate
|
|
304
|
+
# =============================================================================
|
|
305
|
+
|
|
306
|
+
validate_jsonl() {
|
|
307
|
+
local jsonl_file="$1"
|
|
308
|
+
local file_name=$(basename "$jsonl_file")
|
|
309
|
+
local errors=0
|
|
310
|
+
local line_num=0
|
|
311
|
+
|
|
312
|
+
if [[ ! -f "$jsonl_file" ]]; then
|
|
313
|
+
echo -e " ${YELLOW}$file_name: not found (skipped)${NC}"
|
|
314
|
+
return 0
|
|
315
|
+
fi
|
|
316
|
+
|
|
317
|
+
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
318
|
+
line_num=$((line_num + 1))
|
|
319
|
+
[[ -z "$line" ]] && continue
|
|
320
|
+
|
|
321
|
+
if ! echo "$line" | jq -e . > /dev/null 2>&1; then
|
|
322
|
+
echo -e " ${RED}$file_name:$line_num: Invalid JSON${NC}"
|
|
323
|
+
errors=$((errors + 1))
|
|
324
|
+
continue
|
|
325
|
+
fi
|
|
326
|
+
|
|
327
|
+
local file_path=$(echo "$line" | jq -r '.file // empty')
|
|
328
|
+
local entry_type=$(echo "$line" | jq -r '.type // "file"')
|
|
329
|
+
|
|
330
|
+
if [[ -z "$file_path" ]]; then
|
|
331
|
+
echo -e " ${RED}$file_name:$line_num: Missing 'file' field${NC}"
|
|
332
|
+
errors=$((errors + 1))
|
|
333
|
+
continue
|
|
334
|
+
fi
|
|
335
|
+
|
|
336
|
+
local full_path="$REPO_ROOT/$file_path"
|
|
337
|
+
if [[ "$entry_type" == "directory" ]]; then
|
|
338
|
+
if [[ ! -d "$full_path" ]]; then
|
|
339
|
+
echo -e " ${RED}$file_name:$line_num: Directory not found: $file_path${NC}"
|
|
340
|
+
errors=$((errors + 1))
|
|
341
|
+
fi
|
|
342
|
+
else
|
|
343
|
+
if [[ ! -f "$full_path" ]]; then
|
|
344
|
+
echo -e " ${RED}$file_name:$line_num: File not found: $file_path${NC}"
|
|
345
|
+
errors=$((errors + 1))
|
|
346
|
+
fi
|
|
347
|
+
fi
|
|
348
|
+
done < "$jsonl_file"
|
|
349
|
+
|
|
350
|
+
if [[ $errors -eq 0 ]]; then
|
|
351
|
+
echo -e " ${GREEN}$file_name: ✓ ($line_num entries)${NC}"
|
|
352
|
+
else
|
|
353
|
+
echo -e " ${RED}$file_name: ✗ ($errors errors)${NC}"
|
|
354
|
+
fi
|
|
355
|
+
|
|
356
|
+
return $errors
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
cmd_validate() {
|
|
360
|
+
local target_dir="$1"
|
|
361
|
+
|
|
362
|
+
if [[ -z "$target_dir" ]]; then
|
|
363
|
+
echo -e "${RED}Error: feature directory required${NC}"
|
|
364
|
+
exit 1
|
|
365
|
+
fi
|
|
366
|
+
|
|
367
|
+
if [[ ! "$target_dir" = /* ]]; then
|
|
368
|
+
target_dir="$REPO_ROOT/$target_dir"
|
|
369
|
+
fi
|
|
370
|
+
|
|
371
|
+
echo -e "${BLUE}=== Validating Context Files ===${NC}"
|
|
372
|
+
echo -e "Target dir: $target_dir"
|
|
373
|
+
echo ""
|
|
374
|
+
|
|
375
|
+
local total_errors=0
|
|
376
|
+
for jsonl_file in "$target_dir"/{implement,check,debug}.jsonl; do
|
|
377
|
+
validate_jsonl "$jsonl_file"
|
|
378
|
+
total_errors=$((total_errors + $?))
|
|
379
|
+
done
|
|
380
|
+
|
|
381
|
+
echo ""
|
|
382
|
+
if [[ $total_errors -eq 0 ]]; then
|
|
383
|
+
echo -e "${GREEN}✓ All validations passed${NC}"
|
|
384
|
+
else
|
|
385
|
+
echo -e "${RED}✗ Validation failed ($total_errors errors)${NC}"
|
|
386
|
+
exit 1
|
|
387
|
+
fi
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
# =============================================================================
|
|
391
|
+
# Command: list-context
|
|
392
|
+
# =============================================================================
|
|
393
|
+
|
|
394
|
+
cmd_list_context() {
|
|
395
|
+
local target_dir="$1"
|
|
396
|
+
|
|
397
|
+
if [[ -z "$target_dir" ]]; then
|
|
398
|
+
echo -e "${RED}Error: feature directory required${NC}"
|
|
399
|
+
exit 1
|
|
400
|
+
fi
|
|
401
|
+
|
|
402
|
+
if [[ ! "$target_dir" = /* ]]; then
|
|
403
|
+
target_dir="$REPO_ROOT/$target_dir"
|
|
404
|
+
fi
|
|
405
|
+
|
|
406
|
+
echo -e "${BLUE}=== Context Files ===${NC}"
|
|
407
|
+
echo ""
|
|
408
|
+
|
|
409
|
+
for jsonl_file in "$target_dir"/{implement,check,debug}.jsonl; do
|
|
410
|
+
local file_name=$(basename "$jsonl_file")
|
|
411
|
+
[[ ! -f "$jsonl_file" ]] && continue
|
|
412
|
+
|
|
413
|
+
echo -e "${CYAN}[$file_name]${NC}"
|
|
414
|
+
|
|
415
|
+
local count=0
|
|
416
|
+
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
417
|
+
[[ -z "$line" ]] && continue
|
|
418
|
+
|
|
419
|
+
local file_path=$(echo "$line" | jq -r '.file // "?"')
|
|
420
|
+
local entry_type=$(echo "$line" | jq -r '.type // "file"')
|
|
421
|
+
local reason=$(echo "$line" | jq -r '.reason // "-"')
|
|
422
|
+
count=$((count + 1))
|
|
423
|
+
|
|
424
|
+
if [[ "$entry_type" == "directory" ]]; then
|
|
425
|
+
echo -e " ${GREEN}$count.${NC} [DIR] $file_path"
|
|
426
|
+
else
|
|
427
|
+
echo -e " ${GREEN}$count.${NC} $file_path"
|
|
428
|
+
fi
|
|
429
|
+
echo -e " ${YELLOW}→${NC} $reason"
|
|
430
|
+
done < "$jsonl_file"
|
|
431
|
+
|
|
432
|
+
echo ""
|
|
433
|
+
done
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
# =============================================================================
|
|
437
|
+
# Command: start / finish
|
|
438
|
+
# =============================================================================
|
|
439
|
+
|
|
440
|
+
cmd_start() {
|
|
441
|
+
local feature_dir="$1"
|
|
442
|
+
|
|
443
|
+
if [[ -z "$feature_dir" ]]; then
|
|
444
|
+
echo -e "${RED}Error: feature directory required${NC}"
|
|
445
|
+
exit 1
|
|
446
|
+
fi
|
|
447
|
+
|
|
448
|
+
# Convert to relative path
|
|
449
|
+
if [[ "$feature_dir" = /* ]]; then
|
|
450
|
+
feature_dir="${feature_dir#$REPO_ROOT/}"
|
|
451
|
+
fi
|
|
452
|
+
|
|
453
|
+
# Verify directory exists
|
|
454
|
+
if [[ ! -d "$REPO_ROOT/$feature_dir" ]]; then
|
|
455
|
+
echo -e "${RED}Error: Feature directory not found: $feature_dir${NC}"
|
|
456
|
+
exit 1
|
|
457
|
+
fi
|
|
458
|
+
|
|
459
|
+
set_current_feature "$feature_dir"
|
|
460
|
+
echo -e "${GREEN}✓ Current feature set to: $feature_dir${NC}"
|
|
461
|
+
echo ""
|
|
462
|
+
echo -e "${BLUE}The hook will now inject context from this feature's jsonl files.${NC}"
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
cmd_finish() {
|
|
466
|
+
local current=$(get_current_feature)
|
|
467
|
+
|
|
468
|
+
if [[ -z "$current" ]]; then
|
|
469
|
+
echo -e "${YELLOW}No current feature set${NC}"
|
|
470
|
+
exit 0
|
|
471
|
+
fi
|
|
472
|
+
|
|
473
|
+
clear_current_feature
|
|
474
|
+
echo -e "${GREEN}✓ Cleared current feature (was: $current)${NC}"
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
# =============================================================================
|
|
478
|
+
# Command: archive
|
|
479
|
+
# =============================================================================
|
|
480
|
+
|
|
481
|
+
cmd_archive() {
|
|
482
|
+
local feature_name="$1"
|
|
483
|
+
|
|
484
|
+
if [[ -z "$feature_name" ]]; then
|
|
485
|
+
echo -e "${RED}Error: Feature name is required${NC}" >&2
|
|
486
|
+
echo "Usage: $0 archive <feature-name>" >&2
|
|
487
|
+
exit 1
|
|
488
|
+
fi
|
|
489
|
+
|
|
490
|
+
ensure_developer
|
|
491
|
+
|
|
492
|
+
local features_dir=$(get_features_dir)
|
|
493
|
+
local archive_dir="$features_dir/archive"
|
|
494
|
+
local year_month=$(date +%Y-%m)
|
|
495
|
+
local month_dir="$archive_dir/$year_month"
|
|
496
|
+
|
|
497
|
+
# Find feature directory (try exact match first, then suffix match)
|
|
498
|
+
local feature_dir=$(find "$features_dir" -maxdepth 1 -type d -name "${feature_name}" 2>/dev/null | head -1)
|
|
499
|
+
if [[ -z "$feature_dir" ]]; then
|
|
500
|
+
feature_dir=$(find "$features_dir" -maxdepth 1 -type d -name "*-${feature_name}" 2>/dev/null | head -1)
|
|
501
|
+
fi
|
|
502
|
+
|
|
503
|
+
if [[ -z "$feature_dir" ]] || [[ ! -d "$feature_dir" ]]; then
|
|
504
|
+
echo -e "${RED}Error: Feature not found: $feature_name${NC}" >&2
|
|
505
|
+
echo "Active features:" >&2
|
|
506
|
+
cmd_list >&2
|
|
507
|
+
exit 1
|
|
508
|
+
fi
|
|
509
|
+
|
|
510
|
+
if [[ ! -d "$month_dir" ]]; then
|
|
511
|
+
mkdir -p "$month_dir"
|
|
512
|
+
fi
|
|
513
|
+
|
|
514
|
+
local dir_name=$(basename "$feature_dir")
|
|
515
|
+
local feature_json="$feature_dir/feature.json"
|
|
516
|
+
|
|
517
|
+
# Update status
|
|
518
|
+
local today=$(date +%Y-%m-%d)
|
|
519
|
+
if [[ -f "$feature_json" ]] && command -v jq &> /dev/null; then
|
|
520
|
+
local temp_file=$(mktemp)
|
|
521
|
+
jq --arg date "$today" '.status = "completed" | .completedAt = $date' "$feature_json" > "$temp_file"
|
|
522
|
+
mv "$temp_file" "$feature_json"
|
|
523
|
+
elif [[ -f "$feature_json" ]]; then
|
|
524
|
+
sed -i.bak 's/"status": "in-progress"/"status": "completed"/' "$feature_json"
|
|
525
|
+
sed -i.bak "s/\"completedAt\": null/\"completedAt\": \"$today\"/" "$feature_json"
|
|
526
|
+
rm -f "${feature_json}.bak"
|
|
527
|
+
fi
|
|
528
|
+
|
|
529
|
+
# Clear if current feature
|
|
530
|
+
local current=$(get_current_feature)
|
|
531
|
+
if [[ "$current" == *"$dir_name"* ]]; then
|
|
532
|
+
clear_current_feature
|
|
533
|
+
fi
|
|
534
|
+
|
|
535
|
+
mv "$feature_dir" "$month_dir/"
|
|
536
|
+
|
|
537
|
+
echo -e "${GREEN}Archived: $dir_name -> archive/$year_month/${NC}" >&2
|
|
538
|
+
echo "$DIR_WORKFLOW/$DIR_PROGRESS/$(get_developer)/$DIR_FEATURES/$DIR_ARCHIVE/$year_month/$dir_name"
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
# =============================================================================
|
|
542
|
+
# Command: list
|
|
543
|
+
# =============================================================================
|
|
544
|
+
|
|
545
|
+
cmd_list() {
|
|
546
|
+
ensure_developer
|
|
547
|
+
|
|
548
|
+
local features_dir=$(get_features_dir)
|
|
549
|
+
local developer=$(get_developer)
|
|
550
|
+
local current_feature=$(get_current_feature)
|
|
551
|
+
|
|
552
|
+
echo -e "${BLUE}Active features for $developer:${NC}"
|
|
553
|
+
echo ""
|
|
554
|
+
|
|
555
|
+
local count=0
|
|
556
|
+
|
|
557
|
+
for d in "$features_dir"/*/; do
|
|
558
|
+
if [[ -d "$d" ]] && [[ "$(basename "$d")" != "archive" ]]; then
|
|
559
|
+
local dir_name=$(basename "$d")
|
|
560
|
+
local feature_json="$d/feature.json"
|
|
561
|
+
local status="unknown"
|
|
562
|
+
local relative_path="$DIR_WORKFLOW/$DIR_PROGRESS/$developer/$DIR_FEATURES/$dir_name"
|
|
563
|
+
|
|
564
|
+
if [[ -f "$feature_json" ]] && command -v jq &> /dev/null; then
|
|
565
|
+
status=$(jq -r '.status // "unknown"' "$feature_json")
|
|
566
|
+
fi
|
|
567
|
+
|
|
568
|
+
local marker=""
|
|
569
|
+
if [[ "$relative_path" == "$current_feature" ]]; then
|
|
570
|
+
marker=" ${GREEN}<- current${NC}"
|
|
571
|
+
fi
|
|
572
|
+
|
|
573
|
+
echo -e " - $dir_name/ ($status)$marker"
|
|
574
|
+
((count++))
|
|
575
|
+
fi
|
|
576
|
+
done
|
|
577
|
+
|
|
578
|
+
if [[ $count -eq 0 ]]; then
|
|
579
|
+
echo " (no active features)"
|
|
580
|
+
fi
|
|
581
|
+
|
|
582
|
+
echo ""
|
|
583
|
+
echo "Total: $count active feature(s)"
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
# =============================================================================
|
|
587
|
+
# Command: list-archive
|
|
588
|
+
# =============================================================================
|
|
589
|
+
|
|
590
|
+
cmd_list_archive() {
|
|
591
|
+
local month="$1"
|
|
592
|
+
|
|
593
|
+
ensure_developer
|
|
594
|
+
|
|
595
|
+
local features_dir=$(get_features_dir)
|
|
596
|
+
local archive_dir="$features_dir/archive"
|
|
597
|
+
local developer=$(get_developer)
|
|
598
|
+
|
|
599
|
+
echo -e "${BLUE}Archived features for $developer:${NC}"
|
|
600
|
+
echo ""
|
|
601
|
+
|
|
602
|
+
if [[ -n "$month" ]]; then
|
|
603
|
+
local month_dir="$archive_dir/$month"
|
|
604
|
+
if [[ -d "$month_dir" ]]; then
|
|
605
|
+
echo "[$month]"
|
|
606
|
+
for d in "$month_dir"/*/; do
|
|
607
|
+
if [[ -d "$d" ]]; then
|
|
608
|
+
echo " - $(basename "$d")/"
|
|
609
|
+
fi
|
|
610
|
+
done
|
|
611
|
+
else
|
|
612
|
+
echo " No archives for $month"
|
|
613
|
+
fi
|
|
614
|
+
else
|
|
615
|
+
for month_dir in "$archive_dir"/*/; do
|
|
616
|
+
if [[ -d "$month_dir" ]]; then
|
|
617
|
+
local month_name=$(basename "$month_dir")
|
|
618
|
+
local count=$(find "$month_dir" -maxdepth 1 -type d ! -name "$(basename "$month_dir")" | wc -l | tr -d ' ')
|
|
619
|
+
echo "[$month_name] - $count feature(s)"
|
|
620
|
+
fi
|
|
621
|
+
done
|
|
622
|
+
fi
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
# =============================================================================
|
|
626
|
+
# Help
|
|
627
|
+
# =============================================================================
|
|
628
|
+
|
|
629
|
+
show_usage() {
|
|
630
|
+
cat << EOF
|
|
631
|
+
Feature Management Script for Multi-Agent Pipeline
|
|
632
|
+
|
|
633
|
+
Usage:
|
|
634
|
+
$0 create <feature-name> Create new feature directory
|
|
635
|
+
$0 init-context <dir> <dev_type> Initialize jsonl files
|
|
636
|
+
$0 add-context <dir> <jsonl> <path> [reason] Add entry to jsonl
|
|
637
|
+
$0 validate <dir> Validate jsonl files
|
|
638
|
+
$0 list-context <dir> List jsonl entries
|
|
639
|
+
$0 start <dir> Set as current feature
|
|
640
|
+
$0 finish Clear current feature
|
|
641
|
+
$0 archive <feature-name> Archive completed feature
|
|
642
|
+
$0 list List active features
|
|
643
|
+
$0 list-archive [YYYY-MM] List archived features
|
|
644
|
+
|
|
645
|
+
Arguments:
|
|
646
|
+
dev_type: backend | frontend | fullstack | test | docs
|
|
647
|
+
|
|
648
|
+
Examples:
|
|
649
|
+
$0 create add-login-feature
|
|
650
|
+
$0 init-context .trellis/agent-traces/john/features/13-add-login-feature backend
|
|
651
|
+
$0 add-context <dir> implement .trellis/structure/backend/auth.md "Auth guidelines"
|
|
652
|
+
$0 start .trellis/agent-traces/john/features/13-add-login-feature
|
|
653
|
+
$0 finish
|
|
654
|
+
$0 archive add-login-feature
|
|
655
|
+
EOF
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
# =============================================================================
|
|
659
|
+
# Main Entry
|
|
660
|
+
# =============================================================================
|
|
661
|
+
|
|
662
|
+
case "${1:-}" in
|
|
663
|
+
create)
|
|
664
|
+
cmd_create "$2"
|
|
665
|
+
;;
|
|
666
|
+
init-context)
|
|
667
|
+
cmd_init_context "$2" "$3"
|
|
668
|
+
;;
|
|
669
|
+
add-context)
|
|
670
|
+
cmd_add_context "$2" "$3" "$4" "$5"
|
|
671
|
+
;;
|
|
672
|
+
validate)
|
|
673
|
+
cmd_validate "$2"
|
|
674
|
+
;;
|
|
675
|
+
list-context)
|
|
676
|
+
cmd_list_context "$2"
|
|
677
|
+
;;
|
|
678
|
+
start)
|
|
679
|
+
cmd_start "$2"
|
|
680
|
+
;;
|
|
681
|
+
finish)
|
|
682
|
+
cmd_finish
|
|
683
|
+
;;
|
|
684
|
+
archive)
|
|
685
|
+
cmd_archive "$2"
|
|
686
|
+
;;
|
|
687
|
+
list)
|
|
688
|
+
cmd_list
|
|
689
|
+
;;
|
|
690
|
+
list-archive)
|
|
691
|
+
cmd_list_archive "$2"
|
|
692
|
+
;;
|
|
693
|
+
-h|--help|help)
|
|
694
|
+
show_usage
|
|
695
|
+
;;
|
|
696
|
+
*)
|
|
697
|
+
show_usage
|
|
698
|
+
exit 1
|
|
699
|
+
;;
|
|
700
|
+
esac
|