源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
package runtimeprep
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// exposeUserCodexAgentsFile seeds the run-scoped instruction file with the
|
||||
// user's global Codex instructions. The session-owned file must be a copy:
|
||||
// WriteManagedBlock adds Tutti's managed policy to it and must never mutate the
|
||||
// user's real ~/.codex/AGENTS.md.
|
||||
func exposeUserCodexAgentsFile(codexHome string, userCodexHome string) error {
|
||||
source := filepath.Join(userCodexHome, "AGENTS.md")
|
||||
sourceContent, sourceExists, err := readRegularCodexAgentsFile(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
target := filepath.Join(codexHome, "AGENTS.md")
|
||||
targetInfo, err := os.Lstat(target)
|
||||
if os.IsNotExist(err) {
|
||||
if !sourceExists {
|
||||
return nil
|
||||
}
|
||||
if err := writeRegularCodexAgentsFile(target, sourceContent); err != nil {
|
||||
return fmt.Errorf("copy user codex AGENTS.md: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err != nil {
|
||||
return fmt.Errorf("inspect session codex AGENTS.md: %w", err)
|
||||
}
|
||||
|
||||
// Always replace a pre-existing link with a private regular file. This
|
||||
// prevents WriteManagedBlock from following a symlink or mutating a hardlink
|
||||
// to the user's real ~/.codex/AGENTS.md on the next line of Prepare.
|
||||
if targetInfo.Mode()&os.ModeSymlink != 0 {
|
||||
if sourceExists {
|
||||
if err := writeRegularCodexAgentsFile(target, sourceContent); err != nil {
|
||||
return fmt.Errorf("replace session codex AGENTS.md link: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := os.Remove(target); err != nil {
|
||||
return fmt.Errorf("remove session codex AGENTS.md link: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if !targetInfo.Mode().IsRegular() {
|
||||
return fmt.Errorf("session codex AGENTS.md is not a regular file")
|
||||
}
|
||||
|
||||
// Re-materialize an existing regular file too. A hardlink has regular-file
|
||||
// mode, so an atomic replacement is what guarantees a new inode without
|
||||
// discarding any session-local content already present in the file.
|
||||
existing, err := os.ReadFile(target)
|
||||
if err != nil {
|
||||
return fmt.Errorf("read session codex AGENTS.md: %w", err)
|
||||
}
|
||||
if err := writeRegularCodexAgentsFile(target, existing); err != nil {
|
||||
return fmt.Errorf("isolate session codex AGENTS.md: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readRegularCodexAgentsFile(path string) ([]byte, bool, error) {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, false, nil
|
||||
}
|
||||
return nil, false, fmt.Errorf("inspect user codex AGENTS.md: %w", err)
|
||||
}
|
||||
if !info.Mode().IsRegular() {
|
||||
// AGENTS.md is optional. Ignore directories, FIFOs, and other special
|
||||
// files instead of blocking runtime preparation while reading them.
|
||||
return nil, false, nil
|
||||
}
|
||||
content, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("read user codex AGENTS.md: %w", err)
|
||||
}
|
||||
return content, true, nil
|
||||
}
|
||||
|
||||
func writeRegularCodexAgentsFile(path string, content []byte) error {
|
||||
temporary, err := os.CreateTemp(filepath.Dir(path), ".codex-agents-*.tmp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
temporaryPath := temporary.Name()
|
||||
defer func() {
|
||||
_ = temporary.Close()
|
||||
_ = os.Remove(temporaryPath)
|
||||
}()
|
||||
if err := temporary.Chmod(0o600); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := temporary.Write(content); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := temporary.Sync(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := temporary.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Rename(temporaryPath, path)
|
||||
}
|
||||
Reference in New Issue
Block a user