@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,890 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* panels/knowledge.js — orc ui client
|
|
3
|
+
What ORC knows about this repo: the wiki, its coverage, the code patterns,
|
|
4
|
+
the repair memory, and what it knows from next door.
|
|
5
|
+
|
|
6
|
+
FIVE TABS since v0.49.1, the Crosslink two-tab precedent. This was one
|
|
7
|
+
scrolling column of six cards, and the release that made the CLI stop
|
|
8
|
+
discarding what it computes roughly tripled the content — which is not
|
|
9
|
+
survivable as one scroll.
|
|
10
|
+
|
|
11
|
+
THE PANEL DERIVES NOTHING. It never computes a tier, a distance, a coverage
|
|
12
|
+
percentage, an order, an estimate or a price: `computeWikiFreshness` is the
|
|
13
|
+
one engine, `orc wiki plan` decides the order, and a value the CLI could not
|
|
14
|
+
compute renders as an em dash, never as a guess.
|
|
15
|
+
|
|
16
|
+
A FREE ACTION GETS A BUTTON; A PAID ACTION GETS A COPY-ABLE COMMAND — and
|
|
17
|
+
that line is visible on the panel rather than implied.
|
|
18
|
+
|
|
19
|
+
Loaded by app.html in the order its numeric prefix names. Classic
|
|
20
|
+
script, no import/export: an ES module import carries no query string,
|
|
21
|
+
and every static request here needs the per-launch session token. */
|
|
22
|
+
|
|
23
|
+
/* =============================================================== KNOWLEDGE == */
|
|
24
|
+
|
|
25
|
+
PANELS.knowledge = function (host) {
|
|
26
|
+
head(host, t("knowledge.title"), t("knowledge.sub"));
|
|
27
|
+
const body = el("div", "stack");
|
|
28
|
+
host.append(body);
|
|
29
|
+
renderKnowledge(body);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Which tab was open, so a write that re-renders the panel does not throw the
|
|
33
|
+
// user back to the first one.
|
|
34
|
+
let KN_TAB = "wiki";
|
|
35
|
+
|
|
36
|
+
async function renderKnowledge(body) {
|
|
37
|
+
body.replaceChildren(skeleton(6));
|
|
38
|
+
const [wikiRes, impactRes, patRes, gotRes, planRes, debtRes, usageRes, docsRes, covRes] = await Promise.all([
|
|
39
|
+
read("/api/wiki").catch((e) => ({ data: null, error: e })),
|
|
40
|
+
read("/api/wiki/impact").catch((e) => ({ data: null, error: e })),
|
|
41
|
+
read("/api/patterns").catch((e) => ({ data: null, error: e })),
|
|
42
|
+
read("/api/gotchas").catch((e) => ({ data: null, error: e })),
|
|
43
|
+
read("/api/wiki/plan").catch((e) => ({ data: null, error: e })),
|
|
44
|
+
read("/api/wiki/debt").catch((e) => ({ data: null, error: e })),
|
|
45
|
+
read("/api/wiki/usage").catch((e) => ({ data: null, error: e })),
|
|
46
|
+
read("/api/wiki/docs").catch((e) => ({ data: null, error: e })),
|
|
47
|
+
read("/api/wiki/coverage").catch((e) => ({ data: null, error: e })),
|
|
48
|
+
]);
|
|
49
|
+
const d = {
|
|
50
|
+
wiki: wikiRes.data || {},
|
|
51
|
+
impact: impactRes.data,
|
|
52
|
+
patterns: patRes.data || {},
|
|
53
|
+
gotchas: gotRes.data || {},
|
|
54
|
+
plan: planRes.data,
|
|
55
|
+
debt: debtRes.data,
|
|
56
|
+
usage: usageRes.data,
|
|
57
|
+
docs: docsRes.data,
|
|
58
|
+
coverage: covRes.data,
|
|
59
|
+
// A read that FAILED is not the same as a read that came back empty, and
|
|
60
|
+
// rendering them identically is what turned a truncated 30 KB payload into
|
|
61
|
+
// "this repo has no wiki and no git" (v0.49.4). The server already puts the
|
|
62
|
+
// CLI's own words in the 500 body; the panel just has to stop discarding
|
|
63
|
+
// them.
|
|
64
|
+
errors: { coverage: covRes.error || null, docs: docsRes.error || null },
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const out = frag();
|
|
68
|
+
// THE HEADER STRIP, above the tabs and on every one of them: the numbers that
|
|
69
|
+
// answer "what does ORC know about this repo?" in one line. Every value is
|
|
70
|
+
// CLI-computed, and one it could not compute renders as an em dash.
|
|
71
|
+
out.append(knowledgeHeaderStrip(d));
|
|
72
|
+
|
|
73
|
+
const tabs = el("div", "tabs");
|
|
74
|
+
const pane = el("div", "tab-pane stack");
|
|
75
|
+
const views = {
|
|
76
|
+
wiki: () => knWikiTab(d, body),
|
|
77
|
+
coverage: () => knCoverageTab(d),
|
|
78
|
+
patterns: () => knPatternsTab(d),
|
|
79
|
+
memory: () => knMemoryTab(d, body),
|
|
80
|
+
peers: () => knPeersTab(d),
|
|
81
|
+
};
|
|
82
|
+
const select = (which) => {
|
|
83
|
+
KN_TAB = which;
|
|
84
|
+
for (const b of tabs.children) b.setAttribute("aria-selected", String(b.dataset.tab === which));
|
|
85
|
+
pane.replaceChildren(views[which]());
|
|
86
|
+
};
|
|
87
|
+
// Keys are written out in full, never assembled from the tab id — a key built
|
|
88
|
+
// from a fragment is invisible to every check that looks for one.
|
|
89
|
+
for (const [which, label] of [
|
|
90
|
+
["wiki", t("knowledge.tab.wiki")],
|
|
91
|
+
["coverage", t("knowledge.tab.coverage")],
|
|
92
|
+
["patterns", t("knowledge.tab.patterns")],
|
|
93
|
+
["memory", t("knowledge.tab.memory")],
|
|
94
|
+
["peers", t("knowledge.tab.peers")],
|
|
95
|
+
]) {
|
|
96
|
+
const b = el("button", null, label);
|
|
97
|
+
b.type = "button";
|
|
98
|
+
b.dataset.tab = which;
|
|
99
|
+
b.addEventListener("click", () => select(which));
|
|
100
|
+
tabs.append(b);
|
|
101
|
+
}
|
|
102
|
+
out.append(tabs, pane);
|
|
103
|
+
body.replaceChildren(out);
|
|
104
|
+
select(views[KN_TAB] ? KN_TAB : "wiki");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/* THE HEADER STRIP. Six numbers, all of them the CLI's. A `—` means the CLI
|
|
108
|
+
could not compute it, and that is an ANSWER — never a zero, never a guess. */
|
|
109
|
+
function knowledgeHeaderStrip(d) {
|
|
110
|
+
const w = d.wiki || {};
|
|
111
|
+
const strip = el("div", "kn-strip");
|
|
112
|
+
const item = (label, value, kind) => {
|
|
113
|
+
const box = el("div", "kn-strip-item" + (kind ? " kn-" + kind : ""));
|
|
114
|
+
box.append(el("span", "kn-strip-value", value));
|
|
115
|
+
box.append(el("span", "kn-strip-label", label));
|
|
116
|
+
strip.append(box);
|
|
117
|
+
};
|
|
118
|
+
// The tier word is the CLI's own. Never a friendlier synonym.
|
|
119
|
+
item(t("knowledge.strip.wiki"), w.tier || (w.state ? String(w.state).toUpperCase() : "—"));
|
|
120
|
+
item(t("knowledge.strip.docs"), w.docs === undefined ? "—" : String(w.docs));
|
|
121
|
+
item(
|
|
122
|
+
t("knowledge.strip.covered"),
|
|
123
|
+
d.coverage && d.coverage.ok ? d.coverage.coverage_pct + "%" : "—"
|
|
124
|
+
);
|
|
125
|
+
item(t("knowledge.strip.blind"), w.blind === undefined ? "—" : String(w.blind));
|
|
126
|
+
item(
|
|
127
|
+
t("knowledge.strip.pending"),
|
|
128
|
+
d.debt && d.debt.ok && d.debt.pending !== undefined ? String(d.debt.pending) : "—"
|
|
129
|
+
);
|
|
130
|
+
item(t("knowledge.strip.patterns"), String((d.patterns.patterns || []).length));
|
|
131
|
+
item(t("knowledge.strip.gotchas"), d.gotchas.count === undefined ? "—" : String(d.gotchas.count));
|
|
132
|
+
return strip;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* ── TAB 1 — WIKI ────────────────────────────────────────────────────────── */
|
|
136
|
+
function knWikiTab(d, body) {
|
|
137
|
+
const out = frag();
|
|
138
|
+
out.append(wikiPlanCard(d.plan, d.debt, body));
|
|
139
|
+
if (d.usage && d.usage.rows) out.append(wikiUsageCard(d.usage, body));
|
|
140
|
+
|
|
141
|
+
const w = d.wiki;
|
|
142
|
+
const wc = card(t("knowledge.wiki"), wikiActions(body, w));
|
|
143
|
+
if (!w.state || w.state === "none") {
|
|
144
|
+
wc.append(empty(t("knowledge.wiki.none"), t("knowledge.wiki.noneHint")));
|
|
145
|
+
} else if (w.state !== "registered") {
|
|
146
|
+
wc.append(el("div", "note", t("knowledge.wiki.unregistered", { state: String(w.state).toUpperCase() })));
|
|
147
|
+
wc.append(el("div", "note", t("knowledge.wiki.syncHint")));
|
|
148
|
+
} else {
|
|
149
|
+
const tierChip = chip(w.tier || t("overview.tile.wikiUnknown"), w.tier === "FRESH" ? "ok" : w.tier === "AGING" ? "warn" : "bad", w.tier === "STALE");
|
|
150
|
+
const headRow = el("div", "row-actions");
|
|
151
|
+
headRow.append(tierChip);
|
|
152
|
+
// The per-doc split as a small stacked bar. The counts are the CLI's.
|
|
153
|
+
if (w.counts) {
|
|
154
|
+
const total = Math.max(1, w.counts.FRESH + w.counts.AGING + w.counts.STALE + (w.counts.unknown || 0));
|
|
155
|
+
const bar = el("div", "kn-tierbar");
|
|
156
|
+
for (const [tier, cls] of [["FRESH", "ok"], ["AGING", "warn"], ["STALE", "bad"], ["unknown", "idle"]]) {
|
|
157
|
+
const n = w.counts[tier] || 0;
|
|
158
|
+
if (!n) continue;
|
|
159
|
+
const seg = el("div", "kn-tierbar-seg kn-tier-" + cls);
|
|
160
|
+
seg.style.setProperty("--w", ((n / total) * 100).toFixed(2) + "%");
|
|
161
|
+
seg.title = `${tier} ${n}`;
|
|
162
|
+
bar.append(seg);
|
|
163
|
+
}
|
|
164
|
+
headRow.append(bar);
|
|
165
|
+
}
|
|
166
|
+
wc.append(headRow);
|
|
167
|
+
const rows = [
|
|
168
|
+
[t("knowledge.field.docs"), String(w.docs)],
|
|
169
|
+
[t("knowledge.field.lastScan"), w.last_scan],
|
|
170
|
+
];
|
|
171
|
+
// THE DOC PINNING THE TIER, BY NAME. A hash is not a thing anybody can go
|
|
172
|
+
// and refresh — and until v0.49.1 the hash is all `--json` carried.
|
|
173
|
+
if (w.worst)
|
|
174
|
+
rows.push([t("knowledge.field.worst"), `${w.worst.file} (${w.worst.distance}c)`]);
|
|
175
|
+
rows.push(
|
|
176
|
+
[
|
|
177
|
+
t("knowledge.field.distance"),
|
|
178
|
+
w.distance === null ? t("knowledge.field.unmeasurable") : t("knowledge.field.distanceValue", { n: w.distance }),
|
|
179
|
+
],
|
|
180
|
+
[t("knowledge.field.anchor"), w.anchor ? String(w.anchor).slice(0, 8) : ""],
|
|
181
|
+
// `wiki_fresh_max` / `wiki_aging_max` are config keys — the numbers are
|
|
182
|
+
// shown, the key names are not paraphrased.
|
|
183
|
+
[t("knowledge.field.edges"), w.edges ? `fresh < ${w.edges.freshMax}c · aging <= ${w.edges.agingMax}c` : ""],
|
|
184
|
+
[t("knowledge.field.tags"), w.crosslink_tags === undefined ? "" : String(w.crosslink_tags)],
|
|
185
|
+
[t("knowledge.field.blind"), w.blind ? String(w.blind) : "0"]
|
|
186
|
+
);
|
|
187
|
+
wc.append(kvList(rows));
|
|
188
|
+
// The reason text is the CLI's own sentence about a real doc — verbatim.
|
|
189
|
+
for (const r of w.reasons || []) wc.append(el("div", "note", t("knowledge.wiki.why", { reason: r })));
|
|
190
|
+
wc.append(el("div", "note", t("knowledge.wiki.freshNote")));
|
|
191
|
+
// The orientation doc is read FIRST by every consumer, and the panel used
|
|
192
|
+
// not to mention it exists.
|
|
193
|
+
if (w.orientation) {
|
|
194
|
+
if (w.orientation.present)
|
|
195
|
+
wc.append(el("div", "note ok", t("knowledge.orientation.present", { file: w.orientation.file })));
|
|
196
|
+
else {
|
|
197
|
+
wc.append(el("div", "note warn", t("knowledge.orientation.missing")));
|
|
198
|
+
wc.append(el("pre", "cmd", w.orientation.regenerate));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
out.append(wc);
|
|
203
|
+
|
|
204
|
+
// THE DOC TABLE — the headline addition. A row EXPANDS IN PLACE (one at a
|
|
205
|
+
// time, detail fetched on first open); there is no detail box below the
|
|
206
|
+
// table, which is the Runs-row rule.
|
|
207
|
+
out.append(d.errors && d.errors.docs ? failBox(d.errors.docs) : wikiDocsCard(d.docs));
|
|
208
|
+
|
|
209
|
+
// impact, unchanged, moved onto this tab
|
|
210
|
+
const imp = d.impact;
|
|
211
|
+
if (imp && imp.ok) {
|
|
212
|
+
const c = card(t("knowledge.impact.title"));
|
|
213
|
+
const rec = el("div", "row-actions");
|
|
214
|
+
rec.append(chip(imp.recommendation, imp.recommendation === "CLEAN" ? "ok" : imp.recommendation === "DELTA" ? "info" : "warn"));
|
|
215
|
+
c.append(rec);
|
|
216
|
+
for (const r of imp.reasons || []) c.append(el("div", "note", r));
|
|
217
|
+
c.append(
|
|
218
|
+
el(
|
|
219
|
+
"div",
|
|
220
|
+
"note",
|
|
221
|
+
t("knowledge.impact.counts", {
|
|
222
|
+
registered: imp.registered,
|
|
223
|
+
touched: imp.touched,
|
|
224
|
+
structural: imp.structural,
|
|
225
|
+
pct: imp.affected_pct,
|
|
226
|
+
threshold: imp.threshold,
|
|
227
|
+
})
|
|
228
|
+
)
|
|
229
|
+
);
|
|
230
|
+
const scroll = el("div", "scroll-x");
|
|
231
|
+
const table = el("table");
|
|
232
|
+
const thead = el("thead");
|
|
233
|
+
const hr = el("tr");
|
|
234
|
+
for (const h of [t("knowledge.impact.col.doc"), t("knowledge.impact.col.state"), t("knowledge.impact.col.detail")])
|
|
235
|
+
hr.append(el("th", null, h));
|
|
236
|
+
thead.append(hr);
|
|
237
|
+
const tb = el("tbody");
|
|
238
|
+
for (const doc of imp.docs) {
|
|
239
|
+
const tr = el("tr");
|
|
240
|
+
tr.append(el("td", "mono", doc.file));
|
|
241
|
+
const st = el("td");
|
|
242
|
+
st.append(chip(doc.state, doc.state === "CLEAN" ? "ok" : doc.state === "TOUCHED" ? "info" : "warn"));
|
|
243
|
+
tr.append(st);
|
|
244
|
+
tr.append(el("td", "note", doc.gone.length ? "gone: " + doc.gone.join(", ") : doc.hits.slice(0, 4).join(", ")));
|
|
245
|
+
tb.append(tr);
|
|
246
|
+
}
|
|
247
|
+
table.append(thead, tb);
|
|
248
|
+
scroll.append(table);
|
|
249
|
+
c.append(scroll);
|
|
250
|
+
out.append(c);
|
|
251
|
+
} else if (imp && !imp.ok) {
|
|
252
|
+
const c = card(t("knowledge.impact.title"));
|
|
253
|
+
c.append(el("div", "note", imp.hint || `unavailable (${imp.reason})`));
|
|
254
|
+
out.append(c);
|
|
255
|
+
}
|
|
256
|
+
return out;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* THE DOC TABLE. Ordered exactly as the CLI ordered it — THE PANEL NEVER
|
|
260
|
+
INVENTS A RANK (the `wiki plan` rule). A row expands IN PLACE. */
|
|
261
|
+
function wikiDocsCard(docs) {
|
|
262
|
+
const c = card(t("knowledge.docs.title"));
|
|
263
|
+
if (!docs || !docs.ok || !(docs.docs || []).length) {
|
|
264
|
+
c.append(empty(t("knowledge.docs.none"), (docs && docs.hint) || t("knowledge.docs.noneHint")));
|
|
265
|
+
return c;
|
|
266
|
+
}
|
|
267
|
+
c.append(el("div", "note", t("knowledge.docs.note")));
|
|
268
|
+
const scroll = el("div", "scroll-x");
|
|
269
|
+
const table = el("table");
|
|
270
|
+
const thead = el("thead");
|
|
271
|
+
const hr = el("tr");
|
|
272
|
+
for (const h of [
|
|
273
|
+
t("knowledge.docs.col.doc"),
|
|
274
|
+
t("knowledge.docs.col.tier"),
|
|
275
|
+
t("knowledge.docs.col.distance"),
|
|
276
|
+
t("knowledge.docs.col.covers"),
|
|
277
|
+
t("knowledge.docs.col.used"),
|
|
278
|
+
t("knowledge.docs.col.tags"),
|
|
279
|
+
])
|
|
280
|
+
hr.append(el("th", null, h));
|
|
281
|
+
thead.append(hr);
|
|
282
|
+
const tb = el("tbody");
|
|
283
|
+
const open = { row: null };
|
|
284
|
+
for (const r of docs.docs) {
|
|
285
|
+
const tr = el("tr", "kn-doc-row" + (r.retire_hint ? " row-muted" : ""));
|
|
286
|
+
tr.tabIndex = 0;
|
|
287
|
+
const detail = el("tr", "kn-doc-detail");
|
|
288
|
+
const dtd = el("td");
|
|
289
|
+
dtd.setAttribute("colspan", "6");
|
|
290
|
+
detail.append(dtd);
|
|
291
|
+
detail.hidden = true;
|
|
292
|
+
let loaded = false;
|
|
293
|
+
const toggle = () => {
|
|
294
|
+
const willOpen = detail.hidden;
|
|
295
|
+
// One row open at a time — the Runs-row rule.
|
|
296
|
+
if (open.row && open.row !== detail) {
|
|
297
|
+
open.row.hidden = true;
|
|
298
|
+
open.row.previousSibling.classList.remove("open");
|
|
299
|
+
}
|
|
300
|
+
detail.hidden = !willOpen;
|
|
301
|
+
tr.classList.toggle("open", willOpen);
|
|
302
|
+
open.row = willOpen ? detail : null;
|
|
303
|
+
if (willOpen && !loaded) {
|
|
304
|
+
loaded = true;
|
|
305
|
+
loadWikiDoc(dtd, r.file);
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
tr.addEventListener("click", toggle);
|
|
309
|
+
tr.addEventListener("keydown", (e) => {
|
|
310
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
311
|
+
e.preventDefault();
|
|
312
|
+
toggle();
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
tr.append(el("td", "mono", r.file.replace(/^wiki\//, "")));
|
|
316
|
+
const tc = el("td");
|
|
317
|
+
tc.append(chip(r.tier, r.tier === "FRESH" ? "ok" : r.tier === "AGING" ? "warn" : r.tier === "STALE" ? "bad" : ""));
|
|
318
|
+
tr.append(tc);
|
|
319
|
+
tr.append(el("td", "num", r.distance === null ? "?" : r.distance + "c"));
|
|
320
|
+
tr.append(el("td", "note", (r.covers || []).join(", ")));
|
|
321
|
+
// `used: null` is NOT zero-use — unknown must never be reported as dead.
|
|
322
|
+
tr.append(el("td", "num", r.used === null ? "?" : `${r.used}/${r.used_of}`));
|
|
323
|
+
tr.append(el("td", "num", String(r.crosslink_tags || 0)));
|
|
324
|
+
tb.append(tr, detail);
|
|
325
|
+
}
|
|
326
|
+
table.append(thead, tb);
|
|
327
|
+
scroll.append(table);
|
|
328
|
+
c.append(scroll);
|
|
329
|
+
return c;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async function loadWikiDoc(host, file) {
|
|
333
|
+
host.replaceChildren(skeleton(2));
|
|
334
|
+
const r = await read("/api/wiki/show?doc=" + encodeURIComponent(file)).catch(() => ({ data: null }));
|
|
335
|
+
const d = r.data;
|
|
336
|
+
if (!d || !d.ok) {
|
|
337
|
+
host.replaceChildren(el("div", "note", (d && d.hint) || t("common.loadFail")));
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const out = frag();
|
|
341
|
+
out.append(
|
|
342
|
+
kvList([
|
|
343
|
+
[t("knowledge.docs.field.title"), d.title || ""],
|
|
344
|
+
[t("knowledge.docs.field.type"), d.doc_type || ""],
|
|
345
|
+
[t("knowledge.docs.field.scanned"), d.scanned_commit ? String(d.scanned_commit).slice(0, 8) : ""],
|
|
346
|
+
[t("knowledge.docs.field.covers"), (d.covers || []).join(", ")],
|
|
347
|
+
[t("knowledge.docs.field.coveredFiles"), String(d.covered_files)],
|
|
348
|
+
[t("knowledge.docs.field.lastUsed"), d.last_used || t("knowledge.usage.neverUsed")],
|
|
349
|
+
])
|
|
350
|
+
);
|
|
351
|
+
if ((d.tags || []).length) {
|
|
352
|
+
const tl = el("div", "row-actions");
|
|
353
|
+
for (const tag of d.tags) tl.append(chip(tag.tag, "info"));
|
|
354
|
+
out.append(tl);
|
|
355
|
+
}
|
|
356
|
+
// Free repairs FIRST, as everywhere else on this panel.
|
|
357
|
+
for (const rep of d.free_repairs || []) {
|
|
358
|
+
const row = el("div", "free-row");
|
|
359
|
+
row.append(chip(t("knowledge.plan.free"), "ok"));
|
|
360
|
+
row.append(el("span", null, rep.what));
|
|
361
|
+
row.append(el("code", "mono", rep.cmd));
|
|
362
|
+
out.append(row);
|
|
363
|
+
}
|
|
364
|
+
// REVEAL. The body is fetched only on an explicit request, one artifact at a
|
|
365
|
+
// time, and it is rendered as DOM — never as HTML.
|
|
366
|
+
const reveal = el("button", "btn btn-ghost btn-sm", t("knowledge.reveal"));
|
|
367
|
+
reveal.type = "button";
|
|
368
|
+
reveal.addEventListener("click", async () => {
|
|
369
|
+
reveal.disabled = true;
|
|
370
|
+
const b = await read("/api/wiki/show?doc=" + encodeURIComponent(file) + "&body=1").catch(() => ({ data: null }));
|
|
371
|
+
const box = el("div", "kn-body");
|
|
372
|
+
box.append(renderMd((b.data && b.data.body) || ""));
|
|
373
|
+
reveal.replaceWith(box);
|
|
374
|
+
});
|
|
375
|
+
out.append(reveal);
|
|
376
|
+
host.replaceChildren(out);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/* ── TAB 2 — COVERAGE ────────────────────────────────────────────────────── */
|
|
380
|
+
function knCoverageTab(d) {
|
|
381
|
+
const out = frag();
|
|
382
|
+
const cov = d.coverage;
|
|
383
|
+
const c = card(t("knowledge.coverage.title"));
|
|
384
|
+
// The read itself failed — a crash, a timeout, output the server could not
|
|
385
|
+
// parse. That is a BROKEN PANEL, not a repo without a wiki, and it must never
|
|
386
|
+
// again be reported as the latter.
|
|
387
|
+
if (d.errors && d.errors.coverage) {
|
|
388
|
+
c.append(failBox(d.errors.coverage));
|
|
389
|
+
out.append(c);
|
|
390
|
+
return out;
|
|
391
|
+
}
|
|
392
|
+
if (!cov || !cov.ok) {
|
|
393
|
+
c.append(empty(t("knowledge.coverage.na"), (cov && cov.hint) || t("knowledge.coverage.naHint")));
|
|
394
|
+
out.append(c);
|
|
395
|
+
return out;
|
|
396
|
+
}
|
|
397
|
+
const big = el("div", "kn-coverage");
|
|
398
|
+
big.append(el("span", "kn-coverage-num", cov.coverage_pct + "%"));
|
|
399
|
+
big.append(el("span", "note", t("knowledge.coverage.sub", { covered: cov.covered, tracked: cov.tracked })));
|
|
400
|
+
c.append(big);
|
|
401
|
+
const bar = el("div", "kn-tierbar");
|
|
402
|
+
const seg = el("div", "kn-tierbar-seg kn-tier-ok");
|
|
403
|
+
seg.style.setProperty("--w", cov.coverage_pct + "%");
|
|
404
|
+
bar.append(seg);
|
|
405
|
+
const rest = el("div", "kn-tierbar-seg kn-tier-idle");
|
|
406
|
+
rest.style.setProperty("--w", 100 - cov.coverage_pct + "%");
|
|
407
|
+
bar.append(rest);
|
|
408
|
+
c.append(bar);
|
|
409
|
+
// NOT OPTIONAL CHROME. There is no threshold, no config key, and nothing
|
|
410
|
+
// branches on this number — a coverage percentage that starts nagging becomes
|
|
411
|
+
// a number people game.
|
|
412
|
+
c.append(el("div", "note", t("knowledge.coverage.notATarget")));
|
|
413
|
+
out.append(c);
|
|
414
|
+
|
|
415
|
+
if ((cov.uncovered_dirs || []).length) {
|
|
416
|
+
const uc = card(t("knowledge.coverage.uncovered"));
|
|
417
|
+
uc.append(el("div", "note", t("knowledge.coverage.uncoveredNote")));
|
|
418
|
+
const scroll = el("div", "scroll-x");
|
|
419
|
+
const table = el("table");
|
|
420
|
+
const thead = el("thead");
|
|
421
|
+
const hr = el("tr");
|
|
422
|
+
for (const h of [t("knowledge.coverage.col.dir"), t("knowledge.coverage.col.files"), t("knowledge.coverage.col.last")])
|
|
423
|
+
hr.append(el("th", null, h));
|
|
424
|
+
thead.append(hr);
|
|
425
|
+
const tb = el("tbody");
|
|
426
|
+
for (const row of cov.uncovered_dirs) {
|
|
427
|
+
const tr = el("tr");
|
|
428
|
+
tr.append(el("td", "mono", row.dir));
|
|
429
|
+
tr.append(el("td", "num", String(row.files)));
|
|
430
|
+
tr.append(el("td", "note", row.newest_commit || ""));
|
|
431
|
+
tb.append(tr);
|
|
432
|
+
}
|
|
433
|
+
table.append(thead, tb);
|
|
434
|
+
scroll.append(table);
|
|
435
|
+
uc.append(scroll);
|
|
436
|
+
out.append(uc);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// THE STRUCTURAL BLIND SPOT AS THE FILE LIST IT ALWAYS WAS — no longer as the
|
|
440
|
+
// number `2`, which tells a user nothing they can act on.
|
|
441
|
+
const blind = (d.wiki && d.wiki.blind_spot) || (d.impact && d.impact.blind_spot) || [];
|
|
442
|
+
const bc = card(t("knowledge.blind.title"));
|
|
443
|
+
if (!blind.length) {
|
|
444
|
+
bc.append(el("div", "note ok", t("knowledge.blind.none")));
|
|
445
|
+
} else {
|
|
446
|
+
bc.append(el("div", "note", t("knowledge.blind.note")));
|
|
447
|
+
const fl = el("div", "file-list");
|
|
448
|
+
for (const f of blind) fl.append(el("div", null, f));
|
|
449
|
+
bc.append(fl);
|
|
450
|
+
}
|
|
451
|
+
out.append(bc);
|
|
452
|
+
return out;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/* ── TAB 3 — PATTERNS ────────────────────────────────────────────────────── */
|
|
456
|
+
function knPatternsTab(d) {
|
|
457
|
+
const out = frag();
|
|
458
|
+
const p = d.patterns || {};
|
|
459
|
+
const pc = card(t("knowledge.patterns.title"));
|
|
460
|
+
pc.append(el("div", "note", t("knowledge.patterns.note")));
|
|
461
|
+
if (!(p.patterns || []).length) {
|
|
462
|
+
pc.append(empty(t("knowledge.patterns.none"), t("knowledge.patterns.noneHint")));
|
|
463
|
+
} else {
|
|
464
|
+
for (const row of p.patterns) {
|
|
465
|
+
const box = el("div", "kn-pattern");
|
|
466
|
+
const hdr = el("div", "row-actions");
|
|
467
|
+
// The language KEY is the CLI's framework id (`react`, `nestjs`, …) — a
|
|
468
|
+
// translated one would resolve to no playbook.
|
|
469
|
+
hdr.append(el("span", "mono", row.lang));
|
|
470
|
+
hdr.append(el("span", "note", relAge(row.mtime_ms)));
|
|
471
|
+
box.append(hdr);
|
|
472
|
+
box.append(el("div", "note mono", row.path));
|
|
473
|
+
const more = el("button", "btn btn-ghost btn-sm", t("knowledge.patterns.inspect"));
|
|
474
|
+
more.type = "button";
|
|
475
|
+
const detail = el("div", "stack stack-sm");
|
|
476
|
+
more.addEventListener("click", async () => {
|
|
477
|
+
more.disabled = true;
|
|
478
|
+
await loadPattern(detail, row.lang);
|
|
479
|
+
more.remove();
|
|
480
|
+
});
|
|
481
|
+
box.append(more, detail);
|
|
482
|
+
pc.append(box);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
// Known-but-uncached languages: PAID, so a command and never a button.
|
|
486
|
+
const cached = new Set((p.patterns || []).map((x) => x.lang));
|
|
487
|
+
const uncached = (p.known_languages || []).filter((l) => !cached.has(l));
|
|
488
|
+
if (uncached.length) {
|
|
489
|
+
pc.append(el("div", "note", t("knowledge.patterns.known", { list: uncached.join(", ") })));
|
|
490
|
+
for (const l of uncached.slice(0, 6)) pc.append(el("pre", "cmd", `/orc-pattern ${l}`));
|
|
491
|
+
pc.append(el("div", "note", t("knowledge.patterns.paidWhy")));
|
|
492
|
+
}
|
|
493
|
+
out.append(pc);
|
|
494
|
+
return out;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
async function loadPattern(host, lang) {
|
|
498
|
+
host.replaceChildren(skeleton(2));
|
|
499
|
+
const r = await read("/api/pattern/show?lang=" + encodeURIComponent(lang)).catch(() => ({ data: null }));
|
|
500
|
+
const d = r.data;
|
|
501
|
+
if (!d || !d.ok) {
|
|
502
|
+
host.replaceChildren(el("div", "note", (d && d.hint) || t("common.loadFail")));
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
const out = frag();
|
|
506
|
+
out.append(
|
|
507
|
+
kvList([
|
|
508
|
+
[t("knowledge.patterns.field.codified"), d.codified_at || "—"],
|
|
509
|
+
[t("knowledge.patterns.field.source"), d.source_commit ? String(d.source_commit).slice(0, 8) : "—"],
|
|
510
|
+
[t("knowledge.patterns.field.playbook"), d.playbook || "—"],
|
|
511
|
+
[t("knowledge.patterns.field.size"), `${d.lines} · ${d.bytes}`],
|
|
512
|
+
[t("knowledge.patterns.field.counts"), `${d.conventions} · ${d.invariants}`],
|
|
513
|
+
])
|
|
514
|
+
);
|
|
515
|
+
// An unheadered file SAYS SO in one line. No date is ever derived from an
|
|
516
|
+
// mtime — that is the `/orc-pact` UNCHECKABLE rule.
|
|
517
|
+
if (!d.headered) out.append(el("div", "note warn", t("knowledge.patterns.unheadered")));
|
|
518
|
+
if ((d.headings || []).length) {
|
|
519
|
+
const hl = el("div", "row-actions");
|
|
520
|
+
for (const h of d.headings.slice(0, 20)) hl.append(chip(h, ""));
|
|
521
|
+
out.append(hl);
|
|
522
|
+
}
|
|
523
|
+
// CONFLICTS get their own block: they are the most decision-shaped thing in
|
|
524
|
+
// the file (the project does X, the invariant says Y) and until now they were
|
|
525
|
+
// invisible outside it.
|
|
526
|
+
if ((d.conflicts || []).length) {
|
|
527
|
+
const cb = el("div", "kn-conflicts");
|
|
528
|
+
cb.append(el("div", "kn-conflicts-head", t("knowledge.patterns.conflicts")));
|
|
529
|
+
for (const c of d.conflicts) cb.append(el("div", "note", c));
|
|
530
|
+
out.append(cb);
|
|
531
|
+
}
|
|
532
|
+
const reveal = el("button", "btn btn-ghost btn-sm", t("knowledge.reveal"));
|
|
533
|
+
reveal.type = "button";
|
|
534
|
+
reveal.addEventListener("click", async () => {
|
|
535
|
+
reveal.disabled = true;
|
|
536
|
+
const b = await read("/api/pattern/show?lang=" + encodeURIComponent(lang) + "&body=1").catch(() => ({ data: null }));
|
|
537
|
+
const box = el("div", "kn-body");
|
|
538
|
+
box.append(renderMd((b.data && b.data.body) || ""));
|
|
539
|
+
reveal.replaceWith(box);
|
|
540
|
+
});
|
|
541
|
+
out.append(reveal);
|
|
542
|
+
out.append(el("div", "note", t("knowledge.patterns.literalNote")));
|
|
543
|
+
host.replaceChildren(out);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/* ── TAB 4 — MEMORY (gotchas) ────────────────────────────────────────────── */
|
|
547
|
+
function knMemoryTab(d, body) {
|
|
548
|
+
const out = frag();
|
|
549
|
+
const g = d.gotchas || {};
|
|
550
|
+
const gc = card(t("knowledge.gotchas.title"));
|
|
551
|
+
gc.append(el("div", "note", t("knowledge.gotchas.note")));
|
|
552
|
+
if (!g.count) {
|
|
553
|
+
gc.append(empty(t("knowledge.gotchas.none"), t("knowledge.gotchas.noneHint")));
|
|
554
|
+
out.append(gc);
|
|
555
|
+
return out;
|
|
556
|
+
}
|
|
557
|
+
const scroll = el("div", "scroll-x");
|
|
558
|
+
const table = el("table");
|
|
559
|
+
const thead = el("thead");
|
|
560
|
+
const hr = el("tr");
|
|
561
|
+
// These are the gotcha record's own field names, printed by `orc gotcha
|
|
562
|
+
// list` — column headers stay in the file's vocabulary.
|
|
563
|
+
for (const h of ["Id", "Area", "Kind", "Hits", "Last seen", "Trigger"]) hr.append(el("th", null, h));
|
|
564
|
+
thead.append(hr);
|
|
565
|
+
const tb = el("tbody");
|
|
566
|
+
const open = { row: null };
|
|
567
|
+
for (const e of g.gotchas) {
|
|
568
|
+
const tr = el("tr", "kn-doc-row");
|
|
569
|
+
tr.tabIndex = 0;
|
|
570
|
+
const detail = el("tr", "kn-doc-detail");
|
|
571
|
+
const dtd = el("td");
|
|
572
|
+
dtd.setAttribute("colspan", "6");
|
|
573
|
+
detail.append(dtd);
|
|
574
|
+
detail.hidden = true;
|
|
575
|
+
// EVERY FIELD the CLI already emits. `gotchaStatus` has always sent
|
|
576
|
+
// `fields`; the panel rendered six columns and discarded the rest.
|
|
577
|
+
dtd.append(kvList(Object.keys(e.fields || {}).map((k) => [k, e.fields[k]])));
|
|
578
|
+
const toggle = () => {
|
|
579
|
+
const willOpen = detail.hidden;
|
|
580
|
+
if (open.row && open.row !== detail) {
|
|
581
|
+
open.row.hidden = true;
|
|
582
|
+
open.row.previousSibling.classList.remove("open");
|
|
583
|
+
}
|
|
584
|
+
detail.hidden = !willOpen;
|
|
585
|
+
tr.classList.toggle("open", willOpen);
|
|
586
|
+
open.row = willOpen ? detail : null;
|
|
587
|
+
};
|
|
588
|
+
tr.addEventListener("click", toggle);
|
|
589
|
+
tr.addEventListener("keydown", (ev) => {
|
|
590
|
+
if (ev.key === "Enter" || ev.key === " ") {
|
|
591
|
+
ev.preventDefault();
|
|
592
|
+
toggle();
|
|
593
|
+
}
|
|
594
|
+
});
|
|
595
|
+
tr.append(
|
|
596
|
+
el("td", "mono", e.id),
|
|
597
|
+
el("td", "mono", e.area),
|
|
598
|
+
el("td", null, e.kind),
|
|
599
|
+
el("td", null, String(e.hits)),
|
|
600
|
+
el("td", "note", e.last_seen || "?"),
|
|
601
|
+
el("td", "note", e.trigger || "")
|
|
602
|
+
);
|
|
603
|
+
tb.append(tr, detail);
|
|
604
|
+
}
|
|
605
|
+
table.append(thead, tb);
|
|
606
|
+
scroll.append(table);
|
|
607
|
+
gc.append(scroll);
|
|
608
|
+
gc.append(gotchaPruneBox(g, body));
|
|
609
|
+
out.append(gc);
|
|
610
|
+
|
|
611
|
+
// The archive is reachable and clearly labelled as recoverable: eviction is
|
|
612
|
+
// an ARCHIVE, never a delete.
|
|
613
|
+
const ac = card(t("knowledge.archive.title"));
|
|
614
|
+
const load = el("button", "btn btn-ghost btn-sm", t("knowledge.archive.load"));
|
|
615
|
+
load.type = "button";
|
|
616
|
+
load.addEventListener("click", async () => {
|
|
617
|
+
load.disabled = true;
|
|
618
|
+
const r = await read("/api/gotchas/archived").catch((e) => ({ data: null, error: e }));
|
|
619
|
+
const a = r.data;
|
|
620
|
+
const box = el("div", "stack stack-sm");
|
|
621
|
+
if (!a || !a.count) box.append(el("div", "note", t("knowledge.archive.empty")));
|
|
622
|
+
else for (const e of a.gotchas) box.append(el("div", "note mono", `${e.id} · ${e.area} · ${e.kind} · hits ${e.hits}`));
|
|
623
|
+
load.replaceWith(box);
|
|
624
|
+
});
|
|
625
|
+
ac.append(el("div", "note", t("knowledge.archive.note")));
|
|
626
|
+
ac.append(load);
|
|
627
|
+
out.append(ac);
|
|
628
|
+
return out;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/* PREVIEW-THEN-APPLY. The Apply button stays disabled until a preview has been
|
|
632
|
+
fetched, the exact command is on screen throughout, and THE PREVIEW NAMES
|
|
633
|
+
EVERY ENTRY that would be archived — a count is not consent. */
|
|
634
|
+
function gotchaPruneBox(g, body) {
|
|
635
|
+
const box = el("div", "kn-prune");
|
|
636
|
+
const cfgMax = g.gotchas_max;
|
|
637
|
+
box.append(el("div", "kn-prune-head", t("knowledge.gotchas.headroom", { n: g.count, max: cfgMax === undefined ? "?" : cfgMax })));
|
|
638
|
+
box.append(el("pre", "cmd", "orc gotcha prune"));
|
|
639
|
+
const acts = el("div", "row-actions");
|
|
640
|
+
const preview = el("button", "btn btn-sm", t("knowledge.gotchas.preview"));
|
|
641
|
+
preview.type = "button";
|
|
642
|
+
const apply = el("button", "btn btn-sm btn-primary", t("knowledge.gotchas.prune"));
|
|
643
|
+
apply.type = "button";
|
|
644
|
+
apply.disabled = true;
|
|
645
|
+
const list = el("div", "stack stack-sm");
|
|
646
|
+
preview.addEventListener("click", async () => {
|
|
647
|
+
const r = await read("/api/gotcha/prune/preview").catch((e) => ({ data: null, error: e }));
|
|
648
|
+
const d = r.data;
|
|
649
|
+
list.replaceChildren();
|
|
650
|
+
if (!d || !(d.would_archive || []).length) {
|
|
651
|
+
list.append(el("div", "note ok", t("knowledge.gotchas.pruneNone")));
|
|
652
|
+
apply.disabled = true;
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
list.append(el("div", "note warn", t("knowledge.gotchas.pruneWould", { n: d.would_archive.length })));
|
|
656
|
+
for (const e of d.would_archive) list.append(el("div", "note mono", `${e.id} · ${e.area} · ${e.kind} · hits ${e.hits} · ${e.last_seen || "?"}`));
|
|
657
|
+
list.append(el("div", "note", d.honesty));
|
|
658
|
+
apply.disabled = false;
|
|
659
|
+
});
|
|
660
|
+
apply.addEventListener("click", async () => {
|
|
661
|
+
const r = await post("/api/gotcha/prune", {});
|
|
662
|
+
toast(r.command, r.ok ? "ok" : "bad", r.output);
|
|
663
|
+
renderKnowledge(body);
|
|
664
|
+
});
|
|
665
|
+
acts.append(preview, apply);
|
|
666
|
+
box.append(acts, list);
|
|
667
|
+
return box;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/* ── TAB 5 — PEERS ───────────────────────────────────────────────────────── */
|
|
671
|
+
/* COMPACT and READ-ONLY. It links to Crosslink and NEVER duplicates its editor:
|
|
672
|
+
one boundary, one picture. This tab exists because "what does ORC know?"
|
|
673
|
+
includes what it knows from next door, and that is where a user looks first. */
|
|
674
|
+
function knPeersTab(d) {
|
|
675
|
+
const out = frag();
|
|
676
|
+
const c = card(t("knowledge.peers.title"));
|
|
677
|
+
c.append(el("div", "note", t("knowledge.peers.note")));
|
|
678
|
+
const go = el("button", "btn btn-ghost btn-sm", t("knowledge.peers.open"));
|
|
679
|
+
go.type = "button";
|
|
680
|
+
go.addEventListener("click", () => {
|
|
681
|
+
location.hash = "#/crosslink";
|
|
682
|
+
});
|
|
683
|
+
c.append(go);
|
|
684
|
+
out.append(c);
|
|
685
|
+
renderPeers(c);
|
|
686
|
+
return out;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
async function renderPeers(host) {
|
|
690
|
+
const r = await read("/api/crosslink").catch((e) => ({ data: null, error: e }));
|
|
691
|
+
const d = r.data;
|
|
692
|
+
if (!d) return;
|
|
693
|
+
if (!d.configured || !(d.nodes || []).length) {
|
|
694
|
+
host.append(el("div", "note", t("knowledge.peers.none")));
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
const scroll = el("div", "scroll-x");
|
|
698
|
+
const table = el("table");
|
|
699
|
+
const thead = el("thead");
|
|
700
|
+
const hr = el("tr");
|
|
701
|
+
for (const h of [
|
|
702
|
+
t("knowledge.peers.col.repo"),
|
|
703
|
+
t("knowledge.peers.col.state"),
|
|
704
|
+
t("knowledge.peers.col.tier"),
|
|
705
|
+
t("knowledge.peers.col.tags"),
|
|
706
|
+
])
|
|
707
|
+
hr.append(el("th", null, h));
|
|
708
|
+
thead.append(hr);
|
|
709
|
+
const tb = el("tbody");
|
|
710
|
+
for (const n of d.nodes) {
|
|
711
|
+
const prov = n.provider || {};
|
|
712
|
+
const tr = el("tr");
|
|
713
|
+
tr.append(el("td", "mono", n.name));
|
|
714
|
+
const st = el("td");
|
|
715
|
+
// Every word here is the CLI's own — the peer's state, and the peer's
|
|
716
|
+
// freshness tier as IT computed it. A peer's config is not ours to read
|
|
717
|
+
// (`crosslinkProviderInfo`), so nothing here is recomputed on this side.
|
|
718
|
+
st.append(chip(prov.state || "—", prov.state === "wiki" ? "ok" : "warn"));
|
|
719
|
+
tr.append(st);
|
|
720
|
+
const tc = el("td");
|
|
721
|
+
if (prov.tier) tc.append(chip(prov.tier, prov.tier === "FRESH" ? "ok" : prov.tier === "AGING" ? "warn" : "bad"));
|
|
722
|
+
else tc.append(el("span", "note", "—"));
|
|
723
|
+
tr.append(tc);
|
|
724
|
+
tr.append(el("td", "num", prov.tags === undefined ? "—" : String(prov.tags)));
|
|
725
|
+
tb.append(tr);
|
|
726
|
+
}
|
|
727
|
+
table.append(thead, tb);
|
|
728
|
+
scroll.append(table);
|
|
729
|
+
host.append(scroll);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
/* PART B MADE VISIBLE (v0.46.0).
|
|
733
|
+
|
|
734
|
+
THE PANEL MUST NEVER COMPUTE THE ORDER, THE TIER OR THE ESTIMATE ITSELF — it
|
|
735
|
+
renders `orc wiki plan --json`'s rows in the order they arrive and nothing
|
|
736
|
+
else, the same rule the Flow stepper lives under. A second idea of "which doc
|
|
737
|
+
matters most" is exactly the drift this panel exists to make impossible.
|
|
738
|
+
|
|
739
|
+
And: a `used 0/20` row KEEPS ITS SLOT, rendered muted with a retire hint.
|
|
740
|
+
Filtering it out would make "nobody reads this" and "this does not exist"
|
|
741
|
+
look identical — the same rule as an OFF phase in the stepper. */
|
|
742
|
+
function wikiPlanCard(plan, debt, body) {
|
|
743
|
+
const c = card(t("knowledge.plan"), wikiPlanActions(body, plan));
|
|
744
|
+
|
|
745
|
+
if (!plan || !plan.ok) {
|
|
746
|
+
c.append(empty(t("knowledge.plan.na"), t("knowledge.plan.naHint")));
|
|
747
|
+
return c;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// The debt line first: the habit this whole workstream is aiming at.
|
|
751
|
+
if (debt && debt.ok && debt.pending) {
|
|
752
|
+
const chips = el("div", "row-actions");
|
|
753
|
+
chips.append(chip(tn(debt.pending, "knowledge.debt.pending"), "warn"));
|
|
754
|
+
if (debt.tokens) chips.append(chip(kTokUi(debt.tokens.input + debt.tokens.cache_write + debt.tokens.cache_read + debt.tokens.output), null));
|
|
755
|
+
if (debt.usd !== null && debt.usd !== undefined) chips.append(chip("$" + debt.usd.toFixed(2), null));
|
|
756
|
+
if (debt.oldest_commits_behind !== null) chips.append(chip(tn(debt.oldest_commits_behind, "knowledge.debt.oldest"), null));
|
|
757
|
+
c.append(chips);
|
|
758
|
+
c.append(el("div", "note", t("knowledge.debt.nothingBroken")));
|
|
759
|
+
} else if (debt && debt.ok) {
|
|
760
|
+
c.append(el("div", "note ok", t("knowledge.debt.none")));
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
if (!plan.rows || !plan.rows.length) {
|
|
764
|
+
c.append(el("div", "note ok", t("knowledge.plan.clean")));
|
|
765
|
+
return c;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// FREE REPAIRS FIRST — a user must never be able to pay for something a free
|
|
769
|
+
// step would have fixed, so they render ABOVE the priced table.
|
|
770
|
+
if (plan.free_repairs && plan.free_repairs.length) {
|
|
771
|
+
const box = el("div", "free-box");
|
|
772
|
+
box.append(el("div", "free-head", t("knowledge.plan.freeFirst")));
|
|
773
|
+
for (const r of plan.free_repairs) {
|
|
774
|
+
const row = el("div", "free-row");
|
|
775
|
+
row.append(chip(t("knowledge.plan.free"), "ok"));
|
|
776
|
+
row.append(el("span", null, r.what));
|
|
777
|
+
row.append(el("code", "mono", r.cmd));
|
|
778
|
+
box.append(row);
|
|
779
|
+
}
|
|
780
|
+
c.append(box);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
const tbl = el("table", "tbl");
|
|
784
|
+
const th = el("tr");
|
|
785
|
+
for (const h of ["knowledge.plan.col.doc", "knowledge.plan.col.state", "knowledge.plan.col.delta", "knowledge.plan.col.used", "knowledge.plan.col.tier", "knowledge.plan.col.tokens", "knowledge.plan.col.usd"])
|
|
786
|
+
th.append(el("th", null, t(h)));
|
|
787
|
+
tbl.append(th);
|
|
788
|
+
for (const r of plan.rows) {
|
|
789
|
+
const tr = el("tr", r.retire_hint ? "row-muted" : null);
|
|
790
|
+
tr.append(el("td", "mono", r.doc.replace(/^wiki\//, "")));
|
|
791
|
+
// The CLI's exact state words. Never a friendlier synonym.
|
|
792
|
+
const stateCell = el("td");
|
|
793
|
+
stateCell.append(chip(r.state, r.state === "STRUCTURAL" ? "bad" : "warn"));
|
|
794
|
+
tr.append(stateCell);
|
|
795
|
+
tr.append(el("td", "num", r.state === "STRUCTURAL" ? "—" : String(r.delta)));
|
|
796
|
+
tr.append(el("td", "num", r.used === null ? "?" : `${r.used}/${r.used_of}`));
|
|
797
|
+
tr.append(el("td", null, r.tier));
|
|
798
|
+
const est = r.estimate;
|
|
799
|
+
tr.append(el("td", "num", est ? kTokUi(est.p50.input + est.p50.cache_write + est.p50.cache_read + est.p50.output) : "—"));
|
|
800
|
+
// The dollar figure is the CLI's — the panel never prices anything itself,
|
|
801
|
+
// and a row the CLI could not price shows an em dash rather than a guess.
|
|
802
|
+
tr.append(el("td", "num", r.usd === null || r.usd === undefined ? "—" : "$" + r.usd.toFixed(2)));
|
|
803
|
+
tbl.append(tr);
|
|
804
|
+
if (r.state === "STRUCTURAL" && r.gone && r.gone.length) {
|
|
805
|
+
const note = el("tr", "row-note");
|
|
806
|
+
const td = el("td", null, t("knowledge.plan.gone", { files: r.gone.slice(0, 3).join(", ") }));
|
|
807
|
+
td.setAttribute("colspan", "7");
|
|
808
|
+
note.append(td);
|
|
809
|
+
tbl.append(note);
|
|
810
|
+
}
|
|
811
|
+
if (r.retire_hint) {
|
|
812
|
+
const note = el("tr", "row-note");
|
|
813
|
+
const td = el("td", null, t("knowledge.plan.retireHint", { n: r.used_of }));
|
|
814
|
+
td.setAttribute("colspan", "7");
|
|
815
|
+
note.append(td);
|
|
816
|
+
tbl.append(note);
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
c.append(tbl);
|
|
820
|
+
if (plan.estimate_unavailable) c.append(el("div", "note", t("knowledge.plan.noEstimate")));
|
|
821
|
+
c.append(el("div", "note", t("knowledge.plan.tierNote", { mode: plan.scan_tier_mode, deep: plan.deep, light: plan.light })));
|
|
822
|
+
// A refresh COSTS MONEY, so it is a command, never a button.
|
|
823
|
+
c.append(laneCommand(`/orc-wiki refresh --top ${Math.min(2, plan.rows.length)}`, t("knowledge.plan.refreshWhy")));
|
|
824
|
+
return c;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
function wikiPlanActions(body, plan) {
|
|
828
|
+
const wrap = el("div", "row-actions");
|
|
829
|
+
// `orc wiki sync` is FREE ($0.00), so it gets a button.
|
|
830
|
+
const s = el("button", "btn btn-sm", t("knowledge.syncFree"));
|
|
831
|
+
s.type = "button";
|
|
832
|
+
s.addEventListener("click", async () => {
|
|
833
|
+
const r = await post("/api/wiki/sync", {});
|
|
834
|
+
toast(r.ok ? t("knowledge.syncOk") : t("common.writeFail"), r.ok ? "ok" : "bad", r.output);
|
|
835
|
+
renderKnowledge(body);
|
|
836
|
+
});
|
|
837
|
+
wrap.append(s);
|
|
838
|
+
void plan;
|
|
839
|
+
return wrap;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function wikiUsageCard(u, body) {
|
|
843
|
+
const c = card(t("knowledge.usage"), (() => {
|
|
844
|
+
const wrap = el("div", "row-actions");
|
|
845
|
+
const b = el("button", "btn btn-ghost btn-sm", t("knowledge.usage.rebuild"));
|
|
846
|
+
b.type = "button";
|
|
847
|
+
b.addEventListener("click", async () => {
|
|
848
|
+
const r = await post("/api/wiki/usage/rebuild", {});
|
|
849
|
+
toast(r.ok ? t("knowledge.usage.rebuilt") : t("common.writeFail"), r.ok ? "ok" : "bad", r.output);
|
|
850
|
+
renderKnowledge(body);
|
|
851
|
+
});
|
|
852
|
+
wrap.append(b);
|
|
853
|
+
return wrap;
|
|
854
|
+
})());
|
|
855
|
+
const chips = el("div", "row-actions");
|
|
856
|
+
chips.append(chip(t("knowledge.usage.registered", { n: u.registered }), null));
|
|
857
|
+
chips.append(chip(t("knowledge.usage.active", { n: u.in_active_use }), "ok"));
|
|
858
|
+
if (u.never_used) chips.append(chip(t("knowledge.usage.never", { n: u.never_used, runs: u.window_runs }), "warn"));
|
|
859
|
+
c.append(chips);
|
|
860
|
+
const body2 = el("div", "usage-rows");
|
|
861
|
+
for (const r of u.rows) {
|
|
862
|
+
const row = el("div", "usage-row" + (r.used ? "" : " row-muted"));
|
|
863
|
+
row.append(el("span", "mono", r.doc.replace(/^wiki\//, "")));
|
|
864
|
+
const track = el("div", "bar-track");
|
|
865
|
+
const fill = el("div", "bar-fill");
|
|
866
|
+
track.append(fill);
|
|
867
|
+
requestAnimationFrame(() => fill.style.setProperty("width", Math.max(2, (r.used / (r.of || 1)) * 100) + "%"));
|
|
868
|
+
row.append(track);
|
|
869
|
+
row.append(el("span", "bar-value", `${r.used}/${r.of}`));
|
|
870
|
+
row.append(el("span", "note", r.last_used || t("knowledge.usage.neverUsed")));
|
|
871
|
+
body2.append(row);
|
|
872
|
+
}
|
|
873
|
+
c.append(body2);
|
|
874
|
+
c.append(el("div", "note", t("knowledge.usage.note")));
|
|
875
|
+
return c;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
function wikiActions(body, w) {
|
|
879
|
+
if (!w || !w.state || w.state === "none") return null;
|
|
880
|
+
const wrap = el("div", "row-actions");
|
|
881
|
+
const sync = el("button", "btn btn-sm", "orc wiki sync");
|
|
882
|
+
sync.type = "button";
|
|
883
|
+
sync.addEventListener("click", async () => {
|
|
884
|
+
const r = await post("/api/wiki/sync", {});
|
|
885
|
+
toast(r.command, r.ok ? "ok" : "bad", r.output);
|
|
886
|
+
renderKnowledge(body);
|
|
887
|
+
});
|
|
888
|
+
wrap.append(sync);
|
|
889
|
+
return wrap;
|
|
890
|
+
}
|