@pennyfarthing/core 6.6.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/README.md +293 -0
- package/package.json +58 -0
- package/packages/core/bin/pennyfarthing.js +14 -0
- package/packages/core/dist/bmad/context-reader.d.ts +71 -0
- package/packages/core/dist/bmad/context-reader.d.ts.map +1 -0
- package/packages/core/dist/bmad/context-reader.js +369 -0
- package/packages/core/dist/bmad/context-reader.js.map +1 -0
- package/packages/core/dist/bmad/context-reader.test.d.ts +71 -0
- package/packages/core/dist/bmad/context-reader.test.d.ts.map +1 -0
- package/packages/core/dist/bmad/context-reader.test.js +878 -0
- package/packages/core/dist/bmad/context-reader.test.js.map +1 -0
- package/packages/core/dist/bmad/epics-parser.d.ts +61 -0
- package/packages/core/dist/bmad/epics-parser.d.ts.map +1 -0
- package/packages/core/dist/bmad/epics-parser.js +331 -0
- package/packages/core/dist/bmad/epics-parser.js.map +1 -0
- package/packages/core/dist/bmad/epics-parser.test.d.ts +7 -0
- package/packages/core/dist/bmad/epics-parser.test.d.ts.map +1 -0
- package/packages/core/dist/bmad/epics-parser.test.js +449 -0
- package/packages/core/dist/bmad/epics-parser.test.js.map +1 -0
- package/packages/core/dist/bmad/index.d.ts +11 -0
- package/packages/core/dist/bmad/index.d.ts.map +1 -0
- package/packages/core/dist/bmad/index.js +24 -0
- package/packages/core/dist/bmad/index.js.map +1 -0
- package/packages/core/dist/bmad/status-sync.d.ts +173 -0
- package/packages/core/dist/bmad/status-sync.d.ts.map +1 -0
- package/packages/core/dist/bmad/status-sync.js +463 -0
- package/packages/core/dist/bmad/status-sync.js.map +1 -0
- package/packages/core/dist/bmad/status-sync.test.d.ts +7 -0
- package/packages/core/dist/bmad/status-sync.test.d.ts.map +1 -0
- package/packages/core/dist/bmad/status-sync.test.js +702 -0
- package/packages/core/dist/bmad/status-sync.test.js.map +1 -0
- package/packages/core/dist/bmad/story-exporter.d.ts +55 -0
- package/packages/core/dist/bmad/story-exporter.d.ts.map +1 -0
- package/packages/core/dist/bmad/story-exporter.js +170 -0
- package/packages/core/dist/bmad/story-exporter.js.map +1 -0
- package/packages/core/dist/bmad/story-exporter.test.d.ts +51 -0
- package/packages/core/dist/bmad/story-exporter.test.d.ts.map +1 -0
- package/packages/core/dist/bmad/story-exporter.test.js +603 -0
- package/packages/core/dist/bmad/story-exporter.test.js.map +1 -0
- package/packages/core/dist/bmad/story-parser.d.ts +44 -0
- package/packages/core/dist/bmad/story-parser.d.ts.map +1 -0
- package/packages/core/dist/bmad/story-parser.js +307 -0
- package/packages/core/dist/bmad/story-parser.js.map +1 -0
- package/packages/core/dist/bmad/story-parser.test.d.ts +44 -0
- package/packages/core/dist/bmad/story-parser.test.d.ts.map +1 -0
- package/packages/core/dist/bmad/story-parser.test.js +693 -0
- package/packages/core/dist/bmad/story-parser.test.js.map +1 -0
- package/packages/core/dist/cli/commands/command.d.ts +28 -0
- package/packages/core/dist/cli/commands/command.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/command.js +399 -0
- package/packages/core/dist/cli/commands/command.js.map +1 -0
- package/packages/core/dist/cli/commands/cyclist.d.ts +46 -0
- package/packages/core/dist/cli/commands/cyclist.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/cyclist.js +191 -0
- package/packages/core/dist/cli/commands/cyclist.js.map +1 -0
- package/packages/core/dist/cli/commands/cyclist.test.d.ts +13 -0
- package/packages/core/dist/cli/commands/cyclist.test.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/cyclist.test.js +243 -0
- package/packages/core/dist/cli/commands/cyclist.test.js.map +1 -0
- package/packages/core/dist/cli/commands/doctor.d.ts +9 -0
- package/packages/core/dist/cli/commands/doctor.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/doctor.js +652 -0
- package/packages/core/dist/cli/commands/doctor.js.map +1 -0
- package/packages/core/dist/cli/commands/init.d.ts +8 -0
- package/packages/core/dist/cli/commands/init.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/init.js +524 -0
- package/packages/core/dist/cli/commands/init.js.map +1 -0
- package/packages/core/dist/cli/commands/skill.d.ts +28 -0
- package/packages/core/dist/cli/commands/skill.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/skill.js +416 -0
- package/packages/core/dist/cli/commands/skill.js.map +1 -0
- package/packages/core/dist/cli/commands/theme.d.ts +21 -0
- package/packages/core/dist/cli/commands/theme.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/theme.js +201 -0
- package/packages/core/dist/cli/commands/theme.js.map +1 -0
- package/packages/core/dist/cli/commands/uninstall.d.ts +8 -0
- package/packages/core/dist/cli/commands/uninstall.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/uninstall.js +237 -0
- package/packages/core/dist/cli/commands/uninstall.js.map +1 -0
- package/packages/core/dist/cli/commands/update.d.ts +9 -0
- package/packages/core/dist/cli/commands/update.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/update.js +545 -0
- package/packages/core/dist/cli/commands/update.js.map +1 -0
- package/packages/core/dist/cli/commands/version.d.ts +2 -0
- package/packages/core/dist/cli/commands/version.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/version.js +28 -0
- package/packages/core/dist/cli/commands/version.js.map +1 -0
- package/packages/core/dist/cli/customization.test.d.ts +12 -0
- package/packages/core/dist/cli/customization.test.d.ts.map +1 -0
- package/packages/core/dist/cli/customization.test.js +84 -0
- package/packages/core/dist/cli/customization.test.js.map +1 -0
- package/packages/core/dist/cli/cyclist-migration.test.d.ts +16 -0
- package/packages/core/dist/cli/cyclist-migration.test.d.ts.map +1 -0
- package/packages/core/dist/cli/cyclist-migration.test.js +224 -0
- package/packages/core/dist/cli/cyclist-migration.test.js.map +1 -0
- package/packages/core/dist/cli/index.d.ts +3 -0
- package/packages/core/dist/cli/index.d.ts.map +1 -0
- package/packages/core/dist/cli/index.js +174 -0
- package/packages/core/dist/cli/index.js.map +1 -0
- package/packages/core/dist/cli/ocean-profiles.test.d.ts +13 -0
- package/packages/core/dist/cli/ocean-profiles.test.d.ts.map +1 -0
- package/packages/core/dist/cli/ocean-profiles.test.js +134 -0
- package/packages/core/dist/cli/ocean-profiles.test.js.map +1 -0
- package/packages/core/dist/cli/theme-maker.test.d.ts +11 -0
- package/packages/core/dist/cli/theme-maker.test.d.ts.map +1 -0
- package/packages/core/dist/cli/theme-maker.test.js +356 -0
- package/packages/core/dist/cli/theme-maker.test.js.map +1 -0
- package/packages/core/dist/cli/utils/constants.d.ts +60 -0
- package/packages/core/dist/cli/utils/constants.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/constants.js +52 -0
- package/packages/core/dist/cli/utils/constants.js.map +1 -0
- package/packages/core/dist/cli/utils/files.d.ts +71 -0
- package/packages/core/dist/cli/utils/files.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/files.js +162 -0
- package/packages/core/dist/cli/utils/files.js.map +1 -0
- package/packages/core/dist/cli/utils/logger.d.ts +26 -0
- package/packages/core/dist/cli/utils/logger.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/logger.js +88 -0
- package/packages/core/dist/cli/utils/logger.js.map +1 -0
- package/packages/core/dist/cli/utils/manifest.d.ts +47 -0
- package/packages/core/dist/cli/utils/manifest.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/manifest.js +90 -0
- package/packages/core/dist/cli/utils/manifest.js.map +1 -0
- package/packages/core/dist/cli/utils/node-modules.d.ts +6 -0
- package/packages/core/dist/cli/utils/node-modules.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/node-modules.js +22 -0
- package/packages/core/dist/cli/utils/node-modules.js.map +1 -0
- package/packages/core/dist/cli/utils/prompts.d.ts +34 -0
- package/packages/core/dist/cli/utils/prompts.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/prompts.js +93 -0
- package/packages/core/dist/cli/utils/prompts.js.map +1 -0
- package/packages/core/dist/cli/utils/symlinks.d.ts +29 -0
- package/packages/core/dist/cli/utils/symlinks.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/symlinks.js +181 -0
- package/packages/core/dist/cli/utils/symlinks.js.map +1 -0
- package/packages/core/dist/cli/utils/themes.d.ts +104 -0
- package/packages/core/dist/cli/utils/themes.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/themes.js +393 -0
- package/packages/core/dist/cli/utils/themes.js.map +1 -0
- package/packages/core/dist/cli/utils/themes.test.d.ts +12 -0
- package/packages/core/dist/cli/utils/themes.test.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/themes.test.js +144 -0
- package/packages/core/dist/cli/utils/themes.test.js.map +1 -0
- package/packages/core/dist/cli/utils/version.d.ts +10 -0
- package/packages/core/dist/cli/utils/version.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/version.js +63 -0
- package/packages/core/dist/cli/utils/version.js.map +1 -0
- package/packages/core/dist/cli/workspace.test.d.ts +8 -0
- package/packages/core/dist/cli/workspace.test.d.ts.map +1 -0
- package/packages/core/dist/cli/workspace.test.js +154 -0
- package/packages/core/dist/cli/workspace.test.js.map +1 -0
- package/packages/core/dist/index.d.ts +6 -0
- package/packages/core/dist/index.d.ts.map +1 -0
- package/packages/core/dist/index.js +10 -0
- package/packages/core/dist/index.js.map +1 -0
- package/packages/core/dist/permissions/index.d.ts +9 -0
- package/packages/core/dist/permissions/index.d.ts.map +1 -0
- package/packages/core/dist/permissions/index.js +13 -0
- package/packages/core/dist/permissions/index.js.map +1 -0
- package/packages/core/dist/permissions/permission-schema.d.ts +89 -0
- package/packages/core/dist/permissions/permission-schema.d.ts.map +1 -0
- package/packages/core/dist/permissions/permission-schema.js +120 -0
- package/packages/core/dist/permissions/permission-schema.js.map +1 -0
- package/packages/core/dist/permissions/permission-schema.test.d.ts +40 -0
- package/packages/core/dist/permissions/permission-schema.test.d.ts.map +1 -0
- package/packages/core/dist/permissions/permission-schema.test.js +367 -0
- package/packages/core/dist/permissions/permission-schema.test.js.map +1 -0
- package/packages/core/dist/scripts/add-ocean-profiles.d.ts +9 -0
- package/packages/core/dist/scripts/add-ocean-profiles.d.ts.map +1 -0
- package/packages/core/dist/scripts/add-ocean-profiles.js +695 -0
- package/packages/core/dist/scripts/add-ocean-profiles.js.map +1 -0
- package/packages/core/dist/scripts/benchmark-integration.d.ts +182 -0
- package/packages/core/dist/scripts/benchmark-integration.d.ts.map +1 -0
- package/packages/core/dist/scripts/benchmark-integration.js +691 -0
- package/packages/core/dist/scripts/benchmark-integration.js.map +1 -0
- package/packages/core/dist/scripts/benchmark-integration.test.d.ts +13 -0
- package/packages/core/dist/scripts/benchmark-integration.test.d.ts.map +1 -0
- package/packages/core/dist/scripts/benchmark-integration.test.js +680 -0
- package/packages/core/dist/scripts/benchmark-integration.test.js.map +1 -0
- package/packages/core/dist/scripts/debugging-scenarios.test.d.ts +18 -0
- package/packages/core/dist/scripts/debugging-scenarios.test.d.ts.map +1 -0
- package/packages/core/dist/scripts/debugging-scenarios.test.js +317 -0
- package/packages/core/dist/scripts/debugging-scenarios.test.js.map +1 -0
- package/packages/core/dist/scripts/generate-all-faces.d.ts +10 -0
- package/packages/core/dist/scripts/generate-all-faces.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-all-faces.js +256 -0
- package/packages/core/dist/scripts/generate-all-faces.js.map +1 -0
- package/packages/core/dist/scripts/generate-all-faces.test.d.ts +17 -0
- package/packages/core/dist/scripts/generate-all-faces.test.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-all-faces.test.js +372 -0
- package/packages/core/dist/scripts/generate-all-faces.test.js.map +1 -0
- package/packages/core/dist/scripts/generate-all-spiders.d.ts +10 -0
- package/packages/core/dist/scripts/generate-all-spiders.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-all-spiders.js +306 -0
- package/packages/core/dist/scripts/generate-all-spiders.js.map +1 -0
- package/packages/core/dist/scripts/generate-ascii-face.d.ts +52 -0
- package/packages/core/dist/scripts/generate-ascii-face.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-ascii-face.js +155 -0
- package/packages/core/dist/scripts/generate-ascii-face.js.map +1 -0
- package/packages/core/dist/scripts/generate-face.d.ts +52 -0
- package/packages/core/dist/scripts/generate-face.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-face.js +199 -0
- package/packages/core/dist/scripts/generate-face.js.map +1 -0
- package/packages/core/dist/scripts/generate-face.test.d.ts +13 -0
- package/packages/core/dist/scripts/generate-face.test.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-face.test.js +301 -0
- package/packages/core/dist/scripts/generate-face.test.js.map +1 -0
- package/packages/core/dist/scripts/generate-report.d.ts +65 -0
- package/packages/core/dist/scripts/generate-report.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-report.js +378 -0
- package/packages/core/dist/scripts/generate-report.js.map +1 -0
- package/packages/core/dist/scripts/generate-report.test.d.ts +13 -0
- package/packages/core/dist/scripts/generate-report.test.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-report.test.js +363 -0
- package/packages/core/dist/scripts/generate-report.test.js.map +1 -0
- package/packages/core/dist/scripts/generate-spider-report.d.ts +65 -0
- package/packages/core/dist/scripts/generate-spider-report.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-spider-report.js +366 -0
- package/packages/core/dist/scripts/generate-spider-report.js.map +1 -0
- package/packages/core/dist/scripts/generate-spider-report.test.d.ts +13 -0
- package/packages/core/dist/scripts/generate-spider-report.test.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-spider-report.test.js +367 -0
- package/packages/core/dist/scripts/generate-spider-report.test.js.map +1 -0
- package/packages/core/dist/scripts/generate-spider.d.ts +37 -0
- package/packages/core/dist/scripts/generate-spider.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-spider.js +315 -0
- package/packages/core/dist/scripts/generate-spider.js.map +1 -0
- package/packages/core/dist/scripts/generate-spider.test.d.ts +14 -0
- package/packages/core/dist/scripts/generate-spider.test.d.ts.map +1 -0
- package/packages/core/dist/scripts/generate-spider.test.js +269 -0
- package/packages/core/dist/scripts/generate-spider.test.js.map +1 -0
- package/packages/core/dist/scripts/job-fair-aggregator.d.ts +150 -0
- package/packages/core/dist/scripts/job-fair-aggregator.d.ts.map +1 -0
- package/packages/core/dist/scripts/job-fair-aggregator.js +547 -0
- package/packages/core/dist/scripts/job-fair-aggregator.js.map +1 -0
- package/packages/core/dist/scripts/job-fair-aggregator.test.d.ts +14 -0
- package/packages/core/dist/scripts/job-fair-aggregator.test.d.ts.map +1 -0
- package/packages/core/dist/scripts/job-fair-aggregator.test.js +616 -0
- package/packages/core/dist/scripts/job-fair-aggregator.test.js.map +1 -0
- package/packages/core/dist/scripts/run-ci.test.d.ts +20 -0
- package/packages/core/dist/scripts/run-ci.test.d.ts.map +1 -0
- package/packages/core/dist/scripts/run-ci.test.js +127 -0
- package/packages/core/dist/scripts/run-ci.test.js.map +1 -0
- package/packages/core/dist/scripts/theme-detail.test.d.ts +10 -0
- package/packages/core/dist/scripts/theme-detail.test.d.ts.map +1 -0
- package/packages/core/dist/scripts/theme-detail.test.js +199 -0
- package/packages/core/dist/scripts/theme-detail.test.js.map +1 -0
- package/packages/core/dist/scripts/validate-ocean-profiles.d.ts +9 -0
- package/packages/core/dist/scripts/validate-ocean-profiles.d.ts.map +1 -0
- package/packages/core/dist/scripts/validate-ocean-profiles.js +130 -0
- package/packages/core/dist/scripts/validate-ocean-profiles.js.map +1 -0
- package/packages/core/dist/workflow/generic-handoff.d.ts +235 -0
- package/packages/core/dist/workflow/generic-handoff.d.ts.map +1 -0
- package/packages/core/dist/workflow/generic-handoff.js +358 -0
- package/packages/core/dist/workflow/generic-handoff.js.map +1 -0
- package/packages/core/dist/workflow/generic-handoff.test.d.ts +21 -0
- package/packages/core/dist/workflow/generic-handoff.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/generic-handoff.test.js +499 -0
- package/packages/core/dist/workflow/generic-handoff.test.js.map +1 -0
- package/packages/core/dist/workflow/generic-sm-finish.d.ts +89 -0
- package/packages/core/dist/workflow/generic-sm-finish.d.ts.map +1 -0
- package/packages/core/dist/workflow/generic-sm-finish.js +157 -0
- package/packages/core/dist/workflow/generic-sm-finish.js.map +1 -0
- package/packages/core/dist/workflow/generic-sm-setup.d.ts +138 -0
- package/packages/core/dist/workflow/generic-sm-setup.d.ts.map +1 -0
- package/packages/core/dist/workflow/generic-sm-setup.js +382 -0
- package/packages/core/dist/workflow/generic-sm-setup.js.map +1 -0
- package/packages/core/dist/workflow/sm-subagents.test.d.ts +23 -0
- package/packages/core/dist/workflow/sm-subagents.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/sm-subagents.test.js +727 -0
- package/packages/core/dist/workflow/sm-subagents.test.js.map +1 -0
- package/packages/core/dist/workflow/story-workflow-routing.test.d.ts +17 -0
- package/packages/core/dist/workflow/story-workflow-routing.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/story-workflow-routing.test.js +559 -0
- package/packages/core/dist/workflow/story-workflow-routing.test.js.map +1 -0
- package/packages/core/dist/workflow/test-cache.d.ts +131 -0
- package/packages/core/dist/workflow/test-cache.d.ts.map +1 -0
- package/packages/core/dist/workflow/test-cache.js +226 -0
- package/packages/core/dist/workflow/test-cache.js.map +1 -0
- package/packages/core/dist/workflow/test-cache.test.d.ts +17 -0
- package/packages/core/dist/workflow/test-cache.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/test-cache.test.js +438 -0
- package/packages/core/dist/workflow/test-cache.test.js.map +1 -0
- package/packages/core/dist/workflow/workflow-loader.d.ts +76 -0
- package/packages/core/dist/workflow/workflow-loader.d.ts.map +1 -0
- package/packages/core/dist/workflow/workflow-loader.js +133 -0
- package/packages/core/dist/workflow/workflow-loader.js.map +1 -0
- package/packages/core/dist/workflow/workflow-loader.test.d.ts +15 -0
- package/packages/core/dist/workflow/workflow-loader.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/workflow-loader.test.js +354 -0
- package/packages/core/dist/workflow/workflow-loader.test.js.map +1 -0
- package/packages/core/dist/workflow/workflow-migration.test.d.ts +17 -0
- package/packages/core/dist/workflow/workflow-migration.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/workflow-migration.test.js +372 -0
- package/packages/core/dist/workflow/workflow-migration.test.js.map +1 -0
- package/packages/core/dist/workflow/workflow-router.d.ts +55 -0
- package/packages/core/dist/workflow/workflow-router.d.ts.map +1 -0
- package/packages/core/dist/workflow/workflow-router.js +245 -0
- package/packages/core/dist/workflow/workflow-router.js.map +1 -0
- package/packages/core/dist/workflow/workflow-router.test.d.ts +20 -0
- package/packages/core/dist/workflow/workflow-router.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/workflow-router.test.js +607 -0
- package/packages/core/dist/workflow/workflow-router.test.js.map +1 -0
- package/packages/core/dist/workflow/workflow-schema.d.ts +98 -0
- package/packages/core/dist/workflow/workflow-schema.d.ts.map +1 -0
- package/packages/core/dist/workflow/workflow-schema.js +230 -0
- package/packages/core/dist/workflow/workflow-schema.js.map +1 -0
- package/packages/core/dist/workflow/workflow-schema.test.d.ts +45 -0
- package/packages/core/dist/workflow/workflow-schema.test.d.ts.map +1 -0
- package/packages/core/dist/workflow/workflow-schema.test.js +512 -0
- package/packages/core/dist/workflow/workflow-schema.test.js.map +1 -0
- package/pennyfarthing-dist/agents/README.md +397 -0
- package/pennyfarthing-dist/agents/architect.md +171 -0
- package/pennyfarthing-dist/agents/dev.md +225 -0
- package/pennyfarthing-dist/agents/devops.md +183 -0
- package/pennyfarthing-dist/agents/generic-handoff.md +451 -0
- package/pennyfarthing-dist/agents/generic-sm-finish.md +261 -0
- package/pennyfarthing-dist/agents/generic-sm-setup.md +214 -0
- package/pennyfarthing-dist/agents/orchestrator.md +316 -0
- package/pennyfarthing-dist/agents/pm.md +153 -0
- package/pennyfarthing-dist/agents/reviewer-preflight.md +224 -0
- package/pennyfarthing-dist/agents/reviewer.md +315 -0
- package/pennyfarthing-dist/agents/sm-file-summary.md +109 -0
- package/pennyfarthing-dist/agents/sm-handoff.md +97 -0
- package/pennyfarthing-dist/agents/sm.md +480 -0
- package/pennyfarthing-dist/agents/tea.md +191 -0
- package/pennyfarthing-dist/agents/tech-writer.md +148 -0
- package/pennyfarthing-dist/agents/testing-runner.md +420 -0
- package/pennyfarthing-dist/agents/ux-designer.md +158 -0
- package/pennyfarthing-dist/agents/workflow-status-check.md +332 -0
- package/pennyfarthing-dist/commands/architect.md +62 -0
- package/pennyfarthing-dist/commands/benchmark-control.md +69 -0
- package/pennyfarthing-dist/commands/benchmark.md +467 -0
- package/pennyfarthing-dist/commands/brainstorm.md +91 -0
- package/pennyfarthing-dist/commands/check.md +156 -0
- package/pennyfarthing-dist/commands/chore.md +178 -0
- package/pennyfarthing-dist/commands/close-epic.md +136 -0
- package/pennyfarthing-dist/commands/continue-session.md +184 -0
- package/pennyfarthing-dist/commands/create-branches-from-story.md +374 -0
- package/pennyfarthing-dist/commands/create-theme.md +29 -0
- package/pennyfarthing-dist/commands/dev.md +60 -0
- package/pennyfarthing-dist/commands/devops.md +59 -0
- package/pennyfarthing-dist/commands/git-cleanup.md +340 -0
- package/pennyfarthing-dist/commands/health-check.md +108 -0
- package/pennyfarthing-dist/commands/help.md +264 -0
- package/pennyfarthing-dist/commands/job-fair.md +102 -0
- package/pennyfarthing-dist/commands/list-themes.md +17 -0
- package/pennyfarthing-dist/commands/new-work.md +127 -0
- package/pennyfarthing-dist/commands/orchestrator.md +56 -0
- package/pennyfarthing-dist/commands/parallel-work.md +71 -0
- package/pennyfarthing-dist/commands/party-mode.md +67 -0
- package/pennyfarthing-dist/commands/permissions.md +193 -0
- package/pennyfarthing-dist/commands/pm.md +60 -0
- package/pennyfarthing-dist/commands/prime.md +140 -0
- package/pennyfarthing-dist/commands/release.md +58 -0
- package/pennyfarthing-dist/commands/repo-status.md +49 -0
- package/pennyfarthing-dist/commands/retro.md +200 -0
- package/pennyfarthing-dist/commands/reviewer.md +64 -0
- package/pennyfarthing-dist/commands/run-ci.md +116 -0
- package/pennyfarthing-dist/commands/set-theme.md +52 -0
- package/pennyfarthing-dist/commands/show-theme.md +21 -0
- package/pennyfarthing-dist/commands/sm.md +70 -0
- package/pennyfarthing-dist/commands/solo.md +411 -0
- package/pennyfarthing-dist/commands/sprint-planning.md +109 -0
- package/pennyfarthing-dist/commands/start-epic.md +156 -0
- package/pennyfarthing-dist/commands/sync-epic-to-jira.md +184 -0
- package/pennyfarthing-dist/commands/sync-work-with-sprint.md +376 -0
- package/pennyfarthing-dist/commands/tea.md +63 -0
- package/pennyfarthing-dist/commands/tech-writer.md +53 -0
- package/pennyfarthing-dist/commands/theme-maker.md +671 -0
- package/pennyfarthing-dist/commands/update-domain-docs.md +83 -0
- package/pennyfarthing-dist/commands/ux-designer.md +62 -0
- package/pennyfarthing-dist/commands/work.md +111 -0
- package/pennyfarthing-dist/guides/AGENT-COORDINATION.md +480 -0
- package/pennyfarthing-dist/guides/AGENT-SCOPES.md +201 -0
- package/pennyfarthing-dist/guides/HOOKS.md +230 -0
- package/pennyfarthing-dist/guides/PROMPT-PATTERNS.md +338 -0
- package/pennyfarthing-dist/guides/SESSION-ARTIFACTS.md +193 -0
- package/pennyfarthing-dist/guides/agent-template-strategic.md +148 -0
- package/pennyfarthing-dist/guides/agent-template-tactical.md +162 -0
- package/pennyfarthing-dist/guides/patterns/approval-gates-pattern.md +746 -0
- package/pennyfarthing-dist/guides/patterns/fan-out-fan-in-pattern.md +574 -0
- package/pennyfarthing-dist/guides/patterns/helper-delegation-pattern.md +488 -0
- package/pennyfarthing-dist/guides/patterns/tdd-flow-pattern.md +402 -0
- package/pennyfarthing-dist/guides/permission-protocol.md +188 -0
- package/pennyfarthing-dist/guides/persona-loading.md +46 -0
- package/pennyfarthing-dist/guides/persona-system.md +294 -0
- package/pennyfarthing-dist/guides/shared-agent-behavior.md +388 -0
- package/pennyfarthing-dist/guides/shared-context.md +147 -0
- package/pennyfarthing-dist/guides/strategic-agent-behavior.md +348 -0
- package/pennyfarthing-dist/guides/tactical-agent-behavior.md +1041 -0
- package/pennyfarthing-dist/guides/workflow-schema.md +195 -0
- package/pennyfarthing-dist/guides/worktree-mode.md +113 -0
- package/pennyfarthing-dist/output-styles/teaching.md +33 -0
- package/pennyfarthing-dist/output-styles/terse.md +20 -0
- package/pennyfarthing-dist/output-styles/verbose.md +28 -0
- package/pennyfarthing-dist/personas/themes/1984.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/a-team.yaml +207 -0
- package/pennyfarthing-dist/personas/themes/agatha-christie.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/alice-in-wonderland.yaml +330 -0
- package/pennyfarthing-dist/personas/themes/all-stars.yaml +332 -0
- package/pennyfarthing-dist/personas/themes/ancient-philosophers.yaml +320 -0
- package/pennyfarthing-dist/personas/themes/ancient-strategists.yaml +306 -0
- package/pennyfarthing-dist/personas/themes/arcane.yaml +288 -0
- package/pennyfarthing-dist/personas/themes/arthurian-mythos.yaml +331 -0
- package/pennyfarthing-dist/personas/themes/avatar-the-last-airbender.yaml +288 -0
- package/pennyfarthing-dist/personas/themes/babylon-5.yaml +288 -0
- package/pennyfarthing-dist/personas/themes/battlestar-galactica.yaml +288 -0
- package/pennyfarthing-dist/personas/themes/better-call-saul.yaml +288 -0
- package/pennyfarthing-dist/personas/themes/big-lebowski.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/black-sails.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/blade-runner.yaml +295 -0
- package/pennyfarthing-dist/personas/themes/bobiverse.yaml +288 -0
- package/pennyfarthing-dist/personas/themes/breaking-bad.yaml +327 -0
- package/pennyfarthing-dist/personas/themes/catch-22.yaml +316 -0
- package/pennyfarthing-dist/personas/themes/classical-composers.yaml +310 -0
- package/pennyfarthing-dist/personas/themes/control.yaml +197 -0
- package/pennyfarthing-dist/personas/themes/count-of-monte-cristo.yaml +320 -0
- package/pennyfarthing-dist/personas/themes/cowboy-bebop.yaml +323 -0
- package/pennyfarthing-dist/personas/themes/deadwood.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/dickens.yaml +320 -0
- package/pennyfarthing-dist/personas/themes/discworld.yaml +332 -0
- package/pennyfarthing-dist/personas/themes/doctor-who.yaml +290 -0
- package/pennyfarthing-dist/personas/themes/don-quixote.yaml +320 -0
- package/pennyfarthing-dist/personas/themes/dune.yaml +307 -0
- package/pennyfarthing-dist/personas/themes/enlightenment-thinkers.yaml +320 -0
- package/pennyfarthing-dist/personas/themes/expeditionary-force.yaml +288 -0
- package/pennyfarthing-dist/personas/themes/fargo.yaml +330 -0
- package/pennyfarthing-dist/personas/themes/film-auteurs.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/firefly.yaml +328 -0
- package/pennyfarthing-dist/personas/themes/foundation.yaml +290 -0
- package/pennyfarthing-dist/personas/themes/futurama.yaml +321 -0
- package/pennyfarthing-dist/personas/themes/game-of-thrones.yaml +290 -0
- package/pennyfarthing-dist/personas/themes/gilligans-island.yaml +243 -0
- package/pennyfarthing-dist/personas/themes/gothic-literature.yaml +308 -0
- package/pennyfarthing-dist/personas/themes/great-gatsby.yaml +308 -0
- package/pennyfarthing-dist/personas/themes/greek-mythology.yaml +330 -0
- package/pennyfarthing-dist/personas/themes/hannibal.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/harry-potter.yaml +324 -0
- package/pennyfarthing-dist/personas/themes/his-dark-materials.yaml +291 -0
- package/pennyfarthing-dist/personas/themes/historical-figures.yaml +288 -0
- package/pennyfarthing-dist/personas/themes/hitchhikers-guide.yaml +331 -0
- package/pennyfarthing-dist/personas/themes/house-md.yaml +321 -0
- package/pennyfarthing-dist/personas/themes/imperial-radch.yaml +289 -0
- package/pennyfarthing-dist/personas/themes/inspector-morse.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/jane-austen.yaml +287 -0
- package/pennyfarthing-dist/personas/themes/jazz-legends.yaml +320 -0
- package/pennyfarthing-dist/personas/themes/justified.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/legion-of-doom.yaml +219 -0
- package/pennyfarthing-dist/personas/themes/les-miserables.yaml +299 -0
- package/pennyfarthing-dist/personas/themes/lord-of-the-rings.yaml +334 -0
- package/pennyfarthing-dist/personas/themes/lovecraft-mythos.yaml +334 -0
- package/pennyfarthing-dist/personas/themes/mad-max.yaml +355 -0
- package/pennyfarthing-dist/personas/themes/mad-men.yaml +289 -0
- package/pennyfarthing-dist/personas/themes/marvel-mcu.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/mash.yaml +334 -0
- package/pennyfarthing-dist/personas/themes/mass-effect.yaml +289 -0
- package/pennyfarthing-dist/personas/themes/military-commanders.yaml +306 -0
- package/pennyfarthing-dist/personas/themes/moby-dick.yaml +320 -0
- package/pennyfarthing-dist/personas/themes/monty-python.yaml +303 -0
- package/pennyfarthing-dist/personas/themes/neuromancer.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/norse-mythology.yaml +329 -0
- package/pennyfarthing-dist/personas/themes/parks-and-rec.yaml +242 -0
- package/pennyfarthing-dist/personas/themes/peaky-blinders.yaml +298 -0
- package/pennyfarthing-dist/personas/themes/princess-bride.yaml +220 -0
- package/pennyfarthing-dist/personas/themes/renaissance-masters.yaml +320 -0
- package/pennyfarthing-dist/personas/themes/rome.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/russian-masters.yaml +318 -0
- package/pennyfarthing-dist/personas/themes/sandman.yaml +288 -0
- package/pennyfarthing-dist/personas/themes/scientific-revolutionaries.yaml +320 -0
- package/pennyfarthing-dist/personas/themes/shakespeare.yaml +301 -0
- package/pennyfarthing-dist/personas/themes/sherlock-holmes.yaml +289 -0
- package/pennyfarthing-dist/personas/themes/snow-crash.yaml +288 -0
- package/pennyfarthing-dist/personas/themes/software-pioneers.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/star-trek-tng.yaml +230 -0
- package/pennyfarthing-dist/personas/themes/star-trek-tos.yaml +210 -0
- package/pennyfarthing-dist/personas/themes/star-wars.yaml +303 -0
- package/pennyfarthing-dist/personas/themes/succession.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/superfriends.yaml +208 -0
- package/pennyfarthing-dist/personas/themes/ted-lasso.yaml +236 -0
- package/pennyfarthing-dist/personas/themes/the-americans.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/the-crown.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/the-expanse.yaml +213 -0
- package/pennyfarthing-dist/personas/themes/the-good-place.yaml +322 -0
- package/pennyfarthing-dist/personas/themes/the-matrix.yaml +353 -0
- package/pennyfarthing-dist/personas/themes/the-odyssey.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/the-office.yaml +330 -0
- package/pennyfarthing-dist/personas/themes/the-simpsons.yaml +308 -0
- package/pennyfarthing-dist/personas/themes/the-sopranos.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/the-wire.yaml +311 -0
- package/pennyfarthing-dist/personas/themes/the-witcher.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/twin-peaks.yaml +302 -0
- package/pennyfarthing-dist/personas/themes/vorkosigan-saga.yaml +300 -0
- package/pennyfarthing-dist/personas/themes/watchmen.yaml +291 -0
- package/pennyfarthing-dist/personas/themes/west-wing.yaml +291 -0
- package/pennyfarthing-dist/personas/themes/world-explorers.yaml +320 -0
- package/pennyfarthing-dist/personas/themes/wwii-leaders.yaml +307 -0
- package/pennyfarthing-dist/personas/themes/x-files.yaml +302 -0
- package/pennyfarthing-dist/scripts/add-short-names.mjs +264 -0
- package/pennyfarthing-dist/scripts/agent-session.sh +367 -0
- package/pennyfarthing-dist/scripts/check-context.sh +187 -0
- package/pennyfarthing-dist/scripts/check.sh +497 -0
- package/pennyfarthing-dist/scripts/deploy.sh +284 -0
- package/pennyfarthing-dist/scripts/doctor-dogfood.sh +360 -0
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +61 -0
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +66 -0
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +35 -0
- package/pennyfarthing-dist/scripts/hooks/post-merge.sh +166 -0
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +50 -0
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +71 -0
- package/pennyfarthing-dist/scripts/hooks/pre-push.sh +54 -0
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +98 -0
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +59 -0
- package/pennyfarthing-dist/scripts/install-git-hooks.sh +91 -0
- package/pennyfarthing-dist/scripts/prime.sh +161 -0
- package/pennyfarthing-dist/scripts/release.sh +198 -0
- package/pennyfarthing-dist/scripts/repo-utils.sh +778 -0
- package/pennyfarthing-dist/scripts/run-ci.sh +219 -0
- package/pennyfarthing-dist/scripts/run.sh +65 -0
- package/pennyfarthing-dist/scripts/statusline.sh +264 -0
- package/pennyfarthing-dist/scripts/tests/check.test.sh +582 -0
- package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +107 -0
- package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +597 -0
- package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +514 -0
- package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +517 -0
- package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +331 -0
- package/pennyfarthing-dist/scripts/uninstall.sh +271 -0
- package/pennyfarthing-dist/scripts/utils/background-tasks.sh +177 -0
- package/pennyfarthing-dist/scripts/utils/check-status.sh +251 -0
- package/pennyfarthing-dist/scripts/utils/checkpoint.sh +136 -0
- package/pennyfarthing-dist/scripts/utils/common.sh +157 -0
- package/pennyfarthing-dist/scripts/utils/create-feature-branches.sh +230 -0
- package/pennyfarthing-dist/scripts/utils/file-lock.sh +269 -0
- package/pennyfarthing-dist/scripts/utils/find-related-work.sh +231 -0
- package/pennyfarthing-dist/scripts/utils/find-root.sh +33 -0
- package/pennyfarthing-dist/scripts/utils/generate-skill-docs.sh +110 -0
- package/pennyfarthing-dist/scripts/utils/git-status-all.sh +127 -0
- package/pennyfarthing-dist/scripts/utils/ground-truth-judge.py +289 -0
- package/pennyfarthing-dist/scripts/utils/jira/jira-lib.mjs +443 -0
- package/pennyfarthing-dist/scripts/utils/jira/jira-sync-story.mjs +208 -0
- package/pennyfarthing-dist/scripts/utils/jira/jira-sync.mjs +198 -0
- package/pennyfarthing-dist/scripts/utils/jira-claim-story.sh +162 -0
- package/pennyfarthing-dist/scripts/utils/jira-lib.sh +463 -0
- package/pennyfarthing-dist/scripts/utils/jira-sync-story.sh +8 -0
- package/pennyfarthing-dist/scripts/utils/jira-sync.sh +8 -0
- package/pennyfarthing-dist/scripts/utils/log-skill-usage.sh +74 -0
- package/pennyfarthing-dist/scripts/utils/logging.sh +186 -0
- package/pennyfarthing-dist/scripts/utils/repo-scan.sh +141 -0
- package/pennyfarthing-dist/scripts/utils/retry.sh +76 -0
- package/pennyfarthing-dist/scripts/utils/run-timestamp.sh +7 -0
- package/pennyfarthing-dist/scripts/utils/session-cleanup.sh +319 -0
- package/pennyfarthing-dist/scripts/utils/skill-usage-report.sh +193 -0
- package/pennyfarthing-dist/scripts/utils/sprint-common.sh +286 -0
- package/pennyfarthing-dist/scripts/utils/sprint-metrics.sh +241 -0
- package/pennyfarthing-dist/scripts/utils/swebench-judge.py +400 -0
- package/pennyfarthing-dist/scripts/utils/sync-epic-to-jira.sh +16 -0
- package/pennyfarthing-dist/scripts/utils/test-setup.sh +337 -0
- package/pennyfarthing-dist/scripts/utils/validate-subagent-frontmatter.sh +160 -0
- package/pennyfarthing-dist/scripts/worktree-manager.sh +498 -0
- package/pennyfarthing-dist/skills/agentic-patterns/SKILL.md +236 -0
- package/pennyfarthing-dist/skills/changelog/SKILL.md +367 -0
- package/pennyfarthing-dist/skills/code-review/SKILL.md +168 -0
- package/pennyfarthing-dist/skills/context-engineering/SKILL.md +268 -0
- package/pennyfarthing-dist/skills/cyclist/SKILL.md +117 -0
- package/pennyfarthing-dist/skills/dev-patterns/SKILL.md +421 -0
- package/pennyfarthing-dist/skills/finalize-run/SKILL.md +258 -0
- package/pennyfarthing-dist/skills/jira/SKILL.md +281 -0
- package/pennyfarthing-dist/skills/judge/SKILL.md +524 -0
- package/pennyfarthing-dist/skills/just/SKILL.md +160 -0
- package/pennyfarthing-dist/skills/mermaid/SKILL.md +240 -0
- package/pennyfarthing-dist/skills/otel/skill.md +222 -0
- package/pennyfarthing-dist/skills/permissions/skill.md +172 -0
- package/pennyfarthing-dist/skills/persona-benchmark/SKILL.md +173 -0
- package/pennyfarthing-dist/skills/skill-registry.schema.json +102 -0
- package/pennyfarthing-dist/skills/skill-registry.yaml +335 -0
- package/pennyfarthing-dist/skills/sprint-context/SKILL.md +120 -0
- package/pennyfarthing-dist/skills/story-management/SKILL.md +208 -0
- package/pennyfarthing-dist/skills/testing/SKILL.md +99 -0
- package/pennyfarthing-dist/skills/testing/references/troubleshooting.md +124 -0
- package/pennyfarthing-dist/skills/theme/skill.md +129 -0
- package/pennyfarthing-dist/skills/theme-creation/SKILL.md +169 -0
- package/pennyfarthing-dist/skills/workflow/SKILL.md +160 -0
- package/pennyfarthing-dist/skills/yq/SKILL.md +264 -0
- package/pennyfarthing-dist/templates/LEADERBOARD.schema.yaml +187 -0
- package/pennyfarthing-dist/templates/LEADERBOARD.template.md +59 -0
- package/pennyfarthing-dist/templates/agent-scopes.yaml.template +276 -0
- package/pennyfarthing-dist/templates/pennyfarthing-settings.yaml.template +61 -0
- package/pennyfarthing-dist/templates/persona-config.yaml.template +22 -0
- package/pennyfarthing-dist/templates/preferences.yaml.template +15 -0
- package/pennyfarthing-dist/templates/settings.local.json.template +90 -0
- package/pennyfarthing-dist/templates/setup-env.sh.template +18 -0
- package/pennyfarthing-dist/templates/shared-context.md.template +70 -0
- package/pennyfarthing-dist/templates/sidecar/decisions.md.template +40 -0
- package/pennyfarthing-dist/templates/sidecar/gotchas.md.template +37 -0
- package/pennyfarthing-dist/templates/sidecar/patterns.md.template +34 -0
- package/pennyfarthing-dist/workflows/agent-docs.yaml +70 -0
- package/pennyfarthing-dist/workflows/bdd.yaml +58 -0
- package/pennyfarthing-dist/workflows/tdd.yaml +50 -0
- package/pennyfarthing-dist/workflows/trivial.yaml +40 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batch Chernoff Face Generator
|
|
3
|
+
*
|
|
4
|
+
* Story 11-4: Generate anchor theme faces + markdown report
|
|
5
|
+
* Story 11-6: Generate full 630-face matrix with index
|
|
6
|
+
*
|
|
7
|
+
* Generates SVG faces for all themes and creates markdown indices.
|
|
8
|
+
*/
|
|
9
|
+
import { writeFileSync, mkdirSync, existsSync, readdirSync, readFileSync } from 'fs';
|
|
10
|
+
import { join, dirname } from 'path';
|
|
11
|
+
import { fileURLToPath } from 'url';
|
|
12
|
+
import { parse as parseYaml } from 'yaml';
|
|
13
|
+
import { generateFace } from './generate-face.js';
|
|
14
|
+
import { findMonorepoRoot } from '../cli/utils/files.js';
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = dirname(__filename);
|
|
17
|
+
// Find monorepo root by walking up from current directory
|
|
18
|
+
const projectRoot = findMonorepoRoot(__dirname);
|
|
19
|
+
const facesDir = join(projectRoot, 'pennyfarthing-dist', 'personas', 'faces');
|
|
20
|
+
const themesDir = join(projectRoot, 'pennyfarthing-dist', 'personas', 'themes');
|
|
21
|
+
// Dynamically load all themes from the themes directory
|
|
22
|
+
function getAllThemes() {
|
|
23
|
+
const files = readdirSync(themesDir).filter((f) => f.endsWith('.yaml'));
|
|
24
|
+
return files.map((f) => f.replace('.yaml', '')).sort();
|
|
25
|
+
}
|
|
26
|
+
const THEMES = getAllThemes();
|
|
27
|
+
// 10 agents per theme
|
|
28
|
+
const AGENTS = [
|
|
29
|
+
'orchestrator',
|
|
30
|
+
'sm',
|
|
31
|
+
'tea',
|
|
32
|
+
'dev',
|
|
33
|
+
'reviewer',
|
|
34
|
+
'architect',
|
|
35
|
+
'pm',
|
|
36
|
+
'tech-writer',
|
|
37
|
+
'ux-designer',
|
|
38
|
+
'devops',
|
|
39
|
+
];
|
|
40
|
+
// Human-readable agent names for markdown (fallback when character name not available)
|
|
41
|
+
const AGENT_NAMES = {
|
|
42
|
+
orchestrator: 'Orchestrator',
|
|
43
|
+
sm: 'Scrum Master',
|
|
44
|
+
tea: 'Test Engineer',
|
|
45
|
+
dev: 'Developer',
|
|
46
|
+
reviewer: 'Reviewer',
|
|
47
|
+
architect: 'Architect',
|
|
48
|
+
pm: 'Product Manager',
|
|
49
|
+
'tech-writer': 'Tech Writer',
|
|
50
|
+
'ux-designer': 'UX Designer',
|
|
51
|
+
devops: 'DevOps',
|
|
52
|
+
};
|
|
53
|
+
const themeCache = new Map();
|
|
54
|
+
// Convert name to URL-safe slug (lowercase kebab-case)
|
|
55
|
+
function toSlug(name) {
|
|
56
|
+
return name
|
|
57
|
+
.toLowerCase()
|
|
58
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
59
|
+
.replace(/^-|-$/g, '');
|
|
60
|
+
}
|
|
61
|
+
// Generate OCEAN suffix from scores
|
|
62
|
+
function oceanSuffix(ocean) {
|
|
63
|
+
return `${ocean.O}${ocean.C}${ocean.E}${ocean.A}${ocean.N}`;
|
|
64
|
+
}
|
|
65
|
+
// Load agent data for all agents in a theme
|
|
66
|
+
function getAgentData(theme) {
|
|
67
|
+
if (themeCache.has(theme)) {
|
|
68
|
+
return themeCache.get(theme);
|
|
69
|
+
}
|
|
70
|
+
const themePath = join(themesDir, `${theme}.yaml`);
|
|
71
|
+
const content = readFileSync(themePath, 'utf-8');
|
|
72
|
+
const data = parseYaml(content);
|
|
73
|
+
const agents = {};
|
|
74
|
+
if (data?.agents) {
|
|
75
|
+
for (const agent of AGENTS) {
|
|
76
|
+
const agentInfo = data.agents[agent];
|
|
77
|
+
if (agentInfo) {
|
|
78
|
+
const character = agentInfo.character || AGENT_NAMES[agent];
|
|
79
|
+
const shortName = agentInfo.shortName || character.split(' ')[0];
|
|
80
|
+
const baseSlug = toSlug(shortName);
|
|
81
|
+
const ocean = agentInfo.ocean || { O: 3, C: 3, E: 3, A: 3, N: 3 };
|
|
82
|
+
const slug = `${baseSlug}-${oceanSuffix(ocean)}`;
|
|
83
|
+
agents[agent] = { character, shortName, slug };
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
agents[agent] = {
|
|
87
|
+
character: AGENT_NAMES[agent],
|
|
88
|
+
shortName: AGENT_NAMES[agent],
|
|
89
|
+
slug: agent,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
themeCache.set(theme, agents);
|
|
95
|
+
return agents;
|
|
96
|
+
}
|
|
97
|
+
// Load character names for all agents in a theme (backward compat)
|
|
98
|
+
function getCharacterNames(theme) {
|
|
99
|
+
const agents = getAgentData(theme);
|
|
100
|
+
const names = {};
|
|
101
|
+
for (const agent of AGENTS) {
|
|
102
|
+
names[agent] = agents[agent]?.character || AGENT_NAMES[agent];
|
|
103
|
+
}
|
|
104
|
+
return names;
|
|
105
|
+
}
|
|
106
|
+
// Get a specific character name
|
|
107
|
+
function getCharacterName(theme, agent) {
|
|
108
|
+
const names = getCharacterNames(theme);
|
|
109
|
+
return names[agent] || AGENT_NAMES[agent];
|
|
110
|
+
}
|
|
111
|
+
// Escape quotes for use in HTML attributes
|
|
112
|
+
function escapeForAttr(str) {
|
|
113
|
+
return str.replace(/"/g, '"');
|
|
114
|
+
}
|
|
115
|
+
// Escape quotes for use in markdown text (replace with single quotes)
|
|
116
|
+
function escapeForMarkdown(str) {
|
|
117
|
+
return str.replace(/"/g, "'");
|
|
118
|
+
}
|
|
119
|
+
// Format theme name for display
|
|
120
|
+
function formatTheme(theme) {
|
|
121
|
+
return theme
|
|
122
|
+
.split('-')
|
|
123
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
|
124
|
+
.join(' ');
|
|
125
|
+
}
|
|
126
|
+
function ensureDir(dir) {
|
|
127
|
+
if (!existsSync(dir)) {
|
|
128
|
+
mkdirSync(dir, { recursive: true });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
function generateSvgFiles() {
|
|
132
|
+
console.log('Generating SVG files...');
|
|
133
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
134
|
+
const byRoleDir = join(facesDir, 'by-role');
|
|
135
|
+
// Create directory structure
|
|
136
|
+
ensureDir(byThemeDir);
|
|
137
|
+
ensureDir(byRoleDir);
|
|
138
|
+
for (const theme of THEMES) {
|
|
139
|
+
ensureDir(join(byThemeDir, theme));
|
|
140
|
+
}
|
|
141
|
+
for (const agent of AGENTS) {
|
|
142
|
+
ensureDir(join(byRoleDir, agent));
|
|
143
|
+
}
|
|
144
|
+
// Generate faces
|
|
145
|
+
let count = 0;
|
|
146
|
+
for (const theme of THEMES) {
|
|
147
|
+
const agentData = getAgentData(theme);
|
|
148
|
+
for (const agent of AGENTS) {
|
|
149
|
+
const svg = generateFace(theme, agent);
|
|
150
|
+
const slug = agentData[agent]?.slug || agent;
|
|
151
|
+
// Write to by-theme directory using slug-based naming
|
|
152
|
+
const themeFilePath = join(byThemeDir, theme, `${slug}.svg`);
|
|
153
|
+
writeFileSync(themeFilePath, svg);
|
|
154
|
+
// Write to by-role directory (keeps role-based for cross-theme comparison)
|
|
155
|
+
const roleFilePath = join(byRoleDir, agent, `${theme}.svg`);
|
|
156
|
+
writeFileSync(roleFilePath, svg);
|
|
157
|
+
count++;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
console.log(`Generated ${count} SVG files.`);
|
|
161
|
+
}
|
|
162
|
+
// Fixed image size for consistent display
|
|
163
|
+
const IMG_SIZE = 80;
|
|
164
|
+
function imgTag(src, alt) {
|
|
165
|
+
return `<img src="${src}" alt="${escapeForAttr(alt)}" width="${IMG_SIZE}" height="${IMG_SIZE}">`;
|
|
166
|
+
}
|
|
167
|
+
const LEGEND = `## Reading the Faces
|
|
168
|
+
|
|
169
|
+
Each face visualizes OCEAN personality scores through facial features:
|
|
170
|
+
|
|
171
|
+
| Trait | Feature | Low (1) | High (5) |
|
|
172
|
+
|-------|---------|---------|----------|
|
|
173
|
+
| **O**penness | Eye size | Small eyes | Large eyes |
|
|
174
|
+
| **C**onscientiousness | Face shape | Wide & round | Narrow & angular |
|
|
175
|
+
| **E**xtraversion | Mouth | Small frown | Wide smile |
|
|
176
|
+
| **A**greeableness | Eyebrows | Angled down (stern) | Arched up (friendly) |
|
|
177
|
+
| **N**euroticism | Line weight | Thin strokes | Thick strokes |
|
|
178
|
+
|
|
179
|
+
Background colors indicate agent role.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
`;
|
|
184
|
+
// Generate image tag with character name caption (reserved for future use)
|
|
185
|
+
function _imgWithName(src, characterName, agentRole) {
|
|
186
|
+
const safeName = escapeForMarkdown(characterName);
|
|
187
|
+
return `${imgTag(src, characterName)}<br/>**${safeName}**<br/><small>${agentRole}</small>`;
|
|
188
|
+
}
|
|
189
|
+
function generateTeamPhotos() {
|
|
190
|
+
console.log('Generating team-photos.md...');
|
|
191
|
+
let md = `# Team Photos
|
|
192
|
+
|
|
193
|
+
Chernoff faces for each theme's agent team. Vertical layout for easy visual comparison.
|
|
194
|
+
|
|
195
|
+
${LEGEND}`;
|
|
196
|
+
for (const theme of THEMES) {
|
|
197
|
+
const themeTitle = formatTheme(theme);
|
|
198
|
+
const charNames = getCharacterNames(theme);
|
|
199
|
+
md += `## ${themeTitle}\n\n`;
|
|
200
|
+
// Vertical list: one agent per row for easy comparison
|
|
201
|
+
md += '| Role | Face | Character |\n';
|
|
202
|
+
md += '|:-----|:----:|:----------|\n';
|
|
203
|
+
const agentData = getAgentData(theme);
|
|
204
|
+
for (const agent of AGENTS) {
|
|
205
|
+
const charName = escapeForMarkdown(charNames[agent]);
|
|
206
|
+
const slug = agentData[agent]?.slug || agent;
|
|
207
|
+
const imgSrc = `by-theme/${theme}/${slug}.svg`;
|
|
208
|
+
md += `| ${AGENT_NAMES[agent]} | ${imgTag(imgSrc, charNames[agent])} | **${charName}** |\n`;
|
|
209
|
+
}
|
|
210
|
+
md += '\n';
|
|
211
|
+
}
|
|
212
|
+
writeFileSync(join(facesDir, 'team-photos.md'), md);
|
|
213
|
+
console.log('Generated team-photos.md');
|
|
214
|
+
}
|
|
215
|
+
// Generate image tag with character name for role gallery (reserved for future use)
|
|
216
|
+
function _imgWithCharacter(src, theme, agent) {
|
|
217
|
+
const charName = getCharacterName(theme, agent);
|
|
218
|
+
const safeName = escapeForMarkdown(charName);
|
|
219
|
+
return `${imgTag(src, charName)}<br/>**${safeName}**`;
|
|
220
|
+
}
|
|
221
|
+
function generateRoleGallery() {
|
|
222
|
+
console.log('Generating role-gallery.md...');
|
|
223
|
+
let md = `# Role Gallery
|
|
224
|
+
|
|
225
|
+
Each agent role across all ${THEMES.length} themes. Vertical layout for easy visual comparison of how personality profiles vary.
|
|
226
|
+
|
|
227
|
+
${LEGEND}`;
|
|
228
|
+
for (const agent of AGENTS) {
|
|
229
|
+
const agentName = AGENT_NAMES[agent];
|
|
230
|
+
md += `## ${agentName}\n\n`;
|
|
231
|
+
// Vertical list: one theme per row for easy comparison
|
|
232
|
+
md += '| Theme | Face | Character |\n';
|
|
233
|
+
md += '|:------|:----:|:----------|\n';
|
|
234
|
+
for (const theme of THEMES) {
|
|
235
|
+
const charName = escapeForMarkdown(getCharacterName(theme, agent));
|
|
236
|
+
const imgSrc = `by-role/${agent}/${theme}.svg`;
|
|
237
|
+
md += `| ${formatTheme(theme)} | ${imgTag(imgSrc, charName)} | **${charName}** |\n`;
|
|
238
|
+
}
|
|
239
|
+
md += '\n';
|
|
240
|
+
}
|
|
241
|
+
writeFileSync(join(facesDir, 'role-gallery.md'), md);
|
|
242
|
+
console.log('Generated role-gallery.md');
|
|
243
|
+
}
|
|
244
|
+
// Main execution
|
|
245
|
+
console.log('=== Batch Chernoff Face Generator ===');
|
|
246
|
+
console.log(`Output directory: ${facesDir}`);
|
|
247
|
+
console.log(`Themes: ${THEMES.length}`);
|
|
248
|
+
console.log(`Agents: ${AGENTS.length}`);
|
|
249
|
+
console.log(`Total faces: ${THEMES.length * AGENTS.length}`);
|
|
250
|
+
console.log('');
|
|
251
|
+
generateSvgFiles();
|
|
252
|
+
generateTeamPhotos();
|
|
253
|
+
generateRoleGallery();
|
|
254
|
+
console.log('');
|
|
255
|
+
console.log('Done!');
|
|
256
|
+
//# sourceMappingURL=generate-all-faces.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-all-faces.js","sourceRoot":"","sources":["../../src/scripts/generate-all-faces.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Story 11-6: Generate full 630-face matrix with index
|
|
3
|
+
*
|
|
4
|
+
* SKIPPED: The faces/ directory was never created.
|
|
5
|
+
* Story 11-6 was planned but not implemented. These tests are retained
|
|
6
|
+
* for when the feature is implemented, but skipped to avoid false failures.
|
|
7
|
+
*
|
|
8
|
+
* These tests verify:
|
|
9
|
+
* AC1: 630 SVG faces in pennyfarthing-dist/personas/faces/
|
|
10
|
+
* AC2: Master matrix viewable (HTML or markdown)
|
|
11
|
+
* AC3: Navigation by theme, role, or OCEAN profile
|
|
12
|
+
* AC4: File size and load time acceptable
|
|
13
|
+
*
|
|
14
|
+
* Run with: npm test
|
|
15
|
+
*/
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=generate-all-faces.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-all-faces.test.d.ts","sourceRoot":"","sources":["../../src/scripts/generate-all-faces.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Story 11-6: Generate full 630-face matrix with index
|
|
3
|
+
*
|
|
4
|
+
* SKIPPED: The faces/ directory was never created.
|
|
5
|
+
* Story 11-6 was planned but not implemented. These tests are retained
|
|
6
|
+
* for when the feature is implemented, but skipped to avoid false failures.
|
|
7
|
+
*
|
|
8
|
+
* These tests verify:
|
|
9
|
+
* AC1: 630 SVG faces in pennyfarthing-dist/personas/faces/
|
|
10
|
+
* AC2: Master matrix viewable (HTML or markdown)
|
|
11
|
+
* AC3: Navigation by theme, role, or OCEAN profile
|
|
12
|
+
* AC4: File size and load time acceptable
|
|
13
|
+
*
|
|
14
|
+
* Run with: npm test
|
|
15
|
+
*/
|
|
16
|
+
import { describe, it } from 'node:test';
|
|
17
|
+
import assert from 'node:assert';
|
|
18
|
+
import { join, dirname } from 'path';
|
|
19
|
+
import { fileURLToPath } from 'url';
|
|
20
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'fs';
|
|
21
|
+
import { findMonorepoRoot } from '../cli/utils/files.js';
|
|
22
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
23
|
+
const __dirname = dirname(__filename);
|
|
24
|
+
// Find monorepo root by walking up from current directory
|
|
25
|
+
const projectRoot = findMonorepoRoot(__dirname);
|
|
26
|
+
const facesDir = join(projectRoot, 'pennyfarthing-dist', 'personas', 'faces');
|
|
27
|
+
const themesDir = join(projectRoot, 'pennyfarthing-dist', 'personas', 'themes');
|
|
28
|
+
// Expected counts - derive from actual theme files
|
|
29
|
+
const EXPECTED_AGENT_COUNT = 10;
|
|
30
|
+
// Count actual themes dynamically (was hardcoded to 63, now 91+)
|
|
31
|
+
const actualThemeFiles = existsSync(themesDir)
|
|
32
|
+
? readdirSync(themesDir).filter((f) => f.endsWith('.yaml')).length
|
|
33
|
+
: 0;
|
|
34
|
+
const EXPECTED_THEME_COUNT = actualThemeFiles;
|
|
35
|
+
const EXPECTED_TOTAL_FACES = EXPECTED_THEME_COUNT * EXPECTED_AGENT_COUNT;
|
|
36
|
+
// All 10 agent roles
|
|
37
|
+
const AGENTS = [
|
|
38
|
+
'orchestrator',
|
|
39
|
+
'sm',
|
|
40
|
+
'tea',
|
|
41
|
+
'dev',
|
|
42
|
+
'reviewer',
|
|
43
|
+
'architect',
|
|
44
|
+
'pm',
|
|
45
|
+
'tech-writer',
|
|
46
|
+
'ux-designer',
|
|
47
|
+
'devops',
|
|
48
|
+
];
|
|
49
|
+
// Helper to get all theme names from themes directory
|
|
50
|
+
function getAllThemes() {
|
|
51
|
+
const files = readdirSync(themesDir).filter((f) => f.endsWith('.yaml'));
|
|
52
|
+
return files.map((f) => f.replace('.yaml', '')).sort();
|
|
53
|
+
}
|
|
54
|
+
// ============================================================================
|
|
55
|
+
// AC1: 630 SVG faces in pennyfarthing-dist/personas/faces/
|
|
56
|
+
// ============================================================================
|
|
57
|
+
describe('AC1: 630 SVG Faces Generated', { skip: 'Story 11-6 not implemented - faces/ directory does not exist' }, () => {
|
|
58
|
+
it('should have faces directory structure', () => {
|
|
59
|
+
assert.ok(existsSync(facesDir), 'faces/ directory should exist');
|
|
60
|
+
assert.ok(existsSync(join(facesDir, 'by-theme')), 'faces/by-theme/ should exist');
|
|
61
|
+
assert.ok(existsSync(join(facesDir, 'by-role')), 'faces/by-role/ should exist');
|
|
62
|
+
});
|
|
63
|
+
it('should have 63 theme directories in by-theme/', () => {
|
|
64
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
65
|
+
const themeDirs = readdirSync(byThemeDir).filter((f) => statSync(join(byThemeDir, f)).isDirectory());
|
|
66
|
+
assert.strictEqual(themeDirs.length, EXPECTED_THEME_COUNT, `Should have ${EXPECTED_THEME_COUNT} theme directories, got ${themeDirs.length}`);
|
|
67
|
+
});
|
|
68
|
+
it('should have 10 agent directories in by-role/', () => {
|
|
69
|
+
const byRoleDir = join(facesDir, 'by-role');
|
|
70
|
+
const roleDirs = readdirSync(byRoleDir).filter((f) => statSync(join(byRoleDir, f)).isDirectory());
|
|
71
|
+
assert.strictEqual(roleDirs.length, EXPECTED_AGENT_COUNT, `Should have ${EXPECTED_AGENT_COUNT} role directories, got ${roleDirs.length}`);
|
|
72
|
+
});
|
|
73
|
+
it('should have 10 SVG files per theme directory', () => {
|
|
74
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
75
|
+
const themes = getAllThemes();
|
|
76
|
+
for (const theme of themes) {
|
|
77
|
+
const themeDir = join(byThemeDir, theme);
|
|
78
|
+
if (!existsSync(themeDir)) {
|
|
79
|
+
assert.fail(`Missing theme directory: ${theme}`);
|
|
80
|
+
}
|
|
81
|
+
const svgFiles = readdirSync(themeDir).filter((f) => f.endsWith('.svg'));
|
|
82
|
+
assert.strictEqual(svgFiles.length, EXPECTED_AGENT_COUNT, `Theme ${theme} should have ${EXPECTED_AGENT_COUNT} SVG files, got ${svgFiles.length}`);
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
it('should have 63 SVG files per role directory', () => {
|
|
86
|
+
const byRoleDir = join(facesDir, 'by-role');
|
|
87
|
+
for (const agent of AGENTS) {
|
|
88
|
+
const roleDir = join(byRoleDir, agent);
|
|
89
|
+
if (!existsSync(roleDir)) {
|
|
90
|
+
assert.fail(`Missing role directory: ${agent}`);
|
|
91
|
+
}
|
|
92
|
+
const svgFiles = readdirSync(roleDir).filter((f) => f.endsWith('.svg'));
|
|
93
|
+
assert.strictEqual(svgFiles.length, EXPECTED_THEME_COUNT, `Role ${agent} should have ${EXPECTED_THEME_COUNT} SVG files, got ${svgFiles.length}`);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
it('should have exactly 630 total SVG files in by-theme/', () => {
|
|
97
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
98
|
+
let totalCount = 0;
|
|
99
|
+
const themes = readdirSync(byThemeDir).filter((f) => statSync(join(byThemeDir, f)).isDirectory());
|
|
100
|
+
for (const theme of themes) {
|
|
101
|
+
const svgFiles = readdirSync(join(byThemeDir, theme)).filter((f) => f.endsWith('.svg'));
|
|
102
|
+
totalCount += svgFiles.length;
|
|
103
|
+
}
|
|
104
|
+
assert.strictEqual(totalCount, EXPECTED_TOTAL_FACES, `Should have ${EXPECTED_TOTAL_FACES} total SVG files, got ${totalCount}`);
|
|
105
|
+
});
|
|
106
|
+
it('should have matching files in by-theme/ and by-role/', () => {
|
|
107
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
108
|
+
const byRoleDir = join(facesDir, 'by-role');
|
|
109
|
+
// by-theme uses character names (e.g., seth-25334.svg)
|
|
110
|
+
// by-role uses theme names (e.g., deadwood.svg)
|
|
111
|
+
// Verify structure exists and counts match
|
|
112
|
+
const sampleThemes = ['deadwood', 'firefly', 'dune', 'discworld'].filter((t) => existsSync(join(byThemeDir, t)));
|
|
113
|
+
for (const theme of sampleThemes) {
|
|
114
|
+
// Check by-theme has 10 character files
|
|
115
|
+
const themeDir = join(byThemeDir, theme);
|
|
116
|
+
const themeSvgs = readdirSync(themeDir).filter((f) => f.endsWith('.svg'));
|
|
117
|
+
assert.strictEqual(themeSvgs.length, EXPECTED_AGENT_COUNT, `by-theme/${theme}/ should have ${EXPECTED_AGENT_COUNT} SVG files`);
|
|
118
|
+
// Check by-role/{agent}/ has this theme's file
|
|
119
|
+
for (const agent of AGENTS) {
|
|
120
|
+
const roleFile = join(byRoleDir, agent, `${theme}.svg`);
|
|
121
|
+
assert.ok(existsSync(roleFile), `Missing by-role file: ${agent}/${theme}.svg`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
it('should generate valid SVG content in each file', () => {
|
|
126
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
127
|
+
const themes = readdirSync(byThemeDir)
|
|
128
|
+
.filter((f) => statSync(join(byThemeDir, f)).isDirectory())
|
|
129
|
+
.slice(0, 5); // Check first 5 themes to save time
|
|
130
|
+
for (const theme of themes) {
|
|
131
|
+
const themeDir = join(byThemeDir, theme);
|
|
132
|
+
const svgFiles = readdirSync(themeDir).filter((f) => f.endsWith('.svg'));
|
|
133
|
+
for (const file of svgFiles) {
|
|
134
|
+
const content = readFileSync(join(themeDir, file), 'utf-8');
|
|
135
|
+
assert.ok(content.includes('<svg'), `${theme}/${file} should contain <svg tag`);
|
|
136
|
+
assert.ok(content.includes('</svg>'), `${theme}/${file} should contain </svg> tag`);
|
|
137
|
+
assert.ok(content.includes('xmlns="http://www.w3.org/2000/svg"'), `${theme}/${file} should have SVG xmlns`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
// ============================================================================
|
|
143
|
+
// AC2: Master matrix viewable (HTML or markdown)
|
|
144
|
+
// ============================================================================
|
|
145
|
+
describe('AC2: Master Matrix Documentation', { skip: 'Story 11-6 not implemented' }, () => {
|
|
146
|
+
it('should have team-photos.md with all 63 themes', () => {
|
|
147
|
+
const teamPhotosPath = join(facesDir, 'team-photos.md');
|
|
148
|
+
assert.ok(existsSync(teamPhotosPath), 'team-photos.md should exist');
|
|
149
|
+
const content = readFileSync(teamPhotosPath, 'utf-8');
|
|
150
|
+
const themes = getAllThemes();
|
|
151
|
+
// Each theme should have a section
|
|
152
|
+
for (const theme of themes) {
|
|
153
|
+
const formattedTheme = theme
|
|
154
|
+
.split('-')
|
|
155
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
156
|
+
.join(' ');
|
|
157
|
+
assert.ok(content.includes(`## ${formattedTheme}`) || content.includes(`# ${formattedTheme}`), `team-photos.md should have section for ${formattedTheme}`);
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
it('should have role-gallery.md with all 10 agents', () => {
|
|
161
|
+
const roleGalleryPath = join(facesDir, 'role-gallery.md');
|
|
162
|
+
assert.ok(existsSync(roleGalleryPath), 'role-gallery.md should exist');
|
|
163
|
+
const content = readFileSync(roleGalleryPath, 'utf-8');
|
|
164
|
+
// Each agent should have a section
|
|
165
|
+
const agentNames = [
|
|
166
|
+
'Orchestrator',
|
|
167
|
+
'Scrum Master',
|
|
168
|
+
'Test Engineer',
|
|
169
|
+
'Developer',
|
|
170
|
+
'Reviewer',
|
|
171
|
+
'Architect',
|
|
172
|
+
'Product Manager',
|
|
173
|
+
'Tech Writer',
|
|
174
|
+
'UX Designer',
|
|
175
|
+
'DevOps',
|
|
176
|
+
];
|
|
177
|
+
for (const agentName of agentNames) {
|
|
178
|
+
assert.ok(content.includes(`## ${agentName}`) || content.includes(`# ${agentName}`), `role-gallery.md should have section for ${agentName}`);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
it('should have image references for all 630 faces in team-photos.md', () => {
|
|
182
|
+
const teamPhotosPath = join(facesDir, 'team-photos.md');
|
|
183
|
+
const content = readFileSync(teamPhotosPath, 'utf-8');
|
|
184
|
+
// Count image references (img tags or markdown images)
|
|
185
|
+
const imgTagMatches = content.match(/<img[^>]*>/g) || [];
|
|
186
|
+
const mdImgMatches = content.match(/!\[.*?\]\(.*?\.svg\)/g) || [];
|
|
187
|
+
const totalImages = imgTagMatches.length + mdImgMatches.length;
|
|
188
|
+
assert.ok(totalImages >= EXPECTED_TOTAL_FACES, `team-photos.md should reference ${EXPECTED_TOTAL_FACES} images, found ${totalImages}`);
|
|
189
|
+
});
|
|
190
|
+
it('should have image references for all 630 faces in role-gallery.md', () => {
|
|
191
|
+
const roleGalleryPath = join(facesDir, 'role-gallery.md');
|
|
192
|
+
const content = readFileSync(roleGalleryPath, 'utf-8');
|
|
193
|
+
// Count image references
|
|
194
|
+
const imgTagMatches = content.match(/<img[^>]*>/g) || [];
|
|
195
|
+
const mdImgMatches = content.match(/!\[.*?\]\(.*?\.svg\)/g) || [];
|
|
196
|
+
const totalImages = imgTagMatches.length + mdImgMatches.length;
|
|
197
|
+
assert.ok(totalImages >= EXPECTED_TOTAL_FACES, `role-gallery.md should reference ${EXPECTED_TOTAL_FACES} images, found ${totalImages}`);
|
|
198
|
+
});
|
|
199
|
+
it('should include OCEAN legend/explanation', () => {
|
|
200
|
+
const teamPhotosPath = join(facesDir, 'team-photos.md');
|
|
201
|
+
const content = readFileSync(teamPhotosPath, 'utf-8');
|
|
202
|
+
// Check for OCEAN explanation
|
|
203
|
+
assert.ok(content.includes('Openness') || content.includes('OCEAN'), 'team-photos.md should explain OCEAN traits');
|
|
204
|
+
assert.ok(content.includes('Eye') || content.includes('eye'), 'team-photos.md should explain eye feature mapping');
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
// ============================================================================
|
|
208
|
+
// AC3: Navigation by theme, role, or OCEAN profile
|
|
209
|
+
// ============================================================================
|
|
210
|
+
describe('AC3: Navigation Structure', { skip: 'Story 11-6 not implemented' }, () => {
|
|
211
|
+
it('should organize faces by theme for theme-based navigation', () => {
|
|
212
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
213
|
+
const themes = getAllThemes();
|
|
214
|
+
// Verify structure allows finding all agents for a given theme
|
|
215
|
+
// Note: by-theme uses character names (e.g., seth-25334.svg), not role names
|
|
216
|
+
for (const theme of themes.slice(0, 5)) {
|
|
217
|
+
// Sample 5 themes
|
|
218
|
+
const themeDir = join(byThemeDir, theme);
|
|
219
|
+
assert.ok(existsSync(themeDir), `by-theme/${theme}/ should exist`);
|
|
220
|
+
// Should have 10 SVG files (one per agent role)
|
|
221
|
+
const svgFiles = readdirSync(themeDir).filter((f) => f.endsWith('.svg'));
|
|
222
|
+
assert.strictEqual(svgFiles.length, EXPECTED_AGENT_COUNT, `by-theme/${theme}/ should have ${EXPECTED_AGENT_COUNT} SVGs, got ${svgFiles.length}`);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
it('should organize faces by role for role-based navigation', () => {
|
|
226
|
+
const byRoleDir = join(facesDir, 'by-role');
|
|
227
|
+
const themes = getAllThemes();
|
|
228
|
+
// Verify structure allows finding all themes for a given role
|
|
229
|
+
for (const agent of AGENTS) {
|
|
230
|
+
const roleDir = join(byRoleDir, agent);
|
|
231
|
+
assert.ok(existsSync(roleDir), `by-role/${agent}/ should exist`);
|
|
232
|
+
// Check sample of themes
|
|
233
|
+
for (const theme of themes.slice(0, 5)) {
|
|
234
|
+
const themeFile = join(roleDir, `${theme}.svg`);
|
|
235
|
+
assert.ok(existsSync(themeFile), `by-role/${agent}/${theme}.svg should exist`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
it('should have navigable markdown sections for each theme', () => {
|
|
240
|
+
const teamPhotosPath = join(facesDir, 'team-photos.md');
|
|
241
|
+
const content = readFileSync(teamPhotosPath, 'utf-8');
|
|
242
|
+
// Markdown headings create navigable anchors
|
|
243
|
+
const headingMatches = content.match(/^## .+$/gm) || [];
|
|
244
|
+
const themes = getAllThemes();
|
|
245
|
+
assert.ok(headingMatches.length >= themes.length, `team-photos.md should have at least ${themes.length} theme sections, found ${headingMatches.length}`);
|
|
246
|
+
});
|
|
247
|
+
it('should have navigable markdown sections for each role', () => {
|
|
248
|
+
const roleGalleryPath = join(facesDir, 'role-gallery.md');
|
|
249
|
+
const content = readFileSync(roleGalleryPath, 'utf-8');
|
|
250
|
+
// Markdown headings create navigable anchors
|
|
251
|
+
const headingMatches = content.match(/^## .+$/gm) || [];
|
|
252
|
+
assert.ok(headingMatches.length >= EXPECTED_AGENT_COUNT, `role-gallery.md should have at least ${EXPECTED_AGENT_COUNT} role sections, found ${headingMatches.length}`);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
// ============================================================================
|
|
256
|
+
// AC4: File size and load time acceptable
|
|
257
|
+
// ============================================================================
|
|
258
|
+
describe('AC4: Performance - File Size and Load Time', { skip: 'Story 11-6 not implemented' }, () => {
|
|
259
|
+
it('should have reasonable individual SVG file sizes (<50KB each)', () => {
|
|
260
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
261
|
+
const MAX_SVG_SIZE = 50 * 1024; // 50KB per SVG
|
|
262
|
+
const themes = readdirSync(byThemeDir)
|
|
263
|
+
.filter((f) => statSync(join(byThemeDir, f)).isDirectory())
|
|
264
|
+
.slice(0, 10); // Check first 10 themes
|
|
265
|
+
for (const theme of themes) {
|
|
266
|
+
const themeDir = join(byThemeDir, theme);
|
|
267
|
+
const svgFiles = readdirSync(themeDir).filter((f) => f.endsWith('.svg'));
|
|
268
|
+
for (const file of svgFiles) {
|
|
269
|
+
const filePath = join(themeDir, file);
|
|
270
|
+
const stats = statSync(filePath);
|
|
271
|
+
assert.ok(stats.size < MAX_SVG_SIZE, `${theme}/${file} is ${stats.size} bytes, exceeds ${MAX_SVG_SIZE} byte limit`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
it('should have total by-theme directory size under 10MB', () => {
|
|
276
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
277
|
+
const MAX_TOTAL_SIZE = 10 * 1024 * 1024; // 10MB
|
|
278
|
+
let totalSize = 0;
|
|
279
|
+
const themes = readdirSync(byThemeDir).filter((f) => statSync(join(byThemeDir, f)).isDirectory());
|
|
280
|
+
for (const theme of themes) {
|
|
281
|
+
const themeDir = join(byThemeDir, theme);
|
|
282
|
+
const svgFiles = readdirSync(themeDir).filter((f) => f.endsWith('.svg'));
|
|
283
|
+
for (const file of svgFiles) {
|
|
284
|
+
const stats = statSync(join(themeDir, file));
|
|
285
|
+
totalSize += stats.size;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
assert.ok(totalSize < MAX_TOTAL_SIZE, `Total by-theme size is ${(totalSize / 1024 / 1024).toFixed(2)}MB, exceeds 10MB limit`);
|
|
289
|
+
});
|
|
290
|
+
it('should have markdown files under 2MB each', () => {
|
|
291
|
+
const MAX_MD_SIZE = 2 * 1024 * 1024; // 2MB per markdown file
|
|
292
|
+
const mdFiles = ['team-photos.md', 'role-gallery.md'];
|
|
293
|
+
for (const file of mdFiles) {
|
|
294
|
+
const filePath = join(facesDir, file);
|
|
295
|
+
if (existsSync(filePath)) {
|
|
296
|
+
const stats = statSync(filePath);
|
|
297
|
+
assert.ok(stats.size < MAX_MD_SIZE, `${file} is ${(stats.size / 1024).toFixed(2)}KB, exceeds 2MB limit`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
it('should have SVG files that parse quickly (no excessive complexity)', () => {
|
|
302
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
303
|
+
const MAX_ELEMENTS = 100; // Max SVG elements per face
|
|
304
|
+
// Sample a few files
|
|
305
|
+
const themes = readdirSync(byThemeDir)
|
|
306
|
+
.filter((f) => statSync(join(byThemeDir, f)).isDirectory())
|
|
307
|
+
.slice(0, 3);
|
|
308
|
+
for (const theme of themes) {
|
|
309
|
+
const themeDir = join(byThemeDir, theme);
|
|
310
|
+
const svgFile = readdirSync(themeDir).find((f) => f.endsWith('.svg'));
|
|
311
|
+
if (svgFile) {
|
|
312
|
+
const content = readFileSync(join(themeDir, svgFile), 'utf-8');
|
|
313
|
+
const elementCount = (content.match(/<[a-z]+/gi) || []).length;
|
|
314
|
+
assert.ok(elementCount < MAX_ELEMENTS, `${theme}/${svgFile} has ${elementCount} elements, exceeds ${MAX_ELEMENTS} limit`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
// ============================================================================
|
|
320
|
+
// Integration: Full Matrix Validation
|
|
321
|
+
// ============================================================================
|
|
322
|
+
describe('Integration: Complete 630-Face Matrix', { skip: 'Story 11-6 not implemented' }, () => {
|
|
323
|
+
it('should have no missing theme-agent combinations', () => {
|
|
324
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
325
|
+
const byRoleDir = join(facesDir, 'by-role');
|
|
326
|
+
const themes = getAllThemes();
|
|
327
|
+
const missing = [];
|
|
328
|
+
// by-theme uses character names, so check count per theme
|
|
329
|
+
for (const theme of themes) {
|
|
330
|
+
const themeDir = join(byThemeDir, theme);
|
|
331
|
+
if (!existsSync(themeDir)) {
|
|
332
|
+
missing.push(`${theme}/ (directory missing)`);
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
const svgCount = readdirSync(themeDir).filter((f) => f.endsWith('.svg')).length;
|
|
336
|
+
if (svgCount !== EXPECTED_AGENT_COUNT) {
|
|
337
|
+
missing.push(`${theme}/ (has ${svgCount} SVGs, expected ${EXPECTED_AGENT_COUNT})`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// by-role uses theme names, so verify each role has all themes
|
|
341
|
+
for (const agent of AGENTS) {
|
|
342
|
+
const roleDir = join(byRoleDir, agent);
|
|
343
|
+
if (!existsSync(roleDir)) {
|
|
344
|
+
missing.push(`by-role/${agent}/ (directory missing)`);
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
for (const theme of themes) {
|
|
348
|
+
const filePath = join(roleDir, `${theme}.svg`);
|
|
349
|
+
if (!existsSync(filePath)) {
|
|
350
|
+
missing.push(`by-role/${agent}/${theme}.svg`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
assert.strictEqual(missing.length, 0, `Missing ${missing.length} face files: ${missing.slice(0, 10).join(', ')}${missing.length > 10 ? '...' : ''}`);
|
|
355
|
+
});
|
|
356
|
+
it('should have consistent directory structure', () => {
|
|
357
|
+
const byThemeDir = join(facesDir, 'by-theme');
|
|
358
|
+
const byRoleDir = join(facesDir, 'by-role');
|
|
359
|
+
// by-theme should have 63 dirs
|
|
360
|
+
const themeDirs = readdirSync(byThemeDir).filter((f) => statSync(join(byThemeDir, f)).isDirectory());
|
|
361
|
+
// by-role should have 10 dirs
|
|
362
|
+
const roleDirs = readdirSync(byRoleDir).filter((f) => statSync(join(byRoleDir, f)).isDirectory());
|
|
363
|
+
assert.strictEqual(themeDirs.length, EXPECTED_THEME_COUNT, 'by-theme should have 63 dirs');
|
|
364
|
+
assert.strictEqual(roleDirs.length, EXPECTED_AGENT_COUNT, 'by-role should have 10 dirs');
|
|
365
|
+
// Each role dir should have 63 SVGs
|
|
366
|
+
for (const role of roleDirs) {
|
|
367
|
+
const svgs = readdirSync(join(byRoleDir, role)).filter((f) => f.endsWith('.svg'));
|
|
368
|
+
assert.strictEqual(svgs.length, EXPECTED_THEME_COUNT, `by-role/${role} should have 63 SVGs`);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
});
|
|
372
|
+
//# sourceMappingURL=generate-all-faces.test.js.map
|