feat: externalize apps/analysis to Gitea repos, add analysis table

- Migration 007: repo_url on apps table + analysis table with FTS5
- Analysis struct, parser, CRUD, validation, hash computation
- Selective purge: remote-only apps/analysis preserved across fn index
- CLI: fn app list/clone/pull, fn analysis list/clone/pull
- search/show/list now include analysis results
- Apps removed from git tracking (content lives in Gitea repos)
- .gitkeep for apps/ and analysis/ dirs
- Bash functions: jupyter analysis pipeline, shell utilities
- Browser domain: CDP functions moved from infra to browser

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-01 04:23:51 +02:00
parent 8f24157096
commit d7f2c00d7b
111 changed files with 2766 additions and 5043 deletions
+38
View File
@@ -199,6 +199,44 @@ func ValidateApp(a *App, knownFunctions, knownTypes map[string]bool) *Validation
return nil
}
// ValidateAnalysis checks integrity rules for analysis entries.
func ValidateAnalysis(a *Analysis, knownFunctions, knownTypes map[string]bool) *ValidationError {
var errs []string
if a.Name == "" {
errs = append(errs, "name is required")
}
if a.Lang == "" {
errs = append(errs, "lang is required")
}
if a.Domain == "" {
errs = append(errs, "domain is required")
}
if a.Description == "" {
errs = append(errs, "description is required")
}
if a.DirPath != "" && strings.HasPrefix(a.DirPath, "/") {
errs = append(errs, "dir_path must be relative to registry root")
}
for _, ref := range a.UsesFunctions {
if !knownFunctions[ref] {
errs = append(errs, fmt.Sprintf("uses_functions references unknown function: %s", ref))
}
}
for _, ref := range a.UsesTypes {
if !knownTypes[ref] {
errs = append(errs, fmt.Sprintf("uses_types references unknown type: %s", ref))
}
}
if len(errs) > 0 {
return &ValidationError{ID: a.ID, Errors: errs}
}
return nil
}
// ValidateType checks integrity rules for types.
func ValidateType(t *Type, knownTypes map[string]bool) *ValidationError {
var errs []string