-
Notifications
You must be signed in to change notification settings - Fork 663
fix(agent): back off context and cwd #1600
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # Background Exec Shell Fallback Plan | ||
|
|
||
| ## Approach | ||
|
|
||
| - Centralize fallback behavior in `getUserShell()` so foreground exec, background exec, and shell | ||
| environment bootstrap share the same shell resolution. | ||
| - Check absolute shell candidates for path and executable availability before returning them. | ||
| - Search `PATH` plus DeepChat default paths when `SHELL` is a bare command name. | ||
| - Use conservative POSIX fallback chains and keep Windows behavior intact. | ||
| - Return only resolved fallback candidates from the platform fallback chain; if none resolve, use | ||
| `/bin/sh` as the final default. | ||
| - Validate shell process working directories before calling `spawn`, because Node reports missing | ||
| `cwd` as `spawn <shell> ENOENT`. | ||
|
|
||
| ## Affected Paths | ||
|
|
||
| - `src/main/lib/agentRuntime/shellEnvHelper.ts` | ||
| - `src/main/lib/agentRuntime/backgroundExecSessionManager.ts` | ||
| - Existing shell environment and background exec tests. | ||
|
|
||
| ## Compatibility | ||
|
|
||
| - Existing valid user shells are still preferred. | ||
| - Missing or non-executable shells now fall back to an available POSIX shell instead of failing | ||
| with `ENOENT`/`EACCES`. | ||
| - Plain `sh` bootstrap no longer receives login-shell flags it may not support. | ||
| - Missing working directories now produce a direct working-directory error. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| # Background Exec Shell Fallback | ||
|
|
||
| ## User Story | ||
|
|
||
| Users can run foreground and background shell commands even when the configured POSIX login shell | ||
| path, such as `/bin/zsh`, is unavailable in the current runtime environment. | ||
|
|
||
| ## Acceptance Criteria | ||
|
|
||
| - POSIX shell execution does not blindly spawn a missing `process.env.SHELL` path. | ||
| - POSIX shell fallback skips existing but non-executable shell candidates. | ||
| - macOS falls back from zsh to bash and then sh; Linux falls back from bash to sh and then zsh. | ||
| - If no configured or platform fallback shell resolves, DeepChat uses `/bin/sh` instead of an | ||
| unchecked rejected candidate. | ||
| - Background exec sessions use the resolved executable shell path. | ||
| - Shell environment bootstrap uses plain `sh -c` flags when the fallback is `sh`. | ||
| - Missing or inaccessible working directories are reported before spawn instead of surfacing as a | ||
| misleading shell `ENOENT`. | ||
| - Windows shell selection is unchanged. | ||
|
|
||
| ## Non-goals | ||
|
|
||
| - Do not add renderer settings or IPC for shell configuration. | ||
| - Do not persist a detected fallback shell. | ||
| - Do not change user command permission behavior or output formatting. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| # Background Exec Shell Fallback Tasks | ||
|
|
||
| - [x] Document the issue and desired behavior. | ||
| - [x] Add available shell resolution and POSIX fallback ordering. | ||
| - [x] Verify fallback shell candidates are executable before spawn. | ||
| - [x] Avoid returning an unchecked platform fallback after candidate validation fails. | ||
| - [x] Avoid login bootstrap flags for plain `sh`. | ||
| - [x] Validate spawn working directories before launching shell processes. | ||
| - [x] Add unit coverage for missing configured shell fallback. | ||
| - [x] Run format, i18n, lint, typecheck, and targeted tests. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| import fs from 'fs' | ||
| import path from 'path' | ||
|
|
||
| const cwdErrorHint = | ||
| 'Update the session workspace to an existing folder before running shell tools. Node may report this as "spawn <shell> ENOENT" even when the shell exists.' | ||
|
|
||
| export function resolveUsableSpawnCwd(cwd: string): string { | ||
| const normalizedCwd = path.resolve(cwd.trim() || process.cwd()) | ||
|
|
||
| if (!fs.existsSync(normalizedCwd)) { | ||
| throw new Error( | ||
| `Working directory does not exist or is not accessible: ${normalizedCwd}. ${cwdErrorHint}` | ||
| ) | ||
| } | ||
|
|
||
| const statSync = fs.statSync as ((targetPath: fs.PathLike) => fs.Stats) | undefined | ||
| if (typeof statSync !== 'function') { | ||
| return normalizedCwd | ||
| } | ||
|
|
||
| try { | ||
| if (!statSync(normalizedCwd).isDirectory()) { | ||
| throw new Error(`Working directory is not a directory: ${normalizedCwd}. ${cwdErrorHint}`) | ||
| } | ||
| } catch (error) { | ||
| if (error instanceof Error && error.message.includes(cwdErrorHint)) { | ||
| throw error | ||
| } | ||
| throw new Error( | ||
| `Working directory is not accessible: ${normalizedCwd}. ${cwdErrorHint}`, | ||
| error instanceof Error ? { cause: error } : undefined | ||
| ) | ||
| } | ||
|
|
||
| return normalizedCwd | ||
| } | ||
|
|
||
| export function describeSpawnFailure( | ||
| error: Error, | ||
| context: { | ||
| shell: string | ||
| cwd: string | ||
| } | ||
| ): string { | ||
| const code = | ||
| typeof (error as NodeJS.ErrnoException).code === 'string' | ||
| ? ` ${(error as NodeJS.ErrnoException).code}` | ||
| : '' | ||
| const message = `Failed to spawn shell${code}: ${context.shell} (cwd: ${context.cwd}). ${error.message}` | ||
|
|
||
| if ((error as NodeJS.ErrnoException).code === 'ENOENT') { | ||
| return `${message}. If the shell path exists, the working directory may be missing or inaccessible.` | ||
| } | ||
|
|
||
| return message | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.