aicodeman 1.30.0 → 1.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/cli-registry/schema.d.ts +8 -0
- package/dist/config/cli-registry/schema.d.ts.map +1 -1
- package/dist/config/cli-registry/schema.js +29 -0
- package/dist/config/cli-registry/schema.js.map +1 -1
- package/dist/config/cli-registry/stock.d.ts.map +1 -1
- package/dist/config/cli-registry/stock.js +62 -7
- package/dist/config/cli-registry/stock.js.map +1 -1
- package/dist/config/cli-registry/types.d.ts +62 -0
- package/dist/config/cli-registry/types.d.ts.map +1 -1
- package/dist/config/remote-wake-limits.d.ts +23 -0
- package/dist/config/remote-wake-limits.d.ts.map +1 -0
- package/dist/config/remote-wake-limits.js +23 -0
- package/dist/config/remote-wake-limits.js.map +1 -0
- package/dist/custom-model-hosts.d.ts +32 -0
- package/dist/custom-model-hosts.d.ts.map +1 -1
- package/dist/custom-model-hosts.js.map +1 -1
- package/dist/custom-model-injection-apply.d.ts +29 -1
- package/dist/custom-model-injection-apply.d.ts.map +1 -1
- package/dist/custom-model-injection-apply.js +191 -5
- package/dist/custom-model-injection-apply.js.map +1 -1
- package/dist/custom-model-injection.d.ts +35 -9
- package/dist/custom-model-injection.d.ts.map +1 -1
- package/dist/custom-model-injection.js +37 -16
- package/dist/custom-model-injection.js.map +1 -1
- package/dist/mux-interface.d.ts +12 -0
- package/dist/mux-interface.d.ts.map +1 -1
- package/dist/remote-hosts.d.ts +20 -0
- package/dist/remote-hosts.d.ts.map +1 -1
- package/dist/remote-hosts.js +33 -0
- package/dist/remote-hosts.js.map +1 -1
- package/dist/remote-wake.d.ts +446 -0
- package/dist/remote-wake.d.ts.map +1 -0
- package/dist/remote-wake.js +880 -0
- package/dist/remote-wake.js.map +1 -0
- package/dist/session-env-clamp.d.ts +12 -7
- package/dist/session-env-clamp.d.ts.map +1 -1
- package/dist/session-env-clamp.js +12 -7
- package/dist/session-env-clamp.js.map +1 -1
- package/dist/session-submit-verifier.d.ts +44 -0
- package/dist/session-submit-verifier.d.ts.map +1 -0
- package/dist/session-submit-verifier.js +122 -0
- package/dist/session-submit-verifier.js.map +1 -0
- package/dist/session.d.ts +9 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +42 -1
- package/dist/session.js.map +1 -1
- package/dist/tmux-manager.d.ts.map +1 -1
- package/dist/tmux-manager.js +9 -0
- package/dist/tmux-manager.js.map +1 -1
- package/dist/types/session.d.ts +26 -0
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js.map +1 -1
- package/dist/web/public/admin-ui.js.gz +0 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/app.8df358cd.js +38 -0
- package/dist/web/public/app.8df358cd.js.br +0 -0
- package/dist/web/public/app.8df358cd.js.gz +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/{constants.258b140f.js → constants.85ed12f3.js} +74 -0
- package/dist/web/public/constants.85ed12f3.js.br +0 -0
- package/dist/web/public/constants.85ed12f3.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/host-wake-ui.js +440 -0
- package/dist/web/public/host-wake-ui.js.br +0 -0
- package/dist/web/public/host-wake-ui.js.gz +0 -0
- package/dist/web/public/i18n.83924614.js +1 -0
- package/dist/web/public/i18n.83924614.js.br +0 -0
- package/dist/web/public/i18n.83924614.js.gz +0 -0
- package/dist/web/public/image-input.cd4b97c4.js.gz +0 -0
- package/dist/web/public/index.html +186 -10
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.2cf04f17.js.gz +0 -0
- package/dist/web/public/mobile-handlers.6f354a87.js.gz +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/mobile.6caaa28a.css.gz +0 -0
- package/dist/web/public/notification-manager.36ea4624.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/{panels-ui.5b07ad14.js → panels-ui.28df5053.js} +5 -5
- package/dist/web/public/panels-ui.28df5053.js.br +0 -0
- package/dist/web/public/panels-ui.28df5053.js.gz +0 -0
- package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
- package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
- package/dist/web/public/readmymind-ui.js.gz +0 -0
- package/dist/web/public/reboot-restore-ui.js.gz +0 -0
- package/dist/web/public/respawn-ui.ff0dae4c.js.gz +0 -0
- package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/session-ui.d4aea71a.js +88 -0
- package/dist/web/public/session-ui.d4aea71a.js.br +0 -0
- package/dist/web/public/session-ui.d4aea71a.js.gz +0 -0
- package/dist/web/public/settings-ui.4762f480.js +78 -0
- package/dist/web/public/settings-ui.4762f480.js.br +0 -0
- package/dist/web/public/settings-ui.4762f480.js.gz +0 -0
- package/dist/web/public/styles.e34fea04.css +1 -0
- package/dist/web/public/styles.e34fea04.css.br +0 -0
- package/dist/web/public/styles.e34fea04.css.gz +0 -0
- package/dist/web/public/subagent-windows.e6ca799f.js.gz +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/tab-rail-resize.42c24949.js.gz +0 -0
- package/dist/web/public/terminal-keycode229-recovery.fb91b25b.js.gz +0 -0
- package/dist/web/public/terminal-ui.35812aa2.js +2 -0
- package/dist/web/public/terminal-ui.35812aa2.js.br +0 -0
- package/dist/web/public/terminal-ui.35812aa2.js.gz +0 -0
- package/dist/web/public/ultracode-panel.js.gz +0 -0
- package/dist/web/public/ultracode-windows.js.gz +0 -0
- package/dist/web/public/upload.html.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.bd6882b8.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.6fee72f2.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.c4b51eb6.js.gz +0 -0
- package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
- package/dist/web/public/webview-tabs.js.gz +0 -0
- package/dist/web/routes/custom-model-routes.d.ts +173 -0
- package/dist/web/routes/custom-model-routes.d.ts.map +1 -1
- package/dist/web/routes/custom-model-routes.js +628 -11
- package/dist/web/routes/custom-model-routes.js.map +1 -1
- package/dist/web/routes/index.d.ts +1 -1
- package/dist/web/routes/index.d.ts.map +1 -1
- package/dist/web/routes/index.js +1 -1
- package/dist/web/routes/index.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts +6 -1
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +448 -17
- package/dist/web/routes/session-routes.js.map +1 -1
- package/dist/web/schemas.d.ts +15 -0
- package/dist/web/schemas.d.ts.map +1 -1
- package/dist/web/schemas.js +76 -0
- package/dist/web/schemas.js.map +1 -1
- package/dist/web/server.d.ts +21 -0
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +130 -5
- package/dist/web/server.js.map +1 -1
- package/dist/web/sse-events.d.ts +25 -2
- package/dist/web/sse-events.d.ts.map +1 -1
- package/dist/web/sse-events.js +30 -3
- package/dist/web/sse-events.js.map +1 -1
- package/package.json +1 -1
- package/skills/codeman/SKILL.md +75 -26
- package/skills/codeman/preamble.sh +66 -19
- package/skills/codeman/reference/recipes.md +1 -1
- package/dist/web/public/app.6d2dc4e8.js +0 -38
- package/dist/web/public/app.6d2dc4e8.js.br +0 -0
- package/dist/web/public/app.6d2dc4e8.js.gz +0 -0
- package/dist/web/public/constants.258b140f.js.br +0 -0
- package/dist/web/public/constants.258b140f.js.gz +0 -0
- package/dist/web/public/i18n.5f897ed5.js +0 -1
- package/dist/web/public/i18n.5f897ed5.js.br +0 -0
- package/dist/web/public/i18n.5f897ed5.js.gz +0 -0
- package/dist/web/public/panels-ui.5b07ad14.js.br +0 -0
- package/dist/web/public/panels-ui.5b07ad14.js.gz +0 -0
- package/dist/web/public/session-ui.42b81477.js +0 -77
- package/dist/web/public/session-ui.42b81477.js.br +0 -0
- package/dist/web/public/session-ui.42b81477.js.gz +0 -0
- package/dist/web/public/settings-ui.58f1d756.js +0 -67
- package/dist/web/public/settings-ui.58f1d756.js.br +0 -0
- package/dist/web/public/settings-ui.58f1d756.js.gz +0 -0
- package/dist/web/public/styles.e6edfb0b.css +0 -1
- package/dist/web/public/styles.e6edfb0b.css.br +0 -0
- package/dist/web/public/styles.e6edfb0b.css.gz +0 -0
- package/dist/web/public/terminal-ui.4f8d5820.js +0 -2
- package/dist/web/public/terminal-ui.4f8d5820.js.br +0 -0
- package/dist/web/public/terminal-ui.4f8d5820.js.gz +0 -0
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<link rel="manifest" href="manifest.json">
|
|
17
17
|
<title>Codeman</title>
|
|
18
18
|
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0%25' y1='0%25' x2='100%25' y2='100%25'%3E%3Cstop offset='0%25' stop-color='%2360a5fa'/%3E%3Cstop offset='100%25' stop-color='%233b82f6'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='32' height='32' rx='6' fill='%230a0a0a'/%3E%3Cpath d='M18 4L8 18h6l-2 10 10-14h-6z' fill='url(%23g)'/%3E%3C/svg%3E">
|
|
19
|
-
<link rel="stylesheet" href="styles.
|
|
19
|
+
<link rel="stylesheet" href="styles.e34fea04.css">
|
|
20
20
|
<link rel="stylesheet" href="mobile.6caaa28a.css" media="(max-width: 1023px)">
|
|
21
21
|
<!-- xterm.css loaded async — terminal won't display until xterm.js runs anyway -->
|
|
22
22
|
<link rel="preload" href="vendor/xterm.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
<!-- Symbols font before the terminal first paints — a late-loading icon font
|
|
28
28
|
leaves tofu in xterm's glyph atlas until something forces a re-render. -->
|
|
29
29
|
<link rel="preload" href="fonts/symbols-nerd-font-mono.woff2" as="font" type="font/woff2" crossorigin>
|
|
30
|
-
<link rel="preload" href="constants.
|
|
31
|
-
<link rel="preload" href="app.
|
|
30
|
+
<link rel="preload" href="constants.85ed12f3.js" as="script">
|
|
31
|
+
<link rel="preload" href="app.8df358cd.js" as="script">
|
|
32
32
|
<!-- Self-hosted xterm.js — eliminates CDN DNS/TLS latency (~100ms).
|
|
33
33
|
'defer' preserves execution order (xterm loads before fit addon). -->
|
|
34
34
|
<script defer src="vendor/xterm.min.js"></script>
|
|
@@ -213,6 +213,18 @@
|
|
|
213
213
|
<button class="offline-banner-retry" id="offlineBannerRetry" onclick="app.retryConnection()">Retry now</button>
|
|
214
214
|
</div>
|
|
215
215
|
|
|
216
|
+
<!-- Remote-host unreachable: the machine SLEEPS, the local ssh pane stalls
|
|
217
|
+
silently (send-keys succeeds against it, so typed input would vanish) and
|
|
218
|
+
Codeman can wake it. Amber, not red: the session is fine, the host is
|
|
219
|
+
asleep. Without a configured wake target the action becomes "Configure
|
|
220
|
+
WoL" and opens the small config dialog. -->
|
|
221
|
+
<div class="offline-banner host-wake-banner" id="hostWakeBanner" role="status" hidden>
|
|
222
|
+
<span class="offline-banner-dot" aria-hidden="true"></span>
|
|
223
|
+
<span class="offline-banner-text" id="hostWakeBannerText">Remote host is unreachable</span>
|
|
224
|
+
<span class="offline-banner-detail" id="hostWakeBannerDetail"></span>
|
|
225
|
+
<button class="offline-banner-retry" id="hostWakeBannerAction" onclick="app.hostWakeAction()">Wake</button>
|
|
226
|
+
</div>
|
|
227
|
+
|
|
216
228
|
<!-- Reboot-restore offer: shown when the server found sessions a host reboot
|
|
217
229
|
killed and is asking whether to rebuild them. Populated by
|
|
218
230
|
reboot-restore-ui.js; nothing is created until the user clicks. -->
|
|
@@ -668,6 +680,14 @@
|
|
|
668
680
|
<button class="run-mode-option" data-mode="omp" onclick="app.setRunMode('omp')">
|
|
669
681
|
<span class="run-mode-dot omp"></span>OMP
|
|
670
682
|
</button>
|
|
683
|
+
<!-- Custom Model Endpoint Profiles (docs/custom-model-endpoints-plan.md): one
|
|
684
|
+
generated entry per (harness, saved endpoint) pair, e.g. "Claude Code
|
|
685
|
+
(llama.cpp)". Built entirely by _refreshCustomModelRunOptions() — hidden
|
|
686
|
+
when the feature is off or no endpoint has a usable default model, never
|
|
687
|
+
a fixed per-harness duplicate in this markup. -->
|
|
688
|
+
<div class="run-mode-sep" id="runModeCustomModelSep" style="display: none;"></div>
|
|
689
|
+
<div class="run-mode-header" id="runModeCustomModelHeader" style="display: none;">Custom Endpoints</div>
|
|
690
|
+
<div class="run-mode-custom-models" id="runModeCustomModels"></div>
|
|
671
691
|
<div class="run-mode-sep"></div>
|
|
672
692
|
<button class="run-mode-option" data-mode="shell" onclick="app.setRunMode('shell')">
|
|
673
693
|
<span class="run-mode-dot shell"></span>Terminal / Shell
|
|
@@ -920,6 +940,67 @@
|
|
|
920
940
|
</div>
|
|
921
941
|
</div>
|
|
922
942
|
|
|
943
|
+
<!-- Custom Model Endpoint Profiles: "which model" picker (docs/custom-model-endpoints-plan.md).
|
|
944
|
+
Shown only when the chosen endpoint has more than one discovered model — see
|
|
945
|
+
selectCustomModelEntry() in session-ui.js, which skips straight to launch otherwise. -->
|
|
946
|
+
<div class="modal" id="customModelPickModal">
|
|
947
|
+
<div class="modal-backdrop" onclick="app.closeCustomModelPickModal()"></div>
|
|
948
|
+
<div class="modal-content modal-sm">
|
|
949
|
+
<div class="modal-header">
|
|
950
|
+
<h3 id="customModelPickTitle">Choose a model</h3>
|
|
951
|
+
<button class="modal-close" onclick="app.closeCustomModelPickModal()" aria-label="Close model picker">×</button>
|
|
952
|
+
</div>
|
|
953
|
+
<div class="modal-body">
|
|
954
|
+
<p class="form-hint" id="customModelPickHint"></p>
|
|
955
|
+
<div id="customModelPickList" class="run-mode-custom-models"></div>
|
|
956
|
+
</div>
|
|
957
|
+
</div>
|
|
958
|
+
</div>
|
|
959
|
+
|
|
960
|
+
<!-- Custom Model Endpoint Profiles: llama-swap model-swap confirmation
|
|
961
|
+
(docs/custom-model-endpoints-plan.md) — replaces a native confirm()
|
|
962
|
+
popup, shown when switching would unload a model another live
|
|
963
|
+
session is actively using. See _confirmModelSwap() in session-ui.js. -->
|
|
964
|
+
<div class="modal" id="customModelSwapConfirmModal">
|
|
965
|
+
<div class="modal-backdrop" onclick="app._resolveModelSwapConfirm(false)"></div>
|
|
966
|
+
<div class="modal-content modal-sm">
|
|
967
|
+
<div class="modal-header">
|
|
968
|
+
<h3>Switch models?</h3>
|
|
969
|
+
<button class="modal-close" onclick="app._resolveModelSwapConfirm(false)" aria-label="Cancel">×</button>
|
|
970
|
+
</div>
|
|
971
|
+
<div class="modal-body">
|
|
972
|
+
<p class="form-hint" id="customModelSwapConfirmMessage"></p>
|
|
973
|
+
</div>
|
|
974
|
+
<div class="modal-footer">
|
|
975
|
+
<button class="btn-toolbar" onclick="app._resolveModelSwapConfirm(false)">Cancel</button>
|
|
976
|
+
<button class="btn-toolbar btn-primary" onclick="app._resolveModelSwapConfirm(true)">Switch anyway</button>
|
|
977
|
+
</div>
|
|
978
|
+
</div>
|
|
979
|
+
</div>
|
|
980
|
+
|
|
981
|
+
<!-- Custom Model Endpoint Profiles: context-window-too-small warning
|
|
982
|
+
(docs/custom-model-endpoints-plan.md) — shown before launching a CLI
|
|
983
|
+
whose own fixed system-prompt/tool-schema overhead exceeds the
|
|
984
|
+
model's real discovered context, which guarantees a first-message
|
|
985
|
+
failure regardless of CLAUDE_CODE_MAX_CONTEXT_TOKENS. See
|
|
986
|
+
_confirmContextWarning() in session-ui.js. -->
|
|
987
|
+
<div class="modal" id="customModelContextWarningModal">
|
|
988
|
+
<div class="modal-backdrop" onclick="app._resolveContextWarningConfirm(false)"></div>
|
|
989
|
+
<div class="modal-content modal-sm">
|
|
990
|
+
<div class="modal-header">
|
|
991
|
+
<h3>Context window too small</h3>
|
|
992
|
+
<button class="modal-close" onclick="app._resolveContextWarningConfirm(false)" aria-label="Cancel">×</button>
|
|
993
|
+
</div>
|
|
994
|
+
<div class="modal-body">
|
|
995
|
+
<p class="form-hint" id="customModelContextWarningMessage" style="white-space: pre-wrap;"></p>
|
|
996
|
+
</div>
|
|
997
|
+
<div class="modal-footer">
|
|
998
|
+
<button class="btn-toolbar" onclick="app._resolveContextWarningConfirm(false)">Cancel</button>
|
|
999
|
+
<button class="btn-toolbar btn-primary" onclick="app._resolveContextWarningConfirm(true)">Launch anyway</button>
|
|
1000
|
+
</div>
|
|
1001
|
+
</div>
|
|
1002
|
+
</div>
|
|
1003
|
+
|
|
923
1004
|
<!-- Cron Jobs Modal -->
|
|
924
1005
|
<div class="modal" id="cronModal">
|
|
925
1006
|
<div class="modal-backdrop" onclick="app.closeCron()"></div>
|
|
@@ -2216,6 +2297,60 @@
|
|
|
2216
2297
|
</div>
|
|
2217
2298
|
</div>
|
|
2218
2299
|
</div>
|
|
2300
|
+
|
|
2301
|
+
<div class="set-group" id="customModelEndpointsGroup">
|
|
2302
|
+
<div class="set-group-head"><h4>Custom model endpoints</h4><span class="set-scope">synced</span></div>
|
|
2303
|
+
<p class="set-group-hint">Point a harness at your own OpenAI-compatible server (llama.cpp, vLLM, DGX Spark, Azure AI Foundry, OpenRouter) instead of its native cloud backend. When on, the Run menu offers an extra entry per harness that supports it, per saved endpoint.</p>
|
|
2304
|
+
<div class="set-group-body">
|
|
2305
|
+
<div class="set-row" data-search="custom model endpoint llama.cpp local llm run menu picker">
|
|
2306
|
+
<div class="set-row-text">
|
|
2307
|
+
<span class="set-row-label">Enable custom model endpoints</span>
|
|
2308
|
+
<span class="set-row-desc">Adds a per-endpoint entry to the Run menu for every harness that can redirect to one.</span>
|
|
2309
|
+
</div>
|
|
2310
|
+
<label class="switch switch-sm"><input type="checkbox" id="appSettingsCustomModelEndpoints" onchange="app.applyCustomModelEndpointsVisibility()"><span class="slider"></span></label>
|
|
2311
|
+
</div>
|
|
2312
|
+
<!-- Gated on the toggle above (applyCustomModelEndpointsVisibility): with the
|
|
2313
|
+
feature off, a list of endpoints that do nothing is worse than nothing. -->
|
|
2314
|
+
<div id="customModelEndpointsBody" style="display:none">
|
|
2315
|
+
<div id="customModelHostsList" class="set-group-body" data-search="endpoints"></div>
|
|
2316
|
+
<button type="button" class="btn-toolbar btn-sm" id="customModelHostAddBtn" onclick="app.openCustomModelHostEditor()">+ Add endpoint</button>
|
|
2317
|
+
<div id="customModelHostEditor" class="set-inline-form" style="display:none">
|
|
2318
|
+
<h5 id="customModelHostEditorTitle">Add endpoint</h5>
|
|
2319
|
+
<div class="set-row has-field">
|
|
2320
|
+
<div class="set-row-text"><span class="set-row-label">Id</span><span class="set-row-desc">Short, stable — used in URLs, never shown to the CLI.</span></div>
|
|
2321
|
+
<input type="text" id="customModelHostId" class="set-input" placeholder="llama-cpp-local">
|
|
2322
|
+
</div>
|
|
2323
|
+
<div class="set-row has-field">
|
|
2324
|
+
<div class="set-row-text"><span class="set-row-label">Label</span></div>
|
|
2325
|
+
<input type="text" id="customModelHostLabel" class="set-input" placeholder="llama.cpp (local)">
|
|
2326
|
+
</div>
|
|
2327
|
+
<div class="set-row has-field">
|
|
2328
|
+
<div class="set-row-text"><span class="set-row-label">Base URL</span></div>
|
|
2329
|
+
<input type="text" id="customModelHostBaseUrl" class="set-input" placeholder="http://192.168.1.50:8080">
|
|
2330
|
+
</div>
|
|
2331
|
+
<div class="set-row has-field">
|
|
2332
|
+
<div class="set-row-text"><span class="set-row-label">API key</span><span class="set-row-desc">Optional. Left blank on edit keeps the existing key.</span></div>
|
|
2333
|
+
<input type="password" id="customModelHostApiKey" class="set-input" autocomplete="new-password">
|
|
2334
|
+
</div>
|
|
2335
|
+
<div class="set-row has-field">
|
|
2336
|
+
<div class="set-row-text"><span class="set-row-label">Auth header</span><span class="set-row-desc">Never send both — some servers hang indefinitely.</span></div>
|
|
2337
|
+
<select id="customModelHostAuthStyle" class="set-select">
|
|
2338
|
+
<option value="bearer">Authorization: Bearer (default)</option>
|
|
2339
|
+
<option value="api-key">api-key header (Azure)</option>
|
|
2340
|
+
</select>
|
|
2341
|
+
</div>
|
|
2342
|
+
<div class="set-row has-field">
|
|
2343
|
+
<div class="set-row-text"><span class="set-row-label">Default model</span><span class="set-row-desc">What the Run-menu picker applies for this endpoint. Discover models first.</span></div>
|
|
2344
|
+
<select id="customModelHostDefaultModel" class="set-select" disabled></select>
|
|
2345
|
+
</div>
|
|
2346
|
+
<div class="set-row-actions">
|
|
2347
|
+
<button type="button" class="btn-toolbar btn-sm" onclick="app.saveCustomModelHostFromEditor()">Save</button>
|
|
2348
|
+
<button type="button" class="btn-toolbar btn-sm" onclick="app.closeCustomModelHostEditor()">Cancel</button>
|
|
2349
|
+
</div>
|
|
2350
|
+
</div>
|
|
2351
|
+
</div>
|
|
2352
|
+
</div>
|
|
2353
|
+
</div>
|
|
2219
2354
|
</section>
|
|
2220
2355
|
|
|
2221
2356
|
<!-- ══ Agents & CLIs ═════════════════════════════════════════ -->
|
|
@@ -2878,6 +3013,11 @@
|
|
|
2878
3013
|
<input type="number" id="remoteHostPort" placeholder="22" min="1" max="65535" autocomplete="off">
|
|
2879
3014
|
<span class="form-hint">Optional. Leave blank for the default port 22.</span>
|
|
2880
3015
|
</div>
|
|
3016
|
+
<div class="form-row">
|
|
3017
|
+
<label>Wake-on-LAN MAC</label>
|
|
3018
|
+
<input type="text" id="remoteHostWakeMac" placeholder="04:d9:f5:80:c6:58" autocomplete="off" autocapitalize="off" spellcheck="false">
|
|
3019
|
+
<span class="form-hint">Optional. Comma-separated for several NICs. Codeman sends the magic packet itself so a sleeping host can be woken from the session banner.</span>
|
|
3020
|
+
</div>
|
|
2881
3021
|
<div class="form-row">
|
|
2882
3022
|
<label>Codex Command Override</label>
|
|
2883
3023
|
<input type="text" id="remoteHostCodexCommand" placeholder="exec codx personal" autocomplete="off" autocapitalize="off" spellcheck="false">
|
|
@@ -2886,6 +3026,11 @@
|
|
|
2886
3026
|
<details class="advanced-options">
|
|
2887
3027
|
<summary><svg class="set-adv-chev" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg><span>Advanced SSH</span></summary>
|
|
2888
3028
|
<div class="advanced-options-content">
|
|
3029
|
+
<div class="form-row">
|
|
3030
|
+
<label>Wake Command</label>
|
|
3031
|
+
<input type="text" id="remoteHostWakeCommand" placeholder="/home/user/bin/wake-this-host" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false">
|
|
3032
|
+
<span class="form-hint">Optional override for the MAC above (takes precedence). A single executable path, run without a shell — use it when the host needs a router/other machine to send the packet.</span>
|
|
3033
|
+
</div>
|
|
2889
3034
|
<div class="form-row">
|
|
2890
3035
|
<label>Identity File</label>
|
|
2891
3036
|
<input type="text" id="remoteHostIdentityFile" placeholder="~/.ssh/remote_ed25519" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false">
|
|
@@ -3481,6 +3626,36 @@
|
|
|
3481
3626
|
text is set via value/textContent only: predictor output derives from
|
|
3482
3627
|
observable (injectable) content, and the explicit click here is the
|
|
3483
3628
|
security boundary (nothing is ever auto-sent). -->
|
|
3629
|
+
<!-- Wake-on-LAN setup for a remote host whose session cannot be woken yet. Kept
|
|
3630
|
+
deliberately small (host is fixed, only the wake fields are editable) so it can
|
|
3631
|
+
be opened from the banner with one click. Persists via PUT /api/remote-hosts/:id. -->
|
|
3632
|
+
<div class="modal" id="wakeConfigModal">
|
|
3633
|
+
<div class="modal-backdrop" onclick="app.closeWakeConfigDialog()"></div>
|
|
3634
|
+
<div class="modal-content">
|
|
3635
|
+
<div class="modal-header">
|
|
3636
|
+
<h3>Wake-on-LAN · <span id="wakeConfigHostLabel"></span></h3>
|
|
3637
|
+
<button class="modal-close" onclick="app.closeWakeConfigDialog()" aria-label="Close">×</button>
|
|
3638
|
+
</div>
|
|
3639
|
+
<div class="modal-body">
|
|
3640
|
+
<div class="form-row">
|
|
3641
|
+
<label>MAC address(es)</label>
|
|
3642
|
+
<input type="text" id="wakeConfigMac" placeholder="04:d9:f5:80:c6:58" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false">
|
|
3643
|
+
<span class="form-hint">Comma-separated for several NICs. Codeman sends the magic packet itself (UDP port 9, broadcast).</span>
|
|
3644
|
+
</div>
|
|
3645
|
+
<div class="form-row">
|
|
3646
|
+
<label>Wake command (optional)</label>
|
|
3647
|
+
<input type="text" id="wakeConfigCommand" placeholder="/home/user/bin/wake-this-host" autocomplete="off" autocapitalize="off" autocorrect="off" spellcheck="false">
|
|
3648
|
+
<span class="form-hint">Takes precedence over the MAC. A single executable path, run without a shell.</span>
|
|
3649
|
+
</div>
|
|
3650
|
+
<div class="form-hint" id="wakeConfigStatus"></div>
|
|
3651
|
+
</div>
|
|
3652
|
+
<div class="modal-footer">
|
|
3653
|
+
<button class="btn-toolbar" onclick="app.closeWakeConfigDialog()">Cancel</button>
|
|
3654
|
+
<button class="btn-toolbar btn-primary" id="wakeConfigSave" onclick="app.saveWakeConfig()">Save</button>
|
|
3655
|
+
</div>
|
|
3656
|
+
</div>
|
|
3657
|
+
</div>
|
|
3658
|
+
|
|
3484
3659
|
<div class="modal" id="readMyMindModal">
|
|
3485
3660
|
<div class="modal-backdrop" onclick="app.closeReadMyMind()"></div>
|
|
3486
3661
|
<div class="modal-content readmymind-modal">
|
|
@@ -3530,8 +3705,8 @@
|
|
|
3530
3705
|
<div class="approvals-list"></div>
|
|
3531
3706
|
</div>
|
|
3532
3707
|
|
|
3533
|
-
<script defer src="constants.
|
|
3534
|
-
<script defer src="i18n.
|
|
3708
|
+
<script defer src="constants.85ed12f3.js"></script>
|
|
3709
|
+
<script defer src="i18n.83924614.js"></script>
|
|
3535
3710
|
<script defer src="mobile-handlers.6f354a87.js"></script>
|
|
3536
3711
|
<script defer src="voice-input.c4b51eb6.js"></script>
|
|
3537
3712
|
<script defer src="notification-manager.36ea4624.js"></script>
|
|
@@ -3541,21 +3716,22 @@
|
|
|
3541
3716
|
<script defer src="terminal-keycode229-recovery.fb91b25b.js"></script>
|
|
3542
3717
|
<!-- Hardened markdown HTML sanitizer (wires DOMPurify). Must precede app.js. -->
|
|
3543
3718
|
<script defer src="sanitize-html.bc7078d6.js"></script>
|
|
3544
|
-
<script defer src="app.
|
|
3719
|
+
<script defer src="app.8df358cd.js"></script>
|
|
3545
3720
|
<script defer src="tab-rail-resize.42c24949.js"></script>
|
|
3546
|
-
<script defer src="terminal-ui.
|
|
3721
|
+
<script defer src="terminal-ui.35812aa2.js"></script>
|
|
3547
3722
|
<script defer src="respawn-ui.ff0dae4c.js"></script>
|
|
3548
3723
|
<script defer src="ralph-panel.6de2d0f8.js"></script>
|
|
3549
3724
|
<script defer src="orchestrator-panel.js"></script>
|
|
3550
3725
|
<script defer src="cron-ui.js"></script>
|
|
3551
|
-
<script defer src="settings-ui.
|
|
3552
|
-
<script defer src="panels-ui.
|
|
3726
|
+
<script defer src="settings-ui.4762f480.js"></script>
|
|
3727
|
+
<script defer src="panels-ui.28df5053.js"></script>
|
|
3553
3728
|
<script defer src="readmymind-ui.js"></script>
|
|
3554
3729
|
<script defer src="ultracode-panel.js"></script>
|
|
3555
3730
|
<script defer src="approvals-ui.js"></script>
|
|
3556
3731
|
<script defer src="reboot-restore-ui.js"></script>
|
|
3557
3732
|
<script defer src="admin-ui.js"></script>
|
|
3558
|
-
<script defer src="session-ui.
|
|
3733
|
+
<script defer src="session-ui.d4aea71a.js"></script>
|
|
3734
|
+
<script defer src="host-wake-ui.js"></script>
|
|
3559
3735
|
<script defer src="webview-tabs.js"></script>
|
|
3560
3736
|
<script defer src="mobile-overview.js"></script>
|
|
3561
3737
|
<script defer src="home-sessions.js"></script>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";const AWAY_DIGEST_LAST_VIEWED_KEY="codeman-away-digest-last-viewed",FILE_BROWSER_SHOW_HIDDEN_KEY="codeman:fileBrowserShowHidden",TEXT_PREVIEW_MAX_BYTES=524288,TEXT_PREVIEW_MAX_LINES=500,AWAY_DIGEST_SECTIONS=[["needsAttention","Needs Attention"],["completed","Completed"],["stillRunning","Still Running"],["idle","Idle"],["informational","Informational"]];Object.assign(CodemanApp.prototype,{_addActivityEntry(e,t,s=50){const n=this.subagentActivity.get(e)||[];n.push(t),n.length>s&&n.shift(),this.subagentActivity.set(e,n)},_onTaskCreated(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskCompleted(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskFailed(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskUpdated(e){e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onMuxCreated(e){this.muxSessions.push(e),this.renderMuxSessions()},_onMuxKilled(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions()},_onMuxDied(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions(),this.showToast("Mux session died: "+this.getShortId(e.sessionId),"warning")},_onMuxStatsUpdated(e){this.muxSessions=e,document.getElementById("monitorPanel").classList.contains("open")&&this.renderMuxSessions()},_onRemoteSessionReconnected(e){const t=this.getShortId(e.sessionId);this.showToast(`Remote session ${t} reconnected`,"success")},_onRemoteReconnectExhausted(e){const t=e.sessionId,s=this.getShortId(t);this.showToast(`Remote session ${s} dropped \u2014 auto-reconnect gave up`,"error",{duration:15e3,action:{label:"Reconnect",onClick:()=>{this.sessions&&this.sessions.has(t)?this.selectSession(t,{forceReload:!0}):this.showToast("Session no longer available","warning")}}})},_onBashToolStart(e){this.handleBashToolStart(e.sessionId,e.tool)},_onBashToolEnd(e){this.handleBashToolEnd(e.sessionId,e.tool)},_onBashToolsUpdate(e){this.handleBashToolsUpdate(e.sessionId,e.tools)},_onSubagentDiscovered(e){this.subagents.set(e.agentId,e),this.subagentActivity.set(e.agentId,[]),this.subagentToolResults.delete(e.agentId),this.subagentWindows.has(e.agentId)&&this.forceCloseSubagentWindow(e.agentId),this.renderSubagentPanel(),this.findParentSessionForSubagent(e.agentId),requestAnimationFrame(()=>{this.updateConnectionLines()});const t=this.subagentParentMap.get(e.agentId);this._notifySession(t||e.sessionId,"info","subagent-spawn","Subagent Spawned",e.description||"New background agent started")},_onSubagentUpdated(e){const t=this.subagents.get(e.agentId);t?(Object.assign(t,e),this.subagents.set(e.agentId,t)):this.subagents.set(e.agentId,e),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&(this.renderSubagentWindowContent(e.agentId),this.updateSubagentWindowHeader(e.agentId))},_onSubagentToolCall(e){this._addActivityEntry(e.agentId,{type:"tool",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentProgress(e){this._addActivityEntry(e.agentId,{type:"progress",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentMessage(e){this._addActivityEntry(e.agentId,{type:"message",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentToolResult(e){this.subagentToolResults.has(e.agentId)||this.subagentToolResults.set(e.agentId,new Map);const t=this.subagentToolResults.get(e.agentId);if(t.set(e.toolUseId,e),t.size>50){const s=t.keys().next().value;t.delete(s)}this._addActivityEntry(e.agentId,{type:"tool_result",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},async _onSubagentCompleted(e){const t=this.subagents.get(e.agentId);if(t&&(t.status="completed",this.subagents.set(e.agentId,t)),this.renderSubagentPanel(),this.updateSubagentWindows(),this.subagentWindows.has(e.agentId)){const n=this.subagentWindows.get(e.agentId);n&&!n.minimized&&(await this.closeSubagentWindow(e.agentId),this.saveSubagentWindowStates())}const s=this.subagentParentMap.get(e.agentId);this._notifySession(s||t?.sessionId||e.sessionId,"info","subagent-complete","Subagent Completed",t?.description||e.description||"Background agent finished"),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&(this.subagentActivity.delete(e.agentId),this.subagentToolResults.delete(e.agentId))},300*1e3),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&!this.subagentWindows.has(e.agentId)&&(this.subagents.delete(e.agentId),this.subagentParentMap.delete(e.agentId))},1800*1e3)},_onImageDetected(e){console.log("[Image Detected]",e),this.openImagePopup(e)},shouldOpenCommandPaletteFromShortcut(e){if(!e||!e.ctrlKey&&!e.metaKey&&!e.altKey)return!1;const s=typeof this.getShortcutRegistry=="function"&&typeof this.matchesShortcutEvent=="function"?this.getShortcutRegistry().find(a=>a.id==="command-palette"):null;if(s){if(s.disabled||!this.matchesShortcutEvent(e,s))return!1}else if((e.key||"").toLowerCase()!=="k"&&e.code!=="KeyK"||e.shiftKey)return!1;const n=e.target;if(!n)return!0;const i=(n.tagName||"").toUpperCase(),o=typeof n.className=="string"?n.className:"";return n.classList?.contains?.("xterm-helper-textarea")||o.includes("xterm-helper-textarea")?!0:!(i==="INPUT"||i==="TEXTAREA"||i==="SELECT"||n.isContentEditable||typeof n.closest=="function"&&n.closest('[contenteditable="true"]'))},openCommandPalette(){const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch");!e||!t||(this.commandPaletteActiveIndex=0,t.value="",e.classList.add("active"),this._wireCommandPalette(),this.renderCommandPalette(),t.focus(),t.select?.())},closeCommandPalette(){const e=document.getElementById("commandPaletteModal");e&&e.classList.remove("active")},_wireCommandPalette(){if(this._commandPaletteWired)return;this._commandPaletteWired=!0;const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch"),s=document.getElementById("commandPaletteList");t?.addEventListener("input",()=>{this.commandPaletteActiveIndex=0,this.renderCommandPalette()}),t?.addEventListener("keydown",async n=>{if(n.key==="ArrowDown"){n.preventDefault(),this.moveCommandPaletteSelection(1);return}if(n.key==="ArrowUp"){n.preventDefault(),this.moveCommandPaletteSelection(-1);return}if(n.key==="Enter"){n.preventDefault(),n.stopPropagation(),await this.activateCommandPaletteItem();return}n.key==="Escape"&&(n.preventDefault(),this.closeCommandPalette())}),e?.addEventListener("keydown",n=>{n.key==="Escape"&&(n.preventDefault(),this.closeCommandPalette())}),s?.addEventListener?.("click",n=>{const i=n.target?.closest?.("[data-command-index]");i&&(this.commandPaletteActiveIndex=Number(i.dataset.commandIndex)||0,this.activateCommandPaletteItem())})},buildCommandPaletteItems(e=""){const t=e.trim().toLowerCase(),s=[...Array.isArray(this.sessionOrder)?this.sessionOrder:[],...Array.from(this.sessions?.keys?.()||[]).filter(o=>!this.sessionOrder?.includes?.(o))],n=new Set,i=[];for(const o of s){if(n.has(o))continue;n.add(o);const r=this.sessions?.get?.(o);if(!r)continue;const a=this.getSessionName?.(r)||r.name||r.title||o.slice(0,8),l=[r.workingDir,r.mode,r.status].filter(Boolean),c=[a,r.workingDir,r.mode,r.status,o].filter(Boolean).join(" ").toLowerCase();t&&!c.includes(t)||i.push({id:`session:${o}`,type:"session",sessionId:o,title:a,subtitle:l.join(" \xB7 ")})}return i.push(this._buildCommandPaletteNewSessionItem(e)),i.push({id:"browse-sessions",type:"browse-sessions",title:"Browse all sessions\u2026",subtitle:"Open Session Manager"}),i},_buildCommandPaletteNewSessionItem(e=""){const t=this.runMode||this._runMode||"claude",s={claude:"Claude",opencode:"OpenCode",codex:"Codex",gemini:"Gemini",antigravity:"Antigravity",pi:"Pi",grok:"Grok",deepseek:"DeepSeek",omp:"OMP"},n=this._findCommandPaletteCaseMatch(e)||document.getElementById("quickStartCase")?.value||"testcase";return{id:"new-session",type:"new-session",caseName:n,title:"New session",subtitle:`Run ${s[t]||t} in ${n}`}},_findCommandPaletteCaseMatch(e=""){const t=e.trim().toLowerCase();if(!t||!Array.isArray(this.cases))return null;const s=o=>{const r=String(o?.name||"").trim();if(!r)return 0;const a=[r,o?.path,o?.casePath,o?.workingDir,o?.remote?.path,o?.remote?.hostId].filter(Boolean).join(" ").toLowerCase(),l=r.toLowerCase();return l===t?100:l.startsWith(t)?90:l.includes(t)?80:a.includes(t)?60:0};let n=null,i=0;for(const o of this.cases){const r=s(o);r>i&&(n=o,i=r)}return n?.name||null},renderCommandPalette(){const e=document.getElementById("commandPaletteSearch"),t=document.getElementById("commandPaletteList");if(!t)return;const s=e?.value||"",n=this.buildCommandPaletteItems(s);this.commandPaletteItems=n,this.commandPaletteActiveIndex=Math.max(0,Math.min(this.commandPaletteActiveIndex||0,n.length-1)),t.innerHTML=n.map((i,o)=>{const r=o===this.commandPaletteActiveIndex?" active":"",a=i.type==="new-session"?"+":i.type==="browse-sessions"?"\u2261":"\u203A",l=i.type==="browse-sessions"?" command-palette-item--browse":"";return`
|
|
1
|
+
"use strict";const AWAY_DIGEST_LAST_VIEWED_KEY="codeman-away-digest-last-viewed",FILE_BROWSER_SHOW_HIDDEN_KEY="codeman:fileBrowserShowHidden",TEXT_PREVIEW_MAX_BYTES=524288,TEXT_PREVIEW_MAX_LINES=500,AWAY_DIGEST_SECTIONS=[["needsAttention","Needs Attention"],["completed","Completed"],["stillRunning","Still Running"],["idle","Idle"],["informational","Informational"]];Object.assign(CodemanApp.prototype,{_addActivityEntry(e,t,s=50){const n=this.subagentActivity.get(e)||[];n.push(t),n.length>s&&n.shift(),this.subagentActivity.set(e,n)},_onTaskCreated(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskCompleted(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskFailed(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskUpdated(e){e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onMuxCreated(e){this.muxSessions.push(e),this.renderMuxSessions()},_onMuxKilled(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions()},_onMuxDied(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions(),this.showToast("Mux session died: "+this.getShortId(e.sessionId),"warning")},_onMuxStatsUpdated(e){this.muxSessions=e,document.getElementById("monitorPanel").classList.contains("open")&&this.renderMuxSessions()},_onRemoteSessionReconnected(e){const t=this.getShortId(e.sessionId);this.showToast(`Remote session ${t} reconnected`,"success"),this.activeSessionId===e.sessionId&&this._pollHostReachability?.(!0)},_onRemoteReconnectExhausted(e){const t=e.sessionId,s=this.getShortId(t);this.showToast(`Remote session ${s} dropped \u2014 auto-reconnect gave up`,"error",{duration:15e3,action:{label:"Reconnect",onClick:()=>{this.sessions&&this.sessions.has(t)?this.selectSession(t,{forceReload:!0}):this.showToast("Session no longer available","warning")}}})},_onBashToolStart(e){this.handleBashToolStart(e.sessionId,e.tool)},_onBashToolEnd(e){this.handleBashToolEnd(e.sessionId,e.tool)},_onBashToolsUpdate(e){this.handleBashToolsUpdate(e.sessionId,e.tools)},_onSubagentDiscovered(e){this.subagents.set(e.agentId,e),this.subagentActivity.set(e.agentId,[]),this.subagentToolResults.delete(e.agentId),this.subagentWindows.has(e.agentId)&&this.forceCloseSubagentWindow(e.agentId),this.renderSubagentPanel(),this.findParentSessionForSubagent(e.agentId),requestAnimationFrame(()=>{this.updateConnectionLines()});const t=this.subagentParentMap.get(e.agentId);this._notifySession(t||e.sessionId,"info","subagent-spawn","Subagent Spawned",e.description||"New background agent started")},_onSubagentUpdated(e){const t=this.subagents.get(e.agentId);t?(Object.assign(t,e),this.subagents.set(e.agentId,t)):this.subagents.set(e.agentId,e),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&(this.renderSubagentWindowContent(e.agentId),this.updateSubagentWindowHeader(e.agentId))},_onSubagentToolCall(e){this._addActivityEntry(e.agentId,{type:"tool",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentProgress(e){this._addActivityEntry(e.agentId,{type:"progress",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentMessage(e){this._addActivityEntry(e.agentId,{type:"message",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentToolResult(e){this.subagentToolResults.has(e.agentId)||this.subagentToolResults.set(e.agentId,new Map);const t=this.subagentToolResults.get(e.agentId);if(t.set(e.toolUseId,e),t.size>50){const s=t.keys().next().value;t.delete(s)}this._addActivityEntry(e.agentId,{type:"tool_result",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},async _onSubagentCompleted(e){const t=this.subagents.get(e.agentId);if(t&&(t.status="completed",this.subagents.set(e.agentId,t)),this.renderSubagentPanel(),this.updateSubagentWindows(),this.subagentWindows.has(e.agentId)){const n=this.subagentWindows.get(e.agentId);n&&!n.minimized&&(await this.closeSubagentWindow(e.agentId),this.saveSubagentWindowStates())}const s=this.subagentParentMap.get(e.agentId);this._notifySession(s||t?.sessionId||e.sessionId,"info","subagent-complete","Subagent Completed",t?.description||e.description||"Background agent finished"),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&(this.subagentActivity.delete(e.agentId),this.subagentToolResults.delete(e.agentId))},300*1e3),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&!this.subagentWindows.has(e.agentId)&&(this.subagents.delete(e.agentId),this.subagentParentMap.delete(e.agentId))},1800*1e3)},_onImageDetected(e){console.log("[Image Detected]",e),this.openImagePopup(e)},shouldOpenCommandPaletteFromShortcut(e){if(!e||!e.ctrlKey&&!e.metaKey&&!e.altKey)return!1;const s=typeof this.getShortcutRegistry=="function"&&typeof this.matchesShortcutEvent=="function"?this.getShortcutRegistry().find(a=>a.id==="command-palette"):null;if(s){if(s.disabled||!this.matchesShortcutEvent(e,s))return!1}else if((e.key||"").toLowerCase()!=="k"&&e.code!=="KeyK"||e.shiftKey)return!1;const n=e.target;if(!n)return!0;const i=(n.tagName||"").toUpperCase(),o=typeof n.className=="string"?n.className:"";return n.classList?.contains?.("xterm-helper-textarea")||o.includes("xterm-helper-textarea")?!0:!(i==="INPUT"||i==="TEXTAREA"||i==="SELECT"||n.isContentEditable||typeof n.closest=="function"&&n.closest('[contenteditable="true"]'))},openCommandPalette(){const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch");!e||!t||(this.commandPaletteActiveIndex=0,t.value="",e.classList.add("active"),this._wireCommandPalette(),this.renderCommandPalette(),t.focus(),t.select?.())},closeCommandPalette(){const e=document.getElementById("commandPaletteModal");e&&e.classList.remove("active")},_wireCommandPalette(){if(this._commandPaletteWired)return;this._commandPaletteWired=!0;const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch"),s=document.getElementById("commandPaletteList");t?.addEventListener("input",()=>{this.commandPaletteActiveIndex=0,this.renderCommandPalette()}),t?.addEventListener("keydown",async n=>{if(n.key==="ArrowDown"){n.preventDefault(),this.moveCommandPaletteSelection(1);return}if(n.key==="ArrowUp"){n.preventDefault(),this.moveCommandPaletteSelection(-1);return}if(n.key==="Enter"){n.preventDefault(),n.stopPropagation(),await this.activateCommandPaletteItem();return}n.key==="Escape"&&(n.preventDefault(),this.closeCommandPalette())}),e?.addEventListener("keydown",n=>{n.key==="Escape"&&(n.preventDefault(),this.closeCommandPalette())}),s?.addEventListener?.("click",n=>{const i=n.target?.closest?.("[data-command-index]");i&&(this.commandPaletteActiveIndex=Number(i.dataset.commandIndex)||0,this.activateCommandPaletteItem())})},buildCommandPaletteItems(e=""){const t=e.trim().toLowerCase(),s=[...Array.isArray(this.sessionOrder)?this.sessionOrder:[],...Array.from(this.sessions?.keys?.()||[]).filter(o=>!this.sessionOrder?.includes?.(o))],n=new Set,i=[];for(const o of s){if(n.has(o))continue;n.add(o);const r=this.sessions?.get?.(o);if(!r)continue;const a=this.getSessionName?.(r)||r.name||r.title||o.slice(0,8),l=[r.workingDir,r.mode,r.status].filter(Boolean),c=[a,r.workingDir,r.mode,r.status,o].filter(Boolean).join(" ").toLowerCase();t&&!c.includes(t)||i.push({id:`session:${o}`,type:"session",sessionId:o,title:a,subtitle:l.join(" \xB7 ")})}return i.push(this._buildCommandPaletteNewSessionItem(e)),i.push({id:"browse-sessions",type:"browse-sessions",title:"Browse all sessions\u2026",subtitle:"Open Session Manager"}),i},_buildCommandPaletteNewSessionItem(e=""){const t=this.runMode||this._runMode||"claude",s={claude:"Claude",opencode:"OpenCode",codex:"Codex",gemini:"Gemini",antigravity:"Antigravity",pi:"Pi",grok:"Grok",deepseek:"DeepSeek",omp:"OMP"},n=this._findCommandPaletteCaseMatch(e)||document.getElementById("quickStartCase")?.value||"testcase";return{id:"new-session",type:"new-session",caseName:n,title:"New session",subtitle:`Run ${s[t]||t} in ${n}`}},_findCommandPaletteCaseMatch(e=""){const t=e.trim().toLowerCase();if(!t||!Array.isArray(this.cases))return null;const s=o=>{const r=String(o?.name||"").trim();if(!r)return 0;const a=[r,o?.path,o?.casePath,o?.workingDir,o?.remote?.path,o?.remote?.hostId].filter(Boolean).join(" ").toLowerCase(),l=r.toLowerCase();return l===t?100:l.startsWith(t)?90:l.includes(t)?80:a.includes(t)?60:0};let n=null,i=0;for(const o of this.cases){const r=s(o);r>i&&(n=o,i=r)}return n?.name||null},renderCommandPalette(){const e=document.getElementById("commandPaletteSearch"),t=document.getElementById("commandPaletteList");if(!t)return;const s=e?.value||"",n=this.buildCommandPaletteItems(s);this.commandPaletteItems=n,this.commandPaletteActiveIndex=Math.max(0,Math.min(this.commandPaletteActiveIndex||0,n.length-1)),t.innerHTML=n.map((i,o)=>{const r=o===this.commandPaletteActiveIndex?" active":"",a=i.type==="new-session"?"+":i.type==="browse-sessions"?"\u2261":"\u203A",l=i.type==="browse-sessions"?" command-palette-item--browse":"";return`
|
|
2
2
|
<button class="command-palette-item${r}${l}" type="button" data-command-index="${o}">
|
|
3
3
|
<span class="command-palette-icon" aria-hidden="true">${a}</span>
|
|
4
4
|
<span class="command-palette-text">
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
<span class="stat-card-value">${this.formatTokens(u+d)}</span>
|
|
68
68
|
<span class="stat-card-cost">~$${h.toFixed(2)}</span>
|
|
69
69
|
</div>
|
|
70
|
-
`;const m=document.getElementById("statsChart"),g=document.getElementById("statsChartDays"),y=[];for(let f=6;f>=0;f--){const S=new Date;S.setDate(S.getDate()-f);const T=S.toISOString().split("T")[0],v=t.find(
|
|
70
|
+
`;const m=document.getElementById("statsChart"),g=document.getElementById("statsChartDays"),y=[];for(let f=6;f>=0;f--){const S=new Date;S.setDate(S.getDate()-f);const T=S.toISOString().split("T")[0],v=t.find(C=>C.date===T);y.push({date:T,dayName:S.toLocaleDateString("en-US",{weekday:"short"}),tokens:v?v.inputTokens+v.outputTokens:0,cost:v?v.estimatedCost:0})}const w=Math.max(...y.map(f=>f.tokens),1);m.innerHTML=y.map(f=>{const S=Math.max(f.tokens/w*100,3),T=`${f.dayName}: ${this.formatTokens(f.tokens)} (~$${f.cost.toFixed(2)})`;return`<div class="bar" style="height: ${S}%" data-tooltip="${T}"></div>`}).join(""),g.innerHTML=y.map(f=>`<span>${f.dayName}</span>`).join("");const b=document.getElementById("statsTable"),$=t.slice(0,14);$.length===0?b.innerHTML='<div class="stats-no-data">No usage data recorded yet</div>':b.innerHTML=`
|
|
71
71
|
<div class="stats-table-header">
|
|
72
72
|
<span>Date</span>
|
|
73
73
|
<span>Input</span>
|
|
@@ -239,7 +239,7 @@
|
|
|
239
239
|
`}).join("")}n.querySelectorAll(".file-tree-item").forEach(a=>{a.addEventListener("click",()=>{const l=a.dataset.path;a.dataset.type==="directory"?this._openFileBrowserSearchDirectory({...o,path:l}):this.openFilePreview(l,t)})});const r=this.$("fileBrowserStatus");if(r){const a=s.matchCount===void 0?e.length:s.matchCount;r.textContent=`${a} ${a===1?"match":"matches"}${s.truncated?" (truncated)":""}`}},_findFileBrowserDirectory(e,t,s=[]){if(!Array.isArray(e))return null;for(const n of e){if(!n||typeof n!="object")continue;if(n.type==="directory"&&n.path===t)return{target:n,ancestors:[...s]};if(n.type!=="directory"||!Array.isArray(n.children))continue;const i=this._findFileBrowserDirectory(n.children,t,[...s,n.path]);if(i)return i}return null},_isFileBrowserDirectoryContextCurrent(e){const t=this._ensureFileBrowserState(),s=this.$?.("fileBrowserSearch"),n=typeof s?.value=="string"?s.value:t.filter;return e&&t.ownerSessionId===e.ownerSessionId&&this.activeSessionId===e.ownerSessionId&&t.treeEpoch===e.treeEpoch&&t.searchEpoch===e.searchEpoch&&this.fileBrowserShowHidden===!0===e.showHidden&&t.filter===e.rawInput&&n===e.rawInput&&n.trim()===e.query&&t.view===e.view&&this.$?.("fileBrowserPanel")?.classList.contains("visible")===!0},_promptFileBrowserDirectoryReload(){this.showToast?.("Reload files before opening this folder","info")},_openFileBrowserSearchDirectory(e){if(!this._isFileBrowserDirectoryContextCurrent(e))return;const t=this._ensureFileBrowserState(),s=t.normalState;if(!this._isFileBrowserNormalCompatible(s,e.ownerSessionId,e.showHidden,e.treeEpoch)){t.deferredDirectoryTarget=null,this._promptFileBrowserDirectoryReload();return}if(s.phase==="loading"){t.deferredDirectoryTarget={...e};return}if(t.deferredDirectoryTarget=null,s.phase!=="ready"){this._promptFileBrowserDirectoryReload();return}const n=this._findFileBrowserDirectory(s.data?.tree,e.path);if(!n){this._promptFileBrowserDirectoryReload();return}this._leaveFileBrowserSearchForDirectory([...n.ancestors,n.target.path],s)},_completeDeferredFileBrowserDirectory(e){const t=this._ensureFileBrowserState(),s=t.deferredDirectoryTarget;if(!s)return!1;if(!this._isFileBrowserDirectoryContextCurrent(s))return t.deferredDirectoryTarget===s&&(t.deferredDirectoryTarget=null),!1;if(!this._isFileBrowserNormalCompatible(e,s.ownerSessionId,s.showHidden,s.treeEpoch)||e.phase!=="ready"&&e.phase!=="error")return!1;if(t.deferredDirectoryTarget=null,e.phase==="error")return this._promptFileBrowserDirectoryReload(),!1;const n=this._findFileBrowserDirectory(e.data?.tree,s.path);return n?(this._leaveFileBrowserSearchForDirectory([...n.ancestors,n.target.path],e),!0):(this._promptFileBrowserDirectoryReload(),!1)},_leaveFileBrowserSearchForDirectory(e,t){const s=this._ensureFileBrowserState();s.inFlight?.timer!==void 0&&s.inFlight?.timer!==null&&clearTimeout(s.inFlight.timer),s.searchEpoch++,s.inFlight=null,s.filter="",s.matches=[],s.deferredDirectoryTarget=null,s.view="normal",this.fileBrowserFilter="";const n=this.$?.("fileBrowserSearch");n&&(n.value=""),this._syncFileBrowserExpandBtn();for(const i of e)typeof i=="string"&&this.fileBrowserExpandedDirs?.add?.(i);this.fileBrowserData=t.data,this._renderFileBrowserNormalState(t)},expandAllDirectories(e){for(const t of e)t.type==="directory"&&(this.fileBrowserExpandedDirs.add(t.path),t.children&&this.expandAllDirectories(t.children))},collapseAllDirectories(){this.fileBrowserExpandedDirs.clear()},toggleFileBrowserExpand(){if(this._hasFileBrowserQuery()){this._syncFileBrowserExpandBtn();return}this.fileBrowserAllExpanded=!this.fileBrowserAllExpanded;const e=this.$("fileBrowserExpandBtn");this.fileBrowserAllExpanded?(this.expandAllDirectories(this.fileBrowserData?.tree||[]),e&&(e.innerHTML="\u229F")):(this.collapseAllDirectories(),e&&(e.innerHTML="\u229E")),this.renderFileBrowserTree()},refreshFileBrowser(){const e=this._ensureFileBrowserState();e.inFlight?.timer!==void 0&&e.inFlight?.timer!==null&&clearTimeout(e.inFlight.timer),e.inFlight=null,e.searchEpoch++,e.filter="",e.matches=[],e.deferredDirectoryTarget=null,e.view="normal",this.fileBrowserFilter="",this.fileBrowserExpandedDirs.clear(),this.fileBrowserAllExpanded=!1;const t=this.$("fileBrowserExpandBtn");t&&(t.innerHTML="\u229E");const s=this.$("fileBrowserSearch");s&&(s.value=""),this._syncFileBrowserExpandBtn();const n=e.ownerSessionId||this.activeSessionId;if(!(!n||this.activeSessionId!==n))return this.loadFileBrowser(n,{force:!0})},toggleFileBrowserButton(){const t=this.$("fileBrowserPanel")?.classList.contains("visible"),s=document.querySelector(".btn-file-viewer");if(t){this.closeFileBrowserPanel(),s&&s.setAttribute("aria-expanded","false");return}if(!this.activeSessionId){this.showToast("Open a session to browse its files","info");return}const n=this.loadAppSettingsFromStorage();n.showFileBrowser=!0,this.saveAppSettingsToStorage(n);const i=document.getElementById("appSettingsShowFileBrowser");i&&(i.checked=!0),this.applyMonitorVisibility(),s&&s.setAttribute("aria-expanded","true")},closeFileBrowserPanel(){const e=this.$("fileBrowserPanel");if(this._resetFileBrowserForHide(),e&&(e.classList.remove("visible"),e.style.left="",e.style.top="",e.style.bottom="",e.style.right=""),this.fileBrowserDragListeners){const i=this.fileBrowserDragListeners;document.removeEventListener("mousemove",i.move),document.removeEventListener("mouseup",i.up),document.removeEventListener("touchmove",i.touchMove),document.removeEventListener("touchend",i.up),document.removeEventListener("touchcancel",i.up),i.handle&&(i.handle.removeEventListener("mousedown",i.handleMouseDown),i.handle.removeEventListener("touchstart",i.handleTouchStart),i._onFirstDrag&&(i.handle.removeEventListener("mousedown",i._onFirstDrag),i.handle.removeEventListener("touchstart",i._onFirstDrag))),this.fileBrowserDragListeners=null}const t=this.loadAppSettingsFromStorage();t.showFileBrowser=!1,this.saveAppSettingsToStorage(t);const s=document.getElementById("appSettingsShowFileBrowser");s&&(s.checked=!1);const n=document.querySelector(".btn-file-viewer");n&&n.setAttribute("aria-expanded","false")},_isExternalPreviewPath(e,t){if(typeof e!="string"||!e.startsWith("/"))return!1;const s=this.sessions.get(t)?.workingDir;if(!s)return!1;const n=s.endsWith("/")?s:`${s}/`;return e!==s&&!e.startsWith(n)},async _registerExternalPreview(e,t){try{const s=await fetch(`/api/sessions/${t}/attachments`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:e,notify:!1})}),n=await s.json().catch(()=>null);if(s.ok&&n?.success&&n.data?.attachmentId)return{attachmentId:n.data.attachmentId,size:n.data.size||0};const i=n?.error||`Cannot open this file (HTTP ${s.status})`;return/unsupported/i.test(i)?{error:`Cannot preview .${(e.split(".").pop()||"").toLowerCase()} from outside the session workspace (images, video, audio, PDF, Office documents and text files only).`}:{error:i}}catch(s){return{error:s.message||"Cannot open this file"}}},async openFilePreview(e,t=this.activeSessionId,s=null){if(!t||!e)return;const n=this.$("filePreviewOverlay"),i=this.$("filePreviewTitle"),o=this.$("filePreviewBody"),r=this.$("filePreviewFooter");if(!n||!o)return;this._resetFilePreviewEdit(),this._stopFilePreviewMedia(),this.filePreviewDetachUrl="";const a=this.$("filePreviewDetachBtn");a&&(a.hidden=!0),n.classList.add("visible"),i.textContent=e,o.innerHTML='<div class="binary-message">Loading...</div>',r.textContent="";const l=(e.split(".").pop()||"").toLowerCase();let c="",u=0;if(!s&&this._isExternalPreviewPath(e,t)){const h=await this._registerExternalPreview(e,t);s=h.attachmentId||null,c=h.error||"",u=h.size||0}if(!s&&c){r.textContent="",o.innerHTML=`<div class="binary-message">${escapeHtml(c)}</div>`;return}const d=l==="docx"||l==="pptx";if(this.filePreviewDetachUrl=CodemanBase.url(s?`/api/sessions/${t}/attachments/${encodeURIComponent(s)}/${d?"preview":"raw"}`:d?`/api/sessions/${t}/file-preview?path=${encodeURIComponent(e)}`:`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`),a&&(a.hidden=!1),s){const h=CodemanBase.url(`/api/sessions/${t}/attachments/${encodeURIComponent(s)}`),p=new Set(["png","jpg","jpeg","gif","webp","bmp","svg"]),m=new Set(["mp4","webm","mov","m4v","ogv"]),g=new Set(["mp3","wav","ogg","oga","m4a","aac","flac","opus"]);if(r.textContent=u?`${this.formatFileSize(u)} \u2022 ${l}`:l.toUpperCase(),p.has(l))o.innerHTML=`<img src="${escapeHtml(`${h}/raw`)}" alt="${escapeHtml(e)}">`;else if(m.has(l))o.innerHTML=`<video src="${escapeHtml(`${h}/raw`)}" controls autoplay playsinline preload="metadata"></video>`;else if(g.has(l))o.innerHTML=`<audio src="${escapeHtml(`${h}/raw`)}" controls autoplay preload="metadata"></audio>`;else if(l==="pdf")o.innerHTML=`<iframe src="${escapeHtml(`${h}/raw`)}" title="${escapeHtml(e)}"></iframe>`;else if(l==="docx"||l==="pptx")o.innerHTML=`<iframe src="${escapeHtml(`${h}/preview`)}" title="${escapeHtml(e)}"></iframe>`;else try{const y=await fetch(`${h}/raw`,{headers:{Range:"bytes=0-524287"}});if(!y.ok)throw new Error("Failed to load attachment");const w=await y.text(),b=y.status===206&&w.length>=524288,$=w.split(`
|
|
240
240
|
`),f=$.length>500,S=f?$.slice(0,500).join(`
|
|
241
241
|
`):w;if(o.innerHTML=`<pre><code>${escapeHtml(S)}</code></pre>`,this.filePreviewContent=S,f||b){const T=f?"showing first 500 lines":"showing the start of the file";r.textContent=`${r.textContent} (${T})`}}catch(y){o.innerHTML=`<div class="binary-message">Error: ${escapeHtml(y.message)}</div>`}return}if(l==="docx"||l==="pptx"){r.textContent=l.toUpperCase();const h=CodemanBase.url(`/api/sessions/${t}/file-preview?path=${encodeURIComponent(e)}`);o.innerHTML=`<iframe src="${escapeHtml(h)}" title="${escapeHtml(e)}"></iframe>`;return}if(l==="pdf"){r.textContent="PDF";const h=CodemanBase.url(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`);o.innerHTML=`<iframe src="${escapeHtml(h)}" title="${escapeHtml(e)}"></iframe>`;return}if(l==="svg"){r.textContent="SVG";try{const h=await fetch(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`);if(!h.ok)throw new Error("Failed to load image");const p=URL.createObjectURL(new Blob([await h.text()],{type:"image/svg+xml"}));o.innerHTML=`<img src="${p}" alt="${escapeHtml(e)}">`;const m=o.querySelector("img");m&&(m.onload=()=>URL.revokeObjectURL(p))}catch(h){o.innerHTML=`<div class="binary-message">Error: ${escapeHtml(h.message)}</div>`}return}try{const h=await fetch(`/api/sessions/${t}/file-content?path=${encodeURIComponent(e)}&lines=500`);if(!h.ok)throw new Error("Failed to load file");const p=await h.json();if(!p.success)throw new Error(p.error||"Failed to load file");const m=p.data;if(m.type==="image")o.innerHTML=`<img src="${escapeHtml(CodemanBase.url(m.url))}" alt="${escapeHtml(e)}">`,r.textContent=`${this.formatFileSize(m.size)} \u2022 ${m.extension}`;else if(m.type==="video")o.innerHTML=`<video src="${escapeHtml(CodemanBase.url(m.url))}" controls autoplay playsinline preload="metadata"></video>`,r.textContent=`${this.formatFileSize(m.size)} \u2022 ${m.extension}`;else if(m.type==="audio")o.innerHTML=`<audio src="${escapeHtml(CodemanBase.url(m.url))}" controls autoplay preload="metadata"></audio>`,r.textContent=`${this.formatFileSize(m.size)} \u2022 ${m.extension}`;else if(m.type==="binary"){const g=CodemanBase.url(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}&download=true`);o.innerHTML=`<div class="binary-message">Binary file (${this.formatFileSize(m.size)})<br>Cannot preview<br><a href="${escapeHtml(g)}" download>Download</a></div>`,r.textContent=m.extension||"binary"}else{this.filePreviewContent=m.content,o.innerHTML=`<pre><code>${escapeHtml(m.content)}</code></pre>`;const g=m.truncated?` (showing 500/${m.totalLines} lines)`:"";if(r.textContent=`${m.totalLines} lines \u2022 ${this.formatFileSize(m.size)}${g}`,m.editable){this.filePreviewEditTarget={sessionId:t,filePath:e};const y=this.$("filePreviewEditBtn");y&&(y.hidden=!1)}}}catch(h){console.error("Failed to preview file:",h),o.innerHTML=`<div class="binary-message">Error: ${escapeHtml(h.message)}</div>`}},closeFilePreview(){if(this.filePreviewEdit?.dirty&&!confirm("Discard unsaved changes?"))return;this._resetFilePreviewEdit();const e=this.$("filePreviewOverlay");e&&e.classList.remove("visible"),this._stopFilePreviewMedia(),this.filePreviewContent="",this.filePreviewDetachUrl="";const t=this.$("filePreviewDetachBtn");t&&(t.hidden=!0)},detachFilePreview(){if(!this.filePreviewDetachUrl)return;const e=window.open(this.filePreviewDetachUrl,"_blank");if(!e){this.showToast("Pop-up blocked: allow pop-ups for this site to detach previews","error");return}e.opener=null,this.closeFilePreview()},_stopFilePreviewMedia(){const e=this.$("filePreviewBody");if(e){for(const t of e.querySelectorAll("video, audio"))try{t.pause(),t.removeAttribute("src"),t.load()}catch(s){console.warn("Failed to stop preview media:",s)}e.innerHTML=""}},_resetFilePreviewEdit(){this.filePreviewEdit=null,this.filePreviewEditTarget=null;const e=this.$("filePreviewEditBtn");e&&(e.hidden=!0);const t=this.$("filePreviewEditBar");t&&(t.hidden=!0);const s=this.$("filePreviewDirty");s&&(s.hidden=!0);const n=this.$("filePreviewSaveBtn");n&&(n.disabled=!0,n.textContent="Save")},async enterFilePreviewEdit(){const e=this.filePreviewEditTarget;if(!e||this.filePreviewEdit)return;const t=this.$("filePreviewBody"),s=this.$("filePreviewFooter");if(!t)return;let n;try{const a=await fetch(`/api/sessions/${e.sessionId}/file-content?path=${encodeURIComponent(e.filePath)}&edit=1`),l=await a.json().catch(()=>null);if(!l||l.success!==!0)throw new Error(l?.error||`Failed to load file for editing (HTTP ${a.status})`);n=l.data}catch(a){this.showToast(a.message,"error");return}this.filePreviewEdit={sessionId:e.sessionId,filePath:e.filePath,baseHash:n.hash,eol:n.eol,original:n.content,dirty:!1,saving:!1};const i=document.createElement("textarea");i.className="file-preview-editor",i.spellcheck=!1,i.setAttribute("autocapitalize","off"),i.setAttribute("autocorrect","off"),i.setAttribute("autocomplete","off"),i.wrap="off",i.value=n.content,i.addEventListener("input",()=>this._onFilePreviewEditInput()),t.innerHTML="",t.appendChild(i);const o=this.$("filePreviewEditBtn");o&&(o.hidden=!0);const r=this.$("filePreviewEditBar");if(r&&(r.hidden=!1),s){const a=n.eol==="crlf"?" \u2022 CRLF":"";s.textContent=`Editing \u2022 ${n.totalLines} lines \u2022 ${this.formatFileSize(n.size)}${a}`}},_onFilePreviewEditInput(){const e=this.filePreviewEdit;if(!e)return;const t=this.$("filePreviewBody")?.querySelector("textarea.file-preview-editor");if(!t)return;e.dirty=t.value!==e.original;const s=this.$("filePreviewDirty");s&&(s.hidden=!e.dirty);const n=this.$("filePreviewSaveBtn");n&&(n.disabled=!e.dirty||e.saving)},cancelFilePreviewEdit(){const e=this.filePreviewEdit;if(!e||e.dirty&&!confirm("Discard unsaved changes?"))return;const{sessionId:t,filePath:s}=e;this._resetFilePreviewEdit(),this.openFilePreview(s,t)},async saveFilePreviewEdit(e=!1){const t=this.filePreviewEdit;if(!t||t.saving)return;const s=this.$("filePreviewBody")?.querySelector("textarea.file-preview-editor");if(!s)return;t.saving=!0;const n=this.$("filePreviewSaveBtn");n&&(n.disabled=!0,n.textContent="Saving\u2026");const i=()=>{t.saving=!1,n&&(n.textContent="Save"),this._onFilePreviewEditInput()};let o=null,r=0;try{const c=await fetch(`/api/sessions/${t.sessionId}/file-content`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t.filePath,content:s.value,baseHash:t.baseHash,eol:t.eol??void 0,force:e||void 0})});r=c.status,o=await c.json().catch(()=>null)}catch(c){i(),this.showToast(`Save failed: ${c.message}`,"error");return}if(r===409||o?.errorCode==="CONFLICT"){i(),confirm(`File changed on disk since you loaded it.
|
|
242
|
-
OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFilePreviewEdit(!0);return}if(!o||o.success!==!0){i(),this.showToast(`Save failed: ${o?.error||`HTTP ${r}`}`,"error");return}const{sessionId:a,filePath:l}=t;this._resetFilePreviewEdit(),this.showToast("Saved","success"),this.openFilePreview(l,a)},_onAttachmentDetected(e){if(console.log("[Attachment Detected]",e),this.addAttachmentCard(e),e.sessionId){const t=this.attachmentHistoryCounts.get(e.sessionId)??this.sessions.get(e.sessionId)?.attachmentHistory?.length??0;this.attachmentHistoryCounts.set(e.sessionId,Math.min(t+1,100)),e.sessionId===this.activeSessionId&&(this.updateAttachmentHistoryBadge(),this.attachmentHistoryDrawerOpen&&this._debouncedCall("attachmentHistoryRefresh",()=>{this.attachmentHistoryDrawerOpen&&this.activeSessionId===e.sessionId&&this.loadAttachmentHistory(e.sessionId)},250))}},ensureAttachmentCardStack(){let e=this.attachmentCardStack||document.getElementById("attachmentCardStack");return e||(e=document.createElement("div"),e.id="attachmentCardStack",e.className="attachment-card-stack",document.body.appendChild(e)),this.attachmentCardStack=e,e},openAttachmentInNewTab(e,t,s=null){const n=CodemanBase.url(s?`/api/sessions/${e}/attachments/${encodeURIComponent(s)}/raw`:`/api/sessions/${e}/file-raw?path=${encodeURIComponent(t)}`);window.open(n,"_blank")},addAttachmentCard(e){const{sessionId:t,relativePath:s,fileName:n,timestamp:i,size:o,attachmentType:r,extension:a,attachmentId:l,rawUrl:c,previewUrl:u,thumbnailUrl:d}=e,h=s||n,p=l||`${t}-${i}-${n}`;if(this.attachmentCards.has(p)){this.attachmentCards.get(p).element.focus?.();return}if(this.attachmentCards.size>=10){const
|
|
242
|
+
OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFilePreviewEdit(!0);return}if(!o||o.success!==!0){i(),this.showToast(`Save failed: ${o?.error||`HTTP ${r}`}`,"error");return}const{sessionId:a,filePath:l}=t;this._resetFilePreviewEdit(),this.showToast("Saved","success"),this.openFilePreview(l,a)},_onAttachmentDetected(e){if(console.log("[Attachment Detected]",e),this.addAttachmentCard(e),e.sessionId){const t=this.attachmentHistoryCounts.get(e.sessionId)??this.sessions.get(e.sessionId)?.attachmentHistory?.length??0;this.attachmentHistoryCounts.set(e.sessionId,Math.min(t+1,100)),e.sessionId===this.activeSessionId&&(this.updateAttachmentHistoryBadge(),this.attachmentHistoryDrawerOpen&&this._debouncedCall("attachmentHistoryRefresh",()=>{this.attachmentHistoryDrawerOpen&&this.activeSessionId===e.sessionId&&this.loadAttachmentHistory(e.sessionId)},250))}},ensureAttachmentCardStack(){let e=this.attachmentCardStack||document.getElementById("attachmentCardStack");return e||(e=document.createElement("div"),e.id="attachmentCardStack",e.className="attachment-card-stack",document.body.appendChild(e)),this.attachmentCardStack=e,e},openAttachmentInNewTab(e,t,s=null){const n=CodemanBase.url(s?`/api/sessions/${e}/attachments/${encodeURIComponent(s)}/raw`:`/api/sessions/${e}/file-raw?path=${encodeURIComponent(t)}`);window.open(n,"_blank")},addAttachmentCard(e){const{sessionId:t,relativePath:s,fileName:n,timestamp:i,size:o,attachmentType:r,extension:a,attachmentId:l,rawUrl:c,previewUrl:u,thumbnailUrl:d}=e,h=s||n,p=l||`${t}-${i}-${n}`;if(this.attachmentCards.has(p)){this.attachmentCards.get(p).element.focus?.();return}if(this.attachmentCards.size>=10){const I=this.attachmentCards.keys().next().value;I&&this.closeAttachmentCard(I)}const g=this.ensureAttachmentCardStack(),w=this.sessions.get(t)?.name||t.substring(0,8),b=CodemanBase.url(c||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/raw`:`/api/sessions/${t}/file-raw?path=${encodeURIComponent(h)}`)),$=CodemanBase.url(u||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/preview`:null)),f=CodemanBase.url(d||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/thumbnail`:`/api/sessions/${t}/file-thumbnail?path=${encodeURIComponent(h)}`)),S=l?`${b}?download=true`:`${b}&download=true`,T=(a||r||"file").toUpperCase(),v=document.createElement("article");v.className=`attachment-card attachment-${escapeHtml(r||"file")}`,v.tabIndex=0,v.dataset.attachmentId=p,v.dataset.previewUrl=$||"",v.innerHTML=`
|
|
243
243
|
<div class="attachment-thumbnail">
|
|
244
244
|
${f?`<img class="attachment-thumbnail-img" src="${escapeHtml(f)}" alt="">`:""}
|
|
245
245
|
<div class="attachment-thumbnail-fallback ${f?"":"visible"}">${escapeHtml(T)}</div>
|
|
@@ -257,7 +257,7 @@ OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFi
|
|
|
257
257
|
</div>
|
|
258
258
|
</div>
|
|
259
259
|
<button type="button" class="attachment-close-btn" title="Dismiss">×</button>
|
|
260
|
-
`;const
|
|
260
|
+
`;const C=v.querySelector(".attachment-thumbnail-img");C&&(C.onerror=()=>{C.remove(),v.querySelector(".attachment-thumbnail-fallback")?.classList.add("visible")}),v.querySelector(".attachment-preview-btn")?.addEventListener("click",()=>{this.openFilePreview(h,t,l||null)}),v.querySelector(".attachment-open-btn")?.addEventListener("click",()=>{this.openAttachmentInNewTab(t,h,l||null)}),v.querySelector(".attachment-close-btn")?.addEventListener("click",()=>{this.closeAttachmentCard(p)}),g.prepend(v),this.attachmentCards.set(p,{element:v,sessionId:t,filePath:h}),this._refreshAttachmentClearAll()},_refreshAttachmentClearAll(){const e=this.attachmentCardStack;if(!e)return;let t=e.querySelector(".attachment-clear-all");if(this.attachmentCards.size<2){t&&(t.hidden=!0);return}t||(t=document.createElement("button"),t.type="button",t.className="attachment-clear-all",t.textContent="Clear all",t.title="Dismiss all attachment cards",t.addEventListener("click",()=>this.closeAllAttachmentCards()),e.prepend(t)),t.hidden=!1},closeAttachmentCard(e){const t=this.attachmentCards.get(e);t&&(t.element.remove(),this.attachmentCards.delete(e),this.attachmentCardStack&&this.attachmentCards.size===0?(this.attachmentCardStack.remove(),this.attachmentCardStack=null):this._refreshAttachmentClearAll())},closeAllAttachmentCards(){for(const e of[...this.attachmentCards.keys()])this.closeAttachmentCard(e)},closeSessionAttachmentCards(e){const t=[];for(const[s,n]of this.attachmentCards)n.sessionId===e&&t.push(s);for(const s of t)this.closeAttachmentCard(s)},updateAttachmentHistoryBadge(e=null){const t=document.getElementById("attachmentHistoryBadge"),s=document.getElementById("attachmentsHistoryBtn"),n=this.activeSessionId,i=e??(n&&this.attachmentHistoryCounts.get(n)||0);t&&(t.textContent=i>99?"99+":String(i),t.style.display=i>0?"":"none"),s&&(s.classList.toggle("active",this.attachmentHistoryDrawerOpen),s.setAttribute("aria-expanded",this.attachmentHistoryDrawerOpen?"true":"false"))},ensureAttachmentHistoryDrawer(){let e=document.getElementById("attachmentHistoryDrawer");return e||(e=document.createElement("aside"),e.id="attachmentHistoryDrawer",e.className="attachment-history-drawer",e.setAttribute("aria-label","Attachment history"),e.innerHTML=`
|
|
261
261
|
<div class="attachment-history-header">
|
|
262
262
|
<div>
|
|
263
263
|
<div class="attachment-history-title">Attachments</div>
|
|
@@ -356,4 +356,4 @@ OK overwrites it with your version; Cancel keeps your draft open.`)&&this.saveFi
|
|
|
356
356
|
${o.status!=="completed"?`<button class="btn-toolbar btn-sm btn-danger" onclick="app.killSubagent(${escapeHtml(JSON.stringify(o.agentId))})" title="Kill agent">Kill</button>`:""}
|
|
357
357
|
</div>
|
|
358
358
|
</div>
|
|
359
|
-
`}e.innerHTML=i},async killMuxSession(e){if(confirm("Kill this mux session?")){try{await this.closeSession(e,!0)}catch{try{await fetch(`/api/mux-sessions/${e}`,{method:"DELETE"})}catch{}this.showToast("Tmux session killed","success")}this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e),this.renderMuxSessions()}},async reconcileMuxSessions(){try{const t=await(await fetch("/api/mux-sessions/reconcile",{method:"POST"})).json();t.data?.dead&&t.data.dead.length>0?(this.showToast(`Found ${t.data.dead.length} dead mux session(s)`,"warning"),await this.loadMuxSessions()):this.showToast("All mux sessions are alive","success")}catch{this.showToast("Failed to reconcile mux sessions","error")}},toggleNotifications(){this.notificationManager?.toggleDrawer()},async launchMultiMonitor(){try{const e=await fetch("/api/system/span-displays",{method:"POST"}),t=await e.json().catch(()=>({}));e.ok&&t.success?this.showToast("Opening Codeman across all displays\u2026","success"):this.showToast(t.error||"Could not open spanning window","error")}catch(e){this.showToast("Could not open spanning window: "+(e?.message||e),"error")}},toast(e,t="info"){return this.showToast(e,t)},showToast(e,t="info",s={}){const{duration:n=3e3,action:i}=s,o=document.createElement("div");o.className=`toast toast-${t}`;const r=document.createElement("span");if(r.textContent=e,o.appendChild(r),i){const
|
|
359
|
+
`}e.innerHTML=i},async killMuxSession(e){if(confirm("Kill this mux session?")){try{await this.closeSession(e,!0)}catch{try{await fetch(`/api/mux-sessions/${e}`,{method:"DELETE"})}catch{}this.showToast("Tmux session killed","success")}this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e),this.renderMuxSessions()}},async reconcileMuxSessions(){try{const t=await(await fetch("/api/mux-sessions/reconcile",{method:"POST"})).json();t.data?.dead&&t.data.dead.length>0?(this.showToast(`Found ${t.data.dead.length} dead mux session(s)`,"warning"),await this.loadMuxSessions()):this.showToast("All mux sessions are alive","success")}catch{this.showToast("Failed to reconcile mux sessions","error")}},toggleNotifications(){this.notificationManager?.toggleDrawer()},async launchMultiMonitor(){try{const e=await fetch("/api/system/span-displays",{method:"POST"}),t=await e.json().catch(()=>({}));e.ok&&t.success?this.showToast("Opening Codeman across all displays\u2026","success"):this.showToast(t.error||"Could not open spanning window","error")}catch(e){this.showToast("Could not open spanning window: "+(e?.message||e),"error")}},toast(e,t="info"){return this.showToast(e,t)},showToast(e,t="info",s={}){const{duration:n=3e3,action:i}=s,o=document.createElement("div");o.className=`toast toast-${t}`;const r=document.createElement("span");if(r.className="toast-message",r.textContent=e,o.appendChild(r),i){const u=document.createElement("button");u.textContent=i.label,u.style.cssText="margin-left:12px;padding:2px 10px;background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.3);border-radius:3px;color:inherit;cursor:pointer;font-size:12px",u.onclick=d=>{d.stopPropagation(),i.onClick(),o.remove()},o.appendChild(u)}let a=null;const l=()=>{a&&clearTimeout(a),o.classList.remove("show"),setTimeout(()=>o.remove(),200)},c=document.createElement("button");return c.className="toast-close",c.textContent="\xD7",c.setAttribute("aria-label","Dismiss"),c.onclick=u=>{u.stopPropagation(),l()},o.appendChild(c),this._toastContainer||(this._toastContainer=document.querySelector(".toast-container"),this._toastContainer||(this._toastContainer=document.createElement("div"),this._toastContainer.className="toast-container",document.body.appendChild(this._toastContainer))),this._toastContainer.appendChild(o),requestAnimationFrame(()=>o.classList.add("show")),n>0&&(a=setTimeout(l,n)),{dismiss:l,setMessage:u=>{r.textContent=u}}},_showCenterStatus(e,t={}){const{type:s="info",onCancel:n}=t;let i=document.getElementById("customModelCenterStatus");i||(i=document.createElement("div"),i.id="customModelCenterStatus",document.body.appendChild(i)),i._hideTimer&&(clearTimeout(i._hideTimer),i._hideTimer=null),i.className=`center-status-banner center-status-${s}`,i.innerHTML="";const o=()=>{i.classList.remove("show"),i._hideTimer=setTimeout(()=>{i.hidden=!0,i._hideTimer=null},200)};if(s!=="error"){const a=document.createElement("span");a.className="center-status-spinner",a.setAttribute("aria-hidden","true"),i.appendChild(a)}const r=document.createElement("span");if(r.className="center-status-text",r.textContent=e,i.appendChild(r),s==="error"){const a=document.createElement("button");a.className="center-status-close",a.textContent="\xD7",a.setAttribute("aria-label","Dismiss"),a.onclick=l=>{l.stopPropagation(),o()},i.appendChild(a)}else if(n){const a=document.createElement("button");a.className="center-status-cancel",a.textContent="Cancel",a.onclick=l=>{l.stopPropagation(),n()},i.appendChild(a)}return i.hidden=!1,requestAnimationFrame(()=>i.classList.add("show")),{dismiss:o,setMessage:a=>{const l=i.querySelector(".center-status-text");l&&(l.textContent=a)}}},startSystemStatsPolling(){this.stopSystemStatsPolling(),this.fetchSystemStats(),this.systemStatsInterval=setInterval(()=>{this.fetchSystemStats()},2e3)},stopSystemStatsPolling(){this.systemStatsInterval&&(clearInterval(this.systemStatsInterval),this.systemStatsInterval=null)},async fetchSystemStats(){const e=document.getElementById("headerSystemStats");if(!(!e||e.style.display==="none"))try{const s=await(await fetch("/api/system/stats")).json();this.updateSystemStatsDisplay(s.data)}catch{}},updateSystemStatsDisplay(e){const t=this.$("statCpu"),s=this.$("statCpuBar"),n=this.$("statMem"),i=this.$("statMemBar");if(t&&s&&(t.textContent=`${e.cpu}%`,s.style.width=`${Math.min(100,e.cpu)}%`,s.classList.remove("medium","high"),t.classList.remove("high"),e.cpu>80?(s.classList.add("high"),t.classList.add("high")):e.cpu>50&&s.classList.add("medium")),n&&i){const o=(e.memory.usedMB/1024).toFixed(1);n.textContent=`${o}G`,i.style.width=`${Math.min(100,e.memory.percent)}%`,i.classList.remove("medium","high"),n.classList.remove("high"),e.memory.percent>80?(i.classList.add("high"),n.classList.add("high")):e.memory.percent>50&&i.classList.add("medium")}},async _onClipboardWrite(e){const t=e?.text;if(typeof t=="string")try{await navigator.clipboard.writeText(t),this.showToast(`Copied to clipboard (${t.length} chars)`,"success")}catch{this._showClipboardFallback(t)}},_showClipboardFallback(e){const t=document.createElement("div");t.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:10000;display:flex;align-items:center;justify-content:center";const s=document.createElement("div");s.style.cssText="background:#1e1e2e;border:1px solid #444;border-radius:8px;padding:16px;max-width:600px;width:90%;max-height:60vh;display:flex;flex-direction:column;gap:12px";const n=document.createElement("div");n.style.cssText="display:flex;justify-content:space-between;align-items:center";const i=document.createElement("span");i.style.cssText="color:#cdd6f4;font-weight:600",i.textContent="Clipboard (browser blocked auto-copy)";const o=document.createElement("button");o.style.cssText="background:none;border:none;color:#cdd6f4;font-size:18px;cursor:pointer",o.textContent="\xD7",n.appendChild(i),n.appendChild(o);const r=document.createElement("textarea");r.readOnly=!0,r.style.cssText="background:#181825;color:#cdd6f4;border:1px solid #555;border-radius:4px;padding:8px;font-family:monospace;font-size:13px;resize:none;height:200px;width:100%",r.value=e;const a=document.createElement("button");a.style.cssText="background:#89b4fa;color:#1e1e2e;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-weight:600",a.textContent="Copy to Clipboard",s.appendChild(n),s.appendChild(r),s.appendChild(a),t.appendChild(s),document.body.appendChild(t),a.onclick=async()=>{try{await navigator.clipboard.writeText(e),this.showToast("Copied to clipboard","success"),t.remove()}catch{r.select(),document.execCommand("copy"),this.showToast("Copied (fallback)","success"),t.remove()}};const l=()=>t.remove();o.onclick=l,t.onclick=c=>{c.target===t&&l()}}});
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|