fix(core-ide): use path-based routing for multi-window SPA, clean up formatting
Switch Angular from hash-based to path-based routing so each Wails window (/tray, /main, /settings) loads its correct route. Archive GitHub Actions workflows to .gh-actions/, update Forgejo deploy registry to dappco.re/osi, and apply gofmt/alignment fixes across packages. Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
0fb9de600d
commit
a668c5ab5a
54 changed files with 16239 additions and 73 deletions
|
|
@ -16,7 +16,7 @@ on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
REGISTRY: gitea.snider.dev
|
REGISTRY: dappco.re/osi
|
||||||
IMAGE_APP: host-uk/app
|
IMAGE_APP: host-uk/app
|
||||||
IMAGE_WEB: host-uk/web
|
IMAGE_WEB: host-uk/web
|
||||||
IMAGE_CORE: host-uk/core
|
IMAGE_CORE: host-uk/core
|
||||||
|
|
|
||||||
16159
cmd/core-ide/frontend/package-lock.json
generated
Normal file
16159
cmd/core-ide/frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,9 +1,9 @@
|
||||||
import { ApplicationConfig } from '@angular/core';
|
import { ApplicationConfig } from '@angular/core';
|
||||||
import { provideRouter, withHashLocation } from '@angular/router';
|
import { provideRouter } from '@angular/router';
|
||||||
import { routes } from './app.routes';
|
import { routes } from './app.routes';
|
||||||
|
|
||||||
export const appConfig: ApplicationConfig = {
|
export const appConfig: ApplicationConfig = {
|
||||||
providers: [
|
providers: [
|
||||||
provideRouter(routes, withHashLocation())
|
provideRouter(routes)
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';
|
|
||||||
import { ChatComponent } from '../chat/chat.component';
|
import { ChatComponent } from '../chat/chat.component';
|
||||||
import { BuildComponent } from '../build/build.component';
|
import { BuildComponent } from '../build/build.component';
|
||||||
import { DashboardComponent } from '../dashboard/dashboard.component';
|
import { DashboardComponent } from '../dashboard/dashboard.component';
|
||||||
|
|
@ -11,7 +10,7 @@ type Panel = 'chat' | 'build' | 'dashboard' | 'jellyfin';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-main',
|
selector: 'app-main',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, RouterLink, RouterLinkActive, RouterOutlet, ChatComponent, BuildComponent, DashboardComponent, JellyfinComponent],
|
imports: [CommonModule, ChatComponent, BuildComponent, DashboardComponent, JellyfinComponent],
|
||||||
template: `
|
template: `
|
||||||
<div class="ide">
|
<div class="ide">
|
||||||
<nav class="ide__sidebar">
|
<nav class="ide__sidebar">
|
||||||
|
|
|
||||||
|
|
@ -81,4 +81,3 @@ func (s *IDEService) ShowWindow(name string) {
|
||||||
w.Focus()
|
w.Focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,8 +79,8 @@ func (b *MCPBridge) startHTTPServer() {
|
||||||
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(map[string]any{
|
json.NewEncoder(w).Encode(map[string]any{
|
||||||
"status": "ok",
|
"status": "ok",
|
||||||
"mcp": true,
|
"mcp": true,
|
||||||
"claudeBridge": b.claudeBridge.Connected(),
|
"claudeBridge": b.claudeBridge.Connected(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
BIN
core-test
BIN
core-test
Binary file not shown.
|
|
@ -208,7 +208,11 @@ func shortID(id string) string {
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatDur(d interface{ Hours() float64; Minutes() float64; Seconds() float64 }) string {
|
func formatDur(d interface {
|
||||||
|
Hours() float64
|
||||||
|
Minutes() float64
|
||||||
|
Seconds() float64
|
||||||
|
}) string {
|
||||||
type dur interface {
|
type dur interface {
|
||||||
Hours() float64
|
Hours() float64
|
||||||
Minutes() float64
|
Minutes() float64
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
// cmd_agent.go manages persistent agent context within task workspaces.
|
// cmd_agent.go manages persistent agent context within task workspaces.
|
||||||
//
|
//
|
||||||
// Each agent gets a directory at:
|
// Each agent gets a directory at:
|
||||||
// .core/workspace/p{epic}/i{issue}/agents/{provider}/{agent-name}/
|
//
|
||||||
|
// .core/workspace/p{epic}/i{issue}/agents/{provider}/{agent-name}/
|
||||||
//
|
//
|
||||||
// This directory persists across invocations, allowing agents to build
|
// This directory persists across invocations, allowing agents to build
|
||||||
// understanding over time — QA agents accumulate findings, reviewers
|
// understanding over time — QA agents accumulate findings, reviewers
|
||||||
|
|
@ -34,7 +35,7 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
agentProvider string
|
agentProvider string
|
||||||
agentName string
|
agentName string
|
||||||
)
|
)
|
||||||
|
|
||||||
func addAgentCommands(parent *cobra.Command) {
|
func addAgentCommands(parent *cobra.Command) {
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
taskEpic int
|
taskEpic int
|
||||||
taskIssue int
|
taskIssue int
|
||||||
taskRepos []string
|
taskRepos []string
|
||||||
taskForce bool
|
taskForce bool
|
||||||
taskBranch string
|
taskBranch string
|
||||||
)
|
)
|
||||||
|
|
||||||
func addTaskCommands(parent *cobra.Command) {
|
func addTaskCommands(parent *cobra.Command) {
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ type User struct {
|
||||||
// Challenge is a PGP-encrypted nonce sent to a client during authentication.
|
// Challenge is a PGP-encrypted nonce sent to a client during authentication.
|
||||||
type Challenge struct {
|
type Challenge struct {
|
||||||
Nonce []byte `json:"nonce"`
|
Nonce []byte `json:"nonce"`
|
||||||
Encrypted string `json:"encrypted"` // PGP-encrypted nonce (armored)
|
Encrypted string `json:"encrypted"` // PGP-encrypted nonce (armored)
|
||||||
ExpiresAt time.Time `json:"expires_at"`
|
ExpiresAt time.Time `json:"expires_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -226,14 +226,14 @@ func (b *CPPBuilder) findBinaries(fs io.Medium, projectDir string, target build.
|
||||||
func (b *CPPBuilder) targetToProfile(target build.Target) string {
|
func (b *CPPBuilder) targetToProfile(target build.Target) string {
|
||||||
key := target.OS + "/" + target.Arch
|
key := target.OS + "/" + target.Arch
|
||||||
profiles := map[string]string{
|
profiles := map[string]string{
|
||||||
"linux/amd64": "gcc-linux-x86_64",
|
"linux/amd64": "gcc-linux-x86_64",
|
||||||
"linux/x86_64": "gcc-linux-x86_64",
|
"linux/x86_64": "gcc-linux-x86_64",
|
||||||
"linux/arm64": "gcc-linux-armv8",
|
"linux/arm64": "gcc-linux-armv8",
|
||||||
"linux/armv8": "gcc-linux-armv8",
|
"linux/armv8": "gcc-linux-armv8",
|
||||||
"darwin/arm64": "apple-clang-armv8",
|
"darwin/arm64": "apple-clang-armv8",
|
||||||
"darwin/armv8": "apple-clang-armv8",
|
"darwin/armv8": "apple-clang-armv8",
|
||||||
"darwin/amd64": "apple-clang-x86_64",
|
"darwin/amd64": "apple-clang-x86_64",
|
||||||
"darwin/x86_64": "apple-clang-x86_64",
|
"darwin/x86_64": "apple-clang-x86_64",
|
||||||
"windows/amd64": "msvc-194-x86_64",
|
"windows/amd64": "msvc-194-x86_64",
|
||||||
"windows/x86_64": "msvc-194-x86_64",
|
"windows/x86_64": "msvc-194-x86_64",
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,9 @@ const (
|
||||||
// -X github.com/host-uk/core/pkg/cli.BuildDate=2026-02-06 \
|
// -X github.com/host-uk/core/pkg/cli.BuildDate=2026-02-06 \
|
||||||
// -X github.com/host-uk/core/pkg/cli.BuildPreRelease=dev.8"
|
// -X github.com/host-uk/core/pkg/cli.BuildPreRelease=dev.8"
|
||||||
var (
|
var (
|
||||||
AppVersion = "0.0.0"
|
AppVersion = "0.0.0"
|
||||||
BuildCommit = "unknown"
|
BuildCommit = "unknown"
|
||||||
BuildDate = "unknown"
|
BuildDate = "unknown"
|
||||||
BuildPreRelease = ""
|
BuildPreRelease = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,19 +12,19 @@ import (
|
||||||
|
|
||||||
// Config is the top-level infrastructure configuration parsed from infra.yaml.
|
// Config is the top-level infrastructure configuration parsed from infra.yaml.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Hosts map[string]*Host `yaml:"hosts"`
|
Hosts map[string]*Host `yaml:"hosts"`
|
||||||
LoadBalancer LoadBalancer `yaml:"load_balancer"`
|
LoadBalancer LoadBalancer `yaml:"load_balancer"`
|
||||||
Network Network `yaml:"network"`
|
Network Network `yaml:"network"`
|
||||||
DNS DNS `yaml:"dns"`
|
DNS DNS `yaml:"dns"`
|
||||||
SSL SSL `yaml:"ssl"`
|
SSL SSL `yaml:"ssl"`
|
||||||
Database Database `yaml:"database"`
|
Database Database `yaml:"database"`
|
||||||
Cache Cache `yaml:"cache"`
|
Cache Cache `yaml:"cache"`
|
||||||
Containers map[string]*Container `yaml:"containers"`
|
Containers map[string]*Container `yaml:"containers"`
|
||||||
S3 S3Config `yaml:"s3"`
|
S3 S3Config `yaml:"s3"`
|
||||||
CDN CDN `yaml:"cdn"`
|
CDN CDN `yaml:"cdn"`
|
||||||
CICD CICD `yaml:"cicd"`
|
CICD CICD `yaml:"cicd"`
|
||||||
Monitoring Monitoring `yaml:"monitoring"`
|
Monitoring Monitoring `yaml:"monitoring"`
|
||||||
Backups Backups `yaml:"backups"`
|
Backups Backups `yaml:"backups"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Host represents a server in the infrastructure.
|
// Host represents a server in the infrastructure.
|
||||||
|
|
@ -47,16 +47,16 @@ type SSHConf struct {
|
||||||
|
|
||||||
// LoadBalancer represents a Hetzner managed load balancer.
|
// LoadBalancer represents a Hetzner managed load balancer.
|
||||||
type LoadBalancer struct {
|
type LoadBalancer struct {
|
||||||
Name string `yaml:"name"`
|
Name string `yaml:"name"`
|
||||||
FQDN string `yaml:"fqdn"`
|
FQDN string `yaml:"fqdn"`
|
||||||
Provider string `yaml:"provider"`
|
Provider string `yaml:"provider"`
|
||||||
Type string `yaml:"type"`
|
Type string `yaml:"type"`
|
||||||
Location string `yaml:"location"`
|
Location string `yaml:"location"`
|
||||||
Algorithm string `yaml:"algorithm"`
|
Algorithm string `yaml:"algorithm"`
|
||||||
Backends []Backend `yaml:"backends"`
|
Backends []Backend `yaml:"backends"`
|
||||||
Health HealthCheck `yaml:"health_check"`
|
Health HealthCheck `yaml:"health_check"`
|
||||||
Listeners []Listener `yaml:"listeners"`
|
Listeners []Listener `yaml:"listeners"`
|
||||||
SSL LBCert `yaml:"ssl"`
|
SSL LBCert `yaml:"ssl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backend is a load balancer backend target.
|
// Backend is a load balancer backend target.
|
||||||
|
|
@ -94,9 +94,9 @@ type Network struct {
|
||||||
|
|
||||||
// DNS holds DNS provider configuration and zone records.
|
// DNS holds DNS provider configuration and zone records.
|
||||||
type DNS struct {
|
type DNS struct {
|
||||||
Provider string `yaml:"provider"`
|
Provider string `yaml:"provider"`
|
||||||
Nameservers []string `yaml:"nameservers"`
|
Nameservers []string `yaml:"nameservers"`
|
||||||
Zones map[string]*Zone `yaml:"zones"`
|
Zones map[string]*Zone `yaml:"zones"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zone is a DNS zone with its records.
|
// Zone is a DNS zone with its records.
|
||||||
|
|
@ -203,8 +203,8 @@ type CICD struct {
|
||||||
|
|
||||||
// Monitoring describes monitoring configuration.
|
// Monitoring describes monitoring configuration.
|
||||||
type Monitoring struct {
|
type Monitoring struct {
|
||||||
HealthEndpoints []HealthEndpoint `yaml:"health_endpoints"`
|
HealthEndpoints []HealthEndpoint `yaml:"health_endpoints"`
|
||||||
Alerts map[string]int `yaml:"alerts"`
|
Alerts map[string]int `yaml:"alerts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// HealthEndpoint is a URL to monitor.
|
// HealthEndpoint is a URL to monitor.
|
||||||
|
|
|
||||||
|
|
@ -552,10 +552,12 @@ type dirEntry struct {
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dirEntry) Name() string { return d.name }
|
func (d *dirEntry) Name() string { return d.name }
|
||||||
func (d *dirEntry) IsDir() bool { return true }
|
func (d *dirEntry) IsDir() bool { return true }
|
||||||
func (d *dirEntry) Type() fs.FileMode { return fs.ModeDir }
|
func (d *dirEntry) Type() fs.FileMode { return fs.ModeDir }
|
||||||
func (d *dirEntry) Info() (fs.FileInfo, error) { return &fileInfo{name: d.name, isDir: true, mode: fs.ModeDir | 0755}, nil }
|
func (d *dirEntry) Info() (fs.FileInfo, error) {
|
||||||
|
return &fileInfo{name: d.name, isDir: true, mode: fs.ModeDir | 0755}, nil
|
||||||
|
}
|
||||||
|
|
||||||
type fileInfo struct {
|
type fileInfo struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
||||||
|
|
@ -335,7 +335,7 @@ func TestOverwrite_Good(t *testing.T) {
|
||||||
func TestExists_Good(t *testing.T) {
|
func TestExists_Good(t *testing.T) {
|
||||||
m := New()
|
m := New()
|
||||||
|
|
||||||
assert.True(t, m.Exists("")) // root
|
assert.True(t, m.Exists("")) // root
|
||||||
assert.False(t, m.Exists("x"))
|
assert.False(t, m.Exists("x"))
|
||||||
|
|
||||||
require.NoError(t, m.Write("x", "y"))
|
require.NoError(t, m.Write("x", "y"))
|
||||||
|
|
|
||||||
|
|
@ -431,8 +431,8 @@ type dataFile struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *dataFile) Stat() (fs.FileInfo, error) { return &dataFileInfo{file: d}, nil }
|
func (d *dataFile) Stat() (fs.FileInfo, error) { return &dataFileInfo{file: d}, nil }
|
||||||
func (d *dataFile) Read(_ []byte) (int, error) { return 0, goio.EOF }
|
func (d *dataFile) Read(_ []byte) (int, error) { return 0, goio.EOF }
|
||||||
func (d *dataFile) Close() error { return nil }
|
func (d *dataFile) Close() error { return nil }
|
||||||
|
|
||||||
// dataFileInfo implements fs.FileInfo for a dataFile.
|
// dataFileInfo implements fs.FileInfo for a dataFile.
|
||||||
type dataFileInfo struct{ file *dataFile }
|
type dataFileInfo struct{ file *dataFile }
|
||||||
|
|
@ -496,11 +496,13 @@ var _ fs.ReadDirFS = (*Node)(nil)
|
||||||
// Unexported helper: ensure ReadStream result also satisfies fs.File
|
// Unexported helper: ensure ReadStream result also satisfies fs.File
|
||||||
// (for cases where callers do a type assertion).
|
// (for cases where callers do a type assertion).
|
||||||
var _ goio.ReadCloser = goio.NopCloser(nil)
|
var _ goio.ReadCloser = goio.NopCloser(nil)
|
||||||
|
|
||||||
// Ensure nodeWriter satisfies goio.WriteCloser.
|
// Ensure nodeWriter satisfies goio.WriteCloser.
|
||||||
var _ goio.WriteCloser = (*nodeWriter)(nil)
|
var _ goio.WriteCloser = (*nodeWriter)(nil)
|
||||||
|
|
||||||
// Ensure dirFile satisfies fs.File.
|
// Ensure dirFile satisfies fs.File.
|
||||||
var _ fs.File = (*dirFile)(nil)
|
var _ fs.File = (*dirFile)(nil)
|
||||||
|
|
||||||
// Ensure dataFileReader satisfies fs.File.
|
// Ensure dataFileReader satisfies fs.File.
|
||||||
var _ fs.File = (*dataFileReader)(nil)
|
var _ fs.File = (*dataFileReader)(nil)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -567,7 +567,7 @@ type dirEntry struct {
|
||||||
func (de *dirEntry) Name() string { return de.name }
|
func (de *dirEntry) Name() string { return de.name }
|
||||||
func (de *dirEntry) IsDir() bool { return de.isDir }
|
func (de *dirEntry) IsDir() bool { return de.isDir }
|
||||||
func (de *dirEntry) Type() fs.FileMode { return de.mode.Type() }
|
func (de *dirEntry) Type() fs.FileMode { return de.mode.Type() }
|
||||||
func (de *dirEntry) Info() (fs.FileInfo, error) { return de.info, nil }
|
func (de *dirEntry) Info() (fs.FileInfo, error) { return de.info, nil }
|
||||||
|
|
||||||
// s3File implements fs.File for S3 objects.
|
// s3File implements fs.File for S3 objects.
|
||||||
type s3File struct {
|
type s3File struct {
|
||||||
|
|
|
||||||
|
|
@ -239,9 +239,9 @@ func TestHashSigil_Good(t *testing.T) {
|
||||||
data := []byte("hash me")
|
data := []byte("hash me")
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
sigilName string
|
sigilName string
|
||||||
size int
|
size int
|
||||||
}{
|
}{
|
||||||
{"md5", "md5", md5.Size},
|
{"md5", "md5", md5.Size},
|
||||||
{"sha1", "sha1", sha1.Size},
|
{"sha1", "sha1", sha1.Size},
|
||||||
|
|
|
||||||
|
|
@ -611,7 +611,7 @@ type dirEntry struct {
|
||||||
func (de *dirEntry) Name() string { return de.name }
|
func (de *dirEntry) Name() string { return de.name }
|
||||||
func (de *dirEntry) IsDir() bool { return de.isDir }
|
func (de *dirEntry) IsDir() bool { return de.isDir }
|
||||||
func (de *dirEntry) Type() fs.FileMode { return de.mode.Type() }
|
func (de *dirEntry) Type() fs.FileMode { return de.mode.Type() }
|
||||||
func (de *dirEntry) Info() (fs.FileInfo, error) { return de.info, nil }
|
func (de *dirEntry) Info() (fs.FileInfo, error) { return de.info, nil }
|
||||||
|
|
||||||
// sqliteFile implements fs.File for SQLite entries.
|
// sqliteFile implements fs.File for SQLite entries.
|
||||||
type sqliteFile struct {
|
type sqliteFile struct {
|
||||||
|
|
|
||||||
|
|
@ -21,14 +21,14 @@ import (
|
||||||
// For full GUI features, use the core-gui package.
|
// For full GUI features, use the core-gui package.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
server *mcp.Server
|
server *mcp.Server
|
||||||
workspaceRoot string // Root directory for file operations (empty = unrestricted)
|
workspaceRoot string // Root directory for file operations (empty = unrestricted)
|
||||||
medium io.Medium // Filesystem medium for sandboxed operations
|
medium io.Medium // Filesystem medium for sandboxed operations
|
||||||
subsystems []Subsystem // Additional subsystems registered via WithSubsystem
|
subsystems []Subsystem // Additional subsystems registered via WithSubsystem
|
||||||
logger *log.Logger // Logger for tool execution auditing
|
logger *log.Logger // Logger for tool execution auditing
|
||||||
processService *process.Service // Process management service (optional)
|
processService *process.Service // Process management service (optional)
|
||||||
wsHub *ws.Hub // WebSocket hub for real-time streaming (optional)
|
wsHub *ws.Hub // WebSocket hub for real-time streaming (optional)
|
||||||
wsServer *http.Server // WebSocket HTTP server (optional)
|
wsServer *http.Server // WebSocket HTTP server (optional)
|
||||||
wsAddr string // WebSocket server address
|
wsAddr string // WebSocket server address
|
||||||
}
|
}
|
||||||
|
|
||||||
// Option configures a Service.
|
// Option configures a Service.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue