dsh-compound-engineering 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +160 -2
- package/README.zh.md +161 -0
- package/cordis.patch.yml +6 -0
- package/lib/frontmatter.js +167 -0
- package/lib/index.js +46 -0
- package/lib/provider.js +201 -0
- package/package.json +62 -4
- package/skills/CODING_STANDARDS.md +68 -0
- package/skills/ce-babysit-pr/SKILL.md +59 -0
- package/skills/ce-babysit-pr/references/branch-currency.md +22 -0
- package/skills/ce-babysit-pr/references/envelope.md +44 -0
- package/skills/ce-babysit-pr/references/pipeline.md +15 -0
- package/skills/ce-babysit-pr/references/report.md +20 -0
- package/skills/ce-babysit-pr/references/settle.md +37 -0
- package/skills/ce-babysit-pr/references/setup.md +33 -0
- package/skills/ce-babysit-pr/references/stack-commands.md +39 -0
- package/skills/ce-babysit-pr/references/stack.md +43 -0
- package/skills/ce-babysit-pr/references/tick.md +102 -0
- package/skills/ce-babysit-pr/references/watch-loop.md +222 -0
- package/skills/ce-babysit-pr/scripts/pr-snapshot +3656 -0
- package/skills/ce-bakeoff/SKILL.md +48 -0
- package/skills/ce-bakeoff/references/candidates.md +37 -0
- package/skills/ce-bakeoff/references/judging.md +19 -0
- package/skills/ce-bakeoff/references/output.md +11 -0
- package/skills/ce-bakeoff/references/verification.md +15 -0
- package/skills/ce-brainstorm/SKILL.md +69 -0
- package/skills/ce-brainstorm/references/agents/slack-researcher.md +127 -0
- package/skills/ce-brainstorm/references/approaches.md +57 -0
- package/skills/ce-brainstorm/references/bakeoff.md +9 -0
- package/skills/ce-brainstorm/references/blindspot-pass.md +70 -0
- package/skills/ce-brainstorm/references/brainstorm-sections.md +458 -0
- package/skills/ce-brainstorm/references/dialogue.md +89 -0
- package/skills/ce-brainstorm/references/handoff.md +187 -0
- package/skills/ce-brainstorm/references/html-rendering.md +638 -0
- package/skills/ce-brainstorm/references/interaction-rules.md +33 -0
- package/skills/ce-brainstorm/references/markdown-rendering.md +242 -0
- package/skills/ce-brainstorm/references/model-tiers.md +13 -0
- package/skills/ce-brainstorm/references/output-mode.md +26 -0
- package/skills/ce-brainstorm/references/phase-0.md +104 -0
- package/skills/ce-brainstorm/references/plan-write.md +32 -0
- package/skills/ce-brainstorm/references/product-pressure-test.md +42 -0
- package/skills/ce-brainstorm/references/reasoning-elevation.md +124 -0
- package/skills/ce-brainstorm/references/settled-decisions.md +45 -0
- package/skills/ce-brainstorm/references/synthesis-summary.md +149 -0
- package/skills/ce-brainstorm/references/universal-brainstorming.md +72 -0
- package/skills/ce-brainstorm/references/verdict-routing.md +26 -0
- package/skills/ce-brainstorm/references/visual-probes.md +164 -0
- package/skills/ce-brainstorm/scripts/elevation-dispatch.sh +288 -0
- package/skills/ce-brainstorm/scripts/light-webserver.js +1275 -0
- package/skills/ce-brainstorm/scripts/packs-resolve.py +737 -0
- package/skills/ce-brainstorm/scripts/peer-job-runner.py +2594 -0
- package/skills/ce-code-review/SKILL.md +40 -0
- package/skills/ce-code-review/references/action-class-rubric.md +67 -0
- package/skills/ce-code-review/references/cross-model-recovery.md +38 -0
- package/skills/ce-code-review/references/cross-model-review.md +191 -0
- package/skills/ce-code-review/references/depth-paths.md +32 -0
- package/skills/ce-code-review/references/diff-scope.md +59 -0
- package/skills/ce-code-review/references/dispatch-reviewers.md +135 -0
- package/skills/ce-code-review/references/findings-schema.json +125 -0
- package/skills/ce-code-review/references/finish-input.md +118 -0
- package/skills/ce-code-review/references/finish-review.md +202 -0
- package/skills/ce-code-review/references/intent-and-plan.md +73 -0
- package/skills/ce-code-review/references/modes-and-output.md +156 -0
- package/skills/ce-code-review/references/persona-catalog.md +66 -0
- package/skills/ce-code-review/references/personas/adversarial-reviewer.md +111 -0
- package/skills/ce-code-review/references/personas/agent-native-reviewer.md +173 -0
- package/skills/ce-code-review/references/personas/api-contract-reviewer.md +44 -0
- package/skills/ce-code-review/references/personas/correctness-reviewer.md +48 -0
- package/skills/ce-code-review/references/personas/data-migration-reviewer.md +111 -0
- package/skills/ce-code-review/references/personas/deployment-verification-agent.md +157 -0
- package/skills/ce-code-review/references/personas/julik-frontend-races-reviewer.md +45 -0
- package/skills/ce-code-review/references/personas/learnings-researcher.md +260 -0
- package/skills/ce-code-review/references/personas/maintainability-reviewer.md +85 -0
- package/skills/ce-code-review/references/personas/performance-reviewer.md +45 -0
- package/skills/ce-code-review/references/personas/previous-comments-reviewer.md +59 -0
- package/skills/ce-code-review/references/personas/project-standards-reviewer.md +77 -0
- package/skills/ce-code-review/references/personas/reliability-reviewer.md +49 -0
- package/skills/ce-code-review/references/personas/security-reviewer.md +50 -0
- package/skills/ce-code-review/references/personas/swift-ios-reviewer.md +99 -0
- package/skills/ce-code-review/references/personas/testing-reviewer.md +51 -0
- package/skills/ce-code-review/references/review-output-template.md +172 -0
- package/skills/ce-code-review/references/scope.md +176 -0
- package/skills/ce-code-review/references/select-and-route.md +93 -0
- package/skills/ce-code-review/references/subagent-template.md +206 -0
- package/skills/ce-code-review/references/validator-batch-template.md +67 -0
- package/skills/ce-code-review/scripts/cross-model-adversarial-review.sh +1275 -0
- package/skills/ce-code-review/scripts/findings-mechanics.py +274 -0
- package/skills/ce-code-review/scripts/packs-resolve.py +737 -0
- package/skills/ce-code-review/scripts/peer-job-runner.py +2594 -0
- package/skills/ce-code-review/scripts/review-scope.py +419 -0
- package/skills/ce-code-review/scripts/run-log.py +280 -0
- package/skills/ce-commit/SKILL.md +60 -0
- package/skills/ce-commit-push-pr/SKILL.md +69 -0
- package/skills/ce-commit-push-pr/references/apply-and-handoff.md +79 -0
- package/skills/ce-commit-push-pr/references/branch-creation.md +47 -0
- package/skills/ce-commit-push-pr/references/commit-and-push.md +26 -0
- package/skills/ce-commit-push-pr/references/compose.md +29 -0
- package/skills/ce-commit-push-pr/references/context.md +42 -0
- package/skills/ce-commit-push-pr/references/gh-stack-cli.md +83 -0
- package/skills/ce-commit-push-pr/references/pr-description-writing.md +208 -0
- package/skills/ce-commit-push-pr/references/stack-submit.md +81 -0
- package/skills/ce-compound/SKILL.md +79 -0
- package/skills/ce-compound/assets/resolution-template.md +96 -0
- package/skills/ce-compound/references/agents/best-practices-researcher.md +115 -0
- package/skills/ce-compound/references/agents/data-integrity-guardian.md +68 -0
- package/skills/ce-compound/references/agents/framework-docs-researcher.md +93 -0
- package/skills/ce-compound/references/agents/pattern-recognition-specialist.md +55 -0
- package/skills/ce-compound/references/agents/performance-oracle.md +108 -0
- package/skills/ce-compound/references/agents/security-sentinel.md +91 -0
- package/skills/ce-compound/references/agents/session-historian.md +82 -0
- package/skills/ce-compound/references/assembly.md +127 -0
- package/skills/ce-compound/references/concepts-vocabulary.md +98 -0
- package/skills/ce-compound/references/enhancement.md +42 -0
- package/skills/ce-compound/references/grounding-validation.md +89 -0
- package/skills/ce-compound/references/lightweight.md +56 -0
- package/skills/ce-compound/references/modes.md +13 -0
- package/skills/ce-compound/references/refresh-and-discoverability.md +96 -0
- package/skills/ce-compound/references/report.md +115 -0
- package/skills/ce-compound/references/research.md +144 -0
- package/skills/ce-compound/references/schema.yaml +236 -0
- package/skills/ce-compound/references/session-history.md +73 -0
- package/skills/ce-compound/references/yaml-schema.md +130 -0
- package/skills/ce-compound/scripts/packs-resolve.py +737 -0
- package/skills/ce-compound/scripts/session-history/__pycache__/dsh_session.cpython-314.pyc +0 -0
- package/skills/ce-compound/scripts/session-history/discover-sessions.sh +290 -0
- package/skills/ce-compound/scripts/session-history/discover_dsh.py +123 -0
- package/skills/ce-compound/scripts/session-history/dsh_session.py +225 -0
- package/skills/ce-compound/scripts/session-history/extract-errors.py +178 -0
- package/skills/ce-compound/scripts/session-history/extract-metadata.py +301 -0
- package/skills/ce-compound/scripts/session-history/extract-skeleton.py +346 -0
- package/skills/ce-compound/scripts/validate-doc-claims.py +497 -0
- package/skills/ce-compound/scripts/validate-frontmatter.py +137 -0
- package/skills/ce-compound-refresh/SKILL.md +88 -0
- package/skills/ce-compound-refresh/assets/resolution-template.md +96 -0
- package/skills/ce-compound-refresh/references/classify.md +42 -0
- package/skills/ce-compound-refresh/references/commit.md +7 -0
- package/skills/ce-compound-refresh/references/concepts-vocabulary.md +116 -0
- package/skills/ce-compound-refresh/references/discoverability.md +15 -0
- package/skills/ce-compound-refresh/references/investigate.md +23 -0
- package/skills/ce-compound-refresh/references/modes.md +27 -0
- package/skills/ce-compound-refresh/references/per-action-flows.md +142 -0
- package/skills/ce-compound-refresh/references/report.md +23 -0
- package/skills/ce-compound-refresh/references/schema.yaml +236 -0
- package/skills/ce-compound-refresh/references/scope.md +18 -0
- package/skills/ce-compound-refresh/references/worth-audit.md +35 -0
- package/skills/ce-compound-refresh/references/yaml-schema.md +130 -0
- package/skills/ce-compound-refresh/scripts/validate-doc-claims.py +497 -0
- package/skills/ce-compound-refresh/scripts/validate-frontmatter.py +137 -0
- package/skills/ce-debug/SKILL.md +122 -0
- package/skills/ce-debug/references/anti-patterns.md +91 -0
- package/skills/ce-debug/references/defense-in-depth.md +39 -0
- package/skills/ce-debug/references/fix.md +21 -0
- package/skills/ce-debug/references/investigate.md +114 -0
- package/skills/ce-debug/references/investigation-techniques.md +384 -0
- package/skills/ce-debug/references/pipeline-mode.md +78 -0
- package/skills/ce-debug/references/post-fix-handoff.md +60 -0
- package/skills/ce-debug/references/return-to-caller.md +57 -0
- package/skills/ce-doc-review/SKILL.md +75 -0
- package/skills/ce-doc-review/references/bulk-preview.md +146 -0
- package/skills/ce-doc-review/references/cross-model-review.md +207 -0
- package/skills/ce-doc-review/references/decision-primer.md +47 -0
- package/skills/ce-doc-review/references/dispatch.md +56 -0
- package/skills/ce-doc-review/references/document-intake.md +44 -0
- package/skills/ce-doc-review/references/findings-schema.json +85 -0
- package/skills/ce-doc-review/references/modes.md +20 -0
- package/skills/ce-doc-review/references/open-questions-defer.md +158 -0
- package/skills/ce-doc-review/references/persona-selection.md +41 -0
- package/skills/ce-doc-review/references/personas/adversarial-document-reviewer.md +109 -0
- package/skills/ce-doc-review/references/personas/coherence-reviewer.md +69 -0
- package/skills/ce-doc-review/references/personas/design-lens-reviewer.md +48 -0
- package/skills/ce-doc-review/references/personas/feasibility-reviewer.md +50 -0
- package/skills/ce-doc-review/references/personas/product-lens-reviewer.md +85 -0
- package/skills/ce-doc-review/references/personas/scope-guardian-reviewer.md +83 -0
- package/skills/ce-doc-review/references/personas/security-lens-reviewer.md +41 -0
- package/skills/ce-doc-review/references/personas/whole-doc-reviewer.md +25 -0
- package/skills/ce-doc-review/references/rendering-floor.md +175 -0
- package/skills/ce-doc-review/references/review-output-template.md +123 -0
- package/skills/ce-doc-review/references/subagent-template.md +188 -0
- package/skills/ce-doc-review/references/synthesis-and-presentation.md +350 -0
- package/skills/ce-doc-review/references/walkthrough.md +347 -0
- package/skills/ce-doc-review/scripts/cross-model-doc-review.sh +1270 -0
- package/skills/ce-doc-review/scripts/packs-resolve.py +737 -0
- package/skills/ce-doc-review/scripts/peer-job-runner.py +2594 -0
- package/skills/ce-dogfood/SKILL.md +66 -0
- package/skills/ce-dogfood/agents/openai.yaml +2 -0
- package/skills/ce-dogfood/references/dogfood-report-template.md +97 -0
- package/skills/ce-dogfood/references/phases.md +167 -0
- package/skills/ce-dogfood/references/test-matrix-taxonomy.md +62 -0
- package/skills/ce-dogfood/scripts/packs-resolve.py +737 -0
- package/skills/ce-explain/SKILL.md +81 -0
- package/skills/ce-explain/references/agents/behavior-trace-scout.md +19 -0
- package/skills/ce-explain/references/agents/work-recap-scout.md +23 -0
- package/skills/ce-explain/references/check-in.md +18 -0
- package/skills/ce-explain/references/destinations.md +35 -0
- package/skills/ce-explain/references/explainer-html.md +29 -0
- package/skills/ce-explain/references/explainer-markdown.md +24 -0
- package/skills/ce-explain/references/intake.md +50 -0
- package/skills/ce-explain/references/orchestration.md +46 -0
- package/skills/ce-handoff/SKILL.md +54 -0
- package/skills/ce-handoff/references/create.md +88 -0
- package/skills/ce-handoff/references/resume.md +46 -0
- package/skills/ce-ideate/SKILL.md +75 -0
- package/skills/ce-ideate/references/agents/issue-intelligence-analyst.md +166 -0
- package/skills/ce-ideate/references/agents/learnings-researcher.md +247 -0
- package/skills/ce-ideate/references/agents/slack-researcher.md +127 -0
- package/skills/ce-ideate/references/agents/web-researcher.md +121 -0
- package/skills/ce-ideate/references/decomposition.md +39 -0
- package/skills/ce-ideate/references/divergent-ideation.md +112 -0
- package/skills/ce-ideate/references/grounding.md +138 -0
- package/skills/ce-ideate/references/html-rendering.md +638 -0
- package/skills/ce-ideate/references/ideation-sections.md +191 -0
- package/skills/ce-ideate/references/issue-intelligence.md +44 -0
- package/skills/ce-ideate/references/markdown-rendering.md +242 -0
- package/skills/ce-ideate/references/output-mode.md +34 -0
- package/skills/ce-ideate/references/post-ideation-workflow.md +169 -0
- package/skills/ce-ideate/references/scope-gates.md +148 -0
- package/skills/ce-ideate/references/universal-ideation.md +119 -0
- package/skills/ce-ideate/references/user-research-artifacts.md +28 -0
- package/skills/ce-ideate/references/web-research-cache.md +56 -0
- package/skills/ce-noslop/SKILL.md +45 -0
- package/skills/ce-noslop/references/patterns.md +61 -0
- package/skills/ce-noslop/references/terminology.md +3 -0
- package/skills/ce-optimize/SKILL.md +64 -0
- package/skills/ce-optimize/references/agents/learnings-researcher.md +247 -0
- package/skills/ce-optimize/references/agents/repo-research-analyst.md +258 -0
- package/skills/ce-optimize/references/example-expensive-benchmark-spec.yaml +88 -0
- package/skills/ce-optimize/references/example-hard-spec.yaml +64 -0
- package/skills/ce-optimize/references/example-judge-spec.yaml +83 -0
- package/skills/ce-optimize/references/example-text-target-spec.yaml +80 -0
- package/skills/ce-optimize/references/experiment-log-schema.yaml +563 -0
- package/skills/ce-optimize/references/experiment-prompt-template.md +143 -0
- package/skills/ce-optimize/references/judge-prompt-template.md +117 -0
- package/skills/ce-optimize/references/loop.md +286 -0
- package/skills/ce-optimize/references/measurement.md +168 -0
- package/skills/ce-optimize/references/optimize-spec-schema.yaml +570 -0
- package/skills/ce-optimize/references/persistence.md +93 -0
- package/skills/ce-optimize/references/spec.md +107 -0
- package/skills/ce-optimize/references/text-targets.md +51 -0
- package/skills/ce-optimize/references/usage-guide.md +147 -0
- package/skills/ce-optimize/references/wrap-up.md +54 -0
- package/skills/ce-optimize/scripts/decide.mjs +676 -0
- package/skills/ce-optimize/scripts/experiment-worktree.sh +330 -0
- package/skills/ce-optimize/scripts/measure.sh +140 -0
- package/skills/ce-optimize/scripts/parallel-probe.sh +134 -0
- package/skills/ce-plan/SKILL.md +60 -0
- package/skills/ce-plan/references/agents/agent-native-planning-strategist.md +66 -0
- package/skills/ce-plan/references/agents/architecture-strategist.md +46 -0
- package/skills/ce-plan/references/agents/best-practices-researcher.md +118 -0
- package/skills/ce-plan/references/agents/data-integrity-guardian.md +68 -0
- package/skills/ce-plan/references/agents/framework-docs-researcher.md +97 -0
- package/skills/ce-plan/references/agents/git-history-analyzer.md +40 -0
- package/skills/ce-plan/references/agents/learnings-researcher.md +268 -0
- package/skills/ce-plan/references/agents/pattern-recognition-specialist.md +55 -0
- package/skills/ce-plan/references/agents/performance-oracle.md +108 -0
- package/skills/ce-plan/references/agents/repo-research-analyst.md +262 -0
- package/skills/ce-plan/references/agents/security-sentinel.md +91 -0
- package/skills/ce-plan/references/agents/slack-researcher.md +131 -0
- package/skills/ce-plan/references/agents/spec-flow-analyzer.md +84 -0
- package/skills/ce-plan/references/agents/web-researcher.md +125 -0
- package/skills/ce-plan/references/approach-altitude.md +55 -0
- package/skills/ce-plan/references/bakeoff.md +9 -0
- package/skills/ce-plan/references/deepening-workflow.md +263 -0
- package/skills/ce-plan/references/final-review.md +134 -0
- package/skills/ce-plan/references/html-rendering.md +638 -0
- package/skills/ce-plan/references/intake.md +158 -0
- package/skills/ce-plan/references/markdown-rendering.md +242 -0
- package/skills/ce-plan/references/output-contracts.md +29 -0
- package/skills/ce-plan/references/output-mode.md +45 -0
- package/skills/ce-plan/references/plan-handoff.md +116 -0
- package/skills/ce-plan/references/plan-sections.md +489 -0
- package/skills/ce-plan/references/reasoning-elevation.md +124 -0
- package/skills/ce-plan/references/research.md +211 -0
- package/skills/ce-plan/references/resume.md +61 -0
- package/skills/ce-plan/references/settled-decisions.md +45 -0
- package/skills/ce-plan/references/structure.md +207 -0
- package/skills/ce-plan/references/synthesis-summary.md +260 -0
- package/skills/ce-plan/references/universal-planning.md +170 -0
- package/skills/ce-plan/scripts/elevation-dispatch.sh +288 -0
- package/skills/ce-plan/scripts/packs-resolve.py +737 -0
- package/skills/ce-plan/scripts/peer-job-runner.py +2594 -0
- package/skills/ce-polish/SKILL.md +22 -0
- package/skills/ce-polish/agents/openai.yaml +2 -0
- package/skills/ce-polish/references/dev-server-astro.md +58 -0
- package/skills/ce-polish/references/dev-server-detection.md +40 -0
- package/skills/ce-polish/references/dev-server-next.md +61 -0
- package/skills/ce-polish/references/dev-server-nuxt.md +58 -0
- package/skills/ce-polish/references/dev-server-procfile.md +59 -0
- package/skills/ce-polish/references/dev-server-rails.md +50 -0
- package/skills/ce-polish/references/dev-server-remix.md +58 -0
- package/skills/ce-polish/references/dev-server-sveltekit.md +58 -0
- package/skills/ce-polish/references/dev-server-vite.md +48 -0
- package/skills/ce-polish/references/install-riffrec.md +35 -0
- package/skills/ce-polish/references/launch-json-schema.md +177 -0
- package/skills/ce-polish/references/live-loop.md +98 -0
- package/skills/ce-polish/references/live-remote.md +35 -0
- package/skills/ce-polish/references/live-start.md +93 -0
- package/skills/ce-polish/references/live-stream-contract.md +253 -0
- package/skills/ce-polish/references/run.md +67 -0
- package/skills/ce-polish/scripts/detect-project-type.sh +277 -0
- package/skills/ce-polish/scripts/detect-riffrec.sh +225 -0
- package/skills/ce-polish/scripts/live-endpoint.js +2841 -0
- package/skills/ce-polish/scripts/read-launch-json.sh +117 -0
- package/skills/ce-polish/scripts/resolve-package-manager.sh +95 -0
- package/skills/ce-polish/scripts/resolve-port.sh +307 -0
- package/skills/ce-pov/SKILL.md +64 -0
- package/skills/ce-pov/references/agents/external-evidence-researcher.md +26 -0
- package/skills/ce-pov/references/agents/pov-peer.md +43 -0
- package/skills/ce-pov/references/agents/precedent-activity-scout.md +21 -0
- package/skills/ce-pov/references/agents/project-grounding-scout.md +32 -0
- package/skills/ce-pov/references/boundaries.md +36 -0
- package/skills/ce-pov/references/cross-model-panel.md +596 -0
- package/skills/ce-pov/references/followup.md +9 -0
- package/skills/ce-pov/references/grounding.md +47 -0
- package/skills/ce-pov/references/intake.md +61 -0
- package/skills/ce-pov/references/invocation.md +47 -0
- package/skills/ce-pov/references/method.md +68 -0
- package/skills/ce-pov/references/pov-schema.json +56 -0
- package/skills/ce-pov/references/report.md +7 -0
- package/skills/ce-pov/scripts/cross-model-pov.sh +1110 -0
- package/skills/ce-pov/scripts/peer-job-runner.py +2594 -0
- package/skills/ce-product-pulse/SKILL.md +81 -0
- package/skills/ce-product-pulse/agents/openai.yaml +2 -0
- package/skills/ce-product-pulse/references/config.md +20 -0
- package/skills/ce-product-pulse/references/interview.md +260 -0
- package/skills/ce-product-pulse/references/report-template.md +89 -0
- package/skills/ce-product-pulse/references/run.md +46 -0
- package/skills/ce-product-pulse/references/setup.md +43 -0
- package/skills/ce-promote/SKILL.md +90 -0
- package/skills/ce-promote/agents/openai.yaml +2 -0
- package/skills/ce-promote/references/spiral-cli.md +149 -0
- package/skills/ce-proof/SKILL.md +65 -0
- package/skills/ce-proof/references/api.md +176 -0
- package/skills/ce-proof/references/workflows.md +124 -0
- package/skills/ce-prototype/SKILL.md +59 -0
- package/skills/ce-prototype/assets/annotate.css +206 -0
- package/skills/ce-prototype/assets/annotate.js +837 -0
- package/skills/ce-prototype/references/annotation-loop.md +32 -0
- package/skills/ce-prototype/references/build.md +39 -0
- package/skills/ce-prototype/references/craft-floor.md +43 -0
- package/skills/ce-prototype/references/preview.md +118 -0
- package/skills/ce-prototype/references/scoping.md +38 -0
- package/skills/ce-prototype/references/write-back.md +37 -0
- package/skills/ce-prototype/scripts/light-webserver.js +1275 -0
- package/skills/ce-resolve-pr-feedback/SKILL.md +60 -0
- package/skills/ce-resolve-pr-feedback/references/agents/pr-comment-resolver.md +59 -0
- package/skills/ce-resolve-pr-feedback/references/evaluation-rubric.md +141 -0
- package/skills/ce-resolve-pr-feedback/references/full-mode.md +336 -0
- package/skills/ce-resolve-pr-feedback/references/pipeline-mode.md +23 -0
- package/skills/ce-resolve-pr-feedback/references/resume.md +60 -0
- package/skills/ce-resolve-pr-feedback/references/return-to-caller.md +111 -0
- package/skills/ce-resolve-pr-feedback/references/targeted-mode.md +48 -0
- package/skills/ce-resolve-pr-feedback/scripts/get-pr-comments +176 -0
- package/skills/ce-resolve-pr-feedback/scripts/get-thread-for-comment +84 -0
- package/skills/ce-resolve-pr-feedback/scripts/pending-feedback.py +287 -0
- package/skills/ce-resolve-pr-feedback/scripts/reply-to-pr-thread +57 -0
- package/skills/ce-resolve-pr-feedback/scripts/resolve-pr-thread +23 -0
- package/skills/ce-retune/SKILL.md +42 -0
- package/skills/ce-retune/agents/openai.yaml +2 -0
- package/skills/ce-retune/references/baseline-mining.md +122 -0
- package/skills/ce-retune/references/corpus-audit.md +128 -0
- package/skills/ce-retune/references/cut-passes.md +129 -0
- package/skills/ce-retune/references/halt-taxonomy.md +123 -0
- package/skills/ce-retune/references/noise-floor.md +131 -0
- package/skills/ce-retune/references/workflow-shapes.md +73 -0
- package/skills/ce-riffrec-feedback-analysis/SKILL.md +33 -0
- package/skills/ce-riffrec-feedback-analysis/references/analyzer.md +18 -0
- package/skills/ce-riffrec-feedback-analysis/references/compound-engineering-feedback-format.md +116 -0
- package/skills/ce-riffrec-feedback-analysis/references/extensive-analysis.md +98 -0
- package/skills/ce-riffrec-feedback-analysis/references/install-riffrec.md +27 -0
- package/skills/ce-riffrec-feedback-analysis/references/quick-bug-report.md +38 -0
- package/skills/ce-riffrec-feedback-analysis/scripts/analyze_riffrec_zip.py +1306 -0
- package/skills/ce-setup/SKILL.md +103 -0
- package/skills/ce-setup/agents/openai.yaml +2 -0
- package/skills/ce-setup/assets/compounding-directive.md +11 -0
- package/skills/ce-setup/assets/noslop-directive.md +7 -0
- package/skills/ce-setup/assets/pack-rule-template.md +11 -0
- package/skills/ce-setup/references/acpx-cache-warm.md +14 -0
- package/skills/ce-setup/references/config-template.yaml +210 -0
- package/skills/ce-setup/references/legacy-codex-tool-map.md +15 -0
- package/skills/ce-setup/references/pack-scaffold.md +45 -0
- package/skills/ce-setup/references/repo-fixes.md +121 -0
- package/skills/ce-setup/scripts/check-health +929 -0
- package/skills/ce-setup/scripts/packs-resolve.py +737 -0
- package/skills/ce-simplify-code/SKILL.md +76 -0
- package/skills/ce-simplify-code/references/personas/code-quality-reviewer.md +17 -0
- package/skills/ce-simplify-code/references/personas/code-reuse-reviewer.md +7 -0
- package/skills/ce-simplify-code/references/personas/comment-reviewer.md +24 -0
- package/skills/ce-simplify-code/references/personas/efficiency-reviewer.md +11 -0
- package/skills/ce-simplify-code/references/personas/test-value-reviewer.md +23 -0
- package/skills/ce-simplify-code/references/reviewer-dispatch.md +11 -0
- package/skills/ce-simplify-code/references/standalone-report.md +25 -0
- package/skills/ce-strategy/SKILL.md +61 -0
- package/skills/ce-strategy/references/grounding.md +22 -0
- package/skills/ce-strategy/references/interview.md +179 -0
- package/skills/ce-strategy/references/strategy-template.md +94 -0
- package/skills/ce-strategy/references/update-run.md +33 -0
- package/skills/ce-sweep/SKILL.md +93 -0
- package/skills/ce-sweep/agents/openai.yaml +2 -0
- package/skills/ce-sweep/references/agents/media-analyzer.md +54 -0
- package/skills/ce-sweep/references/interview.md +208 -0
- package/skills/ce-sweep/references/model-tiers.md +13 -0
- package/skills/ce-sweep/references/plan-template.md +62 -0
- package/skills/ce-sweep/references/run.md +126 -0
- package/skills/ce-sweep/references/sources/email.md +57 -0
- package/skills/ce-sweep/references/sources/github-issues.md +59 -0
- package/skills/ce-sweep/references/sources/slack.md +61 -0
- package/skills/ce-sweep/references/state-schema.md +157 -0
- package/skills/ce-sweep/references/subagent-template.md +60 -0
- package/skills/ce-sweep/scripts/analyze_riffrec_zip.py +1306 -0
- package/skills/ce-sweep/scripts/sweep-state.py +793 -0
- package/skills/ce-test-browser/SKILL.md +50 -0
- package/skills/ce-test-browser/references/agent-browser-driver.md +47 -0
- package/skills/ce-test-browser/references/pipeline-orchestration.md +45 -0
- package/skills/ce-test-browser/references/route-and-report.md +129 -0
- package/skills/ce-test-browser/scripts/resolve-port.sh +41 -0
- package/skills/ce-test-xcode/SKILL.md +26 -0
- package/skills/ce-test-xcode/agents/openai.yaml +2 -0
- package/skills/ce-test-xcode/references/setup-and-build.md +32 -0
- package/skills/ce-test-xcode/references/test-and-report.md +64 -0
- package/skills/ce-work/SKILL.md +62 -0
- package/skills/ce-work/references/agents/figma-design-sync.md +27 -0
- package/skills/ce-work/references/agents/implementation-worker.md +17 -0
- package/skills/ce-work/references/cross-model-execution.md +191 -0
- package/skills/ce-work/references/execution-engines.md +64 -0
- package/skills/ce-work/references/execution-strategy.md +73 -0
- package/skills/ce-work/references/implementation-loop.md +107 -0
- package/skills/ce-work/references/implementation-result-schema.json +52 -0
- package/skills/ce-work/references/input-triage.md +50 -0
- package/skills/ce-work/references/non-code-execution.md +23 -0
- package/skills/ce-work/references/return-to-caller.md +33 -0
- package/skills/ce-work/references/review-findings-followup.md +82 -0
- package/skills/ce-work/references/shipping-workflow.md +89 -0
- package/skills/ce-work/references/tracker-defer.md +150 -0
- package/skills/ce-work/references/work-intake.md +51 -0
- package/skills/ce-work/references/workspace-setup.md +27 -0
- package/skills/ce-work/scripts/__pycache__/unit_workspace_jobs.cpython-314.pyc +0 -0
- package/skills/ce-work/scripts/__pycache__/unit_workspace_state.cpython-314.pyc +0 -0
- package/skills/ce-work/scripts/cross-model-work.sh +1385 -0
- package/skills/ce-work/scripts/peer-job-runner.py +2594 -0
- package/skills/ce-work/scripts/unit-workspace.py +215 -0
- package/skills/ce-work/scripts/unit_workspace_ignored.py +93 -0
- package/skills/ce-work/scripts/unit_workspace_integration.py +677 -0
- package/skills/ce-work/scripts/unit_workspace_jobs.py +1216 -0
- package/skills/ce-work/scripts/unit_workspace_lifecycle.py +981 -0
- package/skills/ce-work/scripts/unit_workspace_state.py +1379 -0
- package/skills/ce-work/scripts/unit_workspace_transaction.py +612 -0
- package/skills/ce-worktree/SKILL.md +54 -0
- package/skills/lfg/SKILL.md +59 -0
- package/skills/lfg/references/debug-return.md +25 -0
- package/skills/lfg/references/intake.md +30 -0
- package/skills/lfg/references/next-work-handoff.md +96 -0
- package/skills/lfg/references/plan-brief.md +36 -0
- package/skills/lfg/references/review-followup.md +78 -0
- package/skills/lfg/references/shipping.md +65 -0
- package/skills/lfg/references/stage-routing.md +49 -0
- package/skills/lfg/references/task-visibility.md +11 -0
- package/skills/lfg/references/tracker-defer.md +150 -0
- package/skills/lfg/references/work-return.md +27 -0
- package/skills/wtf/SKILL.md +33 -0
- package/skills/wtf/agents/openai.yaml +2 -0
|
@@ -0,0 +1,837 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const token = new URLSearchParams(window.location.search).get("token")
|
|
3
|
+
// The helper stamps the path it served on this script. History API rewrites
|
|
4
|
+
// change location.pathname without changing which screen file this is.
|
|
5
|
+
const servedPage = document.currentScript?.getAttribute("data-ce-page") || "/"
|
|
6
|
+
const servedDocument = document.currentScript?.getAttribute("data-ce-document") || ""
|
|
7
|
+
// Overlay host hangs off <html>, not <body>, so it stays out of body layout
|
|
8
|
+
// and document.body.children. A manual popover puts it on the top layer so
|
|
9
|
+
// Annotate and the end control stay usable over dialog.showModal().
|
|
10
|
+
const host = document.createElement("ce-annotate-host")
|
|
11
|
+
host.style.cssText =
|
|
12
|
+
"display: block; position: fixed; inset: 0; width: auto; height: auto; overflow: visible; color: inherit; background: transparent; pointer-events: none; z-index: 2147483645; margin: 0; padding: 0; border: 0;"
|
|
13
|
+
document.documentElement.appendChild(host)
|
|
14
|
+
host.setAttribute("popover", "manual")
|
|
15
|
+
const raiseOverlay = () => {
|
|
16
|
+
if (typeof host.showPopover !== "function") return
|
|
17
|
+
try { host.hidePopover() } catch {}
|
|
18
|
+
try { host.showPopover() } catch {}
|
|
19
|
+
}
|
|
20
|
+
raiseOverlay()
|
|
21
|
+
if (typeof MutationObserver === "function") {
|
|
22
|
+
new MutationObserver((records) => {
|
|
23
|
+
for (const record of records) {
|
|
24
|
+
const nodes = record.type === "attributes" ? [record.target] : record.addedNodes
|
|
25
|
+
for (const node of nodes) {
|
|
26
|
+
if (node !== host && node.nodeName === "DIALOG" && node.hasAttribute?.("open")) {
|
|
27
|
+
raiseOverlay()
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}).observe(document.documentElement, { subtree: true, childList: true, attributes: true, attributeFilter: ["open"] })
|
|
33
|
+
}
|
|
34
|
+
const shadow = host.attachShadow({ mode: "open" })
|
|
35
|
+
const css = document.createElement("link")
|
|
36
|
+
css.rel = "stylesheet"
|
|
37
|
+
// Resolved against this script's own URL, not the document base a screen may set.
|
|
38
|
+
css.href = new URL("/__ce-annotate/annotate.css", document.currentScript?.src || window.location.origin).href
|
|
39
|
+
shadow.appendChild(css)
|
|
40
|
+
|
|
41
|
+
const chrome = document.createElement("div")
|
|
42
|
+
chrome.className = "ce-annotate-chrome"
|
|
43
|
+
chrome.innerHTML = `
|
|
44
|
+
<button type="button" class="ce-annotate-toggle" aria-pressed="false" aria-keyshortcuts="Control+A Escape" title="Click pins the rest state. Ctrl+A while hovering freezes hover, then click to pin. Esc or Ctrl+A again turns it off."><span class="ce-annotate-toggle-label">Annotate</span><kbd class="ce-annotate-hotkey">Ctrl+A</kbd></button>
|
|
45
|
+
<button type="button" class="ce-annotate-stop" title="Close the preview and return to chat">End session</button>
|
|
46
|
+
<span class="ce-annotate-status" hidden></span>
|
|
47
|
+
`
|
|
48
|
+
shadow.appendChild(chrome)
|
|
49
|
+
|
|
50
|
+
const catcher = document.createElement("div")
|
|
51
|
+
catcher.className = "ce-annotate-catcher"
|
|
52
|
+
catcher.hidden = true
|
|
53
|
+
shadow.appendChild(catcher)
|
|
54
|
+
|
|
55
|
+
const layer = document.createElement("div")
|
|
56
|
+
layer.className = "ce-annotate-layer"
|
|
57
|
+
shadow.appendChild(layer)
|
|
58
|
+
|
|
59
|
+
const pinTip = document.createElement("div")
|
|
60
|
+
pinTip.className = "ce-annotate-pin-tip"
|
|
61
|
+
pinTip.hidden = true
|
|
62
|
+
shadow.appendChild(pinTip)
|
|
63
|
+
|
|
64
|
+
const composer = document.createElement("form")
|
|
65
|
+
composer.className = "ce-annotate-composer"
|
|
66
|
+
composer.hidden = true
|
|
67
|
+
composer.innerHTML = `
|
|
68
|
+
<textarea class="ce-annotate-comment" rows="3" placeholder="What should change here?"></textarea>
|
|
69
|
+
<div class="ce-annotate-actions">
|
|
70
|
+
<button type="submit" class="ce-annotate-submit" disabled>Submit</button>
|
|
71
|
+
<button type="button" class="ce-annotate-cancel">Cancel</button>
|
|
72
|
+
</div>
|
|
73
|
+
<p class="ce-annotate-error" hidden></p>
|
|
74
|
+
`
|
|
75
|
+
shadow.appendChild(composer)
|
|
76
|
+
|
|
77
|
+
const toggle = chrome.querySelector(".ce-annotate-toggle")
|
|
78
|
+
const toggleLabel = chrome.querySelector(".ce-annotate-toggle-label")
|
|
79
|
+
const stop = chrome.querySelector(".ce-annotate-stop")
|
|
80
|
+
const status = chrome.querySelector(".ce-annotate-status")
|
|
81
|
+
const commentField = composer.querySelector(".ce-annotate-comment")
|
|
82
|
+
const submit = composer.querySelector(".ce-annotate-submit")
|
|
83
|
+
const cancel = composer.querySelector(".ce-annotate-cancel")
|
|
84
|
+
const error = composer.querySelector(".ce-annotate-error")
|
|
85
|
+
|
|
86
|
+
const overlaySession = document.currentScript?.getAttribute("data-ce-session") || ""
|
|
87
|
+
const STATE_KEY = overlaySession ? `ce-annotate-state:${overlaySession}` : "ce-annotate-state"
|
|
88
|
+
const PIN_STATUS = { held: "pending", queued: "pending", working: "working" }
|
|
89
|
+
let commentToolOn = false
|
|
90
|
+
let sessionEnded = false
|
|
91
|
+
let lastPointer = { x: 0, y: 0 }
|
|
92
|
+
let sawPointer = false
|
|
93
|
+
const frozenStyles = []
|
|
94
|
+
let inFlight = false
|
|
95
|
+
let reloadPending = false
|
|
96
|
+
let leavingPage = false
|
|
97
|
+
let draft = null
|
|
98
|
+
let source = null
|
|
99
|
+
// The helper's view of each annotation's lifecycle, keyed by id. Pin status
|
|
100
|
+
// follows it; a reload or a screen change never changes a pin on its own.
|
|
101
|
+
let annotationStates = {}
|
|
102
|
+
const pins = []
|
|
103
|
+
// Pins whose target or variant is not on view right now. Derived on each
|
|
104
|
+
// reattach, so it stays out of the persisted pin state.
|
|
105
|
+
const offViewPins = new Set()
|
|
106
|
+
|
|
107
|
+
function prototypeRoot() {
|
|
108
|
+
return document.getElementById("ce-prototype-root") || document.body
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// A revised screen is shown by navigating to the stamped served path, so a
|
|
112
|
+
// History API rewrite is not what the helper looks up. Query and fragment
|
|
113
|
+
// on that path stay. The browser owns every reconciliation; pins, tool
|
|
114
|
+
// state, and open draft are carried across explorer navigation as well as
|
|
115
|
+
// helper-driven reloads.
|
|
116
|
+
function persistState() {
|
|
117
|
+
const state = {
|
|
118
|
+
commentToolOn,
|
|
119
|
+
sessionEnded,
|
|
120
|
+
pins,
|
|
121
|
+
annotationStates,
|
|
122
|
+
draft: draft
|
|
123
|
+
? { ...draft, page: servedPage, text: commentField.value, left: composer.style.left, top: composer.style.top }
|
|
124
|
+
: null,
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
sessionStorage.setItem(STATE_KEY, JSON.stringify(state))
|
|
128
|
+
} catch {
|
|
129
|
+
// Without storage a navigation still shows the next screen; only the pins are lost.
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function persistAndReload() {
|
|
134
|
+
persistState()
|
|
135
|
+
window.location.replace(`${servedPage}${window.location.search}${window.location.hash}`)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// A screen change arriving while a comment is being sent waits for that
|
|
139
|
+
// request to settle, so the pin gets its id (or its retry) before the reload.
|
|
140
|
+
function requestReload() {
|
|
141
|
+
if (inFlight) {
|
|
142
|
+
reloadPending = true
|
|
143
|
+
return
|
|
144
|
+
}
|
|
145
|
+
if (source) source.close()
|
|
146
|
+
persistAndReload()
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function restorePersistedState() {
|
|
150
|
+
let saved = null
|
|
151
|
+
try {
|
|
152
|
+
saved = JSON.parse(sessionStorage.getItem(STATE_KEY) || "null")
|
|
153
|
+
} catch {
|
|
154
|
+
return false
|
|
155
|
+
}
|
|
156
|
+
if (!saved || typeof saved !== "object") return false
|
|
157
|
+
if (saved.annotationStates && typeof saved.annotationStates === "object" && !Array.isArray(saved.annotationStates)) {
|
|
158
|
+
annotationStates = { ...saved.annotationStates, ...annotationStates }
|
|
159
|
+
}
|
|
160
|
+
if (Array.isArray(saved.pins)) {
|
|
161
|
+
for (const pin of saved.pins) {
|
|
162
|
+
if (!pin || typeof pin.selector !== "string" || typeof pin.comment !== "string") continue
|
|
163
|
+
if (pin.id && pins.some((existing) => existing.id === pin.id)) continue
|
|
164
|
+
pins.push(pin)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
dropAppliedPins()
|
|
168
|
+
if (saved.sessionEnded) {
|
|
169
|
+
markEnded()
|
|
170
|
+
return true
|
|
171
|
+
}
|
|
172
|
+
if (saved.commentToolOn && !agentHasBatch()) setCommentTool(true)
|
|
173
|
+
if (
|
|
174
|
+
saved.draft &&
|
|
175
|
+
typeof saved.draft.selector === "string" &&
|
|
176
|
+
(!saved.draft.page || saved.draft.page === servedPage) &&
|
|
177
|
+
!agentHasBatch()
|
|
178
|
+
) {
|
|
179
|
+
restoreDraft(saved.draft)
|
|
180
|
+
}
|
|
181
|
+
syncStopButton()
|
|
182
|
+
return true
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function restoreDraft(saved) {
|
|
186
|
+
let node = null
|
|
187
|
+
try {
|
|
188
|
+
node = document.querySelector(saved.selector)
|
|
189
|
+
} catch {
|
|
190
|
+
node = null
|
|
191
|
+
}
|
|
192
|
+
draft = { selector: saved.selector, textSnippet: saved.textSnippet, variant: saved.variant, rect: saved.rect, point: saved.point, x: saved.x, y: saved.y }
|
|
193
|
+
composer.hidden = false
|
|
194
|
+
if (node && !pinOffView(node, draft)) {
|
|
195
|
+
const rect = node.getBoundingClientRect()
|
|
196
|
+
Object.assign(draft, positionFromNode(node, draft))
|
|
197
|
+
placeComposer(rect.left, rect.top + rect.height)
|
|
198
|
+
} else {
|
|
199
|
+
composer.style.left = saved.left || ""
|
|
200
|
+
composer.style.top = saved.top || ""
|
|
201
|
+
}
|
|
202
|
+
commentField.value = typeof saved.text === "string" ? saved.text : ""
|
|
203
|
+
error.hidden = true
|
|
204
|
+
commentField.focus()
|
|
205
|
+
syncSubmit()
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function applyAnnotationStates(states) {
|
|
209
|
+
if (!states || typeof states !== "object") return
|
|
210
|
+
annotationStates = states
|
|
211
|
+
dropAppliedPins()
|
|
212
|
+
for (const pin of pins) {
|
|
213
|
+
const status = PIN_STATUS[states[pin.id]]
|
|
214
|
+
if (status) pin.status = status
|
|
215
|
+
}
|
|
216
|
+
reattachPins()
|
|
217
|
+
syncStopButton()
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// An applied note is answered by the revised screen. Its pin would only
|
|
221
|
+
// point at whatever the old selector matches now.
|
|
222
|
+
function dropAppliedPins() {
|
|
223
|
+
for (let i = pins.length - 1; i >= 0; i--) {
|
|
224
|
+
if (annotationStates[pins[i].id] === "done") pins.splice(i, 1)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function unflushedCount() {
|
|
229
|
+
const ids = new Set()
|
|
230
|
+
for (const [id, state] of Object.entries(annotationStates)) {
|
|
231
|
+
if (state === "held") ids.add(id)
|
|
232
|
+
}
|
|
233
|
+
for (const pin of pins) {
|
|
234
|
+
const state = pin.id ? annotationStates[pin.id] : "held"
|
|
235
|
+
if (!state || state === "held") ids.add(pin.id || `local:${pins.indexOf(pin)}`)
|
|
236
|
+
}
|
|
237
|
+
return ids.size
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function pinOnThisPage(pin) {
|
|
241
|
+
return !pin.page || pin.page === servedPage
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Variants that share one screen behind a tab control are told apart by the
|
|
245
|
+
// data-ce-variant marker the build convention asks for. Without the marker,
|
|
246
|
+
// only a variant hidden in place (not re-rendered) hides its pins. The whole
|
|
247
|
+
// chain of enclosing markers, outermost first, counts, so nested controls
|
|
248
|
+
// that reuse inner names still tell their outer options apart.
|
|
249
|
+
function variantOf(node) {
|
|
250
|
+
const names = []
|
|
251
|
+
for (let el = node.closest?.("[data-ce-variant]"); el; el = el.parentElement?.closest("[data-ce-variant]")) {
|
|
252
|
+
names.unshift(el.getAttribute("data-ce-variant"))
|
|
253
|
+
}
|
|
254
|
+
return names.length ? names : null
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function sameVariant(a, b) {
|
|
258
|
+
return JSON.stringify(a || null) === JSON.stringify(b || null)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function rendered(node) {
|
|
262
|
+
if (typeof node.checkVisibility === "function") {
|
|
263
|
+
return node.checkVisibility({ opacityProperty: true, visibilityProperty: true })
|
|
264
|
+
}
|
|
265
|
+
return node.getClientRects().length > 0
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// A variant re-rendered out of the DOM leaves no node to check, so its own
|
|
269
|
+
// container being absent or hidden is what takes the pin off the view.
|
|
270
|
+
function pinOffView(node, pin) {
|
|
271
|
+
if (node) return !sameVariant(pin.variant, variantOf(node)) || !rendered(node)
|
|
272
|
+
if (!Array.isArray(pin.variant)) return false
|
|
273
|
+
const innermost = pin.variant[pin.variant.length - 1]
|
|
274
|
+
return ![...document.querySelectorAll(`[data-ce-variant="${CSS.escape(innermost)}"]`)].some(
|
|
275
|
+
(el) => sameVariant(pin.variant, variantOf(el)) && rendered(el),
|
|
276
|
+
)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function agentHasBatch() {
|
|
280
|
+
return Object.values(annotationStates).some((state) => state === "queued" || state === "working")
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function syncStopButton() {
|
|
284
|
+
if (sessionEnded) return
|
|
285
|
+
if (agentHasBatch()) {
|
|
286
|
+
if (commentToolOn) setCommentTool(false)
|
|
287
|
+
toggle.hidden = true
|
|
288
|
+
stop.hidden = true
|
|
289
|
+
setStatus("Sent to agent")
|
|
290
|
+
status.title = "Return to chat. You can annotate again after this batch is applied."
|
|
291
|
+
return
|
|
292
|
+
}
|
|
293
|
+
toggle.hidden = false
|
|
294
|
+
stop.hidden = false
|
|
295
|
+
status.removeAttribute("title")
|
|
296
|
+
if (status.textContent === "Sent to agent") setStatus("")
|
|
297
|
+
const n = unflushedCount()
|
|
298
|
+
if (n === 0) {
|
|
299
|
+
stop.textContent = "End session"
|
|
300
|
+
stop.removeAttribute("aria-label")
|
|
301
|
+
stop.title = "Close the preview and return to chat"
|
|
302
|
+
return
|
|
303
|
+
}
|
|
304
|
+
const badge = document.createElement("span")
|
|
305
|
+
badge.className = "ce-annotate-count"
|
|
306
|
+
badge.textContent = String(n)
|
|
307
|
+
stop.replaceChildren(badge, document.createTextNode("Send to agent"))
|
|
308
|
+
const notes = n === 1 ? "1 note" : `${n} notes`
|
|
309
|
+
stop.setAttribute("aria-label", `Send ${notes} to the agent`)
|
|
310
|
+
stop.title = `Send ${notes} to the agent. The session stays open for another batch.`
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function cssPath(el) {
|
|
314
|
+
if (!(el instanceof Element)) return ""
|
|
315
|
+
if (el.id) return `#${CSS.escape(el.id)}`
|
|
316
|
+
if (el === document.body) return "body"
|
|
317
|
+
const parts = []
|
|
318
|
+
let node = el
|
|
319
|
+
while (node && node.nodeType === 1 && node !== document.documentElement) {
|
|
320
|
+
if (node.id === "ce-prototype-root" || node === document.body) break
|
|
321
|
+
if (node.id) {
|
|
322
|
+
parts.unshift(`#${CSS.escape(node.id)}`)
|
|
323
|
+
break
|
|
324
|
+
}
|
|
325
|
+
const parent = node.parentElement
|
|
326
|
+
if (!parent) break
|
|
327
|
+
const tag = node.tagName.toLowerCase()
|
|
328
|
+
const same = [...parent.children].filter((child) => child.tagName === node.tagName)
|
|
329
|
+
const index = same.indexOf(node) + 1
|
|
330
|
+
parts.unshift(same.length > 1 ? `${tag}:nth-of-type(${index})` : tag)
|
|
331
|
+
node = parent
|
|
332
|
+
}
|
|
333
|
+
return parts.join(" > ")
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function tokenUrl(path, extra) {
|
|
337
|
+
const url = new URL(path, window.location.origin)
|
|
338
|
+
if (token) url.searchParams.set("token", token)
|
|
339
|
+
if (extra) {
|
|
340
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
341
|
+
if (value) url.searchParams.set(key, value)
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return url.toString()
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function setStatus(text) {
|
|
348
|
+
status.hidden = !text
|
|
349
|
+
status.textContent = text || ""
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
function syncSubmit() {
|
|
353
|
+
submit.disabled = sessionEnded || inFlight || commentField.value.trim() === ""
|
|
354
|
+
cancel.disabled = inFlight
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function closeComposer(keep) {
|
|
358
|
+
composer.hidden = true
|
|
359
|
+
if (keep) return
|
|
360
|
+
draft = null
|
|
361
|
+
error.hidden = true
|
|
362
|
+
error.textContent = ""
|
|
363
|
+
commentField.value = ""
|
|
364
|
+
syncSubmit()
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Pins stay click-through so a note on a control never blocks that control;
|
|
368
|
+
// the comment shows by pointer position instead of a hover target.
|
|
369
|
+
const PIN_SIZE = 22
|
|
370
|
+
function showPinTipAt(x, y) {
|
|
371
|
+
const pin = pins.findLast(
|
|
372
|
+
(p) => pinOnThisPage(p) && !offViewPins.has(p) && x >= p.x && x <= p.x + PIN_SIZE && y >= p.y && y <= p.y + PIN_SIZE,
|
|
373
|
+
)
|
|
374
|
+
pinTip.hidden = !pin
|
|
375
|
+
if (!pin) return
|
|
376
|
+
pinTip.textContent = pin.comment
|
|
377
|
+
pinTip.style.left = `${Math.max(0, Math.min(pin.x + PIN_SIZE + 4, window.innerWidth - 260))}px`
|
|
378
|
+
pinTip.style.top = `${pin.y}px`
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function renderPins() {
|
|
382
|
+
pinTip.hidden = true
|
|
383
|
+
layer.replaceChildren()
|
|
384
|
+
for (const pin of pins) {
|
|
385
|
+
if (!pinOnThisPage(pin) || offViewPins.has(pin)) continue
|
|
386
|
+
const marker = document.createElement("button")
|
|
387
|
+
marker.type = "button"
|
|
388
|
+
marker.className = `ce-annotate-pin is-${pin.status}`
|
|
389
|
+
marker.textContent = pin.status === "target-gone" ? "!" : pins.indexOf(pin) + 1
|
|
390
|
+
marker.title = pin.comment
|
|
391
|
+
marker.style.left = `${pin.x}px`
|
|
392
|
+
marker.style.top = `${pin.y}px`
|
|
393
|
+
layer.appendChild(marker)
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// A pin stays where it was dropped inside its target, so a note on a large
|
|
398
|
+
// element does not jump to that element's corner.
|
|
399
|
+
function positionFromNode(node, pin) {
|
|
400
|
+
const rect = node.getBoundingClientRect()
|
|
401
|
+
const was = pin && pin.rect
|
|
402
|
+
if (was && pin.point && was.width > 0 && was.height > 0) {
|
|
403
|
+
const fx = Math.max(0, Math.min(1, (pin.point.x - was.x) / was.width))
|
|
404
|
+
const fy = Math.max(0, Math.min(1, (pin.point.y - was.y) / was.height))
|
|
405
|
+
return { x: rect.left + fx * rect.width, y: rect.top + fy * rect.height }
|
|
406
|
+
}
|
|
407
|
+
return { x: rect.left + Math.min(12, rect.width / 2), y: rect.top + 4 }
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function reattachPins() {
|
|
411
|
+
const root = prototypeRoot()
|
|
412
|
+
offViewPins.clear()
|
|
413
|
+
for (const pin of pins) {
|
|
414
|
+
if (!pinOnThisPage(pin)) continue
|
|
415
|
+
let node = null
|
|
416
|
+
try {
|
|
417
|
+
node = root.querySelector(pin.selector) || document.querySelector(pin.selector)
|
|
418
|
+
} catch {
|
|
419
|
+
node = null
|
|
420
|
+
}
|
|
421
|
+
const queued = pin.status === "pending" || pin.status === "working"
|
|
422
|
+
if (pinOffView(node, pin)) {
|
|
423
|
+
offViewPins.add(pin)
|
|
424
|
+
continue
|
|
425
|
+
}
|
|
426
|
+
if (node) {
|
|
427
|
+
if (!queued) pin.status = "attached"
|
|
428
|
+
Object.assign(pin, positionFromNode(node, pin))
|
|
429
|
+
} else if (!queued) {
|
|
430
|
+
pin.status = "target-gone"
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
renderPins()
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function markEnded() {
|
|
437
|
+
sessionEnded = true
|
|
438
|
+
setCommentTool(false)
|
|
439
|
+
toggle.hidden = true
|
|
440
|
+
stop.hidden = true
|
|
441
|
+
setStatus("Session ended")
|
|
442
|
+
closeComposer()
|
|
443
|
+
pins.length = 0
|
|
444
|
+
renderPins()
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function openComposer(target, event) {
|
|
448
|
+
const selector = cssPath(target)
|
|
449
|
+
if (!selector) return
|
|
450
|
+
const box = target.getBoundingClientRect()
|
|
451
|
+
draft = {
|
|
452
|
+
x: event.clientX,
|
|
453
|
+
y: event.clientY,
|
|
454
|
+
selector,
|
|
455
|
+
textSnippet: (target.textContent || "").trim().slice(0, 240),
|
|
456
|
+
variant: variantOf(target),
|
|
457
|
+
rect: { x: box.left, y: box.top, width: box.width, height: box.height },
|
|
458
|
+
// On a canvas or empty space the target says little; the point is what
|
|
459
|
+
// the explorer indicated.
|
|
460
|
+
point: {
|
|
461
|
+
x: event.clientX,
|
|
462
|
+
y: event.clientY,
|
|
463
|
+
viewportWidth: window.innerWidth,
|
|
464
|
+
viewportHeight: window.innerHeight,
|
|
465
|
+
},
|
|
466
|
+
}
|
|
467
|
+
composer.hidden = false
|
|
468
|
+
placeComposer(event.clientX, event.clientY)
|
|
469
|
+
error.hidden = true
|
|
470
|
+
commentField.focus()
|
|
471
|
+
syncSubmit()
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function placeComposer(x, y) {
|
|
475
|
+
const width = composer.offsetWidth || Math.min(260, window.innerWidth)
|
|
476
|
+
const height = composer.offsetHeight || Math.min(160, window.innerHeight)
|
|
477
|
+
composer.style.left = `${Math.max(0, Math.min(x + 12, window.innerWidth - width))}px`
|
|
478
|
+
composer.style.top = `${Math.max(0, Math.min(y + 12, window.innerHeight - height))}px`
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function setCommentTool(on) {
|
|
482
|
+
commentToolOn = on
|
|
483
|
+
toggle.setAttribute("aria-pressed", String(on))
|
|
484
|
+
toggle.classList.toggle("is-on", on)
|
|
485
|
+
toggleLabel.textContent = on ? "Annotating" : "Annotate"
|
|
486
|
+
catcher.hidden = !on
|
|
487
|
+
if (!on) {
|
|
488
|
+
unfreezeHover()
|
|
489
|
+
closeComposer(inFlight)
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
function pageElementFromPoint(x, y) {
|
|
494
|
+
let node = null
|
|
495
|
+
for (const el of document.elementsFromPoint(x, y)) {
|
|
496
|
+
if (!(el instanceof Element)) continue
|
|
497
|
+
if (el === host || host.contains(el)) continue
|
|
498
|
+
if (el === document.documentElement) continue
|
|
499
|
+
node = el
|
|
500
|
+
break
|
|
501
|
+
}
|
|
502
|
+
return node || prototypeRoot()
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Hit testing skips pointer-events:none, which is how labels and headlines
|
|
506
|
+
// laid over a canvas are usually styled. What was indicated is the topmost
|
|
507
|
+
// painted element at the point with those counted, so every visible one
|
|
508
|
+
// smaller than the hit element joins a single hit test. One at a time would
|
|
509
|
+
// let a label win while another unhittable layer is painted over it.
|
|
510
|
+
function unhittableElementAt(x, y, hit) {
|
|
511
|
+
const hitBox = hit.getBoundingClientRect()
|
|
512
|
+
const hitArea = hitBox.width * hitBox.height
|
|
513
|
+
const candidates = []
|
|
514
|
+
for (const el of document.body.querySelectorAll("*")) {
|
|
515
|
+
if (el === host || host.contains(el)) continue
|
|
516
|
+
const box = el.getBoundingClientRect()
|
|
517
|
+
const area = box.width * box.height
|
|
518
|
+
if (!area || area >= hitArea) continue
|
|
519
|
+
if (x < box.left || x > box.right || y < box.top || y > box.bottom) continue
|
|
520
|
+
if (getComputedStyle(el).pointerEvents !== "none") continue
|
|
521
|
+
const visible = el.checkVisibility
|
|
522
|
+
? el.checkVisibility({ opacityProperty: true, visibilityProperty: true })
|
|
523
|
+
: getComputedStyle(el).visibility === "visible"
|
|
524
|
+
if (visible && paintsAt(el, x, y)) candidates.push(el)
|
|
525
|
+
}
|
|
526
|
+
if (candidates.length === 0) return null
|
|
527
|
+
const saved = candidates.map((el) => [
|
|
528
|
+
el,
|
|
529
|
+
el.style.getPropertyValue("pointer-events"),
|
|
530
|
+
el.style.getPropertyPriority("pointer-events"),
|
|
531
|
+
])
|
|
532
|
+
for (const el of candidates) el.style.setProperty("pointer-events", "auto", "important")
|
|
533
|
+
try {
|
|
534
|
+
// The top element can be a part of a candidate, such as a shape inside
|
|
535
|
+
// an svg, which became hittable by inheritance.
|
|
536
|
+
let top = pageElementFromPoint(x, y)
|
|
537
|
+
while (top && !candidates.includes(top)) top = top.parentElement
|
|
538
|
+
return top || null
|
|
539
|
+
} finally {
|
|
540
|
+
for (const [el, value, priority] of saved) {
|
|
541
|
+
if (value) el.style.setProperty("pointer-events", value, priority)
|
|
542
|
+
else el.style.removeProperty("pointer-events")
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// A box that contains the point can paint nothing there: a positioned
|
|
548
|
+
// wrapper around labels has a box and no pixels of its own. Only what the
|
|
549
|
+
// element itself draws counts, so a wrapper's children are judged as themselves.
|
|
550
|
+
const REPLACED = new Set(["IMG", "SVG", "VIDEO", "CANVAS", "PICTURE", "IFRAME", "OBJECT", "EMBED", "INPUT", "SELECT", "TEXTAREA", "BUTTON"])
|
|
551
|
+
function paintsAt(el, x, y) {
|
|
552
|
+
if (REPLACED.has(el.tagName.toUpperCase())) return true
|
|
553
|
+
const style = getComputedStyle(el)
|
|
554
|
+
// Alpha is the fourth component; `rgb(255, 204, 0)` also ends in ", 0)".
|
|
555
|
+
const transparent = (color) => color === "transparent" || /^rgba\((?:[^,]+,){3}\s*0(?:\.0+)?\)$/.test(color)
|
|
556
|
+
if (!transparent(style.backgroundColor) || style.backgroundImage !== "none") return true
|
|
557
|
+
// A border paints only its own band, not the interior it surrounds.
|
|
558
|
+
const box = el.getBoundingClientRect()
|
|
559
|
+
const depth = { Top: y - box.top, Right: box.right - x, Bottom: box.bottom - y, Left: x - box.left }
|
|
560
|
+
for (const side of ["Top", "Right", "Bottom", "Left"]) {
|
|
561
|
+
const width = parseFloat(style[`border${side}Width`])
|
|
562
|
+
if (!(width > 0) || style[`border${side}Style`] === "none" || transparent(style[`border${side}Color`])) continue
|
|
563
|
+
if (depth[side] >= 0 && depth[side] <= width) return true
|
|
564
|
+
}
|
|
565
|
+
const range = document.createRange()
|
|
566
|
+
for (const node of el.childNodes) {
|
|
567
|
+
if (node.nodeType !== 3 || !node.nodeValue.trim()) continue
|
|
568
|
+
range.selectNodeContents(node)
|
|
569
|
+
for (const box of range.getClientRects()) {
|
|
570
|
+
if (x >= box.left && x <= box.right && y >= box.top && y <= box.bottom) return true
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return false
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
function targetFromCatcher(event) {
|
|
577
|
+
catcher.style.pointerEvents = "none"
|
|
578
|
+
try {
|
|
579
|
+
const hit = pageElementFromPoint(event.clientX, event.clientY)
|
|
580
|
+
return unhittableElementAt(event.clientX, event.clientY, hit) || hit
|
|
581
|
+
} finally {
|
|
582
|
+
catcher.style.pointerEvents = ""
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function unfreezeHover() {
|
|
587
|
+
for (const item of frozenStyles) {
|
|
588
|
+
for (const [prop, value, priority] of item.overrides) {
|
|
589
|
+
if (value) item.el.style.setProperty(prop, value, priority)
|
|
590
|
+
else item.el.style.removeProperty(prop)
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
frozenStyles.length = 0
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const freezeExact = new Set([
|
|
597
|
+
"display", "visibility", "opacity", "overflow", "overflow-x", "overflow-y",
|
|
598
|
+
"color", "cursor", "z-index", "font-weight", "font-style",
|
|
599
|
+
"box-shadow", "text-shadow", "filter", "backdrop-filter", "mix-blend-mode",
|
|
600
|
+
"translate", "rotate", "scale", "clip-path",
|
|
601
|
+
])
|
|
602
|
+
const freezePrefix = ["background-", "border-", "outline-", "text-decoration", "transform", "mask-", "fill", "stroke"]
|
|
603
|
+
|
|
604
|
+
function shouldFreezeProp(prop) {
|
|
605
|
+
if (prop.includes("webkit-text-fill") || prop.includes("webkit-text-stroke")) return false
|
|
606
|
+
if (prop === "border-block-size" || prop === "border-inline-size") return false
|
|
607
|
+
if (freezeExact.has(prop)) return true
|
|
608
|
+
return freezePrefix.some((prefix) => prop === prefix || prop.startsWith(prefix))
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
function freezeSubtree(root) {
|
|
612
|
+
const nodes = [root, ...root.querySelectorAll("*")]
|
|
613
|
+
for (const el of nodes) {
|
|
614
|
+
const overrides = []
|
|
615
|
+
const cs = getComputedStyle(el)
|
|
616
|
+
for (let i = 0; i < cs.length; i++) {
|
|
617
|
+
const prop = cs[i]
|
|
618
|
+
if (!shouldFreezeProp(prop)) continue
|
|
619
|
+
overrides.push([prop, el.style.getPropertyValue(prop), el.style.getPropertyPriority(prop)])
|
|
620
|
+
el.style.setProperty(prop, cs.getPropertyValue(prop))
|
|
621
|
+
}
|
|
622
|
+
frozenStyles.push({ el, overrides })
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function freezeRootFrom(hit) {
|
|
627
|
+
const limit = prototypeRoot()
|
|
628
|
+
const areaCap = window.innerWidth * window.innerHeight * 0.5
|
|
629
|
+
let root = hit
|
|
630
|
+
while (root.parentElement) {
|
|
631
|
+
const parent = root.parentElement
|
|
632
|
+
if (parent === limit || parent === document.body || parent === document.documentElement) break
|
|
633
|
+
const box = parent.getBoundingClientRect()
|
|
634
|
+
if (box.width * box.height > areaCap) break
|
|
635
|
+
root = parent
|
|
636
|
+
}
|
|
637
|
+
freezeSubtree(root)
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function freezeHoverThenAnnotate() {
|
|
641
|
+
catcher.style.pointerEvents = "none"
|
|
642
|
+
try {
|
|
643
|
+
if (sawPointer) {
|
|
644
|
+
unfreezeHover()
|
|
645
|
+
freezeRootFrom(pageElementFromPoint(lastPointer.x, lastPointer.y))
|
|
646
|
+
}
|
|
647
|
+
} finally {
|
|
648
|
+
catcher.style.pointerEvents = ""
|
|
649
|
+
}
|
|
650
|
+
setCommentTool(true)
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
function isTypingTarget(el) {
|
|
654
|
+
if (!(el instanceof Element)) return false
|
|
655
|
+
const tag = el.tagName
|
|
656
|
+
if (tag === "TEXTAREA" || tag === "SELECT") return true
|
|
657
|
+
if (tag === "INPUT") {
|
|
658
|
+
const type = (el.getAttribute("type") || "text").toLowerCase()
|
|
659
|
+
return !["button", "submit", "reset", "checkbox", "radio", "file", "color", "range", "hidden"].includes(type)
|
|
660
|
+
}
|
|
661
|
+
return el.isContentEditable
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
toggle.addEventListener("click", () => {
|
|
665
|
+
if (sessionEnded || agentHasBatch()) return
|
|
666
|
+
setCommentTool(!commentToolOn)
|
|
667
|
+
})
|
|
668
|
+
|
|
669
|
+
commentField.addEventListener("input", syncSubmit)
|
|
670
|
+
cancel.addEventListener("click", () => closeComposer())
|
|
671
|
+
|
|
672
|
+
composer.addEventListener("submit", async (event) => {
|
|
673
|
+
event.preventDefault()
|
|
674
|
+
if (!draft || inFlight || sessionEnded) return
|
|
675
|
+
const comment = commentField.value.trim()
|
|
676
|
+
if (!comment) return
|
|
677
|
+
// The composer can be closed (tool toggled off) while the request is in
|
|
678
|
+
// flight; the submission is complete in itself from here on.
|
|
679
|
+
// The path names the screen this pin is on; the helper resolves it to the
|
|
680
|
+
// file the agent edits. Path only: no query, so no token.
|
|
681
|
+
const payload = {
|
|
682
|
+
page: servedPage,
|
|
683
|
+
comment,
|
|
684
|
+
selector: draft.selector,
|
|
685
|
+
textSnippet: draft.textSnippet,
|
|
686
|
+
variant: draft.variant,
|
|
687
|
+
rect: draft.rect,
|
|
688
|
+
point: draft.point,
|
|
689
|
+
}
|
|
690
|
+
const submission = { ...payload, x: draft.x, y: draft.y }
|
|
691
|
+
inFlight = true
|
|
692
|
+
syncSubmit()
|
|
693
|
+
error.hidden = true
|
|
694
|
+
try {
|
|
695
|
+
const response = await fetch(tokenUrl("/annotation"), {
|
|
696
|
+
method: "POST",
|
|
697
|
+
headers: { "Content-Type": "application/json" },
|
|
698
|
+
body: JSON.stringify(payload),
|
|
699
|
+
})
|
|
700
|
+
if (!response.ok) throw new Error("retry")
|
|
701
|
+
const { id } = await response.json()
|
|
702
|
+
pins.push({ ...submission, id, status: PIN_STATUS[annotationStates[id]] || "pending" })
|
|
703
|
+
renderPins()
|
|
704
|
+
syncStopButton()
|
|
705
|
+
persistState()
|
|
706
|
+
closeComposer()
|
|
707
|
+
} catch {
|
|
708
|
+
if (!sessionEnded) {
|
|
709
|
+
composer.hidden = false
|
|
710
|
+
error.hidden = false
|
|
711
|
+
error.textContent = "Could not send — retry"
|
|
712
|
+
}
|
|
713
|
+
} finally {
|
|
714
|
+
inFlight = false
|
|
715
|
+
syncSubmit()
|
|
716
|
+
}
|
|
717
|
+
if (reloadPending && !sessionEnded) requestReload()
|
|
718
|
+
})
|
|
719
|
+
|
|
720
|
+
stop.addEventListener("click", async () => {
|
|
721
|
+
if (sessionEnded) return
|
|
722
|
+
stop.disabled = true
|
|
723
|
+
while (inFlight && !sessionEnded) {
|
|
724
|
+
await new Promise((resolve) => setTimeout(resolve, 20))
|
|
725
|
+
}
|
|
726
|
+
if (sessionEnded) return
|
|
727
|
+
const sending = unflushedCount() > 0
|
|
728
|
+
try {
|
|
729
|
+
const response = await fetch(tokenUrl(sending ? "/session/flush" : "/session/end"), { method: "POST" })
|
|
730
|
+
if (!response.ok) throw new Error("retry")
|
|
731
|
+
} catch {
|
|
732
|
+
stop.disabled = false
|
|
733
|
+
setStatus(sending ? "Could not send to agent — retry" : "Could not end session — retry")
|
|
734
|
+
return
|
|
735
|
+
}
|
|
736
|
+
if (sending) {
|
|
737
|
+
for (const id of Object.keys(annotationStates)) {
|
|
738
|
+
if (annotationStates[id] === "held") annotationStates[id] = "queued"
|
|
739
|
+
}
|
|
740
|
+
for (const pin of pins) {
|
|
741
|
+
if (pin.id && (!annotationStates[pin.id] || annotationStates[pin.id] === "held")) {
|
|
742
|
+
annotationStates[pin.id] = "queued"
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
persistState()
|
|
746
|
+
stop.disabled = false
|
|
747
|
+
syncStopButton()
|
|
748
|
+
return
|
|
749
|
+
}
|
|
750
|
+
markEnded()
|
|
751
|
+
})
|
|
752
|
+
|
|
753
|
+
window.addEventListener("pagehide", persistState)
|
|
754
|
+
// Leaving the page aborts the event stream before pagehide; that abort is
|
|
755
|
+
// not the helper ending the session, and pagehide would persist it as one.
|
|
756
|
+
window.addEventListener("beforeunload", () => {
|
|
757
|
+
leavingPage = true
|
|
758
|
+
})
|
|
759
|
+
window.addEventListener("pageshow", (event) => {
|
|
760
|
+
leavingPage = false
|
|
761
|
+
if (event.persisted) restorePersistedState()
|
|
762
|
+
})
|
|
763
|
+
window.addEventListener("scroll", reattachPins, { capture: true, passive: true })
|
|
764
|
+
window.addEventListener("resize", reattachPins)
|
|
765
|
+
const layoutRoot = prototypeRoot()
|
|
766
|
+
if (typeof ResizeObserver === "function") {
|
|
767
|
+
new ResizeObserver(reattachPins).observe(layoutRoot)
|
|
768
|
+
}
|
|
769
|
+
if (typeof MutationObserver === "function") {
|
|
770
|
+
new MutationObserver(reattachPins).observe(layoutRoot, {
|
|
771
|
+
subtree: true,
|
|
772
|
+
childList: true,
|
|
773
|
+
attributes: true,
|
|
774
|
+
attributeFilter: ["style", "class", "hidden", "data-ce-variant"],
|
|
775
|
+
})
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
catcher.addEventListener("click", (event) => {
|
|
779
|
+
if (!commentToolOn || sessionEnded || agentHasBatch()) return
|
|
780
|
+
event.preventDefault()
|
|
781
|
+
event.stopPropagation()
|
|
782
|
+
const target = targetFromCatcher(event)
|
|
783
|
+
if (!(target instanceof Element)) return
|
|
784
|
+
openComposer(target, event)
|
|
785
|
+
})
|
|
786
|
+
|
|
787
|
+
document.addEventListener("pointermove", (event) => {
|
|
788
|
+
sawPointer = true
|
|
789
|
+
lastPointer.x = event.clientX
|
|
790
|
+
lastPointer.y = event.clientY
|
|
791
|
+
showPinTipAt(event.clientX, event.clientY)
|
|
792
|
+
}, { capture: true, passive: true })
|
|
793
|
+
|
|
794
|
+
document.addEventListener("keydown", (event) => {
|
|
795
|
+
if (sessionEnded || agentHasBatch()) return
|
|
796
|
+
if (event.key === "Escape") {
|
|
797
|
+
if (!commentToolOn && composer.hidden) return
|
|
798
|
+
event.preventDefault()
|
|
799
|
+
event.stopPropagation()
|
|
800
|
+
setCommentTool(false)
|
|
801
|
+
return
|
|
802
|
+
}
|
|
803
|
+
if (!event.ctrlKey || event.metaKey || event.altKey || event.shiftKey) return
|
|
804
|
+
if (event.key.toLowerCase() !== "a") return
|
|
805
|
+
const path = event.composedPath()
|
|
806
|
+
if (path.some((node) => isTypingTarget(node))) return
|
|
807
|
+
if (isTypingTarget(shadow.activeElement) || isTypingTarget(document.activeElement)) return
|
|
808
|
+
event.preventDefault()
|
|
809
|
+
event.stopPropagation()
|
|
810
|
+
if (commentToolOn) {
|
|
811
|
+
setCommentTool(false)
|
|
812
|
+
return
|
|
813
|
+
}
|
|
814
|
+
freezeHoverThenAnnotate()
|
|
815
|
+
}, true)
|
|
816
|
+
|
|
817
|
+
if (restorePersistedState()) reattachPins()
|
|
818
|
+
syncStopButton()
|
|
819
|
+
|
|
820
|
+
if ("EventSource" in window) {
|
|
821
|
+
source = new EventSource(tokenUrl("/events", { document: servedDocument }))
|
|
822
|
+
source.addEventListener("screen-changed", requestReload)
|
|
823
|
+
source.addEventListener("annotations", (event) => {
|
|
824
|
+
let states
|
|
825
|
+
try {
|
|
826
|
+
states = JSON.parse(event.data)
|
|
827
|
+
} catch {
|
|
828
|
+
return
|
|
829
|
+
}
|
|
830
|
+
applyAnnotationStates(states)
|
|
831
|
+
})
|
|
832
|
+
source.addEventListener("session-ended", markEnded)
|
|
833
|
+
source.addEventListener("error", () => {
|
|
834
|
+
if (source.readyState === EventSource.CLOSED && !leavingPage) markEnded()
|
|
835
|
+
})
|
|
836
|
+
}
|
|
837
|
+
})()
|