Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# go-scm Agent Notes

This repository follows the core/go v0.9.0 consumer layout:

- Go module source lives under `go/`.
- The repository root owns `go.work`.
- Local dependency checkouts live under `external/` and must not be edited directly.

Use `dappco.re/go` primitives instead of banned standard-library imports in consumer code. Public symbols require matching Good, Bad, and Ugly tests plus examples in the source file's sibling test files.
9 changes: 9 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Architecture

`go-scm` is split into small packages around source-control workflows:

- `git`, `repos`, `forge`, and `gitea` wrap repository and forge operations.
- `manifest`, `marketplace`, and `plugin` manage package metadata and installation.
- `collect` and `jobrunner` support automation and agent CI workflows.

Packages should depend on `dappco.re/go` for filesystem, JSON, string, path, error, and process primitives.
15 changes: 15 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Development

Run module commands from `go/` with workspace mode disabled for release-compatible checks:

```sh
GOWORK=off GOPROXY=direct GOSUMDB=off go build ./...
GOWORK=off GOPROXY=direct GOSUMDB=off go vet ./...
GOWORK=off GOPROXY=direct GOSUMDB=off go test -count=1 -short ./...
```

Run the v0.9.0 audit from the repository root:

```sh
bash /Users/snider/Code/core/go/tests/cli/v090-upgrade/audit.sh .
```
9 changes: 9 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# go-scm

`go-scm` contains source-control, forge, marketplace, plugin, and agent CI helpers built on the `dappco.re/go` core primitives.

## Layout

