@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
|
@@ -0,0 +1,969 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AST-based Svelte scaffolding for live component previews.
|
|
3
|
+
*
|
|
4
|
+
* The scaffolder turns the selected block of a route's markup into a detached
|
|
5
|
+
* preview component whose dynamic values arrive as props. The old
|
|
6
|
+
* implementation matched `{...}` with a regex, which flattened control-flow
|
|
7
|
+
* blocks ({#each}, {#if}) into scalar text props and shipped structurally
|
|
8
|
+
* wrong previews. This module uses the app's own svelte compiler
|
|
9
|
+
* (parse with modern: true) and replaces only expressions that are FREE,
|
|
10
|
+
* i.e. reference identifiers not bound by an enclosing template scope:
|
|
11
|
+
*
|
|
12
|
+
* {#each stages as stage, i} stages -> collection prop (array)
|
|
13
|
+
* <span>{stage.label}</span> bound -> left verbatim
|
|
14
|
+
* {/each}
|
|
15
|
+
* <p>{footerNote}</p> free -> text prop (string)
|
|
16
|
+
*
|
|
17
|
+
* Constructs that cannot work in a detached component (component tags whose
|
|
18
|
+
* imports live in the route file, bind:/use: directives, await blocks,
|
|
19
|
+
* render tags) mark the analysis unsupported; the caller falls back to
|
|
20
|
+
* source-preview mode, which keeps the markup inside the route file where
|
|
21
|
+
* those references still resolve. A wrong preview is worse than a plain one.
|
|
22
|
+
*
|
|
23
|
+
* The compiler is resolved from the APP's node_modules, never bundled: the
|
|
24
|
+
* preview must be parsed by the same svelte version that will compile it.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { createRequire } from 'node:module';
|
|
28
|
+
import path from 'node:path';
|
|
29
|
+
|
|
30
|
+
const HANDLER_ATTR_RE = /^on[a-z]/;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the app's svelte compiler synchronously (svelte 5 ships a CJS
|
|
34
|
+
* compiler build, so createRequire works and the accept/scaffold pipeline
|
|
35
|
+
* stays synchronous). Returns { parse, compile, VERSION } or null.
|
|
36
|
+
*/
|
|
37
|
+
export function loadSvelteCompiler(appRoot) {
|
|
38
|
+
try {
|
|
39
|
+
const req = createRequire(path.join(appRoot, 'package.json'));
|
|
40
|
+
const mod = req('svelte/compiler');
|
|
41
|
+
if (typeof mod.parse !== 'function') return null;
|
|
42
|
+
const major = parseInt(String(mod.VERSION || '0'), 10);
|
|
43
|
+
if (major < 5) return null; // detached mount() previews are svelte 5 only
|
|
44
|
+
return { parse: mod.parse, compile: mod.compile, VERSION: mod.VERSION };
|
|
45
|
+
} catch {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// ESTree helpers
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Collect the root identifiers an ESTree expression reads. Walks generically;
|
|
56
|
+
* skips non-computed member properties and non-computed/non-shorthand object
|
|
57
|
+
* keys, which are names, not references.
|
|
58
|
+
*/
|
|
59
|
+
export function collectRootIdentifiers(node, out = new Set()) {
|
|
60
|
+
if (!node || typeof node !== 'object') return out;
|
|
61
|
+
if (Array.isArray(node)) {
|
|
62
|
+
for (const item of node) collectRootIdentifiers(item, out);
|
|
63
|
+
return out;
|
|
64
|
+
}
|
|
65
|
+
switch (node.type) {
|
|
66
|
+
case 'Identifier':
|
|
67
|
+
out.add(node.name);
|
|
68
|
+
return out;
|
|
69
|
+
case 'MemberExpression':
|
|
70
|
+
collectRootIdentifiers(node.object, out);
|
|
71
|
+
if (node.computed) collectRootIdentifiers(node.property, out);
|
|
72
|
+
return out;
|
|
73
|
+
case 'Property':
|
|
74
|
+
if (node.computed) collectRootIdentifiers(node.key, out);
|
|
75
|
+
collectRootIdentifiers(node.value, out);
|
|
76
|
+
return out;
|
|
77
|
+
case 'ArrowFunctionExpression':
|
|
78
|
+
case 'FunctionExpression': {
|
|
79
|
+
// Params shadow outer names inside the body.
|
|
80
|
+
const bound = new Set();
|
|
81
|
+
for (const param of node.params || []) collectPatternNames(param, bound);
|
|
82
|
+
const inner = collectRootIdentifiers(node.body, new Set());
|
|
83
|
+
for (const name of inner) if (!bound.has(name)) out.add(name);
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
default: {
|
|
87
|
+
for (const key of Object.keys(node)) {
|
|
88
|
+
if (key === 'type' || key === 'start' || key === 'end' || key === 'loc' || key === 'range' || key === 'parent') continue;
|
|
89
|
+
collectRootIdentifiers(node[key], out);
|
|
90
|
+
}
|
|
91
|
+
return out;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Collect names bound by a destructuring pattern (each contexts, const tags). */
|
|
97
|
+
export function collectPatternNames(pattern, out = new Set()) {
|
|
98
|
+
if (!pattern || typeof pattern !== 'object') return out;
|
|
99
|
+
switch (pattern.type) {
|
|
100
|
+
case 'Identifier':
|
|
101
|
+
out.add(pattern.name);
|
|
102
|
+
return out;
|
|
103
|
+
case 'ObjectPattern':
|
|
104
|
+
for (const prop of pattern.properties || []) {
|
|
105
|
+
if (prop.type === 'RestElement') collectPatternNames(prop.argument, out);
|
|
106
|
+
else collectPatternNames(prop.value, out);
|
|
107
|
+
}
|
|
108
|
+
return out;
|
|
109
|
+
case 'ArrayPattern':
|
|
110
|
+
for (const el of pattern.elements || []) if (el) collectPatternNames(el, out);
|
|
111
|
+
return out;
|
|
112
|
+
case 'AssignmentPattern':
|
|
113
|
+
collectPatternNames(pattern.left, out);
|
|
114
|
+
return out;
|
|
115
|
+
case 'RestElement':
|
|
116
|
+
collectPatternNames(pattern.argument, out);
|
|
117
|
+
return out;
|
|
118
|
+
default:
|
|
119
|
+
return out;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// Template analysis
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
class Analysis {
|
|
128
|
+
constructor(source) {
|
|
129
|
+
this.source = source;
|
|
130
|
+
this.replacements = []; // { start, end, prop } source ranges to swap
|
|
131
|
+
this.contract = []; // [{ prop, expr, kind, ... }]
|
|
132
|
+
this.byExpr = new Map(); // expr text -> contract entry
|
|
133
|
+
this.usedNames = new Set();
|
|
134
|
+
this.unsupported = null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
fail(reason) {
|
|
138
|
+
if (!this.unsupported) this.unsupported = reason;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
propFor(exprText, kind, extra = {}) {
|
|
142
|
+
const existing = this.byExpr.get(exprText);
|
|
143
|
+
if (existing) return existing;
|
|
144
|
+
const base = derivePropName(exprText);
|
|
145
|
+
let name = base;
|
|
146
|
+
let n = 2;
|
|
147
|
+
while (this.usedNames.has(name)) name = `${base}${n++}`;
|
|
148
|
+
this.usedNames.add(name);
|
|
149
|
+
const entry = { prop: name, expr: exprText, kind, ...extra };
|
|
150
|
+
this.byExpr.set(exprText, entry);
|
|
151
|
+
this.contract.push(entry);
|
|
152
|
+
return entry;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// A derived prop name lands in `let { <name> } = $props()`; a reserved word
|
|
157
|
+
// there is a syntax error the session only hits at import time.
|
|
158
|
+
const RESERVED_PROP_NAMES = new Set([
|
|
159
|
+
'await', 'break', 'case', 'catch', 'class', 'const', 'continue', 'debugger',
|
|
160
|
+
'default', 'delete', 'do', 'else', 'enum', 'export', 'extends', 'false',
|
|
161
|
+
'finally', 'for', 'function', 'if', 'implements', 'import', 'in',
|
|
162
|
+
'instanceof', 'interface', 'let', 'new', 'null', 'package', 'private',
|
|
163
|
+
'protected', 'public', 'return', 'static', 'super', 'switch', 'this',
|
|
164
|
+
'throw', 'true', 'try', 'typeof', 'undefined', 'var', 'void', 'while',
|
|
165
|
+
'with', 'yield',
|
|
166
|
+
]);
|
|
167
|
+
|
|
168
|
+
export function derivePropName(expr) {
|
|
169
|
+
const tail = String(expr).match(/(?:\.|\[["']?)([A-Za-z_$][\w$]*)["']?\]?\s*$/);
|
|
170
|
+
const candidate = (tail && tail[1])
|
|
171
|
+
|| (String(expr).match(/^([A-Za-z_$][\w$]*)$/) || [])[1]
|
|
172
|
+
|| 'value';
|
|
173
|
+
return RESERVED_PROP_NAMES.has(candidate) ? `${candidate}Value` : candidate;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function exprText(source, node) {
|
|
177
|
+
return source.slice(node.start, node.end);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Identifiers that resolve in ANY module scope. They are neither hydratable
|
|
181
|
+
// props nor evidence of route coupling, so they count as neither free nor
|
|
182
|
+
// bound: `{Math.round(x)}` must not mint a prop named `round`, and
|
|
183
|
+
// `{fmt(stage.label)}` must not pass as global-only.
|
|
184
|
+
const GLOBAL_IDENTIFIERS = new Set([
|
|
185
|
+
'Math', 'JSON', 'Date', 'Intl', 'Number', 'String', 'Boolean', 'Array',
|
|
186
|
+
'Object', 'Map', 'Set', 'Promise', 'RegExp', 'NaN', 'Infinity', 'undefined',
|
|
187
|
+
'isNaN', 'isFinite', 'parseInt', 'parseFloat', 'encodeURIComponent',
|
|
188
|
+
'decodeURIComponent', 'console', 'window', 'document', 'navigator',
|
|
189
|
+
'location', 'structuredClone', 'crypto',
|
|
190
|
+
]);
|
|
191
|
+
|
|
192
|
+
function classifyRoots(node, scopes) {
|
|
193
|
+
const roots = collectRootIdentifiers(node);
|
|
194
|
+
let bound = 0;
|
|
195
|
+
let free = 0;
|
|
196
|
+
for (const name of roots) {
|
|
197
|
+
if (GLOBAL_IDENTIFIERS.has(name)) continue;
|
|
198
|
+
if (scopes.some((scope) => scope.has(name))) bound++;
|
|
199
|
+
else free++;
|
|
200
|
+
}
|
|
201
|
+
return { bound, free };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function isFree(node, scopes) {
|
|
205
|
+
const { bound, free } = classifyRoots(node, scopes);
|
|
206
|
+
return free > 0 && bound === 0;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* An expression mixing loop-bound and outer free identifiers (e.g.
|
|
211
|
+
* `{fmt(stage.label)}` where `fmt` lives in the route script) can neither
|
|
212
|
+
* become a prop (the bound part varies per item) nor survive detachment
|
|
213
|
+
* verbatim (the free name is undeclared in the preview and throws at mount,
|
|
214
|
+
* past the compile gate, because globals make it legal to the compiler).
|
|
215
|
+
* Source-preview mode is the only correct home for it.
|
|
216
|
+
*/
|
|
217
|
+
function failOnMixedExpression(node, scopes, analysis, source) {
|
|
218
|
+
const { bound, free } = classifyRoots(node, scopes);
|
|
219
|
+
if (bound > 0 && free > 0) {
|
|
220
|
+
analysis.fail(`expression mixing loop and outer identifiers ({${exprText(source, node).slice(0, 60)}}) requires source-preview mode`);
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Analyze a parsed template fragment. `scopes` is a stack of Sets of bound
|
|
228
|
+
* names; the outermost call passes an empty stack.
|
|
229
|
+
*/
|
|
230
|
+
function analyzeFragment(fragment, analysis, scopes) {
|
|
231
|
+
if (!fragment || !Array.isArray(fragment.nodes)) return;
|
|
232
|
+
// ConstTag declarations bind for the whole fragment.
|
|
233
|
+
const fragmentScope = new Set();
|
|
234
|
+
const nextScopes = [...scopes, fragmentScope];
|
|
235
|
+
for (const node of fragment.nodes) {
|
|
236
|
+
if (node.type === 'ConstTag' && node.declaration) {
|
|
237
|
+
for (const decl of node.declaration.declarations || []) {
|
|
238
|
+
collectPatternNames(decl.id, fragmentScope);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
for (const node of fragment.nodes) analyzeNode(node, analysis, nextScopes);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function analyzeNode(node, analysis, scopes) {
|
|
246
|
+
if (!node || analysis.unsupported) return;
|
|
247
|
+
switch (node.type) {
|
|
248
|
+
case 'Text':
|
|
249
|
+
case 'Comment':
|
|
250
|
+
return;
|
|
251
|
+
case 'ExpressionTag': {
|
|
252
|
+
if (failOnMixedExpression(node.expression, scopes, analysis, analysis.source)) return;
|
|
253
|
+
if (isFree(node.expression, scopes)) {
|
|
254
|
+
const text = exprText(analysis.source, node.expression);
|
|
255
|
+
const entry = analysis.propFor(text, 'text');
|
|
256
|
+
// node.start/end include the braces; keep them, swap the inside.
|
|
257
|
+
analysis.replacements.push({ start: node.expression.start, end: node.expression.end, prop: entry.prop });
|
|
258
|
+
}
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
case 'HtmlTag': {
|
|
262
|
+
if (failOnMixedExpression(node.expression, scopes, analysis, analysis.source)) return;
|
|
263
|
+
if (isFree(node.expression, scopes)) {
|
|
264
|
+
const text = exprText(analysis.source, node.expression);
|
|
265
|
+
const entry = analysis.propFor(text, 'raw');
|
|
266
|
+
analysis.replacements.push({ start: node.expression.start, end: node.expression.end, prop: entry.prop });
|
|
267
|
+
}
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
case 'ConstTag': {
|
|
271
|
+
// Its expression may read free names; leave them: the declaration
|
|
272
|
+
// travels with the markup and stays valid only if its inputs do.
|
|
273
|
+
if (node.declaration) {
|
|
274
|
+
for (const decl of node.declaration.declarations || []) {
|
|
275
|
+
if (decl.init && failOnMixedExpression(decl.init, scopes, analysis, analysis.source)) return;
|
|
276
|
+
if (decl.init && isFree(decl.init, scopes)) {
|
|
277
|
+
const text = exprText(analysis.source, decl.init);
|
|
278
|
+
const entry = analysis.propFor(text, 'text');
|
|
279
|
+
analysis.replacements.push({ start: decl.init.start, end: decl.init.end, prop: entry.prop });
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
case 'EachBlock': {
|
|
286
|
+
if (failOnMixedExpression(node.expression, scopes, analysis, analysis.source)) return;
|
|
287
|
+
if (isFree(node.expression, scopes)) {
|
|
288
|
+
const text = exprText(analysis.source, node.expression);
|
|
289
|
+
const item = describeEachItem(node, analysis.source);
|
|
290
|
+
// Keyed each: the key must evaluate to a distinct value per hydrated
|
|
291
|
+
// item or Svelte throws each_key_duplicate at mount. A key that is a
|
|
292
|
+
// plain member of the item (the common `(item.id)` shape) gets a
|
|
293
|
+
// synthetic per-index value injected by the browser (keyField).
|
|
294
|
+
// Anything else cannot be hydrated safely; source-preview mode keeps
|
|
295
|
+
// it correct.
|
|
296
|
+
if (node.key) {
|
|
297
|
+
const keyInfo = classifyEachKey(node);
|
|
298
|
+
if (keyInfo.unsupported) {
|
|
299
|
+
analysis.fail(keyInfo.unsupported);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (keyInfo.keyField) {
|
|
303
|
+
if (item.textSlots.some((slot) => slot.key === keyInfo.keyField)) {
|
|
304
|
+
// The key doubles as a displayed slot; a synthetic value would
|
|
305
|
+
// change visible text, and the displayed text may not be
|
|
306
|
+
// unique. Not previewable in a detached component.
|
|
307
|
+
analysis.fail('each key that is also a displayed field requires source-preview mode');
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
item.keyField = keyInfo.keyField;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const entry = analysis.propFor(text, 'collection', { item });
|
|
314
|
+
analysis.replacements.push({ start: node.expression.start, end: node.expression.end, prop: entry.prop });
|
|
315
|
+
}
|
|
316
|
+
const bound = new Set();
|
|
317
|
+
if (node.context) collectPatternNames(node.context, bound);
|
|
318
|
+
if (node.index) bound.add(node.index);
|
|
319
|
+
analyzeFragment(node.body, analysis, [...scopes, bound]);
|
|
320
|
+
if (node.fallback) analyzeFragment(node.fallback, analysis, scopes);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
case 'IfBlock': {
|
|
324
|
+
if (failOnMixedExpression(node.test, scopes, analysis, analysis.source)) return;
|
|
325
|
+
if (isFree(node.test, scopes)) {
|
|
326
|
+
const text = exprText(analysis.source, node.test);
|
|
327
|
+
// The browser hydrates a free condition from what the live page
|
|
328
|
+
// currently shows: when the consequent's root element is present
|
|
329
|
+
// under the picked element, the condition is on.
|
|
330
|
+
const entry = analysis.propFor(text, 'condition', {
|
|
331
|
+
probe: describeElementProbe(node.consequent),
|
|
332
|
+
});
|
|
333
|
+
analysis.replacements.push({ start: node.test.start, end: node.test.end, prop: entry.prop });
|
|
334
|
+
}
|
|
335
|
+
analyzeFragment(node.consequent, analysis, scopes);
|
|
336
|
+
if (node.alternate) analyzeFragment(node.alternate, analysis, scopes);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
case 'KeyBlock': {
|
|
340
|
+
if (failOnMixedExpression(node.expression, scopes, analysis, analysis.source)) return;
|
|
341
|
+
if (isFree(node.expression, scopes)) {
|
|
342
|
+
const text = exprText(analysis.source, node.expression);
|
|
343
|
+
const entry = analysis.propFor(text, 'text');
|
|
344
|
+
analysis.replacements.push({ start: node.expression.start, end: node.expression.end, prop: entry.prop });
|
|
345
|
+
}
|
|
346
|
+
analyzeFragment(node.fragment, analysis, scopes);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
case 'SnippetBlock': {
|
|
350
|
+
const bound = new Set();
|
|
351
|
+
for (const param of node.parameters || []) collectPatternNames(param, bound);
|
|
352
|
+
// The snippet's own name becomes available to render tags in this file.
|
|
353
|
+
analyzeFragment(node.body, analysis, [...scopes, bound]);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
case 'RegularElement':
|
|
357
|
+
case 'SlotElement':
|
|
358
|
+
case 'TitleElement': {
|
|
359
|
+
if (node.name === 'script') {
|
|
360
|
+
// An inline script inside the selected block carries route-scoped
|
|
361
|
+
// code; running it a second time from a detached preview is wrong.
|
|
362
|
+
analysis.fail('inline script element requires source-preview mode');
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
analyzeAttributes(node, analysis, scopes);
|
|
366
|
+
if (!analysis.unsupported) analyzeFragment(node.fragment, analysis, scopes);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
case 'SvelteElement':
|
|
370
|
+
case 'SvelteFragment':
|
|
371
|
+
case 'SvelteBoundary': {
|
|
372
|
+
analyzeAttributes(node, analysis, scopes);
|
|
373
|
+
if (!analysis.unsupported) analyzeFragment(node.fragment, analysis, scopes);
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
case 'Component':
|
|
377
|
+
case 'SvelteComponent':
|
|
378
|
+
case 'SvelteSelf':
|
|
379
|
+
// The component's import lives in the route file; a detached preview
|
|
380
|
+
// cannot resolve it. Source-preview mode keeps it working.
|
|
381
|
+
analysis.fail(`component tag <${node.name || 'Component'}> requires source-preview mode`);
|
|
382
|
+
return;
|
|
383
|
+
case 'RenderTag':
|
|
384
|
+
analysis.fail('render tag requires source-preview mode');
|
|
385
|
+
return;
|
|
386
|
+
case 'AwaitBlock':
|
|
387
|
+
analysis.fail('await block requires source-preview mode');
|
|
388
|
+
return;
|
|
389
|
+
case 'SvelteHead':
|
|
390
|
+
case 'SvelteWindow':
|
|
391
|
+
case 'SvelteDocument':
|
|
392
|
+
case 'SvelteBody':
|
|
393
|
+
analysis.fail(`${node.type} requires source-preview mode`);
|
|
394
|
+
return;
|
|
395
|
+
default: {
|
|
396
|
+
if (node.fragment) analyzeFragment(node.fragment, analysis, scopes);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function analyzeAttributes(node, analysis, scopes) {
|
|
403
|
+
for (const attr of node.attributes || []) {
|
|
404
|
+
switch (attr.type) {
|
|
405
|
+
case 'Attribute': {
|
|
406
|
+
if (attr.value === true) break;
|
|
407
|
+
const parts = Array.isArray(attr.value) ? attr.value : [attr.value];
|
|
408
|
+
for (const part of parts) {
|
|
409
|
+
if (!part || part.type !== 'ExpressionTag') continue;
|
|
410
|
+
if (failOnMixedExpression(part.expression, scopes, analysis, analysis.source)) return;
|
|
411
|
+
if (!isFree(part.expression, scopes)) continue;
|
|
412
|
+
const text = exprText(analysis.source, part.expression);
|
|
413
|
+
const kind = HANDLER_ATTR_RE.test(attr.name) ? 'handler' : 'text';
|
|
414
|
+
const entry = analysis.propFor(text, kind);
|
|
415
|
+
analysis.replacements.push({ start: part.expression.start, end: part.expression.end, prop: entry.prop });
|
|
416
|
+
}
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
419
|
+
case 'ClassDirective': {
|
|
420
|
+
const expr = attr.expression;
|
|
421
|
+
if (expr && failOnMixedExpression(expr, scopes, analysis, analysis.source)) return;
|
|
422
|
+
if (expr && isFree(expr, scopes)) {
|
|
423
|
+
const text = exprText(analysis.source, expr);
|
|
424
|
+
// The directive's class name is literal, so the live DOM answers
|
|
425
|
+
// the condition directly: the class is either present or not.
|
|
426
|
+
const entry = analysis.propFor(text, 'condition', {
|
|
427
|
+
probe: { className: attr.name },
|
|
428
|
+
});
|
|
429
|
+
analysis.replacements.push({ start: expr.start, end: expr.end, prop: entry.prop });
|
|
430
|
+
}
|
|
431
|
+
break;
|
|
432
|
+
}
|
|
433
|
+
case 'StyleDirective': {
|
|
434
|
+
// Unlike ClassDirective, a style directive stores its value in
|
|
435
|
+
// attribute shape: `true` for the shorthand, else an array of parts.
|
|
436
|
+
const parts = attr.value === true ? [] : (Array.isArray(attr.value) ? attr.value : [attr.value]);
|
|
437
|
+
for (const part of parts) {
|
|
438
|
+
if (part?.type === 'ExpressionTag'
|
|
439
|
+
&& failOnMixedExpression(part.expression, scopes, analysis, analysis.source)) {
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
const dynamic = parts.some((part) => part?.type === 'ExpressionTag' && isFree(part.expression, scopes));
|
|
444
|
+
const shorthandFree = attr.value === true && isFree({ type: 'Identifier', name: attr.name }, scopes);
|
|
445
|
+
if (dynamic || shorthandFree) {
|
|
446
|
+
// style:opacity={x} carries a css VALUE, not a boolean, and the
|
|
447
|
+
// computed value on the live element is not reliably recoverable in
|
|
448
|
+
// the shape the expression produced. A falsified style is worse
|
|
449
|
+
// than an HMR-resetting preview.
|
|
450
|
+
analysis.fail(`style:${attr.name} with a dynamic value requires source-preview mode`);
|
|
451
|
+
}
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
case 'BindDirective':
|
|
455
|
+
analysis.fail(`bind:${attr.name} requires source-preview mode`);
|
|
456
|
+
return;
|
|
457
|
+
case 'UseDirective':
|
|
458
|
+
analysis.fail(`use:${attr.name} requires source-preview mode`);
|
|
459
|
+
return;
|
|
460
|
+
case 'AnimateDirective':
|
|
461
|
+
case 'TransitionDirective':
|
|
462
|
+
// Motion directives reference route-scoped or svelte/transition
|
|
463
|
+
// imports; a detached preview cannot resolve them.
|
|
464
|
+
analysis.fail(`${attr.type} requires source-preview mode`);
|
|
465
|
+
return;
|
|
466
|
+
case 'OnDirective': {
|
|
467
|
+
// Legacy on:click syntax; treat like handler attributes.
|
|
468
|
+
const expr = attr.expression;
|
|
469
|
+
if (expr && failOnMixedExpression(expr, scopes, analysis, analysis.source)) return;
|
|
470
|
+
if (expr && isFree(expr, scopes)) {
|
|
471
|
+
const text = exprText(analysis.source, expr);
|
|
472
|
+
const entry = analysis.propFor(text, 'handler');
|
|
473
|
+
analysis.replacements.push({ start: expr.start, end: expr.end, prop: entry.prop });
|
|
474
|
+
}
|
|
475
|
+
break;
|
|
476
|
+
}
|
|
477
|
+
case 'SpreadAttribute':
|
|
478
|
+
analysis.fail('spread attribute requires source-preview mode');
|
|
479
|
+
return;
|
|
480
|
+
default:
|
|
481
|
+
break;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* Describe the repeating item of an each block for browser-side hydration:
|
|
488
|
+
* the item's root element (tag + static classes, used to count live
|
|
489
|
+
* iterations) and the ordered text slots that reference loop bindings.
|
|
490
|
+
*/
|
|
491
|
+
function describeEachItem(node, source) {
|
|
492
|
+
const body = node.body;
|
|
493
|
+
const rootEl = (body?.nodes || []).find((n) => n.type === 'RegularElement');
|
|
494
|
+
|
|
495
|
+
const textSlots = [];
|
|
496
|
+
const staticTexts = [];
|
|
497
|
+
let nestedUnsupported = false;
|
|
498
|
+
const collectStatics = (fragment) => {
|
|
499
|
+
for (const child of fragment?.nodes || []) {
|
|
500
|
+
if (child.type === 'Text') {
|
|
501
|
+
const trimmed = String(child.data || '').trim();
|
|
502
|
+
if (trimmed) staticTexts.push(trimmed);
|
|
503
|
+
} else if (child.type === 'IfBlock') {
|
|
504
|
+
collectStatics(child.consequent);
|
|
505
|
+
if (child.alternate) collectStatics(child.alternate);
|
|
506
|
+
} else if (child.type === 'EachBlock') {
|
|
507
|
+
collectStatics(child.body);
|
|
508
|
+
} else if (child.fragment) {
|
|
509
|
+
collectStatics(child.fragment);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
};
|
|
513
|
+
collectStatics(body);
|
|
514
|
+
const attrSlots = [];
|
|
515
|
+
// The hydration item is a SHALLOW object whose string fields are the exact
|
|
516
|
+
// property names the markup accesses, filled from the rendered page. That
|
|
517
|
+
// model supports one item access per slot, optionally wrapped in a global
|
|
518
|
+
// transform ({Math.round(r.score)} hydrates `score`). Shapes it cannot
|
|
519
|
+
// represent split two ways: CRASHY ones would throw at mount time against a
|
|
520
|
+
// shallow item (deep paths like r.meta.label, method calls like r.format())
|
|
521
|
+
// and force the source-preview fallback; LOSSY ones render wrong but safe
|
|
522
|
+
// (bare {r}, multi-access expressions that would double their text) and
|
|
523
|
+
// also fall back in text position, where the damage is visible.
|
|
524
|
+
const boundAs = (name, scopeInfos) => {
|
|
525
|
+
for (let i = scopeInfos.length - 1; i >= 0; i--) {
|
|
526
|
+
const info = scopeInfos[i];
|
|
527
|
+
if (info.indexName === name) return 'index';
|
|
528
|
+
if (info.itemName === name) return 'item';
|
|
529
|
+
if (info.names.has(name)) return 'field';
|
|
530
|
+
}
|
|
531
|
+
return null;
|
|
532
|
+
};
|
|
533
|
+
const slotKeysOf = (expression, scopeInfos) => {
|
|
534
|
+
const keys = new Set();
|
|
535
|
+
let crashy = false;
|
|
536
|
+
let lossy = false;
|
|
537
|
+
let touches = false;
|
|
538
|
+
const visit = (node, ctx) => {
|
|
539
|
+
if (!node || typeof node !== 'object' || crashy) return;
|
|
540
|
+
if (Array.isArray(node)) {
|
|
541
|
+
for (const item of node) visit(item, {});
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
switch (node.type) {
|
|
545
|
+
case 'Identifier': {
|
|
546
|
+
const kind = boundAs(node.name, scopeInfos);
|
|
547
|
+
if (!kind) return;
|
|
548
|
+
touches = true;
|
|
549
|
+
if (kind === 'index') return; // the runtime each provides it
|
|
550
|
+
if (kind === 'item') { lossy = true; return; } // bare item reference
|
|
551
|
+
if (ctx.callee) { crashy = true; return; } // field() on a hydrated string
|
|
552
|
+
keys.add(node.name); // destructured context field
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
case 'MemberExpression': {
|
|
556
|
+
if (
|
|
557
|
+
!node.computed
|
|
558
|
+
&& node.object?.type === 'Identifier'
|
|
559
|
+
&& boundAs(node.object.name, scopeInfos) === 'item'
|
|
560
|
+
&& node.property?.type === 'Identifier'
|
|
561
|
+
) {
|
|
562
|
+
touches = true;
|
|
563
|
+
// item.a.b or item.method(): a shallow string field throws here.
|
|
564
|
+
if (ctx.memberObject || ctx.callee) { crashy = true; return; }
|
|
565
|
+
keys.add(node.property.name);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
visit(node.object, { memberObject: true });
|
|
569
|
+
if (node.computed) visit(node.property, {});
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
case 'CallExpression':
|
|
573
|
+
visit(node.callee, { callee: true });
|
|
574
|
+
for (const arg of node.arguments || []) visit(arg, {});
|
|
575
|
+
return;
|
|
576
|
+
case 'ArrowFunctionExpression':
|
|
577
|
+
case 'FunctionExpression': {
|
|
578
|
+
// Closures cannot hydrate; only lossy when they capture the item.
|
|
579
|
+
const roots = collectRootIdentifiers(node);
|
|
580
|
+
if ([...roots].some((name) => boundAs(name, scopeInfos))) { touches = true; lossy = true; }
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
case 'Property':
|
|
584
|
+
if (node.computed) visit(node.key, {});
|
|
585
|
+
visit(node.value, {});
|
|
586
|
+
return;
|
|
587
|
+
default: {
|
|
588
|
+
for (const key of Object.keys(node)) {
|
|
589
|
+
if (key === 'type' || key === 'start' || key === 'end' || key === 'loc' || key === 'range' || key === 'parent') continue;
|
|
590
|
+
visit(node[key], {});
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
visit(expression, {});
|
|
596
|
+
if (crashy) return { crashy: true };
|
|
597
|
+
if (lossy || keys.size > 1) return { lossy: true };
|
|
598
|
+
if (!touches || keys.size === 0) return { skip: true };
|
|
599
|
+
return { key: [...keys][0] };
|
|
600
|
+
};
|
|
601
|
+
const staticClassesOf = (el) => {
|
|
602
|
+
const classes = [];
|
|
603
|
+
for (const attr of el?.attributes || []) {
|
|
604
|
+
if (attr.type === 'Attribute' && attr.name === 'class' && Array.isArray(attr.value)) {
|
|
605
|
+
for (const part of attr.value) {
|
|
606
|
+
if (part.type === 'Text') classes.push(...part.data.split(/\s+/).filter(Boolean));
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
return classes;
|
|
611
|
+
};
|
|
612
|
+
const scopeInfoOf = (eachNode) => {
|
|
613
|
+
const names = new Set();
|
|
614
|
+
if (eachNode.context) collectPatternNames(eachNode.context, names);
|
|
615
|
+
return {
|
|
616
|
+
names,
|
|
617
|
+
itemName: eachNode.context?.type === 'Identifier' ? eachNode.context.name : null,
|
|
618
|
+
indexName: eachNode.index || null,
|
|
619
|
+
};
|
|
620
|
+
};
|
|
621
|
+
const walkForSlots = (fragment, scopeInfos) => {
|
|
622
|
+
for (const child of fragment?.nodes || []) {
|
|
623
|
+
if (child.type === 'ExpressionTag') {
|
|
624
|
+
const slot = slotKeysOf(child.expression, scopeInfos);
|
|
625
|
+
if (slot.crashy || slot.lossy) { nestedUnsupported = true; continue; }
|
|
626
|
+
if (slot.skip) continue;
|
|
627
|
+
textSlots.push({ key: slot.key, expr: exprText(source, child.expression) });
|
|
628
|
+
} else if (child.type === 'RegularElement' || child.type === 'SvelteElement') {
|
|
629
|
+
// Bound values in ATTRIBUTES (href={link.href}, src={item.img}) are
|
|
630
|
+
// part of the item too: the browser reads the rendered attribute off
|
|
631
|
+
// the live element, so the preview does not mount with empty links.
|
|
632
|
+
// Only a single-expression attribute hydrates exactly; a mixed value
|
|
633
|
+
// ("card {r.status}") stays unhydrated because the rendered attribute
|
|
634
|
+
// is not separable into its parts, which was the prior behavior.
|
|
635
|
+
for (const attr of child.attributes || []) {
|
|
636
|
+
if (attr.type !== 'Attribute' || attr.value === true) continue;
|
|
637
|
+
if (HANDLER_ATTR_RE.test(attr.name)) continue; // functions cannot hydrate
|
|
638
|
+
const parts = Array.isArray(attr.value) ? attr.value : [attr.value];
|
|
639
|
+
const exprParts = parts.filter((part) => part?.type === 'ExpressionTag');
|
|
640
|
+
for (const part of exprParts) {
|
|
641
|
+
const slot = slotKeysOf(part.expression, scopeInfos);
|
|
642
|
+
if (slot.crashy) { nestedUnsupported = true; continue; }
|
|
643
|
+
if (slot.skip || slot.lossy) continue;
|
|
644
|
+
if (parts.length !== 1) continue; // mixed static+dynamic value
|
|
645
|
+
attrSlots.push({
|
|
646
|
+
key: slot.key,
|
|
647
|
+
expr: exprText(source, part.expression),
|
|
648
|
+
attr: attr.name,
|
|
649
|
+
tag: child.name || null,
|
|
650
|
+
classes: staticClassesOf(child),
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
walkForSlots(child.fragment, scopeInfos);
|
|
655
|
+
continue;
|
|
656
|
+
} else if (child.type === 'EachBlock') {
|
|
657
|
+
const roots = collectRootIdentifiers(child.expression);
|
|
658
|
+
const boundNested = [...roots].some((name) => boundAs(name, scopeInfos));
|
|
659
|
+
if (boundNested) nestedUnsupported = true; // nested per-item arrays: no hydration plan yet
|
|
660
|
+
walkForSlots(child.body, [...scopeInfos, scopeInfoOf(child)]);
|
|
661
|
+
} else if (child.type === 'IfBlock') {
|
|
662
|
+
walkForSlots(child.consequent, scopeInfos);
|
|
663
|
+
if (child.alternate) walkForSlots(child.alternate, scopeInfos);
|
|
664
|
+
} else if (child.fragment) {
|
|
665
|
+
walkForSlots(child.fragment, scopeInfos);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
walkForSlots(body, [scopeInfoOf(node)]);
|
|
670
|
+
|
|
671
|
+
const staticClasses = [];
|
|
672
|
+
for (const attr of rootEl?.attributes || []) {
|
|
673
|
+
if (attr.type === 'Attribute' && attr.name === 'class' && Array.isArray(attr.value)) {
|
|
674
|
+
for (const part of attr.value) {
|
|
675
|
+
if (part.type === 'Text') staticClasses.push(...part.data.split(/\s+/).filter(Boolean));
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
return {
|
|
681
|
+
rootTag: rootEl?.name || null,
|
|
682
|
+
rootClasses: staticClasses,
|
|
683
|
+
textSlots,
|
|
684
|
+
attrSlots,
|
|
685
|
+
staticTexts,
|
|
686
|
+
nestedUnsupported,
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Classify a keyed each block's key expression:
|
|
692
|
+
* { keyField } member of the loop item (e.g. `(expense.id)` when the
|
|
693
|
+
* context binds `expense`): browser injects a unique
|
|
694
|
+
* per-index value under that field.
|
|
695
|
+
* {} key is the whole loop item or the index: already
|
|
696
|
+
* distinct per iteration, nothing to inject.
|
|
697
|
+
* { unsupported } free or complex keys: cannot hydrate distinct values.
|
|
698
|
+
*/
|
|
699
|
+
function classifyEachKey(node) {
|
|
700
|
+
const bound = new Set();
|
|
701
|
+
if (node.context) collectPatternNames(node.context, bound);
|
|
702
|
+
if (node.index) bound.add(node.index);
|
|
703
|
+
const key = node.key;
|
|
704
|
+
const roots = collectRootIdentifiers(key);
|
|
705
|
+
const usesLoopBinding = [...roots].some((name) => bound.has(name));
|
|
706
|
+
if (!usesLoopBinding) {
|
|
707
|
+
// A key that ignores the loop item is constant across iterations:
|
|
708
|
+
// guaranteed duplicate keys at mount.
|
|
709
|
+
return { unsupported: 'each key not derived from the loop item requires source-preview mode' };
|
|
710
|
+
}
|
|
711
|
+
if (key.type === 'Identifier' && bound.has(key.name)) return {};
|
|
712
|
+
if (
|
|
713
|
+
key.type === 'MemberExpression'
|
|
714
|
+
&& !key.computed
|
|
715
|
+
&& key.object?.type === 'Identifier'
|
|
716
|
+
&& bound.has(key.object.name)
|
|
717
|
+
&& key.property?.type === 'Identifier'
|
|
718
|
+
) {
|
|
719
|
+
return { keyField: key.property.name };
|
|
720
|
+
}
|
|
721
|
+
return { unsupported: 'complex each key requires source-preview mode' };
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Describe a fragment's root element for browser presence probing:
|
|
726
|
+
* { tag, classes } of the first RegularElement, or null for text-only
|
|
727
|
+
* fragments (which cannot be probed reliably).
|
|
728
|
+
*/
|
|
729
|
+
function describeElementProbe(fragment) {
|
|
730
|
+
const rootEl = (fragment?.nodes || []).find((n) => n.type === 'RegularElement');
|
|
731
|
+
if (!rootEl) return null;
|
|
732
|
+
const classes = [];
|
|
733
|
+
for (const attr of rootEl.attributes || []) {
|
|
734
|
+
if (attr.type === 'Attribute' && attr.name === 'class' && Array.isArray(attr.value)) {
|
|
735
|
+
for (const part of attr.value) {
|
|
736
|
+
if (part.type === 'Text') classes.push(...part.data.split(/\s+/).filter(Boolean));
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
return { tag: rootEl.name, classes };
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
// ---------------------------------------------------------------------------
|
|
744
|
+
// Public API
|
|
745
|
+
// ---------------------------------------------------------------------------
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* Analyze a markup block and produce the prop-substituted scaffold markup and
|
|
749
|
+
* the v2 prop contract. Returns { ok: false, reason } when the block needs
|
|
750
|
+
* source-preview mode (parse failure or unsupported construct).
|
|
751
|
+
*/
|
|
752
|
+
export function analyzeSvelteMarkup(markup, parse) {
|
|
753
|
+
const source = String(markup || '');
|
|
754
|
+
let ast;
|
|
755
|
+
try {
|
|
756
|
+
ast = parse(source, { modern: true });
|
|
757
|
+
} catch (err) {
|
|
758
|
+
return { ok: false, reason: `svelte parse failed: ${err.message}` };
|
|
759
|
+
}
|
|
760
|
+
if (ast.instance || ast.module) {
|
|
761
|
+
return { ok: false, reason: 'selected block contains a script tag' };
|
|
762
|
+
}
|
|
763
|
+
const analysis = new Analysis(source);
|
|
764
|
+
analyzeFragment(ast.fragment, analysis, []);
|
|
765
|
+
if (analysis.unsupported) {
|
|
766
|
+
return { ok: false, reason: analysis.unsupported };
|
|
767
|
+
}
|
|
768
|
+
for (const entry of analysis.contract) {
|
|
769
|
+
if (entry.kind === 'collection' && entry.item?.nestedUnsupported) {
|
|
770
|
+
return { ok: false, reason: 'per-item content (nested blocks or expressions) this preview cannot hydrate requires source-preview mode' };
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
const markupWithProps = applyReplacements(source, analysis.replacements);
|
|
775
|
+
return {
|
|
776
|
+
ok: true,
|
|
777
|
+
markupWithProps,
|
|
778
|
+
contract: analysis.contract.map((entry) => ({
|
|
779
|
+
prop: entry.prop,
|
|
780
|
+
expr: entry.expr,
|
|
781
|
+
kind: entry.kind,
|
|
782
|
+
// Kept for backward compatibility with v1 consumers (fake e2e agent,
|
|
783
|
+
// text-only restore paths).
|
|
784
|
+
placeholder: `{${entry.expr}}`,
|
|
785
|
+
...(entry.item ? { item: entry.item } : {}),
|
|
786
|
+
...(entry.probe ? { probe: entry.probe } : {}),
|
|
787
|
+
})),
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
function applyReplacements(source, replacements) {
|
|
792
|
+
const sorted = [...replacements].sort((a, b) => b.start - a.start);
|
|
793
|
+
let out = source;
|
|
794
|
+
for (const { start, end, prop } of sorted) {
|
|
795
|
+
out = out.slice(0, start) + prop + out.slice(end);
|
|
796
|
+
}
|
|
797
|
+
return out;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Restore a variant's markup back to route-source form: every free
|
|
802
|
+
* identifier that matches a contract prop is replaced by its original
|
|
803
|
+
* expression. AST-based so `{#each stages as stage}` restores to
|
|
804
|
+
* `{#each data.stages as stage}` even though the prop appears without braces.
|
|
805
|
+
*/
|
|
806
|
+
export function restoreSvelteMarkup(markup, contract, parse) {
|
|
807
|
+
const source = String(markup || '');
|
|
808
|
+
const byProp = new Map();
|
|
809
|
+
for (const entry of contract || []) byProp.set(entry.prop, entry.expr);
|
|
810
|
+
if (byProp.size === 0) return { ok: true, markup: source };
|
|
811
|
+
|
|
812
|
+
let ast;
|
|
813
|
+
try {
|
|
814
|
+
ast = parse(source, { modern: true });
|
|
815
|
+
} catch (err) {
|
|
816
|
+
return { ok: false, reason: `variant parse failed: ${err.message}` };
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
const replacements = [];
|
|
820
|
+
const visitExpr = (expression, scopes) => {
|
|
821
|
+
if (!expression) return;
|
|
822
|
+
collectFreeIdentifierRanges(expression, scopes, (name, start, end) => {
|
|
823
|
+
const original = byProp.get(name);
|
|
824
|
+
if (original != null && original !== name) replacements.push({ start, end, prop: original });
|
|
825
|
+
});
|
|
826
|
+
};
|
|
827
|
+
|
|
828
|
+
const walk = (fragment, scopes) => {
|
|
829
|
+
const fragmentScope = new Set();
|
|
830
|
+
const nextScopes = [...scopes, fragmentScope];
|
|
831
|
+
for (const node of fragment?.nodes || []) {
|
|
832
|
+
if (node.type === 'ConstTag' && node.declaration) {
|
|
833
|
+
for (const decl of node.declaration.declarations || []) collectPatternNames(decl.id, fragmentScope);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
for (const node of fragment?.nodes || []) {
|
|
837
|
+
switch (node?.type) {
|
|
838
|
+
case 'ExpressionTag':
|
|
839
|
+
case 'HtmlTag':
|
|
840
|
+
visitExpr(node.expression, nextScopes);
|
|
841
|
+
break;
|
|
842
|
+
case 'ConstTag':
|
|
843
|
+
for (const decl of node.declaration?.declarations || []) visitExpr(decl.init, nextScopes);
|
|
844
|
+
break;
|
|
845
|
+
case 'EachBlock': {
|
|
846
|
+
visitExpr(node.expression, nextScopes);
|
|
847
|
+
const bound = new Set();
|
|
848
|
+
if (node.context) collectPatternNames(node.context, bound);
|
|
849
|
+
if (node.index) bound.add(node.index);
|
|
850
|
+
// The key evaluates per item, so the loop context and index are in
|
|
851
|
+
// scope there. Visiting it with outer scopes only let a contract
|
|
852
|
+
// prop that shares a loop binding's name rewrite the key.
|
|
853
|
+
if (node.key) visitExpr(node.key, [...nextScopes, bound]);
|
|
854
|
+
walk(node.body, [...nextScopes, bound]);
|
|
855
|
+
if (node.fallback) walk(node.fallback, nextScopes);
|
|
856
|
+
break;
|
|
857
|
+
}
|
|
858
|
+
case 'IfBlock':
|
|
859
|
+
visitExpr(node.test, nextScopes);
|
|
860
|
+
walk(node.consequent, nextScopes);
|
|
861
|
+
if (node.alternate) walk(node.alternate, nextScopes);
|
|
862
|
+
break;
|
|
863
|
+
case 'KeyBlock':
|
|
864
|
+
visitExpr(node.expression, nextScopes);
|
|
865
|
+
walk(node.fragment, nextScopes);
|
|
866
|
+
break;
|
|
867
|
+
case 'SnippetBlock': {
|
|
868
|
+
const bound = new Set();
|
|
869
|
+
for (const param of node.parameters || []) collectPatternNames(param, bound);
|
|
870
|
+
walk(node.body, [...nextScopes, bound]);
|
|
871
|
+
break;
|
|
872
|
+
}
|
|
873
|
+
default: {
|
|
874
|
+
for (const attr of node?.attributes || []) {
|
|
875
|
+
if (attr.type === 'Attribute' && Array.isArray(attr.value)) {
|
|
876
|
+
for (const part of attr.value) {
|
|
877
|
+
if (part?.type === 'ExpressionTag') visitExpr(part.expression, nextScopes);
|
|
878
|
+
}
|
|
879
|
+
} else if (attr.expression) {
|
|
880
|
+
visitExpr(attr.expression, nextScopes);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
if (node?.fragment) walk(node.fragment, nextScopes);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
walk(ast.fragment, []);
|
|
889
|
+
|
|
890
|
+
return { ok: true, markup: applyReplacements(source, replacements) };
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
/**
|
|
894
|
+
* Report [name, start, end] for every free root identifier READ in an
|
|
895
|
+
* expression (skips member properties, object keys, shadowed names).
|
|
896
|
+
*/
|
|
897
|
+
function collectFreeIdentifierRanges(node, scopes, emit) {
|
|
898
|
+
const visit = (n, localBound) => {
|
|
899
|
+
if (!n || typeof n !== 'object') return;
|
|
900
|
+
if (Array.isArray(n)) { for (const item of n) visit(item, localBound); return; }
|
|
901
|
+
switch (n.type) {
|
|
902
|
+
case 'Identifier': {
|
|
903
|
+
const bound = localBound.has(n.name) || scopes.some((s) => s.has(n.name));
|
|
904
|
+
if (!bound) emit(n.name, n.start, n.end);
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
case 'MemberExpression':
|
|
908
|
+
visit(n.object, localBound);
|
|
909
|
+
if (n.computed) visit(n.property, localBound);
|
|
910
|
+
return;
|
|
911
|
+
case 'Property':
|
|
912
|
+
if (n.computed) visit(n.key, localBound);
|
|
913
|
+
visit(n.value, localBound);
|
|
914
|
+
return;
|
|
915
|
+
case 'ArrowFunctionExpression':
|
|
916
|
+
case 'FunctionExpression': {
|
|
917
|
+
const inner = new Set(localBound);
|
|
918
|
+
for (const param of n.params || []) collectPatternNames(param, inner);
|
|
919
|
+
visit(n.body, inner);
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
default:
|
|
923
|
+
for (const key of Object.keys(n)) {
|
|
924
|
+
if (key === 'type' || key === 'start' || key === 'end' || key === 'loc' || key === 'range' || key === 'parent') continue;
|
|
925
|
+
visit(n[key], localBound);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
};
|
|
929
|
+
visit(node, new Set());
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Build the preview component's script block from a v2 contract, with
|
|
934
|
+
* defaults that keep an unhydrated mount rendering instead of crashing.
|
|
935
|
+
*/
|
|
936
|
+
// `/** @type {...} */` directly before a destructuring declaration is also
|
|
937
|
+
// JSDoc's cast syntax, and Svelte 5.50+ re-emits the annotation in cast form
|
|
938
|
+
// onto the template's own declaration: `var /** @type {...} */ (h1) = root()`.
|
|
939
|
+
// That is a syntax error, so the browser's dynamic import of the variant dies
|
|
940
|
+
// with "Unexpected token '('" and nothing renders. `@typedef` carries the same
|
|
941
|
+
// shape without being a cast. Keep it a typedef;
|
|
942
|
+
// tests/live-svelte-props-script.test.mjs compiles what these builders emit
|
|
943
|
+
// and parses the result.
|
|
944
|
+
export function buildPropsScriptV2(contract) {
|
|
945
|
+
if (!contract || contract.length === 0) {
|
|
946
|
+
return '<script>\n /** @typedef {Record<string, never>} Props */\n let {} = $props();\n</script>\n';
|
|
947
|
+
}
|
|
948
|
+
const defaults = {
|
|
949
|
+
text: "''",
|
|
950
|
+
raw: "''",
|
|
951
|
+
condition: 'false',
|
|
952
|
+
collection: '[]',
|
|
953
|
+
handler: '() => {}',
|
|
954
|
+
};
|
|
955
|
+
const types = {
|
|
956
|
+
text: 'string',
|
|
957
|
+
raw: 'string',
|
|
958
|
+
condition: 'boolean',
|
|
959
|
+
collection: 'Array<Record<string, unknown>>',
|
|
960
|
+
handler: '() => void',
|
|
961
|
+
};
|
|
962
|
+
const names = contract
|
|
963
|
+
.map((c) => `${c.prop} = ${defaults[c.kind] ?? "''"}`)
|
|
964
|
+
.join(', ');
|
|
965
|
+
const typeFields = contract
|
|
966
|
+
.map((c) => ` ${c.prop}?: ${types[c.kind] ?? 'string'};`)
|
|
967
|
+
.join('\n');
|
|
968
|
+
return `<script>\n /** @typedef {{\n${typeFields}\n }} Props */\n let { ${names} } = $props();\n</script>\n`;
|
|
969
|
+
}
|