refactor(monorepo): extract coord-core
This commit is contained in:
+1
-1
@@ -12,7 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/app"
|
"ai-workflow-skill/internal/app"
|
||||||
"ai-workflow-skill/internal/db"
|
"ai-workflow-skill/packages/coord-core/db"
|
||||||
"ai-workflow-skill/internal/httpapi"
|
"ai-workflow-skill/internal/httpapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ As of now:
|
|||||||
- the first real Phase 2 read-only operator UI is now implemented in `apps/web`, including routed runs list, run detail, blocked queue, and thread timeline views backed by the existing `orchd` HTTP API, plus Tailwind v4 consumer wiring so the source-owned Cadence UI components render correctly in the app
|
- the first real Phase 2 read-only operator UI is now implemented in `apps/web`, including routed runs list, run detail, blocked queue, and thread timeline views backed by the existing `orchd` HTTP API, plus Tailwind v4 consumer wiring so the source-owned Cadence UI components render correctly in the app
|
||||||
- a repository-level skill workspace monorepo migration plan now exists under `docs/skill-workspace-monorepo.md`, defining the target split between runtime packages under `packages/`, agent-facing skill bundles under `skills/`, support apps under `apps/`, and package-based skill packaging flows
|
- a repository-level skill workspace monorepo migration plan now exists under `docs/skill-workspace-monorepo.md`, defining the target split between runtime packages under `packages/`, agent-facing skill bundles under `skills/`, support apps under `apps/`, and package-based skill packaging flows
|
||||||
- the first migration phase for the skill workspace monorepo is now complete: root `go.work` exists, `pnpm-workspace.yaml` now discovers `packages/*`, empty runtime module roots now exist under `packages/`, and a declarative `scripts/skill-bundles.json` plus `scripts/package_skill_runtimes.sh` scaffold now define package-oriented skill bundle metadata from the repo root
|
- the first migration phase for the skill workspace monorepo is now complete: root `go.work` exists, `pnpm-workspace.yaml` now discovers `packages/*`, empty runtime module roots now exist under `packages/`, and a declarative `scripts/skill-bundles.json` plus `scripts/package_skill_runtimes.sh` scaffold now define package-oriented skill bundle metadata from the repo root
|
||||||
|
- `packages/coord-core` now exists as the first real extracted runtime package, containing shared coordination DB/schema, protocol, and store code, and the active coordination runtimes now import `coord-core` instead of root `internal/db`, `internal/store`, and `internal/protocol`
|
||||||
- a repo-local `scripts/package_skill_clis.sh` packaging flow now builds bundled skill CLI assets for `inbox`, `orch`, and `council-review`
|
- a repo-local `scripts/package_skill_clis.sh` packaging flow now builds bundled skill CLI assets for `inbox`, `orch`, and `council-review`
|
||||||
- `orch` now implements `run init/show`, `task add`, `dep add`, `ready`, `dispatch`, `reconcile`, `wait`, `blocked`, `answer`, `retry`, `reassign`, `cancel`, `cleanup`, and `status`
|
- `orch` now implements `run init/show`, `task add`, `dep add`, `ready`, `dispatch`, `reconcile`, `wait`, `blocked`, `answer`, `retry`, `reassign`, `cancel`, `cleanup`, and `status`
|
||||||
- `orch` can create runs, gate tasks through dependencies, dispatch work through `inbox`, reconcile worker thread state back into task state, answer blocked tasks, retry or reassign work, cancel tasks or runs, clean attempt worktrees, and create per-attempt Git worktrees during strict dispatch
|
- `orch` can create runs, gate tasks through dependencies, dispatch work through `inbox`, reconcile worker thread state back into task state, answer blocked tasks, retry or reassign work, cancel tasks or runs, clean attempt worktrees, and create per-attempt Git worktrees during strict dispatch
|
||||||
@@ -495,10 +496,14 @@ Completed so far:
|
|||||||
- initial module roots now exist for `packages/coord-core`, `packages/inbox-runtime`, `packages/orch-runtime`, `packages/orchd-runtime`, and `packages/repo-memory-runtime`
|
- initial module roots now exist for `packages/coord-core`, `packages/inbox-runtime`, `packages/orch-runtime`, `packages/orchd-runtime`, and `packages/repo-memory-runtime`
|
||||||
- `scripts/skill-bundles.json` now records the first package-oriented skill bundle metadata, including the future `repo-memory` runtime mapping
|
- `scripts/skill-bundles.json` now records the first package-oriented skill bundle metadata, including the future `repo-memory` runtime mapping
|
||||||
- `scripts/package_skill_runtimes.sh` now provides a declarative bundle plan/validate scaffold that targets package paths rather than hardcoded root runtime paths
|
- `scripts/package_skill_runtimes.sh` now provides a declarative bundle plan/validate scaffold that targets package paths rather than hardcoded root runtime paths
|
||||||
|
- `packages/coord-core/db` now owns the shared SQLite open, pragmas, migrations, and coordination schema files
|
||||||
|
- `packages/coord-core/protocol` now owns the shared JSON and CLI error helpers used across the coordination stack
|
||||||
|
- `packages/coord-core/store` now owns the shared inbox, orch, and council store logic plus its coordination-domain tests
|
||||||
|
- root coordination runtimes under `cmd/`, `internal/cli/`, `internal/app/`, `internal/httpapi/`, and `internal/query/` now import `coord-core` instead of depending on root `internal/db`, `internal/store`, or root `internal/protocol`
|
||||||
|
- `go test ./...` still passes for the root module, and `go test ./...` passes inside `packages/coord-core`
|
||||||
|
|
||||||
Remaining:
|
Remaining:
|
||||||
|
|
||||||
- extract shared coordination code into `packages/coord-core`
|
|
||||||
- extract `inbox`, `orch`, and `orchd` into package-owned runtimes
|
- extract `inbox`, `orch`, and `orchd` into package-owned runtimes
|
||||||
- import `repo-memory` as its own runtime package and add the corresponding skill bundle
|
- import `repo-memory` as its own runtime package and add the corresponding skill bundle
|
||||||
- graduate the bundle scaffold into the primary packaging flow once package-owned runtime entrypoints exist
|
- graduate the bundle scaffold into the primary packaging flow once package-owned runtime entrypoints exist
|
||||||
@@ -509,12 +514,12 @@ If a new agent is taking over now, the next concrete step should be:
|
|||||||
|
|
||||||
1. treat `Milestone 9: Web Product Phase 2 Read-Only Operator UI` as complete for the initial operator surface and do not expand web feature scope further until the workspace split is decided package-by-package
|
1. treat `Milestone 9: Web Product Phase 2 Read-Only Operator UI` as complete for the initial operator surface and do not expand web feature scope further until the workspace split is decided package-by-package
|
||||||
2. treat the Phase 1 workspace bootstrap for `Milestone 10` as complete and keep the new `go.work`, `packages/`, and declarative bundle metadata as the baseline for all further migration steps
|
2. treat the Phase 1 workspace bootstrap for `Milestone 10` as complete and keep the new `go.work`, `packages/`, and declarative bundle metadata as the baseline for all further migration steps
|
||||||
3. extract the shared coordination kernel into `packages/coord-core` before moving `inbox`, `orch`, or `orchd` into package-owned runtimes
|
3. treat the shared coordination kernel extraction into `packages/coord-core` as complete and move `inbox` plus `orch` into package-owned runtimes next
|
||||||
4. keep the authored skill forward-test plans under `docs/tests/*-skill/` synchronized as runtime ownership moves from root paths to package paths
|
4. keep the authored skill forward-test plans under `docs/tests/*-skill/` synchronized as runtime ownership moves from root paths to package paths
|
||||||
5. keep the legacy hardcoded packaging flow working temporarily, but evolve the new declarative bundle scaffold into the primary packaging path before adding `repo-memory`
|
5. keep the legacy hardcoded packaging flow working temporarily, but evolve the new declarative bundle scaffold into the primary packaging path before adding `repo-memory`
|
||||||
6. import `repo-memory` only after the package-based runtime and skill packaging pattern exists
|
6. import `repo-memory` only after the package-based runtime and skill packaging pattern exists
|
||||||
|
|
||||||
The inbox implementation and its human-readable test-plan set are already in place, `orch` supports the main scheduler loop plus the complete council start/wait/tally/report workflow, the web product now has its first real operator-facing read surfaces, and the repository has finished the first workspace-bootstrap phase of the skill monorepo migration, so the next step should be package extraction rather than continuing to accrete new root-owned runtimes.
|
The inbox implementation and its human-readable test-plan set are already in place, `orch` supports the main scheduler loop plus the complete council start/wait/tally/report workflow, the web product now has its first real operator-facing read surfaces, and the repository has completed both the workspace bootstrap and the shared coordination-kernel extraction phases of the skill monorepo migration, so the next step should be runtime extraction rather than continuing to accrete new root-owned runtimes.
|
||||||
|
|
||||||
## Recommended Driver Choices
|
## Recommended Driver Choices
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
- [x] create or adopt an active execution roadmap for the migration workstream
|
- [x] create or adopt an active execution roadmap for the migration workstream
|
||||||
- [x] Phase 1: bootstrap `go.work`, expanded workspace manifests, package roots, and declarative skill bundle metadata
|
- [x] Phase 1: bootstrap `go.work`, expanded workspace manifests, package roots, and declarative skill bundle metadata
|
||||||
- [ ] Phase 2: extract shared coordination code into `packages/coord-core`
|
- [x] Phase 2: extract shared coordination code into `packages/coord-core`
|
||||||
- [ ] Phase 3: extract `inbox-runtime` and `orch-runtime`
|
- [ ] Phase 3: extract `inbox-runtime` and `orch-runtime`
|
||||||
- [ ] Phase 4: extract `orchd-runtime`
|
- [ ] Phase 4: extract `orchd-runtime`
|
||||||
- [ ] Phase 5: import `repo-memory-runtime` and add `skills/repo-memory`
|
- [ ] Phase 5: import `repo-memory-runtime` and add `skills/repo-memory`
|
||||||
@@ -54,4 +54,4 @@
|
|||||||
|
|
||||||
## Next Step
|
## Next Step
|
||||||
|
|
||||||
- start Phase 2 by extracting the shared coordination kernel into `packages/coord-core`, using the new workspace and bundle metadata scaffold as the stable base for subsequent package moves
|
- start Phase 3 by moving `inbox` and `orch` into package-owned runtimes on top of the now-shared `packages/coord-core` kernel
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/query"
|
"ai-workflow-skill/internal/query"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebService struct {
|
type WebService struct {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package inbox
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package inbox
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resolveBodyValue(body, bodyFile string) (string, error) {
|
func resolveBodyValue(body, bodyFile string) (string, error) {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package inbox
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/db"
|
"ai-workflow-skill/packages/coord-core/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
func openInboxDB(ctx context.Context, dbPath string) (*sql.DB, error) {
|
func openInboxDB(ctx context.Context, dbPath string) (*sql.DB, error) {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package inbox
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Execute(args []string, stdout, stderr io.Writer) int {
|
func Execute(args []string, stdout, stderr io.Writer) int {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package inbox
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package inbox
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package inbox
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package inbox
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package inbox
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package inbox
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package inbox
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
)
|
)
|
||||||
|
|
||||||
func resolveBodyValue(body, bodyFile string) (string, error) {
|
func resolveBodyValue(body, bodyFile string) (string, error) {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/db"
|
"ai-workflow-skill/packages/coord-core/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
func openOrchDB(ctx context.Context, dbPath string) (*sql.DB, error) {
|
func openOrchDB(ctx context.Context, dbPath string) (*sql.DB, error) {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Execute(args []string, stdout, stderr io.Writer) int {
|
func Execute(args []string, stdout, stderr io.Writer) int {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package orch
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/protocol"
|
"ai-workflow-skill/packages/coord-core/protocol"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
type errorEnvelope struct {
|
type errorEnvelope struct {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/query"
|
"ai-workflow-skill/internal/query"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
type readService interface {
|
type readService interface {
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/app"
|
"ai-workflow-skill/internal/app"
|
||||||
dbpkg "ai-workflow-skill/internal/db"
|
dbpkg "ai-workflow-skill/packages/coord-core/db"
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRouterExposesReadOnlyWebEndpoints(t *testing.T) {
|
func TestRouterExposesReadOnlyWebEndpoints(t *testing.T) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"ai-workflow-skill/internal/store"
|
"ai-workflow-skill/packages/coord-core/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ReadService struct {
|
type ReadService struct {
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed schema/*.sql
|
||||||
|
var schemaFS embed.FS
|
||||||
|
|
||||||
|
func ApplyMigrations(ctx context.Context, db *sql.DB) error {
|
||||||
|
files, err := schemaFS.ReadDir("schema")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("read embedded schema directory: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
names := make([]string, 0, len(files))
|
||||||
|
for _, file := range files {
|
||||||
|
if file.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
names = append(names, file.Name())
|
||||||
|
}
|
||||||
|
sort.Strings(names)
|
||||||
|
|
||||||
|
tx, err := db.BeginTx(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("begin schema transaction: %w", err)
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
content, err := schemaFS.ReadFile("schema/" + name)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("read embedded schema file %q: %w", name, err)
|
||||||
|
}
|
||||||
|
if _, err := tx.ExecContext(ctx, string(content)); err != nil {
|
||||||
|
return fmt.Errorf("apply schema file %q: %w", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tx.Commit(); err != nil {
|
||||||
|
return fmt.Errorf("commit schema transaction: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
_ "modernc.org/sqlite"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Open(ctx context.Context, dbPath string) (*sql.DB, error) {
|
||||||
|
if err := ensureParentDir(dbPath); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
db, err := sql.Open("sqlite", dbPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("open sqlite database: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := applyPragmas(ctx, db); err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureParentDir(dbPath string) error {
|
||||||
|
parent := filepath.Dir(dbPath)
|
||||||
|
if parent == "." || parent == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.MkdirAll(parent, 0o755)
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func applyPragmas(ctx context.Context, db *sql.DB) error {
|
||||||
|
pragmas := []string{
|
||||||
|
"PRAGMA foreign_keys = ON;",
|
||||||
|
"PRAGMA journal_mode = WAL;",
|
||||||
|
"PRAGMA busy_timeout = 5000;",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pragma := range pragmas {
|
||||||
|
if _, err := db.ExecContext(ctx, pragma); err != nil {
|
||||||
|
return fmt.Errorf("apply pragma %q: %w", pragma, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS threads (
|
||||||
|
thread_id TEXT PRIMARY KEY,
|
||||||
|
run_id TEXT NOT NULL,
|
||||||
|
task_id TEXT NOT NULL,
|
||||||
|
subject TEXT NOT NULL,
|
||||||
|
created_by TEXT NOT NULL,
|
||||||
|
assigned_to TEXT NOT NULL,
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
priority TEXT NOT NULL DEFAULT 'normal',
|
||||||
|
latest_message_id TEXT,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS messages (
|
||||||
|
message_id TEXT PRIMARY KEY,
|
||||||
|
thread_id TEXT NOT NULL,
|
||||||
|
from_agent TEXT NOT NULL,
|
||||||
|
to_agent TEXT NOT NULL,
|
||||||
|
kind TEXT NOT NULL,
|
||||||
|
summary TEXT NOT NULL,
|
||||||
|
body TEXT NOT NULL DEFAULT '',
|
||||||
|
payload_json TEXT NOT NULL DEFAULT '{}',
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
FOREIGN KEY(thread_id) REFERENCES threads(thread_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS leases (
|
||||||
|
thread_id TEXT PRIMARY KEY,
|
||||||
|
agent_id TEXT NOT NULL,
|
||||||
|
lease_token TEXT NOT NULL,
|
||||||
|
claimed_at TEXT NOT NULL,
|
||||||
|
expires_at TEXT NOT NULL,
|
||||||
|
released_at TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS artifacts (
|
||||||
|
artifact_id TEXT PRIMARY KEY,
|
||||||
|
message_id TEXT NOT NULL,
|
||||||
|
path TEXT NOT NULL,
|
||||||
|
kind TEXT NOT NULL,
|
||||||
|
metadata_json TEXT NOT NULL DEFAULT '{}',
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
FOREIGN KEY(message_id) REFERENCES messages(message_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_threads_status_assigned
|
||||||
|
ON threads(status, assigned_to, updated_at);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_messages_thread_created
|
||||||
|
ON messages(thread_id, created_at);
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS runs (
|
||||||
|
run_id TEXT PRIMARY KEY,
|
||||||
|
goal TEXT NOT NULL,
|
||||||
|
summary TEXT NOT NULL DEFAULT '',
|
||||||
|
status TEXT NOT NULL DEFAULT 'active',
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS tasks (
|
||||||
|
run_id TEXT NOT NULL,
|
||||||
|
task_id TEXT NOT NULL,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
summary TEXT NOT NULL DEFAULT '',
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
default_to TEXT,
|
||||||
|
priority TEXT NOT NULL DEFAULT 'normal',
|
||||||
|
acceptance_json TEXT NOT NULL DEFAULT '[]',
|
||||||
|
latest_attempt_no INTEGER,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (run_id, task_id),
|
||||||
|
FOREIGN KEY(run_id) REFERENCES runs(run_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS task_dependencies (
|
||||||
|
run_id TEXT NOT NULL,
|
||||||
|
task_id TEXT NOT NULL,
|
||||||
|
depends_on_task_id TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (run_id, task_id, depends_on_task_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS task_attempts (
|
||||||
|
run_id TEXT NOT NULL,
|
||||||
|
task_id TEXT NOT NULL,
|
||||||
|
attempt_no INTEGER NOT NULL,
|
||||||
|
assigned_to TEXT NOT NULL,
|
||||||
|
thread_id TEXT NOT NULL,
|
||||||
|
base_ref TEXT,
|
||||||
|
base_commit TEXT,
|
||||||
|
branch_name TEXT,
|
||||||
|
worktree_path TEXT,
|
||||||
|
workspace_status TEXT,
|
||||||
|
result_commit TEXT,
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (run_id, task_id, attempt_no)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_tasks_run_status
|
||||||
|
ON tasks(run_id, status, priority, updated_at);
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS events (
|
||||||
|
event_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
run_id TEXT NOT NULL,
|
||||||
|
task_id TEXT NOT NULL,
|
||||||
|
thread_id TEXT,
|
||||||
|
source TEXT NOT NULL,
|
||||||
|
event_type TEXT NOT NULL,
|
||||||
|
message_id TEXT,
|
||||||
|
summary TEXT NOT NULL DEFAULT '',
|
||||||
|
payload_json TEXT NOT NULL DEFAULT '{}',
|
||||||
|
created_at TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_events_run_event
|
||||||
|
ON events(run_id, event_id);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_events_thread_event
|
||||||
|
ON events(thread_id, event_id);
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS council_runs (
|
||||||
|
run_id TEXT PRIMARY KEY,
|
||||||
|
mode TEXT NOT NULL,
|
||||||
|
target_type TEXT NOT NULL,
|
||||||
|
output_mode TEXT NOT NULL,
|
||||||
|
only_unanimous INTEGER NOT NULL DEFAULT 0,
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS council_reviewers (
|
||||||
|
run_id TEXT NOT NULL,
|
||||||
|
reviewer_role TEXT NOT NULL,
|
||||||
|
task_id TEXT NOT NULL,
|
||||||
|
status TEXT NOT NULL,
|
||||||
|
PRIMARY KEY (run_id, reviewer_role)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS council_findings (
|
||||||
|
run_id TEXT NOT NULL,
|
||||||
|
reviewer_role TEXT NOT NULL,
|
||||||
|
finding_id TEXT NOT NULL,
|
||||||
|
title TEXT NOT NULL,
|
||||||
|
summary TEXT NOT NULL,
|
||||||
|
proposal TEXT NOT NULL,
|
||||||
|
rationale TEXT NOT NULL,
|
||||||
|
confidence TEXT NOT NULL,
|
||||||
|
tags_json TEXT NOT NULL DEFAULT '[]',
|
||||||
|
target_refs_json TEXT NOT NULL DEFAULT '{}',
|
||||||
|
PRIMARY KEY (run_id, reviewer_role, finding_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS council_groups (
|
||||||
|
run_id TEXT NOT NULL,
|
||||||
|
group_id TEXT NOT NULL,
|
||||||
|
proposal TEXT NOT NULL,
|
||||||
|
bucket TEXT NOT NULL,
|
||||||
|
support_count INTEGER NOT NULL,
|
||||||
|
supporters_json TEXT NOT NULL DEFAULT '[]',
|
||||||
|
dissenters_json TEXT NOT NULL DEFAULT '[]',
|
||||||
|
rationale_summary TEXT NOT NULL DEFAULT '',
|
||||||
|
tags_json TEXT NOT NULL DEFAULT '[]',
|
||||||
|
source_finding_ids_json TEXT NOT NULL DEFAULT '[]',
|
||||||
|
PRIMARY KEY (run_id, group_id)
|
||||||
|
);
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS thread_reads (
|
||||||
|
thread_id TEXT NOT NULL,
|
||||||
|
agent_id TEXT NOT NULL,
|
||||||
|
last_read_message_id TEXT NOT NULL,
|
||||||
|
last_read_at TEXT NOT NULL,
|
||||||
|
PRIMARY KEY(thread_id, agent_id),
|
||||||
|
FOREIGN KEY(thread_id) REFERENCES threads(thread_id),
|
||||||
|
FOREIGN KEY(last_read_message_id) REFERENCES messages(message_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_thread_reads_agent
|
||||||
|
ON thread_reads(agent_id, last_read_at);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS council_inputs (
|
||||||
|
run_id TEXT PRIMARY KEY,
|
||||||
|
prompt TEXT NOT NULL DEFAULT '',
|
||||||
|
target_file TEXT NOT NULL DEFAULT '',
|
||||||
|
repo_path TEXT NOT NULL DEFAULT '',
|
||||||
|
target_task_id TEXT NOT NULL DEFAULT '',
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL
|
||||||
|
);
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS council_reports (
|
||||||
|
run_id TEXT PRIMARY KEY,
|
||||||
|
show_json TEXT NOT NULL DEFAULT '[]',
|
||||||
|
summary_json TEXT NOT NULL DEFAULT '{}',
|
||||||
|
markdown_path TEXT NOT NULL DEFAULT '',
|
||||||
|
created_at TEXT NOT NULL,
|
||||||
|
updated_at TEXT NOT NULL
|
||||||
|
);
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
module ai-workflow-skill/packages/coord-core
|
module ai-workflow-skill/packages/coord-core
|
||||||
|
|
||||||
go 1.26
|
go 1.26
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
|
modernc.org/sqlite v1.40.1
|
||||||
|
)
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package protocol
|
||||||
|
|
||||||
|
type CLIError struct {
|
||||||
|
Code string
|
||||||
|
ExitCode int
|
||||||
|
Message string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *CLIError) Error() string {
|
||||||
|
return e.Message
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *CLIError) Unwrap() error {
|
||||||
|
return e.Err
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCLIError(code string, exitCode int, message string, err error) error {
|
||||||
|
return &CLIError{
|
||||||
|
Code: code,
|
||||||
|
ExitCode: exitCode,
|
||||||
|
Message: message,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InvalidInput(message string, err error) error {
|
||||||
|
return NewCLIError("invalid_input", 30, message, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NoMatchingWork(message string) error {
|
||||||
|
return NewCLIError("no_matching_work", 10, message, nil)
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package protocol
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Success struct {
|
||||||
|
OK bool `json:"ok"`
|
||||||
|
Command string `json:"command"`
|
||||||
|
Data map[string]any `json:"data,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Error struct {
|
||||||
|
OK bool `json:"ok"`
|
||||||
|
Error ErrorPayload `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrorPayload struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteJSON(w io.Writer, v any) error {
|
||||||
|
enc := json.NewEncoder(w)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
return enc.Encode(v)
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
// Package store contains higher-level database access helpers.
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,107 @@
|
|||||||
|
package store
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
dbpkg "ai-workflow-skill/packages/coord-core/db"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestClaimThreadReturnsLeaseConflictAfterBusyWrite(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
dbPath := filepath.Join(t.TempDir(), "coord.db")
|
||||||
|
|
||||||
|
sqlDB, err := dbpkg.Open(ctx, dbPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("open base db: %v", err)
|
||||||
|
}
|
||||||
|
defer sqlDB.Close()
|
||||||
|
|
||||||
|
if err := dbpkg.ApplyMigrations(ctx, sqlDB); err != nil {
|
||||||
|
t.Fatalf("apply migrations: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
baseStore := NewInboxStore(sqlDB)
|
||||||
|
thread, _, err := baseStore.Send(ctx, SendInput{
|
||||||
|
FromAgent: "leader",
|
||||||
|
ToAgent: "worker-a",
|
||||||
|
Subject: "race claim",
|
||||||
|
Summary: "race claim",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("seed thread: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
lockerDB, err := dbpkg.Open(ctx, dbPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("open locker db: %v", err)
|
||||||
|
}
|
||||||
|
defer lockerDB.Close()
|
||||||
|
|
||||||
|
lockTx, err := lockerDB.BeginTx(ctx, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("begin locker tx: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
now := nowUTC()
|
||||||
|
if _, err := lockTx.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`INSERT INTO leases (
|
||||||
|
thread_id, agent_id, lease_token, claimed_at, expires_at, released_at
|
||||||
|
) VALUES (?, ?, ?, ?, ?, NULL)`,
|
||||||
|
thread.ThreadID,
|
||||||
|
"worker-a",
|
||||||
|
"lease_locked",
|
||||||
|
formatTime(now),
|
||||||
|
formatTime(now.Add(5*time.Minute)),
|
||||||
|
); err != nil {
|
||||||
|
t.Fatalf("seed active lease in tx: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := lockTx.ExecContext(
|
||||||
|
ctx,
|
||||||
|
`UPDATE threads
|
||||||
|
SET status = ?, assigned_to = ?, latest_message_id = ?, updated_at = ?
|
||||||
|
WHERE thread_id = ?`,
|
||||||
|
"claimed",
|
||||||
|
"worker-a",
|
||||||
|
"msg_locked",
|
||||||
|
formatTime(now),
|
||||||
|
thread.ThreadID,
|
||||||
|
); err != nil {
|
||||||
|
t.Fatalf("seed claimed thread in tx: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
commitDone := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
commitDone <- lockTx.Commit()
|
||||||
|
}()
|
||||||
|
|
||||||
|
claimDB, err := dbpkg.Open(ctx, dbPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("open claim db: %v", err)
|
||||||
|
}
|
||||||
|
defer claimDB.Close()
|
||||||
|
|
||||||
|
claimStore := NewInboxStore(claimDB)
|
||||||
|
_, err = claimStore.ClaimThread(ctx, ClaimInput{
|
||||||
|
ThreadID: thread.ThreadID,
|
||||||
|
Agent: "worker-b",
|
||||||
|
LeaseSeconds: 300,
|
||||||
|
})
|
||||||
|
if !errors.Is(err, ErrLeaseConflict) {
|
||||||
|
t.Fatalf("expected lease conflict after busy retry, got %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := <-commitDone; err != nil {
|
||||||
|
t.Fatalf("commit locker tx: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user