@azure-id/orc 0.55.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/CHANGELOG.md +2017 -0
- package/README-id.md +521 -0
- package/README.md +485 -0
- package/bin/build-agents.js +86 -0
- package/bin/cli.js +29050 -0
- package/bin/mockrun-catalog.js +267 -0
- package/bin/onboarding-content.js +172 -0
- package/bin/pricing.json +200 -0
- package/bin/providers.json +437 -0
- package/bin/ui.js +95 -0
- package/bin/verify-contracts.js +3277 -0
- package/bin/verify-package.js +498 -0
- package/bin/webui/api.js +1163 -0
- package/bin/webui/app.html +198 -0
- package/bin/webui/css/00-tokens.css +92 -0
- package/bin/webui/css/01-base.css +42 -0
- package/bin/webui/css/02-shell.css +103 -0
- package/bin/webui/css/03-components.css +462 -0
- package/bin/webui/css/04-motion.css +91 -0
- package/bin/webui/css/05-tour.css +100 -0
- package/bin/webui/css/06-responsive.css +108 -0
- package/bin/webui/css/panels/boundary.css +26 -0
- package/bin/webui/css/panels/challenge.css +151 -0
- package/bin/webui/css/panels/crosslink.css +194 -0
- package/bin/webui/css/panels/docs.css +254 -0
- package/bin/webui/css/panels/experiment.css +23 -0
- package/bin/webui/css/panels/extra.css +536 -0
- package/bin/webui/css/panels/flow.css +177 -0
- package/bin/webui/css/panels/handoff.css +67 -0
- package/bin/webui/css/panels/knowledge.css +86 -0
- package/bin/webui/css/panels/learn.css +154 -0
- package/bin/webui/css/panels/maintenance.css +55 -0
- package/bin/webui/css/panels/mockrun.css +268 -0
- package/bin/webui/css/panels/overview.css +100 -0
- package/bin/webui/css/panels/pact.css +43 -0
- package/bin/webui/css/panels/runs.css +105 -0
- package/bin/webui/css/panels/settings.css +227 -0
- package/bin/webui/css/panels/stats.css +87 -0
- package/bin/webui/fixtures/boundary.js +92 -0
- package/bin/webui/fixtures/challenge.js +825 -0
- package/bin/webui/fixtures/crosslink.js +31 -0
- package/bin/webui/fixtures/docs.js +982 -0
- package/bin/webui/fixtures/extra.js +1934 -0
- package/bin/webui/fixtures/flow.js +81 -0
- package/bin/webui/fixtures/handoff.js +35 -0
- package/bin/webui/fixtures/index.js +486 -0
- package/bin/webui/fixtures/knowledge.js +291 -0
- package/bin/webui/fixtures/maintenance.js +42 -0
- package/bin/webui/fixtures/mockrun.js +36 -0
- package/bin/webui/fixtures/pact.js +111 -0
- package/bin/webui/fixtures/runs.js +109 -0
- package/bin/webui/fixtures/settings.js +78 -0
- package/bin/webui/fixtures/shell.js +48 -0
- package/bin/webui/fixtures/stats.js +104 -0
- package/bin/webui/i18n/TERMS.md +134 -0
- package/bin/webui/i18n/en/banner.json +29 -0
- package/bin/webui/i18n/en/boundary.json +20 -0
- package/bin/webui/i18n/en/challenge.json +106 -0
- package/bin/webui/i18n/en/common.json +69 -0
- package/bin/webui/i18n/en/crosslink.json +69 -0
- package/bin/webui/i18n/en/docs.json +175 -0
- package/bin/webui/i18n/en/experiment.json +17 -0
- package/bin/webui/i18n/en/extra.json +313 -0
- package/bin/webui/i18n/en/flow.json +30 -0
- package/bin/webui/i18n/en/handoff.json +37 -0
- package/bin/webui/i18n/en/knowledge.json +141 -0
- package/bin/webui/i18n/en/learn.json +16 -0
- package/bin/webui/i18n/en/maintenance.json +52 -0
- package/bin/webui/i18n/en/mockrun.json +19 -0
- package/bin/webui/i18n/en/nav.json +19 -0
- package/bin/webui/i18n/en/overview.json +89 -0
- package/bin/webui/i18n/en/pact.json +36 -0
- package/bin/webui/i18n/en/runs.json +51 -0
- package/bin/webui/i18n/en/settings.json +49 -0
- package/bin/webui/i18n/en/stats.json +69 -0
- package/bin/webui/i18n/en/tour.json +33 -0
- package/bin/webui/i18n/id/banner.json +29 -0
- package/bin/webui/i18n/id/boundary.json +20 -0
- package/bin/webui/i18n/id/challenge.json +106 -0
- package/bin/webui/i18n/id/common.json +70 -0
- package/bin/webui/i18n/id/crosslink.json +69 -0
- package/bin/webui/i18n/id/docs.json +175 -0
- package/bin/webui/i18n/id/experiment.json +17 -0
- package/bin/webui/i18n/id/extra.json +313 -0
- package/bin/webui/i18n/id/flow.json +30 -0
- package/bin/webui/i18n/id/handoff.json +37 -0
- package/bin/webui/i18n/id/knowledge.json +141 -0
- package/bin/webui/i18n/id/learn.json +16 -0
- package/bin/webui/i18n/id/maintenance.json +52 -0
- package/bin/webui/i18n/id/mockrun.json +19 -0
- package/bin/webui/i18n/id/nav.json +19 -0
- package/bin/webui/i18n/id/overview.json +89 -0
- package/bin/webui/i18n/id/pact.json +36 -0
- package/bin/webui/i18n/id/runs.json +51 -0
- package/bin/webui/i18n/id/settings.json +49 -0
- package/bin/webui/i18n/id/stats.json +69 -0
- package/bin/webui/i18n/id/tour.json +33 -0
- package/bin/webui/js/00-core.js +115 -0
- package/bin/webui/js/01-i18n.js +149 -0
- package/bin/webui/js/02-ui.js +211 -0
- package/bin/webui/js/03-md.js +286 -0
- package/bin/webui/js/04-router.js +51 -0
- package/bin/webui/js/05-banners.js +172 -0
- package/bin/webui/js/06-edit.js +183 -0
- package/bin/webui/js/90-tour.js +488 -0
- package/bin/webui/js/91-shortcuts.js +126 -0
- package/bin/webui/js/99-boot.js +118 -0
- package/bin/webui/js/panels/boundary.js +104 -0
- package/bin/webui/js/panels/challenge.js +781 -0
- package/bin/webui/js/panels/crosslink.js +654 -0
- package/bin/webui/js/panels/docs.js +1338 -0
- package/bin/webui/js/panels/experiment.js +98 -0
- package/bin/webui/js/panels/extra.js +3011 -0
- package/bin/webui/js/panels/flow.js +297 -0
- package/bin/webui/js/panels/handoff.js +169 -0
- package/bin/webui/js/panels/knowledge.js +890 -0
- package/bin/webui/js/panels/learn.js +220 -0
- package/bin/webui/js/panels/maintenance.js +235 -0
- package/bin/webui/js/panels/mockrun.js +227 -0
- package/bin/webui/js/panels/overview.js +447 -0
- package/bin/webui/js/panels/pact.js +189 -0
- package/bin/webui/js/panels/runs.js +416 -0
- package/bin/webui/js/panels/settings.js +573 -0
- package/bin/webui/js/panels/stats.js +378 -0
- package/bin/webui/serve.js +557 -0
- package/mock-run/INDEX.md +106 -0
- package/mock-run/a-normal-day.md +587 -0
- package/mock-run/context-combiner.md +100 -0
- package/mock-run/extra-recovery.md +330 -0
- package/mock-run/extra-slots.md +177 -0
- package/mock-run/media/README.md +43 -0
- package/mock-run/orc-aftermath.md +392 -0
- package/mock-run/orc-boundary.md +356 -0
- package/mock-run/orc-brainstorm.md +177 -0
- package/mock-run/orc-budget.md +534 -0
- package/mock-run/orc-challenge-council.md +262 -0
- package/mock-run/orc-challenge.md +416 -0
- package/mock-run/orc-cli.md +200 -0
- package/mock-run/orc-diy.md +129 -0
- package/mock-run/orc-doc.md +448 -0
- package/mock-run/orc-explain.md +86 -0
- package/mock-run/orc-export.md +423 -0
- package/mock-run/orc-extra.md +392 -0
- package/mock-run/orc-fast.md +106 -0
- package/mock-run/orc-grill.md +151 -0
- package/mock-run/orc-handoff.md +480 -0
- package/mock-run/orc-pact.md +421 -0
- package/mock-run/orc-pattern.md +112 -0
- package/mock-run/orc-plan.md +108 -0
- package/mock-run/orc-pr-setup.md +126 -0
- package/mock-run/orc-quick.md +113 -0
- package/mock-run/orc-route.md +93 -0
- package/mock-run/orc-ui.md +125 -0
- package/mock-run/orc-ultra.md +103 -0
- package/mock-run/orc.md +157 -0
- package/mock-run/the-example-project.md +55 -0
- package/package.json +39 -0
- package/templates/agents/MODEL-MAPPING.md +168 -0
- package/templates/agents/orc-advisor-fable-5.md +50 -0
- package/templates/agents/orc-advisor-opus-5-xhigh.md +56 -0
- package/templates/agents/orc-analyst-fable-5.md +115 -0
- package/templates/agents/orc-analyze-mini-opus-5-med.md +60 -0
- package/templates/agents/orc-analyze-mini-sonnet-5-high.md +58 -0
- package/templates/agents/orc-challenge-advisor-opus-5-med.md +75 -0
- package/templates/agents/orc-challenge-contrarian-opus-5-high.md +110 -0
- package/templates/agents/orc-challenge-executor-opus-5-med.md +114 -0
- package/templates/agents/orc-challenge-expansionist-opus-5-med.md +112 -0
- package/templates/agents/orc-challenge-judge-opus-5-high.md +132 -0
- package/templates/agents/orc-challenge-outsider-opus-5-low.md +109 -0
- package/templates/agents/orc-challenge-principles-opus-5-high.md +109 -0
- package/templates/agents/orc-challenge-reader-opus-5-low.md +90 -0
- package/templates/agents/orc-claude-writer-opus-4-8-high.md +53 -0
- package/templates/agents/orc-claude-writer-opus-5-med.md +55 -0
- package/templates/agents/orc-context-combiner-opus-5-high.md +88 -0
- package/templates/agents/orc-doc-checker-opus-5-low.md +108 -0
- package/templates/agents/orc-doc-writer-opus-5-med.md +134 -0
- package/templates/agents/orc-executor-haiku-4-5.md +113 -0
- package/templates/agents/orc-executor-opus-4-7-high.md +114 -0
- package/templates/agents/orc-executor-opus-4-7-med.md +114 -0
- package/templates/agents/orc-executor-opus-4-8-high.md +114 -0
- package/templates/agents/orc-executor-opus-5-high.md +114 -0
- package/templates/agents/orc-executor-opus-5-low.md +114 -0
- package/templates/agents/orc-executor-opus-5-med.md +114 -0
- package/templates/agents/orc-executor-sonnet-4-6-high.md +114 -0
- package/templates/agents/orc-executor-sonnet-4-6-med.md +114 -0
- package/templates/agents/orc-executor-sonnet-5-high.md +114 -0
- package/templates/agents/orc-judge-fable-5.md +79 -0
- package/templates/agents/orc-judge-opus-5-xhigh.md +85 -0
- package/templates/agents/orc-learn-writer-opus-5-low.md +73 -0
- package/templates/agents/orc-pattern-codifier-opus-5-med.md +65 -0
- package/templates/agents/orc-pattern-codifier-sonnet-5-high.md +63 -0
- package/templates/agents/orc-planner-fable-5.md +152 -0
- package/templates/agents/orc-planner-mini-opus-5-med.md +69 -0
- package/templates/agents/orc-planner-mini-sonnet-5-high.md +67 -0
- package/templates/agents/orc-planner-opus-5-med.md +160 -0
- package/templates/agents/orc-retro-opus-5-med.md +73 -0
- package/templates/agents/orc-retro-sonnet-5-high.md +72 -0
- package/templates/agents/orc-reviewer-fable-5.md +57 -0
- package/templates/agents/orc-reviewer-opus-5-med.md +60 -0
- package/templates/agents/orc-scout-opus-5-low.md +40 -0
- package/templates/agents/orc-scout-sonnet-4-6-high.md +39 -0
- package/templates/agents/orc-system-analyst-opus-5-high.md +120 -0
- package/templates/agents/orc-test-author-opus-5-med.md +71 -0
- package/templates/agents/orc-trace-writer-haiku-4-5.md +107 -0
- package/templates/agents/orc-verifier-opus-5-med.md +69 -0
- package/templates/agents/orc-wiki-scanner-opus-4-8-high.md +79 -0
- package/templates/agents/orc-wiki-scanner-opus-5-med.md +81 -0
- package/templates/agents/orc-wiki-scanner-sonnet-5-high.md +106 -0
- package/templates/commands/orc-aftermath.md +49 -0
- package/templates/commands/orc-analyze.md +21 -0
- package/templates/commands/orc-boundary.md +46 -0
- package/templates/commands/orc-brainstorm.md +51 -0
- package/templates/commands/orc-budget.md +54 -0
- package/templates/commands/orc-challenge.md +58 -0
- package/templates/commands/orc-claude.md +14 -0
- package/templates/commands/orc-diy.md +13 -0
- package/templates/commands/orc-doc.md +128 -0
- package/templates/commands/orc-explain.md +20 -0
- package/templates/commands/orc-export.md +46 -0
- package/templates/commands/orc-fast.md +15 -0
- package/templates/commands/orc-grill.md +40 -0
- package/templates/commands/orc-handoff.md +52 -0
- package/templates/commands/orc-learn.md +17 -0
- package/templates/commands/orc-mini.md +12 -0
- package/templates/commands/orc-pact.md +44 -0
- package/templates/commands/orc-pattern.md +15 -0
- package/templates/commands/orc-plan.md +22 -0
- package/templates/commands/orc-poly.md +21 -0
- package/templates/commands/orc-pr-driver.md +30 -0
- package/templates/commands/orc-pr-setup.md +31 -0
- package/templates/commands/orc-quick.md +33 -0
- package/templates/commands/orc-retro.md +17 -0
- package/templates/commands/orc-route.md +41 -0
- package/templates/commands/orc-ultra.md +17 -0
- package/templates/commands/orc-verify.md +11 -0
- package/templates/commands/orc-wiki.md +42 -0
- package/templates/commands/orc.md +16 -0
- package/templates/hooks/orc-effort-guard.js +178 -0
- package/templates/hooks/orc-statusline.js +305 -0
- package/templates/hooks/orc-trace.js +471 -0
- package/templates/hooks/orc-update-lib.js +125 -0
- package/templates/skills/_shared/README.md +50 -0
- package/templates/skills/_shared/detecting-artifacts.md +90 -0
- package/templates/skills/_shared/drift-recovery.md +98 -0
- package/templates/skills/_shared/extra-dispatch.md +1051 -0
- package/templates/skills/_shared/fable5-override.md +56 -0
- package/templates/skills/_shared/fallback-handoff.md +42 -0
- package/templates/skills/_shared/gh-stack-commands.md +65 -0
- package/templates/skills/_shared/gotchas.md +177 -0
- package/templates/skills/_shared/interview.md +144 -0
- package/templates/skills/_shared/lane-suspend.md +82 -0
- package/templates/skills/_shared/opus5-only.md +131 -0
- package/templates/skills/_shared/pr-templates.md +106 -0
- package/templates/skills/_shared/read-ladder.md +54 -0
- package/templates/skills/_shared/return-validation.md +145 -0
- package/templates/skills/_shared/smoke-gate.md +28 -0
- package/templates/skills/_shared/stack-plan.md +135 -0
- package/templates/skills/_shared/untrusted-input.md +63 -0
- package/templates/skills/context-combiner/SKILL.md +187 -0
- package/templates/skills/context-combiner/schemas/combined-report.md +78 -0
- package/templates/skills/context-combiner/schemas/combined-requirement-spec.md +87 -0
- package/templates/skills/orc/README.md +150 -0
- package/templates/skills/orc/SKILL.md +526 -0
- package/templates/skills/orc/config.md +389 -0
- package/templates/skills/orc/examples/full-run-mock.md +73 -0
- package/templates/skills/orc/references/analyst-gates.md +124 -0
- package/templates/skills/orc/references/effort-and-mode.md +224 -0
- package/templates/skills/orc/references/house-rules.md +20 -0
- package/templates/skills/orc/references/intake.md +120 -0
- package/templates/skills/orc/references/log-protocol.md +39 -0
- package/templates/skills/orc/references/pattern-gate.md +89 -0
- package/templates/skills/orc/references/plan-handoff.md +84 -0
- package/templates/skills/orc/references/preflight-report.md +220 -0
- package/templates/skills/orc/references/security-checklist.md +39 -0
- package/templates/skills/orc/references/stop-and-resume.md +160 -0
- package/templates/skills/orc/references/trace-protocol.md +314 -0
- package/templates/skills/orc/references/ultra-mode.md +123 -0
- package/templates/skills/orc/references/wave-grouping.md +121 -0
- package/templates/skills/orc/references/wiki-consult.md +177 -0
- package/templates/skills/orc/schemas/checkpoint.md +122 -0
- package/templates/skills/orc/schemas/intent-spec.md +42 -0
- package/templates/skills/orc/schemas/planning-output.md +279 -0
- package/templates/skills/orc/subskills/orc-checkpoint/SKILL.md +55 -0
- package/templates/skills/orc/subskills/orc-execution/SKILL.md +72 -0
- package/templates/skills/orc/subskills/orc-execution/core.md +151 -0
- package/templates/skills/orc/subskills/orc-execution/subagent.md +13 -0
- package/templates/skills/orc/subskills/orc-planner/SKILL.md +264 -0
- package/templates/skills/orc/subskills/orc-planner-mini/SKILL.md +121 -0
- package/templates/skills/orc/subskills/orc-pr/SKILL.md +51 -0
- package/templates/skills/orc/subskills/orc-pr/pr.md +22 -0
- package/templates/skills/orc/subskills/orc-pr/stack-gate.md +108 -0
- package/templates/skills/orc/subskills/orc-review-verify/SKILL.md +76 -0
- package/templates/skills/orc/subskills/orc-review-verify/core.md +135 -0
- package/templates/skills/orc/subskills/orc-review-verify/subagent.md +7 -0
- package/templates/skills/orc/subskills/orc-testgen/SKILL.md +45 -0
- package/templates/skills/orc/subskills/orc-testgen/core.md +59 -0
- package/templates/skills/orc/subskills/orc-testgen/subagent.md +7 -0
- package/templates/skills/orc-advisor/SKILL.md +60 -0
- package/templates/skills/orc-aftermath/SKILL.md +136 -0
- package/templates/skills/orc-aftermath/references/report.md +95 -0
- package/templates/skills/orc-analyze/SKILL.md +220 -0
- package/templates/skills/orc-analyze/examples/analyze-mock.md +42 -0
- package/templates/skills/orc-analyze/references/branching.md +51 -0
- package/templates/skills/orc-analyze/references/deep-mode.md +27 -0
- package/templates/skills/orc-analyze/references/thin-input.md +77 -0
- package/templates/skills/orc-analyze/schemas/report-audit.md +83 -0
- package/templates/skills/orc-analyze/schemas/report-prose.md +63 -0
- package/templates/skills/orc-analyze/schemas/report-requirement.md +78 -0
- package/templates/skills/orc-analyze/schemas/requirement-spec.md +77 -0
- package/templates/skills/orc-analyze-mini/SKILL.md +112 -0
- package/templates/skills/orc-analyze-mini/examples/quick-analysis-mock.md +31 -0
- package/templates/skills/orc-boundary/SKILL.md +208 -0
- package/templates/skills/orc-boundary/references/card.md +78 -0
- package/templates/skills/orc-boundary/references/gate.md +113 -0
- package/templates/skills/orc-brainstorm/SKILL.md +339 -0
- package/templates/skills/orc-brainstorm/references/brainstorm-doc.md +133 -0
- package/templates/skills/orc-brainstorm/references/lenses.md +152 -0
- package/templates/skills/orc-budget/SKILL.md +225 -0
- package/templates/skills/orc-budget/references/corpus.md +87 -0
- package/templates/skills/orc-challenge/README.md +142 -0
- package/templates/skills/orc-challenge/SKILL.md +255 -0
- package/templates/skills/orc-challenge/examples/code-module.md +110 -0
- package/templates/skills/orc-challenge/examples/council-full-roster.md +273 -0
- package/templates/skills/orc-challenge/examples/tsd-two-iterations.md +213 -0
- package/templates/skills/orc-challenge/references/conservation.md +107 -0
- package/templates/skills/orc-challenge/references/council.md +315 -0
- package/templates/skills/orc-challenge/references/cycle-state.md +185 -0
- package/templates/skills/orc-challenge/references/dimensions.md +121 -0
- package/templates/skills/orc-challenge/references/fix-brief.md +130 -0
- package/templates/skills/orc-challenge/references/intake.md +171 -0
- package/templates/skills/orc-challenge/references/kinds.md +44 -0
- package/templates/skills/orc-challenge/references/plain-english.md +98 -0
- package/templates/skills/orc-challenge/references/rubric.md +109 -0
- package/templates/skills/orc-challenge/references/sealed-slice.md +97 -0
- package/templates/skills/orc-challenge/references/verdict-doc.md +154 -0
- package/templates/skills/orc-claude/SKILL.md +199 -0
- package/templates/skills/orc-claude/examples/claude-run-mock.md +65 -0
- package/templates/skills/orc-claude/references/refresh.md +76 -0
- package/templates/skills/orc-claude/references/template.md +109 -0
- package/templates/skills/orc-diy/README.md +142 -0
- package/templates/skills/orc-diy/SKILL.md +70 -0
- package/templates/skills/orc-diy/references/blocks/analyze.md +24 -0
- package/templates/skills/orc-diy/references/blocks/execution.md +42 -0
- package/templates/skills/orc-diy/references/blocks/extra.md +55 -0
- package/templates/skills/orc-diy/references/blocks/header.md +55 -0
- package/templates/skills/orc-diy/references/blocks/mock-example.md +22 -0
- package/templates/skills/orc-diy/references/blocks/pattern.md +18 -0
- package/templates/skills/orc-diy/references/blocks/planning.md +34 -0
- package/templates/skills/orc-diy/references/blocks/review.md +18 -0
- package/templates/skills/orc-diy/references/blocks/scoring.md +16 -0
- package/templates/skills/orc-diy/references/blocks/security.md +25 -0
- package/templates/skills/orc-diy/references/blocks/ship.md +25 -0
- package/templates/skills/orc-diy/references/blocks/summary.md +18 -0
- package/templates/skills/orc-diy/references/blocks/testgen.md +17 -0
- package/templates/skills/orc-diy/references/blocks/trace.md +28 -0
- package/templates/skills/orc-diy/references/blocks/verify.md +25 -0
- package/templates/skills/orc-diy/references/blocks/wiki.md +26 -0
- package/templates/skills/orc-diy/references/compile.md +59 -0
- package/templates/skills/orc-diy/references/flow-schema.md +100 -0
- package/templates/skills/orc-diy/references/locked-blocks.md +37 -0
- package/templates/skills/orc-doc/README.md +229 -0
- package/templates/skills/orc-doc/SKILL.md +444 -0
- package/templates/skills/orc-doc/examples/orc-doc-prd-run.md +325 -0
- package/templates/skills/orc-doc/references/chunking.md +527 -0
- package/templates/skills/orc-doc/references/gates.md +311 -0
- package/templates/skills/orc-doc/references/generation-rules.md +122 -0
- package/templates/skills/orc-doc/references/house-rules.md +170 -0
- package/templates/skills/orc-doc/references/import-targets.md +40 -0
- package/templates/skills/orc-doc/references/plain-language.md +66 -0
- package/templates/skills/orc-doc/references/portable-markdown.md +74 -0
- package/templates/skills/orc-doc/references/resume-protocol.md +228 -0
- package/templates/skills/orc-doc/references/templates/collaboration.md +118 -0
- package/templates/skills/orc-doc/references/templates/prd.md +133 -0
- package/templates/skills/orc-doc/references/templates/report.md +102 -0
- package/templates/skills/orc-doc/references/templates/tsd.md +122 -0
- package/templates/skills/orc-doc/references/templates/workflow.md +112 -0
- package/templates/skills/orc-explain/SKILL.md +57 -0
- package/templates/skills/orc-export/SKILL.md +154 -0
- package/templates/skills/orc-fast/SKILL.md +188 -0
- package/templates/skills/orc-grill/SKILL.md +207 -0
- package/templates/skills/orc-grill/references/grill-doc.md +105 -0
- package/templates/skills/orc-handoff/SKILL.md +204 -0
- package/templates/skills/orc-handoff/references/handoff-log.md +67 -0
- package/templates/skills/orc-handoff/references/surfaces.md +88 -0
- package/templates/skills/orc-judge/SKILL.md +82 -0
- package/templates/skills/orc-learn/SKILL.md +156 -0
- package/templates/skills/orc-learn/examples/learn-run-mock.md +61 -0
- package/templates/skills/orc-learn/references/deepen.md +70 -0
- package/templates/skills/orc-learn/references/refresh.md +65 -0
- package/templates/skills/orc-learn/references/template-knowledge.md +83 -0
- package/templates/skills/orc-learn/references/template-learning.md +67 -0
- package/templates/skills/orc-mini/SKILL.md +226 -0
- package/templates/skills/orc-mini/examples/mini-run-mock.md +50 -0
- package/templates/skills/orc-pact/SKILL.md +218 -0
- package/templates/skills/orc-pact/references/gate.md +70 -0
- package/templates/skills/orc-pact/references/ledger.md +99 -0
- package/templates/skills/orc-pattern/SKILL.md +124 -0
- package/templates/skills/orc-pattern/references/INDEX.md +73 -0
- package/templates/skills/orc-pattern/references/be-django.md +80 -0
- package/templates/skills/orc-pattern/references/be-express.md +82 -0
- package/templates/skills/orc-pattern/references/be-fastapi.md +107 -0
- package/templates/skills/orc-pattern/references/be-go.md +96 -0
- package/templates/skills/orc-pattern/references/be-nestjs.md +86 -0
- package/templates/skills/orc-pattern/references/be-postgres.md +98 -0
- package/templates/skills/orc-pattern/references/fe-a11y.md +36 -0
- package/templates/skills/orc-pattern/references/fe-angular.md +87 -0
- package/templates/skills/orc-pattern/references/fe-nextjs.md +65 -0
- package/templates/skills/orc-pattern/references/fe-perf.md +39 -0
- package/templates/skills/orc-pattern/references/fe-react.md +83 -0
- package/templates/skills/orc-pattern/references/fe-vue.md +75 -0
- package/templates/skills/orc-pattern/schemas/pattern-doc.md +62 -0
- package/templates/skills/orc-poly/SKILL.md +216 -0
- package/templates/skills/orc-poly/examples/poly-run-mock.md +51 -0
- package/templates/skills/orc-poly/references/gather.md +70 -0
- package/templates/skills/orc-poly/references/poly-spec.md +84 -0
- package/templates/skills/orc-pr-driver/README.md +349 -0
- package/templates/skills/orc-pr-driver/SKILL.md +167 -0
- package/templates/skills/orc-pr-driver/references/conflict-playbook.md +78 -0
- package/templates/skills/orc-pr-driver/references/green-gate.md +105 -0
- package/templates/skills/orc-pr-driver/references/orc-run-split.md +99 -0
- package/templates/skills/orc-pr-setup/README.md +436 -0
- package/templates/skills/orc-pr-setup/SKILL.md +184 -0
- package/templates/skills/orc-pr-setup/references/certainty-gate.md +66 -0
- package/templates/skills/orc-pr-setup/references/layer-taxonomy.md +67 -0
- package/templates/skills/orc-quick/README.md +423 -0
- package/templates/skills/orc-quick/SKILL.md +306 -0
- package/templates/skills/orc-quick/references/context-doc.md +114 -0
- package/templates/skills/orc-quick/references/dispatch-gate.md +163 -0
- package/templates/skills/orc-quick/references/gh-mode.md +127 -0
- package/templates/skills/orc-retro/SKILL.md +222 -0
- package/templates/skills/orc-retro/examples/retro-mock.md +171 -0
- package/templates/skills/orc-route/SKILL.md +165 -0
- package/templates/skills/orc-verify/SKILL.md +86 -0
- package/templates/skills/orc-verify/examples/verify-mock.md +33 -0
- package/templates/skills/orc-wiki/README.md +325 -0
- package/templates/skills/orc-wiki/SKILL.md +322 -0
- package/templates/skills/orc-wiki/examples/wiki-run-mock.md +37 -0
- package/templates/skills/orc-wiki/references/claude-md-injection.md +61 -0
- package/templates/skills/orc-wiki/references/crosslink-compile.md +39 -0
- package/templates/skills/orc-wiki/references/crosslink-kinds.md +57 -0
- package/templates/skills/orc-wiki/references/crosslink.md +284 -0
- package/templates/skills/orc-wiki/references/extra.md +79 -0
- package/templates/skills/orc-wiki/references/integrity-check.md +86 -0
- package/templates/skills/orc-wiki/references/orientation.md +51 -0
- package/templates/skills/orc-wiki/references/partial-refresh.md +203 -0
- package/templates/skills/orc-wiki/references/pattern-prewarm.md +19 -0
- package/templates/skills/orc-wiki/references/staleness.md +288 -0
- package/templates/skills/orc-wiki/schemas/crosslink-tag.md +166 -0
- package/templates/skills/orc-wiki/schemas/wiki-doc.md +120 -0
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* panels/challenge.js — orc ui client
|
|
3
|
+
The iteration timeline, the convergence chart, the findings.
|
|
4
|
+
|
|
5
|
+
Loaded by app.html in the order its numeric prefix names. Classic
|
|
6
|
+
script, no import/export: an ES module import carries no query string,
|
|
7
|
+
and every static request here needs the per-launch session token. */
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
PANELS.challenge = function (host) {
|
|
11
|
+
head(host, t("challenge.title"), t("challenge.sub"));
|
|
12
|
+
const body = el("div", "stack");
|
|
13
|
+
host.append(body);
|
|
14
|
+
renderChallenge(body);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
async function renderChallenge(body) {
|
|
18
|
+
body.replaceChildren(skeleton(5));
|
|
19
|
+
let d;
|
|
20
|
+
try {
|
|
21
|
+
d = (await read("/api/challenge")).data;
|
|
22
|
+
} catch (e) {
|
|
23
|
+
body.replaceChildren(failBox(e));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const out = frag();
|
|
27
|
+
|
|
28
|
+
if (!d || !d.cycles || !d.cycles.length) {
|
|
29
|
+
const c = card(t("challenge.title"));
|
|
30
|
+
c.append(empty(t("challenge.none"), t("challenge.noneHint")));
|
|
31
|
+
c.append(laneCommand("/orc-challenge", t("challenge.cmdWhy")));
|
|
32
|
+
out.append(c);
|
|
33
|
+
body.replaceChildren(out);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const sum = card(t("challenge.summary"));
|
|
38
|
+
const chips = el("div", "row-actions");
|
|
39
|
+
for (const s of Object.keys(CH_STATE_KIND)) {
|
|
40
|
+
const n = d.cycles.filter((c) => c.state === s).length;
|
|
41
|
+
if (!n) continue;
|
|
42
|
+
chips.append(chip(`${n} ${s}`, CH_STATE_KIND[s], s === CH_PULSE));
|
|
43
|
+
}
|
|
44
|
+
sum.append(chips);
|
|
45
|
+
sum.append(el("div", "note", t("challenge.contract")));
|
|
46
|
+
out.append(sum);
|
|
47
|
+
|
|
48
|
+
const list = el("div", "run-list ch-list");
|
|
49
|
+
const rows = [];
|
|
50
|
+
const setOpen = (entry, open) => {
|
|
51
|
+
entry.row.classList.toggle("open", open);
|
|
52
|
+
entry.head.setAttribute("aria-expanded", String(open));
|
|
53
|
+
if (open && !entry.loaded) {
|
|
54
|
+
entry.loaded = true;
|
|
55
|
+
loadChallengeDetail(entry.pane, entry.slug, body);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
const collapseAll = (except) => {
|
|
59
|
+
for (const r of rows) if (r.row !== except) setOpen(r, false);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
for (const c of d.cycles) {
|
|
63
|
+
const row = el("div", "run-row");
|
|
64
|
+
const headBtn = el("button", "run-card");
|
|
65
|
+
headBtn.type = "button";
|
|
66
|
+
headBtn.setAttribute("aria-expanded", "false");
|
|
67
|
+
headBtn.append(el("span", "run-caret", "▸"));
|
|
68
|
+
// The CLI's own state words. Never a friendlier synonym.
|
|
69
|
+
headBtn.append(chip(c.state, CH_STATE_KIND[c.state] || "", c.state === CH_PULSE));
|
|
70
|
+
if (c.stalled) headBtn.append(chip(t("challenge.stalledChip"), "warn"));
|
|
71
|
+
if (c.no_template) headBtn.append(chip(t("challenge.noTemplateChip"), "warn"));
|
|
72
|
+
const mid = el("div", "run-mid");
|
|
73
|
+
mid.append(el("div", "run-slug", c.slug));
|
|
74
|
+
mid.append(el("div", "run-where", `${c.kind} · ${tn(c.iterations, "challenge.iterN")}`));
|
|
75
|
+
headBtn.append(mid);
|
|
76
|
+
headBtn.append(el("div", "run-age", c.blocking ? tn(c.blocking, "challenge.blockingN") : t("challenge.noBlocking")));
|
|
77
|
+
|
|
78
|
+
const pane = el("div", "run-pane stack stack-sm");
|
|
79
|
+
pane.append(skeleton(4));
|
|
80
|
+
const inner = el("div", "run-body-inner");
|
|
81
|
+
inner.append(pane);
|
|
82
|
+
const fold = el("div", "run-body");
|
|
83
|
+
fold.append(inner);
|
|
84
|
+
|
|
85
|
+
const entry = { row, head: headBtn, pane, slug: c.slug, loaded: false };
|
|
86
|
+
rows.push(entry);
|
|
87
|
+
headBtn.addEventListener("click", () => {
|
|
88
|
+
const isOpen = row.classList.contains("open");
|
|
89
|
+
collapseAll(row);
|
|
90
|
+
setOpen(entry, !isOpen);
|
|
91
|
+
});
|
|
92
|
+
row.append(headBtn, fold);
|
|
93
|
+
list.append(row);
|
|
94
|
+
}
|
|
95
|
+
out.append(list);
|
|
96
|
+
out.append(laneCommand("/orc-challenge", t("challenge.cmdWhy")));
|
|
97
|
+
body.replaceChildren(out);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// PROGRESSIVE DISCLOSURE, in the order a human reads: the goal, then the state
|
|
101
|
+
// and the timeline, then the reader's score and the dimension strip, then the
|
|
102
|
+
// findings, then the raw verdict last and collapsed. Nobody should have to
|
|
103
|
+
// scroll past a wall of findings to learn what the document was for.
|
|
104
|
+
async function loadChallengeDetail(pane, slug, body) {
|
|
105
|
+
let s;
|
|
106
|
+
let show = null;
|
|
107
|
+
let diff = null;
|
|
108
|
+
let roles = null;
|
|
109
|
+
try {
|
|
110
|
+
s = (await read("/api/challenge/one?slug=" + encodeURIComponent(slug))).data;
|
|
111
|
+
show = (await read("/api/challenge/show?slug=" + encodeURIComponent(slug)).catch(() => ({ data: null }))).data;
|
|
112
|
+
diff = (await read("/api/challenge/diff?slug=" + encodeURIComponent(slug)).catch(() => ({ data: null }))).data;
|
|
113
|
+
// THE CATALOGUE. The panel names no lens, no class and no disposition
|
|
114
|
+
// itself — it draws what `orc challenge roles --json` returns, exactly as
|
|
115
|
+
// the Flow stepper draws `orc diy show --json`'s steps[].
|
|
116
|
+
roles = (await read("/api/challenge/roles").catch(() => ({ data: null }))).data;
|
|
117
|
+
} catch (e) {
|
|
118
|
+
pane.replaceChildren(failBox(e));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const out = frag();
|
|
122
|
+
|
|
123
|
+
// --- 1. the goal block, ABOVE everything. It is the first thing a reader
|
|
124
|
+
// needs in order to read anything below it.
|
|
125
|
+
const g = card(t("challenge.goalTitle") + " v" + s.goals.version);
|
|
126
|
+
g.append(
|
|
127
|
+
kvList([
|
|
128
|
+
[t("challenge.field.goal"), s.goals.goal],
|
|
129
|
+
[t("challenge.field.audience"), s.goals.audience],
|
|
130
|
+
[t("challenge.field.done"), s.goals.done_means],
|
|
131
|
+
[t("challenge.field.outOfScope"), (s.goals.out_of_scope || []).join(" · ")],
|
|
132
|
+
[t("challenge.field.context"), (s.goals.context_refs || []).join(" · ")],
|
|
133
|
+
])
|
|
134
|
+
);
|
|
135
|
+
g.append(el("div", "note", t("challenge.goalNote")));
|
|
136
|
+
out.append(g);
|
|
137
|
+
|
|
138
|
+
// --- 1b. THE COUNCIL, directly under the goal (v0.49.1). One row per roster
|
|
139
|
+
// lens. A NOT-RUN row KEEPS ITS SLOT and carries its reason, and a
|
|
140
|
+
// NOT-SELECTED row renders muted with the line that would add it —
|
|
141
|
+
// filtering either out makes "the contrarian found nothing" and "the
|
|
142
|
+
// contrarian never ran" look identical.
|
|
143
|
+
out.append(challengeCouncilCard(s, roles, show));
|
|
144
|
+
|
|
145
|
+
// --- 1c. PREMISE CHALLENGES. When one is open this is the LOUDEST card on
|
|
146
|
+
// the panel and it sits above the findings, because a premise disputes the
|
|
147
|
+
// yardstick every finding below it was measured against.
|
|
148
|
+
const premiseCard = challengePremiseCard(s, slug, body);
|
|
149
|
+
if (premiseCard) out.append(premiseCard);
|
|
150
|
+
|
|
151
|
+
// --- 2. the state, and its ONE next action
|
|
152
|
+
const st = card(null);
|
|
153
|
+
const stRow = el("div", "row-actions");
|
|
154
|
+
stRow.append(chip(s.state, CH_STATE_KIND[s.state] || "", s.state === CH_PULSE));
|
|
155
|
+
stRow.append(el("span", "note", s.why));
|
|
156
|
+
st.append(stRow);
|
|
157
|
+
st.append(challengeNextAction(s, diff, body));
|
|
158
|
+
out.append(st);
|
|
159
|
+
|
|
160
|
+
// --- 3. the timeline (the hero) + the convergence chart
|
|
161
|
+
if (s.convergence && s.convergence.length) {
|
|
162
|
+
const tl = card(t("challenge.timeline"));
|
|
163
|
+
tl.append(challengeTimeline(s));
|
|
164
|
+
tl.append(challengeConvergence(s));
|
|
165
|
+
if (s.stalled) tl.append(el("div", "note bad", t("challenge.stalledNote", { n: s.convergence.length })));
|
|
166
|
+
out.append(tl);
|
|
167
|
+
} else {
|
|
168
|
+
const tl = card(t("challenge.timeline"));
|
|
169
|
+
tl.append(empty(t("challenge.noIterations"), t("challenge.noIterationsHint", { slug: s.slug })));
|
|
170
|
+
out.append(tl);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// --- 4. the reader's comprehension score — the most legible thing here to a
|
|
174
|
+
// non-engineer, so it sits high.
|
|
175
|
+
const last = show && show.iterations && show.iterations[0];
|
|
176
|
+
if (last && last.reader) {
|
|
177
|
+
const rc = card(t("challenge.readerTitle"));
|
|
178
|
+
const big = el("div", "ch-score");
|
|
179
|
+
big.append(el("span", "ch-score-num", String(last.reader.score || "—")));
|
|
180
|
+
big.append(el("span", "note", t("challenge.readerSub", { asked: last.reader.asked, answered: last.reader.answered })));
|
|
181
|
+
rc.append(big);
|
|
182
|
+
rc.append(el("div", "note", t("challenge.readerNote")));
|
|
183
|
+
out.append(rc);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// --- 5. the dimension strip. A NOT-CHECKED chip KEEPS ITS SLOT and carries
|
|
187
|
+
// its reason; a 0-finding dimension keeps its slot too.
|
|
188
|
+
const dc = card(t("challenge.dimensions"));
|
|
189
|
+
const strip = el("div", "row-actions");
|
|
190
|
+
for (const dim of s.dimensions || []) {
|
|
191
|
+
const label =
|
|
192
|
+
dim.status === "CHECKED"
|
|
193
|
+
? `${dim.id} ${dim.findings}${dim.score ? " · " + dim.score : ""}`
|
|
194
|
+
: `${dim.id} ${dim.status}`;
|
|
195
|
+
const c = chip(label, CH_DIM_KIND[dim.status] || "");
|
|
196
|
+
if (dim.reason) {
|
|
197
|
+
c.title = dim.reason;
|
|
198
|
+
// A reason on hover only is a reason a screen reader never gets.
|
|
199
|
+
c.setAttribute("aria-label", `${dim.id} ${dim.status} — ${dim.reason}`);
|
|
200
|
+
}
|
|
201
|
+
strip.append(c);
|
|
202
|
+
}
|
|
203
|
+
dc.append(strip);
|
|
204
|
+
dc.append(el("div", "note", t("challenge.dimNote")));
|
|
205
|
+
out.append(dc);
|
|
206
|
+
|
|
207
|
+
// --- 6. the findings
|
|
208
|
+
if (last && last.findings && last.findings.length) {
|
|
209
|
+
const fc = card(t("challenge.findings"), challengeReportBtn(slug, body));
|
|
210
|
+
for (const f of last.findings) {
|
|
211
|
+
const box = el("div", "ch-finding");
|
|
212
|
+
const hdr = el("div", "row-actions");
|
|
213
|
+
hdr.append(chip(f.severity, CH_SEV_KIND[f.severity] || ""));
|
|
214
|
+
hdr.append(el("span", "mono dim", f.id));
|
|
215
|
+
hdr.append(chip(f.dimension, ""));
|
|
216
|
+
// The RAISER. An adopted council finding keeps the raiser's id, so this
|
|
217
|
+
// chip is how a user finds out whether a lens is earning its dispatch.
|
|
218
|
+
// The word is the CLI's own lens id — never a friendlier synonym.
|
|
219
|
+
if (f.lens && f.lens !== "judge") hdr.append(chip(f.lens, "info"));
|
|
220
|
+
if ((f.corroborated_by || []).length)
|
|
221
|
+
hdr.append(chip(t("challenge.alsoFoundBy", { lenses: f.corroborated_by.join(", ") }), "info"));
|
|
222
|
+
if (f.outcome) hdr.append(chip(f.outcome, f.outcome === "resolved" ? "ok" : f.outcome === "still-open" ? "warn" : ""));
|
|
223
|
+
if (show.accepted && show.accepted[f.id]) hdr.append(chip(t("challenge.acceptedBadge"), "ok"));
|
|
224
|
+
if (show.rebuttals && show.rebuttals[f.id]) hdr.append(chip(t("challenge.rebuttedBadge"), "info"));
|
|
225
|
+
box.append(hdr);
|
|
226
|
+
box.append(el("div", "ch-anchor mono", f.anchor || "—"));
|
|
227
|
+
if (f.quote) box.append(el("blockquote", "ch-quote", f.quote));
|
|
228
|
+
const rows = [];
|
|
229
|
+
if (f.what_is_wrong) rows.push([t("challenge.field.wrong"), f.what_is_wrong]);
|
|
230
|
+
if (f.consequence) rows.push([t("challenge.field.consequence"), f.consequence]);
|
|
231
|
+
if (f.acceptance_line) rows.push([t("challenge.field.fixedWhen"), f.acceptance_line]);
|
|
232
|
+
if (f.serves) rows.push([t("challenge.field.serves"), f.serves]);
|
|
233
|
+
if (f.lens && f.lens !== "judge")
|
|
234
|
+
rows.push([t("challenge.field.raisedBy"), t("challenge.raisedAdopted", { lens: f.lens })]);
|
|
235
|
+
if (f.disposition) rows.push([t("challenge.field.disposition"), f.disposition]);
|
|
236
|
+
if (f.superseded_by) rows.push([t("challenge.field.supersededBy"), f.superseded_by]);
|
|
237
|
+
if (f.reason) rows.push([t("challenge.field.reason"), f.reason]);
|
|
238
|
+
box.append(kvList(rows));
|
|
239
|
+
if (show.accepted && show.accepted[f.id])
|
|
240
|
+
box.append(el("div", "note ok", t("challenge.acceptedNote", { reason: show.accepted[f.id].reason })));
|
|
241
|
+
if (show.rebuttals && show.rebuttals[f.id])
|
|
242
|
+
box.append(el("div", "note", t("challenge.rebuttedNote", { reason: show.rebuttals[f.id].reason, status: show.rebuttals[f.id].status })));
|
|
243
|
+
// Both escape valves are FREE, so both are buttons — and both refuse
|
|
244
|
+
// without a reason, which the CLI decides, not this form.
|
|
245
|
+
if (!f.outcome || f.outcome === "still-open") {
|
|
246
|
+
const acts = el("div", "row-actions");
|
|
247
|
+
if (!(show.accepted && show.accepted[f.id]))
|
|
248
|
+
acts.append(challengeValveBtn("accept", slug, f.id, body));
|
|
249
|
+
if (!(show.rebuttals && show.rebuttals[f.id]))
|
|
250
|
+
acts.append(challengeValveBtn("rebut", slug, f.id, body));
|
|
251
|
+
box.append(acts);
|
|
252
|
+
}
|
|
253
|
+
fc.append(box);
|
|
254
|
+
}
|
|
255
|
+
if (last.dropped && last.dropped.length)
|
|
256
|
+
fc.append(el("div", "note", t("challenge.dropped", { n: last.dropped.length, ids: last.dropped.map((x) => x.id).join(", ") })));
|
|
257
|
+
out.append(fc);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// --- 6b. OPPORTUNITIES. Its own card, visually distinct from findings, and
|
|
261
|
+
// with NO SEVERITY COLOUR anywhere in it: an opportunity never blocks, and
|
|
262
|
+
// colouring it like a defect is exactly the confusion the class split
|
|
263
|
+
// exists to prevent.
|
|
264
|
+
const oppCard = challengeOpportunityCard(s, slug, body);
|
|
265
|
+
if (oppCard) out.append(oppCard);
|
|
266
|
+
|
|
267
|
+
// --- 7. events, collapsed
|
|
268
|
+
if (show && show.events && show.events.length)
|
|
269
|
+
out.append(
|
|
270
|
+
collapsible({
|
|
271
|
+
title: t("challenge.events"),
|
|
272
|
+
count: String(show.events.length),
|
|
273
|
+
collapsed: true,
|
|
274
|
+
content: kvList(show.events.map((e) => [e.at, `${e.kind} — ${e.detail}`])),
|
|
275
|
+
})
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
pane.replaceChildren(out);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// EVERY STATE ANSWERS "so what do I do now?" — the one next action, inline.
|
|
282
|
+
function challengeNextAction(s, diff, body) {
|
|
283
|
+
const wrap = el("div", "stack stack-sm");
|
|
284
|
+
if (s.state === "MISSING-REVISION") {
|
|
285
|
+
wrap.append(el("div", "note bad", t("challenge.missingRevision", { path: s.revision.expected })));
|
|
286
|
+
if (diff && diff.candidates && diff.candidates.length) {
|
|
287
|
+
const ul = el("ul", "file-list");
|
|
288
|
+
for (const c of diff.candidates) {
|
|
289
|
+
const li = el("li");
|
|
290
|
+
li.append(el("span", "mono", c.path));
|
|
291
|
+
li.append(el("span", "note", ` +${c.added} −${c.removed}`));
|
|
292
|
+
ul.append(li);
|
|
293
|
+
}
|
|
294
|
+
wrap.append(ul);
|
|
295
|
+
// It LISTS, it does not adopt. So the panel offers the recorded escape as
|
|
296
|
+
// a COMMAND — picking one for the user is the exact thing the CLI refuses.
|
|
297
|
+
wrap.append(el("div", "note", t("challenge.candidatesNote")));
|
|
298
|
+
wrap.append(el("pre", "cmd", `orc challenge expect ${s.slug} --set <path>`));
|
|
299
|
+
}
|
|
300
|
+
return wrap;
|
|
301
|
+
}
|
|
302
|
+
if (s.state === "TAMPERED") {
|
|
303
|
+
wrap.append(el("div", "note bad", t("challenge.tamperedNote")));
|
|
304
|
+
return wrap;
|
|
305
|
+
}
|
|
306
|
+
if (s.state === "PASSED" || s.state === "STALE-PASS") {
|
|
307
|
+
wrap.append(el("div", "note", s.state === "PASSED" ? t("challenge.passedNote") : t("challenge.stalePassNote")));
|
|
308
|
+
wrap.append(el("pre", "cmd", `git add orc/orc-challenge/${s.slug}/`));
|
|
309
|
+
return wrap;
|
|
310
|
+
}
|
|
311
|
+
if (s.state === "AWAITING-FIX") {
|
|
312
|
+
wrap.append(el("div", "note", t("challenge.awaitingFixNote")));
|
|
313
|
+
wrap.append(challengeCopyPrompt(s));
|
|
314
|
+
return wrap;
|
|
315
|
+
}
|
|
316
|
+
// AWAITING-JUDGE and AWAITING-RECHECK both need a paid run.
|
|
317
|
+
wrap.append(laneCommand(s.next || `/orc-challenge ${s.slug}`, t("challenge.paidWhy")));
|
|
318
|
+
return wrap;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Copying is FREE, so it is a button. The prompt is assembled from the CLI's own
|
|
322
|
+
// fields — the expected path, the slug, the frozen goal file — never from a
|
|
323
|
+
// second idea of where anything lives.
|
|
324
|
+
function challengeCopyPrompt(s) {
|
|
325
|
+
const prompt = [
|
|
326
|
+
`Fix the findings in orc/orc-challenge/${s.slug}/fix-brief.md.`,
|
|
327
|
+
"",
|
|
328
|
+
`Artifact: ${(s.artifacts[0] || {}).path || ""}`,
|
|
329
|
+
`Goal: orc/orc-challenge/${s.slug}/goals.md (read this first)`,
|
|
330
|
+
"",
|
|
331
|
+
`Write the revised version to: ${s.revision.expected}`,
|
|
332
|
+
"",
|
|
333
|
+
"Rules:",
|
|
334
|
+
"- Change the artifact only. Do not edit anything under orc/orc-challenge/.",
|
|
335
|
+
"- Do not mark findings resolved. The next judgement decides that.",
|
|
336
|
+
"- If you think a finding is wrong, do not argue with it here —",
|
|
337
|
+
` run: orc challenge rebut ${s.slug} <id> "why"`,
|
|
338
|
+
"",
|
|
339
|
+
"When you are done, start ANOTHER new session and run:",
|
|
340
|
+
` /orc-challenge ${s.slug}`,
|
|
341
|
+
].join("\n");
|
|
342
|
+
const box = el("div", "lane-cmd");
|
|
343
|
+
box.append(el("div", "lane-cmd-head", t("challenge.pasteHead")));
|
|
344
|
+
box.append(el("pre", "cmd ch-prompt", prompt));
|
|
345
|
+
const b = el("button", "btn btn-sm", t("challenge.copyPrompt"));
|
|
346
|
+
b.type = "button";
|
|
347
|
+
b.addEventListener("click", () => copy(prompt, t("challenge.copyPrompt")));
|
|
348
|
+
box.append(b);
|
|
349
|
+
return box;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function challengeReportBtn(slug, body) {
|
|
353
|
+
const b = el("button", "btn btn-ghost btn-sm", t("challenge.reRender"));
|
|
354
|
+
b.type = "button";
|
|
355
|
+
b.addEventListener("click", async () => {
|
|
356
|
+
const r = await post("/api/challenge/report", { slug });
|
|
357
|
+
toast(r.ok ? t("challenge.reportOk") : t("common.writeFail"), r.ok ? "ok" : "bad", r.output);
|
|
358
|
+
renderChallenge(body);
|
|
359
|
+
});
|
|
360
|
+
return b;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// KEYS ARE WRITTEN OUT IN FULL, never assembled from a fragment — the i18n rule.
|
|
364
|
+
// A dotted key built by concatenation is a key no lint can find and no
|
|
365
|
+
// translator can see.
|
|
366
|
+
const CH_VALVE = {
|
|
367
|
+
accept: {
|
|
368
|
+
btn: "challenge.acceptBtn",
|
|
369
|
+
title: "challenge.acceptTitle",
|
|
370
|
+
body: "challenge.acceptBody",
|
|
371
|
+
note: "challenge.acceptNote",
|
|
372
|
+
go: "challenge.acceptGo",
|
|
373
|
+
ok: "challenge.acceptOk",
|
|
374
|
+
route: "/api/challenge/accept",
|
|
375
|
+
},
|
|
376
|
+
rebut: {
|
|
377
|
+
btn: "challenge.rebutBtn",
|
|
378
|
+
title: "challenge.rebutTitle",
|
|
379
|
+
body: "challenge.rebutBody",
|
|
380
|
+
note: "challenge.rebutNote",
|
|
381
|
+
go: "challenge.rebutGo",
|
|
382
|
+
ok: "challenge.rebutOk",
|
|
383
|
+
route: "/api/challenge/rebut",
|
|
384
|
+
},
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// A COUNT IS NOT CONSENT, and neither is a click: a reason is mandatory, and the
|
|
388
|
+
// exact command is on screen the whole time — the CLI refuses without one too,
|
|
389
|
+
// so this form has no second idea of what a valid acceptance is.
|
|
390
|
+
function challengeValveBtn(which, slug, id, body) {
|
|
391
|
+
const K = CH_VALVE[which];
|
|
392
|
+
const b = el("button", "btn btn-ghost btn-sm", t(K.btn));
|
|
393
|
+
b.type = "button";
|
|
394
|
+
b.addEventListener("click", () => {
|
|
395
|
+
const wrap = frag();
|
|
396
|
+
wrap.append(el("p", null, t(K.body, { id })));
|
|
397
|
+
const input = el("input", "text-input");
|
|
398
|
+
input.type = "text";
|
|
399
|
+
input.placeholder = t("challenge.reasonPlaceholder");
|
|
400
|
+
wrap.append(input);
|
|
401
|
+
const cmd = el("pre", "cmd", `orc challenge ${which} ${slug} ${id} "…"`);
|
|
402
|
+
wrap.append(cmd);
|
|
403
|
+
wrap.append(el("div", "note", t(K.note)));
|
|
404
|
+
const m = modal({
|
|
405
|
+
title: t(K.title),
|
|
406
|
+
body: wrap,
|
|
407
|
+
actions: {
|
|
408
|
+
[t("common.cancel")]: null,
|
|
409
|
+
[t(K.go)]: async () => {
|
|
410
|
+
const reason = input.value.trim();
|
|
411
|
+
if (!reason) return toast(t("challenge.needReason"), "bad");
|
|
412
|
+
const r = await post(K.route, { slug, id, reason });
|
|
413
|
+
toast(r.ok ? t(K.ok) : t("common.writeFail"), r.ok ? "ok" : "bad", r.output);
|
|
414
|
+
renderChallenge(body);
|
|
415
|
+
},
|
|
416
|
+
},
|
|
417
|
+
});
|
|
418
|
+
input.addEventListener("input", () => {
|
|
419
|
+
cmd.textContent = `orc challenge ${which} ${slug} ${id} "${input.value || "…"}"`;
|
|
420
|
+
});
|
|
421
|
+
requestAnimationFrame(() => input.focus());
|
|
422
|
+
return m;
|
|
423
|
+
});
|
|
424
|
+
return b;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/* ONE reason prompt for the two council writes (v0.49.1).
|
|
428
|
+
|
|
429
|
+
Both `premise --dismiss` and `opportunity --take|--drop` REFUSE without a
|
|
430
|
+
reason, and the refusal is the CLI's, not this form's — so the button submits
|
|
431
|
+
whatever was typed and reports what came back. A reason recorded here stays
|
|
432
|
+
visible in the report forever, which is the point of demanding one. */
|
|
433
|
+
function challengeReasonPrompt({ title, note, onSubmit }) {
|
|
434
|
+
const wrap = frag();
|
|
435
|
+
const input = el("input", "text-input");
|
|
436
|
+
input.type = "text";
|
|
437
|
+
input.placeholder = t("challenge.reasonPlaceholder");
|
|
438
|
+
wrap.append(input);
|
|
439
|
+
wrap.append(el("div", "note", note));
|
|
440
|
+
const m = modal({
|
|
441
|
+
title,
|
|
442
|
+
body: wrap,
|
|
443
|
+
actions: {
|
|
444
|
+
[t("common.cancel")]: null,
|
|
445
|
+
[t("common.confirm")]: async () => {
|
|
446
|
+
const reason = input.value.trim();
|
|
447
|
+
if (!reason) return toast(t("challenge.needReason"), "bad");
|
|
448
|
+
await onSubmit(reason);
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
requestAnimationFrame(() => input.focus());
|
|
453
|
+
return m;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/* THE ITERATION TIMELINE — the hero.
|
|
457
|
+
|
|
458
|
+
GEOMETRY IS SOLVED FROM THE BOX SIZE, never expressed as a fraction of the
|
|
459
|
+
container (the VAULT / ringRadii lesson from Crosslink): a node box is a fixed
|
|
460
|
+
size, the rail is the bounding box of what was PLACED, and too many iterations
|
|
461
|
+
SCROLLS rather than being squeezed. A `regoal` or `retemplate` draws a VERSION
|
|
462
|
+
BREAK, because a comparison across one is not a comparison. */
|
|
463
|
+
const CH_NODE = { W: 92, H: 62, GAP: 30, PAD: 16, BREAK: 22 };
|
|
464
|
+
|
|
465
|
+
function challengeTimeline(s) {
|
|
466
|
+
const iters = s.convergence || [];
|
|
467
|
+
const box = el("div", "ch-rail-wrap");
|
|
468
|
+
// Where a version break falls: between iteration i-1 and i, when either frozen
|
|
469
|
+
// yardstick's version number changed.
|
|
470
|
+
// v0.49.1 adds a THIRD trigger: comparing an iteration judged by three lenses
|
|
471
|
+
// to one judged by six is not a comparison.
|
|
472
|
+
const breakBefore = iters.map((it, i) =>
|
|
473
|
+
i === 0
|
|
474
|
+
? false
|
|
475
|
+
: it.graded_against !== iters[i - 1].graded_against ||
|
|
476
|
+
it.graded_against_goal !== iters[i - 1].graded_against_goal ||
|
|
477
|
+
(it.graded_against_council || 1) !== (iters[i - 1].graded_against_council || 1)
|
|
478
|
+
);
|
|
479
|
+
const xs = [];
|
|
480
|
+
let x = CH_NODE.PAD;
|
|
481
|
+
for (let i = 0; i < iters.length; i++) {
|
|
482
|
+
if (breakBefore[i]) x += CH_NODE.BREAK;
|
|
483
|
+
xs.push(x);
|
|
484
|
+
x += CH_NODE.W + CH_NODE.GAP;
|
|
485
|
+
}
|
|
486
|
+
const width = (xs.length ? xs[xs.length - 1] + CH_NODE.W : 0) + CH_NODE.PAD;
|
|
487
|
+
const height = CH_NODE.H + 2 * CH_NODE.PAD + 18;
|
|
488
|
+
|
|
489
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
490
|
+
svg.setAttribute("class", "ch-rail");
|
|
491
|
+
// The canvas is the bounding box of what was PLACED, and it keeps its aspect:
|
|
492
|
+
// a stretched viewBox squashes every label and every stroke.
|
|
493
|
+
svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
494
|
+
svg.setAttribute("width", String(width));
|
|
495
|
+
svg.setAttribute("height", String(height));
|
|
496
|
+
svg.setAttribute("role", "img");
|
|
497
|
+
svg.setAttribute("aria-label", t("challenge.timelineAria", { n: iters.length }));
|
|
498
|
+
|
|
499
|
+
const mk = (name, attrs, text) => {
|
|
500
|
+
const n = document.createElementNS("http://www.w3.org/2000/svg", name);
|
|
501
|
+
for (const k of Object.keys(attrs)) n.setAttribute(k, String(attrs[k]));
|
|
502
|
+
if (text !== undefined) n.textContent = text;
|
|
503
|
+
return n;
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
for (let i = 0; i < iters.length; i++) {
|
|
507
|
+
const it = iters[i];
|
|
508
|
+
const cx = xs[i];
|
|
509
|
+
const cy = CH_NODE.PAD;
|
|
510
|
+
if (i > 0) {
|
|
511
|
+
const prevEnd = xs[i - 1] + CH_NODE.W;
|
|
512
|
+
svg.append(mk("line", { x1: prevEnd, y1: cy + CH_NODE.H / 2, x2: cx, y2: cy + CH_NODE.H / 2, class: "ch-rail-link" }));
|
|
513
|
+
if (breakBefore[i]) {
|
|
514
|
+
const bx = (prevEnd + cx) / 2;
|
|
515
|
+
svg.append(mk("line", { x1: bx, y1: cy - 6, x2: bx, y2: cy + CH_NODE.H + 6, class: "ch-rail-break" }));
|
|
516
|
+
// The label names WHICH yardstick moved. `c2` is a council change; a
|
|
517
|
+
// bare version number is a goal change, as it always was.
|
|
518
|
+
const prev = iters[i - 1];
|
|
519
|
+
const label =
|
|
520
|
+
(it.graded_against_council || 1) !== (prev.graded_against_council || 1)
|
|
521
|
+
? `c${it.graded_against_council || 1}`
|
|
522
|
+
: `v${it.graded_against_goal}`;
|
|
523
|
+
svg.append(mk("text", { x: bx, y: cy + CH_NODE.H + 18, class: "ch-rail-breaklabel", "text-anchor": "middle" }, label));
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
const g = mk("g", { class: "ch-rail-node" + (it.passed ? " pass" : " fail"), style: `animation-delay:${i * 40}ms` });
|
|
527
|
+
g.append(mk("rect", { x: cx, y: cy, width: CH_NODE.W, height: CH_NODE.H, rx: 10, class: "ch-rail-box" }));
|
|
528
|
+
g.append(mk("text", { x: cx + CH_NODE.W / 2, y: cy + 24, class: "ch-rail-n", "text-anchor": "middle" }, String(it.n)));
|
|
529
|
+
g.append(
|
|
530
|
+
mk("text", { x: cx + CH_NODE.W / 2, y: cy + 44, class: "ch-rail-verdict", "text-anchor": "middle" }, it.passed ? "PASS" : `FAIL ${it.blocking}`)
|
|
531
|
+
);
|
|
532
|
+
svg.append(g);
|
|
533
|
+
}
|
|
534
|
+
box.append(svg);
|
|
535
|
+
return box;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/* THE CONVERGENCE CHART — blocking findings per iteration, stacked by severity,
|
|
539
|
+
the same visual family as the budget cost bar. THIS IS THE PAYOFF PICTURE: you
|
|
540
|
+
can see a cycle converging, or not. It draws left to right on open, once,
|
|
541
|
+
because the SHAPE of the trend is the information. */
|
|
542
|
+
function challengeConvergence(s) {
|
|
543
|
+
const iters = s.convergence || [];
|
|
544
|
+
const wrap = el("div", "ch-conv");
|
|
545
|
+
const max = Math.max(1, ...iters.map((i) => ["P0", "P1", "P2", "P3"].reduce((n, k) => n + ((i.severities || {})[k] || 0), 0)));
|
|
546
|
+
for (const it of iters) {
|
|
547
|
+
const rowEl = el("div", "ch-conv-row");
|
|
548
|
+
rowEl.append(el("span", "ch-conv-n", String(it.n)));
|
|
549
|
+
const bar = el("div", "ch-conv-bar");
|
|
550
|
+
for (const sev of ["P0", "P1", "P2", "P3"]) {
|
|
551
|
+
const n = (it.severities || {})[sev] || 0;
|
|
552
|
+
if (!n) continue;
|
|
553
|
+
const seg = el("div", "ch-conv-seg ch-sev-" + sev.toLowerCase());
|
|
554
|
+
seg.style.setProperty("--w", ((n / max) * 100).toFixed(2) + "%");
|
|
555
|
+
seg.title = `${sev} ${n}`;
|
|
556
|
+
bar.append(seg);
|
|
557
|
+
}
|
|
558
|
+
rowEl.append(bar);
|
|
559
|
+
rowEl.append(el("span", "ch-conv-blocking", String(it.blocking)));
|
|
560
|
+
wrap.append(rowEl);
|
|
561
|
+
}
|
|
562
|
+
// THE PER-LENS LEGEND (v0.49.1). The stacking stays severity — do not add a
|
|
563
|
+
// second dimension to a bar that works — so "which lens is earning its money"
|
|
564
|
+
// gets its own row underneath. The counts and the prefixes are the CLI's.
|
|
565
|
+
const counts = s.lens_counts || {};
|
|
566
|
+
const lenses = Object.keys(counts);
|
|
567
|
+
if (lenses.length) {
|
|
568
|
+
const legend = el("div", "ch-lens-legend");
|
|
569
|
+
for (const lens of lenses) {
|
|
570
|
+
const item = el("span", "ch-lens-legend-item");
|
|
571
|
+
item.append(el("span", "mono", lens));
|
|
572
|
+
item.append(el("span", "ch-lens-legend-n", String(counts[lens])));
|
|
573
|
+
legend.append(item);
|
|
574
|
+
}
|
|
575
|
+
wrap.append(legend);
|
|
576
|
+
}
|
|
577
|
+
wrap.append(el("div", "note", t("challenge.convNote")));
|
|
578
|
+
return wrap;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/* THE COUNCIL CARD (v0.49.1).
|
|
582
|
+
|
|
583
|
+
THE PANEL DERIVES NOTHING HERE. It does not name a lens, does not know which
|
|
584
|
+
class blocks, does not compute a disposition and does not decide the roster
|
|
585
|
+
suggestion — every one of those comes from `orc challenge roles --json` and
|
|
586
|
+
`orc challenge status --json`. Same rule as the Flow stepper: a second idea of
|
|
587
|
+
what the council is, is exactly the drift this panel exists to make
|
|
588
|
+
impossible.
|
|
589
|
+
|
|
590
|
+
A NOT-RUN row KEEPS ITS SLOT with its reason, and a NOT-SELECTED row renders
|
|
591
|
+
muted with the one line that would add it. */
|
|
592
|
+
function challengeCouncilCard(s, roles, show) {
|
|
593
|
+
const c = card(t("challenge.council") + (s.council_version ? " v" + s.council_version : ""));
|
|
594
|
+
if (s.council_unset) {
|
|
595
|
+
c.append(empty(t("challenge.councilUnset"), t("challenge.councilUnsetHint")));
|
|
596
|
+
c.append(laneCommand(`/orc-challenge ${s.slug}`, t("challenge.councilUnsetWhy")));
|
|
597
|
+
return c;
|
|
598
|
+
}
|
|
599
|
+
const ran = (s.council || []).filter((r) => r.status === "RAN").length;
|
|
600
|
+
const selected = (s.council || []).filter((r) => r.selected).length;
|
|
601
|
+
const head = el("div", "row-actions");
|
|
602
|
+
head.append(chip(t("challenge.councilRan", { ran, of: selected }), ran === selected ? "ok" : "warn"));
|
|
603
|
+
c.append(head);
|
|
604
|
+
|
|
605
|
+
for (const r of s.council || []) {
|
|
606
|
+
const row = el("div", "ch-lens-row" + (r.selected ? "" : " row-muted"));
|
|
607
|
+
const top = el("div", "row-actions");
|
|
608
|
+
top.append(chip(r.status, r.status === "RAN" ? "ok" : r.status === "NOT-RUN" ? "warn" : ""));
|
|
609
|
+
top.append(el("span", "ch-lens-name", r.display));
|
|
610
|
+
// `class` is the CLI's word — finding | opportunity | premise. It is never
|
|
611
|
+
// translated: a translated class word is a class that does not exist.
|
|
612
|
+
top.append(chip(r.class, r.class === "finding" ? "" : "info"));
|
|
613
|
+
if (!r.blocks) top.append(chip(t("challenge.neverBlocks"), "info"));
|
|
614
|
+
row.append(top);
|
|
615
|
+
row.append(el("div", "mono dim ch-lens-agent", r.agent + " · " + r.effort));
|
|
616
|
+
row.append(el("div", "note", r.why));
|
|
617
|
+
if (r.status === "RAN" && r.raised !== undefined)
|
|
618
|
+
row.append(
|
|
619
|
+
el(
|
|
620
|
+
"div",
|
|
621
|
+
"note",
|
|
622
|
+
t("challenge.lensCounts", {
|
|
623
|
+
raised: r.raised,
|
|
624
|
+
adopted: r.adopted || 0,
|
|
625
|
+
merged: r.merged || 0,
|
|
626
|
+
rejected: r.rejected || 0,
|
|
627
|
+
outOfGoal: r.out_of_goal || 0,
|
|
628
|
+
})
|
|
629
|
+
)
|
|
630
|
+
);
|
|
631
|
+
// Rule 15: a selected role is never silently absent.
|
|
632
|
+
if (r.status === "NOT-RUN" && r.reason) row.append(el("div", "note warn", t("challenge.lensNotRun", { reason: r.reason })));
|
|
633
|
+
if (r.status === "NOT-SELECTED" && r.add_with) {
|
|
634
|
+
row.append(el("div", "note", t("challenge.lensNotSelected")));
|
|
635
|
+
row.append(el("pre", "cmd", r.add_with));
|
|
636
|
+
}
|
|
637
|
+
// THE MONDAY-MORNING LIST — the single most legible artifact this lane
|
|
638
|
+
// produces for a non-engineer, so it sits high, inside the council card.
|
|
639
|
+
if ((r.monday_morning || []).length) {
|
|
640
|
+
const ol = el("ol", "ch-monday");
|
|
641
|
+
for (const step of r.monday_morning) ol.append(el("li", null, step));
|
|
642
|
+
row.append(el("div", "ch-monday-head", t("challenge.mondayMorning")));
|
|
643
|
+
row.append(ol);
|
|
644
|
+
}
|
|
645
|
+
c.append(row);
|
|
646
|
+
}
|
|
647
|
+
c.append(el("div", "note", t("challenge.councilNote")));
|
|
648
|
+
void roles;
|
|
649
|
+
void show;
|
|
650
|
+
return c;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/* PREMISE CHALLENGES — the loudest card here when one is open, because a premise
|
|
654
|
+
disputes the frozen goal that every finding below was measured against.
|
|
655
|
+
|
|
656
|
+
Two resolutions, and NEITHER IS AUTOMATIC: dismiss (free, a real write, so a
|
|
657
|
+
button) or change the goal (a copy-able command, because it needs a FILE the
|
|
658
|
+
panel must not invent). */
|
|
659
|
+
function challengePremiseCard(s, slug, body) {
|
|
660
|
+
const all = Object.entries(s.premises || {});
|
|
661
|
+
if (!all.length) return null;
|
|
662
|
+
const open = all.filter(([, q]) => q.status === "open");
|
|
663
|
+
const c = card(t("challenge.premises"));
|
|
664
|
+
if (open.length) c.classList.add("ch-premise-loud");
|
|
665
|
+
for (const [id, q] of all) {
|
|
666
|
+
const box = el("div", "ch-premise");
|
|
667
|
+
const hdr = el("div", "row-actions");
|
|
668
|
+
hdr.append(el("span", "mono dim", id));
|
|
669
|
+
hdr.append(chip(t("challenge.disputes", { what: q.disputes }), q.status === "open" ? "bad" : ""));
|
|
670
|
+
hdr.append(chip(q.status, q.status === "open" ? "warn" : ""));
|
|
671
|
+
box.append(hdr);
|
|
672
|
+
if (q.quote) box.append(el("blockquote", "ch-quote", q.quote));
|
|
673
|
+
const rows = [];
|
|
674
|
+
if (q.reframe) rows.push([t("challenge.field.reframe"), q.reframe]);
|
|
675
|
+
if (q.what_changes) rows.push([t("challenge.field.whatChanges"), q.what_changes]);
|
|
676
|
+
if (q.cheapest_test) rows.push([t("challenge.field.cheapestTest"), q.cheapest_test]);
|
|
677
|
+
if (q.reason) rows.push([t("challenge.field.reason"), q.reason]);
|
|
678
|
+
box.append(kvList(rows));
|
|
679
|
+
if (q.status === "open") {
|
|
680
|
+
const acts = el("div", "row-actions");
|
|
681
|
+
const dismiss = el("button", "btn btn-sm", t("challenge.dismissPremise"));
|
|
682
|
+
dismiss.type = "button";
|
|
683
|
+
dismiss.addEventListener("click", () => challengeReasonPrompt({
|
|
684
|
+
title: t("challenge.dismissPremise"),
|
|
685
|
+
note: t("challenge.dismissPremiseNote"),
|
|
686
|
+
onSubmit: async (reason) => {
|
|
687
|
+
const r = await post("/api/challenge/premise", { slug, id, reason });
|
|
688
|
+
toast(r.command, r.ok ? "ok" : "bad", r.output);
|
|
689
|
+
renderChallenge(body);
|
|
690
|
+
},
|
|
691
|
+
}));
|
|
692
|
+
acts.append(dismiss);
|
|
693
|
+
box.append(acts);
|
|
694
|
+
// Adopting needs a goals FILE, so it is a command and never a button.
|
|
695
|
+
box.append(laneCommand(`orc challenge goals ${slug} --set <path> --reason "…"`, t("challenge.adoptPremiseWhy")));
|
|
696
|
+
}
|
|
697
|
+
c.append(box);
|
|
698
|
+
}
|
|
699
|
+
c.append(el("div", "note", t("challenge.premiseNote")));
|
|
700
|
+
return c;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/* OPPORTUNITIES — no severity colour anywhere in this card. An opportunity never
|
|
704
|
+
blocks, and every one of them carries a first step and a route. */
|
|
705
|
+
function challengeOpportunityCard(s, slug, body) {
|
|
706
|
+
const all = Object.entries(s.opportunities || {});
|
|
707
|
+
if (!all.length) return null;
|
|
708
|
+
const c = card(t("challenge.opportunities"));
|
|
709
|
+
c.append(el("div", "note", t("challenge.opportunityNote")));
|
|
710
|
+
for (const [id, o] of all) {
|
|
711
|
+
const box = el("div", "ch-opportunity");
|
|
712
|
+
const hdr = el("div", "row-actions");
|
|
713
|
+
hdr.append(el("span", "mono dim", id));
|
|
714
|
+
hdr.append(chip(o.status, ""));
|
|
715
|
+
// The route is the CLI's own word — it is the lane this belongs in next.
|
|
716
|
+
if (o.route && o.route !== "none") hdr.append(chip(o.route, "info"));
|
|
717
|
+
box.append(hdr);
|
|
718
|
+
const rows = [];
|
|
719
|
+
if (o.what) rows.push([t("challenge.field.what"), o.what]);
|
|
720
|
+
if (o.upside) rows.push([t("challenge.field.upside"), o.upside]);
|
|
721
|
+
if (o.first_step) rows.push([t("challenge.field.firstStep"), o.first_step]);
|
|
722
|
+
if (o.anchor) rows.push([t("challenge.field.anchor"), o.anchor]);
|
|
723
|
+
if (o.confidence) rows.push([t("challenge.field.confidence"), o.confidence]);
|
|
724
|
+
if (o.resolved_reason) rows.push([t("challenge.field.reason"), o.resolved_reason]);
|
|
725
|
+
box.append(kvList(rows));
|
|
726
|
+
if (o.status === "open") {
|
|
727
|
+
const acts = el("div", "row-actions");
|
|
728
|
+
for (const take of [true, false]) {
|
|
729
|
+
const b = el("button", "btn btn-sm" + (take ? "" : " btn-ghost"), take ? t("challenge.takeOpportunity") : t("challenge.dropOpportunity"));
|
|
730
|
+
b.type = "button";
|
|
731
|
+
b.addEventListener("click", () => challengeReasonPrompt({
|
|
732
|
+
title: take ? t("challenge.takeOpportunity") : t("challenge.dropOpportunity"),
|
|
733
|
+
note: t("challenge.opportunityReasonNote"),
|
|
734
|
+
onSubmit: async (reason) => {
|
|
735
|
+
const r = await post("/api/challenge/opportunity", { slug, id, take, reason });
|
|
736
|
+
toast(r.command, r.ok ? "ok" : "bad", r.output);
|
|
737
|
+
renderChallenge(body);
|
|
738
|
+
},
|
|
739
|
+
}));
|
|
740
|
+
acts.append(b);
|
|
741
|
+
}
|
|
742
|
+
box.append(acts);
|
|
743
|
+
}
|
|
744
|
+
c.append(box);
|
|
745
|
+
}
|
|
746
|
+
return c;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
/* A paid action is a COMMAND, never a button. This renders one, with the reason
|
|
750
|
+
it is not a button — making the boundary visible rather than hiding it. */
|
|
751
|
+
function laneCommand(cmd, why) {
|
|
752
|
+
const box = el("div", "lane-cmd");
|
|
753
|
+
box.append(el("div", "lane-cmd-head", t("common.runInClaude")));
|
|
754
|
+
const row = el("div", "row-actions");
|
|
755
|
+
row.append(el("pre", "cmd", cmd));
|
|
756
|
+
const b = el("button", "btn btn-ghost btn-sm", t("common.copy"));
|
|
757
|
+
b.type = "button";
|
|
758
|
+
b.addEventListener("click", () => copy(cmd, cmd));
|
|
759
|
+
row.append(b);
|
|
760
|
+
box.append(row);
|
|
761
|
+
if (why) box.append(el("div", "note", why));
|
|
762
|
+
return box;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/* ==================================================================== DOCS == */
|
|
766
|
+
/*
|
|
767
|
+
THE PANEL DERIVES NOTHING. Not the section order, not a line range, not a
|
|
768
|
+
state word, not the batching, not a lint rule name, not the completion
|
|
769
|
+
verdict. It draws `orc doc … --json`. (The Flow-stepper rule: a second idea
|
|
770
|
+
of the pipeline is exactly the drift this panel exists to make impossible.)
|
|
771
|
+
|
|
772
|
+
THE FREE/PAID LINE, visible rather than hidden: `list`, `status`, `map`,
|
|
773
|
+
`lint`, `plan` and `assemble` are deterministic and cost no model tokens, so
|
|
774
|
+
each is a real BUTTON. Writing a section, checking a range and editing one all
|
|
775
|
+
cost model tokens, so they are copy-able commands and there is no route for
|
|
776
|
+
any of them.
|
|
777
|
+
|
|
778
|
+
AND IT IS A PLAN PREVIEW, NOT A LIVE MONITOR. The server cannot see a running
|
|
779
|
+
session, so the wave card says so in one line. Claiming live status would be
|
|
780
|
+
this panel's first lie.
|
|
781
|
+
*/
|