@mindfoldhq/trellis 0.3.10-beta.0 → 0.3.10
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/cli/index.js +0 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +0 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +31 -203
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +6 -154
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/workflow.d.ts +2 -6
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +58 -88
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/migrations/index.d.ts +0 -1
- package/dist/migrations/index.d.ts.map +1 -1
- package/dist/migrations/index.js +0 -2
- package/dist/migrations/index.js.map +1 -1
- package/dist/migrations/manifests/0.3.10.json +9 -0
- package/dist/templates/claude/agents/dispatch.md +2 -1
- package/dist/templates/claude/agents/implement.md +3 -2
- package/dist/templates/claude/commands/trellis/before-backend-dev.md +13 -0
- package/dist/templates/claude/commands/trellis/before-frontend-dev.md +13 -0
- package/dist/templates/claude/commands/trellis/check-backend.md +13 -0
- package/dist/templates/claude/commands/trellis/check-frontend.md +13 -0
- package/dist/templates/claude/commands/trellis/create-command.md +2 -2
- package/dist/templates/claude/commands/trellis/onboard.md +13 -13
- package/dist/templates/claude/commands/trellis/parallel.md +2 -1
- package/dist/templates/claude/commands/trellis/record-session.md +2 -2
- package/dist/templates/claude/commands/trellis/start.md +4 -8
- package/dist/templates/claude/hooks/inject-subagent-context.py +13 -21
- package/dist/templates/claude/hooks/session-start.py +2 -170
- package/dist/templates/codex/skills/before-backend-dev/SKILL.md +18 -0
- package/dist/templates/codex/skills/before-frontend-dev/SKILL.md +18 -0
- package/dist/templates/codex/skills/check-backend/SKILL.md +18 -0
- package/dist/templates/codex/skills/check-frontend/SKILL.md +18 -0
- package/dist/templates/codex/skills/create-command/SKILL.md +2 -2
- package/dist/templates/codex/skills/onboard/SKILL.md +11 -11
- package/dist/templates/codex/skills/record-session/SKILL.md +2 -2
- package/dist/templates/codex/skills/start/SKILL.md +3 -8
- package/dist/templates/cursor/commands/trellis-before-backend-dev.md +13 -0
- package/dist/templates/cursor/commands/trellis-before-frontend-dev.md +13 -0
- package/dist/templates/cursor/commands/trellis-check-backend.md +13 -0
- package/dist/templates/cursor/commands/trellis-check-frontend.md +13 -0
- package/dist/templates/cursor/commands/trellis-create-command.md +2 -2
- package/dist/templates/cursor/commands/trellis-onboard.md +13 -13
- package/dist/templates/cursor/commands/trellis-record-session.md +2 -2
- package/dist/templates/cursor/commands/trellis-start.md +16 -7
- package/dist/templates/gemini/commands/trellis/before-backend-dev.toml +17 -0
- package/dist/templates/gemini/commands/trellis/before-frontend-dev.toml +17 -0
- package/dist/templates/gemini/commands/trellis/check-backend.toml +17 -0
- package/dist/templates/gemini/commands/trellis/check-frontend.toml +17 -0
- package/dist/templates/gemini/commands/trellis/create-command.toml +2 -2
- package/dist/templates/gemini/commands/trellis/onboard.toml +2 -2
- package/dist/templates/gemini/commands/trellis/record-session.toml +2 -2
- package/dist/templates/gemini/commands/trellis/start.toml +4 -9
- package/dist/templates/iflow/agents/dispatch.md +2 -1
- package/dist/templates/iflow/agents/implement.md +3 -2
- package/dist/templates/iflow/commands/trellis/before-backend-dev.md +13 -0
- package/dist/templates/iflow/commands/trellis/before-frontend-dev.md +13 -0
- package/dist/templates/iflow/commands/trellis/check-backend.md +13 -0
- package/dist/templates/iflow/commands/trellis/check-frontend.md +13 -0
- package/dist/templates/iflow/commands/trellis/create-command.md +2 -2
- package/dist/templates/iflow/commands/trellis/onboard.md +13 -13
- package/dist/templates/iflow/commands/trellis/parallel.md +2 -1
- package/dist/templates/iflow/commands/trellis/record-session.md +2 -2
- package/dist/templates/iflow/commands/trellis/start.md +4 -8
- package/dist/templates/iflow/hooks/inject-subagent-context.py +13 -21
- package/dist/templates/iflow/hooks/session-start.py +1 -156
- package/dist/templates/kilo/workflows/before-backend-dev.md +13 -0
- package/dist/templates/kilo/workflows/before-frontend-dev.md +13 -0
- package/dist/templates/kilo/workflows/check-backend.md +13 -0
- package/dist/templates/kilo/workflows/check-frontend.md +13 -0
- package/dist/templates/kilo/workflows/create-command.md +2 -2
- package/dist/templates/kilo/workflows/onboard.md +13 -13
- package/dist/templates/kilo/workflows/parallel.md +2 -1
- package/dist/templates/kilo/workflows/record-session.md +2 -2
- package/dist/templates/kilo/workflows/start.md +3 -8
- package/dist/templates/kiro/skills/before-backend-dev/SKILL.md +18 -0
- package/dist/templates/kiro/skills/before-frontend-dev/SKILL.md +18 -0
- package/dist/templates/kiro/skills/check-backend/SKILL.md +18 -0
- package/dist/templates/kiro/skills/check-frontend/SKILL.md +18 -0
- package/dist/templates/kiro/skills/create-command/SKILL.md +2 -2
- package/dist/templates/kiro/skills/onboard/SKILL.md +11 -11
- package/dist/templates/kiro/skills/record-session/SKILL.md +2 -2
- package/dist/templates/kiro/skills/start/SKILL.md +3 -8
- package/dist/templates/markdown/spec/backend/script-conventions.md +0 -93
- package/dist/templates/opencode/agents/dispatch.md +2 -1
- package/dist/templates/opencode/agents/implement.md +2 -2
- package/dist/templates/opencode/agents/research.md +2 -1
- package/dist/templates/opencode/commands/trellis/before-backend-dev.md +13 -0
- package/dist/templates/opencode/commands/trellis/before-frontend-dev.md +13 -0
- package/dist/templates/opencode/commands/trellis/check-backend.md +13 -0
- package/dist/templates/opencode/commands/trellis/check-frontend.md +13 -0
- package/dist/templates/opencode/commands/trellis/create-command.md +2 -2
- package/dist/templates/opencode/commands/trellis/onboard.md +13 -13
- package/dist/templates/opencode/commands/trellis/parallel.md +2 -1
- package/dist/templates/opencode/commands/trellis/record-session.md +2 -2
- package/dist/templates/opencode/commands/trellis/start.md +3 -8
- package/dist/templates/opencode/plugin/inject-subagent-context.js +18 -45
- package/dist/templates/opencode/plugin/session-start.js +1 -149
- package/dist/templates/qoder/skills/before-backend-dev/SKILL.md +18 -0
- package/dist/templates/qoder/skills/before-frontend-dev/SKILL.md +18 -0
- package/dist/templates/qoder/skills/check-backend/SKILL.md +18 -0
- package/dist/templates/qoder/skills/check-frontend/SKILL.md +18 -0
- package/dist/templates/qoder/skills/create-command/SKILL.md +2 -2
- package/dist/templates/qoder/skills/onboard/SKILL.md +13 -13
- package/dist/templates/qoder/skills/record-session/SKILL.md +2 -2
- package/dist/templates/qoder/skills/start/SKILL.md +3 -8
- package/dist/templates/trellis/config.yaml +0 -20
- package/dist/templates/trellis/index.d.ts +0 -11
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +0 -22
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/add_session.py +7 -52
- package/dist/templates/trellis/scripts/common/cli_adapter.py +45 -33
- package/dist/templates/trellis/scripts/common/config.py +0 -152
- package/dist/templates/trellis/scripts/common/git_context.py +586 -23
- package/dist/templates/trellis/scripts/common/paths.py +0 -46
- package/dist/templates/trellis/scripts/common/phase.py +49 -50
- package/dist/templates/trellis/scripts/common/registry.py +72 -41
- package/dist/templates/trellis/scripts/common/task_queue.py +98 -27
- package/dist/templates/trellis/scripts/common/task_utils.py +6 -96
- package/dist/templates/trellis/scripts/create_bootstrap.py +26 -31
- package/dist/templates/trellis/scripts/multi_agent/cleanup.py +48 -43
- package/dist/templates/trellis/scripts/multi_agent/create_pr.py +45 -336
- package/dist/templates/trellis/scripts/multi_agent/plan.py +26 -2
- package/dist/templates/trellis/scripts/multi_agent/start.py +57 -126
- package/dist/templates/trellis/scripts/multi_agent/status.py +753 -12
- package/dist/templates/trellis/scripts/task.py +975 -50
- package/dist/templates/trellis/workflow.md +34 -21
- package/dist/types/migration.d.ts +1 -3
- package/dist/types/migration.d.ts.map +1 -1
- package/dist/utils/project-detector.d.ts +0 -23
- package/dist/utils/project-detector.d.ts.map +1 -1
- package/dist/utils/project-detector.js +0 -364
- package/dist/utils/project-detector.js.map +1 -1
- package/dist/utils/template-fetcher.d.ts +10 -2
- package/dist/utils/template-fetcher.d.ts.map +1 -1
- package/dist/utils/template-fetcher.js +43 -12
- package/dist/utils/template-fetcher.js.map +1 -1
- package/package.json +1 -1
- package/dist/migrations/manifests/0.4.0-beta.1.json +0 -228
- package/dist/templates/claude/commands/trellis/before-dev.md +0 -29
- package/dist/templates/claude/commands/trellis/check.md +0 -25
- package/dist/templates/codex/skills/before-dev/SKILL.md +0 -34
- package/dist/templates/codex/skills/check/SKILL.md +0 -30
- package/dist/templates/cursor/commands/trellis-before-dev.md +0 -29
- package/dist/templates/cursor/commands/trellis-check.md +0 -25
- package/dist/templates/gemini/commands/trellis/before-dev.toml +0 -33
- package/dist/templates/gemini/commands/trellis/check.toml +0 -29
- package/dist/templates/iflow/commands/trellis/before-dev.md +0 -29
- package/dist/templates/iflow/commands/trellis/check.md +0 -25
- package/dist/templates/kilo/workflows/before-dev.md +0 -29
- package/dist/templates/kilo/workflows/check.md +0 -25
- package/dist/templates/kiro/skills/before-dev/SKILL.md +0 -34
- package/dist/templates/kiro/skills/check/SKILL.md +0 -30
- package/dist/templates/opencode/commands/trellis/before-dev.md +0 -29
- package/dist/templates/opencode/commands/trellis/check.md +0 -25
- package/dist/templates/qoder/skills/before-dev/SKILL.md +0 -34
- package/dist/templates/qoder/skills/check/SKILL.md +0 -30
- package/dist/templates/trellis/scripts/common/git.py +0 -31
- package/dist/templates/trellis/scripts/common/io.py +0 -37
- package/dist/templates/trellis/scripts/common/log.py +0 -45
- package/dist/templates/trellis/scripts/common/packages_context.py +0 -233
- package/dist/templates/trellis/scripts/common/session_context.py +0 -466
- package/dist/templates/trellis/scripts/common/task_context.py +0 -384
- package/dist/templates/trellis/scripts/common/task_store.py +0 -534
- package/dist/templates/trellis/scripts/common/tasks.py +0 -109
- package/dist/templates/trellis/scripts/common/types.py +0 -112
- package/dist/templates/trellis/scripts/hooks/linear_sync.py +0 -243
- package/dist/templates/trellis/scripts/multi_agent/_bootstrap.py +0 -17
- package/dist/templates/trellis/scripts/multi_agent/status_display.py +0 -542
- package/dist/templates/trellis/scripts/multi_agent/status_monitor.py +0 -225
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Core type definitions for Trellis task data.
|
|
3
|
-
|
|
4
|
-
Provides:
|
|
5
|
-
TaskData — TypedDict for task.json shape (read-path type hints only)
|
|
6
|
-
TaskInfo — Frozen dataclass for loaded task (the public API type)
|
|
7
|
-
AgentRecord — TypedDict for registry.json agent entries
|
|
8
|
-
"""
|
|
9
|
-
|
|
10
|
-
from __future__ import annotations
|
|
11
|
-
|
|
12
|
-
from dataclasses import dataclass
|
|
13
|
-
from pathlib import Path
|
|
14
|
-
from typing import TypedDict
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# =============================================================================
|
|
18
|
-
# task.json shape (TypedDict — used only for read-path type hints)
|
|
19
|
-
# =============================================================================
|
|
20
|
-
|
|
21
|
-
class TaskData(TypedDict, total=False):
|
|
22
|
-
"""Shape of task.json on disk.
|
|
23
|
-
|
|
24
|
-
Used only for type annotations when reading task.json.
|
|
25
|
-
Writes must use the original dict to avoid losing unknown fields.
|
|
26
|
-
"""
|
|
27
|
-
|
|
28
|
-
id: str
|
|
29
|
-
name: str
|
|
30
|
-
title: str
|
|
31
|
-
description: str
|
|
32
|
-
status: str
|
|
33
|
-
dev_type: str
|
|
34
|
-
scope: str | None
|
|
35
|
-
package: str | None
|
|
36
|
-
priority: str
|
|
37
|
-
creator: str
|
|
38
|
-
assignee: str
|
|
39
|
-
createdAt: str
|
|
40
|
-
completedAt: str | None
|
|
41
|
-
branch: str | None
|
|
42
|
-
base_branch: str | None
|
|
43
|
-
worktree_path: str | None
|
|
44
|
-
current_phase: int
|
|
45
|
-
next_action: list[dict]
|
|
46
|
-
commit: str | None
|
|
47
|
-
pr_url: str | None
|
|
48
|
-
subtasks: list[str]
|
|
49
|
-
children: list[str]
|
|
50
|
-
parent: str | None
|
|
51
|
-
relatedFiles: list[str]
|
|
52
|
-
notes: str
|
|
53
|
-
meta: dict
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# =============================================================================
|
|
57
|
-
# Loaded task object (frozen dataclass — the public API type)
|
|
58
|
-
# =============================================================================
|
|
59
|
-
|
|
60
|
-
@dataclass(frozen=True)
|
|
61
|
-
class TaskInfo:
|
|
62
|
-
"""Immutable view of a loaded task.
|
|
63
|
-
|
|
64
|
-
Created by load_task() / iter_active_tasks().
|
|
65
|
-
Contains the commonly accessed fields; the original dict
|
|
66
|
-
is preserved in `raw` for write-back and uncommon field access.
|
|
67
|
-
"""
|
|
68
|
-
|
|
69
|
-
dir_name: str
|
|
70
|
-
directory: Path
|
|
71
|
-
title: str
|
|
72
|
-
status: str
|
|
73
|
-
assignee: str
|
|
74
|
-
priority: str
|
|
75
|
-
children: tuple[str, ...]
|
|
76
|
-
parent: str | None
|
|
77
|
-
package: str | None
|
|
78
|
-
raw: dict # original dict — use for writes and uncommon fields
|
|
79
|
-
|
|
80
|
-
@property
|
|
81
|
-
def name(self) -> str:
|
|
82
|
-
"""Task name (id or name field)."""
|
|
83
|
-
return self.raw.get("name") or self.raw.get("id") or self.dir_name
|
|
84
|
-
|
|
85
|
-
@property
|
|
86
|
-
def description(self) -> str:
|
|
87
|
-
return self.raw.get("description", "")
|
|
88
|
-
|
|
89
|
-
@property
|
|
90
|
-
def branch(self) -> str | None:
|
|
91
|
-
return self.raw.get("branch")
|
|
92
|
-
|
|
93
|
-
@property
|
|
94
|
-
def meta(self) -> dict:
|
|
95
|
-
return self.raw.get("meta", {})
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
# =============================================================================
|
|
99
|
-
# registry.json agent entry
|
|
100
|
-
# =============================================================================
|
|
101
|
-
|
|
102
|
-
class AgentRecord(TypedDict, total=False):
|
|
103
|
-
"""Shape of an agent entry in registry.json."""
|
|
104
|
-
|
|
105
|
-
id: str
|
|
106
|
-
pid: int
|
|
107
|
-
task_dir: str
|
|
108
|
-
worktree_path: str
|
|
109
|
-
branch: str
|
|
110
|
-
platform: str
|
|
111
|
-
started_at: str
|
|
112
|
-
status: str
|
|
@@ -1,243 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Linear sync hook for Trellis task lifecycle.
|
|
3
|
-
|
|
4
|
-
Syncs task events to Linear via the `linearis` CLI.
|
|
5
|
-
|
|
6
|
-
Usage (called automatically by task.py hooks):
|
|
7
|
-
python3 .trellis/scripts/hooks/linear_sync.py create
|
|
8
|
-
python3 .trellis/scripts/hooks/linear_sync.py start
|
|
9
|
-
python3 .trellis/scripts/hooks/linear_sync.py archive
|
|
10
|
-
|
|
11
|
-
Manual usage:
|
|
12
|
-
TASK_JSON_PATH=.trellis/tasks/<name>/task.json python3 .trellis/scripts/hooks/linear_sync.py sync
|
|
13
|
-
|
|
14
|
-
Environment:
|
|
15
|
-
TASK_JSON_PATH - Absolute path to task.json (set by task.py)
|
|
16
|
-
|
|
17
|
-
Configuration:
|
|
18
|
-
.trellis/hooks.local.json - Local config (gitignored), example:
|
|
19
|
-
{
|
|
20
|
-
"linear": {
|
|
21
|
-
"team": "TEAM_KEY",
|
|
22
|
-
"project": "Project Name",
|
|
23
|
-
"assignees": {
|
|
24
|
-
"dev-name": "linear-user-id"
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
"""
|
|
29
|
-
|
|
30
|
-
from __future__ import annotations
|
|
31
|
-
|
|
32
|
-
import json
|
|
33
|
-
import os
|
|
34
|
-
import subprocess
|
|
35
|
-
import sys
|
|
36
|
-
from pathlib import Path
|
|
37
|
-
|
|
38
|
-
# ─── Configuration ────────────────────────────────────────────────────────────
|
|
39
|
-
|
|
40
|
-
# Trellis priority → Linear priority (1=Urgent, 2=High, 3=Medium, 4=Low)
|
|
41
|
-
PRIORITY_MAP = {"P0": 1, "P1": 2, "P2": 3, "P3": 4}
|
|
42
|
-
|
|
43
|
-
# Linear status names (must match your team's workflow)
|
|
44
|
-
STATUS_IN_PROGRESS = "In Progress"
|
|
45
|
-
STATUS_DONE = "Done"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
def _load_config() -> dict:
|
|
49
|
-
"""Load local hook config from .trellis/hooks.local.json."""
|
|
50
|
-
task_json_path = os.environ.get("TASK_JSON_PATH", "")
|
|
51
|
-
if task_json_path:
|
|
52
|
-
# Walk up from task.json to find .trellis/
|
|
53
|
-
trellis_dir = Path(task_json_path).parent.parent.parent
|
|
54
|
-
else:
|
|
55
|
-
trellis_dir = Path(".trellis")
|
|
56
|
-
|
|
57
|
-
config_path = trellis_dir / "hooks.local.json"
|
|
58
|
-
try:
|
|
59
|
-
with open(config_path, encoding="utf-8") as f:
|
|
60
|
-
return json.load(f)
|
|
61
|
-
except (OSError, json.JSONDecodeError):
|
|
62
|
-
return {}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
CONFIG = _load_config()
|
|
66
|
-
LINEAR_CFG = CONFIG.get("linear", {})
|
|
67
|
-
|
|
68
|
-
TEAM = LINEAR_CFG.get("team", "")
|
|
69
|
-
PROJECT = LINEAR_CFG.get("project", "")
|
|
70
|
-
ASSIGNEE_MAP = LINEAR_CFG.get("assignees", {})
|
|
71
|
-
|
|
72
|
-
# ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def _read_task() -> tuple[dict, str]:
|
|
76
|
-
path = os.environ.get("TASK_JSON_PATH", "")
|
|
77
|
-
if not path:
|
|
78
|
-
print("TASK_JSON_PATH not set", file=sys.stderr)
|
|
79
|
-
sys.exit(1)
|
|
80
|
-
with open(path, encoding="utf-8") as f:
|
|
81
|
-
return json.load(f), path
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def _write_task(data: dict, path: str) -> None:
|
|
85
|
-
with open(path, "w", encoding="utf-8") as f:
|
|
86
|
-
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
87
|
-
f.write("\n")
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
def _linearis(*args: str) -> dict | None:
|
|
91
|
-
result = subprocess.run(
|
|
92
|
-
["linearis", *args],
|
|
93
|
-
capture_output=True,
|
|
94
|
-
text=True,
|
|
95
|
-
encoding="utf-8",
|
|
96
|
-
errors="replace",
|
|
97
|
-
)
|
|
98
|
-
if result.returncode != 0:
|
|
99
|
-
print(f"linearis error: {result.stderr.strip()}", file=sys.stderr)
|
|
100
|
-
sys.exit(1)
|
|
101
|
-
stdout = result.stdout.strip()
|
|
102
|
-
if stdout:
|
|
103
|
-
return json.loads(stdout)
|
|
104
|
-
return None
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def _get_linear_issue(task: dict) -> str | None:
|
|
108
|
-
meta = task.get("meta")
|
|
109
|
-
if isinstance(meta, dict):
|
|
110
|
-
return meta.get("linear_issue")
|
|
111
|
-
return None
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
# ─── Actions ──────────────────────────────────────────────────────────────────
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
def cmd_create() -> None:
|
|
118
|
-
if not TEAM:
|
|
119
|
-
print("No linear.team configured in hooks.local.json", file=sys.stderr)
|
|
120
|
-
sys.exit(1)
|
|
121
|
-
|
|
122
|
-
task, path = _read_task()
|
|
123
|
-
|
|
124
|
-
# Skip if already linked
|
|
125
|
-
if _get_linear_issue(task):
|
|
126
|
-
print(f"Already linked: {_get_linear_issue(task)}")
|
|
127
|
-
return
|
|
128
|
-
|
|
129
|
-
title = task.get("title") or task.get("name") or "Untitled"
|
|
130
|
-
args = ["issues", "create", title, "--team", TEAM]
|
|
131
|
-
|
|
132
|
-
# Map priority
|
|
133
|
-
priority = PRIORITY_MAP.get(task.get("priority", ""), 0)
|
|
134
|
-
if priority:
|
|
135
|
-
args.extend(["-p", str(priority)])
|
|
136
|
-
|
|
137
|
-
# Set project
|
|
138
|
-
if PROJECT:
|
|
139
|
-
args.extend(["--project", PROJECT])
|
|
140
|
-
|
|
141
|
-
# Assign to Linear user
|
|
142
|
-
assignee = task.get("assignee", "")
|
|
143
|
-
linear_user_id = ASSIGNEE_MAP.get(assignee)
|
|
144
|
-
if linear_user_id:
|
|
145
|
-
args.extend(["--assignee", linear_user_id])
|
|
146
|
-
|
|
147
|
-
# Link to parent's Linear issue if available
|
|
148
|
-
parent_issue = _resolve_parent_linear_issue(task)
|
|
149
|
-
if parent_issue:
|
|
150
|
-
args.extend(["--parent-ticket", parent_issue])
|
|
151
|
-
|
|
152
|
-
result = _linearis(*args)
|
|
153
|
-
if result and "identifier" in result:
|
|
154
|
-
if not isinstance(task.get("meta"), dict):
|
|
155
|
-
task["meta"] = {}
|
|
156
|
-
task["meta"]["linear_issue"] = result["identifier"]
|
|
157
|
-
_write_task(task, path)
|
|
158
|
-
print(f"Created Linear issue: {result['identifier']}")
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
def cmd_start() -> None:
|
|
162
|
-
task, _ = _read_task()
|
|
163
|
-
issue = _get_linear_issue(task)
|
|
164
|
-
if not issue:
|
|
165
|
-
return
|
|
166
|
-
_linearis("issues", "update", issue, "-s", STATUS_IN_PROGRESS)
|
|
167
|
-
print(f"Updated {issue} -> {STATUS_IN_PROGRESS}")
|
|
168
|
-
cmd_sync()
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
def cmd_archive() -> None:
|
|
172
|
-
task, _ = _read_task()
|
|
173
|
-
issue = _get_linear_issue(task)
|
|
174
|
-
if not issue:
|
|
175
|
-
return
|
|
176
|
-
_linearis("issues", "update", issue, "-s", STATUS_DONE)
|
|
177
|
-
print(f"Updated {issue} -> {STATUS_DONE}")
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
def cmd_sync() -> None:
|
|
181
|
-
"""Sync prd.md content to Linear issue description."""
|
|
182
|
-
task, _ = _read_task()
|
|
183
|
-
issue = _get_linear_issue(task)
|
|
184
|
-
if not issue:
|
|
185
|
-
print("No linear_issue in meta, run create first", file=sys.stderr)
|
|
186
|
-
sys.exit(1)
|
|
187
|
-
|
|
188
|
-
# Find prd.md next to task.json
|
|
189
|
-
task_json_path = os.environ.get("TASK_JSON_PATH", "")
|
|
190
|
-
prd_path = Path(task_json_path).parent / "prd.md"
|
|
191
|
-
if not prd_path.is_file():
|
|
192
|
-
print(f"No prd.md found at {prd_path}", file=sys.stderr)
|
|
193
|
-
sys.exit(1)
|
|
194
|
-
|
|
195
|
-
description = prd_path.read_text(encoding="utf-8").strip()
|
|
196
|
-
_linearis("issues", "update", issue, "-d", description)
|
|
197
|
-
print(f"Synced prd.md to {issue} description")
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
# ─── Parent Issue Resolution ─────────────────────────────────────────────────
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
def _resolve_parent_linear_issue(task: dict) -> str | None:
|
|
204
|
-
"""Find parent task's Linear issue identifier."""
|
|
205
|
-
parent_name = task.get("parent")
|
|
206
|
-
if not parent_name:
|
|
207
|
-
return None
|
|
208
|
-
|
|
209
|
-
task_json_path = os.environ.get("TASK_JSON_PATH", "")
|
|
210
|
-
if not task_json_path:
|
|
211
|
-
return None
|
|
212
|
-
|
|
213
|
-
current_task_dir = Path(task_json_path).parent
|
|
214
|
-
tasks_dir = current_task_dir.parent
|
|
215
|
-
parent_json = tasks_dir / parent_name / "task.json"
|
|
216
|
-
|
|
217
|
-
if parent_json.exists():
|
|
218
|
-
try:
|
|
219
|
-
with open(parent_json, encoding="utf-8") as f:
|
|
220
|
-
parent_task = json.load(f)
|
|
221
|
-
return _get_linear_issue(parent_task)
|
|
222
|
-
except (json.JSONDecodeError, OSError):
|
|
223
|
-
pass
|
|
224
|
-
return None
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
# ─── Main ─────────────────────────────────────────────────────────────────────
|
|
228
|
-
|
|
229
|
-
if __name__ == "__main__":
|
|
230
|
-
action = sys.argv[1] if len(sys.argv) > 1 else ""
|
|
231
|
-
actions = {
|
|
232
|
-
"create": cmd_create,
|
|
233
|
-
"start": cmd_start,
|
|
234
|
-
"archive": cmd_archive,
|
|
235
|
-
"sync": cmd_sync,
|
|
236
|
-
}
|
|
237
|
-
fn = actions.get(action)
|
|
238
|
-
if fn:
|
|
239
|
-
fn()
|
|
240
|
-
else:
|
|
241
|
-
print(f"Unknown action: {action}", file=sys.stderr)
|
|
242
|
-
print(f"Valid actions: {', '.join(actions)}", file=sys.stderr)
|
|
243
|
-
sys.exit(1)
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
"""Bootstrap path setup for multi_agent scripts.
|
|
2
|
-
|
|
3
|
-
Import this module before importing from common/:
|
|
4
|
-
|
|
5
|
-
import _bootstrap # noqa: F401
|
|
6
|
-
|
|
7
|
-
This adds the parent scripts/ directory to sys.path so that
|
|
8
|
-
`from common.xxx import yyy` works when running scripts directly
|
|
9
|
-
via `python3 .trellis/scripts/multi_agent/some_script.py`.
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
import sys
|
|
13
|
-
from pathlib import Path
|
|
14
|
-
|
|
15
|
-
_scripts_dir = str(Path(__file__).resolve().parent.parent)
|
|
16
|
-
if _scripts_dir not in sys.path:
|
|
17
|
-
sys.path.insert(0, _scripts_dir)
|