mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 02:29:33 +01:00
fix: name the pane directory field paneCwd and apply the review items for #740
`cwd` beside the fixed `workingDir` reads ambiguously on a public API surface, and `paneCwd` says where the value comes from, like `paneExit`. Also pin the field on the payload the browser really receives (getSessionStateWithRespawn), and give the pane-directory text its own architecture-invariants paragraph. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4f50af6a9f
commit
91d157cae4
9 files changed
+83
-70
No files matched your search
+8
-8
@@ -765,7 +765,7 @@ export class Session extends EventEmitter {
|
||||
* The pane's live directory, from the pane-exit watcher's read. Runtime-only:
|
||||
* serialized by toState() but never restored by the constructor.
|
||||
*/
|
||||
private _cwd: string | undefined;
|
||||
private _paneCwd: string | undefined;
|
||||
/**
|
||||
* `workingDir` with symlinks resolved, so a pane reading (tmux reads the
|
||||
* process cwd, always the resolved path) can be put back into `workingDir`'s
|
||||
@@ -1530,8 +1530,8 @@ export class Session extends EventEmitter {
|
||||
}
|
||||
|
||||
/** The pane's live working directory, when the pane read has reported one. */
|
||||
get cwd(): string | undefined {
|
||||
return this._cwd;
|
||||
get paneCwd(): string | undefined {
|
||||
return this._paneCwd;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1553,7 +1553,7 @@ export class Session extends EventEmitter {
|
||||
* `workingDir`'s spelling. Until that resolution has settled, only a reading
|
||||
* lexically inside `workingDir` is accepted.
|
||||
*/
|
||||
setCwd(next: string | undefined): boolean {
|
||||
setPaneCwd(next: string | undefined): boolean {
|
||||
let resolved = this.paneExitApplies && next?.startsWith('/') ? next : undefined;
|
||||
if (resolved !== undefined) {
|
||||
if (
|
||||
@@ -1571,8 +1571,8 @@ export class Session extends EventEmitter {
|
||||
resolved = rebasePath(resolved, this._workspaceRealPath, this._workspaceSpelling());
|
||||
}
|
||||
}
|
||||
if (resolved === this._cwd) return false;
|
||||
this._cwd = resolved;
|
||||
if (resolved === this._paneCwd) return false;
|
||||
this._paneCwd = resolved;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1582,7 +1582,7 @@ export class Session extends EventEmitter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve `workingDir`'s symlinks in the background for {@link setCwd}.
|
||||
* Resolve `workingDir`'s symlinks in the background for {@link setPaneCwd}.
|
||||
*
|
||||
* Bounded: the folder can sit on a network mount that stopped answering, so it
|
||||
* is probed with `probePathKind()` first and the `realpath()` is raced against
|
||||
@@ -2299,7 +2299,7 @@ export class Session extends EventEmitter {
|
||||
pid: this.pid,
|
||||
status: this._status,
|
||||
workingDir: this.workingDir,
|
||||
cwd: this._cwd,
|
||||
paneCwd: this._paneCwd,
|
||||
remote: this._remote,
|
||||
docker: this._docker,
|
||||
owner: this._owner,
|
||||
|
||||
+2
-2
@@ -441,7 +441,7 @@ export function derivePaneExits(rows: PaneRow[], now: number): Map<string, PaneE
|
||||
* no entry: those are authoritative absences, not unanswered questions.
|
||||
*
|
||||
* The launch directory is NOT filtered here (unlike the rediscovery path): a
|
||||
* remote or docker pane that never leaves it is refused by `Session.setCwd()`,
|
||||
* remote or docker pane that never leaves it is refused by `Session.setPaneCwd()`,
|
||||
* and a local pane reporting it really is there.
|
||||
*/
|
||||
export function derivePaneCurrentPaths(
|
||||
@@ -2049,7 +2049,7 @@ export class TmuxManager extends EventEmitter implements TerminalMultiplexer {
|
||||
* muxName -> `#{pane_current_path}` from the last authoritative pane read
|
||||
* ({@link derivePaneCurrentPaths}). Replaced wholesale by each non-empty read,
|
||||
* so it is bounded by the panes on the socket. Like {@link paneExits} it holds
|
||||
* the raw reading; `Session.setCwd()` decides which sessions may use it.
|
||||
* the raw reading; `Session.setPaneCwd()` decides which sessions may use it.
|
||||
*/
|
||||
private paneCurrentPaths: Map<string, string> = new Map();
|
||||
/** The pane-exit watcher's own interval. Runs whether or not stats are on. */
|
||||
|
||||
@@ -846,7 +846,7 @@ export interface SessionState {
|
||||
* to `workingDir`, and a path resolved outside it goes through the attachment
|
||||
* routes like any other out-of-workspace path.
|
||||
*/
|
||||
cwd?: string;
|
||||
paneCwd?: string;
|
||||
/** Remote execution metadata, present when this session runs over SSH through local tmux */
|
||||
remote?: SessionRemote;
|
||||
/** Docker execution metadata, present when this session runs inside a container via local tmux + docker exec */
|
||||
|
||||
@@ -2431,23 +2431,23 @@ function resolveLinkedFilePath(filePath, workingDir) {
|
||||
*
|
||||
* `workingDir` is recorded once at create time and never follows a `cd`, so it
|
||||
* stops describing where a shell (or an agent that changed directory) really
|
||||
* is. `session.cwd` is the pane's live `#{pane_current_path}`, published by the
|
||||
* is. `session.paneCwd` is the pane's live `#{pane_current_path}`, published by the
|
||||
* server from its pane read. It only changes which BASE a relative path joins;
|
||||
* the result is then routed like any other path, so a target outside the
|
||||
* workspace still goes through the attachment routes.
|
||||
*
|
||||
* Remote and Docker sessions are excluded (the server never sends them a cwd,
|
||||
* Remote and Docker sessions are excluded (the server never sends them a paneCwd,
|
||||
* and this checks again): their local pane runs the ssh / docker-exec CLIENT,
|
||||
* so its directory says nothing about the agent. An unknown cwd falls back to
|
||||
* so its directory says nothing about the agent. An unknown paneCwd falls back to
|
||||
* `workingDir`.
|
||||
*
|
||||
* @param {{workingDir?: string, cwd?: string, remote?: unknown, docker?: unknown}} [session]
|
||||
* @param {{workingDir?: string, paneCwd?: string, remote?: unknown, docker?: unknown}} [session]
|
||||
* @returns {string|undefined}
|
||||
*/
|
||||
function relativeResolutionBase(session) {
|
||||
if (!session) return undefined;
|
||||
const cwd = session.cwd;
|
||||
if (!session.remote && !session.docker && typeof cwd === 'string' && cwd.startsWith('/')) return cwd;
|
||||
const paneCwd = session.paneCwd;
|
||||
if (!session.remote && !session.docker && typeof paneCwd === 'string' && paneCwd.startsWith('/')) return paneCwd;
|
||||
return session.workingDir;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -2866,10 +2866,10 @@ export class WebServer extends EventEmitter {
|
||||
// or empty read and carries a blank `#{pane_current_path}` forward, so an
|
||||
// `undefined` here means an authoritative read listed no single directory
|
||||
// for the session (split into several panes, or gone from the socket).
|
||||
const cwdChanged = getPaneCurrentPath ? session.setCwd(getPaneCurrentPath(muxName)) : false;
|
||||
const paneCwdChanged = getPaneCurrentPath ? session.setPaneCwd(getPaneCurrentPath(muxName)) : false;
|
||||
if (session.setPaneExit(getPaneExit(muxName))) {
|
||||
this.persistSessionState(session);
|
||||
} else if (!cwdChanged) {
|
||||
} else if (!paneCwdChanged) {
|
||||
continue;
|
||||
}
|
||||
this.broadcastSessionStateDebounced(session.id);
|
||||
|
||||
Reference in new issue
Block a user