aicodeman 1.48.0 → 1.49.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/README.md +12 -3
- package/dist/config/cli-registry/schema.d.ts +1 -0
- package/dist/config/cli-registry/schema.d.ts.map +1 -1
- package/dist/config/cli-registry/schema.js +5 -1
- 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 +71 -5
- package/dist/config/cli-registry/stock.js.map +1 -1
- package/dist/config/cli-registry/types.d.ts +4 -4
- package/dist/config/cli-registry/types.d.ts.map +1 -1
- package/dist/config/foreign-tmux.d.ts +48 -0
- package/dist/config/foreign-tmux.d.ts.map +1 -0
- package/dist/config/foreign-tmux.js +48 -0
- package/dist/config/foreign-tmux.js.map +1 -0
- package/dist/custom-model-injection-apply.d.ts +4 -2
- package/dist/custom-model-injection-apply.d.ts.map +1 -1
- package/dist/custom-model-injection-apply.js +35 -21
- package/dist/custom-model-injection-apply.js.map +1 -1
- package/dist/docker-hosts.d.ts +8 -1
- package/dist/docker-hosts.d.ts.map +1 -1
- package/dist/docker-hosts.js +5 -5
- package/dist/docker-hosts.js.map +1 -1
- package/dist/foreign-tmux-discovery.d.ts +140 -0
- package/dist/foreign-tmux-discovery.d.ts.map +1 -0
- package/dist/foreign-tmux-discovery.js +366 -0
- package/dist/foreign-tmux-discovery.js.map +1 -0
- package/dist/foreign-tmux.d.ts +381 -0
- package/dist/foreign-tmux.d.ts.map +1 -0
- package/dist/foreign-tmux.js +775 -0
- package/dist/foreign-tmux.js.map +1 -0
- package/dist/git-fetch-scheduler.d.ts +2 -0
- package/dist/git-fetch-scheduler.d.ts.map +1 -1
- package/dist/git-fetch-scheduler.js +1 -1
- package/dist/git-fetch-scheduler.js.map +1 -1
- package/dist/git-fetch.d.ts +1 -1
- package/dist/git-fetch.d.ts.map +1 -1
- package/dist/git-workspace-status.d.ts +2 -2
- package/dist/git-workspace-status.d.ts.map +1 -1
- package/dist/hooks-config.d.ts +2 -1
- package/dist/hooks-config.d.ts.map +1 -1
- package/dist/hooks-config.js +2 -1
- package/dist/hooks-config.js.map +1 -1
- package/dist/live-worktree.d.ts +53 -0
- package/dist/live-worktree.d.ts.map +1 -0
- package/dist/live-worktree.js +97 -0
- package/dist/live-worktree.js.map +1 -0
- package/dist/mux-interface.d.ts +12 -1
- package/dist/mux-interface.d.ts.map +1 -1
- package/dist/reboot-restore.d.ts +1 -1
- package/dist/reboot-restore.d.ts.map +1 -1
- package/dist/reboot-restore.js +9 -0
- package/dist/reboot-restore.js.map +1 -1
- package/dist/remote-files.d.ts +150 -5
- package/dist/remote-files.d.ts.map +1 -1
- package/dist/remote-files.js +505 -7
- package/dist/remote-files.js.map +1 -1
- package/dist/remote-hosts.d.ts +15 -9
- package/dist/remote-hosts.d.ts.map +1 -1
- package/dist/remote-hosts.js +42 -20
- package/dist/remote-hosts.js.map +1 -1
- package/dist/session-cli-registry-bridge.d.ts.map +1 -1
- package/dist/session-cli-registry-bridge.js +19 -8
- package/dist/session-cli-registry-bridge.js.map +1 -1
- package/dist/session-env-clamp.d.ts +1 -1
- package/dist/session-env-clamp.d.ts.map +1 -1
- package/dist/session-env-clamp.js +4 -3
- package/dist/session-env-clamp.js.map +1 -1
- package/dist/session.d.ts +91 -21
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +190 -33
- package/dist/session.js.map +1 -1
- package/dist/tmux-manager.d.ts +74 -12
- package/dist/tmux-manager.d.ts.map +1 -1
- package/dist/tmux-manager.js +256 -41
- package/dist/tmux-manager.js.map +1 -1
- package/dist/types/foreign-tmux.d.ts +101 -0
- package/dist/types/foreign-tmux.d.ts.map +1 -0
- package/dist/types/foreign-tmux.js +27 -0
- package/dist/types/foreign-tmux.js.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/session.d.ts +106 -2
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js.map +1 -1
- package/dist/types/update.d.ts +4 -1
- package/dist/types/update.d.ts.map +1 -1
- package/dist/web/edit-history-sync.d.ts +27 -7
- package/dist/web/edit-history-sync.d.ts.map +1 -1
- package/dist/web/edit-history-sync.js +35 -19
- package/dist/web/edit-history-sync.js.map +1 -1
- package/dist/web/launch-defaults.d.ts +1 -1
- package/dist/web/launch-defaults.js +2 -2
- package/dist/web/launch-defaults.js.map +1 -1
- package/dist/web/linked-cases-writer.d.ts +43 -0
- package/dist/web/linked-cases-writer.d.ts.map +1 -0
- package/dist/web/linked-cases-writer.js +107 -0
- package/dist/web/linked-cases-writer.js.map +1 -0
- package/dist/web/paste-image-gc.d.ts +4 -1
- package/dist/web/paste-image-gc.d.ts.map +1 -1
- package/dist/web/paste-image-gc.js +4 -2
- package/dist/web/paste-image-gc.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.963b5ba8.js → app.9ea37070.js} +6 -6
- package/dist/web/public/app.9ea37070.js.br +0 -0
- package/dist/web/public/app.9ea37070.js.gz +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/constants.782170e1.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/edit-history-ui.js +27 -14
- package/dist/web/public/edit-history-ui.js.br +0 -0
- package/dist/web/public/edit-history-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/foreign-sessions.js +476 -0
- package/dist/web/public/foreign-sessions.js.br +0 -0
- package/dist/web/public/foreign-sessions.js.gz +0 -0
- package/dist/web/public/git-status-ui.js +5 -3
- package/dist/web/public/git-status-ui.js.br +0 -0
- package/dist/web/public/git-status-ui.js.gz +0 -0
- package/dist/web/public/header-divider.eb2d2463.js.gz +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/host-wake-ui.js.gz +0 -0
- package/dist/web/public/i18n.a5e82c95.js +2 -0
- package/dist/web/public/i18n.a5e82c95.js.br +0 -0
- package/dist/web/public/i18n.a5e82c95.js.gz +0 -0
- package/dist/web/public/image-input.a5d0f8f3.js.gz +0 -0
- package/dist/web/public/index.html +36 -17
- 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.d4ec5957.js → keyboard-accessory.b941676c.js} +3 -1
- package/dist/web/public/keyboard-accessory.b941676c.js.br +0 -0
- package/dist/web/public/{keyboard-accessory.d4ec5957.js.gz → keyboard-accessory.b941676c.js.gz} +0 -0
- package/dist/web/public/mobile-handlers.f7c3f692.js.gz +0 -0
- package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
- package/dist/web/public/mobile-overview.js +10 -0
- package/dist/web/public/mobile-overview.js.br +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/{mobile.5ef2ce85.css → mobile.67c8eb5b.css} +1 -1
- package/dist/web/public/mobile.67c8eb5b.css.br +0 -0
- package/dist/web/public/{mobile.5ef2ce85.css.gz → mobile.67c8eb5b.css.gz} +0 -0
- package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/{panels-ui.b100727d.js → panels-ui.8bcd4473.js} +4 -4
- package/dist/web/public/panels-ui.8bcd4473.js.br +0 -0
- package/dist/web/public/panels-ui.8bcd4473.js.gz +0 -0
- package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
- package/dist/web/public/ralph-wizard.b6c0dd19.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.304ba0d4.js.gz +0 -0
- package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/{session-ui.5ac82f2c.js → session-ui.a7c8c095.js} +11 -11
- package/dist/web/public/session-ui.a7c8c095.js.br +0 -0
- package/dist/web/public/session-ui.a7c8c095.js.gz +0 -0
- package/dist/web/public/{settings-ui.d1d4fb99.js → settings-ui.18f92052.js} +3 -3
- package/dist/web/public/settings-ui.18f92052.js.br +0 -0
- package/dist/web/public/settings-ui.18f92052.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview.75c751de.js.gz +0 -0
- package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
- package/dist/web/public/{styles.77dc538f.css → styles.6a718331.css} +1 -1
- package/dist/web/public/styles.6a718331.css.br +0 -0
- package/dist/web/public/{styles.77dc538f.css.gz → styles.6a718331.css.gz} +0 -0
- package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
- package/dist/web/public/sw.js +2 -2
- package/dist/web/public/sw.js.br +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/tab-layout-browser.2d6189f7.js.gz +0 -0
- package/dist/web/public/tab-rail-resize.b5cdceaf.js.gz +0 -0
- package/dist/web/public/terminal-keycode229-recovery.98843069.js.gz +0 -0
- package/dist/web/public/terminal-split.js.gz +0 -0
- package/dist/web/public/terminal-tile.js +2 -2
- package/dist/web/public/terminal-tile.js.br +0 -0
- package/dist/web/public/terminal-tile.js.gz +0 -0
- package/dist/web/public/{terminal-ui.d7c75ce8.js → terminal-ui.a7883640.js} +2 -2
- package/dist/web/public/terminal-ui.a7883640.js.br +0 -0
- package/dist/web/public/terminal-ui.a7883640.js.gz +0 -0
- package/dist/web/public/tile-grid.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/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
- package/dist/web/public/vendor/fflate.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.276b11d9.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.1be42307.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.2342c37b.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/public/whats-new.json +9 -9
- package/dist/web/routes/case-routes.d.ts.map +1 -1
- package/dist/web/routes/case-routes.js +72 -53
- package/dist/web/routes/case-routes.js.map +1 -1
- package/dist/web/routes/discord-routes.js +1 -1
- package/dist/web/routes/discord-routes.js.map +1 -1
- package/dist/web/routes/edit-history-routes.d.ts +2 -2
- package/dist/web/routes/edit-history-routes.d.ts.map +1 -1
- package/dist/web/routes/edit-history-routes.js +4 -3
- package/dist/web/routes/edit-history-routes.js.map +1 -1
- package/dist/web/routes/file-routes.d.ts.map +1 -1
- package/dist/web/routes/file-routes.js +213 -102
- package/dist/web/routes/file-routes.js.map +1 -1
- package/dist/web/routes/git-status-routes.d.ts.map +1 -1
- package/dist/web/routes/git-status-routes.js +7 -2
- package/dist/web/routes/git-status-routes.js.map +1 -1
- package/dist/web/routes/mux-routes.d.ts +10 -3
- package/dist/web/routes/mux-routes.d.ts.map +1 -1
- package/dist/web/routes/mux-routes.js +59 -1
- package/dist/web/routes/mux-routes.js.map +1 -1
- package/dist/web/routes/ralph-routes.d.ts.map +1 -1
- package/dist/web/routes/ralph-routes.js +22 -0
- package/dist/web/routes/ralph-routes.js.map +1 -1
- package/dist/web/routes/readmymind-routes.d.ts.map +1 -1
- package/dist/web/routes/readmymind-routes.js +3 -2
- package/dist/web/routes/readmymind-routes.js.map +1 -1
- package/dist/web/routes/respawn-routes.d.ts.map +1 -1
- package/dist/web/routes/respawn-routes.js +24 -0
- package/dist/web/routes/respawn-routes.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts +11 -8
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +262 -29
- package/dist/web/routes/session-routes.js.map +1 -1
- package/dist/web/routes/system-routes.d.ts.map +1 -1
- package/dist/web/routes/system-routes.js +3 -2
- package/dist/web/routes/system-routes.js.map +1 -1
- package/dist/web/schemas.d.ts +24 -1
- package/dist/web/schemas.d.ts.map +1 -1
- package/dist/web/schemas.js +34 -9
- package/dist/web/schemas.js.map +1 -1
- package/dist/web/self-update.d.ts +9 -0
- package/dist/web/self-update.d.ts.map +1 -1
- package/dist/web/self-update.js +19 -3
- package/dist/web/self-update.js.map +1 -1
- package/dist/web/server.d.ts +16 -3
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +84 -24
- package/dist/web/server.js.map +1 -1
- package/dist/web/session-wait-registry.d.ts +13 -0
- package/dist/web/session-wait-registry.d.ts.map +1 -1
- package/dist/web/session-wait-registry.js +16 -8
- package/dist/web/session-wait-registry.js.map +1 -1
- package/package.json +2 -2
- package/skills/codeman/SKILL.md +20 -4
- package/dist/web/public/app.963b5ba8.js.br +0 -0
- package/dist/web/public/app.963b5ba8.js.gz +0 -0
- package/dist/web/public/i18n.33f930d7.js +0 -2
- package/dist/web/public/i18n.33f930d7.js.br +0 -0
- package/dist/web/public/i18n.33f930d7.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.d4ec5957.js.br +0 -0
- package/dist/web/public/mobile.5ef2ce85.css.br +0 -0
- package/dist/web/public/panels-ui.b100727d.js.br +0 -0
- package/dist/web/public/panels-ui.b100727d.js.gz +0 -0
- package/dist/web/public/session-ui.5ac82f2c.js.br +0 -0
- package/dist/web/public/session-ui.5ac82f2c.js.gz +0 -0
- package/dist/web/public/settings-ui.d1d4fb99.js.br +0 -0
- package/dist/web/public/settings-ui.d1d4fb99.js.gz +0 -0
- package/dist/web/public/styles.77dc538f.css.br +0 -0
- package/dist/web/public/terminal-ui.d7c75ce8.js.br +0 -0
- package/dist/web/public/terminal-ui.d7c75ce8.js.gz +0 -0
package/dist/web/server.js
CHANGED
|
@@ -34,6 +34,7 @@ import fastifyWebsocket from '@fastify/websocket';
|
|
|
34
34
|
import fastifyMultipart from '@fastify/multipart';
|
|
35
35
|
import { pasteImageDirInUseByOtherSession, startPasteImageGc, uploadDirs } from './paste-image-gc.js';
|
|
36
36
|
import { CLEAN_EXIT_CLOSE_REASON, shouldCloseCleanlyExitedSession } from '../pane-exit-sweep.js';
|
|
37
|
+
import { findLiveWorktree } from '../live-worktree.js';
|
|
37
38
|
import { join, dirname } from 'node:path';
|
|
38
39
|
import { fileURLToPath } from 'node:url';
|
|
39
40
|
import { existsSync, mkdirSync, readFileSync, chmodSync, statSync } from 'node:fs';
|
|
@@ -80,6 +81,7 @@ import { createRequire } from 'node:module';
|
|
|
80
81
|
import { RunSummaryTracker } from '../run-summary.js';
|
|
81
82
|
import { OrchestratorLoop } from '../orchestrator-loop.js';
|
|
82
83
|
import { getLifecycleLog } from '../session-lifecycle-log.js';
|
|
84
|
+
import { clampEnvOverridesForOwner } from '../session-env-clamp.js';
|
|
83
85
|
import { applyWorkspaceHooks, pruneAgentSessionPreambles, readGitFetchSettings, readKeepWarmSettingsOrThrow, readPlanUsageTelemetryEnabled, removeAgentSessionPreamble, } from '../hooks-config.js';
|
|
84
86
|
import { PushSubscriptionStore } from '../push-store.js';
|
|
85
87
|
import webpush from 'web-push';
|
|
@@ -99,11 +101,14 @@ import { fetchWorkspaceOnce } from '../git-fetch.js';
|
|
|
99
101
|
import { GitFetchScheduler } from '../git-fetch-scheduler.js';
|
|
100
102
|
import { probePathKind } from '../utils/bounded-path-probe.js';
|
|
101
103
|
import { defaultDockerWorkspaces } from './routes/git-status-routes.js';
|
|
104
|
+
import { guardSessionConfigDirHome } from './routes/session-routes.js';
|
|
102
105
|
import { composerIsEmpty, plainFrame } from '../session-submit-verifier.js';
|
|
103
106
|
import { detectUsageLimitPause } from '../usage-limit-patterns.js';
|
|
104
|
-
import { EditHistorySync } from './edit-history-sync.js';
|
|
107
|
+
import { EditHistorySync, remoteTranscriptIds } from './edit-history-sync.js';
|
|
105
108
|
import { EditHistoryStore } from '../edit-history-store.js';
|
|
106
109
|
import { probeLocalPaths, readClaudeEditSources, resolveClaudeTranscript } from '../edit-history-local-source.js';
|
|
110
|
+
import { remoteLocateClaudeTranscript, remoteProbePaths, remoteReadClaudeEditSources } from '../remote-files.js';
|
|
111
|
+
import { remoteTmuxLocation } from '../tmux-manager.js';
|
|
107
112
|
import { stopDeepSeekWeb } from '../deepseek-web-server.js';
|
|
108
113
|
import { wireRespawnListeners, setupTimedRespawn, restoreRespawnController, saveRespawnConfig, } from './respawn-event-wiring.js';
|
|
109
114
|
import { reconcileUpdateOnBoot } from './self-update.js';
|
|
@@ -211,14 +216,21 @@ export class WebServer extends EventEmitter {
|
|
|
211
216
|
app;
|
|
212
217
|
sessions = new Map();
|
|
213
218
|
/**
|
|
214
|
-
* The edit history panel's reader (edit-history-sync.ts). Reads only when the panel asks
|
|
215
|
-
*
|
|
216
|
-
* before the first hook after a restart, a lookup under the session's claude
|
|
219
|
+
* The edit history panel's reader (edit-history-sync.ts). Reads only when the panel asks.
|
|
220
|
+
* A local session's main transcript is the one the transcript watcher follows (hook-reported
|
|
221
|
+
* path), or, before the first hook after a restart, a lookup under the session's claude
|
|
222
|
+
* config dir. A remote session sends no hooks: its host is asked over ssh for the transcript
|
|
223
|
+
* the pane's claude writes, else the stored conversation's (`remoteTranscriptIds`), and is
|
|
224
|
+
* never woken for it (remote-files.ts).
|
|
217
225
|
*/
|
|
218
226
|
editHistorySync = new EditHistorySync({
|
|
219
|
-
transcriptPath: (session) =>
|
|
220
|
-
|
|
221
|
-
|
|
227
|
+
transcriptPath: (session, storedTranscriptId) => session.remote
|
|
228
|
+
? remoteLocateClaudeTranscript(session.remote, remoteTranscriptIds(session, storedTranscriptId), remoteTmuxLocation(session.remote, session.id))
|
|
229
|
+
: resolveClaudeTranscript(this.transcriptWatchers.get(session.id)?.getPath(), [session.claudeSessionId || session.id, session.id], session.claudeConfigDir),
|
|
230
|
+
readSources: (session, mainPath, requests, budget, opts) => session.remote
|
|
231
|
+
? remoteReadClaudeEditSources(session.remote, mainPath, requests, budget, opts)
|
|
232
|
+
: readClaudeEditSources(mainPath, requests, budget, opts),
|
|
233
|
+
probe: (session, paths) => (session.remote ? remoteProbePaths(session.remote, paths) : probeLocalPaths(paths)),
|
|
222
234
|
loadStore: (sessionId) => EditHistoryStore.load(sessionId),
|
|
223
235
|
deleteStore: (sessionId) => EditHistoryStore.delete(sessionId),
|
|
224
236
|
sweepStores: (keep) => EditHistoryStore.sweep(keep),
|
|
@@ -387,9 +399,10 @@ export class WebServer extends EventEmitter {
|
|
|
387
399
|
agentExited: (id) => !!this.sessions.get(id)?.paneExit,
|
|
388
400
|
awaitingChoice: (id) => approvalInbox.listPending().some((item) => item.sessionId === id && item.kind !== 'idle'),
|
|
389
401
|
// Remote (ssh) sessions keep their folder on another host, so received files have nowhere local to go.
|
|
402
|
+
// An adopted session's folder is the neutral wrapper folder, which its agent need not be able to read.
|
|
390
403
|
sessionDir: (sessionId) => {
|
|
391
404
|
const session = this.sessions.get(sessionId);
|
|
392
|
-
return session && !session.remote ? session.workingDir : undefined;
|
|
405
|
+
return session && !session.remote && !session.isAdopted ? session.workingDir : undefined;
|
|
393
406
|
},
|
|
394
407
|
});
|
|
395
408
|
teamWatcher = new TeamWatcher();
|
|
@@ -1286,7 +1299,7 @@ export class WebServer extends EventEmitter {
|
|
|
1286
1299
|
* endpoint is gone or the CLI is unregistered: the bookkeeping is still restored so
|
|
1287
1300
|
* the selection can be cleared, and the pane keeps running on tmux's retained env.
|
|
1288
1301
|
*/
|
|
1289
|
-
async _rebuildCustomModelEnv(session, saved) {
|
|
1302
|
+
async _rebuildCustomModelEnv(session, saved, ownEnv = {}) {
|
|
1290
1303
|
const entry = getCli(session.mode);
|
|
1291
1304
|
if (!entry)
|
|
1292
1305
|
return undefined;
|
|
@@ -1296,14 +1309,14 @@ export class WebServer extends EventEmitter {
|
|
|
1296
1309
|
return undefined;
|
|
1297
1310
|
}
|
|
1298
1311
|
try {
|
|
1299
|
-
// Boot recovery omits
|
|
1300
|
-
//
|
|
1301
|
-
//
|
|
1302
|
-
//
|
|
1303
|
-
//
|
|
1304
|
-
//
|
|
1305
|
-
// `DSH_HOME` or
|
|
1306
|
-
return applyCustomModelInjection(entry, endpoint, saved.modelId, session.id, resolveCustomModelContextLength(endpoint, saved.modelId));
|
|
1312
|
+
// Boot recovery omits `workingDir` (no reason to re-answer a trust dialog that already
|
|
1313
|
+
// fired once). The real-home lookup reads the record's own values, since the session's
|
|
1314
|
+
// overrides hold what the previous run injected. `linkRealHomeEntry()` keeps what is
|
|
1315
|
+
// there, so this only decides an entry that is missing, which an own home skips when it
|
|
1316
|
+
// does not hold one. With no own home, or one that does not answer (probed under the
|
|
1317
|
+
// bulk cap, this walks every saved session), a missing entry links from the SERVER's
|
|
1318
|
+
// `DSH_HOME` or `CLAUDE_CONFIG_DIR`, or their defaults (~/.dsh, ~/.claude).
|
|
1319
|
+
return applyCustomModelInjection(entry, endpoint, saved.modelId, session.id, resolveCustomModelContextLength(endpoint, saved.modelId), undefined, await guardSessionConfigDirHome(entry, (envVar) => ownEnv[envVar], {}));
|
|
1307
1320
|
}
|
|
1308
1321
|
catch (err) {
|
|
1309
1322
|
console.warn('[WebServer] Failed to rebuild custom-model env on recovery:', err);
|
|
@@ -1318,17 +1331,24 @@ export class WebServer extends EventEmitter {
|
|
|
1318
1331
|
* while the new recipe writes one, and clearing it later could then never delete the
|
|
1319
1332
|
* generated dir. `envKeys` is the UNION of saved and applied keys: the tmux session may
|
|
1320
1333
|
* still carry `setenv`s from both, and a clear has to unset every one.
|
|
1334
|
+
*
|
|
1335
|
+
* `ownEnv` is always passed, empty for a record saved before it existed: `_envOverrides`
|
|
1336
|
+
* holds what the previous run injected, and only this record says what was the session's
|
|
1337
|
+
* own. It meets the owner's grant again, like every other env override rebuilt from disk.
|
|
1321
1338
|
*/
|
|
1322
1339
|
async _restoreCustomModel(session, saved) {
|
|
1323
|
-
const
|
|
1340
|
+
const ownEnv = (await clampEnvOverridesForOwner(session.owner, saved.ownEnv)) ?? {};
|
|
1341
|
+
const applied = await this._rebuildCustomModelEnv(session, saved, ownEnv);
|
|
1324
1342
|
if (!applied) {
|
|
1325
1343
|
// Endpoint gone or CLI unregistered: restore the bookkeeping exactly as saved, which
|
|
1326
1344
|
// is what a later clear needs.
|
|
1327
|
-
session.setCustomModel(saved);
|
|
1345
|
+
session.setCustomModel({ ...saved, ownEnv });
|
|
1328
1346
|
return;
|
|
1329
1347
|
}
|
|
1330
1348
|
session.setCustomModel({
|
|
1331
1349
|
...saved,
|
|
1350
|
+
ownEnv,
|
|
1351
|
+
homeEnvVar: applied.homeEnvVar ?? saved.homeEnvVar,
|
|
1332
1352
|
// Prefer the current recipe's dir; keep the saved one when the recipe writes none,
|
|
1333
1353
|
// so a clear can still delete a directory an older recipe created.
|
|
1334
1354
|
configDir: applied.configDir ?? saved.configDir,
|
|
@@ -1345,8 +1365,9 @@ export class WebServer extends EventEmitter {
|
|
|
1345
1365
|
// __attachmentHistory keeps the private (externalPath-bearing) history on disk,
|
|
1346
1366
|
// separate from the sanitized public attachmentHistory in toState().
|
|
1347
1367
|
const attachmentHistory = session.getAttachmentHistoryForPersist();
|
|
1348
|
-
// __customModel keeps the selection's bookkeeping (injected env KEYS, config dir,
|
|
1349
|
-
//
|
|
1368
|
+
// __customModel keeps the selection's bookkeeping (injected env KEYS, config dir, launch
|
|
1369
|
+
// model, the session's own home path; never an injected value or any other own value)
|
|
1370
|
+
// so recovery can restore and later clear it.
|
|
1350
1371
|
const customModel = session.getCustomModelForPersist();
|
|
1351
1372
|
const state = {
|
|
1352
1373
|
...base,
|
|
@@ -1879,7 +1900,9 @@ export class WebServer extends EventEmitter {
|
|
|
1879
1900
|
// fs.watch()es it on the LOCAL disk, so a remote session only records the path: the fix plan stays
|
|
1880
1901
|
// authoritative as for a local session (keeping the output-based completion guessers off), and its
|
|
1881
1902
|
// file is read over ssh only on an explicit import (fix-plan/read).
|
|
1882
|
-
|
|
1903
|
+
// ⚠️ An ADOPTED session is skipped outright: Ralph is refused for one anyway, and its
|
|
1904
|
+
// `workingDir` is the neutral wrapper folder, not the foreign pane's work.
|
|
1905
|
+
if (!isExternalCliMode(session.mode) && !session.isAdopted) {
|
|
1883
1906
|
if (session.remote) {
|
|
1884
1907
|
session.ralphTracker.setRemoteWorkingDir(session.workingDir);
|
|
1885
1908
|
}
|
|
@@ -1889,8 +1912,10 @@ export class WebServer extends EventEmitter {
|
|
|
1889
1912
|
}
|
|
1890
1913
|
// Start watching for new images in this session's working directory (if enabled globally and per-session).
|
|
1891
1914
|
// A remote session's workingDir is a path on the remote host, and the watcher watches it on the LOCAL
|
|
1892
|
-
// disk, so it is skipped there (the per-session and app-wide toggles skip it too).
|
|
1893
|
-
|
|
1915
|
+
// disk, so it is skipped there (the per-session and app-wide toggles skip it too). An ADOPTED session
|
|
1916
|
+
// is skipped for the same reason as the Ralph watcher above: nothing in its wrapper folder is the
|
|
1917
|
+
// foreign pane's work.
|
|
1918
|
+
if ((await this.isImageWatcherEnabled()) && session.imageWatcherEnabled && !session.remote && !session.isAdopted) {
|
|
1894
1919
|
imageWatcher.watchSession(session.id, session.workingDir);
|
|
1895
1920
|
}
|
|
1896
1921
|
// Create and attach all listener handlers via dependency injection
|
|
@@ -1970,6 +1995,10 @@ export class WebServer extends EventEmitter {
|
|
|
1970
1995
|
const session = this.sessions.get(sessionId);
|
|
1971
1996
|
if (!session)
|
|
1972
1997
|
return;
|
|
1998
|
+
// ⚠️ A link scanned from an adopted pane was printed by a process on another host or in a
|
|
1999
|
+
// container, while confinement here would be to this host's `/tmp`, the wrapper's folder.
|
|
2000
|
+
if (session.isAdopted)
|
|
2001
|
+
return;
|
|
1973
2002
|
const event = source === 'codex-generated'
|
|
1974
2003
|
? await registerGeneratedArtifactAttachment({
|
|
1975
2004
|
sessionId,
|
|
@@ -2588,6 +2617,8 @@ export class WebServer extends EventEmitter {
|
|
|
2588
2617
|
// `undefined` here means an authoritative read listed no single directory
|
|
2589
2618
|
// for the session (split into several panes, or gone from the socket).
|
|
2590
2619
|
const paneCwdChanged = getPaneCurrentPath ? session.setPaneCwd(getPaneCurrentPath(muxName)) : false;
|
|
2620
|
+
if (paneCwdChanged)
|
|
2621
|
+
void this.refreshLiveWorktree(session);
|
|
2591
2622
|
if (session.setPaneExit(getPaneExit(muxName))) {
|
|
2592
2623
|
this.persistSessionState(session);
|
|
2593
2624
|
}
|
|
@@ -2598,6 +2629,19 @@ export class WebServer extends EventEmitter {
|
|
|
2598
2629
|
}
|
|
2599
2630
|
this.closeCleanlyExitedSessions();
|
|
2600
2631
|
}
|
|
2632
|
+
/**
|
|
2633
|
+
* Work out which linked worktree a session's pane moved into (#765). In the background, since
|
|
2634
|
+
* it reads the folder, and only after the directory changed, so an idle pane costs nothing.
|
|
2635
|
+
* A reading newer than the one this lookup started from owns the answer.
|
|
2636
|
+
*/
|
|
2637
|
+
async refreshLiveWorktree(session) {
|
|
2638
|
+
const cwd = session.paneCwd;
|
|
2639
|
+
const worktree = await findLiveWorktree(session.workingDir, cwd);
|
|
2640
|
+
if (session.paneCwd !== cwd)
|
|
2641
|
+
return;
|
|
2642
|
+
if (session.setLiveWorktree(worktree))
|
|
2643
|
+
this.broadcastSessionStateDebounced(session.id);
|
|
2644
|
+
}
|
|
2601
2645
|
/**
|
|
2602
2646
|
* Close every session whose agent exited cleanly, through the same
|
|
2603
2647
|
* `cleanupSession()` the X button uses (Ark0N/Codeman#446). A pinned session
|
|
@@ -3641,6 +3685,14 @@ export class WebServer extends EventEmitter {
|
|
|
3641
3685
|
// MuxSession.docker; state.json carries SessionState.docker), so recovery
|
|
3642
3686
|
// rebuilds the `docker exec` launch instead of a broken local command.
|
|
3643
3687
|
docker: muxSession.docker ?? savedState?.docker,
|
|
3688
|
+
// Adoption metadata round-trips for the same reason remote/docker do,
|
|
3689
|
+
// and one more: it is the ONLY thing that marks this session as
|
|
3690
|
+
// wrapping a process Codeman never launched. Dropping it on recovery
|
|
3691
|
+
// silently re-enabled respawn, Ralph and hook-backed waits against
|
|
3692
|
+
// someone else's live tmux session after every server restart:
|
|
3693
|
+
// measured, not hypothetical. The mux record is preferred because it
|
|
3694
|
+
// is what `killSession`'s detach-not-kill guard already reads.
|
|
3695
|
+
adopt: muxSession.adopt ?? savedState?.adopt,
|
|
3644
3696
|
owner: recoveredOwner,
|
|
3645
3697
|
// Tab lineage survives a restart. It is only decoration, so a parent
|
|
3646
3698
|
// that did NOT come back is harmless: the frontend draws an edge only
|
|
@@ -3895,6 +3947,14 @@ export class WebServer extends EventEmitter {
|
|
|
3895
3947
|
for (const session of this.sessions.values()) {
|
|
3896
3948
|
if (session.mode !== 'claude' || session.remote)
|
|
3897
3949
|
continue;
|
|
3950
|
+
// ⚠️ An ADOPTED session is not caught by the `remote` check above: its
|
|
3951
|
+
// connection facts live on `adopt.remote` / `adopt.docker`, so a session
|
|
3952
|
+
// wrapping someone's in-container or over-ssh claude looks local here.
|
|
3953
|
+
// Its workspace was never Codeman's to begin with, so installing hooks
|
|
3954
|
+
// there writes `.claude/settings.local.json` into the human's own repo,
|
|
3955
|
+
// on EVERY restart, since this sweep runs from boot recovery.
|
|
3956
|
+
if (session.isAdopted)
|
|
3957
|
+
continue;
|
|
3898
3958
|
if (session.docker && !session.docker.hooksEnabled)
|
|
3899
3959
|
continue;
|
|
3900
3960
|
if (session.workingDir)
|