galangal-orchestrate 0.13.0__py3-none-any.whl
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.
- galangal/__init__.py +36 -0
- galangal/__main__.py +6 -0
- galangal/ai/__init__.py +167 -0
- galangal/ai/base.py +159 -0
- galangal/ai/claude.py +352 -0
- galangal/ai/codex.py +370 -0
- galangal/ai/gemini.py +43 -0
- galangal/ai/subprocess.py +254 -0
- galangal/cli.py +371 -0
- galangal/commands/__init__.py +27 -0
- galangal/commands/complete.py +367 -0
- galangal/commands/github.py +355 -0
- galangal/commands/init.py +177 -0
- galangal/commands/init_wizard.py +762 -0
- galangal/commands/list.py +20 -0
- galangal/commands/pause.py +34 -0
- galangal/commands/prompts.py +89 -0
- galangal/commands/reset.py +41 -0
- galangal/commands/resume.py +30 -0
- galangal/commands/skip.py +62 -0
- galangal/commands/start.py +530 -0
- galangal/commands/status.py +44 -0
- galangal/commands/switch.py +28 -0
- galangal/config/__init__.py +15 -0
- galangal/config/defaults.py +183 -0
- galangal/config/loader.py +163 -0
- galangal/config/schema.py +330 -0
- galangal/core/__init__.py +33 -0
- galangal/core/artifacts.py +136 -0
- galangal/core/state.py +1097 -0
- galangal/core/tasks.py +454 -0
- galangal/core/utils.py +116 -0
- galangal/core/workflow/__init__.py +68 -0
- galangal/core/workflow/core.py +789 -0
- galangal/core/workflow/engine.py +781 -0
- galangal/core/workflow/pause.py +35 -0
- galangal/core/workflow/tui_runner.py +1322 -0
- galangal/exceptions.py +36 -0
- galangal/github/__init__.py +31 -0
- galangal/github/client.py +427 -0
- galangal/github/images.py +324 -0
- galangal/github/issues.py +298 -0
- galangal/logging.py +364 -0
- galangal/prompts/__init__.py +5 -0
- galangal/prompts/builder.py +527 -0
- galangal/prompts/defaults/benchmark.md +34 -0
- galangal/prompts/defaults/contract.md +35 -0
- galangal/prompts/defaults/design.md +54 -0
- galangal/prompts/defaults/dev.md +89 -0
- galangal/prompts/defaults/docs.md +104 -0
- galangal/prompts/defaults/migration.md +59 -0
- galangal/prompts/defaults/pm.md +110 -0
- galangal/prompts/defaults/pm_questions.md +53 -0
- galangal/prompts/defaults/preflight.md +32 -0
- galangal/prompts/defaults/qa.md +65 -0
- galangal/prompts/defaults/review.md +90 -0
- galangal/prompts/defaults/review_codex.md +99 -0
- galangal/prompts/defaults/security.md +84 -0
- galangal/prompts/defaults/test.md +91 -0
- galangal/results.py +176 -0
- galangal/ui/__init__.py +5 -0
- galangal/ui/console.py +126 -0
- galangal/ui/tui/__init__.py +56 -0
- galangal/ui/tui/adapters.py +168 -0
- galangal/ui/tui/app.py +902 -0
- galangal/ui/tui/entry.py +24 -0
- galangal/ui/tui/mixins.py +196 -0
- galangal/ui/tui/modals.py +339 -0
- galangal/ui/tui/styles/app.tcss +86 -0
- galangal/ui/tui/styles/modals.tcss +197 -0
- galangal/ui/tui/types.py +107 -0
- galangal/ui/tui/widgets.py +263 -0
- galangal/validation/__init__.py +5 -0
- galangal/validation/runner.py +1072 -0
- galangal_orchestrate-0.13.0.dist-info/METADATA +985 -0
- galangal_orchestrate-0.13.0.dist-info/RECORD +79 -0
- galangal_orchestrate-0.13.0.dist-info/WHEEL +4 -0
- galangal_orchestrate-0.13.0.dist-info/entry_points.txt +2 -0
- galangal_orchestrate-0.13.0.dist-info/licenses/LICENSE +674 -0
galangal/cli.py
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Galangal Orchestrate - AI-Driven Development Workflow CLI
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
galangal init - Initialize in current project
|
|
7
|
+
galangal start "task description" - Start new task
|
|
8
|
+
galangal start "desc" --name my-task - Start with explicit name
|
|
9
|
+
galangal list - List all tasks
|
|
10
|
+
galangal switch <task-name> - Switch active task
|
|
11
|
+
galangal status - Show active task status
|
|
12
|
+
galangal resume - Continue active task
|
|
13
|
+
galangal pause - Pause task for break/shutdown
|
|
14
|
+
galangal reset - Delete active task
|
|
15
|
+
galangal complete - Move task to done/, create PR
|
|
16
|
+
galangal prompts export - Export default prompts for customization
|
|
17
|
+
|
|
18
|
+
Debug mode:
|
|
19
|
+
galangal --debug <command> - Enable debug logging to logs/galangal_debug.log
|
|
20
|
+
GALANGAL_DEBUG=1 galangal <command> - Alternative via environment variable
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
import argparse
|
|
24
|
+
import os
|
|
25
|
+
import sys
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _setup_debug_mode() -> None:
|
|
29
|
+
"""Enable debug mode by setting environment variable and configuring logging."""
|
|
30
|
+
os.environ["GALANGAL_DEBUG"] = "1"
|
|
31
|
+
|
|
32
|
+
from galangal.config.loader import get_project_root
|
|
33
|
+
|
|
34
|
+
# Create logs directory in project root (not cwd)
|
|
35
|
+
logs_dir = get_project_root() / "logs"
|
|
36
|
+
logs_dir.mkdir(exist_ok=True)
|
|
37
|
+
|
|
38
|
+
# Write initial debug log entry immediately so file is always created
|
|
39
|
+
# Do this BEFORE configure_logging to ensure we have a log even if that fails
|
|
40
|
+
from galangal.core.utils import debug_log, reset_debug_state
|
|
41
|
+
|
|
42
|
+
reset_debug_state() # Clear any cached state
|
|
43
|
+
debug_log("Debug mode enabled", command=" ".join(sys.argv))
|
|
44
|
+
|
|
45
|
+
# Also enable structured logging to file
|
|
46
|
+
try:
|
|
47
|
+
from galangal.logging import configure_logging
|
|
48
|
+
|
|
49
|
+
configure_logging(
|
|
50
|
+
level="debug",
|
|
51
|
+
log_file=logs_dir / "galangal.jsonl",
|
|
52
|
+
json_format=True,
|
|
53
|
+
console_output=False, # Don't spam console, just log to file
|
|
54
|
+
)
|
|
55
|
+
except Exception as e:
|
|
56
|
+
debug_log("Failed to configure structured logging", error=str(e))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _build_epilog() -> str:
|
|
60
|
+
"""Build CLI epilog from canonical sources in state.py."""
|
|
61
|
+
from galangal.core.state import TaskType, get_workflow_diagram
|
|
62
|
+
|
|
63
|
+
# Build task types section from TaskType enum
|
|
64
|
+
task_lines = []
|
|
65
|
+
for i, tt in enumerate(TaskType, start=1):
|
|
66
|
+
task_lines.append(f" [{i}] {tt.display_name():10} - {tt.short_description()}")
|
|
67
|
+
|
|
68
|
+
task_types_section = "\n".join(task_lines)
|
|
69
|
+
|
|
70
|
+
# Build workflow diagram from STAGE_ORDER
|
|
71
|
+
workflow = get_workflow_diagram().replace("→", "->")
|
|
72
|
+
|
|
73
|
+
return f"""
|
|
74
|
+
Debug mode:
|
|
75
|
+
galangal --debug start "task" Enable verbose logging to logs/galangal_debug.log
|
|
76
|
+
GALANGAL_DEBUG=1 galangal ... Alternative via environment variable
|
|
77
|
+
|
|
78
|
+
Examples:
|
|
79
|
+
galangal init
|
|
80
|
+
galangal start "Add user authentication"
|
|
81
|
+
galangal start "Add auth" --name add-auth-feature
|
|
82
|
+
galangal list
|
|
83
|
+
galangal switch add-auth-feature
|
|
84
|
+
galangal status
|
|
85
|
+
galangal resume
|
|
86
|
+
galangal pause
|
|
87
|
+
galangal skip-to DEV
|
|
88
|
+
galangal skip-to TEST --resume
|
|
89
|
+
galangal complete
|
|
90
|
+
galangal reset
|
|
91
|
+
galangal prompts export
|
|
92
|
+
|
|
93
|
+
Task Types:
|
|
94
|
+
At task start, you'll select from:
|
|
95
|
+
{task_types_section}
|
|
96
|
+
|
|
97
|
+
Workflow:
|
|
98
|
+
{workflow}
|
|
99
|
+
|
|
100
|
+
* = Conditional stages (auto-skipped if condition not met)
|
|
101
|
+
|
|
102
|
+
Tip: Press Ctrl+C during execution to pause gracefully.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def main() -> int:
|
|
107
|
+
parser = argparse.ArgumentParser(
|
|
108
|
+
description="Galangal Orchestrate - AI-Driven Development Workflow",
|
|
109
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
110
|
+
epilog=_build_epilog(),
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Global --debug flag (before subparsers)
|
|
114
|
+
parser.add_argument(
|
|
115
|
+
"--debug",
|
|
116
|
+
"-d",
|
|
117
|
+
action="store_true",
|
|
118
|
+
help="Enable debug logging to logs/galangal_debug.log and logs/galangal.jsonl",
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
122
|
+
|
|
123
|
+
# init
|
|
124
|
+
init_parser = subparsers.add_parser("init", help="Initialize galangal in current project")
|
|
125
|
+
init_parser.add_argument(
|
|
126
|
+
"--quick",
|
|
127
|
+
"-q",
|
|
128
|
+
action="store_true",
|
|
129
|
+
help="Quick init without interactive wizard (for CI/automation)",
|
|
130
|
+
)
|
|
131
|
+
init_parser.set_defaults(func=_cmd_init)
|
|
132
|
+
|
|
133
|
+
# start
|
|
134
|
+
start_parser = subparsers.add_parser("start", help="Start new task")
|
|
135
|
+
start_parser.add_argument(
|
|
136
|
+
"description", nargs="*", help="Task description (prompted if not provided)"
|
|
137
|
+
)
|
|
138
|
+
start_parser.add_argument("--name", "-n", help="Task name (auto-generated if not provided)")
|
|
139
|
+
start_parser.add_argument(
|
|
140
|
+
"--type",
|
|
141
|
+
"-t",
|
|
142
|
+
choices=[
|
|
143
|
+
"feature",
|
|
144
|
+
"bugfix",
|
|
145
|
+
"refactor",
|
|
146
|
+
"chore",
|
|
147
|
+
"docs",
|
|
148
|
+
"hotfix",
|
|
149
|
+
"1",
|
|
150
|
+
"2",
|
|
151
|
+
"3",
|
|
152
|
+
"4",
|
|
153
|
+
"5",
|
|
154
|
+
"6",
|
|
155
|
+
],
|
|
156
|
+
help="Task type (skip interactive selection)",
|
|
157
|
+
)
|
|
158
|
+
start_parser.add_argument(
|
|
159
|
+
"--skip-discovery",
|
|
160
|
+
action="store_true",
|
|
161
|
+
help="Skip the discovery Q&A phase and go straight to spec generation",
|
|
162
|
+
)
|
|
163
|
+
start_parser.add_argument(
|
|
164
|
+
"--issue", "-i", type=int, help="Create task from GitHub issue number"
|
|
165
|
+
)
|
|
166
|
+
start_parser.set_defaults(func=_cmd_start)
|
|
167
|
+
|
|
168
|
+
# list
|
|
169
|
+
list_parser = subparsers.add_parser("list", help="List all tasks")
|
|
170
|
+
list_parser.set_defaults(func=_cmd_list)
|
|
171
|
+
|
|
172
|
+
# switch
|
|
173
|
+
switch_parser = subparsers.add_parser("switch", help="Switch active task")
|
|
174
|
+
switch_parser.add_argument("task_name", help="Task name to switch to")
|
|
175
|
+
switch_parser.set_defaults(func=_cmd_switch)
|
|
176
|
+
|
|
177
|
+
# resume
|
|
178
|
+
resume_parser = subparsers.add_parser("resume", help="Resume active task")
|
|
179
|
+
resume_parser.add_argument(
|
|
180
|
+
"--skip-discovery",
|
|
181
|
+
action="store_true",
|
|
182
|
+
help="Skip remaining discovery Q&A and go straight to spec generation",
|
|
183
|
+
)
|
|
184
|
+
resume_parser.set_defaults(func=_cmd_resume)
|
|
185
|
+
|
|
186
|
+
# pause
|
|
187
|
+
pause_parser = subparsers.add_parser("pause", help="Pause task for break/shutdown")
|
|
188
|
+
pause_parser.set_defaults(func=_cmd_pause)
|
|
189
|
+
|
|
190
|
+
# status
|
|
191
|
+
status_parser = subparsers.add_parser("status", help="Show active task status")
|
|
192
|
+
status_parser.set_defaults(func=_cmd_status)
|
|
193
|
+
|
|
194
|
+
# skip-to
|
|
195
|
+
skip_to_parser = subparsers.add_parser(
|
|
196
|
+
"skip-to", help="Jump to a specific stage (for debugging/re-running)"
|
|
197
|
+
)
|
|
198
|
+
skip_to_parser.add_argument("stage", help="Target stage (e.g., DEV, TEST, SECURITY)")
|
|
199
|
+
skip_to_parser.add_argument("--force", "-f", action="store_true", help="Skip confirmation")
|
|
200
|
+
skip_to_parser.add_argument(
|
|
201
|
+
"--resume", "-r", action="store_true", help="Resume workflow immediately after jumping"
|
|
202
|
+
)
|
|
203
|
+
skip_to_parser.set_defaults(func=_cmd_skip_to)
|
|
204
|
+
|
|
205
|
+
# reset
|
|
206
|
+
reset_parser = subparsers.add_parser("reset", help="Delete active task")
|
|
207
|
+
reset_parser.add_argument("--force", "-f", action="store_true", help="Skip confirmation")
|
|
208
|
+
reset_parser.set_defaults(func=_cmd_reset)
|
|
209
|
+
|
|
210
|
+
# complete
|
|
211
|
+
complete_parser = subparsers.add_parser(
|
|
212
|
+
"complete", help="Move completed task to done/, create PR"
|
|
213
|
+
)
|
|
214
|
+
complete_parser.add_argument(
|
|
215
|
+
"--force", "-f", action="store_true", help="Continue on commit errors"
|
|
216
|
+
)
|
|
217
|
+
complete_parser.set_defaults(func=_cmd_complete)
|
|
218
|
+
|
|
219
|
+
# prompts
|
|
220
|
+
prompts_parser = subparsers.add_parser("prompts", help="Manage prompts")
|
|
221
|
+
prompts_subparsers = prompts_parser.add_subparsers(dest="prompts_command")
|
|
222
|
+
prompts_export = prompts_subparsers.add_parser(
|
|
223
|
+
"export", help="Export default prompts for customization"
|
|
224
|
+
)
|
|
225
|
+
prompts_export.set_defaults(func=_cmd_prompts_export)
|
|
226
|
+
prompts_show = prompts_subparsers.add_parser("show", help="Show effective prompt for a stage")
|
|
227
|
+
prompts_show.add_argument("stage", help="Stage name (e.g., pm, dev, test)")
|
|
228
|
+
prompts_show.set_defaults(func=_cmd_prompts_show)
|
|
229
|
+
|
|
230
|
+
# github
|
|
231
|
+
github_parser = subparsers.add_parser("github", help="GitHub integration")
|
|
232
|
+
github_subparsers = github_parser.add_subparsers(dest="github_command")
|
|
233
|
+
github_setup = github_subparsers.add_parser(
|
|
234
|
+
"setup", help="Set up GitHub integration (create labels, verify gh CLI)"
|
|
235
|
+
)
|
|
236
|
+
github_setup.add_argument(
|
|
237
|
+
"--help-install", action="store_true", help="Show detailed gh CLI installation instructions"
|
|
238
|
+
)
|
|
239
|
+
github_setup.set_defaults(func=_cmd_github_setup)
|
|
240
|
+
github_check = github_subparsers.add_parser(
|
|
241
|
+
"check", help="Check GitHub CLI installation and authentication"
|
|
242
|
+
)
|
|
243
|
+
github_check.set_defaults(func=_cmd_github_check)
|
|
244
|
+
github_issues = github_subparsers.add_parser("issues", help="List issues with galangal label")
|
|
245
|
+
github_issues.add_argument(
|
|
246
|
+
"--label", "-l", default="galangal", help="Label to filter by (default: galangal)"
|
|
247
|
+
)
|
|
248
|
+
github_issues.add_argument(
|
|
249
|
+
"--limit", "-n", type=int, default=50, help="Maximum number of issues to list"
|
|
250
|
+
)
|
|
251
|
+
github_issues.set_defaults(func=_cmd_github_issues)
|
|
252
|
+
github_run = github_subparsers.add_parser(
|
|
253
|
+
"run", help="Process all galangal-labeled issues (headless mode)"
|
|
254
|
+
)
|
|
255
|
+
github_run.add_argument(
|
|
256
|
+
"--label", "-l", default="galangal", help="Label to filter by (default: galangal)"
|
|
257
|
+
)
|
|
258
|
+
github_run.add_argument(
|
|
259
|
+
"--dry-run", action="store_true", help="List issues without processing them"
|
|
260
|
+
)
|
|
261
|
+
github_run.set_defaults(func=_cmd_github_run)
|
|
262
|
+
|
|
263
|
+
args = parser.parse_args()
|
|
264
|
+
|
|
265
|
+
# Enable debug mode if requested
|
|
266
|
+
if args.debug:
|
|
267
|
+
_setup_debug_mode()
|
|
268
|
+
|
|
269
|
+
result: int = args.func(args)
|
|
270
|
+
return result
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
# Command wrappers that import lazily to speed up CLI startup
|
|
274
|
+
def _cmd_init(args: argparse.Namespace) -> int:
|
|
275
|
+
from galangal.commands.init import cmd_init
|
|
276
|
+
|
|
277
|
+
return cmd_init(args)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def _cmd_start(args: argparse.Namespace) -> int:
|
|
281
|
+
from galangal.commands.start import cmd_start
|
|
282
|
+
|
|
283
|
+
return cmd_start(args)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def _cmd_list(args: argparse.Namespace) -> int:
|
|
287
|
+
from galangal.commands.list import cmd_list
|
|
288
|
+
|
|
289
|
+
return cmd_list(args)
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def _cmd_switch(args: argparse.Namespace) -> int:
|
|
293
|
+
from galangal.commands.switch import cmd_switch
|
|
294
|
+
|
|
295
|
+
return cmd_switch(args)
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def _cmd_resume(args: argparse.Namespace) -> int:
|
|
299
|
+
from galangal.commands.resume import cmd_resume
|
|
300
|
+
|
|
301
|
+
return cmd_resume(args)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def _cmd_pause(args: argparse.Namespace) -> int:
|
|
305
|
+
from galangal.commands.pause import cmd_pause
|
|
306
|
+
|
|
307
|
+
return cmd_pause(args)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def _cmd_status(args: argparse.Namespace) -> int:
|
|
311
|
+
from galangal.commands.status import cmd_status
|
|
312
|
+
|
|
313
|
+
return cmd_status(args)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def _cmd_skip_to(args: argparse.Namespace) -> int:
|
|
317
|
+
from galangal.commands.skip import cmd_skip_to
|
|
318
|
+
|
|
319
|
+
return cmd_skip_to(args)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def _cmd_reset(args: argparse.Namespace) -> int:
|
|
323
|
+
from galangal.commands.reset import cmd_reset
|
|
324
|
+
|
|
325
|
+
return cmd_reset(args)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def _cmd_complete(args: argparse.Namespace) -> int:
|
|
329
|
+
from galangal.commands.complete import cmd_complete
|
|
330
|
+
|
|
331
|
+
return cmd_complete(args)
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
def _cmd_prompts_export(args: argparse.Namespace) -> int:
|
|
335
|
+
from galangal.commands.prompts import cmd_prompts_export
|
|
336
|
+
|
|
337
|
+
return cmd_prompts_export(args)
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def _cmd_prompts_show(args: argparse.Namespace) -> int:
|
|
341
|
+
from galangal.commands.prompts import cmd_prompts_show
|
|
342
|
+
|
|
343
|
+
return cmd_prompts_show(args)
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _cmd_github_setup(args: argparse.Namespace) -> int:
|
|
347
|
+
from galangal.commands.github import cmd_github_setup
|
|
348
|
+
|
|
349
|
+
return cmd_github_setup(args)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def _cmd_github_check(args: argparse.Namespace) -> int:
|
|
353
|
+
from galangal.commands.github import cmd_github_check
|
|
354
|
+
|
|
355
|
+
return cmd_github_check(args)
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def _cmd_github_issues(args: argparse.Namespace) -> int:
|
|
359
|
+
from galangal.commands.github import cmd_github_issues
|
|
360
|
+
|
|
361
|
+
return cmd_github_issues(args)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def _cmd_github_run(args: argparse.Namespace) -> int:
|
|
365
|
+
from galangal.commands.github import cmd_github_run
|
|
366
|
+
|
|
367
|
+
return cmd_github_run(args)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
if __name__ == "__main__":
|
|
371
|
+
sys.exit(main())
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""CLI commands."""
|
|
2
|
+
|
|
3
|
+
from galangal.commands.complete import cmd_complete
|
|
4
|
+
from galangal.commands.init import cmd_init
|
|
5
|
+
from galangal.commands.list import cmd_list
|
|
6
|
+
from galangal.commands.pause import cmd_pause
|
|
7
|
+
from galangal.commands.prompts import cmd_prompts
|
|
8
|
+
from galangal.commands.reset import cmd_reset
|
|
9
|
+
from galangal.commands.resume import cmd_resume
|
|
10
|
+
from galangal.commands.skip import cmd_skip_to
|
|
11
|
+
from galangal.commands.start import cmd_start
|
|
12
|
+
from galangal.commands.status import cmd_status
|
|
13
|
+
from galangal.commands.switch import cmd_switch
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"cmd_init",
|
|
17
|
+
"cmd_start",
|
|
18
|
+
"cmd_resume",
|
|
19
|
+
"cmd_status",
|
|
20
|
+
"cmd_list",
|
|
21
|
+
"cmd_switch",
|
|
22
|
+
"cmd_pause",
|
|
23
|
+
"cmd_skip_to",
|
|
24
|
+
"cmd_reset",
|
|
25
|
+
"cmd_complete",
|
|
26
|
+
"cmd_prompts",
|
|
27
|
+
]
|