@bastani/atomic 0.9.28-alpha.3 → 0.9.28-alpha.5
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 +39 -0
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/README.md +3 -2
- package/dist/builtin/intercom/broker/broker.ts +90 -14
- package/dist/builtin/intercom/broker/paths.ts +4 -0
- package/dist/builtin/intercom/broker/socket-liveness.ts +32 -0
- package/dist/builtin/intercom/broker/socket-replacement-lock.ts +104 -0
- package/dist/builtin/intercom/broker/spawn.ts +108 -63
- package/dist/builtin/intercom/index.bundle.mjs +114 -61
- package/dist/builtin/intercom/package.json +2 -2
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +6 -0
- package/dist/builtin/subagents/package.json +3 -3
- package/dist/builtin/subagents/skills/agent-browser/SKILL.md +1 -1
- package/dist/builtin/subagents/skills/cua-driver/BROWSER.md +60 -39
- package/dist/builtin/subagents/skills/cua-driver/EMBEDDING.md +119 -36
- package/dist/builtin/subagents/skills/cua-driver/LINUX.md +225 -183
- package/dist/builtin/subagents/skills/cua-driver/MACOS.md +120 -89
- package/dist/builtin/subagents/skills/cua-driver/README.md +16 -7
- package/dist/builtin/subagents/skills/cua-driver/RECORDING.md +85 -115
- package/dist/builtin/subagents/skills/cua-driver/RUNTIME.md +113 -0
- package/dist/builtin/subagents/skills/cua-driver/SKILL.md +55 -1071
- package/dist/builtin/subagents/skills/cua-driver/VISUAL.md +125 -0
- package/dist/builtin/subagents/skills/cua-driver/WINDOWS.md +145 -185
- package/dist/builtin/subagents/skills/cua-driver/WORKFLOW.md +173 -0
- package/dist/builtin/web-access/package.json +2 -2
- package/dist/builtin/workflows/CHANGELOG.md +16 -0
- package/dist/builtin/workflows/README.md +1 -1
- package/dist/builtin/workflows/builtin/{chunk-aqv8ny38.js → chunk-9ywkdsa9.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-p6jagvyf.js → chunk-bnz4knhy.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-br4ac9a3.js → chunk-dx5sjaxe.js} +1 -1
- package/dist/builtin/workflows/builtin/{chunk-p3xmajmj.js → chunk-v4scsq3y.js} +41 -13
- package/dist/builtin/workflows/builtin/goal.js +2 -2
- package/dist/builtin/workflows/builtin/index.js +3 -3
- package/dist/builtin/workflows/builtin/ralph.js +2 -2
- package/dist/builtin/workflows/package.json +2 -2
- package/dist/builtin/workflows/skills/impeccable/SKILL.md +8 -2
- package/dist/builtin/workflows/skills/impeccable/reference/adapt.md +6 -0
- package/dist/builtin/workflows/skills/impeccable/reference/audit.md +2 -1
- package/dist/builtin/workflows/skills/impeccable/reference/component-review.md +63 -0
- package/dist/builtin/workflows/skills/impeccable/reference/degraded/asset-producer.md +5 -0
- package/dist/builtin/workflows/skills/impeccable/reference/degraded/finish-reviewer.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/generate.md +101 -0
- package/dist/builtin/workflows/skills/impeccable/reference/harden.md +9 -0
- package/dist/builtin/workflows/skills/impeccable/reference/hooks.md +3 -1
- package/dist/builtin/workflows/skills/impeccable/reference/mode-operate.md +21 -0
- package/dist/builtin/workflows/skills/impeccable/reference/mode-persuade.md +19 -0
- package/dist/builtin/workflows/skills/impeccable/reference/mode-read.md +21 -0
- package/dist/builtin/workflows/skills/impeccable/reference/new-work.md +19 -12
- package/dist/builtin/workflows/skills/impeccable/reference/region-map.md +26 -0
- package/dist/builtin/workflows/skills/impeccable/reference/routing.md +1 -1
- package/dist/builtin/workflows/skills/impeccable/reference/visualize.md +5 -5
- package/dist/builtin/workflows/skills/impeccable/scripts/VERSION +1 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/command-metadata.json +4 -0
- package/dist/builtin/workflows/skills/impeccable/scripts/impeccable.cmd +2 -2
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser-session.js +5 -1
- package/dist/builtin/workflows/skills/impeccable/scripts/live-browser.js +524 -4
- package/dist/builtin/workflows/skills/prompt-engineer/SKILL.md +1 -0
- package/dist/builtin/workflows/skills/prompt-engineer/references/claude_haiku_5_5.md +81 -0
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +38 -14
- package/dist/builtin/workflows/src/index.js +38 -14
- package/dist/cli/startup-ui.d.ts +3 -2
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +19 -4
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/codemode-worker.js +2 -2
- package/dist/core/agent-session-compaction.d.ts +3 -3
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +5 -1
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +1 -0
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-extension-bindings.d.ts.map +1 -1
- package/dist/core/agent-session-extension-bindings.js +4 -0
- package/dist/core/agent-session-extension-bindings.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +6 -1
- 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.map +1 -1
- package/dist/core/agent-session-prompt.js +3 -2
- package/dist/core/agent-session-prompt.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts +5 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +13 -9
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +1 -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 +1 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js +2 -0
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/agent-events.d.ts +2 -0
- package/dist/core/extensions/agent-events.d.ts.map +1 -1
- package/dist/core/extensions/agent-events.js.map +1 -1
- package/dist/core/extensions/context-types.d.ts +2 -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/mcp-server-registry.d.ts +4 -1
- package/dist/core/extensions/mcp-server-registry.d.ts.map +1 -1
- package/dist/core/extensions/mcp-server-registry.js +7 -4
- package/dist/core/extensions/mcp-server-registry.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +3 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +19 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/session-events.d.ts +2 -0
- package/dist/core/extensions/session-events.d.ts.map +1 -1
- package/dist/core/extensions/session-events.js.map +1 -1
- package/dist/core/extensions/tool-types.d.ts +2 -0
- package/dist/core/extensions/tool-types.d.ts.map +1 -1
- package/dist/core/extensions/tool-types.js.map +1 -1
- package/dist/core/fast-model-variants.d.ts.map +1 -1
- package/dist/core/fast-model-variants.js +3 -2
- package/dist/core/fast-model-variants.js.map +1 -1
- package/dist/core/model-resolver-defaults.d.ts.map +1 -1
- package/dist/core/model-resolver-defaults.js +2 -0
- package/dist/core/model-resolver-defaults.js.map +1 -1
- package/dist/core/nested-tool-calls.d.ts +1 -0
- package/dist/core/nested-tool-calls.d.ts.map +1 -1
- package/dist/core/nested-tool-calls.js +1 -0
- package/dist/core/nested-tool-calls.js.map +1 -1
- package/dist/core/provider-alias.d.ts.map +1 -1
- package/dist/core/provider-alias.js +8 -0
- package/dist/core/provider-alias.js.map +1 -1
- package/dist/core/provider-composer-internal.d.ts.map +1 -1
- package/dist/core/provider-composer-internal.js +6 -3
- package/dist/core/provider-composer-internal.js.map +1 -1
- package/dist/core/resource-loader-reload.d.ts.map +1 -1
- package/dist/core/resource-loader-reload.js +1 -0
- package/dist/core/resource-loader-reload.js.map +1 -1
- package/dist/core/resource-loader-types.d.ts +1 -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/settings-types.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +7 -3
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.js +1 -1
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/extensions/codemode/execute.d.ts.map +1 -1
- package/dist/extensions/codemode/execute.js +55 -7
- package/dist/extensions/codemode/execute.js.map +1 -1
- package/dist/extensions/codemode/index.d.ts.map +1 -1
- package/dist/extensions/codemode/index.js +7 -0
- package/dist/extensions/codemode/index.js.map +1 -1
- package/dist/extensions/codemode/tool.d.ts +2 -0
- package/dist/extensions/codemode/tool.d.ts.map +1 -1
- package/dist/extensions/codemode/tool.js +2 -0
- package/dist/extensions/codemode/tool.js.map +1 -1
- package/dist/extensions/herdr/index.d.ts.map +1 -1
- package/dist/extensions/herdr/index.js +20 -2
- package/dist/extensions/herdr/index.js.map +1 -1
- package/dist/extensions/herdr/pane-owner.d.ts +7 -0
- package/dist/extensions/herdr/pane-owner.d.ts.map +1 -1
- package/dist/extensions/herdr/pane-owner.js +53 -11
- package/dist/extensions/herdr/pane-owner.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main-deferred-startup.d.ts +8 -0
- package/dist/main-deferred-startup.d.ts.map +1 -1
- package/dist/main-deferred-startup.js +6 -0
- package/dist/main-deferred-startup.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +11 -3
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +5 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +17 -14
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +2 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +5 -2
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts +1 -0
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js +19 -8
- package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
- package/dist/modes/interactive/components/compaction-boundary-message.d.ts +3 -2
- package/dist/modes/interactive/components/compaction-boundary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-boundary-message.js +7 -4
- package/dist/modes/interactive/components/compaction-boundary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.d.ts +3 -1
- package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-entry.js +8 -2
- package/dist/modes/interactive/components/custom-entry.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +1 -0
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector-items.js +1 -1
- package/dist/modes/interactive/components/settings-selector-items.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +5 -2
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +4 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +10 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-agent-events.js +3 -1
- package/dist/modes/interactive/interactive-agent-events.js.map +1 -1
- package/dist/modes/interactive/interactive-auth-login.js +6 -0
- package/dist/modes/interactive/interactive-auth-login.js.map +1 -1
- package/dist/modes/interactive/interactive-auth-routing.js +2 -2
- package/dist/modes/interactive/interactive-auth-routing.js.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-dialogs.js +19 -2
- package/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode-base.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-base.js +7 -0
- package/dist/modes/interactive/interactive-mode-base.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-helpers.js +1 -1
- package/dist/modes/interactive/interactive-mode-helpers.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-mode-types.d.ts +1 -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-process-lifecycle.js +1 -1
- package/dist/modes/interactive/interactive-process-lifecycle.js.map +1 -1
- package/dist/modes/interactive/interactive-render-chat.js +7 -5
- package/dist/modes/interactive/interactive-render-chat.js.map +1 -1
- package/dist/modes/interactive/interactive-selectors.js +8 -1
- package/dist/modes/interactive/interactive-selectors.js.map +1 -1
- package/dist/modes/interactive/interactive-session-runtime.js +1 -0
- package/dist/modes/interactive/interactive-session-runtime.js.map +1 -1
- package/dist/modes/interactive/interactive-startup-trust.d.ts +6 -0
- package/dist/modes/interactive/interactive-startup-trust.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-startup-trust.js +15 -0
- package/dist/modes/interactive/interactive-startup-trust.js.map +1 -0
- package/dist/modes/interactive/interactive-startup.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-startup.js +4 -0
- package/dist/modes/interactive/interactive-startup.js.map +1 -1
- package/dist/modes/interactive/program-status-reporter.d.ts +24 -0
- package/dist/modes/interactive/program-status-reporter.d.ts.map +1 -0
- package/dist/modes/interactive/program-status-reporter.js +96 -0
- package/dist/modes/interactive/program-status-reporter.js.map +1 -0
- package/dist/modes/interactive-engine/engine-child-liveness.d.ts +1 -0
- package/dist/modes/interactive-engine/engine-child-liveness.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-child-liveness.js +15 -1
- package/dist/modes/interactive-engine/engine-child-liveness.js.map +1 -1
- 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/engine-monitor.d.ts +4 -0
- package/dist/modes/interactive-engine/engine-monitor.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-monitor.js +17 -0
- package/dist/modes/interactive-engine/engine-monitor.js.map +1 -1
- package/dist/modes/interactive-engine/engine-quit-intent.d.ts +16 -0
- package/dist/modes/interactive-engine/engine-quit-intent.d.ts.map +1 -0
- package/dist/modes/interactive-engine/engine-quit-intent.js +27 -0
- package/dist/modes/interactive-engine/engine-quit-intent.js.map +1 -0
- package/dist/modes/interactive-engine/engine-render-service.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-render-service.js +3 -1
- package/dist/modes/interactive-engine/engine-render-service.js.map +1 -1
- package/dist/modes/interactive-engine/extension-ui-bridge.d.ts +1 -0
- package/dist/modes/interactive-engine/extension-ui-bridge.d.ts.map +1 -1
- package/dist/modes/interactive-engine/extension-ui-bridge.js +5 -0
- package/dist/modes/interactive-engine/extension-ui-bridge.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts +4 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +19 -2
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/interactive-engine/protocol.d.ts +19 -1
- package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
- package/dist/modes/interactive-engine/protocol.js +7 -0
- package/dist/modes/interactive-engine/protocol.js.map +1 -1
- package/dist/modes/interactive-engine/remote-renderer.d.ts +3 -0
- package/dist/modes/interactive-engine/remote-renderer.d.ts.map +1 -1
- package/dist/modes/interactive-engine/remote-renderer.js +7 -0
- package/dist/modes/interactive-engine/remote-renderer.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +11 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +42 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-input-scheduler.js +2 -2
- package/dist/modes/rpc/rpc-input-scheduler.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +23 -6
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-provider-auth.js +1 -1
- package/dist/modes/rpc/rpc-provider-auth.js.map +1 -1
- package/docs/codemode.md +10 -6
- package/docs/compaction.md +1 -1
- package/docs/computer-use.md +9 -9
- package/docs/custom-provider/streaming.md +4 -0
- package/docs/environment-variables.md +2 -0
- package/docs/extensions/api-reference.md +1 -1
- package/docs/extensions/authoring.md +2 -0
- package/docs/extensions/events.md +8 -1
- package/docs/getting-started/first-session.md +1 -1
- package/docs/herdr.md +11 -2
- package/docs/json.md +6 -1
- package/docs/models/evals.md +34 -3
- package/docs/models.md +1 -1
- package/docs/providers.md +10 -0
- package/docs/sdk.md +8 -2
- package/docs/settings.md +2 -2
- package/docs/skills.md +1 -1
- package/docs/terminal-setup.md +14 -0
- package/docs/workflows/authoring.md +3 -3
- package/examples/extensions/sandbox/package-lock.json +3 -3
- package/npm-shrinkwrap.json +67 -67
- package/package.json +8 -8
|
@@ -165,6 +165,14 @@
|
|
|
165
165
|
}
|
|
166
166
|
let parameterGenerationState = 'idle';
|
|
167
167
|
let parameterReadyAnnouncedSession = null;
|
|
168
|
+
// 'agent' when the generate verb fired this session's Go (the generate
|
|
169
|
+
// lane declares no knobs, so its bar never shows a pending Tune chip);
|
|
170
|
+
// null for every Go a user presses.
|
|
171
|
+
let sessionOrigin = null;
|
|
172
|
+
// The generate lane picks for the agent and never edits copy in the
|
|
173
|
+
// browser, so its selection carries no edit-copy badge (set on the
|
|
174
|
+
// agent-target pick, cleared with the session; a user's pick never sets it).
|
|
175
|
+
let editBadgeSuppressed = false;
|
|
168
176
|
let svelteComponentSession = null;
|
|
169
177
|
let svelteRuntimePromise = null;
|
|
170
178
|
let pendingSvelteComponentRetryObserver = null;
|
|
@@ -983,9 +991,20 @@
|
|
|
983
991
|
}
|
|
984
992
|
} catch { /* cross-origin */ }
|
|
985
993
|
}
|
|
994
|
+
// The selector a mechanical bake would anchor lasting rules on, and how
|
|
995
|
+
// many elements it matches right now: the bake refuses anything but one,
|
|
996
|
+
// since its rules would restyle every match, not just this element.
|
|
997
|
+
const cssIdent = (s) => /^[A-Za-z_-][\w-]*$/.test(s);
|
|
998
|
+
const anchorClasses = [...el.classList].filter(cssIdent);
|
|
999
|
+
const anchor = el.id && cssIdent(el.id)
|
|
1000
|
+
? '#' + el.id
|
|
1001
|
+
: (anchorClasses.length ? el.tagName.toLowerCase() + '.' + anchorClasses.join('.') : null);
|
|
1002
|
+
let anchorMatches = null;
|
|
1003
|
+
if (anchor) { try { anchorMatches = document.querySelectorAll(anchor).length; } catch { anchorMatches = null; } }
|
|
986
1004
|
return {
|
|
987
1005
|
tagName: el.tagName.toLowerCase(), id: el.id || null,
|
|
988
1006
|
classes: [...el.classList],
|
|
1007
|
+
anchor, anchorMatches,
|
|
989
1008
|
textContent: (el.textContent || '').slice(0, 500),
|
|
990
1009
|
outerHTML: sanitizedContextOuterHTML(el, 10000),
|
|
991
1010
|
computedStyles: {
|
|
@@ -2037,6 +2056,7 @@
|
|
|
2037
2056
|
function setLiveState(next) {
|
|
2038
2057
|
state = next;
|
|
2039
2058
|
window.__IMPECCABLE_LIVE_STATE__ = next;
|
|
2059
|
+
retryDeclinedAgentTargets();
|
|
2040
2060
|
syncPageInteractionCursor();
|
|
2041
2061
|
// Whether a queued steer is still behind a generation is a function of this
|
|
2042
2062
|
// state, so the hint has to move with it, not only with the 5s poll.
|
|
@@ -4014,6 +4034,7 @@
|
|
|
4014
4034
|
|
|
4015
4035
|
function hidePendingApplyDock() {
|
|
4016
4036
|
pendingApplyInFlight = false;
|
|
4037
|
+
retryDeclinedAgentTargets();
|
|
4017
4038
|
clearStoredManualApplyState();
|
|
4018
4039
|
if (pendingIntroAnimation) { pendingIntroAnimation.cancel(); pendingIntroAnimation = null; }
|
|
4019
4040
|
if (pendingDockEl) pendingDockEl.style.display = 'none';
|
|
@@ -4047,6 +4068,7 @@
|
|
|
4047
4068
|
function setPendingApplyLoading(loading, count) {
|
|
4048
4069
|
if (!pendingPillEl || !pendingPillLabelEl || !pendingPillCountEl || !pendingTrashBtn) return;
|
|
4049
4070
|
pendingApplyInFlight = loading === true;
|
|
4071
|
+
if (!pendingApplyInFlight) retryDeclinedAgentTargets();
|
|
4050
4072
|
const currentCount = count || parseInt(pendingPillEl.dataset.count || '0', 10) || 0;
|
|
4051
4073
|
if (pendingApplyInFlight) storeManualApplyState(currentCount);
|
|
4052
4074
|
else clearStoredManualApplyState();
|
|
@@ -4688,6 +4710,7 @@
|
|
|
4688
4710
|
}
|
|
4689
4711
|
|
|
4690
4712
|
function renderEditBadge(mode) {
|
|
4713
|
+
if (editBadgeSuppressed || sessionOrigin === 'agent') mode = 'hidden';
|
|
4691
4714
|
if (mode === 'hidden' || !editBadgeEl) {
|
|
4692
4715
|
hideConfigureBarTooltip();
|
|
4693
4716
|
if (editBadgeEl) editBadgeEl.style.display = 'none';
|
|
@@ -6181,6 +6204,8 @@
|
|
|
6181
6204
|
resetSessionFileMeta();
|
|
6182
6205
|
currentSessionId = null;
|
|
6183
6206
|
parameterGenerationState = 'idle';
|
|
6207
|
+
sessionOrigin = null;
|
|
6208
|
+
editBadgeSuppressed = false;
|
|
6184
6209
|
parameterReadyAnnouncedSession = null;
|
|
6185
6210
|
expectedVariants = 0;
|
|
6186
6211
|
arrivedVariants = 0;
|
|
@@ -7112,6 +7137,398 @@
|
|
|
7112
7137
|
}
|
|
7113
7138
|
|
|
7114
7139
|
//
|
|
7140
|
+
// ------------------------------------------------------------------
|
|
7141
|
+
// Agent-initiated targeting (the `generate` command). The agent names an
|
|
7142
|
+
// element by CSS selector over POST /agent-target; the server pushes an
|
|
7143
|
+
// `agent_target` SSE message here. The overlay resolves the selector,
|
|
7144
|
+
// scrolls the element into view, enters the same picked state a user
|
|
7145
|
+
// click produces, and fires the normal Go pipeline, so everything
|
|
7146
|
+
// downstream (generate event, variants, cycling, accept) is unchanged.
|
|
7147
|
+
// The verdict goes back through POST /agent-target-result, which resolves
|
|
7148
|
+
// the agent's held-open CLI call.
|
|
7149
|
+
|
|
7150
|
+
function postAgentTargetResult(targetId, result) {
|
|
7151
|
+
fetch('http://localhost:' + PORT + '/agent-target-result?token=' + TOKEN, {
|
|
7152
|
+
method: 'POST',
|
|
7153
|
+
headers: { 'Content-Type': 'application/json' },
|
|
7154
|
+
body: JSON.stringify({ token: TOKEN, targetId, clientId: AGENT_TARGET_CLIENT_ID, ...result }),
|
|
7155
|
+
}).catch(() => { /* server gone; nothing to report to */ });
|
|
7156
|
+
}
|
|
7157
|
+
|
|
7158
|
+
function describeAgentTargetCandidate(el) {
|
|
7159
|
+
return {
|
|
7160
|
+
tag: el.tagName.toLowerCase(),
|
|
7161
|
+
id: el.id || null,
|
|
7162
|
+
classes: [...el.classList].filter((c) => !c.startsWith('impeccable-')),
|
|
7163
|
+
text: (el.textContent || '').trim().slice(0, 80),
|
|
7164
|
+
};
|
|
7165
|
+
}
|
|
7166
|
+
|
|
7167
|
+
function resolveAgentTargetElement(msg) {
|
|
7168
|
+
let matched;
|
|
7169
|
+
try {
|
|
7170
|
+
matched = [...document.querySelectorAll(msg.selector)];
|
|
7171
|
+
} catch {
|
|
7172
|
+
return { error: { ok: false, error: 'invalid_selector', selector: msg.selector } };
|
|
7173
|
+
}
|
|
7174
|
+
let candidates = matched.filter((el) => pickable(el));
|
|
7175
|
+
if (msg.text) {
|
|
7176
|
+
const needle = String(msg.text).toLowerCase();
|
|
7177
|
+
candidates = candidates.filter((el) => (el.textContent || '').toLowerCase().includes(needle));
|
|
7178
|
+
}
|
|
7179
|
+
if (candidates.length === 0) {
|
|
7180
|
+
return {
|
|
7181
|
+
error: {
|
|
7182
|
+
ok: false,
|
|
7183
|
+
error: 'no_match',
|
|
7184
|
+
selector: msg.selector,
|
|
7185
|
+
matchCount: 0,
|
|
7186
|
+
// How many nodes the raw selector hit before the pickable/text
|
|
7187
|
+
// filters: distinguishes a wrong selector from an unpickable match.
|
|
7188
|
+
rawMatchCount: matched.length,
|
|
7189
|
+
},
|
|
7190
|
+
};
|
|
7191
|
+
}
|
|
7192
|
+
if (Number.isInteger(msg.index)) {
|
|
7193
|
+
const el = candidates[msg.index - 1];
|
|
7194
|
+
if (!el) {
|
|
7195
|
+
return { error: { ok: false, error: 'index_out_of_range', selector: msg.selector, matchCount: candidates.length } };
|
|
7196
|
+
}
|
|
7197
|
+
return { el, matchCount: candidates.length };
|
|
7198
|
+
}
|
|
7199
|
+
if (candidates.length > 1) {
|
|
7200
|
+
return {
|
|
7201
|
+
error: {
|
|
7202
|
+
ok: false,
|
|
7203
|
+
error: 'ambiguous',
|
|
7204
|
+
selector: msg.selector,
|
|
7205
|
+
matchCount: candidates.length,
|
|
7206
|
+
candidates: candidates.slice(0, 8).map(describeAgentTargetCandidate),
|
|
7207
|
+
},
|
|
7208
|
+
};
|
|
7209
|
+
}
|
|
7210
|
+
return { el: candidates[0], matchCount: 1 };
|
|
7211
|
+
}
|
|
7212
|
+
|
|
7213
|
+
function scrollAgentTargetIntoView(el, done) {
|
|
7214
|
+
const rect = el.getBoundingClientRect();
|
|
7215
|
+
if (rect.top >= 0 && rect.bottom <= window.innerHeight) { done(); return; }
|
|
7216
|
+
let settled = false;
|
|
7217
|
+
let fallback = null;
|
|
7218
|
+
const finish = () => {
|
|
7219
|
+
if (settled) return;
|
|
7220
|
+
settled = true;
|
|
7221
|
+
removeEventListener('scrollend', finish, true);
|
|
7222
|
+
if (fallback) clearTimeout(fallback);
|
|
7223
|
+
done();
|
|
7224
|
+
};
|
|
7225
|
+
// scrollend where supported; a timer covers engines without it and the
|
|
7226
|
+
// no-movement case (element already at its final resting position).
|
|
7227
|
+
addEventListener('scrollend', finish, true);
|
|
7228
|
+
fallback = setTimeout(finish, 1200);
|
|
7229
|
+
el.scrollIntoView({ block: 'center', behavior: 'smooth' });
|
|
7230
|
+
}
|
|
7231
|
+
|
|
7232
|
+
// One id per page load: the server keys claims and roll-call reports on
|
|
7233
|
+
// it, and only the tab that holds the lease can renew it.
|
|
7234
|
+
const AGENT_TARGET_CLIENT_ID = id8();
|
|
7235
|
+
|
|
7236
|
+
// The agent target an agent-initiated Go is serving: set by
|
|
7237
|
+
// actOnAgentTarget around its handleGo call, read once by handleGo.
|
|
7238
|
+
let agentTargetForGo = null;
|
|
7239
|
+
|
|
7240
|
+
// The helper's word on its global bar. The generate lane asks the helper
|
|
7241
|
+
// to keep it out of the way (`impeccable live --no-live-bar`, or an agent
|
|
7242
|
+
// target carrying hideLiveBar), and the helper tells every connected tab
|
|
7243
|
+
// at once (`live_bar`) and every later connection on `connected`, so the
|
|
7244
|
+
// bar stays hidden in every tab, through reloads, the accept, and the
|
|
7245
|
+
// bake, until the helper stops and takes the overlay with it. The variant
|
|
7246
|
+
// controls still show.
|
|
7247
|
+
let liveBarHiddenByHelper = false;
|
|
7248
|
+
|
|
7249
|
+
function applyLiveBarPreference(hidden) {
|
|
7250
|
+
liveBarHiddenByHelper = hidden === true;
|
|
7251
|
+
setLiveBarHidden(liveBarHiddenByHelper);
|
|
7252
|
+
}
|
|
7253
|
+
|
|
7254
|
+
// A plain live session must never notice this code: hiding remembers the
|
|
7255
|
+
// bar's own display value and restoring puts exactly that back, and a
|
|
7256
|
+
// restore on a bar that is not hidden is a no-op, so the `connected`
|
|
7257
|
+
// frame every session receives changes nothing unless the lane asked.
|
|
7258
|
+
function setLiveBarHidden(hidden) {
|
|
7259
|
+
if (!globalBarEl) return;
|
|
7260
|
+
if (hidden) {
|
|
7261
|
+
if (globalBarEl.style.display !== 'none') {
|
|
7262
|
+
globalBarEl.dataset.liveBarDisplay = globalBarEl.style.display || 'flex';
|
|
7263
|
+
globalBarEl.style.display = 'none';
|
|
7264
|
+
}
|
|
7265
|
+
return;
|
|
7266
|
+
}
|
|
7267
|
+
if (globalBarEl.style.display === 'none') {
|
|
7268
|
+
globalBarEl.style.display = globalBarEl.dataset.liveBarDisplay || 'flex';
|
|
7269
|
+
}
|
|
7270
|
+
}
|
|
7271
|
+
|
|
7272
|
+
function claimAgentTarget(targetId, report) {
|
|
7273
|
+
return fetch('http://localhost:' + PORT + '/agent-target-claim?token=' + TOKEN, {
|
|
7274
|
+
method: 'POST',
|
|
7275
|
+
headers: { 'Content-Type': 'application/json' },
|
|
7276
|
+
body: JSON.stringify({ token: TOKEN, targetId, clientId: AGENT_TARGET_CLIENT_ID, ...report }),
|
|
7277
|
+
}).then((res) => res.json())
|
|
7278
|
+
.then((j) => ({ granted: !!j && j.granted === true, pending: !!j && j.pending === true }))
|
|
7279
|
+
.catch(() => ({ granted: false, pending: false }));
|
|
7280
|
+
}
|
|
7281
|
+
|
|
7282
|
+
// `exceptTargetId` is the target this call is about: a tab acting on it
|
|
7283
|
+
// is not busy for itself, but it is busy for every other target, or two
|
|
7284
|
+
// held requests could both be claimed here and the second Go would
|
|
7285
|
+
// overwrite the session the first one minted.
|
|
7286
|
+
function agentTargetBusyReason(exceptTargetId) {
|
|
7287
|
+
if (pendingApplyInFlight) return 'manual_apply_in_flight';
|
|
7288
|
+
if (state !== 'IDLE' && state !== 'PICKING' && state !== 'CONFIGURING') return 'session_active';
|
|
7289
|
+
for (const [targetId, status] of agentTargetsSeen) {
|
|
7290
|
+
if (status === 'acting' && targetId !== exceptTargetId) return 'agent_target_in_flight';
|
|
7291
|
+
}
|
|
7292
|
+
return null;
|
|
7293
|
+
}
|
|
7294
|
+
|
|
7295
|
+
// Targets this tab declined as busy. A busy report is only this tab's word
|
|
7296
|
+
// at that moment: the moment it is free again (setLiveState), it claims
|
|
7297
|
+
// each of these as eligible, and the server drops the stale report, so a
|
|
7298
|
+
// busy verdict is never built on a tab that has since gone idle. The
|
|
7299
|
+
// server denies claims for resolved targets, so retries are harmless.
|
|
7300
|
+
const busyDeclinedTargets = new Map();
|
|
7301
|
+
|
|
7302
|
+
function declineAgentTargetBusy(msg, busy) {
|
|
7303
|
+
busyDeclinedTargets.set(msg.targetId, msg);
|
|
7304
|
+
noteAgentTarget(msg.targetId, 'declined');
|
|
7305
|
+
claimAgentTarget(msg.targetId, { eligible: false, state, reason: busy });
|
|
7306
|
+
}
|
|
7307
|
+
|
|
7308
|
+
// A torn-down overlay, or one whose helper connection is gone, cannot
|
|
7309
|
+
// serve a target and must not even claim one: it would hold the lease for
|
|
7310
|
+
// a request it will never act on.
|
|
7311
|
+
function agentTargetOverlayGone() {
|
|
7312
|
+
return !evtSource;
|
|
7313
|
+
}
|
|
7314
|
+
|
|
7315
|
+
// A denied claimant retries at this cadence, a little over the lease, so
|
|
7316
|
+
// the first retry after a dead holder's lease lapses is granted.
|
|
7317
|
+
const AGENT_TARGET_RESCUE_RETRY_MS = 3500;
|
|
7318
|
+
|
|
7319
|
+
// Claim the lease and act as the holder. A denied claim means another tab
|
|
7320
|
+
// holds the lease. That holder can die before posting its result (reload,
|
|
7321
|
+
// crash, even after renewing), and its lease lapses after ~3s, so this tab
|
|
7322
|
+
// keeps retrying for as long as the server still holds the request: the
|
|
7323
|
+
// answer's `pending` is the server's word that the request is alive, and
|
|
7324
|
+
// it turns false the moment the request resolved or timed out, so no tab
|
|
7325
|
+
// retries a request nobody awaits. A tab that turned busy meanwhile joins
|
|
7326
|
+
// the roll call instead of taking a lease it cannot use. The first claim
|
|
7327
|
+
// and the busy-to-idle re-claim share this.
|
|
7328
|
+
function claimAndActOnAgentTarget(msg) {
|
|
7329
|
+
if (agentTargetOverlayGone()) return;
|
|
7330
|
+
const busy = agentTargetBusyReason(msg.targetId);
|
|
7331
|
+
if (busy) { declineAgentTargetBusy(msg, busy); return; }
|
|
7332
|
+
if (declineAgentTargetUnresolvable(msg)) return;
|
|
7333
|
+
claimAgentTarget(msg.targetId, { eligible: true }).then((claim) => {
|
|
7334
|
+
if (claim.granted) { noteAgentTarget(msg.targetId, 'acting'); actOnAgentTarget(msg); return; }
|
|
7335
|
+
noteAgentTarget(msg.targetId, 'denied');
|
|
7336
|
+
if (!claim.pending) return;
|
|
7337
|
+
setTimeout(() => claimAndActOnAgentTarget(msg), AGENT_TARGET_RESCUE_RETRY_MS);
|
|
7338
|
+
});
|
|
7339
|
+
}
|
|
7340
|
+
|
|
7341
|
+
function retryDeclinedAgentTargets() {
|
|
7342
|
+
if (busyDeclinedTargets.size === 0 || agentTargetBusyReason()) return;
|
|
7343
|
+
for (const [targetId, msg] of busyDeclinedTargets) {
|
|
7344
|
+
busyDeclinedTargets.delete(targetId);
|
|
7345
|
+
claimAndActOnAgentTarget(msg);
|
|
7346
|
+
}
|
|
7347
|
+
}
|
|
7348
|
+
|
|
7349
|
+
// This page's participation in each target it heard: 'acting' once a
|
|
7350
|
+
// claim was granted, 'done' once it replied (or stood down from a lapsed
|
|
7351
|
+
// lease), else the word it last gave. The server replays pending targets
|
|
7352
|
+
// to every connection that opens. After a reconnect that overlapped the
|
|
7353
|
+
// old connection the server still holds this page's word; after one that
|
|
7354
|
+
// did not, it dropped the word on the close, so a replayed target is
|
|
7355
|
+
// handled again: a busy or unresolvable page re-declines (idempotent), an
|
|
7356
|
+
// idle page claims.
|
|
7357
|
+
const agentTargetsSeen = new Map();
|
|
7358
|
+
function noteAgentTarget(targetId, status) {
|
|
7359
|
+
agentTargetsSeen.set(targetId, status);
|
|
7360
|
+
if (agentTargetsSeen.size > 100) agentTargetsSeen.delete(agentTargetsSeen.keys().next().value);
|
|
7361
|
+
}
|
|
7362
|
+
|
|
7363
|
+
// A target this page took a lease on is off-limits for a replay: while
|
|
7364
|
+
// acting (a second claim or Go), and once done, because its result may
|
|
7365
|
+
// still be on the wire and this tab is GENERATING by then, so handling
|
|
7366
|
+
// the replay would decline busy, hand the lease back mid-resolution, and
|
|
7367
|
+
// let another tab fire a second Go.
|
|
7368
|
+
function agentTargetTaken(targetId) {
|
|
7369
|
+
const status = agentTargetsSeen.get(targetId);
|
|
7370
|
+
return status === 'acting' || status === 'done';
|
|
7371
|
+
}
|
|
7372
|
+
|
|
7373
|
+
// Only a page that can resolve the target claims it. A tab whose page
|
|
7374
|
+
// lacks the element declines with its resolution verdict instead, so a
|
|
7375
|
+
// first-wins claim never lets the wrong page answer for a target that
|
|
7376
|
+
// another page has. The server prefers a busy report (a tab that could
|
|
7377
|
+
// serve later) over these, and returns the resolution verdict only when
|
|
7378
|
+
// no connected page can serve.
|
|
7379
|
+
//
|
|
7380
|
+
// An element can be momentarily absent (a route still rendering, an HMR
|
|
7381
|
+
// commit mid-swap), so a failed resolution is not this page's final word:
|
|
7382
|
+
// it is re-checked a few times over about two seconds, claiming the
|
|
7383
|
+
// moment the element mounts, and only the last miss is reported. The
|
|
7384
|
+
// server's timeout still bounds the whole exchange.
|
|
7385
|
+
// The page reports the miss at once (so the other overlays' words can
|
|
7386
|
+
// complete the roll call) and keeps re-checking at this cadence for as
|
|
7387
|
+
// long as the server says the request is pending: the server holds an
|
|
7388
|
+
// all-no_match roll call open for a short grace precisely so a late mount
|
|
7389
|
+
// can still be claimed, drops the stale report on an eligible claim, and
|
|
7390
|
+
// ends the watch by answering pending:false once the request resolved or
|
|
7391
|
+
// timed out.
|
|
7392
|
+
const AGENT_TARGET_RESOLVE_WATCH_MS = 500;
|
|
7393
|
+
|
|
7394
|
+
function declineAgentTargetUnresolvable(msg) {
|
|
7395
|
+
const probe = resolveAgentTargetElement(msg);
|
|
7396
|
+
if (!probe.error) return false;
|
|
7397
|
+
reportAgentTargetUnresolvable(msg, probe.error);
|
|
7398
|
+
return true;
|
|
7399
|
+
}
|
|
7400
|
+
|
|
7401
|
+
function reportAgentTargetUnresolvable(msg, error) {
|
|
7402
|
+
noteAgentTarget(msg.targetId, 'declined');
|
|
7403
|
+
claimAgentTarget(msg.targetId, { eligible: false, state, reason: 'no_match', result: error }).then((answer) => {
|
|
7404
|
+
if (!answer.pending) return;
|
|
7405
|
+
setTimeout(() => watchAgentTargetResolution(msg, error), AGENT_TARGET_RESOLVE_WATCH_MS);
|
|
7406
|
+
});
|
|
7407
|
+
}
|
|
7408
|
+
|
|
7409
|
+
function watchAgentTargetResolution(msg, lastError) {
|
|
7410
|
+
if (agentTargetOverlayGone() || agentTargetTaken(msg.targetId)) return;
|
|
7411
|
+
const busy = agentTargetBusyReason(msg.targetId);
|
|
7412
|
+
if (busy) { declineAgentTargetBusy(msg, busy); return; }
|
|
7413
|
+
const probe = resolveAgentTargetElement(msg);
|
|
7414
|
+
if (!probe.error) { claimAndActOnAgentTarget(msg); return; }
|
|
7415
|
+
// Still unresolvable: re-report (idempotent); the answer says whether
|
|
7416
|
+
// the server is still holding the request open.
|
|
7417
|
+
reportAgentTargetUnresolvable(msg, probe.error || lastError);
|
|
7418
|
+
}
|
|
7419
|
+
|
|
7420
|
+
function handleAgentTarget(msg) {
|
|
7421
|
+
if (!msg || typeof msg.targetId !== 'string') return;
|
|
7422
|
+
if (agentTargetTaken(msg.targetId)) return;
|
|
7423
|
+
noteAgentTarget(msg.targetId, 'heard');
|
|
7424
|
+
const busy = agentTargetBusyReason(msg.targetId);
|
|
7425
|
+
if (busy) {
|
|
7426
|
+
// Roll call: a busy tab reports itself and never acts. The server
|
|
7427
|
+
// answers `busy` the moment every connected overlay has reported, so
|
|
7428
|
+
// an idle tab elsewhere is never raced by a timer.
|
|
7429
|
+
declineAgentTargetBusy(msg, busy);
|
|
7430
|
+
return;
|
|
7431
|
+
}
|
|
7432
|
+
if (declineAgentTargetUnresolvable(msg)) return;
|
|
7433
|
+
// Eligible tabs race for the server's lease and only the holder acts. A
|
|
7434
|
+
// hidden tab yields a short head start so a visible one wins when both
|
|
7435
|
+
// exist, and still serves the request on its own: the user finds the
|
|
7436
|
+
// selection waiting when they return to it.
|
|
7437
|
+
setTimeout(() => claimAndActOnAgentTarget(msg), document.hidden ? 150 : 0);
|
|
7438
|
+
}
|
|
7439
|
+
|
|
7440
|
+
function actOnAgentTarget(msg) {
|
|
7441
|
+
if (agentTargetOverlayGone()) return;
|
|
7442
|
+
// Every exit ends this tab's acting state, so a later target is not
|
|
7443
|
+
// refused for a Go that already happened or never will.
|
|
7444
|
+
const reply = (result) => { noteAgentTarget(msg.targetId, 'done'); postAgentTargetResult(msg.targetId, result); };
|
|
7445
|
+
const busy = agentTargetBusyReason(msg.targetId);
|
|
7446
|
+
if (busy) {
|
|
7447
|
+
// Turned busy between claim and act: report it, which also hands the
|
|
7448
|
+
// lease back so the roll call can complete or a rescuer can claim.
|
|
7449
|
+
declineAgentTargetBusy(msg, busy);
|
|
7450
|
+
return;
|
|
7451
|
+
}
|
|
7452
|
+
const resolved = resolveAgentTargetElement(msg);
|
|
7453
|
+
if (resolved.error) {
|
|
7454
|
+
// The element went away between claim and act. A result would end the
|
|
7455
|
+
// request for every tab; a decline hands the lease back so another
|
|
7456
|
+
// page or a remount can still serve it.
|
|
7457
|
+
reportAgentTargetUnresolvable(msg, resolved.error);
|
|
7458
|
+
return;
|
|
7459
|
+
}
|
|
7460
|
+
const el = resolved.el;
|
|
7461
|
+
if (msg.dryRun) {
|
|
7462
|
+
reply({
|
|
7463
|
+
ok: true,
|
|
7464
|
+
dryRun: true,
|
|
7465
|
+
matchCount: resolved.matchCount,
|
|
7466
|
+
element: describeAgentTargetCandidate(el),
|
|
7467
|
+
});
|
|
7468
|
+
return;
|
|
7469
|
+
}
|
|
7470
|
+
scrollAgentTargetIntoView(el, () => {
|
|
7471
|
+
// Torn down during the scroll settle: do not renew. The lease lapses
|
|
7472
|
+
// for a rescuer instead of Go minting a session on a dismantled
|
|
7473
|
+
// overlay.
|
|
7474
|
+
if (agentTargetOverlayGone()) return;
|
|
7475
|
+
// Renew the lease right before the irreversible part: a tab whose
|
|
7476
|
+
// lease lapsed while it scrolled (a rescuer took over) stops here, so
|
|
7477
|
+
// one request never gets two Go presses.
|
|
7478
|
+
claimAgentTarget(msg.targetId, { eligible: true }).then((renewal) => {
|
|
7479
|
+
if (!renewal.granted) { noteAgentTarget(msg.targetId, 'done'); return; }
|
|
7480
|
+
// An insert placement left mid-configure gives way, exactly as a
|
|
7481
|
+
// click outside it does in handleClick.
|
|
7482
|
+
if (state === 'CONFIGURING' && configureKind === 'insert') cancelInsertConfigure();
|
|
7483
|
+
// Mirror of the user-click pick entry in handleClick, minus the
|
|
7484
|
+
// pick-mode gate (the agent's intent replaces the toggle); the entry
|
|
7485
|
+
// goes through beginNewLiveConfiguration like every other pick so
|
|
7486
|
+
// deferred recovery sees a fresh interaction revision.
|
|
7487
|
+
selectedElement = el;
|
|
7488
|
+
beginNewLiveConfiguration();
|
|
7489
|
+
showHighlight(selectedElement);
|
|
7490
|
+
clearAnnotations();
|
|
7491
|
+
showAnnotOverlay(selectedElement);
|
|
7492
|
+
showBar('configure');
|
|
7493
|
+
editBadgeSuppressed = true;
|
|
7494
|
+
renderEditBadge('hidden');
|
|
7495
|
+
startScrollTracking();
|
|
7496
|
+
maybePrefetchPage();
|
|
7497
|
+
maybeWarnConditionalAncestor(selectedElement);
|
|
7498
|
+
// Preset what the agent asked for, then fire the same Go a user press
|
|
7499
|
+
// fires. handleGo reads exactly these inputs.
|
|
7500
|
+
selectedAction = msg.action;
|
|
7501
|
+
selectedCount = msg.count;
|
|
7502
|
+
// updateBarContent rebuilds the configure row and replaces the input
|
|
7503
|
+
// element, so the prompt must be written into the input it creates,
|
|
7504
|
+
// never before (the action-chip click handler does the same dance).
|
|
7505
|
+
updateBarContent('configure');
|
|
7506
|
+
const input = uiGetById(PREFIX + '-input');
|
|
7507
|
+
if (input) input.value = msg.prompt || '';
|
|
7508
|
+
// The target rides on the generate event too: the helper resolves
|
|
7509
|
+
// the request from whichever lands first, so a page that dies
|
|
7510
|
+
// between Go and its result cannot leave the request pending for a
|
|
7511
|
+
// second Go elsewhere.
|
|
7512
|
+
const candidate = describeAgentTargetCandidate(el);
|
|
7513
|
+
agentTargetForGo = { targetId: msg.targetId, matchCount: resolved.matchCount, action: msg.action, count: msg.count, element: candidate };
|
|
7514
|
+
handleGo();
|
|
7515
|
+
agentTargetForGo = null;
|
|
7516
|
+
if (state === 'GENERATING' && currentSessionId) {
|
|
7517
|
+
reply({
|
|
7518
|
+
ok: true,
|
|
7519
|
+
matchCount: resolved.matchCount,
|
|
7520
|
+
sessionId: currentSessionId,
|
|
7521
|
+
action: msg.action,
|
|
7522
|
+
count: msg.count,
|
|
7523
|
+
element: candidate,
|
|
7524
|
+
});
|
|
7525
|
+
} else {
|
|
7526
|
+
reply({ ok: false, error: 'go_failed', state });
|
|
7527
|
+
}
|
|
7528
|
+
});
|
|
7529
|
+
});
|
|
7530
|
+
}
|
|
7531
|
+
|
|
7115
7532
|
// SSE (server→browser) + fetch POST (browser→server)
|
|
7116
7533
|
// Zero-dependency replacement for WebSocket.
|
|
7117
7534
|
//
|
|
@@ -7121,7 +7538,7 @@
|
|
|
7121
7538
|
const SSE_MAX_RETRIES = 20; // generous: heartbeats keep the connection alive, so retries mean real trouble
|
|
7122
7539
|
|
|
7123
7540
|
function connectSSE() {
|
|
7124
|
-
evtSource = new EventSource('http://localhost:' + PORT + '/events?token=' + TOKEN);
|
|
7541
|
+
evtSource = new EventSource('http://localhost:' + PORT + '/events?token=' + TOKEN + '&clientId=' + AGENT_TARGET_CLIENT_ID);
|
|
7125
7542
|
|
|
7126
7543
|
evtSource.onopen = () => {
|
|
7127
7544
|
sseRetries = 0; // reset on successful (re)connect
|
|
@@ -7132,8 +7549,11 @@
|
|
|
7132
7549
|
let msg; try { msg = JSON.parse(e.data); } catch { return; }
|
|
7133
7550
|
switch (msg.type) {
|
|
7134
7551
|
case 'connected':
|
|
7552
|
+
applyLiveBarPreference(msg.hideLiveBar === true);
|
|
7135
7553
|
hasProjectContext = !!msg.hasProjectContext;
|
|
7136
|
-
|
|
7554
|
+
// The generate lane runs without PRODUCT.md by design and never
|
|
7555
|
+
// sends the user to init, so its quiet chrome skips this notice.
|
|
7556
|
+
if (!hasProjectContext && !liveBarHiddenByHelper) showToast(`No PRODUCT.md found. Variants will be brand-agnostic. Run ${IMPECCABLE_COMMAND} init to generate one.`, 7000);
|
|
7137
7557
|
console.log('[impeccable] Live mode connected.');
|
|
7138
7558
|
syncAgentPollingUi(!!msg.agentPolling);
|
|
7139
7559
|
startAgentStatusPoll();
|
|
@@ -7143,9 +7563,15 @@
|
|
|
7143
7563
|
syncPageInteractionCursor();
|
|
7144
7564
|
syncPageChatFocus('sse-connected');
|
|
7145
7565
|
break;
|
|
7566
|
+
case 'live_bar':
|
|
7567
|
+
applyLiveBarPreference(msg.hidden === true);
|
|
7568
|
+
break;
|
|
7146
7569
|
case 'agent_polling':
|
|
7147
7570
|
syncAgentPollingUi(!!msg.connected);
|
|
7148
7571
|
break;
|
|
7572
|
+
case 'agent_target':
|
|
7573
|
+
handleAgentTarget(msg);
|
|
7574
|
+
break;
|
|
7149
7575
|
case 'agent_phase':
|
|
7150
7576
|
if (msg.id === currentSessionId && (state === 'GENERATING' || state === 'CYCLING')) {
|
|
7151
7577
|
// Advance the visible phase monotonically. A behind/resumed
|
|
@@ -7208,6 +7634,11 @@
|
|
|
7208
7634
|
disableInlineEdit();
|
|
7209
7635
|
refreshParamsPanel();
|
|
7210
7636
|
}
|
|
7637
|
+
// The done reply is the agent's last word on this generation:
|
|
7638
|
+
// with every variant mounted and no knobs declared, the Tune
|
|
7639
|
+
// chip must stop spinning. A reload between the mount and this
|
|
7640
|
+
// reply restored the pending state from the cache.
|
|
7641
|
+
completeParameterGenerationIfReady();
|
|
7211
7642
|
break;
|
|
7212
7643
|
}
|
|
7213
7644
|
// Source fallback when HMR did not land variants in this tab.
|
|
@@ -7371,6 +7802,15 @@
|
|
|
7371
7802
|
}).then(async res => {
|
|
7372
7803
|
if (res.ok) return res;
|
|
7373
7804
|
const body = await res.json().catch(() => ({}));
|
|
7805
|
+
// The helper refused to open a session for an agent target it has
|
|
7806
|
+
// already answered (another page served it after this page's lease
|
|
7807
|
+
// lapsed mid-capture, or the request timed out): drop the local
|
|
7808
|
+
// session and hand the surface back.
|
|
7809
|
+
if (body.error === 'agent_target_already_served' && msg.type === 'generate'
|
|
7810
|
+
&& msg.id && msg.id === currentSessionId) {
|
|
7811
|
+
abandonSupersededGo(msg.id);
|
|
7812
|
+
return null;
|
|
7813
|
+
}
|
|
7374
7814
|
// The server refused to journal progress for a session it has never
|
|
7375
7815
|
// seen: this browser is carrying state from another project or a
|
|
7376
7816
|
// wiped store (two apps sharing a localhost port). Continuing to
|
|
@@ -7392,6 +7832,14 @@
|
|
|
7392
7832
|
return sessionCreationGate.then(doSend);
|
|
7393
7833
|
}
|
|
7394
7834
|
|
|
7835
|
+
function abandonSupersededGo(sessionId) {
|
|
7836
|
+
if (sessionId !== currentSessionId) return;
|
|
7837
|
+
console.warn('[impeccable] The helper already answered this agent target; clearing session ' + sessionId + '.');
|
|
7838
|
+
markSessionHandled();
|
|
7839
|
+
cleanup({ instantChrome: true });
|
|
7840
|
+
showToast('The helper already answered this request, so this session was cleared. Pick an element to start fresh.', 6000);
|
|
7841
|
+
}
|
|
7842
|
+
|
|
7395
7843
|
let abandonedForeignSessionId = null;
|
|
7396
7844
|
function abandonForeignSession(sessionId) {
|
|
7397
7845
|
if (abandonedForeignSessionId === sessionId || sessionId !== currentSessionId) return;
|
|
@@ -7796,6 +8244,7 @@
|
|
|
7796
8244
|
visibleVariant = 0;
|
|
7797
8245
|
generationPhase = 'queued';
|
|
7798
8246
|
parameterGenerationState = 'pending';
|
|
8247
|
+
sessionOrigin = agentTargetForGo ? 'agent' : null;
|
|
7799
8248
|
parameterReadyAnnouncedSession = null;
|
|
7800
8249
|
resetSessionFileMeta();
|
|
7801
8250
|
|
|
@@ -7821,6 +8270,24 @@
|
|
|
7821
8270
|
};
|
|
7822
8271
|
if (snapshot.comments.length > 0) basePayload.comments = snapshot.comments;
|
|
7823
8272
|
if (snapshot.strokes.length > 0) basePayload.strokes = snapshot.strokes;
|
|
8273
|
+
if (agentTargetForGo) {
|
|
8274
|
+
// An agent-initiated Go names the target it serves (see
|
|
8275
|
+
// actOnAgentTarget): the helper resolves that request from this event
|
|
8276
|
+
// as well as from the overlay's own result post.
|
|
8277
|
+
basePayload.agentTarget = {
|
|
8278
|
+
targetId: agentTargetForGo.targetId,
|
|
8279
|
+
clientId: AGENT_TARGET_CLIENT_ID,
|
|
8280
|
+
result: {
|
|
8281
|
+
ok: true,
|
|
8282
|
+
matchCount: agentTargetForGo.matchCount,
|
|
8283
|
+
sessionId: currentSessionId,
|
|
8284
|
+
action: agentTargetForGo.action,
|
|
8285
|
+
count: agentTargetForGo.count,
|
|
8286
|
+
element: agentTargetForGo.element,
|
|
8287
|
+
},
|
|
8288
|
+
};
|
|
8289
|
+
agentTargetForGo = null;
|
|
8290
|
+
}
|
|
7824
8291
|
|
|
7825
8292
|
// Hide the interactive overlay so it doesn't linger during generation.
|
|
7826
8293
|
hideAnnotOverlay();
|
|
@@ -7881,6 +8348,7 @@
|
|
|
7881
8348
|
visibleVariant = 0;
|
|
7882
8349
|
generationPhase = 'queued';
|
|
7883
8350
|
parameterGenerationState = 'pending';
|
|
8351
|
+
sessionOrigin = agentTargetForGo ? 'agent' : null;
|
|
7884
8352
|
parameterReadyAnnouncedSession = null;
|
|
7885
8353
|
resetSessionFileMeta();
|
|
7886
8354
|
selectedElement = placeholderElement;
|
|
@@ -8927,6 +9395,8 @@ void main() {
|
|
|
8927
9395
|
pagePickSkipClick = false;
|
|
8928
9396
|
currentSessionId = null;
|
|
8929
9397
|
parameterGenerationState = 'idle';
|
|
9398
|
+
sessionOrigin = null;
|
|
9399
|
+
editBadgeSuppressed = false;
|
|
8930
9400
|
parameterReadyAnnouncedSession = null;
|
|
8931
9401
|
selectedAction = 'impeccable';
|
|
8932
9402
|
pendingAcceptedSession = null;
|
|
@@ -9018,6 +9488,7 @@ void main() {
|
|
|
9018
9488
|
paramsCurrentValues = { ...saved.paramValues };
|
|
9019
9489
|
}
|
|
9020
9490
|
if (saved.parameterState) parameterGenerationState = saved.parameterState;
|
|
9491
|
+
sessionOrigin = saved.origin === 'agent' ? 'agent' : null;
|
|
9021
9492
|
if (saved.generationPhase) generationPhase = saved.generationPhase;
|
|
9022
9493
|
}
|
|
9023
9494
|
|
|
@@ -9105,7 +9576,12 @@ void main() {
|
|
|
9105
9576
|
}
|
|
9106
9577
|
|
|
9107
9578
|
function restoreSessionWithoutWrapper(reason, activeSessions) {
|
|
9108
|
-
|
|
9579
|
+
// The session cache is per origin, so a tab on another page of the same
|
|
9580
|
+
// app sees this page's session too. Only the page that saved it may
|
|
9581
|
+
// resume it: the server-adoption branch below already applies the same
|
|
9582
|
+
// check, and a tab on another page has nothing to render for it.
|
|
9583
|
+
const cachedRaw = loadSession();
|
|
9584
|
+
const cached = cachedRaw?.id && !pageMatchesCurrent(cachedRaw.pageUrl) ? null : cachedRaw;
|
|
9109
9585
|
// localStorage is a cache, not a gate. A cleared tab, a second browser
|
|
9110
9586
|
// profile, or a teardown that dropped local state all leave the durable
|
|
9111
9587
|
// server session as the only record of work in progress; adopt it instead
|
|
@@ -9218,6 +9694,7 @@ void main() {
|
|
|
9218
9694
|
pageUrl: location.pathname,
|
|
9219
9695
|
paramValues: { ...paramsCurrentValues },
|
|
9220
9696
|
parameterState: parameterGenerationState,
|
|
9697
|
+
origin: sessionOrigin || undefined,
|
|
9221
9698
|
insertPlaceholder: insertPlaceholderSnapshot || undefined,
|
|
9222
9699
|
pickedAnchor: pickedAnchorSnapshot || undefined,
|
|
9223
9700
|
pickedAnchorViewportTop: Number.isFinite(pickedAnchorViewportTop) ? pickedAnchorViewportTop : undefined,
|
|
@@ -9343,6 +9820,8 @@ void main() {
|
|
|
9343
9820
|
pagePickSkipClick = false;
|
|
9344
9821
|
currentSessionId = null;
|
|
9345
9822
|
parameterGenerationState = 'idle';
|
|
9823
|
+
sessionOrigin = null;
|
|
9824
|
+
editBadgeSuppressed = false;
|
|
9346
9825
|
parameterReadyAnnouncedSession = null;
|
|
9347
9826
|
selectedAction = 'impeccable';
|
|
9348
9827
|
renderEditBadge('hidden');
|
|
@@ -9601,6 +10080,14 @@ void main() {
|
|
|
9601
10080
|
|
|
9602
10081
|
const resumedState = arrivedVariants > 0 ? 'CYCLING' : 'GENERATING';
|
|
9603
10082
|
|
|
10083
|
+
// A reload between the variants mounting and the agent's done reply
|
|
10084
|
+
// restores a pending Tune state from the cache; the helper knows whether
|
|
10085
|
+
// that generation already finished.
|
|
10086
|
+
if (arrivedVariants >= expectedVariants && expectedVariants > 0
|
|
10087
|
+
&& (parameterGenerationState === 'pending' || parameterGenerationState === 'loading')) {
|
|
10088
|
+
settleParameterStateFromHelper(sessionId);
|
|
10089
|
+
}
|
|
10090
|
+
|
|
9604
10091
|
// Find the visible variant's content element for highlight positioning.
|
|
9605
10092
|
const isInsert = wrapper.dataset.impeccableMode === 'insert';
|
|
9606
10093
|
const visEl = visibleVariant > 0 ? pickVariantContent(wrapper, visibleVariant) : null;
|
|
@@ -11064,6 +11551,21 @@ void main() {
|
|
|
11064
11551
|
}
|
|
11065
11552
|
}
|
|
11066
11553
|
|
|
11554
|
+
// After a resume the cache may say the Tune knobs are still coming while
|
|
11555
|
+
// the agent already replied done before the reload. The helper's session
|
|
11556
|
+
// record settles it; otherwise the done reply on SSE does.
|
|
11557
|
+
function settleParameterStateFromHelper(sessionId) {
|
|
11558
|
+
fetch('http://localhost:' + PORT + '/status?token=' + TOKEN, { cache: 'no-store' })
|
|
11559
|
+
.then((res) => (res.ok ? res.json() : null))
|
|
11560
|
+
.then((data) => {
|
|
11561
|
+
if (!data || sessionId !== currentSessionId) return;
|
|
11562
|
+
const session = (data.activeSessions || []).find((s) => s && s.id === sessionId);
|
|
11563
|
+
if (!session) return;
|
|
11564
|
+
if (session.generationCompletedAt || session.generationPhase === 'completed') completeParameterGenerationIfReady();
|
|
11565
|
+
})
|
|
11566
|
+
.catch(() => { /* the done reply on SSE settles it otherwise */ });
|
|
11567
|
+
}
|
|
11568
|
+
|
|
11067
11569
|
function fetchAgentPollingStatus() {
|
|
11068
11570
|
fetch('http://localhost:' + PORT + '/status?token=' + TOKEN, { cache: 'no-store' })
|
|
11069
11571
|
.then((res) => (res.ok ? res.json() : null))
|
|
@@ -11103,11 +11605,15 @@ void main() {
|
|
|
11103
11605
|
uiAppendStyle(s);
|
|
11104
11606
|
}
|
|
11105
11607
|
|
|
11608
|
+
// The generate lane's helper says so in the served script itself, so a
|
|
11609
|
+
// lane session never draws the bar at all; every other session mounts
|
|
11610
|
+
// it exactly as before.
|
|
11611
|
+
const barHiddenFromStart = window.__IMPECCABLE_LIVE_BAR_HIDDEN__ === true;
|
|
11106
11612
|
globalBarEl = el('div', {
|
|
11107
11613
|
position: 'fixed', bottom: '14px', left: '50%',
|
|
11108
11614
|
transform: 'translateX(-50%) translateY(20px)',
|
|
11109
11615
|
zIndex: Z.bar + 5,
|
|
11110
|
-
display: 'flex', alignItems: 'stretch',
|
|
11616
|
+
display: barHiddenFromStart ? 'none' : 'flex', alignItems: 'stretch',
|
|
11111
11617
|
gap: '0',
|
|
11112
11618
|
width: 'max-content',
|
|
11113
11619
|
background: P.surface,
|
|
@@ -11123,6 +11629,10 @@ void main() {
|
|
|
11123
11629
|
});
|
|
11124
11630
|
globalBarEl.id = PREFIX + '-global-bar';
|
|
11125
11631
|
globalBarEl.dataset.theme = theme;
|
|
11632
|
+
if (barHiddenFromStart) {
|
|
11633
|
+
liveBarHiddenByHelper = true;
|
|
11634
|
+
globalBarEl.dataset.liveBarDisplay = 'flex';
|
|
11635
|
+
}
|
|
11126
11636
|
|
|
11127
11637
|
// Brand mark - kinpaku Impeccable icon (site header / favicon paths).
|
|
11128
11638
|
const brand = el('span', {
|
|
@@ -11518,6 +12028,9 @@ void main() {
|
|
|
11518
12028
|
// Listen for detection results AND ready signal
|
|
11519
12029
|
window.addEventListener('message', onDetectMessage);
|
|
11520
12030
|
updateGlobalBarState();
|
|
12031
|
+
// The helper may already have said the bar stays hidden (a connect
|
|
12032
|
+
// that raced the bar build, or a reload mid-lane): re-apply it here.
|
|
12033
|
+
if (liveBarHiddenByHelper) setLiveBarHidden(true);
|
|
11521
12034
|
}
|
|
11522
12035
|
|
|
11523
12036
|
function updateGlobalBarState() {
|
|
@@ -11714,6 +12227,13 @@ void main() {
|
|
|
11714
12227
|
|
|
11715
12228
|
/** Full teardown: remove all UI, disconnect SSE, clean up. */
|
|
11716
12229
|
function teardown() {
|
|
12230
|
+
// Declined targets die with the overlay: the IDLE transition below must
|
|
12231
|
+
// not re-claim a lease this page can no longer act on. So does the
|
|
12232
|
+
// target ledger: an 'acting' entry from a Go that never happened must
|
|
12233
|
+
// not refuse every target the next connection hears.
|
|
12234
|
+
busyDeclinedTargets.clear();
|
|
12235
|
+
agentTargetsSeen.clear();
|
|
12236
|
+
liveBarHiddenByHelper = false;
|
|
11717
12237
|
stopAgentStatusPoll();
|
|
11718
12238
|
hideAgentPollTooltip();
|
|
11719
12239
|
if (agentPollTooltipEl) {
|