@maudecode/talaria-web 1.17.2 → 1.19.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/_release.json +8 -8
- package/dist/api/auth-raw.d.ts +1 -1
- package/dist/api/auth-raw.js +20 -20
- package/dist/api/auth-raw.js.map +1 -1
- package/dist/api/automation-raw.d.ts +7 -1
- package/dist/api/automation-raw.js +74 -27
- package/dist/api/automation-raw.js.map +1 -1
- package/dist/api/automation-router.d.ts +128 -23
- package/dist/api/automation-router.js +29 -13
- package/dist/api/automation-router.js.map +1 -1
- package/dist/api/chat-router.d.ts +1845 -40
- package/dist/api/chat-router.js +196 -114
- package/dist/api/chat-router.js.map +1 -1
- package/dist/api/git-router.d.ts +37 -3
- package/dist/api/git-router.js +47 -48
- package/dist/api/git-router.js.map +1 -1
- package/dist/api/raw-routes.d.ts +9 -1
- package/dist/api/raw-routes.js +286 -73
- package/dist/api/raw-routes.js.map +1 -1
- package/dist/api/router.d.ts +16 -6
- package/dist/api/router.js +28 -26
- package/dist/api/router.js.map +1 -1
- package/dist/api/session-visibility.d.ts +4 -4
- package/dist/api/session-visibility.js +26 -16
- package/dist/api/session-visibility.js.map +1 -1
- package/dist/api/sessions-router.d.ts +3312 -131
- package/dist/api/sessions-router.js +287 -157
- package/dist/api/sessions-router.js.map +1 -1
- package/dist/api/settings-router.d.ts +457 -8
- package/dist/api/settings-router.js +54 -33
- package/dist/api/settings-router.js.map +1 -1
- package/dist/api/sse-routes.d.ts +7 -2
- package/dist/api/sse-routes.js +109 -62
- package/dist/api/sse-routes.js.map +1 -1
- package/dist/api/tools-raw.d.ts +5 -0
- package/dist/api/tools-raw.js +63 -55
- package/dist/api/tools-raw.js.map +1 -1
- package/dist/api/tools-router.d.ts +998 -85
- package/dist/api/tools-router.js +447 -61
- package/dist/api/tools-router.js.map +1 -1
- package/dist/api/transcribe-stream.d.ts +16 -0
- package/dist/api/transcribe-stream.js +172 -0
- package/dist/api/transcribe-stream.js.map +1 -0
- package/dist/app.d.ts +4 -1
- package/dist/app.js +98 -59
- package/dist/app.js.map +1 -1
- package/dist/auth/gate.js +15 -11
- package/dist/auth/gate.js.map +1 -1
- package/dist/auth/oidc.d.ts +5 -2
- package/dist/auth/oidc.js +8 -7
- package/dist/auth/oidc.js.map +1 -1
- package/dist/auth/passkeys.d.ts +15 -14
- package/dist/auth/passkeys.js +89 -91
- package/dist/auth/passkeys.js.map +1 -1
- package/dist/auth/store.d.ts +17 -7
- package/dist/auth/store.js +93 -52
- package/dist/auth/store.js.map +1 -1
- package/dist/bin/talaria-web.js +12 -81
- package/dist/bin/talaria-web.js.map +1 -1
- package/dist/cli/ctl.js +2 -1
- package/dist/cli/ctl.js.map +1 -1
- package/dist/cli/dotenv.d.ts +5 -0
- package/dist/cli/dotenv.js +15 -2
- package/dist/cli/dotenv.js.map +1 -1
- package/dist/cli/launcher.js +5 -5
- package/dist/cli/launcher.js.map +1 -1
- package/dist/cli/main.d.ts +1 -0
- package/dist/cli/main.js +85 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/supervise.d.ts +2 -0
- package/dist/cli/supervise.js +67 -4
- package/dist/cli/supervise.js.map +1 -1
- package/dist/config/agent-config.d.ts +34 -11
- package/dist/config/agent-config.js +116 -60
- package/dist/config/agent-config.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.js +19 -6
- package/dist/config.js.map +1 -1
- package/dist/fs/atomic.d.ts +1 -0
- package/dist/fs/atomic.js +4 -1
- package/dist/fs/atomic.js.map +1 -1
- package/dist/fs/stat.d.ts +1 -0
- package/dist/fs/stat.js +11 -0
- package/dist/fs/stat.js.map +1 -0
- package/dist/http/context.d.ts +31 -12
- package/dist/http/context.js +60 -24
- package/dist/http/context.js.map +1 -1
- package/dist/http/csp.d.ts +2 -1
- package/dist/http/csp.js +3 -2
- package/dist/http/csp.js.map +1 -1
- package/dist/onboarding.d.ts +2 -2
- package/dist/onboarding.js +10 -8
- package/dist/onboarding.js.map +1 -1
- package/dist/profiles/profiles.d.ts +20 -4
- package/dist/profiles/profiles.js +115 -30
- package/dist/profiles/profiles.js.map +1 -1
- package/dist/projects.d.ts +15 -6
- package/dist/projects.js +55 -47
- package/dist/projects.js.map +1 -1
- package/dist/providers/catalog.d.ts +84 -14
- package/dist/providers/catalog.js +474 -151
- package/dist/providers/catalog.js.map +1 -1
- package/dist/providers/env-file.d.ts +10 -3
- package/dist/providers/env-file.js +24 -75
- package/dist/providers/env-file.js.map +1 -1
- package/dist/providers/runtime-env.d.ts +4 -2
- package/dist/providers/runtime-env.js +9 -6
- package/dist/providers/runtime-env.js.map +1 -1
- package/dist/providers/tables.d.ts +3 -1
- package/dist/providers/tables.js +4 -2
- package/dist/providers/tables.js.map +1 -1
- package/dist/raster-image.d.ts +7 -0
- package/dist/raster-image.js +267 -0
- package/dist/raster-image.js.map +1 -0
- package/dist/redact.js +342 -46
- package/dist/redact.js.map +1 -1
- package/dist/release.d.ts +7 -0
- package/dist/release.js +14 -0
- package/dist/release.js.map +1 -1
- package/dist/runtime.d.ts +5 -1
- package/dist/runtime.js +305 -96
- package/dist/runtime.js.map +1 -1
- package/dist/server.js +15 -0
- package/dist/server.js.map +1 -1
- package/dist/sessions/anchor.d.ts +9 -3
- package/dist/sessions/anchor.js +28 -36
- package/dist/sessions/anchor.js.map +1 -1
- package/dist/sessions/background-events.d.ts +2 -0
- package/dist/sessions/background-events.js +10 -0
- package/dist/sessions/background-events.js.map +1 -0
- package/dist/sessions/background-tasks.d.ts +26 -27
- package/dist/sessions/background-tasks.js +89 -97
- package/dist/sessions/background-tasks.js.map +1 -1
- package/dist/sessions/background-updates.d.ts +15 -8
- package/dist/sessions/background-updates.js +101 -25
- package/dist/sessions/background-updates.js.map +1 -1
- package/dist/sessions/cli-sessions.d.ts +27 -6
- package/dist/sessions/cli-sessions.js +152 -42
- package/dist/sessions/cli-sessions.js.map +1 -1
- package/dist/sessions/completions.d.ts +77 -9
- package/dist/sessions/completions.js +482 -45
- package/dist/sessions/completions.js.map +1 -1
- package/dist/sessions/compress.d.ts +8 -0
- package/dist/sessions/compress.js +2 -2
- package/dist/sessions/compress.js.map +1 -1
- package/dist/sessions/drafts.d.ts +14 -10
- package/dist/sessions/drafts.js +38 -43
- package/dist/sessions/drafts.js.map +1 -1
- package/dist/sessions/export.d.ts +5 -0
- package/dist/sessions/export.js +30 -0
- package/dist/sessions/export.js.map +1 -1
- package/dist/sessions/gateway-sessions.d.ts +46 -0
- package/dist/sessions/gateway-sessions.js +378 -0
- package/dist/sessions/gateway-sessions.js.map +1 -0
- package/dist/sessions/gateway-watcher.d.ts +7 -3
- package/dist/sessions/gateway-watcher.js +31 -19
- package/dist/sessions/gateway-watcher.js.map +1 -1
- package/dist/sessions/goals.d.ts +31 -0
- package/dist/sessions/goals.js +75 -0
- package/dist/sessions/goals.js.map +1 -0
- package/dist/sessions/handoff.d.ts +32 -0
- package/dist/sessions/handoff.js +114 -0
- package/dist/sessions/handoff.js.map +1 -0
- package/dist/sessions/journal.d.ts +5 -79
- package/dist/sessions/journal.js +15 -606
- package/dist/sessions/journal.js.map +1 -1
- package/dist/sessions/list.d.ts +31 -16
- package/dist/sessions/list.js +139 -129
- package/dist/sessions/list.js.map +1 -1
- package/dist/sessions/merge.d.ts +69 -13
- package/dist/sessions/merge.js +265 -64
- package/dist/sessions/merge.js.map +1 -1
- package/dist/sessions/notices.d.ts +22 -0
- package/dist/sessions/notices.js +72 -0
- package/dist/sessions/notices.js.map +1 -0
- package/dist/sessions/pending.d.ts +10 -4
- package/dist/sessions/pending.js +83 -7
- package/dist/sessions/pending.js.map +1 -1
- package/dist/sessions/prefix-index.d.ts +82 -0
- package/dist/sessions/prefix-index.js +232 -0
- package/dist/sessions/prefix-index.js.map +1 -0
- package/dist/sessions/recovery.d.ts +19 -0
- package/dist/sessions/recovery.js +322 -0
- package/dist/sessions/recovery.js.map +1 -0
- package/dist/sessions/relay.d.ts +38 -19
- package/dist/sessions/relay.js +302 -79
- package/dist/sessions/relay.js.map +1 -1
- package/dist/sessions/service.d.ts +260 -55
- package/dist/sessions/service.js +1448 -462
- package/dist/sessions/service.js.map +1 -1
- package/dist/sessions/session.d.ts +24 -2
- package/dist/sessions/session.js +69 -7
- package/dist/sessions/session.js.map +1 -1
- package/dist/sessions/shares.d.ts +7 -6
- package/dist/sessions/shares.js +22 -45
- package/dist/sessions/shares.js.map +1 -1
- package/dist/sessions/source-kind.js +1 -0
- package/dist/sessions/source-kind.js.map +1 -1
- package/dist/sessions/state-db-identity.d.ts +18 -0
- package/dist/sessions/state-db-identity.js +67 -0
- package/dist/sessions/state-db-identity.js.map +1 -0
- package/dist/sessions/state-db-worker.d.ts +1 -0
- package/dist/sessions/state-db-worker.js +35 -0
- package/dist/sessions/state-db-worker.js.map +1 -0
- package/dist/sessions/state-db.d.ts +113 -7
- package/dist/sessions/state-db.js +861 -44
- package/dist/sessions/state-db.js.map +1 -1
- package/dist/sessions/storage/backend.d.ts +162 -0
- package/dist/sessions/storage/backend.js +19 -0
- package/dist/sessions/storage/backend.js.map +1 -0
- package/dist/sessions/storage/conformance.d.ts +20 -0
- package/dist/sessions/storage/conformance.js +237 -0
- package/dist/sessions/storage/conformance.js.map +1 -0
- package/dist/sessions/storage/document.d.ts +16 -0
- package/dist/sessions/storage/document.js +44 -0
- package/dist/sessions/storage/document.js.map +1 -0
- package/dist/sessions/storage/json-documents.d.ts +23 -0
- package/dist/sessions/storage/json-documents.js +233 -0
- package/dist/sessions/storage/json-documents.js.map +1 -0
- package/dist/sessions/storage/json-files.d.ts +12 -0
- package/dist/sessions/storage/json-files.js +124 -0
- package/dist/sessions/storage/json-files.js.map +1 -0
- package/dist/sessions/storage/json-installation.d.ts +3 -0
- package/dist/sessions/storage/json-installation.js +31 -0
- package/dist/sessions/storage/json-installation.js.map +1 -0
- package/dist/sessions/storage/json-journal.d.ts +114 -0
- package/dist/sessions/storage/json-journal.js +686 -0
- package/dist/sessions/storage/json-journal.js.map +1 -0
- package/dist/sessions/storage/json-recovery.d.ts +4 -0
- package/dist/sessions/storage/json-recovery.js +195 -0
- package/dist/sessions/storage/json-recovery.js.map +1 -0
- package/dist/sessions/storage/json.d.ts +68 -0
- package/dist/sessions/storage/json.js +258 -0
- package/dist/sessions/storage/json.js.map +1 -0
- package/dist/sessions/storage/row.d.ts +6 -0
- package/dist/sessions/storage/row.js +49 -0
- package/dist/sessions/storage/row.js.map +1 -0
- package/dist/sessions/storage/search-text.d.ts +4 -0
- package/dist/sessions/storage/search-text.js +16 -0
- package/dist/sessions/storage/search-text.js.map +1 -0
- package/dist/sessions/store.d.ts +65 -68
- package/dist/sessions/store.js +305 -602
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/streams.d.ts +4 -0
- package/dist/sessions/streams.js +9 -1
- package/dist/sessions/streams.js.map +1 -1
- package/dist/sessions/titles.d.ts +2 -0
- package/dist/sessions/titles.js +5 -1
- package/dist/sessions/titles.js.map +1 -1
- package/dist/sessions/todo.d.ts +5 -0
- package/dist/sessions/todo.js +28 -21
- package/dist/sessions/todo.js.map +1 -1
- package/dist/sessions/tool-display.d.ts +5 -4
- package/dist/sessions/tool-display.js +30 -50
- package/dist/sessions/tool-display.js.map +1 -1
- package/dist/sessions/turn-context.d.ts +11 -2
- package/dist/sessions/turn-context.js +18 -11
- package/dist/sessions/turn-context.js.map +1 -1
- package/dist/sessions/turn.d.ts +122 -17
- package/dist/sessions/turn.js +939 -358
- package/dist/sessions/turn.js.map +1 -1
- package/dist/sessions/wakeup-pause.d.ts +54 -0
- package/dist/sessions/wakeup-pause.js +163 -0
- package/dist/sessions/wakeup-pause.js.map +1 -0
- package/dist/sessions/window.js +13 -12
- package/dist/sessions/window.js.map +1 -1
- package/dist/settings.d.ts +19 -7
- package/dist/settings.js +178 -184
- package/dist/settings.js.map +1 -1
- package/dist/sidecar/client.d.ts +17 -3
- package/dist/sidecar/client.js +78 -8
- package/dist/sidecar/client.js.map +1 -1
- package/dist/sidecar/discover.d.ts +2 -1
- package/dist/sidecar/discover.js +93 -10
- package/dist/sidecar/discover.js.map +1 -1
- package/dist/sidecar/env.d.ts +4 -0
- package/dist/sidecar/env.js +3 -0
- package/dist/sidecar/env.js.map +1 -0
- package/dist/sidecar/fake.d.ts +2 -2
- package/dist/sidecar/fake.js +19 -2
- package/dist/sidecar/fake.js.map +1 -1
- package/dist/startup.d.ts +13 -5
- package/dist/startup.js +48 -0
- package/dist/startup.js.map +1 -1
- package/dist/test/env-file.d.ts +5 -0
- package/dist/test/env-file.js +88 -0
- package/dist/test/env-file.js.map +1 -0
- package/dist/test/harness.d.ts +1 -0
- package/dist/test/harness.js +1 -1
- package/dist/test/harness.js.map +1 -1
- package/dist/test/passkeys.d.ts +22 -0
- package/dist/test/passkeys.js +62 -0
- package/dist/test/passkeys.js.map +1 -0
- package/dist/test/storage.d.ts +15 -0
- package/dist/test/storage.js +26 -0
- package/dist/test/storage.js.map +1 -0
- package/dist/test/ts-worker-hooks.d.ts +1 -0
- package/dist/test/ts-worker-hooks.js +24 -0
- package/dist/test/ts-worker-hooks.js.map +1 -0
- package/dist/text/diff.d.ts +9 -14
- package/dist/text/diff.js +74 -108
- package/dist/text/diff.js.map +1 -1
- package/dist/tools/commands.d.ts +6 -1
- package/dist/tools/commands.js +8 -2
- package/dist/tools/commands.js.map +1 -1
- package/dist/tools/connectors.d.ts +33 -0
- package/dist/tools/connectors.js +121 -0
- package/dist/tools/connectors.js.map +1 -0
- package/dist/tools/crons.d.ts +38 -1
- package/dist/tools/crons.js +122 -18
- package/dist/tools/crons.js.map +1 -1
- package/dist/tools/dashboard-plugins.d.ts +53 -0
- package/dist/tools/dashboard-plugins.js +188 -0
- package/dist/tools/dashboard-plugins.js.map +1 -0
- package/dist/tools/extensions.d.ts +18 -5
- package/dist/tools/extensions.js +344 -266
- package/dist/tools/extensions.js.map +1 -1
- package/dist/tools/gateway-restart.d.ts +62 -0
- package/dist/tools/gateway-restart.js +142 -0
- package/dist/tools/gateway-restart.js.map +1 -0
- package/dist/tools/health.d.ts +44 -0
- package/dist/tools/health.js +201 -46
- package/dist/tools/health.js.map +1 -1
- package/dist/tools/hygiene.d.ts +4 -3
- package/dist/tools/hygiene.js +23 -9
- package/dist/tools/hygiene.js.map +1 -1
- package/dist/tools/kanban.d.ts +4 -2
- package/dist/tools/kanban.js +28 -19
- package/dist/tools/kanban.js.map +1 -1
- package/dist/tools/mcp.d.ts +13 -0
- package/dist/tools/mcp.js +88 -0
- package/dist/tools/mcp.js.map +1 -1
- package/dist/tools/memory-masks.d.ts +5 -0
- package/dist/tools/memory-masks.js +256 -0
- package/dist/tools/memory-masks.js.map +1 -0
- package/dist/tools/memory.d.ts +29 -3
- package/dist/tools/memory.js +69 -27
- package/dist/tools/memory.js.map +1 -1
- package/dist/tools/plugin-settings.d.ts +15 -0
- package/dist/tools/plugin-settings.js +90 -0
- package/dist/tools/plugin-settings.js.map +1 -0
- package/dist/tools/project-os.d.ts +11 -0
- package/dist/tools/project-os.js +267 -0
- package/dist/tools/project-os.js.map +1 -0
- package/dist/tools/skills.d.ts +14 -5
- package/dist/tools/skills.js +49 -16
- package/dist/tools/skills.js.map +1 -1
- package/dist/tools/update-notifications.d.ts +34 -15
- package/dist/tools/update-notifications.js +141 -57
- package/dist/tools/update-notifications.js.map +1 -1
- package/dist/tools/update-rollback.d.ts +11 -0
- package/dist/tools/update-rollback.js +28 -0
- package/dist/tools/update-rollback.js.map +1 -0
- package/dist/tools/updates.d.ts +110 -32
- package/dist/tools/updates.js +1112 -294
- package/dist/tools/updates.js.map +1 -1
- package/dist/tools/wiki.d.ts +68 -0
- package/dist/tools/wiki.js +413 -0
- package/dist/tools/wiki.js.map +1 -0
- package/dist/util.d.ts +2 -0
- package/dist/util.js +5 -0
- package/dist/util.js.map +1 -1
- package/dist/workspace/escape.d.ts +61 -0
- package/dist/workspace/escape.js +149 -0
- package/dist/workspace/escape.js.map +1 -0
- package/dist/workspace/extract.d.ts +22 -0
- package/dist/workspace/extract.js +308 -0
- package/dist/workspace/extract.js.map +1 -0
- package/dist/workspace/fs.d.ts +12 -0
- package/dist/workspace/fs.js +92 -23
- package/dist/workspace/fs.js.map +1 -1
- package/dist/workspace/git.d.ts +34 -1
- package/dist/workspace/git.js +328 -35
- package/dist/workspace/git.js.map +1 -1
- package/dist/workspace/media.d.ts +16 -13
- package/dist/workspace/media.js +43 -61
- package/dist/workspace/media.js.map +1 -1
- package/dist/workspace/rollback.d.ts +36 -22
- package/dist/workspace/rollback.js +178 -272
- package/dist/workspace/rollback.js.map +1 -1
- package/dist/workspace/unzip.js +4 -1
- package/dist/workspace/unzip.js.map +1 -1
- package/dist/workspace/upload.d.ts +7 -4
- package/dist/workspace/upload.js +5 -2
- package/dist/workspace/upload.js.map +1 -1
- package/dist/workspace/workspaces.d.ts +15 -19
- package/dist/workspace/workspaces.js +55 -127
- package/dist/workspace/workspaces.js.map +1 -1
- package/dist/workspace/worktrees.d.ts +2 -1
- package/dist/workspace/worktrees.js +179 -42
- package/dist/workspace/worktrees.js.map +1 -1
- package/package.json +7 -3
- package/sidecar/agent_dependency.json +4 -4
- package/sidecar/agent_support.json +26 -0
- package/sidecar/scripts/record-fixtures.py +12 -3
- package/sidecar/scripts/replay_sidecar.py +32 -0
- package/sidecar/scripts/suite_runner.py +302 -0
- package/sidecar/scripts/test.sh +12 -4
- package/sidecar/talaria_sidecar/__init__.py +6 -1
- package/sidecar/talaria_sidecar/__main__.py +4 -2
- package/sidecar/talaria_sidecar/agent_mutation.py +975 -0
- package/sidecar/talaria_sidecar/agent_services.py +1053 -0
- package/sidecar/talaria_sidecar/dependency_sync.py +85 -0
- package/sidecar/talaria_sidecar/home.py +56 -3
- package/sidecar/talaria_sidecar/methods/__init__.py +2 -2
- package/sidecar/talaria_sidecar/methods/aux.py +166 -24
- package/sidecar/talaria_sidecar/methods/chat.py +852 -135
- package/sidecar/talaria_sidecar/methods/checkpoints.py +89 -0
- package/sidecar/talaria_sidecar/methods/commands.py +294 -4
- package/sidecar/talaria_sidecar/methods/config.py +123 -4
- package/sidecar/talaria_sidecar/methods/connectors.py +343 -0
- package/sidecar/talaria_sidecar/methods/cron.py +395 -36
- package/sidecar/talaria_sidecar/methods/cron_execution.py +284 -0
- package/sidecar/talaria_sidecar/methods/gateway.py +212 -55
- package/sidecar/talaria_sidecar/methods/gateway_sessions.py +234 -0
- package/sidecar/talaria_sidecar/methods/goals.py +81 -41
- package/sidecar/talaria_sidecar/methods/kanban.py +108 -34
- package/sidecar/talaria_sidecar/methods/mcp.py +1 -1
- package/sidecar/talaria_sidecar/methods/memory.py +84 -0
- package/sidecar/talaria_sidecar/methods/oauth.py +5 -2
- package/sidecar/talaria_sidecar/methods/process.py +218 -15
- package/sidecar/talaria_sidecar/methods/profiles.py +121 -13
- package/sidecar/talaria_sidecar/methods/providers.py +217 -28
- package/sidecar/talaria_sidecar/methods/runtime.py +69 -1
- package/sidecar/talaria_sidecar/methods/skills.py +67 -4
- package/sidecar/talaria_sidecar/methods/state_db.py +316 -75
- package/sidecar/talaria_sidecar/methods/stt.py +159 -78
- package/sidecar/talaria_sidecar/methods/text.py +14 -1
- package/sidecar/talaria_sidecar/methods/toolsets.py +49 -0
- package/sidecar/talaria_sidecar/methods/usage.py +113 -14
- package/sidecar/talaria_sidecar/methods/worktree.py +26 -19
- package/sidecar/talaria_sidecar/methods/write_approval.py +181 -0
- package/sidecar/talaria_sidecar/rpc.py +45 -4
- package/sidecar/talaria_sidecar/runtime.py +98 -13
- package/sidecar/talaria_sidecar/speed.py +35 -0
- package/static/dist/FILES.txt +126 -126
- package/static/dist/assets/AppShell-cey33v9s.js +8 -0
- package/static/dist/assets/ChatPage-i8wnugr7.js +18 -0
- package/static/dist/assets/ConnectTargets-hg19553x.js +1 -0
- package/static/dist/assets/ExtensionRoute-cly4apm5.js +1 -0
- package/static/dist/assets/Field-j8uqoigz.js +9 -0
- package/static/dist/assets/HubRoute-e4bgz41j.js +2 -0
- package/static/dist/assets/Markdown-lahuichm.js +598 -0
- package/static/dist/assets/RightPanel-lbo4i0fn.js +1 -0
- package/static/dist/assets/Select-gqatm2e0.js +1 -0
- package/static/dist/assets/SessionListPanel-mfqayfjh.js +1 -0
- package/static/dist/assets/SettingsLayout-b8980u7k.js +1 -0
- package/static/dist/assets/States-e7dkgtxf.js +1 -0
- package/static/dist/assets/Toaster-bfqqy786.js +1 -0
- package/static/dist/assets/_app-n1n6pfx1.js +1 -0
- package/static/dist/assets/{_app.ext._extensionId-opyh9y0v.js → _app.ext._extensionId-buxjxav3.js} +1 -1
- package/static/dist/assets/_app.index-jt8zwiu2.js +1 -0
- package/static/dist/assets/_app.insights-cv76ml71.js +1 -0
- package/static/dist/assets/_app.kanban-h6ts53j7.js +1 -0
- package/static/dist/assets/_app.logs-dm873z90.js +1 -0
- package/static/dist/assets/_app.memory-glk5y6m8.js +1 -0
- package/static/dist/assets/_app.profiles-ka6zpstq.js +1 -0
- package/static/dist/assets/{_app.session._sessionId-bfd4h3id.js → _app.session._sessionId-g2vzghvc.js} +1 -1
- package/static/dist/assets/_app.settings-hgjdhzcd.js +1 -0
- package/static/dist/assets/_app.settings._section-jf2kmhae.js +3 -0
- package/static/dist/assets/_app.skills-cii852yq.js +1 -0
- package/static/dist/assets/_app.tasks-fp9q7atm.js +1 -0
- package/static/dist/assets/_app.todos-dw94qzue.js +1 -0
- package/static/dist/assets/_app.workspaces-inyygzze.js +1 -0
- package/static/dist/assets/{abnfDiagram-VCTEODGH-b2x1lqot.js → abnfDiagram-VCTEODGH-gjayq3ra.js} +1 -1
- package/static/dist/assets/architecture-7GRP2DOG-lp56972r.js +1 -0
- package/static/dist/assets/{architectureDiagram-5GKGNRK7-h38o5l7b.js → architectureDiagram-5GKGNRK7-nwb3xovn.js} +1 -1
- package/static/dist/assets/archive-b1j004vn.js +1 -0
- package/static/dist/assets/back-g74gkozu.js +1 -0
- package/static/dist/assets/{blockDiagram-I7D4REHJ-bqquxv2u.js → blockDiagram-I7D4REHJ-joedghi3.js} +1 -1
- package/static/dist/assets/{c4Diagram-7LVT6UL2-f3fb8w6z.js → c4Diagram-7LVT6UL2-hyrjrohe.js} +1 -1
- package/static/dist/assets/channel-es95o4y8.js +1 -0
- package/static/dist/assets/{chunk-4HAMMTFA-bzfyyzp3.js → chunk-4HAMMTFA-koouqbut.js} +1 -1
- package/static/dist/assets/{chunk-75Z2AOVW-ly99rfx5.js → chunk-75Z2AOVW-bl4bhdnt.js} +1 -1
- package/static/dist/assets/{chunk-DU6HZSFF-bg6ecfqf.js → chunk-DU6HZSFF-gpedttsp.js} +3 -3
- package/static/dist/assets/{chunk-F27PBJKO-e8k7mmqw.js → chunk-F27PBJKO-d8xxi0zi.js} +1 -1
- package/static/dist/assets/{chunk-GMAD6QVW-cmalnoaj.js → chunk-GMAD6QVW-jro0hl73.js} +1 -1
- package/static/dist/assets/{chunk-GVQU2GXP-gmif5o01.js → chunk-GVQU2GXP-djn6gbyu.js} +1 -1
- package/static/dist/assets/{chunk-IMKFNOWR-f1nwwh6u.js → chunk-IMKFNOWR-vw4p5p7o.js} +1 -1
- package/static/dist/assets/{chunk-L3NEJ4N5-oktfh5v7.js → chunk-L3NEJ4N5-n1hj77q8.js} +1 -1
- package/static/dist/assets/{chunk-OSK3NFVY-b1sdx96z.js → chunk-OSK3NFVY-oy0gwn2n.js} +1 -1
- package/static/dist/assets/{chunk-P2QGCYS3-fhu4nzxt.js → chunk-P2QGCYS3-onf1hz6c.js} +1 -1
- package/static/dist/assets/{chunk-POPQ4Y6H-em31rnef.js → chunk-POPQ4Y6H-m8sqn7cs.js} +1 -1
- package/static/dist/assets/{chunk-PWAF6VOD-bxhhyftw.js → chunk-PWAF6VOD-ek4smc8x.js} +1 -1
- package/static/dist/assets/{chunk-SHT3W25Y-fmrvwcav.js → chunk-SHT3W25Y-g9gfvefo.js} +3 -3
- package/static/dist/assets/{chunk-SVP7TREG-lymukl2j.js → chunk-SVP7TREG-f9nfv2cu.js} +1 -1
- package/static/dist/assets/{chunk-TICWLB2K-lmza6k23.js → chunk-TICWLB2K-bnk3m1mq.js} +1 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-kmihoqxh.js +1 -0
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-kmihoqxh.js +1 -0
- package/static/dist/assets/copied-bli9tbcx.js +1 -0
- package/static/dist/assets/{copy-fw5b1pc6.js → copy-jamtd1pf.js} +1 -1
- package/static/dist/assets/{cynefin-OW5HDTMX-czlhbyhs.js → cynefin-OW5HDTMX-f8xfdd3f.js} +1 -1
- package/static/dist/assets/{cynefinDiagram-5FMLGOSQ-gq7mvswb.js → cynefinDiagram-5FMLGOSQ-n9lb99h9.js} +1 -1
- package/static/dist/assets/{dagre-GXQ25YYZ-cqdbf7dr.js → dagre-GXQ25YYZ-dgailddi.js} +4 -4
- package/static/dist/assets/{diagram-S7CK7UJ4-o6arxa58.js → diagram-S7CK7UJ4-m6aeoe7c.js} +1 -1
- package/static/dist/assets/{diagram-UQ7AKVKN-nhnd68tz.js → diagram-UQ7AKVKN-jall3j0x.js} +1 -1
- package/static/dist/assets/{diagram-VSXAHHWV-dk2sclzn.js → diagram-VSXAHHWV-hbawi7hn.js} +1 -1
- package/static/dist/assets/{diagram-VX7I27RA-n3k5nyx3.js → diagram-VX7I27RA-hendl2tt.js} +1 -1
- package/static/dist/assets/{diagram-Z3DM3KII-m6q9cwdh.js → diagram-Z3DM3KII-igwc35p3.js} +1 -1
- package/static/dist/assets/{ebnfDiagram-PWID7BFC-lsa5641p.js → ebnfDiagram-PWID7BFC-c64knz08.js} +1 -1
- package/static/dist/assets/{erDiagram-RLTQ6QDP-fo2ckbe6.js → erDiagram-RLTQ6QDP-brdu9lcm.js} +1 -1
- package/static/dist/assets/eventmodeling-NTZA5JFV-njk1j8wl.js +1 -0
- package/static/dist/assets/flowDiagram-HODETNUW-nma6f0ga.js +1 -0
- package/static/dist/assets/folder-plus-lvt9kudb.js +1 -0
- package/static/dist/assets/{ganttDiagram-EL5Y4UJY-nzqz6x9g.js → ganttDiagram-EL5Y4UJY-ma6jxj5i.js} +1 -1
- package/static/dist/assets/{gitGraph-4MIJSDKK-gukvcxe6.js → gitGraph-4MIJSDKK-naa9w6xa.js} +1 -1
- package/static/dist/assets/{gitGraphDiagram-WWUBYQGX-lqhdp8f0.js → gitGraphDiagram-WWUBYQGX-hzltvsod.js} +1 -1
- package/static/dist/assets/{highlighted-body-KPVGNVTW-igw6cp39.js → highlighted-body-KPVGNVTW-ghoavj8d.js} +1 -1
- package/static/dist/assets/host-hzm8n85n.js +1 -0
- package/static/dist/assets/index-drdcaqeq.css +2 -0
- package/static/dist/assets/index-jzm844he.js +11 -0
- package/static/dist/assets/{info-A6RAGUB7-gvu7a93l.js → info-A6RAGUB7-mn2ut5ko.js} +1 -1
- package/static/dist/assets/{infoDiagram-27XIBGKW-m8t8g6w1.js → infoDiagram-27XIBGKW-h6kuqvsb.js} +1 -1
- package/static/dist/assets/{ishikawaDiagram-5VMMS53U-l07vkbgj.js → ishikawaDiagram-5VMMS53U-e7bnwq7h.js} +1 -1
- package/static/dist/assets/{journeyDiagram-3NMN7TZE-hybkgj8l.js → journeyDiagram-3NMN7TZE-etd1bi6p.js} +1 -1
- package/static/dist/assets/{kanban-definition-UXKFOSKX-by13uvtn.js → kanban-definition-UXKFOSKX-emb1g9dz.js} +4 -4
- package/static/dist/assets/lazyRouteComponent-o816ytzl.js +1 -0
- package/static/dist/assets/{line-osxq6fq7.js → line-h0ojzsvs.js} +1 -1
- package/static/dist/assets/link-k01ryaf9.js +1 -0
- package/static/dist/assets/login-bsae49ew.js +1 -0
- package/static/dist/assets/mermaid-HWGCJPDP-ihl34s74.js +1 -0
- package/static/dist/assets/{mermaid-parser.core-i91oxmou.js → mermaid-parser.core-bnre27u8.js} +3 -3
- package/static/dist/assets/{mindmap-definition-YA3MSWOX-m82mx8ww.js → mindmap-definition-YA3MSWOX-o1vathns.js} +1 -1
- package/static/dist/assets/onboarding-c65tysya.js +1 -0
- package/static/dist/assets/onboarding_model_label-gpn28uix.js +1 -0
- package/static/dist/assets/{packet-AYTQ26CC-nbtgge2o.js → packet-AYTQ26CC-hatq7m2e.js} +1 -1
- package/static/dist/assets/pcmTap.worklet-74EKjWAZ.js +1 -0
- package/static/dist/assets/{pegDiagram-XKGWAZYB-f1zxzga1.js → pegDiagram-XKGWAZYB-gwisz8jv.js} +1 -1
- package/static/dist/assets/{pie-WAS4IAKB-of8vuhxs.js → pie-WAS4IAKB-fpftf0mk.js} +1 -1
- package/static/dist/assets/{pieDiagram-E7YTZNPT-o7y8ftio.js → pieDiagram-E7YTZNPT-khm1o9a6.js} +1 -1
- package/static/dist/assets/{quadrantDiagram-AXDQQJYC-iqiwia1t.js → quadrantDiagram-AXDQQJYC-owqc4uqn.js} +1 -1
- package/static/dist/assets/{radar-RG4KPBEZ-delnsy2v.js → radar-RG4KPBEZ-cntfwjpq.js} +1 -1
- package/static/dist/assets/{railroad-74A4TZTK-nspnyq9u.js → railroad-74A4TZTK-a7t5eibp.js} +1 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-ol8cdktf.js +1 -0
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-i8vzd429.js +1 -0
- package/static/dist/assets/railroad-peg-WCYAUIDC-nw3ulewz.js +1 -0
- package/static/dist/assets/{railroadDiagram-O6MQD6OU-z41tqx5z.js → railroadDiagram-O6MQD6OU-etuh0qa0.js} +1 -1
- package/static/dist/assets/{refresh-cw-nt1dtsx4.js → refresh-cw-mqbkv2a3.js} +1 -1
- package/static/dist/assets/refresh-l29ljp76.js +1 -0
- package/static/dist/assets/{requirementDiagram-BXWQKSXE-bdvif194.js → requirementDiagram-BXWQKSXE-oq2ulk22.js} +1 -1
- package/static/dist/assets/{sankeyDiagram-P5KCCOFB-h73e0rol.js → sankeyDiagram-P5KCCOFB-iqc02emv.js} +1 -1
- package/static/dist/assets/saved-ndd4t2xb.js +1 -0
- package/static/dist/assets/{sequenceDiagram-WJ2MYXX4-iv95mb1z.js → sequenceDiagram-WJ2MYXX4-i0v116q0.js} +2 -2
- package/static/dist/assets/settings_section_extensions_title-jhfo6o8z.js +1 -0
- package/static/dist/assets/share._token-c1ri0hy1.js +2 -0
- package/static/dist/assets/sliders-horizontal-j3jjt9tv.js +1 -0
- package/static/dist/assets/{stateDiagram-D77RDMKH-k417ixmf.js → stateDiagram-D77RDMKH-dnpt1ato.js} +1 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-bxjacpk6.js +1 -0
- package/static/dist/assets/{swimlanes-42K2YHIH-esola70w.js → swimlanes-42K2YHIH-loqbdazb.js} +1 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-id62p9hz.js +8 -0
- package/static/dist/assets/{timeline-definition-24CTP7MA-getrz2y8.js → timeline-definition-24CTP7MA-ol2hnvma.js} +1 -1
- package/static/dist/assets/toast-i3h34v6o.js +64 -0
- package/static/dist/assets/{treeView-Q6P3EWNA-hc7ap1q7.js → treeView-Q6P3EWNA-idrj6iox.js} +1 -1
- package/static/dist/assets/{treemap-WGGIJYW6-b7k1syy5.js → treemap-WGGIJYW6-lzr49vv5.js} +1 -1
- package/static/dist/assets/untitled-oaoya4qj.js +1 -0
- package/static/dist/assets/useForm-nfaxgmsk.js +1 -0
- package/static/dist/assets/{useParams-lhg566ew.js → useParams-gjc70qru.js} +1 -1
- package/static/dist/assets/{useSearch-lbrh6ejn.js → useSearch-e6ae539u.js} +1 -1
- package/static/dist/assets/{vennDiagram-4TSXK5OY-n6pcy5qb.js → vennDiagram-4TSXK5OY-bvwr9o2z.js} +1 -1
- package/static/dist/assets/{wardley-WFR3VGLG-lpa18vz1.js → wardley-WFR3VGLG-31ui8tma.js} +1 -1
- package/static/dist/assets/{wardleyDiagram-VM6X3IG4-kpclwwg7.js → wardleyDiagram-VM6X3IG4-k5wqtx4b.js} +1 -1
- package/static/dist/assets/{xychartDiagram-S5SC5T6Z-paa2n8y0.js → xychartDiagram-S5SC5T6Z-aqbgvujg.js} +1 -1
- package/static/dist/index.html +1 -1
- package/static/dist/sw.js +1 -1
- package/static/dist/assets/AppShell-fb2td9zi.js +0 -1
- package/static/dist/assets/ChatPage-cj96kiy9.js +0 -25
- package/static/dist/assets/Dialog-kxcg7ard.js +0 -1
- package/static/dist/assets/ExtensionRoute-jf7h0754.js +0 -1
- package/static/dist/assets/HubRoute-gmanpd5y.js +0 -2
- package/static/dist/assets/Markdown-mdwlvj3w.js +0 -598
- package/static/dist/assets/RightPanel-ftvrjlcp.js +0 -1
- package/static/dist/assets/Select-bilaypej.js +0 -1
- package/static/dist/assets/SessionListPanel-og8n36qs.js +0 -1
- package/static/dist/assets/SettingsLayout-jonjefmj.js +0 -1
- package/static/dist/assets/States-nmejrwrm.js +0 -1
- package/static/dist/assets/Toaster-nnl8zkt9.js +0 -1
- package/static/dist/assets/_app-gdidzd94.js +0 -1
- package/static/dist/assets/_app.index-hbarzbjx.js +0 -1
- package/static/dist/assets/_app.insights-luywlarz.js +0 -1
- package/static/dist/assets/_app.kanban-kincnbr8.js +0 -1
- package/static/dist/assets/_app.logs-oi2gr3gs.js +0 -1
- package/static/dist/assets/_app.memory-b6jfivt6.js +0 -1
- package/static/dist/assets/_app.profiles-lpvixmqp.js +0 -1
- package/static/dist/assets/_app.settings-vowx3iq0.js +0 -1
- package/static/dist/assets/_app.settings._section-cnntg1tu.js +0 -3
- package/static/dist/assets/_app.skills-fb57lpau.js +0 -1
- package/static/dist/assets/_app.tasks-eszpx1q7.js +0 -2
- package/static/dist/assets/_app.todos-nr05ac6w.js +0 -1
- package/static/dist/assets/_app.workspaces-d2luomu6.js +0 -1
- package/static/dist/assets/architecture-7GRP2DOG-hd0o7bde.js +0 -1
- package/static/dist/assets/back-bemaer09.js +0 -1
- package/static/dist/assets/cancel-drd0g6d9.js +0 -1
- package/static/dist/assets/channel-cpdgf867.js +0 -1
- package/static/dist/assets/classDiagram-ZZMXUADV-ko09sguk.js +0 -1
- package/static/dist/assets/classDiagram-v2-VYDZK3BY-ko09sguk.js +0 -1
- package/static/dist/assets/copied-ima3pysb.js +0 -1
- package/static/dist/assets/endpoints-d33siokx.js +0 -64
- package/static/dist/assets/eventmodeling-NTZA5JFV-emctlo64.js +0 -1
- package/static/dist/assets/flowDiagram-HODETNUW-bfi3moqa.js +0 -1
- package/static/dist/assets/index-cxq58xb1.js +0 -11
- package/static/dist/assets/index-hgtx08n5.css +0 -2
- package/static/dist/assets/lazyRouteComponent-af0lvgjx.js +0 -1
- package/static/dist/assets/link-jyxicdhg.js +0 -1
- package/static/dist/assets/login-ec21t39x.js +0 -1
- package/static/dist/assets/mermaid-HWGCJPDP-gfl8z3ep.js +0 -1
- package/static/dist/assets/onboarding-btnltvyz.js +0 -1
- package/static/dist/assets/onboarding_model_label-dp7xffoh.js +0 -1
- package/static/dist/assets/railroad-abnf-HS5TGJTU-nst1qxyn.js +0 -1
- package/static/dist/assets/railroad-ebnf-LZEXJU2U-ci37x8qy.js +0 -1
- package/static/dist/assets/railroad-peg-WCYAUIDC-aimkk07z.js +0 -1
- package/static/dist/assets/refresh-b4uams1i.js +0 -1
- package/static/dist/assets/saved-kg52csy7.js +0 -1
- package/static/dist/assets/settings_section_extensions_title-ej0iapxe.js +0 -1
- package/static/dist/assets/share._token-f97e94r0.js +0 -2
- package/static/dist/assets/sliders-horizontal-fj18it47.js +0 -1
- package/static/dist/assets/sse-fwpqtzbg.js +0 -1
- package/static/dist/assets/stateDiagram-v2-MP3YSRHH-hwn4apct.js +0 -1
- package/static/dist/assets/swimlanesDiagram-VR7AAH4N-d1h97oyg.js +0 -8
- package/static/dist/assets/todoStore-eginf9h4.js +0 -1
- package/static/dist/assets/tts-lxdxnmjd.js +0 -1
- package/static/dist/assets/untitled-ovpfthg4.js +0 -1
- package/static/dist/assets/useForm-bcblv1rx.js +0 -1
- package/static/dist/assets/useLocale-fi5jb8ma.js +0 -1
package/dist/api/raw-routes.js
CHANGED
|
@@ -3,38 +3,52 @@
|
|
|
3
3
|
* ZIPs, transcript exports, and multipart uploads. Each mirrors its Python
|
|
4
4
|
* handler and reuses the anchored file helpers.
|
|
5
5
|
*/
|
|
6
|
-
import { closeSync, createReadStream, existsSync, readdirSync, statSync, realpathSync } from 'node:fs';
|
|
6
|
+
import { closeSync, createReadStream, existsSync, mkdirSync, readdirSync, statSync, realpathSync } from 'node:fs';
|
|
7
7
|
import { Readable } from 'node:stream';
|
|
8
8
|
import { basename, join, relative } from 'node:path';
|
|
9
9
|
import { HttpError } from './router.js';
|
|
10
|
-
import { fileOpsSession } from './sessions-router.js';
|
|
10
|
+
import { escapeRequest, fileError, fileOpsSession } from './sessions-router.js';
|
|
11
11
|
import { HttpFailure } from '../sessions/service.js';
|
|
12
12
|
import { SessionNotFound } from '../sessions/store.js';
|
|
13
|
-
import { openAnchoredFd, safeResolve } from '../workspace/fs.js';
|
|
13
|
+
import { FileExistsError, makeAnchoredDir, openAnchoredCreateFd, openAnchoredFd, rmtreeAnchored, safeResolve, safeResolveWs, unlinkAnchored } from '../workspace/fs.js';
|
|
14
14
|
import { isWithin, resolvePathLikePython } from '../workspace/paths.js';
|
|
15
|
-
import {
|
|
15
|
+
import { isLoopback } from '../http/origin.js';
|
|
16
|
+
import { truthy } from '../config.js';
|
|
17
|
+
import { AUDIO_VIDEO_PDF_TYPES, contentDispositionValue, INLINE_IMAGE_TYPES, mediaAnchorRoot, mediaTarget, mimeFor, serveFileBytes, serveInlineHtmlPreview } from '../workspace/media.js';
|
|
16
18
|
import { PREVIEW_PREFIX, previewGrantRoot } from '../workspace/preview.js';
|
|
17
19
|
import { REMOTE_WORKSPACE_UNSUPPORTED_CODE, REMOTE_WORKSPACE_UNSUPPORTED_MESSAGE } from '../workspace/workspaces.js';
|
|
20
|
+
import { WORKSPACE_BUSY_MESSAGE } from '../workspace/git.js';
|
|
18
21
|
import { ZipWriter } from '../workspace/zip.js';
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
22
|
+
import { anchoredAt } from '../workspace/escape.js';
|
|
23
|
+
import { guessMime, parseMultipart, sanitizeUploadName, uploadDestination, UploadConflict, UploadRejected } from '../workspace/upload.js';
|
|
24
|
+
import { ArchiveRejected, CorruptArchive, extractArchive, isArchiveName } from '../workspace/extract.js';
|
|
25
|
+
import { writeFully } from '../fs/atomic.js';
|
|
26
|
+
import { pythonPrettyJson, renderSessionHtml, renderSessionMarkdown } from '../sessions/export.js';
|
|
21
27
|
import { handleCspReport, handleTranscribe, handleTts } from './tools-raw.js';
|
|
22
28
|
import { handleOidcCallback, handleOidcStart } from './auth-raw.js';
|
|
29
|
+
import { handleTranscribeStream } from './transcribe-stream.js';
|
|
23
30
|
const SANDBOX_CSP = 'sandbox allow-scripts allow-popups allow-popups-to-escape-sandbox';
|
|
24
31
|
const DANGEROUS_TYPES = new Set(['text/html', 'application/xhtml+xml', 'image/svg+xml']);
|
|
25
32
|
export const RAW_GET_ROUTES = {
|
|
26
33
|
'/api/auth/oidc/start': handleOidcStart,
|
|
27
34
|
'/api/auth/oidc/callback': handleOidcCallback,
|
|
28
35
|
'/api/file/raw': handleFileRaw,
|
|
36
|
+
'/api/escape/file/raw': handleEscapeFileRaw,
|
|
29
37
|
'/api/media': handleMedia,
|
|
30
38
|
'/api/folder/download': handleFolderDownload,
|
|
31
39
|
'/api/session/export': handleSessionExport,
|
|
40
|
+
'/api/transcribe/stream': handleTranscribeStream,
|
|
41
|
+
'/api/approval/inject_test': testHook(handleApprovalInject),
|
|
42
|
+
'/api/clarify/inject_test': testHook(handleClarifyInject),
|
|
32
43
|
};
|
|
33
44
|
export const RAW_POST_ROUTES = {
|
|
34
45
|
'/api/upload': handleUpload,
|
|
46
|
+
'/api/upload/extract': handleUploadExtract,
|
|
47
|
+
'/api/workspace/upload': handleWorkspaceUpload,
|
|
35
48
|
'/api/transcribe': handleTranscribe,
|
|
36
49
|
'/api/tts': handleTts,
|
|
37
50
|
'/api/csp-report': handleCspReport,
|
|
51
|
+
'/api/process-complete-ack': handleProcessCompleteAck,
|
|
38
52
|
};
|
|
39
53
|
/** Run a raw handler, translating thrown `HttpError`s into the JSON error body. */
|
|
40
54
|
export async function runRaw(ctx, handler) {
|
|
@@ -45,20 +59,54 @@ export async function runRaw(ctx, handler) {
|
|
|
45
59
|
if (ctx.isFinished)
|
|
46
60
|
return;
|
|
47
61
|
if (error instanceof HttpError) {
|
|
48
|
-
ctx.json({ error: error.message, ...error.data }, { status: error.status });
|
|
62
|
+
await ctx.json({ error: error.message, ...error.data }, { status: error.status });
|
|
49
63
|
return;
|
|
50
64
|
}
|
|
51
65
|
if (error instanceof HttpFailure) {
|
|
52
|
-
ctx.json({ error: error.message, ...error.extra }, { status: error.status });
|
|
66
|
+
await ctx.json({ error: error.message, ...error.extra }, { status: error.status });
|
|
53
67
|
return;
|
|
54
68
|
}
|
|
55
69
|
if (error instanceof SessionNotFound) {
|
|
56
|
-
ctx.json({ error: 'Session not found' }, { status: 404 });
|
|
70
|
+
await ctx.json({ error: 'Session not found' }, { status: 404 });
|
|
57
71
|
return;
|
|
58
72
|
}
|
|
59
73
|
throw error;
|
|
60
74
|
}
|
|
61
75
|
}
|
|
76
|
+
/** Retired by the `process_complete` -> `bg_task_complete` rename: always 410, naming the replacement. */
|
|
77
|
+
async function handleProcessCompleteAck(ctx) {
|
|
78
|
+
await ctx.json({ error: 'gone: /api/process-complete-ack was replaced by /api/bg-task-complete-ack as part of the process_complete -> bg_task_complete event rename', replaced_by: '/api/bg-task-complete-ack' }, { status: 410, headers: { 'X-Replaced-By': '/api/bg-task-complete-ack' } });
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Automated-test hooks: served only to a loopback peer while `HERMES_WEBUI_TEST_HOOKS=1` is set (loopback alone means
|
|
82
|
+
* nothing behind a same-host reverse proxy); anything else gets the plain 404.
|
|
83
|
+
*/
|
|
84
|
+
function testHook(handler) {
|
|
85
|
+
return async (ctx) => {
|
|
86
|
+
if (!truthy(ctx.deps.config.env.HERMES_WEBUI_TEST_HOOKS) || !isLoopback(ctx.peer)) {
|
|
87
|
+
await ctx.json({ error: 'not found' }, { status: 404 });
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
return handler(ctx);
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Queue a fake approval; `_injected` entries are answered locally, since no Agent is parked on them. */
|
|
94
|
+
async function handleApprovalInject(ctx) {
|
|
95
|
+
const sid = ctx.query.get('session_id') ?? '';
|
|
96
|
+
if (!sid)
|
|
97
|
+
throw new HttpError(400, 'session_id required');
|
|
98
|
+
const key = ctx.query.get('pattern_key') || 'test_pattern';
|
|
99
|
+
ctx.deps.pending.submitApproval(sid, { command: ctx.query.get('command') || 'rm -rf /tmp/test', pattern_key: key, pattern_keys: [key], description: 'test pattern', session_id: sid, _injected: true });
|
|
100
|
+
await ctx.json({ ok: true, session_id: sid });
|
|
101
|
+
}
|
|
102
|
+
/** Queue a fake clarify prompt (repeated `choices`); answered locally like an injected approval. */
|
|
103
|
+
async function handleClarifyInject(ctx) {
|
|
104
|
+
const sid = ctx.query.get('session_id') ?? '';
|
|
105
|
+
if (!sid)
|
|
106
|
+
throw new HttpError(400, 'session_id required');
|
|
107
|
+
ctx.deps.pending.submitClarify(sid, { question: ctx.query.get('question') || 'Which option?', choices_offered: ctx.query.getAll('choices').filter(Boolean), session_id: sid, kind: 'clarify', _injected: true });
|
|
108
|
+
await ctx.json({ ok: true, session_id: sid });
|
|
109
|
+
}
|
|
62
110
|
function fileRawTarget(ctx, workspace, sid, rel) {
|
|
63
111
|
try {
|
|
64
112
|
const target = safeResolve(workspace, rel);
|
|
@@ -75,38 +123,54 @@ function fileRawTarget(ctx, workspace, sid, rel) {
|
|
|
75
123
|
catch { /* none */ }
|
|
76
124
|
return null;
|
|
77
125
|
}
|
|
78
|
-
function handleFileRaw(ctx) {
|
|
126
|
+
async function handleFileRaw(ctx) {
|
|
79
127
|
const sid = ctx.query.get('session_id') ?? '';
|
|
80
128
|
if (!sid)
|
|
81
129
|
throw new HttpError(400, 'session_id is required');
|
|
82
|
-
const s = fileOpsSession(ctx, sid);
|
|
130
|
+
const s = (await fileOpsSession(ctx, sid));
|
|
83
131
|
const rel = ctx.query.get('path') ?? '';
|
|
84
132
|
if (rel.includes('\0'))
|
|
85
133
|
throw new HttpError(400, 'invalid path');
|
|
86
|
-
const forceDownload = ctx.query.get('download') === '1';
|
|
87
134
|
const resolved = fileRawTarget(ctx, s.workspace, sid, rel);
|
|
88
135
|
if (!resolved) {
|
|
89
|
-
ctx.json({ error: 'not found' }, { status: 404 });
|
|
136
|
+
await ctx.json({ error: 'not found' }, { status: 404 });
|
|
90
137
|
return;
|
|
91
138
|
}
|
|
92
|
-
|
|
139
|
+
await serveRawFile(ctx, resolved[0], resolved[1]);
|
|
140
|
+
}
|
|
141
|
+
/** Python `_handle_escape_file_raw`: `/api/file/raw` for a path under an escape grant, anchored at the grant root. */
|
|
142
|
+
async function handleEscapeFileRaw(ctx) {
|
|
143
|
+
const req = (await escapeRequest(ctx, ctx.query.get('session_id') ?? '', ctx.query.get('token') ?? '', ctx.query.get('path') ?? ''));
|
|
144
|
+
let target;
|
|
145
|
+
try {
|
|
146
|
+
target = ctx.deps.escapeGrants.rawTarget(req);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
throw fileError(error, 404);
|
|
150
|
+
}
|
|
151
|
+
// The anchored open and fstat in `serveRawFile` answer a missing or non-file target with 404 through the pinned root.
|
|
152
|
+
await anchoredAt(req, async () => { (await serveRawFile(ctx, req.externalRoot, target)); });
|
|
153
|
+
}
|
|
154
|
+
/** The `/api/file/raw` response: MIME, attachment for dangerous types unless an inline HTML preview, sandbox CSP, no-store. */
|
|
155
|
+
async function serveRawFile(ctx, anchorRoot, target) {
|
|
156
|
+
const forceDownload = ctx.query.get('download') === '1';
|
|
93
157
|
const mime = mimeFor(target);
|
|
94
158
|
const inlinePreview = ctx.query.get('inline') === '1';
|
|
95
159
|
const htmlInlineOk = inlinePreview && mime === 'text/html';
|
|
96
160
|
const disposition = forceDownload || (DANGEROUS_TYPES.has(mime) && !htmlInlineOk) ? 'attachment' : 'inline';
|
|
97
161
|
const csp = inlinePreview && !forceDownload && disposition === 'inline' ? SANDBOX_CSP : null;
|
|
98
162
|
if (htmlInlineOk) {
|
|
99
|
-
serveInlineHtmlPreview(ctx, target, 'no-store', SANDBOX_CSP, anchorRoot);
|
|
163
|
+
await serveInlineHtmlPreview(ctx, target, 'no-store', SANDBOX_CSP, anchorRoot);
|
|
100
164
|
return;
|
|
101
165
|
}
|
|
102
|
-
serveFileBytes(ctx, target, { mime, disposition, cacheControl: 'no-store', csp, anchorRoot });
|
|
166
|
+
await serveFileBytes(ctx, target, { mime, disposition, cacheControl: 'no-store', csp, anchorRoot });
|
|
103
167
|
}
|
|
104
168
|
/**
|
|
105
169
|
* `/workspace-preview/<grant>/<path>` (TAL-566): the HTML preview frame and its relative assets, authorized by the
|
|
106
170
|
* signed grant rather than a cookie. Every response carries the sandbox CSP and no CORS header, so the page's scripts
|
|
107
171
|
* can run and load assets but cannot read workspace files.
|
|
108
172
|
*/
|
|
109
|
-
export function handleWorkspacePreview(ctx) {
|
|
173
|
+
export async function handleWorkspacePreview(ctx) {
|
|
110
174
|
const rest = ctx.path.slice(PREVIEW_PREFIX.length);
|
|
111
175
|
const slash = rest.indexOf('/');
|
|
112
176
|
const root = slash > 0 ? previewGrantRoot(ctx.deps.auth.signingKey(), rest.slice(0, slash)) : null;
|
|
@@ -121,16 +185,16 @@ export function handleWorkspacePreview(ctx) {
|
|
|
121
185
|
catch { /* malformed escape or outside the root */ }
|
|
122
186
|
}
|
|
123
187
|
if (!root || !target) {
|
|
124
|
-
ctx.json({ error: 'not found' }, { status: 404 });
|
|
188
|
+
await ctx.json({ error: 'not found' }, { status: 404 });
|
|
125
189
|
return;
|
|
126
190
|
}
|
|
127
191
|
const mime = mimeFor(target);
|
|
128
192
|
if (mime === 'text/html')
|
|
129
|
-
serveInlineHtmlPreview(ctx, target, 'no-store', SANDBOX_CSP, root);
|
|
193
|
+
(await serveInlineHtmlPreview(ctx, target, 'no-store', SANDBOX_CSP, root));
|
|
130
194
|
else
|
|
131
|
-
serveFileBytes(ctx, target, { mime, disposition: 'inline', cacheControl: 'no-store', csp: SANDBOX_CSP, anchorRoot: root });
|
|
195
|
+
(await serveFileBytes(ctx, target, { mime, disposition: 'inline', cacheControl: 'no-store', csp: SANDBOX_CSP, anchorRoot: root }));
|
|
132
196
|
}
|
|
133
|
-
function handleMedia(ctx) {
|
|
197
|
+
async function handleMedia(ctx) {
|
|
134
198
|
const { deps } = ctx;
|
|
135
199
|
const rawPath = (ctx.query.get('path') ?? '').trim();
|
|
136
200
|
if (!rawPath)
|
|
@@ -140,7 +204,7 @@ function handleMedia(ctx) {
|
|
|
140
204
|
let localAllowed;
|
|
141
205
|
if (sessionId) {
|
|
142
206
|
try {
|
|
143
|
-
mediaSession = deps.sessionStore.get(sessionId);
|
|
207
|
+
mediaSession = (await deps.sessionStore.get(sessionId));
|
|
144
208
|
}
|
|
145
209
|
catch {
|
|
146
210
|
throw new HttpError(404, 'Session not found');
|
|
@@ -150,7 +214,7 @@ function handleMedia(ctx) {
|
|
|
150
214
|
else
|
|
151
215
|
localAllowed = deps.workspaces.profileSupportsLocalIo(null);
|
|
152
216
|
if (!localAllowed) {
|
|
153
|
-
ctx.json({ error: REMOTE_WORKSPACE_UNSUPPORTED_CODE, message: REMOTE_WORKSPACE_UNSUPPORTED_MESSAGE }, { status: 400 });
|
|
217
|
+
await ctx.json({ error: REMOTE_WORKSPACE_UNSUPPORTED_CODE, message: REMOTE_WORKSPACE_UNSUPPORTED_MESSAGE }, { status: 400 });
|
|
154
218
|
return;
|
|
155
219
|
}
|
|
156
220
|
let target;
|
|
@@ -160,7 +224,7 @@ function handleMedia(ctx) {
|
|
|
160
224
|
catch {
|
|
161
225
|
throw new HttpError(400, 'Invalid path');
|
|
162
226
|
}
|
|
163
|
-
const anchorRoot = mediaAnchorRoot(target, mediaSession, deps.mediaAccess);
|
|
227
|
+
const anchorRoot = (await mediaAnchorRoot(target, mediaSession, deps.mediaAccess));
|
|
164
228
|
if (!anchorRoot)
|
|
165
229
|
throw new HttpError(403, 'Path not in allowed location');
|
|
166
230
|
const mime = mimeFor(target);
|
|
@@ -169,24 +233,8 @@ function handleMedia(ctx) {
|
|
|
169
233
|
const inlinePreviewTypes = new Set([...INLINE_IMAGE_TYPES, ...AUDIO_VIDEO_PDF_TYPES]);
|
|
170
234
|
const disposition = mime !== 'image/svg+xml' && (INLINE_IMAGE_TYPES.has(mime) || (inlinePreview && inlinePreviewTypes.has(mime)) || htmlInlineOk) ? 'inline' : 'attachment';
|
|
171
235
|
const csp = htmlInlineOk ? 'sandbox allow-scripts' : null;
|
|
172
|
-
const snapDigest = (ctx.query.get('snap') ?? '').trim().toLowerCase();
|
|
173
|
-
if (snapDigest) {
|
|
174
|
-
const snapDir = resolvePathLikePython(deps.mediaPolicy.snapshotDir());
|
|
175
|
-
if (isValidDigest(snapDigest)) {
|
|
176
|
-
let snapshotFile = snapshotPathForDigest(snapDir, snapDigest);
|
|
177
|
-
if (snapshotFile && !snapshotServableForPath(snapDir, snapDigest, target))
|
|
178
|
-
snapshotFile = null;
|
|
179
|
-
if (!snapshotFile) {
|
|
180
|
-
ctx.json({ error: 'snapshot unavailable' }, { status: 410 });
|
|
181
|
-
return;
|
|
182
|
-
}
|
|
183
|
-
// Same inode rule as live media: a `.snap` replaced by a hard link to a state file must not be served as the snapshot.
|
|
184
|
-
serveFileBytes(ctx, snapshotFile, { mime, disposition, cacheControl: 'private, max-age=31536000, immutable', csp, downloadName: basename(target), anchorRoot: snapDir, denyHardLinks: true });
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
236
|
// The pathname policy ran before the open; the hard-link rule is re-applied to the inode actually opened.
|
|
189
|
-
serveFileBytes(ctx, target, { mime, disposition, cacheControl: mime === 'text/html' ? 'no-store' : 'private, no-cache', csp, anchorRoot, denyHardLinks: true });
|
|
237
|
+
await serveFileBytes(ctx, target, { mime, disposition, cacheControl: mime === 'text/html' ? 'no-store' : 'private, no-cache', csp, anchorRoot, denyHardLinks: true });
|
|
190
238
|
}
|
|
191
239
|
/** Python `_folder_zip_limits`: `HERMES_WEBUI_FOLDER_ZIP_MAX_MB` / `_MAX_FILES` are honoured as given (ZIP64 covers large archives). */
|
|
192
240
|
export function folderZipMaxBytes(env) {
|
|
@@ -265,7 +313,7 @@ async function handleFolderDownload(ctx) {
|
|
|
265
313
|
const sid = ctx.query.get('session_id') ?? '';
|
|
266
314
|
if (!sid)
|
|
267
315
|
throw new HttpError(400, 'session_id is required');
|
|
268
|
-
const s = fileOpsSession(ctx, sid);
|
|
316
|
+
const s = (await fileOpsSession(ctx, sid));
|
|
269
317
|
const rel = ctx.query.get('path') ?? '';
|
|
270
318
|
let target;
|
|
271
319
|
try {
|
|
@@ -275,7 +323,7 @@ async function handleFolderDownload(ctx) {
|
|
|
275
323
|
throw new HttpError(400, 'invalid path');
|
|
276
324
|
}
|
|
277
325
|
if (!existsSync(target)) {
|
|
278
|
-
ctx.json({ error: 'not found' }, { status: 404 });
|
|
326
|
+
await ctx.json({ error: 'not found' }, { status: 404 });
|
|
279
327
|
return;
|
|
280
328
|
}
|
|
281
329
|
if (!statSync(target).isDirectory())
|
|
@@ -285,11 +333,11 @@ async function handleFolderDownload(ctx) {
|
|
|
285
333
|
const maxFiles = folderZipMaxFiles(ctx.deps.config.env);
|
|
286
334
|
const { files, limit } = collectFolder(target, workspaceRoot, maxBytes, maxFiles);
|
|
287
335
|
if (limit === 'max_files') {
|
|
288
|
-
ctx.json({ error: 'too many files', limit: maxFiles, configure: 'HERMES_WEBUI_FOLDER_ZIP_MAX_FILES' }, { status: 413 });
|
|
336
|
+
await ctx.json({ error: 'too many files', limit: maxFiles, configure: 'HERMES_WEBUI_FOLDER_ZIP_MAX_FILES' }, { status: 413 });
|
|
289
337
|
return;
|
|
290
338
|
}
|
|
291
339
|
if (limit === 'max_bytes') {
|
|
292
|
-
ctx.json({ error: 'folder too large', limit_bytes: maxBytes, configure: 'HERMES_WEBUI_FOLDER_ZIP_MAX_MB' }, { status: 413 });
|
|
340
|
+
await ctx.json({ error: 'folder too large', limit_bytes: maxBytes, configure: 'HERMES_WEBUI_FOLDER_ZIP_MAX_MB' }, { status: 413 });
|
|
293
341
|
return;
|
|
294
342
|
}
|
|
295
343
|
const zipName = `${basename(target) || 'workspace'}.zip`;
|
|
@@ -329,13 +377,13 @@ async function handleFolderDownload(ctx) {
|
|
|
329
377
|
ctx.res.end();
|
|
330
378
|
}
|
|
331
379
|
}
|
|
332
|
-
function handleSessionExport(ctx) {
|
|
380
|
+
async function handleSessionExport(ctx) {
|
|
333
381
|
const sid = ctx.query.get('session_id') ?? '';
|
|
334
382
|
if (!sid)
|
|
335
383
|
throw new HttpError(400, 'session_id is required');
|
|
336
384
|
let session;
|
|
337
385
|
try {
|
|
338
|
-
session = ctx.deps.sessionStore.get(sid);
|
|
386
|
+
session = (await ctx.deps.sessionStore.get(sid));
|
|
339
387
|
}
|
|
340
388
|
catch {
|
|
341
389
|
throw new HttpError(404, 'Session not found');
|
|
@@ -366,20 +414,26 @@ function handleSessionExport(ctx) {
|
|
|
366
414
|
contentType = 'text/html; charset=utf-8';
|
|
367
415
|
ext = 'html';
|
|
368
416
|
}
|
|
417
|
+
else if (fmt === 'markdown') {
|
|
418
|
+
payload = renderSessionMarkdown(safe);
|
|
419
|
+
contentType = 'text/markdown; charset=utf-8';
|
|
420
|
+
ext = 'md';
|
|
421
|
+
}
|
|
369
422
|
else {
|
|
370
423
|
payload = pythonPrettyJson(safe);
|
|
371
424
|
contentType = 'application/json; charset=utf-8';
|
|
372
425
|
ext = 'json';
|
|
373
426
|
}
|
|
374
|
-
ctx.send({ status: 200, headers: { 'Content-Type': contentType, 'Content-Disposition': `attachment; filename="hermes-${sid}.${ext}"`, 'Cache-Control': 'no-store' }, body: Buffer.from(payload, 'utf8') });
|
|
427
|
+
await ctx.send({ status: 200, headers: { 'Content-Type': contentType, 'Content-Disposition': `attachment; filename="hermes-${sid}.${ext}"`, 'Cache-Control': 'no-store' }, body: Buffer.from(payload, 'utf8') });
|
|
375
428
|
}
|
|
376
|
-
|
|
429
|
+
/** The shared upload preamble: the declared-size gate, the bounded body read, and the multipart parse (answers on failure). */
|
|
430
|
+
export async function readUploadForm(ctx) {
|
|
377
431
|
const maxBytes = ctx.deps.config.maxUploadBytes;
|
|
378
432
|
const contentType = ctx.header('content-type') ?? '';
|
|
379
433
|
const contentLength = Number.parseInt(ctx.header('content-length') ?? '0', 10) || 0;
|
|
380
434
|
if (contentLength > maxBytes) {
|
|
381
|
-
ctx.json({ error: `File too large (max ${String(Math.floor(maxBytes / 1024 / 1024))}MB)` }, { status: 413 });
|
|
382
|
-
return;
|
|
435
|
+
await ctx.json({ error: `File too large (max ${String(Math.floor(maxBytes / 1024 / 1024))}MB)` }, { status: 413 });
|
|
436
|
+
return null;
|
|
383
437
|
}
|
|
384
438
|
let raw;
|
|
385
439
|
try {
|
|
@@ -387,57 +441,216 @@ async function handleUpload(ctx) {
|
|
|
387
441
|
}
|
|
388
442
|
catch {
|
|
389
443
|
// Node's parser already answers a garbage or negative Content-Length with 400 before this handler runs.
|
|
390
|
-
ctx.json({ error: `Upload too large (max ${String(maxBytes)} bytes)` }, { status: 400 });
|
|
391
|
-
return;
|
|
444
|
+
await ctx.json({ error: `Upload too large (max ${String(maxBytes)} bytes)` }, { status: 400 });
|
|
445
|
+
return null;
|
|
392
446
|
}
|
|
393
|
-
let parsed;
|
|
394
447
|
try {
|
|
395
|
-
|
|
448
|
+
return parseMultipart(raw, contentType);
|
|
396
449
|
}
|
|
397
450
|
catch (error) {
|
|
398
|
-
ctx.json({ error: error.message }, { status: 400 });
|
|
399
|
-
return;
|
|
451
|
+
await ctx.json({ error: error.message }, { status: 400 });
|
|
452
|
+
return null;
|
|
400
453
|
}
|
|
401
|
-
|
|
402
|
-
|
|
454
|
+
}
|
|
455
|
+
/** The single `file` part of a chat upload, or null after answering 400. */
|
|
456
|
+
export async function uploadFile(ctx, form) {
|
|
457
|
+
const file = form.files.file;
|
|
403
458
|
if (!file) {
|
|
404
|
-
ctx.json({ error: 'No file field in request' }, { status: 400 });
|
|
405
|
-
return;
|
|
459
|
+
await ctx.json({ error: 'No file field in request' }, { status: 400 });
|
|
460
|
+
return null;
|
|
406
461
|
}
|
|
407
462
|
if (!file.filename) {
|
|
408
|
-
ctx.json({ error: 'No filename in upload' }, { status: 400 });
|
|
409
|
-
return;
|
|
463
|
+
await ctx.json({ error: 'No filename in upload' }, { status: 400 });
|
|
464
|
+
return null;
|
|
410
465
|
}
|
|
466
|
+
return file;
|
|
467
|
+
}
|
|
468
|
+
/** An unknown session and another profile's session both answer 404 before anything is written. */
|
|
469
|
+
async function uploadSessionVisible(ctx, sessionId) {
|
|
411
470
|
let session;
|
|
412
471
|
try {
|
|
413
|
-
session = ctx.deps.sessionStore.get(sessionId, { metadataOnly: true });
|
|
472
|
+
session = (await ctx.deps.sessionStore.get(sessionId, { metadataOnly: true }));
|
|
414
473
|
}
|
|
415
474
|
catch {
|
|
416
|
-
ctx.json({ error: 'Session not found' }, { status: 404 });
|
|
417
|
-
return;
|
|
475
|
+
await ctx.json({ error: 'Session not found' }, { status: 404 });
|
|
476
|
+
return false;
|
|
418
477
|
}
|
|
419
478
|
if (!ctx.deps.profilesMatch(session.profile, ctx.deps.activeProfile())) {
|
|
420
|
-
ctx.json({ error: 'Session not found' }, { status: 404 });
|
|
421
|
-
return;
|
|
479
|
+
await ctx.json({ error: 'Session not found' }, { status: 404 });
|
|
480
|
+
return false;
|
|
422
481
|
}
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
async function handleUpload(ctx) {
|
|
485
|
+
const form = await readUploadForm(ctx);
|
|
486
|
+
if (!form)
|
|
487
|
+
return;
|
|
488
|
+
const sessionId = form.fields.session_id ?? ctx.query.get('session_id') ?? '';
|
|
489
|
+
const file = (await uploadFile(ctx, form));
|
|
490
|
+
if (!file || !(await uploadSessionVisible(ctx, sessionId)))
|
|
491
|
+
return;
|
|
423
492
|
try {
|
|
424
|
-
ctx.json(ctx.deps.uploads.store(sessionId, file.filename, file.body));
|
|
493
|
+
await ctx.json(ctx.deps.uploads.store(sessionId, file.filename, file.body));
|
|
425
494
|
}
|
|
426
495
|
catch (error) {
|
|
427
496
|
if (error instanceof UploadConflict) {
|
|
428
|
-
ctx.json({ error: error.message }, { status: 409 });
|
|
497
|
+
(await ctx.json({ error: error.message }, { status: 409 }));
|
|
429
498
|
return;
|
|
430
499
|
}
|
|
431
500
|
if (error instanceof UploadRejected) {
|
|
432
|
-
ctx.json({ error: error.message }, { status: 403 });
|
|
501
|
+
(await ctx.json({ error: error.message }, { status: 403 }));
|
|
433
502
|
return;
|
|
434
503
|
}
|
|
435
504
|
if (error instanceof Error && error.message === 'Invalid filename') {
|
|
436
|
-
ctx.json({ error: error.message }, { status: 400 });
|
|
505
|
+
(await ctx.json({ error: error.message }, { status: 400 }));
|
|
437
506
|
return;
|
|
438
507
|
}
|
|
439
508
|
ctx.deps.log(`[webui] upload error: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`);
|
|
440
|
-
ctx.json({ error: 'Upload failed' }, { status: 500 });
|
|
509
|
+
await ctx.json({ error: 'Upload failed' }, { status: 500 });
|
|
441
510
|
}
|
|
442
511
|
}
|
|
512
|
+
/** Python `handle_upload_extract`: unpack an archive into `<session inbox>/<stem>` with a directory rollback receipt. */
|
|
513
|
+
async function handleUploadExtract(ctx) {
|
|
514
|
+
const form = await readUploadForm(ctx);
|
|
515
|
+
if (!form)
|
|
516
|
+
return;
|
|
517
|
+
const sessionId = form.fields.session_id ?? '';
|
|
518
|
+
const file = (await uploadFile(ctx, form));
|
|
519
|
+
if (!file || !(await uploadSessionVisible(ctx, sessionId)))
|
|
520
|
+
return;
|
|
521
|
+
const { uploads } = ctx.deps;
|
|
522
|
+
try {
|
|
523
|
+
const inbox = uploads.sessionDir(sessionId);
|
|
524
|
+
mkdirSync(inbox, { recursive: true });
|
|
525
|
+
const result = await extractArchive(file.body, file.filename, inbox, inbox, ctx.deps.config.maxExtractedBytes);
|
|
526
|
+
let token;
|
|
527
|
+
try {
|
|
528
|
+
token = uploads.registerReceipt(sessionId, result.dest, true);
|
|
529
|
+
}
|
|
530
|
+
catch (error) {
|
|
531
|
+
try {
|
|
532
|
+
rmtreeAnchored(inbox, result.dest);
|
|
533
|
+
}
|
|
534
|
+
catch { /* ignore */ }
|
|
535
|
+
throw error;
|
|
536
|
+
}
|
|
537
|
+
await ctx.json({ ok: true, ...result, rollback_token: token });
|
|
538
|
+
}
|
|
539
|
+
catch (error) {
|
|
540
|
+
if (error instanceof ArchiveRejected) {
|
|
541
|
+
(await ctx.json({ error: error.message }, { status: 400 }));
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
ctx.deps.log(`[webui] upload extract error: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`);
|
|
545
|
+
await ctx.json({ error: 'Archive extraction failed' }, { status: 500 });
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Python `handle_workspace_upload`: store each multipart file under `<workspace>/<path>` (deduplicated `-1`...`-999`);
|
|
550
|
+
* an archive is extracted into `<path>/<stem>` and removed, and a failed extraction is reported on that file.
|
|
551
|
+
*/
|
|
552
|
+
async function handleWorkspaceUpload(ctx) {
|
|
553
|
+
const form = await readUploadForm(ctx);
|
|
554
|
+
if (!form)
|
|
555
|
+
return;
|
|
556
|
+
const sessionId = form.fields.session_id ?? '';
|
|
557
|
+
const subpath = form.fields.path ?? '';
|
|
558
|
+
if (!sessionId)
|
|
559
|
+
throw new HttpError(400, 'Missing session_id');
|
|
560
|
+
if (!form.parts.length)
|
|
561
|
+
throw new HttpError(400, 'No file field in request');
|
|
562
|
+
let workspace;
|
|
563
|
+
try {
|
|
564
|
+
workspace = (await fileOpsSession(ctx, sessionId, { strictWorkspace: true })).workspace;
|
|
565
|
+
}
|
|
566
|
+
catch (error) {
|
|
567
|
+
if (error instanceof HttpError && error.message === REMOTE_WORKSPACE_UNSUPPORTED_CODE)
|
|
568
|
+
throw new HttpError(400, REMOTE_WORKSPACE_UNSUPPORTED_MESSAGE, { code: REMOTE_WORKSPACE_UNSUPPORTED_CODE });
|
|
569
|
+
throw error;
|
|
570
|
+
}
|
|
571
|
+
workspace = resolvePathLikePython(workspace);
|
|
572
|
+
if (ctx.deps.git.workspaceBusy(workspace))
|
|
573
|
+
throw new HttpError(409, WORKSPACE_BUSY_MESSAGE);
|
|
574
|
+
let targetDir;
|
|
575
|
+
try {
|
|
576
|
+
targetDir = subpath ? safeResolveWs(workspace, subpath) : workspace;
|
|
577
|
+
}
|
|
578
|
+
catch (error) {
|
|
579
|
+
throw new HttpError(400, error.message);
|
|
580
|
+
}
|
|
581
|
+
try {
|
|
582
|
+
makeAnchoredDir(workspace, targetDir);
|
|
583
|
+
}
|
|
584
|
+
catch {
|
|
585
|
+
throw new HttpError(403, 'Upload target escapes workspace');
|
|
586
|
+
}
|
|
587
|
+
const results = [];
|
|
588
|
+
try {
|
|
589
|
+
// Held for the whole upload, extraction included, so a Git operation cannot start in this workspace meanwhile.
|
|
590
|
+
await ctx.deps.git.holdWrite(workspace, async () => {
|
|
591
|
+
for (const file of form.parts) {
|
|
592
|
+
if (!file.filename)
|
|
593
|
+
continue;
|
|
594
|
+
const safeName = sanitizeUploadName(file.filename);
|
|
595
|
+
let dest;
|
|
596
|
+
try {
|
|
597
|
+
dest = uploadDestination(targetDir, safeName);
|
|
598
|
+
}
|
|
599
|
+
catch (error) {
|
|
600
|
+
if (error instanceof UploadRejected)
|
|
601
|
+
throw new HttpError(400, error.message);
|
|
602
|
+
throw error;
|
|
603
|
+
}
|
|
604
|
+
let fd;
|
|
605
|
+
try {
|
|
606
|
+
fd = openAnchoredCreateFd(workspace, dest);
|
|
607
|
+
}
|
|
608
|
+
catch (error) {
|
|
609
|
+
if (error instanceof FileExistsError)
|
|
610
|
+
throw new HttpError(409, `Upload destination already exists: ${safeName}`);
|
|
611
|
+
throw new HttpError(403, `Path traversal blocked: ${safeName}`);
|
|
612
|
+
}
|
|
613
|
+
try {
|
|
614
|
+
writeFully(fd, file.body);
|
|
615
|
+
}
|
|
616
|
+
finally {
|
|
617
|
+
closeSync(fd);
|
|
618
|
+
}
|
|
619
|
+
const mime = guessMime(safeName);
|
|
620
|
+
if (isArchiveName(safeName)) {
|
|
621
|
+
let outcome;
|
|
622
|
+
try {
|
|
623
|
+
const extraction = await extractArchive(file.body, safeName, workspace, targetDir, ctx.deps.config.maxExtractedBytes);
|
|
624
|
+
outcome = { filename: safeName, path: extraction.dest, size: file.body.length, is_image: false, extracted: true, extracted_files: extraction.files, extracted_count: extraction.extracted };
|
|
625
|
+
}
|
|
626
|
+
catch (error) {
|
|
627
|
+
const reason = error instanceof ArchiveRejected || error instanceof CorruptArchive ? error.message : null;
|
|
628
|
+
ctx.deps.log(`[webui] workspace upload extract error: ${reason ?? (error instanceof Error ? (error.stack ?? error.message) : String(error))}`);
|
|
629
|
+
outcome = { filename: safeName, path: targetDir, size: file.body.length, mime, is_image: false, extracted: false, extract_error: reason || 'Archive extraction failed' };
|
|
630
|
+
}
|
|
631
|
+
// The archive itself never stays behind, whether or not it extracted.
|
|
632
|
+
try {
|
|
633
|
+
unlinkAnchored(workspace, dest);
|
|
634
|
+
}
|
|
635
|
+
catch (error) {
|
|
636
|
+
if (error.code !== 'ENOENT')
|
|
637
|
+
throw error;
|
|
638
|
+
}
|
|
639
|
+
results.push(outcome);
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
results.push({ filename: basename(dest), path: dest, size: file.body.length, mime, is_image: mime.startsWith('image/'), extracted: false });
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
}
|
|
646
|
+
catch (error) {
|
|
647
|
+
if (error instanceof HttpError)
|
|
648
|
+
throw error;
|
|
649
|
+
if (error instanceof Error && error.message === 'Invalid filename')
|
|
650
|
+
throw new HttpError(400, error.message);
|
|
651
|
+
ctx.deps.log(`[webui] workspace upload error: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`);
|
|
652
|
+
throw new HttpError(500, 'Upload failed');
|
|
653
|
+
}
|
|
654
|
+
await ctx.json(results.length === 1 ? results[0] : { files: results, count: results.length });
|
|
655
|
+
}
|
|
443
656
|
//# sourceMappingURL=raw-routes.js.map
|