micro-models-agent 1.7.0 → 2.0.0

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/dist/main.js CHANGED
@@ -2804,6 +2804,10 @@ Fix the error and re-edit the file (a clean write clears the failure), or mark t
2804
2804
  "cli.list_sessions": "List all sessions",
2805
2805
  "cli.show_details": "Show session details",
2806
2806
  "cli.delete_session": "Delete a session",
2807
+ "cli.export_session": "Export a session to a file (md, json, or jsonl)",
2808
+ "cli.export_format": "Output format: md|json|jsonl (default md)",
2809
+ "cli.export_out": "Output path ('-' for stdout)",
2810
+ "cli.export_no_redact": "Do not redact secrets",
2807
2811
  "cli.first_run": "First run detected. Running setup wizard...",
2808
2812
  "cli.first_run_oneshot": "No configuration found — running with defaults. Run `mma` (no arguments) once to set up the wizard.",
2809
2813
  "cli.setup_saved_restart": "Settings saved. Restarting with the new configuration...",
@@ -2872,20 +2876,21 @@ Available commands:`,
2872
2876
  "repl.exit_usage": "Usage: /exit",
2873
2877
  "repl.clear": "Clear the screen",
2874
2878
  "repl.clear_usage": "Usage: /clear",
2879
+ "repl.clear_hint": "Screen cleared. To start a fresh session and context: /new",
2875
2880
  "repl.run": "Run a prompt through the agent",
2876
2881
  "repl.run_usage": "Usage: /run <prompt>",
2877
- "repl.config": "Show current configuration",
2878
- "repl.config_usage": "Usage: /config",
2879
- "repl.reasoning": "Toggle showing model reasoning/thinking",
2880
- "repl.reasoning_usage": "Usage: /reasoning [auto|none|low|medium|high|max]",
2882
+ "repl.config": "Show or change settings (get / set / reset)",
2883
+ "repl.config_usage": "Usage: /config [<key> [value]] | /config reset <key> | /config reset --all [--yes] | /config migrate",
2884
+ "repl.reasoning": "Show reasoning status, toggle display, or set effort level",
2885
+ "repl.reasoning_usage": "Usage: /reasoning [show|hide|level <auto|default|none|low|medium|high|max>]",
2881
2886
  "repl.reasoning_level_set": "Reasoning level set to: {level}",
2882
2887
  "repl.reasoning_invalid_level": "Invalid level '{level}'. Valid: {valid}",
2883
- "repl.verbose": "Chat verbosity: quiet, normal, or verbose",
2888
+ "repl.verbose": "Chat verbosity (quiet, normal, verbose)",
2884
2889
  "repl.verbose_usage": "Usage: /verbose [quiet|normal|verbose]",
2885
2890
  "repl.verbose_set": "Chat verbosity: {level}",
2886
2891
  "repl.verbose_invalid_level": "Invalid level '{level}'. Valid: {valid}",
2887
2892
  "repl.last_action_none": "No recent action to show.",
2888
- "repl.status": "Show agent status",
2893
+ "repl.status": "Show a compact status line",
2889
2894
  "repl.status_usage": "Usage: /status",
2890
2895
  "repl.plugins": "List loaded plugins",
2891
2896
  "repl.plugins_usage": "Usage: /plugins [--all]",
@@ -2925,11 +2930,13 @@ Available commands:`,
2925
2930
  "repl.context": "Context:",
2926
2931
  "repl.sysprompt_label": "System prompt:",
2927
2932
  "repl.sysprompt_size": "{used} / {budget} tokens",
2928
- "repl.sysprompt_desc": "Show system prompt",
2933
+ "repl.sysprompt_desc": "System prompt size and blocks (use --full for the text)",
2934
+ "repl.sysprompt_usage": "Usage: /sysprompt [--full]",
2935
+ "repl.sysprompt_full_hint": "Full prompt text hidden — run /sysprompt --full to print it.",
2929
2936
  "repl.sysprompt_tokens": "System prompt ({count} tokens):",
2930
2937
  "repl.excluded_blocks": `
2931
2938
  Excluded blocks: {count}`,
2932
- "repl.context_usage": "Usage: /context [<size> | system <fraction> | reserve <fraction>] (min 1024; fractions 0.05–0.9)",
2939
+ "repl.context_usage": "Usage: /context [<size, min 1024> | system <share> | reserve <share>] (share 0.05–0.9 or e.g. 10%; system+reserve ≤ 0.95)",
2933
2940
  "repl.msgs": "msgs",
2934
2941
  "repl.max_iters": "Max iters:",
2935
2942
  "repl.stuck_thresh": "Stuck thresh:",
@@ -2973,13 +2980,105 @@ Excluded blocks: {count}`,
2973
2980
  "repl.provider_list": "List configured providers or hot-swap the active one",
2974
2981
  "repl.provider_current": "Current provider",
2975
2982
  "repl.provider_set": "Provider set to: {name}",
2976
- "repl.provider_usage": "/provider list - show entries (* = active, prio = fallback order) | /provider use <name> - switch without restart | /provider add <name> [--url <url>] [--key <key>] [--priority <n>] [--context-window <n>] [--rpm <n>] [--parallel <n>] - add to config",
2983
+ "repl.provider_usage": `Usage: /provider list | /provider use <name> | /provider add <name> [flags]
2984
+ --url <url> base API URL (fallback: known presets)
2985
+ --key <key> API key
2986
+ --priority <n> fallback order; lower = tried first
2987
+ --context-window <n> per-provider context window (tokens)
2988
+ --rpm <n> max requests/minute (default 60)
2989
+ --parallel <n> max parallel tasks (default 1)`,
2977
2990
  "repl.provider_add_missing_value": "Missing value for {flag}",
2991
+ "repl.provider_add_invalid_number": "Invalid number for {flag}: '{value}'",
2978
2992
  "repl.provider_switch_hint": "Switch to it with: /provider use {name}",
2993
+ "repl.provider_flag_url": "Base API URL (fallback: known presets)",
2994
+ "repl.provider_flag_key": "API key",
2995
+ "repl.provider_flag_priority": "Fallback order; lower = tried first",
2996
+ "repl.provider_flag_context_window": "Per-provider context window (tokens)",
2997
+ "repl.provider_flag_rpm": "Max requests per minute (default 60)",
2998
+ "repl.provider_flag_parallel": "Max parallel tasks (default 1)",
2979
2999
  "repl.model_list": "List models of the active provider or switch the model",
2980
3000
  "repl.model_current": "Current model",
2981
3001
  "repl.model_set": "Model set to: {name}",
2982
- "repl.model_usage": "/model list - fetch models from the active provider | /model use <name> - switch model",
3002
+ "repl.model_usage": "Usage: /model list | /model use <name>",
3003
+ "repl.unknown_sub": "Unknown subcommand '{sub}' for /{cmd}. See usage below.",
3004
+ "repl.help_unknown": "Unknown command '/{name}'",
3005
+ "repl.help_aliases": "Aliases: {names}",
3006
+ "repl.help_examples": "Examples:",
3007
+ "repl.export": "Export a session to a file",
3008
+ "repl.export_usage": "Usage: /export [<id|name>] [--format md|json|jsonl] [--out <path>] [--no-redact]",
3009
+ "config.header": "Managed settings",
3010
+ "config.col_setting": "Setting",
3011
+ "config.col_value": "Value",
3012
+ "config.col_domain": "Domain",
3013
+ "config.col_change": "Change with",
3014
+ "config.session_line": "Session: {name} ({id}) — {count} messages",
3015
+ "config.usage_hint": "Get: /config <key> · Set: /config <key> <value> · Reset: /config reset <key>",
3016
+ "config.saved": "saved · reset: /config reset {key}",
3017
+ "config.read_only_hint": "read-only",
3018
+ "config.read_only": "'{key}' is read-only",
3019
+ "config.unknown_key": "Unknown key '{key}'. {suggestion}",
3020
+ "config.suggest": "Did you mean '{name}'?",
3021
+ "config.valid_keys": "Valid keys: {keys}",
3022
+ "config.invalid_value": "Invalid value for {key}. {hint}",
3023
+ "config.range": "Value out of range for {key}",
3024
+ "config.combined": "system + reserve must stay below 0.95",
3025
+ "config.hint_string": "Expected a non-empty string",
3026
+ "config.hint_enum": "Allowed: {values}",
3027
+ "config.hint_bool": "Expected on/off",
3028
+ "config.hint_share": "Expected 0.05–0.9 or a percentage (e.g. 10%)",
3029
+ "config.hint_int": "Expected an integer ≥ {min}",
3030
+ "config.reset_ok": "{key} restored to session-start value: {value} · saved",
3031
+ "config.reset_unchanged": "{key} already at session value",
3032
+ "config.reset_none": "No settings changed this session",
3033
+ "config.reset_all_confirm": "Reset {count} changed setting(s) to session-start values? [y/N] ",
3034
+ "config.reset_all_done": "Restored {count} setting(s) · saved",
3035
+ "config.reset_all_needs_yes": "Refusing to reset without confirmation in non-interactive mode; pass --yes",
3036
+ "config.reset_cancelled": "Reset cancelled",
3037
+ "config.reset_usage": "Usage: /config reset <key> | /config reset --all [--yes]",
3038
+ "config.alias_label": "alias of",
3039
+ "config.group_label": "group",
3040
+ "reasoning.status": "Reasoning: display {display} · effort {level} {auto}",
3041
+ "reasoning.on": "on",
3042
+ "reasoning.off": "off",
3043
+ "reasoning.auto_on": "(auto policy)",
3044
+ "reasoning.auto_off": "(auto policy off)",
3045
+ "reasoning.auto_off_hint": "Auto policy off. Restore with: /config reset reasoning.mode",
3046
+ "reasoning.display_set": "Reasoning display: {state}",
3047
+ "reasoning.unknown_sub": "Unknown argument '{sub}'.",
3048
+ "reasoning.sub_show": "Show reasoning content",
3049
+ "reasoning.sub_hide": "Hide reasoning content",
3050
+ "reasoning.sub_level": "Set reasoning effort level",
3051
+ "verbose.status": "Verbosity: {level}",
3052
+ "verbose.sub_quiet": "One line per action",
3053
+ "verbose.sub_normal": "Add short result summaries",
3054
+ "verbose.sub_verbose": "Full per-action detail",
3055
+ "context.unknown_arg": "Unknown argument '{arg}'.",
3056
+ "context.sub_system": "System-prompt share",
3057
+ "context.sub_reserve": "Response-reserve share",
3058
+ "model.not_in_list": "Note: '{name}' is not in the known model list",
3059
+ "model.sub_list": "List models of the active provider",
3060
+ "model.sub_use": "Switch model",
3061
+ "provider.sub_list": "List configured providers",
3062
+ "provider.sub_use": "Switch active provider",
3063
+ "provider.sub_add": "Add a provider",
3064
+ "map.sub_summary": "Show the project map summary",
3065
+ "map.sub_refresh": "Rebuild the project index",
3066
+ "map.sub_find": "Search the project map",
3067
+ "lsp.sub_status": "Show LSP server status",
3068
+ "lsp.sub_restart": "Reset disabled servers",
3069
+ "lsp.sub_check": "Run an LSP check on a path",
3070
+ "skill.sub_list": "List available skills",
3071
+ "skill.sub_loaded": "List loaded skills",
3072
+ "skill.sub_load": "Load a skill",
3073
+ "skill.sub_unload": "Unload a skill",
3074
+ "skill.sub_search": "Search skills",
3075
+ "export.written": "Exported to {path}",
3076
+ "export.redacted": "secrets redacted (--no-redact to disable)",
3077
+ "export.raw": "secrets NOT redacted",
3078
+ "export.empty": "session has no messages — nothing exported",
3079
+ "export.invalid_format": "Unknown format '{format}'. Use md|json|jsonl",
3080
+ "export.missing_value": "Missing value for {flag}",
3081
+ "export.write_failed": "Failed to write export: {error}",
2983
3082
  "repl.group.general": "General",
2984
3083
  "repl.group.agent": "Agent",
2985
3084
  "repl.group.session": "Sessions",
@@ -3677,6 +3776,10 @@ var init_ru = __esm(() => {
3677
3776
  "cli.list_sessions": "Список всех сессий",
3678
3777
  "cli.show_details": "Показать детали сессии",
3679
3778
  "cli.delete_session": "Удалить сессию",
3779
+ "cli.export_session": "Экспортировать сессию в файл (md, json или jsonl)",
3780
+ "cli.export_format": "Формат вывода: md|json|jsonl (по умолчанию md)",
3781
+ "cli.export_out": "Путь вывода ('-' для stdout)",
3782
+ "cli.export_no_redact": "Не скрывать секреты",
3680
3783
  "cli.first_run": "Первый запуск. Запускаем мастер настройки...",
3681
3784
  "cli.first_run_oneshot": "Конфигурация не найдена — запуск с настройками по умолчанию. Запустите `mma` без аргументов один раз для настройки.",
3682
3785
  "cli.setup_saved_restart": "Настройки сохранены. Перезапуск с новой конфигурацией...",
@@ -3745,20 +3848,21 @@ var init_ru = __esm(() => {
3745
3848
  "repl.exit_usage": "Использование: /exit",
3746
3849
  "repl.clear": "Очистить экран",
3747
3850
  "repl.clear_usage": "Использование: /clear",
3851
+ "repl.clear_hint": "Экран очищен. Новая сессия и контекст: /new",
3748
3852
  "repl.run": "Выполнить запрос через агента",
3749
3853
  "repl.run_usage": "Использование: /run <запрос>",
3750
- "repl.config": "Показать текущую конфигурацию",
3751
- "repl.config_usage": "Использование: /config",
3752
- "repl.reasoning": "Переключить показ рассуждений модели",
3753
- "repl.reasoning_usage": "Использование: /reasoning [auto|none|low|medium|high|max]",
3854
+ "repl.config": "Показать или изменить настройки (get / set / reset)",
3855
+ "repl.config_usage": "Использование: /config [<ключ> [значение]] | /config reset <ключ> | /config reset --all [--yes] | /config migrate",
3856
+ "repl.reasoning": "Показать статус рассуждений, переключить показ или уровень",
3857
+ "repl.reasoning_usage": "Использование: /reasoning [show|hide|level <auto|default|none|low|medium|high|max>]",
3754
3858
  "repl.reasoning_level_set": "Уровень рассуждений установлен: {level}",
3755
3859
  "repl.reasoning_invalid_level": "Неверный уровень '{level}'. Допустимые: {valid}",
3756
- "repl.verbose": "Подробность вывода: quiet, normal или verbose",
3860
+ "repl.verbose": "Подробность вывода (quiet, normal, verbose)",
3757
3861
  "repl.verbose_usage": "Использование: /verbose [quiet|normal|verbose]",
3758
3862
  "repl.verbose_set": "Подробность вывода: {level}",
3759
3863
  "repl.verbose_invalid_level": "Неверный уровень '{level}'. Допустимые: {valid}",
3760
3864
  "repl.last_action_none": "Нет недавнего действия для показа.",
3761
- "repl.status": "Показать статус агента",
3865
+ "repl.status": "Показать компактную строку статуса",
3762
3866
  "repl.status_usage": "Использование: /status",
3763
3867
  "repl.plugins": "Список загруженных плагинов",
3764
3868
  "repl.plugins_usage": "Использование: /plugins [--all]",
@@ -3798,11 +3902,13 @@ var init_ru = __esm(() => {
3798
3902
  "repl.context": "Контекст:",
3799
3903
  "repl.sysprompt_label": "Системный промпт:",
3800
3904
  "repl.sysprompt_size": "{used} / {budget} токенов",
3801
- "repl.sysprompt_desc": "Показать системный промпт",
3905
+ "repl.sysprompt_desc": "Размер системного промпта и блоки (текст — через --full)",
3906
+ "repl.sysprompt_usage": "Использование: /sysprompt [--full]",
3907
+ "repl.sysprompt_full_hint": "Полный текст промпта скрыт — выполните /sysprompt --full.",
3802
3908
  "repl.sysprompt_tokens": "Системный промпт ({count} токенов):",
3803
3909
  "repl.excluded_blocks": `
