@mindfoldhq/trellis 0.5.0-beta.14 → 0.5.0-beta.16

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 (127) hide show
  1. package/README.md +5 -5
  2. package/dist/cli/index.js +1 -0
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/commands/init.d.ts +1 -0
  5. package/dist/commands/init.d.ts.map +1 -1
  6. package/dist/commands/init.js +24 -20
  7. package/dist/commands/init.js.map +1 -1
  8. package/dist/commands/update.d.ts.map +1 -1
  9. package/dist/commands/update.js +44 -13
  10. package/dist/commands/update.js.map +1 -1
  11. package/dist/configurators/claude.js +1 -1
  12. package/dist/configurators/claude.js.map +1 -1
  13. package/dist/configurators/codebuddy.js +1 -1
  14. package/dist/configurators/codebuddy.js.map +1 -1
  15. package/dist/configurators/codex.d.ts.map +1 -1
  16. package/dist/configurators/codex.js +3 -6
  17. package/dist/configurators/codex.js.map +1 -1
  18. package/dist/configurators/copilot.d.ts.map +1 -1
  19. package/dist/configurators/copilot.js +4 -11
  20. package/dist/configurators/copilot.js.map +1 -1
  21. package/dist/configurators/cursor.js +1 -1
  22. package/dist/configurators/cursor.js.map +1 -1
  23. package/dist/configurators/droid.js +1 -1
  24. package/dist/configurators/droid.js.map +1 -1
  25. package/dist/configurators/gemini.d.ts.map +1 -1
  26. package/dist/configurators/gemini.js +1 -3
  27. package/dist/configurators/gemini.js.map +1 -1
  28. package/dist/configurators/index.d.ts.map +1 -1
  29. package/dist/configurators/index.js +24 -38
  30. package/dist/configurators/index.js.map +1 -1
  31. package/dist/configurators/kiro.js +1 -1
  32. package/dist/configurators/kiro.js.map +1 -1
  33. package/dist/configurators/opencode.d.ts.map +1 -1
  34. package/dist/configurators/opencode.js +4 -1
  35. package/dist/configurators/opencode.js.map +1 -1
  36. package/dist/configurators/pi.d.ts +3 -0
  37. package/dist/configurators/pi.d.ts.map +1 -0
  38. package/dist/configurators/pi.js +39 -0
  39. package/dist/configurators/pi.js.map +1 -0
  40. package/dist/configurators/qoder.d.ts.map +1 -1
  41. package/dist/configurators/qoder.js +1 -3
  42. package/dist/configurators/qoder.js.map +1 -1
  43. package/dist/configurators/shared.d.ts +2 -4
  44. package/dist/configurators/shared.d.ts.map +1 -1
  45. package/dist/configurators/shared.js +6 -9
  46. package/dist/configurators/shared.js.map +1 -1
  47. package/dist/migrations/manifests/0.5.0-beta.15.json +116 -0
  48. package/dist/migrations/manifests/0.5.0-beta.16.json +9 -0
  49. package/dist/templates/claude/agents/trellis-research.md +1 -1
  50. package/dist/templates/claude/settings.json +0 -4
  51. package/dist/templates/codebuddy/agents/trellis-research.md +1 -1
  52. package/dist/templates/codex/agents/trellis-check.toml +0 -16
  53. package/dist/templates/codex/agents/trellis-implement.toml +0 -16
  54. package/dist/templates/codex/agents/trellis-research.toml +3 -2
  55. package/dist/templates/codex/hooks/session-start.py +51 -21
  56. package/dist/templates/codex/skills/start/SKILL.md +1 -1
  57. package/dist/templates/copilot/hooks/session-start.py +51 -21
  58. package/dist/templates/copilot/prompts/start.prompt.md +1 -1
  59. package/dist/templates/cursor/agents/trellis-check.md +1 -1
  60. package/dist/templates/cursor/agents/trellis-implement.md +1 -1
  61. package/dist/templates/cursor/agents/trellis-research.md +2 -2
  62. package/dist/templates/cursor/hooks.json +7 -1
  63. package/dist/templates/droid/droids/trellis-research.md +1 -1
  64. package/dist/templates/extract.d.ts +6 -0
  65. package/dist/templates/extract.d.ts.map +1 -1
  66. package/dist/templates/extract.js +14 -0
  67. package/dist/templates/extract.js.map +1 -1
  68. package/dist/templates/gemini/agents/trellis-research.md +1 -1
  69. package/dist/templates/kiro/agents/trellis-research.json +1 -1
  70. package/dist/templates/markdown/agents.md +11 -12
  71. package/dist/templates/markdown/gitignore.txt +3 -0
  72. package/dist/templates/opencode/agents/trellis-check.md +1 -1
  73. package/dist/templates/opencode/agents/trellis-implement.md +1 -1
  74. package/dist/templates/opencode/agents/trellis-research.md +2 -2
  75. package/dist/templates/opencode/lib/trellis-context.js +100 -13
  76. package/dist/templates/opencode/plugins/inject-subagent-context.js +54 -4
  77. package/dist/templates/opencode/plugins/inject-workflow-state.js +48 -25
  78. package/dist/templates/opencode/plugins/session-start.js +29 -16
  79. package/dist/templates/pi/agents/trellis-check.md +28 -0
  80. package/dist/templates/pi/agents/trellis-implement.md +33 -0
  81. package/dist/templates/pi/agents/trellis-research.md +25 -0
  82. package/dist/templates/pi/extensions/trellis/index.ts.txt +549 -0
  83. package/dist/templates/pi/index.d.ts +5 -0
  84. package/dist/templates/pi/index.d.ts.map +1 -0
  85. package/dist/templates/pi/index.js +12 -0
  86. package/dist/templates/pi/index.js.map +1 -0
  87. package/dist/templates/pi/settings.json +12 -0
  88. package/dist/templates/qoder/agents/trellis-research.md +1 -1
  89. package/dist/templates/shared-hooks/index.d.ts +31 -0
  90. package/dist/templates/shared-hooks/index.d.ts.map +1 -1
  91. package/dist/templates/shared-hooks/index.js +59 -0
  92. package/dist/templates/shared-hooks/index.js.map +1 -1
  93. package/dist/templates/shared-hooks/inject-shell-session-context.py +180 -0
  94. package/dist/templates/shared-hooks/inject-subagent-context.py +128 -26
  95. package/dist/templates/shared-hooks/inject-workflow-state.py +99 -62
  96. package/dist/templates/shared-hooks/session-start.py +139 -24
  97. package/dist/templates/trellis/gitignore.txt +3 -0
  98. package/dist/templates/trellis/index.d.ts +1 -0
  99. package/dist/templates/trellis/index.d.ts.map +1 -1
  100. package/dist/templates/trellis/index.js +2 -0
  101. package/dist/templates/trellis/index.js.map +1 -1
  102. package/dist/templates/trellis/scripts/common/__init__.py +8 -0
  103. package/dist/templates/trellis/scripts/common/active_task.py +593 -0
  104. package/dist/templates/trellis/scripts/common/cli_adapter.py +43 -8
  105. package/dist/templates/trellis/scripts/common/paths.py +61 -58
  106. package/dist/templates/trellis/scripts/common/session_context.py +12 -0
  107. package/dist/templates/trellis/scripts/common/task_store.py +6 -8
  108. package/dist/templates/trellis/scripts/task.py +59 -17
  109. package/dist/templates/trellis/workflow.md +30 -26
  110. package/dist/types/ai-tools.d.ts +3 -3
  111. package/dist/types/ai-tools.d.ts.map +1 -1
  112. package/dist/types/ai-tools.js +16 -0
  113. package/dist/types/ai-tools.js.map +1 -1
  114. package/dist/utils/posix.d.ts +13 -0
  115. package/dist/utils/posix.d.ts.map +1 -0
  116. package/dist/utils/posix.js +15 -0
  117. package/dist/utils/posix.js.map +1 -0
  118. package/dist/utils/template-fetcher.d.ts +22 -6
  119. package/dist/utils/template-fetcher.d.ts.map +1 -1
  120. package/dist/utils/template-fetcher.js +405 -27
  121. package/dist/utils/template-fetcher.js.map +1 -1
  122. package/dist/utils/template-hash.d.ts +22 -3
  123. package/dist/utils/template-hash.d.ts.map +1 -1
  124. package/dist/utils/template-hash.js +80 -18
  125. package/dist/utils/template-hash.js.map +1 -1
  126. package/package.json +1 -1
  127. package/dist/templates/shared-hooks/statusline.py +0 -219
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env python3
2
2
  """Trellis UserPromptSubmit hook: inject per-turn workflow breadcrumb.
3
3
 
4
- Runs on every user prompt. Reads the active task (.trellis/.current-task)
5
- and emits a short <workflow-state> block reminding the main AI what task
6
- is active and its expected flow. Breadcrumb text is pulled from
4
+ Runs on every user prompt. Resolves the active task through Trellis'
5
+ session-aware active task resolver and emits a short <workflow-state> block
6
+ reminding the main AI what task is active and its expected flow. Breadcrumb text is pulled from
7
7
  workflow.md [workflow-state:STATUS] tag blocks (single source of truth
8
8
  for users who fork the Trellis workflow), with hardcoded fallbacks so
9
9
  the hook never breaks when workflow.md is missing or malformed.
@@ -15,7 +15,6 @@ writeSharedHooks() at init time.
15
15
 
16
16
  Silent exit 0 cases (no output):
17
17
  - No .trellis/ directory found (not a Trellis project)
18
- - No .current-task file, or it's empty
19
18
  - task.json malformed or missing status
20
19
 
21
20
  Unknown status (no tag + no hardcoded fallback) emits a generic
@@ -29,7 +28,7 @@ import os
29
28
  import re
30
29
  import sys
31
30
  from pathlib import Path
32
- from typing import Optional, Tuple
31
+ from typing import Optional
33
32
 
34
33
 
35
34
  # ---------------------------------------------------------------------------
@@ -54,48 +53,63 @@ def find_trellis_root(start: Path) -> Optional[Path]:
54
53
  # Active task discovery
55
54
  # ---------------------------------------------------------------------------
56
55
 
57
- def _normalize_task_ref(task_ref: str) -> str:
58
- """Normalize .current-task path ref.
56
+ def _detect_platform(input_data: dict) -> str | None:
57
+ if isinstance(input_data.get("cursor_version"), str):
58
+ return "cursor"
59
+ env_map = {
60
+ "CLAUDE_PROJECT_DIR": "claude",
61
+ "CURSOR_PROJECT_DIR": "cursor",
62
+ "CODEBUDDY_PROJECT_DIR": "codebuddy",
63
+ "FACTORY_PROJECT_DIR": "droid",
64
+ "GEMINI_PROJECT_DIR": "gemini",
65
+ "QODER_PROJECT_DIR": "qoder",
66
+ "KIRO_PROJECT_DIR": "kiro",
67
+ "COPILOT_PROJECT_DIR": "copilot",
68
+ }
69
+ for env_name, platform in env_map.items():
70
+ if os.environ.get(env_name):
71
+ return platform
72
+ script_parts = set(Path(sys.argv[0]).parts)
73
+ if ".claude" in script_parts:
74
+ return "claude"
75
+ if ".cursor" in script_parts:
76
+ return "cursor"
77
+ if ".codex" in script_parts:
78
+ return "codex"
79
+ if ".gemini" in script_parts:
80
+ return "gemini"
81
+ if ".qoder" in script_parts:
82
+ return "qoder"
83
+ if ".codebuddy" in script_parts:
84
+ return "codebuddy"
85
+ if ".factory" in script_parts:
86
+ return "droid"
87
+ if ".kiro" in script_parts:
88
+ return "kiro"
89
+ return None
59
90
 
