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:
|
||||
|
||||
env:
|
||||
REGISTRY: gitea.snider.dev
|
||||
REGISTRY: dappco.re/osi
|
||||
IMAGE_APP: host-uk/app
|
||||
IMAGE_WEB: host-uk/web
|
||||
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 { provideRouter, withHashLocation } from '@angular/router';
|
||||
import { provideRouter } from '@angular/router';
|
||||
import { routes } from './app.routes';
|
||||
|
||||
export const appConfig: ApplicationConfig = {
|
||||
providers: [
|
||||
provideRouter(routes, withHashLocation())
|
||||
provideRouter(routes)
|
||||
]
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { Component } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';
|
||||
import { ChatComponent } from '../chat/chat.component';
|
||||
import { BuildComponent } from '../build/build.component';
|
||||
import { DashboardComponent } from '../dashboard/dashboard.component';
|
||||
|
|
@ -11,7 +10,7 @@ type Panel = 'chat' | 'build' | 'dashboard' | 'jellyfin';
|
|||
@Component({
|
||||
selector: 'app-main',
|
||||
standalone: true,
|
||||
imports: [CommonModule, RouterLink, RouterLinkActive, RouterOutlet, ChatComponent, BuildComponent, DashboardComponent, JellyfinComponent],
|
||||
imports: [CommonModule, ChatComponent, BuildComponent, DashboardComponent, JellyfinComponent],
|
||||
template: `
|
||||
<div class="ide">
|
||||
<nav class="ide__sidebar">
|
||||
|
|
|
|||
|
|
@ -81,4 +81,3 @@ func (s *IDEService) ShowWindow(name string) {
|
|||
w.Focus()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,8 +79,8 @@ func (b *MCPBridge) startHTTPServer() {
|
|||
mux.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"status": "ok",
|
||||
"mcp": true,
|
||||
"status": "ok",
|
||||
"mcp": true,
|
||||
"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
|
||||
}
|
||||
|
||||
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 {
|
||||
Hours() float64
|
||||
Minutes() float64
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// cmd_agent.go manages persistent agent context within task workspaces.
|
||||
//
|
||||
// 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
|
||||
// understanding over time — QA agents accumulate findings, reviewers
|
||||
|
|
@ -34,7 +35,7 @@ import (
|
|||
|
||||
var (
|
||||
agentProvider string
|
||||
agentName string
|
||||
agentName string
|
||||
)
|
||||
|
||||
func addAgentCommands(parent *cobra.Command) {
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
taskEpic int
|
||||
taskIssue int
|
||||
taskRepos []string
|
||||
taskForce bool
|
||||
taskBranch string
|
||||
taskEpic int
|
||||
taskIssue int
|
||||
taskRepos []string
|
||||
taskForce bool
|
||||
taskBranch string
|
||||
)
|
||||
|
||||
func addTaskCommands(parent *cobra.Command) {
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ type User struct {
|
|||
// Challenge is a PGP-encrypted nonce sent to a client during authentication.
|
||||
type Challenge struct {
|
||||
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"`
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -226,14 +226,14 @@ func (b *CPPBuilder) findBinaries(fs io.Medium, projectDir string, target build.
|
|||
func (b *CPPBuilder) targetToProfile(target build.Target) string {
|
||||
key := target.OS + "/" + target.Arch
|
||||
profiles := map[string]string{
|
||||
"linux/amd64": "gcc-linux-x86_64",
|
||||
"linux/x86_64": "gcc-linux-x86_64",
|
||||
"linux/arm64": "gcc-linux-armv8",
|
||||
"linux/armv8": "gcc-linux-armv8",
|
||||
"darwin/arm64": "apple-clang-armv8",
|
||||
"darwin/armv8": "apple-clang-armv8",
|
||||
"darwin/amd64": "apple-clang-x86_64",
|
||||
"darwin/x86_64": "apple-clang-x86_64",
|
||||
"linux/amd64": "gcc-linux-x86_64",
|
||||
"linux/x86_64": "gcc-linux-x86_64",
|
||||
"linux/arm64": "gcc-linux-armv8",
|
||||
"linux/armv8": "gcc-linux-armv8",
|
||||
"darwin/arm64": "apple-clang-armv8",
|
||||
"darwin/armv8": "apple-clang-armv8",
|
||||
"darwin/amd64": "apple-clang-x86_64",
|
||||
"darwin/x86_64": "apple-clang-x86_64",
|
||||
"windows/amd64": "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.BuildPreRelease=dev.8"
|
||||
var (
|
||||
AppVersion = "0.0.0"
|
||||
BuildCommit = "unknown"
|
||||
BuildDate = "unknown"
|
||||
AppVersion = "0.0.0"
|
||||
BuildCommit = "unknown"
|
||||
BuildDate = "unknown"
|
||||
BuildPreRelease = ""
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,19 +12,19 @@ import (
|
|||
|
||||
// Config is the top-level infrastructure configuration parsed from infra.yaml.
|
||||
type Config struct {
|
||||
Hosts map[string]*Host `yaml:"hosts"`
|
||||
LoadBalancer LoadBalancer `yaml:"load_balancer"`
|
||||
Network Network `yaml:"network"`
|
||||
DNS DNS `yaml:"dns"`
|
||||
SSL SSL `yaml:"ssl"`
|
||||
Database Database `yaml:"database"`
|
||||
Cache Cache `yaml:"cache"`
|
||||
Hosts map[string]*Host `yaml:"hosts"`
|
||||
LoadBalancer LoadBalancer `yaml:"load_balancer"`
|
||||
Network Network `yaml:"network"`
|
||||
DNS DNS `yaml:"dns"`
|
||||
SSL SSL `yaml:"ssl"`
|
||||
Database Database `yaml:"database"`
|
||||
Cache Cache `yaml:"cache"`
|
||||
Containers map[string]*Container `yaml:"containers"`
|
||||
S3 S3Config `yaml:"s3"`
|
||||
CDN CDN `yaml:"cdn"`
|
||||
CICD CICD `yaml:"cicd"`
|
||||
Monitoring Monitoring `yaml:"monitoring"`
|
||||
Backups Backups `yaml:"backups"`
|
||||
S3 S3Config `yaml:"s3"`
|
||||
CDN CDN `yaml:"cdn"`
|
||||
CICD CICD `yaml:"cicd"`
|
||||
Monitoring Monitoring `yaml:"monitoring"`
|
||||
Backups Backups `yaml:"backups"`
|
||||
}
|
||||
|
||||
// Host represents a server in the infrastructure.
|
||||
|
|
@ -47,16 +47,16 @@ type SSHConf struct {
|
|||
|
||||
// LoadBalancer represents a Hetzner managed load balancer.
|
||||
type LoadBalancer struct {
|
||||
Name string `yaml:"name"`
|
||||
FQDN string `yaml:"fqdn"`
|
||||
Provider string `yaml:"provider"`
|
||||
Type string `yaml:"type"`
|
||||
Location string `yaml:"location"`
|
||||
Algorithm string `yaml:"algorithm"`
|
||||
Backends []Backend `yaml:"backends"`
|
||||
Name string `yaml:"name"`
|
||||
FQDN string `yaml:"fqdn"`
|
||||
Provider string `yaml:"provider"`
|
||||
Type string `yaml:"type"`
|
||||
Location string `yaml:"location"`
|
||||
Algorithm string `yaml:"algorithm"`
|
||||
Backends []Backend `yaml:"backends"`
|
||||
Health HealthCheck `yaml:"health_check"`
|
||||
Listeners []Listener `yaml:"listeners"`
|
||||
SSL LBCert `yaml:"ssl"`
|
||||
Listeners []Listener `yaml:"listeners"`
|
||||
SSL LBCert `yaml:"ssl"`
|
||||
}
|
||||
|
||||
// Backend is a load balancer backend target.
|
||||
|
|
@ -94,9 +94,9 @@ type Network struct {
|
|||
|
||||
// DNS holds DNS provider configuration and zone records.
|
||||
type DNS struct {
|
||||
Provider string `yaml:"provider"`
|
||||
Nameservers []string `yaml:"nameservers"`
|
||||
Zones map[string]*Zone `yaml:"zones"`
|
||||
Provider string `yaml:"provider"`
|
||||
Nameservers []string `yaml:"nameservers"`
|
||||
Zones map[string]*Zone `yaml:"zones"`
|
||||
}
|
||||
|
||||
// Zone is a DNS zone with its records.
|
||||
|
|
@ -203,8 +203,8 @@ type CICD struct {
|
|||
|
||||
// Monitoring describes monitoring configuration.
|
||||
type Monitoring struct {
|
||||
HealthEndpoints []HealthEndpoint `yaml:"health_endpoints"`
|
||||
Alerts map[string]int `yaml:"alerts"`
|
||||
HealthEndpoints []HealthEndpoint `yaml:"health_endpoints"`
|
||||
Alerts map[string]int `yaml:"alerts"`
|
||||
}
|
||||
|
||||
// HealthEndpoint is a URL to monitor.
|
||||
|
|
|
|||
|
|
@ -552,10 +552,12 @@ type dirEntry struct {
|
|||
name string
|
||||
}
|
||||
|
||||
func (d *dirEntry) Name() string { return d.name }
|
||||
func (d *dirEntry) IsDir() bool { return true }
|
||||
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) Name() string { return d.name }
|
||||
func (d *dirEntry) IsDir() bool { return true }
|
||||
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
|
||||
}
|
||||
|
||||
type fileInfo struct {
|
||||
name string
|
||||
|
|
|
|||
|
|
@ -335,7 +335,7 @@ func TestOverwrite_Good(t *testing.T) {
|
|||
func TestExists_Good(t *testing.T) {
|
||||
m := New()
|
||||
|
||||
assert.True(t, m.Exists("")) // root
|
||||
assert.True(t, m.Exists("")) // root
|
||||
assert.False(t, m.Exists("x"))
|
||||
|
||||
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) Read(_ []byte) (int, error) { return 0, goio.EOF }
|
||||
func (d *dataFile) Close() error { return nil }
|
||||
func (d *dataFile) Read(_ []byte) (int, error) { return 0, goio.EOF }
|
||||
func (d *dataFile) Close() error { return nil }
|
||||
|
||||
// dataFileInfo implements fs.FileInfo for a dataFile.
|
||||
type dataFileInfo struct{ file *dataFile }
|
||||
|
|
@ -496,11 +496,13 @@ var _ fs.ReadDirFS = (*Node)(nil)
|
|||
// Unexported helper: ensure ReadStream result also satisfies fs.File
|
||||
// (for cases where callers do a type assertion).
|
||||
var _ goio.ReadCloser = goio.NopCloser(nil)
|
||||
|
||||
// Ensure nodeWriter satisfies goio.WriteCloser.
|
||||
var _ goio.WriteCloser = (*nodeWriter)(nil)
|
||||
|
||||
// Ensure dirFile satisfies fs.File.
|
||||
var _ fs.File = (*dirFile)(nil)
|
||||
|
||||
// Ensure dataFileReader satisfies fs.File.
|
||||
var _ fs.File = (*dataFileReader)(nil)
|
||||
|
||||
|
|
|
|||
|
|
@ -567,7 +567,7 @@ type dirEntry struct {
|
|||
func (de *dirEntry) Name() string { return de.name }
|
||||
func (de *dirEntry) IsDir() bool { return de.isDir }
|
||||
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.
|
||||
type s3File struct {
|
||||
|
|
|
|||
|
|
@ -239,9 +239,9 @@ func TestHashSigil_Good(t *testing.T) {
|
|||
data := []byte("hash me")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
name string
|
||||
sigilName string
|
||||
size int
|
||||
size int
|
||||
}{
|
||||
{"md5", "md5", md5.Size},
|
||||
{"sha1", "sha1", sha1.Size},
|
||||
|
|
|
|||
|
|
@ -611,7 +611,7 @@ type dirEntry struct {
|
|||
func (de *dirEntry) Name() string { return de.name }
|
||||
func (de *dirEntry) IsDir() bool { return de.isDir }
|
||||
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.
|
||||
type sqliteFile struct {
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@ import (
|
|||
// For full GUI features, use the core-gui package.
|
||||
type Service struct {
|
||||
server *mcp.Server
|
||||
workspaceRoot string // Root directory for file operations (empty = unrestricted)
|
||||
medium io.Medium // Filesystem medium for sandboxed operations
|
||||
subsystems []Subsystem // Additional subsystems registered via WithSubsystem
|
||||
logger *log.Logger // Logger for tool execution auditing
|
||||
processService *process.Service // Process management service (optional)
|
||||
wsHub *ws.Hub // WebSocket hub for real-time streaming (optional)
|
||||
wsServer *http.Server // WebSocket HTTP server (optional)
|
||||
wsAddr string // WebSocket server address
|
||||
workspaceRoot string // Root directory for file operations (empty = unrestricted)
|
||||
medium io.Medium // Filesystem medium for sandboxed operations
|
||||
subsystems []Subsystem // Additional subsystems registered via WithSubsystem
|
||||
logger *log.Logger // Logger for tool execution auditing
|
||||
processService *process.Service // Process management service (optional)
|
||||
wsHub *ws.Hub // WebSocket hub for real-time streaming (optional)
|
||||
wsServer *http.Server // WebSocket HTTP server (optional)
|
||||
wsAddr string // WebSocket server address
|
||||
}
|
||||
|
||||
// Option configures a Service.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue