feat(go): durable transaction engine and Kiro IDE 1.0 adapter

Split the monolithic transaction into focused modules: append-only
crash-recoverable journal under ~/.elydora/transactions with owner
tokens and per-transaction namespaces, staged atomic publication
(stage .pending, fsync, rename, fsync), platform-specific atomic
replacement (MoveFileEx, renameat2, renamex_np), private-directory
hardening per OS, lock-guarded recovery, and workspace cleanup that
removes only transaction-created empty directories.

Add the Kiro IDE 1.0 plugin: strict v1 hook schema with one enabled
PreToolUse guard and PostToolUse audit pair bound to the active
workspace, agent-to-workspace identity binding in runtime config, and
exact migration of the legacy elydora-audit.kiro.hook contract.

Gates: go test ./... and -race pass, go vet clean, govulncheck reports
zero reachable vulnerabilities, git diff --check clean.
This commit is contained in:
ZacharyZhang-NY committed 2026-07-21 19:02:57 -04:00
1 parent dd72793cdb
commit eb41b991bf
70 files changed
+8182 -358

No files matched your search

+192
View File
@@ -0,0 +1,192 @@
package plugins
import (
"fmt"
"os"
"path/filepath"
)
type kiroIdePaths struct {
homeDirectory string
workspaceRoot string
kiroDirectory string
hooksDirectory string
configPath string
legacyPath string
}
type kiroIdeSources struct {
paths *kiroIdePaths
document *kiroIdeDocument
legacy *kiroIdeLegacyDocument
initialDirectories []kiroIdeDirectoryIdentity
}
func resolveKiroIdePaths() (*kiroIdePaths, error) {
workspace, err := os.Getwd()
if err != nil {
return nil, fmt.Errorf("resolve Kiro IDE workspace: %w", err)
}
workspace, err = filepath.Abs(workspace)
if err != nil {
return nil, fmt.Errorf("resolve Kiro IDE workspace path: %w", err)
}
home, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("resolve home directory: %w", err)
}
kiroDirectory := filepath.Join(workspace, ".kiro")
hooksDirectory := filepath.Join(kiroDirectory, "hooks")
return &kiroIdePaths{
homeDirectory: home, workspaceRoot: workspace,
kiroDirectory: kiroDirectory, hooksDirectory: hooksDirectory,
configPath: filepath.Join(hooksDirectory, kiroIdeConfigFile),
legacyPath: filepath.Join(home, ".kiro", "hooks", kiroIdeLegacyFile),
}, nil
}
func inspectKiroIdeWorkspace(paths *kiroIdePaths) error {
exists, err := managedPhysicalDirectoryExists(
paths.workspaceRoot,
"Kiro IDE workspace",
)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("Kiro IDE workspace is missing: %s", paths.workspaceRoot)
}
if _, err := managedPhysicalDirectoryExists(
paths.kiroDirectory,
"Kiro IDE configuration directory",
); err != nil {
return err
}
_, err = managedPhysicalDirectoryExists(
paths.hooksDirectory,
"Kiro IDE hooks directory",
)
return err
}
func inspectKiroIdeLegacyDirectories(paths *kiroIdePaths) error {
kiroDirectory := filepath.Dir(filepath.Dir(paths.legacyPath))
hooksDirectory := filepath.Dir(paths.legacyPath)
for _, item := range []struct{ path, label string }{
{kiroDirectory, "legacy Kiro IDE configuration directory"},
{hooksDirectory, "legacy Kiro IDE hooks directory"},
} {
exists, err := managedPhysicalDirectoryExists(item.path, item.label)
if err != nil {
return err
}
if !exists {
return fmt.Errorf("%s is missing: %s", item.label, item.path)
}
}
return nil
}
func readKiroIdeSources() (*kiroIdeSources, error) {
paths, err := resolveKiroIdePaths()
if err != nil {
return nil, err
}
initialDirectories := make([]kiroIdeDirectoryIdentity, 0, 5)
for _, item := range []struct{ path, label string }{
{paths.workspaceRoot, "Kiro IDE workspace"},
{paths.kiroDirectory, "Kiro IDE configuration directory"},
{paths.hooksDirectory, "Kiro IDE hooks directory"},
} {
identity, err := snapshotKiroIdeDirectory(item.path, item.label)
if err != nil {
return nil, err
}
initialDirectories = append(initialDirectories, identity)
}
if err := inspectKiroIdeWorkspace(paths); err != nil {
return nil, err
}
workspaceSnapshot, err := readManagedFile(
paths.configPath,
"Kiro IDE hooks",
maxManagedSourceBytes,
)
if err != nil {
return nil, err
}
document, err := parseKiroIdeDocument(paths.configPath, workspaceSnapshot)
if err != nil {
return nil, err
}
legacySnapshot, err := readManagedFile(
paths.legacyPath,
"legacy Kiro IDE hook",
maxManagedSourceBytes,
)
if err != nil {
return nil, err
}
if legacySnapshot != nil {
if err := inspectKiroIdeLegacyDirectories(paths); err != nil {
return nil, err
}
for _, item := range []struct{ path, label string }{
{
filepath.Dir(filepath.Dir(paths.legacyPath)),
"legacy Kiro IDE configuration directory",
},
{filepath.Dir(paths.legacyPath), "legacy Kiro IDE hooks directory"},
} {
identity, err := snapshotKiroIdeDirectory(item.path, item.label)
if err != nil {
return nil, err
}
initialDirectories = append(initialDirectories, identity)
}
current, err := readManagedFile(
paths.legacyPath,
"legacy Kiro IDE hook",
maxManagedSourceBytes,
)
if err != nil {
return nil, err
}
if !sameManagedSnapshot(current, legacySnapshot) {
return nil, fmt.Errorf(
"legacy Kiro IDE hook changed while reading: %s",
paths.legacyPath,
)
}
}
legacy, err := parseKiroIdeLegacyDocument(paths.legacyPath, legacySnapshot)
if err != nil {
return nil, err
}
if err := assertKiroIdeDirectoryStates(
initialDirectories,
"Kiro IDE source read",
); err != nil {
return nil, err
}
return &kiroIdeSources{
paths: paths, document: document, legacy: legacy,
initialDirectories: initialDirectories,
}, nil
}
func prepareRenderedKiroIdeChange(
rendered *kiroIdeRenderedDocument,
) (*fileChange, error) {
if rendered == nil || !rendered.changed {
return nil, nil
}
return prepareSnapshotSourceChange(
rendered.document.filePath,
"Kiro IDE hooks",
rendered.document.snapshot,
rendered.next,
0600,
rendered.remove,
)
}