Skip to content

Commit 6300c71

Browse files
committed
Update dependencies and improve health check functionality
- Updated `github.com/xraph/vessel` and `github.com/xraph/go-utils` to version 1.0.0 across multiple modules. - Enhanced health check aggregation to use the map key as the canonical name, ensuring accurate reporting. - Added validation to ensure health check names are not empty during registration. - Improved metric value retrieval to include type metadata for better exporter handling.
1 parent f6cd3f3 commit 6300c71

File tree

225 files changed

+17059
-4459
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

225 files changed

+17059
-4459
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,5 +126,8 @@ METRICS_DEADLOCK_FIX.md
126126
extensions/dashboard/forgeui
127127
*.blob
128128

129+
# Node modules (for Tailwind CSS builds)
130+
extensions/**/node_modules/
131+
129132
# Worktrees
130133
.worktrees/

cmd/forge/go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,8 @@ require (
8989
github.com/xdg-go/scram v1.1.2 // indirect
9090
github.com/xdg-go/stringprep v1.0.4 // indirect
9191
github.com/xraph/confy v0.1.0 // indirect
92-
github.com/xraph/go-utils v0.0.11 // indirect
93-
github.com/xraph/vessel v0.0.5 // indirect
92+
github.com/xraph/go-utils v1.0.0 // indirect
93+
github.com/xraph/vessel v1.0.0 // indirect
9494
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
9595
go.mongodb.org/mongo-driver v1.17.4 // indirect
9696
go.uber.org/multierr v1.11.0 // indirect

cmd/forge/go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,10 +306,10 @@ github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6
306306
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
307307
github.com/xraph/confy v0.1.0 h1:dAdI/ShnkU5PEXVsfR86swoWj6XjJ37BdPQpBIUmg9M=
308308
github.com/xraph/confy v0.1.0/go.mod h1:/uhVfKibPR+kn7MI9LkVVekk84NP0sxsKZ9sFQoQ5Kc=
309-
github.com/xraph/go-utils v0.0.11 h1:9CT0l4yQ8RWIQJmFQcxjA1cb8Re2fHxJPDNmdmG8Vz8=
310-
github.com/xraph/go-utils v0.0.11/go.mod h1:yp+PD9dXSA7tA9Pxmuveg5E7Ht1iHIVov8yMvanMG7U=
311-
github.com/xraph/vessel v0.0.5 h1:vA/H+lB6MzBkvesysBVHRaBFtHxgVLTExCfuwWMJbjs=
312-
github.com/xraph/vessel v0.0.5/go.mod h1:t7UbkGensTnqpvda2gOnH2/lnAwnUpa5oEDFHwIqQ+k=
309+
github.com/xraph/go-utils v1.0.0 h1:P1jOvtDlC5xZyGtnIhypFfPUBgpfyrwESY4TK4P2I5g=
310+
github.com/xraph/go-utils v1.0.0/go.mod h1:yp+PD9dXSA7tA9Pxmuveg5E7Ht1iHIVov8yMvanMG7U=
311+
github.com/xraph/vessel v1.0.0 h1:n2q30d0OGPENpFfmOUgEuS99Y+X6b6WTfzdOHiE4Ds0=
312+
github.com/xraph/vessel v1.0.0/go.mod h1:quT3UWDXZF0RLL34H3ijXP9kVnh2pdfnn0f2s3ezChA=
313313
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
314314
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
315315
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=

cmd/forge/plugins/contributor.go

Lines changed: 106 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ func (p *ContributorPlugin) Commands() []cli.Command {
4444
"new",
4545
"Scaffold a new dashboard contributor",
4646
p.newContributor,
47-
cli.WithFlag(cli.NewStringFlag("framework", "f", "UI framework (astro, nextjs)", "")),
48-
cli.WithFlag(cli.NewStringFlag("mode", "m", "Build mode (static, ssr)", "static")),
47+
cli.WithFlag(cli.NewStringFlag("framework", "f", "UI framework (templ, astro, nextjs)", "")),
48+
cli.WithFlag(cli.NewStringFlag("mode", "m", "Build mode (static, ssr, local)", "static")),
4949
cli.WithFlag(cli.NewBoolFlag("in-extension", "e", "Scaffold inside an existing extension directory", false)),
5050
))
5151

