@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,557 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* serve.js — the `orc ui` http server.
|
|
4
|
+
*
|
|
5
|
+
* NOTE THE NAME: this is `bin/webui/`, not `bin/ui/`. `bin/ui.js` is the
|
|
6
|
+
* TERMINAL styling kit (colors, glyphs, boxes) the CLI prints through. Two
|
|
7
|
+
* different things; the user-facing command is still `orc ui`.
|
|
8
|
+
*
|
|
9
|
+
* The server can write config, so it is treated as a write surface throughout:
|
|
10
|
+
* loopback bind only, a per-launch token on every /api call, a Host-header
|
|
11
|
+
* check against DNS rebinding, no CORS headers at all, POST-only mutations,
|
|
12
|
+
* and a token that is never logged.
|
|
13
|
+
*
|
|
14
|
+
* It never runs a lane, never spawns `claude`, never calls a model API. Every
|
|
15
|
+
* byte it serves or writes comes from `bin/cli.js`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const http = require("http");
|
|
19
|
+
const fs = require("fs");
|
|
20
|
+
const path = require("path");
|
|
21
|
+
const crypto = require("crypto");
|
|
22
|
+
const { spawn } = require("child_process");
|
|
23
|
+
const { handleApi } = require("./api.js");
|
|
24
|
+
|
|
25
|
+
const DEFAULT_PORT = 9921;
|
|
26
|
+
const PORT_WALK_MAX = 9930;
|
|
27
|
+
// No heartbeat from ANY client for this long → exit. Closing the tab shuts the
|
|
28
|
+
// server down within about a minute.
|
|
29
|
+
const HEARTBEAT_GRACE_MS = 60_000;
|
|
30
|
+
// Backstop for a client that died without a beacon (laptop sleep, browser
|
|
31
|
+
// crash, killed tab process) — it never sent a heartbeat OR a bye.
|
|
32
|
+
const DEFAULT_IDLE_MIN = 30;
|
|
33
|
+
const LOCK_REL = path.join("orc", "ui.lock");
|
|
34
|
+
|
|
35
|
+
// ── the static map ──────────────────────────────────────────────────────────
|
|
36
|
+
// The panel is ~55 files (v0.48.1), so the old hand-written table became a
|
|
37
|
+
// maintenance trap: a new stylesheet that nobody added to it 401s, and the
|
|
38
|
+
// symptom is an unstyled page rather than an error anyone can read.
|
|
39
|
+
//
|
|
40
|
+
// It is built by a ONE-TIME walk at server start, never per request. A request
|
|
41
|
+
// path is therefore still a KEY LOOKUP in a frozen table and never a path join
|
|
42
|
+
// — directory traversal stays structurally impossible, which is a STRONGER
|
|
43
|
+
// guarantee than the hand-written table gave, not a weaker one.
|
|
44
|
+
//
|
|
45
|
+
// The string tables are static assets rather than an API route on purpose:
|
|
46
|
+
// they are shipped data with no CLI behind them, so adding a language is
|
|
47
|
+
// dropping JSON into i18n/ and naming it in LANGS — no server change.
|
|
48
|
+
const TYPES = {
|
|
49
|
+
".html": "text/html; charset=utf-8",
|
|
50
|
+
".css": "text/css; charset=utf-8",
|
|
51
|
+
".js": "text/javascript; charset=utf-8",
|
|
52
|
+
".json": "application/json; charset=utf-8",
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Server-side code is NEVER served. These are required by node, not fetched by
|
|
56
|
+
// the browser, and shipping them would hand a reader the API surface map.
|
|
57
|
+
const NEVER_SERVE = new Set(["serve.js", "api.js", "fixtures.js"]);
|
|
58
|
+
|
|
59
|
+
function buildStatic(rootDir) {
|
|
60
|
+
const map = Object.create(null);
|
|
61
|
+
const walk = (dir, prefix) => {
|
|
62
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
63
|
+
const rel = prefix ? prefix + "/" + e.name : e.name;
|
|
64
|
+
// fixtures/ is canned data for `--fixtures`; api.js reads it in-process.
|
|
65
|
+
if (e.isDirectory()) {
|
|
66
|
+
if (e.name === "fixtures") continue;
|
|
67
|
+
walk(path.join(dir, e.name), rel);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (NEVER_SERVE.has(rel)) continue;
|
|
71
|
+
const type = TYPES[path.extname(e.name)];
|
|
72
|
+
if (!type) continue;
|
|
73
|
+
// The key is the POSIX-normalised path relative to bin/webui/, so Windows
|
|
74
|
+
// and macOS agree on it — the /api/fs/list precedent.
|
|
75
|
+
map["/" + rel] = { file: path.join(...rel.split("/")), type };
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
walk(rootDir, "");
|
|
79
|
+
map["/"] = map["/app.html"];
|
|
80
|
+
return map;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const STATIC = buildStatic(__dirname);
|
|
84
|
+
|
|
85
|
+
// ── the lock file ───────────────────────────────────────────────────────────
|
|
86
|
+
// `.claude/orc/ui.lock` — project-scoped like everything else, and the thing
|
|
87
|
+
// that makes re-running `orc ui` idempotent, `--stop` possible, and a forgotten
|
|
88
|
+
// server findable. It lives under .claude/orc/, which `isPrunable` in cli.js
|
|
89
|
+
// can never match, so `orc update --prune` will not delete it.
|
|
90
|
+
|
|
91
|
+
function lockPath(claudeDir) {
|
|
92
|
+
return path.join(claudeDir, LOCK_REL);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function readLock(claudeDir) {
|
|
96
|
+
try {
|
|
97
|
+
const raw = JSON.parse(fs.readFileSync(lockPath(claudeDir), "utf8"));
|
|
98
|
+
if (raw && raw.pid && raw.port && raw.token) return raw;
|
|
99
|
+
} catch (_) {}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function writeLock(claudeDir, data) {
|
|
104
|
+
const p = lockPath(claudeDir);
|
|
105
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
106
|
+
fs.writeFileSync(p, JSON.stringify(data, null, 2) + "\n");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function removeLock(claudeDir) {
|
|
110
|
+
try {
|
|
111
|
+
fs.rmSync(lockPath(claudeDir));
|
|
112
|
+
} catch (_) {}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function pidAlive(pid) {
|
|
116
|
+
try {
|
|
117
|
+
// Signal 0 tests for existence without touching the process.
|
|
118
|
+
process.kill(pid, 0);
|
|
119
|
+
return true;
|
|
120
|
+
} catch (e) {
|
|
121
|
+
// EPERM means it exists and belongs to someone else — still alive.
|
|
122
|
+
return e.code === "EPERM";
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// A lock whose pid is dead is stale: delete it and start fresh.
|
|
127
|
+
function liveLock(claudeDir) {
|
|
128
|
+
const lock = readLock(claudeDir);
|
|
129
|
+
if (!lock) return null;
|
|
130
|
+
if (pidAlive(lock.pid)) return lock;
|
|
131
|
+
removeLock(claudeDir);
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function urlFor(port, token) {
|
|
136
|
+
return `http://127.0.0.1:${port}/?t=${token}`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ── restarting in place ─────────────────────────────────────────────────────
|
|
140
|
+
//
|
|
141
|
+
// `orc upgrade` replaces the package this process is RUNNING FROM. Node read
|
|
142
|
+
// bin/webui into memory at require time, and `STATIC` is a one-time walk at
|
|
143
|
+
// boot, so an upgraded panel keeps serving the old bytes until something
|
|
144
|
+
// restarts it. Until now that something was the user: stop the server, re-run
|
|
145
|
+
// `orc ui`, find the new URL, open it. Three manual steps to see the release
|
|
146
|
+
// they just installed.
|
|
147
|
+
//
|
|
148
|
+
// So the server hands itself over. The successor is spawned DETACHED with the
|
|
149
|
+
// SAME port and the SAME token, which is the whole trick — the URL in the
|
|
150
|
+
// user's address bar stays valid, so the open tab only has to reload.
|
|
151
|
+
//
|
|
152
|
+
// THE TOKEN TRAVELS IN THE ENVIRONMENT, NEVER IN ARGV. It authenticates a write
|
|
153
|
+
// surface, which puts it in the same class as the credentials `orc extra`
|
|
154
|
+
// refuses to accept on a command line: argv is world-readable in a process
|
|
155
|
+
// list and lands in shell history, while a child's environment is readable by
|
|
156
|
+
// its owner. It is read ONCE at boot and deleted from process.env immediately,
|
|
157
|
+
// so the CLI subprocesses this server shells out to never inherit it.
|
|
158
|
+
const RESTART_ENV_TOKEN = "ORC_UI_TOKEN";
|
|
159
|
+
const RESTART_ENV_FLAG = "ORC_UI_RESTART";
|
|
160
|
+
// The successor binds the port its predecessor has only just released. A few
|
|
161
|
+
// hundred milliseconds of EADDRINUSE is normal and is not an error worth
|
|
162
|
+
// showing anybody.
|
|
163
|
+
const RESTART_BIND_RETRIES = 20;
|
|
164
|
+
const RESTART_BIND_WAIT_MS = 250;
|
|
165
|
+
|
|
166
|
+
function spawnSuccessor({ claudeDir, projectRoot, port, token, idleMinutes }) {
|
|
167
|
+
const cli = path.join(__dirname, "..", "cli.js");
|
|
168
|
+
const argv = [cli, "ui", "--port", String(port), "--no-open", "--idle", String(idleMinutes)];
|
|
169
|
+
if (projectRoot) argv.push("--dir", projectRoot);
|
|
170
|
+
const env = Object.assign({}, process.env);
|
|
171
|
+
env[RESTART_ENV_TOKEN] = token;
|
|
172
|
+
env[RESTART_ENV_FLAG] = "1";
|
|
173
|
+
const child = spawn(process.execPath, argv, {
|
|
174
|
+
detached: true,
|
|
175
|
+
stdio: "ignore",
|
|
176
|
+
windowsHide: true,
|
|
177
|
+
cwd: projectRoot || undefined,
|
|
178
|
+
env,
|
|
179
|
+
});
|
|
180
|
+
child.unref();
|
|
181
|
+
return child.pid;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ── open a browser ──────────────────────────────────────────────────────────
|
|
185
|
+
// Best-effort and never fatal: the URL is always printed, so a failed open is
|
|
186
|
+
// an inconvenience, not an error.
|
|
187
|
+
function openBrowser(url) {
|
|
188
|
+
try {
|
|
189
|
+
const [cmd, args] =
|
|
190
|
+
process.platform === "win32"
|
|
191
|
+
? ["cmd", ["/c", "start", "", url]]
|
|
192
|
+
: process.platform === "darwin"
|
|
193
|
+
? ["open", [url]]
|
|
194
|
+
: ["xdg-open", [url]];
|
|
195
|
+
const child = spawn(cmd, args, { detached: true, stdio: "ignore", windowsHide: true });
|
|
196
|
+
child.unref();
|
|
197
|
+
return true;
|
|
198
|
+
} catch (_) {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ── `orc ui --stop` ─────────────────────────────────────────────────────────
|
|
204
|
+
// Exit 0 if something was stopped, 1 if nothing was running — the same
|
|
205
|
+
// exit-code convention as `orc resume` and `orc pattern status`.
|
|
206
|
+
function stop(claudeDir) {
|
|
207
|
+
const lock = liveLock(claudeDir);
|
|
208
|
+
if (!lock) {
|
|
209
|
+
removeLock(claudeDir);
|
|
210
|
+
console.log("No orc ui server is running for this project.");
|
|
211
|
+
return 1;
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
process.kill(lock.pid);
|
|
215
|
+
} catch (_) {}
|
|
216
|
+
removeLock(claudeDir);
|
|
217
|
+
console.log(`Stopped the orc ui server (pid ${lock.pid}, port ${lock.port}).`);
|
|
218
|
+
return 0;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// ── binding ─────────────────────────────────────────────────────────────────
|
|
222
|
+
// Port free → bind it. Port held by anything else → walk 9922…9930 — but ONLY
|
|
223
|
+
// when the port was the default. An EXPLICIT --port never auto-increments: if
|
|
224
|
+
// you asked for a specific port and it is taken, that is an error, not a silent
|
|
225
|
+
// move to somewhere you are not looking.
|
|
226
|
+
function listen(server, port, explicit, retries = 0) {
|
|
227
|
+
return new Promise((resolve, reject) => {
|
|
228
|
+
let left = retries;
|
|
229
|
+
const tryPort = (p) => {
|
|
230
|
+
const onError = (err) => {
|
|
231
|
+
server.removeListener("listening", onOk);
|
|
232
|
+
if (err.code !== "EADDRINUSE") return reject(err);
|
|
233
|
+
// A SUCCESSOR waits for the port rather than moving or failing. Its
|
|
234
|
+
// predecessor released it moments ago and the whole point of the
|
|
235
|
+
// handover is that the URL already in the user's address bar keeps
|
|
236
|
+
// working — walking to another port would break exactly what this is
|
|
237
|
+
// trying to preserve.
|
|
238
|
+
if (left > 0) {
|
|
239
|
+
left--;
|
|
240
|
+
setTimeout(() => tryPort(p), RESTART_BIND_WAIT_MS);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (explicit)
|
|
244
|
+
return reject(
|
|
245
|
+
Object.assign(new Error(`port ${p} is already in use`), { code: "EADDRINUSE", port: p })
|
|
246
|
+
);
|
|
247
|
+
if (p >= PORT_WALK_MAX)
|
|
248
|
+
return reject(
|
|
249
|
+
Object.assign(new Error(`ports ${DEFAULT_PORT}-${PORT_WALK_MAX} are all in use`), {
|
|
250
|
+
code: "ENOPORT",
|
|
251
|
+
})
|
|
252
|
+
);
|
|
253
|
+
tryPort(p + 1);
|
|
254
|
+
};
|
|
255
|
+
const onOk = () => {
|
|
256
|
+
server.removeListener("error", onError);
|
|
257
|
+
resolve(p);
|
|
258
|
+
};
|
|
259
|
+
server.once("error", onError);
|
|
260
|
+
server.once("listening", onOk);
|
|
261
|
+
// 127.0.0.1 ONLY — never 0.0.0.0. This is a write surface.
|
|
262
|
+
server.listen(p, "127.0.0.1");
|
|
263
|
+
};
|
|
264
|
+
tryPort(port);
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ── security ────────────────────────────────────────────────────────────────
|
|
269
|
+
|
|
270
|
+
// DNS-rebinding guard. A page on evil.example can make a browser resolve a
|
|
271
|
+
// hostname to 127.0.0.1 and reach this server; the Host header it sends is that
|
|
272
|
+
// attacker hostname, never a loopback literal. Anything but a loopback Host is
|
|
273
|
+
// refused before routing.
|
|
274
|
+
function loopbackHost(hostHeader, port) {
|
|
275
|
+
if (!hostHeader) return false;
|
|
276
|
+
const h = String(hostHeader).trim().toLowerCase();
|
|
277
|
+
return (
|
|
278
|
+
h === `127.0.0.1:${port}` ||
|
|
279
|
+
h === `localhost:${port}` ||
|
|
280
|
+
h === `[::1]:${port}` ||
|
|
281
|
+
h === "127.0.0.1" ||
|
|
282
|
+
h === "localhost"
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Constant-time compare so a token cannot be recovered by timing the reply.
|
|
287
|
+
function tokenOk(given, expected) {
|
|
288
|
+
if (typeof given !== "string" || given.length !== expected.length) return false;
|
|
289
|
+
return crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ── the server ──────────────────────────────────────────────────────────────
|
|
293
|
+
|
|
294
|
+
async function serve(opts) {
|
|
295
|
+
const {
|
|
296
|
+
claudeDir,
|
|
297
|
+
projectRoot,
|
|
298
|
+
port: wantPort,
|
|
299
|
+
explicitPort,
|
|
300
|
+
open = true,
|
|
301
|
+
idleMinutes = DEFAULT_IDLE_MIN,
|
|
302
|
+
fixtures = false,
|
|
303
|
+
version = "",
|
|
304
|
+
} = opts;
|
|
305
|
+
|
|
306
|
+
// The handoff from a predecessor that is on its way out, read ONCE and then
|
|
307
|
+
// removed from the environment so no CLI subprocess ever inherits the token.
|
|
308
|
+
const inheritedToken = process.env[RESTART_ENV_TOKEN] || null;
|
|
309
|
+
const isSuccessor = process.env[RESTART_ENV_FLAG] === "1" && !!inheritedToken;
|
|
310
|
+
delete process.env[RESTART_ENV_TOKEN];
|
|
311
|
+
delete process.env[RESTART_ENV_FLAG];
|
|
312
|
+
|
|
313
|
+
// Idempotent relaunch: a live server for THIS project is not replaced by a
|
|
314
|
+
// second one — read its lock, verify the pid, and just open the browser at
|
|
315
|
+
// the recorded port and token.
|
|
316
|
+
//
|
|
317
|
+
// A SUCCESSOR SKIPS THIS. The lock it would find names its own predecessor,
|
|
318
|
+
// which is either dying or already gone; treating that as "already running"
|
|
319
|
+
// would make the restart a silent no-op and leave the user on the old build
|
|
320
|
+
// with no way to tell.
|
|
321
|
+
if (!fixtures && !isSuccessor) {
|
|
322
|
+
const existing = liveLock(claudeDir);
|
|
323
|
+
if (existing) {
|
|
324
|
+
const url = urlFor(existing.port, existing.token);
|
|
325
|
+
console.log(`orc ui is already running for this project (pid ${existing.pid}).`);
|
|
326
|
+
console.log(` ${url}`);
|
|
327
|
+
if (open) openBrowser(url);
|
|
328
|
+
console.log(" Stop it with: orc ui --stop");
|
|
329
|
+
return 0;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const token = inheritedToken || crypto.randomBytes(32).toString("hex");
|
|
334
|
+
const startedMs = Date.now();
|
|
335
|
+
let lastContact = Date.now();
|
|
336
|
+
let boundPort = wantPort;
|
|
337
|
+
// Has a browser ever talked to us? Until one has, only the idle timeout
|
|
338
|
+
// applies — otherwise a `--no-open` launch would shut itself down in 60s.
|
|
339
|
+
let sawClient = false;
|
|
340
|
+
// One handover per process. A second request while the successor is starting
|
|
341
|
+
// is answered with the same "yes, it is happening" rather than spawning two.
|
|
342
|
+
let restarting = false;
|
|
343
|
+
|
|
344
|
+
const ctx = {
|
|
345
|
+
claudeDir,
|
|
346
|
+
projectRoot,
|
|
347
|
+
fixtures,
|
|
348
|
+
version,
|
|
349
|
+
startedMs,
|
|
350
|
+
idleMinutes,
|
|
351
|
+
get port() {
|
|
352
|
+
return boundPort;
|
|
353
|
+
},
|
|
354
|
+
onHeartbeat() {
|
|
355
|
+
lastContact = Date.now();
|
|
356
|
+
sawClient = true;
|
|
357
|
+
},
|
|
358
|
+
onBye() {
|
|
359
|
+
// A beacon is a hint, not a command: another tab may still be open, so
|
|
360
|
+
// the heartbeat window — not this call — decides the actual shutdown.
|
|
361
|
+
lastContact = Date.now() - HEARTBEAT_GRACE_MS + 3000;
|
|
362
|
+
},
|
|
363
|
+
// Hand this project's panel over to a fresh process on the same port and
|
|
364
|
+
// token. CLIENT-TRIGGERED, always: the server never restarts itself the
|
|
365
|
+
// moment a job finishes, because the job's output lives in memory and a
|
|
366
|
+
// restart the user did not ask for would take the record of what just ran
|
|
367
|
+
// with it. It also means a tab that is already closed leaves the old
|
|
368
|
+
// process running the old code, which is the safe resting state.
|
|
369
|
+
restart() {
|
|
370
|
+
if (fixtures) return { ok: false, reason: "fixtures" };
|
|
371
|
+
if (restarting) return { ok: true, already: true, port: boundPort };
|
|
372
|
+
restarting = true;
|
|
373
|
+
// The lock is deliberately NOT removed. The successor overwrites it with
|
|
374
|
+
// the same port and token under its own pid; if the spawn fails instead,
|
|
375
|
+
// the lock names a dead pid and `liveLock` cleans it up on the next
|
|
376
|
+
// launch. Removing it here would open a window where `orc ui` sees no
|
|
377
|
+
// server and starts a second one somewhere else.
|
|
378
|
+
let pid = null;
|
|
379
|
+
try {
|
|
380
|
+
pid = spawnSuccessor({ claudeDir, projectRoot, port: boundPort, token, idleMinutes });
|
|
381
|
+
} catch (e) {
|
|
382
|
+
restarting = false;
|
|
383
|
+
return { ok: false, reason: "spawn-failed", error: String(e && e.message) };
|
|
384
|
+
}
|
|
385
|
+
// Stop listening FIRST so the successor can take the port, then leave.
|
|
386
|
+
// The delay is only long enough for this response to reach the browser
|
|
387
|
+
// that asked for it.
|
|
388
|
+
setTimeout(() => {
|
|
389
|
+
console.log("\norc ui — handing over to a fresh process on port " + boundPort + " (pid " + pid + ")");
|
|
390
|
+
try {
|
|
391
|
+
server.close();
|
|
392
|
+
} catch (_) {}
|
|
393
|
+
process.exit(0);
|
|
394
|
+
}, 250);
|
|
395
|
+
return { ok: true, pid, port: boundPort, url: urlFor(boundPort, token) };
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
|
|
399
|
+
const server = http.createServer((req, res) => {
|
|
400
|
+
lastContact = Date.now();
|
|
401
|
+
let url;
|
|
402
|
+
try {
|
|
403
|
+
url = new URL(req.url, `http://127.0.0.1:${boundPort}`);
|
|
404
|
+
} catch (_) {
|
|
405
|
+
res.writeHead(400).end();
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (!loopbackHost(req.headers.host, boundPort)) {
|
|
410
|
+
// Deliberately terse: an attacker learns nothing, and this can only be
|
|
411
|
+
// hit by something that is not the local browser we opened.
|
|
412
|
+
res.writeHead(403, { "content-type": "text/plain" }).end("forbidden\n");
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// No CORS headers at ALL — no Access-Control-Allow-*, ever. A cross-origin
|
|
417
|
+
// page must not be able to read a single byte of this.
|
|
418
|
+
const given = url.searchParams.get("t") || req.headers["x-orc-token"];
|
|
419
|
+
const authed = tokenOk(given, token);
|
|
420
|
+
|
|
421
|
+
const stat = STATIC[url.pathname];
|
|
422
|
+
if (stat) {
|
|
423
|
+
if (!authed) {
|
|
424
|
+
res
|
|
425
|
+
.writeHead(401, { "content-type": "text/html; charset=utf-8" })
|
|
426
|
+
.end(
|
|
427
|
+
"<h1>orc ui</h1><p>This link is missing its session token. Re-run <code>orc ui</code> " +
|
|
428
|
+
"in your project to get a fresh URL.</p>"
|
|
429
|
+
);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
let body;
|
|
433
|
+
try {
|
|
434
|
+
body = fs.readFileSync(path.join(__dirname, stat.file));
|
|
435
|
+
} catch (_) {
|
|
436
|
+
res.writeHead(500, { "content-type": "text/plain" }).end("missing asset\n");
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
// The token is required on EVERY request, and a <link>/<script> in the
|
|
440
|
+
// HTML carries no query string of its own — so every asset would 401 and
|
|
441
|
+
// the page would render as unstyled, scriptless markup. Stamp the live
|
|
442
|
+
// token onto EVERY asset reference as the shell goes out. Doing it here
|
|
443
|
+
// (rather than with a cookie) keeps the token explicit per request: there
|
|
444
|
+
// is no ambient credential a cross-origin page could ever ride on.
|
|
445
|
+
//
|
|
446
|
+
// Generic since v0.48.1: naming the two files was fine when there were
|
|
447
|
+
// two. With ~55 the pattern has to be the rule, or the next <script> tag
|
|
448
|
+
// someone adds 401s silently. A test parses app.html and asserts every
|
|
449
|
+
// href/src comes back stamped AND resolves to a real entry in STATIC.
|
|
450
|
+
if (stat.file === "app.html") {
|
|
451
|
+
body = Buffer.from(
|
|
452
|
+
body
|
|
453
|
+
.toString("utf8")
|
|
454
|
+
.replace(
|
|
455
|
+
/(href|src)="([\w./-]+\.(?:css|js))"/g,
|
|
456
|
+
(m, attr, ref) => `${attr}="${ref}?t=${token}"`
|
|
457
|
+
),
|
|
458
|
+
"utf8"
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
res.writeHead(200, {
|
|
462
|
+
"content-type": stat.type,
|
|
463
|
+
"cache-control": "no-store",
|
|
464
|
+
"x-content-type-options": "nosniff",
|
|
465
|
+
// The page loads only its own inline-free assets and talks only to
|
|
466
|
+
// itself; nothing external is ever fetched.
|
|
467
|
+
"content-security-policy":
|
|
468
|
+
"default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'self'; base-uri 'none'; form-action 'none'",
|
|
469
|
+
"referrer-policy": "no-referrer",
|
|
470
|
+
});
|
|
471
|
+
res.end(body);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (!url.pathname.startsWith("/api/")) {
|
|
476
|
+
res.writeHead(404, { "content-type": "text/plain" }).end("not found\n");
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (!authed) {
|
|
480
|
+
res
|
|
481
|
+
.writeHead(401, { "content-type": "application/json" })
|
|
482
|
+
.end(JSON.stringify({ error: "bad or missing token" }));
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
// Mutations are POST-only, enforced here as well as in the router, so a GET
|
|
486
|
+
// can never reach a write path however the table is later edited.
|
|
487
|
+
if (req.method !== "GET" && req.method !== "POST") {
|
|
488
|
+
res.writeHead(405, { "content-type": "application/json" }).end(JSON.stringify({ error: "method not allowed" }));
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
Promise.resolve(handleApi(req, res, url, ctx)).catch((e) => {
|
|
492
|
+
if (res.headersSent) return;
|
|
493
|
+
res.writeHead(500, { "content-type": "application/json" }).end(JSON.stringify({ error: String(e && e.message) }));
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
try {
|
|
498
|
+
boundPort = await listen(server, wantPort, explicitPort, isSuccessor ? RESTART_BIND_RETRIES : 0);
|
|
499
|
+
} catch (e) {
|
|
500
|
+
if (e.code === "EADDRINUSE")
|
|
501
|
+
console.error(
|
|
502
|
+
`❌ port ${e.port} is already in use.\n` +
|
|
503
|
+
" You asked for that port explicitly, so orc ui will not move to another one.\n" +
|
|
504
|
+
" Pick a different one with --port <n>, or stop whatever holds it."
|
|
505
|
+
);
|
|
506
|
+
else if (e.code === "ENOPORT")
|
|
507
|
+
console.error(
|
|
508
|
+
`❌ ports ${DEFAULT_PORT}-${PORT_WALK_MAX} are all in use.\n` +
|
|
509
|
+
" Choose one yourself with: orc ui --port <n>"
|
|
510
|
+
);
|
|
511
|
+
else console.error("❌ could not start the orc ui server: " + e.message);
|
|
512
|
+
return 1;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
const url = urlFor(boundPort, token);
|
|
516
|
+
if (!fixtures) writeLock(claudeDir, { pid: process.pid, port: boundPort, token, started_ms: startedMs });
|
|
517
|
+
|
|
518
|
+
// The token is part of the URL the user needs; it is never written to a log
|
|
519
|
+
// line of its own, and never echoed by any /api response.
|
|
520
|
+
console.log(`\norc ui — ${fixtures ? "FIXTURE MODE (canned data, nothing real is read)" : projectRoot}`);
|
|
521
|
+
console.log(` ${url}`);
|
|
522
|
+
console.log(
|
|
523
|
+
" " +
|
|
524
|
+
(idleMinutes > 0
|
|
525
|
+
? `Shuts down ~1 min after the last tab closes, or after ${idleMinutes} idle minutes.`
|
|
526
|
+
: "Idle timeout disabled (--idle 0) — stop it with `orc ui --stop`.")
|
|
527
|
+
);
|
|
528
|
+
console.log(" Stop it now with: orc ui --stop (or Ctrl-C here)\n");
|
|
529
|
+
if (open) openBrowser(url);
|
|
530
|
+
|
|
531
|
+
// A shutdown is never mysterious: the reason is printed to the terminal this
|
|
532
|
+
// was launched from.
|
|
533
|
+
const shutdown = (reason, code = 0) => {
|
|
534
|
+
console.log(`\norc ui stopped — ${reason}`);
|
|
535
|
+
if (!fixtures) removeLock(claudeDir);
|
|
536
|
+
try {
|
|
537
|
+
server.close();
|
|
538
|
+
} catch (_) {}
|
|
539
|
+
process.exit(code);
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
const idleMs = idleMinutes > 0 ? idleMinutes * 60_000 : 0;
|
|
543
|
+
const timer = setInterval(() => {
|
|
544
|
+
const quiet = Date.now() - lastContact;
|
|
545
|
+
// 1) Heartbeat: a client WAS here and has stopped pinging → the tab closed.
|
|
546
|
+
if (sawClient && quiet > HEARTBEAT_GRACE_MS) shutdown("the browser tab closed");
|
|
547
|
+
// 2) Idle: nothing at all for the whole window → nobody is using this.
|
|
548
|
+
if (idleMs && quiet > idleMs) shutdown(`idle for ${idleMinutes} minutes`);
|
|
549
|
+
}, 5000);
|
|
550
|
+
timer.unref();
|
|
551
|
+
|
|
552
|
+
for (const sig of ["SIGINT", "SIGTERM"]) process.on(sig, () => shutdown(`received ${sig}`));
|
|
553
|
+
|
|
554
|
+
return new Promise(() => {}); // run until a shutdown path exits
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
module.exports = { serve, stop, readLock, liveLock, lockPath, removeLock, loopbackHost, buildStatic, DEFAULT_PORT, PORT_WALK_MAX, HEARTBEAT_GRACE_MS, DEFAULT_IDLE_MIN };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Mocked runs — what each ORC lane looks like when it runs
|
|
2
|
+
|
|
3
|
+
New to ORC? Start here. Every file below is a **mocked run**: the screen you
|
|
4
|
+
would see, the questions you would be asked, and the files that would land on
|
|
5
|
+
disk — written the way the real lane writes them.
|
|
6
|
+
|
|
7
|
+
Nothing here was executed. It is documentation, and it is here because you
|
|
8
|
+
should not have to spend tokens to find out what a command does.
|
|
9
|
+
|
|
10
|
+
All of it uses **easy English**, short sentences, and the same fake project.
|
|
11
|
+
|
|
12
|
+
> **Read it in the panel instead:** `orc ui` ▸ **Mocked Skill Use** — the same
|
|
13
|
+
> documents, searchable, with a reading pane. From the terminal:
|
|
14
|
+
> `orc mock-run list` and `orc mock-run show <slug>`.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Start here
|
|
19
|
+
|
|
20
|
+
| Doc | What it shows |
|
|
21
|
+
|---|---|
|
|
22
|
+
| [The example project](the-example-project.md) | `shopcart`, the fake project every mock uses, and how to read these files |
|
|
23
|
+
| [A normal day](a-normal-day.md) | `/orc-pact`, `/orc-boundary`, `/orc-budget`, `/orc-aftermath` and the rest, all inside one ordinary run |
|
|
24
|
+
|
|
25
|
+
## Build a change
|
|
26
|
+
|
|
27
|
+
| Doc | Lane | One line |
|
|
28
|
+
|---|---|---|
|
|
29
|
+
| [orc](orc.md) | `/orc` | The full pipeline: intake → plan → score → parallel waves → review → verify → ship |
|
|
30
|
+
| [orc-ultra](orc-ultra.md) | `/orc-ultra` | The same, plus an advisor and three judgment gates. Costs the most |
|
|
31
|
+
| [orc-mini](../templates/skills/orc-mini/examples/mini-run-mock.md) | `/orc-mini` | One executor, a smoke gate, ship |
|
|
32
|
+
| [orc-fast](orc-fast.md) | `/orc-fast` | No analyst, no planner — the wiki and the pattern already did that work |
|
|
33
|
+
| [orc-quick](orc-quick.md) | `/orc-quick` | Ask for anything. Look → ask once → do, and it always asks which agent |
|
|
34
|
+
| [orc-diy](orc-diy.md) | `/orc-diy` | Your own lane, composed in the terminal and compiled |
|
|
35
|
+
|
|
36
|
+
## Decide what to build
|
|
37
|
+
|
|
38
|
+
| Doc | Lane | One line |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| [orc-brainstorm](orc-brainstorm.md) | `/orc-brainstorm` | No idea yet: it generates the options and **you** pick |
|
|
41
|
+
| [orc-grill](orc-grill.md) | `/orc-grill` | One vague idea, sharpened by questions — it never answers its own |
|
|
42
|
+
| [orc-doc](orc-doc.md) | `/orc-doc` | A PRD, TSD, agreement, report or runbook — written in parts, so nothing holds it all |
|
|
43
|
+
| [orc-plan](orc-plan.md) | `/orc-plan` | A real task plan: grounded files, dependencies, facets, test dispositions |
|
|
44
|
+
| [orc-route](orc-route.md) | `/orc-route` | You have a plan — which lane should build it, and which cannot |
|
|
45
|
+
| [orc-explain](orc-explain.md) | `/orc-explain` | "Wait, what?" — it says the last message again, properly |
|
|
46
|
+
| [orc-analyze](../templates/skills/orc-analyze/examples/analyze-mock.md) | `/orc-analyze` | A document turned into code-grounded requirements |
|
|
47
|
+
| [orc-analyze-mini](../templates/skills/orc-analyze-mini/examples/quick-analysis-mock.md) | *(inside `/orc-mini`)* | The same, single pass, much cheaper |
|
|
48
|
+
| [context-combiner](context-combiner.md) | — | Two related analyses merged into one spec, with a 100% conservation gate |
|
|
49
|
+
| [orc-poly](../templates/skills/orc-poly/examples/poly-run-mock.md) | `/orc-poly` | One change across two or more repos, without drift |
|
|
50
|
+
|
|
51
|
+
## Teach ORC your project
|
|
52
|
+
|
|
53
|
+
| Doc | Lane | One line |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| [orc-wiki](../templates/skills/orc-wiki/examples/wiki-run-mock.md) | `/orc-wiki` | Scan the codebase into an evidence-anchored knowledge base |
|
|
56
|
+
| [orc-pattern](orc-pattern.md) | `/orc-pattern` | Learn your real conventions so executors match your house style |
|
|
57
|
+
| [orc-learn](../templates/skills/orc-learn/examples/learn-run-mock.md) | `/orc-learn` | Onboarding docs for a human, per feature |
|
|
58
|
+
| [orc-claude](../templates/skills/orc-claude/examples/claude-run-mock.md) | `/orc-claude` | Build or refresh this repo's `CLAUDE.md` from verified facts |
|
|
59
|
+
| [orc-export](orc-export.md) | `/orc-export` | Compile it all into a portable `AGENTS.md` so ORC is not a trap |
|
|
60
|
+
|
|
61
|
+
## Check what happened
|
|
62
|
+
|
|
63
|
+
| Doc | Lane | One line |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| [orc-verify](../templates/skills/orc-verify/examples/verify-mock.md) | `/orc-verify` | Verify only your git-modified changes. Read-only |
|
|
66
|
+
| [orc-challenge](orc-challenge.md) | `/orc-challenge` | Grade a finished document, then stop and make you fix it in another session |
|
|
67
|
+
| [orc-challenge-council](orc-challenge-council.md) | `/orc-challenge` | Six more ways of looking at the same document — and you choose which ones run |
|
|
68
|
+
| [orc-pact](orc-pact.md) | `/orc-pact` | The promises your system makes, and which are in doubt right now |
|
|
69
|
+
| [orc-boundary](orc-boundary.md) | `/orc-boundary` | What the agent should **not** try here, and what would change that |
|
|
70
|
+
| [orc-aftermath](orc-aftermath.md) | `/orc-aftermath` | Did what we shipped hold up. Churn is a signal, never a verdict |
|
|
71
|
+
| [orc-budget](orc-budget.md) | `/orc-budget` | What a run costs, in the unit you are billed in |
|
|
72
|
+
| [orc-retro](../templates/skills/orc-retro/examples/retro-mock.md) | `/orc-retro` | Mine the behavior traces into a calibration report |
|
|
73
|
+
|
|
74
|
+
## Ship and hand over
|
|
75
|
+
|
|
76
|
+
| Doc | Lane | One line |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| [orc-pr-setup / orc-pr-driver](orc-pr-setup.md) | `/orc-pr-setup`, `/orc-pr-driver` | Split a big change into a stack of PRs, then build and merge them |
|
|
79
|
+
| [orc-handoff](orc-handoff.md) | `/orc-handoff` | What a non-developer can safely change, graded by whether a check exists |
|
|
80
|
+
|
|
81
|
+
## Panel and terminal
|
|
82
|
+
|
|
83
|
+
| Doc | One line |
|
|
84
|
+
|---|---|
|
|
85
|
+
| [orc-ui](orc-ui.md) | The local control panel for everything that is not ai (**video placeholder here**) |
|
|
86
|
+
| [orc-cli](orc-cli.md) | The terminal commands: install, config, probes, run state, stats |
|
|
87
|
+
| [orc-extra](orc-extra.md) | Run some of ORC's work on a different AI model, and still know what left your machine |
|
|
88
|
+
| [extra-recovery](extra-recovery.md) | When that other model stops half-way: what it left on disk, whose fault it was, and how to continue |
|
|
89
|
+
| [extra-slots](extra-slots.md) | The four lanes that never score a task: giving one JOB to a cheaper model, and what ORC says before it does |
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Two kinds of document
|
|
94
|
+
|
|
95
|
+
- **Walkthroughs** (this folder) — written for a person, in easy English.
|
|
96
|
+
- **Annotated examples** (`templates/skills/<skill>/examples/`) — dense, written
|
|
97
|
+
for the model, and shipped inside your `.claude/` install. Both appear in
|
|
98
|
+
`orc mock-run list` and in the **Mocked Skill Use** panel.
|
|
99
|
+
|
|
100
|
+
## Adding one
|
|
101
|
+
|
|
102
|
+
Drop a `.md` file in this folder with a `# Title` heading and a `> one line`
|
|
103
|
+
summary under it. It appears in `orc mock-run`, in the panel, and here — no list
|
|
104
|
+
to update anywhere else. Reading order comes from `GROUP_OF` in
|
|
105
|
+
[`bin/mockrun-catalog.js`](../bin/mockrun-catalog.js); a file nobody placed
|
|
106
|
+
there still shows, under **More**.
|