60
- Accepts:
61
- - Absolute paths (left as-is)
62
- - Windows-style backslashes (converted to forward slash)
63
- - Legacy relative refs like "tasks/foo" (prefixed with .trellis/)
64
- """
65
- normalized = task_ref.strip()
66
- if not normalized:
67
- return ""
68
- path_obj = Path(normalized)
69
- if path_obj.is_absolute():
70
- return str(path_obj)
71
- normalized = normalized.replace("\\", "/")
72
- while normalized.startswith("./"):
73
- normalized = normalized[2:]
74
- if normalized.startswith("tasks/"):
75
- normalized = f".trellis/{normalized}"
76
- return normalized
77
-
78
-
79
- def get_active_task(root: Path) -> Optional[Tuple[str, str]]:
80
- """Return (task_id, status) from the current active task, else None.
81
-
82
- Reads .trellis/.current-task (a path relative to root, e.g.
83
- ".trellis/tasks/04-17-foo") then that task's task.json.
84
- Normalizes backslashes so Windows paths work on Unix and vice versa.
85
- """
86
- ref_file = root / ".trellis" / ".current-task"
87
- if not ref_file.is_file():
88
- return None
89
- try:
90
- raw = ref_file.read_text(encoding="utf-8").strip()
91
- except OSError:
92
- return None
93
- task_ref = _normalize_task_ref(raw)
94
- if not task_ref:
91
+
92
+ def _resolve_active_task(root: Path, input_data: dict):
93
+ scripts_dir = root / ".trellis" / "scripts"
94
+ if str(scripts_dir) not in sys.path:
95
+ sys.path.insert(0, str(scripts_dir))
96
+ from common.active_task import resolve_active_task # type: ignore[import-not-found]
97
+
98
+ return resolve_active_task(root, input_data, platform=_detect_platform(input_data))
99
+
100
+
101
+ def get_active_task(root: Path, input_data: dict) -> Optional[tuple[str, str, str]]:
102
+ """Return (task_id, status, source) from the current active task."""
103
+ active = _resolve_active_task(root, input_data)
104
+ if not active.task_path:
95
105
  return None
96
106
 
97
- path_obj = Path(task_ref)
98
- task_dir = path_obj if path_obj.is_absolute() else root / path_obj
107
+ task_dir = Path(active.task_path)
108
+ if not task_dir.is_absolute():
109
+ task_dir = root / task_dir
110
+ if active.stale:
111
+ return task_dir.name, f"stale_{active.source_type}", active.source
112
+
99
113
  task_json = task_dir / "task.json"
100
114
  if not task_json.is_file():
101
115
  return None
@@ -108,7 +122,7 @@ def get_active_task(root: Path) -> Optional[Tuple[str, str]]:
108
122
  status = data.get("status", "")
109
123
  if not isinstance(status, str) or not status:
110
124
  return None
111
- return task_id, status
125
+ return task_id, status, active.source
112
126
 
113
127
 
114
128
  # ---------------------------------------------------------------------------
@@ -125,25 +139,32 @@ _TAG_RE = re.compile(
125
139
  # Hardcoded defaults for built-in Trellis statuses. Used when workflow.md is
126
140
  # missing, malformed, or lacks the tag for this status.
127
141
  #
128
- # `no_task` is a pseudo-status emitted when .current-task is missing — it keeps
142
+ # `no_task` is a pseudo-status emitted when no session active task exists — it keeps
129
143
  # the Next-Action reminder flowing per-turn even without an active task.
130
144
  _FALLBACK_BREADCRUMBS = {
131
145
  "no_task": (
132
146
  "No active task.\n"
133
- "Trigger words in the user message that REQUIRE creating a task "
134
- "(non-negotiable, do NOT self-exempt): 重构 / 抽成 / 独立 / 分发 / "
135
- "拆出来 / 搞一个 / 做成 / 接入 / 集成 / refactor / rewrite / extract / "
136
- "productize / publish / build X / design Y.\n"
137
- "Task is NOT required ONLY if ALL three hold: (a) zero file writes "
138
- "this turn, (b) answer fits in one reply with no multi-round plan, "
139
- "(c) no research beyond reading 1-2 repo files.\n"
140
- "When in doubt: create task. Over-tasking is cheap; under-tasking "
141
- "leaks plans and research into main context.\n"
147
+ "Trigger words in the user message that suggest creating a task: "
148
+ "重构 / 抽成 / 独立 / 分发 / 拆出来 / 搞一个 / 做成 / 接入 / 集成 / "
149
+ "refactor / rewrite / extract / productize / publish / build X / design Y.\n"
150
+ "Task is NOT required if ALL three hold: (a) zero file writes this turn, "
151
+ "(b) answer fits in one reply with no multi-round plan, (c) no research "
152
+ "beyond reading 1-2 repo files.\n"
153
+ "When in doubt and no override below applies: prefer creating a task — "
154
+ "over-tasking is cheap; under-tasking leaks plans and research into "
155
+ "main context.\n"
142
156
  "Flow: load `trellis-brainstorm` skill → it creates the task via "
143
157
  "`python3 ./.trellis/scripts/task.py create` and drives requirements Q&A. "
144
158
  "For research-heavy work (tool comparison, docs, cross-platform survey), "
145
159
  "spawn `trellis-research` sub-agents via Task tool — NEVER do 3+ inline "
146
- "WebFetch/WebSearch/`gh api` calls in the main conversation."
160
+ "WebFetch/WebSearch/`gh api` calls in the main conversation.\n"
161
+ "User override (per-turn escape hatch): if the user's CURRENT message "
162
+ "contains an explicit opt-out phrase (\"跳过 trellis\" / \"别走流程\" / "
163
+ "\"小修一下\" / \"直接改\" / \"先别建任务\" / \"skip trellis\" / "
164
+ "\"no task\" / \"just do it\" / \"don't create a task\"), honor it for "
165
+ "this turn — briefly acknowledge (\"好,本轮跳过 trellis 流程\") and "
166
+ "proceed without creating a task. Per-turn only; does not carry forward; "
167
+ "do NOT invent an override the user did not say."
147
168
  ),
148
169
  "planning": (
149
170
  "Complete prd.md via trellis-brainstorm skill; then run task.py start.\n"
@@ -155,9 +176,19 @@ _FALLBACK_BREADCRUMBS = {
155
176
  "Flow: trellis-implement → trellis-check → trellis-update-spec → finish\n"
156
177
  "Next required action: inspect conversation history + git status, then "
157
178
  "execute the next uncompleted step in that sequence.\n"
158
- "For agent-capable platforms, do NOT edit code in the main session; "
159
- "dispatch `trellis-implement` for implementation and dispatch "
160
- "`trellis-check` before reporting completion."
179
+ "For agent-capable platforms, the default is to dispatch "
180
+ "`trellis-implement` for implementation and `trellis-check` before "
181
+ "reporting completion do not edit code in the main session by default.\n"
182
+ "Use the exact Trellis agent type names when spawning sub-agents: "
183
+ "`trellis-implement`, `trellis-check`, or `trellis-research`. "
184
+ "Generic/default/generalPurpose sub-agents do not receive "
185
+ "`implement.jsonl` / `check.jsonl` injection.\n"
186
+ "User override (per-turn escape hatch): if the user's CURRENT message "
187
+ "explicitly tells the main session to handle it directly (\"你直接改\" / "
188
+ "\"别派 sub-agent\" / \"main session 写就行\" / \"do it inline\" / "
189
+ "\"不用 sub-agent\"), honor it for this turn and edit code directly. "
190
+ "Per-turn only; does not carry forward; do NOT invent an override the "
191
+ "user did not say."
161
192
  ),
162
193
  "completed": (
163
194
  "User commits changes; then run task.py archive."
@@ -192,7 +223,10 @@ def load_breadcrumbs(root: Path) -> dict[str, str]:
192
223
 
193
224
 
194
225
  def build_breadcrumb(
195
- task_id: Optional[str], status: str, templates: dict[str, str]
226
+ task_id: Optional[str],
227
+ status: str,
228
+ templates: dict[str, str],
229
+ source: str | None = None,
196
230
  ) -> str:
197
231
  """Build the <workflow-state>...</workflow-state> block.
198
232
 
@@ -204,6 +238,8 @@ def build_breadcrumb(
204
238
  if body is None:
205
239
  body = "Refer to workflow.md for current step."
206
240
  header = f"Status: {status}" if task_id is None else f"Task: {task_id} ({status})"
241
+ if source:
242
+ header = f"{header}\nSource: {source}"
207
243
  return f"<workflow-state>\n{header}\n{body}\n</workflow-state>"
208
244
 
209
245
 
@@ -225,13 +261,14 @@ def main() -> int:
225
261
  return 0 # not a Trellis project
226
262
 
227
263
  templates = load_breadcrumbs(root)
228
- task = get_active_task(root)
264
+ task = get_active_task(root, data)
229
265
  if task is None:
230
266
  # No active task — still emit a breadcrumb nudging AI toward
231
267
  # trellis-brainstorm + task.py create when user describes real work.
232
268
  breadcrumb = build_breadcrumb(None, "no_task", templates)
233
269
  else:
234
- breadcrumb = build_breadcrumb(*task, templates=templates)
270
+ task_id, status, source = task
271
+ breadcrumb = build_breadcrumb(task_id, status, templates, source)
235
272
 
236
273
  output = {
237
274
  "hookSpecificOutput": {
@@ -11,6 +11,7 @@ warnings.filterwarnings("ignore")
11
11
 
12
12
  import json
13
13
  import os
14
+ import shlex
14
15
  import subprocess
15
16
  import sys
16
17
  from io import StringIO
@@ -38,7 +39,8 @@ def _has_curated_jsonl_entry(jsonl_path: Path) -> bool:
38
39
 
39
40
  A freshly seeded jsonl only contains a ``{"_example": ...}`` row (no
40
41
  ``file`` key) — that is NOT "ready". Readiness requires at least one
41
- curated entry. Matches the contract used by ``inject-subagent-context.py``.
42
+ curated entry. Matches the contract used by hook-inject and pull-based
43
+ sub-agent context loaders.
42
44
  """
43
45
  try:
44
46
  for line in jsonl_path.read_text(encoding="utf-8").splitlines():
@@ -78,15 +80,97 @@ def read_file(path: Path, fallback: str = "") -> str:
78
80
  return fallback
79
81
 
80
82
 
81
- def run_script(script_path: Path) -> str:
83
+ def _detect_platform(input_data: dict) -> str | None:
84
+ if isinstance(input_data.get("cursor_version"), str):
85
+ return "cursor"
86
+ env_map = {
87
+ "CLAUDE_PROJECT_DIR": "claude",
88
+ "CURSOR_PROJECT_DIR": "cursor",
89
+ "CODEBUDDY_PROJECT_DIR": "codebuddy",
90
+ "FACTORY_PROJECT_DIR": "droid",
91
+ "GEMINI_PROJECT_DIR": "gemini",
92
+ "QODER_PROJECT_DIR": "qoder",
93
+ "KIRO_PROJECT_DIR": "kiro",
94
+ "COPILOT_PROJECT_DIR": "copilot",
95
+ }
96
+ for env_name, platform in env_map.items():
97
+ if os.environ.get(env_name):
98
+ return platform
99
+ script_parts = set(Path(sys.argv[0]).parts)
100
+ if ".claude" in script_parts:
101
+ return "claude"
102
+ if ".cursor" in script_parts:
103
+ return "cursor"
104
+ if ".codex" in script_parts:
105
+ return "codex"
106
+ if ".gemini" in script_parts:
107
+ return "gemini"
108
+ if ".qoder" in script_parts:
109
+ return "qoder"
110
+ if ".codebuddy" in script_parts:
111
+ return "codebuddy"
112
+ if ".factory" in script_parts:
113
+ return "droid"
114
+ if ".kiro" in script_parts:
115
+ return "kiro"
116
+ return None
117
+
118
+
119
+ def _resolve_context_key(trellis_dir: Path, input_data: dict) -> str | None:
120
+ scripts_dir = trellis_dir / "scripts"
121
+ if str(scripts_dir) not in sys.path:
122
+ sys.path.insert(0, str(scripts_dir))
123
+ from common.active_task import resolve_context_key # type: ignore[import-not-found]
124
+
125
+ return resolve_context_key(input_data, platform=_detect_platform(input_data))
126
+
127
+
128
+ def _persist_context_key_for_bash(context_key: str | None) -> None:
129
+ """Expose Trellis session identity to later Claude Code Bash commands.
130
+
131
+ Claude Code SessionStart hooks can append exports to CLAUDE_ENV_FILE; those
132
+ variables are then available to Bash tools in the same conversation. Without
133
+ this bridge, `task.py start` has hook stdin during SessionStart but no
134
+ session identity when the AI later runs it as a normal shell command.
135
+ """
136
+ if not context_key:
137
+ return
138
+ env_file = os.environ.get("CLAUDE_ENV_FILE")
139
+ if not env_file:
140
+ return
141
+ try:
142
+ with open(env_file, "a", encoding="utf-8") as handle:
143
+ handle.write(f"export TRELLIS_CONTEXT_ID={shlex.quote(context_key)}\n")
144
+ except OSError:
145
+ pass
146
+
147
+
148
+ def _resolve_active_task(trellis_dir: Path, input_data: dict):
149
+ scripts_dir = trellis_dir / "scripts"
150
+ if str(scripts_dir) not in sys.path:
151
+ sys.path.insert(0, str(scripts_dir))
152
+ from common.active_task import resolve_active_task # type: ignore[import-not-found]
153
+
154
+ return resolve_active_task(
155
+ trellis_dir.parent,
156
+ input_data,
157
+ platform=_detect_platform(input_data),
158
+ )
159
+
160
+
161
+ def run_script(script_path: Path, context_key: str | None = None) -> str:
82
162
  try:
83
163
  if script_path.suffix == ".py":
84
164
  # Add PYTHONIOENCODING to force UTF-8 in subprocess
85
165
  env = os.environ.copy()
86
166
  env["PYTHONIOENCODING"] = "utf-8"
167
+ if context_key:
168
+ env["TRELLIS_CONTEXT_ID"] = context_key
87
169
  cmd = [sys.executable, "-W", "ignore", str(script_path)]
88
170
  else:
89
- env = os.environ
171
+ env = os.environ.copy()
172
+ if context_key:
173
+ env["TRELLIS_CONTEXT_ID"] = context_key
90
174
  cmd = [str(script_path)]
91
175
 
92
176
  result = subprocess.run(
@@ -133,7 +217,7 @@ def _resolve_task_dir(trellis_dir: Path, task_ref: str) -> Path:
133
217
  return trellis_dir / "tasks" / path_obj
134
218
 
135
219
 
136
- def _get_task_status(trellis_dir: Path) -> str:
220
+ def _get_task_status(trellis_dir: Path, input_data: dict) -> str:
137
221
  """Check current task status and return structured status string with explicit next action.
138
222
 
139
223
  Returns a block with three fields:
@@ -141,27 +225,32 @@ def _get_task_status(trellis_dir: Path) -> str:
141
225
  - Task: task identifier (when applicable)
142
226
  - Next-Action: explicit skill/command/tool call the AI should invoke
143
227
  """
144
- current_task_file = trellis_dir / ".current-task"
228
+ active = _resolve_active_task(trellis_dir, input_data)
145
229
 
146
230
  # Case 1: No active task — waiting for user to describe intent
147
- if not current_task_file.is_file() or not current_task_file.read_text(encoding="utf-8").strip():
231
+ if not active.task_path:
148
232
  return (
149
233
  "Status: NO ACTIVE TASK\n"
234
+ f"Source: {active.source}\n"
150
235
  "Next-Action: After the user describes their intent, load skill `trellis-brainstorm` "
151
236
  "to clarify requirements and create a task via `python3 ./.trellis/scripts/task.py create`.\n"
152
237
  "Research reminder: for research-heavy tasks (comparing tools, reading external docs, "
153
238
  "cross-platform surveys), spawn `trellis-research` sub-agents via the Task tool — "
154
239
  "they persist findings to `{TASK_DIR}/research/*.md` and keep main context clean. "
155
- "Do NOT do 10+ inline WebFetch/WebSearch in the main conversation."
240
+ "Do NOT do 10+ inline WebFetch/WebSearch in the main conversation.\n"
241
+ "User override (per-turn escape hatch): if the user's first message explicitly opts "
242
+ "out of the workflow (\"跳过 trellis\" / \"别走流程\" / \"小修一下\" / \"直接改\" / "
243
+ "\"skip trellis\" / \"no task\" / \"just do it\"), honor it for this turn — "
244
+ "acknowledge briefly and proceed without creating a task. Per-turn only."
156
245
  )
157
246
 
158
- task_ref = _normalize_task_ref(current_task_file.read_text(encoding="utf-8").strip())
159
-
160
247
  # Case 2: Stale pointer — task dir was deleted
248
+ task_ref = active.task_path
161
249
  task_dir = _resolve_task_dir(trellis_dir, task_ref)
162
- if not task_dir.is_dir():
250
+ if active.stale or not task_dir.is_dir():
163
251
  return (
164
252
  f"Status: STALE POINTER\nTask: {task_ref}\n"
253
+ f"Source: {active.source}\n"
165
254
  f"Next-Action: Run `python3 ./.trellis/scripts/task.py finish` to clear the stale pointer, "
166
255
  "then ask the user what to work on next."
167
256
  )
@@ -182,6 +271,7 @@ def _get_task_status(trellis_dir: Path) -> str:
182
271
  if task_status == "completed":
183
272
  return (
184
273
  f"Status: COMPLETED\nTask: {task_title}\n"
274
+ f"Source: {active.source}\n"
185
275
  f"Next-Action: Load skill `trellis-update-spec` to capture learnings, "
186
276
  f"then archive with `python3 ./.trellis/scripts/task.py archive {task_dir.name}`."
187
277
  )
@@ -192,6 +282,7 @@ def _get_task_status(trellis_dir: Path) -> str:
192
282
  if not has_prd:
193
283
  return (
194
284
  f"Status: PLANNING\nTask: {task_title}\n"
285
+ f"Source: {active.source}\n"
195
286
  "Next-Action: Load skill `trellis-brainstorm` to clarify requirements with the user "
196
287
  "and produce prd.md in the task directory.\n"
197
288
  "Research reminder: when the task needs external research (tool comparison, docs, "
@@ -204,6 +295,7 @@ def _get_task_status(trellis_dir: Path) -> str:
204
295
  if implement_jsonl.is_file() and not _has_curated_jsonl_entry(implement_jsonl):
205
296
  return (
206
297
  f"Status: PLANNING (Phase 1.3)\nTask: {task_title}\n"
298
+ f"Source: {active.source}\n"
207
299
  "Next-Action: Curate `implement.jsonl` and `check.jsonl` with the spec + research files "
208
300
  "the Phase 2 sub-agents will need. Only spec paths (`.trellis/spec/**/*.md`) and research "
209
301
  "files (`{TASK_DIR}/research/*.md`) — no code paths. Run "
@@ -215,16 +307,21 @@ def _get_task_status(trellis_dir: Path) -> str:
215
307
  # Case 5: PRD + curated jsonl (or agent-less platform with no jsonl) — enter Execute phase
216
308
  return (
217
309
  f"Status: READY\nTask: {task_title}\n"
310
+ f"Source: {active.source}\n"
218
311
  "Next required action: dispatch `trellis-implement` per Phase 2.1. "
219
- "For agent-capable platforms, do NOT edit code in the main session. "
312
+ "For agent-capable platforms, the default is to NOT edit code in the main session. "
220
313
  "After implementation, dispatch `trellis-check` per Phase 2.2 before reporting completion.\n"
221
314
  "Sub-agent roster: `trellis-implement` (writes code), `trellis-check` (verifies + self-fixes), "
222
315
  "`trellis-research` (persists findings to `research/*.md` — use when you'd otherwise do "
223
- "multiple WebFetch/WebSearch inline)."
316
+ "multiple WebFetch/WebSearch inline).\n"
317
+ "User override (per-turn escape hatch): if the user's CURRENT message explicitly tells the "
318
+ "main session to handle it directly (\"你直接改\" / \"别派 sub-agent\" / \"main session 写就行\" / "
319
+ "\"do it inline\" / \"不用 sub-agent\"), honor it for this turn and edit code directly. "
320
+ "Per-turn only; do NOT invent an override the user did not say."
224
321
  )
225
322
 
226
323
 
227
- def _load_trellis_config(trellis_dir: Path) -> tuple:
324
+ def _load_trellis_config(trellis_dir: Path, input_data: dict) -> tuple:
228
325
  """Load Trellis config for session-start decisions.
229
326
 
230
327
  Returns:
@@ -245,7 +342,11 @@ def _load_trellis_config(trellis_dir: Path) -> tuple:
245
342
 
246
343
  # Get active task's package
247
344
  task_pkg = None
248
- current = get_current_task(repo_root)
345
+ current = get_current_task(
346
+ repo_root,
347
+ input_data,
348
+ platform=_detect_platform(input_data),
349
+ )
249
350
  if current:
250
351
  task_json = repo_root / current / "task.json"
251
352
  if task_json.is_file():
@@ -440,7 +541,14 @@ def main():
440
541
  if should_skip_injection():
441
542
  sys.exit(0)
442
543
 
443
- # Try platform-specific env vars, fallback to cwd
544
+ try:
545
+ hook_input = json.loads(sys.stdin.read())
546
+ if not isinstance(hook_input, dict):
547
+ hook_input = {}
548
+ except (json.JSONDecodeError, ValueError):
549
+ hook_input = {}
550
+
551
+ # Try platform-specific env vars, hook cwd, fallback to cwd
444
552
  project_dir_env_vars = [
445
553
  "CLAUDE_PROJECT_DIR",
446
554
  "QODER_PROJECT_DIR",
@@ -458,12 +566,17 @@ def main():
458
566
  project_dir = Path(val).resolve()
459
567
  break
460
568
  if project_dir is None:
461
- project_dir = Path(".").resolve()
569
+ project_dir = Path(hook_input.get("cwd", ".")).resolve()
462
570
 
463
571
  trellis_dir = project_dir / ".trellis"
572
+ context_key = _resolve_context_key(trellis_dir, hook_input)
573
+ _persist_context_key_for_bash(context_key)
464
574
 
465
575
  # Load config for scope filtering and legacy detection
466
- is_mono, packages, scope_config, task_pkg, default_pkg = _load_trellis_config(trellis_dir)
576
+ is_mono, packages, scope_config, task_pkg, default_pkg = _load_trellis_config(
577
+ trellis_dir,
578
+ hook_input,
579
+ )
467
580
  allowed_pkgs = _resolve_spec_scope(is_mono, packages, scope_config, task_pkg, default_pkg)
468
581
 
469
582
  output = StringIO()
@@ -484,7 +597,7 @@ Read and follow all instructions below carefully.
484
597
 
485
598
  output.write("<current-state>\n")
486
599
  context_script = trellis_dir / "scripts" / "get_context.py"
487
- output.write(run_script(context_script))
600
+ output.write(run_script(context_script, context_key))
488
601
  output.write("\n</current-state>\n\n")
489
602
 
490
603
  output.write("<workflow>\n")
@@ -497,11 +610,13 @@ Read and follow all instructions below carefully.
497
610
  "**Pre-Development Checklist** listing the specific guideline files to "
498
611
  "read before coding.\n\n"
499
612
  "- If you're spawning an implement/check sub-agent, context is injected "
500
- "automatically via `{task}/implement.jsonl` / `check.jsonl`. You do NOT "
501
- "need to read these indexes yourself.\n"
502
- "- For agent-capable platforms, do NOT edit code directly in the main "
503
- "session; dispatch `trellis-implement` and `trellis-check` so JSONL "
504
- "context is loaded by the sub-agents.\n\n"
613
+ "or loaded by the sub-agent via `{task}/implement.jsonl` / `check.jsonl`. "
614
+ "You do NOT need to read these indexes yourself.\n"
615
+ "- For agent-capable platforms, the default is to dispatch "
616
+ "`trellis-implement` and `trellis-check` (so JSONL context is loaded by "
617
+ "the sub-agents) rather than editing code in the main session. "
618
+ "Honor a per-turn user override only if the user's current message "
619
+ "explicitly opts out (see <task-status> below for override phrases).\n\n"
505
620
  )
506
621
 
507
622
  # guides/ is cross-package thinking — always include inline (small, broadly useful)
@@ -553,7 +668,7 @@ Read and follow all instructions below carefully.
553
668
  output.write("</guidelines>\n\n")
554
669
 
555
670
  # Check task status and inject structured tag
556
- task_status = _get_task_status(trellis_dir)
671
+ task_status = _get_task_status(trellis_dir, hook_input)
557
672
  output.write(f"<task-status>\n{task_status}\n</task-status>\n\n")
558
673
 
559
674
  output.write("""<ready>
@@ -4,6 +4,9 @@
4
4
  # Current task pointer (each dev works on different task)
5
5
  .current-task
6
6
 
7
+ # Session/window scoped runtime state
8
+ .runtime/
9
+
7
10
  # Ralph Loop state file
8
11
  .ralph-state.json
9
12
 
@@ -22,6 +22,7 @@ export declare const commonDeveloper: string;
22
22
  export declare const commonGitContext: string;
23
23
  export declare const commonTaskQueue: string;
24
24
  export declare const commonTaskUtils: string;
25
+ export declare const commonActiveTask: string;
25
26
  export declare const commonCliAdapter: string;
26
27
  export declare const commonConfig: string;
27
28
  export declare const commonIo: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAcH,eAAO,MAAM,WAAW,QAAsC,CAAC;AAG/D,eAAO,MAAM,UAAU,QAA6C,CAAC;AACrE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,eAAe,QAA8C,CAAC;AAC3E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,YAAY,QAA2C,CAAC;AACrE,eAAO,MAAM,QAAQ,QAAuC,CAAC;AAC7D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,iBAAiB,QAAiD,CAAC;AAChF,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,oBAAoB,QAEhC,CAAC;AACF,eAAO,MAAM,qBAAqB,QAEjC,CAAC;AACF,eAAO,MAAM,mBAAmB,QAE/B,CAAC;AAGF,eAAO,MAAM,kBAAkB,QAA2C,CAAC;AAC3E,eAAO,MAAM,mBAAmB,QAA4C,CAAC;AAC7E,eAAO,MAAM,UAAU,QAAkC,CAAC;AAC1D,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AACvE,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AAGvE,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAC9D,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAC9D,eAAO,MAAM,iBAAiB,QAAgC,CAAC;AAE/D;;GAEG;AACH,wBAAgB,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAkCnD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAcH,eAAO,MAAM,WAAW,QAAsC,CAAC;AAG/D,eAAO,MAAM,UAAU,QAA6C,CAAC;AACrE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,eAAe,QAA8C,CAAC;AAC3E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,gBAAgB,QAAgD,CAAC;AAC9E,eAAO,MAAM,YAAY,QAA2C,CAAC;AACrE,eAAO,MAAM,QAAQ,QAAuC,CAAC;AAC7D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,SAAS,QAAwC,CAAC;AAC/D,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,WAAW,QAA0C,CAAC;AACnE,eAAO,MAAM,iBAAiB,QAAiD,CAAC;AAChF,eAAO,MAAM,eAAe,QAA+C,CAAC;AAC5E,eAAO,MAAM,oBAAoB,QAEhC,CAAC;AACF,eAAO,MAAM,qBAAqB,QAEjC,CAAC;AACF,eAAO,MAAM,mBAAmB,QAE/B,CAAC;AAGF,eAAO,MAAM,kBAAkB,QAA2C,CAAC;AAC3E,eAAO,MAAM,mBAAmB,QAA4C,CAAC;AAC7E,eAAO,MAAM,UAAU,QAAkC,CAAC;AAC1D,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AACvE,eAAO,MAAM,gBAAgB,QAAyC,CAAC;AAGvE,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAC9D,eAAO,MAAM,kBAAkB,QAA8B,CAAC;AAC9D,eAAO,MAAM,iBAAiB,QAAgC,CAAC;AAE/D;;GAEG;AACH,wBAAgB,aAAa,IAAI,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAmCnD"}
@@ -32,6 +32,7 @@ export const commonDeveloper = readTemplate("scripts/common/developer.py");
32
32
  export const commonGitContext = readTemplate("scripts/common/git_context.py");
33
33
  export const commonTaskQueue = readTemplate("scripts/common/task_queue.py");
34
34
  export const commonTaskUtils = readTemplate("scripts/common/task_utils.py");
35
+ export const commonActiveTask = readTemplate("scripts/common/active_task.py");
35
36
  export const commonCliAdapter = readTemplate("scripts/common/cli_adapter.py");
36
37
  export const commonConfig = readTemplate("scripts/common/config.py");
37
38
  export const commonIo = readTemplate("scripts/common/io.py");
@@ -68,6 +69,7 @@ export function getAllScripts() {
68
69
  scripts.set("common/git_context.py", commonGitContext);
69
70
  scripts.set("common/task_queue.py", commonTaskQueue);
70
71
  scripts.set("common/task_utils.py", commonTaskUtils);
72
+ scripts.set("common/active_task.py", commonActiveTask);
71
73
  scripts.set("common/cli_adapter.py", commonCliAdapter);
72
74
  scripts.set("common/config.py", commonConfig);
73
75
  scripts.set("common/io.py", commonIo);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/templates/trellis/index.ts"],"names":[],"mappings":"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"}
@@ -82,3 +82,11 @@ from .paths import (
82
82
  has_current_task,
83
83
  generate_task_date_prefix,
84
84
  )
85
+
86
+ from .active_task import (
87
+ ActiveTask,
88
+ clear_active_task,
89
+ resolve_active_task,
90
+ resolve_context_key,
91
+ set_active_task,
92
+ )