@jahanxu/trellis 0.4.2 → 0.5.1
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/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +58 -1
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/constants/paths.d.ts +17 -0
- package/dist/constants/paths.d.ts.map +1 -1
- package/dist/constants/paths.js +19 -0
- package/dist/constants/paths.js.map +1 -1
- package/dist/templates/claude/commands/trellis/handoff.md +90 -387
- package/dist/templates/claude/commands/trellis/pick-task.md +74 -444
- package/dist/templates/claude/commands/trellis/update-spec.md +19 -3
- package/dist/templates/claude/hooks/inject-subagent-context.py +17 -101
- package/dist/templates/claude/hooks/ralph-loop.py +1 -0
- package/dist/templates/claude/hooks/session-start.py +170 -54
- package/dist/templates/iflow/commands/trellis/handoff.md +148 -0
- package/dist/templates/iflow/commands/trellis/pick-task.md +145 -0
- package/dist/templates/iflow/commands/trellis/update-spec.md +19 -3
- package/dist/templates/iflow/hooks/inject-subagent-context.py +1 -0
- package/dist/templates/iflow/hooks/ralph-loop.py +1 -0
- package/dist/templates/iflow/hooks/session-start.py +171 -0
- package/dist/templates/markdown/index.d.ts +9 -0
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +10 -0
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/spec/roles/designer/index.md.txt +57 -0
- package/dist/templates/markdown/spec/roles/designer/mock-data-standards.md.txt +63 -0
- package/dist/templates/markdown/spec/roles/designer/prototype-guidelines.md.txt +49 -0
- package/dist/templates/markdown/spec/roles/frontend-impl/api-integration.md.txt +63 -0
- package/dist/templates/markdown/spec/roles/frontend-impl/index.md.txt +57 -0
- package/dist/templates/markdown/spec/roles/frontend-impl/prototype-to-production.md.txt +57 -0
- package/dist/templates/markdown/spec/roles/pm/index.md.txt +45 -0
- package/dist/templates/markdown/spec/roles/pm/prd-template.md.txt +64 -0
- package/dist/templates/markdown/spec/roles/pm/requirement-checklist.md.txt +43 -0
- package/dist/templates/trellis/index.d.ts +1 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +2 -0
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/add_session.py +3 -2
- package/dist/templates/trellis/scripts/common/cli_adapter.py +4 -4
- package/dist/templates/trellis/scripts/common/developer.py +4 -4
- package/dist/templates/trellis/scripts/common/git_context.py +7 -7
- package/dist/templates/trellis/scripts/common/paths.py +64 -14
- package/dist/templates/trellis/scripts/common/phase.py +2 -2
- package/dist/templates/trellis/scripts/common/registry.py +16 -16
- package/dist/templates/trellis/scripts/common/task_queue.py +10 -10
- package/dist/templates/trellis/scripts/common/task_utils.py +5 -5
- package/dist/templates/trellis/scripts/common/worktree.py +8 -8
- package/dist/templates/trellis/scripts/pool.py +214 -266
- package/dist/templates/trellis/scripts/task.py +3 -116
- package/package.json +3 -3
- package/dist/templates/claude/commands/trellis/before-role-work.md +0 -364
- package/dist/templates/trellis/VERSION +0 -1
- package/dist/templates/trellis/deliverables/README.md +0 -51
- package/dist/templates/trellis/paths.README.md +0 -277
- package/dist/templates/trellis/paths.yaml +0 -41
- package/dist/templates/trellis/pool/implementations.json +0 -5
- package/dist/templates/trellis/pool/prototypes.json +0 -5
- package/dist/templates/trellis/pool/requirements.json +0 -5
- package/dist/templates/trellis/scripts/common/project_paths.py +0 -189
- package/dist/templates/trellis/scripts/handoff_generator.py +0 -380
- package/dist/templates/trellis/spec/roles/designer/index.md +0 -243
- package/dist/templates/trellis/spec/roles/designer/mock-data-standards.md +0 -481
- package/dist/templates/trellis/spec/roles/designer/prototype-guidelines.md +0 -429
- package/dist/templates/trellis/spec/roles/frontend-impl/api-integration.md +0 -565
- package/dist/templates/trellis/spec/roles/frontend-impl/index.md +0 -321
- package/dist/templates/trellis/spec/roles/frontend-impl/state-management.md +0 -599
- package/dist/templates/trellis/spec/roles/pm/index.md +0 -112
- package/dist/templates/trellis/spec/roles/pm/prd-template.md +0 -124
|
@@ -10,10 +10,11 @@ Provides:
|
|
|
10
10
|
get_active_journal_file - Get current journal file
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
13
15
|
import re
|
|
14
16
|
from datetime import datetime
|
|
15
17
|
from pathlib import Path
|
|
16
|
-
from typing import Optional
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
# =============================================================================
|
|
@@ -27,19 +28,23 @@ DIR_TASKS = "tasks"
|
|
|
27
28
|
DIR_ARCHIVE = "archive"
|
|
28
29
|
DIR_SPEC = "spec"
|
|
29
30
|
DIR_SCRIPTS = "scripts"
|
|
31
|
+
DIR_POOL = "pool"
|
|
32
|
+
DIR_DELIVERABLES = "deliverables"
|
|
30
33
|
|
|
31
34
|
# File names
|
|
32
35
|
FILE_DEVELOPER = ".developer"
|
|
33
36
|
FILE_CURRENT_TASK = ".current-task"
|
|
34
37
|
FILE_TASK_JSON = "task.json"
|
|
35
38
|
FILE_JOURNAL_PREFIX = "journal-"
|
|
39
|
+
FILE_SOURCE_JSON = "source.json"
|
|
40
|
+
FILE_HANDOFF_MD = "HANDOFF.md"
|
|
36
41
|
|
|
37
42
|
|
|
38
43
|
# =============================================================================
|
|
39
44
|
# Repository Root
|
|
40
45
|
# =============================================================================
|
|
41
46
|
|
|
42
|
-
def get_repo_root(start_path:
|
|
47
|
+
def get_repo_root(start_path: Path | None = None) -> Path:
|
|
43
48
|
"""Find the nearest directory containing .trellis/ folder.
|
|
44
49
|
|
|
45
50
|
This handles nested git repos correctly (e.g., test project inside another repo).
|
|
@@ -65,7 +70,7 @@ def get_repo_root(start_path: Optional[Path] = None) -> Path:
|
|
|
65
70
|
# Developer
|
|
66
71
|
# =============================================================================
|
|
67
72
|
|
|
68
|
-
def get_developer(repo_root:
|
|
73
|
+
def get_developer(repo_root: Path | None = None) -> str | None:
|
|
69
74
|
"""Get developer name from .developer file.
|
|
70
75
|
|
|
71
76
|
Args:
|
|
@@ -93,7 +98,7 @@ def get_developer(repo_root: Optional[Path] = None) -> Optional[str]:
|
|
|
93
98
|
return None
|
|
94
99
|
|
|
95
100
|
|
|
96
|
-
def check_developer(repo_root:
|
|
101
|
+
def check_developer(repo_root: Path | None = None) -> bool:
|
|
97
102
|
"""Check if developer is initialized.
|
|
98
103
|
|
|
99
104
|
Args:
|
|
@@ -109,7 +114,7 @@ def check_developer(repo_root: Optional[Path] = None) -> bool:
|
|
|
109
114
|
# Tasks Directory
|
|
110
115
|
# =============================================================================
|
|
111
116
|
|
|
112
|
-
def get_tasks_dir(repo_root:
|
|
117
|
+
def get_tasks_dir(repo_root: Path | None = None) -> Path:
|
|
113
118
|
"""Get tasks directory path.
|
|
114
119
|
|
|
115
120
|
Args:
|
|
@@ -127,7 +132,7 @@ def get_tasks_dir(repo_root: Optional[Path] = None) -> Path:
|
|
|
127
132
|
# Workspace Directory
|
|
128
133
|
# =============================================================================
|
|
129
134
|
|
|
130
|
-
def get_workspace_dir(repo_root:
|
|
135
|
+
def get_workspace_dir(repo_root: Path | None = None) -> Path | None:
|
|
131
136
|
"""Get developer workspace directory.
|
|
132
137
|
|
|
133
138
|
Args:
|
|
@@ -149,7 +154,7 @@ def get_workspace_dir(repo_root: Optional[Path] = None) -> Optional[Path]:
|
|
|
149
154
|
# Journal File
|
|
150
155
|
# =============================================================================
|
|
151
156
|
|
|
152
|
-
def get_active_journal_file(repo_root:
|
|
157
|
+
def get_active_journal_file(repo_root: Path | None = None) -> Path | None:
|
|
153
158
|
"""Get the current active journal file.
|
|
154
159
|
|
|
155
160
|
Args:
|
|
@@ -165,7 +170,7 @@ def get_active_journal_file(repo_root: Optional[Path] = None) -> Optional[Path]:
|
|
|
165
170
|
if workspace_dir is None or not workspace_dir.is_dir():
|
|
166
171
|
return None
|
|
167
172
|
|
|
168
|
-
latest:
|
|
173
|
+
latest: Path | None = None
|
|
169
174
|
highest = 0
|
|
170
175
|
|
|
171
176
|
for f in workspace_dir.glob(f"{FILE_JOURNAL_PREFIX}*.md"):
|
|
@@ -206,7 +211,7 @@ def count_lines(file_path: Path) -> int:
|
|
|
206
211
|
# Current Task Management
|
|
207
212
|
# =============================================================================
|
|
208
213
|
|
|
209
|
-
def _get_current_task_file(repo_root:
|
|
214
|
+
def _get_current_task_file(repo_root: Path | None = None) -> Path:
|
|
210
215
|
"""Get .current-task file path.
|
|
211
216
|
|
|
212
217
|
Args:
|
|
@@ -220,7 +225,7 @@ def _get_current_task_file(repo_root: Optional[Path] = None) -> Path:
|
|
|
220
225
|
return repo_root / DIR_WORKFLOW / FILE_CURRENT_TASK
|
|
221
226
|
|
|
222
227
|
|
|
223
|
-
def get_current_task(repo_root:
|
|
228
|
+
def get_current_task(repo_root: Path | None = None) -> str | None:
|
|
224
229
|
"""Get current task directory path (relative to repo_root).
|
|
225
230
|
|
|
226
231
|
Args:
|
|
@@ -240,7 +245,7 @@ def get_current_task(repo_root: Optional[Path] = None) -> Optional[str]:
|
|
|
240
245
|
return None
|
|
241
246
|
|
|
242
247
|
|
|
243
|
-
def get_current_task_abs(repo_root:
|
|
248
|
+
def get_current_task_abs(repo_root: Path | None = None) -> Path | None:
|
|
244
249
|
"""Get current task directory absolute path.
|
|
245
250
|
|
|
246
251
|
Args:
|
|
@@ -258,7 +263,7 @@ def get_current_task_abs(repo_root: Optional[Path] = None) -> Optional[Path]:
|
|
|
258
263
|
return None
|
|
259
264
|
|
|
260
265
|
|
|
261
|
-
def set_current_task(task_path: str, repo_root:
|
|
266
|
+
def set_current_task(task_path: str, repo_root: Path | None = None) -> bool:
|
|
262
267
|
"""Set current task.
|
|
263
268
|
|
|
264
269
|
Args:
|
|
@@ -288,7 +293,7 @@ def set_current_task(task_path: str, repo_root: Optional[Path] = None) -> bool:
|
|
|
288
293
|
return False
|
|
289
294
|
|
|
290
295
|
|
|
291
|
-
def clear_current_task(repo_root:
|
|
296
|
+
def clear_current_task(repo_root: Path | None = None) -> bool:
|
|
292
297
|
"""Clear current task.
|
|
293
298
|
|
|
294
299
|
Args:
|
|
@@ -307,7 +312,7 @@ def clear_current_task(repo_root: Optional[Path] = None) -> bool:
|
|
|
307
312
|
return False
|
|
308
313
|
|
|
309
314
|
|
|
310
|
-
def has_current_task(repo_root:
|
|
315
|
+
def has_current_task(repo_root: Path | None = None) -> bool:
|
|
311
316
|
"""Check if has current task.
|
|
312
317
|
|
|
313
318
|
Args:
|
|
@@ -319,6 +324,51 @@ def has_current_task(repo_root: Optional[Path] = None) -> bool:
|
|
|
319
324
|
return get_current_task(repo_root) is not None
|
|
320
325
|
|
|
321
326
|
|
|
327
|
+
# =============================================================================
|
|
328
|
+
# Pool Directory
|
|
329
|
+
# =============================================================================
|
|
330
|
+
|
|
331
|
+
def get_pool_dir(repo_root: Path | None = None) -> Path:
|
|
332
|
+
"""Get pool directory path.
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
repo_root: Repository root path. Defaults to auto-detected.
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
Path to pool directory.
|
|
339
|
+
"""
|
|
340
|
+
if repo_root is None:
|
|
341
|
+
repo_root = get_repo_root()
|
|
342
|
+
return repo_root / DIR_WORKFLOW / DIR_POOL
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def get_pool_file(pool_name: str, repo_root: Path | None = None) -> Path:
|
|
346
|
+
"""Get pool JSON file path.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
pool_name: Pool name (e.g., 'requirements').
|
|
350
|
+
repo_root: Repository root path. Defaults to auto-detected.
|
|
351
|
+
|
|
352
|
+
Returns:
|
|
353
|
+
Path to pool JSON file.
|
|
354
|
+
"""
|
|
355
|
+
return get_pool_dir(repo_root) / f"{pool_name}.json"
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def get_deliverables_dir(repo_root: Path | None = None) -> Path:
|
|
359
|
+
"""Get deliverables directory path (at project root).
|
|
360
|
+
|
|
361
|
+
Args:
|
|
362
|
+
repo_root: Repository root path. Defaults to auto-detected.
|
|
363
|
+
|
|
364
|
+
Returns:
|
|
365
|
+
Path to deliverables directory.
|
|
366
|
+
"""
|
|
367
|
+
if repo_root is None:
|
|
368
|
+
repo_root = get_repo_root()
|
|
369
|
+
return repo_root / DIR_DELIVERABLES
|
|
370
|
+
|
|
371
|
+
|
|
322
372
|
# =============================================================================
|
|
323
373
|
# Task ID Generation
|
|
324
374
|
# =============================================================================
|
|
@@ -17,13 +17,13 @@ Provides:
|
|
|
17
17
|
is_current_action - Check if at specific action
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
|
+
from __future__ import annotations
|
|
20
21
|
|
|
21
22
|
import json
|
|
22
23
|
from pathlib import Path
|
|
23
|
-
from typing import Optional
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
def _read_json_file(path: Path) ->
|
|
26
|
+
def _read_json_file(path: Path) -> dict | None:
|
|
27
27
|
"""Read and parse a JSON file."""
|
|
28
28
|
try:
|
|
29
29
|
return json.loads(path.read_text(encoding="utf-8"))
|
|
@@ -14,17 +14,17 @@ Provides:
|
|
|
14
14
|
registry_list_agents - List all agents
|
|
15
15
|
"""
|
|
16
16
|
|
|
17
|
+
from __future__ import annotations
|
|
17
18
|
|
|
18
19
|
import json
|
|
19
20
|
from datetime import datetime
|
|
20
21
|
from pathlib import Path
|
|
21
|
-
from typing import Optional
|
|
22
22
|
|
|
23
23
|
from .paths import get_repo_root
|
|
24
24
|
from .worktree import get_agents_dir
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
def _read_json_file(path: Path) ->
|
|
27
|
+
def _read_json_file(path: Path) -> dict | None:
|
|
28
28
|
"""Read and parse a JSON file."""
|
|
29
29
|
try:
|
|
30
30
|
return json.loads(path.read_text(encoding="utf-8"))
|
|
@@ -45,7 +45,7 @@ def _write_json_file(path: Path, data: dict) -> bool:
|
|
|
45
45
|
# Registry File Access
|
|
46
46
|
# =============================================================================
|
|
47
47
|
|
|
48
|
-
def registry_get_file(repo_root:
|
|
48
|
+
def registry_get_file(repo_root: Path | None = None) -> Path | None:
|
|
49
49
|
"""Get registry file path.
|
|
50
50
|
|
|
51
51
|
Args:
|
|
@@ -63,7 +63,7 @@ def registry_get_file(repo_root: Optional[Path] = None) -> Optional[Path]:
|
|
|
63
63
|
return None
|
|
64
64
|
|
|
65
65
|
|
|
66
|
-
def _ensure_registry(repo_root:
|
|
66
|
+
def _ensure_registry(repo_root: Path | None = None) -> Path | None:
|
|
67
67
|
"""Ensure registry file exists with valid structure.
|
|
68
68
|
|
|
69
69
|
Args:
|
|
@@ -98,8 +98,8 @@ def _ensure_registry(repo_root: Optional[Path] = None) -> Optional[Path]:
|
|
|
98
98
|
|
|
99
99
|
def registry_get_agent_by_id(
|
|
100
100
|
agent_id: str,
|
|
101
|
-
repo_root:
|
|
102
|
-
) ->
|
|
101
|
+
repo_root: Path | None = None
|
|
102
|
+
) -> dict | None:
|
|
103
103
|
"""Get agent by ID.
|
|
104
104
|
|
|
105
105
|
Args:
|
|
@@ -129,8 +129,8 @@ def registry_get_agent_by_id(
|
|
|
129
129
|
|
|
130
130
|
def registry_get_agent_by_worktree(
|
|
131
131
|
worktree_path: str,
|
|
132
|
-
repo_root:
|
|
133
|
-
) ->
|
|
132
|
+
repo_root: Path | None = None
|
|
133
|
+
) -> dict | None:
|
|
134
134
|
"""Get agent by worktree path.
|
|
135
135
|
|
|
136
136
|
Args:
|
|
@@ -160,8 +160,8 @@ def registry_get_agent_by_worktree(
|
|
|
160
160
|
|
|
161
161
|
def registry_search_agent(
|
|
162
162
|
search: str,
|
|
163
|
-
repo_root:
|
|
164
|
-
) ->
|
|
163
|
+
repo_root: Path | None = None
|
|
164
|
+
) -> dict | None:
|
|
165
165
|
"""Search agent by ID or task_dir containing search term.
|
|
166
166
|
|
|
167
167
|
Args:
|
|
@@ -196,8 +196,8 @@ def registry_search_agent(
|
|
|
196
196
|
|
|
197
197
|
def registry_get_task_dir(
|
|
198
198
|
worktree_path: str,
|
|
199
|
-
repo_root:
|
|
200
|
-
) ->
|
|
199
|
+
repo_root: Path | None = None
|
|
200
|
+
) -> str | None:
|
|
201
201
|
"""Get task directory for a worktree.
|
|
202
202
|
|
|
203
203
|
Args:
|
|
@@ -217,7 +217,7 @@ def registry_get_task_dir(
|
|
|
217
217
|
# Agent Modification
|
|
218
218
|
# =============================================================================
|
|
219
219
|
|
|
220
|
-
def registry_remove_by_id(agent_id: str, repo_root:
|
|
220
|
+
def registry_remove_by_id(agent_id: str, repo_root: Path | None = None) -> bool:
|
|
221
221
|
"""Remove agent by ID.
|
|
222
222
|
|
|
223
223
|
Args:
|
|
@@ -246,7 +246,7 @@ def registry_remove_by_id(agent_id: str, repo_root: Optional[Path] = None) -> bo
|
|
|
246
246
|
|
|
247
247
|
def registry_remove_by_worktree(
|
|
248
248
|
worktree_path: str,
|
|
249
|
-
repo_root:
|
|
249
|
+
repo_root: Path | None = None
|
|
250
250
|
) -> bool:
|
|
251
251
|
"""Remove agent by worktree path.
|
|
252
252
|
|
|
@@ -279,7 +279,7 @@ def registry_add_agent(
|
|
|
279
279
|
worktree_path: str,
|
|
280
280
|
pid: int,
|
|
281
281
|
task_dir: str,
|
|
282
|
-
repo_root:
|
|
282
|
+
repo_root: Path | None = None,
|
|
283
283
|
platform: str = "claude",
|
|
284
284
|
) -> bool:
|
|
285
285
|
"""Add agent to registry (replaces if same ID exists).
|
|
@@ -327,7 +327,7 @@ def registry_add_agent(
|
|
|
327
327
|
return _write_json_file(registry_file, data)
|
|
328
328
|
|
|
329
329
|
|
|
330
|
-
def registry_list_agents(repo_root:
|
|
330
|
+
def registry_list_agents(repo_root: Path | None = None) -> list[dict]:
|
|
331
331
|
"""List all agents.
|
|
332
332
|
|
|
333
333
|
Args:
|
|
@@ -10,10 +10,10 @@ Provides:
|
|
|
10
10
|
get_task_stats - Get P0/P1/P2/P3 counts
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
+
from __future__ import annotations
|
|
13
14
|
|
|
14
15
|
import json
|
|
15
16
|
from pathlib import Path
|
|
16
|
-
from typing import Optional, List
|
|
17
17
|
|
|
18
18
|
from .paths import (
|
|
19
19
|
FILE_TASK_JSON,
|
|
@@ -23,7 +23,7 @@ from .paths import (
|
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
|
|
26
|
-
def _read_json_file(path: Path) ->
|
|
26
|
+
def _read_json_file(path: Path) -> dict | None:
|
|
27
27
|
"""Read and parse a JSON file."""
|
|
28
28
|
try:
|
|
29
29
|
return json.loads(path.read_text(encoding="utf-8"))
|
|
@@ -36,8 +36,8 @@ def _read_json_file(path: Path) -> Optional[dict]:
|
|
|
36
36
|
# =============================================================================
|
|
37
37
|
|
|
38
38
|
def list_tasks_by_status(
|
|
39
|
-
filter_status:
|
|
40
|
-
repo_root:
|
|
39
|
+
filter_status: str | None = None,
|
|
40
|
+
repo_root: Path | None = None
|
|
41
41
|
) -> list[dict]:
|
|
42
42
|
"""List tasks by status.
|
|
43
43
|
|
|
@@ -91,7 +91,7 @@ def list_tasks_by_status(
|
|
|
91
91
|
return results
|
|
92
92
|
|
|
93
93
|
|
|
94
|
-
def list_pending_tasks(repo_root:
|
|
94
|
+
def list_pending_tasks(repo_root: Path | None = None) -> list[dict]:
|
|
95
95
|
"""List pending tasks.
|
|
96
96
|
|
|
97
97
|
Args:
|
|
@@ -105,8 +105,8 @@ def list_pending_tasks(repo_root: Optional[Path] = None) -> list[dict]:
|
|
|
105
105
|
|
|
106
106
|
def list_tasks_by_assignee(
|
|
107
107
|
assignee: str,
|
|
108
|
-
filter_status:
|
|
109
|
-
repo_root:
|
|
108
|
+
filter_status: str | None = None,
|
|
109
|
+
repo_root: Path | None = None
|
|
110
110
|
) -> list[dict]:
|
|
111
111
|
"""List tasks assigned to a specific developer.
|
|
112
112
|
|
|
@@ -167,8 +167,8 @@ def list_tasks_by_assignee(
|
|
|
167
167
|
|
|
168
168
|
|
|
169
169
|
def list_my_tasks(
|
|
170
|
-
filter_status:
|
|
171
|
-
repo_root:
|
|
170
|
+
filter_status: str | None = None,
|
|
171
|
+
repo_root: Path | None = None
|
|
172
172
|
) -> list[dict]:
|
|
173
173
|
"""List tasks assigned to current developer.
|
|
174
174
|
|
|
@@ -192,7 +192,7 @@ def list_my_tasks(
|
|
|
192
192
|
return list_tasks_by_assignee(developer, filter_status, repo_root)
|
|
193
193
|
|
|
194
194
|
|
|
195
|
-
def get_task_stats(repo_root:
|
|
195
|
+
def get_task_stats(repo_root: Path | None = None) -> dict[str, int]:
|
|
196
196
|
"""Get task statistics.
|
|
197
197
|
|
|
198
198
|
Args:
|
|
@@ -8,12 +8,12 @@ Provides:
|
|
|
8
8
|
archive_task_dir - Archive task to monthly directory
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
from __future__ import annotations
|
|
11
12
|
|
|
12
13
|
import shutil
|
|
13
14
|
import sys
|
|
14
15
|
from datetime import datetime
|
|
15
16
|
from pathlib import Path
|
|
16
|
-
from typing import Optional
|
|
17
17
|
|
|
18
18
|
from .paths import get_repo_root
|
|
19
19
|
|
|
@@ -22,7 +22,7 @@ from .paths import get_repo_root
|
|
|
22
22
|
# Path Safety
|
|
23
23
|
# =============================================================================
|
|
24
24
|
|
|
25
|
-
def is_safe_task_path(task_path: str, repo_root:
|
|
25
|
+
def is_safe_task_path(task_path: str, repo_root: Path | None = None) -> bool:
|
|
26
26
|
"""Check if a relative task path is safe to operate on.
|
|
27
27
|
|
|
28
28
|
Args:
|
|
@@ -69,7 +69,7 @@ def is_safe_task_path(task_path: str, repo_root: Optional[Path] = None) -> bool:
|
|
|
69
69
|
# Task Lookup
|
|
70
70
|
# =============================================================================
|
|
71
71
|
|
|
72
|
-
def find_task_by_name(task_name: str, tasks_dir: Path) ->
|
|
72
|
+
def find_task_by_name(task_name: str, tasks_dir: Path) -> Path | None:
|
|
73
73
|
"""Find task directory by name (exact or suffix match).
|
|
74
74
|
|
|
75
75
|
Args:
|
|
@@ -99,7 +99,7 @@ def find_task_by_name(task_name: str, tasks_dir: Path) -> Optional[Path]:
|
|
|
99
99
|
# Archive Operations
|
|
100
100
|
# =============================================================================
|
|
101
101
|
|
|
102
|
-
def archive_task_dir(task_dir_abs: Path, repo_root:
|
|
102
|
+
def archive_task_dir(task_dir_abs: Path, repo_root: Path | None = None) -> Path | None:
|
|
103
103
|
"""Archive a task directory to archive/{YYYY-MM}/.
|
|
104
104
|
|
|
105
105
|
Args:
|
|
@@ -141,7 +141,7 @@ def archive_task_dir(task_dir_abs: Path, repo_root: Optional[Path] = None) -> Op
|
|
|
141
141
|
|
|
142
142
|
def archive_task_complete(
|
|
143
143
|
task_dir_abs: Path,
|
|
144
|
-
repo_root:
|
|
144
|
+
repo_root: Path | None = None
|
|
145
145
|
) -> dict[str, str]:
|
|
146
146
|
"""Complete archive workflow: archive directory.
|
|
147
147
|
|
|
@@ -10,9 +10,9 @@ Provides:
|
|
|
10
10
|
get_agents_dir - Get agents registry directory
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
+
from __future__ import annotations
|
|
13
14
|
|
|
14
15
|
from pathlib import Path
|
|
15
|
-
from typing import Optional
|
|
16
16
|
|
|
17
17
|
from .paths import (
|
|
18
18
|
DIR_WORKFLOW,
|
|
@@ -35,7 +35,7 @@ def parse_simple_yaml(content: str) -> dict:
|
|
|
35
35
|
Parsed dict.
|
|
36
36
|
"""
|
|
37
37
|
result: dict = {}
|
|
38
|
-
current_list:
|
|
38
|
+
current_list: list | None = None
|
|
39
39
|
|
|
40
40
|
for line in content.splitlines():
|
|
41
41
|
stripped = line.strip()
|
|
@@ -61,7 +61,7 @@ def parse_simple_yaml(content: str) -> dict:
|
|
|
61
61
|
return result
|
|
62
62
|
|
|
63
63
|
|
|
64
|
-
def _yaml_get_value(config_file: Path, key: str) ->
|
|
64
|
+
def _yaml_get_value(config_file: Path, key: str) -> str | None:
|
|
65
65
|
"""Read simple value from worktree.yaml.
|
|
66
66
|
|
|
67
67
|
Args:
|
|
@@ -111,7 +111,7 @@ def _yaml_get_list(config_file: Path, section: str) -> list[str]:
|
|
|
111
111
|
WORKTREE_CONFIG_PATH = f"{DIR_WORKFLOW}/worktree.yaml"
|
|
112
112
|
|
|
113
113
|
|
|
114
|
-
def get_worktree_config(repo_root:
|
|
114
|
+
def get_worktree_config(repo_root: Path | None = None) -> Path:
|
|
115
115
|
"""Get worktree.yaml config file path.
|
|
116
116
|
|
|
117
117
|
Args:
|
|
@@ -125,7 +125,7 @@ def get_worktree_config(repo_root: Optional[Path] = None) -> Path:
|
|
|
125
125
|
return repo_root / WORKTREE_CONFIG_PATH
|
|
126
126
|
|
|
127
127
|
|
|
128
|
-
def get_worktree_base_dir(repo_root:
|
|
128
|
+
def get_worktree_base_dir(repo_root: Path | None = None) -> Path:
|
|
129
129
|
"""Get worktree base directory.
|
|
130
130
|
|
|
131
131
|
Args:
|
|
@@ -153,7 +153,7 @@ def get_worktree_base_dir(repo_root: Optional[Path] = None) -> Path:
|
|
|
153
153
|
return Path(worktree_dir)
|
|
154
154
|
|
|
155
155
|
|
|
156
|
-
def get_worktree_copy_files(repo_root:
|
|
156
|
+
def get_worktree_copy_files(repo_root: Path | None = None) -> list[str]:
|
|
157
157
|
"""Get files to copy list.
|
|
158
158
|
|
|
159
159
|
Args:
|
|
@@ -168,7 +168,7 @@ def get_worktree_copy_files(repo_root: Optional[Path] = None) -> list[str]:
|
|
|
168
168
|
return _yaml_get_list(config, "copy")
|
|
169
169
|
|
|
170
170
|
|
|
171
|
-
def get_worktree_post_create_hooks(repo_root:
|
|
171
|
+
def get_worktree_post_create_hooks(repo_root: Path | None = None) -> list[str]:
|
|
172
172
|
"""Get post_create hooks.
|
|
173
173
|
|
|
174
174
|
Args:
|
|
@@ -187,7 +187,7 @@ def get_worktree_post_create_hooks(repo_root: Optional[Path] = None) -> list[str
|
|
|
187
187
|
# Agents Registry
|
|
188
188
|
# =============================================================================
|
|
189
189
|
|
|
190
|
-
def get_agents_dir(repo_root:
|
|
190
|
+
def get_agents_dir(repo_root: Path | None = None) -> Path | None:
|
|
191
191
|
"""Get agents directory for current developer.
|
|
192
192
|
|
|
193
193
|
Args:
|