Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
d9cc610
feat: Implement comprehensive test suite for queue commands
Aug 2, 2026
9d776d8
docs: Update documentation for prompt queue feature
Aug 2, 2026
73041ce
fix: Correct format_command_result calls in remove_queue
Aug 2, 2026
0a337de
fix: Correct queue command error handling and test assertions
Aug 2, 2026
eea4b81
fix: Update test assertions for remove-queue interactive mode
Aug 2, 2026
3c06656
fix: Correct format_command_result usage in queue commands
Aug 2, 2026
e44847a
cli33: merged
Sep 1, 2026
45d5e65
update reqs
Sep 3, 2026
7cc0d5e
feat: preserve prompt queue on model switch and isolate sub-agents
Sep 4, 2026
798bc1a
fix: improve prompt queue processing and fix source code corruption
Sep 5, 2026
1be85a7
feat: scope queue commands to the active agent
Sep 5, 2026
f1de8a0
fix: isolate sub-agent prompt queues by guarding inheritance
Sep 5, 2026
97537db
cli-64: unpack error mcp server fix
Sep 5, 2026
562813e
Bump Version
dwash96 Sep 5, 2026
c913e9b
Add skill imports from community resources and skiils.sh
dwash96 Sep 6, 2026
f0337a5
Merge pull request #674 from szmania/cli-64-unpack-error
dwash96 Sep 6, 2026
018d9fe
Overhaul `/voice` command to run locally using Moonshine AI's lightwe…
dwash96 Sep 6, 2026
12134c9
Don't let tests bleed into real user directories
dwash96 Sep 6, 2026
d0ad6fb
Update model metadata for all of the recent model releases
dwash96 Sep 6, 2026
10e3360
Allow for concurrent recording and generation
dwash96 Sep 6, 2026
12e87a9
feat: implement /insert-queue command
Sep 6, 2026
61f913c
feat: implement /insert-queue command dispatch in TUI
Sep 6, 2026
9f76025
merged
Sep 6, 2026
c5e36a9
feat: implement prompt queue management system (CLI-33)
Sep 7, 2026
a347481
fix linting
Sep 7, 2026
34f6042
fix linting
Sep 7, 2026
db22778
fix linting
Sep 7, 2026
9adb066
fix: restore missing command methods and fix AttributeError in execute
Sep 7, 2026
de3e831
Fix voice tests now that recording message is in hints section
dwash96 Sep 7, 2026
f161c1c
#676: Preserve openrouter prefix
dwash96 Sep 7, 2026
2847ff5
fix: remove non-existent custom_commands assertion in test
Sep 7, 2026
5d26e5f
fix: remove unused variable 'commands' in test_command_paths_none_doe…
Sep 7, 2026
dd71975
docs: add `/insert-queue` to command documentation
Sep 7, 2026
0601aa6
Add token rate limiting configuration with `--tokens-per-minute` to h…
dwash96 Sep 7, 2026
1970986
Subagents should not use the default reminders as it conflicts with o…
dwash96 Sep 7, 2026
086cc55
Centralize tracking logic for background model calls
dwash96 Sep 7, 2026
3d73c8c
Sub agents should not inherit parent model files, needless context in…
dwash96 Sep 7, 2026
aed5092
Update background commands to use `paging` action in `ResourceManager…
dwash96 Sep 7, 2026
3717269
Fix tests
dwash96 Sep 7, 2026
d6d4059
Merge remote-tracking branch 'szmania/cli-33-queue-prompts' into v1.5…
dwash96 Sep 8, 2026
9fb17f6
Add actual onboarding walkthrough for first time model configuration
dwash96 Sep 8, 2026
dca4ba8
Fix race condition in test in github ci/cd
Sep 8, 2026
4e4c6ae
Default to huggingface for voice model, add download markers for user…
dwash96 Sep 8, 2026
de79a6c
Update voice documentation
dwash96 Sep 8, 2026
e38abd5
Add fallbacl detection for microphones
dwash96 Sep 8, 2026
2ed58c6
Close failed voice streams while finding compatible configurations
dwash96 Sep 8, 2026
82e5aa5
Fix usage accumulation gathering
dwash96 Sep 8, 2026
45b7285
check_tokens() should respect compaction max tokens, throttle message…
dwash96 Sep 8, 2026
3442031
Revert /voice bootstrapping and fallback detection to simple form
dwash96 Sep 8, 2026
ea99e9a
Remove test post-simplification
dwash96 Sep 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cecli/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from packaging import version

__version__ = "1.3.2.dev"
__version__ = "1.5.0.dev"
safe_version = __version__

try:
Expand Down
19 changes: 17 additions & 2 deletions cecli/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,18 @@ def get_parser(default_config_files, git_root):
help="Number of times to ping at 5min intervals to keep prompt cache warm (default: 0)",
)

##########
group = parser.add_argument_group("Rate limiting")
group.add_argument(
"--tokens-per-minute",
type=int,
default=1000000,
help=(
"Set the maximum tokens sent per minute before rate limiting sleeps are"
" inserted before LLM API calls (default: 1000000, use 0 to disable)"
),
)

##########
group = parser.add_argument_group("Repomap settings")
group.add_argument(
Expand Down Expand Up @@ -1062,8 +1074,11 @@ def get_parser(default_config_files, git_root):
group.add_argument(
"--voice-language",
metavar="VOICE_LANGUAGE",
default="en",
help="Specify the language for voice using ISO 639-1 code (default: auto)",
default=None,
help=(
"Specify the language for voice using ISO 639-1 code "
"(default: resolve from the voice setting, then chat language)"
),
)
group.add_argument(
"--voice-input-device",
Expand Down
342 changes: 271 additions & 71 deletions cecli/coders/base_coder.py

Large diffs are not rendered by default.

23 changes: 15 additions & 8 deletions cecli/commands/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
from .history_search import HistorySearchCommand
from .hooks import HooksCommand
from .hot_reload import HotReloadCommand
from .import_skill import ImportSkillCommand
from .include_skill import IncludeSkillCommand
from .insert_queue import InsertQueueCommand
from .lint import LintCommand
from .list_mcp import ListMcpCommand
from .list_queue import ListQueueCommand
Expand Down Expand Up @@ -130,10 +132,9 @@
CommandRegistry.register(HistorySearchCommand)
CommandRegistry.register(HooksCommand)
CommandRegistry.register(HotReloadCommand)
CommandRegistry.register(ReapAgentCommand)
CommandRegistry.register(SpawnAgentCommand)
CommandRegistry.register(SwitchAgentCommand)
CommandRegistry.register(ImportSkillCommand)
CommandRegistry.register(IncludeSkillCommand)
CommandRegistry.register(InsertQueueCommand)
CommandRegistry.register(LintCommand)
CommandRegistry.register(ListMcpCommand)
CommandRegistry.register(ListQueueCommand)
Expand All @@ -156,6 +157,7 @@
CommandRegistry.register(QuitCommand)
CommandRegistry.register(ReadOnlyCommand)
CommandRegistry.register(ReadOnlyStubCommand)
CommandRegistry.register(ReapAgentCommand)
CommandRegistry.register(ReasoningEffortCommand)
CommandRegistry.register(RemoveHookCommand)
CommandRegistry.register(RemoveMcpCommand)
Expand All @@ -170,6 +172,8 @@
CommandRegistry.register(SaveSessionCommand)
CommandRegistry.register(SearchMemoryCommand)
CommandRegistry.register(SettingsCommand)
CommandRegistry.register(SpawnAgentCommand)
CommandRegistry.register(SwitchAgentCommand)
CommandRegistry.register(TerminalSetupCommand)
CommandRegistry.register(TestCommand)
CommandRegistry.register(ThinkTokensCommand)
Expand Down Expand Up @@ -220,17 +224,17 @@
"HistorySearchCommand",
"HooksCommand",
"HotReloadCommand",
"ImportSkillCommand",
"IncludeSkillCommand",
"ReapAgentCommand",
"SpawnAgentCommand",
"SwitchAgentCommand",
"InsertQueueCommand",
"LintCommand",
"ListMcpCommand",
"ListQueueCommand",
"ListSessionsCommand",
"ListSkillsCommand",
"LoadCommand",
"LoadHookCommand",
"LoadMcpCommand",
"ListMcpCommand",
"LoadSessionCommand",
"LoadSkillCommand",
"LsCommand",
Expand All @@ -242,11 +246,12 @@
"MultilineModeCommand",
"parse_quoted_filenames",
"PasteCommand",
"quote_filename",
"QueueCommand",
"QuitCommand",
"quote_filename",
"ReadOnlyCommand",
"ReadOnlyStubCommand",
"ReapAgentCommand",
"ReasoningEffortCommand",
"ReloadProgramSignal",
"RemoveHookCommand",
Expand All @@ -262,6 +267,8 @@
"SaveSessionCommand",
"SearchMemoryCommand",
"SettingsCommand",
"SpawnAgentCommand",
"SwitchAgentCommand",
"SwitchCoderSignal",
"TerminalSetupCommand",
"TestCommand",
Expand Down
6 changes: 6 additions & 0 deletions cecli/commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ def prompt_queue(self):
coder = self.coder
return coder.prompt_queue if coder is not None else []

def _insert_prompt(self, text: str, index: int) -> dict:
"""Insert a prompt at the given index in the active coder's queue."""
from cecli.helpers import command_queue

return command_queue.insert_prompt(self._active_coder(), text, index)

def _enqueue_prompt(self, text: str) -> dict:
"""Add a prompt to the owning coder's queue."""
from cecli.helpers import command_queue
Expand Down
95 changes: 95 additions & 0 deletions cecli/commands/import_skill.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
from typing import List

from cecli.commands.utils.base_command import BaseCommand
from cecli.commands.utils.helpers import format_command_result


class ImportSkillCommand(BaseCommand):
NORM_NAME = "import-skill"
DESCRIPTION = "Import a skill from the community registry or skills.sh (agent mode only)"

@classmethod
async def execute(cls, io, coder, args, **kwargs):
"""Execute the import-skill command with given parameters."""
tokens = args.strip().split()
global_install = "--global" in tokens or "-g" in tokens
tokens = [token for token in tokens if token not in ("--global", "-g")]

if not tokens:
io.tool_output("Usage: /import-skill [--global] <skill-name>")
return format_command_result(
io, "import-skill", "Usage: /import-skill [--global] <skill-name>"
)

skill_name = " ".join(tokens)

# Importing (and including) skills is only available in agent mode.
if not hasattr(coder, "edit_format") or coder.edit_format not in ("agent", "subagent"):
io.tool_output("Skill import is only available in agent mode.")
return format_command_result(
io, "import-skill", "Skill import is only available in agent mode"
)

if not hasattr(coder, "skills_manager") or coder.skills_manager is None:
io.tool_output("Skills manager is not initialized. Skills may not be configured.")
return format_command_result(io, "import-skill", "Skills manager is not initialized")

from cecli.helpers.extensions.skills_importer import (
add_skill_to_config,
install_skill,
)

root = getattr(coder, "primary_root", None) or getattr(coder, "root", None)
result = install_skill(skill_name, global_install=global_install, root=root)

if not result["ok"]:
io.tool_output(result["message"])
return format_command_result(io, "import-skill", result["message"])

imported_name = result["name"]
include_result = coder.skills_manager.include_skill(imported_name)
config_result = add_skill_to_config(imported_name, root=root)

message = (
f"Imported skill '{imported_name}' from {result['source']} to {result['dest']}.\n\n"
f"{include_result}\n\n"
f"{config_result}"
)

return format_command_result(io, "import-skill", message)

@classmethod
def get_completions(cls, io, coder, args) -> List[str]:
"""Get completion options for import-skill command."""
candidates = ["--global"]

try:
from cecli.helpers.extensions.skills_importer import get_registry_skills

candidates.extend(get_registry_skills())
except Exception:
pass

return candidates

@classmethod
def get_help(cls) -> str:
"""Get help text for the import-skill command."""
help_text = super().get_help()
help_text += "\nUsage:\n"
help_text += (
" /import-skill <skill-name> # Import a skill into the project .cecli/skills\n"
)
help_text += (
" /import-skill --global <skill-name> # Import a skill into ~/.cecli/skills\n"
)
help_text += "\nExamples:\n"
help_text += (
" /import-skill files/docx # Import the docx skill from the community registry\n"
)
help_text += " /import-skill --global pdf # Import the PDF skill globally\n"
help_text += (
"\nSkills are looked up in the cecli community registry first, then on skills.sh.\n"
)
help_text += "The imported skill is added to the current session like /include-skill.\n"
return help_text
86 changes: 86 additions & 0 deletions cecli/commands/insert_queue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""Insert-queue command for CLI-33: inserts a prompt at a specific queue position."""

from typing import List

from cecli.commands.utils.base_command import BaseCommand
from cecli.commands.utils.helpers import format_command_result


class InsertQueueCommand(BaseCommand):
NORM_NAME = "insert-queue"
DESCRIPTION = "Insert a prompt into the queue at a specific position"

@classmethod
async def execute(cls, io, coder, args, **kwargs):
"""Execute the insert-queue command with given parameters.

Args:
io: InputOutput instance
coder: Coder instance (may be None for some commands)
args: Command arguments as string ("<index> <prompt text>")
**kwargs: Additional context

Returns:
Formatted result string
"""
# Sad path: coder.commands is None
if not coder.commands:
return format_command_result(
io,
cls.NORM_NAME,
"",
error="Command system not available. Cannot insert into queue.",
)

# Sad path: missing index or prompt text
parts = (args or "").strip().split(maxsplit=1)
if len(parts) != 2:
return format_command_result(
io,
cls.NORM_NAME,
"",
error="Usage: /insert-queue <index> <prompt text>",
)

# Sad path: non-integer index
try:
index = int(parts[0])
except ValueError:
return format_command_result(
io,
cls.NORM_NAME,
"",
error=f"Invalid index: '{parts[0]}'. Please provide a number.",
)

prompt_text = parts[1].strip()

# Happy path: insert the prompt
try:
item = coder.commands._insert_prompt(prompt_text, index)
io.tool_output(f"Prompt inserted at position {index + 1} (id: {item['id']})")
return f"Successfully executed {cls.NORM_NAME}."
except ValueError as e:
return format_command_result(io, cls.NORM_NAME, "", error=str(e))
except RuntimeError as e:
return format_command_result(io, cls.NORM_NAME, "", error=str(e))

@classmethod
def get_completions(cls, io, coder, args) -> List[str]:
"""Get completion options for insert-queue command."""
return []

@classmethod
def get_help(cls) -> str:
"""Get help text for the insert-queue command."""
help_text = super().get_help()
help_text += "\nUsage:\n"
help_text += " /insert-queue <index> <prompt text> # Insert at a specific position\n"
help_text += "\nDescription:\n"
help_text += " Inserts a prompt into the queue at the given 1-based position.\n"
help_text += " Existing items shift down. Index is clamped to the queue bounds.\n"
help_text += "\nExamples:\n"
help_text += " /insert-queue 1 Review the changes in src/main.py\n"
help_text += " /insert-queue 3 Write unit tests for the new feature\n"
help_text += "\nSee also: /queue, /list-queue, /remove-queue\n"
return help_text
2 changes: 1 addition & 1 deletion cecli/commands/list_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ async def execute(cls, io, coder, args, **kwargs):
# Sad path: coder.commands is None
if not coder.commands:
return format_command_result(
io, cls.NORM_NAME, error="Command system not available. Cannot list queue."
io, cls.NORM_NAME, "", error="Command system not available. Cannot list queue."
)

queue = coder.commands.prompt_queue
Expand Down
14 changes: 9 additions & 5 deletions cecli/commands/queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,19 @@ async def execute(cls, io, coder, args, **kwargs):
# Sad path: coder.commands is None
if not coder.commands:
return format_command_result(
io, cls.NORM_NAME, error="Command system not available. Cannot queue prompts."
io, cls.NORM_NAME, "", error="Command system not available. Cannot queue prompts."
)

# Sad path: no args (empty prompt text)
if not args or not args.strip():
return format_command_result(
io,
cls.NORM_NAME,
"Usage: /queue <prompt text>\n"
"Add a prompt to the queue for processing after current tasks complete.",
"",
error=(
"Usage: /queue <prompt text> - Add a prompt to the queue "
"for processing after current tasks complete."
),
)

prompt_text = args.strip()
Expand All @@ -45,6 +48,7 @@ async def execute(cls, io, coder, args, **kwargs):
return format_command_result(
io,
cls.NORM_NAME,
"",
error=f"Prompt exceeds maximum length of 10000 characters "
f"(got {len(prompt_text)}).",
)
Expand All @@ -56,9 +60,9 @@ async def execute(cls, io, coder, args, **kwargs):
io.tool_output(f"Prompt queued at position {position} (id: {item['id']})")
return f"Successfully executed {cls.NORM_NAME}."
except ValueError as e:
return format_command_result(io, cls.NORM_NAME, error=str(e))
return format_command_result(io, cls.NORM_NAME, "", error=str(e))
except RuntimeError as e:
return format_command_result(io, cls.NORM_NAME, error=str(e))
return format_command_result(io, cls.NORM_NAME, "", error=str(e))

@classmethod
def get_completions(cls, io, coder, args) -> List[str]:
Expand Down
Loading
Loading