aicodeman 1.28.0 → 1.28.2

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.
Files changed (146) hide show
  1. package/README.md +1 -0
  2. package/README.zh-CN.md +1 -0
  3. package/dist/config/cli-registry/schema.d.ts +4 -0
  4. package/dist/config/cli-registry/schema.d.ts.map +1 -1
  5. package/dist/config/cli-registry/schema.js +7 -0
  6. package/dist/config/cli-registry/schema.js.map +1 -1
  7. package/dist/config/cli-registry/stock.d.ts.map +1 -1
  8. package/dist/config/cli-registry/stock.js +8 -0
  9. package/dist/config/cli-registry/stock.js.map +1 -1
  10. package/dist/config/cli-registry/types.d.ts +19 -0
  11. package/dist/config/cli-registry/types.d.ts.map +1 -1
  12. package/dist/docker-hosts.d.ts +22 -1
  13. package/dist/docker-hosts.d.ts.map +1 -1
  14. package/dist/docker-hosts.js +57 -3
  15. package/dist/docker-hosts.js.map +1 -1
  16. package/dist/hooks-config.d.ts +93 -0
  17. package/dist/hooks-config.d.ts.map +1 -1
  18. package/dist/hooks-config.js +211 -6
  19. package/dist/hooks-config.js.map +1 -1
  20. package/dist/session-cli-registry-bridge.d.ts +8 -0
  21. package/dist/session-cli-registry-bridge.d.ts.map +1 -1
  22. package/dist/session-cli-registry-bridge.js +14 -3
  23. package/dist/session-cli-registry-bridge.js.map +1 -1
  24. package/dist/session.d.ts.map +1 -1
  25. package/dist/session.js +6 -1
  26. package/dist/session.js.map +1 -1
  27. package/dist/tmux-manager.d.ts +21 -0
  28. package/dist/tmux-manager.d.ts.map +1 -1
  29. package/dist/tmux-manager.js +53 -0
  30. package/dist/tmux-manager.js.map +1 -1
  31. package/dist/usage-telemetry.d.ts +4 -1
  32. package/dist/usage-telemetry.d.ts.map +1 -1
  33. package/dist/usage-telemetry.js +6 -3
  34. package/dist/usage-telemetry.js.map +1 -1
  35. package/dist/web/public/admin-ui.js.gz +0 -0
  36. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  37. package/dist/web/public/app.78bf0bf8.js.gz +0 -0
  38. package/dist/web/public/approvals-ui.js.gz +0 -0
  39. package/dist/web/public/{constants.9cd8ed69.js → constants.258b140f.js} +50 -0
  40. package/dist/web/public/constants.258b140f.js.br +0 -0
  41. package/dist/web/public/constants.258b140f.js.gz +0 -0
  42. package/dist/web/public/cron-ui.js.gz +0 -0
  43. package/dist/web/public/entrance-animations.js.gz +0 -0
  44. package/dist/web/public/home-sessions.js.gz +0 -0
  45. package/dist/web/public/i18n.561ca09c.js +1 -0
  46. package/dist/web/public/i18n.561ca09c.js.br +0 -0
  47. package/dist/web/public/i18n.561ca09c.js.gz +0 -0
  48. package/dist/web/public/image-input.cd4b97c4.js.gz +0 -0
  49. package/dist/web/public/index.html +48 -12
  50. package/dist/web/public/index.html.br +0 -0
  51. package/dist/web/public/index.html.gz +0 -0
  52. package/dist/web/public/input-cjk.87f14251.js.gz +0 -0
  53. package/dist/web/public/keyboard-accessory.1d0dda9b.js.gz +0 -0
  54. package/dist/web/public/{mobile-handlers.2e9c214a.js → mobile-handlers.6f354a87.js} +61 -13
  55. package/dist/web/public/mobile-handlers.6f354a87.js.br +0 -0
  56. package/dist/web/public/mobile-handlers.6f354a87.js.gz +0 -0
  57. package/dist/web/public/mobile-overview.js +2 -2
  58. package/dist/web/public/mobile-overview.js.br +0 -0
  59. package/dist/web/public/mobile-overview.js.gz +0 -0
  60. package/dist/web/public/{mobile.65176832.css → mobile.e9d0b53e.css} +1 -1
  61. package/dist/web/public/mobile.e9d0b53e.css.br +0 -0
  62. package/dist/web/public/mobile.e9d0b53e.css.gz +0 -0
  63. package/dist/web/public/notification-manager.36ea4624.js.gz +0 -0
  64. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  65. package/dist/web/public/{panels-ui.4e9ea307.js → panels-ui.5b07ad14.js} +77 -77
  66. package/dist/web/public/panels-ui.5b07ad14.js.br +0 -0
  67. package/dist/web/public/panels-ui.5b07ad14.js.gz +0 -0
  68. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  69. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  70. package/dist/web/public/readmymind-ui.js.gz +0 -0
  71. package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
  72. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  73. package/dist/web/public/session-lineage.js.gz +0 -0
  74. package/dist/web/public/session-ui.5d0a7b15.js +77 -0
  75. package/dist/web/public/session-ui.5d0a7b15.js.br +0 -0
  76. package/dist/web/public/session-ui.5d0a7b15.js.gz +0 -0
  77. package/dist/web/public/settings-ui.e0c7f6b4.js +67 -0
  78. package/dist/web/public/settings-ui.e0c7f6b4.js.br +0 -0
  79. package/dist/web/public/settings-ui.e0c7f6b4.js.gz +0 -0
  80. package/dist/web/public/styles.5d36726d.css +1 -0
  81. package/dist/web/public/styles.5d36726d.css.br +0 -0
  82. package/dist/web/public/styles.5d36726d.css.gz +0 -0
  83. package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
  84. package/dist/web/public/sw.js.gz +0 -0
  85. package/dist/web/public/tab-rail-resize.42c24949.js.gz +0 -0
  86. package/dist/web/public/terminal-keycode229-recovery.6ea8fe37.js.gz +0 -0
  87. package/dist/web/public/terminal-ui.0cbe8637.js +2 -0
  88. package/dist/web/public/terminal-ui.0cbe8637.js.br +0 -0
  89. package/dist/web/public/terminal-ui.0cbe8637.js.gz +0 -0
  90. package/dist/web/public/ultracode-panel.js.gz +0 -0
  91. package/dist/web/public/ultracode-windows.js.gz +0 -0
  92. package/dist/web/public/upload.html.gz +0 -0
  93. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  94. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  95. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  96. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  97. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  98. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  99. package/dist/web/public/vendor/xterm-predictive-echo.bd6882b8.js.gz +0 -0
  100. package/dist/web/public/vendor/xterm-zerolag-input.6fee72f2.js.gz +0 -0
  101. package/dist/web/public/vendor/xterm.css.gz +0 -0
  102. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  103. package/dist/web/public/voice-input.c4b51eb6.js.gz +0 -0
  104. package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
  105. package/dist/web/public/webview-tabs.js.gz +0 -0
  106. package/dist/web/routes/session-routes.d.ts.map +1 -1
  107. package/dist/web/routes/session-routes.js +14 -22
  108. package/dist/web/routes/session-routes.js.map +1 -1
  109. package/dist/web/routes/status-telemetry-routes.d.ts +3 -2
  110. package/dist/web/routes/status-telemetry-routes.d.ts.map +1 -1
  111. package/dist/web/routes/status-telemetry-routes.js +6 -4
  112. package/dist/web/routes/status-telemetry-routes.js.map +1 -1
  113. package/dist/web/routes/system-routes.d.ts.map +1 -1
  114. package/dist/web/routes/system-routes.js +32 -22
  115. package/dist/web/routes/system-routes.js.map +1 -1
  116. package/dist/web/schemas.d.ts +0 -2
  117. package/dist/web/schemas.d.ts.map +1 -1
  118. package/dist/web/schemas.js +6 -8
  119. package/dist/web/schemas.js.map +1 -1
  120. package/dist/web/server.d.ts.map +1 -1
  121. package/dist/web/server.js +4 -1
  122. package/dist/web/server.js.map +1 -1
  123. package/package.json +10 -9
  124. package/dist/web/public/constants.9cd8ed69.js.br +0 -0
  125. package/dist/web/public/constants.9cd8ed69.js.gz +0 -0
  126. package/dist/web/public/i18n.9db8c4e0.js +0 -1
  127. package/dist/web/public/i18n.9db8c4e0.js.br +0 -0
  128. package/dist/web/public/i18n.9db8c4e0.js.gz +0 -0
  129. package/dist/web/public/mobile-handlers.2e9c214a.js.br +0 -0
  130. package/dist/web/public/mobile-handlers.2e9c214a.js.gz +0 -0
  131. package/dist/web/public/mobile.65176832.css.br +0 -0
  132. package/dist/web/public/mobile.65176832.css.gz +0 -0
  133. package/dist/web/public/panels-ui.4e9ea307.js.br +0 -0
  134. package/dist/web/public/panels-ui.4e9ea307.js.gz +0 -0
  135. package/dist/web/public/session-ui.cd222710.js +0 -77
  136. package/dist/web/public/session-ui.cd222710.js.br +0 -0
  137. package/dist/web/public/session-ui.cd222710.js.gz +0 -0
  138. package/dist/web/public/settings-ui.c175db9a.js +0 -67
  139. package/dist/web/public/settings-ui.c175db9a.js.br +0 -0
  140. package/dist/web/public/settings-ui.c175db9a.js.gz +0 -0
  141. package/dist/web/public/styles.0d41361c.css +0 -1
  142. package/dist/web/public/styles.0d41361c.css.br +0 -0
  143. package/dist/web/public/styles.0d41361c.css.gz +0 -0
  144. package/dist/web/public/terminal-ui.89e4eb1a.js +0 -2
  145. package/dist/web/public/terminal-ui.89e4eb1a.js.br +0 -0
  146. package/dist/web/public/terminal-ui.89e4eb1a.js.gz +0 -0
