Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0e681bc
feat(config): add server configuration types
thruflo Jan 17, 2026
6c1b4b8
feat(cli): add --server, --port, --password flags to start command
thruflo Jan 17, 2026
ba685da
feat(cli): add --server, --port, --password flags to resume command
thruflo Jan 17, 2026
bb384b5
feat(server): create internal/server package with core server struct
thruflo Jan 17, 2026
2487e8c
feat(server): implement Durable Streams integration
thruflo Jan 17, 2026
98ea87d
feat(server): implement HTTP endpoints for web server
thruflo Jan 17, 2026
764a63b
feat(server): implement asset embedding for web client
thruflo Jan 17, 2026
aaf49aa
feat(loop): integrate server with loop for state broadcasting
thruflo Jan 17, 2026
6b224c4
feat(web): set up web client project structure
thruflo Jan 17, 2026
66b0bc9
feat(web): implement disconnection handling for web client
thruflo Jan 17, 2026
4ae8e3d
feat(server): implement first-response-wins for concurrent input
thruflo Jan 17, 2026
24c61e6
test(server): add integration tests for web server
thruflo Jan 17, 2026
bb544f1
docs: update CLI help and README with remote access documentation
thruflo Jan 17, 2026
e22a3c0
feat(cli): start web server when --server flag is used
thruflo Jan 19, 2026
9d300e8
fix(server): parse auth request body as JSON instead of form data
thruflo Jan 19, 2026
ed251aa
fix(web): fix auth flow and stream connection issues
thruflo Jan 19, 2026
f075919
feat(dev): add standalone debug server for testing web auth
thruflo Jan 19, 2026
95abb53
fix tests
thruflo Jan 19, 2026
2c93e46
use correct mutex
thruflo Jan 19, 2026
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
.DS_Store
.claude/settings.local.json
.wisp/
wisp
wisp

# Web client
web/node_modules/
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,36 @@ wisp start --repo org/repo --spec docs/my-rfc.md --sibling-repos org/shared-lib

When the agent needs input, the TUI prompts for a response. Type and press Enter.

### Remote access

Monitor and interact with sessions from any device using the built-in web server:

```bash
wisp start --repo org/repo --spec docs/rfc.md --server
```

On first use, you'll be prompted to set a password. The server URL is printed
(default: `http://localhost:8374`). Expose via ngrok for mobile access:

```bash
ngrok http 8374
```

The web interface provides:
- Dashboard with active sessions
- Task list with completion status
- Live Claude output stream
- Input prompt for NEEDS_INPUT responses
- Browser notifications when input is needed

Additional server options:

```bash
wisp start ... --server --port 9000 # custom port
wisp start ... --server --password # change password
wisp resume wisp/my-feature --server # resume with server
```

### Complete and create PR

