gitoriaLog in with ident

antcolony

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commitc613d26bc613d26btemplates: bridges to external components (login.js for ident's selector) are allowed (creator 2026-09-27)mrec613d26b/lib/registry.hl

3.1 KB

  1. // registry.hl — project metadata, one JSON file per project (`<name>.json`), the model being the
  2. // antcolony repo's `projects/` folder on Byrodin (decided 2026-09-24, docs/scheduler-agent.md).
  3. // COLONY_PROJECTS_DIR points at the folder; default `projects/` beside scheduler.hl (a copy —
  4. // refresh it from Byrodin, README "Config").
  5. //
  6. // A project file: { name, dev: { host, folder }, concept, dependsOn: [..], code?, live?, deploy?, note?,
  7. // workers?, ui?, needs? }. Only what the rules need is checked: `name` = file name, `concept` a string (may be
  8. // empty = no concept yet), `dependsOn` a list of strings, `workers` a boolean when present
  9. // (`false` = the scheduler never starts a worker there, e.g. hybriel: AntColony only files issues).
  10. import { listDir } from 'hl:fs'
  11. import { env } from 'hl:proc'
  12. import { readJson, fromCwd, isList, isObject, isString, sortStrings } from './util.hl'
  13. static projectsDir = () => {
  14. let d = env('COLONY_PROJECTS_DIR')
  15. if (d == null || d == '') { return './projects' }
  16. return fromCwd(d)
  17. }
  18. // → { dir, projects: { name → meta }, names: [sorted], errors: [text] }
  19. static loadRegistry = () => {
  20. let dir = projectsDir()
  21. let out = { dir = dir projects = {} names = [] errors = [] }
  22. for (n of listDir(dir)) {
  23. let file = hlTypeName(n) == 'String' ? n : n.name
  24. if (file.endsWith('.json')) {
  25. let r = readJson(dir + '/' + file)
  26. let name = file.slice(0, file.length - 5)
  27. if (r.error != null) {
  28. out.errors.push(r.error)
  29. } else if (!isObject(r.value)) {
  30. out.errors.push(file + ': not a JSON object')
  31. } else if (r.value.name != name) {
  32. out.errors.push(file + ": 'name' must be '" + name + "' (the file name)")
  33. } else {
  34. let m = r.value
  35. let deps = []
  36. if (m.dependsOn != null) {
  37. if (!isList(m.dependsOn)) { out.errors.push(file + ": 'dependsOn' must be a list") } else {
  38. for (d of m.dependsOn) { if (isString(d)) { deps.push(d) } else { out.errors.push(file + ": 'dependsOn' entries must be strings") } }
  39. }
  40. }
  41. m.deps = deps
  42. m.takesWorkers = true
  43. if (m.workers != null) {
  44. if (hlTypeName(m.workers) != 'Boolean') { out.errors.push(file + ": 'workers' must be true or false") }
  45. else if (m.workers == false) { m.takesWorkers = false }
  46. }
  47. // antcolony#15: `"needs": ["chrome", "gpu"]` = capabilities the host's agent must announce before work starts here
  48. let needs = []
  49. if (m.needs != null) {
  50. if (!isList(m.needs)) { out.errors.push(file + ": 'needs' must be a list") } else {
  51. for (x of m.needs) { if (isString(x) && x.trim() != '') { needs.push(x.trim().toLowerCase()) } else { out.errors.push(file + ": 'needs' entries must be non-empty strings") } }
  52. }
  53. }
  54. m.needList = needs
  55. m.hasConcept = isString(m.concept) && m.concept.trim() != ''
  56. // mission 029: `"ui": true` = an app with pages/styles → its briefs name the creator's layout conventions
  57. m.hasUi = false
  58. if (m.ui != null) {
  59. if (hlTypeName(m.ui) != 'Boolean') { out.errors.push(file + ": 'ui' must be true or false") }
  60. else if (m.ui == true) { m.hasUi = true }
  61. }
  62. out.projects[name] = m
  63. out.names.push(name)
  64. }
  65. }
  66. }
  67. sortStrings(out.names)
  68. return out
  69. }

Branches

Latest commits

  • c613d26btemplates: bridges to external components (login.js for ident's selector) are allowed (creator 2026-09-27)mre
  • 9062978ctracker: worker box sees /media/STORAGE/projects/old-tracker read-only (tracker#2 source data)mre
  • 7f9660eeState of 2026-09-27, before the move to gitoriamre