Skip to content

feat(hooks): opt-in auto-lint + auto-test after every edit (#376) - #403

Closed
Delqhi wants to merge 1 commit into
mainfrom
feat/auto-lint-test
Closed

feat(hooks): opt-in auto-lint + auto-test after every edit (#376)#403
Delqhi wants to merge 1 commit into
mainfrom
feat/auto-lint-test

Conversation

@Delqhi

@Delqhi Delqhi commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Auto-lint + auto-test after sin_write/sin_edit, opt-in. 5 tests race-clean.

Adds two programmatic PostListeners to the agent loop's tool.post
event so the operator can opt in to:\n
  - agentloop.auto_lint=true \u2014 after every sin_write/sin_edit to a
    .go file: gofmt -l + go vet on the file's package, advisory only.\n
  - agentloop.auto_test=true \u2014 after every sin_write/sin_edit to a
    *_test.go file: go test -race -count=1 on the file's package,
    advisory (may mutate state).\n
Both default off (legacy behaviour preserved). Both can be overridden
via agentloop.auto_lint_timeout / agentloop.auto_test_timeout.\n
Implementation:\n
- internal/hooks: new PostListener type + Engine.RegisterPostListener.\n
  Engine.Fire invokes registered listeners on tool.post events in\n
  registration order; their return values are merged into Result.\n
  PromptInjects so the agent sees the feedback in its next turn.\n
  Listeners never block (tool.post is not in the blockable set).\n
  safeInvokePostListener recovers from any panic so a misbehaving\n
  listener cannot crash the agent loop.\n
- internal/hooks/auto_hook.go: AutoLintListener + AutoTestListener\n
  + AutoHookConfig + AutoLintDefaultTimeout=30s /\n
  AutoTestDefaultTimeout=120s.\n
- internal/hooks/auto_hook_test.go: 5 tests including the 3 required\n
  (TestAutoLintFiresAfterSinEdit / TestAutoTestFiresAfterTestFileEdit\n
  / TestAutoLintDisabledByDefault) plus nil-engine and panic-recovery.\n
- internal/config.go: 4 new keys (auto_lint, auto_test, auto_lint_timeout,\n
  auto_test_timeout) wired through SinCodeConfig defaults, TOML\n
  template, get/set/parsers/pairs output.\n
- cmd/sin-code/chat_cmd.go: --help advertises the new opt-ins\n
  ("set agentloop.auto_lint=true to auto-lint after edits") and\n
  registers the listeners on the hook engine only when the operator\n
  has opted in via config.\n
Constraints honored:\n
- Opt-in: both default false (legacy single-shot behaviour preserved).\n
- read-only lint vs mutating test documented in --help.\n
- Hooks emit warnings only (PromptInject + stderr) and never block.\n
- go test -race -count=1 of internal/hooks passes; session-mutating\n
  tests properly skip when go / gofmt binaries are missing.\n
@Delqhi Delqhi added the enhancement New feature or request label Jun 18, 2026
@vercel

vercel Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
sin-code Ready Ready Preview, Comment, Open in v0 Jun 18, 2026 6:13pm

@github-actions

Copy link
Copy Markdown

🏆 CEO Audit — A+ (100.0/100)

Metric Value
Grade A+
Score 100.0/100
Critical findings 0
High findings 0
Profile QUICK
Min grade gate B

📥 Download full report (Markdown)
📊 Download SARIF (for Code Scanning)

Run ~/.config/opencode/skills/ceo-audit/scripts/audit.sh . --profile=QUICK locally to reproduce.

@github-actions

Copy link
Copy Markdown

🏆 CEO Audit — A+ (100.0/100)

Metric Value
Grade A+
Score 100.0/100
Critical findings 0
High findings 0
Medium findings 0
Profile QUICK
Min grade gate B

📥 Download full report (Markdown)

Run ID: 27779950695 · Commit: ${github.sha}

Run ~/.config/opencode/skills/ceo-audit/scripts/audit.sh . --profile=QUICK locally to reproduce.

}
gofmtCtx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
gofmtCmd := exec.CommandContext(gofmtCtx, "gofmt", "-l", goFile)
if cmdWorkdir == "" {
cmdWorkdir = "."
}
vetCmd := exec.CommandContext(vetCtx, "go", "vet", "./"+pkgDir)
"./" + filepath.Base(dirOfFile),
"-count=1",
}
cmd := exec.CommandContext(ctx, "go", args...)
Comment thread cmd/sin-code/chat_cmd.go
}

hookEngine := chatNewHooksFn(loadHooks(workspace))
// --- post-edit auto listeners (issue #376) ------------------
Comment thread cmd/sin-code/chat_cmd.go
// --- post-edit auto listeners (issue #376) ------------------
// Register the lint + test listeners ONLY when the operator has opted
// in via config. Default behaviour (no listener registered) preserves
// the legacy single-shot semantics and stays off in headless / CI runs.
@Delqhi

Delqhi commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator Author

Closing as duplicate. Issue #376 (Auto-lint + auto-test after edits) was already shipped by a parallel agent on main:

  • Already committed: cmd/sin-code/internal/agentloop/auto_hook.go
  • This branch feat/auto-lint-test was created from an older snapshot of main; merging would create conflicts and risk deleting parallel agent work.
  • The shipped implementation lives on current main (see commits by parallel agents).

@Delqhi Delqhi closed this Jun 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants