claude-code-workflow 6.3.13 → 6.3.15
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/.claude/agents/issue-plan-agent.md +57 -103
- package/.claude/agents/issue-queue-agent.md +69 -120
- package/.claude/commands/issue/new.md +217 -473
- package/.claude/commands/issue/plan.md +76 -154
- package/.claude/commands/issue/queue.md +208 -259
- package/.claude/skills/issue-manage/SKILL.md +63 -22
- package/.claude/workflows/cli-templates/schemas/discovery-finding-schema.json +3 -3
- package/.claude/workflows/cli-templates/schemas/issues-jsonl-schema.json +3 -3
- package/.claude/workflows/cli-templates/schemas/queue-schema.json +0 -5
- package/.codex/prompts/issue-plan.md +16 -19
- package/.codex/prompts/issue-queue.md +0 -1
- package/README.md +1 -0
- package/ccw/dist/cli.d.ts.map +1 -1
- package/ccw/dist/cli.js +3 -1
- package/ccw/dist/cli.js.map +1 -1
- package/ccw/dist/commands/cli.d.ts.map +1 -1
- package/ccw/dist/commands/cli.js +45 -3
- package/ccw/dist/commands/cli.js.map +1 -1
- package/ccw/dist/commands/issue.d.ts +3 -1
- package/ccw/dist/commands/issue.d.ts.map +1 -1
- package/ccw/dist/commands/issue.js +383 -30
- package/ccw/dist/commands/issue.js.map +1 -1
- package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/issue-routes.js +77 -16
- package/ccw/dist/core/routes/issue-routes.js.map +1 -1
- package/ccw/dist/tools/cli-executor.d.ts.map +1 -1
- package/ccw/dist/tools/cli-executor.js +117 -4
- package/ccw/dist/tools/cli-executor.js.map +1 -1
- package/ccw/dist/tools/litellm-executor.d.ts +4 -0
- package/ccw/dist/tools/litellm-executor.d.ts.map +1 -1
- package/ccw/dist/tools/litellm-executor.js +54 -1
- package/ccw/dist/tools/litellm-executor.js.map +1 -1
- package/ccw/dist/tools/ui-generate-preview.d.ts +18 -0
- package/ccw/dist/tools/ui-generate-preview.d.ts.map +1 -1
- package/ccw/dist/tools/ui-generate-preview.js +26 -10
- package/ccw/dist/tools/ui-generate-preview.js.map +1 -1
- package/ccw/src/cli.ts +3 -1
- package/ccw/src/commands/cli.ts +47 -3
- package/ccw/src/commands/issue.ts +442 -34
- package/ccw/src/core/routes/issue-routes.ts +82 -16
- package/ccw/src/tools/cli-executor.ts +125 -4
- package/ccw/src/tools/litellm-executor.ts +107 -24
- package/ccw/src/tools/ui-generate-preview.js +60 -37
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/entities.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/config.py +25 -2
- package/codex-lens/src/codexlens/entities.py +5 -1
- package/codex-lens/src/codexlens/indexing/__pycache__/symbol_extractor.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/indexing/symbol_extractor.py +243 -243
- package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/factory.py +256 -256
- package/codex-lens/src/codexlens/parsers/treesitter_parser.py +335 -335
- package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/chain_search.py +30 -1
- package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/reranker.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/embedder.py +6 -9
- package/codex-lens/src/codexlens/semantic/vector_store.py +271 -200
- package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/sqlite_store.py +184 -108
- package/package.json +6 -1
- package/.claude/commands/issue/manage.md +0 -113
|
@@ -2,55 +2,68 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import json
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
|
|
10
|
-
from
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
import sqlite3
|
|
8
|
+
import threading
|
|
9
|
+
import time
|
|
10
|
+
from dataclasses import asdict
|
|
11
|
+
from pathlib import Path
|
|
11
12
|
from typing import Any, Dict, Iterable, List, Optional, Tuple
|
|
12
13
|
|
|
13
|
-
from codexlens.entities import IndexedFile, SearchResult, Symbol
|
|
14
|
-
from codexlens.errors import StorageError
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
#
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
self.
|
|
35
|
-
self.
|
|
14
|
+
from codexlens.entities import IndexedFile, SearchResult, Symbol
|
|
15
|
+
from codexlens.errors import StorageError
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SQLiteStore:
|
|
21
|
+
"""SQLiteStore providing FTS5 search and symbol lookup.
|
|
22
|
+
|
|
23
|
+
Implements thread-local connection pooling for improved performance.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
# Maximum number of connections to keep in pool to prevent memory leaks
|
|
27
|
+
MAX_POOL_SIZE = 32
|
|
28
|
+
# Idle timeout in seconds (10 minutes)
|
|
29
|
+
IDLE_TIMEOUT = 600
|
|
30
|
+
# Periodic cleanup interval in seconds (5 minutes)
|
|
31
|
+
CLEANUP_INTERVAL = 300
|
|
32
|
+
|
|
33
|
+
def __init__(self, db_path: str | Path) -> None:
|
|
34
|
+
self.db_path = Path(db_path)
|
|
35
|
+
self._lock = threading.RLock()
|
|
36
|
+
self._local = threading.local()
|
|
37
|
+
self._pool_lock = threading.Lock()
|
|
38
|
+
# Pool stores (connection, last_access_time) tuples
|
|
39
|
+
self._pool: Dict[int, Tuple[sqlite3.Connection, float]] = {}
|
|
40
|
+
self._pool_generation = 0
|
|
41
|
+
self._cleanup_timer: threading.Timer | None = None
|
|
42
|
+
self._cleanup_stop_event = threading.Event()
|
|
43
|
+
self._start_cleanup_timer()
|
|
36
44
|
|
|
37
45
|
def _get_connection(self) -> sqlite3.Connection:
|
|
38
46
|
"""Get or create a thread-local database connection."""
|
|
39
47
|
thread_id = threading.get_ident()
|
|
40
48
|
current_time = time.time()
|
|
41
49
|
|
|
42
|
-
if getattr(self._local, "generation", None) == self._pool_generation:
|
|
43
|
-
conn = getattr(self._local, "conn", None)
|
|
44
|
-
if conn is not None:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
if getattr(self._local, "generation", None) == self._pool_generation:
|
|
51
|
+
conn = getattr(self._local, "conn", None)
|
|
52
|
+
if conn is not None:
|
|
53
|
+
with self._pool_lock:
|
|
54
|
+
pool_entry = self._pool.get(thread_id)
|
|
55
|
+
if pool_entry is not None:
|
|
56
|
+
pooled_conn, _ = pool_entry
|
|
57
|
+
self._pool[thread_id] = (pooled_conn, current_time)
|
|
58
|
+
self._local.conn = pooled_conn
|
|
59
|
+
return pooled_conn
|
|
60
|
+
|
|
61
|
+
# Thread-local connection is stale (e.g., cleaned up by timer).
|
|
62
|
+
self._local.conn = None
|
|
63
|
+
|
|
64
|
+
with self._pool_lock:
|
|
65
|
+
pool_entry = self._pool.get(thread_id)
|
|
66
|
+
if pool_entry is not None:
|
|
54
67
|
conn, _ = pool_entry
|
|
55
68
|
# Update last access time
|
|
56
69
|
self._pool[thread_id] = (conn, current_time)
|
|
@@ -72,37 +85,91 @@ class SQLiteStore:
|
|
|
72
85
|
self._local.generation = self._pool_generation
|
|
73
86
|
return conn
|
|
74
87
|
|
|
75
|
-
def _cleanup_stale_connections(self) -> None:
|
|
76
|
-
"""Remove connections for threads that no longer exist or have been idle too long."""
|
|
77
|
-
current_time = time.time()
|
|
78
|
-
# Get list of active thread IDs
|
|
79
|
-
active_threads = {t.ident for t in threading.enumerate() if t.ident is not None}
|
|
80
|
-
|
|
81
|
-
# Find connections to remove: dead threads or idle timeout exceeded
|
|
82
|
-
stale_ids = []
|
|
83
|
-
for tid, (conn, last_access) in list(self._pool.items()):
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
88
|
+
def _cleanup_stale_connections(self) -> None:
|
|
89
|
+
"""Remove connections for threads that no longer exist or have been idle too long."""
|
|
90
|
+
current_time = time.time()
|
|
91
|
+
# Get list of active thread IDs
|
|
92
|
+
active_threads = {t.ident for t in threading.enumerate() if t.ident is not None}
|
|
93
|
+
|
|
94
|
+
# Find connections to remove: dead threads or idle timeout exceeded
|
|
95
|
+
stale_ids: list[tuple[int, str]] = []
|
|
96
|
+
for tid, (conn, last_access) in list(self._pool.items()):
|
|
97
|
+
try:
|
|
98
|
+
is_dead_thread = tid not in active_threads
|
|
99
|
+
is_idle = (current_time - last_access) > self.IDLE_TIMEOUT
|
|
100
|
+
|
|
101
|
+
is_invalid_connection = False
|
|
102
|
+
if not is_dead_thread and not is_idle:
|
|
103
|
+
try:
|
|
104
|
+
conn.execute("SELECT 1").fetchone()
|
|
105
|
+
except sqlite3.ProgrammingError:
|
|
106
|
+
is_invalid_connection = True
|
|
107
|
+
except sqlite3.Error:
|
|
108
|
+
is_invalid_connection = True
|
|
109
|
+
|
|
110
|
+
if is_invalid_connection:
|
|
111
|
+
stale_ids.append((tid, "invalid_connection"))
|
|
112
|
+
elif is_dead_thread:
|
|
113
|
+
stale_ids.append((tid, "dead_thread"))
|
|
114
|
+
elif is_idle:
|
|
115
|
+
stale_ids.append((tid, "idle_timeout"))
|
|
116
|
+
except Exception:
|
|
117
|
+
# Never break cleanup for a single bad entry.
|
|
118
|
+
continue
|
|
119
|
+
|
|
120
|
+
# Close and remove stale connections
|
|
121
|
+
for tid, reason in stale_ids:
|
|
122
|
+
try:
|
|
123
|
+
conn, _ = self._pool[tid]
|
|
124
|
+
conn.close()
|
|
125
|
+
except Exception:
|
|
126
|
+
pass
|
|
127
|
+
del self._pool[tid]
|
|
128
|
+
logger.debug("Cleaned SQLiteStore connection for thread_id=%s (%s)", tid, reason)
|
|
129
|
+
|
|
130
|
+
def _start_cleanup_timer(self) -> None:
|
|
131
|
+
if self.CLEANUP_INTERVAL <= 0:
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
self._cleanup_stop_event.clear()
|
|
135
|
+
|
|
136
|
+
def tick() -> None:
|
|
137
|
+
if self._cleanup_stop_event.is_set():
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
with self._pool_lock:
|
|
142
|
+
self._cleanup_stale_connections()
|
|
143
|
+
finally:
|
|
144
|
+
with self._pool_lock:
|
|
145
|
+
if self._cleanup_stop_event.is_set():
|
|
146
|
+
self._cleanup_timer = None
|
|
147
|
+
return
|
|
148
|
+
|
|
149
|
+
self._cleanup_timer = threading.Timer(self.CLEANUP_INTERVAL, tick)
|
|
150
|
+
self._cleanup_timer.daemon = True
|
|
151
|
+
self._cleanup_timer.start()
|
|
152
|
+
|
|
153
|
+
self._cleanup_timer = threading.Timer(self.CLEANUP_INTERVAL, tick)
|
|
154
|
+
self._cleanup_timer.daemon = True
|
|
155
|
+
self._cleanup_timer.start()
|
|
156
|
+
|
|
157
|
+
def _stop_cleanup_timer(self) -> None:
|
|
158
|
+
self._cleanup_stop_event.set()
|
|
159
|
+
with self._pool_lock:
|
|
160
|
+
if self._cleanup_timer is not None:
|
|
161
|
+
self._cleanup_timer.cancel()
|
|
162
|
+
self._cleanup_timer = None
|
|
163
|
+
|
|
164
|
+
def close(self) -> None:
|
|
165
|
+
"""Close all pooled connections."""
|
|
166
|
+
with self._lock:
|
|
167
|
+
self._stop_cleanup_timer()
|
|
168
|
+
with self._pool_lock:
|
|
169
|
+
for conn, _ in self._pool.values():
|
|
170
|
+
conn.close()
|
|
171
|
+
self._pool.clear()
|
|
172
|
+
self._pool_generation += 1
|
|
106
173
|
|
|
107
174
|
if hasattr(self._local, "conn"):
|
|
108
175
|
self._local.conn = None
|
|
@@ -262,14 +329,20 @@ class SQLiteStore:
|
|
|
262
329
|
],
|
|
263
330
|
)
|
|
264
331
|
|
|
265
|
-
conn.commit()
|
|
266
|
-
except Exception:
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
332
|
+
conn.commit()
|
|
333
|
+
except Exception as exc:
|
|
334
|
+
try:
|
|
335
|
+
conn.rollback()
|
|
336
|
+
except Exception as rollback_exc:
|
|
337
|
+
logger.error(
|
|
338
|
+
"Rollback failed after add_files() error (%s): %s", exc, rollback_exc
|
|
339
|
+
)
|
|
340
|
+
raise exc.with_traceback(exc.__traceback__) from rollback_exc
|
|
341
|
+
raise
|
|
342
|
+
|
|
343
|
+
def remove_file(self, path: str | Path) -> bool:
|
|
344
|
+
"""Remove a file from the index."""
|
|
345
|
+
with self._lock:
|
|
273
346
|
conn = self._get_connection()
|
|
274
347
|
resolved_path = str(Path(path).resolve())
|
|
275
348
|
|
|
@@ -539,10 +612,10 @@ class SQLiteStore:
|
|
|
539
612
|
"""
|
|
540
613
|
)
|
|
541
614
|
|
|
542
|
-
def _migrate_fts_to_external(self, conn: sqlite3.Connection) -> None:
|
|
543
|
-
"""Migrate legacy files_fts (with duplicated content) to external content."""
|
|
544
|
-
try:
|
|
545
|
-
conn.execute("BEGIN")
|
|
615
|
+
def _migrate_fts_to_external(self, conn: sqlite3.Connection) -> None:
|
|
616
|
+
"""Migrate legacy files_fts (with duplicated content) to external content."""
|
|
617
|
+
try:
|
|
618
|
+
conn.execute("BEGIN")
|
|
546
619
|
conn.execute("DROP TRIGGER IF EXISTS files_ai")
|
|
547
620
|
conn.execute("DROP TRIGGER IF EXISTS files_ad")
|
|
548
621
|
conn.execute("DROP TRIGGER IF EXISTS files_au")
|
|
@@ -550,27 +623,30 @@ class SQLiteStore:
|
|
|
550
623
|
conn.execute("ALTER TABLE files_fts RENAME TO files_fts_legacy")
|
|
551
624
|
self._create_external_fts(conn)
|
|
552
625
|
conn.execute("INSERT INTO files_fts(files_fts) VALUES('rebuild')")
|
|
553
|
-
conn.execute("DROP TABLE files_fts_legacy")
|
|
554
|
-
conn.commit()
|
|
555
|
-
except sqlite3.DatabaseError:
|
|
556
|
-
try:
|
|
557
|
-
conn.rollback()
|
|
558
|
-
except Exception:
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
626
|
+
conn.execute("DROP TABLE files_fts_legacy")
|
|
627
|
+
conn.commit()
|
|
628
|
+
except sqlite3.DatabaseError as exc:
|
|
629
|
+
try:
|
|
630
|
+
conn.rollback()
|
|
631
|
+
except Exception as rollback_exc:
|
|
632
|
+
logger.error(
|
|
633
|
+
"Rollback failed during FTS schema migration (%s): %s", exc, rollback_exc
|
|
634
|
+
)
|
|
635
|
+
raise exc.with_traceback(exc.__traceback__) from rollback_exc
|
|
636
|
+
|
|
637
|
+
try:
|
|
638
|
+
conn.execute("DROP TABLE IF EXISTS files_fts")
|
|
639
|
+
except Exception:
|
|
640
|
+
pass
|
|
641
|
+
|
|
642
|
+
try:
|
|
643
|
+
conn.execute("ALTER TABLE files_fts_legacy RENAME TO files_fts")
|
|
644
|
+
conn.commit()
|
|
645
|
+
except Exception:
|
|
646
|
+
pass
|
|
647
|
+
raise
|
|
648
|
+
|
|
649
|
+
try:
|
|
650
|
+
conn.execute("VACUUM")
|
|
651
|
+
except sqlite3.DatabaseError:
|
|
652
|
+
pass
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-workflow",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.15",
|
|
4
4
|
"description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "ccw/src/index.js",
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"build": "tsc -p ccw/tsconfig.json",
|
|
13
13
|
"start": "node ccw/bin/ccw.js",
|
|
14
14
|
"test": "node --experimental-strip-types --test ccw/tests/*.test.js",
|
|
15
|
+
"test:visual": "node --experimental-strip-types --test ccw/tests/visual/**/*.visual.test.ts",
|
|
15
16
|
"prepublishOnly": "npm run build && echo 'Ready to publish @dyw/claude-code-workflow'"
|
|
16
17
|
},
|
|
17
18
|
"keywords": [
|
|
@@ -74,10 +75,14 @@
|
|
|
74
75
|
},
|
|
75
76
|
"homepage": "https://github.com/catlog22/Claude-Code-Workflow#readme",
|
|
76
77
|
"devDependencies": {
|
|
78
|
+
"@playwright/test": "^1.57.0",
|
|
77
79
|
"@types/better-sqlite3": "^7.6.12",
|
|
78
80
|
"@types/gradient-string": "^1.1.6",
|
|
79
81
|
"@types/inquirer": "^9.0.9",
|
|
80
82
|
"@types/node": "^25.0.1",
|
|
83
|
+
"pixelmatch": "^7.1.0",
|
|
84
|
+
"playwright": "^1.57.0",
|
|
85
|
+
"pngjs": "^7.0.0",
|
|
81
86
|
"typescript": "^5.9.3"
|
|
82
87
|
}
|
|
83
88
|
}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: manage
|
|
3
|
-
description: Interactive issue management (CRUD) via ccw cli endpoints with menu-driven interface
|
|
4
|
-
argument-hint: "[issue-id] [--action list|view|edit|delete|bulk]"
|
|
5
|
-
allowed-tools: TodoWrite(*), Bash(*), Read(*), Write(*), AskUserQuestion(*), Task(*)
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Issue Manage Command (/issue:manage)
|
|
9
|
-
|
|
10
|
-
## Overview
|
|
11
|
-
|
|
12
|
-
Interactive menu-driven interface for issue management using `ccw issue` CLI endpoints:
|
|
13
|
-
- **List**: Browse and filter issues
|
|
14
|
-
- **View**: Detailed issue inspection
|
|
15
|
-
- **Edit**: Modify issue fields
|
|
16
|
-
- **Delete**: Remove issues
|
|
17
|
-
- **Bulk**: Batch operations on multiple issues
|
|
18
|
-
|
|
19
|
-
## CLI Endpoints Reference
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
# Core endpoints (ccw issue)
|
|
23
|
-
ccw issue list # List all issues
|
|
24
|
-
ccw issue list <id> --json # Get issue details
|
|
25
|
-
ccw issue status <id> # Detailed status
|
|
26
|
-
ccw issue init <id> --title "..." # Create issue
|
|
27
|
-
ccw issue task <id> --title "..." # Add task
|
|
28
|
-
ccw issue bind <id> <solution-id> # Bind solution
|
|
29
|
-
|
|
30
|
-
# Queue management
|
|
31
|
-
ccw issue queue # List current queue
|
|
32
|
-
ccw issue queue add <id> # Add to queue
|
|
33
|
-
ccw issue queue list # Queue history
|
|
34
|
-
ccw issue queue switch <queue-id> # Switch queue
|
|
35
|
-
ccw issue queue archive # Archive queue
|
|
36
|
-
ccw issue queue delete <queue-id> # Delete queue
|
|
37
|
-
ccw issue next # Get next task
|
|
38
|
-
ccw issue done <queue-id> # Mark completed
|
|
39
|
-
ccw issue complete <item-id> # (legacy alias for done)
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## Usage
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
# Interactive mode (menu-driven)
|
|
46
|
-
/issue:manage
|
|
47
|
-
|
|
48
|
-
# Direct to specific issue
|
|
49
|
-
/issue:manage GH-123
|
|
50
|
-
|
|
51
|
-
# Direct action
|
|
52
|
-
/issue:manage --action list
|
|
53
|
-
/issue:manage GH-123 --action edit
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Implementation
|
|
57
|
-
|
|
58
|
-
This command delegates to the `issue-manage` skill for detailed implementation.
|
|
59
|
-
|
|
60
|
-
### Entry Point
|
|
61
|
-
|
|
62
|
-
```javascript
|
|
63
|
-
const issueId = parseIssueId(userInput);
|
|
64
|
-
const action = flags.action;
|
|
65
|
-
|
|
66
|
-
// Show main menu if no action specified
|
|
67
|
-
if (!action) {
|
|
68
|
-
await showMainMenu(issueId);
|
|
69
|
-
} else {
|
|
70
|
-
await executeAction(action, issueId);
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### Main Menu Flow
|
|
75
|
-
|
|
76
|
-
1. **Dashboard**: Fetch issues summary via `ccw issue list --json`
|
|
77
|
-
2. **Menu**: Present action options via AskUserQuestion
|
|
78
|
-
3. **Route**: Execute selected action (List/View/Edit/Delete/Bulk)
|
|
79
|
-
4. **Loop**: Return to menu after each action
|
|
80
|
-
|
|
81
|
-
### Available Actions
|
|
82
|
-
|
|
83
|
-
| Action | Description | CLI Command |
|
|
84
|
-
|--------|-------------|-------------|
|
|
85
|
-
| List | Browse with filters | `ccw issue list --json` |
|
|
86
|
-
| View | Detail view | `ccw issue status <id> --json` |
|
|
87
|
-
| Edit | Modify fields | Update `issues.jsonl` |
|
|
88
|
-
| Delete | Remove issue | Clean up all related files |
|
|
89
|
-
| Bulk | Batch operations | Multi-select + batch update |
|
|
90
|
-
|
|
91
|
-
## Data Files
|
|
92
|
-
|
|
93
|
-
| File | Purpose |
|
|
94
|
-
|------|---------|
|
|
95
|
-
| `.workflow/issues/issues.jsonl` | Issue records |
|
|
96
|
-
| `.workflow/issues/solutions/<id>.jsonl` | Solutions per issue |
|
|
97
|
-
| `.workflow/issues/queue.json` | Execution queue |
|
|
98
|
-
|
|
99
|
-
## Error Handling
|
|
100
|
-
|
|
101
|
-
| Error | Resolution |
|
|
102
|
-
|-------|------------|
|
|
103
|
-
| No issues found | Suggest creating with /issue:new |
|
|
104
|
-
| Issue not found | Show available issues, ask for correction |
|
|
105
|
-
| Invalid selection | Show error, re-prompt |
|
|
106
|
-
| Write failure | Check permissions, show error |
|
|
107
|
-
|
|
108
|
-
## Related Commands
|
|
109
|
-
|
|
110
|
-
- `/issue:new` - Create structured issue
|
|
111
|
-
- `/issue:plan` - Plan solution for issue
|
|
112
|
-
- `/issue:queue` - Form execution queue
|
|
113
|
-
- `/issue:execute` - Execute queued tasks
|