tabminal 3.0.13 → 3.0.14
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/AGENTS.md +5 -0
- package/package.json +1 -1
- package/public/app.js +2305 -251
- package/public/index.html +137 -35
- package/public/styles.css +307 -0
- package/src/acp-manager.mjs +180 -18
- package/src/fs-routes.mjs +148 -39
- package/src/server.mjs +69 -25
- package/src/terminal-manager.mjs +97 -2
- package/src/terminal-session.mjs +24 -1
package/src/terminal-manager.mjs
CHANGED
|
@@ -80,6 +80,20 @@ function uniqueStringList(values) {
|
|
|
80
80
|
function normalizeWorkspaceState(input = {}, fallback = {}) {
|
|
81
81
|
const source = input && typeof input === 'object' ? input : {};
|
|
82
82
|
const base = fallback && typeof fallback === 'object' ? fallback : {};
|
|
83
|
+
const activeWorkspaceTabKey = typeof source.activeWorkspaceTabKey === 'string'
|
|
84
|
+
? source.activeWorkspaceTabKey
|
|
85
|
+
: (
|
|
86
|
+
typeof base.activeWorkspaceTabKey === 'string'
|
|
87
|
+
? base.activeWorkspaceTabKey
|
|
88
|
+
: ''
|
|
89
|
+
);
|
|
90
|
+
const markdownSplitPath = typeof source.markdownSplitPath === 'string'
|
|
91
|
+
? source.markdownSplitPath
|
|
92
|
+
: (
|
|
93
|
+
typeof base.markdownSplitPath === 'string'
|
|
94
|
+
? base.markdownSplitPath
|
|
95
|
+
: ''
|
|
96
|
+
);
|
|
83
97
|
return {
|
|
84
98
|
updatedAt: Number.isFinite(source.updatedAt)
|
|
85
99
|
? source.updatedAt
|
|
@@ -100,7 +114,9 @@ function normalizeWorkspaceState(input = {}, fallback = {}) {
|
|
|
100
114
|
terminalDisplayMode: source.terminalDisplayMode === 'tab'
|
|
101
115
|
? 'tab'
|
|
102
116
|
: 'auto',
|
|
103
|
-
expandedPaths: uniqueStringList(source.expandedPaths)
|
|
117
|
+
expandedPaths: uniqueStringList(source.expandedPaths),
|
|
118
|
+
markdownSplitPath,
|
|
119
|
+
activeWorkspaceTabKey
|
|
104
120
|
};
|
|
105
121
|
}
|
|
106
122
|
|
|
@@ -131,6 +147,70 @@ export class TerminalManager {
|
|
|
131
147
|
this.disposing = false;
|
|
132
148
|
}
|
|
133
149
|
|
|
150
|
+
getLatestWorkspaceSession() {
|
|
151
|
+
let bestSession = null;
|
|
152
|
+
let bestWorkspaceUpdatedAt = -1;
|
|
153
|
+
let bestTerminalUpdatedAt = -1;
|
|
154
|
+
let bestCreatedAt = -1;
|
|
155
|
+
|
|
156
|
+
for (const session of this.sessions.values()) {
|
|
157
|
+
const cwd = typeof session?.cwd === 'string'
|
|
158
|
+
? session.cwd.trim()
|
|
159
|
+
: '';
|
|
160
|
+
if (!cwd) continue;
|
|
161
|
+
|
|
162
|
+
const workspaceUpdatedAt = Number.isFinite(
|
|
163
|
+
session?.editorState?.updatedAt
|
|
164
|
+
)
|
|
165
|
+
? session.editorState.updatedAt
|
|
166
|
+
: 0;
|
|
167
|
+
const terminalUpdatedAt = session?.updatedAt instanceof Date
|
|
168
|
+
? session.updatedAt.getTime()
|
|
169
|
+
: Date.parse(session?.updatedAt || '') || 0;
|
|
170
|
+
const createdAt = session?.createdAt instanceof Date
|
|
171
|
+
? session.createdAt.getTime()
|
|
172
|
+
: Date.parse(session?.createdAt || '') || 0;
|
|
173
|
+
|
|
174
|
+
const isBetterWorkspace = (
|
|
175
|
+
workspaceUpdatedAt > bestWorkspaceUpdatedAt
|
|
176
|
+
);
|
|
177
|
+
const isSameWorkspace = (
|
|
178
|
+
workspaceUpdatedAt === bestWorkspaceUpdatedAt
|
|
179
|
+
);
|
|
180
|
+
const isBetterTerminal = (
|
|
181
|
+
isSameWorkspace
|
|
182
|
+
&& terminalUpdatedAt > bestTerminalUpdatedAt
|
|
183
|
+
);
|
|
184
|
+
const isSameTerminal = (
|
|
185
|
+
isSameWorkspace
|
|
186
|
+
&& terminalUpdatedAt === bestTerminalUpdatedAt
|
|
187
|
+
);
|
|
188
|
+
const isBetterCreated = (
|
|
189
|
+
isSameTerminal
|
|
190
|
+
&& createdAt > bestCreatedAt
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
if (
|
|
194
|
+
isBetterWorkspace
|
|
195
|
+
|| isBetterTerminal
|
|
196
|
+
|| isBetterCreated
|
|
197
|
+
) {
|
|
198
|
+
bestSession = session;
|
|
199
|
+
bestWorkspaceUpdatedAt = workspaceUpdatedAt;
|
|
200
|
+
bestTerminalUpdatedAt = terminalUpdatedAt;
|
|
201
|
+
bestCreatedAt = createdAt;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return bestSession;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
getDefaultSessionCwd() {
|
|
209
|
+
return this.getLatestWorkspaceSession()?.cwd
|
|
210
|
+
|| process.env.TABMINAL_CWD
|
|
211
|
+
|| os.homedir();
|
|
212
|
+
}
|
|
213
|
+
|
|
134
214
|
queueSessionPersistence(id, operation) {
|
|
135
215
|
const previous = this.sessionPersistenceChains.get(id)
|
|
136
216
|
|| Promise.resolve();
|
|
@@ -316,10 +396,25 @@ precmd_functions+=(_tabminal_zsh_apply_prompt_marker)
|
|
|
316
396
|
}
|
|
317
397
|
|
|
318
398
|
createSession(restoredData = null) {
|
|
399
|
+
const isRestoredSession = !!(
|
|
400
|
+
restoredData
|
|
401
|
+
&& typeof restoredData === 'object'
|
|
402
|
+
&& (
|
|
403
|
+
restoredData.id
|
|
404
|
+
|| restoredData.createdAt
|
|
405
|
+
|| restoredData.executions
|
|
406
|
+
|| restoredData.editorState
|
|
407
|
+
|| restoredData.workspaceState
|
|
408
|
+
)
|
|
409
|
+
);
|
|
319
410
|
return this._createPtySession({
|
|
320
411
|
id: restoredData?.id,
|
|
321
412
|
shell: resolveShell(),
|
|
322
|
-
cwd: restoredData?.cwd
|
|
413
|
+
cwd: restoredData?.cwd || (
|
|
414
|
+
isRestoredSession
|
|
415
|
+
? undefined
|
|
416
|
+
: this.getDefaultSessionCwd()
|
|
417
|
+
),
|
|
323
418
|
cols: restoredData?.cols,
|
|
324
419
|
rows: restoredData?.rows,
|
|
325
420
|
createdAt: restoredData?.createdAt,
|
package/src/terminal-session.mjs
CHANGED
|
@@ -167,6 +167,22 @@ function selectFallbackQueryResponder(clients, pendingClients) {
|
|
|
167
167
|
return null;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
|
+
function isIgnorablePtyResizeError(error) {
|
|
171
|
+
if (!error) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (error.code === 'EBADF') {
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const message = String(error.message || '');
|
|
180
|
+
return (
|
|
181
|
+
/ioctl\(2\) failed/i.test(message)
|
|
182
|
+
|| /bad file descriptor/i.test(message)
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
170
186
|
export class TerminalSession {
|
|
171
187
|
constructor(pty, options = {}) {
|
|
172
188
|
this.pty = pty;
|
|
@@ -488,7 +504,14 @@ export class TerminalSession {
|
|
|
488
504
|
|
|
489
505
|
resize(cols, rows) {
|
|
490
506
|
if (this.closed) return;
|
|
491
|
-
|
|
507
|
+
try {
|
|
508
|
+
this.pty.resize(cols, rows);
|
|
509
|
+
} catch (error) {
|
|
510
|
+
if (isIgnorablePtyResizeError(error)) {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
throw error;
|
|
514
|
+
}
|
|
492
515
|
this._queueSnapshotMutation(() => {
|
|
493
516
|
this.snapshotTerminal.resize(cols, rows);
|
|
494
517
|
});
|