sdks/go: mirror Elydora-Go-SDK v2.0.1 under the /v2 module path

Rebuilt from the standalone f5341ed tree (durable managed-file
transactions, Kiro IDE adapter, hook retry with a bounded chain lock,
CLI version 2.0.1) with the Open-Source API trims re-applied: no admin
events, members, webhooks, deep health, token rotation, or agent
integration updates, and the mirror's freeze/unfreeze and registration
validation contracts kept. The root quickstart now imports the /v2 path.

Claude-Session: https://claude.ai/code/session_01QoUjdc7HGKTsgj5GhG8HvF
This commit is contained in:
雷电芽衣 committed 2026-09-02 10:34:21 -04:00
1 parent edf9d73c3e
commit b00932d047
75 files changed
+8529 -443

No files matched your search

+95 -244
View File
@@ -4,7 +4,6 @@ import (
"bytes"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
@@ -12,12 +11,14 @@ import (
)
type renameFunc func(source, destination string) error
type replaceWithBackupFunc func(target, replacement, backup string) error
type fileChange struct {
filePath string
label string
original []byte
originalInfo os.FileInfo
originalID string
originalMode os.FileMode
existed bool
next []byte
@@ -26,11 +27,40 @@ type fileChange struct {
}
type stagedChange struct {
change fileChange
temporaryPath string
rollbackPath string
committedInfo os.FileInfo
committed bool
change fileChange
temporaryPath string
temporaryInfo os.FileInfo
rollbackPath string
originalCaptured bool
committedInfo os.FileInfo
committed bool
}
type transactionFileOps struct {
moveNoReplace renameFunc
compensateNoReplace renameFunc
replaceWithBackup replaceWithBackupFunc
production bool
}
func newTransactionFileOps(rename renameFunc) transactionFileOps {
if rename == nil {
rename = atomicRenameNoReplace
return transactionFileOps{
moveNoReplace: rename,
compensateNoReplace: rename,
replaceWithBackup: atomicReplaceWithBackup,
production: true,
}
}
return transactionFileOps{
moveNoReplace: rename,
compensateNoReplace: atomicRenameNoReplace,
}
}
func sameManagedFileMode(current, expected os.FileMode) bool {
return runtime.GOOS == "windows" || current.Perm() == expected.Perm()
}
func readOptionalFile(path, label string) ([]byte, bool, error) {
@@ -80,7 +110,8 @@ func prepareSourceChange(
(currentExists && !bytes.Equal(snapshot.contents, original)) {
return nil, fmt.Errorf("%s changed before update: %s", label, filePath)
}
if existed && !remove && bytes.Equal(original, next) {
if existed && !remove && bytes.Equal(original, next) &&
sameManagedFileMode(snapshot.mode, mode) {
return nil, nil
}
if !existed && (remove || next == nil) {
@@ -94,22 +125,52 @@ func prepareSourceChange(
}
return &fileChange{
filePath: filePath, label: label, original: append([]byte(nil), original...),
originalInfo: originalInfo, originalMode: originalMode, existed: existed,
originalInfo: originalInfo, originalID: snapshotIdentity(snapshot),
originalMode: originalMode, existed: existed,
next: append([]byte(nil), next...),
mode: mode, remove: remove,
}, nil
}
func snapshotIdentity(snapshot *managedFileSnapshot) string {
if snapshot == nil {
return ""
}
return snapshot.identity
}
func writeChanges(
changes []*fileChange,
label string,
rename renameFunc,
preconditions ...filePrecondition,
) error {
return writeChangesWithFileOps(
changes,
label,
newTransactionFileOps(rename),
preconditions...,
)
}
func writeChangesWithFileOps(
changes []*fileChange,
label string,
ops transactionFileOps,
preconditions ...filePrecondition,
) error {
if ops.production {
return writeDurableChanges(changes, label, ops, preconditions...)
}
if ops.moveNoReplace == nil {
return fmt.Errorf("%s is missing atomic file operations", label)
}
filtered := make([]fileChange, 0, len(changes))
targets := map[string]bool{}
for _, change := range changes {
if change == nil || (change.existed && !change.remove && bytes.Equal(change.original, change.next)) {
if change == nil || (change.existed && !change.remove &&
bytes.Equal(change.original, change.next) &&
sameManagedFileMode(change.originalMode, change.mode)) {
continue
}
target := filepath.Clean(change.filePath)
@@ -128,17 +189,30 @@ func writeChanges(
if len(filtered) == 0 {
return nil
}
if rename == nil {
rename = os.Rename
}
staged := make([]stagedChange, 0, len(filtered))
for _, change := range filtered {
if err := assertFilePreconditions(preconditions, label); err != nil {
cleanupErrors := cleanupStaging(staged)
return joinTransactionFailure(
fmt.Errorf("%s: %w", label, err),
cleanupErrors,
"cleanup failed",
)
}
item, err := stageChange(change)
if err != nil {
cleanupErrors := cleanupStaging(staged)
return joinTransactionFailure(fmt.Errorf("%s: %w", label, err), cleanupErrors, "cleanup failed")
}
staged = append(staged, item)
if err := assertFilePreconditions(preconditions, label); err != nil {
cleanupErrors := cleanupStaging(staged)
return joinTransactionFailure(
fmt.Errorf("%s: %w", label, err),
cleanupErrors,
"cleanup failed",
)
}
}
if err := assertFilePreconditions(preconditions, label); err != nil {
cleanupErrors := cleanupStaging(staged)
@@ -146,18 +220,23 @@ func writeChanges(
}
for index := range staged {
if err := assertFilePreconditions(preconditions, label); err != nil {
recoveryErrors := rollbackChanges(staged, rename)
recoveryErrors := rollbackChanges(staged, ops)
recoveryErrors = append(recoveryErrors, cleanupStaging(staged)...)
return joinTransactionFailure(fmt.Errorf("%s: %w", label, err), recoveryErrors, "recovery failed")
}
if err := commitChange(&staged[index], rename); err != nil {
recoveryErrors := rollbackChanges(staged, rename)
if err := commitChange(&staged[index], ops); err != nil {
recoveryErrors := rollbackChanges(staged, ops)
recoveryErrors = append(recoveryErrors, cleanupStaging(staged)...)
return joinTransactionFailure(fmt.Errorf("%s: %w", label, err), recoveryErrors, "recovery failed")
}
}
if err := assertFilePreconditions(preconditions, label); err != nil {
recoveryErrors := rollbackChanges(staged, rename)
recoveryErrors := rollbackChanges(staged, ops)
recoveryErrors = append(recoveryErrors, cleanupStaging(staged)...)
return joinTransactionFailure(fmt.Errorf("%s: %w", label, err), recoveryErrors, "recovery failed")
}
if err := assertCommittedChanges(staged); err != nil {
recoveryErrors := rollbackChanges(staged, ops)
recoveryErrors = append(recoveryErrors, cleanupStaging(staged)...)
return joinTransactionFailure(fmt.Errorf("%s: %w", label, err), recoveryErrors, "recovery failed")
}
@@ -168,234 +247,6 @@ func writeChanges(
return nil
}
func stageChange(change fileChange) (stagedChange, error) {
if err := assertFileUnchanged(change); err != nil {
return stagedChange{}, err
}
directory := filepath.Dir(change.filePath)
if err := ensureManagedDirectory(directory, "directory for "+change.label); err != nil {
return stagedChange{}, err
}
staged := stagedChange{change: change}
var err error
if change.remove {
staged.rollbackPath, err = reserveStagingPath(directory, filepath.Base(change.filePath), ".rollback")
} else {
staged.temporaryPath, err = writeStagedFile(
directory, filepath.Base(change.filePath), ".tmp", change.next, change.mode,
)
if err == nil && change.existed {
staged.rollbackPath, err = writeStagedFile(
directory, filepath.Base(change.filePath), ".rollback", change.original, change.originalMode,
)
}
}
if err != nil {
cleanupErrors := cleanupStaging([]stagedChange{staged})
return stagedChange{}, joinTransactionFailure(
fmt.Errorf("stage %s: %w", change.label, err), cleanupErrors, "cleanup failed",
)
}
return staged, nil
}
func writeStagedFile(
directory, basename, suffix string,
content []byte,
mode os.FileMode,
) (string, error) {
file, err := os.CreateTemp(directory, "."+basename+".*"+suffix)
if err != nil {
return "", err
}
path := file.Name()
failed := func(cause error) (string, error) {
return "", errors.Join(cause, file.Close(), removeOptionalFile(path))
}
if err := file.Chmod(mode); err != nil {
return failed(err)
}
written, err := file.Write(content)
if err != nil {
return failed(err)
}
if written != len(content) {
return failed(io.ErrShortWrite)
}
if err := file.Sync(); err != nil {
return failed(err)
}
if err := file.Close(); err != nil {
return "", errors.Join(err, removeOptionalFile(path))
}
return path, nil
}
func reserveStagingPath(directory, basename, suffix string) (string, error) {
file, err := os.CreateTemp(directory, "."+basename+".*"+suffix)
if err != nil {
return "", err
}
path := file.Name()
if err := file.Close(); err != nil {
return "", errors.Join(err, removeOptionalFile(path))
}
if err := os.Remove(path); err != nil {
return "", err
}
return path, nil
}
func assertFileUnchanged(change fileChange) error {
current, err := readManagedFile(change.filePath, change.label, maxManagedSourceBytes)
if err != nil {
return err
}
currentExists := current != nil
if currentExists != change.existed ||
(currentExists && (!bytes.Equal(current.contents, change.original) ||
!os.SameFile(current.info, change.originalInfo))) {
return fmt.Errorf("%s changed during installation: %s", change.label, change.filePath)
}
return nil
}
func commitChange(staged *stagedChange, rename renameFunc) error {
if err := assertFileUnchanged(staged.change); err != nil {
return err
}
if staged.change.remove {
if staged.rollbackPath == "" {
return fmt.Errorf("missing rollback path for %s", staged.change.label)
}
if err := rename(staged.change.filePath, staged.rollbackPath); err != nil {
return fmt.Errorf("remove %s at %s: %w", staged.change.label, staged.change.filePath, err)
}
} else {
if staged.temporaryPath == "" {
return fmt.Errorf("missing staged file for %s", staged.change.label)
}
if err := rename(staged.temporaryPath, staged.change.filePath); err != nil {
return fmt.Errorf("commit %s at %s: %w", staged.change.label, staged.change.filePath, err)
}
}
staged.committed = true
if !staged.change.remove {
current, err := readManagedFile(
staged.change.filePath,
staged.change.label,
maxManagedSourceBytes,
)
if err != nil {
return err
}
if current == nil || !bytes.Equal(current.contents, staged.change.next) {
return fmt.Errorf(
"%s changed immediately after commit: %s",
staged.change.label,
staged.change.filePath,
)
}
staged.committedInfo = current.info
}
return nil
}
func assertCommittedFileUnchanged(item *stagedChange) error {
current, err := readManagedFile(
item.change.filePath,
item.change.label,
maxManagedSourceBytes,
)
if err != nil {
return err
}
if item.change.remove {
if current != nil {
return fmt.Errorf(
"%s changed during transaction recovery: %s",
item.change.label,
item.change.filePath,
)
}
return nil
}
if current == nil || item.committedInfo == nil ||
!bytes.Equal(current.contents, item.change.next) ||
!os.SameFile(current.info, item.committedInfo) {
return fmt.Errorf(
"%s changed during transaction recovery: %s",
item.change.label,
item.change.filePath,
)
}
return nil
}
func rollbackChanges(staged []stagedChange, rename renameFunc) []error {
failures := make([]error, 0)
for index := len(staged) - 1; index >= 0; index-- {
item := &staged[index]
if !item.committed {
continue
}
if err := assertCommittedFileUnchanged(item); err != nil {
failures = append(failures, preserveRollbackFile(item, err))
continue
}
var err error
switch {
case item.change.remove:
err = rename(item.rollbackPath, item.change.filePath)
case item.change.existed:
err = rename(item.rollbackPath, item.change.filePath)
default:
err = removeOptionalFile(item.change.filePath)
}
if err != nil {
failure := fmt.Errorf(
"restore %s at %s: %w",
item.change.label,
item.change.filePath,
err,
)
failures = append(failures, preserveRollbackFile(item, failure))
}
}
return failures
}
func preserveRollbackFile(item *stagedChange, cause error) error {
if item.rollbackPath == "" {
return cause
}
path := item.rollbackPath
item.rollbackPath = ""
return fmt.Errorf("%w; original content preserved at %s", cause, path)
}
func cleanupStaging(staged []stagedChange) []error {
failures := make([]error, 0)
for _, item := range staged {
for _, path := range []string{item.temporaryPath, item.rollbackPath} {
if err := removeOptionalFile(path); err != nil {
failures = append(failures, err)
}
}
}
return failures
}
func removeOptionalFile(path string) error {
if path == "" {
return nil
}
if err := os.Remove(path); err != nil && !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("remove staged file at %s: %w", path, err)
}
return nil
}
func joinTransactionFailure(cause error, related []error, label string) error {
if len(related) == 0 {
return cause