@@ -105,22 +105,30 @@ func (p *ContributorPlugin) newContributor(ctx cli.CommandContext) error {
105105
framework := ctx.String("framework")
106106
if framework == "" {
107107
var err error
108-
framework, err = ctx.Select("UI framework:", []string{"astro", "nextjs"})
108+
framework, err = ctx.Select("UI framework:", []string{"templ (recommended)", "astro", "nextjs"})
109109
if err != nil {
110110
return err
111111
}
112+
// Normalize the selection (strip suffix)
113+
if framework == "templ (recommended)" {
114+
framework = "templ"
115+
}
112116
}
113117
if !contribConfig.ValidFrameworkTypes[framework] {
114-
return fmt.Errorf("unsupported framework: %s (use astro, nextjs, or custom)", framework)
118+
return fmt.Errorf("unsupported framework: %s (use templ, astro, nextjs, or custom)", framework)
115119
}
116120

117121
// Get build mode
118122
mode := ctx.String("mode")
119123
if mode == "" {
120-
mode = "static"
124+
if framework == "templ" {
125+
mode = "local"
126+
} else {
127+
mode = "static"
128+
}
121129
}
122130
if !contribConfig.ValidBuildModes[mode] {
123-
return fmt.Errorf("unsupported build mode: %s (use static or ssr)", mode)
131+
return fmt.Errorf("unsupported build mode: %s (use static, ssr, or local)", mode)
124132
}
125133

126134
// Determine target directory
@@ -143,10 +151,17 @@ func (p *ContributorPlugin) newContributor(ctx cli.CommandContext) error {
143151
spinner := ctx.Spinner(fmt.Sprintf("Scaffolding %s contributor with %s (%s)...", name, framework, mode))
144152

145153
// Create directory structure
146-
uiDir := filepath.Join(targetDir, "ui")
147-
if err := os.MkdirAll(uiDir, 0755); err != nil {
148-
spinner.Stop(cli.Red("✗ Failed"))
149-
return err
154+
if framework != "templ" {
155+
uiDir := filepath.Join(targetDir, "ui")
156+
if err := os.MkdirAll(uiDir, 0755); err != nil {
157+
spinner.Stop(cli.Red("✗ Failed"))
158+
return err
159+
}
160+
} else {
161+
if err := os.MkdirAll(targetDir, 0755); err != nil {
162+
spinner.Stop(cli.Red("✗ Failed"))
163+
return err
164+
}
150165
}
151166

152167
// Prepare template data
@@ -179,7 +194,13 @@ func (p *ContributorPlugin) newContributor(ctx cli.CommandContext) error {
179194
}
180195

181196
// Framework-specific scaffolding
197+
uiDir := filepath.Join(targetDir, "ui")
182198
switch framework {
199+
case "templ":
200+
if err := p.scaffoldTempl(targetDir, data); err != nil {
201+
spinner.Stop(cli.Red("✗ Failed"))
202+
return err
203+
}
183204
case "astro":
184205
if err := p.scaffoldAstro(uiDir, data); err != nil {
185206
spinner.Stop(cli.Red("✗ Failed"))
@@ -196,10 +217,42 @@ func (p *ContributorPlugin) newContributor(ctx cli.CommandContext) error {
196217

197218
ctx.Println("")
198219
ctx.Success("Next steps:")
199-
ctx.Println(fmt.Sprintf(" 1. cd %s/ui && npm install", relPath(p.config.RootDir, targetDir)))
200-
ctx.Println(" 2. Edit UI pages in ui/src/pages/ (Astro) or ui/app/ (Next.js)")
201-
ctx.Println(fmt.Sprintf(" 3. forge contributor build %s", name))
202-
ctx.Println(fmt.Sprintf(" 4. forge contributor dev %s # for live development", name))
220+
if framework == "templ" {
221+
ctx.Println(fmt.Sprintf(" 1. cd %s", relPath(p.config.RootDir, targetDir)))
222+
ctx.Println(" 2. Edit .templ files (pages.templ, widgets.templ, settings.templ)")
223+
ctx.Println(" 3. templ generate # generate Go code from .templ files")
224+
ctx.Println(" 4. Register the contributor in your extension's init()")
225+
} else {
226+
ctx.Println(fmt.Sprintf(" 1. cd %s/ui && npm install", relPath(p.config.RootDir, targetDir)))
227+
ctx.Println(" 2. Edit UI pages in ui/src/pages/ (Astro) or ui/app/ (Next.js)")
228+
ctx.Println(fmt.Sprintf(" 3. forge contributor build %s", name))
229+
ctx.Println(fmt.Sprintf(" 4. forge contributor dev %s # for live development", name))
230+
}
231+
232+
return nil
233+
}
234+
235+
// scaffoldTempl creates templ-specific project files directly in the contributor directory.
236+
func (p *ContributorPlugin) scaffoldTempl(targetDir string, data scaffoldTemplateData) error {
237+
// Write contributor.go (main Go file with RenderPage/RenderWidget/RenderSettings)
238+
if err := writeTemplate(filepath.Join(targetDir, "contributor.go"), templContributorGoTemplate, data); err != nil {
239+
return err
240+
}
241+
242+
// Write pages.templ (sample overview page)
243+
if err := writeTemplate(filepath.Join(targetDir, "pages.templ"), templPageTemplate, data); err != nil {
244+
return err
245+
}
246+
247+
// Write widgets.templ (sample status widget)
248+
if err := writeTemplate(filepath.Join(targetDir, "widgets.templ"), templWidgetTemplate, data); err != nil {
249+
return err
250+
}
251+
252+
// Write settings.templ (sample settings panel)
253+
if err := writeTemplate(filepath.Join(targetDir, "settings.templ"), templSettingsTemplate, data); err != nil {
254+
return err
255+
}
203256

204257
return nil
205258
}
@@ -331,8 +384,8 @@ func (p *ContributorPlugin) buildSingleContributor(ctx cli.CommandContext, dir s
331384

332385
ctx.Info(fmt.Sprintf("Building contributor: %s (%s, %s mode)", cfg.DisplayName, cfg.Type, cfg.Build.Mode))
333386

334-
// Step 1: npm install (if requested and node_modules doesn't exist or flag set)
335-
if install {
387+
// Step 1: npm install (if requested, not templ, and node_modules doesn't exist)
388+
if install && cfg.Type != "templ" {
336389
if _, err := os.Stat(filepath.Join(uiDir, "node_modules")); os.IsNotExist(err) {
337390
spinner := ctx.Spinner("Installing dependencies...")
338391
pm := detectPackageManager(uiDir)
@@ -359,9 +412,15 @@ func (p *ContributorPlugin) buildSingleContributor(ctx cli.CommandContext, dir s
359412
buildCmd = adapter.DefaultBuildCmd(cfg.Build.Mode)
360413
}
361414

415+
// For templ, run the build command in the contributor dir; for others, in the ui dir
416+
buildDir := uiDir
417+
if cfg.Type == "templ" {
418+
buildDir = configDir
419+
}
420+
362421
spinner := ctx.Spinner(fmt.Sprintf("Building %s UI...", cfg.Type))
363422
cmd := exec.Command("sh", "-c", buildCmd)
364-
cmd.Dir = uiDir
423+
cmd.Dir = buildDir
365424
cmd.Stdout = os.Stdout
366425
cmd.Stderr = os.Stderr
367426
if err := cmd.Run(); err != nil {
@@ -370,10 +429,12 @@ func (p *ContributorPlugin) buildSingleContributor(ctx cli.CommandContext, dir s
370429
}
371430
spinner.Stop(cli.Green("✓ UI built"))
372431

373-
// Step 3: Validate build output
374-
distPath := cfg.DistPath(configDir)
375-
if err := adapter.ValidateBuild(distPath); err != nil {
376-
return fmt.Errorf("build validation failed: %w", err)
432+
// Step 3: Validate build output (skip for templ — compiled into Go binary)
433+
if cfg.Type != "templ" {
434+
distPath := cfg.DistPath(configDir)
435+
if err := adapter.ValidateBuild(distPath); err != nil {
436+
return fmt.Errorf("build validation failed: %w", err)
437+
}
377438
}
378439

379440
// Step 4: Run codegen
@@ -463,19 +524,21 @@ func (p *ContributorPlugin) devContributor(ctx cli.CommandContext) error {
463524
cfgDir := filepath.Dir(yamlPath)
464525
uiDir := cfg.UIPath(cfgDir)
465526

466-
// Ensure dependencies are installed
467-
if _, err := os.Stat(filepath.Join(uiDir, "node_modules")); os.IsNotExist(err) {
468-
spinner := ctx.Spinner("Installing dependencies...")
469-
pm := detectPackageManager(uiDir)
470-
cmd := exec.Command("sh", "-c", installCmd(pm))
471-
cmd.Dir = uiDir
472-
cmd.Stdout = os.Stdout
473-
cmd.Stderr = os.Stderr
474-
if err := cmd.Run(); err != nil {
475-
spinner.Stop(cli.Red("✗ Install failed"))
476-
return fmt.Errorf("npm install failed: %w", err)
527+
// Ensure dependencies are installed (skip for templ)
528+
if cfg.Type != "templ" {
529+
if _, err := os.Stat(filepath.Join(uiDir, "node_modules")); os.IsNotExist(err) {
530+
spinner := ctx.Spinner("Installing dependencies...")
531+
pm := detectPackageManager(uiDir)
532+
cmd := exec.Command("sh", "-c", installCmd(pm))
533+
cmd.Dir = uiDir
534+
cmd.Stdout = os.Stdout
535+
cmd.Stderr = os.Stderr
536+
if err := cmd.Run(); err != nil {
537+
spinner.Stop(cli.Red("✗ Install failed"))
538+
return fmt.Errorf("npm install failed: %w", err)
539+
}
540+
spinner.Stop(cli.Green("✓ Dependencies installed"))
477541
}
478-
spinner.Stop(cli.Green("✓ Dependencies installed"))
479542
}
480543

481544
// Determine dev command
@@ -489,19 +552,25 @@ func (p *ContributorPlugin) devContributor(ctx cli.CommandContext) error {
489552
devCmd = adapter.DefaultDevCmd()
490553
}
491554

492-
// Add port if specified
555+
// Add port if specified (not applicable for templ)
493556
port := ctx.Int("port")
494-
if port > 0 {
557+
if port > 0 && cfg.Type != "templ" {
495558
devCmd = fmt.Sprintf("%s --port %d", devCmd, port)
496559
}
497560

561+
// For templ, run in contributor dir; for others, in ui dir
562+
runDir := uiDir
563+
if cfg.Type == "templ" {
564+
runDir = cfgDir
565+
}
566+
498567
ctx.Info(fmt.Sprintf("Starting %s dev server for %s...", cfg.Type, cfg.DisplayName))
499-
ctx.Info(fmt.Sprintf(" UI dir: %s", relPath(p.config.RootDir, uiDir)))
568+
ctx.Info(fmt.Sprintf(" Dir: %s", relPath(p.config.RootDir, runDir)))
500569
ctx.Println("")
501570

502571
// Run dev server (blocking — user Ctrl+C to stop)
503572
cmd := exec.Command("sh", "-c", devCmd)
504-
cmd.Dir = uiDir
573+
cmd.Dir = runDir
505574
cmd.Stdout = os.Stdout
506575
cmd.Stderr = os.Stderr
507576
cmd.Stdin = os.Stdin

cmd/forge/plugins/contributor_adapters.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ type FrameworkAdapter interface {
3131
// GetFrameworkAdapter returns the adapter for the given framework type.
3232
func GetFrameworkAdapter(frameworkType string) (FrameworkAdapter, error) {
3333
switch frameworkType {
34+
case "templ":
35+
return &TemplAdapter{}, nil
3436
case "astro":
3537
return &AstroAdapter{}, nil
3638
case "nextjs":
@@ -129,6 +131,33 @@ func (a *CustomAdapter) ValidateBuild(distDir string) error {
129131
return nil
130132
}
131133

134+
// TemplAdapter provides templ-specific build configuration.
135+
// Templ contributors are Go-native — they compile directly into the Go binary
136+
// without requiring Node.js, npm, or a separate build output directory.
137+
type TemplAdapter struct{}
138+
139+
func (a *TemplAdapter) Name() string { return "templ" }
140+
141+
func (a *TemplAdapter) DefaultBuildCmd(_ string) string {
142+
return "templ generate"
143+
}
144+
145+
func (a *TemplAdapter) DefaultDevCmd() string {
146+
return "templ generate --watch"
147+
}
148+
149+
func (a *TemplAdapter) DefaultDistDir(_ string) string {
150+
return "" // No dist dir — compiled into Go binary
151+
}
152+
153+
func (a *TemplAdapter) DefaultSSREntry() string {
154+
return "" // No SSR entry — runs in-process via LocalContributor
155+
}
156+
157+
func (a *TemplAdapter) ValidateBuild(_ string) error {
158+
return nil // Templ generates Go code; validation happens at go build time
159+
}
160+
132161
// detectPackageManager detects the package manager from lockfiles in the given directory.
133162
func detectPackageManager(dir string) string {
134163
if _, err := os.Stat(filepath.Join(dir, "pnpm-lock.yaml")); err == nil {

0 commit comments

Comments
 (0)