Skip to content

fix(session): resolve workspaces without git - #716

Open
ALV0612 wants to merge 11 commits into
openai:mainfrom
ALV0612:fix/issue-403-avoid-git-in-session-end
Open

fix(session): resolve workspaces without git#716
ALV0612 wants to merge 11 commits into
openai:mainfrom
ALV0612:fix/issue-403-avoid-git-in-session-end

Conversation

@ALV0612

@ALV0612 ALV0612 commented Sep 2, 2026

Copy link
Copy Markdown

Summary

  • replace git rev-parse --show-toplevel workspace discovery with a filesystem-only ancestor walk
  • support .git directories and linked-worktree gitfiles
  • canonicalize aliases while preserving non-repository and inaccessible cwd fallback
  • add coverage proving no child process is started

Verification

  • focused workspace/state tests: 10/10 pass
  • full suite: 98/98 pass
  • build and version checks pass
  • OpenSpec strict validation and git diff --check pass

Fixes #403

@ALV0612
ALV0612 requested a review from a team September 2, 2026 10:07

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 090f28bf28

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
@ALV0612

ALV0612 commented Sep 2, 2026

Copy link
Copy Markdown
Author

Fixed in e965ca9 by following the .git marker with statSync before classifying it. Added a regression with a symlinked .git directory; focused workspace/state tests now pass 11/11.

