@owlmeans/viable-common 0.0.4
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/README.md +68 -0
- package/agent-meta/manifest.json +16 -0
- package/agent-meta/skills/viable-common/SKILL.md +179 -0
- package/build/agent/index.d.ts +4 -0
- package/build/agent/index.d.ts.map +1 -0
- package/build/agent/index.js +3 -0
- package/build/agent/index.js.map +1 -0
- package/build/agent/memory.d.ts +12 -0
- package/build/agent/memory.d.ts.map +1 -0
- package/build/agent/memory.js +11 -0
- package/build/agent/memory.js.map +1 -0
- package/build/agent/spectator/consts.d.ts +9 -0
- package/build/agent/spectator/consts.d.ts.map +1 -0
- package/build/agent/spectator/consts.js +10 -0
- package/build/agent/spectator/consts.js.map +1 -0
- package/build/agent/spectator/index.d.ts +3 -0
- package/build/agent/spectator/index.d.ts.map +1 -0
- package/build/agent/spectator/index.js +2 -0
- package/build/agent/spectator/index.js.map +1 -0
- package/build/agent/spectator/types.d.ts +13 -0
- package/build/agent/spectator/types.d.ts.map +1 -0
- package/build/agent/spectator/types.js +2 -0
- package/build/agent/spectator/types.js.map +1 -0
- package/build/agent/types.d.ts +10 -0
- package/build/agent/types.d.ts.map +1 -0
- package/build/agent/types.js +2 -0
- package/build/agent/types.js.map +1 -0
- package/build/areas/consts.d.ts +88 -0
- package/build/areas/consts.d.ts.map +1 -0
- package/build/areas/consts.js +106 -0
- package/build/areas/consts.js.map +1 -0
- package/build/areas/index.d.ts +3 -0
- package/build/areas/index.d.ts.map +1 -0
- package/build/areas/index.js +2 -0
- package/build/areas/index.js.map +1 -0
- package/build/areas/types.d.ts +28 -0
- package/build/areas/types.d.ts.map +1 -0
- package/build/areas/types.js +2 -0
- package/build/areas/types.js.map +1 -0
- package/build/ba/consts.d.ts +38 -0
- package/build/ba/consts.d.ts.map +1 -0
- package/build/ba/consts.js +41 -0
- package/build/ba/consts.js.map +1 -0
- package/build/ba/helpers.d.ts +41 -0
- package/build/ba/helpers.d.ts.map +1 -0
- package/build/ba/helpers.js +79 -0
- package/build/ba/helpers.js.map +1 -0
- package/build/ba/index.d.ts +5 -0
- package/build/ba/index.d.ts.map +1 -0
- package/build/ba/index.js +4 -0
- package/build/ba/index.js.map +1 -0
- package/build/ba/schemas.d.ts +13 -0
- package/build/ba/schemas.d.ts.map +1 -0
- package/build/ba/schemas.js +181 -0
- package/build/ba/schemas.js.map +1 -0
- package/build/ba/types.d.ts +113 -0
- package/build/ba/types.d.ts.map +1 -0
- package/build/ba/types.js +2 -0
- package/build/ba/types.js.map +1 -0
- package/build/blueprint/case.d.ts +73 -0
- package/build/blueprint/case.d.ts.map +1 -0
- package/build/blueprint/case.js +244 -0
- package/build/blueprint/case.js.map +1 -0
- package/build/blueprint/consts.d.ts +11 -0
- package/build/blueprint/consts.d.ts.map +1 -0
- package/build/blueprint/consts.js +11 -0
- package/build/blueprint/consts.js.map +1 -0
- package/build/blueprint/index.d.ts +6 -0
- package/build/blueprint/index.d.ts.map +1 -0
- package/build/blueprint/index.js +6 -0
- package/build/blueprint/index.js.map +1 -0
- package/build/blueprint/resolve.d.ts +51 -0
- package/build/blueprint/resolve.d.ts.map +1 -0
- package/build/blueprint/resolve.js +108 -0
- package/build/blueprint/resolve.js.map +1 -0
- package/build/blueprint/schemas.d.ts +41 -0
- package/build/blueprint/schemas.d.ts.map +1 -0
- package/build/blueprint/schemas.js +27 -0
- package/build/blueprint/schemas.js.map +1 -0
- package/build/blueprint/types.d.ts +186 -0
- package/build/blueprint/types.d.ts.map +1 -0
- package/build/blueprint/types.js +32 -0
- package/build/blueprint/types.js.map +1 -0
- package/build/branding.d.ts +19 -0
- package/build/branding.d.ts.map +1 -0
- package/build/branding.js +32 -0
- package/build/branding.js.map +1 -0
- package/build/connect/consts.d.ts +378 -0
- package/build/connect/consts.d.ts.map +1 -0
- package/build/connect/consts.js +425 -0
- package/build/connect/consts.js.map +1 -0
- package/build/connect/entrypoints.d.ts +41 -0
- package/build/connect/entrypoints.d.ts.map +1 -0
- package/build/connect/entrypoints.js +141 -0
- package/build/connect/entrypoints.js.map +1 -0
- package/build/connect/errors.d.ts +50 -0
- package/build/connect/errors.d.ts.map +1 -0
- package/build/connect/errors.js +77 -0
- package/build/connect/errors.js.map +1 -0
- package/build/connect/index.d.ts +8 -0
- package/build/connect/index.d.ts.map +1 -0
- package/build/connect/index.js +6 -0
- package/build/connect/index.js.map +1 -0
- package/build/connect/ops.d.ts +192 -0
- package/build/connect/ops.d.ts.map +1 -0
- package/build/connect/ops.js +2 -0
- package/build/connect/ops.js.map +1 -0
- package/build/connect/references.d.ts +194 -0
- package/build/connect/references.d.ts.map +1 -0
- package/build/connect/references.js +62 -0
- package/build/connect/references.js.map +1 -0
- package/build/connect/schemas.d.ts +59 -0
- package/build/connect/schemas.d.ts.map +1 -0
- package/build/connect/schemas.js +346 -0
- package/build/connect/schemas.js.map +1 -0
- package/build/connect/types.d.ts +428 -0
- package/build/connect/types.d.ts.map +1 -0
- package/build/connect/types.js +2 -0
- package/build/connect/types.js.map +1 -0
- package/build/consts.d.ts +9 -0
- package/build/consts.d.ts.map +1 -0
- package/build/consts.js +31 -0
- package/build/consts.js.map +1 -0
- package/build/convert/consts.d.ts +539 -0
- package/build/convert/consts.d.ts.map +1 -0
- package/build/convert/consts.js +630 -0
- package/build/convert/consts.js.map +1 -0
- package/build/convert/helpers.d.ts +91 -0
- package/build/convert/helpers.d.ts.map +1 -0
- package/build/convert/helpers.js +301 -0
- package/build/convert/helpers.js.map +1 -0
- package/build/convert/index.d.ts +11 -0
- package/build/convert/index.d.ts.map +1 -0
- package/build/convert/index.js +4 -0
- package/build/convert/index.js.map +1 -0
- package/build/convert/schemas.d.ts +62 -0
- package/build/convert/schemas.d.ts.map +1 -0
- package/build/convert/schemas.js +626 -0
- package/build/convert/schemas.js.map +1 -0
- package/build/convert/types.d.ts +683 -0
- package/build/convert/types.d.ts.map +1 -0
- package/build/convert/types.js +2 -0
- package/build/convert/types.js.map +1 -0
- package/build/design/consts.d.ts +25 -0
- package/build/design/consts.d.ts.map +1 -0
- package/build/design/consts.js +26 -0
- package/build/design/consts.js.map +1 -0
- package/build/design/helpers.d.ts +60 -0
- package/build/design/helpers.d.ts.map +1 -0
- package/build/design/helpers.js +221 -0
- package/build/design/helpers.js.map +1 -0
- package/build/design/index.d.ts +6 -0
- package/build/design/index.d.ts.map +1 -0
- package/build/design/index.js +5 -0
- package/build/design/index.js.map +1 -0
- package/build/design/runtime.d.ts +126 -0
- package/build/design/runtime.d.ts.map +1 -0
- package/build/design/runtime.js +65 -0
- package/build/design/runtime.js.map +1 -0
- package/build/design/schemas.d.ts +21 -0
- package/build/design/schemas.d.ts.map +1 -0
- package/build/design/schemas.js +369 -0
- package/build/design/schemas.js.map +1 -0
- package/build/design/types.d.ts +199 -0
- package/build/design/types.d.ts.map +1 -0
- package/build/design/types.js +2 -0
- package/build/design/types.js.map +1 -0
- package/build/dev/consts.d.ts +32 -0
- package/build/dev/consts.d.ts.map +1 -0
- package/build/dev/consts.js +33 -0
- package/build/dev/consts.js.map +1 -0
- package/build/dev/index.d.ts +4 -0
- package/build/dev/index.d.ts.map +1 -0
- package/build/dev/index.js +3 -0
- package/build/dev/index.js.map +1 -0
- package/build/dev/schemas.d.ts +15 -0
- package/build/dev/schemas.d.ts.map +1 -0
- package/build/dev/schemas.js +116 -0
- package/build/dev/schemas.js.map +1 -0
- package/build/dev/types.d.ts +42 -0
- package/build/dev/types.d.ts.map +1 -0
- package/build/dev/types.js +2 -0
- package/build/dev/types.js.map +1 -0
- package/build/execution/consts.d.ts +36 -0
- package/build/execution/consts.d.ts.map +1 -0
- package/build/execution/consts.js +37 -0
- package/build/execution/consts.js.map +1 -0
- package/build/execution/index.d.ts +3 -0
- package/build/execution/index.d.ts.map +1 -0
- package/build/execution/index.js +2 -0
- package/build/execution/index.js.map +1 -0
- package/build/execution/types.d.ts +50 -0
- package/build/execution/types.d.ts.map +1 -0
- package/build/execution/types.js +2 -0
- package/build/execution/types.js.map +1 -0
- package/build/index.d.ts +22 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +21 -0
- package/build/index.js.map +1 -0
- package/build/integrity/consts.d.ts +226 -0
- package/build/integrity/consts.d.ts.map +1 -0
- package/build/integrity/consts.js +401 -0
- package/build/integrity/consts.js.map +1 -0
- package/build/integrity/index.d.ts +4 -0
- package/build/integrity/index.d.ts.map +1 -0
- package/build/integrity/index.js +3 -0
- package/build/integrity/index.js.map +1 -0
- package/build/integrity/types.d.ts +35 -0
- package/build/integrity/types.d.ts.map +1 -0
- package/build/integrity/types.js +2 -0
- package/build/integrity/types.js.map +1 -0
- package/build/integrity/verify.d.ts +23 -0
- package/build/integrity/verify.d.ts.map +1 -0
- package/build/integrity/verify.js +198 -0
- package/build/integrity/verify.js.map +1 -0
- package/build/metadata/consts.d.ts +101 -0
- package/build/metadata/consts.d.ts.map +1 -0
- package/build/metadata/consts.js +104 -0
- package/build/metadata/consts.js.map +1 -0
- package/build/metadata/index.d.ts +3 -0
- package/build/metadata/index.d.ts.map +1 -0
- package/build/metadata/index.js +3 -0
- package/build/metadata/index.js.map +1 -0
- package/build/metadata/types.d.ts +286 -0
- package/build/metadata/types.d.ts.map +1 -0
- package/build/metadata/types.js +39 -0
- package/build/metadata/types.js.map +1 -0
- package/build/moderation/consts.d.ts +58 -0
- package/build/moderation/consts.d.ts.map +1 -0
- package/build/moderation/consts.js +60 -0
- package/build/moderation/consts.js.map +1 -0
- package/build/moderation/index.d.ts +5 -0
- package/build/moderation/index.d.ts.map +1 -0
- package/build/moderation/index.js +4 -0
- package/build/moderation/index.js.map +1 -0
- package/build/moderation/schemas.d.ts +19 -0
- package/build/moderation/schemas.d.ts.map +1 -0
- package/build/moderation/schemas.js +26 -0
- package/build/moderation/schemas.js.map +1 -0
- package/build/moderation/types.d.ts +64 -0
- package/build/moderation/types.d.ts.map +1 -0
- package/build/moderation/types.js +2 -0
- package/build/moderation/types.js.map +1 -0
- package/build/moderation/utils.d.ts +21 -0
- package/build/moderation/utils.d.ts.map +1 -0
- package/build/moderation/utils.js +31 -0
- package/build/moderation/utils.js.map +1 -0
- package/build/preview/consts.d.ts +10 -0
- package/build/preview/consts.d.ts.map +1 -0
- package/build/preview/consts.js +11 -0
- package/build/preview/consts.js.map +1 -0
- package/build/preview/index.d.ts +3 -0
- package/build/preview/index.d.ts.map +1 -0
- package/build/preview/index.js +2 -0
- package/build/preview/index.js.map +1 -0
- package/build/preview/types.d.ts +60 -0
- package/build/preview/types.d.ts.map +1 -0
- package/build/preview/types.js +2 -0
- package/build/preview/types.js.map +1 -0
- package/build/scaffold/consts.d.ts +25 -0
- package/build/scaffold/consts.d.ts.map +1 -0
- package/build/scaffold/consts.js +26 -0
- package/build/scaffold/consts.js.map +1 -0
- package/build/scaffold/helpers.d.ts +35 -0
- package/build/scaffold/helpers.d.ts.map +1 -0
- package/build/scaffold/helpers.js +54 -0
- package/build/scaffold/helpers.js.map +1 -0
- package/build/scaffold/index.d.ts +5 -0
- package/build/scaffold/index.d.ts.map +1 -0
- package/build/scaffold/index.js +4 -0
- package/build/scaffold/index.js.map +1 -0
- package/build/scaffold/schemas.d.ts +5 -0
- package/build/scaffold/schemas.d.ts.map +1 -0
- package/build/scaffold/schemas.js +273 -0
- package/build/scaffold/schemas.js.map +1 -0
- package/build/scaffold/types.d.ts +144 -0
- package/build/scaffold/types.d.ts.map +1 -0
- package/build/scaffold/types.js +2 -0
- package/build/scaffold/types.js.map +1 -0
- package/build/skills/catalogue.d.ts +47 -0
- package/build/skills/catalogue.d.ts.map +1 -0
- package/build/skills/catalogue.js +1566 -0
- package/build/skills/catalogue.js.map +1 -0
- package/build/skills/consts.d.ts +104 -0
- package/build/skills/consts.d.ts.map +1 -0
- package/build/skills/consts.js +170 -0
- package/build/skills/consts.js.map +1 -0
- package/build/skills/index.d.ts +4 -0
- package/build/skills/index.d.ts.map +1 -0
- package/build/skills/index.js +4 -0
- package/build/skills/index.js.map +1 -0
- package/build/skills/roles.d.ts +52 -0
- package/build/skills/roles.d.ts.map +1 -0
- package/build/skills/roles.js +256 -0
- package/build/skills/roles.js.map +1 -0
- package/build/slot/consts.d.ts +305 -0
- package/build/slot/consts.d.ts.map +1 -0
- package/build/slot/consts.js +376 -0
- package/build/slot/consts.js.map +1 -0
- package/build/slot/helpers.d.ts +25 -0
- package/build/slot/helpers.d.ts.map +1 -0
- package/build/slot/helpers.js +27 -0
- package/build/slot/helpers.js.map +1 -0
- package/build/slot/index.d.ts +6 -0
- package/build/slot/index.d.ts.map +1 -0
- package/build/slot/index.js +5 -0
- package/build/slot/index.js.map +1 -0
- package/build/slot/layout.d.ts +72 -0
- package/build/slot/layout.d.ts.map +1 -0
- package/build/slot/layout.js +82 -0
- package/build/slot/layout.js.map +1 -0
- package/build/slot/schemas.d.ts +12 -0
- package/build/slot/schemas.d.ts.map +1 -0
- package/build/slot/schemas.js +43 -0
- package/build/slot/schemas.js.map +1 -0
- package/build/slot/types.d.ts +147 -0
- package/build/slot/types.d.ts.map +1 -0
- package/build/slot/types.js +2 -0
- package/build/slot/types.js.map +1 -0
- package/build/topology/card.d.ts +23 -0
- package/build/topology/card.d.ts.map +1 -0
- package/build/topology/card.js +95 -0
- package/build/topology/card.js.map +1 -0
- package/build/topology/consts.d.ts +32 -0
- package/build/topology/consts.d.ts.map +1 -0
- package/build/topology/consts.js +55 -0
- package/build/topology/consts.js.map +1 -0
- package/build/topology/helpers.d.ts +44 -0
- package/build/topology/helpers.d.ts.map +1 -0
- package/build/topology/helpers.js +112 -0
- package/build/topology/helpers.js.map +1 -0
- package/build/topology/index.d.ts +5 -0
- package/build/topology/index.d.ts.map +1 -0
- package/build/topology/index.js +4 -0
- package/build/topology/index.js.map +1 -0
- package/build/topology/types.d.ts +83 -0
- package/build/topology/types.d.ts.map +1 -0
- package/build/topology/types.js +2 -0
- package/build/topology/types.js.map +1 -0
- package/build/types.d.ts +88 -0
- package/build/types.d.ts.map +1 -0
- package/build/types.js +2 -0
- package/build/types.js.map +1 -0
- package/build/ux/consts.d.ts +5 -0
- package/build/ux/consts.d.ts.map +1 -0
- package/build/ux/consts.js +6 -0
- package/build/ux/consts.js.map +1 -0
- package/build/ux/index.d.ts +4 -0
- package/build/ux/index.d.ts.map +1 -0
- package/build/ux/index.js +3 -0
- package/build/ux/index.js.map +1 -0
- package/build/ux/schemas.d.ts +8 -0
- package/build/ux/schemas.d.ts.map +1 -0
- package/build/ux/schemas.js +91 -0
- package/build/ux/schemas.js.map +1 -0
- package/build/ux/types.d.ts +21 -0
- package/build/ux/types.d.ts.map +1 -0
- package/build/ux/types.js +2 -0
- package/build/ux/types.js.map +1 -0
- package/package.json +71 -0
- package/src/agent/index.ts +4 -0
- package/src/agent/memory.ts +16 -0
- package/src/agent/spectator/consts.ts +10 -0
- package/src/agent/spectator/index.ts +3 -0
- package/src/agent/spectator/types.ts +14 -0
- package/src/agent/types.ts +10 -0
- package/src/areas/consts.ts +112 -0
- package/src/areas/index.ts +3 -0
- package/src/areas/types.ts +29 -0
- package/src/ba/consts.ts +40 -0
- package/src/ba/helpers.ts +93 -0
- package/src/ba/index.ts +5 -0
- package/src/ba/schemas.ts +196 -0
- package/src/ba/types.ts +125 -0
- package/src/blueprint/case.ts +272 -0
- package/src/blueprint/consts.ts +11 -0
- package/src/blueprint/index.ts +6 -0
- package/src/blueprint/resolve.ts +133 -0
- package/src/blueprint/schemas.ts +44 -0
- package/src/blueprint/types.ts +204 -0
- package/src/branding.ts +34 -0
- package/src/connect/consts.ts +441 -0
- package/src/connect/entrypoints.ts +291 -0
- package/src/connect/errors.ts +91 -0
- package/src/connect/index.ts +7 -0
- package/src/connect/ops.ts +208 -0
- package/src/connect/references.ts +89 -0
- package/src/connect/schemas.ts +384 -0
- package/src/connect/types.ts +456 -0
- package/src/consts.ts +34 -0
- package/src/convert/consts.ts +672 -0
- package/src/convert/helpers.ts +340 -0
- package/src/convert/index.ts +10 -0
- package/src/convert/schemas.ts +663 -0
- package/src/convert/types.ts +741 -0
- package/src/design/consts.ts +26 -0
- package/src/design/helpers.ts +255 -0
- package/src/design/index.ts +5 -0
- package/src/design/runtime.ts +142 -0
- package/src/design/schemas.ts +384 -0
- package/src/design/types.ts +191 -0
- package/src/dev/consts.ts +35 -0
- package/src/dev/index.ts +4 -0
- package/src/dev/schemas.ts +124 -0
- package/src/dev/types.ts +47 -0
- package/src/execution/consts.ts +37 -0
- package/src/execution/index.ts +3 -0
- package/src/execution/types.ts +55 -0
- package/src/index.ts +22 -0
- package/src/integrity/consts.ts +477 -0
- package/src/integrity/index.ts +3 -0
- package/src/integrity/types.ts +37 -0
- package/src/integrity/verify.ts +221 -0
- package/src/metadata/consts.ts +118 -0
- package/src/metadata/index.ts +3 -0
- package/src/metadata/types.ts +310 -0
- package/src/moderation/consts.ts +59 -0
- package/src/moderation/index.ts +4 -0
- package/src/moderation/schemas.ts +28 -0
- package/src/moderation/types.ts +68 -0
- package/src/moderation/utils.ts +35 -0
- package/src/preview/consts.ts +9 -0
- package/src/preview/index.ts +3 -0
- package/src/preview/types.ts +79 -0
- package/src/scaffold/consts.ts +26 -0
- package/src/scaffold/helpers.ts +84 -0
- package/src/scaffold/index.ts +4 -0
- package/src/scaffold/schemas.ts +283 -0
- package/src/scaffold/types.ts +118 -0
- package/src/skills/catalogue.ts +1617 -0
- package/src/skills/consts.ts +183 -0
- package/src/skills/index.ts +4 -0
- package/src/skills/roles.ts +299 -0
- package/src/slot/consts.ts +393 -0
- package/src/slot/helpers.ts +34 -0
- package/src/slot/index.ts +5 -0
- package/src/slot/layout.ts +141 -0
- package/src/slot/schemas.ts +46 -0
- package/src/slot/types.ts +164 -0
- package/src/topology/card.ts +106 -0
- package/src/topology/consts.ts +59 -0
- package/src/topology/helpers.ts +138 -0
- package/src/topology/index.ts +5 -0
- package/src/topology/types.ts +86 -0
- package/src/types.ts +104 -0
- package/src/ux/consts.ts +5 -0
- package/src/ux/index.ts +4 -0
- package/src/ux/schemas.ts +97 -0
- package/src/ux/types.ts +25 -0
- package/tests/connect-convert.spec.ts +161 -0
- package/tests/convert.spec.ts +318 -0
- package/tests/design.spec.ts +136 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import type { SlotCommandType, SlotFileCommand, SlotGitCommand, SlotShellCommand, SubProject } from './consts.js'
|
|
2
|
+
|
|
3
|
+
export type SlotCommand = SlotFileCommand | SlotShellCommand | SlotGitCommand
|
|
4
|
+
|
|
5
|
+
export interface SlotCommandPayload {
|
|
6
|
+
type: SlotCommandType
|
|
7
|
+
command: SlotCommand
|
|
8
|
+
args?: Record<string, any>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* What a shell command answers with.
|
|
13
|
+
*
|
|
14
|
+
* `result` is the contract every caller reads: **error text, or `null` for success**. It is not a
|
|
15
|
+
* transcript — a command that fails returns the diagnostics a fixer or a person can act on, and a
|
|
16
|
+
* command that succeeds returns nothing at all. The remaining fields belong to the two commands
|
|
17
|
+
* that report a JOB rather than a verdict ({@link SlotShellCommand.BootCheck} and its status read)
|
|
18
|
+
* and to the integrity check, which reports a refusal rather than a failure.
|
|
19
|
+
*/
|
|
20
|
+
export interface SlotShellResult {
|
|
21
|
+
result: string | null
|
|
22
|
+
/** BootCheck: the job was started; the verdict comes from a BootCheckStatus read. */
|
|
23
|
+
started?: boolean
|
|
24
|
+
/** BootCheckStatus: whether a check is still in flight, and when it began. */
|
|
25
|
+
running?: boolean
|
|
26
|
+
startedAt?: string
|
|
27
|
+
/** BootCheckStatus: a verdict is available in `result`. */
|
|
28
|
+
done?: boolean
|
|
29
|
+
/** The target's own boot phase, when it got far enough to report one. */
|
|
30
|
+
phase?: string
|
|
31
|
+
/** Integrity: whether the tree still holds the generated application. */
|
|
32
|
+
ok?: boolean
|
|
33
|
+
violations?: string[]
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The shapes the git commands answer with.
|
|
38
|
+
*
|
|
39
|
+
* Redeclared here rather than imported: the implementation lives in a package that carries
|
|
40
|
+
* `simple-git` and a GitHub client, and the connector — which executes these commands through the
|
|
41
|
+
* `git` CLI on a developer's machine — must not depend on either. The platform keeps answering
|
|
42
|
+
* with its own richer types; these are the subset both ends agree on.
|
|
43
|
+
*/
|
|
44
|
+
export interface SlotGitFileChange {
|
|
45
|
+
path: string
|
|
46
|
+
status: string
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface SlotGitCommitInfo {
|
|
50
|
+
hash: string
|
|
51
|
+
shortHash: string
|
|
52
|
+
subject: string
|
|
53
|
+
authorName: string
|
|
54
|
+
authorEmail: string
|
|
55
|
+
committedAt: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface SlotGitStatus {
|
|
59
|
+
initialized: boolean
|
|
60
|
+
head: SlotGitCommitInfo | null
|
|
61
|
+
branch: string
|
|
62
|
+
dirty: boolean
|
|
63
|
+
changedFiles: number
|
|
64
|
+
files: SlotGitFileChange[]
|
|
65
|
+
remoteUrl: string | null
|
|
66
|
+
ahead: number | null
|
|
67
|
+
behind: number | null
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface SlotGitCommitResult {
|
|
71
|
+
commit: SlotGitCommitInfo | null
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface SlotGitLogResult {
|
|
75
|
+
commits: SlotGitCommitInfo[]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Bring a remote repository onto the volume.
|
|
80
|
+
*
|
|
81
|
+
* `token` is a per-invocation credential and never reaches the tree: the executor passes it
|
|
82
|
+
* through the process environment for the one fetch, exactly as push and pull already do, so it
|
|
83
|
+
* appears in no `.git/config`, no remote URL and no argv anything can observe.
|
|
84
|
+
*/
|
|
85
|
+
export interface SlotGitCloneArgs {
|
|
86
|
+
remoteUrl: string
|
|
87
|
+
/** The branch to check out. Absent means whatever the remote calls its default. */
|
|
88
|
+
branch?: string
|
|
89
|
+
/** Fetch depth; 0 means the whole history. Defaults to a shallow fetch. */
|
|
90
|
+
depth?: number
|
|
91
|
+
token?: string
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface SlotGitCloneResult {
|
|
95
|
+
cloned: boolean
|
|
96
|
+
/** The branch actually checked out — the resolved default, when none was asked for. */
|
|
97
|
+
branch: string
|
|
98
|
+
head: SlotGitCommitInfo | null
|
|
99
|
+
/** Executor diagnostics, when it has any worth reporting. */
|
|
100
|
+
result?: string
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* One entry of a {@link SlotFileCommand.StatTree} listing.
|
|
105
|
+
*
|
|
106
|
+
* The shape both a publisher and a connector answer with, so a census walks a pod's volume and a
|
|
107
|
+
* developer's own directory through one contract. `binary` is the executor's own verdict — the
|
|
108
|
+
* caller has not read the file and cannot form one.
|
|
109
|
+
*/
|
|
110
|
+
export interface FileStat {
|
|
111
|
+
path: string
|
|
112
|
+
bytes: number
|
|
113
|
+
binary: boolean
|
|
114
|
+
modifiedAt?: string
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface StatTreeArgs {
|
|
118
|
+
/** Project-relative directory to walk. Absent means the whole project. */
|
|
119
|
+
dir?: string
|
|
120
|
+
/** Entries to return before the answer reports itself truncated. */
|
|
121
|
+
limit?: number
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* `total` is what the walk SAW, `entries` what it returned.
|
|
126
|
+
*
|
|
127
|
+
* The two differ on a truncated walk, and the difference is what tells a caller its picture of the
|
|
128
|
+
* tree is partial — a bounded listing that reported only what it returned would be indistinguish-
|
|
129
|
+
* able from a small repository.
|
|
130
|
+
*/
|
|
131
|
+
export interface StatTreeResult {
|
|
132
|
+
entries: FileStat[]
|
|
133
|
+
truncated: boolean
|
|
134
|
+
total: number
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface ReadHeadArgs {
|
|
138
|
+
path: string
|
|
139
|
+
bytes: number
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Move everything in the project root under `dir`, leaving the named entries where they are. */
|
|
143
|
+
export interface RelocateArgs {
|
|
144
|
+
dir: string
|
|
145
|
+
/** Root-relative names that stay put — the slot's own metadata and markers. */
|
|
146
|
+
keep?: string[]
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface RelocateResult {
|
|
150
|
+
moved: number
|
|
151
|
+
kept: string[]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export interface RemoveTreeArgs {
|
|
155
|
+
dir: string
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Arguments a shell command may carry. */
|
|
159
|
+
export interface SlotShellArgs {
|
|
160
|
+
subproject?: SubProject
|
|
161
|
+
/** Free-form arguments for {@link SlotShellCommand.Bun}; absent means a plain install. */
|
|
162
|
+
args?: string
|
|
163
|
+
skipBuild?: boolean
|
|
164
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { SubProject } from '../slot/consts.js'
|
|
2
|
+
import { TOPOLOGY_VERSION } from './consts.js'
|
|
3
|
+
import { orderPackages } from './helpers.js'
|
|
4
|
+
import type { TargetPackageDescriptor, TargetPackageKind, TopologyDescriptor } from './types.js'
|
|
5
|
+
|
|
6
|
+
/** What `.agents/memory/topology.md` carries in its frontmatter. */
|
|
7
|
+
export interface TopologyMeta extends TopologyDescriptor {
|
|
8
|
+
version: number
|
|
9
|
+
updatedAt: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const ROLES = new Set<string>(Object.values(SubProject))
|
|
13
|
+
const KINDS = new Set<TargetPackageKind>(['library', 'bundle'])
|
|
14
|
+
|
|
15
|
+
const asStrings = (value: unknown): string[] =>
|
|
16
|
+
Array.isArray(value) ? value.filter((item): item is string => typeof item === 'string') : []
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Read a package descriptor out of whatever the file held.
|
|
20
|
+
*
|
|
21
|
+
* Everything is narrowed rather than trusted: the file is on the target's volume, where a person,
|
|
22
|
+
* a GitHub pull or a previous platform version may have written it. A descriptor that cannot be
|
|
23
|
+
* narrowed is DROPPED, never repaired — a package with no name or no recognisable role would
|
|
24
|
+
* otherwise resolve a path somewhere real and wrong.
|
|
25
|
+
*/
|
|
26
|
+
const parsePackage = (value: unknown): TargetPackageDescriptor | null => {
|
|
27
|
+
if (value == null || typeof value !== 'object') return null
|
|
28
|
+
const raw = value as Record<string, unknown>
|
|
29
|
+
const name = typeof raw.name === 'string' ? raw.name.trim() : ''
|
|
30
|
+
if (name === '' || name.includes('/') || name.startsWith('.')) return null
|
|
31
|
+
const roles = asStrings(raw.roles).filter((role): role is SubProject => ROLES.has(role))
|
|
32
|
+
if (roles.length === 0) return null
|
|
33
|
+
const kind = KINDS.has(raw.kind as TargetPackageKind) ? raw.kind as TargetPackageKind : 'bundle'
|
|
34
|
+
const areas = asStrings(raw.areas)
|
|
35
|
+
const queues = asStrings(raw.queues)
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
name,
|
|
39
|
+
roles,
|
|
40
|
+
kind,
|
|
41
|
+
dependsOn: asStrings(raw.dependsOn),
|
|
42
|
+
...(areas.length > 0 ? { areas: areas as TargetPackageDescriptor['areas'] } : {}),
|
|
43
|
+
...(queues.length > 0 ? { queues } : {}),
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Narrow a parsed frontmatter block into a topology, or answer `null`.
|
|
49
|
+
*
|
|
50
|
+
* `null` means "use the layout default", and every caller treats it that way. A topology file
|
|
51
|
+
* written by a platform version this one cannot read must not stop a project from building — the
|
|
52
|
+
* arrangement it describes is almost certainly still the default one.
|
|
53
|
+
*/
|
|
54
|
+
export const parseTopologyMeta = (data: unknown): TopologyDescriptor | null => {
|
|
55
|
+
if (data == null || typeof data !== 'object') return null
|
|
56
|
+
const raw = data as Record<string, unknown>
|
|
57
|
+
if (typeof raw.dir !== 'string' || raw.dir.trim() === '') return null
|
|
58
|
+
const packages = Array.isArray(raw.packages)
|
|
59
|
+
? raw.packages.map(parsePackage).filter((pkg): pkg is TargetPackageDescriptor => pkg != null)
|
|
60
|
+
: []
|
|
61
|
+
if (packages.length === 0) return null
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
id: typeof raw.id === 'string' && raw.id !== '' ? raw.id : 'recorded',
|
|
65
|
+
dir: raw.dir.trim(),
|
|
66
|
+
packages,
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const topologyMeta = (topology: TopologyDescriptor): TopologyMeta => ({
|
|
71
|
+
...topology,
|
|
72
|
+
packages: orderPackages(topology.packages),
|
|
73
|
+
version: TOPOLOGY_VERSION,
|
|
74
|
+
updatedAt: new Date().toISOString(),
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The body of `.agents/memory/topology.md` — what a model reads, and what a person reads.
|
|
79
|
+
*
|
|
80
|
+
* Rendered from the descriptor rather than maintained beside it, for the same reason the layout
|
|
81
|
+
* tables are: a card that disagrees with the frontmatter teaches the wrong tree.
|
|
82
|
+
*/
|
|
83
|
+
export const renderTopologyCard = (topology: TopologyDescriptor): string => {
|
|
84
|
+
const ordered = orderPackages(topology.packages)
|
|
85
|
+
const rows = ordered.map(pkg => {
|
|
86
|
+
const deps = pkg.dependsOn.length > 0 ? pkg.dependsOn.join(', ') : '—'
|
|
87
|
+
const extra = [
|
|
88
|
+
...(pkg.areas != null ? [`areas: ${pkg.areas.join(', ')}`] : []),
|
|
89
|
+
...(pkg.queues != null ? [`queues: ${pkg.queues.join(', ')}`] : []),
|
|
90
|
+
].join('; ')
|
|
91
|
+
|
|
92
|
+
return `| \`${topology.dir}/${pkg.name}\` | ${pkg.roles.join(', ')} | ${pkg.kind} | ${deps} | ${extra === '' ? '—' : extra} |`
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
return [
|
|
96
|
+
'# Topology',
|
|
97
|
+
'',
|
|
98
|
+
'Which packages this project has, what each one is, and which compile against which.',
|
|
99
|
+
'Built in the order of the table — a `library` must be built before anything importing it.',
|
|
100
|
+
'',
|
|
101
|
+
'| Package | Roles | Kind | Depends on | Notes |',
|
|
102
|
+
'|---|---|---|---|---|',
|
|
103
|
+
...rows,
|
|
104
|
+
'',
|
|
105
|
+
].join('\n')
|
|
106
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { TargetLayout } from '../integrity/consts.js'
|
|
2
|
+
import { SubProject } from '../slot/consts.js'
|
|
3
|
+
import type { TopologyDescriptor } from './types.js'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The two arrangements the platform itself writes.
|
|
7
|
+
*
|
|
8
|
+
* They are the DEFAULTS a project falls back to, not the set of arrangements that can exist: a
|
|
9
|
+
* project records its own topology and may hold packages neither of these names. What makes them
|
|
10
|
+
* special is only that `detectTargetLayout` can recognise them from the disk, which is what a
|
|
11
|
+
* consumer needs when a project predates the topology file entirely.
|
|
12
|
+
*
|
|
13
|
+
* v1 is frozen. A target's tree is the one it was initialized with, so nothing is ever added here.
|
|
14
|
+
*/
|
|
15
|
+
export const DEFAULT_TOPOLOGY: TopologyDescriptor = {
|
|
16
|
+
id: 'owlmeans-fullstack',
|
|
17
|
+
dir: 'sources',
|
|
18
|
+
packages: [
|
|
19
|
+
{ name: 'common', roles: [SubProject.Common], kind: 'library', dependsOn: [] },
|
|
20
|
+
// The shared LIBRARY, not the server — that is `api`. It owns the context factory, the config,
|
|
21
|
+
// the resources, the services, the domain models and the job processors.
|
|
22
|
+
{ name: 'backend', roles: [SubProject.Backend], kind: 'library', dependsOn: ['common'] },
|
|
23
|
+
{ name: 'api', roles: [SubProject.Api], kind: 'bundle', dependsOn: ['common', 'backend'] },
|
|
24
|
+
{ name: 'web', roles: [SubProject.Web, SubProject.Frontend], kind: 'bundle', dependsOn: ['common'] },
|
|
25
|
+
{ name: 'worker', roles: [SubProject.Worker], kind: 'bundle', dependsOn: ['common', 'backend'] },
|
|
26
|
+
],
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The pre-restructure arrangement, frozen.
|
|
31
|
+
*
|
|
32
|
+
* `backend` here is the HTTP SERVER and `frontend` the browser app — the same two words the
|
|
33
|
+
* current topology uses for other things, which is why roles are mapped per topology and never
|
|
34
|
+
* joined onto a path.
|
|
35
|
+
*/
|
|
36
|
+
export const LEGACY_TOPOLOGY: TopologyDescriptor = {
|
|
37
|
+
id: 'owlmeans-fullstack-v1',
|
|
38
|
+
dir: 'packages',
|
|
39
|
+
packages: [
|
|
40
|
+
{ name: 'common', roles: [SubProject.Common], kind: 'library', dependsOn: [] },
|
|
41
|
+
{ name: 'backend', roles: [SubProject.Backend, SubProject.Api], kind: 'bundle', dependsOn: ['common'] },
|
|
42
|
+
{ name: 'frontend', roles: [SubProject.Frontend, SubProject.Web], kind: 'bundle', dependsOn: ['common'] },
|
|
43
|
+
],
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The default topology for each layout the platform can detect on disk. */
|
|
47
|
+
export const LAYOUT_TOPOLOGIES: Readonly<Record<TargetLayout, TopologyDescriptor>> = {
|
|
48
|
+
[TargetLayout.V2]: DEFAULT_TOPOLOGY,
|
|
49
|
+
[TargetLayout.V1]: LEGACY_TOPOLOGY,
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The frontmatter version of `.agents/memory/topology.md`.
|
|
54
|
+
*
|
|
55
|
+
* A file written by an older platform is READ, never refused: an unknown or missing version falls
|
|
56
|
+
* back to the layout default, because a topology nobody can parse must not stop a project from
|
|
57
|
+
* building.
|
|
58
|
+
*/
|
|
59
|
+
export const TOPOLOGY_VERSION = 1
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { TargetLayout } from '../integrity/consts.js'
|
|
2
|
+
import type { ProjectArea } from '../areas/consts.js'
|
|
3
|
+
import type { SubProject } from '../slot/consts.js'
|
|
4
|
+
import { LAYOUT_TOPOLOGIES, DEFAULT_TOPOLOGY } from './consts.js'
|
|
5
|
+
import type {
|
|
6
|
+
ResolvedTopology, TargetPackageDescriptor, TopologyDescriptor,
|
|
7
|
+
} from './types.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Order the packages so that nothing is built before what it compiles against.
|
|
11
|
+
*
|
|
12
|
+
* Kahn's algorithm, with two deliberate tolerances. An edge to a package the topology does not
|
|
13
|
+
* hold is DROPPED rather than fatal — a project may declare a dependency on something a pull has
|
|
14
|
+
* not brought in yet, and refusing to order the tree would take the whole build down over one
|
|
15
|
+
* name. A cycle leaves its members unvisited, and they are appended in declaration order: a cycle
|
|
16
|
+
* cannot be built correctly in any order, so the useful behaviour is to build it in the order
|
|
17
|
+
* somebody wrote rather than to throw.
|
|
18
|
+
*/
|
|
19
|
+
export const orderPackages = (packages: TargetPackageDescriptor[]): TargetPackageDescriptor[] => {
|
|
20
|
+
const known = new Set(packages.map(pkg => pkg.name))
|
|
21
|
+
const index = new Map(packages.map((pkg, at) => [pkg.name, at]))
|
|
22
|
+
const pending = new Map(packages.map(pkg => [
|
|
23
|
+
pkg.name, pkg.dependsOn.filter(dep => known.has(dep) && dep !== pkg.name).length,
|
|
24
|
+
]))
|
|
25
|
+
const dependents = new Map<string, string[]>()
|
|
26
|
+
for (const pkg of packages) {
|
|
27
|
+
for (const dep of pkg.dependsOn) {
|
|
28
|
+
if (!known.has(dep) || dep === pkg.name) continue
|
|
29
|
+
dependents.set(dep, [...dependents.get(dep) ?? [], pkg.name])
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const byName = new Map(packages.map(pkg => [pkg.name, pkg]))
|
|
34
|
+
const out: TargetPackageDescriptor[] = []
|
|
35
|
+
// Ready packages are taken in DECLARATION order, not in the order they became ready. Both are
|
|
36
|
+
// correct builds; only one is the same list every time and the same list a person wrote, and
|
|
37
|
+
// this order is compared against the shipped layout tables by a test.
|
|
38
|
+
const ready = packages.filter(pkg => pending.get(pkg.name) === 0).map(pkg => pkg.name)
|
|
39
|
+
const take = (): string | undefined => {
|
|
40
|
+
if (ready.length === 0) return undefined
|
|
41
|
+
let at = 0
|
|
42
|
+
for (let i = 1; i < ready.length; i++) {
|
|
43
|
+
if ((index.get(ready[i]) ?? 0) < (index.get(ready[at]) ?? 0)) at = i
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return ready.splice(at, 1)[0]
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (let name = take(); name != null; name = take()) {
|
|
50
|
+
const pkg = byName.get(name)
|
|
51
|
+
if (pkg == null) continue
|
|
52
|
+
out.push(pkg)
|
|
53
|
+
for (const next of dependents.get(name) ?? []) {
|
|
54
|
+
const left = (pending.get(next) ?? 0) - 1
|
|
55
|
+
pending.set(next, left)
|
|
56
|
+
if (left === 0) ready.push(next)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const seen = new Set(out.map(pkg => pkg.name))
|
|
61
|
+
|
|
62
|
+
return [...out, ...packages.filter(pkg => !seen.has(pkg.name))]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Resolve the derived halves — build order, library order and the role index. */
|
|
66
|
+
export const resolveTopology = (topology: TopologyDescriptor): ResolvedTopology => {
|
|
67
|
+
const ordered = orderPackages(topology.packages)
|
|
68
|
+
const byRole: Partial<Record<SubProject, TargetPackageDescriptor[]>> = {}
|
|
69
|
+
for (const pkg of ordered) {
|
|
70
|
+
for (const role of pkg.roles) {
|
|
71
|
+
byRole[role] = [...byRole[role] ?? [], pkg]
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
...topology,
|
|
77
|
+
packages: ordered,
|
|
78
|
+
build: ordered.map(pkg => pkg.name),
|
|
79
|
+
libraries: ordered.filter(pkg => pkg.kind === 'library').map(pkg => pkg.name),
|
|
80
|
+
byRole,
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The default topology for a layout already decided. */
|
|
85
|
+
export const topologyOf = (layout: TargetLayout): TopologyDescriptor =>
|
|
86
|
+
LAYOUT_TOPOLOGIES[layout] ?? DEFAULT_TOPOLOGY
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The directory a role names, or `null` when this topology has no package for it.
|
|
90
|
+
*
|
|
91
|
+
* `null` rather than the role's own name: a command aimed at a package the tree does not have must
|
|
92
|
+
* fail where it is issued. Answering with a plausible directory runs it somewhere real and wrong,
|
|
93
|
+
* which is how a type check once ran against the shared package instead of the one under repair.
|
|
94
|
+
*/
|
|
95
|
+
export const packageForRole = (
|
|
96
|
+
topology: ResolvedTopology, role: SubProject
|
|
97
|
+
): TargetPackageDescriptor | null => topology.byRole[role]?.[0] ?? null
|
|
98
|
+
|
|
99
|
+
/** Every package holding a role — more than one only where a topology splits that role. */
|
|
100
|
+
export const packagesForRole = (
|
|
101
|
+
topology: ResolvedTopology, role: SubProject
|
|
102
|
+
): TargetPackageDescriptor[] => topology.byRole[role] ?? []
|
|
103
|
+
|
|
104
|
+
/** The package serving an area, for a topology that splits the browser app across several. */
|
|
105
|
+
export const packageForArea = (
|
|
106
|
+
topology: ResolvedTopology, role: SubProject, area: ProjectArea
|
|
107
|
+
): TargetPackageDescriptor | null => {
|
|
108
|
+
const candidates = packagesForRole(topology, role)
|
|
109
|
+
return candidates.find(pkg => pkg.areas?.includes(area) === true)
|
|
110
|
+
?? candidates.find(pkg => pkg.areas == null)
|
|
111
|
+
?? candidates[0]
|
|
112
|
+
?? null
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** `<dir>/<package>` — the only place a topology directory is composed. */
|
|
116
|
+
export const packageDir = (topology: TopologyDescriptor, pkg: TargetPackageDescriptor): string =>
|
|
117
|
+
`${topology.dir}/${pkg.name}`
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Merge a package into a topology, by name.
|
|
121
|
+
*
|
|
122
|
+
* This is the ADOPTION path: a package that arrived with a GitHub pull is classified once and
|
|
123
|
+
* recorded here, so the next run addresses the tree that exists rather than re-deriving one that
|
|
124
|
+
* does not. Replacing by name rather than appending keeps a re-classification idempotent.
|
|
125
|
+
*/
|
|
126
|
+
export const withPackage = (
|
|
127
|
+
topology: TopologyDescriptor, pkg: TargetPackageDescriptor
|
|
128
|
+
): TopologyDescriptor => ({
|
|
129
|
+
...topology,
|
|
130
|
+
packages: topology.packages.some(known => known.name === pkg.name)
|
|
131
|
+
? topology.packages.map(known => known.name === pkg.name ? pkg : known)
|
|
132
|
+
: [...topology.packages, pkg],
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
/** Whether two topologies describe the same arrangement — used to skip a needless rewrite. */
|
|
136
|
+
export const sameTopology = (a: TopologyDescriptor, b: TopologyDescriptor): boolean =>
|
|
137
|
+
JSON.stringify(orderPackages(a.packages)) === JSON.stringify(orderPackages(b.packages))
|
|
138
|
+
&& a.dir === b.dir
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { ProjectArea } from '../areas/consts.js'
|
|
2
|
+
import type { SubProject } from '../slot/consts.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* How a target's workspace packages are ARRANGED — which of them exist, what role each plays and
|
|
6
|
+
* which compile against which.
|
|
7
|
+
*
|
|
8
|
+
* The layout tables this replaces ({@link LAYOUTS}, {@link ROLE_DIRS}) were two hand-written
|
|
9
|
+
* records keyed by a closed `TargetLayout` enum, so "the target has five packages named
|
|
10
|
+
* common/backend/api/web/worker" was not a fact ABOUT a project but a constant of the platform.
|
|
11
|
+
* Everything the pipeline could ever generate had to fit those five names.
|
|
12
|
+
*
|
|
13
|
+
* A topology is that same information as DATA: a project carries one, the two shipped layouts are
|
|
14
|
+
* just the two the platform writes by default, and the tables are derived from them rather than
|
|
15
|
+
* spelled beside them. That is what lets a target grow a second web application, a library package
|
|
16
|
+
* nobody planned, or the package a GitHub pull brought in.
|
|
17
|
+
*
|
|
18
|
+
* It is deliberately a DESCRIPTION and never a plan. Nothing here says a directory exists — a
|
|
19
|
+
* caller that acts on a package still checks the disk, exactly as `workerPath` always has.
|
|
20
|
+
*/
|
|
21
|
+
export interface TargetPackageDescriptor {
|
|
22
|
+
/**
|
|
23
|
+
* The package's directory name under {@link TopologyDescriptor.dir}, and the tail of its npm
|
|
24
|
+
* name (`<slug>-<name>`). Unique within a topology.
|
|
25
|
+
*/
|
|
26
|
+
name: string
|
|
27
|
+
/**
|
|
28
|
+
* What this package IS, in the role vocabulary the wire already speaks.
|
|
29
|
+
*
|
|
30
|
+
* A list rather than a single value because one package may answer to more than one role in a
|
|
31
|
+
* smaller arrangement — a target that serves its browser app from the same process that serves
|
|
32
|
+
* its API is one package holding both `Api` and `Web`. The default topology gives every package
|
|
33
|
+
* exactly one role.
|
|
34
|
+
*/
|
|
35
|
+
roles: SubProject[]
|
|
36
|
+
/**
|
|
37
|
+
* `library` builds with `tsc -b` and is consumed through its `build/` output at RUN time;
|
|
38
|
+
* `bundle` bundles itself and keeps every dependency external.
|
|
39
|
+
*
|
|
40
|
+
* The distinction is load-bearing rather than descriptive: a bundle resolves its libraries from
|
|
41
|
+
* `node_modules` when the process starts, so a library that nothing built makes the bundle exit
|
|
42
|
+
* with a message naming a missing dependency rather than a missing build.
|
|
43
|
+
*/
|
|
44
|
+
kind: TargetPackageKind
|
|
45
|
+
/** Sibling package NAMES this one compiles against. The build order is this graph, sorted. */
|
|
46
|
+
dependsOn: string[]
|
|
47
|
+
/**
|
|
48
|
+
* For a package holding the `Web` role: which audiences it serves.
|
|
49
|
+
*
|
|
50
|
+
* Absent means all four. A topology that splits the areas across two browser applications is
|
|
51
|
+
* the reason this exists; nothing generates one yet.
|
|
52
|
+
*/
|
|
53
|
+
areas?: ProjectArea[]
|
|
54
|
+
/** For a package holding the `Worker` role: which queues this process consumes. */
|
|
55
|
+
queues?: string[]
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type TargetPackageKind = 'library' | 'bundle'
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* One arrangement, named.
|
|
62
|
+
*
|
|
63
|
+
* `id` is what a project records; it is compared, never parsed.
|
|
64
|
+
*/
|
|
65
|
+
export interface TopologyDescriptor {
|
|
66
|
+
id: string
|
|
67
|
+
/** The directory holding the workspace packages — `sources`, or `packages` for a legacy tree. */
|
|
68
|
+
dir: string
|
|
69
|
+
packages: TargetPackageDescriptor[]
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* A topology read back from a project, with the resolutions every consumer would otherwise redo.
|
|
74
|
+
*
|
|
75
|
+
* `build` and `libraries` are DERIVED — a topological sort of `dependsOn` — rather than declared,
|
|
76
|
+
* because the two lists disagreeing with the graph is a whole class of outage (a library built
|
|
77
|
+
* after the bundle that imports it) that nobody can see by reading either one.
|
|
78
|
+
*/
|
|
79
|
+
export interface ResolvedTopology extends TopologyDescriptor {
|
|
80
|
+
/** Every package, in dependency order. */
|
|
81
|
+
build: string[]
|
|
82
|
+
/** The `library`-kind packages, in dependency order. */
|
|
83
|
+
libraries: string[]
|
|
84
|
+
/** Role → the packages holding it, in topology order. */
|
|
85
|
+
byRole: Partial<Record<SubProject, TargetPackageDescriptor[]>>
|
|
86
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
|
|
2
|
+
export interface SlotMetadata extends
|
|
3
|
+
SlotConstMetadata,
|
|
4
|
+
SlotSecretMetadata,
|
|
5
|
+
SlotListMetadata,
|
|
6
|
+
CustomSecretMetadata {
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface SlotConstMetadata {
|
|
10
|
+
projectName: string
|
|
11
|
+
oidcClientId: string
|
|
12
|
+
oidcRealm: string
|
|
13
|
+
/**
|
|
14
|
+
* Fully-qualified PUBLIC OIDC issuer URL the integrated viable IAM serves this client from
|
|
15
|
+
* (`{host}/oidc`). Populated when the production IAM client is provisioned; the canonical
|
|
16
|
+
* single value a standalone self-hosted deployment of the exported target uses. Empty until
|
|
17
|
+
* provisioned.
|
|
18
|
+
*/
|
|
19
|
+
oidcIssuerUrl: string
|
|
20
|
+
/**
|
|
21
|
+
* What the project's owner says about themselves, delivered to the generated application.
|
|
22
|
+
*
|
|
23
|
+
* Scalars rather than an object because metadata is scalar — the store is one row per key, and
|
|
24
|
+
* a nested value would have to be serialized at the boundary anyway.
|
|
25
|
+
*
|
|
26
|
+
* `brandingCredit` is the EFFECTIVE value, not the owner's intent: `''` hides the platform
|
|
27
|
+
* credit and anything else shows it. Absent means shown, so a push that never happened, or one
|
|
28
|
+
* that lost the value, keeps the credit rather than silently giving away a paid capability.
|
|
29
|
+
*/
|
|
30
|
+
brandingCopyright: string
|
|
31
|
+
brandingOrganization: string
|
|
32
|
+
brandingTermsUrl: string
|
|
33
|
+
brandingPrivacyUrl: string
|
|
34
|
+
brandingCredit: string
|
|
35
|
+
brandingHideCreditIntent: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface SlotSecretMetadata {
|
|
39
|
+
oidcClientSecret: string
|
|
40
|
+
/**
|
|
41
|
+
* The application role's password — the one database credential the generated app legitimately
|
|
42
|
+
* holds, and the one it already carries inside `DATABASE_URL`.
|
|
43
|
+
*
|
|
44
|
+
* The sidecar's SUPERUSER password is deliberately absent from this interface. Everything in
|
|
45
|
+
* `SlotMetadata` is pushed into the slot as `sandbox-meta.json`, which is a world-readable file
|
|
46
|
+
* in the untrusted application's own directory; the admin credential is kept platform-side and
|
|
47
|
+
* reaches the pod only as a Kubernetes Secret mounted into the Postgres container.
|
|
48
|
+
*/
|
|
49
|
+
dbAppPassword?: string
|
|
50
|
+
/**
|
|
51
|
+
* Password of the queue store's `app` ACL user — the whole of what the slot is given for its
|
|
52
|
+
* Valkey sidecar, and what it already carries inside `VALKEY_URL`.
|
|
53
|
+
*
|
|
54
|
+
* The store's `ops` user is deliberately absent for the same reason the Postgres superuser is:
|
|
55
|
+
* it holds the administrative surface, and everything in `SlotMetadata` lands in the untrusted
|
|
56
|
+
* application's own directory. Its password lives only in the ACL Secret.
|
|
57
|
+
*/
|
|
58
|
+
valkeyPassword?: string
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface SlotListMetadata {
|
|
62
|
+
permissions: string[]
|
|
63
|
+
backendEnvVars: string[]
|
|
64
|
+
frontendEnvVars: string[]
|
|
65
|
+
/**
|
|
66
|
+
* Owner-registered allowed OIDC redirect URIs for the production (standalone) client.
|
|
67
|
+
* Each entry is a full callback URL of a self-hosted deployment of the exported target
|
|
68
|
+
* project. Combined with the production hosts (generated + custom domain) when the
|
|
69
|
+
* production IAM client is (re)provisioned.
|
|
70
|
+
*/
|
|
71
|
+
oidcRedirectUris: string[]
|
|
72
|
+
/**
|
|
73
|
+
* Origins the target's own API accepts browser requests from.
|
|
74
|
+
*
|
|
75
|
+
* The redirect URIs say where a login may RETURN to; these say who may call the API afterwards.
|
|
76
|
+
* They are separate lists because they answer different questions and are wrong in different
|
|
77
|
+
* ways: an unregistered redirect URI is a login that cannot complete, an unlisted origin is an
|
|
78
|
+
* app that loads and then fails every request it makes.
|
|
79
|
+
*
|
|
80
|
+
* Set by the owner for a deployment the platform does not host — a target published on their own
|
|
81
|
+
* domain, or run on a developer's machine on a port the platform never chose. The platform's own
|
|
82
|
+
* hosts are always accepted and are never in this list.
|
|
83
|
+
*/
|
|
84
|
+
allowedOrigins: string[]
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export interface CustomSecretMetadata {
|
|
88
|
+
backendSecrets: Record<string, string>
|
|
89
|
+
frontendSecrets: Record<string, string>
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface NonSecretScalarSlotMetadata extends
|
|
93
|
+
SlotConstMetadata {
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface ScalarSlotMetadata extends
|
|
97
|
+
SlotConstMetadata,
|
|
98
|
+
SlotSecretMetadata {
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface ConfigSlotMetadata extends
|
|
102
|
+
SlotConstMetadata,
|
|
103
|
+
SlotListMetadata {
|
|
104
|
+
}
|
package/src/ux/consts.ts
ADDED
package/src/ux/index.ts
ADDED