@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.
Files changed (122) hide show
  1. package/LICENSE +110 -0
  2. package/README.md +149 -0
  3. package/bin/trellis.js +3 -0
  4. package/dist/cli/index.d.ts +2 -0
  5. package/dist/cli/index.d.ts.map +1 -0
  6. package/dist/cli/index.js +42 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/commands/init.d.ts +11 -0
  9. package/dist/commands/init.d.ts.map +1 -0
  10. package/dist/commands/init.js +236 -0
  11. package/dist/commands/init.js.map +1 -0
  12. package/dist/configurators/claude.d.ts +35 -0
  13. package/dist/configurators/claude.d.ts.map +1 -0
  14. package/dist/configurators/claude.js +83 -0
  15. package/dist/configurators/claude.js.map +1 -0
  16. package/dist/configurators/cursor.d.ts +8 -0
  17. package/dist/configurators/cursor.d.ts.map +1 -0
  18. package/dist/configurators/cursor.js +22 -0
  19. package/dist/configurators/cursor.js.map +1 -0
  20. package/dist/configurators/templates.d.ts +40 -0
  21. package/dist/configurators/templates.d.ts.map +1 -0
  22. package/dist/configurators/templates.js +67 -0
  23. package/dist/configurators/templates.js.map +1 -0
  24. package/dist/configurators/workflow.d.ts +16 -0
  25. package/dist/configurators/workflow.d.ts.map +1 -0
  26. package/dist/configurators/workflow.js +169 -0
  27. package/dist/configurators/workflow.js.map +1 -0
  28. package/dist/constants/paths.d.ts +69 -0
  29. package/dist/constants/paths.d.ts.map +1 -0
  30. package/dist/constants/paths.js +80 -0
  31. package/dist/constants/paths.js.map +1 -0
  32. package/dist/index.d.ts +9 -0
  33. package/dist/index.d.ts.map +1 -0
  34. package/dist/index.js +9 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/templates/agents/check.txt +120 -0
  37. package/dist/templates/agents/debug.txt +121 -0
  38. package/dist/templates/agents/dispatch.txt +201 -0
  39. package/dist/templates/agents/implement.txt +114 -0
  40. package/dist/templates/agents/index.d.ts +35 -0
  41. package/dist/templates/agents/index.d.ts.map +1 -0
  42. package/dist/templates/agents/index.js +71 -0
  43. package/dist/templates/agents/index.js.map +1 -0
  44. package/dist/templates/agents/research.txt +258 -0
  45. package/dist/templates/commands/claude/start.md.txt +127 -0
  46. package/dist/templates/commands/common/before-backend-dev.txt +13 -0
  47. package/dist/templates/commands/common/before-frontend-dev.txt +13 -0
  48. package/dist/templates/commands/common/break-loop.txt +107 -0
  49. package/dist/templates/commands/common/check-backend.txt +13 -0
  50. package/dist/templates/commands/common/check-cross-layer.txt +153 -0
  51. package/dist/templates/commands/common/check-frontend.txt +13 -0
  52. package/dist/templates/commands/common/create-command.txt +154 -0
  53. package/dist/templates/commands/common/finish-work.txt +129 -0
  54. package/dist/templates/commands/common/integrate-skill.txt +219 -0
  55. package/dist/templates/commands/common/onboard-developer.txt +355 -0
  56. package/dist/templates/commands/common/record-agent-flow.txt +62 -0
  57. package/dist/templates/commands/cursor/start.md.txt +94 -0
  58. package/dist/templates/commands/index.d.ts +46 -0
  59. package/dist/templates/commands/index.d.ts.map +1 -0
  60. package/dist/templates/commands/index.js +151 -0
  61. package/dist/templates/commands/index.js.map +1 -0
  62. package/dist/templates/extract.d.ts +22 -0
  63. package/dist/templates/extract.d.ts.map +1 -0
  64. package/dist/templates/extract.js +34 -0
  65. package/dist/templates/extract.js.map +1 -0
  66. package/dist/templates/hooks/index.d.ts +33 -0
  67. package/dist/templates/hooks/index.d.ts.map +1 -0
  68. package/dist/templates/hooks/index.js +53 -0
  69. package/dist/templates/hooks/index.js.map +1 -0
  70. package/dist/templates/hooks/inject-subagent-context.py +620 -0
  71. package/dist/templates/hooks/settings.json +16 -0
  72. package/dist/templates/markdown/agent-traces-index.md.txt +124 -0
  73. package/dist/templates/markdown/agents.md.txt +18 -0
  74. package/dist/templates/markdown/gitignore.txt +3 -0
  75. package/dist/templates/markdown/index.d.ts +26 -0
  76. package/dist/templates/markdown/index.d.ts.map +1 -0
  77. package/dist/templates/markdown/index.js +33 -0
  78. package/dist/templates/markdown/index.js.map +1 -0
  79. package/dist/templates/markdown/init-agent.md.txt +315 -0
  80. package/dist/templates/markdown/structure/backend/database-guidelines.md.txt +51 -0
  81. package/dist/templates/markdown/structure/backend/directory-structure.md.txt +54 -0
  82. package/dist/templates/markdown/structure/backend/error-handling.md.txt +51 -0
  83. package/dist/templates/markdown/structure/backend/index.md.txt +38 -0
  84. package/dist/templates/markdown/structure/backend/logging-guidelines.md.txt +51 -0
  85. package/dist/templates/markdown/structure/backend/quality-guidelines.md.txt +51 -0
  86. package/dist/templates/markdown/structure/frontend/component-guidelines.md.txt +59 -0
  87. package/dist/templates/markdown/structure/frontend/directory-structure.md.txt +54 -0
  88. package/dist/templates/markdown/structure/frontend/hook-guidelines.md.txt +51 -0
  89. package/dist/templates/markdown/structure/frontend/index.md.txt +39 -0
  90. package/dist/templates/markdown/structure/frontend/quality-guidelines.md.txt +51 -0
  91. package/dist/templates/markdown/structure/frontend/state-management.md.txt +51 -0
  92. package/dist/templates/markdown/structure/frontend/type-safety.md.txt +51 -0
  93. package/dist/templates/markdown/structure/guides/code-reuse-thinking-guide.md.txt +92 -0
  94. package/dist/templates/markdown/structure/guides/cross-layer-thinking-guide.md.txt +94 -0
  95. package/dist/templates/markdown/structure/guides/index.md.txt +79 -0
  96. package/dist/templates/markdown/workflow.md.txt +335 -0
  97. package/dist/templates/scripts/add-session.sh.txt +384 -0
  98. package/dist/templates/scripts/common/developer.sh.txt +130 -0
  99. package/dist/templates/scripts/common/git-context.sh.txt +237 -0
  100. package/dist/templates/scripts/common/paths.sh.txt +201 -0
  101. package/dist/templates/scripts/create-bootstrap.sh.txt +298 -0
  102. package/dist/templates/scripts/feature.sh.txt +700 -0
  103. package/dist/templates/scripts/get-context.sh.txt +7 -0
  104. package/dist/templates/scripts/get-developer.sh.txt +15 -0
  105. package/dist/templates/scripts/index.d.ts +25 -0
  106. package/dist/templates/scripts/index.d.ts.map +1 -0
  107. package/dist/templates/scripts/index.js +28 -0
  108. package/dist/templates/scripts/index.js.map +1 -0
  109. package/dist/templates/scripts/init-developer.sh.txt +34 -0
  110. package/dist/types/ai-tools.d.ts +35 -0
  111. package/dist/types/ai-tools.d.ts.map +1 -0
  112. package/dist/types/ai-tools.js +31 -0
  113. package/dist/types/ai-tools.js.map +1 -0
  114. package/dist/utils/file-writer.d.ts +23 -0
  115. package/dist/utils/file-writer.d.ts.map +1 -0
  116. package/dist/utils/file-writer.js +140 -0
  117. package/dist/utils/file-writer.js.map +1 -0
  118. package/dist/utils/project-detector.d.ts +16 -0
  119. package/dist/utils/project-detector.d.ts.map +1 -0
  120. package/dist/utils/project-detector.js +186 -0
  121. package/dist/utils/project-detector.js.map +1 -0
  122. 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
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ # Get Session Context for AI Agent
3
+ #
4
+ # This is a wrapper that calls the actual implementation in common/git-context.sh
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ exec "$SCRIPT_DIR/common/git-context.sh" "$@"