@bastani/atomic 0.9.13 → 0.9.14-alpha.2
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 +58 -0
- package/README.md +3 -3
- package/dist/builtin/intercom/package.json +2 -2
- package/dist/builtin/mcp/package.json +3 -3
- package/dist/builtin/subagents/CHANGELOG.md +14 -0
- package/dist/builtin/subagents/README.md +6 -4
- package/dist/builtin/subagents/agents/code-simplifier.md +1 -1
- package/dist/builtin/subagents/agents/codebase-analyzer.md +1 -1
- package/dist/builtin/subagents/agents/codebase-locator.md +1 -1
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +1 -1
- package/dist/builtin/subagents/agents/codebase-pattern-finder.md +1 -1
- package/dist/builtin/subagents/agents/codebase-research-analyzer.md +1 -1
- package/dist/builtin/subagents/agents/codebase-research-locator.md +1 -1
- package/dist/builtin/subagents/agents/debugger.md +1 -1
- package/dist/builtin/subagents/agents/worker.md +1 -1
- package/dist/builtin/subagents/package.json +6 -5
- package/dist/builtin/subagents/src/agents/agent-discovery.ts +17 -11
- package/dist/builtin/subagents/src/agents/agent-loaders.ts +115 -43
- package/dist/builtin/subagents/src/agents/agent-management-helpers.ts +10 -8
- package/dist/builtin/subagents/src/agents/agent-management.ts +8 -7
- package/dist/builtin/subagents/src/agents/agent-overrides.ts +2 -2
- package/dist/builtin/subagents/src/agents/agent-scope.ts +1 -1
- package/dist/builtin/subagents/src/agents/agent-selection.ts +1 -1
- package/dist/builtin/subagents/src/agents/agent-serializer.ts +24 -3
- package/dist/builtin/subagents/src/agents/agent-types.ts +3 -1
- package/dist/builtin/subagents/src/agents/agents.ts +7 -5
- package/dist/builtin/subagents/src/agents/frontmatter.ts +67 -22
- package/dist/builtin/subagents/src/agents/identity.ts +1 -1
- package/dist/builtin/subagents/src/agents/skills-paths.ts +1 -1
- package/dist/builtin/subagents/src/agents/skills.ts +64 -6
- package/dist/builtin/subagents/src/extension/config.ts +1 -1
- package/dist/builtin/subagents/src/extension/control-notices.ts +2 -2
- package/dist/builtin/subagents/src/extension/doctor.ts +15 -5
- package/dist/builtin/subagents/src/extension/fanout-child.ts +12 -12
- package/dist/builtin/subagents/src/extension/index.ts +23 -23
- package/dist/builtin/subagents/src/extension/notification-content.ts +1 -1
- package/dist/builtin/subagents/src/extension/schemas.ts +1 -1
- package/dist/builtin/subagents/src/extension/startup-maintenance.ts +3 -3
- package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +3 -3
- package/dist/builtin/subagents/src/intercom/result-intercom.ts +1 -1
- package/dist/builtin/subagents/src/intercom/supervisor-authorization.ts +1 -1
- package/dist/builtin/subagents/src/runs/foreground/completion-notification.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/execution-detach-reservations.ts +1 -1
- package/dist/builtin/subagents/src/runs/foreground/execution-intercom-detach.ts +3 -3
- package/dist/builtin/subagents/src/runs/foreground/execution-run-sync.ts +1 -1
- package/dist/builtin/subagents/src/runs/foreground/execution-updates.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/execution-utils.ts +1 -1
- package/dist/builtin/subagents/src/runs/foreground/execution.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +27 -11
- package/dist/builtin/subagents/src/runs/foreground/notify.ts +3 -3
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +11 -11
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-input.ts +3 -3
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +15 -14
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +19 -19
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +2 -2
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +14 -13
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +9 -9
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +7 -7
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor-worktree.ts +6 -6
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +24 -23
- package/dist/builtin/subagents/src/runs/inprocess/control-registry.ts +1 -1
- package/dist/builtin/subagents/src/runs/inprocess/control-status.ts +3 -3
- package/dist/builtin/subagents/src/runs/inprocess/index.ts +3 -3
- package/dist/builtin/subagents/src/runs/inprocess/prompt-behavior.ts +17 -8
- package/dist/builtin/subagents/src/runs/inprocess/runner.ts +60 -12
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-api.ts +8 -8
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-control.ts +3 -3
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-core.ts +4 -4
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-projection.ts +4 -4
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-registry.ts +5 -5
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-rendering.ts +3 -3
- package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-sanitize.ts +3 -3
- package/dist/builtin/subagents/src/runs/inprocess.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/long-running-guard.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/mcp-direct-tool-allowlist.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/model-candidate-filter.ts +3 -3
- package/dist/builtin/subagents/src/runs/shared/model-fallback.ts +2 -2
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/single-output.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/subagent-control.ts +1 -1
- package/dist/builtin/subagents/src/shared/artifacts.ts +2 -2
- package/dist/builtin/subagents/src/shared/event-jsonl-writer.ts +1 -1
- package/dist/builtin/subagents/src/shared/fast-mode.ts +1 -1
- package/dist/builtin/subagents/src/shared/formatters.ts +2 -2
- package/dist/builtin/subagents/src/shared/jsonl-writer.ts +1 -1
- package/dist/builtin/subagents/src/shared/model-resolution.ts +1 -1
- package/dist/builtin/subagents/src/shared/session-tokens.ts +1 -1
- package/dist/builtin/subagents/src/shared/settings.ts +4 -4
- package/dist/builtin/subagents/src/shared/status-format.ts +1 -1
- package/dist/builtin/subagents/src/shared/types-config.ts +16 -4
- package/dist/builtin/subagents/src/shared/types-depth.ts +1 -1
- package/dist/builtin/subagents/src/shared/types-nested.ts +1 -1
- package/dist/builtin/subagents/src/shared/types-output.ts +1 -1
- package/dist/builtin/subagents/src/shared/types-results.ts +1 -1
- package/dist/builtin/subagents/src/shared/types-runtime.ts +1 -1
- package/dist/builtin/subagents/src/shared/types.ts +6 -6
- package/dist/builtin/subagents/src/shared/utils.ts +3 -3
- package/dist/builtin/subagents/src/slash/prompt-template-bridge.ts +1 -1
- package/dist/builtin/subagents/src/slash/slash-bridge.ts +3 -3
- package/dist/builtin/subagents/src/slash/slash-commands.ts +6 -6
- package/dist/builtin/subagents/src/slash/slash-live-state.ts +3 -3
- package/dist/builtin/subagents/src/tui/render-event-formatting.ts +2 -2
- package/dist/builtin/subagents/src/tui/render-layout.ts +1 -1
- package/dist/builtin/subagents/src/tui/render-progress.ts +2 -2
- package/dist/builtin/subagents/src/tui/render-result-compact.ts +7 -7
- package/dist/builtin/subagents/src/tui/render-result.ts +10 -10
- package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -1
- package/dist/builtin/subagents/src/tui/render-status-progress.ts +5 -5
- package/dist/builtin/subagents/src/tui/render.ts +4 -4
- package/dist/builtin/web-access/package.json +2 -2
- package/dist/builtin/workflows/CHANGELOG.md +57 -0
- package/dist/builtin/workflows/README.md +39 -8
- package/dist/builtin/workflows/builtin/adversarial-verification-runner.ts +16 -5
- package/dist/builtin/workflows/builtin/adversarial-verification.ts +4 -0
- package/dist/builtin/workflows/builtin/classify-and-act.ts +4 -0
- package/dist/builtin/workflows/builtin/fan-out-and-synthesize.ts +4 -0
- package/dist/builtin/workflows/builtin/generate-and-filter-runner.ts +12 -4
- package/dist/builtin/workflows/builtin/generate-and-filter.ts +4 -0
- package/dist/builtin/workflows/builtin/goal-models.ts +8 -10
- package/dist/builtin/workflows/builtin/goal.ts +4 -0
- package/dist/builtin/workflows/builtin/index.d.ts +0 -4
- package/dist/builtin/workflows/builtin/loop-until-done-runner.ts +4 -2
- package/dist/builtin/workflows/builtin/loop-until-done.ts +4 -0
- package/dist/builtin/workflows/builtin/open-claude-design-live-protocol.ts +305 -0
- package/dist/builtin/workflows/builtin/open-claude-design-phases.ts +115 -171
- package/dist/builtin/workflows/builtin/open-claude-design-runner.ts +9 -25
- package/dist/builtin/workflows/builtin/open-claude-design-setup.ts +19 -86
- package/dist/builtin/workflows/builtin/open-claude-design-utils.ts +0 -6
- package/dist/builtin/workflows/builtin/open-claude-design.d.ts +0 -5
- package/dist/builtin/workflows/builtin/open-claude-design.ts +11 -15
- package/dist/builtin/workflows/builtin/ralph-models.ts +24 -29
- package/dist/builtin/workflows/builtin/ralph.ts +4 -0
- package/dist/builtin/workflows/builtin/tournament-runner.ts +6 -3
- package/dist/builtin/workflows/builtin/tournament.ts +4 -0
- package/dist/builtin/workflows/package.json +2 -2
- package/dist/builtin/workflows/skills/impeccable/SKILL.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/agents/impeccable_asset_producer.toml +25 -31
- package/dist/builtin/workflows/skills/impeccable/agents/impeccable_documenter.toml +1 -0
- package/dist/builtin/workflows/skills/impeccable/agents/impeccable_finish_reviewer.toml +16 -10
- package/dist/builtin/workflows/skills/impeccable/agents/impeccable_manual_edit_applier.toml +2 -2
- package/dist/builtin/workflows/skills/impeccable/reference/android.md +6 -0
- package/dist/builtin/workflows/skills/impeccable/reference/animate.md +3 -0
- package/dist/builtin/workflows/skills/impeccable/reference/bolder.md +3 -1
- package/dist/builtin/workflows/skills/impeccable/reference/craft-floor.md +6 -1
- package/dist/builtin/workflows/skills/impeccable/reference/critique.md +18 -2
- package/dist/builtin/workflows/skills/impeccable/reference/degraded/asset-producer.md +24 -30
- package/dist/builtin/workflows/skills/impeccable/reference/degraded/documenter.md +1 -0
- package/dist/builtin/workflows/skills/impeccable/reference/degraded/finish-reviewer.md +16 -10
- package/dist/builtin/workflows/skills/impeccable/reference/degraded/manual-edit-applier.md +2 -2
- package/dist/builtin/workflows/skills/impeccable/reference/distill.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/doctor.md +1 -0
- package/dist/builtin/workflows/skills/impeccable/reference/document.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/extract.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +12 -6
- package/dist/builtin/workflows/skills/impeccable/reference/init.md +12 -3
- package/dist/builtin/workflows/skills/impeccable/reference/ios.md +6 -0
- package/dist/builtin/workflows/skills/impeccable/reference/live-setup.md +102 -0
- package/dist/builtin/workflows/skills/impeccable/reference/live.md +113 -521
- package/dist/builtin/workflows/skills/impeccable/reference/new-work.md +39 -26
- package/dist/builtin/workflows/skills/impeccable/reference/overdrive.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/polish.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/quieter.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/visualize.md +25 -11
- package/dist/builtin/workflows/skills/impeccable/scripts/concept-seed.mjs +332 -221
- package/dist/builtin/workflows/skills/impeccable/scripts/context-signals.mjs +10 -19
- package/dist/builtin/workflows/skills/impeccable/scripts/context.mjs +91 -38
- package/dist/builtin/workflows/skills/impeccable/scripts/critique-storage.mjs +19 -10
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/browser/injected/index.mjs +56 -6
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/cli/main.mjs +10 -16
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/design-system.mjs +140 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/detect-antipatterns-browser.js +1174 -694
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/detect-antipatterns.mjs +1 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/browser/detect-url.mjs +5 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/regex/detect-text.mjs +431 -45
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/static-html/css-cascade.mjs +10 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/engines/static-html/detect-html.mjs +47 -6
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/node/file-system.mjs +23 -22
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/registry/antipatterns.mjs +0 -10
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/rules/checks.mjs +384 -384
- package/dist/builtin/workflows/skills/impeccable/scripts/detector/shared/color.mjs +466 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/doctor.mjs +2 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/embed-prompt.mjs +270 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/generate-image.mjs +51 -6
- package/dist/builtin/workflows/skills/impeccable/scripts/hook-admin.mjs +70 -10
- package/dist/builtin/workflows/skills/impeccable/scripts/hook-lib.mjs +336 -90
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/composition-catalog.mjs +38 -3
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/concept-catalog.mjs +77 -11
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/design-parser.mjs +102 -19
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/impeccable-config.mjs +44 -59
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/is-generated.mjs +3 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/open-system-browser.mjs +57 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/roll-selection.mjs +369 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/staleness-deep.mjs +31 -3
- package/dist/builtin/workflows/skills/impeccable/scripts/lib/staleness.mjs +73 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/live/accept-css.mjs +617 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/accept-verify.mjs +71 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/browser-script-parts.mjs +29 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/live/event-validation.mjs +54 -7
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/astro.mjs +47 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/detect-utils.mjs +157 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/index.mjs +143 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/journal.mjs +205 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/nextjs.mjs +49 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/nuxt.mjs +170 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/script-src.mjs +26 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/static-html.mjs +26 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/sveltekit.mjs +71 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/tag-strategy.mjs +247 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/tanstack-start.mjs +70 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/frameworks/vite-generic.mjs +42 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/instructions.mjs +169 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/roots.mjs +670 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/session-store.mjs +232 -35
- package/dist/builtin/workflows/skills/impeccable/scripts/live/svelte-ast.mjs +969 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/svelte-component.mjs +621 -74
- package/dist/builtin/workflows/skills/impeccable/scripts/live/sveltekit-adapter.mjs +66 -28
- package/dist/builtin/workflows/skills/impeccable/scripts/live/tanstack-adapter.mjs +12 -12
- package/dist/builtin/workflows/skills/impeccable/scripts/live/ui-surfaces.mjs +75 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live/vocabulary.mjs +135 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live-accept.mjs +23 -37
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +945 -115
- package/dist/builtin/workflows/skills/impeccable/scripts/live-complete.mjs +33 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/live-copy-edit-agent.mjs +132 -15
- package/dist/builtin/workflows/skills/impeccable/scripts/live-inject.mjs +173 -425
- package/dist/builtin/workflows/skills/impeccable/scripts/live-insert.mjs +2 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/live-poll.mjs +16 -3
- package/dist/builtin/workflows/skills/impeccable/scripts/live-resume.mjs +39 -10
- package/dist/builtin/workflows/skills/impeccable/scripts/live-server.mjs +194 -27
- package/dist/builtin/workflows/skills/impeccable/scripts/live-status.mjs +10 -4
- package/dist/builtin/workflows/skills/impeccable/scripts/live-wrap.mjs +50 -31
- package/dist/builtin/workflows/skills/impeccable/scripts/live.mjs +91 -28
- package/dist/builtin/workflows/skills/impeccable/scripts/pin.mjs +8 -5
- package/dist/builtin/workflows/skills/impeccable/scripts/serve-question.mjs +759 -109
- package/dist/builtin/workflows/src/authoring/workflow.ts +9 -0
- package/dist/builtin/workflows/src/authoring.d.ts +3 -0
- package/dist/builtin/workflows/src/durable/completed-catalog.ts +23 -2
- package/dist/builtin/workflows/src/durable/dbos-backend.ts +30 -17
- package/dist/builtin/workflows/src/durable/dbos-envelope.ts +14 -0
- package/dist/builtin/workflows/src/durable/dbos-lifecycle.ts +60 -57
- package/dist/builtin/workflows/src/durable/dbos-process-owner.ts +87 -0
- package/dist/builtin/workflows/src/durable/dbos-registration-diagnostics.ts +113 -0
- package/dist/builtin/workflows/src/durable/factory.ts +11 -8
- package/dist/builtin/workflows/src/durable/tool-failure-checkpoint.ts +5 -0
- package/dist/builtin/workflows/src/durable/tool-primitive.ts +186 -20
- package/dist/builtin/workflows/src/durable/types.ts +4 -0
- package/dist/builtin/workflows/src/durable/workflow-heartbeat-anchor.ts +153 -0
- package/dist/builtin/workflows/src/engine/run-durable-stage-session.ts +28 -0
- package/dist/builtin/workflows/src/engine/run-tool-control-registry.ts +9 -1
- package/dist/builtin/workflows/src/engine/run.ts +1 -0
- package/dist/builtin/workflows/src/extension/adopt-session-run-state.ts +20 -0
- package/dist/builtin/workflows/src/extension/background-ui-adapter.ts +9 -30
- package/dist/builtin/workflows/src/extension/extension-factory.ts +3 -0
- package/dist/builtin/workflows/src/extension/extension-lifecycle.ts +28 -10
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +138 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +3365 -1341
- package/dist/builtin/workflows/src/extension/workflow-heartbeat-delivery.ts +197 -0
- package/dist/builtin/workflows/src/extension/workflow-heartbeat-notice.ts +115 -0
- package/dist/builtin/workflows/src/extension/workflow-heartbeat-scheduler.ts +962 -0
- package/dist/builtin/workflows/src/extension/workflow-prompts.ts +4 -1
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +29 -5
- package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +32 -1
- package/dist/builtin/workflows/src/runs/background/cancellation-registry.ts +10 -1
- package/dist/builtin/workflows/src/runs/background/job-tracker.ts +10 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-prompt-nodes.ts +16 -11
- package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +31 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +41 -10
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-messages.ts +48 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts +4 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-structured-output.ts +45 -12
- package/dist/builtin/workflows/src/sdk-surface.ts +9 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +10 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +10 -0
- package/dist/builtin/workflows/src/shared/graph-store-snapshot.ts +14 -2
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +12 -0
- package/dist/builtin/workflows/src/shared/prompt-answer.ts +130 -0
- package/dist/builtin/workflows/src/shared/session-scoped-singleton.ts +98 -0
- package/dist/builtin/workflows/src/shared/stage-ui-broker.ts +9 -1
- package/dist/builtin/workflows/src/shared/store-factory.ts +9 -1
- package/dist/builtin/workflows/src/shared/store-public-types.ts +2 -1
- package/dist/builtin/workflows/src/shared/store-tool-node-methods.ts +7 -0
- package/dist/builtin/workflows/src/shared/store-types.ts +18 -1
- package/dist/builtin/workflows/src/shared/tool-payload-bounds.ts +576 -0
- package/dist/builtin/workflows/src/shared/workflow-authoring-types.d.ts +1 -0
- package/dist/builtin/workflows/src/shared/workflow-authoring-types.ts +1 -0
- package/dist/builtin/workflows/src/shared/workflow-heartbeat-contract.d.ts +21 -0
- package/dist/builtin/workflows/src/shared/workflow-heartbeat-contract.ts +25 -0
- package/dist/builtin/workflows/src/tui/graph-theme.ts +8 -1
- package/dist/builtin/workflows/src/tui/graph-view-constants.ts +11 -0
- package/dist/builtin/workflows/src/tui/graph-view-input.ts +100 -5
- package/dist/builtin/workflows/src/tui/graph-view-layout.ts +42 -11
- package/dist/builtin/workflows/src/tui/graph-view-render-helpers.ts +55 -6
- package/dist/builtin/workflows/src/tui/graph-view-render.ts +71 -6
- package/dist/builtin/workflows/src/tui/graph-view-state.ts +43 -0
- package/dist/builtin/workflows/src/tui/keybindings-adapter.ts +2 -0
- package/dist/builtin/workflows/src/tui/node-card.ts +5 -1
- package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +11 -2
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +36 -10
- package/dist/builtin/workflows/src/tui/switcher.ts +11 -4
- package/dist/builtin/workflows/src/tui/tool-detail.ts +348 -0
- package/dist/builtin/workflows/src/tui/workflow-status.ts +5 -2
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +11 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/auth-check.d.ts +1 -1
- package/dist/cli/auth-check.js.map +1 -1
- package/dist/cli/credential-print.d.ts +1 -1
- package/dist/cli/credential-print.js.map +1 -1
- package/dist/cli/list-models.d.ts +1 -1
- package/dist/cli/list-models.js.map +1 -1
- package/dist/cli/startup-ui.d.ts +9 -0
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +7 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/core/agent-session-custom-message-commit.js +2 -2
- package/dist/core/agent-session-custom-message-commit.js.map +1 -1
- package/dist/core/agent-session-export.d.ts +6 -1
- package/dist/core/agent-session-export.d.ts.map +1 -1
- package/dist/core/agent-session-export.js +6 -3
- package/dist/core/agent-session-export.js.map +1 -1
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
- package/dist/core/agent-session-extension-bindings.js +6 -4
- package/dist/core/agent-session-extension-bindings.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +5 -2
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-prompt.d.ts +12 -1
- package/dist/core/agent-session-prompt.d.ts.map +1 -1
- package/dist/core/agent-session-prompt.js +31 -10
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-runtime-auth.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +1 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session-skill-block.d.ts +1 -0
- package/dist/core/agent-session-skill-block.d.ts.map +1 -1
- package/dist/core/agent-session-skill-block.js +18 -2
- package/dist/core/agent-session-skill-block.js.map +1 -1
- package/dist/core/agent-session-state.d.ts.map +1 -1
- package/dist/core/agent-session-state.js +2 -1
- package/dist/core/agent-session-state.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +2 -1
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +1 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/atomic-guide-command.js +2 -2
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/builtin-packages.d.ts.map +1 -1
- package/dist/core/builtin-packages.js +0 -6
- package/dist/core/builtin-packages.js.map +1 -1
- package/dist/core/cloudflare-gateway-binding.d.ts +11 -0
- package/dist/core/cloudflare-gateway-binding.d.ts.map +1 -0
- package/dist/core/cloudflare-gateway-binding.js +11 -0
- package/dist/core/cloudflare-gateway-binding.js.map +1 -0
- package/dist/core/codex-fast-mode-transport.d.ts +12 -0
- package/dist/core/codex-fast-mode-transport.d.ts.map +1 -0
- package/dist/core/codex-fast-mode-transport.js +130 -0
- package/dist/core/codex-fast-mode-transport.js.map +1 -0
- package/dist/core/codex-fast-mode.d.ts +20 -6
- package/dist/core/codex-fast-mode.d.ts.map +1 -1
- package/dist/core/codex-fast-mode.js +111 -3
- package/dist/core/codex-fast-mode.js.map +1 -1
- package/dist/core/diagnostics.d.ts +4 -0
- package/dist/core/diagnostics.d.ts.map +1 -1
- package/dist/core/diagnostics.js.map +1 -1
- package/dist/core/event-bus.d.ts +12 -0
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js +22 -0
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/experimental.d.ts +25 -0
- package/dist/core/experimental.d.ts.map +1 -1
- package/dist/core/experimental.js +24 -0
- package/dist/core/experimental.js.map +1 -1
- package/dist/core/export-html/template-js/tree-filter-render.js +4 -3
- package/dist/core/export-html/template.js +4 -3
- package/dist/core/extension-session-state.d.ts +28 -0
- package/dist/core/extension-session-state.d.ts.map +1 -0
- package/dist/core/extension-session-state.js +55 -0
- package/dist/core/extension-session-state.js.map +1 -0
- package/dist/core/extensions/api-types.d.ts +6 -0
- package/dist/core/extensions/api-types.d.ts.map +1 -1
- package/dist/core/extensions/api-types.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +4 -0
- package/dist/core/extensions/context-types.d.ts.map +1 -1
- package/dist/core/extensions/context-types.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -0
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -0
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader-api.d.ts +1 -1
- package/dist/core/extensions/loader-api.d.ts.map +1 -1
- package/dist/core/extensions/loader-api.js +16 -10
- package/dist/core/extensions/loader-api.js.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/loader-virtual-modules.js +12 -1
- package/dist/core/extensions/loader-virtual-modules.js.map +1 -1
- package/dist/core/extensions/runner-context.d.ts +2 -0
- package/dist/core/extensions/runner-context.d.ts.map +1 -1
- package/dist/core/extensions/runner-context.js +8 -0
- package/dist/core/extensions/runner-context.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +3 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/runtime-types.d.ts +3 -0
- package/dist/core/extensions/runtime-types.d.ts.map +1 -1
- package/dist/core/extensions/runtime-types.js.map +1 -1
- package/dist/core/extensions/ui-types.d.ts +26 -0
- package/dist/core/extensions/ui-types.d.ts.map +1 -1
- package/dist/core/extensions/ui-types.js +17 -1
- package/dist/core/extensions/ui-types.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +5 -0
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/keybindings.d.ts +24 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +6 -0
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-config.d.ts +5 -0
- package/dist/core/model-config.d.ts.map +1 -1
- package/dist/core/model-config.js +1 -0
- package/dist/core/model-config.js.map +1 -1
- package/dist/core/model-registry.d.ts +1 -1
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver-cli.d.ts +1 -1
- package/dist/core/model-resolver-cli.js.map +1 -1
- package/dist/core/model-resolver-defaults.js +3 -3
- package/dist/core/model-resolver-defaults.js.map +1 -1
- package/dist/core/model-resolver-initial.d.ts +1 -1
- package/dist/core/model-resolver-initial.js.map +1 -1
- package/dist/core/model-resolver-scope.d.ts +1 -1
- package/dist/core/model-resolver-scope.js.map +1 -1
- package/dist/core/model-runtime.d.ts +54 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +96 -13
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/oauth-login.js.map +1 -1
- package/dist/core/project-trust.d.ts +10 -0
- package/dist/core/project-trust.d.ts.map +1 -1
- package/dist/core/project-trust.js +12 -0
- package/dist/core/project-trust.js.map +1 -1
- package/dist/core/resource-loader-assets.d.ts.map +1 -1
- package/dist/core/resource-loader-assets.js +14 -5
- package/dist/core/resource-loader-assets.js.map +1 -1
- package/dist/core/resource-loader-core.d.ts +3 -0
- package/dist/core/resource-loader-core.d.ts.map +1 -1
- package/dist/core/resource-loader-core.js +5 -0
- package/dist/core/resource-loader-core.js.map +1 -1
- package/dist/core/resource-loader-internals.d.ts +2 -0
- package/dist/core/resource-loader-internals.d.ts.map +1 -1
- package/dist/core/resource-loader-internals.js.map +1 -1
- package/dist/core/resource-loader-reload.d.ts.map +1 -1
- package/dist/core/resource-loader-reload.js +2 -0
- package/dist/core/resource-loader-reload.js.map +1 -1
- package/dist/core/resource-loader-types.d.ts +2 -0
- package/dist/core/resource-loader-types.d.ts.map +1 -1
- package/dist/core/resource-loader-types.js.map +1 -1
- package/dist/core/resource-loader.d.ts +2 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +1 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk-types.d.ts +7 -6
- package/dist/core/sdk-types.d.ts.map +1 -1
- package/dist/core/sdk-types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +17 -6
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-core.d.ts +7 -1
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +11 -2
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-entries.d.ts +2 -2
- package/dist/core/session-manager-entries.d.ts.map +1 -1
- package/dist/core/session-manager-entries.js +6 -4
- package/dist/core/session-manager-entries.js.map +1 -1
- package/dist/core/session-manager-list.d.ts.map +1 -1
- package/dist/core/session-manager-list.js +5 -1
- package/dist/core/session-manager-list.js.map +1 -1
- package/dist/core/session-manager-types.d.ts +25 -2
- package/dist/core/session-manager-types.d.ts.map +1 -1
- package/dist/core/session-manager-types.js.map +1 -1
- package/dist/core/session-manager.d.ts +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager-basic-accessors.d.ts +1 -0
- package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-basic-accessors.js +8 -0
- package/dist/core/settings-manager-basic-accessors.js.map +1 -1
- package/dist/core/settings-manager-ui-accessors.d.ts +3 -1
- package/dist/core/settings-manager-ui-accessors.d.ts.map +1 -1
- package/dist/core/settings-manager-ui-accessors.js +9 -0
- package/dist/core/settings-manager-ui-accessors.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-types.d.ts +4 -0
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/skill-catalog.d.ts +35 -0
- package/dist/core/skill-catalog.d.ts.map +1 -0
- package/dist/core/skill-catalog.js +264 -0
- package/dist/core/skill-catalog.js.map +1 -0
- package/dist/core/skills-async.d.ts.map +1 -1
- package/dist/core/skills-async.js +12 -6
- package/dist/core/skills-async.js.map +1 -1
- package/dist/core/skills.d.ts +2 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +8 -5
- package/dist/core/skills.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -5
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.js +2 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/ask-user-question/ask-user-question.d.ts +25 -2
- package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/ask-user-question.js +47 -18
- package/dist/core/tools/ask-user-question/ask-user-question.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/multi-select-view.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/multi-select-view.js +5 -2
- package/dist/core/tools/ask-user-question/view/components/multi-select-view.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/submit-picker.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/submit-picker.js +3 -1
- package/dist/core/tools/ask-user-question/view/components/submit-picker.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.js +8 -1
- package/dist/core/tools/ask-user-question/view/components/wrapping-select.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +2 -0
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +2 -0
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +3 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.js +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/hashline-engine/format.d.ts +2 -0
- package/dist/core/tools/hashline-engine/format.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/format.js +4 -2
- package/dist/core/tools/hashline-engine/format.js.map +1 -1
- package/dist/core/tools/hashline-engine/messages.d.ts +2 -0
- package/dist/core/tools/hashline-engine/messages.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/messages.js +4 -2
- package/dist/core/tools/hashline-engine/messages.js.map +1 -1
- package/dist/core/tools/hashline-engine/parser.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/parser.js +16 -4
- package/dist/core/tools/hashline-engine/parser.js.map +1 -1
- package/dist/core/tools/hashline-engine/tokenizer.d.ts.map +1 -1
- package/dist/core/tools/hashline-engine/tokenizer.js +37 -27
- package/dist/core/tools/hashline-engine/tokenizer.js.map +1 -1
- package/dist/core/tools/hashline.d.ts.map +1 -1
- package/dist/core/tools/hashline.js +8 -2
- package/dist/core/tools/hashline.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +2 -0
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +8 -1
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/search.d.ts.map +1 -1
- package/dist/core/tools/search.js +2 -0
- package/dist/core/tools/search.js.map +1 -1
- package/dist/core/tools/todos.d.ts +3 -12
- package/dist/core/tools/todos.d.ts.map +1 -1
- package/dist/core/tools/todos.js +19 -4
- package/dist/core/tools/todos.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +2 -0
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index-extensions.d.ts +1 -1
- package/dist/index-extensions.d.ts.map +1 -1
- package/dist/index-extensions.js +1 -1
- package/dist/index-extensions.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/main-runtime-api-key.d.ts +1 -1
- package/dist/main-runtime-api-key.js.map +1 -1
- package/dist/main-session-options.d.ts +1 -1
- package/dist/main-session-options.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +10 -2
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.js +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.d.ts +8 -0
- package/dist/modes/interactive/components/chat-session-host-state.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-state.js +8 -0
- package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts +26 -0
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +38 -0
- package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
- package/dist/modes/interactive/components/chat-transcript.d.ts +37 -0
- package/dist/modes/interactive/components/chat-transcript.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-transcript.js +54 -1
- package/dist/modes/interactive/components/chat-transcript.js.map +1 -1
- package/dist/modes/interactive/components/fast-mode-selector.js +1 -1
- package/dist/modes/interactive/components/fast-mode-selector.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +2 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +1 -1
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/reserved-bottom-overlay.d.ts +95 -0
- package/dist/modes/interactive/components/reserved-bottom-overlay.d.ts.map +1 -0
- package/dist/modes/interactive/components/reserved-bottom-overlay.js +234 -0
- package/dist/modes/interactive/components/reserved-bottom-overlay.js.map +1 -0
- package/dist/modes/interactive/components/session-selector-search.d.ts +4 -0
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js +4 -0
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-handlers.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-handlers.js +3 -0
- package/dist/modes/interactive/components/settings-selector-handlers.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-items.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-items.js +7 -0
- package/dist/modes/interactive/components/settings-selector-items.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-types.d.ts +3 -1
- package/dist/modes/interactive/components/settings-selector-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector-types.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +12 -1
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-auth-login.js.map +1 -1
- package/dist/modes/interactive/interactive-auth-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-autocomplete.js +5 -4
- package/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
- package/dist/modes/interactive/interactive-bash-compact.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-bash-compact.js +2 -2
- package/dist/modes/interactive/interactive-bash-compact.js.map +1 -1
- package/dist/modes/interactive/interactive-extension-custom-ui.js +94 -6
- package/dist/modes/interactive/interactive-extension-custom-ui.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts +41 -3
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +80 -11
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +9 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-types.d.ts +2 -0
- package/dist/modes/interactive/interactive-mode-types.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-types.js.map +1 -1
- package/dist/modes/interactive/interactive-model-catalog-startup.d.ts +8 -1
- package/dist/modes/interactive/interactive-model-catalog-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-model-catalog-startup.js +13 -3
- package/dist/modes/interactive/interactive-model-catalog-startup.js.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.js +3 -4
- package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.js +6 -0
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/interactive/interactive-resource-disclosure.js +2 -2
- package/dist/modes/interactive/interactive-resource-disclosure.js.map +1 -1
- package/dist/modes/interactive/interactive-selectors.js +7 -3
- package/dist/modes/interactive/interactive-selectors.js.map +1 -1
- package/dist/modes/interactive/interactive-session-runtime.js +7 -1
- package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-slash-commands.js +2 -2
- package/dist/modes/interactive/interactive-slash-commands.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +34 -9
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive/interactive-tui.d.ts +21 -1
- package/dist/modes/interactive/interactive-tui.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-tui.js +140 -38
- package/dist/modes/interactive/interactive-tui.js.map +1 -1
- package/dist/modes/interactive/model-catalog-refresh.d.ts +17 -0
- package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
- package/dist/modes/interactive/model-catalog-refresh.js +84 -0
- package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
- package/dist/modes/interactive/theme/dark.json +2 -0
- package/dist/modes/interactive/theme/light.json +2 -0
- package/dist/modes/interactive/theme/theme-class.d.ts +12 -3
- package/dist/modes/interactive/theme/theme-class.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-class.js +6 -1
- package/dist/modes/interactive/theme/theme-class.js.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-controller.js +23 -10
- package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
- package/dist/modes/interactive/theme/theme-loading.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-loading.js +1 -0
- package/dist/modes/interactive/theme/theme-loading.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.d.ts +8 -0
- package/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.js +3 -1
- package/dist/modes/interactive/theme/theme-schema.js.map +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +9 -1
- package/dist/modes/interactive-engine/engine-custom-ui.d.ts +2 -0
- package/dist/modes/interactive-engine/engine-custom-ui.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-custom-ui.js +1 -0
- package/dist/modes/interactive-engine/engine-custom-ui.js.map +1 -1
- package/dist/modes/interactive-engine/protocol.d.ts +1 -0
- package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
- package/dist/modes/interactive-engine/protocol.js +1 -0
- package/dist/modes/interactive-engine/protocol.js.map +1 -1
- package/dist/modes/interactive-engine/remote-component.d.ts +3 -1
- package/dist/modes/interactive-engine/remote-component.d.ts.map +1 -1
- package/dist/modes/interactive-engine/remote-component.js +3 -2
- package/dist/modes/interactive-engine/remote-component.js.map +1 -1
- package/dist/modes/json-event.d.ts +6 -1
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js +17 -2
- package/dist/modes/json-event.js.map +1 -1
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +5 -4
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
- package/dist/modes/rpc/rpc-responses.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/server/create-harness.d.ts.map +1 -1
- package/dist/server/create-harness.js +11 -0
- package/dist/server/create-harness.js.map +1 -1
- package/dist/utils/abort.d.ts +9 -0
- package/dist/utils/abort.d.ts.map +1 -0
- package/dist/utils/abort.js +19 -0
- package/dist/utils/abort.js.map +1 -0
- package/dist/utils/tools-manager.d.ts +16 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +19 -19
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/custom-provider.md +9 -8
- package/docs/development.md +0 -1
- package/docs/docs.json +0 -1
- package/docs/environment-variables.md +3 -0
- package/docs/extensions.md +100 -2
- package/docs/json.md +3 -1
- package/docs/keybindings.md +8 -3
- package/docs/models/artificial-analysis-index.md +2 -2
- package/docs/models/model-selection.md +32 -23
- package/docs/models/pareto-efficiency.md +25 -24
- package/docs/providers.md +95 -2
- package/docs/quickstart.md +4 -2
- package/docs/rpc.md +21 -7
- package/docs/sdk.md +26 -1
- package/docs/session-format.md +5 -2
- package/docs/settings.md +34 -3
- package/docs/skills.md +16 -1
- package/docs/terminal-setup.md +15 -2
- package/docs/themes.md +22 -4
- package/docs/tools.md +3 -1
- package/docs/tui.md +2 -0
- package/docs/usage.md +5 -4
- package/docs/workflows.md +96 -19
- package/npm-shrinkwrap.json +211 -232
- package/package.json +8 -8
- package/dist/builtin/i-have-adhd/CHANGELOG.md +0 -30
- package/dist/builtin/i-have-adhd/LICENSE +0 -21
- package/dist/builtin/i-have-adhd/README.md +0 -18
- package/dist/builtin/i-have-adhd/index.ts +0 -238
- package/dist/builtin/i-have-adhd/package.json +0 -56
- package/dist/builtin/i-have-adhd/skills/i-have-adhd/SKILL.md +0 -140
- package/dist/builtin/workflows/builtin/open-claude-design-feedback.ts +0 -359
- package/dist/builtin/workflows/skills/impeccable/scripts/live/ui-core.mjs +0 -180
- package/docs/i-have-adhd.md +0 -36
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
|
|
22
22
|
const TOKEN = window.__IMPECCABLE_TOKEN__;
|
|
23
23
|
const PORT = window.__IMPECCABLE_PORT__;
|
|
24
|
+
const APP_ROOT = window.__IMPECCABLE_APP_ROOT__ || null;
|
|
24
25
|
if (!TOKEN || !PORT) {
|
|
25
26
|
window.__IMPECCABLE_LIVE_INIT__ = false; // reset so the real load can init
|
|
26
27
|
return;
|
|
@@ -96,23 +97,20 @@
|
|
|
96
97
|
return { value: c.value, label: c.label };
|
|
97
98
|
});
|
|
98
99
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
{ key: 'toasts-and-errors', ids: [PREFIX + '-toast'] },
|
|
114
|
-
{ key: 'css-isolation-boundary', ids: [PREFIX + '-root'] },
|
|
115
|
-
];
|
|
100
|
+
// The Live chrome inventory (which surfaces exist, and the element ids each
|
|
101
|
+
// one owns) comes from the canonical source, skill/scripts/live/ui-surfaces.mjs,
|
|
102
|
+
// which the /live.js assembler serializes into these globals alongside the
|
|
103
|
+
// token/port/vocabulary. This file is served raw and injected as a classic
|
|
104
|
+
// script, so it cannot import that module; the private impeccable-site repo
|
|
105
|
+
// imports it directly to check its Live UI lab holds a snapshot for every
|
|
106
|
+
// surface, which only works while the list has exactly one definition.
|
|
107
|
+
// Add a surface in ui-surfaces.mjs, not here.
|
|
108
|
+
const LIVE_CHROME_MOUNT_CONTRACT = Array.isArray(window.__IMPECCABLE_LIVE_MOUNT_CONTRACT__)
|
|
109
|
+
? window.__IMPECCABLE_LIVE_MOUNT_CONTRACT__
|
|
110
|
+
: ['root', 'transport', 'state', 'actions'];
|
|
111
|
+
const LIVE_UI_SURFACES = Array.isArray(window.__IMPECCABLE_LIVE_UI_SURFACES__)
|
|
112
|
+
? window.__IMPECCABLE_LIVE_UI_SURFACES__
|
|
113
|
+
: [];
|
|
116
114
|
const LIVE_UI_COMPONENT_IDS = [...new Set(LIVE_UI_SURFACES.flatMap((surface) => surface.ids))];
|
|
117
115
|
|
|
118
116
|
//
|
|
@@ -131,8 +129,14 @@
|
|
|
131
129
|
// must never regress: a `browser_resumed`/behind checkpoint re-broadcasts an
|
|
132
130
|
// earlier phase (the server regresses the snapshot phase to `generating` on a
|
|
133
131
|
// behind checkpoint), and without this the bar jumps backward mid-generation.
|
|
134
|
-
// Unranked phases
|
|
135
|
-
//
|
|
132
|
+
// Unranked phases always pass so we never block a phase we do not model.
|
|
133
|
+
//
|
|
134
|
+
// Every `agent_phase` name here is emitted by recordAgentPhase() in
|
|
135
|
+
// live-server.mjs and listed in AGENT_PHASES in live/vocabulary.mjs, which the
|
|
136
|
+
// event validator enforces. This file is served raw and injected as an IIFE,
|
|
137
|
+
// so it cannot import that list; adding a phase means adding it in both.
|
|
138
|
+
// `queued`, `generating`, `variants_progress`, and `variants_ready` are set
|
|
139
|
+
// locally by this file and never arrive over the wire.
|
|
136
140
|
const PHASE_RANK = {
|
|
137
141
|
queued: 0,
|
|
138
142
|
picked_up: 1,
|
|
@@ -142,17 +146,10 @@
|
|
|
142
146
|
generation_ready: 5,
|
|
143
147
|
generating: 5,
|
|
144
148
|
variants_progress: 5,
|
|
145
|
-
first_variant_generating: 6,
|
|
146
|
-
first_variant_validating: 7,
|
|
147
149
|
first_reviewable: 8,
|
|
148
|
-
remaining_variants_generating: 9,
|
|
149
|
-
remaining_variants_validating: 10,
|
|
150
150
|
second_reviewable: 11,
|
|
151
151
|
all_variants_ready: 12,
|
|
152
152
|
variants_ready: 12,
|
|
153
|
-
variant_parameters_generating: 13,
|
|
154
|
-
variant_parameters_validating: 14,
|
|
155
|
-
parameters_ready: 15,
|
|
156
153
|
};
|
|
157
154
|
function shouldAdvancePhase(current, next) {
|
|
158
155
|
if (!next || next === current) return false;
|
|
@@ -167,6 +164,13 @@
|
|
|
167
164
|
let svelteComponentSession = null;
|
|
168
165
|
let svelteRuntimePromise = null;
|
|
169
166
|
let pendingSvelteComponentRetryObserver = null;
|
|
167
|
+
// The persistent mount-error card. A failed import/mount used to wipe local
|
|
168
|
+
// session state and flash a 5s toast, which destroyed the only handle the
|
|
169
|
+
// user had on a session the server still considered live. The card stays up
|
|
170
|
+
// until the variant mounts, the user retries, or a new cycle starts.
|
|
171
|
+
let mountErrorEl = null;
|
|
172
|
+
let mountErrorState = null;
|
|
173
|
+
let lastReportedMountFailure = null;
|
|
170
174
|
let currentSourceFile = null;
|
|
171
175
|
let currentPreviewFile = null;
|
|
172
176
|
let currentPreviewMode = null;
|
|
@@ -2025,6 +2029,9 @@
|
|
|
2025
2029
|
state = next;
|
|
2026
2030
|
window.__IMPECCABLE_LIVE_STATE__ = next;
|
|
2027
2031
|
syncPageInteractionCursor();
|
|
2032
|
+
// Whether a queued steer is still behind a generation is a function of this
|
|
2033
|
+
// state, so the hint has to move with it, not only with the 5s poll.
|
|
2034
|
+
syncSteerQueueHint();
|
|
2028
2035
|
}
|
|
2029
2036
|
|
|
2030
2037
|
/** Element used to position the floating bar / shader during a session. */
|
|
@@ -2588,10 +2595,8 @@
|
|
|
2588
2595
|
if (generationPhase === 'scaffolding') return 'Finding the source...';
|
|
2589
2596
|
if (generationPhase === 'source_ready') return 'Source ready. Generating...';
|
|
2590
2597
|
if (generationPhase === 'scaffold_fallback') return 'Agent is locating the source...';
|
|
2591
|
-
if (generationPhase === '
|
|
2592
|
-
if (generationPhase === '
|
|
2593
|
-
if (generationPhase === 'remaining_variants_generating') return 'Exploring two more directions...';
|
|
2594
|
-
if (generationPhase === 'remaining_variants_validating') return 'Checking the remaining variants...';
|
|
2598
|
+
if (generationPhase === 'first_reviewable') return 'First variant is ready. Exploring more...';
|
|
2599
|
+
if (generationPhase === 'second_reviewable') return 'Checking the remaining variants...';
|
|
2595
2600
|
return 'Generating ' + expectedVariants + ' variants...';
|
|
2596
2601
|
}
|
|
2597
2602
|
|
|
@@ -2599,6 +2604,30 @@
|
|
|
2599
2604
|
|
|
2600
2605
|
const TUNE_ICON_SVG = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" style="flex-shrink:0"><line x1="4" y1="8" x2="20" y2="8"/><circle cx="14" cy="8" r="2.4" fill="currentColor" stroke="none"/><line x1="4" y1="16" x2="20" y2="16"/><circle cx="10" cy="16" r="2.4" fill="currentColor" stroke="none"/></svg>';
|
|
2601
2606
|
|
|
2607
|
+
/**
|
|
2608
|
+
* Which variant the user is actually looking at. For component previews the
|
|
2609
|
+
* mounted component is the truth; `visibleVariant` is the intent, and the two
|
|
2610
|
+
* differ while a mount is in flight.
|
|
2611
|
+
*/
|
|
2612
|
+
function cyclingShownVariant() {
|
|
2613
|
+
return svelteComponentSession?.sessionId === currentSessionId && svelteComponentSession.mountedVariant > 0
|
|
2614
|
+
? svelteComponentSession.mountedVariant
|
|
2615
|
+
: visibleVariant;
|
|
2616
|
+
}
|
|
2617
|
+
|
|
2618
|
+
/**
|
|
2619
|
+
* The single counter string. It is built here rather than at each call site
|
|
2620
|
+
* because the row builder and the incremental sync used to disagree on the
|
|
2621
|
+
* denominator: one showed the planned count, the other the arrived count, so
|
|
2622
|
+
* "2/3" turned into "2/2" on the next sync without anything changing on
|
|
2623
|
+
* screen. Arrived wins once anything has arrived; expected covers the window
|
|
2624
|
+
* before the first variant lands.
|
|
2625
|
+
*/
|
|
2626
|
+
function cyclingCounterText() {
|
|
2627
|
+
const total = arrivedVariants > 0 ? arrivedVariants : expectedVariants;
|
|
2628
|
+
return cyclingShownVariant() + '/' + total;
|
|
2629
|
+
}
|
|
2630
|
+
|
|
2602
2631
|
function buildCyclingRow() {
|
|
2603
2632
|
if (!ensureCyclingRenderable('build-cycling-row')) {
|
|
2604
2633
|
return el('div', { display: 'none' });
|
|
@@ -2612,7 +2641,7 @@
|
|
|
2612
2641
|
const prev = navBtn('\u2190');
|
|
2613
2642
|
prev.id = PREFIX + '-variant-prev';
|
|
2614
2643
|
prev.addEventListener('click', (e) => { e.stopPropagation(); cycleVariant(-1); });
|
|
2615
|
-
if (
|
|
2644
|
+
if (cyclingShownVariant() <= 1) prev.style.opacity = '0.3';
|
|
2616
2645
|
row.appendChild(prev);
|
|
2617
2646
|
|
|
2618
2647
|
// Dots (clickable)
|
|
@@ -2624,14 +2653,14 @@
|
|
|
2624
2653
|
color: BP.textDim, minWidth: '24px', textAlign: 'center',
|
|
2625
2654
|
});
|
|
2626
2655
|
counter.id = PREFIX + '-variant-counter';
|
|
2627
|
-
counter.textContent =
|
|
2656
|
+
counter.textContent = cyclingCounterText();
|
|
2628
2657
|
row.appendChild(counter);
|
|
2629
2658
|
|
|
2630
2659
|
// Next
|
|
2631
2660
|
const next = navBtn('\u2192');
|
|
2632
2661
|
next.id = PREFIX + '-variant-next';
|
|
2633
2662
|
next.addEventListener('click', (e) => { e.stopPropagation(); cycleVariant(1); });
|
|
2634
|
-
if (
|
|
2663
|
+
if (cyclingShownVariant() >= arrivedVariants) next.style.opacity = '0.3';
|
|
2635
2664
|
row.appendChild(next);
|
|
2636
2665
|
|
|
2637
2666
|
// Tune chip stays visible while the deferred parameter phase is running,
|
|
@@ -2996,7 +3025,7 @@
|
|
|
2996
3025
|
console.warn('[impeccable] Refusing to render empty variant cycling state:', reason);
|
|
2997
3026
|
const message = 'No variants were mounted. Please try again.';
|
|
2998
3027
|
if (svelteComponentSession?.sessionId === currentSessionId) {
|
|
2999
|
-
|
|
3028
|
+
resetSvelteComponentSession(currentSessionId, message);
|
|
3000
3029
|
return;
|
|
3001
3030
|
}
|
|
3002
3031
|
cleanup();
|
|
@@ -3734,7 +3763,10 @@
|
|
|
3734
3763
|
const container = copyEditContainerContext(contextElement);
|
|
3735
3764
|
if (container) for (const op of ops) op.container = container;
|
|
3736
3765
|
try {
|
|
3737
|
-
|
|
3766
|
+
// Token in the query string as well as the body: the URL token is what
|
|
3767
|
+
// authorizes the CORS preflight when the page runs on a non-loopback
|
|
3768
|
+
// dev host (ddev, Valet), since the preflight carries no request body.
|
|
3769
|
+
const res = await fetch('http://localhost:' + PORT + '/manual-edit-stash?token=' + encodeURIComponent(TOKEN), {
|
|
3738
3770
|
method: 'POST',
|
|
3739
3771
|
headers: { 'Content-Type': 'application/json' },
|
|
3740
3772
|
body: JSON.stringify({
|
|
@@ -4926,11 +4958,9 @@
|
|
|
4926
4958
|
}
|
|
4927
4959
|
|
|
4928
4960
|
function syncCyclingControls() {
|
|
4929
|
-
const shown =
|
|
4930
|
-
? svelteComponentSession.mountedVariant
|
|
4931
|
-
: visibleVariant;
|
|
4961
|
+
const shown = cyclingShownVariant();
|
|
4932
4962
|
const counter = uiGetById(PREFIX + '-variant-counter');
|
|
4933
|
-
if (counter
|
|
4963
|
+
if (counter) counter.textContent = cyclingCounterText();
|
|
4934
4964
|
const prev = uiGetById(PREFIX + '-variant-prev');
|
|
4935
4965
|
const next = uiGetById(PREFIX + '-variant-next');
|
|
4936
4966
|
if (prev) prev.style.opacity = shown <= 1 ? '0.3' : '1';
|
|
@@ -5160,15 +5190,74 @@
|
|
|
5160
5190
|
}
|
|
5161
5191
|
}
|
|
5162
5192
|
|
|
5163
|
-
|
|
5164
|
-
|
|
5193
|
+
// The dev server may serve under a non-root base (vite `base`) or a root
|
|
5194
|
+
// that differs from where the helper wrote the preview tree. Root-relative
|
|
5195
|
+
// URLs are tried against the detected base first; the /@fs/ absolute form
|
|
5196
|
+
// is the fallback that works regardless of base and root, as long as the
|
|
5197
|
+
// path is inside the server's fs.allow.
|
|
5198
|
+
let detectedDevBase = null;
|
|
5199
|
+
function detectDevServerBase() {
|
|
5200
|
+
if (detectedDevBase !== null) return detectedDevBase;
|
|
5201
|
+
detectedDevBase = '/';
|
|
5202
|
+
const scripts = document.querySelectorAll('script[type="module"][src]');
|
|
5203
|
+
for (const script of scripts) {
|
|
5204
|
+
const src = script.getAttribute('src') || '';
|
|
5205
|
+
const idx = src.indexOf('/@vite/client');
|
|
5206
|
+
if (idx > 0) { detectedDevBase = src.slice(0, idx) + '/'; break; }
|
|
5207
|
+
if (idx === 0) { detectedDevBase = '/'; break; }
|
|
5208
|
+
}
|
|
5209
|
+
return detectedDevBase;
|
|
5210
|
+
}
|
|
5211
|
+
|
|
5212
|
+
function componentModuleCandidates(manifest, modulePath, absPath) {
|
|
5213
|
+
const base = detectDevServerBase();
|
|
5214
|
+
const rel = String(modulePath || '').replace(/^\/+/, '');
|
|
5215
|
+
const candidates = [new URL(base + rel, location.origin).href];
|
|
5216
|
+
if (base !== '/') candidates.push(new URL('/' + rel, location.origin).href);
|
|
5217
|
+
if (absPath) {
|
|
5218
|
+
const fsRel = '@fs/' + String(absPath).replace(/^\/+/, '');
|
|
5219
|
+
candidates.push(new URL(base + fsRel, location.origin).href);
|
|
5220
|
+
// Vite versions differ on whether @fs is served under base or at the
|
|
5221
|
+
// server root; with a non-root base, try both.
|
|
5222
|
+
if (base !== '/') candidates.push(new URL('/' + fsRel, location.origin).href);
|
|
5223
|
+
}
|
|
5224
|
+
return candidates;
|
|
5225
|
+
}
|
|
5226
|
+
|
|
5227
|
+
async function importFirstReachable(candidates, bust) {
|
|
5228
|
+
let lastErr = null;
|
|
5229
|
+
for (const candidate of candidates) {
|
|
5230
|
+
try {
|
|
5231
|
+
const url = bust ? candidate + (candidate.includes('?') ? '&' : '?') + 't=' + Date.now() : candidate;
|
|
5232
|
+
const mod = await import(/* @vite-ignore */ url);
|
|
5233
|
+
return { mod, url: candidate };
|
|
5234
|
+
} catch (err) {
|
|
5235
|
+
lastErr = err;
|
|
5236
|
+
}
|
|
5237
|
+
}
|
|
5238
|
+
throw Object.assign(lastErr || new Error('no module candidates'), {
|
|
5239
|
+
impeccableTriedUrls: candidates,
|
|
5240
|
+
});
|
|
5241
|
+
}
|
|
5242
|
+
|
|
5243
|
+
// Distinguishes "this variant is broken" from "the preview tree is not
|
|
5244
|
+
// reachable from the dev server at all" (wrong root, unserved directory).
|
|
5245
|
+
async function probePreviewTree(manifest) {
|
|
5246
|
+
if (!manifest?.probeModule) return { ok: true, skipped: true };
|
|
5247
|
+
const candidates = componentModuleCandidates(manifest, manifest.probeModule, manifest.probeModuleAbs);
|
|
5248
|
+
try {
|
|
5249
|
+
await importFirstReachable(candidates, false);
|
|
5250
|
+
return { ok: true };
|
|
5251
|
+
} catch (err) {
|
|
5252
|
+
return { ok: false, tried: err.impeccableTriedUrls || candidates };
|
|
5253
|
+
}
|
|
5165
5254
|
}
|
|
5166
5255
|
|
|
5167
5256
|
function loadSvelteRuntime(runtimeModule, manifest) {
|
|
5168
5257
|
const modulePath = runtimeModule || '/src/lib/impeccable/__runtime.js';
|
|
5169
|
-
const url = resolveComponentModuleUrl(manifest, modulePath);
|
|
5170
5258
|
if (!svelteRuntimePromise) {
|
|
5171
|
-
|
|
5259
|
+
const candidates = componentModuleCandidates(manifest, modulePath, manifest?.runtimeModuleAbs);
|
|
5260
|
+
svelteRuntimePromise = importFirstReachable(candidates, false).then((r) => r.mod);
|
|
5172
5261
|
}
|
|
5173
5262
|
return svelteRuntimePromise;
|
|
5174
5263
|
}
|
|
@@ -5178,7 +5267,7 @@
|
|
|
5178
5267
|
// attribute with JSON braces can't survive the Svelte compiler. Returns a map of
|
|
5179
5268
|
// { "1": [...params], "2": [...] }; an empty object when the agent declared none.
|
|
5180
5269
|
async function loadSvelteComponentParams(manifest) {
|
|
5181
|
-
const dir = String(manifest?.componentDir || '').replace(/^\/+/, '');
|
|
5270
|
+
const dir = String(manifest?.revisionDir || manifest?.componentDir || '').replace(/^\/+/, '');
|
|
5182
5271
|
if (!dir) return {};
|
|
5183
5272
|
const paramsPath = dir + '/params.json';
|
|
5184
5273
|
const url = 'http://localhost:' + PORT + '/source?token=' + TOKEN + '&path=' + encodeURIComponent(paramsPath);
|
|
@@ -5197,42 +5286,14 @@
|
|
|
5197
5286
|
}
|
|
5198
5287
|
}
|
|
5199
5288
|
|
|
5200
|
-
async function loadSvelteComponentVariantSource(manifest, variantNum) {
|
|
5201
|
-
const dir = String(manifest?.componentDir || '').replace(/^\/+/, '');
|
|
5202
|
-
if (!dir || !variantNum) return '';
|
|
5203
|
-
const extension = manifest.componentExtension || 'svelte';
|
|
5204
|
-
const sourcePath = dir + '/v' + variantNum + '.' + extension;
|
|
5205
|
-
const url = 'http://localhost:' + PORT + '/source?token=' + TOKEN + '&path=' + encodeURIComponent(sourcePath);
|
|
5206
|
-
try {
|
|
5207
|
-
const res = await fetch(url);
|
|
5208
|
-
if (!res.ok) return '';
|
|
5209
|
-
return await res.text();
|
|
5210
|
-
} catch {
|
|
5211
|
-
return '';
|
|
5212
|
-
}
|
|
5213
|
-
}
|
|
5214
5289
|
|
|
5215
|
-
function extractSvelteComponentStyle(source) {
|
|
5216
|
-
const match = String(source || '').match(/<style\b[^>]*>([\s\S]*?)<\/style\s*>/i);
|
|
5217
|
-
return match ? match[1].trim() : '';
|
|
5218
|
-
}
|
|
5219
5290
|
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
if (!css) return;
|
|
5227
|
-
const scopedCss = scopeCssToSveltePreview(css, sessionId);
|
|
5228
|
-
if (!scopedCss) return;
|
|
5229
|
-
const style = document.createElement('style');
|
|
5230
|
-
style.dataset.impeccableSvelteComponentStyle = sessionId;
|
|
5231
|
-
style.dataset.impeccableVariant = String(variantNum);
|
|
5232
|
-
style.textContent = scopedCss;
|
|
5233
|
-
document.head.appendChild(style);
|
|
5234
|
-
svelteComponentSession.styleEl = style;
|
|
5235
|
-
}
|
|
5291
|
+
// NOTE: the compiled component imported from the dev server already carries
|
|
5292
|
+
// its own scoped styles (vite-plugin-svelte injects them on module
|
|
5293
|
+
// evaluation). The old second injection re-fetched the raw source through
|
|
5294
|
+
// the helper and re-prefixed every selector un-hashed, so the same rules
|
|
5295
|
+
// applied twice with different specificity: preview and accepted cascades
|
|
5296
|
+
// disagreed. The single compiled copy is the truth now.
|
|
5236
5297
|
|
|
5237
5298
|
function removeSvelteComponentVariantStyle(session = svelteComponentSession) {
|
|
5238
5299
|
const style = session?.styleEl;
|
|
@@ -5353,6 +5414,9 @@
|
|
|
5353
5414
|
const contract = manifest?.propContract || [];
|
|
5354
5415
|
const values = {};
|
|
5355
5416
|
if (!liveEl || contract.length === 0) return values;
|
|
5417
|
+
if (Number(manifest.contractVersion) === 2) {
|
|
5418
|
+
return buildSveltePropValuesV2(liveEl, manifest);
|
|
5419
|
+
}
|
|
5356
5420
|
const sourceOriginal = parseOriginalMarkupElement(manifest.originalMarkup || '');
|
|
5357
5421
|
if (!sourceOriginal) return values;
|
|
5358
5422
|
const map = buildSvelteExpressionTextMap(sourceOriginal, liveEl);
|
|
@@ -5363,19 +5427,199 @@
|
|
|
5363
5427
|
return values;
|
|
5364
5428
|
}
|
|
5365
5429
|
|
|
5430
|
+
// Contract v2 hydration. The scaffolder preserved control flow, so props
|
|
5431
|
+
// come in kinds: `collection` hydrates from the live DOM's rendered items
|
|
5432
|
+
// (count by the item root selector, texts by slot order), `condition` from
|
|
5433
|
+
// whether the branch's probe element is currently rendered, `text` from the
|
|
5434
|
+
// v1 index-zip run over the markup WITH control-flow regions stripped and
|
|
5435
|
+
// the live tree WITH item elements excluded, so loop tokens can never shift
|
|
5436
|
+
// slots again. `handler` props keep their no-op defaults.
|
|
5437
|
+
function buildSveltePropValuesV2(liveEl, manifest) {
|
|
5438
|
+
const contract = manifest.propContract || [];
|
|
5439
|
+
const values = {};
|
|
5440
|
+
const itemElsByProp = new Map();
|
|
5441
|
+
|
|
5442
|
+
for (const entry of contract) {
|
|
5443
|
+
if (entry.kind === 'collection' && entry.item && entry.item.rootTag) {
|
|
5444
|
+
const selector = entry.item.rootTag + (entry.item.rootClasses || []).map((c) => '.' + cssEscapeIdent(c)).join('');
|
|
5445
|
+
let matches = [];
|
|
5446
|
+
try { matches = Array.from(liveEl.querySelectorAll(selector)); } catch { matches = []; }
|
|
5447
|
+
itemElsByProp.set(entry.prop, matches);
|
|
5448
|
+
const statics = new Set((entry.item.staticTexts || []).map((t) => String(t).trim()));
|
|
5449
|
+
const slots = entry.item.textSlots || [];
|
|
5450
|
+
values[entry.prop] = matches.map((itemEl, index) => {
|
|
5451
|
+
const texts = collectVisibleTexts(itemEl).filter((t) => !statics.has(t));
|
|
5452
|
+
const item = {};
|
|
5453
|
+
slots.forEach((slot, i) => { item[slot.key] = texts[i] != null ? texts[i] : ''; });
|
|
5454
|
+
// Attribute-bound values (href={link.href}) hydrate from the
|
|
5455
|
+
// rendered attribute on the live item element or a descendant.
|
|
5456
|
+
for (const slot of entry.item.attrSlots || []) {
|
|
5457
|
+
if (item[slot.key] != null || !slot.tag) continue;
|
|
5458
|
+
const sel = slot.tag + (slot.classes || []).map((c) => '.' + cssEscapeIdent(c)).join('');
|
|
5459
|
+
let el = null;
|
|
5460
|
+
try { el = itemEl.matches(sel) ? itemEl : itemEl.querySelector(sel); } catch { el = null; }
|
|
5461
|
+
const value = el ? el.getAttribute(slot.attr) : null;
|
|
5462
|
+
if (value != null) item[slot.key] = value;
|
|
5463
|
+
}
|
|
5464
|
+
// Keyed each: the key field is never rendered, so hydrate it with a
|
|
5465
|
+
// unique per-index value or Svelte throws each_key_duplicate.
|
|
5466
|
+
if (entry.item.keyField && item[entry.item.keyField] == null) {
|
|
5467
|
+
item[entry.item.keyField] = 'impeccable-live-' + index;
|
|
5468
|
+
}
|
|
5469
|
+
return item;
|
|
5470
|
+
});
|
|
5471
|
+
} else if (entry.kind === 'condition') {
|
|
5472
|
+
if (entry.probe && entry.probe.tag) {
|
|
5473
|
+
const selector = entry.probe.tag + (entry.probe.classes || []).map((c) => '.' + cssEscapeIdent(c)).join('');
|
|
5474
|
+
try { values[entry.prop] = !!liveEl.querySelector(selector); } catch { /* keep default */ }
|
|
5475
|
+
} else if (entry.probe && entry.probe.className) {
|
|
5476
|
+
// class:name directive: the live DOM answers directly, either on
|
|
5477
|
+
// the picked element itself or on a descendant carrying the class.
|
|
5478
|
+
try {
|
|
5479
|
+
values[entry.prop] = liveEl.classList.contains(entry.probe.className)
|
|
5480
|
+
|| !!liveEl.querySelector('.' + cssEscapeIdent(entry.probe.className));
|
|
5481
|
+
} catch { /* keep default */ }
|
|
5482
|
+
}
|
|
5483
|
+
}
|
|
5484
|
+
}
|
|
5485
|
+
|
|
5486
|
+
// Text props outside control flow: strip block regions from the source
|
|
5487
|
+
// markup, exclude live text nodes inside any hydrated item element, then
|
|
5488
|
+
// run the existing zip.
|
|
5489
|
+
const textEntries = contract.filter((e) => e.kind === 'text' || e.kind === 'raw');
|
|
5490
|
+
if (textEntries.length > 0) {
|
|
5491
|
+
const strippedMarkup = stripSvelteBlockRegions(manifest.originalMarkup || '');
|
|
5492
|
+
const sourceOriginal = parseOriginalMarkupElement(strippedMarkup);
|
|
5493
|
+
if (sourceOriginal) {
|
|
5494
|
+
const excluded = [];
|
|
5495
|
+
for (const els of itemElsByProp.values()) excluded.push(...els);
|
|
5496
|
+
const filteredLive = cloneWithoutElements(liveEl, excluded);
|
|
5497
|
+
const map = buildSvelteExpressionTextMap(sourceOriginal, filteredLive);
|
|
5498
|
+
for (const entry of textEntries) {
|
|
5499
|
+
const token = '{' + entry.expr + '}';
|
|
5500
|
+
if (map.has(token)) values[entry.prop] = map.get(token) || '';
|
|
5501
|
+
}
|
|
5502
|
+
}
|
|
5503
|
+
}
|
|
5504
|
+
return values;
|
|
5505
|
+
}
|
|
5506
|
+
|
|
5507
|
+
function cssEscapeIdent(value) {
|
|
5508
|
+
try { return CSS.escape(value); } catch { return String(value).replace(/[^a-zA-Z0-9_-]/g, ''); }
|
|
5509
|
+
}
|
|
5510
|
+
|
|
5511
|
+
function collectVisibleTexts(rootEl) {
|
|
5512
|
+
const texts = [];
|
|
5513
|
+
const walker = document.createTreeWalker(rootEl, NodeFilter.SHOW_TEXT);
|
|
5514
|
+
let node;
|
|
5515
|
+
while ((node = walker.nextNode())) {
|
|
5516
|
+
const trimmed = String(node.textContent || '').trim();
|
|
5517
|
+
if (trimmed) texts.push(trimmed);
|
|
5518
|
+
}
|
|
5519
|
+
return texts;
|
|
5520
|
+
}
|
|
5521
|
+
|
|
5522
|
+
// Remove balanced {#each}...{/each} and {#if}...{/if} regions (including
|
|
5523
|
+
// the delimiters) from a markup string. Nesting-aware. {#key} blocks keep
|
|
5524
|
+
// their CONTENT (it always renders) but lose their delimiter tokens, which
|
|
5525
|
+
// would otherwise consume live text slots in the zip and shift every
|
|
5526
|
+
// following expression.
|
|
5527
|
+
function stripSvelteBlockRegions(markup) {
|
|
5528
|
+
let out = String(markup || '');
|
|
5529
|
+
out = stripSvelteKeyDelimiters(out);
|
|
5530
|
+
for (const kind of ['each', 'if']) {
|
|
5531
|
+
const open = '{#' + kind;
|
|
5532
|
+
const close = '{/' + kind + '}';
|
|
5533
|
+
for (;;) {
|
|
5534
|
+
const start = out.indexOf(open);
|
|
5535
|
+
if (start === -1) break;
|
|
5536
|
+
let depth = 0;
|
|
5537
|
+
let i = start;
|
|
5538
|
+
let end = -1;
|
|
5539
|
+
while (i < out.length) {
|
|
5540
|
+
if (out.startsWith(open, i)) { depth++; i += open.length; continue; }
|
|
5541
|
+
if (out.startsWith(close, i)) {
|
|
5542
|
+
depth--;
|
|
5543
|
+
i += close.length;
|
|
5544
|
+
if (depth === 0) { end = i; break; }
|
|
5545
|
+
continue;
|
|
5546
|
+
}
|
|
5547
|
+
i++;
|
|
5548
|
+
}
|
|
5549
|
+
if (end === -1) break;
|
|
5550
|
+
out = out.slice(0, start) + out.slice(end);
|
|
5551
|
+
}
|
|
5552
|
+
}
|
|
5553
|
+
return out;
|
|
5554
|
+
}
|
|
5555
|
+
|
|
5556
|
+
function stripSvelteKeyDelimiters(markup) {
|
|
5557
|
+
let out = String(markup || '');
|
|
5558
|
+
for (;;) {
|
|
5559
|
+
const start = out.indexOf('{#key');
|
|
5560
|
+
if (start === -1) break;
|
|
5561
|
+
// The opening tag runs to its matching close brace (expressions inside
|
|
5562
|
+
// may nest braces).
|
|
5563
|
+
let depth = 0;
|
|
5564
|
+
let i = start;
|
|
5565
|
+
let openEnd = -1;
|
|
5566
|
+
while (i < out.length) {
|
|
5567
|
+
if (out[i] === '{') depth++;
|
|
5568
|
+
else if (out[i] === '}') {
|
|
5569
|
+
depth--;
|
|
5570
|
+
if (depth === 0) { openEnd = i + 1; break; }
|
|
5571
|
+
}
|
|
5572
|
+
i++;
|
|
5573
|
+
}
|
|
5574
|
+
if (openEnd === -1) break;
|
|
5575
|
+
out = out.slice(0, start) + out.slice(openEnd);
|
|
5576
|
+
}
|
|
5577
|
+
return out.split('{/key}').join('');
|
|
5578
|
+
}
|
|
5579
|
+
|
|
5580
|
+
function cloneWithoutElements(rootEl, excludedEls) {
|
|
5581
|
+
if (!excludedEls || excludedEls.length === 0) return rootEl;
|
|
5582
|
+
const excludedSet = new Set(excludedEls);
|
|
5583
|
+
// Mark originals, clone, then strip marked clones: identity does not
|
|
5584
|
+
// survive cloneNode, attributes do.
|
|
5585
|
+
const MARK = 'data-impeccable-hydration-excluded';
|
|
5586
|
+
for (const el of excludedSet) { try { el.setAttribute(MARK, '1'); } catch { /* detached */ } }
|
|
5587
|
+
let clone;
|
|
5588
|
+
try {
|
|
5589
|
+
clone = rootEl.cloneNode(true);
|
|
5590
|
+
clone.querySelectorAll('[' + MARK + ']').forEach((el) => el.remove());
|
|
5591
|
+
} finally {
|
|
5592
|
+
for (const el of excludedSet) { try { el.removeAttribute(MARK); } catch { /* detached */ } }
|
|
5593
|
+
}
|
|
5594
|
+
return clone || rootEl;
|
|
5595
|
+
}
|
|
5596
|
+
|
|
5366
5597
|
async function mountSvelteComponentVariant(variantNum) {
|
|
5367
5598
|
if (!svelteComponentSession || !variantNum) return false;
|
|
5368
5599
|
const { manifest, mountTargetEl, sessionId } = svelteComponentSession;
|
|
5600
|
+
// Resolved before the first await so the failure report can name the module
|
|
5601
|
+
// the browser could not reach, whichever step threw.
|
|
5602
|
+
const extension = manifest.componentExtension || 'svelte';
|
|
5603
|
+
// Prefer the server-stamped revision dir: its path changes on every
|
|
5604
|
+
// publish, which is what defeats stale transform caches for files the
|
|
5605
|
+
// dev server does not watch.
|
|
5606
|
+
const dirRel = manifest.revisionDir || manifest.componentDir || '';
|
|
5607
|
+
const dirAbs = manifest.revisionDirAbs || manifest.componentDirAbs || null;
|
|
5608
|
+
const moduleBase = manifest.componentModuleBase
|
|
5609
|
+
|| ('/' + String(dirRel).replace(/^\/+/, ''));
|
|
5610
|
+
const modulePath = String(moduleBase).replace(/\/+$/, '') + '/v' + variantNum + '.' + extension;
|
|
5611
|
+
const moduleAbs = dirAbs
|
|
5612
|
+
? String(dirAbs).replace(/\/+$/, '') + '/v' + variantNum + '.' + extension
|
|
5613
|
+
: null;
|
|
5614
|
+
const candidates = componentModuleCandidates(manifest, modulePath, moduleAbs);
|
|
5615
|
+
let moduleUrl = candidates[0];
|
|
5369
5616
|
try {
|
|
5370
5617
|
const previousAnchor = getMountedSvelteComponentAnchor(svelteComponentSession) || selectedElement;
|
|
5371
5618
|
svelteComponentSession.swapAnchor = makeFrozenAnchor(previousAnchor) || svelteComponentSession.swapAnchor || null;
|
|
5372
5619
|
const runtime = await loadSvelteRuntime(manifest.runtimeModule, manifest);
|
|
5373
|
-
const
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
const modulePath = String(moduleBase).replace(/\/+$/, '') + '/v' + variantNum + '.' + extension;
|
|
5377
|
-
const moduleUrl = resolveComponentModuleUrl(manifest, modulePath) + '?t=' + Date.now();
|
|
5378
|
-
const mod = await import(/* @vite-ignore */ moduleUrl);
|
|
5620
|
+
const imported = await importFirstReachable(candidates, true);
|
|
5621
|
+
moduleUrl = imported.url;
|
|
5622
|
+
const mod = imported.mod;
|
|
5379
5623
|
const Component = mod.default;
|
|
5380
5624
|
if (svelteComponentSession.mountedInstance && runtime.unmount) {
|
|
5381
5625
|
await runtime.unmount(svelteComponentSession.mountedInstance);
|
|
@@ -5388,7 +5632,7 @@
|
|
|
5388
5632
|
});
|
|
5389
5633
|
svelteComponentSession.mountedVariant = variantNum;
|
|
5390
5634
|
svelteComponentSession.runtime = runtime;
|
|
5391
|
-
|
|
5635
|
+
removeSvelteComponentVariantStyle(svelteComponentSession);
|
|
5392
5636
|
if (state === 'CYCLING') syncCyclingControls();
|
|
5393
5637
|
const nextAnchor = getMountedSvelteComponentAnchor(svelteComponentSession);
|
|
5394
5638
|
if (nextAnchor) {
|
|
@@ -5409,16 +5653,44 @@
|
|
|
5409
5653
|
selectedElement = settledAnchor;
|
|
5410
5654
|
});
|
|
5411
5655
|
}
|
|
5656
|
+
// Render truth, not publish truth: this is the only point in the whole
|
|
5657
|
+
// pipeline that proves the user can see variant N.
|
|
5658
|
+
reportVariantMounted(sessionId, variantNum, moduleUrl);
|
|
5659
|
+
if (mountErrorState?.sessionId === sessionId && mountErrorState.variant === variantNum) {
|
|
5660
|
+
clearMountErrorCard();
|
|
5661
|
+
}
|
|
5412
5662
|
return true;
|
|
5413
5663
|
} catch (err) {
|
|
5414
5664
|
if (svelteComponentSession?.sessionId === sessionId) {
|
|
5415
5665
|
svelteComponentSession.swapAnchor = null;
|
|
5416
5666
|
}
|
|
5417
5667
|
console.error('[impeccable] Failed to mount component variant ' + variantNum + ' for ' + sessionId + ':', err);
|
|
5668
|
+
reportVariantMountFailed(sessionId, variantNum, moduleUrl, err);
|
|
5669
|
+
// Every mount failure gets the card, so the variant-switch path (which
|
|
5670
|
+
// used to revert with no feedback whatsoever) says what broke too.
|
|
5671
|
+
showMountErrorCard(sessionId, {
|
|
5672
|
+
variant: variantNum,
|
|
5673
|
+
url: moduleUrl,
|
|
5674
|
+
message: await describeMountFailure(manifest, err),
|
|
5675
|
+
});
|
|
5418
5676
|
return false;
|
|
5419
5677
|
}
|
|
5420
5678
|
}
|
|
5421
5679
|
|
|
5680
|
+
// Distinguishes a broken variant from an unreachable preview tree; the
|
|
5681
|
+
// recovery differs (fix the component vs fix the root/dev-server pair).
|
|
5682
|
+
async function describeMountFailure(manifest, err) {
|
|
5683
|
+
try {
|
|
5684
|
+
const probe = await probePreviewTree(manifest);
|
|
5685
|
+
if (probe.ok === false) {
|
|
5686
|
+
return 'The preview tree is not reachable from the dev server (probe failed on '
|
|
5687
|
+
+ (probe.tried || []).join(', ')
|
|
5688
|
+
+ '). The resolved app root and the dev server root likely disagree; restart live from the app the dev server serves.';
|
|
5689
|
+
}
|
|
5690
|
+
} catch { /* probe is best-effort */ }
|
|
5691
|
+
return 'The compiled component could not be imported or mounted. ' + (err?.message || 'Unknown error');
|
|
5692
|
+
}
|
|
5693
|
+
|
|
5422
5694
|
function teardownSvelteComponentSession(restoreOriginal) {
|
|
5423
5695
|
if (!svelteComponentSession) return;
|
|
5424
5696
|
const { wrapperEl, detachedOriginal, runtime, mountedInstance } = svelteComponentSession;
|
|
@@ -5471,12 +5743,29 @@
|
|
|
5471
5743
|
}
|
|
5472
5744
|
|
|
5473
5745
|
async function injectSvelteComponentsFromManifest(manifestPath, sessionId) {
|
|
5746
|
+
// Every (re)injection is a fresh attempt: reset the failure dedupe so a
|
|
5747
|
+
// republish that is STILL broken at the same URL reports again instead of
|
|
5748
|
+
// being swallowed while the agent believes the repair landed.
|
|
5749
|
+
lastReportedMountFailure = null;
|
|
5474
5750
|
const url = 'http://localhost:' + PORT + '/source?token=' + TOKEN + '&path=' + encodeURIComponent(manifestPath);
|
|
5475
5751
|
try {
|
|
5476
5752
|
const res = await fetch(url);
|
|
5477
5753
|
if (!res.ok) throw new Error(String(res.status));
|
|
5478
5754
|
const manifest = JSON.parse(await res.text());
|
|
5479
|
-
if (manifest.id !== sessionId)
|
|
5755
|
+
if (manifest.id !== sessionId) {
|
|
5756
|
+
// A manifest at the expected path belonging to a different session is
|
|
5757
|
+
// an agent-side publish error. Left as a bare return it stranded the
|
|
5758
|
+
// bar in GENERATING with no explanation and no event.
|
|
5759
|
+
const mismatch = 'Manifest at ' + manifestPath + ' belongs to session ' + (manifest.id || 'unknown') + ', not ' + sessionId + '.';
|
|
5760
|
+
reportVariantMountFailed(sessionId, visibleVariant || 1, manifestPath, mismatch);
|
|
5761
|
+
showMountErrorCard(sessionId, {
|
|
5762
|
+
variant: visibleVariant || 0,
|
|
5763
|
+
url: manifestPath,
|
|
5764
|
+
message: 'The variant manifest is for a different session. Ask the agent to republish.',
|
|
5765
|
+
previewFile: manifestPath,
|
|
5766
|
+
});
|
|
5767
|
+
return;
|
|
5768
|
+
}
|
|
5480
5769
|
|
|
5481
5770
|
const paramsByVariant = await loadSvelteComponentParams(manifest);
|
|
5482
5771
|
const availableVariants = Number(manifest.arrivedVariants) || Number(manifest.count) || 1;
|
|
@@ -5500,7 +5789,14 @@
|
|
|
5500
5789
|
arrivedVariants = availableVariants;
|
|
5501
5790
|
expectedVariants = Number(manifest.count) || expectedVariants || arrivedVariants;
|
|
5502
5791
|
visibleVariant = visibleVariant > 0 && visibleVariant <= arrivedVariants ? visibleVariant : 1;
|
|
5503
|
-
await mountSvelteComponentVariant(visibleVariant || 1);
|
|
5792
|
+
const remounted = await mountSvelteComponentVariant(visibleVariant || 1);
|
|
5793
|
+
if (!remounted) {
|
|
5794
|
+
// The mount already reported the failure and raised the card.
|
|
5795
|
+
// Advancing to CYCLING here would show a bar claiming variants are
|
|
5796
|
+
// ready over a page where nothing rendered.
|
|
5797
|
+
saveSession();
|
|
5798
|
+
return;
|
|
5799
|
+
}
|
|
5504
5800
|
setLiveState('CYCLING');
|
|
5505
5801
|
showOrUpdateCyclingBar();
|
|
5506
5802
|
saveSession();
|
|
@@ -5575,9 +5871,11 @@
|
|
|
5575
5871
|
const mounted = await mountSvelteComponentVariant(visibleVariant);
|
|
5576
5872
|
if (!mounted) {
|
|
5577
5873
|
// The compiled component threw (e.g. a Svelte compile error in the
|
|
5578
|
-
// variant file).
|
|
5579
|
-
//
|
|
5580
|
-
|
|
5874
|
+
// variant file). mountSvelteComponentVariant already reported the
|
|
5875
|
+
// failure and raised the card; tear the half-built preview down but
|
|
5876
|
+
// keep the session so Retry and a republish still have something to
|
|
5877
|
+
// act on.
|
|
5878
|
+
abortSvelteComponentInjection(sessionId);
|
|
5581
5879
|
return;
|
|
5582
5880
|
}
|
|
5583
5881
|
|
|
@@ -5594,7 +5892,15 @@
|
|
|
5594
5892
|
console.log('[impeccable] Mounted ' + arrivedVariants + ' ' + manifest.framework + ' component variants.');
|
|
5595
5893
|
} catch (err) {
|
|
5596
5894
|
console.error('[impeccable] Failed to mount component-preview variants:', err);
|
|
5597
|
-
|
|
5895
|
+
// Report the manifest PATH, never the fetch URL: that URL carries the
|
|
5896
|
+
// live helper token and this string is journaled.
|
|
5897
|
+
reportVariantMountFailed(sessionId, visibleVariant || 1, manifestPath, err);
|
|
5898
|
+
abortSvelteComponentInjection(sessionId, {
|
|
5899
|
+
variant: visibleVariant || 0,
|
|
5900
|
+
url: manifestPath,
|
|
5901
|
+
message: 'Could not read the variant manifest. ' + (err?.message || 'Unknown error'),
|
|
5902
|
+
previewFile: manifestPath,
|
|
5903
|
+
});
|
|
5598
5904
|
}
|
|
5599
5905
|
}
|
|
5600
5906
|
|
|
@@ -5615,10 +5921,187 @@
|
|
|
5615
5921
|
pendingSvelteComponentRetryObserver.observe(document.body, { childList: true, subtree: true });
|
|
5616
5922
|
}
|
|
5617
5923
|
|
|
5618
|
-
//
|
|
5619
|
-
//
|
|
5620
|
-
//
|
|
5621
|
-
|
|
5924
|
+
//
|
|
5925
|
+
// Mount acknowledgements
|
|
5926
|
+
//
|
|
5927
|
+
// The agent's `done` says it published files. Only the browser knows whether
|
|
5928
|
+
// the import resolved and the component reached the DOM. These two events
|
|
5929
|
+
// carry that answer back, so the journal, `live-status`, and `live-resume`
|
|
5930
|
+
// can tell "the user is comparing variants" from "nothing ever rendered".
|
|
5931
|
+
|
|
5932
|
+
// Mirror of the caps in live/event-validation.mjs. Trimming here keeps a
|
|
5933
|
+
// stack-trace-sized error from being rejected outright and lost.
|
|
5934
|
+
const MOUNT_URL_MAX = 2000;
|
|
5935
|
+
const MOUNT_ERROR_MAX = 1000;
|
|
5936
|
+
|
|
5937
|
+
function reportVariantMounted(sessionId, variantNum, moduleUrl) {
|
|
5938
|
+
const variant = Math.floor(Number(variantNum) || 0);
|
|
5939
|
+
if (!sessionId || variant < 1) return;
|
|
5940
|
+
sendEvent({
|
|
5941
|
+
type: 'variant_mounted',
|
|
5942
|
+
id: sessionId,
|
|
5943
|
+
variant,
|
|
5944
|
+
url: moduleUrl ? String(moduleUrl).slice(0, MOUNT_URL_MAX) : undefined,
|
|
5945
|
+
});
|
|
5946
|
+
}
|
|
5947
|
+
|
|
5948
|
+
function reportVariantMountFailed(sessionId, variantNum, moduleUrl, error) {
|
|
5949
|
+
if (!sessionId) return;
|
|
5950
|
+
const parsed = Math.floor(Number(variantNum) || 0);
|
|
5951
|
+
const variant = parsed >= 1 ? parsed : 1;
|
|
5952
|
+
const url = String(moduleUrl || 'unknown').slice(0, MOUNT_URL_MAX);
|
|
5953
|
+
const message = String(error?.message || error || 'Unknown mount error').slice(0, MOUNT_ERROR_MAX);
|
|
5954
|
+
// Progressive delivery and the Retry button both re-enter the same failure.
|
|
5955
|
+
// Report each distinct one once so the agent's poll queue and the journal
|
|
5956
|
+
// stay readable; a genuinely new failure (different variant, URL, or
|
|
5957
|
+
// message) still gets through.
|
|
5958
|
+
const key = sessionId + '|' + variant + '|' + url + '|' + message;
|
|
5959
|
+
if (lastReportedMountFailure === key) return;
|
|
5960
|
+
lastReportedMountFailure = key;
|
|
5961
|
+
sendEvent({ type: 'variant_mount_failed', id: sessionId, variant, url, error: message });
|
|
5962
|
+
}
|
|
5963
|
+
|
|
5964
|
+
function truncateMiddle(value, max) {
|
|
5965
|
+
const text = String(value || '');
|
|
5966
|
+
if (text.length <= max) return text;
|
|
5967
|
+
const head = Math.ceil((max - 1) / 2);
|
|
5968
|
+
const tail = max - 1 - head;
|
|
5969
|
+
return text.slice(0, head) + '…' + text.slice(text.length - tail);
|
|
5970
|
+
}
|
|
5971
|
+
|
|
5972
|
+
/**
|
|
5973
|
+
* Persistent failure surface. Replaces the old 5s toast: a toast that
|
|
5974
|
+
* disappears while the session is unusable is indistinguishable from no
|
|
5975
|
+
* feedback at all, and the wipe that came with it deleted the only handle on
|
|
5976
|
+
* a session the server still considered live.
|
|
5977
|
+
*/
|
|
5978
|
+
function showMountErrorCard(sessionId, details) {
|
|
5979
|
+
mountErrorState = {
|
|
5980
|
+
sessionId: sessionId || currentSessionId || null,
|
|
5981
|
+
variant: Math.floor(Number(details?.variant) || 0),
|
|
5982
|
+
url: details?.url ? String(details.url) : '',
|
|
5983
|
+
message: details?.message || 'A variant failed to load.',
|
|
5984
|
+
previewFile: details?.previewFile || currentPreviewFile || null,
|
|
5985
|
+
};
|
|
5986
|
+
renderMountErrorCard();
|
|
5987
|
+
}
|
|
5988
|
+
|
|
5989
|
+
function clearMountErrorCard() {
|
|
5990
|
+
mountErrorState = null;
|
|
5991
|
+
if (mountErrorEl) {
|
|
5992
|
+
mountErrorEl.remove();
|
|
5993
|
+
mountErrorEl = null;
|
|
5994
|
+
}
|
|
5995
|
+
}
|
|
5996
|
+
|
|
5997
|
+
function mountErrorCardBottomOffset() {
|
|
5998
|
+
const barRect = globalBarEl?.getBoundingClientRect();
|
|
5999
|
+
return barRect && barRect.height > 0
|
|
6000
|
+
? Math.max(16, window.innerHeight - barRect.top + 12)
|
|
6001
|
+
: 16;
|
|
6002
|
+
}
|
|
6003
|
+
|
|
6004
|
+
function renderMountErrorCard() {
|
|
6005
|
+
if (!mountErrorState) return;
|
|
6006
|
+
if (mountErrorEl) mountErrorEl.remove();
|
|
6007
|
+
const P = BP || barPaletteForTheme(detectPageTheme());
|
|
6008
|
+
const card = el('div', {
|
|
6009
|
+
position: 'fixed', bottom: mountErrorCardBottomOffset() + 'px', left: '50%',
|
|
6010
|
+
transform: 'translateX(-50%)',
|
|
6011
|
+
display: 'flex', flexDirection: 'column', gap: '6px',
|
|
6012
|
+
background: P.surface, color: P.text,
|
|
6013
|
+
border: '1px solid oklch(65% 0.18 30 / 0.55)',
|
|
6014
|
+
borderRadius: '8px', padding: '10px 12px',
|
|
6015
|
+
fontFamily: FONT, fontSize: '12px',
|
|
6016
|
+
boxShadow: P.shadow, zIndex: Z.toast,
|
|
6017
|
+
maxWidth: 'min(520px, calc(100vw - 32px))',
|
|
6018
|
+
pointerEvents: 'auto', textAlign: 'left',
|
|
6019
|
+
});
|
|
6020
|
+
card.id = PREFIX + '-mount-error';
|
|
6021
|
+
|
|
6022
|
+
const head = el('div', { display: 'flex', alignItems: 'center', gap: '8px' });
|
|
6023
|
+
const glyph = el('span', { fontSize: '13px', lineHeight: '1', color: 'oklch(62% 0.19 30)', flexShrink: '0' });
|
|
6024
|
+
glyph.textContent = '⚠';
|
|
6025
|
+
head.appendChild(glyph);
|
|
6026
|
+
const title = el('span', { fontWeight: '600', flex: '1' });
|
|
6027
|
+
title.textContent = mountErrorState.variant > 0
|
|
6028
|
+
? 'Variant ' + mountErrorState.variant + ' failed to load'
|
|
6029
|
+
: 'Variants failed to load';
|
|
6030
|
+
head.appendChild(title);
|
|
6031
|
+
const dismiss = el('button', {
|
|
6032
|
+
border: 'none', background: 'transparent', color: P.textDim,
|
|
6033
|
+
cursor: 'pointer', fontFamily: FONT, fontSize: '14px', lineHeight: '1',
|
|
6034
|
+
padding: '0 2px', flexShrink: '0',
|
|
6035
|
+
});
|
|
6036
|
+
dismiss.textContent = '×';
|
|
6037
|
+
dismiss.setAttribute('aria-label', 'Dismiss');
|
|
6038
|
+
dismiss.addEventListener('click', (e) => {
|
|
6039
|
+
e.stopPropagation();
|
|
6040
|
+
clearMountErrorCard();
|
|
6041
|
+
// The card was the only recovery affordance while the bar is hidden;
|
|
6042
|
+
// dismissing it must hand the user back a usable surface. PICKING
|
|
6043
|
+
// reactivates the global mark and the picker. The saved session and
|
|
6044
|
+
// server truth survive, so a later republish (SSE `done`) still
|
|
6045
|
+
// resurrects the comparison through the normal handlers.
|
|
6046
|
+
if (state === 'GENERATING') setLiveState('PICKING');
|
|
6047
|
+
});
|
|
6048
|
+
head.appendChild(dismiss);
|
|
6049
|
+
card.appendChild(head);
|
|
6050
|
+
|
|
6051
|
+
const body = el('div', { color: P.textDim, lineHeight: '1.4' });
|
|
6052
|
+
body.textContent = mountErrorState.message;
|
|
6053
|
+
card.appendChild(body);
|
|
6054
|
+
|
|
6055
|
+
if (mountErrorState.url) {
|
|
6056
|
+
const urlLine = el('div', {
|
|
6057
|
+
fontFamily: MONO, fontSize: '11px', color: P.textDim,
|
|
6058
|
+
wordBreak: 'break-all', opacity: '0.85',
|
|
6059
|
+
});
|
|
6060
|
+
urlLine.textContent = truncateMiddle(mountErrorState.url, 72);
|
|
6061
|
+
urlLine.title = mountErrorState.url;
|
|
6062
|
+
card.appendChild(urlLine);
|
|
6063
|
+
}
|
|
6064
|
+
|
|
6065
|
+
const actions = el('div', { display: 'flex', gap: '8px', marginTop: '2px' });
|
|
6066
|
+
const retry = el('button', {
|
|
6067
|
+
border: '1px solid ' + P.hairline, background: 'transparent',
|
|
6068
|
+
color: P.text, fontFamily: FONT, fontSize: '12px', fontWeight: '500',
|
|
6069
|
+
borderRadius: '5px', padding: '4px 10px', cursor: 'pointer',
|
|
6070
|
+
});
|
|
6071
|
+
retry.textContent = 'Retry';
|
|
6072
|
+
retry.dataset.impeccableMountRetry = 'true';
|
|
6073
|
+
retry.addEventListener('click', (e) => { e.stopPropagation(); retryMountErrorCard(); });
|
|
6074
|
+
actions.appendChild(retry);
|
|
6075
|
+
card.appendChild(actions);
|
|
6076
|
+
|
|
6077
|
+
mountErrorEl = card;
|
|
6078
|
+
uiAppend(card);
|
|
6079
|
+
defangOutsideHandlers(card);
|
|
6080
|
+
}
|
|
6081
|
+
|
|
6082
|
+
function retryMountErrorCard() {
|
|
6083
|
+
const info = mountErrorState;
|
|
6084
|
+
if (!info) return;
|
|
6085
|
+
const sessionId = info.sessionId || currentSessionId;
|
|
6086
|
+
const manifestPath = info.previewFile || currentPreviewFile;
|
|
6087
|
+
clearMountErrorCard();
|
|
6088
|
+
if (!sessionId || !manifestPath) {
|
|
6089
|
+
showToast('No variant manifest to retry. Ask the agent to republish.', 5000);
|
|
6090
|
+
return;
|
|
6091
|
+
}
|
|
6092
|
+
// A retry must be able to report the same failure again, otherwise a second
|
|
6093
|
+
// attempt against an unchanged broken module would look silent.
|
|
6094
|
+
lastReportedMountFailure = null;
|
|
6095
|
+
if (state !== 'CYCLING') setLiveState('GENERATING');
|
|
6096
|
+
injectSvelteComponentsFromManifest(manifestPath, sessionId);
|
|
6097
|
+
}
|
|
6098
|
+
|
|
6099
|
+
// Tear down a component preview that could not mount, WITHOUT touching
|
|
6100
|
+
// session identity. The old version cleared localStorage, nulled
|
|
6101
|
+
// currentSessionId, and reset to PICKING, which orphaned a session the server
|
|
6102
|
+
// still had in its journal and made every recovery path unreachable. The DOM
|
|
6103
|
+
// teardown and observer cleanup are still right; the state wipe never was.
|
|
6104
|
+
function abortSvelteComponentInjection(sessionId, details) {
|
|
5622
6105
|
try {
|
|
5623
6106
|
if (svelteComponentSession?.sessionId === sessionId) {
|
|
5624
6107
|
teardownSvelteComponentSession(true);
|
|
@@ -5630,11 +6113,46 @@
|
|
|
5630
6113
|
console.warn('[impeccable] Svelte component abort cleanup failed:', err);
|
|
5631
6114
|
}
|
|
5632
6115
|
hideShaderOverlay();
|
|
6116
|
+
if (pendingSvelteComponentRetryObserver) { pendingSvelteComponentRetryObserver.disconnect(); pendingSvelteComponentRetryObserver = null; }
|
|
6117
|
+
if (pendingVariantAnchorRetryObserver) { pendingVariantAnchorRetryObserver.disconnect(); pendingVariantAnchorRetryObserver = null; }
|
|
6118
|
+
// The generate submit armed a scroll lock and a variant observer; a page
|
|
6119
|
+
// the user cannot scroll, watched by a stale observer, is exactly the
|
|
6120
|
+
// wrong place to show a card asking them to act.
|
|
6121
|
+
stopScrollLock();
|
|
6122
|
+
if (variantObserver) { variantObserver.disconnect(); variantObserver = null; }
|
|
6123
|
+
removeVariantStateStylesheet();
|
|
6124
|
+
hideBar(true);
|
|
6125
|
+
// currentSessionId, the saved session, and the file metadata all survive on
|
|
6126
|
+
// purpose: Retry, a republish from the agent, and a page reload all need
|
|
6127
|
+
// them. saveSession keeps the localStorage cache in step with the server.
|
|
6128
|
+
saveSession();
|
|
6129
|
+
if (details) showMountErrorCard(sessionId, details);
|
|
6130
|
+
else if (!mountErrorState) {
|
|
6131
|
+
showMountErrorCard(sessionId, { message: 'Variants could not be mounted. Retry, or ask the agent to republish.' });
|
|
6132
|
+
}
|
|
6133
|
+
}
|
|
6134
|
+
|
|
6135
|
+
// Hard reset for the one case that is not a mount failure: a cycling state
|
|
6136
|
+
// with nothing to cycle. There is no variant to retry and no URL to report,
|
|
6137
|
+
// so the session really is over.
|
|
6138
|
+
function resetSvelteComponentSession(sessionId, message) {
|
|
6139
|
+
try {
|
|
6140
|
+
if (svelteComponentSession?.sessionId === sessionId) {
|
|
6141
|
+
teardownSvelteComponentSession(true);
|
|
6142
|
+
} else {
|
|
6143
|
+
const orphan = document.querySelector('[data-impeccable-variants="' + sessionId + '"]');
|
|
6144
|
+
if (orphan) orphan.remove();
|
|
6145
|
+
}
|
|
6146
|
+
} catch (err) {
|
|
6147
|
+
console.warn('[impeccable] Svelte component reset cleanup failed:', err);
|
|
6148
|
+
}
|
|
6149
|
+
hideShaderOverlay();
|
|
5633
6150
|
if (variantObserver) { variantObserver.disconnect(); variantObserver = null; }
|
|
5634
6151
|
if (pendingSvelteComponentRetryObserver) { pendingSvelteComponentRetryObserver.disconnect(); pendingSvelteComponentRetryObserver = null; }
|
|
5635
6152
|
if (pendingVariantAnchorRetryObserver) { pendingVariantAnchorRetryObserver.disconnect(); pendingVariantAnchorRetryObserver = null; }
|
|
5636
6153
|
stopScrollLock();
|
|
5637
6154
|
removeVariantStateStylesheet();
|
|
6155
|
+
clearMountErrorCard();
|
|
5638
6156
|
clearSession();
|
|
5639
6157
|
clearHandled();
|
|
5640
6158
|
resetSessionFileMeta();
|
|
@@ -5656,6 +6174,22 @@
|
|
|
5656
6174
|
const COMPLETED_SOURCE_FALLBACK_RETRIES = 3;
|
|
5657
6175
|
const COMPLETED_SOURCE_FALLBACK_RETRY_MS = 1200;
|
|
5658
6176
|
|
|
6177
|
+
/**
|
|
6178
|
+
* Terminal recovery for a session whose source-side scaffolding no longer
|
|
6179
|
+
* exists. The discard event is best-effort: with no agent polling it parks
|
|
6180
|
+
* the durable session in discard_requested, which no resume path adopts;
|
|
6181
|
+
* with an agent attached it triggers the normal discard finalization.
|
|
6182
|
+
*/
|
|
6183
|
+
function discardOrphanedSession(reason) {
|
|
6184
|
+
const sessionId = currentSessionId;
|
|
6185
|
+
if (!sessionId) return;
|
|
6186
|
+
console.warn('[impeccable] Discarding orphaned session ' + sessionId + ': ' + reason);
|
|
6187
|
+
sendEvent({ type: 'discard', id: sessionId, orphaned: true }).catch(() => {});
|
|
6188
|
+
markSessionHandled();
|
|
6189
|
+
cleanup({ instantChrome: true });
|
|
6190
|
+
showToast('The previous live session no longer matches the source file, so it was discarded. Pick an element to start fresh.', 6000);
|
|
6191
|
+
}
|
|
6192
|
+
|
|
5659
6193
|
/**
|
|
5660
6194
|
* No-HMR fallback: fetch the raw source file from the live server,
|
|
5661
6195
|
* parse it, extract the variant wrapper, and inject it into the live DOM.
|
|
@@ -5692,6 +6226,25 @@
|
|
|
5692
6226
|
srcWrapper = doc.querySelector('[data-impeccable-variants="' + sessionId + '"]');
|
|
5693
6227
|
if (!srcWrapper) {
|
|
5694
6228
|
console.warn('[impeccable] Variant wrapper not found in source file.');
|
|
6229
|
+
// A resumed cycling session whose wrapper is gone from source is an
|
|
6230
|
+
// ORPHAN: the file was edited or regenerated out from under it, so
|
|
6231
|
+
// no reload, HMR push, or server restart can ever complete it, and
|
|
6232
|
+
// the frozen picker it leaves behind used to need a manual
|
|
6233
|
+
// live-complete --discarded. Retry a few reads first (an agent
|
|
6234
|
+
// rewrite or HMR patch may be mid-flight), then self-discard and
|
|
6235
|
+
// hand the surface back to the picker.
|
|
6236
|
+
if (opts.orphanDiscard && sessionId === currentSessionId) {
|
|
6237
|
+
const attempt = opts._orphanAttempt || 0;
|
|
6238
|
+
if (attempt < COMPLETED_SOURCE_FALLBACK_RETRIES) {
|
|
6239
|
+
setTimeout(() => {
|
|
6240
|
+
if (sessionId !== currentSessionId) return;
|
|
6241
|
+
if (state !== 'GENERATING' && state !== 'CYCLING') return;
|
|
6242
|
+
injectVariantsFromSource(filePath, sessionId, { ...opts, _orphanAttempt: attempt + 1 });
|
|
6243
|
+
}, COMPLETED_SOURCE_FALLBACK_RETRY_MS);
|
|
6244
|
+
} else {
|
|
6245
|
+
discardOrphanedSession('variant wrapper missing from source');
|
|
6246
|
+
}
|
|
6247
|
+
}
|
|
5695
6248
|
return;
|
|
5696
6249
|
}
|
|
5697
6250
|
|
|
@@ -6394,12 +6947,8 @@
|
|
|
6394
6947
|
// checkpoint may carry an earlier phase for internal bookkeeping,
|
|
6395
6948
|
// but the bar must not move backward.
|
|
6396
6949
|
if (shouldAdvancePhase(generationPhase, msg.phase)) generationPhase = msg.phase;
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
}
|
|
6400
|
-
if (msg.phase === 'parameters_ready' && parameterGenerationState !== 'ready') {
|
|
6401
|
-
parameterGenerationState = 'loading';
|
|
6402
|
-
}
|
|
6950
|
+
// The deferred parameter pass reports through `variant_progress`
|
|
6951
|
+
// with publicationKind 'params', not through agent_phase.
|
|
6403
6952
|
updateBarContent(state === 'CYCLING' ? 'cycling' : 'generating');
|
|
6404
6953
|
saveSession();
|
|
6405
6954
|
}
|
|
@@ -6588,6 +7137,13 @@
|
|
|
6588
7137
|
if (currentSessionId) saveSession();
|
|
6589
7138
|
}
|
|
6590
7139
|
|
|
7140
|
+
// Progress events must never overtake the event that CREATES their session:
|
|
7141
|
+
// the Go-time checkpoint and the generate POST are concurrent fetches, and
|
|
7142
|
+
// when the checkpoint lands first the server rightly refuses it as
|
|
7143
|
+
// unknown_session — which must mean "foreign leftovers", not "you raced
|
|
7144
|
+
// your own Go click". The gate serializes creation before progress.
|
|
7145
|
+
let sessionCreationGate = Promise.resolve();
|
|
7146
|
+
|
|
6591
7147
|
function sendEvent(msg, opts) {
|
|
6592
7148
|
msg.token = TOKEN;
|
|
6593
7149
|
function handleFailure(err) {
|
|
@@ -6598,15 +7154,45 @@
|
|
|
6598
7154
|
console.debug('[impeccable] Dropped optional live event:', err);
|
|
6599
7155
|
return null;
|
|
6600
7156
|
}
|
|
6601
|
-
|
|
7157
|
+
// Token in the query string as well as the body: the URL token is what
|
|
7158
|
+
// authorizes the CORS preflight when the page runs on a non-loopback
|
|
7159
|
+
// dev host (ddev, Valet), since the preflight carries no request body.
|
|
7160
|
+
const doSend = () => fetch('http://localhost:' + PORT + '/events?token=' + encodeURIComponent(TOKEN), {
|
|
6602
7161
|
method: 'POST',
|
|
6603
7162
|
headers: { 'Content-Type': 'application/json' },
|
|
6604
7163
|
body: JSON.stringify(msg),
|
|
6605
7164
|
}).then(async res => {
|
|
6606
7165
|
if (res.ok) return res;
|
|
6607
7166
|
const body = await res.json().catch(() => ({}));
|
|
7167
|
+
// The server refused to journal progress for a session it has never
|
|
7168
|
+
// seen: this browser is carrying state from another project or a
|
|
7169
|
+
// wiped store (two apps sharing a localhost port). Continuing to
|
|
7170
|
+
// report it would freeze the picker behind a session that can never
|
|
7171
|
+
// complete, so drop the local state and hand the surface back.
|
|
7172
|
+
if (body.error === 'unknown_session' && msg.type === 'checkpoint'
|
|
7173
|
+
&& msg.id && msg.id === currentSessionId) {
|
|
7174
|
+
abandonForeignSession(msg.id);
|
|
7175
|
+
return null;
|
|
7176
|
+
}
|
|
6608
7177
|
return handleFailure(new Error(body.error || ('HTTP ' + res.status + ' ' + res.statusText)));
|
|
6609
7178
|
}).catch(handleFailure);
|
|
7179
|
+
|
|
7180
|
+
if (msg.type === 'generate' || msg.type === 'steer') {
|
|
7181
|
+
const creation = doSend();
|
|
7182
|
+
sessionCreationGate = creation.then(() => {}, () => {});
|
|
7183
|
+
return creation;
|
|
7184
|
+
}
|
|
7185
|
+
return sessionCreationGate.then(doSend);
|
|
7186
|
+
}
|
|
7187
|
+
|
|
7188
|
+
let abandonedForeignSessionId = null;
|
|
7189
|
+
function abandonForeignSession(sessionId) {
|
|
7190
|
+
if (abandonedForeignSessionId === sessionId || sessionId !== currentSessionId) return;
|
|
7191
|
+
abandonedForeignSessionId = sessionId;
|
|
7192
|
+
console.warn('[impeccable] The live server has no record of session ' + sessionId + '; clearing stale local state.');
|
|
7193
|
+
markSessionHandled();
|
|
7194
|
+
cleanup({ instantChrome: true });
|
|
7195
|
+
showToast('A saved live session belonged to a different project, so it was cleared. Pick an element to start fresh.', 6000);
|
|
6610
7196
|
}
|
|
6611
7197
|
|
|
6612
7198
|
function checkpointPayload(reason) {
|
|
@@ -6989,6 +7575,10 @@
|
|
|
6989
7575
|
disableInlineEdit();
|
|
6990
7576
|
stripManualEditRuntimeState(selectedElement);
|
|
6991
7577
|
|
|
7578
|
+
// A new cycle publishes new modules, so the previous cycle's mount failure
|
|
7579
|
+
// is about files that no longer matter.
|
|
7580
|
+
clearMountErrorCard();
|
|
7581
|
+
lastReportedMountFailure = null;
|
|
6992
7582
|
pendingAcceptedSession = null;
|
|
6993
7583
|
// A new session supersedes any accept still awaiting its result; a late
|
|
6994
7584
|
// failure toast for the previous session would only mislead here.
|
|
@@ -7071,6 +7661,10 @@
|
|
|
7071
7661
|
if (!canCreateInsert({ prompt, comments: snapshot.comments, strokes: snapshot.strokes })) return;
|
|
7072
7662
|
|
|
7073
7663
|
stopVoice({ suppressSubmit: true });
|
|
7664
|
+
// A new cycle publishes new modules, so the previous cycle's mount failure
|
|
7665
|
+
// is about files that no longer matter.
|
|
7666
|
+
clearMountErrorCard();
|
|
7667
|
+
lastReportedMountFailure = null;
|
|
7074
7668
|
pendingAcceptedSession = null;
|
|
7075
7669
|
// A new session supersedes any accept still awaiting its result; a late
|
|
7076
7670
|
// failure toast for the previous session would only mislead here.
|
|
@@ -8193,8 +8787,62 @@ void main() {
|
|
|
8193
8787
|
return Math.floor(num);
|
|
8194
8788
|
}
|
|
8195
8789
|
|
|
8790
|
+
/**
|
|
8791
|
+
* A durable server session this page can adopt when the browser has no local
|
|
8792
|
+
* record of it. Requires an explicit pageUrl match: a summary with no page is
|
|
8793
|
+
* not evidence that it belongs to THIS page, and adopting it would hijack an
|
|
8794
|
+
* unrelated route.
|
|
8795
|
+
*/
|
|
8796
|
+
// Phases in which the user is (or should be) comparing variants. Only these
|
|
8797
|
+
// are adoptable by a browser with no local record. Steer and manual-edit
|
|
8798
|
+
// sessions have no wrapper to restore, and accept/carbonize phases are
|
|
8799
|
+
// agent-side work: a reload mid-carbonize must not resurrect the bar over a
|
|
8800
|
+
// page whose comparison is already decided (a slow-CI reload hit exactly
|
|
8801
|
+
// that window and left the bar stranded after accept).
|
|
8802
|
+
const ADOPTABLE_SESSION_PHASES = new Set([
|
|
8803
|
+
'generate_requested', 'variants_ready', 'generating', 'cycling',
|
|
8804
|
+
]);
|
|
8805
|
+
|
|
8806
|
+
function findAdoptableServerSession(activeSessions) {
|
|
8807
|
+
if (!Array.isArray(activeSessions)) return null;
|
|
8808
|
+
return activeSessions.find((session) => (
|
|
8809
|
+
session?.id
|
|
8810
|
+
&& !isTerminalSessionSummary(session)
|
|
8811
|
+
&& !isSessionHandled(session.id)
|
|
8812
|
+
&& session.pageUrl
|
|
8813
|
+
&& pageMatchesCurrent(session.pageUrl)
|
|
8814
|
+
&& (session.previewFile || session.sourceFile)
|
|
8815
|
+
&& Number(session.expectedVariants) > 0
|
|
8816
|
+
&& ADOPTABLE_SESSION_PHASES.has(String(session.phase || ''))
|
|
8817
|
+
)) || null;
|
|
8818
|
+
}
|
|
8819
|
+
|
|
8820
|
+
// Shape a server summary like a saved local session so one restore path
|
|
8821
|
+
// serves both. The server has no browser state machine, so an adopted session
|
|
8822
|
+
// always re-enters GENERATING and lets the injection settle the final state.
|
|
8823
|
+
function serverSessionAsSavedShape(session) {
|
|
8824
|
+
return {
|
|
8825
|
+
id: session.id,
|
|
8826
|
+
state: 'GENERATING',
|
|
8827
|
+
expected: Number(session.expectedVariants) || 0,
|
|
8828
|
+
arrived: Number(session.arrivedVariants) || 0,
|
|
8829
|
+
visible: Number(session.visibleVariant) || 0,
|
|
8830
|
+
sourceFile: session.sourceFile || undefined,
|
|
8831
|
+
previewFile: session.previewFile || undefined,
|
|
8832
|
+
previewMode: session.previewMode || undefined,
|
|
8833
|
+
pageUrl: session.pageUrl || undefined,
|
|
8834
|
+
paramValues: session.paramValues && typeof session.paramValues === 'object' ? session.paramValues : {},
|
|
8835
|
+
};
|
|
8836
|
+
}
|
|
8837
|
+
|
|
8196
8838
|
function restoreSessionWithoutWrapper(reason, activeSessions) {
|
|
8197
|
-
const
|
|
8839
|
+
const cached = loadSession();
|
|
8840
|
+
// localStorage is a cache, not a gate. A cleared tab, a second browser
|
|
8841
|
+
// profile, or a teardown that dropped local state all leave the durable
|
|
8842
|
+
// server session as the only record of work in progress; adopt it instead
|
|
8843
|
+
// of stranding a session the server still considers live.
|
|
8844
|
+
const adopted = cached?.id ? null : findAdoptableServerSession(activeSessions);
|
|
8845
|
+
const saved = cached?.id ? cached : (adopted ? serverSessionAsSavedShape(adopted) : null);
|
|
8198
8846
|
if (!saved?.id || isSessionHandled(saved.id)) return false;
|
|
8199
8847
|
const savedState = String(saved.state || '').toUpperCase();
|
|
8200
8848
|
if (savedState !== 'GENERATING' && savedState !== 'CYCLING') return false;
|
|
@@ -8231,7 +8879,14 @@ void main() {
|
|
|
8231
8879
|
? currentPreviewFile
|
|
8232
8880
|
: (currentSourceFile || currentPreviewFile);
|
|
8233
8881
|
if (restoreFile) {
|
|
8234
|
-
|
|
8882
|
+
// A restored CYCLING session promises variants already written into
|
|
8883
|
+
// source; if they are not there (after retries), the session is an
|
|
8884
|
+
// orphan and must self-discard instead of freezing the picker (#439).
|
|
8885
|
+
// GENERATING restores make no such promise: deferred-wrapper flows
|
|
8886
|
+
// legitimately have no wrapper in source until the agent's write lands.
|
|
8887
|
+
injectVariantsFromSource(restoreFile, currentSessionId, {
|
|
8888
|
+
orphanDiscard: savedState === 'CYCLING' && !isFrameworkComponentPreviewMode(currentPreviewMode),
|
|
8889
|
+
});
|
|
8235
8890
|
return true;
|
|
8236
8891
|
}
|
|
8237
8892
|
|
|
@@ -8281,6 +8936,7 @@ void main() {
|
|
|
8281
8936
|
// it here would overwrite the Go-time value every time state changes.
|
|
8282
8937
|
sessionState.saveSession({
|
|
8283
8938
|
id: currentSessionId,
|
|
8939
|
+
appRoot: APP_ROOT || undefined,
|
|
8284
8940
|
state,
|
|
8285
8941
|
action: selectedAction,
|
|
8286
8942
|
count: selectedCount,
|
|
@@ -8302,7 +8958,17 @@ void main() {
|
|
|
8302
8958
|
}
|
|
8303
8959
|
|
|
8304
8960
|
function loadSession() {
|
|
8305
|
-
|
|
8961
|
+
const saved = sessionState.loadSession();
|
|
8962
|
+
// localStorage is per-origin, and two projects routinely reuse the same
|
|
8963
|
+
// localhost port. A saved session stamped with another project's appRoot
|
|
8964
|
+
// is that project's leftover, never a session this server can complete;
|
|
8965
|
+
// resuming it freezes the picker behind an unfinishable banner.
|
|
8966
|
+
if (saved?.appRoot && APP_ROOT && saved.appRoot !== APP_ROOT) {
|
|
8967
|
+
console.warn('[impeccable] Ignoring saved live session from another project (' + saved.appRoot + ').');
|
|
8968
|
+
sessionState.clearSession();
|
|
8969
|
+
return null;
|
|
8970
|
+
}
|
|
8971
|
+
return saved;
|
|
8306
8972
|
}
|
|
8307
8973
|
|
|
8308
8974
|
function clearSession() {
|
|
@@ -8329,6 +8995,8 @@ void main() {
|
|
|
8329
8995
|
const restoreOriginal = options?.restoreOriginal === true;
|
|
8330
8996
|
const instantChrome = options?.instantChrome === true;
|
|
8331
8997
|
const cleanupSessionId = currentSessionId;
|
|
8998
|
+
clearMountErrorCard();
|
|
8999
|
+
lastReportedMountFailure = null;
|
|
8332
9000
|
if (svelteComponentSession?.sessionId === cleanupSessionId) {
|
|
8333
9001
|
teardownSvelteComponentSession(true);
|
|
8334
9002
|
} else if (cleanupSessionId) {
|
|
@@ -8671,6 +9339,8 @@ void main() {
|
|
|
8671
9339
|
let pageChatInput = null;
|
|
8672
9340
|
let pageChatHint = null;
|
|
8673
9341
|
let pageChatVoiceBtn = null;
|
|
9342
|
+
let pageChatSendBtn = null;
|
|
9343
|
+
let pageChatQueueHintEl = null;
|
|
8674
9344
|
let pageChatExpanded = false;
|
|
8675
9345
|
let steerLocked = false;
|
|
8676
9346
|
let steerRequestId = null;
|
|
@@ -8685,7 +9355,7 @@ void main() {
|
|
|
8685
9355
|
/** @type {{ mode: 'steer'|'configure', input: HTMLInputElement, submit: () => void, beforeStart?: () => void } | null} */
|
|
8686
9356
|
let voiceCtx = null;
|
|
8687
9357
|
const PAGE_CHAT_COLLAPSED_W = '104px';
|
|
8688
|
-
const
|
|
9358
|
+
const PAGE_CHAT_QUEUED_W = '212px';
|
|
8689
9359
|
const PAGE_CHAT_PLACEHOLDER_COLLAPSED = 'Steer…';
|
|
8690
9360
|
const PAGE_CHAT_PLACEHOLDER_EXPANDED = 'Steer the page…';
|
|
8691
9361
|
const STEER_AWAIT_TIMEOUT_MS = 120000;
|
|
@@ -8699,6 +9369,10 @@ void main() {
|
|
|
8699
9369
|
// every normal generation, and telling the user to start a poll loop then is
|
|
8700
9370
|
// wrong advice about a healthy session.
|
|
8701
9371
|
const AGENT_BUSY_TIP = 'Agent is working - steering resumes when it finishes';
|
|
9372
|
+
// Same distinction, said where the steer request is waiting. A submitted
|
|
9373
|
+
// steer that lands while a generate holds the poll lease is not stuck, it is
|
|
9374
|
+
// second in line, and the pulsing dots alone read as "nothing is happening".
|
|
9375
|
+
const STEER_QUEUED_HINT = 'Queued behind current generation';
|
|
8702
9376
|
const GLOBAL_BAR_SECTION_GAP = 8;
|
|
8703
9377
|
const GLOBAL_BAR_INNER_GAP = 2;
|
|
8704
9378
|
const GLOBAL_BAR_INNER_PAD_LEFT = 2;
|
|
@@ -8851,10 +9525,85 @@ void main() {
|
|
|
8851
9525
|
}
|
|
8852
9526
|
|
|
8853
9527
|
function syncPageChatVisual() {
|
|
8854
|
-
if (!pageChatInput || steerLocked)
|
|
9528
|
+
if (!pageChatInput || steerLocked) {
|
|
9529
|
+
syncPageChatSendButton();
|
|
9530
|
+
return;
|
|
9531
|
+
}
|
|
8855
9532
|
const hasText = pageChatInput.value.length > 0;
|
|
8856
9533
|
if (hasText && !pageChatExpanded) expandPageChat({ focus: false });
|
|
8857
9534
|
else if (!hasText && pageChatExpanded) collapsePageChat();
|
|
9535
|
+
syncPageChatSendButton();
|
|
9536
|
+
}
|
|
9537
|
+
|
|
9538
|
+
/**
|
|
9539
|
+
* Send is visible once the pill is open for typing and enabled once there is
|
|
9540
|
+
* something to send. It disappears entirely while a steer is in flight, the
|
|
9541
|
+
* same way the mic does: a second submit during the lock has nowhere to go.
|
|
9542
|
+
*/
|
|
9543
|
+
function syncPageChatSendButton() {
|
|
9544
|
+
if (!pageChatSendBtn) return;
|
|
9545
|
+
const P = pageChatPalette();
|
|
9546
|
+
const hasText = !!pageChatInput?.value.trim();
|
|
9547
|
+
const focused = pageChatInput && activeElementDeep() === pageChatInput;
|
|
9548
|
+
const visible = !steerLocked && (pageChatExpanded || hasText || focused);
|
|
9549
|
+
pageChatSendBtn.style.display = visible ? 'inline-flex' : 'none';
|
|
9550
|
+
pageChatSendBtn.disabled = !visible || !hasText;
|
|
9551
|
+
pageChatSendBtn.style.background = P.accent;
|
|
9552
|
+
pageChatSendBtn.style.color = C.ink;
|
|
9553
|
+
pageChatSendBtn.style.borderLeft = '1px solid ' + P.hairline;
|
|
9554
|
+
pageChatSendBtn.style.opacity = pageChatSendBtn.disabled ? '0.42' : '1';
|
|
9555
|
+
pageChatSendBtn.style.cursor = pageChatSendBtn.disabled ? 'not-allowed' : 'pointer';
|
|
9556
|
+
pageChatSendBtn.title = pageChatSendBtn.disabled ? 'Type what to change first' : 'Send (Enter)';
|
|
9557
|
+
}
|
|
9558
|
+
|
|
9559
|
+
/**
|
|
9560
|
+
* A submitted steer is queued, not ignored, whenever no poll is parked and
|
|
9561
|
+
* the browser knows a generation is in flight: the agent holds the lease and
|
|
9562
|
+
* will not see the steer until it finishes. Saying so beats three dots that
|
|
9563
|
+
* look identical to a lost request.
|
|
9564
|
+
*/
|
|
9565
|
+
function steerQueuedBehindGeneration() {
|
|
9566
|
+
return steerLocked && !agentPollingConnected && agentHasWorkInFlight();
|
|
9567
|
+
}
|
|
9568
|
+
|
|
9569
|
+
function buildSteerQueueHint() {
|
|
9570
|
+
const P = pageChatPalette();
|
|
9571
|
+
const hint = el('span', {
|
|
9572
|
+
display: 'inline-flex', alignItems: 'center', justifyContent: 'flex-end',
|
|
9573
|
+
flex: '1', minWidth: '0', marginLeft: 'auto',
|
|
9574
|
+
padding: '0 10px 0 6px',
|
|
9575
|
+
fontFamily: FONT, fontSize: '10.5px', fontWeight: '500',
|
|
9576
|
+
color: P.patinaPale,
|
|
9577
|
+
whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
|
|
9578
|
+
pointerEvents: 'none',
|
|
9579
|
+
});
|
|
9580
|
+
hint.id = PREFIX + '-page-chat-queue';
|
|
9581
|
+
return hint;
|
|
9582
|
+
}
|
|
9583
|
+
|
|
9584
|
+
function syncSteerQueueHint() {
|
|
9585
|
+
if (!pageChatEl) return;
|
|
9586
|
+
const queued = steerQueuedBehindGeneration();
|
|
9587
|
+
if (queued) {
|
|
9588
|
+
if (!pageChatQueueHintEl) {
|
|
9589
|
+
pageChatQueueHintEl = buildSteerQueueHint();
|
|
9590
|
+
pageChatEl.appendChild(pageChatQueueHintEl);
|
|
9591
|
+
}
|
|
9592
|
+
pageChatQueueHintEl.textContent = STEER_QUEUED_HINT;
|
|
9593
|
+
if (pageChatDotsEl) pageChatDotsEl.style.display = 'none';
|
|
9594
|
+
pageChatEl.style.width = PAGE_CHAT_QUEUED_W;
|
|
9595
|
+
pageChatEl.setAttribute('aria-label', STEER_QUEUED_HINT);
|
|
9596
|
+
return;
|
|
9597
|
+
}
|
|
9598
|
+
if (pageChatQueueHintEl?.parentNode) {
|
|
9599
|
+
pageChatQueueHintEl.remove();
|
|
9600
|
+
pageChatQueueHintEl = null;
|
|
9601
|
+
if (steerLocked) {
|
|
9602
|
+
pageChatEl.style.width = pageChatExpanded ? pageChatExpandedWidth() : PAGE_CHAT_COLLAPSED_W;
|
|
9603
|
+
pageChatEl.setAttribute('aria-label', 'Processing steer request');
|
|
9604
|
+
}
|
|
9605
|
+
}
|
|
9606
|
+
if (pageChatDotsEl) pageChatDotsEl.style.display = '';
|
|
8858
9607
|
}
|
|
8859
9608
|
|
|
8860
9609
|
function shouldFocusSteerChat() {
|
|
@@ -9026,6 +9775,7 @@ void main() {
|
|
|
9026
9775
|
|
|
9027
9776
|
function syncPageChatFocusRing() {
|
|
9028
9777
|
if (!pageChatEl || !pageChatInput) return;
|
|
9778
|
+
syncPageChatSendButton();
|
|
9029
9779
|
const focused = activeElementDeep() === pageChatInput;
|
|
9030
9780
|
const typingReady = focused && !steerLocked;
|
|
9031
9781
|
pageChatEl.dataset.inputFocused = focused ? 'true' : 'false';
|
|
@@ -9179,12 +9929,28 @@ void main() {
|
|
|
9179
9929
|
steerAwaitTimer = setTimeout(() => {
|
|
9180
9930
|
if (!steerLocked || steerRequestId !== id) return;
|
|
9181
9931
|
unlockSteerChat({
|
|
9182
|
-
error:
|
|
9932
|
+
error: steerTimeoutMessage(),
|
|
9183
9933
|
restoreMessage: steerPendingMessage,
|
|
9184
9934
|
});
|
|
9185
9935
|
}, STEER_AWAIT_TIMEOUT_MS);
|
|
9186
9936
|
}
|
|
9187
9937
|
|
|
9938
|
+
/**
|
|
9939
|
+
* Two minutes of silence has three different causes and only one of them is
|
|
9940
|
+
* "live-poll is not running". Naming the wrong one sends the user to restart
|
|
9941
|
+
* a poll loop that was never the problem.
|
|
9942
|
+
*/
|
|
9943
|
+
function steerTimeoutMessage() {
|
|
9944
|
+
const head = 'Steer timed out after 2 minutes. ';
|
|
9945
|
+
if (steerQueuedBehindGeneration()) {
|
|
9946
|
+
return head + 'The agent is still busy with the current generation - your message was not lost, but it never got picked up. Send it again once the variants land.';
|
|
9947
|
+
}
|
|
9948
|
+
if (!agentPollingConnected) {
|
|
9949
|
+
return head + 'No agent is polling right now. Run live-poll.mjs, then send it again.';
|
|
9950
|
+
}
|
|
9951
|
+
return head + 'The agent picked it up but never replied with steer_done. Check the agent session for a stalled or failed steer.';
|
|
9952
|
+
}
|
|
9953
|
+
|
|
9188
9954
|
function lockSteerChat() {
|
|
9189
9955
|
if (!pageChatEl || !pageChatInput) return;
|
|
9190
9956
|
stopVoice({ suppressSubmit: true });
|
|
@@ -9208,6 +9974,7 @@ void main() {
|
|
|
9208
9974
|
pageChatDotsEl = buildSteerProcessingDots();
|
|
9209
9975
|
pageChatEl.appendChild(pageChatDotsEl);
|
|
9210
9976
|
}
|
|
9977
|
+
syncSteerQueueHint();
|
|
9211
9978
|
syncPageChatFocusRing();
|
|
9212
9979
|
syncPageChatChrome();
|
|
9213
9980
|
}
|
|
@@ -9249,6 +10016,10 @@ void main() {
|
|
|
9249
10016
|
pageChatDotsEl.remove();
|
|
9250
10017
|
pageChatDotsEl = null;
|
|
9251
10018
|
}
|
|
10019
|
+
if (pageChatQueueHintEl?.parentNode) {
|
|
10020
|
+
pageChatQueueHintEl.remove();
|
|
10021
|
+
pageChatQueueHintEl = null;
|
|
10022
|
+
}
|
|
9252
10023
|
steerPendingMessage = keepExpanded ? restoreMessage : '';
|
|
9253
10024
|
steerInputWasFocused = false;
|
|
9254
10025
|
syncPageChatChrome();
|
|
@@ -9486,10 +10257,11 @@ void main() {
|
|
|
9486
10257
|
const id = id8();
|
|
9487
10258
|
steerRequestId = id;
|
|
9488
10259
|
steerPendingMessage = text;
|
|
9489
|
-
if (steerInputWasFocused) sendSteerCheckpoint(id, 'steer_input_focused', { focused: true });
|
|
9490
10260
|
lockSteerChat();
|
|
9491
10261
|
scheduleSteerAwaitTimeout(id);
|
|
9492
|
-
|
|
10262
|
+
// Checkpoints follow the steer event, never precede it: the steer event
|
|
10263
|
+
// is what creates the session journal server-side, and a checkpoint for
|
|
10264
|
+
// a not-yet-created session is rejected as unknown_session.
|
|
9493
10265
|
sendEvent({
|
|
9494
10266
|
type: 'steer',
|
|
9495
10267
|
id,
|
|
@@ -9497,9 +10269,11 @@ void main() {
|
|
|
9497
10269
|
pageUrl: location.href,
|
|
9498
10270
|
}).then((res) => {
|
|
9499
10271
|
if (!res) {
|
|
9500
|
-
sendSteerCheckpoint(id, 'steer_send_failed', { message: text });
|
|
9501
10272
|
unlockSteerChat({ error: 'Could not reach live server', restoreMessage: text });
|
|
10273
|
+
return;
|
|
9502
10274
|
}
|
|
10275
|
+
if (steerInputWasFocused) sendSteerCheckpoint(id, 'steer_input_focused', { focused: true });
|
|
10276
|
+
sendSteerCheckpoint(id, 'steer_submitted', { message: text, pageUrl: location.href });
|
|
9503
10277
|
});
|
|
9504
10278
|
}
|
|
9505
10279
|
|
|
@@ -9615,10 +10389,41 @@ void main() {
|
|
|
9615
10389
|
pageChatVoiceBtn.setAttribute('aria-label', 'Voice input');
|
|
9616
10390
|
pageChatVoiceBtn.innerHTML = ICON_PAGE_VOICE;
|
|
9617
10391
|
|
|
10392
|
+
// Visible Send, same affordance the element-level Go bar gets from
|
|
10393
|
+
// buildConfigureSubmitButton. Enter still submits; the button exists so a
|
|
10394
|
+
// typed steer does not look like a dead-end text field.
|
|
10395
|
+
pageChatSendBtn = el('button', {
|
|
10396
|
+
display: 'none', alignItems: 'center', justifyContent: 'center',
|
|
10397
|
+
padding: '0', boxSizing: 'border-box',
|
|
10398
|
+
width: '28px', height: '28px', flexShrink: '0',
|
|
10399
|
+
border: 'none', borderLeft: '1px solid ' + P.hairline,
|
|
10400
|
+
borderRadius: '0',
|
|
10401
|
+
background: P.accent, color: C.ink,
|
|
10402
|
+
cursor: 'pointer',
|
|
10403
|
+
transition: 'filter 0.12s ease, opacity 0.12s ease',
|
|
10404
|
+
});
|
|
10405
|
+
pageChatSendBtn.id = PREFIX + '-page-chat-send';
|
|
10406
|
+
pageChatSendBtn.type = 'button';
|
|
10407
|
+
pageChatSendBtn.setAttribute('aria-label', 'Send steer message');
|
|
10408
|
+
pageChatSendBtn.innerHTML = ICON_CONFIGURE_SUBMIT;
|
|
10409
|
+
pageChatSendBtn.addEventListener('pointerdown', keepSteerPointerInside);
|
|
10410
|
+
pageChatSendBtn.addEventListener('mousedown', keepSteerPointerInside);
|
|
10411
|
+
pageChatSendBtn.addEventListener('mouseenter', () => {
|
|
10412
|
+
if (!pageChatSendBtn.disabled) pageChatSendBtn.style.filter = 'brightness(1.1)';
|
|
10413
|
+
});
|
|
10414
|
+
pageChatSendBtn.addEventListener('mouseleave', () => { pageChatSendBtn.style.filter = 'none'; });
|
|
10415
|
+
pageChatSendBtn.addEventListener('click', (e) => {
|
|
10416
|
+
e.stopPropagation();
|
|
10417
|
+
keepSteerPointerInside(e);
|
|
10418
|
+
if (steerLocked || pageChatSendBtn.disabled) return;
|
|
10419
|
+
submitSteerMessage();
|
|
10420
|
+
});
|
|
10421
|
+
|
|
9618
10422
|
pageChatEl.appendChild(chatIcon);
|
|
9619
10423
|
pageChatEl.appendChild(pageChatHint);
|
|
9620
10424
|
pageChatEl.appendChild(pageChatInput);
|
|
9621
10425
|
pageChatEl.appendChild(pageChatVoiceBtn);
|
|
10426
|
+
pageChatEl.appendChild(pageChatSendBtn);
|
|
9622
10427
|
|
|
9623
10428
|
if (!uiGetById(PREFIX + '-page-chat-style')) {
|
|
9624
10429
|
const s = document.createElement('style');
|
|
@@ -9641,14 +10446,14 @@ void main() {
|
|
|
9641
10446
|
|
|
9642
10447
|
pageChatEl.addEventListener('pointerdown', (e) => {
|
|
9643
10448
|
keepSteerPointerInside(e);
|
|
9644
|
-
if (steerLocked || pageChatVoiceBtn.contains(e.target)) return;
|
|
10449
|
+
if (steerLocked || pageChatVoiceBtn.contains(e.target) || pageChatSendBtn.contains(e.target)) return;
|
|
9645
10450
|
armPageChatForTyping({ expand: true, focus: false });
|
|
9646
10451
|
});
|
|
9647
10452
|
pageChatEl.addEventListener('mousedown', keepSteerPointerInside);
|
|
9648
10453
|
pageChatEl.addEventListener('click', (e) => {
|
|
9649
10454
|
keepSteerPointerInside(e);
|
|
9650
10455
|
if (steerLocked) return;
|
|
9651
|
-
if (pageChatVoiceBtn.contains(e.target)) return;
|
|
10456
|
+
if (pageChatVoiceBtn.contains(e.target) || pageChatSendBtn.contains(e.target)) return;
|
|
9652
10457
|
armPageChatForTyping({ expand: true, focus: true });
|
|
9653
10458
|
});
|
|
9654
10459
|
|
|
@@ -9669,6 +10474,7 @@ void main() {
|
|
|
9669
10474
|
|
|
9670
10475
|
pageChatInput.addEventListener('input', () => {
|
|
9671
10476
|
syncPageChatVisual();
|
|
10477
|
+
syncPageChatSendButton();
|
|
9672
10478
|
});
|
|
9673
10479
|
|
|
9674
10480
|
pageChatInput.addEventListener('focus', () => {
|
|
@@ -9739,6 +10545,7 @@ void main() {
|
|
|
9739
10545
|
|
|
9740
10546
|
function syncAgentPollingUi(connected) {
|
|
9741
10547
|
agentPollingConnected = !!connected;
|
|
10548
|
+
syncSteerQueueHint();
|
|
9742
10549
|
if (!globalBarBrandEl) return;
|
|
9743
10550
|
const P = barPaletteForTheme(globalBarEl?.dataset.theme || detectPageTheme());
|
|
9744
10551
|
agentStatusMessage = agentStatusText();
|
|
@@ -11033,7 +11840,28 @@ void main() {
|
|
|
11033
11840
|
|
|
11034
11841
|
// Unified render: merge parsed DESIGN.md frontmatter with sidecar v2
|
|
11035
11842
|
|
|
11843
|
+
/**
|
|
11844
|
+
* The empty state has to say which emptiness it is. `present:false` (no
|
|
11845
|
+
* DESIGN.md at all) is handled upstream in renderDesignBody; everything here
|
|
11846
|
+
* means the helper found a design system and this panel found nothing in it
|
|
11847
|
+
* worth drawing. Telling that user "no design system data" reads as "your
|
|
11848
|
+
* DESIGN.md is missing" and sends them to write a file they already have.
|
|
11849
|
+
*/
|
|
11850
|
+
function designEmptyMessage() {
|
|
11851
|
+
if (designState.hasMd && !designState.hasSidecar) {
|
|
11852
|
+
return 'DESIGN.md found, no structured tokens to display. Run ' + IMPECCABLE_COMMAND + ' document to generate the .impeccable/design.json sidecar.';
|
|
11853
|
+
}
|
|
11854
|
+
if (designState.hasMd) {
|
|
11855
|
+
return 'DESIGN.md and its sidecar were found, but neither carries colors, type, radii, or components to display.';
|
|
11856
|
+
}
|
|
11857
|
+
return 'No design system data available.';
|
|
11858
|
+
}
|
|
11859
|
+
|
|
11036
11860
|
function renderDesignVisual(body, parsed, sidecar) {
|
|
11861
|
+
// Count only what this function draws: renderDesignBody may already have
|
|
11862
|
+
// appended a stale-sidecar hint or the basic-view CTA, and those must not
|
|
11863
|
+
// pass for token content.
|
|
11864
|
+
const beforeCount = body.childElementCount;
|
|
11037
11865
|
const frontmatter = parsed?.frontmatter || {};
|
|
11038
11866
|
const extensions = sidecar?.extensions || {};
|
|
11039
11867
|
const proseColors = parsed?.colors || null;
|
|
@@ -11061,8 +11889,8 @@ void main() {
|
|
|
11061
11889
|
body.appendChild(renderOverviewCollapsible(narrative));
|
|
11062
11890
|
}
|
|
11063
11891
|
|
|
11064
|
-
if (body.childElementCount ===
|
|
11065
|
-
body.appendChild(msgDiv('empty',
|
|
11892
|
+
if (body.childElementCount === beforeCount) {
|
|
11893
|
+
body.appendChild(msgDiv('empty', designEmptyMessage()));
|
|
11066
11894
|
}
|
|
11067
11895
|
}
|
|
11068
11896
|
|
|
@@ -11147,7 +11975,9 @@ void main() {
|
|
|
11147
11975
|
rules: [
|
|
11148
11976
|
...(md.colors?.rules || []).map((r) => ({ ...r, section: 'colors' })),
|
|
11149
11977
|
...(md.typography?.rules || []).map((r) => ({ ...r, section: 'typography' })),
|
|
11978
|
+
...(md.layout?.rules || []).map((r) => ({ ...r, section: 'layout' })),
|
|
11150
11979
|
...(md.elevation?.rules || []).map((r) => ({ ...r, section: 'elevation' })),
|
|
11980
|
+
...(md.shapes?.rules || []).map((r) => ({ ...r, section: 'shapes' })),
|
|
11151
11981
|
],
|
|
11152
11982
|
dos: md.dosDonts?.dos || [],
|
|
11153
11983
|
donts: md.dosDonts?.donts || [],
|