```bash
Expand Down
69 changes: 69 additions & 0 deletions cmd/debug-server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Simple standalone server for debugging auth flow.
// Run with: go run ./cmd/debug-server
// Make sure to rebuild web assets first: cd web && npm run build
package main

import (
"context"
"fmt"
"os"
"os/signal"
"syscall"

"github.com/thruflo/wisp/internal/auth"
"github.com/thruflo/wisp/internal/server"
"github.com/thruflo/wisp/web"
)

func main() {
password := "test123"
if len(os.Args) > 1 {
password = os.Args[1]
}

hash, err := auth.HashPassword(password)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to hash password: %v\n", err)
os.Exit(1)
}

// Check if web/dist exists (fresh build)
if stat, err := os.Stat("./web/dist"); err != nil || !stat.IsDir() {
fmt.Fprintln(os.Stderr, "Warning: ./web/dist not found. Run 'cd web && npm run build' first.")
fmt.Fprintln(os.Stderr, "Using embedded assets (may be stale).")
} else {
fmt.Println("Using live assets from ./web/dist")
}

srv, err := server.NewServer(&server.Config{
Port: 8375,
PasswordHash: hash,
Assets: web.GetAssets("./web/dist"),
})
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to create server: %v\n", err)
os.Exit(1)
}

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

// Handle Ctrl+C
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigCh
fmt.Println("\nShutting down...")
cancel()
}()

go srv.Start(ctx)

fmt.Printf("Server running on http://localhost:%d\n", srv.Port())
fmt.Printf("Password: %s\n", password)
fmt.Println("\nTest with:")
fmt.Printf(" curl -X POST http://localhost:%d/auth -H 'Content-Type: application/json' -d '{\"password\":\"%s\"}'\n", srv.Port(), password)

<-ctx.Done()
srv.Stop()
}
129 changes: 123 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,21 +1,138 @@
module github.com/thruflo/wisp

go 1.24.0
go 1.25

require (
github.com/spf13/cobra v1.10.2
github.com/stretchr/testify v1.11.1
github.com/superfly/sprites-go v0.0.0-20260115223022-8bc92b9127c7
golang.org/x/crypto v0.47.0
golang.org/x/term v0.39.0
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/Masterminds/semver/v3 v3.2.1 // indirect
cel.dev/expr v0.24.0 // indirect
cloud.google.com/go/auth v0.16.2 // indirect
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
cloud.google.com/go/compute/metadata v0.7.0 // indirect
dario.cat/mergo v1.0.1 // indirect
filippo.io/edwards25519 v1.1.0 // indirect
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
github.com/KimMachineGun/automemlimit v0.7.4 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/caddyserver/caddy/v2 v2.10.2 // indirect
github.com/caddyserver/certmagic v0.24.0 // indirect
github.com/caddyserver/zerossl v0.1.3 // indirect
github.com/ccoveille/go-safecast v1.6.1 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/chzyer/readline v1.5.1 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/coreos/go-oidc/v3 v3.14.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dgraph-io/badger v1.6.2 // indirect
github.com/dgraph-io/badger/v2 v2.2007.4 // indirect
github.com/dgraph-io/ristretto v0.2.0 // indirect
github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect
github.com/durable-streams/durable-streams/packages/caddy-plugin v0.0.0-20260116005712-42bf4d3b3e45 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-sql-driver/mysql v1.8.1 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/google/cel-go v0.26.0 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgx/v5 v5.6.0 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
github.com/libdns/libdns v1.1.0 // indirect
github.com/manifoldco/promptui v0.9.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mholt/acmez/v3 v3.1.2 // indirect
github.com/miekg/dns v1.1.63 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/go-ps v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.23.0 // indirect
github.com/prometheus/client_model v0.6.2 // indirect
github.com/prometheus/common v0.65.0 // indirect
github.com/prometheus/procfs v0.16.1 // indirect
github.com/quic-go/qpack v0.5.1 // indirect
github.com/quic-go/quic-go v0.54.0 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
github.com/slackhq/nebula v1.9.5 // indirect
github.com/smallstep/certificates v0.28.4 // indirect
github.com/smallstep/cli-utils v0.12.1 // indirect
github.com/smallstep/linkedca v0.23.0 // indirect
github.com/smallstep/nosql v0.7.0 // indirect
github.com/smallstep/pkcs7 v0.2.1 // indirect
github.com/smallstep/scep v0.0.0-20240926084937-8cf1ca453101 // indirect
github.com/smallstep/truststore v0.13.0 // indirect
github.com/spf13/cast v1.7.0 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/superfly/sprites-go v0.0.0-20260115223022-8bc92b9127c7 // indirect
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
github.com/tailscale/tscert v0.0.0-20240608151842-d3f834017e53 // indirect
github.com/urfave/cli v1.22.17 // indirect
github.com/zeebo/blake3 v0.2.4 // indirect
go.etcd.io/bbolt v1.4.3 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.37.0 // indirect
go.opentelemetry.io/otel/metric v1.37.0 // indirect
go.opentelemetry.io/otel/trace v1.37.0 // indirect
go.step.sm/crypto v0.67.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/mock v0.5.2 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.1 // indirect
go.uber.org/zap/exp v0.3.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto/x509roots/fallback v0.0.0-20250305170421-49bf5b80c810 // indirect
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
golang.org/x/mod v0.31.0 // indirect
golang.org/x/net v0.48.0 // indirect
golang.org/x/oauth2 v0.30.0 // indirect
golang.org/x/sync v0.19.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
golang.org/x/time v0.12.0 // indirect
golang.org/x/tools v0.40.0 // indirect
google.golang.org/api v0.240.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
google.golang.org/grpc v1.73.0 // indirect
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect
google.golang.org/protobuf v1.36.6 // indirect
howett.net/plist v1.0.0 // indirect
)
Loading
Loading