@slope-dev/slope 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +243 -0
- package/dist/cli/commands/auto-card.d.ts +2 -0
- package/dist/cli/commands/auto-card.d.ts.map +1 -0
- package/dist/cli/commands/auto-card.js +267 -0
- package/dist/cli/commands/auto-card.js.map +1 -0
- package/dist/cli/commands/briefing.d.ts +2 -0
- package/dist/cli/commands/briefing.d.ts.map +1 -0
- package/dist/cli/commands/briefing.js +133 -0
- package/dist/cli/commands/briefing.js.map +1 -0
- package/dist/cli/commands/card.d.ts +2 -0
- package/dist/cli/commands/card.d.ts.map +1 -0
- package/dist/cli/commands/card.js +144 -0
- package/dist/cli/commands/card.js.map +1 -0
- package/dist/cli/commands/claim.d.ts +2 -0
- package/dist/cli/commands/claim.d.ts.map +1 -0
- package/dist/cli/commands/claim.js +99 -0
- package/dist/cli/commands/claim.js.map +1 -0
- package/dist/cli/commands/classify.d.ts +2 -0
- package/dist/cli/commands/classify.d.ts.map +1 -0
- package/dist/cli/commands/classify.js +70 -0
- package/dist/cli/commands/classify.js.map +1 -0
- package/dist/cli/commands/dashboard.d.ts +4 -0
- package/dist/cli/commands/dashboard.d.ts.map +1 -0
- package/dist/cli/commands/dashboard.js +156 -0
- package/dist/cli/commands/dashboard.js.map +1 -0
- package/dist/cli/commands/distill.d.ts +2 -0
- package/dist/cli/commands/distill.d.ts.map +1 -0
- package/dist/cli/commands/distill.js +91 -0
- package/dist/cli/commands/distill.js.map +1 -0
- package/dist/cli/commands/escalate.d.ts +2 -0
- package/dist/cli/commands/escalate.d.ts.map +1 -0
- package/dist/cli/commands/escalate.js +136 -0
- package/dist/cli/commands/escalate.js.map +1 -0
- package/dist/cli/commands/extract.d.ts +2 -0
- package/dist/cli/commands/extract.d.ts.map +1 -0
- package/dist/cli/commands/extract.js +147 -0
- package/dist/cli/commands/extract.js.map +1 -0
- package/dist/cli/commands/flows.d.ts +2 -0
- package/dist/cli/commands/flows.d.ts.map +1 -0
- package/dist/cli/commands/flows.js +156 -0
- package/dist/cli/commands/flows.js.map +1 -0
- package/dist/cli/commands/guard.d.ts +15 -0
- package/dist/cli/commands/guard.d.ts.map +1 -0
- package/dist/cli/commands/guard.js +207 -0
- package/dist/cli/commands/guard.js.map +1 -0
- package/dist/cli/commands/hook.d.ts +2 -0
- package/dist/cli/commands/hook.d.ts.map +1 -0
- package/dist/cli/commands/hook.js +299 -0
- package/dist/cli/commands/hook.js.map +1 -0
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +421 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/map.d.ts +10 -0
- package/dist/cli/commands/map.d.ts.map +1 -0
- package/dist/cli/commands/map.js +591 -0
- package/dist/cli/commands/map.js.map +1 -0
- package/dist/cli/commands/next.d.ts +2 -0
- package/dist/cli/commands/next.d.ts.map +1 -0
- package/dist/cli/commands/next.js +28 -0
- package/dist/cli/commands/next.js.map +1 -0
- package/dist/cli/commands/plan.d.ts +2 -0
- package/dist/cli/commands/plan.d.ts.map +1 -0
- package/dist/cli/commands/plan.js +54 -0
- package/dist/cli/commands/plan.js.map +1 -0
- package/dist/cli/commands/plugin.d.ts +2 -0
- package/dist/cli/commands/plugin.d.ts.map +1 -0
- package/dist/cli/commands/plugin.js +118 -0
- package/dist/cli/commands/plugin.js.map +1 -0
- package/dist/cli/commands/release.d.ts +2 -0
- package/dist/cli/commands/release.d.ts.map +1 -0
- package/dist/cli/commands/release.js +64 -0
- package/dist/cli/commands/release.js.map +1 -0
- package/dist/cli/commands/report.d.ts +2 -0
- package/dist/cli/commands/report.d.ts.map +1 -0
- package/dist/cli/commands/report.js +68 -0
- package/dist/cli/commands/report.js.map +1 -0
- package/dist/cli/commands/review-state.d.ts +11 -0
- package/dist/cli/commands/review-state.d.ts.map +1 -0
- package/dist/cli/commands/review-state.js +193 -0
- package/dist/cli/commands/review-state.js.map +1 -0
- package/dist/cli/commands/review.d.ts +2 -0
- package/dist/cli/commands/review.d.ts.map +1 -0
- package/dist/cli/commands/review.js +53 -0
- package/dist/cli/commands/review.js.map +1 -0
- package/dist/cli/commands/roadmap.d.ts +2 -0
- package/dist/cli/commands/roadmap.d.ts.map +1 -0
- package/dist/cli/commands/roadmap.js +283 -0
- package/dist/cli/commands/roadmap.js.map +1 -0
- package/dist/cli/commands/session.d.ts +2 -0
- package/dist/cli/commands/session.d.ts.map +1 -0
- package/dist/cli/commands/session.js +232 -0
- package/dist/cli/commands/session.js.map +1 -0
- package/dist/cli/commands/standup.d.ts +2 -0
- package/dist/cli/commands/standup.d.ts.map +1 -0
- package/dist/cli/commands/standup.js +117 -0
- package/dist/cli/commands/standup.js.map +1 -0
- package/dist/cli/commands/status.d.ts +2 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +148 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/tournament.d.ts +2 -0
- package/dist/cli/commands/tournament.d.ts.map +1 -0
- package/dist/cli/commands/tournament.js +60 -0
- package/dist/cli/commands/tournament.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +2 -0
- package/dist/cli/commands/validate.d.ts.map +1 -0
- package/dist/cli/commands/validate.js +74 -0
- package/dist/cli/commands/validate.js.map +1 -0
- package/dist/cli/config.d.ts +2 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +2 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/guards/commit-nudge.d.ts +7 -0
- package/dist/cli/guards/commit-nudge.d.ts.map +1 -0
- package/dist/cli/guards/commit-nudge.js +50 -0
- package/dist/cli/guards/commit-nudge.js.map +1 -0
- package/dist/cli/guards/compaction.d.ts +8 -0
- package/dist/cli/guards/compaction.d.ts.map +1 -0
- package/dist/cli/guards/compaction.js +79 -0
- package/dist/cli/guards/compaction.js.map +1 -0
- package/dist/cli/guards/explore.d.ts +8 -0
- package/dist/cli/guards/explore.d.ts.map +1 -0
- package/dist/cli/guards/explore.js +78 -0
- package/dist/cli/guards/explore.js.map +1 -0
- package/dist/cli/guards/hazard.d.ts +7 -0
- package/dist/cli/guards/hazard.d.ts.map +1 -0
- package/dist/cli/guards/hazard.js +43 -0
- package/dist/cli/guards/hazard.js.map +1 -0
- package/dist/cli/guards/next-action.d.ts +28 -0
- package/dist/cli/guards/next-action.d.ts.map +1 -0
- package/dist/cli/guards/next-action.js +196 -0
- package/dist/cli/guards/next-action.js.map +1 -0
- package/dist/cli/guards/push-nudge.d.ts +7 -0
- package/dist/cli/guards/push-nudge.d.ts.map +1 -0
- package/dist/cli/guards/push-nudge.js +53 -0
- package/dist/cli/guards/push-nudge.js.map +1 -0
- package/dist/cli/guards/review-tier.d.ts +7 -0
- package/dist/cli/guards/review-tier.d.ts.map +1 -0
- package/dist/cli/guards/review-tier.js +108 -0
- package/dist/cli/guards/review-tier.js.map +1 -0
- package/dist/cli/guards/scope-drift.d.ts +7 -0
- package/dist/cli/guards/scope-drift.d.ts.map +1 -0
- package/dist/cli/guards/scope-drift.js +47 -0
- package/dist/cli/guards/scope-drift.js.map +1 -0
- package/dist/cli/guards/stop-check.d.ts +7 -0
- package/dist/cli/guards/stop-check.d.ts.map +1 -0
- package/dist/cli/guards/stop-check.js +34 -0
- package/dist/cli/guards/stop-check.js.map +1 -0
- package/dist/cli/guards/subagent-gate.d.ts +7 -0
- package/dist/cli/guards/subagent-gate.d.ts.map +1 -0
- package/dist/cli/guards/subagent-gate.js +39 -0
- package/dist/cli/guards/subagent-gate.js.map +1 -0
- package/dist/cli/guards/version-check.d.ts +8 -0
- package/dist/cli/guards/version-check.d.ts.map +1 -0
- package/dist/cli/guards/version-check.js +49 -0
- package/dist/cli/guards/version-check.js.map +1 -0
- package/dist/cli/guards/workflow-gate.d.ts +7 -0
- package/dist/cli/guards/workflow-gate.d.ts.map +1 -0
- package/dist/cli/guards/workflow-gate.js +31 -0
- package/dist/cli/guards/workflow-gate.js.map +1 -0
- package/dist/cli/hooks-config.d.ts +9 -0
- package/dist/cli/hooks-config.d.ts.map +1 -0
- package/dist/cli/hooks-config.js +21 -0
- package/dist/cli/hooks-config.js.map +1 -0
- package/dist/cli/index.d.ts +19 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +282 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/loader.d.ts +2 -0
- package/dist/cli/loader.d.ts.map +1 -0
- package/dist/cli/loader.js +2 -0
- package/dist/cli/loader.js.map +1 -0
- package/dist/cli/metaphor.d.ts +6 -0
- package/dist/cli/metaphor.d.ts.map +1 -0
- package/dist/cli/metaphor.js +26 -0
- package/dist/cli/metaphor.js.map +1 -0
- package/dist/cli/registries/api-registry.d.ts +11 -0
- package/dist/cli/registries/api-registry.d.ts.map +1 -0
- package/dist/cli/registries/api-registry.js +42 -0
- package/dist/cli/registries/api-registry.js.map +1 -0
- package/dist/cli/registries/file-registry.d.ts +13 -0
- package/dist/cli/registries/file-registry.d.ts.map +1 -0
- package/dist/cli/registries/file-registry.js +55 -0
- package/dist/cli/registries/file-registry.js.map +1 -0
- package/dist/cli/registries/index.d.ts +7 -0
- package/dist/cli/registries/index.d.ts.map +1 -0
- package/dist/cli/registries/index.js +20 -0
- package/dist/cli/registries/index.js.map +1 -0
- package/dist/cli/store.d.ts +3 -0
- package/dist/cli/store.d.ts.map +1 -0
- package/dist/cli/store.js +13 -0
- package/dist/cli/store.js.map +1 -0
- package/dist/cli/template-generator.d.ts +15 -0
- package/dist/cli/template-generator.d.ts.map +1 -0
- package/dist/cli/template-generator.js +562 -0
- package/dist/cli/template-generator.js.map +1 -0
- package/dist/core/advisor.d.ts +63 -0
- package/dist/core/advisor.d.ts.map +1 -0
- package/dist/core/advisor.js +395 -0
- package/dist/core/advisor.js.map +1 -0
- package/dist/core/briefing.d.ts +103 -0
- package/dist/core/briefing.d.ts.map +1 -0
- package/dist/core/briefing.js +380 -0
- package/dist/core/briefing.js.map +1 -0
- package/dist/core/builder.d.ts +70 -0
- package/dist/core/builder.d.ts.map +1 -0
- package/dist/core/builder.js +175 -0
- package/dist/core/builder.js.map +1 -0
- package/dist/core/ci-signals.d.ts +10 -0
- package/dist/core/ci-signals.d.ts.map +1 -0
- package/dist/core/ci-signals.js +145 -0
- package/dist/core/ci-signals.js.map +1 -0
- package/dist/core/config.d.ts +48 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +42 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/constants.d.ts +14 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +44 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/dashboard.d.ts +40 -0
- package/dist/core/dashboard.d.ts.map +1 -0
- package/dist/core/dashboard.js +413 -0
- package/dist/core/dashboard.js.map +1 -0
- package/dist/core/dispersion.d.ts +12 -0
- package/dist/core/dispersion.d.ts.map +1 -0
- package/dist/core/dispersion.js +164 -0
- package/dist/core/dispersion.js.map +1 -0
- package/dist/core/escalation.d.ts +52 -0
- package/dist/core/escalation.d.ts.map +1 -0
- package/dist/core/escalation.js +105 -0
- package/dist/core/escalation.js.map +1 -0
- package/dist/core/flows.d.ts +44 -0
- package/dist/core/flows.d.ts.map +1 -0
- package/dist/core/flows.js +123 -0
- package/dist/core/flows.js.map +1 -0
- package/dist/core/formatter.d.ts +23 -0
- package/dist/core/formatter.d.ts.map +1 -0
- package/dist/core/formatter.js +301 -0
- package/dist/core/formatter.js.map +1 -0
- package/dist/core/guard.d.ts +124 -0
- package/dist/core/guard.d.ts.map +1 -0
- package/dist/core/guard.js +185 -0
- package/dist/core/guard.js.map +1 -0
- package/dist/core/handicap.d.ts +22 -0
- package/dist/core/handicap.d.ts.map +1 -0
- package/dist/core/handicap.js +111 -0
- package/dist/core/handicap.js.map +1 -0
- package/dist/core/index.d.ts +55 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +62 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/leaderboard.d.ts +32 -0
- package/dist/core/leaderboard.d.ts.map +1 -0
- package/dist/core/leaderboard.js +98 -0
- package/dist/core/leaderboard.js.map +1 -0
- package/dist/core/loader.d.ts +17 -0
- package/dist/core/loader.d.ts.map +1 -0
- package/dist/core/loader.js +68 -0
- package/dist/core/loader.js.map +1 -0
- package/dist/core/metaphor.d.ts +73 -0
- package/dist/core/metaphor.d.ts.map +1 -0
- package/dist/core/metaphor.js +73 -0
- package/dist/core/metaphor.js.map +1 -0
- package/dist/core/metaphors/baseball.d.ts +3 -0
- package/dist/core/metaphors/baseball.d.ts.map +1 -0
- package/dist/core/metaphors/baseball.js +89 -0
- package/dist/core/metaphors/baseball.js.map +1 -0
- package/dist/core/metaphors/dnd.d.ts +3 -0
- package/dist/core/metaphors/dnd.d.ts.map +1 -0
- package/dist/core/metaphors/dnd.js +89 -0
- package/dist/core/metaphors/dnd.js.map +1 -0
- package/dist/core/metaphors/gaming.d.ts +3 -0
- package/dist/core/metaphors/gaming.d.ts.map +1 -0
- package/dist/core/metaphors/gaming.js +89 -0
- package/dist/core/metaphors/gaming.js.map +1 -0
- package/dist/core/metaphors/golf.d.ts +3 -0
- package/dist/core/metaphors/golf.d.ts.map +1 -0
- package/dist/core/metaphors/golf.js +89 -0
- package/dist/core/metaphors/golf.js.map +1 -0
- package/dist/core/metaphors/index.d.ts +8 -0
- package/dist/core/metaphors/index.d.ts.map +1 -0
- package/dist/core/metaphors/index.js +17 -0
- package/dist/core/metaphors/index.js.map +1 -0
- package/dist/core/metaphors/matrix.d.ts +3 -0
- package/dist/core/metaphors/matrix.d.ts.map +1 -0
- package/dist/core/metaphors/matrix.js +89 -0
- package/dist/core/metaphors/matrix.js.map +1 -0
- package/dist/core/metaphors/tennis.d.ts +3 -0
- package/dist/core/metaphors/tennis.d.ts.map +1 -0
- package/dist/core/metaphors/tennis.js +89 -0
- package/dist/core/metaphors/tennis.js.map +1 -0
- package/dist/core/pipeline.d.ts +39 -0
- package/dist/core/pipeline.d.ts.map +1 -0
- package/dist/core/pipeline.js +158 -0
- package/dist/core/pipeline.js.map +1 -0
- package/dist/core/player.d.ts +51 -0
- package/dist/core/player.d.ts.map +1 -0
- package/dist/core/player.js +101 -0
- package/dist/core/player.js.map +1 -0
- package/dist/core/plugins.d.ts +33 -0
- package/dist/core/plugins.d.ts.map +1 -0
- package/dist/core/plugins.js +176 -0
- package/dist/core/plugins.js.map +1 -0
- package/dist/core/pr-signals.d.ts +23 -0
- package/dist/core/pr-signals.d.ts.map +1 -0
- package/dist/core/pr-signals.js +178 -0
- package/dist/core/pr-signals.js.map +1 -0
- package/dist/core/registry.d.ts +20 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +62 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/report.d.ts +50 -0
- package/dist/core/report.d.ts.map +1 -0
- package/dist/core/report.js +392 -0
- package/dist/core/report.js.map +1 -0
- package/dist/core/roadmap.d.ts +74 -0
- package/dist/core/roadmap.d.ts.map +1 -0
- package/dist/core/roadmap.js +389 -0
- package/dist/core/roadmap.js.map +1 -0
- package/dist/core/roles.d.ts +23 -0
- package/dist/core/roles.d.ts.map +1 -0
- package/dist/core/roles.js +107 -0
- package/dist/core/roles.js.map +1 -0
- package/dist/core/standup.d.ts +44 -0
- package/dist/core/standup.d.ts.map +1 -0
- package/dist/core/standup.js +164 -0
- package/dist/core/standup.js.map +1 -0
- package/dist/core/store.d.ts +43 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +11 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/team-handicap.d.ts +59 -0
- package/dist/core/team-handicap.d.ts.map +1 -0
- package/dist/core/team-handicap.js +227 -0
- package/dist/core/team-handicap.js.map +1 -0
- package/dist/core/tournament.d.ts +12 -0
- package/dist/core/tournament.d.ts.map +1 -0
- package/dist/core/tournament.js +249 -0
- package/dist/core/tournament.js.map +1 -0
- package/dist/core/types.d.ts +339 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +4 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/validation.d.ts +23 -0
- package/dist/core/validation.d.ts.map +1 -0
- package/dist/core/validation.js +140 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/index.d.ts +17 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +363 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/index.test.d.ts +2 -0
- package/dist/mcp/index.test.d.ts.map +1 -0
- package/dist/mcp/index.test.js +497 -0
- package/dist/mcp/index.test.js.map +1 -0
- package/dist/mcp/registry.d.ts +17 -0
- package/dist/mcp/registry.d.ts.map +1 -0
- package/dist/mcp/registry.js +708 -0
- package/dist/mcp/registry.js.map +1 -0
- package/dist/mcp/sandbox.d.ts +15 -0
- package/dist/mcp/sandbox.d.ts.map +1 -0
- package/dist/mcp/sandbox.js +153 -0
- package/dist/mcp/sandbox.js.map +1 -0
- package/dist/store/index.d.ts +40 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +324 -0
- package/dist/store/index.js.map +1 -0
- package/dist/tokens/colors.d.ts +47 -0
- package/dist/tokens/colors.d.ts.map +1 -0
- package/dist/tokens/colors.js +56 -0
- package/dist/tokens/colors.js.map +1 -0
- package/dist/tokens/css.d.ts +3 -0
- package/dist/tokens/css.d.ts.map +1 -0
- package/dist/tokens/css.js +58 -0
- package/dist/tokens/css.js.map +1 -0
- package/dist/tokens/index.d.ts +5 -0
- package/dist/tokens/index.d.ts.map +1 -0
- package/dist/tokens/index.js +6 -0
- package/dist/tokens/index.js.map +1 -0
- package/dist/tokens/spacing.d.ts +23 -0
- package/dist/tokens/spacing.d.ts.map +1 -0
- package/dist/tokens/spacing.js +28 -0
- package/dist/tokens/spacing.js.map +1 -0
- package/dist/tokens/typography.d.ts +28 -0
- package/dist/tokens/typography.d.ts.map +1 -0
- package/dist/tokens/typography.js +34 -0
- package/dist/tokens/typography.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// SLOPE Plugin System
|
|
2
|
+
// Discovers and loads custom metaphor and guard plugins from .slope/plugins/
|
|
3
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { validateMetaphor, registerMetaphor } from './metaphor.js';
|
|
6
|
+
import { registerCustomGuard } from './guard.js';
|
|
7
|
+
// --- Validation ---
|
|
8
|
+
export function validatePluginManifest(raw) {
|
|
9
|
+
const errors = [];
|
|
10
|
+
if (!raw || typeof raw !== 'object') {
|
|
11
|
+
return { valid: false, errors: ['Plugin manifest must be an object'] };
|
|
12
|
+
}
|
|
13
|
+
const obj = raw;
|
|
14
|
+
if (!obj.type || (obj.type !== 'metaphor' && obj.type !== 'guard')) {
|
|
15
|
+
errors.push('Missing or invalid "type" (must be "metaphor" or "guard")');
|
|
16
|
+
}
|
|
17
|
+
if (!obj.id || typeof obj.id !== 'string') {
|
|
18
|
+
errors.push('Missing or invalid "id" (must be a non-empty string)');
|
|
19
|
+
}
|
|
20
|
+
if (!obj.name || typeof obj.name !== 'string') {
|
|
21
|
+
errors.push('Missing or invalid "name" (must be a non-empty string)');
|
|
22
|
+
}
|
|
23
|
+
return { valid: errors.length === 0, errors };
|
|
24
|
+
}
|
|
25
|
+
// --- Discovery ---
|
|
26
|
+
export function discoverPlugins(cwd) {
|
|
27
|
+
const plugins = [];
|
|
28
|
+
const seen = new Set();
|
|
29
|
+
const dirs = [
|
|
30
|
+
{ dir: join(cwd, '.slope', 'plugins', 'metaphors'), type: 'metaphor' },
|
|
31
|
+
{ dir: join(cwd, '.slope', 'plugins', 'guards'), type: 'guard' },
|
|
32
|
+
];
|
|
33
|
+
for (const { dir, type } of dirs) {
|
|
34
|
+
if (!existsSync(dir))
|
|
35
|
+
continue;
|
|
36
|
+
for (const file of readdirSync(dir)) {
|
|
37
|
+
if (!file.endsWith('.json'))
|
|
38
|
+
continue;
|
|
39
|
+
const filePath = join(dir, file);
|
|
40
|
+
try {
|
|
41
|
+
const raw = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
42
|
+
// Infer type from directory if not specified in file
|
|
43
|
+
if (!raw.type)
|
|
44
|
+
raw.type = type;
|
|
45
|
+
const { valid } = validatePluginManifest(raw);
|
|
46
|
+
if (!valid)
|
|
47
|
+
continue;
|
|
48
|
+
// For metaphors, use the metaphor's id field; for guards, use name field
|
|
49
|
+
const id = type === 'guard' ? raw.name : raw.id;
|
|
50
|
+
if (seen.has(`${type}:${id}`))
|
|
51
|
+
continue;
|
|
52
|
+
seen.add(`${type}:${id}`);
|
|
53
|
+
plugins.push({
|
|
54
|
+
manifest: {
|
|
55
|
+
type: raw.type ?? type,
|
|
56
|
+
id: raw.id,
|
|
57
|
+
name: raw.name,
|
|
58
|
+
version: raw.version,
|
|
59
|
+
description: raw.description,
|
|
60
|
+
},
|
|
61
|
+
filePath,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch { /* skip unparseable files */ }
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return plugins;
|
|
68
|
+
}
|
|
69
|
+
// --- Config filtering ---
|
|
70
|
+
export function isPluginEnabled(id, config) {
|
|
71
|
+
if (!config)
|
|
72
|
+
return true;
|
|
73
|
+
// Disabled list takes priority
|
|
74
|
+
if (config.disabled?.includes(id))
|
|
75
|
+
return false;
|
|
76
|
+
// If enabled list exists, only those are allowed
|
|
77
|
+
if (config.enabled && config.enabled.length > 0) {
|
|
78
|
+
return config.enabled.includes(id);
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
// --- Type-specific loaders ---
|
|
83
|
+
export function loadPluginMetaphors(cwd, config) {
|
|
84
|
+
const result = { loaded: [], errors: [] };
|
|
85
|
+
const dir = join(cwd, '.slope', 'plugins', 'metaphors');
|
|
86
|
+
if (!existsSync(dir))
|
|
87
|
+
return result;
|
|
88
|
+
for (const file of readdirSync(dir)) {
|
|
89
|
+
if (!file.endsWith('.json'))
|
|
90
|
+
continue;
|
|
91
|
+
const filePath = join(dir, file);
|
|
92
|
+
try {
|
|
93
|
+
const raw = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
94
|
+
if (!raw.id || typeof raw.id !== 'string') {
|
|
95
|
+
result.errors.push({ filePath, error: 'Missing "id" field' });
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (!isPluginEnabled(raw.id, config))
|
|
99
|
+
continue;
|
|
100
|
+
const metaphor = raw;
|
|
101
|
+
const validationErrors = validateMetaphor(metaphor);
|
|
102
|
+
if (validationErrors.length > 0) {
|
|
103
|
+
result.errors.push({ filePath, error: validationErrors.join('; ') });
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
registerMetaphor(metaphor);
|
|
107
|
+
result.loaded.push({
|
|
108
|
+
manifest: { type: 'metaphor', id: metaphor.id, name: metaphor.name, version: raw.version, description: metaphor.description },
|
|
109
|
+
filePath,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
result.errors.push({ filePath, error: err.message });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
export function loadPluginGuards(cwd, config) {
|
|
119
|
+
const result = { loaded: [], errors: [] };
|
|
120
|
+
const dir = join(cwd, '.slope', 'plugins', 'guards');
|
|
121
|
+
if (!existsSync(dir))
|
|
122
|
+
return result;
|
|
123
|
+
for (const file of readdirSync(dir)) {
|
|
124
|
+
if (!file.endsWith('.json'))
|
|
125
|
+
continue;
|
|
126
|
+
const filePath = join(dir, file);
|
|
127
|
+
try {
|
|
128
|
+
const raw = JSON.parse(readFileSync(filePath, 'utf8'));
|
|
129
|
+
if (!raw.name || typeof raw.name !== 'string') {
|
|
130
|
+
result.errors.push({ filePath, error: 'Missing "name" field' });
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (!raw.hookEvent || typeof raw.hookEvent !== 'string') {
|
|
134
|
+
result.errors.push({ filePath, error: 'Missing "hookEvent" field' });
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (!raw.command || typeof raw.command !== 'string') {
|
|
138
|
+
result.errors.push({ filePath, error: 'Missing "command" field' });
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (!raw.level || (raw.level !== 'scoring' && raw.level !== 'full')) {
|
|
142
|
+
result.errors.push({ filePath, error: 'Missing or invalid "level" (must be "scoring" or "full")' });
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (!isPluginEnabled(raw.name, config))
|
|
146
|
+
continue;
|
|
147
|
+
const guard = {
|
|
148
|
+
name: raw.name,
|
|
149
|
+
description: raw.description ?? '',
|
|
150
|
+
hookEvent: raw.hookEvent,
|
|
151
|
+
matcher: raw.matcher,
|
|
152
|
+
level: raw.level,
|
|
153
|
+
command: raw.command,
|
|
154
|
+
};
|
|
155
|
+
registerCustomGuard(guard);
|
|
156
|
+
result.loaded.push({
|
|
157
|
+
manifest: { type: 'guard', id: raw.name, name: raw.name, version: raw.version, description: raw.description },
|
|
158
|
+
filePath,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
result.errors.push({ filePath, error: err.message });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
// --- Main loader ---
|
|
168
|
+
export function loadPlugins(cwd, config) {
|
|
169
|
+
const metaphors = loadPluginMetaphors(cwd, config);
|
|
170
|
+
const guards = loadPluginGuards(cwd, config);
|
|
171
|
+
return {
|
|
172
|
+
loaded: [...metaphors.loaded, ...guards.loaded],
|
|
173
|
+
errors: [...metaphors.errors, ...guards.errors],
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=plugins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugins.js","sourceRoot":"","sources":["../../src/core/plugins.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { PRSignal, CISignal } from './types.js';
|
|
2
|
+
/** Fields to request from `gh pr view --json` */
|
|
3
|
+
export declare const GH_PR_JSON_FIELDS: readonly ["number", "additions", "deletions", "changedFiles", "comments", "reviews", "reviewDecision", "statusCheckRollup", "createdAt", "mergedAt"];
|
|
4
|
+
/** Build the `gh pr view` CLI command string */
|
|
5
|
+
export declare function buildGhCommand(prNumber: number): string;
|
|
6
|
+
/** Parse raw `gh pr view --json` output into a PRSignal */
|
|
7
|
+
export declare function parsePRJson(json: Record<string, unknown>): PRSignal;
|
|
8
|
+
/** Safe defaults for graceful degradation when PR data is unavailable */
|
|
9
|
+
export declare function emptyPRSignal(prNumber?: number): PRSignal;
|
|
10
|
+
/**
|
|
11
|
+
* Merge PR check data with an existing CISignal.
|
|
12
|
+
*
|
|
13
|
+
* - Both exist: keep CI runner data (more granular), detect retry scenario
|
|
14
|
+
* (PR had failures but CI shows passing → increment retries)
|
|
15
|
+
* - No existing CI: derive CISignal from PR check counts (runner='unknown')
|
|
16
|
+
*/
|
|
17
|
+
export declare function mergePRChecksWithCI(prSignal: PRSignal, existingCI?: CISignal): CISignal;
|
|
18
|
+
/**
|
|
19
|
+
* Count checks that failed initially then succeeded (retry detection).
|
|
20
|
+
* Looks at statusCheckRollup for checks with multiple runs where earlier runs failed.
|
|
21
|
+
*/
|
|
22
|
+
export declare function detectCheckRetries(statusCheckRollup: unknown): number;
|
|
23
|
+
//# sourceMappingURL=pr-signals.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-signals.d.ts","sourceRoot":"","sources":["../../src/core/pr-signals.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAoB,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEvE,iDAAiD;AACjD,eAAO,MAAM,iBAAiB,sJAWpB,CAAC;AAEX,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGvD;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,QAAQ,CA0BnE;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAezD;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAyBvF;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,iBAAiB,EAAE,OAAO,GAAG,MAAM,CAuBrE"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// SLOPE — PR Signal Parser
|
|
2
|
+
// Parses GitHub PR metadata (from `gh pr view --json`) into structured PRSignal objects.
|
|
3
|
+
// Pure parser — no I/O. CLI handles `gh` execution.
|
|
4
|
+
/** Fields to request from `gh pr view --json` */
|
|
5
|
+
export const GH_PR_JSON_FIELDS = [
|
|
6
|
+
'number',
|
|
7
|
+
'additions',
|
|
8
|
+
'deletions',
|
|
9
|
+
'changedFiles',
|
|
10
|
+
'comments',
|
|
11
|
+
'reviews',
|
|
12
|
+
'reviewDecision',
|
|
13
|
+
'statusCheckRollup',
|
|
14
|
+
'createdAt',
|
|
15
|
+
'mergedAt',
|
|
16
|
+
];
|
|
17
|
+
/** Build the `gh pr view` CLI command string */
|
|
18
|
+
export function buildGhCommand(prNumber) {
|
|
19
|
+
const fields = GH_PR_JSON_FIELDS.join(',');
|
|
20
|
+
return `gh pr view ${prNumber} --json ${fields}`;
|
|
21
|
+
}
|
|
22
|
+
/** Parse raw `gh pr view --json` output into a PRSignal */
|
|
23
|
+
export function parsePRJson(json) {
|
|
24
|
+
const reviews = Array.isArray(json.reviews) ? json.reviews : [];
|
|
25
|
+
const comments = Array.isArray(json.comments) ? json.comments : [];
|
|
26
|
+
const statusCheckRollup = Array.isArray(json.statusCheckRollup)
|
|
27
|
+
? json.statusCheckRollup
|
|
28
|
+
: [];
|
|
29
|
+
const { passed, failed } = extractStatusChecks(statusCheckRollup);
|
|
30
|
+
return {
|
|
31
|
+
platform: 'github',
|
|
32
|
+
pr_number: typeof json.number === 'number' ? json.number : 0,
|
|
33
|
+
review_cycles: countReviewCycles(reviews),
|
|
34
|
+
change_request_count: countChangeRequests(reviews),
|
|
35
|
+
time_to_merge_minutes: computeTimeToMerge(json.createdAt, json.mergedAt),
|
|
36
|
+
ci_checks_passed: passed,
|
|
37
|
+
ci_checks_failed: failed,
|
|
38
|
+
file_count: typeof json.changedFiles === 'number' ? json.changedFiles : 0,
|
|
39
|
+
additions: typeof json.additions === 'number' ? json.additions : 0,
|
|
40
|
+
deletions: typeof json.deletions === 'number' ? json.deletions : 0,
|
|
41
|
+
comment_count: comments.length,
|
|
42
|
+
review_decision: normalizeReviewDecision(json.reviewDecision),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Safe defaults for graceful degradation when PR data is unavailable */
|
|
46
|
+
export function emptyPRSignal(prNumber) {
|
|
47
|
+
return {
|
|
48
|
+
platform: 'unknown',
|
|
49
|
+
pr_number: prNumber ?? 0,
|
|
50
|
+
review_cycles: 0,
|
|
51
|
+
change_request_count: 0,
|
|
52
|
+
time_to_merge_minutes: null,
|
|
53
|
+
ci_checks_passed: 0,
|
|
54
|
+
ci_checks_failed: 0,
|
|
55
|
+
file_count: 0,
|
|
56
|
+
additions: 0,
|
|
57
|
+
deletions: 0,
|
|
58
|
+
comment_count: 0,
|
|
59
|
+
review_decision: 'NONE',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Merge PR check data with an existing CISignal.
|
|
64
|
+
*
|
|
65
|
+
* - Both exist: keep CI runner data (more granular), detect retry scenario
|
|
66
|
+
* (PR had failures but CI shows passing → increment retries)
|
|
67
|
+
* - No existing CI: derive CISignal from PR check counts (runner='unknown')
|
|
68
|
+
*/
|
|
69
|
+
export function mergePRChecksWithCI(prSignal, existingCI) {
|
|
70
|
+
if (!existingCI) {
|
|
71
|
+
// Derive CISignal from PR check counts
|
|
72
|
+
return {
|
|
73
|
+
runner: 'unknown',
|
|
74
|
+
test_total: prSignal.ci_checks_passed + prSignal.ci_checks_failed,
|
|
75
|
+
test_passed: prSignal.ci_checks_passed,
|
|
76
|
+
test_failed: prSignal.ci_checks_failed,
|
|
77
|
+
test_skipped: 0,
|
|
78
|
+
suites_total: prSignal.ci_checks_passed + prSignal.ci_checks_failed,
|
|
79
|
+
suites_passed: prSignal.ci_checks_passed,
|
|
80
|
+
suites_failed: prSignal.ci_checks_failed,
|
|
81
|
+
retries: 0,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Both exist: keep CI data, detect retry scenario
|
|
85
|
+
const retryBoost = (prSignal.ci_checks_failed > 0 && existingCI.test_failed === 0)
|
|
86
|
+
? prSignal.ci_checks_failed // PR had failures, CI now passing → retries occurred
|
|
87
|
+
: 0;
|
|
88
|
+
return {
|
|
89
|
+
...existingCI,
|
|
90
|
+
retries: existingCI.retries + retryBoost,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Count checks that failed initially then succeeded (retry detection).
|
|
95
|
+
* Looks at statusCheckRollup for checks with multiple runs where earlier runs failed.
|
|
96
|
+
*/
|
|
97
|
+
export function detectCheckRetries(statusCheckRollup) {
|
|
98
|
+
if (!Array.isArray(statusCheckRollup))
|
|
99
|
+
return 0;
|
|
100
|
+
let retries = 0;
|
|
101
|
+
// Group by check name, count those with mixed results
|
|
102
|
+
const byName = new Map();
|
|
103
|
+
for (const check of statusCheckRollup) {
|
|
104
|
+
const rec = check;
|
|
105
|
+
const name = typeof rec.name === 'string' ? rec.name : 'unknown';
|
|
106
|
+
const conclusion = typeof rec.conclusion === 'string' ? rec.conclusion.toUpperCase() : '';
|
|
107
|
+
if (!byName.has(name))
|
|
108
|
+
byName.set(name, []);
|
|
109
|
+
byName.get(name).push(conclusion);
|
|
110
|
+
}
|
|
111
|
+
for (const conclusions of byName.values()) {
|
|
112
|
+
if (conclusions.length > 1) {
|
|
113
|
+
const hasFail = conclusions.some(c => c === 'FAILURE' || c === 'TIMED_OUT');
|
|
114
|
+
const hasPass = conclusions.some(c => c === 'SUCCESS');
|
|
115
|
+
if (hasFail && hasPass)
|
|
116
|
+
retries++;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return retries;
|
|
120
|
+
}
|
|
121
|
+
// --- Internal helpers ---
|
|
122
|
+
/**
|
|
123
|
+
* Count review cycles: each time a reviewer submits a review constitutes a cycle.
|
|
124
|
+
* Multiple reviews from the same author count as separate cycles (re-reviews).
|
|
125
|
+
*/
|
|
126
|
+
function countReviewCycles(reviews) {
|
|
127
|
+
return reviews.length;
|
|
128
|
+
}
|
|
129
|
+
/** Count reviews with CHANGES_REQUESTED state */
|
|
130
|
+
function countChangeRequests(reviews) {
|
|
131
|
+
return reviews.filter(r => r.state === 'CHANGES_REQUESTED').length;
|
|
132
|
+
}
|
|
133
|
+
/** Compute time to merge in minutes. Returns null if not merged. */
|
|
134
|
+
function computeTimeToMerge(createdAt, mergedAt) {
|
|
135
|
+
if (!createdAt || !mergedAt)
|
|
136
|
+
return null;
|
|
137
|
+
const created = new Date(createdAt).getTime();
|
|
138
|
+
const merged = new Date(mergedAt).getTime();
|
|
139
|
+
if (isNaN(created) || isNaN(merged))
|
|
140
|
+
return null;
|
|
141
|
+
return Math.round((merged - created) / 60000);
|
|
142
|
+
}
|
|
143
|
+
/** Extract pass/fail counts from statusCheckRollup */
|
|
144
|
+
function extractStatusChecks(rollup) {
|
|
145
|
+
let passed = 0;
|
|
146
|
+
let failed = 0;
|
|
147
|
+
for (const check of rollup) {
|
|
148
|
+
const conclusion = (check.conclusion ?? '').toUpperCase();
|
|
149
|
+
const status = (check.status ?? '').toUpperCase();
|
|
150
|
+
if (conclusion === 'SUCCESS' || conclusion === 'NEUTRAL' || conclusion === 'SKIPPED') {
|
|
151
|
+
passed++;
|
|
152
|
+
}
|
|
153
|
+
else if (conclusion === 'FAILURE' || conclusion === 'TIMED_OUT' || conclusion === 'CANCELLED') {
|
|
154
|
+
failed++;
|
|
155
|
+
}
|
|
156
|
+
else if (status === 'COMPLETED') {
|
|
157
|
+
// No conclusion but completed — count as passed
|
|
158
|
+
passed++;
|
|
159
|
+
}
|
|
160
|
+
else if (status === 'IN_PROGRESS' || status === 'QUEUED' || status === 'PENDING') {
|
|
161
|
+
// Still running — don't count either way
|
|
162
|
+
}
|
|
163
|
+
else if (conclusion) {
|
|
164
|
+
// Unknown conclusion — be conservative, count as failed
|
|
165
|
+
failed++;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return { passed, failed };
|
|
169
|
+
}
|
|
170
|
+
/** Normalize review decision to our union type */
|
|
171
|
+
function normalizeReviewDecision(decision) {
|
|
172
|
+
if (typeof decision !== 'string')
|
|
173
|
+
return 'NONE';
|
|
174
|
+
const upper = decision.toUpperCase();
|
|
175
|
+
const valid = ['APPROVED', 'CHANGES_REQUESTED', 'REVIEW_REQUIRED', 'COMMENTED'];
|
|
176
|
+
return (valid.includes(upper) ? upper : 'NONE');
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=pr-signals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-signals.js","sourceRoot":"","sources":["../../src/core/pr-signals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SprintClaim, SprintConflict } from './types.js';
|
|
2
|
+
/** Async registry for managing sprint claims */
|
|
3
|
+
export interface SprintRegistry {
|
|
4
|
+
claim(claim: Omit<SprintClaim, 'id' | 'claimed_at'>): Promise<SprintClaim>;
|
|
5
|
+
release(id: string): Promise<boolean>;
|
|
6
|
+
list(sprintNumber: number): Promise<SprintClaim[]>;
|
|
7
|
+
get(id: string): Promise<SprintClaim | undefined>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Detect conflicts among a set of sprint claims.
|
|
11
|
+
*
|
|
12
|
+
* Rules:
|
|
13
|
+
* 1. Same target, different players → 'overlap'
|
|
14
|
+
* 2. Area prefix containment (both 'area' scope) → 'adjacent'
|
|
15
|
+
* 3. Ticket target starts with area target (mixed scopes) → 'adjacent'
|
|
16
|
+
*
|
|
17
|
+
* Skips same-player pairs and cross-sprint pairs.
|
|
18
|
+
*/
|
|
19
|
+
export declare function checkConflicts(claims: SprintClaim[]): SprintConflict[];
|
|
20
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE9D,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,YAAY,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAC3E,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACtC,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACnD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;CACnD;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,cAAc,EAAE,CAoDtE"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// SLOPE — Sprint Claims Registry
|
|
2
|
+
// Provides the SprintRegistry interface and pure conflict detection logic.
|
|
3
|
+
/**
|
|
4
|
+
* Detect conflicts among a set of sprint claims.
|
|
5
|
+
*
|
|
6
|
+
* Rules:
|
|
7
|
+
* 1. Same target, different players → 'overlap'
|
|
8
|
+
* 2. Area prefix containment (both 'area' scope) → 'adjacent'
|
|
9
|
+
* 3. Ticket target starts with area target (mixed scopes) → 'adjacent'
|
|
10
|
+
*
|
|
11
|
+
* Skips same-player pairs and cross-sprint pairs.
|
|
12
|
+
*/
|
|
13
|
+
export function checkConflicts(claims) {
|
|
14
|
+
const conflicts = [];
|
|
15
|
+
const seen = new Set();
|
|
16
|
+
for (let i = 0; i < claims.length; i++) {
|
|
17
|
+
for (let j = i + 1; j < claims.length; j++) {
|
|
18
|
+
const a = claims[i];
|
|
19
|
+
const b = claims[j];
|
|
20
|
+
// Skip same player or different sprints
|
|
21
|
+
if (a.player === b.player)
|
|
22
|
+
continue;
|
|
23
|
+
if (a.sprint_number !== b.sprint_number)
|
|
24
|
+
continue;
|
|
25
|
+
let reason = null;
|
|
26
|
+
let severity = null;
|
|
27
|
+
// Rule 1: exact same target
|
|
28
|
+
if (a.target === b.target) {
|
|
29
|
+
reason = `Both ${a.player} and ${b.player} claimed "${a.target}"`;
|
|
30
|
+
severity = 'overlap';
|
|
31
|
+
}
|
|
32
|
+
// Rule 2: area prefix containment (both area scope)
|
|
33
|
+
else if (a.scope === 'area' && b.scope === 'area') {
|
|
34
|
+
if (b.target.startsWith(a.target) || a.target.startsWith(b.target)) {
|
|
35
|
+
const parent = a.target.length <= b.target.length ? a.target : b.target;
|
|
36
|
+
const child = a.target.length <= b.target.length ? b.target : a.target;
|
|
37
|
+
reason = `Area "${child}" is within area "${parent}"`;
|
|
38
|
+
severity = 'adjacent';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Rule 3: ticket target starts with area target (mixed scopes)
|
|
42
|
+
else if (a.scope !== b.scope) {
|
|
43
|
+
const areaClaim = a.scope === 'area' ? a : b;
|
|
44
|
+
const ticketClaim = a.scope === 'area' ? b : a;
|
|
45
|
+
if (ticketClaim.target.startsWith(areaClaim.target)) {
|
|
46
|
+
reason = `Ticket "${ticketClaim.target}" falls within area "${areaClaim.target}"`;
|
|
47
|
+
severity = 'adjacent';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (reason && severity) {
|
|
51
|
+
// Deduplicate by sorted claim IDs
|
|
52
|
+
const key = [a.id, b.id].sort().join(':');
|
|
53
|
+
if (!seen.has(key)) {
|
|
54
|
+
seen.add(key);
|
|
55
|
+
conflicts.push({ claims: [a, b], reason, severity });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return conflicts;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/core/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { GolfScorecard, HandicapCard, DispersionReport, AreaReport, NutritionCategory } from './types.js';
|
|
2
|
+
import type { MetaphorDefinition } from './metaphor.js';
|
|
3
|
+
export interface ReportData {
|
|
4
|
+
generatedAt: string;
|
|
5
|
+
sprintCount: number;
|
|
6
|
+
scorecards: GolfScorecard[];
|
|
7
|
+
handicapCard: HandicapCard;
|
|
8
|
+
dispersion: DispersionReport;
|
|
9
|
+
areaPerformance: AreaReport;
|
|
10
|
+
nutritionTrends: NutritionTrendEntry[];
|
|
11
|
+
sprintTrend: SprintTrendEntry[];
|
|
12
|
+
}
|
|
13
|
+
export interface SprintTrendEntry {
|
|
14
|
+
sprintNumber: number;
|
|
15
|
+
theme: string;
|
|
16
|
+
par: number;
|
|
17
|
+
score: number;
|
|
18
|
+
differential: number;
|
|
19
|
+
fairwayPct: number;
|
|
20
|
+
girPct: number;
|
|
21
|
+
}
|
|
22
|
+
export interface NutritionTrendEntry {
|
|
23
|
+
category: NutritionCategory;
|
|
24
|
+
healthy: number;
|
|
25
|
+
needsAttention: number;
|
|
26
|
+
neglected: number;
|
|
27
|
+
total: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function buildReportData(scorecards: GolfScorecard[]): ReportData;
|
|
30
|
+
export declare function svgLine(data: {
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
}[], width: number, height: number, color: string, strokeWidth?: number): string;
|
|
34
|
+
export declare function svgRect(x: number, y: number, w: number, h: number, fill: string, rx?: number): string;
|
|
35
|
+
export declare function svgText(x: number, y: number, text: string, opts?: {
|
|
36
|
+
anchor?: string;
|
|
37
|
+
size?: number;
|
|
38
|
+
fill?: string;
|
|
39
|
+
weight?: string;
|
|
40
|
+
}): string;
|
|
41
|
+
export declare function renderHandicapTrendChart(trend: SprintTrendEntry[], metaphor?: MetaphorDefinition): string;
|
|
42
|
+
export declare function renderDispersionChart(dispersion: DispersionReport, metaphor?: MetaphorDefinition): string;
|
|
43
|
+
export declare function renderAreaPerformanceChart(area: AreaReport, metaphor?: MetaphorDefinition): string;
|
|
44
|
+
export declare function renderNutritionChart(trends: NutritionTrendEntry[], metaphor?: MetaphorDefinition): string;
|
|
45
|
+
export declare function renderSummaryCards(data: ReportData, metaphor?: MetaphorDefinition): string;
|
|
46
|
+
export declare function renderSprintTable(trend: SprintTrendEntry[], metaphor?: MetaphorDefinition): string;
|
|
47
|
+
export declare const REPORT_CSS: string;
|
|
48
|
+
export declare function generateHtmlReport(data: ReportData, metaphor?: MetaphorDefinition): string;
|
|
49
|
+
export declare function escapeHtml(s: string): string;
|
|
50
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/core/report.ts"],"names":[],"mappings":"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"}
|