@mindfoldhq/trellis 0.4.0 → 0.5.0-beta.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 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +10 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +382 -120
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/update.d.ts +5 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +178 -61
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/antigravity.d.ts +3 -4
- package/dist/configurators/antigravity.d.ts.map +1 -1
- package/dist/configurators/antigravity.js +17 -10
- package/dist/configurators/antigravity.js.map +1 -1
- package/dist/configurators/claude.d.ts +5 -28
- package/dist/configurators/claude.d.ts.map +1 -1
- package/dist/configurators/claude.js +30 -51
- package/dist/configurators/claude.js.map +1 -1
- package/dist/configurators/codebuddy.d.ts +6 -7
- package/dist/configurators/codebuddy.d.ts.map +1 -1
- package/dist/configurators/codebuddy.js +23 -51
- package/dist/configurators/codebuddy.js.map +1 -1
- package/dist/configurators/codex.d.ts +3 -6
- package/dist/configurators/codex.d.ts.map +1 -1
- package/dist/configurators/codex.js +29 -12
- package/dist/configurators/codex.js.map +1 -1
- package/dist/configurators/copilot.d.ts +6 -5
- package/dist/configurators/copilot.d.ts.map +1 -1
- package/dist/configurators/copilot.js +42 -13
- package/dist/configurators/copilot.js.map +1 -1
- package/dist/configurators/cursor.d.ts +6 -1
- package/dist/configurators/cursor.d.ts.map +1 -1
- package/dist/configurators/cursor.js +22 -45
- package/dist/configurators/cursor.js.map +1 -1
- package/dist/configurators/droid.d.ts +6 -1
- package/dist/configurators/droid.d.ts.map +1 -1
- package/dist/configurators/droid.js +23 -41
- package/dist/configurators/droid.js.map +1 -1
- package/dist/configurators/gemini.d.ts +8 -4
- package/dist/configurators/gemini.d.ts.map +1 -1
- package/dist/configurators/gemini.js +28 -47
- package/dist/configurators/gemini.js.map +1 -1
- package/dist/configurators/index.d.ts +1 -1
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +146 -100
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/kilo.d.ts +3 -4
- package/dist/configurators/kilo.d.ts.map +1 -1
- package/dist/configurators/kilo.js +19 -46
- package/dist/configurators/kilo.js.map +1 -1
- package/dist/configurators/kiro.d.ts +4 -4
- package/dist/configurators/kiro.d.ts.map +1 -1
- package/dist/configurators/kiro.js +18 -14
- package/dist/configurators/kiro.js.map +1 -1
- package/dist/configurators/opencode.d.ts +7 -25
- package/dist/configurators/opencode.d.ts.map +1 -1
- package/dist/configurators/opencode.js +57 -56
- package/dist/configurators/opencode.js.map +1 -1
- package/dist/configurators/qoder.d.ts +6 -3
- package/dist/configurators/qoder.d.ts.map +1 -1
- package/dist/configurators/qoder.js +27 -46
- package/dist/configurators/qoder.js.map +1 -1
- package/dist/configurators/shared.d.ts +68 -3
- package/dist/configurators/shared.d.ts.map +1 -1
- package/dist/configurators/shared.js +274 -3
- package/dist/configurators/shared.js.map +1 -1
- package/dist/configurators/windsurf.d.ts +3 -4
- package/dist/configurators/windsurf.d.ts.map +1 -1
- package/dist/configurators/windsurf.js +17 -10
- package/dist/configurators/windsurf.js.map +1 -1
- package/dist/configurators/workflow.d.ts +0 -3
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +1 -7
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/migrations/manifests/0.4.0.json +1 -1
- package/dist/migrations/manifests/0.5.0-beta.0.json +1646 -0
- package/dist/migrations/manifests/0.5.0-beta.1.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.2.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.3.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.4.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.5.json +222 -0
- package/dist/migrations/manifests/0.5.0-beta.6.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.7.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.8.json +9 -0
- package/dist/migrations/manifests/0.5.0-beta.9.json +48 -0
- package/dist/templates/claude/agents/{check.md → trellis-check.md} +3 -31
- package/dist/templates/claude/agents/{implement.md → trellis-implement.md} +1 -2
- package/dist/templates/claude/agents/trellis-research.md +137 -0
- package/dist/templates/claude/index.d.ts +5 -37
- package/dist/templates/claude/index.d.ts.map +1 -1
- package/dist/templates/claude/index.js +3 -42
- package/dist/templates/claude/index.js.map +1 -1
- package/dist/templates/claude/settings.json +6 -4
- package/dist/templates/{iflow/agents/check.md → codebuddy/agents/trellis-check.md} +3 -31
- package/dist/templates/{iflow/agents/implement.md → codebuddy/agents/trellis-implement.md} +1 -2
- package/dist/templates/codebuddy/agents/trellis-research.md +137 -0
- package/dist/templates/codebuddy/index.d.ts +6 -16
- package/dist/templates/codebuddy/index.d.ts.map +1 -1
- package/dist/templates/codebuddy/index.js +6 -36
- package/dist/templates/codebuddy/index.js.map +1 -1
- package/dist/templates/codebuddy/settings.json +59 -0
- package/dist/templates/codex/agents/trellis-check.toml +38 -0
- package/dist/templates/codex/agents/{implement.toml → trellis-implement.toml} +1 -1
- package/dist/templates/codex/agents/trellis-research.toml +60 -0
- package/dist/templates/codex/config.toml +10 -0
- package/dist/templates/codex/hooks/session-start.py +65 -29
- package/dist/templates/codex/hooks.json +11 -0
- package/dist/templates/codex/index.d.ts +0 -1
- package/dist/templates/codex/index.d.ts.map +1 -1
- package/dist/templates/codex/index.js +1 -8
- package/dist/templates/codex/index.js.map +1 -1
- package/dist/templates/codex/skills/start/SKILL.md +1 -1
- package/dist/templates/common/commands/continue.md +51 -0
- package/dist/templates/common/commands/finish-work.md +32 -0
- package/dist/templates/common/commands/start.md +56 -0
- package/dist/templates/common/index.d.ts +28 -0
- package/dist/templates/common/index.d.ts.map +1 -0
- package/dist/templates/common/index.js +55 -0
- package/dist/templates/common/index.js.map +1 -0
- package/dist/templates/{droid/commands/trellis → common/skills}/brainstorm.md +51 -12
- package/dist/templates/{iflow/commands/trellis → common/skills}/break-loop.md +4 -4
- package/dist/templates/common/skills/check.md +87 -0
- package/dist/templates/{codebuddy/commands/trellis → common/skills}/update-spec.md +18 -21
- package/dist/templates/copilot/hooks/session-start.py +65 -29
- package/dist/templates/copilot/hooks.json +8 -0
- package/dist/templates/copilot/prompts/start.prompt.md +13 -16
- package/dist/templates/cursor/agents/trellis-check.md +94 -0
- package/dist/templates/cursor/agents/trellis-implement.md +94 -0
- package/dist/templates/cursor/agents/trellis-research.md +137 -0
- package/dist/templates/cursor/hooks.json +24 -0
- package/dist/templates/cursor/index.d.ts +6 -17
- package/dist/templates/cursor/index.d.ts.map +1 -1
- package/dist/templates/cursor/index.js +6 -37
- package/dist/templates/cursor/index.js.map +1 -1
- package/dist/templates/droid/droids/trellis-check.md +94 -0
- package/dist/templates/droid/droids/trellis-implement.md +94 -0
- package/dist/templates/droid/droids/trellis-research.md +137 -0
- package/dist/templates/droid/index.d.ts +7 -19
- package/dist/templates/droid/index.d.ts.map +1 -1
- package/dist/templates/droid/index.js +7 -39
- package/dist/templates/droid/index.js.map +1 -1
- package/dist/templates/droid/settings.json +59 -0
- package/dist/templates/extract.d.ts +7 -193
- package/dist/templates/extract.d.ts.map +1 -1
- package/dist/templates/extract.js +7 -310
- package/dist/templates/extract.js.map +1 -1
- package/dist/templates/gemini/agents/trellis-check.md +94 -0
- package/dist/templates/gemini/agents/trellis-implement.md +94 -0
- package/dist/templates/gemini/agents/trellis-research.md +137 -0
- package/dist/templates/gemini/index.d.ts +6 -14
- package/dist/templates/gemini/index.d.ts.map +1 -1
- package/dist/templates/gemini/index.js +6 -37
- package/dist/templates/gemini/index.js.map +1 -1
- package/dist/templates/gemini/settings.json +28 -0
- package/dist/templates/kiro/agents/trellis-check.json +13 -0
- package/dist/templates/kiro/agents/trellis-implement.json +13 -0
- package/dist/templates/kiro/agents/trellis-research.json +21 -0
- package/dist/templates/kiro/index.d.ts +11 -11
- package/dist/templates/kiro/index.d.ts.map +1 -1
- package/dist/templates/kiro/index.js +11 -33
- package/dist/templates/kiro/index.js.map +1 -1
- package/dist/templates/opencode/agents/{check.md → trellis-check.md} +3 -30
- package/dist/templates/opencode/agents/{implement.md → trellis-implement.md} +1 -1
- package/dist/templates/opencode/agents/{research.md → trellis-research.md} +1 -2
- package/dist/templates/opencode/plugins/inject-subagent-context.js +18 -190
- package/dist/templates/opencode/plugins/inject-workflow-state.js +172 -0
- package/dist/templates/opencode/plugins/session-start.js +76 -39
- package/dist/templates/qoder/agents/trellis-check.md +94 -0
- package/dist/templates/qoder/agents/trellis-implement.md +94 -0
- package/dist/templates/qoder/agents/trellis-research.md +137 -0
- package/dist/templates/qoder/index.d.ts +7 -10
- package/dist/templates/qoder/index.d.ts.map +1 -1
- package/dist/templates/qoder/index.js +7 -32
- package/dist/templates/qoder/index.js.map +1 -1
- package/dist/templates/qoder/settings.json +47 -0
- package/dist/templates/shared-hooks/index.d.ts +19 -0
- package/dist/templates/shared-hooks/index.d.ts.map +1 -0
- package/dist/templates/shared-hooks/index.js +30 -0
- package/dist/templates/shared-hooks/index.js.map +1 -0
- package/dist/templates/{iflow/hooks → shared-hooks}/inject-subagent-context.py +77 -266
- package/dist/templates/shared-hooks/inject-workflow-state.py +244 -0
- package/dist/templates/{claude/hooks → shared-hooks}/session-start.py +172 -55
- package/dist/templates/template-utils.d.ts +26 -0
- package/dist/templates/template-utils.d.ts.map +1 -0
- package/dist/templates/template-utils.js +60 -0
- package/dist/templates/template-utils.js.map +1 -0
- package/dist/templates/trellis/config.yaml +6 -0
- package/dist/templates/trellis/index.d.ts +1 -15
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +2 -29
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/common/cli_adapter.py +31 -8
- package/dist/templates/trellis/scripts/common/config.py +126 -1
- package/dist/templates/trellis/scripts/common/git_context.py +25 -2
- package/dist/templates/trellis/scripts/common/task_context.py +23 -28
- package/dist/templates/trellis/scripts/common/task_store.py +0 -12
- package/dist/templates/trellis/scripts/common/types.py +0 -2
- package/dist/templates/trellis/scripts/common/workflow_phase.py +176 -0
- package/dist/templates/trellis/scripts/task.py +13 -35
- package/dist/templates/trellis/workflow.md +283 -298
- package/dist/types/ai-tools.d.ts +30 -3
- package/dist/types/ai-tools.d.ts.map +1 -1
- package/dist/types/ai-tools.js +119 -15
- package/dist/types/ai-tools.js.map +1 -1
- package/dist/types/migration.d.ts +8 -1
- package/dist/types/migration.d.ts.map +1 -1
- package/dist/utils/project-detector.d.ts +2 -0
- package/dist/utils/project-detector.d.ts.map +1 -1
- package/dist/utils/project-detector.js +120 -11
- package/dist/utils/project-detector.js.map +1 -1
- package/dist/utils/task-json.d.ts +46 -0
- package/dist/utils/task-json.d.ts.map +1 -0
- package/dist/utils/task-json.js +49 -0
- package/dist/utils/task-json.js.map +1 -0
- package/package.json +3 -2
- package/dist/configurators/iflow.d.ts +0 -33
- package/dist/configurators/iflow.d.ts.map +0 -1
- package/dist/configurators/iflow.js +0 -99
- package/dist/configurators/iflow.js.map +0 -1
- package/dist/templates/antigravity/index.d.ts +0 -12
- package/dist/templates/antigravity/index.d.ts.map +0 -1
- package/dist/templates/antigravity/index.js +0 -29
- package/dist/templates/antigravity/index.js.map +0 -1
- package/dist/templates/claude/agents/debug.md +0 -106
- package/dist/templates/claude/agents/dispatch.md +0 -213
- package/dist/templates/claude/agents/plan.md +0 -396
- package/dist/templates/claude/agents/research.md +0 -120
- package/dist/templates/claude/commands/trellis/brainstorm.md +0 -487
- package/dist/templates/claude/commands/trellis/break-loop.md +0 -125
- package/dist/templates/claude/commands/trellis/check-cross-layer.md +0 -153
- package/dist/templates/claude/commands/trellis/check.md +0 -25
- package/dist/templates/claude/commands/trellis/create-command.md +0 -154
- package/dist/templates/claude/commands/trellis/finish-work.md +0 -153
- package/dist/templates/claude/commands/trellis/integrate-skill.md +0 -219
- package/dist/templates/claude/commands/trellis/onboard.md +0 -358
- package/dist/templates/claude/commands/trellis/parallel.md +0 -192
- package/dist/templates/claude/commands/trellis/record-session.md +0 -62
- package/dist/templates/claude/commands/trellis/start.md +0 -393
- package/dist/templates/claude/commands/trellis/update-spec.md +0 -354
- package/dist/templates/claude/hooks/inject-subagent-context.py +0 -803
- package/dist/templates/claude/hooks/ralph-loop.py +0 -396
- package/dist/templates/codebuddy/commands/trellis/before-dev.md +0 -29
- package/dist/templates/codebuddy/commands/trellis/brainstorm.md +0 -487
- package/dist/templates/codebuddy/commands/trellis/break-loop.md +0 -107
- package/dist/templates/codebuddy/commands/trellis/check-cross-layer.md +0 -153
- package/dist/templates/codebuddy/commands/trellis/check.md +0 -25
- package/dist/templates/codebuddy/commands/trellis/create-command.md +0 -154
- package/dist/templates/codebuddy/commands/trellis/finish-work.md +0 -143
- package/dist/templates/codebuddy/commands/trellis/integrate-skill.md +0 -219
- package/dist/templates/codebuddy/commands/trellis/onboard.md +0 -358
- package/dist/templates/codebuddy/commands/trellis/record-session.md +0 -61
- package/dist/templates/codebuddy/commands/trellis/start.md +0 -373
- package/dist/templates/codex/agents/check.toml +0 -23
- package/dist/templates/codex/agents/research.toml +0 -26
- package/dist/templates/codex/codex-skills/parallel/SKILL.md +0 -194
- package/dist/templates/cursor/commands/trellis-before-dev.md +0 -29
- package/dist/templates/cursor/commands/trellis-brainstorm.md +0 -487
- package/dist/templates/cursor/commands/trellis-break-loop.md +0 -107
- package/dist/templates/cursor/commands/trellis-check-cross-layer.md +0 -153
- package/dist/templates/cursor/commands/trellis-check.md +0 -25
- package/dist/templates/cursor/commands/trellis-create-command.md +0 -154
- package/dist/templates/cursor/commands/trellis-finish-work.md +0 -143
- package/dist/templates/cursor/commands/trellis-integrate-skill.md +0 -219
- package/dist/templates/cursor/commands/trellis-onboard.md +0 -358
- package/dist/templates/cursor/commands/trellis-record-session.md +0 -62
- package/dist/templates/cursor/commands/trellis-start.md +0 -373
- package/dist/templates/cursor/commands/trellis-update-spec.md +0 -354
- package/dist/templates/droid/commands/trellis/before-dev.md +0 -33
- package/dist/templates/droid/commands/trellis/break-loop.md +0 -111
- package/dist/templates/droid/commands/trellis/check-cross-layer.md +0 -157
- package/dist/templates/droid/commands/trellis/check.md +0 -29
- package/dist/templates/droid/commands/trellis/create-command.md +0 -158
- package/dist/templates/droid/commands/trellis/finish-work.md +0 -147
- package/dist/templates/droid/commands/trellis/integrate-skill.md +0 -223
- package/dist/templates/droid/commands/trellis/onboard.md +0 -362
- package/dist/templates/droid/commands/trellis/record-session.md +0 -66
- package/dist/templates/droid/commands/trellis/start.md +0 -377
- package/dist/templates/droid/commands/trellis/update-spec.md +0 -358
- package/dist/templates/gemini/commands/trellis/before-dev.toml +0 -33
- package/dist/templates/gemini/commands/trellis/brainstorm.toml +0 -435
- package/dist/templates/gemini/commands/trellis/break-loop.toml +0 -129
- package/dist/templates/gemini/commands/trellis/check-cross-layer.toml +0 -147
- package/dist/templates/gemini/commands/trellis/check.toml +0 -29
- package/dist/templates/gemini/commands/trellis/create-command.toml +0 -119
- package/dist/templates/gemini/commands/trellis/finish-work.toml +0 -133
- package/dist/templates/gemini/commands/trellis/integrate-skill.toml +0 -104
- package/dist/templates/gemini/commands/trellis/onboard.toml +0 -111
- package/dist/templates/gemini/commands/trellis/record-session.toml +0 -66
- package/dist/templates/gemini/commands/trellis/start.toml +0 -354
- package/dist/templates/gemini/commands/trellis/update-spec.toml +0 -132
- package/dist/templates/iflow/agents/debug.md +0 -106
- package/dist/templates/iflow/agents/dispatch.md +0 -213
- package/dist/templates/iflow/agents/plan.md +0 -396
- package/dist/templates/iflow/agents/research.md +0 -120
- package/dist/templates/iflow/commands/trellis/before-dev.md +0 -29
- package/dist/templates/iflow/commands/trellis/brainstorm.md +0 -487
- package/dist/templates/iflow/commands/trellis/check-cross-layer.md +0 -153
- package/dist/templates/iflow/commands/trellis/check.md +0 -25
- package/dist/templates/iflow/commands/trellis/create-command.md +0 -152
- package/dist/templates/iflow/commands/trellis/finish-work.md +0 -153
- package/dist/templates/iflow/commands/trellis/integrate-skill.md +0 -219
- package/dist/templates/iflow/commands/trellis/onboard.md +0 -358
- package/dist/templates/iflow/commands/trellis/parallel.md +0 -192
- package/dist/templates/iflow/commands/trellis/record-session.md +0 -62
- package/dist/templates/iflow/commands/trellis/start.md +0 -393
- package/dist/templates/iflow/commands/trellis/update-spec.md +0 -354
- package/dist/templates/iflow/hooks/ralph-loop.py +0 -395
- package/dist/templates/iflow/hooks/session-start.py +0 -403
- package/dist/templates/iflow/index.d.ts +0 -54
- package/dist/templates/iflow/index.d.ts.map +0 -1
- package/dist/templates/iflow/index.js +0 -85
- package/dist/templates/iflow/index.js.map +0 -1
- package/dist/templates/iflow/settings.json +0 -60
- package/dist/templates/kilo/index.d.ts +0 -16
- package/dist/templates/kilo/index.d.ts.map +0 -1
- package/dist/templates/kilo/index.js +0 -39
- package/dist/templates/kilo/index.js.map +0 -1
- package/dist/templates/kilo/workflows/before-dev.md +0 -29
- package/dist/templates/kilo/workflows/brainstorm.md +0 -487
- package/dist/templates/kilo/workflows/break-loop.md +0 -125
- package/dist/templates/kilo/workflows/check-cross-layer.md +0 -153
- package/dist/templates/kilo/workflows/check.md +0 -25
- package/dist/templates/kilo/workflows/create-command.md +0 -152
- package/dist/templates/kilo/workflows/finish-work.md +0 -129
- package/dist/templates/kilo/workflows/integrate-skill.md +0 -219
- package/dist/templates/kilo/workflows/onboard.md +0 -358
- package/dist/templates/kilo/workflows/parallel.md +0 -193
- package/dist/templates/kilo/workflows/record-session.md +0 -62
- package/dist/templates/kilo/workflows/start.md +0 -387
- package/dist/templates/kilo/workflows/update-spec.md +0 -285
- package/dist/templates/kiro/skills/before-dev/SKILL.md +0 -34
- package/dist/templates/kiro/skills/brainstorm/SKILL.md +0 -492
- package/dist/templates/kiro/skills/break-loop/SKILL.md +0 -130
- package/dist/templates/kiro/skills/check/SKILL.md +0 -30
- package/dist/templates/kiro/skills/check-cross-layer/SKILL.md +0 -158
- package/dist/templates/kiro/skills/create-command/SKILL.md +0 -101
- package/dist/templates/kiro/skills/finish-work/SKILL.md +0 -148
- package/dist/templates/kiro/skills/integrate-skill/SKILL.md +0 -221
- package/dist/templates/kiro/skills/onboard/SKILL.md +0 -363
- package/dist/templates/kiro/skills/record-session/SKILL.md +0 -67
- package/dist/templates/kiro/skills/start/SKILL.md +0 -351
- package/dist/templates/kiro/skills/update-spec/SKILL.md +0 -335
- package/dist/templates/markdown/spec/backend/directory-structure.md +0 -292
- package/dist/templates/markdown/spec/backend/index.md +0 -40
- package/dist/templates/markdown/spec/backend/script-conventions.md +0 -742
- package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md +0 -118
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md +0 -394
- package/dist/templates/opencode/agents/debug.md +0 -129
- package/dist/templates/opencode/agents/dispatch.md +0 -223
- package/dist/templates/opencode/agents/trellis-plan.md +0 -427
- package/dist/templates/opencode/commands/trellis/before-dev.md +0 -29
- package/dist/templates/opencode/commands/trellis/brainstorm.md +0 -487
- package/dist/templates/opencode/commands/trellis/break-loop.md +0 -125
- package/dist/templates/opencode/commands/trellis/check-cross-layer.md +0 -153
- package/dist/templates/opencode/commands/trellis/check.md +0 -25
- package/dist/templates/opencode/commands/trellis/create-command.md +0 -154
- package/dist/templates/opencode/commands/trellis/finish-work.md +0 -144
- package/dist/templates/opencode/commands/trellis/integrate-skill.md +0 -219
- package/dist/templates/opencode/commands/trellis/migrate-specs.md +0 -0
- package/dist/templates/opencode/commands/trellis/onboard.md +0 -358
- package/dist/templates/opencode/commands/trellis/parallel.md +0 -193
- package/dist/templates/opencode/commands/trellis/record-session.md +0 -62
- package/dist/templates/opencode/commands/trellis/start.md +0 -351
- package/dist/templates/opencode/commands/trellis/update-spec.md +0 -354
- package/dist/templates/qoder/skills/before-dev/SKILL.md +0 -34
- package/dist/templates/qoder/skills/brainstorm/SKILL.md +0 -492
- package/dist/templates/qoder/skills/break-loop/SKILL.md +0 -130
- package/dist/templates/qoder/skills/check/SKILL.md +0 -30
- package/dist/templates/qoder/skills/check-cross-layer/SKILL.md +0 -158
- package/dist/templates/qoder/skills/create-command/SKILL.md +0 -101
- package/dist/templates/qoder/skills/finish-work/SKILL.md +0 -134
- package/dist/templates/qoder/skills/integrate-skill/SKILL.md +0 -221
- package/dist/templates/qoder/skills/onboard/SKILL.md +0 -363
- package/dist/templates/qoder/skills/record-session/SKILL.md +0 -67
- package/dist/templates/qoder/skills/start/SKILL.md +0 -388
- package/dist/templates/qoder/skills/update-spec/SKILL.md +0 -290
- package/dist/templates/trellis/scripts/common/phase.py +0 -254
- package/dist/templates/trellis/scripts/common/registry.py +0 -335
- package/dist/templates/trellis/scripts/common/worktree.py +0 -305
- package/dist/templates/trellis/scripts/create_bootstrap.py +0 -298
- package/dist/templates/trellis/scripts/multi_agent/__init__.py +0 -5
- package/dist/templates/trellis/scripts/multi_agent/_bootstrap.py +0 -17
- package/dist/templates/trellis/scripts/multi_agent/cleanup.py +0 -398
- package/dist/templates/trellis/scripts/multi_agent/create_pr.py +0 -620
- package/dist/templates/trellis/scripts/multi_agent/plan.py +0 -213
- package/dist/templates/trellis/scripts/multi_agent/start.py +0 -539
- package/dist/templates/trellis/scripts/multi_agent/status.py +0 -76
- package/dist/templates/trellis/scripts/multi_agent/status_display.py +0 -542
- package/dist/templates/trellis/scripts/multi_agent/status_monitor.py +0 -225
- package/dist/templates/trellis/scripts-shell-archive/add-session.sh +0 -384
- package/dist/templates/trellis/scripts-shell-archive/common/developer.sh +0 -129
- package/dist/templates/trellis/scripts-shell-archive/common/git-context.sh +0 -263
- package/dist/templates/trellis/scripts-shell-archive/common/paths.sh +0 -208
- package/dist/templates/trellis/scripts-shell-archive/common/phase.sh +0 -150
- package/dist/templates/trellis/scripts-shell-archive/common/registry.sh +0 -247
- package/dist/templates/trellis/scripts-shell-archive/common/task-queue.sh +0 -142
- package/dist/templates/trellis/scripts-shell-archive/common/task-utils.sh +0 -151
- package/dist/templates/trellis/scripts-shell-archive/common/worktree.sh +0 -128
- package/dist/templates/trellis/scripts-shell-archive/create-bootstrap.sh +0 -299
- package/dist/templates/trellis/scripts-shell-archive/get-context.sh +0 -7
- package/dist/templates/trellis/scripts-shell-archive/get-developer.sh +0 -15
- package/dist/templates/trellis/scripts-shell-archive/init-developer.sh +0 -34
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/cleanup.sh +0 -396
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/create-pr.sh +0 -241
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/plan.sh +0 -207
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/start.sh +0 -317
- package/dist/templates/trellis/scripts-shell-archive/multi-agent/status.sh +0 -828
- package/dist/templates/trellis/scripts-shell-archive/task.sh +0 -1204
- package/dist/templates/trellis/worktree.yaml +0 -47
- package/dist/templates/windsurf/index.d.ts +0 -21
- package/dist/templates/windsurf/index.d.ts.map +0 -1
- package/dist/templates/windsurf/index.js +0 -44
- package/dist/templates/windsurf/index.js.map +0 -1
- package/dist/templates/windsurf/workflows/trellis-before-dev.md +0 -31
- package/dist/templates/windsurf/workflows/trellis-brainstorm.md +0 -491
- package/dist/templates/windsurf/workflows/trellis-break-loop.md +0 -111
- package/dist/templates/windsurf/workflows/trellis-check-cross-layer.md +0 -157
- package/dist/templates/windsurf/workflows/trellis-check.md +0 -27
- package/dist/templates/windsurf/workflows/trellis-create-command.md +0 -154
- package/dist/templates/windsurf/workflows/trellis-finish-work.md +0 -147
- package/dist/templates/windsurf/workflows/trellis-integrate-skill.md +0 -220
- package/dist/templates/windsurf/workflows/trellis-onboard.md +0 -362
- package/dist/templates/windsurf/workflows/trellis-record-session.md +0 -66
- package/dist/templates/windsurf/workflows/trellis-start.md +0 -373
- package/dist/templates/windsurf/workflows/trellis-update-spec.md +0 -358
- /package/dist/templates/{claude/commands/trellis → common/skills}/before-dev.md +0 -0
- /package/dist/templates/{claude/hooks → shared-hooks}/statusline.py +0 -0
|
@@ -1,742 +0,0 @@
|
|
|
1
|
-
# Script Conventions
|
|
2
|
-
|
|
3
|
-
> Standards for Python scripts in the `.trellis/scripts/` directory.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Overview
|
|
8
|
-
|
|
9
|
-
All workflow scripts are written in **Python 3.10+** for cross-platform compatibility. Scripts use only the standard library (no external dependencies).
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## Directory Structure
|
|
14
|
-
|
|
15
|
-
```
|
|
16
|
-
.trellis/scripts/
|
|
17
|
-
├── __init__.py # Package init
|
|
18
|
-
├── common/ # Shared modules
|
|
19
|
-
│ ├── __init__.py
|
|
20
|
-
│ ├── paths.py # Path constants and functions
|
|
21
|
-
│ ├── developer.py # Developer identity management
|
|
22
|
-
│ ├── task_queue.py # Task queue CRUD
|
|
23
|
-
│ ├── task_utils.py # Task helper functions
|
|
24
|
-
│ ├── phase.py # Multi-agent phase tracking
|
|
25
|
-
│ ├── registry.py # Agent registry management
|
|
26
|
-
│ ├── config.py # Config reader (config.yaml, hooks)
|
|
27
|
-
│ ├── worktree.py # Git worktree utilities + YAML parser
|
|
28
|
-
│ └── git_context.py # Git/session context
|
|
29
|
-
├── hooks/ # Lifecycle hook scripts (project-specific)
|
|
30
|
-
│ └── linear_sync.py # Example: sync tasks to Linear
|
|
31
|
-
├── multi_agent/ # Multi-agent pipeline scripts
|
|
32
|
-
│ ├── __init__.py
|
|
33
|
-
│ ├── start.py # Start worktree agent
|
|
34
|
-
│ ├── status.py # Monitor agent status
|
|
35
|
-
│ ├── plan.py # Start plan agent
|
|
36
|
-
│ ├── cleanup.py # Cleanup worktree
|
|
37
|
-
│ └── create_pr.py # Create PR from task
|
|
38
|
-
├── task.py # Main task management CLI
|
|
39
|
-
├── get_context.py # Session context retrieval
|
|
40
|
-
├── init_developer.py # Developer initialization
|
|
41
|
-
├── get_developer.py # Get current developer
|
|
42
|
-
├── add_session.py # Session recording
|
|
43
|
-
└── create_bootstrap.py # Bootstrap task creation
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## Script Types
|
|
49
|
-
|
|
50
|
-
### Library Modules (`common/*.py`)
|
|
51
|
-
|
|
52
|
-
Shared utilities imported by other scripts. **Never run directly.**
|
|
53
|
-
|
|
54
|
-
```python
|
|
55
|
-
# common/paths.py - Example library module
|
|
56
|
-
|
|
57
|
-
from __future__ import annotations
|
|
58
|
-
|
|
59
|
-
from pathlib import Path
|
|
60
|
-
|
|
61
|
-
# Constants
|
|
62
|
-
DIR_WORKFLOW = ".trellis"
|
|
63
|
-
DIR_SCRIPTS = "scripts"
|
|
64
|
-
DIR_TASKS = "tasks"
|
|
65
|
-
|
|
66
|
-
def get_repo_root() -> Path | None:
|
|
67
|
-
"""Find repository root by looking for .trellis directory."""
|
|
68
|
-
current = Path.cwd().resolve()
|
|
69
|
-
while current != current.parent:
|
|
70
|
-
if (current / DIR_WORKFLOW).is_dir():
|
|
71
|
-
return current
|
|
72
|
-
current = current.parent
|
|
73
|
-
return None
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
### Entry Scripts (`*.py`)
|
|
77
|
-
|
|
78
|
-
CLI tools that users run directly. Include docstring with usage.
|
|
79
|
-
|
|
80
|
-
```python
|
|
81
|
-
#!/usr/bin/env python3
|
|
82
|
-
"""
|
|
83
|
-
Task Management Script.
|
|
84
|
-
|
|
85
|
-
Usage:
|
|
86
|
-
python3 task.py create "<title>" [--slug <name>]
|
|
87
|
-
python3 task.py init-context <dir> <dev_type>
|
|
88
|
-
python3 task.py add-context <dir> <file> <reason>
|
|
89
|
-
python3 task.py validate <dir>
|
|
90
|
-
python3 task.py list-context <dir>
|
|
91
|
-
python3 task.py start <dir>
|
|
92
|
-
python3 task.py finish
|
|
93
|
-
python3 task.py set-branch <dir> <branch>
|
|
94
|
-
python3 task.py set-base-branch <dir> <branch>
|
|
95
|
-
python3 task.py set-scope <dir> <scope>
|
|
96
|
-
python3 task.py create-pr [dir] [--dry-run]
|
|
97
|
-
python3 task.py archive <task-name>
|
|
98
|
-
python3 task.py list [--mine] [--status <status>]
|
|
99
|
-
python3 task.py list-archive [YYYY-MM]
|
|
100
|
-
"""
|
|
101
|
-
|
|
102
|
-
from __future__ import annotations
|
|
103
|
-
|
|
104
|
-
import argparse
|
|
105
|
-
import sys
|
|
106
|
-
from pathlib import Path
|
|
107
|
-
|
|
108
|
-
from common.paths import get_repo_root, DIR_WORKFLOW
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def main() -> int:
|
|
112
|
-
"""Main entry point."""
|
|
113
|
-
parser = argparse.ArgumentParser(description="Task management")
|
|
114
|
-
# ... argument setup
|
|
115
|
-
args = parser.parse_args()
|
|
116
|
-
# ... command dispatch
|
|
117
|
-
return 0
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if __name__ == "__main__":
|
|
121
|
-
sys.exit(main())
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
---
|
|
125
|
-
|
|
126
|
-
## Coding Standards
|
|
127
|
-
|
|
128
|
-
### Type Hints
|
|
129
|
-
|
|
130
|
-
Use modern type hints (Python 3.10+ syntax):
|
|
131
|
-
|
|
132
|
-
```python
|
|
133
|
-
# Good
|
|
134
|
-
def get_tasks(status: str | None = None) -> list[dict]:
|
|
135
|
-
...
|
|
136
|
-
|
|
137
|
-
def read_json(path: Path) -> dict | None:
|
|
138
|
-
...
|
|
139
|
-
|
|
140
|
-
# Bad - old style
|
|
141
|
-
from typing import Optional, List, Dict
|
|
142
|
-
def get_tasks(status: Optional[str] = None) -> List[Dict]:
|
|
143
|
-
...
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### Path Handling
|
|
147
|
-
|
|
148
|
-
Always use `pathlib.Path`:
|
|
149
|
-
|
|
150
|
-
```python
|
|
151
|
-
# Good
|
|
152
|
-
from pathlib import Path
|
|
153
|
-
|
|
154
|
-
def read_file(path: Path) -> str:
|
|
155
|
-
return path.read_text(encoding="utf-8")
|
|
156
|
-
|
|
157
|
-
config_path = repo_root / DIR_WORKFLOW / "config.json"
|
|
158
|
-
|
|
159
|
-
# Bad - string concatenation
|
|
160
|
-
config_path = repo_root + "/" + DIR_WORKFLOW + "/config.json"
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
### JSON Operations
|
|
164
|
-
|
|
165
|
-
Use helper functions for consistent error handling:
|
|
166
|
-
|
|
167
|
-
```python
|
|
168
|
-
import json
|
|
169
|
-
from pathlib import Path
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
def read_json(path: Path) -> dict | None:
|
|
173
|
-
"""Read JSON file, return None on error."""
|
|
174
|
-
try:
|
|
175
|
-
return json.loads(path.read_text(encoding="utf-8"))
|
|
176
|
-
except (FileNotFoundError, json.JSONDecodeError):
|
|
177
|
-
return None
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
def write_json(path: Path, data: dict) -> bool:
|
|
181
|
-
"""Write JSON file, return success status."""
|
|
182
|
-
try:
|
|
183
|
-
path.write_text(
|
|
184
|
-
json.dumps(data, indent=2, ensure_ascii=False),
|
|
185
|
-
encoding="utf-8"
|
|
186
|
-
)
|
|
187
|
-
return True
|
|
188
|
-
except Exception:
|
|
189
|
-
return False
|
|
190
|
-
```
|
|
191
|
-
|
|
192
|
-
### Subprocess Execution
|
|
193
|
-
|
|
194
|
-
```python
|
|
195
|
-
import subprocess
|
|
196
|
-
from pathlib import Path
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
def run_command(
|
|
200
|
-
cmd: list[str],
|
|
201
|
-
cwd: Path | None = None
|
|
202
|
-
) -> tuple[int, str, str]:
|
|
203
|
-
"""Run command and return (returncode, stdout, stderr)."""
|
|
204
|
-
result = subprocess.run(
|
|
205
|
-
cmd,
|
|
206
|
-
cwd=cwd,
|
|
207
|
-
capture_output=True,
|
|
208
|
-
text=True
|
|
209
|
-
)
|
|
210
|
-
return result.returncode, result.stdout, result.stderr
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
---
|
|
214
|
-
|
|
215
|
-
## Cross-Platform Compatibility
|
|
216
|
-
|
|
217
|
-
### CRITICAL: Windows stdio Encoding (stdout + stdin)
|
|
218
|
-
|
|
219
|
-
On Windows, Python's stdout AND stdin default to the system code page (e.g., GBK/CP936 in China, CP1252 in Western locales). This causes:
|
|
220
|
-
- `UnicodeEncodeError` when **printing** non-ASCII characters (stdout)
|
|
221
|
-
- `UnicodeDecodeError` when **reading piped** UTF-8 content (stdin), e.g. Chinese text via `cat << EOF | python3 script.py`
|
|
222
|
-
|
|
223
|
-
**The Problem Chain (stdout)**:
|
|
224
|
-
|
|
225
|
-
```
|
|
226
|
-
Windows code page = GBK (936)
|
|
227
|
-
↓
|
|
228
|
-
Python stdout defaults to GBK encoding
|
|
229
|
-
↓
|
|
230
|
-
Subprocess output contains special chars → replaced with \ufffd (replacement char)
|
|
231
|
-
↓
|
|
232
|
-
json.dumps(ensure_ascii=False) → print()
|
|
233
|
-
↓
|
|
234
|
-
GBK cannot encode \ufffd → UnicodeEncodeError: 'gbk' codec can't encode character
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
**The Problem Chain (stdin)**:
|
|
238
|
-
|
|
239
|
-
```
|
|
240
|
-
AI agent pipes UTF-8 content via heredoc: cat << 'EOF' | python3 add_session.py ...
|
|
241
|
-
↓
|
|
242
|
-
Python stdin defaults to GBK encoding (PowerShell default code page)
|
|
243
|
-
↓
|
|
244
|
-
sys.stdin.read() decodes bytes as GBK, not UTF-8
|
|
245
|
-
↓
|
|
246
|
-
Chinese text garbled or UnicodeDecodeError
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
**Root Cause**: Even if you set `PYTHONIOENCODING` in subprocess calls, the **parent process's stdio** still uses the system code page.
|
|
250
|
-
|
|
251
|
-
---
|
|
252
|
-
|
|
253
|
-
#### GOOD: Centralize encoding fix in `common/__init__.py`
|
|
254
|
-
|
|
255
|
-
All stdio encoding is handled in one place. Scripts that `from common import ...` automatically get the fix:
|
|
256
|
-
|
|
257
|
-
```python
|
|
258
|
-
# common/__init__.py
|
|
259
|
-
import io
|
|
260
|
-
import sys
|
|
261
|
-
|
|
262
|
-
def _configure_stream(stream):
|
|
263
|
-
"""Configure a stream for UTF-8 encoding on Windows."""
|
|
264
|
-
if hasattr(stream, "reconfigure"):
|
|
265
|
-
stream.reconfigure(encoding="utf-8", errors="replace")
|
|
266
|
-
return stream
|
|
267
|
-
elif hasattr(stream, "detach"):
|
|
268
|
-
return io.TextIOWrapper(stream.detach(), encoding="utf-8", errors="replace")
|
|
269
|
-
return stream
|
|
270
|
-
|
|
271
|
-
if sys.platform == "win32":
|
|
272
|
-
sys.stdout = _configure_stream(sys.stdout)
|
|
273
|
-
sys.stderr = _configure_stream(sys.stderr)
|
|
274
|
-
sys.stdin = _configure_stream(sys.stdin) # Don't forget stdin!
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
---
|
|
278
|
-
|
|
279
|
-
#### DON'T: Inline encoding code in individual scripts
|
|
280
|
-
|
|
281
|
-
```python
|
|
282
|
-
# BAD - Duplicated in every script, easy to forget stdin
|
|
283
|
-
import sys
|
|
284
|
-
if sys.platform == "win32":
|
|
285
|
-
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
286
|
-
# Forgot stdin! Piped Chinese text will break.
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
**Why this is bad**:
|
|
290
|
-
1. **Easy to forget streams**: stdout was fixed but stdin was missed in multiple scripts, causing real user bugs
|
|
291
|
-
2. **Duplicated code**: Same logic copy-pasted across `add_session.py`, `git_context.py`, etc.
|
|
292
|
-
3. **Inconsistent coverage**: Some scripts fix stdout only, others fix stdout+stderr, none fixed stdin
|
|
293
|
-
|
|
294
|
-
**Real-world failure**: Users on Windows reported garbled Chinese text when using `cat << EOF | python3 add_session.py`. Root cause: stdin was never reconfigured to UTF-8.
|
|
295
|
-
|
|
296
|
-
---
|
|
297
|
-
|
|
298
|
-
#### Summary
|
|
299
|
-
|
|
300
|
-
| Method | Works? | Reason |
|
|
301
|
-
|--------|--------|--------|
|
|
302
|
-
| `common/__init__.py` centralized fix | ✅ Yes | All streams, all scripts, one place |
|
|
303
|
-
| `sys.stdout.reconfigure(encoding="utf-8")` | ⚠️ Partial | Only stdout; easy to forget stdin/stderr |
|
|
304
|
-
| `io.TextIOWrapper(sys.stdout.buffer, ...)` | ❌ No | Creates wrapper, doesn't fix underlying encoding |
|
|
305
|
-
| `PYTHONIOENCODING=utf-8` env var | ⚠️ Partial | Only works if set **before** Python starts |
|
|
306
|
-
|
|
307
|
-
### CRITICAL: Always Use `python3` Explicitly
|
|
308
|
-
|
|
309
|
-
Windows does not support shebang (`#!/usr/bin/env python3`). Always document invocation with explicit `python3`:
|
|
310
|
-
|
|
311
|
-
```python
|
|
312
|
-
# In docstrings
|
|
313
|
-
"""
|
|
314
|
-
Usage:
|
|
315
|
-
python3 task.py create "My Task"
|
|
316
|
-
python3 task.py list --mine
|
|
317
|
-
"""
|
|
318
|
-
|
|
319
|
-
# In error messages
|
|
320
|
-
print("Usage: python3 task.py <command>")
|
|
321
|
-
print("Run: python3 ./.trellis/scripts/init_developer.py <name>")
|
|
322
|
-
|
|
323
|
-
# In help text
|
|
324
|
-
print("Next steps:")
|
|
325
|
-
print(" python3 task.py start <dir>")
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
### Path Separators
|
|
329
|
-
|
|
330
|
-
Use `pathlib.Path` - it handles separators automatically:
|
|
331
|
-
|
|
332
|
-
```python
|
|
333
|
-
# Good - works on all platforms
|
|
334
|
-
path = Path(".trellis") / "scripts" / "task.py"
|
|
335
|
-
|
|
336
|
-
# Bad - Unix-only
|
|
337
|
-
path = ".trellis/scripts/task.py"
|
|
338
|
-
```
|
|
339
|
-
|
|
340
|
-
---
|
|
341
|
-
|
|
342
|
-
## Task Lifecycle Hooks
|
|
343
|
-
|
|
344
|
-
### Scope / Trigger
|
|
345
|
-
|
|
346
|
-
Task lifecycle events (`after_create`, `after_start`, `after_finish`, `after_archive`) execute user-defined shell commands configured in `config.yaml`.
|
|
347
|
-
|
|
348
|
-
### Signatures
|
|
349
|
-
|
|
350
|
-
```python
|
|
351
|
-
# config.py — read hook commands from config
|
|
352
|
-
def get_hooks(event: str, repo_root: Path | None = None) -> list[str]
|
|
353
|
-
|
|
354
|
-
# task.py — execute hooks (never blocks main operation)
|
|
355
|
-
def _run_hooks(event: str, task_json_path: Path, repo_root: Path) -> None
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
### Contracts
|
|
359
|
-
|
|
360
|
-
**Config format** (`config.yaml`):
|
|
361
|
-
```yaml
|
|
362
|
-
hooks:
|
|
363
|
-
after_create:
|
|
364
|
-
- "python3 .trellis/scripts/hooks/my_hook.py create"
|
|
365
|
-
after_start:
|
|
366
|
-
- "python3 .trellis/scripts/hooks/my_hook.py start"
|
|
367
|
-
after_archive:
|
|
368
|
-
- "python3 .trellis/scripts/hooks/my_hook.py archive"
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
**Environment variables passed to hooks**:
|
|
372
|
-
|
|
373
|
-
| Key | Type | Description |
|
|
374
|
-
|-----|------|-------------|
|
|
375
|
-
| `TASK_JSON_PATH` | Absolute path string | Path to the task's `task.json` |
|
|
376
|
-
|
|
377
|
-
- `cwd` is set to `repo_root`
|
|
378
|
-
- Hooks inherit the parent process environment + `TASK_JSON_PATH`
|
|
379
|
-
|
|
380
|
-
### Subprocess Execution
|
|
381
|
-
|
|
382
|
-
```python
|
|
383
|
-
import os
|
|
384
|
-
import subprocess
|
|
385
|
-
|
|
386
|
-
env = {**os.environ, "TASK_JSON_PATH": str(task_json_path)}
|
|
387
|
-
|
|
388
|
-
result = subprocess.run(
|
|
389
|
-
cmd,
|
|
390
|
-
shell=True,
|
|
391
|
-
cwd=repo_root,
|
|
392
|
-
env=env,
|
|
393
|
-
capture_output=True,
|
|
394
|
-
text=True,
|
|
395
|
-
encoding="utf-8", # REQUIRED: cross-platform
|
|
396
|
-
errors="replace", # REQUIRED: cross-platform
|
|
397
|
-
)
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
### Validation & Error Matrix
|
|
401
|
-
|
|
402
|
-
| Condition | Behavior |
|
|
403
|
-
|-----------|----------|
|
|
404
|
-
| No `hooks` key in config | No-op (empty list) |
|
|
405
|
-
| `hooks` is not a dict | No-op (empty list) |
|
|
406
|
-
| Event key missing | No-op (empty list) |
|
|
407
|
-
| Hook command exits non-zero | `[WARN]` to stderr, continues to next hook |
|
|
408
|
-
| Hook command throws exception | `[WARN]` to stderr, continues to next hook |
|
|
409
|
-
| `linearis` not installed | Hook fails with warning, task operation succeeds |
|
|
410
|
-
|
|
411
|
-
### Wrong vs Correct
|
|
412
|
-
|
|
413
|
-
#### Wrong — blocking on hook failure
|
|
414
|
-
```python
|
|
415
|
-
result = subprocess.run(cmd, shell=True, check=True) # Raises on failure!
|
|
416
|
-
```
|
|
417
|
-
|
|
418
|
-
#### Correct — warn and continue
|
|
419
|
-
```python
|
|
420
|
-
try:
|
|
421
|
-
result = subprocess.run(cmd, shell=True, ...)
|
|
422
|
-
if result.returncode != 0:
|
|
423
|
-
print(f"[WARN] Hook failed: {cmd}", file=sys.stderr)
|
|
424
|
-
except Exception as e:
|
|
425
|
-
print(f"[WARN] Hook error: {cmd} — {e}", file=sys.stderr)
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
### Hook Script Pattern
|
|
429
|
-
|
|
430
|
-
Hook scripts that need project-specific config (API keys, user IDs) should:
|
|
431
|
-
1. Store config in a **gitignored** local file (e.g., `.trellis/hooks.local.json`)
|
|
432
|
-
2. Read config at startup, fail with clear message if missing
|
|
433
|
-
3. Keep the script itself committable (no hardcoded secrets)
|
|
434
|
-
|
|
435
|
-
```python
|
|
436
|
-
# .trellis/scripts/hooks/my_hook.py — committable, no secrets
|
|
437
|
-
CONFIG = _load_config() # reads from .trellis/hooks.local.json (gitignored)
|
|
438
|
-
TEAM = CONFIG.get("linear", {}).get("team", "")
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
---
|
|
442
|
-
|
|
443
|
-
## Auto-Commit Pattern
|
|
444
|
-
|
|
445
|
-
Scripts that modify `.trellis/` tracked files should auto-commit their changes to keep the workspace clean. Use a `--no-commit` flag for opt-out.
|
|
446
|
-
|
|
447
|
-
### Convention: Auto-Commit After Mutation
|
|
448
|
-
|
|
449
|
-
```python
|
|
450
|
-
def _auto_commit(scope: str, message: str, repo_root: Path) -> None:
|
|
451
|
-
"""Stage and commit changes in a specific .trellis/ subdirectory."""
|
|
452
|
-
subprocess.run(["git", "add", "-A", scope], cwd=repo_root, capture_output=True)
|
|
453
|
-
# Check if there are staged changes
|
|
454
|
-
result = subprocess.run(
|
|
455
|
-
["git", "diff", "--cached", "--quiet", "--", scope],
|
|
456
|
-
cwd=repo_root,
|
|
457
|
-
)
|
|
458
|
-
if result.returncode == 0:
|
|
459
|
-
print("[OK] No changes to commit.", file=sys.stderr)
|
|
460
|
-
return
|
|
461
|
-
commit_result = subprocess.run(
|
|
462
|
-
["git", "commit", "-m", message],
|
|
463
|
-
cwd=repo_root, capture_output=True, text=True,
|
|
464
|
-
)
|
|
465
|
-
if commit_result.returncode == 0:
|
|
466
|
-
print(f"[OK] Auto-committed: {message}", file=sys.stderr)
|
|
467
|
-
else:
|
|
468
|
-
print(f"[WARN] Auto-commit failed: {commit_result.stderr.strip()}", file=sys.stderr)
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
**Scripts using this pattern**:
|
|
472
|
-
- `add_session.py` — commits `.trellis/workspace` + `.trellis/tasks` after recording a session
|
|
473
|
-
- `task.py archive` — commits `.trellis/tasks` after archiving a task
|
|
474
|
-
|
|
475
|
-
**Always add `--no-commit` flag** for scripts that auto-commit, so users can opt out.
|
|
476
|
-
|
|
477
|
-
---
|
|
478
|
-
|
|
479
|
-
## CLI Mode Extension Pattern
|
|
480
|
-
|
|
481
|
-
### Design Decision: `--mode` for Context-Dependent Output
|
|
482
|
-
|
|
483
|
-
When a script needs different output for different use cases, use `--mode` (not separate scripts or additional flags).
|
|
484
|
-
|
|
485
|
-
**Example**: `get_context.py` serves two modes:
|
|
486
|
-
- `--mode default` — full session context (DEVELOPER, GIT STATUS, RECENT COMMITS, CURRENT TASK, ACTIVE TASKS, MY TASKS, JOURNAL, PATHS)
|
|
487
|
-
- `--mode record` — focused output for record-session (MY ACTIVE TASKS first with emphasis, GIT STATUS, RECENT COMMITS, CURRENT TASK)
|
|
488
|
-
|
|
489
|
-
```python
|
|
490
|
-
parser.add_argument(
|
|
491
|
-
"--mode", "-m",
|
|
492
|
-
choices=["default", "record"],
|
|
493
|
-
default="default",
|
|
494
|
-
help="Output mode: default (full context) or record (for record-session)",
|
|
495
|
-
)
|
|
496
|
-
```
|
|
497
|
-
|
|
498
|
-
**When to add a new mode** (not a new script):
|
|
499
|
-
- Output is a subset/reordering of the same data
|
|
500
|
-
- The underlying data sources are shared
|
|
501
|
-
- The difference is in presentation, not in data fetching
|
|
502
|
-
|
|
503
|
-
---
|
|
504
|
-
|
|
505
|
-
## Parsing Structured Command Output
|
|
506
|
-
|
|
507
|
-
### CRITICAL: Preserve Semantic Whitespace
|
|
508
|
-
|
|
509
|
-
Many CLI tools encode status information in leading/trailing whitespace characters. **Never blindly `.strip()` before parsing.**
|
|
510
|
-
|
|
511
|
-
**Example — `git submodule status` output format**:
|
|
512
|
-
|
|
513
|
-
```
|
|
514
|
-
abc1234 path/to/submodule (v1.0) ← space prefix = initialized
|
|
515
|
-
-def5678 path/to/other (v2.0) ← minus prefix = not initialized
|
|
516
|
-
+ghi9012 path/to/modified (v3.0) ← plus prefix = modified (out of sync)
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
```python
|
|
520
|
-
# BAD — .strip() removes the leading space that means "initialized"
|
|
521
|
-
status_line = status_out.strip()
|
|
522
|
-
prefix = status_line[0] # Reads commit hash char, not status prefix!
|
|
523
|
-
|
|
524
|
-
# GOOD — parse the raw line, then strip individual fields
|
|
525
|
-
raw_line = status_out.rstrip("\n") # Only remove trailing newline
|
|
526
|
-
if not raw_line:
|
|
527
|
-
continue
|
|
528
|
-
prefix = raw_line[0] # ' ', '-', or '+'
|
|
529
|
-
rest = raw_line[1:].strip() # Now safe to strip the rest
|
|
530
|
-
commit_hash = rest.split()[0]
|
|
531
|
-
```
|
|
532
|
-
|
|
533
|
-
**General rule**: When a command's output uses positional formatting (columns, prefixes, fixed-width fields), parse the structure first, then clean up individual values.
|
|
534
|
-
|
|
535
|
-
**Other commands with semantic whitespace**:
|
|
536
|
-
- `git status --porcelain` — two-char status prefix (`XY`)
|
|
537
|
-
- `git diff --name-status` — tab-separated with status prefix
|
|
538
|
-
- `docker ps --format` — column-aligned output
|
|
539
|
-
|
|
540
|
-
---
|
|
541
|
-
|
|
542
|
-
## Monorepo Config API (`common/config.py`)
|
|
543
|
-
|
|
544
|
-
### Config Functions
|
|
545
|
-
|
|
546
|
-
| Function | Return | Purpose |
|
|
547
|
-
|----------|--------|---------|
|
|
548
|
-
| `is_monorepo(repo_root)` | `bool` | Whether `packages:` exists in config.yaml |
|
|
549
|
-
| `get_packages(repo_root)` | `dict[str, dict] \| None` | All packages from config.yaml (`{name: {path, type?}}`) |
|
|
550
|
-
| `get_default_package(repo_root)` | `str \| None` | The `default_package` from config.yaml |
|
|
551
|
-
| `get_submodule_packages(repo_root)` | `dict[str, str]` | Packages with `type: submodule` (`{name: path}`) |
|
|
552
|
-
| `get_spec_base(package, repo_root)` | `str` | `"spec"` (single-repo) or `"spec/<package>"` (monorepo) |
|
|
553
|
-
| `validate_package(package, repo_root)` | `bool` | Whether package exists in config (always `True` for single-repo) |
|
|
554
|
-
| `resolve_package(task_pkg, repo_root)` | `str \| None` | Resolve package: task → default → None |
|
|
555
|
-
| `get_spec_scope(repo_root)` | `str \| list \| None` | The `session.spec_scope` config value |
|
|
556
|
-
| `get_hooks(event, repo_root)` | `list[str]` | Hook commands for lifecycle event |
|
|
557
|
-
|
|
558
|
-
### Config.yaml Schema
|
|
559
|
-
|
|
560
|
-
```yaml
|
|
561
|
-
# Auto-detected monorepo packages (written by trellis init)
|
|
562
|
-
packages:
|
|
563
|
-
cli:
|
|
564
|
-
path: packages/cli
|
|
565
|
-
docs-site:
|
|
566
|
-
path: docs-site
|
|
567
|
-
type: submodule # optional, marks git submodule
|
|
568
|
-
default_package: cli # first non-submodule package
|
|
569
|
-
|
|
570
|
-
# Session behavior
|
|
571
|
-
session:
|
|
572
|
-
spec_scope: active_task # or ["cli", "docs-site"] or omit for full scan
|
|
573
|
-
|
|
574
|
-
# Update behavior
|
|
575
|
-
update:
|
|
576
|
-
skip:
|
|
577
|
-
- .claude/commands/trellis/my-custom.md
|
|
578
|
-
|
|
579
|
-
# Lifecycle hooks
|
|
580
|
-
hooks:
|
|
581
|
-
after_create:
|
|
582
|
-
- "python3 .trellis/scripts/hooks/my_hook.py create"
|
|
583
|
-
```
|
|
584
|
-
|
|
585
|
-
### Worktree Submodule Initialization
|
|
586
|
-
|
|
587
|
-
When `start.py` creates a worktree for a task, it calls `_init_submodules_for_task()`:
|
|
588
|
-
|
|
589
|
-
1. Read `packages` from config.yaml via `get_packages()`
|
|
590
|
-
2. Resolve target package from task data or `default_package`
|
|
591
|
-
3. Check if the package is a submodule via `get_submodule_packages()`
|
|
592
|
-
4. Run `git submodule status <path>` in the worktree
|
|
593
|
-
5. Parse the status prefix (see "Parsing Structured Command Output" above)
|
|
594
|
-
6. If uninitialized (`-` prefix): run `git submodule update --init <path>`
|
|
595
|
-
|
|
596
|
-
---
|
|
597
|
-
|
|
598
|
-
## Error Handling
|
|
599
|
-
|
|
600
|
-
### Exit Codes
|
|
601
|
-
|
|
602
|
-
| Code | Meaning |
|
|
603
|
-
|------|---------|
|
|
604
|
-
| 0 | Success |
|
|
605
|
-
| 1 | General error |
|
|
606
|
-
| 2 | Usage error (wrong arguments) |
|
|
607
|
-
|
|
608
|
-
### Error Messages
|
|
609
|
-
|
|
610
|
-
Print errors to stderr with context:
|
|
611
|
-
|
|
612
|
-
```python
|
|
613
|
-
import sys
|
|
614
|
-
|
|
615
|
-
def error(msg: str) -> None:
|
|
616
|
-
"""Print error message to stderr."""
|
|
617
|
-
print(f"Error: {msg}", file=sys.stderr)
|
|
618
|
-
|
|
619
|
-
# Usage
|
|
620
|
-
if not repo_root:
|
|
621
|
-
error("Not in a Trellis project (no .trellis directory found)")
|
|
622
|
-
sys.exit(1)
|
|
623
|
-
```
|
|
624
|
-
|
|
625
|
-
---
|
|
626
|
-
|
|
627
|
-
## Argument Parsing
|
|
628
|
-
|
|
629
|
-
Use `argparse` for consistent CLI interface:
|
|
630
|
-
|
|
631
|
-
```python
|
|
632
|
-
import argparse
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
def main() -> int:
|
|
636
|
-
parser = argparse.ArgumentParser(
|
|
637
|
-
description="Task management",
|
|
638
|
-
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
639
|
-
epilog="""
|
|
640
|
-
Examples:
|
|
641
|
-
python3 task.py create "Add login" --slug add-login
|
|
642
|
-
python3 task.py list --mine --status in_progress
|
|
643
|
-
"""
|
|
644
|
-
)
|
|
645
|
-
|
|
646
|
-
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
647
|
-
|
|
648
|
-
# create command
|
|
649
|
-
create_parser = subparsers.add_parser("create", help="Create new task")
|
|
650
|
-
create_parser.add_argument("title", help="Task title")
|
|
651
|
-
create_parser.add_argument("--slug", help="URL-friendly name")
|
|
652
|
-
|
|
653
|
-
# list command
|
|
654
|
-
list_parser = subparsers.add_parser("list", help="List tasks")
|
|
655
|
-
list_parser.add_argument("--mine", "-m", action="store_true")
|
|
656
|
-
list_parser.add_argument("--status", "-s", choices=["planning", "in_progress", "review", "completed"])
|
|
657
|
-
|
|
658
|
-
args = parser.parse_args()
|
|
659
|
-
|
|
660
|
-
if args.command == "create":
|
|
661
|
-
return cmd_create(args)
|
|
662
|
-
elif args.command == "list":
|
|
663
|
-
return cmd_list(args)
|
|
664
|
-
|
|
665
|
-
return 0
|
|
666
|
-
```
|
|
667
|
-
|
|
668
|
-
---
|
|
669
|
-
|
|
670
|
-
## Import Conventions
|
|
671
|
-
|
|
672
|
-
### Relative Imports Within Package
|
|
673
|
-
|
|
674
|
-
```python
|
|
675
|
-
# In task.py (root level)
|
|
676
|
-
from common.paths import get_repo_root, DIR_WORKFLOW
|
|
677
|
-
from common.developer import get_developer
|
|
678
|
-
|
|
679
|
-
# In common/developer.py
|
|
680
|
-
from .paths import get_repo_root, DIR_WORKFLOW
|
|
681
|
-
```
|
|
682
|
-
|
|
683
|
-
### Standard Library Imports
|
|
684
|
-
|
|
685
|
-
Group and order imports:
|
|
686
|
-
|
|
687
|
-
```python
|
|
688
|
-
# 1. Future imports
|
|
689
|
-
from __future__ import annotations
|
|
690
|
-
|
|
691
|
-
# 2. Standard library
|
|
692
|
-
import argparse
|
|
693
|
-
import json
|
|
694
|
-
import os
|
|
695
|
-
import subprocess
|
|
696
|
-
import sys
|
|
697
|
-
from datetime import datetime
|
|
698
|
-
from pathlib import Path
|
|
699
|
-
|
|
700
|
-
# 3. Local imports
|
|
701
|
-
from common.paths import get_repo_root
|
|
702
|
-
from common.developer import get_developer
|
|
703
|
-
```
|
|
704
|
-
|
|
705
|
-
---
|
|
706
|
-
|
|
707
|
-
## DO / DON'T
|
|
708
|
-
|
|
709
|
-
### DO
|
|
710
|
-
|
|
711
|
-
- Use `pathlib.Path` for all path operations
|
|
712
|
-
- Use type hints (Python 3.10+ syntax)
|
|
713
|
-
- Return exit codes from `main()`
|
|
714
|
-
- Print errors to stderr
|
|
715
|
-
- Always use `python3` in documentation and messages
|
|
716
|
-
- Use `encoding="utf-8"` for all file operations
|
|
717
|
-
|
|
718
|
-
### DON'T
|
|
719
|
-
|
|
720
|
-
- Don't use string path concatenation
|
|
721
|
-
- Don't use `os.path` when `pathlib` works
|
|
722
|
-
- Don't rely on shebang for invocation documentation
|
|
723
|
-
- Don't use `print()` for errors (use stderr)
|
|
724
|
-
- Don't hardcode paths - use constants from `common/paths.py`
|
|
725
|
-
- Don't use external dependencies (stdlib only)
|
|
726
|
-
|
|
727
|
-
---
|
|
728
|
-
|
|
729
|
-
## Example: Complete Script
|
|
730
|
-
|
|
731
|
-
See `.trellis/scripts/task.py` for a comprehensive example with:
|
|
732
|
-
- Multiple subcommands
|
|
733
|
-
- Argument parsing
|
|
734
|
-
- JSON file operations
|
|
735
|
-
- Error handling
|
|
736
|
-
- Cross-platform path handling
|
|
737
|
-
|
|
738
|
-
---
|
|
739
|
-
|
|
740
|
-
## Migration Note
|
|
741
|
-
|
|
742
|
-
> **Historical Context**: Scripts were migrated from Bash to Python in v0.3.0 for cross-platform compatibility. The old shell scripts are archived in `.trellis/scripts-shell-archive/` (if preserved).
|