3804
3910
  Исключённые блоки: {count}`,
3805
- "repl.context_usage": "Использование: /context [<размер> | system <доля> | reserve <доля>] (мин 1024; доли 0.05–0.9)",
3911
+ "repl.context_usage": "Использование: /context [<размер, мин 1024> | system <доля> | reserve <доля>] (доля 0.05–0.9 или напр. 10%; system+reserve ≤ 0.95)",
3806
3912
  "repl.msgs": "сообщ.",
3807
3913
  "repl.max_iters": "Макс итераций:",
3808
3914
  "repl.stuck_thresh": "Порог зависания:",
@@ -3846,13 +3952,105 @@ var init_ru = __esm(() => {
3846
3952
  "repl.provider_list": "Список настроенных провайдеров или горячая смена активного",
3847
3953
  "repl.provider_current": "Текущий провайдер",
3848
3954
  "repl.provider_set": "Провайдер установлен: {name}",
3849
- "repl.provider_usage": "/provider list — записи (* = активный, prio = порядок fallback) | /provider use <имя> — смена без перезапуска | /provider add <имя> [--url <url>] [--key <ключ>] [--priority <n>] [--context-window <n>] [--rpm <n>] [--parallel <n>] — добавить в конфиг",
3955
+ "repl.provider_usage": `Использование: /provider list | /provider use <имя> | /provider add <имя> [флаги]
3956
+ --url <url> базовый URL API (иначе — из пресетов)
3957
+ --key <ключ> API-ключ
3958
+ --priority <n> порядок fallback; меньше = раньше
3959
+ --context-window <n> окно контекста провайдера (токены)
3960
+ --rpm <n> запросов/мин (по умолчанию 60)
3961
+ --parallel <n> параллельных задач (по умолчанию 1)`,
3850
3962
  "repl.provider_add_missing_value": "Нет значения для {flag}",
3963
+ "repl.provider_add_invalid_number": "Неверное число для {flag}: '{value}'",
3851
3964
  "repl.provider_switch_hint": "Переключитесь на него: /provider use {name}",
3965
+ "repl.provider_flag_url": "Базовый URL API (иначе — из пресетов)",
3966
+ "repl.provider_flag_key": "API-ключ",
3967
+ "repl.provider_flag_priority": "Порядок fallback; меньше = раньше",
3968
+ "repl.provider_flag_context_window": "Окно контекста провайдера (токены)",
3969
+ "repl.provider_flag_rpm": "Запросов в минуту (по умолчанию 60)",
3970
+ "repl.provider_flag_parallel": "Параллельных задач (по умолчанию 1)",
3852
3971
  "repl.model_list": "Список моделей активного провайдера или смена модели",
3853
3972
  "repl.model_current": "Текущая модель",
3854
3973
  "repl.model_set": "Модель установлена: {name}",
3855
- "repl.model_usage": "/model list — получить модели активного провайдера | /model use <имя> — сменить модель",
3974
+ "repl.model_usage": "Использование: /model list | /model use <имя>",
3975
+ "repl.unknown_sub": "Неизвестная подкоманда '{sub}' для /{cmd}. См. использование ниже.",
3976
+ "repl.help_unknown": "Неизвестная команда '/{name}'",
3977
+ "repl.help_aliases": "Алиасы: {names}",
3978
+ "repl.help_examples": "Примеры:",
3979
+ "repl.export": "Экспортировать сессию в файл",
3980
+ "repl.export_usage": "Использование: /export [<id|имя>] [--format md|json|jsonl] [--out <путь>] [--no-redact]",
3981
+ "config.header": "Управляемые настройки",
3982
+ "config.col_setting": "Настройка",
3983
+ "config.col_value": "Значение",
3984
+ "config.col_domain": "Домен",
3985
+ "config.col_change": "Как менять",
3986
+ "config.session_line": "Сессия: {name} ({id}) — {count} сообщений",
3987
+ "config.usage_hint": "Чтение: /config <ключ> · Запись: /config <ключ> <значение> · Сброс: /config reset <ключ>",
3988
+ "config.saved": "сохранено · сброс: /config reset {key}",
3989
+ "config.read_only_hint": "только чтение",
3990
+ "config.read_only": "'{key}' — только чтение",
3991
+ "config.unknown_key": "Неизвестный ключ '{key}'. {suggestion}",
3992
+ "config.suggest": "Возможно, вы имели в виду '{name}'?",
3993
+ "config.valid_keys": "Допустимые ключи: {keys}",
3994
+ "config.invalid_value": "Неверное значение для {key}. {hint}",
3995
+ "config.range": "Значение вне диапазона для {key}",
3996
+ "config.combined": "system + reserve должны оставаться ниже 0.95",
3997
+ "config.hint_string": "Ожидается непустая строка",
3998
+ "config.hint_enum": "Допустимые: {values}",
3999
+ "config.hint_bool": "Ожидается on/off",
4000
+ "config.hint_share": "Ожидается 0.05–0.9 или процент (напр. 10%)",
4001
+ "config.hint_int": "Ожидается целое ≥ {min}",
4002
+ "config.reset_ok": "{key} восстановлен к значению на старте сессии: {value} · сохранено",
4003
+ "config.reset_unchanged": "{key} уже соответствует значению сессии",
4004
+ "config.reset_none": "В этой сессии настройки не менялись",
4005
+ "config.reset_all_confirm": "Сбросить {count} изменённых настроек к значениям на старте сессии? [y/N] ",
4006
+ "config.reset_all_done": "Восстановлено настроек: {count} · сохранено",
4007
+ "config.reset_all_needs_yes": "Отказ от сброса без подтверждения в неинтерактивном режиме; укажите --yes",
4008
+ "config.reset_cancelled": "Сброс отменён",
4009
+ "config.reset_usage": "Использование: /config reset <ключ> | /config reset --all [--yes]",
4010
+ "config.alias_label": "алиас",
4011
+ "config.group_label": "группа",
4012
+ "reasoning.status": "Рассуждения: показ {display} · усилие {level} {auto}",
4013
+ "reasoning.on": "вкл",
4014
+ "reasoning.off": "выкл",
4015
+ "reasoning.auto_on": "(авто-политика)",
4016
+ "reasoning.auto_off": "(авто-политика выключена)",
4017
+ "reasoning.auto_off_hint": "Авто-политика выключена. Вернуть: /config reset reasoning.mode",
4018
+ "reasoning.display_set": "Показ рассуждений: {state}",
4019
+ "reasoning.unknown_sub": "Неизвестный аргумент '{sub}'.",
4020
+ "reasoning.sub_show": "Показывать рассуждения",
4021
+ "reasoning.sub_hide": "Скрыть рассуждения",
4022
+ "reasoning.sub_level": "Установить уровень рассуждений",
4023
+ "verbose.status": "Подробность: {level}",
4024
+ "verbose.sub_quiet": "Одна строка на действие",
4025
+ "verbose.sub_normal": "Плюс короткие сводки результатов",
4026
+ "verbose.sub_verbose": "Полная деталь по действиям",
4027
+ "context.unknown_arg": "Неизвестный аргумент '{arg}'.",
4028
+ "context.sub_system": "Доля системного промпта",
4029
+ "context.sub_reserve": "Доля резерва ответа",
4030
+ "model.not_in_list": "Примечание: '{name}' нет в списке известных моделей",
4031
+ "model.sub_list": "Список моделей активного провайдера",
4032
+ "model.sub_use": "Сменить модель",
4033
+ "provider.sub_list": "Список настроенных провайдеров",
4034
+ "provider.sub_use": "Сменить активного провайдера",
4035
+ "provider.sub_add": "Добавить провайдера",
4036
+ "map.sub_summary": "Показать сводку карты проекта",
4037
+ "map.sub_refresh": "Перестроить индекс проекта",
4038
+ "map.sub_find": "Поиск по карте проекта",
4039
+ "lsp.sub_status": "Статус LSP-серверов",
4040
+ "lsp.sub_restart": "Сбросить отключённые серверы",
4041
+ "lsp.sub_check": "Запустить LSP-проверку пути",
4042
+ "skill.sub_list": "Список доступных скиллов",
4043
+ "skill.sub_loaded": "Список загруженных скиллов",
4044
+ "skill.sub_load": "Загрузить скилл",
4045
+ "skill.sub_unload": "Выгрузить скилл",
4046
+ "skill.sub_search": "Поиск скиллов",
4047
+ "export.written": "Экспортировано в {path}",
4048
+ "export.redacted": "секреты скрыты (--no-redact чтобы отключить)",
4049
+ "export.raw": "секреты НЕ скрыты",
4050
+ "export.empty": "в сессии нет сообщений — экспорт не создан",
4051
+ "export.invalid_format": "Неизвестный формат '{format}'. Используйте md|json|jsonl",
4052
+ "export.missing_value": "Нет значения для {flag}",
4053
+ "export.write_failed": "Не удалось записать экспорт: {error}",
3856
4054
  "repl.reload": "Перезагрузить агента с текущим конфигом",
3857
4055
  "repl.reload_usage": "Использование: /reload",
3858
4056
  "repl.reloading": "Перезагрузка агента...",
@@ -6606,7 +6804,7 @@ class OpenAICompatProvider {
6606
6804
  }
6607
6805
  }
6608
6806
  async* streamOnce(messages, tools, signal, options, onEmit, idleTimeoutMs) {
6609
- const maxTokens = options?.maxTokens ?? this.config.maxCompletionTokens ?? 4096;
6807
+ const maxTokens = options?.maxTokens ?? this.config.maxCompletionTokens ?? DEFAULT_MAX_COMPLETION_TOKENS;
6610
6808
  const body = buildRequestBody({
6611
6809
  model: this.model,
6612
6810
  messages,
@@ -6872,7 +7070,7 @@ class OpenAICompatProvider {
6872
7070
  };
6873
7071
  }
6874
7072
  async doNonStreaming(messages, tools, signal, options) {
6875
- const maxTokens = options?.maxTokens ?? this.config.maxCompletionTokens ?? 4096;
7073
+ const maxTokens = options?.maxTokens ?? this.config.maxCompletionTokens ?? DEFAULT_MAX_COMPLETION_TOKENS;
6876
7074
  const body = buildRequestBody({
6877
7075
  model: this.model,
6878
7076
  messages,
@@ -7048,7 +7246,7 @@ class OpenAICompatProvider {
7048
7246
  });
7049
7247
  }
7050
7248
  }
7051
- var REQUEST_TIMEOUT_MS = 120000, MAX_RATE_WAIT_MS = 30000, cachedUserAgent = null;
7249
+ var REQUEST_TIMEOUT_MS = 120000, MAX_RATE_WAIT_MS = 30000, DEFAULT_MAX_COMPLETION_TOKENS = 8192, cachedUserAgent = null;
7052
7250
  var init_openai_compat = __esm(() => {
7053
7251
  init_token_counter();
7054
7252
  init_i18n();
@@ -24564,7 +24762,7 @@ import {
24564
24762
  appendFileSync as appendFileSync6
24565
24763
  } from "fs";
24566
24764
  import { join as join34 } from "path";
24567
- import { gzipSync } from "zlib";
24765
+ import { gzipSync, gunzipSync } from "zlib";
24568
24766
 
24569
24767
  class SessionStore {
24570
24768
  baseDir;
@@ -24700,6 +24898,24 @@ class SessionStore {
24700
24898
  return [];
24701
24899
  }
24702
24900
  }
24901
+ loadRotatedHistory(id) {
24902
+ const gzPath = join34(this.baseDir, `${id}.jsonl.gz`);
24903
+ if (!existsSync41(gzPath))
24904
+ return [];
24905
+ try {
24906
+ const content = gunzipSync(readFileSync25(gzPath)).toString("utf-8");
24907
+ return content.split(`
24908
+ `).filter(Boolean).map((line) => {
24909
+ try {
24910
+ return JSON.parse(line);
24911
+ } catch {
24912
+ return null;
24913
+ }
24914
+ }).filter((m) => m !== null);
24915
+ } catch {
24916
+ return [];
24917
+ }
24918
+ }
24703
24919
  appendSessionLog(id, entry) {
24704
24920
  const dir = this.sessionDir(id);
24705
24921
  mkdirSync18(dir, { recursive: true, mode: 448 });
@@ -24896,6 +25112,12 @@ class SessionManager {
24896
25112
  return [];
24897
25113
  return this.store.loadHistory(this.activeId);
24898
25114
  }
25115
+ getHistory(id) {
25116
+ const live = this.store.loadHistory(id);
25117
+ if (live.length > 0)
25118
+ return live;
25119
+ return this.store.loadRotatedHistory(id);
25120
+ }
24899
25121
  getSessionContext() {
24900
25122
  if (!this.activeId)
24901
25123
  return;
@@ -29761,6 +29983,87 @@ var init_setup_order = __esm(() => {
29761
29983
  ];
29762
29984
  });
29763
29985
 
29986
+ // src/modules/session/export.ts
29987
+ function roleHeading(role) {
29988
+ switch (role) {
29989
+ case "user":
29990
+ return "User";
29991
+ case "assistant":
29992
+ return "Assistant";
29993
+ case "tool":
29994
+ return "Tool";
29995
+ case "system":
29996
+ return "System";
29997
+ default:
29998
+ return role;
29999
+ }
30000
+ }
30001
+ function renderSessionMarkdown(meta, messages) {
30002
+ const lines = [];
30003
+ const name = meta?.name ?? "session";
30004
+ const id = meta?.id ?? "unknown";
30005
+ lines.push(`# ${name} (${id})`);
30006
+ lines.push("");
30007
+ if (meta) {
30008
+ lines.push(`- Model: ${meta.model}`);
30009
+ lines.push(`- Created: ${meta.createdAt}`);
30010
+ lines.push(`- Updated: ${meta.updatedAt}`);
30011
+ lines.push(`- Messages: ${meta.messageCount}`);
30012
+ if (meta.projectDir)
30013
+ lines.push(`- Project: ${meta.projectDir}`);
30014
+ }
30015
+ lines.push("");
30016
+ lines.push("---");
30017
+ lines.push("");
30018
+ for (const msg of messages) {
30019
+ const heading = roleHeading(msg.role);
30020
+ const nameSuffix = msg.name ? ` (${msg.name})` : "";
30021
+ lines.push(`## ${heading}${nameSuffix}`);
30022
+ lines.push("");
30023
+ const text = getMessageText(msg.content);
30024
+ lines.push(text.length > 0 ? text : "_(empty)_");
30025
+ lines.push("");
30026
+ if (Array.isArray(msg.tool_calls)) {
30027
+ for (const tc of msg.tool_calls) {
30028
+ lines.push(`- tool_call: \`${tc.function.name}\` ${tc.function.arguments}`);
30029
+ }
30030
+ lines.push("");
30031
+ }
30032
+ }
30033
+ return lines.join(`
30034
+ `);
30035
+ }
30036
+ function buildSessionJson(meta, messages) {
30037
+ return JSON.stringify({ meta, messages }, null, 2);
30038
+ }
30039
+ function buildSessionJsonl(log2) {
30040
+ return log2.map((e) => JSON.stringify(e)).join(`
30041
+ `);
30042
+ }
30043
+ function formatExport(bundle, format) {
30044
+ switch (format) {
30045
+ case "md":
30046
+ return renderSessionMarkdown(bundle.meta, bundle.messages);
30047
+ case "json":
30048
+ return buildSessionJson(bundle.meta, bundle.messages);
30049
+ case "jsonl":
30050
+ return buildSessionJsonl(bundle.log);
30051
+ }
30052
+ }
30053
+ function redactExport(text, redact) {
30054
+ return redact ? redactContextSecrets(text) : text;
30055
+ }
30056
+ function sanitizeFileName(name) {
30057
+ const cleaned = name.replace(/[<>:"/\\|?*\u0000-\u001f]/g, "-").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^[-.]+|[-.]+$/g, "");
30058
+ return cleaned.length > 0 ? cleaned.slice(0, 60) : "session";
30059
+ }
30060
+ function extensionFor(format) {
30061
+ return format === "jsonl" ? "jsonl" : format;
30062
+ }
30063
+ var init_export = __esm(() => {
30064
+ init_context_log();
30065
+ });
30066
+
29764
30067
  // src/modules/indexer/map-command.ts
29765
30068
  async function runMapAction(module, action, query) {
29766
30069
  const summary = async () => {
@@ -38050,6 +38353,404 @@ var init_cli = __esm(() => {
38050
38353
  MMA_ROOT = findMmaRoot(HERE);
38051
38354
  });
38052
38355
 
38356
+ // src/config/registry.ts
38357
+ function shareField(key, canonical) {
38358
+ const field = key === "system" ? "systemPrompt" : "responseReserve";
38359
+ const other = key === "system" ? "responseReserve" : "systemPrompt";
38360
+ return {
38361
+ key: canonical,
38362
+ aliases: [`context.${key}`],
38363
+ domain: "budget",
38364
+ valueType: "share",
38365
+ reconfigure: true,
38366
+ get: (c) => c.contextBudget[field],
38367
+ set: (c, v) => setBudgetShare(c, key, v),
38368
+ extraValidate: (c, v) => {
38369
+ const n = v;
38370
+ const total = n + c.contextBudget[other];
38371
+ return total > MAX_COMBINED2 ? "combined" : null;
38372
+ }
38373
+ };
38374
+ }
38375
+ function resolveConfigKey(name) {
38376
+ return BY_NAME.get(name) ?? null;
38377
+ }
38378
+ function configDefs() {
38379
+ return DEFINITIONS;
38380
+ }
38381
+ function canonicalKeys() {
38382
+ return DEFINITIONS.map((d) => d.key);
38383
+ }
38384
+ function keysForGroup(prefix) {
38385
+ return DEFINITIONS.filter((d) => d.key.startsWith(prefix + "."));
38386
+ }
38387
+ function allConfigNames() {
38388
+ const out = [];
38389
+ for (const def of DEFINITIONS) {
38390
+ out.push({ name: def.key, def, alias: false });
38391
+ for (const a of def.aliases)
38392
+ out.push({ name: a, def, alias: true });
38393
+ }
38394
+ return out;
38395
+ }
38396
+ function formatConfigValue(value) {
38397
+ if (typeof value === "boolean")
38398
+ return value ? "on" : "off";
38399
+ return String(value);
38400
+ }
38401
+ function parseBool(raw) {
38402
+ const v = raw.trim().toLowerCase();
38403
+ if (["on", "true", "1", "yes", "y", "enable", "enabled"].includes(v))
38404
+ return { ok: true, value: true };
38405
+ if (["off", "false", "0", "no", "n", "disable", "disabled"].includes(v))
38406
+ return { ok: true, value: false };
38407
+ return { ok: false, reason: "invalid" };
38408
+ }
38409
+ function parseConfigValue(def, raw) {
38410
+ const trimmed = raw.trim();
38411
+ switch (def.valueType) {
38412
+ case "string":
38413
+ return trimmed.length > 0 ? { ok: true, value: trimmed } : { ok: false, reason: "invalid" };
38414
+ case "bool":
38415
+ return parseBool(trimmed);
38416
+ case "enum": {
38417
+ const v = trimmed.toLowerCase();
38418
+ if (def.enumValues && !def.enumValues.includes(v))
38419
+ return { ok: false, reason: "invalid" };
38420
+ return { ok: true, value: v };
38421
+ }
38422
+ case "int": {
38423
+ if (!/^-?\d+$/.test(trimmed))
38424
+ return { ok: false, reason: "invalid" };
38425
+ const n = Number(trimmed);
38426
+ if (!Number.isFinite(n))
38427
+ return { ok: false, reason: "invalid" };
38428
+ if (def.min !== undefined && n < def.min)
38429
+ return { ok: false, reason: "invalid" };
38430
+ if (def.max !== undefined && n > def.max)
38431
+ return { ok: false, reason: "invalid" };
38432
+ return { ok: true, value: n };
38433
+ }
38434
+ case "share": {
38435
+ const isPct = trimmed.endsWith("%");
38436
+ const body = isPct ? trimmed.slice(0, -1).trim() : trimmed;
38437
+ if (!/^-?\d+(\.\d+)?$/.test(body))
38438
+ return { ok: false, reason: "invalid" };
38439
+ let n = Number(body);
38440
+ if (isPct)
38441
+ n = n / 100;
38442
+ if (!Number.isFinite(n) || n < MIN_SHARE2 || n > MAX_SHARE2)
38443
+ return { ok: false, reason: "invalid" };
38444
+ return { ok: true, value: n };
38445
+ }
38446
+ }
38447
+ }
38448
+ function getConfigValue(config, name) {
38449
+ const def = resolveConfigKey(name);
38450
+ if (!def)
38451
+ return { ok: false, reason: "unknown-key", input: name };
38452
+ const value = def.get(config);
38453
+ return { ok: true, key: def.key, def, value, display: formatConfigValue(value) };
38454
+ }
38455
+ function setConfigValue(config, name, raw) {
38456
+ const def = resolveConfigKey(name);
38457
+ if (!def)
38458
+ return { ok: false, reason: "unknown-key", input: name };
38459
+ if (def.readOnly)
38460
+ return { ok: false, reason: "read-only", input: name, key: def.key, def };
38461
+ const parsed = parseConfigValue(def, raw);
38462
+ if (!parsed.ok)
38463
+ return { ok: false, reason: "invalid-value", input: name, key: def.key, def };
38464
+ const extra = def.extraValidate?.(config, parsed.value);
38465
+ if (extra)
38466
+ return { ok: false, reason: extra, input: name, key: def.key, def };
38467
+ def.set(config, parsed.value);
38468
+ return {
38469
+ ok: true,
38470
+ key: def.key,
38471
+ def,
38472
+ value: parsed.value,
38473
+ display: formatConfigValue(parsed.value),
38474
+ reconfigure: def.reconfigure,
38475
+ reasoningChanged: def.key === "reasoning.mode"
38476
+ };
38477
+ }
38478
+ function captureConfigSnapshot(config) {
38479
+ const snapshot = new Map;
38480
+ for (const def of DEFINITIONS) {
38481
+ try {
38482
+ snapshot.set(def.key, structuredClone(def.get(config)));
38483
+ } catch {}
38484
+ }
38485
+ return snapshot;
38486
+ }
38487
+ var REASONING_LEVELS, LOG_LEVELS, VERBOSITY_LEVELS, LOCALES, MIN_SHARE2 = 0.05, MAX_SHARE2 = 0.9, MAX_COMBINED2 = 0.95, DEFINITIONS, BY_NAME;
38488
+ var init_registry2 = __esm(() => {
38489
+ init_defaults();
38490
+ init_budget();
38491
+ REASONING_LEVELS = [
38492
+ "auto",
38493
+ "default",
38494
+ "none",
38495
+ "low",
38496
+ "medium",
38497
+ "high",
38498
+ "max"
38499
+ ];
38500
+ LOG_LEVELS = ["silent", "error", "warn", "info", "debug"];
38501
+ VERBOSITY_LEVELS = ["quiet", "normal", "verbose"];
38502
+ LOCALES = ["en", "ru"];
38503
+ DEFINITIONS = [
38504
+ {
38505
+ key: "model",
38506
+ aliases: [],
38507
+ domain: "agent",
38508
+ valueType: "string",
38509
+ reconfigure: true,
38510
+ get: (c) => c.model,
38511
+ set: (c, v) => {
38512
+ c.model = String(v);
38513
+ }
38514
+ },
38515
+ {
38516
+ key: "provider.active",
38517
+ aliases: [],
38518
+ domain: "provider",
38519
+ valueType: "string",
38520
+ reconfigure: true,
38521
+ get: (c) => c.provider.active ?? c.provider.type,
38522
+ set: (c, v) => {
38523
+ c.provider.active = String(v);
38524
+ },
38525
+ extraValidate: (c, v) => {
38526
+ const entries = c.provider.entries ?? [];
38527
+ if (entries.length === 0)
38528
+ return null;
38529
+ const name = String(v);
38530
+ const found = entries.some((e) => e.label === name || e.type === name);
38531
+ return found ? null : "invalid";
38532
+ }
38533
+ },
38534
+ {
38535
+ key: "contextWindow",
38536
+ aliases: ["context.window"],
38537
+ domain: "budget",
38538
+ valueType: "int",
38539
+ min: 1024,
38540
+ reconfigure: true,
38541
+ get: (c) => c.contextWindow,
38542
+ set: (c, v) => {
38543
+ c.contextWindow = v;
38544
+ }
38545
+ },
38546
+ shareField("system", "contextBudget.systemPrompt"),
38547
+ shareField("reserve", "contextBudget.responseReserve"),
38548
+ {
38549
+ key: "showReasoning",
38550
+ aliases: ["reasoning.show"],
38551
+ domain: "reasoning",
38552
+ valueType: "bool",
38553
+ reconfigure: false,
38554
+ get: (c) => c.showReasoning,
38555
+ set: (c, v) => {
38556
+ c.showReasoning = v;
38557
+ }
38558
+ },
38559
+ {
38560
+ key: "reasoning.mode",
38561
+ aliases: ["reasoning.level"],
38562
+ domain: "reasoning",
38563
+ valueType: "enum",
38564
+ enumValues: REASONING_LEVELS,
38565
+ reconfigure: true,
38566
+ get: (c) => c.reasoning?.mode ?? "auto",
38567
+ set: (c, v) => {
38568
+ const base = c.reasoning ?? structuredClone(DEFAULTS.reasoning);
38569
+ c.reasoning = { ...base, mode: v };
38570
+ }
38571
+ },
38572
+ {
38573
+ key: "ui.verbosity",
38574
+ aliases: ["verbosity"],
38575
+ domain: "ui",
38576
+ valueType: "enum",
38577
+ enumValues: VERBOSITY_LEVELS,
38578
+ reconfigure: false,
38579
+ get: (c) => c.ui.verbosity ?? (c.ui.verbose ? "verbose" : "quiet"),
38580
+ set: (c, v) => {
38581
+ c.ui.verbosity = v;
38582
+ }
38583
+ },
38584
+ {
38585
+ key: "maxToolIterations",
38586
+ aliases: [],
38587
+ domain: "agent",
38588
+ valueType: "int",
38589
+ min: 1,
38590
+ reconfigure: false,
38591
+ get: (c) => c.maxToolIterations,
38592
+ set: (c, v) => {
38593
+ c.maxToolIterations = v;
38594
+ }
38595
+ },
38596
+ {
38597
+ key: "stuckThreshold",
38598
+ aliases: [],
38599
+ domain: "agent",
38600
+ valueType: "int",
38601
+ min: 1,
38602
+ reconfigure: false,
38603
+ get: (c) => c.stuckThreshold,
38604
+ set: (c, v) => {
38605
+ c.stuckThreshold = v;
38606
+ }
38607
+ },
38608
+ {
38609
+ key: "logLevel",
38610
+ aliases: [],
38611
+ domain: "agent",
38612
+ valueType: "enum",
38613
+ enumValues: LOG_LEVELS,
38614
+ reconfigure: false,
38615
+ get: (c) => c.logLevel,
38616
+ set: (c, v) => {
38617
+ c.logLevel = String(v);
38618
+ }
38619
+ },
38620
+ {
38621
+ key: "locale",
38622
+ aliases: [],
38623
+ domain: "i18n",
38624
+ valueType: "enum",
38625
+ enumValues: LOCALES,
38626
+ reconfigure: false,
38627
+ get: (c) => c.locale,
38628
+ set: (c, v) => {
38629
+ c.locale = String(v);
38630
+ }
38631
+ },
38632
+ {
38633
+ key: "version",
38634
+ aliases: [],
38635
+ domain: "agent",
38636
+ valueType: "string",
38637
+ reconfigure: false,
38638
+ readOnly: true,
38639
+ get: (c) => c.version
38640
+ }
38641
+ ];
38642
+ BY_NAME = new Map;
38643
+ for (const def of DEFINITIONS) {
38644
+ BY_NAME.set(def.key, def);
38645
+ for (const alias of def.aliases)
38646
+ BY_NAME.set(alias, def);
38647
+ }
38648
+ });
38649
+
38650
+ // src/ui/theme.ts
38651
+ function resolveVerbosity(ui) {
38652
+ if (ui?.verbosity)
38653
+ return ui.verbosity;
38654
+ return ui?.verbose ? "verbose" : "quiet";
38655
+ }
38656
+ function toolCategory(tool) {
38657
+ for (const [category, tools] of Object.entries(CATEGORY_TOOLS)) {
38658
+ if (tools.has(tool))
38659
+ return category;
38660
+ }
38661
+ return "meta";
38662
+ }
38663
+ function toolAccent(tool) {
38664
+ switch (toolCategory(tool)) {
38665
+ case "recon":
38666
+ return pc.cyan;
38667
+ case "mutate":
38668
+ return pc.magenta;
38669
+ case "execute":
38670
+ return pc.blue;
38671
+ case "meta":
38672
+ default:
38673
+ return pc.dim;
38674
+ }
38675
+ }
38676
+ function actionMarkFor(tool) {
38677
+ return toolAccent(tool)(glyph.action);
38678
+ }
38679
+ function successMark() {
38680
+ return pc.green(glyph.success);
38681
+ }
38682
+ function failureMark() {
38683
+ return pc.red(glyph.failure);
38684
+ }
38685
+ function formatDuration(ms) {
38686
+ if (ms < 1000)
38687
+ return `${ms}ms`;
38688
+ return `${(ms / 1000).toFixed(1)}s`;
38689
+ }
38690
+ var glyph, CATEGORY_TOOLS;
38691
+ var init_theme = __esm(() => {
38692
+ init_colors();
38693
+ glyph = {
38694
+ action: "◇",
38695
+ success: "✓",
38696
+ failure: "✗",
38697
+ warning: "⚠",
38698
+ thinking: "✦",
38699
+ question: "?",
38700
+ user: "↵",
38701
+ detail: "↳",
38702
+ group: "│",
38703
+ metric: "⟡",
38704
+ compact: "⟳"
38705
+ };
38706
+ CATEGORY_TOOLS = {
38707
+ recon: new Set([
38708
+ "read_file",
38709
+ "list_dir",
38710
+ "glob",
38711
+ "grep",
38712
+ "file_info",
38713
+ "project_map",
38714
+ "chunk_query",
38715
+ "web_search",
38716
+ "web_fetch",
38717
+ "web_browse",
38718
+ "search_history",
38719
+ "recall",
38720
+ "session_info",
38721
+ "process_list",
38722
+ "process_log"
38723
+ ]),
38724
+ mutate: new Set([
38725
+ "write_file",
38726
+ "edit_file",
38727
+ "create_dir",
38728
+ "delete_file",
38729
+ "move_file",
38730
+ "attach_image"
38731
+ ]),
38732
+ execute: new Set([
38733
+ "bash",
38734
+ "process_kill",
38735
+ "pipeline_run",
38736
+ "browser",
38737
+ "download_file",
38738
+ "subagent",
38739
+ "mcp_call"
38740
+ ]),
38741
+ meta: new Set([
38742
+ "plan",
38743
+ "todo",
38744
+ "verify",
38745
+ "lsp_check",
38746
+ "enable_tools",
38747
+ "set_thinking",
38748
+ "load_skill",
38749
+ "remember"
38750
+ ])
38751
+ };
38752
+ });
38753
+
38053
38754
  // src/cli/repl-commands.ts
38054
38755
  var exports_repl_commands = {};
38055
38756
  __export(exports_repl_commands, {
@@ -38057,7 +38758,8 @@ __export(exports_repl_commands, {
38057
38758
  COMMAND_GROUPS: () => COMMAND_GROUPS
38058
38759
  });
38059
38760
  import { join as join55, dirname as dirname25 } from "path";
38060
- import { existsSync as existsSync60 } from "fs";
38761
+ import { existsSync as existsSync60, writeFileSync as writeFileSync25, mkdirSync as mkdirSync26 } from "fs";
38762
+ import { homedir as homedir18 } from "os";
38061
38763
  function registerAllCommands(ctx) {
38062
38764
  registerBuiltinCommands(ctx);
38063
38765
  registerMmaCommands(ctx);
@@ -38069,7 +38771,8 @@ function registerBuiltinCommands(ctx) {
38069
38771
  name: "help",
38070
38772
  description: t("repl.help"),
38071
38773
  usage: t("repl.help_usage"),
38072
- action: () => ctx.showHelp()
38774
+ examples: ["/help", "/help config"],
38775
+ action: (args) => ctx.showHelp(args[0])
38073
38776
  });
38074
38777
  ctx.registerCommand({
38075
38778
  name: "exit",
@@ -38084,6 +38787,7 @@ function registerBuiltinCommands(ctx) {
38084
38787
  usage: t("repl.clear_usage"),
38085
38788
  action: () => {
38086
38789
  ctx.output.clearScreen();
38790
+ ctx.output.writeLine(pc.dim(t("repl.clear_hint")));
38087
38791
  }
38088
38792
  });
38089
38793
  }
@@ -38159,36 +38863,267 @@ function registerRunCommands(ctx) {
38159
38863
  }
38160
38864
  });
38161
38865
  }
38866
+ function changeHint(def) {
38867
+ if (def.readOnly)
38868
+ return t("config.read_only_hint");
38869
+ return SUGAR_HINTS[def.key] ?? `/config ${def.key} <value>`;
38870
+ }
38871
+ function configValueHint(def) {
38872
+ if (!def)
38873
+ return "";
38874
+ switch (def.valueType) {
38875
+ case "enum":
38876
+ return t("config.hint_enum", { values: (def.enumValues ?? []).join(", ") });
38877
+ case "bool":
38878
+ return t("config.hint_bool");
38879
+ case "share":
38880
+ return t("config.hint_share");
38881
+ case "int":
38882
+ return t("config.hint_int", { min: String(def.min ?? 1) });
38883
+ default:
38884
+ return t("config.hint_string");
38885
+ }
38886
+ }
38887
+ function editDistance(a, b) {
38888
+ const dp = Array.from({ length: b.length + 1 }, (_, i) => i);
38889
+ for (let i = 1;i <= a.length; i++) {
38890
+ let prev = dp[0];
38891
+ dp[0] = i;
38892
+ for (let j = 1;j <= b.length; j++) {
38893
+ const tmp = dp[j];
38894
+ dp[j] = Math.min(dp[j] + 1, dp[j - 1] + 1, prev + (a[i - 1] === b[j - 1] ? 0 : 1));
38895
+ prev = tmp;
38896
+ }
38897
+ }
38898
+ return dp[b.length];
38899
+ }
38900
+ function nearestConfigKey(input) {
38901
+ const names = canonicalKeys();
38902
+ let best = null;
38903
+ for (const name of names) {
38904
+ const d = editDistance(input.toLowerCase(), name.toLowerCase());
38905
+ if (best === null || d < best.dist)
38906
+ best = { name, dist: d };
38907
+ }
38908
+ if (!best)
38909
+ return null;
38910
+ const threshold = Math.max(2, Math.floor(best.name.length / 3));
38911
+ return best.dist <= threshold ? best.name : null;
38912
+ }
38913
+ function renderConfigError(ctx, result) {
38914
+ const key = result.key ?? result.input;
38915
+ switch (result.reason) {
38916
+ case "unknown-key": {
38917
+ const suggestion = nearestConfigKey(result.input);
38918
+ const suffix = suggestion ? t("config.suggest", { name: suggestion }) : t("config.valid_keys", { keys: canonicalKeys().join(", ") });
38919
+ ctx.output.writeLine(pc.yellow(t("config.unknown_key", { key: result.input, suggestion: suffix })), "stderr");
38920
+ return;
38921
+ }
38922
+ case "read-only":
38923
+ ctx.output.writeLine(pc.yellow(t("config.read_only", { key })), "stderr");
38924
+ return;
38925
+ case "range":
38926
+ ctx.output.writeLine(pc.yellow(t("config.range", { key })), "stderr");
38927
+ return;
38928
+ case "combined":
38929
+ ctx.output.writeLine(pc.yellow(t("config.combined")), "stderr");
38930
+ return;
38931
+ default:
38932
+ ctx.output.writeLine(pc.yellow(t("config.invalid_value", { key, hint: configValueHint(result.def) })), "stderr");
38933
+ }
38934
+ }
38935
+ function applyConfigSideEffects(ctx, result) {
38936
+ if (result.key === "ui.verbosity") {
38937
+ ctx.output.setSuppressInfoLogs(result.value === "quiet");
38938
+ } else if (result.key === "reasoning.mode") {
38939
+ ctx.agent.setReasoningLevel(result.value);
38940
+ } else if (result.key === "locale") {
38941
+ setLocale(result.value);
38942
+ }
38943
+ }
38944
+ function persistConfig(ctx) {
38945
+ const configPath = join55(ctx.configDir, "config.json");
38946
+ saveConfig(ctx.config, configPath, dirname25(configPath));
38947
+ }
38948
+ async function mutateConfig(ctx, key, raw) {
38949
+ const result = setConfigValue(ctx.config, key, raw);
38950
+ if (!result.ok)
38951
+ return result;
38952
+ applyConfigSideEffects(ctx, result);
38953
+ persistConfig(ctx);
38954
+ if (result.reconfigure)
38955
+ await ctx.agent.reconfigure(ctx.config);
38956
+ if (result.key === "locale")
38957
+ ctx.reregisterCommands();
38958
+ return result;
38959
+ }
38960
+ function reportSaved(ctx, result) {
38961
+ ctx.output.writeLine(pc.green(t("config.saved", { key: result.key })));
38962
+ }
38963
+ function rawFromValue(value) {
38964
+ if (typeof value === "boolean")
38965
+ return value ? "on" : "off";
38966
+ return String(value);
38967
+ }
38968
+ function printConfigTable(ctx, defs) {
38969
+ const list = defs ?? configDefs();
38970
+ const rows = list.map((def) => [
38971
+ def.key,
38972
+ formatConfigValue(def.get(ctx.config)),
38973
+ def.domain,
38974
+ changeHint(def)
38975
+ ]);
38976
+ ctx.output.writeLine(pc.bold(t("config.header")));
38977
+ for (const line of renderTable([
38978
+ t("config.col_setting"),
38979
+ t("config.col_value"),
38980
+ t("config.col_domain"),
38981
+ t("config.col_change")
38982
+ ], rows)) {
38983
+ ctx.output.writeLine(line);
38984
+ }
38985
+ const meta = ctx.sessionManager?.getActiveMeta();
38986
+ if (meta) {
38987
+ ctx.output.writeLine(pc.dim(t("config.session_line", {
38988
+ name: meta.name,
38989
+ id: meta.id,
38990
+ count: String(meta.messageCount)
38991
+ })));
38992
+ }
38993
+ ctx.output.writeLine(pc.dim(t("config.usage_hint")));
38994
+ }
38995
+ function confirm(ctx, prompt) {
38996
+ return new Promise((resolve25) => {
38997
+ ctx.withExclusiveInput(async () => {
38998
+ await new Promise((done) => {
38999
+ ctx.rl.question(prompt, (answer) => {
39000
+ resolve25(/^y(es)?$/i.test(answer.trim()));
39001
+ done();
39002
+ });
39003
+ });
39004
+ });
39005
+ });
39006
+ }
39007
+ async function runConfigReset(ctx, rest) {
39008
+ const snapshot = ctx.getConfigSnapshot();
39009
+ const yes = rest.includes("--yes");
39010
+ const all = rest.includes("--all");
39011
+ const target = rest.find((a) => !a.startsWith("--"));
39012
+ if (all) {
39013
+ const changed = canonicalKeys().filter((k) => {
39014
+ const def2 = resolveConfigKey(k);
39015
+ if (!def2 || !snapshot.has(k))
39016
+ return false;
39017
+ return rawFromValue(def2.get(ctx.config)) !== rawFromValue(snapshot.get(k));
39018
+ });
39019
+ if (changed.length === 0) {
39020
+ ctx.output.writeLine(t("config.reset_none"));
39021
+ return;
39022
+ }
39023
+ if (!yes) {
39024
+ if (!process.stdin.isTTY) {
39025
+ ctx.output.writeLine(pc.yellow(t("config.reset_all_needs_yes")), "stderr");
39026
+ return;
39027
+ }
39028
+ const ok = await confirm(ctx, t("config.reset_all_confirm", { count: String(changed.length) }));
39029
+ if (!ok) {
39030
+ ctx.output.writeLine(t("config.reset_cancelled"));
39031
+ return;
39032
+ }
39033
+ }
39034
+ let anyReconfig = false;
39035
+ let localeChanged = false;
39036
+ for (const k of changed) {
39037
+ const result2 = setConfigValue(ctx.config, k, rawFromValue(snapshot.get(k)));
39038
+ if (result2.ok) {
39039
+ applyConfigSideEffects(ctx, result2);
39040
+ anyReconfig = anyReconfig || result2.reconfigure;
39041
+ localeChanged = localeChanged || result2.key === "locale";
39042
+ }
39043
+ }
39044
+ persistConfig(ctx);
39045
+ if (anyReconfig)
39046
+ await ctx.agent.reconfigure(ctx.config);
39047
+ if (localeChanged)
39048
+ ctx.reregisterCommands();
39049
+ ctx.output.writeLine(pc.green(t("config.reset_all_done", { count: String(changed.length) })));
39050
+ return;
39051
+ }
39052
+ if (!target) {
39053
+ ctx.output.writeLine(t("config.reset_usage"));
39054
+ return;
39055
+ }
39056
+ const def = resolveConfigKey(target);
39057
+ if (!def) {
39058
+ renderConfigError(ctx, { reason: "unknown-key", input: target });
39059
+ return;
39060
+ }
39061
+ if (def.readOnly || !snapshot.has(def.key)) {
39062
+ ctx.output.writeLine(t("config.reset_unchanged", { key: def.key }));
39063
+ return;
39064
+ }
39065
+ if (rawFromValue(def.get(ctx.config)) === rawFromValue(snapshot.get(def.key))) {
39066
+ ctx.output.writeLine(t("config.reset_unchanged", { key: def.key }));
39067
+ return;
39068
+ }
39069
+ const result = await mutateConfig(ctx, def.key, rawFromValue(snapshot.get(def.key)));
39070
+ if (!result.ok) {
39071
+ renderConfigError(ctx, result);
39072
+ return;
39073
+ }
39074
+ ctx.output.writeLine(pc.green(t("config.reset_ok", { key: result.key, value: result.display })));
39075
+ }
39076
+ function printReasoningStatus(ctx) {
39077
+ const display = ctx.config.showReasoning ? t("reasoning.on") : t("reasoning.off");
39078
+ const mode = ctx.config.reasoning?.mode ?? "auto";
39079
+ const auto = mode === "auto" ? t("reasoning.auto_on") : t("reasoning.auto_off");
39080
+ ctx.output.writeLine(t("reasoning.status", { display, level: mode, auto }));
39081
+ }
38162
39082
  function registerConfigCommands(ctx) {
38163
39083
  ctx.registerCommand({
38164
39084
  name: "config",
38165
39085
  description: t("repl.config"),
38166
39086
  usage: t("repl.config_usage"),
38167
- action: (args) => {
39087
+ examples: ["/config", "/config model", "/config reasoning.mode high", "/config reset ui.verbosity"],
39088
+ action: async (args) => {
38168
39089
  if ((args[0] ?? "").trim().toLowerCase() === "migrate") {
38169
39090
  return runConfigMigrate(ctx);
38170
39091
  }
38171
- const cfg = ctx.config;
38172
- const ctxW = cfg.contextWindow;
38173
- const sys = Math.floor(ctxW * cfg.contextBudget.systemPrompt);
38174
- const res = Math.floor(ctxW * cfg.contextBudget.responseReserve);
38175
- ctx.output.writeLine(`${t("repl.model")} ${cfg.model}`);
38176
- const providers = ctx.agent.listProviders();
38177
- const active = providers.find((p) => p.active);
38178
- if (active) {
38179
- ctx.output.writeLine(`${t("repl.provider")} ${active.label} (${pc.dim(active.type)}) → ${pc.dim(active.baseUrl)}`);
38180
- } else {
38181
- ctx.output.writeLine(`${t("repl.provider")} ${cfg.provider.type} → ${cfg.provider.baseUrl}`);
38182
- }
38183
- ctx.output.writeLine(`${t("repl.context")} ${ctxW} (sys:${sys} res:${res} hist:${ctxW - sys - res})`);
38184
- ctx.output.writeLine(`${t("repl.max_iters")} ${cfg.maxToolIterations}`);
38185
- ctx.output.writeLine(`${t("repl.stuck_thresh")} ${cfg.stuckThreshold}`);
38186
- ctx.output.writeLine(`${t("repl.reasoning_label")} ${cfg.showReasoning ? pc.green(t("repl.show")) : pc.dim(t("repl.hide"))}`);
38187
- ctx.output.writeLine(`${t("repl.log_level")} ${cfg.logLevel}`);
38188
- ctx.output.writeLine(`${t("repl.locale")} ${cfg.locale}`);
38189
- const meta = ctx.sessionManager?.getActiveMeta();
38190
- if (meta) {
38191
- ctx.output.writeLine(`${t("repl.session_label")} ${meta.name} (${meta.id}) — ${meta.messageCount} msgs`);
39092
+ if (args.length === 0) {
39093
+ printConfigTable(ctx);
39094
+ return;
39095
+ }
39096
+ if (args[0] === "reset") {
39097
+ await runConfigReset(ctx, args.slice(1));
39098
+ return;
39099
+ }
39100
+ const name = args[0];
39101
+ if (args.length === 1) {
39102
+ const group = keysForGroup(name);
39103
+ if (group.length > 0) {
39104
+ printConfigTable(ctx, group);
39105
+ return;
39106
+ }
39107
+ const got = getConfigValue(ctx.config, name);
39108
+ if (!got.ok) {
39109
+ renderConfigError(ctx, got);
39110
+ return;
39111
+ }
39112
+ ctx.output.writeLine(`${got.key} = ${got.display}`);
39113
+ return;
39114
+ }
39115
+ const raw = args.slice(1).join(" ");
39116
+ const result = await mutateConfig(ctx, name, raw);
39117
+ if (!result.ok) {
39118
+ renderConfigError(ctx, result);
39119
+ return;
39120
+ }
39121
+ reportSaved(ctx, result);
39122
+ if (result.key === "model") {
39123
+ const known = ctx.knownModels();
39124
+ if (known.length > 0 && !known.includes(String(result.value))) {
39125
+ ctx.output.writeLine(pc.yellow(t("model.not_in_list", { name: String(result.value) })));
39126
+ }
38192
39127
  }
38193
39128
  }
38194
39129
  });
@@ -38196,37 +39131,60 @@ function registerConfigCommands(ctx) {
38196
39131
  name: "reasoning",
38197
39132
  description: t("repl.reasoning"),
38198
39133
  usage: t("repl.reasoning_usage"),
38199
- action: (args) => {
38200
- const level = args[0]?.trim().toLowerCase();
38201
- const VALID_LEVELS2 = ["auto", "none", "low", "medium", "high", "max"];
38202
- if (!level) {
38203
- ctx.config.showReasoning = !ctx.config.showReasoning;
38204
- const status = ctx.config.showReasoning ? pc.green(t("repl.show")) : pc.dim(t("repl.hide"));
38205
- ctx.output.writeLine(t("repl.reasoning_status", { status }));
38206
- } else if (VALID_LEVELS2.includes(level)) {
38207
- ctx.agent.setReasoningLevel(level);
38208
- ctx.output.writeLine(pc.green(t("repl.reasoning_level_set", { level })));
38209
- } else {
38210
- ctx.output.writeLine(pc.yellow(t("repl.reasoning_invalid_level", { level, valid: VALID_LEVELS2.join(", ") })));
39134
+ examples: ["/reasoning", "/reasoning show", "/reasoning level high"],
39135
+ action: async (args) => {
39136
+ const sub = args[0]?.trim().toLowerCase();
39137
+ if (!sub) {
39138
+ printReasoningStatus(ctx);
39139
+ return;
38211
39140
  }
39141
+ if (sub === "show" || sub === "on" || sub === "hide" || sub === "off") {
39142
+ const on = sub === "show" || sub === "on";
39143
+ const result = await mutateConfig(ctx, "showReasoning", on ? "on" : "off");
39144
+ if (!result.ok) {
39145
+ renderConfigError(ctx, result);
39146
+ return;
39147
+ }
39148
+ ctx.output.writeLine(pc.green(t("reasoning.display_set", { state: on ? t("reasoning.on") : t("reasoning.off") })));
39149
+ return;
39150
+ }
39151
+ if (sub === "level") {
39152
+ const lvl = args[1]?.trim().toLowerCase();
39153
+ if (!lvl) {
39154
+ ctx.output.writeLine(t("repl.reasoning_usage"));
39155
+ return;
39156
+ }
39157
+ const result = await mutateConfig(ctx, "reasoning.mode", lvl);
39158
+ if (!result.ok) {
39159
+ renderConfigError(ctx, result);
39160
+ return;
39161
+ }
39162
+ ctx.output.writeLine(pc.green(t("repl.reasoning_level_set", { level: lvl })));
39163
+ if (lvl !== "auto")
39164
+ ctx.output.writeLine(pc.dim(t("reasoning.auto_off_hint")));
39165
+ return;
39166
+ }
39167
+ ctx.output.writeLine(pc.yellow(t("reasoning.unknown_sub", { sub })));
39168
+ ctx.output.writeLine(t("repl.reasoning_usage"));
38212
39169
  }
38213
39170
  });
38214
39171
  ctx.registerCommand({
38215
39172
  name: "verbose",
38216
39173
  description: t("repl.verbose"),
38217
39174
  usage: t("repl.verbose_usage"),
38218
- action: (args) => {
38219
- const VALID = ["quiet", "normal", "verbose"];
39175
+ examples: ["/verbose", "/verbose normal"],
39176
+ action: async (args) => {
38220
39177
  const level = args[0]?.trim().toLowerCase();
38221
- if (level && !VALID.includes(level)) {
38222
- ctx.output.writeLine(pc.yellow(t("repl.verbose_invalid_level", { level, valid: VALID.join(", ") })));
39178
+ if (!level) {
39179
+ ctx.output.writeLine(t("verbose.status", { level: resolveVerbosity(ctx.config.ui) }));
39180
+ return;
39181
+ }
39182
+ const result = await mutateConfig(ctx, "ui.verbosity", level);
39183
+ if (!result.ok) {
39184
+ renderConfigError(ctx, result);
38223
39185
  return;
38224
39186
  }
38225
- const current = ctx.config.ui.verbosity ?? (ctx.config.ui.verbose ? "verbose" : "quiet");
38226
- const next = level ?? (current === "verbose" ? "quiet" : "verbose");
38227
- ctx.config.ui.verbosity = next;
38228
- ctx.output.setSuppressInfoLogs(next === "quiet");
38229
- ctx.output.writeLine(pc.green(t("repl.verbose_set", { level: next })));
39187
+ ctx.output.writeLine(pc.green(t("repl.verbose_set", { level: result.display })));
38230
39188
  }
38231
39189
  });
38232
39190
  ctx.registerCommand({
@@ -38236,16 +39194,13 @@ function registerConfigCommands(ctx) {
38236
39194
  action: () => {
38237
39195
  const providers = ctx.agent.listProviders();
38238
39196
  const active = providers.find((p) => p.active);
38239
- ctx.output.writeLine(`${t("repl.model")} ${ctx.config.model}`);
38240
- if (active) {
38241
- ctx.output.writeLine(`${t("repl.provider")} ${active.label} (${pc.dim(active.type)}) @ ${pc.dim(active.baseUrl)}`);
38242
- } else {
38243
- ctx.output.writeLine(`${t("repl.provider")} ${ctx.config.provider.type} @ ${pc.dim(ctx.config.provider.baseUrl)}`);
38244
- }
39197
+ const providerLabel = active ? active.label : ctx.config.provider.type;
39198
+ const parts = [ctx.config.model, providerLabel];
38245
39199
  const meta = ctx.sessionManager?.getActiveMeta();
38246
- if (meta) {
38247
- ctx.output.writeLine(`${t("repl.session_label")} ${meta.name} (${meta.id}) — ${meta.messageCount} messages`);
38248
- }
39200
+ if (meta)
39201
+ parts.push(`${meta.name} (${meta.messageCount} ${t("repl.msgs")})`);
39202
+ parts.push(`${ctx.config.contextWindow} tok`);
39203
+ ctx.output.writeLine(parts.join(pc.dim(" · ")));
38249
39204
  }
38250
39205
  });
38251
39206
  ctx.registerCommand({
@@ -38268,22 +39223,28 @@ function registerConfigCommands(ctx) {
38268
39223
  ctx.registerCommand({
38269
39224
  name: "sysprompt",
38270
39225
  description: t("repl.sysprompt_desc"),
38271
- usage: t("repl.sysprompt_desc"),
38272
- action: () => {
39226
+ usage: t("repl.sysprompt_usage"),
39227
+ examples: ["/sysprompt", "/sysprompt --full"],
39228
+ action: (args) => {
38273
39229
  const info = ctx.agent.getSystemPromptInfo();
39230
+ const full = args.includes("--full");
38274
39231
  ctx.output.writeLine(pc.bold(t("repl.sysprompt_tokens", { count: String(info.tokenCount) })));
38275
- ctx.output.writeLine(pc.dim("─".repeat(60)));
38276
- for (const line of info.text.split(`
38277
- `)) {
38278
- ctx.output.writeLine(line);
38279
- }
38280
- ctx.output.writeLine(pc.dim("─".repeat(60)));
38281
39232
  if (info.excluded.length > 0) {
38282
39233
  ctx.output.writeLine(pc.yellow(t("repl.excluded_blocks", { count: String(info.excluded.length) })));
38283
39234
  for (const e of info.excluded) {
38284
39235
  ctx.output.writeLine(pc.dim(` - ${e.slice(0, 80)}${e.length > 80 ? "..." : ""}`));
38285
39236
  }
38286
39237
  }
39238
+ if (full) {
39239
+ ctx.output.writeLine(pc.dim("─".repeat(60)));
39240
+ for (const line of info.text.split(`
39241
+ `)) {
39242
+ ctx.output.writeLine(line);
39243
+ }
39244
+ ctx.output.writeLine(pc.dim("─".repeat(60)));
39245
+ } else {
39246
+ ctx.output.writeLine(pc.dim(t("repl.sysprompt_full_hint")));
39247
+ }
38287
39248
  }
38288
39249
  });
38289
39250
  ctx.registerCommand({
@@ -38323,13 +39284,14 @@ function registerProviderCommands(ctx) {
38323
39284
  ctx.output.writeLine(t("repl.provider_usage"));
38324
39285
  return;
38325
39286
  }
38326
- try {
38327
- await ctx.agent.setProvider(name);
38328
- ctx.refreshModelCache();
38329
- ctx.output.writeLine(pc.green(t("repl.provider_set", { name })));
38330
- } catch (e) {
38331
- ctx.output.writeLine(pc.red(e.message), "stderr");
39287
+ const result = await mutateConfig(ctx, "provider.active", name);
39288
+ if (!result.ok) {
39289
+ renderConfigError(ctx, result);
39290
+ return;
38332
39291
  }
39292
+ ctx.refreshModelCache();
39293
+ ctx.output.writeLine(pc.green(t("repl.provider_set", { name })));
39294
+ reportSaved(ctx, result);
38333
39295
  };
38334
39296
  const add = async (args) => {
38335
39297
  const flags = {};
@@ -38352,6 +39314,13 @@ function registerProviderCommands(ctx) {
38352
39314
  ctx.output.writeLine(t("repl.provider_usage"));
38353
39315
  return;
38354
39316
  }
39317
+ for (const flag of ["priority", "context-window", "rpm", "parallel"]) {
39318
+ const v = flags[flag];
39319
+ if (v !== undefined && !Number.isFinite(Number(v))) {
39320
+ ctx.output.writeLine(pc.red(t("repl.provider_add_invalid_number", { flag: `--${flag}`, value: v })), "stderr");
39321
+ return;
39322
+ }
39323
+ }
38355
39324
  const entries = Array.isArray(ctx.config.provider.entries) ? ctx.config.provider.entries : [];
38356
39325
  if (entries.length === 0) {
38357
39326
  entries.push({
@@ -38382,8 +39351,7 @@ function registerProviderCommands(ctx) {
38382
39351
  });
38383
39352
  ctx.config.provider.entries = entries;
38384
39353
  ctx.config.provider.active = ctx.config.provider.active || ctx.config.provider.type;
38385
- const configPath = join55(ctx.configDir, "config.json");
38386
- saveConfig(ctx.config, configPath, dirname25(configPath));
39354
+ persistConfig(ctx);
38387
39355
  await ctx.agent.reconfigure(ctx.config);
38388
39356
  ctx.output.writeLine(pc.green(t("cli.provider_added", { name })));
38389
39357
  ctx.output.writeLine(t("repl.provider_switch_hint", { name }));
@@ -38397,10 +39365,12 @@ function registerProviderCommands(ctx) {
38397
39365
  name: "provider",
38398
39366
  description: t("repl.provider_list"),
38399
39367
  usage: t("repl.provider_usage"),
39368
+ examples: ["/provider list", "/provider use openrouter", "/provider add openai --key sk-..."],
38400
39369
  action: async (args) => {
38401
39370
  const subcmd = args[0];
38402
39371
  const handler = subcmd ? handlers[subcmd] : handlers.list;
38403
39372
  if (!handler) {
39373
+ ctx.output.writeLine(pc.yellow(t("repl.unknown_sub", { cmd: "provider", sub: subcmd })));
38404
39374
  ctx.output.writeLine(t("repl.provider_usage"));
38405
39375
  return;
38406
39376
  }
@@ -38448,11 +39418,17 @@ function registerProviderCommands(ctx) {
38448
39418
  ctx.output.writeLine(t("repl.model_usage"));
38449
39419
  return;
38450
39420
  }
38451
- ctx.config.model = name;
38452
- const configPath = join55(ctx.configDir, "config.json");
38453
- saveConfig(ctx.config, configPath, dirname25(configPath));
38454
- await ctx.agent.reconfigure(ctx.config);
39421
+ const result = await mutateConfig(ctx, "model", name);
39422
+ if (!result.ok) {
39423
+ renderConfigError(ctx, result);
39424
+ return;
39425
+ }
38455
39426
  ctx.output.writeLine(pc.green(t("repl.model_set", { name })));
39427
+ const known = ctx.knownModels();
39428
+ if (known.length > 0 && !known.includes(name)) {
39429
+ ctx.output.writeLine(pc.yellow(t("model.not_in_list", { name })));
39430
+ }
39431
+ reportSaved(ctx, result);
38456
39432
  };
38457
39433
  const modelHandlers = {
38458
39434
  list: listModels,
@@ -38462,10 +39438,12 @@ function registerProviderCommands(ctx) {
38462
39438
  name: "model",
38463
39439
  description: t("repl.model_list"),
38464
39440
  usage: t("repl.model_usage"),
39441
+ examples: ["/model list", "/model use qwen/qwen3.5-9b"],
38465
39442
  action: async (args) => {
38466
39443
  const subcmd = args[0];
38467
39444
  const handler = subcmd ? modelHandlers[subcmd] : modelHandlers.list;
38468
39445
  if (!handler) {
39446
+ ctx.output.writeLine(pc.yellow(t("repl.unknown_sub", { cmd: "model", sub: subcmd })));
38469
39447
  ctx.output.writeLine(t("repl.model_usage"));
38470
39448
  return;
38471
39449
  }
@@ -38476,12 +39454,8 @@ function registerProviderCommands(ctx) {
38476
39454
  name: "context",
38477
39455
  description: t("cli.manage_context"),
38478
39456
  usage: t("repl.context_usage"),
39457
+ examples: ["/context", "/context 64000", "/context system 10%", "/context reserve 0.2"],
38479
39458
  action: async (args) => {
38480
- const save = async () => {
38481
- const configPath = join55(ctx.configDir, "config.json");
38482
- saveConfig(ctx.config, configPath, dirname25(configPath));
38483
- await ctx.agent.reconfigure(ctx.config);
38484
- };
38485
39459
  if (args.length === 0) {
38486
39460
  for (const line of budgetBreakdownLines(ctx.config))
38487
39461
  ctx.output.writeLine(line);
@@ -38489,24 +39463,32 @@ function registerProviderCommands(ctx) {
38489
39463
  return;
38490
39464
  }
38491
39465
  if (args[0] === "system" || args[0] === "reserve") {
38492
- const key = args[0];
38493
- const value = Number(args[1]);
38494
- if (setBudgetShare(ctx.config, key, value) !== null) {
38495
- ctx.output.writeLine(pc.yellow(t("cli.context_invalid_fraction")));
39466
+ const raw = args[1];
39467
+ if (!raw) {
39468
+ ctx.output.writeLine(t("repl.context_usage"));
38496
39469
  return;
38497
39470
  }
38498
- await save();
38499
- ctx.output.writeLine(pc.green(t("cli.context_fraction_set", { key, value })));
39471
+ const key = args[0] === "system" ? "contextBudget.systemPrompt" : "contextBudget.responseReserve";
39472
+ const result2 = await mutateConfig(ctx, key, raw);
39473
+ if (!result2.ok) {
39474
+ renderConfigError(ctx, result2);
39475
+ return;
39476
+ }
39477
+ ctx.output.writeLine(pc.green(t("cli.context_fraction_set", { key: args[0], value: result2.display })));
39478
+ return;
39479
+ }
39480
+ if (!/^\d+$/.test(args[0])) {
39481
+ ctx.output.writeLine(pc.yellow(t("context.unknown_arg", { arg: args[0] })));
39482
+ ctx.output.writeLine(t("repl.context_usage"));
38500
39483
  return;
38501
39484
  }
38502
- const size = parseInt(args[0], 10);
38503
- if (isNaN(size) || size < 1024) {
38504
- ctx.output.writeLine(t("cli.invalid_context_size"));
39485
+ const result = await mutateConfig(ctx, "contextWindow", args[0]);
39486
+ if (!result.ok) {
39487
+ renderConfigError(ctx, result);
38505
39488
  return;
38506
39489
  }
38507
- ctx.config.contextWindow = size;
38508
- await save();
38509
- ctx.output.writeLine(pc.green(t("cli.context_set", { size })));
39490
+ ctx.output.writeLine(pc.green(t("cli.context_set", { size: String(result.value) })));
39491
+ reportSaved(ctx, result);
38510
39492
  }
38511
39493
  });
38512
39494
  }
@@ -38565,15 +39547,15 @@ function registerLspCommands(ctx) {
38565
39547
  name: "lsp",
38566
39548
  description: t("repl.lsp"),
38567
39549
  usage: t("repl.lsp_usage"),
39550
+ examples: ["/lsp status", "/lsp restart", "/lsp check src/index.ts"],
38568
39551
  action: async (args) => {
38569
- const subcommand = args[0] || "status";
38570
39552
  const lspModule = ctx.agent.getModule("lsp");
38571
39553
  if (!lspModule) {
38572
39554
  ctx.output.writeLine(pc.yellow(t("repl.lsp_not_available")));
38573
39555
  return;
38574
39556
  }
38575
- switch (subcommand) {
38576
- case "status": {
39557
+ const handlers = {
39558
+ status: () => {
38577
39559
  const disabled = lspModule.getDisabledServers();
38578
39560
  const failures = lspModule.getFailureCounts();
38579
39561
  const config = ctx.config.lsp;
@@ -38591,16 +39573,14 @@ function registerLspCommands(ctx) {
38591
39573
  if (disabled.length === 0 && failures.size === 0) {
38592
39574
  ctx.output.writeLine(pc.green(t("repl.lsp_all_ok")));
38593
39575
  }
38594
- break;
38595
- }
38596
- case "restart": {
39576
+ },
39577
+ restart: () => {
38597
39578
  ctx.output.writeLine(pc.yellow(t("repl.lsp_restarting")));
38598
39579
  lspModule.resetDisabledServers();
38599
39580
  ctx.output.writeLine(pc.green(t("repl.lsp_restarted")));
38600
- break;
38601
- }
38602
- case "check": {
38603
- const path = args[1];
39581
+ },
39582
+ check: async (rest) => {
39583
+ const path = rest[0];
38604
39584
  if (!path) {
38605
39585
  ctx.output.writeLine(pc.yellow(t("repl.lsp_check_usage")));
38606
39586
  return;
@@ -38614,13 +39594,16 @@ function registerLspCommands(ctx) {
38614
39594
  } catch (e) {
38615
39595
  ctx.output.writeLine(pc.red(t("repl.lsp_check_error", { error: errMsg(e) })), "stderr");
38616
39596
  }
38617
- break;
38618
- }
38619
- default: {
38620
- ctx.output.writeLine(pc.dim(t("repl.lsp_usage")));
38621
- break;
38622
39597
  }
39598
+ };
39599
+ const subcommand = args[0] || "status";
39600
+ const handler = handlers[subcommand];
39601
+ if (!handler) {
39602
+ ctx.output.writeLine(pc.yellow(t("repl.unknown_sub", { cmd: "lsp", sub: subcommand })));
39603
+ ctx.output.writeLine(pc.dim(t("repl.lsp_usage")));
39604
+ return;
38623
39605
  }
39606
+ await handler(args.slice(1));
38624
39607
  }
38625
39608
  });
38626
39609
  }
@@ -38684,8 +39667,9 @@ function registerSessionCommands(ctx) {
38684
39667
  ctx.registerCommand({
38685
39668
  name: "resume",
38686
39669
  description: t("repl.resume"),
38687
- aliases: ["switch", "use"],
39670
+ aliases: ["switch"],
38688
39671
  usage: t("repl.resume_usage"),
39672
+ examples: ["/resume", "/resume my-session"],
38689
39673
  action: (args) => {
38690
39674
  const query = args.join(" ");
38691
39675
  const sessions = ctx.sessionManager.list();
@@ -38772,6 +39756,77 @@ function registerSessionCommands(ctx) {
38772
39756
  ctx.output.writeLine(`${t("session.deleted", { id: match.id })}: ${match.name}`);
38773
39757
  }
38774
39758
  });
39759
+ ctx.registerCommand({
39760
+ name: "export",
39761
+ description: t("repl.export"),
39762
+ usage: t("repl.export_usage"),
39763
+ examples: [
39764
+ "/export",
39765
+ "/export my-session --format md",
39766
+ "/export --format json --out -"
39767
+ ],
39768
+ action: async (args) => {
39769
+ let format = "md";
39770
+ let out;
39771
+ let redact = true;
39772
+ const positional = [];
39773
+ for (let i = 0;i < args.length; i++) {
39774
+ const a = args[i];
39775
+ if (a === "--format") {
39776
+ const v = args[++i];
39777
+ if (!v) {
39778
+ ctx.output.writeLine(t("export.missing_value", { flag: a }));
39779
+ return;
39780
+ }
39781
+ format = v;
39782
+ } else if (a === "--out") {
39783
+ const v = args[++i];
39784
+ if (v === undefined) {
39785
+ ctx.output.writeLine(t("export.missing_value", { flag: a }));
39786
+ return;
39787
+ }
39788
+ out = v;
39789
+ } else if (a === "--no-redact") {
39790
+ redact = false;
39791
+ } else {
39792
+ positional.push(a);
39793
+ }
39794
+ }
39795
+ if (format !== "md" && format !== "json" && format !== "jsonl") {
39796
+ ctx.output.writeLine(pc.yellow(t("export.invalid_format", { format })), "stderr");
39797
+ return;
39798
+ }
39799
+ const query = positional.join(" ");
39800
+ const sessions = ctx.sessionManager.list();
39801
+ const match = query ? sessions.find((s) => s.id === query || s.id.startsWith(query) || s.name.toLowerCase().includes(query.toLowerCase())) : sessions.find((s) => s.id === ctx.sessionManager.getActive());
39802
+ if (!match) {
39803
+ ctx.output.writeLine(query ? t("session.no_match", { query }) : t("session.no_active"));
39804
+ return;
39805
+ }
39806
+ const messages = ctx.sessionManager.getHistory(match.id);
39807
+ const log2 = ctx.sessionManager.loadSessionLog(match.id);
39808
+ if (format === "jsonl" ? log2.length === 0 : messages.length === 0) {
39809
+ ctx.output.writeLine(pc.yellow(t("export.empty")));
39810
+ return;
39811
+ }
39812
+ const text = redactExport(formatExport({ meta: match, messages, log: log2 }, format), redact);
39813
+ if (out === "-") {
39814
+ ctx.output.writeLine(text);
39815
+ return;
39816
+ }
39817
+ const baseDir = out ? dirname25(out) : join55(homedir18(), ".mma", "exports");
39818
+ const path = out ?? join55(baseDir, `${sanitizeFileName(match.name)}-${match.id.slice(0, 8)}.${extensionFor(format)}`);
39819
+ try {
39820
+ mkdirSync26(baseDir, { recursive: true });
39821
+ writeFileSync25(path, text, "utf-8");
39822
+ } catch (e) {
39823
+ ctx.output.writeLine(pc.red(t("export.write_failed", { error: errMsg(e) })), "stderr");
39824
+ return;
39825
+ }
39826
+ ctx.output.writeLine(pc.green(t("export.written", { path })));
39827
+ ctx.output.writeLine(pc.dim(redact ? t("export.redacted") : t("export.raw")));
39828
+ }
39829
+ });
38775
39830
  }
38776
39831
  function registerSkillCommands(ctx) {
38777
39832
  if (!ctx.skillsModule)
@@ -38862,7 +39917,7 @@ function registerSkillCommands(ctx) {
38862
39917
  const subcmd = args[0];
38863
39918
  const handler = subcmd ? skillHandlers[subcmd] : skillHandlers.list;
38864
39919
  if (!handler) {
38865
- ctx.output.writeLine(pc.red(t("repl.skill_unknown_sub", { subcmd })), "stderr");
39920
+ ctx.output.writeLine(pc.yellow(t("repl.unknown_sub", { cmd: "skill", sub: subcmd })));
38866
39921
  ctx.output.writeLine(t("repl.skill_usage"));
38867
39922
  return;
38868
39923
  }
@@ -38891,9 +39946,10 @@ async function runConfigMigrate(ctx) {
38891
39946
  const domainFiles = readdirSync20(join55(configDir, "config")).filter((f) => f.endsWith(".json"));
38892
39947
  ctx.output.writeLine(pc.green(t("config.migrate_done", { count: String(domainFiles.length) })));
38893
39948
  }
38894
- var version2, COMMAND_GROUPS;
39949
+ var version2, COMMAND_GROUPS, SUGAR_HINTS;
38895
39950
  var init_repl_commands = __esm(() => {
38896
39951
  init_colors();
39952
+ init_theme();
38897
39953
  init_version();
38898
39954
  init_table();
38899
39955
  init_i18n();
@@ -38902,6 +39958,8 @@ var init_repl_commands = __esm(() => {
38902
39958
  init_config2();
38903
39959
  init_presets();
38904
39960
  init_budget();
39961
+ init_registry2();
39962
+ init_export();
38905
39963
  init_token_counter();
38906
39964
  init_map_command();
38907
39965
  init_utils();
@@ -38929,9 +39987,20 @@ var init_repl_commands = __esm(() => {
38929
39987
  resume: "session",
38930
39988
  rename: "session",
38931
39989
  delete: "session",
39990
+ export: "session",
38932
39991
  skill: "skill",
38933
39992
  plugins: "agent"
38934
39993
  };
39994
+ SUGAR_HINTS = {
39995
+ model: "/model use <name>",
39996
+ "provider.active": "/provider use <name>",
39997
+ contextWindow: "/context <size>",
39998
+ "contextBudget.systemPrompt": "/context system <share>",
39999
+ "contextBudget.responseReserve": "/context reserve <share>",
40000
+ showReasoning: "/reasoning show | hide",
40001
+ "reasoning.mode": "/reasoning level <level>",
40002
+ "ui.verbosity": "/verbose <level>"
40003
+ };
38935
40004
  });
38936
40005
 
38937
40006
  // node_modules/commander/esm.mjs
@@ -38957,9 +40026,10 @@ init_setup();
38957
40026
  init_setup_order();
38958
40027
  init_i18n();
38959
40028
  init_colors();
40029
+ init_export();
38960
40030
  import { join as join53, dirname as dirname24 } from "path";
38961
40031
  import { homedir as homedir17 } from "os";
38962
- import { existsSync as existsSync59 } from "fs";
40032
+ import { existsSync as existsSync59, mkdirSync as mkdirSync25, writeFileSync as writeFileSync24 } from "fs";
38963
40033
 
38964
40034
  // src/cli/security-commands.ts
38965
40035
  init_bootstrap();
@@ -40224,6 +41294,41 @@ function buildSessionCommands(program2) {
40224
41294
  }
40225
41295
  }
40226
41296
  });
41297
+ session2.command("export").argument("<id>", "Session id (or name prefix)").description(t("cli.export_session")).option("--format <format>", t("cli.export_format"), "md").option("--out <path>", t("cli.export_out")).option("--no-redact", t("cli.export_no_redact")).action(async (id, opts) => {
41298
+ const { sessionManager } = await bootstrap();
41299
+ const meta = sessionManager.get(id) ?? sessionManager.list().find((s) => s.id.startsWith(id)) ?? sessionManager.list().find((s) => s.name.toLowerCase().includes(id.toLowerCase()));
41300
+ if (!meta) {
41301
+ getDefaultChannel().writeLine(t("session.not_found", { id }));
41302
+ return;
41303
+ }
41304
+ const format = opts.format;
41305
+ if (format !== "md" && format !== "json" && format !== "jsonl") {
41306
+ getDefaultChannel().writeLine(t("export.invalid_format", { format }));
41307
+ return;
41308
+ }
41309
+ const messages = sessionManager.getHistory(meta.id);
41310
+ const log2 = sessionManager.loadSessionLog(meta.id);
41311
+ if (format === "jsonl" ? log2.length === 0 : messages.length === 0) {
41312
+ getDefaultChannel().writeLine(t("export.empty"));
41313
+ return;
41314
+ }
41315
+ const text = redactExport(formatExport({ meta, messages, log: log2 }, format), opts.redact);
41316
+ if (opts.out === "-") {
41317
+ getDefaultChannel().writeLine(text);
41318
+ return;
41319
+ }
41320
+ const baseDir = opts.out ? dirname24(opts.out) : join53(homedir17(), ".mma", "exports");
41321
+ const path = opts.out ?? join53(baseDir, `${sanitizeFileName(meta.name)}-${meta.id.slice(0, 8)}.${extensionFor(format)}`);
41322
+ try {
41323
+ mkdirSync25(baseDir, { recursive: true });
41324
+ writeFileSync24(path, text, "utf-8");
41325
+ } catch (e) {
41326
+ getDefaultChannel().writeLine(t("export.write_failed", { error: String(e) }));
41327
+ return;
41328
+ }
41329
+ getDefaultChannel().writeLine(t("export.written", { path }));
41330
+ getDefaultChannel().writeLine(t(opts.redact ? "export.redacted" : "export.raw"));
41331
+ });
40227
41332
  session2.command("delete").argument("<id>", "Session id").description(t("cli.delete_session")).action(async (id) => {
40228
41333
  const { sessionManager } = await bootstrap();
40229
41334
  sessionManager.delete(id);
@@ -41355,11 +42460,13 @@ class LineEditor {
41355
42460
  }
41356
42461
 
41357
42462
  // src/cli/repl.ts
41358
- import { existsSync as existsSync61, mkdirSync as mkdirSync25, readFileSync as readFileSync42, writeFileSync as writeFileSync24 } from "fs";
42463
+ import { existsSync as existsSync61, mkdirSync as mkdirSync27, readFileSync as readFileSync42, writeFileSync as writeFileSync26 } from "fs";
41359
42464
  import { dirname as dirname26, join as join56 } from "path";
41360
- import { homedir as homedir18 } from "os";
42465
+ import { homedir as homedir19 } from "os";
41361
42466
 
41362
42467
  // src/cli/completer.ts
42468
+ init_registry2();
42469
+ init_i18n();
41363
42470
  import { readdirSync as readdirSync19, statSync as statSync11 } from "fs";
41364
42471
  import { join as join54 } from "path";
41365
42472
  function buildSlashCompletions(commands) {
@@ -41464,11 +42571,13 @@ class ProviderArgProvider {
41464
42571
  class SessionNameProvider {
41465
42572
  name = "session-names";
41466
42573
  getNames;
41467
- constructor(getNames) {
42574
+ commands;
42575
+ constructor(getNames, commands = ["/resume"]) {
41468
42576
  this.getNames = getNames;
42577
+ this.commands = commands;
41469
42578
  }
41470
42579
  match(ctx) {
41471
- return ctx.tokenIndex >= 1 && ctx.tokens[0] === "/resume";
42580
+ return ctx.tokenIndex >= 1 && this.commands.includes(ctx.tokens[0]);
41472
42581
  }
41473
42582
  complete(ctx) {
41474
42583
  const names = this.getNames();
@@ -41500,6 +42609,74 @@ class SkillNameProvider {
41500
42609
  }
41501
42610
  }
41502
42611
 
42612
+ class ConfigKeyProvider {
42613
+ name = "config-keys";
42614
+ match(ctx) {
42615
+ return ctx.tokenIndex === 1 && ctx.tokens[0] === "/config";
42616
+ }
42617
+ complete(ctx) {
42618
+ const partial = ctx.partial;
42619
+ const items = allConfigNames().map(({ name, def, alias }) => ({
42620
+ value: name,
42621
+ description: alias ? `${t("config.alias_label")} ${def.key}` : def.domain
42622
+ }));
42623
+ if (!partial.includes(".")) {
42624
+ const groups = [...new Set(canonicalKeys().filter((k) => k.includes(".")).map((k) => k.split(".")[0]))];
42625
+ const groupItems = groups.map((g) => ({
42626
+ value: g,
42627
+ description: t("config.group_label")
42628
+ }));
42629
+ return [...groupItems, ...items].filter((i) => i.value.startsWith(partial));
42630
+ }
42631
+ return items.filter((i) => i.value.startsWith(partial));
42632
+ }
42633
+ }
42634
+
42635
+ class ConfigValueProvider {
42636
+ name = "config-values";
42637
+ match(ctx) {
42638
+ return ctx.tokenIndex === 2 && ctx.tokens[0] === "/config";
42639
+ }
42640
+ complete(ctx) {
42641
+ const def = resolveConfigKey(ctx.tokens[1]);
42642
+ if (!def?.enumValues)
42643
+ return [];
42644
+ return def.enumValues.filter((v) => v.startsWith(ctx.partial)).map((v) => ({ value: v }));
42645
+ }
42646
+ }
42647
+
42648
+ class FlagProvider {
42649
+ name = "provider-add-flags";
42650
+ match(ctx) {
42651
+ return ctx.tokens[0] === "/provider" && ctx.tokens[1] === "add" && ctx.tokenIndex >= 2;
42652
+ }
42653
+ complete(ctx) {
42654
+ const flags = [
42655
+ { value: "--url", description: t("repl.provider_flag_url") },
42656
+ { value: "--key", description: t("repl.provider_flag_key") },
42657
+ { value: "--priority", description: t("repl.provider_flag_priority") },
42658
+ { value: "--context-window", description: t("repl.provider_flag_context_window") },
42659
+ { value: "--rpm", description: t("repl.provider_flag_rpm") },
42660
+ { value: "--parallel", description: t("repl.provider_flag_parallel") }
42661
+ ];
42662
+ return flags.filter((f) => f.value.startsWith(ctx.partial));
42663
+ }
42664
+ }
42665
+
42666
+ class CommandArgProvider {
42667
+ name = "help-command-args";
42668
+ getNames;
42669
+ constructor(getNames) {
42670
+ this.getNames = getNames;
42671
+ }
42672
+ match(ctx) {
42673
+ return ctx.tokenIndex === 1 && ctx.tokens[0] === "/help";
42674
+ }
42675
+ complete(ctx) {
42676
+ return this.getNames().filter((n) => n.startsWith(ctx.partial)).map((n) => ({ value: n }));
42677
+ }
42678
+ }
42679
+
41503
42680
  class Completer {
41504
42681
  providers = [];
41505
42682
  registerProvider(provider) {
@@ -41534,109 +42711,7 @@ init_colors();
41534
42711
  init_string_width();
41535
42712
  init_i18n();
41536
42713
  init_table();
41537
-
41538
- // src/ui/theme.ts
41539
- init_colors();
41540
- var glyph = {
41541
- action: "◇",
41542
- success: "✓",
41543
- failure: "✗",
41544
- warning: "⚠",
41545
- thinking: "✦",
41546
- question: "?",
41547
- user: "↵",
41548
- detail: "↳",
41549
- group: "│",
41550
- metric: "⟡",
41551
- compact: "⟳"
41552
- };
41553
- function resolveVerbosity(ui) {
41554
- if (ui?.verbosity)
41555
- return ui.verbosity;
41556
- return ui?.verbose ? "verbose" : "quiet";
41557
- }
41558
- var CATEGORY_TOOLS = {
41559
- recon: new Set([
41560
- "read_file",
41561
- "list_dir",
41562
- "glob",
41563
- "grep",
41564
- "file_info",
41565
- "project_map",
41566
- "chunk_query",
41567
- "web_search",
41568
- "web_fetch",
41569
- "web_browse",
41570
- "search_history",
41571
- "recall",
41572
- "session_info",
41573
- "process_list",
41574
- "process_log"
41575
- ]),
41576
- mutate: new Set([
41577
- "write_file",
41578
- "edit_file",
41579
- "create_dir",
41580
- "delete_file",
41581
- "move_file",
41582
- "attach_image"
41583
- ]),
41584
- execute: new Set([
41585
- "bash",
41586
- "process_kill",
41587
- "pipeline_run",
41588
- "browser",
41589
- "download_file",
41590
- "subagent",
41591
- "mcp_call"
41592
- ]),
41593
- meta: new Set([
41594
- "plan",
41595
- "todo",
41596
- "verify",
41597
- "lsp_check",
41598
- "enable_tools",
41599
- "set_thinking",
41600
- "load_skill",
41601
- "remember"
41602
- ])
41603
- };
41604
- function toolCategory(tool) {
41605
- for (const [category, tools] of Object.entries(CATEGORY_TOOLS)) {
41606
- if (tools.has(tool))
41607
- return category;
41608
- }
41609
- return "meta";
41610
- }
41611
- function toolAccent(tool) {
41612
- switch (toolCategory(tool)) {
41613
- case "recon":
41614
- return pc.cyan;
41615
- case "mutate":
41616
- return pc.magenta;
41617
- case "execute":
41618
- return pc.blue;
41619
- case "meta":
41620
- default:
41621
- return pc.dim;
41622
- }
41623
- }
41624
- function actionMarkFor(tool) {
41625
- return toolAccent(tool)(glyph.action);
41626
- }
41627
- function successMark() {
41628
- return pc.green(glyph.success);
41629
- }
41630
- function failureMark() {
41631
- return pc.red(glyph.failure);
41632
- }
41633
- function formatDuration(ms) {
41634
- if (ms < 1000)
41635
- return `${ms}ms`;
41636
- return `${(ms / 1000).toFixed(1)}s`;
41637
- }
41638
-
41639
- // src/ui/md-formatter.ts
42714
+ init_theme();
41640
42715
  var KW = /\b(import|export|from|const|let|var|function|return|if|else|for|while|do|switch|case|break|continue|new|class|extends|implements|interface|type|enum|namespace|module|declare|abstract|async|await|yield|throw|try|catch|finally|typeof|instanceof|in|of|as|is|keyof|readonly|static|private|public|protected|get|set|constructor|this|super|void|never|any|unknown|boolean|string|number|symbol|object|true|false|null|undefined|default)\b/g;
41641
42716
  var STRING = /('[^']*'|"[^"]*"|`[^`]*`)/g;
41642
42717
  var COMMENT = /(\/\/[^\n]*|\/\*[\s\S]*?\*\/|#[^\n]*)/g;
@@ -41892,6 +42967,7 @@ function formatWarning(text) {
41892
42967
 
41893
42968
  // src/ui/renderer.ts
41894
42969
  init_spinner();
42970
+ init_theme();
41895
42971
 
41896
42972
  // src/ui/action-log.ts
41897
42973
  var last = null;
@@ -42359,9 +43435,11 @@ ${pc.dim(glyph.metric)} ${model} · ${provider} · ${pc.dim(formatDuration(durat
42359
43435
  }
42360
43436
 
42361
43437
  // src/cli/repl.ts
43438
+ init_theme();
42362
43439
  init_box();
42363
43440
  init_i18n();
42364
43441
  init_repl_commands();
43442
+ init_registry2();
42365
43443
 
42366
43444
  // src/modules/lsp/probe.ts
42367
43445
  init_client2();
@@ -42445,6 +43523,7 @@ init_session_logger();
42445
43523
 
42446
43524
  // src/ui/plan-view.ts
42447
43525
  init_colors();
43526
+ init_theme();
42448
43527
  init_js_identifiers();
42449
43528
  init_i18n();
42450
43529
  function currentStepIndex(plan) {
@@ -42647,6 +43726,7 @@ function createHostBridge(opts) {
42647
43726
  class Repl {
42648
43727
  completer = new Completer;
42649
43728
  modelCache = [];
43729
+ configSnapshot = new Map;
42650
43730
  running = false;
42651
43731
  agentRunning = false;
42652
43732
  inputLocked = false;
@@ -42690,10 +43770,10 @@ class Repl {
42690
43770
  this.execModule = execModule;
42691
43771
  this.slog = new SessionLogger(sessionManager, logger4);
42692
43772
  this.bindSessionOutput();
42693
- this.configDir = configDir || join56(homedir18(), ".mma");
43773
+ this.configDir = configDir || join56(homedir19(), ".mma");
42694
43774
  this.baseDir = baseDir || process.cwd();
42695
43775
  this.noAgentsMd = noAgentsMd === true;
42696
- this.historyPath = historyPath ?? join56(homedir18(), ".mma", "repl-history");
43776
+ this.historyPath = historyPath ?? join56(homedir19(), ".mma", "repl-history");
42697
43777
  this.loadHistory();
42698
43778
  const editorCompleter = (line) => {
42699
43779
  const [matches, partial] = this.completer.complete(line);
@@ -42747,6 +43827,7 @@ class Repl {
42747
43827
  });
42748
43828
  this.agent.setPromptIO?.(this.promptIO);
42749
43829
  registerAllCommands(this);
43830
+ this.configSnapshot = captureConfigSnapshot(this.config);
42750
43831
  this.setupCompleter();
42751
43832
  this.setupListeners();
42752
43833
  if (pluginManager) {
@@ -42807,9 +43888,9 @@ class Repl {
42807
43888
  }
42808
43889
  saveHistory() {
42809
43890
  try {
42810
- mkdirSync25(dirname26(this.historyPath), { recursive: true });
43891
+ mkdirSync27(dirname26(this.historyPath), { recursive: true });
42811
43892
  const allHistory = this.history.slice(-this.maxHistory);
42812
- writeFileSync24(this.historyPath, allHistory.join(`
43893
+ writeFileSync26(this.historyPath, allHistory.join(`
42813
43894
  `), "utf-8");
42814
43895
  } catch (e) {
42815
43896
  this.logger?.debug(`Failed to save REPL history: ${e.message}`);
@@ -42820,14 +43901,59 @@ class Repl {
42820
43901
  const slashCommands = buildSlashCompletions(this.commands);
42821
43902
  this.completer.registerProvider(new SlashCommandProvider(slashCommands));
42822
43903
  if (this.sessionManager) {
42823
- this.completer.registerProvider(new SessionNameProvider(() => this.sessionManager.list().map((s) => s.name)));
43904
+ this.completer.registerProvider(new SessionNameProvider(() => this.sessionManager.list().map((s) => s.name), [
43905
+ "/resume",
43906
+ "/delete",
43907
+ "/export"
43908
+ ]));
42824
43909
  }
42825
43910
  if (this.skillsModule) {
42826
- this.completer.registerProvider(new SubcommandProvider("skill", ["list", "loaded", "load", "unload", "search"]));
43911
+ this.completer.registerProvider(new SubcommandProvider("skill", [
43912
+ { name: "list", description: t("skill.sub_list") },
43913
+ { name: "loaded", description: t("skill.sub_loaded") },
43914
+ { name: "load", description: t("skill.sub_load") },
43915
+ { name: "unload", description: t("skill.sub_unload") },
43916
+ { name: "search", description: t("skill.sub_search") }
43917
+ ]));
42827
43918
  this.completer.registerProvider(new SkillNameProvider(this.skillsModule));
42828
43919
  }
42829
- this.completer.registerProvider(new SubcommandProvider("provider", ["list", "use", "add"]));
42830
- this.completer.registerProvider(new SubcommandProvider("model", ["list", "use"]));
43920
+ this.completer.registerProvider(new SubcommandProvider("provider", [
43921
+ { name: "list", description: t("provider.sub_list") },
43922
+ { name: "use", description: t("provider.sub_use") },
43923
+ { name: "add", description: t("provider.sub_add") }
43924
+ ]));
43925
+ this.completer.registerProvider(new SubcommandProvider("model", [
43926
+ { name: "list", description: t("model.sub_list") },
43927
+ { name: "use", description: t("model.sub_use") }
43928
+ ]));
43929
+ this.completer.registerProvider(new SubcommandProvider("map", [
43930
+ { name: "summary", description: t("map.sub_summary") },
43931
+ { name: "refresh", description: t("map.sub_refresh") },
43932
+ { name: "find", description: t("map.sub_find") }
43933
+ ]));
43934
+ this.completer.registerProvider(new SubcommandProvider("context", [
43935
+ { name: "system", description: t("context.sub_system") },
43936
+ { name: "reserve", description: t("context.sub_reserve") }
43937
+ ]));
43938
+ this.completer.registerProvider(new SubcommandProvider("lsp", [
43939
+ { name: "status", description: t("lsp.sub_status") },
43940
+ { name: "restart", description: t("lsp.sub_restart") },
43941
+ { name: "check", description: t("lsp.sub_check") }
43942
+ ]));
43943
+ this.completer.registerProvider(new SubcommandProvider("reasoning", [
43944
+ { name: "show", description: t("reasoning.sub_show") },
43945
+ { name: "hide", description: t("reasoning.sub_hide") },
43946
+ { name: "level", description: t("reasoning.sub_level") }
43947
+ ]));
43948
+ this.completer.registerProvider(new SubcommandProvider("verbose", [
43949
+ { name: "quiet", description: t("verbose.sub_quiet") },
43950
+ { name: "normal", description: t("verbose.sub_normal") },
43951
+ { name: "verbose", description: t("verbose.sub_verbose") }
43952
+ ]));
43953
+ this.completer.registerProvider(new ConfigKeyProvider);
43954
+ this.completer.registerProvider(new ConfigValueProvider);
43955
+ this.completer.registerProvider(new FlagProvider);
43956
+ this.completer.registerProvider(new CommandArgProvider(() => Array.from(this.commands.entries()).filter(([key, cmd]) => key === cmd.name).map(([, cmd]) => cmd.name)));
42831
43957
  const entryLabels = this.config.provider?.entries?.map((e) => e.label || e.type) ?? [];
42832
43958
  if (entryLabels.length > 0) {
42833
43959
  this.completer.registerProvider(new ProviderArgProvider(entryLabels));
@@ -42836,6 +43962,17 @@ class Repl {
42836
43962
  this.completer.registerProvider(new FilePathProvider(this.baseDir));
42837
43963
  this.refreshModelCache();
42838
43964
  }
43965
+ reregisterCommands() {
43966
+ this.commands.clear();
43967
+ registerAllCommands(this);
43968
+ this.setupCompleter();
43969
+ }
43970
+ getConfigSnapshot() {
43971
+ return this.configSnapshot;
43972
+ }
43973
+ knownModels() {
43974
+ return this.modelCache;
43975
+ }
42839
43976
  refreshModelCache() {
42840
43977
  (async () => {
42841
43978
  try {
@@ -43182,7 +44319,13 @@ ${divider()}`);
43182
44319
  this.runHandledPrompt = false;
43183
44320
  const cmd = this.commands.get(name);
43184
44321
  if (!cmd) {
43185
- this.output.writeLine(`${pc.red(t("cli.unknown_cmd", { name }))} ${t("cli.help_hint")}`);
44322
+ const formerAliases = { use: "resume" };
44323
+ const suggestion = formerAliases[name];
44324
+ if (suggestion) {
44325
+ this.output.writeLine(pc.red(t("cli.unknown_command", { input: `/${name}`, suggestion: `/${suggestion}` })));
44326
+ } else {
44327
+ this.output.writeLine(`${pc.red(t("cli.unknown_cmd", { name }))} ${t("cli.help_hint")}`);
44328
+ }
43186
44329
  return;
43187
44330
  }
43188
44331
  try {
@@ -43193,8 +44336,29 @@ ${divider()}`);
43193
44336
  })), "stderr");
43194
44337
  }
43195
44338
  }
43196
- showHelp() {
44339
+ showHelp(command) {
43197
44340
  const { COMMAND_GROUPS: COMMAND_GROUPS2 } = (init_repl_commands(), __toCommonJS(exports_repl_commands));
44341
+ if (command) {
44342
+ const name = command.replace(/^\//, "");
44343
+ const cmd = this.commands.get(name);
44344
+ if (!cmd) {
44345
+ this.output.writeLine(pc.red(t("repl.help_unknown", { name })));
44346
+ return;
44347
+ }
44348
+ this.output.writeLine(pc.bold(pc.cyan("/" + cmd.name)));
44349
+ this.output.writeLine(` ${cmd.description}`);
44350
+ if (cmd.usage)
44351
+ this.output.writeLine(` ${pc.dim(cmd.usage)}`);
44352
+ if (cmd.aliases?.length) {
44353
+ this.output.writeLine(pc.dim(` ${t("repl.help_aliases", { names: cmd.aliases.join(", ") })}`));
44354
+ }
44355
+ if (cmd.examples?.length) {
44356
+ this.output.writeLine(pc.dim(` ${t("repl.help_examples")}`));
44357
+ for (const ex of cmd.examples)
44358
+ this.output.writeLine(pc.dim(` ${ex}`));
44359
+ }
44360
+ return;
44361
+ }
43198
44362
  const order = ["general", "agent", "session", "skill"];
43199
44363
  const seen = new Set;
43200
44364
  for (const groupKey of order) {
@@ -43405,6 +44569,9 @@ ${line}`);
43405
44569
  }
43406
44570
  }
43407
44571
 
44572
+ // src/cli/main.ts
44573
+ init_theme();
44574
+
43408
44575
  // src/cli/run-result.ts
43409
44576
  init_i18n();
43410
44577
  init_colors();
@@ -43498,7 +44665,7 @@ init_i18n();
43498
44665
  init_colors();
43499
44666
  import { existsSync as existsSync62 } from "fs";
43500
44667
  import { join as join58, dirname as dirname27 } from "path";
43501
- import { homedir as homedir20 } from "os";
44668
+ import { homedir as homedir21 } from "os";
43502
44669
  import { fileURLToPath as fileURLToPath6 } from "url";
43503
44670
 
43504
44671
  // src/modules/updater/index.ts
@@ -43618,10 +44785,10 @@ init_environment();
43618
44785
  init_data_sanitizer();
43619
44786
  init_i18n();
43620
44787
  init_utils();
43621
- import { appendFileSync as appendFileSync8, mkdirSync as mkdirSync26 } from "fs";
44788
+ import { appendFileSync as appendFileSync8, mkdirSync as mkdirSync28 } from "fs";
43622
44789
  import { join as join57 } from "path";
43623
- import { homedir as homedir19 } from "os";
43624
- var CRASH_LOG_DIR = join57(homedir19(), ".mma", "logs");
44790
+ import { homedir as homedir20 } from "os";
44791
+ var CRASH_LOG_DIR = join57(homedir20(), ".mma", "logs");
43625
44792
  var CRASH_LOG_FILE = "crash.jsonl";
43626
44793
  function formatCrashEntry(type2, err) {
43627
44794
  const message = errMsg(err);
@@ -43631,12 +44798,12 @@ function formatCrashEntry(type2, err) {
43631
44798
  type: type2,
43632
44799
  message: sanitizeLogMessage(message),
43633
44800
  stack: sanitizeLogMessage(stack),
43634
- environment: collectEnvironment({ configDir: homedir19(), scanTools: false })
44801
+ environment: collectEnvironment({ configDir: homedir20(), scanTools: false })
43635
44802
  };
43636
44803
  }
43637
44804
  function writeCrashEntry(dir, entry) {
43638
44805
  try {
43639
- mkdirSync26(dir, { recursive: true });
44806
+ mkdirSync28(dir, { recursive: true });
43640
44807
  appendFileSync8(join57(dir, CRASH_LOG_FILE), JSON.stringify(entry) + `
43641
44808
  `, "utf-8");
43642
44809
  } catch {}
@@ -43765,7 +44932,7 @@ async function main() {
43765
44932
  }
43766
44933
  const jsonSink = jsonOpt ? new JsonOutputSink(defaultOutputBus) : undefined;
43767
44934
  const prompt = program2.args.join(" ");
43768
- const mmaDir = process.env.MMA_CONFIG_DIR || join58(homedir20(), ".mma");
44935
+ const mmaDir = process.env.MMA_CONFIG_DIR || join58(homedir21(), ".mma");
43769
44936
  const { hasDomainFiles: hasDomainFiles2 } = await Promise.resolve().then(() => (init_domains(), exports_domains));
43770
44937
  const virgin = !existsSync62(join58(mmaDir, "config.json")) && !hasDomainFiles2(mmaDir);
43771
44938
  const { agent, config, baseDir, legacyDetected, contextProbe } = await bootstrap(undefined, projectDir, noAgentsMd, exitOnComplete, reasoningLevel, contextLog);
@@ -43853,7 +45020,7 @@ async function main() {
43853
45020
  await updater?.waitForIdle();
43854
45021
  process.exit(exitCode);
43855
45022
  } else {
43856
- const mmaDir = process.env.MMA_CONFIG_DIR || join58(homedir20(), ".mma");
45023
+ const mmaDir = process.env.MMA_CONFIG_DIR || join58(homedir21(), ".mma");
43857
45024
  const legacyConfigPath = join58(mmaDir, "config.json");
43858
45025
  let hasAnyConfig = existsSync62(legacyConfigPath);
43859
45026
  if (!hasAnyConfig) {