package definition import "strings" // The closed vocabulary a definition is allowed to name. // // Every table here is a transcription of a frontend table, and the conformance // suite asserts each one against the vocabulary the JavaScript actually // exports (testdata/oracle.json, `vocabulary`) — so a page added to // surfaces.js or an icon added to vocabulary.js fails a test here rather than // silently making the two ends disagree about what is valid. // // Nothing is looked up dynamically and nothing is constructed: a definition // names a key and this file answers whether that key exists. // pageSurfaces mirrors SKILL_SURFACES in src/lib/skills/surfaces.js — id first, // then the alternative spellings an author may use for it. var pageSurfaces = []struct { ID string Aliases []string }{ {ID: "control-center"}, {ID: "positions"}, {ID: "create-position", Aliases: []string{"new-position"}}, {ID: "candidates"}, {ID: "hired-history", Aliases: []string{"hired"}}, {ID: "talent-pool"}, {ID: "krow-forge", Aliases: []string{"university", "forge"}}, {ID: "analytics"}, {ID: "activity"}, {ID: "workspace-agent-configure"}, {ID: "settings"}, {ID: "workspace"}, {ID: "workspace-agents"}, {ID: "workspace-skills"}, {ID: "workspace-skill-configure"}, {ID: "skill-development"}, {ID: "profile"}, {ID: "candidates-analysis"}, } // surfaceByKey resolves every spelling — canonical or alias — to its canonical // id. var surfaceByKey = func() map[string]string { m := map[string]string{} for _, s := range pageSurfaces { m[s.ID] = s.ID for _, a := range s.Aliases { m[a] = s.ID } } return m }() // SupportedPages is every canonical page id, in declaration order. The order is // the order the frontend lists them in when it refuses an unsupported page, and // that message is compared byte for byte. var SupportedPages = func() []string { out := make([]string, len(pageSurfaces)) for i, s := range pageSurfaces { out[i] = s.ID } return out }() // normalizeKey is surfaces.js's own: trimmed, lower-cased, with spaces and // underscores read as dashes. `Talent Pool` and `talent_pool` both reach // `talent-pool`; the canonical keys never widen, only what an author may type // to reach them. func normalizeKey(page any) string { s := strings.ToLower(jsTrim(jsString(page))) if page == nil { s = "" } return strings.Map(func(r rune) rune { if r == ' ' || r == '_' || jsIsSpace(r) { return '-' } return r }, s) } // SurfaceExists reports whether a declared page name refers to a real surface. func SurfaceExists(page any) bool { _, ok := surfaceByKey[normalizeKey(page)] return ok } // CanonicalPage is the canonical id a declared page name refers to, or "". func CanonicalPage(page any) string { return surfaceByKey[normalizeKey(page)] } /* ── Agent vocabulary — src/lib/agents/vocabulary.js ─────────────────────── */ var ( AgentStatuses = []string{"draft", "published", "archived"} ReasoningModes = []string{"fast", "balanced", "deep"} KnowledgeKinds = []string{"note", "link", "skill-reference"} AgentAccess = []string{"all", "specific"} PermissionRole = []string{"manager", "editor", "viewer"} AgentIcons = []string{ "owliver", "sparkles", "briefcase", "users", "user-check", "layers", "graduation-cap", "bar-chart", "activity", "shield", } ) const ( DefaultAgentStatus = "draft" DefaultReasoning = "balanced" DefaultAgentIcon = "owliver" DefaultKnowledgeKind = "note" DefaultAgentAccess = "all" DefaultPermission = "viewer" ) func contains(list []string, want string) bool { for _, v := range list { if v == want { return true } } return false } /* ── Skill vocabulary ────────────────────────────────────────────────────── */ // SkillStatuses is the whole of a skill's lifecycle. There is no version and no // publish step: migration 000005 states the same two values. var SkillStatuses = []string{"active", "inactive"} // levelHeadings are the rungs a workforce skill may define, and the reason a // definition is read as workforce rather than assistant. Order is the ladder's. var levelHeadings = []string{"Beginner", "Intermediate", "Advanced", "Expert"} // slugify is uiConfig.js's, used to derive an id from a name. // // String(value || '').toLowerCase().trim() // .replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '') // // The lower-casing happens BEFORE the class replacement, so an upper-case // letter becomes itself rather than a dash. func slugify(value any) string { if !jsTruthy(value) { return "" } s := jsTrim(strings.ToLower(jsString(value))) var b strings.Builder dash := false for _, r := range s { if (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9') { b.WriteRune(r) dash = false continue } if !dash { b.WriteByte('-') dash = true } } out := b.String() out = strings.TrimPrefix(out, "-") out = strings.TrimSuffix(out, "-") return out } // isDefinitionID is the id format the frontend validator enforces and the // definition_id CHECK in migration 000005 restates. func isDefinitionID(id string) bool { if id == "" { return false } for i, r := range id { lower := r >= 'a' && r <= 'z' digit := r >= '0' && r <= '9' if lower || digit { continue } if r == '-' && i > 0 { continue } return false } return true }