Skip to content

Commit 9ac01fb

Browse files
committed
Merge upstream-fix/build-churn into halo-main (PR smart-mcp-proxy#472)
Brings in the generator-sync + drift-prevention test: - fc0945c fix(generate-types): re-sync hardcoded TS output with contracts.ts - f2d90e5 test(generate-types): catch future contracts.ts drift in CI After this merge, running `go run ./cmd/generate-types` is idempotent against the committed frontend/src/types/contracts.ts and CI will fail on any future drift between the two.
2 parents b56ee5c + f2d90e5 commit 9ac01fb

2 files changed

Lines changed: 86 additions & 14 deletions

File tree

cmd/generate-types/main.go

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,34 @@ import (
88
"strings"
99
)
1010

11-
func main() {
12-
// Define the TypeScript types based on our Go contracts
13-
typeDefinitions := generateTypeDefinitions()
11+
// contractsRelPath is the location of the generated TypeScript file
12+
// relative to the module root.
13+
const contractsRelPath = "frontend/src/types/contracts.ts"
14+
15+
// generateFileContent returns the full contents that should be written to
16+
// contracts.ts (header + generated type definitions). Exposed so tests can
17+
// verify the committed file matches the generator output and catch drift
18+
// without writing to disk.
19+
func generateFileContent() string {
20+
return fmt.Sprintf(`// Generated TypeScript types from Go contracts
21+
// DO NOT EDIT - This file is auto-generated by cmd/generate-types
22+
23+
%s`, generateTypeDefinitions())
24+
}
1425

15-
// Create output directory if it doesn't exist
16-
outputDir := "frontend/src/types"
26+
func main() {
27+
outputDir := filepath.Dir(contractsRelPath)
1728
if err := os.MkdirAll(outputDir, 0755); err != nil {
1829
fmt.Printf("Error creating output directory: %v\n", err)
1930
os.Exit(1)
2031
}
2132

22-
// Write the TypeScript file
23-
outputFile := filepath.Join(outputDir, "contracts.ts")
24-
content := fmt.Sprintf(`// Generated TypeScript types from Go contracts
25-
// DO NOT EDIT - This file is auto-generated by cmd/generate-types
26-
27-
%s`, typeDefinitions)
28-
29-
if err := os.WriteFile(outputFile, []byte(content), 0600); err != nil {
33+
if err := os.WriteFile(contractsRelPath, []byte(generateFileContent()), 0600); err != nil {
3034
fmt.Printf("Error writing TypeScript file: %v\n", err)
3135
os.Exit(1)
3236
}
3337

34-
fmt.Printf("Successfully generated TypeScript types: %s\n", outputFile)
38+
fmt.Printf("Successfully generated TypeScript types: %s\n", contractsRelPath)
3539
}
3640

3741
func generateTypeDefinitions() string {
@@ -117,6 +121,7 @@ export interface HealthStatus {
117121
created: string; // ISO date string
118122
updated: string; // ISO date string
119123
isolation?: IsolationConfig;
124+
isolation_defaults?: IsolationDefaults; // Resolved baseline values (read-only, used as placeholders)
120125
oauth_status?: 'authenticated' | 'expired' | 'error' | 'none'; // OAuth authentication status
121126
token_expires_at?: string; // ISO date string when OAuth token expires
122127
user_logged_out?: boolean; // True if user explicitly logged out (prevents auto-reconnection)
@@ -135,12 +140,27 @@ export interface OAuthConfig {
135140
export interface IsolationConfig {
136141
enabled: boolean;
137142
image?: string;
143+
network_mode?: string;
144+
extra_args?: string[];
138145
memory_limit?: string;
139146
cpu_limit?: string;
140147
working_dir?: string;
141148
timeout?: string;
142149
}
143150
151+
// IsolationDefaults reports the resolved baseline Docker isolation
152+
// values the backend will apply when no per-server override is set.
153+
// Populated on server-list / server-get responses; the Web UI uses these
154+
// as placeholders so "empty = inherit" is discoverable instead of
155+
// mysterious. Never sent back on PATCH requests.
156+
export interface IsolationDefaults {
157+
runtime_type?: string;
158+
image?: string;
159+
network_mode?: string;
160+
extra_args?: string[];
161+
working_dir?: string;
162+
}
163+
144164
`)
145165

146166
// Tool types
@@ -151,6 +171,12 @@ export interface IsolationConfig {
151171
schema?: Record<string, any>;
152172
usage: number;
153173
last_used?: string; // ISO date string
174+
// Mirrors contracts.Tool.Disabled on the Go side — present when an
175+
// approval record exists for this tool. Absent means "enabled" (default).
176+
disabled?: boolean;
177+
// Tool-level quarantine status surfaced by the same approval record.
178+
// Optional because non-quarantined tools simply omit the field.
179+
approval_status?: string;
154180
}
155181
156182
export interface SearchResult {

cmd/generate-types/main_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package main
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
)
8+
9+
// TestContractsInSync fails when frontend/src/types/contracts.ts has drifted
10+
// from what cmd/generate-types would produce today. Catches the failure mode
11+
// where a contributor hand-edits contracts.ts (or hand-edits the generator's
12+
// hardcoded string literals) without updating the other side: the next
13+
// `make build` / `go run ./cmd/generate-types` silently reverts their work
14+
// and leaves a dirty working tree.
15+
//
16+
// To fix a failure of this test:
17+
// 1. Decide which side is correct (usually: the generator).
18+
// 2. Run `go run ./cmd/generate-types` from the module root, OR update the
19+
// string literals in main.go to match contracts.ts.
20+
// 3. Commit both files in the same change.
21+
func TestContractsInSync(t *testing.T) {
22+
// cmd/generate-types tests run with cwd = the package directory.
23+
// Walk up two levels to reach the module root.
24+
contractsPath := filepath.Join("..", "..", contractsRelPath)
25+
26+
committed, err := os.ReadFile(contractsPath)
27+
if err != nil {
28+
t.Fatalf("reading %s: %v", contractsPath, err)
29+
}
30+
31+
generated := []byte(generateFileContent())
32+
33+
if string(committed) == string(generated) {
34+
return
35+
}
36+
37+
t.Fatalf(
38+
"%s is out of sync with cmd/generate-types/main.go.\n"+
39+
"\nThe TypeScript string literals in main.go must produce a byte-identical\n"+
40+
"copy of contracts.ts. To fix: either run `go run ./cmd/generate-types`\n"+
41+
"from the module root (if the generator is the source of truth) or update\n"+
42+
"the string literals in main.go (if contracts.ts is the source of truth).\n"+
43+
"\ncommitted size: %d bytes\ngenerated size: %d bytes",
44+
contractsRelPath, len(committed), len(generated),
45+
)
46+
}

0 commit comments

Comments
 (0)