@mindfoldhq/trellis 0.5.0-beta.9 → 0.5.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -95
- package/dist/cli/index.js +7 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +117 -117
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +289 -33
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/antigravity.d.ts.map +1 -1
- package/dist/configurators/antigravity.js +2 -8
- package/dist/configurators/antigravity.js.map +1 -1
- package/dist/configurators/claude.d.ts.map +1 -1
- package/dist/configurators/claude.js +4 -10
- package/dist/configurators/claude.js.map +1 -1
- package/dist/configurators/codebuddy.d.ts.map +1 -1
- package/dist/configurators/codebuddy.js +3 -3
- package/dist/configurators/codebuddy.js.map +1 -1
- package/dist/configurators/codex.d.ts.map +1 -1
- package/dist/configurators/codex.js +5 -13
- package/dist/configurators/codex.js.map +1 -1
- package/dist/configurators/copilot.d.ts.map +1 -1
- package/dist/configurators/copilot.js +5 -19
- package/dist/configurators/copilot.js.map +1 -1
- package/dist/configurators/cursor.d.ts.map +1 -1
- package/dist/configurators/cursor.js +3 -3
- package/dist/configurators/cursor.js.map +1 -1
- package/dist/configurators/droid.d.ts.map +1 -1
- package/dist/configurators/droid.js +3 -3
- package/dist/configurators/droid.js.map +1 -1
- package/dist/configurators/gemini.d.ts.map +1 -1
- package/dist/configurators/gemini.js +3 -5
- package/dist/configurators/gemini.js.map +1 -1
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +37 -49
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/kilo.d.ts.map +1 -1
- package/dist/configurators/kilo.js +2 -8
- package/dist/configurators/kilo.js.map +1 -1
- package/dist/configurators/kiro.d.ts.map +1 -1
- package/dist/configurators/kiro.js +3 -3
- package/dist/configurators/kiro.js.map +1 -1
- package/dist/configurators/opencode.d.ts.map +1 -1
- package/dist/configurators/opencode.js +7 -4
- package/dist/configurators/opencode.js.map +1 -1
- package/dist/configurators/pi.d.ts +3 -0
- package/dist/configurators/pi.d.ts.map +1 -0
- package/dist/configurators/pi.js +44 -0
- package/dist/configurators/pi.js.map +1 -0
- package/dist/configurators/qoder.d.ts.map +1 -1
- package/dist/configurators/qoder.js +3 -5
- package/dist/configurators/qoder.js.map +1 -1
- package/dist/configurators/shared.d.ts +28 -6
- package/dist/configurators/shared.d.ts.map +1 -1
- package/dist/configurators/shared.js +47 -15
- package/dist/configurators/shared.js.map +1 -1
- package/dist/configurators/windsurf.d.ts.map +1 -1
- package/dist/configurators/windsurf.js +2 -8
- package/dist/configurators/windsurf.js.map +1 -1
- package/dist/constants/paths.d.ts +2 -0
- package/dist/constants/paths.d.ts.map +1 -1
- package/dist/constants/paths.js +2 -0
- package/dist/constants/paths.js.map +1 -1
- package/dist/migrations/manifests/0.5.0-beta.0.json +2 -0
- package/dist/migrations/manifests/0.5.0-beta.10.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.11.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.12.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.13.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.14.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.15.json +116 -0
- package/dist/migrations/manifests/0.5.0-beta.16.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.17.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.18.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.19.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.5.json +2 -0
- package/dist/migrations/manifests/0.5.0-rc.0.json +9 -0
- package/dist/templates/claude/agents/trellis-research.md +1 -1
- package/dist/templates/claude/settings.json +0 -4
- package/dist/templates/codebuddy/agents/trellis-research.md +1 -1
- package/dist/templates/codex/agents/trellis-research.toml +3 -2
- package/dist/templates/codex/hooks/session-start.py +126 -26
- package/dist/templates/codex/skills/finish-work/SKILL.md +41 -109
- package/dist/templates/codex/skills/start/SKILL.md +12 -9
- package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +73 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/add-project-local-conventions.md +83 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +54 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-context-loading.md +81 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-hooks.md +57 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +78 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-spec-structure.md +83 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-task-lifecycle.md +90 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-workflow.md +64 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/overview.md +55 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/context-injection.md +68 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +80 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/overview.md +51 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/spec-system.md +102 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/task-system.md +101 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/workflow.md +75 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/workspace-memory.md +71 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +79 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +69 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +59 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +74 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +83 -0
- package/dist/templates/common/commands/continue.md +9 -5
- package/dist/templates/common/commands/finish-work.md +34 -10
- package/dist/templates/common/index.d.ts +22 -2
- package/dist/templates/common/index.d.ts.map +1 -1
- package/dist/templates/common/index.js +53 -4
- package/dist/templates/common/index.js.map +1 -1
- package/dist/templates/common/skills/brainstorm.md +3 -0
- package/dist/templates/copilot/hooks/session-start.py +127 -30
- package/dist/templates/copilot/prompts/finish-work.prompt.md +44 -112
- package/dist/templates/copilot/prompts/start.prompt.md +12 -9
- package/dist/templates/cursor/agents/trellis-check.md +1 -1
- package/dist/templates/cursor/agents/trellis-implement.md +1 -1
- package/dist/templates/cursor/agents/trellis-research.md +2 -2
- package/dist/templates/cursor/hooks.json +7 -1
- package/dist/templates/droid/droids/trellis-research.md +1 -1
- package/dist/templates/extract.d.ts +6 -0
- package/dist/templates/extract.d.ts.map +1 -1
- package/dist/templates/extract.js +14 -0
- package/dist/templates/extract.js.map +1 -1
- package/dist/templates/gemini/agents/trellis-research.md +1 -1
- package/dist/templates/kiro/agents/trellis-research.json +1 -1
- package/dist/templates/markdown/agents.md +19 -12
- package/dist/templates/markdown/gitignore.txt +3 -0
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +24 -0
- package/dist/templates/opencode/agents/trellis-check.md +1 -1
- package/dist/templates/opencode/agents/trellis-implement.md +7 -4
- package/dist/templates/opencode/agents/trellis-research.md +2 -2
- package/dist/templates/opencode/lib/trellis-context.js +100 -13
- package/dist/templates/opencode/plugins/inject-subagent-context.js +70 -5
- package/dist/templates/opencode/plugins/inject-workflow-state.js +38 -58
- package/dist/templates/opencode/plugins/session-start.js +76 -31
- package/dist/templates/pi/agents/trellis-check.md +28 -0
- package/dist/templates/pi/agents/trellis-implement.md +33 -0
- package/dist/templates/pi/agents/trellis-research.md +25 -0
- package/dist/templates/pi/extensions/trellis/index.ts.txt +997 -0
- package/dist/templates/pi/index.d.ts +5 -0
- package/dist/templates/pi/index.d.ts.map +1 -0
- package/dist/templates/pi/index.js +12 -0
- package/dist/templates/pi/index.js.map +1 -0
- package/dist/templates/pi/settings.json +12 -0
- package/dist/templates/qoder/agents/trellis-research.md +1 -1
- package/dist/templates/shared-hooks/index.d.ts +31 -0
- package/dist/templates/shared-hooks/index.d.ts.map +1 -1
- package/dist/templates/shared-hooks/index.js +59 -0
- package/dist/templates/shared-hooks/index.js.map +1 -1
- package/dist/templates/shared-hooks/inject-shell-session-context.py +180 -0
- package/dist/templates/shared-hooks/inject-subagent-context.py +156 -27
- package/dist/templates/shared-hooks/inject-workflow-state.py +85 -105
- package/dist/templates/shared-hooks/session-start.py +222 -36
- package/dist/templates/trellis/gitignore.txt +3 -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/common/__init__.py +8 -0
- package/dist/templates/trellis/scripts/common/active_task.py +593 -0
- package/dist/templates/trellis/scripts/common/cli_adapter.py +72 -14
- package/dist/templates/trellis/scripts/common/paths.py +61 -58
- package/dist/templates/trellis/scripts/common/session_context.py +12 -0
- package/dist/templates/trellis/scripts/common/task_context.py +27 -194
- package/dist/templates/trellis/scripts/common/task_store.py +102 -26
- package/dist/templates/trellis/scripts/common/tasks.py +4 -1
- package/dist/templates/trellis/scripts/common/workflow_phase.py +15 -3
- package/dist/templates/trellis/scripts/task.py +99 -34
- package/dist/templates/trellis/workflow.md +332 -69
- package/dist/types/ai-tools.d.ts +12 -3
- package/dist/types/ai-tools.d.ts.map +1 -1
- package/dist/types/ai-tools.js +29 -0
- package/dist/types/ai-tools.js.map +1 -1
- package/dist/utils/file-writer.d.ts.map +1 -1
- package/dist/utils/file-writer.js +7 -2
- package/dist/utils/file-writer.js.map +1 -1
- package/dist/utils/posix.d.ts +13 -0
- package/dist/utils/posix.d.ts.map +1 -0
- package/dist/utils/posix.js +15 -0
- package/dist/utils/posix.js.map +1 -0
- package/dist/utils/template-fetcher.d.ts +22 -6
- package/dist/utils/template-fetcher.d.ts.map +1 -1
- package/dist/utils/template-fetcher.js +405 -27
- package/dist/utils/template-fetcher.js.map +1 -1
- package/dist/utils/template-hash.d.ts +22 -3
- package/dist/utils/template-hash.d.ts.map +1 -1
- package/dist/utils/template-hash.js +99 -19
- package/dist/utils/template-hash.js.map +1 -1
- package/package.json +7 -7
- package/dist/templates/shared-hooks/statusline.py +0 -218
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
"""Trellis UserPromptSubmit hook: inject per-turn workflow breadcrumb.
|
|
3
3
|
|
|
4
|
-
Runs on every user prompt.
|
|
5
|
-
and emits a short <workflow-state>
|
|
6
|
-
is active and its expected flow.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
Runs on every user prompt. Resolves the active task through Trellis'
|
|
5
|
+
session-aware active task resolver and emits a short <workflow-state>
|
|
6
|
+
block reminding the main AI what task is active and its expected flow.
|
|
7
|
+
Breadcrumb text is pulled exclusively from workflow.md
|
|
8
|
+
[workflow-state:STATUS] tag blocks — workflow.md is the single source of
|
|
9
|
+
truth. There are no fallback dicts in this script: when workflow.md is
|
|
10
|
+
missing or a tag is absent, the breadcrumb degrades to a generic
|
|
11
|
+
"Refer to workflow.md for current step." line so users see (and fix)
|
|
12
|
+
the broken state instead of the hook silently masking it.
|
|
10
13
|
|
|
11
14
|
Shared across all hook-capable platforms (Claude, Cursor, Codex, Qoder,
|
|
12
15
|
CodeBuddy, Droid, Gemini, Copilot). Kiro is not wired (no per-turn
|
|
@@ -15,12 +18,7 @@ writeSharedHooks() at init time.
|
|
|
15
18
|
|
|
16
19
|
Silent exit 0 cases (no output):
|
|
17
20
|
- No .trellis/ directory found (not a Trellis project)
|
|
18
|
-
- No .current-task file, or it's empty
|
|
19
21
|
- task.json malformed or missing status
|
|
20
|
-
|
|
21
|
-
Unknown status (no tag + no hardcoded fallback) emits a generic
|
|
22
|
-
breadcrumb rather than silent-exiting, so custom statuses surface in
|
|
23
|
-
the UI instead of appearing as "randomly broken".
|
|
24
22
|
"""
|
|
25
23
|
from __future__ import annotations
|
|
26
24
|
|
|
@@ -29,7 +27,7 @@ import os
|
|
|
29
27
|
import re
|
|
30
28
|
import sys
|
|
31
29
|
from pathlib import Path
|
|
32
|
-
from typing import Optional
|
|
30
|
+
from typing import Optional
|
|
33
31
|
|
|
34
32
|
|
|
35
33
|
# ---------------------------------------------------------------------------
|
|
@@ -54,48 +52,63 @@ def find_trellis_root(start: Path) -> Optional[Path]:
|
|
|
54
52
|
# Active task discovery
|
|
55
53
|
# ---------------------------------------------------------------------------
|
|
56
54
|
|
|
57
|
-
def
|
|
58
|
-
""
|
|
55
|
+
def _detect_platform(input_data: dict) -> str | None:
|
|
56
|
+
if isinstance(input_data.get("cursor_version"), str):
|
|
57
|
+
return "cursor"
|
|
58
|
+
env_map = {
|
|
59
|
+
"CLAUDE_PROJECT_DIR": "claude",
|
|
60
|
+
"CURSOR_PROJECT_DIR": "cursor",
|
|
61
|
+
"CODEBUDDY_PROJECT_DIR": "codebuddy",
|
|
62
|
+
"FACTORY_PROJECT_DIR": "droid",
|
|
63
|
+
"GEMINI_PROJECT_DIR": "gemini",
|
|
64
|
+
"QODER_PROJECT_DIR": "qoder",
|
|
65
|
+
"KIRO_PROJECT_DIR": "kiro",
|
|
66
|
+
"COPILOT_PROJECT_DIR": "copilot",
|
|
67
|
+
}
|
|
68
|
+
for env_name, platform in env_map.items():
|
|
69
|
+
if os.environ.get(env_name):
|
|
70
|
+
return platform
|
|
71
|
+
script_parts = set(Path(sys.argv[0]).parts)
|
|
72
|
+
if ".claude" in script_parts:
|
|
73
|
+
return "claude"
|
|
74
|
+
if ".cursor" in script_parts:
|
|
75
|
+
return "cursor"
|
|
76
|
+
if ".codex" in script_parts:
|
|
77
|
+
return "codex"
|
|
78
|
+
if ".gemini" in script_parts:
|
|
79
|
+
return "gemini"
|
|
80
|
+
if ".qoder" in script_parts:
|
|
81
|
+
return "qoder"
|
|
82
|
+
if ".codebuddy" in script_parts:
|
|
83
|
+
return "codebuddy"
|
|
84
|
+
if ".factory" in script_parts:
|
|
85
|
+
return "droid"
|
|
86
|
+
if ".kiro" in script_parts:
|
|
87
|
+
return "kiro"
|
|
88
|
+
return None
|
|
59
89
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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:
|
|
90
|
+
|
|
91
|
+
def _resolve_active_task(root: Path, input_data: dict):
|
|
92
|
+
scripts_dir = root / ".trellis" / "scripts"
|
|
93
|
+
if str(scripts_dir) not in sys.path:
|
|
94
|
+
sys.path.insert(0, str(scripts_dir))
|
|
95
|
+
from common.active_task import resolve_active_task # type: ignore[import-not-found]
|
|
96
|
+
|
|
97
|
+
return resolve_active_task(root, input_data, platform=_detect_platform(input_data))
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def get_active_task(root: Path, input_data: dict) -> Optional[tuple[str, str, str]]:
|
|
101
|
+
"""Return (task_id, status, source) from the current active task."""
|
|
102
|
+
active = _resolve_active_task(root, input_data)
|
|
103
|
+
if not active.task_path:
|
|
95
104
|
return None
|
|
96
105
|
|
|
97
|
-
|
|
98
|
-
|
|
106
|
+
task_dir = Path(active.task_path)
|
|
107
|
+
if not task_dir.is_absolute():
|
|
108
|
+
task_dir = root / task_dir
|
|
109
|
+
if active.stale:
|
|
110
|
+
return task_dir.name, f"stale_{active.source_type}", active.source
|
|
111
|
+
|
|
99
112
|
task_json = task_dir / "task.json"
|
|
100
113
|
if not task_json.is_file():
|
|
101
114
|
return None
|
|
@@ -108,7 +121,7 @@ def get_active_task(root: Path) -> Optional[Tuple[str, str]]:
|
|
|
108
121
|
status = data.get("status", "")
|
|
109
122
|
if not isinstance(status, str) or not status:
|
|
110
123
|
return None
|
|
111
|
-
return task_id, status
|
|
124
|
+
return task_id, status, active.source
|
|
112
125
|
|
|
113
126
|
|
|
114
127
|
# ---------------------------------------------------------------------------
|
|
@@ -122,64 +135,24 @@ _TAG_RE = re.compile(
|
|
|
122
135
|
re.DOTALL,
|
|
123
136
|
)
|
|
124
137
|
|
|
125
|
-
# Hardcoded defaults for built-in Trellis statuses. Used when workflow.md is
|
|
126
|
-
# missing, malformed, or lacks the tag for this status.
|
|
127
|
-
#
|
|
128
|
-
# `no_task` is a pseudo-status emitted when .current-task is missing — it keeps
|
|
129
|
-
# the Next-Action reminder flowing per-turn even without an active task.
|
|
130
|
-
_FALLBACK_BREADCRUMBS = {
|
|
131
|
-
"no_task": (
|
|
132
|
-
"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"
|
|
142
|
-
"Flow: load `trellis-brainstorm` skill → it creates the task via "
|
|
143
|
-
"`python3 ./.trellis/scripts/task.py create` and drives requirements Q&A. "
|
|
144
|
-
"For research-heavy work (tool comparison, docs, cross-platform survey), "
|
|
145
|
-
"spawn `trellis-research` sub-agents via Task tool — NEVER do 3+ inline "
|
|
146
|
-
"WebFetch/WebSearch/`gh api` calls in the main conversation."
|
|
147
|
-
),
|
|
148
|
-
"planning": (
|
|
149
|
-
"Complete prd.md via trellis-brainstorm skill; then run task.py start.\n"
|
|
150
|
-
"Research belongs in `{task_dir}/research/*.md`, written by "
|
|
151
|
-
"`trellis-research` sub-agents. Do NOT inline WebFetch/WebSearch in "
|
|
152
|
-
"main session — PRD only links to research files."
|
|
153
|
-
),
|
|
154
|
-
"in_progress": (
|
|
155
|
-
"Flow: trellis-implement → trellis-check → trellis-update-spec → finish\n"
|
|
156
|
-
"Check conversation history + git status to determine current step; "
|
|
157
|
-
"do NOT skip trellis-check."
|
|
158
|
-
),
|
|
159
|
-
"completed": (
|
|
160
|
-
"User commits changes; then run task.py archive."
|
|
161
|
-
),
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
|
|
165
138
|
def load_breadcrumbs(root: Path) -> dict[str, str]:
|
|
166
139
|
"""Parse workflow.md for [workflow-state:STATUS] blocks.
|
|
167
140
|
|
|
168
|
-
Returns {status: body_text}.
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
141
|
+
Returns {status: body_text}. workflow.md is the single source of
|
|
142
|
+
truth — there are no fallback dicts in this script. Missing tags
|
|
143
|
+
(or a missing/unreadable workflow.md) fall back to a generic line
|
|
144
|
+
in build_breadcrumb so users see the broken state and fix
|
|
145
|
+
workflow.md, rather than the hook silently masking the issue.
|
|
172
146
|
"""
|
|
173
|
-
result = dict(_FALLBACK_BREADCRUMBS)
|
|
174
|
-
|
|
175
147
|
workflow = root / ".trellis" / "workflow.md"
|
|
176
148
|
if not workflow.is_file():
|
|
177
|
-
return
|
|
149
|
+
return {}
|
|
178
150
|
try:
|
|
179
151
|
content = workflow.read_text(encoding="utf-8")
|
|
180
152
|
except OSError:
|
|
181
|
-
return
|
|
153
|
+
return {}
|
|
182
154
|
|
|
155
|
+
result: dict[str, str] = {}
|
|
183
156
|
for match in _TAG_RE.finditer(content):
|
|
184
157
|
status = match.group(1)
|
|
185
158
|
body = match.group(2).strip()
|
|
@@ -189,18 +162,24 @@ def load_breadcrumbs(root: Path) -> dict[str, str]:
|
|
|
189
162
|
|
|
190
163
|
|
|
191
164
|
def build_breadcrumb(
|
|
192
|
-
task_id: Optional[str],
|
|
165
|
+
task_id: Optional[str],
|
|
166
|
+
status: str,
|
|
167
|
+
templates: dict[str, str],
|
|
168
|
+
source: str | None = None,
|
|
193
169
|
) -> str:
|
|
194
170
|
"""Build the <workflow-state>...</workflow-state> block.
|
|
195
171
|
|
|
196
|
-
- Known status (
|
|
197
|
-
- Unknown status (no tag
|
|
172
|
+
- Known status (tag present in workflow.md) → detailed template body
|
|
173
|
+
- Unknown status (no tag, or workflow.md missing) → generic
|
|
174
|
+
"Refer to workflow.md for current step." line
|
|
198
175
|
- `no_task` pseudo-status (task_id is None) → header omits task info
|
|
199
176
|
"""
|
|
200
177
|
body = templates.get(status)
|
|
201
178
|
if body is None:
|
|
202
179
|
body = "Refer to workflow.md for current step."
|
|
203
180
|
header = f"Status: {status}" if task_id is None else f"Task: {task_id} ({status})"
|
|
181
|
+
if source:
|
|
182
|
+
header = f"{header}\nSource: {source}"
|
|
204
183
|
return f"<workflow-state>\n{header}\n{body}\n</workflow-state>"
|
|
205
184
|
|
|
206
185
|
|
|
@@ -222,13 +201,14 @@ def main() -> int:
|
|
|
222
201
|
return 0 # not a Trellis project
|
|
223
202
|
|
|
224
203
|
templates = load_breadcrumbs(root)
|
|
225
|
-
task = get_active_task(root)
|
|
204
|
+
task = get_active_task(root, data)
|
|
226
205
|
if task is None:
|
|
227
206
|
# No active task — still emit a breadcrumb nudging AI toward
|
|
228
207
|
# trellis-brainstorm + task.py create when user describes real work.
|
|
229
208
|
breadcrumb = build_breadcrumb(None, "no_task", templates)
|
|
230
209
|
else:
|
|
231
|
-
|
|
210
|
+
task_id, status, source = task
|
|
211
|
+
breadcrumb = build_breadcrumb(task_id, status, templates, source)
|
|
232
212
|
|
|
233
213
|
output = {
|
|
234
214
|
"hookSpecificOutput": {
|