Claude Code should be able to work inside the user's open editor tab. This first stage connects the two and lets the agent look: what the user sees and a picture of it. Changing the project comes in stage 2. - An agent token per account opens only /mcp, no API route. The dialog "Agent tokens..." in the account menu creates it once, shows the ready "claude mcp add" line and revokes it. The server keeps only its sha256 (api/lib/AgentTokens.php). - Wrong tokens count into the sign-in brake from #427. Changing the password, renaming or deleting an account ends its tokens. - The relay (tools/mcp/) is a small Node service without packages, WebSocket server included. It runs in the container feuerwerk-mcp because PHP-FPM cannot hold connections. Whether a token or a tab ticket is valid is still decided by the PHP API, through two routes that answer only with the relay key. - The tab joins over WebSocket on the same origin with the normal session, an Origin check and a one-time ticket. It connects only after "Agent" is switched on in the account menu. One tab per account is active, a new one takes over. Guests get nothing. - Tools: get_view (project, tab, document, selection with names, camera, play state, open dialog) and screenshot. The resource feuerwerk://view can be subscribed. Claude Code does not act on that reliably, so a changed view is also noted on the next answer. - A badge next to the account menu shows the connected agents. It counts only agents with an open stream or a request in the last two minutes. - CI starts the relay in front of php -S (tools/ci/serve.sh), and e2e 71 runs the whole path in the browser. Found on the live test: the badge showed four agents because old sessions of revoked tokens were still counted. Tests: - Gate on atx: 316 files, 4888 tests - relay protocol test with fake API and fake tabs: 23/23 - get_view, tools, socketUrl: 16/16 - PHP agents 29, rights 103 checks - e2e 71 on atx 10/10, against the live site 10/10, no CSP violation - real Claude Code against the live site: get_view answered - ZAP against /mcp: nothing at High or Medium - every new check fails when the guard it covers is taken out (6) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
151 lines
4.4 KiB
JavaScript
151 lines
4.4 KiB
JavaScript
/**
|
|
* The e2e steps in the order they run. Each step is `async (t) => {}` over the harness
|
|
* toolbox; later steps rely on the scene state earlier ones leave behind (names given in
|
|
* the parenting step, the container created in the container step, …).
|
|
*/
|
|
import { hierarchy } from './01-hierarchy.mjs';
|
|
import { inspector } from './02-inspector.mjs';
|
|
import { play } from './03-play.mjs';
|
|
import { assets } from './04-assets.mjs';
|
|
import { drawing } from './05-drawing.mjs';
|
|
import { graph } from './06-graph.mjs';
|
|
import { parenting } from './07-parenting.mjs';
|
|
import { colliders } from './08-colliders.mjs';
|
|
import { containers } from './09-containers.mjs';
|
|
import { textAndEnabled } from './10-text-and-enabled.mjs';
|
|
import { menus } from './11-menus.mjs';
|
|
import { textures } from './12-textures.mjs';
|
|
import { frames } from './13-frames.mjs';
|
|
import { overflow } from './14-overflow.mjs';
|
|
import { aspect } from './15-aspect.mjs';
|
|
import { containerTab } from './16-container.mjs';
|
|
import { editorRun } from './17-editor-run.mjs';
|
|
import { pause } from './18-pause.mjs';
|
|
import { nestedBehavior } from './19-nested-behavior.mjs';
|
|
import { keyRepeat } from './20-key-repeat.mjs';
|
|
import { listTab } from './21-list.mjs';
|
|
import { structVariable } from './22-struct.mjs';
|
|
import { variableNodes } from './23-variable-nodes.mjs';
|
|
import { propertyNodes } from './24-property-nodes.mjs';
|
|
import { animation } from './25-animation.mjs';
|
|
import { stateMachine } from './26-state-machine.mjs';
|
|
import { consolePanel } from './27-console.mjs';
|
|
import { shader } from './28-shader.mjs';
|
|
import { transform } from './29-transform.mjs';
|
|
import { font } from './30-font.mjs';
|
|
import { particles } from './31-particles.mjs';
|
|
import { scope } from './32-scope.mjs';
|
|
import { renderOnChange } from './33-render-on-change.mjs';
|
|
import { sound } from './34-sound.mjs';
|
|
import { loadScene } from './35-load-scene.mjs';
|
|
import { graphGroups } from './36-graph-groups.mjs';
|
|
import { nineSlice } from './37-nine-slice.mjs';
|
|
import { plugins } from './38-plugins.mjs';
|
|
import { tile } from './39-tile.mjs';
|
|
import { tilemap } from './40-tilemap.mjs';
|
|
import { physics } from './41-physics.mjs';
|
|
import { shapes } from './42-shapes.mjs';
|
|
import { queries } from './43-queries.mjs';
|
|
import { documents } from './44-documents.mjs';
|
|
import { login } from './45-login.mjs';
|
|
import { topbar } from './46-topbar.mjs';
|
|
import { vectorArt } from './47-vectorart.mjs';
|
|
import { pixelArt } from './48-pixelart.mjs';
|
|
import { users } from './49-users.mjs';
|
|
import { snapshots } from './50-snapshots.mjs';
|
|
import { clipboard } from './51-clipboard.mjs';
|
|
import { hierarchyGroups } from './52-hierarchy-groups.mjs';
|
|
import { curves } from './53-curves.mjs';
|
|
import { structTypes } from './54-struct-types.mjs';
|
|
import { typedLists } from './55-typed-lists.mjs';
|
|
import { privateVariables } from './56-private-variables.mjs';
|
|
import { objectReferences } from './57-object-references.mjs';
|
|
import { clipAreas } from './58-clip-areas.mjs';
|
|
import { whilePlaying } from './59-while-playing.mjs';
|
|
import { release } from './60-release.mjs';
|
|
import { fullscreen } from './61-fullscreen.mjs';
|
|
import { devicePixels } from './62-device-pixels.mjs';
|
|
import { renderLayers } from './63-render-layers.mjs';
|
|
import { pattern } from './64-pattern.mjs';
|
|
import { song } from './65-song.mjs';
|
|
import { video } from './66-video.mjs';
|
|
import { recording } from './67-recording.mjs';
|
|
import { composition } from './68-composition.mjs';
|
|
import { compositionTab } from './69-composition-tab.mjs';
|
|
import { guest } from './70-guest.mjs';
|
|
import { mcp } from './71-mcp.mjs';
|
|
|
|
export const STEPS = [
|
|
hierarchy,
|
|
inspector,
|
|
play,
|
|
assets,
|
|
drawing,
|
|
graph,
|
|
parenting,
|
|
colliders,
|
|
containers,
|
|
textAndEnabled,
|
|
menus,
|
|
textures,
|
|
frames,
|
|
overflow,
|
|
aspect,
|
|
containerTab,
|
|
editorRun,
|
|
pause,
|
|
nestedBehavior,
|
|
keyRepeat,
|
|
listTab,
|
|
structVariable,
|
|
variableNodes,
|
|
propertyNodes,
|
|
animation,
|
|
stateMachine,
|
|
consolePanel,
|
|
shader,
|
|
transform,
|
|
font,
|
|
particles,
|
|
scope,
|
|
renderOnChange,
|
|
sound,
|
|
loadScene,
|
|
graphGroups,
|
|
nineSlice,
|
|
plugins,
|
|
tile,
|
|
tilemap,
|
|
physics,
|
|
shapes,
|
|
queries,
|
|
documents,
|
|
login,
|
|
topbar,
|
|
vectorArt,
|
|
pixelArt,
|
|
users,
|
|
snapshots,
|
|
clipboard,
|
|
hierarchyGroups,
|
|
curves,
|
|
structTypes,
|
|
typedLists,
|
|
privateVariables,
|
|
objectReferences,
|
|
clipAreas,
|
|
whilePlaying,
|
|
release,
|
|
fullscreen,
|
|
devicePixels,
|
|
renderLayers,
|
|
pattern,
|
|
song,
|
|
video,
|
|
recording,
|
|
composition,
|
|
compositionTab,
|
|
guest,
|
|
mcp,
|
|
];
|