cozyclay 2.1.1 → 3.0.0
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 +60 -0
- package/README.md +12 -30
- package/bin/agent/agent-routes.mjs +40 -113
- package/bin/agent/agent-runner.mjs +9 -10
- package/bin/agent/cliproxy-provider.mjs +135 -0
- package/bin/agent/credential-store.mjs +30 -7
- package/bin/agent/pi-tools.mjs +4 -1
- package/bin/agent/provider-keys.mjs +32 -0
- package/bin/agent/provider-login.mjs +110 -0
- package/bin/agent/provider-routes.mjs +99 -0
- package/bin/agent/providers.mjs +19 -97
- package/bin/agent/script-tool.mjs +17 -4
- package/bin/agent/studio-motion-reference.mjs +23 -0
- package/bin/agent/studio-prompt.mjs +1 -1
- package/bin/agent/studio-rebase-text.mjs +32 -0
- package/bin/agent/studio-rebase.mjs +26 -39
- package/bin/agent/studio-tools.mjs +9 -28
- package/bin/agent/tool-arguments.mjs +49 -0
- package/bin/agent/turn-frames.mjs +66 -0
- package/bin/codex-auth.mjs +9 -2
- package/bin/cozyclay.mjs +10 -116
- package/bin/live/cli.mjs +3 -3
- package/bin/mcp-runtime.mjs +2 -12
- package/bin/package-signature.mjs +0 -4
- package/dist/app/index.html +7 -6
- package/dist/assets/EXRLoader-CvVIvGVE.js +1 -0
- package/dist/assets/analytics-C9sUnndd.js +1 -0
- package/dist/assets/app-CCh--1Hc.js +5087 -0
- package/dist/assets/app-f-fkV5uP.css +1 -0
- package/dist/assets/compile-worker-CkxiD6lH.js +5 -0
- package/dist/assets/fflate.module-KbGj5-H6.js +5 -0
- package/dist/assets/{first-shot-handoff-msLI71g1.js → first-shot-handoff-CC4xe4HM.js} +1 -1
- package/dist/assets/{landing-ChUvB_zL.js → landing-DjHD8u7k.js} +1 -1
- package/dist/assets/scene-asset-sync-Hx_FzdOH.js +20 -0
- package/dist/assets/scene-asset-sync-_S8NQl5B.css +1 -0
- package/dist/assets/workflow-C4yKH1p4.js +179 -0
- package/dist/cozyclay-package.json +1 -1
- package/dist/index.html +3 -3
- package/dist/sw.js +3 -6
- package/dist/workflow/index.html +5 -4
- package/mcp/LIVE-PROTOCOL.md +7 -47
- package/mcp/README.md +16 -26
- package/mcp/live-hub.mjs +6 -10
- package/mcp/package.json +1 -3
- package/mcp/tool-handlers.mjs +4 -168
- package/package.json +3 -22
- package/src/App.jsx +150 -2624
- package/src/agent-progress.js +79 -0
- package/src/agent-turn-mark.js +30 -0
- package/src/analytics.js +1 -19
- package/src/app-context.js +5 -0
- package/src/app-stage.jsx +2 -34
- package/src/asset-pane.jsx +6 -5
- package/src/camera-block.js +21 -0
- package/src/camera-direction.js +120 -0
- package/src/character-kind.js +3 -9
- package/src/command-bus.js +8 -6
- package/src/commands/cast.js +5 -34
- package/src/commands/elements/character.js +1 -1
- package/src/commands/elements/motion.js +1 -6
- package/src/commands/elements/object.js +6 -2
- package/src/commands/elements/shot.js +4 -1
- package/src/commands/elements.js +38 -14
- package/src/commands/index.js +3 -1
- package/src/commands/kits.js +37 -0
- package/src/commands/motion-timing.js +57 -0
- package/src/commands/motion.js +9 -152
- package/src/commands/motion3-compile.js +65 -0
- package/src/commands/motion3.js +207 -0
- package/src/commands/objects.js +6 -4
- package/src/commands/shot.js +49 -11
- package/src/commands/stage.js +14 -1
- package/src/commands/view.js +4 -1
- package/src/document-mirrors.js +42 -0
- package/src/document-store.js +4 -0
- package/src/domains/cast.js +19 -194
- package/src/domains/motion/motion-range-pin-rules.js +1 -1
- package/src/domains/motion/take-source.js +51 -0
- package/src/domains/motion.js +60 -1838
- package/src/domains/scenes.js +12 -55
- package/src/domains/shots.js +2 -2
- package/src/domains/stage.js +4 -2
- package/src/draft-ghost.js +46 -0
- package/src/draft-ghost.jsx +129 -0
- package/src/dualview.jsx +4 -3
- package/src/effects/EffectsLayer.jsx +112 -0
- package/src/effects/effect-meshes.js +232 -0
- package/src/effects/effect-record.js +103 -0
- package/src/effects/emitter.js +59 -0
- package/src/effects/simulate.js +261 -0
- package/src/effects/state.js +59 -0
- package/src/execution-telemetry.js +2 -3
- package/src/first-success-guide.jsx +5 -5
- package/src/ghost-set.js +257 -0
- package/src/held-object-edit.jsx +113 -0
- package/src/held-object-pose.js +175 -0
- package/src/hierarchy-model.js +1 -1
- package/src/hierarchy-panel.jsx +1 -1
- package/src/imported-mesh.jsx +103 -0
- package/src/kits/held.js +84 -0
- package/src/kits/index.js +70 -0
- package/src/kits/smoking.js +57 -0
- package/src/light-blockers.js +93 -0
- package/src/motion/beat-board-model.js +84 -0
- package/src/motion/beat-board.css +124 -0
- package/src/motion/beat-board.jsx +59 -0
- package/src/motion/center-of-mass.js +66 -0
- package/src/motion/fix-collisions.js +850 -0
- package/src/motion/physics-review.js +118 -0
- package/src/{ardy → motion}/physics-support.js +1 -76
- package/src/motion/rig-snapshot.js +22 -0
- package/src/motion/take-segments.jsx +140 -0
- package/src/{ardy → motion}/timeline-coordinates.js +0 -21
- package/src/{ardy → motion}/timeline.css +1 -2
- package/src/{ardy → motion}/timeline.jsx +42 -413
- package/src/motion/waypoints.js +76 -0
- package/src/motion3/beats.js +83 -0
- package/src/motion3/body.js +158 -0
- package/src/motion3/bones.js +47 -0
- package/src/motion3/carried.js +47 -0
- package/src/motion3/compile-job.js +75 -0
- package/src/motion3/compile-worker.js +10 -0
- package/src/motion3/compiler/anchors.js +105 -0
- package/src/motion3/compiler/arm-orient.js +128 -0
- package/src/motion3/compiler/channels.js +125 -0
- package/src/motion3/compiler/compile.js +205 -0
- package/src/motion3/compiler/gait-rhythm.js +97 -0
- package/src/motion3/compiler/grip.js +171 -0
- package/src/motion3/compiler/head-steady.js +48 -0
- package/src/motion3/compiler/hold.js +134 -0
- package/src/motion3/compiler/idle.js +113 -0
- package/src/motion3/compiler/limbs.js +170 -0
- package/src/motion3/compiler/math.js +72 -0
- package/src/motion3/compiler/pose.js +162 -0
- package/src/motion3/compiler/quat.js +49 -0
- package/src/motion3/compiler/skeleton.js +74 -0
- package/src/motion3/compiler/validate-common.js +32 -0
- package/src/motion3/compiler/validate-goals.js +118 -0
- package/src/motion3/compiler/validate-objects.js +143 -0
- package/src/motion3/compiler/validate-parts.js +116 -0
- package/src/motion3/compiler/validate.js +122 -0
- package/src/motion3/compiler/vocab.js +73 -0
- package/src/motion3/compiler/walk-pelvis.js +275 -0
- package/src/motion3/compiler/walk.js +207 -0
- package/src/motion3/compiler/wrist-clamp.js +32 -0
- package/src/motion3/delta.js +47 -0
- package/src/motion3/describe.js +174 -0
- package/src/motion3/docs.js +27 -0
- package/src/motion3/edit-carry.js +21 -0
- package/src/motion3/fix/ease.js +16 -0
- package/src/motion3/fix/ground.js +37 -0
- package/src/motion3/fix/index.js +52 -0
- package/src/motion3/fix/push.js +71 -0
- package/src/motion3/fix/reach.js +46 -0
- package/src/motion3/fix/retime.js +79 -0
- package/src/motion3/fix/self.js +211 -0
- package/src/motion3/fix/slide.js +70 -0
- package/src/motion3/fix/turn.js +51 -0
- package/src/motion3/follow.js +39 -0
- package/src/motion3/free-motion.js +173 -0
- package/src/motion3/grip-choice.js +130 -0
- package/src/motion3/hold-plan.js +157 -0
- package/src/motion3/json-patch.js +77 -0
- package/src/motion3/key-aim.js +105 -0
- package/src/motion3/key-edit.js +82 -0
- package/src/motion3/lenient.js +127 -0
- package/src/motion3/object-keys.js +236 -0
- package/src/motion3/object-pose.js +182 -0
- package/src/motion3/object-tracks.js +12 -0
- package/src/motion3/pipeline.js +102 -0
- package/src/motion3/playback.js +51 -0
- package/src/motion3/probes.js +91 -0
- package/src/motion3/qa/body-checks.js +34 -0
- package/src/motion3/qa/check-names.js +14 -0
- package/src/motion3/qa/checks.js +121 -0
- package/src/motion3/qa/contact-checks.js +51 -0
- package/src/motion3/qa/explain.js +80 -0
- package/src/motion3/qa/fmt.js +5 -0
- package/src/motion3/qa/foot-checks.js +72 -0
- package/src/motion3/qa/geometry.js +77 -0
- package/src/motion3/qa/goals.js +191 -0
- package/src/motion3/qa/ground.js +60 -0
- package/src/motion3/qa/hints-contact.js +179 -0
- package/src/motion3/qa/hints-goal.js +160 -0
- package/src/motion3/qa/hints-knee.js +24 -0
- package/src/motion3/qa/hints-motion.js +209 -0
- package/src/motion3/qa/hints-object.js +91 -0
- package/src/motion3/qa/index.js +42 -0
- package/src/motion3/qa/key-checks.js +82 -0
- package/src/motion3/qa/near.js +96 -0
- package/src/motion3/qa/object-checks.js +135 -0
- package/src/motion3/qa/patch.js +161 -0
- package/src/motion3/qa/severity.js +38 -0
- package/src/motion3/qa/spec-checks.js +65 -0
- package/src/motion3/qa/style.js +218 -0
- package/src/motion3/qa/wrist-checks.js +69 -0
- package/src/motion3/qa/wrist-obs.js +60 -0
- package/src/motion3/refs.js +120 -0
- package/src/motion3/repair-tune.js +121 -0
- package/src/motion3/repair.js +83 -0
- package/src/motion3/report.js +67 -0
- package/src/motion3/rigs/index.js +14 -0
- package/src/motion3/rigs/x-bot-tpose-body.json +1 -0
- package/src/motion3/rigs/x-bot-tpose.json +1 -0
- package/src/motion3/rigs/y-bot-tpose-body.json +1 -0
- package/src/motion3/rigs/y-bot-tpose.json +1 -0
- package/src/motion3/scene.js +60 -0
- package/src/motion3/schema/brief.js +89 -0
- package/src/motion3/schema/fields.js +44 -0
- package/src/motion3/schema/spec-examples.js +46 -0
- package/src/motion3/schema/topics.js +111 -0
- package/src/motion3/schema/types.js +147 -0
- package/src/motion3/search.js +117 -0
- package/src/motion3/second-hand.js +112 -0
- package/src/motion3/skills/basic.js +82 -0
- package/src/motion3/skills/book.js +76 -0
- package/src/motion3/skills/car.js +145 -0
- package/src/motion3/skills/frames-auto.js +29 -0
- package/src/motion3/skills/index.js +83 -0
- package/src/motion3/skills/info.js +65 -0
- package/src/motion3/skills/smoke-kit.js +109 -0
- package/src/motion3/skills/smoke.js +160 -0
- package/src/motion3/spec-store.js +59 -0
- package/src/motion3/take-edit.js +155 -0
- package/src/motion3/take.js +63 -0
- package/src/motion3/timeline.js +127 -0
- package/src/motion3/views.js +121 -0
- package/src/motion3/walk-plan.js +119 -0
- package/src/object-catalog.jsx +7 -1
- package/src/object-colors.js +98 -0
- package/src/object-gizmo-parts.js +115 -0
- package/src/object-gizmo.jsx +37 -122
- package/src/object-glow.js +139 -0
- package/src/object-hidden.js +33 -0
- package/src/object-look.js +196 -0
- package/src/object-size.js +10 -0
- package/src/object-travel.js +71 -6
- package/src/panels/CameraPanel.jsx +7 -7
- package/src/panels/HdrEnvironmentControls.jsx +59 -0
- package/src/panels/LightPanel.jsx +25 -4
- package/src/panels/ObjectLookPanel.jsx +88 -0
- package/src/panels/PosePanel.jsx +2 -17
- package/src/panels/RigControlPanel.jsx +5 -53
- package/src/panels/SubjectBox.jsx +4 -1
- package/src/panels/details.css +14 -0
- package/src/posestudio.jsx +4 -27
- package/src/project-browser.jsx +3 -4
- package/src/project-resources.js +18 -31
- package/src/project.js +13 -104
- package/src/props.jsx +25 -280
- package/src/rail-dot-drag.js +23 -0
- package/src/render-passes.js +10 -0
- package/src/resource-status.jsx +1 -0
- package/src/result-modal.jsx +4 -19
- package/src/room.jsx +20 -12
- package/src/scene-assets.js +8 -6
- package/src/scene-light-place.js +72 -0
- package/src/scene-lights.jsx +148 -0
- package/src/scene-objects.js +31 -139
- package/src/scenes.js +15 -105
- package/src/semantic-edit.js +2 -5
- package/src/set-pieces.jsx +183 -0
- package/src/settings-menu.jsx +3 -11
- package/src/shell/BottomDock.jsx +9 -51
- package/src/shell/DetailsSlot.jsx +16 -200
- package/src/shell/GhostsMenuGroup.jsx +74 -0
- package/src/shell/LibrarySlot.jsx +1 -3
- package/src/shell/MenuBar.jsx +3 -3
- package/src/shell/PreferencesDialog.jsx +15 -264
- package/src/shell/PreferencesSlot.jsx +2 -8
- package/src/shell/TopBar.jsx +5 -84
- package/src/shell/ViewportToolbar.jsx +10 -70
- package/src/shell/agent-glass.css +19 -6
- package/src/shell/details-selection.js +42 -0
- package/src/shell/ghosts-menu.css +22 -0
- package/src/shell/glass-regions.css +29 -3
- package/src/shell/preferences.css +6 -1
- package/src/shot-authoring.js +4 -7
- package/src/soft-shadows.js +37 -0
- package/src/stage-attach-frames.js +12 -12
- package/src/stage-canvas-rigs.jsx +3 -3
- package/src/stage-capture.jsx +42 -8
- package/src/stage-characters.jsx +22 -216
- package/src/stage-editor-gizmos.jsx +6 -6
- package/src/stage-environment.js +93 -0
- package/src/stage-hdr-builtins.js +107 -0
- package/src/stage-hdr-image.js +116 -0
- package/src/stage-hdr-library.js +70 -0
- package/src/stage-hdr-map.js +94 -0
- package/src/stage-hdr.js +130 -0
- package/src/stage-lighting.js +149 -0
- package/src/stage-occlusion.js +210 -0
- package/src/stage-sky.jsx +159 -0
- package/src/stage-startup-defaults.js +5 -9
- package/src/studio-actions.js +12 -14
- package/src/studio-agent-commands.js +19 -16
- package/src/studio-agent-motion.js +9 -9
- package/src/studio-agent-protocol.js +41 -71
- package/src/studio-app-binding.js +25 -45
- package/src/studio-asset-list.js +17 -0
- package/src/studio-contact-sheet.js +37 -5
- package/src/studio-elements.js +27 -7
- package/src/studio-entity-bounds.js +18 -0
- package/src/studio-error-codes.js +8 -0
- package/src/studio-export-framing.js +152 -0
- package/src/studio-lighting-check.js +103 -0
- package/src/studio-motion-visual.js +150 -0
- package/src/studio-schema-errors.js +80 -0
- package/src/studio-support-gap.js +74 -0
- package/src/styles.css +1 -19
- package/src/timeline-defaults.js +5 -0
- package/src/timeline-extent.js +8 -20
- package/src/tutorial-walk.js +17 -0
- package/src/ui-scrub.js +1 -1
- package/src/use-shot-camera-tracks.js +12 -0
- package/src/view-ghosts.js +97 -0
- package/src/view-ghosts.jsx +49 -0
- package/src/workflow/AgentPanel.jsx +47 -166
- package/src/workflow/AgentProgressCard.jsx +107 -0
- package/src/workflow/AgentReplyText.jsx +37 -0
- package/src/workflow/AgentTurnSteps.jsx +84 -0
- package/src/workflow/LoginPanel.jsx +140 -0
- package/src/workflow/WorkflowBuilder.jsx +7 -23
- package/src/workflow/agent-client.js +54 -51
- package/src/workflow/agent-panel.css +71 -1
- package/src/workflow/agent-progress-card.css +167 -0
- package/src/workflow/agent-progress-view.js +47 -0
- package/src/workflow/agent-turn-steps.css +113 -0
- package/src/workflow/agent-turn.js +191 -0
- package/src/workflow/login-client.js +34 -0
- package/src/workflow/motion-input.js +18 -31
- package/src/workflow/node-schema.js +1 -1
- package/src/workflow/reply-markdown.js +69 -0
- package/src/workflow/scene-asset-sync.js +8 -8
- package/tools/agent-session-stats.mjs +61 -0
- package/tools/dev-full.mjs +5 -56
- package/tools/eslint-baseline.json +12 -13
- package/tools/knip-baseline.json +0 -179
- package/tools/loc-baseline.json +31 -81
- package/tools/motion3/extract-body.mjs +103 -0
- package/tools/motion3/extract-rig.mjs +85 -0
- package/tools/process-supervisor.mjs +0 -88
- package/tools/run-tests.mjs +8 -124
- package/bin/agent/motion-runtime.mjs +0 -76
- package/dist/ardy/cskel27-rest.json +0 -557
- package/dist/assets/analytics-C9pMpW7s.js +0 -1
- package/dist/assets/app-B_2XB9rw.css +0 -1
- package/dist/assets/app-DAuvKPP8.js +0 -4920
- package/dist/assets/config-Bx7pYsD9.js +0 -1
- package/dist/assets/config-DeoFTYzb.css +0 -1
- package/dist/assets/demo-CvKuBgy5.js +0 -1
- package/dist/assets/scene-asset-sync-DKkpjKBV.js +0 -19
- package/dist/assets/scene-asset-sync-DjJ_cJ2R.css +0 -1
- package/dist/assets/ticket-BPk2Ni95.js +0 -1
- package/dist/assets/workflow-jJRBR94Z.js +0 -179
- package/dist/demo/walk-then-stop.npz +0 -0
- package/mcp/ardy-prompts.mjs +0 -218
- package/src/ardy/auto-fix-panel.css +0 -108
- package/src/ardy/auto-physics.js +0 -1194
- package/src/ardy/client.js +0 -153
- package/src/ardy/convert.js +0 -313
- package/src/ardy/cskel27-neutral.js +0 -39
- package/src/ardy/cskel27.js +0 -77
- package/src/ardy/export.js +0 -165
- package/src/ardy/fix-collisions.js +0 -2257
- package/src/ardy/foot-lock.js +0 -230
- package/src/ardy/motion-calibration.js +0 -118
- package/src/ardy/motion-edit.js +0 -213
- package/src/ardy/motion-url.js +0 -55
- package/src/ardy/mp4-duration.js +0 -102
- package/src/ardy/npz.js +0 -595
- package/src/ardy/physics-panel.css +0 -21
- package/src/ardy/physics-panel.jsx +0 -89
- package/src/ardy/physics-refine.js +0 -111
- package/src/ardy/physics-review.js +0 -567
- package/src/ardy/physics-temporal.js +0 -54
- package/src/ardy/platform-fit-panel.css +0 -64
- package/src/ardy/platform-fit-panel.jsx +0 -41
- package/src/ardy/platform-fit.js +0 -326
- package/src/ardy/playback.js +0 -711
- package/src/ardy/pose-pin.js +0 -97
- package/src/ardy/prompt-clips.js +0 -30
- package/src/ardy/retime.js +0 -211
- package/src/ardy/root-drop.js +0 -369
- package/src/ardy/timeline-resize.js +0 -13
- package/src/ardy/to-cskel27.js +0 -225
- package/src/ardy/trim.js +0 -33
- package/src/ardy/waypoints.js +0 -369
- package/src/ardy-bridge-contract.js +0 -281
- package/src/domains/motion/motion-video-capture.js +0 -664
- package/src/i2v-motion-client.js +0 -77
- package/src/i2v-motion-studio.jsx +0 -180
- package/src/line-edit.js +0 -1348
- package/src/motion/generation.js +0 -105
- package/src/motion-readiness-ui.jsx +0 -67
- package/src/motion-readiness.js +0 -40
- package/src/motion-resources.js +0 -177
- package/src/motion-store.js +0 -65
- package/src/motion-trail.js +0 -601
- package/src/multimodel-ingest.js +0 -394
- package/src/panels/PromptBlocksPanel.jsx +0 -444
- package/src/panels/VideoCapturePanel.jsx +0 -181
- package/src/pose-extract/browser.js +0 -42
- package/src/pose-extract/detector.js +0 -100
- package/src/pose-extract/fit.js +0 -227
- package/src/pose-extract/image-frame.js +0 -51
- package/src/pose-extract/index.js +0 -58
- package/src/pose-extract/keyframes.js +0 -74
- package/src/pose-extract/landmarks.js +0 -162
- package/src/pose-extract/mirror.js +0 -153
- package/src/pose-extract/take.js +0 -131
- package/src/pose-extract/video-frames.js +0 -91
- package/src/take-recipe.js +0 -165
- package/src/trail-key-conflicts.js +0 -39
- package/src/trail-pick.js +0 -59
- package/src/use-i2v-capture-modal.js +0 -15
- package/tools/ardy/BRIDGE.md +0 -37
- package/tools/ardy/GVHMR-NPZ.md +0 -68
- package/tools/ardy/README.md +0 -124
- package/tools/ardy/__pycache__/cclay_gvhmr_worker.cpython-313.pyc +0 -0
- package/tools/ardy/artifacts.mjs +0 -34
- package/tools/ardy/bridge.mjs +0 -1732
- package/tools/ardy/bvh-cskel27.mjs +0 -1265
- package/tools/ardy/cclay_constrained_generate.py +0 -561
- package/tools/ardy/cclay_gvhmr_worker.py +0 -264
- package/tools/ardy/cclay_motion_edit.py +0 -510
- package/tools/ardy/cclay_sequence_generate.py +0 -705
- package/tools/ardy/cclay_worker.py +0 -304
- package/tools/ardy/dump-npz.py +0 -205
- package/tools/ardy/extract-rest.mjs +0 -299
- package/tools/ardy/extract.mjs +0 -507
- package/tools/ardy/footage.mjs +0 -467
- package/tools/ardy/gvhmr-floor.mjs +0 -102
- package/tools/ardy/gvhmr-to-cskel27.mjs +0 -21
- package/tools/ardy/gvhmr_fastpath.py +0 -168
- package/tools/ardy/gvhmr_trajectory.py +0 -240
- package/tools/ardy/merge-text-encoder.py +0 -160
- package/tools/ardy/mocap-metrics.mjs +0 -200
- package/tools/ardy/mocap-quality-gate.mjs +0 -110
- package/tools/ardy/motion-stabilize.mjs +0 -348
- package/tools/ardy/npz.mjs +0 -414
- package/tools/ardy/pose-to-npz.mjs +0 -106
- package/tools/ardy/prompt-limits.mjs +0 -5
- package/tools/ardy/run-edit-on-box.sh +0 -73
- package/tools/ardy/run-local.mjs +0 -233
- package/tools/ardy/run-on-box.sh +0 -593
- package/tools/ardy/run-sequence-on-box.sh +0 -177
- package/tools/ardy/runners/gvhmr-worker.mjs +0 -206
- package/tools/ardy/runners/index.mjs +0 -18
- package/tools/ardy/runners/local.mjs +0 -455
- package/tools/ardy/runners/proc.mjs +0 -125
- package/tools/ardy/runners/remote.mjs +0 -252
- package/tools/ardy/setup-local.mjs +0 -189
- package/tools/ardy/setup-text-encoder-on-box.sh +0 -93
- package/tools/ardy/setup-text-encoder.py +0 -306
- package/tools/ardy/smpl-cskel27.mjs +0 -178
- package/tools/ardy/visual-qa.mjs +0 -196
- package/tools/ardy/vq-car.mjs +0 -52
- package/tools/bench/EXP3.md +0 -61
- package/tools/bench/cclay_bench_extract_incam.py +0 -125
- package/tools/bench/cclay_bench_extract_obs.py +0 -204
- package/tools/bench/cclay_bench_runner.py +0 -42
- package/tools/bench/cube-contact.mjs +0 -162
- package/tools/bench/exp3.mjs +0 -152
- package/tools/bench/extract-bench-lib.mjs +0 -216
- package/tools/bench/extract-bench.mjs +0 -302
- package/tools/bench/fal-generate.mjs +0 -88
- package/tools/bench/fit/README.md +0 -189
- package/tools/bench/fit/camera.mjs +0 -59
- package/tools/bench/fit/contact.mjs +0 -419
- package/tools/bench/fit/footlock.mjs +0 -234
- package/tools/bench/fit/motion.mjs +0 -85
- package/tools/bench/fit/pin.mjs +0 -27
- package/tools/bench/fit/remote.mjs +0 -105
- package/tools/bench/fit-bench.mjs +0 -126
- package/tools/bench/fit-sanity.mjs +0 -45
- package/tools/bench/metrics.mjs +0 -313
- package/tools/bench/obs/depth.mjs +0 -258
- package/tools/bench/obs/extrinsics.mjs +0 -175
- package/tools/bench/obs/fit_mannequin_betas.py +0 -340
- package/tools/bench/obs/ground.mjs +0 -294
- package/tools/bench/obs/heading.mjs +0 -151
- package/tools/bench/obs/ladder.mjs +0 -555
- package/tools/bench/obs/mannequin-betas.json +0 -124
- package/tools/bench/obs/remote.mjs +0 -83
- package/tools/bench/obs/rest_joints.py +0 -52
- package/tools/bench/obs/ybot-targets.mjs +0 -49
- package/tools/bench/obs-bench.mjs +0 -520
- package/tools/bench/score.mjs +0 -343
- package/tools/bench/summarize.mjs +0 -86
- package/tools/demo-worker/README.md +0 -137
- package/tools/demo-worker/api-client.mjs +0 -233
- package/tools/demo-worker/generate.mjs +0 -301
- package/tools/demo-worker/index.mjs +0 -466
- package/tools/demo-worker/sign-core.mjs +0 -112
- package/tools/demo-worker/sign.mjs +0 -161
- package/tools/gt-render/browser.mjs +0 -182
- package/tools/gt-render/camera-math.mjs +0 -276
- package/tools/gt-render/page.mjs +0 -267
- package/tools/gt-render/render.mjs +0 -514
- package/tools/gt-render/scene-box.mjs +0 -31
- package/tools/gt-render/take-transform.mjs +0 -87
- package/tools/kimodo/compare-seam.mjs +0 -108
- package/tools/kimodo/constraints.mjs +0 -244
- package/tools/kimodo/edit.mjs +0 -259
- package/tools/kimodo/effector-constraints.mjs +0 -200
- package/tools/kimodo/generate.mjs +0 -646
- package/tools/kimodo/local-output.mjs +0 -265
- package/tools/kimodo/measure-pose.mjs +0 -65
- package/tools/kimodo/measure-preserve.mjs +0 -899
- package/tools/kimodo/measure-waypoints.mjs +0 -55
- package/tools/kimodo/mlx-generate.py +0 -111
- package/tools/kimodo/pose-constraints.mjs +0 -248
- package/tools/kimodo/preserve-mask.mjs +0 -543
- package/tools/kimodo/read-npz.mjs +0 -189
- package/tools/kimodo/run-edit-on-box.mjs +0 -155
- package/tools/kimodo/run-sequence-on-box.mjs +0 -178
- package/tools/kimodo/runner.mjs +0 -284
- package/tools/kimodo/seam-batch.mjs +0 -77
- package/tools/kimodo/setup-local.mjs +0 -30
- package/tools/kimodo/setup-on-box.sh +0 -339
- package/tools/kimodo/soma77-to-cskel27.mjs +0 -305
- package/tools/morphgs/assets/gen_truth.py +0 -39
- package/tools/morphgs/assets/mesh_ori_rig.txt +0 -27
- package/tools/morphgs/assets/playback-check.mjs +0 -30
- package/tools/morphgs/demo-gate.sh +0 -26
- package/tools/morphgs/fbx2morphgs.mjs +0 -68
- package/tools/morphgs/morphgs-to-cskel27.mjs +0 -105
- package/tools/morphgs/patches/preprocess_src-none-mode.patch +0 -76
- package/tools/morphgs/setup-on-cluster.sh +0 -126
- package/tools/projflow/driver.py +0 -1069
- package/tools/projflow/generate.mjs +0 -805
- package/tools/projflow/hml22-to-cskel27.mjs +0 -735
- package/tools/projflow/line-edit-job.mjs +0 -547
- package/tools/projflow/replay.mjs +0 -452
- package/tools/projflow/runner.mjs +0 -269
- package/tools/projflow/service.mjs +0 -742
- package/tools/track/DESIGN.md +0 -513
- package/tools/track/backfill-provenance.mjs +0 -116
- package/tools/track/budget.mjs +0 -8
- package/tools/track/check-rig.mjs +0 -209
- package/tools/track/diagnostics.schema.json +0 -60
- package/tools/track/export-rig.mjs +0 -256
- package/tools/track/fallback.mjs +0 -7
- package/tools/track/fk-parity-fixture.mjs +0 -161
- package/tools/track/gate.mjs +0 -349
- package/tools/track/masks.mjs +0 -318
- package/tools/track/metrics.mjs +0 -201
- package/tools/track/publish-obs.mjs +0 -108
- package/tools/track/py/check_env.py +0 -61
- package/tools/track/py/eval_lr.py +0 -229
- package/tools/track/py/lr_viterbi.py +0 -294
- package/tools/track/py/masks.py +0 -405
- package/tools/track/py/objective.py +0 -382
- package/tools/track/py/rig.py +0 -508
- package/tools/track/py/scene.py +0 -326
- package/tools/track/py/test_joint_indices.py +0 -123
- package/tools/track/py/test_lr_viterbi.py +0 -195
- package/tools/track/py/test_masks.py +0 -229
- package/tools/track/py/test_rig.py +0 -288
- package/tools/track/py/test_scene.py +0 -354
- package/tools/track/py/test_track.py +0 -328
- package/tools/track/py/track.py +0 -411
- package/tools/track/remote.mjs +0 -140
- package/tools/track/rig-dump.mjs +0 -227
- package/tools/track/run-box-tests.mjs +0 -14
- package/tools/track/run-box.mjs +0 -168
- package/tools/track/setup-box.sh +0 -59
- package/tools/track/study-2d.mjs +0 -728
- /package/src/{ardy → motion}/collision-blockers.js +0 -0
- /package/src/{ardy → motion}/ground.js +0 -0
- /package/src/{ardy → motion}/ik-drag.js +0 -0
- /package/src/{ardy → motion}/ik-key-json.js +0 -0
- /package/src/{ardy → motion}/ik.js +0 -0
- /package/src/{ardy → motion}/physics-surface.js +0 -0
- /package/src/{ardy → motion}/playback-clock.js +0 -0
- /package/src/{ardy → motion}/range-pin.js +0 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// The live progress card in the agent panel (agent-progress.js). While the agent works on motion it shows what
|
|
2
|
+
// the agent actually produced so far: how many drafts it compiled and their QA trend, the latest draft's goals
|
|
3
|
+
// (met or not, value against need) and heaviest issues, whether that draft is installed, and the images the
|
|
4
|
+
// agent asked to see (click to enlarge, over the whole window). Nothing here is invented progress. A new turn
|
|
5
|
+
// starts it over.
|
|
6
|
+
import { useEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
7
|
+
import { createPortal } from "react-dom";
|
|
8
|
+
import { FiCheck, FiX } from "react-icons/fi";
|
|
9
|
+
import { clearProgress, draftsOf, latestDraft, progressSheets, progressVersion, subscribeProgress } from "../agent-progress.js";
|
|
10
|
+
import { ko } from "../locale.js";
|
|
11
|
+
import { goalRows, issueRows, trendPoints, turnCount } from "./agent-progress-view.js";
|
|
12
|
+
import "./agent-progress-card.css";
|
|
13
|
+
|
|
14
|
+
const W = 220, H = 40;
|
|
15
|
+
|
|
16
|
+
function Trend({ totals }) {
|
|
17
|
+
const { points, first, last } = trendPoints(totals, { width: W, height: H });
|
|
18
|
+
if (!points.length) return null;
|
|
19
|
+
const [lx, ly] = points[points.length - 1];
|
|
20
|
+
const label = ko(`QA issues by draft: ${totals.join(", ")}`, `초안별 QA 문제 수: ${totals.join(", ")}`);
|
|
21
|
+
return <div className="agent-progress-trend">
|
|
22
|
+
<svg viewBox={`0 0 ${W} ${H}`} role="img" aria-label={label} preserveAspectRatio="none">
|
|
23
|
+
<line className="base" x1={4} y1={H - 4} x2={W - 4} y2={H - 4} />
|
|
24
|
+
{points.length > 1 && <polyline className="line" points={points.map(p => p.join(",")).join(" ")} />}
|
|
25
|
+
{points.slice(0, -1).map(([x, y], i) => <circle key={i} className="dot" cx={x} cy={y} r={1.8} />)}
|
|
26
|
+
<circle className={`end ${last === 0 ? "ok" : "issue"}`} cx={lx} cy={ly} r={3.4} />
|
|
27
|
+
</svg>
|
|
28
|
+
<span className="agent-progress-trend-text">{totals.length > 1 ? `${first} → ${last}` : `${last}`}</span>
|
|
29
|
+
</div>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// The panel's own lightbox stays inside the panel; a contact sheet needs the window.
|
|
33
|
+
function SheetViewer({ sheet, onClose }) {
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const onKey = event => { if (event.key === "Escape") onClose(); };
|
|
36
|
+
window.addEventListener("keydown", onKey);
|
|
37
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
38
|
+
}, [onClose]);
|
|
39
|
+
return createPortal(<button type="button" className="agent-progress-viewer" aria-label={ko("Close image", "이미지 닫기")} onClick={onClose}>
|
|
40
|
+
<img src={sheet.dataUrl} alt={sheet.caption || ko("Image the agent checked", "에이전트가 확인한 이미지")} />
|
|
41
|
+
{sheet.caption && <span className="agent-progress-viewer-caption">{sheet.caption}</span>}
|
|
42
|
+
</button>, document.body);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** `since`: when the latest turn started (null: no turn yet). Drafts and images from before it are not this turn's
|
|
46
|
+
* work, such as the take the camera tutorial compiles at startup. `live`: that turn is still running. */
|
|
47
|
+
export function AgentProgressCard({ items, since = null, live = false }) {
|
|
48
|
+
useSyncExternalStore(subscribeProgress, progressVersion);
|
|
49
|
+
const [open, setOpen] = useState(null);
|
|
50
|
+
// The goal and issue lists fold to one line each: the panel is short and the live steps sit below the card.
|
|
51
|
+
const [shown, setShown] = useState({});
|
|
52
|
+
const toggle = key => setShown(now => ({ ...now, [key]: !now[key] }));
|
|
53
|
+
// a new turn (not a steer of the running one) starts the card over
|
|
54
|
+
const turns = turnCount(items), seen = useRef(turns);
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (turns > seen.current) clearProgress();
|
|
57
|
+
seen.current = turns;
|
|
58
|
+
}, [turns]);
|
|
59
|
+
const ours = record => since !== null && record.at >= since;
|
|
60
|
+
const newest = latestDraft(), latest = newest && ours(newest) ? newest : null, sheets = progressSheets().filter(ours);
|
|
61
|
+
const viewing = open && sheets.find(sheet => sheet.seq === open);
|
|
62
|
+
if (!latest && !sheets.length) return null;
|
|
63
|
+
const drafts = latest ? draftsOf(latest.characterId).filter(ours) : [];
|
|
64
|
+
const goals = goalRows(latest?.qa.goals), issues = latest && !latest.qa.ok ? issueRows(latest.qa.groups) : [];
|
|
65
|
+
return <div className="agent-row">
|
|
66
|
+
<div className="agent-card agent-progress-card" data-agent-card="progress" data-drafts={drafts.length} data-installed={latest?.installed ? "true" : "false"} role="status" aria-live="polite">
|
|
67
|
+
{latest && <div className="agent-progress-head">
|
|
68
|
+
<span className="agent-progress-title">{ko("Draft", "초안")} {latest.n} · QA {latest.qa.total}</span>
|
|
69
|
+
<span className={`agent-progress-chip ${latest.installed ? "installed" : "draft"}`}>{latest.installed ? ko("Installed", "설치됨") : live ? ko("Not installed yet", "아직 설치 전") : ko("Not installed", "설치 안 됨")}</span>
|
|
70
|
+
</div>}
|
|
71
|
+
{latest?.label && <p className="agent-progress-label">{latest.label}</p>}
|
|
72
|
+
{drafts.length > 0 && <section className="agent-progress-section">
|
|
73
|
+
<h4>{ko(`QA issues across ${drafts.length} draft${drafts.length === 1 ? "" : "s"}`, `초안 ${drafts.length}개의 QA 문제 수`)}</h4>
|
|
74
|
+
<Trend totals={drafts.map(d => d.qa.total)} />
|
|
75
|
+
</section>}
|
|
76
|
+
{goals.length > 0 && <section className="agent-progress-section">
|
|
77
|
+
<button type="button" className="agent-progress-fold" aria-expanded={!!shown.goals} onClick={() => toggle("goals")}>
|
|
78
|
+
<h4>{ko("Goals", "목표")}</h4><span>{ko(`${goals.filter(g => g.ok).length} of ${goals.length} met`, `${goals.length}개 중 ${goals.filter(g => g.ok).length}개 충족`)}</span>
|
|
79
|
+
</button>
|
|
80
|
+
{shown.goals && <ul className="agent-progress-goals">
|
|
81
|
+
{goals.map((g, i) => <li key={i} data-goal-ok={g.ok ? "true" : "false"}>
|
|
82
|
+
<span className={`agent-progress-mark ${g.ok ? "ok" : "miss"}`} aria-label={g.ok ? ko("met", "충족") : ko("missed", "미충족")}>{g.ok ? <FiCheck size={11} /> : <FiX size={11} />}</span>
|
|
83
|
+
<span className="agent-progress-goal-name">{g.name}</span>
|
|
84
|
+
<span className="agent-progress-goal-value">{g.value}{g.need && <span className="need"> / {g.need}</span>}</span>
|
|
85
|
+
</li>)}
|
|
86
|
+
</ul>}
|
|
87
|
+
</section>}
|
|
88
|
+
{issues.length > 0 && <section className="agent-progress-section">
|
|
89
|
+
<button type="button" className="agent-progress-fold" aria-expanded={!!shown.issues} onClick={() => toggle("issues")}>
|
|
90
|
+
<h4>{ko("Largest issues", "가장 큰 문제")}</h4><span>{issues[0].kind} {issues[0].subject}</span>
|
|
91
|
+
</button>
|
|
92
|
+
{shown.issues && <ul className="agent-progress-issues">
|
|
93
|
+
{issues.map((row, i) => <li key={i}><span className="kind">{row.kind}</span> {row.subject} <span className="meta">×{row.count}{row.frames && ` · ${row.frames}`}</span></li>)}
|
|
94
|
+
</ul>}
|
|
95
|
+
</section>}
|
|
96
|
+
{sheets.length > 0 && <section className="agent-progress-section">
|
|
97
|
+
<h4>{ko("What the agent looked at", "에이전트가 본 화면")}</h4>
|
|
98
|
+
<div className="agent-progress-sheets">
|
|
99
|
+
{sheets.map(sheet => <button type="button" key={sheet.seq} className="agent-progress-sheet" title={sheet.caption} onClick={() => setOpen(sheet.seq)}>
|
|
100
|
+
<img src={sheet.dataUrl} alt={sheet.caption || ko("Image the agent checked", "에이전트가 확인한 이미지")} />
|
|
101
|
+
</button>)}
|
|
102
|
+
</div>
|
|
103
|
+
</section>}
|
|
104
|
+
</div>
|
|
105
|
+
{viewing && <SheetViewer sheet={viewing} onClose={() => setOpen(null)} />}
|
|
106
|
+
</div>;
|
|
107
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// The agent's reply as formatted text (reply-markdown.js): paragraphs, headings, lists, bold, code and tables,
|
|
2
|
+
// never the raw marks. `tail` (the streaming caret) sits at the end of the last line.
|
|
3
|
+
import { Fragment, useMemo } from "react";
|
|
4
|
+
import { replyBlocks } from "./reply-markdown.js";
|
|
5
|
+
|
|
6
|
+
function Spans({ spans }) {
|
|
7
|
+
return spans.map((span, index) => {
|
|
8
|
+
if (span.code) return <code key={index}>{span.text}</code>;
|
|
9
|
+
if (span.bold) return <strong key={index}>{span.text}</strong>;
|
|
10
|
+
return <Fragment key={index}>{span.text}</Fragment>;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function Block({ block, tail }) {
|
|
15
|
+
if (block.type === "h") return <p className="agent-reply-heading"><Spans spans={block.spans} />{tail}</p>;
|
|
16
|
+
if (block.type === "code") return <pre><code>{block.text}</code>{tail}</pre>;
|
|
17
|
+
if (block.type === "ul" || block.type === "ol") {
|
|
18
|
+
const List = block.type;
|
|
19
|
+
return <List start={block.start}>
|
|
20
|
+
{block.items.map((spans, index) => <li key={index}><Spans spans={spans} />{index === block.items.length - 1 && tail}</li>)}
|
|
21
|
+
</List>;
|
|
22
|
+
}
|
|
23
|
+
if (block.type === "table") return <>
|
|
24
|
+
<div className="agent-reply-table"><table>
|
|
25
|
+
<thead><tr>{block.head.map((spans, index) => <th key={index}><Spans spans={spans} /></th>)}</tr></thead>
|
|
26
|
+
<tbody>{block.rows.map((row, rowIndex) => <tr key={rowIndex}>{row.map((spans, index) => <td key={index}><Spans spans={spans} /></td>)}</tr>)}</tbody>
|
|
27
|
+
</table></div>
|
|
28
|
+
{tail}
|
|
29
|
+
</>;
|
|
30
|
+
return <p><Spans spans={block.spans} />{tail}</p>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function ReplyText({ text, tail = null }) {
|
|
34
|
+
const blocks = useMemo(() => replyBlocks(text), [text]);
|
|
35
|
+
if (!blocks.length) return tail || null;
|
|
36
|
+
return blocks.map((block, index) => <Block key={index} block={block} tail={index === blocks.length - 1 ? tail : null} />);
|
|
37
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
// One turn's work in the agent panel (agent-turn.js turnLayout): a header that says how the turn stands (working,
|
|
2
|
+
// done, stopped, failed), how many steps and how long, and one compact row per step: the tool call with a plain
|
|
3
|
+
// label, what it was about and its one-line result; the reasoning the model streamed between calls; the call it is
|
|
4
|
+
// writing now. Open while the turn runs, folded to its header when the turn ends (a failed or stopped turn stays
|
|
5
|
+
// open, and a stopped one says what it left in the scene).
|
|
6
|
+
import { useState } from "react";
|
|
7
|
+
import { FiCheck, FiChevronRight, FiSquare, FiX } from "react-icons/fi";
|
|
8
|
+
import { ko } from "../locale.js";
|
|
9
|
+
import { scriptNow, stepLabel, stepResult, stepsHeader, stoppedNote, thinkingLine } from "./agent-turn.js";
|
|
10
|
+
import "./agent-turn-steps.css";
|
|
11
|
+
|
|
12
|
+
/** Step time: "0.6 s", "12 s", "1 m 05 s". */
|
|
13
|
+
function stepClock(ms) {
|
|
14
|
+
if (!Number.isFinite(ms) || ms < 0) return "";
|
|
15
|
+
const s = ms / 1000;
|
|
16
|
+
if (s < 10) return `${s.toFixed(1)} s`;
|
|
17
|
+
if (s < 60) return `${Math.round(s)} s`;
|
|
18
|
+
return `${Math.floor(s / 60)} m ${String(Math.round(s % 60)).padStart(2, "0")} s`;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function StepIcon({ state }) {
|
|
22
|
+
if (state === "running") return <span className="agent-step-spin" aria-label={ko("running", "진행 중")} />;
|
|
23
|
+
if (state === "failed") return <FiX className="agent-step-icon alert" size={11} aria-label={ko("failed", "실패")} />;
|
|
24
|
+
if (state === "cancelled") return <FiSquare className="agent-step-icon warn" size={9} aria-label={ko("stopped", "중지됨")} />;
|
|
25
|
+
if (state === "note") return <span className="agent-step-dot" aria-hidden="true" />;
|
|
26
|
+
return <FiCheck className="agent-step-icon ok" size={11} aria-label={ko("done", "완료")} />;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function Step({ step, live, isLast, now, toolLabels }) {
|
|
30
|
+
const [open, setOpen] = useState(false);
|
|
31
|
+
if (step.kind === "narration") return <li className="agent-step narration" data-step-kind="narration"><StepIcon state="note" /><span className="agent-step-text">{step.text}</span></li>;
|
|
32
|
+
if (step.kind === "thinking") {
|
|
33
|
+
const running = live && isLast;
|
|
34
|
+
const line = thinkingLine(step.text);
|
|
35
|
+
// from its first words until the next step began; a thought that arrived at once shows no time
|
|
36
|
+
const took = (running ? now : step.endedAt ?? step.updatedAt) - step.startedAt;
|
|
37
|
+
return <li className="agent-step thinking" data-step-kind="thinking">
|
|
38
|
+
<button type="button" className="agent-step-row" aria-expanded={open} onClick={() => setOpen(value => !value)}>
|
|
39
|
+
<StepIcon state={running ? "running" : "note"} />
|
|
40
|
+
<span className="agent-step-label">{ko("Thinking", "생각")}</span>
|
|
41
|
+
<span className="agent-step-subject">{open ? "" : line}</span>
|
|
42
|
+
<span className="agent-step-time">{took >= 1000 ? stepClock(took) : ""}</span>
|
|
43
|
+
</button>
|
|
44
|
+
{open && <p className="agent-step-thought">{step.text}</p>}
|
|
45
|
+
</li>;
|
|
46
|
+
}
|
|
47
|
+
const running = step.kind === "compose" || step.status === "running";
|
|
48
|
+
const label = step.kind === "compose" ? ko(`Preparing ${stepLabel(step, toolLabels)}`, `${stepLabel(step, toolLabels)} 준비 중`) : stepLabel(step, toolLabels);
|
|
49
|
+
const result = running ? (step.progress ? `${scriptNow(step)}${step.progress.summary ? ` — ${step.progress.summary}` : ""}` : "") : stepResult(step);
|
|
50
|
+
const time = running ? now - (step.startedAt ?? now) : step.elapsedMs;
|
|
51
|
+
return <li className={`agent-step ${step.kind}${step.status === "failed" ? " failed" : ""}`} data-step-kind={step.kind} data-tool-name={step.name} data-tool-status={step.kind === "compose" ? "composing" : step.status} data-action={step.action}>
|
|
52
|
+
<div className="agent-step-row">
|
|
53
|
+
<StepIcon state={running ? "running" : step.status} />
|
|
54
|
+
<span className="agent-step-label">{label}</span>
|
|
55
|
+
{step.subject && <span className="agent-step-subject">{step.subject}</span>}
|
|
56
|
+
<span className="agent-step-time">{stepClock(time)}</span>
|
|
57
|
+
</div>
|
|
58
|
+
{result && <p className="agent-step-result">{result}</p>}
|
|
59
|
+
</li>;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function TurnSteps({ block, now, toolLabels, formatClock, onRetry }) {
|
|
63
|
+
const [chosen, setChosen] = useState(null);
|
|
64
|
+
const failed = block.end?.status === "failed" || block.steps.some(step => step.failure);
|
|
65
|
+
const stopped = block.end?.status === "stopped";
|
|
66
|
+
const open = chosen ?? (block.live || failed || stopped);
|
|
67
|
+
const header = stepsHeader(block, now, formatClock);
|
|
68
|
+
const failure = block.steps.find(step => step.failure)?.failure;
|
|
69
|
+
return <div className="agent-card agent-steps" data-agent-card="steps" data-steps-state={block.live ? "live" : block.end?.status ?? "done"} data-open={open ? "true" : "false"}>
|
|
70
|
+
<button type="button" className="agent-steps-head" aria-expanded={open} onClick={() => setChosen(!open)}>
|
|
71
|
+
<span className={`agent-status-dot ${header.tone}`} aria-hidden="true" />
|
|
72
|
+
<span className="agent-steps-title">{header.text}</span>
|
|
73
|
+
<FiChevronRight className="agent-steps-chevron" size={12} aria-hidden="true" />
|
|
74
|
+
</button>
|
|
75
|
+
{open && <ol className="agent-steps-list">
|
|
76
|
+
{block.steps.map((step, index) => <Step key={step.id} step={step} live={block.live} isLast={index === block.steps.length - 1} now={now} toolLabels={toolLabels} />)}
|
|
77
|
+
</ol>}
|
|
78
|
+
{stopped && <p className="agent-steps-note">{stoppedNote(block)}</p>}
|
|
79
|
+
{failure && <div className="agent-error" role="alert">
|
|
80
|
+
<span>{failure.message || ko("The turn failed.", "턴이 실패했어요.")}</span>
|
|
81
|
+
<div className="agent-error-actions"><button type="button" className="agent-ghost-button agent-error-retry" onClick={onRetry}>{ko("Retry", "다시 시도")}</button></div>
|
|
82
|
+
</div>}
|
|
83
|
+
</div>;
|
|
84
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import { FiX } from "react-icons/fi";
|
|
3
|
+
import { answerLogin, cancelLogin, fetchLogins, logoutProvider, readLogin, startLogin } from "./login-client.js";
|
|
4
|
+
|
|
5
|
+
// "Connect a model": pi's own login (the coding agent's /login) inside the agent panel (#pi-login). The list
|
|
6
|
+
// is what pi ships: each provider with its subscription sign-in and/or api-key login; picking one runs pi's
|
|
7
|
+
// flow in the sidecar and this panel only shows what pi asks (a key, a server address, a pasted code, a
|
|
8
|
+
// choice) and tells (a sign-in page to open, a device code, progress). ChatGPT keeps CozyClay's own sign-in.
|
|
9
|
+
|
|
10
|
+
const GROUPS = [
|
|
11
|
+
["Connected", (entry) => entry.connected],
|
|
12
|
+
["Subscriptions", (entry) => !entry.connected && entry.methods.some((method) => method.subscription)],
|
|
13
|
+
["API keys", (entry) => !entry.connected && !entry.methods.some((method) => method.subscription)],
|
|
14
|
+
];
|
|
15
|
+
|
|
16
|
+
function PromptForm({ prompt, onSubmit }) {
|
|
17
|
+
const [value, setValue] = useState("");
|
|
18
|
+
const ask = prompt.prompt;
|
|
19
|
+
if (ask.type === "select") {
|
|
20
|
+
return <div className="agent-login-choices" role="group" aria-label={ask.message}>
|
|
21
|
+
<p className="agent-login-ask">{ask.message}</p>
|
|
22
|
+
{(ask.options ?? []).map((option) => <button key={option.id} type="button" className="agent-ghost-button" onClick={() => onSubmit(option.id)}>{option.label}</button>)}
|
|
23
|
+
</div>;
|
|
24
|
+
}
|
|
25
|
+
const inputId = `agent-login-${prompt.promptId}`;
|
|
26
|
+
return <form className="agent-login-form" onSubmit={(event) => { event.preventDefault(); onSubmit(value); setValue(""); }}>
|
|
27
|
+
<label className="agent-login-ask" htmlFor={inputId}>{ask.message}</label>
|
|
28
|
+
<div className="agent-key-controls">
|
|
29
|
+
<input id={inputId} className="agent-key-input" type={ask.type === "secret" ? "password" : "text"} autoComplete="off" spellCheck="false"
|
|
30
|
+
placeholder={ask.placeholder ?? ""} value={value} autoFocus onChange={(event) => setValue(event.target.value)} />
|
|
31
|
+
<button type="submit" className="agent-key-save" disabled={ask.type === "secret" && !value.trim()}>Continue</button>
|
|
32
|
+
</div>
|
|
33
|
+
</form>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function FlowLog({ entries }) {
|
|
37
|
+
return <ul className="agent-login-log">
|
|
38
|
+
{entries.map((entry, index) => {
|
|
39
|
+
const event = entry.event;
|
|
40
|
+
if (event.type === "auth_url") return <li key={index}><a className="agent-primary-button agent-login-open" href={event.url} target="_blank" rel="noopener noreferrer">Open the sign-in page</a>{event.instructions && <span className="agent-key-note">{event.instructions}</span>}</li>;
|
|
41
|
+
if (event.type === "device_code") return <li key={index}><span className="agent-key-note">Enter this code at </span><a href={event.verificationUri} target="_blank" rel="noopener noreferrer">{event.verificationUri}</a><code className="agent-login-code">{event.userCode}</code></li>;
|
|
42
|
+
return <li key={index} className="agent-key-note">{event.message}{(event.links ?? []).map((link) => <a key={link.url} href={link.url} target="_blank" rel="noopener noreferrer"> {link.label || link.url}</a>)}</li>;
|
|
43
|
+
})}
|
|
44
|
+
</ul>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function LoginPanel({ onClose, onChatGPT, onChanged }) {
|
|
48
|
+
const [providers, setProviders] = useState(null);
|
|
49
|
+
const [error, setError] = useState("");
|
|
50
|
+
const [query, setQuery] = useState("");
|
|
51
|
+
const [flow, setFlow] = useState(null);
|
|
52
|
+
const live = useRef(true);
|
|
53
|
+
const load = useCallback(async () => {
|
|
54
|
+
try { setProviders(await fetchLogins()); setError(""); } catch (failure) { setError(failure?.message || "The login list is unavailable."); }
|
|
55
|
+
}, []);
|
|
56
|
+
useEffect(() => { live.current = true; load(); return () => { live.current = false; }; }, [load]);
|
|
57
|
+
// Read the running flow until pi finishes it.
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (!flow?.flowId || flow.done) return undefined;
|
|
60
|
+
let stopped = false;
|
|
61
|
+
(async () => {
|
|
62
|
+
let after = 0;
|
|
63
|
+
while (!stopped && live.current) {
|
|
64
|
+
let page;
|
|
65
|
+
try { page = await readLogin(flow.flowId, after); } catch (failure) { if (!stopped) setFlow((current) => current && { ...current, done: true, ok: false, message: failure?.message || "The login stopped." }); return; }
|
|
66
|
+
if (stopped) return;
|
|
67
|
+
after = page.next;
|
|
68
|
+
for (const entry of page.events) {
|
|
69
|
+
setFlow((current) => {
|
|
70
|
+
if (!current || current.flowId !== flow.flowId) return current;
|
|
71
|
+
if (entry.type === "prompt") return { ...current, prompt: entry };
|
|
72
|
+
if (entry.type === "prompt_closed") return current.prompt?.promptId === entry.promptId ? { ...current, prompt: null } : current;
|
|
73
|
+
if (entry.type === "event") return { ...current, log: [...current.log, entry] };
|
|
74
|
+
return { ...current, prompt: null, done: true, ok: entry.ok, message: entry.message ?? "" };
|
|
75
|
+
});
|
|
76
|
+
if (entry.type === "done" && entry.ok) { await onChanged?.(); load(); }
|
|
77
|
+
}
|
|
78
|
+
if (page.done) return;
|
|
79
|
+
}
|
|
80
|
+
})();
|
|
81
|
+
return () => { stopped = true; };
|
|
82
|
+
}, [flow?.flowId, flow?.done, load, onChanged]);
|
|
83
|
+
|
|
84
|
+
const begin = async (provider, method) => {
|
|
85
|
+
setError("");
|
|
86
|
+
// ChatGPT's own sign-in shows its waiting card in the panel body, so the list steps aside.
|
|
87
|
+
if (method.type === "chatgpt") { onChatGPT?.(); onClose?.(); return; }
|
|
88
|
+
try {
|
|
89
|
+
const flowId = await startLogin(provider.id, method.type);
|
|
90
|
+
setFlow({ flowId, name: provider.name, label: method.label, log: [], prompt: null, done: false });
|
|
91
|
+
} catch (failure) { setError(failure?.message || "That login could not start."); }
|
|
92
|
+
};
|
|
93
|
+
const answer = async (value) => {
|
|
94
|
+
const prompt = flow?.prompt;
|
|
95
|
+
if (!prompt) return;
|
|
96
|
+
setFlow((current) => current && { ...current, prompt: null });
|
|
97
|
+
try { await answerLogin(flow.flowId, prompt.promptId, value); } catch (failure) { setError(failure?.message || "That answer was not taken."); }
|
|
98
|
+
};
|
|
99
|
+
const cancel = async () => {
|
|
100
|
+
if (flow && !flow.done) await cancelLogin(flow.flowId).catch(() => {});
|
|
101
|
+
setFlow(null);
|
|
102
|
+
};
|
|
103
|
+
const logout = async (provider) => {
|
|
104
|
+
try { await logoutProvider(provider.id); await onChanged?.(); load(); } catch (failure) { setError(failure?.message || "Logout failed."); }
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const shown = (providers ?? []).filter((entry) => !query.trim() || entry.name.toLowerCase().includes(query.trim().toLowerCase()));
|
|
108
|
+
return <section className="agent-keys agent-login" aria-label="Connect a model" data-agent-keys="true">
|
|
109
|
+
<div className="agent-keys-head">
|
|
110
|
+
<h3 className="agent-keys-title">Connect a model</h3>
|
|
111
|
+
<button type="button" className="agent-icon-button agent-keys-close" aria-label="Close" onClick={async () => { await cancel(); onClose?.(); }}><FiX size={11} aria-hidden="true" /></button>
|
|
112
|
+
</div>
|
|
113
|
+
{error && <p className="agent-key-error" role="alert">{error}</p>}
|
|
114
|
+
{flow ? <div className="agent-login-flow" data-login-flow={flow.done ? (flow.ok ? "connected" : "failed") : "running"}>
|
|
115
|
+
<p className="agent-key-label">{flow.name} · {flow.label}</p>
|
|
116
|
+
<FlowLog entries={flow.log} />
|
|
117
|
+
{flow.prompt && <PromptForm key={flow.prompt.promptId} prompt={flow.prompt} onSubmit={answer} />}
|
|
118
|
+
{!flow.done && !flow.prompt && <p className="agent-key-note">Waiting for {flow.name}…</p>}
|
|
119
|
+
{flow.done && <p className={flow.ok ? "agent-key-note" : "agent-key-error"} role={flow.ok ? "status" : "alert"}>{flow.ok ? `Connected to ${flow.name}.` : flow.message}</p>}
|
|
120
|
+
<div className="agent-key-controls"><button type="button" className="agent-ghost-button" onClick={cancel}>{flow.done ? "Back to the list" : "Cancel"}</button></div>
|
|
121
|
+
</div> : <>
|
|
122
|
+
<p className="agent-keys-hint">A subscription signs in on its own page. A key or server address you type stays with the local CozyClay service and is never shown again.</p>
|
|
123
|
+
<input className="agent-key-input" type="search" aria-label="Search providers" placeholder="Search providers" value={query} onChange={(event) => setQuery(event.target.value)} />
|
|
124
|
+
{providers === null && !error && <p className="agent-keys-note">Loading providers…</p>}
|
|
125
|
+
{GROUPS.map(([title, test]) => {
|
|
126
|
+
const rows = shown.filter(test);
|
|
127
|
+
return rows.length ? <div key={title} className="agent-login-group"><p className="agent-key-endpoint-label">{title}</p>
|
|
128
|
+
{rows.map((provider) => <div key={provider.id} className="agent-key-row" data-provider={provider.id} data-provider-signed-in={provider.connected ? "true" : "false"}>
|
|
129
|
+
<div className="agent-key-head"><span className="agent-key-label">{provider.name}</span><span className="agent-key-source">{provider.connected ? (provider.via === "oauth" ? "signed in" : provider.source || "key") : ""}</span></div>
|
|
130
|
+
<div className="agent-key-controls">
|
|
131
|
+
{provider.connected && provider.id !== "openai-codex"
|
|
132
|
+
? <button type="button" className="agent-ghost-button agent-key-remove" onClick={() => logout(provider)}>Log out</button>
|
|
133
|
+
: provider.methods.map((method) => <button key={method.type} type="button" className={method.subscription ? "agent-key-save" : "agent-ghost-button"} onClick={() => begin(provider, method)}>{method.label}</button>)}
|
|
134
|
+
</div>
|
|
135
|
+
</div>)}
|
|
136
|
+
</div> : null;
|
|
137
|
+
})}
|
|
138
|
+
</>}
|
|
139
|
+
</section>;
|
|
140
|
+
}
|
|
@@ -15,7 +15,7 @@ import { loadWorkflowGraph, normalizeWorkflowGraph, storeWorkflowGraph, WORKFLOW
|
|
|
15
15
|
import AgentPanel from "./AgentPanel.jsx";
|
|
16
16
|
import CozySceneNode from "./CozySceneNode.jsx";
|
|
17
17
|
import { applyCozyScenePatch, normalizeCozySceneData, sceneConnectionAllowed } from "./cozy-scene-node.js";
|
|
18
|
-
import { activeSceneCharacters, characterHandleId, characterIdFromHandle, normalizeMotionInputData, motionInputOutput } from "./motion-input.js";
|
|
18
|
+
import { activeSceneCharacters, characterHandleId, characterIdFromHandle, normalizeMotionInputData, motionInputOutput, parseMotionSpec } from "./motion-input.js";
|
|
19
19
|
import { DEFAULT_NODE_SCHEMAS, defaultFormValues, schemaCategoryForType, schemaModelEntries, schemaProperties } from "./node-schema.js";
|
|
20
20
|
import { executeLocalWorkflowGraph } from "./local-workflow.js";
|
|
21
21
|
import { createLiveControl } from "../live-control.js";
|
|
@@ -24,7 +24,6 @@ import { startWorkflowExecution } from "../execution-telemetry.js";
|
|
|
24
24
|
import { createCanvasCommands } from "./canvas-commands.js";
|
|
25
25
|
import { applyMotionToActiveScene, importImageIntoActiveScene, readStoredSceneDocument } from "./scene-asset-sync.js";
|
|
26
26
|
import { createHttpTransport } from "./agent-client.js";
|
|
27
|
-
import { fetchVideoOutputBlob, requestBridgeExtract } from "../multimodel-ingest.js";
|
|
28
27
|
import { canvasTakesPaste, fileToDataUrl, imageFileFromTransfer, pastedImageNodeData } from "./clipboard-image.js";
|
|
29
28
|
import { appendVersion, compareIndex, pinnedInputs, selectVersion, versionLabel, versionState } from "./image-versions.js";
|
|
30
29
|
import { normalizeVideoForm, videoFormContract } from "./video-contract.js";
|
|
@@ -214,10 +213,8 @@ function VideoNode({ id, data }) {
|
|
|
214
213
|
<label>Motion prompt</label><textarea className="workflow-textarea" value={form.prompt ?? data.prompt ?? ""} onChange={(event) => update("prompt", event.target.value)} placeholder="Motion prompt" />
|
|
215
214
|
<label>Duration (seconds)</label><input type="number" min={contract.minDuration} max={contract.maxDuration} value={form.duration_seconds} onChange={(event) => update("duration_seconds", Number(event.target.value))} />
|
|
216
215
|
<label>Aspect</label>{contract.aspectFromImage ? <><div className="workflow-hint" data-testid="video-source-aspect">Matches input image · frame the full body in the source image</div><div className="workflow-warning" role="status" data-testid="mocap-framing-warning">Before generating: confirm the captured frame shows the head, hands, feet, and any needed objects. Cropped parts can break mocap alignment.</div></> : <select value={form.aspect} onChange={(event) => update("aspect", event.target.value)}>{contract.aspects.map((aspect) => <option key={aspect}>{aspect}</option>)}</select>}
|
|
217
|
-
<label className="workflow-schema-check"><input type="checkbox" checked={Boolean(form.extract_mocap)} onChange={(event) => update("extract_mocap", event.target.checked)} />Extract GVHMR motion into connected Motion Input</label>
|
|
218
216
|
</>}
|
|
219
217
|
{data.videoUrl && <video controls className="workflow-video-preview" src={data.videoUrl} />}
|
|
220
|
-
{generated && data.motionExtraction?.motionUrl && <div className="workflow-hint" data-testid="mocap-extraction-receipt">✓ GVHMR motion extracted{Number.isFinite(data.motionExtraction.frames) ? ` · ${data.motionExtraction.frames} frames` : ""}</div>}
|
|
221
218
|
{generated && data.preservation?.pass && <div className="workflow-hint workflow-preservation-ok" data-testid="h3-preservation-receipt">✓ H3 scene/camera lock verified{h3VerificationMetrics(data.preservation)}</div>}
|
|
222
219
|
{generated && data.preservation && !data.preservation.pass && <div className="workflow-error workflow-preservation-failed" data-testid="h3-preservation-failed">✕ H3 output rejected: background/camera drift{h3VerificationMetrics(data.preservation)}</div>}
|
|
223
220
|
{generated && data.isLoading && <div className="workflow-hint">Generating video…</div>}{generated && data.errorMsg && <div className="workflow-error">{data.errorMsg}</div>}
|
|
@@ -246,9 +243,8 @@ function MotionInputNode({ id, data }) {
|
|
|
246
243
|
{options.map((character) => <option key={character.id} value={character.id}>{character.name || character.subject || character.id}</option>)}
|
|
247
244
|
</select>
|
|
248
245
|
<input aria-label="Character id" value={normalized.characterId} onChange={(event) => update({ characterId: event.target.value.trim() })} placeholder="character id (e.g. char-a)" />
|
|
249
|
-
<label>
|
|
250
|
-
<
|
|
251
|
-
<label className="workflow-upload workflow-motion-upload"><FiUpload size={18} /><span>{normalized.fileName || "Choose local .npz motion"}</span><input type="file" accept=".npz,application/octet-stream,.json" onChange={(event) => { const file = event.target.files?.[0]; if (!file) return; const objectUrl = URL.createObjectURL(file); update({ objectUrl, url: objectUrl, fileName: file.name, mimeType: file.type || "application/octet-stream", status: "ready" }); }} /></label>
|
|
246
|
+
<label>Motion spec (cozyclay.motion-spec.v1)</label>
|
|
247
|
+
<label className="workflow-upload workflow-motion-upload"><FiUpload size={18} /><span>{normalized.fileName || "Choose a motion spec .json"}</span><input type="file" accept=".json,application/json" onChange={(event) => { const file = event.target.files?.[0]; if (!file) return; file.text().then((body) => { const spec = parseMotionSpec(body); if (!spec) toast.error("Not a cozyclay.motion-spec.v1 file"); update(spec ? { spec, fileName: file.name, status: "ready" } : { spec: null, fileName: file.name, status: "error" }); }); }} /></label>
|
|
252
248
|
<div className="workflow-node-foot"><span>{normalized.status === "ready" ? `${handleId} ready` : "Connect to a character handle"}</span><span>{motionInputOutput(normalized).frames ? `${motionInputOutput(normalized).frames}f` : ""}</span></div>
|
|
253
249
|
</NodeShell>;
|
|
254
250
|
}
|
|
@@ -539,20 +535,8 @@ export default function WorkflowBuilder() {
|
|
|
539
535
|
const videoForm = normalizeVideoForm(provider, { ...form, duration_seconds: form.duration_seconds ?? current.data.duration_seconds, aspect: form.aspect || current.data.aspect }, falModel);
|
|
540
536
|
const output = await createHttpTransport().video({ provider, prompt: motionPrompt, imageDataUrl: frame, ...(lastFrameDataUrl ? { lastFrameDataUrl } : {}), durationSeconds: videoForm.duration_seconds, aspect: videoForm.aspect });
|
|
541
537
|
const videoUrl = output.dataUrl || output.url;
|
|
542
|
-
let motionExtraction = null;
|
|
543
|
-
const motionTargets = graph.edges.filter((edge) => edge.source === id).map((edge) => result.nodes.find((node) => node.id === edge.target)).filter((node) => node?.type === "motion-input");
|
|
544
|
-
if (videoForm.extract_mocap && motionTargets.length) {
|
|
545
|
-
const done = await requestBridgeExtract(await fetchVideoOutputBlob(videoUrl));
|
|
546
|
-
motionExtraction = done;
|
|
547
|
-
for (const target of motionTargets) {
|
|
548
|
-
const motionData = normalizeMotionInputData({ ...target.data, url: done.motionUrl, objectUrl: null, status: "ready", frames: done.frames, fps: done.fps, motionRef: done.motionRef || null });
|
|
549
|
-
const motionOutput = motionInputOutput(motionData);
|
|
550
|
-
values.set(target.id, motionOutput);
|
|
551
|
-
patchNode(target.id, { ...motionData, outputs: [{ value: motionOutput }] });
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
538
|
values.set(id, videoUrl);
|
|
555
|
-
patchNode(id, { isLoading: false, status: "complete", videoUrl, resultUrl: videoUrl, outputs: [{ value: videoUrl }], preservation: output.preservation || null,
|
|
539
|
+
patchNode(id, { isLoading: false, status: "complete", videoUrl, resultUrl: videoUrl, outputs: [{ value: videoUrl }], preservation: output.preservation || null, errorMsg: null });
|
|
556
540
|
if (videoUrl) execution.apply();
|
|
557
541
|
}
|
|
558
542
|
catch (error) {
|
|
@@ -592,7 +576,7 @@ export default function WorkflowBuilder() {
|
|
|
592
576
|
const source = resultById.get(assignment.source);
|
|
593
577
|
if (source?.type !== "motion-input" || !assignment.characterId) continue;
|
|
594
578
|
const motion = motionInputOutput({ ...source.data, ...(patches.get(source.id) || {}) });
|
|
595
|
-
if (motion.
|
|
579
|
+
if (motion.spec) applyMotionToActiveScene(assignment.characterId, motion);
|
|
596
580
|
}
|
|
597
581
|
}
|
|
598
582
|
setRunState("complete");
|
|
@@ -672,8 +656,8 @@ export default function WorkflowBuilder() {
|
|
|
672
656
|
const onConnect = useCallback((params) => {
|
|
673
657
|
const target = nodes.find((node) => node.id === params.target);
|
|
674
658
|
const source = nodes.find((node) => node.id === params.source);
|
|
675
|
-
if (target?.type === "motion-input"
|
|
676
|
-
toast.error("Motion Input
|
|
659
|
+
if (target?.type === "motion-input") {
|
|
660
|
+
toast.error("Motion Input takes a motion spec file, not a node");
|
|
677
661
|
return;
|
|
678
662
|
}
|
|
679
663
|
if (target?.type === "scene" && !sceneConnectionAllowed(source, params.targetHandle, source?.data)) {
|