@chinhae/atw-cli 0.1.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/COPYRIGHT +14 -0
- package/LICENSE +77 -0
- package/README.md +122 -0
- package/bin/atw.js +3 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +299 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/ablate.d.ts +14 -0
- package/dist/commands/ablate.d.ts.map +1 -0
- package/dist/commands/ablate.js +307 -0
- package/dist/commands/ablate.js.map +1 -0
- package/dist/commands/channel/adapters/claude.d.ts +53 -0
- package/dist/commands/channel/adapters/claude.d.ts.map +1 -0
- package/dist/commands/channel/adapters/claude.js +225 -0
- package/dist/commands/channel/adapters/claude.js.map +1 -0
- package/dist/commands/channel/adapters/codex.d.ts +93 -0
- package/dist/commands/channel/adapters/codex.d.ts.map +1 -0
- package/dist/commands/channel/adapters/codex.js +573 -0
- package/dist/commands/channel/adapters/codex.js.map +1 -0
- package/dist/commands/channel/adapters/index.d.ts +94 -0
- package/dist/commands/channel/adapters/index.d.ts.map +1 -0
- package/dist/commands/channel/adapters/index.js +116 -0
- package/dist/commands/channel/adapters/index.js.map +1 -0
- package/dist/commands/channel/adapters/types.d.ts +33 -0
- package/dist/commands/channel/adapters/types.d.ts.map +1 -0
- package/dist/commands/channel/adapters/types.js +2 -0
- package/dist/commands/channel/adapters/types.js.map +1 -0
- package/dist/commands/channel/agent-loader.d.ts +32 -0
- package/dist/commands/channel/agent-loader.d.ts.map +1 -0
- package/dist/commands/channel/agent-loader.js +158 -0
- package/dist/commands/channel/agent-loader.js.map +1 -0
- package/dist/commands/channel/context-loader.d.ts +26 -0
- package/dist/commands/channel/context-loader.d.ts.map +1 -0
- package/dist/commands/channel/context-loader.js +311 -0
- package/dist/commands/channel/context-loader.js.map +1 -0
- package/dist/commands/channel/context-trust.d.ts +31 -0
- package/dist/commands/channel/context-trust.d.ts.map +1 -0
- package/dist/commands/channel/context-trust.js +139 -0
- package/dist/commands/channel/context-trust.js.map +1 -0
- package/dist/commands/channel/context.d.ts +16 -0
- package/dist/commands/channel/context.d.ts.map +1 -0
- package/dist/commands/channel/context.js +83 -0
- package/dist/commands/channel/context.js.map +1 -0
- package/dist/commands/channel/create.d.ts +27 -0
- package/dist/commands/channel/create.d.ts.map +1 -0
- package/dist/commands/channel/create.js +39 -0
- package/dist/commands/channel/create.js.map +1 -0
- package/dist/commands/channel/dev-parse-trace.d.ts +14 -0
- package/dist/commands/channel/dev-parse-trace.d.ts.map +1 -0
- package/dist/commands/channel/dev-parse-trace.js +70 -0
- package/dist/commands/channel/dev-parse-trace.js.map +1 -0
- package/dist/commands/channel/guard.d.ts +150 -0
- package/dist/commands/channel/guard.d.ts.map +1 -0
- package/dist/commands/channel/guard.js +479 -0
- package/dist/commands/channel/guard.js.map +1 -0
- package/dist/commands/channel/index.d.ts +3 -0
- package/dist/commands/channel/index.d.ts.map +1 -0
- package/dist/commands/channel/index.js +535 -0
- package/dist/commands/channel/index.js.map +1 -0
- package/dist/commands/channel/interrupt.d.ts +10 -0
- package/dist/commands/channel/interrupt.d.ts.map +1 -0
- package/dist/commands/channel/interrupt.js +22 -0
- package/dist/commands/channel/interrupt.js.map +1 -0
- package/dist/commands/channel/kill.d.ts +7 -0
- package/dist/commands/channel/kill.d.ts.map +1 -0
- package/dist/commands/channel/kill.js +130 -0
- package/dist/commands/channel/kill.js.map +1 -0
- package/dist/commands/channel/list.d.ts +17 -0
- package/dist/commands/channel/list.d.ts.map +1 -0
- package/dist/commands/channel/list.js +233 -0
- package/dist/commands/channel/list.js.map +1 -0
- package/dist/commands/channel/messages.d.ts +15 -0
- package/dist/commands/channel/messages.d.ts.map +1 -0
- package/dist/commands/channel/messages.js +245 -0
- package/dist/commands/channel/messages.js.map +1 -0
- package/dist/commands/channel/rm.d.ts +27 -0
- package/dist/commands/channel/rm.d.ts.map +1 -0
- package/dist/commands/channel/rm.js +216 -0
- package/dist/commands/channel/rm.js.map +1 -0
- package/dist/commands/channel/run.d.ts +30 -0
- package/dist/commands/channel/run.d.ts.map +1 -0
- package/dist/commands/channel/run.js +130 -0
- package/dist/commands/channel/run.js.map +1 -0
- package/dist/commands/channel/send.d.ts +11 -0
- package/dist/commands/channel/send.d.ts.map +1 -0
- package/dist/commands/channel/send.js +24 -0
- package/dist/commands/channel/send.js.map +1 -0
- package/dist/commands/channel/spawn.d.ts +43 -0
- package/dist/commands/channel/spawn.d.ts.map +1 -0
- package/dist/commands/channel/spawn.js +247 -0
- package/dist/commands/channel/spawn.js.map +1 -0
- package/dist/commands/channel/store/events.d.ts +22 -0
- package/dist/commands/channel/store/events.d.ts.map +1 -0
- package/dist/commands/channel/store/events.js +43 -0
- package/dist/commands/channel/store/events.js.map +1 -0
- package/dist/commands/channel/store/filter.d.ts +3 -0
- package/dist/commands/channel/store/filter.d.ts.map +1 -0
- package/dist/commands/channel/store/filter.js +2 -0
- package/dist/commands/channel/store/filter.js.map +1 -0
- package/dist/commands/channel/store/lock.d.ts +23 -0
- package/dist/commands/channel/store/lock.d.ts.map +1 -0
- package/dist/commands/channel/store/lock.js +99 -0
- package/dist/commands/channel/store/lock.js.map +1 -0
- package/dist/commands/channel/store/paths.d.ts +77 -0
- package/dist/commands/channel/store/paths.d.ts.map +1 -0
- package/dist/commands/channel/store/paths.js +272 -0
- package/dist/commands/channel/store/paths.js.map +1 -0
- package/dist/commands/channel/store/schema.d.ts +27 -0
- package/dist/commands/channel/store/schema.d.ts.map +1 -0
- package/dist/commands/channel/store/schema.js +34 -0
- package/dist/commands/channel/store/schema.js.map +1 -0
- package/dist/commands/channel/store/thread-state.d.ts +5 -0
- package/dist/commands/channel/store/thread-state.d.ts.map +1 -0
- package/dist/commands/channel/store/thread-state.js +16 -0
- package/dist/commands/channel/store/thread-state.js.map +1 -0
- package/dist/commands/channel/store/watch.d.ts +19 -0
- package/dist/commands/channel/store/watch.d.ts.map +1 -0
- package/dist/commands/channel/store/watch.js +153 -0
- package/dist/commands/channel/store/watch.js.map +1 -0
- package/dist/commands/channel/supervisor/idle.d.ts +45 -0
- package/dist/commands/channel/supervisor/idle.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/idle.js +70 -0
- package/dist/commands/channel/supervisor/idle.js.map +1 -0
- package/dist/commands/channel/supervisor/inbox.d.ts +30 -0
- package/dist/commands/channel/supervisor/inbox.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/inbox.js +160 -0
- package/dist/commands/channel/supervisor/inbox.js.map +1 -0
- package/dist/commands/channel/supervisor/shutdown.d.ts +68 -0
- package/dist/commands/channel/supervisor/shutdown.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/shutdown.js +146 -0
- package/dist/commands/channel/supervisor/shutdown.js.map +1 -0
- package/dist/commands/channel/supervisor/stdout.d.ts +71 -0
- package/dist/commands/channel/supervisor/stdout.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/stdout.js +229 -0
- package/dist/commands/channel/supervisor/stdout.js.map +1 -0
- package/dist/commands/channel/supervisor/turns.d.ts +31 -0
- package/dist/commands/channel/supervisor/turns.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/turns.js +45 -0
- package/dist/commands/channel/supervisor/turns.js.map +1 -0
- package/dist/commands/channel/supervisor/warning.d.ts +48 -0
- package/dist/commands/channel/supervisor/warning.d.ts.map +1 -0
- package/dist/commands/channel/supervisor/warning.js +77 -0
- package/dist/commands/channel/supervisor/warning.js.map +1 -0
- package/dist/commands/channel/supervisor.d.ts +91 -0
- package/dist/commands/channel/supervisor.d.ts.map +1 -0
- package/dist/commands/channel/supervisor.js +463 -0
- package/dist/commands/channel/supervisor.js.map +1 -0
- package/dist/commands/channel/text-body.d.ts +13 -0
- package/dist/commands/channel/text-body.d.ts.map +1 -0
- package/dist/commands/channel/text-body.js +47 -0
- package/dist/commands/channel/text-body.js.map +1 -0
- package/dist/commands/channel/threads.d.ts +39 -0
- package/dist/commands/channel/threads.d.ts.map +1 -0
- package/dist/commands/channel/threads.js +106 -0
- package/dist/commands/channel/threads.js.map +1 -0
- package/dist/commands/channel/title.d.ts +12 -0
- package/dist/commands/channel/title.d.ts.map +1 -0
- package/dist/commands/channel/title.js +24 -0
- package/dist/commands/channel/title.js.map +1 -0
- package/dist/commands/channel/wait.d.ts +17 -0
- package/dist/commands/channel/wait.d.ts.map +1 -0
- package/dist/commands/channel/wait.js +75 -0
- package/dist/commands/channel/wait.js.map +1 -0
- package/dist/commands/init.d.ts +71 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +1612 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mem.d.ts +30 -0
- package/dist/commands/mem.d.ts.map +1 -0
- package/dist/commands/mem.js +423 -0
- package/dist/commands/mem.js.map +1 -0
- package/dist/commands/uninstall.d.ts +36 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +205 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.d.ts +133 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +2255 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/upgrade.d.ts +28 -0
- package/dist/commands/upgrade.d.ts.map +1 -0
- package/dist/commands/upgrade.js +84 -0
- package/dist/commands/upgrade.js.map +1 -0
- package/dist/commands/workflow.d.ts +35 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +232 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/configurators/antigravity.d.ts +7 -0
- package/dist/configurators/antigravity.d.ts.map +1 -0
- package/dist/configurators/antigravity.js +11 -0
- package/dist/configurators/antigravity.js.map +1 -0
- package/dist/configurators/claude.d.ts +23 -0
- package/dist/configurators/claude.d.ts.map +1 -0
- package/dist/configurators/claude.js +123 -0
- package/dist/configurators/claude.js.map +1 -0
- package/dist/configurators/codebuddy.d.ts +10 -0
- package/dist/configurators/codebuddy.d.ts.map +1 -0
- package/dist/configurators/codebuddy.js +24 -0
- package/dist/configurators/codebuddy.js.map +1 -0
- package/dist/configurators/codex.d.ts +57 -0
- package/dist/configurators/codex.d.ts.map +1 -0
- package/dist/configurators/codex.js +170 -0
- package/dist/configurators/codex.js.map +1 -0
- package/dist/configurators/copilot.d.ts +18 -0
- package/dist/configurators/copilot.d.ts.map +1 -0
- package/dist/configurators/copilot.js +50 -0
- package/dist/configurators/copilot.js.map +1 -0
- package/dist/configurators/cursor.d.ts +10 -0
- package/dist/configurators/cursor.d.ts.map +1 -0
- package/dist/configurators/cursor.js +23 -0
- package/dist/configurators/cursor.js.map +1 -0
- package/dist/configurators/devin.d.ts +8 -0
- package/dist/configurators/devin.d.ts.map +1 -0
- package/dist/configurators/devin.js +12 -0
- package/dist/configurators/devin.js.map +1 -0
- package/dist/configurators/droid.d.ts +10 -0
- package/dist/configurators/droid.d.ts.map +1 -0
- package/dist/configurators/droid.js +24 -0
- package/dist/configurators/droid.js.map +1 -0
- package/dist/configurators/dsh.d.ts +29 -0
- package/dist/configurators/dsh.d.ts.map +1 -0
- package/dist/configurators/dsh.js +64 -0
- package/dist/configurators/dsh.js.map +1 -0
- package/dist/configurators/gemini.d.ts +19 -0
- package/dist/configurators/gemini.d.ts.map +1 -0
- package/dist/configurators/gemini.js +40 -0
- package/dist/configurators/gemini.js.map +1 -0
- package/dist/configurators/grok.d.ts +17 -0
- package/dist/configurators/grok.d.ts.map +1 -0
- package/dist/configurators/grok.js +38 -0
- package/dist/configurators/grok.js.map +1 -0
- package/dist/configurators/index.d.ts +68 -0
- package/dist/configurators/index.d.ts.map +1 -0
- package/dist/configurators/index.js +191 -0
- package/dist/configurators/index.js.map +1 -0
- package/dist/configurators/kilo.d.ts +7 -0
- package/dist/configurators/kilo.d.ts.map +1 -0
- package/dist/configurators/kilo.js +11 -0
- package/dist/configurators/kilo.js.map +1 -0
- package/dist/configurators/kimi.d.ts +26 -0
- package/dist/configurators/kimi.d.ts.map +1 -0
- package/dist/configurators/kimi.js +74 -0
- package/dist/configurators/kimi.js.map +1 -0
- package/dist/configurators/kiro.d.ts +11 -0
- package/dist/configurators/kiro.d.ts.map +1 -0
- package/dist/configurators/kiro.js +30 -0
- package/dist/configurators/kiro.js.map +1 -0
- package/dist/configurators/omp.d.ts +6 -0
- package/dist/configurators/omp.d.ts.map +1 -0
- package/dist/configurators/omp.js +28 -0
- package/dist/configurators/omp.js.map +1 -0
- package/dist/configurators/opencode.d.ts +5 -0
- package/dist/configurators/opencode.d.ts.map +1 -0
- package/dist/configurators/opencode.js +80 -0
- package/dist/configurators/opencode.js.map +1 -0
- package/dist/configurators/pi.d.ts +5 -0
- package/dist/configurators/pi.d.ts.map +1 -0
- package/dist/configurators/pi.js +39 -0
- package/dist/configurators/pi.js.map +1 -0
- package/dist/configurators/qoder.d.ts +12 -0
- package/dist/configurators/qoder.d.ts.map +1 -0
- package/dist/configurators/qoder.js +30 -0
- package/dist/configurators/qoder.js.map +1 -0
- package/dist/configurators/reasonix.d.ts +17 -0
- package/dist/configurators/reasonix.d.ts.map +1 -0
- package/dist/configurators/reasonix.js +37 -0
- package/dist/configurators/reasonix.js.map +1 -0
- package/dist/configurators/shared.d.ts +196 -0
- package/dist/configurators/shared.d.ts.map +1 -0
- package/dist/configurators/shared.js +600 -0
- package/dist/configurators/shared.js.map +1 -0
- package/dist/configurators/snow.d.ts +25 -0
- package/dist/configurators/snow.d.ts.map +1 -0
- package/dist/configurators/snow.js +69 -0
- package/dist/configurators/snow.js.map +1 -0
- package/dist/configurators/trae.d.ts +16 -0
- package/dist/configurators/trae.d.ts.map +1 -0
- package/dist/configurators/trae.js +34 -0
- package/dist/configurators/trae.js.map +1 -0
- package/dist/configurators/workflow.d.ts +51 -0
- package/dist/configurators/workflow.d.ts.map +1 -0
- package/dist/configurators/workflow.js +210 -0
- package/dist/configurators/workflow.js.map +1 -0
- package/dist/configurators/zcode.d.ts +19 -0
- package/dist/configurators/zcode.d.ts.map +1 -0
- package/dist/configurators/zcode.js +51 -0
- package/dist/configurators/zcode.js.map +1 -0
- package/dist/constants/paths.d.ts +74 -0
- package/dist/constants/paths.d.ts.map +1 -0
- package/dist/constants/paths.js +83 -0
- package/dist/constants/paths.js.map +1 -0
- package/dist/constants/version.d.ts +9 -0
- package/dist/constants/version.d.ts.map +1 -0
- package/dist/constants/version.js +15 -0
- package/dist/constants/version.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/migrations/index.d.ts +65 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +202 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/templates/atw/agents/implement-agent.md +69 -0
- package/dist/templates/atw/agents/review.md +68 -0
- package/dist/templates/atw/config.yaml +158 -0
- package/dist/templates/atw/gitattributes.txt +9 -0
- package/dist/templates/atw/gitignore.txt +32 -0
- package/dist/templates/atw/index.d.ts +70 -0
- package/dist/templates/atw/index.d.ts.map +1 -0
- package/dist/templates/atw/index.js +137 -0
- package/dist/templates/atw/index.js.map +1 -0
- package/dist/templates/atw/scripts/__init__.py +5 -0
- package/dist/templates/atw/scripts/add_session.py +1545 -0
- package/dist/templates/atw/scripts/common/__init__.py +94 -0
- package/dist/templates/atw/scripts/common/active_task.py +857 -0
- package/dist/templates/atw/scripts/common/atw_config.py +239 -0
- package/dist/templates/atw/scripts/common/cli_adapter.py +949 -0
- package/dist/templates/atw/scripts/common/config.py +482 -0
- package/dist/templates/atw/scripts/common/developer.py +192 -0
- package/dist/templates/atw/scripts/common/git.py +203 -0
- package/dist/templates/atw/scripts/common/git_context.py +106 -0
- package/dist/templates/atw/scripts/common/io.py +160 -0
- package/dist/templates/atw/scripts/common/log.py +45 -0
- package/dist/templates/atw/scripts/common/packages_context.py +238 -0
- package/dist/templates/atw/scripts/common/paths.py +543 -0
- package/dist/templates/atw/scripts/common/safe_commit.py +322 -0
- package/dist/templates/atw/scripts/common/session_context.py +892 -0
- package/dist/templates/atw/scripts/common/task_context.py +470 -0
- package/dist/templates/atw/scripts/common/task_queue.py +188 -0
- package/dist/templates/atw/scripts/common/task_store.py +1940 -0
- package/dist/templates/atw/scripts/common/task_utils.py +498 -0
- package/dist/templates/atw/scripts/common/tasks.py +122 -0
- package/dist/templates/atw/scripts/common/types.py +110 -0
- package/dist/templates/atw/scripts/common/workflow_phase.py +242 -0
- package/dist/templates/atw/scripts/get_context.py +16 -0
- package/dist/templates/atw/scripts/get_developer.py +26 -0
- package/dist/templates/atw/scripts/github_sync.py +391 -0
- package/dist/templates/atw/scripts/hooks/linear_sync.py +243 -0
- package/dist/templates/atw/scripts/init_developer.py +51 -0
- package/dist/templates/atw/scripts/task.py +833 -0
- package/dist/templates/atw/scripts/tickets.py +495 -0
- package/dist/templates/atw/tasks/.gitkeep +0 -0
- package/dist/templates/atw/workflow.md +754 -0
- package/dist/templates/claude/agents/atw-implement-agent.md +107 -0
- package/dist/templates/claude/agents/atw-review.md +113 -0
- package/dist/templates/claude/hooks/statusline.py +332 -0
- package/dist/templates/claude/index.d.ts +31 -0
- package/dist/templates/claude/index.d.ts.map +1 -0
- package/dist/templates/claude/index.js +57 -0
- package/dist/templates/claude/index.js.map +1 -0
- package/dist/templates/claude/settings.json +73 -0
- package/dist/templates/codebuddy/agents/atw-implement-agent.md +107 -0
- package/dist/templates/codebuddy/agents/atw-review.md +113 -0
- package/dist/templates/codebuddy/index.d.ts +15 -0
- package/dist/templates/codebuddy/index.d.ts.map +1 -0
- package/dist/templates/codebuddy/index.js +15 -0
- package/dist/templates/codebuddy/index.js.map +1 -0
- package/dist/templates/codebuddy/settings.json +69 -0
- package/dist/templates/codex/agents/atw-implement-agent.toml +37 -0
- package/dist/templates/codex/agents/atw-review.toml +56 -0
- package/dist/templates/codex/config.toml +39 -0
- package/dist/templates/codex/hooks/session-start.py +514 -0
- package/dist/templates/codex/hooks.json +27 -0
- package/dist/templates/codex/index.d.ts +35 -0
- package/dist/templates/codex/index.d.ts.map +1 -0
- package/dist/templates/codex/index.js +67 -0
- package/dist/templates/codex/index.js.map +1 -0
- package/dist/templates/common/bundled-skills/atw-askme/SKILL.md +7 -0
- package/dist/templates/common/bundled-skills/atw-askme/agents/openai.yaml +5 -0
- package/dist/templates/common/bundled-skills/atw-askme-with-docs/SKILL.md +7 -0
- package/dist/templates/common/bundled-skills/atw-askme-with-docs/agents/openai.yaml +5 -0
- package/dist/templates/common/bundled-skills/atw-channel/SKILL.md +67 -0
- package/dist/templates/common/bundled-skills/atw-channel/references/command-reference.md +480 -0
- package/dist/templates/common/bundled-skills/atw-channel/references/forum.md +233 -0
- package/dist/templates/common/bundled-skills/atw-channel/references/progress-debugging.md +226 -0
- package/dist/templates/common/bundled-skills/atw-channel/references/workers.md +274 -0
- package/dist/templates/common/bundled-skills/atw-channel/references/workflows.md +125 -0
- package/dist/templates/common/bundled-skills/atw-code-review/SKILL.md +113 -0
- package/dist/templates/common/bundled-skills/atw-code-review/agents/openai.yaml +3 -0
- package/dist/templates/common/bundled-skills/atw-codebase-design/DEEPENING.md +37 -0
- package/dist/templates/common/bundled-skills/atw-codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/dist/templates/common/bundled-skills/atw-codebase-design/SKILL.md +114 -0
- package/dist/templates/common/bundled-skills/atw-codebase-design/agents/openai.yaml +3 -0
- package/dist/templates/common/bundled-skills/atw-diagnosing-bugs/SKILL.md +138 -0
- package/dist/templates/common/bundled-skills/atw-diagnosing-bugs/agents/openai.yaml +3 -0
- package/dist/templates/common/bundled-skills/atw-diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
- package/dist/templates/common/bundled-skills/atw-domain-modeling/ADR-FORMAT.md +47 -0
- package/dist/templates/common/bundled-skills/atw-domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/dist/templates/common/bundled-skills/atw-domain-modeling/SKILL.md +74 -0
- package/dist/templates/common/bundled-skills/atw-domain-modeling/agents/openai.yaml +3 -0
- package/dist/templates/common/bundled-skills/atw-handoff/SKILL.md +16 -0
- package/dist/templates/common/bundled-skills/atw-handoff/agents/openai.yaml +5 -0
- package/dist/templates/common/bundled-skills/atw-implement/SKILL.md +21 -0
- package/dist/templates/common/bundled-skills/atw-implement/agents/openai.yaml +5 -0
- package/dist/templates/common/bundled-skills/atw-improve-codebase-architecture/HTML-REPORT.md +123 -0
- package/dist/templates/common/bundled-skills/atw-improve-codebase-architecture/SKILL.md +71 -0
- package/dist/templates/common/bundled-skills/atw-improve-codebase-architecture/agents/openai.yaml +5 -0
- package/dist/templates/common/bundled-skills/atw-init-repo/SKILL.md +130 -0
- package/dist/templates/common/bundled-skills/atw-init-repo/references/domain.md +51 -0
- package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw-local.md +133 -0
- package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-atw.md +109 -0
- package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-github.md +45 -0
- package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-gitlab.md +46 -0
- package/dist/templates/common/bundled-skills/atw-init-repo/references/issue-tracker-local.md +30 -0
- package/dist/templates/common/bundled-skills/atw-init-repo/references/triage-labels.md +15 -0
- package/dist/templates/common/bundled-skills/atw-interview/SKILL.md +22 -0
- package/dist/templates/common/bundled-skills/atw-interview/agents/openai.yaml +3 -0
- package/dist/templates/common/bundled-skills/atw-map/SKILL.md +128 -0
- package/dist/templates/common/bundled-skills/atw-map/agents/openai.yaml +5 -0
- package/dist/templates/common/bundled-skills/atw-merge/SKILL.md +14 -0
- package/dist/templates/common/bundled-skills/atw-merge/agents/openai.yaml +3 -0
- package/dist/templates/common/bundled-skills/atw-meta/SKILL.md +85 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/add-project-local-conventions.md +83 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-agents.md +55 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-context-loading.md +80 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-hooks.md +57 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-skills-or-commands.md +123 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-spec-structure.md +83 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-task-lifecycle.md +91 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/change-workflow.md +59 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/customize-local/overview.md +55 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/bundled-skills.md +159 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/context-injection.md +68 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/generated-files.md +80 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/multi-agent-channel.md +69 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/overview.md +51 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/spec-system.md +102 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/task-system.md +126 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/workflow.md +79 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/local-architecture/workspace-memory.md +71 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/agents.md +80 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/hooks-and-settings.md +72 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/overview.md +59 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/platform-map.md +112 -0
- package/dist/templates/common/bundled-skills/atw-meta/references/platform-files/skills-and-commands.md +86 -0
- package/dist/templates/common/bundled-skills/atw-prototype/LOGIC.md +67 -0
- package/dist/templates/common/bundled-skills/atw-prototype/SKILL.md +26 -0
- package/dist/templates/common/bundled-skills/atw-prototype/UI.md +112 -0
- package/dist/templates/common/bundled-skills/atw-prototype/agents/openai.yaml +3 -0
- package/dist/templates/common/bundled-skills/atw-research/SKILL.md +14 -0
- package/dist/templates/common/bundled-skills/atw-research/agents/openai.yaml +3 -0
- package/dist/templates/common/bundled-skills/atw-session-insight/SKILL.md +81 -0
- package/dist/templates/common/bundled-skills/atw-session-insight/references/cli-quick-reference.md +65 -0
- package/dist/templates/common/bundled-skills/atw-session-insight/references/triggering-patterns.md +93 -0
- package/dist/templates/common/bundled-skills/atw-spec/SKILL.md +75 -0
- package/dist/templates/common/bundled-skills/atw-spec/agents/openai.yaml +5 -0
- package/dist/templates/common/bundled-skills/atw-spec-bootstrap/SKILL.md +41 -0
- package/dist/templates/common/bundled-skills/atw-spec-bootstrap/references/mcp-setup.md +90 -0
- package/dist/templates/common/bundled-skills/atw-spec-bootstrap/references/repository-analysis.md +59 -0
- package/dist/templates/common/bundled-skills/atw-spec-bootstrap/references/spec-task-planning.md +61 -0
- package/dist/templates/common/bundled-skills/atw-spec-bootstrap/references/spec-writing.md +70 -0
- package/dist/templates/common/bundled-skills/atw-tdd/SKILL.md +38 -0
- package/dist/templates/common/bundled-skills/atw-tdd/agents/openai.yaml +3 -0
- package/dist/templates/common/bundled-skills/atw-tdd/mocking.md +59 -0
- package/dist/templates/common/bundled-skills/atw-tdd/tests.md +77 -0
- package/dist/templates/common/bundled-skills/atw-tickets/SKILL.md +105 -0
- package/dist/templates/common/bundled-skills/atw-tickets/agents/openai.yaml +5 -0
- package/dist/templates/common/bundled-skills/atw-triage/AGENT-BRIEF.md +207 -0
- package/dist/templates/common/bundled-skills/atw-triage/OUT-OF-SCOPE.md +105 -0
- package/dist/templates/common/bundled-skills/atw-triage/SKILL.md +112 -0
- package/dist/templates/common/bundled-skills/atw-triage/agents/openai.yaml +5 -0
- package/dist/templates/common/commands/continue.md +55 -0
- package/dist/templates/common/commands/finish-work.md +69 -0
- package/dist/templates/common/commands/start.md +68 -0
- package/dist/templates/common/index.d.ts +48 -0
- package/dist/templates/common/index.d.ts.map +1 -0
- package/dist/templates/common/index.js +104 -0
- package/dist/templates/common/index.js.map +1 -0
- package/dist/templates/common/skills/before-dev.md +44 -0
- package/dist/templates/common/skills/brainstorm.md +194 -0
- package/dist/templates/common/skills/update-spec.md +351 -0
- package/dist/templates/copilot/copilot-instructions.md +11 -0
- package/dist/templates/copilot/hooks/session-start.py +510 -0
- package/dist/templates/copilot/hooks.json +19 -0
- package/dist/templates/copilot/index.d.ts +23 -0
- package/dist/templates/copilot/index.d.ts.map +1 -0
- package/dist/templates/copilot/index.js +48 -0
- package/dist/templates/copilot/index.js.map +1 -0
- package/dist/templates/cursor/agents/atw-implement-agent.md +106 -0
- package/dist/templates/cursor/agents/atw-review.md +112 -0
- package/dist/templates/cursor/hooks.json +24 -0
- package/dist/templates/cursor/index.d.ts +13 -0
- package/dist/templates/cursor/index.d.ts.map +1 -0
- package/dist/templates/cursor/index.js +13 -0
- package/dist/templates/cursor/index.js.map +1 -0
- package/dist/templates/droid/droids/atw-implement-agent.md +99 -0
- package/dist/templates/droid/droids/atw-review.md +105 -0
- package/dist/templates/droid/index.d.ts +15 -0
- package/dist/templates/droid/index.d.ts.map +1 -0
- package/dist/templates/droid/index.js +15 -0
- package/dist/templates/droid/index.js.map +1 -0
- package/dist/templates/droid/settings.json +69 -0
- package/dist/templates/dsh/DSH.md +56 -0
- package/dist/templates/dsh/index.d.ts +21 -0
- package/dist/templates/dsh/index.d.ts.map +1 -0
- package/dist/templates/dsh/index.js +25 -0
- package/dist/templates/dsh/index.js.map +1 -0
- package/dist/templates/extract.d.ts +40 -0
- package/dist/templates/extract.d.ts.map +1 -0
- package/dist/templates/extract.js +106 -0
- package/dist/templates/extract.js.map +1 -0
- package/dist/templates/gemini/agents/atw-implement-agent.md +99 -0
- package/dist/templates/gemini/agents/atw-review.md +105 -0
- package/dist/templates/gemini/index.d.ts +13 -0
- package/dist/templates/gemini/index.d.ts.map +1 -0
- package/dist/templates/gemini/index.js +13 -0
- package/dist/templates/gemini/index.js.map +1 -0
- package/dist/templates/gemini/settings.json +40 -0
- package/dist/templates/grok/agents/atw-implement-agent.md +115 -0
- package/dist/templates/grok/agents/atw-review.md +105 -0
- package/dist/templates/grok/index.d.ts +15 -0
- package/dist/templates/grok/index.d.ts.map +1 -0
- package/dist/templates/grok/index.js +18 -0
- package/dist/templates/grok/index.js.map +1 -0
- package/dist/templates/kimi/agents/atw-implement-agent.md +114 -0
- package/dist/templates/kimi/agents/atw-review.md +103 -0
- package/dist/templates/kimi/index.d.ts +20 -0
- package/dist/templates/kimi/index.d.ts.map +1 -0
- package/dist/templates/kimi/index.js +23 -0
- package/dist/templates/kimi/index.js.map +1 -0
- package/dist/templates/kiro/agents/atw-implement-agent.json +26 -0
- package/dist/templates/kiro/agents/atw-review.json +26 -0
- package/dist/templates/kiro/agents/atw.json +34 -0
- package/dist/templates/kiro/hooks/atw-workflow-state.kiro.hook +14 -0
- package/dist/templates/kiro/index.d.ts +32 -0
- package/dist/templates/kiro/index.d.ts.map +1 -0
- package/dist/templates/kiro/index.js +28 -0
- package/dist/templates/kiro/index.js.map +1 -0
- package/dist/templates/markdown/agents.md +21 -0
- package/dist/templates/markdown/gitignore.txt +15 -0
- package/dist/templates/markdown/index.d.ts +27 -0
- package/dist/templates/markdown/index.d.ts.map +1 -0
- package/dist/templates/markdown/index.js +52 -0
- package/dist/templates/markdown/index.js.map +1 -0
- package/dist/templates/markdown/spec/backend/database-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/directory-structure.md.txt +54 -0
- package/dist/templates/markdown/spec/backend/error-handling.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/index.md.txt +38 -0
- package/dist/templates/markdown/spec/backend/logging-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/backend/quality-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/component-guidelines.md.txt +59 -0
- package/dist/templates/markdown/spec/frontend/directory-structure.md.txt +54 -0
- package/dist/templates/markdown/spec/frontend/hook-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/index.md.txt +39 -0
- package/dist/templates/markdown/spec/frontend/quality-guidelines.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/state-management.md.txt +51 -0
- package/dist/templates/markdown/spec/frontend/type-safety.md.txt +51 -0
- package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +223 -0
- package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +290 -0
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +634 -0
- package/dist/templates/markdown/spec/guides/index.md.txt +97 -0
- package/dist/templates/markdown/workspace-index.md +125 -0
- package/dist/templates/markdown/worktree.yaml.txt +58 -0
- package/dist/templates/omp/agents/atw-implement-agent.md +45 -0
- package/dist/templates/omp/agents/atw-review.md +41 -0
- package/dist/templates/omp/extensions/atw/index.ts.txt +1109 -0
- package/dist/templates/omp/index.d.ts +4 -0
- package/dist/templates/omp/index.d.ts.map +1 -0
- package/dist/templates/omp/index.js +9 -0
- package/dist/templates/omp/index.js.map +1 -0
- package/dist/templates/opencode/agents/atw-implement-agent.md +115 -0
- package/dist/templates/opencode/agents/atw-review.md +120 -0
- package/dist/templates/opencode/lib/atw-context.js +637 -0
- package/dist/templates/opencode/lib/context-visibility.js +148 -0
- package/dist/templates/opencode/lib/session-utils.js +474 -0
- package/dist/templates/opencode/package.json +6 -0
- package/dist/templates/opencode/plugins/inject-subagent-context.js +390 -0
- package/dist/templates/opencode/plugins/inject-workflow-state.js +240 -0
- package/dist/templates/opencode/plugins/session-start.js +65 -0
- package/dist/templates/pi/agents/atw-implement-agent.md +42 -0
- package/dist/templates/pi/agents/atw-review.md +37 -0
- package/dist/templates/pi/extensions/atw/index.ts.txt +2014 -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 +9 -0
- package/dist/templates/qoder/agents/atw-implement-agent.md +100 -0
- package/dist/templates/qoder/agents/atw-review.md +106 -0
- package/dist/templates/qoder/index.d.ts +15 -0
- package/dist/templates/qoder/index.d.ts.map +1 -0
- package/dist/templates/qoder/index.js +15 -0
- package/dist/templates/qoder/index.js.map +1 -0
- package/dist/templates/qoder/settings.json +59 -0
- package/dist/templates/reasonix/agents/atw-implement-agent.md +41 -0
- package/dist/templates/reasonix/agents/atw-review.md +36 -0
- package/dist/templates/reasonix/index.d.ts +13 -0
- package/dist/templates/reasonix/index.d.ts.map +1 -0
- package/dist/templates/reasonix/index.js +16 -0
- package/dist/templates/reasonix/index.js.map +1 -0
- package/dist/templates/shared-hooks/index.d.ts +77 -0
- package/dist/templates/shared-hooks/index.d.ts.map +1 -0
- package/dist/templates/shared-hooks/index.js +140 -0
- package/dist/templates/shared-hooks/index.js.map +1 -0
- package/dist/templates/shared-hooks/inject-shell-session-context.py +292 -0
- package/dist/templates/shared-hooks/inject-subagent-context.py +1178 -0
- package/dist/templates/shared-hooks/inject-workflow-state.py +488 -0
- package/dist/templates/shared-hooks/session-start.py +889 -0
- package/dist/templates/snow/SNOW.md +86 -0
- package/dist/templates/snow/agents/atw-implement-agent.md +152 -0
- package/dist/templates/snow/agents/atw-review.md +135 -0
- package/dist/templates/snow/hooks/beforeSubAgentStart.json +15 -0
- package/dist/templates/snow/hooks/onSessionStart.json +15 -0
- package/dist/templates/snow/hooks/onUserMessage.json +15 -0
- package/dist/templates/snow/hooks/write-atw-context.py +637 -0
- package/dist/templates/snow/index.d.ts +25 -0
- package/dist/templates/snow/index.d.ts.map +1 -0
- package/dist/templates/snow/index.js +35 -0
- package/dist/templates/snow/index.js.map +1 -0
- 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 +64 -0
- package/dist/templates/template-utils.js.map +1 -0
- package/dist/templates/trae/agents/atw-implement-agent.md +100 -0
- package/dist/templates/trae/agents/atw-review.md +106 -0
- package/dist/templates/trae/hooks.json +39 -0
- package/dist/templates/trae/index.d.ts +15 -0
- package/dist/templates/trae/index.d.ts.map +1 -0
- package/dist/templates/trae/index.js +15 -0
- package/dist/templates/trae/index.js.map +1 -0
- package/dist/templates/zcode/agents/atw-implement-agent.md +108 -0
- package/dist/templates/zcode/agents/atw-review.md +109 -0
- package/dist/templates/zcode/config.json +52 -0
- package/dist/templates/zcode/index.d.ts +22 -0
- package/dist/templates/zcode/index.d.ts.map +1 -0
- package/dist/templates/zcode/index.js +26 -0
- package/dist/templates/zcode/index.js.map +1 -0
- package/dist/types/ai-tools.d.ts +95 -0
- package/dist/types/ai-tools.d.ts.map +1 -0
- package/dist/types/ai-tools.js +494 -0
- package/dist/types/ai-tools.js.map +1 -0
- package/dist/types/migration.d.ts +125 -0
- package/dist/types/migration.d.ts.map +1 -0
- package/dist/types/migration.js +8 -0
- package/dist/types/migration.js.map +1 -0
- package/dist/utils/ablation-store.d.ts +123 -0
- package/dist/utils/ablation-store.d.ts.map +1 -0
- package/dist/utils/ablation-store.js +749 -0
- package/dist/utils/ablation-store.js.map +1 -0
- package/dist/utils/agent-refs.d.ts +31 -0
- package/dist/utils/agent-refs.d.ts.map +1 -0
- package/dist/utils/agent-refs.js +63 -0
- package/dist/utils/agent-refs.js.map +1 -0
- package/dist/utils/atomic-write.d.ts +12 -0
- package/dist/utils/atomic-write.d.ts.map +1 -0
- package/dist/utils/atomic-write.js +30 -0
- package/dist/utils/atomic-write.js.map +1 -0
- package/dist/utils/compare-versions.d.ts +12 -0
- package/dist/utils/compare-versions.d.ts.map +1 -0
- package/dist/utils/compare-versions.js +86 -0
- package/dist/utils/compare-versions.js.map +1 -0
- package/dist/utils/cwd-guard.d.ts +38 -0
- package/dist/utils/cwd-guard.d.ts.map +1 -0
- package/dist/utils/cwd-guard.js +62 -0
- package/dist/utils/cwd-guard.js.map +1 -0
- package/dist/utils/file-writer.d.ts +36 -0
- package/dist/utils/file-writer.d.ts.map +1 -0
- package/dist/utils/file-writer.js +204 -0
- package/dist/utils/file-writer.js.map +1 -0
- package/dist/utils/managed-paths.d.ts +5 -0
- package/dist/utils/managed-paths.d.ts.map +1 -0
- package/dist/utils/managed-paths.js +51 -0
- package/dist/utils/managed-paths.js.map +1 -0
- package/dist/utils/managed-removal.d.ts +74 -0
- package/dist/utils/managed-removal.d.ts.map +1 -0
- package/dist/utils/managed-removal.js +270 -0
- package/dist/utils/managed-removal.js.map +1 -0
- package/dist/utils/manifest-prune.d.ts +61 -0
- package/dist/utils/manifest-prune.d.ts.map +1 -0
- package/dist/utils/manifest-prune.js +135 -0
- package/dist/utils/manifest-prune.js.map +1 -0
- 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/project-detector.d.ts +46 -0
- package/dist/utils/project-detector.d.ts.map +1 -0
- package/dist/utils/project-detector.js +666 -0
- package/dist/utils/project-detector.js.map +1 -0
- package/dist/utils/proxy.d.ts +25 -0
- package/dist/utils/proxy.d.ts.map +1 -0
- package/dist/utils/proxy.js +60 -0
- package/dist/utils/proxy.js.map +1 -0
- package/dist/utils/registry-config.d.ts +7 -0
- package/dist/utils/registry-config.d.ts.map +1 -0
- package/dist/utils/registry-config.js +172 -0
- package/dist/utils/registry-config.js.map +1 -0
- package/dist/utils/task-json.d.ts +13 -0
- package/dist/utils/task-json.d.ts.map +1 -0
- package/dist/utils/task-json.js +12 -0
- package/dist/utils/task-json.js.map +1 -0
- package/dist/utils/template-fetcher.d.ts +161 -0
- package/dist/utils/template-fetcher.d.ts.map +1 -0
- package/dist/utils/template-fetcher.js +994 -0
- package/dist/utils/template-fetcher.js.map +1 -0
- package/dist/utils/template-hash.d.ts +127 -0
- package/dist/utils/template-hash.d.ts.map +1 -0
- package/dist/utils/template-hash.js +335 -0
- package/dist/utils/template-hash.js.map +1 -0
- package/dist/utils/uninstall-scrubbers.d.ts +66 -0
- package/dist/utils/uninstall-scrubbers.d.ts.map +1 -0
- package/dist/utils/uninstall-scrubbers.js +417 -0
- package/dist/utils/uninstall-scrubbers.js.map +1 -0
- package/dist/utils/workflow-resolver.d.ts +86 -0
- package/dist/utils/workflow-resolver.d.ts.map +1 -0
- package/dist/utils/workflow-resolver.js +265 -0
- package/dist/utils/workflow-resolver.js.map +1 -0
- package/package.json +93 -0
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""任务目录 → 远程 GitHub 的单向同步。安装到 .atw/scripts/github_sync.py。
|
|
3
|
+
|
|
4
|
+
**权威始终在任务目录,远程是镜像。** 不做双向——双向要处理冲突合并,而正文是
|
|
5
|
+
你自己写的,远程改正文的场景基本不存在。
|
|
6
|
+
|
|
7
|
+
create 确保任务有对应的远程 Issue,号码写进 meta.source_ref
|
|
8
|
+
sync-spec 把 <task>/prd.md 整篇推到 Issue 正文
|
|
9
|
+
sync-tickets 每张票建一个 sub-issue + 原生 blocked_by 依赖边,
|
|
10
|
+
票文件回填 **Issue:** #NN
|
|
11
|
+
archive 关闭远程 Issue
|
|
12
|
+
selfcheck 跑内置断言(不联网)
|
|
13
|
+
|
|
14
|
+
**本脚本默认不接线,也不该默认接线。** 镜像是逐仓选择:装了 ATW 不等于
|
|
15
|
+
这个仓库要把任务目录推到 GitHub Issues。所以 `.atw/config.yaml` 的 `hooks:`
|
|
16
|
+
整段出厂就是注释掉的(模板里没有任何一个默认开启的 hook),`workflow.md`
|
|
17
|
+
也不提它——那个文件对 tracker 是中立的。
|
|
18
|
+
|
|
19
|
+
一个仓库**是否**跑镜像,写在 `docs/agents/issue-tracker.md` 里,由
|
|
20
|
+
`atw-init-repo` 技能落盘。选「ATW 任务目录 + GitHub」变体的仓库,那份文档会
|
|
21
|
+
列出下面两条显式命令和该加的两个 hook;选「纯本地」变体的,文档里有一节
|
|
22
|
+
「Re-enabling the GitHub mirror」讲怎么打开。**别到别处找接线,那里没有。**
|
|
23
|
+
|
|
24
|
+
两种触发方式,不能都当 Hook:
|
|
25
|
+
|
|
26
|
+
create / archive 真 Hook,加进 .atw/config.yaml 的 hooks: 段
|
|
27
|
+
sync-spec / sync-tickets 显式调用,由跑流程的人/代理按 tracker 文档执行
|
|
28
|
+
|
|
29
|
+
原因:**Lifecycle Hook 事件全在任务生命周期转换时触发**,没有任何事件在
|
|
30
|
+
prd.md 或 issues/*.md 被写入时触发。所以「写完 Spec 自动同步」靠 hooks: 配置
|
|
31
|
+
做不到。
|
|
32
|
+
|
|
33
|
+
失败策略按调用方式分:
|
|
34
|
+
|
|
35
|
+
Hook 场景(create/archive) gh 缺失、没有远程仓库 → 警告后退出 0,
|
|
36
|
+
不能因为同步失败就阻断建任务/归档
|
|
37
|
+
显式场景(sync-*) 同样情况 → 退出 1,因为是你主动要求同步的
|
|
38
|
+
|
|
39
|
+
环境变量 TASK_JSON_PATH 指向 task.json:Hook 场景由 task.py 自动设置,
|
|
40
|
+
显式调用时自己传。
|
|
41
|
+
"""
|
|
42
|
+
from __future__ import annotations
|
|
43
|
+
|
|
44
|
+
import json
|
|
45
|
+
import os
|
|
46
|
+
import re
|
|
47
|
+
import subprocess
|
|
48
|
+
import sys
|
|
49
|
+
import tempfile
|
|
50
|
+
from pathlib import Path
|
|
51
|
+
|
|
52
|
+
# 票的解析复用 tickets.py,不在这里造第二个解析器——
|
|
53
|
+
# 一个概念只有一个地方校验,Blocker 成环之类的检查也就只有一份实现。
|
|
54
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
55
|
+
from tickets import ( # noqa: E402
|
|
56
|
+
Ticket, TicketError, field_pattern, load_tickets,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
RE_ISSUE = field_pattern("Issue")
|
|
60
|
+
|
|
61
|
+
# 「已经建过这条边」这类错误是幂等重跑的正常结果,不当失败
|
|
62
|
+
ALREADY_EXISTS = ("already", "must be unique", "duplicate")
|
|
63
|
+
# 没有 GitHub 远程不是故障,是「这个仓库不走镜像」。三个 cmd_* 据此优雅跳过,
|
|
64
|
+
# 否则 Specify / Slice 的完成条件在纯本地仓库里永远满足不了,流程直接死锁。
|
|
65
|
+
NO_REMOTE_HINTS = ("no git remotes found", "not a git repository")
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class SyncError(Exception):
|
|
69
|
+
"""同步失败。Hook 场景转成警告,显式场景转成退出码 1。"""
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
# 纯函数(selfcheck 驱动这一层)
|
|
74
|
+
# ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
def dependency_order(tickets: list[Ticket]) -> list[Ticket]:
|
|
77
|
+
"""按依赖顺序排序:blocker 一定排在被它挡住的票前面。
|
|
78
|
+
|
|
79
|
+
必须先建 blocker 的 Issue 才能拿到它的 database id 去建依赖边。
|
|
80
|
+
load_tickets 已经保证无环、无悬空引用,所以这里不用再校验一次。
|
|
81
|
+
"""
|
|
82
|
+
by_num = {t.num: t for t in tickets}
|
|
83
|
+
ordered: list[Ticket] = []
|
|
84
|
+
seen: set[int] = set()
|
|
85
|
+
|
|
86
|
+
def visit(t: Ticket) -> None:
|
|
87
|
+
if t.num in seen:
|
|
88
|
+
return
|
|
89
|
+
seen.add(t.num)
|
|
90
|
+
for b in t.blockers:
|
|
91
|
+
visit(by_num[b])
|
|
92
|
+
ordered.append(t)
|
|
93
|
+
|
|
94
|
+
for t in sorted(tickets, key=lambda x: x.num):
|
|
95
|
+
visit(t)
|
|
96
|
+
return ordered
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def read_issue_ref(path: Path) -> str | None:
|
|
100
|
+
"""读票文件里的 **Issue:** #58,返回 "58"。没填返回 None。"""
|
|
101
|
+
m = RE_ISSUE.search(path.read_text(encoding="utf-8"))
|
|
102
|
+
if not m:
|
|
103
|
+
return None
|
|
104
|
+
value = m.group(1).strip().lstrip("#")
|
|
105
|
+
return value or None
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def write_issue_ref(path: Path, number: str) -> None:
|
|
109
|
+
text = path.read_text(encoding="utf-8")
|
|
110
|
+
new_text, n = RE_ISSUE.subn(f"**Issue:** #{number}", text, count=1)
|
|
111
|
+
if n != 1:
|
|
112
|
+
raise SyncError(f"{path.name} 没有 **Issue:** 字段,无法回填")
|
|
113
|
+
path.write_text(new_text, encoding="utf-8")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# ---------------------------------------------------------------------------
|
|
117
|
+
# gh 交界面
|
|
118
|
+
# ---------------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
def gh(*args: str, tolerate_existing: bool = False) -> str:
|
|
121
|
+
proc = subprocess.run(
|
|
122
|
+
["gh", *args], capture_output=True, text=True,
|
|
123
|
+
encoding="utf-8", errors="replace",
|
|
124
|
+
)
|
|
125
|
+
if proc.returncode != 0:
|
|
126
|
+
err = (proc.stderr or proc.stdout).strip()
|
|
127
|
+
if tolerate_existing and any(k in err.lower() for k in ALREADY_EXISTS):
|
|
128
|
+
return ""
|
|
129
|
+
raise SyncError(f"gh {' '.join(args)} 失败:{err}")
|
|
130
|
+
return proc.stdout.strip()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def require_gh() -> str:
|
|
134
|
+
"""确认 gh 可用且当前仓库有 GitHub 远程,返回 owner/repo。"""
|
|
135
|
+
try:
|
|
136
|
+
return gh("repo", "view", "--json", "nameWithOwner", "--jq", ".nameWithOwner")
|
|
137
|
+
except FileNotFoundError:
|
|
138
|
+
raise SyncError("找不到 gh 命令。装一个 GitHub CLI,或者把这个 Hook 从 config.yaml 里去掉")
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def is_no_remote_error(msg: str) -> bool:
|
|
142
|
+
"""区分「这仓库没有远程」和「gh 真的出错了」。"""
|
|
143
|
+
return any(h in msg.lower() for h in NO_REMOTE_HINTS)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def remote_repo() -> str | None:
|
|
147
|
+
"""有 GitHub 远程返回 owner/repo,纯本地仓库返回 None,其余照常抛错。"""
|
|
148
|
+
try:
|
|
149
|
+
return require_gh()
|
|
150
|
+
except SyncError as e:
|
|
151
|
+
if is_no_remote_error(str(e)):
|
|
152
|
+
return None
|
|
153
|
+
raise
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def issue_db_id(repo: str, number: str) -> str:
|
|
157
|
+
"""依赖边要的是 database id,不是 #number 也不是 node_id。"""
|
|
158
|
+
return gh("api", f"repos/{repo}/issues/{number}", "--jq", ".id")
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# ---------------------------------------------------------------------------
|
|
162
|
+
# 任务目录
|
|
163
|
+
# ---------------------------------------------------------------------------
|
|
164
|
+
|
|
165
|
+
def read_task() -> tuple[dict, Path, Path]:
|
|
166
|
+
raw = os.environ.get("TASK_JSON_PATH", "")
|
|
167
|
+
if not raw:
|
|
168
|
+
raise SyncError(
|
|
169
|
+
"TASK_JSON_PATH 没设。Hook 场景由 task.py 自动设置;"
|
|
170
|
+
"显式调用时自己传:TASK_JSON_PATH=<task>/task.json python3 ..."
|
|
171
|
+
)
|
|
172
|
+
task_json = Path(raw).resolve()
|
|
173
|
+
if not task_json.is_file():
|
|
174
|
+
raise SyncError(f"找不到 {task_json}")
|
|
175
|
+
return json.loads(task_json.read_text(encoding="utf-8")), task_json, task_json.parent
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def write_task(data: dict, path: Path) -> None:
|
|
179
|
+
path.write_text(
|
|
180
|
+
json.dumps(data, indent=2, ensure_ascii=False) + "\n", encoding="utf-8"
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def source_ref(task: dict) -> str | None:
|
|
185
|
+
meta = task.get("meta")
|
|
186
|
+
ref = meta.get("source_ref") if isinstance(meta, dict) else None
|
|
187
|
+
return str(ref).lstrip("#") if ref else None
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
# ---------------------------------------------------------------------------
|
|
191
|
+
# 命令
|
|
192
|
+
# ---------------------------------------------------------------------------
|
|
193
|
+
|
|
194
|
+
def cmd_create() -> None:
|
|
195
|
+
task, task_json, task_dir = read_task()
|
|
196
|
+
if source_ref(task):
|
|
197
|
+
print(f"已有远程 Issue #{source_ref(task)},不重复创建")
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
repo = remote_repo()
|
|
201
|
+
if repo is None:
|
|
202
|
+
print("本仓库没有 GitHub 远程,跳过 Issue 创建")
|
|
203
|
+
return
|
|
204
|
+
title = task.get("title") or task.get("id") or task_dir.name
|
|
205
|
+
# 建任务时 prd.md 还是默认骨架,推上去是噪声。先占位,等 sync-spec 推正文。
|
|
206
|
+
url = gh("issue", "create", "--repo", repo, "--title", str(title),
|
|
207
|
+
"--body", "Spec 尚未写入。写完后由 `github_sync.py sync-spec` 同步正文。")
|
|
208
|
+
number = url.rstrip("/").rsplit("/", 1)[-1]
|
|
209
|
+
|
|
210
|
+
task.setdefault("meta", {})["source_ref"] = number
|
|
211
|
+
write_task(task, task_json)
|
|
212
|
+
print(f"已创建远程 Issue #{number},并写进 meta.source_ref")
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def cmd_sync_spec() -> None:
|
|
216
|
+
task, _, task_dir = read_task()
|
|
217
|
+
number = source_ref(task)
|
|
218
|
+
if not number:
|
|
219
|
+
if remote_repo() is None:
|
|
220
|
+
print("本仓库没有 GitHub 远程,跳过 Spec 同步")
|
|
221
|
+
return
|
|
222
|
+
raise SyncError("meta.source_ref 是空的。先跑 create,或者手工填上已有的 Issue 号")
|
|
223
|
+
|
|
224
|
+
prd = task_dir / "prd.md"
|
|
225
|
+
if not prd.is_file():
|
|
226
|
+
raise SyncError(f"找不到 {prd}。Specify 阶段还没写 Spec?")
|
|
227
|
+
|
|
228
|
+
repo = require_gh()
|
|
229
|
+
gh("issue", "edit", number, "--repo", repo, "--body-file", str(prd))
|
|
230
|
+
print(f"prd.md → Issue #{number}")
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def cmd_sync_tickets() -> None:
|
|
234
|
+
task, _, task_dir = read_task()
|
|
235
|
+
parent = source_ref(task)
|
|
236
|
+
if not parent:
|
|
237
|
+
if remote_repo() is None:
|
|
238
|
+
print("本仓库没有 GitHub 远程,跳过票同步")
|
|
239
|
+
return
|
|
240
|
+
raise SyncError("meta.source_ref 是空的。先跑 create")
|
|
241
|
+
|
|
242
|
+
tickets = load_tickets(task_dir / "issues")
|
|
243
|
+
if not tickets:
|
|
244
|
+
print("没有票(单会话任务的正常状态),跳过")
|
|
245
|
+
return
|
|
246
|
+
|
|
247
|
+
repo = require_gh()
|
|
248
|
+
numbers: dict[int, str] = {}
|
|
249
|
+
|
|
250
|
+
# 必须按依赖顺序:先建 blocker 才能拿到它的 database id 去建边
|
|
251
|
+
for t in dependency_order(tickets):
|
|
252
|
+
number = read_issue_ref(t.path)
|
|
253
|
+
if number:
|
|
254
|
+
gh("issue", "edit", number, "--repo", repo, "--body-file", str(t.path))
|
|
255
|
+
print(f"{t.label} → 更新 Issue #{number}")
|
|
256
|
+
else:
|
|
257
|
+
url = gh("issue", "create", "--repo", repo,
|
|
258
|
+
"--title", t.label, "--body-file", str(t.path))
|
|
259
|
+
number = url.rstrip("/").rsplit("/", 1)[-1]
|
|
260
|
+
write_issue_ref(t.path, number)
|
|
261
|
+
print(f"{t.label} → 新建 Issue #{number},已回填 **Issue:**")
|
|
262
|
+
# 挂成来源 Issue 的 sub-issue。重跑时 GitHub 会报「已存在」,忽略即可
|
|
263
|
+
gh("api", "--method", "POST", f"repos/{repo}/issues/{parent}/sub_issues",
|
|
264
|
+
"-F", f"sub_issue_id={issue_db_id(repo, number)}",
|
|
265
|
+
tolerate_existing=True)
|
|
266
|
+
numbers[t.num] = number
|
|
267
|
+
|
|
268
|
+
# 依赖边单独一轮:这时候所有票都有号了
|
|
269
|
+
for t in tickets:
|
|
270
|
+
for b in t.blockers:
|
|
271
|
+
gh("api", "--method", "POST",
|
|
272
|
+
f"repos/{repo}/issues/{numbers[t.num]}/dependencies/blocked_by",
|
|
273
|
+
"-F", f"issue_id={issue_db_id(repo, numbers[b])}",
|
|
274
|
+
tolerate_existing=True)
|
|
275
|
+
print(f"依赖边:#{numbers[t.num]} blocked_by #{numbers[b]}")
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def cmd_archive() -> None:
|
|
279
|
+
task, _, task_dir = read_task()
|
|
280
|
+
number = source_ref(task)
|
|
281
|
+
if not number:
|
|
282
|
+
print("没有 meta.source_ref,没有远程 Issue 要关")
|
|
283
|
+
return
|
|
284
|
+
repo = require_gh()
|
|
285
|
+
|
|
286
|
+
# 先关子 issue 再关父 issue。归档门禁已保证所有票 Impl: done,
|
|
287
|
+
# 漏关的话镜像里会永久留下 N 个 OPEN 的票,几个任务之后 issue 列表全是噪音。
|
|
288
|
+
for t in load_tickets(task_dir / "issues"):
|
|
289
|
+
sub = read_issue_ref(t.path)
|
|
290
|
+
if sub:
|
|
291
|
+
gh("issue", "close", sub, "--repo", repo, "--comment", "任务已归档。")
|
|
292
|
+
print(f"{t.label} → 已关闭 Issue #{sub}")
|
|
293
|
+
|
|
294
|
+
gh("issue", "close", number, "--repo", repo, "--comment", "任务已归档。")
|
|
295
|
+
print(f"已关闭 Issue #{number}")
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
# ---------------------------------------------------------------------------
|
|
299
|
+
# 自检:只跑不联网的那部分
|
|
300
|
+
# ---------------------------------------------------------------------------
|
|
301
|
+
|
|
302
|
+
TICKET_TMPL = """# {label}
|
|
303
|
+
|
|
304
|
+
**Status:** ready-for-agent
|
|
305
|
+
**Impl:** ready
|
|
306
|
+
**Blocked by:** {blocked}
|
|
307
|
+
**Issue:**{issue}
|
|
308
|
+
|
|
309
|
+
## What to build
|
|
310
|
+
略
|
|
311
|
+
"""
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def cmd_selfcheck() -> None:
|
|
315
|
+
with tempfile.TemporaryDirectory() as d:
|
|
316
|
+
issues = Path(d).resolve()
|
|
317
|
+
specs = [(1, "03", ""), (2, "01", " #58"), (3, "none", "")]
|
|
318
|
+
for num, blocked, issue in specs:
|
|
319
|
+
(issues / f"{num:02d}-t{num}.md").write_text(
|
|
320
|
+
TICKET_TMPL.format(label=f"{num:02d}-t{num}", blocked=blocked,
|
|
321
|
+
issue=issue),
|
|
322
|
+
encoding="utf-8",
|
|
323
|
+
)
|
|
324
|
+
tickets = load_tickets(issues)
|
|
325
|
+
|
|
326
|
+
# 03 谁都不挡 → 最先;01 被 03 挡 → 其次;02 被 01 挡 → 最后
|
|
327
|
+
order = [t.num for t in dependency_order(tickets)]
|
|
328
|
+
assert order == [3, 1, 2], order
|
|
329
|
+
|
|
330
|
+
# 回填过的读得出来,没填的是 None
|
|
331
|
+
by_num = {t.num: t for t in tickets}
|
|
332
|
+
assert read_issue_ref(by_num[2].path) == "58"
|
|
333
|
+
assert read_issue_ref(by_num[1].path) is None
|
|
334
|
+
|
|
335
|
+
write_issue_ref(by_num[1].path, "57")
|
|
336
|
+
assert read_issue_ref(by_num[1].path) == "57"
|
|
337
|
+
# 回填不能动别的字段
|
|
338
|
+
again = load_tickets(issues)
|
|
339
|
+
assert {t.num: t.blockers for t in again} == {1: [3], 2: [1], 3: []}
|
|
340
|
+
|
|
341
|
+
# 缺 **Issue:** 字段要报错,不能静默跳过
|
|
342
|
+
(issues / "04-t4.md").write_text(
|
|
343
|
+
"# 04-t4\n\n**Status:** ready-for-agent\n**Impl:** ready\n"
|
|
344
|
+
"**Blocked by:** none\n", encoding="utf-8")
|
|
345
|
+
try:
|
|
346
|
+
write_issue_ref(issues / "04-t4.md", "60")
|
|
347
|
+
except SyncError:
|
|
348
|
+
pass
|
|
349
|
+
else:
|
|
350
|
+
raise AssertionError("缺 **Issue:** 字段本该报错")
|
|
351
|
+
|
|
352
|
+
# 无远程仓库要能和真故障区分开,否则纯本地项目会卡死在 Specify
|
|
353
|
+
assert is_no_remote_error("gh repo view 失败:no git remotes found")
|
|
354
|
+
assert is_no_remote_error("fatal: not a git repository")
|
|
355
|
+
assert not is_no_remote_error("gh issue create 失败:HTTP 403 权限不足")
|
|
356
|
+
assert not is_no_remote_error("找不到 gh 命令")
|
|
357
|
+
|
|
358
|
+
print("selfcheck 通过")
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
COMMANDS = {
|
|
362
|
+
"create": cmd_create,
|
|
363
|
+
"sync-spec": cmd_sync_spec,
|
|
364
|
+
"sync-tickets": cmd_sync_tickets,
|
|
365
|
+
"archive": cmd_archive,
|
|
366
|
+
"selfcheck": cmd_selfcheck,
|
|
367
|
+
}
|
|
368
|
+
# 失败一律返回非零。run_task_hooks(task_utils.py)用 capture_output=True
|
|
369
|
+
# 吞掉两个流,**只在非零退出时**才把 stderr 打出来 —— 早前为了「不阻断建任务」
|
|
370
|
+
# 返回 0,结果是钩子失败彻底无声:远程 Issue 没建、票没同步、归档没关,
|
|
371
|
+
# 全都一声不吭。
|
|
372
|
+
#
|
|
373
|
+
# 而「非零会阻断」这个前提是错的:run_task_hooks 只打印 [WARN],不抛异常,
|
|
374
|
+
# 调用方继续往下走。返回非零既不阻断,又换回全部可观测性。
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def main(argv: list[str]) -> int:
|
|
378
|
+
action = argv[1] if len(argv) > 1 else ""
|
|
379
|
+
if action not in COMMANDS:
|
|
380
|
+
print(f"用法:{Path(argv[0]).name} {{{' | '.join(COMMANDS)}}}", file=sys.stderr)
|
|
381
|
+
return 1
|
|
382
|
+
try:
|
|
383
|
+
COMMANDS[action]()
|
|
384
|
+
return 0
|
|
385
|
+
except (SyncError, TicketError, FileNotFoundError) as e:
|
|
386
|
+
print(f"错误:{e}", file=sys.stderr)
|
|
387
|
+
return 1
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
if __name__ == "__main__":
|
|
391
|
+
sys.exit(main(sys.argv))
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Linear sync hook for ATW task lifecycle.
|
|
3
|
+
|
|
4
|
+
Syncs task events to Linear via the `linearis` CLI.
|
|
5
|
+
|
|
6
|
+
Usage (called automatically by task.py hooks):
|
|
7
|
+
python3 .atw/scripts/hooks/linear_sync.py create
|
|
8
|
+
python3 .atw/scripts/hooks/linear_sync.py start
|
|
9
|
+
python3 .atw/scripts/hooks/linear_sync.py archive
|
|
10
|
+
|
|
11
|
+
Manual usage:
|
|
12
|
+
TASK_JSON_PATH=.atw/tasks/<name>/task.json python3 .atw/scripts/hooks/linear_sync.py sync
|
|
13
|
+
|
|
14
|
+
Environment:
|
|
15
|
+
TASK_JSON_PATH - Absolute path to task.json (set by task.py)
|
|
16
|
+
|
|
17
|
+
Configuration:
|
|
18
|
+
.atw/hooks.local.json - Local config (gitignored), example:
|
|
19
|
+
{
|
|
20
|
+
"linear": {
|
|
21
|
+
"team": "TEAM_KEY",
|
|
22
|
+
"project": "Project Name",
|
|
23
|
+
"assignees": {
|
|
24
|
+
"dev-name": "linear-user-id"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import json
|
|
33
|
+
import os
|
|
34
|
+
import subprocess
|
|
35
|
+
import sys
|
|
36
|
+
from pathlib import Path
|
|
37
|
+
|
|
38
|
+
# ─── Configuration ────────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
# ATW priority → Linear priority (1=Urgent, 2=High, 3=Medium, 4=Low)
|
|
41
|
+
PRIORITY_MAP = {"P0": 1, "P1": 2, "P2": 3, "P3": 4}
|
|
42
|
+
|
|
43
|
+
# Linear status names (must match your team's workflow)
|
|
44
|
+
STATUS_IN_PROGRESS = "In Progress"
|
|
45
|
+
STATUS_DONE = "Done"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _load_config() -> dict:
|
|
49
|
+
"""Load local hook config from .atw/hooks.local.json."""
|
|
50
|
+
task_json_path = os.environ.get("TASK_JSON_PATH", "")
|
|
51
|
+
if task_json_path:
|
|
52
|
+
# Walk up from task.json to find .atw/
|
|
53
|
+
atw_dir = Path(task_json_path).parent.parent.parent
|
|
54
|
+
else:
|
|
55
|
+
atw_dir = Path(".atw")
|
|
56
|
+
|
|
57
|
+
config_path = atw_dir / "hooks.local.json"
|
|
58
|
+
try:
|
|
59
|
+
with open(config_path, encoding="utf-8") as f:
|
|
60
|
+
return json.load(f)
|
|
61
|
+
except (OSError, json.JSONDecodeError):
|
|
62
|
+
return {}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
CONFIG = _load_config()
|
|
66
|
+
LINEAR_CFG = CONFIG.get("linear", {})
|
|
67
|
+
|
|
68
|
+
TEAM = LINEAR_CFG.get("team", "")
|
|
69
|
+
PROJECT = LINEAR_CFG.get("project", "")
|
|
70
|
+
ASSIGNEE_MAP = LINEAR_CFG.get("assignees", {})
|
|
71
|
+
|
|
72
|
+
# ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _read_task() -> tuple[dict, str]:
|
|
76
|
+
path = os.environ.get("TASK_JSON_PATH", "")
|
|
77
|
+
if not path:
|
|
78
|
+
print("TASK_JSON_PATH not set", file=sys.stderr)
|
|
79
|
+
sys.exit(1)
|
|
80
|
+
with open(path, encoding="utf-8") as f:
|
|
81
|
+
return json.load(f), path
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _write_task(data: dict, path: str) -> None:
|
|
85
|
+
with open(path, "w", encoding="utf-8") as f:
|
|
86
|
+
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
87
|
+
f.write("\n")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _linearis(*args: str) -> dict | None:
|
|
91
|
+
result = subprocess.run(
|
|
92
|
+
["linearis", *args],
|
|
93
|
+
capture_output=True,
|
|
94
|
+
text=True,
|
|
95
|
+
encoding="utf-8",
|
|
96
|
+
errors="replace",
|
|
97
|
+
)
|
|
98
|
+
if result.returncode != 0:
|
|
99
|
+
print(f"linearis error: {result.stderr.strip()}", file=sys.stderr)
|
|
100
|
+
sys.exit(1)
|
|
101
|
+
stdout = result.stdout.strip()
|
|
102
|
+
if stdout:
|
|
103
|
+
return json.loads(stdout)
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def _get_linear_issue(task: dict) -> str | None:
|
|
108
|
+
meta = task.get("meta")
|
|
109
|
+
if isinstance(meta, dict):
|
|
110
|
+
return meta.get("linear_issue")
|
|
111
|
+
return None
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
# ─── Actions ──────────────────────────────────────────────────────────────────
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def cmd_create() -> None:
|
|
118
|
+
if not TEAM:
|
|
119
|
+
print("No linear.team configured in hooks.local.json", file=sys.stderr)
|
|
120
|
+
sys.exit(1)
|
|
121
|
+
|
|
122
|
+
task, path = _read_task()
|
|
123
|
+
|
|
124
|
+
# Skip if already linked
|
|
125
|
+
if _get_linear_issue(task):
|
|
126
|
+
print(f"Already linked: {_get_linear_issue(task)}")
|
|
127
|
+
return
|
|
128
|
+
|
|
129
|
+
title = task.get("title") or task.get("name") or "Untitled"
|
|
130
|
+
args = ["issues", "create", title, "--team", TEAM]
|
|
131
|
+
|
|
132
|
+
# Map priority
|
|
133
|
+
priority = PRIORITY_MAP.get(task.get("priority", ""), 0)
|
|
134
|
+
if priority:
|
|
135
|
+
args.extend(["-p", str(priority)])
|
|
136
|
+
|
|
137
|
+
# Set project
|
|
138
|
+
if PROJECT:
|
|
139
|
+
args.extend(["--project", PROJECT])
|
|
140
|
+
|
|
141
|
+
# Assign to Linear user
|
|
142
|
+
assignee = task.get("assignee", "")
|
|
143
|
+
linear_user_id = ASSIGNEE_MAP.get(assignee)
|
|
144
|
+
if linear_user_id:
|
|
145
|
+
args.extend(["--assignee", linear_user_id])
|
|
146
|
+
|
|
147
|
+
# Link to parent's Linear issue if available
|
|
148
|
+
parent_issue = _resolve_parent_linear_issue(task)
|
|
149
|
+
if parent_issue:
|
|
150
|
+
args.extend(["--parent-ticket", parent_issue])
|
|
151
|
+
|
|
152
|
+
result = _linearis(*args)
|
|
153
|
+
if result and "identifier" in result:
|
|
154
|
+
if not isinstance(task.get("meta"), dict):
|
|
155
|
+
task["meta"] = {}
|
|
156
|
+
task["meta"]["linear_issue"] = result["identifier"]
|
|
157
|
+
_write_task(task, path)
|
|
158
|
+
print(f"Created Linear issue: {result['identifier']}")
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def cmd_start() -> None:
|
|
162
|
+
task, _ = _read_task()
|
|
163
|
+
issue = _get_linear_issue(task)
|
|
164
|
+
if not issue:
|
|
165
|
+
return
|
|
166
|
+
_linearis("issues", "update", issue, "-s", STATUS_IN_PROGRESS)
|
|
167
|
+
print(f"Updated {issue} -> {STATUS_IN_PROGRESS}")
|
|
168
|
+
cmd_sync()
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def cmd_archive() -> None:
|
|
172
|
+
task, _ = _read_task()
|
|
173
|
+
issue = _get_linear_issue(task)
|
|
174
|
+
if not issue:
|
|
175
|
+
return
|
|
176
|
+
_linearis("issues", "update", issue, "-s", STATUS_DONE)
|
|
177
|
+
print(f"Updated {issue} -> {STATUS_DONE}")
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def cmd_sync() -> None:
|
|
181
|
+
"""Sync prd.md content to Linear issue description."""
|
|
182
|
+
task, _ = _read_task()
|
|
183
|
+
issue = _get_linear_issue(task)
|
|
184
|
+
if not issue:
|
|
185
|
+
print("No linear_issue in meta, run create first", file=sys.stderr)
|
|
186
|
+
sys.exit(1)
|
|
187
|
+
|
|
188
|
+
# Find prd.md next to task.json
|
|
189
|
+
task_json_path = os.environ.get("TASK_JSON_PATH", "")
|
|
190
|
+
prd_path = Path(task_json_path).parent / "prd.md"
|
|
191
|
+
if not prd_path.is_file():
|
|
192
|
+
print(f"No prd.md found at {prd_path}", file=sys.stderr)
|
|
193
|
+
sys.exit(1)
|
|
194
|
+
|
|
195
|
+
description = prd_path.read_text(encoding="utf-8").strip()
|
|
196
|
+
_linearis("issues", "update", issue, "-d", description)
|
|
197
|
+
print(f"Synced prd.md to {issue} description")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# ─── Parent Issue Resolution ─────────────────────────────────────────────────
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _resolve_parent_linear_issue(task: dict) -> str | None:
|
|
204
|
+
"""Find parent task's Linear issue identifier."""
|
|
205
|
+
parent_name = task.get("parent")
|
|
206
|
+
if not parent_name:
|
|
207
|
+
return None
|
|
208
|
+
|
|
209
|
+
task_json_path = os.environ.get("TASK_JSON_PATH", "")
|
|
210
|
+
if not task_json_path:
|
|
211
|
+
return None
|
|
212
|
+
|
|
213
|
+
current_task_dir = Path(task_json_path).parent
|
|
214
|
+
tasks_dir = current_task_dir.parent
|
|
215
|
+
parent_json = tasks_dir / parent_name / "task.json"
|
|
216
|
+
|
|
217
|
+
if parent_json.exists():
|
|
218
|
+
try:
|
|
219
|
+
with open(parent_json, encoding="utf-8") as f:
|
|
220
|
+
parent_task = json.load(f)
|
|
221
|
+
return _get_linear_issue(parent_task)
|
|
222
|
+
except (json.JSONDecodeError, OSError):
|
|
223
|
+
pass
|
|
224
|
+
return None
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
# ─── Main ─────────────────────────────────────────────────────────────────────
|
|
228
|
+
|
|
229
|
+
if __name__ == "__main__":
|
|
230
|
+
action = sys.argv[1] if len(sys.argv) > 1 else ""
|
|
231
|
+
actions = {
|
|
232
|
+
"create": cmd_create,
|
|
233
|
+
"start": cmd_start,
|
|
234
|
+
"archive": cmd_archive,
|
|
235
|
+
"sync": cmd_sync,
|
|
236
|
+
}
|
|
237
|
+
fn = actions.get(action)
|
|
238
|
+
if fn:
|
|
239
|
+
fn()
|
|
240
|
+
else:
|
|
241
|
+
print(f"Unknown action: {action}", file=sys.stderr)
|
|
242
|
+
print(f"Valid actions: {', '.join(actions)}", file=sys.stderr)
|
|
243
|
+
sys.exit(1)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Initialize developer for workflow.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
python3 init_developer.py <developer-name>
|
|
7
|
+
|
|
8
|
+
This creates:
|
|
9
|
+
- .atw/.developer file with developer info
|
|
10
|
+
- .atw/workspace/<name>/ directory structure
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import sys
|
|
16
|
+
|
|
17
|
+
from common.paths import (
|
|
18
|
+
DIR_WORKFLOW,
|
|
19
|
+
FILE_DEVELOPER,
|
|
20
|
+
get_developer,
|
|
21
|
+
)
|
|
22
|
+
from common.developer import init_developer
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def main() -> None:
|
|
26
|
+
"""CLI entry point."""
|
|
27
|
+
if len(sys.argv) < 2:
|
|
28
|
+
print(f"Usage: {sys.argv[0]} <developer-name>")
|
|
29
|
+
print()
|
|
30
|
+
print("Example:")
|
|
31
|
+
print(f" {sys.argv[0]} john")
|
|
32
|
+
sys.exit(1)
|
|
33
|
+
|
|
34
|
+
name = sys.argv[1]
|
|
35
|
+
|
|
36
|
+
# Check if already initialized
|
|
37
|
+
existing = get_developer()
|
|
38
|
+
if existing:
|
|
39
|
+
print(f"Developer already initialized: {existing}")
|
|
40
|
+
print()
|
|
41
|
+
print(f"To reinitialize, remove {DIR_WORKFLOW}/{FILE_DEVELOPER} first")
|
|
42
|
+
sys.exit(0)
|
|
43
|
+
|
|
44
|
+
if init_developer(name):
|
|
45
|
+
sys.exit(0)
|
|
46
|
+
else:
|
|
47
|
+
sys.exit(1)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
main()
|