mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-14 16:14:28 +00:00
Compare commits
2 Commits
feat/click
...
fix/dev-se
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cd7c985e3 | ||
|
|
548c9dd996 |
@@ -12,7 +12,7 @@
|
||||
"dev:watch": "./tools/dev/run.sh watch",
|
||||
"dev:watch:new": "./tools/dev/run.sh watch --new",
|
||||
"dev:manual": "./tools/dev/run.sh watch --manual",
|
||||
"dev:setup": "./tools/dev/setup.sh",
|
||||
"dev:setup": "./tools/dev/run.sh setup",
|
||||
"dev:cleanup": "./tools/dev/run.sh cleanup",
|
||||
"dev:reset": "./tools/dev/run.sh reset",
|
||||
"install:browseros-dogfood": "make -C tools/dogfood install",
|
||||
|
||||
81
packages/browseros-agent/tools/dev/cmd/setup.go
Normal file
81
packages/browseros-agent/tools/dev/cmd/setup.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"browseros-dev/proc"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var setupIfNeeded bool
|
||||
|
||||
const setupModeIfNeeded = true
|
||||
|
||||
var setupCmd = &cobra.Command{
|
||||
Use: "setup",
|
||||
Short: "Install dev dependencies and generate required code",
|
||||
Long: "Installs Bun dependencies and generates agent GraphQL code needed by the dev environment.",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
root, err := proc.FindMonorepoRoot()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return runDevSetup(cmd.Context(), root, setupIfNeeded)
|
||||
},
|
||||
}
|
||||
|
||||
type setupPlan struct {
|
||||
RunInstall bool
|
||||
RunCodegen bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
setupCmd.Flags().BoolVar(&setupIfNeeded, "if-needed", false, "Skip generated code refresh when it already exists")
|
||||
rootCmd.AddCommand(setupCmd)
|
||||
}
|
||||
|
||||
func buildSetupPlan(root string, ifNeeded bool) setupPlan {
|
||||
return setupPlan{
|
||||
RunInstall: true,
|
||||
RunCodegen: !ifNeeded || !generatedGraphQLExists(root),
|
||||
}
|
||||
}
|
||||
|
||||
func generatedGraphQLExists(root string) bool {
|
||||
for _, file := range []string{"gql.ts", "graphql.ts", "schema.graphql"} {
|
||||
info, err := os.Stat(filepath.Join(root, "apps/agent/generated/graphql", file))
|
||||
if err != nil || info.IsDir() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// runDevSetup prepares the repo for local development. Dependency install always
|
||||
// runs because Bun is fast and this keeps watch resilient after branch changes.
|
||||
func runDevSetup(ctx context.Context, root string, ifNeeded bool) error {
|
||||
plan := buildSetupPlan(root, ifNeeded)
|
||||
|
||||
if plan.RunInstall {
|
||||
proc.LogMsg(proc.TagSetup, "Installing dependencies...")
|
||||
if err := proc.RunBlocking(ctx, root, proc.TagSetup, "bun", "install", "--frozen-lockfile"); err != nil {
|
||||
return fmt.Errorf("installing dependencies: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if plan.RunCodegen {
|
||||
proc.LogMsg(proc.TagSetup, "Generating agent code...")
|
||||
if err := proc.RunBlocking(ctx, root, proc.TagSetup, "bun", "run", "codegen:agent"); err != nil {
|
||||
return fmt.Errorf("generating agent code: %w", err)
|
||||
}
|
||||
} else {
|
||||
proc.LogMsg(proc.TagSetup, "Agent code already generated")
|
||||
}
|
||||
|
||||
proc.LogMsg(proc.TagSetup, "Setup ready")
|
||||
return nil
|
||||
}
|
||||
76
packages/browseros-agent/tools/dev/cmd/setup_test.go
Normal file
76
packages/browseros-agent/tools/dev/cmd/setup_test.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuildSetupPlanAlwaysInstallsDependencies(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
|
||||
plan := buildSetupPlan(root, true)
|
||||
|
||||
if !plan.RunInstall {
|
||||
t.Fatal("expected dependency install to always run")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildSetupPlanIfNeededSkipsExistingGeneratedGraphQL(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
writeGeneratedGraphQLSentinels(t, root)
|
||||
|
||||
plan := buildSetupPlan(root, true)
|
||||
|
||||
if plan.RunCodegen {
|
||||
t.Fatal("expected --if-needed setup to skip codegen when generated GraphQL exists")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildSetupPlanIfNeededRunsCodegenWhenGeneratedGraphQLEmpty(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
generatedDir := filepath.Join(root, "apps/agent/generated/graphql")
|
||||
if err := os.MkdirAll(generatedDir, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
plan := buildSetupPlan(root, true)
|
||||
|
||||
if !plan.RunCodegen {
|
||||
t.Fatal("expected --if-needed setup to run codegen when generated GraphQL is empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildSetupPlanIfNeededRunsCodegenWhenGeneratedGraphQLMissing(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
|
||||
plan := buildSetupPlan(root, true)
|
||||
|
||||
if !plan.RunCodegen {
|
||||
t.Fatal("expected --if-needed setup to run codegen when generated GraphQL is missing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildSetupPlanExplicitSetupRunsCodegen(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
writeGeneratedGraphQLSentinels(t, root)
|
||||
|
||||
plan := buildSetupPlan(root, false)
|
||||
|
||||
if !plan.RunCodegen {
|
||||
t.Fatal("expected explicit setup to refresh codegen")
|
||||
}
|
||||
}
|
||||
|
||||
func writeGeneratedGraphQLSentinels(t *testing.T, root string) {
|
||||
t.Helper()
|
||||
generatedDir := filepath.Join(root, "apps/agent/generated/graphql")
|
||||
if err := os.MkdirAll(generatedDir, 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, file := range []string{"gql.ts", "graphql.ts", "schema.graphql"} {
|
||||
if err := os.WriteFile(filepath.Join(generatedDir, file), []byte("generated"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,6 +115,10 @@ func runWatch(cmd *cobra.Command, args []string) error {
|
||||
}()
|
||||
defer reservations.ReleaseAll()
|
||||
|
||||
if err := runDevSetup(cmd.Context(), root, setupModeIfNeeded); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println()
|
||||
proc.LogMsgf(proc.TagInfo, "Mode: %s", proc.BoldColor.Sprint(mode))
|
||||
proc.LogMsgf(proc.TagInfo, "Ports: CDP=%d Server=%d Extension=%d", p.CDP, p.Server, p.Extension)
|
||||
|
||||
@@ -14,6 +14,7 @@ type Tag struct {
|
||||
|
||||
var (
|
||||
TagBuild = Tag{"build", color.New(color.FgYellow)}
|
||||
TagSetup = Tag{"setup", color.New(color.FgHiYellow)}
|
||||
TagAgent = Tag{"agent", color.New(color.FgMagenta)}
|
||||
TagServer = Tag{"server", color.New(color.FgCyan)}
|
||||
TagBrowser = Tag{"browser", color.New(color.FgBlue)}
|
||||
|
||||
@@ -2,14 +2,4 @@
|
||||
set -euo pipefail
|
||||
|
||||
DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
ROOT="$(cd "$DIR/../.." && pwd)"
|
||||
|
||||
cd "$ROOT"
|
||||
|
||||
echo "[setup] Installing dependencies..."
|
||||
bun install --frozen-lockfile
|
||||
|
||||
echo "[setup] Generating agent code..."
|
||||
bun run codegen:agent
|
||||
|
||||
echo "[setup] Ready"
|
||||
exec "$DIR/run.sh" setup "$@"
|
||||
|
||||
Reference in New Issue
Block a user