Skip to content

Commit 15ebf4e

Browse files
feat: remove v2 from sprint-list-epics.sh (d775-4a36) (merge worktree-20260324-142611)
2 parents dde0f42 + 2c8c17d commit 15ebf4e

16 files changed

+1228
-815
lines changed

.test-index

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ plugins/dso/scripts/classify-task.py:tests/scripts/test-classify-task.sh
2929
plugins/dso/scripts/collect-discoveries.sh:tests/scripts/test-collect-discoveries-plugin-root.sh
3030
plugins/dso/scripts/ensure-pre-commit.sh:tests/scripts/test-ensure-precommit-config-paths.sh
3131
plugins/dso/scripts/check-acceptance-criteria.sh:tests/scripts/test_issue_quality_check_file_impact.py
32-
plugins/dso/scripts/enrich-file-impact.sh:tests/scripts/test_issue_quality_check_file_impact.py
32+
plugins/dso/scripts/enrich-file-impact.sh:tests/scripts/test_issue_quality_check_file_impact.py,tests/scripts/test-enrich-file-impact-v2-removal.sh [test_enrich_file_impact_no_TK_variable]
3333
plugins/dso/scripts/issue-quality-check.sh:tests/scripts/test_issue_quality_check_file_impact.py
3434
plugins/dso/scripts/merge-ticket-index.py:tests/scripts/test-merge-ticket-index.sh
3535
plugins/dso/scripts/pre-commit-format-fix.sh:tests/scripts/test-precommit-format-fix-config-paths.sh
@@ -44,7 +44,8 @@ plugins/dso/scripts/ticket-link.sh:tests/scripts/test-ticket-link.sh [test_link_
4444
plugins/dso/scripts/ticket-transition.sh:tests/scripts/test-ticket-transition.sh [test_transition_bug_close_requires_reason]
4545
plugins/dso/scripts/runners/bash-runner.sh:tests/scripts/test-test-batched.sh
4646
plugins/dso/scripts/capture-review-diff.sh:tests/hooks/test-merge-aware-diff.sh
47-
plugins/dso/scripts/validate-phase.sh:tests/test-validate-phase-portability.sh
47+
plugins/dso/scripts/agent-batch-lifecycle.sh:tests/scripts/test-validate-phase-v2-removal.sh [test_validate_phase_no_TK_variable]
48+
plugins/dso/scripts/validate-phase.sh:tests/test-validate-phase-portability.sh,tests/scripts/test-validate-phase-v2-removal.sh [test_validate_phase_no_TK_variable]
4849
plugins/dso/scripts/validate.sh:tests/plugin/test-validate-work-portability.sh,tests/hooks/test-validate-review-output.sh,tests/hooks/test-validate-crash-detection.sh,tests/scripts/test-validate-test-batched-integration.sh,tests/scripts/test-validate-flock-timeout.sh,tests/scripts/test-validate-background.sh,tests/scripts/test-validate-skip-ci-flag.sh,tests/scripts/test-validate-issues.sh,tests/scripts/test-validate-config.sh,tests/scripts/test-validate-script-writes-integration.sh,tests/scripts/test-validate-config-driven.sh,tests/scripts/test-validate-state-lifecycle.sh,tests/test-validate-phase-portability.sh
4950
plugins/dso/scripts/worktree-cleanup.sh:tests/scripts/test_worktree_cleanup_startup_config.py
5051
plugins/dso/skills/batch-overlap-check/SKILL.md:plugins/dso/tests/test-sprint-skill-step10-no-merge-to-main.sh,tests/plugin/test-audit-skill-resolution.sh,tests/hooks/test-fix-bug-skill.sh,tests/hooks/test-generate-claude-md-skill.sh,tests/hooks/test-init-skill.sh,tests/scripts/test-qualify-skill-refs.sh,tests/scripts/test-skill-path-refs.sh,tests/scripts/test-check-skill-refs.sh,tests/skills/test_end_skill_final_verification_step.py,tests/skills/test_implementation_plan_skill_tdd_enforcement.py,tests/skills/test-quick-ref-skill.sh,tests/skills/test_project_setup_skill_conditional_prompts.py,tests/skills/test_fix_bug_skill.py,tests/skills/test_end_skill_summary_displays_stored_learnings.py,tests/skills/test_end_skill_learnings_step_before_commit.py,tests/skills/test-design-skills-cross-stack.sh,tests/skills/test_end_skill_dirty_worktree_resolution.py,tests/skills/test_fix_bug_skill_escalated_section.py,tests/skills/test_end_skill_bug_tickets_before_commit.py
@@ -64,6 +65,7 @@ plugins/dso/skills/design-wireframe/SKILL.md:plugins/dso/tests/test-sprint-skill
6465
plugins/dso/skills/dev-onboarding/SKILL.md:plugins/dso/tests/test-sprint-skill-step10-no-merge-to-main.sh,tests/plugin/test-audit-skill-resolution.sh,tests/hooks/test-fix-bug-skill.sh,tests/hooks/test-generate-claude-md-skill.sh,tests/hooks/test-init-skill.sh,tests/scripts/test-qualify-skill-refs.sh,tests/scripts/test-skill-path-refs.sh,tests/scripts/test-check-skill-refs.sh,tests/skills/test_end_skill_final_verification_step.py,tests/skills/test_implementation_plan_skill_tdd_enforcement.py,tests/skills/test-quick-ref-skill.sh,tests/skills/test_project_setup_skill_conditional_prompts.py,tests/skills/test_fix_bug_skill.py,tests/skills/test_end_skill_summary_displays_stored_learnings.py,tests/skills/test_end_skill_learnings_step_before_commit.py,tests/skills/test-design-skills-cross-stack.sh,tests/skills/test_end_skill_dirty_worktree_resolution.py,tests/skills/test_fix_bug_skill_escalated_section.py,tests/skills/test_end_skill_bug_tickets_before_commit.py,tests/hooks/test-sub-agent-guard.sh
6566
plugins/dso/skills/dryrun/SKILL.md:plugins/dso/tests/test-sprint-skill-step10-no-merge-to-main.sh,tests/plugin/test-audit-skill-resolution.sh,tests/hooks/test-fix-bug-skill.sh,tests/hooks/test-generate-claude-md-skill.sh,tests/hooks/test-init-skill.sh,tests/scripts/test-qualify-skill-refs.sh,tests/scripts/test-skill-path-refs.sh,tests/scripts/test-check-skill-refs.sh,tests/skills/test_end_skill_final_verification_step.py,tests/skills/test_implementation_plan_skill_tdd_enforcement.py,tests/skills/test-quick-ref-skill.sh,tests/skills/test_project_setup_skill_conditional_prompts.py,tests/skills/test_fix_bug_skill.py,tests/skills/test_end_skill_summary_displays_stored_learnings.py,tests/skills/test_end_skill_learnings_step_before_commit.py,tests/skills/test-design-skills-cross-stack.sh,tests/skills/test_end_skill_dirty_worktree_resolution.py,tests/skills/test_fix_bug_skill_escalated_section.py,tests/skills/test_end_skill_bug_tickets_before_commit.py
6667
plugins/dso/skills/end-session/SKILL.md:plugins/dso/tests/test-sprint-skill-step10-no-merge-to-main.sh,tests/plugin/test-audit-skill-resolution.sh,tests/hooks/test-fix-bug-skill.sh,tests/hooks/test-generate-claude-md-skill.sh,tests/hooks/test-init-skill.sh,tests/scripts/test-qualify-skill-refs.sh,tests/scripts/test-skill-path-refs.sh,tests/scripts/test-check-skill-refs.sh,tests/skills/test_end_skill_final_verification_step.py,tests/skills/test_implementation_plan_skill_tdd_enforcement.py,tests/skills/test-quick-ref-skill.sh,tests/skills/test_project_setup_skill_conditional_prompts.py,tests/skills/test_fix_bug_skill.py,tests/skills/test_end_skill_summary_displays_stored_learnings.py,tests/skills/test_end_skill_learnings_step_before_commit.py,tests/skills/test-design-skills-cross-stack.sh,tests/skills/test_end_skill_dirty_worktree_resolution.py,tests/skills/test_fix_bug_skill_escalated_section.py,tests/skills/test_end_skill_bug_tickets_before_commit.py,tests/skills/test-end-session-rationalized-failures.sh,tests/hooks/test-sub-agent-guard.sh
68+
plugins/dso/skills/end-session/error-sweep.sh:tests/scripts/test-end-session-error-sweep.sh [test_error_sweep_no_tk_list_call]
6769
plugins/dso/skills/fix-bug/SKILL.md:plugins/dso/tests/test-sprint-skill-step10-no-merge-to-main.sh,tests/plugin/test-audit-skill-resolution.sh,tests/hooks/test-fix-bug-skill.sh,tests/hooks/test-generate-claude-md-skill.sh,tests/hooks/test-init-skill.sh,tests/scripts/test-qualify-skill-refs.sh,tests/scripts/test-skill-path-refs.sh,tests/scripts/test-check-skill-refs.sh,tests/skills/test_end_skill_final_verification_step.py,tests/skills/test_implementation_plan_skill_tdd_enforcement.py,tests/skills/test-quick-ref-skill.sh,tests/skills/test_project_setup_skill_conditional_prompts.py,tests/skills/test_fix_bug_skill.py,tests/skills/test_end_skill_summary_displays_stored_learnings.py,tests/skills/test_end_skill_learnings_step_before_commit.py,tests/skills/test-design-skills-cross-stack.sh,tests/skills/test_end_skill_dirty_worktree_resolution.py,tests/skills/test_fix_bug_skill_escalated_section.py,tests/skills/test_end_skill_bug_tickets_before_commit.py
6870
plugins/dso/skills/fix-bug/prompts/advanced-investigation-agent-a.md:tests/skills/test_advanced_investigation_agent_a_prompt.py,tests/skills/test_advanced_investigation_agent_b_prompt.py
6971
plugins/dso/skills/fix-bug/prompts/advanced-investigation-agent-b.md:tests/skills/test_advanced_investigation_agent_b_prompt.py
@@ -105,4 +107,8 @@ plugins/dso/skills/using-lockpick/SKILL.md:plugins/dso/tests/test-sprint-skill-s
105107
plugins/dso/skills/validate-work/SKILL.md:plugins/dso/tests/test-sprint-skill-step10-no-merge-to-main.sh,tests/plugin/test-audit-skill-resolution.sh,tests/hooks/test-fix-bug-skill.sh,tests/hooks/test-generate-claude-md-skill.sh,tests/hooks/test-init-skill.sh,tests/scripts/test-qualify-skill-refs.sh,tests/scripts/test-skill-path-refs.sh,tests/scripts/test-check-skill-refs.sh,tests/skills/test_end_skill_final_verification_step.py,tests/skills/test_implementation_plan_skill_tdd_enforcement.py,tests/skills/test-quick-ref-skill.sh,tests/skills/test_project_setup_skill_conditional_prompts.py,tests/skills/test_fix_bug_skill.py,tests/skills/test_end_skill_summary_displays_stored_learnings.py,tests/skills/test_end_skill_learnings_step_before_commit.py,tests/skills/test-design-skills-cross-stack.sh,tests/skills/test_end_skill_dirty_worktree_resolution.py,tests/skills/test_fix_bug_skill_escalated_section.py,tests/skills/test_end_skill_bug_tickets_before_commit.py,tests/hooks/test-sub-agent-guard.sh
106108
plugins/dso/skills/validate-work/prompts/ci-status.md:tests/hooks/test-ci-status-no-jq.sh,tests/scripts/test-ci-status-auth-ratelimit.sh,tests/scripts/test-ci-status-timeout.sh,tests/scripts/test-ci-status.sh
107109
plugins/dso/skills/verification-before-completion/SKILL.md:plugins/dso/tests/test-sprint-skill-step10-no-merge-to-main.sh,tests/plugin/test-audit-skill-resolution.sh,tests/hooks/test-fix-bug-skill.sh,tests/hooks/test-generate-claude-md-skill.sh,tests/hooks/test-init-skill.sh,tests/scripts/test-qualify-skill-refs.sh,tests/scripts/test-skill-path-refs.sh,tests/scripts/test-check-skill-refs.sh,tests/skills/test_end_skill_final_verification_step.py,tests/skills/test_implementation_plan_skill_tdd_enforcement.py,tests/skills/test-quick-ref-skill.sh,tests/skills/test_project_setup_skill_conditional_prompts.py,tests/skills/test_fix_bug_skill.py,tests/skills/test_end_skill_summary_displays_stored_learnings.py,tests/skills/test_end_skill_learnings_step_before_commit.py,tests/skills/test-design-skills-cross-stack.sh,tests/skills/test_end_skill_dirty_worktree_resolution.py,tests/skills/test_fix_bug_skill_escalated_section.py,tests/skills/test_end_skill_bug_tickets_before_commit.py
110+
.github/workflows/ci.yml: tests/scripts/test-ci-no-v2-paths.sh [test_ci_yml_no_tickets_paths]
111+
examples/ci.example.yml: tests/scripts/test-ci-no-v2-paths.sh [test_ci_example_yml_no_tickets_paths]
112+
examples/pre-commit-config.example.yaml: tests/scripts/test-ci-no-v2-paths.sh [test_precommit_example_no_tickets_exclude]
108113
plugins/dso/hooks/pre-commit-ticket-gate.sh: tests/hooks/test-pre-commit-ticket-gate.sh [test_blocks_missing_ticket_id]
114+
plugins/dso/scripts/merge-to-main.sh: tests/scripts/test-merge-to-main.sh [test_merge_to_main_no_v2_tickets_md_pattern]

plugins/dso/scripts/agent-batch-lifecycle.sh

Lines changed: 61 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ set -euo pipefail
99
# pre-check [--db] Pre-batch safety checks (session usage, git, optional DB)
1010
# preflight [--start-db] Pre-flight Docker & DB check (before diagnostic sub-agents)
1111
# file-overlap <file>... Detect file conflicts from multiple agent result files
12-
# lock-acquire <label> Session lock via tk (debug-everything only)
12+
# lock-acquire <label> Session lock via ticket CLI (debug-everything only)
1313
# lock-release <issue-id> Release session lock (debug-everything only)
1414
# lock-status <label> Check if a session lock exists
1515
# cleanup-stale-containers Remove Docker containers for worktrees that no longer exist
@@ -25,7 +25,7 @@ set -euo pipefail
2525
set -euo pipefail
2626
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
2727
PLUGIN_SCRIPTS="$SCRIPT_DIR"
28-
TK="${TK:-$SCRIPT_DIR/tk}"
28+
TICKET_CMD="${TICKET_CMD:-$SCRIPT_DIR/ticket}"
2929

3030
REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo "")
3131
if [ -z "$REPO_ROOT" ]; then
@@ -236,7 +236,7 @@ cmd_file_overlap() {
236236

237237
# ─── lock-acquire ────────────────────────────────────────────────────────────
238238
#
239-
# Acquires a tk-based session lock. Used by debug-everything Phase 1 ONLY.
239+
# Acquires a ticket-CLI-based session lock. Used by debug-everything Phase 1 ONLY.
240240
#
241241
# Usage:
242242
# agent-batch-lifecycle.sh lock-acquire "debug-everything"
@@ -251,53 +251,68 @@ cmd_file_overlap() {
251251
cmd_lock_acquire() {
252252
local label="${1:?Missing lock label}"
253253

254-
# Check for existing lock by scanning TICKETS_DIR for in_progress lock tickets
254+
# Check for existing lock using ticket CLI (v3): list all tickets, find in_progress
255+
# lock tasks matching the label.
255256
local lock_id=""
256-
if [ -d "$TICKETS_DIR" ]; then
257-
while IFS= read -r ticket_file; do
258-
[ -z "$ticket_file" ] && continue
259-
# Check if this ticket has the right title and is in_progress.
260-
# Tickets store their title as a markdown H1 heading after the YAML
261-
# frontmatter (e.g., "# [LOCK] debug-everything"), NOT as a YAML
262-
# `title:` field. Match the H1 form to correctly find synced tickets.
263-
if grep -qE "^# \\[LOCK\\] $label$" "$ticket_file" 2>/dev/null; then
264-
if grep -q "^status: in_progress" "$ticket_file" 2>/dev/null; then
265-
lock_id=$(grep -m1 "^id:" "$ticket_file" | sed 's/^id: *//' | tr -d '"'"'" || echo "")
266-
break
267-
fi
268-
fi
269-
done < <(find "$TICKETS_DIR" -maxdepth 1 -name "*.md" 2>/dev/null)
270-
fi
257+
lock_id=$(export LOCK_LABEL="$label"; "$TICKET_CMD" list 2>/dev/null | python3 -c "
258+
import json, sys, os
259+
label = os.environ.get('LOCK_LABEL', '')
260+
tickets = json.load(sys.stdin)
261+
for t in tickets:
262+
if (t.get('ticket_type') == 'task'
263+
and t.get('status') == 'in_progress'
264+
and t.get('title', '') == '[LOCK] ' + label):
265+
print(t['ticket_id'])
266+
break
267+
" 2>/dev/null || echo "")
271268

272269
if [ -n "$lock_id" ]; then
273-
# Check if the lock's worktree still exists
270+
# Check if the lock's worktree still exists by reading ticket notes via ticket CLI
274271
local notes
275-
notes=$("$TK" show "$lock_id" 2>/dev/null | grep -oE 'Worktree: [^ ]+' | sed 's/Worktree: //' || echo "")
272+
notes=$("$TICKET_CMD" show "$lock_id" 2>/dev/null | python3 -c "
273+
import json, sys
274+
t = json.load(sys.stdin)
275+
for c in t.get('comments', []):
276+
body = c.get('body', '')
277+
if 'Worktree: ' in body:
278+
for part in body.split('|'):
279+
part = part.strip()
280+
if part.startswith('Worktree: '):
281+
print(part[len('Worktree: '):].strip())
282+
break
283+
break
284+
" 2>/dev/null || echo "")
276285
if [ -n "$notes" ] && [ -d "$notes" ]; then
277286
# Live lock — blocked
278287
echo "LOCK_BLOCKED: $lock_id"
279288
echo "LOCK_WORKTREE: $notes"
280289
return 1
281290
else
282-
# Stale lock — reclaim (add-note before close: tk rejects notes on closed tickets)
283-
"$TK" add-note "$lock_id" "Stale lock — worktree no longer exists" 2>/dev/null || true
284-
"$TK" close "$lock_id" 2>/dev/null || true
291+
# Stale lock — reclaim (comment before close)
292+
"$TICKET_CMD" comment "$lock_id" "Stale lock — worktree no longer exists" 2>/dev/null || true
293+
# Read current status (ticket show) before: ticket transition <id> <current> closed
294+
local current_status
295+
current_status=$("$TICKET_CMD" show "$lock_id" 2>/dev/null | python3 -c "import json,sys; print(json.load(sys.stdin).get('status','in_progress'))" 2>/dev/null || echo "in_progress")
296+
"$TICKET_CMD" transition "$lock_id" "$current_status" closed 2>/dev/null || true
285297
echo "LOCK_STALE: $lock_id"
286298
fi
287299
fi
288300

289-
# Create new lock — tk create outputs just the ticket ID (single line, no decoration)
301+
# Create new lock using v3 ticket CLI (ticket create task "<title>")
290302
local new_id
291-
new_id=$("$TK" create "[LOCK] $label" -t task -p 0 2>&1 | tr -d '[:space:]')
303+
new_id=$("$TICKET_CMD" create task "[LOCK] $label" 2>&1 | tr -d '[:space:]')
292304

293305
if [ -z "$new_id" ] || echo "$new_id" | grep -qiE 'error|fail'; then
294306
echo "ERROR: Failed to create lock ticket"
295307
echo "OUTPUT: $new_id"
296308
return 1
297309
fi
298310

299-
"$TK" status "$new_id" in_progress 2>/dev/null || true
300-
"$TK" add-note "$new_id" "Session: $(date -Iseconds) | Worktree: $REPO_ROOT" 2>/dev/null || true
311+
# Read current status before transitioning to in_progress
312+
local new_status
313+
new_status=$("$TICKET_CMD" show "$new_id" 2>/dev/null | python3 -c "import json,sys; print(json.load(sys.stdin).get('status','open'))" 2>/dev/null || echo "open")
314+
"$TICKET_CMD" transition "$new_id" "$new_status" in_progress 2>/dev/null || true
315+
"$TICKET_CMD" comment "$new_id" "Session: $(date -Iseconds) | Worktree: $REPO_ROOT" 2>/dev/null || true
301316

302317
echo "LOCK_ID: $new_id"
303318
return 0
@@ -314,9 +329,12 @@ cmd_lock_release() {
314329
local lock_id="${1:?Missing lock ticket ID}"
315330
local reason="${2:-Session complete}"
316331

317-
# add-note before close: tk rejects notes on closed tickets
318-
"$TK" add-note "$lock_id" "Closed: $reason" 2>/dev/null || true
319-
"$TK" close "$lock_id" 2>/dev/null || true
332+
# Comment before close (ticket CLI rejects comments on closed tickets)
333+
"$TICKET_CMD" comment "$lock_id" "Closed: $reason" 2>/dev/null || true
334+
# Read current status before transitioning to closed
335+
local current_status
336+
current_status=$("$TICKET_CMD" show "$lock_id" 2>/dev/null | python3 -c "import json,sys; print(json.load(sys.stdin).get('status','in_progress'))" 2>/dev/null || echo "in_progress")
337+
"$TICKET_CMD" transition "$lock_id" "$current_status" closed 2>/dev/null || true
320338
echo "LOCK_RELEASED: $lock_id"
321339
return 0
322340
}
@@ -335,22 +353,19 @@ cmd_lock_release() {
335353
cmd_lock_status() {
336354
local label="${1:?Missing lock label}"
337355

338-
# Scan TICKETS_DIR for in_progress lock tickets matching the label
356+
# Query ticket CLI (v3) for in_progress lock tasks matching the label
339357
local lock_id=""
340-
if [ -d "$TICKETS_DIR" ]; then
341-
while IFS= read -r ticket_file; do
342-
[ -z "$ticket_file" ] && continue
343-
# Tickets store their title as a markdown H1 heading after the YAML
344-
# frontmatter (e.g., "# [LOCK] debug-everything"), NOT as a YAML
345-
# `title:` field. Match the H1 form to correctly find synced tickets.
346-
if grep -qE "^# \\[LOCK\\] $label$" "$ticket_file" 2>/dev/null; then
347-
if grep -q "^status: in_progress" "$ticket_file" 2>/dev/null; then
348-
lock_id=$(grep -m1 "^id:" "$ticket_file" | sed 's/^id: *//' | tr -d '"'"'" || echo "")
349-
break
350-
fi
351-
fi
352-
done < <(find "$TICKETS_DIR" -maxdepth 1 -name "*.md" 2>/dev/null)
353-
fi
358+
lock_id=$(export LOCK_LABEL="$label"; "$TICKET_CMD" list 2>/dev/null | python3 -c "
359+
import json, sys, os
360+
label = os.environ.get('LOCK_LABEL', '')
361+
tickets = json.load(sys.stdin)
362+
for t in tickets:
363+
if (t.get('ticket_type') == 'task'
364+
and t.get('status') == 'in_progress'
365+
and t.get('title', '') == '[LOCK] ' + label):
366+
print(t['ticket_id'])
367+
break
368+
" 2>/dev/null || echo "")
354369

355370
if [ -n "$lock_id" ]; then
356371
echo "LOCKED: $lock_id"

0 commit comments

Comments
 (0)