@sylvesterkaczmarek sylvesterkaczmarek left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regular .git files are still too broad on this head. statSync fixes the symlink case, but now any ordinary file named .git marks the directory as a repo root, even if it isn't a valid Git gitfile. The old git rev-parse path rejected that, so a stray/junk .git file can now change workspace/state identity. Could the file case validate gitdir: (and ideally the target) before accepting it?

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2667b207af

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
try {
const markerPath = path.join(current, ".git");
const markerStats = fs.statSync(markerPath);
const validGitFile = markerStats.isFile() && /^gitdir:\s*\S/m.test(fs.readFileSync(markerPath, "utf8"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require the mandatory separator in gitfile markers

When a non-repository child directory within an outer checkout contains an ordinary .git file such as gitdir:/tmp/metadata (or one with a later gitdir: line), this regex accepts it because \s* permits no separator and /m searches every line. Git rejects those as invalid gitfiles—the valid header must begin the file as gitdir: <path>—so resolveWorkspaceRoot incorrectly selects the child instead of the real outer workspace, splitting job state and narrowing the app-server workspace for commands run below it.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0106a64f04

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
@ALV0612

ALV0612 commented Sep 2, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 39c6c2a85c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
Comment on lines +12 to +13
const markerPath = path.join(current, ".git");
const markerStats = fs.statSync(markerPath);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor Git work trees configured through the environment

When a checkout is configured with GIT_DIR and GIT_WORK_TREE but has no .git marker in the work tree, Git still resolves rev-parse --show-toplevel to the configured work-tree root, whereas this walk returns each caller's own directory. A task launched from work/sub is therefore stored and sandboxed under sub, while /codex:status or task resume run from work uses a separate state directory; preserve an environment-aware workspace-root path before falling back to marker discovery.

Useful? React with 👍 / 👎.

@ALV0612

ALV0612 commented Sep 2, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 39c6c2a85c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@ALV0612

ALV0612 commented Sep 2, 2026

Copy link
Copy Markdown
Author

Fixed in fe4f2a4. resolveWorkspaceRoot now honors a valid GIT_DIR + GIT_WORK_TREE pair before marker discovery, canonicalizes the configured work tree, and falls back normally for incomplete or missing paths. Added three environment-path regressions; focused tests pass 19/19 and full suite 107/107.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe4f2a4d6e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
export function resolveWorkspaceRoot(cwd, env = process.env) {
try {
return ensureGitRepository(cwd);
if (env?.GIT_DIR && env?.GIT_WORK_TREE) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Respect GIT_WORK_TREE when it is used alone

When invoked inside a real repository with only GIT_WORK_TREE set (for example, from repo/packages/app with GIT_WORK_TREE=/tmp/wt), Git treats that variable as the working-tree root—its docs say it sets “the path to the root of the working tree” (Git environment docs)—but this pair-only guard skips it and the marker walk returns repo. Before this change, ensureGitRepository delegated to git rev-parse --show-toplevel, so task/status state and the app-server sandbox used the configured worktree; now they are incorrectly scoped to the metadata checkout. Handle the valid work-tree-only case after confirming the repository marker.

Useful? React with 👍 / 👎.

@ALV0612

ALV0612 commented Sep 2, 2026

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fe4f2a4d6e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
try {
const configuredGitDirectory = path.resolve(cwd, env.GIT_DIR);
const configuredWorkTree = path.resolve(cwd, env.GIT_WORK_TREE);
if (fs.statSync(configuredGitDirectory).isDirectory() && fs.statSync(configuredWorkTree).isDirectory()) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Follow gitfile values set through GIT_DIR

When GIT_DIR names a gitfile (for example, a gitdir: ... pointer copied from a linked worktree) and GIT_WORK_TREE names a work tree without its own .git marker, Git resolves that pair successfully, but this directory-only check rejects the valid GIT_DIR. The ancestor walk then returns the caller's subdirectory instead of the configured work-tree root, splitting task/state storage and narrowing the app-server workspace for commands launched below that root. Resolve gitfile-form GIT_DIR values before falling back to marker discovery.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4718eda3a9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
return false;
}

const match = /^gitdir: (.+?)(?:\r?\n|$)/.exec(fs.readFileSync(candidatePath, "utf8"));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject gitfiles with trailing data

When a nested .git file contains an otherwise valid header followed by extra content (for example, gitdir: /valid/.git\ntrailing-data), Git rejects the gitfile, but this expression accepts only its first line and findMarkerWorkspace selects the nested directory as a workspace. That creates a bogus state/job namespace and scopes task sandboxing to the child instead of continuing to the enclosing valid workspace; require the match to consume the complete gitfile.

Useful? React with 👍 / 👎.

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
const canonicalCwd = fs.realpathSync.native(cwd);
const markerWorkspace = findMarkerWorkspace(canonicalCwd);

if (env?.GIT_WORK_TREE) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor GIT_DIR without GIT_WORK_TREE

When a process sets a valid GIT_DIR but leaves GIT_WORK_TREE unset, Git treats the invocation directory as the working-tree root (git rev-parse --show-toplevel returns that directory). This guard ignores that valid configuration, so a task started from a subdirectory that also has an enclosing .git marker is instead rooted at the enclosing checkout, changing the prior state identity and giving Codex a broader, incorrect workspace sandbox.

Useful? React with 👍 / 👎.

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
}
}

return markerWorkspace ?? cwd;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Honor core.worktree configuration

When a checkout's .git/config sets core.worktree to an external working tree, the previous ensureGitRepository call returned that configured directory via git rev-parse --show-toplevel. The marker-only fallback returns the directory containing .git instead, so executeTaskRun stores jobs and launches the app server under the metadata checkout rather than the actual working tree; workspace-write tasks may consequently be unable to reach the configured worktree files.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 80236169be

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
}
const valueMatch = /^worktree\s*=\s*(.+)$/i.exec(line);
if (valueMatch) {
const value = valueMatch[1].trim().replace(/^(?:"(.*)"|'(.*)')$/, "$1$2");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Strip Git config comments before resolving core.worktree

When a valid repository config uses an inline comment after a core.worktree value (for example, worktree = "../work tree" # external tree), Git parses the value as ../work tree, but this code keeps the comment and therefore cannot unquote or stat the intended directory. configuredWorkTree then returns null and resolution falls back to the metadata checkout rather than the configured work tree, splitting task state and giving workspace-write app-server turns the wrong sandbox root.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8e6a9988cf

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
const valueMatch = /^worktree\s*=\s*(.+)$/i.exec(line);
if (valueMatch) {
const value = parseConfigValue(valueMatch[1]);
return value ? path.resolve(gitDirectory, value) : null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the effective final core.worktree value

When a valid config contains more than one core.worktree entry, Git's effective value is the last entry, but this returns as soon as it sees the first. For such a checkout, resolveWorkspaceRoot selects a stale worktree, placing task state and the workspace-write app-server sandbox in the wrong root even though git rev-parse --show-toplevel resolves the final entry; continue scanning and retain the final value.

Useful? React with 👍 / 👎.

Comment thread plugins/codex/scripts/lib/workspace.mjs Outdated
if (!line || line.startsWith("#") || line.startsWith(";")) {
continue;
}
const sectionMatch = /^\[([^\]]+)\]$/.exec(line);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept comments after core section headers

When a valid config uses [core] # ... or [core] ; ... after another section, this anchored header regexp does not recognize the header and leaves section set to the preceding section. Git treats those as core headers, so the following worktree setting is ignored here and task state plus the workspace-write sandbox fall back to the metadata checkout instead of the configured worktree.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6f45241476

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +6 to +7
if (candidateStats.isDirectory()) {
return fs.realpathSync.native(candidatePath);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Verify .git directories before accepting them as repositories

When a non-repository child inside a real checkout contains an empty (or otherwise invalid) .git directory, this branch immediately accepts it. Git ignores such a directory and continues discovery to the enclosing repository, so a task invoked below the child now receives a separate job/state namespace and runAppServerTurn is confined to that child; validate directory markers as actual Git directories before returning them.

Useful? React with 👍 / 👎.

const configPath = path.join(gitDirectory, "config");
let section = "";
let workTree = null;
for (const rawLine of fs.readFileSync(configPath, "utf8").split(/\r?\n/)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Join continued core.worktree values

Git config permits a value to continue across a backslash-newline. For example, a valid core.worktree = ../work\ followed by tree resolves in Git to ../work tree, but splitting the config before parsing reads the incomplete first line, cannot stat that path, and falls back to the metadata checkout. This gives tasks and their app-server sandbox the wrong workspace whenever the configured external worktree uses a continued value.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SessionEnd hook can hit 5s timeout on Windows due to shelling out to git

2 participants