@ag-eco/agentplate-cli 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +462 -0
- package/agents/ap-co-creation.md +90 -0
- package/agents/builder.md +144 -0
- package/agents/coordinator.md +377 -0
- package/agents/lead.md +435 -0
- package/agents/merger.md +164 -0
- package/agents/monitor.md +214 -0
- package/agents/orchestrator.md +239 -0
- package/agents/reviewer.md +140 -0
- package/agents/scout.md +125 -0
- package/agents/supervisor.md +427 -0
- package/package.json +66 -0
- package/src/agents/capabilities.test.ts +85 -0
- package/src/agents/capabilities.ts +125 -0
- package/src/agents/checkpoint.test.ts +88 -0
- package/src/agents/checkpoint.ts +101 -0
- package/src/agents/copilot-hooks-deployer.test.ts +162 -0
- package/src/agents/copilot-hooks-deployer.ts +93 -0
- package/src/agents/guard-rules.test.ts +372 -0
- package/src/agents/guard-rules.ts +97 -0
- package/src/agents/headless-mail-injector.test.ts +709 -0
- package/src/agents/headless-mail-injector.ts +377 -0
- package/src/agents/headless-prompt.test.ts +102 -0
- package/src/agents/headless-prompt.ts +68 -0
- package/src/agents/hooks-deployer.test.ts +3119 -0
- package/src/agents/hooks-deployer.ts +804 -0
- package/src/agents/identity.test.ts +604 -0
- package/src/agents/identity.ts +384 -0
- package/src/agents/lifecycle.test.ts +196 -0
- package/src/agents/lifecycle.ts +183 -0
- package/src/agents/mail-poll-detect.test.ts +153 -0
- package/src/agents/mail-poll-detect.ts +73 -0
- package/src/agents/manifest.test.ts +1026 -0
- package/src/agents/manifest.ts +376 -0
- package/src/agents/overlay.test.ts +1058 -0
- package/src/agents/overlay.ts +490 -0
- package/src/agents/scope-detect.test.ts +190 -0
- package/src/agents/scope-detect.ts +146 -0
- package/src/agents/turn-lock.test.ts +181 -0
- package/src/agents/turn-lock.ts +235 -0
- package/src/agents/turn-runner-dispatch.test.ts +182 -0
- package/src/agents/turn-runner-dispatch.ts +105 -0
- package/src/agents/turn-runner.test.ts +2312 -0
- package/src/agents/turn-runner.ts +1383 -0
- package/src/beads/client.test.ts +217 -0
- package/src/beads/client.ts +230 -0
- package/src/beads/molecules.test.ts +338 -0
- package/src/beads/molecules.ts +198 -0
- package/src/commands/agents.test.ts +328 -0
- package/src/commands/agents.ts +299 -0
- package/src/commands/clean.test.ts +797 -0
- package/src/commands/clean.ts +791 -0
- package/src/commands/completions.test.ts +348 -0
- package/src/commands/completions.ts +981 -0
- package/src/commands/coordinator.test.ts +2975 -0
- package/src/commands/coordinator.ts +1841 -0
- package/src/commands/costs.test.ts +1183 -0
- package/src/commands/costs.ts +599 -0
- package/src/commands/dashboard.test.ts +954 -0
- package/src/commands/dashboard.ts +1212 -0
- package/src/commands/discover.test.ts +288 -0
- package/src/commands/discover.ts +202 -0
- package/src/commands/doctor.test.ts +303 -0
- package/src/commands/doctor.ts +311 -0
- package/src/commands/ecosystem.test.ts +226 -0
- package/src/commands/ecosystem.ts +248 -0
- package/src/commands/errors.test.ts +654 -0
- package/src/commands/errors.ts +197 -0
- package/src/commands/feed.test.ts +709 -0
- package/src/commands/feed.ts +260 -0
- package/src/commands/group.test.ts +475 -0
- package/src/commands/group.ts +546 -0
- package/src/commands/hooks.test.ts +458 -0
- package/src/commands/hooks.ts +263 -0
- package/src/commands/init.test.ts +1011 -0
- package/src/commands/init.ts +967 -0
- package/src/commands/inspect.test.ts +1239 -0
- package/src/commands/inspect.ts +648 -0
- package/src/commands/log.test.ts +1913 -0
- package/src/commands/log.ts +958 -0
- package/src/commands/logs.test.ts +801 -0
- package/src/commands/logs.ts +483 -0
- package/src/commands/mail.test.ts +1501 -0
- package/src/commands/mail.ts +848 -0
- package/src/commands/merge.test.ts +864 -0
- package/src/commands/merge.ts +381 -0
- package/src/commands/metrics.test.ts +458 -0
- package/src/commands/metrics.ts +129 -0
- package/src/commands/monitor.test.ts +191 -0
- package/src/commands/monitor.ts +409 -0
- package/src/commands/nudge.test.ts +579 -0
- package/src/commands/nudge.ts +646 -0
- package/src/commands/orchestrator.ts +42 -0
- package/src/commands/prime.test.ts +612 -0
- package/src/commands/prime.ts +359 -0
- package/src/commands/replay.test.ts +757 -0
- package/src/commands/replay.ts +231 -0
- package/src/commands/run.test.ts +469 -0
- package/src/commands/run.ts +353 -0
- package/src/commands/serve/agent-actions.test.ts +210 -0
- package/src/commands/serve/agent-actions.ts +192 -0
- package/src/commands/serve/build.test.ts +202 -0
- package/src/commands/serve/build.ts +206 -0
- package/src/commands/serve/coordinator-actions.test.ts +339 -0
- package/src/commands/serve/coordinator-actions.ts +410 -0
- package/src/commands/serve/dev.test.ts +168 -0
- package/src/commands/serve/dev.ts +117 -0
- package/src/commands/serve/mail-actions.test.ts +312 -0
- package/src/commands/serve/mail-actions.ts +167 -0
- package/src/commands/serve/rest.test.ts +1680 -0
- package/src/commands/serve/rest.ts +1130 -0
- package/src/commands/serve/static.ts +51 -0
- package/src/commands/serve/ws.test.ts +361 -0
- package/src/commands/serve/ws.ts +332 -0
- package/src/commands/serve.test.ts +459 -0
- package/src/commands/serve.ts +654 -0
- package/src/commands/sling.test.ts +1583 -0
- package/src/commands/sling.ts +1351 -0
- package/src/commands/spec.test.ts +179 -0
- package/src/commands/spec.ts +105 -0
- package/src/commands/status.test.ts +614 -0
- package/src/commands/status.ts +403 -0
- package/src/commands/stop.test.ts +964 -0
- package/src/commands/stop.ts +319 -0
- package/src/commands/supervisor.test.ts +185 -0
- package/src/commands/supervisor.ts +537 -0
- package/src/commands/trace.test.ts +762 -0
- package/src/commands/trace.ts +205 -0
- package/src/commands/update.test.ts +466 -0
- package/src/commands/update.ts +263 -0
- package/src/commands/upgrade.test.ts +48 -0
- package/src/commands/upgrade.ts +240 -0
- package/src/commands/watch.test.ts +257 -0
- package/src/commands/watch.ts +308 -0
- package/src/commands/worktree.test.ts +1297 -0
- package/src/commands/worktree.ts +451 -0
- package/src/config.test.ts +1535 -0
- package/src/config.ts +1064 -0
- package/src/doctor/agents.test.ts +523 -0
- package/src/doctor/agents.ts +399 -0
- package/src/doctor/config-check.test.ts +191 -0
- package/src/doctor/config-check.ts +183 -0
- package/src/doctor/consistency.test.ts +807 -0
- package/src/doctor/consistency.ts +347 -0
- package/src/doctor/databases.test.ts +350 -0
- package/src/doctor/databases.ts +243 -0
- package/src/doctor/dependencies.test.ts +296 -0
- package/src/doctor/dependencies.ts +272 -0
- package/src/doctor/ecosystem.test.ts +308 -0
- package/src/doctor/ecosystem.ts +156 -0
- package/src/doctor/logs.test.ts +253 -0
- package/src/doctor/logs.ts +295 -0
- package/src/doctor/merge-queue.test.ts +315 -0
- package/src/doctor/merge-queue.ts +167 -0
- package/src/doctor/providers.test.ts +409 -0
- package/src/doctor/providers.ts +250 -0
- package/src/doctor/serve.test.ts +95 -0
- package/src/doctor/serve.ts +86 -0
- package/src/doctor/structure.test.ts +423 -0
- package/src/doctor/structure.ts +285 -0
- package/src/doctor/types.ts +43 -0
- package/src/doctor/version.test.ts +241 -0
- package/src/doctor/version.ts +132 -0
- package/src/doctor/watchdog.test.ts +167 -0
- package/src/doctor/watchdog.ts +214 -0
- package/src/e2e/init-sling-lifecycle.test.ts +283 -0
- package/src/errors.test.ts +350 -0
- package/src/errors.ts +217 -0
- package/src/events/store.test.ts +660 -0
- package/src/events/store.ts +369 -0
- package/src/events/tailer.test.ts +719 -0
- package/src/events/tailer.ts +332 -0
- package/src/events/tool-filter.test.ts +330 -0
- package/src/events/tool-filter.ts +126 -0
- package/src/index.ts +533 -0
- package/src/insights/analyzer.test.ts +466 -0
- package/src/insights/analyzer.ts +203 -0
- package/src/insights/quality-gates.test.ts +141 -0
- package/src/insights/quality-gates.ts +156 -0
- package/src/json.test.ts +72 -0
- package/src/json.ts +53 -0
- package/src/loam/client.test.ts +752 -0
- package/src/loam/client.ts +664 -0
- package/src/logging/color.test.ts +252 -0
- package/src/logging/color.ts +105 -0
- package/src/logging/format.test.ts +110 -0
- package/src/logging/format.ts +255 -0
- package/src/logging/logger.test.ts +814 -0
- package/src/logging/logger.ts +266 -0
- package/src/logging/reporter.test.ts +259 -0
- package/src/logging/reporter.ts +110 -0
- package/src/logging/sanitizer.test.ts +190 -0
- package/src/logging/sanitizer.ts +57 -0
- package/src/logging/theme.ts +140 -0
- package/src/mail/broadcast.test.ts +204 -0
- package/src/mail/broadcast.ts +92 -0
- package/src/mail/client.test.ts +774 -0
- package/src/mail/client.ts +236 -0
- package/src/mail/store.test.ts +898 -0
- package/src/mail/store.ts +425 -0
- package/src/merge/lock.test.ts +149 -0
- package/src/merge/lock.ts +140 -0
- package/src/merge/predict.test.ts +387 -0
- package/src/merge/predict.ts +249 -0
- package/src/merge/queue.test.ts +426 -0
- package/src/merge/queue.ts +246 -0
- package/src/merge/resolver.test.ts +1993 -0
- package/src/merge/resolver.ts +926 -0
- package/src/metrics/pricing.test.ts +258 -0
- package/src/metrics/pricing.ts +135 -0
- package/src/metrics/store.test.ts +978 -0
- package/src/metrics/store.ts +501 -0
- package/src/metrics/summary.test.ts +398 -0
- package/src/metrics/summary.ts +178 -0
- package/src/metrics/transcript.test.ts +483 -0
- package/src/metrics/transcript.ts +114 -0
- package/src/runtimes/__fixtures__/claude-stream-fixture.ts +22 -0
- package/src/runtimes/aider.test.ts +124 -0
- package/src/runtimes/aider.ts +147 -0
- package/src/runtimes/amp.test.ts +164 -0
- package/src/runtimes/amp.ts +154 -0
- package/src/runtimes/claude.test.ts +1474 -0
- package/src/runtimes/claude.ts +579 -0
- package/src/runtimes/codex.test.ts +805 -0
- package/src/runtimes/codex.ts +273 -0
- package/src/runtimes/connections.test.ts +214 -0
- package/src/runtimes/connections.ts +103 -0
- package/src/runtimes/copilot.test.ts +707 -0
- package/src/runtimes/copilot.ts +316 -0
- package/src/runtimes/cursor.test.ts +497 -0
- package/src/runtimes/cursor.ts +205 -0
- package/src/runtimes/gemini.test.ts +537 -0
- package/src/runtimes/gemini.ts +243 -0
- package/src/runtimes/goose.test.ts +133 -0
- package/src/runtimes/goose.ts +157 -0
- package/src/runtimes/headless-connection.test.ts +264 -0
- package/src/runtimes/headless-connection.ts +158 -0
- package/src/runtimes/opencode.test.ts +325 -0
- package/src/runtimes/opencode.ts +188 -0
- package/src/runtimes/pi-guards.test.ts +486 -0
- package/src/runtimes/pi-guards.ts +367 -0
- package/src/runtimes/pi.test.ts +789 -0
- package/src/runtimes/pi.ts +305 -0
- package/src/runtimes/registry.test.ts +196 -0
- package/src/runtimes/registry.ts +99 -0
- package/src/runtimes/sapling.test.ts +1267 -0
- package/src/runtimes/sapling.ts +710 -0
- package/src/runtimes/types.ts +266 -0
- package/src/schema-consistency.test.ts +246 -0
- package/src/sessions/compat.test.ts +281 -0
- package/src/sessions/compat.ts +105 -0
- package/src/sessions/store.test.ts +1748 -0
- package/src/sessions/store.ts +858 -0
- package/src/test-helpers.test.ts +124 -0
- package/src/test-helpers.ts +145 -0
- package/src/test-setup.test.ts +31 -0
- package/src/test-setup.ts +28 -0
- package/src/tools/loam/api.ts +368 -0
- package/src/tools/loam/cli.ts +278 -0
- package/src/tools/loam/commands/add.ts +52 -0
- package/src/tools/loam/commands/archive.ts +214 -0
- package/src/tools/loam/commands/audit.ts +276 -0
- package/src/tools/loam/commands/compact.ts +1062 -0
- package/src/tools/loam/commands/completions.ts +79 -0
- package/src/tools/loam/commands/config.ts +381 -0
- package/src/tools/loam/commands/delete-domain.ts +121 -0
- package/src/tools/loam/commands/delete.ts +316 -0
- package/src/tools/loam/commands/diff.ts +200 -0
- package/src/tools/loam/commands/doctor.ts +1113 -0
- package/src/tools/loam/commands/edit.ts +226 -0
- package/src/tools/loam/commands/init.ts +31 -0
- package/src/tools/loam/commands/learn.ts +179 -0
- package/src/tools/loam/commands/move.ts +323 -0
- package/src/tools/loam/commands/onboard.ts +374 -0
- package/src/tools/loam/commands/outcome.ts +185 -0
- package/src/tools/loam/commands/prime.ts +688 -0
- package/src/tools/loam/commands/prune.ts +614 -0
- package/src/tools/loam/commands/query.ts +218 -0
- package/src/tools/loam/commands/rank.ts +180 -0
- package/src/tools/loam/commands/ready.ts +189 -0
- package/src/tools/loam/commands/record.ts +1210 -0
- package/src/tools/loam/commands/restore.ts +166 -0
- package/src/tools/loam/commands/search.ts +327 -0
- package/src/tools/loam/commands/setup.ts +887 -0
- package/src/tools/loam/commands/status.ts +103 -0
- package/src/tools/loam/commands/sync.ts +298 -0
- package/src/tools/loam/commands/update.ts +19 -0
- package/src/tools/loam/commands/upgrade.ts +93 -0
- package/src/tools/loam/commands/validate.ts +190 -0
- package/src/tools/loam/index.ts +62 -0
- package/src/tools/loam/log.ts +127 -0
- package/src/tools/loam/registry/builtins.ts +409 -0
- package/src/tools/loam/registry/custom.ts +431 -0
- package/src/tools/loam/registry/init.ts +55 -0
- package/src/tools/loam/registry/template.ts +40 -0
- package/src/tools/loam/registry/type-registry.ts +113 -0
- package/src/tools/loam/schemas/config-schema.ts +489 -0
- package/src/tools/loam/schemas/config.ts +245 -0
- package/src/tools/loam/schemas/index.ts +18 -0
- package/src/tools/loam/schemas/record-schema.ts +191 -0
- package/src/tools/loam/schemas/record.ts +115 -0
- package/src/tools/loam/utils/active-work.ts +205 -0
- package/src/tools/loam/utils/anchor-validity.ts +80 -0
- package/src/tools/loam/utils/archive.ts +146 -0
- package/src/tools/loam/utils/audit.ts +667 -0
- package/src/tools/loam/utils/bm25.ts +238 -0
- package/src/tools/loam/utils/budget.ts +142 -0
- package/src/tools/loam/utils/config.ts +344 -0
- package/src/tools/loam/utils/dir-anchors.ts +62 -0
- package/src/tools/loam/utils/domain-rules.ts +114 -0
- package/src/tools/loam/utils/expertise.ts +393 -0
- package/src/tools/loam/utils/format-helpers.ts +96 -0
- package/src/tools/loam/utils/format.ts +1234 -0
- package/src/tools/loam/utils/git-context.ts +50 -0
- package/src/tools/loam/utils/git.ts +183 -0
- package/src/tools/loam/utils/hooks.ts +299 -0
- package/src/tools/loam/utils/index.ts +52 -0
- package/src/tools/loam/utils/json-output.ts +13 -0
- package/src/tools/loam/utils/lock.ts +76 -0
- package/src/tools/loam/utils/markers.ts +48 -0
- package/src/tools/loam/utils/numeric-flags.ts +20 -0
- package/src/tools/loam/utils/palette.ts +44 -0
- package/src/tools/loam/utils/prime-ranking.ts +135 -0
- package/src/tools/loam/utils/recipe-discovery.ts +195 -0
- package/src/tools/loam/utils/runtime-flags.ts +28 -0
- package/src/tools/loam/utils/scoring.ts +94 -0
- package/src/tools/loam/utils/version.ts +116 -0
- package/src/tools/sprout/commands/block.ts +64 -0
- package/src/tools/sprout/commands/blocked.ts +86 -0
- package/src/tools/sprout/commands/close.ts +129 -0
- package/src/tools/sprout/commands/completions.ts +198 -0
- package/src/tools/sprout/commands/config.ts +238 -0
- package/src/tools/sprout/commands/create.ts +164 -0
- package/src/tools/sprout/commands/dep.ts +148 -0
- package/src/tools/sprout/commands/doctor.ts +979 -0
- package/src/tools/sprout/commands/init.ts +83 -0
- package/src/tools/sprout/commands/label.ts +178 -0
- package/src/tools/sprout/commands/list.ts +210 -0
- package/src/tools/sprout/commands/migrate.ts +133 -0
- package/src/tools/sprout/commands/onboard.ts +207 -0
- package/src/tools/sprout/commands/plan-show.ts +278 -0
- package/src/tools/sprout/commands/plan.ts +2526 -0
- package/src/tools/sprout/commands/prime.ts +399 -0
- package/src/tools/sprout/commands/ready.ts +245 -0
- package/src/tools/sprout/commands/search.ts +221 -0
- package/src/tools/sprout/commands/show.ts +277 -0
- package/src/tools/sprout/commands/stats.ts +146 -0
- package/src/tools/sprout/commands/sync.ts +134 -0
- package/src/tools/sprout/commands/tpl.ts +364 -0
- package/src/tools/sprout/commands/unblock.ts +115 -0
- package/src/tools/sprout/commands/update.ts +257 -0
- package/src/tools/sprout/commands/upgrade.ts +91 -0
- package/src/tools/sprout/config-schema.ts +152 -0
- package/src/tools/sprout/config.ts +355 -0
- package/src/tools/sprout/filter.ts +107 -0
- package/src/tools/sprout/format.ts +43 -0
- package/src/tools/sprout/id.ts +22 -0
- package/src/tools/sprout/index.ts +204 -0
- package/src/tools/sprout/log.ts +76 -0
- package/src/tools/sprout/markers.ts +22 -0
- package/src/tools/sprout/output.ts +121 -0
- package/src/tools/sprout/plan-backref.ts +93 -0
- package/src/tools/sprout/plan-context.ts +81 -0
- package/src/tools/sprout/plan-domain.ts +139 -0
- package/src/tools/sprout/plan-lifecycle.ts +65 -0
- package/src/tools/sprout/plan-loam.ts +207 -0
- package/src/tools/sprout/plan-schema.ts +209 -0
- package/src/tools/sprout/sort.ts +31 -0
- package/src/tools/sprout/store.ts +172 -0
- package/src/tools/sprout/types.ts +118 -0
- package/src/tools/sprout/validation.ts +119 -0
- package/src/tools/sprout/version.ts +1 -0
- package/src/tools/sprout/yaml.ts +387 -0
- package/src/tools/trellis/commands/archive.ts +87 -0
- package/src/tools/trellis/commands/completions.ts +610 -0
- package/src/tools/trellis/commands/config.ts +382 -0
- package/src/tools/trellis/commands/create.ts +252 -0
- package/src/tools/trellis/commands/diff.ts +150 -0
- package/src/tools/trellis/commands/doctor.ts +771 -0
- package/src/tools/trellis/commands/emit.ts +365 -0
- package/src/tools/trellis/commands/history.ts +83 -0
- package/src/tools/trellis/commands/import.ts +198 -0
- package/src/tools/trellis/commands/init.ts +81 -0
- package/src/tools/trellis/commands/list.ts +103 -0
- package/src/tools/trellis/commands/onboard.ts +156 -0
- package/src/tools/trellis/commands/pin.ts +172 -0
- package/src/tools/trellis/commands/prime.ts +193 -0
- package/src/tools/trellis/commands/render.ts +122 -0
- package/src/tools/trellis/commands/schema.ts +353 -0
- package/src/tools/trellis/commands/show.ts +115 -0
- package/src/tools/trellis/commands/stats.ts +65 -0
- package/src/tools/trellis/commands/sync.ts +112 -0
- package/src/tools/trellis/commands/tree.ts +123 -0
- package/src/tools/trellis/commands/update.ts +330 -0
- package/src/tools/trellis/commands/upgrade.ts +95 -0
- package/src/tools/trellis/commands/validate.ts +166 -0
- package/src/tools/trellis/config-schema.ts +81 -0
- package/src/tools/trellis/config.ts +108 -0
- package/src/tools/trellis/frontmatter.ts +348 -0
- package/src/tools/trellis/id.ts +24 -0
- package/src/tools/trellis/index.ts +209 -0
- package/src/tools/trellis/markers.ts +28 -0
- package/src/tools/trellis/output.ts +84 -0
- package/src/tools/trellis/render.ts +212 -0
- package/src/tools/trellis/store.ts +144 -0
- package/src/tools/trellis/types.ts +82 -0
- package/src/tools/trellis/validate.ts +199 -0
- package/src/tools/trellis/yaml.ts +309 -0
- package/src/tracker/beads.test.ts +454 -0
- package/src/tracker/beads.ts +56 -0
- package/src/tracker/factory.test.ts +90 -0
- package/src/tracker/factory.ts +65 -0
- package/src/tracker/sprout.test.ts +461 -0
- package/src/tracker/sprout.ts +182 -0
- package/src/tracker/types.ts +52 -0
- package/src/trellis/client.test.ts +107 -0
- package/src/trellis/client.ts +179 -0
- package/src/types.ts +970 -0
- package/src/utils/bin.test.ts +10 -0
- package/src/utils/bin.ts +37 -0
- package/src/utils/browser.test.ts +49 -0
- package/src/utils/browser.ts +48 -0
- package/src/utils/fs.test.ts +119 -0
- package/src/utils/fs.ts +62 -0
- package/src/utils/pid.test.ts +152 -0
- package/src/utils/pid.ts +130 -0
- package/src/utils/process-scan.test.ts +53 -0
- package/src/utils/process-scan.ts +76 -0
- package/src/utils/time.test.ts +43 -0
- package/src/utils/time.ts +37 -0
- package/src/utils/version.test.ts +33 -0
- package/src/utils/version.ts +70 -0
- package/src/version.ts +5 -0
- package/src/watchdog/daemon.test.ts +3721 -0
- package/src/watchdog/daemon.ts +1257 -0
- package/src/watchdog/health.test.ts +830 -0
- package/src/watchdog/health.ts +434 -0
- package/src/watchdog/triage.test.ts +205 -0
- package/src/watchdog/triage.ts +205 -0
- package/src/worktree/manager.test.ts +720 -0
- package/src/worktree/manager.ts +405 -0
- package/src/worktree/process.test.ts +172 -0
- package/src/worktree/process.ts +131 -0
- package/src/worktree/tmux.test.ts +1616 -0
- package/src/worktree/tmux.ts +721 -0
- package/templates/CLAUDE.md.tmpl +100 -0
- package/templates/copilot-hooks.json.tmpl +13 -0
- package/templates/hooks.json.tmpl +109 -0
- package/templates/overlay.md.tmpl +88 -0
- package/ui/dist/apple-touch-icon-bdy6teep.png +0 -0
- package/ui/dist/chunk-8s31f05k.css +1 -0
- package/ui/dist/chunk-vm5rz679.js +300 -0
- package/ui/dist/favicon-nzb39vza.svg +4 -0
- package/ui/dist/index.html +17 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export interface Section {
|
|
2
|
+
name: string;
|
|
3
|
+
body: string;
|
|
4
|
+
required?: boolean;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type LoamOnEmpty = "skip" | "warn" | "error";
|
|
8
|
+
|
|
9
|
+
export interface LoamPrime {
|
|
10
|
+
domains?: string[];
|
|
11
|
+
files?: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface LoamBlock {
|
|
15
|
+
prime?: LoamPrime;
|
|
16
|
+
budget?: number;
|
|
17
|
+
on_empty?: LoamOnEmpty;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface Prompt {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
version: number;
|
|
25
|
+
sections: Section[];
|
|
26
|
+
extends?: string;
|
|
27
|
+
mixins?: string[];
|
|
28
|
+
tags?: string[];
|
|
29
|
+
schema?: string;
|
|
30
|
+
emitAs?: string;
|
|
31
|
+
emitDir?: string;
|
|
32
|
+
pinned?: number;
|
|
33
|
+
frontmatter?: Record<string, unknown>;
|
|
34
|
+
loam?: LoamBlock;
|
|
35
|
+
extends_loam?: boolean;
|
|
36
|
+
status: "draft" | "active" | "archived";
|
|
37
|
+
createdAt: string;
|
|
38
|
+
updatedAt: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ValidationRule {
|
|
42
|
+
section: string;
|
|
43
|
+
pattern: string;
|
|
44
|
+
message: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface Schema {
|
|
48
|
+
id: string;
|
|
49
|
+
name: string;
|
|
50
|
+
requiredSections: string[];
|
|
51
|
+
optionalSections?: string[];
|
|
52
|
+
rules?: ValidationRule[];
|
|
53
|
+
createdAt: string;
|
|
54
|
+
updatedAt: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface EmitTarget {
|
|
58
|
+
dir: string;
|
|
59
|
+
default?: boolean;
|
|
60
|
+
tags?: string[];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface Config {
|
|
64
|
+
project: string;
|
|
65
|
+
version: string;
|
|
66
|
+
targets?: Record<string, EmitTarget>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Thrown inside lock-guarded blocks instead of process.exit(1)
|
|
71
|
+
* to ensure finally blocks release the lock before exiting.
|
|
72
|
+
*/
|
|
73
|
+
export class ExitError extends Error {
|
|
74
|
+
constructor(public readonly exitCode: number = 1) {
|
|
75
|
+
super("");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export const LOCK_STALE_MS = 30000;
|
|
80
|
+
export const LOCK_RETRY_MS = 50;
|
|
81
|
+
export const LOCK_TIMEOUT_MS = 5000;
|
|
82
|
+
export const MAX_INHERIT_DEPTH = 5;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { resolvePrompt } from "./render.ts";
|
|
2
|
+
import type { Prompt, Schema } from "./types.ts";
|
|
3
|
+
|
|
4
|
+
export interface ValidationResult {
|
|
5
|
+
valid: boolean;
|
|
6
|
+
errors: ValidationError[];
|
|
7
|
+
warnings: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ValidationError {
|
|
11
|
+
section: string;
|
|
12
|
+
rule: string;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function validatePrompt(
|
|
17
|
+
prompt: Prompt,
|
|
18
|
+
schema: Schema,
|
|
19
|
+
allPrompts: Prompt[],
|
|
20
|
+
): ValidationResult {
|
|
21
|
+
const errors: ValidationError[] = [];
|
|
22
|
+
const warnings: string[] = [];
|
|
23
|
+
|
|
24
|
+
// Resolve full section list (including inherited sections)
|
|
25
|
+
let sections = prompt.sections;
|
|
26
|
+
try {
|
|
27
|
+
const rendered = resolvePrompt(prompt.name, allPrompts);
|
|
28
|
+
sections = rendered.sections;
|
|
29
|
+
} catch {
|
|
30
|
+
// If render fails, validate with own sections only
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const sectionMap = new Map(sections.map((s) => [s.name, s]));
|
|
34
|
+
|
|
35
|
+
// Check required sections
|
|
36
|
+
for (const required of schema.requiredSections) {
|
|
37
|
+
if (!sectionMap.has(required)) {
|
|
38
|
+
errors.push({
|
|
39
|
+
section: required,
|
|
40
|
+
rule: "required",
|
|
41
|
+
message: `Required section "${required}" is missing`,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Run regex rules
|
|
47
|
+
if (schema.rules) {
|
|
48
|
+
for (const rule of schema.rules) {
|
|
49
|
+
const section = sectionMap.get(rule.section);
|
|
50
|
+
if (!section) {
|
|
51
|
+
// Section doesn't exist — skip regex check (required check handles missing)
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const regex = new RegExp(rule.pattern);
|
|
57
|
+
if (!regex.test(section.body)) {
|
|
58
|
+
errors.push({
|
|
59
|
+
section: rule.section,
|
|
60
|
+
rule: rule.pattern,
|
|
61
|
+
message: rule.message,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
} catch {
|
|
65
|
+
warnings.push(
|
|
66
|
+
`Invalid regex pattern in rule for section "${rule.section}": ${rule.pattern}`,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Loam block / extends_loam shape validation runs regardless of schema rules.
|
|
73
|
+
errors.push(...validateLoam(prompt));
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
valid: errors.length === 0,
|
|
77
|
+
errors,
|
|
78
|
+
warnings,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const VALID_LOAM_KEYS = new Set(["prime", "budget", "on_empty"]);
|
|
83
|
+
const VALID_PRIME_KEYS = new Set(["domains", "files"]);
|
|
84
|
+
const VALID_ON_EMPTY = new Set(["skip", "warn", "error"]);
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Validate the shape of a prompt's `loam` block and `extends_loam` flag.
|
|
88
|
+
* Returns structural errors (unknown keys, wrong types, bad enum values).
|
|
89
|
+
* Does not check semantics like "domains exist in .loam/loam.config.yaml" —
|
|
90
|
+
* that lives in the optional doctor check (trellis-552d).
|
|
91
|
+
*/
|
|
92
|
+
export function validateLoam(prompt: Prompt): ValidationError[] {
|
|
93
|
+
const errors: ValidationError[] = [];
|
|
94
|
+
|
|
95
|
+
const extendsLoam = (prompt as { extends_loam?: unknown }).extends_loam;
|
|
96
|
+
if (extendsLoam !== undefined && typeof extendsLoam !== "boolean") {
|
|
97
|
+
errors.push({
|
|
98
|
+
section: "extends_loam",
|
|
99
|
+
rule: "type",
|
|
100
|
+
message: `extends_loam must be a boolean (got ${describeValue(extendsLoam)})`,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const loam = (prompt as { loam?: unknown }).loam;
|
|
105
|
+
if (loam === undefined) return errors;
|
|
106
|
+
|
|
107
|
+
if (!isPlainObject(loam)) {
|
|
108
|
+
errors.push({
|
|
109
|
+
section: "loam",
|
|
110
|
+
rule: "type",
|
|
111
|
+
message: `loam must be an object (got ${describeValue(loam)})`,
|
|
112
|
+
});
|
|
113
|
+
return errors;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
for (const key of Object.keys(loam)) {
|
|
117
|
+
if (!VALID_LOAM_KEYS.has(key)) {
|
|
118
|
+
errors.push({
|
|
119
|
+
section: "loam",
|
|
120
|
+
rule: "unknown-key",
|
|
121
|
+
message: `Unknown key "${key}" in loam block (allowed: prime, budget, on_empty)`,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (loam.budget !== undefined) {
|
|
127
|
+
const b = loam.budget;
|
|
128
|
+
if (typeof b !== "number" || !Number.isFinite(b) || b < 0) {
|
|
129
|
+
errors.push({
|
|
130
|
+
section: "loam.budget",
|
|
131
|
+
rule: "type",
|
|
132
|
+
message: `loam.budget must be a non-negative finite number (got ${describeValue(b)})`,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (loam.on_empty !== undefined) {
|
|
138
|
+
const v = loam.on_empty;
|
|
139
|
+
if (typeof v !== "string" || !VALID_ON_EMPTY.has(v)) {
|
|
140
|
+
errors.push({
|
|
141
|
+
section: "loam.on_empty",
|
|
142
|
+
rule: "enum",
|
|
143
|
+
message: `loam.on_empty must be one of "skip", "warn", "error" (got ${describeValue(v)})`,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (loam.prime !== undefined) {
|
|
149
|
+
const prime = loam.prime;
|
|
150
|
+
if (!isPlainObject(prime)) {
|
|
151
|
+
errors.push({
|
|
152
|
+
section: "loam.prime",
|
|
153
|
+
rule: "type",
|
|
154
|
+
message: `loam.prime must be an object (got ${describeValue(prime)})`,
|
|
155
|
+
});
|
|
156
|
+
} else {
|
|
157
|
+
for (const key of Object.keys(prime)) {
|
|
158
|
+
if (!VALID_PRIME_KEYS.has(key)) {
|
|
159
|
+
errors.push({
|
|
160
|
+
section: "loam.prime",
|
|
161
|
+
rule: "unknown-key",
|
|
162
|
+
message: `Unknown key "${key}" in loam.prime (allowed: domains, files)`,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (prime.domains !== undefined && !isStringArray(prime.domains)) {
|
|
167
|
+
errors.push({
|
|
168
|
+
section: "loam.prime.domains",
|
|
169
|
+
rule: "type",
|
|
170
|
+
message: `loam.prime.domains must be an array of strings (got ${describeValue(prime.domains)})`,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (prime.files !== undefined && !isStringArray(prime.files)) {
|
|
174
|
+
errors.push({
|
|
175
|
+
section: "loam.prime.files",
|
|
176
|
+
rule: "type",
|
|
177
|
+
message: `loam.prime.files must be an array of strings (got ${describeValue(prime.files)})`,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return errors;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function isPlainObject(v: unknown): v is Record<string, unknown> {
|
|
187
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function isStringArray(v: unknown): v is string[] {
|
|
191
|
+
return Array.isArray(v) && v.every((item) => typeof item === "string");
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function describeValue(v: unknown): string {
|
|
195
|
+
if (v === null) return "null";
|
|
196
|
+
if (Array.isArray(v)) return "array";
|
|
197
|
+
if (typeof v === "string") return `string "${v}"`;
|
|
198
|
+
return typeof v;
|
|
199
|
+
}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal YAML parser for config files with multi-level nesting and array support.
|
|
3
|
+
* Handles: string values, quoted strings, numbers as strings, nested maps, arrays.
|
|
4
|
+
* Does NOT handle: multiline values, flow syntax ({}/[]), anchors/aliases.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface YamlMap {
|
|
8
|
+
[key: string]: YamlValue;
|
|
9
|
+
}
|
|
10
|
+
export type YamlValue = string | string[] | YamlMap;
|
|
11
|
+
|
|
12
|
+
// Broader scalar/flow value type for parseScalarOrFlow: covers the values a
|
|
13
|
+
// user can pass on the command line (tl config set <path> <value>). Kept
|
|
14
|
+
// alongside YamlMap/YamlValue rather than replacing them so existing
|
|
15
|
+
// parseYaml/serializeYaml callers (config.yaml round-trips) remain unchanged.
|
|
16
|
+
export type YamlScalar =
|
|
17
|
+
| string
|
|
18
|
+
| number
|
|
19
|
+
| boolean
|
|
20
|
+
| null
|
|
21
|
+
| YamlScalar[]
|
|
22
|
+
| { [key: string]: YamlScalar };
|
|
23
|
+
|
|
24
|
+
function maybeQuote(value: string): string {
|
|
25
|
+
const needsQuotes =
|
|
26
|
+
value.includes(":") ||
|
|
27
|
+
value.includes("#") ||
|
|
28
|
+
value.includes('"') ||
|
|
29
|
+
value.includes("'") ||
|
|
30
|
+
value.includes("\n") ||
|
|
31
|
+
value.startsWith(" ") ||
|
|
32
|
+
value.endsWith(" ");
|
|
33
|
+
|
|
34
|
+
if (needsQuotes) {
|
|
35
|
+
const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
|
|
36
|
+
return `"${escaped}"`;
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function unquote(value: string): string {
|
|
42
|
+
// Handle double-quoted strings
|
|
43
|
+
if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) {
|
|
44
|
+
return value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\").replace(/\\n/g, "\n");
|
|
45
|
+
}
|
|
46
|
+
// Handle single-quoted strings
|
|
47
|
+
if (value.startsWith("'") && value.endsWith("'") && value.length >= 2) {
|
|
48
|
+
return value.slice(1, -1).replace(/\\''/g, "'");
|
|
49
|
+
}
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function stripInlineComment(value: string): string {
|
|
54
|
+
if (!value.startsWith('"') && !value.startsWith("'")) {
|
|
55
|
+
const commentIdx = value.indexOf(" #");
|
|
56
|
+
if (commentIdx !== -1) {
|
|
57
|
+
return value.slice(0, commentIdx).trim();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getIndent(line: string): number {
|
|
64
|
+
return line.length - line.trimStart().length;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function parseBlock(lines: string[], startIdx: number, baseIndent: number): [YamlMap, number] {
|
|
68
|
+
const result: YamlMap = {};
|
|
69
|
+
let i = startIdx;
|
|
70
|
+
|
|
71
|
+
while (i < lines.length) {
|
|
72
|
+
const rawLine = lines[i] ?? "";
|
|
73
|
+
const trimmed = rawLine.trim();
|
|
74
|
+
|
|
75
|
+
// Skip empty lines and comments
|
|
76
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
77
|
+
i++;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const indent = getIndent(rawLine);
|
|
82
|
+
|
|
83
|
+
// Dedented — end of this block
|
|
84
|
+
if (indent < baseIndent) break;
|
|
85
|
+
|
|
86
|
+
// Array item at this indent — shouldn't happen at map level
|
|
87
|
+
if (trimmed.startsWith("- ")) break;
|
|
88
|
+
|
|
89
|
+
const colonIdx = trimmed.indexOf(":");
|
|
90
|
+
if (colonIdx === -1) {
|
|
91
|
+
i++;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
96
|
+
const valuePart = trimmed.slice(colonIdx + 1).trim();
|
|
97
|
+
|
|
98
|
+
if (!key) {
|
|
99
|
+
i++;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Key has an inline value
|
|
104
|
+
if (valuePart && !valuePart.startsWith("#")) {
|
|
105
|
+
result[key] = unquote(stripInlineComment(valuePart));
|
|
106
|
+
i++;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// No inline value — look for children
|
|
111
|
+
i++;
|
|
112
|
+
if (i < lines.length) {
|
|
113
|
+
// Find the next non-empty, non-comment line
|
|
114
|
+
let peekIdx = i;
|
|
115
|
+
while (peekIdx < lines.length) {
|
|
116
|
+
const peekTrimmed = (lines[peekIdx] ?? "").trim();
|
|
117
|
+
if (peekTrimmed && !peekTrimmed.startsWith("#")) break;
|
|
118
|
+
peekIdx++;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (peekIdx < lines.length) {
|
|
122
|
+
const nextRaw = lines[peekIdx] ?? "";
|
|
123
|
+
const nextIndent = getIndent(nextRaw);
|
|
124
|
+
const nextTrimmed = nextRaw.trim();
|
|
125
|
+
|
|
126
|
+
if (nextIndent > baseIndent) {
|
|
127
|
+
if (nextTrimmed.startsWith("- ")) {
|
|
128
|
+
// Array children
|
|
129
|
+
const [arr, newIdx] = parseArray(lines, peekIdx, nextIndent);
|
|
130
|
+
result[key] = arr;
|
|
131
|
+
i = newIdx;
|
|
132
|
+
} else {
|
|
133
|
+
// Nested map children
|
|
134
|
+
const [map, newIdx] = parseBlock(lines, peekIdx, nextIndent);
|
|
135
|
+
result[key] = map;
|
|
136
|
+
i = newIdx;
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
// No children — empty value
|
|
140
|
+
result[key] = "";
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
result[key] = "";
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
result[key] = "";
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return [result, i];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function parseArray(lines: string[], startIdx: number, baseIndent: number): [string[], number] {
|
|
154
|
+
const result: string[] = [];
|
|
155
|
+
let i = startIdx;
|
|
156
|
+
|
|
157
|
+
while (i < lines.length) {
|
|
158
|
+
const rawLine = lines[i] ?? "";
|
|
159
|
+
const trimmed = rawLine.trim();
|
|
160
|
+
|
|
161
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
162
|
+
i++;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const indent = getIndent(rawLine);
|
|
167
|
+
if (indent < baseIndent) break;
|
|
168
|
+
|
|
169
|
+
if (trimmed.startsWith("- ")) {
|
|
170
|
+
result.push(unquote(stripInlineComment(trimmed.slice(2).trim())));
|
|
171
|
+
i++;
|
|
172
|
+
} else {
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return [result, i];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function parseYaml(text: string): YamlMap {
|
|
181
|
+
const lines = text.split("\n");
|
|
182
|
+
const [result] = parseBlock(lines, 0, 0);
|
|
183
|
+
return result;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function serializeValue(key: string, value: YamlValue, indent: number): string[] {
|
|
187
|
+
const prefix = "\t".repeat(0) + " ".repeat(indent);
|
|
188
|
+
|
|
189
|
+
if (typeof value === "string") {
|
|
190
|
+
return [`${prefix}${key}: ${maybeQuote(value)}`];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (Array.isArray(value)) {
|
|
194
|
+
const lines = [`${prefix}${key}:`];
|
|
195
|
+
for (const item of value) {
|
|
196
|
+
lines.push(`${prefix} - ${maybeQuote(item)}`);
|
|
197
|
+
}
|
|
198
|
+
return lines;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Nested map
|
|
202
|
+
const lines = [`${prefix}${key}:`];
|
|
203
|
+
for (const [childKey, childValue] of Object.entries(value)) {
|
|
204
|
+
lines.push(...serializeValue(childKey, childValue, indent + 2));
|
|
205
|
+
}
|
|
206
|
+
return lines;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export function serializeYaml(obj: YamlMap): string {
|
|
210
|
+
const lines: string[] = [];
|
|
211
|
+
|
|
212
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
213
|
+
lines.push(...serializeValue(key, value, 0));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return `${lines.join("\n")}\n`;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Parse a single scalar or flow-style value. Used by `tl config set` to turn a
|
|
220
|
+
// CLI argument into a typed JSON value before schema-validating the write.
|
|
221
|
+
// Supports: quoted strings, booleans, null/~, integers, floats, flow sequences
|
|
222
|
+
// [a, b, c], and flow mappings { k: v, k2: v2 }. Bare strings pass through.
|
|
223
|
+
export function parseScalarOrFlow(s: string): YamlScalar {
|
|
224
|
+
if (s.startsWith("[")) return parseFlowSeq(s);
|
|
225
|
+
if (s.startsWith("{")) return parseFlowMap(s);
|
|
226
|
+
if (s.startsWith('"') || s.startsWith("'")) return unquoteScalar(s);
|
|
227
|
+
if (s === "true") return true;
|
|
228
|
+
if (s === "false") return false;
|
|
229
|
+
if (s === "null" || s === "~" || s === "") return null;
|
|
230
|
+
if (/^-?\d+$/.test(s)) return Number(s);
|
|
231
|
+
if (/^-?\d+\.\d+$/.test(s)) return Number(s);
|
|
232
|
+
return s;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function unquoteScalar(s: string): string {
|
|
236
|
+
if (s.length >= 2 && s.startsWith('"') && s.endsWith('"')) {
|
|
237
|
+
try {
|
|
238
|
+
return JSON.parse(s) as string;
|
|
239
|
+
} catch {
|
|
240
|
+
return s.slice(1, -1);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (s.length >= 2 && s.startsWith("'") && s.endsWith("'")) {
|
|
244
|
+
return s.slice(1, -1).replace(/''/g, "'");
|
|
245
|
+
}
|
|
246
|
+
return s;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function parseFlowSeq(s: string): YamlScalar[] {
|
|
250
|
+
if (!s.endsWith("]")) throw new Error(`Unclosed flow sequence: ${s}`);
|
|
251
|
+
const inner = s.slice(1, -1).trim();
|
|
252
|
+
if (inner === "") return [];
|
|
253
|
+
return splitFlow(inner).map((p) => parseScalarOrFlow(p.trim()));
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function parseFlowMap(s: string): { [key: string]: YamlScalar } {
|
|
257
|
+
if (!s.endsWith("}")) throw new Error(`Unclosed flow mapping: ${s}`);
|
|
258
|
+
const inner = s.slice(1, -1).trim();
|
|
259
|
+
const out: { [key: string]: YamlScalar } = {};
|
|
260
|
+
if (inner === "") return out;
|
|
261
|
+
for (const part of splitFlow(inner)) {
|
|
262
|
+
const t = part.trim();
|
|
263
|
+
const colonIdx = findFlowKeyColon(t);
|
|
264
|
+
if (colonIdx === -1) throw new Error(`Flow map entry missing ':': ${t}`);
|
|
265
|
+
const k = unquoteScalar(t.slice(0, colonIdx).trim());
|
|
266
|
+
const v = t.slice(colonIdx + 1).trim();
|
|
267
|
+
out[k] = parseScalarOrFlow(v);
|
|
268
|
+
}
|
|
269
|
+
return out;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function findFlowKeyColon(text: string): number {
|
|
273
|
+
let inSingle = false;
|
|
274
|
+
let inDouble = false;
|
|
275
|
+
let depth = 0;
|
|
276
|
+
for (let i = 0; i < text.length; i++) {
|
|
277
|
+
const c = text[i];
|
|
278
|
+
if (!inDouble && c === "'") inSingle = !inSingle;
|
|
279
|
+
else if (!inSingle && c === '"') inDouble = !inDouble;
|
|
280
|
+
else if (!inSingle && !inDouble && (c === "{" || c === "[")) depth++;
|
|
281
|
+
else if (!inSingle && !inDouble && (c === "}" || c === "]")) depth--;
|
|
282
|
+
else if (!inSingle && !inDouble && depth === 0 && c === ":") {
|
|
283
|
+
const next = text[i + 1];
|
|
284
|
+
if (next === undefined || next === " " || next === "\t") return i;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return -1;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function splitFlow(s: string): string[] {
|
|
291
|
+
const parts: string[] = [];
|
|
292
|
+
let depth = 0;
|
|
293
|
+
let inSingle = false;
|
|
294
|
+
let inDouble = false;
|
|
295
|
+
let start = 0;
|
|
296
|
+
for (let i = 0; i < s.length; i++) {
|
|
297
|
+
const c = s[i];
|
|
298
|
+
if (!inDouble && c === "'") inSingle = !inSingle;
|
|
299
|
+
else if (!inSingle && c === '"') inDouble = !inDouble;
|
|
300
|
+
else if (!inSingle && !inDouble && (c === "[" || c === "{")) depth++;
|
|
301
|
+
else if (!inSingle && !inDouble && (c === "]" || c === "}")) depth--;
|
|
302
|
+
else if (!inSingle && !inDouble && depth === 0 && c === ",") {
|
|
303
|
+
parts.push(s.slice(start, i));
|
|
304
|
+
start = i + 1;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (start <= s.length) parts.push(s.slice(start));
|
|
308
|
+
return parts;
|
|
309
|
+
}
|