forked from deftai/directive
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTaskfile.yml
More file actions
564 lines (536 loc) · 24.3 KB
/
Taskfile.yml
File metadata and controls
564 lines (536 loc) · 24.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
version: '3'
vars:
PROJECT_NAME: deft
# VERSION is resolved dynamically (#723) so `task build` produces
# `dist/deft-{version}.{zip,tar.gz}` matching the in-flight release.
# Resolution priority (mirrors scripts/resolve_version.py):
# 1. $DEFT_RELEASE_VERSION env var (set by scripts/release.py:run_build
# so `task release -- 0.21.0` builds dist/deft-0.21.0.zip).
# 2. `git describe --tags --abbrev=0` stripped of leading `v`.
# 3. `0.0.0-dev` fallback for fresh checkouts with no tags.
# The previous hard-coded literal (`VERSION: 0.20.0`) was the root cause
# of #723: every release after v0.20.0 produced a stale artifact name
# because nothing in the release pipeline updated the Taskfile literal.
# Inline POSIX sh (run by go-task's embedded mvdan/sh interpreter so the
# block is cross-platform on Windows / macOS / Linux without requiring
# uv/python at parse time -- the Python equivalent lives in
# scripts/resolve_version.py for Python callers + regression tests).
VERSION:
sh: |
if [ -n "$DEFT_RELEASE_VERSION" ]; then
printf '%s' "$DEFT_RELEASE_VERSION"
elif tag=$(git describe --tags --abbrev=0 2>/dev/null); then
printf '%s' "${tag#v}"
else
printf '0.0.0-dev'
fi
# Each included sub-taskfile (tasks/*.yml) defines its own DEFT_ROOT as
# `{{joinPath .TASKFILE_DIR ".."}}` so scripts can be dispatched via
# `{{.DEFT_ROOT}}/scripts/...` on every platform (#566). `joinPath` is
# evaluated eagerly by go-task's templating and uses Go's `filepath.Clean`,
# which yields a native-separator, `..`-free absolute path that
# `uv run python` can open on Windows. The previous
# `{{.TASKFILE_DIR}}/../scripts/...` shape mixed native separators with
# forward-slash traversal and normalized incorrectly under Windows Python,
# dropping the deft/ prefix.
#
# DEFT_ROOT is intentionally NOT defined here at the root Taskfile level
# because go-task re-evaluates var templates at use site in included
# subfiles -- a root-level `DEFT_ROOT: '{{.TASKFILE_DIR}}'` would expand
# to the subfile's own directory (tasks/) when referenced from a subfile,
# not to the deft/ root.
# Top-level env propagates into included taskfiles (Task v3 includes inherit
# the parent env:). PYTHONUTF8=1 ensures Python scripts invoked from any
# deft task have UTF-8 stdout/stderr on Windows (cp1252 default would crash
# on the ✓/→/✗/⚠ symbols emitted by spec_validate / roadmap_render / etc.).
# Every task that runs Python ALSO sets this in its own env: block as a
# belt-and-suspenders guard -- see #540 for the full audit.
#
# UV_PROJECT is the Layer-1 safety net for #1011: every framework-side
# `uv run` invocation must resolve against the framework's own pyproject.toml,
# not an ancestor pyproject.toml that happens to live above the install
# location on the consumer machine. Without this, `uv run` walks upward
# from cwd looking for the nearest pyproject.toml and binds to whatever
# it finds first -- on a typical dev box with a parent workspace
# pyproject.toml, that workspace's build backend (e.g. unresolvable
# `setuptools.backends._legacy:_Backend`) crashes during environment
# resolution before any framework task body runs. UV_PROJECT short-circuits
# the upward walk by pinning the project root explicitly. {{.TASKFILE_DIR}}
# at this top-level env: resolves to the directory containing this
# Taskfile.yml (the framework root), which is exactly the right pin for
# the framework's own pyproject.toml. CLI `--project` on each call site
# (Layer 2, see tasks/*.yml) overrides env, which overrides walk -- the
# CLI flag is the contract; UV_PROJECT is defense-in-depth for any task
# that drops the flag in a future edit. See #1011 for the full root-cause
# analysis and the two-layer rationale.
env:
PYTHONUTF8: "1"
UV_PROJECT: '{{.TASKFILE_DIR}}'
includes:
core:
taskfile: ./tasks/core.yml
optional: true
spec:
taskfile: ./tasks/spec.yml
optional: true
install:
taskfile: ./tasks/install.yml
optional: true
deployments:
taskfile: ./tasks/deployments.yml
optional: true
toolchain:
taskfile: ./tasks/toolchain.yml
optional: true
verify:
taskfile: ./tasks/verify.yml
optional: true
change:
taskfile: ./tasks/change.yml
optional: true
commit:
taskfile: ./tasks/commit.yml
optional: true
scope:
taskfile: ./tasks/scope.yml
optional: true
roadmap:
taskfile: ./tasks/roadmap.yml
optional: true
project:
taskfile: ./tasks/project.yml
optional: true
migrate:
taskfile: ./tasks/migrate.yml
optional: true
vbrief:
taskfile: ./tasks/vbrief.yml
optional: true
prd:
taskfile: ./tasks/prd.yml
optional: true
reconcile:
taskfile: ./tasks/reconcile.yml
optional: true
issue:
taskfile: ./tasks/issue.yml
optional: true
pr:
taskfile: ./tasks/pr.yml
optional: true
ci:
taskfile: ./tasks/ci.yml
optional: true
policy:
taskfile: ./tasks/policy.yml
optional: true
framework:
taskfile: ./tasks/framework.yml
optional: true
# #883 Story 1 stub include. The fragment exposes its inner tasks
# (`issue:list` / `issue:view` / `issue:close` / `issue:edit`) under the
# `scm` namespace key, producing the canonical `scm:issue:*` surface in
# `task -l` with no doubled prefix. Forward-compat marker block lives at
# the top of `tasks/scm.yml`; the full scm:* namespace lives at #881 and
# replaces this stub wholesale when it lands.
scm:
taskfile: ./tasks/scm.yml
optional: true
# #883 Story 2 cache + quarantine layer. Five-command surface
# (cache:put / cache:get / cache:invalidate / cache:fetch-all /
# cache:prune) under the canonical `cache:` namespace via the include
# key. Forward-compat: future v2 cache surfaces (cache:check /
# cache:refresh / cache:doctor / cache:stats / quarantine:scan) are
# deferred per the epic deferred_to_v2 list and land here when v2
# ships.
cache:
taskfile: ./tasks/cache.yml
optional: true
# Triage v1 fragment includes (#845 epic, #883 Story 3 rebind onto cache:*).
#
# Three standalone fragments authored by stories A3, A4, and A6
# respectively (the legacy A1 `triage-cache` fragment was deleted in
# #883 Story 3 -- the unified `cache:*` surface above is the
# single content-mirroring layer). Each fragment is `optional: true`
# so the parent Taskfile parses cleanly even when a sibling fragment
# has not yet landed.
#
# Namespacing: go-task v3 prefixes inner task names with the include
# key. Two includes cannot share a single namespace key, so the
# fragments use unique keys derived from the file basename. The
# user-facing `task triage:bootstrap` / `task triage:accept` /
# `task triage:bulk-*` etc. forms are exposed via top-level alias
# tasks below.
triage-actions:
taskfile: ./tasks/triage-actions.yml
optional: true
triage-bulk:
taskfile: ./tasks/triage-bulk.yml
optional: true
triage-bootstrap:
taskfile: ./tasks/triage-bootstrap.yml
optional: true
# Windows maintainer onboarding fragment (#902). Exposes the inner task
# `toolchain` as `task setup:toolchain`. Note: the root-level `setup` task
# below (git-hooks bootstrap) coexists with `setup:toolchain` because
# go-task treats them as distinct task names.
setup:
taskfile: ./tasks/setup.yml
optional: true
# CHANGELOG.md union-merge helper (#911). Exposes
# `task changelog:resolve-unreleased` -- the canonical swarm-cascade Phase 6
# Step 1 surface that replaces the older HEAD-take-and-discard pattern that
# silently dropped rebasing-branch CHANGELOG entries on every cascade rebase.
# See skills/deft-directive-swarm/SKILL.md Phase 6 Step 1 for the manual-
# fallback contract; the include is `optional: true` so the parent Taskfile
# parses cleanly when the fragment is absent (rolling-merge tolerance).
changelog:
taskfile: ./tasks/changelog.yml
optional: true
# Wipe-and-reinstall relocator (#992 PR2). Exposes `task relocate` --
# forwards user-facing flags (`--confirm` / `--dry-run` / `--force` /
# `--rollback` / `--no-snapshot` / `--json` / `--quiet`) via
# {{.CLI_ARGS}}; per `conventions/task-caching.md` no `sources:` /
# `generates:` so the recovery flags reach the script (#574). The
# include is `optional: true` for rolling-merge tolerance.
relocate:
taskfile: ./tasks/relocate.yml
optional: true
tasks:
default:
desc: List all available tasks
cmds:
- task --list
silent: true
# Backward-compatible aliases -- project convention is `task check`, `task test`, etc.
check:
desc: "Run all pre-commit checks (skips @pytest.mark.slow tests via pyproject addopts -- run `task check:slow` for the slow lane, #975)"
deps:
- core:validate
- core:lint
- core:test
- toolchain:check
- verify:stubs
- verify:links
- verify:rule-ownership
- verify:branch
- verify:encoding
- verify:destructive-gh-verbs
- vbrief:validate
cmds:
- echo "All checks passed"
# `task check:slow` runs the @pytest.mark.slow lane that the default
# `task check` skips (#975). The slow lane is dominated by the
# triage_bootstrap watchdog regression suite (5 of the 6 marked tests),
# which burns ~5.85s on real time.sleep / thread joins -- the proper
# monkeypatch refactor is tracked as a follow-up to #975. The `-o
# addopts=` reset overrides the pyproject default of `-m 'not slow'`
# so the `-m slow` selector here actually picks up the marked tests.
check:slow:
desc: "Run the @pytest.mark.slow test lane (watchdog regression suite excluded from `task check` by default, #975)"
cmds:
# `--project` pins uv to the framework root so ancestor pyproject.toml
# files cannot hijack the resolver via uv's upward walk (#1011).
- uv --project "{{.TASKFILE_DIR}}" run pytest tests/ -o addopts= -m slow
test:
desc: Run test suite (alias for core:test)
cmds:
- task: core:test
test:coverage:
desc: Run tests with coverage (alias for core:test:coverage)
cmds:
- task: core:test:coverage
lint:
desc: Lint and type-check Python code (alias for core:lint)
cmds:
- task: core:lint
fmt:
desc: Format Python code (alias for core:fmt)
cmds:
- task: core:fmt
build:
desc: Package framework for distribution (alias for core:build)
cmds:
- task: core:build
clean:
desc: Clean generated artifacts (alias for core:clean)
cmds:
- task: core:clean
validate:
desc: Validate all markdown files (alias for core:validate)
cmds:
- task: core:validate
install:
desc: Install deft (alias for install:install)
cmds:
- task: install:install
uninstall:
desc: Remove deft entry from AGENTS.md (alias for install:uninstall)
cmds:
- task: install:uninstall
# User-facing upgrade entrypoint (#1061). Aliases the install:upgrade
# wrapper that delegates to `run upgrade`. Cited by the doctor's
# failure prose and docs/install-manifest.md as the canonical
# post-drift repair entrypoint for the AGENTS.md / manifest /
# .deft-version triple.
upgrade:
desc: "Upgrade deft framework -- refresh AGENTS.md + write install manifest + regenerate .deft-version (alias for install:upgrade, #1061)"
cmds:
- task: install:upgrade
stats:
desc: Show framework statistics (alias for core:stats)
cmds:
- task: core:stats
setup:
desc: "Idempotent local-dev setup: configure git hooks (#747); detect-and-prompt ghx (#884). Sets core.hooksPath=.githooks so .githooks/pre-commit + .githooks/pre-push run."
dir: '{{.USER_WORKING_DIR}}'
env:
PYTHONUTF8: "1"
cmds:
# Inline POSIX-sh under go-task's mvdan/sh interpreter -- cross-platform.
# `git config core.hooksPath .githooks` is itself idempotent, but we
# detect the no-op so the task prints a friendly message rather than
# silently re-asserting on every invocation.
- |
configured=$(git config --get core.hooksPath || true)
if [ "$configured" = ".githooks" ]; then
echo "✓ core.hooksPath already set to .githooks (no change)."
else
git config core.hooksPath .githooks
echo "✓ core.hooksPath set to .githooks (#747 branch gate active)."
fi
# #814: Detect a Python interpreter whose stdout defaults to a
# non-UTF-8 Windows code page (cp1252 / cp437). Informational only --
# the deft hook scripts themselves self-reconfigure to UTF-8 at
# main() entry, so this warning surfaces a fact about the user's
# environment, not a defect that blocks setup. We do NOT auto-set
# PYTHONIOENCODING because mutating the user's environment would
# surprise other tooling (out-of-scope per the issue body).
- |
python_bin="${DEFT_PYTHON:-}"
if [ -z "$python_bin" ]; then
if command -v python3 >/dev/null 2>&1; then
python_bin=python3
elif command -v python >/dev/null 2>&1; then
python_bin=python
fi
fi
if [ -n "$python_bin" ]; then
# NOTE: we explicitly unset PYTHONUTF8 / PYTHONIOENCODING in the
# subshell so the probe measures what Python would do under git's
# hook environment (which inherits the user's shell, NOT the
# Taskfile root env: block). Without the unset, the root-level
# `env: PYTHONUTF8: "1"` (#540) masks cp1252 here and the warning
# would never surface even when the user actually has the bug.
enc=$(unset PYTHONUTF8 PYTHONIOENCODING; "$python_bin" -c "import sys; print((sys.stdout.encoding or '').lower())" 2>/dev/null || true)
case "$enc" in
cp1252|cp437|charmap)
echo ""
echo "WARN: Detected Python stdout encoding '$enc' (Windows default). Deft hooks"
echo "print non-ASCII glyphs and may crash without UTF-8 stdout. Either:"
echo " (a) set the user-environment variable PYTHONIOENCODING=utf-8 (one-time,"
echo " via System Properties > Environment Variables), OR"
echo " (b) add \$env:PYTHONIOENCODING='utf-8' to your PowerShell profile."
echo "The deft hook scripts also self-reconfigure as of #814, so this"
echo "warning is informational on current versions."
;;
esac
fi
# #884: ghx adoption -- consent-gated install of the brunoborges/ghx
# GitHub CLI cache proxy. Default invocation here passes --check so
# `task setup` never prompts on a clean re-run; operators wanting to
# opt in run `task setup:ghx` (defined below) which is the
# interactive entry point. The script is pure-stdlib so it works
# before `uv sync` has run on a fresh worktree; `uv run` is still
# the canonical dispatcher to keep the python interpreter consistent
# with every other Taskfile-dispatched script. `--project` pins uv
# to the framework root so ancestor pyproject.toml files cannot
# hijack the resolver via uv's upward walk (#1011).
- uv --project "{{.TASKFILE_DIR}}" run python "{{.TASKFILE_DIR}}/scripts/setup_ghx.py" --check
setup:ghx:
desc: "Consent-gated ghx (brunoborges/ghx) installer (#884) -- task setup:ghx [-- --yes]"
dir: '{{.USER_WORKING_DIR}}'
env:
PYTHONUTF8: "1"
# Per `conventions/task-caching.md` (#574): no `sources:` / `generates:`
# because the script forwards user-facing flags via {{.CLI_ARGS}}
# (notably --yes for non-interactive CI / scripted approval).
cmds:
- uv --project "{{.TASKFILE_DIR}}" run python "{{.TASKFILE_DIR}}/scripts/setup_ghx.py" {{.CLI_ARGS}}
# Release pipeline tasks (#74 + #716 safety hardening, namespace flatten #718).
#
# Defined inline at the root Taskfile rather than via `includes: release: ./tasks/release.yml`
# because go-task concatenates the namespace key with each inner task name -- so an inner
# task named `release:` under namespace `release:` would install as `task release:release`,
# not `task release` (the documented invocation in skills/deft-directive-release/SKILL.md
# and CHANGELOG entries from #74/#716). See #718 for the full root-cause analysis.
#
# Sibling pattern: tasks/pr.yml uses inner task name `check-protected-issues` (no `pr:`
# repeat) so the include-namespace mechanism produces `pr:check-protected-issues`. The
# release pipeline cannot use that pattern because it needs BOTH a top-level `release`
# name AND `release:e2e` / `release:publish` / `release:rollback` sub-names.
#
# Per `conventions/task-caching.md` (#574): tasks that accept user-facing recovery flags
# via {{.CLI_ARGS}} (here: --dry-run / --skip-tag / --skip-release / --allow-dirty /
# --repo / --no-draft / --allow-low-downloads / --allow-data-loss / --force-strict-0 /
# --owner / --keep-repo) MUST NOT declare `sources:` / `generates:` -- the cached `cmds:`
# skip would silently discard the recovery flag.
#
# Path resolution uses `{{.TASKFILE_DIR}}/scripts/<script>.py` directly because these
# tasks live in the root Taskfile.yml where `{{.TASKFILE_DIR}}` already resolves to the
# deft/ root (no per-subfile DEFT_ROOT joinPath dance is needed -- see Taskfile.yml
# header comment for why `DEFT_ROOT` is intentionally absent at the root level).
#
# Companion scripts: scripts/release.py, scripts/release_publish.py,
# scripts/release_rollback.py, scripts/release_e2e.py
# Companion tests: tests/cli/test_release.py,
# tests/cli/test_release_publish.py,
# tests/cli/test_release_rollback.py,
# tests/cli/test_release_e2e.py
# Refs #74, #233, #642, #635, #709, #710, #716, #718.
release:
desc: "Automate the v0.X.Y release flow (#74) -- task release -- <version> [--dry-run] [--skip-tag] [--skip-release] [--no-draft]"
dir: '{{.USER_WORKING_DIR}}'
env:
PYTHONUTF8: "1"
cmds:
# `--project` pins uv to the framework root so ancestor pyproject.toml
# files cannot hijack the resolver via uv's upward walk (#1011).
- uv --project "{{.TASKFILE_DIR}}" run python "{{.TASKFILE_DIR}}/scripts/release.py" {{.CLI_ARGS}}
release:publish:
desc: "Flip a draft GitHub release to public (#716) -- task release:publish -- <version> [--dry-run] [--repo OWNER/REPO]"
dir: '{{.USER_WORKING_DIR}}'
env:
PYTHONUTF8: "1"
cmds:
- uv --project "{{.TASKFILE_DIR}}" run python "{{.TASKFILE_DIR}}/scripts/release_publish.py" {{.CLI_ARGS}}
release:rollback:
desc: "State-aware release unwind (#716) -- task release:rollback -- <version> [--dry-run] [--allow-low-downloads N] [--allow-data-loss] [--force-strict-0]"
dir: '{{.USER_WORKING_DIR}}'
env:
PYTHONUTF8: "1"
cmds:
- uv --project "{{.TASKFILE_DIR}}" run python "{{.TASKFILE_DIR}}/scripts/release_rollback.py" {{.CLI_ARGS}}
release:e2e:
desc: "End-to-end release rehearsal against an auto-created+destroyed temp repo (#716) -- task release:e2e [-- --dry-run] [--owner OWNER] [--keep-repo]"
dir: '{{.USER_WORKING_DIR}}'
env:
PYTHONUTF8: "1"
cmds:
- uv --project "{{.TASKFILE_DIR}}" run python "{{.TASKFILE_DIR}}/scripts/release_e2e.py" {{.CLI_ARGS}}
# ------------------------------------------------------------------
# Triage v1 user-facing alias tasks (#845, #913).
#
# The four triage fragments are namespaced under their unique include
# keys (`triage-cache`, `triage-actions`, `triage-bulk`,
# `triage-bootstrap`) -- a single shared `triage:` include namespace
# is not supported by go-task v3 (two includes cannot share a key).
# The aliases below provide the documented `task triage:<verb>`
# user-facing surface that vBRIEFs / UPGRADING.md / scripts/triage_*.py
# describe. Each alias delegates to the underlying namespaced task
# and forwards `{{.CLI_ARGS}}` so flags (`--repo`, `--reason`, etc.)
# reach the script. The inner tasks in each fragment are
# `internal: true` so the fragment-namespace forms
# (`triage-cache:cache`, `triage-actions:accept`, `triage-bulk:bulk-defer`,
# `triage-bootstrap:bootstrap`) drop out of `task -l`; only the
# documented `triage:*` aliases below appear in the listing. The
# internal tasks remain CALLABLE for legacy invocations (e.g. recap
# text in `scripts/triage_bootstrap.py` still prints the namespaced
# forms, which continue to dispatch correctly via the fragment
# include).
#
# Aliases are inline at the root Taskfile rather than in a separate
# fragment because they cross include namespaces and must exist
# regardless of which fragments are present.
#
# Mirrors the established #718 release-pipeline flatten precedent
# (release: tasks defined inline at the root Taskfile so go-task
# does not double-prefix them).
# ------------------------------------------------------------------
# task triage:cache and task triage:show were removed in #883 Story 3.
# The unified cache:* surface (cache:fetch-all, cache:get) is the
# canonical replacement; see UPGRADING.md for migration text.
triage:accept:
desc: "Accept an issue for triage. Records an audit entry. (#845 Story 3)"
cmds:
- task: triage-actions:accept
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:reject:
desc: "Reject an issue. Closes upstream via gh + applies triage-rejected label; rolls audit back on gh failure. (#845 Story 3)"
cmds:
- task: triage-actions:reject
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:defer:
desc: "Defer an issue. Records an audit entry. (#845 Story 3)"
cmds:
- task: triage-actions:defer
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:needs-ac:
desc: "Mark an issue as needing acceptance criteria + post AC-request comment upstream. (#845 Story 3)"
cmds:
- task: triage-actions:needs-ac
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:mark-duplicate:
desc: "Link an issue as a duplicate of another (validated against Story 1 cache). (#845 Story 3)"
cmds:
- task: triage-actions:mark-duplicate
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:status:
desc: "Print the latest triage decision for an issue. Read-only. (#845 Story 3)"
cmds:
- task: triage-actions:status
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:reset:
desc: "Reset an issue's triage state. Appends a reset audit entry referencing prior; does NOT delete history. (#845 Story 3)"
cmds:
- task: triage-actions:reset
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:history:
desc: "Print the full triage timeline for an issue, ordered by timestamp. Read-only. (#845 Story 3)"
cmds:
- task: triage-actions:history
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:bulk-accept:
desc: "Bulk accept cached candidates -- task triage:bulk-accept -- --repo OWNER/NAME [--label L] [--author A] [--age-days N] [--cluster C] [--re-action] (#845 Story 4 / #915)"
cmds:
- task: triage-bulk:bulk-accept
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:bulk-reject:
desc: "Bulk reject cached candidates -- task triage:bulk-reject -- --repo OWNER/NAME --reason 'why' [--label L] [--author A] [--age-days N] [--cluster C] [--re-action] (#845 Story 4 / #915)"
cmds:
- task: triage-bulk:bulk-reject
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:bulk-defer:
desc: "Bulk defer cached candidates -- task triage:bulk-defer -- --repo OWNER/NAME [--label L] [--author A] [--age-days N] [--cluster C] [--re-action] (#845 Story 4 / #915)"
cmds:
- task: triage-bulk:bulk-defer
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:bulk-needs-ac:
desc: "Bulk needs-ac cached candidates -- task triage:bulk-needs-ac -- --repo OWNER/NAME [--label L] [--author A] [--age-days N] [--cluster C] [--re-action] (#845 Story 4 / #915)"
cmds:
- task: triage-bulk:bulk-needs-ac
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:refresh-active:
desc: "Pre-swarm freshness gate (#845 Story 4) -- detects drift between cached and live `gh issue view` for every issue referenced in vbrief/active/*.vbrief.json"
cmds:
- task: triage-bulk:refresh-active
vars:
CLI_ARGS: "{{.CLI_ARGS}}"
triage:bootstrap:
desc: "Run the triage v1 idempotent installer (#845 Story 6)."
cmds:
- task: triage-bootstrap:bootstrap
vars:
CLI_ARGS: "{{.CLI_ARGS}}"