- `go/` contains the Go module.
- `external/` contains local submodule dependencies used by `go.work`.
- `docs/` contains architecture and development notes.
2 changes: 1 addition & 1 deletion go.work
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ go 1.26.2
use (
./go
./external/go
./external/config
./external/config/go
./external/io
./external/ws
./external/log
Expand Down
85 changes: 85 additions & 0 deletions go.work.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cyphar.com/go-pathrs v0.2.1 h1:9nx1vOgwVvX1mNBWDu93+vaceedpbsDqo+XuBGL40b8=
cyphar.com/go-pathrs v0.2.1/go.mod h1:y8f1EMG7r+hCuFf/rXsKqMJrJAUoADZGNh5/vZPKcGc=
dappco.re/go/core v0.8.0-alpha.1 h1:gj7+Scv+L63Z7wMxbJYHhaRFkHJo2u4MMPuUSv/Dhtk=
dappco.re/go/core v0.8.0-alpha.1/go.mod h1:f2/tBZ3+3IqDrg2F5F598llv0nmb/4gJVCFzM5geE4A=
github.com/bep/debounce v1.2.1 h1:v67fRdBA9UQu2NhLFXrSg0Brw7CexQekrBwDMM8bzeY=
github.com/bep/debounce v1.2.1/go.mod h1:H8yggRPQKLUhUoqrJC1bO2xNya7vanpDl7xR3ISbCJ0=
github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ=
github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ=
github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1 h1:njuLRcjAuMKr7kI3D85AXWkw6/+v9PwtV6M6o11sWHQ=
github.com/jchv/go-winloader v0.0.0-20250406163304-c1995be93bd1/go.mod h1:alcuEEnZsY1WQsagKhZDsoPCRoOijYqhZvPwLG0kzVs=
github.com/jordanlewis/gcassert v0.0.0-20250430164644-389ef753e22e h1:a+PGEeXb+exwBS3NboqXHyxarD9kaboBbrSp+7GuBuc=
github.com/jordanlewis/gcassert v0.0.0-20250430164644-389ef753e22e/go.mod h1:ZybsQk6DWyN5t7An1MuPm1gtSZ1xDaTXS9ZjIOxvQrk=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c=
github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4=
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/leaanthony/go-ansi-parser v1.6.1 h1:xd8bzARK3dErqkPFtoF9F3/HgN8UQk0ed1YDKpEz01A=
github.com/leaanthony/go-ansi-parser v1.6.1/go.mod h1:+vva/2y4alzVmmIEpk9QDhA7vLC5zKDTRwfZGOp3IWU=
github.com/leaanthony/gosod v1.0.4 h1:YLAbVyd591MRffDgxUOU1NwLhT9T1/YiwjKZpkNFeaI=
github.com/leaanthony/gosod v1.0.4/go.mod h1:GKuIL0zzPj3O1SdWQOdgURSuhkF+Urizzxh26t9f1cw=
github.com/leaanthony/slicer v1.6.0 h1:1RFP5uiPJvT93TAHi+ipd3NACobkW53yUiBqZheE/Js=
github.com/leaanthony/slicer v1.6.0/go.mod h1:o/Iz29g7LN0GqH3aMjWAe90381nyZlDNquK+mtH2Fj8=
github.com/leaanthony/u v1.1.1 h1:TUFjwDGlNX+WuwVEzDqQwC2lOv0P4uhTQw7CMFdiK7M=
github.com/leaanthony/u v1.1.1/go.mod h1:9+o6hejoRljvZ3BzdYlVL0JYCwtnAsVuN9pVTQcaRfI=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/samber/lo v1.52.0 h1:Rvi+3BFHES3A8meP33VPAxiBZX/Aws5RxrschYGjomw=
github.com/samber/lo v1.52.0/go.mod h1:4+MXEGsJzbKGaUEQFKBq2xtfuznW9oz/WrgyzMzRoM0=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/tkrajina/go-reflector v0.5.8 h1:yPADHrwmUbMq4RGEyaOUpz2H90sRsETNVpjzo3DLVQQ=
github.com/tkrajina/go-reflector v0.5.8/go.mod h1:ECbqLgccecY5kPmPmXg1MrHW585yMcDkVl6IvJe64T4=
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/wailsapp/go-webview2 v1.0.23 h1:jmv8qhz1lHibCc79bMM/a/FqOnnzOGEisLav+a0b9P0=
github.com/wailsapp/go-webview2 v1.0.23/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
github.com/wailsapp/wails/v2 v2.11.0 h1:seLacV8pqupq32IjS4Y7V8ucab0WZwtK6VvUVxSBtqQ=
github.com/wailsapp/wails/v2 v2.11.0/go.mod h1:jrf0ZaM6+GBc1wRmXsM8cIvzlg0karYin3erahI4+0k=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.2.0 h1:bYKF2AEwG5rqd1BumT4gAnvwU/M9nBp2pTSxeZw7Wvs=
github.com/xdg-go/scram v1.2.0/go.mod h1:3dlrS0iBaWKYVt2ZfA4cj48umJZ+cAEbR6/SjLA88I8=
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
28 changes: 14 additions & 14 deletions go/agentci/agentci_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package agentci

import (
"context"
"path/filepath"
`path/filepath`

core "dappco.re/go"
"dappco.re/go/config"
Expand All @@ -20,14 +20,14 @@ const (
sonarAgentciTestEchoReady = "echo ready"
)

func ax7AgentConfig(t *core.T) *config.Config {
func testAgentConfig(t *core.T) *config.Config {
r := config.New(config.WithPath(filepath.Join(t.TempDir(), "config.yaml")))
core.RequireNoError(t, configResultError(r))
return core.MustCast[*config.Config](r)
}

func TestAgentci_LoadAgents_Good(t *core.T) {
cfg := ax7AgentConfig(t)
cfg := testAgentConfig(t)
core.RequireNoError(t, configResultError(cfg.Set("agents", map[string]AgentConfig{"codex": {Active: true, Roles: []string{"coder"}}})))
agents, err := LoadAgents(cfg)
core.AssertNoError(t, err)
Expand All @@ -41,7 +41,7 @@ func TestAgentci_LoadAgents_Bad(t *core.T) {
}

func TestAgentci_LoadAgents_Ugly(t *core.T) {
cfg := ax7AgentConfig(t)
cfg := testAgentConfig(t)
core.RequireNoError(t, configResultError(cfg.Set("agents", map[string]AgentConfig{"codex": {Roles: []string{"coder"}}})))
agents, err := LoadAgents(cfg)
core.AssertNoError(t, err)
Expand All @@ -52,7 +52,7 @@ func TestAgentci_LoadAgents_Ugly(t *core.T) {
}

func TestAgentci_ListAgents_Good(t *core.T) {
cfg := ax7AgentConfig(t)
cfg := testAgentConfig(t)
core.RequireNoError(t, configResultError(cfg.Set("agents", map[string]AgentConfig{"codex": {Active: true}})))
agents, err := ListAgents(cfg)
core.AssertNoError(t, err)
Expand All @@ -66,14 +66,14 @@ func TestAgentci_ListAgents_Bad(t *core.T) {
}

func TestAgentci_ListAgents_Ugly(t *core.T) {
cfg := ax7AgentConfig(t)
cfg := testAgentConfig(t)
agents, err := ListAgents(cfg)
core.AssertNoError(t, err)
core.AssertEmpty(t, agents)
}

func TestAgentci_LoadActiveAgents_Good(t *core.T) {
cfg := ax7AgentConfig(t)
cfg := testAgentConfig(t)
core.RequireNoError(t, configResultError(cfg.Set("agents", map[string]AgentConfig{"codex": {Active: true}, "idle": {Active: false}})))
agents, err := LoadActiveAgents(cfg)
core.AssertNoError(t, err)
Expand All @@ -88,15 +88,15 @@ func TestAgentci_LoadActiveAgents_Bad(t *core.T) {
}

func TestAgentci_LoadActiveAgents_Ugly(t *core.T) {
cfg := ax7AgentConfig(t)
cfg := testAgentConfig(t)
core.RequireNoError(t, configResultError(cfg.Set("agents", map[string]AgentConfig{"idle": {Active: false}})))
agents, err := LoadActiveAgents(cfg)
core.AssertNoError(t, err)
core.AssertEmpty(t, agents)
}

func TestAgentci_LoadClothoConfig_Good(t *core.T) {
cfg := ax7AgentConfig(t)
cfg := testAgentConfig(t)
core.RequireNoError(t, configResultError(cfg.Set("clotho", map[string]any{"strategy": sonarAgentciTestClothoVerified, "validation_threshold": 0.75})))
got, err := LoadClothoConfig(cfg)
core.AssertNoError(t, err)
Expand All @@ -105,7 +105,7 @@ func TestAgentci_LoadClothoConfig_Good(t *core.T) {
}

func TestAgentci_LoadClothoConfig_Bad(t *core.T) {
cfg := ax7AgentConfig(t)
cfg := testAgentConfig(t)
core.RequireNoError(t, configResultError(cfg.Set("clotho", map[string]any{"strategy": "unknown"})))
_, err := LoadClothoConfig(cfg)
core.AssertError(t, err)
Expand All @@ -119,7 +119,7 @@ func TestAgentci_LoadClothoConfig_Ugly(t *core.T) {
}

func TestAgentci_SaveAgent_Good(t *core.T) {
cfg := ax7AgentConfig(t)
cfg := testAgentConfig(t)
err := SaveAgent(cfg, "codex", AgentConfig{Host: sonarAgentciTestAgentLocal, Active: true})
core.AssertNoError(t, err)
agents, loadErr := LoadAgents(cfg)
Expand All @@ -135,14 +135,14 @@ func TestAgentci_SaveAgent_Bad(t *core.T) {
}

func TestAgentci_SaveAgent_Ugly(t *core.T) {
err := SaveAgent(ax7AgentConfig(t), "", AgentConfig{})
err := SaveAgent(testAgentConfig(t), "", AgentConfig{})
core.AssertError(
t, err,
)
}

func TestAgentci_RemoveAgent_Good(t *core.T) {
cfg := ax7AgentConfig(t)
cfg := testAgentConfig(t)
core.RequireNoError(t, SaveAgent(cfg, "codex", AgentConfig{Active: true}))
err := RemoveAgent(cfg, "codex")
core.AssertNoError(t, err)
Expand All @@ -160,7 +160,7 @@ func TestAgentci_RemoveAgent_Bad(t *core.T) {
}

func TestAgentci_RemoveAgent_Ugly(t *core.T) {
err := RemoveAgent(ax7AgentConfig(t), "")
err := RemoveAgent(testAgentConfig(t), "")
core.AssertError(
t, err,
)
Expand Down
2 changes: 1 addition & 1 deletion go/agentci/clotho.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (s *Spinner) GetVerifierModel(agentName string) string {
}

// Weave compares primary and verifier outputs. Returns true if they converge.
func (s *Spinner) Weave(ctx context.Context, primaryOutput, signedOutput []byte) (bool, error) {
func (s *Spinner) Weave(ctx context.Context, primaryOutput, signedOutput []byte) (bool, error) /* v090-result-boundary */ {
if ctx != nil {
if err := ctx.Err(); err != nil {
return false, err
Expand Down
23 changes: 23 additions & 0 deletions go/agentci/clotho_example_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: EUPL-1.2

package agentci

func ExampleNewSpinner() {
_ = "NewSpinner"
}

func ExampleSpinner_DeterminePlan() {
_ = "Spinner_DeterminePlan"
}

func ExampleSpinner_FindByForgejoUser() {
_ = "Spinner_FindByForgejoUser"
}

func ExampleSpinner_GetVerifierModel() {
_ = "Spinner_GetVerifierModel"
}

func ExampleSpinner_Weave() {
_ = "Spinner_Weave"
}
Loading
Loading