* fix(ai_mail): resolve relative mailbox_path bug + archive dead handlers Fix get_user_by_email() and get_all_users() returning relative mailbox_path values from registry instead of absolute paths (causing doubled paths in reply). Added path resolution matching get_current_user() pattern. Archive 7 unused handler files to apps/.archive/ (gitignored): - pending_work.py — planned feature, never wired - lock_utils.py — superseded by inbox_lock.py - data_ops.py — consumer (error_monitor) was archived - config_generator.py, users/load.py, registry/validate.py — scaffolded, never used - trigger/error_handler.py — superseded by trigger branch's event system Added test_user_paths.py (13 tests) covering absolute path resolution. Co-Authored-By: @ai_mail <ai_mail@aipass> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(spawn): seedgo compliance cleanup — 93% to 98% Archive legacy files (dev.local.md, ai_mail.local/, .seed/). Update META Modified dates on 22 files. Update README architecture tree and freshness. Fix 15 Pyright unused warnings. Add introspection no-args gates to 6 modules. Wire json_handler + log_operation to 15 operational files. Add seedgo bypass for 5 pure data files and log_structure. Remove deprecated dev.local.md from builder template. Co-Authored-By: @spawn <spawn@aipass> Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(system): session 34 — maintenance day, multi-branch work System changes: - setup.sh: symlink install replaces .bashrc PATH export for drone/seedgo - .claude/settings.json: deny list moved to per-branch settings.local.json - .gitignore: updated - CLAUDE.md culture doc: stale refs fixed (Cortex→spawn, id.json→passport.json) Branch work (accumulated from 15-branch rounds): - daemon: stale term cleanup, plugin removals, json handler modernization - drone: module refactor (discovery, registry, router, resolver, config) - commons: 50+ file cleanup (imports, handlers, modules) - flow: template loader, plan type system, command parser Per-branch settings.local.json: reworked deny lists — allow PR workflow, deny destructive git ops (reset, rebase, merge, clean, force push, rm -rf). Fixed pattern syntax from :* to * glob. Co-Authored-By: @devpulse <devpulse@aipass> --------- Co-authored-by: @ai_mail <ai_mail@aipass> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: @spawn <spawn@aipass> Co-authored-by: @devpulse <devpulse@aipass>
187 lines
5.7 KiB
Python
187 lines
5.7 KiB
Python
# =================== AIPass ====================
|
|
# Name: command_parser.py
|
|
# Description: Command Argument Parser
|
|
# Version: 0.2.0
|
|
# Created: 2025-11-15
|
|
# Modified: 2025-11-15
|
|
# =============================================
|
|
|
|
"""
|
|
Command Argument Parser
|
|
|
|
Parses command-line arguments for plan operations.
|
|
"""
|
|
|
|
from typing import List, Tuple
|
|
|
|
|
|
def parse_create_plan_args(args: List[str]) -> Tuple[str | None, str, str]:
|
|
"""
|
|
Parse arguments for plan creation
|
|
|
|
The third argument is treated as a plan type identifier and mapped
|
|
to a plan_type_key understood by the plan_types plugin system:
|
|
|
|
- No 3rd arg or "default" -> "flow_plans" (FPLAN with default template)
|
|
- "master" -> "master" (FPLAN with master template)
|
|
- "dplan" -> "dev_plans" (DPLAN with default template)
|
|
- Any other value -> passed through for plan_type_loader lookup
|
|
|
|
Args:
|
|
args: List of command arguments
|
|
|
|
Returns:
|
|
Tuple of (location, subject, plan_type_key)
|
|
- location: First arg or None
|
|
- subject: Second arg or empty string
|
|
- plan_type_key: Resolved plan type key for the plugin system
|
|
|
|
Examples:
|
|
>>> parse_create_plan_args(["@flow", "My task", "master"])
|
|
("@flow", "My task", "master")
|
|
|
|
>>> parse_create_plan_args(["@flow", "My task", "dplan"])
|
|
("@flow", "My task", "dev_plans")
|
|
|
|
>>> parse_create_plan_args([])
|
|
(None, "", "flow_plans")
|
|
|
|
>>> parse_create_plan_args(["@flow"])
|
|
("@flow", "", "flow_plans")
|
|
"""
|
|
location = args[0] if len(args) > 0 else None
|
|
subject = args[1] if len(args) > 1 else ""
|
|
raw_type = args[2] if len(args) > 2 else "default"
|
|
|
|
# Map raw type argument to plan_type_key
|
|
_TYPE_MAP = {
|
|
"default": "flow_plans",
|
|
"dplan": "dev_plans",
|
|
}
|
|
plan_type_key = _TYPE_MAP.get(raw_type.lower(), raw_type)
|
|
|
|
return location, subject, plan_type_key
|
|
|
|
|
|
def parse_delete_command_args(args: List[str]) -> Tuple[str | None, bool, str | None]:
|
|
"""
|
|
Parse arguments for delete command (DEPRECATED - use parse_close_command_args)
|
|
|
|
Args:
|
|
args: Command arguments
|
|
|
|
Returns:
|
|
Tuple of (plan_num, confirm, error_message)
|
|
- plan_num: Plan number from first arg, or None if missing
|
|
- confirm: False if --yes or -y flag present, True otherwise
|
|
- error_message: None if valid, error string if plan_num missing
|
|
|
|
Examples:
|
|
>>> parse_delete_command_args(["42"])
|
|
("42", True, None)
|
|
|
|
>>> parse_delete_command_args(["42", "--yes"])
|
|
("42", False, None)
|
|
|
|
>>> parse_delete_command_args([])
|
|
(None, True, "Plan number required")
|
|
"""
|
|
if len(args) < 1:
|
|
return None, True, "Plan number required"
|
|
|
|
plan_num = args[0]
|
|
confirm = '--yes' not in args and '-y' not in args
|
|
|
|
return plan_num, confirm, None
|
|
|
|
|
|
def parse_close_command_args(args: List[str]) -> Tuple[str | None, bool, bool, str | None]:
|
|
"""
|
|
Parse arguments for close command
|
|
|
|
Auto-confirms by default (running 'close' IS the intent).
|
|
Use --confirm or --interactive to explicitly request a confirmation prompt.
|
|
--yes/-y kept for backwards compatibility (now redundant, already auto-confirms).
|
|
|
|
Args:
|
|
args: Command arguments
|
|
|
|
Returns:
|
|
Tuple of (plan_num, confirm, all_plans, error_message)
|
|
- plan_num: Plan number from first arg, or None if --all or missing
|
|
- confirm: True only if --confirm or --interactive flag present, False otherwise
|
|
- all_plans: True if --all flag present, False otherwise
|
|
- error_message: None if valid, error string if invalid args
|
|
|
|
Examples:
|
|
>>> parse_close_command_args(["42"])
|
|
("42", False, False, None)
|
|
|
|
>>> parse_close_command_args(["42", "--yes"])
|
|
("42", False, False, None)
|
|
|
|
>>> parse_close_command_args(["42", "--confirm"])
|
|
("42", True, False, None)
|
|
|
|
>>> parse_close_command_args(["42", "--interactive"])
|
|
("42", True, False, None)
|
|
|
|
>>> parse_close_command_args(["--all"])
|
|
(None, False, True, None)
|
|
|
|
>>> parse_close_command_args(["--all", "--confirm"])
|
|
(None, True, True, None)
|
|
|
|
>>> parse_close_command_args([])
|
|
(None, False, False, "Plan number or --all required")
|
|
"""
|
|
# Check for --all flag
|
|
all_plans = '--all' in args
|
|
|
|
# Default: auto-confirm (confirm=False means no prompt)
|
|
# --confirm or --interactive explicitly requests a prompt
|
|
# --yes/-y kept for backwards compat (redundant, already auto-confirms)
|
|
confirm = '--confirm' in args or '--interactive' in args
|
|
|
|
# If --all, plan_num is None
|
|
if all_plans:
|
|
return None, confirm, True, None
|
|
|
|
# Otherwise, need plan number
|
|
# Filter out flag args to find the plan number
|
|
non_flag_args = [a for a in args if not a.startswith('--') and a not in ('-y',)]
|
|
if not non_flag_args:
|
|
return None, False, False, "Plan number or --all required"
|
|
|
|
plan_num = non_flag_args[0]
|
|
return plan_num, confirm, False, None
|
|
|
|
|
|
def parse_restore_command_args(args: List[str]) -> Tuple[str | None, str | None]:
|
|
"""
|
|
Parse arguments for restore command
|
|
|
|
Args:
|
|
args: Command arguments
|
|
|
|
Returns:
|
|
Tuple of (plan_num, error_message)
|
|
- plan_num: Plan number from first arg, or None if missing
|
|
- error_message: None if valid, error string if plan_num missing
|
|
|
|
Examples:
|
|
>>> parse_restore_command_args(["42"])
|
|
("42", None)
|
|
|
|
>>> parse_restore_command_args(["0034"])
|
|
("0034", None)
|
|
|
|
>>> parse_restore_command_args([])
|
|
(None, "Plan number required")
|
|
"""
|
|
if len(args) < 1:
|
|
return None, "Plan number required"
|
|
|
|
plan_num = args[0]
|
|
return plan_num, None
|