archymedes-cli 3.0.0 → 3.2.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.
@@ -1,1119 +0,0 @@
1
- import {
2
- GUTTER,
3
- clip,
4
- note,
5
- panel,
6
- rule
7
- } from "./archymedes-2emwtckp.mjs";
8
- import {
9
- BOLD,
10
- DIM,
11
- UNICODE_GLYPHS,
12
- paint,
13
- paintAll,
14
- visibleWidth
15
- } from "./archymedes-y64yssbc.mjs";
16
-
17
- // packages/archymedes-cli/src/platform/i18n.ts
18
- var CONTROL_LANGUAGES = {
19
- en: "English",
20
- zh: "中文 (Mandarin)",
21
- hi: "हिन्दी",
22
- es: "Español",
23
- fr: "Français",
24
- ar: "العربية",
25
- bn: "বাংলা",
26
- pt: "Português",
27
- ru: "Русский",
28
- ur: "اردو",
29
- ja: "日本語",
30
- ko: "한국어",
31
- de: "Deutsch",
32
- id: "Bahasa Indonesia",
33
- vi: "Tiếng Việt",
34
- tr: "Türkçe"
35
- };
36
- function resolveControlLanguage(value) {
37
- const normalized = value?.trim().toLowerCase().replace("_", "-") ?? "";
38
- const base = normalized.split("-")[0];
39
- return base in CONTROL_LANGUAGES ? base : "en";
40
- }
41
- var LABELS = {
42
- en: { help: "commands", guide: "guide", exit: "leave", settings: "settings", voice: "voice", choose: "Choose a setting", saved: "saved", keyboard: "Keyboard shortcuts", remember: "remember" },
43
- zh: { help: "命令", guide: "指南", exit: "退出", settings: "设置", voice: "语音", choose: "选择设置", saved: "已保存", keyboard: "键盘快捷键", remember: "记住" },
44
- hi: { help: "कमांड", guide: "गाइड", exit: "बाहर निकलें", settings: "सेटिंग्स", voice: "आवाज़", choose: "सेटिंग चुनें", saved: "सहेजा गया", keyboard: "कीबोर्ड शॉर्टकट", remember: "याद रखें" },
45
- es: { help: "comandos", guide: "guía", exit: "salir", settings: "ajustes", voice: "voz", choose: "Elige un ajuste", saved: "guardado", keyboard: "Atajos de teclado", remember: "recordar" },
46
- fr: { help: "commandes", guide: "guide", exit: "quitter", settings: "réglages", voice: "voix", choose: "Choisissez un réglage", saved: "enregistré", keyboard: "Raccourcis clavier", remember: "mémoriser" },
47
- ar: { help: "الأوامر", guide: "دليل", exit: "خروج", settings: "الإعدادات", voice: "الصوت", choose: "اختر إعدادًا", saved: "تم الحفظ", keyboard: "اختصارات لوحة المفاتيح", remember: "تذكّر" },
48
- bn: { help: "কমান্ড", guide: "গাইড", exit: "প্রস্থান", settings: "সেটিংস", voice: "ভয়েস", choose: "একটি সেটিং বেছে নিন", saved: "সংরক্ষিত", keyboard: "কীবোর্ড শর্টকাট", remember: "মনে রাখুন" },
49
- pt: { help: "comandos", guide: "guia", exit: "sair", settings: "configurações", voice: "voz", choose: "Escolha uma configuração", saved: "salvo", keyboard: "Atalhos de teclado", remember: "lembrar" },
50
- ru: { help: "команды", guide: "руководство", exit: "выход", settings: "настройки", voice: "голос", choose: "Выберите настройку", saved: "сохранено", keyboard: "Горячие клавиши", remember: "запомнить" },
51
- ur: { help: "کمانڈز", guide: "گائیڈ", exit: "باہر نکلیں", settings: "ترتیبات", voice: "آواز", choose: "ترتیب منتخب کریں", saved: "محفوظ ہوگیا", keyboard: "کی بورڈ شارٹ کٹس", remember: "یاد رکھیں" },
52
- ja: { help: "コマンド", guide: "ガイド", exit: "終了", settings: "設定", voice: "音声", choose: "設定を選択", saved: "保存しました", keyboard: "キーボードショートカット", remember: "記憶" },
53
- ko: { help: "명령", guide: "가이드", exit: "종료", settings: "설정", voice: "음성", choose: "설정 선택", saved: "저장됨", keyboard: "키보드 단축키", remember: "기억" },
54
- de: { help: "Befehle", guide: "Anleitung", exit: "beenden", settings: "Einstellungen", voice: "Sprache", choose: "Einstellung wählen", saved: "gespeichert", keyboard: "Tastenkürzel", remember: "merken" },
55
- id: { help: "perintah", guide: "panduan", exit: "keluar", settings: "pengaturan", voice: "suara", choose: "Pilih pengaturan", saved: "tersimpan", keyboard: "Pintasan keyboard", remember: "ingat" },
56
- vi: { help: "lệnh", guide: "hướng dẫn", exit: "thoát", settings: "cài đặt", voice: "giọng nói", choose: "Chọn một cài đặt", saved: "đã lưu", keyboard: "Phím tắt", remember: "ghi nhớ" },
57
- tr: { help: "komutlar", guide: "kılavuz", exit: "çık", settings: "ayarlar", voice: "ses", choose: "Bir ayar seçin", saved: "kaydedildi", keyboard: "Klavye kısayolları", remember: "hatırla" }
58
- };
59
- function controlLabel(language, key) {
60
- return LABELS[language][key];
61
- }
62
- var COMMANDS = {
63
- zh: { "/plan": "切换到只读规划模式", "/build": "切换到需批准的构建模式", "/auto": "自动应用编辑", "/model": "切换模型并保留上下文", "/undo": "撤销上一轮更改", "/diff": "显示最近更改", "/todos": "显示代理计划", "/clear": "开始新对话", "/pull": "复制沙箱文件", "/where": "显示当前工作区", "/providers": "显示模型提供商", "/settings": "配置密钥、网址、模型和语音", "/voice": "录音或转写语音提示", "/cost": "显示令牌和费用", "/sessions": "列出项目会话", "/keys": "键盘快捷键", "/help": "显示命令", "/exit": "退出" },
64
- hi: { "/plan": "केवल-पढ़ने की योजना मोड", "/build": "अनुमति वाला बिल्ड मोड", "/auto": "संपादन अपने-आप लागू करें", "/model": "संदर्भ रखते हुए मॉडल बदलें", "/undo": "पिछले बदलाव वापस लें", "/diff": "हाल के बदलाव दिखाएँ", "/todos": "एजेंट की योजना", "/clear": "नई बातचीत", "/pull": "सैंडबॉक्स फ़ाइलें कॉपी करें", "/where": "वर्तमान वर्कस्पेस", "/providers": "मॉडल प्रदाता", "/settings": "कुंजियाँ, URL, मॉडल और आवाज़", "/voice": "आवाज़ रिकॉर्ड या ट्रांसक्राइब करें", "/cost": "टोकन और लागत", "/sessions": "प्रोजेक्ट सत्र", "/keys": "कीबोर्ड शॉर्टकट", "/help": "कमांड दिखाएँ", "/exit": "बाहर निकलें" },
65
- es: { "/plan": "Modo de planificación de solo lectura", "/build": "Modo de cambios con aprobación", "/auto": "Aplicar cambios automáticamente", "/model": "Cambiar modelo conservando el contexto", "/undo": "Deshacer los últimos cambios", "/diff": "Mostrar cambios recientes", "/todos": "Mostrar el plan del agente", "/clear": "Iniciar una conversación nueva", "/pull": "Copiar archivos del entorno aislado", "/where": "Mostrar el espacio de trabajo", "/providers": "Mostrar proveedores de modelos", "/settings": "Configurar claves, URL, modelos y voz", "/voice": "Grabar o transcribir una instrucción", "/cost": "Mostrar tokens y coste", "/sessions": "Listar sesiones del proyecto", "/keys": "Atajos de teclado", "/help": "Mostrar comandos", "/exit": "Salir" },
66
- fr: { "/plan": "Mode planification en lecture seule", "/build": "Mode modification avec approbation", "/auto": "Appliquer les modifications automatiquement", "/model": "Changer de modèle en gardant le contexte", "/undo": "Annuler les dernières modifications", "/diff": "Afficher les changements récents", "/todos": "Afficher le plan de l’agent", "/clear": "Nouvelle conversation", "/pull": "Copier les fichiers du bac à sable", "/where": "Afficher l’espace de travail", "/providers": "Afficher les fournisseurs de modèles", "/settings": "Configurer clés, URL, modèles et voix", "/voice": "Enregistrer ou transcrire une demande", "/cost": "Afficher jetons et coût", "/sessions": "Lister les sessions du projet", "/keys": "Raccourcis clavier", "/help": "Afficher les commandes", "/exit": "Quitter" },
67
- ar: { "/plan": "وضع التخطيط للقراءة فقط", "/build": "وضع التعديل مع الموافقة", "/auto": "تطبيق التعديلات تلقائيًا", "/model": "تغيير النموذج مع حفظ السياق", "/undo": "التراجع عن آخر التعديلات", "/diff": "عرض التغييرات الأخيرة", "/todos": "عرض خطة الوكيل", "/clear": "بدء محادثة جديدة", "/pull": "نسخ ملفات البيئة المعزولة", "/where": "عرض مساحة العمل", "/providers": "عرض مزودي النماذج", "/settings": "إعداد المفاتيح والروابط والنماذج والصوت", "/voice": "تسجيل أو تحويل الصوت إلى نص", "/cost": "عرض الرموز والتكلفة", "/sessions": "عرض جلسات المشروع", "/keys": "اختصارات لوحة المفاتيح", "/help": "عرض الأوامر", "/exit": "خروج" },
68
- bn: { "/plan": "শুধু-পঠন পরিকল্পনা মোড", "/build": "অনুমোদনসহ বিল্ড মোড", "/auto": "সম্পাদনা স্বয়ংক্রিয়ভাবে প্রয়োগ", "/model": "প্রসঙ্গ রেখে মডেল বদলান", "/undo": "শেষ পরিবর্তন ফিরিয়ে নিন", "/diff": "সাম্প্রতিক পরিবর্তন দেখান", "/todos": "এজেন্টের পরিকল্পনা", "/clear": "নতুন আলাপ", "/pull": "স্যান্ডবক্স ফাইল কপি", "/where": "বর্তমান ওয়ার্কস্পেস", "/providers": "মডেল প্রদানকারী", "/settings": "কী, URL, মডেল ও ভয়েস", "/voice": "ভয়েস রেকর্ড বা ট্রান্সক্রাইব", "/cost": "টোকেন ও খরচ", "/sessions": "প্রজেক্ট সেশন", "/keys": "কীবোর্ড শর্টকাট", "/help": "কমান্ড দেখান", "/exit": "প্রস্থান" },
69
- pt: { "/plan": "Modo de planejamento somente leitura", "/build": "Modo de alterações com aprovação", "/auto": "Aplicar alterações automaticamente", "/model": "Trocar modelo mantendo o contexto", "/undo": "Desfazer últimas alterações", "/diff": "Mostrar alterações recentes", "/todos": "Mostrar plano do agente", "/clear": "Nova conversa", "/pull": "Copiar arquivos do sandbox", "/where": "Mostrar espaço de trabalho", "/providers": "Mostrar provedores de modelos", "/settings": "Configurar chaves, URLs, modelos e voz", "/voice": "Gravar ou transcrever uma solicitação", "/cost": "Mostrar tokens e custo", "/sessions": "Listar sessões do projeto", "/keys": "Atalhos de teclado", "/help": "Mostrar comandos", "/exit": "Sair" },
70
- ru: { "/plan": "Режим планирования без записи", "/build": "Режим изменений с подтверждением", "/auto": "Применять изменения автоматически", "/model": "Сменить модель, сохранив контекст", "/undo": "Отменить последние изменения", "/diff": "Показать последние изменения", "/todos": "Показать план агента", "/clear": "Новый диалог", "/pull": "Скопировать файлы из песочницы", "/where": "Показать рабочую область", "/providers": "Показать провайдеров моделей", "/settings": "Настроить ключи, URL, модели и голос", "/voice": "Записать или распознать запрос", "/cost": "Показать токены и стоимость", "/sessions": "Список сессий проекта", "/keys": "Горячие клавиши", "/help": "Показать команды", "/exit": "Выход" },
71
- ur: { "/plan": "صرف پڑھنے کا منصوبہ موڈ", "/build": "منظوری کے ساتھ بلڈ موڈ", "/auto": "تبدیلیاں خودکار لگائیں", "/model": "سیاق رکھتے ہوئے ماڈل بدلیں", "/undo": "آخری تبدیلی واپس کریں", "/diff": "حالیہ تبدیلیاں دکھائیں", "/todos": "ایجنٹ کا منصوبہ", "/clear": "نئی گفتگو", "/pull": "سینڈباکس فائلیں نقل کریں", "/where": "ورک اسپیس دکھائیں", "/providers": "ماڈل فراہم کنندگان", "/settings": "کلیدیں، URLs، ماڈلز اور آواز", "/voice": "آواز ریکارڈ یا متن میں بدلیں", "/cost": "ٹوکن اور لاگت", "/sessions": "پروجیکٹ سیشن", "/keys": "کی بورڈ شارٹ کٹس", "/help": "کمانڈز دکھائیں", "/exit": "باہر نکلیں" },
72
- ja: { "/plan": "読み取り専用の計画モード", "/build": "承認付きのビルドモード", "/auto": "編集を自動で適用", "/model": "コンテキストを保ったままモデルを切り替え", "/undo": "前のターンの変更を取り消す", "/diff": "最近の変更を表示", "/todos": "エージェントの計画を表示", "/clear": "新しい会話を開始", "/pull": "サンドボックスのファイルをコピー", "/where": "現在のワークスペースを表示", "/providers": "モデルプロバイダーを表示", "/settings": "キー・URL・モデル・音声を設定", "/voice": "音声プロンプトを録音または文字起こし", "/cost": "トークンとコストを表示", "/sessions": "プロジェクトのセッション一覧", "/keys": "キーボードショートカット", "/help": "コマンドを表示", "/exit": "終了" },
73
- ko: { "/plan": "읽기 전용 계획 모드", "/build": "승인이 필요한 빌드 모드", "/auto": "편집 자동 적용", "/model": "컨텍스트를 유지한 채 모델 전환", "/undo": "마지막 턴의 변경 취소", "/diff": "최근 변경 사항 표시", "/todos": "에이전트 계획 표시", "/clear": "새 대화 시작", "/pull": "샌드박스 파일 복사", "/where": "현재 작업 공간 표시", "/providers": "모델 제공자 표시", "/settings": "키, URL, 모델, 음성 설정", "/voice": "음성 프롬프트 녹음 또는 전사", "/cost": "토큰과 비용 표시", "/sessions": "프로젝트 세션 목록", "/keys": "키보드 단축키", "/help": "명령 표시", "/exit": "종료" },
74
- de: { "/plan": "Nur-Lese-Planungsmodus", "/build": "Änderungsmodus mit Bestätigung", "/auto": "Änderungen automatisch übernehmen", "/model": "Modell wechseln und Kontext behalten", "/undo": "Letzte Änderungen zurücknehmen", "/diff": "Letzte Änderungen anzeigen", "/todos": "Plan des Agenten anzeigen", "/clear": "Neues Gespräch beginnen", "/pull": "Dateien aus der Sandbox kopieren", "/where": "Aktuellen Arbeitsbereich anzeigen", "/providers": "Modellanbieter anzeigen", "/settings": "Schlüssel, URLs, Modelle und Spracheingabe", "/voice": "Sprachaufforderung aufnehmen oder transkribieren", "/cost": "Tokens und Kosten anzeigen", "/sessions": "Projektsitzungen auflisten", "/keys": "Tastenkürzel", "/help": "Befehle anzeigen", "/exit": "Beenden" },
75
- id: { "/plan": "Mode perencanaan hanya-baca", "/build": "Mode perubahan dengan persetujuan", "/auto": "Terapkan perubahan otomatis", "/model": "Ganti model sambil menjaga konteks", "/undo": "Batalkan perubahan giliran terakhir", "/diff": "Tampilkan perubahan terbaru", "/todos": "Tampilkan rencana agen", "/clear": "Mulai percakapan baru", "/pull": "Salin berkas sandbox", "/where": "Tampilkan ruang kerja saat ini", "/providers": "Tampilkan penyedia model", "/settings": "Atur kunci, URL, model, dan suara", "/voice": "Rekam atau transkripsikan perintah suara", "/cost": "Tampilkan token dan biaya", "/sessions": "Daftar sesi proyek", "/keys": "Pintasan keyboard", "/help": "Tampilkan perintah", "/exit": "Keluar" },
76
- vi: { "/plan": "Chế độ lập kế hoạch chỉ đọc", "/build": "Chế độ thay đổi cần phê duyệt", "/auto": "Tự động áp dụng chỉnh sửa", "/model": "Đổi mô hình mà vẫn giữ ngữ cảnh", "/undo": "Hoàn tác thay đổi của lượt trước", "/diff": "Hiển thị thay đổi gần đây", "/todos": "Hiển thị kế hoạch của tác nhân", "/clear": "Bắt đầu cuộc trò chuyện mới", "/pull": "Sao chép tệp từ sandbox", "/where": "Hiển thị không gian làm việc hiện tại", "/providers": "Hiển thị nhà cung cấp mô hình", "/settings": "Cấu hình khóa, URL, mô hình và giọng nói", "/voice": "Ghi âm hoặc chuyển lời nhắc thành văn bản", "/cost": "Hiển thị token và chi phí", "/sessions": "Liệt kê phiên của dự án", "/keys": "Phím tắt", "/help": "Hiển thị các lệnh", "/exit": "Thoát" },
77
- tr: { "/plan": "Salt okunur planlama modu", "/build": "Onaylı değişiklik modu", "/auto": "Değişiklikleri otomatik uygula", "/model": "Bağlamı koruyarak modeli değiştir", "/undo": "Son turun değişikliklerini geri al", "/diff": "Son değişiklikleri göster", "/todos": "Aracının planını göster", "/clear": "Yeni bir konuşma başlat", "/pull": "Sanal alan dosyalarını kopyala", "/where": "Geçerli çalışma alanını göster", "/providers": "Model sağlayıcılarını göster", "/settings": "Anahtarları, URL'leri, modelleri ve sesi ayarla", "/voice": "Sesli istemi kaydet veya yazıya dök", "/cost": "Belirteç ve maliyeti göster", "/sessions": "Proje oturumlarını listele", "/keys": "Klavye kısayolları", "/help": "Komutları göster", "/exit": "Çık" }
78
- };
79
- function commandDescription(language, command, fallback) {
80
- return COMMANDS[language]?.[command] ?? fallback;
81
- }
82
- var TRANSLATED_KEYBOARD_IDS = {
83
- zh: { "complete-command": "补全斜杠命令", "complete-path": "补全项目文件路径", history: "搜索历史输入", "line-ends": "移到输入开头 / 结尾", delete: "删除前一词 / 全部输入", clear: "清屏并重绘", interrupt: "中断当前任务", voice: "从麦克风录入提示" },
84
- hi: { "complete-command": "स्लैश कमांड पूरा करें", "complete-path": "प्रोजेक्ट फ़ाइल पथ पूरा करें", history: "पुराना इनपुट खोजें", "line-ends": "इनपुट की शुरुआत / अंत", delete: "पिछला शब्द / पूरा इनपुट मिटाएँ", clear: "टर्मिनल साफ़ करें", interrupt: "वर्तमान काम रोकें", voice: "माइक्रोफ़ोन से प्रॉम्प्ट रिकॉर्ड करें" },
85
- es: { "complete-command": "Completar un comando", "complete-path": "Completar una ruta del proyecto", history: "Buscar en el historial", "line-ends": "Ir al inicio / final", delete: "Borrar palabra / entrada completa", clear: "Limpiar la terminal", interrupt: "Interrumpir la tarea actual", voice: "Grabar desde el micrófono" },
86
- fr: { "complete-command": "Compléter une commande", "complete-path": "Compléter un chemin du projet", history: "Rechercher dans l’historique", "line-ends": "Début / fin de la saisie", delete: "Effacer le mot / toute la saisie", clear: "Effacer le terminal", interrupt: "Interrompre la tâche", voice: "Enregistrer avec le microphone" },
87
- ar: { "complete-command": "إكمال أمر", "complete-path": "إكمال مسار ملف المشروع", history: "البحث في السجل", "line-ends": "بداية / نهاية الإدخال", delete: "حذف الكلمة / كامل الإدخال", clear: "مسح الطرفية", interrupt: "إيقاف المهمة الحالية", voice: "تسجيل الطلب من الميكروفون" },
88
- bn: { "complete-command": "স্ল্যাশ কমান্ড পূরণ", "complete-path": "প্রজেক্ট ফাইল পথ পূরণ", history: "ইতিহাস খুঁজুন", "line-ends": "ইনপুটের শুরু / শেষ", delete: "আগের শব্দ / সব ইনপুট মুছুন", clear: "টার্মিনাল পরিষ্কার", interrupt: "বর্তমান কাজ থামান", voice: "মাইক্রোফোন থেকে রেকর্ড" },
89
- pt: { "complete-command": "Completar um comando", "complete-path": "Completar caminho do projeto", history: "Pesquisar histórico", "line-ends": "Ir ao início / fim", delete: "Apagar palavra / entrada inteira", clear: "Limpar o terminal", interrupt: "Interromper a tarefa", voice: "Gravar pelo microfone" },
90
- ru: { "complete-command": "Дополнить команду", "complete-path": "Дополнить путь к файлу", history: "Искать в истории", "line-ends": "В начало / конец строки", delete: "Удалить слово / всю строку", clear: "Очистить терминал", interrupt: "Прервать задачу", voice: "Записать запрос с микрофона" },
91
- ur: { "complete-command": "سلیش کمانڈ مکمل کریں", "complete-path": "پروجیکٹ فائل کا راستہ مکمل کریں", history: "تاریخ تلاش کریں", "line-ends": "ان پٹ کے شروع / آخر جائیں", delete: "پچھلا لفظ / پوری سطر مٹائیں", clear: "ٹرمینل صاف کریں", interrupt: "موجودہ کام روکیں", voice: "مائیکروفون سے ریکارڈ کریں" },
92
- ja: { "complete-command": "スラッシュコマンドを補完", "complete-path": "プロジェクトのファイルパスを補完", history: "入力履歴を検索", "line-ends": "入力の先頭 / 末尾へ", delete: "前の単語 / 入力全体を削除", clear: "画面をクリアして再描画", interrupt: "現在のタスクを中断", voice: "マイクからプロンプトを録音" },
93
- ko: { "complete-command": "슬래시 명령 자동완성", "complete-path": "프로젝트 파일 경로 자동완성", history: "입력 기록 검색", "line-ends": "입력의 처음 / 끝으로", delete: "이전 단어 / 전체 입력 삭제", clear: "화면 지우고 다시 그리기", interrupt: "현재 작업 중단", voice: "마이크로 프롬프트 녹음" },
94
- de: { "complete-command": "Slash-Befehl vervollständigen", "complete-path": "Projektdateipfad vervollständigen", history: "Eingabeverlauf durchsuchen", "line-ends": "An Anfang / Ende der Eingabe", delete: "Vorheriges Wort / gesamte Eingabe löschen", clear: "Terminal leeren und neu zeichnen", interrupt: "Aktuelle Aufgabe abbrechen", voice: "Prompt über das Mikrofon aufnehmen" },
95
- id: { "complete-command": "Lengkapi perintah garis miring", "complete-path": "Lengkapi jalur berkas proyek", history: "Cari riwayat masukan", "line-ends": "Ke awal / akhir masukan", delete: "Hapus kata sebelumnya / seluruh masukan", clear: "Bersihkan terminal dan gambar ulang", interrupt: "Hentikan tugas saat ini", voice: "Rekam prompt dari mikrofon" },
96
- vi: { "complete-command": "Hoàn thành lệnh gạch chéo", "complete-path": "Hoàn thành đường dẫn tệp dự án", history: "Tìm trong lịch sử nhập", "line-ends": "Về đầu / cuối dòng nhập", delete: "Xóa từ trước / toàn bộ dòng nhập", clear: "Xóa và vẽ lại màn hình", interrupt: "Dừng tác vụ hiện tại", voice: "Ghi âm lời nhắc từ micro" },
97
- tr: { "complete-command": "Eğik çizgi komutunu tamamla", "complete-path": "Proje dosya yolunu tamamla", history: "Girdi geçmişinde ara", "line-ends": "Girdinin başına / sonuna git", delete: "Önceki kelimeyi / tüm girdiyi sil", clear: "Terminali temizle ve yeniden çiz", interrupt: "Geçerli görevi durdur", voice: "Mikrofondan istem kaydet" }
98
- };
99
- function keyboardDescription(language, id, fallback) {
100
- return TRANSLATED_KEYBOARD_IDS[language]?.[id] ?? fallback;
101
- }
102
- var MESSAGES = {
103
- tagline: {
104
- en: "a coding agent that shows its work",
105
- zh: "会展示推导过程的编码代理",
106
- hi: "अपना काम दिखाने वाला कोडिंग एजेंट",
107
- es: "un agente de programación que muestra su razonamiento",
108
- fr: "un agent de codage qui montre son raisonnement",
109
- ar: "وكيل برمجة يُظهر خطوات عمله",
110
- bn: "যে কোডিং এজেন্ট তার কাজ দেখায়",
111
- pt: "um agente de programação que mostra seu raciocínio",
112
- ru: "агент-программист, который показывает ход решения",
113
- ur: "ایک کوڈنگ ایجنٹ جو اپنا کام دکھاتا ہے",
114
- ja: "途中の考え方まで示すコーディングエージェント",
115
- ko: "풀이 과정을 보여주는 코딩 에이전트",
116
- de: "ein Coding-Agent, der seinen Rechenweg zeigt",
117
- id: "agen pemrograman yang menunjukkan cara kerjanya",
118
- vi: "một tác nhân lập trình trình bày cách làm",
119
- tr: "yaptığı işi adım adım gösteren bir kodlama aracı"
120
- },
121
- "help.startHere": {
122
- en: "Start here",
123
- zh: "从这里开始",
124
- hi: "यहाँ से शुरू करें",
125
- es: "Empieza aquí",
126
- fr: "Commencez ici",
127
- ar: "ابدأ من هنا",
128
- bn: "এখান থেকে শুরু করুন",
129
- pt: "Comece aqui",
130
- ru: "Начните здесь",
131
- ur: "یہاں سے شروع کریں",
132
- ja: "ここから始める",
133
- ko: "여기서 시작",
134
- de: "Hier anfangen",
135
- id: "Mulai di sini",
136
- vi: "Bắt đầu tại đây",
137
- tr: "Buradan başlayın"
138
- },
139
- "help.running": {
140
- en: "Running it",
141
- zh: "运行方式",
142
- hi: "इसे चलाना",
143
- es: "Cómo ejecutarlo",
144
- fr: "L'exécuter",
145
- ar: "طريقة التشغيل",
146
- bn: "এটি চালানো",
147
- pt: "Como executar",
148
- ru: "Как запускать",
149
- ur: "اسے چلانا",
150
- ja: "実行する",
151
- ko: "실행하기",
152
- de: "Ausführen",
153
- id: "Menjalankannya",
154
- vi: "Chạy nó",
155
- tr: "Çalıştırma"
156
- },
157
- "help.files": {
158
- en: "Where the files go",
159
- zh: "文件位置",
160
- hi: "फ़ाइलें कहाँ जाती हैं",
161
- es: "Dónde van los archivos",
162
- fr: "Où vont les fichiers",
163
- ar: "أين تذهب الملفات",
164
- bn: "ফাইল কোথায় যায়",
165
- pt: "Para onde vão os arquivos",
166
- ru: "Где находятся файлы",
167
- ur: "فائلیں کہاں جاتی ہیں",
168
- ja: "ファイルの場所",
169
- ko: "파일이 저장되는 곳",
170
- de: "Wohin die Dateien gehen",
171
- id: "Ke mana berkas disimpan",
172
- vi: "Tệp được lưu ở đâu",
173
- tr: "Dosyalar nereye gider"
174
- },
175
- "help.model": {
176
- en: "Model",
177
- zh: "模型",
178
- hi: "मॉडल",
179
- es: "Modelo",
180
- fr: "Modèle",
181
- ar: "النموذج",
182
- bn: "মডেল",
183
- pt: "Modelo",
184
- ru: "Модель",
185
- ur: "ماڈل",
186
- ja: "モデル",
187
- ko: "모델",
188
- de: "Modell",
189
- id: "Model",
190
- vi: "Mô hình",
191
- tr: "Model"
192
- },
193
- "help.cost": {
194
- en: "Cost",
195
- zh: "费用",
196
- hi: "लागत",
197
- es: "Coste",
198
- fr: "Coût",
199
- ar: "التكلفة",
200
- bn: "খরচ",
201
- pt: "Custo",
202
- ru: "Стоимость",
203
- ur: "لاگت",
204
- ja: "コスト",
205
- ko: "비용",
206
- de: "Kosten",
207
- id: "Biaya",
208
- vi: "Chi phí",
209
- tr: "Maliyet"
210
- },
211
- "help.memory": {
212
- en: "Memory and history",
213
- zh: "记忆与历史",
214
- hi: "मेमोरी और इतिहास",
215
- es: "Memoria e historial",
216
- fr: "Mémoire et historique",
217
- ar: "الذاكرة والسجل",
218
- bn: "মেমরি ও ইতিহাস",
219
- pt: "Memória e histórico",
220
- ru: "Память и история",
221
- ur: "میموری اور تاریخ",
222
- ja: "メモリと履歴",
223
- ko: "메모리와 기록",
224
- de: "Speicher und Verlauf",
225
- id: "Memori dan riwayat",
226
- vi: "Bộ nhớ và lịch sử",
227
- tr: "Bellek ve geçmiş"
228
- },
229
- "help.transcript": {
230
- en: "Reading the transcript",
231
- zh: "阅读记录",
232
- hi: "ट्रांसक्रिप्ट पढ़ना",
233
- es: "Leer la transcripción",
234
- fr: "Lire la transcription",
235
- ar: "قراءة النص",
236
- bn: "ট্রান্সক্রিপ্ট পড়া",
237
- pt: "Ler a transcrição",
238
- ru: "Чтение стенограммы",
239
- ur: "ٹرانسکرپٹ پڑھنا",
240
- ja: "記録を読む",
241
- ko: "대화 기록 읽기",
242
- de: "Das Transkript lesen",
243
- id: "Membaca transkrip",
244
- vi: "Đọc bản ghi",
245
- tr: "Dökümü okuma"
246
- },
247
- "help.headless": {
248
- en: "Headless output",
249
- zh: "无界面输出",
250
- hi: "हेडलेस आउटपुट",
251
- es: "Salida sin interfaz",
252
- fr: "Sortie sans interface",
253
- ar: "المخرجات بدون واجهة",
254
- bn: "হেডলেস আউটপুট",
255
- pt: "Saída headless",
256
- ru: "Вывод без интерфейса",
257
- ur: "ہیڈ لیس آؤٹ پٹ",
258
- ja: "ヘッドレス出力",
259
- ko: "헤드리스 출력",
260
- de: "Headless-Ausgabe",
261
- id: "Keluaran tanpa antarmuka",
262
- vi: "Đầu ra không giao diện",
263
- tr: "Arayüzsüz çıktı"
264
- },
265
- "help.inSession": {
266
- en: "In a session",
267
- zh: "会话中",
268
- hi: "सत्र में",
269
- es: "En una sesión",
270
- fr: "Dans une session",
271
- ar: "داخل الجلسة",
272
- bn: "একটি সেশনে",
273
- pt: "Em uma sessão",
274
- ru: "В сессии",
275
- ur: "سیشن میں",
276
- ja: "セッション中",
277
- ko: "세션 안에서",
278
- de: "In einer Sitzung",
279
- id: "Dalam sesi",
280
- vi: "Trong một phiên",
281
- tr: "Bir oturumda"
282
- },
283
- "help.footnote": {
284
- en: "Everything below is here when you need it — these five are the ones you need first.",
285
- zh: "下面的内容备你所需——这五个是你首先要用的。",
286
- hi: "नीचे सब कुछ ज़रूरत पड़ने पर है — ये पाँच पहले चाहिए।",
287
- es: "Todo lo de abajo está aquí cuando lo necesites; estos cinco son los primeros.",
288
- fr: "Tout ce qui suit est là au besoin — ces cinq-là sont les premiers.",
289
- ar: "كل ما بالأسفل موجود عند الحاجة — وهذه الخمسة هي ما تحتاجه أولاً.",
290
- bn: "নিচের সব কিছু প্রয়োজনে আছে — এই পাঁচটি প্রথমে দরকার।",
291
- pt: "Tudo abaixo está aqui quando precisar — estes cinco vêm primeiro.",
292
- ru: "Всё, что ниже, — на случай необходимости; эти пять нужны в первую очередь.",
293
- ur: "نیچے سب کچھ ضرورت پر موجود ہے — یہ پانچ پہلے درکار ہیں۔",
294
- ja: "以下は必要になったときのために。まずはこの5つ。",
295
- ko: "아래는 필요할 때를 위한 것 — 이 다섯 개가 먼저 필요합니다.",
296
- de: "Alles Weitere steht bereit, wenn du es brauchst — diese fünf zuerst.",
297
- id: "Semua di bawah tersedia saat dibutuhkan — lima ini yang pertama.",
298
- vi: "Mọi thứ bên dưới có sẵn khi bạn cần — năm mục này cần trước.",
299
- tr: "Aşağıdakiler gerektiğinde burada — önce bu beşi."
300
- },
301
- "help.sessionHint": {
302
- en: "marks the ones to learn first",
303
- zh: "标记先学的项目",
304
- hi: "पहले सीखने वाले चिह्नित",
305
- es: "marca los que aprender primero",
306
- fr: "marque ceux à apprendre d'abord",
307
- ar: "يشير إلى ما يُتعلَّم أولاً",
308
- bn: "প্রথমে শেখারগুলো চিহ্নিত",
309
- pt: "marca os que aprender primeiro",
310
- ru: "отмечает то, что изучить в первую очередь",
311
- ur: "پہلے سیکھنے والوں کی نشاندہی",
312
- ja: "最初に覚えるものを示す",
313
- ko: "먼저 익힐 것을 표시",
314
- de: "markiert, was zuerst zu lernen ist",
315
- id: "menandai yang dipelajari lebih dulu",
316
- vi: "đánh dấu những mục nên học trước",
317
- tr: "önce öğrenilecekleri işaretler"
318
- },
319
- "mode.plan": {
320
- en: "plan",
321
- zh: "规划",
322
- hi: "योजना",
323
- es: "plan",
324
- fr: "plan",
325
- ar: "تخطيط",
326
- bn: "পরিকল্পনা",
327
- pt: "plano",
328
- ru: "план",
329
- ur: "منصوبہ",
330
- ja: "計画",
331
- ko: "계획",
332
- de: "Plan",
333
- id: "rencana",
334
- vi: "kế hoạch",
335
- tr: "plan"
336
- },
337
- "mode.auto": {
338
- en: "auto",
339
- zh: "自动",
340
- hi: "स्वतः",
341
- es: "auto",
342
- fr: "auto",
343
- ar: "تلقائي",
344
- bn: "স্বয়ংক্রিয়",
345
- pt: "auto",
346
- ru: "авто",
347
- ur: "خودکار",
348
- ja: "自動",
349
- ko: "자동",
350
- de: "auto",
351
- id: "otomatis",
352
- vi: "tự động",
353
- tr: "otomatik"
354
- },
355
- "mode.build": {
356
- en: "build",
357
- zh: "构建",
358
- hi: "बिल्ड",
359
- es: "construir",
360
- fr: "construire",
361
- ar: "بناء",
362
- bn: "বিল্ড",
363
- pt: "construir",
364
- ru: "сборка",
365
- ur: "بلڈ",
366
- ja: "ビルド",
367
- ko: "빌드",
368
- de: "Build",
369
- id: "bangun",
370
- vi: "xây dựng",
371
- tr: "derleme"
372
- },
373
- "mode.defender": {
374
- en: "defender",
375
- zh: "防御",
376
- hi: "डिफेंडर",
377
- es: "defensor",
378
- fr: "défenseur",
379
- ar: "مدافع",
380
- bn: "ডিফেন্ডার",
381
- pt: "defensor",
382
- ru: "защита",
383
- ur: "محافظ",
384
- ja: "ディフェンダー",
385
- ko: "디펜더",
386
- de: "Verteidiger",
387
- id: "penjaga",
388
- vi: "phòng thủ",
389
- tr: "savunucu"
390
- },
391
- "firstRun.notConfigured": {
392
- en: "Archymedes is not configured yet. Add a provider key below to start.",
393
- zh: "Archymedes 尚未配置。请在下方添加一个提供商密钥以开始。",
394
- hi: "Archymedes अभी कॉन्फ़िगर नहीं है। शुरू करने के लिए नीचे एक प्रदाता कुंजी जोड़ें।",
395
- es: "Archymedes aún no está configurado. Añade una clave de proveedor abajo para empezar.",
396
- fr: "Archymedes n'est pas encore configuré. Ajoutez une clé de fournisseur ci-dessous pour commencer.",
397
- ar: "لم يتم إعداد Archymedes بعد. أضف مفتاح مزوّد بالأسفل للبدء.",
398
- bn: "Archymedes এখনও কনফিগার করা হয়নি। শুরু করতে নিচে একটি প্রোভাইডার কী যোগ করুন।",
399
- pt: "O Archymedes ainda não está configurado. Adicione uma chave de provedor abaixo para começar.",
400
- ru: "Archymedes ещё не настроен. Добавьте ключ провайдера ниже, чтобы начать.",
401
- ur: "Archymedes ابھی ترتیب نہیں دیا گیا۔ شروع کرنے کے لیے نیچے ایک پرووائیڈر کلید شامل کریں۔",
402
- ja: "Archymedes はまだ設定されていません。開始するには下でプロバイダーのキーを追加してください。",
403
- ko: "Archymedes가 아직 설정되지 않았습니다. 시작하려면 아래에 공급자 키를 추가하세요.",
404
- de: "Archymedes ist noch nicht konfiguriert. Füge unten einen Anbieter-Schlüssel hinzu, um zu starten.",
405
- id: "Archymedes belum dikonfigurasi. Tambahkan kunci penyedia di bawah untuk memulai.",
406
- vi: "Archymedes chưa được cấu hình. Thêm khóa nhà cung cấp bên dưới để bắt đầu.",
407
- tr: "Archymedes henüz yapılandırılmadı. Başlamak için aşağıya bir sağlayıcı anahtarı ekleyin."
408
- },
409
- "doctor.header": {
410
- en: "Archymedes connectivity check",
411
- zh: "Archymedes 连接检查",
412
- hi: "Archymedes कनेक्टिविटी जाँच",
413
- es: "Comprobación de conectividad de Archymedes",
414
- fr: "Vérification de connectivité d'Archymedes",
415
- ar: "فحص اتصال Archymedes",
416
- bn: "Archymedes সংযোগ পরীক্ষা",
417
- pt: "Verificação de conectividade do Archymedes",
418
- ru: "Проверка соединения Archymedes",
419
- ur: "Archymedes کنیکٹیویٹی جانچ",
420
- ja: "Archymedes 接続チェック",
421
- ko: "Archymedes 연결 점검",
422
- de: "Archymedes-Verbindungsprüfung",
423
- id: "Pemeriksaan konektivitas Archymedes",
424
- vi: "Kiểm tra kết nối Archymedes",
425
- tr: "Archymedes bağlantı kontrolü"
426
- },
427
- "doctor.allReachable": {
428
- en: "All required endpoints are reachable.",
429
- zh: "所有必需的端点均可访问。",
430
- hi: "सभी आवश्यक एंडपॉइंट पहुँच योग्य हैं।",
431
- es: "Todos los puntos finales necesarios son accesibles.",
432
- fr: "Tous les points de terminaison requis sont accessibles.",
433
- ar: "جميع نقاط النهاية المطلوبة قابلة للوصول.",
434
- bn: "সব প্রয়োজনীয় এন্ডপয়েন্টে পৌঁছানো যাচ্ছে।",
435
- pt: "Todos os endpoints necessários estão acessíveis.",
436
- ru: "Все необходимые адреса доступны.",
437
- ur: "تمام مطلوبہ اینڈ پوائنٹس قابل رسائی ہیں۔",
438
- ja: "必要なエンドポイントはすべて到達可能です。",
439
- ko: "필요한 모든 엔드포인트에 연결할 수 있습니다.",
440
- de: "Alle erforderlichen Endpunkte sind erreichbar.",
441
- id: "Semua endpoint yang diperlukan dapat dijangkau.",
442
- vi: "Tất cả các endpoint cần thiết đều truy cập được.",
443
- tr: "Gerekli tüm uç noktalara erişilebiliyor."
444
- },
445
- "doctor.noProvider": {
446
- en: "No provider is configured — set an API key to use Archymedes.",
447
- zh: "未配置任何提供商——设置一个 API 密钥以使用 Archymedes。",
448
- hi: "कोई प्रदाता कॉन्फ़िगर नहीं है — Archymedes उपयोग करने के लिए एक API कुंजी सेट करें।",
449
- es: "No hay ningún proveedor configurado: establece una clave de API para usar Archymedes.",
450
- fr: "Aucun fournisseur configuré — définissez une clé API pour utiliser Archymedes.",
451
- ar: "لا يوجد مزوّد مُهيّأ — عيّن مفتاح API لاستخدام Archymedes.",
452
- bn: "কোনো প্রোভাইডার কনফিগার করা নেই — Archymedes ব্যবহার করতে একটি API কী সেট করুন।",
453
- pt: "Nenhum provedor configurado — defina uma chave de API para usar o Archymedes.",
454
- ru: "Провайдер не настроен — задайте ключ API, чтобы использовать Archymedes.",
455
- ur: "کوئی پرووائیڈر ترتیب نہیں — Archymedes استعمال کرنے کے لیے ایک API کلید سیٹ کریں۔",
456
- ja: "プロバイダーが未設定です。Archymedes を使うには API キーを設定してください。",
457
- ko: "설정된 공급자가 없습니다 — Archymedes를 사용하려면 API 키를 설정하세요.",
458
- de: "Kein Anbieter konfiguriert — lege einen API-Schlüssel fest, um Archymedes zu nutzen.",
459
- id: "Tidak ada penyedia yang dikonfigurasi — atur kunci API untuk memakai Archymedes.",
460
- vi: "Chưa cấu hình nhà cung cấp — đặt khóa API để dùng Archymedes.",
461
- tr: "Yapılandırılmış sağlayıcı yok — Archymedes'i kullanmak için bir API anahtarı ayarlayın."
462
- },
463
- "doctor.cannotReach": {
464
- en: "Archymedes cannot reach its model provider:",
465
- zh: "Archymedes 无法连接其模型提供商:",
466
- hi: "Archymedes अपने मॉडल प्रदाता तक नहीं पहुँच सकता:",
467
- es: "Archymedes no puede acceder a su proveedor de modelos:",
468
- fr: "Archymedes ne peut pas joindre son fournisseur de modèles :",
469
- ar: "لا يستطيع Archymedes الوصول إلى مزوّد النموذج:",
470
- bn: "Archymedes তার মডেল প্রোভাইডারে পৌঁছাতে পারছে না:",
471
- pt: "O Archymedes não consegue acessar seu provedor de modelos:",
472
- ru: "Archymedes не может связаться с провайдером модели:",
473
- ur: "Archymedes اپنے ماڈل پرووائیڈر تک نہیں پہنچ سکتا:",
474
- ja: "Archymedes はモデルプロバイダーに接続できません:",
475
- ko: "Archymedes가 모델 공급자에 연결할 수 없습니다:",
476
- de: "Archymedes kann seinen Modellanbieter nicht erreichen:",
477
- id: "Archymedes tidak dapat menjangkau penyedia modelnya:",
478
- vi: "Archymedes không thể kết nối tới nhà cung cấp mô hình:",
479
- tr: "Archymedes model sağlayıcısına ulaşamıyor:"
480
- },
481
- "balance.tracking": {
482
- en: "Archymedes will subtract each turn's measured cost from it.",
483
- zh: "Archymedes 将从中扣除每轮的实测费用。",
484
- hi: "Archymedes हर टर्न की मापी गई लागत इसमें से घटाएगा।",
485
- es: "Archymedes restará de él el coste medido de cada turno.",
486
- fr: "Archymedes en soustraira le coût mesuré de chaque tour.",
487
- ar: "سيخصم Archymedes منه التكلفة المقاسة لكل جولة.",
488
- bn: "Archymedes প্রতিটি টার্নের পরিমাপকৃত খরচ এটি থেকে বাদ দেবে।",
489
- pt: "O Archymedes subtrairá dele o custo medido de cada turno.",
490
- ru: "Archymedes будет вычитать из него измеренную стоимость каждого хода.",
491
- ur: "Archymedes ہر باری کی ماپی گئی لاگت اس میں سے منہا کرے گا۔",
492
- ja: "Archymedes は各ターンの実測コストをここから差し引きます。",
493
- ko: "Archymedes가 매 턴의 측정된 비용을 여기서 차감합니다.",
494
- de: "Archymedes zieht die gemessenen Kosten jeder Runde davon ab.",
495
- id: "Archymedes akan mengurangi biaya terukur setiap giliran dari saldo ini.",
496
- vi: "Archymedes sẽ trừ chi phí đo được của mỗi lượt khỏi số dư này.",
497
- tr: "Archymedes her turun ölçülen maliyetini bundan düşecek."
498
- }
499
- };
500
- function t(language, key) {
501
- return MESSAGES[key][language] ?? MESSAGES[key].en;
502
- }
503
-
504
- // packages/archymedes-cli/src/catalog/commands.ts
505
- function defineCommands(table) {
506
- return Object.entries(table).map(([name, command]) => ({ name, ...command }));
507
- }
508
- var COMMANDS2 = defineCommands({
509
- "/layout": { args: "[fixed|scrollback]", description: "Toggle the fixed workspace or terminal scrollback layout" },
510
- "/mode": { args: "[plan|build|auto|defender]", description: "Show or switch the permission mode" },
511
- "/plan": { description: "Switch to plan mode — read and reason, no writes" },
512
- "/build": { description: "Switch to build mode — edits need approval" },
513
- "/auto": { description: "Auto-apply ordinary edits; sensitive actions still ask" },
514
- "/defender": { description: "Switch to defender mode — find and fix real security issues, every change still asks" },
515
- "/models": { args: "[refresh]", description: "Every model each provider actually offers, with prices — or add a key for one you can't use yet" },
516
- "/model": { args: "[name | N | provider model]", description: "Open the model picker, or switch straight to a name, keeping the transcript" },
517
- "/fallback": { args: "[off|ask|provider:model]", description: "Opt into a safe alternate model after transient provider failures" },
518
- "/undo": { args: "[code|conversation]", description: "Revert the last turn — files, the conversation, or both (default)" },
519
- "/retry": { description: "Repeat the last failed request only when no tool or file change already happened" },
520
- "/continue": { description: "Resume an interrupted or incomplete task from its current workspace state" },
521
- "/diff": { description: "What changed since the last checkpoint" },
522
- "/todos": { description: "The agent's current plan" },
523
- "/task": { description: "Where the whole task stands: request, plan, changes, verification, blockers" },
524
- "/route": { args: "[all|summary|plan]", description: "The hosted exchange's routing decision: chosen model, alternatives, policy, est vs actual cost. `plan` forecasts the next turn before spending" },
525
- "/clear": { description: "Start a fresh thread" },
526
- "/memory": { args: "[add|replace|recall|forget]", description: "Bounded, relevant memory across sessions — # <fact> remembers for this project" },
527
- "/history": { args: "[list | <id> | search <text> | delete <id>|--all | status]", description: "Go back to an earlier conversation — opens a picker (Del deletes one); list prints them, search finds one" },
528
- "/resume": { args: "[<id> | latest]", description: "Continue an earlier conversation in this folder (picker, or straight to one)" },
529
- "/export": { args: "[markdown|json|support]", description: "Write a redacted session transcript or compact support artifact" },
530
- "/expand": { args: "[N | all | list]", description: "Show a folded block — written code, a test run, a long result — in full" },
531
- "/slow": { args: "[on|strict|off]", description: "Spend at a slower pace: fewer model rounds, smaller replies, a pause between turns" },
532
- "/workspace": { description: "Open the control panel: every tab and watched job, live, on one screen" },
533
- "/watch": { args: "[id|show <id>|stop <id>]", description: "Follow a background job's output without giving up the prompt" },
534
- "/theme": { args: "[name|list|where]", description: "Pick the colours from a list, or name one — blueprint, parchment, chalkboard, high-contrast, rainbow, or a .tss file of your own" },
535
- "/tab": { args: "[new|next|prev|close|rename|N]", description: "Several pieces of work, one at a time — only the tab in front runs (/detach for parallel)" },
536
- "/pull": { args: "[dir]", description: "Copy sandbox files here" },
537
- "/where": { description: "Show the current workspace" },
538
- "/diagnostics": { args: "[glob]", description: "Language server diagnostics for the workspace — errors, warnings, info from installed language servers" },
539
- "/tools": { description: "What the agent can call, and which skills, plugins, MCP servers or hooks a project added" },
540
- "/providers": { description: "Which model providers are configured" },
541
- "/settings": { description: "Theme, code colours, simple mode, startup, free-mode savings, keys and models" },
542
- "/upgrade": { description: "Use your own OpenRouter API key instead of the shared free gateway" },
543
- "/update": { args: "[auto|check|off]", description: "Update Archymedes now, or choose whether it updates itself" },
544
- "/voice": { args: "[audio-file]", description: "Record or transcribe an editable voice prompt" },
545
- "/wander": { args: "[topic|random|daily|weekly]", description: "Run a bounded research lab and grade what it finds" },
546
- "/jobs": { args: "[run|cancel|approve]", description: "Durable background work: list, start, cancel, or answer" },
547
- "/attach": { args: "<id>", description: "Watch a background job's log live" },
548
- "/detach": { args: "<task>", description: "Start work in the background; press Alt+B to send a running turn there" },
549
- "/cost": { description: "Token and cost breakdown for this session" },
550
- "/balance": { args: "[amount] [currency] | clear", description: "Your Archymedes credit balance on the exchange, or a locally tracked spend limit on a direct provider" },
551
- "/scan": { args: "[glob]", description: "Deterministic secret scan of the workspace, worst severity first — no model turn needed" },
552
- "/sessions": { description: "Pick an earlier conversation in this project (an alias for /history)" },
553
- "/palette": { description: "Search every command by name or by what it does" },
554
- "/keys": { description: "Every shortcut in full, plus line-editing keys and which chords this terminal may not deliver — /help lists them inline, next to each command" },
555
- "/guide": { args: "[topic|search <text>|all]", description: "The user guide, as a screen you can browse — or print one topic with /guide <topic>" },
556
- "/files": { description: "Browse the project tree — expand folders, preview a file, pick one to @mention" },
557
- "/edit": { args: "<path>", description: "Open a file in the built-in editor — through the workspace, so it works in a sandbox too" },
558
- "/cat": { args: "<path>", description: "Print a file into the transcript — markdown rendered like a document, code numbered and highlighted, PNG images drawn" },
559
- "/find": { args: "<text> | next | prev | off", description: "Search this tab's transcript in the fixed workspace; repeat /find for the next match" },
560
- "/pager": { description: "Open this tab's transcript in $PAGER (less -R) to search, select and save it" },
561
- "/help": { args: "[all|work|review|steer|parallel|learn|setup]", description: "Commands grouped by purpose" },
562
- "/exit": { description: "Leave" }
563
- });
564
- function renderCommandHelp(language = "en", shortcuts = new Map, options = {}) {
565
- const width = Math.max(...COMMANDS2.map((command) => command.name.length + (command.args ? command.args.length + 1 : 0)));
566
- const shortcutWidth = Math.max(0, ...[...shortcuts.values()].map((label) => label.length));
567
- const mark = options.mark ?? (() => " ");
568
- return COMMANDS2.map((command) => {
569
- const head = command.args ? `${command.name} ${command.args}` : command.name;
570
- const shortcut = shortcuts.get(command.name) ?? "";
571
- const shortcutColumn = shortcutWidth > 0 ? shortcut.padEnd(shortcutWidth + 2) : "";
572
- return `${mark(command.name)}${head.padEnd(width + 2)}${shortcutColumn}${commandDescription(language, command.name, command.description)}`;
573
- }).join(`
574
- `);
575
- }
576
- function suggestionsFor(line, models = []) {
577
- const model = /^\/models?\s+(\S*)$/.exec(line);
578
- if (model) {
579
- const fragment = model[1].toLowerCase();
580
- const matched = models.filter((id) => id.toLowerCase().includes(fragment));
581
- return matched.length === 1 && matched[0].toLowerCase() === fragment ? [] : matched.map((id) => ({ command: id, description: "" }));
582
- }
583
- if (!/^\/\S*$/.test(line))
584
- return [];
585
- const matches = COMMANDS2.filter((command) => command.name.startsWith(line));
586
- if (matches.length === 1 && matches[0].name === line)
587
- return [];
588
- return matches.map((command) => ({ command: command.name, ...command.args ? { args: command.args } : {}, description: command.description }));
589
- }
590
- function inlineCompletion(line, models = []) {
591
- const none = { suffix: "", alternatives: 0 };
592
- const model = /^(\/models?\s+)(\S+)$/.exec(line);
593
- if (model) {
594
- const fragment = model[2].toLowerCase();
595
- const matched2 = models.filter((id) => id.toLowerCase().startsWith(fragment)).sort((a, b) => a.length - b.length);
596
- if (matched2.length === 0 || matched2[0].length === fragment.length)
597
- return none;
598
- return { suffix: matched2[0].slice(model[2].length), alternatives: matched2.length - 1 };
599
- }
600
- if (!/^\/\S*$/.test(line) || line === "/")
601
- return none;
602
- const matched = COMMANDS2.map((command) => command.name).filter((name) => name.startsWith(line)).sort((left, right) => left.length - right.length);
603
- if (matched.length === 0 || matched[0] === line)
604
- return none;
605
- return { suffix: matched[0].slice(line.length), alternatives: matched.length - 1 };
606
- }
607
- function isKnownCommand(name) {
608
- return COMMANDS2.some((command) => command.name === name);
609
- }
610
- var MODE_NAMES = ["plan", "build", "auto", "defender"];
611
- function isModeName(value) {
612
- return MODE_NAMES.includes(value);
613
- }
614
- function parseModeCommand(input) {
615
- const bareModeCommand = input.startsWith("/") ? input.slice(1) : "";
616
- if (isModeName(bareModeCommand))
617
- return { type: "switch", mode: bareModeCommand };
618
- const match = /^\/mode(?:\s+(\S+))?$/.exec(input);
619
- if (!match)
620
- return null;
621
- if (!match[1])
622
- return { type: "show" };
623
- return isModeName(match[1]) ? { type: "switch", mode: match[1] } : { type: "invalid" };
624
- }
625
- function editDistance(left, right) {
626
- const previous = Array.from({ length: right.length + 1 }, (_unused, index) => index);
627
- for (let row = 1;row <= left.length; row += 1) {
628
- let diagonal = previous[0];
629
- previous[0] = row;
630
- for (let column = 1;column <= right.length; column += 1) {
631
- const candidate = Math.min(previous[column] + 1, previous[column - 1] + 1, diagonal + (left[row - 1] === right[column - 1] ? 0 : 1));
632
- diagonal = previous[column];
633
- previous[column] = candidate;
634
- }
635
- }
636
- return previous[right.length];
637
- }
638
- function suggestCommand(name) {
639
- const ranked = COMMANDS2.map((command) => ({ name: command.name, distance: editDistance(name, command.name) })).sort((left, right) => left.distance - right.distance);
640
- const best = ranked[0];
641
- return best && best.distance <= 2 ? best.name : undefined;
642
- }
643
- var KEYBOARD_SHORTCUTS = [
644
- ["menu-move", "↑ / ↓", "Move through any menu — settings, models, the palette"],
645
- ["menu-number", "1-9", "Jump straight to a numbered row in a menu"],
646
- ["menu-take", "Enter / Esc", "Take the highlighted row / leave the menu"],
647
- ["complete-command", "Tab", "Complete a slash command"],
648
- ["complete-path", "@ + path", "Complete a project file mention"],
649
- ["history", "Up / Down", "Search persistent prompt history"],
650
- ["line-ends", "Home / End", "Move to the start / end of the input"],
651
- ["delete", "Alt-Backspace / Ctrl-U", "Delete the previous word / whole input"],
652
- ["clear", "Ctrl-L", "Clear and redraw the terminal"],
653
- ["interrupt", "Ctrl-C", "Interrupt the current turn"],
654
- ["voice", "/voice", "Record a prompt from the microphone"],
655
- ["expand", "Ctrl-O", "Unfold the most recent folded block"],
656
- ["memory", "# fact", "Remember a fact for every future session in this project"]
657
- ];
658
- function renderKeyboardShortcuts(language = "en") {
659
- const width = Math.max(...KEYBOARD_SHORTCUTS.map(([, key]) => key.length));
660
- return KEYBOARD_SHORTCUTS.map(([id, key, description]) => ` ${key.padEnd(width + 2)}${keyboardDescription(language, id, description)}`).join(`
661
- `);
662
- }
663
-
664
- // packages/archymedes-cli/src/terminal/viewport.ts
665
- function newViewport(lines, height) {
666
- return clamp({ lines, height: Math.max(1, Math.floor(height)), top: 0 });
667
- }
668
- function maxTop(state) {
669
- return Math.max(0, state.lines.length - state.height);
670
- }
671
- function clamp(state) {
672
- const height = Math.max(1, Math.floor(state.height));
673
- const bounded = { ...state, height };
674
- const top = Math.max(0, Math.min(Math.floor(bounded.top) || 0, maxTop(bounded)));
675
- return { ...bounded, top };
676
- }
677
- function applyViewport(state, action) {
678
- switch (action.kind) {
679
- case "up":
680
- return clamp({ ...state, top: state.top - Math.max(1, action.rows ?? 1) });
681
- case "down":
682
- return clamp({ ...state, top: state.top + Math.max(1, action.rows ?? 1) });
683
- case "halfUp":
684
- return clamp({ ...state, top: state.top - Math.max(1, Math.floor(state.height / 2)) });
685
- case "halfDown":
686
- return clamp({ ...state, top: state.top + Math.max(1, Math.floor(state.height / 2)) });
687
- case "pageUp":
688
- return clamp({ ...state, top: state.top - Math.max(1, state.height - 1) });
689
- case "pageDown":
690
- return clamp({ ...state, top: state.top + Math.max(1, state.height - 1) });
691
- case "top":
692
- return clamp({ ...state, top: 0 });
693
- case "bottom":
694
- return clamp({ ...state, top: maxTop(state) });
695
- case "resize":
696
- return clamp({ ...state, height: action.height });
697
- case "content": {
698
- const next = clamp({ ...state, lines: action.lines });
699
- return action.follow ? clamp({ ...next, top: maxTop(next) }) : next;
700
- }
701
- }
702
- }
703
- function visibleLines(state) {
704
- return state.lines.slice(state.top, state.top + state.height);
705
- }
706
- function atTop(state) {
707
- return state.top <= 0;
708
- }
709
- function atBottom(state) {
710
- return state.top >= maxTop(state);
711
- }
712
- function scrollFraction(state) {
713
- const furthest = maxTop(state);
714
- return furthest === 0 ? 1 : state.top / furthest;
715
- }
716
-
717
- // packages/archymedes-cli/src/render/guide.ts
718
- var GUIDE_TOPICS = [
719
- {
720
- id: "start",
721
- title: "Getting started",
722
- summary: "What Archymedes is, and the first thing to type.",
723
- body: [
724
- "Archymedes is a coding agent that works in a scrolling terminal transcript. You type what you want in plain language; it reads files, runs commands and edits code, and shows you what it did as it goes.",
725
- "Everything it prints stays in your terminal's scrollback, so you can scroll up, select text and pipe a session to a file the way you would with any other command.",
726
- "Type a request and press Enter. Slash commands do everything else — press / to see them, or open the searchable list.",
727
- "One rule everywhere: Esc takes you back. Out of a menu, the guide, the file browser, the pager or the editor, Esc returns you to the chat prompt. A lone ? on the prompt shows the short help.",
728
- "Archymedes starts in simple mode — one line of help and nothing else to learn. Turn ARCHYMEDES_SIMPLE off in /settings for the full banner, starter ideas and the grouped /help."
729
- ],
730
- examples: [
731
- { input: "fix the failing test in cart.ts", effect: "an ordinary request; Archymedes reads, edits and runs the tests" },
732
- { input: "?", effect: "the short help: the handful of commands worth knowing first" },
733
- { input: "/help all", effect: "every command, with one line each" },
734
- { input: "/palette", effect: "search commands by name or by what they do" },
735
- { input: "/guide", effect: "open this guide as a screen — arrows to move, / to search, Esc to come back" },
736
- { input: "/guide tabs", effect: "print one topic into the transcript, to keep or to copy" },
737
- { input: "/exit", effect: "leave; the session is saved and can be resumed" }
738
- ],
739
- covers: ["/help", "/palette", "/exit", "/keys", "/guide"]
740
- },
741
- {
742
- id: "modes",
743
- title: "Permission modes",
744
- summary: "How much Archymedes may do without asking.",
745
- body: [
746
- "Four modes, and you can change them at any time. Plan reads and reasons but cannot write or run commands. Build is the default: edits are proposed and you approve them. Auto applies ordinary workspace edits without asking, while anything sensitive or reaching outside the workspace still stops for you. Defender turns Archymedes into a security reviewer — full tool access to actually scan and fix, but never auto-approved, the same posture as Build.",
747
- "Defender also looks outward: when web search is configured it checks current advisories against what the project actually depends on, remembers durable findings in project memory so the next review builds on this one, and closes out with concrete, costed remediation resources fitted to how the project actually hosts and deploys — not a generic checklist.",
748
- "/scan runs the deterministic half of defender's own secrets playbook directly — no model turn, no mode switch needed. It is the same pattern-matching scan_secrets uses, worst severity first: a private key or a live cloud credential ahead of a merely credential-shaped variable name.",
749
- "The mode is per tab, so one piece of work can be on a short leash while another runs freely."
750
- ],
751
- examples: [
752
- { input: "/plan", effect: "read-only: no writes, no commands" },
753
- { input: "/build", effect: "edits ask first (the default)" },
754
- { input: "/auto", effect: "ordinary edits apply; sensitive actions still ask" },
755
- { input: "/defender", effect: "security review — find and fix real issues; every change still asks" },
756
- { input: "/mode", effect: "show which mode you are in" },
757
- { input: "/scan", effect: "pattern-based secret scan, worst severity first, no model call" },
758
- { input: "/scan src/**", effect: "same scan, limited to files matching the glob" }
759
- ],
760
- covers: ["/mode", "/plan", "/build", "/auto", "/defender", "/scan"]
761
- },
762
- {
763
- id: "tabs",
764
- title: "Tabs: several pieces of work, one at a time",
765
- summary: "Each tab keeps its own conversation, model, cost and machine — the tab in front is the one that runs.",
766
- body: [
767
- "A tab is a separate piece of work with its own conversation, its own running total, its own mode — and its own model and location. One tab can be on a large model against your checkout while another runs a cheaper or open model inside a throwaway remote sandbox.",
768
- "Only the tab in front runs. Switching away does not leave a turn working in the background — it pauses that piece of work and hands the terminal to another one. That is a deliberate limit rather than a missing feature: a terminal transcript has one bottom, and two agents printing into it at once would interleave into something neither of them said. (Archymedes's desktop window is different — it has a transcript per tab, so its tabs really do run at the same time.)",
769
- "When you want work running while you do something else, that is what /detach and /jobs are for: a detached job keeps going after you close the terminal, and /watch streams it into the session without taking the prompt.",
770
- "Tabs keep what they printed. Leave one and come back and the last lines reappear, so you can pick up where you were instead of facing a bare prompt.",
771
- "The strip above the prompt shows every tab with its model and a mark for where it runs. Closing a tab that started its own sandbox stops that sandbox — and only that one."
772
- ],
773
- examples: [
774
- { input: "/tab new review", effect: "a second tab, same model, same machine" },
775
- { input: "/tab new fast --model claude-haiku-4-5-20251001", effect: "a tab on a different model" },
776
- { input: "/tab new risky --sandbox e2b", effect: "a tab whose edits land in a remote sandbox, not on your disk" },
777
- { input: "/tab 2", effect: "switch to tab 2 and replay where you left off" },
778
- { input: "/tab close 2", effect: "close it, stopping its sandbox if it started one" },
779
- { input: "/detach run the full test suite", effect: "work that runs while you use another tab" }
780
- ],
781
- covers: ["/tab"]
782
- },
783
- {
784
- id: "models",
785
- title: "Models and providers",
786
- summary: "Choosing what runs, and what it costs.",
787
- body: [
788
- "Archymedes talks to several providers. The picker lists what you can use, with prices, and offers to save a key for anything you cannot use yet. Switching model keeps the conversation — you are changing who answers, not starting over.",
789
- "The list is the union of what this build knows the prices of and what each provider says it has today, so a model released last week is still offerable — it is simply shown without a price rather than hidden. The live half is cached for six hours; /models refresh asks again.",
790
- "A model switch applies to the tab you are in. Opening a tab with --model is how you compare two models on the same problem.",
791
- "Type in /model to narrow a long list; Esc clears the search before it leaves.",
792
- "archymedes --free needs no key: it runs zero-priced tool models (openrouter/free or an exact model:free ID) through the Archymedes free gateway, which holds the shared OpenRouter key server-side and enforces a daily allowance — 100,000 tokens and 300 requests per UTC day, 20 a minute; tokens are the budget that usually runs out first. Until that gateway is live, free mode uses your own free OpenRouter key (50 free-model requests a day, 1,000 once the account has bought 10 credits). Every request carries a zero price cap and never falls back to a paid provider. When the allowance runs out, it says so and when it resets.",
793
- "Type /upgrade (or /upgrades) to use your own OpenRouter API key instead: free-mode limits stop applying and requests go straight to OpenRouter. With your own key, --free talks to OpenRouter directly.",
794
- "For any other OpenRouter model — paid or free — use --provider openrouter with the same key (e.g. --provider openrouter --model openrouter/auto). That path has no price cap and needs no Archymedes Cloud account.",
795
- "Paste a TYPESAFE_API_KEY in archymedes settings for a Jev second opinion: it annotates approvals with a tool-fit reading and prints a post-turn verdict with probabilities. Advisory only — it never approves, denies, or blocks."
796
- ],
797
- examples: [
798
- { input: "/models", effect: "the list, with prices" },
799
- { input: "/models refresh", effect: "ask every provider what it has right now" },
800
- { input: "/model", effect: "the picker" },
801
- { input: "/model claude-sonnet-5", effect: "switch straight to one, keeping the transcript" },
802
- { input: "/fallback openai:gpt-5.4-mini", effect: "retry transient provider failures on this model, only before any output or tool action" },
803
- { input: "/providers", effect: "which providers are configured" }
804
- ],
805
- covers: ["/models", "/model", "/fallback", "/providers", "/settings", "/upgrade"]
806
- },
807
- {
808
- id: "where",
809
- title: "Where the work happens",
810
- summary: "This machine, a container, or a remote sandbox.",
811
- body: [
812
- "By default Archymedes edits the directory you started it in. Started with --sandbox e2b it works inside a throwaway remote machine instead, and --sandbox docker uses a local container. Files written there never touch your disk unless you ask for them.",
813
- "Sandboxes are per tab, so 'try this somewhere I don't mind breaking' is one command rather than a second terminal.",
814
- "One thing worth knowing: background jobs always run on your machine, even when the session that started them is sandboxed. Archymedes says so each time you start one."
815
- ],
816
- examples: [
817
- { input: "archymedes --sandbox e2b", effect: "the whole session runs in a remote sandbox" },
818
- { input: "/tab new spike --sandbox docker", effect: "one tab in a local container" },
819
- { input: "/where", effect: "which machine the current tab is using" },
820
- { input: "/pull", effect: "copy files out of a sandbox and onto your disk" }
821
- ],
822
- covers: ["/where", "/pull"]
823
- },
824
- {
825
- id: "reading",
826
- title: "Reading what Archymedes did",
827
- summary: "Code, diffs, test results, and folded detail.",
828
- body: [
829
- "When Archymedes writes or edits a file it shows the code, numbered, under the tool line. When it runs tests it re-lays the output into sections with the failures pulled out. When output is long it is folded rather than truncated, and the whole of it is one command away.",
830
- "The diff shows the actual patch since the last checkpoint — the lines, not a count of them.",
831
- "/diagnostics asks the language servers installed on this machine what they make of the code: errors, warnings and hints, file by file. It runs no model and changes nothing. A language whose server is not installed is listed as unavailable rather than passed over in silence."
832
- ],
833
- examples: [
834
- { input: "/diff", effect: "the real patch, file by file" },
835
- { input: "/diff stat", effect: "just the summary of how much changed" },
836
- { input: "/expand", effect: "unfold the last folded block" },
837
- { input: "/expand list", effect: "everything that has been folded this session" },
838
- { input: "/undo", effect: "revert the last turn — files, conversation, or both" },
839
- { input: "/retry", effect: "repeat a failed request when nothing had run or changed" },
840
- { input: "/continue", effect: "finish an interrupted task without repeating completed work" },
841
- { input: "/todos", effect: "the agent's current plan" },
842
- { input: "/task", effect: "the whole task at a glance: request, plan, changes, verification, blockers" },
843
- { input: "/route", effect: "the hosted exchange's routing decision for the last turn — chosen model, alternatives, cost vs estimate" },
844
- { input: "/diagnostics", effect: "errors and warnings from installed language servers, no model call" },
845
- { input: "/diagnostics src/**", effect: "the same, limited to files matching the glob" }
846
- ],
847
- covers: ["/diff", "/expand", "/undo", "/retry", "/continue", "/todos", "/task", "/route", "/diagnostics"]
848
- },
849
- {
850
- id: "memory",
851
- title: "Memory",
852
- summary: "Facts worth keeping between sessions.",
853
- body: [
854
- "Telling Archymedes the same thing every session costs you tokens and patience. A remembered fact is prepended to the conversation instead.",
855
- "Memory is a plain markdown file you can open, edit, commit or delete. Project memory belongs to the repository; personal memory follows you across projects. Nothing is remembered unless you say so."
856
- ],
857
- examples: [
858
- { input: "# we use bun, not npm", effect: "remember a fact about this project" },
859
- { input: "/memory", effect: "list what is remembered" },
860
- { input: "/memory add --user I prefer terse explanations", effect: "remember something about you, everywhere" },
861
- { input: "/memory forget 2", effect: "drop one" }
862
- ],
863
- covers: ["/memory"]
864
- },
865
- {
866
- id: "history",
867
- title: "History",
868
- summary: "Past conversations, searchable and resumable.",
869
- body: [
870
- "Every session is saved, so you can always go back to a normal conversation. /history (or /resume) opens a list of your earlier chats in this folder — arrows to choose, Enter to continue it with its whole context, Esc to stay where you are.",
871
- "When you start Archymedes in a folder with a recent chat, it offers to continue it: press Enter on the empty prompt to pick it up, or just type to start fresh. ARCHYMEDES_RESUME in /settings changes that to always or never.",
872
- "Chats belong to the folder they were started in: the list only ever shows this project's chats. In the picker, Del (or Ctrl+D) deletes the highlighted chat after asking — the chat you are in can't be deleted while it is open."
873
- ],
874
- examples: [
875
- { input: "/history", effect: "pick an earlier chat and continue it" },
876
- { input: "/resume latest", effect: "continue the most recent one straight away" },
877
- { input: "/history list", effect: "print recent sessions, newest first" },
878
- { input: "/history search failing tests", effect: "find one by what you typed" },
879
- { input: "/history delete --all", effect: "delete every other chat in this folder, after a yes (Del in the picker deletes one)" },
880
- { input: "archymedes --resume", effect: "start Archymedes on the picker" },
881
- { input: "/export support", effect: "write a compact redacted artifact safe to attach to a support request" },
882
- { input: "/clear", effect: "start a fresh thread in this tab" }
883
- ],
884
- covers: ["/history", "/sessions", "/resume", "/export", "/clear"]
885
- },
886
- {
887
- id: "cost",
888
- title: "Cost and pace",
889
- summary: "Knowing what you are spending, and spending it slower.",
890
- body: [
891
- "Every turn is priced in your own currency, and the running total is always on screen. Start with --budget N to approve a cap that is then enforced rather than merely reported.",
892
- "Slow mode is the other half: it limits how many model rounds and tool calls a turn may use, shortens replies, and pauses between turns. It caps the rate, not the total, and asks before an unusually expensive turn."
893
- ],
894
- examples: [
895
- { input: "/cost", effect: "the breakdown for this session" },
896
- { input: "archymedes --budget 20", effect: "approve and enforce a cap" },
897
- { input: "/slow", effect: "spend at a gentler pace" },
898
- { input: "/slow strict", effect: "slower still, with a pause between turns" },
899
- { input: "/slow off", effect: "back to full speed" }
900
- ],
901
- covers: ["/cost", "/slow"]
902
- },
903
- {
904
- id: "balance",
905
- title: "Tracking a spend balance",
906
- summary: "A local budget the prompt draws down as you work.",
907
- body: [
908
- "Archymedes has no hosted wallet. /balance sets a figure — the amount you have decided this project can spend — and after every completed turn Archymedes subtracts that turn's measured cost from it. It is an estimate you own, not a provider statement.",
909
- "The balance is kept in whatever currency your session shows costs in. /balance 5000 uses that currency; /balance 50 usd or /balance 5000 inr sets it explicitly. /balance on its own shows what remains and what this session has used so far. /balance clear stops tracking.",
910
- "Once a balance is being tracked, Archymedes warns calmly when it gets low, drops below the critical threshold, or falls unusually fast between turns. Before a demanding task it compares its token-based estimate with the balance and stops before contacting the model when even the conservative estimate cannot fit.",
911
- "The thresholds default to small USD amounts converted to your currency; ARCHYMEDES_LOW_BALANCE and ARCHYMEDES_CRITICAL_BALANCE override them in /settings."
912
- ],
913
- examples: [
914
- { input: "/balance 5000", effect: "track a 5,000 balance in the display currency" },
915
- { input: "/balance 50 usd", effect: "track a balance in a specific currency" },
916
- { input: "/balance", effect: "what remains, and what this session has used" },
917
- { input: "/balance clear", effect: "stop tracking a balance" }
918
- ],
919
- covers: ["/balance", "/cost"]
920
- },
921
- {
922
- id: "updating",
923
- title: "Keeping Archymedes current",
924
- summary: "Automatic updates by default, with explicit check-only and off controls.",
925
- body: [
926
- "Archymedes looks for a new version once a day, at the moment a session starts and never in the middle of one. The check is bounded at three seconds and its failure is silent: an unreachable registry costs one attempt a day, not a slow prompt.",
927
- "By default Archymedes installs a newer release automatically through whichever package manager installed it; it does not wait for another acceptance prompt. /update check changes that to notification-only behavior, and /update off stops it looking at all.",
928
- "Automatic installs never happen in a piped or headless run, or in CI, because automation may depend on an exact installed version. A version that fails to install is remembered and not retried, because an update mechanism that fails loudly every launch is one people uninstall.",
929
- "An install replaces the program on disk; the session you are in keeps running the version it started with until you restart it."
930
- ],
931
- examples: [
932
- { input: "/update", effect: "install the newest version now" },
933
- { input: "/update check", effect: "tell you about updates without installing" },
934
- { input: "/update off", effect: "stop looking for updates" }
935
- ],
936
- covers: ["/update"]
937
- },
938
- {
939
- id: "background",
940
- title: "Background work",
941
- summary: "Jobs that outlive the prompt, and research that runs itself.",
942
- body: [
943
- "Work can be sent to the background and keeps running after you close the terminal. A watched job streams its output into the session without taking the prompt, so you can read it when you want to and carry on meanwhile.",
944
- "This — not tabs — is how two things run at once in the terminal. A tab you switch away from is paused; a detached job keeps working.",
945
- "Wander runs a bounded research lab on a topic, gathers evidence first, and grades its own claims. It can run once or on a schedule.",
946
- "A job that needs approval says so and waits — attach to it to answer."
947
- ],
948
- examples: [
949
- { input: "/detach update the changelog", effect: "start it in the background" },
950
- { input: "/jobs", effect: "what is running, queued or finished" },
951
- { input: "/watch 20260814T0132Z-ab12cd", effect: "follow its output without giving up the prompt" },
952
- { input: "/watch show <id>", effect: "read what it has said so far" },
953
- { input: "/attach <id>", effect: "take the prompt to answer an approval" },
954
- { input: "/wander daily coral reefs", effect: "a research lab, every day" }
955
- ],
956
- covers: ["/detach", "/jobs", "/attach", "/watch", "/wander"]
957
- },
958
- {
959
- id: "panel",
960
- title: "The control panel",
961
- summary: "Every tab and job, live, on one screen.",
962
- body: [
963
- "The workspace is a full-screen view of everything at once: each tab as a pane showing its live output, what model it is running and where, and each watched job alongside them.",
964
- "It is a view — it reads the session and changes nothing — so leaving it puts you back exactly where you were.",
965
- "Inside it: 1-9 select a pane, arrows or Tab move between them, arrows or j/k scroll, g and G jump to the ends, Esc comes back to the chat."
966
- ],
967
- examples: [
968
- { input: "/workspace", effect: "open the panel" },
969
- { input: "q", effect: "leave it and return to the prompt" }
970
- ],
971
- covers: ["/workspace"]
972
- },
973
- {
974
- id: "look",
975
- title: "How it looks",
976
- summary: "Themes, symbols, the fixed workspace, and terminals that need help.",
977
- body: [
978
- "Archymedes ships a blueprint theme and three others, and reads themes you write yourself as .tss files in .archymedes/themes — the same format TermUI apps use, so a palette written once works in both. /theme <name> also saves the choice, so it is still your theme tomorrow.",
979
- "Code is coloured like VS Code — Dark+ on a dark theme, Light+ on a light one — with numbered lines in code blocks and green and red bands on changed lines in diffs. In /settings, Code colours set to theme paints code in the theme's own palette instead, and Line numbers in code blocks turns the numbers off.",
980
- "Sessions open in the fixed workspace: a mode rail and composer stay anchored while the transcript scrolls underneath. Read history with the mouse wheel or Page Up / Page Down, move a line at a time with Alt+Up / Alt+Down, jump to the top with Ctrl+Home, and press Escape to return to live output. Menus open inside the transcript area so the composer never jumps. Prefer the plain terminal log? Use --layout scrollback, ARCHYMEDES_LAYOUT=scrollback, or /layout. ARCHYMEDES_MOUSE=0 keeps the terminal's own text selection instead of wheel scrolling.",
981
- "If your terminal draws question marks instead of symbols, --ascii switches to characters every terminal has. If you would rather have a status line pinned to the bottom row, --pin does that, at the cost of your terminal's scrollback. ARCHYMEDES_NO_MOTION=1 keeps the opening geometry and menu focus still."
982
- ],
983
- examples: [
984
- { input: "/theme list", effect: "every theme available, including your own" },
985
- { input: "/theme chalkboard", effect: "change the colours immediately" },
986
- { input: "/theme where", effect: "where to put a theme file of your own" },
987
- { input: "/layout fixed", effect: "mode rail, anchored composer, menus in the transcript" },
988
- { input: "/find TypeError", effect: "search this tab's history; /find again for the next match, Esc to return" },
989
- { input: "/pager", effect: "open the whole transcript to scroll and search — in less, or the built-in pager on Windows (Esc back)" },
990
- { input: "/settings", effect: "theme, code colours, line numbers, simple mode, startup and free-mode savings" },
991
- { input: "/layout scrollback", effect: "return to the ordinary terminal log" },
992
- { input: "archymedes --ascii", effect: "plain characters for terminals that mangle symbols" }
993
- ],
994
- covers: ["/theme", "/layout", "/find", "/pager", "/settings"]
995
- },
996
- {
997
- id: "extend",
998
- title: "Tools and voice",
999
- summary: "What the agent can call, and talking to it.",
1000
- body: [
1001
- "Archymedes has a fixed set of built-in tools, and a project can add more through skills, plugins, MCP servers and hooks. The tools command shows exactly what is available in this project.",
1002
- "A prompt you type often can be saved as a command: `.archymedes/commands/review.md` becomes `/review`, shared with everyone on the project, and the same file in your config directory's `commands` folder is yours alone. `$ARGUMENTS` in the file is replaced by whatever you type after the name. Built-in commands cannot be replaced.",
1003
- "Voice input records or transcribes a prompt you can edit before sending.",
1004
- "The file picker is the project as a tree rather than a flat completion list: expand a folder, preview a file's contents, and pick one to drop an @mention into the line you're writing.",
1005
- "Mentioning an image — `what is wrong in @screenshots/bug.png?` — sends the picture itself with that request (PNG, JPEG, GIF or WebP, up to four, 5 MB each, from a local workspace). The model must accept images; the saved conversation keeps a note of the attachment rather than the image.",
1006
- "`/edit <path>` opens a file in the built-in editor. It reads and writes through the workspace like every tool does, so it edits the sandbox's copy in a sandboxed session rather than a same-named file on this machine, and it only writes when you save — quitting really is a discard."
1007
- ],
1008
- examples: [
1009
- { input: "/tools", effect: "every tool, skill, plugin, MCP server and hook" },
1010
- { input: "/review src/auth.ts", effect: "run .archymedes/commands/review.md with src/auth.ts as $ARGUMENTS" },
1011
- { input: "/voice", effect: "record a prompt, then edit it before sending" },
1012
- { input: "/cat README.md", effect: "read a file in the transcript, with markdown formatting or numbered code" },
1013
- { input: "/cat docs/diagram.png", effect: "draw a PNG in the transcript (ARCHYMEDES_IMAGES=kitty for real pixels in scrollback)" },
1014
- { input: "/files", effect: "browse the project tree and @mention a file" },
1015
- { input: "/edit src/app.ts", effect: "open a file in the built-in editor" }
1016
- ],
1017
- covers: ["/tools", "/voice", "/files", "/edit", "/cat"]
1018
- }
1019
- ];
1020
- function findTopic(id) {
1021
- const wanted = id.trim().toLowerCase();
1022
- return GUIDE_TOPICS.find((topic) => topic.id === wanted) ?? GUIDE_TOPICS.find((topic) => topic.title.toLowerCase().includes(wanted));
1023
- }
1024
- function searchTopics(query) {
1025
- const needle = query.trim().toLowerCase();
1026
- if (!needle)
1027
- return GUIDE_TOPICS;
1028
- return GUIDE_TOPICS.filter((topic) => [topic.title, topic.summary, ...topic.body, ...(topic.examples ?? []).flatMap((example) => [example.input, example.effect])].some((text) => text.toLowerCase().includes(needle)));
1029
- }
1030
- function wrapText(text, width) {
1031
- const measure = Math.max(1, width);
1032
- const lines = [];
1033
- let current = "";
1034
- for (const word of text.split(/\s+/).filter(Boolean)) {
1035
- if (current === "") {
1036
- current = word;
1037
- continue;
1038
- }
1039
- if (visibleWidth(current) + 1 + visibleWidth(word) <= measure)
1040
- current = `${current} ${word}`;
1041
- else {
1042
- lines.push(current);
1043
- current = word;
1044
- }
1045
- }
1046
- if (current !== "")
1047
- lines.push(current);
1048
- return lines;
1049
- }
1050
- function renderGuideIndex(style) {
1051
- const glyphs = style.glyphs ?? UNICODE_GLYPHS;
1052
- const available = Math.max(8, style.width - GUTTER.length);
1053
- const longest = Math.max(...GUIDE_TOPICS.map((topic) => topic.id.length));
1054
- const rows = GUIDE_TOPICS.map((topic) => {
1055
- const id = paint(topic.id.padEnd(longest + 2), style.depth === "none" ? "" : DIM, style.depth);
1056
- return `${GUTTER}${id}${clip(topic.title, Math.max(0, available - longest - 2), glyphs)}`;
1057
- });
1058
- return [
1059
- rule(style, { label: "archymedes guide", tone: "accent" }),
1060
- ...rows,
1061
- "",
1062
- note(clip("/guide <topic> · /guide search <text> · /guide all", Math.max(0, style.width - GUTTER.length * 2), glyphs), style)
1063
- ].join(`
1064
- `);
1065
- }
1066
- function renderGuideTopic(topic, style) {
1067
- const glyphs = style.glyphs ?? UNICODE_GLYPHS;
1068
- const measure = Math.max(20, style.width - GUTTER.length * 2);
1069
- const parts = [
1070
- rule(style, { label: topic.title, tone: "accent" }),
1071
- ""
1072
- ];
1073
- for (const paragraph of topic.body) {
1074
- for (const line of wrapText(paragraph, measure))
1075
- parts.push(`${GUTTER}${line}`);
1076
- parts.push("");
1077
- }
1078
- if (topic.examples && topic.examples.length > 0) {
1079
- const inner = Math.max(8, style.width - GUTTER.length - 4);
1080
- const longest = Math.max(...topic.examples.map((example) => visibleWidth(example.input)));
1081
- const bold = (text) => paintAll(text, [style.depth === "none" ? "" : BOLD], style.depth);
1082
- const dim = (text) => paint(text, style.depth === "none" ? "" : DIM, style.depth);
1083
- const stacked = longest > Math.floor(inner / 2);
1084
- const rows = topic.examples.flatMap((example) => stacked ? [bold(example.input), ` ${dim(clip(example.effect, inner - 2, glyphs))}`] : [`${bold(example.input.padEnd(longest + 2))}${dim(clip(example.effect, inner - longest - 2, glyphs))}`]);
1085
- parts.push(panel(rows, style, { title: "try", tone: "accent" }));
1086
- }
1087
- const next = GUIDE_TOPICS[GUIDE_TOPICS.indexOf(topic) + 1];
1088
- if (next) {
1089
- parts.push(note(clip(`next: /guide ${next.id} ${glyphs.middot} ${next.title}`, Math.max(0, style.width - GUTTER.length * 2), glyphs), style));
1090
- }
1091
- return parts.join(`
1092
- `);
1093
- }
1094
- function renderWholeGuide(style) {
1095
- return [
1096
- renderGuideIndex(style),
1097
- "",
1098
- ...GUIDE_TOPICS.map((topic) => renderGuideTopic(topic, style))
1099
- ].join(`
1100
- `);
1101
- }
1102
- function parseGuideCommand(input) {
1103
- const match = /^\/(?:guide|tutorial)(?:\s+([\s\S]*))?$/.exec(input.trim());
1104
- if (!match)
1105
- return null;
1106
- const rest = (match[1] ?? "").trim().replace(/\s+/g, " ");
1107
- if (!rest)
1108
- return { kind: "index" };
1109
- const [verb, ...words] = rest.split(" ");
1110
- if (verb.toLowerCase() === "all")
1111
- return { kind: "all" };
1112
- if (verb.toLowerCase() === "search") {
1113
- const query = words.join(" ").trim();
1114
- return query ? { kind: "search", query } : { kind: "index" };
1115
- }
1116
- return findTopic(rest) ? { kind: "topic", id: findTopic(rest).id } : { kind: "unknown", id: rest };
1117
- }
1118
-
1119
- export { CONTROL_LANGUAGES, resolveControlLanguage, controlLabel, t, COMMANDS2 as COMMANDS, renderCommandHelp, suggestionsFor, inlineCompletion, isKnownCommand, parseModeCommand, suggestCommand, renderKeyboardShortcuts, newViewport, maxTop, applyViewport, visibleLines, atTop, atBottom, scrollFraction, GUIDE_TOPICS, findTopic, searchTopics, wrapText, renderGuideIndex, renderGuideTopic, renderWholeGuide, parseGuideCommand };