@@ -1 +0,0 @@
1
- "use strict";(function(a){"use strict";const c="Codeman",x=new Set(["en","zh-CN"]),C=["title","aria-label","placeholder"],O=["[data-i18n-skip]",".xterm",".terminal-container",".terminal-output",".response-content",".response-viewer-content",".file-preview-content",".session-tab-name",".session-name",".case-name",".notif-item-message","pre","code","script","style","textarea"].join(","),L=[".history-item-title",".history-item-subtitle",".history-detail-prompt",".history-detail-path",".folder-history-subtitle"].join(","),m=Object.freeze({"Skip to terminal":"\u8DF3\u8F6C\u5230\u7EC8\u7AEF","Go to main page":"\u8FD4\u56DE\u4E3B\u9875","Session tabs":"\u4F1A\u8BDD\u6807\u7B7E\u9875","Collapse session sidebar":"\u6536\u8D77\u4F1A\u8BDD\u4FA7\u8FB9\u680F","Expand session sidebar":"\u5C55\u5F00\u4F1A\u8BDD\u4FA7\u8FB9\u680F","Filter sessions":"\u7B5B\u9009\u4F1A\u8BDD","Admin Panel":"\u7BA1\u7406\u9762\u677F","Open admin panel":"\u6253\u5F00\u7BA1\u7406\u9762\u677F","Re-dock to dashboard (close window)":"\u91CD\u65B0\u505C\u9760\u5230\u4E3B\u754C\u9762\uFF08\u5173\u95ED\u7A97\u53E3\uFF09","Tunnel status":"\u96A7\u9053\u72B6\u6001","Decrease font size":"\u51CF\u5C0F\u5B57\u4F53","Increase font size":"\u589E\u5927\u5B57\u4F53","Current font size":"\u5F53\u524D\u5B57\u4F53\u5927\u5C0F","System resource usage":"\u7CFB\u7EDF\u8D44\u6E90\u4F7F\u7528\u60C5\u51B5","Redraw terminal":"\u91CD\u7ED8\u7EC8\u7AEF","Redraw terminal to fit current screen (Ctrl+Shift+R)":"\u91CD\u7ED8\u7EC8\u7AEF\u4EE5\u9002\u5E94\u5F53\u524D\u5C4F\u5E55\uFF08Ctrl+Shift+R\uFF09","View last response":"\u67E5\u770B\u6700\u8FD1\u4E00\u6B21\u56DE\u590D","Away Digest":"\u79BB\u5F00\u671F\u95F4\u6458\u8981","Open away digest":"\u6253\u5F00\u79BB\u5F00\u671F\u95F4\u6458\u8981","Session Manager":"\u4F1A\u8BDD\u7BA1\u7406\u5668","Session actions":"\u4F1A\u8BDD\u64CD\u4F5C","Open session manager":"\u6253\u5F00\u4F1A\u8BDD\u7BA1\u7406\u5668",Attachments:"\u9644\u4EF6","Open attachment history":"\u6253\u5F00\u9644\u4EF6\u5386\u53F2","File Viewer":"\u6587\u4EF6\u67E5\u770B\u5668","Open file viewer":"\u6253\u5F00\u6587\u4EF6\u67E5\u770B\u5668","Open Codeman across all displays":"\u5728\u6240\u6709\u663E\u793A\u5668\u4E0A\u6253\u5F00 {name}","Ultracode / Workflow agents":"Ultracode / Workflow \u667A\u80FD\u4F53","Open ultracode workflow agents":"\u6253\u5F00 Ultracode \u5DE5\u4F5C\u6D41\u667A\u80FD\u4F53",Notifications:"\u901A\u77E5","Toggle notifications":"\u5207\u6362\u901A\u77E5\u9762\u677F","Session Lifecycle Log":"\u4F1A\u8BDD\u751F\u547D\u5468\u671F\u65E5\u5FD7","Open session lifecycle log":"\u6253\u5F00\u4F1A\u8BDD\u751F\u547D\u5468\u671F\u65E5\u5FD7","App Settings":"\u5E94\u7528\u8BBE\u7F6E","Open app settings":"\u6253\u5F00\u5E94\u7528\u8BBE\u7F6E","Total tokens across all sessions":"\u6240\u6709\u4F1A\u8BDD\u7684 Token \u603B\u6570","Token usage across active sessions":"\u6D3B\u52A8\u4F1A\u8BDD\u7684 Token \u4F7F\u7528\u91CF","Instance count":"\u5B9E\u4F8B\u6570\u91CF","No response yet":"\u6682\u65E0\u56DE\u590D","No response yet \u2014 send a message in this session first.":"\u6682\u65E0\u56DE\u590D\uFF0C\u8BF7\u5148\u5728\u6B64\u4F1A\u8BDD\u4E2D\u53D1\u9001\u4E00\u6761\u6D88\u606F\u3002","No full conversation history available for this session":"\u6B64\u4F1A\u8BDD\u6CA1\u6709\u53EF\u663E\u793A\u7684\u5B8C\u6574\u5BF9\u8BDD\u5386\u53F2","Last Response":"\u6700\u8FD1\u4E00\u6B21\u56DE\u590D",More:"\u66F4\u591A","Codeman version":"{name}\u7248\u672C",Stop:"\u505C\u6B62",Watching:"\u76D1\u89C6\u4E2D",Orchestrator:"\u7F16\u6392\u5668",Close:"\u5173\u95ED","Close window":"\u5173\u95ED\u7A97\u53E3","Session unavailable":"\u4F1A\u8BDD\u4E0D\u53EF\u7528","This session has ended or is no longer available.":"\u6B64\u4F1A\u8BDD\u5DF2\u7ED3\u675F\u6216\u4E0D\u518D\u53EF\u7528\u3002","Manage AI Coding tools in persistent tmux sessions.":"\u5728\u6301\u4E45\u5316 tmux \u4F1A\u8BDD\u4E2D\u7BA1\u7406 AI \u7F16\u7A0B\u5DE5\u5177\u3002","Select case":"\u9009\u62E9\u6848\u4F8B","Select Case":"\u9009\u62E9\u6848\u4F8B","All cases":"\u5168\u90E8\u6848\u4F8B","No directory":"\u672A\u9009\u62E9\u76EE\u5F55",Run:"\u8FD0\u884C","Run Claude Code":"\u8FD0\u884C Claude Code","Run OpenCode":"\u8FD0\u884C OpenCode","Run Gemini":"\u8FD0\u884C Gemini","Run Antigravity":"\u8FD0\u884C Antigravity","Run Pi":"\u8FD0\u884C Pi","Run Grok":"\u8FD0\u884C Grok","Run DeepSeek":"\u8FD0\u884C DeepSeek","Run Shell":"\u8FD0\u884C Shell","Select AI backend":"\u9009\u62E9 AI \u540E\u7AEF","Create New Case":"\u65B0\u5EFA\u6848\u4F8B","Create new case":"\u65B0\u5EFA\u6848\u4F8B","Link Existing":"\u5173\u8054\u73B0\u6709\u76EE\u5F55","Add Case":"\u6DFB\u52A0\u6848\u4F8B","Open sessions":"\u6253\u5F00\u4F1A\u8BDD","Recent Sessions":"\u6700\u8FD1\u4F1A\u8BDD","Search sessions by name, prompt, or path\u2026":"\u6309\u540D\u79F0\u3001\u63D0\u793A\u8BCD\u6216\u8DEF\u5F84\u641C\u7D22\u4F1A\u8BDD\u2026","Search open sessions or start a new one":"\u641C\u7D22\u5DF2\u6253\u5F00\u4F1A\u8BDD\u6216\u542F\u52A8\u65B0\u4F1A\u8BDD","Find Open Session":"\u67E5\u627E\u5DF2\u6253\u5F00\u4F1A\u8BDD","No background agents":"\u6CA1\u6709\u540E\u53F0\u667A\u80FD\u4F53","No background agents detected":"\u672A\u68C0\u6D4B\u5230\u540E\u53F0\u667A\u80FD\u4F53","No notifications":"\u6CA1\u6709\u901A\u77E5","No mux sessions":"\u6CA1\u6709 mux \u4F1A\u8BDD","No lifecycle entries found":"\u672A\u627E\u5230\u751F\u547D\u5468\u671F\u8BB0\u5F55","No ultracode runs detected":"\u672A\u68C0\u6D4B\u5230 Ultracode \u8FD0\u884C",Display:"\u663E\u793A","Claude CLI":"Claude CLI","Codex CLI":"Codex CLI",Models:"\u6A21\u578B",Shortcuts:"\u5FEB\u6377\u952E",Voice:"\u8BED\u97F3",Save:"\u4FDD\u5B58",Cancel:"\u53D6\u6D88",Apply:"\u5E94\u7528",Create:"\u521B\u5EFA",Add:"\u6DFB\u52A0",Delete:"\u5220\u9664",Remove:"\u79FB\u9664",Edit:"\u7F16\u8F91",Refresh:"\u5237\u65B0",Back:"\u8FD4\u56DE",Next:"\u4E0B\u4E00\u6B65",Previous:"\u4E0A\u4E00\u6B65",Clear:"\u6E05\u9664","Clear all":"\u5168\u90E8\u6E05\u9664","Clear All":"\u5168\u90E8\u6E05\u9664",Search:"\u641C\u7D22",Filter:"\u7B5B\u9009",Enable:"\u542F\u7528",Enabled:"\u5DF2\u542F\u7528",Disabled:"\u5DF2\u7981\u7528",Active:"\u6D3B\u52A8","Not active":"\u672A\u6D3B\u52A8",On:"\u5F00",Off:"\u5173",Yes:"\u662F",No:"\u5426",Optional:"\u53EF\u9009",Default:"\u9ED8\u8BA4",Custom:"\u81EA\u5B9A\u4E49",Name:"\u540D\u79F0",Description:"\u63CF\u8FF0",Status:"\u72B6\u6001",Reason:"\u539F\u56E0",Time:"\u65F6\u95F4",Event:"\u4E8B\u4EF6",Events:"\u4E8B\u4EF6",Session:"\u4F1A\u8BDD",Sessions:"\u4F1A\u8BDD",Files:"\u6587\u4EF6",History:"\u5386\u53F2",Summary:"\u6458\u8981",Details:"\u8BE6\u60C5",Options:"\u9009\u9879",Settings:"\u8BBE\u7F6E",Help:"\u5E2E\u52A9",Loading:"\u6B63\u5728\u52A0\u8F7D",Error:"\u9519\u8BEF",Errors:"\u9519\u8BEF",Warning:"\u8B66\u544A",Warnings:"\u8B66\u544A",Info:"\u4FE1\u606F",Complete:"\u5B8C\u6210",Completed:"\u5DF2\u5B8C\u6210",Stopped:"\u5DF2\u505C\u6B62",Running:"\u8FD0\u884C\u4E2D",Idle:"\u7A7A\u95F2",Working:"\u5DE5\u4F5C\u4E2D",Today:"\u4ECA\u5929",Home:"\u4E3B\u9875",Local:"\u672C\u5730",Remote:"\u8FDC\u7A0B",Docker:"Docker",Terminal:"\u7EC8\u7AEF",Prompt:"\u63D0\u793A\u8BCD",Source:"\u6765\u6E90",Type:"\u7C7B\u578B",Language:"\u8BED\u8A00","Branding & Language":"\u54C1\u724C\u4E0E\u8BED\u8A00","Display Name":"\u663E\u793A\u540D\u79F0","Interface Language":"\u754C\u9762\u8BED\u8A00","Name shown in the browser UI and window title. Supports Unicode, including Chinese.":"\u663E\u793A\u5728\u6D4F\u89C8\u5668\u754C\u9762\u548C\u7A97\u53E3\u6807\u9898\u4E2D\u7684\u540D\u79F0\u3002\u652F\u6301 Unicode\uFF0C\u5305\u62EC\u4E2D\u6587\u3002","Language for this device. Dynamic status messages and dialogs use the same language.":"\u6B64\u8BBE\u5907\u4F7F\u7528\u7684\u754C\u9762\u8BED\u8A00\u3002\u52A8\u6001\u72B6\u6001\u6D88\u606F\u4E0E\u5BF9\u8BDD\u6846\u4E5F\u4F1A\u4F7F\u7528\u540C\u4E00\u8BED\u8A00\u3002",English:"English",Appearance:"\u5916\u89C2",Skin:"\u76AE\u80A4","Visual theme for this device (not synced)":"\u6B64\u8BBE\u5907\u7684\u89C6\u89C9\u4E3B\u9898\uFF08\u4E0D\u540C\u6B65\uFF09","Daylight Blue":"\u65E5\u5149\u84DD","Daylight Green":"\u65E5\u5149\u7EFF","OG Codeman":"\u7ECF\u5178 {name}",Performance:"\u6027\u80FD","WebGL Renderer":"WebGL \u6E32\u67D3\u5668","Header Displays":"\u9876\u90E8\u680F\u663E\u793A","Font Controls":"\u5B57\u4F53\u63A7\u5236","System Stats":"\u7CFB\u7EDF\u72B6\u6001","Lifecycle Log":"\u751F\u547D\u5468\u671F\u65E5\u5FD7","Response Viewer":"\u56DE\u590D\u67E5\u770B\u5668","Attachments Button":"\u9644\u4EF6\u6309\u94AE","Multi-monitor Button":"\u591A\u663E\u793A\u5668\u6309\u94AE","Session Manager Button":"\u4F1A\u8BDD\u7BA1\u7406\u5668\u6309\u94AE","Away Digest Button":"\u79BB\u5F00\u671F\u95F4\u6458\u8981\u6309\u94AE","Cron Button":"\u5B9A\u65F6\u4EFB\u52A1\u6309\u94AE","Redraw Terminal Button":"\u91CD\u7ED8\u7EC8\u7AEF\u6309\u94AE","Tab Bar":"\u6807\u7B7E\u680F","Session List Layout":"\u4F1A\u8BDD\u5217\u8868\u5E03\u5C40","Session Name Font Size":"\u4F1A\u8BDD\u540D\u79F0\u5B57\u4F53\u5927\u5C0F","Adjust only session names in the vertical sidebar.":"\u4EC5\u8C03\u6574\u5782\u76F4\u4FA7\u8FB9\u680F\u4E2D\u7684\u4F1A\u8BDD\u540D\u79F0\u3002","Header tab strip":"\u9876\u680F\u6807\u7B7E\u6761","Left sidebar":"\u5DE6\u4FA7\u8FB9\u680F","Left sidebar simple":"\u5DE6\u4FA7\u8FB9\u680F\uFF08\u7B80\u6D01\uFF09","Horizontal strip in the header, or a collapsible left sidebar (Alt+B). The rich sidebar carries the same per-session detail as the home screen.":"\u4F1A\u8BDD\u5217\u8868\u663E\u793A\u4E3A\u9876\u680F\u6A2A\u5411\u6807\u7B7E\u6761\uFF0C\u6216\u5DE6\u4FA7\u53EF\u6298\u53E0\u4FA7\u8FB9\u680F\uFF08Alt+B\uFF09\u3002\u5B8C\u6574\u4FA7\u8FB9\u680F\u4E3A\u6BCF\u4E2A\u4F1A\u8BDD\u663E\u793A\u4E0E\u4E3B\u754C\u9762\u76F8\u540C\u7684\u8BE6\u7EC6\u4FE1\u606F\u3002","Tall Tabs (Name + Folder)":"\u53CC\u884C\u6807\u7B7E\uFF08\u540D\u79F0 + \u6587\u4EF6\u5939\uFF09","Pop-out Button on Tabs":"\u6807\u7B7E\u9875\u5F39\u51FA\u7A97\u53E3\u6309\u94AE",Panels:"\u9762\u677F",Monitor:"\u76D1\u89C6\u5668","Project Insights":"\u9879\u76EE\u6D1E\u5BDF","File Browser":"\u6587\u4EF6\u6D4F\u89C8\u5668",Subagents:"\u5B50\u667A\u80FD\u4F53","Ultracode Agents":"Ultracode \u667A\u80FD\u4F53","Ultracode Floating Windows":"Ultracode \u6D6E\u52A8\u7A97\u53E3","Approvals Inbox":"\u5BA1\u6279\u6536\u4EF6\u7BB1",Approvals:"\u5BA1\u6279","Prompts waiting on you, across all sessions":"\u6240\u6709\u4F1A\u8BDD\u4E2D\u7B49\u5F85\u60A8\u5904\u7406\u7684\u63D0\u793A","No pending approvals":"\u6CA1\u6709\u5F85\u5904\u7406\u7684\u5BA1\u6279","Approvals waiting on you":"\u7B49\u5F85\u60A8\u5BA1\u6279\u7684\u8BF7\u6C42","Open approvals inbox":"\u6253\u5F00\u5BA1\u6279\u6536\u4EF6\u7BB1","Close approvals inbox":"\u5173\u95ED\u5BA1\u6279\u6536\u4EF6\u7BB1",Approve:"\u6279\u51C6","Deny (Esc)":"\u62D2\u7EDD (Esc)",Deny:"\u62D2\u7EDD","Open session":"\u6253\u5F00\u4F1A\u8BDD",Dismiss:"\u5FFD\u7565",Send:"\u53D1\u9001",Permission:"\u6743\u9650",Question:"\u95EE\u9898",Idle:"\u7A7A\u95F2","Read My Mind":"\u8BFB\u5FC3\u672F","Read My Mind: predict your next prompt":"\u8BFB\u5FC3\u672F\uFF1A\u9884\u6D4B\u60A8\u7684\u4E0B\u4E00\u6761\u63D0\u793A","Predict my next prompt":"\u9884\u6D4B\u6211\u7684\u4E0B\u4E00\u6761\u63D0\u793A","Reading your mind\u2026":"\u6B63\u5728\u8BFB\u53D6\u60A8\u7684\u60F3\u6CD5\u2026","No suggestion this time. Add a steer note and Rethink to try again.":"\u8FD9\u6B21\u6CA1\u6709\u5EFA\u8BAE\u3002\u53EF\u6DFB\u52A0\u5F15\u5BFC\u5907\u6CE8\u540E\u70B9\u51FB\u300C\u91CD\u60F3\u300D\u518D\u8BD5\u4E00\u6B21\u3002",Rethink:"\u91CD\u60F3",Insert:"\u63D2\u5165","Put the text on the session's composer without submitting it":"\u5C06\u6587\u672C\u653E\u5165\u4F1A\u8BDD\u8F93\u5165\u6846\u4F46\u4E0D\u63D0\u4EA4","Predicted prompt, editable":"\u9884\u6D4B\u7684\u63D0\u793A\uFF0C\u53EF\u7F16\u8F91","Use this suggestion instead":"\u6539\u7528\u6B64\u5EFA\u8BAE","Steer the rethink, e.g. 'no, I meant the mobile bug'":'\u5F15\u5BFC\u91CD\u60F3\uFF0C\u4F8B\u5982\uFF1A"\u4E0D\uFF0C\u6211\u662F\u6307\u79FB\u52A8\u7AEF\u7684\u95EE\u9898"',"Steer note for Rethink":"\u91CD\u60F3\u7684\u5F15\u5BFC\u5907\u6CE8","Select a session first":"\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u4F1A\u8BDD","Read My Mind works on Claude sessions only":"\u8BFB\u5FC3\u672F\u4EC5\u9002\u7528\u4E8E Claude \u4F1A\u8BDD","Prompt sent":"\u63D0\u793A\u5DF2\u53D1\u9001","Inserted, press Enter in the terminal to send":"\u5DF2\u63D2\u5165\uFF0C\u5728\u7EC8\u7AEF\u4E2D\u6309 Enter \u53D1\u9001","Could not reach the session":"\u65E0\u6CD5\u8FDE\u63A5\u5230\u4F1A\u8BDD","Subagent Options":"\u5B50\u667A\u80FD\u4F53\u9009\u9879","Enable Tracking":"\u542F\u7528\u8DDF\u8E2A","Active Tab Only":"\u4EC5\u6D3B\u52A8\u6807\u7B7E\u9875","Image Watcher":"\u56FE\u50CF\u76D1\u89C6\u5668","Enable Globally":"\u5168\u5C40\u542F\u7528","Remote Access":"\u8FDC\u7A0B\u8BBF\u95EE","Cloudflare Tunnel":"Cloudflare \u96A7\u9053","Tunnel URL":"\u96A7\u9053\u5730\u5740","Upload URL":"\u4E0A\u4F20\u5730\u5740",Updates:"\u66F4\u65B0","Current Version":"\u5F53\u524D\u7248\u672C","Check for Updates":"\u68C0\u67E5\u66F4\u65B0","Check now":"\u7ACB\u5373\u68C0\u67E5","Update available":"\u6709\u53EF\u7528\u66F4\u65B0","Update now":"\u7ACB\u5373\u66F4\u65B0","Show CPU and memory usage in header":"\u5728\u9876\u90E8\u680F\u663E\u793A CPU \u4E0E\u5185\u5B58\u4F7F\u7528\u60C5\u51B5","Show session lifecycle log button in header":"\u5728\u9876\u90E8\u680F\u663E\u793A\u4F1A\u8BDD\u751F\u547D\u5468\u671F\u65E5\u5FD7\u6309\u94AE","Show the response viewer (eye) button in header":"\u5728\u9876\u90E8\u680F\u663E\u793A\u56DE\u590D\u67E5\u770B\u5668\uFF08\u773C\u775B\uFF09\u6309\u94AE","Show the file viewer button in header (opens the file browser panel for the active session)":"\u5728\u9876\u90E8\u680F\u663E\u793A\u6587\u4EF6\u67E5\u770B\u5668\u6309\u94AE\uFF08\u6253\u5F00\u5F53\u524D\u4F1A\u8BDD\u7684\u6587\u4EF6\u6D4F\u89C8\u5668\u9762\u677F\uFF09","Show the attachments button in header (opens the attachment history drawer)":"\u5728\u9876\u90E8\u680F\u663E\u793A\u9644\u4EF6\u6309\u94AE\uFF08\u6253\u5F00\u9644\u4EF6\u5386\u53F2\u62BD\u5C49\uFF09","Show the multi-monitor button in the header (opens Codeman spanned across all displays)":"\u5728\u9876\u90E8\u680F\u663E\u793A\u591A\u663E\u793A\u5668\u6309\u94AE\uFF08\u8DE8\u6240\u6709\u663E\u793A\u5668\u6253\u5F00 {name}\uFF09","Show the session manager button in the header (opens the session manager \u2014 sessions also stay reachable via the Ctrl+K palette)":"\u5728\u9876\u90E8\u680F\u663E\u793A\u4F1A\u8BDD\u7BA1\u7406\u5668\u6309\u94AE\uFF08\u4E5F\u53EF\u901A\u8FC7 Ctrl+K \u9762\u677F\u8BBF\u95EE\u4F1A\u8BDD\uFF09","Show the away digest button in the header (opens the 'what happened while you were away' summary)":"\u5728\u9876\u90E8\u680F\u663E\u793A\u79BB\u5F00\u671F\u95F4\u6458\u8981\u6309\u94AE","Show the Cron button in the footer toolbar (opens the cron jobs manager)":"\u5728\u5E95\u90E8\u5DE5\u5177\u680F\u663E\u793A\u5B9A\u65F6\u4EFB\u52A1\u6309\u94AE","Show a terminal redraw button in the header \u2014 refit the terminal to the current screen size (useful when switching between devices)":"\u5728\u9876\u90E8\u680F\u663E\u793A\u7EC8\u7AEF\u91CD\u7ED8\u6309\u94AE\uFF0C\u4EE5\u91CD\u65B0\u9002\u914D\u5F53\u524D\u5C4F\u5E55\u5927\u5C0F","Show folder path below tab name and allow tab bar to wrap into multiple rows":"\u5728\u6807\u7B7E\u540D\u79F0\u4E0B\u663E\u793A\u6587\u4EF6\u5939\u8DEF\u5F84\uFF0C\u5E76\u5141\u8BB8\u6807\u7B7E\u680F\u6362\u884C","Show Monitor panel at bottom right":"\u5728\u53F3\u4E0B\u89D2\u663E\u793A\u76D1\u89C6\u5668\u9762\u677F","Show active tools and file viewers in a floating panel":"\u5728\u6D6E\u52A8\u9762\u677F\u4E2D\u663E\u793A\u6D3B\u52A8\u5DE5\u5177\u4E0E\u6587\u4EF6\u67E5\u770B\u5668","Show file browser panel on the right side":"\u5728\u53F3\u4FA7\u663E\u793A\u6587\u4EF6\u6D4F\u89C8\u5668\u9762\u677F","Show the Subagents panel (independent from Monitor)":"\u663E\u793A\u5B50\u667A\u80FD\u4F53\u9762\u677F\uFF08\u72EC\u7ACB\u4E8E\u76D1\u89C6\u5668\uFF09","Monitor Claude Code background agents in real-time":"\u5B9E\u65F6\u76D1\u89C6 Claude Code \u540E\u53F0\u667A\u80FD\u4F53","Only show subagent windows when their parent tab is selected":"\u4EC5\u5728\u9009\u4E2D\u7236\u6807\u7B7E\u9875\u65F6\u663E\u793A\u5B50\u667A\u80FD\u4F53\u7A97\u53E3","Automatically detect and popup new images in session directories":"\u81EA\u52A8\u68C0\u6D4B\u5E76\u5F39\u51FA\u4F1A\u8BDD\u76EE\u5F55\u4E2D\u7684\u65B0\u56FE\u50CF","Expose Codeman via Cloudflare Tunnel for remote access":"\u901A\u8FC7 Cloudflare \u96A7\u9053\u8FDC\u7A0B\u8BBF\u95EE {name}","Codeman version currently running":"\u5F53\u524D\u8FD0\u884C\u7684{name}\u7248\u672C","Check GitHub for a newer Codeman release":"\u68C0\u67E5 GitHub \u4E0A\u662F\u5426\u6709\u65B0\u7248 {name}",Input:"\u8F93\u5165",Font:"\u5B57\u4F53","Terminal font":"\u7EC8\u7AEF\u5B57\u4F53","Prepended to the built-in stack, so fallbacks (including bundled Nerd Font symbols) keep working. Must be installed on this device. Leave empty for the default.":"\u7F6E\u4E8E\u5185\u7F6E\u5B57\u4F53\u6808\u4E4B\u524D\uFF0C\u56DE\u9000\u5B57\u4F53\uFF08\u5305\u62EC\u5185\u7F6E\u7684 Nerd Font \u56FE\u6807\uFF09\u4ECD\u7136\u751F\u6548\u3002\u9700\u5DF2\u5B89\u88C5\u5728\u672C\u8BBE\u5907\u4E0A\u3002\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\u503C\u3002","Local Echo":"\u672C\u5730\u56DE\u663E","CJK Input":"\u4E2D\u65E5\u97E9\u8F93\u5165","Extended Keyboard Bar":"\u6269\u5C55\u952E\u76D8\u680F","Gesture Control (beta)":"\u624B\u52BF\u63A7\u5236\uFF08\u6D4B\u8BD5\u7248\uFF09","Wheel Scrolls Local History":"\u6EDA\u8F6E\u6EDA\u52A8\u672C\u5730\u5386\u53F2","Auto Copy Selection":"\u81EA\u52A8\u590D\u5236\u9009\u4E2D\u5185\u5BB9","Selection & clipboard":"\u9009\u4E2D\u4E0E\u526A\u8D34\u677F","Auto Copy: selection copied":"\u81EA\u52A8\u590D\u5236\uFF1A\u5DF2\u590D\u5236\u9009\u4E2D\u5185\u5BB9","Auto Copy failed: the browser blocked clipboard access":"\u81EA\u52A8\u590D\u5236\u5931\u8D25\uFF1A\u6D4F\u89C8\u5668\u963B\u6B62\u4E86\u526A\u8D34\u677F\u8BBF\u95EE","Selection too large to copy automatically. Press Ctrl+C.":"\u9009\u4E2D\u5185\u5BB9\u8FC7\u5927\uFF0C\u65E0\u6CD5\u81EA\u52A8\u590D\u5236\u3002\u8BF7\u6309 Ctrl+C\u3002","Instant typing feedback with local echo":"\u901A\u8FC7\u672C\u5730\u56DE\u663E\u5373\u65F6\u663E\u793A\u8F93\u5165","Dedicated IME input field for CJK languages":"\u4E3A\u4E2D\u65E5\u97E9\u8BED\u8A00\u63D0\u4F9B\u4E13\u7528\u8F93\u5165\u6CD5\u6587\u672C\u6846","Extra keys: Tab, Esc, arrows, Ctrl+O":"\u9644\u52A0\u6309\u952E\uFF1ATab\u3001Esc\u3001\u65B9\u5411\u952E\u3001Ctrl+O","Startup Mode":"\u542F\u52A8\u6A21\u5F0F","Skip Permissions (default)":"\u8DF3\u8FC7\u6743\u9650\u786E\u8BA4\uFF08\u9ED8\u8BA4\uFF09","Auto (classifier-guarded, low prompts)":"\u81EA\u52A8\uFF08\u5206\u7C7B\u5668\u4FDD\u62A4\uFF0C\u8F83\u5C11\u63D0\u793A\uFF09","Normal (with prompts)":"\u666E\u901A\uFF08\u663E\u793A\u63D0\u793A\uFF09","Allowed Tools Only":"\u4EC5\u5141\u8BB8\u6307\u5B9A\u5DE5\u5177","Allowed Tools":"\u5141\u8BB8\u7684\u5DE5\u5177","Comma-separated list of tools to allow":"\u4EE5\u9017\u53F7\u5206\u9694\u5141\u8BB8\u4F7F\u7528\u7684\u5DE5\u5177","Enable Ralph / Todo Tracker":"\u542F\u7528 Ralph / \u5F85\u529E\u8DDF\u8E2A\u5668","Claude Permissions":"Claude \u6743\u9650","Agent Teams":"\u667A\u80FD\u4F53\u56E2\u961F","Claude Model":"Claude \u6A21\u578B","1M Opus Context":"Opus 100 \u4E07\u4E0A\u4E0B\u6587","Remote auto-reconnect":"\u8FDC\u7A0B\u81EA\u52A8\u91CD\u8FDE","Thinking Effort":"\u601D\u8003\u5F3A\u5EA6",Low:"\u4F4E",Medium:"\u4E2D",High:"\u9AD8",Max:"\u6700\u9AD8","Nice Priority":"Nice \u4F18\u5148\u7EA7","Enable Nice Priority Reduction":"\u542F\u7528 Nice \u4F18\u5148\u7EA7\u8C03\u6574","Nice Value":"Nice \u503C","Bypass Approvals and Sandbox":"\u7ED5\u8FC7\u5BA1\u6279\u4E0E\u6C99\u7BB1","Default Model":"\u9ED8\u8BA4\u6A21\u578B","Show Optimizer Recommendations":"\u663E\u793A\u4F18\u5316\u5668\u5EFA\u8BAE","Agent Type Overrides":"\u6309\u667A\u80FD\u4F53\u7C7B\u578B\u8986\u76D6","Use Default":"\u4F7F\u7528\u9ED8\u8BA4\u503C","Enable Notifications":"\u542F\u7528\u901A\u77E5","Master toggle for all notification layers":"\u6240\u6709\u901A\u77E5\u5C42\u7684\u603B\u5F00\u5173","Browser Notifications":"\u6D4F\u89C8\u5668\u901A\u77E5","Audio Alerts":"\u58F0\u97F3\u63D0\u9192","Push Notifications":"\u63A8\u9001\u901A\u77E5","Notification Levels":"\u901A\u77E5\u7EA7\u522B",Critical:"\u4E25\u91CD","Per-Event Settings":"\u6309\u4E8B\u4EF6\u8BBE\u7F6E","Permission prompts":"\u6743\u9650\u63D0\u793A","Questions from Claude":"Claude \u63D0\u95EE","Session idle":"\u4F1A\u8BDD\u7A7A\u95F2","Response complete":"\u56DE\u590D\u5B8C\u6210","Respawn cycles":"\u91CD\u751F\u5FAA\u73AF","Task complete":"\u4EFB\u52A1\u5B8C\u6210","Subagent activity":"\u5B50\u667A\u80FD\u4F53\u6D3B\u52A8",Browser:"\u6D4F\u89C8\u5668",Audio:"\u58F0\u97F3",Push:"\u63A8\u9001","Voice Input":"\u8BED\u97F3\u8F93\u5165",Provider:"\u670D\u52A1\u5546","Active Provider":"\u5F53\u524D\u670D\u52A1\u5546","API Key":"API \u5BC6\u94A5","Domain Keywords":"\u9886\u57DF\u5173\u952E\u8BCD","Input Mode":"\u8F93\u5165\u6A21\u5F0F","Direct to input":"\u76F4\u63A5\u8F93\u5165","Compose dialog":"\u7F16\u8F91\u5BF9\u8BDD\u6846","Keyboard Shortcuts":"\u952E\u76D8\u5FEB\u6377\u952E","Customize keyboard shortcuts. Click the binding to capture a new key combination.":"\u81EA\u5B9A\u4E49\u952E\u76D8\u5FEB\u6377\u952E\u3002\u70B9\u51FB\u6309\u952E\u7EC4\u5408\u5373\u53EF\u5F55\u5165\u65B0\u7684\u7EC4\u5408\u3002","Show Shortcuts":"\u663E\u793A\u5FEB\u6377\u952E","Full shortcut reference":"\u5B8C\u6574\u5FEB\u6377\u952E\u53C2\u8003","Needs you":"\u9700\u8981\u4F60","Current sessions":"\u5F53\u524D\u4F1A\u8BDD","Past sessions":"\u5386\u53F2\u4F1A\u8BDD","Show all past sessions":"\u663E\u793A\u5168\u90E8\u5386\u53F2\u4F1A\u8BDD","Show fewer":"\u6536\u8D77","Choose what to run":"\u9009\u62E9\u8FD0\u884C\u65B9\u5F0F","Web / URL":"\u7F51\u9875 / \u94FE\u63A5","Add URL\u2026":"\u6DFB\u52A0\u94FE\u63A5\u2026","Nothing running. Hit Run to start something.":"\u5F53\u524D\u6CA1\u6709\u8FD0\u884C\u4E2D\u7684\u4F1A\u8BDD\u3002\u70B9\u51FB\u201C\u8FD0\u884C\u201D\u5F00\u59CB\u3002","No past conversations yet":"\u5C1A\u65E0\u5386\u53F2\u5BF9\u8BDD","Loading\u2026":"\u52A0\u8F7D\u4E2D\u2026","Overview Home Screen":"\u6982\u89C8\u4E3B\u9875","On phones, the C logo opens a session overview (needs you / spaces / idle) instead of the welcome screen":"\u5728\u624B\u673A\u4E0A\uFF0C\u70B9\u51FB C \u56FE\u6807\u6253\u5F00\u4F1A\u8BDD\u6982\u89C8\uFF08\u9700\u8981\u4F60 / \u7A7A\u95F4 / \u7A7A\u95F2\uFF09\uFF0C\u800C\u4E0D\u662F\u6B22\u8FCE\u9875",Phone:"\u624B\u673A","Open tabs":"\u6253\u5F00\u7684\u6807\u7B7E","Session Options":"\u4F1A\u8BDD\u9009\u9879","Session Name":"\u4F1A\u8BDD\u540D\u79F0","Session Color":"\u4F1A\u8BDD\u989C\u8272","Working Directory":"\u5DE5\u4F5C\u76EE\u5F55","Set working directory":"\u8BBE\u7F6E\u5DE5\u4F5C\u76EE\u5F55","Resume Conversation":"\u7EE7\u7EED\u5BF9\u8BDD","Close Session":"\u5173\u95ED\u4F1A\u8BDD","Choose how to close":"\u9009\u62E9\u5173\u95ED\u65B9\u5F0F","Tmux session keeps running in background":"Tmux \u4F1A\u8BDD\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C","Terminate the session completely":"\u5F7B\u5E95\u7EC8\u6B62\u4F1A\u8BDD","Cancel close session":"\u53D6\u6D88\u5173\u95ED\u4F1A\u8BDD","Case Name":"\u6848\u4F8B\u540D\u79F0","Folder Path":"\u6587\u4EF6\u5939\u8DEF\u5F84","Default Working Directory":"\u9ED8\u8BA4\u5DE5\u4F5C\u76EE\u5F55","Default directory for new sessions.":"\u65B0\u4F1A\u8BDD\u7684\u9ED8\u8BA4\u76EE\u5F55\u3002","Default CLAUDE.md Template":"\u9ED8\u8BA4 CLAUDE.md \u6A21\u677F","Used when creating new cases. Leave empty for built-in template.":"\u521B\u5EFA\u65B0\u6848\u4F8B\u65F6\u4F7F\u7528\uFF1B\u7559\u7A7A\u5219\u4F7F\u7528\u5185\u7F6E\u6A21\u677F\u3002","Remote Path":"\u8FDC\u7A0B\u8DEF\u5F84","SSH Host/IP":"SSH \u4E3B\u673A/IP","SSH Username":"SSH \u7528\u6237\u540D","SSH Port":"SSH \u7AEF\u53E3","Identity File":"\u8EAB\u4EFD\u6587\u4EF6","Jump Host":"\u8DF3\u677F\u4E3B\u673A","Advanced SSH":"\u9AD8\u7EA7 SSH","Discover existing sessions":"\u53D1\u73B0\u73B0\u6709\u4F1A\u8BDD","Workspace Path":"\u5DE5\u4F5C\u533A\u8DEF\u5F84","Container settings (optional, sensible defaults)":"\u5BB9\u5668\u8BBE\u7F6E\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4\u503C\u5408\u7406\uFF09",Template:"\u6A21\u677F",Network:"\u7F51\u7EDC",CPUs:"CPU \u6570",Memory:"\u5185\u5B58",GPUs:"GPU","Cron Jobs":"\u5B9A\u65F6\u4EFB\u52A1","+ New Job":"+ \u65B0\u5EFA\u4EFB\u52A1","New Cron Job":"\u65B0\u5EFA\u5B9A\u65F6\u4EFB\u52A1",Schedule:"\u8BA1\u5212","Schedule Type":"\u8BA1\u5212\u7C7B\u578B",Once:"\u4E00\u6B21",Interval:"\u95F4\u9694",Daily:"\u6BCF\u5929",Weekly:"\u6BCF\u5468","Run At":"\u8FD0\u884C\u65F6\u95F4","Every (minutes)":"\u6BCF\u9694\uFF08\u5206\u949F\uFF09",Weekdays:"\u5DE5\u4F5C\u65E5","Times use the server's local timezone.":"\u65F6\u95F4\u4F7F\u7528\u670D\u52A1\u5668\u672C\u5730\u65F6\u533A\u3002","All Events":"\u5168\u90E8\u4E8B\u4EF6",Created:"\u5DF2\u521B\u5EFA",Started:"\u5DF2\u542F\u52A8",Exit:"\u9000\u51FA",Deleted:"\u5DF2\u5220\u9664",Recovered:"\u5DF2\u6062\u590D","Stale Cleaned":"\u5DF2\u6E05\u7406\u8FC7\u671F\u9879","Mux Died":"Mux \u5DF2\u7EC8\u6B62","Server Started":"\u670D\u52A1\u5668\u5DF2\u542F\u52A8","Server Stopped":"\u670D\u52A1\u5668\u5DF2\u505C\u6B62",Extra:"\u9644\u52A0\u4FE1\u606F","Token Usage Statistics":"Token \u4F7F\u7528\u7EDF\u8BA1","Daily Breakdown":"\u6BCF\u65E5\u660E\u7EC6","Export JSON":"\u5BFC\u51FA JSON","Export MD":"\u5BFC\u51FA Markdown","Settings saved":"\u8BBE\u7F6E\u5DF2\u4FDD\u5B58","Settings saved locally":"\u8BBE\u7F6E\u5DF2\u4FDD\u5B58\u5230\u672C\u673A","Tunnel active":"\u96A7\u9053\u5DF2\u542F\u7528","Tunnel starting \u2014 QR code will appear when ready...":"\u96A7\u9053\u6B63\u5728\u542F\u52A8\uFF0C\u51C6\u5907\u597D\u540E\u5C06\u663E\u793A\u4E8C\u7EF4\u7801\u2026","Push notifications enabled":"\u63A8\u9001\u901A\u77E5\u5DF2\u542F\u7528","Push notifications disabled":"\u63A8\u9001\u901A\u77E5\u5DF2\u7981\u7528","Permission Required":"\u9700\u8981\u6388\u6743","Waiting for Input":"\u7B49\u5F85\u8F93\u5165","Question Asked":"Claude \u6B63\u5728\u63D0\u95EE","Response Complete":"\u56DE\u590D\u5B8C\u6210","Task Completed":"\u4EFB\u52A1\u5DF2\u5B8C\u6210","Teammate Idle":"\u961F\u53CB\u7A7A\u95F2","Session Error":"\u4F1A\u8BDD\u9519\u8BEF","Respawn Blocked":"\u91CD\u751F\u5DF2\u963B\u6B62","Task Complete":"\u4EFB\u52A1\u5B8C\u6210","Copied to clipboard":"\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F",Copy:"\u590D\u5236",Line:"\u6574\u884C","Clear selection":"\u6E05\u9664\u9009\u62E9","Failed to copy":"\u590D\u5236\u5931\u8D25","Checking\u2026":"\u6B63\u5728\u68C0\u67E5\u2026","Starting\u2026":"\u6B63\u5728\u542F\u52A8\u2026","Starting update\u2026":"\u6B63\u5728\u5F00\u59CB\u66F4\u65B0\u2026","Queued\u2026":"\u5DF2\u6392\u961F\u2026","Preparing\u2026":"\u6B63\u5728\u51C6\u5907\u2026","Stashing local changes\u2026":"\u6B63\u5728\u6682\u5B58\u672C\u5730\u66F4\u6539\u2026","Fetching release\u2026":"\u6B63\u5728\u83B7\u53D6\u53D1\u884C\u7248\u2026","Checking out release\u2026":"\u6B63\u5728\u68C0\u51FA\u53D1\u884C\u7248\u2026","Installing dependencies\u2026":"\u6B63\u5728\u5B89\u88C5\u4F9D\u8D56\u2026","Building\u2026":"\u6B63\u5728\u6784\u5EFA\u2026","Restarting Codeman\u2026":"\u6B63\u5728\u91CD\u542F {name}\u2026","Try again":"\u91CD\u8BD5","Could not check for updates. Try again later.":"\u65E0\u6CD5\u68C0\u67E5\u66F4\u65B0\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002","The previous version is still running.":"\u5148\u524D\u7248\u672C\u4ECD\u5728\u8FD0\u884C\u3002","Advanced Options":"\u9AD8\u7EA7\u9009\u9879","Advanced container settings":"\u9AD8\u7EA7\u5BB9\u5668\u8BBE\u7F6E",Basics:"\u57FA\u672C\u8BBE\u7F6E",Behavior:"\u884C\u4E3A",Alerts:"\u63D0\u9192",Limits:"\u9650\u5236",Paths:"\u8DEF\u5F84",Notes:"\u5907\u6CE8",Context:"\u4E0A\u4E0B\u6587",Duration:"\u6301\u7EED\u65F6\u95F4",Iterations:"\u8FED\u4EE3\u6B21\u6570",Elapsed:"\u5DF2\u7528\u65F6\u95F4",Launch:"\u542F\u52A8","Launch Command":"\u542F\u52A8\u547D\u4EE4","Background Agents":"\u540E\u53F0\u667A\u80FD\u4F53","Background Tasks":"\u540E\u53F0\u4EFB\u52A1",Tasks:"\u4EFB\u52A1","Explore Tasks":"\u63A2\u7D22\u4EFB\u52A1","Implement Tasks":"\u5B9E\u73B0\u4EFB\u52A1","Test Tasks":"\u6D4B\u8BD5\u4EFB\u52A1","Review Tasks":"\u5BA1\u67E5\u4EFB\u52A1","Agent Type":"\u667A\u80FD\u4F53\u7C7B\u578B","Implementation Plan":"\u5B9E\u65BD\u8BA1\u5212",Plan:"\u8BA1\u5212","Plan:":"\u8BA1\u5212\uFF1A","Plan Usage Limits":"\u5957\u9910\u4F7F\u7528\u9650\u5236","Plan Wizard Agents":"\u8BA1\u5212\u5411\u5BFC\u667A\u80FD\u4F53","Fix Plan Menu":"\u4FEE\u590D\u8BA1\u5212\u83DC\u5355","View Fix Plan":"\u67E5\u770B\u4FEE\u590D\u8BA1\u5212","Regenerate Plan":"\u91CD\u65B0\u751F\u6210\u8BA1\u5212","Cancel plan generation":"\u53D6\u6D88\u751F\u6210\u8BA1\u5212","Describe your task below. Claude will generate an implementation plan with testing steps.":"\u8BF7\u5728\u4E0B\u65B9\u63CF\u8FF0\u4EFB\u52A1\uFF0CClaude \u5C06\u751F\u6210\u5305\u542B\u6D4B\u8BD5\u6B65\u9AA4\u7684\u5B9E\u65BD\u8BA1\u5212\u3002","What do you want to build?":"\u4F60\u60F3\u6784\u5EFA\u4EC0\u4E48\uFF1F","A brief description...":"\u7B80\u8981\u63CF\u8FF0\u2026",Describe:"\u63CF\u8FF0",Enhanced:"\u589E\u5F3A","Enhanced: parallel subagents + verification (slower but more thorough)":"\u589E\u5F3A\uFF1A\u5E76\u884C\u5B50\u667A\u80FD\u4F53 + \u9A8C\u8BC1\uFF08\u901F\u5EA6\u8F83\u6162\uFF0C\u4F46\u66F4\u5168\u9762\uFF09",Standard:"\u6807\u51C6","Single-pass generation with Opus 4.5":"\u4F7F\u7528 Opus 4.5 \u5355\u8F6E\u751F\u6210","Initializing deep reasoning model":"\u6B63\u5728\u521D\u59CB\u5316\u6DF1\u5EA6\u63A8\u7406\u6A21\u578B","Starting Opus 4.5...":"\u6B63\u5728\u542F\u52A8 Opus 4.5\u2026","Auto-launch when plan completes":"\u8BA1\u5212\u5B8C\u6210\u540E\u81EA\u52A8\u542F\u52A8","Auto-accept prompts":"\u81EA\u52A8\u63A5\u53D7\u63D0\u793A","Presses Enter for plan approvals and default question options":"\u5BF9\u8BA1\u5212\u5BA1\u6279\u548C\u9ED8\u8BA4\u95EE\u9898\u9009\u9879\u81EA\u52A8\u6309 Enter","Auto-accepts, auto-clears, agent completions":"\u81EA\u52A8\u63A5\u53D7\u3001\u81EA\u52A8\u6E05\u7406\u548C\u667A\u80FD\u4F53\u5B8C\u6210\u63D0\u9192","Or click Run to start":"\u6216\u70B9\u51FB\u201C\u8FD0\u884C\u201D\u5F00\u59CB","to edit your task, or":"\u4EE5\u7F16\u8F91\u4EFB\u52A1\uFF0C\u6216","to continue without a plan":"\u4EE5\u4E0D\u4F7F\u7528\u8BA1\u5212\u76F4\u63A5\u7EE7\u7EED",Respawn:"\u91CD\u751F","Respawn loop":"\u91CD\u751F\u5FAA\u73AF","Enable Respawn":"\u542F\u7528\u91CD\u751F","Stop Respawn":"\u505C\u6B62\u91CD\u751F","Auto-resume when usage limit resets":"\u4F7F\u7528\u9650\u5236\u91CD\u7F6E\u540E\u81EA\u52A8\u7EE7\u7EED","Auto-restart sessions when context fills up (usually not needed)":"\u4E0A\u4E0B\u6587\u5DF2\u6EE1\u65F6\u81EA\u52A8\u91CD\u542F\u4F1A\u8BDD\uFF08\u901A\u5E38\u4E0D\u9700\u8981\uFF09","Auto-Compact":"\u81EA\u52A8\u538B\u7F29","Auto-Clear":"\u81EA\u52A8\u6E05\u7A7A","Token Management":"Token \u7BA1\u7406","Use 1M token context window":"\u4F7F\u7528 100 \u4E07 Token \u4E0A\u4E0B\u6587\u7A97\u53E3","Use 1M token context window for new sessions":"\u65B0\u4F1A\u8BDD\u4F7F\u7528 100 \u4E07 Token \u4E0A\u4E0B\u6587\u7A97\u53E3","Full context reset at threshold (use higher than compact)":"\u8FBE\u5230\u9608\u503C\u65F6\u5B8C\u5168\u91CD\u7F6E\u4E0A\u4E0B\u6587\uFF08\u9608\u503C\u5E94\u9AD8\u4E8E\u538B\u7F29\u9608\u503C\uFF09","Idle Threshold":"\u7A7A\u95F2\u9608\u503C","Max Iterations":"\u6700\u5927\u8FED\u4EE3\u6B21\u6570","Max Iterations:":"\u6700\u5927\u8FED\u4EE3\u6B21\u6570\uFF1A","Max Todos":"\u6700\u5927\u5F85\u529E\u6570","Todo Expiration":"\u5F85\u529E\u8FC7\u671F\u65F6\u95F4","Completion Phrase":"\u5B8C\u6210\u77ED\u8BED","Completion Phrase:":"\u5B8C\u6210\u77ED\u8BED\uFF1A","Phrase Claude outputs when loop is complete (without <promise> tags)":"\u5FAA\u73AF\u5B8C\u6210\u65F6 Claude \u8F93\u51FA\u7684\u77ED\u8BED\uFF08\u4E0D\u542B <promise> \u6807\u7B7E\uFF09","Prompt to send when idle":"\u7A7A\u95F2\u65F6\u53D1\u9001\u7684\u63D0\u793A\u8BCD","Prompt to send into the session":"\u53D1\u9001\u5230\u4F1A\u8BDD\u7684\u63D0\u793A\u8BCD","Prompt Source":"\u63D0\u793A\u8BCD\u6765\u6E90","Prompt File Path":"\u63D0\u793A\u8BCD\u6587\u4EF6\u8DEF\u5F84","Prompt file path":"\u63D0\u793A\u8BCD\u6587\u4EF6\u8DEF\u5F84","Prompt Preview":"\u63D0\u793A\u8BCD\u9884\u89C8","Load Preset":"\u52A0\u8F7D\u9884\u8BBE",Presets:"\u9884\u8BBE","Apply preset":"\u5E94\u7528\u9884\u8BBE","Save Preset":"\u4FDD\u5B58\u9884\u8BBE","Save Respawn Preset":"\u4FDD\u5B58\u91CD\u751F\u9884\u8BBE","Save current config as preset":"\u5C06\u5F53\u524D\u914D\u7F6E\u4FDD\u5B58\u4E3A\u9884\u8BBE","Preset Name":"\u9884\u8BBE\u540D\u79F0","Description (optional)":"\u63CF\u8FF0\uFF08\u53EF\u9009\uFF09","When to use this preset":"\u6B64\u9884\u8BBE\u7684\u9002\u7528\u573A\u666F","Start Loop":"\u542F\u52A8\u5FAA\u73AF","Start Ralph Loop":"\u542F\u52A8 Ralph \u5FAA\u73AF","Start Ralph Loop \u2192":"\u542F\u52A8 Ralph \u5FAA\u73AF \u2192","Enable Tracker":"\u542F\u7528\u8DDF\u8E2A\u5668","Ralph / Todo":"Ralph / \u5F85\u529E","Ralph / Todo Tracker":"Ralph / \u5F85\u529E\u8DDF\u8E2A\u5668","Cycle Steps":"\u5FAA\u73AF\u6B65\u9AA4","1. Update Prompt":"1. \u66F4\u65B0\u63D0\u793A\u8BCD","2. Send /clear":"2. \u53D1\u9001 /clear","3. Send /init":"3. \u53D1\u9001 /init","4. Kickstart Prompt":"4. \u542F\u52A8\u63D0\u793A\u8BCD","Sent only when /init completes but Claude stays idle \xB7 Auto-accept presses Enter for plan approvals and default options":"\u4EC5\u5728 /init \u5B8C\u6210\u540E Claude \u4ECD\u7A7A\u95F2\u65F6\u53D1\u9001\uFF1B\u81EA\u52A8\u63A5\u53D7\u4F1A\u5BF9\u8BA1\u5212\u5BA1\u6279\u548C\u9ED8\u8BA4\u9009\u9879\u6309 Enter","One autonomous work cycle: whenever Claude goes idle, Codeman sends the update prompt, optionally runs /clear + /init, and kickstarts the next round \u2014 repeating for the chosen duration. All settings below belong to this loop; configure them, then press Enable.":"\u4E00\u4E2A\u81EA\u4E3B\u5DE5\u4F5C\u5FAA\u73AF\uFF1AClaude \u6BCF\u6B21\u7A7A\u95F2\u65F6\uFF0C{name}\u90FD\u4F1A\u53D1\u9001\u66F4\u65B0\u63D0\u793A\u8BCD\uFF0C\u53EF\u9009\u6267\u884C /clear + /init\uFF0C\u5E76\u542F\u52A8\u4E0B\u4E00\u8F6E\uFF0C\u6301\u7EED\u5230\u8BBE\u5B9A\u65F6\u957F\u3002\u4E0B\u65B9\u8BBE\u7F6E\u5747\u5C5E\u4E8E\u6B64\u5FAA\u73AF\uFF1B\u914D\u7F6E\u540E\u70B9\u51FB\u201C\u542F\u7528\u201D\u3002",'If Claude pauses on a usage limit ("limit reached \xB7 resets 3pm"), Codeman waits for the reset time and automatically continues the work. Independent of the respawn loop below.':"\u5982\u679C Claude \u56E0\u4F7F\u7528\u9650\u5236\u6682\u505C\uFF08\u201Climit reached \xB7 resets 3pm\u201D\uFF09\uFF0C{name}\u4F1A\u7B49\u5F85\u9650\u5236\u91CD\u7F6E\u5E76\u81EA\u52A8\u7EE7\u7EED\u5DE5\u4F5C\u3002\u6B64\u529F\u80FD\u72EC\u7ACB\u4E8E\u4E0B\u65B9\u7684\u91CD\u751F\u5FAA\u73AF\u3002","Search sessions, events, files\u2026":"\u641C\u7D22\u4F1A\u8BDD\u3001\u4E8B\u4EF6\u548C\u6587\u4EF6\u2026","Search across sessions":"\u8DE8\u4F1A\u8BDD\u641C\u7D22","Filter by case":"\u6309\u6848\u4F8B\u7B5B\u9009","Filter by date range":"\u6309\u65E5\u671F\u8303\u56F4\u7B5B\u9009","Filter by session status":"\u6309\u4F1A\u8BDD\u72B6\u6001\u7B5B\u9009","Filter files...":"\u7B5B\u9009\u6587\u4EF6\u2026","Any status":"\u4EFB\u610F\u72B6\u6001","Any time":"\u4EFB\u610F\u65F6\u95F4","Last hour":"\u6700\u8FD1\u4E00\u5C0F\u65F6","Last 7 Days":"\u6700\u8FD1 7 \u5929","Past 24h":"\u8FC7\u53BB 24 \u5C0F\u65F6","Past 7 days":"\u8FC7\u53BB 7 \u5929","Past 30 days":"\u8FC7\u53BB 30 \u5929","Since last visit":"\u81EA\u4E0A\u6B21\u8BBF\u95EE\u4EE5\u6765",Since:"\u5F00\u59CB\u65F6\u95F4",Until:"\u7ED3\u675F\u65F6\u95F4","Away digest range":"\u79BB\u5F00\u671F\u95F4\u6458\u8981\u8303\u56F4","Open the digest to load recent activity":"\u6253\u5F00\u6458\u8981\u4EE5\u52A0\u8F7D\u6700\u8FD1\u6D3B\u52A8","Refresh away digest":"\u5237\u65B0\u79BB\u5F00\u671F\u95F4\u6458\u8981","Refresh summary":"\u5237\u65B0\u6458\u8981","Select a session to view files":"\u9009\u62E9\u4F1A\u8BDD\u4EE5\u67E5\u770B\u6587\u4EF6","Select a session to view summary":"\u9009\u62E9\u4F1A\u8BDD\u4EE5\u67E5\u770B\u6458\u8981","Select an agent to view details":"\u9009\u62E9\u667A\u80FD\u4F53\u4EE5\u67E5\u770B\u8BE6\u60C5","Select a run to view its agents":"\u9009\u62E9\u4E00\u6B21\u8FD0\u884C\u4EE5\u67E5\u770B\u5176\u667A\u80FD\u4F53","Source type filter":"\u6765\u6E90\u7C7B\u578B\u7B5B\u9009","Copy content":"\u590D\u5236\u5185\u5BB9","Edit file":"\u7F16\u8F91\u6587\u4EF6","Unsaved changes":"\u672A\u4FDD\u5B58\u7684\u66F4\u6539",Saved:"\u5DF2\u4FDD\u5B58","Export as JSON":"\u5BFC\u51FA\u4E3A JSON","Export as Markdown":"\u5BFC\u51FA\u4E3A Markdown","Mark all read":"\u5168\u90E8\u6807\u4E3A\u5DF2\u8BFB","Clear search":"\u6E05\u9664\u641C\u7D22","Clear all tracked subagents":"\u6E05\u9664\u6240\u6709\u5DF2\u8DDF\u8E2A\u7684\u5B50\u667A\u80FD\u4F53","Kill All Sessions":"\u7EC8\u6B62\u6240\u6709\u4F1A\u8BDD","Kill all sessions and their tmux processes":"\u7EC8\u6B62\u6240\u6709\u4F1A\u8BDD\u53CA\u5176 tmux \u8FDB\u7A0B","Kill All Claude + Tmux":"\u7EC8\u6B62\u5168\u90E8 Claude + Tmux","Kill Tmux & Claude Code":"\u7EC8\u6B62 Tmux \u4E0E Claude Code","Terminate everything completely":"\u5F7B\u5E95\u7EC8\u6B62\u6240\u6709\u5185\u5BB9","Tmux Sessions":"Tmux \u4F1A\u8BDD","Tmux sessions keep running in background":"Tmux \u4F1A\u8BDD\u7EE7\u7EED\u5728\u540E\u53F0\u8FD0\u884C","Refresh tmux sessions":"\u5237\u65B0 Tmux \u4F1A\u8BDD","Restore Terminal Size":"\u6062\u590D\u7EC8\u7AEF\u5927\u5C0F","Clear Terminal":"\u6E05\u7A7A\u7EC8\u7AEF","Stop current run":"\u505C\u6B62\u5F53\u524D\u8FD0\u884C","Stop respawn":"\u505C\u6B62\u91CD\u751F","Stop (Ctrl+C)":"\u505C\u6B62\uFF08Ctrl+C\uFF09",Case:"\u6848\u4F8B","Case:":"\u6848\u4F8B\uFF1A","Case settings":"\u6848\u4F8B\u8BBE\u7F6E","Create New":"\u65B0\u5EFA","Auto (directory name)":"\u81EA\u52A8\uFF08\u76EE\u5F55\u540D\uFF09","Custom name shown in the tab (right-click tab to rename inline)":"\u6807\u7B7E\u9875\u4E2D\u663E\u793A\u7684\u81EA\u5B9A\u4E49\u540D\u79F0\uFF08\u53F3\u952E\u6807\u7B7E\u53EF\u76F4\u63A5\u91CD\u547D\u540D\uFF09","Name to identify this case in Codeman":"\u7528\u4E8E\u5728{name}\u4E2D\u6807\u8BC6\u6B64\u6848\u4F8B\u7684\u540D\u79F0","Name to identify this remote case in Codeman":"\u7528\u4E8E\u5728{name}\u4E2D\u6807\u8BC6\u6B64\u8FDC\u7A0B\u6848\u4F8B\u7684\u540D\u79F0","Absolute path on the remote host. Codeman will not create or delete it.":"\u8FDC\u7A0B\u4E3B\u673A\u4E0A\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF1B{name}\u4E0D\u4F1A\u521B\u5EFA\u6216\u5220\u9664\u8BE5\u76EE\u5F55\u3002","Absolute path to an existing project folder, e.g. /home/you/my-project":"\u73B0\u6709\u9879\u76EE\u6587\u4EF6\u5939\u7684\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982 /home/you/my-project","Letters, numbers, hyphens, underscores only. Created in ~/codeman-cases/":"\u4EC5\u5141\u8BB8\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u8FDE\u5B57\u7B26\u548C\u4E0B\u5212\u7EBF\uFF1B\u5C06\u5728 ~/codeman-cases/ \u4E2D\u521B\u5EFA\u3002","Docker exports":"Docker \u5BFC\u51FA","No exports yet. Export a docker case from its tab.":"\u6682\u65E0\u5BFC\u51FA\uFF1B\u8BF7\u4ECE Docker \u6848\u4F8B\u6807\u7B7E\u9875\u5BFC\u51FA\u3002","Runs inside an isolated container. Multiple sessions can share the same container.":"\u5728\u9694\u79BB\u5BB9\u5668\u5185\u8FD0\u884C\uFF1B\u591A\u4E2A\u4F1A\u8BDD\u53EF\u4EE5\u5171\u4EAB\u540C\u4E00\u5BB9\u5668\u3002","Runs this case in a hardened, isolated container. The base image is built automatically on first use. Docker/Podman must be installed.":"\u5728\u52A0\u56FA\u7684\u9694\u79BB\u5BB9\u5668\u4E2D\u8FD0\u884C\u6B64\u6848\u4F8B\u3002\u9996\u6B21\u4F7F\u7528\u65F6\u4F1A\u81EA\u52A8\u6784\u5EFA\u57FA\u7840\u955C\u50CF\uFF1B\u5FC5\u987B\u5B89\u88C5 Docker/Podman\u3002","Run in an isolated Docker container":"\u5728\u9694\u79BB\u7684 Docker \u5BB9\u5668\u4E2D\u8FD0\u884C","Attach to an existing container":"\u63A5\u5165\u5DF2\u5728\u8FD0\u884C\u7684\u5BB9\u5668","On: Codeman only runs docker exec into a container you already built and run \u2014 it never creates, starts, stops or removes it. The CLIs must already be installed and logged in inside it.":"\u5F00\u542F\u540E\uFF0C{name}\u53EA\u4F1A docker exec \u8FDB\u5165\u4F60\u81EA\u5DF1\u6784\u5EFA\u5E76\u8FD0\u884C\u7684\u5BB9\u5668\uFF0C\u7EDD\u4E0D\u521B\u5EFA\u3001\u542F\u52A8\u3001\u505C\u6B62\u6216\u5220\u9664\u5B83\uFF1B\u5BB9\u5668\u5185\u5FC5\u987B\u5DF2\u5B89\u88C5\u5E76\u767B\u5F55\u597D\u76F8\u5E94 CLI\u3002","Container Name":"\u5BB9\u5668\u540D\u79F0","Pick from the running containers or type a name.":"\u4ECE\u6B63\u5728\u8FD0\u884C\u7684\u5BB9\u5668\u4E2D\u9009\u62E9\uFF0C\u6216\u76F4\u63A5\u8F93\u5165\u540D\u79F0\u3002","Check container":"\u68C0\u67E5\u5BB9\u5668","Container Workdir":"\u5BB9\u5668\u5185\u5DE5\u4F5C\u76EE\u5F55","A path that already exists inside the container. Adoption mounts nothing, so this need not match the host workspace path.":"\u5BB9\u5668\u5185\u5DF2\u5B58\u5728\u7684\u8DEF\u5F84\u3002\u63A5\u5165\u4E0D\u6302\u8F7D\u4EFB\u4F55\u76EE\u5F55\uFF0C\u56E0\u6B64\u5B83\u4E0D\u5FC5\u4E0E\u4E3B\u673A\u5DE5\u4F5C\u533A\u8DEF\u5F84\u76F8\u540C\u3002","Already have a container running?":"\u5DF2\u7ECF\u6709\u6B63\u5728\u8FD0\u884C\u7684\u5BB9\u5668\uFF1F","Attach to it instead":"\u6539\u4E3A\u63A5\u5165\u8BE5\u5BB9\u5668","Codeman only runs docker exec into it and never touches its lifecycle.":"{name}\u53EA\u4F1A docker exec \u8FDB\u5165\u5B83\uFF0C\u7EDD\u4E0D\u89E6\u78B0\u5176\u751F\u547D\u5468\u671F\u3002","Absolute HOST directory, bind-mounted into the container. Codeman scaffolds CLAUDE.md + hooks into it.":"\u7ED1\u5B9A\u6302\u8F7D\u5230\u5BB9\u5668\u4E2D\u7684\u4E3B\u673A\u7EDD\u5BF9\u76EE\u5F55\uFF1B{name}\u4F1A\u5728\u5176\u4E2D\u751F\u6210 CLAUDE.md \u548C hooks\u3002","A reusable docker host profile. Reuse the same ID across cases to share settings.":"\u53EF\u590D\u7528\u7684 Docker \u4E3B\u673A\u914D\u7F6E\uFF1B\u591A\u4E2A\u6848\u4F8B\u4F7F\u7528\u540C\u4E00 ID \u53EF\u5171\u4EAB\u8BBE\u7F6E\u3002","Mount host credentials (~/.claude etc.)":"\u6302\u8F7D\u4E3B\u673A\u51ED\u636E\uFF08~/.claude \u7B49\uFF09","On: your existing login just works (creds stay on the host, never in exports). Off: sealed sandbox, log in inside the container.":"\u5F00\u542F\uFF1A\u76F4\u63A5\u4F7F\u7528\u73B0\u6709\u767B\u5F55\uFF08\u51ED\u636E\u4FDD\u7559\u5728\u4E3B\u673A\u4E14\u4E0D\u4F1A\u8FDB\u5165\u5BFC\u51FA\uFF09\uFF1B\u5173\u95ED\uFF1A\u4F7F\u7528\u5BC6\u5C01\u6C99\u7BB1\uFF0C\u9700\u8981\u5728\u5BB9\u5668\u5185\u767B\u5F55\u3002","Disk is elastic: storage grows automatically as data flows in (no fixed cap).":"\u78C1\u76D8\u4E3A\u5F39\u6027\u5BB9\u91CF\uFF1A\u4F1A\u968F\u6570\u636E\u81EA\u52A8\u589E\u957F\uFF08\u65E0\u56FA\u5B9A\u4E0A\u9650\uFF09\u3002","Needs the NVIDIA container toolkit on the host.":"\u4E3B\u673A\u9700\u8981\u5B89\u88C5 NVIDIA Container Toolkit\u3002","GPU \u2014 8 GB RAM, 4 CPU, all GPUs":"GPU \u2014 8 GB \u5185\u5B58\u30014 CPU\u3001\u5168\u90E8 GPU","Large \u2014 8 GB RAM, 4 CPU":"\u5927\u578B \u2014 8 GB \u5185\u5B58\u30014 CPU","Medium \u2014 4 GB RAM, 2 CPU (default)":"\u4E2D\u578B \u2014 4 GB \u5185\u5B58\u30012 CPU\uFF08\u9ED8\u8BA4\uFF09","Small \u2014 2 GB RAM, 1 CPU":"\u5C0F\u578B \u2014 2 GB \u5185\u5B58\u30011 CPU","bridge (internet on, default)":"\u6865\u63A5\uFF08\u53EF\u8054\u7F51\uFF0C\u9ED8\u8BA4\uFF09","bridge (internet on)":"\u6865\u63A5\uFF08\u53EF\u8054\u7F51\uFF09","none (fully isolated, no network)":"\u65E0\uFF08\u5B8C\u5168\u9694\u79BB\uFF0C\u4E0D\u8054\u7F51\uFF09","none (fully isolated)":"\u65E0\uFF08\u5B8C\u5168\u9694\u79BB\uFF09","Resume last conversation on relaunch":"\u91CD\u65B0\u542F\u52A8\u65F6\u7EE7\u7EED\u6700\u8FD1\u4E00\u6B21\u5BF9\u8BDD","Extra -o Options":"\u9644\u52A0 -o \u9009\u9879","SOCKS Proxy":"SOCKS \u4EE3\u7406","Host ID":"\u4E3B\u673A ID","Optional. Leave blank for the default port 22.":"\u53EF\u9009\uFF1B\u7559\u7A7A\u4F7F\u7528\u9ED8\u8BA4\u7AEF\u53E3 22\u3002","Optional. Path to a private key on this machine (passed to ssh -i). Never the key contents.":"\u53EF\u9009\uFF1B\u672C\u673A\u79C1\u94A5\u6587\u4EF6\u8DEF\u5F84\uFF08\u4F20\u7ED9 ssh -i\uFF09\uFF0C\u8BF7\u52FF\u586B\u5199\u5BC6\u94A5\u5185\u5BB9\u3002","Optional. [user@]host[:port] for ssh -J (jump/bastion host).":"\u53EF\u9009\uFF1Bssh -J \u4F7F\u7528\u7684 [user@]host[:port]\uFF08\u8DF3\u677F\u673A\uFF09\u3002","Optional. One KEY=VALUE per line; each becomes an ssh -o option.":"\u53EF\u9009\uFF1B\u6BCF\u884C\u4E00\u4E2A KEY=VALUE\uFF0C\u6BCF\u9879\u90FD\u4F1A\u6210\u4E3A ssh -o \u9009\u9879\u3002","Use the GPU-accelerated WebGL terminal renderer (desktop only). Turn off to force the DOM renderer if you hit GPU glitches. Codeman also auto-falls-back to the DOM renderer after repeated GPU stalls.":"\u4F7F\u7528 GPU \u52A0\u901F\u7684 WebGL \u7EC8\u7AEF\u6E32\u67D3\u5668\uFF08\u4EC5\u684C\u9762\u7AEF\uFF09\u3002\u5982\u9047 GPU \u663E\u793A\u95EE\u9898\uFF0C\u53EF\u5173\u95ED\u4EE5\u5F3A\u5236\u4F7F\u7528 DOM \u6E32\u67D3\u5668\uFF1B\u591A\u6B21 GPU \u5361\u987F\u540E{name}\u4E5F\u4F1A\u81EA\u52A8\u56DE\u9000\u3002","Show A-/A+ font size buttons in header":"\u5728\u9876\u90E8\u680F\u663E\u793A A-/A+ \u5B57\u4F53\u5927\u5C0F\u6309\u94AE","Show Claude plan usage limits (5-hour & weekly) in the header. Applies to newly created sessions.":"\u5728\u9876\u90E8\u680F\u663E\u793A Claude \u5957\u9910\u4F7F\u7528\u9650\u5236\uFF085 \u5C0F\u65F6\u548C\u6BCF\u5468\uFF09\uFF1B\u9002\u7528\u4E8E\u65B0\u5EFA\u4F1A\u8BDD\u3002","Show ultracode / Workflow runs as a master-detail tab (tasks on the left, agents with tokens + tool calls on the right)":"\u4EE5\u4E3B\u4ECE\u6807\u7B7E\u9875\u663E\u793A Ultracode / Workflow \u8FD0\u884C\uFF08\u5DE6\u4FA7\u4EFB\u52A1\uFF0C\u53F3\u4FA7\u667A\u80FD\u4F53 Token \u4E0E\u5DE5\u5177\u8C03\u7528\uFF09","Pop a floating window for each active ultracode / Workflow run, connected by a line to its session tab (additional to the Ultracode Agents panel)":"\u4E3A\u6BCF\u4E2A\u6D3B\u52A8\u7684 Ultracode / Workflow \u8FD0\u884C\u5F39\u51FA\u6D6E\u52A8\u7A97\u53E3\uFF0C\u5E76\u7528\u8FDE\u7EBF\u8FDE\u63A5\u5230\u5176\u4F1A\u8BDD\u6807\u7B7E\u9875","Shows typed characters instantly via overlay while forwarding keystrokes to the server in the background. Enables Tab completion, preserves input across tab switches, and protects against session crashes. Recommended for mobile and high-latency connections.":"\u901A\u8FC7\u8986\u76D6\u5C42\u5373\u65F6\u663E\u793A\u8F93\u5165\uFF0C\u540C\u65F6\u5728\u540E\u53F0\u628A\u6309\u952E\u8F6C\u53D1\u5230\u670D\u52A1\u5668\u3002\u652F\u6301 Tab \u8865\u5168\u3001\u5207\u6362\u6807\u7B7E\u65F6\u4FDD\u7559\u8F93\u5165\u5E76\u9632\u6B62\u4F1A\u8BDD\u5D29\u6E83\u4E22\u5B57\uFF1B\u63A8\u8350\u79FB\u52A8\u7AEF\u548C\u9AD8\u5EF6\u8FDF\u8FDE\u63A5\u4F7F\u7528\u3002","Show a dedicated input field below the terminal for CJK (Chinese/Japanese/Korean) IME composition. Recommended for mobile devices with Chinese input methods where xterm's native input handling may drop characters.":"\u5728\u7EC8\u7AEF\u4E0B\u65B9\u663E\u793A\u4E2D\u65E5\u97E9\u8F93\u5165\u6CD5\u4E13\u7528\u6587\u672C\u6846\u3002\u63A8\u8350\u5728\u53EF\u80FD\u56E0 xterm \u539F\u751F\u8F93\u5165\u800C\u4E22\u5B57\u7684\u79FB\u52A8\u7AEF\u4E2D\u6587\u8F93\u5165\u6CD5\u4E2D\u4F7F\u7528\u3002","Show additional buttons (Tab, Shift+Tab, Ctrl+O, Esc, Alt+Enter, left/right arrows) in the mobile keyboard accessory bar.":"\u5728\u79FB\u52A8\u7AEF\u952E\u76D8\u5DE5\u5177\u680F\u663E\u793A\u9644\u52A0\u6309\u952E\uFF08Tab\u3001Shift+Tab\u3001Ctrl+O\u3001Esc\u3001Alt+Enter\u3001\u5DE6\u53F3\u65B9\u5411\u952E\uFF09\u3002","Scroll local history (when mouse passthrough is active)":"\u6EDA\u52A8\u672C\u5730\u5386\u53F2\uFF08\u9F20\u6807\u76F4\u901A\u542F\u7528\u65F6\uFF09","Plain wheel/trackpad pages the terminal scrollback":"\u4F7F\u7528\u666E\u901A\u6EDA\u8F6E/\u89E6\u63A7\u677F\u7FFB\u9605\u7EC8\u7AEF\u5386\u53F2","Camera hand-tracking overlay (applied on reload)":"\u6444\u50CF\u5934\u624B\u52BF\u8DDF\u8E2A\u8986\u76D6\u5C42\uFF08\u91CD\u65B0\u52A0\u8F7D\u540E\u751F\u6548\uFF09","Enable the camera hand-tracking gesture overlay (applied on reload). The instance must run with CODEMAN_GESTURE=1.":"\u542F\u7528\u6444\u50CF\u5934\u624B\u52BF\u8DDF\u8E2A\u8986\u76D6\u5C42\uFF08\u91CD\u65B0\u52A0\u8F7D\u540E\u751F\u6548\uFF09\uFF1B\u5B9E\u4F8B\u5FC5\u987B\u4EE5 CODEMAN_GESTURE=1 \u8FD0\u884C\u3002","How Claude CLI is started in screen sessions. Auto Mode runs without routine prompts behind a background safety classifier (needs Claude Code 2.1.207+ and Opus 4.6+/Sonnet 4.6+/Fable 5)":"\u8BBE\u7F6E Claude CLI \u5728\u4F1A\u8BDD\u4E2D\u7684\u542F\u52A8\u65B9\u5F0F\u3002\u81EA\u52A8\u6A21\u5F0F\u7531\u540E\u53F0\u5B89\u5168\u5206\u7C7B\u5668\u4FDD\u62A4\uFF0C\u65E0\u9700\u5E38\u89C4\u786E\u8BA4\uFF08\u9700\u8981 Claude Code 2.1.207+ \u548C Opus 4.6+/Sonnet 4.6+/Fable 5\uFF09\u3002","Auto-enable for new sessions (otherwise auto-enables on Ralph pattern detection)":"\u4E3A\u65B0\u4F1A\u8BDD\u81EA\u52A8\u542F\u7528\uFF08\u5426\u5219\u68C0\u6D4B\u5230 Ralph \u6A21\u5F0F\u65F6\u81EA\u52A8\u542F\u7528\uFF09","Enable experimental Agent Teams for all new Claude sessions (disabled by default)":"\u4E3A\u6240\u6709\u65B0 Claude \u4F1A\u8BDD\u542F\u7528\u5B9E\u9A8C\u6027\u667A\u80FD\u4F53\u56E2\u961F\uFF08\u9ED8\u8BA4\u5173\u95ED\uFF09","Automatically re-establish remote (SSH) sessions when the connection drops, reattaching to the durable remote tmux session (on by default; bounded backoff)":"\u8FDE\u63A5\u65AD\u5F00\u65F6\u81EA\u52A8\u91CD\u5EFA\u8FDC\u7A0B SSH \u4F1A\u8BDD\uFF0C\u5E76\u91CD\u65B0\u9644\u52A0\u5230\u6301\u4E45\u5316\u8FDC\u7A0B tmux \u4F1A\u8BDD\uFF08\u9ED8\u8BA4\u5F00\u542F\uFF0C\u6709\u9650\u9000\u907F\uFF09","Default effort for new Claude sessions \u2014 soft default, switchable anytime in-session via /effort (e.g. /effort ultracode)":"\u65B0 Claude \u4F1A\u8BDD\u7684\u9ED8\u8BA4\u601D\u8003\u5F3A\u5EA6\uFF1B\u8FD9\u662F\u8F6F\u9ED8\u8BA4\u503C\uFF0C\u53EF\u968F\u65F6\u5728\u4F1A\u8BDD\u4E2D\u901A\u8FC7 /effort \u5207\u6362\u3002","Lower priority of Claude sessions (reduces system impact, only affects new sessions)":"\u964D\u4F4E Claude \u4F1A\u8BDD\u7684\u8FDB\u7A0B\u4F18\u5148\u7EA7\uFF08\u51CF\u5C11\u7CFB\u7EDF\u5F71\u54CD\uFF0C\u4EC5\u5F71\u54CD\u65B0\u4F1A\u8BDD\uFF09","Process priority (-20 to 19, higher = lower priority, default: 10)":"\u8FDB\u7A0B\u4F18\u5148\u7EA7\uFF08-20 \u5230 19\uFF1B\u6570\u503C\u8D8A\u5927\u4F18\u5148\u7EA7\u8D8A\u4F4E\uFF1B\u9ED8\u8BA4 10\uFF09","Start new Codex sessions with --dangerously-bypass-approvals-and-sandbox":"\u4F7F\u7528 --dangerously-bypass-approvals-and-sandbox \u542F\u52A8\u65B0\u7684 Codex \u4F1A\u8BDD","Model used for execution tasks. Optimizer suggestions are advisory only.":"\u6267\u884C\u4EFB\u52A1\u4F7F\u7528\u7684\u6A21\u578B\uFF1B\u4F18\u5316\u5668\u5EFA\u8BAE\u4EC5\u4F9B\u53C2\u8003\u3002","Show what the optimizer recommends (doesn't override your choice)":"\u663E\u793A\u4F18\u5316\u5668\u5EFA\u8BAE\uFF08\u4E0D\u4F1A\u8986\u76D6\u4F60\u7684\u9009\u62E9\uFF09",'Optionally set specific models for each task type. Leave as "Use Default" to use your default model.':"\u53EF\u4E3A\u6BCF\u79CD\u4EFB\u52A1\u7C7B\u578B\u6307\u5B9A\u6A21\u578B\uFF1B\u4FDD\u7559\u201C\u4F7F\u7528\u9ED8\u8BA4\u503C\u201D\u5373\u53EF\u4F7F\u7528\u9ED8\u8BA4\u6A21\u578B\u3002","Request browser notification permission":"\u8BF7\u6C42\u6D4F\u89C8\u5668\u901A\u77E5\u6743\u9650","Show OS-level notifications when tab is hidden":"\u6807\u7B7E\u9875\u9690\u85CF\u65F6\u663E\u793A\u7CFB\u7EDF\u7EA7\u901A\u77E5","OS-level push notifications \u2014 works even when tab is closed":"\u7CFB\u7EDF\u7EA7\u63A8\u9001\u901A\u77E5\uFF0C\u5373\u4F7F\u6807\u7B7E\u9875\u5173\u95ED\u4E5F\u53EF\u63A5\u6536","Play a short beep for critical events":"\u4E25\u91CD\u4E8B\u4EF6\u53D1\u751F\u65F6\u64AD\u653E\u77ED\u63D0\u793A\u97F3","Completions, budget warnings, stuck sessions":"\u5B8C\u6210\u63D0\u9192\u3001\u9884\u7B97\u8B66\u544A\u548C\u4F1A\u8BDD\u5361\u4F4F\u63D0\u9192","Errors, crashes, agent failures":"\u9519\u8BEF\u3001\u5D29\u6E83\u548C\u667A\u80FD\u4F53\u5931\u8D25","Notify when a session is idle longer than this":"\u4F1A\u8BDD\u7A7A\u95F2\u8D85\u8FC7\u6B64\u65F6\u957F\u65F6\u901A\u77E5","Stored locally only, never sent to server. Get a key at":"\u4EC5\u5B58\u50A8\u5728\u672C\u673A\uFF0C\u7EDD\u4E0D\u4F1A\u53D1\u9001\u5230\u670D\u52A1\u5668\u3002\u53EF\u5728\u6B64\u83B7\u53D6\u5BC6\u94A5\uFF1A","Comma-separated terms to boost recognition accuracy":"\u4EE5\u9017\u53F7\u5206\u9694\u53EF\u63D0\u9AD8\u8BC6\u522B\u51C6\u786E\u7387\u7684\u672F\u8BED","Start voice input":"\u5F00\u59CB\u8BED\u97F3\u8F93\u5165","Voice input":"\u8BED\u97F3\u8F93\u5165","Voice input (Ctrl+Shift+V)":"\u8BED\u97F3\u8F93\u5165\uFF08Ctrl+Shift+V\uFF09","Insert Newline":"\u63D2\u5165\u6362\u884C","Close Panels":"\u5173\u95ED\u9762\u677F","Previous / Next Session":"\u4E0A\u4E00\u4E2A / \u4E0B\u4E00\u4E2A\u4F1A\u8BDD","Next Session":"\u4E0B\u4E00\u4E2A\u4F1A\u8BDD","Switch to Tab N":"\u5207\u6362\u5230\u7B2C N \u4E2A\u6807\u7B7E\u9875","Move Active Tab Left":"\u5411\u5DE6\u79FB\u52A8\u5F53\u524D\u6807\u7B7E\u9875","Move Active Tab Right":"\u5411\u53F3\u79FB\u52A8\u5F53\u524D\u6807\u7B7E\u9875","Focus First Tab":"\u805A\u7126\u7B2C\u4E00\u4E2A\u6807\u7B7E\u9875","Focus Last Tab":"\u805A\u7126\u6700\u540E\u4E00\u4E2A\u6807\u7B7E\u9875","Focus Next Tab":"\u805A\u7126\u4E0B\u4E00\u4E2A\u6807\u7B7E\u9875","Focus Previous Tab":"\u805A\u7126\u4E0A\u4E00\u4E2A\u6807\u7B7E\u9875","Activate Focused Tab":"\u6FC0\u6D3B\u805A\u7126\u7684\u6807\u7B7E\u9875","Remove Tab":"\u79FB\u9664\u6807\u7B7E\u9875","Remove All Tabs":"\u79FB\u9664\u6240\u6709\u6807\u7B7E\u9875","Use arrows to reorder. Changes are saved automatically.":"\u4F7F\u7528\u65B9\u5411\u952E\u91CD\u65B0\u6392\u5E8F\uFF1B\u66F4\u6539\u4F1A\u81EA\u52A8\u4FDD\u5B58\u3002"}),w=new Map(Object.entries(m).map(([e,t])=>[e.toLocaleLowerCase("en"),t])),b=new WeakMap,S=new WeakMap;let r=f(a.__codemanLanguage),i=c,h=null,p=!1;function f(e){return x.has(e)?e:"en"}function k(e){if(typeof e!="string")return c;const t=e.normalize("NFC").replace(/[\u0000-\u001f\u007f]/g,"").trim();return t?Array.from(t).slice(0,40).join(""):c}function v(e,t){return e.replace(/\{([a-zA-Z][\w]*)\}/g,(s,o)=>String(t[o]??""))}function D(e){const t=[[/^(\d+) tokens?$/,(o,n)=>`${n} \u4E2A Token`],[/^(\d+) sessions?$/,(o,n)=>`${n} \u4E2A\u4F1A\u8BDD`],[/^(\d+) tasks?$/,(o,n)=>`${n} \u4E2A\u4EFB\u52A1`],[/^(\d+) running$/,(o,n)=>`${n} \u4E2A\u8FD0\u884C\u4E2D`],[/^(\d+) active$/,(o,n)=>`${n} \u4E2A\u6D3B\u52A8`],[/^Show (\d+) more$/,(o,n)=>`\u518D\u663E\u793A ${n} \u9879`],[/^Show (\d+) more \((\d+) remaining\)$/,(o,n,l)=>`\u518D\u663E\u793A ${n} \u9879\uFF08\u5269\u4F59 ${l} \u9879\uFF09`],[/^Lifetime: (\d+) sessions created$/,(o,n)=>`\u7D2F\u8BA1\u5DF2\u521B\u5EFA ${n} \u4E2A\u4F1A\u8BDD`],[/^Tunnel active: (.+)$/,(o,n)=>`\u96A7\u9053\u5DF2\u542F\u7528\uFF1A${n}`],[/^Tunnel error: (.+)$/,(o,n)=>`\u96A7\u9053\u9519\u8BEF\uFF1A${n}`],[/^Update to v(.+)$/,(o,n)=>`\u66F4\u65B0\u5230 v${n}`],[/^You're up to date \(v(.+)\)\.$/,(o,n)=>`\u5DF2\u662F\u6700\u65B0\u7248\u672C\uFF08v${n}\uFF09\u3002`],[/^Update available: v(.+)$/,(o,n)=>`\u6709\u53EF\u7528\u66F4\u65B0\uFF1Av${n}`],[/^Selected: (.+)$/,(o,n)=>`\u5DF2\u9009\u62E9\uFF1A${n}`],[/^Failed to (.+)$/,(o,n)=>`\u64CD\u4F5C\u5931\u8D25\uFF1A${n}`]];for(const[o,n]of t){const l=e.match(o);if(l)return n(...l)}const s=e.match(/^(Open|Close|Show|Hide|Enable|Disable|Start|Stop|Refresh|Save|Cancel|Clear|Select|View|Export|Import|Remove|Kill|Toggle|Increase|Decrease) (.+)$/i);if(s){const o={open:"\u6253\u5F00",close:"\u5173\u95ED",show:"\u663E\u793A",hide:"\u9690\u85CF",enable:"\u542F\u7528",disable:"\u7981\u7528",start:"\u542F\u52A8",stop:"\u505C\u6B62",refresh:"\u5237\u65B0",save:"\u4FDD\u5B58",cancel:"\u53D6\u6D88",clear:"\u6E05\u9664",select:"\u9009\u62E9",view:"\u67E5\u770B",export:"\u5BFC\u51FA",import:"\u5BFC\u5165",remove:"\u79FB\u9664",kill:"\u7EC8\u6B62",toggle:"\u5207\u6362",increase:"\u589E\u5927",decrease:"\u51CF\u5C0F"}[s[1].toLowerCase()],n=m[s[2]]||w.get(s[2].toLocaleLowerCase("en"));if(o&&n)return`${o}${n}`}return null}function g(e){return!e||i===c?e:e.replace(/Codeman/g,i).replace(/codeman(?=:)/g,i)}function d(e,t={}){if(typeof e!="string"||!e)return e;const s={name:i,...t};if(r==="zh-CN"){const o=m[e]||w.get(e.toLocaleLowerCase("en"))||D(e);if(o)return g(v(o,s))}return g(v(e,s))}function T(e){const t=e.nodeType===Node.ELEMENT_NODE?e:e.parentElement;return!t||!!t.closest(O)}function U(e){const t=e.nodeType===Node.ELEMENT_NODE?e:e.parentElement;return T(e)||!!t?.closest(L)}function M(e,t){const s=e.match(/^\s*/)?.[0]||"",o=e.match(/\s*$/)?.[0]||"";return s+t+o}function A(e){let t=b.get(e);if(U(e)||!t&&!/[A-Za-z]/.test(e.nodeValue||""))return;(!t||e.nodeValue!==t.applied)&&(t={source:e.nodeValue,applied:e.nodeValue});const s=t.source.trim();if(!s)return;const o=M(t.source,d(s));t.applied=o,b.set(e,t),e.nodeValue!==o&&(e.nodeValue=o)}function y(e){if(T(e)||e.matches(".history-item[title]"))return;let t=S.get(e);t||(t=new Map);for(const s of C){if(!e.hasAttribute(s))continue;const o=e.getAttribute(s)||"";let n=t.get(s);(!n||o!==n.applied)&&(n={source:o,applied:o});const l=d(n.source);n.applied=l,t.set(s,n),o!==l&&e.setAttribute(s,l)}S.set(e,t)}function u(e){if(!(!e||p)){p=!0;try{if(e.nodeType===Node.TEXT_NODE){A(e);return}if(e.nodeType!==Node.ELEMENT_NODE&&e.nodeType!==Node.DOCUMENT_NODE)return;e.nodeType===Node.ELEMENT_NODE&&y(e);const t=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT);for(let s=t.nextNode();s;s=t.nextNode())s.nodeType===Node.TEXT_NODE?A(s):y(s)}finally{p=!1}}}function E(){const e=document.title||"",t=document.documentElement.dataset.i18nTitleSource||e;document.documentElement.dataset.i18nTitleSource=t,document.title=g(t)}function I(e={}){const t=i;if(r=f(e.language??r),i=k(e.displayName??i),a.__codemanLanguage=r,a.__codemanDisplayName=i,document.documentElement.lang=r,document.documentElement.dataset.language=r,t!==i){const s=document.documentElement.dataset.i18nTitleSource||document.title||"";t!==c&&s.includes(t)&&(document.documentElement.dataset.i18nTitleSource=s.replaceAll(t,i))}return u(document.body),E(),{language:r,displayName:i}}function P(){u(document.body),E(),!h&&(h=new MutationObserver(e=>{if(!p)for(const t of e){t.type==="characterData"&&u(t.target),t.type==="attributes"&&y(t.target);for(const s of t.addedNodes)u(s)}}),h.observe(document.body,{subtree:!0,childList:!0,characterData:!0,attributes:!0,attributeFilter:C}))}const _=Object.freeze({t:d,configure:I,start:P,translateNode:u,normalizeDisplayName:k,normalizeLanguage:f,get language(){return r},get displayName(){return i}});a.CodemanI18n=_,a.codemanT=d;const N=typeof a.confirm=="function"?a.confirm.bind(a):null,R=typeof a.alert=="function"?a.alert.bind(a):null;N&&(a.confirm=e=>N(d(String(e)))),R&&(a.alert=e=>R(d(String(e)))),document.addEventListener("DOMContentLoaded",P,{once:!0})})(window);
Binary file
Binary file
@@ -1,77 +0,0 @@
1
- "use strict";Object.assign(CodemanApp.prototype,{buildEnvOverrides(e,t){const s={};return(e?.agentTeams||t?.agentTeamsEnabled)&&(s.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS="1"),s},getEffortSetting(e){const t=e?.thinkingEffort;return["low","medium","high","xhigh","max","ultracode"].includes(t)?t:void 0},formatCasePickerLabel(e){return e?.location==="remote"&&e.remote?.hostId?`${e.name} @ ${e.remote.hostId}`:e?.location==="docker"?`${e.name} (${this.dockerCaseTag(e.docker?.hostId)})`:e?.name||""},dockerCaseTag(e){return!e||e==="default"||e==="local"||/^q-/.test(e)?"docker":e},buildCasePickerOptions(e=[]){const t=[],s=new Set;for(const n of e)!n?.name||s.has(n.name)||(s.add(n.name),t.push(n));return s.has("testcase")||t.push({name:"testcase"}),t.map(n=>{const a=this.formatCasePickerLabel(n),i=[n.name,a,n.path,n.location,n.remote?.hostId,n.remote?.label,n.remote?.path,n.docker?.container,n.docker?.image,n.docker?.path].filter(Boolean).join(" ").toLowerCase();return{name:n.name,label:a,case:n,searchText:i}}).sort((n,a)=>n.label.localeCompare(a.label,void 0,{sensitivity:"base",numeric:!0}))},filterCasePickerOptions(e,t){const s=String(t||"").trim().toLowerCase().split(/\s+/).filter(Boolean);return s.length===0?e:e.filter(n=>s.every(a=>n.searchText.includes(a)))},getCasePickerOptions(){return this.buildCasePickerOptions(this.cases||[])},updateCasePickerInput(e){const t=document.getElementById("quickStartCaseSearch");if(!t)return;const s=this.getCasePickerOptions().find(n=>n.name===e);t.value=s?.label||e||"testcase",t.title=s?.label||t.value},renderQuickStartCaseSelectOptions(e,t){e&&(e.innerHTML=t.map(s=>`<option value="${escapeHtml(s.name)}">${escapeHtml(s.label)}</option>`).join(""))},openCasePicker(e=""){const t=document.getElementById("quickStartCaseSearch"),s=document.getElementById("quickStartCaseList");!t||!s||(this._casePickerOpen=!0,this._casePickerFilter=e,this._casePickerActiveIndex=0,t.setAttribute("aria-expanded","true"),this.renderCasePickerList())},closeCasePicker(){const e=document.getElementById("quickStartCaseSearch"),t=document.getElementById("quickStartCaseList");this._casePickerOpen=!1,this._casePickerFilter="",e?.setAttribute("aria-expanded","false"),e?.removeAttribute("aria-activedescendant"),t?.classList.add("hidden")},renderCasePickerList(){const e=document.getElementById("quickStartCaseSearch"),t=document.getElementById("quickStartCaseList"),s=document.getElementById("quickStartCase");if(!e||!t||!s)return;const n=this.filterCasePickerOptions(this.getCasePickerOptions(),this._casePickerFilter||""),a=s.value||"testcase",i=Math.max(0,n.length-1);if(this._casePickerActiveIndex=Math.min(Math.max(this._casePickerActiveIndex||0,0),i),n.length===0){t.innerHTML='<div class="case-combobox-empty">No cases match</div>',t.classList.remove("hidden"),e.removeAttribute("aria-activedescendant");return}t.innerHTML=n.map((o,r)=>{const c=r===this._casePickerActiveIndex,d=o.name===a;return`
2
- <button
3
- type="button"
4
- id="${`quickStartCaseOption-${r}`}"
5
- class="case-combobox-option ${c?"active":""} ${d?"selected":""}"
6
- role="option"
7
- aria-selected="${d?"true":"false"}"
8
- data-case="${escapeHtml(o.name)}"
9
- title="${escapeHtml(o.label)}">
10
- <span class="case-combobox-check">${d?"\u2713":""}</span>
11
- <span class="case-combobox-option-label">${escapeHtml(o.label)}</span>
12
- </button>
13
- `}).join(""),t.classList.remove("hidden"),e.setAttribute("aria-activedescendant",`quickStartCaseOption-${this._casePickerActiveIndex}`)},selectQuickStartCase(e,{save:t=!0}={}){const s=document.getElementById("quickStartCase");if(!s)return;s.value=e||"testcase",this.updateCasePickerInput(s.value),this.closeCasePicker(),this.updateDirDisplayForCase(s.value),this.updateMobileCaseLabel(s.value);const n=(this.cases||[]).find(a=>a.name===s.value);n?.location==="docker"&&this._probeDockerCaseModes(n,null),t&&this.saveLastUsedCase(s.value)},setupQuickStartCasePicker(){const e=document.getElementById("quickStartCase"),t=document.getElementById("quickStartCaseSearch"),s=document.getElementById("quickStartCaseList"),n=document.getElementById("quickStartCasePicker");!e||!t||!s||!n||t.dataset.listenerAdded||(t.addEventListener("focus",()=>{t.select?.(),this.openCasePicker("")}),t.addEventListener("click",()=>{t.select?.(),this.openCasePicker("")}),t.addEventListener("input",()=>{this.openCasePicker(t.value)}),t.addEventListener("keydown",a=>{const i=this.filterCasePickerOptions(this.getCasePickerOptions(),this._casePickerFilter||t.value);if(a.key==="ArrowDown")a.preventDefault(),this._casePickerActiveIndex=Math.min((this._casePickerActiveIndex||0)+1,Math.max(0,i.length-1)),this._casePickerOpen?this.renderCasePickerList():this.openCasePicker(t.value);else if(a.key==="ArrowUp")a.preventDefault(),this._casePickerActiveIndex=Math.max((this._casePickerActiveIndex||0)-1,0),this._casePickerOpen?this.renderCasePickerList():this.openCasePicker(t.value);else if(a.key==="Enter"){const o=i[this._casePickerActiveIndex||0];o&&(a.preventDefault(),this.selectQuickStartCase(o.name),this.run?.())}else a.key==="Escape"?(a.preventDefault(),this.updateCasePickerInput(e.value),this.closeCasePicker()):a.key==="Tab"&&(this.updateCasePickerInput(e.value),this.closeCasePicker())}),s.addEventListener("mousedown",a=>a.preventDefault()),s.addEventListener("click",a=>{const i=a.target.closest?.(".case-combobox-option");i?.dataset?.case&&this.selectQuickStartCase(i.dataset.case)}),document.addEventListener&&!this._casePickerDocumentListenerAdded&&(document.addEventListener("pointerdown",a=>{n.contains(a.target)||(this.updateCasePickerInput(e.value),this.closeCasePicker())}),this._casePickerDocumentListenerAdded=!0),t.dataset.listenerAdded="true")},async loadQuickStartCases(e=null,t=null){try{let s=null;try{const r=t?await t:await fetch("/api/settings").then(c=>c.ok?c.json():null).then(c=>c?.data??null);r&&(s=r.lastUsedCase||null)}catch{}const a=(await(await fetch("/api/cases")).json()).data;this.cases=a,console.log("[loadQuickStartCases] Loaded cases:",a.map(r=>r.name),"lastUsedCase:",s);const i=document.getElementById("quickStartCase"),o=this.getCasePickerOptions();if(this.renderQuickStartCaseSelectOptions(i,o),console.log("[loadQuickStartCases] Set options:",i.innerHTML.substring(0,200)),e)i.value=e,this.updateDirDisplayForCase(e),this.updateMobileCaseLabel(e);else if(s&&a.some(r=>r.name===s))i.value=s,this.updateDirDisplayForCase(s),this.updateMobileCaseLabel(s);else if(a.length>0){const r=a.find(c=>c.name==="testcase")||a[0];i.value=r.name,this.updateDirDisplayForCase(r.name),this.updateMobileCaseLabel(r.name)}else i.value="testcase",document.getElementById("dirDisplay").textContent="~/codeman-cases/testcase",this.updateMobileCaseLabel("testcase");this.updateCasePickerInput(i.value),this.renderCasePickerList(),this.closeCasePicker(),i.dataset.listenerAdded||(i.addEventListener("change",()=>{this.updateDirDisplayForCase(i.value),this.saveLastUsedCase(i.value),this.updateMobileCaseLabel(i.value),this.updateCasePickerInput(i.value)}),i.dataset.listenerAdded="true"),this.setupQuickStartCasePicker(),this._refreshMobileOverviewIfVisible?.()}catch(s){console.error("Failed to load cases:",s)}},async updateDirDisplayForCase(e){try{const s=(await(await fetch(`/api/cases/${e}`)).json()).data;s.path&&(document.getElementById("dirDisplay").textContent=s.path,document.getElementById("dirInput").value=s.path)}catch{document.getElementById("dirDisplay").textContent=e}},async saveLastUsedCase(e){try{await fetch("/api/settings",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({lastUsedCase:e})})}catch(t){console.error("Failed to save last used case:",t)}},async quickStart(){return this.run()},async _ensureCreatedSessionVisible(e,t){if(!e)return;let s=t;if(!s&&!this.sessions?.has(e)){const a=await(await fetch(`/api/sessions/${encodeURIComponent(e)}`)).json();if(!a.success)throw new Error(a.error||"Failed to load the new session");s=a.data?.session||a.data}s?.id&&this._onSessionCreated(s),this._renderSessionTabsImmediate?.()},async run(){if(this._runInFlight)return;const e=Date.now(),t=Number.isFinite(this._runMinLockMs)?this._runMinLockMs:500,s=document.getElementById("runBtn");this._runInFlight=!0,s&&(s.disabled=!0,s.setAttribute("aria-busy","true"));try{const n=this._runMode||"claude";return n==="opencode"?await this.runOpenCode():n==="codex"?await this.runCodex():n==="gemini"?await this.runGemini():n==="antigravity"?await this.runAntigravity():n==="omp"?await this.runOmp():n==="pi"?await this.runPi():n==="grok"?await this.runGrok():n==="deepseek"?await this.runDeepSeek():n==="shell"?await this.runShell():await this.runClaude()}finally{const n=t-(Date.now()-e);n>0&&await new Promise(a=>setTimeout(a,n)),this._runInFlight=!1,s&&(s.disabled=!1,s.removeAttribute("aria-busy"))}},setRunMode(e){this._runMode=e;try{localStorage.setItem("codeman_runMode",e)}catch{}this._applyRunMode(),this._apiPut("/api/settings",{runMode:e}).catch(()=>{}),document.getElementById("runModeMenu")?.classList.remove("active")},toggleRunModeMenu(e){e?.stopPropagation();const t=document.getElementById("runModeMenu");if(t&&(t.classList.toggle("active"),t.querySelectorAll(".run-mode-option").forEach(s=>{s.classList.toggle("selected",s.dataset.mode===this.runMode)}),t.classList.contains("active"))){this._loadRunModeHistory(),this._refreshRunModeAvailability(t);const s=n=>{t.contains(n.target)||(t.classList.remove("active"),document.removeEventListener("click",s))};setTimeout(()=>document.addEventListener("click",s),0)}},_refreshRunModeAvailability(e){const t=document.getElementById("quickStartCase")?.value,s=t?(this.cases||[]).find(d=>d.name===t):null,n=s?.location==="docker",a=n&&(this._dockerCaseModes?.[t]||s.docker?.availableModes)||null;n&&!this._dockerCaseModes?.[t]&&this._probeDockerCaseModes(s,e);const i=n?this._dockerCaseProbeError?.[t]:null;for(const d of["claude","opencode","codex","gemini","antigravity","pi","grok","deepseek","omp"]){const l=e.querySelector(`.run-mode-option[data-mode="${d}"]`);if(!l)continue;let m;n?m=i?!1:a?a.includes(d):!0:m=this.isCliAvailable(d),l.style.display=m?"flex":"none"}this._renderRunModeNotice(e,i);const o=window.__codemanCliAvailable||{},r=e.querySelector("#runModeDeepSeekInstall");r&&(r.style.display=!o.deepseek&&o.deepseekBinary?"flex":"none");const c=e.querySelector("#runModeDeepSeekWeb");c&&(c.style.display=o.deepseekBinary?"flex":"none")},async runDeepSeekWeb(){document.getElementById("runModeMenu")?.classList.remove("active");const e=this._beginSessionLaunchStatus("Starting the DeepSeek web UI...");try{const s=await(await fetch("/api/deepseek/web",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({authority:location.host})})).json();if(!s.success)throw new Error(s.error||"Failed to start the DeepSeek web UI");const n=s.data.url;let a=[...this.webviews?.values()||[]].find(i=>i.managed==="deepseek-web");if(a){const o=await(await fetch(`/api/webviews/${a.id}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({url:n,trusted:!0})})).json();if(!o.success)throw new Error(o.error||"Failed to update the web tab");a=o.data.webview||o.data}else{const o=await(await fetch("/api/webviews",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:"DeepSeek Harness",url:n,icon:"\u{1F433}",managed:"deepseek-web",trusted:!0})})).json();if(!o.success)throw new Error(o.error||"Failed to save the web tab");a=o.data.webview||o.data}await this.refreshWebviews?.(),this._appendSessionLaunchStatus(e,`Serving on ${n} - opening it as a tab.`),a?.id&&await this.openWebview(a.id)}catch(t){this._reportSessionLaunchError(e,t.message)}},async installDeepSeekProfile(){const t=this._beginSessionLaunchStatus("Installing a DeepSeek terminal profile (this can take a minute)...");try{const n=await(await fetch("/api/deepseek/install-profile",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({})})).json();if(!n.success)throw new Error(n.error||"Failed to install the profile");window.__codemanCliAvailable={...window.__codemanCliAvailable||{},deepseek:!!n.data.runnable},this._appendSessionLaunchStatus(t,`Installed ${n.data.package} into profile "${n.data.profile}".`),this.showToast?.(`DeepSeek profile "${n.data.profile}" installed`,"success");const a=document.getElementById("runModeMenu");a&&this._refreshRunModeAvailability(a)}catch(s){this._reportSessionLaunchError(t,s.message)}},_renderRunModeNotice(e,t){if(!e)return;let s=e.querySelector(".run-mode-notice");if(!t){s?.remove();return}s||(s=document.createElement("div"),s.className="run-mode-notice",e.prepend(s)),s.textContent=t},async _probeDockerCaseModes(e,t){const s=e?.name,n=e?.docker?.container,a=e?.docker?.hostId;if(!(!s||!n||!a)&&(this._dockerCaseModes=this._dockerCaseModes||{},!this._dockerModeProbeInFlight?.[s])){this._dockerModeProbeInFlight=this._dockerModeProbeInFlight||{},this._dockerModeProbeInFlight[s]=!0;try{const i=await this._apiJson("/api/docker-cases/adopt-preflight",{method:"POST",body:{hostId:a,container:n}});i?.ok&&Array.isArray(i.availableModes)?(this._dockerCaseModes[s]=i.availableModes,delete this._dockerCaseProbeError?.[s]):(e?.docker?.owned===!1&&(this._dockerCaseProbeError=this._dockerCaseProbeError||{},this._dockerCaseProbeError[s]=i?.error||`Could not read container "${n}".`),delete this._dockerCaseModes[s]),t?.classList.contains("active")&&this._refreshRunModeAvailability(t)}finally{delete this._dockerModeProbeInFlight[s]}}},async _loadRunModeHistory(){const e=document.getElementById("runModeHistory");if(e){e.innerHTML='<div class="run-mode-hist-empty">Loading...</div>';try{const t=await this._fetchHistorySessions(10);if(t.length===0){e.innerHTML='<div class="run-mode-hist-empty">No history</div>';return}e.replaceChildren();for(const s of t){const n=new Date(s.lastModified),a=n.toLocaleDateString("en",{month:"short",day:"numeric"})+" "+n.toLocaleTimeString("en",{hour:"2-digit",minute:"2-digit",hour12:!1}),i=this._shortenHomePath(s.workingDir),o=i.lastIndexOf("/"),r=o===-1?i:i.slice(o+1),c=(o===-1?"":i.slice(0,o)).replace(/\/\.claude\/worktrees$/,""),d=document.createElement("button");d.className="run-mode-option run-mode-hist-row",d.title=s.workingDir,d.dataset.sessionId=s.sessionId,d.dataset.workingDir=s.workingDir;const l=document.createElement("span");l.className="hist-name",l.textContent=r;const m=[l],h=this._worktreeLabel?this._worktreeLabel(s):"";if(h){const u=document.createElement("span");u.className="hist-wt",u.textContent=h,m.push(u)}if(c){const u=document.createElement("span");u.className="hist-dir",u.textContent=c,m.push(u)}const C=document.createElement("span");C.className="hist-meta",C.textContent=a,m.push(C),d.append(...m),d.addEventListener("click",u=>{u.stopPropagation(),this.resumeHistorySession(s.sessionId,s.workingDir,s.name,s.mode,s.resumeId)}),e.appendChild(d)}}catch{e.innerHTML='<div class="run-mode-hist-empty">Failed to load</div>'}}},_applyRunMode(){const e=this.runMode,t=document.getElementById("runBtn"),s=t?.nextElementSibling,n=document.getElementById("runBtnLabel");t&&(t.className=`btn-toolbar btn-run mode-${e}`),s&&(s.className=`btn-toolbar btn-run-gear mode-${e}`),n&&(n.textContent=e==="opencode"?"Run OC":e==="codex"?"Run CX":e==="gemini"?"Run GM":e==="antigravity"?"Run AG":e==="pi"?"Run PI":e==="grok"?"Run GK":e==="deepseek"?"Run DS":e==="omp"?"Run OMP":e==="shell"?"Run SH":"Run")},sendEnterKey(){if(!this.activeSessionId)return;const e=this.terminal?._core?.coreService;if(e&&typeof e.triggerDataEvent=="function"){e.triggerDataEvent("\r",!0);return}this.sendInput("\r")},_initRunMode(){try{this._runMode=localStorage.getItem("codeman_runMode")||"claude"}catch{this._runMode="claude"}this._applyRunMode()},incrementTabCount(){const e=document.getElementById("tabCount"),t=parseInt(e.value)||1;e.value=Math.min(20,t+1)},decrementTabCount(){const e=document.getElementById("tabCount"),t=parseInt(e.value)||1;e.value=Math.max(1,t-1)},incrementShellCount(){const e=document.getElementById("shellCount"),t=parseInt(e.value)||1;e.value=Math.min(20,t+1)},decrementShellCount(){const e=document.getElementById("shellCount"),t=parseInt(e.value)||1;e.value=Math.max(1,t-1)},_nextCaseSessionStartNumber(e,t="w"){const s=new RegExp(`^${t}(\\d+)-([a-zA-Z0-9_-]+)`);let n=1;for(const[,a]of this.sessions||[]){const i=a.name&&a.name.match(s);if(i&&i[2]===e){const o=parseInt(i[1]);o>=n&&(n=o+1)}}return n},_beginSessionLaunchStatus(e,t="1;32"){const s=!this.activeSessionId;return s?(this.terminal.clear(),this.terminal.writeln(`\x1B[${t}m ${e}\x1B[0m`),this.terminal.writeln("")):this.showToast?.(e,"info"),s},_appendSessionLaunchStatus(e,t,s="90"){!e||this.activeSessionId||this.terminal.writeln(`\x1B[${s}m ${t}\x1B[0m`)},_reportSessionLaunchError(e,t){e&&!this.activeSessionId?this.terminal.writeln(`\x1B[1;31m Error: ${t}\x1B[0m`):this.showToast?.(t,"error")},async runClaude(){const e=document.getElementById("quickStartCase").value||"testcase",t=Math.min(20,Math.max(1,parseInt(document.getElementById("tabCount").value)||1)),s=this._beginSessionLaunchStatus(`Starting ${t} Claude session(s) in ${e}...`);this.terminal.focus();try{let a=(await(await fetch(`/api/cases/${e}`)).json())?.data??{};if(!a.path){const S=await(await fetch("/api/cases",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,description:""})})).json();if(!S.success)throw new Error(S.error||"Failed to create case");a=S.data.case}const i=a.path;if(!i)throw new Error("Case path not found");if(a.location==="remote"||a.location==="docker"){const g=this._nextCaseSessionStartNumber(e);let S;if(a.location==="docker"){const E=this.loadAppSettingsFromStorage(),I=this.getCaseSettings(e).opusContext1m||E.opusContext1mEnabled;S=E.claudeModel||(I?"opus[1m]":"")}const b=[];let T=!1;for(let E=0;E<t;E++){const B=JSON.stringify({caseName:e,mode:"claude",sessionName:`w${g+E}-${e}`,...S!==void 0?{modelOverride:S}:{}}),I=async()=>(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:B})).json();let v=await I();if(!v.success&&v.errorCode==="CONFLICT"&&a.location==="docker"&&!T&&(T=!0,confirm(`Container config for "${e}" changed since its container was created.
14
-
15
- Recreate the container to apply the new config? Workspace files and the conversation survive (the conversation resumes on launch).`))){const _=await(await fetch(`/api/docker-cases/${encodeURIComponent(e)}/recreate`,{method:"POST"})).json();if(!_.success)throw new Error(_.error||"Failed to recreate container");v=await I()}if(!v.success)throw new Error(v.error||"Failed to start remote Claude session");await this._ensureCreatedSessionVisible(v.data.sessionId,v.data.session),b.push(v.data.sessionId)}this._appendSessionLaunchStatus(s,`All ${t} remote session(s) ready`),b[0]&&(await this.selectSession(b[0]),this.loadQuickStartCases()),this.terminal.focus();return}let o=null;const r=this._nextCaseSessionStartNumber(e),c=this.isRalphTrackerEnabledByDefault(),d=[];for(let g=0;g<t;g++)d.push(`w${r+g}-${e}`);const l=this.getCaseSettings(e),m=this.loadAppSettingsFromStorage(),h=this.buildEnvOverrides(l,m),C=Object.keys(h).length>0,u=this.getEffortSetting(m),f=l.opusContext1m||m.opusContext1mEnabled,y=m.claudeModel||(f?"opus[1m]":"");this._appendSessionLaunchStatus(s,`Creating ${t} session(s)...`);const k=d.map(g=>fetch("/api/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({workingDir:i,name:g,...C?{envOverrides:h}:{},...u?{effort:u}:{},...y!==void 0?{modelOverride:y}:{},statusLineTelemetry:this.planUsageChipEnabled(m)})}).then(S=>S.json())),p=await Promise.all(k),w=[];for(const g of p){if(!g.success)throw new Error(g.error);await this._ensureCreatedSessionVisible(g.data.session.id,g.data.session),w.push(g.data.session.id)}o=w[0],await Promise.all(w.map(g=>fetch(`/api/sessions/${g}/ralph-config`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:c,disableAutoEnable:!c})}))),this._appendSessionLaunchStatus(s,`Starting ${t} session(s) in parallel...`),await Promise.all(w.map(g=>fetch(`/api/sessions/${g}/interactive`,{method:"POST"}))),this._appendSessionLaunchStatus(s,`All ${t} sessions ready`),o&&(await this.selectSession(o),this.loadQuickStartCases()),this.terminal.focus()}catch(n){this._reportSessionLaunchError(s,n.message)}},stopClaude(){if(!this.activeSessionId)return;const e=document.querySelector(".btn-toolbar.btn-stop");e&&(this._stopConfirmTimer?(clearTimeout(this._stopConfirmTimer),this._stopConfirmTimer=null,e.innerHTML=e.dataset.origHtml,delete e.dataset.origHtml,e.classList.remove("confirming"),fetch(`/api/sessions/${this.activeSessionId}/input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({input:""})})):(e.dataset.origHtml=e.innerHTML,e.textContent="Tap again",e.classList.add("confirming"),this._stopConfirmTimer=setTimeout(()=>{this._stopConfirmTimer=null,e.dataset.origHtml&&(e.innerHTML=e.dataset.origHtml,delete e.dataset.origHtml),e.classList.remove("confirming")},2e3)))},async runShell(){const e=document.getElementById("quickStartCase").value||"testcase",t=Math.min(20,Math.max(1,parseInt(document.getElementById("shellCount").value)||1)),s=this._beginSessionLaunchStatus(`Starting ${t} Shell session(s) in ${e}...`,"1;33");try{let a=(await(await fetch(`/api/cases/${e}`)).json())?.data??{};if(!a.path){const f=await(await fetch("/api/cases",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,description:""})})).json();if(!f.success)throw new Error(f.error||"Failed to create case");a=f.data.case}const i=(this.cases||[]).find(u=>u.name===e),o=a.location==="remote"||a.location==="docker"||i?.location==="remote"||i?.location==="docker",r=a.path;if(!r)throw new Error("Case path not found");if(a.location==="remote"||a.location==="docker"){const u=this._nextCaseSessionStartNumber(e,"s"),f=[];for(let y=0;y<t;y++){const p=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"shell",sessionName:`s${u+y}-${e}`})})).json();if(!p.success)throw new Error(p.error||"Failed to start remote shell session");await this._ensureCreatedSessionVisible(p.data.sessionId,p.data.session),f.push(p.data.sessionId)}f[0]&&await this.selectSession(f[0]),this.terminal.focus();return}const c=this._nextCaseSessionStartNumber(e,"s"),d=[];for(let u=0;u<t;u++)d.push(`s${c+u}-${e}`);const l=d.map(u=>fetch("/api/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...o?{caseName:e}:{workingDir:r},mode:"shell",name:u})}).then(f=>f.json())),m=await Promise.all(l),h=[];for(const u of m){if(!u.success)throw new Error(u.error);await this._ensureCreatedSessionVisible(u.data.session.id,u.data.session),h.push(u.data.session.id)}await Promise.all(h.map(u=>fetch(`/api/sessions/${u}/shell`,{method:"POST"})));const C=this.getTerminalDimensions();C&&await Promise.all(h.map(u=>fetch(`/api/sessions/${u}/resize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(C)}))),h.length>0&&await this.selectSession(h[0]),this.terminal.focus()}catch(n){this._reportSessionLaunchError(s,n.message)}},async runOpenCode(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting OpenCode session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/opencode/status")).json()).data.available){this._reportSessionLaunchError(n,"OpenCode CLI not found. Install with: curl -fsSL https://opencode.ai/install | bash");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"opencode",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{openCodeConfig:{autoAllowTools:!0},...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start OpenCode");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runCodex(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting Codex session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/codex/status")).json()).data.available){this._reportSessionLaunchError(n,"Codex CLI not found. Install with: npm install -g @openai/codex");return}const a=this.loadAppSettingsFromStorage(),i=this.buildEnvOverrides(this.getCaseSettings(e),a),r=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"codex",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{codexConfig:{dangerouslyBypassApprovals:a.codexDangerouslyBypassApprovals??!1,animations:a.codexAnimationsEnabled??!1,renderMode:"hybrid"},...Object.keys(i).length>0?{envOverrides:i}:{}}})})).json();if(!r.success)throw new Error(r.error||"Failed to start Codex");await this._ensureCreatedSessionVisible(r.data.sessionId,r.data.session),r.data.sessionId&&await this.selectSession(r.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runGemini(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting Gemini session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/gemini/status")).json()).data.available){this._reportSessionLaunchError(n,"Gemini CLI not found. Install with: npm install -g @google/gemini-cli");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"gemini",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{geminiConfig:{approvalMode:"yolo"},...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start Gemini");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runAntigravity(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting Antigravity session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/antigravity/status")).json()).data.available){this._reportSessionLaunchError(n,"Antigravity CLI not found. Install with: curl -fsSL https://antigravity.google/cli/install.sh | bash");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"antigravity",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{antigravityConfig:{dangerouslySkipPermissions:!0},...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start Antigravity");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runPi(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting Pi session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/pi/status")).json()).data.available){this._reportSessionLaunchError(n,"Pi CLI not found. Install with: npm install -g --ignore-scripts @earendil-works/pi-coding-agent");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"pi",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s||Object.keys(a).length===0?{}:{envOverrides:a}})})).json();if(!o.success)throw new Error(o.error||"Failed to start Pi");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runOmp(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting OMP session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/omp/status")).json()).data.available){this._reportSessionLaunchError(n,"OMP CLI not found. Install with: curl -fsSL https://omp.sh/install | sh");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"omp",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start OMP");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runGrok(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting Grok session in ${e}...`);this.terminal.focus();try{if(!s&&!(await(await fetch("/api/grok/status")).json()).data.available){this._reportSessionLaunchError(n,"Grok CLI not found. Install with: curl -fsSL https://x.ai/cli/install.sh | bash");return}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"grok",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{grokConfig:{alwaysApprove:!0},...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start Grok");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},async runDeepSeek(){const e=document.getElementById("quickStartCase").value||"testcase",t=(this.cases||[]).find(a=>a.name===e)?.location,s=t==="remote"||t==="docker",n=this._beginSessionLaunchStatus(`Starting DeepSeek session in ${e}...`);this.terminal.focus();try{if(!s){const c=(await(await fetch("/api/deepseek/status")).json()).data;if(!c.available){this._reportSessionLaunchError(n,"DeepSeek Harness CLI (dsh) not found. Install with: npm install -g @deepseek-ai/dsh");return}if(!c.runnable){this._reportSessionLaunchError(n,"No interactive DeepSeek Harness profile is installed. DeepSeek ships only web and headless profiles, so the terminal agent comes from a plugin. Install one from the Run menu, or run: dsh plugin --profile dsh-tui add @deepseek-harness-tui/dsh-tui");return}}const a=this.buildEnvOverrides(this.getCaseSettings(e),this.loadAppSettingsFromStorage()),o=await(await fetch("/api/quick-start",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({caseName:e,mode:"deepseek",sessionName:`w${this._nextCaseSessionStartNumber(e)}-${e}`,...s?{}:{deepSeekConfig:{permissionMode:"danger-full-access"},...Object.keys(a).length>0?{envOverrides:a}:{}}})})).json();if(!o.success)throw new Error(o.error||"Failed to start DeepSeek");await this._ensureCreatedSessionVisible(o.data.sessionId,o.data.session),o.data.sessionId&&await this.selectSession(o.data.sessionId),this.terminal.focus()}catch(a){this._reportSessionLaunchError(n,a.message)}},_tabDetachOverrides(){if(this._tabDetachOverrideMap===void 0)try{this._tabDetachOverrideMap=JSON.parse(localStorage.getItem("codeman:tab-detach-overrides")||"{}")||{}}catch{this._tabDetachOverrideMap={}}return this._tabDetachOverrideMap},hasTabDetachOverride(e){return!!this._tabDetachOverrides()[e]},onSessionTabDetachToggle(e){const t=this.editingSessionId;if(!t)return;const s=this._tabDetachOverrides();e?s[t]=1:delete s[t];for(const a of Object.keys(s))a!==t&&this.sessions&&!this.sessions.has(a)&&delete s[a];try{localStorage.setItem("codeman:tab-detach-overrides",JSON.stringify(s))}catch{}const n=document.querySelector(`.session-tab[data-id="${CSS.escape(t)}"]`);n&&n.classList.toggle("tab-show-detach",!!e)},openSessionOptions(e){const t=this.sessions.get(e);if(!t)return;this.editingSessionId=e;const s=document.getElementById("sessionOptShowTabDetach");s&&(s.checked=this.hasTabDetachOverride(e));const n=t.mode==="opencode"||t.mode==="codex"||t.mode==="gemini"||t.mode==="antigravity"||t.mode==="pi"||t.mode==="grok"||t.mode==="deepseek"||t.mode==="omp";this.switchOptionsTab(n?"summary":"respawn");const a=document.getElementById("sessionRespawnStatus"),i=document.getElementById("modalEnableRespawnBtn"),o=document.getElementById("modalStopRespawnBtn");this.respawnStatus[e]?(a.classList.add("active"),a.querySelector(".respawn-status-text").textContent=this.respawnStatus[e].state||"Active",i.style.display="none",o.style.display=""):(a.classList.remove("active"),a.querySelector(".respawn-status-text").textContent="Not active",i.style.display="",o.style.display="none");const r=document.getElementById("sessionRespawnSection");t.mode==="claude"&&t.pid?r.style.display="":r.style.display="none";const c=t.mode==="opencode"||t.mode==="codex"||t.mode==="gemini"||t.mode==="antigravity"||t.mode==="pi"||t.mode==="grok"||t.mode==="deepseek"||t.mode==="omp";document.querySelectorAll("[data-claude-only]").forEach(k=>{k.style.display=c?"none":""}),this.selectDurationPreset(""),this.loadSavedRespawnConfig(e),document.getElementById("modalAutoCompactEnabled").checked=t.autoCompactEnabled??!1,document.getElementById("modalAutoCompactThreshold").value=t.autoCompactThreshold??11e4,document.getElementById("modalAutoCompactPrompt").value=t.autoCompactPrompt??"",document.getElementById("modalAutoClearEnabled").checked=t.autoClearEnabled??!1,document.getElementById("modalAutoClearThreshold").value=t.autoClearThreshold??14e4,document.getElementById("modalAutoResumeEnabled").checked=t.autoResumeEnabled??!1,this.updateAutoResumeStatus(e),document.getElementById("modalImageWatcherEnabled").checked=t.imageWatcherEnabled??!0,document.getElementById("modalFlickerFilterEnabled").checked=t.flickerFilterEnabled??!1;const l=parseSessionPrefix(t.name),m=document.getElementById("modalSessionPrefix");l?(m.textContent=l.prefix+": ",m.style.display="",document.getElementById("modalSessionName").value=l.suffix,document.getElementById("modalSessionName").placeholder="Add description..."):(m.style.display="none",m.textContent="",document.getElementById("modalSessionName").value=t.name||"",document.getElementById("modalSessionName").placeholder="Auto (directory name)");const h=t.color||"default";document.getElementById("sessionColorPicker")?.querySelectorAll(".color-swatch").forEach(k=>{k.classList.toggle("selected",k.dataset.color===h)}),this.renderPresetDropdown(),document.getElementById("respawnPresetSelect").value="",document.getElementById("presetDescriptionHint").textContent="";const u=document.querySelector('#sessionOptionsModal .set-rail-item[data-tab="ralph"]'),f=document.querySelector('#sessionOptionsModal .set-rail-item[data-tab="respawn"]');if(c?(u&&(u.style.display="none"),f&&(f.style.display="none"),this.switchOptionsTab("context")):(u&&(u.style.display=""),f&&(f.style.display="")),!c){const k=this.ralphStates.get(e);this.populateRalphForm({enabled:k?.loop?.enabled??t.ralphLoop?.enabled??!1,completionPhrase:k?.loop?.completionPhrase||t.ralphLoop?.completionPhrase||"",maxIterations:k?.loop?.maxIterations||t.ralphLoop?.maxIterations||0,maxTodos:k?.loop?.maxTodos||t.ralphLoop?.maxTodos,todoExpirationMinutes:k?.loop?.todoExpirationMinutes||t.ralphLoop?.todoExpirationMinutes})}const y=document.getElementById("sessionOptionsModal");y.dataset.chipsReady!=="1"&&(y.dataset.chipsReady="1",y.addEventListener("change",k=>{k.target?.closest?.(".set-chip")&&this._syncSettingsChips()})),this._syncSettingsChips(),y.classList.add("active"),this.activeFocusTrap=new FocusTrap(y),this.activeFocusTrap.activate()},_applyLocalSessionName(e,t){if(typeof t!="string")return;const s=this.sessions.get(e);s&&(s.name=t,this.sessions.set(e,s),this.updateSubagentParentNames?.(e))},async _putSessionName(e,t){const s=await this._apiPut(`/api/sessions/${e}/name`,{name:t});if(!s||!s.ok)return null;let n=null;try{n=await s.json()}catch{return null}if(n&&n.success===!1)return null;const a=n?.data?.name;return typeof a=="string"?a:t},async saveSessionName(){if(!this.editingSessionId)return;const e=this.editingSessionId,t=this.sessions.get(e),s=t?parseSessionPrefix(t.name):null,n=document.getElementById("modalSessionName").value.trim();let a;s?a=s.prefix+(n?": "+n:""):a=n;const i=await this._putSessionName(e,a);if(i===null){this.showToast("Failed to save session name","error");return}this._applyLocalSessionName(e,i),this.renderSessionTabs()},async autoSaveAutoCompact(){if(this.editingSessionId)try{await this._apiPost(`/api/sessions/${this.editingSessionId}/auto-compact`,{enabled:document.getElementById("modalAutoCompactEnabled").checked,threshold:parseInt(document.getElementById("modalAutoCompactThreshold").value)||11e4,prompt:document.getElementById("modalAutoCompactPrompt").value.trim()||void 0})}catch{}},async autoSaveAutoClear(){if(this.editingSessionId)try{await this._apiPost(`/api/sessions/${this.editingSessionId}/auto-clear`,{enabled:document.getElementById("modalAutoClearEnabled").checked,threshold:parseInt(document.getElementById("modalAutoClearThreshold").value)||14e4})}catch{}},async autoSaveAutoResume(){if(!this.editingSessionId)return;const e=document.getElementById("modalAutoResumeEnabled").checked;try{await this._apiPost(`/api/sessions/${this.editingSessionId}/auto-resume`,{enabled:e});const t=this.sessions.get(this.editingSessionId);t&&(t.autoResumeEnabled=e,e||(t.autoResumeAt=void 0)),this.updateAutoResumeStatus(this.editingSessionId),this.showToast(`Auto-resume on usage limit ${e?"enabled":"disabled"}`,"success")}catch(t){this.showToast("Failed to toggle auto-resume: "+t.message,"error")}},updateAutoResumeStatus(e){const t=document.getElementById("autoResumeStatus");if(!t||this.editingSessionId!==e)return;const s=this.sessions.get(e);if(s?.autoResumeAt&&s.autoResumeAt>Date.now()){const n=new Date(s.autoResumeAt).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});t.textContent=`Usage limit pause active \u2014 resumes at ${n}`,t.classList.add("active")}else t.textContent="",t.classList.remove("active")},async toggleSessionImageWatcher(){if(!this.editingSessionId)return;const e=document.getElementById("modalImageWatcherEnabled").checked;try{await this._apiPost(`/api/sessions/${this.editingSessionId}/image-watcher`,{enabled:e});const t=this.sessions.get(this.editingSessionId);t&&(t.imageWatcherEnabled=e),this.showToast(`Image watcher ${e?"enabled":"disabled"}`,"success")}catch{this.showToast("Failed to toggle image watcher","error")}},async toggleFlickerFilter(){if(!this.editingSessionId)return;const e=document.getElementById("modalFlickerFilterEnabled").checked;try{await this._apiPost(`/api/sessions/${this.editingSessionId}/flicker-filter`,{enabled:e});const t=this.sessions.get(this.editingSessionId);t&&(t.flickerFilterEnabled=e),this.showToast(`Flicker filter ${e?"enabled":"disabled"}`,"success")}catch{this.showToast("Failed to toggle flicker filter","error")}},async autoSaveRespawnConfig(){if(!this.editingSessionId)return;const e={updatePrompt:document.getElementById("modalRespawnPrompt").value,sendClear:document.getElementById("modalRespawnSendClear").checked,sendInit:document.getElementById("modalRespawnSendInit").checked,kickstartPrompt:document.getElementById("modalRespawnKickstart").value.trim()||void 0,autoAcceptPrompts:document.getElementById("modalRespawnAutoAccept").checked};try{await this._apiPut(`/api/sessions/${this.editingSessionId}/respawn/config`,e)}catch{}},async loadSavedRespawnConfig(e){try{const s=await(await fetch(`/api/sessions/${e}/respawn/config`)).json();if(s.success&&s.data&&s.data.config){const n=s.data.config;document.getElementById("modalRespawnPrompt").value=n.updatePrompt||"update all the docs and CLAUDE.md",document.getElementById("modalRespawnSendClear").checked=n.sendClear??!0,document.getElementById("modalRespawnSendInit").checked=n.sendInit??!0,document.getElementById("modalRespawnKickstart").value=n.kickstartPrompt||"",document.getElementById("modalRespawnAutoAccept").checked=n.autoAcceptPrompts??!0,n.durationMinutes&&(document.querySelector(`.duration-preset-btn[data-minutes="${n.durationMinutes}"]`)?this.selectDurationPreset(String(n.durationMinutes)):(this.selectDurationPreset("custom"),document.getElementById("modalRespawnDuration").value=n.durationMinutes))}}catch{}},selectDurationPreset(e){document.querySelectorAll(".duration-preset-btn").forEach(a=>a.classList.remove("active"));const t=document.querySelector(`.duration-preset-btn[data-minutes="${e}"]`);t&&t.classList.add("active");const s=document.querySelector(".duration-custom-input"),n=document.getElementById("modalRespawnDuration");e==="custom"?(s.classList.add("visible"),n.focus()):(s.classList.remove("visible"),n.value="")},getSelectedDuration(){const e=document.querySelector(".duration-custom-input"),t=document.getElementById("modalRespawnDuration");if(e.classList.contains("visible"))return t.value?parseInt(t.value):null;{const n=document.querySelector(".duration-preset-btn.active")?.dataset.minutes;return n?parseInt(n):null}},switchOptionsTab(e){document.querySelectorAll("#sessionOptionsModal .set-rail-item").forEach(s=>{s.classList.toggle("active",s.dataset.tab===e)}),document.getElementById("respawn-tab").classList.toggle("hidden",e!=="respawn"),document.getElementById("context-tab").classList.toggle("hidden",e!=="context"),document.getElementById("ralph-tab").classList.toggle("hidden",e!=="ralph"),document.getElementById("summary-tab").classList.toggle("hidden",e!=="summary");const t=document.getElementById("sessionOptionsDoc");t&&(t.scrollTop=0),e==="summary"&&this.editingSessionId&&this.loadRunSummary(this.editingSessionId)},getRalphConfig(){return{enabled:document.getElementById("modalRalphEnabled").checked,completionPhrase:document.getElementById("modalRalphPhrase").value.trim(),maxIterations:parseInt(document.getElementById("modalRalphMaxIterations").value)||0,maxTodos:parseInt(document.getElementById("modalRalphMaxTodos").value)||50,todoExpirationMinutes:parseInt(document.getElementById("modalRalphTodoExpiration").value)||60}},populateRalphForm(e){document.getElementById("modalRalphEnabled").checked=e?.enabled??!1,document.getElementById("modalRalphPhrase").value=e?.completionPhrase||"",document.getElementById("modalRalphMaxIterations").value=e?.maxIterations||0,document.getElementById("modalRalphMaxTodos").value=e?.maxTodos||50,document.getElementById("modalRalphTodoExpiration").value=e?.todoExpirationMinutes||60},async saveRalphConfig(){if(!this.editingSessionId){this.showToast("No session selected","warning");return}const e=this.getRalphConfig();e.enabled&&this.ralphClosedSessions.delete(this.editingSessionId);try{const s=await(await fetch(`/api/sessions/${this.editingSessionId}/ralph-config`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})).json();if(s.error)throw new Error(s.error);this.showToast("Ralph config saved","success")}catch(t){this.showToast("Failed to save Ralph config: "+t.message,"error")}},startInlineRename(e){const t=this.sessions.get(e);if(!t)return;this._activeRename?.cancel();const s=document.querySelector(`.tab-name[data-session-id="${e}"]`);if(!s)return;this._inlineRenameActive=!0,s.classList.add("tab-name-renaming");const n=this.getSessionName(t),a=parseSessionPrefix(t.name),i=s.textContent,o=[...s.childNodes].map(p=>p.cloneNode(!0)),r=()=>{s.replaceChildren(...o.map(p=>p.cloneNode(!0)))};for(s.textContent="";s.firstChild;)s.removeChild(s.firstChild);if(a){const p=document.createElement("span");p.className="tab-rename-prefix",p.textContent=a.prefix+": ",p.style.cssText="color: var(--text-muted); font-size: 0.75rem; white-space: nowrap;",s.appendChild(p)}const c=document.createElement("input");c.type="text",c.value=a?a.suffix:t.name||"",c.placeholder=a?"Add description...":n,c.className="tab-rename-input";const d=s.closest(".tab-rail")?"auto":this.isSessionSidebarActive?.()?"100%":"80px";c.style.cssText=`width: ${d}; min-width: 0; font-size: 0.75rem; padding: 2px 4px; background: var(--bg-input); border: 1px solid var(--accent); border-radius: 3px; color: var(--text); outline: none;`,s.appendChild(c),c.focus(),c.select();let l=!1,m=!1,h=!1;const C=()=>{this._activeRename===k&&(this._inlineRenameActive=!1)},u=()=>{this._activeRename===k&&(h=!0,C(),this._activeRename=null,this.renderSessionTabs())},f=()=>{m||h||(m=!0,l=!0,s.classList.remove("tab-name-renaming"),r(),u())},y=async({commit:p})=>{if(l||m)return;if(l=!0,s.classList.remove("tab-name-renaming"),!p){f();return}if(this._activeRename!==k)return;C();const w=c.value.trim(),g=a?a.prefix+(w?": "+w:""):w;if(g===t.name?r():s.textContent=g||i,this.sessions.has(e)&&g!==t.name){const b=await this._putSessionName(e,g);if(m||this._activeRename!==k||!this.sessions.has(e))return;b===null?(r(),this.showToast("Failed to rename","error")):this._applyLocalSessionName(e,b)}u()},k={sessionId:e,cancel:f};this._activeRename=k,c.addEventListener("blur",()=>y({commit:!0})),c.addEventListener("keydown",p=>{p.isComposing||p.keyCode===229||(p.key==="Enter"?(p.preventDefault(),c.blur()):p.key==="Escape"&&(p.preventDefault(),f()))})},toggleCaseSettings(){const e=document.getElementById("caseSettingsPopover");if(e.classList.contains("hidden")){const t=document.getElementById("quickStartCase").value||"testcase",s=this.getCaseSettings(t);document.getElementById("caseAgentTeams").checked=s.agentTeams,document.getElementById("caseOpusContext1m").checked=s.opusContext1m,e.classList.remove("hidden");const n=a=>{!e.contains(a.target)&&!a.target.classList.contains("btn-case-settings")&&(e.classList.add("hidden"),document.removeEventListener("click",n))};setTimeout(()=>document.addEventListener("click",n),0)}else e.classList.add("hidden")},getCaseSettings(e){try{const t=localStorage.getItem("caseSettings_"+e);if(t)return JSON.parse(t)}catch{}return{agentTeams:!1,opusContext1m:!0}},saveCaseSettings(e,t){localStorage.setItem("caseSettings_"+e,JSON.stringify(t))},onCaseSettingChanged(){const e=document.getElementById("quickStartCase").value||"testcase",t=this.getCaseSettings(e);t.agentTeams=document.getElementById("caseAgentTeams").checked,t.opusContext1m=document.getElementById("caseOpusContext1m").checked,this.saveCaseSettings(e,t);const s=document.getElementById("caseAgentTeamsMobile");s&&(s.checked=t.agentTeams);const n=document.getElementById("caseOpusContext1mMobile");n&&(n.checked=t.opusContext1m)},toggleCaseSettingsMobile(){const e=document.getElementById("caseSettingsPopoverMobile");if(e.classList.contains("hidden")){const t=document.getElementById("quickStartCase").value||"testcase",s=this.getCaseSettings(t);document.getElementById("caseAgentTeamsMobile").checked=s.agentTeams,document.getElementById("caseOpusContext1mMobile").checked=s.opusContext1m,e.classList.remove("hidden");const n=a=>{!e.contains(a.target)&&!a.target.classList.contains("btn-case-settings-mobile")&&(e.classList.add("hidden"),document.removeEventListener("click",n))};setTimeout(()=>document.addEventListener("click",n),0)}else e.classList.add("hidden")},onCaseSettingChangedMobile(){const e=document.getElementById("quickStartCase").value||"testcase",t=this.getCaseSettings(e);t.agentTeams=document.getElementById("caseAgentTeamsMobile").checked,t.opusContext1m=document.getElementById("caseOpusContext1mMobile").checked,this.saveCaseSettings(e,t);const s=document.getElementById("caseAgentTeams");s&&(s.checked=t.agentTeams);const n=document.getElementById("caseOpusContext1m");n&&(n.checked=t.opusContext1m)},showCreateCaseModal(){document.getElementById("newCaseName").value="",document.getElementById("newCaseDescription").value="",document.getElementById("linkCaseName").value="",document.getElementById("linkCasePath").value="",["remoteCaseName","remoteCasePath","remoteHostId","remoteHostAddress","remoteHostUsername","remoteHostPort","remoteHostCodexCommand","remoteHostIdentityFile","remoteHostSocksProxy","remoteHostJumpHost","remoteHostExtraSshOptions"].forEach(r=>{const c=document.getElementById(r);c&&(c.value="")}),this._resetCloneForm();const t=document.getElementById("caseCloneTabBtn");t&&(t.style.display=this.isCliAvailable("git")?"":"none"),this.caseModalTab="case-create",this.switchCaseModalTab("case-create");const s=document.getElementById("createCaseModal");s.querySelectorAll(".set-rail-item").forEach(r=>{r.onclick=()=>this.switchCaseModalTab(r.dataset.tab)});const n=document.getElementById("dockerAdoptExisting");n&&(n.onchange=()=>this._syncDockerAdoptMode());const a=document.getElementById("dockerAdoptCheckBtn");a&&(a.onclick=()=>this._dockerAdoptPreflight());const i=document.getElementById("dockerAdoptJumpBtn");i&&(i.onclick=()=>this.jumpToDockerAdopt());const o=document.getElementById("dockerHostId");o&&(o.onchange=()=>{delete document.getElementById("dockerContainerList")?.dataset.loadedFor,document.getElementById("dockerAdoptExisting")?.checked&&this._loadDockerContainerOptions()}),delete document.getElementById("dockerContainerList")?.dataset.loadedFor,this._syncDockerAdoptMode(),s.querySelectorAll('input[type="text"]').forEach(r=>{r._mobileScrollWired||(r._mobileScrollWired=!0,r.addEventListener("focus",()=>{window.innerWidth<=430&&setTimeout(()=>r.scrollIntoView({behavior:"smooth",block:"center"}),300)}))}),s.classList.add("active"),document.getElementById("newCaseName").focus()},switchCaseModalTab(e){this.caseModalTab=e;const t=document.getElementById("createCaseModal");t.querySelectorAll(".set-rail-item").forEach(a=>{a.classList.toggle("active",a.dataset.tab===e)}),t.querySelectorAll(".set-section").forEach(a=>{a.classList.toggle("hidden",a.id!==e)});const s=document.getElementById("createCaseDoc");s&&(s.scrollTop=0);const n=["caseModalSubmit","caseModalSubmitMobile"].map(a=>document.getElementById(a)).filter(Boolean);if(e==="case-manage")n.forEach(a=>{a.style.display="none"}),this.renderCaseManageList(),this.refreshDockerExports();else{const a=e==="case-create"?"Create":e==="case-clone"?"Clone":e==="case-remote"?"Link Remote":e==="case-docker"?"Link Docker":"Link";n.forEach(i=>{i.style.display="",i.textContent=a})}e==="case-create"?document.getElementById("newCaseName").focus():e==="case-clone"?document.getElementById("cloneRepoUrl").focus():e==="case-link"?document.getElementById("linkCaseName").focus():e==="case-remote"?document.getElementById("remoteCaseName").focus():e==="case-docker"&&document.getElementById("dockerCaseName").focus()},closeCreateCaseModal(){document.getElementById("createCaseModal").classList.remove("active")},async submitCaseModal(){const e=["caseModalSubmit","caseModalSubmitMobile"].map(n=>document.getElementById(n)).filter(Boolean),t=e.map(n=>n.textContent),s=this.caseModalTab==="case-create"?"Creating...":this.caseModalTab==="case-clone"?"Cloning...":"Linking...";e.forEach(n=>{n.classList.add("loading"),n.textContent=s,n.disabled=!0});try{this.caseModalTab==="case-create"?await this.createCase():this.caseModalTab==="case-clone"?await this.cloneCase():this.caseModalTab==="case-remote"?await this.linkRemoteCase():this.caseModalTab==="case-docker"?await this.linkDockerCase():await this.linkCase()}finally{e.forEach((n,a)=>{n.classList.remove("loading"),n.disabled=!1,n.textContent=t[a]})}},async createCase(){const e=document.getElementById("newCaseName").value.trim(),t=document.getElementById("newCaseDescription").value.trim();if(!e){this.showToast("Please enter a case name","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}const s=document.getElementById("newCaseDocker")?.checked,n=s?"/api/cases/docker-quickcreate":"/api/cases",a=s?{name:e,description:t,...this._collectDockerQuickSettings()}:{name:e,description:t};try{const o=await(await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)})).json();if(o.success)if(this.closeCreateCaseModal(),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e),s){const r=o.data?.capsEnforced===!1?" (resource caps advisory on this engine)":"";this.showToast(`Docker case "${e}" created${r} \u2014 starting session\u2026`,"success"),await this.runClaude()}else this.showToast(`Case "${e}" created`,"success");else this.showToast(o.error||"Failed to create case","error")}catch(i){console.error("Failed to create case:",i),this.showToast("Failed to create case: "+i.message,"error")}},applyDockerTemplate(){const e=document.getElementById("quickDockerTemplate")?.value,s={small:{m:"2g",c:"1",g:""},medium:{m:"",c:"",g:""},large:{m:"8g",c:"4",g:""},gpu:{m:"8g",c:"4",g:"all"}}[e];if(!s)return;const n=(a,i)=>{const o=document.getElementById(a);o&&(o.value=i)};n("quickDockerMemory",s.m),n("quickDockerCpus",s.c),n("quickDockerGpus",s.g)},_collectDockerQuickSettings(){const e=c=>(document.getElementById(c)?.value||"").trim(),t={},s=e("quickDockerMemory");s&&(t.memory=s);const n=e("quickDockerCpus");n&&(t.cpus=n);const a=e("quickDockerGpus");a&&a.toLowerCase()!=="none"&&(t.gpus=a);const i=document.getElementById("quickDockerNetwork")?.value;i&&i!=="bridge"&&(t.network=i);const o=e("quickDockerImage");o&&(t.image=o);const r=document.getElementById("quickDockerMountCreds");return r&&!r.checked&&(t.mountCredentials=!1),t},async linkCase(){const e=document.getElementById("linkCaseName").value.trim(),t=document.getElementById("linkCasePath").value.trim();if(!e){this.showToast("Please enter a case name","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}if(!t){this.showToast("Please enter a folder path","error");return}try{const n=await(await fetch("/api/cases/link",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,path:t})})).json();n.success?(this.closeCreateCaseModal(),this.showToast(`Case "${e}" linked to ${t}`,"success"),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e)):this.showToast(n.error||"Failed to link case","error")}catch(s){console.error("Failed to link case:",s),this.showToast("Failed to link case: "+s.message,"error")}},_resetCloneForm(){const e=(o,r)=>{const c=document.getElementById(o);c&&(c.value=r)};e("cloneRepoUrl",""),e("cloneCaseName",""),e("cloneRepoRef","");const t=document.getElementById("cloneShallow");t&&(t.checked=!1);const s=document.getElementById("cloneStartSession");s&&(s.checked=!1);const n=document.getElementById("cloneRepoRefOptions");n&&n.replaceChildren();const a=document.getElementById("cloneRefHint");a&&(a.textContent="Leave blank for the repository's default branch."),this._cloneNameEdited=!1,this._clonePreflight=null,clearTimeout(this._clonePreflightTimer),this._clonePreflightAbort?.abort(),this._clonePreflightAbort=null,this._setCloneStatus("Public repositories only: Codeman clones with no credentials.","");const i=document.getElementById("cloneCaseBrain");if(i){for(const r of i.options){const c=r.dataset.cli;r.hidden=!!c&&!this.isCliAvailable(c)}const o=this.runMode||"claude";i.value=[...i.options].some(r=>r.value===o&&!r.hidden)?o:""}},_setCloneStatus(e,t){const s=document.getElementById("cloneRepoStatus");s&&(s.textContent=e,s.className=`form-hint clone-status${t?" clone-status-"+t:""}`)},_repoNameFromUrl(e){const t=(e||"").trim().replace(/\/+$/,"");return t?(t.replace(/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//,"").replace(/^[^@/]*@/,"").split(/[/:]/).filter(Boolean).pop()||"").replace(/\.git$/i,"").replace(/[^a-zA-Z0-9_-]+/g,"-").replace(/-{2,}/g,"-").replace(/^[-_]+|[-_]+$/g,"").slice(0,64):""},onCloneNameEdited(){this._cloneNameEdited=!!document.getElementById("cloneCaseName")?.value.trim()},onCloneUrlInput(){const e=document.getElementById("cloneRepoUrl")?.value.trim()||"",t=document.getElementById("cloneCaseName");if(t&&!this._cloneNameEdited&&(t.value=this._repoNameFromUrl(e)),clearTimeout(this._clonePreflightTimer),this._clonePreflightAbort?.abort(),this._clonePreflightAbort=null,!e){this._setCloneStatus("Public repositories only: Codeman clones with no credentials.","");return}if(this.isCliAvailable("git")===!1){this._setCloneStatus("git is not installed on the Codeman host, so cloning is unavailable.","err");return}this._setCloneStatus("Checking the repository\u2026",""),this._clonePreflightTimer=setTimeout(()=>this._runClonePreflight(e),450)},async _runClonePreflight(e){const t=new AbortController;this._clonePreflightAbort=t;try{const n=await(await fetch("/api/cases/clone-preflight",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({repository:e}),signal:t.signal})).json();if(document.getElementById("cloneRepoUrl")?.value.trim()!==e)return;if(!n.success){this._setCloneStatus(n.error||"Could not check that URL.","err");return}this._applyClonePreflight(n.data,e)}catch(s){if(s.name==="AbortError")return;this._setCloneStatus("Could not reach Codeman to check that URL.","err")}},_applyClonePreflight(e,t){this._clonePreflight=e;const s=e?.parse;if(!s?.cloneable){this._setCloneStatus(s?.message||"That URL cannot be cloned.","err");return}const n=document.getElementById("cloneCaseName");n&&!this._cloneNameEdited&&s.suggestedName&&(n.value=s.suggestedName);const a=s.owner?`${s.provider} ${s.owner}/${s.repo}`:`${s.provider} ${s.repo}`;if(e.gitAvailable===!1){this._setCloneStatus(`${a}: git is not installed on the Codeman host.`,"err");return}const i=e.remote;if(i&&!i.reachable){this._setCloneStatus(`${a}: ${i.failure?.message||"the remote could not be read."}`,"err");return}const o=document.getElementById("cloneRefHint"),r=document.getElementById("cloneRepoRefOptions");if(i&&r){r.replaceChildren();for(const d of[...i.branches||[],...i.tags||[]]){const l=document.createElement("option");l.value=d,r.appendChild(l)}if(o){const d=`${i.branches?.length||0} branches, ${i.tags?.length||0} tags`;o.textContent=i.defaultBranch?`Blank clones the default branch (${i.defaultBranch}). ${d} available.`:`Blank clones the default branch. ${d} available.`}}const c=s.warnings?.[0];this._setCloneStatus(c?`${a}: ${c}`:`${a}: ready to clone.`,c?"warn":"ok")},async cloneCase(){const e=document.getElementById("cloneRepoUrl").value.trim(),t=document.getElementById("cloneCaseName").value.trim(),s=document.getElementById("cloneRepoRef").value.trim(),n=!!document.getElementById("cloneShallow")?.checked,a=document.getElementById("cloneCaseBrain")?.value||"",i=!!document.getElementById("cloneStartSession")?.checked;if(!e){this.showToast("Please enter a repository URL","error");return}if(!t){this.showToast("Please enter a case name","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(t)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}this._setCloneStatus(`Cloning ${e}\u2026 this can take a while for a large repository.`,"");try{const r=await(await fetch("/api/cases/clone",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:t,repository:e,...s?{ref:s}:{},...n?{shallow:!0}:{}})})).json();if(!r.success){this._setCloneStatus(r.error||"Clone failed.","err"),this.showToast(r.error||"Failed to clone repository","error");return}a&&this.setRunMode(a),this.closeCreateCaseModal(),await this.loadQuickStartCases(t),await this.saveLastUsedCase(t),this.showToast(`Cloned into case "${t}"`,"success");for(const c of r.data?.warnings||[])this.showToast(c,"warning");i&&await this.run()}catch(o){console.error("Failed to clone repository:",o),this._setCloneStatus(`Lost the connection while cloning: ${o.message}. If git finishes, the case still appears in the list.`,"warn"),this.showToast("Clone request interrupted \u2014 watch the case list","error")}},openLinkCasePathPicker(){const e=document.getElementById("linkCasePath");PathPicker.open({title:"Select Existing Project Folder",initialPath:e.value.trim(),directoriesOnly:!0,onSelect:t=>{e.value=t;const s=document.getElementById("linkCaseName");if(!s.value.trim()){const n=t.split("/").filter(Boolean).pop()||"";/^[\p{L}\p{N}_-]+$/u.test(n)&&(s.value=n)}e.focus(),e.setSelectionRange(t.length,t.length)}})},openDockerWorkspacePathPicker(){const e=document.getElementById("dockerWorkspacePath");PathPicker.open({title:"Select Host Workspace Folder",initialPath:e.value.trim(),directoriesOnly:!0,onSelect:t=>{e.value=t;const s=document.getElementById("dockerCaseName");if(s&&!s.value.trim()){const n=t.split("/").filter(Boolean).pop()||"";/^[a-zA-Z0-9_-]+$/.test(n)&&(s.value=n)}}})},openDockerWorkdirPicker(){const e=document.getElementById("dockerAdoptWorkdir"),t=document.getElementById("dockerContainerName")?.value.trim(),s=document.getElementById("dockerHostId")?.value.trim()||"local";if(!t){this.showToast("Enter the container name first","error");return}PathPicker.open({title:`Select Folder Inside ${t}`,initialPath:e.value.trim()||"/",directoriesOnly:!0,fetchListing:async n=>{const a=await this._apiJson("/api/docker-cases/browse",{method:"POST",body:{hostId:s,container:t,path:n||"/"}});return a?a.error?{success:!1,error:a.error}:{success:!0,data:{...a,root:"/",roots:[{label:t,path:"/"}],truncated:!1}}:{success:!1,error:`Could not read ${t}. Is it running?`}},onSelect:n=>{e.value=n}})},async linkRemoteCase(){const e=document.getElementById("remoteCaseName").value.trim(),t=document.getElementById("remoteCasePath").value.trim(),s=document.getElementById("remoteHostId").value.trim(),n=document.getElementById("remoteHostAddress").value.trim(),a=document.getElementById("remoteHostUsername").value.trim(),i=document.getElementById("remoteHostCodexCommand").value.trim(),o=document.getElementById("remoteHostPort").value.trim(),r=document.getElementById("remoteHostIdentityFile").value.trim(),c=document.getElementById("remoteHostSocksProxy").value.trim(),d=document.getElementById("remoteHostJumpHost").value.trim(),l=document.getElementById("remoteHostExtraSshOptions").value.split(`
16
- `).map(h=>h.trim()).filter(h=>h.length>0);if(!e||!t||!s||!n||!a){this.showToast("Please complete all required remote fields","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)||!/^[a-zA-Z0-9_-]+$/.test(s)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}if(!t.startsWith("/")){this.showToast("Remote path must be absolute","error");return}let m;if(o&&(m=Number(o),!Number.isInteger(m)||m<1||m>65535)){this.showToast("SSH port must be a number between 1 and 65535","error");return}try{const h={id:s,label:s,host:n,username:a,...m?{port:m}:{},...r?{identityFile:r}:{},...c?{socksProxy:c}:{},...d?{jumpHost:d}:{},...l.length?{extraSshOptions:l}:{},...i?{commands:{codex:i}}:{}},u=await(await fetch("/api/remote-hosts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(h)})).json();if(!u.success&&u.errorCode!=="ALREADY_EXISTS")throw new Error(u.error||"Failed to save remote host");const y=await(await fetch("/api/cases/remote-link",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e,hostId:s,remotePath:t})})).json();y.success?(this.closeCreateCaseModal(),this.showToast(`Remote case "${e}" linked`,"success"),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e)):this.showToast(y.error||"Failed to link remote case","error")}catch(h){console.error("Failed to link remote case:",h),this.showToast("Failed to link remote case: "+h.message,"error")}},_syncDockerAdoptMode(){const e=document.getElementById("createCaseModal");if(!e)return;const t=document.getElementById("dockerAdoptExisting")?.checked;t?e.setAttribute("data-docker-adopt","1"):e.removeAttribute("data-docker-adopt"),t&&this._loadDockerContainerOptions()},async _loadDockerContainerOptions(){const e=document.getElementById("dockerContainerList");if(!e)return;const t=document.getElementById("dockerHostId")?.value.trim()||"local";if(e.dataset.loadedFor===t)return;const n=(await this._apiJson(`/api/docker-hosts/${encodeURIComponent(t)}/containers`))?.containers||[];e.textContent="";for(const a of n){const i=document.createElement("option");i.value=a.name,i.textContent=a.running?`${a.image} \xB7 ${a.status}`:`${a.image} \xB7 ${a.status} (not running)`,e.appendChild(i)}e.dataset.loadedFor=t},jumpToDockerAdopt(){this.switchCaseModalTab("case-docker");const e=document.getElementById("dockerAdoptExisting");e&&(e.checked=!0),this._syncDockerAdoptMode(),document.getElementById("dockerContainerName")?.focus()},async _dockerAdoptPreflight(){const e=document.getElementById("dockerLinkStatus"),t=document.getElementById("dockerContainerName")?.value.trim(),s=document.getElementById("dockerAdoptWorkdir")?.value.trim(),n=document.getElementById("dockerHostId").value.trim()||"local";if(!t){e&&(e.textContent="Enter a container name first.");return}e&&(e.textContent="Inspecting container...");const a=await this._apiJson("/api/docker-cases/adopt-preflight",{method:"POST",body:{hostId:n,container:t,...s?{containerWorkdir:s}:{}}});if(!e)return;if(!a){e.textContent="Could not reach the docker host profile. Save a Host ID first.";return}if(!a.ok){e.textContent=a.error||"Container is not adoptable.";return}const i=(a.availableModes||[]).filter(o=>o!=="shell");e.textContent=i.length?`Running (${a.image||"unknown image"}). Available: ${i.join(", ")}.`:`Running (${a.image||"unknown image"}), but no agent CLI found inside \u2014 only Shell will work.`},async linkDockerCase(){const e=document.getElementById("dockerCaseName").value.trim(),t=document.getElementById("dockerWorkspacePath").value.trim(),s=document.getElementById("dockerHostId").value.trim()||"local",n=!!document.getElementById("dockerAdoptExisting")?.checked,a=document.getElementById("dockerContainerName")?.value.trim()||"",i=document.getElementById("dockerAdoptWorkdir")?.value.trim()||"",o=document.getElementById("dockerImage").value.trim()||"codeman/agent:base",r=document.getElementById("dockerNetwork").value,c=document.getElementById("dockerMemory").value.trim(),d=document.getElementById("dockerCpus").value.trim(),l=document.getElementById("dockerMountCredentials").checked,m=document.getElementById("dockerResumeOnStart").checked,h=document.getElementById("dockerLinkStatus");if(!e||!t){this.showToast("Please enter a case name and workspace path","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(e)||!/^[a-zA-Z0-9_-]+$/.test(s)){this.showToast("Invalid name. Use only letters, numbers, hyphens, underscores.","error");return}if(!t.startsWith("/")){this.showToast("Workspace path must be absolute","error");return}if(n&&!a){this.showToast("Enter the name of the running container to attach to","error");return}try{h&&(h.textContent=n?"Inspecting the existing container...":"Checking docker daemon + base image...");const C={};c&&(C.memory=c),d&&(C.cpus=d);const u={id:s,label:s,image:o,network:r,mountCredentials:l,resumeOnStart:m,...Object.keys(C).length?{resources:C}:{}};let f=await fetch("/api/docker-hosts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)}),y=await f.json();if(!y.success&&y.errorCode==="ALREADY_EXISTS"&&(f=await fetch(`/api/docker-hosts/${encodeURIComponent(s)}`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(u)}),y=await f.json()),!y.success)throw new Error(y.error||"Failed to save docker host");const p=await(await fetch(n?"/api/cases/docker-adopt":"/api/cases/docker-link",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n?{name:e,hostId:s,hostWorkspacePath:t,container:a,...i?{containerWorkdir:i}:{}}:{name:e,hostId:s,hostWorkspacePath:t})})).json();if(p.success){this.closeCreateCaseModal();const w=p.data?.capsEnforced===!1?" (resource caps are advisory on this engine)":"",g=(p.data?.availableModes||[]).filter(b=>b!=="shell"),S=n&&g.length?` \u2014 found ${g.join(", ")}`:"";this.showToast(`Docker case "${e}" ${n?"attached":"linked"}${w}${S}`,"success"),await this.loadQuickStartCases(e),await this.saveLastUsedCase(e)}else h&&(h.textContent=p.error||"Failed to link docker case"),this.showToast(p.error||"Failed to link docker case","error")}catch(C){console.error("Failed to link docker case:",C),h&&(h.textContent=C.message),this.showToast("Failed to link docker case: "+C.message,"error")}},async refreshDockerExports(){const e=document.getElementById("dockerExportsList");if(e)try{const n=(await(await fetch("/api/docker-exports")).json())?.data?.exports||[];if(n.length===0){e.innerHTML='<span class="form-hint">No exports yet. Export a docker case from its tab.</span>';return}e.innerHTML=n.map(a=>{const i=(a.sizeBytes/1e6).toFixed(1),o=escapeHtml(a.name);return`<div class="case-manage-item" style="display:flex; align-items:center; gap:8px; justify-content:space-between;">
17
- <span style="overflow:hidden; text-overflow:ellipsis; white-space:nowrap;" title="${o}">${o} <span class="form-hint">(${i} MB)</span></span>
18
- <span style="flex-shrink:0;">
19
- <a class="btn-toolbar" href="${CodemanBase.url(`/api/docker-exports/${encodeURIComponent(a.name)}`)}" download>Download</a>
20
- <button class="btn-toolbar" onclick="app.importDockerBundle('${o.replace(/'/g,"\\'")}')">Import</button>
21
- <button class="btn-toolbar" onclick="app.deleteDockerExport('${o.replace(/'/g,"\\'")}')">Delete</button>
22
- </span>
23
- </div>`}).join("")}catch(t){e.innerHTML=`<span class="form-hint">Failed to load exports: ${t.message}</span>`}},async exportDockerCaseBundle(e,t="full"){try{const n=await(await fetch(`/api/docker-cases/${encodeURIComponent(e)}/export`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mode:t})})).json();n.success?this.showToast(`Exporting "${e}" (${t})... you'll be notified when the bundle is ready`,"info"):this.showToast(n.error||"Export failed","error")}catch(s){this.showToast("Export failed: "+s.message,"error")}},async importDockerBundle(e){const t=prompt("New case name for the imported bundle:",e.split("-")[0]+"-imported");if(!t)return;const s=prompt("Absolute host directory to restore the workspace into:","");if(s)try{const a=await(await fetch("/api/docker-cases/import",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({bundle:e,newCaseName:t,destWorkspacePath:s})})).json();a.success?(this.showToast(`Imported as "${t}"`,"success"),await this.loadQuickStartCases(t)):this.showToast(a.error||"Import failed","error")}catch(n){this.showToast("Import failed: "+n.message,"error")}},async deleteDockerExport(e){if(confirm(`Delete export bundle "${e}"?`))try{const s=await(await fetch(`/api/docker-exports/${encodeURIComponent(e)}`,{method:"DELETE"})).json();s.success?(this.showToast("Export deleted","success"),this.refreshDockerExports()):this.showToast(s.error||"Delete failed","error")}catch(t){this.showToast("Delete failed: "+t.message,"error")}},_readRemoteHostFromForm(){const e=document.getElementById("remoteHostId").value.trim(),t=document.getElementById("remoteHostAddress").value.trim(),s=document.getElementById("remoteHostUsername").value.trim(),n=document.getElementById("remoteHostPort").value.trim(),a=document.getElementById("remoteHostIdentityFile").value.trim(),i=document.getElementById("remoteHostSocksProxy").value.trim(),o=document.getElementById("remoteHostJumpHost").value.trim(),r=document.getElementById("remoteHostCodexCommand").value.trim(),c=document.getElementById("remoteHostExtraSshOptions").value.split(`
24
- `).map(l=>l.trim()).filter(l=>l.length>0);let d;if(n){const l=Number(n);Number.isInteger(l)&&l>=1&&l<=65535&&(d=l)}return{id:e,label:e,host:t,username:s,...d?{port:d}:{},...a?{identityFile:a}:{},...i?{socksProxy:i}:{},...o?{jumpHost:o}:{},...c.length?{extraSshOptions:c}:{},...r?{commands:{codex:r}}:{}}},async discoverRemoteSessions(){const e=document.getElementById("remoteDiscoverResults"),t=document.getElementById("remoteDiscoverBtn"),s=this._readRemoteHostFromForm();if(!s.id||!s.host||!s.username){this.showToast("Fill in Host ID, address, and username first","error");return}if(!/^[a-zA-Z0-9_-]+$/.test(s.id)){this.showToast("Invalid Host ID. Use letters, numbers, hyphens, underscores.","error");return}t&&(t.disabled=!0),e&&(e.innerHTML='<div class="form-hint">Discovering\u2026</div>');try{const a=await(await fetch("/api/remote-hosts",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)})).json();if(!a.success&&a.errorCode!=="ALREADY_EXISTS")throw new Error(a.error||"Failed to save remote host");const o=await(await fetch(`/api/remote-hosts/${encodeURIComponent(s.id)}/sessions`)).json();if(!o.success)throw new Error(o.error||"Discovery failed");this._renderDiscoveredSessions(s.id,o.data.sessions||[])}catch(n){console.error("Discover remote sessions failed:",n),e&&(e.innerHTML=`<div class="form-hint" style="color: var(--error, #e06c75);">${escapeHtml(n.message)}</div>`)}finally{t&&(t.disabled=!1)}},_renderDiscoveredSessions(e,t){const s=document.getElementById("remoteDiscoverResults");if(!s)return;if(!t.length){s.innerHTML='<div class="form-hint">No <code>codeman-*</code> sessions running on this host (or it is unreachable).</div>';return}const n=Math.floor(Date.now()/1e3),a=t.map(i=>{const o=Math.max(0,n-(i.created||0)),r=o<3600?`${Math.floor(o/60)}m`:o<86400?`${Math.floor(o/3600)}h`:`${Math.floor(o/86400)}d`,c=i.attachedClients!=null?i.attachedClients:i.attached?1:0,d=c>1?`<span class="case-location-badge" style="background: var(--warning, #e5c07b); color: #000;">shared \xB7 ${c} clients</span>`:c===1?'<span class="case-location-badge" style="background: var(--accent, #61afef);">attached</span>':"";return`
25
- <div class="remote-discover-item">
26
- <div class="remote-discover-info">
27
- <span class="remote-discover-name">${escapeHtml(i.name)} ${d}</span>
28
- <span class="form-hint">age ${r} \xB7 ${i.windows||1} window(s)</span>
29
- </div>
30
- <button type="button" class="btn-toolbar" onclick="app.attachDiscoveredSession('${escapeHtml(e)}', '${escapeHtml(i.name)}')">Attach</button>
31
- </div>`}).join("");s.innerHTML=a},async attachDiscoveredSession(e,t){try{const n=await(await fetch("/api/sessions",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({mode:"shell",name:t,attachRemoteSession:{hostId:e,remoteSessionName:t}})})).json();if(!n.success)throw new Error(n.error||"Failed to create session");const a=n.data.session.id;await fetch(`/api/sessions/${a}/shell`,{method:"POST"});const i=this.getTerminalDimensions();i&&await fetch(`/api/sessions/${a}/resize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)}),this.closeCreateCaseModal(),this.showToast(`Attached to ${t} (detach on close)`,"success"),this.activeSessionId=a,await this.selectSession(a),this.terminal&&typeof this.terminal.focus=="function"&&this.terminal.focus()}catch(s){console.error("Attach discovered session failed:",s),this.showToast("Failed to attach: "+s.message,"error")}},renderCaseManageList(){const e=document.getElementById("caseManageList"),t=this.cases||[];if(t.length===0){e.innerHTML='<div class="form-hint" style="text-align: center; padding: 2rem 0;">No cases yet</div>';return}const s=t.filter(a=>a.agentCreated);let n=s.length>0?`<div class="case-manage-agent-bar">
32
- <span class="case-manage-agent-count">${s.length} case${s.length===1?"":"s"} created by agent workers</span>
33
- <button class="case-manage-btn case-manage-btn-cleanup" onclick="app.cleanupAgentCases()"
34
- title="Review and delete the scratch cases agent workers left behind">Clean up</button>
35
- </div>`:"";t.forEach((a,i)=>{const o=i===0,r=i===t.length-1,c=a.path?this._shortenHomePath(a.path):"",d=a.agentCreated?`Created by an agent worker${a.agentCreated.parentSessionName?` from ${a.agentCreated.parentSessionName}`:""} (${a.agentCreated.createdBy})${a.agentCreated.createdAt?` on ${new Date(a.agentCreated.createdAt).toLocaleString()}`:""}`:"";n+=`
36
- <div class="case-manage-item" data-case="${escapeHtml(a.name)}">
37
- <div class="case-manage-info">
38
- <span class="case-manage-name">${escapeHtml(a.name)}${a.agentCreated?`<span class="case-manage-tag-agent" title="${escapeHtml(d)}" data-i18n-skip>agent</span>`:""}</span>
39
- <span class="case-manage-path">${escapeHtml(c)}</span>
40
- </div>
41
- <div class="case-manage-actions">
42
- ${a.location==="docker"?`<button class="case-manage-btn" onclick="app.exportDockerCaseBundle(${escapeHtml(JSON.stringify(a.name))}, 'full')"
43
- title="Export container (full image + workspace) to move to another machine">&#x1F4E6;</button>`:""}
44
- <button class="case-manage-btn" onclick="app.moveCaseUp(${escapeHtml(JSON.stringify(a.name))})"
45
- title="Move up" ${o?"disabled":""}>&#x25B2;</button>
46
- <button class="case-manage-btn" onclick="app.moveCaseDown(${escapeHtml(JSON.stringify(a.name))})"
47
- title="Move down" ${r?"disabled":""}>&#x25BC;</button>
48
- <button class="case-manage-btn case-manage-btn-delete" onclick="app.deleteCase(${escapeHtml(JSON.stringify(a.name))})"
49
- title="Delete case">&#x2715;</button>
50
- </div>
51
- </div>
52
- `}),e.innerHTML=n},async moveCaseUp(e){const t=this.cases||[],s=t.findIndex(a=>a.name===e);if(s<=0)return;const n=[...t];[n[s-1],n[s]]=[n[s],n[s-1]],this.cases=n,this.renderCaseManageList(),await this.saveCaseOrder(n.map(a=>a.name))},async moveCaseDown(e){const t=this.cases||[],s=t.findIndex(a=>a.name===e);if(s<0||s>=t.length-1)return;const n=[...t];[n[s],n[s+1]]=[n[s+1],n[s]],this.cases=n,this.renderCaseManageList(),await this.saveCaseOrder(n.map(a=>a.name))},async deleteCase(e){if(confirm(`Delete case "${e}"? Linked cases will only be unlinked (folder preserved). Created cases will be permanently deleted.`))try{const s=await(await fetch(`/api/cases/${encodeURIComponent(e)}`,{method:"DELETE"})).json();if(s.success){this.showToast(`Case "${e}" ${s.data?.type==="unlinked"?"unlinked":"deleted"}`,"success"),this.cases=(this.cases||[]).filter(i=>i.name!==e),this.renderCaseManageList();const n=document.getElementById("quickStartCase"),a=n.value;a===e&&n.blur?.(),await this.loadQuickStartCases(a===e?null:a),a===e&&await this.saveLastUsedCase(document.getElementById("quickStartCase")?.value||"testcase")}else this.showToast(s.error||"Failed to delete case","error")}catch(t){this.showToast("Failed to delete case: "+t.message,"error")}},async cleanupAgentCases(){let e;try{const m=await(await fetch("/api/cases/agent-created")).json();if(!m.success){this.showToast(m.error||"Failed to list agent cases","error");return}e=m.data.cases||[]}catch(l){this.showToast("Failed to list agent cases: "+l.message,"error");return}const t=e.filter(l=>l.inUse),s=e.filter(l=>!l.inUse);if(s.length===0){this.showToast(t.length>0?`All ${t.length} agent case(s) are still in use by a running session`:"No agent-created cases to clean up","info");return}const n=s.map(l=>` ${l.name}`).join(`
53
- `),a=t.length>0?`
54
-
55
- Skipping ${t.length} case(s) still in use by a running session.`:"";if(!confirm(`Permanently delete ${s.length} agent-created case folder(s) and everything in them?
56
-
57
- ${n}${a}`))return;let i=0;const o=[];for(const l of s)try{(await(await fetch(`/api/cases/${encodeURIComponent(l.name)}`,{method:"DELETE"})).json()).success?i++:o.push(l.name)}catch{o.push(l.name)}this.showToast(o.length===0?`Deleted ${i} agent case(s)`:`Deleted ${i}, failed: ${o.join(", ")}`,o.length===0?"success":"error");const r=document.getElementById("quickStartCase"),c=r?.value,d=s.some(l=>l.name===c);d&&r?.blur?.(),await this.loadQuickStartCases(d?null:c),d&&await this.saveLastUsedCase(document.getElementById("quickStartCase")?.value||"testcase"),this.renderCaseManageList()},async saveCaseOrder(e){try{await fetch("/api/cases/order",{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({order:e})});const s=document.getElementById("quickStartCase").value;await this.loadQuickStartCases(s)}catch(t){this.showToast("Failed to save case order: "+t.message,"error")}},showMobileCasePicker(){const e=document.getElementById("mobileCasePickerModal"),t=document.getElementById("mobileCaseList"),n=document.getElementById("quickStartCase").value;let a="";const i=this.getCasePickerOptions();for(const o of i){const r=o.name===n;a+=`
58
- <button class="mobile-case-item ${r?"selected":""}"
59
- onclick="app.selectMobileCase(${escapeHtml(JSON.stringify(o.name))})">
60
- <span class="mobile-case-item-icon">
61
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
62
- <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/>
63
- </svg>
64
- </span>
65
- <span class="mobile-case-item-name">${escapeHtml(o.label)}</span>
66
- <span class="mobile-case-item-delete" onclick="event.stopPropagation(); app.deleteCaseMobile(${escapeHtml(JSON.stringify(o.name))})" title="Delete">
67
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
68
- <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
69
- </svg>
70
- </span>
71
- <span class="mobile-case-item-check">
72
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
73
- <polyline points="20 6 9 17 4 12"/>
74
- </svg>
75
- </span>
76
- </button>
77
- `}t.innerHTML=a,e.classList.add("active")},closeMobileCasePicker(){document.getElementById("mobileCasePickerModal").classList.remove("active")},selectMobileCase(e){const t=document.getElementById("quickStartCase");t.value=e,this.updateMobileCaseLabel(e),this.updateDirDisplayForCase(e),this.saveLastUsedCase(e),this.closeMobileCasePicker(),this.showToast(`Selected: ${e}`,"success")},updateMobileCaseLabel(e){const t=document.getElementById("mobileCaseName");t&&(t.textContent=e)},async deleteCaseMobile(e){if(confirm(`Delete case "${e}"?`))try{const s=await(await fetch(`/api/cases/${encodeURIComponent(e)}`,{method:"DELETE"})).json();s.success?(this.showToast(`Case "${e}" ${s.data?.type==="unlinked"?"unlinked":"deleted"}`,"success"),this.cases=(this.cases||[]).filter(n=>n.name!==e),this.closeMobileCasePicker(),await this.loadQuickStartCases()):this.showToast(s.error||"Failed to delete case","error")}catch(t){this.showToast("Failed to delete case: "+t.message,"error")}},showCreateCaseFromMobile(){this.closeMobileCasePicker(),this.showCreateCaseModal();const e=document.getElementById("createCaseModal");e.classList.add("from-mobile"),setTimeout(()=>e.classList.remove("from-mobile"),300)}}),Object.defineProperty(CodemanApp.prototype,"runMode",{configurable:!0,enumerable:!0,get(){return this._runMode||"claude"},set(e){this._runMode=e==="opencode"||e==="codex"||e==="gemini"||e==="antigravity"||e==="pi"||e==="grok"||e==="deepseek"||e==="omp"||e==="claude"?e:"claude"}});