@bastani/atomic 0.9.39 → 0.9.40-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 +35 -0
- package/dist/builtin/intercom/CHANGELOG.md +14 -0
- package/dist/builtin/intercom/broker/broker.ts +523 -72
- package/dist/builtin/intercom/broker/client.ts +136 -5
- package/dist/builtin/intercom/broker/database-wake-up-bus.ts +274 -0
- package/dist/builtin/intercom/broker/group-membership.ts +2 -2
- package/dist/builtin/intercom/broker/multinode-router.ts +1500 -0
- package/dist/builtin/intercom/broker/multinode-state-store.ts +569 -0
- package/dist/builtin/intercom/broker/open-broker-state.ts +160 -0
- package/dist/builtin/intercom/broker/paths.ts +6 -0
- package/dist/builtin/intercom/broker/pending-send-registry.ts +14 -0
- package/dist/builtin/intercom/broker/recipient-receipts.ts +93 -0
- package/dist/builtin/intercom/broker/restoring-recipients.ts +263 -0
- package/dist/builtin/intercom/broker/send-handler.ts +241 -25
- package/dist/builtin/intercom/broker/session-id-reclaim.ts +41 -0
- package/dist/builtin/intercom/broker/socket-writes.ts +47 -0
- package/dist/builtin/intercom/broker/spawn.ts +10 -2
- package/dist/builtin/intercom/broker/sql-held-send-store.ts +96 -0
- package/dist/builtin/intercom/broker/sql-known-session-store.ts +129 -0
- package/dist/builtin/intercom/broker/sql-lease-store.ts +194 -0
- package/dist/builtin/intercom/broker/sql-outbox-store.ts +249 -0
- package/dist/builtin/intercom/broker/sql-pending-ask-store.ts +105 -0
- package/dist/builtin/intercom/broker/sql-restoring-reservation-store.ts +295 -0
- package/dist/builtin/intercom/broker/sql-sent-message-authority.ts +126 -0
- package/dist/builtin/intercom/broker/supervisor-channel.ts +10 -0
- package/dist/builtin/intercom/broker/wake-up-bus.ts +60 -0
- package/dist/builtin/intercom/index.bundle.mjs +793 -91
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/retry-policy.ts +4 -0
- package/dist/builtin/intercom/session-target.ts +24 -0
- package/dist/builtin/intercom/types.ts +57 -3
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +31 -0
- package/dist/builtin/subagents/README.md +18 -12
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/skills/agent-browser/SKILL.md +1 -1
- package/dist/builtin/subagents/skills/cua-driver/BROWSER.md +55 -8
- package/dist/builtin/subagents/skills/cua-driver/EMBEDDING.md +7 -2
- package/dist/builtin/subagents/skills/cua-driver/LINUX.md +7 -1
- package/dist/builtin/subagents/skills/cua-driver/MACOS.md +151 -27
- package/dist/builtin/subagents/skills/cua-driver/RUNTIME.md +1 -1
- package/dist/builtin/subagents/skills/cua-driver/SKILL.md +33 -17
- package/dist/builtin/subagents/skills/cua-driver/WINDOWS.md +5 -0
- package/dist/builtin/subagents/skills/cua-driver/WORKFLOW.md +46 -8
- package/dist/builtin/subagents/skills/subagent/SKILL.md +18 -20
- package/dist/builtin/subagents/src/extension/index.bundle.mjs +8032 -6034
- package/dist/builtin/web-access/CHANGELOG.md +6 -0
- package/dist/builtin/web-access/README.md +1 -1
- package/dist/builtin/web-access/index.bundle.mjs +2 -5
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +24 -0
- package/dist/builtin/workflows/README.md +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/impeccable/SKILL.md +8 -8
- package/dist/builtin/workflows/skills/impeccable/reference/adapt.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/adapt.native.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/audit.md +4 -2
- package/dist/builtin/workflows/skills/impeccable/reference/audit.native.md +2 -2
- package/dist/builtin/workflows/skills/impeccable/reference/craft-floor.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/critique.md +22 -9
- package/dist/builtin/workflows/skills/impeccable/reference/degraded/finish-reviewer.md +2 -2
- package/dist/builtin/workflows/skills/impeccable/reference/distill.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/extract.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/harden.md +2 -4
- package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +4 -4
- package/dist/builtin/workflows/skills/impeccable/reference/live.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/new-work.md +6 -6
- package/dist/builtin/workflows/skills/impeccable/reference/onboard.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/optimize.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/overdrive.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/quieter.md +3 -3
- package/dist/builtin/workflows/skills/impeccable/reference/typeset.md +10 -0
- package/dist/builtin/workflows/skills/impeccable/reference/visualize.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/VERSION +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/impeccable +6 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/impeccable.cmd +47 -22
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-dom.js +34 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-session.js +25 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +33 -8
- package/dist/builtin/workflows/src/durable/journal/resolution.d.ts +7 -7
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +22715 -22159
- package/dist/builtin/workflows/src/index.js +106 -35
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +17 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session-extension-bindings.d.ts +2 -0
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
- package/dist/core/agent-session-extension-bindings.js +6 -6
- package/dist/core/agent-session-extension-bindings.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +6 -3
- 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-persistent-custom-messages.d.ts +7 -2
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +29 -12
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session-recovery.d.ts +14 -0
- package/dist/core/agent-session-recovery.d.ts.map +1 -0
- package/dist/core/agent-session-recovery.js +83 -0
- package/dist/core/agent-session-recovery.js.map +1 -0
- package/dist/core/agent-session-tasks.d.ts.map +1 -1
- package/dist/core/agent-session-tasks.js +4 -6
- package/dist/core/agent-session-tasks.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +13 -0
- 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 +2 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +4 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +3 -2
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/export-html/template.html +1 -0
- package/dist/core/export-html/template.js +37 -20
- package/dist/core/export-html/vendor/marked-cjk-friendly.min.js +6 -0
- package/dist/core/export-html/vendor/marked.min.js +76 -3
- package/dist/core/extensions/api-types.d.ts +6 -2
- 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/event-results.d.ts +21 -0
- package/dist/core/extensions/event-results.d.ts.map +1 -1
- package/dist/core/extensions/event-results.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader-api.d.ts.map +1 -1
- package/dist/core/extensions/loader-api.js +4 -0
- package/dist/core/extensions/loader-api.js.map +1 -1
- package/dist/core/extensions/runner-events.d.ts +9 -2
- package/dist/core/extensions/runner-events.d.ts.map +1 -1
- package/dist/core/extensions/runner-events.js +29 -0
- package/dist/core/extensions/runner-events.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +5 -3
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +7 -2
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/runtime-types.d.ts +1 -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/session-events.d.ts +30 -2
- package/dist/core/extensions/session-events.d.ts.map +1 -1
- package/dist/core/extensions/session-events.js.map +1 -1
- package/dist/core/sdk-types.d.ts +3 -2
- 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 +3 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-storage.d.ts.map +1 -1
- package/dist/core/session-storage.js +15 -9
- package/dist/core/session-storage.js.map +1 -1
- package/dist/core/storage/process-selection.d.ts +39 -0
- package/dist/core/storage/process-selection.d.ts.map +1 -0
- package/dist/core/storage/process-selection.js +154 -0
- package/dist/core/storage/process-selection.js.map +1 -0
- package/dist/core/storage/provider.d.ts +6 -1
- package/dist/core/storage/provider.d.ts.map +1 -1
- package/dist/core/storage/provider.js +3 -2
- package/dist/core/storage/provider.js.map +1 -1
- package/dist/core/storage/selection.d.ts +1 -1
- package/dist/core/storage/selection.d.ts.map +1 -1
- package/dist/core/storage/selection.js.map +1 -1
- package/dist/core/storage/session/jsonl-session-store.d.ts +2 -0
- package/dist/core/storage/session/jsonl-session-store.d.ts.map +1 -1
- package/dist/core/storage/session/jsonl-session-store.js +38 -2
- package/dist/core/storage/session/jsonl-session-store.js.map +1 -1
- package/dist/core/tasks/completion.d.ts +11 -2
- package/dist/core/tasks/completion.d.ts.map +1 -1
- package/dist/core/tasks/completion.js +40 -16
- package/dist/core/tasks/completion.js.map +1 -1
- package/dist/core/tasks/pause.d.ts +4 -1
- package/dist/core/tasks/pause.d.ts.map +1 -1
- package/dist/core/tasks/pause.js +8 -5
- package/dist/core/tasks/pause.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.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +7 -1
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-rendering.js +11 -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 +2 -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 +2 -0
- package/dist/modes/interactive/components/chat-session-host-state.js.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-deferred-startup.js +4 -0
- package/dist/modes/interactive/interactive-deferred-startup.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +2 -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-render-chat.js +3 -0
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/interactive/interactive-session-routing.js +2 -0
- package/dist/modes/interactive/interactive-session-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-session-runtime.d.ts +2 -1
- package/dist/modes/interactive/interactive-session-runtime.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-session-runtime.js +29 -0
- package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +4 -1
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive-engine/engine-args.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-args.js +4 -0
- package/dist/modes/interactive-engine/engine-args.js.map +1 -1
- package/dist/modes/interactive-engine/engine-render-service.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-render-service.js +4 -4
- package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +4 -0
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/interactive-engine/remote-renderer.js +1 -1
- package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
- package/dist/modes/rpc/rpc-client-api.d.ts +4 -1
- package/dist/modes/rpc/rpc-client-api.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-api.js +4 -0
- package/dist/modes/rpc/rpc-client-api.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +3 -0
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-command-timeouts.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-timeouts.js +1 -0
- package/dist/modes/rpc/rpc-command-timeouts.js.map +1 -1
- package/dist/modes/rpc/rpc-input-scheduler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-input-scheduler.js +6 -1
- package/dist/modes/rpc/rpc-input-scheduler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +12 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +44 -11
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/tools-manager.js +1 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/background-tasks.md +5 -3
- package/docs/computer-use.md +2 -2
- package/docs/environment-variables.md +4 -1
- package/docs/extensions/events.md +29 -2
- package/docs/getting-started/first-session.md +1 -1
- package/docs/guides/intercom.md +1 -1
- package/docs/intercom/operations.md +103 -1
- package/docs/intercom/reference.md +10 -3
- package/docs/intercom.md +8 -6
- package/docs/keybindings.md +1 -1
- package/docs/models.md +1 -1
- package/docs/providers.md +5 -3
- package/docs/reference/cli.md +5 -0
- package/docs/rpc/protocol.md +19 -0
- package/docs/rpc.md +3 -0
- package/docs/sdk/web-server.md +1 -1
- package/docs/sdk.md +5 -2
- package/docs/sessions.md +17 -1
- package/docs/settings.md +6 -4
- package/docs/skills.md +1 -1
- package/docs/storage.md +54 -3
- package/docs/subagents.md +49 -9
- package/docs/usage.md +1 -1
- package/docs/windows.md +14 -4
- package/docs/workflows/api-reference.md +1 -1
- package/docs/workflows/authoring.md +1 -1
- package/docs/workflows/operations.md +10 -6
- package/npm-shrinkwrap.json +40 -40
- package/package.json +6 -6
- package/dist/core/export-html/template-js/data-tree.js +0 -287
- package/dist/core/export-html/template-js/entries-navigation.js +0 -434
- package/dist/core/export-html/template-js/initialization.js +0 -335
- package/dist/core/export-html/template-js/message-tools.js +0 -428
- package/dist/core/export-html/template-js/tree-filter-render.js +0 -419
- package/dist/core/export-html/template-script.d.ts +0 -3
- package/dist/core/export-html/template-script.d.ts.map +0 -1
- package/dist/core/export-html/template-script.js +0 -13
- package/dist/core/export-html/template-script.js.map +0 -1
|
@@ -38,7 +38,7 @@ Keep the visual system fixed. Derive five to seven materially different structur
|
|
|
38
38
|
|
|
39
39
|
`.pi/skills/impeccable/scripts/impeccable concept-seed --scope surface --mode <mode>`
|
|
40
40
|
|
|
41
|
-
The script deals three of your structures; the dice pick which three reach the user, breaking the ranking rut while the user keeps a real choice. Present them on the decision page as full cards of equal salience, the dealt lead under kicker THE ROLL, with steer and re-roll; the user locks one. No canon card and no pick card at surface scope: the world is settled, so every card visualizes composition, not identity. With image generation and a comp-led build path (the path the PRESENTATION block printed for this surface; the build-path paragraph below), each card declares a `comp` under `.impeccable/mocks/decision/`, generated after serving, in reading order, under [visualize.md](visualize.md)'s comp discipline and the MODE RULES block concept-seed printed for this surface. Anchor each comp on the established identity: pass a screenshot of a representative existing page as a reference image (the harness image tool's input image, or `impeccable generate-image --ref`) with a short prompt in visualize.md's shape; prose paraphrases of a design system drift, pixel references do not. Without image generation, or on a code-led round, each card carries an HTML sketch of the first viewport, declared as its `html`, which the page draws as a skeleton; the PRESENTATION block names its shape, and a card without one falls back to a `wireframe` schematic (`impeccable serve-question --schema`). Locking a card is the approval and sets the build path: a locked comp builds comp-led with that comp as the approved comp, discharging [visualize.md](visualize.md)'s three-option round with no second approval point; a locked sketch or wireframe builds code-led, its ambition carried by the direction contract, and a locked sketch is the composition the build matches. Never run the script for a local extension or a precisely specified narrow request; shape those directly.
|
|
41
|
+
The script deals three of your structures; the dice pick which three reach the user, breaking the ranking rut while the user keeps a real choice. Present them on the decision page as full cards of equal salience, the dealt lead under kicker THE ROLL, with steer and re-roll; the user locks one. Each card declares `kind`: `assigned` on the dealt lead, `dealt` on the other dealt structures, and `challenger` with its `catalogId` (the SOURCE ID) on a challenger that won its place. No canon card and no pick card at surface scope: the world is settled, so every card visualizes composition, not identity. With image generation and a comp-led build path (the path the PRESENTATION block printed for this surface; the build-path paragraph below), each card declares a `comp` under `.impeccable/mocks/decision/`, generated after serving, in reading order, under [visualize.md](visualize.md)'s comp discipline and the MODE RULES block concept-seed printed for this surface. Anchor each comp on the established identity: pass a screenshot of a representative existing page as a reference image (the harness image tool's input image, or `impeccable generate-image --ref`) with a short prompt in visualize.md's shape; prose paraphrases of a design system drift, pixel references do not. Without image generation, or on a code-led round, each card carries an HTML sketch of the first viewport, declared as its `html`, which the page draws as a skeleton; the PRESENTATION block names its shape, and a card without one falls back to a `wireframe` schematic (`impeccable serve-question --schema`). Locking a card is the approval and sets the build path: a locked comp builds comp-led with that comp as the approved comp, discharging [visualize.md](visualize.md)'s three-option round with no second approval point; a locked sketch or wireframe builds code-led, its ambition carried by the direction contract, and a locked sketch is the composition the build matches. Never run the script for a local extension or a precisely specified narrow request; shape those directly.
|
|
42
42
|
|
|
43
43
|
### Create or replace the visual world
|
|
44
44
|
|
|
@@ -48,7 +48,7 @@ The script deals three of your structures; the dice pick which three reach the u
|
|
|
48
48
|
4. Run `.pi/skills/impeccable/scripts/impeccable concept-seed --scope direction --mode <mode>` and follow what it prints. No substitute, no skip: on a new or replacement world, writing artifact code before this script has run and its assignment is acknowledged is a contract violation, whatever the harness, the model, or the time pressure; the roll is what keeps every run from converging on the category default. The script assigns the direction to build and deals catalog challengers. Fuse each challenger before judging it: the challenger supplies the form and its system grammar, the product supplies every fact, clarity wins conflicts. Weigh fused challengers against the assigned direction on exactly two axes, audience identification and product clarity. Losing to strong grounded material is a valid outcome; beating a thin or tool-monoculture list is the point. Close with a verdict per challenger, decided before any borrowing: wins (beats the assigned direction on both axes; becomes the build candidate), competitive (holds one axis; stays a full alternate), or declined (loses both). A declined challenger is not spent: name the one discipline of its system the assigned direction lacks, and raise the assigned direction to match before presenting it. A donation transfers ambition and system discipline (a palette's total commitment, a grid's density courage, a form's structural honesty), never the challenger's clothes. A component treatment, such as a button's shadow or a display face, is clothes, not discipline; a lifted motif is a costume note, not a raise, and one world owns the page. Write each raise into the presented direction as its own line, named for its donor; a raise nobody can read did not happen.
|
|
49
49
|
5. Present one direction, fully committed and already raised by the hand it beat, raises visible as named lines: world, first viewport, visitor path, signature interaction, cross-surface reach, honest risk. Route each challenger by verdict: winning and competitive challengers are full alternates with their QUALITY BAR cards and one-line case; declined challengers render demoted, compact and quiet, each carrying its verdict and what the direction kept from it, never full-size, never silently dropped, still adoptable on request. The verdict informs the user's choice, never pre-empts it; the demoted row is the hand's proof of judgment. A hand holds at most three full-card challengers: when the roll deals more, the three strongest join and the rest wait in the re-roll pool, noted in one line; dropping a challenger from the hand itself takes a named product-truth failure, disclosed. Add one card for your own top-ranked grounded candidate when it is not the assigned direction, kicker IMPECCABLE’S PICK, same anatomy as every card, with an honest risk line naming its familiarity when true: the strongest grounded direction is often where most runs in this category land, and the user deciding that trade is the point of showing it. Familiar and effective is a legitimate destination, not a failure of nerve; the pick card and the standing exit serve it at two depths. One pick card, never two, never a ranked list: a lineup of your candidates hands selection back to a taste function and invites the safest card. The pick never takes the lead position; when the dice assign your top candidate there is no pick card, and the assigned card notes it topped your list. Add re-roll with an optional one-line steer, in three registers: plain (a fresh hand, same spread), safer (your remaining conventional grounded candidates plus the canon against named competitors), bolder (foreign forms only, at full commitment). The register is the user's steering on the familiar-to-bold axis, never yours to pre-select; when the answer carries one, re-run the seed with `--register <value>` and the next `--reroll` round, and follow what it prints. A user saying "bolder" or "safer" while a direction round is open means these registers, never the bolder or harden commands. The two channels share this structure and differ only in richness: cards and boards on the decision page, names and one-liners through the structured tool, whose option list carries the assigned direction, the pick, the winning and competitive challengers, and the standing exit last; declined challengers fold into the assigned option's description as their kept lines, so the raise survives the text channel.
|
|
50
50
|
|
|
51
|
-
The standing exit: every direction round offers one quiet, permanent alternative, the category standard, played straight. It is the user's door, never yours: never recommend it, never weigh it against the roll, never let it soften the dealt directions; the counterweights bind the unchosen default, not the chosen one. When the user takes it (the canon action, a safer-steer, or plain words asking for the familiar or competitor-like path), convention becomes the commitment: ask once for two or three products this should sit alongside, make their craft level the bar, and execute the canon at full fidelity, without irony or smuggled quirk. Record a standing preference as a brand commitment in PRODUCT.md. Re-roll eliminates every direction already shown, grounded and challenger alike; after two consecutive re-rolls, ask what quality is missing. Re-roll on your own only on named factual grounds, when the assigned direction cannot carry the product's truth or task; taste is never grounds. The user may re-roll freely, and a user- or brief-pinned direction beats the roll, always. Resolve collisions field by field: preserve every user- or brief-pinned constraint. In dimensions the brief leaves open, the assignment still binds through its topology, controls, state vocabulary, and ritual; when only its materials conflict with a pinned visual direction or PRODUCT.md brand commitment, translate that material expression and name the translation in the presented direction. A look mismatch is not grounds to re-roll. Present the decision visually: write an options payload with the assigned direction leading, its raised lines included; the pick card when one exists; the dealt challengers as alternates with their QUALITY BAR cards, verdicts, and kept lines; re-roll with its safer and bolder registers; steer; canon enabled; and `buildPath` carrying the recorded default with `toggle: true` whenever image generation exists (details in the build-path paragraph below). A degraded roll with no challengers still uses the page, as a single text-only card with re-roll. Give every card the same anatomy: thesis, palette, materials, first viewport, honest risk, and the challengers' case lines (`--schema` prints the exact shape); the page renders identity from these fields, demotes declined challengers to their row on its own, and a challenger's catalog image rides as labeled inspiration, never the promise of the build. Author `canonCard` too: the category standard as one honest card, same anatomy; the page keeps it subordinate, and the counterweights still bind you. Run `.pi/skills/impeccable/scripts/impeccable serve-question --start --payload <file>` (`--schema` first for the payload shape). It daemonizes, prints the page URL and a key, and exits; open that URL for the user, in-app browser first, then the system opener, then showing the URL. Collect the choice with `--wait --key <key>`, repeating while it exits 3; the ANSWER prints as JSON. An ANSWER of `{"optionId":"reroll"}` keeps the server alive and the page open on a loading hand: rerun concept-seed with the same `--scope` and `--mode` plus `--from <seed-key> --reroll <n>` (1 on the first re-roll, counting up), build the next payload, deliver it with `--update --key <same key> --payload <file>`, then return to `--wait` on that key. Never `--start` a second server or fall back to chat here: either strands the open tab on a hand that never arrives. Exit 4 means the page closed unanswered: re-present once through the structured question tool, and with no answer there either, proceed unattended with the assigned direction and state the assumptions. A harness that can leave a shell blocked in the background may run the script without `--start` and let it auto-open and block. A harness that cannot hold a blocking `--wait` (it detaches long-running commands without ever returning their output, or reaps a backgrounded child) takes the structured tool without starting the page and discloses the substitution in the first reply, so the tab is never left unanswered. A shell that hands back a still-running command as a session you can poll holds the wait: poll that session until it exits, and rerun `--wait` only after it exits without an answer. Never predict any other fallback: run the script, and only exit code 2 from starting it, or that wait check before starting, routes the decision to the structured tool; those are the fallback, never an error to retry. concept-seed closes every roll with this procedure, condensed, as a PRESENTATION block that names the recorded build path.
|
|
51
|
+
The standing exit: every direction round offers one quiet, permanent alternative, the category standard, played straight. It is the user's door, never yours: never recommend it, never weigh it against the roll, never let it soften the dealt directions; the counterweights bind the unchosen default, not the chosen one. When the user takes it (the canon action, a safer-steer, or plain words asking for the familiar or competitor-like path), convention becomes the commitment: ask once for two or three products this should sit alongside, make their craft level the bar, and execute the canon at full fidelity, without irony or smuggled quirk. Record a standing preference as a brand commitment in PRODUCT.md. Re-roll eliminates every direction already shown, grounded and challenger alike; after two consecutive re-rolls, ask what quality is missing. Re-roll on your own only on named factual grounds, when the assigned direction cannot carry the product's truth or task; taste is never grounds. The user may re-roll freely, and a user- or brief-pinned direction beats the roll, always. Resolve collisions field by field: preserve every user- or brief-pinned constraint. In dimensions the brief leaves open, the assignment still binds through its topology, controls, state vocabulary, and ritual; when only its materials conflict with a pinned visual direction or PRODUCT.md brand commitment, translate that material expression and name the translation in the presented direction. A look mismatch is not grounds to re-roll. Present the decision visually: write an options payload with the assigned direction leading, its raised lines included; the pick card when one exists; the dealt challengers as alternates with their QUALITY BAR cards, verdicts, and kept lines; re-roll with its safer and bolder registers; steer; canon enabled; and `buildPath` carrying the recorded default with `toggle: true` whenever image generation exists (details in the build-path paragraph below). A degraded roll with no challengers still uses the page, as a single text-only card with re-roll. Every option declares its identity: `kind` is `assigned`, `pick`, `challenger`, or `grounded` (another of your own grounded directions, such as each card of a safer hand's lineup, any number of them), and each challenger carries `catalogId`, the SOURCE ID concept-seed printed for its world, never the card's own id; `--start` and `--update` refuse a direction or surface payload without them, and the page reports the choice from them. Give every card the same anatomy: thesis, palette, materials, first viewport, honest risk, and the challengers' case lines (`--schema` prints the exact shape); the page renders identity from these fields, demotes declined challengers to their row on its own, and a challenger's catalog image rides as labeled inspiration, never the promise of the build. Author `canonCard` too: the category standard as one honest card, same anatomy; the page keeps it subordinate, and the counterweights still bind you. Run `.pi/skills/impeccable/scripts/impeccable serve-question --start --payload <file>` (`--schema` first for the payload shape). It daemonizes, prints the page URL and a key, and exits; open that URL for the user, in-app browser first, then the system opener, then showing the URL. Collect the choice with `--wait --key <key>`, repeating while it exits 3; the ANSWER prints as JSON. An ANSWER of `{"optionId":"reroll"}` keeps the server alive and the page open on a loading hand: rerun concept-seed with the same `--scope` and `--mode` plus `--from <seed-key> --reroll <n>` (1 on the first re-roll, counting up), build the next payload, deliver it with `--update --key <same key> --payload <file>`, then return to `--wait` on that key. Never `--start` a second server or fall back to chat here: either strands the open tab on a hand that never arrives. Exit 4 means the page closed unanswered: re-present once through the structured question tool, and with no answer there either, proceed unattended with the assigned direction and state the assumptions. A harness that can leave a shell blocked in the background may run the script without `--start` and let it auto-open and block. A harness that cannot hold a blocking `--wait` (it detaches long-running commands without ever returning their output, or reaps a backgrounded child) takes the structured tool without starting the page and discloses the substitution in the first reply, so the tab is never left unanswered. A shell that hands back a still-running command as a session you can poll holds the wait: poll that session until it exits, and rerun `--wait` only after it exits without an answer. Never predict any other fallback: run the script, and only exit code 2 from starting it, or that wait check before starting, routes the decision to the structured tool; those are the fallback, never an error to retry. concept-seed closes every roll with this procedure, condensed, as a PRESENTATION block that names the recorded build path.
|
|
52
52
|
|
|
53
53
|
When image generation exists, every card also declares a `comp` path under `.impeccable/mocks/decision/`, the canon card included. Where the harness sandboxes its shell, start the page through the least-sandboxed command path it offers: a sandboxed shell cannot bind the board's port, and the first-attempt failure costs a retry every session. Serve the page first, then produce the comps; the page shimmer-waits per slot and the user may answer before they land. Load [visualize.md](visualize.md) before writing the first decision comp prompt, not at the comp round: each card's image is that direction's north-star comp at full fidelity under its comp discipline and the MODE RULES block concept-seed printed, and a prompt written before reading them misses every rule there: the requested surface as the real page, its first viewport and the start of the section below it, held like every comp to visualize.md's rule that a template skeleton stays the template whatever world paints it (your own pick included: a safe layout under a world skin is the template), a short prompt in visualize.md's shape, real product name and real content, no invented commercial claims, in that card's own palette, type character, and material world, committed all the way. Once a round declares comps it has not generated yet, `impeccable serve-question --start` (and `--update`, and a flip to comp) prints a `NEXT read <path>/visualize.md` line; read that file then, before the first prompt. `--wait` prints `COMP SIDECAR MISSING` for any landed decision comp with no prompt sidecar (the image's full file name plus `.json`: `a.png` gets `a.png.json`); write the missing sidecar before you continue. `COMP STALE` names a file an earlier round left at one of this hand's slots; regenerate it there. Generation takes the same time at any fidelity, so an unfinished draft pays comp cost for draft quality; fairness between cards is equal fidelity in each card's own grammar, one surface, one aspect, never shared unfinishedness. The frame's aspect is the surface's own: portrait at device viewport for a native app or mobile-first surface, landscape for desktop web; the decision page adapts to either, and a phone screen comped landscape is a broken frame, not a neutral default. Produce in reading order, the assigned card, then the pick, then the full-card hand, then canon, each file written with its prompt sidecar the moment it is done, so a re-roll's spend front-loads onto the cards read first; declined challengers get no comp, their catalog thumb is their face. With parallel subagents, fan out one agent per card: each spawn is the shipped asset producer with a single-comp packet, that card's fields, its world's card images when the NEXT line names them, PRODUCT.md, the shared frame, the path to visualize.md for its comp discipline, the COMPS section of the MODE RULES block copied verbatim (the subagent never sees the roll's output), and the card's declared path, up to four in flight. Regenerate inline any slot still empty when its agent returns; drop without ceremony any slot still empty when the user answers. No other supervision is owed. Without parallel subagents, generate in the main thread after serving, same order, and let the harness's own generation display carry the progress; the wait for the answer follows the last file. The chosen card's comp is not spent by the choice: comp-led, it enters the comp round as compositional option one; code-led, it returns at the finish review as the critique reference, what the image dared that the build did not. Unchosen comps stay in `.impeccable/mocks/decision/` as the round's spent hand; they carry no approval and imply none. With no image generation, cards carry their identity in palette chips and facts, and that page is complete, not a lesser version; the page then also demotes every challenger's catalog art to a labeled thumbnail on its own, because salience must encode the verdict, never the accident of which cards have images.
|
|
54
54
|
|
|
@@ -70,7 +70,7 @@ Calibration: AI-generated interfaces cluster around a few looks regardless of su
|
|
|
70
70
|
|
|
71
71
|
## 5. Record the decision
|
|
72
72
|
|
|
73
|
-
Before code, record the chosen direction as a development-only contract under `## Direction contract` in the relevant surface brief. A direction contract is durable route or artifact strategy, so create or update the brief even when no other surface strategy needs persistence. Use six short blocks, roughly 150 words; do not spend tool calls counting words. THESIS: the one idea this surface owns and the category-default arrangement it refuses. OWN-WORLD: the palette and component language, specific enough to be recognizable with all content removed. STORY: what the visitor understands, believes, and does. FIRST VIEWPORT: the exact composition, what is where and at what scale, and where the primary action sits. FORM: the chosen form, its position on your ordered list, and the seed key the
|
|
73
|
+
Before code, record the chosen direction as a development-only contract under `## Direction contract` in the relevant surface brief. A direction contract is durable route or artifact strategy, so create or update the brief even when no other surface strategy needs persistence. Use six short blocks, roughly 150 words; do not spend tool calls counting words. THESIS: the one idea this surface owns and the category-default arrangement it refuses. OWN-WORLD: the palette and component language, specific enough to be recognizable with all content removed. STORY: what the visitor understands, believes, and does. FIRST VIEWPORT: the exact composition, what is where and at what scale, and where the primary action sits. FORM: the chosen form, its position on your ordered list, and the SEED REFERENCE concept-seed printed (`seed:` and 16 hex), never the raw seed key: the brief is committed, and on this machine the reference stands in for the key wherever a command takes one. When the roll printed SEED REFERENCE unavailable, write `seed: none (unavailable)` instead, and nothing else. Close with one more line, FINISH: the run's exit condition, verbatim "unreviewed and undocumented is unfinished; this build ends with the finish review, the verdict, DESIGN.md, and every shipping raster carrying its provenance". The surface brief is the reminder later agents reload across edits and sessions: a page that looks complete with the FINISH line undischarged is not done, it is abandoned at the finish line. If a block reads like a mood, the direction is not decided yet; the finishing review audits the render against this contract.
|
|
74
74
|
|
|
75
75
|
Never copy the direction contract into implementation source or any browser-delivered artifact. This includes HTML or framework comments, hidden DOM, `<template>` elements, `data-*` attributes, rendered JSX or TSX output, serialized props or state, React Server Component payloads, client bundles, metadata or JSON-LD, accessibility-only text, and files served beside the artifact. A compiler or optimizer removing development metadata is not a safety boundary. Reviewers and documenters receive the contract from the surface brief.
|
|
76
76
|
|
|
@@ -82,7 +82,7 @@ Read the existing surface brief before updating it:
|
|
|
82
82
|
|
|
83
83
|
`.pi/skills/impeccable/scripts/impeccable surface-brief write <primary-target> <body-file> [related-target ...]`
|
|
84
84
|
|
|
85
|
-
After writing, read the brief once more and verify that all six contract blocks and the seed
|
|
85
|
+
After writing, read the brief once more and verify that all six contract blocks and the seed reference (or `seed: none (unavailable)` when the roll printed that) are present before building.
|
|
86
86
|
|
|
87
87
|
Keep the brief small: scope and visitor mode; audience, job, action/task, proof/content, and constraints; chosen direction and memorable moment; unresolved decisions. Do not copy global product truth or DESIGN.md tokens into it.
|
|
88
88
|
|
|
@@ -98,7 +98,7 @@ Build the assigned direction, not a safer interpretation of it. The form supplie
|
|
|
98
98
|
|
|
99
99
|
When an approved comp exists, it is a spatial contract, not a mood board: only the user can downgrade its authority, in explicit words. Models systematically believe their HTML, CSS, and SVG recreation of an image succeeded when it did not, so the build runs as a state machine on disk whose gates measure the screen against the comp instead of asking you to remember it. Start it once, and let it tell you what is next:
|
|
100
100
|
|
|
101
|
-
`.pi/skills/impeccable/scripts/impeccable build-phase start --direction <seed
|
|
101
|
+
`.pi/skills/impeccable/scripts/impeccable build-phase start --direction <seed reference, or none when it was unavailable> --artifact <entry file>` right after the direction choice, adding `--decision-comp <path>` when the chosen card has a decision comp (the path CHOSEN COMP names) so the comps gate counts it as option one, or `start --comp <approved comp> --artifact <entry file>` when a surface round already locked one. Start is not the choice ping: that is the `concept-seed --kind` rerun the roll's TELEMETRY line names, sent once when the roll printed one.
|
|
102
102
|
|
|
103
103
|
Then, in order, each closed by `.pi/skills/impeccable/scripts/impeccable build-phase advance` (every verb below runs as `.pi/skills/impeccable/scripts/impeccable <verb>`; exit 2 means the gate failed and printed why; fix that and advance again; write nothing for a later phase while an earlier gate is open):
|
|
104
104
|
|
|
@@ -133,7 +133,7 @@ Preserve semantics, accessibility, performance, responsiveness, project conventi
|
|
|
133
133
|
|
|
134
134
|
## 7. Inspect and finish
|
|
135
135
|
|
|
136
|
-
Inspect the surface's target sizes in one batched screenshot round: desktop and mobile on the web; on a native platform (`ios` / `android` / `adaptive`), the shipped device classes per OS, captured from the simulator or emulator the way the platform reference's Verifying the build section describes. When the harness reports the user's actual viewport (an in-app browser's size, a named resolution), add that width to the set: the width that breaks is the one the user sees first. Critique the render against the user's request and the direction contract, fix material gaps, and confirm with one final round; two rounds is the ceiling, and fixes batch between them rather than earning per-tweak screenshots. The ceiling bounds inspection and never closes an open build-phase gate: a gate stays open until it passes or the route it names is taken. On a comp-led build, run `.pi/skills/impeccable/scripts/impeccable comp-diff --comp <approved comp> --build .impeccable/review/desktop.png --spec .impeccable/build/spec.json --out-dir .impeccable/review/diff/final` and read its region rows and paired crops as the critique: the side-by-side is the view the build thread never has on its own, and a region it scores missing or contradicted is a fix whatever the page looks like from memory. Never judge fidelity from one full-page thumbnail; it hides exactly the failures that matter. On a Persuade surface, verify the mode did its job: a first-time visitor should know what this is, why it matters, and what to do within seconds, in the form's own vocabulary.
|
|
136
|
+
Inspect the surface's target sizes in one batched screenshot round: desktop and mobile on the web; on a native platform (`ios` / `android` / `adaptive`), the shipped device classes per OS, captured from the simulator or emulator the way the platform reference's Verifying the build section describes. When the harness reports the user's actual viewport (an in-app browser's size, a named resolution), add that width to the set: the width that breaks is the one the user sees first. On anything interactive, the round drives every interaction and reachable state (open, closed, hover, focus, error, empty, overlong content) and checks each for overlap and clipping, not only the resting screen. Critique the render against the user's request and the direction contract, fix material gaps, and confirm with one final round; two rounds is the ceiling, and fixes batch between them rather than earning per-tweak screenshots. The ceiling bounds inspection and never closes an open build-phase gate: a gate stays open until it passes or the route it names is taken. On a comp-led build, run `.pi/skills/impeccable/scripts/impeccable comp-diff --comp <approved comp> --build .impeccable/review/desktop.png --spec .impeccable/build/spec.json --out-dir .impeccable/review/diff/final` and read its region rows and paired crops as the critique: the side-by-side is the view the build thread never has on its own, and a region it scores missing or contradicted is a fix whatever the page looks like from memory. Never judge fidelity from one full-page thumbnail; it hides exactly the failures that matter. On a Persuade surface, verify the mode did its job: a first-time visitor should know what this is, why it matters, and what to do within seconds, in the form's own vocabulary.
|
|
137
137
|
|
|
138
138
|
A capture is evidence only when it is valid, and you validate before you send. Settle or disable entrance motion first: an element hidden by animation timing reads as a missing element and gets fixed into a regression. Capture full-page shots from the document top. Capture the comp comparison at the comp's own pixel dimensions. Then open every file once and confirm it shows what its name claims: no black or blank regions, no wrong section behind a right filename, no half-loaded state. A malformed capture sent onward costs the whole round; the reviewer answers it with `disposition: recapture` and nothing it reviewed binds.
|
|
139
139
|
|
|
@@ -23,7 +23,7 @@ Understand what users need to learn and why:
|
|
|
23
23
|
- What's the key action we want them to take? (First project? First invite?)
|
|
24
24
|
- How do we know onboarding worked? (Completion rate? Time to value?)
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
Onboarding should get users to value as quickly as possible, not teach everything possible.
|
|
27
27
|
|
|
28
28
|
## Onboarding Principles
|
|
29
29
|
|
|
@@ -208,9 +208,9 @@ localStorage.setItem('onboarding-completed', 'true');
|
|
|
208
208
|
localStorage.setItem('feature-tooltip-seen-reports', 'true');
|
|
209
209
|
```
|
|
210
210
|
|
|
211
|
-
|
|
211
|
+
Show onboarding once: track completion and respect dismissals.
|
|
212
212
|
|
|
213
|
-
**
|
|
213
|
+
**Avoid**:
|
|
214
214
|
- Force users through long onboarding before they can use product
|
|
215
215
|
- Patronize users with obvious explanations
|
|
216
216
|
- Show same tooltip repeatedly (respect dismissals)
|
|
@@ -17,7 +17,7 @@ Understand current performance and identify problems:
|
|
|
17
17
|
- How bad is it? (Perceivable? Annoying? Blocking?)
|
|
18
18
|
- Who's affected? (All users? Mobile only? Slow connections?)
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Measure before and after. Optimizing without a measurement spends effort on things that do not matter.
|
|
21
21
|
|
|
22
22
|
## Optimization Strategy
|
|
23
23
|
|
|
@@ -233,9 +233,9 @@ const observer = new IntersectionObserver((entries) => {
|
|
|
233
233
|
- Bundle size
|
|
234
234
|
- Request count
|
|
235
235
|
|
|
236
|
-
|
|
236
|
+
Measure on real devices with real network conditions. Desktop Chrome on a fast connection isn't representative.
|
|
237
237
|
|
|
238
|
-
**
|
|
238
|
+
**Avoid**:
|
|
239
239
|
- Optimize without measuring (premature optimization)
|
|
240
240
|
- Sacrifice accessibility for performance
|
|
241
241
|
- Break functionality while optimizing
|
|
@@ -7,7 +7,7 @@ Start your response with:
|
|
|
7
7
|
|
|
8
8
|
Push an interface past conventional limits. This isn't just about visual effects. It's about using the full power of the browser to make any part of an interface feel extraordinary: a table that handles a million rows, a dialog that morphs from its trigger, a form that validates in real-time with streaming feedback, a page transition that feels cinematic.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Context decides what "extraordinary" means. A particle system on a creative portfolio is impressive. The same particle system on a settings page is embarrassing. But a settings page with instant optimistic saves and animated state transitions? That's extraordinary too. Understand the project's personality and goals before deciding what's appropriate.
|
|
11
11
|
|
|
12
12
|
### Propose Before Building
|
|
13
13
|
|
|
@@ -19,9 +19,9 @@ This command has the highest potential to misfire. Do NOT jump straight into imp
|
|
|
19
19
|
|
|
20
20
|
Skipping this step risks building something embarrassing that needs to be thrown away.
|
|
21
21
|
|
|
22
|
-
###
|
|
22
|
+
### Verify in the Browser
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
Ambitious effects rarely work on the first try, so verify them in the browser rather than from code: an effect that technically runs can still stutter, ease wrong, or land on the wrong frame. Aim the checks at timing, easing, and smoothness, batch the fixes between looks, and keep refining until the effect is extraordinary.
|
|
25
25
|
|
|
26
26
|
---
|
|
27
27
|
|
|
@@ -30,7 +30,7 @@ Analyze what makes the design feel too intense:
|
|
|
30
30
|
|
|
31
31
|
If any of these are unclear from the codebase, do not guess. Ask the user directly to clarify what you cannot infer.
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
"Quieter" means refined and easier on the eyes, not generic. Generic quiet looks like gray text on white, one sans at a uniform weight, and a grid of identical cards; restraint still needs a point of view.
|
|
34
34
|
|
|
35
35
|
## Plan Refinement
|
|
36
36
|
|
|
@@ -41,7 +41,7 @@ Create a strategy to reduce intensity while maintaining impact:
|
|
|
41
41
|
- **Simplification approach**: What can be removed entirely?
|
|
42
42
|
- **Sophistication approach**: How can we signal quality through restraint?
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
Subtlety requires precision. Quiet without intent collapses to generic.
|
|
45
45
|
|
|
46
46
|
## Refine the Design
|
|
47
47
|
|
|
@@ -80,7 +80,7 @@ Systematically reduce intensity across these dimensions:
|
|
|
80
80
|
- **Align to grid**: Bring rogue elements back into systematic alignment
|
|
81
81
|
- **Even out spacing**: Replace extreme spacing variations with consistent rhythm
|
|
82
82
|
|
|
83
|
-
**
|
|
83
|
+
**Avoid**:
|
|
84
84
|
- Make everything the same size/weight (hierarchy still matters)
|
|
85
85
|
- Remove all color (quiet ≠ grayscale)
|
|
86
86
|
- Eliminate all personality (maintain character through refinement)
|
|
@@ -56,6 +56,16 @@ Use the fewest roles and families that make the hierarchy unmistakable. Combine
|
|
|
56
56
|
|
|
57
57
|
Do not make type decorative at the expense of comprehension, or introduce a second family without a clear role it alone can perform.
|
|
58
58
|
|
|
59
|
+
## Line breaks
|
|
60
|
+
|
|
61
|
+
After Matthew Butterick's *Practical Typography*, paraphrased; where his numbers differ from these, these stand.
|
|
62
|
+
|
|
63
|
+
- Set `text-wrap: balance` on headings and short centered blocks, and `text-wrap: pretty` on body copy. Both are progressive: a browser that ignores them keeps its default wrap.
|
|
64
|
+
- `pretty` pulls a word down beside a lone last word. It does not fill the last line, and a two-word tail is fine.
|
|
65
|
+
- In a column too narrow for either to help, edit the copy or widen the column.
|
|
66
|
+
- Break a heading by hand only between phrases, and check the break at every width the heading renders at. A hard break that lands mid-line on a phone is worse than the default wrap.
|
|
67
|
+
- An uneven break can carry meaning: a headline that lands on one word for weight, a poster line, a pull quote. Make it deliberate with a hard break or a wrap set on that element, and keep it rare. The detector's `straggler` and `unbalanced-heading` findings are advisory for this reason; say which breaks are intended.
|
|
68
|
+
|
|
59
69
|
## Verify
|
|
60
70
|
|
|
61
71
|
- Primary, secondary, body, and metadata roles are recognizable without reading the copy.
|
|
@@ -6,7 +6,7 @@ A probe tests composition, narrative, hierarchy, density, focal moment, signatur
|
|
|
6
6
|
|
|
7
7
|
## Generate three compositional options
|
|
8
8
|
|
|
9
|
-
The comp round runs inside the build's phase state: `impeccable build-phase start --direction <seed
|
|
9
|
+
The comp round runs inside the build's phase state: `impeccable build-phase start --direction <seed reference>` has already run (with `--decision-comp <path>` when the chosen card has a decision comp) and its `comps` phase is open before the first comp is generated; a comp rendered before that sits outside the state, and a session resumed from that point has no phases to follow. `impeccable generate-image` refuses to write under `.impeccable/mocks/` until start has run; a harness-native image tool is bound by the same order.
|
|
10
10
|
|
|
11
11
|
Render three distinct high-fidelity north-star comps of the requested surface, saved under `.impeccable/mocks/` so they survive the session. When the chosen card has a decision comp, it is option one: it stays at its path under `.impeccable/mocks/decision/`, where the gate counts it through `--decision-comp`, and is never regenerated; render the other two. Comp at the surface's own viewport: portrait at device size for a native app or mobile-first surface, desktop landscape otherwise; a phone screen comped landscape misstates the composition before anything is built against it. Comps are the build thread's own work, never delegated: the thread that writes the prompts holds the direction's full context and has seen every comp when the build starts. Open every image by its workspace-relative path; sandboxed viewers reject absolute paths, and everything under the project root has a relative one. Base the comps on real content and the surface concepts already developed with the user. On an established world, anchor every comp on the real identity: capture a screenshot of a representative existing page and pass it as a reference image (the harness image tool's input image, or `impeccable generate-image --ref`); the prompt leads with the new surface's structure while the reference carries palette, type, and component character, because DESIGN.md words alone drift where a pixel reference does not. Name what the reference contributes and what it must not: chrome, palette, type, and component character carry over; the reference page's own content does not, and a banner, hero, or card lifted verbatim is the reference leaking, not fidelity. Three is the number: one comp invites rubber-stamping; the spread between three surfaces the composition worth building. The chosen card's decision comp is the first of the three: it already renders this direction at full fidelity under this discipline, so generate two more that vary what the first held fixed, from the direction in words rather than with the first comp as an input image (a reference image anchors the layout, and three comps collapse into one composition). How comps two and three vary from the first is the mode's call, in its COMPS rules. A variant that simplifies the first into a tidier version of itself adds no choice to the round. Send all three to the approval point together. Only a round arriving with no decision comp (a degraded roll, an identity-mode page, a direction pinned without the decision round) renders all three here.
|
|
12
12
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
0.1.
|
|
1
|
+
0.1.16
|
|
@@ -130,6 +130,12 @@ if [ -n "$version" ] && [ "$os" != unknown ] && [ "$arch" != unknown ]; then
|
|
|
130
130
|
[ "$os" = windows ] && asset="$asset.exe"
|
|
131
131
|
url="$base/engine-v$version/$asset"
|
|
132
132
|
tmp="$cache_root/bin/$version/.impeccable.part.$$"
|
|
133
|
+
# An interrupted download (Ctrl-C, a hook timeout) would otherwise leave the
|
|
134
|
+
# PID-named staging file behind for good. The handlers must exit explicitly.
|
|
135
|
+
cleanup() { rm -f "$tmp" "$tmp.sha256" 2>/dev/null || :; }
|
|
136
|
+
trap 'cleanup; exit 129' HUP
|
|
137
|
+
trap 'cleanup; exit 130' INT
|
|
138
|
+
trap 'cleanup; exit 143' TERM
|
|
133
139
|
if ! mkdir -p "$cache_root/bin/$version" 2>/dev/null; then
|
|
134
140
|
echo "impeccable: engine $version is not installed; cannot create cache directory: $cache_root/bin/$version" >&2
|
|
135
141
|
setup_help
|
|
@@ -78,20 +78,37 @@ if exist "%IMPECCABLE_HOME%\bin\%version%\" goto cache_ready
|
|
|
78
78
|
mkdir "%IMPECCABLE_HOME%\bin\%version%" >nul 2>nul
|
|
79
79
|
if errorlevel 1 goto cache_directory_failed
|
|
80
80
|
:cache_ready
|
|
81
|
-
rem
|
|
81
|
+
rem Stage the download in a directory only this run owns, as the sh launcher
|
|
82
|
+
rem does with .impeccable.part.$$: concurrent first runs (parallel hooks, two
|
|
83
|
+
rem agents) must never write, hash or move each other's files. mkdir fails
|
|
84
|
+
rem when the name exists, so it claims the name atomically. RANDOM alone is
|
|
85
|
+
rem not enough because cmd seeds it from the clock in whole seconds; the
|
|
86
|
+
rem timestamp and the retry on collision keep same-second runs apart. A cache
|
|
87
|
+
rem directory that refuses every mkdir is reported as unwritable.
|
|
88
|
+
set "attempt=0"
|
|
89
|
+
:claim_staging
|
|
90
|
+
set /a attempt+=1
|
|
91
|
+
if %attempt% GTR 20 goto cache_write_failed
|
|
92
|
+
set "stamp=%TIME: =0%"
|
|
93
|
+
set "stamp=%stamp::=%"
|
|
94
|
+
set "stamp=%stamp:.=%"
|
|
95
|
+
set "stamp=%stamp:,=%"
|
|
96
|
+
set "staging=%IMPECCABLE_HOME%\bin\%version%\.impeccable.part.%stamp%-%RANDOM%%RANDOM%"
|
|
97
|
+
mkdir "%staging%" >nul 2>nul
|
|
98
|
+
if errorlevel 1 goto claim_staging
|
|
99
|
+
set "part=%staging%\impeccable.exe"
|
|
100
|
+
set "sidecar=%staging%\impeccable.sha256"
|
|
82
101
|
rem Redirection failures do not reliably update ERRORLEVEL in cmd.exe;
|
|
83
|
-
rem branch on the command's failure directly.
|
|
84
|
-
|
|
85
|
-
if exist "%cached%.part\" goto cache_write_failed
|
|
86
|
-
(type nul >"%cached%.part") 2>nul || goto cache_write_failed
|
|
102
|
+
rem branch on the command's failure directly.
|
|
103
|
+
(type nul >"%part%") 2>nul || goto staging_write_failed
|
|
87
104
|
set "asset=impeccable-windows-%arch%.exe"
|
|
88
105
|
set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%"
|
|
89
|
-
curl.exe -fsSL -o "%
|
|
106
|
+
curl.exe -fsSL -o "%part%" "%url%" >nul 2>nul
|
|
90
107
|
if not errorlevel 1 goto verify
|
|
91
108
|
if not "%arch%"=="arm64" goto download_failed
|
|
92
109
|
set "asset=impeccable-windows-x64.exe"
|
|
93
110
|
set "url=%IMPECCABLE_DOWNLOAD_BASE%/engine-v%version%/%asset%"
|
|
94
|
-
curl.exe -fsSL -o "%
|
|
111
|
+
curl.exe -fsSL -o "%part%" "%url%" >nul 2>nul
|
|
95
112
|
if errorlevel 1 goto download_failed
|
|
96
113
|
|
|
97
114
|
:verify
|
|
@@ -101,61 +118,67 @@ rem Mirrors the sh launcher and fails closed: a freshly downloaded binary
|
|
|
101
118
|
rem runs only after verifying against its .sha256 sidecar. A sidecar that
|
|
102
119
|
rem cannot be fetched, or an empty certutil result, refuses the download
|
|
103
120
|
rem instead of running an unverified binary.
|
|
104
|
-
curl.exe -fsSL -o "%
|
|
121
|
+
curl.exe -fsSL -o "%sidecar%" "%url%.sha256" >nul 2>nul
|
|
105
122
|
if errorlevel 1 goto verify_refuse
|
|
106
123
|
set "expected="
|
|
107
|
-
set /p expected=<"%
|
|
124
|
+
set /p expected=<"%sidecar%"
|
|
108
125
|
for /f "tokens=1" %%h in ("%expected%") do set "expected=%%h"
|
|
109
126
|
call :check_download
|
|
110
127
|
if errorlevel 1 exit /b 127
|
|
111
128
|
set "actual="
|
|
112
129
|
rem Reuse the sidecar staging file after reading expected. Check certutil's
|
|
113
130
|
rem status before parsing: its error text on stdout is not a digest.
|
|
114
|
-
certutil -hashfile "%
|
|
131
|
+
certutil -hashfile "%part%" SHA256 >"%sidecar%" 2>nul
|
|
115
132
|
if errorlevel 1 goto verify_refuse
|
|
116
133
|
call :check_download
|
|
117
134
|
if errorlevel 1 exit /b 127
|
|
118
|
-
for /f "usebackq skip=1 delims=" %%h in ("%
|
|
119
|
-
del "%
|
|
135
|
+
for /f "usebackq skip=1 delims=" %%h in ("%sidecar%") do if not defined actual set "actual=%%h"
|
|
136
|
+
del "%sidecar%" >nul 2>nul
|
|
120
137
|
if not defined expected goto verify_refuse
|
|
121
138
|
if not defined actual goto verify_refuse
|
|
122
139
|
set "actual=%actual: =%"
|
|
123
140
|
if /I "%actual%"=="%expected%" goto place
|
|
124
|
-
|
|
141
|
+
call :discard_staging
|
|
125
142
|
echo impeccable: checksum mismatch downloading %url% 1>&2
|
|
126
143
|
exit /b 127
|
|
127
144
|
|
|
128
145
|
:verify_refuse
|
|
129
146
|
call :check_download
|
|
130
147
|
if errorlevel 1 exit /b 127
|
|
131
|
-
|
|
132
|
-
del "%cached%.sha256" >nul 2>nul
|
|
148
|
+
call :discard_staging
|
|
133
149
|
echo impeccable: cannot verify %url% against %url%.sha256; refusing the unverified download 1>&2
|
|
134
150
|
exit /b 127
|
|
135
151
|
|
|
136
152
|
:check_download
|
|
137
153
|
set "download_file=%~1"
|
|
138
|
-
if not defined download_file set "download_file=%
|
|
154
|
+
if not defined download_file set "download_file=%part%"
|
|
139
155
|
if not exist "%download_file%" goto download_missing
|
|
140
156
|
for %%f in ("%download_file%") do if %%~zf==0 goto download_empty
|
|
141
157
|
exit /b 0
|
|
142
158
|
|
|
143
159
|
:download_missing
|
|
144
|
-
|
|
160
|
+
call :discard_staging
|
|
145
161
|
echo impeccable: download completed but the file was removed before execution: %url%; check your antivirus quarantine or logs. Refusing to continue; do not disable protection. 1>&2
|
|
146
162
|
exit /b 127
|
|
147
163
|
|
|
148
164
|
:download_empty
|
|
149
165
|
del "%download_file%" >nul 2>nul
|
|
150
|
-
|
|
166
|
+
call :discard_staging
|
|
151
167
|
echo impeccable: downloaded file is empty: %url%; refusing the unverified download 1>&2
|
|
152
168
|
exit /b 127
|
|
153
169
|
|
|
170
|
+
:discard_staging
|
|
171
|
+
rem Removes this run's staging directory and whatever is left in it. Never
|
|
172
|
+
rem touches another run's staging directory or the cached binary.
|
|
173
|
+
if defined staging rd /s /q "%staging%" >nul 2>nul
|
|
174
|
+
exit /b 0
|
|
175
|
+
|
|
154
176
|
:place
|
|
155
177
|
call :check_download
|
|
156
178
|
if errorlevel 1 exit /b 127
|
|
157
|
-
move /y "%
|
|
179
|
+
move /y "%part%" "%cached%" >nul 2>nul
|
|
158
180
|
if errorlevel 1 goto place_failed
|
|
181
|
+
call :discard_staging
|
|
159
182
|
call :check_download "%cached%"
|
|
160
183
|
if errorlevel 1 exit /b 127
|
|
161
184
|
set "run=%cached%"
|
|
@@ -164,7 +187,7 @@ goto run
|
|
|
164
187
|
:place_failed
|
|
165
188
|
call :check_download
|
|
166
189
|
if errorlevel 1 exit /b 127
|
|
167
|
-
|
|
190
|
+
call :discard_staging
|
|
168
191
|
echo impeccable: could not cache the verified download: %url% 1>&2
|
|
169
192
|
exit /b 127
|
|
170
193
|
|
|
@@ -193,6 +216,9 @@ exit /b 0
|
|
|
193
216
|
echo impeccable: engine %version% is not installed; cannot create cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2
|
|
194
217
|
goto setup_failed
|
|
195
218
|
|
|
219
|
+
:staging_write_failed
|
|
220
|
+
call :discard_staging
|
|
221
|
+
|
|
196
222
|
:cache_write_failed
|
|
197
223
|
echo impeccable: engine %version% is not installed; cannot write to cache directory: "%IMPECCABLE_HOME%\bin\%version%" 1>&2
|
|
198
224
|
goto setup_failed
|
|
@@ -202,7 +228,7 @@ echo impeccable: cannot download engine %version%; curl.exe is unavailable. 1>&2
|
|
|
202
228
|
goto setup_failed
|
|
203
229
|
|
|
204
230
|
:download_failed
|
|
205
|
-
|
|
231
|
+
call :discard_staging
|
|
206
232
|
echo impeccable: could not download engine %version% from %url%; check network access and the release URL. 1>&2
|
|
207
233
|
|
|
208
234
|
:setup_failed
|
|
@@ -212,7 +238,6 @@ echo Alternatively, set IMPECCABLE_HOME to a writable cache location, or IMPECCA
|
|
|
212
238
|
exit /b 127
|
|
213
239
|
|
|
214
240
|
:fail
|
|
215
|
-
del "%cached%.part" >nul 2>nul
|
|
216
241
|
echo impeccable: no engine binary found (looked in %bin%, %cached%, PATH). 1>&2
|
|
217
242
|
echo Download impeccable-windows-%arch%.exe from https://github.com/pbakaus/impeccable/releases (tag engine-v%version%) and save it as %cached%, or set IMPECCABLE_BIN to a preinstalled engine binary. Docs: https://impeccable.style 1>&2
|
|
218
243
|
exit /b 127
|
|
@@ -85,7 +85,10 @@
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
function id8() {
|
|
88
|
-
|
|
88
|
+
// randomUUID is secure-context only (issue #1055); getRandomValues is not.
|
|
89
|
+
try {
|
|
90
|
+
if (typeof crypto?.randomUUID === 'function') return crypto.randomUUID().replace(/-/g, '').slice(0, 8);
|
|
91
|
+
} catch { /* fall through */ }
|
|
89
92
|
// Insecure-context fallback (plain-http LAN preview): still draw from the
|
|
90
93
|
// CSPRNG. Math.random here was flagged by CodeQL (js/insecure-randomness)
|
|
91
94
|
// because these ids name live-edit sessions.
|
|
@@ -200,6 +203,35 @@
|
|
|
200
203
|
return el;
|
|
201
204
|
}
|
|
202
205
|
|
|
206
|
+
// Copy text through a selected textarea and execCommand, for origins where
|
|
207
|
+
// navigator.clipboard is missing or refused (plain HTTP, issue #1055).
|
|
208
|
+
// The textarea mounts like any page-level chrome, so while a modal
|
|
209
|
+
// <dialog> is open it sits in that dialog's top-layer host: on <body> it
|
|
210
|
+
// would be inert, and inert text cannot be selected or copied.
|
|
211
|
+
function copyTextViaSelection(text) {
|
|
212
|
+
let ta = null;
|
|
213
|
+
const previous = activeElementDeep();
|
|
214
|
+
try {
|
|
215
|
+
ta = doc.createElement('textarea');
|
|
216
|
+
ta.id = prefix + '-clipboard';
|
|
217
|
+
ta.value = text;
|
|
218
|
+
ta.setAttribute('readonly', '');
|
|
219
|
+
ta.setAttribute('aria-hidden', 'true');
|
|
220
|
+
ta.tabIndex = -1;
|
|
221
|
+
ta.style.cssText = 'position:fixed;top:0;left:0;width:1px;height:1px;opacity:0;pointer-events:none;';
|
|
222
|
+
uiAppendToPage(ta);
|
|
223
|
+
ta.select();
|
|
224
|
+
return doc.execCommand('copy');
|
|
225
|
+
} catch {
|
|
226
|
+
return false;
|
|
227
|
+
} finally {
|
|
228
|
+
ta?.remove();
|
|
229
|
+
if (previous && previous !== activeElementDeep() && typeof previous.focus === 'function') {
|
|
230
|
+
try { previous.focus({ preventScroll: true }); } catch { /* best effort */ }
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
203
235
|
function uiAppend(el) {
|
|
204
236
|
const uiRoot = liveUiRoot();
|
|
205
237
|
if (uiRoot === doc.body) return uiAppendToPage(el);
|
|
@@ -267,6 +299,7 @@
|
|
|
267
299
|
liveUiRoot,
|
|
268
300
|
uiAppend,
|
|
269
301
|
uiAppendToPage,
|
|
302
|
+
copyTextViaSelection,
|
|
270
303
|
topLayerHost,
|
|
271
304
|
watchModalDialogs,
|
|
272
305
|
cloneWithoutChrome,
|
|
@@ -8,6 +8,30 @@
|
|
|
8
8
|
(function (root) {
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
+
// crypto.randomUUID() exists only in secure contexts (HTTPS, localhost), so a
|
|
12
|
+
// dev site on a LAN IP, a Tailscale address, or a custom hostname over plain
|
|
13
|
+
// HTTP has no randomUUID at all (issue #1055). getRandomValues() is available
|
|
14
|
+
// in every context, so the fallback still draws from the CSPRNG: the upstream
|
|
15
|
+
// Math.random last resort is the insecure-randomness class CodeQL flagged in
|
|
16
|
+
// the id8 helper, and these ids name live-edit sessions.
|
|
17
|
+
function randomUUID(cryptoImpl) {
|
|
18
|
+
const c = cryptoImpl === undefined ? root.crypto : cryptoImpl;
|
|
19
|
+
try {
|
|
20
|
+
if (c && typeof c.randomUUID === 'function') return c.randomUUID();
|
|
21
|
+
} catch { /* fall through to getRandomValues */ }
|
|
22
|
+
const bytes = new Uint8Array(16);
|
|
23
|
+
(c || crypto).getRandomValues(bytes);
|
|
24
|
+
bytes[6] = (bytes[6] & 0x0f) | 0x40; // version 4
|
|
25
|
+
bytes[8] = (bytes[8] & 0x3f) | 0x80; // RFC 4122 variant
|
|
26
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
|
|
27
|
+
return hex.slice(0, 8) + '-' + hex.slice(8, 12) + '-' + hex.slice(12, 16)
|
|
28
|
+
+ '-' + hex.slice(16, 20) + '-' + hex.slice(20);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function randomId8(cryptoImpl) {
|
|
32
|
+
return randomUUID(cryptoImpl).replace(/-/g, '').slice(0, 8);
|
|
33
|
+
}
|
|
34
|
+
|
|
11
35
|
function createLiveBrowserSessionState({ prefix, storage, idFactory }) {
|
|
12
36
|
if (!prefix) throw new Error('prefix required');
|
|
13
37
|
const store = storage || root.localStorage;
|
|
@@ -150,5 +174,5 @@
|
|
|
150
174
|
};
|
|
151
175
|
}
|
|
152
176
|
|
|
153
|
-
root.__IMPECCABLE_LIVE_SESSION__ = { createLiveBrowserSessionState };
|
|
177
|
+
root.__IMPECCABLE_LIVE_SESSION__ = { createLiveBrowserSessionState, randomUUID, randomId8 };
|
|
154
178
|
})(typeof window !== 'undefined' ? window : globalThis);
|
|
@@ -61,11 +61,19 @@
|
|
|
61
61
|
const IMPECCABLE_COMMAND = (window.__IMPECCABLE_COMMAND_PREFIX__ || '/') + 'impeccable';
|
|
62
62
|
const PICK_CURSOR_STYLE_ID = PREFIX + '-pick-cursor-style';
|
|
63
63
|
const MANUAL_APPLY_STATE_TTL_MS = 15 * 60 * 1000;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
// No idFactory: the session helper's default works on plain-HTTP origins,
|
|
65
|
+
// where the secure-context-only randomUUID does not exist (issue #1055).
|
|
66
|
+
let sessionState = null;
|
|
67
|
+
try {
|
|
68
|
+
sessionState = window.__IMPECCABLE_LIVE_SESSION__?.createLiveBrowserSessionState({
|
|
69
|
+
prefix: PREFIX,
|
|
70
|
+
storage: localStorage,
|
|
71
|
+
});
|
|
72
|
+
} catch (err) {
|
|
73
|
+
console.error('[impeccable] Live mode could not create its session state.', err);
|
|
74
|
+
window.__IMPECCABLE_LIVE_INIT__ = false; // let a later injection retry
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
69
77
|
if (!sessionState) {
|
|
70
78
|
console.error('[impeccable] live-browser-session.js was not loaded. Live mode cannot start safely.');
|
|
71
79
|
window.__IMPECCABLE_LIVE_INIT__ = false;
|
|
@@ -293,6 +301,7 @@
|
|
|
293
301
|
liveUiRoot,
|
|
294
302
|
uiAppend,
|
|
295
303
|
uiAppendToPage,
|
|
304
|
+
copyTextViaSelection,
|
|
296
305
|
topLayerHost,
|
|
297
306
|
watchModalDialogs,
|
|
298
307
|
cloneWithoutChrome,
|
|
@@ -7120,6 +7129,10 @@
|
|
|
7120
7129
|
//
|
|
7121
7130
|
|
|
7122
7131
|
function startScrollTracking() {
|
|
7132
|
+
// Idempotent: callers overlap (showBar starts tracking, then the agent
|
|
7133
|
+
// pick path starts it again), and a second loop would never be cancelled
|
|
7134
|
+
// because scrollRaf only remembers the latest one (#1002).
|
|
7135
|
+
stopScrollTracking();
|
|
7123
7136
|
function tick() {
|
|
7124
7137
|
if (state === 'CONFIGURING' || state === 'GENERATING' || state === 'CYCLING') {
|
|
7125
7138
|
if (isInsertGeneratingSession()) ensureInsertPlaceholder();
|
|
@@ -13461,12 +13474,24 @@ void main() {
|
|
|
13461
13474
|
.replace(/'/g, ''');
|
|
13462
13475
|
}
|
|
13463
13476
|
|
|
13477
|
+
// navigator.clipboard exists only in secure contexts, and writeText can
|
|
13478
|
+
// reject even where it exists (no focus, permission). Fall back
|
|
13479
|
+
// to the DOM helpers' selection copy (execCommand), which plain-HTTP origins
|
|
13480
|
+
// still allow and which stays usable under an open modal dialog.
|
|
13464
13481
|
function copyToClipboard(text) {
|
|
13465
13482
|
if (!text) return;
|
|
13483
|
+
const report = (ok) => showToast(ok ? 'Copied: ' + text : 'Could not copy: ' + text);
|
|
13484
|
+
let pending = null;
|
|
13466
13485
|
try {
|
|
13467
|
-
navigator.clipboard.writeText
|
|
13468
|
-
|
|
13469
|
-
|
|
13486
|
+
if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
|
|
13487
|
+
pending = navigator.clipboard.writeText(text);
|
|
13488
|
+
}
|
|
13489
|
+
} catch { pending = null; }
|
|
13490
|
+
if (pending && typeof pending.then === 'function') {
|
|
13491
|
+
pending.then(() => report(true), () => report(copyTextViaSelection(text)));
|
|
13492
|
+
return;
|
|
13493
|
+
}
|
|
13494
|
+
report(copyTextViaSelection(text));
|
|
13470
13495
|
}
|
|
13471
13496
|
|
|
13472
13497
|
//
|
|
@@ -7,13 +7,13 @@ export interface RunJournalSettings {
|
|
|
7
7
|
};
|
|
8
8
|
storage?: StorageSettingsSelection;
|
|
9
9
|
}
|
|
10
|
-
export
|
|
10
|
+
export interface RunJournalResolutionOptions {
|
|
11
11
|
journal?: RunJournalOption;
|
|
12
12
|
settings?: RunJournalSettings;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export declare function openSelectedRunJournal(selection: StorageSelection | RunJournal): Promise<RunJournal>;
|
|
13
|
+
/** The agent directory the owning session resolved its storage against; defaults to `getAgentDir()`. */
|
|
14
|
+
agentDir?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function selectRunJournal(options?: RunJournalResolutionOptions): StorageSelection | RunJournal;
|
|
17
|
+
export declare function resolveRunJournal(options?: RunJournalResolutionOptions): Promise<RunJournal>;
|
|
18
|
+
export declare function openSelectedRunJournal(selection: StorageSelection | RunJournal, agentDir?: string): Promise<RunJournal>;
|
|
19
19
|
export declare function withRunJournalConfigSource<T>(selection: StorageSelection | RunJournal, open: () => Promise<T>): Promise<T>;
|