@pennyfarthing/core 10.4.0 → 11.0.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 +4 -4
- package/package.json +16 -14
- package/packages/core/dist/benchmark/benchmark-integration.d.ts +182 -0
- package/packages/core/dist/benchmark/benchmark-integration.d.ts.map +1 -0
- package/packages/core/dist/benchmark/benchmark-integration.js +710 -0
- package/packages/core/dist/benchmark/benchmark-integration.js.map +1 -0
- package/packages/core/dist/benchmark/benchmark-integration.test.d.ts +6 -0
- package/packages/core/dist/benchmark/benchmark-integration.test.d.ts.map +1 -0
- package/packages/core/dist/benchmark/benchmark-integration.test.js +41 -0
- package/packages/core/dist/benchmark/benchmark-integration.test.js.map +1 -0
- package/packages/core/dist/benchmark/index.d.ts +3 -0
- package/packages/core/dist/benchmark/index.d.ts.map +1 -0
- package/packages/core/dist/benchmark/index.js +5 -0
- package/packages/core/dist/benchmark/index.js.map +1 -0
- package/packages/core/dist/benchmark/job-fair-aggregator.d.ts +150 -0
- package/packages/core/dist/benchmark/job-fair-aggregator.d.ts.map +1 -0
- package/packages/core/dist/benchmark/job-fair-aggregator.js +547 -0
- package/packages/core/dist/benchmark/job-fair-aggregator.js.map +1 -0
- package/packages/core/dist/benchmark/job-fair-aggregator.test.d.ts +6 -0
- package/packages/core/dist/benchmark/job-fair-aggregator.test.d.ts.map +1 -0
- package/packages/core/dist/benchmark/job-fair-aggregator.test.js +35 -0
- package/packages/core/dist/benchmark/job-fair-aggregator.test.js.map +1 -0
- package/packages/core/dist/cli/commands/hook-chaining.test.d.ts +17 -0
- package/packages/core/dist/cli/commands/hook-chaining.test.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/hook-chaining.test.js +386 -0
- package/packages/core/dist/cli/commands/hook-chaining.test.js.map +1 -0
- package/packages/core/dist/cli/commands/init.d.ts +6 -1
- package/packages/core/dist/cli/commands/init.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/init.js +83 -30
- package/packages/core/dist/cli/commands/init.js.map +1 -1
- package/packages/core/dist/cli/commands/uninstall.d.ts.map +1 -1
- package/packages/core/dist/cli/commands/uninstall.js +20 -3
- package/packages/core/dist/cli/commands/uninstall.js.map +1 -1
- package/packages/core/dist/cli/commands/uninstall.test.d.ts +8 -0
- package/packages/core/dist/cli/commands/uninstall.test.d.ts.map +1 -0
- package/packages/core/dist/cli/commands/uninstall.test.js +120 -0
- package/packages/core/dist/cli/commands/uninstall.test.js.map +1 -0
- package/packages/core/dist/cli/commands/update.js +4 -4
- package/packages/core/dist/cli/commands/update.js.map +1 -1
- package/packages/core/dist/cli/cyclist-migration.test.js +2 -1
- package/packages/core/dist/cli/cyclist-migration.test.js.map +1 -1
- package/packages/core/dist/cli/ocean-profiles.test.js +5 -4
- package/packages/core/dist/cli/ocean-profiles.test.js.map +1 -1
- package/packages/core/dist/cli/theme-maker.test.js +5 -4
- package/packages/core/dist/cli/theme-maker.test.js.map +1 -1
- package/packages/core/dist/cli/utils/008-sprint-shard-migration.test.d.ts +15 -0
- package/packages/core/dist/cli/utils/008-sprint-shard-migration.test.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/008-sprint-shard-migration.test.js +295 -0
- package/packages/core/dist/cli/utils/008-sprint-shard-migration.test.js.map +1 -0
- package/packages/core/dist/cli/utils/settings-consolidation.test.js +26 -0
- package/packages/core/dist/cli/utils/settings-consolidation.test.js.map +1 -1
- package/packages/core/dist/cli/utils/settings-merge.d.ts +128 -0
- package/packages/core/dist/cli/utils/settings-merge.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/settings-merge.js +303 -0
- package/packages/core/dist/cli/utils/settings-merge.js.map +1 -0
- package/packages/core/dist/cli/utils/settings-merge.test.d.ts +15 -0
- package/packages/core/dist/cli/utils/settings-merge.test.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/settings-merge.test.js +781 -0
- package/packages/core/dist/cli/utils/settings-merge.test.js.map +1 -0
- package/packages/core/dist/cli/utils/settings.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/settings.js +3 -0
- package/packages/core/dist/cli/utils/settings.js.map +1 -1
- package/packages/core/dist/cli/utils/symlinks.d.ts +6 -16
- package/packages/core/dist/cli/utils/symlinks.d.ts.map +1 -1
- package/packages/core/dist/cli/utils/symlinks.js +100 -171
- package/packages/core/dist/cli/utils/symlinks.js.map +1 -1
- package/packages/core/dist/cli/utils/symlinks.test.d.ts +10 -0
- package/packages/core/dist/cli/utils/symlinks.test.d.ts.map +1 -0
- package/packages/core/dist/cli/utils/symlinks.test.js +266 -0
- package/packages/core/dist/cli/utils/symlinks.test.js.map +1 -0
- package/packages/core/dist/cli/utils/themes.js +1 -1
- package/packages/core/dist/cli/workspace.test.js +2 -5
- package/packages/core/dist/cli/workspace.test.js.map +1 -1
- package/packages/core/dist/consolidation.test.d.ts +11 -0
- package/packages/core/dist/consolidation.test.d.ts.map +1 -0
- package/packages/core/dist/consolidation.test.js +249 -0
- package/packages/core/dist/consolidation.test.js.map +1 -0
- package/packages/core/dist/index.d.ts +2 -0
- package/packages/core/dist/index.d.ts.map +1 -1
- package/packages/core/dist/index.js +4 -0
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/plugins/plugin-discovery.js +1 -1
- package/packages/core/dist/plugins/plugin-discovery.js.map +1 -1
- package/packages/core/dist/plugins/plugin-discovery.test.d.ts +1 -1
- package/packages/core/dist/plugins/plugin-discovery.test.js +47 -36
- package/packages/core/dist/plugins/plugin-discovery.test.js.map +1 -1
- package/packages/core/dist/public/css/react.css +1 -0
- package/packages/core/dist/public/js/react/react.js +82 -0
- package/packages/core/dist/scripts/generate-report.test.js +2 -2
- package/packages/core/dist/scripts/generate-spider-report.test.js +2 -2
- package/packages/core/dist/scripts/generate-spider.test.js +2 -1
- package/packages/core/dist/scripts/generate-spider.test.js.map +1 -1
- package/packages/core/dist/server/agent-context.d.ts +5 -0
- package/packages/core/dist/server/agent-context.d.ts.map +1 -0
- package/packages/core/dist/server/agent-context.js +5 -0
- package/packages/core/dist/server/agent-context.js.map +1 -0
- package/packages/core/dist/server/agent-evaluation.d.ts +17 -0
- package/packages/core/dist/server/agent-evaluation.d.ts.map +1 -0
- package/packages/core/dist/server/agent-evaluation.js +15 -0
- package/packages/core/dist/server/agent-evaluation.js.map +1 -0
- package/packages/core/dist/server/api/agent-load.d.ts +3 -0
- package/packages/core/dist/server/api/agent-load.d.ts.map +1 -0
- package/packages/core/dist/server/api/agent-load.js +19 -0
- package/packages/core/dist/server/api/agent-load.js.map +1 -0
- package/packages/core/dist/server/api/audit-log.d.ts +3 -0
- package/packages/core/dist/server/api/audit-log.d.ts.map +1 -0
- package/packages/core/dist/server/api/audit-log.js +31 -0
- package/packages/core/dist/server/api/audit-log.js.map +1 -0
- package/packages/core/dist/server/api/background-tasks.d.ts +27 -0
- package/packages/core/dist/server/api/background-tasks.d.ts.map +1 -0
- package/packages/core/dist/server/api/background-tasks.js +56 -0
- package/packages/core/dist/server/api/background-tasks.js.map +1 -0
- package/packages/core/dist/server/api/bell.d.ts +19 -0
- package/packages/core/dist/server/api/bell.d.ts.map +1 -0
- package/packages/core/dist/server/api/bell.js +34 -0
- package/packages/core/dist/server/api/bell.js.map +1 -0
- package/packages/core/dist/server/api/code-markers.d.ts +9 -0
- package/packages/core/dist/server/api/code-markers.d.ts.map +1 -0
- package/packages/core/dist/server/api/code-markers.js +62 -0
- package/packages/core/dist/server/api/code-markers.js.map +1 -0
- package/packages/core/dist/server/api/complexity.d.ts +3 -0
- package/packages/core/dist/server/api/complexity.d.ts.map +1 -0
- package/packages/core/dist/server/api/complexity.js +47 -0
- package/packages/core/dist/server/api/complexity.js.map +1 -0
- package/packages/core/dist/server/api/context.d.ts +38 -0
- package/packages/core/dist/server/api/context.d.ts.map +1 -0
- package/packages/core/dist/server/api/context.js +144 -0
- package/packages/core/dist/server/api/context.js.map +1 -0
- package/packages/core/dist/server/api/dead-code.d.ts +3 -0
- package/packages/core/dist/server/api/dead-code.d.ts.map +1 -0
- package/packages/core/dist/server/api/dead-code.js +70 -0
- package/packages/core/dist/server/api/dead-code.js.map +1 -0
- package/packages/core/dist/server/api/dependencies.d.ts +3 -0
- package/packages/core/dist/server/api/dependencies.d.ts.map +1 -0
- package/packages/core/dist/server/api/dependencies.js +43 -0
- package/packages/core/dist/server/api/dependencies.js.map +1 -0
- package/packages/core/dist/server/api/evaluation.d.ts +3 -0
- package/packages/core/dist/server/api/evaluation.d.ts.map +1 -0
- package/packages/core/dist/server/api/evaluation.js +33 -0
- package/packages/core/dist/server/api/evaluation.js.map +1 -0
- package/packages/core/dist/server/api/file-browser.d.ts +9 -0
- package/packages/core/dist/server/api/file-browser.d.ts.map +1 -0
- package/packages/core/dist/server/api/file-browser.js +133 -0
- package/packages/core/dist/server/api/file-browser.js.map +1 -0
- package/packages/core/dist/server/api/git-fetch-cooldown.test.d.ts +10 -0
- package/packages/core/dist/server/api/git-fetch-cooldown.test.d.ts.map +1 -0
- package/packages/core/dist/server/api/git-fetch-cooldown.test.js +30 -0
- package/packages/core/dist/server/api/git-fetch-cooldown.test.js.map +1 -0
- package/packages/core/dist/server/api/git.d.ts +55 -0
- package/packages/core/dist/server/api/git.d.ts.map +1 -0
- package/packages/core/dist/server/api/git.js +382 -0
- package/packages/core/dist/server/api/git.js.map +1 -0
- package/packages/core/dist/server/api/health-score.d.ts +3 -0
- package/packages/core/dist/server/api/health-score.d.ts.map +1 -0
- package/packages/core/dist/server/api/health-score.js +47 -0
- package/packages/core/dist/server/api/health-score.js.map +1 -0
- package/packages/core/dist/server/api/hook-request.d.ts +41 -0
- package/packages/core/dist/server/api/hook-request.d.ts.map +1 -0
- package/packages/core/dist/server/api/hook-request.js +278 -0
- package/packages/core/dist/server/api/hook-request.js.map +1 -0
- package/packages/core/dist/server/api/hotspots.d.ts +3 -0
- package/packages/core/dist/server/api/hotspots.d.ts.map +1 -0
- package/packages/core/dist/server/api/hotspots.js +62 -0
- package/packages/core/dist/server/api/hotspots.js.map +1 -0
- package/packages/core/dist/server/api/identity.d.ts +17 -0
- package/packages/core/dist/server/api/identity.d.ts.map +1 -0
- package/packages/core/dist/server/api/identity.js +79 -0
- package/packages/core/dist/server/api/identity.js.map +1 -0
- package/packages/core/dist/server/api/index.d.ts +36 -0
- package/packages/core/dist/server/api/index.d.ts.map +1 -0
- package/packages/core/dist/server/api/index.js +47 -0
- package/packages/core/dist/server/api/index.js.map +1 -0
- package/packages/core/dist/server/api/mode.d.ts +24 -0
- package/packages/core/dist/server/api/mode.d.ts.map +1 -0
- package/packages/core/dist/server/api/mode.js +40 -0
- package/packages/core/dist/server/api/mode.js.map +1 -0
- package/packages/core/dist/server/api/otlp.d.ts +3 -0
- package/packages/core/dist/server/api/otlp.d.ts.map +1 -0
- package/packages/core/dist/server/api/otlp.js +40 -0
- package/packages/core/dist/server/api/otlp.js.map +1 -0
- package/packages/core/dist/server/api/permissions.d.ts +16 -0
- package/packages/core/dist/server/api/permissions.d.ts.map +1 -0
- package/packages/core/dist/server/api/permissions.js +67 -0
- package/packages/core/dist/server/api/permissions.js.map +1 -0
- package/packages/core/dist/server/api/persona.d.ts +9 -0
- package/packages/core/dist/server/api/persona.d.ts.map +1 -0
- package/packages/core/dist/server/api/persona.js +68 -0
- package/packages/core/dist/server/api/persona.js.map +1 -0
- package/packages/core/dist/server/api/portrait.d.ts +6 -0
- package/packages/core/dist/server/api/portrait.d.ts.map +1 -0
- package/packages/core/dist/server/api/portrait.js +28 -0
- package/packages/core/dist/server/api/portrait.js.map +1 -0
- package/packages/core/dist/server/api/settings.d.ts +14 -0
- package/packages/core/dist/server/api/settings.d.ts.map +1 -0
- package/packages/core/dist/server/api/settings.js +68 -0
- package/packages/core/dist/server/api/settings.js.map +1 -0
- package/packages/core/dist/server/api/spans.d.ts +3 -0
- package/packages/core/dist/server/api/spans.d.ts.map +1 -0
- package/packages/core/dist/server/api/spans.js +33 -0
- package/packages/core/dist/server/api/spans.js.map +1 -0
- package/packages/core/dist/server/api/stats.d.ts +13 -0
- package/packages/core/dist/server/api/stats.d.ts.map +1 -0
- package/packages/core/dist/server/api/stats.js +85 -0
- package/packages/core/dist/server/api/stats.js.map +1 -0
- package/packages/core/dist/server/api/story.d.ts +3 -0
- package/packages/core/dist/server/api/story.d.ts.map +1 -0
- package/packages/core/dist/server/api/story.js +15 -0
- package/packages/core/dist/server/api/story.js.map +1 -0
- package/packages/core/dist/server/api/telemetry.d.ts +3 -0
- package/packages/core/dist/server/api/telemetry.d.ts.map +1 -0
- package/packages/core/dist/server/api/telemetry.js +30 -0
- package/packages/core/dist/server/api/telemetry.js.map +1 -0
- package/packages/core/dist/server/api/theme-agents.d.ts +10 -0
- package/packages/core/dist/server/api/theme-agents.d.ts.map +1 -0
- package/packages/core/dist/server/api/theme-agents.js +39 -0
- package/packages/core/dist/server/api/theme-agents.js.map +1 -0
- package/packages/core/dist/server/api/todos.d.ts +33 -0
- package/packages/core/dist/server/api/todos.d.ts.map +1 -0
- package/packages/core/dist/server/api/todos.js +44 -0
- package/packages/core/dist/server/api/todos.js.map +1 -0
- package/packages/core/dist/server/api/token-stats.d.ts +8 -0
- package/packages/core/dist/server/api/token-stats.d.ts.map +1 -0
- package/packages/core/dist/server/api/token-stats.js +36 -0
- package/packages/core/dist/server/api/token-stats.js.map +1 -0
- package/packages/core/dist/server/api/welcome.d.ts +22 -0
- package/packages/core/dist/server/api/welcome.d.ts.map +1 -0
- package/packages/core/dist/server/api/welcome.js +35 -0
- package/packages/core/dist/server/api/welcome.js.map +1 -0
- package/packages/core/dist/server/bell-mode.d.ts +7 -0
- package/packages/core/dist/server/bell-mode.d.ts.map +1 -0
- package/packages/core/dist/server/bell-mode.js +7 -0
- package/packages/core/dist/server/bell-mode.js.map +1 -0
- package/packages/core/dist/server/dangerous-path.d.ts +36 -0
- package/packages/core/dist/server/dangerous-path.d.ts.map +1 -0
- package/packages/core/dist/server/dangerous-path.js +159 -0
- package/packages/core/dist/server/dangerous-path.js.map +1 -0
- package/packages/core/dist/server/enriched-span-exporter.d.ts +17 -0
- package/packages/core/dist/server/enriched-span-exporter.d.ts.map +1 -0
- package/packages/core/dist/server/enriched-span-exporter.js +12 -0
- package/packages/core/dist/server/enriched-span-exporter.js.map +1 -0
- package/packages/core/dist/server/env.d.ts +6 -0
- package/packages/core/dist/server/env.d.ts.map +1 -0
- package/packages/core/dist/server/env.js +10 -0
- package/packages/core/dist/server/env.js.map +1 -0
- package/packages/core/dist/server/file-browser.d.ts +17 -0
- package/packages/core/dist/server/file-browser.d.ts.map +1 -0
- package/packages/core/dist/server/file-browser.js +11 -0
- package/packages/core/dist/server/file-browser.js.map +1 -0
- package/packages/core/dist/server/otlp-receiver.d.ts +87 -0
- package/packages/core/dist/server/otlp-receiver.d.ts.map +1 -0
- package/packages/core/dist/server/otlp-receiver.js +106 -0
- package/packages/core/dist/server/otlp-receiver.js.map +1 -0
- package/packages/core/dist/server/parser.d.ts +11 -0
- package/packages/core/dist/server/parser.d.ts.map +1 -0
- package/packages/core/dist/server/parser.js +6 -0
- package/packages/core/dist/server/parser.js.map +1 -0
- package/packages/core/dist/server/paths.d.ts +37 -0
- package/packages/core/dist/server/paths.d.ts.map +1 -0
- package/packages/core/dist/server/paths.js +227 -0
- package/packages/core/dist/server/paths.js.map +1 -0
- package/packages/core/dist/server/pennyfarthing.d.ts +56 -0
- package/packages/core/dist/server/pennyfarthing.d.ts.map +1 -0
- package/packages/core/dist/server/pennyfarthing.js +356 -0
- package/packages/core/dist/server/pennyfarthing.js.map +1 -0
- package/packages/core/dist/server/plugin-loader.d.ts +22 -0
- package/packages/core/dist/server/plugin-loader.d.ts.map +1 -0
- package/packages/core/dist/server/plugin-loader.js +67 -0
- package/packages/core/dist/server/plugin-loader.js.map +1 -0
- package/packages/core/dist/server/prime.d.ts +12 -0
- package/packages/core/dist/server/prime.d.ts.map +1 -0
- package/packages/core/dist/server/prime.js +8 -0
- package/packages/core/dist/server/prime.js.map +1 -0
- package/packages/core/dist/server/server.d.ts +47 -0
- package/packages/core/dist/server/server.d.ts.map +1 -0
- package/packages/core/dist/server/server.js +353 -0
- package/packages/core/dist/server/server.js.map +1 -0
- package/packages/core/dist/server/server.test.d.ts +26 -0
- package/packages/core/dist/server/server.test.d.ts.map +1 -0
- package/packages/core/dist/server/server.test.js +447 -0
- package/packages/core/dist/server/server.test.js.map +1 -0
- package/packages/core/dist/server/settings-store.d.ts +195 -0
- package/packages/core/dist/server/settings-store.d.ts.map +1 -0
- package/packages/core/dist/server/settings-store.js +398 -0
- package/packages/core/dist/server/settings-store.js.map +1 -0
- package/packages/core/dist/server/settings.d.ts +136 -0
- package/packages/core/dist/server/settings.d.ts.map +1 -0
- package/packages/core/dist/server/settings.js +417 -0
- package/packages/core/dist/server/settings.js.map +1 -0
- package/packages/core/dist/server/span-hierarchy.d.ts +5 -0
- package/packages/core/dist/server/span-hierarchy.d.ts.map +1 -0
- package/packages/core/dist/server/span-hierarchy.js +5 -0
- package/packages/core/dist/server/span-hierarchy.js.map +1 -0
- package/packages/core/dist/server/story-context.d.ts +5 -0
- package/packages/core/dist/server/story-context.d.ts.map +1 -0
- package/packages/core/dist/server/story-context.js +5 -0
- package/packages/core/dist/server/story-context.js.map +1 -0
- package/packages/core/dist/server/story-parser.d.ts +74 -0
- package/packages/core/dist/server/story-parser.d.ts.map +1 -0
- package/packages/core/dist/server/story-parser.js +748 -0
- package/packages/core/dist/server/story-parser.js.map +1 -0
- package/packages/core/dist/server/tdd-metrics.d.ts +5 -0
- package/packages/core/dist/server/tdd-metrics.d.ts.map +1 -0
- package/packages/core/dist/server/tdd-metrics.js +5 -0
- package/packages/core/dist/server/tdd-metrics.js.map +1 -0
- package/packages/core/dist/server/ui-build.test.d.ts +19 -0
- package/packages/core/dist/server/ui-build.test.d.ts.map +1 -0
- package/packages/core/dist/server/ui-build.test.js +152 -0
- package/packages/core/dist/server/ui-build.test.js.map +1 -0
- package/packages/core/dist/server/websocket.d.ts +7 -0
- package/packages/core/dist/server/websocket.d.ts.map +1 -0
- package/packages/core/dist/server/websocket.js +8 -0
- package/packages/core/dist/server/websocket.js.map +1 -0
- package/packages/core/dist/shared/browser.d.ts +6 -0
- package/packages/core/dist/shared/browser.d.ts.map +1 -0
- package/packages/core/dist/shared/browser.js +8 -0
- package/packages/core/dist/shared/browser.js.map +1 -0
- package/packages/core/dist/shared/generate-skill-docs.d.ts +35 -0
- package/packages/core/dist/shared/generate-skill-docs.d.ts.map +1 -0
- package/packages/core/dist/shared/generate-skill-docs.js +442 -0
- package/packages/core/dist/shared/generate-skill-docs.js.map +1 -0
- package/packages/core/dist/shared/generate-skill-docs.test.d.ts +13 -0
- package/packages/core/dist/shared/generate-skill-docs.test.d.ts.map +1 -0
- package/packages/core/dist/shared/generate-skill-docs.test.js +519 -0
- package/packages/core/dist/shared/generate-skill-docs.test.js.map +1 -0
- package/packages/core/dist/shared/index.d.ts +11 -0
- package/packages/core/dist/shared/index.d.ts.map +1 -0
- package/packages/core/dist/shared/index.js +13 -0
- package/packages/core/dist/shared/index.js.map +1 -0
- package/packages/core/dist/shared/marker/constants.d.ts +39 -0
- package/packages/core/dist/shared/marker/constants.d.ts.map +1 -0
- package/packages/core/dist/shared/marker/constants.js +46 -0
- package/packages/core/dist/shared/marker/constants.js.map +1 -0
- package/packages/core/dist/shared/marker/continue.test.d.ts +12 -0
- package/packages/core/dist/shared/marker/continue.test.d.ts.map +1 -0
- package/packages/core/dist/shared/marker/continue.test.js +76 -0
- package/packages/core/dist/shared/marker/continue.test.js.map +1 -0
- package/packages/core/dist/shared/marker/detect.d.ts +25 -0
- package/packages/core/dist/shared/marker/detect.d.ts.map +1 -0
- package/packages/core/dist/shared/marker/detect.js +53 -0
- package/packages/core/dist/shared/marker/detect.js.map +1 -0
- package/packages/core/dist/shared/marker/detect.test.d.ts +10 -0
- package/packages/core/dist/shared/marker/detect.test.d.ts.map +1 -0
- package/packages/core/dist/shared/marker/detect.test.js +418 -0
- package/packages/core/dist/shared/marker/detect.test.js.map +1 -0
- package/packages/core/dist/shared/marker/index.d.ts +14 -0
- package/packages/core/dist/shared/marker/index.d.ts.map +1 -0
- package/packages/core/dist/shared/marker/index.js +15 -0
- package/packages/core/dist/shared/marker/index.js.map +1 -0
- package/packages/core/dist/shared/marker/strip.d.ts +26 -0
- package/packages/core/dist/shared/marker/strip.d.ts.map +1 -0
- package/packages/core/dist/shared/marker/strip.js +39 -0
- package/packages/core/dist/shared/marker/strip.js.map +1 -0
- package/packages/core/dist/shared/marker/types.d.ts +23 -0
- package/packages/core/dist/shared/marker/types.d.ts.map +1 -0
- package/packages/core/dist/shared/marker/types.js +7 -0
- package/packages/core/dist/shared/marker/types.js.map +1 -0
- package/packages/core/dist/shared/migrate-theme-schema.test.d.ts +8 -0
- package/packages/core/dist/shared/migrate-theme-schema.test.d.ts.map +1 -0
- package/packages/core/dist/shared/migrate-theme-schema.test.js +100 -0
- package/packages/core/dist/shared/migrate-theme-schema.test.js.map +1 -0
- package/packages/core/dist/shared/portrait-resolver.d.ts +35 -0
- package/packages/core/dist/shared/portrait-resolver.d.ts.map +1 -0
- package/packages/core/dist/shared/portrait-resolver.js +259 -0
- package/packages/core/dist/shared/portrait-resolver.js.map +1 -0
- package/packages/core/dist/shared/portrait-resolver.test.d.ts +2 -0
- package/packages/core/dist/shared/portrait-resolver.test.d.ts.map +1 -0
- package/packages/core/dist/shared/portrait-resolver.test.js +157 -0
- package/packages/core/dist/shared/portrait-resolver.test.js.map +1 -0
- package/packages/core/dist/shared/repos-topology.d.ts +49 -0
- package/packages/core/dist/shared/repos-topology.d.ts.map +1 -0
- package/packages/core/dist/shared/repos-topology.js +101 -0
- package/packages/core/dist/shared/repos-topology.js.map +1 -0
- package/packages/core/dist/shared/repos-topology.test.d.ts +8 -0
- package/packages/core/dist/shared/repos-topology.test.d.ts.map +1 -0
- package/packages/core/dist/shared/repos-topology.test.js +250 -0
- package/packages/core/dist/shared/repos-topology.test.js.map +1 -0
- package/packages/core/dist/shared/skill-search.d.ts +36 -0
- package/packages/core/dist/shared/skill-search.d.ts.map +1 -0
- package/packages/core/dist/shared/skill-search.js +300 -0
- package/packages/core/dist/shared/skill-search.js.map +1 -0
- package/packages/core/dist/shared/skill-search.test.d.ts +16 -0
- package/packages/core/dist/shared/skill-search.test.d.ts.map +1 -0
- package/packages/core/dist/shared/skill-search.test.js +177 -0
- package/packages/core/dist/shared/skill-search.test.js.map +1 -0
- package/packages/core/dist/shared/skill-suggest.d.ts +76 -0
- package/packages/core/dist/shared/skill-suggest.d.ts.map +1 -0
- package/packages/core/dist/shared/skill-suggest.js +256 -0
- package/packages/core/dist/shared/skill-suggest.js.map +1 -0
- package/packages/core/dist/shared/skill-suggest.test.d.ts +12 -0
- package/packages/core/dist/shared/skill-suggest.test.d.ts.map +1 -0
- package/packages/core/dist/shared/skill-suggest.test.js +257 -0
- package/packages/core/dist/shared/skill-suggest.test.js.map +1 -0
- package/packages/core/dist/shared/theme-loader.d.ts +81 -0
- package/packages/core/dist/shared/theme-loader.d.ts.map +1 -0
- package/packages/core/dist/shared/theme-loader.js +491 -0
- package/packages/core/dist/shared/theme-loader.js.map +1 -0
- package/packages/core/dist/shared/theme-loader.test.d.ts +8 -0
- package/packages/core/dist/shared/theme-loader.test.d.ts.map +1 -0
- package/packages/core/dist/shared/theme-loader.test.js +62 -0
- package/packages/core/dist/shared/theme-loader.test.js.map +1 -0
- package/packages/core/dist/workflow/context-watch.test.js +1 -1
- package/packages/core/dist/workflow/context-watch.test.js.map +1 -1
- package/packages/core/dist/workflow/variable-resolver.test.js +1 -1
- package/packages/core/dist/workflow/variable-resolver.test.js.map +1 -1
- package/packages/core/dist/workflow/workflow-migration.test.js +4 -3
- package/packages/core/dist/workflow/workflow-migration.test.js.map +1 -1
- package/pennyfarthing-dist/agents/architect.md +1 -2
- package/pennyfarthing-dist/agents/ba.md +1 -1
- package/pennyfarthing-dist/agents/dev.md +2 -3
- package/pennyfarthing-dist/agents/devops.md +1 -1
- package/pennyfarthing-dist/agents/orchestrator.md +2 -3
- package/pennyfarthing-dist/agents/pm.md +2 -2
- package/pennyfarthing-dist/agents/reviewer.md +2 -2
- package/pennyfarthing-dist/agents/sm-setup.md +7 -7
- package/pennyfarthing-dist/agents/sm.md +19 -18
- package/pennyfarthing-dist/agents/tea.md +3 -2
- package/pennyfarthing-dist/agents/tech-writer.md +1 -1
- package/pennyfarthing-dist/agents/ux-designer.md +0 -1
- package/pennyfarthing-dist/commands/benchmark-control.md +69 -0
- package/pennyfarthing-dist/commands/benchmark.md +485 -0
- package/pennyfarthing-dist/commands/job-fair.md +102 -0
- package/pennyfarthing-dist/commands/{close-epic.md → pf-close-epic.md} +1 -1
- package/pennyfarthing-dist/commands/{new-work.md → pf-new-work.md} +4 -4
- package/pennyfarthing-dist/commands/{party-mode.md → pf-party-mode.md} +15 -2
- package/pennyfarthing-dist/commands/{patch.md → pf-patch.md} +3 -3
- package/pennyfarthing-dist/commands/{release.md → pf-release.md} +17 -10
- package/pennyfarthing-dist/commands/{setup.md → pf-setup.md} +2 -2
- package/pennyfarthing-dist/commands/{sprint.md → pf-sprint.md} +19 -19
- package/pennyfarthing-dist/commands/{standalone.md → pf-standalone.md} +2 -2
- package/pennyfarthing-dist/commands/{workflow.md → pf-workflow.md} +7 -7
- package/pennyfarthing-dist/commands/solo.md +447 -0
- package/pennyfarthing-dist/guides/agent-behavior.md +2 -2
- package/pennyfarthing-dist/guides/agent-tag-taxonomy.md +1 -2
- package/pennyfarthing-dist/guides/agent-template-strategic.md +1 -1
- package/pennyfarthing-dist/guides/agent-template-tactical.md +2 -2
- package/pennyfarthing-dist/guides/bikelane.md +6 -6
- package/pennyfarthing-dist/guides/permission-protocol.md +1 -1
- package/pennyfarthing-dist/guides/scale-levels.md +2 -2
- package/pennyfarthing-dist/guides/skill-schema.md +9 -9
- package/pennyfarthing-dist/guides/xml-tags.md +2 -2
- package/pennyfarthing-dist/personas/themes/dune.yaml +0 -1
- package/pennyfarthing-dist/personas/themes/hogans-heroes.yaml +260 -0
- package/pennyfarthing-dist/personas/themes/monty-python.yaml +312 -0
- package/pennyfarthing-dist/personas/themes/stephen-king.yaml +260 -0
- package/pennyfarthing-dist/scripts/core/agent-session.sh +0 -0
- package/pennyfarthing-dist/scripts/core/check-context.sh +0 -0
- package/pennyfarthing-dist/scripts/core/handoff-marker.sh +0 -0
- package/pennyfarthing-dist/scripts/core/phase-check-start.sh +0 -0
- package/pennyfarthing-dist/scripts/core/prime.sh +0 -0
- package/pennyfarthing-dist/scripts/cyclist/is-cyclist.sh +0 -0
- package/pennyfarthing-dist/scripts/git/create-feature-branches.sh +0 -0
- package/pennyfarthing-dist/scripts/git/git-status-all.sh +0 -0
- package/pennyfarthing-dist/scripts/git/install-git-hooks.sh +84 -21
- package/pennyfarthing-dist/scripts/git/release.sh +0 -0
- package/pennyfarthing-dist/scripts/git/worktree-manager.sh +0 -0
- package/pennyfarthing-dist/scripts/health/drift-detection.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/bell-mode-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-circuit-breaker.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/context-warning.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/dispatcher-template.sh +45 -0
- package/pennyfarthing-dist/scripts/hooks/otel-auto-config.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/post-merge.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-commit.sh +27 -2
- package/pennyfarthing-dist/scripts/hooks/pre-edit-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/pre-push.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/question-reflector-check.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/question_reflector_check.py +0 -0
- package/pennyfarthing-dist/scripts/hooks/schema-validation.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/session-start.sh +25 -89
- package/pennyfarthing-dist/scripts/hooks/session-stop.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/sprint-yaml-validation.sh +0 -0
- package/pennyfarthing-dist/scripts/hooks/welcome-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/README.md +1 -1
- package/pennyfarthing-dist/scripts/jira/create-jira-epic.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/create-jira-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-claim-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-reconcile.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/jira-sync-story.sh +0 -0
- package/pennyfarthing-dist/scripts/jira/sync-epic-jira.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/background-tasks.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/common.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/file-lock.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/logging.sh +0 -0
- package/pennyfarthing-dist/scripts/lib/retry.sh +0 -0
- package/pennyfarthing-dist/scripts/maintenance/migrate-theme-schema.mjs +0 -0
- package/pennyfarthing-dist/scripts/maintenance/sidecar-health.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/add-short-names.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/add_short_names.py +0 -0
- package/pennyfarthing-dist/scripts/misc/backlog.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/check-status.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/find-related-work.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/generate-skill-docs.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/log-skill-usage.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate-bmad-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/migrate_bmad_workflow.py +0 -0
- package/pennyfarthing-dist/scripts/misc/repo-scan.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/repo-utils.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/run-ci.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/run-timestamp.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/session-cleanup.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/skill-usage-report.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/statusline.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/uninstall.sh +0 -0
- package/pennyfarthing-dist/scripts/misc/validate-subagent-frontmatter.sh +0 -0
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.py +50 -26
- package/pennyfarthing-dist/scripts/portraits/generate-portraits.sh +18 -6
- package/pennyfarthing-dist/scripts/sprint/README.md +1 -1
- package/pennyfarthing-dist/scripts/story/README.md +1 -1
- package/pennyfarthing-dist/scripts/story/create-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/size-story.sh +0 -0
- package/pennyfarthing-dist/scripts/story/story-template.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/check.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/dev-story-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/epics-and-stories-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/handoff-phase-update.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/implementation-readiness-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/migrate-bmad-workflow.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/prd-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/project-context-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-character-voice.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-drift-detection.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-post-merge-hook.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-session-checkpoint.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/test-solo-command.sh +0 -0
- package/pennyfarthing-dist/scripts/tests/ux-design-workflow-import.test.sh +0 -0
- package/pennyfarthing-dist/scripts/theme/list-themes.sh +0 -0
- package/pennyfarthing-dist/scripts/validation/validate-agent-schema.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/README.md +1 -1
- package/pennyfarthing-dist/scripts/workflow/check.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/check.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/complete-step.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/finish-story.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/fix-session-phase.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.py +0 -0
- package/pennyfarthing-dist/scripts/workflow/get-workflow-type.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/list-workflows.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/phase-owner.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/resume-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/show-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/start-workflow.sh +0 -0
- package/pennyfarthing-dist/scripts/workflow/workflow-status.sh +0 -0
- package/pennyfarthing-dist/skills/pf-bc/examples.md +83 -0
- package/pennyfarthing-dist/skills/pf-bc/skill.md +51 -0
- package/pennyfarthing-dist/skills/pf-bc/usage.md +113 -0
- package/pennyfarthing-dist/skills/{cyclist → pf-cyclist}/SKILL.md +5 -5
- package/pennyfarthing-dist/skills/pf-finalize-run/SKILL.md +261 -0
- package/pennyfarthing-dist/skills/pf-jira/SKILL.md +61 -0
- package/pennyfarthing-dist/skills/pf-jira/examples.md +163 -0
- package/pennyfarthing-dist/skills/pf-jira/usage.md +213 -0
- package/pennyfarthing-dist/skills/pf-judge/SKILL.md +644 -0
- package/pennyfarthing-dist/skills/{just → pf-just}/SKILL.md +23 -23
- package/pennyfarthing-dist/skills/{permissions → pf-permissions}/skill.md +8 -8
- package/pennyfarthing-dist/skills/pf-persona-benchmark/SKILL.md +187 -0
- package/pennyfarthing-dist/skills/pf-sprint/examples.md +189 -0
- package/pennyfarthing-dist/skills/pf-sprint/skill.md +85 -0
- package/pennyfarthing-dist/skills/pf-sprint/usage.md +293 -0
- package/pennyfarthing-dist/skills/{story → pf-story}/scripts/create-story.sh +0 -0
- package/pennyfarthing-dist/skills/{story → pf-story}/scripts/size-story.sh +0 -0
- package/pennyfarthing-dist/skills/{story → pf-story}/scripts/story-template.sh +0 -0
- package/pennyfarthing-dist/skills/pf-story/skill.md +27 -0
- package/pennyfarthing-dist/skills/{systematic-debugging → pf-systematic-debugging}/SKILL.md +5 -6
- package/pennyfarthing-dist/skills/pf-theme/examples.md +92 -0
- package/pennyfarthing-dist/skills/pf-theme/skill.md +42 -0
- package/pennyfarthing-dist/skills/pf-theme/usage.md +149 -0
- package/pennyfarthing-dist/skills/pf-workflow/examples.md +101 -0
- package/pennyfarthing-dist/skills/{workflow → pf-workflow}/scripts/list-workflows.sh +0 -0
- package/pennyfarthing-dist/skills/{workflow → pf-workflow}/scripts/resume-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/{workflow → pf-workflow}/scripts/show-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/{workflow → pf-workflow}/scripts/start-workflow.sh +0 -0
- package/pennyfarthing-dist/skills/{workflow → pf-workflow}/scripts/workflow-status.sh +0 -0
- package/pennyfarthing-dist/skills/pf-workflow/skill.md +49 -0
- package/pennyfarthing-dist/skills/pf-workflow/usage.md +145 -0
- package/pennyfarthing-dist/skills/skill-registry.yaml +63 -81
- package/pennyfarthing-dist/workflows/architecture/data/domain-complexity.csv +13 -0
- package/pennyfarthing-dist/workflows/architecture/data/project-types.csv +7 -0
- package/pennyfarthing-dist/workflows/epics-and-stories/steps/step-05-import-to-future.md +40 -11
- package/pennyfarthing-dist/workflows/party-mode-roleplay/steps/step-01-agent-loading.md +99 -0
- package/pennyfarthing-dist/workflows/party-mode-roleplay/steps/step-02-discussion.md +130 -0
- package/pennyfarthing-dist/workflows/party-mode-roleplay/steps/step-03-exit.md +100 -0
- package/pennyfarthing-dist/workflows/party-mode-roleplay/workflow.yaml +62 -0
- package/pennyfarthing-dist/workflows/prd/data/domain-complexity.csv +2 -0
- package/pennyfarthing-dist/workflows/prd/data/prd-purpose.md +2 -0
- package/pennyfarthing-dist/workflows/prd/steps-v/step-v-08-domain-compliance-validation.md +16 -0
- package/pennyfarthing-dist/workflows/project-setup/steps/step-04-claude-md.md +3 -3
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-01-understand.md +193 -0
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-02-investigate.md +148 -0
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-03-generate.md +141 -0
- package/pennyfarthing-dist/workflows/quick-spec/steps/step-04-review.md +192 -0
- package/pennyfarthing-dist/workflows/quick-spec/tech-spec-template.md +74 -0
- package/pennyfarthing-dist/workflows/quick-spec/workflow.yaml +35 -0
- package/pennyfarthing-dist/workflows/release/steps/step-01-preflight.md +42 -3
- package/pennyfarthing-dist/workflows/release/steps/step-02-bump.md +10 -3
- package/pennyfarthing-dist/workflows/release/steps/step-03-changelog.md +1 -1
- package/pennyfarthing-dist/workflows/release/steps/step-07-commit.md +13 -4
- package/pennyfarthing-dist/workflows/release/steps/step-08-merge.md +31 -6
- package/pennyfarthing-dist/workflows/release/steps/step-09-push.md +12 -6
- package/pennyfarthing-dist/workflows/release/steps/step-10-publish.md +30 -5
- package/pennyfarthing-dist/workflows/release/steps/step-11-finalize.md +29 -0
- package/pennyfarthing-dist/workflows/release.yaml +7 -0
- package/pennyfarthing_scripts/CLAUDE.md +182 -0
- package/pennyfarthing_scripts/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/patch_mode.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/__pycache__/session_start_hook.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__init__.py +1 -0
- package/pennyfarthing_scripts/bc/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/__pycache__/focus.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bc/cli.py +223 -0
- package/pennyfarthing_scripts/bc/focus.py +333 -0
- package/pennyfarthing_scripts/bikerack/__init__.py +8 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/background_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/base_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/changed_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/diffs_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/git_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/launcher.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/sprint_panel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/tui.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/__pycache__/ws_client.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/bikerack/background_panel.py +81 -0
- package/pennyfarthing_scripts/bikerack/base_panel.py +100 -0
- package/pennyfarthing_scripts/bikerack/changed_panel.py +105 -0
- package/pennyfarthing_scripts/bikerack/cli.py +22 -24
- package/pennyfarthing_scripts/bikerack/diffs_panel.py +146 -0
- package/pennyfarthing_scripts/bikerack/git_panel.py +69 -0
- package/pennyfarthing_scripts/bikerack/launcher.py +63 -4
- package/pennyfarthing_scripts/bikerack/sprint_panel.py +72 -0
- package/pennyfarthing_scripts/bikerack/tui.py +193 -0
- package/pennyfarthing_scripts/bikerack/ws_client.py +176 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/brownfield/__pycache__/discover.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/cli.py +60 -16
- package/pennyfarthing_scripts/codemarkers/__pycache__/formatters.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/complexity/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/deadcode/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/dependencies/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/create_branches.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/git/__pycache__/status_all.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/__pycache__/analyze.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/healthscore/analyze.py +15 -1
- package/pennyfarthing_scripts/hooks/cyclist-pretooluse-hook.sh +0 -0
- package/pennyfarthing_scripts/jira/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/jira/cli.py +10 -2
- package/pennyfarthing_scripts/launch/__init__.py +1 -0
- package/pennyfarthing_scripts/launch/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/launch/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/launch/cli.py +231 -0
- package/pennyfarthing_scripts/preflight/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/preflight/__pycache__/finish.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/__pycache__/version_sentinel.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/prime/version_sentinel.py +0 -1
- package/pennyfarthing_scripts/session_start_hook.py +192 -0
- package/pennyfarthing_scripts/sprint/__pycache__/__main__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/archive_epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/epic_add.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/epic_update.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/import_epic.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/loader.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_add.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_finish.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/story_update.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/validate_cmd.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/__pycache__/yaml_io.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/sprint/archive_epic.py +109 -1
- package/pennyfarthing_scripts/sprint/cli.py +30 -9
- package/pennyfarthing_scripts/sprint/epic_add.py +7 -1
- package/pennyfarthing_scripts/sprint/epic_update.py +148 -0
- package/pennyfarthing_scripts/sprint/loader.py +33 -0
- package/pennyfarthing_scripts/sprint/story_add.py +11 -1
- package/pennyfarthing_scripts/sprint/story_finish.py +14 -10
- package/pennyfarthing_scripts/sprint/story_update.py +7 -0
- package/pennyfarthing_scripts/sprint/validate_cmd.py +2 -1
- package/pennyfarthing_scripts/sprint/yaml_io.py +64 -6
- package/pennyfarthing_scripts/story/__pycache__/__init__.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/size.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/story/__pycache__/template.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_archive_epic.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_bc.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_bikerack.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_brownfield.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_cli_modules.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_cli_normalization.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_codemarkers.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_common.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_epic_shard_validation.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_git_utils.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_healthscore.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_jira_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_package_structure.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_patch_mode.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_prime.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_panel.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_sprint_validator.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_add.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_package.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_story_update.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tiers.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_token_counting.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_topology_loader.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tui_focus.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_tui_panel_persistence.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_validate_cmd.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_version_sentinel.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_workflow_check.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/__pycache__/test_yaml_io.cpython-314-pytest-9.0.2.pyc +0 -0
- package/pennyfarthing_scripts/tests/test_archive_epic.py +185 -0
- package/pennyfarthing_scripts/tests/test_bc.py +490 -0
- package/pennyfarthing_scripts/tests/test_cli_normalization.py +295 -0
- package/pennyfarthing_scripts/tests/test_sprint_panel.py +531 -0
- package/pennyfarthing_scripts/tests/test_tui_focus.py +411 -0
- package/pennyfarthing_scripts/tests/test_tui_panel_persistence.py +411 -0
- package/pennyfarthing_scripts/tests/test_version_sentinel.py +1 -5
- package/pennyfarthing_scripts/tests/test_yaml_io.py +5 -5
- package/pennyfarthing_scripts/theme/__pycache__/cli.cpython-314.pyc +0 -0
- package/pennyfarthing_scripts/theme/cli.py +25 -2
- package/scripts/README.md +41 -0
- package/packages/core/dist/scripts/benchmark-integration.test.d.ts +0 -13
- package/packages/core/dist/scripts/benchmark-integration.test.d.ts.map +0 -1
- package/packages/core/dist/scripts/benchmark-integration.test.js +0 -680
- package/packages/core/dist/scripts/benchmark-integration.test.js.map +0 -1
- package/packages/core/dist/scripts/debugging-scenarios.test.d.ts +0 -18
- package/packages/core/dist/scripts/debugging-scenarios.test.d.ts.map +0 -1
- package/packages/core/dist/scripts/debugging-scenarios.test.js +0 -317
- package/packages/core/dist/scripts/debugging-scenarios.test.js.map +0 -1
- package/packages/core/dist/scripts/job-fair-aggregator.test.d.ts +0 -14
- package/packages/core/dist/scripts/job-fair-aggregator.test.d.ts.map +0 -1
- package/packages/core/dist/scripts/job-fair-aggregator.test.js +0 -616
- package/packages/core/dist/scripts/job-fair-aggregator.test.js.map +0 -1
- package/packages/core/dist/scripts/theme-detail.test.d.ts +0 -10
- package/packages/core/dist/scripts/theme-detail.test.js +0 -199
- package/pennyfarthing-dist/personas/themes/star-trek-tng.yaml +0 -392
- package/pennyfarthing-dist/skills/dev-patterns/SKILL.md +0 -461
- package/pennyfarthing-dist/skills/jira/SKILL.md +0 -207
- package/pennyfarthing-dist/skills/sprint/skill.md +0 -806
- package/pennyfarthing-dist/skills/story/skill.md +0 -27
- package/pennyfarthing-dist/skills/theme/skill.md +0 -356
- package/pennyfarthing-dist/skills/workflow/skill.md +0 -368
- /package/pennyfarthing-dist/commands/{architect.md → pf-architect.md} +0 -0
- /package/pennyfarthing-dist/commands/{ba.md → pf-ba.md} +0 -0
- /package/pennyfarthing-dist/commands/{brainstorming.md → pf-brainstorming.md} +0 -0
- /package/pennyfarthing-dist/commands/{check.md → pf-check.md} +0 -0
- /package/pennyfarthing-dist/commands/{chore.md → pf-chore.md} +0 -0
- /package/pennyfarthing-dist/commands/{continue-session.md → pf-continue-session.md} +0 -0
- /package/pennyfarthing-dist/commands/{create-branches-from-story.md → pf-create-branches-from-story.md} +0 -0
- /package/pennyfarthing-dist/commands/{create-theme.md → pf-create-theme.md} +0 -0
- /package/pennyfarthing-dist/commands/{dev.md → pf-dev.md} +0 -0
- /package/pennyfarthing-dist/commands/{devops.md → pf-devops.md} +0 -0
- /package/pennyfarthing-dist/commands/{fix-blocker.md → pf-fix-blocker.md} +0 -0
- /package/pennyfarthing-dist/commands/{git-cleanup.md → pf-git-cleanup.md} +0 -0
- /package/pennyfarthing-dist/commands/{health-check.md → pf-health-check.md} +0 -0
- /package/pennyfarthing-dist/commands/{help.md → pf-help.md} +0 -0
- /package/pennyfarthing-dist/commands/{list-themes.md → pf-list-themes.md} +0 -0
- /package/pennyfarthing-dist/commands/{orchestrator.md → pf-orchestrator.md} +0 -0
- /package/pennyfarthing-dist/commands/{parallel-work.md → pf-parallel-work.md} +0 -0
- /package/pennyfarthing-dist/commands/{permissions.md → pf-permissions.md} +0 -0
- /package/pennyfarthing-dist/commands/{pm.md → pf-pm.md} +0 -0
- /package/pennyfarthing-dist/commands/{prime.md → pf-prime.md} +0 -0
- /package/pennyfarthing-dist/commands/{repo-status.md → pf-repo-status.md} +0 -0
- /package/pennyfarthing-dist/commands/{retro.md → pf-retro.md} +0 -0
- /package/pennyfarthing-dist/commands/{reviewer.md → pf-reviewer.md} +0 -0
- /package/pennyfarthing-dist/commands/{run-ci.md → pf-run-ci.md} +0 -0
- /package/pennyfarthing-dist/commands/{set-theme.md → pf-set-theme.md} +0 -0
- /package/pennyfarthing-dist/commands/{show-theme.md → pf-show-theme.md} +0 -0
- /package/pennyfarthing-dist/commands/{sm.md → pf-sm.md} +0 -0
- /package/pennyfarthing-dist/commands/{sprint-planning.md → pf-sprint-planning.md} +0 -0
- /package/pennyfarthing-dist/commands/{start-epic.md → pf-start-epic.md} +0 -0
- /package/pennyfarthing-dist/commands/{sync-epic-to-jira.md → pf-sync-epic-to-jira.md} +0 -0
- /package/pennyfarthing-dist/commands/{sync-work-with-sprint.md → pf-sync-work-with-sprint.md} +0 -0
- /package/pennyfarthing-dist/commands/{tea.md → pf-tea.md} +0 -0
- /package/pennyfarthing-dist/commands/{tech-writer.md → pf-tech-writer.md} +0 -0
- /package/pennyfarthing-dist/commands/{theme-maker.md → pf-theme-maker.md} +0 -0
- /package/pennyfarthing-dist/commands/{theme.md → pf-theme.md} +0 -0
- /package/pennyfarthing-dist/commands/{update-domain-docs.md → pf-update-domain-docs.md} +0 -0
- /package/pennyfarthing-dist/commands/{ux-designer.md → pf-ux-designer.md} +0 -0
- /package/pennyfarthing-dist/commands/{work.md → pf-work.md} +0 -0
- /package/pennyfarthing-dist/skills/{agentic-patterns → pf-agentic-patterns}/SKILL.md +0 -0
- /package/pennyfarthing-dist/skills/{changelog → pf-changelog}/SKILL.md +0 -0
- /package/pennyfarthing-dist/skills/{code-review → pf-code-review}/SKILL.md +0 -0
- /package/pennyfarthing-dist/skills/{context-engineering → pf-context-engineering}/SKILL.md +0 -0
- /package/pennyfarthing-dist/skills/{mermaid → pf-mermaid}/SKILL.md +0 -0
- /package/pennyfarthing-dist/skills/{otel → pf-otel}/skill.md +0 -0
- /package/pennyfarthing-dist/skills/{testing → pf-testing}/SKILL.md +0 -0
- /package/pennyfarthing-dist/skills/{testing → pf-testing}/references/troubleshooting.md +0 -0
- /package/pennyfarthing-dist/skills/{theme-creation → pf-theme-creation}/SKILL.md +0 -0
- /package/pennyfarthing-dist/skills/{yq → pf-yq}/SKILL.md +0 -0
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Story 98-11: Settings.local.json shared merge model for multi-framework coexistence
|
|
3
|
+
*
|
|
4
|
+
* Acceptance Criteria:
|
|
5
|
+
* AC1: Namespace/section approach — each framework contributes settings under its own key
|
|
6
|
+
* AC2: Merge conflict resolution — hooks concatenated, permissions unioned, scalars priority-based
|
|
7
|
+
* AC3: Migration from legacy v1 format to v2 shared format
|
|
8
|
+
* AC4: Rollback — removing a framework cleanly extracts its contributions
|
|
9
|
+
* AC5: Backward compatibility — v2 exports flat format compatible with Claude Code
|
|
10
|
+
* AC6: Validation and error handling
|
|
11
|
+
*
|
|
12
|
+
* Run with: cd packages/core && npm run build && npm test
|
|
13
|
+
*/
|
|
14
|
+
import { describe, it, beforeEach } from 'node:test';
|
|
15
|
+
import assert from 'node:assert';
|
|
16
|
+
import { createEmptySharedSettings, contributeFrameworkSettings, removeFrameworkSettings, mergeHooks, mergePermissions, resolveScalar, detectConflicts, migrateToSharedFormat, isSharedFormat, toFlatFormat, validateSharedSettings, SHARED_SETTINGS_VERSION, } from './settings-merge.js';
|
|
17
|
+
// =============================================================================
|
|
18
|
+
// Test Fixtures
|
|
19
|
+
// =============================================================================
|
|
20
|
+
function makePennyfarthingContribution() {
|
|
21
|
+
return {
|
|
22
|
+
version: '10.4.0',
|
|
23
|
+
hooks: {
|
|
24
|
+
SessionStart: [
|
|
25
|
+
{
|
|
26
|
+
hooks: [
|
|
27
|
+
{ type: 'command', command: '.pennyfarthing/scripts/hooks/session-start.sh' },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
PostToolUse: [
|
|
32
|
+
{
|
|
33
|
+
matcher: '',
|
|
34
|
+
hooks: [
|
|
35
|
+
{ type: 'command', command: '.pennyfarthing/scripts/hooks/bell-mode-hook.sh' },
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
permissions: {
|
|
41
|
+
allow: ['Read', 'Grep', 'Glob', 'Bash', 'Skill(sm)', 'Skill(tea)'],
|
|
42
|
+
},
|
|
43
|
+
statusLine: {
|
|
44
|
+
type: 'command',
|
|
45
|
+
command: '.pennyfarthing/scripts/misc/statusline.sh',
|
|
46
|
+
},
|
|
47
|
+
context_budget: {
|
|
48
|
+
warning_threshold: 70,
|
|
49
|
+
critical_threshold: 85,
|
|
50
|
+
max_tokens: 200000,
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function makeOtherFrameworkContribution() {
|
|
55
|
+
return {
|
|
56
|
+
version: '2.1.0',
|
|
57
|
+
hooks: {
|
|
58
|
+
SessionStart: [
|
|
59
|
+
{
|
|
60
|
+
hooks: [
|
|
61
|
+
{ type: 'command', command: '.other-framework/hooks/init.sh' },
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
PreToolUse: [
|
|
66
|
+
{
|
|
67
|
+
matcher: 'Bash',
|
|
68
|
+
hooks: [
|
|
69
|
+
{ type: 'command', command: '.other-framework/hooks/pre-bash.sh' },
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
permissions: {
|
|
75
|
+
allow: ['Read', 'Bash', 'Skill(custom-skill)'],
|
|
76
|
+
},
|
|
77
|
+
statusLine: {
|
|
78
|
+
type: 'command',
|
|
79
|
+
command: '.other-framework/statusline.sh',
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function makeMinimalContribution() {
|
|
84
|
+
return {
|
|
85
|
+
version: '1.0.0',
|
|
86
|
+
hooks: {
|
|
87
|
+
Stop: [
|
|
88
|
+
{
|
|
89
|
+
matcher: '',
|
|
90
|
+
hooks: [{ type: 'command', command: '.minimal/hooks/stop.sh' }],
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// =============================================================================
|
|
97
|
+
// AC1: Namespace/Section Approach
|
|
98
|
+
// =============================================================================
|
|
99
|
+
describe('AC1: Namespace/section approach', () => {
|
|
100
|
+
let settings;
|
|
101
|
+
beforeEach(() => {
|
|
102
|
+
settings = createEmptySharedSettings();
|
|
103
|
+
});
|
|
104
|
+
it('should create empty shared settings with correct version', () => {
|
|
105
|
+
assert.strictEqual(settings._version, SHARED_SETTINGS_VERSION);
|
|
106
|
+
assert.deepStrictEqual(settings._frameworks, {});
|
|
107
|
+
assert.deepStrictEqual(settings._contributions, {});
|
|
108
|
+
assert.deepStrictEqual(settings.hooks, {});
|
|
109
|
+
assert.deepStrictEqual(settings.permissions, { allow: [] });
|
|
110
|
+
});
|
|
111
|
+
it('should store framework contribution under its namespace key', () => {
|
|
112
|
+
const contribution = makePennyfarthingContribution();
|
|
113
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', contribution);
|
|
114
|
+
assert.ok(result.settings._contributions['pennyfarthing'], 'Contribution should be stored under pennyfarthing key');
|
|
115
|
+
assert.strictEqual(result.settings._contributions['pennyfarthing'].version, '10.4.0', 'Should store the framework version');
|
|
116
|
+
});
|
|
117
|
+
it('should register framework metadata on contribution', () => {
|
|
118
|
+
const contribution = makePennyfarthingContribution();
|
|
119
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', contribution);
|
|
120
|
+
assert.ok(result.settings._frameworks['pennyfarthing'], 'Framework metadata should exist');
|
|
121
|
+
assert.strictEqual(result.settings._frameworks['pennyfarthing'].version, '10.4.0');
|
|
122
|
+
assert.ok(result.settings._frameworks['pennyfarthing'].installed_at, 'Should have installed_at timestamp');
|
|
123
|
+
});
|
|
124
|
+
it('should store multiple frameworks with separate namespace keys', () => {
|
|
125
|
+
const pf = makePennyfarthingContribution();
|
|
126
|
+
const other = makeOtherFrameworkContribution();
|
|
127
|
+
let result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
128
|
+
result = contributeFrameworkSettings(result.settings, 'other-framework', other);
|
|
129
|
+
assert.ok(result.settings._contributions['pennyfarthing']);
|
|
130
|
+
assert.ok(result.settings._contributions['other-framework']);
|
|
131
|
+
assert.strictEqual(Object.keys(result.settings._contributions).length, 2, 'Should have exactly 2 framework contributions');
|
|
132
|
+
});
|
|
133
|
+
it('should update existing framework contribution without creating duplicate', () => {
|
|
134
|
+
const v1 = makePennyfarthingContribution();
|
|
135
|
+
const v2 = { ...makePennyfarthingContribution(), version: '10.5.0' };
|
|
136
|
+
let result = contributeFrameworkSettings(settings, 'pennyfarthing', v1);
|
|
137
|
+
result = contributeFrameworkSettings(result.settings, 'pennyfarthing', v2);
|
|
138
|
+
assert.strictEqual(Object.keys(result.settings._contributions).length, 1, 'Should still have exactly 1 contribution');
|
|
139
|
+
assert.strictEqual(result.settings._contributions['pennyfarthing'].version, '10.5.0', 'Should have updated version');
|
|
140
|
+
});
|
|
141
|
+
it('should preserve framework contribution data integrity', () => {
|
|
142
|
+
const contribution = makePennyfarthingContribution();
|
|
143
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', contribution);
|
|
144
|
+
const stored = result.settings._contributions['pennyfarthing'];
|
|
145
|
+
assert.deepStrictEqual(stored.hooks, contribution.hooks, 'Stored hooks should match contribution');
|
|
146
|
+
assert.deepStrictEqual(stored.permissions, contribution.permissions, 'Stored permissions should match contribution');
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
// =============================================================================
|
|
150
|
+
// AC2: Merge Conflict Resolution — Hooks
|
|
151
|
+
// =============================================================================
|
|
152
|
+
describe('AC2a: Hook merging', () => {
|
|
153
|
+
it('should merge hooks from single framework', () => {
|
|
154
|
+
const contributions = {
|
|
155
|
+
pennyfarthing: makePennyfarthingContribution(),
|
|
156
|
+
};
|
|
157
|
+
const merged = mergeHooks(contributions);
|
|
158
|
+
assert.ok(merged.SessionStart, 'Should have SessionStart hooks');
|
|
159
|
+
assert.ok(merged.PostToolUse, 'Should have PostToolUse hooks');
|
|
160
|
+
assert.strictEqual(merged.SessionStart.length, 1, 'Should have 1 SessionStart entry');
|
|
161
|
+
});
|
|
162
|
+
it('should concatenate hooks from multiple frameworks per hook type', () => {
|
|
163
|
+
const contributions = {
|
|
164
|
+
pennyfarthing: makePennyfarthingContribution(),
|
|
165
|
+
'other-framework': makeOtherFrameworkContribution(),
|
|
166
|
+
};
|
|
167
|
+
const merged = mergeHooks(contributions);
|
|
168
|
+
// SessionStart: both frameworks contribute
|
|
169
|
+
assert.ok(merged.SessionStart, 'Should have SessionStart');
|
|
170
|
+
assert.strictEqual(merged.SessionStart.length, 2, 'SessionStart should have entries from both frameworks');
|
|
171
|
+
// PostToolUse: only pennyfarthing
|
|
172
|
+
assert.ok(merged.PostToolUse, 'Should have PostToolUse');
|
|
173
|
+
assert.strictEqual(merged.PostToolUse.length, 1, 'PostToolUse from pennyfarthing only');
|
|
174
|
+
// PreToolUse: only other-framework
|
|
175
|
+
assert.ok(merged.PreToolUse, 'Should have PreToolUse');
|
|
176
|
+
assert.strictEqual(merged.PreToolUse.length, 1, 'PreToolUse from other-framework only');
|
|
177
|
+
});
|
|
178
|
+
it('should deduplicate identical hooks within same framework', () => {
|
|
179
|
+
const contribution = {
|
|
180
|
+
version: '1.0.0',
|
|
181
|
+
hooks: {
|
|
182
|
+
SessionStart: [
|
|
183
|
+
{ hooks: [{ type: 'command', command: 'same-hook.sh' }] },
|
|
184
|
+
{ hooks: [{ type: 'command', command: 'same-hook.sh' }] },
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
const merged = mergeHooks({ test: contribution });
|
|
189
|
+
assert.strictEqual(merged.SessionStart.length, 1, 'Duplicate hooks within same framework should be deduplicated');
|
|
190
|
+
});
|
|
191
|
+
it('should preserve hook ordering — framework order then hook order', () => {
|
|
192
|
+
const contributions = {
|
|
193
|
+
alpha: {
|
|
194
|
+
version: '1.0.0',
|
|
195
|
+
hooks: {
|
|
196
|
+
SessionStart: [
|
|
197
|
+
{ hooks: [{ type: 'command', command: 'alpha-first.sh' }] },
|
|
198
|
+
{ hooks: [{ type: 'command', command: 'alpha-second.sh' }] },
|
|
199
|
+
],
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
beta: {
|
|
203
|
+
version: '1.0.0',
|
|
204
|
+
hooks: {
|
|
205
|
+
SessionStart: [
|
|
206
|
+
{ hooks: [{ type: 'command', command: 'beta-first.sh' }] },
|
|
207
|
+
],
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
const merged = mergeHooks(contributions);
|
|
212
|
+
const commands = merged.SessionStart.map(e => e.hooks[0].command);
|
|
213
|
+
assert.strictEqual(commands[0], 'alpha-first.sh');
|
|
214
|
+
assert.strictEqual(commands[1], 'alpha-second.sh');
|
|
215
|
+
assert.strictEqual(commands[2], 'beta-first.sh');
|
|
216
|
+
});
|
|
217
|
+
it('should handle framework with no hooks', () => {
|
|
218
|
+
const contributions = {
|
|
219
|
+
empty: { version: '1.0.0' },
|
|
220
|
+
withHooks: makePennyfarthingContribution(),
|
|
221
|
+
};
|
|
222
|
+
const merged = mergeHooks(contributions);
|
|
223
|
+
assert.ok(merged.SessionStart, 'Should still have hooks from the other framework');
|
|
224
|
+
});
|
|
225
|
+
it('should return empty object when no contributions have hooks', () => {
|
|
226
|
+
const contributions = {
|
|
227
|
+
a: { version: '1.0.0' },
|
|
228
|
+
b: { version: '2.0.0' },
|
|
229
|
+
};
|
|
230
|
+
const merged = mergeHooks(contributions);
|
|
231
|
+
assert.deepStrictEqual(merged, {}, 'Should return empty hooks');
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
// =============================================================================
|
|
235
|
+
// AC2: Merge Conflict Resolution — Permissions
|
|
236
|
+
// =============================================================================
|
|
237
|
+
describe('AC2b: Permission merging', () => {
|
|
238
|
+
it('should union permissions from multiple frameworks', () => {
|
|
239
|
+
const contributions = {
|
|
240
|
+
pennyfarthing: makePennyfarthingContribution(),
|
|
241
|
+
'other-framework': makeOtherFrameworkContribution(),
|
|
242
|
+
};
|
|
243
|
+
const merged = mergePermissions(contributions);
|
|
244
|
+
// Pennyfarthing: Read, Grep, Glob, Bash, Skill(sm), Skill(tea)
|
|
245
|
+
// Other: Read, Bash, Skill(custom-skill)
|
|
246
|
+
// Union: Read, Grep, Glob, Bash, Skill(sm), Skill(tea), Skill(custom-skill)
|
|
247
|
+
assert.ok(merged.allow.includes('Read'), 'Should include Read');
|
|
248
|
+
assert.ok(merged.allow.includes('Grep'), 'Should include Grep (pennyfarthing only)');
|
|
249
|
+
assert.ok(merged.allow.includes('Glob'), 'Should include Glob (pennyfarthing only)');
|
|
250
|
+
assert.ok(merged.allow.includes('Bash'), 'Should include Bash');
|
|
251
|
+
assert.ok(merged.allow.includes('Skill(sm)'), 'Should include Skill(sm)');
|
|
252
|
+
assert.ok(merged.allow.includes('Skill(custom-skill)'), 'Should include Skill(custom-skill)');
|
|
253
|
+
});
|
|
254
|
+
it('should deduplicate permissions present in multiple frameworks', () => {
|
|
255
|
+
const contributions = {
|
|
256
|
+
pennyfarthing: makePennyfarthingContribution(),
|
|
257
|
+
'other-framework': makeOtherFrameworkContribution(),
|
|
258
|
+
};
|
|
259
|
+
const merged = mergePermissions(contributions);
|
|
260
|
+
// Read and Bash appear in both — should only appear once
|
|
261
|
+
const readCount = merged.allow.filter(p => p === 'Read').length;
|
|
262
|
+
const bashCount = merged.allow.filter(p => p === 'Bash').length;
|
|
263
|
+
assert.strictEqual(readCount, 1, 'Read should appear exactly once');
|
|
264
|
+
assert.strictEqual(bashCount, 1, 'Bash should appear exactly once');
|
|
265
|
+
});
|
|
266
|
+
it('should handle framework with no permissions', () => {
|
|
267
|
+
const contributions = {
|
|
268
|
+
minimal: makeMinimalContribution(),
|
|
269
|
+
pennyfarthing: makePennyfarthingContribution(),
|
|
270
|
+
};
|
|
271
|
+
const merged = mergePermissions(contributions);
|
|
272
|
+
assert.ok(merged.allow.length > 0, 'Should have permissions from pennyfarthing');
|
|
273
|
+
assert.ok(merged.allow.includes('Read'));
|
|
274
|
+
});
|
|
275
|
+
it('should return empty allow list when no frameworks contribute permissions', () => {
|
|
276
|
+
const contributions = {
|
|
277
|
+
a: { version: '1.0.0' },
|
|
278
|
+
};
|
|
279
|
+
const merged = mergePermissions(contributions);
|
|
280
|
+
assert.deepStrictEqual(merged, { allow: [] });
|
|
281
|
+
});
|
|
282
|
+
it('should maintain stable ordering — alphabetical by permission string', () => {
|
|
283
|
+
const contributions = {
|
|
284
|
+
z: {
|
|
285
|
+
version: '1.0.0',
|
|
286
|
+
permissions: { allow: ['Zebra', 'Apple'] },
|
|
287
|
+
},
|
|
288
|
+
a: {
|
|
289
|
+
version: '1.0.0',
|
|
290
|
+
permissions: { allow: ['Mango', 'Banana'] },
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
const merged = mergePermissions(contributions);
|
|
294
|
+
const sorted = [...merged.allow].sort();
|
|
295
|
+
assert.deepStrictEqual(merged.allow, sorted, 'Permissions should be alphabetically sorted');
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
// =============================================================================
|
|
299
|
+
// AC2: Merge Conflict Resolution — Scalar Values
|
|
300
|
+
// =============================================================================
|
|
301
|
+
describe('AC2c: Scalar resolution', () => {
|
|
302
|
+
it('should use statusLine from highest-priority framework', () => {
|
|
303
|
+
const contributions = {
|
|
304
|
+
pennyfarthing: makePennyfarthingContribution(),
|
|
305
|
+
'other-framework': makeOtherFrameworkContribution(),
|
|
306
|
+
};
|
|
307
|
+
const frameworks = {
|
|
308
|
+
pennyfarthing: { version: '10.4.0', installed_at: '2026-01-01', priority: 1 },
|
|
309
|
+
'other-framework': { version: '2.1.0', installed_at: '2026-02-01', priority: 2 },
|
|
310
|
+
};
|
|
311
|
+
const result = resolveScalar(contributions, frameworks, 'statusLine');
|
|
312
|
+
assert.ok(result, 'Should resolve a statusLine');
|
|
313
|
+
assert.ok(result.command.includes('.pennyfarthing'), 'Should use pennyfarthing statusLine (priority 1)');
|
|
314
|
+
});
|
|
315
|
+
it('should use context_budget from highest-priority framework', () => {
|
|
316
|
+
const contributions = {
|
|
317
|
+
pennyfarthing: makePennyfarthingContribution(),
|
|
318
|
+
'other-framework': {
|
|
319
|
+
...makeOtherFrameworkContribution(),
|
|
320
|
+
context_budget: { warning_threshold: 60, critical_threshold: 80, max_tokens: 150000 },
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
const frameworks = {
|
|
324
|
+
pennyfarthing: { version: '10.4.0', installed_at: '2026-01-01', priority: 1 },
|
|
325
|
+
'other-framework': { version: '2.1.0', installed_at: '2026-02-01', priority: 2 },
|
|
326
|
+
};
|
|
327
|
+
const result = resolveScalar(contributions, frameworks, 'context_budget');
|
|
328
|
+
assert.ok(result, 'Should resolve context_budget');
|
|
329
|
+
assert.strictEqual(result.warning_threshold, 70, 'Should use pennyfarthing value (priority 1)');
|
|
330
|
+
});
|
|
331
|
+
it('should fall back to alphabetical order when priorities are equal', () => {
|
|
332
|
+
const contributions = {
|
|
333
|
+
beta: {
|
|
334
|
+
version: '1.0.0',
|
|
335
|
+
statusLine: { type: 'command', command: 'beta-status.sh' },
|
|
336
|
+
},
|
|
337
|
+
alpha: {
|
|
338
|
+
version: '1.0.0',
|
|
339
|
+
statusLine: { type: 'command', command: 'alpha-status.sh' },
|
|
340
|
+
},
|
|
341
|
+
};
|
|
342
|
+
const frameworks = {
|
|
343
|
+
alpha: { version: '1.0.0', installed_at: '2026-01-01' },
|
|
344
|
+
beta: { version: '1.0.0', installed_at: '2026-01-01' },
|
|
345
|
+
};
|
|
346
|
+
const result = resolveScalar(contributions, frameworks, 'statusLine');
|
|
347
|
+
assert.ok(result);
|
|
348
|
+
assert.ok(result.command.includes('alpha'), 'Should use alpha (alphabetically first) when priorities equal');
|
|
349
|
+
});
|
|
350
|
+
it('should return undefined when no framework contributes the scalar', () => {
|
|
351
|
+
const contributions = {
|
|
352
|
+
minimal: makeMinimalContribution(),
|
|
353
|
+
};
|
|
354
|
+
const frameworks = {
|
|
355
|
+
minimal: { version: '1.0.0', installed_at: '2026-01-01' },
|
|
356
|
+
};
|
|
357
|
+
const result = resolveScalar(contributions, frameworks, 'statusLine');
|
|
358
|
+
assert.strictEqual(result, undefined, 'Should return undefined when nobody contributes');
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
// =============================================================================
|
|
362
|
+
// AC2: Conflict Detection
|
|
363
|
+
// =============================================================================
|
|
364
|
+
describe('AC2d: Conflict detection', () => {
|
|
365
|
+
it('should detect duplicate hook commands across frameworks', () => {
|
|
366
|
+
const contributions = {
|
|
367
|
+
alpha: {
|
|
368
|
+
version: '1.0.0',
|
|
369
|
+
hooks: {
|
|
370
|
+
SessionStart: [
|
|
371
|
+
{ hooks: [{ type: 'command', command: 'shared-hook.sh' }] },
|
|
372
|
+
],
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
beta: {
|
|
376
|
+
version: '1.0.0',
|
|
377
|
+
hooks: {
|
|
378
|
+
SessionStart: [
|
|
379
|
+
{ hooks: [{ type: 'command', command: 'shared-hook.sh' }] },
|
|
380
|
+
],
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
const conflicts = detectConflicts(contributions);
|
|
385
|
+
assert.ok(conflicts.length > 0, 'Should detect at least one conflict');
|
|
386
|
+
const hookConflict = conflicts.find(c => c.type === 'hook_duplicate');
|
|
387
|
+
assert.ok(hookConflict, 'Should have a hook_duplicate conflict');
|
|
388
|
+
assert.ok(hookConflict.frameworks.includes('alpha') && hookConflict.frameworks.includes('beta'), 'Conflict should reference both frameworks');
|
|
389
|
+
});
|
|
390
|
+
it('should detect statusLine collisions between frameworks', () => {
|
|
391
|
+
const contributions = {
|
|
392
|
+
alpha: {
|
|
393
|
+
version: '1.0.0',
|
|
394
|
+
statusLine: { type: 'command', command: 'alpha-status.sh' },
|
|
395
|
+
},
|
|
396
|
+
beta: {
|
|
397
|
+
version: '1.0.0',
|
|
398
|
+
statusLine: { type: 'command', command: 'beta-status.sh' },
|
|
399
|
+
},
|
|
400
|
+
};
|
|
401
|
+
const conflicts = detectConflicts(contributions);
|
|
402
|
+
const scalarConflict = conflicts.find(c => c.type === 'scalar_collision');
|
|
403
|
+
assert.ok(scalarConflict, 'Should detect scalar collision for statusLine');
|
|
404
|
+
assert.strictEqual(scalarConflict.key, 'statusLine');
|
|
405
|
+
});
|
|
406
|
+
it('should NOT report conflict when only one framework contributes a scalar', () => {
|
|
407
|
+
const contributions = {
|
|
408
|
+
alpha: {
|
|
409
|
+
version: '1.0.0',
|
|
410
|
+
statusLine: { type: 'command', command: 'alpha-status.sh' },
|
|
411
|
+
},
|
|
412
|
+
beta: { version: '1.0.0' },
|
|
413
|
+
};
|
|
414
|
+
const conflicts = detectConflicts(contributions);
|
|
415
|
+
const scalarConflicts = conflicts.filter(c => c.type === 'scalar_collision');
|
|
416
|
+
assert.strictEqual(scalarConflicts.length, 0, 'No collision when only one contributes');
|
|
417
|
+
});
|
|
418
|
+
it('should NOT report conflict for different hook commands in same hook type', () => {
|
|
419
|
+
const contributions = {
|
|
420
|
+
alpha: {
|
|
421
|
+
version: '1.0.0',
|
|
422
|
+
hooks: {
|
|
423
|
+
SessionStart: [
|
|
424
|
+
{ hooks: [{ type: 'command', command: 'alpha-hook.sh' }] },
|
|
425
|
+
],
|
|
426
|
+
},
|
|
427
|
+
},
|
|
428
|
+
beta: {
|
|
429
|
+
version: '1.0.0',
|
|
430
|
+
hooks: {
|
|
431
|
+
SessionStart: [
|
|
432
|
+
{ hooks: [{ type: 'command', command: 'beta-hook.sh' }] },
|
|
433
|
+
],
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
};
|
|
437
|
+
const conflicts = detectConflicts(contributions);
|
|
438
|
+
const hookConflicts = conflicts.filter(c => c.type === 'hook_duplicate');
|
|
439
|
+
assert.strictEqual(hookConflicts.length, 0, 'Different commands in same hook type is normal, not a conflict');
|
|
440
|
+
});
|
|
441
|
+
it('should return empty array when there are no conflicts', () => {
|
|
442
|
+
const contributions = {
|
|
443
|
+
alpha: makePennyfarthingContribution(),
|
|
444
|
+
};
|
|
445
|
+
const conflicts = detectConflicts(contributions);
|
|
446
|
+
assert.deepStrictEqual(conflicts, [], 'Single framework should have no conflicts');
|
|
447
|
+
});
|
|
448
|
+
});
|
|
449
|
+
// =============================================================================
|
|
450
|
+
// AC3: Migration from Legacy v1 to Shared v2 Format
|
|
451
|
+
// =============================================================================
|
|
452
|
+
describe('AC3: Migration from legacy format', () => {
|
|
453
|
+
it('should migrate legacy settings into v2 format under framework namespace', () => {
|
|
454
|
+
const legacy = {
|
|
455
|
+
hooks: {
|
|
456
|
+
SessionStart: [
|
|
457
|
+
{ hooks: [{ type: 'command', command: 'session-start.sh' }] },
|
|
458
|
+
],
|
|
459
|
+
},
|
|
460
|
+
permissions: { allow: ['Read', 'Bash'] },
|
|
461
|
+
statusLine: { type: 'command', command: 'statusline.sh' },
|
|
462
|
+
context_budget: { warning_threshold: 70, critical_threshold: 85, max_tokens: 200000 },
|
|
463
|
+
};
|
|
464
|
+
const migrated = migrateToSharedFormat(legacy, 'pennyfarthing', '10.4.0');
|
|
465
|
+
assert.strictEqual(migrated._version, SHARED_SETTINGS_VERSION, 'Should be v2');
|
|
466
|
+
assert.ok(migrated._frameworks['pennyfarthing'], 'Should have framework metadata');
|
|
467
|
+
assert.ok(migrated._contributions['pennyfarthing'], 'Should have contribution');
|
|
468
|
+
const contribution = migrated._contributions['pennyfarthing'];
|
|
469
|
+
assert.deepStrictEqual(contribution.hooks, legacy.hooks, 'Hooks should be preserved in contribution');
|
|
470
|
+
assert.deepStrictEqual(contribution.permissions, legacy.permissions, 'Permissions should be preserved');
|
|
471
|
+
});
|
|
472
|
+
it('should populate merged output fields after migration', () => {
|
|
473
|
+
const legacy = {
|
|
474
|
+
hooks: {
|
|
475
|
+
SessionStart: [
|
|
476
|
+
{ hooks: [{ type: 'command', command: 'session-start.sh' }] },
|
|
477
|
+
],
|
|
478
|
+
},
|
|
479
|
+
permissions: { allow: ['Read', 'Bash'] },
|
|
480
|
+
};
|
|
481
|
+
const migrated = migrateToSharedFormat(legacy, 'pennyfarthing', '10.4.0');
|
|
482
|
+
// Merged output should reflect the single framework's contributions
|
|
483
|
+
assert.ok(migrated.hooks.SessionStart, 'Merged hooks should exist');
|
|
484
|
+
assert.ok(migrated.permissions.allow.includes('Read'), 'Merged permissions should include Read');
|
|
485
|
+
});
|
|
486
|
+
it('should handle legacy settings with no hooks', () => {
|
|
487
|
+
const legacy = {
|
|
488
|
+
permissions: { allow: ['Read'] },
|
|
489
|
+
};
|
|
490
|
+
const migrated = migrateToSharedFormat(legacy, 'test-framework', '1.0.0');
|
|
491
|
+
assert.ok(migrated._contributions['test-framework']);
|
|
492
|
+
assert.deepStrictEqual(migrated.hooks, {}, 'Hooks should be empty when legacy has none');
|
|
493
|
+
});
|
|
494
|
+
it('should handle legacy settings with no permissions', () => {
|
|
495
|
+
const legacy = {
|
|
496
|
+
hooks: {
|
|
497
|
+
Stop: [{ hooks: [{ type: 'command', command: 'stop.sh' }] }],
|
|
498
|
+
},
|
|
499
|
+
};
|
|
500
|
+
const migrated = migrateToSharedFormat(legacy, 'test-framework', '1.0.0');
|
|
501
|
+
assert.deepStrictEqual(migrated.permissions, { allow: [] }, 'Permissions should default to empty');
|
|
502
|
+
});
|
|
503
|
+
it('should handle completely empty legacy settings', () => {
|
|
504
|
+
const migrated = migrateToSharedFormat({}, 'test-framework', '1.0.0');
|
|
505
|
+
assert.strictEqual(migrated._version, SHARED_SETTINGS_VERSION);
|
|
506
|
+
assert.ok(migrated._frameworks['test-framework']);
|
|
507
|
+
assert.deepStrictEqual(migrated.hooks, {});
|
|
508
|
+
assert.deepStrictEqual(migrated.permissions, { allow: [] });
|
|
509
|
+
});
|
|
510
|
+
it('should handle unknown top-level keys gracefully without crashing', () => {
|
|
511
|
+
const legacy = {
|
|
512
|
+
hooks: {},
|
|
513
|
+
permissions: { allow: [] },
|
|
514
|
+
customExtension: { someData: true },
|
|
515
|
+
};
|
|
516
|
+
// Unknown keys are intentionally dropped — only known fields are migrated
|
|
517
|
+
const migrated = migrateToSharedFormat(legacy, 'test-framework', '1.0.0');
|
|
518
|
+
assert.ok(migrated._frameworks['test-framework'], 'Framework should be registered');
|
|
519
|
+
assert.strictEqual(migrated._version, SHARED_SETTINGS_VERSION);
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
// =============================================================================
|
|
523
|
+
// AC4: Framework Removal (Rollback)
|
|
524
|
+
// =============================================================================
|
|
525
|
+
describe('AC4: Framework removal (rollback)', () => {
|
|
526
|
+
it('should remove a framework contribution cleanly', () => {
|
|
527
|
+
const settings = createEmptySharedSettings();
|
|
528
|
+
const pf = makePennyfarthingContribution();
|
|
529
|
+
const other = makeOtherFrameworkContribution();
|
|
530
|
+
let result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
531
|
+
result = contributeFrameworkSettings(result.settings, 'other-framework', other);
|
|
532
|
+
const afterRemoval = removeFrameworkSettings(result.settings, 'other-framework');
|
|
533
|
+
assert.ok(!afterRemoval._contributions['other-framework'], 'Removed framework contribution should not exist');
|
|
534
|
+
assert.ok(!afterRemoval._frameworks['other-framework'], 'Removed framework metadata should not exist');
|
|
535
|
+
assert.ok(afterRemoval._contributions['pennyfarthing'], 'Remaining framework should still exist');
|
|
536
|
+
});
|
|
537
|
+
it('should re-merge hooks after framework removal', () => {
|
|
538
|
+
const settings = createEmptySharedSettings();
|
|
539
|
+
const pf = makePennyfarthingContribution();
|
|
540
|
+
const other = makeOtherFrameworkContribution();
|
|
541
|
+
let result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
542
|
+
result = contributeFrameworkSettings(result.settings, 'other-framework', other);
|
|
543
|
+
const afterRemoval = removeFrameworkSettings(result.settings, 'other-framework');
|
|
544
|
+
// PreToolUse was only contributed by other-framework — should be gone
|
|
545
|
+
assert.ok(!afterRemoval.hooks.PreToolUse || afterRemoval.hooks.PreToolUse.length === 0, 'PreToolUse hooks should be removed with other-framework');
|
|
546
|
+
// SessionStart should only have pennyfarthing's entry now
|
|
547
|
+
assert.strictEqual(afterRemoval.hooks.SessionStart?.length, 1, 'SessionStart should only have pennyfarthing entry');
|
|
548
|
+
});
|
|
549
|
+
it('should re-merge permissions after framework removal', () => {
|
|
550
|
+
const settings = createEmptySharedSettings();
|
|
551
|
+
const pf = makePennyfarthingContribution();
|
|
552
|
+
const other = makeOtherFrameworkContribution();
|
|
553
|
+
let result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
554
|
+
result = contributeFrameworkSettings(result.settings, 'other-framework', other);
|
|
555
|
+
const afterRemoval = removeFrameworkSettings(result.settings, 'other-framework');
|
|
556
|
+
assert.ok(!afterRemoval.permissions.allow.includes('Skill(custom-skill)'), 'Permission from removed framework should be gone');
|
|
557
|
+
assert.ok(afterRemoval.permissions.allow.includes('Skill(sm)'), 'Permission from remaining framework should stay');
|
|
558
|
+
});
|
|
559
|
+
it('should handle removing the only framework', () => {
|
|
560
|
+
const settings = createEmptySharedSettings();
|
|
561
|
+
const pf = makePennyfarthingContribution();
|
|
562
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
563
|
+
const afterRemoval = removeFrameworkSettings(result.settings, 'pennyfarthing');
|
|
564
|
+
assert.deepStrictEqual(afterRemoval._contributions, {});
|
|
565
|
+
assert.deepStrictEqual(afterRemoval._frameworks, {});
|
|
566
|
+
assert.deepStrictEqual(afterRemoval.hooks, {});
|
|
567
|
+
assert.deepStrictEqual(afterRemoval.permissions, { allow: [] });
|
|
568
|
+
});
|
|
569
|
+
it('should be no-op when removing non-existent framework', () => {
|
|
570
|
+
const settings = createEmptySharedSettings();
|
|
571
|
+
const pf = makePennyfarthingContribution();
|
|
572
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
573
|
+
const afterRemoval = removeFrameworkSettings(result.settings, 'nonexistent');
|
|
574
|
+
assert.deepStrictEqual(afterRemoval._contributions, result.settings._contributions, 'Should not change anything');
|
|
575
|
+
});
|
|
576
|
+
});
|
|
577
|
+
// =============================================================================
|
|
578
|
+
// AC5: Backward Compatibility — Flat Format Export
|
|
579
|
+
// =============================================================================
|
|
580
|
+
describe('AC5: Backward compatibility (flat format export)', () => {
|
|
581
|
+
it('should export merged settings in Claude Code-compatible flat format', () => {
|
|
582
|
+
const settings = createEmptySharedSettings();
|
|
583
|
+
const pf = makePennyfarthingContribution();
|
|
584
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
585
|
+
const flat = toFlatFormat(result.settings);
|
|
586
|
+
// Should NOT contain internal fields
|
|
587
|
+
assert.strictEqual(flat._version, undefined, 'Should not contain _version');
|
|
588
|
+
assert.strictEqual(flat._frameworks, undefined, 'Should not contain _frameworks');
|
|
589
|
+
assert.strictEqual(flat._contributions, undefined, 'Should not contain _contributions');
|
|
590
|
+
// Should contain merged results
|
|
591
|
+
assert.ok(flat.hooks, 'Should contain hooks');
|
|
592
|
+
assert.ok(flat.permissions, 'Should contain permissions');
|
|
593
|
+
});
|
|
594
|
+
it('should produce valid hooks structure in flat format', () => {
|
|
595
|
+
const settings = createEmptySharedSettings();
|
|
596
|
+
const pf = makePennyfarthingContribution();
|
|
597
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
598
|
+
const flat = toFlatFormat(result.settings);
|
|
599
|
+
const hooks = flat.hooks;
|
|
600
|
+
assert.ok(Array.isArray(hooks.SessionStart), 'SessionStart should be an array');
|
|
601
|
+
assert.ok(Array.isArray(hooks.PostToolUse), 'PostToolUse should be an array');
|
|
602
|
+
});
|
|
603
|
+
it('should produce valid permissions structure in flat format', () => {
|
|
604
|
+
const settings = createEmptySharedSettings();
|
|
605
|
+
const pf = makePennyfarthingContribution();
|
|
606
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
607
|
+
const flat = toFlatFormat(result.settings);
|
|
608
|
+
const permissions = flat.permissions;
|
|
609
|
+
assert.ok(Array.isArray(permissions.allow), 'allow should be an array');
|
|
610
|
+
assert.ok(permissions.allow.includes('Read'));
|
|
611
|
+
});
|
|
612
|
+
it('should include statusLine in flat format when present', () => {
|
|
613
|
+
const settings = createEmptySharedSettings();
|
|
614
|
+
const pf = makePennyfarthingContribution();
|
|
615
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
616
|
+
const flat = toFlatFormat(result.settings);
|
|
617
|
+
assert.ok(flat.statusLine, 'Should include statusLine');
|
|
618
|
+
const sl = flat.statusLine;
|
|
619
|
+
assert.strictEqual(sl.type, 'command');
|
|
620
|
+
assert.ok(sl.command.includes('statusline.sh'));
|
|
621
|
+
});
|
|
622
|
+
it('should include context_budget in flat format when present', () => {
|
|
623
|
+
const settings = createEmptySharedSettings();
|
|
624
|
+
const pf = makePennyfarthingContribution();
|
|
625
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
626
|
+
const flat = toFlatFormat(result.settings);
|
|
627
|
+
assert.ok(flat.context_budget, 'Should include context_budget');
|
|
628
|
+
const cb = flat.context_budget;
|
|
629
|
+
assert.strictEqual(cb.warning_threshold, 70);
|
|
630
|
+
});
|
|
631
|
+
it('should produce identical JSON to what Claude Code expects', () => {
|
|
632
|
+
const settings = createEmptySharedSettings();
|
|
633
|
+
const pf = makePennyfarthingContribution();
|
|
634
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
635
|
+
const flat = toFlatFormat(result.settings);
|
|
636
|
+
// Verify it round-trips through JSON without issues
|
|
637
|
+
const json = JSON.stringify(flat, null, 2);
|
|
638
|
+
const parsed = JSON.parse(json);
|
|
639
|
+
assert.deepStrictEqual(parsed, flat, 'Should round-trip through JSON');
|
|
640
|
+
});
|
|
641
|
+
});
|
|
642
|
+
// =============================================================================
|
|
643
|
+
// AC6: Validation
|
|
644
|
+
// =============================================================================
|
|
645
|
+
describe('AC6: Validation', () => {
|
|
646
|
+
it('should validate a correct SharedSettings structure', () => {
|
|
647
|
+
const settings = createEmptySharedSettings();
|
|
648
|
+
const pf = makePennyfarthingContribution();
|
|
649
|
+
const result = contributeFrameworkSettings(settings, 'pennyfarthing', pf);
|
|
650
|
+
const validation = validateSharedSettings(result.settings);
|
|
651
|
+
assert.ok(validation.valid, `Should be valid, errors: ${validation.errors.join(', ')}`);
|
|
652
|
+
assert.deepStrictEqual(validation.errors, []);
|
|
653
|
+
});
|
|
654
|
+
it('should reject null input', () => {
|
|
655
|
+
const validation = validateSharedSettings(null);
|
|
656
|
+
assert.strictEqual(validation.valid, false);
|
|
657
|
+
assert.ok(validation.errors.length > 0);
|
|
658
|
+
});
|
|
659
|
+
it('should reject non-object input', () => {
|
|
660
|
+
const validation = validateSharedSettings('not an object');
|
|
661
|
+
assert.strictEqual(validation.valid, false);
|
|
662
|
+
});
|
|
663
|
+
it('should reject missing _version field', () => {
|
|
664
|
+
const validation = validateSharedSettings({
|
|
665
|
+
_frameworks: {},
|
|
666
|
+
_contributions: {},
|
|
667
|
+
hooks: {},
|
|
668
|
+
permissions: { allow: [] },
|
|
669
|
+
});
|
|
670
|
+
assert.strictEqual(validation.valid, false);
|
|
671
|
+
assert.ok(validation.errors.some(e => e.includes('version')), 'Should mention version in error');
|
|
672
|
+
});
|
|
673
|
+
it('should reject wrong _version value', () => {
|
|
674
|
+
const validation = validateSharedSettings({
|
|
675
|
+
_version: 999,
|
|
676
|
+
_frameworks: {},
|
|
677
|
+
_contributions: {},
|
|
678
|
+
hooks: {},
|
|
679
|
+
permissions: { allow: [] },
|
|
680
|
+
});
|
|
681
|
+
assert.strictEqual(validation.valid, false);
|
|
682
|
+
});
|
|
683
|
+
it('should reject missing _frameworks field', () => {
|
|
684
|
+
const validation = validateSharedSettings({
|
|
685
|
+
_version: SHARED_SETTINGS_VERSION,
|
|
686
|
+
_contributions: {},
|
|
687
|
+
hooks: {},
|
|
688
|
+
permissions: { allow: [] },
|
|
689
|
+
});
|
|
690
|
+
assert.strictEqual(validation.valid, false);
|
|
691
|
+
});
|
|
692
|
+
it('should validate empty shared settings as valid', () => {
|
|
693
|
+
const settings = createEmptySharedSettings();
|
|
694
|
+
const validation = validateSharedSettings(settings);
|
|
695
|
+
assert.ok(validation.valid, 'Empty shared settings should be valid');
|
|
696
|
+
});
|
|
697
|
+
});
|
|
698
|
+
// =============================================================================
|
|
699
|
+
// Format Detection
|
|
700
|
+
// =============================================================================
|
|
701
|
+
describe('Format detection', () => {
|
|
702
|
+
it('should identify v2 shared format', () => {
|
|
703
|
+
const settings = createEmptySharedSettings();
|
|
704
|
+
assert.ok(isSharedFormat(settings), 'Should detect shared format');
|
|
705
|
+
});
|
|
706
|
+
it('should reject legacy v1 format', () => {
|
|
707
|
+
const legacy = {
|
|
708
|
+
hooks: {},
|
|
709
|
+
permissions: { allow: [] },
|
|
710
|
+
};
|
|
711
|
+
assert.ok(!isSharedFormat(legacy), 'Should reject legacy format');
|
|
712
|
+
});
|
|
713
|
+
it('should reject null', () => {
|
|
714
|
+
assert.ok(!isSharedFormat(null));
|
|
715
|
+
});
|
|
716
|
+
it('should reject wrong version number', () => {
|
|
717
|
+
assert.ok(!isSharedFormat({ _version: 1 }));
|
|
718
|
+
assert.ok(!isSharedFormat({ _version: 3 }));
|
|
719
|
+
});
|
|
720
|
+
});
|
|
721
|
+
// =============================================================================
|
|
722
|
+
// Integration: Full Multi-Framework Lifecycle
|
|
723
|
+
// =============================================================================
|
|
724
|
+
describe('Integration: multi-framework lifecycle', () => {
|
|
725
|
+
it('should handle full lifecycle: create → contribute → contribute → remove → export', () => {
|
|
726
|
+
// 1. Create empty
|
|
727
|
+
const empty = createEmptySharedSettings();
|
|
728
|
+
assert.strictEqual(Object.keys(empty._contributions).length, 0);
|
|
729
|
+
// 2. First framework contributes
|
|
730
|
+
const r1 = contributeFrameworkSettings(empty, 'pennyfarthing', makePennyfarthingContribution());
|
|
731
|
+
assert.strictEqual(Object.keys(r1.settings._contributions).length, 1);
|
|
732
|
+
assert.ok(r1.settings.hooks.SessionStart);
|
|
733
|
+
// 3. Second framework contributes
|
|
734
|
+
const r2 = contributeFrameworkSettings(r1.settings, 'other', makeOtherFrameworkContribution());
|
|
735
|
+
assert.strictEqual(Object.keys(r2.settings._contributions).length, 2);
|
|
736
|
+
// Both frameworks' SessionStart hooks should be present
|
|
737
|
+
assert.strictEqual(r2.settings.hooks.SessionStart.length, 2);
|
|
738
|
+
// Permissions should be unioned
|
|
739
|
+
assert.ok(r2.settings.permissions.allow.includes('Skill(sm)'));
|
|
740
|
+
assert.ok(r2.settings.permissions.allow.includes('Skill(custom-skill)'));
|
|
741
|
+
// 4. Remove second framework
|
|
742
|
+
const afterRemove = removeFrameworkSettings(r2.settings, 'other');
|
|
743
|
+
assert.strictEqual(Object.keys(afterRemove._contributions).length, 1);
|
|
744
|
+
assert.strictEqual(afterRemove.hooks.SessionStart.length, 1);
|
|
745
|
+
assert.ok(!afterRemove.permissions.allow.includes('Skill(custom-skill)'));
|
|
746
|
+
// 5. Export flat format
|
|
747
|
+
const flat = toFlatFormat(afterRemove);
|
|
748
|
+
assert.strictEqual(flat._version, undefined);
|
|
749
|
+
assert.ok(flat.hooks);
|
|
750
|
+
assert.ok(flat.permissions);
|
|
751
|
+
});
|
|
752
|
+
it('should handle migrate-then-contribute workflow', () => {
|
|
753
|
+
// Legacy settings exist, then another framework installs
|
|
754
|
+
const legacy = {
|
|
755
|
+
hooks: {
|
|
756
|
+
SessionStart: [
|
|
757
|
+
{ hooks: [{ type: 'command', command: '.pennyfarthing/scripts/hooks/session-start.sh' }] },
|
|
758
|
+
],
|
|
759
|
+
},
|
|
760
|
+
permissions: { allow: ['Read', 'Bash'] },
|
|
761
|
+
statusLine: { type: 'command', command: '.pennyfarthing/scripts/misc/statusline.sh' },
|
|
762
|
+
};
|
|
763
|
+
// Migrate legacy to v2
|
|
764
|
+
const migrated = migrateToSharedFormat(legacy, 'pennyfarthing', '10.4.0');
|
|
765
|
+
assert.strictEqual(migrated._version, SHARED_SETTINGS_VERSION);
|
|
766
|
+
// New framework contributes
|
|
767
|
+
const result = contributeFrameworkSettings(migrated, 'new-tool', makeOtherFrameworkContribution());
|
|
768
|
+
assert.strictEqual(Object.keys(result.settings._contributions).length, 2);
|
|
769
|
+
assert.ok(result.settings.hooks.SessionStart.length >= 2, 'Should have hooks from both');
|
|
770
|
+
});
|
|
771
|
+
it('should be idempotent — contributing same framework twice produces same result', () => {
|
|
772
|
+
const settings = createEmptySharedSettings();
|
|
773
|
+
const contribution = makePennyfarthingContribution();
|
|
774
|
+
const r1 = contributeFrameworkSettings(settings, 'pennyfarthing', contribution);
|
|
775
|
+
const r2 = contributeFrameworkSettings(r1.settings, 'pennyfarthing', contribution);
|
|
776
|
+
// Merged output should be identical
|
|
777
|
+
assert.deepStrictEqual(r1.settings.hooks, r2.settings.hooks, 'Hooks should be identical');
|
|
778
|
+
assert.deepStrictEqual(r1.settings.permissions, r2.settings.permissions, 'Permissions should be identical');
|
|
779
|
+
});
|
|
780
|
+
});
|
|
781
|
+
//# sourceMappingURL=settings-merge.test.js.map
|