feat(env): per-workspace PATH preset injected at spawn (T-511)
Implements D-106. The T-439 login-shell probe is a global heuristic with a known hole — login-but-non-interactive shells skip ~/.bashrc, so interactive-only additions (brew shellenv) never reach the agent's Bash tool or terminal panes on a desktop launch. The preset is the explicit per-repo layer on top: user-scope storage keyed by repo identity (a linked worktree resolves through its gitdir pointer to the main repo, so worktrees share the preset), prepended at spawn via the PaneRegistry pathForSpawn hook and agentEnvDelta prependDirs — which now exports PATH even when clide is already resolvable, closing the gap where the hosted session inherited the sparse GUI PATH untouched. CLI half: `clide env path list|set|add|remove|clear|capture` over an injected Flutter-free store port; capture diffs the login-shell PATH against the process PATH to suggest the dirs a desktop launch dropped. Binary resolution (toolchain, supporter pins, bundled pql/git) stays preset-blind per the D-92/T-98 fence. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,32 @@ void main() {
|
||||
expect(pane.kind, PaneKind.claude);
|
||||
expect(pane.toJson()['kind'], 'claude');
|
||||
});
|
||||
|
||||
test('pathForSpawn hook sets the child PATH per cwd (D-106)', tags: ['pty'], () async {
|
||||
String? seenCwd;
|
||||
final preset = PaneRegistry(
|
||||
events: sink,
|
||||
pathForSpawn: (cwd) {
|
||||
seenCwd = cwd;
|
||||
return '/preset-marker:/usr/bin:/bin';
|
||||
},
|
||||
);
|
||||
addTearDown(preset.shutdown);
|
||||
|
||||
final buf = StringBuffer();
|
||||
final got = Completer<void>();
|
||||
final sub = sink.stream.listen((e) {
|
||||
if (e.kind != 'pane.output') return;
|
||||
buf.write(utf8.decode(base64Decode(e.data['bytes_b64']! as String)));
|
||||
if (buf.toString().contains('/preset-marker') && !got.isCompleted) got.complete();
|
||||
});
|
||||
addTearDown(sub.cancel);
|
||||
|
||||
await preset.spawn(kind: PaneKind.terminal, argv: const ['/bin/sh', '-c', r'printf %s "$PATH"; sleep 0.25'], cwd: '/tmp');
|
||||
|
||||
await got.future.timeout(ioTimeout, onTimeout: () => fail('child PATH never carried the preset marker within ${ioTimeout.inSeconds}s'));
|
||||
expect(seenCwd, '/tmp');
|
||||
});
|
||||
});
|
||||
|
||||
group('RecordingEventSink filters', () {
|
||||
|
||||
Reference in New Issue
Block a user